Merge "Fix app image memory leak"
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index 4c03e5d..4785885 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -249,9 +249,9 @@
ProfileCompilationInfo info;
for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
- std::cout << std::string(dex_file->GetLocation());
- profile_info_.AddData(dex_file->GetLocation(), dex_file->GetLocationChecksum(), 1);
- profile_info_.AddData(dex_file->GetLocation(), dex_file->GetLocationChecksum(), 2);
+ std::string key = ProfileCompilationInfo::GetProfileDexFileKey(dex_file->GetLocation());
+ profile_info_.AddData(key, dex_file->GetLocationChecksum(), 1);
+ profile_info_.AddData(key, dex_file->GetLocationChecksum(), 2);
}
return &profile_info_;
}
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index d2bf6c0..3fe7861 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -203,6 +203,7 @@
}
bool JitCompiler::CompileMethod(Thread* self, ArtMethod* method, bool osr) {
+ DCHECK(!method->IsProxyMethod());
TimingLogger logger("JIT compiler timing logger", true, VLOG_IS_ON(jit));
const uint64_t start_time = NanoTime();
StackHandleScope<2> hs(self);
@@ -220,20 +221,17 @@
bool success = false;
{
TimingLogger::ScopedTiming t2("Compiling", &logger);
- // If we get a request to compile a proxy method, we pass the actual Java method
- // of that proxy method, as the compiler does not expect a proxy method.
- ArtMethod* method_to_compile = method->GetInterfaceMethodIfProxy(sizeof(void*));
JitCodeCache* const code_cache = runtime->GetJit()->GetCodeCache();
- success = compiler_driver_->GetCompiler()->JitCompile(self, code_cache, method_to_compile, osr);
+ success = compiler_driver_->GetCompiler()->JitCompile(self, code_cache, method, osr);
if (success && (perf_file_ != nullptr)) {
- const void* ptr = method_to_compile->GetEntryPointFromQuickCompiledCode();
+ const void* ptr = method->GetEntryPointFromQuickCompiledCode();
std::ostringstream stream;
stream << std::hex
<< reinterpret_cast<uintptr_t>(ptr)
<< " "
<< code_cache->GetMemorySizeOfCodePointer(ptr)
<< " "
- << PrettyMethod(method_to_compile)
+ << PrettyMethod(method)
<< std::endl;
std::string str = stream.str();
bool res = perf_file_->WriteFully(str.c_str(), str.size());
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 8d77daf..a1d6276 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -37,41 +37,6 @@
namespace art {
-/**
- * Helper class to add HTemporary instructions. This class is used when
- * converting a DEX instruction to multiple HInstruction, and where those
- * instructions do not die at the following instruction, but instead spans
- * multiple instructions.
- */
-class Temporaries : public ValueObject {
- public:
- explicit Temporaries(HGraph* graph) : graph_(graph), index_(0) {}
-
- void Add(HInstruction* instruction) {
- HInstruction* temp = new (graph_->GetArena()) HTemporary(index_, instruction->GetDexPc());
- instruction->GetBlock()->AddInstruction(temp);
-
- DCHECK(temp->GetPrevious() == instruction);
-
- size_t offset;
- if (instruction->GetType() == Primitive::kPrimLong
- || instruction->GetType() == Primitive::kPrimDouble) {
- offset = 2;
- } else {
- offset = 1;
- }
- index_ += offset;
-
- graph_->UpdateTemporariesVRegSlots(index_);
- }
-
- private:
- HGraph* const graph_;
-
- // Current index in the temporary stack, updated by `Add`.
- size_t index_;
-};
-
void HGraphBuilder::InitializeLocals(uint16_t count) {
graph_->SetNumberOfVRegs(count);
locals_.resize(count);
@@ -1166,12 +1131,10 @@
size_t start_index = 0;
size_t argument_index = 0;
if (invoke->GetOriginalInvokeType() != InvokeType::kStatic) { // Instance call.
- Temporaries temps(graph_);
HInstruction* arg = LoadLocal(
is_range ? register_index : args[0], Primitive::kPrimNot, invoke->GetDexPc());
HNullCheck* null_check = new (arena_) HNullCheck(arg, invoke->GetDexPc());
current_block_->AddInstruction(null_check);
- temps.Add(null_check);
invoke->SetArgumentAt(0, null_check);
start_index = 1;
argument_index = 1;
@@ -1269,9 +1232,6 @@
? GetFieldAccessType(*dex_file_, field_index)
: resolved_field->GetTypeAsPrimitiveType();
if (is_put) {
- Temporaries temps(graph_);
- // We need one temporary for the null check.
- temps.Add(null_check);
HInstruction* value = LoadLocal(source_or_dest_reg, field_type, dex_pc);
HInstruction* field_set = nullptr;
if (resolved_field == nullptr) {
@@ -1456,8 +1416,6 @@
uint16_t class_def_index = klass->GetDexClassDefIndex();
if (is_put) {
// We need to keep the class alive before loading the value.
- Temporaries temps(graph_);
- temps.Add(cls);
HInstruction* value = LoadLocal(source_or_dest_reg, field_type, dex_pc);
DCHECK_EQ(value->GetType(), field_type);
current_block_->AddInstruction(new (arena_) HStaticFieldSet(cls,
@@ -1510,9 +1468,7 @@
|| (type == Primitive::kPrimInt && second->AsIntConstant()->GetValue() == 0)
|| (type == Primitive::kPrimLong && second->AsLongConstant()->GetValue() == 0)) {
second = new (arena_) HDivZeroCheck(second, dex_pc);
- Temporaries temps(graph_);
current_block_->AddInstruction(second);
- temps.Add(current_block_->GetLastInstruction());
}
if (isDiv) {
@@ -1531,21 +1487,15 @@
uint8_t array_reg = instruction.VRegB_23x();
uint8_t index_reg = instruction.VRegC_23x();
- // We need one temporary for the null check, one for the index, and one for the length.
- Temporaries temps(graph_);
-
HInstruction* object = LoadLocal(array_reg, Primitive::kPrimNot, dex_pc);
object = new (arena_) HNullCheck(object, dex_pc);
current_block_->AddInstruction(object);
- temps.Add(object);
HInstruction* length = new (arena_) HArrayLength(object, dex_pc);
current_block_->AddInstruction(length);
- temps.Add(length);
HInstruction* index = LoadLocal(index_reg, Primitive::kPrimInt, dex_pc);
index = new (arena_) HBoundsCheck(index, length, dex_pc);
current_block_->AddInstruction(index);
- temps.Add(index);
if (is_put) {
HInstruction* value = LoadLocal(source_or_dest_reg, anticipated_type, dex_pc);
// TODO: Insert a type check node if the type is Object.
@@ -1586,8 +1536,6 @@
bool is_reference_array = (primitive == 'L') || (primitive == '[');
Primitive::Type type = is_reference_array ? Primitive::kPrimNot : Primitive::kPrimInt;
- Temporaries temps(graph_);
- temps.Add(object);
for (size_t i = 0; i < number_of_vreg_arguments; ++i) {
HInstruction* value = LoadLocal(is_range ? register_index + i : args[i], type, dex_pc);
HInstruction* index = graph_->GetIntConstant(i, dex_pc);
@@ -1612,11 +1560,9 @@
}
void HGraphBuilder::BuildFillArrayData(const Instruction& instruction, uint32_t dex_pc) {
- Temporaries temps(graph_);
HInstruction* array = LoadLocal(instruction.VRegA_31t(), Primitive::kPrimNot, dex_pc);
HNullCheck* null_check = new (arena_) HNullCheck(array, dex_pc);
current_block_->AddInstruction(null_check);
- temps.Add(null_check);
HInstruction* length = new (arena_) HArrayLength(null_check, dex_pc);
current_block_->AddInstruction(length);
@@ -1733,10 +1679,6 @@
compiler_driver_->CanAssumeTypeIsPresentInDexCache(dex_file, type_index));
current_block_->AddInstruction(cls);
- // The class needs a temporary before being used by the type check.
- Temporaries temps(graph_);
- temps.Add(cls);
-
TypeCheckKind check_kind = ComputeTypeCheckKind(resolved_class);
if (instruction.Opcode() == Instruction::INSTANCE_OF) {
current_block_->AddInstruction(new (arena_) HInstanceOf(object, cls, check_kind, dex_pc));
@@ -2815,8 +2757,6 @@
case Instruction::ARRAY_LENGTH: {
HInstruction* object = LoadLocal(instruction.VRegB_12x(), Primitive::kPrimNot, dex_pc);
- // No need for a temporary for the null check, it is the only input of the following
- // instruction.
object = new (arena_) HNullCheck(object, dex_pc);
current_block_->AddInstruction(object);
current_block_->AddInstruction(new (arena_) HArrayLength(object, dex_pc));
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index e1b83f0..c2c8ccf 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -287,19 +287,6 @@
}
}
-Location CodeGenerator::GetTemporaryLocation(HTemporary* temp) const {
- uint16_t number_of_locals = GetGraph()->GetNumberOfLocalVRegs();
- // The type of the previous instruction tells us if we need a single or double stack slot.
- Primitive::Type type = temp->GetType();
- int32_t temp_size = (type == Primitive::kPrimLong) || (type == Primitive::kPrimDouble) ? 2 : 1;
- // Use the temporary region (right below the dex registers).
- int32_t slot = GetFrameSize() - FrameEntrySpillSize()
- - kVRegSize // filler
- - (number_of_locals * kVRegSize)
- - ((temp_size + temp->GetIndex()) * kVRegSize);
- return temp_size == 2 ? Location::DoubleStackSlot(slot) : Location::StackSlot(slot);
-}
-
int32_t CodeGenerator::GetStackSlot(HLocal* local) const {
uint16_t reg_number = local->GetRegNumber();
uint16_t number_of_locals = GetGraph()->GetNumberOfLocalVRegs();
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 0a688cf..49c193e 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -187,7 +187,6 @@
virtual void GenerateFrameEntry() = 0;
virtual void GenerateFrameExit() = 0;
virtual void Bind(HBasicBlock* block) = 0;
- virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) = 0;
virtual void MoveConstant(Location destination, int32_t value) = 0;
virtual void MoveLocation(Location dst, Location src, Primitive::Type dst_type) = 0;
virtual void AddLocationAsTemp(Location location, LocationSummary* locations) = 0;
@@ -203,7 +202,6 @@
size_t number_of_out_slots,
const ArenaVector<HBasicBlock*>& block_order);
int32_t GetStackSlot(HLocal* local) const;
- Location GetTemporaryLocation(HTemporary* temp) const;
uint32_t GetFrameSize() const { return frame_size_; }
void SetFrameSize(uint32_t size) { frame_size_ = size; }
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index e434932..005b6c1 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1195,90 +1195,6 @@
}
}
-void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
- LocationSummary* locations = instruction->GetLocations();
- if (instruction->IsCurrentMethod()) {
- Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
- } else if (locations != nullptr && locations->Out().Equals(location)) {
- return;
- } else if (locations != nullptr && locations->Out().IsConstant()) {
- HConstant* const_to_move = locations->Out().GetConstant();
- if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
- int32_t value = GetInt32ValueOf(const_to_move);
- if (location.IsRegister()) {
- __ LoadImmediate(location.AsRegister<Register>(), value);
- } else {
- DCHECK(location.IsStackSlot());
- __ LoadImmediate(IP, value);
- __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
- }
- } else {
- DCHECK(const_to_move->IsLongConstant()) << const_to_move->DebugName();
- int64_t value = const_to_move->AsLongConstant()->GetValue();
- if (location.IsRegisterPair()) {
- __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
- __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
- } else {
- DCHECK(location.IsDoubleStackSlot());
- __ LoadImmediate(IP, Low32Bits(value));
- __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
- __ LoadImmediate(IP, High32Bits(value));
- __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
- }
- }
- } else if (instruction->IsLoadLocal()) {
- uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
- switch (instruction->GetType()) {
- case Primitive::kPrimBoolean:
- case Primitive::kPrimByte:
- case Primitive::kPrimChar:
- case Primitive::kPrimShort:
- case Primitive::kPrimInt:
- case Primitive::kPrimNot:
- case Primitive::kPrimFloat:
- Move32(location, Location::StackSlot(stack_slot));
- break;
-
- case Primitive::kPrimLong:
- case Primitive::kPrimDouble:
- Move64(location, Location::DoubleStackSlot(stack_slot));
- break;
-
- default:
- LOG(FATAL) << "Unexpected type " << instruction->GetType();
- }
- } else if (instruction->IsTemporary()) {
- Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
- if (temp_location.IsStackSlot()) {
- Move32(location, temp_location);
- } else {
- DCHECK(temp_location.IsDoubleStackSlot());
- Move64(location, temp_location);
- }
- } else {
- DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
- switch (instruction->GetType()) {
- case Primitive::kPrimBoolean:
- case Primitive::kPrimByte:
- case Primitive::kPrimChar:
- case Primitive::kPrimShort:
- case Primitive::kPrimNot:
- case Primitive::kPrimInt:
- case Primitive::kPrimFloat:
- Move32(location, locations->Out());
- break;
-
- case Primitive::kPrimLong:
- case Primitive::kPrimDouble:
- Move64(location, locations->Out());
- break;
-
- default:
- LOG(FATAL) << "Unexpected type " << instruction->GetType();
- }
- }
-}
-
void CodeGeneratorARM::MoveConstant(Location location, int32_t value) {
DCHECK(location.IsRegister());
__ LoadImmediate(location.AsRegister<Register>(), value);
@@ -4933,14 +4849,6 @@
}
}
-void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
- temp->SetLocations(nullptr);
-}
-
-void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) {
- // Nothing to do, this is driven by the code generator.
-}
-
void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
LOG(FATAL) << "Unreachable";
}
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 558c9cf..cfd7a3b 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -307,7 +307,6 @@
void GenerateFrameEntry() OVERRIDE;
void GenerateFrameExit() OVERRIDE;
void Bind(HBasicBlock* block) OVERRIDE;
- void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
void MoveConstant(Location destination, int32_t value) OVERRIDE;
void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE;
void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index cfdf6b1..de23fe8 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -1066,54 +1066,6 @@
__ Bind(GetLabelOf(block));
}
-void CodeGeneratorARM64::Move(HInstruction* instruction,
- Location location,
- HInstruction* move_for) {
- LocationSummary* locations = instruction->GetLocations();
- Primitive::Type type = instruction->GetType();
- DCHECK_NE(type, Primitive::kPrimVoid);
-
- if (instruction->IsCurrentMethod()) {
- MoveLocation(location,
- Location::DoubleStackSlot(kCurrentMethodStackOffset),
- Primitive::kPrimVoid);
- } else if (locations != nullptr && locations->Out().Equals(location)) {
- return;
- } else if (instruction->IsIntConstant()
- || instruction->IsLongConstant()
- || instruction->IsNullConstant()) {
- int64_t value = GetInt64ValueOf(instruction->AsConstant());
- if (location.IsRegister()) {
- Register dst = RegisterFrom(location, type);
- DCHECK(((instruction->IsIntConstant() || instruction->IsNullConstant()) && dst.Is32Bits()) ||
- (instruction->IsLongConstant() && dst.Is64Bits()));
- __ Mov(dst, value);
- } else {
- DCHECK(location.IsStackSlot() || location.IsDoubleStackSlot());
- UseScratchRegisterScope temps(GetVIXLAssembler());
- Register temp = (instruction->IsIntConstant() || instruction->IsNullConstant())
- ? temps.AcquireW()
- : temps.AcquireX();
- __ Mov(temp, value);
- __ Str(temp, StackOperandFrom(location));
- }
- } else if (instruction->IsTemporary()) {
- Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
- MoveLocation(location, temp_location, type);
- } else if (instruction->IsLoadLocal()) {
- uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
- if (Primitive::Is64BitType(type)) {
- MoveLocation(location, Location::DoubleStackSlot(stack_slot), type);
- } else {
- MoveLocation(location, Location::StackSlot(stack_slot), type);
- }
-
- } else {
- DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
- MoveLocation(location, locations->Out(), type);
- }
-}
-
void CodeGeneratorARM64::MoveConstant(Location location, int32_t value) {
DCHECK(location.IsRegister());
__ Mov(RegisterFrom(location, Primitive::kPrimInt), value);
@@ -4445,14 +4397,6 @@
GenerateSuspendCheck(instruction, nullptr);
}
-void LocationsBuilderARM64::VisitTemporary(HTemporary* temp) {
- temp->SetLocations(nullptr);
-}
-
-void InstructionCodeGeneratorARM64::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) {
- // Nothing to do, this is driven by the code generator.
-}
-
void LocationsBuilderARM64::VisitThrow(HThrow* instruction) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index a9d1bbd..360488e 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -350,8 +350,6 @@
return CommonGetLabelOf<vixl::Label>(block_labels_, block);
}
- void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
-
size_t GetWordSize() const OVERRIDE {
return kArm64WordSize;
}
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index e9c0b6a..3eda863 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -976,46 +976,6 @@
__ LoadConst32(dst, value);
}
-void CodeGeneratorMIPS::Move(HInstruction* instruction,
- Location location,
- HInstruction* move_for) {
- LocationSummary* locations = instruction->GetLocations();
- Primitive::Type type = instruction->GetType();
- DCHECK_NE(type, Primitive::kPrimVoid);
-
- if (instruction->IsCurrentMethod()) {
- Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
- } else if (locations != nullptr && locations->Out().Equals(location)) {
- return;
- } else if (instruction->IsIntConstant()
- || instruction->IsLongConstant()
- || instruction->IsNullConstant()) {
- MoveConstant(location, instruction->AsConstant());
- } else if (instruction->IsTemporary()) {
- Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
- if (temp_location.IsStackSlot()) {
- Move32(location, temp_location);
- } else {
- DCHECK(temp_location.IsDoubleStackSlot());
- Move64(location, temp_location);
- }
- } else if (instruction->IsLoadLocal()) {
- uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
- if (Primitive::Is64BitType(type)) {
- Move64(location, Location::DoubleStackSlot(stack_slot));
- } else {
- Move32(location, Location::StackSlot(stack_slot));
- }
- } else {
- DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
- if (Primitive::Is64BitType(type)) {
- Move64(location, locations->Out());
- } else {
- Move32(location, locations->Out());
- }
- }
-}
-
void CodeGeneratorMIPS::AddLocationAsTemp(Location location, LocationSummary* locations) {
if (location.IsRegister()) {
locations->AddTemp(location);
@@ -4795,14 +4755,6 @@
GenerateSuspendCheck(instruction, nullptr);
}
-void LocationsBuilderMIPS::VisitTemporary(HTemporary* temp) {
- temp->SetLocations(nullptr);
-}
-
-void InstructionCodeGeneratorMIPS::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) {
- // Nothing to do, this is driven by the code generator.
-}
-
void LocationsBuilderMIPS::VisitThrow(HThrow* instruction) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index 2cde0ed..12964b0 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -268,7 +268,6 @@
void Bind(HBasicBlock* block) OVERRIDE;
- void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
void Move32(Location destination, Location source);
void Move64(Location destination, Location source);
void MoveConstant(Location location, HConstant* c);
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index da98a89..71d65e8 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -869,65 +869,6 @@
}
}
-void CodeGeneratorMIPS64::Move(HInstruction* instruction,
- Location location,
- HInstruction* move_for) {
- LocationSummary* locations = instruction->GetLocations();
- Primitive::Type type = instruction->GetType();
- DCHECK_NE(type, Primitive::kPrimVoid);
-
- if (instruction->IsCurrentMethod()) {
- MoveLocation(location, Location::DoubleStackSlot(kCurrentMethodStackOffset), type);
- } else if (locations != nullptr && locations->Out().Equals(location)) {
- return;
- } else if (instruction->IsIntConstant()
- || instruction->IsLongConstant()
- || instruction->IsNullConstant()) {
- if (location.IsRegister()) {
- // Move to GPR from constant
- GpuRegister dst = location.AsRegister<GpuRegister>();
- if (instruction->IsNullConstant() || instruction->IsIntConstant()) {
- __ LoadConst32(dst, GetInt32ValueOf(instruction->AsConstant()));
- } else {
- __ LoadConst64(dst, instruction->AsLongConstant()->GetValue());
- }
- } else {
- DCHECK(location.IsStackSlot() || location.IsDoubleStackSlot());
- // Move to stack from constant
- GpuRegister gpr = ZERO;
- if (location.IsStackSlot()) {
- int32_t value = GetInt32ValueOf(instruction->AsConstant());
- if (value != 0) {
- gpr = TMP;
- __ LoadConst32(gpr, value);
- }
- __ StoreToOffset(kStoreWord, gpr, SP, location.GetStackIndex());
- } else {
- DCHECK(location.IsDoubleStackSlot());
- int64_t value = instruction->AsLongConstant()->GetValue();
- if (value != 0) {
- gpr = TMP;
- __ LoadConst64(gpr, value);
- }
- __ StoreToOffset(kStoreDoubleword, gpr, SP, location.GetStackIndex());
- }
- }
- } else if (instruction->IsTemporary()) {
- Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
- MoveLocation(location, temp_location, type);
- } else if (instruction->IsLoadLocal()) {
- uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
- if (Primitive::Is64BitType(type)) {
- MoveLocation(location, Location::DoubleStackSlot(stack_slot), type);
- } else {
- MoveLocation(location, Location::StackSlot(stack_slot), type);
- }
- } else {
- DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
- MoveLocation(location, locations->Out(), type);
- }
-}
-
void CodeGeneratorMIPS64::MoveConstant(Location location, int32_t value) {
DCHECK(location.IsRegister());
__ LoadConst32(location.AsRegister<GpuRegister>(), value);
@@ -3946,14 +3887,6 @@
GenerateSuspendCheck(instruction, nullptr);
}
-void LocationsBuilderMIPS64::VisitTemporary(HTemporary* temp) {
- temp->SetLocations(nullptr);
-}
-
-void InstructionCodeGeneratorMIPS64::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) {
- // Nothing to do, this is driven by the code generator.
-}
-
void LocationsBuilderMIPS64::VisitThrow(HThrow* instruction) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h
index c836f83..1161253 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -268,8 +268,6 @@
void Bind(HBasicBlock* block) OVERRIDE;
- void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
-
size_t GetWordSize() const OVERRIDE { return kMips64DoublewordSize; }
size_t GetFloatingPointSpillSlotSize() const OVERRIDE { return kMips64DoublewordSize; }
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index de62010..3713690 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -1127,91 +1127,6 @@
}
}
-void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
- LocationSummary* locations = instruction->GetLocations();
- if (instruction->IsCurrentMethod()) {
- Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
- } else if (locations != nullptr && locations->Out().Equals(location)) {
- return;
- } else if (locations != nullptr && locations->Out().IsConstant()) {
- HConstant* const_to_move = locations->Out().GetConstant();
- if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
- Immediate imm(GetInt32ValueOf(const_to_move));
- if (location.IsRegister()) {
- __ movl(location.AsRegister<Register>(), imm);
- } else if (location.IsStackSlot()) {
- __ movl(Address(ESP, location.GetStackIndex()), imm);
- } else {
- DCHECK(location.IsConstant());
- DCHECK_EQ(location.GetConstant(), const_to_move);
- }
- } else if (const_to_move->IsLongConstant()) {
- int64_t value = const_to_move->AsLongConstant()->GetValue();
- if (location.IsRegisterPair()) {
- __ movl(location.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
- __ movl(location.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
- } else if (location.IsDoubleStackSlot()) {
- __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value)));
- __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)),
- Immediate(High32Bits(value)));
- } else {
- DCHECK(location.IsConstant());
- DCHECK_EQ(location.GetConstant(), instruction);
- }
- }
- } else if (instruction->IsTemporary()) {
- Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
- if (temp_location.IsStackSlot()) {
- Move32(location, temp_location);
- } else {
- DCHECK(temp_location.IsDoubleStackSlot());
- Move64(location, temp_location);
- }
- } else if (instruction->IsLoadLocal()) {
- int slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
- switch (instruction->GetType()) {
- case Primitive::kPrimBoolean:
- case Primitive::kPrimByte:
- case Primitive::kPrimChar:
- case Primitive::kPrimShort:
- case Primitive::kPrimInt:
- case Primitive::kPrimNot:
- case Primitive::kPrimFloat:
- Move32(location, Location::StackSlot(slot));
- break;
-
- case Primitive::kPrimLong:
- case Primitive::kPrimDouble:
- Move64(location, Location::DoubleStackSlot(slot));
- break;
-
- default:
- LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
- }
- } else {
- DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
- switch (instruction->GetType()) {
- case Primitive::kPrimBoolean:
- case Primitive::kPrimByte:
- case Primitive::kPrimChar:
- case Primitive::kPrimShort:
- case Primitive::kPrimInt:
- case Primitive::kPrimNot:
- case Primitive::kPrimFloat:
- Move32(location, locations->Out());
- break;
-
- case Primitive::kPrimLong:
- case Primitive::kPrimDouble:
- Move64(location, locations->Out());
- break;
-
- default:
- LOG(FATAL) << "Unexpected type " << instruction->GetType();
- }
- }
-}
-
void CodeGeneratorX86::MoveConstant(Location location, int32_t value) {
DCHECK(location.IsRegister());
__ movl(location.AsRegister<Register>(), Immediate(value));
@@ -5513,14 +5428,6 @@
}
}
-void LocationsBuilderX86::VisitTemporary(HTemporary* temp) {
- temp->SetLocations(nullptr);
-}
-
-void InstructionCodeGeneratorX86::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) {
- // Nothing to do, this is driven by the code generator.
-}
-
void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
LOG(FATAL) << "Unreachable";
}
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 45e8ffa..2fb6d60 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -317,7 +317,6 @@
void GenerateFrameEntry() OVERRIDE;
void GenerateFrameExit() OVERRIDE;
void Bind(HBasicBlock* block) OVERRIDE;
- void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
void MoveConstant(Location destination, int32_t value) OVERRIDE;
void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE;
void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 4f0f5f0..35603aa 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1206,82 +1206,6 @@
}
}
-void CodeGeneratorX86_64::Move(HInstruction* instruction,
- Location location,
- HInstruction* move_for) {
- LocationSummary* locations = instruction->GetLocations();
- if (instruction->IsCurrentMethod()) {
- Move(location, Location::DoubleStackSlot(kCurrentMethodStackOffset));
- } else if (locations != nullptr && locations->Out().Equals(location)) {
- return;
- } else if (locations != nullptr && locations->Out().IsConstant()) {
- HConstant* const_to_move = locations->Out().GetConstant();
- if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
- Immediate imm(GetInt32ValueOf(const_to_move));
- if (location.IsRegister()) {
- __ movl(location.AsRegister<CpuRegister>(), imm);
- } else if (location.IsStackSlot()) {
- __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
- } else {
- DCHECK(location.IsConstant());
- DCHECK_EQ(location.GetConstant(), const_to_move);
- }
- } else if (const_to_move->IsLongConstant()) {
- int64_t value = const_to_move->AsLongConstant()->GetValue();
- if (location.IsRegister()) {
- Load64BitValue(location.AsRegister<CpuRegister>(), value);
- } else if (location.IsDoubleStackSlot()) {
- Store64BitValueToStack(location, value);
- } else {
- DCHECK(location.IsConstant());
- DCHECK_EQ(location.GetConstant(), const_to_move);
- }
- }
- } else if (instruction->IsLoadLocal()) {
- switch (instruction->GetType()) {
- case Primitive::kPrimBoolean:
- case Primitive::kPrimByte:
- case Primitive::kPrimChar:
- case Primitive::kPrimShort:
- case Primitive::kPrimInt:
- case Primitive::kPrimNot:
- case Primitive::kPrimFloat:
- Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
- break;
-
- case Primitive::kPrimLong:
- case Primitive::kPrimDouble:
- Move(location,
- Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
- break;
-
- default:
- LOG(FATAL) << "Unexpected local type " << instruction->GetType();
- }
- } else if (instruction->IsTemporary()) {
- Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
- Move(location, temp_location);
- } else {
- DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
- switch (instruction->GetType()) {
- case Primitive::kPrimBoolean:
- case Primitive::kPrimByte:
- case Primitive::kPrimChar:
- case Primitive::kPrimShort:
- case Primitive::kPrimInt:
- case Primitive::kPrimNot:
- case Primitive::kPrimLong:
- case Primitive::kPrimFloat:
- case Primitive::kPrimDouble:
- Move(location, locations->Out());
- break;
-
- default:
- LOG(FATAL) << "Unexpected type " << instruction->GetType();
- }
- }
-}
-
void CodeGeneratorX86_64::MoveConstant(Location location, int32_t value) {
DCHECK(location.IsRegister());
Load64BitValue(location.AsRegister<CpuRegister>(), static_cast<int64_t>(value));
@@ -5142,14 +5066,6 @@
}
}
-void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
- temp->SetLocations(nullptr);
-}
-
-void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) {
- // Nothing to do, this is driven by the code generator.
-}
-
void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
LOG(FATAL) << "Unimplemented";
}
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 72dddfd..97f6f84 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -299,7 +299,6 @@
void GenerateFrameEntry() OVERRIDE;
void GenerateFrameExit() OVERRIDE;
void Bind(HBasicBlock* block) OVERRIDE;
- void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
void MoveConstant(Location destination, int32_t value) OVERRIDE;
void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE;
void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE;
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index 322a577..4f37c37 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -777,9 +777,9 @@
HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
HLessThan cmp_lt(cst_lhs, cst_rhs);
if_block->AddInstruction(&cmp_lt);
- // We insert a temporary to separate the HIf from the HLessThan and force
- // the materialization of the condition.
- HTemporary force_materialization(0);
+ // We insert a dummy instruction to separate the HIf from the HLessThan
+ // and force the materialization of the condition.
+ HMemoryBarrier force_materialization(MemBarrierKind::kAnyAny, 0);
if_block->AddInstruction(&force_materialization);
HIf if_lt(&cmp_lt);
if_block->AddInstruction(&if_lt);
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index fa6aae8..3740c40 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -378,7 +378,7 @@
// Run type propagation to get the guard typed, and eventually propagate the
// type of the receiver.
- ReferenceTypePropagation rtp_fixup(graph_, handles_);
+ ReferenceTypePropagation rtp_fixup(graph_, handles_, /* is_first_run */ false);
rtp_fixup.Run();
MaybeRecordStat(kInlinedMonomorphicCall);
@@ -420,6 +420,9 @@
actual_method = new_method;
} else if (actual_method != new_method) {
// Different methods, bailout.
+ VLOG(compiler) << "Call to " << PrettyMethod(resolved_method)
+ << " from inline cache is not inlined because it resolves"
+ << " to different methods";
return false;
}
}
@@ -474,7 +477,7 @@
deoptimize->CopyEnvironmentFrom(invoke_instruction->GetEnvironment());
// Run type propagation to get the guard typed.
- ReferenceTypePropagation rtp_fixup(graph_, handles_);
+ ReferenceTypePropagation rtp_fixup(graph_, handles_, /* is_first_run */ false);
rtp_fixup.Run();
MaybeRecordStat(kInlinedPolymorphicCall);
@@ -727,7 +730,7 @@
// dex pc for the associated stack map. 0 is bogus but valid. Bug: 26854537.
/* dex_pc */ 0);
if (iget->GetType() == Primitive::kPrimNot) {
- ReferenceTypePropagation rtp(graph_, handles_);
+ ReferenceTypePropagation rtp(graph_, handles_, /* is_first_run */ false);
rtp.Visit(iget);
}
return iget;
@@ -756,6 +759,7 @@
/* dex_pc */ 0);
return iput;
}
+
bool HInliner::TryBuildAndInline(ArtMethod* resolved_method,
HInvoke* invoke_instruction,
bool same_dex_file,
@@ -988,12 +992,18 @@
if (current->IsNewInstance() &&
(current->AsNewInstance()->GetEntrypoint() == kQuickAllocObjectWithAccessCheck)) {
+ VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
+ << " could not be inlined because it is using an entrypoint"
+ << " with access checks";
// Allocation entrypoint does not handle inlined frames.
return false;
}
if (current->IsNewArray() &&
(current->AsNewArray()->GetEntrypoint() == kQuickAllocArrayWithAccessCheck)) {
+ VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
+ << " could not be inlined because it is using an entrypoint"
+ << " with access checks";
// Allocation entrypoint does not handle inlined frames.
return false;
}
@@ -1003,6 +1013,9 @@
current->IsUnresolvedStaticFieldSet() ||
current->IsUnresolvedInstanceFieldSet()) {
// Entrypoint for unresolved fields does not handle inlined frames.
+ VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
+ << " could not be inlined because it is using an unresolved"
+ << " entrypoint";
return false;
}
}
@@ -1044,13 +1057,13 @@
if (invoke_rti.IsStrictSupertypeOf(return_rti)
|| (return_rti.IsExact() && !invoke_rti.IsExact())
|| !return_replacement->CanBeNull()) {
- ReferenceTypePropagation(graph_, handles_).Run();
+ ReferenceTypePropagation(graph_, handles_, /* is_first_run */ false).Run();
}
}
} else if (return_replacement->IsInstanceOf()) {
if (do_rtp) {
// Inlining InstanceOf into an If may put a tighter bound on reference types.
- ReferenceTypePropagation(graph_, handles_).Run();
+ ReferenceTypePropagation(graph_, handles_, /* is_first_run */ false).Run();
}
}
}
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 7f463a3..2697af3 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -1235,7 +1235,6 @@
M(StoreLocal, Instruction) \
M(Sub, BinaryOperation) \
M(SuspendCheck, Instruction) \
- M(Temporary, Instruction) \
M(Throw, Instruction) \
M(TryBoundary, Instruction) \
M(TypeConversion, Instruction) \
@@ -4941,33 +4940,6 @@
DISALLOW_COPY_AND_ASSIGN(HBoundsCheck);
};
-/**
- * Some DEX instructions are folded into multiple HInstructions that need
- * to stay live until the last HInstruction. This class
- * is used as a marker for the baseline compiler to ensure its preceding
- * HInstruction stays live. `index` represents the stack location index of the
- * instruction (the actual offset is computed as index * vreg_size).
- */
-class HTemporary : public HTemplateInstruction<0> {
- public:
- explicit HTemporary(size_t index, uint32_t dex_pc = kNoDexPc)
- : HTemplateInstruction(SideEffects::None(), dex_pc), index_(index) {}
-
- size_t GetIndex() const { return index_; }
-
- Primitive::Type GetType() const OVERRIDE {
- // The previous instruction is the one that will be stored in the temporary location.
- DCHECK(GetPrevious() != nullptr);
- return GetPrevious()->GetType();
- }
-
- DECLARE_INSTRUCTION(Temporary);
-
- private:
- const size_t index_;
- DISALLOW_COPY_AND_ASSIGN(HTemporary);
-};
-
class HSuspendCheck : public HTemplateInstruction<0> {
public:
explicit HSuspendCheck(uint32_t dex_pc)
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 1224a48..deaa415 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -55,10 +55,12 @@
public:
RTPVisitor(HGraph* graph,
HandleCache* handle_cache,
- ArenaVector<HInstruction*>* worklist)
+ ArenaVector<HInstruction*>* worklist,
+ bool is_first_run)
: HGraphDelegateVisitor(graph),
handle_cache_(handle_cache),
- worklist_(worklist) {}
+ worklist_(worklist),
+ is_first_run_(is_first_run) {}
void VisitNewInstance(HNewInstance* new_instance) OVERRIDE;
void VisitLoadClass(HLoadClass* load_class) OVERRIDE;
@@ -86,14 +88,17 @@
private:
HandleCache* handle_cache_;
ArenaVector<HInstruction*>* worklist_;
+ const bool is_first_run_;
};
ReferenceTypePropagation::ReferenceTypePropagation(HGraph* graph,
StackHandleScopeCollection* handles,
+ bool is_first_run,
const char* name)
: HOptimization(graph, name),
handle_cache_(handles),
- worklist_(graph->GetArena()->Adapter(kArenaAllocReferenceTypePropagation)) {
+ worklist_(graph->GetArena()->Adapter(kArenaAllocReferenceTypePropagation)),
+ is_first_run_(is_first_run) {
}
void ReferenceTypePropagation::ValidateTypes() {
@@ -125,7 +130,7 @@
}
void ReferenceTypePropagation::Visit(HInstruction* instruction) {
- RTPVisitor visitor(graph_, &handle_cache_, &worklist_);
+ RTPVisitor visitor(graph_, &handle_cache_, &worklist_, is_first_run_);
instruction->Accept(&visitor);
}
@@ -144,7 +149,7 @@
}
void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
- RTPVisitor visitor(graph_, &handle_cache_, &worklist_);
+ RTPVisitor visitor(graph_, &handle_cache_, &worklist_, is_first_run_);
// Handle Phis first as there might be instructions in the same block who depend on them.
for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
VisitPhi(it.Current()->AsPhi());
@@ -620,6 +625,7 @@
DCHECK_EQ(bound_type->InputAt(0), check_cast->InputAt(0));
if (class_rti.IsValid()) {
+ DCHECK(is_first_run_);
// This is the first run of RTP and class is resolved.
bound_type->SetUpperBound(class_rti, /* CheckCast succeeds for nulls. */ true);
} else {
@@ -636,6 +642,12 @@
}
if (phi->GetBlock()->IsLoopHeader()) {
+ if (!is_first_run_ && graph_->IsCompilingOsr()) {
+ // Don't update the type of a loop phi when compiling OSR: we may have done
+ // speculative optimizations dominating that phi, that do not hold at the
+ // point the interpreter jumps to that loop header.
+ return;
+ }
ScopedObjectAccess soa(Thread::Current());
// Set the initial type for the phi. Use the non back edge input for reaching
// a fixed point faster.
diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h
index a7f10a6..028a6fc 100644
--- a/compiler/optimizing/reference_type_propagation.h
+++ b/compiler/optimizing/reference_type_propagation.h
@@ -33,6 +33,7 @@
public:
ReferenceTypePropagation(HGraph* graph,
StackHandleScopeCollection* handles,
+ bool is_first_run,
const char* name = kReferenceTypePropagationPassName);
// Visit a single instruction.
@@ -93,6 +94,8 @@
ArenaVector<HInstruction*> worklist_;
+ // Whether this reference type propagation is the first run we are doing.
+ const bool is_first_run_;
static constexpr size_t kDefaultWorklistSize = 8;
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index 165d09d..2d0a399 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -483,7 +483,7 @@
// 6) Compute type of reference type instructions. The pass assumes that
// NullConstant has been fixed up.
- ReferenceTypePropagation(GetGraph(), handles_).Run();
+ ReferenceTypePropagation(GetGraph(), handles_, /* is_first_run */ true).Run();
// 7) Step 1) duplicated ArrayGet instructions with ambiguous type (int/float
// or long/double) and marked ArraySets with ambiguous input type. Now that RTP
@@ -899,11 +899,6 @@
}
}
-void SsaBuilder::VisitTemporary(HTemporary* temp) {
- // Temporaries are only used by the baseline register allocator.
- temp->GetBlock()->RemoveInstruction(temp);
-}
-
void SsaBuilder::VisitArrayGet(HArrayGet* aget) {
Primitive::Type type = aget->GetType();
DCHECK(!Primitive::IsFloatingPointType(type));
diff --git a/compiler/optimizing/ssa_builder.h b/compiler/optimizing/ssa_builder.h
index ccef8ea..4cba41f 100644
--- a/compiler/optimizing/ssa_builder.h
+++ b/compiler/optimizing/ssa_builder.h
@@ -75,7 +75,6 @@
void VisitLoadLocal(HLoadLocal* load) OVERRIDE;
void VisitStoreLocal(HStoreLocal* store) OVERRIDE;
void VisitInstruction(HInstruction* instruction) OVERRIDE;
- void VisitTemporary(HTemporary* instruction) OVERRIDE;
void VisitArrayGet(HArrayGet* aget) OVERRIDE;
void VisitArraySet(HArraySet* aset) OVERRIDE;
void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE;
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 949ad99..c4e314b 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -444,11 +444,12 @@
mov r10, r1 @ Save size of stack
ldr r9, [r11, #40] @ Move managed thread pointer into r9
mov r8, r2 @ Save the pc to call
- sub r7, sp, #12 @ Reserve space for stack pointer, JValue result, and ArtMethod* slot
+ sub r7, sp, #12 @ Reserve space for stack pointer,
+ @ JValue* result, and ArtMethod* slot.
and r7, #0xFFFFFFF0 @ Align stack pointer
mov sp, r7 @ Update stack pointer
str r11, [sp, #4] @ Save old stack pointer
- str r3, [sp, #8] @ Save JValue result
+ str r3, [sp, #8] @ Save JValue* result
mov ip, #0
str ip, [sp] @ Store null for ArtMethod* at bottom of frame
sub sp, sp, r1 @ Reserve space for callee stack
@@ -457,9 +458,8 @@
mov r0, sp
bl memcpy @ memcpy (dest r0, src r1, bytes r2)
bl .Losr_entry @ Call the method
- ldr r11, [sp, #4] @ Restore saved stack pointer
- ldr r10, [sp, #8] @ Restore JValue result
- mov sp, r11 @ Restore stack pointer.
+ ldr r10, [sp, #8] @ Restore JValue* result
+ ldr sp, [sp, #4] @ Restore saved stack pointer
ldr r4, [sp, #36] @ load shorty
ldrb r4, [r4, #0] @ load return type
cmp r4, #68 @ Test if result type char == 'D'.
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index d6e0f1c..69caec8 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -1755,6 +1755,8 @@
* rcx = JValue* result
* r8 = shorty
* r9 = thread
+ *
+ * Note that the native C ABI already aligned the stack to 16-byte.
*/
DEFINE_FUNCTION art_quick_osr_stub
// Save the non-volatiles.
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index e38a684..fcfa457 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -36,8 +36,6 @@
namespace art {
namespace jit {
-static constexpr bool kEnableOnStackReplacement = false;
-
JitOptions* JitOptions::CreateFromRuntimeArguments(const RuntimeArgumentMap& options) {
auto* jit_options = new JitOptions;
jit_options->use_jit_ = options.GetOrDefault(RuntimeArgumentMap::UseJIT);
@@ -164,6 +162,7 @@
bool Jit::CompileMethod(ArtMethod* method, Thread* self, bool osr) {
DCHECK(!method->IsRuntimeMethod());
+
// Don't compile the method if it has breakpoints.
if (Dbg::IsDebuggerActive() && Dbg::MethodHasAnyBreakpoints(method)) {
VLOG(jit) << "JIT not compiling " << PrettyMethod(method) << " due to breakpoint";
@@ -177,12 +176,15 @@
return false;
}
- if (!code_cache_->NotifyCompilationOf(method, self, osr)) {
+ // If we get a request to compile a proxy method, we pass the actual Java method
+ // of that proxy method, as the compiler does not expect a proxy method.
+ ArtMethod* method_to_compile = method->GetInterfaceMethodIfProxy(sizeof(void*));
+ if (!code_cache_->NotifyCompilationOf(method_to_compile, self, osr)) {
VLOG(jit) << "JIT not compiling " << PrettyMethod(method) << " due to code cache";
return false;
}
- bool success = jit_compile_method_(jit_compiler_handle_, method, self, osr);
- code_cache_->DoneCompiling(method, self);
+ bool success = jit_compile_method_(jit_compiler_handle_, method_to_compile, self, osr);
+ code_cache_->DoneCompiling(method_to_compile, self);
return success;
}
@@ -276,10 +278,6 @@
uint32_t dex_pc,
int32_t dex_pc_offset,
JValue* result) {
- if (!kEnableOnStackReplacement) {
- return false;
- }
-
Jit* jit = Runtime::Current()->GetJit();
if (jit == nullptr) {
return false;
@@ -326,7 +324,13 @@
ShadowFrame* shadow_frame = thread->PopShadowFrame();
size_t frame_size = osr_method->GetFrameSizeInBytes();
+
+ // Allocate memory to put shadow frame values. The osr stub will copy that memory to
+ // stack.
+ // Note that we could pass the shadow frame to the stub, and let it copy the values there,
+ // but that is engineering complexity not worth the effort for something like OSR.
void** memory = reinterpret_cast<void**>(malloc(frame_size));
+ CHECK(memory != nullptr);
memset(memory, 0, frame_size);
// Art ABI: ArtMethod is at the bottom of the stack.
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 464c441..9111ddf 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -578,7 +578,7 @@
}
}
- // Empty osr method map, as osr compile code will be deleted (except the ones
+ // Empty osr method map, as osr compiled code will be deleted (except the ones
// on thread stacks).
osr_code_map_.clear();
}
diff --git a/runtime/jit/offline_profiling_info.cc b/runtime/jit/offline_profiling_info.cc
index b4b872f..0aff1f7 100644
--- a/runtime/jit/offline_profiling_info.cc
+++ b/runtime/jit/offline_profiling_info.cc
@@ -33,6 +33,21 @@
namespace art {
+// Transform the actual dex location into relative paths.
+// Note: this is OK because we don't store profiles of different apps into the same file.
+// Apps with split apks don't cause trouble because each split has a different name and will not
+// collide with other entries.
+std::string ProfileCompilationInfo::GetProfileDexFileKey(const std::string& dex_location) {
+ DCHECK(!dex_location.empty());
+ size_t last_sep_index = dex_location.find_last_of('/');
+ if (last_sep_index == std::string::npos) {
+ return dex_location;
+ } else {
+ DCHECK(last_sep_index < dex_location.size());
+ return dex_location.substr(last_sep_index + 1);
+ }
+}
+
bool ProfileCompilationInfo::SaveProfilingInfo(const std::string& filename,
const std::vector<ArtMethod*>& methods) {
if (methods.empty()) {
@@ -58,7 +73,7 @@
ScopedObjectAccess soa(Thread::Current());
for (auto it = methods.begin(); it != methods.end(); it++) {
const DexFile* dex_file = (*it)->GetDexFile();
- if (!info.AddData(dex_file->GetLocation(),
+ if (!info.AddData(GetProfileDexFileKey(dex_file->GetLocation()),
dex_file->GetLocationChecksum(),
(*it)->GetDexMethodIndex())) {
return false;
@@ -107,8 +122,8 @@
* dex_location1,dex_location_checksum1,method_id11,method_id12...
* dex_location2,dex_location_checksum2,method_id21,method_id22...
* e.g.
- * /system/priv-app/app/app.apk,131232145,11,23,454,54
- * /system/priv-app/app/app.apk:classes5.dex,218490184,39,13,49,1
+ * app.apk,131232145,11,23,454,54
+ * app.apk:classes5.dex,218490184,39,13,49,1
**/
bool ProfileCompilationInfo::Save(uint32_t fd) {
DCHECK_GE(fd, 0u);
@@ -270,7 +285,7 @@
}
bool ProfileCompilationInfo::ContainsMethod(const MethodReference& method_ref) const {
- auto info_it = info_.find(method_ref.dex_file->GetLocation());
+ auto info_it = info_.find(GetProfileDexFileKey(method_ref.dex_file->GetLocation()));
if (info_it != info_.end()) {
if (method_ref.dex_file->GetLocationChecksum() != info_it->second.checksum) {
return false;
diff --git a/runtime/jit/offline_profiling_info.h b/runtime/jit/offline_profiling_info.h
index ffd1433..c388c4a 100644
--- a/runtime/jit/offline_profiling_info.h
+++ b/runtime/jit/offline_profiling_info.h
@@ -66,6 +66,8 @@
// For testing purposes.
bool Equals(ProfileCompilationInfo& other);
+ // Exposed for testing purpose.
+ static std::string GetProfileDexFileKey(const std::string& dex_location);
private:
bool AddData(const std::string& dex_location, uint32_t checksum, uint16_t method_idx);
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index c7ac172..8d5e6ea 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -2411,6 +2411,8 @@
if (!reg_types_.JavaLangThrowable(false).IsAssignableFrom(res_type)) {
if (res_type.IsUninitializedTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "thrown exception not initialized";
+ } else if (!res_type.IsReferenceTypes()) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "thrown value of non-reference type " << res_type;
} else {
Fail(res_type.IsUnresolvedTypes() ? VERIFY_ERROR_NO_CLASS : VERIFY_ERROR_BAD_CLASS_SOFT)
<< "thrown class " << res_type << " not instanceof Throwable";
diff --git a/test/510-checker-try-catch/smali/Builder.smali b/test/510-checker-try-catch/smali/Builder.smali
index 1fde5ed..c91b83e 100644
--- a/test/510-checker-try-catch/smali/Builder.smali
+++ b/test/510-checker-try-catch/smali/Builder.smali
@@ -1126,7 +1126,6 @@
## CHECK-START: int[] Builder.testMoveResult_FilledNewArray(int, int, int) builder (after)
## CHECK: <<Res:l\d+>> NewArray
-## CHECK-NEXT: Temporary
## CHECK-NEXT: <<Local1:i\d+>> LoadLocal [v0]
## CHECK-NEXT: ArraySet [<<Res>>,{{i\d+}},<<Local1>>]
## CHECK-NEXT: <<Local2:i\d+>> LoadLocal [v1]
diff --git a/test/570-checker-osr/expected.txt b/test/570-checker-osr/expected.txt
index 555c6a9..25fb220 100644
--- a/test/570-checker-osr/expected.txt
+++ b/test/570-checker-osr/expected.txt
@@ -1,5 +1,5 @@
JNI_OnLoad called
-100000000
-200000000
-300000000
-400000000
+100000
+200000
+300000
+400000
diff --git a/test/570-checker-osr/osr.cc b/test/570-checker-osr/osr.cc
index fb84687..c1774f3 100644
--- a/test/570-checker-osr/osr.cc
+++ b/test/570-checker-osr/osr.cc
@@ -38,7 +38,8 @@
(m_name.compare("$noinline$returnFloat") == 0) ||
(m_name.compare("$noinline$returnDouble") == 0) ||
(m_name.compare("$noinline$returnLong") == 0) ||
- (m_name.compare("$noinline$deopt") == 0)) {
+ (m_name.compare("$noinline$deopt") == 0) ||
+ (m_name.compare("$noinline$inlineCache") == 0)) {
const OatQuickMethodHeader* header =
Runtime::Current()->GetJit()->GetCodeCache()->LookupOsrMethodHeader(m);
if (header != nullptr && header == GetCurrentOatQuickMethodHeader()) {
diff --git a/test/570-checker-osr/src/Main.java b/test/570-checker-osr/src/Main.java
index 7485163..bc6612f 100644
--- a/test/570-checker-osr/src/Main.java
+++ b/test/570-checker-osr/src/Main.java
@@ -16,6 +16,7 @@
public class Main {
public static void main(String[] args) {
+ new SubMain();
System.loadLibrary(args[0]);
if ($noinline$returnInt() != 53) {
throw new Error("Unexpected return value");
@@ -33,12 +34,18 @@
try {
$noinline$deopt();
} catch (Exception e) {}
+ DeoptimizationController.stopDeoptimization();
+
+ $noinline$inlineCache(new Main(), 0);
+ if ($noinline$inlineCache(new SubMain(), 1) != SubMain.class) {
+ throw new Error("Unexpected return value");
+ }
}
public static int $noinline$returnInt() {
if (doThrow) throw new Error("");
int i = 0;
- for (; i < 100000000; ++i) {
+ for (; i < 100000; ++i) {
}
while (!ensureInOsrCode()) {}
System.out.println(i);
@@ -48,7 +55,7 @@
public static float $noinline$returnFloat() {
if (doThrow) throw new Error("");
int i = 0;
- for (; i < 200000000; ++i) {
+ for (; i < 200000; ++i) {
}
while (!ensureInOsrCode()) {}
System.out.println(i);
@@ -58,7 +65,7 @@
public static double $noinline$returnDouble() {
if (doThrow) throw new Error("");
int i = 0;
- for (; i < 300000000; ++i) {
+ for (; i < 300000; ++i) {
}
while (!ensureInOsrCode()) {}
System.out.println(i);
@@ -67,8 +74,8 @@
public static long $noinline$returnLong() {
if (doThrow) throw new Error("");
- int i = 1000000;
- for (; i < 400000000; ++i) {
+ int i = 0;
+ for (; i < 400000; ++i) {
}
while (!ensureInOsrCode()) {}
System.out.println(i);
@@ -78,15 +85,63 @@
public static void $noinline$deopt() {
if (doThrow) throw new Error("");
int i = 0;
- for (; i < 100000000; ++i) {
+ for (; i < 100000; ++i) {
}
while (!ensureInOsrCode()) {}
DeoptimizationController.startDeoptimization();
}
+ public static Class $noinline$inlineCache(Main m, int count) {
+ for (int i = 0; i < 500; ++i) {
+ // Warm me up.
+ }
+ if (count == 1) {
+ // Lots of back edges to trigger OSR compilation.
+ for (int i = 0; i < 1000; ++i) {
+ }
+ // Best effort to wait for OSR compilation.
+ try {
+ Thread.sleep(1);
+ } catch (Exception e) {}
+ }
+
+ // This call will be optimized in the OSR compiled code
+ // to check and deoptimize if m is not of type 'Main'.
+ Main other = m.inlineCache();
+
+ if (count == 1) {
+ // Jump to OSR compiled code. The second run
+ // of this method will have 'm' as a SubMain, and the compiled
+ // code we are jumping to will have wrongly optimize other as being a
+ // 'Main'.
+ while (!ensureInOsrCode()) {}
+ }
+
+ // We used to wrongly optimize this call and assume 'other' was a 'Main'.
+ return other.returnClass();
+ }
+
+ public Main inlineCache() {
+ return new Main();
+ }
+
+ public Class returnClass() {
+ return Main.class;
+ }
+
public static int[] array = new int[4];
public static native boolean ensureInOsrCode();
public static boolean doThrow = false;
}
+
+class SubMain extends Main {
+ public Class returnClass() {
+ return SubMain.class;
+ }
+
+ public Main inlineCache() {
+ return new SubMain();
+ }
+}
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index 73ce307..edbb7b5 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -58,4 +58,5 @@
b/26594149 (6)
b/26594149 (7)
b/26594149 (8)
+b/27148248
Done!
diff --git a/test/800-smali/smali/b_27148248.smali b/test/800-smali/smali/b_27148248.smali
new file mode 100644
index 0000000..4601cc6
--- /dev/null
+++ b/test/800-smali/smali/b_27148248.smali
@@ -0,0 +1,27 @@
+# Copyright (C) 2016 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.
+
+.class public LB27148248;
+
+# Regression for dex2oatd crash during compilation of method which
+# used to throw with argument of non-reference type.
+
+.super Ljava/lang/Object;
+
+.method public static run()V
+ .registers 1
+ const v0, 0xbad
+ throw v0
+.end method
+
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index b0eff5d..2ea3367 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -160,6 +160,8 @@
null));
testCases.add(new TestCase("b/26594149 (8)", "B26594149_8", "run", null, new VerifyError(),
null));
+ testCases.add(new TestCase("b/27148248", "B27148248", "run", null, new VerifyError(),
+ null));
}
public void runTests() {
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 9dcd4dc..b3560b6 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -446,9 +446,7 @@
# Known broken tests for the JIT.
# CFI unwinding expects managed frames, and the test does not iterate enough to even compile. JIT
# also uses Generic JNI instead of the JNI compiler.
-# 570 is disabled while investigating osr flakiness.
TEST_ART_BROKEN_JIT_RUN_TESTS := \
- 570-checker-osr \
137-cfi
ifneq (,$(filter jit,$(COMPILER_TYPES)))