From e5cf5d95023746c796c122d4b94f61963eb514b5 Mon Sep 17 00:00:00 2001 From: Tess Strickland Date: Thu, 20 Aug 2020 11:36:00 +0000 Subject: [PATCH] [vm/compiler] Add nullable boxed native field slots. Previously, all boxed native field slots were marked not nullable. However, several boxed native fields are in fact nullable, which means that even generated IL that appropriately checks these fields for null can break in optimized code when the null checks are removed. Also add some helper utilities for working with representations. Change-Id: I22703d14cfbadbabeae74179476dea47ace12161 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/159280 Commit-Queue: Tess Strickland Reviewed-by: Ryan Macnak Reviewed-by: Clement Skau --- runtime/vm/compiler/backend/il.cc | 87 +++++++++++++- runtime/vm/compiler/backend/il.h | 113 ++---------------- runtime/vm/compiler/backend/il_arm.cc | 13 +- runtime/vm/compiler/backend/il_arm64.cc | 73 ++++++----- runtime/vm/compiler/backend/il_ia32.cc | 14 ++- runtime/vm/compiler/backend/il_x64.cc | 62 +++++----- runtime/vm/compiler/backend/locations.cc | 52 +++++++- runtime/vm/compiler/backend/locations.h | 59 +++++++-- runtime/vm/compiler/backend/slot.cc | 89 +++++++------- runtime/vm/compiler/backend/slot.h | 49 +++++--- runtime/vm/compiler/runtime_api.h | 1 + .../vm/compiler/runtime_offsets_extracted.h | 14 +++ runtime/vm/compiler/runtime_offsets_list.h | 1 + .../vm/compiler/write_barrier_elimination.cc | 5 +- 14 files changed, 373 insertions(+), 259 deletions(-) diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc index 5f51a5b384c..85abf0f970c 100644 --- a/runtime/vm/compiler/backend/il.cc +++ b/runtime/vm/compiler/backend/il.cc @@ -478,6 +478,80 @@ bool HierarchyInfo::InstanceOfHasClassRange(const AbstractType& type, return false; } +// The set of supported non-integer unboxed representations. +// Format: (unboxed representations suffix, boxed class type) +#define FOR_EACH_NON_INT_BOXED_REPRESENTATION(M) \ + M(Double, Double) \ + M(Float, Double) \ + M(Float32x4, Float32x4) \ + M(Float64x2, Float64x2) \ + M(Int32x4, Int32x4) + +#define BOXING_IN_SET_CASE(unboxed, boxed) \ + case kUnboxed##unboxed: \ + return true; +#define BOXING_VALUE_OFFSET_CASE(unboxed, boxed) \ + case kUnboxed##unboxed: \ + return compiler::target::boxed::value_offset(); +#define BOXING_CID_CASE(unboxed, boxed) \ + case kUnboxed##unboxed: \ + return k##boxed##Cid; + +bool Boxing::Supports(Representation rep) { + if (RepresentationUtils::IsUnboxedInteger(rep)) { + return true; + } + switch (rep) { + FOR_EACH_NON_INT_BOXED_REPRESENTATION(BOXING_IN_SET_CASE) + default: + return false; + } +} + +bool Boxing::RequiresAllocation(Representation rep) { + if (RepresentationUtils::IsUnboxedInteger(rep)) { + return (kBitsPerByte * RepresentationUtils::ValueSize(rep)) > + compiler::target::kSmiBits; + } + return true; +} + +intptr_t Boxing::ValueOffset(Representation rep) { + if (RepresentationUtils::IsUnboxedInteger(rep) && + Boxing::RequiresAllocation(rep) && + RepresentationUtils::ValueSize(rep) <= sizeof(int64_t)) { + return compiler::target::Mint::value_offset(); + } + switch (rep) { + FOR_EACH_NON_INT_BOXED_REPRESENTATION(BOXING_VALUE_OFFSET_CASE) + default: + UNREACHABLE(); + return 0; + } +} + +// Note that not all boxes require allocation (e.g., Smis). +intptr_t Boxing::BoxCid(Representation rep) { + if (RepresentationUtils::IsUnboxedInteger(rep)) { + if (!Boxing::RequiresAllocation(rep)) { + return kSmiCid; + } else if (RepresentationUtils::ValueSize(rep) <= sizeof(int64_t)) { + return kMintCid; + } + } + switch (rep) { + FOR_EACH_NON_INT_BOXED_REPRESENTATION(BOXING_CID_CASE) + default: + UNREACHABLE(); + return kIllegalCid; + } +} + +#undef BOXING_CID_CASE +#undef BOXING_VALUE_OFFSET_CASE +#undef BOXING_IN_SET_CASE +#undef FOR_EACH_NON_INT_BOXED_REPRESENTATION + #if defined(DEBUG) void Instruction::CheckField(const Field& field) const { ASSERT(field.IsZoneHandle()); @@ -5255,6 +5329,7 @@ void RangeErrorSlowPath::EmitSharedStubCall(FlowGraphCompiler* compiler, void UnboxInstr::EmitLoadFromBoxWithDeopt(FlowGraphCompiler* compiler) { const intptr_t box_cid = BoxCid(); + ASSERT(box_cid != kSmiCid); // Should never reach here with Smi-able ints. const Register box = locs()->in(0).reg(); const Register temp = (locs()->temp_count() > 0) ? locs()->temp(0).reg() : kNoRegister; @@ -5285,6 +5360,11 @@ void UnboxInstr::EmitLoadFromBoxWithDeopt(FlowGraphCompiler* compiler) { void UnboxInstr::EmitNativeCode(FlowGraphCompiler* compiler) { if (SpeculativeModeOfInputs() == kNotSpeculative) { + if (BoxCid() == kSmiCid) { + // Since the representation fits in a Smi, we can extract it directly. + ASSERT_EQUAL(value()->Type()->ToCid(), kSmiCid); + return EmitSmiConversion(compiler); + } switch (representation()) { case kUnboxedDouble: case kUnboxedFloat: @@ -5317,14 +5397,15 @@ void UnboxInstr::EmitNativeCode(FlowGraphCompiler* compiler) { const intptr_t value_cid = value()->Type()->ToCid(); const intptr_t box_cid = BoxCid(); - if (value_cid == box_cid) { - EmitLoadFromBox(compiler); - } else if (CanConvertSmi() && (value_cid == kSmiCid)) { + if (box_cid == kSmiCid || (CanConvertSmi() && (value_cid == kSmiCid))) { + ASSERT_EQUAL(value_cid, kSmiCid); EmitSmiConversion(compiler); } else if (representation() == kUnboxedInt32 && value()->Type()->IsInt()) { EmitLoadInt32FromBoxOrSmi(compiler); } else if (representation() == kUnboxedInt64 && value()->Type()->IsInt()) { EmitLoadInt64FromBoxOrSmi(compiler); + } else if (value_cid == box_cid) { + EmitLoadFromBox(compiler); } else { ASSERT(CanDeoptimize()); EmitLoadFromBoxWithDeopt(compiler); diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h index b3c6d6986e8..df2ec7f541c 100644 --- a/runtime/vm/compiler/backend/il.h +++ b/runtime/vm/compiler/backend/il.h @@ -3492,19 +3492,6 @@ class ConstantInstr : public TemplateDefinition<0, NoThrow, Pure> { virtual TokenPosition token_pos() const { return token_pos_; } - // Returns whether the constant fits in an unboxed 64-bit signed integer. - bool IsUnboxedSignedIntegerConstant() const { - return representation() == kUnboxedUint32 || - representation() == kUnboxedInt32 || - representation() == kUnboxedInt64; - } - - int64_t GetUnboxedSignedIntegerConstantValue() const { - ASSERT(IsUnboxedSignedIntegerConstant()); - return value_.IsSmi() ? Smi::Cast(value_).Value() - : Mint::Cast(value_).value(); - } - void EmitMoveToLocation(FlowGraphCompiler* compiler, const Location& destination, Register tmp = kNoRegister); @@ -6664,97 +6651,21 @@ class CheckEitherNonSmiInstr : public TemplateInstruction<2, NoThrow, Pure> { DISALLOW_COPY_AND_ASSIGN(CheckEitherNonSmiInstr); }; -class Boxing : public AllStatic { - public: - static bool Supports(Representation rep) { - switch (rep) { - case kUnboxedDouble: - case kUnboxedFloat32x4: - case kUnboxedFloat64x2: - case kUnboxedInt32x4: - case kUnboxedInt64: - case kUnboxedInt32: - case kUnboxedUint32: - return true; - default: - return false; - } - } +struct Boxing : public AllStatic { + // Whether the given representation can be boxed or unboxed. + static bool Supports(Representation rep); - static bool RequiresAllocation(Representation rep) { - switch (rep) { - case kUnboxedDouble: - case kUnboxedFloat32x4: - case kUnboxedFloat64x2: - case kUnboxedInt32x4: - case kUnboxedInt64: - return true; - case kUnboxedInt32: - case kUnboxedUint32: - return kBitsPerInt32 > compiler::target::kSmiBits; - default: - UNREACHABLE(); - return true; - } - } + // Whether boxing this value requires allocating a new object. + static bool RequiresAllocation(Representation rep); - static intptr_t ValueOffset(Representation rep) { - switch (rep) { - case kUnboxedFloat: - case kUnboxedDouble: - return Double::value_offset(); + // The offset into the Layout object for the boxed value that can store + // the full range of values in the representation. + // Only defined for allocated boxes (i.e., RequiresAllocation must be true). + static intptr_t ValueOffset(Representation rep); - case kUnboxedFloat32x4: - return Float32x4::value_offset(); - - case kUnboxedFloat64x2: - return Float64x2::value_offset(); - - case kUnboxedInt32x4: - return Int32x4::value_offset(); - - case kUnboxedInt64: - return Mint::value_offset(); - - case kUnboxedInt32: - case kUnboxedUint32: - if (RequiresAllocation(rep)) { - return Mint::value_offset(); - } - UNREACHABLE(); - return 0; - - default: - UNREACHABLE(); - return 0; - } - } - - static intptr_t BoxCid(Representation rep) { - switch (rep) { - case kUnboxedInt32: - case kUnboxedUint32: - if (RequiresAllocation(rep)) { - return kMintCid; - } - UNREACHABLE(); - return kIllegalCid; - case kUnboxedInt64: - return kMintCid; - case kUnboxedDouble: - case kUnboxedFloat: - return kDoubleCid; - case kUnboxedFloat32x4: - return kFloat32x4Cid; - case kUnboxedFloat64x2: - return kFloat64x2Cid; - case kUnboxedInt32x4: - return kInt32x4Cid; - default: - UNREACHABLE(); - return kIllegalCid; - } - } + // The class ID for the boxed value that can store the full range + // of values in the representation. + static intptr_t BoxCid(Representation rep); }; class BoxInstr : public TemplateDefinition<1, NoThrow, Pure> { diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc index bedb2ec6976..1c3daa9c038 100644 --- a/runtime/vm/compiler/backend/il_arm.cc +++ b/runtime/vm/compiler/backend/il_arm.cc @@ -672,14 +672,12 @@ void ConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) { void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler, const Location& destination, Register tmp) { - const bool is_unboxed_int = - representation() == kUnboxedUint32 || representation() == kUnboxedInt32; if (destination.IsRegister()) { - if (is_unboxed_int) { + if (RepresentationUtils::IsUnboxedInteger(representation())) { int64_t v; const bool ok = compiler::HasIntegerValue(value_, &v); RELEASE_ASSERT(ok); - if (value_.IsSmi() && representation() == kUnboxedUint32) { + if (value_.IsSmi() && RepresentationUtils::IsUnsigned(representation())) { // If the value is negative, then the sign bit was preserved during // Smi untagging, which means the resulting value may be unexpected. ASSERT(v >= 0); @@ -713,7 +711,7 @@ void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler, ASSERT(destination.IsStackSlot()); ASSERT(tmp != kNoRegister); const intptr_t dest_offset = destination.ToStackSlotOffset(); - if (is_unboxed_int) { + if (RepresentationUtils::IsUnboxedInteger(representation())) { int64_t v; const bool ok = compiler::HasIntegerValue(value_, &v); RELEASE_ASSERT(ok); @@ -728,7 +726,9 @@ void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler, LocationSummary* UnboxedConstantInstr::MakeLocationSummary(Zone* zone, bool opt) const { const bool is_unboxed_int = - representation() == kUnboxedUint32 || representation() == kUnboxedInt32; + RepresentationUtils::IsUnboxedInteger(representation()); + ASSERT(!is_unboxed_int || RepresentationUtils::ValueSize(representation()) <= + compiler::target::kWordSize); const intptr_t kNumInputs = 0; const intptr_t kNumTemps = is_unboxed_int ? 0 : 1; LocationSummary* locs = new (zone) @@ -4826,6 +4826,7 @@ void BoxInstr::EmitNativeCode(FlowGraphCompiler* compiler) { } LocationSummary* UnboxInstr::MakeLocationSummary(Zone* zone, bool opt) const { + ASSERT(BoxCid() != kSmiCid); const bool needs_temp = CanDeoptimize(); const intptr_t kNumInputs = 1; const intptr_t kNumTemps = needs_temp ? 1 : 0; diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc index 51f63300714..8b5e74633b9 100644 --- a/runtime/vm/compiler/backend/il_arm64.cc +++ b/runtime/vm/compiler/backend/il_arm64.cc @@ -619,23 +619,26 @@ void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler, LocationSummary* UnboxedConstantInstr::MakeLocationSummary(Zone* zone, bool opt) const { + const bool is_unboxed_int = + RepresentationUtils::IsUnboxedInteger(representation()); + ASSERT(!is_unboxed_int || RepresentationUtils::ValueSize(representation()) <= + compiler::target::kWordSize); const intptr_t kNumInputs = 0; - const intptr_t kNumTemps = IsUnboxedSignedIntegerConstant() ? 0 : 1; + const intptr_t kNumTemps = is_unboxed_int ? 0 : 1; LocationSummary* locs = new (zone) LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); - switch (representation()) { - case kUnboxedDouble: - locs->set_out(0, Location::RequiresFpuRegister()); - locs->set_temp(0, Location::RequiresRegister()); - break; - case kUnboxedInt32: - case kUnboxedUint32: - case kUnboxedInt64: - locs->set_out(0, Location::RequiresRegister()); - break; - default: - UNREACHABLE(); - break; + if (is_unboxed_int) { + locs->set_out(0, Location::RequiresRegister()); + } else { + switch (representation()) { + case kUnboxedDouble: + locs->set_out(0, Location::RequiresFpuRegister()); + locs->set_temp(0, Location::RequiresRegister()); + break; + default: + UNREACHABLE(); + break; + } } return locs; } @@ -643,7 +646,9 @@ LocationSummary* UnboxedConstantInstr::MakeLocationSummary(Zone* zone, void UnboxedConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) { if (!locs()->out(0).IsInvalid()) { const Register scratch = - IsUnboxedSignedIntegerConstant() ? kNoRegister : locs()->temp(0).reg(); + RepresentationUtils::IsUnboxedInteger(representation()) + ? kNoRegister + : locs()->temp(0).reg(); EmitMoveToLocation(compiler, locs()->out(0), scratch); } } @@ -835,29 +840,29 @@ static Condition EmitInt64ComparisonOp(FlowGraphCompiler* compiler, Condition true_condition = TokenKindToSmiCondition(kind); if (left.IsConstant() || right.IsConstant()) { // Ensure constant is on the right. - ConstantInstr* right_constant = NULL; + ConstantInstr* constant = nullptr; if (left.IsConstant()) { - right_constant = left.constant_instruction(); + constant = left.constant_instruction(); Location tmp = right; right = left; left = tmp; true_condition = FlipCondition(true_condition); } else { - right_constant = right.constant_instruction(); + constant = right.constant_instruction(); } - if (right_constant->IsUnboxedSignedIntegerConstant()) { - const int64_t constant = - right_constant->GetUnboxedSignedIntegerConstantValue(); - if (constant == 0 && CanUseCbzTbzForComparison(compiler, left.reg(), - true_condition, labels)) { + if (RepresentationUtils::IsUnboxedInteger(constant->representation())) { + int64_t value; + const bool ok = compiler::HasIntegerValue(constant->value(), &value); + RELEASE_ASSERT(ok); + if (value == 0 && CanUseCbzTbzForComparison(compiler, left.reg(), + true_condition, labels)) { EmitCbzTbz(left.reg(), compiler, true_condition, labels); return kInvalidCondition; } - __ CompareImmediate( - left.reg(), right_constant->GetUnboxedSignedIntegerConstantValue()); + __ CompareImmediate(left.reg(), value); } else { - ASSERT(right_constant->representation() == kTagged); + ASSERT(constant->representation() == kTagged); __ CompareObject(left.reg(), right.constant()); } } else { @@ -4050,10 +4055,11 @@ void BoxInstr::EmitNativeCode(FlowGraphCompiler* compiler) { } LocationSummary* UnboxInstr::MakeLocationSummary(Zone* zone, bool opt) const { + ASSERT(!RepresentationUtils::IsUnsigned(representation())); const intptr_t kNumInputs = 1; const intptr_t kNumTemps = 0; const bool is_floating_point = - representation() != kUnboxedInt64 && representation() != kUnboxedInt32; + !RepresentationUtils::IsUnboxedInteger(representation()); LocationSummary* summary = new (zone) LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); summary->set_in(0, Location::RequiresRegister()); @@ -4103,6 +4109,7 @@ void UnboxInstr::EmitSmiConversion(FlowGraphCompiler* compiler) { const Register box = locs()->in(0).reg(); switch (representation()) { + case kUnboxedInt32: case kUnboxedInt64: { const Register result = locs()->out(0).reg(); __ SmiUntag(result, box); @@ -5855,9 +5862,9 @@ void BinaryInt64OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { } else if (op_kind() == Token::kMUL) { Register r = TMP; if (right.IsConstant()) { - ConstantInstr* constant_instr = right.constant_instruction(); - const int64_t value = - constant_instr->GetUnboxedSignedIntegerConstantValue(); + int64_t value; + const bool ok = compiler::HasIntegerValue(right.constant(), &value); + RELEASE_ASSERT(ok); __ LoadImmediate(r, value); } else { r = right.reg(); @@ -5867,9 +5874,9 @@ void BinaryInt64OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { } if (right.IsConstant()) { - ConstantInstr* constant_instr = right.constant_instruction(); - const int64_t value = - constant_instr->GetUnboxedSignedIntegerConstantValue(); + int64_t value; + const bool ok = compiler::HasIntegerValue(right.constant(), &value); + RELEASE_ASSERT(ok); switch (op_kind()) { case Token::kADD: __ AddImmediate(out, left, value); diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc index 4a2ad851d34..45958f9eb62 100644 --- a/runtime/vm/compiler/backend/il_ia32.cc +++ b/runtime/vm/compiler/backend/il_ia32.cc @@ -397,14 +397,12 @@ void ConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) { void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler, const Location& destination, Register tmp) { - const bool is_unboxed_int = - representation() == kUnboxedUint32 || representation() == kUnboxedInt32; if (destination.IsRegister()) { - if (is_unboxed_int) { + if (RepresentationUtils::IsUnboxedInteger(representation())) { int64_t v; const bool ok = compiler::HasIntegerValue(value_, &v); RELEASE_ASSERT(ok); - if (value_.IsSmi() && representation() == kUnboxedUint32) { + if (value_.IsSmi() && RepresentationUtils::IsUnsigned(representation())) { // If the value is negative, then the sign bit was preserved during // Smi untagging, which means the resulting value may be unexpected. ASSERT(v >= 0); @@ -444,7 +442,8 @@ void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler, __ movsd(LocationToStackSlotAddress(destination), FpuTMP); } else { ASSERT(destination.IsStackSlot()); - if (value_.IsSmi() && is_unboxed_int) { + if (value_.IsSmi() && + RepresentationUtils::IsUnboxedInteger(representation())) { __ movl(LocationToStackSlotAddress(destination), compiler::Immediate(Smi::Cast(value_).Value())); } else { @@ -464,7 +463,9 @@ void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler, LocationSummary* UnboxedConstantInstr::MakeLocationSummary(Zone* zone, bool opt) const { const bool is_unboxed_int = - representation() == kUnboxedUint32 || representation() == kUnboxedInt32; + RepresentationUtils::IsUnboxedInteger(representation()); + ASSERT(!is_unboxed_int || RepresentationUtils::ValueSize(representation()) <= + compiler::target::kWordSize); const intptr_t kNumInputs = 0; const intptr_t kNumTemps = (constant_address() == 0) && !is_unboxed_int ? 1 : 0; @@ -3758,6 +3759,7 @@ void BoxInstr::EmitNativeCode(FlowGraphCompiler* compiler) { } LocationSummary* UnboxInstr::MakeLocationSummary(Zone* zone, bool opt) const { + ASSERT(BoxCid() != kSmiCid); const bool needs_temp = CanDeoptimize() || (CanConvertSmi() && (value()->Type()->ToCid() == kSmiCid)); diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc index a803165ceee..94c6beee901 100644 --- a/runtime/vm/compiler/backend/il_x64.cc +++ b/runtime/vm/compiler/backend/il_x64.cc @@ -510,9 +510,7 @@ void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler, const Location& destination, Register tmp) { if (destination.IsRegister()) { - if (representation() == kUnboxedInt32 || - representation() == kUnboxedUint32 || - representation() == kUnboxedInt64) { + if (RepresentationUtils::IsUnboxedInteger(representation())) { const int64_t value = Integer::Cast(value_).AsInt64Value(); if (value == 0) { __ xorl(destination.reg(), destination.reg()); @@ -543,9 +541,7 @@ void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler, __ movsd(LocationToStackSlotAddress(destination), FpuTMP); } else { ASSERT(destination.IsStackSlot()); - if (representation() == kUnboxedInt32 || - representation() == kUnboxedUint32 || - representation() == kUnboxedInt64) { + if (RepresentationUtils::IsUnboxedInteger(representation())) { const int64_t value = Integer::Cast(value_).AsInt64Value(); __ movq(LocationToStackSlotAddress(destination), compiler::Immediate(value)); @@ -558,23 +554,26 @@ void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler, LocationSummary* UnboxedConstantInstr::MakeLocationSummary(Zone* zone, bool opt) const { + const bool is_unboxed_int = + RepresentationUtils::IsUnboxedInteger(representation()); + ASSERT(!is_unboxed_int || RepresentationUtils::ValueSize(representation()) <= + compiler::target::kWordSize); const intptr_t kNumInputs = 0; - const intptr_t kNumTemps = IsUnboxedSignedIntegerConstant() ? 0 : 1; + const intptr_t kNumTemps = is_unboxed_int ? 0 : 1; LocationSummary* locs = new (zone) LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); - switch (representation()) { - case kUnboxedDouble: - locs->set_out(0, Location::RequiresFpuRegister()); - locs->set_temp(0, Location::RequiresRegister()); - break; - case kUnboxedInt32: - case kUnboxedUint32: - case kUnboxedInt64: - locs->set_out(0, Location::RequiresRegister()); - break; - default: - UNREACHABLE(); - break; + if (is_unboxed_int) { + locs->set_out(0, Location::RequiresRegister()); + } else { + switch (representation()) { + case kUnboxedDouble: + locs->set_out(0, Location::RequiresFpuRegister()); + locs->set_temp(0, Location::RequiresRegister()); + break; + default: + UNREACHABLE(); + break; + } } return locs; } @@ -583,7 +582,9 @@ void UnboxedConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) { // The register allocator drops constant definitions that have no uses. if (!locs()->out(0).IsInvalid()) { const Register scratch = - IsUnboxedSignedIntegerConstant() ? kNoRegister : locs()->temp(0).reg(); + RepresentationUtils::IsUnboxedInteger(representation()) + ? kNoRegister + : locs()->temp(0).reg(); EmitMoveToLocation(compiler, locs()->out(0), scratch); } } @@ -794,10 +795,11 @@ static Condition EmitInt64ComparisonOp(FlowGraphCompiler* compiler, constant = right.constant_instruction(); } - if (constant->IsUnboxedSignedIntegerConstant()) { - __ cmpq(left.reg(), - compiler::Immediate( - constant->GetUnboxedSignedIntegerConstantValue())); + if (RepresentationUtils::IsUnboxedInteger(constant->representation())) { + int64_t value; + const bool ok = compiler::HasIntegerValue(constant->value(), &value); + RELEASE_ASSERT(ok); + __ cmpq(left.reg(), compiler::Immediate(value)); } else { ASSERT(constant->representation() == kTagged); __ CompareObject(left.reg(), right.constant()); @@ -4270,6 +4272,7 @@ void BoxInstr::EmitNativeCode(FlowGraphCompiler* compiler) { } LocationSummary* UnboxInstr::MakeLocationSummary(Zone* zone, bool opt) const { + ASSERT(!RepresentationUtils::IsUnsigned(representation())); const intptr_t kNumInputs = 1; const intptr_t kNumTemps = 0; const bool needs_writable_input = @@ -4279,7 +4282,7 @@ LocationSummary* UnboxInstr::MakeLocationSummary(Zone* zone, bool opt) const { LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall); summary->set_in(0, needs_writable_input ? Location::WritableRegister() : Location::RequiresRegister()); - if (representation() == kUnboxedInt64 || representation() == kUnboxedInt32) { + if (RepresentationUtils::IsUnboxedInteger(representation())) { summary->set_out(0, Location::SameAsFirstInput()); } else { summary->set_out(0, Location::RequiresFpuRegister()); @@ -4328,6 +4331,7 @@ void UnboxInstr::EmitSmiConversion(FlowGraphCompiler* compiler) { const Register box = locs()->in(0).reg(); switch (representation()) { + case kUnboxedInt32: case kUnboxedInt64: { const Register result = locs()->out(0).reg(); ASSERT(result == box); @@ -6253,9 +6257,9 @@ void BinaryInt64OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { temp.reg(), out.reg()); } else if (right.IsConstant()) { ASSERT(out.reg() == left.reg()); - ConstantInstr* constant_instr = right.constant_instruction(); - const int64_t value = - constant_instr->GetUnboxedSignedIntegerConstantValue(); + int64_t value; + const bool ok = compiler::HasIntegerValue(right.constant(), &value); + RELEASE_ASSERT(ok); EmitInt64Arithmetic(compiler, op_kind(), left.reg(), compiler::Immediate(value)); } else { diff --git a/runtime/vm/compiler/backend/locations.cc b/runtime/vm/compiler/backend/locations.cc index 2c40969dfaa..d31957cfe3d 100644 --- a/runtime/vm/compiler/backend/locations.cc +++ b/runtime/vm/compiler/backend/locations.cc @@ -11,9 +11,57 @@ namespace dart { +#define REP_IN_SET_CLAUSE(name, __, ___) \ + case k##name: \ + return true; +#define REP_SIZEOF_CLAUSE(name, __, type) \ + case k##name: \ + return sizeof(type); +#define REP_IS_UNSIGNED_CLAUSE(name, unsigned, ___) \ + case k##name: \ + return unsigned; + +bool RepresentationUtils::IsUnboxedInteger(Representation rep) { + switch (rep) { + FOR_EACH_INTEGER_REPRESENTATION_KIND(REP_IN_SET_CLAUSE) + default: + return false; + } +} + +bool RepresentationUtils::IsUnboxed(Representation rep) { + switch (rep) { + FOR_EACH_UNBOXED_REPRESENTATION_KIND(REP_IN_SET_CLAUSE) + default: + return false; + } +} + +size_t RepresentationUtils::ValueSize(Representation rep) { + switch (rep) { + FOR_EACH_SIMPLE_REPRESENTATION_KIND(REP_SIZEOF_CLAUSE) + default: + UNREACHABLE(); + return compiler::target::kWordSize; + } +} + +bool RepresentationUtils::IsUnsigned(Representation rep) { + switch (rep) { + FOR_EACH_SIMPLE_REPRESENTATION_KIND(REP_IS_UNSIGNED_CLAUSE) + default: + UNREACHABLE(); + return false; + } +} + +#undef REP_IS_UNSIGNED_CLAUSE +#undef REP_SIZEOF_CLAUSE +#undef REP_IN_SET_CLAUSE + const char* Location::RepresentationToCString(Representation repr) { switch (repr) { -#define REPR_CASE(Name) \ +#define REPR_CASE(Name, __, ___) \ case k##Name: \ return #Name; FOR_EACH_REPRESENTATION_KIND(REPR_CASE) @@ -26,7 +74,7 @@ const char* Location::RepresentationToCString(Representation repr) { bool Location::ParseRepresentation(const char* str, Representation* out) { ASSERT(str != nullptr && out != nullptr); -#define KIND_CASE(Name) \ +#define KIND_CASE(Name, __, ___) \ if (strcmp(str, #Name) == 0) { \ *out = k##Name; \ return true; \ diff --git a/runtime/vm/compiler/backend/locations.h b/runtime/vm/compiler/backend/locations.h index 34edf4c510a..8f4c37ff26e 100644 --- a/runtime/vm/compiler/backend/locations.h +++ b/runtime/vm/compiler/backend/locations.h @@ -24,27 +24,60 @@ class Definition; class PairLocation; class Value; +// All unboxed integer representations. +// Format: (representation name, is unsigned, value type) +#define FOR_EACH_INTEGER_REPRESENTATION_KIND(M) \ + M(UnboxedInt32, false, int32_t) \ + M(UnboxedUint32, true, uint32_t) \ + M(UnboxedInt64, false, int64_t) + +// All unboxed representations. +// Format: (representation name, is unsigned, value type) +#define FOR_EACH_UNBOXED_REPRESENTATION_KIND(M) \ + M(UnboxedDouble, false, double_t) \ + M(UnboxedFloat, false, float_t) \ + FOR_EACH_INTEGER_REPRESENTATION_KIND(M) \ + M(UnboxedFloat32x4, false, simd128_value_t) \ + M(UnboxedInt32x4, false, simd128_value_t) \ + M(UnboxedFloat64x2, false, simd128_value_t) + +// All representations that represent a single boxed or unboxed value. +// (Note that packed SIMD values are considered a single value here.) +// Format: (representation name, is unsigned, value type) +#define FOR_EACH_SIMPLE_REPRESENTATION_KIND(M) \ + M(Tagged, false, compiler::target::word) \ + M(Untagged, false, compiler::target::word) \ + FOR_EACH_UNBOXED_REPRESENTATION_KIND(M) + +// All representations, including sentinel and multi-value representations. +// Format: (representation name, _, _) (only the name is guaranteed to exist) +// Ordered so that NoRepresentation is first (and thus 0 in the enum). #define FOR_EACH_REPRESENTATION_KIND(M) \ - M(NoRepresentation) \ - M(Tagged) \ - M(Untagged) \ - M(UnboxedDouble) \ - M(UnboxedFloat) \ - M(UnboxedInt32) \ - M(UnboxedUint32) \ - M(UnboxedInt64) \ - M(UnboxedFloat32x4) \ - M(UnboxedInt32x4) \ - M(UnboxedFloat64x2) \ - M(PairOfTagged) + M(NoRepresentation, _, _) \ + FOR_EACH_SIMPLE_REPRESENTATION_KIND(M) \ + M(PairOfTagged, _, _) enum Representation { -#define DECLARE_REPRESENTATION(name) k##name, +#define DECLARE_REPRESENTATION(name, __, ___) k##name, FOR_EACH_REPRESENTATION_KIND(DECLARE_REPRESENTATION) #undef DECLARE_REPRESENTATION kNumRepresentations }; +struct RepresentationUtils : AllStatic { + // Whether the representation is for a type of unboxed integer. + static bool IsUnboxedInteger(Representation rep); + + // Whether the representation is for a type of unboxed value. + static bool IsUnboxed(Representation rep); + + // The size of values described by this representation. + static size_t ValueSize(Representation rep); + + // Whether the values described by this representation are unsigned integers. + static bool IsUnsigned(Representation rep); +}; + // 'UnboxedFfiIntPtr' should be able to hold a pointer of the target word-size. // On a 32-bit platform, it's an unsigned 32-bit int because it should be // zero-extended to 64-bits, not sign-extended (pointers are inherently diff --git a/runtime/vm/compiler/backend/slot.cc b/runtime/vm/compiler/backend/slot.cc index a8a9ec074ea..5f256b66e6b 100644 --- a/runtime/vm/compiler/backend/slot.cc +++ b/runtime/vm/compiler/backend/slot.cc @@ -46,16 +46,15 @@ class SlotCache : public ZoneAllocated { DirectChainedHashMap > fields_; }; -#define NATIVE_SLOT_NAME(C, F, id, M) Kind::k##C##_##F -#define NATIVE_TO_STR(C, F, id, M) #C "_" #F +#define NATIVE_SLOT_NAME(C, F) Kind::k##C##_##F +#define NATIVE_TO_STR(C, F) #C "_" #F const char* Slot::KindToCString(Kind k) { switch (k) { -#define NATIVE_CASE(C, U, F, id, M) \ - case NATIVE_SLOT_NAME(C, F, id, M): \ - return NATIVE_TO_STR(C, F, id, M); - BOXED_NATIVE_SLOTS_LIST(NATIVE_CASE) - UNBOXED_NATIVE_SLOTS_LIST(NATIVE_CASE) +#define NATIVE_CASE(C, __, F, ___, ____) \ + case NATIVE_SLOT_NAME(C, F): \ + return NATIVE_TO_STR(C, F); + NATIVE_SLOTS_LIST(NATIVE_CASE) #undef NATIVE_CASE case Kind::kTypeArguments: return "TypeArguments"; @@ -71,13 +70,12 @@ const char* Slot::KindToCString(Kind k) { bool Slot::ParseKind(const char* str, Kind* out) { ASSERT(str != nullptr && out != nullptr); -#define NATIVE_CASE(C, U, F, id, M) \ - if (strcmp(str, NATIVE_TO_STR(C, F, id, M)) == 0) { \ - *out = NATIVE_SLOT_NAME(C, F, id, M); \ +#define NATIVE_CASE(C, __, F, ___, ____) \ + if (strcmp(str, NATIVE_TO_STR(C, F)) == 0) { \ + *out = NATIVE_SLOT_NAME(C, F); \ return true; \ } - BOXED_NATIVE_SLOTS_LIST(NATIVE_CASE) - UNBOXED_NATIVE_SLOTS_LIST(NATIVE_CASE) + NATIVE_SLOTS_LIST(NATIVE_CASE) #undef NATIVE_CASE if (strcmp(str, "TypeArguments") == 0) { *out = Kind::kTypeArguments; @@ -97,31 +95,11 @@ bool Slot::ParseKind(const char* str, Kind* out) { #undef NATIVE_TO_STR #undef NATIVE_SLOT_NAME -static Representation CheckFit(Representation rep) { - ASSERT(Boxing::Supports(rep)); - switch (rep) { - case kUnboxedInt64: - case kUnboxedInt32: - case kUnboxedUint32: - break; - default: - UNREACHABLE(); - break; - } - return rep; -} - static classid_t GetUnboxedNativeSlotCid(Representation rep) { - ASSERT(Boxing::Supports(rep)); - if (Boxing::RequiresAllocation(rep)) { + // Currently we only support integer unboxed fields. + if (RepresentationUtils::IsUnboxedInteger(rep)) { return Boxing::BoxCid(rep); } -#if defined(TARGET_ARCH_IS_64_BIT) - // On 64-bit platforms, these always fit in Smis. - if (rep == kUnboxedInt32 || rep == kUnboxedUint32) { - return kSmiCid; - } -#endif UNREACHABLE(); return kIllegalCid; } @@ -130,30 +108,45 @@ const Slot& Slot::GetNativeSlot(Kind kind) { // There is a fixed statically known number of native slots so we cache // them statically. static const Slot fields[] = { -#define FIELD_FINAL (IsImmutableBit::encode(true)) -#define FIELD_VAR (0) -#define DEFINE_BOXED_NATIVE_FIELD(ClassName, UnderlyingType, FieldName, cid, \ - mutability) \ - Slot(Kind::k##ClassName##_##FieldName, FIELD_##mutability, k##cid##Cid, \ - compiler::target::ClassName::FieldName##_offset(), \ +#define NULLABLE_FIELD_FINAL \ + (IsNullableBit::encode(true) | IsImmutableBit::encode(true)) +#define NULLABLE_FIELD_VAR (IsNullableBit::encode(true)) +#define DEFINE_NULLABLE_BOXED_NATIVE_FIELD(ClassName, UnderlyingType, \ + FieldName, cid, mutability) \ + Slot(Kind::k##ClassName##_##FieldName, NULLABLE_FIELD_##mutability, \ + k##cid##Cid, compiler::target::ClassName::FieldName##_offset(), \ #ClassName "." #FieldName, nullptr, kTagged), - BOXED_NATIVE_SLOTS_LIST(DEFINE_BOXED_NATIVE_FIELD) + NULLABLE_BOXED_NATIVE_SLOTS_LIST(DEFINE_NULLABLE_BOXED_NATIVE_FIELD) -#undef DEFINE_BOXED_NATIVE_FIELD +#undef DEFINE_NULLABLE_BOXED_NATIVE_FIELD +#undef NULLABLE_FIELD_FINAL +#undef NULLABLE_FIELD_VAR + +#define NONNULLABLE_FIELD_FINAL (Slot::IsImmutableBit::encode(true)) +#define NONNULLABLE_FIELD_VAR (0) +#define DEFINE_NONNULLABLE_BOXED_NATIVE_FIELD(ClassName, UnderlyingType, \ + FieldName, cid, mutability) \ + Slot(Kind::k##ClassName##_##FieldName, NONNULLABLE_FIELD_##mutability, \ + k##cid##Cid, compiler::target::ClassName::FieldName##_offset(), \ + #ClassName "." #FieldName, nullptr, kTagged), + + NONNULLABLE_BOXED_NATIVE_SLOTS_LIST( + DEFINE_NONNULLABLE_BOXED_NATIVE_FIELD) + +#undef DEFINE_NONNULLABLE_BOXED_NATIVE_FIELD #define DEFINE_UNBOXED_NATIVE_FIELD(ClassName, UnderlyingType, FieldName, \ representation, mutability) \ - Slot(Kind::k##ClassName##_##FieldName, FIELD_##mutability, \ + Slot(Kind::k##ClassName##_##FieldName, NONNULLABLE_FIELD_##mutability, \ GetUnboxedNativeSlotCid(kUnboxed##representation), \ compiler::target::ClassName::FieldName##_offset(), \ - #ClassName "." #FieldName, nullptr, \ - CheckFit(kUnboxed##representation)), + #ClassName "." #FieldName, nullptr, kUnboxed##representation), - UNBOXED_NATIVE_SLOTS_LIST(DEFINE_UNBOXED_NATIVE_FIELD) + UNBOXED_NATIVE_SLOTS_LIST(DEFINE_UNBOXED_NATIVE_FIELD) #undef DEFINE_UNBOXED_NATIVE_FIELD -#undef FIELD_VAR -#undef FIELD_FINAL +#undef NONNULLABLE_FIELD_VAR +#undef NONNULLABLE_FIELD_FINAL }; ASSERT(static_cast(kind) < ARRAY_SIZE(fields)); diff --git a/runtime/vm/compiler/backend/slot.h b/runtime/vm/compiler/backend/slot.h index 6b2bd688068..c73b017ca2c 100644 --- a/runtime/vm/compiler/backend/slot.h +++ b/runtime/vm/compiler/backend/slot.h @@ -38,8 +38,8 @@ class LocalScope; class LocalVariable; class ParsedFunction; -// List of slots that correspond to fields of native objects in the following -// format: +// The list of slots that correspond to nullable boxed fields of native objects +// in the following format: // // V(class_name, underlying_type, field_name, exact_type, FINAL|VAR) // @@ -51,20 +51,34 @@ class ParsedFunction; // - the last component specifies whether field behaves like a final field // (i.e. initialized once at construction time and does not change after // that) or like a non-final field. -// -// Note: native slots are expected to be non-nullable. -#define BOXED_NATIVE_SLOTS_LIST(V) \ - V(Array, ArrayLayout, length, Smi, FINAL) \ +#define NULLABLE_BOXED_NATIVE_SLOTS_LIST(V) \ V(Context, ContextLayout, parent, Context, FINAL) \ V(Closure, ClosureLayout, instantiator_type_arguments, TypeArguments, FINAL) \ V(Closure, ClosureLayout, delayed_type_arguments, TypeArguments, FINAL) \ V(Closure, ClosureLayout, function_type_arguments, TypeArguments, FINAL) \ + V(Function, FunctionLayout, type_parameters, TypeArguments, FINAL) \ + V(Type, TypeLayout, arguments, TypeArguments, FINAL) + +// The list of slots that correspond to non-nullable boxed fields of native +// objects in the following format: +// +// V(class_name, underlying_type, field_name, exact_type, FINAL|VAR) +// +// - class_name and field_name specify the name of the host class and the name +// of the field respectively; +// - underlying_type: the Raw class which holds the field; +// - exact_type specifies exact type of the field (any load from this field +// would only yield instances of this type); +// - the last component specifies whether field behaves like a final field +// (i.e. initialized once at construction time and does not change after +// that) or like a non-final field. +#define NONNULLABLE_BOXED_NATIVE_SLOTS_LIST(V) \ + V(Array, ArrayLayout, length, Smi, FINAL) \ V(Closure, ClosureLayout, function, Function, FINAL) \ V(Closure, ClosureLayout, context, Context, FINAL) \ V(Closure, ClosureLayout, hash, Context, VAR) \ V(Function, FunctionLayout, parameter_names, Array, FINAL) \ V(Function, FunctionLayout, parameter_types, Array, FINAL) \ - V(Function, FunctionLayout, type_parameters, Array, FINAL) \ V(GrowableObjectArray, GrowableObjectArrayLayout, length, Smi, VAR) \ V(GrowableObjectArray, GrowableObjectArrayLayout, data, Array, VAR) \ V(TypedDataBase, TypedDataBaseLayout, length, Smi, FINAL) \ @@ -81,7 +95,6 @@ class ParsedFunction; V(ArgumentsDescriptor, ArrayLayout, count, Smi, FINAL) \ V(ArgumentsDescriptor, ArrayLayout, size, Smi, FINAL) \ V(PointerBase, PointerBaseLayout, data_field, Dynamic, FINAL) \ - V(Type, TypeLayout, arguments, TypeArguments, FINAL) \ V(UnhandledException, UnhandledExceptionLayout, exception, Dynamic, FINAL) \ V(UnhandledException, UnhandledExceptionLayout, stacktrace, Dynamic, FINAL) @@ -99,10 +112,18 @@ class ParsedFunction; // (i.e. initialized once at construction time and does not change after // that) or like a non-final field. // -// Note: As the underlying field is not boxed, these slots cannot be nullable. +// Note: As the underlying field is unboxed, these slots cannot be nullable. #define UNBOXED_NATIVE_SLOTS_LIST(V) \ V(Function, FunctionLayout, packed_fields, Uint32, FINAL) +// For uses that do not need the exact_type (boxed) or representation (unboxed) +// or whether a boxed native slot is nullable. (Generally, such users only need +// the class name, the underlying type, and/or the field name.) +#define NATIVE_SLOTS_LIST(V) \ + NULLABLE_BOXED_NATIVE_SLOTS_LIST(V) \ + NONNULLABLE_BOXED_NATIVE_SLOTS_LIST(V) \ + UNBOXED_NATIVE_SLOTS_LIST(V) + // Slot is an abstraction that describes an readable (and possibly writeable) // location within an object. // @@ -115,10 +136,9 @@ class Slot : public ZoneAllocated { // clang-format off enum class Kind : uint8_t { // Native slots are identified by their kind - each native slot has its own. -#define DECLARE_KIND(ClassName, UnderlyingType, FieldName, cid, mutability) \ +#define DECLARE_KIND(ClassName, __, FieldName, ___, ____) \ k##ClassName##_##FieldName, - BOXED_NATIVE_SLOTS_LIST(DECLARE_KIND) - UNBOXED_NATIVE_SLOTS_LIST(DECLARE_KIND) + NATIVE_SLOTS_LIST(DECLARE_KIND) #undef DECLARE_KIND // A slot used to store type arguments. @@ -164,13 +184,12 @@ class Slot : public ZoneAllocated { const ParsedFunction* parsed_function); // Convenience getters for native slots. -#define DEFINE_GETTER(ClassName, UnderlyingType, FieldName, cid, mutability) \ +#define DEFINE_GETTER(ClassName, UnderlyingType, FieldName, __, ___) \ static const Slot& ClassName##_##FieldName() { \ return GetNativeSlot(Kind::k##ClassName##_##FieldName); \ } - BOXED_NATIVE_SLOTS_LIST(DEFINE_GETTER) - UNBOXED_NATIVE_SLOTS_LIST(DEFINE_GETTER) + NATIVE_SLOTS_LIST(DEFINE_GETTER) #undef DEFINE_GETTER Kind kind() const { return kind_; } diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h index 572f0a00df1..048038e1546 100644 --- a/runtime/vm/compiler/runtime_api.h +++ b/runtime/vm/compiler/runtime_api.h @@ -714,6 +714,7 @@ class ExternalTwoByteString : public AllStatic { class Int32x4 : public AllStatic { public: + static word value_offset(); static word InstanceSize(); static word NextFieldOffset(); }; diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h index 63f65ca106a..6320c51c5a0 100644 --- a/runtime/vm/compiler/runtime_offsets_extracted.h +++ b/runtime/vm/compiler/runtime_offsets_extracted.h @@ -146,6 +146,7 @@ static constexpr dart::compiler::target::word ICData_NumArgsTestedShift = 0; static constexpr dart::compiler::target::word ICData_entries_offset = 12; static constexpr dart::compiler::target::word ICData_owner_offset = 20; static constexpr dart::compiler::target::word ICData_state_bits_offset = 28; +static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_shared_class_table_offset = 36; static constexpr dart::compiler::target::word @@ -648,6 +649,7 @@ static constexpr dart::compiler::target::word ICData_NumArgsTestedShift = 0; static constexpr dart::compiler::target::word ICData_entries_offset = 24; static constexpr dart::compiler::target::word ICData_owner_offset = 40; static constexpr dart::compiler::target::word ICData_state_bits_offset = 52; +static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_shared_class_table_offset = 72; static constexpr dart::compiler::target::word @@ -1154,6 +1156,7 @@ static constexpr dart::compiler::target::word ICData_NumArgsTestedShift = 0; static constexpr dart::compiler::target::word ICData_entries_offset = 12; static constexpr dart::compiler::target::word ICData_owner_offset = 20; static constexpr dart::compiler::target::word ICData_state_bits_offset = 28; +static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_shared_class_table_offset = 36; static constexpr dart::compiler::target::word @@ -1653,6 +1656,7 @@ static constexpr dart::compiler::target::word ICData_NumArgsTestedShift = 0; static constexpr dart::compiler::target::word ICData_entries_offset = 24; static constexpr dart::compiler::target::word ICData_owner_offset = 40; static constexpr dart::compiler::target::word ICData_state_bits_offset = 52; +static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_shared_class_table_offset = 72; static constexpr dart::compiler::target::word @@ -2160,6 +2164,7 @@ static constexpr dart::compiler::target::word ICData_NumArgsTestedShift = 0; static constexpr dart::compiler::target::word ICData_entries_offset = 12; static constexpr dart::compiler::target::word ICData_owner_offset = 20; static constexpr dart::compiler::target::word ICData_state_bits_offset = 28; +static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_shared_class_table_offset = 36; static constexpr dart::compiler::target::word @@ -2656,6 +2661,7 @@ static constexpr dart::compiler::target::word ICData_NumArgsTestedShift = 0; static constexpr dart::compiler::target::word ICData_entries_offset = 24; static constexpr dart::compiler::target::word ICData_owner_offset = 40; static constexpr dart::compiler::target::word ICData_state_bits_offset = 52; +static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_shared_class_table_offset = 72; static constexpr dart::compiler::target::word @@ -3156,6 +3162,7 @@ static constexpr dart::compiler::target::word ICData_NumArgsTestedShift = 0; static constexpr dart::compiler::target::word ICData_entries_offset = 12; static constexpr dart::compiler::target::word ICData_owner_offset = 20; static constexpr dart::compiler::target::word ICData_state_bits_offset = 28; +static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_shared_class_table_offset = 36; static constexpr dart::compiler::target::word @@ -3649,6 +3656,7 @@ static constexpr dart::compiler::target::word ICData_NumArgsTestedShift = 0; static constexpr dart::compiler::target::word ICData_entries_offset = 24; static constexpr dart::compiler::target::word ICData_owner_offset = 40; static constexpr dart::compiler::target::word ICData_state_bits_offset = 52; +static constexpr dart::compiler::target::word Int32x4_value_offset = 8; static constexpr dart::compiler::target::word Isolate_shared_class_table_offset = 72; static constexpr dart::compiler::target::word @@ -4158,6 +4166,7 @@ static constexpr dart::compiler::target::word AOT_ICData_NumArgsTestedShift = 0; static constexpr dart::compiler::target::word AOT_ICData_entries_offset = 12; static constexpr dart::compiler::target::word AOT_ICData_owner_offset = 16; static constexpr dart::compiler::target::word AOT_ICData_state_bits_offset = 20; +static constexpr dart::compiler::target::word AOT_Int32x4_value_offset = 8; static constexpr dart::compiler::target::word AOT_Isolate_shared_class_table_offset = 36; static constexpr dart::compiler::target::word @@ -4712,6 +4721,7 @@ static constexpr dart::compiler::target::word AOT_ICData_NumArgsTestedShift = 0; static constexpr dart::compiler::target::word AOT_ICData_entries_offset = 24; static constexpr dart::compiler::target::word AOT_ICData_owner_offset = 32; static constexpr dart::compiler::target::word AOT_ICData_state_bits_offset = 40; +static constexpr dart::compiler::target::word AOT_Int32x4_value_offset = 8; static constexpr dart::compiler::target::word AOT_Isolate_shared_class_table_offset = 72; static constexpr dart::compiler::target::word @@ -5272,6 +5282,7 @@ static constexpr dart::compiler::target::word AOT_ICData_NumArgsTestedShift = 0; static constexpr dart::compiler::target::word AOT_ICData_entries_offset = 24; static constexpr dart::compiler::target::word AOT_ICData_owner_offset = 32; static constexpr dart::compiler::target::word AOT_ICData_state_bits_offset = 40; +static constexpr dart::compiler::target::word AOT_Int32x4_value_offset = 8; static constexpr dart::compiler::target::word AOT_Isolate_shared_class_table_offset = 72; static constexpr dart::compiler::target::word @@ -5829,6 +5840,7 @@ static constexpr dart::compiler::target::word AOT_ICData_NumArgsTestedShift = 0; static constexpr dart::compiler::target::word AOT_ICData_entries_offset = 12; static constexpr dart::compiler::target::word AOT_ICData_owner_offset = 16; static constexpr dart::compiler::target::word AOT_ICData_state_bits_offset = 20; +static constexpr dart::compiler::target::word AOT_Int32x4_value_offset = 8; static constexpr dart::compiler::target::word AOT_Isolate_shared_class_table_offset = 36; static constexpr dart::compiler::target::word @@ -6376,6 +6388,7 @@ static constexpr dart::compiler::target::word AOT_ICData_NumArgsTestedShift = 0; static constexpr dart::compiler::target::word AOT_ICData_entries_offset = 24; static constexpr dart::compiler::target::word AOT_ICData_owner_offset = 32; static constexpr dart::compiler::target::word AOT_ICData_state_bits_offset = 40; +static constexpr dart::compiler::target::word AOT_Int32x4_value_offset = 8; static constexpr dart::compiler::target::word AOT_Isolate_shared_class_table_offset = 72; static constexpr dart::compiler::target::word @@ -6929,6 +6942,7 @@ static constexpr dart::compiler::target::word AOT_ICData_NumArgsTestedShift = 0; static constexpr dart::compiler::target::word AOT_ICData_entries_offset = 24; static constexpr dart::compiler::target::word AOT_ICData_owner_offset = 32; static constexpr dart::compiler::target::word AOT_ICData_state_bits_offset = 40; +static constexpr dart::compiler::target::word AOT_Int32x4_value_offset = 8; static constexpr dart::compiler::target::word AOT_Isolate_shared_class_table_offset = 72; static constexpr dart::compiler::target::word diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h index b477334bfc5..0dc6a352dd2 100644 --- a/runtime/vm/compiler/runtime_offsets_list.h +++ b/runtime/vm/compiler/runtime_offsets_list.h @@ -109,6 +109,7 @@ FIELD(ICData, entries_offset) \ FIELD(ICData, owner_offset) \ FIELD(ICData, state_bits_offset) \ + FIELD(Int32x4, value_offset) \ FIELD(Isolate, shared_class_table_offset) \ FIELD(Isolate, cached_class_table_table_offset) \ FIELD(Isolate, current_tag_offset) \ diff --git a/runtime/vm/compiler/write_barrier_elimination.cc b/runtime/vm/compiler/write_barrier_elimination.cc index 4d1e453f453..10b18c5af8f 100644 --- a/runtime/vm/compiler/write_barrier_elimination.cc +++ b/runtime/vm/compiler/write_barrier_elimination.cc @@ -329,14 +329,13 @@ bool WriteBarrierElimination::SlotEligibleForWBE(const Slot& slot) { case Slot::Kind::kDartField: // Instance return true; -#define FOR_EACH_NATIVE_SLOT(class, underlying_type, field, type, modifiers) \ +#define FOR_EACH_NATIVE_SLOT(class, underlying_type, field, __, ___) \ case Slot::Kind::k##class##_##field: \ return std::is_base_of::value || \ std::is_base_of::value || \ std::is_base_of::value; - BOXED_NATIVE_SLOTS_LIST(FOR_EACH_NATIVE_SLOT) - UNBOXED_NATIVE_SLOTS_LIST(FOR_EACH_NATIVE_SLOT) + NATIVE_SLOTS_LIST(FOR_EACH_NATIVE_SLOT) #undef FOR_EACH_NATIVE_SLOT default: