diff options
-rw-r--r-- | runtime/common_dex_operations.h | 12 | ||||
-rw-r--r-- | runtime/interpreter/interpreter.cc | 6 | ||||
-rw-r--r-- | runtime/interpreter/interpreter_common.cc | 41 | ||||
-rw-r--r-- | runtime/interpreter/interpreter_common.h | 3 | ||||
-rw-r--r-- | runtime/method_handles.cc | 25 |
5 files changed, 67 insertions, 20 deletions
diff --git a/runtime/common_dex_operations.h b/runtime/common_dex_operations.h index 6693eefa5a..133ddb0721 100644 --- a/runtime/common_dex_operations.h +++ b/runtime/common_dex_operations.h @@ -36,8 +36,8 @@ namespace interpreter { void ArtInterpreterToCompiledCodeBridge(Thread* self, ArtMethod* caller, - const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, + uint16_t arg_offset, JValue* result); } // namespace interpreter @@ -46,17 +46,15 @@ inline void PerformCall(Thread* self, ArtMethod* caller_method, const size_t first_dest_reg, ShadowFrame* callee_frame, - JValue* result) + JValue* result, + bool use_interpreter_entrypoint) REQUIRES_SHARED(Locks::mutator_lock_) { if (LIKELY(Runtime::Current()->IsStarted())) { - ArtMethod* target = callee_frame->GetMethod(); - if (ClassLinker::ShouldUseInterpreterEntrypoint( - target, - target->GetEntryPointFromQuickCompiledCode())) { + if (use_interpreter_entrypoint) { interpreter::ArtInterpreterToInterpreterBridge(self, code_item, callee_frame, result); } else { interpreter::ArtInterpreterToCompiledCodeBridge( - self, caller_method, code_item, callee_frame, result); + self, caller_method, callee_frame, first_dest_reg, result); } } else { interpreter::UnstartedRuntime::Invoke(self, code_item, callee_frame, result, first_dest_reg); diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc index bf49e84760..d2f5232de1 100644 --- a/runtime/interpreter/interpreter.cc +++ b/runtime/interpreter/interpreter.cc @@ -264,7 +264,11 @@ static inline JValue Execute( // Pop the shadow frame before calling into compiled code. self->PopShadowFrame(); - ArtInterpreterToCompiledCodeBridge(self, nullptr, code_item, &shadow_frame, &result); + // Calculate the offset of the first input reg. The input registers are in the high regs. + // It's ok to access the code item here since JIT code will have been touched by the + // interpreter and compiler already. + uint16_t arg_offset = code_item->registers_size_ - code_item->ins_size_; + ArtInterpreterToCompiledCodeBridge(self, nullptr, &shadow_frame, arg_offset, &result); // Push the shadow frame back as the caller will expect it. self->PushShadowFrame(&shadow_frame); diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index ef0ddb30db..084cb4218f 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -458,8 +458,8 @@ ALWAYS_INLINE void CopyRegisters(ShadowFrame& caller_frame, void ArtInterpreterToCompiledCodeBridge(Thread* self, ArtMethod* caller, - const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, + uint16_t arg_offset, JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { ArtMethod* method = shadow_frame->GetMethod(); @@ -482,9 +482,17 @@ void ArtInterpreterToCompiledCodeBridge(Thread* self, method = shadow_frame->GetMethod(); } } - uint16_t arg_offset = (code_item == nullptr) - ? 0 - : code_item->registers_size_ - code_item->ins_size_; + // Basic checks for the arg_offset. If there's no code item, the arg_offset must be 0. Otherwise, + // check that the arg_offset isn't greater than the number of registers. A stronger check is + // difficult since the frame may contain space for all the registers in the method, or only enough + // space for the arguments. + if (kIsDebugBuild) { + if (method->GetCodeItem() == nullptr) { + DCHECK_EQ(0u, arg_offset) << method->PrettyMethod(); + } else { + DCHECK_LE(arg_offset, shadow_frame->NumberOfVRegs()); + } + } jit::Jit* jit = Runtime::Current()->GetJit(); if (jit != nullptr && caller != nullptr) { jit->NotifyInterpreterToCompiledCodeTransition(self, caller); @@ -918,12 +926,23 @@ static inline bool DoCallCommon(ArtMethod* called_method, // Compute method information. const DexFile::CodeItem* code_item = called_method->GetCodeItem(); - // Number of registers for the callee's call frame. uint16_t num_regs; + // Test whether to use the interpreter or compiler entrypoint, and save that result to pass to + // PerformCall. A deoptimization could occur at any time, and we shouldn't change which + // entrypoint to use once we start building the shadow frame. + bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint( + called_method, called_method->GetEntryPointFromQuickCompiledCode()); if (LIKELY(code_item != nullptr)) { - num_regs = code_item->registers_size_; - DCHECK_EQ(string_init ? number_of_inputs - 1 : number_of_inputs, code_item->ins_size_); + // When transitioning to compiled code, space only needs to be reserved for the input registers. + // The rest of the frame gets discarded. This also prevents accessing the called method's code + // item, saving memory by keeping code items of compiled code untouched. + if (Runtime::Current()->IsStarted() && !use_interpreter_entrypoint) { + num_regs = number_of_inputs; + } else { + num_regs = code_item->registers_size_; + DCHECK_EQ(string_init ? number_of_inputs - 1 : number_of_inputs, code_item->ins_size_); + } } else { DCHECK(called_method->IsNative() || called_method->IsProxyMethod()); num_regs = number_of_inputs; @@ -1077,7 +1096,13 @@ static inline bool DoCallCommon(ArtMethod* called_method, self->EndAssertNoThreadSuspension(old_cause); } - PerformCall(self, code_item, shadow_frame.GetMethod(), first_dest_reg, new_shadow_frame, result); + PerformCall(self, + code_item, + shadow_frame.GetMethod(), + first_dest_reg, + new_shadow_frame, + result, + use_interpreter_entrypoint); if (string_init && !self->IsExceptionPending()) { SetStringInitValueToAllAliases(&shadow_frame, string_init_vreg_this, *result); diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index fdc0505e7f..38edc7a9e7 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -527,10 +527,11 @@ static inline void AssignRegister(ShadowFrame* new_shadow_frame, const ShadowFra } } +// The arg_offset is the offset to the first input register in the frame. void ArtInterpreterToCompiledCodeBridge(Thread* self, ArtMethod* caller, - const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, + uint16_t arg_offset, JValue* result); // Set string value created from StringFactory.newStringFromXXX() into all aliases of diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc index 54d45b1e79..090bac1173 100644 --- a/runtime/method_handles.cc +++ b/runtime/method_handles.cc @@ -514,7 +514,15 @@ static inline bool DoCallPolymorphic(ArtMethod* called_method, } } - PerformCall(self, code_item, shadow_frame.GetMethod(), first_dest_reg, new_shadow_frame, result); + bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint( + called_method, called_method->GetEntryPointFromQuickCompiledCode()); + PerformCall(self, + code_item, + shadow_frame.GetMethod(), + first_dest_reg, + new_shadow_frame, + result, + use_interpreter_entrypoint); if (self->IsExceptionPending()) { return false; } @@ -602,12 +610,15 @@ static inline bool DoCallTransform(ArtMethod* called_method, new_shadow_frame->SetVRegReference(0, receiver.Get()); new_shadow_frame->SetVRegReference(1, sf.Get()); + bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint( + called_method, called_method->GetEntryPointFromQuickCompiledCode()); PerformCall(self, code_item, shadow_frame.GetMethod(), 0 /* first destination register */, new_shadow_frame, - result); + result, + use_interpreter_entrypoint); if (self->IsExceptionPending()) { return false; } @@ -1091,7 +1102,15 @@ bool DoInvokePolymorphicExact(Thread* self, num_input_regs); self->EndAssertNoThreadSuspension(old_cause); - PerformCall(self, code_item, shadow_frame.GetMethod(), first_dest_reg, new_shadow_frame, result); + bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint( + called_method, called_method->GetEntryPointFromQuickCompiledCode()); + PerformCall(self, + code_item, + shadow_frame.GetMethod(), + first_dest_reg, + new_shadow_frame, + result, + use_interpreter_entrypoint); if (self->IsExceptionPending()) { return false; } |