Skip to content

Commit 78d280a

Browse files
rmacnak-googleCommit Queue
authored andcommitted
[vm] Symbolize JIT Dart frames for TSAN.
TEST=tsan Bug: #61352 Change-Id: I0e64e563b19bbd7b67e6f275dbc373db08b9d2c7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/449980 Reviewed-by: Alexander Aprelev <[email protected]> Commit-Queue: Ryan Macnak <[email protected]>
1 parent 17abf40 commit 78d280a

File tree

17 files changed

+549
-168
lines changed

17 files changed

+549
-168
lines changed

runtime/platform/thread_sanitizer.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ extern "C" void __tsan_write2(void* addr);
3535
extern "C" void __tsan_write4(void* addr);
3636
extern "C" void __tsan_write8(void* addr);
3737
extern "C" void __tsan_write16(void* addr);
38+
extern "C" void __tsan_read1_pc(void* addr, void* pc);
39+
extern "C" void __tsan_read2_pc(void* addr, void* pc);
40+
extern "C" void __tsan_read4_pc(void* addr, void* pc);
41+
extern "C" void __tsan_read8_pc(void* addr, void* pc);
42+
extern "C" void __tsan_read16_pc(void* addr, void* pc);
43+
extern "C" void __tsan_write1_pc(void* addr, void* pc);
44+
extern "C" void __tsan_write2_pc(void* addr, void* pc);
45+
extern "C" void __tsan_write4_pc(void* addr, void* pc);
46+
extern "C" void __tsan_write8_pc(void* addr, void* pc);
47+
extern "C" void __tsan_write16_pc(void* addr, void* pc);
3848
extern "C" void __tsan_func_entry(void* pc);
3949
extern "C" void __tsan_func_exit();
4050
#else

runtime/vm/compiler/assembler/assembler_arm64.cc

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -353,56 +353,6 @@ void Assembler::TsanStoreRelease(Register src,
353353
}
354354
}
355355

