diff options
author | 2016-10-25 18:17:23 +0100 | |
---|---|---|
committer | 2016-11-02 16:49:30 +0000 | |
commit | e28d9ae520082caece9dc90c87b69f864bf886e5 (patch) | |
tree | 34e0fb6cf8081cc298a4db8e69284c5bb93416c7 | |
parent | 77a0e4541a29c26dba21ed8c1ed1c29ef8d0ce4c (diff) |
ARM: VIXL32: Implement the functionality needed by intrinsics.
This patch passes:
* 004-UnsafeTest
Test: ART_USE_VIXL_ARM_BACKEND=true m test-art-host
Test: ART_USE_VIXL_ARM_BACKEND=true m test-art-target
Change-Id: I7a3cd410411ef3a520d419734a835090097b2aee
-rw-r--r-- | compiler/optimizing/code_generator_arm_vixl.cc | 288 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm_vixl.h | 80 | ||||
-rw-r--r-- | compiler/optimizing/common_arm.h | 10 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm_vixl.cc | 6 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm_vixl.h | 2 | ||||
-rw-r--r-- | test/Android.arm_vixl.mk | 2 |
6 files changed, 370 insertions, 18 deletions
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index cc40522731..c00ee553ef 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -62,6 +62,7 @@ static bool ExpectedPairLayout(Location location) { return ((location.low() & 1) == 0) && (location.low() + 1 == location.high()); } +static constexpr int kCurrentMethodStackOffset = 0; static constexpr size_t kArmInstrMaxSizeInBytes = 4u; #ifdef __ @@ -434,6 +435,59 @@ class LoadClassSlowPathARMVIXL : public SlowPathCodeARMVIXL { DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARMVIXL); }; +class TypeCheckSlowPathARMVIXL : public SlowPathCodeARMVIXL { + public: + TypeCheckSlowPathARMVIXL(HInstruction* instruction, bool is_fatal) + : SlowPathCodeARMVIXL(instruction), is_fatal_(is_fatal) {} + + void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { + LocationSummary* locations = instruction_->GetLocations(); + Location object_class = instruction_->IsCheckCast() ? locations->GetTemp(0) + : locations->Out(); + DCHECK(instruction_->IsCheckCast() + || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); + + CodeGeneratorARMVIXL* arm_codegen = down_cast<CodeGeneratorARMVIXL*>(codegen); + __ Bind(GetEntryLabel()); + + if (!is_fatal_) { + TODO_VIXL32(FATAL); + } + + // We're moving two locations to locations that could overlap, so we need a parallel + // move resolver. + InvokeRuntimeCallingConventionARMVIXL calling_convention; + codegen->EmitParallelMoves( + locations->InAt(1), + LocationFrom(calling_convention.GetRegisterAt(0)), + Primitive::kPrimNot, + object_class, + LocationFrom(calling_convention.GetRegisterAt(1)), + Primitive::kPrimNot); + + if (instruction_->IsInstanceOf()) { + TODO_VIXL32(FATAL); + } else { + DCHECK(instruction_->IsCheckCast()); + arm_codegen->InvokeRuntime(kQuickCheckCast, instruction_, instruction_->GetDexPc(), this); + CheckEntrypointTypes<kQuickCheckCast, void, const mirror::Class*, const mirror::Class*>(); + } + + if (!is_fatal_) { + TODO_VIXL32(FATAL); + } + } + + const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathARMVIXL"; } + + bool IsFatal() const OVERRIDE { return is_fatal_; } + + private: + const bool is_fatal_; + + DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARMVIXL); +}; + class DeoptimizationSlowPathARMVIXL : public SlowPathCodeARMVIXL { public: explicit DeoptimizationSlowPathARMVIXL(HDeoptimize* instruction) @@ -567,6 +621,11 @@ static uint32_t ComputeSRegisterListMask(const SRegisterList& regs) { return mask; } +size_t CodeGeneratorARMVIXL::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) { + GetAssembler()->LoadSFromOffset(vixl32::SRegister(reg_id), sp, stack_index); + return kArmWordSize; +} + #undef __ CodeGeneratorARMVIXL::CodeGeneratorARMVIXL(HGraph* graph, @@ -1418,6 +1477,8 @@ void LocationsBuilderARMVIXL::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* i // TODO(VIXL): TryDispatch HandleInvoke(invoke); + + // TODO(VIXL): invoke->HasPcRelativeDexCache() } void InstructionCodeGeneratorARMVIXL::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { @@ -1507,6 +1568,8 @@ void InstructionCodeGeneratorARMVIXL::VisitNeg(HNeg* neg) { case Primitive::kPrimFloat: case Primitive::kPrimDouble: + // TODO(VIXL): Consider introducing an InputVRegister() + // helper function (equivalent to InputRegister()). __ Vneg(OutputVRegister(neg), InputVRegisterAt(neg, 0)); break; @@ -2325,7 +2388,12 @@ void LocationsBuilderARMVIXL::VisitDiv(HDiv* div) { break; } case Primitive::kPrimLong: { - TODO_VIXL32(FATAL); + 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))); + locations->SetOut(LocationFrom(r0, r1)); break; } case Primitive::kPrimFloat: @@ -2342,6 +2410,7 @@ void LocationsBuilderARMVIXL::VisitDiv(HDiv* div) { } void InstructionCodeGeneratorARMVIXL::VisitDiv(HDiv* div) { + Location lhs = div->GetLocations()->InAt(0); Location rhs = div->GetLocations()->InAt(1); switch (div->GetResultType()) { @@ -2357,7 +2426,16 @@ void InstructionCodeGeneratorARMVIXL::VisitDiv(HDiv* div) { } case Primitive::kPrimLong: { - TODO_VIXL32(FATAL); + InvokeRuntimeCallingConventionARMVIXL calling_convention; + DCHECK(calling_convention.GetRegisterAt(0).Is(LowRegisterFrom(lhs))); + DCHECK(calling_convention.GetRegisterAt(1).Is(HighRegisterFrom(lhs))); + DCHECK(calling_convention.GetRegisterAt(2).Is(LowRegisterFrom(rhs))); + DCHECK(calling_convention.GetRegisterAt(3).Is(HighRegisterFrom(rhs))); + DCHECK(LowRegisterFrom(div->GetLocations()->Out()).Is(r0)); + DCHECK(HighRegisterFrom(div->GetLocations()->Out()).Is(r1)); + + codegen_->InvokeRuntime(kQuickLdiv, div, div->GetDexPc()); + CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>(); break; } @@ -3663,7 +3741,7 @@ void LocationsBuilderARMVIXL::VisitArrayGet(HArrayGet* instruction) { // Also need for String compression feature. if ((object_array_get_with_read_barrier && kUseBakerReadBarrier) || (mirror::kUseStringCompression && instruction->IsStringCharAt())) { - TODO_VIXL32(FATAL); + locations->AddTemp(Location::RequiresRegister()); } } @@ -3692,7 +3770,24 @@ void InstructionCodeGeneratorARMVIXL::VisitArrayGet(HArrayGet* instruction) { if (index.IsConstant()) { int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue(); if (maybe_compressed_char_at) { - TODO_VIXL32(FATAL); + vixl32::Register length = temps.Acquire(); + vixl32::Label uncompressed_load, done; + uint32_t count_offset = mirror::String::CountOffset().Uint32Value(); + GetAssembler()->LoadFromOffset(kLoadWord, length, obj, count_offset); + codegen_->MaybeRecordImplicitNullCheck(instruction); + __ Cmp(length, 0); + __ B(ge, &uncompressed_load); + GetAssembler()->LoadFromOffset(kLoadUnsignedByte, + RegisterFrom(out_loc), + obj, + data_offset + const_index); + __ B(&done); + __ Bind(&uncompressed_load); + GetAssembler()->LoadFromOffset(GetLoadOperandType(Primitive::kPrimChar), + RegisterFrom(out_loc), + obj, + data_offset + (const_index << 1)); + __ Bind(&done); } else { uint32_t full_offset = data_offset + (const_index << Primitive::ComponentSizeShift(type)); @@ -3708,7 +3803,18 @@ void InstructionCodeGeneratorARMVIXL::VisitArrayGet(HArrayGet* instruction) { __ Add(temp, obj, data_offset); } if (maybe_compressed_char_at) { - TODO_VIXL32(FATAL); + vixl32::Label uncompressed_load, done; + uint32_t count_offset = mirror::String::CountOffset().Uint32Value(); + vixl32::Register length = RegisterFrom(locations->GetTemp(0)); + GetAssembler()->LoadFromOffset(kLoadWord, length, obj, count_offset); + codegen_->MaybeRecordImplicitNullCheck(instruction); + __ Cmp(length, 0); + __ B(ge, &uncompressed_load); + __ Ldrb(RegisterFrom(out_loc), MemOperand(temp, RegisterFrom(index), vixl32::LSL, 0)); + __ B(&done); + __ Bind(&uncompressed_load); + __ Ldrh(RegisterFrom(out_loc), MemOperand(temp, RegisterFrom(index), vixl32::LSL, 1)); + __ Bind(&done); } else { codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, RegisterFrom(index)); } @@ -4080,7 +4186,10 @@ void InstructionCodeGeneratorARMVIXL::VisitArrayLength(HArrayLength* instruction vixl32::Register out = OutputRegister(instruction); GetAssembler()->LoadFromOffset(kLoadWord, out, obj, offset); codegen_->MaybeRecordImplicitNullCheck(instruction); - // TODO(VIXL): https://android-review.googlesource.com/#/c/272625/ + // Mask out compression flag from String's array length. + if (mirror::kUseStringCompression && instruction->IsStringLength()) { + __ Bic(out, out, 1u << 31); + } } void LocationsBuilderARMVIXL::VisitBoundsCheck(HBoundsCheck* instruction) { @@ -4376,7 +4485,12 @@ void ParallelMoveResolverARMVIXL::EmitSwap(size_t index) { GetAssembler()->LoadFromOffset(kLoadWordPair, low_reg, sp, mem); GetAssembler()->StoreDToOffset(temp, sp, mem); } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) { - TODO_VIXL32(FATAL); + vixl32::DRegister first = DRegisterFrom(source); + vixl32::DRegister second = DRegisterFrom(destination); + vixl32::DRegister temp = temps.AcquireD(); + __ Vmov(temp, first); + __ Vmov(first, second); + __ Vmov(second, temp); } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) { TODO_VIXL32(FATAL); } else if (source.IsFpuRegister() || destination.IsFpuRegister()) { @@ -4609,6 +4723,115 @@ void InstructionCodeGeneratorARMVIXL::VisitThrow(HThrow* instruction) { CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>(); } +static bool TypeCheckNeedsATemporary(TypeCheckKind type_check_kind) { + return kEmitCompilerReadBarrier && + (kUseBakerReadBarrier || + type_check_kind == TypeCheckKind::kAbstractClassCheck || + type_check_kind == TypeCheckKind::kClassHierarchyCheck || + type_check_kind == TypeCheckKind::kArrayObjectCheck); +} + +void LocationsBuilderARMVIXL::VisitCheckCast(HCheckCast* instruction) { + LocationSummary::CallKind call_kind = LocationSummary::kNoCall; + bool throws_into_catch = instruction->CanThrowIntoCatchBlock(); + + TypeCheckKind type_check_kind = instruction->GetTypeCheckKind(); + switch (type_check_kind) { + case TypeCheckKind::kExactCheck: + case TypeCheckKind::kAbstractClassCheck: + case TypeCheckKind::kClassHierarchyCheck: + case TypeCheckKind::kArrayObjectCheck: + call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ? + LocationSummary::kCallOnSlowPath : + LocationSummary::kNoCall; // In fact, call on a fatal (non-returning) slow path. + break; + case TypeCheckKind::kArrayCheck: + case TypeCheckKind::kUnresolvedCheck: + case TypeCheckKind::kInterfaceCheck: + call_kind = LocationSummary::kCallOnSlowPath; + break; + } + + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + // Note that TypeCheckSlowPathARM uses this "temp" register too. + locations->AddTemp(Location::RequiresRegister()); + // When read barriers are enabled, we need an additional temporary + // register for some cases. + if (TypeCheckNeedsATemporary(type_check_kind)) { + locations->AddTemp(Location::RequiresRegister()); + } +} + +void InstructionCodeGeneratorARMVIXL::VisitCheckCast(HCheckCast* instruction) { + TypeCheckKind type_check_kind = instruction->GetTypeCheckKind(); + LocationSummary* locations = instruction->GetLocations(); + Location obj_loc = locations->InAt(0); + vixl32::Register obj = InputRegisterAt(instruction, 0); + vixl32::Register cls = InputRegisterAt(instruction, 1); + Location temp_loc = locations->GetTemp(0); + vixl32::Register temp = RegisterFrom(temp_loc); + Location maybe_temp2_loc = TypeCheckNeedsATemporary(type_check_kind) ? + locations->GetTemp(1) : + Location::NoLocation(); + uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); + + bool is_type_check_slow_path_fatal = + (type_check_kind == TypeCheckKind::kExactCheck || + type_check_kind == TypeCheckKind::kAbstractClassCheck || + type_check_kind == TypeCheckKind::kClassHierarchyCheck || + type_check_kind == TypeCheckKind::kArrayObjectCheck) && + !instruction->CanThrowIntoCatchBlock(); + SlowPathCodeARMVIXL* type_check_slow_path = + new (GetGraph()->GetArena()) TypeCheckSlowPathARMVIXL(instruction, + is_type_check_slow_path_fatal); + codegen_->AddSlowPath(type_check_slow_path); + + vixl32::Label done; + // Avoid null check if we know obj is not null. + if (instruction->MustDoNullCheck()) { + __ Cbz(obj, &done); + } + + // /* HeapReference<Class> */ temp = obj->klass_ + GenerateReferenceLoadTwoRegisters(instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc); + + switch (type_check_kind) { + case TypeCheckKind::kExactCheck: + case TypeCheckKind::kArrayCheck: { + __ Cmp(temp, cls); + // Jump to slow path for throwing the exception or doing a + // more involved array check. + __ B(ne, type_check_slow_path->GetEntryLabel()); + break; + } + + case TypeCheckKind::kAbstractClassCheck: { + TODO_VIXL32(FATAL); + break; + } + + case TypeCheckKind::kClassHierarchyCheck: { + TODO_VIXL32(FATAL); + break; + } + + case TypeCheckKind::kArrayObjectCheck: { + TODO_VIXL32(FATAL); + break; + } + + case TypeCheckKind::kUnresolvedCheck: + case TypeCheckKind::kInterfaceCheck: + TODO_VIXL32(FATAL); + break; + } + __ Bind(&done); + + __ Bind(type_check_slow_path->GetExitLabel()); +} + void LocationsBuilderARMVIXL::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); } @@ -4780,6 +5003,24 @@ void InstructionCodeGeneratorARMVIXL::HandleBitwiseOperation(HBinaryOperation* i } } +void InstructionCodeGeneratorARMVIXL::GenerateReferenceLoadTwoRegisters( + HInstruction* instruction ATTRIBUTE_UNUSED, + Location out, + Location obj, + uint32_t offset, + Location maybe_temp ATTRIBUTE_UNUSED) { + vixl32::Register out_reg = RegisterFrom(out); + vixl32::Register obj_reg = RegisterFrom(obj); + if (kEmitCompilerReadBarrier) { + TODO_VIXL32(FATAL); + } else { + // Plain load with no read barrier. + // /* HeapReference<Object> */ out = *(obj + offset) + GetAssembler()->LoadFromOffset(kLoadWord, out_reg, obj_reg, offset); + GetAssembler()->MaybeUnpoisonHeapReference(out_reg); + } +} + void InstructionCodeGeneratorARMVIXL::GenerateGcRootFieldLoad( HInstruction* instruction ATTRIBUTE_UNUSED, Location root, @@ -4871,7 +5112,10 @@ void CodeGeneratorARMVIXL::GenerateStaticOrDirectCall( if (current_method.IsRegister()) { method_reg = RegisterFrom(current_method); } else { - TODO_VIXL32(FATAL); + DCHECK(invoke->GetLocations()->Intrinsified()); + DCHECK(!current_method.IsValid()); + method_reg = temp_reg; + GetAssembler()->LoadFromOffset(kLoadWord, temp_reg, sp, kCurrentMethodStackOffset); } // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_; GetAssembler()->LoadFromOffset( @@ -4942,9 +5186,31 @@ void CodeGeneratorARMVIXL::GenerateVirtualCall(HInvokeVirtual* invoke, Location } // Copy the result of a call into the given target. -void CodeGeneratorARMVIXL::MoveFromReturnRegister(Location trg ATTRIBUTE_UNUSED, - Primitive::Type type ATTRIBUTE_UNUSED) { - TODO_VIXL32(FATAL); +void CodeGeneratorARMVIXL::MoveFromReturnRegister(Location trg, Primitive::Type type) { + if (!trg.IsValid()) { + DCHECK_EQ(type, Primitive::kPrimVoid); + return; + } + + DCHECK_NE(type, Primitive::kPrimVoid); + + Location return_loc = InvokeDexCallingConventionVisitorARM().GetReturnLocation(type); + if (return_loc.Equals(trg)) { + return; + } + + // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged + // with the last branch. + if (type == Primitive::kPrimLong) { + TODO_VIXL32(FATAL); + } else if (type == Primitive::kPrimDouble) { + TODO_VIXL32(FATAL); + } else { + // Let the parallel move resolver take care of all of this. + HParallelMove parallel_move(GetGraph()->GetArena()); + parallel_move.AddMove(return_loc, trg, type, nullptr); + GetMoveResolver()->EmitNativeCode(¶llel_move); + } } #undef __ diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h index df7d46782d..c583a44924 100644 --- a/compiler/optimizing/code_generator_arm_vixl.h +++ b/compiler/optimizing/code_generator_arm_vixl.h @@ -113,6 +113,7 @@ class LoadClassSlowPathARMVIXL; M(BelowOrEqual) \ M(BooleanNot) \ M(BoundsCheck) \ + M(CheckCast) \ M(ClearException) \ M(ClinitCheck) \ M(Compare) \ @@ -171,7 +172,6 @@ class LoadClassSlowPathARMVIXL; // TODO: Remove once the VIXL32 backend is implemented completely. #define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M) \ M(BoundType) \ - M(CheckCast) \ M(ClassTableGet) \ M(InstanceOf) \ M(InvokeInterface) \ @@ -344,6 +344,22 @@ class InstructionCodeGeneratorARMVIXL : public InstructionCodeGenerator { bool value_can_be_null); void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); + // Generate a heap reference load using two different registers + // `out` and `obj`: + // + // out <- *(obj + offset) + // + // while honoring heap poisoning and/or read barriers (if any). + // + // Location `maybe_temp` is used when generating a Baker's (fast + // path) read barrier and shall be a register in that case; it may + // be an invalid location otherwise. + void GenerateReferenceLoadTwoRegisters(HInstruction* instruction, + Location out, + Location obj, + uint32_t offset, + Location maybe_temp); + // Generate a GC root reference load: // // root <- *(obj + offset) @@ -473,11 +489,7 @@ class CodeGeneratorARMVIXL : public CodeGenerator { return 0; } - size_t RestoreFloatingPointRegister(size_t stack_index ATTRIBUTE_UNUSED, - uint32_t reg_id ATTRIBUTE_UNUSED) OVERRIDE { - UNIMPLEMENTED(INFO) << "TODO: RestoreFloatingPointRegister"; - return 0; - } + size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; bool NeedsTwoRegisters(Primitive::Type type) const OVERRIDE { return type == Primitive::kPrimDouble || type == Primitive::kPrimLong; @@ -513,6 +525,62 @@ class CodeGeneratorARMVIXL : public CodeGenerator { vixl::aarch32::Register value, bool can_be_null); + // Fast path implementation of ReadBarrier::Barrier for a heap + // reference field load when Baker's read barriers are used. + void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction, + Location ref, + vixl::aarch32::Register obj, + uint32_t offset, + Location temp, + bool needs_null_check); + + // Factored implementation, used by GenerateFieldLoadWithBakerReadBarrier, + // GenerateArrayLoadWithBakerReadBarrier and some intrinsics. + // + // Load the object reference located at the address + // `obj + offset + (index << scale_factor)`, held by object `obj`, into + // `ref`, and mark it if needed. + // + // If `always_update_field` is true, the value of the reference is + // atomically updated in the holder (`obj`). This operation + // requires an extra temporary register, which must be provided as a + // non-null pointer (`temp2`). + void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction, + Location ref, + vixl::aarch32::Register obj, + uint32_t offset, + Location index, + ScaleFactor scale_factor, + Location temp, + bool needs_null_check, + bool always_update_field = false, + vixl::aarch32::Register* temp2 = nullptr); + + // Generate a read barrier for a heap reference within `instruction` + // using a slow path. + // + // A read barrier for an object reference read from the heap is + // implemented as a call to the artReadBarrierSlow runtime entry + // point, which is passed the values in locations `ref`, `obj`, and + // `offset`: + // + // mirror::Object* artReadBarrierSlow(mirror::Object* ref, + // mirror::Object* obj, + // uint32_t offset); + // + // The `out` location contains the value returned by + // artReadBarrierSlow. + // + // When `index` is provided (i.e. for array accesses), the offset + // value passed to artReadBarrierSlow is adjusted to take `index` + // into account. + void GenerateReadBarrierSlow(HInstruction* instruction, + Location out, + Location ref, + Location obj, + uint32_t offset, + Location index = Location::NoLocation()); + // If read barriers are enabled, generate a read barrier for a heap // reference using a slow path. If heap poisoning is enabled, also // unpoison the reference in `out`. diff --git a/compiler/optimizing/common_arm.h b/compiler/optimizing/common_arm.h index 8c08a9c8b9..13824ad671 100644 --- a/compiler/optimizing/common_arm.h +++ b/compiler/optimizing/common_arm.h @@ -135,6 +135,16 @@ inline vixl::aarch32::Register InputRegister(HInstruction* instr) { return InputRegisterAt(instr, 0); } +inline int32_t Int32ConstantFrom(Location location) { + HConstant* instr = location.GetConstant(); + if (instr->IsIntConstant()) { + return instr->AsIntConstant()->GetValue(); + } else { + DCHECK(instr->IsNullConstant()) << instr->DebugName(); + return 0; + } +} + inline int64_t Int64ConstantFrom(Location location) { HConstant* instr = location.GetConstant(); if (instr->IsIntConstant()) { diff --git a/compiler/utils/arm/assembler_arm_vixl.cc b/compiler/utils/arm/assembler_arm_vixl.cc index 8045bd2c6a..e3b9fb62c8 100644 --- a/compiler/utils/arm/assembler_arm_vixl.cc +++ b/compiler/utils/arm/assembler_arm_vixl.cc @@ -62,6 +62,12 @@ void ArmVIXLAssembler::UnpoisonHeapReference(vixl::aarch32::Register reg) { ___ Rsb(reg, reg, 0); } +void ArmVIXLAssembler::MaybePoisonHeapReference(vixl32::Register reg) { + if (kPoisonHeapReferences) { + PoisonHeapReference(reg); + } +} + void ArmVIXLAssembler::MaybeUnpoisonHeapReference(vixl32::Register reg) { if (kPoisonHeapReferences) { UnpoisonHeapReference(reg); diff --git a/compiler/utils/arm/assembler_arm_vixl.h b/compiler/utils/arm/assembler_arm_vixl.h index 68fd32e107..e0206287eb 100644 --- a/compiler/utils/arm/assembler_arm_vixl.h +++ b/compiler/utils/arm/assembler_arm_vixl.h @@ -72,6 +72,8 @@ class ArmVIXLAssembler FINAL : public Assembler { void PoisonHeapReference(vixl32::Register reg); // Unpoison a heap reference contained in `reg`. void UnpoisonHeapReference(vixl32::Register reg); + // Poison a heap reference contained in `reg` if heap poisoning is enabled. + void MaybePoisonHeapReference(vixl32::Register reg); // Unpoison a heap reference contained in `reg` if heap poisoning is enabled. void MaybeUnpoisonHeapReference(vixl32::Register reg); diff --git a/test/Android.arm_vixl.mk b/test/Android.arm_vixl.mk index 2d9708de93..e5628129db 100644 --- a/test/Android.arm_vixl.mk +++ b/test/Android.arm_vixl.mk @@ -22,7 +22,6 @@ TEST_ART_BROKEN_OPTIMIZING_ARM_VIXL_RUN_TESTS := \ 004-JniTest \ 004-NativeAllocations \ 004-ThreadStress \ - 004-UnsafeTest \ 004-checker-UnsafeTest18 \ 005-annotations \ 009-instanceof \ @@ -208,6 +207,7 @@ TEST_ART_BROKEN_OPTIMIZING_ARM_VIXL_RUN_TESTS := \ 570-checker-osr \ 570-checker-select \ 573-checker-checkcast-regression \ + 574-irreducible-and-constant-area \ 575-checker-string-init-alias \ 580-checker-round \ 584-checker-div-bool \ |