[vm, gc] Implement the incremental marking barrier for IA32.

Enable concurrent marking for IA32.

This removes the last write barrier relying on different alignment offsets for old and new space.

TEST=ci
Change-Id: Ib1c13124002392cf1c3ec264643325ec471a6918
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/262280
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Ryan Macnak 2022-10-05 18:08:32 +00:00 committed by Commit Queue
parent c515938ee4
commit 1bff4bead9
12 changed files with 285 additions and 217 deletions

View file

@ -1289,6 +1289,19 @@ void Assembler::testl(Register reg, const Immediate& immediate) {
}
}
void Assembler::testl(const Address& address, const Immediate& immediate) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF7);
EmitOperand(0, address);
EmitImmediate(immediate);
}
void Assembler::testl(const Address& address, Register reg) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x85);
EmitOperand(reg, address);
}
void Assembler::testb(const Address& address, const Immediate& imm) {
ASSERT(imm.is_int8());
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
@ -1297,6 +1310,12 @@ void Assembler::testb(const Address& address, const Immediate& imm) {
EmitUint8(imm.value() & 0xFF);
}
void Assembler::testb(const Address& address, ByteRegister reg) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x84);
EmitOperand(reg, address);
}
void Assembler::Alu(int bytes, uint8_t opcode, Register dst, Register src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
if (bytes == 2) {
@ -2003,49 +2022,12 @@ void Assembler::CompareObject(Register reg, const Object& object) {
}
}
// Destroys the value register.
void Assembler::StoreIntoObjectFilter(Register object,
Register value,
Label* label,
CanBeSmi can_be_smi,
BarrierFilterMode how_to_jump) {
if (can_be_smi == kValueIsNotSmi) {
#if defined(DEBUG)
Label okay;
BranchIfNotSmi(value, &okay);
Stop("Unexpected Smi!");
Bind(&okay);
#endif
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).
// 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(target::ObjectAlignment::kNewObjectAlignmentOffset == 4);
ASSERT(kHeapObjectTag == 1);
// Detect value being ...101 and object being ...001.
andl(value, Immediate(7));
leal(value, Address(value, object, TIMES_2, 9));
testl(value, Immediate(0xf));
}
Condition condition = how_to_jump == kJumpToNoUpdate ? NOT_ZERO : ZERO;
auto const distance = how_to_jump == kJumpToNoUpdate ? kNearJump : kFarJump;
j(condition, label, distance);
}
void Assembler::StoreIntoObject(Register object,
const Address& dest,
Register value,
CanBeSmi can_be_smi,
MemoryOrder memory_order) {
MemoryOrder memory_order,
Register scratch) {
// x.slot = x. Barrier should have be removed at the IL level.
ASSERT(object != value);
@ -2054,18 +2036,65 @@ void Assembler::StoreIntoObject(Register object,
} else {
movl(dest, value);
}
Label done;
StoreIntoObjectFilter(object, value, &done, can_be_smi, kJumpToNoUpdate);
// A store buffer update is required.
if (object != EDX) {
if (value != EDX) {
pushl(EDX); // Preserve EDX.
bool spill_scratch = false;
if (scratch == kNoRegister) {
spill_scratch = true;
if (object != EAX && value != EAX) {
scratch = EAX;
} else if (object != EBX && value != EBX) {
scratch = EBX;
} else {
scratch = ECX;
}
movl(EDX, object);
}
call(Address(THR, target::Thread::write_barrier_entry_point_offset()));
if ((object != EDX) && (value != EDX)) {
popl(EDX); // Restore EDX.
ASSERT(scratch != object);
ASSERT(scratch != value);
// In parallel, test whether
// - object is old and not remembered and value is new, or
// - object is old and value is old and not marked and concurrent marking is
// in progress
// If so, call the WriteBarrier stub, which will either add object to the
// store buffer (case 1) or add value to the marking stack (case 2).
// Compare UntaggedObject::StorePointer.
Label done;
if (can_be_smi == kValueCanBeSmi) {
BranchIfSmi(value, &done, kNearJump);
}
if (spill_scratch) {
pushl(scratch);
}
movl(scratch, FieldAddress(object, target::Object::tags_offset()));
shrl(scratch, Immediate(target::UntaggedObject::kBarrierOverlapShift));
andl(scratch, Address(THR, target::Thread::write_barrier_mask_offset()));
testl(FieldAddress(value, target::Object::tags_offset()), scratch);
if (spill_scratch) {
popl(scratch);
}
j(ZERO, &done, kNearJump);
Register object_for_call = object;
if (value != kWriteBarrierValueReg) {
// Unlikely. Only non-graph intrinsics.
// TODO(rmacnak): Shuffle registers in intrinsics.
pushl(kWriteBarrierValueReg);
if (object == kWriteBarrierValueReg) {
COMPILE_ASSERT(EAX != kWriteBarrierValueReg);
COMPILE_ASSERT(ECX != kWriteBarrierValueReg);
object_for_call = (value == EAX) ? ECX : EAX;
pushl(object_for_call);
movl(object_for_call, object);
}
movl(kWriteBarrierValueReg, value);
}
call(Address(THR, target::Thread::write_barrier_wrappers_thread_offset(
object_for_call)));
if (value != kWriteBarrierValueReg) {
if (object == kWriteBarrierValueReg) {
popl(object_for_call);
}
popl(kWriteBarrierValueReg);
}
Bind(&done);
}
@ -2096,48 +2125,46 @@ void Assembler::StoreIntoObjectNoBarrier(Register object,
Stop("Write barrier is required");
Bind(&done);
#endif // defined(DEBUG)
// No store buffer update.
}
// Destroys the value register.
void Assembler::StoreIntoArray(Register object,
Register slot,
Register value,
CanBeSmi can_be_smi) {
CanBeSmi can_be_smi,
Register scratch) {
ASSERT(object != value);
movl(Address(slot, 0), value);
ASSERT(scratch != kNoRegister);
ASSERT(scratch != object);
ASSERT(scratch != value);
ASSERT(scratch != slot);
// In parallel, test whether
// - object is old and not remembered and value is new, or
// - object is old and value is old and not marked and concurrent marking is
// in progress
// If so, call the WriteBarrier stub, which will either add object to the
// store buffer (case 1) or add value to the marking stack (case 2).
// Compare UntaggedObject::StorePointer.
Label done;
StoreIntoObjectFilter(object, value, &done, can_be_smi, kJumpToNoUpdate);
// A store buffer update is required.
if (value != kWriteBarrierObjectReg) {
pushl(kWriteBarrierObjectReg); // Preserve kWriteBarrierObjectReg.
if (can_be_smi == kValueCanBeSmi) {
BranchIfSmi(value, &done, kNearJump);
}
if (value != kWriteBarrierSlotReg && slot != kWriteBarrierSlotReg) {
pushl(kWriteBarrierSlotReg); // Preserve kWriteBarrierSlotReg.
}
if (object != kWriteBarrierObjectReg && slot != kWriteBarrierSlotReg) {
if (slot == kWriteBarrierObjectReg && object == kWriteBarrierSlotReg) {
xchgl(slot, object);
} else if (slot == kWriteBarrierObjectReg) {
movl(kWriteBarrierSlotReg, slot);
movl(kWriteBarrierObjectReg, object);
} else {
movl(kWriteBarrierObjectReg, object);
movl(kWriteBarrierSlotReg, slot);
}
} else if (object != kWriteBarrierObjectReg) {
movl(kWriteBarrierObjectReg, object);
} else if (slot != kWriteBarrierSlotReg) {
movl(kWriteBarrierSlotReg, slot);
movl(scratch, FieldAddress(object, target::Object::tags_offset()));
shrl(scratch, Immediate(target::UntaggedObject::kBarrierOverlapShift));
andl(scratch, Address(THR, target::Thread::write_barrier_mask_offset()));
testl(FieldAddress(value, target::Object::tags_offset()), scratch);
j(ZERO, &done, kNearJump);
if ((object != kWriteBarrierObjectReg) || (value != kWriteBarrierValueReg) ||
(slot != kWriteBarrierSlotReg)) {
// Spill and shuffle unimplemented. Currently StoreIntoArray is only used
// from StoreIndexInstr, which gets these exact registers from the register
// allocator.
UNIMPLEMENTED();
}
call(Address(THR, target::Thread::array_write_barrier_entry_point_offset()));
if (value != kWriteBarrierSlotReg && slot != kWriteBarrierSlotReg) {
popl(kWriteBarrierSlotReg); // Restore kWriteBarrierSlotReg.
}
if (value != kWriteBarrierObjectReg) {
popl(kWriteBarrierObjectReg); // Restore kWriteBarrierObjectReg.
}
Bind(&done);
}

View file

@ -463,7 +463,10 @@ class Assembler : public AssemblerBase {
void testl(Register reg1, Register reg2);
void testl(Register reg, const Immediate& imm);
void testl(const Address& address, const Immediate& imm);
void testl(const Address& address, Register reg);
void testb(const Address& address, const Immediate& imm);
void testb(const Address& address, ByteRegister reg);
// clang-format off
// Macro for handling common ALU instructions. Arguments to F:
@ -820,11 +823,21 @@ class Assembler : public AssemblerBase {
const Address& dest, // Where we are storing into.
Register value, // Value we are storing.
CanBeSmi can_value_be_smi = kValueCanBeSmi,
MemoryOrder memory_order = kRelaxedNonAtomic) override;
MemoryOrder memory_order = kRelaxedNonAtomic) override {
StoreIntoObject(object, dest, value, can_value_be_smi, memory_order,
kNoRegister);
}
void StoreIntoObject(Register object, // Object we are storing into.
const Address& dest, // Where we are storing into.
Register value, // Value we are storing.
CanBeSmi can_value_be_smi,
MemoryOrder memory_order,
Register scratch);
void StoreIntoArray(Register object, // Object we are storing into.
Register slot, // Where we are storing into.
Register value, // Value we are storing.
CanBeSmi can_value_be_smi = kValueCanBeSmi);
CanBeSmi can_value_be_smi = kValueCanBeSmi,
Register scratch = kNoRegister);
void StoreIntoObjectNoBarrier(
Register object,
const Address& dest,
@ -839,9 +852,10 @@ class Assembler : public AssemblerBase {
int32_t offset, // Where we are storing into.
Register value, // Value we are storing.
CanBeSmi can_value_be_smi = kValueCanBeSmi,
MemoryOrder memory_order = kRelaxedNonAtomic) {
MemoryOrder memory_order = kRelaxedNonAtomic,
Register scratch = kNoRegister) {
StoreIntoObject(object, FieldAddress(object, offset), value,
can_value_be_smi, memory_order);
can_value_be_smi, memory_order, scratch);
}
void StoreIntoObjectOffsetNoBarrier(
Register object,
@ -1197,22 +1211,6 @@ class Assembler : public AssemblerBase {
void EmitGenericShift(int rm, Register reg, const Immediate& imm);
void EmitGenericShift(int rm, const Operand& operand, Register shifter);
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);
int32_t jit_cookie();
int32_t jit_cookie_;

View file

@ -6949,7 +6949,11 @@ void RawStoreFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
LocationSummary* StoreFieldInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 2;
#if defined(TARGET_ARCH_IA32)
const intptr_t kNumTemps = ShouldEmitStoreBarrier() ? 1 : 0;
#else
const intptr_t kNumTemps = 0;
#endif
LocationSummary* summary = new (zone)
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
@ -6973,9 +6977,7 @@ LocationSummary* StoreFieldInstr::MakeLocationSummary(Zone* zone,
Location value_loc;
if (ShouldEmitStoreBarrier()) {
summary->set_in(kValuePos,
kWriteBarrierValueReg != kNoRegister
? Location::RegisterLocation(kWriteBarrierValueReg)
: Location::WritableRegister());
Location::RegisterLocation(kWriteBarrierValueReg));
} else {
#if defined(TARGET_ARCH_IA32)
// IA32 supports emitting `mov mem, Imm32` even for heap
@ -7004,6 +7006,11 @@ LocationSummary* StoreFieldInstr::MakeLocationSummary(Zone* zone,
#endif
}
}
if (kNumTemps == 1) {
summary->set_temp(0, Location::RequiresRegister());
} else {
ASSERT(kNumTemps == 0);
}
return summary;
}
@ -7057,8 +7064,14 @@ void StoreFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
if (ShouldEmitStoreBarrier()) {
Register value_reg = locs()->in(kValuePos).reg();
if (!compressed) {
#if defined(TARGET_ARCH_IA32)
__ StoreIntoObjectOffset(instance_reg, offset_in_bytes, value_reg,
CanValueBeSmi(), memory_order_,
locs()->temp(0).reg());
#else
__ StoreIntoObjectOffset(instance_reg, offset_in_bytes, value_reg,
CanValueBeSmi(), memory_order_);
#endif
} else {
#if defined(DART_COMPRESSED_POINTERS)
__ StoreCompressedIntoObjectOffset(instance_reg, offset_in_bytes,

View file

@ -1705,7 +1705,7 @@ LocationSummary* StoreIndexedInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 3;
const intptr_t kNumTemps =
class_id() == kArrayCid && ShouldEmitStoreBarrier() ? 1 : 0;
class_id() == kArrayCid && ShouldEmitStoreBarrier() ? 2 : 0;
LocationSummary* locs = new (zone)
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
locs->set_in(0, Location::RequiresRegister());
@ -1720,12 +1720,12 @@ LocationSummary* StoreIndexedInstr::MakeLocationSummary(Zone* zone,
}
switch (class_id()) {
case kArrayCid:
locs->set_in(2, ShouldEmitStoreBarrier()
? Location::WritableRegister()
: LocationRegisterOrConstant(value()));
locs->set_in(2, LocationRegisterOrConstant(value()));
if (ShouldEmitStoreBarrier()) {
locs->set_in(0, Location::RegisterLocation(kWriteBarrierObjectReg));
locs->set_in(2, Location::RegisterLocation(kWriteBarrierValueReg));
locs->set_temp(0, Location::RegisterLocation(kWriteBarrierSlotReg));
locs->set_temp(1, Location::RequiresRegister());
}
break;
case kExternalTypedDataUint8ArrayCid:
@ -1791,8 +1791,9 @@ void StoreIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
if (ShouldEmitStoreBarrier()) {
Register value = locs()->in(2).reg();
Register slot = locs()->temp(0).reg();
Register scratch = locs()->temp(1).reg();
__ leal(slot, element_address);
__ StoreIntoArray(array, slot, value, CanValueBeSmi());
__ StoreIntoArray(array, slot, value, CanValueBeSmi(), scratch);
} else if (locs()->in(2).IsConstant()) {
const Object& constant = locs()->in(2).constant();
__ StoreIntoObjectNoBarrier(array, element_address, constant);

View file

@ -1614,9 +1614,9 @@ static constexpr dart::compiler::target::word
static constexpr dart::compiler::target::word
Thread_AllocateArray_entry_point_offset = 408;
static constexpr dart::compiler::target::word Thread_active_exception_offset =
832;
852;
static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
836;
856;
static constexpr dart::compiler::target::word
Thread_array_write_barrier_entry_point_offset = 300;
static constexpr dart::compiler::target::word
@ -1639,7 +1639,7 @@ static constexpr dart::compiler::target::word
Thread_allocate_object_slow_entry_point_offset = 324;
static constexpr dart::compiler::target::word
Thread_allocate_object_slow_stub_offset = 208;
static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 872;
static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 892;
static constexpr dart::compiler::target::word
Thread_async_exception_handler_stub_offset = 212;
static constexpr dart::compiler::target::word
@ -1652,13 +1652,13 @@ static constexpr dart::compiler::target::word
Thread_call_to_runtime_entry_point_offset = 304;
static constexpr dart::compiler::target::word
Thread_call_to_runtime_stub_offset = 140;
static constexpr dart::compiler::target::word Thread_dart_stream_offset = 904;
static constexpr dart::compiler::target::word Thread_dart_stream_offset = 928;
static constexpr dart::compiler::target::word
Thread_dispatch_table_array_offset = 44;
static constexpr dart::compiler::target::word
Thread_double_truncate_round_supported_offset = 876;
Thread_double_truncate_round_supported_offset = 896;
static constexpr dart::compiler::target::word
Thread_service_extension_stream_offset = 908;
Thread_service_extension_stream_offset = 932;
static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
344;
static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 256;
@ -1674,7 +1674,7 @@ static constexpr dart::compiler::target::word Thread_end_offset = 52;
static constexpr dart::compiler::target::word
Thread_enter_safepoint_stub_offset = 280;
static constexpr dart::compiler::target::word Thread_execution_state_offset =
852;
872;
static constexpr dart::compiler::target::word
Thread_exit_safepoint_stub_offset = 284;
static constexpr dart::compiler::target::word
@ -1696,13 +1696,13 @@ static constexpr dart::compiler::target::word Thread_float_not_address_offset =
static constexpr dart::compiler::target::word
Thread_float_zerow_address_offset = 404;
static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
840;
860;
static constexpr dart::compiler::target::word
Thread_invoke_dart_code_stub_offset = 136;
static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
868;
888;
static constexpr dart::compiler::target::word Thread_isolate_offset = 40;
static constexpr dart::compiler::target::word Thread_isolate_group_offset = 912;
static constexpr dart::compiler::target::word Thread_isolate_group_offset = 936;
static constexpr dart::compiler::target::word Thread_field_table_values_offset =
64;
static constexpr dart::compiler::target::word
@ -1755,11 +1755,11 @@ static constexpr dart::compiler::target::word Thread_return_async_stub_offset =
static constexpr dart::compiler::target::word Thread_object_null_offset = 112;
static constexpr dart::compiler::target::word
Thread_predefined_symbols_address_offset = 376;
static constexpr dart::compiler::target::word Thread_resume_pc_offset = 844;
static constexpr dart::compiler::target::word Thread_resume_pc_offset = 864;
static constexpr dart::compiler::target::word
Thread_saved_shadow_call_stack_offset = 848;
Thread_saved_shadow_call_stack_offset = 868;
static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
856;
876;
static constexpr dart::compiler::target::word
Thread_slow_type_test_stub_offset = 272;
static constexpr dart::compiler::target::word
@ -1780,25 +1780,25 @@ static constexpr dart::compiler::target::word
static constexpr dart::compiler::target::word Thread_store_buffer_block_offset =
76;
static constexpr dart::compiler::target::word
Thread_suspend_state_await_entry_point_offset = 796;
Thread_suspend_state_await_entry_point_offset = 816;
static constexpr dart::compiler::target::word
Thread_suspend_state_init_async_entry_point_offset = 792;
Thread_suspend_state_init_async_entry_point_offset = 812;
static constexpr dart::compiler::target::word
Thread_suspend_state_return_async_entry_point_offset = 800;
Thread_suspend_state_return_async_entry_point_offset = 820;
static constexpr dart::compiler::target::word
Thread_suspend_state_return_async_not_future_entry_point_offset = 804;
Thread_suspend_state_return_async_not_future_entry_point_offset = 824;
static constexpr dart::compiler::target::word
Thread_suspend_state_init_async_star_entry_point_offset = 808;
Thread_suspend_state_init_async_star_entry_point_offset = 828;
static constexpr dart::compiler::target::word
Thread_suspend_state_yield_async_star_entry_point_offset = 812;
Thread_suspend_state_yield_async_star_entry_point_offset = 832;
static constexpr dart::compiler::target::word
Thread_suspend_state_return_async_star_entry_point_offset = 816;
Thread_suspend_state_return_async_star_entry_point_offset = 836;
static constexpr dart::compiler::target::word
Thread_suspend_state_init_sync_star_entry_point_offset = 820;
Thread_suspend_state_init_sync_star_entry_point_offset = 840;
static constexpr dart::compiler::target::word
Thread_suspend_state_suspend_sync_star_at_start_entry_point_offset = 824;
Thread_suspend_state_suspend_sync_star_at_start_entry_point_offset = 844;
static constexpr dart::compiler::target::word
Thread_suspend_state_handle_exception_entry_point_offset = 828;
Thread_suspend_state_handle_exception_entry_point_offset = 848;
static constexpr dart::compiler::target::word
Thread_top_exit_frame_info_offset = 72;
static constexpr dart::compiler::target::word Thread_top_offset = 48;
@ -1811,14 +1811,14 @@ static constexpr dart::compiler::target::word
static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
32;
static constexpr dart::compiler::target::word Thread_heap_base_offset = 36;
static constexpr dart::compiler::target::word Thread_callback_code_offset = 860;
static constexpr dart::compiler::target::word Thread_callback_code_offset = 880;
static constexpr dart::compiler::target::word
Thread_callback_stack_return_offset = 864;
static constexpr dart::compiler::target::word Thread_next_task_id_offset = 880;
static constexpr dart::compiler::target::word Thread_random_offset = 888;
Thread_callback_stack_return_offset = 884;
static constexpr dart::compiler::target::word Thread_next_task_id_offset = 904;
static constexpr dart::compiler::target::word Thread_random_offset = 912;
static constexpr dart::compiler::target::word
Thread_jump_to_frame_entry_point_offset = 356;
static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 896;
static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 920;
static constexpr dart::compiler::target::word TsanUtils_setjmp_function_offset =
0;
static constexpr dart::compiler::target::word TsanUtils_setjmp_buffer_offset =
@ -1901,6 +1901,9 @@ static constexpr dart::compiler::target::word
WeakReference_type_arguments_offset = 8;
static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
4, 12, 8, 16};
static constexpr dart::compiler::target::word
Thread_write_barrier_wrappers_thread_offset[] = {792, 796, 800, 804,
-1, -1, -1, 808};
static constexpr dart::compiler::target::word AbstractType_InstanceSize = 16;
static constexpr dart::compiler::target::word ApiError_InstanceSize = 8;
static constexpr dart::compiler::target::word Array_header_size = 12;
@ -6907,9 +6910,9 @@ static constexpr dart::compiler::target::word
static constexpr dart::compiler::target::word
Thread_AllocateArray_entry_point_offset = 408;
static constexpr dart::compiler::target::word Thread_active_exception_offset =
832;
852;
static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
836;
856;
static constexpr dart::compiler::target::word
Thread_array_write_barrier_entry_point_offset = 300;
static constexpr dart::compiler::target::word
@ -6932,7 +6935,7 @@ static constexpr dart::compiler::target::word
Thread_allocate_object_slow_entry_point_offset = 324;
static constexpr dart::compiler::target::word
Thread_allocate_object_slow_stub_offset = 208;
static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 872;
static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 892;
static constexpr dart::compiler::target::word
Thread_async_exception_handler_stub_offset = 212;
static constexpr dart::compiler::target::word
@ -6945,13 +6948,13 @@ static constexpr dart::compiler::target::word
Thread_call_to_runtime_entry_point_offset = 304;
static constexpr dart::compiler::target::word
Thread_call_to_runtime_stub_offset = 140;
static constexpr dart::compiler::target::word Thread_dart_stream_offset = 904;
static constexpr dart::compiler::target::word Thread_dart_stream_offset = 928;
static constexpr dart::compiler::target::word
Thread_dispatch_table_array_offset = 44;
static constexpr dart::compiler::target::word
Thread_double_truncate_round_supported_offset = 876;
Thread_double_truncate_round_supported_offset = 896;
static constexpr dart::compiler::target::word
Thread_service_extension_stream_offset = 908;
Thread_service_extension_stream_offset = 932;
static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
344;
static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 256;
@ -6967,7 +6970,7 @@ static constexpr dart::compiler::target::word Thread_end_offset = 52;
static constexpr dart::compiler::target::word
Thread_enter_safepoint_stub_offset = 280;
static constexpr dart::compiler::target::word Thread_execution_state_offset =
852;
872;
static constexpr dart::compiler::target::word
Thread_exit_safepoint_stub_offset = 284;
static constexpr dart::compiler::target::word
@ -6989,13 +6992,13 @@ static constexpr dart::compiler::target::word Thread_float_not_address_offset =
static constexpr dart::compiler::target::word
Thread_float_zerow_address_offset = 404;
static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
840;
860;
static constexpr dart::compiler::target::word
Thread_invoke_dart_code_stub_offset = 136;
static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
868;
888;
static constexpr dart::compiler::target::word Thread_isolate_offset = 40;
static constexpr dart::compiler::target::word Thread_isolate_group_offset = 912;
static constexpr dart::compiler::target::word Thread_isolate_group_offset = 936;
static constexpr dart::compiler::target::word Thread_field_table_values_offset =
64;
static constexpr dart::compiler::target::word
@ -7048,11 +7051,11 @@ static constexpr dart::compiler::target::word Thread_return_async_stub_offset =
static constexpr dart::compiler::target::word Thread_object_null_offset = 112;
static constexpr dart::compiler::target::word
Thread_predefined_symbols_address_offset = 376;
static constexpr dart::compiler::target::word Thread_resume_pc_offset = 844;
static constexpr dart::compiler::target::word Thread_resume_pc_offset = 864;
static constexpr dart::compiler::target::word
Thread_saved_shadow_call_stack_offset = 848;
Thread_saved_shadow_call_stack_offset = 868;
static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
856;
876;
static constexpr dart::compiler::target::word
Thread_slow_type_test_stub_offset = 272;
static constexpr dart::compiler::target::word
@ -7073,25 +7076,25 @@ static constexpr dart::compiler::target::word
static constexpr dart::compiler::target::word Thread_store_buffer_block_offset =
76;
static constexpr dart::compiler::target::word
Thread_suspend_state_await_entry_point_offset = 796;
Thread_suspend_state_await_entry_point_offset = 816;
static constexpr dart::compiler::target::word
Thread_suspend_state_init_async_entry_point_offset = 792;
Thread_suspend_state_init_async_entry_point_offset = 812;
static constexpr dart::compiler::target::word
Thread_suspend_state_return_async_entry_point_offset = 800;
Thread_suspend_state_return_async_entry_point_offset = 820;
static constexpr dart::compiler::target::word
Thread_suspend_state_return_async_not_future_entry_point_offset = 804;
Thread_suspend_state_return_async_not_future_entry_point_offset = 824;
static constexpr dart::compiler::target::word
Thread_suspend_state_init_async_star_entry_point_offset = 808;
Thread_suspend_state_init_async_star_entry_point_offset = 828;
static constexpr dart::compiler::target::word
Thread_suspend_state_yield_async_star_entry_point_offset = 812;
Thread_suspend_state_yield_async_star_entry_point_offset = 832;
static constexpr dart::compiler::target::word
Thread_suspend_state_return_async_star_entry_point_offset = 816;
Thread_suspend_state_return_async_star_entry_point_offset = 836;
static constexpr dart::compiler::target::word
Thread_suspend_state_init_sync_star_entry_point_offset = 820;
Thread_suspend_state_init_sync_star_entry_point_offset = 840;
static constexpr dart::compiler::target::word
Thread_suspend_state_suspend_sync_star_at_start_entry_point_offset = 824;
Thread_suspend_state_suspend_sync_star_at_start_entry_point_offset = 844;
static constexpr dart::compiler::target::word
Thread_suspend_state_handle_exception_entry_point_offset = 828;
Thread_suspend_state_handle_exception_entry_point_offset = 848;
static constexpr dart::compiler::target::word
Thread_top_exit_frame_info_offset = 72;
static constexpr dart::compiler::target::word Thread_top_offset = 48;
@ -7104,14 +7107,14 @@ static constexpr dart::compiler::target::word
static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
32;
static constexpr dart::compiler::target::word Thread_heap_base_offset = 36;
static constexpr dart::compiler::target::word Thread_callback_code_offset = 860;
static constexpr dart::compiler::target::word Thread_callback_code_offset = 880;
static constexpr dart::compiler::target::word
Thread_callback_stack_return_offset = 864;
static constexpr dart::compiler::target::word Thread_next_task_id_offset = 880;
static constexpr dart::compiler::target::word Thread_random_offset = 888;
Thread_callback_stack_return_offset = 884;
static constexpr dart::compiler::target::word Thread_next_task_id_offset = 904;
static constexpr dart::compiler::target::word Thread_random_offset = 912;
static constexpr dart::compiler::target::word
Thread_jump_to_frame_entry_point_offset = 356;
static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 896;
static constexpr dart::compiler::target::word Thread_tsan_utils_offset = 920;
static constexpr dart::compiler::target::word TsanUtils_setjmp_function_offset =
0;
static constexpr dart::compiler::target::word TsanUtils_setjmp_buffer_offset =
@ -7194,6 +7197,9 @@ static constexpr dart::compiler::target::word
WeakReference_type_arguments_offset = 8;
static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
4, 12, 8, 16};
static constexpr dart::compiler::target::word
Thread_write_barrier_wrappers_thread_offset[] = {792, 796, 800, 804,
-1, -1, -1, 808};
static constexpr dart::compiler::target::word AbstractType_InstanceSize = 16;
static constexpr dart::compiler::target::word ApiError_InstanceSize = 8;
static constexpr dart::compiler::target::word Array_header_size = 12;

View file

@ -384,10 +384,10 @@
RANGE(Code, entry_point_offset, CodeEntryKind, CodeEntryKind::kNormal, \
CodeEntryKind::kMonomorphicUnchecked, \
[](CodeEntryKind value) { return true; }) \
NOT_IN_IA32(RANGE(Thread, write_barrier_wrappers_thread_offset, Register, 0, \
kNumberOfCpuRegisters - 1, [](Register reg) { \
return (kDartAvailableCpuRegs & (1 << reg)) != 0; \
})) \
RANGE(Thread, write_barrier_wrappers_thread_offset, Register, 0, \
kNumberOfCpuRegisters - 1, [](Register reg) { \
return (kDartAvailableCpuRegs & (1 << reg)) != 0; \
}) \
\
SIZEOF(AbstractType, InstanceSize, UntaggedAbstractType) \
SIZEOF(ApiError, InstanceSize, UntaggedApiError) \

View file

@ -1340,60 +1340,60 @@ void StubCodeCompiler::GenerateCloneContextStub(Assembler* assembler) {
}
void StubCodeCompiler::GenerateWriteBarrierWrappersStub(Assembler* assembler) {
// Not used on IA32.
__ Breakpoint();
for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
if ((kDartAvailableCpuRegs & (1 << i)) == 0) continue;
Register reg = static_cast<Register>(i);
intptr_t start = __ CodeSize();
__ pushl(kWriteBarrierObjectReg);
__ movl(kWriteBarrierObjectReg, reg);
__ call(Address(THR, target::Thread::write_barrier_entry_point_offset()));
__ popl(kWriteBarrierObjectReg);
__ ret();
intptr_t end = __ CodeSize();
ASSERT_EQUAL(end - start, kStoreBufferWrapperSize);
RELEASE_ASSERT(end - start == kStoreBufferWrapperSize);
}
}
// Helper stub to implement Assembler::StoreIntoObject/Array.
// Input parameters:
// EDX: Object (old)
// EBX: Value (old or new)
// EDI: Slot
// If EDX is not remembered, mark as remembered and add to the store buffer.
// If EAX is new, add EDX to the store buffer. Otherwise EAX is old, mark EAX
// and add it to the mark list.
COMPILE_ASSERT(kWriteBarrierObjectReg == EDX);
COMPILE_ASSERT(kWriteBarrierValueReg == kNoRegister);
COMPILE_ASSERT(kWriteBarrierValueReg == EBX);
COMPILE_ASSERT(kWriteBarrierSlotReg == EDI);
static void GenerateWriteBarrierStubHelper(Assembler* assembler,
bool cards) {
Label remember_card;
// Save values being destroyed.
__ pushl(EAX);
__ pushl(ECX);
Label add_to_buffer;
// Check whether this object has already been remembered. Skip adding to the
// store buffer if the object is in the store buffer already.
// Spilled: EAX, ECX
// EDX: Address being stored
__ movl(EAX, FieldAddress(EDX, target::Object::tags_offset()));
__ testl(EAX,
Immediate(1 << target::UntaggedObject::kOldAndNotRememberedBit));
__ j(NOT_EQUAL, &add_to_buffer, Assembler::kNearJump);
__ popl(ECX);
__ popl(EAX);
__ ret();
// Update the tags that this object has been remembered.
// EDX: Address being stored
// EAX: Current tag value
__ Bind(&add_to_buffer);
Label add_to_mark_stack, remember_card, lost_race;
__ testl(EBX, Immediate(1 << target::ObjectAlignment::kNewObjectBitPosition));
__ j(ZERO, &add_to_mark_stack);
if (cards) {
// Check if this object is using remembered cards.
__ testl(EAX, Immediate(1 << target::UntaggedObject::kCardRememberedBit));
__ j(NOT_EQUAL, &remember_card, Assembler::kFarJump); // Unlikely.
__ testl(FieldAddress(EDX, target::Object::tags_offset()),
Immediate(1 << target::UntaggedObject::kCardRememberedBit));
__ j(NOT_ZERO, &remember_card, Assembler::kFarJump); // Unlikely.
} else {
#if defined(DEBUG)
Label ok;
__ testl(EAX, Immediate(1 << target::UntaggedObject::kCardRememberedBit));
__ j(ZERO, &ok, Assembler::kFarJump); // Unlikely.
__ testl(FieldAddress(EDX, target::Object::tags_offset()),
Immediate(1 << target::UntaggedObject::kCardRememberedBit));
__ j(ZERO, &ok, Assembler::kFarJump);
__ Stop("Wrong barrier");
__ Bind(&ok);
#endif
}
// Atomically clear kOldAndNotRememberedBit.
Label retry, lost_race;
Label retry;
__ movl(EAX, FieldAddress(EDX, target::Object::tags_offset()));
__ Bind(&retry);
__ movl(ECX, EAX);
@ -1443,6 +1443,43 @@ static void GenerateWriteBarrierStubHelper(Assembler* assembler,
}
__ ret();
__ Bind(&add_to_mark_stack);
// Atomically clear kOldAndNotMarkedBit.
Label retry_marking, marking_overflow;
__ movl(EAX, FieldAddress(EBX, target::Object::tags_offset()));
__ Bind(&retry_marking);
__ movl(ECX, EAX);
__ testl(ECX, Immediate(1 << target::UntaggedObject::kOldAndNotMarkedBit));
__ j(ZERO, &lost_race); // Marked by another thread.
__ andl(ECX, Immediate(~(1 << target::UntaggedObject::kOldAndNotMarkedBit)));
// Cmpxchgq: compare value = implicit operand EAX, new value = ECX.
// On failure, EAX is updated with the current value.
__ LockCmpxchgl(FieldAddress(EBX, target::Object::tags_offset()), ECX);
__ j(NOT_EQUAL, &retry_marking, Assembler::kNearJump);
__ movl(EAX, Address(THR, target::Thread::marking_stack_block_offset()));
__ movl(ECX, Address(EAX, target::MarkingStackBlock::top_offset()));
__ movl(
Address(EAX, ECX, TIMES_4, target::MarkingStackBlock::pointers_offset()),
EBX);
__ incl(ECX);
__ movl(Address(EAX, target::MarkingStackBlock::top_offset()), ECX);
__ cmpl(ECX, Immediate(target::MarkingStackBlock::kSize));
__ popl(ECX); // Unspill.
__ popl(EAX); // Unspill.
__ j(EQUAL, &marking_overflow, Assembler::kNearJump);
__ ret();
__ Bind(&marking_overflow);
{
LeafRuntimeScope rt(assembler,
/*frame_size=*/1 * target::kWordSize,
/*preserve_registers=*/true);
__ movl(Address(ESP, 0), THR); // Push the thread as the only argument.
rt.Call(kMarkingStackBlockProcessRuntimeEntry, 1);
}
__ ret();
__ Bind(&lost_race);
__ popl(ECX); // Unspill.
__ popl(EAX); // Unspill.

View file

@ -11,6 +11,7 @@
#include "platform/assert.h"
#include "platform/globals.h"
#include "platform/utils.h"
#include "vm/constants_base.h"
@ -101,7 +102,7 @@ const Register kStackTraceObjectReg = EDX;
// ABI for write barrier stub.
const Register kWriteBarrierObjectReg = EDX;
const Register kWriteBarrierValueReg = kNoRegister;
const Register kWriteBarrierValueReg = EBX;
const Register kWriteBarrierSlotReg = EDI;
// Common ABI for shared slow path stubs.
@ -352,11 +353,16 @@ const RegList kAllCpuRegistersList = 0xFF;
const RegList kAllFpuRegistersList = (1 << kNumberOfFpuRegisters) - 1;
const intptr_t kReservedCpuRegisters = (1 << SPREG) | (1 << FPREG) | (1 << THR);
constexpr intptr_t kNumberOfReservedCpuRegisters =
Utils::CountOneBits32(kReservedCpuRegisters);
// CPU registers available to Dart allocator.
const RegList kDartAvailableCpuRegs =
kAllCpuRegistersList & ~kReservedCpuRegisters;
constexpr int kNumberOfDartAvailableCpuRegs =
kNumberOfCpuRegisters - kNumberOfReservedCpuRegisters;
// No reason to prefer certain registers on IA32.
constexpr int kRegisterAllocationBias = 0;
constexpr int kStoreBufferWrapperSize = 11;
const RegList kAbiPreservedCpuRegs = (1 << EDI) | (1 << ESI) | (1 << EBX);

View file

@ -936,12 +936,8 @@ void PageSpace::CollectGarbage(Thread* thread, bool compact, bool finalize) {
ASSERT(!Thread::Current()->force_growth());
if (!finalize) {
#if defined(TARGET_ARCH_IA32)
return; // Barrier not implemented.
#else
if (!enable_concurrent_mark()) return; // Disabled.
if (FLAG_marker_tasks == 0) return; // Disabled.
#endif
}
GcSafepointOperationScope safepoint_scope(thread);
@ -1498,11 +1494,7 @@ void PageSpaceController::RecordUpdate(SpaceUsage before,
intptr_t threshold =
after.CombinedUsedInWords() + (kPageSizeInWords * growth_in_pages);
#if defined(TARGET_ARCH_IA32)
bool concurrent_mark = false;
#else
bool concurrent_mark = FLAG_concurrent_mark && (FLAG_marker_tasks != 0);
#endif
if (concurrent_mark) {
soft_gc_threshold_in_words_ = threshold;
hard_gc_threshold_in_words_ = kIntptrMax / kWordSize;

View file

@ -688,13 +688,11 @@ class UntaggedObject {
// Incremental barrier: record when a store creates an
// old -> old-and-not-marked reference.
ASSERT(value->IsOldObject());
#if !defined(TARGET_ARCH_IA32)
if (ClassIdTag::decode(target_tags) == kInstructionsCid) {
// Instruction pages may be non-writable. Defer marking.
thread->DeferredMarkingStackAddObject(value);
return;
}
#endif
if (value->untag()->TryAcquireMarkBit()) {
thread->MarkingStackAddObject(value);
}
@ -722,13 +720,11 @@ class UntaggedObject {
// Incremental barrier: record when a store creates an
// old -> old-and-not-marked reference.
ASSERT(value->IsOldObject());
#if !defined(TARGET_ARCH_IA32)
if (ClassIdTag::decode(target_tags) == kInstructionsCid) {
// Instruction pages may be non-writable. Defer marking.
thread->DeferredMarkingStackAddObject(value);
return;
}
#endif
if (value->untag()->TryAcquireMarkBit()) {
thread->MarkingStackAddObject(value);
}

View file

@ -122,11 +122,9 @@ Thread::Thread(bool is_vm_isolate)
CACHED_CONSTANTS_LIST(DEFAULT_INIT)
#undef DEFAULT_INIT
#if !defined(TARGET_ARCH_IA32)
for (intptr_t i = 0; i < kNumberOfDartAvailableCpuRegs; ++i) {
write_barrier_wrappers_entry_points_[i] = 0;
}
#endif
#define DEFAULT_INIT(name) name##_entry_point_ = 0;
RUNTIME_ENTRY_LIST(DEFAULT_INIT)
@ -205,13 +203,11 @@ void Thread::InitVMConstants() {
CACHED_CONSTANTS_LIST(INIT_VALUE)
#undef INIT_VALUE
#if !defined(TARGET_ARCH_IA32)
for (intptr_t i = 0; i < kNumberOfDartAvailableCpuRegs; ++i) {
write_barrier_wrappers_entry_points_[i] =
StubCode::WriteBarrierWrappers().EntryPoint() +
i * kStoreBufferWrapperSize;
}
#endif
#define INIT_VALUE(name) \
ASSERT(name##_entry_point_ == 0); \

View file

@ -701,7 +701,6 @@ class Thread : public ThreadState {
CACHED_CONSTANTS_LIST(DEFINE_OFFSET_METHOD)
#undef DEFINE_OFFSET_METHOD
#if !defined(TARGET_ARCH_IA32)
static intptr_t write_barrier_wrappers_thread_offset(Register reg) {
ASSERT((kDartAvailableCpuRegs & (1 << reg)) != 0);
intptr_t index = 0;
@ -726,7 +725,6 @@ class Thread : public ThreadState {
UNREACHABLE();
return 0;
}
#endif
#define DEFINE_OFFSET_METHOD(name) \
static intptr_t name##_entry_point_offset() { \
@ -1195,9 +1193,7 @@ class Thread : public ThreadState {
LEAF_RUNTIME_ENTRY_LIST(DECLARE_MEMBERS)
#undef DECLARE_MEMBERS
#if !defined(TARGET_ARCH_IA32)
uword write_barrier_wrappers_entry_points_[kNumberOfDartAvailableCpuRegs];
#endif
#define DECLARE_MEMBERS(name) uword name##_entry_point_ = 0;
CACHED_FUNCTION_ENTRY_POINTS_LIST(DECLARE_MEMBERS)