1
0
mirror of https://github.com/dart-lang/sdk synced 2024-07-05 09:20:04 +00:00

[dart2wasm] Fix bug in restoration of this in async functions.

When entering async functions we read the suspend-state's context and
populate local variables with the context parent chain as well as the
this pointer.

This restoration code assumed that `this` is stored in the outermost
context, which isn't necessarily the case.

In constructors the outermost context can contain the type parameters.

TEST=tests/web/wasm/capture_type_and_this_test.dart

Change-Id: Ie8e3c8732203aea4964d48cb78c97578d0322b2b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/364321
Reviewed-by: Ömer Ağacan <omersa@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Martin Kustermann 2024-04-24 10:03:00 +00:00 committed by Commit Queue
parent 2a2781edff
commit e44bc22ca3
2 changed files with 52 additions and 13 deletions

View File

@ -898,19 +898,26 @@ class AsyncCodeGenerator extends CodeGenerator {
_cloneContext(cloneContextFor!, context, context.currentLocal);
}
while (context!.parent != null) {
assert(!context.parent!.isEmpty);
b.local_get(context.currentLocal);
b.struct_get(context.struct, context.parentFieldIndex);
b.ref_as_non_null();
context = context.parent!;
b.local_set(context.currentLocal);
}
if (context.containsThis) {
b.local_get(context.currentLocal);
b.struct_get(context.struct, context.thisFieldIndex);
b.ref_as_non_null();
b.local_set(thisLocal!);
bool restoredThis = false;
while (context != null) {
if (context.containsThis) {
assert(!restoredThis);
b.local_get(context.currentLocal);
b.struct_get(context.struct, context.thisFieldIndex);
b.ref_as_non_null();
b.local_set(thisLocal!);
restoredThis = true;
}
final parent = context.parent;
if (parent != null) {
assert(!parent.isEmpty);
b.local_get(context.currentLocal);
b.struct_get(context.struct, context.parentFieldIndex);
b.ref_as_non_null();
b.local_set(parent.currentLocal);
}
context = parent;
}
}
}

View File

@ -0,0 +1,32 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
late final Type capturedType;
late final A capturedThis;
class A<T> {
A() {
foo() async {
// This will create a context chain as follows:
// Context [T]
// `--> Context [<parent-context>, this]
// `--> Context [<parent-context, ...]
capturedType = T;
capturedThis = this;
}
foo();
}
}
main() {
final a = A<String>();
if (!identical(a, capturedThis)) {
throw 'Should have captured the correct `this`.';
}
if (!identical(String, capturedType)) {
throw 'Should have captured the correct `T`.';
}
}