[vm, compiler] Don't touch memory in AssertBoolean and BooleanNegate.

AssertBoolean may assume its input is nullable bool. BooleanNegate may assume its input is non-nullable bool. Use fixed alignment bits to distinguish true, false and null.

TEST=ci
Change-Id: Ife694e66c1225d943881c2325cd67f18575a47e7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/189240
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Ryan Macnak 2021-03-09 20:27:00 +00:00 committed by commit-bot@chromium.org
parent 927d45d013
commit d1605bc5c5
8 changed files with 92 additions and 97 deletions

View file

@ -4504,23 +4504,6 @@ LocationSummary* AssertBooleanInstr::MakeLocationSummary(Zone* zone,
return locs;
}
void AssertBooleanInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// Check that the type of the value is allowed in conditional context.
ASSERT(locs()->always_calls());
auto object_store = compiler->isolate_group()->object_store();
const auto& assert_boolean_stub =
Code::ZoneHandle(compiler->zone(), object_store->assert_boolean_stub());
compiler::Label done;
__ CompareObject(AssertBooleanABI::kObjectReg, Object::null_instance());
__ BranchIf(NOT_EQUAL, &done);
compiler->GenerateStubCall(source(), assert_boolean_stub,
/*kind=*/UntaggedPcDescriptors::kOther, locs(),
deopt_id());
__ Bind(&done);
}
LocationSummary* PhiInstr::MakeLocationSummary(Zone* zone,
bool optimizing) const {
UNREACHABLE();

View file

@ -822,6 +822,23 @@ LocationSummary* AssertAssignableInstr::MakeLocationSummary(Zone* zone,
return summary;
}
void AssertBooleanInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT(locs()->always_calls());
auto object_store = compiler->isolate_group()->object_store();
const auto& assert_boolean_stub =
Code::ZoneHandle(compiler->zone(), object_store->assert_boolean_stub());
compiler::Label done;
__ tst(AssertBooleanABI::kObjectReg,
compiler::Operand(compiler::target::ObjectAlignment::kBoolVsNullMask));
__ b(&done, NOT_ZERO);
compiler->GenerateStubCall(source(), assert_boolean_stub,
/*kind=*/UntaggedPcDescriptors::kOther, locs(),
deopt_id());
__ Bind(&done);
}
static Condition TokenKindToSmiCondition(Token::Kind kind) {
switch (kind) {
case Token::kEQ:
@ -7895,16 +7912,8 @@ LocationSummary* BooleanNegateInstr::MakeLocationSummary(Zone* zone,
void BooleanNegateInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const Register input = locs()->in(0).reg();
const Register result = locs()->out(0).reg();
if (value()->Type()->ToCid() == kBoolCid) {
__ eor(
result, input,
compiler::Operand(compiler::target::ObjectAlignment::kBoolValueMask));
} else {
__ LoadObject(result, Bool::True());
__ cmp(result, compiler::Operand(input));
__ LoadObject(result, Bool::False(), EQ);
}
__ eor(result, input,
compiler::Operand(compiler::target::ObjectAlignment::kBoolValueMask));
}
LocationSummary* AllocateObjectInstr::MakeLocationSummary(Zone* zone,

View file

@ -720,6 +720,21 @@ LocationSummary* AssertAssignableInstr::MakeLocationSummary(Zone* zone,
return summary;
}
void AssertBooleanInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT(locs()->always_calls());
auto object_store = compiler->isolate_group()->object_store();
const auto& assert_boolean_stub =
Code::ZoneHandle(compiler->zone(), object_store->assert_boolean_stub());
compiler::Label done;
__ tbnz(&done, AssertBooleanABI::kObjectReg, kBoolVsNullBitPosition);
compiler->GenerateStubCall(source(), assert_boolean_stub,
/*kind=*/UntaggedPcDescriptors::kOther, locs(),
deopt_id());
__ Bind(&done);
}
static Condition TokenKindToSmiCondition(Token::Kind kind) {
switch (kind) {
case Token::kEQ:
@ -6925,17 +6940,9 @@ LocationSummary* BooleanNegateInstr::MakeLocationSummary(Zone* zone,
void BooleanNegateInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const Register input = locs()->in(0).reg();
const Register result = locs()->out(0).reg();
if (value()->Type()->ToCid() == kBoolCid) {
__ eori(
result, input,
compiler::Immediate(compiler::target::ObjectAlignment::kBoolValueMask));
} else {
__ LoadObject(result, Bool::True());
__ LoadObject(TMP, Bool::False());
__ CompareRegisters(result, input);
__ csel(result, TMP, result, EQ);
}
__ eori(
result, input,
compiler::Immediate(compiler::target::ObjectAlignment::kBoolValueMask));
}
LocationSummary* AllocateObjectInstr::MakeLocationSummary(Zone* zone,

View file

@ -508,6 +508,24 @@ LocationSummary* AssertAssignableInstr::MakeLocationSummary(Zone* zone,
return summary;
}
void AssertBooleanInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT(locs()->always_calls());
auto object_store = compiler->isolate_group()->object_store();
const auto& assert_boolean_stub =
Code::ZoneHandle(compiler->zone(), object_store->assert_boolean_stub());
compiler::Label done;
__ testl(
AssertBooleanABI::kObjectReg,
compiler::Immediate(compiler::target::ObjectAlignment::kBoolVsNullMask));
__ j(NOT_ZERO, &done, compiler::Assembler::kNearJump);
compiler->GenerateStubCall(source(), assert_boolean_stub,
/*kind=*/UntaggedPcDescriptors::kOther, locs(),
deopt_id());
__ Bind(&done);
}
static Condition TokenKindToSmiCondition(Token::Kind kind) {
switch (kind) {
case Token::kEQ:
@ -6836,30 +6854,16 @@ void ClosureCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
LocationSummary* BooleanNegateInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
return LocationSummary::Make(zone, 1,
value()->Type()->ToCid() == kBoolCid
? Location::SameAsFirstInput()
: Location::RequiresRegister(),
return LocationSummary::Make(zone, 1, Location::SameAsFirstInput(),
LocationSummary::kNoCall);
}
void BooleanNegateInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register input = locs()->in(0).reg();
Register result = locs()->out(0).reg();
if (value()->Type()->ToCid() == kBoolCid) {
ASSERT(input == result);
__ xorl(result, compiler::Immediate(
compiler::target::ObjectAlignment::kBoolValueMask));
} else {
ASSERT(input != result);
compiler::Label done;
__ LoadObject(result, Bool::True());
__ CompareRegisters(result, input);
__ j(NOT_EQUAL, &done, compiler::Assembler::kNearJump);
__ LoadObject(result, Bool::False());
__ Bind(&done);
}
ASSERT(input == result);
__ xorl(result, compiler::Immediate(
compiler::target::ObjectAlignment::kBoolValueMask));
}
LocationSummary* AllocateObjectInstr::MakeLocationSummary(Zone* zone,

View file

@ -656,6 +656,24 @@ LocationSummary* AssertAssignableInstr::MakeLocationSummary(Zone* zone,
return summary;
}
void AssertBooleanInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT(locs()->always_calls());
auto object_store = compiler->isolate_group()->object_store();
const auto& assert_boolean_stub =
Code::ZoneHandle(compiler->zone(), object_store->assert_boolean_stub());
compiler::Label done;
__ testq(
AssertBooleanABI::kObjectReg,
compiler::Immediate(compiler::target::ObjectAlignment::kBoolVsNullMask));
__ j(NOT_ZERO, &done, compiler::Assembler::kNearJump);
compiler->GenerateStubCall(source(), assert_boolean_stub,
/*kind=*/UntaggedPcDescriptors::kOther, locs(),
deopt_id());
__ Bind(&done);
}
static Condition TokenKindToIntCondition(Token::Kind kind) {
switch (kind) {
case Token::kEQ:
@ -861,7 +879,6 @@ void ComparisonInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
if (true_condition != kInvalidCondition) {
EmitBranchOnCondition(compiler, true_condition, labels);
}
Register result = locs()->out(0).reg();
compiler::Label done;
__ Bind(&is_false);
@ -7417,30 +7434,16 @@ void ClosureCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
LocationSummary* BooleanNegateInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
return LocationSummary::Make(zone, 1,
value()->Type()->ToCid() == kBoolCid
? Location::SameAsFirstInput()
: Location::RequiresRegister(),
return LocationSummary::Make(zone, 1, Location::SameAsFirstInput(),
LocationSummary::kNoCall);
}
void BooleanNegateInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register input = locs()->in(0).reg();
Register result = locs()->out(0).reg();
if (value()->Type()->ToCid() == kBoolCid) {
ASSERT(input == result);
__ xorq(result, compiler::Immediate(
compiler::target::ObjectAlignment::kBoolValueMask));
} else {
ASSERT(input != result);
compiler::Label done;
__ LoadObject(result, Bool::True());
__ CompareRegisters(result, input);
__ j(NOT_EQUAL, &done, compiler::Assembler::kNearJump);
__ LoadObject(result, Bool::False());
__ Bind(&done);
}
ASSERT(input == result);
__ xorq(result, compiler::Immediate(
compiler::target::ObjectAlignment::kBoolValueMask));
}
LocationSummary* AllocateObjectInstr::MakeLocationSummary(Zone* zone,

View file

@ -569,6 +569,9 @@ void Object::InitNullAndBool(IsolateGroup* isolate_group) {
ASSERT((static_cast<uword>(false_) & kBoolValueMask) != 0);
ASSERT(static_cast<uword>(false_) ==
(static_cast<uword>(true_) | kBoolValueMask));
ASSERT((static_cast<uword>(null_) & kBoolVsNullMask) == 0);
ASSERT((static_cast<uword>(true_) & kBoolVsNullMask) != 0);
ASSERT((static_cast<uword>(false_) & kBoolVsNullMask) != 0);
}
void Object::InitVtables() {
@ -23581,23 +23584,6 @@ ExternalTwoByteStringPtr ExternalTwoByteString::New(
return ExternalTwoByteString::raw(result);
}
BoolPtr Bool::New(bool value) {
ASSERT(IsolateGroup::Current()->object_store()->bool_class() !=
Class::null());
Bool& result = Bool::Handle();
{
// Since the two boolean instances are singletons we allocate them straight
// in the old generation.
ObjectPtr raw =
Object::Allocate(Bool::kClassId, Bool::InstanceSize(), Heap::kOld);
NoSafepointScope no_safepoint;
result ^= raw;
}
result.set_value(value);
result.SetCanonical();
return result.ptr();
}
const char* Bool::ToCString() const {
return value() ? "true" : "false";
}

View file

@ -9583,11 +9583,6 @@ class Bool : public Instance {
}
private:
void set_value(bool value) const { StoreNonPointer(&untag()->value_, value); }
// New should only be called to initialize the two legal bool values.
static BoolPtr New(bool value);
FINAL_HEAP_OBJECT_IMPLEMENTATION(Bool, Instance);
friend class Class;
friend class Object; // To initialize the true and false values.

View file

@ -37,6 +37,10 @@ struct ObjectAlignment {
static constexpr intptr_t kBoolValueBitPosition = kObjectAlignmentLog2;
static constexpr intptr_t kBoolValueMask = 1 << kBoolValueBitPosition;
// Discriminate between bool and null based on bit after the alignment bit.
static constexpr intptr_t kBoolVsNullBitPosition = kObjectAlignmentLog2 + 1;
static constexpr intptr_t kBoolVsNullMask = 1 << kBoolVsNullBitPosition;
static constexpr intptr_t kTrueOffsetFromNull = kObjectAlignment * 2;
static constexpr intptr_t kFalseOffsetFromNull = kObjectAlignment * 3;
};
@ -58,6 +62,10 @@ static constexpr intptr_t kObjectAlignmentMask =
static constexpr intptr_t kBoolValueBitPosition =
HostObjectAlignment::kBoolValueBitPosition;
static constexpr intptr_t kBoolValueMask = HostObjectAlignment::kBoolValueMask;
static constexpr intptr_t kBoolVsNullBitPosition =
HostObjectAlignment::kBoolVsNullBitPosition;
static constexpr intptr_t kBoolVsNullMask =
HostObjectAlignment::kBoolVsNullMask;
static constexpr intptr_t kTrueOffsetFromNull =
HostObjectAlignment::kTrueOffsetFromNull;
static constexpr intptr_t kFalseOffsetFromNull =