diff options
Diffstat (limited to 'compiler/optimizing')
| -rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 74 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 71 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm_vixl.cc | 335 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm_vixl.h | 35 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_mips.cc | 14 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_mips64.cc | 15 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 56 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 56 |
8 files changed, 515 insertions, 141 deletions
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 7c72d00389..c6363d1708 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -489,14 +489,6 @@ class TypeCheckSlowPathARM : public SlowPathCodeARM { void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { LocationSummary* locations = instruction_->GetLocations(); - Location arg0, arg1; - if (instruction_->IsInstanceOf()) { - arg0 = locations->InAt(1); - arg1 = locations->Out(); - } else { - arg0 = locations->InAt(0); - arg1 = locations->InAt(1); - } DCHECK(instruction_->IsCheckCast() || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); @@ -510,10 +502,10 @@ class TypeCheckSlowPathARM : public SlowPathCodeARM { // We're moving two locations to locations that could overlap, so we need a parallel // move resolver. InvokeRuntimeCallingConvention calling_convention; - codegen->EmitParallelMoves(arg0, + codegen->EmitParallelMoves(locations->InAt(0), Location::RegisterLocation(calling_convention.GetRegisterAt(0)), Primitive::kPrimNot, - arg1, + locations->InAt(1), Location::RegisterLocation(calling_convention.GetRegisterAt(1)), Primitive::kPrimNot); if (instruction_->IsInstanceOf()) { @@ -521,7 +513,7 @@ class TypeCheckSlowPathARM : public SlowPathCodeARM { instruction_, instruction_->GetDexPc(), this); - CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Class*, mirror::Class*>(); + CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>(); arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0)); } else { DCHECK(instruction_->IsCheckCast()); @@ -6114,16 +6106,15 @@ void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { __ CompareAndBranchIfZero(obj, &zero); } - // /* HeapReference<Class> */ out = obj->klass_ - GenerateReferenceLoadTwoRegisters(instruction, - out_loc, - obj_loc, - class_offset, - maybe_temp_loc, - kCompilerReadBarrierOption); - switch (type_check_kind) { case TypeCheckKind::kExactCheck: { + // /* HeapReference<Class> */ out = obj->klass_ + GenerateReferenceLoadTwoRegisters(instruction, + out_loc, + obj_loc, + class_offset, + maybe_temp_loc, + kCompilerReadBarrierOption); __ cmp(out, ShifterOperand(cls)); // Classes must be equal for the instanceof to succeed. __ b(&zero, NE); @@ -6133,6 +6124,13 @@ void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { } case TypeCheckKind::kAbstractClassCheck: { + // /* HeapReference<Class> */ out = obj->klass_ + GenerateReferenceLoadTwoRegisters(instruction, + out_loc, + obj_loc, + class_offset, + maybe_temp_loc, + kCompilerReadBarrierOption); // If the class is abstract, we eagerly fetch the super class of the // object to avoid doing a comparison we know will fail. Label loop; @@ -6155,6 +6153,13 @@ void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { } case TypeCheckKind::kClassHierarchyCheck: { + // /* HeapReference<Class> */ out = obj->klass_ + GenerateReferenceLoadTwoRegisters(instruction, + out_loc, + obj_loc, + class_offset, + maybe_temp_loc, + kCompilerReadBarrierOption); // Walk over the class hierarchy to find a match. Label loop, success; __ Bind(&loop); @@ -6178,6 +6183,13 @@ void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { } case TypeCheckKind::kArrayObjectCheck: { + // /* HeapReference<Class> */ out = obj->klass_ + GenerateReferenceLoadTwoRegisters(instruction, + out_loc, + obj_loc, + class_offset, + maybe_temp_loc, + kCompilerReadBarrierOption); // Do an exact check. Label exact_check; __ cmp(out, ShifterOperand(cls)); @@ -6201,6 +6213,14 @@ void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { } case TypeCheckKind::kArrayCheck: { + // No read barrier since the slow path will retry upon failure. + // /* HeapReference<Class> */ out = obj->klass_ + GenerateReferenceLoadTwoRegisters(instruction, + out_loc, + obj_loc, + class_offset, + maybe_temp_loc, + kWithoutReadBarrier); __ cmp(out, ShifterOperand(cls)); DCHECK(locations->OnlyCallsOnSlowPath()); slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM(instruction, @@ -6470,30 +6490,26 @@ void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) { iftable_offset, maybe_temp2_loc, kWithoutReadBarrier); - Label is_null; // Null iftable means it is empty and will always fail the check. - // Not cbz since the temp may not be a low register. - __ CompareAndBranchIfZero(temp, &is_null); + __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel()); // Loop through the iftable and check if any class matches. __ ldr(maybe_temp2_loc.AsRegister<Register>(), Address(temp, array_length_offset)); Label start_loop; __ Bind(&start_loop); + __ CompareAndBranchIfZero(maybe_temp2_loc.AsRegister<Register>(), + type_check_slow_path->GetEntryLabel()); __ ldr(maybe_temp3_loc.AsRegister<Register>(), Address(temp, object_array_data_offset)); __ MaybeUnpoisonHeapReference(maybe_temp3_loc.AsRegister<Register>()); - __ cmp(cls, ShifterOperand(maybe_temp3_loc.AsRegister<Register>())); - __ b(&done, EQ); // Return if same class. // Go to next interface. __ add(temp, temp, ShifterOperand(2 * kHeapReferenceSize)); __ sub(maybe_temp2_loc.AsRegister<Register>(), maybe_temp2_loc.AsRegister<Register>(), ShifterOperand(2)); - // Not cbnz since the temp may not be a low register. - __ CompareAndBranchIfNonZero(maybe_temp2_loc.AsRegister<Register>(), &start_loop); - __ Bind(&is_null); - - __ b(type_check_slow_path->GetEntryLabel()); + // Compare the classes and continue the loop if they do not match. + __ cmp(cls, ShifterOperand(maybe_temp3_loc.AsRegister<Register>())); + __ b(&start_loop, NE); break; } } diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 35b16051e5..4ab6065819 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -459,14 +459,6 @@ class TypeCheckSlowPathARM64 : public SlowPathCodeARM64 { void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { LocationSummary* locations = instruction_->GetLocations(); - Location arg0, arg1; - if (instruction_->IsInstanceOf()) { - arg0 = locations->InAt(1); - arg1 = locations->Out(); - } else { - arg0 = locations->InAt(0); - arg1 = locations->InAt(1); - } DCHECK(instruction_->IsCheckCast() || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); @@ -482,15 +474,15 @@ class TypeCheckSlowPathARM64 : public SlowPathCodeARM64 { // We're moving two locations to locations that could overlap, so we need a parallel // move resolver. InvokeRuntimeCallingConvention calling_convention; - codegen->EmitParallelMoves(arg0, + codegen->EmitParallelMoves(locations->InAt(0), LocationFrom(calling_convention.GetRegisterAt(0)), Primitive::kPrimNot, - arg1, + locations->InAt(1), LocationFrom(calling_convention.GetRegisterAt(1)), Primitive::kPrimNot); if (instruction_->IsInstanceOf()) { arm64_codegen->InvokeRuntime(kQuickInstanceofNonTrivial, instruction_, dex_pc, this); - CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Class*, mirror::Class*>(); + CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>(); Primitive::Type ret_type = instruction_->GetType(); Location ret_loc = calling_convention.GetReturnLocation(ret_type); arm64_codegen->MoveLocation(locations->Out(), ret_loc, ret_type); @@ -3427,16 +3419,15 @@ void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) { __ Cbz(obj, &zero); } - // /* HeapReference<Class> */ out = obj->klass_ - GenerateReferenceLoadTwoRegisters(instruction, - out_loc, - obj_loc, - class_offset, - maybe_temp_loc, - kCompilerReadBarrierOption); - switch (type_check_kind) { case TypeCheckKind::kExactCheck: { + // /* HeapReference<Class> */ out = obj->klass_ + GenerateReferenceLoadTwoRegisters(instruction, + out_loc, + obj_loc, + class_offset, + maybe_temp_loc, + kCompilerReadBarrierOption); __ Cmp(out, cls); __ Cset(out, eq); if (zero.IsLinked()) { @@ -3446,6 +3437,13 @@ void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) { } case TypeCheckKind::kAbstractClassCheck: { + // /* HeapReference<Class> */ out = obj->klass_ + GenerateReferenceLoadTwoRegisters(instruction, + out_loc, + obj_loc, + class_offset, + maybe_temp_loc, + kCompilerReadBarrierOption); // If the class is abstract, we eagerly fetch the super class of the // object to avoid doing a comparison we know will fail. vixl::aarch64::Label loop, success; @@ -3468,6 +3466,13 @@ void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) { } case TypeCheckKind::kClassHierarchyCheck: { + // /* HeapReference<Class> */ out = obj->klass_ + GenerateReferenceLoadTwoRegisters(instruction, + out_loc, + obj_loc, + class_offset, + maybe_temp_loc, + kCompilerReadBarrierOption); // Walk over the class hierarchy to find a match. vixl::aarch64::Label loop, success; __ Bind(&loop); @@ -3491,6 +3496,13 @@ void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) { } case TypeCheckKind::kArrayObjectCheck: { + // /* HeapReference<Class> */ out = obj->klass_ + GenerateReferenceLoadTwoRegisters(instruction, + out_loc, + obj_loc, + class_offset, + maybe_temp_loc, + kCompilerReadBarrierOption); // Do an exact check. vixl::aarch64::Label exact_check; __ Cmp(out, cls); @@ -3514,6 +3526,14 @@ void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) { } case TypeCheckKind::kArrayCheck: { + // No read barrier since the slow path will retry upon failure. + // /* HeapReference<Class> */ out = obj->klass_ + GenerateReferenceLoadTwoRegisters(instruction, + out_loc, + obj_loc, + class_offset, + maybe_temp_loc, + kWithoutReadBarrier); __ Cmp(out, cls); DCHECK(locations->OnlyCallsOnSlowPath()); slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM64(instruction, @@ -3782,26 +3802,23 @@ void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) { iftable_offset, maybe_temp2_loc, kWithoutReadBarrier); - vixl::aarch64::Label is_null; // Null iftable means it is empty and will always fail the check. - __ Cbz(temp, &is_null); + __ Cbz(temp, type_check_slow_path->GetEntryLabel()); // Loop through the iftable and check if any class matches. __ Ldr(WRegisterFrom(maybe_temp2_loc), HeapOperand(temp.W(), array_length_offset)); vixl::aarch64::Label start_loop; __ Bind(&start_loop); + __ Cbz(WRegisterFrom(maybe_temp2_loc), type_check_slow_path->GetEntryLabel()); __ Ldr(WRegisterFrom(maybe_temp3_loc), HeapOperand(temp.W(), object_array_data_offset)); GetAssembler()->MaybeUnpoisonHeapReference(WRegisterFrom(maybe_temp3_loc)); - __ Cmp(cls, WRegisterFrom(maybe_temp3_loc)); - __ B(eq, &done); // Return if same class. // Go to next interface. __ Add(temp, temp, 2 * kHeapReferenceSize); __ Sub(WRegisterFrom(maybe_temp2_loc), WRegisterFrom(maybe_temp2_loc), 2); - __ Cbnz(WRegisterFrom(maybe_temp2_loc), &start_loop); - __ Bind(&is_null); - - __ B(type_check_slow_path->GetEntryLabel()); + // Compare the classes and continue the loop if they do not match. + __ Cmp(cls, WRegisterFrom(maybe_temp3_loc)); + __ B(ne, &start_loop); break; } } diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index 1c1cc95ab1..e9827e8620 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -65,6 +65,7 @@ static bool ExpectedPairLayout(Location location) { static constexpr int kCurrentMethodStackOffset = 0; static constexpr size_t kArmInstrMaxSizeInBytes = 4u; +static constexpr uint32_t kPackedSwitchCompareJumpThreshold = 7; #ifdef __ #error "ARM Codegen VIXL macro-assembler macro already defined." @@ -443,14 +444,6 @@ class TypeCheckSlowPathARMVIXL : public SlowPathCodeARMVIXL { void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { LocationSummary* locations = instruction_->GetLocations(); - Location arg0, arg1; - if (instruction_->IsInstanceOf()) { - arg0 = locations->InAt(1); - arg1 = locations->Out(); - } else { - arg0 = locations->InAt(0); - arg1 = locations->InAt(1); - } DCHECK(instruction_->IsCheckCast() || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); @@ -465,10 +458,10 @@ class TypeCheckSlowPathARMVIXL : public SlowPathCodeARMVIXL { // move resolver. InvokeRuntimeCallingConventionARMVIXL calling_convention; - codegen->EmitParallelMoves(arg0, + codegen->EmitParallelMoves(locations->InAt(0), LocationFrom(calling_convention.GetRegisterAt(0)), Primitive::kPrimNot, - arg1, + locations->InAt(1), LocationFrom(calling_convention.GetRegisterAt(1)), Primitive::kPrimNot); if (instruction_->IsInstanceOf()) { @@ -476,8 +469,7 @@ class TypeCheckSlowPathARMVIXL : public SlowPathCodeARMVIXL { instruction_, instruction_->GetDexPc(), this); - CheckEntrypointTypes< - kQuickInstanceofNonTrivial, size_t, mirror::Class*, mirror::Class*>(); + CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>(); arm_codegen->Move32(locations->Out(), LocationFrom(r0)); } else { DCHECK(instruction_->IsCheckCast()); @@ -657,6 +649,7 @@ CodeGeneratorARMVIXL::CodeGeneratorARMVIXL(HGraph* graph, compiler_options, stats), block_labels_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), + jump_tables_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), location_builder_(graph, this), instruction_visitor_(graph, this), move_resolver_(graph->GetArena(), this), @@ -675,9 +668,44 @@ CodeGeneratorARMVIXL::CodeGeneratorARMVIXL(HGraph* graph, GetVIXLAssembler()->GetScratchVRegisterList()->Combine(d15); } +void JumpTableARMVIXL::EmitTable(CodeGeneratorARMVIXL* codegen) { + uint32_t num_entries = switch_instr_->GetNumEntries(); + DCHECK_GE(num_entries, kPackedSwitchCompareJumpThreshold); + + // We are about to use the assembler to place literals directly. Make sure we have enough + // underlying code buffer and we have generated the jump table with right size. + codegen->GetVIXLAssembler()->GetBuffer().Align(); + AssemblerAccurateScope aas(codegen->GetVIXLAssembler(), + num_entries * sizeof(int32_t), + CodeBufferCheckScope::kMaximumSize); + // TODO(VIXL): Check that using lower case bind is fine here. + codegen->GetVIXLAssembler()->bind(&table_start_); + const ArenaVector<HBasicBlock*>& successors = switch_instr_->GetBlock()->GetSuccessors(); + for (uint32_t i = 0; i < num_entries; i++) { + vixl32::Label* target_label = codegen->GetLabelOf(successors[i]); + DCHECK(target_label->IsBound()); + int32_t jump_offset = target_label->GetLocation() - table_start_.GetLocation(); + // When doing BX to address we need to have lower bit set to 1 in T32. + if (codegen->GetVIXLAssembler()->IsUsingT32()) { + jump_offset++; + } + DCHECK_GT(jump_offset, std::numeric_limits<int32_t>::min()); + DCHECK_LE(jump_offset, std::numeric_limits<int32_t>::max()); + vixl32::Literal<int32_t> literal(jump_offset); + codegen->GetVIXLAssembler()->place(&literal); + } +} + +void CodeGeneratorARMVIXL::EmitJumpTables() { + for (auto&& jump_table : jump_tables_) { + jump_table->EmitTable(this); + } +} + #define __ reinterpret_cast<ArmVIXLAssembler*>(GetAssembler())->GetVIXLAssembler()-> // NOLINT void CodeGeneratorARMVIXL::Finalize(CodeAllocator* allocator) { + EmitJumpTables(); GetAssembler()->FinalizeCode(); CodeGenerator::Finalize(allocator); } @@ -1253,6 +1281,14 @@ void InstructionCodeGeneratorARMVIXL::VisitSelect(HSelect* select) { __ Bind(&false_target); } +void LocationsBuilderARMVIXL::VisitNativeDebugInfo(HNativeDebugInfo* info) { + new (GetGraph()->GetArena()) LocationSummary(info); +} + +void InstructionCodeGeneratorARMVIXL::VisitNativeDebugInfo(HNativeDebugInfo*) { + // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile. +} + void CodeGeneratorARMVIXL::GenerateNop() { __ Nop(); } @@ -2495,7 +2531,12 @@ void LocationsBuilderARMVIXL::VisitDiv(HDiv* div) { locations->SetInAt(1, Location::RequiresRegister()); locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); } else { - TODO_VIXL32(FATAL); + InvokeRuntimeCallingConventionARMVIXL calling_convention; + locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0))); + locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1))); + // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but + // we only need the former. + locations->SetOut(LocationFrom(r0)); } break; } @@ -2532,7 +2573,13 @@ void InstructionCodeGeneratorARMVIXL::VisitDiv(HDiv* div) { } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { __ Sdiv(OutputRegister(div), InputRegisterAt(div, 0), InputRegisterAt(div, 1)); } else { - TODO_VIXL32(FATAL); + InvokeRuntimeCallingConventionARMVIXL calling_convention; + DCHECK(calling_convention.GetRegisterAt(0).Is(RegisterFrom(lhs))); + DCHECK(calling_convention.GetRegisterAt(1).Is(RegisterFrom(rhs))); + DCHECK(r0.Is(OutputRegister(div))); + + codegen_->InvokeRuntime(kQuickIdivmod, div, div->GetDexPc()); + CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>(); } break; } @@ -2561,6 +2608,140 @@ void InstructionCodeGeneratorARMVIXL::VisitDiv(HDiv* div) { } } +void LocationsBuilderARMVIXL::VisitRem(HRem* rem) { + Primitive::Type type = rem->GetResultType(); + + // Most remainders are implemented in the runtime. + LocationSummary::CallKind call_kind = LocationSummary::kCallOnMainOnly; + if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) { + // sdiv will be replaced by other instruction sequence. + call_kind = LocationSummary::kNoCall; + } else if ((rem->GetResultType() == Primitive::kPrimInt) + && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { + // Have hardware divide instruction for int, do it with three instructions. + call_kind = LocationSummary::kNoCall; + } + + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind); + + switch (type) { + case Primitive::kPrimInt: { + if (rem->InputAt(1)->IsConstant()) { + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant())); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + int32_t value = rem->InputAt(1)->AsIntConstant()->GetValue(); + if (value == 1 || value == 0 || value == -1) { + // No temp register required. + } else { + locations->AddTemp(Location::RequiresRegister()); + if (!IsPowerOfTwo(AbsOrMin(value))) { + locations->AddTemp(Location::RequiresRegister()); + } + } + } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + locations->AddTemp(Location::RequiresRegister()); + } else { + InvokeRuntimeCallingConventionARMVIXL calling_convention; + locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0))); + locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1))); + // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but + // we only need the latter. + locations->SetOut(LocationFrom(r1)); + } + break; + } + case Primitive::kPrimLong: { + InvokeRuntimeCallingConventionARMVIXL calling_convention; + locations->SetInAt(0, LocationFrom( + calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1))); + locations->SetInAt(1, LocationFrom( + calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3))); + // The runtime helper puts the output in R2,R3. + locations->SetOut(LocationFrom(r2, r3)); + break; + } + case Primitive::kPrimFloat: { + InvokeRuntimeCallingConventionARMVIXL calling_convention; + locations->SetInAt(0, LocationFrom(calling_convention.GetFpuRegisterAt(0))); + locations->SetInAt(1, LocationFrom(calling_convention.GetFpuRegisterAt(1))); + locations->SetOut(LocationFrom(s0)); + break; + } + + case Primitive::kPrimDouble: { + InvokeRuntimeCallingConventionARMVIXL calling_convention; + locations->SetInAt(0, LocationFrom( + calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1))); + locations->SetInAt(1, LocationFrom( + calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3))); + locations->SetOut(LocationFrom(s0, s1)); + break; + } + + default: + LOG(FATAL) << "Unexpected rem type " << type; + } +} + +void InstructionCodeGeneratorARMVIXL::VisitRem(HRem* rem) { + LocationSummary* locations = rem->GetLocations(); + Location second = locations->InAt(1); + + Primitive::Type type = rem->GetResultType(); + switch (type) { + case Primitive::kPrimInt: { + vixl32::Register reg1 = InputRegisterAt(rem, 0); + vixl32::Register out_reg = OutputRegister(rem); + if (second.IsConstant()) { + GenerateDivRemConstantIntegral(rem); + } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { + vixl32::Register reg2 = RegisterFrom(second); + vixl32::Register temp = RegisterFrom(locations->GetTemp(0)); + + // temp = reg1 / reg2 (integer division) + // dest = reg1 - temp * reg2 + __ Sdiv(temp, reg1, reg2); + __ Mls(out_reg, temp, reg2, reg1); + } else { + InvokeRuntimeCallingConventionARMVIXL calling_convention; + DCHECK(reg1.Is(calling_convention.GetRegisterAt(0))); + DCHECK(RegisterFrom(second).Is(calling_convention.GetRegisterAt(1))); + DCHECK(out_reg.Is(r1)); + + codegen_->InvokeRuntime(kQuickIdivmod, rem, rem->GetDexPc()); + CheckEntrypointTypes<kQuickIdivmod, int32_t, int32_t, int32_t>(); + } + break; + } + + case Primitive::kPrimLong: { + codegen_->InvokeRuntime(kQuickLmod, rem, rem->GetDexPc()); + CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>(); + break; + } + + case Primitive::kPrimFloat: { + codegen_->InvokeRuntime(kQuickFmodf, rem, rem->GetDexPc()); + CheckEntrypointTypes<kQuickFmodf, float, float, float>(); + break; + } + + case Primitive::kPrimDouble: { + codegen_->InvokeRuntime(kQuickFmod, rem, rem->GetDexPc()); + CheckEntrypointTypes<kQuickFmod, double, double, double>(); + break; + } + + default: + LOG(FATAL) << "Unexpected rem type " << type; + } +} + + void LocationsBuilderARMVIXL::VisitDivZeroCheck(HDivZeroCheck* instruction) { // TODO(VIXL): https://android-review.googlesource.com/#/c/275337/ LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock() @@ -5257,6 +5438,24 @@ void InstructionCodeGeneratorARMVIXL::VisitCheckCast(HCheckCast* instruction) { __ Bind(type_check_slow_path->GetExitLabel()); } +void LocationsBuilderARMVIXL::VisitMonitorOperation(HMonitorOperation* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly); + InvokeRuntimeCallingConventionARMVIXL calling_convention; + locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0))); +} + +void InstructionCodeGeneratorARMVIXL::VisitMonitorOperation(HMonitorOperation* instruction) { + codegen_->InvokeRuntime(instruction->IsEnter() ? kQuickLockObject : kQuickUnlockObject, + instruction, + instruction->GetDexPc()); + if (instruction->IsEnter()) { + CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>(); + } else { + CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>(); + } +} + void LocationsBuilderARMVIXL::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); } @@ -5659,6 +5858,103 @@ void CodeGeneratorARMVIXL::GenerateVirtualCall(HInvokeVirtual* invoke, Location __ Blx(lr); } +void LocationsBuilderARMVIXL::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) { + // Nothing to do, this should be removed during prepare for register allocator. + LOG(FATAL) << "Unreachable"; +} + +void InstructionCodeGeneratorARMVIXL::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) { + // Nothing to do, this should be removed during prepare for register allocator. + LOG(FATAL) << "Unreachable"; +} + +// Simple implementation of packed switch - generate cascaded compare/jumps. +void LocationsBuilderARMVIXL::VisitPackedSwitch(HPackedSwitch* switch_instr) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall); + locations->SetInAt(0, Location::RequiresRegister()); + if (switch_instr->GetNumEntries() > kPackedSwitchCompareJumpThreshold && + codegen_->GetAssembler()->GetVIXLAssembler()->IsUsingT32()) { + locations->AddTemp(Location::RequiresRegister()); // We need a temp for the table base. + if (switch_instr->GetStartValue() != 0) { + locations->AddTemp(Location::RequiresRegister()); // We need a temp for the bias. + } + } +} + +// TODO(VIXL): Investigate and reach the parity with old arm codegen. +void InstructionCodeGeneratorARMVIXL::VisitPackedSwitch(HPackedSwitch* switch_instr) { + int32_t lower_bound = switch_instr->GetStartValue(); + uint32_t num_entries = switch_instr->GetNumEntries(); + LocationSummary* locations = switch_instr->GetLocations(); + vixl32::Register value_reg = InputRegisterAt(switch_instr, 0); + HBasicBlock* default_block = switch_instr->GetDefaultBlock(); + + if (num_entries <= kPackedSwitchCompareJumpThreshold || + !codegen_->GetAssembler()->GetVIXLAssembler()->IsUsingT32()) { + // Create a series of compare/jumps. + UseScratchRegisterScope temps(GetAssembler()->GetVIXLAssembler()); + vixl32::Register temp_reg = temps.Acquire(); + // Note: It is fine for the below AddConstantSetFlags() using IP register to temporarily store + // the immediate, because IP is used as the destination register. For the other + // AddConstantSetFlags() and GenerateCompareWithImmediate(), the immediate values are constant, + // and they can be encoded in the instruction without making use of IP register. + __ Adds(temp_reg, value_reg, -lower_bound); + + const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors(); + // Jump to successors[0] if value == lower_bound. + __ B(eq, codegen_->GetLabelOf(successors[0])); + int32_t last_index = 0; + for (; num_entries - last_index > 2; last_index += 2) { + __ Adds(temp_reg, temp_reg, -2); + // Jump to successors[last_index + 1] if value < case_value[last_index + 2]. + __ B(lo, codegen_->GetLabelOf(successors[last_index + 1])); + // Jump to successors[last_index + 2] if value == case_value[last_index + 2]. + __ B(eq, codegen_->GetLabelOf(successors[last_index + 2])); + } + if (num_entries - last_index == 2) { + // The last missing case_value. + __ Cmp(temp_reg, 1); + __ B(eq, codegen_->GetLabelOf(successors[last_index + 1])); + } + + // And the default for any other value. + if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) { + __ B(codegen_->GetLabelOf(default_block)); + } + } else { + // Create a table lookup. + vixl32::Register table_base = RegisterFrom(locations->GetTemp(0)); + + JumpTableARMVIXL* jump_table = codegen_->CreateJumpTable(switch_instr); + + // Remove the bias. + vixl32::Register key_reg; + if (lower_bound != 0) { + key_reg = RegisterFrom(locations->GetTemp(1)); + __ Sub(key_reg, value_reg, lower_bound); + } else { + key_reg = value_reg; + } + + // Check whether the value is in the table, jump to default block if not. + __ Cmp(key_reg, num_entries - 1); + __ B(hi, codegen_->GetLabelOf(default_block)); + + UseScratchRegisterScope temps(GetAssembler()->GetVIXLAssembler()); + vixl32::Register jump_offset = temps.Acquire(); + + // Load jump offset from the table. + __ Adr(table_base, jump_table->GetTableStartLabel()); + __ Ldr(jump_offset, MemOperand(table_base, key_reg, vixl32::LSL, 2)); + + // Jump to target block by branching to table_base(pc related) + offset. + vixl32::Register target_address = table_base; + __ Add(target_address, table_base, jump_offset); + __ Bx(target_address); + } +} + // Copy the result of a call into the given target. void CodeGeneratorARMVIXL::MoveFromReturnRegister(Location trg, Primitive::Type type) { if (!trg.IsValid()) { @@ -5687,6 +5983,17 @@ void CodeGeneratorARMVIXL::MoveFromReturnRegister(Location trg, Primitive::Type } } +void LocationsBuilderARMVIXL::VisitClassTableGet( + HClassTableGet* instruction ATTRIBUTE_UNUSED) { + TODO_VIXL32(FATAL); +} + +void InstructionCodeGeneratorARMVIXL::VisitClassTableGet( + HClassTableGet* instruction ATTRIBUTE_UNUSED) { + TODO_VIXL32(FATAL); +} + + #undef __ #undef QUICK_ENTRY_POINT #undef TODO_VIXL32 diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h index 2ccc30ff5f..ccd866c367 100644 --- a/compiler/optimizing/code_generator_arm_vixl.h +++ b/compiler/optimizing/code_generator_arm_vixl.h @@ -114,7 +114,9 @@ class LoadClassSlowPathARMVIXL; M(BelowOrEqual) \ M(BooleanNot) \ M(BoundsCheck) \ + M(BoundType) \ M(CheckCast) \ + M(ClassTableGet) \ M(ClearException) \ M(ClinitCheck) \ M(Compare) \ @@ -145,7 +147,9 @@ class LoadClassSlowPathARMVIXL; M(LoadString) \ M(LongConstant) \ M(MemoryBarrier) \ + M(MonitorOperation) \ M(Mul) \ + M(NativeDebugInfo) \ M(Neg) \ M(NewArray) \ M(NewInstance) \ @@ -154,9 +158,11 @@ class LoadClassSlowPathARMVIXL; M(NullCheck) \ M(NullConstant) \ M(Or) \ + M(PackedSwitch) \ M(ParallelMove) \ M(ParameterValue) \ M(Phi) \ + M(Rem) \ M(Return) \ M(ReturnVoid) \ M(Ror) \ @@ -181,17 +187,27 @@ class LoadClassSlowPathARMVIXL; #define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M) \ M(ArmDexCacheArraysBase) \ M(BitwiseNegatedRight) \ - M(BoundType) \ - M(ClassTableGet) \ M(IntermediateAddress) \ - M(MonitorOperation) \ M(MultiplyAccumulate) \ - M(NativeDebugInfo) \ - M(PackedSwitch) \ - M(Rem) \ class CodeGeneratorARMVIXL; +class JumpTableARMVIXL : public DeletableArenaObject<kArenaAllocSwitchTable> { + public: + explicit JumpTableARMVIXL(HPackedSwitch* switch_instr) + : switch_instr_(switch_instr), table_start_() {} + + vixl::aarch32::Label* GetTableStartLabel() { return &table_start_; } + + void EmitTable(CodeGeneratorARMVIXL* codegen); + + private: + HPackedSwitch* const switch_instr_; + vixl::aarch32::Label table_start_; + + DISALLOW_COPY_AND_ASSIGN(JumpTableARMVIXL); +}; + class InvokeRuntimeCallingConventionARMVIXL : public CallingConvention<vixl::aarch32::Register, vixl::aarch32::SRegister> { public: @@ -488,10 +504,16 @@ class CodeGeneratorARMVIXL : public CodeGenerator { return block_entry_label->GetLocation(); } + JumpTableARMVIXL* CreateJumpTable(HPackedSwitch* switch_instr) { + jump_tables_.emplace_back(new (GetGraph()->GetArena()) JumpTableARMVIXL(switch_instr)); + return jump_tables_.back().get(); + } + HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; } HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; } + void EmitJumpTables(); void GenerateMemoryBarrier(MemBarrierKind kind); void Finalize(CodeAllocator* allocator) OVERRIDE; void SetupBlockedRegisters() const OVERRIDE; @@ -673,6 +695,7 @@ class CodeGeneratorARMVIXL : public CodeGenerator { ArenaDeque<vixl::aarch32::Label> block_labels_; // Indexed by block id. vixl::aarch32::Label frame_entry_label_; + ArenaVector<std::unique_ptr<JumpTableARMVIXL>> jump_tables_; LocationsBuilderARMVIXL location_builder_; InstructionCodeGeneratorARMVIXL instruction_visitor_; ParallelMoveResolverARMVIXL move_resolver_; diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index f169eb00f3..573bb507f2 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -378,14 +378,6 @@ class TypeCheckSlowPathMIPS : public SlowPathCodeMIPS { void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { LocationSummary* locations = instruction_->GetLocations(); - Location arg0, arg1; - if (instruction_->IsInstanceOf()) { - arg0 = locations->InAt(1); - arg1 = locations->Out(); - } else { - arg0 = locations->InAt(0); - arg1 = locations->InAt(1); - } uint32_t dex_pc = instruction_->GetDexPc(); DCHECK(instruction_->IsCheckCast() || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); @@ -397,15 +389,15 @@ class TypeCheckSlowPathMIPS : public SlowPathCodeMIPS { // We're moving two locations to locations that could overlap, so we need a parallel // move resolver. InvokeRuntimeCallingConvention calling_convention; - codegen->EmitParallelMoves(arg0, + codegen->EmitParallelMoves(locations->InAt(0), Location::RegisterLocation(calling_convention.GetRegisterAt(0)), Primitive::kPrimNot, - arg1, + locations->InAt(1), Location::RegisterLocation(calling_convention.GetRegisterAt(1)), Primitive::kPrimNot); if (instruction_->IsInstanceOf()) { mips_codegen->InvokeRuntime(kQuickInstanceofNonTrivial, instruction_, dex_pc, this); - CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Class*, mirror::Class*>(); + CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>(); Primitive::Type ret_type = instruction_->GetType(); Location ret_loc = calling_convention.GetReturnLocation(ret_type); mips_codegen->MoveLocation(locations->Out(), ret_loc, ret_type); diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index 7598740d3c..1a54935a25 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -322,14 +322,6 @@ class TypeCheckSlowPathMIPS64 : public SlowPathCodeMIPS64 { void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { LocationSummary* locations = instruction_->GetLocations(); - Location arg0, arg1; - if (instruction_->IsInstanceOf()) { - arg0 = locations->InAt(1); - arg1 = locations->Out(); - } else { - arg0 = locations->InAt(0); - arg1 = locations->InAt(1); - } uint32_t dex_pc = instruction_->GetDexPc(); DCHECK(instruction_->IsCheckCast() @@ -342,16 +334,15 @@ class TypeCheckSlowPathMIPS64 : public SlowPathCodeMIPS64 { // We're moving two locations to locations that could overlap, so we need a parallel // move resolver. InvokeRuntimeCallingConvention calling_convention; - codegen->EmitParallelMoves(arg0, + codegen->EmitParallelMoves(locations->InAt(0), Location::RegisterLocation(calling_convention.GetRegisterAt(0)), Primitive::kPrimNot, - arg1, + locations->InAt(1), Location::RegisterLocation(calling_convention.GetRegisterAt(1)), Primitive::kPrimNot); if (instruction_->IsInstanceOf()) { mips64_codegen->InvokeRuntime(kQuickInstanceofNonTrivial, instruction_, dex_pc, this); - CheckEntrypointTypes< - kQuickInstanceofNonTrivial, size_t, mirror::Class*, mirror::Class*>(); + CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>(); Primitive::Type ret_type = instruction_->GetType(); Location ret_loc = calling_convention.GetReturnLocation(ret_type); mips64_codegen->MoveLocation(locations->Out(), ret_loc, ret_type); diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 2a9e21d1e1..2451b8d247 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -312,14 +312,6 @@ class TypeCheckSlowPathX86 : public SlowPathCode { void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { LocationSummary* locations = instruction_->GetLocations(); - Location arg0, arg1; - if (instruction_->IsInstanceOf()) { - arg0 = locations->InAt(1); - arg1 = locations->Out(); - } else { - arg0 = locations->InAt(0); - arg1 = locations->InAt(1); - } DCHECK(instruction_->IsCheckCast() || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); @@ -333,10 +325,10 @@ class TypeCheckSlowPathX86 : public SlowPathCode { // We're moving two locations to locations that could overlap, so we need a parallel // move resolver. InvokeRuntimeCallingConvention calling_convention; - x86_codegen->EmitParallelMoves(arg0, + x86_codegen->EmitParallelMoves(locations->InAt(0), Location::RegisterLocation(calling_convention.GetRegisterAt(0)), Primitive::kPrimNot, - arg1, + locations->InAt(1), Location::RegisterLocation(calling_convention.GetRegisterAt(1)), Primitive::kPrimNot); if (instruction_->IsInstanceOf()) { @@ -344,7 +336,7 @@ class TypeCheckSlowPathX86 : public SlowPathCode { instruction_, instruction_->GetDexPc(), this); - CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Class*, mirror::Class*>(); + CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>(); } else { DCHECK(instruction_->IsCheckCast()); x86_codegen->InvokeRuntime(kQuickCheckInstanceOf, @@ -6422,15 +6414,14 @@ void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) { __ j(kEqual, &zero); } - // /* HeapReference<Class> */ out = obj->klass_ - GenerateReferenceLoadTwoRegisters(instruction, - out_loc, - obj_loc, - class_offset, - kCompilerReadBarrierOption); - switch (type_check_kind) { case TypeCheckKind::kExactCheck: { + // /* HeapReference<Class> */ out = obj->klass_ + GenerateReferenceLoadTwoRegisters(instruction, + out_loc, + obj_loc, + class_offset, + kCompilerReadBarrierOption); if (cls.IsRegister()) { __ cmpl(out, cls.AsRegister<Register>()); } else { @@ -6446,6 +6437,12 @@ void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) { } case TypeCheckKind::kAbstractClassCheck: { + // /* HeapReference<Class> */ out = obj->klass_ + GenerateReferenceLoadTwoRegisters(instruction, + out_loc, + obj_loc, + class_offset, + kCompilerReadBarrierOption); // If the class is abstract, we eagerly fetch the super class of the // object to avoid doing a comparison we know will fail. NearLabel loop; @@ -6474,6 +6471,12 @@ void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) { } case TypeCheckKind::kClassHierarchyCheck: { + // /* HeapReference<Class> */ out = obj->klass_ + GenerateReferenceLoadTwoRegisters(instruction, + out_loc, + obj_loc, + class_offset, + kCompilerReadBarrierOption); // Walk over the class hierarchy to find a match. NearLabel loop, success; __ Bind(&loop); @@ -6503,6 +6506,12 @@ void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) { } case TypeCheckKind::kArrayObjectCheck: { + // /* HeapReference<Class> */ out = obj->klass_ + GenerateReferenceLoadTwoRegisters(instruction, + out_loc, + obj_loc, + class_offset, + kCompilerReadBarrierOption); // Do an exact check. NearLabel exact_check; if (cls.IsRegister()) { @@ -6531,6 +6540,13 @@ void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) { } case TypeCheckKind::kArrayCheck: { + // No read barrier since the slow path will retry upon failure. + // /* HeapReference<Class> */ out = obj->klass_ + GenerateReferenceLoadTwoRegisters(instruction, + out_loc, + obj_loc, + class_offset, + kWithoutReadBarrier); if (cls.IsRegister()) { __ cmpl(out, cls.AsRegister<Register>()); } else { @@ -6833,10 +6849,9 @@ void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) { temp_loc, iftable_offset, kWithoutReadBarrier); - NearLabel is_null; // Null iftable means it is empty. __ testl(temp, temp); - __ j(kZero, &is_null); + __ j(kZero, type_check_slow_path->GetEntryLabel()); // Loop through the iftable and check if any class matches. __ movl(maybe_temp2_loc.AsRegister<Register>(), Address(temp, array_length_offset)); @@ -6849,7 +6864,6 @@ void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) { __ addl(temp, Immediate(2 * kHeapReferenceSize)); __ subl(maybe_temp2_loc.AsRegister<Register>(), Immediate(2)); __ j(kNotZero, &start_loop); - __ Bind(&is_null); } __ jmp(type_check_slow_path->GetEntryLabel()); diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index cb89e50dbb..2425a4c3cb 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -332,14 +332,6 @@ class TypeCheckSlowPathX86_64 : public SlowPathCode { void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { LocationSummary* locations = instruction_->GetLocations(); - Location arg0, arg1; - if (instruction_->IsInstanceOf()) { - arg0 = locations->InAt(1); - arg1 = locations->Out(); - } else { - arg0 = locations->InAt(0); - arg1 = locations->InAt(1); - } uint32_t dex_pc = instruction_->GetDexPc(); DCHECK(instruction_->IsCheckCast() || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); @@ -354,15 +346,15 @@ class TypeCheckSlowPathX86_64 : public SlowPathCode { // We're moving two locations to locations that could overlap, so we need a parallel // move resolver. InvokeRuntimeCallingConvention calling_convention; - codegen->EmitParallelMoves(arg0, + codegen->EmitParallelMoves(locations->InAt(0), Location::RegisterLocation(calling_convention.GetRegisterAt(0)), Primitive::kPrimNot, - arg1, + locations->InAt(1), Location::RegisterLocation(calling_convention.GetRegisterAt(1)), Primitive::kPrimNot); if (instruction_->IsInstanceOf()) { x86_64_codegen->InvokeRuntime(kQuickInstanceofNonTrivial, instruction_, dex_pc, this); - CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Class*, mirror::Class*>(); + CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>(); } else { DCHECK(instruction_->IsCheckCast()); x86_64_codegen->InvokeRuntime(kQuickCheckInstanceOf, instruction_, dex_pc, this); @@ -5826,15 +5818,14 @@ void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) { __ j(kEqual, &zero); } - // /* HeapReference<Class> */ out = obj->klass_ - GenerateReferenceLoadTwoRegisters(instruction, - out_loc, - obj_loc, - class_offset, - kCompilerReadBarrierOption); - switch (type_check_kind) { case TypeCheckKind::kExactCheck: { + // /* HeapReference<Class> */ out = obj->klass_ + GenerateReferenceLoadTwoRegisters(instruction, + out_loc, + obj_loc, + class_offset, + kCompilerReadBarrierOption); if (cls.IsRegister()) { __ cmpl(out, cls.AsRegister<CpuRegister>()); } else { @@ -5855,6 +5846,12 @@ void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) { } case TypeCheckKind::kAbstractClassCheck: { + // /* HeapReference<Class> */ out = obj->klass_ + GenerateReferenceLoadTwoRegisters(instruction, + out_loc, + obj_loc, + class_offset, + kCompilerReadBarrierOption); // If the class is abstract, we eagerly fetch the super class of the // object to avoid doing a comparison we know will fail. NearLabel loop, success; @@ -5883,6 +5880,12 @@ void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) { } case TypeCheckKind::kClassHierarchyCheck: { + // /* HeapReference<Class> */ out = obj->klass_ + GenerateReferenceLoadTwoRegisters(instruction, + out_loc, + obj_loc, + class_offset, + kCompilerReadBarrierOption); // Walk over the class hierarchy to find a match. NearLabel loop, success; __ Bind(&loop); @@ -5912,6 +5915,12 @@ void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) { } case TypeCheckKind::kArrayObjectCheck: { + // /* HeapReference<Class> */ out = obj->klass_ + GenerateReferenceLoadTwoRegisters(instruction, + out_loc, + obj_loc, + class_offset, + kCompilerReadBarrierOption); // Do an exact check. NearLabel exact_check; if (cls.IsRegister()) { @@ -5940,6 +5949,13 @@ void InstructionCodeGeneratorX86_64::VisitInstanceOf(HInstanceOf* instruction) { } case TypeCheckKind::kArrayCheck: { + // No read barrier since the slow path will retry upon failure. + // /* HeapReference<Class> */ out = obj->klass_ + GenerateReferenceLoadTwoRegisters(instruction, + out_loc, + obj_loc, + class_offset, + kWithoutReadBarrier); if (cls.IsRegister()) { __ cmpl(out, cls.AsRegister<CpuRegister>()); } else { @@ -6243,10 +6259,9 @@ void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) { temp_loc, iftable_offset, kWithoutReadBarrier); - NearLabel is_null; // Null iftable means it is empty. __ testl(temp, temp); - __ j(kZero, &is_null); + __ j(kZero, type_check_slow_path->GetEntryLabel()); // Loop through the iftable and check if any class matches. __ movl(maybe_temp2_loc.AsRegister<CpuRegister>(), Address(temp, array_length_offset)); @@ -6259,7 +6274,6 @@ void InstructionCodeGeneratorX86_64::VisitCheckCast(HCheckCast* instruction) { __ addl(temp, Immediate(2 * kHeapReferenceSize)); __ subl(maybe_temp2_loc.AsRegister<CpuRegister>(), Immediate(2)); __ j(kNotZero, &start_loop); - __ Bind(&is_null); } __ jmp(type_check_slow_path->GetEntryLabel()); break; |