diff options
| author | 2018-10-31 09:44:27 +0000 | |
|---|---|---|
| committer | 2018-10-31 09:44:27 +0000 | |
| commit | 91ddef31f229e6d116cc8988b71aa77bc5083bcb (patch) | |
| tree | ecaaff2fffea82f809f1735a656107668dc060c9 | |
| parent | fe79b5939696c87f66d9d39540fe0f38369c5158 (diff) | |
| parent | 9581e6176c78f3f2a8f40ff9d5a6c4d4029253fb (diff) | |
Merge "Cache whether we should use interpreter invoke fast-path."
| -rw-r--r-- | libdexfile/dex/modifiers.h | 10 | ||||
| -rw-r--r-- | runtime/art_method.h | 19 | ||||
| -rw-r--r-- | runtime/interpreter/interpreter_common.cc | 25 | ||||
| -rw-r--r-- | runtime/interpreter/interpreter_common.h | 53 |
4 files changed, 76 insertions, 31 deletions
diff --git a/libdexfile/dex/modifiers.h b/libdexfile/dex/modifiers.h index 018b1419b1..c4ea2d39b4 100644 --- a/libdexfile/dex/modifiers.h +++ b/libdexfile/dex/modifiers.h @@ -86,9 +86,9 @@ static constexpr uint32_t kAccSingleImplementation = 0x08000000; // method (ru static constexpr uint32_t kAccHiddenApiBits = 0x30000000; // field, method -// Not currently used, except for intrinsic methods where these bits -// are part of the intrinsic ordinal. -static constexpr uint32_t kAccMayBeUnusedBits = 0x40000000; +// Non-intrinsics: Caches whether we can use fast-path in the interpreter invokes. +// Intrinsics: These bits are part of the intrinsic ordinal. +static constexpr uint32_t kAccFastInterpreterToInterpreterInvoke = 0x40000000; // method. // Set by the compiler driver when compiling boot classes with instrinsic methods. static constexpr uint32_t kAccIntrinsic = 0x80000000; // method (runtime) @@ -103,9 +103,9 @@ static constexpr uint32_t kAccClassIsFinalizable = 0x80000000; // Continuous sequence of bits used to hold the ordinal of an intrinsic method. Flags // which overlap are not valid when kAccIntrinsic is set. -static constexpr uint32_t kAccIntrinsicBits = kAccMayBeUnusedBits | kAccHiddenApiBits | +static constexpr uint32_t kAccIntrinsicBits = kAccHiddenApiBits | kAccSingleImplementation | kAccMustCountLocks | kAccCompileDontBother | kAccDefaultConflict | - kAccPreviouslyWarm; + kAccPreviouslyWarm | kAccFastInterpreterToInterpreterInvoke; // Valid (meaningful) bits for a field. static constexpr uint32_t kAccValidFieldFlags = kAccPublic | kAccPrivate | kAccProtected | diff --git a/runtime/art_method.h b/runtime/art_method.h index e56f3fd6bc..4e3ef5366a 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -285,6 +285,23 @@ class ArtMethod final { bool IsPolymorphicSignature() REQUIRES_SHARED(Locks::mutator_lock_); + bool UseFastInterpreterToInterpreterInvoke() { + // The bit is applicable only if the method is not intrinsic. + constexpr uint32_t mask = kAccFastInterpreterToInterpreterInvoke | kAccIntrinsic; + return (GetAccessFlags() & mask) == kAccFastInterpreterToInterpreterInvoke; + } + + void SetFastInterpreterToInterpreterInvokeFlag() { + DCHECK(!IsIntrinsic()); + AddAccessFlags(kAccFastInterpreterToInterpreterInvoke); + } + + void ClearFastInterpreterToInterpreterInvokeFlag() { + if (!IsIntrinsic()) { + ClearAccessFlags(kAccFastInterpreterToInterpreterInvoke); + } + } + bool SkipAccessChecks() { // The kAccSkipAccessChecks flag value is used with a different meaning for native methods, // so we need to check the kAccNative flag as well. @@ -422,6 +439,8 @@ class ArtMethod final { SetNativePointer(EntryPointFromQuickCompiledCodeOffset(pointer_size), entry_point_from_quick_compiled_code, pointer_size); + // We might want to invoke compiled code, so don't use the fast path. + ClearFastInterpreterToInterpreterInvokeFlag(); } // Registers the native method and returns the new entry point. NB The returned entry point might diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index d5902ecbec..fe6154792c 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -64,6 +64,31 @@ bool CheckStackOverflow(Thread* self, size_t frame_size) return true; } +bool UseFastInterpreterToInterpreterInvoke(ArtMethod* method) { + Runtime* runtime = Runtime::Current(); + const void* quick_code = method->GetEntryPointFromQuickCompiledCode(); + if (!runtime->GetClassLinker()->IsQuickToInterpreterBridge(quick_code)) { + return false; + } + if (!method->SkipAccessChecks() || method->IsNative() || method->IsProxyMethod()) { + return false; + } + if (method->IsIntrinsic()) { + return false; + } + if (method->GetDeclaringClass()->IsStringClass() && method->IsConstructor()) { + return false; + } + if (method->IsStatic() && !method->GetDeclaringClass()->IsInitialized()) { + return false; + } + ProfilingInfo* profiling_info = method->GetProfilingInfo(kRuntimePointerSize); + if ((profiling_info != nullptr) && (profiling_info->GetSavedEntryPoint() != nullptr)) { + return false; + } + return true; +} + template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check, bool transaction_active> bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index e515d9df52..bf84227560 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -124,31 +124,8 @@ template<bool is_range, bool do_assignability_check> bool DoCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data, JValue* result); -template<InvokeType type> -static ALWAYS_INLINE bool UseInterpreterToInterpreterFastPath(ArtMethod* method) - REQUIRES_SHARED(Locks::mutator_lock_) { - Runtime* runtime = Runtime::Current(); - const void* quick_code = method->GetEntryPointFromQuickCompiledCode(); - DCHECK(runtime->IsStarted()); - if (!runtime->GetClassLinker()->IsQuickToInterpreterBridge(quick_code)) { - return false; - } - if (!method->SkipAccessChecks() || method->IsNative() || method->IsProxyMethod()) { - return false; - } - if (method->GetDeclaringClass()->IsStringClass() && method->IsConstructor()) { - return false; - } - if (type == kStatic && !method->GetDeclaringClass()->IsInitialized()) { - return false; - } - DCHECK(!runtime->IsActiveTransaction()); - ProfilingInfo* profiling_info = method->GetProfilingInfo(kRuntimePointerSize); - if ((profiling_info != nullptr) && (profiling_info->GetSavedEntryPoint() != nullptr)) { - return false; - } - return true; -} +bool UseFastInterpreterToInterpreterInvoke(ArtMethod* method) + REQUIRES_SHARED(Locks::mutator_lock_); // Throws exception if we are getting close to the end of the stack. NO_INLINE bool CheckStackOverflow(Thread* self, size_t frame_size) @@ -238,7 +215,31 @@ static ALWAYS_INLINE bool DoInvoke(Thread* self, } } - if (is_mterp && self->UseMterp() && UseInterpreterToInterpreterFastPath<type>(called_method)) { + // Check whether we can use the fast path. The result is cached in the ArtMethod. + // If the bit is not set, we explicitly recheck all the conditions. + // If any of the conditions get falsified, it is important to clear the bit. + bool use_fast_path = false; + if (is_mterp && self->UseMterp()) { + use_fast_path = called_method->UseFastInterpreterToInterpreterInvoke(); + if (!use_fast_path) { + use_fast_path = UseFastInterpreterToInterpreterInvoke(called_method); + if (use_fast_path) { + called_method->SetFastInterpreterToInterpreterInvokeFlag(); + } + } + } + + if (use_fast_path) { + DCHECK(Runtime::Current()->IsStarted()); + DCHECK(!Runtime::Current()->IsActiveTransaction()); + DCHECK(called_method->SkipAccessChecks()); + DCHECK(!called_method->IsNative()); + DCHECK(!called_method->IsProxyMethod()); + DCHECK(!called_method->IsIntrinsic()); + DCHECK(!(called_method->GetDeclaringClass()->IsStringClass() && + called_method->IsConstructor())); + DCHECK(type != kStatic || called_method->GetDeclaringClass()->IsInitialized()); + const uint16_t number_of_inputs = (is_range) ? inst->VRegA_3rc(inst_data) : inst->VRegA_35c(inst_data); CodeItemDataAccessor accessor(called_method->DexInstructionData()); |