summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libdexfile/dex/modifiers.h10
-rw-r--r--runtime/art_method.h19
-rw-r--r--runtime/interpreter/interpreter_common.cc25
-rw-r--r--runtime/interpreter/interpreter_common.h53
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());