356-
void Assembler::TsanRead(Register addr, intptr_t size) {
357-
Comment("TsanRead");
358-
LeafRuntimeScope rt(this, /*frame_size=*/0, /*preserve_registers=*/true);
359-
MoveRegister(R0, addr);
360-
switch (size) {
361-
case 1:
362-
rt.Call(kTsanRead1RuntimeEntry, /*argument_count=*/1);
363-
break;
364-
case 2:
365-
rt.Call(kTsanRead2RuntimeEntry, /*argument_count=*/1);
366-
break;
367-
case 4:
368-
rt.Call(kTsanRead4RuntimeEntry, /*argument_count=*/1);
369-
break;
370-
case 8:
371-
rt.Call(kTsanRead8RuntimeEntry, /*argument_count=*/1);
372-
break;
373-
case 16:
374-
rt.Call(kTsanRead16RuntimeEntry, /*argument_count=*/1);
375-
break;
376-
default:
377-
UNREACHABLE();
378-
}
379-
}
380-
381-
void Assembler::TsanWrite(Register addr, intptr_t size) {
382-
Comment("TsanWrite");
383-
LeafRuntimeScope rt(this, /*frame_size=*/0, /*preserve_registers=*/true);
384-
MoveRegister(R0, addr);
385-
switch (size) {
386-
case 1:
387-
rt.Call(kTsanWrite1RuntimeEntry, /*argument_count=*/1);
388-
break;
389-
case 2:
390-
rt.Call(kTsanWrite2RuntimeEntry, /*argument_count=*/1);
391-
break;
392-
case 4:
393-
rt.Call(kTsanWrite4RuntimeEntry, /*argument_count=*/1);
394-
break;
395-
case 8:
396-
rt.Call(kTsanWrite8RuntimeEntry, /*argument_count=*/1);
397-
break;
398-
case 16:
399-
rt.Call(kTsanWrite16RuntimeEntry, /*argument_count=*/1);
400-
break;
401-
default:
402-
UNREACHABLE();
403-
}
404-
}
405-
406356
void Assembler::TsanFuncEntry(bool preserve_registers) {
407357
Comment("TsanFuncEntry");
408358
LeafRuntimeScope rt(this, /*frame_size=*/0, preserve_registers);

runtime/vm/compiler/assembler/assembler_arm64.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -504,8 +504,6 @@ class Assembler : public AssemblerBase {
504504

505505
void TsanLoadAcquire(Register dst, Register addr, OperandSize size);
506506
void TsanStoreRelease(Register src, Register addr, OperandSize size);
507-
void TsanRead(Register addr, intptr_t size);
508-
void TsanWrite(Register addr, intptr_t size);
509507
void TsanFuncEntry(bool preserve_registers = true);
510508
void TsanFuncExit(bool preserve_registers = true);
511509

runtime/vm/compiler/assembler/assembler_riscv.cc

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3172,56 +3172,6 @@ void Assembler::TsanStoreRelease(Register src,
31723172
}
31733173
}
31743174

3175-
void Assembler::TsanRead(Register addr, intptr_t size) {
3176-
Comment("TsanRead");
3177-
LeafRuntimeScope rt(this, /*frame_size=*/0, /*preserve_registers=*/true);
3178-
MoveRegister(A0, addr);
3179-
switch (size) {
3180-
case 1:
3181-
rt.Call(kTsanRead1RuntimeEntry, /*argument_count=*/1);
3182-
break;
3183-
case 2:
3184-
rt.Call(kTsanRead2RuntimeEntry, /*argument_count=*/1);
3185-
break;
3186-
case 4:
3187-
rt.Call(kTsanRead4RuntimeEntry, /*argument_count=*/1);
3188-
break;
3189-
case 8:
3190-
rt.Call(kTsanRead8RuntimeEntry, /*argument_count=*/1);
3191-
break;
3192-
case 16:
3193-
rt.Call(kTsanRead16RuntimeEntry, /*argument_count=*/1);
3194-
break;
3195-
default:
3196-
UNREACHABLE();
3197-
}
3198-
}
3199-
3200-
void Assembler::TsanWrite(Register addr, intptr_t size) {
3201-
Comment("TsanWrite");
3202-
LeafRuntimeScope rt(this, /*frame_size=*/0, /*preserve_registers=*/true);
3203-
MoveRegister(A0, addr);
3204-
switch (size) {
3205-
case 1:
3206-
rt.Call(kTsanWrite1RuntimeEntry, /*argument_count=*/1);
3207-
break;
3208-
case 2:
3209-
rt.Call(kTsanWrite2RuntimeEntry, /*argument_count=*/1);
3210-
break;
3211-
case 4:
3212-
rt.Call(kTsanWrite4RuntimeEntry, /*argument_count=*/1);
3213-
break;
3214-
case 8:
3215-
rt.Call(kTsanWrite8RuntimeEntry, /*argument_count=*/1);
3216-
break;
3217-
case 16:
3218-
rt.Call(kTsanWrite16RuntimeEntry, /*argument_count=*/1);
3219-
break;
3220-
default:
3221-
UNREACHABLE();
3222-
}
3223-
}
3224-
32253175
void Assembler::TsanFuncEntry(bool preserve_registers) {
32263176
Comment("TsanFuncEntry");
32273177
LeafRuntimeScope rt(this, /*frame_size=*/0, preserve_registers);

runtime/vm/compiler/assembler/assembler_riscv.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,8 +1009,6 @@ class Assembler : public MicroAssembler {
10091009

10101010
void TsanLoadAcquire(Register dst, const Address& address, OperandSize size);
10111011
void TsanStoreRelease(Register src, const Address& address, OperandSize size);
1012-
void TsanRead(Register addr, intptr_t size);
1013-
void TsanWrite(Register addr, intptr_t size);
10141012
void TsanFuncEntry(bool preserve_registers = true);
10151013
void TsanFuncExit(bool preserve_registers = true);
10161014

runtime/vm/compiler/assembler/assembler_x64.cc

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2210,56 +2210,6 @@ void Assembler::TsanStoreRelease(Register src, Address addr, OperandSize size) {
22102210
}
22112211
}
22122212

2213-
void Assembler::TsanRead(Register addr, intptr_t size) {
2214-
Comment("TsanRead");
2215-
LeafRuntimeScope rt(this, /*frame_size=*/0, /*preserve_registers=*/true);
2216-
MoveRegister(CallingConventions::kArg1Reg, addr);
2217-
switch (size) {
2218-
case 1:
2219-
rt.Call(kTsanRead1RuntimeEntry, /*argument_count=*/1);
2220-
break;
2221-
case 2:
2222-
rt.Call(kTsanRead2RuntimeEntry, /*argument_count=*/1);
2223-
break;
2224-
case 4:
2225-
rt.Call(kTsanRead4RuntimeEntry, /*argument_count=*/1);
2226-
break;
2227-
case 8:
2228-
rt.Call(kTsanRead8RuntimeEntry, /*argument_count=*/1);
2229-
break;
2230-
case 16:
2231-
rt.Call(kTsanRead16RuntimeEntry, /*argument_count=*/1);
2232-
break;
2233-
default:
2234-
UNREACHABLE();
2235-
}
2236-
}
2237-
2238-
void Assembler::TsanWrite(Register addr, intptr_t size) {
2239-
Comment("TsanWrite");
2240-
LeafRuntimeScope rt(this, /*frame_size=*/0, /*preserve_registers=*/true);
2241-
MoveRegister(CallingConventions::kArg1Reg, addr);
2242-
switch (size) {
2243-
case 1:
2244-
rt.Call(kTsanWrite1RuntimeEntry, /*argument_count=*/1);
2245-
break;
2246-
case 2:
2247-
rt.Call(kTsanWrite2RuntimeEntry, /*argument_count=*/1);
2248-
break;
2249-
case 4:
2250-
rt.Call(kTsanWrite4RuntimeEntry, /*argument_count=*/1);
2251-
break;
2252-
case 8:
2253-
rt.Call(kTsanWrite8RuntimeEntry, /*argument_count=*/1);
2254-
break;
2255-
case 16:
2256-
rt.Call(kTsanWrite16RuntimeEntry, /*argument_count=*/1);
2257-
break;
2258-
default:
2259-
UNREACHABLE();
2260-
}
2261-
}
2262-
22632213
void Assembler::TsanFuncEntry(bool preserve_registers) {
22642214
Comment("TsanFuncEntry");
22652215
LeafRuntimeScope rt(this, /*frame_size=*/0, preserve_registers);

runtime/vm/compiler/assembler/assembler_x64.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,8 +1163,6 @@ class Assembler : public AssemblerBase {
11631163

11641164
void TsanLoadAcquire(Register dst, Address addr, OperandSize size);
11651165
void TsanStoreRelease(Register src, Address addr, OperandSize size);
1166-
void TsanRead(Register addr, intptr_t size);
1167-
void TsanWrite(Register addr, intptr_t size);
11681166
void TsanFuncEntry(bool preserve_registers = true);
11691167
void TsanFuncExit(bool preserve_registers = true);
11701168

runtime/vm/compiler/backend/il.cc

Lines changed: 84 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4684,6 +4684,30 @@ void LoadFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
46844684
ASSERT(OffsetInBytes() != 0 || slot().has_untagged_instance());
46854685
auto const rep = slot().representation();
46864686

4687+
if (!compiler->is_optimizing() && FLAG_target_thread_sanitizer &&
4688+
!slot().is_no_sanitize_thread() &&
4689+
memory_order() == compiler::Assembler::kRelaxedNonAtomic) {
4690+
EmitTsanCallUnopt(compiler, this, [&]() -> const RuntimeEntry& {
4691+
intptr_t tag = slot().has_untagged_instance() ? 0 : kHeapObjectTag;
4692+
__ AddImmediate(CallingConventions::ArgumentRegisters[0], instance_reg,
4693+
slot().offset_in_bytes() - tag);
4694+
switch (RepresentationUtils::ValueSize(rep)) {
4695+
case 1:
4696+
return kTsanRead1RuntimeEntry;
4697+
case 2:
4698+
return kTsanRead2RuntimeEntry;
4699+
case 4:
4700+
return kTsanRead4RuntimeEntry;
4701+
case 8:
4702+
return kTsanRead8RuntimeEntry;
4703+
case 16:
4704+
return kTsanRead16RuntimeEntry;
4705+
default:
4706+
UNREACHABLE();
4707+
}
4708+
});
4709+
}
4710+
46874711
if (calls_initializer()) {
46884712
__ LoadFromSlot(locs()->out(0).reg(), instance_reg, slot(), memory_order_);
46894713
EmitNativeCodeForInitializerCall(compiler);
@@ -7297,11 +7321,11 @@ static LocationSummary* MakeTsanLocationSummary(Zone* zone,
72977321
return result;
72987322
}
72997323

7300-
static void EmitTsanNativeCode(
7301-
FlowGraphCompiler* compiler,
7302-
LocationSummary* locs,
7303-
std::function<const RuntimeEntry&()> move_parameters) {
7304-
const Register saved_sp = locs->temp(0).reg();
7324+
static void EmitTsanCall(FlowGraphCompiler* compiler,
7325+
Instruction* instr,
7326+
RegisterSet spill_set,
7327+
Register saved_sp,
7328+
std::function<const RuntimeEntry&()> move_parameters) {
73057329
ASSERT(IsCalleeSavedRegister(saved_sp));
73067330
ASSERT(IsCalleeSavedRegister(THR));
73077331
ASSERT(IsCalleeSavedRegister(PP));
@@ -7316,6 +7340,7 @@ static void EmitTsanNativeCode(
73167340
ASSERT(IsCalleeSavedRegister(DISPATCH_TABLE_REG));
73177341
#endif
73187342

7343+
__ PushRegisters(spill_set);
73197344
__ MoveRegister(saved_sp, SPREG);
73207345
#if defined(TARGET_ARCH_ARM64)
73217346
__ AndImmediate(CSP, SP, ~(OS::ActivationFrameAlignment() - 1));
@@ -7327,13 +7352,40 @@ static void EmitTsanNativeCode(
73277352
__ Store(TMP,
73287353
compiler::Address(THR, compiler::target::Thread::vm_tag_offset()));
73297354
__ CallCFunction(TMP);
7355+
compiler->AddCurrentDescriptor(UntaggedPcDescriptors::kOther, DeoptId::kNone,
7356+
instr->source());
73307357
__ LoadImmediate(TMP, VMTag::kDartTagId);
73317358
__ Store(TMP,
73327359
compiler::Address(THR, compiler::target::Thread::vm_tag_offset()));
73337360
__ MoveRegister(SPREG, saved_sp);
73347361
#if defined(TARGET_ARCH_ARM64)
73357362
__ SetupCSPFromThread(THR);
73367363
#endif
7364+
__ PopRegisters(spill_set);
7365+
}
7366+
7367+
static void EmitTsanCall(FlowGraphCompiler* compiler,
7368+
Instruction* instr,
7369+
std::function<const RuntimeEntry&()> move_parameters) {
7370+
EmitTsanCall(compiler, instr, RegisterSet(), instr->locs()->temp(0).reg(),
7371+
move_parameters);
7372+
}
7373+
7374+
void EmitTsanCallUnopt(FlowGraphCompiler* compiler,
7375+
Instruction* instr,
7376+
std::function<const RuntimeEntry&()> move_parameters) {
7377+
intptr_t cpu_reg_mask = 0;
7378+
intptr_t fpu_reg_mask = 0;
7379+
LocationSummary* locs = instr->locs();
7380+
for (intptr_t i = 0, n = locs->input_count(); i < n; i++) {
7381+
if (locs->in(i).IsRegister()) {
7382+
cpu_reg_mask |= 1 << locs->in(i).reg();
7383+
} else if (locs->in(i).IsFpuRegister()) {
7384+
fpu_reg_mask |= 1 << locs->in(i).fpu_reg();
7385+
}
7386+
}
7387+
EmitTsanCall(compiler, instr, RegisterSet(cpu_reg_mask, fpu_reg_mask),
7388+
CALLEE_SAVED_TEMP, move_parameters);
73377389
}
73387390

73397391
LocationSummary* TsanFuncEntryExitInstr::MakeLocationSummary(Zone* zone,
@@ -7344,7 +7396,7 @@ LocationSummary* TsanFuncEntryExitInstr::MakeLocationSummary(Zone* zone,
73447396
void TsanFuncEntryExitInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
73457397
if (!compiler->flow_graph().graph_entry()->NeedsFrame()) return;
73467398

7347-
EmitTsanNativeCode(compiler, locs(), [&]() -> const RuntimeEntry& {
7399+
EmitTsanCall(compiler, this, [&]() -> const RuntimeEntry& {
73487400
if (kind_ == kEntry) {
73497401
__ Load(
73507402
CallingConventions::ArgumentRegisters[0],
@@ -7364,7 +7416,7 @@ LocationSummary* TsanReadWriteInstr::MakeLocationSummary(Zone* zone,
73647416
}
73657417

73667418
void TsanReadWriteInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
7367-
EmitTsanNativeCode(compiler, locs(), [&]() -> const RuntimeEntry& {
7419+
EmitTsanCall(compiler, this, [&]() -> const RuntimeEntry& {
73687420
const Register instance_reg = locs()->in(0).reg();
73697421
intptr_t tag = slot().has_untagged_instance() ? 0 : kHeapObjectTag;
73707422
__ AddImmediate(CallingConventions::ArgumentRegisters[0], instance_reg,
@@ -7413,7 +7465,7 @@ LocationSummary* TsanReadWriteIndexedInstr::MakeLocationSummary(
74137465
}
74147466

74157467
void TsanReadWriteIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
7416-
EmitTsanNativeCode(compiler, locs(), [&]() -> const RuntimeEntry& {
7468+
EmitTsanCall(compiler, this, [&]() -> const RuntimeEntry& {
74177469
const Register array_reg = locs()->in(kArrayPos).reg();
74187470
Register index_reg = locs()->in(kIndexPos).reg();
74197471

@@ -8022,6 +8074,30 @@ void StoreFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
80228074
ASSERT(OffsetInBytes() != 0 || slot().has_untagged_instance());
80238075
const Representation rep = slot().representation();
80248076

8077+
if (!compiler->is_optimizing() && FLAG_target_thread_sanitizer &&
8078+
!slot().is_no_sanitize_thread() &&
8079+
memory_order() == compiler::Assembler::kRelaxedNonAtomic) {
8080+
EmitTsanCallUnopt(compiler, this, [&]() -> const RuntimeEntry& {
8081+
intptr_t tag = slot().has_untagged_instance() ? 0 : kHeapObjectTag;
8082+
__ AddImmediate(CallingConventions::ArgumentRegisters[0], instance_reg,
8083+
slot().offset_in_bytes() - tag);
8084+
switch (RepresentationUtils::ValueSize(rep)) {
8085+
case 1:
8086+
return kTsanWrite1RuntimeEntry;
8087+
case 2:
8088+
return kTsanWrite2RuntimeEntry;
8089+
case 4:
8090+
return kTsanWrite4RuntimeEntry;
8091+
case 8:
8092+
return kTsanWrite8RuntimeEntry;
8093+
case 16:
8094+
return kTsanWrite16RuntimeEntry;
8095+
default:
8096+
UNREACHABLE();
8097+
}
8098+
});
8099+
}
8100+
80258101
#if defined(TARGET_ARCH_ARM64) || defined(TARGET_ARCH_RISCV32) || \
80268102
defined(TARGET_ARCH_RISCV64)
80278103
if (locs()->in(kValuePos).IsConstant() &&

runtime/vm/compiler/backend/il.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11799,6 +11799,10 @@ inline bool Value::CanBe(const Object& value) {
1179911799
#undef DECLARE_CUSTOM_SERIALIZATION
1180011800
#undef DECLARE_EMPTY_SERIALIZATION
1180111801

11802+
void EmitTsanCallUnopt(FlowGraphCompiler* compiler,
11803+
Instruction* instr,
11804+
std::function<const RuntimeEntry&()> move_parameters);
11805+
1180211806
} // namespace dart
1180311807

1180411808
#endif // RUNTIME_VM_COMPILER_BACKEND_IL_H_

0 commit comments

Comments
 (0)