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
diff --git a/src/compiler/dex/dex_to_dex_compiler.cc b/src/compiler/dex/dex_to_dex_compiler.cc
index afb29f4..938de7a 100644
--- a/src/compiler/dex/dex_to_dex_compiler.cc
+++ b/src/compiler/dex/dex_to_dex_compiler.cc
@@ -55,8 +55,25 @@
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 @@
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 @@
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 9daec61..8257c78 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 1e8ee9c..21725de 100644
--- a/src/interpreter/interpreter.cc
+++ b/src/interpreter/interpreter.cc
@@ -1136,6 +1136,17 @@
}
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 @@
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 87cc328..32ebcf8 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -2412,7 +2412,12 @@
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 @@
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: