diff options
author | 2017-05-05 16:59:29 -0700 | |
---|---|---|
committer | 2017-05-16 11:28:26 -0700 | |
commit | 178dce79220c16e6f0061bcd12e9e9683ec045ee (patch) | |
tree | 1cff48009b99bd67d8859f2aa13075612a1d7fee /runtime | |
parent | 6579b099786c8cac8fdb0c86d98ad4b232a52ea0 (diff) |
Stop interpreter from accessing code items of compiled code.
The ArtInterpreterToCompiledCodeBridge accesses the code item in a
number of places to handle argument marshalling. However, the code item
of a compiled method should have no need to be accessed by the runtime
at all, since the code has been compiled. By removing these accesses,
there is a drop in the memory footprint of the dex file, since these
code items remain untouched by the runtime.
Maps Vdex Memory Usage: 19.4/33.4MB -> 18.8/33.4MB
Bug: 35800981
Test: mm test-art-host
Change-Id: I147a9267ec022547b384374e1449d20bcab1ead2
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/common_dex_operations.h | 4 | ||||
-rw-r--r-- | runtime/interpreter/interpreter.cc | 6 | ||||
-rw-r--r-- | runtime/interpreter/interpreter_common.cc | 28 | ||||
-rw-r--r-- | runtime/interpreter/interpreter_common.h | 3 |
4 files changed, 30 insertions, 11 deletions
diff --git a/runtime/common_dex_operations.h b/runtime/common_dex_operations.h index 6693eefa5a..8776061433 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 @@ -56,7 +56,7 @@ inline void PerformCall(Thread* self, 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..f3ca3383a5 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. + // The frame may only contain room for the inputs, in which case the arg offset is 0. + uint16_t arg_offset = code_item->registers_size_ == shadow_frame.NumberOfVRegs() ? + code_item->registers_size_ - code_item->ins_size_ : 0; + 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..d8c17f24e2 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,15 @@ 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 (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 +924,20 @@ 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; 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() && + !ClassLinker::ShouldUseInterpreterEntrypoint( + called_method, called_method->GetEntryPointFromQuickCompiledCode())) { + 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; diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index 2589ad046b..67e072dd96 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 |