summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/Android.mk3
-rw-r--r--compiler/dex/dex_to_dex_compiler.cc10
-rw-r--r--compiler/dex/frontend.cc16
-rw-r--r--compiler/dex/frontend.h14
-rw-r--r--compiler/dex/local_value_numbering.cc12
-rw-r--r--compiler/dex/mir_graph.cc33
-rw-r--r--compiler/dex/mir_graph.h4
-rw-r--r--compiler/dex/mir_optimization.cc12
-rw-r--r--compiler/dex/quick/arm/codegen_arm.h17
-rw-r--r--compiler/dex/quick/arm/fp_arm.cc2
-rw-r--r--compiler/dex/quick/arm/int_arm.cc39
-rw-r--r--compiler/dex/quick/arm/target_arm.cc11
-rw-r--r--compiler/dex/quick/codegen_util.cc57
-rw-r--r--compiler/dex/quick/gen_common.cc126
-rw-r--r--compiler/dex/quick/gen_invoke.cc24
-rw-r--r--compiler/dex/quick/gen_loadstore.cc90
-rw-r--r--compiler/dex/quick/mips/codegen_mips.h15
-rw-r--r--compiler/dex/quick/mips/int_mips.cc34
-rw-r--r--compiler/dex/quick/mips/target_mips.cc13
-rw-r--r--compiler/dex/quick/mir_to_lir.cc6
-rw-r--r--compiler/dex/quick/mir_to_lir.h97
-rw-r--r--compiler/dex/quick/x86/assemble_x86.cc37
-rw-r--r--compiler/dex/quick/x86/codegen_x86.h147
-rw-r--r--compiler/dex/quick/x86/fp_x86.cc2
-rw-r--r--compiler/dex/quick/x86/int_x86.cc1066
-rw-r--r--compiler/dex/quick/x86/target_x86.cc58
-rw-r--r--compiler/dex/quick/x86/utility_x86.cc53
-rw-r--r--compiler/dex/quick/x86/x86_lir.h5
-rw-r--r--compiler/dex/verification_results.cc110
-rw-r--r--compiler/dex/verification_results.h70
-rw-r--r--compiler/dex/verified_method.cc (renamed from compiler/dex/verified_methods_data.cc)352
-rw-r--r--compiler/dex/verified_method.h98
-rw-r--r--compiler/dex/verified_methods_data.h117
-rw-r--r--compiler/driver/compiler_driver.cc171
-rw-r--r--compiler/driver/compiler_driver.h156
-rw-r--r--compiler/driver/dex_compilation_unit.cc9
-rw-r--r--compiler/driver/dex_compilation_unit.h9
-rw-r--r--compiler/elf_writer.h2
-rw-r--r--compiler/elf_writer_mclinker.h2
-rw-r--r--compiler/image_writer.cc66
-rw-r--r--compiler/llvm/compiler_llvm.cc13
-rw-r--r--compiler/oat_test.cc9
-rw-r--r--compiler/oat_writer.cc6
43 files changed, 2389 insertions, 804 deletions
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 25dfb0a192..c6662c2181 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -59,7 +59,8 @@ LIBART_COMPILER_SRC_FILES := \
dex/frontend.cc \
dex/mir_graph.cc \
dex/mir_analysis.cc \
- dex/verified_methods_data.cc \
+ dex/verified_method.cc \
+ dex/verification_results.cc \
dex/vreg_analysis.cc \
dex/ssa_transformation.cc \
driver/compiler_driver.cc \
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index 3368132a0e..ff8fea0f88 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -176,8 +176,7 @@ Instruction* DexCompiler::CompileCheckCast(Instruction* inst, uint32_t dex_pc) {
if (!kEnableCheckCastEllision || !PerformOptimizations()) {
return inst;
}
- MethodReference referrer(&GetDexFile(), unit_.GetDexMethodIndex());
- if (!driver_.IsSafeCast(referrer, dex_pc)) {
+ if (!driver_.IsSafeCast(&unit_, dex_pc)) {
return inst;
}
// Ok, this is a safe cast. Since the "check-cast" instruction size is 2 code
@@ -272,15 +271,16 @@ void DexCompiler::CompileInvokeVirtual(Instruction* inst,
} // namespace optimizer
} // namespace art
-extern "C" void ArtCompileDEX(art::CompilerDriver& compiler, const art::DexFile::CodeItem* code_item,
+extern "C" void ArtCompileDEX(art::CompilerDriver& driver, const art::DexFile::CodeItem* code_item,
uint32_t access_flags, art::InvokeType invoke_type,
uint16_t class_def_idx, uint32_t method_idx, jobject class_loader,
const art::DexFile& dex_file,
art::DexToDexCompilationLevel dex_to_dex_compilation_level) {
if (dex_to_dex_compilation_level != art::kDontDexToDexCompile) {
art::DexCompilationUnit unit(NULL, class_loader, art::Runtime::Current()->GetClassLinker(),
- dex_file, code_item, class_def_idx, method_idx, access_flags);
- art::optimizer::DexCompiler dex_compiler(compiler, unit, dex_to_dex_compilation_level);
+ dex_file, code_item, class_def_idx, method_idx, access_flags,
+ driver.GetVerifiedMethod(&dex_file, method_idx));
+ art::optimizer::DexCompiler dex_compiler(driver, unit, dex_to_dex_compilation_level);
dex_compiler.Compile();
}
}
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index 364a8bc55b..f5bb85a910 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -141,25 +141,24 @@ CompilationUnit::CompilationUnit(ArenaPool* pool)
CompilationUnit::~CompilationUnit() {
}
+// TODO: Add a cumulative version of logging, and combine with dex2oat --dump-timing
void CompilationUnit::StartTimingSplit(const char* label) {
- if (compiler_driver->GetDumpPasses()) {
+ if (enable_debug & (1 << kDebugTimings)) {
timings.StartSplit(label);
}
}
void CompilationUnit::NewTimingSplit(const char* label) {
- if (compiler_driver->GetDumpPasses()) {
+ if (enable_debug & (1 << kDebugTimings)) {
timings.NewSplit(label);
}
}
void CompilationUnit::EndTiming() {
- if (compiler_driver->GetDumpPasses()) {
+ if (enable_debug & (1 << kDebugTimings)) {
timings.EndSplit();
- if (enable_debug & (1 << kDebugTimings)) {
- LOG(INFO) << "TIMINGS " << PrettyMethod(method_idx, *dex_file);
- LOG(INFO) << Dumpable<TimingLogger>(timings);
- }
+ LOG(INFO) << "TIMINGS " << PrettyMethod(method_idx, *dex_file);
+ LOG(INFO) << Dumpable<TimingLogger>(timings);
}
}
@@ -317,9 +316,6 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler,
}
cu.EndTiming();
- compiler.GetTimingsLogger().Start();
- compiler.GetTimingsLogger().AddLogger(cu.timings);
- compiler.GetTimingsLogger().End();
return result;
}
diff --git a/compiler/dex/frontend.h b/compiler/dex/frontend.h
index 8eb6684d7f..8ce12067ee 100644
--- a/compiler/dex/frontend.h
+++ b/compiler/dex/frontend.h
@@ -18,12 +18,7 @@
#define ART_COMPILER_DEX_FRONTEND_H_
#include "dex_file.h"
-#include "dex_instruction.h"
-
-
-
-
-
+#include "invoke_type.h"
namespace llvm {
class Module;
@@ -82,9 +77,6 @@ enum debugControlVector {
kDebugTimings
};
-class DexFileToMethodInlinerMap;
-class CompilerDriver;
-
class LLVMInfo {
public:
LLVMInfo();
@@ -113,8 +105,8 @@ class LLVMInfo {
UniquePtr<art::llvm::IRBuilder> ir_builder_;
};
-struct CompilationUnit;
-struct BasicBlock;
+struct CompiledMethod;
+class CompilerDriver;
} // namespace art
diff --git a/compiler/dex/local_value_numbering.cc b/compiler/dex/local_value_numbering.cc
index 75883b7bd6..9e83210012 100644
--- a/compiler/dex/local_value_numbering.cc
+++ b/compiler/dex/local_value_numbering.cc
@@ -380,9 +380,6 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
}
mir->optimization_flags |= MIR_IGNORE_RANGE_CHECK;
}
- if (mir->meta.throw_insn != NULL) {
- mir->meta.throw_insn->optimization_flags |= mir->optimization_flags;
- }
// Use side effect to note range check completed.
(void)LookupValue(ARRAY_REF, array, index, NO_VALUE);
// Establish value number for loaded register. Note use of memory version.
@@ -421,9 +418,6 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
}
mir->optimization_flags |= MIR_IGNORE_RANGE_CHECK;
}
- if (mir->meta.throw_insn != NULL) {
- mir->meta.throw_insn->optimization_flags |= mir->optimization_flags;
- }
// Use side effect to note range check completed.
(void)LookupValue(ARRAY_REF, array, index, NO_VALUE);
// Rev the memory version
@@ -447,9 +441,6 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
} else {
null_checked_.insert(base);
}
- if (mir->meta.throw_insn != NULL) {
- mir->meta.throw_insn->optimization_flags |= mir->optimization_flags;
- }
uint16_t field_ref = mir->dalvikInsn.vC;
uint16_t memory_version = GetMemoryVersion(base, field_ref);
if (opcode == Instruction::IGET_WIDE) {
@@ -479,9 +470,6 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
} else {
null_checked_.insert(base);
}
- if (mir->meta.throw_insn != NULL) {
- mir->meta.throw_insn->optimization_flags |= mir->optimization_flags;
- }
uint16_t field_ref = mir->dalvikInsn.vC;
AdvanceMemoryVersion(base, field_ref);
}
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc
index 8d1653fc6c..9dbb3417a3 100644
--- a/compiler/dex/mir_graph.cc
+++ b/compiler/dex/mir_graph.cc
@@ -126,9 +126,6 @@ BasicBlock* MIRGraph::SplitBlock(DexOffset code_offset,
bottom_block->terminated_by_return = orig_block->terminated_by_return;
orig_block->terminated_by_return = false;
- /* Add it to the quick lookup cache */
- dex_pc_to_block_map_.Put(bottom_block->start_offset, bottom_block->id);
-
/* Handle the taken path */
bottom_block->taken = orig_block->taken;
if (bottom_block->taken != NullBasicBlockId) {
@@ -177,19 +174,29 @@ BasicBlock* MIRGraph::SplitBlock(DexOffset code_offset,
}
// Associate dex instructions in the bottom block with the new container.
- MIR* p = bottom_block->first_mir_insn;
- while (p != NULL) {
+ DCHECK(insn != nullptr);
+ DCHECK(insn != orig_block->first_mir_insn);
+ DCHECK(insn == bottom_block->first_mir_insn);
+ DCHECK_EQ(insn->offset, bottom_block->start_offset);
+ DCHECK(static_cast<int>(insn->dalvikInsn.opcode) == kMirOpCheck ||
+ !IsPseudoMirOp(insn->dalvikInsn.opcode));
+ DCHECK_EQ(dex_pc_to_block_map_.Get(insn->offset), orig_block->id);
+ MIR* p = insn;
+ dex_pc_to_block_map_.Put(p->offset, bottom_block->id);
+ while (p != bottom_block->last_mir_insn) {
+ p = p->next;
+ DCHECK(p != nullptr);
int opcode = p->dalvikInsn.opcode;
/*
* Some messiness here to ensure that we only enter real opcodes and only the
* first half of a potentially throwing instruction that has been split into
- * CHECK and work portions. The 2nd half of a split operation will have a non-null
- * throw_insn pointer that refers to the 1st half.
+ * CHECK and work portions. Since the 2nd half of a split operation is always
+ * the first in a BasicBlock, we can't hit it here.
*/
- if ((opcode == kMirOpCheck) || (!IsPseudoMirOp(opcode) && (p->meta.throw_insn == NULL))) {
+ if ((opcode == kMirOpCheck) || !IsPseudoMirOp(opcode)) {
+ DCHECK_EQ(dex_pc_to_block_map_.Get(p->offset), orig_block->id);
dex_pc_to_block_map_.Put(p->offset, bottom_block->id);
}
- p = (p == bottom_block->last_mir_insn) ? NULL : p->next;
}
return bottom_block;
@@ -508,7 +515,6 @@ BasicBlock* MIRGraph::ProcessCanThrow(BasicBlock* cur_block, MIR* insn, DexOffse
static_cast<Instruction::Code>(kMirOpCheck);
// Associate the two halves
insn->meta.throw_insn = new_insn;
- new_insn->meta.throw_insn = insn;
AppendMIR(new_block, new_insn);
return new_block;
}
@@ -523,7 +529,8 @@ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_
current_offset_ = 0;
// TODO: will need to snapshot stack image and use that as the mir context identification.
m_units_.push_back(new DexCompilationUnit(cu_, class_loader, Runtime::Current()->GetClassLinker(),
- dex_file, current_code_item_, class_def_idx, method_idx, access_flags));
+ dex_file, current_code_item_, class_def_idx, method_idx, access_flags,
+ cu_->compiler_driver->GetVerifiedMethod(&dex_file, method_idx)));
const uint16_t* code_ptr = current_code_item_->insns_;
const uint16_t* code_end =
current_code_item_->insns_ + current_code_item_->insns_size_in_code_units_;
@@ -973,7 +980,7 @@ char* MIRGraph::GetDalvikDisassembly(const MIR* mir) {
str.append(StringPrintf(", #%d", insn.vB));
break;
case Instruction::k51l: // Add one wide immediate
- str.append(StringPrintf(", #%lld", insn.vB_wide));
+ str.append(StringPrintf(", #%" PRId64, insn.vB_wide));
break;
case Instruction::k21c: // One register, one string/type/method index
case Instruction::k31c:
@@ -1026,7 +1033,7 @@ std::string MIRGraph::GetSSANameWithConst(int ssa_reg, bool singles_only) {
}
if (IsConst(reg_location_[ssa_reg])) {
if (!singles_only && reg_location_[ssa_reg].wide) {
- return StringPrintf("v%d_%d#0x%llx", SRegToVReg(ssa_reg), GetSSASubscript(ssa_reg),
+ return StringPrintf("v%d_%d#0x%" PRIx64, SRegToVReg(ssa_reg), GetSSASubscript(ssa_reg),
ConstantValueWide(reg_location_[ssa_reg]));
} else {
return StringPrintf("v%d_%d#0x%x", SRegToVReg(ssa_reg), GetSSASubscript(ssa_reg),
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index b68e6997ae..4666d1e47a 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -253,8 +253,10 @@ struct MIR {
union {
// Incoming edges for phi node.
BasicBlockId* phi_incoming;
- // Establish link between two halves of throwing instructions.
+ // Establish link from check instruction (kMirOpCheck) to the actual throwing instruction.
MIR* throw_insn;
+ // Fused cmp branch condition.
+ ConditionCode ccode;
} meta;
};
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc
index ee9f28e184..0d53d4cba2 100644
--- a/compiler/dex/mir_optimization.cc
+++ b/compiler/dex/mir_optimization.cc
@@ -259,7 +259,7 @@ bool MIRGraph::BasicBlockOpt(BasicBlock* bb) {
if ((ccode != kCondNv) &&
(mir->ssa_rep->defs[0] == mir_next->ssa_rep->uses[0]) &&
(GetSSAUseCount(mir->ssa_rep->defs[0]) == 1)) {
- mir_next->dalvikInsn.arg[0] = ccode;
+ mir_next->meta.ccode = ccode;
switch (opcode) {
case Instruction::CMPL_FLOAT:
mir_next->dalvikInsn.opcode =
@@ -323,9 +323,10 @@ bool MIRGraph::BasicBlockOpt(BasicBlock* bb) {
break;
}
// Is this the select pattern?
- // TODO: flesh out support for Mips and X86. NOTE: llvm's select op doesn't quite work here.
+ // TODO: flesh out support for Mips. NOTE: llvm's select op doesn't quite work here.
// TUNING: expand to support IF_xx compare & branches
- if (!(cu_->compiler_backend == kPortable) && (cu_->instruction_set == kThumb2) &&
+ if ((cu_->compiler_backend != kPortable) &&
+ (cu_->instruction_set == kThumb2 || cu_->instruction_set == kX86) &&
((mir->dalvikInsn.opcode == Instruction::IF_EQZ) ||
(mir->dalvikInsn.opcode == Instruction::IF_NEZ))) {
BasicBlock* ft = GetBasicBlock(bb->fall_through);
@@ -391,6 +392,11 @@ bool MIRGraph::BasicBlockOpt(BasicBlock* bb) {
}
}
if (const_form) {
+ /*
+ * TODO: If both constants are the same value, then instead of generating
+ * a select, we should simply generate a const bytecode. This should be
+ * considered after inlining which can lead to CFG of this form.
+ */
// "true" set val in vB
mir->dalvikInsn.vB = if_true->dalvikInsn.vB;
// "false" set val in vC
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 2bc579a675..32673db41e 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -17,6 +17,7 @@
#ifndef ART_COMPILER_DEX_QUICK_ARM_CODEGEN_ARM_H_
#define ART_COMPILER_DEX_QUICK_ARM_CODEGEN_ARM_H_
+#include "arm_lir.h"
#include "dex/compiler_internals.h"
namespace art {
@@ -94,9 +95,9 @@ class ArmMir2Lir : public Mir2Lir {
RegLocation rl_src, int scale, bool card_mark);
void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_src1, RegLocation rl_shift);
- void GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- void GenAndLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenMulLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenAddLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenAndLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_src1, RegLocation rl_src2);
void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
@@ -110,9 +111,9 @@ class ArmMir2Lir : public Mir2Lir {
bool GenInlinedPeek(CallInfo* info, OpSize size);
bool GenInlinedPoke(CallInfo* info, OpSize size);
void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
- void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- void GenXorLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenOrLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenSubLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenXorLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base, int offset,
ThrowKind kind);
RegLocation GenDivRem(RegLocation rl_dest, int reg_lo, int reg_hi, bool is_div);
@@ -191,10 +192,12 @@ class ArmMir2Lir : public Mir2Lir {
MIR* SpecialIPut(BasicBlock** bb, MIR* mir, OpSize size, bool long_or_double, bool is_object);
MIR* SpecialIdentity(MIR* mir);
LIR* LoadFPConstantValue(int r_dest, int value);
- bool BadOverlap(RegLocation rl_src, RegLocation rl_dest);
void ReplaceFixup(LIR* prev_lir, LIR* orig_lir, LIR* new_lir);
void InsertFixupBefore(LIR* prev_lir, LIR* orig_lir, LIR* new_lir);
void AssignDataOffsets();
+ RegLocation GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
+ RegLocation rl_src2, bool is_div, bool check_zero);
+ RegLocation GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div);
};
} // namespace art
diff --git a/compiler/dex/quick/arm/fp_arm.cc b/compiler/dex/quick/arm/fp_arm.cc
index 1a9d9c5e70..46542e118c 100644
--- a/compiler/dex/quick/arm/fp_arm.cc
+++ b/compiler/dex/quick/arm/fp_arm.cc
@@ -209,7 +209,7 @@ void ArmMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
NewLIR2(kThumb2Vcmps, rl_src1.low_reg, rl_src2.low_reg);
}
NewLIR0(kThumb2Fmstat);
- ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
+ ConditionCode ccode = mir->meta.ccode;
switch (ccode) {
case kCondEq:
case kCondNe:
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index 86ae75e29b..150794e75d 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -228,7 +228,7 @@ void ArmMir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) {
RegLocation rl_src1 = mir_graph_->GetSrcWide(mir, 0);
RegLocation rl_src2 = mir_graph_->GetSrcWide(mir, 2);
// Normalize such that if either operand is constant, src2 will be constant.
- ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
+ ConditionCode ccode = mir->meta.ccode;
if (rl_src1.is_const) {
std::swap(rl_src1, rl_src2);
ccode = FlipComparisonOrder(ccode);
@@ -444,6 +444,17 @@ LIR* ArmMir2Lir::GenRegMemCheck(ConditionCode c_code,
return NULL;
}
+RegLocation ArmMir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
+ RegLocation rl_src2, bool is_div, bool check_zero) {
+ LOG(FATAL) << "Unexpected use of GenDivRem for Arm";
+ return rl_dest;
+}
+
+RegLocation ArmMir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) {
+ LOG(FATAL) << "Unexpected use of GenDivRemLit for Arm";
+ return rl_dest;
+}
+
RegLocation ArmMir2Lir::GenDivRemLit(RegLocation rl_dest, int reg1, int lit,
bool is_div) {
RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
@@ -783,20 +794,8 @@ void ArmMir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
StoreValueWide(rl_dest, rl_result);
}
-
- /*
- * Check to see if a result pair has a misaligned overlap with an operand pair. This
- * is not usual for dx to generate, but it is legal (for now). In a future rev of
- * dex, we'll want to make this case illegal.
- */
-bool ArmMir2Lir::BadOverlap(RegLocation rl_src, RegLocation rl_dest) {
- DCHECK(rl_src.wide);
- DCHECK(rl_dest.wide);
- return (abs(mir_graph_->SRegToVReg(rl_src.s_reg_low) - mir_graph_->SRegToVReg(rl_dest.s_reg_low)) == 1);
-}
-
-void ArmMir2Lir::GenMulLong(RegLocation rl_dest, RegLocation rl_src1,
- RegLocation rl_src2) {
+void ArmMir2Lir::GenMulLong(Instruction::Code opcode, RegLocation rl_dest,
+ RegLocation rl_src1, RegLocation rl_src2) {
/*
* To pull off inline multiply, we have a worst-case requirement of 8 temporary
* registers. Normally for Arm, we get 5. We can get to 6 by including
@@ -868,27 +867,27 @@ void ArmMir2Lir::GenMulLong(RegLocation rl_dest, RegLocation rl_src1,
UnmarkTemp(rARM_LR);
}
-void ArmMir2Lir::GenAddLong(RegLocation rl_dest, RegLocation rl_src1,
+void ArmMir2Lir::GenAddLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
RegLocation rl_src2) {
LOG(FATAL) << "Unexpected use of GenAddLong for Arm";
}
-void ArmMir2Lir::GenSubLong(RegLocation rl_dest, RegLocation rl_src1,
+void ArmMir2Lir::GenSubLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
RegLocation rl_src2) {
LOG(FATAL) << "Unexpected use of GenSubLong for Arm";
}
-void ArmMir2Lir::GenAndLong(RegLocation rl_dest, RegLocation rl_src1,
+void ArmMir2Lir::GenAndLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
RegLocation rl_src2) {
LOG(FATAL) << "Unexpected use of GenAndLong for Arm";
}
-void ArmMir2Lir::GenOrLong(RegLocation rl_dest, RegLocation rl_src1,
+void ArmMir2Lir::GenOrLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
RegLocation rl_src2) {
LOG(FATAL) << "Unexpected use of GenOrLong for Arm";
}
-void ArmMir2Lir::GenXorLong(RegLocation rl_dest, RegLocation rl_src1,
+void ArmMir2Lir::GenXorLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
RegLocation rl_src2) {
LOG(FATAL) << "Unexpected use of genXoLong for Arm";
}
diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc
index 759104150d..ceec7d50ce 100644
--- a/compiler/dex/quick/arm/target_arm.cc
+++ b/compiler/dex/quick/arm/target_arm.cc
@@ -14,10 +14,12 @@
* limitations under the License.
*/
+#include "codegen_arm.h"
+
+#include <inttypes.h>
+
#include <string>
-#include "arm_lir.h"
-#include "codegen_arm.h"
#include "dex/compiler_internals.h"
#include "dex/quick/mir_to_lir-inl.h"
@@ -407,9 +409,8 @@ std::string ArmMir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char
strcpy(tbuf, cc_names[operand]);
break;
case 't':
- snprintf(tbuf, arraysize(tbuf), "0x%08x (L%p)",
- reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 +
- (operand << 1),
+ snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
+ reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
lir->target);
break;
case 'u': {
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 29554c0977..7f19ea1eb9 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -21,7 +21,8 @@
#include "mir_to_lir-inl.h"
#include "dex/quick/dex_file_method_inliner.h"
#include "dex/quick/dex_file_to_method_inliner_map.h"
-#include "dex/verified_methods_data.h"
+#include "dex/verification_results.h"
+#include "dex/verified_method.h"
#include "verifier/dex_gc_map.h"
#include "verifier/method_verifier.h"
@@ -34,7 +35,7 @@ template <typename It>
void DumpMappingTable(const char* table_name, const char* descriptor, const char* name,
const Signature& signature, uint32_t size, It first) {
if (size != 0) {
- std::string line(StringPrintf("\n %s %s%s_%s_table[%zu] = {", table_name,
+ std::string line(StringPrintf("\n %s %s%s_%s_table[%u] = {", table_name,
descriptor, name, signature.ToString().c_str(), size));
std::replace(line.begin(), line.end(), ';', '_');
LOG(INFO) << line;
@@ -234,8 +235,8 @@ void Mir2Lir::DumpLIRInsn(LIR* lir, unsigned char* base_addr) {
lir, base_addr));
std::string op_operands(BuildInsnString(GetTargetInstFmt(lir->opcode),
lir, base_addr));
- LOG(INFO) << StringPrintf("%05x: %-9s%s%s",
- reinterpret_cast<unsigned int>(base_addr + offset),
+ LOG(INFO) << StringPrintf("%5p: %-9s%s%s",
+ base_addr + offset,
op_name.c_str(), op_operands.c_str(),
lir->flags.is_nop ? "(nop)" : "");
}
@@ -440,6 +441,20 @@ void Mir2Lir::InstallLiteralPools() {
PushPointer(code_buffer_, &id);
data_lir = NEXT_LIR(data_lir);
}
+ // Push class literals.
+ data_lir = class_literal_list_;
+ while (data_lir != NULL) {
+ uint32_t target = data_lir->operands[0];
+ cu_->compiler_driver->AddClassPatch(cu_->dex_file,
+ cu_->class_def_idx,
+ cu_->method_idx,
+ target,
+ code_buffer_.size());
+ const DexFile::TypeId& id = cu_->dex_file->GetTypeId(target);
+ // unique value based on target to ensure code deduplication works
+ PushPointer(code_buffer_, &id);
+ data_lir = NEXT_LIR(data_lir);
+ }
}
/* Write the switch tables to the output stream */
@@ -749,10 +764,10 @@ void Mir2Lir::CreateNativeGcMap() {
}
}
MethodReference method_ref(cu_->dex_file, cu_->method_idx);
- const std::vector<uint8_t>* gc_map_raw =
- cu_->compiler_driver->GetVerifiedMethodsData()->GetDexGcMap(method_ref);
- verifier::DexPcToReferenceMap dex_gc_map(&(*gc_map_raw)[0]);
- DCHECK_EQ(gc_map_raw->size(), dex_gc_map.RawSize());
+ const std::vector<uint8_t>& gc_map_raw =
+ mir_graph_->GetCurrentDexCompilationUnit()->GetVerifiedMethod()->GetDexGcMap();
+ verifier::DexPcToReferenceMap dex_gc_map(&(gc_map_raw)[0]);
+ DCHECK_EQ(gc_map_raw.size(), dex_gc_map.RawSize());
// Compute native offset to references size.
NativePcToReferenceMapBuilder native_gc_map_builder(&native_gc_map_,
mapping_table.PcToDexSize(),
@@ -772,6 +787,7 @@ int Mir2Lir::AssignLiteralOffset(CodeOffset offset) {
offset = AssignLiteralOffsetCommon(literal_list_, offset);
offset = AssignLiteralPointerOffsetCommon(code_literal_list_, offset);
offset = AssignLiteralPointerOffsetCommon(method_literal_list_, offset);
+ offset = AssignLiteralPointerOffsetCommon(class_literal_list_, offset);
return offset;
}
@@ -960,6 +976,7 @@ Mir2Lir::Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena
: Backend(arena),
literal_list_(NULL),
method_literal_list_(NULL),
+ class_literal_list_(NULL),
code_literal_list_(NULL),
first_fixup_(NULL),
cu_(cu),
@@ -1121,4 +1138,28 @@ void Mir2Lir::InsertLIRAfter(LIR* current_lir, LIR* new_lir) {
new_lir->next->prev = new_lir;
}
+bool Mir2Lir::IsPowerOfTwo(uint64_t x) {
+ return (x & (x - 1)) == 0;
+}
+
+// Returns the index of the lowest set bit in 'x'.
+int32_t Mir2Lir::LowestSetBit(uint64_t x) {
+ int bit_posn = 0;
+ while ((x & 0xf) == 0) {
+ bit_posn += 4;
+ x >>= 4;
+ }
+ while ((x & 1) == 0) {
+ bit_posn++;
+ x >>= 1;
+ }
+ return bit_posn;
+}
+
+bool Mir2Lir::BadOverlap(RegLocation rl_src, RegLocation rl_dest) {
+ DCHECK(rl_src.wide);
+ DCHECK(rl_dest.wide);
+ return (abs(mir_graph_->SRegToVReg(rl_src.s_reg_low) - mir_graph_->SRegToVReg(rl_dest.s_reg_low)) == 1);
+}
+
} // namespace art
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 3bd0298a22..522bacb223 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -19,6 +19,7 @@
#include "dex/quick/mir_to_lir-inl.h"
#include "entrypoints/quick/quick_entrypoints.h"
#include "mirror/array.h"
+#include "mirror/object-inl.h"
#include "verifier/method_verifier.h"
namespace art {
@@ -206,13 +207,43 @@ void Mir2Lir::GenNewArray(uint32_t type_idx, RegLocation rl_dest,
RegLocation rl_src) {
FlushAllRegs(); /* Everything to home location */
ThreadOffset func_offset(-1);
- if (cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, *cu_->dex_file,
+ const DexFile* dex_file = cu_->dex_file;
+ CompilerDriver* driver = cu_->compiler_driver;
+ if (cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, *dex_file,
type_idx)) {
- func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocArray);
+ bool is_type_initialized; // Ignored as an array does not have an initializer.
+ bool use_direct_type_ptr;
+ uintptr_t direct_type_ptr;
+ if (kEmbedClassInCode &&
+ driver->CanEmbedTypeInCode(*dex_file, type_idx,
+ &is_type_initialized, &use_direct_type_ptr, &direct_type_ptr)) {
+ // The fast path.
+ if (!use_direct_type_ptr) {
+ // Use the literal pool and a PC-relative load from a data word.
+ LIR* data_target = ScanLiteralPool(class_literal_list_, type_idx, 0);
+ if (data_target == nullptr) {
+ data_target = AddWordData(&class_literal_list_, type_idx);
+ }
+ LIR* load_pc_rel = OpPcRelLoad(TargetReg(kArg0), data_target);
+ AppendLIR(load_pc_rel);
+ func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocArrayResolved);
+ CallRuntimeHelperRegMethodRegLocation(func_offset, TargetReg(kArg0), rl_src, true);
+ } else {
+ // Use the direct pointer.
+ func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocArrayResolved);
+ CallRuntimeHelperImmMethodRegLocation(func_offset, direct_type_ptr, rl_src, true);
+ }
+ } else {
+ // The slow path.
+ DCHECK_EQ(func_offset.Int32Value(), -1);
+ func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocArray);
+ CallRuntimeHelperImmMethodRegLocation(func_offset, type_idx, rl_src, true);
+ }
+ DCHECK_NE(func_offset.Int32Value(), -1);
} else {
func_offset= QUICK_ENTRYPOINT_OFFSET(pAllocArrayWithAccessCheck);
+ CallRuntimeHelperImmMethodRegLocation(func_offset, type_idx, rl_src, true);
}
- CallRuntimeHelperImmMethodRegLocation(func_offset, type_idx, rl_src, true);
RegLocation rl_result = GetReturn(false);
StoreValue(rl_dest, rl_result);
}
@@ -883,13 +914,53 @@ void Mir2Lir::GenNewInstance(uint32_t type_idx, RegLocation rl_dest) {
// alloc will always check for resolution, do we also need to verify
// access because the verifier was unable to?
ThreadOffset func_offset(-1);
- if (cu_->compiler_driver->CanAccessInstantiableTypeWithoutChecks(
- cu_->method_idx, *cu_->dex_file, type_idx)) {
- func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObject);
+ const DexFile* dex_file = cu_->dex_file;
+ CompilerDriver* driver = cu_->compiler_driver;
+ if (driver->CanAccessInstantiableTypeWithoutChecks(
+ cu_->method_idx, *dex_file, type_idx)) {
+ bool is_type_initialized;
+ bool use_direct_type_ptr;
+ uintptr_t direct_type_ptr;
+ if (kEmbedClassInCode &&
+ driver->CanEmbedTypeInCode(*dex_file, type_idx,
+ &is_type_initialized, &use_direct_type_ptr, &direct_type_ptr)) {
+ // The fast path.
+ if (!use_direct_type_ptr) {
+ // Use the literal pool and a PC-relative load from a data word.
+ LIR* data_target = ScanLiteralPool(class_literal_list_, type_idx, 0);
+ if (data_target == nullptr) {
+ data_target = AddWordData(&class_literal_list_, type_idx);
+ }
+ LIR* load_pc_rel = OpPcRelLoad(TargetReg(kArg0), data_target);
+ AppendLIR(load_pc_rel);
+ if (!is_type_initialized) {
+ func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObjectResolved);
+ CallRuntimeHelperRegMethod(func_offset, TargetReg(kArg0), true);
+ } else {
+ func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObjectInitialized);
+ CallRuntimeHelperRegMethod(func_offset, TargetReg(kArg0), true);
+ }
+ } else {
+ // Use the direct pointer.
+ if (!is_type_initialized) {
+ func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObjectResolved);
+ CallRuntimeHelperImmMethod(func_offset, direct_type_ptr, true);
+ } else {
+ func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObjectInitialized);
+ CallRuntimeHelperImmMethod(func_offset, direct_type_ptr, true);
+ }
+ }
+ } else {
+ // The slow path.
+ DCHECK_EQ(func_offset.Int32Value(), -1);
+ func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObject);
+ CallRuntimeHelperImmMethod(func_offset, type_idx, true);
+ }
+ DCHECK_NE(func_offset.Int32Value(), -1);
} else {
func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObjectWithAccessCheck);
+ CallRuntimeHelperImmMethod(func_offset, type_idx, true);
}
- CallRuntimeHelperImmMethod(func_offset, type_idx, true);
RegLocation rl_result = GetReturn(false);
StoreValue(rl_dest, rl_result);
}
@@ -1092,8 +1163,7 @@ void Mir2Lir::GenCheckCast(uint32_t insn_idx, uint32_t type_idx, RegLocation rl_
// Note: currently type_known_final is unused, as optimizing will only improve the performance
// of the exception throw path.
DexCompilationUnit* cu = mir_graph_->GetCurrentDexCompilationUnit();
- const MethodReference mr(cu->GetDexFile(), cu->GetDexMethodIndex());
- if (!needs_access_check && cu_->compiler_driver->IsSafeCast(mr, insn_idx)) {
+ if (!needs_access_check && cu_->compiler_driver->IsSafeCast(cu, insn_idx)) {
// Verifier type analysis proved this check cast would never cause an exception.
return;
}
@@ -1341,6 +1411,9 @@ void Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest,
}
rl_result = GenDivRem(rl_dest, rl_src1.low_reg, rl_src2.low_reg, op == kOpDiv);
done = true;
+ } else if (cu_->instruction_set == kX86) {
+ rl_result = GenDivRem(rl_dest, rl_src1, rl_src2, op == kOpDiv, check_zero);
+ done = true;
} else if (cu_->instruction_set == kThumb2) {
if (cu_->GetInstructionSetFeatures().HasDivideInstruction()) {
// Use ARM SDIV instruction for division. For remainder we also need to
@@ -1382,30 +1455,12 @@ void Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest,
* or produce corresponding Thumb instructions directly.
*/
-static bool IsPowerOfTwo(int x) {
- return (x & (x - 1)) == 0;
-}
-
// Returns true if no more than two bits are set in 'x'.
static bool IsPopCountLE2(unsigned int x) {
x &= x - 1;
return (x & (x - 1)) == 0;
}
-// Returns the index of the lowest set bit in 'x'.
-static int32_t LowestSetBit(uint32_t x) {
- int bit_posn = 0;
- while ((x & 0xf) == 0) {
- bit_posn += 4;
- x >>= 4;
- }
- while ((x & 1) == 0) {
- bit_posn++;
- x >>= 1;
- }
- return bit_posn;
-}
-
// Returns true if it added instructions to 'cu' to divide 'rl_src' by 'lit'
// and store the result in 'rl_dest'.
bool Mir2Lir::HandleEasyDivRem(Instruction::Code dalvik_opcode, bool is_div,
@@ -1609,6 +1664,9 @@ void Mir2Lir::GenArithOpIntLit(Instruction::Code opcode, RegLocation rl_dest, Re
rl_src = LoadValue(rl_src, kCoreReg);
rl_result = GenDivRemLit(rl_dest, rl_src.low_reg, lit, is_div);
done = true;
+ } else if (cu_->instruction_set == kX86) {
+ rl_result = GenDivRemLit(rl_dest, rl_src, lit, is_div);
+ done = true;
} else if (cu_->instruction_set == kThumb2) {
if (cu_->GetInstructionSetFeatures().HasDivideInstruction()) {
// Use ARM SDIV instruction for division. For remainder we also need to
@@ -1677,7 +1735,7 @@ void Mir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest,
case Instruction::ADD_LONG:
case Instruction::ADD_LONG_2ADDR:
if (cu_->instruction_set != kThumb2) {
- GenAddLong(rl_dest, rl_src1, rl_src2);
+ GenAddLong(opcode, rl_dest, rl_src1, rl_src2);
return;
}
first_op = kOpAdd;
@@ -1686,7 +1744,7 @@ void Mir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest,
case Instruction::SUB_LONG:
case Instruction::SUB_LONG_2ADDR:
if (cu_->instruction_set != kThumb2) {
- GenSubLong(rl_dest, rl_src1, rl_src2);
+ GenSubLong(opcode, rl_dest, rl_src1, rl_src2);
return;
}
first_op = kOpSub;
@@ -1694,8 +1752,8 @@ void Mir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest,
break;
case Instruction::MUL_LONG:
case Instruction::MUL_LONG_2ADDR:
- if (cu_->instruction_set == kThumb2) {
- GenMulLong(rl_dest, rl_src1, rl_src2);
+ if (cu_->instruction_set != kMips) {
+ GenMulLong(opcode, rl_dest, rl_src1, rl_src2);
return;
} else {
call_out = true;
@@ -1721,7 +1779,7 @@ void Mir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest,
case Instruction::AND_LONG_2ADDR:
case Instruction::AND_LONG:
if (cu_->instruction_set == kX86) {
- return GenAndLong(rl_dest, rl_src1, rl_src2);
+ return GenAndLong(opcode, rl_dest, rl_src1, rl_src2);
}
first_op = kOpAnd;
second_op = kOpAnd;
@@ -1729,7 +1787,7 @@ void Mir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest,
case Instruction::OR_LONG:
case Instruction::OR_LONG_2ADDR:
if (cu_->instruction_set == kX86) {
- GenOrLong(rl_dest, rl_src1, rl_src2);
+ GenOrLong(opcode, rl_dest, rl_src1, rl_src2);
return;
}
first_op = kOpOr;
@@ -1738,7 +1796,7 @@ void Mir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest,
case Instruction::XOR_LONG:
case Instruction::XOR_LONG_2ADDR:
if (cu_->instruction_set == kX86) {
- GenXorLong(rl_dest, rl_src1, rl_src2);
+ GenXorLong(opcode, rl_dest, rl_src1, rl_src2);
return;
}
first_op = kOpXor;
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index d942a24a18..4bc1a37d81 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -142,6 +142,30 @@ void Mir2Lir::CallRuntimeHelperImmMethod(ThreadOffset helper_offset, int arg0, b
CallHelper(r_tgt, helper_offset, safepoint_pc);
}
+void Mir2Lir::CallRuntimeHelperRegMethod(ThreadOffset helper_offset, int arg0, bool safepoint_pc) {
+ int r_tgt = CallHelperSetup(helper_offset);
+ DCHECK_NE(TargetReg(kArg1), arg0);
+ if (TargetReg(kArg0) != arg0) {
+ OpRegCopy(TargetReg(kArg0), arg0);
+ }
+ LoadCurrMethodDirect(TargetReg(kArg1));
+ ClobberCallerSave();
+ CallHelper(r_tgt, helper_offset, safepoint_pc);
+}
+
+void Mir2Lir::CallRuntimeHelperRegMethodRegLocation(ThreadOffset helper_offset, int arg0,
+ RegLocation arg2, bool safepoint_pc) {
+ int r_tgt = CallHelperSetup(helper_offset);
+ DCHECK_NE(TargetReg(kArg1), arg0);
+ if (TargetReg(kArg0) != arg0) {
+ OpRegCopy(TargetReg(kArg0), arg0);
+ }
+ LoadCurrMethodDirect(TargetReg(kArg1));
+ LoadValueDirectFixed(arg2, TargetReg(kArg2));
+ ClobberCallerSave();
+ CallHelper(r_tgt, helper_offset, safepoint_pc);
+}
+
void Mir2Lir::CallRuntimeHelperRegLocationRegLocation(ThreadOffset helper_offset, RegLocation arg0,
RegLocation arg1, bool safepoint_pc) {
int r_tgt = CallHelperSetup(helper_offset);
diff --git a/compiler/dex/quick/gen_loadstore.cc b/compiler/dex/quick/gen_loadstore.cc
index 8f2f6adba8..65582ddefd 100644
--- a/compiler/dex/quick/gen_loadstore.cc
+++ b/compiler/dex/quick/gen_loadstore.cc
@@ -294,6 +294,53 @@ void Mir2Lir::StoreValueWide(RegLocation rl_dest, RegLocation rl_src) {
}
}
+void Mir2Lir::StoreFinalValueWide(RegLocation rl_dest, RegLocation rl_src) {
+ DCHECK_EQ(IsFpReg(rl_src.low_reg), IsFpReg(rl_src.high_reg));
+ DCHECK(rl_dest.wide);
+ DCHECK(rl_src.wide);
+ DCHECK_EQ(rl_src.location, kLocPhysReg);
+
+ if (rl_dest.location == kLocPhysReg) {
+ OpRegCopyWide(rl_dest.low_reg, rl_dest.high_reg, rl_src.low_reg, rl_src.high_reg);
+ } else {
+ // Just re-assign the registers. Dest gets Src's regs.
+ rl_dest.low_reg = rl_src.low_reg;
+ rl_dest.high_reg = rl_src.high_reg;
+ rl_dest.location = kLocPhysReg;
+ Clobber(rl_src.low_reg);
+ Clobber(rl_src.high_reg);
+ }
+
+ // Dest is now live and dirty (until/if we flush it to home location).
+ MarkLive(rl_dest.low_reg, rl_dest.s_reg_low);
+
+ // Does this wide value live in two registers (or one vector one)?
+ if (rl_dest.low_reg != rl_dest.high_reg) {
+ MarkLive(rl_dest.high_reg, GetSRegHi(rl_dest.s_reg_low));
+ MarkDirty(rl_dest);
+ MarkPair(rl_dest.low_reg, rl_dest.high_reg);
+ } else {
+ // This must be an x86 vector register value,
+ DCHECK(IsFpReg(rl_dest.low_reg) && (cu_->instruction_set == kX86));
+ MarkDirty(rl_dest);
+ }
+
+ ResetDefLocWide(rl_dest);
+ if ((IsDirty(rl_dest.low_reg) ||
+ IsDirty(rl_dest.high_reg)) &&
+ (oat_live_out(rl_dest.s_reg_low) ||
+ oat_live_out(GetSRegHi(rl_dest.s_reg_low)))) {
+ LIR *def_start = last_lir_insn_;
+ DCHECK_EQ((mir_graph_->SRegToVReg(rl_dest.s_reg_low)+1),
+ mir_graph_->SRegToVReg(GetSRegHi(rl_dest.s_reg_low)));
+ StoreBaseDispWide(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low),
+ rl_dest.low_reg, rl_dest.high_reg);
+ MarkClean(rl_dest);
+ LIR *def_end = last_lir_insn_;
+ MarkDefWide(rl_dest, def_start, def_end);
+ }
+}
+
/* Utilities to load the current Method* */
void Mir2Lir::LoadCurrMethodDirect(int r_tgt) {
LoadValueDirectFixed(mir_graph_->GetMethodLoc(), r_tgt);
@@ -303,4 +350,47 @@ RegLocation Mir2Lir::LoadCurrMethod() {
return LoadValue(mir_graph_->GetMethodLoc(), kCoreReg);
}
+RegLocation Mir2Lir::ForceTemp(RegLocation loc) {
+ DCHECK(!loc.wide);
+ DCHECK(loc.location == kLocPhysReg);
+ DCHECK(!IsFpReg(loc.low_reg));
+ DCHECK(!IsFpReg(loc.high_reg));
+ if (IsTemp(loc.low_reg)) {
+ Clobber(loc.low_reg);
+ } else {
+ int temp_low = AllocTemp();
+ OpRegCopy(temp_low, loc.low_reg);
+ loc.low_reg = temp_low;
+ }
+
+ // Ensure that this doesn't represent the original SR any more.
+ loc.s_reg_low = INVALID_SREG;
+ return loc;
+}
+
+RegLocation Mir2Lir::ForceTempWide(RegLocation loc) {
+ DCHECK(loc.wide);
+ DCHECK(loc.location == kLocPhysReg);
+ DCHECK(!IsFpReg(loc.low_reg));
+ DCHECK(!IsFpReg(loc.high_reg));
+ if (IsTemp(loc.low_reg)) {
+ Clobber(loc.low_reg);
+ } else {
+ int temp_low = AllocTemp();
+ OpRegCopy(temp_low, loc.low_reg);
+ loc.low_reg = temp_low;
+ }
+ if (IsTemp(loc.high_reg)) {
+ Clobber(loc.high_reg);
+ } else {
+ int temp_high = AllocTemp();
+ OpRegCopy(temp_high, loc.high_reg);
+ loc.high_reg = temp_high;
+ }
+
+ // Ensure that this doesn't represent the original SR any more.
+ loc.s_reg_low = INVALID_SREG;
+ return loc;
+}
+
} // namespace art
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index a5a14d5c0e..aca93f51d3 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -94,9 +94,9 @@ class MipsMir2Lir : public Mir2Lir {
RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark);
void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_src1, RegLocation rl_shift);
- void GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- void GenAndLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenMulLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenAddLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenAndLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_src1, RegLocation rl_src2);
void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
@@ -110,9 +110,9 @@ class MipsMir2Lir : public Mir2Lir {
bool GenInlinedPeek(CallInfo* info, OpSize size);
bool GenInlinedPoke(CallInfo* info, OpSize size);
void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
- void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- void GenXorLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenOrLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenSubLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenXorLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base, int offset,
ThrowKind kind);
RegLocation GenDivRem(RegLocation rl_dest, int reg_lo, int reg_hi, bool is_div);
@@ -175,6 +175,9 @@ class MipsMir2Lir : public Mir2Lir {
private:
void ConvertShortToLongBranch(LIR* lir);
+ RegLocation GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
+ RegLocation rl_src2, bool is_div, bool check_zero);
+ RegLocation GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div);
};
} // namespace art
diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc
index 180d56c782..013041a9a5 100644
--- a/compiler/dex/quick/mips/int_mips.cc
+++ b/compiler/dex/quick/mips/int_mips.cc
@@ -250,6 +250,17 @@ RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, int reg1, int lit,
return rl_result;
}
+RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
+ RegLocation rl_src2, bool is_div, bool check_zero) {
+ LOG(FATAL) << "Unexpected use of GenDivRem for Mips";
+ return rl_dest;
+}
+
+RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) {
+ LOG(FATAL) << "Unexpected use of GenDivRemLit for Mips";
+ return rl_dest;
+}
+
void MipsMir2Lir::OpLea(int rBase, int reg1, int reg2, int scale, int offset) {
LOG(FATAL) << "Unexpected use of OpLea for Arm";
}
@@ -356,13 +367,13 @@ LIR* MipsMir2Lir::OpIT(ConditionCode cond, const char* guide) {
return NULL;
}
-void MipsMir2Lir::GenMulLong(RegLocation rl_dest, RegLocation rl_src1,
- RegLocation rl_src2) {
+void MipsMir2Lir::GenMulLong(Instruction::Code opcode, RegLocation rl_dest,
+ RegLocation rl_src1, RegLocation rl_src2) {
LOG(FATAL) << "Unexpected use of GenMulLong for Mips";
}
-void MipsMir2Lir::GenAddLong(RegLocation rl_dest, RegLocation rl_src1,
- RegLocation rl_src2) {
+void MipsMir2Lir::GenAddLong(Instruction::Code opcode, RegLocation rl_dest,
+ RegLocation rl_src1, RegLocation rl_src2) {
rl_src1 = LoadValueWide(rl_src1, kCoreReg);
rl_src2 = LoadValueWide(rl_src2, kCoreReg);
RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
@@ -383,8 +394,8 @@ void MipsMir2Lir::GenAddLong(RegLocation rl_dest, RegLocation rl_src1,
StoreValueWide(rl_dest, rl_result);
}
-void MipsMir2Lir::GenSubLong(RegLocation rl_dest, RegLocation rl_src1,
- RegLocation rl_src2) {
+void MipsMir2Lir::GenSubLong(Instruction::Code opcode, RegLocation rl_dest,
+ RegLocation rl_src1, RegLocation rl_src2) {
rl_src1 = LoadValueWide(rl_src1, kCoreReg);
rl_src2 = LoadValueWide(rl_src2, kCoreReg);
RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
@@ -425,18 +436,19 @@ void MipsMir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
StoreValueWide(rl_dest, rl_result);
}
-void MipsMir2Lir::GenAndLong(RegLocation rl_dest, RegLocation rl_src1,
+void MipsMir2Lir::GenAndLong(Instruction::Code opcode, RegLocation rl_dest,
+ RegLocation rl_src1,
RegLocation rl_src2) {
LOG(FATAL) << "Unexpected use of GenAndLong for Mips";
}
-void MipsMir2Lir::GenOrLong(RegLocation rl_dest, RegLocation rl_src1,
- RegLocation rl_src2) {
+void MipsMir2Lir::GenOrLong(Instruction::Code opcode, RegLocation rl_dest,
+ RegLocation rl_src1, RegLocation rl_src2) {
LOG(FATAL) << "Unexpected use of GenOrLong for Mips";
}
-void MipsMir2Lir::GenXorLong(RegLocation rl_dest, RegLocation rl_src1,
- RegLocation rl_src2) {
+void MipsMir2Lir::GenXorLong(Instruction::Code opcode, RegLocation rl_dest,
+ RegLocation rl_src1, RegLocation rl_src2) {
LOG(FATAL) << "Unexpected use of GenXorLong for Mips";
}
diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc
index 1aee06c89a..b744adcd97 100644
--- a/compiler/dex/quick/mips/target_mips.cc
+++ b/compiler/dex/quick/mips/target_mips.cc
@@ -15,12 +15,15 @@
*/
#include "codegen_mips.h"
+
+#include <inttypes.h>
+
+#include <string>
+
#include "dex/compiler_internals.h"
#include "dex/quick/mir_to_lir-inl.h"
#include "mips_lir.h"
-#include <string>
-
namespace art {
static int core_regs[] = {r_ZERO, r_AT, r_V0, r_V1, r_A0, r_A1, r_A2, r_A3,
@@ -203,9 +206,9 @@ std::string MipsMir2Lir::BuildInsnString(const char *fmt, LIR *lir, unsigned cha
snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
break;
case 't':
- snprintf(tbuf, arraysize(tbuf), "0x%08x (L%p)",
- reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 2),
- lir->target);
+ snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
+ reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
+ lir->target);
break;
case 'T':
snprintf(tbuf, arraysize(tbuf), "0x%08x", operand << 2);
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 6281eff873..1f4122d7a3 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -342,8 +342,8 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list
bool is_safe = is_null; // Always safe to store null.
if (!is_safe) {
// Check safety from verifier type information.
- const MethodReference mr(cu_->dex_file, cu_->method_idx);
- is_safe = cu_->compiler_driver->IsSafeCast(mr, mir->offset);
+ const DexCompilationUnit* unit = mir_graph_->GetCurrentDexCompilationUnit();
+ is_safe = cu_->compiler_driver->IsSafeCast(unit, mir->offset);
}
if (is_null || is_safe) {
// Store of constant null doesn't require an assignability test and can be generated inline
@@ -762,11 +762,13 @@ bool Mir2Lir::MethodBlockCodeGen(BasicBlock* bb) {
// Combine check and work halves of throwing instruction.
MIR* work_half = mir->meta.throw_insn;
mir->dalvikInsn.opcode = work_half->dalvikInsn.opcode;
+ mir->meta = work_half->meta; // Whatever the work_half had, we need to copy it.
opcode = work_half->dalvikInsn.opcode;
SSARepresentation* ssa_rep = work_half->ssa_rep;
work_half->ssa_rep = mir->ssa_rep;
mir->ssa_rep = ssa_rep;
work_half->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpCheckPart2);
+ work_half->meta.throw_insn = mir;
}
if (opcode >= kMirOpFirst) {
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index c157327109..bcd0eb190e 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -529,6 +529,9 @@ class Mir2Lir : public Backend {
bool safepoint_pc);
void CallRuntimeHelperImmMethod(ThreadOffset helper_offset, int arg0,
bool safepoint_pc);
+ void CallRuntimeHelperRegMethod(ThreadOffset helper_offset, int arg0, bool safepoint_pc);
+ void CallRuntimeHelperRegMethodRegLocation(ThreadOffset helper_offset, int arg0,
+ RegLocation arg2, bool safepoint_pc);
void CallRuntimeHelperRegLocationRegLocation(ThreadOffset helper_offset,
RegLocation arg0, RegLocation arg1,
bool safepoint_pc);
@@ -627,6 +630,18 @@ class Mir2Lir : public Backend {
*/
void StoreValueWide(RegLocation rl_dest, RegLocation rl_src);
+ /**
+ * @brief Used to do the final store in a wide destination as per bytecode semantics.
+ * @see StoreValueWide
+ * @param rl_dest The destination dalvik register location.
+ * @param rl_src The source register location. It must be kLocPhysReg
+ *
+ * This is used for x86 two operand computations, where we have computed the correct
+ * register values that now need to be properly registered. This is used to avoid an
+ * extra pair of register copies that would result if StoreValueWide was called.
+ */
+ void StoreFinalValueWide(RegLocation rl_dest, RegLocation rl_src);
+
// Shared by all targets - implemented in mir_to_lir.cc.
void CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list);
void HandleExtendedMethodMIR(BasicBlock* bb, MIR* mir);
@@ -695,11 +710,14 @@ class Mir2Lir : public Backend {
// Required for target - Dalvik-level generators.
virtual void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_src1, RegLocation rl_src2) = 0;
- virtual void GenMulLong(RegLocation rl_dest, RegLocation rl_src1,
+ virtual void GenMulLong(Instruction::Code,
+ RegLocation rl_dest, RegLocation rl_src1,
RegLocation rl_src2) = 0;
- virtual void GenAddLong(RegLocation rl_dest, RegLocation rl_src1,
+ virtual void GenAddLong(Instruction::Code,
+ RegLocation rl_dest, RegLocation rl_src1,
RegLocation rl_src2) = 0;
- virtual void GenAndLong(RegLocation rl_dest, RegLocation rl_src1,
+ virtual void GenAndLong(Instruction::Code,
+ RegLocation rl_dest, RegLocation rl_src1,
RegLocation rl_src2) = 0;
virtual void GenArithOpDouble(Instruction::Code opcode,
RegLocation rl_dest, RegLocation rl_src1,
@@ -727,11 +745,14 @@ class Mir2Lir : public Backend {
virtual bool GenInlinedPeek(CallInfo* info, OpSize size) = 0;
virtual bool GenInlinedPoke(CallInfo* info, OpSize size) = 0;
virtual void GenNegLong(RegLocation rl_dest, RegLocation rl_src) = 0;
- virtual void GenOrLong(RegLocation rl_dest, RegLocation rl_src1,
+ virtual void GenOrLong(Instruction::Code,
+ RegLocation rl_dest, RegLocation rl_src1,
RegLocation rl_src2) = 0;
- virtual void GenSubLong(RegLocation rl_dest, RegLocation rl_src1,
+ virtual void GenSubLong(Instruction::Code,
+ RegLocation rl_dest, RegLocation rl_src1,
RegLocation rl_src2) = 0;
- virtual void GenXorLong(RegLocation rl_dest, RegLocation rl_src1,
+ virtual void GenXorLong(Instruction::Code,
+ RegLocation rl_dest, RegLocation rl_src1,
RegLocation rl_src2) = 0;
virtual LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base,
int offset, ThrowKind kind) = 0;
@@ -739,6 +760,25 @@ class Mir2Lir : public Backend {
bool is_div) = 0;
virtual RegLocation GenDivRemLit(RegLocation rl_dest, int reg_lo, int lit,
bool is_div) = 0;
+ /*
+ * @brief Generate an integer div or rem operation by a literal.
+ * @param rl_dest Destination Location.
+ * @param rl_src1 Numerator Location.
+ * @param rl_src2 Divisor Location.
+ * @param is_div 'true' if this is a division, 'false' for a remainder.
+ * @param check_zero 'true' if an exception should be generated if the divisor is 0.
+ */
+ virtual RegLocation GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
+ RegLocation rl_src2, bool is_div, bool check_zero) = 0;
+ /*
+ * @brief Generate an integer div or rem operation by a literal.
+ * @param rl_dest Destination Location.
+ * @param rl_src Numerator Location.
+ * @param lit Divisor.
+ * @param is_div 'true' if this is a division, 'false' for a remainder.
+ */
+ virtual RegLocation GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1,
+ int lit, bool is_div) = 0;
virtual void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1,
RegLocation rl_src2) = 0;
@@ -758,7 +798,14 @@ class Mir2Lir : public Backend {
virtual void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
bool is_double) = 0;
virtual void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) = 0;
+
+ /**
+ * @brief Lowers the kMirOpSelect MIR into LIR.
+ * @param bb The basic block in which the MIR is from.
+ * @param mir The MIR whose opcode is kMirOpSelect.
+ */
virtual void GenSelect(BasicBlock* bb, MIR* mir) = 0;
+
virtual void GenMemBarrier(MemBarrierKind barrier_kind) = 0;
virtual void GenMoveException(RegLocation rl_dest) = 0;
virtual void GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
@@ -835,6 +882,43 @@ class Mir2Lir : public Backend {
CompilationUnit* GetCompilationUnit() {
return cu_;
}
+ /*
+ * @brief Returns the index of the lowest set bit in 'x'.
+ * @param x Value to be examined.
+ * @returns The bit number of the lowest bit set in the value.
+ */
+ int32_t LowestSetBit(uint64_t x);
+ /*
+ * @brief Is this value a power of two?
+ * @param x Value to be examined.
+ * @returns 'true' if only 1 bit is set in the value.
+ */
+ bool IsPowerOfTwo(uint64_t x);
+ /*
+ * @brief Do these SRs overlap?
+ * @param rl_op1 One RegLocation
+ * @param rl_op2 The other RegLocation
+ * @return 'true' if the VR pairs overlap
+ *
+ * Check to see if a result pair has a misaligned overlap with an operand pair. This
+ * is not usual for dx to generate, but it is legal (for now). In a future rev of
+ * dex, we'll want to make this case illegal.
+ */
+ bool BadOverlap(RegLocation rl_op1, RegLocation rl_op2);
+
+ /*
+ * @brief Force a location (in a register) into a temporary register
+ * @param loc location of result
+ * @returns update location
+ */
+ RegLocation ForceTemp(RegLocation loc);
+
+ /*
+ * @brief Force a wide location (in registers) into temporary registers
+ * @param loc location of result
+ * @returns update location
+ */
+ RegLocation ForceTempWide(RegLocation loc);
private:
void GenInstanceofFinal(bool use_declaring_class, uint32_t type_idx, RegLocation rl_dest,
@@ -855,6 +939,7 @@ class Mir2Lir : public Backend {
// TODO: add accessors for these.
LIR* literal_list_; // Constants.
LIR* method_literal_list_; // Method literals requiring patching.
+ LIR* class_literal_list_; // Class literals requiring patching.
LIR* code_literal_list_; // Code literals requiring patching.
LIR* first_fixup_; // Doubly-linked list of LIR nodes requiring fixups.
diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc
index 1dcff652ba..c29d6c422a 100644
--- a/compiler/dex/quick/x86/assemble_x86.cc
+++ b/compiler/dex/quick/x86/assemble_x86.cc
@@ -211,6 +211,8 @@ ENCODING_MAP(Cmp, IS_LOAD, 0, 0,
#undef SHIFT_ENCODING_MAP
{ kX86Cmc, kNullary, NO_OPERAND, { 0, 0, 0xF5, 0, 0, 0, 0, 0}, "Cmc", "" },
+ { kX86Shld32RRI, kRegRegImmRev, IS_TERTIARY_OP | REG_DEF0_USE01 | SETS_CCODES, { 0, 0, 0x0F, 0xA4, 0, 0, 0, 1}, "Shld32", "!0r,!1r,!2d" },
+ { kX86Shrd32RRI, kRegRegImmRev, IS_TERTIARY_OP | REG_DEF0_USE01 | SETS_CCODES, { 0, 0, 0x0F, 0xAC, 0, 0, 0, 1}, "Shrd32", "!0r,!1r,!2d" },
{ kX86Test8RI, kRegImm, IS_BINARY_OP | REG_USE0 | SETS_CCODES, { 0, 0, 0xF6, 0, 0, 0, 0, 1}, "Test8RI", "!0r,!1d" },
{ kX86Test8MI, kMemImm, IS_LOAD | IS_TERTIARY_OP | REG_USE0 | SETS_CCODES, { 0, 0, 0xF6, 0, 0, 0, 0, 1}, "Test8MI", "[!0r+!1d],!2d" },
@@ -242,12 +244,13 @@ ENCODING_MAP(Cmp, IS_LOAD, 0, 0,
UNARY_ENCODING_MAP(Not, 0x2, IS_STORE, 0, R, kReg, IS_UNARY_OP | REG_DEF0_USE0, M, kMem, IS_BINARY_OP | REG_USE0, A, kArray, IS_QUAD_OP | REG_USE01, 0, 0, 0, 0, "", "", ""),
UNARY_ENCODING_MAP(Neg, 0x3, IS_STORE, SETS_CCODES, R, kReg, IS_UNARY_OP | REG_DEF0_USE0, M, kMem, IS_BINARY_OP | REG_USE0, A, kArray, IS_QUAD_OP | REG_USE01, 0, 0, 0, 0, "", "", ""),
- UNARY_ENCODING_MAP(Mul, 0x4, 0, SETS_CCODES, DaR, kRegRegReg, IS_UNARY_OP | REG_USE0, DaM, kRegRegMem, IS_BINARY_OP | REG_USE0, DaA, kRegRegArray, IS_QUAD_OP | REG_USE01, 0, REG_DEFA_USEA, REG_DEFAD_USEA, REG_DEFAD_USEA, "ax,al,", "dx:ax,ax,", "edx:eax,eax,"),
- UNARY_ENCODING_MAP(Imul, 0x5, 0, SETS_CCODES, DaR, kRegRegReg, IS_UNARY_OP | REG_USE0, DaM, kRegRegMem, IS_BINARY_OP | REG_USE0, DaA, kRegRegArray, IS_QUAD_OP | REG_USE01, 0, REG_DEFA_USEA, REG_DEFAD_USEA, REG_DEFAD_USEA, "ax,al,", "dx:ax,ax,", "edx:eax,eax,"),
- UNARY_ENCODING_MAP(Divmod, 0x6, 0, SETS_CCODES, DaR, kRegRegReg, IS_UNARY_OP | REG_USE0, DaM, kRegRegMem, IS_BINARY_OP | REG_USE0, DaA, kRegRegArray, IS_QUAD_OP | REG_USE01, 0, REG_DEFA_USEA, REG_DEFAD_USEAD, REG_DEFAD_USEAD, "ah:al,ax,", "dx:ax,dx:ax,", "edx:eax,edx:eax,"),
- UNARY_ENCODING_MAP(Idivmod, 0x7, 0, SETS_CCODES, DaR, kRegRegReg, IS_UNARY_OP | REG_USE0, DaM, kRegRegMem, IS_BINARY_OP | REG_USE0, DaA, kRegRegArray, IS_QUAD_OP | REG_USE01, 0, REG_DEFA_USEA, REG_DEFAD_USEAD, REG_DEFAD_USEAD, "ah:al,ax,", "dx:ax,dx:ax,", "edx:eax,edx:eax,"),
+ UNARY_ENCODING_MAP(Mul, 0x4, 0, SETS_CCODES, DaR, kReg, IS_UNARY_OP | REG_USE0, DaM, kMem, IS_BINARY_OP | REG_USE0, DaA, kArray, IS_QUAD_OP | REG_USE01, 0, REG_DEFA_USEA, REG_DEFAD_USEA, REG_DEFAD_USEA, "ax,al,", "dx:ax,ax,", "edx:eax,eax,"),
+ UNARY_ENCODING_MAP(Imul, 0x5, 0, SETS_CCODES, DaR, kReg, IS_UNARY_OP | REG_USE0, DaM, kMem, IS_BINARY_OP | REG_USE0, DaA, kArray, IS_QUAD_OP | REG_USE01, 0, REG_DEFA_USEA, REG_DEFAD_USEA, REG_DEFAD_USEA, "ax,al,", "dx:ax,ax,", "edx:eax,eax,"),
+ UNARY_ENCODING_MAP(Divmod, 0x6, 0, SETS_CCODES, DaR, kReg, IS_UNARY_OP | REG_USE0, DaM, kMem, IS_BINARY_OP | REG_USE0, DaA, kArray, IS_QUAD_OP | REG_USE01, 0, REG_DEFA_USEA, REG_DEFAD_USEAD, REG_DEFAD_USEAD, "ah:al,ax,", "dx:ax,dx:ax,", "edx:eax,edx:eax,"),
+ UNARY_ENCODING_MAP(Idivmod, 0x7, 0, SETS_CCODES, DaR, kReg, IS_UNARY_OP | REG_USE0, DaM, kMem, IS_BINARY_OP | REG_USE0, DaA, kArray, IS_QUAD_OP | REG_USE01, 0, REG_DEFA_USEA, REG_DEFAD_USEAD, REG_DEFAD_USEAD, "ah:al,ax,", "dx:ax,dx:ax,", "edx:eax,edx:eax,"),
#undef UNARY_ENCODING_MAP
+ { kx86Cdq32Da, kRegOpcode, NO_OPERAND | REG_DEFAD_USEA, { 0, 0, 0x99, 0, 0, 0, 0, 0 }, "Cdq", "" },
{ kX86Bswap32R, kRegOpcode, IS_UNARY_OP | REG_DEF0_USE0, { 0, 0, 0x0F, 0xC8, 0, 0, 0, 0 }, "Bswap32R", "!0r" },
{ kX86Push32R, kRegOpcode, IS_UNARY_OP | REG_USE0 | REG_USE_SP | REG_DEF_SP | IS_STORE, { 0, 0, 0x50, 0, 0, 0, 0, 0 }, "Push32R", "!0r" },
{ kX86Pop32R, kRegOpcode, IS_UNARY_OP | REG_DEF0 | REG_USE_SP | REG_DEF_SP | IS_LOAD, { 0, 0, 0x58, 0, 0, 0, 0, 0 }, "Pop32R", "!0r" },
@@ -287,6 +290,7 @@ ENCODING_MAP(Cmp, IS_LOAD, 0, 0,
EXT_0F_ENCODING_MAP(Subss, 0xF3, 0x5C, REG_DEF0),
EXT_0F_ENCODING_MAP(Divsd, 0xF2, 0x5E, REG_DEF0),
EXT_0F_ENCODING_MAP(Divss, 0xF3, 0x5E, REG_DEF0),
+ EXT_0F_ENCODING_MAP(Punpckldq, 0x66, 0x62, REG_DEF0),
{ kX86PsrlqRI, kRegImm, IS_BINARY_OP | REG_DEF0_USE0, { 0x66, 0, 0x0F, 0x73, 0, 2, 0, 1 }, "PsrlqRI", "!0r,!1d" },
{ kX86PsllqRI, kRegImm, IS_BINARY_OP | REG_DEF0_USE0, { 0x66, 0, 0x0F, 0x73, 0, 6, 0, 1 }, "PsllqRI", "!0r,!1d" },
@@ -421,6 +425,7 @@ int X86Mir2Lir::GetInsnSize(LIR* lir) {
case kThreadImm: // lir operands - 0: disp, 1: imm
return ComputeSize(entry, 0, 0x12345678, false); // displacement size is always 32bit
case kRegRegImm: // lir operands - 0: reg, 1: reg, 2: imm
+ case kRegRegImmRev:
return ComputeSize(entry, 0, 0, false);
case kRegMemImm: // lir operands - 0: reg, 1: base, 2: disp, 3: imm
return ComputeSize(entry, lir->operands[1], lir->operands[2], false);
@@ -641,7 +646,6 @@ void X86Mir2Lir::EmitOpMem(const X86EncodingMap* entry, uint8_t base, int disp)
DCHECK_NE(0x0F, entry->skeleton.opcode);
DCHECK_EQ(0, entry->skeleton.extra_opcode1);
DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- DCHECK_NE(rX86_SP, base);
EmitModrmDisp(entry->skeleton.modrm_opcode, base, disp);
DCHECK_EQ(0, entry->skeleton.ax_opcode);
DCHECK_EQ(0, entry->skeleton.immediate_bytes);
@@ -754,6 +758,22 @@ void X86Mir2Lir::EmitRegRegImm(const X86EncodingMap* entry,
EmitImm(entry, imm);
}
+void X86Mir2Lir::EmitRegRegImmRev(const X86EncodingMap* entry,
+ uint8_t reg1, uint8_t reg2, int32_t imm) {
+ EmitRegRegImm(entry, reg2, reg1, imm);
+}
+
+void X86Mir2Lir::EmitRegMemImm(const X86EncodingMap* entry,
+ uint8_t reg, uint8_t base, int disp, int32_t imm) {
+ EmitPrefixAndOpcode(entry);
+ DCHECK(!X86_FPREG(reg));
+ DCHECK_LT(reg, 8);
+ EmitModrmDisp(reg, base, disp);
+ DCHECK_EQ(0, entry->skeleton.modrm_opcode);
+ DCHECK_EQ(0, entry->skeleton.ax_opcode);
+ EmitImm(entry, imm);
+}
+
void X86Mir2Lir::EmitRegImm(const X86EncodingMap* entry, uint8_t reg, int imm) {
if (entry->skeleton.prefix1 != 0) {
code_buffer_.push_back(entry->skeleton.prefix1);
@@ -1185,9 +1205,16 @@ AssemblerStatus X86Mir2Lir::AssembleInstructions(CodeOffset start_addr) {
case kRegRegStore: // lir operands - 0: reg2, 1: reg1
EmitRegReg(entry, lir->operands[1], lir->operands[0]);
break;
+ case kRegRegImmRev:
+ EmitRegRegImmRev(entry, lir->operands[0], lir->operands[1], lir->operands[2]);
+ break;
case kRegRegImm:
EmitRegRegImm(entry, lir->operands[0], lir->operands[1], lir->operands[2]);
break;
+ case kRegMemImm:
+ EmitRegMemImm(entry, lir->operands[0], lir->operands[1], lir->operands[2],
+ lir->operands[3]);
+ break;
case kRegImm: // lir operands - 0: reg, 1: immediate
EmitRegImm(entry, lir->operands[0], lir->operands[1]);
break;
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 816f2d0c5c..6280b646f5 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -94,9 +94,9 @@ class X86Mir2Lir : public Mir2Lir {
RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark);
void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_src1, RegLocation rl_shift);
- void GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- void GenAndLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenMulLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenAddLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenAndLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_src1, RegLocation rl_src2);
void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
@@ -110,9 +110,9 @@ class X86Mir2Lir : public Mir2Lir {
bool GenInlinedPeek(CallInfo* info, OpSize size);
bool GenInlinedPoke(CallInfo* info, OpSize size);
void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
- void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
- void GenXorLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenOrLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenSubLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+ void GenXorLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base, int offset,
ThrowKind kind);
LIR* GenMemImmedCheck(ConditionCode c_code, int base, int offset, int check_value,
@@ -136,6 +136,49 @@ class X86Mir2Lir : public Mir2Lir {
void GenPackedSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src);
void GenSparseSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src);
void GenSpecialCase(BasicBlock* bb, MIR* mir, const InlineMethod& special);
+ /*
+ * @brief Generate a two address long operation with a constant value
+ * @param rl_dest location of result
+ * @param rl_src constant source operand
+ * @param op Opcode to be generated
+ */
+ void GenLongImm(RegLocation rl_dest, RegLocation rl_src, Instruction::Code op);
+ /*
+ * @brief Generate a three address long operation with a constant value
+ * @param rl_dest location of result
+ * @param rl_src1 source operand
+ * @param rl_src2 constant source operand
+ * @param op Opcode to be generated
+ */
+ void GenLongLongImm(RegLocation rl_dest, RegLocation rl_src1,
+ RegLocation rl_src2, Instruction::Code op);
+
+ /**
+ * @brief Generate a long arithmetic operation.
+ * @param rl_dest The destination.
+ * @param rl_src1 First operand.
+ * @param rl_src2 Second operand.
+ * @param op The DEX opcode for the operation.
+ * @param is_commutative The sources can be swapped if needed.
+ */
+ void GenLongArith(RegLocation rl_dest, RegLocation rl_src1,
+ RegLocation rl_src2, Instruction::Code op, bool is_commutative);
+
+ /**
+ * @brief Generate a two operand long arithmetic operation.
+ * @param rl_dest The destination.
+ * @param rl_src Second operand.
+ * @param op The DEX opcode for the operation.
+ */
+ void GenLongArith(RegLocation rl_dest, RegLocation rl_src, Instruction::Code op);
+
+ /**
+ * @brief Generate a long operation.
+ * @param rl_dest The destination. Must be in a register
+ * @param rl_src The other operand. May be in a register or in memory.
+ * @param op The DEX opcode for the operation.
+ */
+ void GenLongRegOrMemOp(RegLocation rl_dest, RegLocation rl_src, Instruction::Code op);
// Single operation generators.
LIR* OpUnconditionalBranch(LIR* target);
@@ -202,6 +245,8 @@ class X86Mir2Lir : public Mir2Lir {
void EmitRegThread(const X86EncodingMap* entry, uint8_t reg, int disp);
void EmitRegReg(const X86EncodingMap* entry, uint8_t reg1, uint8_t reg2);
void EmitRegRegImm(const X86EncodingMap* entry, uint8_t reg1, uint8_t reg2, int32_t imm);
+ void EmitRegRegImmRev(const X86EncodingMap* entry, uint8_t reg1, uint8_t reg2, int32_t imm);
+ void EmitRegMemImm(const X86EncodingMap* entry, uint8_t reg1, uint8_t base, int disp, int32_t imm);
void EmitRegImm(const X86EncodingMap* entry, uint8_t reg, int imm);
void EmitThreadImm(const X86EncodingMap* entry, int disp, int imm);
void EmitMovRegImm(const X86EncodingMap* entry, uint8_t reg, int imm);
@@ -230,6 +275,96 @@ class X86Mir2Lir : public Mir2Lir {
int64_t val, ConditionCode ccode);
void OpVectorRegCopyWide(uint8_t fp_reg, uint8_t low_reg, uint8_t high_reg);
void GenConstWide(RegLocation rl_dest, int64_t value);
+
+ /*
+ * @brief Return the correct x86 opcode for the Dex operation
+ * @param op Dex opcode for the operation
+ * @param loc Register location of the operand
+ * @param is_high_op 'true' if this is an operation on the high word
+ * @param value Immediate value for the operation. Used for byte variants
+ * @returns the correct x86 opcode to perform the operation
+ */
+ X86OpCode GetOpcode(Instruction::Code op, RegLocation loc, bool is_high_op, int32_t value);
+
+ /*
+ * @brief Return the correct x86 opcode for the Dex operation
+ * @param op Dex opcode for the operation
+ * @param dest location of the destination. May be register or memory.
+ * @param rhs Location for the rhs of the operation. May be in register or memory.
+ * @param is_high_op 'true' if this is an operation on the high word
+ * @returns the correct x86 opcode to perform the operation
+ * @note at most one location may refer to memory
+ */
+ X86OpCode GetOpcode(Instruction::Code op, RegLocation dest, RegLocation rhs,
+ bool is_high_op);
+
+ /*
+ * @brief Is this operation a no-op for this opcode and value
+ * @param op Dex opcode for the operation
+ * @param value Immediate value for the operation.
+ * @returns 'true' if the operation will have no effect
+ */
+ bool IsNoOp(Instruction::Code op, int32_t value);
+
+ /*
+ * @brief Dump a RegLocation using printf
+ * @param loc Register location to dump
+ */
+ static void DumpRegLocation(RegLocation loc);
+
+ /**
+ * @brief Calculate magic number and shift for a given divisor
+ * @param divisor divisor number for calculation
+ * @param magic hold calculated magic number
+ * @param shift hold calculated shift
+ */
+ void CalculateMagicAndShift(int divisor, int& magic, int& shift);
+
+ /*
+ * @brief Generate an integer div or rem operation.
+ * @param rl_dest Destination Location.
+ * @param rl_src1 Numerator Location.
+ * @param rl_src2 Divisor Location.
+ * @param is_div 'true' if this is a division, 'false' for a remainder.
+ * @param check_zero 'true' if an exception should be generated if the divisor is 0.
+ */
+ RegLocation GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
+ RegLocation rl_src2, bool is_div, bool check_zero);
+
+ /*
+ * @brief Generate an integer div or rem operation by a literal.
+ * @param rl_dest Destination Location.
+ * @param rl_src Numerator Location.
+ * @param lit Divisor.
+ * @param is_div 'true' if this is a division, 'false' for a remainder.
+ */
+ RegLocation GenDivRemLit(RegLocation rl_dest, RegLocation rl_src, int lit, bool is_div);
+
+ /*
+ * Generate code to implement long shift operations.
+ * @param opcode The DEX opcode to specify the shift type.
+ * @param rl_dest The destination.
+ * @param rl_src The value to be shifted.
+ * @param shift_amount How much to shift.
+ * @returns the RegLocation of the result.
+ */
+ RegLocation GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
+ RegLocation rl_src, int shift_amount);
+ /*
+ * Generate an imul of a register by a constant or a better sequence.
+ * @param dest Destination Register.
+ * @param src Source Register.
+ * @param val Constant multiplier.
+ */
+ void GenImulRegImm(int dest, int src, int val);
+ /*
+ * Generate an imul of a memory location by a constant or a better sequence.
+ * @param dest Destination Register.
+ * @param sreg Symbolic register.
+ * @param displacement Displacement on stack of Symbolic Register.
+ * @param val Constant multiplier.
+ */
+ void GenImulMemImm(int dest, int sreg, int displacement, int val);
};
} // namespace art
diff --git a/compiler/dex/quick/x86/fp_x86.cc b/compiler/dex/quick/x86/fp_x86.cc
index 6272498065..006fe76f1b 100644
--- a/compiler/dex/quick/x86/fp_x86.cc
+++ b/compiler/dex/quick/x86/fp_x86.cc
@@ -303,7 +303,7 @@ void X86Mir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
rl_src2 = LoadValue(rl_src2, kFPReg);
NewLIR2(kX86UcomissRR, rl_src1.low_reg, rl_src2.low_reg);
}
- ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
+ ConditionCode ccode = mir->meta.ccode;
switch (ccode) {
case kCondEq:
if (!gt_bias) {
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 01479a9021..e665f700ba 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -180,14 +180,104 @@ void X86Mir2Lir::OpRegCopyWide(int dest_lo, int dest_hi,
}
void X86Mir2Lir::GenSelect(BasicBlock* bb, MIR* mir) {
- UNIMPLEMENTED(FATAL) << "Need codegen for GenSelect";
+ RegLocation rl_result;
+ RegLocation rl_src = mir_graph_->GetSrc(mir, 0);
+ RegLocation rl_dest = mir_graph_->GetDest(mir);
+ rl_src = LoadValue(rl_src, kCoreReg);
+
+ // The kMirOpSelect has two variants, one for constants and one for moves.
+ const bool is_constant_case = (mir->ssa_rep->num_uses == 1);
+
+ if (is_constant_case) {
+ int true_val = mir->dalvikInsn.vB;
+ int false_val = mir->dalvikInsn.vC;
+ rl_result = EvalLoc(rl_dest, kCoreReg, true);
+
+ /*
+ * 1) When the true case is zero and result_reg is not same as src_reg:
+ * xor result_reg, result_reg
+ * cmp $0, src_reg
+ * mov t1, $false_case
+ * cmovnz result_reg, t1
+ * 2) When the false case is zero and result_reg is not same as src_reg:
+ * xor result_reg, result_reg
+ * cmp $0, src_reg
+ * mov t1, $true_case
+ * cmovz result_reg, t1
+ * 3) All other cases (we do compare first to set eflags):
+ * cmp $0, src_reg
+ * mov result_reg, $true_case
+ * mov t1, $false_case
+ * cmovnz result_reg, t1
+ */
+ const bool result_reg_same_as_src = (rl_src.location == kLocPhysReg && rl_src.low_reg == rl_result.low_reg);
+ const bool true_zero_case = (true_val == 0 && false_val != 0 && !result_reg_same_as_src);
+ const bool false_zero_case = (false_val == 0 && true_val != 0 && !result_reg_same_as_src);
+ const bool catch_all_case = !(true_zero_case || false_zero_case);
+
+ if (true_zero_case || false_zero_case) {
+ OpRegReg(kOpXor, rl_result.low_reg, rl_result.low_reg);
+ }
+
+ if (true_zero_case || false_zero_case || catch_all_case) {
+ OpRegImm(kOpCmp, rl_src.low_reg, 0);
+ }
+
+ if (catch_all_case) {
+ OpRegImm(kOpMov, rl_result.low_reg, true_val);
+ }
+
+ if (true_zero_case || false_zero_case || catch_all_case) {
+ int immediateForTemp = false_zero_case ? true_val : false_val;
+ int temp1_reg = AllocTemp();
+ OpRegImm(kOpMov, temp1_reg, immediateForTemp);
+
+ ConditionCode cc = false_zero_case ? kCondEq : kCondNe;
+ OpCondRegReg(kOpCmov, cc, rl_result.low_reg, temp1_reg);
+
+ FreeTemp(temp1_reg);
+ }
+ } else {
+ RegLocation rl_true = mir_graph_->GetSrc(mir, 1);
+ RegLocation rl_false = mir_graph_->GetSrc(mir, 2);
+ rl_true = LoadValue(rl_true, kCoreReg);
+ rl_false = LoadValue(rl_false, kCoreReg);
+ rl_result = EvalLoc(rl_dest, kCoreReg, true);
+
+ /*
+ * 1) When true case is already in place:
+ * cmp $0, src_reg
+ * cmovnz result_reg, false_reg
+ * 2) When false case is already in place:
+ * cmp $0, src_reg
+ * cmovz result_reg, true_reg
+ * 3) When neither cases are in place:
+ * cmp $0, src_reg
+ * mov result_reg, true_reg
+ * cmovnz result_reg, false_reg
+ */
+
+ // kMirOpSelect is generated just for conditional cases when comparison is done with zero.
+ OpRegImm(kOpCmp, rl_src.low_reg, 0);
+
+ if (rl_result.low_reg == rl_true.low_reg) {
+ OpCondRegReg(kOpCmov, kCondNe, rl_result.low_reg, rl_false.low_reg);
+ } else if (rl_result.low_reg == rl_false.low_reg) {
+ OpCondRegReg(kOpCmov, kCondEq, rl_result.low_reg, rl_true.low_reg);
+ } else {
+ OpRegCopy(rl_result.low_reg, rl_true.low_reg);
+ OpCondRegReg(kOpCmov, kCondNe, rl_result.low_reg, rl_false.low_reg);
+ }
+ }
+
+ StoreValue(rl_dest, rl_result);
}
void X86Mir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) {
LIR* taken = &block_label_list_[bb->taken];
RegLocation rl_src1 = mir_graph_->GetSrcWide(mir, 0);
RegLocation rl_src2 = mir_graph_->GetSrcWide(mir, 2);
- ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
+ ConditionCode ccode = mir->meta.ccode;
if (rl_src1.is_const) {
std::swap(rl_src1, rl_src2);
@@ -284,18 +374,261 @@ void X86Mir2Lir::GenFusedLongCmpImmBranch(BasicBlock* bb, RegLocation rl_src1,
OpCmpImmBranch(ccode, low_reg, val_lo, taken);
}
+void X86Mir2Lir::CalculateMagicAndShift(int divisor, int& magic, int& shift) {
+ // It does not make sense to calculate magic and shift for zero divisor.
+ DCHECK_NE(divisor, 0);
+
+ /* According to H.S.Warren's Hacker's Delight Chapter 10 and
+ * T,Grablund, P.L.Montogomery's Division by invariant integers using multiplication.
+ * The magic number M and shift S can be calculated in the following way:
+ * Let nc be the most positive value of numerator(n) such that nc = kd - 1,
+ * where divisor(d) >=2.
+ * Let nc be the most negative value of numerator(n) such that nc = kd + 1,
+ * where divisor(d) <= -2.
+ * Thus nc can be calculated like:
+ * nc = 2^31 + 2^31 % d - 1, where d >= 2
+ * nc = -2^31 + (2^31 + 1) % d, where d >= 2.
+ *
+ * So the shift p is the smallest p satisfying
+ * 2^p > nc * (d - 2^p % d), where d >= 2
+ * 2^p > nc * (d + 2^p % d), where d <= -2.
+ *
+ * the magic number M is calcuated by
+ * M = (2^p + d - 2^p % d) / d, where d >= 2
+ * M = (2^p - d - 2^p % d) / d, where d <= -2.
+ *
+ * Notice that p is always bigger than or equal to 32, so we just return 32-p as
+ * the shift number S.
+ */
+
+ int32_t p = 31;
+ const uint32_t two31 = 0x80000000U;
+
+ // Initialize the computations.
+ uint32_t abs_d = (divisor >= 0) ? divisor : -divisor;
+ uint32_t tmp = two31 + (static_cast<uint32_t>(divisor) >> 31);
+ uint32_t abs_nc = tmp - 1 - tmp % abs_d;
+ uint32_t quotient1 = two31 / abs_nc;
+ uint32_t remainder1 = two31 % abs_nc;
+ uint32_t quotient2 = two31 / abs_d;
+ uint32_t remainder2 = two31 % abs_d;
+
+ /*
+ * To avoid handling both positive and negative divisor, Hacker's Delight
+ * introduces a method to handle these 2 cases together to avoid duplication.
+ */
+ uint32_t delta;
+ do {
+ p++;
+ quotient1 = 2 * quotient1;
+ remainder1 = 2 * remainder1;
+ if (remainder1 >= abs_nc) {
+ quotient1++;
+ remainder1 = remainder1 - abs_nc;
+ }
+ quotient2 = 2 * quotient2;
+ remainder2 = 2 * remainder2;
+ if (remainder2 >= abs_d) {
+ quotient2++;
+ remainder2 = remainder2 - abs_d;
+ }
+ delta = abs_d - remainder2;
+ } while (quotient1 < delta || (quotient1 == delta && remainder1 == 0));
+
+ magic = (divisor > 0) ? (quotient2 + 1) : (-quotient2 - 1);
+ shift = p - 32;
+}
+
RegLocation X86Mir2Lir::GenDivRemLit(RegLocation rl_dest, int reg_lo,
int lit, bool is_div) {
LOG(FATAL) << "Unexpected use of GenDivRemLit for x86";
return rl_dest;
}
+RegLocation X86Mir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src,
+ int imm, bool is_div) {
+ // Use a multiply (and fixup) to perform an int div/rem by a constant.
+
+ // We have to use fixed registers, so flush all the temps.
+ FlushAllRegs();
+ LockCallTemps(); // Prepare for explicit register usage.
+
+ // Assume that the result will be in EDX.
+ RegLocation rl_result = {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
+ r2, INVALID_REG, INVALID_SREG, INVALID_SREG};
+
+ // handle 0x80000000 / -1 special case.
+ LIR *minint_branch = 0;
+ if (imm == -1) {
+ if (is_div) {
+ LoadValueDirectFixed(rl_src, r0);
+ OpRegImm(kOpCmp, r0, 0x80000000);
+ minint_branch = NewLIR2(kX86Jcc8, 0, kX86CondEq);
+
+ // for x != MIN_INT, x / -1 == -x.
+ NewLIR1(kX86Neg32R, r0);
+
+ LIR* branch_around = NewLIR1(kX86Jmp8, 0);
+ // The target for cmp/jmp above.
+ minint_branch->target = NewLIR0(kPseudoTargetLabel);
+ // EAX already contains the right value (0x80000000),
+ branch_around->target = NewLIR0(kPseudoTargetLabel);
+ } else {
+ // x % -1 == 0.
+ LoadConstantNoClobber(r0, 0);
+ }
+ // For this case, return the result in EAX.
+ rl_result.low_reg = r0;
+ } else {
+ DCHECK(imm <= -2 || imm >= 2);
+ // Use H.S.Warren's Hacker's Delight Chapter 10 and
+ // T,Grablund, P.L.Montogomery's Division by invariant integers using multiplication.
+ int magic, shift;
+ CalculateMagicAndShift(imm, magic, shift);
+
+ /*
+ * For imm >= 2,
+ * int(n/imm) = floor(n/imm) = floor(M*n/2^S), while n > 0
+ * int(n/imm) = ceil(n/imm) = floor(M*n/2^S) +1, while n < 0.
+ * For imm <= -2,
+ * int(n/imm) = ceil(n/imm) = floor(M*n/2^S) +1 , while n > 0
+ * int(n/imm) = floor(n/imm) = floor(M*n/2^S), while n < 0.
+ * We implement this algorithm in the following way:
+ * 1. multiply magic number m and numerator n, get the higher 32bit result in EDX
+ * 2. if imm > 0 and magic < 0, add numerator to EDX
+ * if imm < 0 and magic > 0, sub numerator from EDX
+ * 3. if S !=0, SAR S bits for EDX
+ * 4. add 1 to EDX if EDX < 0
+ * 5. Thus, EDX is the quotient
+ */
+
+ // Numerator into EAX.
+ int numerator_reg = -1;
+ if (!is_div || (imm > 0 && magic < 0) || (imm < 0 && magic > 0)) {
+ // We will need the value later.
+ if (rl_src.location == kLocPhysReg) {
+ // We can use it directly.
+ DCHECK(rl_src.low_reg != r0 && rl_src.low_reg != r2);
+ numerator_reg = rl_src.low_reg;
+ } else {
+ LoadValueDirectFixed(rl_src, r1);
+ numerator_reg = r1;
+ }
+ OpRegCopy(r0, numerator_reg);
+ } else {
+ // Only need this once. Just put it into EAX.
+ LoadValueDirectFixed(rl_src, r0);
+ }
+
+ // EDX = magic.
+ LoadConstantNoClobber(r2, magic);
+
+ // EDX:EAX = magic & dividend.
+ NewLIR1(kX86Imul32DaR, r2);
+
+ if (imm > 0 && magic < 0) {
+ // Add numerator to EDX.
+ DCHECK_NE(numerator_reg, -1);
+ NewLIR2(kX86Add32RR, r2, numerator_reg);
+ } else if (imm < 0 && magic > 0) {
+ DCHECK_NE(numerator_reg, -1);
+ NewLIR2(kX86Sub32RR, r2, numerator_reg);
+ }
+
+ // Do we need the shift?
+ if (shift != 0) {
+ // Shift EDX by 'shift' bits.
+ NewLIR2(kX86Sar32RI, r2, shift);
+ }
+
+ // Add 1 to EDX if EDX < 0.
+
+ // Move EDX to EAX.
+ OpRegCopy(r0, r2);
+
+ // Move sign bit to bit 0, zeroing the rest.
+ NewLIR2(kX86Shr32RI, r2, 31);
+
+ // EDX = EDX + EAX.
+ NewLIR2(kX86Add32RR, r2, r0);
+
+ // Quotient is in EDX.
+ if (!is_div) {
+ // We need to compute the remainder.
+ // Remainder is divisor - (quotient * imm).
+ DCHECK_NE(numerator_reg, -1);
+ OpRegCopy(r0, numerator_reg);
+
+ // EAX = numerator * imm.
+ OpRegRegImm(kOpMul, r2, r2, imm);
+
+ // EDX -= EAX.
+ NewLIR2(kX86Sub32RR, r0, r2);
+
+ // For this case, return the result in EAX.
+ rl_result.low_reg = r0;
+ }
+ }
+
+ return rl_result;
+}
+
RegLocation X86Mir2Lir::GenDivRem(RegLocation rl_dest, int reg_lo,
int reg_hi, bool is_div) {
LOG(FATAL) << "Unexpected use of GenDivRem for x86";
return rl_dest;
}
+RegLocation X86Mir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
+ RegLocation rl_src2, bool is_div, bool check_zero) {
+ // We have to use fixed registers, so flush all the temps.
+ FlushAllRegs();
+ LockCallTemps(); // Prepare for explicit register usage.
+
+ // Load LHS into EAX.
+ LoadValueDirectFixed(rl_src1, r0);
+
+ // Load RHS into EBX.
+ LoadValueDirectFixed(rl_src2, r1);
+
+ // Copy LHS sign bit into EDX.
+ NewLIR0(kx86Cdq32Da);
+
+ if (check_zero) {
+ // Handle division by zero case.
+ GenImmedCheck(kCondEq, r1, 0, kThrowDivZero);
+ }
+
+ // Have to catch 0x80000000/-1 case, or we will get an exception!
+ OpRegImm(kOpCmp, r1, -1);
+ LIR *minus_one_branch = NewLIR2(kX86Jcc8, 0, kX86CondNe);
+
+ // RHS is -1.
+ OpRegImm(kOpCmp, r0, 0x80000000);
+ LIR * minint_branch = NewLIR2(kX86Jcc8, 0, kX86CondNe);
+
+ // In 0x80000000/-1 case.
+ if (!is_div) {
+ // For DIV, EAX is already right. For REM, we need EDX 0.
+ LoadConstantNoClobber(r2, 0);
+ }
+ LIR* done = NewLIR1(kX86Jmp8, 0);
+
+ // Expected case.
+ minus_one_branch->target = NewLIR0(kPseudoTargetLabel);
+ minint_branch->target = minus_one_branch->target;
+ NewLIR1(kX86Idivmod32DaR, r1);
+ done->target = NewLIR0(kPseudoTargetLabel);
+
+ // Result is in EAX for div and EDX for rem.
+ RegLocation rl_result = {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
+ r0, INVALID_REG, INVALID_SREG, INVALID_SREG};
+ if (!is_div) {
+ rl_result.low_reg = r2;
+ }
+ return rl_result;
+}
+
bool X86Mir2Lir::GenInlinedMinMaxInt(CallInfo* info, bool is_min) {
DCHECK_EQ(cu_->instruction_set, kX86);
@@ -512,100 +845,353 @@ LIR* X86Mir2Lir::OpIT(ConditionCode cond, const char* guide) {
return NULL;
}
-void X86Mir2Lir::GenMulLong(RegLocation rl_dest, RegLocation rl_src1,
- RegLocation rl_src2) {
- LOG(FATAL) << "Unexpected use of GenX86Long for x86";
+void X86Mir2Lir::GenImulRegImm(int dest, int src, int val) {
+ switch (val) {
+ case 0:
+ NewLIR2(kX86Xor32RR, dest, dest);
+ break;
+ case 1:
+ OpRegCopy(dest, src);
+ break;
+ default:
+ OpRegRegImm(kOpMul, dest, src, val);
+ break;
+ }
}
-void X86Mir2Lir::GenAddLong(RegLocation rl_dest, RegLocation rl_src1,
- RegLocation rl_src2) {
- // TODO: fixed register usage here as we only have 4 temps and temporary allocation isn't smart
- // enough.
- FlushAllRegs();
- LockCallTemps(); // Prepare for explicit register usage
- LoadValueDirectWideFixed(rl_src1, r0, r1);
- LoadValueDirectWideFixed(rl_src2, r2, r3);
- // Compute (r1:r0) = (r1:r0) + (r2:r3)
- OpRegReg(kOpAdd, r0, r2); // r0 = r0 + r2
- OpRegReg(kOpAdc, r1, r3); // r1 = r1 + r3 + CF
- RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed, r0, r1,
- INVALID_SREG, INVALID_SREG};
- StoreValueWide(rl_dest, rl_result);
+
+void X86Mir2Lir::GenImulMemImm(int dest, int sreg, int displacement, int val) {
+ LIR *m;
+ switch (val) {
+ case 0:
+ NewLIR2(kX86Xor32RR, dest, dest);
+ break;
+ case 1:
+ LoadBaseDisp(rX86_SP, displacement, dest, kWord, sreg);
+ break;
+ default:
+ m = NewLIR4(IS_SIMM8(val) ? kX86Imul32RMI8 : kX86Imul32RMI, dest, rX86_SP,
+ displacement, val);
+ AnnotateDalvikRegAccess(m, displacement >> 2, true /* is_load */, true /* is_64bit */);
+ break;
+ }
}
-void X86Mir2Lir::GenSubLong(RegLocation rl_dest, RegLocation rl_src1,
+void X86Mir2Lir::GenMulLong(Instruction::Code, RegLocation rl_dest, RegLocation rl_src1,
RegLocation rl_src2) {
- // TODO: fixed register usage here as we only have 4 temps and temporary allocation isn't smart
- // enough.
+ if (rl_src1.is_const) {
+ std::swap(rl_src1, rl_src2);
+ }
+ // Are we multiplying by a constant?
+ if (rl_src2.is_const) {
+ // Do special compare/branch against simple const operand
+ int64_t val = mir_graph_->ConstantValueWide(rl_src2);
+ if (val == 0) {
+ RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
+ OpRegReg(kOpXor, rl_result.low_reg, rl_result.low_reg);
+ OpRegReg(kOpXor, rl_result.high_reg, rl_result.high_reg);
+ StoreValueWide(rl_dest, rl_result);
+ return;
+ } else if (val == 1) {
+ rl_src1 = EvalLocWide(rl_src1, kCoreReg, true);
+ StoreValueWide(rl_dest, rl_src1);
+ return;
+ } else if (val == 2) {
+ GenAddLong(Instruction::ADD_LONG, rl_dest, rl_src1, rl_src1);
+ return;
+ } else if (IsPowerOfTwo(val)) {
+ int shift_amount = LowestSetBit(val);
+ if (!BadOverlap(rl_src1, rl_dest)) {
+ rl_src1 = LoadValueWide(rl_src1, kCoreReg);
+ RegLocation rl_result = GenShiftImmOpLong(Instruction::SHL_LONG, rl_dest,
+ rl_src1, shift_amount);
+ StoreValueWide(rl_dest, rl_result);
+ return;
+ }
+ }
+
+ // Okay, just bite the bullet and do it.
+ int32_t val_lo = Low32Bits(val);
+ int32_t val_hi = High32Bits(val);
+ FlushAllRegs();
+ LockCallTemps(); // Prepare for explicit register usage.
+ rl_src1 = UpdateLocWide(rl_src1);
+ bool src1_in_reg = rl_src1.location == kLocPhysReg;
+ int displacement = SRegOffset(rl_src1.s_reg_low);
+
+ // ECX <- 1H * 2L
+ // EAX <- 1L * 2H
+ if (src1_in_reg) {
+ GenImulRegImm(r1, rl_src1.high_reg, val_lo);
+ GenImulRegImm(r0, rl_src1.low_reg, val_hi);
+ } else {
+ GenImulMemImm(r1, GetSRegHi(rl_src1.s_reg_low), displacement + HIWORD_OFFSET, val_lo);
+ GenImulMemImm(r0, rl_src1.s_reg_low, displacement + LOWORD_OFFSET, val_hi);
+ }
+
+ // ECX <- ECX + EAX (2H * 1L) + (1H * 2L)
+ NewLIR2(kX86Add32RR, r1, r0);
+
+ // EAX <- 2L
+ LoadConstantNoClobber(r0, val_lo);
+
+ // EDX:EAX <- 2L * 1L (double precision)
+ if (src1_in_reg) {
+ NewLIR1(kX86Mul32DaR, rl_src1.low_reg);
+ } else {
+ LIR *m = NewLIR2(kX86Mul32DaM, rX86_SP, displacement + LOWORD_OFFSET);
+ AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
+ true /* is_load */, true /* is_64bit */);
+ }
+
+ // EDX <- EDX + ECX (add high words)
+ NewLIR2(kX86Add32RR, r2, r1);
+
+ // Result is EDX:EAX
+ RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed, r0, r2,
+ INVALID_SREG, INVALID_SREG};
+ StoreValueWide(rl_dest, rl_result);
+ return;
+ }
+
+ // Nope. Do it the hard way
FlushAllRegs();
- LockCallTemps(); // Prepare for explicit register usage
- LoadValueDirectWideFixed(rl_src1, r0, r1);
- LoadValueDirectWideFixed(rl_src2, r2, r3);
- // Compute (r1:r0) = (r1:r0) + (r2:r3)
- OpRegReg(kOpSub, r0, r2); // r0 = r0 - r2
- OpRegReg(kOpSbc, r1, r3); // r1 = r1 - r3 - CF
- RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed, r0, r1,
- INVALID_SREG, INVALID_SREG};
+ LockCallTemps(); // Prepare for explicit register usage.
+ rl_src1 = UpdateLocWide(rl_src1);
+ rl_src2 = UpdateLocWide(rl_src2);
+
+ // At this point, the VRs are in their home locations.
+ bool src1_in_reg = rl_src1.location == kLocPhysReg;
+ bool src2_in_reg = rl_src2.location == kLocPhysReg;
+
+ // ECX <- 1H
+ if (src1_in_reg) {
+ NewLIR2(kX86Mov32RR, r1, rl_src1.high_reg);
+ } else {
+ LoadBaseDisp(rX86_SP, SRegOffset(rl_src1.s_reg_low) + HIWORD_OFFSET, r1,
+ kWord, GetSRegHi(rl_src1.s_reg_low));
+ }
+
+ // EAX <- 2H
+ if (src2_in_reg) {
+ NewLIR2(kX86Mov32RR, r0, rl_src2.high_reg);
+ } else {
+ LoadBaseDisp(rX86_SP, SRegOffset(rl_src2.s_reg_low) + HIWORD_OFFSET, r0,
+ kWord, GetSRegHi(rl_src2.s_reg_low));
+ }
+
+ // EAX <- EAX * 1L (2H * 1L)
+ if (src1_in_reg) {
+ NewLIR2(kX86Imul32RR, r0, rl_src1.low_reg);
+ } else {
+ int displacement = SRegOffset(rl_src1.s_reg_low);
+ LIR *m = NewLIR3(kX86Imul32RM, r0, rX86_SP, displacement + LOWORD_OFFSET);
+ AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
+ true /* is_load */, true /* is_64bit */);
+ }
+
+ // ECX <- ECX * 2L (1H * 2L)
+ if (src2_in_reg) {
+ NewLIR2(kX86Imul32RR, r1, rl_src2.low_reg);
+ } else {
+ int displacement = SRegOffset(rl_src2.s_reg_low);
+ LIR *m = NewLIR3(kX86Imul32RM, r1, rX86_SP, displacement + LOWORD_OFFSET);
+ AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
+ true /* is_load */, true /* is_64bit */);
+ }
+
+ // ECX <- ECX + EAX (2H * 1L) + (1H * 2L)
+ NewLIR2(kX86Add32RR, r1, r0);
+
+ // EAX <- 2L
+ if (src2_in_reg) {
+ NewLIR2(kX86Mov32RR, r0, rl_src2.low_reg);
+ } else {
+ LoadBaseDisp(rX86_SP, SRegOffset(rl_src2.s_reg_low) + LOWORD_OFFSET, r0,
+ kWord, rl_src2.s_reg_low);
+ }
+
+ // EDX:EAX <- 2L * 1L (double precision)
+ if (src1_in_reg) {
+ NewLIR1(kX86Mul32DaR, rl_src1.low_reg);
+ } else {
+ int displacement = SRegOffset(rl_src1.s_reg_low);
+ LIR *m = NewLIR2(kX86Mul32DaM, rX86_SP, displacement + LOWORD_OFFSET);
+ AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
+ true /* is_load */, true /* is_64bit */);
+ }
+
+ // EDX <- EDX + ECX (add high words)
+ NewLIR2(kX86Add32RR, r2, r1);
+
+ // Result is EDX:EAX
+ RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed, r0, r2,
+ INVALID_SREG, INVALID_SREG};
StoreValueWide(rl_dest, rl_result);
}
-void X86Mir2Lir::GenAndLong(RegLocation rl_dest, RegLocation rl_src1,
- RegLocation rl_src2) {
- // TODO: fixed register usage here as we only have 4 temps and temporary allocation isn't smart
- // enough.
- FlushAllRegs();
- LockCallTemps(); // Prepare for explicit register usage
- LoadValueDirectWideFixed(rl_src1, r0, r1);
- LoadValueDirectWideFixed(rl_src2, r2, r3);
- // Compute (r1:r0) = (r1:r0) & (r2:r3)
- OpRegReg(kOpAnd, r0, r2); // r0 = r0 & r2
- OpRegReg(kOpAnd, r1, r3); // r1 = r1 & r3
- RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed, r0, r1,
- INVALID_SREG, INVALID_SREG};
- StoreValueWide(rl_dest, rl_result);
+void X86Mir2Lir::GenLongRegOrMemOp(RegLocation rl_dest, RegLocation rl_src,
+ Instruction::Code op) {
+ DCHECK_EQ(rl_dest.location, kLocPhysReg);
+ X86OpCode x86op = GetOpcode(op, rl_dest, rl_src, false);
+ if (rl_src.location == kLocPhysReg) {
+ // Both operands are in registers.
+ if (rl_dest.low_reg == rl_src.high_reg) {
+ // The registers are the same, so we would clobber it before the use.
+ int temp_reg = AllocTemp();
+ OpRegCopy(temp_reg, rl_dest.low_reg);
+ rl_src.high_reg = temp_reg;
+ }
+ NewLIR2(x86op, rl_dest.low_reg, rl_src.low_reg);
+
+ x86op = GetOpcode(op, rl_dest, rl_src, true);
+ NewLIR2(x86op, rl_dest.high_reg, rl_src.high_reg);
+ FreeTemp(rl_src.low_reg);
+ FreeTemp(rl_src.high_reg);
+ return;
+ }
+
+ // RHS is in memory.
+ DCHECK((rl_src.location == kLocDalvikFrame) ||
+ (rl_src.location == kLocCompilerTemp));
+ int rBase = TargetReg(kSp);
+ int displacement = SRegOffset(rl_src.s_reg_low);
+
+ LIR *lir = NewLIR3(x86op, rl_dest.low_reg, rBase, displacement + LOWORD_OFFSET);
+ AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2,
+ true /* is_load */, true /* is64bit */);
+ x86op = GetOpcode(op, rl_dest, rl_src, true);
+ lir = NewLIR3(x86op, rl_dest.high_reg, rBase, displacement + HIWORD_OFFSET);
+ AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2,
+ true /* is_load */, true /* is64bit */);
+}
+
+void X86Mir2Lir::GenLongArith(RegLocation rl_dest, RegLocation rl_src, Instruction::Code op) {
+ rl_dest = UpdateLocWide(rl_dest);
+ if (rl_dest.location == kLocPhysReg) {
+ // Ensure we are in a register pair
+ RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
+
+ rl_src = UpdateLocWide(rl_src);
+ GenLongRegOrMemOp(rl_result, rl_src, op);
+ StoreFinalValueWide(rl_dest, rl_result);
+ return;
+ }
+
+ // It wasn't in registers, so it better be in memory.
+ DCHECK((rl_dest.location == kLocDalvikFrame) ||
+ (rl_dest.location == kLocCompilerTemp));
+ rl_src = LoadValueWide(rl_src, kCoreReg);
+
+ // Operate directly into memory.
+ X86OpCode x86op = GetOpcode(op, rl_dest, rl_src, false);
+ int rBase = TargetReg(kSp);
+ int displacement = SRegOffset(rl_dest.s_reg_low);
+
+ LIR *lir = NewLIR3(x86op, rBase, displacement + LOWORD_OFFSET, rl_src.low_reg);
+ AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2,
+ false /* is_load */, true /* is64bit */);
+ x86op = GetOpcode(op, rl_dest, rl_src, true);
+ lir = NewLIR3(x86op, rBase, displacement + HIWORD_OFFSET, rl_src.high_reg);
+ AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2,
+ false /* is_load */, true /* is64bit */);
+ FreeTemp(rl_src.low_reg);
+ FreeTemp(rl_src.high_reg);
+}
+
+void X86Mir2Lir::GenLongArith(RegLocation rl_dest, RegLocation rl_src1,
+ RegLocation rl_src2, Instruction::Code op,
+ bool is_commutative) {
+ // Is this really a 2 operand operation?
+ switch (op) {
+ case Instruction::ADD_LONG_2ADDR:
+ case Instruction::SUB_LONG_2ADDR:
+ case Instruction::AND_LONG_2ADDR:
+ case Instruction::OR_LONG_2ADDR:
+ case Instruction::XOR_LONG_2ADDR:
+ GenLongArith(rl_dest, rl_src2, op);
+ return;
+ default:
+ break;
+ }
+
+ if (rl_dest.location == kLocPhysReg) {
+ RegLocation rl_result = LoadValueWide(rl_src1, kCoreReg);
+
+ // We are about to clobber the LHS, so it needs to be a temp.
+ rl_result = ForceTempWide(rl_result);
+
+ // Perform the operation using the RHS.
+ rl_src2 = UpdateLocWide(rl_src2);
+ GenLongRegOrMemOp(rl_result, rl_src2, op);
+
+ // And now record that the result is in the temp.
+ StoreFinalValueWide(rl_dest, rl_result);
+ return;
+ }
+
+ // It wasn't in registers, so it better be in memory.
+ DCHECK((rl_dest.location == kLocDalvikFrame) ||
+ (rl_dest.location == kLocCompilerTemp));
+ rl_src1 = UpdateLocWide(rl_src1);
+ rl_src2 = UpdateLocWide(rl_src2);
+
+ // Get one of the source operands into temporary register.
+ rl_src1 = LoadValueWide(rl_src1, kCoreReg);
+ if (IsTemp(rl_src1.low_reg) && IsTemp(rl_src1.high_reg)) {
+ GenLongRegOrMemOp(rl_src1, rl_src2, op);
+ } else if (is_commutative) {
+ rl_src2 = LoadValueWide(rl_src2, kCoreReg);
+ // We need at least one of them to be a temporary.
+ if (!(IsTemp(rl_src2.low_reg) && IsTemp(rl_src2.high_reg))) {
+ rl_src1 = ForceTempWide(rl_src1);
+ }
+ GenLongRegOrMemOp(rl_src1, rl_src2, op);
+ } else {
+ // Need LHS to be the temp.
+ rl_src1 = ForceTempWide(rl_src1);
+ GenLongRegOrMemOp(rl_src1, rl_src2, op);
+ }
+
+ StoreFinalValueWide(rl_dest, rl_src1);
+}
+
+void X86Mir2Lir::GenAddLong(Instruction::Code opcode, RegLocation rl_dest,
+ RegLocation rl_src1, RegLocation rl_src2) {
+ GenLongArith(rl_dest, rl_src1, rl_src2, opcode, true);
+}
+
+void X86Mir2Lir::GenSubLong(Instruction::Code opcode, RegLocation rl_dest,
+ RegLocation rl_src1, RegLocation rl_src2) {
+ GenLongArith(rl_dest, rl_src1, rl_src2, opcode, false);
+}
+
+void X86Mir2Lir::GenAndLong(Instruction::Code opcode, RegLocation rl_dest,
+ RegLocation rl_src1, RegLocation rl_src2) {
+ GenLongArith(rl_dest, rl_src1, rl_src2, opcode, true);
}
-void X86Mir2Lir::GenOrLong(RegLocation rl_dest,
+void X86Mir2Lir::GenOrLong(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_src1, RegLocation rl_src2) {
- // TODO: fixed register usage here as we only have 4 temps and temporary allocation isn't smart
- // enough.
- FlushAllRegs();
- LockCallTemps(); // Prepare for explicit register usage
- LoadValueDirectWideFixed(rl_src1, r0, r1);
- LoadValueDirectWideFixed(rl_src2, r2, r3);
- // Compute (r1:r0) = (r1:r0) | (r2:r3)
- OpRegReg(kOpOr, r0, r2); // r0 = r0 | r2
- OpRegReg(kOpOr, r1, r3); // r1 = r1 | r3
- RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed, r0, r1,
- INVALID_SREG, INVALID_SREG};
- StoreValueWide(rl_dest, rl_result);
+ GenLongArith(rl_dest, rl_src1, rl_src2, opcode, true);
}
-void X86Mir2Lir::GenXorLong(RegLocation rl_dest,
+void X86Mir2Lir::GenXorLong(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_src1, RegLocation rl_src2) {
- // TODO: fixed register usage here as we only have 4 temps and temporary allocation isn't smart
- // enough.
- FlushAllRegs();
- LockCallTemps(); // Prepare for explicit register usage
- LoadValueDirectWideFixed(rl_src1, r0, r1);
- LoadValueDirectWideFixed(rl_src2, r2, r3);
- // Compute (r1:r0) = (r1:r0) ^ (r2:r3)
- OpRegReg(kOpXor, r0, r2); // r0 = r0 ^ r2
- OpRegReg(kOpXor, r1, r3); // r1 = r1 ^ r3
- RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed, r0, r1,
- INVALID_SREG, INVALID_SREG};
- StoreValueWide(rl_dest, rl_result);
+ GenLongArith(rl_dest, rl_src1, rl_src2, opcode, true);
}
void X86Mir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
- FlushAllRegs();
- LockCallTemps(); // Prepare for explicit register usage
- LoadValueDirectWideFixed(rl_src, r0, r1);
- // Compute (r1:r0) = -(r1:r0)
- OpRegReg(kOpNeg, r0, r0); // r0 = -r0
- OpRegImm(kOpAdc, r1, 0); // r1 = r1 + CF
- OpRegReg(kOpNeg, r1, r1); // r1 = -r1
- RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed, r0, r1,
- INVALID_SREG, INVALID_SREG};
+ rl_src = LoadValueWide(rl_src, kCoreReg);
+ RegLocation rl_result = ForceTempWide(rl_src);
+ if (rl_dest.low_reg == rl_src.high_reg) {
+ // The registers are the same, so we would clobber it before the use.
+ int temp_reg = AllocTemp();
+ OpRegCopy(temp_reg, rl_result.low_reg);
+ rl_result.high_reg = temp_reg;
+ }
+ OpRegReg(kOpNeg, rl_result.low_reg, rl_result.low_reg); // rLow = -rLow
+ OpRegImm(kOpAdc, rl_result.high_reg, 0); // rHigh = rHigh + CF
+ OpRegReg(kOpNeg, rl_result.high_reg, rl_result.high_reg); // rHigh = -rHigh
StoreValueWide(rl_dest, rl_result);
}
@@ -740,16 +1326,328 @@ void X86Mir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
}
}
+RegLocation X86Mir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
+ RegLocation rl_src, int shift_amount) {
+ RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+ switch (opcode) {
+ case Instruction::SHL_LONG:
+ case Instruction::SHL_LONG_2ADDR:
+ DCHECK_NE(shift_amount, 1); // Prevent a double store from happening.
+ if (shift_amount == 32) {
+ OpRegCopy(rl_result.high_reg, rl_src.low_reg);
+ LoadConstant(rl_result.low_reg, 0);
+ } else if (shift_amount > 31) {
+ OpRegCopy(rl_result.high_reg, rl_src.low_reg);
+ FreeTemp(rl_src.high_reg);
+ NewLIR2(kX86Sal32RI, rl_result.high_reg, shift_amount - 32);
+ LoadConstant(rl_result.low_reg, 0);
+ } else {
+ OpRegCopy(rl_result.low_reg, rl_src.low_reg);
+ OpRegCopy(rl_result.high_reg, rl_src.high_reg);
+ NewLIR3(kX86Shld32RRI, rl_result.high_reg, rl_result.low_reg, shift_amount);
+ NewLIR2(kX86Sal32RI, rl_result.low_reg, shift_amount);
+ }
+ break;
+ case Instruction::SHR_LONG:
+ case Instruction::SHR_LONG_2ADDR:
+ if (shift_amount == 32) {
+ OpRegCopy(rl_result.low_reg, rl_src.high_reg);
+ OpRegCopy(rl_result.high_reg, rl_src.high_reg);
+ NewLIR2(kX86Sar32RI, rl_result.high_reg, 31);
+ } else if (shift_amount > 31) {
+ OpRegCopy(rl_result.low_reg, rl_src.high_reg);
+ OpRegCopy(rl_result.high_reg, rl_src.high_reg);
+ NewLIR2(kX86Sar32RI, rl_result.low_reg, shift_amount - 32);
+ NewLIR2(kX86Sar32RI, rl_result.high_reg, 31);
+ } else {
+ OpRegCopy(rl_result.low_reg, rl_src.low_reg);
+ OpRegCopy(rl_result.high_reg, rl_src.high_reg);
+ NewLIR3(kX86Shrd32RRI, rl_result.low_reg, rl_result.high_reg, shift_amount);
+ NewLIR2(kX86Sar32RI, rl_result.high_reg, shift_amount);
+ }
+ break;
+ case Instruction::USHR_LONG:
+ case Instruction::USHR_LONG_2ADDR:
+ if (shift_amount == 32) {
+ OpRegCopy(rl_result.low_reg, rl_src.high_reg);
+ LoadConstant(rl_result.high_reg, 0);
+ } else if (shift_amount > 31) {
+ OpRegCopy(rl_result.low_reg, rl_src.high_reg);
+ NewLIR2(kX86Shr32RI, rl_result.low_reg, shift_amount - 32);
+ LoadConstant(rl_result.high_reg, 0);
+ } else {
+ OpRegCopy(rl_result.low_reg, rl_src.low_reg);
+ OpRegCopy(rl_result.high_reg, rl_src.high_reg);
+ NewLIR3(kX86Shrd32RRI, rl_result.low_reg, rl_result.high_reg, shift_amount);
+ NewLIR2(kX86Shr32RI, rl_result.high_reg, shift_amount);
+ }
+ break;
+ default:
+ LOG(FATAL) << "Unexpected case";
+ }
+ return rl_result;
+}
+
void X86Mir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
- RegLocation rl_src1, RegLocation rl_shift) {
- // Default implementation is just to ignore the constant case.
- GenShiftOpLong(opcode, rl_dest, rl_src1, rl_shift);
+ RegLocation rl_src, RegLocation rl_shift) {
+ // Per spec, we only care about low 6 bits of shift amount.
+ int shift_amount = mir_graph_->ConstantValue(rl_shift) & 0x3f;
+ if (shift_amount == 0) {
+ rl_src = LoadValueWide(rl_src, kCoreReg);
+ StoreValueWide(rl_dest, rl_src);
+ return;
+ } else if (shift_amount == 1 &&
+ (opcode == Instruction::SHL_LONG || opcode == Instruction::SHL_LONG_2ADDR)) {
+ // Need to handle this here to avoid calling StoreValueWide twice.
+ GenAddLong(Instruction::ADD_LONG, rl_dest, rl_src, rl_src);
+ return;
+ }
+ if (BadOverlap(rl_src, rl_dest)) {
+ GenShiftOpLong(opcode, rl_dest, rl_src, rl_shift);
+ return;
+ }
+ rl_src = LoadValueWide(rl_src, kCoreReg);
+ RegLocation rl_result = GenShiftImmOpLong(opcode, rl_dest, rl_src, shift_amount);
+ StoreValueWide(rl_dest, rl_result);
}
void X86Mir2Lir::GenArithImmOpLong(Instruction::Code opcode,
RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
- // Default - bail to non-const handler.
- GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
+ switch (opcode) {
+ case Instruction::ADD_LONG:
+ case Instruction::AND_LONG:
+ case Instruction::OR_LONG:
+ case Instruction::XOR_LONG:
+ if (rl_src2.is_const) {
+ GenLongLongImm(rl_dest, rl_src1, rl_src2, opcode);
+ } else {
+ DCHECK(rl_src1.is_const);
+ GenLongLongImm(rl_dest, rl_src2, rl_src1, opcode);
+ }
+ break;
+ case Instruction::SUB_LONG:
+ case Instruction::SUB_LONG_2ADDR:
+ if (rl_src2.is_const) {
+ GenLongLongImm(rl_dest, rl_src1, rl_src2, opcode);
+ } else {
+ GenSubLong(opcode, rl_dest, rl_src1, rl_src2);
+ }
+ break;
+ case Instruction::ADD_LONG_2ADDR:
+ case Instruction::OR_LONG_2ADDR:
+ case Instruction::XOR_LONG_2ADDR:
+ case Instruction::AND_LONG_2ADDR:
+ if (rl_src2.is_const) {
+ GenLongImm(rl_dest, rl_src2, opcode);
+ } else {
+ DCHECK(rl_src1.is_const);
+ GenLongLongImm(rl_dest, rl_src2, rl_src1, opcode);
+ }
+ break;
+ default:
+ // Default - bail to non-const handler.
+ GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
+ break;
+ }
+}
+
+bool X86Mir2Lir::IsNoOp(Instruction::Code op, int32_t value) {
+ switch (op) {
+ case Instruction::AND_LONG_2ADDR:
+ case Instruction::AND_LONG:
+ return value == -1;
+ case Instruction::OR_LONG:
+ case Instruction::OR_LONG_2ADDR:
+ case Instruction::XOR_LONG:
+ case Instruction::XOR_LONG_2ADDR:
+ return value == 0;
+ default:
+ return false;
+ }
+}
+
+X86OpCode X86Mir2Lir::GetOpcode(Instruction::Code op, RegLocation dest, RegLocation rhs,
+ bool is_high_op) {
+ bool rhs_in_mem = rhs.location != kLocPhysReg;
+ bool dest_in_mem = dest.location != kLocPhysReg;
+ DCHECK(!rhs_in_mem || !dest_in_mem);
+ switch (op) {
+ case Instruction::ADD_LONG:
+ case Instruction::ADD_LONG_2ADDR:
+ if (dest_in_mem) {
+ return is_high_op ? kX86Adc32MR : kX86Add32MR;
+ } else if (rhs_in_mem) {
+ return is_high_op ? kX86Adc32RM : kX86Add32RM;
+ }
+ return is_high_op ? kX86Adc32RR : kX86Add32RR;
+ case Instruction::SUB_LONG:
+ case Instruction::SUB_LONG_2ADDR:
+ if (dest_in_mem) {
+ return is_high_op ? kX86Sbb32MR : kX86Sub32MR;
+ } else if (rhs_in_mem) {
+ return is_high_op ? kX86Sbb32RM : kX86Sub32RM;
+ }
+ return is_high_op ? kX86Sbb32RR : kX86Sub32RR;
+ case Instruction::AND_LONG_2ADDR:
+ case Instruction::AND_LONG:
+ if (dest_in_mem) {
+ return kX86And32MR;
+ }
+ return rhs_in_mem ? kX86And32RM : kX86And32RR;
+ case Instruction::OR_LONG:
+ case Instruction::OR_LONG_2ADDR:
+ if (dest_in_mem) {
+ return kX86Or32MR;
+ }
+ return rhs_in_mem ? kX86Or32RM : kX86Or32RR;
+ case Instruction::XOR_LONG:
+ case Instruction::XOR_LONG_2ADDR:
+ if (dest_in_mem) {
+ return kX86Xor32MR;
+ }
+ return rhs_in_mem ? kX86Xor32RM : kX86Xor32RR;
+ default:
+ LOG(FATAL) << "Unexpected opcode: " << op;
+ return kX86Add32RR;
+ }
+}
+
+X86OpCode X86Mir2Lir::GetOpcode(Instruction::Code op, RegLocation loc, bool is_high_op,
+ int32_t value) {
+ bool in_mem = loc.location != kLocPhysReg;
+ bool byte_imm = IS_SIMM8(value);
+ DCHECK(in_mem || !IsFpReg(loc.low_reg));
+ switch (op) {
+ case Instruction::ADD_LONG:
+ case Instruction::ADD_LONG_2ADDR:
+ if (byte_imm) {
+ if (in_mem) {
+ return is_high_op ? kX86Adc32MI8 : kX86Add32MI8;
+ }
+ return is_high_op ? kX86Adc32RI8 : kX86Add32RI8;
+ }
+ if (in_mem) {
+ return is_high_op ? kX86Adc32MI : kX86Add32MI;
+ }
+ return is_high_op ? kX86Adc32RI : kX86Add32RI;
+ case Instruction::SUB_LONG:
+ case Instruction::SUB_LONG_2ADDR:
+ if (byte_imm) {
+ if (in_mem) {
+ return is_high_op ? kX86Sbb32MI8 : kX86Sub32MI8;
+ }
+ return is_high_op ? kX86Sbb32RI8 : kX86Sub32RI8;
+ }
+ if (in_mem) {
+ return is_high_op ? kX86Sbb32MI : kX86Sub32MI;
+ }
+ return is_high_op ? kX86Sbb32RI : kX86Sub32RI;
+ case Instruction::AND_LONG_2ADDR:
+ case Instruction::AND_LONG:
+ if (byte_imm) {
+ return in_mem ? kX86And32MI8 : kX86And32RI8;
+ }
+ return in_mem ? kX86And32MI : kX86And32RI;
+ case Instruction::OR_LONG:
+ case Instruction::OR_LONG_2ADDR:
+ if (byte_imm) {
+ return in_mem ? kX86Or32MI8 : kX86Or32RI8;
+ }
+ return in_mem ? kX86Or32MI : kX86Or32RI;
+ case Instruction::XOR_LONG:
+ case Instruction::XOR_LONG_2ADDR:
+ if (byte_imm) {
+ return in_mem ? kX86Xor32MI8 : kX86Xor32RI8;
+ }
+ return in_mem ? kX86Xor32MI : kX86Xor32RI;
+ default:
+ LOG(FATAL) << "Unexpected opcode: " << op;
+ return kX86Add32MI;
+ }
+}
+
+void X86Mir2Lir::GenLongImm(RegLocation rl_dest, RegLocation rl_src, Instruction::Code op) {
+ DCHECK(rl_src.is_const);
+ int64_t val = mir_graph_->ConstantValueWide(rl_src);
+ int32_t val_lo = Low32Bits(val);
+ int32_t val_hi = High32Bits(val);
+ rl_dest = UpdateLocWide(rl_dest);
+
+ // Can we just do this into memory?
+ if ((rl_dest.location == kLocDalvikFrame) ||
+ (rl_dest.location == kLocCompilerTemp)) {
+ int rBase = TargetReg(kSp);
+ int displacement = SRegOffset(rl_dest.s_reg_low);
+
+ if (!IsNoOp(op, val_lo)) {
+ X86OpCode x86op = GetOpcode(op, rl_dest, false, val_lo);
+ LIR *lir = NewLIR3(x86op, rBase, displacement + LOWORD_OFFSET, val_lo);
+ AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2,
+ false /* is_load */, true /* is64bit */);
+ }
+ if (!IsNoOp(op, val_hi)) {
+ X86OpCode x86op = GetOpcode(op, rl_dest, true, val_hi);
+ LIR *lir = NewLIR3(x86op, rBase, displacement + HIWORD_OFFSET, val_hi);
+ AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2,
+ false /* is_load */, true /* is64bit */);
+ }
+ return;
+ }
+
+ RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
+ DCHECK_EQ(rl_result.location, kLocPhysReg);
+ DCHECK(!IsFpReg(rl_result.low_reg));
+
+ if (!IsNoOp(op, val_lo)) {
+ X86OpCode x86op = GetOpcode(op, rl_result, false, val_lo);
+ NewLIR2(x86op, rl_result.low_reg, val_lo);
+ }
+ if (!IsNoOp(op, val_hi)) {
+ X86OpCode x86op = GetOpcode(op, rl_result, true, val_hi);
+ NewLIR2(x86op, rl_result.high_reg, val_hi);
+ }
+ StoreValueWide(rl_dest, rl_result);
+}
+
+void X86Mir2Lir::GenLongLongImm(RegLocation rl_dest, RegLocation rl_src1,
+ RegLocation rl_src2, Instruction::Code op) {
+ DCHECK(rl_src2.is_const);
+ int64_t val = mir_graph_->ConstantValueWide(rl_src2);
+ int32_t val_lo = Low32Bits(val);
+ int32_t val_hi = High32Bits(val);
+ rl_dest = UpdateLocWide(rl_dest);
+ rl_src1 = UpdateLocWide(rl_src1);
+
+ // Can we do this directly into the destination registers?
+ if (rl_dest.location == kLocPhysReg && rl_src1.location == kLocPhysReg &&
+ rl_dest.low_reg == rl_src1.low_reg && rl_dest.high_reg == rl_src1.high_reg &&
+ !IsFpReg(rl_dest.low_reg)) {
+ if (!IsNoOp(op, val_lo)) {
+ X86OpCode x86op = GetOpcode(op, rl_dest, false, val_lo);
+ NewLIR2(x86op, rl_dest.low_reg, val_lo);
+ }
+ if (!IsNoOp(op, val_hi)) {
+ X86OpCode x86op = GetOpcode(op, rl_dest, true, val_hi);
+ NewLIR2(x86op, rl_dest.high_reg, val_hi);
+ }
+ return;
+ }
+
+ rl_src1 = LoadValueWide(rl_src1, kCoreReg);
+ DCHECK_EQ(rl_src1.location, kLocPhysReg);
+
+ // We need the values to be in a temporary
+ RegLocation rl_result = ForceTempWide(rl_src1);
+ if (!IsNoOp(op, val_lo)) {
+ X86OpCode x86op = GetOpcode(op, rl_result, false, val_lo);
+ NewLIR2(x86op, rl_result.low_reg, val_lo);
+ }
+ if (!IsNoOp(op, val_hi)) {
+ X86OpCode x86op = GetOpcode(op, rl_result, true, val_hi);
+ NewLIR2(x86op, rl_result.high_reg, val_hi);
+ }
+
+ StoreFinalValueWide(rl_dest, rl_result);
}
} // namespace art
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 5c993c5ac5..f22354859c 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -243,9 +243,9 @@ std::string X86Mir2Lir::BuildInsnString(const char *fmt, LIR *lir, unsigned char
}
break;
case 't':
- buf += StringPrintf("0x%08x (L%p)",
- reinterpret_cast<uintptr_t>(base_addr)
- + lir->offset + operand, lir->target);
+ buf += StringPrintf("0x%08" PRIxPTR " (L%p)",
+ reinterpret_cast<uintptr_t>(base_addr) + lir->offset + operand,
+ lir->target);
break;
default:
buf += StringPrintf("DecodeError '%c'", fmt[i]);
@@ -679,31 +679,24 @@ RegLocation X86Mir2Lir::EvalLocWide(RegLocation loc, int reg_class, bool update)
}
DCHECK_NE(loc.s_reg_low, INVALID_SREG);
- if (IsFpReg(loc.low_reg) && reg_class != kCoreReg) {
- // Need a wide vector register.
- low_reg = AllocTypedTemp(true, reg_class);
- loc.low_reg = low_reg;
- loc.high_reg = low_reg; // Play nice with existing code.
- loc.vec_len = kVectorLength8;
- if (update) {
- loc.location = kLocPhysReg;
- MarkLive(loc.low_reg, loc.s_reg_low);
- }
- DCHECK(IsFpReg(loc.low_reg));
- } else {
- DCHECK_NE(GetSRegHi(loc.s_reg_low), INVALID_SREG);
+ DCHECK_NE(GetSRegHi(loc.s_reg_low), INVALID_SREG);
- new_regs = AllocTypedTempPair(loc.fp, reg_class);
- loc.low_reg = new_regs & 0xff;
- loc.high_reg = (new_regs >> 8) & 0xff;
+ new_regs = AllocTypedTempPair(loc.fp, reg_class);
+ loc.low_reg = new_regs & 0xff;
+ loc.high_reg = (new_regs >> 8) & 0xff;
+ if (loc.low_reg == loc.high_reg) {
+ DCHECK(IsFpReg(loc.low_reg));
+ loc.vec_len = kVectorLength8;
+ } else {
MarkPair(loc.low_reg, loc.high_reg);
- if (update) {
- loc.location = kLocPhysReg;
- MarkLive(loc.low_reg, loc.s_reg_low);
+ }
+ if (update) {
+ loc.location = kLocPhysReg;
+ MarkLive(loc.low_reg, loc.s_reg_low);
+ if (loc.low_reg != loc.high_reg) {
MarkLive(loc.high_reg, GetSRegHi(loc.s_reg_low));
}
- DCHECK(!IsFpReg(loc.low_reg) || ((loc.low_reg & 0x1) == 0));
}
return loc;
}
@@ -796,4 +789,23 @@ void X86Mir2Lir::GenConstWide(RegLocation rl_dest, int64_t value) {
// Just use the standard code to do the generation.
Mir2Lir::GenConstWide(rl_dest, value);
}
+
+// TODO: Merge with existing RegLocation dumper in vreg_analysis.cc
+void X86Mir2Lir::DumpRegLocation(RegLocation loc) {
+ LOG(INFO) << "location: " << loc.location << ','
+ << (loc.wide ? " w" : " ")
+ << (loc.defined ? " D" : " ")
+ << (loc.is_const ? " c" : " ")
+ << (loc.fp ? " F" : " ")
+ << (loc.core ? " C" : " ")
+ << (loc.ref ? " r" : " ")
+ << (loc.high_word ? " h" : " ")
+ << (loc.home ? " H" : " ")
+ << " vec_len: " << loc.vec_len
+ << ", low: " << static_cast<int>(loc.low_reg)
+ << ", high: " << static_cast<int>(loc.high_reg)
+ << ", s_reg: " << loc.s_reg_low
+ << ", orig: " << loc.orig_sreg;
+}
+
} // namespace art
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index 91c39fa682..97c04dc65d 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -141,7 +141,14 @@ LIR* X86Mir2Lir::OpRegImm(OpKind op, int r_dest_src1, int value) {
case kOpSub: opcode = byte_imm ? kX86Sub32RI8 : kX86Sub32RI; break;
case kOpXor: opcode = byte_imm ? kX86Xor32RI8 : kX86Xor32RI; break;
case kOpCmp: opcode = byte_imm ? kX86Cmp32RI8 : kX86Cmp32RI; break;
- case kOpMov: return LoadConstantNoClobber(r_dest_src1, value);
+ case kOpMov:
+ /*
+ * Moving the constant zero into register can be specialized as an xor of the register.
+ * However, that sets eflags while the move does not. For that reason here, always do
+ * the move and if caller is flexible, they should be calling LoadConstantNoClobber instead.
+ */
+ opcode = kX86Mov32RI;
+ break;
case kOpMul:
opcode = byte_imm ? kX86Imul32RRI8 : kX86Imul32RRI;
return NewLIR3(opcode, r_dest_src1, r_dest_src1, value);
@@ -346,8 +353,7 @@ LIR* X86Mir2Lir::LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value) {
if (val_hi != 0) {
r_dest_hi = AllocTempDouble();
LoadConstantNoClobber(r_dest_hi, val_hi);
- NewLIR2(kX86PsllqRI, r_dest_hi, 32);
- NewLIR2(kX86OrpsRR, r_dest_lo, r_dest_hi);
+ NewLIR2(kX86PunpckldqRR, r_dest_lo, r_dest_hi);
FreeTemp(r_dest_hi);
}
}
@@ -435,15 +441,37 @@ LIR* X86Mir2Lir::LoadBaseIndexedDisp(int rBase, int r_index, int scale,
displacement + LOWORD_OFFSET);
} else {
if (rBase == r_dest) {
- load2 = NewLIR5(opcode, r_dest_hi, rBase, r_index, scale,
- displacement + HIWORD_OFFSET);
- load = NewLIR5(opcode, r_dest, rBase, r_index, scale,
- displacement + LOWORD_OFFSET);
+ if (r_dest_hi == r_index) {
+ // We can't use either register for the first load.
+ int temp = AllocTemp();
+ load2 = NewLIR5(opcode, temp, rBase, r_index, scale,
+ displacement + HIWORD_OFFSET);
+ load = NewLIR5(opcode, r_dest, rBase, r_index, scale,
+ displacement + LOWORD_OFFSET);
+ OpRegCopy(r_dest_hi, temp);
+ FreeTemp(temp);
+ } else {
+ load2 = NewLIR5(opcode, r_dest_hi, rBase, r_index, scale,
+ displacement + HIWORD_OFFSET);
+ load = NewLIR5(opcode, r_dest, rBase, r_index, scale,
+ displacement + LOWORD_OFFSET);
+ }
} else {
- load = NewLIR5(opcode, r_dest, rBase, r_index, scale,
- displacement + LOWORD_OFFSET);
- load2 = NewLIR5(opcode, r_dest_hi, rBase, r_index, scale,
- displacement + HIWORD_OFFSET);
+ if (r_dest == r_index) {
+ // We can't use either register for the first load.
+ int temp = AllocTemp();
+ load = NewLIR5(opcode, temp, rBase, r_index, scale,
+ displacement + LOWORD_OFFSET);
+ load2 = NewLIR5(opcode, r_dest_hi, rBase, r_index, scale,
+ displacement + HIWORD_OFFSET);
+ OpRegCopy(r_dest, temp);
+ FreeTemp(temp);
+ } else {
+ load = NewLIR5(opcode, r_dest, rBase, r_index, scale,
+ displacement + LOWORD_OFFSET);
+ load2 = NewLIR5(opcode, r_dest_hi, rBase, r_index, scale,
+ displacement + HIWORD_OFFSET);
+ }
}
}
}
@@ -572,8 +600,7 @@ void X86Mir2Lir::OpVectorRegCopyWide(uint8_t fp_reg, uint8_t low_reg, uint8_t hi
NewLIR2(kX86MovdxrRR, fp_reg, low_reg);
int tmp_reg = AllocTempDouble();
NewLIR2(kX86MovdxrRR, tmp_reg, high_reg);
- NewLIR2(kX86PsllqRI, tmp_reg, 32);
- NewLIR2(kX86OrpsRR, fp_reg, tmp_reg);
+ NewLIR2(kX86PunpckldqRR, fp_reg, tmp_reg);
FreeTemp(tmp_reg);
}
diff --git a/compiler/dex/quick/x86/x86_lir.h b/compiler/dex/quick/x86/x86_lir.h
index 1488f5d557..7f35d061b5 100644
--- a/compiler/dex/quick/x86/x86_lir.h
+++ b/compiler/dex/quick/x86/x86_lir.h
@@ -304,6 +304,8 @@ enum X86OpCode {
BinaryShiftOpCode(kX86Sar),
#undef BinaryShiftOpcode
kX86Cmc,
+ kX86Shld32RRI,
+ kX86Shrd32RRI,
#define UnaryOpcode(opcode, reg, mem, array) \
opcode ## 8 ## reg, opcode ## 8 ## mem, opcode ## 8 ## array, \
opcode ## 16 ## reg, opcode ## 16 ## mem, opcode ## 16 ## array, \
@@ -316,6 +318,7 @@ enum X86OpCode {
UnaryOpcode(kX86Imul, DaR, DaM, DaA),
UnaryOpcode(kX86Divmod, DaR, DaM, DaA),
UnaryOpcode(kX86Idivmod, DaR, DaM, DaA),
+ kx86Cdq32Da,
kX86Bswap32R,
kX86Push32R, kX86Pop32R,
#undef UnaryOpcode
@@ -349,6 +352,7 @@ enum X86OpCode {
Binary0fOpCode(kX86Subss), // float subtract
Binary0fOpCode(kX86Divsd), // double divide
Binary0fOpCode(kX86Divss), // float divide
+ Binary0fOpCode(kX86Punpckldq), // Interleave low-order double words
kX86PsrlqRI, // right shift of floating point registers
kX86PsllqRI, // left shift of floating point registers
kX86SqrtsdRR, // sqrt of floating point register
@@ -397,6 +401,7 @@ enum X86EncodingKind {
kRegImm, kMemImm, kArrayImm, kThreadImm, // RI, MI, AI and TI instruction kinds.
kRegRegImm, kRegMemImm, kRegArrayImm, // RRI, RMI and RAI instruction kinds.
kMovRegImm, // Shorter form move RI.
+ kRegRegImmRev, // RRI with first reg in r/m
kShiftRegImm, kShiftMemImm, kShiftArrayImm, // Shift opcode with immediate.
kShiftRegCl, kShiftMemCl, kShiftArrayCl, // Shift opcode with register CL.
kRegRegReg, kRegRegMem, kRegRegArray, // RRR, RRM, RRA instruction kinds.
diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc
new file mode 100644
index 0000000000..edccec55ba
--- /dev/null
+++ b/compiler/dex/verification_results.cc
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "verification_results.h"
+
+#include "base/stl_util.h"
+#include "base/mutex.h"
+#include "base/mutex-inl.h"
+#include "thread.h"
+#include "thread-inl.h"
+#include "verified_method.h"
+#include "verifier/method_verifier.h"
+#include "verifier/method_verifier-inl.h"
+
+namespace art {
+
+VerificationResults::VerificationResults()
+ : verified_methods_lock_("compiler verified methods lock"),
+ verified_methods_(),
+ rejected_classes_lock_("compiler rejected classes lock"),
+ rejected_classes_() {
+}
+
+VerificationResults::~VerificationResults() {
+ Thread* self = Thread::Current();
+ {
+ WriterMutexLock mu(self, verified_methods_lock_);
+ STLDeleteValues(&verified_methods_);
+ }
+}
+
+bool VerificationResults::ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier) {
+ MethodReference ref = method_verifier->GetMethodReference();
+ bool compile = IsCandidateForCompilation(ref, method_verifier->GetAccessFlags());
+ // TODO: Check also for virtual/interface invokes when DEX-to-DEX supports devirtualization.
+ if (!compile && !method_verifier->HasCheckCasts()) {
+ return true;
+ }
+
+ const VerifiedMethod* verified_method = VerifiedMethod::Create(method_verifier, compile);
+ if (verified_method == nullptr) {
+ DCHECK(method_verifier->HasFailures());
+ return false;
+ }
+
+ WriterMutexLock mu(Thread::Current(), verified_methods_lock_);
+ auto it = verified_methods_.find(ref);
+ if (it != verified_methods_.end()) {
+ // TODO: Investigate why are we doing the work again for this method and try to avoid it.
+ LOG(WARNING) << "Method processed more than once: "
+ << PrettyMethod(ref.dex_method_index, *ref.dex_file);
+ DCHECK_EQ(it->second->GetDevirtMap().size(), verified_method->GetDevirtMap().size());
+ DCHECK_EQ(it->second->GetSafeCastSet().size(), verified_method->GetSafeCastSet().size());
+ DCHECK_EQ(it->second->GetDexGcMap().size(), verified_method->GetDexGcMap().size());
+ delete it->second;
+ verified_methods_.erase(it);
+ }
+ verified_methods_.Put(ref, verified_method);
+ DCHECK(verified_methods_.find(ref) != verified_methods_.end());
+ return true;
+}
+
+const VerifiedMethod* VerificationResults::GetVerifiedMethod(MethodReference ref) {
+ ReaderMutexLock mu(Thread::Current(), verified_methods_lock_);
+ auto it = verified_methods_.find(ref);
+ return (it != verified_methods_.end()) ? it->second : nullptr;
+}
+
+void VerificationResults::AddRejectedClass(ClassReference ref) {
+ {
+ WriterMutexLock mu(Thread::Current(), rejected_classes_lock_);
+ rejected_classes_.insert(ref);
+ }
+ DCHECK(IsClassRejected(ref));
+}
+
+bool VerificationResults::IsClassRejected(ClassReference ref) {
+ ReaderMutexLock mu(Thread::Current(), rejected_classes_lock_);
+ return (rejected_classes_.find(ref) != rejected_classes_.end());
+}
+
+bool VerificationResults::IsCandidateForCompilation(MethodReference& method_ref,
+ const uint32_t access_flags) {
+#ifdef ART_SEA_IR_MODE
+ bool use_sea = Runtime::Current()->IsSeaIRMode();
+ use_sea = use_sea && (std::string::npos != PrettyMethod(
+ method_ref.dex_method_index, *(method_ref.dex_file)).find("fibonacci"));
+ if (use_sea) return true;
+#endif
+ // Don't compile class initializers, ever.
+ if (((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) {
+ return false;
+ }
+ return (Runtime::Current()->GetCompilerFilter() != Runtime::kInterpretOnly);
+}
+
+} // namespace art
diff --git a/compiler/dex/verification_results.h b/compiler/dex/verification_results.h
new file mode 100644
index 0000000000..2eb07131ce
--- /dev/null
+++ b/compiler/dex/verification_results.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_DEX_VERIFICATION_RESULTS_H_
+#define ART_COMPILER_DEX_VERIFICATION_RESULTS_H_
+
+#include <stdint.h>
+#include <set>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/mutex.h"
+#include "class_reference.h"
+#include "method_reference.h"
+#include "safe_map.h"
+
+namespace art {
+
+namespace verifier {
+class MethodVerifier;
+} // namespace verifier
+
+class VerifiedMethod;
+
+class VerificationResults {
+ public:
+ VerificationResults();
+ ~VerificationResults();
+
+ bool ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ LOCKS_EXCLUDED(verified_methods_lock_);
+
+ const VerifiedMethod* GetVerifiedMethod(MethodReference ref)
+ LOCKS_EXCLUDED(verified_methods_lock_);
+
+ void AddRejectedClass(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_);
+ bool IsClassRejected(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_);
+
+ static bool IsCandidateForCompilation(MethodReference& method_ref,
+ const uint32_t access_flags);
+
+ private:
+ // Verified methods.
+ typedef SafeMap<MethodReference, const VerifiedMethod*,
+ MethodReferenceComparator> VerifiedMethodMap;
+ ReaderWriterMutex verified_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ VerifiedMethodMap verified_methods_;
+
+ // Rejected classes.
+ ReaderWriterMutex rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ std::set<ClassReference> rejected_classes_ GUARDED_BY(rejected_classes_lock_);
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_DEX_VERIFICATION_RESULTS_H_
diff --git a/compiler/dex/verified_methods_data.cc b/compiler/dex/verified_method.cc
index e6c4ddab06..0f812a49cd 100644
--- a/compiler/dex/verified_methods_data.cc
+++ b/compiler/dex/verified_method.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,6 +14,12 @@
* limitations under the License.
*/
+#include "verified_method.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "base/logging.h"
#include "base/stl_util.h"
#include "dex_file.h"
#include "dex_instruction.h"
@@ -28,7 +34,7 @@
#include "mirror/dex_cache-inl.h"
#include "mirror/object.h"
#include "mirror/object-inl.h"
-#include "verified_methods_data.h"
+#include "UniquePtr.h"
#include "verifier/dex_gc_map.h"
#include "verifier/method_verifier.h"
#include "verifier/method_verifier-inl.h"
@@ -37,150 +43,58 @@
namespace art {
-VerifiedMethodsData::VerifiedMethodsData()
- : dex_gc_maps_lock_("compiler GC maps lock"),
- dex_gc_maps_(),
- safecast_map_lock_("compiler Cast Elision lock"),
- safecast_map_(),
- devirt_maps_lock_("compiler Devirtualization lock"),
- devirt_maps_(),
- rejected_classes_lock_("compiler rejected classes lock"),
- rejected_classes_() {
-}
-
-VerifiedMethodsData::~VerifiedMethodsData() {
- Thread* self = Thread::Current();
- {
- WriterMutexLock mu(self, dex_gc_maps_lock_);
- STLDeleteValues(&dex_gc_maps_);
- }
- {
- WriterMutexLock mu(self, safecast_map_lock_);
- STLDeleteValues(&safecast_map_);
- }
- {
- WriterMutexLock mu(self, devirt_maps_lock_);
- STLDeleteValues(&devirt_maps_);
- }
-}
-
-bool VerifiedMethodsData::ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier) {
- MethodReference ref = method_verifier->GetMethodReference();
- bool compile = IsCandidateForCompilation(ref, method_verifier->GetAccessFlags());
+const VerifiedMethod* VerifiedMethod::Create(verifier::MethodVerifier* method_verifier,
+ bool compile) {
+ UniquePtr<VerifiedMethod> verified_method(new VerifiedMethod);
if (compile) {
- /* Generate a register map and add it to the method. */
- const std::vector<uint8_t>* dex_gc_map = GenerateGcMap(method_verifier);
- if (dex_gc_map == NULL) {
- DCHECK(method_verifier->HasFailures());
- return false; // Not a real failure, but a failure to encode
+ /* Generate a register map. */
+ if (!verified_method->GenerateGcMap(method_verifier)) {
+ CHECK(method_verifier->HasFailures());
+ return nullptr; // Not a real failure, but a failure to encode.
}
if (kIsDebugBuild) {
- VerifyGcMap(method_verifier, *dex_gc_map);
+ VerifyGcMap(method_verifier, verified_method->dex_gc_map_);
}
- SetDexGcMap(ref, dex_gc_map);
// TODO: move this out when DEX-to-DEX supports devirtualization.
if (method_verifier->HasVirtualOrInterfaceInvokes()) {
- PcToConcreteMethodMap* pc_to_concrete_method = GenerateDevirtMap(method_verifier);
- if (pc_to_concrete_method != NULL) {
- SetDevirtMap(ref, pc_to_concrete_method);
- }
+ verified_method->GenerateDevirtMap(method_verifier);
}
}
if (method_verifier->HasCheckCasts()) {
- MethodSafeCastSet* method_to_safe_casts = GenerateSafeCastSet(method_verifier);
- if (method_to_safe_casts != NULL) {
- SetSafeCastMap(ref, method_to_safe_casts);
- }
- }
- return true;
-}
-
-const std::vector<uint8_t>* VerifiedMethodsData::GetDexGcMap(MethodReference ref) {
- ReaderMutexLock mu(Thread::Current(), dex_gc_maps_lock_);
- DexGcMapTable::const_iterator it = dex_gc_maps_.find(ref);
- CHECK(it != dex_gc_maps_.end())
- << "Didn't find GC map for: " << PrettyMethod(ref.dex_method_index, *ref.dex_file);
- CHECK(it->second != NULL);
- return it->second;
-}
-
-const MethodReference* VerifiedMethodsData::GetDevirtMap(const MethodReference& ref,
- uint32_t dex_pc) {
- ReaderMutexLock mu(Thread::Current(), devirt_maps_lock_);
- DevirtualizationMapTable::const_iterator it = devirt_maps_.find(ref);
- if (it == devirt_maps_.end()) {
- return NULL;
- }
-
- // Look up the PC in the map, get the concrete method to execute and return its reference.
- PcToConcreteMethodMap::const_iterator pc_to_concrete_method = it->second->find(dex_pc);
- if (pc_to_concrete_method != it->second->end()) {
- return &(pc_to_concrete_method->second);
- } else {
- return NULL;
- }
-}
-
-bool VerifiedMethodsData::IsSafeCast(MethodReference ref, uint32_t pc) {
- ReaderMutexLock mu(Thread::Current(), safecast_map_lock_);
- SafeCastMap::const_iterator it = safecast_map_.find(ref);
- if (it == safecast_map_.end()) {
- return false;
+ verified_method->GenerateSafeCastSet(method_verifier);
}
-
- // Look up the cast address in the set of safe casts
- // Use binary_search for lookup in the sorted vector.
- return std::binary_search(it->second->begin(), it->second->end(), pc);
-}
-
-void VerifiedMethodsData::AddRejectedClass(ClassReference ref) {
- {
- WriterMutexLock mu(Thread::Current(), rejected_classes_lock_);
- rejected_classes_.insert(ref);
- }
- DCHECK(IsClassRejected(ref));
+ return verified_method.release();
}
-bool VerifiedMethodsData::IsClassRejected(ClassReference ref) {
- ReaderMutexLock mu(Thread::Current(), rejected_classes_lock_);
- return (rejected_classes_.find(ref) != rejected_classes_.end());
+const MethodReference* VerifiedMethod::GetDevirtTarget(uint32_t dex_pc) const {
+ auto it = devirt_map_.find(dex_pc);
+ return (it != devirt_map_.end()) ? &it->second : nullptr;
}
-bool VerifiedMethodsData::IsCandidateForCompilation(MethodReference& method_ref,
- const uint32_t access_flags) {
-#ifdef ART_SEA_IR_MODE
- bool use_sea = Runtime::Current()->IsSeaIRMode();
- use_sea = use_sea && (std::string::npos != PrettyMethod(
- method_ref.dex_method_index, *(method_ref.dex_file)).find("fibonacci"));
- if (use_sea) return true;
-#endif
- // Don't compile class initializers, ever.
- if (((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) {
- return false;
- }
- return (Runtime::Current()->GetCompilerFilter() != Runtime::kInterpretOnly);
+bool VerifiedMethod::IsSafeCast(uint32_t pc) const {
+ return std::binary_search(safe_cast_set_.begin(), safe_cast_set_.end(), pc);
}
-const std::vector<uint8_t>* VerifiedMethodsData::GenerateGcMap(
- verifier::MethodVerifier* method_verifier) {
+bool VerifiedMethod::GenerateGcMap(verifier::MethodVerifier* method_verifier) {
+ DCHECK(dex_gc_map_.empty());
size_t num_entries, ref_bitmap_bits, pc_bits;
ComputeGcMapSizes(method_verifier, &num_entries, &ref_bitmap_bits, &pc_bits);
- // There's a single byte to encode the size of each bitmap
+ // There's a single byte to encode the size of each bitmap.
if (ref_bitmap_bits >= (8 /* bits per byte */ * 8192 /* 13-bit size */ )) {
// TODO: either a better GC map format or per method failures
method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD)
<< "Cannot encode GC map for method with " << ref_bitmap_bits << " registers";
- return NULL;
+ return false;
}
size_t ref_bitmap_bytes = (ref_bitmap_bits + 7) / 8;
- // There are 2 bytes to encode the number of entries
+ // There are 2 bytes to encode the number of entries.
if (num_entries >= 65536) {
- // TODO: either a better GC map format or per method failures
+ // TODO: Either a better GC map format or per method failures.
method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD)
<< "Cannot encode GC map for method with " << num_entries << " entries";
- return NULL;
+ return false;
}
size_t pc_bytes;
verifier::RegisterMapFormat format;
@@ -191,45 +105,39 @@ const std::vector<uint8_t>* VerifiedMethodsData::GenerateGcMap(
format = verifier::kRegMapFormatCompact16;
pc_bytes = 2;
} else {
- // TODO: either a better GC map format or per method failures
+ // TODO: Either a better GC map format or per method failures.
method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD)
<< "Cannot encode GC map for method with "
<< (1 << pc_bits) << " instructions (number is rounded up to nearest power of 2)";
- return NULL;
+ return false;
}
size_t table_size = ((pc_bytes + ref_bitmap_bytes) * num_entries) + 4;
- std::vector<uint8_t>* table = new std::vector<uint8_t>;
- if (table == NULL) {
- method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD)
- << "Failed to encode GC map (size=" << table_size << ")";
- return NULL;
- }
- table->reserve(table_size);
- // Write table header
- table->push_back(format | ((ref_bitmap_bytes & ~0xFF) >> 5));
- table->push_back(ref_bitmap_bytes & 0xFF);
- table->push_back(num_entries & 0xFF);
- table->push_back((num_entries >> 8) & 0xFF);
- // Write table data
+ dex_gc_map_.reserve(table_size);
+ // Write table header.
+ dex_gc_map_.push_back(format | ((ref_bitmap_bytes & ~0xFF) >> 5));
+ dex_gc_map_.push_back(ref_bitmap_bytes & 0xFF);
+ dex_gc_map_.push_back(num_entries & 0xFF);
+ dex_gc_map_.push_back((num_entries >> 8) & 0xFF);
+ // Write table data.
const DexFile::CodeItem* code_item = method_verifier->CodeItem();
for (size_t i = 0; i < code_item->insns_size_in_code_units_; i++) {
if (method_verifier->GetInstructionFlags(i).IsCompileTimeInfoPoint()) {
- table->push_back(i & 0xFF);
+ dex_gc_map_.push_back(i & 0xFF);
if (pc_bytes == 2) {
- table->push_back((i >> 8) & 0xFF);
+ dex_gc_map_.push_back((i >> 8) & 0xFF);
}
verifier::RegisterLine* line = method_verifier->GetRegLine(i);
- line->WriteReferenceBitMap(*table, ref_bitmap_bytes);
+ line->WriteReferenceBitMap(dex_gc_map_, ref_bitmap_bytes);
}
}
- DCHECK_EQ(table->size(), table_size);
- return table;
+ DCHECK_EQ(dex_gc_map_.size(), table_size);
+ return true;
}
-void VerifiedMethodsData::VerifyGcMap(verifier::MethodVerifier* method_verifier,
- const std::vector<uint8_t>& data) {
+void VerifiedMethod::VerifyGcMap(verifier::MethodVerifier* method_verifier,
+ const std::vector<uint8_t>& data) {
// Check that for every GC point there is a map entry, there aren't entries for non-GC points,
- // that the table data is well formed and all references are marked (or not) in the bitmap
+ // that the table data is well formed and all references are marked (or not) in the bitmap.
verifier::DexPcToReferenceMap map(&data[0]);
DCHECK_EQ(data.size(), map.RawSize());
size_t map_index = 0;
@@ -237,30 +145,30 @@ void VerifiedMethodsData::VerifyGcMap(verifier::MethodVerifier* method_verifier,
for (size_t i = 0; i < code_item->insns_size_in_code_units_; i++) {
const uint8_t* reg_bitmap = map.FindBitMap(i, false);
if (method_verifier->GetInstructionFlags(i).IsCompileTimeInfoPoint()) {
- CHECK_LT(map_index, map.NumEntries());
- CHECK_EQ(map.GetDexPc(map_index), i);
- CHECK_EQ(map.GetBitMap(map_index), reg_bitmap);
+ DCHECK_LT(map_index, map.NumEntries());
+ DCHECK_EQ(map.GetDexPc(map_index), i);
+ DCHECK_EQ(map.GetBitMap(map_index), reg_bitmap);
map_index++;
verifier::RegisterLine* line = method_verifier->GetRegLine(i);
for (size_t j = 0; j < code_item->registers_size_; j++) {
if (line->GetRegisterType(j).IsNonZeroReferenceTypes()) {
- CHECK_LT(j / 8, map.RegWidth());
- CHECK_EQ((reg_bitmap[j / 8] >> (j % 8)) & 1, 1);
+ DCHECK_LT(j / 8, map.RegWidth());
+ DCHECK_EQ((reg_bitmap[j / 8] >> (j % 8)) & 1, 1);
} else if ((j / 8) < map.RegWidth()) {
- CHECK_EQ((reg_bitmap[j / 8] >> (j % 8)) & 1, 0);
+ DCHECK_EQ((reg_bitmap[j / 8] >> (j % 8)) & 1, 0);
} else {
- // If a register doesn't contain a reference then the bitmap may be shorter than the line
+ // If a register doesn't contain a reference then the bitmap may be shorter than the line.
}
}
} else {
- CHECK(reg_bitmap == NULL);
+ DCHECK(reg_bitmap == NULL);
}
}
}
-void VerifiedMethodsData::ComputeGcMapSizes(verifier::MethodVerifier* method_verifier,
- size_t* gc_points, size_t* ref_bitmap_bits,
- size_t* log2_max_gc_pc) {
+void VerifiedMethod::ComputeGcMapSizes(verifier::MethodVerifier* method_verifier,
+ size_t* gc_points, size_t* ref_bitmap_bits,
+ size_t* log2_max_gc_pc) {
size_t local_gc_points = 0;
size_t max_insn = 0;
size_t max_ref_reg = -1;
@@ -274,7 +182,7 @@ void VerifiedMethodsData::ComputeGcMapSizes(verifier::MethodVerifier* method_ver
}
}
*gc_points = local_gc_points;
- *ref_bitmap_bits = max_ref_reg + 1; // if max register is 0 we need 1 bit to encode (ie +1)
+ *ref_bitmap_bits = max_ref_reg + 1; // If max register is 0 we need 1 bit to encode (ie +1).
size_t i = 0;
while ((1U << i) <= max_insn) {
i++;
@@ -282,92 +190,13 @@ void VerifiedMethodsData::ComputeGcMapSizes(verifier::MethodVerifier* method_ver
*log2_max_gc_pc = i;
}
-void VerifiedMethodsData::SetDexGcMap(MethodReference ref, const std::vector<uint8_t>* gc_map) {
- DCHECK(Runtime::Current()->IsCompiler());
- {
- WriterMutexLock mu(Thread::Current(), dex_gc_maps_lock_);
- DexGcMapTable::iterator it = dex_gc_maps_.find(ref);
- if (it != dex_gc_maps_.end()) {
- delete it->second;
- dex_gc_maps_.erase(it);
- }
- dex_gc_maps_.Put(ref, gc_map);
- }
- DCHECK(GetDexGcMap(ref) != NULL);
-}
-
-VerifiedMethodsData::MethodSafeCastSet* VerifiedMethodsData::GenerateSafeCastSet(
- verifier::MethodVerifier* method_verifier) {
- /*
- * Walks over the method code and adds any cast instructions in which
- * the type cast is implicit to a set, which is used in the code generation
- * to elide these casts.
- */
- if (method_verifier->HasFailures()) {
- return NULL;
- }
- UniquePtr<MethodSafeCastSet> mscs;
- const DexFile::CodeItem* code_item = method_verifier->CodeItem();
- const Instruction* inst = Instruction::At(code_item->insns_);
- const Instruction* end = Instruction::At(code_item->insns_ +
- code_item->insns_size_in_code_units_);
-
- for (; inst < end; inst = inst->Next()) {
- Instruction::Code code = inst->Opcode();
- if ((code == Instruction::CHECK_CAST) || (code == Instruction::APUT_OBJECT)) {
- uint32_t dex_pc = inst->GetDexPc(code_item->insns_);
- const verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc);
- bool is_safe_cast = false;
- if (code == Instruction::CHECK_CAST) {
- const verifier::RegType& reg_type(line->GetRegisterType(inst->VRegA_21c()));
- const verifier::RegType& cast_type =
- method_verifier->ResolveCheckedClass(inst->VRegB_21c());
- is_safe_cast = cast_type.IsStrictlyAssignableFrom(reg_type);
- } else {
- const verifier::RegType& array_type(line->GetRegisterType(inst->VRegB_23x()));
- // We only know its safe to assign to an array if the array type is precise. For example,
- // an Object[] can have any type of object stored in it, but it may also be assigned a
- // String[] in which case the stores need to be of Strings.
- if (array_type.IsPreciseReference()) {
- const verifier::RegType& value_type(line->GetRegisterType(inst->VRegA_23x()));
- const verifier::RegType& component_type = method_verifier->GetRegTypeCache()
- ->GetComponentType(array_type, method_verifier->GetClassLoader());
- is_safe_cast = component_type.IsStrictlyAssignableFrom(value_type);
- }
- }
- if (is_safe_cast) {
- if (mscs.get() == nullptr) {
- mscs.reset(new MethodSafeCastSet());
- } else {
- DCHECK_LT(mscs->back(), dex_pc); // Verify ordering for push_back() to the sorted vector.
- }
- mscs->push_back(dex_pc);
- }
- }
- }
- return mscs.release();
-}
-
-void VerifiedMethodsData::SetSafeCastMap(MethodReference ref, const MethodSafeCastSet* cast_set) {
- WriterMutexLock mu(Thread::Current(), safecast_map_lock_);
- SafeCastMap::iterator it = safecast_map_.find(ref);
- if (it != safecast_map_.end()) {
- delete it->second;
- safecast_map_.erase(it);
- }
- safecast_map_.Put(ref, cast_set);
- DCHECK(safecast_map_.find(ref) != safecast_map_.end());
-}
-
-VerifiedMethodsData::PcToConcreteMethodMap* VerifiedMethodsData::GenerateDevirtMap(
- verifier::MethodVerifier* method_verifier) {
+void VerifiedMethod::GenerateDevirtMap(verifier::MethodVerifier* method_verifier) {
// It is risky to rely on reg_types for sharpening in cases of soft
// verification, we might end up sharpening to a wrong implementation. Just abort.
if (method_verifier->HasFailures()) {
- return NULL;
+ return;
}
- UniquePtr<PcToConcreteMethodMap> pc_to_concrete_method_map;
const DexFile::CodeItem* code_item = method_verifier->CodeItem();
const uint16_t* insns = code_item->insns_;
const Instruction* inst = Instruction::At(insns);
@@ -426,29 +255,58 @@ VerifiedMethodsData::PcToConcreteMethodMap* VerifiedMethodsData::GenerateDevirtM
concrete_method->GetDeclaringClass()->IsFinal()) {
// If we knew exactly the class being dispatched upon, or if the target method cannot be
// overridden record the target to be used in the compiler driver.
- if (pc_to_concrete_method_map.get() == NULL) {
- pc_to_concrete_method_map.reset(new PcToConcreteMethodMap());
- }
MethodReference concrete_ref(
concrete_method->GetDeclaringClass()->GetDexCache()->GetDexFile(),
concrete_method->GetDexMethodIndex());
- pc_to_concrete_method_map->Put(dex_pc, concrete_ref);
+ devirt_map_.Put(dex_pc, concrete_ref);
}
}
- return pc_to_concrete_method_map.release();
}
-void VerifiedMethodsData::SetDevirtMap(MethodReference ref,
- const PcToConcreteMethodMap* devirt_map) {
- WriterMutexLock mu(Thread::Current(), devirt_maps_lock_);
- DevirtualizationMapTable::iterator it = devirt_maps_.find(ref);
- if (it != devirt_maps_.end()) {
- delete it->second;
- devirt_maps_.erase(it);
+void VerifiedMethod::GenerateSafeCastSet(verifier::MethodVerifier* method_verifier) {
+ /*
+ * Walks over the method code and adds any cast instructions in which
+ * the type cast is implicit to a set, which is used in the code generation
+ * to elide these casts.
+ */
+ if (method_verifier->HasFailures()) {
+ return;
}
+ const DexFile::CodeItem* code_item = method_verifier->CodeItem();
+ const Instruction* inst = Instruction::At(code_item->insns_);
+ const Instruction* end = Instruction::At(code_item->insns_ +
+ code_item->insns_size_in_code_units_);
- devirt_maps_.Put(ref, devirt_map);
- DCHECK(devirt_maps_.find(ref) != devirt_maps_.end());
+ for (; inst < end; inst = inst->Next()) {
+ Instruction::Code code = inst->Opcode();
+ if ((code == Instruction::CHECK_CAST) || (code == Instruction::APUT_OBJECT)) {
+ uint32_t dex_pc = inst->GetDexPc(code_item->insns_);
+ const verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc);
+ bool is_safe_cast = false;
+ if (code == Instruction::CHECK_CAST) {
+ const verifier::RegType& reg_type(line->GetRegisterType(inst->VRegA_21c()));
+ const verifier::RegType& cast_type =
+ method_verifier->ResolveCheckedClass(inst->VRegB_21c());
+ is_safe_cast = cast_type.IsStrictlyAssignableFrom(reg_type);
+ } else {
+ const verifier::RegType& array_type(line->GetRegisterType(inst->VRegB_23x()));
+ // We only know its safe to assign to an array if the array type is precise. For example,
+ // an Object[] can have any type of object stored in it, but it may also be assigned a
+ // String[] in which case the stores need to be of Strings.
+ if (array_type.IsPreciseReference()) {
+ const verifier::RegType& value_type(line->GetRegisterType(inst->VRegA_23x()));
+ const verifier::RegType& component_type = method_verifier->GetRegTypeCache()
+ ->GetComponentType(array_type, method_verifier->GetClassLoader());
+ is_safe_cast = component_type.IsStrictlyAssignableFrom(value_type);
+ }
+ }
+ if (is_safe_cast) {
+ // Verify ordering for push_back() to the sorted vector.
+ DCHECK(safe_cast_set_.empty() || safe_cast_set_.back() < dex_pc);
+ safe_cast_set_.push_back(dex_pc);
+ }
+ }
+ }
}
} // namespace art
diff --git a/compiler/dex/verified_method.h b/compiler/dex/verified_method.h
new file mode 100644
index 0000000000..aa0e72a5ca
--- /dev/null
+++ b/compiler/dex/verified_method.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_DEX_VERIFIED_METHOD_H_
+#define ART_COMPILER_DEX_VERIFIED_METHOD_H_
+
+#include <vector>
+
+#include "method_reference.h"
+#include "safe_map.h"
+
+namespace art {
+
+namespace verifier {
+class MethodVerifier;
+} // namespace verifier
+
+class VerifiedMethod {
+ public:
+ // Cast elision set type.
+ // Since we're adding the dex PCs to the set in increasing order, a sorted vector
+ // is better for performance (not just memory usage), especially for large sets.
+ typedef std::vector<uint32_t> SafeCastSet;
+
+ // Devirtualization map type maps dex offset to concrete method reference.
+ typedef SafeMap<uint32_t, MethodReference> DevirtualizationMap;
+
+ static const VerifiedMethod* Create(verifier::MethodVerifier* method_verifier, bool compile)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ ~VerifiedMethod() = default;
+
+ const std::vector<uint8_t>& GetDexGcMap() const {
+ return dex_gc_map_;
+ }
+
+ const DevirtualizationMap& GetDevirtMap() const {
+ return devirt_map_;
+ }
+
+ const SafeCastSet& GetSafeCastSet() const {
+ return safe_cast_set_;
+ }
+
+ // Returns the devirtualization target method, or nullptr if none.
+ const MethodReference* GetDevirtTarget(uint32_t dex_pc) const;
+
+ // Returns true if the cast can statically be verified to be redundant
+ // by using the check-cast elision peephole optimization in the verifier.
+ bool IsSafeCast(uint32_t pc) const;
+
+ private:
+ VerifiedMethod() = default;
+
+ /*
+ * Generate the GC map for a method that has just been verified (i.e. we're doing this as part of
+ * verification). For type-precise determination we have all the data we need, so we just need to
+ * encode it in some clever fashion.
+ * Stores the data in dex_gc_map_, returns true on success and false on failure.
+ */
+ bool GenerateGcMap(verifier::MethodVerifier* method_verifier);
+
+ // Verify that the GC map associated with method_ is well formed.
+ static void VerifyGcMap(verifier::MethodVerifier* method_verifier,
+ const std::vector<uint8_t>& data);
+
+ // Compute sizes for GC map data.
+ static void ComputeGcMapSizes(verifier::MethodVerifier* method_verifier,
+ size_t* gc_points, size_t* ref_bitmap_bits, size_t* log2_max_gc_pc);
+
+ // Generate devirtualizaion map into devirt_map_.
+ void GenerateDevirtMap(verifier::MethodVerifier* method_verifier)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Generate safe case set into safe_cast_set_.
+ void GenerateSafeCastSet(verifier::MethodVerifier* method_verifier)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ std::vector<uint8_t> dex_gc_map_;
+ DevirtualizationMap devirt_map_;
+ SafeCastSet safe_cast_set_;
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_DEX_VERIFIED_METHOD_H_
diff --git a/compiler/dex/verified_methods_data.h b/compiler/dex/verified_methods_data.h
deleted file mode 100644
index d495dff7d9..0000000000
--- a/compiler/dex/verified_methods_data.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_DEX_VERIFIED_METHODS_DATA_H_
-#define ART_COMPILER_DEX_VERIFIED_METHODS_DATA_H_
-
-#include <stdint.h>
-#include <set>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/mutex.h"
-#include "class_reference.h"
-#include "method_reference.h"
-#include "safe_map.h"
-
-namespace art {
-
-namespace verifier {
-class MethodVerifier;
-} // namespace verifier
-
-class VerifiedMethodsData {
- public:
- VerifiedMethodsData();
- ~VerifiedMethodsData();
-
- bool ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- LOCKS_EXCLUDED(dex_gc_maps_lock_, devirt_maps_lock_, safecast_map_lock_);
-
- const std::vector<uint8_t>* GetDexGcMap(MethodReference ref)
- LOCKS_EXCLUDED(dex_gc_maps_lock_);
-
- const MethodReference* GetDevirtMap(const MethodReference& ref, uint32_t dex_pc)
- LOCKS_EXCLUDED(devirt_maps_lock_);
-
- // Returns true if the cast can statically be verified to be redundant
- // by using the check-cast elision peephole optimization in the verifier
- bool IsSafeCast(MethodReference ref, uint32_t pc) LOCKS_EXCLUDED(safecast_map_lock_);
-
- void AddRejectedClass(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_);
- bool IsClassRejected(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_);
-
- static bool IsCandidateForCompilation(MethodReference& method_ref,
- const uint32_t access_flags);
-
- private:
- /*
- * Generate the GC map for a method that has just been verified (i.e. we're doing this as part of
- * verification). For type-precise determination we have all the data we need, so we just need to
- * encode it in some clever fashion.
- * Returns a pointer to a newly-allocated RegisterMap, or NULL on failure.
- */
- const std::vector<uint8_t>* GenerateGcMap(verifier::MethodVerifier* method_verifier);
-
- // Verify that the GC map associated with method_ is well formed
- void VerifyGcMap(verifier::MethodVerifier* method_verifier, const std::vector<uint8_t>& data);
-
- // Compute sizes for GC map data
- void ComputeGcMapSizes(verifier::MethodVerifier* method_verifier,
- size_t* gc_points, size_t* ref_bitmap_bits, size_t* log2_max_gc_pc);
-
- // All the GC maps that the verifier has created
- typedef SafeMap<const MethodReference, const std::vector<uint8_t>*,
- MethodReferenceComparator> DexGcMapTable;
- ReaderWriterMutex dex_gc_maps_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
- DexGcMapTable dex_gc_maps_ GUARDED_BY(dex_gc_maps_lock_);
- void SetDexGcMap(MethodReference ref, const std::vector<uint8_t>* dex_gc_map)
- LOCKS_EXCLUDED(dex_gc_maps_lock_);
-
- // Cast elision types.
- // Since we're adding the dex PCs to the set in increasing order, a sorted vector
- // is better for performance (not just memory usage), especially for large sets.
- typedef std::vector<uint32_t> MethodSafeCastSet;
- typedef SafeMap<MethodReference, const MethodSafeCastSet*,
- MethodReferenceComparator> SafeCastMap;
- MethodSafeCastSet* GenerateSafeCastSet(verifier::MethodVerifier* method_verifier)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void SetSafeCastMap(MethodReference ref, const MethodSafeCastSet* mscs)
- LOCKS_EXCLUDED(safecast_map_lock_);
- ReaderWriterMutex safecast_map_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
- SafeCastMap safecast_map_ GUARDED_BY(safecast_map_lock_);
-
- // Devirtualization map.
- typedef SafeMap<uint32_t, MethodReference> PcToConcreteMethodMap;
- typedef SafeMap<MethodReference, const PcToConcreteMethodMap*,
- MethodReferenceComparator> DevirtualizationMapTable;
- PcToConcreteMethodMap* GenerateDevirtMap(verifier::MethodVerifier* method_verifier)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- ReaderWriterMutex devirt_maps_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
- DevirtualizationMapTable devirt_maps_ GUARDED_BY(devirt_maps_lock_);
- void SetDevirtMap(MethodReference ref, const PcToConcreteMethodMap* pc_method_map)
- LOCKS_EXCLUDED(devirt_maps_lock_);
-
- // Rejected classes
- typedef std::set<ClassReference> RejectedClassesTable;
- ReaderWriterMutex rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
- RejectedClassesTable rejected_classes_ GUARDED_BY(rejected_classes_lock_);
-};
-
-} // namespace art
-
-#endif // ART_COMPILER_DEX_VERIFIED_METHODS_DATA_H_
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 714dc4cb5e..d504a4e704 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -27,7 +27,8 @@
#include "class_linker.h"
#include "dex_compilation_unit.h"
#include "dex_file-inl.h"
-#include "dex/verified_methods_data.h"
+#include "dex/verification_results.h"
+#include "dex/verified_method.h"
#include "jni_internal.h"
#include "object_utils.h"
#include "runtime.h"
@@ -336,13 +337,13 @@ extern "C" art::CompiledMethod* ArtQuickJniCompileMethod(art::CompilerDriver& co
extern "C" void compilerLLVMSetBitcodeFileName(art::CompilerDriver& driver,
std::string const& filename);
-CompilerDriver::CompilerDriver(VerifiedMethodsData* verified_methods_data,
+CompilerDriver::CompilerDriver(VerificationResults* verification_results,
DexFileToMethodInlinerMap* method_inliner_map,
CompilerBackend compiler_backend, InstructionSet instruction_set,
InstructionSetFeatures instruction_set_features,
bool image, DescriptorSet* image_classes, size_t thread_count,
- bool dump_stats, bool dump_passes, CumulativeLogger* timer)
- : verified_methods_data_(verified_methods_data),
+ bool dump_stats)
+ : verification_results_(verification_results),
method_inliner_map_(method_inliner_map),
compiler_backend_(compiler_backend),
instruction_set_(instruction_set),
@@ -356,8 +357,6 @@ CompilerDriver::CompilerDriver(VerifiedMethodsData* verified_methods_data,
start_ns_(0),
stats_(new AOTCompilationStats),
dump_stats_(dump_stats),
- dump_passes_(dump_passes),
- timings_logger_(timer),
compiler_library_(NULL),
compiler_(NULL),
compiler_context_(NULL),
@@ -441,6 +440,10 @@ CompilerDriver::~CompilerDriver() {
MutexLock mu(self, compiled_methods_lock_);
STLDeleteElements(&methods_to_patch_);
}
+ {
+ MutexLock mu(self, compiled_methods_lock_);
+ STLDeleteElements(&classes_to_patch_);
+ }
CHECK_PTHREAD_CALL(pthread_key_delete, (tls_key_), "delete tls key");
typedef void (*UninitCompilerContextFn)(CompilerDriver&);
UninitCompilerContextFn uninit_compiler_context;
@@ -908,6 +911,51 @@ bool CompilerDriver::CanAccessInstantiableTypeWithoutChecks(uint32_t referrer_id
return result;
}
+bool CompilerDriver::CanEmbedTypeInCode(const DexFile& dex_file, uint32_t type_idx,
+ bool* is_type_initialized, bool* use_direct_type_ptr,
+ uintptr_t* direct_type_ptr) {
+ ScopedObjectAccess soa(Thread::Current());
+ mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
+ mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
+ if (resolved_class == nullptr) {
+ return false;
+ }
+ const bool compiling_boot = Runtime::Current()->GetHeap()->IsCompilingBoot();
+ if (compiling_boot) {
+ // boot -> boot class pointers.
+ // True if the class is in the image at boot compiling time.
+ const bool is_image_class = IsImage() && IsImageClass(
+ dex_file.StringDataByIdx(dex_file.GetTypeId(type_idx).descriptor_idx_));
+ // True if pc relative load works.
+ const bool support_boot_image_fixup = GetSupportBootImageFixup();
+ if (is_image_class && support_boot_image_fixup) {
+ *is_type_initialized = resolved_class->IsInitialized();
+ *use_direct_type_ptr = false;
+ *direct_type_ptr = 0;
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ // True if the class is in the image at app compiling time.
+ const bool class_in_image =
+ Runtime::Current()->GetHeap()->FindSpaceFromObject(resolved_class, false)->IsImageSpace();
+ if (class_in_image) {
+ // boot -> app class pointers.
+ *is_type_initialized = resolved_class->IsInitialized();
+ *use_direct_type_ptr = true;
+ *direct_type_ptr = reinterpret_cast<uintptr_t>(resolved_class);
+ return true;
+ } else {
+ // app -> app class pointers.
+ // Give up because app does not have an image and class
+ // isn't created at compile time. TODO: implement this
+ // if/when each app gets an image.
+ return false;
+ }
+ }
+}
+
static mirror::Class* ComputeCompilingMethodsClass(ScopedObjectAccess& soa,
SirtRef<mirror::DexCache>& dex_cache,
const DexCompilationUnit* mUnit)
@@ -960,21 +1008,8 @@ bool CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompi
ComputeCompilingMethodsClass(soa, dex_cache, mUnit);
if (referrer_class != NULL) {
mirror::Class* fields_class = resolved_field->GetDeclaringClass();
- bool access_ok = referrer_class->CanAccess(fields_class) &&
- referrer_class->CanAccessMember(fields_class,
- resolved_field->GetAccessFlags());
- if (!access_ok) {
- // The referring class can't access the resolved field, this may occur as a result of a
- // protected field being made public by a sub-class. Resort to the dex file to determine
- // the correct class for the access check.
- const DexFile& dex_file = *referrer_class->GetDexCache()->GetDexFile();
- mirror::Class* dex_fields_class = mUnit->GetClassLinker()->ResolveType(dex_file,
- dex_file.GetFieldId(field_idx).class_idx_,
- referrer_class);
- access_ok = referrer_class->CanAccess(dex_fields_class) &&
- referrer_class->CanAccessMember(dex_fields_class,
- resolved_field->GetAccessFlags());
- }
+ bool access_ok =
+ referrer_class->CanAccessResolvedField<false>(fields_class, resolved_field, field_idx);
bool is_write_to_final_from_wrong_class = is_put && resolved_field->IsFinal() &&
fields_class != referrer_class;
if (access_ok && !is_write_to_final_from_wrong_class) {
@@ -1020,23 +1055,8 @@ bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompila
stats_->ResolvedLocalStaticField();
return true; // fast path
} else {
- bool access_ok = referrer_class->CanAccess(fields_class) &&
- referrer_class->CanAccessMember(fields_class,
- resolved_field->GetAccessFlags());
- if (!access_ok) {
- // The referring class can't access the resolved field, this may occur as a result of a
- // protected field being made public by a sub-class. Resort to the dex file to determine
- // the correct class for the access check. Don't change the field's class as that is
- // used to identify the SSB.
- const DexFile& dex_file = *referrer_class->GetDexCache()->GetDexFile();
- mirror::Class* dex_fields_class =
- mUnit->GetClassLinker()->ResolveType(dex_file,
- dex_file.GetFieldId(field_idx).class_idx_,
- referrer_class);
- access_ok = referrer_class->CanAccess(dex_fields_class) &&
- referrer_class->CanAccessMember(dex_fields_class,
- resolved_field->GetAccessFlags());
- }
+ bool access_ok =
+ referrer_class->CanAccessResolvedField<false>(fields_class, resolved_field, field_idx);
bool is_write_to_final_from_wrong_class = is_put && resolved_field->IsFinal();
if (access_ok && !is_write_to_final_from_wrong_class) {
// We have the resolved field, we must make it into a index for the referrer
@@ -1219,20 +1239,8 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui
bool icce = resolved_method->CheckIncompatibleClassChange(*invoke_type);
if (referrer_class != NULL && !icce) {
mirror::Class* methods_class = resolved_method->GetDeclaringClass();
- if (!referrer_class->CanAccess(methods_class) ||
- !referrer_class->CanAccessMember(methods_class,
- resolved_method->GetAccessFlags())) {
- // The referring class can't access the resolved method, this may occur as a result of a
- // protected method being made public by implementing an interface that re-declares the
- // method public. Resort to the dex file to determine the correct class for the access
- // check.
- uint16_t class_idx =
- target_method->dex_file->GetMethodId(target_method->dex_method_index).class_idx_;
- methods_class = mUnit->GetClassLinker()->ResolveType(*target_method->dex_file,
- class_idx, referrer_class);
- }
- if (referrer_class->CanAccess(methods_class) &&
- referrer_class->CanAccessMember(methods_class, resolved_method->GetAccessFlags())) {
+ if (referrer_class->CanAccessResolvedMethod<false>(methods_class, resolved_method,
+ target_method->dex_method_index)) {
const bool enableFinalBasedSharpening = enable_devirtualization;
// Sharpen a virtual call into a direct call when the target is known not to have been
// overridden (ie is final).
@@ -1265,9 +1273,9 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui
if (enableVerifierBasedSharpening && (*invoke_type == kVirtual ||
*invoke_type == kInterface)) {
// Did the verifier record a more precise invoke target based on its type information?
- const MethodReference caller_method(mUnit->GetDexFile(), mUnit->GetDexMethodIndex());
+ DCHECK(mUnit->GetVerifiedMethod() != nullptr);
const MethodReference* devirt_map_target =
- verified_methods_data_->GetDevirtMap(caller_method, dex_pc);
+ mUnit->GetVerifiedMethod()->GetDevirtTarget(dex_pc);
if (devirt_map_target != NULL) {
SirtRef<mirror::DexCache> target_dex_cache(soa.Self(), mUnit->GetClassLinker()->FindDexCache(*devirt_map_target->dex_file));
SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
@@ -1314,8 +1322,15 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui
return false; // Incomplete knowledge needs slow path.
}
-bool CompilerDriver::IsSafeCast(const MethodReference& mr, uint32_t dex_pc) {
- bool result = verified_methods_data_->IsSafeCast(mr, dex_pc);
+const VerifiedMethod* CompilerDriver::GetVerifiedMethod(const DexFile* dex_file,
+ uint32_t method_idx) const {
+ MethodReference ref(dex_file, method_idx);
+ return verification_results_->GetVerifiedMethod(ref);
+}
+
+bool CompilerDriver::IsSafeCast(const DexCompilationUnit* mUnit, uint32_t dex_pc) {
+ DCHECK(mUnit->GetVerifiedMethod() != nullptr);
+ bool result = mUnit->GetVerifiedMethod()->IsSafeCast(dex_pc);
if (result) {
stats_->SafeCast();
} else {
@@ -1333,13 +1348,13 @@ void CompilerDriver::AddCodePatch(const DexFile* dex_file,
InvokeType target_invoke_type,
size_t literal_offset) {
MutexLock mu(Thread::Current(), compiled_methods_lock_);
- code_to_patch_.push_back(new PatchInformation(dex_file,
- referrer_class_def_idx,
- referrer_method_idx,
- referrer_invoke_type,
- target_method_idx,
- target_invoke_type,
- literal_offset));
+ code_to_patch_.push_back(new CallPatchInformation(dex_file,
+ referrer_class_def_idx,
+ referrer_method_idx,
+ referrer_invoke_type,
+ target_method_idx,
+ target_invoke_type,
+ literal_offset));
}
void CompilerDriver::AddMethodPatch(const DexFile* dex_file,
uint16_t referrer_class_def_idx,
@@ -1349,13 +1364,25 @@ void CompilerDriver::AddMethodPatch(const DexFile* dex_file,
InvokeType target_invoke_type,
size_t literal_offset) {
MutexLock mu(Thread::Current(), compiled_methods_lock_);
- methods_to_patch_.push_back(new PatchInformation(dex_file,
- referrer_class_def_idx,
- referrer_method_idx,
- referrer_invoke_type,
- target_method_idx,
- target_invoke_type,
- literal_offset));
+ methods_to_patch_.push_back(new CallPatchInformation(dex_file,
+ referrer_class_def_idx,
+ referrer_method_idx,
+ referrer_invoke_type,
+ target_method_idx,
+ target_invoke_type,
+ literal_offset));
+}
+void CompilerDriver::AddClassPatch(const DexFile* dex_file,
+ uint16_t referrer_class_def_idx,
+ uint32_t referrer_method_idx,
+ uint32_t target_type_idx,
+ size_t literal_offset) {
+ MutexLock mu(Thread::Current(), compiled_methods_lock_);
+ classes_to_patch_.push_back(new TypePatchInformation(dex_file,
+ referrer_class_def_idx,
+ referrer_method_idx,
+ target_type_idx,
+ literal_offset));
}
class ParallelCompilationManager {
@@ -2249,7 +2276,7 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz
}
ClassReference ref(&dex_file, class_def_index);
// Skip compiling classes with generic verifier failures since they will still fail at runtime
- if (manager->GetCompiler()->verified_methods_data_->IsClassRejected(ref)) {
+ if (manager->GetCompiler()->verification_results_->IsClassRejected(ref)) {
return;
}
const byte* class_data = dex_file.GetClassData(class_def);
@@ -2332,7 +2359,7 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t
} else if ((access_flags & kAccAbstract) != 0) {
} else {
MethodReference method_ref(&dex_file, method_idx);
- bool compile = VerifiedMethodsData::IsCandidateForCompilation(method_ref, access_flags);
+ bool compile = VerificationResults::IsCandidateForCompilation(method_ref, access_flags);
if (compile) {
CompilerFn compiler = compiler_;
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index aabdf2f9f6..a8110e71d7 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -22,7 +22,6 @@
#include <vector>
#include "base/mutex.h"
-#include "base/timing_logger.h"
#include "class_reference.h"
#include "compiled_class.h"
#include "compiled_method.h"
@@ -45,7 +44,8 @@ class DexCompilationUnit;
class DexFileToMethodInlinerMap;
class OatWriter;
class TimingLogger;
-class VerifiedMethodsData;
+class VerificationResults;
+class VerifiedMethod;
enum CompilerBackend {
kQuick,
@@ -93,13 +93,12 @@ class CompilerDriver {
// enabled. "image_classes" lets the compiler know what classes it
// can assume will be in the image, with NULL implying all available
// classes.
- explicit CompilerDriver(VerifiedMethodsData* verified_methods_data,
+ explicit CompilerDriver(VerificationResults* verification_results,
DexFileToMethodInlinerMap* method_inliner_map,
CompilerBackend compiler_backend, InstructionSet instruction_set,
InstructionSetFeatures instruction_set_features,
bool image, DescriptorSet* image_classes,
- size_t thread_count, bool dump_stats, bool dump_passes,
- CumulativeLogger* timer);
+ size_t thread_count, bool dump_stats);
~CompilerDriver();
@@ -111,8 +110,8 @@ class CompilerDriver {
void CompileOne(const mirror::ArtMethod* method, TimingLogger& timings)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- VerifiedMethodsData* GetVerifiedMethodsData() const {
- return verified_methods_data_;
+ VerificationResults* GetVerificationResults() const {
+ return verification_results_;
}
DexFileToMethodInlinerMap* GetMethodInlinerMap() const {
@@ -191,6 +190,10 @@ class CompilerDriver {
uint32_t type_idx)
LOCKS_EXCLUDED(Locks::mutator_lock_);
+ bool CanEmbedTypeInCode(const DexFile& dex_file, uint32_t type_idx,
+ bool* is_type_initialized, bool* use_direct_type_ptr,
+ uintptr_t* direct_type_ptr);
+
// Can we fast path instance field access? Computes field's offset and volatility.
bool ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, bool is_put,
int* field_offset, bool* is_volatile)
@@ -211,7 +214,8 @@ class CompilerDriver {
uintptr_t* direct_code, uintptr_t* direct_method)
LOCKS_EXCLUDED(Locks::mutator_lock_);
- bool IsSafeCast(const MethodReference& mr, uint32_t dex_pc);
+ const VerifiedMethod* GetVerifiedMethod(const DexFile* dex_file, uint32_t method_idx) const;
+ bool IsSafeCast(const DexCompilationUnit* mUnit, uint32_t dex_pc);
// Record patch information for later fix up.
void AddCodePatch(const DexFile* dex_file,
@@ -230,6 +234,12 @@ class CompilerDriver {
InvokeType target_invoke_type,
size_t literal_offset)
LOCKS_EXCLUDED(compiled_methods_lock_);
+ void AddClassPatch(const DexFile* dex_file,
+ uint16_t referrer_class_def_idx,
+ uint32_t referrer_method_idx,
+ uint32_t target_method_idx,
+ size_t literal_offset)
+ LOCKS_EXCLUDED(compiled_methods_lock_);
void SetBitcodeFileName(std::string const& filename);
@@ -269,14 +279,8 @@ class CompilerDriver {
return thread_count_;
}
- bool GetDumpPasses() const {
- return dump_passes_;
- }
-
- CumulativeLogger& GetTimingsLogger() const {
- return *timings_logger_;
- }
-
+ class CallPatchInformation;
+ class TypePatchInformation;
class PatchInformation {
public:
const DexFile& GetDexFile() const {
@@ -288,55 +292,127 @@ class CompilerDriver {
uint32_t GetReferrerMethodIdx() const {
return referrer_method_idx_;
}
- InvokeType GetReferrerInvokeType() const {
- return referrer_invoke_type_;
+ size_t GetLiteralOffset() const {
+ return literal_offset_;
}
- uint32_t GetTargetMethodIdx() const {
- return target_method_idx_;
+
+ virtual bool IsCall() const {
+ return false;
}
- InvokeType GetTargetInvokeType() const {
- return target_invoke_type_;
+ virtual bool IsType() const {
+ return false;
}
- size_t GetLiteralOffset() const {;
- return literal_offset_;
+ virtual const CallPatchInformation* AsCall() const {
+ LOG(FATAL) << "Unreachable";
+ return nullptr;
+ }
+ virtual const TypePatchInformation* AsType() const {
+ LOG(FATAL) << "Unreachable";
+ return nullptr;
}
- private:
+ protected:
PatchInformation(const DexFile* dex_file,
uint16_t referrer_class_def_idx,
uint32_t referrer_method_idx,
- InvokeType referrer_invoke_type,
- uint32_t target_method_idx,
- InvokeType target_invoke_type,
size_t literal_offset)
: dex_file_(dex_file),
referrer_class_def_idx_(referrer_class_def_idx),
referrer_method_idx_(referrer_method_idx),
- referrer_invoke_type_(referrer_invoke_type),
- target_method_idx_(target_method_idx),
- target_invoke_type_(target_invoke_type),
literal_offset_(literal_offset) {
CHECK(dex_file_ != NULL);
}
+ virtual ~PatchInformation() {}
const DexFile* const dex_file_;
const uint16_t referrer_class_def_idx_;
const uint32_t referrer_method_idx_;
+ const size_t literal_offset_;
+
+ friend class CompilerDriver;
+ };
+
+ class CallPatchInformation : public PatchInformation {
+ public:
+ InvokeType GetReferrerInvokeType() const {
+ return referrer_invoke_type_;
+ }
+ uint32_t GetTargetMethodIdx() const {
+ return target_method_idx_;
+ }
+ InvokeType GetTargetInvokeType() const {
+ return target_invoke_type_;
+ }
+
+ const CallPatchInformation* AsCall() const {
+ return this;
+ }
+ bool IsCall() const {
+ return true;
+ }
+
+ private:
+ CallPatchInformation(const DexFile* dex_file,
+ uint16_t referrer_class_def_idx,
+ uint32_t referrer_method_idx,
+ InvokeType referrer_invoke_type,
+ uint32_t target_method_idx,
+ InvokeType target_invoke_type,
+ size_t literal_offset)
+ : PatchInformation(dex_file, referrer_class_def_idx,
+ referrer_method_idx, literal_offset),
+ referrer_invoke_type_(referrer_invoke_type),
+ target_method_idx_(target_method_idx),
+ target_invoke_type_(target_invoke_type) {
+ }
+
const InvokeType referrer_invoke_type_;
const uint32_t target_method_idx_;
const InvokeType target_invoke_type_;
- const size_t literal_offset_;
friend class CompilerDriver;
- DISALLOW_COPY_AND_ASSIGN(PatchInformation);
+ DISALLOW_COPY_AND_ASSIGN(CallPatchInformation);
};
- const std::vector<const PatchInformation*>& GetCodeToPatch() const {
+ class TypePatchInformation : public PatchInformation {
+ public:
+ uint32_t GetTargetTypeIdx() const {
+ return target_type_idx_;
+ }
+
+ bool IsType() const {
+ return true;
+ }
+ const TypePatchInformation* AsType() const {
+ return this;
+ }
+
+ private:
+ TypePatchInformation(const DexFile* dex_file,
+ uint16_t referrer_class_def_idx,
+ uint32_t referrer_method_idx,
+ uint32_t target_type_idx,
+ size_t literal_offset)
+ : PatchInformation(dex_file, referrer_class_def_idx,
+ referrer_method_idx, literal_offset),
+ target_type_idx_(target_type_idx) {
+ }
+
+ const uint32_t target_type_idx_;
+
+ friend class CompilerDriver;
+ DISALLOW_COPY_AND_ASSIGN(TypePatchInformation);
+ };
+
+ const std::vector<const CallPatchInformation*>& GetCodeToPatch() const {
return code_to_patch_;
}
- const std::vector<const PatchInformation*>& GetMethodsToPatch() const {
+ const std::vector<const CallPatchInformation*>& GetMethodsToPatch() const {
return methods_to_patch_;
}
+ const std::vector<const TypePatchInformation*>& GetClassesToPatch() const {
+ return classes_to_patch_;
+ }
// Checks if class specified by type_idx is one of the image_classes_
bool IsImageClass(const char* descriptor) const;
@@ -408,10 +484,11 @@ class CompilerDriver {
static void CompileClass(const ParallelCompilationManager* context, size_t class_def_index)
LOCKS_EXCLUDED(Locks::mutator_lock_);
- std::vector<const PatchInformation*> code_to_patch_;
- std::vector<const PatchInformation*> methods_to_patch_;
+ std::vector<const CallPatchInformation*> code_to_patch_;
+ std::vector<const CallPatchInformation*> methods_to_patch_;
+ std::vector<const TypePatchInformation*> classes_to_patch_;
- VerifiedMethodsData* verified_methods_data_;
+ VerificationResults* verification_results_;
DexFileToMethodInlinerMap* method_inliner_map_;
CompilerBackend compiler_backend_;
@@ -446,9 +523,6 @@ class CompilerDriver {
UniquePtr<AOTCompilationStats> stats_;
bool dump_stats_;
- const bool dump_passes_;
-
- CumulativeLogger* const timings_logger_;
typedef void (*CompilerCallbackFn)(CompilerDriver& driver);
typedef MutexLock* (*CompilerMutexLockFn)(CompilerDriver& driver);
diff --git a/compiler/driver/dex_compilation_unit.cc b/compiler/driver/dex_compilation_unit.cc
index c441d09ab2..840b0adf49 100644
--- a/compiler/driver/dex_compilation_unit.cc
+++ b/compiler/driver/dex_compilation_unit.cc
@@ -31,7 +31,8 @@ DexCompilationUnit::DexCompilationUnit(CompilationUnit* cu)
code_item_(cu->code_item),
class_def_idx_(cu->class_def_idx),
dex_method_idx_(cu->method_idx),
- access_flags_(cu->access_flags) {
+ access_flags_(cu->access_flags),
+ verified_method_(cu_->compiler_driver->GetVerifiedMethod(cu->dex_file, cu->method_idx)) {
}
DexCompilationUnit::DexCompilationUnit(CompilationUnit* cu,
@@ -41,7 +42,8 @@ DexCompilationUnit::DexCompilationUnit(CompilationUnit* cu,
const DexFile::CodeItem* code_item,
uint16_t class_def_idx,
uint32_t method_idx,
- uint32_t access_flags)
+ uint32_t access_flags,
+ const VerifiedMethod* verified_method)
: cu_(cu),
class_loader_(class_loader),
class_linker_(class_linker),
@@ -49,7 +51,8 @@ DexCompilationUnit::DexCompilationUnit(CompilationUnit* cu,
code_item_(code_item),
class_def_idx_(class_def_idx),
dex_method_idx_(method_idx),
- access_flags_(access_flags) {
+ access_flags_(access_flags),
+ verified_method_(verified_method) {
}
const std::string& DexCompilationUnit::GetSymbol() {
diff --git a/compiler/driver/dex_compilation_unit.h b/compiler/driver/dex_compilation_unit.h
index 3df50ffec6..84f57991c3 100644
--- a/compiler/driver/dex_compilation_unit.h
+++ b/compiler/driver/dex_compilation_unit.h
@@ -29,6 +29,7 @@ class DexCache;
} // namespace mirror
class ClassLinker;
struct CompilationUnit;
+class VerifiedMethod;
class DexCompilationUnit {
public:
@@ -36,7 +37,8 @@ class DexCompilationUnit {
DexCompilationUnit(CompilationUnit* cu, jobject class_loader, ClassLinker* class_linker,
const DexFile& dex_file, const DexFile::CodeItem* code_item,
- uint16_t class_def_idx, uint32_t method_idx, uint32_t access_flags);
+ uint16_t class_def_idx, uint32_t method_idx, uint32_t access_flags,
+ const VerifiedMethod* verified_method);
CompilationUnit* GetCompilationUnit() const {
return cu_;
@@ -96,6 +98,10 @@ class DexCompilationUnit {
return ((access_flags_ & kAccSynchronized) != 0);
}
+ const VerifiedMethod* GetVerifiedMethod() const {
+ return verified_method_;
+ }
+
const std::string& GetSymbol();
private:
@@ -111,6 +117,7 @@ class DexCompilationUnit {
const uint16_t class_def_idx_;
const uint32_t dex_method_idx_;
const uint32_t access_flags_;
+ const VerifiedMethod* const verified_method_;
std::string symbol_;
};
diff --git a/compiler/elf_writer.h b/compiler/elf_writer.h
index 0ef4185431..dbc986a6e2 100644
--- a/compiler/elf_writer.h
+++ b/compiler/elf_writer.h
@@ -44,7 +44,7 @@ class ElfWriter {
size_t& oat_data_offset);
// Returns runtime oat_data runtime address for an opened ElfFile.
- static llvm::ELF::Elf32_Addr GetOatDataAddress(ElfFile* elf_file);
+ static ::llvm::ELF::Elf32_Addr GetOatDataAddress(ElfFile* elf_file);
protected:
ElfWriter(const CompilerDriver& driver, File* elf_file);
diff --git a/compiler/elf_writer_mclinker.h b/compiler/elf_writer_mclinker.h
index fa7e9caa19..8ee7231f79 100644
--- a/compiler/elf_writer_mclinker.h
+++ b/compiler/elf_writer_mclinker.h
@@ -69,7 +69,7 @@ class ElfWriterMclinker : public ElfWriter {
void FixupOatMethodOffsets(const std::vector<const DexFile*>& dex_files)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
uint32_t FixupCompiledCodeOffset(ElfFile& elf_file,
- llvm::ELF::Elf32_Addr oatdata_address,
+ ::llvm::ELF::Elf32_Addr oatdata_address,
const CompiledCode& compiled_code);
#endif
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 556dec25ad..09bb70cd2f 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -734,7 +734,7 @@ void ImageWriter::FixupFields(const Object* orig,
}
}
-static ArtMethod* GetTargetMethod(const CompilerDriver::PatchInformation* patch)
+static ArtMethod* GetTargetMethod(const CompilerDriver::CallPatchInformation* patch)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Thread* self = Thread::Current();
@@ -757,15 +757,34 @@ static ArtMethod* GetTargetMethod(const CompilerDriver::PatchInformation* patch)
return method;
}
+static Class* GetTargetType(const CompilerDriver::TypePatchInformation* patch)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Thread* self = Thread::Current();
+ SirtRef<mirror::DexCache> dex_cache(self, class_linker->FindDexCache(patch->GetDexFile()));
+ SirtRef<mirror::ClassLoader> class_loader(self, nullptr);
+ Class* klass = class_linker->ResolveType(patch->GetDexFile(),
+ patch->GetTargetTypeIdx(),
+ dex_cache,
+ class_loader);
+ CHECK(klass != NULL)
+ << patch->GetDexFile().GetLocation() << " " << patch->GetTargetTypeIdx();
+ CHECK(dex_cache->GetResolvedTypes()->Get(patch->GetTargetTypeIdx()) == klass)
+ << patch->GetDexFile().GetLocation() << " " << patch->GetReferrerMethodIdx() << " "
+ << PrettyClass(dex_cache->GetResolvedTypes()->Get(patch->GetTargetTypeIdx())) << " "
+ << PrettyClass(klass);
+ return klass;
+}
+
void ImageWriter::PatchOatCodeAndMethods() {
Thread* self = Thread::Current();
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter");
- typedef std::vector<const CompilerDriver::PatchInformation*> Patches;
- const Patches& code_to_patch = compiler_driver_.GetCodeToPatch();
+ typedef std::vector<const CompilerDriver::CallPatchInformation*> CallPatches;
+ const CallPatches& code_to_patch = compiler_driver_.GetCodeToPatch();
for (size_t i = 0; i < code_to_patch.size(); i++) {
- const CompilerDriver::PatchInformation* patch = code_to_patch[i];
+ const CompilerDriver::CallPatchInformation* patch = code_to_patch[i];
ArtMethod* target = GetTargetMethod(patch);
uint32_t code = reinterpret_cast<uint32_t>(class_linker->GetOatCodeFor(target));
uint32_t code_base = reinterpret_cast<uint32_t>(&oat_file_->GetOatHeader());
@@ -773,13 +792,21 @@ void ImageWriter::PatchOatCodeAndMethods() {
SetPatchLocation(patch, reinterpret_cast<uint32_t>(GetOatAddress(code_offset)));
}
- const Patches& methods_to_patch = compiler_driver_.GetMethodsToPatch();
+ const CallPatches& methods_to_patch = compiler_driver_.GetMethodsToPatch();
for (size_t i = 0; i < methods_to_patch.size(); i++) {
- const CompilerDriver::PatchInformation* patch = methods_to_patch[i];
+ const CompilerDriver::CallPatchInformation* patch = methods_to_patch[i];
ArtMethod* target = GetTargetMethod(patch);
SetPatchLocation(patch, reinterpret_cast<uint32_t>(GetImageAddress(target)));
}
+ const std::vector<const CompilerDriver::TypePatchInformation*>& classes_to_patch =
+ compiler_driver_.GetClassesToPatch();
+ for (size_t i = 0; i < classes_to_patch.size(); i++) {
+ const CompilerDriver::TypePatchInformation* patch = classes_to_patch[i];
+ Class* target = GetTargetType(patch);
+ SetPatchLocation(patch, reinterpret_cast<uint32_t>(GetImageAddress(target)));
+ }
+
// Update the image header with the new checksum after patching
ImageHeader* image_header = reinterpret_cast<ImageHeader*>(image_->Begin());
image_header->SetOatChecksum(oat_file_->GetOatHeader().GetChecksum());
@@ -796,13 +823,26 @@ void ImageWriter::SetPatchLocation(const CompilerDriver::PatchInformation* patch
uint8_t* base = reinterpret_cast<uint8_t*>(reinterpret_cast<uint32_t>(oat_code) & ~0x1);
uint32_t* patch_location = reinterpret_cast<uint32_t*>(base + patch->GetLiteralOffset());
if (kIsDebugBuild) {
- const DexFile::MethodId& id = patch->GetDexFile().GetMethodId(patch->GetTargetMethodIdx());
- uint32_t expected = reinterpret_cast<uint32_t>(&id);
- uint32_t actual = *patch_location;
- CHECK(actual == expected || actual == value) << std::hex
- << "actual=" << actual
- << "expected=" << expected
- << "value=" << value;
+ if (patch->IsCall()) {
+ const CompilerDriver::CallPatchInformation* cpatch = patch->AsCall();
+ const DexFile::MethodId& id = cpatch->GetDexFile().GetMethodId(cpatch->GetTargetMethodIdx());
+ uint32_t expected = reinterpret_cast<uint32_t>(&id);
+ uint32_t actual = *patch_location;
+ CHECK(actual == expected || actual == value) << std::hex
+ << "actual=" << actual
+ << "expected=" << expected
+ << "value=" << value;
+ }
+ if (patch->IsType()) {
+ const CompilerDriver::TypePatchInformation* tpatch = patch->AsType();
+ const DexFile::TypeId& id = tpatch->GetDexFile().GetTypeId(tpatch->GetTargetTypeIdx());
+ uint32_t expected = reinterpret_cast<uint32_t>(&id);
+ uint32_t actual = *patch_location;
+ CHECK(actual == expected || actual == value) << std::hex
+ << "actual=" << actual
+ << "expected=" << expected
+ << "value=" << value;
+ }
}
*patch_location = value;
oat_header.UpdateChecksum(patch_location, sizeof(value));
diff --git a/compiler/llvm/compiler_llvm.cc b/compiler/llvm/compiler_llvm.cc
index 35d1ecd783..94408bb39c 100644
--- a/compiler/llvm/compiler_llvm.cc
+++ b/compiler/llvm/compiler_llvm.cc
@@ -20,7 +20,8 @@
#include "base/stl_util.h"
#include "class_linker.h"
#include "compiled_method.h"
-#include "dex/verified_methods_data.h"
+#include "dex/verification_results.h"
+#include "dex/verified_method.h"
#include "driver/compiler_driver.h"
#include "driver/dex_compilation_unit.h"
#include "globals.h"
@@ -153,11 +154,9 @@ CompileDexMethod(DexCompilationUnit* dex_compilation_unit, InvokeType invoke_typ
cunit->Materialize();
- MethodReference mref(dex_compilation_unit->GetDexFile(),
- dex_compilation_unit->GetDexMethodIndex());
return new CompiledMethod(*compiler_driver_, compiler_driver_->GetInstructionSet(),
cunit->GetElfObject(),
- *compiler_driver_->GetVerifiedMethodsData()->GetDexGcMap(mref),
+ dex_compilation_unit->GetVerifiedMethod()->GetDexGcMap(),
cunit->GetDexCompilationUnit()->GetSymbol());
}
@@ -214,7 +213,7 @@ extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver& driver,
art::DexCompilationUnit dex_compilation_unit(
NULL, class_loader, class_linker, dex_file, code_item,
- class_def_idx, method_idx, access_flags);
+ class_def_idx, method_idx, access_flags, driver.GetVerifiedMethod(&dex_file, method_idx));
art::llvm::CompilerLLVM* compiler_llvm = ContextOf(driver);
art::CompiledMethod* result = compiler_llvm->CompileDexMethod(&dex_compilation_unit, invoke_type);
return result;
@@ -226,8 +225,8 @@ extern "C" art::CompiledMethod* ArtLLVMJniCompileMethod(art::CompilerDriver& dri
art::ClassLinker *class_linker = art::Runtime::Current()->GetClassLinker();
art::DexCompilationUnit dex_compilation_unit(
- NULL, NULL, class_linker, dex_file, NULL,
- 0, method_idx, access_flags);
+ nullptr, nullptr, class_linker, dex_file, nullptr,
+ 0, method_idx, access_flags, nullptr);
art::llvm::CompilerLLVM* compiler_llvm = ContextOf(driver);
art::CompiledMethod* result = compiler_llvm->CompileNativeMethod(&dex_compilation_unit);
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 12d821239f..fc454127c3 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -79,14 +79,13 @@ TEST_F(OatTest, WriteRead) {
InstructionSet insn_set = kIsTargetBuild ? kThumb2 : kX86;
InstructionSetFeatures insn_features;
- verified_methods_data_.reset(new VerifiedMethodsData);
+ verification_results_.reset(new VerificationResults);
method_inliner_map_.reset(compiler_backend == kQuick ? new DexFileToMethodInlinerMap : nullptr);
- callbacks_.Reset(verified_methods_data_.get(), method_inliner_map_.get());
- CumulativeLogger timer("Compilation times");
- compiler_driver_.reset(new CompilerDriver(verified_methods_data_.get(),
+ callbacks_.Reset(verification_results_.get(), method_inliner_map_.get());
+ compiler_driver_.reset(new CompilerDriver(verification_results_.get(),
method_inliner_map_.get(),
compiler_backend, insn_set,
- insn_features, false, NULL, 2, true, true, &timer));
+ insn_features, false, NULL, 2, true));
jobject class_loader = NULL;
if (kCompile) {
TimingLogger timings("OatTest::WriteRead", false, false);
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 199a2b8d58..7a902d86d6 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -23,7 +23,7 @@
#include "base/unix_file/fd_file.h"
#include "class_linker.h"
#include "dex_file-inl.h"
-#include "dex/verified_methods_data.h"
+#include "dex/verification_results.h"
#include "gc/space/space.h"
#include "mirror/art_method-inl.h"
#include "mirror/array.h"
@@ -218,7 +218,7 @@ size_t OatWriter::InitOatClasses(size_t offset) {
mirror::Class::Status status;
if (compiled_class != NULL) {
status = compiled_class->GetStatus();
- } else if (compiler_driver_->GetVerifiedMethodsData()->IsClassRejected(class_ref)) {
+ } else if (compiler_driver_->GetVerificationResults()->IsClassRejected(class_ref)) {
status = mirror::Class::kStatusError;
} else {
status = mirror::Class::kStatusNotReady;
@@ -433,7 +433,7 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index,
mirror::Class::Status status;
if (compiled_class != NULL) {
status = compiled_class->GetStatus();
- } else if (compiler_driver_->GetVerifiedMethodsData()->IsClassRejected(class_ref)) {
+ } else if (compiler_driver_->GetVerificationResults()->IsClassRejected(class_ref)) {
status = mirror::Class::kStatusError;
} else {
status = mirror::Class::kStatusNotReady;