[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 <sstrickl@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Clement Skau <cskau@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
65968a481b
commit
e5cf5d9502
@@ -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);
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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; \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -46,16 +46,15 @@ class SlotCache : public ZoneAllocated {
|
||||
DirectChainedHashMap<PointerKeyValueTrait<const Slot> > 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<uint8_t>(kind) < ARRAY_SIZE(fields));
|
||||
|
||||
@@ -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_; }
|
||||
|
||||
@@ -714,6 +714,7 @@ class ExternalTwoByteString : public AllStatic {
|
||||
|
||||
class Int32x4 : public AllStatic {
|
||||
public:
|
||||
static word value_offset();
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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<InstanceLayout, underlying_type>::value || \
|
||||
std::is_base_of<ContextLayout, underlying_type>::value || \
|
||||
std::is_base_of<UnhandledExceptionLayout, underlying_type>::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:
|
||||
|
||||
Reference in New Issue
Block a user