PC-relative loads from dex cache arrays for arm.
Change-Id: Ic25df4b51a901ff1d2ca356b5eec71d4acc5d9b7
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index e6158c3..3f4f1fe 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -29,6 +29,7 @@
#include "mirror/object_array-inl.h"
#include "entrypoints/quick/quick_entrypoints.h"
#include "utils.h"
+#include "utils/dex_cache_arrays_layout-inl.h"
namespace art {
@@ -571,12 +572,12 @@
* Bit of a hack here - in the absence of a real scheduling pass,
* emit the next instruction in static & direct invoke sequences.
*/
-static int ArmNextSDCallInsn(CompilationUnit* cu, CallInfo* info ATTRIBUTE_UNUSED,
- int state, const MethodReference& target_method,
- uint32_t unused_idx ATTRIBUTE_UNUSED,
- uintptr_t direct_code, uintptr_t direct_method,
- InvokeType type) {
- Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
+int ArmMir2Lir::ArmNextSDCallInsn(CompilationUnit* cu, CallInfo* info ATTRIBUTE_UNUSED,
+ int state, const MethodReference& target_method,
+ uint32_t unused_idx ATTRIBUTE_UNUSED,
+ uintptr_t direct_code, uintptr_t direct_method,
+ InvokeType type) {
+ ArmMir2Lir* cg = static_cast<ArmMir2Lir*>(cu->cg.get());
if (direct_code != 0 && direct_method != 0) {
switch (state) {
case 0: // Get the current Method* [sets kArg0]
@@ -597,17 +598,24 @@
return -1;
}
} else {
+ bool use_pc_rel = cg->CanUseOpPcRelDexCacheArrayLoad();
RegStorage arg0_ref = cg->TargetReg(kArg0, kRef);
switch (state) {
case 0: // Get the current Method* [sets kArg0]
// TUNING: we can save a reg copy if Method* has been promoted.
- cg->LoadCurrMethodDirect(arg0_ref);
- break;
+ if (!use_pc_rel) {
+ cg->LoadCurrMethodDirect(arg0_ref);
+ break;
+ }
+ ++state;
+ FALLTHROUGH_INTENDED;
case 1: // Get method->dex_cache_resolved_methods_
- cg->LoadRefDisp(arg0_ref,
- mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(),
- arg0_ref,
- kNotVolatile);
+ if (!use_pc_rel) {
+ cg->LoadRefDisp(arg0_ref,
+ mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(),
+ arg0_ref,
+ kNotVolatile);
+ }
// Set up direct code if known.
if (direct_code != 0) {
if (direct_code != static_cast<uintptr_t>(-1)) {
@@ -619,14 +627,23 @@
cg->LoadCodeAddress(target_method, type, kInvokeTgt);
}
}
- break;
+ if (!use_pc_rel || direct_code != 0) {
+ break;
+ }
+ ++state;
+ FALLTHROUGH_INTENDED;
case 2: // Grab target method*
CHECK_EQ(cu->dex_file, target_method.dex_file);
- cg->LoadRefDisp(arg0_ref,
- mirror::ObjectArray<mirror::Object>::OffsetOfElement(
- target_method.dex_method_index).Int32Value(),
- arg0_ref,
- kNotVolatile);
+ if (!use_pc_rel) {
+ cg->LoadRefDisp(arg0_ref,
+ mirror::ObjectArray<mirror::Object>::OffsetOfElement(
+ target_method.dex_method_index).Int32Value(),
+ arg0_ref,
+ kNotVolatile);
+ } else {
+ size_t offset = cg->dex_cache_arrays_layout_.MethodOffset(target_method.dex_method_index);
+ cg->OpPcRelDexCacheArrayLoad(cu->dex_file, offset, arg0_ref);
+ }
break;
case 3: // Grab the code from the method*
if (direct_code == 0) {
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 4141bcf..619c11f 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -82,6 +82,9 @@
/// @copydoc Mir2Lir::UnconditionallyMarkGCCard(RegStorage)
void UnconditionallyMarkGCCard(RegStorage tgt_addr_reg) OVERRIDE;
+ bool CanUseOpPcRelDexCacheArrayLoad() const OVERRIDE;
+ void OpPcRelDexCacheArrayLoad(const DexFile* dex_file, int offset, RegStorage r_dest) OVERRIDE;
+
// Required for target - register utilities.
RegStorage TargetReg(SpecialTargetRegister reg) OVERRIDE;
RegStorage TargetReg(SpecialTargetRegister reg, WideKind wide_kind) OVERRIDE {
@@ -300,6 +303,9 @@
ArenaVector<LIR*> call_method_insns_;
+ // Instructions needing patching with PC relative code addresses.
+ ArenaVector<LIR*> dex_cache_access_insns_;
+
/**
* @brief Given float register pair, returns Solo64 float register.
* @param reg #RegStorage containing a float register pair (e.g. @c s2 and @c s3).
@@ -329,6 +335,12 @@
}
int GenDalvikArgsBulkCopy(CallInfo* info, int first, int count) OVERRIDE;
+
+ static int ArmNextSDCallInsn(CompilationUnit* cu, CallInfo* info ATTRIBUTE_UNUSED,
+ int state, const MethodReference& target_method,
+ uint32_t unused_idx ATTRIBUTE_UNUSED,
+ uintptr_t direct_code, uintptr_t direct_method,
+ InvokeType type);
};
} // namespace art
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index 9193e1b..c788401 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -1087,6 +1087,27 @@
lir->target = target;
}
+bool ArmMir2Lir::CanUseOpPcRelDexCacheArrayLoad() const {
+ return dex_cache_arrays_layout_.Valid();
+}
+
+void ArmMir2Lir::OpPcRelDexCacheArrayLoad(const DexFile* dex_file, int offset, RegStorage r_dest) {
+ LIR* movw = NewLIR2(kThumb2MovImm16, r_dest.GetReg(), 0);
+ LIR* movt = NewLIR2(kThumb2MovImm16H, r_dest.GetReg(), 0);
+ ArmOpcode add_pc_opcode = (r_dest.GetRegNum() < 8) ? kThumbAddRRLH : kThumbAddRRHH;
+ LIR* add_pc = NewLIR2(add_pc_opcode, r_dest.GetReg(), rs_rARM_PC.GetReg());
+ add_pc->flags.fixup = kFixupLabel;
+ movw->operands[2] = WrapPointer(dex_file);
+ movw->operands[3] = offset;
+ movw->operands[4] = WrapPointer(add_pc);
+ movt->operands[2] = movw->operands[2];
+ movt->operands[3] = movw->operands[3];
+ movt->operands[4] = movw->operands[4];
+ dex_cache_access_insns_.push_back(movw);
+ dex_cache_access_insns_.push_back(movt);
+ LoadRefDisp(r_dest, 0, r_dest, kNotVolatile);
+}
+
LIR* ArmMir2Lir::OpVldm(RegStorage r_base, int count) {
return NewLIR3(kThumb2Vldms, r_base.GetReg(), rs_fr0.GetReg(), count);
}
diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc
index 9812d9f..580dcb7 100644
--- a/compiler/dex/quick/arm/target_arm.cc
+++ b/compiler/dex/quick/arm/target_arm.cc
@@ -575,7 +575,8 @@
ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
: Mir2Lir(cu, mir_graph, arena),
- call_method_insns_(arena->Adapter()) {
+ call_method_insns_(arena->Adapter()),
+ dex_cache_access_insns_(arena->Adapter()) {
call_method_insns_.reserve(100);
// Sanity check - make sure encoding map lines up.
for (int i = 0; i < kArmLast; i++) {
@@ -901,14 +902,28 @@
}
void ArmMir2Lir::InstallLiteralPools() {
+ patches_.reserve(call_method_insns_.size() + dex_cache_access_insns_.size());
+
// PC-relative calls to methods.
- patches_.reserve(call_method_insns_.size());
for (LIR* p : call_method_insns_) {
- DCHECK_EQ(p->opcode, kThumb2Bl);
- uint32_t target_method_idx = p->operands[1];
- const DexFile* target_dex_file = UnwrapPointer<DexFile>(p->operands[2]);
- patches_.push_back(LinkerPatch::RelativeCodePatch(p->offset,
- target_dex_file, target_method_idx));
+ DCHECK_EQ(p->opcode, kThumb2Bl);
+ uint32_t target_method_idx = p->operands[1];
+ const DexFile* target_dex_file = UnwrapPointer<DexFile>(p->operands[2]);
+ patches_.push_back(LinkerPatch::RelativeCodePatch(p->offset,
+ target_dex_file, target_method_idx));
+ }
+
+ // PC-relative dex cache array accesses.
+ for (LIR* p : dex_cache_access_insns_) {
+ DCHECK(p->opcode = kThumb2MovImm16 || p->opcode == kThumb2MovImm16H);
+ const LIR* add_pc = UnwrapPointer<LIR>(p->operands[4]);
+ DCHECK(add_pc->opcode == kThumbAddRRLH || add_pc->opcode == kThumbAddRRHH);
+ const DexFile* dex_file = UnwrapPointer<DexFile>(p->operands[2]);
+ uint32_t offset = p->operands[3];
+ DCHECK(!p->flags.is_nop);
+ DCHECK(!add_pc->flags.is_nop);
+ patches_.push_back(LinkerPatch::DexCacheArrayPatch(p->offset,
+ dex_file, add_pc->offset, offset));
}
// And do the normal processing.