Merge "Ignore not yet loaded classes during hprof"
diff --git a/compiler/compiler.h b/compiler/compiler.h
index 6ec39f9..a04641e 100644
--- a/compiler/compiler.h
+++ b/compiler/compiler.h
@@ -107,6 +107,9 @@
return driver_;
}
+ // Whether to produce 64-bit ELF files for 64-bit targets. Leave this off for now.
+ static constexpr bool kProduce64BitELFFiles = false;
+
private:
CompilerDriver* const driver_;
const uint64_t maximum_compilation_time_before_warning_;
diff --git a/compiler/dex/mir_dataflow.cc b/compiler/dex/mir_dataflow.cc
index f638b0b..2a920a4 100644
--- a/compiler/dex/mir_dataflow.cc
+++ b/compiler/dex/mir_dataflow.cc
@@ -1396,6 +1396,13 @@
InitializeBasicBlockDataFlow();
}
+uint32_t MIRGraph::GetUseCountWeight(BasicBlock* bb) const {
+ // Each level of nesting adds *100 to count, up to 3 levels deep.
+ uint32_t depth = std::min(3U, static_cast<uint32_t>(bb->nesting_depth));
+ uint32_t weight = std::max(1U, depth * 100);
+ return weight;
+}
+
/*
* Count uses, weighting by loop nesting depth. This code only
* counts explicitly used s_regs. A later phase will add implicit
@@ -1405,9 +1412,7 @@
if (bb->block_type != kDalvikByteCode) {
return;
}
- // Each level of nesting adds *100 to count, up to 3 levels deep.
- uint32_t depth = std::min(3U, static_cast<uint32_t>(bb->nesting_depth));
- uint32_t weight = std::max(1U, depth * 100);
+ uint32_t weight = GetUseCountWeight(bb);
for (MIR* mir = bb->first_mir_insn; (mir != NULL); mir = mir->next) {
if (mir->ssa_rep == NULL) {
continue;
@@ -1417,23 +1422,6 @@
raw_use_counts_[s_reg] += 1u;
use_counts_[s_reg] += weight;
}
- if (!(cu_->disable_opt & (1 << kPromoteCompilerTemps))) {
- uint64_t df_attributes = GetDataFlowAttributes(mir);
- // Implicit use of Method* ? */
- if (df_attributes & DF_UMS) {
- /*
- * Some invokes will not use Method* - need to perform test similar
- * to that found in GenInvoke() to decide whether to count refs
- * for Method* on invoke-class opcodes. This is a relatively expensive
- * operation, so should only be done once.
- * TODO: refactor InvokeUsesMethodStar() to perform check at parse time,
- * and save results for both here and GenInvoke. For now, go ahead
- * and assume all invokes use method*.
- */
- raw_use_counts_[method_sreg_] += 1u;
- use_counts_[method_sreg_] += weight;
- }
- }
}
}
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc
index 58f12c9..4d34038 100644
--- a/compiler/dex/mir_graph.cc
+++ b/compiler/dex/mir_graph.cc
@@ -1609,8 +1609,8 @@
}
std::string MIRGraph::GetSSAName(int ssa_reg) {
- // TODO: This value is needed for LLVM and debugging. Currently, we compute this and then copy to
- // the arena. We should be smarter and just place straight into the arena, or compute the
+ // TODO: This value is needed for debugging. Currently, we compute this and then copy to the
+ // arena. We should be smarter and just place straight into the arena, or compute the
// value more lazily.
int vreg = SRegToVReg(ssa_reg);
if (vreg >= static_cast<int>(GetFirstTempVR())) {
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index 3298af1..d4a9eb9 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -960,6 +960,12 @@
*/
CompilerTemp* GetNewCompilerTemp(CompilerTempType ct_type, bool wide);
+ /**
+ * @brief Used to remove last created compiler temporary when it's not needed.
+ * @param temp the temporary to remove.
+ */
+ void RemoveLastCompilerTemp(CompilerTempType ct_type, bool wide, CompilerTemp* temp);
+
bool MethodIsLeaf() {
return attributes_ & METHOD_IS_LEAF;
}
@@ -1185,6 +1191,12 @@
void DoConstantPropagation(BasicBlock* bb);
/**
+ * @brief Get use count weight for a given block.
+ * @param bb the BasicBlock.
+ */
+ uint32_t GetUseCountWeight(BasicBlock* bb) const;
+
+ /**
* @brief Count the uses in the BasicBlock
* @param bb the BasicBlock
*/
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc
index c85c3b6..5dcc903 100644
--- a/compiler/dex/mir_optimization.cc
+++ b/compiler/dex/mir_optimization.cc
@@ -318,9 +318,11 @@
// Since VR temps cannot be requested once the BE temps are requested, we
// allow reservation of VR temps as well for BE. We
size_t available_temps = reserved_temps_for_backend_ + GetNumAvailableVRTemps();
- if (available_temps <= 0 || (available_temps <= 1 && wide)) {
+ size_t needed_temps = wide ? 2u : 1u;
+ if (available_temps < needed_temps) {
if (verbose) {
- LOG(INFO) << "CompilerTemps: Not enough temp(s) of type " << ct_type_str << " are available.";
+ LOG(INFO) << "CompilerTemps: Not enough temp(s) of type " << ct_type_str
+ << " are available.";
}
return nullptr;
}
@@ -328,12 +330,8 @@
// Update the remaining reserved temps since we have now used them.
// Note that the code below is actually subtracting to remove them from reserve
// once they have been claimed. It is careful to not go below zero.
- if (reserved_temps_for_backend_ >= 1) {
- reserved_temps_for_backend_--;
- }
- if (wide && reserved_temps_for_backend_ >= 1) {
- reserved_temps_for_backend_--;
- }
+ reserved_temps_for_backend_ =
+ std::max(reserved_temps_for_backend_, needed_temps) - needed_temps;
// The new non-special compiler temp must receive a unique v_reg.
compiler_temp->v_reg = GetFirstNonSpecialTempVR() + num_non_special_compiler_temps_;
@@ -407,6 +405,36 @@
return compiler_temp;
}
+void MIRGraph::RemoveLastCompilerTemp(CompilerTempType ct_type, bool wide, CompilerTemp* temp) {
+ // Once the compiler temps have been committed, it's too late for any modifications.
+ DCHECK_EQ(compiler_temps_committed_, false);
+
+ size_t used_temps = wide ? 2u : 1u;
+
+ if (ct_type == kCompilerTempBackend) {
+ DCHECK(requested_backend_temp_);
+
+ // Make the temps available to backend again.
+ reserved_temps_for_backend_ += used_temps;
+ } else if (ct_type == kCompilerTempVR) {
+ DCHECK(!requested_backend_temp_);
+ } else {
+ UNIMPLEMENTED(FATAL) << "No handling for compiler temp type " << static_cast<int>(ct_type);
+ }
+
+ // Reduce the number of non-special compiler temps.
+ DCHECK_LE(used_temps, num_non_special_compiler_temps_);
+ num_non_special_compiler_temps_ -= used_temps;
+
+ // Check that this was really the last temp.
+ DCHECK_EQ(static_cast<size_t>(temp->v_reg),
+ GetFirstNonSpecialTempVR() + num_non_special_compiler_temps_);
+
+ if (cu_->verbose) {
+ LOG(INFO) << "Last temporary has been removed.";
+ }
+}
+
static bool EvaluateBranch(Instruction::Code opcode, int32_t src1, int32_t src2) {
bool is_taken;
switch (opcode) {
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index e6158c3..518e3ea 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -29,6 +29,7 @@
#include "mirror/object_array-inl.h"
#include "entrypoints/quick/quick_entrypoints.h"
#include "utils.h"
+#include "utils/dex_cache_arrays_layout-inl.h"
namespace art {
@@ -490,6 +491,14 @@
FlushIns(ArgLocs, rl_method);
+ // We can promote a PC-relative reference to dex cache arrays to a register
+ // if it's used at least twice. Without investigating where we should lazily
+ // load the reference, we conveniently load it after flushing inputs.
+ if (dex_cache_arrays_base_reg_.Valid()) {
+ OpPcRelDexCacheArrayAddr(cu_->dex_file, dex_cache_arrays_min_offset_,
+ dex_cache_arrays_base_reg_);
+ }
+
FreeTemp(rs_r0);
FreeTemp(rs_r1);
FreeTemp(rs_r2);
@@ -571,12 +580,12 @@
* Bit of a hack here - in the absence of a real scheduling pass,
* emit the next instruction in static & direct invoke sequences.
*/
-static int ArmNextSDCallInsn(CompilationUnit* cu, CallInfo* info ATTRIBUTE_UNUSED,
- int state, const MethodReference& target_method,
- uint32_t unused_idx ATTRIBUTE_UNUSED,
- uintptr_t direct_code, uintptr_t direct_method,
- InvokeType type) {
- Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
+int ArmMir2Lir::ArmNextSDCallInsn(CompilationUnit* cu, CallInfo* info ATTRIBUTE_UNUSED,
+ int state, const MethodReference& target_method,
+ uint32_t unused_idx ATTRIBUTE_UNUSED,
+ uintptr_t direct_code, uintptr_t direct_method,
+ InvokeType type) {
+ ArmMir2Lir* cg = static_cast<ArmMir2Lir*>(cu->cg.get());
if (direct_code != 0 && direct_method != 0) {
switch (state) {
case 0: // Get the current Method* [sets kArg0]
@@ -597,17 +606,24 @@
return -1;
}
} else {
+ bool use_pc_rel = cg->CanUseOpPcRelDexCacheArrayLoad();
RegStorage arg0_ref = cg->TargetReg(kArg0, kRef);
switch (state) {
case 0: // Get the current Method* [sets kArg0]
// TUNING: we can save a reg copy if Method* has been promoted.
- cg->LoadCurrMethodDirect(arg0_ref);
- break;
+ if (!use_pc_rel) {
+ cg->LoadCurrMethodDirect(arg0_ref);
+ break;
+ }
+ ++state;
+ FALLTHROUGH_INTENDED;
case 1: // Get method->dex_cache_resolved_methods_
- cg->LoadRefDisp(arg0_ref,
- mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(),
- arg0_ref,
- kNotVolatile);
+ if (!use_pc_rel) {
+ cg->LoadRefDisp(arg0_ref,
+ mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(),
+ arg0_ref,
+ kNotVolatile);
+ }
// Set up direct code if known.
if (direct_code != 0) {
if (direct_code != static_cast<uintptr_t>(-1)) {
@@ -619,14 +635,23 @@
cg->LoadCodeAddress(target_method, type, kInvokeTgt);
}
}
- break;
+ if (!use_pc_rel || direct_code != 0) {
+ break;
+ }
+ ++state;
+ FALLTHROUGH_INTENDED;
case 2: // Grab target method*
CHECK_EQ(cu->dex_file, target_method.dex_file);
- cg->LoadRefDisp(arg0_ref,
- mirror::ObjectArray<mirror::Object>::OffsetOfElement(
- target_method.dex_method_index).Int32Value(),
- arg0_ref,
- kNotVolatile);
+ if (!use_pc_rel) {
+ cg->LoadRefDisp(arg0_ref,
+ mirror::ObjectArray<mirror::Object>::OffsetOfElement(
+ target_method.dex_method_index).Int32Value(),
+ arg0_ref,
+ kNotVolatile);
+ } else {
+ size_t offset = cg->dex_cache_arrays_layout_.MethodOffset(target_method.dex_method_index);
+ cg->OpPcRelDexCacheArrayLoad(cu->dex_file, offset, arg0_ref);
+ }
break;
case 3: // Grab the code from the method*
if (direct_code == 0) {
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 4141bcf..83b27df 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -82,6 +82,9 @@
/// @copydoc Mir2Lir::UnconditionallyMarkGCCard(RegStorage)
void UnconditionallyMarkGCCard(RegStorage tgt_addr_reg) OVERRIDE;
+ bool CanUseOpPcRelDexCacheArrayLoad() const OVERRIDE;
+ void OpPcRelDexCacheArrayLoad(const DexFile* dex_file, int offset, RegStorage r_dest) OVERRIDE;
+
// Required for target - register utilities.
RegStorage TargetReg(SpecialTargetRegister reg) OVERRIDE;
RegStorage TargetReg(SpecialTargetRegister reg, WideKind wide_kind) OVERRIDE {
@@ -257,6 +260,9 @@
*/
LIR* GenCallInsn(const MirMethodLoweringInfo& method_info) OVERRIDE;
+ void CountRefs(RefCounts* core_counts, RefCounts* fp_counts, size_t num_regs) OVERRIDE;
+ void DoPromotion() OVERRIDE;
+
/*
* @brief Handle ARM specific literals.
*/
@@ -300,6 +306,13 @@
ArenaVector<LIR*> call_method_insns_;
+ // Instructions needing patching with PC relative code addresses.
+ ArenaVector<LIR*> dex_cache_access_insns_;
+
+ // Register with a reference to the dex cache arrays at dex_cache_arrays_min_offset_,
+ // if promoted.
+ RegStorage dex_cache_arrays_base_reg_;
+
/**
* @brief Given float register pair, returns Solo64 float register.
* @param reg #RegStorage containing a float register pair (e.g. @c s2 and @c s3).
@@ -329,6 +342,14 @@
}
int GenDalvikArgsBulkCopy(CallInfo* info, int first, int count) OVERRIDE;
+
+ static int ArmNextSDCallInsn(CompilationUnit* cu, CallInfo* info ATTRIBUTE_UNUSED,
+ int state, const MethodReference& target_method,
+ uint32_t unused_idx ATTRIBUTE_UNUSED,
+ uintptr_t direct_code, uintptr_t direct_method,
+ InvokeType type);
+
+ void OpPcRelDexCacheArrayAddr(const DexFile* dex_file, int offset, RegStorage r_dest);
};
} // namespace art
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index 9193e1b..47669db 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -1087,6 +1087,36 @@
lir->target = target;
}
+bool ArmMir2Lir::CanUseOpPcRelDexCacheArrayLoad() const {
+ return dex_cache_arrays_layout_.Valid();
+}
+
+void ArmMir2Lir::OpPcRelDexCacheArrayAddr(const DexFile* dex_file, int offset, RegStorage r_dest) {
+ LIR* movw = NewLIR2(kThumb2MovImm16, r_dest.GetReg(), 0);
+ LIR* movt = NewLIR2(kThumb2MovImm16H, r_dest.GetReg(), 0);
+ ArmOpcode add_pc_opcode = (r_dest.GetRegNum() < 8) ? kThumbAddRRLH : kThumbAddRRHH;
+ LIR* add_pc = NewLIR2(add_pc_opcode, r_dest.GetReg(), rs_rARM_PC.GetReg());
+ add_pc->flags.fixup = kFixupLabel;
+ movw->operands[2] = WrapPointer(dex_file);
+ movw->operands[3] = offset;
+ movw->operands[4] = WrapPointer(add_pc);
+ movt->operands[2] = movw->operands[2];
+ movt->operands[3] = movw->operands[3];
+ movt->operands[4] = movw->operands[4];
+ dex_cache_access_insns_.push_back(movw);
+ dex_cache_access_insns_.push_back(movt);
+}
+
+void ArmMir2Lir::OpPcRelDexCacheArrayLoad(const DexFile* dex_file, int offset, RegStorage r_dest) {
+ if (dex_cache_arrays_base_reg_.Valid()) {
+ LoadRefDisp(dex_cache_arrays_base_reg_, offset - dex_cache_arrays_min_offset_,
+ r_dest, kNotVolatile);
+ } else {
+ OpPcRelDexCacheArrayAddr(dex_file, offset, r_dest);
+ LoadRefDisp(r_dest, 0, r_dest, kNotVolatile);
+ }
+}
+
LIR* ArmMir2Lir::OpVldm(RegStorage r_base, int count) {
return NewLIR3(kThumb2Vldms, r_base.GetReg(), rs_fr0.GetReg(), count);
}
diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc
index 9812d9f..5f27338 100644
--- a/compiler/dex/quick/arm/target_arm.cc
+++ b/compiler/dex/quick/arm/target_arm.cc
@@ -575,7 +575,9 @@
ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
: Mir2Lir(cu, mir_graph, arena),
- call_method_insns_(arena->Adapter()) {
+ call_method_insns_(arena->Adapter()),
+ dex_cache_access_insns_(arena->Adapter()),
+ dex_cache_arrays_base_reg_(RegStorage::InvalidReg()) {
call_method_insns_.reserve(100);
// Sanity check - make sure encoding map lines up.
for (int i = 0; i < kArmLast; i++) {
@@ -901,14 +903,28 @@
}
void ArmMir2Lir::InstallLiteralPools() {
+ patches_.reserve(call_method_insns_.size() + dex_cache_access_insns_.size());
+
// PC-relative calls to methods.
- patches_.reserve(call_method_insns_.size());
for (LIR* p : call_method_insns_) {
- DCHECK_EQ(p->opcode, kThumb2Bl);
- uint32_t target_method_idx = p->operands[1];
- const DexFile* target_dex_file = UnwrapPointer<DexFile>(p->operands[2]);
- patches_.push_back(LinkerPatch::RelativeCodePatch(p->offset,
- target_dex_file, target_method_idx));
+ DCHECK_EQ(p->opcode, kThumb2Bl);
+ uint32_t target_method_idx = p->operands[1];
+ const DexFile* target_dex_file = UnwrapPointer<DexFile>(p->operands[2]);
+ patches_.push_back(LinkerPatch::RelativeCodePatch(p->offset,
+ target_dex_file, target_method_idx));
+ }
+
+ // PC-relative dex cache array accesses.
+ for (LIR* p : dex_cache_access_insns_) {
+ DCHECK(p->opcode = kThumb2MovImm16 || p->opcode == kThumb2MovImm16H);
+ const LIR* add_pc = UnwrapPointer<LIR>(p->operands[4]);
+ DCHECK(add_pc->opcode == kThumbAddRRLH || add_pc->opcode == kThumbAddRRHH);
+ const DexFile* dex_file = UnwrapPointer<DexFile>(p->operands[2]);
+ uint32_t offset = p->operands[3];
+ DCHECK(!p->flags.is_nop);
+ DCHECK(!add_pc->flags.is_nop);
+ patches_.push_back(LinkerPatch::DexCacheArrayPatch(p->offset,
+ dex_file, add_pc->offset, offset));
}
// And do the normal processing.
diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc
index e4bd2a3..c3371cf 100644
--- a/compiler/dex/quick/arm/utility_arm.cc
+++ b/compiler/dex/quick/arm/utility_arm.cc
@@ -19,6 +19,7 @@
#include "arch/arm/instruction_set_features_arm.h"
#include "arm_lir.h"
#include "base/logging.h"
+#include "dex/mir_graph.h"
#include "dex/quick/mir_to_lir-inl.h"
#include "dex/reg_storage_eq.h"
#include "driver/compiler_driver.h"
@@ -1266,4 +1267,38 @@
return offset;
}
+void ArmMir2Lir::CountRefs(RefCounts* core_counts, RefCounts* fp_counts, size_t num_regs) {
+ // Start with the default counts.
+ Mir2Lir::CountRefs(core_counts, fp_counts, num_regs);
+
+ if (pc_rel_temp_ != nullptr) {
+ // Now, if the dex cache array base temp is used only once outside any loops (weight = 1),
+ // avoid the promotion, otherwise boost the weight by factor 4 because the full PC-relative
+ // load sequence is 4 instructions long.
+ int p_map_idx = SRegToPMap(pc_rel_temp_->s_reg_low);
+ if (core_counts[p_map_idx].count == 1) {
+ core_counts[p_map_idx].count = 0;
+ } else {
+ core_counts[p_map_idx].count *= 4;
+ }
+ }
+}
+
+void ArmMir2Lir::DoPromotion() {
+ if (CanUseOpPcRelDexCacheArrayLoad()) {
+ pc_rel_temp_ = mir_graph_->GetNewCompilerTemp(kCompilerTempBackend, false);
+ }
+
+ Mir2Lir::DoPromotion();
+
+ if (pc_rel_temp_ != nullptr) {
+ // Now, if the dex cache array base temp is promoted, remember the register but
+ // always remove the temp's stack location to avoid unnecessarily bloating the stack.
+ dex_cache_arrays_base_reg_ = mir_graph_->reg_location_[pc_rel_temp_->s_reg_low].reg;
+ DCHECK(!dex_cache_arrays_base_reg_.Valid() || !dex_cache_arrays_base_reg_.IsFloat());
+ mir_graph_->RemoveLastCompilerTemp(kCompilerTempBackend, false, pc_rel_temp_);
+ pc_rel_temp_ = nullptr;
+ }
+}
+
} // namespace art
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index f944c11..c51046e 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -1070,6 +1070,8 @@
mask_cache_(arena),
safepoints_(arena->Adapter()),
dex_cache_arrays_layout_(cu->compiler_driver->GetDexCacheArraysLayout(cu->dex_file)),
+ pc_rel_temp_(nullptr),
+ dex_cache_arrays_min_offset_(std::numeric_limits<uint32_t>::max()),
in_to_reg_storage_mapping_(arena) {
switch_tables_.reserve(4);
fill_array_data_.reserve(4);
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 1813e09..b132c4c 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -94,6 +94,97 @@
r_method, r_result));
}
+RegStorage Mir2Lir::GenGetOtherTypeForSgetSput(const MirSFieldLoweringInfo& field_info,
+ int opt_flags) {
+ DCHECK_NE(field_info.StorageIndex(), DexFile::kDexNoIndex);
+ // May do runtime call so everything to home locations.
+ FlushAllRegs();
+ RegStorage r_base = TargetReg(kArg0, kRef);
+ LockTemp(r_base);
+ RegStorage r_method = RegStorage::InvalidReg(); // Loaded lazily, maybe in the slow-path.
+ if (CanUseOpPcRelDexCacheArrayLoad()) {
+ uint32_t offset = dex_cache_arrays_layout_.TypeOffset(field_info.StorageIndex());
+ OpPcRelDexCacheArrayLoad(cu_->dex_file, offset, r_base);
+ } else {
+ // Using fixed register to sync with possible call to runtime support.
+ r_method = LoadCurrMethodWithHint(TargetReg(kArg1, kRef));
+ LoadRefDisp(r_method, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), r_base,
+ kNotVolatile);
+ int32_t offset_of_field = ObjArray::OffsetOfElement(field_info.StorageIndex()).Int32Value();
+ LoadRefDisp(r_base, offset_of_field, r_base, kNotVolatile);
+ }
+ // r_base now points at static storage (Class*) or nullptr if the type is not yet resolved.
+ LIR* unresolved_branch = nullptr;
+ if (!field_info.IsClassInDexCache() && (opt_flags & MIR_CLASS_IS_IN_DEX_CACHE) == 0) {
+ // Check if r_base is nullptr.
+ unresolved_branch = OpCmpImmBranch(kCondEq, r_base, 0, nullptr);
+ }
+ LIR* uninit_branch = nullptr;
+ if (!field_info.IsClassInitialized() && (opt_flags & MIR_CLASS_IS_INITIALIZED) == 0) {
+ // Check if r_base is not yet initialized class.
+ RegStorage r_tmp = TargetReg(kArg2, kNotWide);
+ LockTemp(r_tmp);
+ uninit_branch = OpCmpMemImmBranch(kCondLt, r_tmp, r_base,
+ mirror::Class::StatusOffset().Int32Value(),
+ mirror::Class::kStatusInitialized, nullptr, nullptr);
+ FreeTemp(r_tmp);
+ }
+ if (unresolved_branch != nullptr || uninit_branch != nullptr) {
+ //
+ // Slow path to ensure a class is initialized for sget/sput.
+ //
+ class StaticFieldSlowPath : public Mir2Lir::LIRSlowPath {
+ public:
+ // There are up to two branches to the static field slow path, the "unresolved" when the type
+ // entry in the dex cache is nullptr, and the "uninit" when the class is not yet initialized.
+ // At least one will be non-nullptr here, otherwise we wouldn't generate the slow path.
+ StaticFieldSlowPath(Mir2Lir* m2l, LIR* unresolved, LIR* uninit, LIR* cont, int storage_index,
+ RegStorage r_base_in, RegStorage r_method_in)
+ : LIRSlowPath(m2l, unresolved != nullptr ? unresolved : uninit, cont),
+ second_branch_(unresolved != nullptr ? uninit : nullptr),
+ storage_index_(storage_index), r_base_(r_base_in), r_method_(r_method_in) {
+ }
+
+ void Compile() {
+ LIR* target = GenerateTargetLabel();
+ if (second_branch_ != nullptr) {
+ second_branch_->target = target;
+ }
+ if (r_method_.Valid()) {
+ // ArtMethod* was loaded in normal path - use it.
+ m2l_->CallRuntimeHelperImmReg(kQuickInitializeStaticStorage, storage_index_, r_method_,
+ true);
+ } else {
+ // ArtMethod* wasn't loaded in normal path - use a helper that loads it.
+ m2l_->CallRuntimeHelperImmMethod(kQuickInitializeStaticStorage, storage_index_, true);
+ }
+ // Copy helper's result into r_base, a no-op on all but MIPS.
+ m2l_->OpRegCopy(r_base_, m2l_->TargetReg(kRet0, kRef));
+
+ m2l_->OpUnconditionalBranch(cont_);
+ }
+
+ private:
+ // Second branch to the slow path, or nullptr if there's only one branch.
+ LIR* const second_branch_;
+
+ const int storage_index_;
+ const RegStorage r_base_;
+ RegStorage r_method_;
+ };
+
+ // The slow path is invoked if the r_base is nullptr or the class pointed
+ // to by it is not initialized.
+ LIR* cont = NewLIR0(kPseudoTargetLabel);
+ AddSlowPath(new (arena_) StaticFieldSlowPath(this, unresolved_branch, uninit_branch, cont,
+ field_info.StorageIndex(), r_base, r_method));
+ }
+ if (IsTemp(r_method)) {
+ FreeTemp(r_method);
+ }
+ return r_base;
+}
+
/*
* Generate a kPseudoBarrier marker to indicate the boundary of special
* blocks.
@@ -609,41 +700,6 @@
CallRuntimeHelperImmRegLocation(kQuickHandleFillArrayData, table_offset_from_start, rl_src, true);
}
-//
-// Slow path to ensure a class is initialized for sget/sput.
-//
-class StaticFieldSlowPath : public Mir2Lir::LIRSlowPath {
- public:
- // There are up to two branches to the static field slow path, the "unresolved" when the type
- // entry in the dex cache is null, and the "uninit" when the class is not yet initialized.
- // At least one will be non-null here, otherwise we wouldn't generate the slow path.
- StaticFieldSlowPath(Mir2Lir* m2l, LIR* unresolved, LIR* uninit, LIR* cont, int storage_index,
- RegStorage r_base)
- : LIRSlowPath(m2l, unresolved != nullptr ? unresolved : uninit, cont),
- second_branch_(unresolved != nullptr ? uninit : nullptr),
- storage_index_(storage_index), r_base_(r_base) {
- }
-
- void Compile() {
- LIR* target = GenerateTargetLabel();
- if (second_branch_ != nullptr) {
- second_branch_->target = target;
- }
- m2l_->CallRuntimeHelperImm(kQuickInitializeStaticStorage, storage_index_, true);
- // Copy helper's result into r_base, a no-op on all but MIPS.
- m2l_->OpRegCopy(r_base_, m2l_->TargetReg(kRet0, kRef));
-
- m2l_->OpUnconditionalBranch(cont_);
- }
-
- private:
- // Second branch to the slow path, or null if there's only one branch.
- LIR* const second_branch_;
-
- const int storage_index_;
- const RegStorage r_base_;
-};
-
void Mir2Lir::GenSput(MIR* mir, RegLocation rl_src, OpSize size) {
const MirSFieldLoweringInfo& field_info = mir_graph_->GetSFieldLoweringInfo(mir);
DCHECK_EQ(SPutMemAccessType(mir->dalvikInsn.opcode), field_info.MemAccessType());
@@ -653,65 +709,23 @@
RegStorage r_base;
if (field_info.IsReferrersClass()) {
// Fast path, static storage base is this method's class
- RegLocation rl_method = LoadCurrMethod();
r_base = AllocTempRef();
- LoadRefDisp(rl_method.reg, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), r_base,
+ RegStorage r_method = LoadCurrMethodWithHint(r_base);
+ LoadRefDisp(r_method, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), r_base,
kNotVolatile);
- if (IsTemp(rl_method.reg)) {
- FreeTemp(rl_method.reg);
- }
} else {
// Medium path, static storage base in a different class which requires checks that the other
// class is initialized.
- // TODO: remove initialized check now that we are initializing classes in the compiler driver.
- DCHECK_NE(field_info.StorageIndex(), DexFile::kDexNoIndex);
- // May do runtime call so everything to home locations.
- FlushAllRegs();
- // Using fixed register to sync with possible call to runtime support.
- RegStorage r_method = TargetReg(kArg1, kRef);
- LockTemp(r_method);
- LoadCurrMethodDirect(r_method);
- r_base = TargetReg(kArg0, kRef);
- LockTemp(r_base);
- LoadRefDisp(r_method, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), r_base,
- kNotVolatile);
- int32_t offset_of_field = ObjArray::OffsetOfElement(field_info.StorageIndex()).Int32Value();
- LoadRefDisp(r_base, offset_of_field, r_base, kNotVolatile);
- // r_base now points at static storage (Class*) or NULL if the type is not yet resolved.
- LIR* unresolved_branch = nullptr;
- if (!field_info.IsClassInDexCache() &&
- (mir->optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) == 0) {
- // Check if r_base is NULL.
- unresolved_branch = OpCmpImmBranch(kCondEq, r_base, 0, NULL);
- }
- LIR* uninit_branch = nullptr;
+ r_base = GenGetOtherTypeForSgetSput(field_info, mir->optimization_flags);
if (!field_info.IsClassInitialized() &&
(mir->optimization_flags & MIR_CLASS_IS_INITIALIZED) == 0) {
- // Check if r_base is not yet initialized class.
- RegStorage r_tmp = TargetReg(kArg2, kNotWide);
- LockTemp(r_tmp);
- uninit_branch = OpCmpMemImmBranch(kCondLt, r_tmp, r_base,
- mirror::Class::StatusOffset().Int32Value(),
- mirror::Class::kStatusInitialized, nullptr, nullptr);
- FreeTemp(r_tmp);
+ // Ensure load of status and store of value don't re-order.
+ // TODO: Presumably the actual value store is control-dependent on the status load,
+ // and will thus not be reordered in any case, since stores are never speculated.
+ // Does later code "know" that the class is now initialized? If so, we still
+ // need the barrier to guard later static loads.
+ GenMemBarrier(kLoadAny);
}
- if (unresolved_branch != nullptr || uninit_branch != nullptr) {
- // The slow path is invoked if the r_base is NULL or the class pointed
- // to by it is not initialized.
- LIR* cont = NewLIR0(kPseudoTargetLabel);
- AddSlowPath(new (arena_) StaticFieldSlowPath(this, unresolved_branch, uninit_branch, cont,
- field_info.StorageIndex(), r_base));
-
- if (uninit_branch != nullptr) {
- // Ensure load of status and store of value don't re-order.
- // TODO: Presumably the actual value store is control-dependent on the status load,
- // and will thus not be reordered in any case, since stores are never speculated.
- // Does later code "know" that the class is now initialized? If so, we still
- // need the barrier to guard later static loads.
- GenMemBarrier(kLoadAny);
- }
- }
- FreeTemp(r_method);
}
// rBase now holds static storage base
RegisterClass reg_class = RegClassForFieldLoadStore(size, field_info.IsVolatile());
@@ -773,57 +787,19 @@
RegStorage r_base;
if (field_info.IsReferrersClass()) {
// Fast path, static storage base is this method's class
- RegLocation rl_method = LoadCurrMethod();
r_base = AllocTempRef();
- LoadRefDisp(rl_method.reg, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), r_base,
+ RegStorage r_method = LoadCurrMethodWithHint(r_base);
+ LoadRefDisp(r_method, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), r_base,
kNotVolatile);
} else {
// Medium path, static storage base in a different class which requires checks that the other
// class is initialized
- DCHECK_NE(field_info.StorageIndex(), DexFile::kDexNoIndex);
- // May do runtime call so everything to home locations.
- FlushAllRegs();
- // Using fixed register to sync with possible call to runtime support.
- RegStorage r_method = TargetReg(kArg1, kRef);
- LockTemp(r_method);
- LoadCurrMethodDirect(r_method);
- r_base = TargetReg(kArg0, kRef);
- LockTemp(r_base);
- LoadRefDisp(r_method, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), r_base,
- kNotVolatile);
- int32_t offset_of_field = ObjArray::OffsetOfElement(field_info.StorageIndex()).Int32Value();
- LoadRefDisp(r_base, offset_of_field, r_base, kNotVolatile);
- // r_base now points at static storage (Class*) or NULL if the type is not yet resolved.
- LIR* unresolved_branch = nullptr;
- if (!field_info.IsClassInDexCache() &&
- (mir->optimization_flags & MIR_CLASS_IS_IN_DEX_CACHE) == 0) {
- // Check if r_base is NULL.
- unresolved_branch = OpCmpImmBranch(kCondEq, r_base, 0, NULL);
- }
- LIR* uninit_branch = nullptr;
+ r_base = GenGetOtherTypeForSgetSput(field_info, mir->optimization_flags);
if (!field_info.IsClassInitialized() &&
(mir->optimization_flags & MIR_CLASS_IS_INITIALIZED) == 0) {
- // Check if r_base is not yet initialized class.
- RegStorage r_tmp = TargetReg(kArg2, kNotWide);
- LockTemp(r_tmp);
- uninit_branch = OpCmpMemImmBranch(kCondLt, r_tmp, r_base,
- mirror::Class::StatusOffset().Int32Value(),
- mirror::Class::kStatusInitialized, nullptr, nullptr);
- FreeTemp(r_tmp);
+ // Ensure load of status and load of value don't re-order.
+ GenMemBarrier(kLoadAny);
}
- if (unresolved_branch != nullptr || uninit_branch != nullptr) {
- // The slow path is invoked if the r_base is NULL or the class pointed
- // to by it is not initialized.
- LIR* cont = NewLIR0(kPseudoTargetLabel);
- AddSlowPath(new (arena_) StaticFieldSlowPath(this, unresolved_branch, uninit_branch, cont,
- field_info.StorageIndex(), r_base));
-
- if (uninit_branch != nullptr) {
- // Ensure load of status and load of value don't re-order.
- GenMemBarrier(kLoadAny);
- }
- }
- FreeTemp(r_method);
}
// r_base now holds static storage base
RegisterClass reg_class = RegClassForFieldLoadStore(size, field_info.IsVolatile());
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index bb8fbae..45a5855 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -135,6 +135,7 @@
class BitVector;
struct CallInfo;
struct CompilationUnit;
+struct CompilerTemp;
struct InlineMethod;
class MIR;
struct LIR;
@@ -142,6 +143,7 @@
class DexFileMethodInliner;
class MIRGraph;
class MirMethodLoweringInfo;
+class MirSFieldLoweringInfo;
typedef int (*NextCallInsn)(CompilationUnit*, CallInfo*, int,
const MethodReference& target_method,
@@ -774,9 +776,10 @@
*/
virtual RegLocation EvalLoc(RegLocation loc, int reg_class, bool update);
- void CountRefs(RefCounts* core_counts, RefCounts* fp_counts, size_t num_regs);
+ void AnalyzeMIR(RefCounts* core_counts, MIR* mir, uint32_t weight);
+ virtual void CountRefs(RefCounts* core_counts, RefCounts* fp_counts, size_t num_regs);
void DumpCounts(const RefCounts* arr, int size, const char* msg);
- void DoPromotion();
+ virtual void DoPromotion();
int VRegOffset(int v_reg);
int SRegOffset(int s_reg);
RegLocation GetReturnWide(RegisterClass reg_class);
@@ -1692,6 +1695,13 @@
void GenIfNullUseHelperImmMethod(
RegStorage r_result, QuickEntrypointEnum trampoline, int imm, RegStorage r_method);
+ /**
+ * @brief Generate code to retrieve Class* for another type to be used by SGET/SPUT.
+ * @param field_info information about the field to be accessed.
+ * @param opt_flags the optimization flags of the MIR.
+ */
+ RegStorage GenGetOtherTypeForSgetSput(const MirSFieldLoweringInfo& field_info, int opt_flags);
+
void AddDivZeroCheckSlowPath(LIR* branch);
// Copy arg0 and arg1 to kArg0 and kArg1 safely, possibly using
@@ -1841,6 +1851,18 @@
// The layout of the cu_->dex_file's dex cache arrays for PC-relative addressing.
const DexCacheArraysLayout dex_cache_arrays_layout_;
+ // For architectures that don't have true PC-relative addressing, we can promote
+ // a PC of an instruction (or another PC-relative address such as a pointer to
+ // the dex cache arrays if supported) to a register. This is indicated to the
+ // register promotion by allocating a backend temp.
+ CompilerTemp* pc_rel_temp_;
+
+ // For architectures that don't have true PC-relative addressing (see pc_rel_temp_
+ // above) and also have a limited range of offsets for loads, it's be useful to
+ // know the minimum offset into the dex cache arrays, so we calculate that as well
+ // if pc_rel_temp_ isn't nullptr.
+ uint32_t dex_cache_arrays_min_offset_;
+
// ABI support
class ShortyArg {
public:
diff --git a/compiler/dex/quick/quick_compiler.cc b/compiler/dex/quick/quick_compiler.cc
index 8baafc7..01652d6 100644
--- a/compiler/dex/quick/quick_compiler.cc
+++ b/compiler/dex/quick/quick_compiler.cc
@@ -798,8 +798,13 @@
const std::vector<const art::DexFile*>& dex_files,
const std::string& android_root,
bool is_host) const {
- return art::ElfWriterQuick32::Create(file, oat_writer, dex_files, android_root, is_host,
- *GetCompilerDriver());
+ if (kProduce64BitELFFiles && Is64BitInstructionSet(GetCompilerDriver()->GetInstructionSet())) {
+ return art::ElfWriterQuick64::Create(file, oat_writer, dex_files, android_root, is_host,
+ *GetCompilerDriver());
+ } else {
+ return art::ElfWriterQuick32::Create(file, oat_writer, dex_files, android_root, is_host,
+ *GetCompilerDriver());
+ }
}
Mir2Lir* QuickCompiler::GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const {
diff --git a/compiler/dex/quick/ralloc_util.cc b/compiler/dex/quick/ralloc_util.cc
index 741657b..487d31c 100644
--- a/compiler/dex/quick/ralloc_util.cc
+++ b/compiler/dex/quick/ralloc_util.cc
@@ -19,9 +19,11 @@
#include "mir_to_lir-inl.h"
#include "dex/compiler_ir.h"
+#include "dex/dataflow_iterator-inl.h"
#include "dex/mir_graph.h"
#include "driver/compiler_driver.h"
#include "driver/dex_compilation_unit.h"
+#include "utils/dex_cache_arrays_layout-inl.h"
namespace art {
@@ -1128,6 +1130,146 @@
return loc;
}
+void Mir2Lir::AnalyzeMIR(RefCounts* core_counts, MIR* mir, uint32_t weight) {
+ // NOTE: This should be in sync with functions that actually generate code for
+ // the opcodes below. However, if we get this wrong, the generated code will
+ // still be correct even if it may be sub-optimal.
+ int opcode = mir->dalvikInsn.opcode;
+ bool uses_method = false;
+ bool uses_pc_rel_load = false;
+ uint32_t dex_cache_array_offset = std::numeric_limits<uint32_t>::max();
+ switch (opcode) {
+ case Instruction::CHECK_CAST:
+ case Instruction::INSTANCE_OF: {
+ if ((opcode == Instruction::CHECK_CAST) &&
+ (mir->optimization_flags & MIR_IGNORE_CHECK_CAST) != 0) {
+ break; // No code generated.
+ }
+ uint32_t type_idx =
+ (opcode == Instruction::CHECK_CAST) ? mir->dalvikInsn.vB : mir->dalvikInsn.vC;
+ bool type_known_final, type_known_abstract, use_declaring_class;
+ bool needs_access_check = !cu_->compiler_driver->CanAccessTypeWithoutChecks(
+ cu_->method_idx, *cu_->dex_file, type_idx,
+ &type_known_final, &type_known_abstract, &use_declaring_class);
+ if (opcode == Instruction::CHECK_CAST && !needs_access_check &&
+ cu_->compiler_driver->IsSafeCast(
+ mir_graph_->GetCurrentDexCompilationUnit(), mir->offset)) {
+ break; // No code generated.
+ }
+ if (!needs_access_check && !use_declaring_class && pc_rel_temp_ != nullptr) {
+ uses_pc_rel_load = true; // And ignore method use in slow path.
+ dex_cache_array_offset = dex_cache_arrays_layout_.TypeOffset(type_idx);
+ } else {
+ uses_method = true;
+ }
+ break;
+ }
+
+ case Instruction::CONST_CLASS:
+ if (pc_rel_temp_ != nullptr &&
+ cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, *cu_->dex_file,
+ mir->dalvikInsn.vB)) {
+ uses_pc_rel_load = true; // And ignore method use in slow path.
+ dex_cache_array_offset = dex_cache_arrays_layout_.TypeOffset(mir->dalvikInsn.vB);
+ } else {
+ uses_method = true;
+ }
+ break;
+
+ case Instruction::CONST_STRING:
+ case Instruction::CONST_STRING_JUMBO:
+ if (pc_rel_temp_ != nullptr) {
+ uses_pc_rel_load = true; // And ignore method use in slow path.
+ dex_cache_array_offset = dex_cache_arrays_layout_.StringOffset(mir->dalvikInsn.vB);
+ } else {
+ uses_method = true;
+ }
+ break;
+
+ case Instruction::INVOKE_VIRTUAL:
+ case Instruction::INVOKE_SUPER:
+ case Instruction::INVOKE_DIRECT:
+ case Instruction::INVOKE_STATIC:
+ case Instruction::INVOKE_INTERFACE:
+ case Instruction::INVOKE_VIRTUAL_RANGE:
+ case Instruction::INVOKE_SUPER_RANGE:
+ case Instruction::INVOKE_DIRECT_RANGE:
+ case Instruction::INVOKE_STATIC_RANGE:
+ case Instruction::INVOKE_INTERFACE_RANGE:
+ case Instruction::INVOKE_VIRTUAL_QUICK:
+ case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: {
+ const MirMethodLoweringInfo& info = mir_graph_->GetMethodLoweringInfo(mir);
+ InvokeType sharp_type = info.GetSharpType();
+ if (!info.FastPath() || (sharp_type != kStatic && sharp_type != kDirect)) {
+ // Nothing to do, the generated code or entrypoint uses method from the stack.
+ } else if (info.DirectCode() != 0 && info.DirectMethod() != 0) {
+ // Nothing to do, the generated code uses method from the stack.
+ } else if (pc_rel_temp_ != nullptr) {
+ uses_pc_rel_load = true;
+ dex_cache_array_offset = dex_cache_arrays_layout_.MethodOffset(mir->dalvikInsn.vB);
+ } else {
+ uses_method = true;
+ }
+ break;
+ }
+
+ case Instruction::NEW_INSTANCE:
+ case Instruction::NEW_ARRAY:
+ case Instruction::FILLED_NEW_ARRAY:
+ case Instruction::FILLED_NEW_ARRAY_RANGE:
+ uses_method = true;
+ break;
+ case Instruction::FILL_ARRAY_DATA:
+ // Nothing to do, the entrypoint uses method from the stack.
+ break;
+ case Instruction::THROW:
+ // Nothing to do, the entrypoint uses method from the stack.
+ break;
+
+ case Instruction::SGET:
+ case Instruction::SGET_WIDE:
+ case Instruction::SGET_OBJECT:
+ case Instruction::SGET_BOOLEAN:
+ case Instruction::SGET_BYTE:
+ case Instruction::SGET_CHAR:
+ case Instruction::SGET_SHORT:
+ case Instruction::SPUT:
+ case Instruction::SPUT_WIDE:
+ case Instruction::SPUT_OBJECT:
+ case Instruction::SPUT_BOOLEAN:
+ case Instruction::SPUT_BYTE:
+ case Instruction::SPUT_CHAR:
+ case Instruction::SPUT_SHORT: {
+ const MirSFieldLoweringInfo& field_info = mir_graph_->GetSFieldLoweringInfo(mir);
+ bool fast = IsInstructionSGet(static_cast<Instruction::Code>(opcode))
+ ? field_info.FastGet()
+ : field_info.FastPut();
+ if (fast && (cu_->enable_debug & (1 << kDebugSlowFieldPath)) == 0) {
+ if (!field_info.IsReferrersClass() && pc_rel_temp_ != nullptr) {
+ uses_pc_rel_load = true; // And ignore method use in slow path.
+ dex_cache_array_offset = dex_cache_arrays_layout_.TypeOffset(field_info.StorageIndex());
+ } else {
+ uses_method = true;
+ }
+ } else {
+ // Nothing to do, the entrypoint uses method from the stack.
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ if (uses_method) {
+ core_counts[SRegToPMap(mir_graph_->GetMethodLoc().s_reg_low)].count += weight;
+ }
+ if (uses_pc_rel_load) {
+ core_counts[SRegToPMap(pc_rel_temp_->s_reg_low)].count += weight;
+ DCHECK_NE(dex_cache_array_offset, std::numeric_limits<uint32_t>::max());
+ dex_cache_arrays_min_offset_ = std::min(dex_cache_arrays_min_offset_, dex_cache_array_offset);
+ }
+}
+
/* USE SSA names to count references of base Dalvik v_regs. */
void Mir2Lir::CountRefs(RefCounts* core_counts, RefCounts* fp_counts, size_t num_regs) {
for (int i = 0; i < mir_graph_->GetNumSSARegs(); i++) {
@@ -1157,6 +1299,22 @@
}
}
}
+
+ // Now analyze the ArtMethod* and pc_rel_temp_ uses.
+ DCHECK_EQ(core_counts[SRegToPMap(mir_graph_->GetMethodLoc().s_reg_low)].count, 0);
+ if (pc_rel_temp_ != nullptr) {
+ DCHECK_EQ(core_counts[SRegToPMap(pc_rel_temp_->s_reg_low)].count, 0);
+ }
+ PreOrderDfsIterator iter(mir_graph_);
+ for (BasicBlock* bb = iter.Next(); bb != nullptr; bb = iter.Next()) {
+ if (bb->block_type == kDead) {
+ continue;
+ }
+ uint32_t weight = mir_graph_->GetUseCountWeight(bb);
+ for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) {
+ AnalyzeMIR(core_counts, mir, weight);
+ }
+ }
}
/* qsort callback function, sort descending */
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index f6b217a..c2b8375 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -2370,44 +2370,6 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return compiler_->WriteElf(file, oat_writer, dex_files, android_root, is_host);
}
-void CompilerDriver::InstructionSetToLLVMTarget(InstructionSet instruction_set,
- std::string* target_triple,
- std::string* target_cpu,
- std::string* target_attr) {
- switch (instruction_set) {
- case kThumb2:
- *target_triple = "thumb-none-linux-gnueabi";
- *target_cpu = "cortex-a9";
- *target_attr = "+thumb2,+neon,+neonfp,+vfp3,+db";
- break;
-
- case kArm:
- *target_triple = "armv7-none-linux-gnueabi";
- // TODO: Fix for Nexus S.
- *target_cpu = "cortex-a9";
- // TODO: Fix for Xoom.
- *target_attr = "+v7,+neon,+neonfp,+vfp3,+db";
- break;
-
- case kX86:
- *target_triple = "i386-pc-linux-gnu";
- *target_attr = "";
- break;
-
- case kX86_64:
- *target_triple = "x86_64-pc-linux-gnu";
- *target_attr = "";
- break;
-
- case kMips:
- *target_triple = "mipsel-unknown-linux";
- *target_attr = "mips32r2";
- break;
-
- default:
- LOG(FATAL) << "Unknown instruction set: " << instruction_set;
- }
- }
bool CompilerDriver::SkipCompilation(const std::string& method_name) {
if (!profile_present_) {
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index edd1bd2..a6ed559 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -385,12 +385,6 @@
OatWriter* oat_writer,
File* file);
- // TODO: move to a common home for llvm helpers once quick/portable are merged.
- static void InstructionSetToLLVMTarget(InstructionSet instruction_set,
- std::string* target_triple,
- std::string* target_cpu,
- std::string* target_attr);
-
void SetCompilerContext(void* compiler_context) {
compiler_context_ = compiler_context;
}
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 3ce19ab..24cb364 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -490,14 +490,11 @@
int code_factor_bits_ = 0;
int isa = -1;
switch (oat_writer->GetOatHeader().GetInstructionSet()) {
+ case kArm: // arm actually means thumb2.
case kThumb2:
code_factor_bits_ = 1; // 16-bit instuctions
isa = 1; // DW_ISA_ARM_thumb.
break;
- case kArm:
- code_factor_bits_ = 1; // 16-bit instructions
- isa = 2; // DW_ISA_ARM_arm.
- break;
case kArm64:
case kMips:
case kMips64:
diff --git a/compiler/linker/arm/relative_patcher_thumb2.cc b/compiler/linker/arm/relative_patcher_thumb2.cc
index 4267743..b17cbca 100644
--- a/compiler/linker/arm/relative_patcher_thumb2.cc
+++ b/compiler/linker/arm/relative_patcher_thumb2.cc
@@ -48,22 +48,30 @@
uint32_t value = (signbit << 26) | (j1 << 13) | (j2 << 11) | (imm10 << 16) | imm11;
value |= 0xf000d000; // BL
- uint8_t* addr = &(*code)[literal_offset];
// Check that we're just overwriting an existing BL.
- DCHECK_EQ(addr[1] & 0xf8, 0xf0);
- DCHECK_EQ(addr[3] & 0xd0, 0xd0);
+ DCHECK_EQ(GetInsn32(code, literal_offset) & 0xf800d000, 0xf000d000);
// Write the new BL.
- addr[0] = (value >> 16) & 0xff;
- addr[1] = (value >> 24) & 0xff;
- addr[2] = (value >> 0) & 0xff;
- addr[3] = (value >> 8) & 0xff;
+ SetInsn32(code, literal_offset, value);
}
-void Thumb2RelativePatcher::PatchDexCacheReference(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
- const LinkerPatch& patch ATTRIBUTE_UNUSED,
- uint32_t patch_offset ATTRIBUTE_UNUSED,
- uint32_t target_offset ATTRIBUTE_UNUSED) {
- LOG(FATAL) << "Unexpected relative dex cache array patch.";
+void Thumb2RelativePatcher::PatchDexCacheReference(std::vector<uint8_t>* code,
+ const LinkerPatch& patch,
+ uint32_t patch_offset,
+ uint32_t target_offset) {
+ uint32_t literal_offset = patch.LiteralOffset();
+ uint32_t pc_literal_offset = patch.PcInsnOffset();
+ uint32_t pc_base = patch_offset + (pc_literal_offset - literal_offset) + 4u /* PC adjustment */;
+ uint32_t diff = target_offset - pc_base;
+
+ uint32_t insn = GetInsn32(code, literal_offset);
+ DCHECK_EQ(insn & 0xff7ff0ffu, 0xf2400000u); // MOVW/MOVT, unpatched (imm16 == 0).
+ uint32_t diff16 = ((insn & 0x00800000u) != 0u) ? (diff >> 16) : (diff & 0xffffu);
+ uint32_t imm4 = (diff16 >> 12) & 0xfu;
+ uint32_t imm = (diff16 >> 11) & 0x1u;
+ uint32_t imm3 = (diff16 >> 8) & 0x7u;
+ uint32_t imm8 = diff16 & 0xffu;
+ insn = (insn & 0xfbf08f00u) | (imm << 26) | (imm4 << 16) | (imm3 << 12) | imm8;
+ SetInsn32(code, literal_offset, insn);
}
std::vector<uint8_t> Thumb2RelativePatcher::CompileThunkCode() {
@@ -80,5 +88,31 @@
return thunk_code;
}
+void Thumb2RelativePatcher::SetInsn32(std::vector<uint8_t>* code, uint32_t offset, uint32_t value) {
+ DCHECK_LE(offset + 4u, code->size());
+ DCHECK_EQ(offset & 1u, 0u);
+ uint8_t* addr = &(*code)[offset];
+ addr[0] = (value >> 16) & 0xff;
+ addr[1] = (value >> 24) & 0xff;
+ addr[2] = (value >> 0) & 0xff;
+ addr[3] = (value >> 8) & 0xff;
+}
+
+uint32_t Thumb2RelativePatcher::GetInsn32(ArrayRef<const uint8_t> code, uint32_t offset) {
+ DCHECK_LE(offset + 4u, code.size());
+ DCHECK_EQ(offset & 1u, 0u);
+ const uint8_t* addr = &code[offset];
+ return
+ (static_cast<uint32_t>(addr[0]) << 16) +
+ (static_cast<uint32_t>(addr[1]) << 24) +
+ (static_cast<uint32_t>(addr[2]) << 0)+
+ (static_cast<uint32_t>(addr[3]) << 8);
+}
+
+template <typename Alloc>
+uint32_t Thumb2RelativePatcher::GetInsn32(std::vector<uint8_t, Alloc>* code, uint32_t offset) {
+ return GetInsn32(ArrayRef<const uint8_t>(*code), offset);
+}
+
} // namespace linker
} // namespace art
diff --git a/compiler/linker/arm/relative_patcher_thumb2.h b/compiler/linker/arm/relative_patcher_thumb2.h
index 5611303..2d474c2 100644
--- a/compiler/linker/arm/relative_patcher_thumb2.h
+++ b/compiler/linker/arm/relative_patcher_thumb2.h
@@ -34,6 +34,12 @@
private:
static std::vector<uint8_t> CompileThunkCode();
+ void SetInsn32(std::vector<uint8_t>* code, uint32_t offset, uint32_t value);
+ static uint32_t GetInsn32(ArrayRef<const uint8_t> code, uint32_t offset);
+
+ template <typename Alloc>
+ static uint32_t GetInsn32(std::vector<uint8_t, Alloc>* code, uint32_t offset);
+
// PC displacement from patch location; Thumb2 PC is always at instruction address + 4.
static constexpr int32_t kPcDisplacement = 4;
diff --git a/compiler/linker/arm/relative_patcher_thumb2_test.cc b/compiler/linker/arm/relative_patcher_thumb2_test.cc
index 3b397cc..a057a4c 100644
--- a/compiler/linker/arm/relative_patcher_thumb2_test.cc
+++ b/compiler/linker/arm/relative_patcher_thumb2_test.cc
@@ -121,6 +121,48 @@
result.push_back(static_cast<uint8_t>(bl >> 8));
return result;
}
+
+ void TestDexCachereference(uint32_t dex_cache_arrays_begin, uint32_t element_offset) {
+ dex_cache_arrays_begin_ = dex_cache_arrays_begin;
+ static const uint8_t raw_code[] = {
+ 0x40, 0xf2, 0x00, 0x00, // MOVW r0, #0 (placeholder)
+ 0xc0, 0xf2, 0x00, 0x00, // MOVT r0, #0 (placeholder)
+ 0x78, 0x44, // ADD r0, pc
+ };
+ constexpr uint32_t pc_insn_offset = 8u;
+ const ArrayRef<const uint8_t> code(raw_code);
+ LinkerPatch patches[] = {
+ LinkerPatch::DexCacheArrayPatch(0u, nullptr, pc_insn_offset, element_offset),
+ LinkerPatch::DexCacheArrayPatch(4u, nullptr, pc_insn_offset, element_offset),
+ };
+ AddCompiledMethod(MethodRef(1u), code, ArrayRef<const LinkerPatch>(patches));
+ Link();
+
+ uint32_t method1_offset = GetMethodOffset(1u);
+ uint32_t pc_base_offset = method1_offset + pc_insn_offset + 4u /* PC adjustment */;
+ uint32_t diff = dex_cache_arrays_begin_ + element_offset - pc_base_offset;
+ // Distribute the bits of the diff between the MOVW and MOVT:
+ uint32_t diffw = diff & 0xffffu;
+ uint32_t difft = diff >> 16;
+ uint32_t movw = 0xf2400000u | // MOVW r0, #0 (placeholder),
+ ((diffw & 0xf000u) << (16 - 12)) | // move imm4 from bits 12-15 to bits 16-19,
+ ((diffw & 0x0800u) << (26 - 11)) | // move imm from bit 11 to bit 26,
+ ((diffw & 0x0700u) << (12 - 8)) | // move imm3 from bits 8-10 to bits 12-14,
+ ((diffw & 0x00ffu)); // keep imm8 at bits 0-7.
+ uint32_t movt = 0xf2c00000u | // MOVT r0, #0 (placeholder),
+ ((difft & 0xf000u) << (16 - 12)) | // move imm4 from bits 12-15 to bits 16-19,
+ ((difft & 0x0800u) << (26 - 11)) | // move imm from bit 11 to bit 26,
+ ((difft & 0x0700u) << (12 - 8)) | // move imm3 from bits 8-10 to bits 12-14,
+ ((difft & 0x00ffu)); // keep imm8 at bits 0-7.
+ const uint8_t expected_code[] = {
+ static_cast<uint8_t>(movw >> 16), static_cast<uint8_t>(movw >> 24),
+ static_cast<uint8_t>(movw >> 0), static_cast<uint8_t>(movw >> 8),
+ static_cast<uint8_t>(movt >> 16), static_cast<uint8_t>(movt >> 24),
+ static_cast<uint8_t>(movt >> 0), static_cast<uint8_t>(movt >> 8),
+ 0x78, 0x44,
+ };
+ EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
+ }
};
const uint8_t Thumb2RelativePatcherTest::kCallRawCode[] = {
@@ -285,5 +327,25 @@
EXPECT_TRUE(CheckThunk(thunk_offset));
}
+TEST_F(Thumb2RelativePatcherTest, DexCacheReferenceImm8) {
+ TestDexCachereference(0x00ff0000u, 0x00fcu);
+ ASSERT_LT(GetMethodOffset(1u), 0xfcu);
+}
+
+TEST_F(Thumb2RelativePatcherTest, DexCacheReferenceImm3) {
+ TestDexCachereference(0x02ff0000u, 0x05fcu);
+ ASSERT_LT(GetMethodOffset(1u), 0xfcu);
+}
+
+TEST_F(Thumb2RelativePatcherTest, DexCacheReferenceImm) {
+ TestDexCachereference(0x08ff0000u, 0x08fcu);
+ ASSERT_LT(GetMethodOffset(1u), 0xfcu);
+}
+
+TEST_F(Thumb2RelativePatcherTest, DexCacheReferenceimm4) {
+ TestDexCachereference(0xd0ff0000u, 0x60fcu);
+ ASSERT_LT(GetMethodOffset(1u), 0xfcu);
+}
+
} // namespace linker
} // namespace art
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 49c0d38..4c28378 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -337,13 +337,11 @@
HGraphVisualizer::HGraphVisualizer(std::ostream* output,
HGraph* graph,
- const CodeGenerator& codegen,
- const char* method_name)
- : output_(output), graph_(graph), codegen_(codegen) {
- if (output == nullptr) {
- return;
- }
+ const CodeGenerator& codegen)
+ : output_(output), graph_(graph), codegen_(codegen) {}
+void HGraphVisualizer::PrintHeader(const char* method_name) const {
+ DCHECK(output_ != nullptr);
HGraphVisualizerPrinter printer(graph_, *output_, "", true, codegen_);
printer.StartTag("compilation");
printer.PrintProperty("name", method_name);
diff --git a/compiler/optimizing/graph_visualizer.h b/compiler/optimizing/graph_visualizer.h
index bc553ae..513bceb 100644
--- a/compiler/optimizing/graph_visualizer.h
+++ b/compiler/optimizing/graph_visualizer.h
@@ -35,9 +35,9 @@
public:
HGraphVisualizer(std::ostream* output,
HGraph* graph,
- const CodeGenerator& codegen,
- const char* method_name);
+ const CodeGenerator& codegen);
+ void PrintHeader(const char* method_name) const;
void DumpGraph(const char* pass_name, bool is_after_pass = true) const;
private:
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index e474c49..12798ed 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -96,10 +96,13 @@
timing_logger_enabled_(compiler_driver->GetDumpPasses()),
timing_logger_(method_name, true, true),
visualizer_enabled_(!compiler_driver->GetDumpCfgFileName().empty()),
- visualizer_(visualizer_output, graph, codegen, method_name_) {
+ visualizer_(visualizer_output, graph, codegen) {
if (strstr(method_name, kStringFilter) == nullptr) {
timing_logger_enabled_ = visualizer_enabled_ = false;
}
+ if (visualizer_enabled_) {
+ visualizer_.PrintHeader(method_name_);
+ }
}
~PassInfoPrinter() {
@@ -201,8 +204,13 @@
const std::vector<const art::DexFile*>& dex_files,
const std::string& android_root,
bool is_host) const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return art::ElfWriterQuick32::Create(file, oat_writer, dex_files, android_root, is_host,
- *GetCompilerDriver());
+ if (kProduce64BitELFFiles && Is64BitInstructionSet(GetCompilerDriver()->GetInstructionSet())) {
+ return art::ElfWriterQuick64::Create(file, oat_writer, dex_files, android_root, is_host,
+ *GetCompilerDriver());
+ } else {
+ return art::ElfWriterQuick32::Create(file, oat_writer, dex_files, android_root, is_host,
+ *GetCompilerDriver());
+ }
}
void InitCompilationUnit(CompilationUnit& cu) const OVERRIDE;
diff --git a/disassembler/Android.mk b/disassembler/Android.mk
index c9aa8c8..1cfd45a 100644
--- a/disassembler/Android.mk
+++ b/disassembler/Android.mk
@@ -81,6 +81,8 @@
endif
LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime
+ LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+ LOCAL_MULTILIB := both
LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
diff --git a/disassembler/disassembler_mips64.cc b/disassembler/disassembler_mips64.cc
index 1b6e6be..f1c7d8e 100644
--- a/disassembler/disassembler_mips64.cc
+++ b/disassembler/disassembler_mips64.cc
@@ -185,7 +185,7 @@
return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
}
-static void DumpMips64(std::ostream& os, const uint8_t* instr_ptr) {
+size_t DisassemblerMips64::Dump(std::ostream& os, const uint8_t* instr_ptr) {
uint32_t instruction = ReadU32(instr_ptr);
uint32_t rs = (instruction >> 21) & 0x1f; // I-type, R-type.
@@ -272,19 +272,16 @@
}
}
- os << StringPrintf("%p: %08x\t%-7s ", instr_ptr, instruction, opcode.c_str())
+ os << FormatInstructionPointer(instr_ptr)
+ << StringPrintf(": %08x\t%-7s ", instruction, opcode.c_str())
<< args.str() << '\n';
-}
-
-size_t DisassemblerMips64::Dump(std::ostream& os, const uint8_t* begin) {
- DumpMips64(os, begin);
return 4;
}
void DisassemblerMips64::Dump(std::ostream& os, const uint8_t* begin,
const uint8_t* end) {
for (const uint8_t* cur = begin; cur < end; cur += 4) {
- DumpMips64(os, cur);
+ Dump(os, cur);
}
}
diff --git a/runtime/arch/mips64/instruction_set_features_mips64.cc b/runtime/arch/mips64/instruction_set_features_mips64.cc
index 8c48a08..5c0c914 100644
--- a/runtime/arch/mips64/instruction_set_features_mips64.cc
+++ b/runtime/arch/mips64/instruction_set_features_mips64.cc
@@ -27,7 +27,6 @@
const Mips64InstructionSetFeatures* Mips64InstructionSetFeatures::FromVariant(
const std::string& variant, std::string* error_msg ATTRIBUTE_UNUSED) {
if (variant != "default" && variant != "mips64r6") {
- std::ostringstream os;
LOG(WARNING) << "Unexpected CPU variant for Mips64 using defaults: " << variant;
}
bool smp = true; // Conservative default.
diff --git a/runtime/arch/x86/instruction_set_features_x86.cc b/runtime/arch/x86/instruction_set_features_x86.cc
index 8227633..ef39999 100644
--- a/runtime/arch/x86/instruction_set_features_x86.cc
+++ b/runtime/arch/x86/instruction_set_features_x86.cc
@@ -63,7 +63,6 @@
bool known_variant = FindVariantInArray(x86_known_variants, arraysize(x86_known_variants),
variant);
if (!known_variant && variant != "default") {
- std::ostringstream os;
LOG(WARNING) << "Unexpected CPU variant for X86 using defaults: " << variant;
}
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 33d75d2..12fa546 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -914,7 +914,8 @@
void ClassLinker::VisitClassRoots(RootVisitor* visitor, VisitRootFlags flags) {
WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
if ((flags & kVisitRootFlagAllRoots) != 0) {
- BufferedRootVisitor<128> buffered_visitor(visitor, RootInfo(kRootStickyClass));
+ BufferedRootVisitor<kDefaultBufferedRootCount> buffered_visitor(
+ visitor, RootInfo(kRootStickyClass));
for (GcRoot<mirror::Class>& root : class_table_) {
buffered_visitor.VisitRoot(root);
}
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 3f67f9e..6759c4d 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -1283,18 +1283,37 @@
return JDWP::ERR_NONE;
}
-JDWP::ObjectId Dbg::CreateString(const std::string& str) {
- return gRegistry->Add(mirror::String::AllocFromModifiedUtf8(Thread::Current(), str.c_str()));
+JDWP::JdwpError Dbg::CreateString(const std::string& str, JDWP::ObjectId* new_string_id) {
+ Thread* self = Thread::Current();
+ mirror::String* new_string = mirror::String::AllocFromModifiedUtf8(self, str.c_str());
+ if (new_string == nullptr) {
+ DCHECK(self->IsExceptionPending());
+ self->ClearException();
+ LOG(ERROR) << "Could not allocate string";
+ *new_string_id = 0;
+ return JDWP::ERR_OUT_OF_MEMORY;
+ }
+ *new_string_id = gRegistry->Add(new_string);
+ return JDWP::ERR_NONE;
}
-JDWP::JdwpError Dbg::CreateObject(JDWP::RefTypeId class_id, JDWP::ObjectId* new_object) {
+JDWP::JdwpError Dbg::CreateObject(JDWP::RefTypeId class_id, JDWP::ObjectId* new_object_id) {
JDWP::JdwpError error;
mirror::Class* c = DecodeClass(class_id, &error);
if (c == nullptr) {
- *new_object = 0;
+ *new_object_id = 0;
return error;
}
- *new_object = gRegistry->Add(c->AllocObject(Thread::Current()));
+ Thread* self = Thread::Current();
+ mirror::Object* new_object = c->AllocObject(self);
+ if (new_object == nullptr) {
+ DCHECK(self->IsExceptionPending());
+ self->ClearException();
+ LOG(ERROR) << "Could not allocate object of type " << PrettyDescriptor(c);
+ *new_object_id = 0;
+ return JDWP::ERR_OUT_OF_MEMORY;
+ }
+ *new_object_id = gRegistry->Add(new_object);
return JDWP::ERR_NONE;
}
@@ -1302,16 +1321,26 @@
* Used by Eclipse's "Display" view to evaluate "new byte[5]" to get "(byte[]) [0, 0, 0, 0, 0]".
*/
JDWP::JdwpError Dbg::CreateArrayObject(JDWP::RefTypeId array_class_id, uint32_t length,
- JDWP::ObjectId* new_array) {
+ JDWP::ObjectId* new_array_id) {
JDWP::JdwpError error;
mirror::Class* c = DecodeClass(array_class_id, &error);
if (c == nullptr) {
- *new_array = 0;
+ *new_array_id = 0;
return error;
}
- *new_array = gRegistry->Add(mirror::Array::Alloc<true>(Thread::Current(), c, length,
- c->GetComponentSizeShift(),
- Runtime::Current()->GetHeap()->GetCurrentAllocator()));
+ Thread* self = Thread::Current();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
+ mirror::Array* new_array = mirror::Array::Alloc<true>(self, c, length,
+ c->GetComponentSizeShift(),
+ heap->GetCurrentAllocator());
+ if (new_array == nullptr) {
+ DCHECK(self->IsExceptionPending());
+ self->ClearException();
+ LOG(ERROR) << "Could not allocate array of type " << PrettyDescriptor(c);
+ *new_array_id = 0;
+ return JDWP::ERR_OUT_OF_MEMORY;
+ }
+ *new_array_id = gRegistry->Add(new_array);
return JDWP::ERR_NONE;
}
diff --git a/runtime/debugger.h b/runtime/debugger.h
index 62eda62..5898784 100644
--- a/runtime/debugger.h
+++ b/runtime/debugger.h
@@ -313,12 +313,12 @@
JDWP::Request* request)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static JDWP::ObjectId CreateString(const std::string& str)
+ static JDWP::JdwpError CreateString(const std::string& str, JDWP::ObjectId* new_string_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static JDWP::JdwpError CreateObject(JDWP::RefTypeId class_id, JDWP::ObjectId* new_object)
+ static JDWP::JdwpError CreateObject(JDWP::RefTypeId class_id, JDWP::ObjectId* new_object_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static JDWP::JdwpError CreateArrayObject(JDWP::RefTypeId array_class_id, uint32_t length,
- JDWP::ObjectId* new_array)
+ JDWP::ObjectId* new_array_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
//
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index bc5cf9b..411ec43 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -1630,8 +1630,10 @@
return frame->CIE_pointer != 0;
}
-static bool FixupEHFrame(off_t base_address_delta,
- uint8_t* eh_frame, size_t eh_frame_size) {
+template <typename Elf_SOff>
+static bool FixupEHFrame(Elf_SOff base_address_delta, uint8_t* eh_frame, size_t eh_frame_size) {
+ // TODO: Check the spec whether this is really data-dependent, or whether it's clear from the
+ // ELF file whether we should expect 32-bit or 64-bit.
if (*(reinterpret_cast<uint32_t*>(eh_frame)) == 0xffffffff) {
FDE64* last_frame = reinterpret_cast<FDE64*>(eh_frame + eh_frame_size);
FDE64* frame = NextFDE(reinterpret_cast<FDE64*>(eh_frame));
@@ -1643,6 +1645,7 @@
}
return true;
} else {
+ CHECK(IsInt<32>(base_address_delta));
FDE32* last_frame = reinterpret_cast<FDE32*>(eh_frame + eh_frame_size);
FDE32* frame = NextFDE(reinterpret_cast<FDE32*>(eh_frame));
for (; frame < last_frame; frame = NextFDE(frame)) {
@@ -1772,7 +1775,9 @@
uint8_t* current_instruction_;
};
-static bool FixupDebugLine(off_t base_offset_delta, DebugLineInstructionIterator* iter) {
+template <typename Elf_SOff>
+static bool FixupDebugLine(Elf_SOff base_offset_delta, DebugLineInstructionIterator* iter) {
+ CHECK(IsInt<32>(base_offset_delta));
for (; iter->GetInstruction(); iter->Next()) {
if (iter->IsExtendedOpcode() && iter->GetOpcode() == dwarf::DW_LNE_set_address) {
*reinterpret_cast<uint32_t*>(iter->GetArguments()) += base_offset_delta;
@@ -2044,7 +2049,9 @@
DebugTag* current_tag_;
};
-static bool FixupDebugInfo(off_t base_address_delta, DebugInfoIterator* iter) {
+template <typename Elf_SOff>
+static bool FixupDebugInfo(Elf_SOff base_address_delta, DebugInfoIterator* iter) {
+ CHECK(IsInt<32>(base_address_delta));
do {
if (iter->GetCurrentTag()->GetAttrSize(dwarf::DW_AT_low_pc) != sizeof(int32_t) ||
iter->GetCurrentTag()->GetAttrSize(dwarf::DW_AT_high_pc) != sizeof(int32_t)) {
@@ -2066,7 +2073,7 @@
typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
- ::FixupDebugSections(off_t base_address_delta) {
+ ::FixupDebugSections(typename std::make_signed<Elf_Off>::type base_address_delta) {
const Elf_Shdr* debug_info = FindSectionByName(".debug_info");
const Elf_Shdr* debug_abbrev = FindSectionByName(".debug_abbrev");
const Elf_Shdr* eh_frame = FindSectionByName(".eh_frame");
@@ -2280,7 +2287,7 @@
typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
- ::Fixup(uintptr_t base_address) {
+ ::Fixup(Elf_Addr base_address) {
if (!FixupDynamic(base_address)) {
LOG(WARNING) << "Failed to fixup .dynamic in " << file_->GetPath();
return false;
@@ -2305,7 +2312,8 @@
LOG(WARNING) << "Failed to fixup .rel.dyn in " << file_->GetPath();
return false;
}
- if (!FixupDebugSections(base_address)) {
+ static_assert(sizeof(Elf_Off) >= sizeof(base_address), "Potentially losing precision.");
+ if (!FixupDebugSections(static_cast<Elf_Off>(base_address))) {
LOG(WARNING) << "Failed to fixup debug sections in " << file_->GetPath();
return false;
}
@@ -2317,7 +2325,7 @@
typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
- ::FixupDynamic(uintptr_t base_address) {
+ ::FixupDynamic(Elf_Addr base_address) {
for (Elf_Word i = 0; i < GetDynamicNum(); i++) {
Elf_Dyn& elf_dyn = GetDynamic(i);
Elf_Word d_tag = elf_dyn.d_tag;
@@ -2341,7 +2349,7 @@
typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
- ::FixupSectionHeaders(uintptr_t base_address) {
+ ::FixupSectionHeaders(Elf_Addr base_address) {
for (Elf_Word i = 0; i < GetSectionHeaderNum(); i++) {
Elf_Shdr* sh = GetSectionHeader(i);
CHECK(sh != nullptr);
@@ -2365,7 +2373,7 @@
typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
- ::FixupProgramHeaders(uintptr_t base_address) {
+ ::FixupProgramHeaders(Elf_Addr base_address) {
// TODO: ELFObjectFile doesn't have give to Elf_Phdr, so we do that ourselves for now.
for (Elf_Word i = 0; i < GetProgramHeaderNum(); i++) {
Elf_Phdr* ph = GetProgramHeader(i);
@@ -2392,7 +2400,7 @@
typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
- ::FixupSymbols(uintptr_t base_address, bool dynamic) {
+ ::FixupSymbols(Elf_Addr base_address, bool dynamic) {
Elf_Word section_type = dynamic ? SHT_DYNSYM : SHT_SYMTAB;
// TODO: Unfortunate ELFObjectFile has protected symbol access, so use ElfFile
Elf_Shdr* symbol_section = FindSectionByType(section_type);
@@ -2422,7 +2430,7 @@
typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word,
Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>
- ::FixupRelocations(uintptr_t base_address) {
+ ::FixupRelocations(Elf_Addr base_address) {
for (Elf_Word i = 0; i < GetSectionHeaderNum(); i++) {
Elf_Shdr* sh = GetSectionHeader(i);
CHECK(sh != nullptr);
@@ -2622,7 +2630,14 @@
return elf_file->elf32_->Strip(error_msg);
}
-bool ElfFile::Fixup(uintptr_t base_address) {
+bool ElfFile::Fixup(uint64_t base_address) {
+ if (elf64_.get() != nullptr) {
+ return elf64_->Fixup(static_cast<Elf64_Addr>(base_address));
+ } else {
+ DCHECK(elf32_.get() != nullptr);
+ CHECK(IsUint<32>(base_address)) << std::hex << base_address;
+ return elf32_->Fixup(static_cast<Elf32_Addr>(base_address));
+ }
DELEGATE_TO_IMPL(Fixup, base_address);
}
diff --git a/runtime/elf_file.h b/runtime/elf_file.h
index 41c54bc..286c2a6 100644
--- a/runtime/elf_file.h
+++ b/runtime/elf_file.h
@@ -78,9 +78,9 @@
// Fixup an ELF file so that that oat header will be loaded at oat_begin.
// Returns true on success, false on failure.
- static bool Fixup(File* file, uintptr_t oat_data_begin);
+ static bool Fixup(File* file, uint64_t oat_data_begin);
- bool Fixup(uintptr_t base_address);
+ bool Fixup(uint64_t base_address);
bool Is64Bit() const {
return elf64_.get() != nullptr;
diff --git a/runtime/elf_file_impl.h b/runtime/elf_file_impl.h
index a70fa17..16d3857 100644
--- a/runtime/elf_file_impl.h
+++ b/runtime/elf_file_impl.h
@@ -19,6 +19,7 @@
#include <map>
#include <memory>
+#include <type_traits>
#include <vector>
// Explicitly include our own elf.h to avoid Linux and other dependencies.
@@ -102,13 +103,13 @@
// executable is true at run time, false at compile time.
bool Load(bool executable, std::string* error_msg);
- bool Fixup(uintptr_t base_address);
- bool FixupDynamic(uintptr_t base_address);
- bool FixupSectionHeaders(uintptr_t base_address);
- bool FixupProgramHeaders(uintptr_t base_address);
- bool FixupSymbols(uintptr_t base_address, bool dynamic);
- bool FixupRelocations(uintptr_t base_address);
- bool FixupDebugSections(off_t base_address_delta);
+ bool Fixup(Elf_Addr base_address);
+ bool FixupDynamic(Elf_Addr base_address);
+ bool FixupSectionHeaders(Elf_Addr base_address);
+ bool FixupProgramHeaders(Elf_Addr base_address);
+ bool FixupSymbols(Elf_Addr base_address, bool dynamic);
+ bool FixupRelocations(Elf_Addr base_address);
+ bool FixupDebugSections(typename std::make_signed<Elf_Off>::type base_address_delta);
bool Strip(std::string* error_msg);
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index 19d4e1a..6a68880 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -1148,11 +1148,11 @@
mirror::Object** root = roots[i];
mirror::Object* ref = *root;
if (ref == nullptr || region_space_->IsInToSpace(ref)) {
- return;
+ continue;
}
mirror::Object* to_ref = Mark(ref);
if (to_ref == ref) {
- return;
+ continue;
}
Atomic<mirror::Object*>* addr = reinterpret_cast<Atomic<mirror::Object*>*>(root);
mirror::Object* expected_ref = ref;
@@ -1173,11 +1173,11 @@
mirror::CompressedReference<mirror::Object>* root = roots[i];
mirror::Object* ref = root->AsMirrorPtr();
if (ref == nullptr || region_space_->IsInToSpace(ref)) {
- return;
+ continue;
}
mirror::Object* to_ref = Mark(ref);
if (to_ref == ref) {
- return;
+ continue;
}
auto* addr = reinterpret_cast<Atomic<mirror::CompressedReference<mirror::Object>>*>(root);
auto expected_ref = mirror::CompressedReference<mirror::Object>::FromMirrorPtr(ref);
diff --git a/runtime/gc_root.h b/runtime/gc_root.h
index 2f4da3f..0d3c93b 100644
--- a/runtime/gc_root.h
+++ b/runtime/gc_root.h
@@ -30,6 +30,9 @@
template <size_t kBufferSize>
class BufferedRootVisitor;
+// Dependent on pointer size so that we don't have frames that are too big on 64 bit.
+static const size_t kDefaultBufferedRootCount = 1024 / sizeof(void*);
+
enum RootType {
kRootUnknown = 0,
kRootJNIGlobal,
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index a3aa1de..cd59365 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -243,7 +243,7 @@
}
void IndirectReferenceTable::VisitRoots(RootVisitor* visitor, const RootInfo& root_info) {
- BufferedRootVisitor<128> root_visitor(visitor, root_info);
+ BufferedRootVisitor<kDefaultBufferedRootCount> root_visitor(visitor, root_info);
for (auto ref : *this) {
root_visitor.VisitRootIfNonNull(*ref);
}
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index dea157a..680b563 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -1082,7 +1082,7 @@
if (IsDeoptimizedMethodsEmpty()) {
return;
}
- BufferedRootVisitor<128> roots(visitor, RootInfo(kRootVMInternal));
+ BufferedRootVisitor<kDefaultBufferedRootCount> roots(visitor, RootInfo(kRootVMInternal));
for (auto pair : deoptimized_methods_) {
roots.VisitRoot(pair.second);
}
diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc
index 8e85435..1f1f9e8 100644
--- a/runtime/intern_table.cc
+++ b/runtime/intern_table.cc
@@ -336,7 +336,8 @@
}
void InternTable::Table::VisitRoots(RootVisitor* visitor) {
- BufferedRootVisitor<128> buffered_visitor(visitor, RootInfo(kRootInternedString));
+ BufferedRootVisitor<kDefaultBufferedRootCount> buffered_visitor(
+ visitor, RootInfo(kRootInternedString));
for (auto& intern : pre_zygote_table_) {
buffered_visitor.VisitRoot(intern);
}
diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc
index add1394..0d161bc 100644
--- a/runtime/jdwp/jdwp_handler.cc
+++ b/runtime/jdwp/jdwp_handler.cc
@@ -315,11 +315,12 @@
static JdwpError VM_CreateString(JdwpState*, Request* request, ExpandBuf* pReply)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
std::string str(request->ReadUtf8String());
- ObjectId stringId = Dbg::CreateString(str);
- if (stringId == 0) {
- return ERR_OUT_OF_MEMORY;
+ ObjectId string_id;
+ JdwpError status = Dbg::CreateString(str, &string_id);
+ if (status != ERR_NONE) {
+ return status;
}
- expandBufAddObjectId(pReply, stringId);
+ expandBufAddObjectId(pReply, string_id);
return ERR_NONE;
}
@@ -711,9 +712,6 @@
if (status != ERR_NONE) {
return status;
}
- if (object_id == 0) {
- return ERR_OUT_OF_MEMORY;
- }
return RequestInvoke(state, request, pReply, thread_id, object_id, class_id, method_id, true);
}
@@ -730,9 +728,6 @@
if (status != ERR_NONE) {
return status;
}
- if (object_id == 0) {
- return ERR_OUT_OF_MEMORY;
- }
expandBufAdd1(pReply, JT_ARRAY);
expandBufAddObjectId(pReply, object_id);
return ERR_NONE;
@@ -1657,6 +1652,7 @@
if (result == ERR_NONE) {
request->CheckConsumed();
}
+ self->AssertNoPendingException();
break;
}
}
diff --git a/runtime/reference_table.cc b/runtime/reference_table.cc
index ac36447..beba64f 100644
--- a/runtime/reference_table.cc
+++ b/runtime/reference_table.cc
@@ -238,7 +238,7 @@
}
void ReferenceTable::VisitRoots(RootVisitor* visitor, const RootInfo& root_info) {
- BufferedRootVisitor<128> buffered_visitor(visitor, root_info);
+ BufferedRootVisitor<kDefaultBufferedRootCount> buffered_visitor(visitor, root_info);
for (GcRoot<mirror::Object>& root : entries_) {
buffered_visitor.VisitRoot(root);
}
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 79d2b13..d1b0464 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1385,7 +1385,8 @@
}
void Thread::HandleScopeVisitRoots(RootVisitor* visitor, uint32_t thread_id) {
- BufferedRootVisitor<128> buffered_visitor(visitor, RootInfo(kRootNativeStack, thread_id));
+ BufferedRootVisitor<kDefaultBufferedRootCount> buffered_visitor(
+ visitor, RootInfo(kRootNativeStack, thread_id));
for (HandleScope* cur = tlsPtr_.top_handle_scope; cur; cur = cur->GetLink()) {
for (size_t j = 0, count = cur->NumberOfReferences(); j < count; ++j) {
buffered_visitor.VisitRootIfNonNull(cur->GetHandle(j).GetReference());
diff --git a/tools/dexfuzz/Android.mk b/tools/dexfuzz/Android.mk
index 1e4b4f5..1580bc3 100644
--- a/tools/dexfuzz/Android.mk
+++ b/tools/dexfuzz/Android.mk
@@ -31,7 +31,10 @@
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE := dexfuzz
include $(BUILD_SYSTEM)/base_rules.mk
-$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/dexfuzz $(ACP) $(HOST_CORE_IMG_OUTS)
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/dexfuzz $(ACP)
@echo "Copy: $(PRIVATE_MODULE) ($@)"
$(copy-file-to-new-target)
$(hide) chmod 755 $@
+
+# --- dexfuzz script with core image dependencies ----------------
+fuzzer: $(LOCAL_BUILT_MODULE) $(HOST_CORE_IMG_OUTS)
diff --git a/tools/dexfuzz/src/dexfuzz/executors/Device.java b/tools/dexfuzz/src/dexfuzz/executors/Device.java
index 736aaad..4a53957 100644
--- a/tools/dexfuzz/src/dexfuzz/executors/Device.java
+++ b/tools/dexfuzz/src/dexfuzz/executors/Device.java
@@ -17,6 +17,7 @@
package dexfuzz.executors;
import java.io.IOException;
+import java.io.File;
import java.util.Map;
import dexfuzz.ExecutionResult;
@@ -67,6 +68,10 @@
return envVars.get(key);
}
+ private String getHostCoreImagePath() {
+ return androidHostOut + "/framework/core.art";
+ }
+
private void setup() {
programPushed = false;
@@ -74,6 +79,13 @@
androidProductOut = checkForEnvVar(envVars, "ANDROID_PRODUCT_OUT");
androidHostOut = checkForEnvVar(envVars, "ANDROID_HOST_OUT");
+ if (Options.executeOnHost) {
+ File coreImage = new File(getHostCoreImagePath());
+ if (!coreImage.exists()) {
+ Log.errorAndQuit("Host core image not found at " + coreImage.getPath()
+ + ". Did you forget to build it?");
+ }
+ }
if (!isHost) {
// Create temporary consumers for the initial test.
StreamConsumer outputConsumer = new StreamConsumer();
@@ -144,7 +156,7 @@
* Get any extra flags required to execute ART on the host.
*/
public String getHostExecutionFlags() {
- return String.format("-Xnorelocate -Ximage:%s/framework/core.art", androidHostOut);
+ return String.format("-Xnorelocate -Ximage:%s", getHostCoreImagePath());
}
public String getAndroidHostOut() {