mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 18:19:44 +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:
parent
2a2781edff
commit
e44bc22ca3
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
32
tests/web/wasm/capture_type_and_this_test.dart
Normal file
32
tests/web/wasm/capture_type_and_this_test.dart
Normal 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`.';
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue