Skip to content

Commit bf4bb95

Browse files
alexmarkovCommit Bot
authored and
Commit Bot
committed
[vm] New async/await implementation in the VM, part 2 - vm
The new implementation moves away from desugaring of async functions on kernel AST, state machine generated in the flow graph and capturing all local variables in the context. Instead, async/await is implemented using a few stubs (InitSuspendableFunction, Suspend, Resume, Return and AsyncExceptionHandler). The stubs are implemented in a platform-independent way using (macro-)assembler helpers. When suspending a function, its frame is copied into a SuspendState object, and when resuming a function it is copied back onto the stack. No extra code is generated for accessing local variables. Callback closures are created lazily on the first await. Design doc: go/compact-async-await. Part 1 (kernel): https://dart-review.googlesource.com/c/sdk/+/241842 TEST=ci Issue: #48378 Change-Id: Ibad757035b7cc438ebdff80b460728b1d3eff1f5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/242000 Reviewed-by: Ryan Macnak <[email protected]> Reviewed-by: Slava Egorov <[email protected]>
1 parent fcc9169 commit bf4bb95

File tree

112 files changed

+3731
-855
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

112 files changed

+3731
-855
lines changed

runtime/lib/isolate.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ static ObjectPtr ValidateMessageObject(Zone* zone,
250250
MESSAGE_SNAPSHOT_ILLEGAL(Pointer);
251251
MESSAGE_SNAPSHOT_ILLEGAL(ReceivePort);
252252
MESSAGE_SNAPSHOT_ILLEGAL(UserTag);
253+
MESSAGE_SNAPSHOT_ILLEGAL(SuspendState);
253254

254255
default:
255256
if (cid >= kNumPredefinedCids) {

runtime/vm/app_snapshot.cc

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3061,7 +3061,7 @@ class ExceptionHandlersSerializationCluster : public SerializationCluster {
30613061
ExceptionHandlersPtr handlers = objects_[i];
30623062
s->AssignRef(handlers);
30633063
AutoTraceObject(handlers);
3064-
const intptr_t length = handlers->untag()->num_entries_;
3064+
const intptr_t length = handlers->untag()->num_entries();
30653065
s->WriteUnsigned(length);
30663066
target_memory_size_ +=
30673067
compiler::target::ExceptionHandlers::InstanceSize(length);
@@ -3073,8 +3073,10 @@ class ExceptionHandlersSerializationCluster : public SerializationCluster {
30733073
for (intptr_t i = 0; i < count; i++) {
30743074
ExceptionHandlersPtr handlers = objects_[i];
30753075
AutoTraceObject(handlers);
3076-
const intptr_t length = handlers->untag()->num_entries_;
3077-
s->WriteUnsigned(length);
3076+
const intptr_t packed_fields = handlers->untag()->packed_fields_;
3077+
const intptr_t length =
3078+
UntaggedExceptionHandlers::NumEntriesBits::decode(packed_fields);
3079+
s->WriteUnsigned(packed_fields);
30783080
WriteCompressedField(handlers, handled_types_data);
30793081
for (intptr_t j = 0; j < length; j++) {
30803082
const ExceptionHandlerInfo& info = handlers->untag()->data()[j];
@@ -3117,10 +3119,12 @@ class ExceptionHandlersDeserializationCluster : public DeserializationCluster {
31173119
for (intptr_t id = start_index_, n = stop_index_; id < n; id++) {
31183120
ExceptionHandlersPtr handlers =
31193121
static_cast<ExceptionHandlersPtr>(d.Ref(id));
3120-
const intptr_t length = d.ReadUnsigned();
3122+
const intptr_t packed_fields = d.ReadUnsigned();
3123+
const intptr_t length =
3124+
UntaggedExceptionHandlers::NumEntriesBits::decode(packed_fields);
31213125
Deserializer::InitializeHeader(handlers, kExceptionHandlersCid,
31223126
ExceptionHandlers::InstanceSize(length));
3123-
handlers->untag()->num_entries_ = length;
3127+
handlers->untag()->packed_fields_ = packed_fields;
31243128
handlers->untag()->handled_types_data_ =
31253129
static_cast<ArrayPtr>(d.ReadRef());
31263130
for (intptr_t j = 0; j < length; j++) {
@@ -5683,6 +5687,8 @@ class VMSerializationRoots : public SerializationRoots {
56835687
"LocalVarDescriptors", "<empty>");
56845688
s->AddBaseObject(Object::empty_exception_handlers().ptr(),
56855689
"ExceptionHandlers", "<empty>");
5690+
s->AddBaseObject(Object::empty_async_exception_handlers().ptr(),
5691+
"ExceptionHandlers", "<empty async>");
56865692

56875693
for (intptr_t i = 0; i < ArgumentsDescriptor::kCachedDescriptorCount; i++) {
56885694
s->AddBaseObject(ArgumentsDescriptor::cached_args_descriptors_[i],
@@ -5794,6 +5800,7 @@ class VMDeserializationRoots : public DeserializationRoots {
57945800
d->AddBaseObject(Object::empty_descriptors().ptr());
57955801
d->AddBaseObject(Object::empty_var_descriptors().ptr());
57965802
d->AddBaseObject(Object::empty_exception_handlers().ptr());
5803+
d->AddBaseObject(Object::empty_async_exception_handlers().ptr());
57975804

57985805
for (intptr_t i = 0; i < ArgumentsDescriptor::kCachedDescriptorCount; i++) {
57995806
d->AddBaseObject(ArgumentsDescriptor::cached_args_descriptors_[i]);

runtime/vm/class_id.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ typedef uint16_t ClassIdTagType;
9595
V(ReceivePort) \
9696
V(SendPort) \
9797
V(StackTrace) \
98+
V(SuspendState) \
9899
V(RegExp) \
99100
V(WeakProperty) \
100101
V(WeakReference) \

runtime/vm/code_descriptors.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,12 @@ ExceptionHandlersPtr ExceptionHandlerList::FinalizeExceptionHandlers(
125125
uword entry_point) const {
126126
intptr_t num_handlers = Length();
127127
if (num_handlers == 0) {
128-
return Object::empty_exception_handlers().ptr();
128+
return has_async_handler_ ? Object::empty_async_exception_handlers().ptr()
129+
: Object::empty_exception_handlers().ptr();
129130
}
130131
const ExceptionHandlers& handlers =
131132
ExceptionHandlers::Handle(ExceptionHandlers::New(num_handlers));
133+
handlers.set_has_async_handler(has_async_handler_);
132134
for (intptr_t i = 0; i < num_handlers; i++) {
133135
// Assert that every element in the array has been initialized.
134136
if (list_[i].handler_types == NULL) {

runtime/vm/code_descriptors.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ class ExceptionHandlerList : public ZoneAllocated {
7676
bool needs_stacktrace;
7777
};
7878

79-
ExceptionHandlerList() : list_() {}
79+
explicit ExceptionHandlerList(const Function& function)
80+
: list_(), has_async_handler_(function.IsCompactAsyncFunction()) {}
8081

8182
intptr_t Length() const { return list_.length(); }
8283

@@ -137,6 +138,7 @@ class ExceptionHandlerList : public ZoneAllocated {
137138

138139
private:
139140
GrowableArray<struct HandlerDesc> list_;
141+
const bool has_async_handler_;
140142
DISALLOW_COPY_AND_ASSIGN(ExceptionHandlerList);
141143
};
142144

runtime/vm/compiler/aot/dispatch_table_generator.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ void DispatchTableGenerator::NumberSelectors() {
453453
if (function.IsDynamicFunction(/*allow_abstract=*/false)) {
454454
const bool on_null_interface = klass.IsObjectClass();
455455
const bool requires_args_descriptor =
456-
function.IsGeneric() || function.HasOptionalParameters();
456+
function.PrologueNeedsArgumentsDescriptor();
457457
// Get assigned selector ID for this function.
458458
const int32_t sid = selector_map_.SelectorId(function);
459459
if (sid == SelectorMap::kInvalidSelectorId) {

runtime/vm/compiler/asm_intrinsifier_arm.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1592,8 +1592,7 @@ static void TryAllocateString(Assembler* assembler,
15921592
__ cmp(length_reg, Operand(0));
15931593
__ b(failure, LT);
15941594

1595-
NOT_IN_PRODUCT(__ LoadAllocationStatsAddress(R0, cid));
1596-
NOT_IN_PRODUCT(__ MaybeTraceAllocation(R0, failure));
1595+
NOT_IN_PRODUCT(__ MaybeTraceAllocation(cid, failure, R0));
15971596
__ mov(R8, Operand(length_reg)); // Save the length register.
15981597
if (cid == kOneByteStringCid) {
15991598
__ SmiUntag(length_reg);

runtime/vm/compiler/asm_intrinsifier_arm64.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1819,7 +1819,7 @@ static void TryAllocateString(Assembler* assembler,
18191819
// negative length: call to runtime to produce error.
18201820
__ tbnz(failure, length_reg, compiler::target::kBitsPerWord - 1);
18211821

1822-
NOT_IN_PRODUCT(__ MaybeTraceAllocation(cid, R0, failure));
1822+
NOT_IN_PRODUCT(__ MaybeTraceAllocation(cid, failure, R0));
18231823
__ mov(R6, length_reg); // Save the length register.
18241824
if (cid == kOneByteStringCid) {
18251825
// Untag length.

runtime/vm/compiler/asm_intrinsifier_ia32.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1626,8 +1626,7 @@ static void TryAllocateString(Assembler* assembler,
16261626
__ cmpl(length_reg, Immediate(0));
16271627
__ j(LESS, failure);
16281628

1629-
NOT_IN_PRODUCT(
1630-
__ MaybeTraceAllocation(cid, EAX, failure, Assembler::kFarJump));
1629+
NOT_IN_PRODUCT(__ MaybeTraceAllocation(cid, failure, EAX));
16311630
if (length_reg != EDI) {
16321631
__ movl(EDI, length_reg);
16331632
}

runtime/vm/compiler/asm_intrinsifier_riscv.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1510,7 +1510,7 @@ static void TryAllocateString(Assembler* assembler,
15101510
// negative length: call to runtime to produce error.
15111511
__ bltz(length_reg, failure);
15121512

1513-
NOT_IN_PRODUCT(__ MaybeTraceAllocation(cid, TMP, failure));
1513+
NOT_IN_PRODUCT(__ MaybeTraceAllocation(cid, failure, TMP));
15141514
__ mv(T0, length_reg); // Save the length register.
15151515
if (cid == kOneByteStringCid) {
15161516
// Untag length.

runtime/vm/compiler/asm_intrinsifier_x64.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1702,7 +1702,7 @@ static void TryAllocateString(Assembler* assembler,
17021702
__ cmpq(length_reg, Immediate(0));
17031703
__ j(LESS, failure);
17041704

1705-
NOT_IN_PRODUCT(__ MaybeTraceAllocation(cid, failure, Assembler::kFarJump));
1705+
NOT_IN_PRODUCT(__ MaybeTraceAllocation(cid, failure));
17061706
if (length_reg != RDI) {
17071707
__ movq(RDI, length_reg);
17081708
}

runtime/vm/compiler/assembler/assembler_arm.cc

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3161,6 +3161,19 @@ void Assembler::AndImmediate(Register rd,
31613161
}
31623162
}
31633163

3164+
void Assembler::OrImmediate(Register rd,
3165+
Register rs,
3166+
int32_t imm,
3167+
Condition cond) {
3168+
Operand o;
3169+
if (Operand::CanHold(imm, &o)) {
3170+
orr(rd, rs, Operand(o), cond);
3171+
} else {
3172+
LoadImmediate(TMP, imm, cond);
3173+
orr(rd, rs, Operand(TMP), cond);
3174+
}
3175+
}
3176+
31643177
void Assembler::CompareImmediate(Register rn, int32_t value, Condition cond) {
31653178
Operand o;
31663179
if (Operand::CanHold(value, &o)) {
@@ -3516,6 +3529,14 @@ void Assembler::MaybeTraceAllocation(Register stats_addr_reg, Label* trace) {
35163529
b(trace, NE);
35173530
}
35183531

3532+
void Assembler::MaybeTraceAllocation(intptr_t cid,
3533+
Label* trace,
3534+
Register temp_reg,
3535+
JumpDistance distance) {
3536+
LoadAllocationStatsAddress(temp_reg, cid);
3537+
MaybeTraceAllocation(temp_reg, trace);
3538+
}
3539+
35193540
void Assembler::LoadAllocationStatsAddress(Register dest, intptr_t cid) {
35203541
ASSERT(dest != kNoRegister);
35213542
ASSERT(dest != TMP);
@@ -3623,6 +3644,21 @@ void Assembler::TryAllocateArray(intptr_t cid,
36233644
}
36243645
}
36253646

3647+
void Assembler::CopyMemoryWords(Register src,
3648+
Register dst,
3649+
Register size,
3650+
Register temp) {
3651+
Label loop, done;
3652+
__ cmp(size, Operand(0));
3653+
__ b(&done, EQUAL);
3654+
__ Bind(&loop);
3655+
__ ldr(temp, Address(src, target::kWordSize, Address::PostIndex));
3656+
__ str(temp, Address(dst, target::kWordSize, Address::PostIndex));
3657+
__ subs(size, size, Operand(target::kWordSize));
3658+
__ b(&loop, NOT_ZERO);
3659+
__ Bind(&done);
3660+
}
3661+
36263662
void Assembler::GenerateUnRelocatedPcRelativeCall(Condition cond,
36273663
intptr_t offset_into_target) {
36283664
// Emit "blr.cond <offset>".

runtime/vm/compiler/assembler/assembler_arm.h

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,8 @@ class Assembler : public AssemblerBase {
385385
void Bind(Label* label);
386386
// Unconditional jump to a given label. [distance] is ignored on ARM.
387387
void Jump(Label* label, JumpDistance distance = kFarJump) { b(label); }
388+
// Unconditional jump to a given address in register.
389+
void Jump(Register target) { bx(target); }
388390
// Unconditional jump to a given address in memory.
389391
void Jump(const Address& address) { Branch(address); }
390392

@@ -415,9 +417,6 @@ class Assembler : public AssemblerBase {
415417
// We don't run TSAN bots on 32 bit.
416418
}
417419

418-
void CompareWithFieldValue(Register value, FieldAddress address) {
419-
CompareWithMemoryValue(value, address);
420-
}
421420
void CompareWithCompressedFieldFromOffset(Register value,
422421
Register base,
423422
int32_t offset) {
@@ -818,6 +817,9 @@ class Assembler : public AssemblerBase {
818817
Register rn,
819818
int32_t value,
820819
Condition cond = AL);
820+
void AddRegisters(Register dest, Register src) {
821+
add(dest, dest, Operand(src));
822+
}
821823
void SubImmediate(Register rd,
822824
Register rn,
823825
int32_t value,
@@ -826,7 +828,24 @@ class Assembler : public AssemblerBase {
826828
Register rn,
827829
int32_t value,
828830
Condition cond = AL);
831+
void SubRegisters(Register dest, Register src) {
832+
sub(dest, dest, Operand(src));
833+
}
829834
void AndImmediate(Register rd, Register rs, int32_t imm, Condition cond = AL);
835+
void AndImmediate(Register rd, int32_t imm, Condition cond = AL) {
836+
AndImmediate(rd, rd, imm, cond);
837+
}
838+
void OrImmediate(Register rd, Register rs, int32_t imm, Condition cond = AL);
839+
void OrImmediate(Register rd, int32_t imm, Condition cond = AL) {
840+
OrImmediate(rd, rd, imm, cond);
841+
}
842+
void LslImmediate(Register rd, Register rn, int32_t shift) {
843+
ASSERT((shift >= 0) && (shift < kBitsPerInt32));
844+
Lsl(rd, rn, Operand(shift));
845+
}
846+
void LslImmediate(Register rd, int32_t shift) {
847+
LslImmediate(rd, rd, shift);
848+
}
830849

831850
// Test rn and immediate. May clobber IP.
832851
void TestImmediate(Register rn, int32_t imm, Condition cond = AL);
@@ -1051,6 +1070,10 @@ class Assembler : public AssemblerBase {
10511070
Condition cond = AL) {
10521071
StoreToOffset(reg, base, offset - kHeapObjectTag, type, cond);
10531072
}
1073+
void StoreZero(const Address& address, Register temp) {
1074+
mov(temp, Operand(0));
1075+
str(temp, address);
1076+
}
10541077
void LoadSFromOffset(SRegister reg,
10551078
Register base,
10561079
int32_t offset,
@@ -1137,6 +1160,14 @@ class Assembler : public AssemblerBase {
11371160
cmp(rn, Operand(0));
11381161
b(label, ZERO);
11391162
}
1163+
void BranchIfBit(Register rn,
1164+
intptr_t bit_number,
1165+
Condition condition,
1166+
Label* label,
1167+
JumpDistance distance = kFarJump) {
1168+
tst(rn, Operand(1 << bit_number));
1169+
b(label, condition);
1170+
}
11401171

11411172
void MoveRegister(Register rd, Register rm, Condition cond) {
11421173
ExtendValue(rd, rm, kFourBytes, cond);
@@ -1368,6 +1399,13 @@ class Assembler : public AssemblerBase {
13681399
// which will allocate in the runtime where tracing occurs.
13691400
void MaybeTraceAllocation(Register stats_addr_reg, Label* trace);
13701401

1402+
// If allocation tracing for |cid| is enabled, will jump to |trace| label,
1403+
// which will allocate in the runtime where tracing occurs.
1404+
void MaybeTraceAllocation(intptr_t cid,
1405+
Label* trace,
1406+
Register temp_reg,
1407+
JumpDistance distance = JumpDistance::kFarJump);
1408+
13711409
void TryAllocateObject(intptr_t cid,
13721410
intptr_t instance_size,
13731411
Label* failure,
@@ -1383,6 +1421,14 @@ class Assembler : public AssemblerBase {
13831421
Register temp1,
13841422
Register temp2);
13851423

1424+
// Copy [size] bytes from [src] address to [dst] address.
1425+
// [size] should be a multiple of word size.
1426+
// Clobbers [src], [dst], [size] and [temp] registers.
1427+
void CopyMemoryWords(Register src,
1428+
Register dst,
1429+
Register size,
1430+
Register temp);
1431+
13861432
// This emits an PC-relative call of the form "blr.<cond> <offset>". The
13871433
// offset is not yet known and needs therefore relocation to the right place
13881434
// before the code can be used.

runtime/vm/compiler/assembler/assembler_arm64.cc

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1998,8 +1998,9 @@ void Assembler::BranchOnMonomorphicCheckedEntryJIT(Label* label) {
19981998

19991999
#ifndef PRODUCT
20002000
void Assembler::MaybeTraceAllocation(intptr_t cid,
2001+
Label* trace,
20012002
Register temp_reg,
2002-
Label* trace) {
2003+
JumpDistance distance) {
20032004
ASSERT(cid > 0);
20042005

20052006
const intptr_t shared_table_offset =
@@ -2034,7 +2035,7 @@ void Assembler::TryAllocateObject(intptr_t cid,
20342035
// If this allocation is traced, program will jump to failure path
20352036
// (i.e. the allocation stub) which will allocate the object and trace the
20362037
// allocation call site.
2037-
NOT_IN_PRODUCT(MaybeTraceAllocation(cid, temp_reg, failure));
2038+
NOT_IN_PRODUCT(MaybeTraceAllocation(cid, failure, temp_reg));
20382039
RELEASE_ASSERT((target::Thread::top_offset() + target::kWordSize) ==
20392040
target::Thread::end_offset());
20402041
ldp(instance_reg, temp_reg,
@@ -2076,7 +2077,7 @@ void Assembler::TryAllocateArray(intptr_t cid,
20762077
// If this allocation is traced, program will jump to failure path
20772078
// (i.e. the allocation stub) which will allocate the object and trace the
20782079
// allocation call site.
2079-
NOT_IN_PRODUCT(MaybeTraceAllocation(cid, temp1, failure));
2080+
NOT_IN_PRODUCT(MaybeTraceAllocation(cid, failure, temp1));
20802081
// Potential new object start.
20812082
ldr(instance, Address(THR, target::Thread::top_offset()));
20822083
AddImmediateSetFlags(end_address, instance, instance_size);
@@ -2105,6 +2106,20 @@ void Assembler::TryAllocateArray(intptr_t cid,
21052106
}
21062107
}
21072108

2109+
void Assembler::CopyMemoryWords(Register src,
2110+
Register dst,
2111+
Register size,
2112+
Register temp) {
2113+
Label loop, done;
2114+
__ cbz(&done, size);
2115+
__ Bind(&loop);
2116+
__ ldr(temp, Address(src, target::kWordSize, Address::PostIndex));
2117+
__ str(temp, Address(dst, target::kWordSize, Address::PostIndex));
2118+
__ subs(size, size, Operand(target::kWordSize));
2119+
__ b(&loop, NOT_ZERO);
2120+
__ Bind(&done);
2121+
}
2122+
21082123
void Assembler::GenerateUnRelocatedPcRelativeCall(intptr_t offset_into_target) {
21092124
// Emit "bl <offset>".
21102125
EmitUnconditionalBranchOp(BL, 0);

0 commit comments

Comments
 (0)