diff options
author | 2013-06-28 14:24:48 +0200 | |
---|---|---|
committer | 2013-07-01 10:59:28 +0200 | |
commit | cc10e0eca724a005faa2d0d5a9445df7fe6ef1c6 (patch) | |
tree | d7660a0eeaca72e422a55fe92d7b79a172714389 | |
parent | 2cb33b8f7377f532cebed755be89bb351c150a22 (diff) |
Constructor barrier support in DEX-to-DEX compiler.
Bug: 9307738
Some constructors require a barrier before returning. This CL introduces the
RETURN-VOID-BARRIER instruction. The DEX-to-DEX compiler replaces all
RETURN-VOID instructions where a barrier is required by this instruction.
The interpreter and the verifier are updated to support this new instruction.
Change-Id: If31979b4027bc12157b933eda9fcbd5270edd202
-rw-r--r-- | src/compiler/dex/dex_to_dex_compiler.cc | 46 | ||||
-rw-r--r-- | src/dex_instruction_list.h | 2 | ||||
-rw-r--r-- | src/interpreter/interpreter.cc | 12 | ||||
-rw-r--r-- | src/verifier/method_verifier.cc | 8 |
4 files changed, 63 insertions, 5 deletions
diff --git a/src/compiler/dex/dex_to_dex_compiler.cc b/src/compiler/dex/dex_to_dex_compiler.cc index afb29f4163..938de7a977 100644 --- a/src/compiler/dex/dex_to_dex_compiler.cc +++ b/src/compiler/dex/dex_to_dex_compiler.cc @@ -55,8 +55,25 @@ class DexCompiler { return *const_cast<DexFile*>(unit_.GetDexFile()); } + // Compiles a RETURN-VOID into a RETURN-VOID-BARRIER within a constructor where + // a barrier is required. + void CompileReturnVoid(Instruction* inst, uint32_t dex_pc); + + // Compiles a field access into a quick field access. + // The field index is replaced by an offset within an Object where we can read + // from / write to this field. Therefore, this does not involve any resolution + // at runtime. + // Since the field index is encoded with 16 bits, we can replace it only if the + // field offset can be encoded with 16 bits too. void CompileInstanceFieldAccess(Instruction* inst, uint32_t dex_pc, Instruction::Code new_opcode, bool is_put); + + // Compiles a virtual method invocation into a quick virtual method invocation. + // The method index is replaced by the vtable index where the corresponding + // AbstractMethod can be found. Therefore, this does not involve any resolution + // at runtime. + // Since the method index is encoded with 16 bits, we can replace it only if the + // vtable index can be encoded with 16 bits too. void CompileInvokeVirtual(Instruction* inst, uint32_t dex_pc, Instruction::Code new_opcode, bool is_range); @@ -124,9 +141,14 @@ void DexCompiler::Compile() { for (uint32_t dex_pc = 0; dex_pc < insns_size; inst = const_cast<Instruction*>(inst->Next()), dex_pc = inst->GetDexPc(insns)) { switch (inst->Opcode()) { + case Instruction::RETURN_VOID: + CompileReturnVoid(inst, dex_pc); + break; + case Instruction::IGET: CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_QUICK, false); break; + case Instruction::IGET_WIDE: CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_WIDE_QUICK, false); break; @@ -162,12 +184,34 @@ void DexCompiler::Compile() { break; default: - // No optimization. + // Nothing to do. break; } } } +void DexCompiler::CompileReturnVoid(Instruction* inst, uint32_t dex_pc) { + DCHECK(inst->Opcode() == Instruction::RETURN_VOID); + // Are we compiling a constructor ? + if ((unit_.GetAccessFlags() & kAccConstructor) == 0) { + return; + } + // Do we need a constructor barrier ? + if (!driver_.RequiresConstructorBarrier(Thread::Current(), unit_.GetDexFile(), + unit_.GetClassDefIndex())) { + return; + } + // Replace RETURN_VOID by RETURN_VOID_BARRIER. + if (kEnableLogging) { + LOG(INFO) << "Replacing " << Instruction::Name(inst->Opcode()) + << " by " << Instruction::Name(Instruction::RETURN_VOID_BARRIER) + << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method " + << PrettyMethod(unit_.GetDexMethodIndex(), GetDexFile(), true); + } + ScopedDexWriteAccess sdwa(GetModifiableDexFile(), inst, 2u); + inst->SetOpcode(Instruction::RETURN_VOID_BARRIER); +} + void DexCompiler::CompileInstanceFieldAccess(Instruction* inst, uint32_t dex_pc, Instruction::Code new_opcode, diff --git a/src/dex_instruction_list.h b/src/dex_instruction_list.h index 9daec61ba5..8257c783e7 100644 --- a/src/dex_instruction_list.h +++ b/src/dex_instruction_list.h @@ -130,7 +130,7 @@ V(0x70, INVOKE_DIRECT, "invoke-direct", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArg) \ V(0x71, INVOKE_STATIC, "invoke-static", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArg) \ V(0x72, INVOKE_INTERFACE, "invoke-interface", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArg) \ - V(0x73, UNUSED_73, "unused-73", k10x, false, kUnknown, 0, kVerifyError) \ + V(0x73, RETURN_VOID_BARRIER, "return-void-barrier", k10x, false, kNone, kReturn, kVerifyNone) \ V(0x74, INVOKE_VIRTUAL_RANGE, "invoke-virtual/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRange) \ V(0x75, INVOKE_SUPER_RANGE, "invoke-super/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRange) \ V(0x76, INVOKE_DIRECT_RANGE, "invoke-direct/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRange) \ diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc index 1e8ee9c63c..21725dee72 100644 --- a/src/interpreter/interpreter.cc +++ b/src/interpreter/interpreter.cc @@ -1136,6 +1136,17 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte } return result; } + case Instruction::RETURN_VOID_BARRIER: { + PREAMBLE(); + ANDROID_MEMBAR_STORE(); + JValue result; + if (UNLIKELY(instrumentation->HasMethodExitListeners())) { + instrumentation->MethodExitEvent(self, this_object_ref.get(), + shadow_frame.GetMethod(), inst->GetDexPc(insns), + result); + } + return result; + } case Instruction::RETURN: { PREAMBLE(); JValue result; @@ -2932,7 +2943,6 @@ static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeIte break; case Instruction::UNUSED_3E ... Instruction::UNUSED_43: case Instruction::UNUSED_EB ... Instruction::UNUSED_FF: - case Instruction::UNUSED_73: case Instruction::UNUSED_79: case Instruction::UNUSED_7A: UnexpectedOpcode(inst, mh); diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc index 87cc3286b3..32ebcf8e31 100644 --- a/src/verifier/method_verifier.cc +++ b/src/verifier/method_verifier.cc @@ -2412,7 +2412,12 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { break; // Special instructions. - // + case Instruction::RETURN_VOID_BARRIER: + DCHECK(Runtime::Current()->IsStarted()); + if (!IsConstructor()) { + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "return-void-barrier not expected"; + } + break; // Note: the following instructions encode offsets derived from class linking. // As such they use Class*/Field*/AbstractMethod* as these offsets only have // meaning if the class linking and resolution were successful. @@ -2458,7 +2463,6 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { case Instruction::UNUSED_41: case Instruction::UNUSED_42: case Instruction::UNUSED_43: - case Instruction::UNUSED_73: case Instruction::UNUSED_79: case Instruction::UNUSED_7A: case Instruction::UNUSED_EB: |