summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Sebastien Hertz <shertz@google.com> 2013-06-28 14:24:48 +0200
committer Sebastien Hertz <shertz@google.com> 2013-07-01 10:59:28 +0200
commitcc10e0eca724a005faa2d0d5a9445df7fe6ef1c6 (patch)
treed7660a0eeaca72e422a55fe92d7b79a172714389
parent2cb33b8f7377f532cebed755be89bb351c150a22 (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.cc46
-rw-r--r--src/dex_instruction_list.h2
-rw-r--r--src/interpreter/interpreter.cc12
-rw-r--r--src/verifier/method_verifier.cc8
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: