7b53e209c5
Summary: 1. Previously, in 'BuildGraphOfConvertedClosureFunction', the VM was unable to correctly forward parameters to converted closure functions when they were captured in the converted function's body. This could happen when, for example, a closure was introduced into it by async conversion. Now, this is fixed by an approach that mirrors the technique in 'BuildGraphOfFunction'. 2. Previously, local variables declared inside loop bodies were being saved in the loop's enclosing context, so closures within the loop would see new values initialized to the variable in subsequent iterations. Now, this is fixed by creating nested contexts for all loops, regardless of whether the loop variables are captured. 3. Previously, arity checks were not being performed on converted closures, so they could be called with too few or too many arguments. In the former case, the missing arguments would be filled in with garbage on the stack. Now, the assembly generation in 'CompileGraph' inserts argument count checks for converted closures as well as regular closures. Test Plan: Introduced new tests in the closure conversion suite to test each bug: 1. syncstart.dart 2. loop2.dart, blocks.dart, updated for_in_closure.dart 3. arity.dart With these changes, closure conversion passes all co19 tests in non-checked mode, except those that are not passed without it: python tools/test.py -m release -c dartk --vm-options "--reify --reify_generic_functions" co19 BUG= R=dmitryas@google.com Review-Url: https://codereview.chromium.org/3000333002 .
31 lines
871 B
Dart
31 lines
871 B
Dart
// Copyright (c) 2017, 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.
|
|
//
|
|
// Check that a variable declared and captured inside a loop is given a separate
|
|
// context for each iteration of the loop, so changes to the variable in
|
|
// subsequent iterations are not visible to closures capturing it in prior
|
|
// iterations.
|
|
|
|
void doit(int x) {
|
|
final int max = 10;
|
|
final double expectedSum = ((max - 1) * max) / 2;
|
|
|
|
int counter = 0;
|
|
var calls = [];
|
|
while (counter < max) {
|
|
int pos = counter;
|
|
calls.add(() => pos + x);
|
|
counter++;
|
|
}
|
|
|
|
double sum = 0.0;
|
|
for (var c in calls) sum += c();
|
|
if (sum != expectedSum)
|
|
throw new Exception("Unexpected sum = $sum != $expectedSum");
|
|
}
|
|
|
|
void main() {
|
|
doit(0);
|
|
}
|