mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 13:08:01 +00:00
[vm, gc] Don't use alignment bits when verifying eliminated write barriers.
TEST=ci Change-Id: I6affde0b9db6ec951458905391670fe602dd3b61 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/262266 Reviewed-by: Alexander Markov <alexmarkov@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
parent
9a53b32c9c
commit
7e4f448f78
|
@ -1704,38 +1704,6 @@ void Assembler::CompareObject(Register rn, const Object& object) {
|
|||
}
|
||||
}
|
||||
|
||||
// Preserves object and value registers.
|
||||
void Assembler::StoreIntoObjectFilter(Register object,
|
||||
Register value,
|
||||
Label* label,
|
||||
CanBeSmi value_can_be_smi,
|
||||
BarrierFilterMode how_to_jump) {
|
||||
COMPILE_ASSERT((target::ObjectAlignment::kNewObjectAlignmentOffset ==
|
||||
target::kWordSize) &&
|
||||
(target::ObjectAlignment::kOldObjectAlignmentOffset == 0));
|
||||
// For the value we are only interested in the new/old bit and the tag bit.
|
||||
// And the new bit with the tag bit. The resulting bit will be 0 for a Smi.
|
||||
if (value_can_be_smi == kValueCanBeSmi) {
|
||||
and_(
|
||||
IP, value,
|
||||
Operand(value, LSL, target::ObjectAlignment::kObjectAlignmentLog2 - 1));
|
||||
// And the result with the negated space bit of the object.
|
||||
bic(IP, IP, Operand(object));
|
||||
} else {
|
||||
#if defined(DEBUG)
|
||||
Label okay;
|
||||
BranchIfNotSmi(value, &okay);
|
||||
Stop("Unexpected Smi!");
|
||||
Bind(&okay);
|
||||
#endif
|
||||
bic(IP, value, Operand(object));
|
||||
}
|
||||
tst(IP, Operand(target::ObjectAlignment::kNewObjectAlignmentOffset));
|
||||
if (how_to_jump != kNoJump) {
|
||||
b(label, how_to_jump == kJumpToNoUpdate ? EQ : NE);
|
||||
}
|
||||
}
|
||||
|
||||
Register UseRegister(Register reg, RegList* used) {
|
||||
ASSERT(reg != THR);
|
||||
ASSERT(reg != SP);
|
||||
|
@ -1782,7 +1750,7 @@ void Assembler::StoreIntoObject(Register object,
|
|||
// Compare UntaggedObject::StorePointer.
|
||||
Label done;
|
||||
if (can_be_smi == kValueCanBeSmi) {
|
||||
BranchIfSmi(value, &done);
|
||||
BranchIfSmi(value, &done, kNearJump);
|
||||
}
|
||||
const bool preserve_lr = lr_state().LRContainsReturnAddress();
|
||||
if (preserve_lr) {
|
||||
|
@ -1853,7 +1821,7 @@ void Assembler::StoreIntoArray(Register object,
|
|||
// Compare UntaggedObject::StorePointer.
|
||||
Label done;
|
||||
if (can_be_smi == kValueCanBeSmi) {
|
||||
BranchIfSmi(value, &done);
|
||||
BranchIfSmi(value, &done, kNearJump);
|
||||
}
|
||||
const bool preserve_lr = lr_state().LRContainsReturnAddress();
|
||||
if (preserve_lr) {
|
||||
|
@ -1915,13 +1883,14 @@ void Assembler::StoreIntoObjectNoBarrier(Register object,
|
|||
// reachable via a constant pool, so it doesn't matter if it is not traced via
|
||||
// 'object'.
|
||||
Label done;
|
||||
StoreIntoObjectFilter(object, value, &done, kValueCanBeSmi, kJumpToNoUpdate);
|
||||
|
||||
BranchIfSmi(value, &done, kNearJump);
|
||||
ldrb(TMP, FieldAddress(value, target::Object::tags_offset()));
|
||||
tst(TMP, Operand(1 << target::UntaggedObject::kNewBit));
|
||||
b(&done, ZERO);
|
||||
ldrb(TMP, FieldAddress(object, target::Object::tags_offset()));
|
||||
tst(TMP, Operand(1 << target::UntaggedObject::kOldAndNotRememberedBit));
|
||||
b(&done, ZERO);
|
||||
|
||||
Stop("Store buffer update is required");
|
||||
Stop("Write barrier is required");
|
||||
Bind(&done);
|
||||
#endif // defined(DEBUG)
|
||||
// No store buffer update.
|
||||
|
@ -1998,16 +1967,6 @@ void Assembler::InitializeFieldsNoBarrier(Register object,
|
|||
strd(value_even, value_odd, begin, -2 * target::kWordSize, LS);
|
||||
b(&init_loop, CC);
|
||||
str(value_even, Address(begin, -2 * target::kWordSize), HI);
|
||||
#if defined(DEBUG)
|
||||
Label done;
|
||||
StoreIntoObjectFilter(object, value_even, &done, kValueCanBeSmi,
|
||||
kJumpToNoUpdate);
|
||||
StoreIntoObjectFilter(object, value_odd, &done, kValueCanBeSmi,
|
||||
kJumpToNoUpdate);
|
||||
Stop("Store buffer update is required");
|
||||
Bind(&done);
|
||||
#endif // defined(DEBUG)
|
||||
// No store buffer update.
|
||||
}
|
||||
|
||||
void Assembler::InitializeFieldsNoBarrierUnrolled(Register object,
|
||||
|
@ -2026,16 +1985,6 @@ void Assembler::InitializeFieldsNoBarrierUnrolled(Register object,
|
|||
str(value_even, Address(base, current_offset));
|
||||
current_offset += target::kWordSize;
|
||||
}
|
||||
#if defined(DEBUG)
|
||||
Label done;
|
||||
StoreIntoObjectFilter(object, value_even, &done, kValueCanBeSmi,
|
||||
kJumpToNoUpdate);
|
||||
StoreIntoObjectFilter(object, value_odd, &done, kValueCanBeSmi,
|
||||
kJumpToNoUpdate);
|
||||
Stop("Store buffer update is required");
|
||||
Bind(&done);
|
||||
#endif // defined(DEBUG)
|
||||
// No store buffer update.
|
||||
}
|
||||
|
||||
void Assembler::StoreIntoSmiField(const Address& dest, Register value) {
|
||||
|
|
|
@ -1645,27 +1645,6 @@ class Assembler : public AssemblerBase {
|
|||
int32_t EncodeTstOffset(int32_t offset, int32_t inst);
|
||||
int32_t DecodeTstOffset(int32_t inst);
|
||||
|
||||
enum BarrierFilterMode {
|
||||
// Filter falls through into the barrier update code. Target label
|
||||
// is a "after-store" label.
|
||||
kJumpToNoUpdate,
|
||||
|
||||
// Filter falls through to the "after-store" code. Target label
|
||||
// is barrier update code label.
|
||||
kJumpToBarrier,
|
||||
|
||||
// Filter falls through into the conditional barrier update code and does
|
||||
// not jump. Target label is unused. The barrier should run if the NE
|
||||
// condition is set.
|
||||
kNoJump
|
||||
};
|
||||
|
||||
void StoreIntoObjectFilter(Register object,
|
||||
Register value,
|
||||
Label* label,
|
||||
CanBeSmi can_be_smi,
|
||||
BarrierFilterMode barrier_filter_mode);
|
||||
|
||||
friend class dart::FlowGraphCompiler;
|
||||
std::function<void(Condition, Register)>
|
||||
generate_invoke_write_barrier_wrapper_;
|
||||
|
|
|
@ -994,43 +994,6 @@ void Assembler::LoadCompressedSmiFromOffset(Register dest,
|
|||
#endif
|
||||
}
|
||||
|
||||
// Preserves object and value registers.
|
||||
void Assembler::StoreIntoObjectFilter(Register object,
|
||||
Register value,
|
||||
Label* label,
|
||||
CanBeSmi value_can_be_smi,
|
||||
BarrierFilterMode how_to_jump) {
|
||||
COMPILE_ASSERT((target::ObjectAlignment::kNewObjectAlignmentOffset ==
|
||||
target::kWordSize) &&
|
||||
(target::ObjectAlignment::kOldObjectAlignmentOffset == 0));
|
||||
|
||||
// Write-barrier triggers if the value is in the new space (has bit set) and
|
||||
// the object is in the old space (has bit cleared).
|
||||
if (value_can_be_smi == kValueIsNotSmi) {
|
||||
#if defined(DEBUG)
|
||||
Label okay;
|
||||
BranchIfNotSmi(value, &okay);
|
||||
Stop("Unexpected Smi!");
|
||||
Bind(&okay);
|
||||
#endif
|
||||
// To check that, we compute value & ~object and skip the write barrier
|
||||
// if the bit is not set. We can't destroy the object.
|
||||
bic(TMP, value, Operand(object));
|
||||
} else {
|
||||
// For the value we are only interested in the new/old bit and the tag bit.
|
||||
// And the new bit with the tag bit. The resulting bit will be 0 for a Smi.
|
||||
and_(TMP, value,
|
||||
Operand(value, LSL, target::ObjectAlignment::kNewObjectBitPosition));
|
||||
// And the result with the negated space bit of the object.
|
||||
bic(TMP, TMP, Operand(object));
|
||||
}
|
||||
if (how_to_jump == kJumpToNoUpdate) {
|
||||
tbz(label, TMP, target::ObjectAlignment::kNewObjectBitPosition);
|
||||
} else {
|
||||
tbnz(label, TMP, target::ObjectAlignment::kNewObjectBitPosition);
|
||||
}
|
||||
}
|
||||
|
||||
void Assembler::StoreIntoObjectOffset(Register object,
|
||||
int32_t offset,
|
||||
Register value,
|
||||
|
@ -1220,13 +1183,12 @@ void Assembler::StoreIntoObjectNoBarrier(Register object,
|
|||
// reachable via a constant pool, so it doesn't matter if it is not traced via
|
||||
// 'object'.
|
||||
Label done;
|
||||
StoreIntoObjectFilter(object, value, &done, kValueCanBeSmi, kJumpToNoUpdate);
|
||||
|
||||
BranchIfSmi(value, &done, kNearJump);
|
||||
ldr(TMP, FieldAddress(value, target::Object::tags_offset()), kUnsignedByte);
|
||||
tbz(&done, TMP, target::UntaggedObject::kNewBit);
|
||||
ldr(TMP, FieldAddress(object, target::Object::tags_offset()), kUnsignedByte);
|
||||
tsti(TMP, Immediate(1 << target::UntaggedObject::kOldAndNotRememberedBit));
|
||||
b(&done, ZERO);
|
||||
|
||||
Stop("Store buffer update is required");
|
||||
tbz(&done, TMP, target::UntaggedObject::kOldAndNotRememberedBit);
|
||||
Stop("Write barrier is required");
|
||||
Bind(&done);
|
||||
#endif // defined(DEBUG)
|
||||
// No store buffer update.
|
||||
|
@ -1246,13 +1208,12 @@ void Assembler::StoreCompressedIntoObjectNoBarrier(Register object,
|
|||
// reachable via a constant pool, so it doesn't matter if it is not traced via
|
||||
// 'object'.
|
||||
Label done;
|
||||
StoreIntoObjectFilter(object, value, &done, kValueCanBeSmi, kJumpToNoUpdate);
|
||||
|
||||
BranchIfSmi(value, &done, kNearJump);
|
||||
ldr(TMP, FieldAddress(value, target::Object::tags_offset()), kUnsignedByte);
|
||||
tbz(&done, TMP, target::UntaggedObject::kNewBit);
|
||||
ldr(TMP, FieldAddress(object, target::Object::tags_offset()), kUnsignedByte);
|
||||
tsti(TMP, Immediate(1 << target::UntaggedObject::kOldAndNotRememberedBit));
|
||||
b(&done, ZERO);
|
||||
|
||||
Stop("Store buffer update is required");
|
||||
tbz(&done, TMP, target::UntaggedObject::kOldAndNotRememberedBit);
|
||||
Stop("Write barrier is required");
|
||||
Bind(&done);
|
||||
#endif // defined(DEBUG)
|
||||
// No store buffer update.
|
||||
|
|
|
@ -2982,22 +2982,6 @@ class Assembler : public AssemblerBase {
|
|||
Emit(encoding);
|
||||
}
|
||||
|
||||
enum BarrierFilterMode {
|
||||
// Filter falls through into the barrier update code. Target label
|
||||
// is a "after-store" label.
|
||||
kJumpToNoUpdate,
|
||||
|
||||
// Filter falls through to the "after-store" code. Target label
|
||||
// is barrier update code label.
|
||||
kJumpToBarrier,
|
||||
};
|
||||
|
||||
void StoreIntoObjectFilter(Register object,
|
||||
Register value,
|
||||
Label* label,
|
||||
CanBeSmi can_be_smi,
|
||||
BarrierFilterMode barrier_filter_mode);
|
||||
|
||||
friend class dart::FlowGraphCompiler;
|
||||
std::function<void(Register reg)> generate_invoke_write_barrier_wrapper_;
|
||||
std::function<void()> generate_invoke_array_write_barrier_;
|
||||
|
|
|
@ -2086,16 +2086,15 @@ void Assembler::StoreIntoObjectNoBarrier(Register object,
|
|||
// reachable via a constant pool, so it doesn't matter if it is not traced via
|
||||
// 'object'.
|
||||
Label done;
|
||||
pushl(value);
|
||||
StoreIntoObjectFilter(object, value, &done, kValueCanBeSmi, kJumpToNoUpdate);
|
||||
|
||||
BranchIfSmi(value, &done, kNearJump);
|
||||
testb(FieldAddress(value, target::Object::tags_offset()),
|
||||
Immediate(1 << target::UntaggedObject::kNewBit));
|
||||
j(ZERO, &done, Assembler::kNearJump);
|
||||
testb(FieldAddress(object, target::Object::tags_offset()),
|
||||
Immediate(1 << target::UntaggedObject::kOldAndNotRememberedBit));
|
||||
j(ZERO, &done, Assembler::kNearJump);
|
||||
|
||||
Stop("Store buffer update is required");
|
||||
Stop("Write barrier is required");
|
||||
Bind(&done);
|
||||
popl(value);
|
||||
#endif // defined(DEBUG)
|
||||
// No store buffer update.
|
||||
}
|
||||
|
|
|
@ -3144,15 +3144,14 @@ void Assembler::StoreIntoObjectNoBarrier(Register object,
|
|||
// reachable via a constant pool, so it doesn't matter if it is not traced via
|
||||
// 'object'.
|
||||
Label done;
|
||||
beq(object, value, &done, kNearJump);
|
||||
BranchIfSmi(value, &done, kNearJump);
|
||||
lbu(TMP, FieldAddress(object, target::Object::tags_offset()));
|
||||
lbu(TMP2, FieldAddress(value, target::Object::tags_offset()));
|
||||
srli(TMP, TMP, target::UntaggedObject::kBarrierOverlapShift);
|
||||
and_(TMP, TMP, TMP2);
|
||||
andi(TMP, TMP, target::UntaggedObject::kGenerationalBarrierMask);
|
||||
beqz(TMP, &done, kNearJump);
|
||||
Stop("Store buffer update is required");
|
||||
andi(TMP2, TMP2, 1 << target::UntaggedObject::kNewBit);
|
||||
beqz(TMP2, &done, kNearJump);
|
||||
lbu(TMP2, FieldAddress(object, target::Object::tags_offset()));
|
||||
andi(TMP2, TMP2, 1 << target::UntaggedObject::kOldAndNotRememberedBit);
|
||||
beqz(TMP2, &done, kNearJump);
|
||||
Stop("Write barrier is required");
|
||||
Bind(&done);
|
||||
#endif
|
||||
}
|
||||
|
@ -3178,15 +3177,14 @@ void Assembler::StoreIntoObjectOffsetNoBarrier(Register object,
|
|||
// reachable via a constant pool, so it doesn't matter if it is not traced via
|
||||
// 'object'.
|
||||
Label done;
|
||||
beq(object, value, &done, kNearJump);
|
||||
BranchIfSmi(value, &done, kNearJump);
|
||||
lbu(TMP, FieldAddress(object, target::Object::tags_offset()));
|
||||
lbu(TMP2, FieldAddress(value, target::Object::tags_offset()));
|
||||
srli(TMP, TMP, target::UntaggedObject::kBarrierOverlapShift);
|
||||
and_(TMP, TMP, TMP2);
|
||||
andi(TMP, TMP, target::UntaggedObject::kGenerationalBarrierMask);
|
||||
beqz(TMP, &done, kNearJump);
|
||||
Stop("Store buffer update is required");
|
||||
andi(TMP2, TMP2, 1 << target::UntaggedObject::kNewBit);
|
||||
beqz(TMP2, &done, kNearJump);
|
||||
lbu(TMP2, FieldAddress(object, target::Object::tags_offset()));
|
||||
andi(TMP2, TMP2, 1 << target::UntaggedObject::kOldAndNotRememberedBit);
|
||||
beqz(TMP2, &done, kNearJump);
|
||||
Stop("Write barrier is required");
|
||||
Bind(&done);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1478,22 +1478,6 @@ class Assembler : public MicroAssembler {
|
|||
// Note: the function never clobbers TMP, TMP2 scratch registers.
|
||||
void LoadObjectHelper(Register dst, const Object& obj, bool is_unique);
|
||||
|
||||
enum BarrierFilterMode {
|
||||
// Filter falls through into the barrier update code. Target label
|
||||
// is a "after-store" label.
|
||||
kJumpToNoUpdate,
|
||||
|
||||
// Filter falls through to the "after-store" code. Target label
|
||||
// is barrier update code label.
|
||||
kJumpToBarrier,
|
||||
};
|
||||
|
||||
void StoreIntoObjectFilter(Register object,
|
||||
Register value,
|
||||
Label* label,
|
||||
CanBeSmi can_be_smi,
|
||||
BarrierFilterMode barrier_filter_mode);
|
||||
|
||||
friend class dart::FlowGraphCompiler;
|
||||
std::function<void(Register reg)> generate_invoke_write_barrier_wrapper_;
|
||||
std::function<void()> generate_invoke_array_write_barrier_;
|
||||
|
|
|
@ -1434,44 +1434,6 @@ void Assembler::LoadCompressedSmi(Register dest, const Address& slot) {
|
|||
#endif
|
||||
}
|
||||
|
||||
// Destroys the value register.
|
||||
void Assembler::StoreIntoObjectFilter(Register object,
|
||||
Register value,
|
||||
Label* label,
|
||||
CanBeSmi can_be_smi,
|
||||
BarrierFilterMode how_to_jump) {
|
||||
COMPILE_ASSERT((target::ObjectAlignment::kNewObjectAlignmentOffset ==
|
||||
target::kWordSize) &&
|
||||
(target::ObjectAlignment::kOldObjectAlignmentOffset == 0));
|
||||
|
||||
if (can_be_smi == kValueIsNotSmi) {
|
||||
#if defined(DEBUG)
|
||||
Label okay;
|
||||
BranchIfNotSmi(value, &okay);
|
||||
Stop("Unexpected Smi!");
|
||||
Bind(&okay);
|
||||
#endif
|
||||
// Write-barrier triggers if the value is in the new space (has bit set) and
|
||||
// the object is in the old space (has bit cleared).
|
||||
// To check that we could compute value & ~object and skip the write barrier
|
||||
// if the bit is not set. However we can't destroy the object.
|
||||
// However to preserve the object we compute negated expression
|
||||
// ~value | object instead and skip the write barrier if the bit is set.
|
||||
notl(value);
|
||||
orl(value, object);
|
||||
testl(value, Immediate(target::ObjectAlignment::kNewObjectAlignmentOffset));
|
||||
} else {
|
||||
ASSERT(kHeapObjectTag == 1);
|
||||
// Detect value being ...1001 and object being ...0001.
|
||||
andl(value, Immediate(0xf));
|
||||
leal(value, Address(value, object, TIMES_2, 0x15));
|
||||
testl(value, Immediate(0x1f));
|
||||
}
|
||||
Condition condition = how_to_jump == kJumpToNoUpdate ? NOT_ZERO : ZERO;
|
||||
JumpDistance distance = how_to_jump == kJumpToNoUpdate ? kNearJump : kFarJump;
|
||||
j(condition, label, distance);
|
||||
}
|
||||
|
||||
void Assembler::StoreIntoObject(Register object,
|
||||
const Address& dest,
|
||||
Register value,
|
||||
|
@ -1515,8 +1477,7 @@ void Assembler::StoreBarrier(Register object,
|
|||
// Compare UntaggedObject::StorePointer.
|
||||
Label done;
|
||||
if (can_be_smi == kValueCanBeSmi) {
|
||||
testq(value, Immediate(kSmiTagMask));
|
||||
j(ZERO, &done, kNearJump);
|
||||
BranchIfSmi(value, &done, kNearJump);
|
||||
}
|
||||
movb(ByteRegisterOf(TMP),
|
||||
FieldAddress(object, target::Object::tags_offset()));
|
||||
|
@ -1582,8 +1543,7 @@ void Assembler::StoreIntoArrayBarrier(Register object,
|
|||
// Compare UntaggedObject::StorePointer.
|
||||
Label done;
|
||||
if (can_be_smi == kValueCanBeSmi) {
|
||||
testq(value, Immediate(kSmiTagMask));
|
||||
j(ZERO, &done, kNearJump);
|
||||
BranchIfSmi(value, &done, kNearJump);
|
||||
}
|
||||
movb(ByteRegisterOf(TMP),
|
||||
FieldAddress(object, target::Object::tags_offset()));
|
||||
|
@ -1621,16 +1581,15 @@ void Assembler::StoreIntoObjectNoBarrier(Register object,
|
|||
// reachable via a constant pool, so it doesn't matter if it is not traced via
|
||||
// 'object'.
|
||||
Label done;
|
||||
pushq(value);
|
||||
StoreIntoObjectFilter(object, value, &done, kValueCanBeSmi, kJumpToNoUpdate);
|
||||
|
||||
BranchIfSmi(value, &done, kNearJump);
|
||||
testb(FieldAddress(value, target::Object::tags_offset()),
|
||||
Immediate(1 << target::UntaggedObject::kNewBit));
|
||||
j(ZERO, &done, Assembler::kNearJump);
|
||||
testb(FieldAddress(object, target::Object::tags_offset()),
|
||||
Immediate(1 << target::UntaggedObject::kOldAndNotRememberedBit));
|
||||
j(ZERO, &done, Assembler::kNearJump);
|
||||
|
||||
Stop("Store buffer update is required");
|
||||
Stop("Write barrier is required");
|
||||
Bind(&done);
|
||||
popq(value);
|
||||
#endif // defined(DEBUG)
|
||||
// No store buffer update.
|
||||
}
|
||||
|
@ -1651,16 +1610,15 @@ void Assembler::StoreCompressedIntoObjectNoBarrier(Register object,
|
|||
// reachable via a constant pool, so it doesn't matter if it is not traced via
|
||||
// 'object'.
|
||||
Label done;
|
||||
pushq(value);
|
||||
StoreIntoObjectFilter(object, value, &done, kValueCanBeSmi, kJumpToNoUpdate);
|
||||
|
||||
BranchIfSmi(value, &done, kNearJump);
|
||||
testb(FieldAddress(value, target::Object::tags_offset()),
|
||||
Immediate(1 << target::UntaggedObject::kNewBit));
|
||||
j(ZERO, &done, Assembler::kNearJump);
|
||||
testb(FieldAddress(object, target::Object::tags_offset()),
|
||||
Immediate(1 << target::UntaggedObject::kOldAndNotRememberedBit));
|
||||
j(ZERO, &done, Assembler::kNearJump);
|
||||
|
||||
Stop("Store buffer update is required");
|
||||
Stop("Write barrier is required");
|
||||
Bind(&done);
|
||||
popq(value);
|
||||
#endif // defined(DEBUG)
|
||||
// No store buffer update.
|
||||
}
|
||||
|
|
|
@ -1491,11 +1491,6 @@ class Assembler : public AssemblerBase {
|
|||
kJumpToBarrier,
|
||||
};
|
||||
|
||||
void StoreIntoObjectFilter(Register object,
|
||||
Register value,
|
||||
Label* label,
|
||||
CanBeSmi can_be_smi,
|
||||
BarrierFilterMode barrier_filter_mode);
|
||||
void StoreIntoArrayBarrier(Register object,
|
||||
Register slot,
|
||||
Register value,
|
||||
|
|
|
@ -360,6 +360,8 @@ const word UntaggedObject::kCardRememberedBit =
|
|||
|
||||
const word UntaggedObject::kCanonicalBit = dart::UntaggedObject::kCanonicalBit;
|
||||
|
||||
const word UntaggedObject::kNewBit = dart::UntaggedObject::kNewBit;
|
||||
|
||||
const word UntaggedObject::kOldAndNotRememberedBit =
|
||||
dart::UntaggedObject::kOldAndNotRememberedBit;
|
||||
|
||||
|
|
|
@ -411,6 +411,7 @@ class UntaggedObject : public AllStatic {
|
|||
public:
|
||||
static const word kCardRememberedBit;
|
||||
static const word kCanonicalBit;
|
||||
static const word kNewBit;
|
||||
static const word kOldAndNotRememberedBit;
|
||||
static const word kOldAndNotMarkedBit;
|
||||
static const word kImmutableBit;
|
||||
|
|
Loading…
Reference in a new issue