Revert "Run async functions immediately."
This reverts commit 67bac0bce6.
Reason for revert: broke the bot.
Original change's description:
> Run async functions immediately.
>
> Migrated from https://codereview.chromium.org/2478703003/
>
> Change-Id: I1d678c01ba5876490b12c676c500171328361d31
> Reviewed-on: https://dart-review.googlesource.com/5263
> Commit-Queue: Florian Loitsch <floitsch@google.com>
> Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
> Reviewed-by: Vijay Menon <vsm@google.com>
> Reviewed-by: William Hesse <whesse@google.com>
> Reviewed-by: Martin Kustermann <kustermann@google.com>
> Reviewed-by: Régis Crelier <regis@google.com>
TBR=whesse@google.com,rnystrom@google.com,vegorov@google.com,kustermann@google.com,zra@google.com,floitsch@google.com,jmesserly@google.com,vsm@google.com,regis@google.com,sigmund@google.com
Change-Id: I20c948057423c3fa5aa8c72843f8f2a17e086ad5
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/37981
Reviewed-by: Florian Loitsch <floitsch@google.com>
Reviewed-by: William Hesse <whesse@google.com>
This commit is contained in:
@@ -8,9 +8,6 @@
|
||||
This allows libraries with no library declarations (and therefore no name)
|
||||
to have parts, and it allows tools to easily find the library of a part
|
||||
file.
|
||||
* Added support for starting `async` functions synchronously. All tools (VM,
|
||||
dart2js, DDC) have now a flag `--sync-async` to enable this behavior.
|
||||
Currently this behavior is opt-in. It will become the default.
|
||||
|
||||
#### Strong Mode
|
||||
|
||||
|
||||
@@ -88,11 +88,6 @@ class Flags {
|
||||
// https://gist.github.com/eernstg/4353d7b4f669745bed3a5423e04a453c.
|
||||
static const String genericMethodSyntax = '--generic-method-syntax';
|
||||
|
||||
// Starts `async` functions synchronously.
|
||||
//
|
||||
// This is the Dart 2.0 behavior. This flag is only used during the migration.
|
||||
static const String syncAsync = '--sync-async';
|
||||
|
||||
// Initializing-formal access is enabled by default and cannot be disabled.
|
||||
// For backward compatibility the option is still accepted, but it is ignored.
|
||||
static const String initializingFormalAccess = '--initializing-formal-access';
|
||||
|
||||
@@ -508,8 +508,6 @@ class CommonElements {
|
||||
|
||||
FunctionEntity get asyncHelperStart =>
|
||||
_findAsyncHelperFunction("_asyncStart");
|
||||
FunctionEntity get asyncHelperStartSync =>
|
||||
_findAsyncHelperFunction("_asyncStartSync");
|
||||
FunctionEntity get asyncHelperAwait =>
|
||||
_findAsyncHelperFunction("_asyncAwait");
|
||||
FunctionEntity get asyncHelperReturn =>
|
||||
@@ -552,12 +550,6 @@ class CommonElements {
|
||||
ConstructorEntity get syncCompleterConstructor =>
|
||||
_env.lookupConstructor(_findAsyncHelperClass("Completer"), "sync");
|
||||
|
||||
ConstructorEntity get asyncAwaitCompleterConstructor =>
|
||||
_env.lookupConstructor(asyncAwaitCompleter, "");
|
||||
|
||||
ClassEntity get asyncAwaitCompleter =>
|
||||
_findAsyncHelperClass("_AsyncAwaitCompleter");
|
||||
|
||||
ClassEntity get asyncStarController =>
|
||||
_findAsyncHelperClass("_AsyncStarStreamController");
|
||||
|
||||
|
||||
@@ -355,7 +355,6 @@ Future<api.CompilationResult> compile(List<String> argv,
|
||||
new OptionHandler(Flags.allowMockCompilation, passThrough),
|
||||
new OptionHandler(Flags.fastStartup, passThrough),
|
||||
new OptionHandler(Flags.genericMethodSyntax, ignoreOption),
|
||||
new OptionHandler(Flags.syncAsync, passThrough),
|
||||
new OptionHandler(Flags.initializingFormalAccess, ignoreOption),
|
||||
new OptionHandler('${Flags.minify}|-m', implyCompilation),
|
||||
new OptionHandler(Flags.preserveUris, passThrough),
|
||||
|
||||
@@ -700,8 +700,7 @@ class JavaScriptBackend {
|
||||
NativeBasicData nativeBasicData = compiler.frontendStrategy.nativeBasicData;
|
||||
RuntimeTypesNeedBuilder rtiNeedBuilder =
|
||||
compiler.frontendStrategy.createRuntimeTypesNeedBuilder();
|
||||
BackendImpacts impacts =
|
||||
new BackendImpacts(compiler.options, commonElements);
|
||||
BackendImpacts impacts = new BackendImpacts(commonElements);
|
||||
TypeVariableResolutionAnalysis typeVariableResolutionAnalysis =
|
||||
new TypeVariableResolutionAnalysis(
|
||||
compiler.frontendStrategy.elementEnvironment,
|
||||
@@ -784,8 +783,7 @@ class JavaScriptBackend {
|
||||
CompilerTask task, Compiler compiler, ClosedWorld closedWorld) {
|
||||
ElementEnvironment elementEnvironment = closedWorld.elementEnvironment;
|
||||
CommonElements commonElements = closedWorld.commonElements;
|
||||
BackendImpacts impacts =
|
||||
new BackendImpacts(compiler.options, commonElements);
|
||||
BackendImpacts impacts = new BackendImpacts(commonElements);
|
||||
_typeVariableCodegenAnalysis = new TypeVariableCodegenAnalysis(
|
||||
closedWorld.elementEnvironment, this, commonElements, mirrorsData);
|
||||
_mirrorsCodegenAnalysis = mirrorsResolutionAnalysis.close();
|
||||
@@ -983,8 +981,7 @@ class JavaScriptBackend {
|
||||
emitter.createEmitter(namer, closedWorld, codegenWorldBuilder, sorter);
|
||||
// TODO(johnniwinther): Share the impact object created in
|
||||
// createCodegenEnqueuer.
|
||||
BackendImpacts impacts =
|
||||
new BackendImpacts(compiler.options, closedWorld.commonElements);
|
||||
BackendImpacts impacts = new BackendImpacts(closedWorld.commonElements);
|
||||
if (compiler.options.disableRtiOptimization) {
|
||||
_rtiSubstitutions = new TrivialRuntimeTypesSubstitutions(
|
||||
closedWorld.elementEnvironment, closedWorld.dartTypes);
|
||||
@@ -1170,20 +1167,13 @@ class JavaScriptBackend {
|
||||
jsAst.Expression code,
|
||||
SourceInformation bodySourceInformation,
|
||||
SourceInformation exitSourceInformation) {
|
||||
bool startAsyncSynchronously = compiler.options.startAsyncSynchronously;
|
||||
|
||||
AsyncRewriterBase rewriter = null;
|
||||
jsAst.Name name = namer.methodPropertyName(element);
|
||||
switch (element.asyncMarker) {
|
||||
case AsyncMarker.ASYNC:
|
||||
var startFunction = startAsyncSynchronously
|
||||
? commonElements.asyncHelperStartSync
|
||||
: commonElements.asyncHelperStart;
|
||||
var completerConstructor = startAsyncSynchronously
|
||||
? commonElements.asyncAwaitCompleterConstructor
|
||||
: commonElements.syncCompleterConstructor;
|
||||
rewriter = new AsyncRewriter(reporter, element,
|
||||
asyncStart: emitter.staticFunctionAccess(startFunction),
|
||||
asyncStart:
|
||||
emitter.staticFunctionAccess(commonElements.asyncHelperStart),
|
||||
asyncAwait:
|
||||
emitter.staticFunctionAccess(commonElements.asyncHelperAwait),
|
||||
asyncReturn:
|
||||
@@ -1191,8 +1181,8 @@ class JavaScriptBackend {
|
||||
asyncRethrow:
|
||||
emitter.staticFunctionAccess(commonElements.asyncHelperRethrow),
|
||||
wrapBody: emitter.staticFunctionAccess(commonElements.wrapBody),
|
||||
completerFactory:
|
||||
emitter.staticFunctionAccess(completerConstructor),
|
||||
completerFactory: emitter
|
||||
.staticFunctionAccess(commonElements.syncCompleterConstructor),
|
||||
safeVariableName: namer.safeVariablePrefixForAsyncRewrite,
|
||||
bodyName: namer.deriveAsyncBodyName(name));
|
||||
break;
|
||||
|
||||
@@ -8,7 +8,6 @@ import '../common/names.dart';
|
||||
import '../common_elements.dart' show CommonElements, ElementEnvironment;
|
||||
import '../elements/types.dart' show InterfaceType;
|
||||
import '../elements/entities.dart';
|
||||
import '../options.dart' show CompilerOptions;
|
||||
import '../universe/selector.dart';
|
||||
import '../universe/world_impact.dart'
|
||||
show WorldImpact, WorldImpactBuilder, WorldImpactBuilderImpl;
|
||||
@@ -89,10 +88,9 @@ class BackendImpact {
|
||||
|
||||
/// The JavaScript backend dependencies for various features.
|
||||
class BackendImpacts {
|
||||
final CompilerOptions _options;
|
||||
final CommonElements _commonElements;
|
||||
|
||||
BackendImpacts(this._options, this._commonElements);
|
||||
BackendImpacts(this._commonElements);
|
||||
|
||||
BackendImpact _getRuntimeTypeArgument;
|
||||
|
||||
@@ -128,24 +126,15 @@ class BackendImpacts {
|
||||
BackendImpact _asyncBody;
|
||||
|
||||
BackendImpact get asyncBody {
|
||||
var staticUses = [
|
||||
return _asyncBody ??= new BackendImpact(staticUses: [
|
||||
_commonElements.asyncHelperStart,
|
||||
_commonElements.asyncHelperAwait,
|
||||
_commonElements.asyncHelperReturn,
|
||||
_commonElements.asyncHelperRethrow,
|
||||
_commonElements.syncCompleterConstructor,
|
||||
_commonElements.streamIteratorConstructor,
|
||||
_commonElements.wrapBody
|
||||
];
|
||||
var instantiantedClasses = <ClassEntity>[];
|
||||
if (_options.startAsyncSynchronously) {
|
||||
staticUses.add(_commonElements.asyncAwaitCompleterConstructor);
|
||||
staticUses.add(_commonElements.asyncHelperStartSync);
|
||||
instantiantedClasses.add(_commonElements.asyncAwaitCompleter);
|
||||
} else {
|
||||
staticUses.add(_commonElements.syncCompleterConstructor);
|
||||
staticUses.add(_commonElements.asyncHelperStart);
|
||||
}
|
||||
return _asyncBody ??= new BackendImpact(
|
||||
staticUses: staticUses, instantiatedClasses: instantiantedClasses);
|
||||
]);
|
||||
}
|
||||
|
||||
BackendImpact _syncStarBody;
|
||||
|
||||
@@ -276,9 +276,6 @@ class CompilerOptions implements DiagnosticOptions {
|
||||
/// Strip option used by dart2dart.
|
||||
final List<String> strips;
|
||||
|
||||
/// Whether to start `async` functions synchronously.
|
||||
final bool startAsyncSynchronously;
|
||||
|
||||
/// Create an options object by parsing flags from [options].
|
||||
factory CompilerOptions.parse(
|
||||
{Uri entryPoint,
|
||||
@@ -359,7 +356,6 @@ class CompilerOptions implements DiagnosticOptions {
|
||||
useMultiSourceInfo: _hasOption(options, Flags.useMultiSourceInfo),
|
||||
useNewSourceInfo: _hasOption(options, Flags.useNewSourceInfo),
|
||||
useStartupEmitter: _hasOption(options, Flags.fastStartup),
|
||||
startAsyncSynchronously: _hasOption(options, Flags.syncAsync),
|
||||
verbose: _hasOption(options, Flags.verbose));
|
||||
}
|
||||
|
||||
@@ -425,7 +421,6 @@ class CompilerOptions implements DiagnosticOptions {
|
||||
bool useMultiSourceInfo: false,
|
||||
bool useNewSourceInfo: false,
|
||||
bool useStartupEmitter: false,
|
||||
bool startAsyncSynchronously: false,
|
||||
bool verbose: false}) {
|
||||
// TODO(sigmund): should entrypoint be here? should we validate it is not
|
||||
// null? In unittests we use the same compiler to analyze or build multiple
|
||||
@@ -509,7 +504,6 @@ class CompilerOptions implements DiagnosticOptions {
|
||||
useMultiSourceInfo: useMultiSourceInfo,
|
||||
useNewSourceInfo: useNewSourceInfo,
|
||||
useStartupEmitter: useStartupEmitter,
|
||||
startAsyncSynchronously: startAsyncSynchronously,
|
||||
verbose: verbose);
|
||||
}
|
||||
|
||||
@@ -565,7 +559,6 @@ class CompilerOptions implements DiagnosticOptions {
|
||||
this.useMultiSourceInfo: false,
|
||||
this.useNewSourceInfo: false,
|
||||
this.useStartupEmitter: false,
|
||||
this.startAsyncSynchronously: false,
|
||||
this.verbose: false})
|
||||
: _shownPackageWarnings = shownPackageWarnings;
|
||||
|
||||
|
||||
@@ -60,12 +60,6 @@ if [ "$1" = "-k" ]; then
|
||||
shift
|
||||
fi
|
||||
|
||||
SYNC_ASYNC=false
|
||||
if [ "$1" = "--sync-async" ]; then
|
||||
SYNC_ASYNC=true
|
||||
shift
|
||||
fi
|
||||
|
||||
BASENAME=$( basename "${1%.*}")
|
||||
LIBROOT=$(cd $( dirname "${1%.*}") && pwd)
|
||||
|
||||
@@ -110,7 +104,6 @@ echo "
|
||||
let sdk = require(\"dart_sdk\");
|
||||
let main = require(\"./$BASENAME\").$BASENAME.main;
|
||||
sdk.dart.ignoreWhitelistedErrors(false);
|
||||
if ($SYNC_ASYNC) sdk.dart.setStartAsyncSynchronously();
|
||||
try {
|
||||
sdk._isolate_helper.startRootIsolate(main, []);
|
||||
} catch(e) {
|
||||
|
||||
@@ -17,8 +17,6 @@ import 'dart:_isolate_helper'
|
||||
|
||||
import 'dart:_foreign_helper' show JS, JSExportName;
|
||||
|
||||
import 'dart:_runtime' as dart;
|
||||
|
||||
typedef void _Callback();
|
||||
typedef void _TakeCallback(_Callback callback);
|
||||
|
||||
@@ -69,7 +67,7 @@ async_<T>(Function() initGenerator) {
|
||||
onError = zone.registerUnaryCallback(onError);
|
||||
}
|
||||
var asyncFuture = new _Future<T>();
|
||||
var body = () {
|
||||
scheduleMicrotask(() {
|
||||
try {
|
||||
iter = JS('', '#[Symbol.iterator]()', initGenerator());
|
||||
var iteratorValue = JS('', '#.next(null)', iter);
|
||||
@@ -99,20 +97,9 @@ async_<T>(Function() initGenerator) {
|
||||
_Future._chainCoreFuture(onAwait(value), asyncFuture);
|
||||
}
|
||||
} catch (e, s) {
|
||||
if (dart.startAsyncSynchronously) {
|
||||
scheduleMicrotask(() {
|
||||
_completeWithErrorCallback(asyncFuture, e, s);
|
||||
});
|
||||
} else {
|
||||
_completeWithErrorCallback(asyncFuture, e, s);
|
||||
}
|
||||
_completeWithErrorCallback(asyncFuture, e, s);
|
||||
}
|
||||
};
|
||||
if (dart.startAsyncSynchronously) {
|
||||
body();
|
||||
} else {
|
||||
scheduleMicrotask(body);
|
||||
}
|
||||
});
|
||||
return asyncFuture;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,12 +11,6 @@
|
||||
/// stepping stone for proposed ES7 async/await, and uses ES6 Promises.
|
||||
part of dart._runtime;
|
||||
|
||||
// TODO(vsm): Remove once this flag is the default.
|
||||
bool startAsyncSynchronously = false;
|
||||
void setStartAsyncSynchronously() {
|
||||
startAsyncSynchronously = true;
|
||||
}
|
||||
|
||||
final _jsIterator = JS('', 'Symbol("_jsIterator")');
|
||||
final _current = JS('', 'Symbol("_current")');
|
||||
|
||||
|
||||
@@ -228,13 +228,9 @@ ProcessedOptions analyzeCommandLine(
|
||||
final bool strongMode =
|
||||
options.containsKey("--strong-mode") || options.containsKey("--strong");
|
||||
|
||||
final bool syncAsync = options.containsKey("--sync-async");
|
||||
|
||||
final String targetName = options["-t"] ?? options["--target"] ?? "vm";
|
||||
|
||||
final TargetFlags flags =
|
||||
new TargetFlags(strongMode: strongMode, syncAsync: syncAsync);
|
||||
|
||||
final TargetFlags flags = new TargetFlags(strongMode: strongMode);
|
||||
final Target target = getTarget(targetName, flags);
|
||||
if (target == null) {
|
||||
return throw new CommandLineProblem.deprecated(
|
||||
|
||||
@@ -44,10 +44,7 @@ ArgParser parser = new ArgParser()
|
||||
..addOption('transformation',
|
||||
abbr: 't',
|
||||
help: 'The transformation to apply.',
|
||||
defaultsTo: 'continuation')
|
||||
..addFlag('sync-async',
|
||||
help: 'Whether `async` functions start synchronously.',
|
||||
defaultsTo: false);
|
||||
defaultsTo: 'continuation');
|
||||
|
||||
main(List<String> arguments) async {
|
||||
if (arguments.isNotEmpty && arguments[0] == '--batch') {
|
||||
@@ -72,7 +69,6 @@ Future<CompilerOutcome> runTransformation(List<String> arguments) async {
|
||||
var output = options['out'];
|
||||
var format = options['format'];
|
||||
var verbose = options['verbose'];
|
||||
var syncAsync = options['sync-async'];
|
||||
|
||||
if (output == null) {
|
||||
output = '${input.substring(0, input.lastIndexOf('.'))}.transformed.dill';
|
||||
@@ -89,7 +85,7 @@ Future<CompilerOutcome> runTransformation(List<String> arguments) async {
|
||||
final hierarchy = new ClassHierarchy(program);
|
||||
switch (options['transformation']) {
|
||||
case 'continuation':
|
||||
program = cont.transformProgram(coreTypes, program, syncAsync);
|
||||
program = cont.transformProgram(coreTypes, program);
|
||||
break;
|
||||
case 'resolve-mixins':
|
||||
mix.transformLibraries(
|
||||
|
||||
@@ -79,9 +79,7 @@ class CoreTypes {
|
||||
Class _stackTraceClass;
|
||||
Class _streamClass;
|
||||
Class _completerClass;
|
||||
Class _asyncAwaitCompleterClass;
|
||||
Class _futureOrClass;
|
||||
Constructor _asyncAwaitCompleterConstructor;
|
||||
Procedure _completerSyncConstructor;
|
||||
Procedure _completerComplete;
|
||||
Procedure _completerCompleteError;
|
||||
@@ -164,21 +162,11 @@ class CoreTypes {
|
||||
return _completerClass ??= _index.getClass('dart:async', 'Completer');
|
||||
}
|
||||
|
||||
Class get asyncAwaitCompleterClass {
|
||||
return _asyncAwaitCompleterClass ??=
|
||||
_index.getClass('dart:async', '_AsyncAwaitCompleter');
|
||||
}
|
||||
|
||||
Procedure get completerSyncConstructor {
|
||||
return _completerSyncConstructor ??=
|
||||
_index.getMember('dart:async', 'Completer', 'sync');
|
||||
}
|
||||
|
||||
Constructor get asyncAwaitCompleterConstructor {
|
||||
return _asyncAwaitCompleterConstructor ??=
|
||||
_index.getMember('dart:async', '_AsyncAwaitCompleter', '');
|
||||
}
|
||||
|
||||
Procedure get completerComplete {
|
||||
return _completerComplete ??=
|
||||
_index.getMember('dart:async', 'Completer', 'complete');
|
||||
|
||||
@@ -15,20 +15,16 @@ import 'vmreify.dart' show VmGenericTypesReifiedTarget;
|
||||
final List<String> targetNames = targets.keys.toList();
|
||||
|
||||
class TargetFlags {
|
||||
final bool strongMode;
|
||||
final bool treeShake;
|
||||
|
||||
/// Whether `async` functions start synchronously.
|
||||
final bool syncAsync;
|
||||
final List<ProgramRoot> programRoots;
|
||||
final Uri kernelRuntime;
|
||||
bool strongMode;
|
||||
bool treeShake;
|
||||
List<ProgramRoot> programRoots;
|
||||
Uri kernelRuntime;
|
||||
|
||||
TargetFlags(
|
||||
{this.strongMode: false,
|
||||
this.treeShake: false,
|
||||
this.syncAsync: false,
|
||||
this.programRoots: const <ProgramRoot>[],
|
||||
this.kernelRuntime});
|
||||
this.kernelRuntime}) {}
|
||||
}
|
||||
|
||||
typedef Target _TargetBuilder(TargetFlags flags);
|
||||
|
||||
@@ -64,7 +64,7 @@ class VmTarget extends Target {
|
||||
logger?.call("Transformed mixin applications");
|
||||
|
||||
// TODO(kmillikin): Make this run on a per-method basis.
|
||||
transformAsync.transformLibraries(coreTypes, libraries, flags.syncAsync);
|
||||
transformAsync.transformLibraries(coreTypes, libraries);
|
||||
logger?.call("Transformed async methods");
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ class VmClosureConvertedTarget extends vm_target.VmTarget {
|
||||
performTreeShaking(coreTypes, program);
|
||||
}
|
||||
|
||||
cont.transformProgram(coreTypes, program, flags.syncAsync);
|
||||
cont.transformProgram(coreTypes, program);
|
||||
|
||||
new SanitizeForVM().transform(program);
|
||||
|
||||
|
||||
@@ -484,8 +484,8 @@ class ExpressionLifter extends Transformer {
|
||||
}
|
||||
|
||||
visitFunctionNode(FunctionNode node) {
|
||||
var nestedRewriter = new RecursiveContinuationRewriter(
|
||||
continuationRewriter.helper, continuationRewriter.syncAsync);
|
||||
var nestedRewriter =
|
||||
new RecursiveContinuationRewriter(continuationRewriter.helper);
|
||||
return node.accept(nestedRewriter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,34 +12,29 @@ import '../visitor.dart';
|
||||
|
||||
import 'async.dart';
|
||||
|
||||
void transformLibraries(
|
||||
CoreTypes coreTypes, List<Library> libraries, bool syncAsync) {
|
||||
void transformLibraries(CoreTypes coreTypes, List<Library> libraries) {
|
||||
var helper = new HelperNodes.fromCoreTypes(coreTypes);
|
||||
var rewriter = new RecursiveContinuationRewriter(helper, syncAsync);
|
||||
var rewriter = new RecursiveContinuationRewriter(helper);
|
||||
for (var library in libraries) {
|
||||
rewriter.rewriteLibrary(library);
|
||||
}
|
||||
}
|
||||
|
||||
Program transformProgram(CoreTypes coreTypes, Program program, bool syncAsync) {
|
||||
Program transformProgram(CoreTypes coreTypes, Program program) {
|
||||
var helper = new HelperNodes.fromCoreTypes(coreTypes);
|
||||
var rewriter = new RecursiveContinuationRewriter(helper, syncAsync);
|
||||
var rewriter = new RecursiveContinuationRewriter(helper);
|
||||
return rewriter.rewriteProgram(program);
|
||||
}
|
||||
|
||||
class RecursiveContinuationRewriter extends Transformer {
|
||||
final HelperNodes helper;
|
||||
|
||||
/// Whether `async` functions should start synchronously.
|
||||
final bool syncAsync;
|
||||
|
||||
final VariableDeclaration asyncJumpVariable = new VariableDeclaration(
|
||||
":await_jump_var",
|
||||
initializer: new IntLiteral(0));
|
||||
final VariableDeclaration asyncContextVariable =
|
||||
new VariableDeclaration(":await_ctx_var");
|
||||
|
||||
RecursiveContinuationRewriter(this.helper, this.syncAsync);
|
||||
RecursiveContinuationRewriter(this.helper);
|
||||
|
||||
Program rewriteProgram(Program node) {
|
||||
return node.accept(this);
|
||||
@@ -57,15 +52,14 @@ class RecursiveContinuationRewriter extends Transformer {
|
||||
switch (node.asyncMarker) {
|
||||
case AsyncMarker.Sync:
|
||||
case AsyncMarker.SyncYielding:
|
||||
node.transformChildren(
|
||||
new RecursiveContinuationRewriter(helper, syncAsync));
|
||||
node.transformChildren(new RecursiveContinuationRewriter(helper));
|
||||
return node;
|
||||
case AsyncMarker.SyncStar:
|
||||
return new SyncStarFunctionRewriter(helper, node, syncAsync).rewrite();
|
||||
return new SyncStarFunctionRewriter(helper, node).rewrite();
|
||||
case AsyncMarker.Async:
|
||||
return new AsyncFunctionRewriter(helper, node, syncAsync).rewrite();
|
||||
return new AsyncFunctionRewriter(helper, node).rewrite();
|
||||
case AsyncMarker.AsyncStar:
|
||||
return new AsyncStarFunctionRewriter(helper, node, syncAsync).rewrite();
|
||||
return new AsyncStarFunctionRewriter(helper, node).rewrite();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,9 +72,8 @@ abstract class ContinuationRewriterBase extends RecursiveContinuationRewriter {
|
||||
int capturedTryDepth = 0; // Deepest yield point within a try-block.
|
||||
int capturedCatchDepth = 0; // Deepest yield point within a catch-block.
|
||||
|
||||
ContinuationRewriterBase(
|
||||
HelperNodes helper, this.enclosingFunction, bool syncAsync)
|
||||
: super(helper, syncAsync);
|
||||
ContinuationRewriterBase(HelperNodes helper, this.enclosingFunction)
|
||||
: super(helper);
|
||||
|
||||
/// Given a container [type], which is an instantiation of the given
|
||||
/// [containerClass] extract its element type.
|
||||
@@ -164,14 +157,13 @@ abstract class ContinuationRewriterBase extends RecursiveContinuationRewriter {
|
||||
class SyncStarFunctionRewriter extends ContinuationRewriterBase {
|
||||
final VariableDeclaration iteratorVariable;
|
||||
|
||||
SyncStarFunctionRewriter(
|
||||
HelperNodes helper, FunctionNode enclosingFunction, syncAsync)
|
||||
SyncStarFunctionRewriter(HelperNodes helper, FunctionNode enclosingFunction)
|
||||
: iteratorVariable = new VariableDeclaration(':iterator')
|
||||
..type = new InterfaceType(helper.syncIteratorClass, [
|
||||
ContinuationRewriterBase.elementTypeFrom(
|
||||
helper.iterableClass, enclosingFunction.returnType)
|
||||
]),
|
||||
super(helper, enclosingFunction, syncAsync);
|
||||
super(helper, enclosingFunction);
|
||||
|
||||
FunctionNode rewrite() {
|
||||
// :sync_op(:iterator) {
|
||||
@@ -264,9 +256,8 @@ abstract class AsyncRewriterBase extends ContinuationRewriterBase {
|
||||
|
||||
ExpressionLifter expressionRewriter;
|
||||
|
||||
AsyncRewriterBase(
|
||||
HelperNodes helper, FunctionNode enclosingFunction, bool syncAsync)
|
||||
: super(helper, enclosingFunction, syncAsync) {}
|
||||
AsyncRewriterBase(helper, enclosingFunction)
|
||||
: super(helper, enclosingFunction) {}
|
||||
|
||||
void setupAsyncContinuations(List<Statement> statements) {
|
||||
expressionRewriter = new ExpressionLifter(this);
|
||||
@@ -763,9 +754,8 @@ abstract class AsyncRewriterBase extends ContinuationRewriterBase {
|
||||
class AsyncStarFunctionRewriter extends AsyncRewriterBase {
|
||||
VariableDeclaration controllerVariable;
|
||||
|
||||
AsyncStarFunctionRewriter(
|
||||
HelperNodes helper, FunctionNode enclosingFunction, bool syncAsync)
|
||||
: super(helper, enclosingFunction, syncAsync);
|
||||
AsyncStarFunctionRewriter(helper, enclosingFunction)
|
||||
: super(helper, enclosingFunction);
|
||||
|
||||
FunctionNode rewrite() {
|
||||
var statements = <Statement>[];
|
||||
@@ -872,9 +862,8 @@ class AsyncFunctionRewriter extends AsyncRewriterBase {
|
||||
VariableDeclaration completerVariable;
|
||||
VariableDeclaration returnVariable;
|
||||
|
||||
AsyncFunctionRewriter(
|
||||
HelperNodes helper, FunctionNode enclosingFunction, bool syncAsync)
|
||||
: super(helper, enclosingFunction, syncAsync);
|
||||
AsyncFunctionRewriter(helper, enclosingFunction)
|
||||
: super(helper, enclosingFunction);
|
||||
|
||||
FunctionNode rewrite() {
|
||||
var statements = <Statement>[];
|
||||
@@ -888,29 +877,16 @@ class AsyncFunctionRewriter extends AsyncRewriterBase {
|
||||
final DartType returnType =
|
||||
new InterfaceType(helper.futureOrClass, <DartType>[valueType]);
|
||||
var completerTypeArguments = <DartType>[valueType];
|
||||
var completerType =
|
||||
new InterfaceType(helper.completerClass, completerTypeArguments);
|
||||
|
||||
if (syncAsync) {
|
||||
final completerType = new InterfaceType(
|
||||
helper.asyncAwaitCompleterClass, completerTypeArguments);
|
||||
// final Completer<T> :completer = new _AsyncAwaitCompleter<T>();
|
||||
completerVariable = new VariableDeclaration(":completer",
|
||||
initializer: new ConstructorInvocation(
|
||||
helper.asyncAwaitCompleterConstructor,
|
||||
new Arguments([], types: completerTypeArguments))
|
||||
..fileOffset = enclosingFunction.body?.fileOffset ?? -1,
|
||||
isFinal: true,
|
||||
type: completerType);
|
||||
} else {
|
||||
final completerType =
|
||||
new InterfaceType(helper.completerClass, completerTypeArguments);
|
||||
// final Completer<T> :completer = new Completer<T>.sync();
|
||||
completerVariable = new VariableDeclaration(":completer",
|
||||
initializer: new StaticInvocation(helper.completerConstructor,
|
||||
new Arguments([], types: completerTypeArguments))
|
||||
..fileOffset = enclosingFunction.body?.fileOffset ?? -1,
|
||||
isFinal: true,
|
||||
type: completerType);
|
||||
}
|
||||
// final Completer<T> :completer = new Completer<T>.sync();
|
||||
completerVariable = new VariableDeclaration(":completer",
|
||||
initializer: new StaticInvocation(helper.completerConstructor,
|
||||
new Arguments([], types: completerTypeArguments))
|
||||
..fileOffset = enclosingFunction.body?.fileOffset ?? -1,
|
||||
isFinal: true,
|
||||
type: completerType);
|
||||
statements.add(completerVariable);
|
||||
|
||||
returnVariable = new VariableDeclaration(":return_value", type: returnType);
|
||||
@@ -918,23 +894,14 @@ class AsyncFunctionRewriter extends AsyncRewriterBase {
|
||||
|
||||
setupAsyncContinuations(statements);
|
||||
|
||||
if (syncAsync) {
|
||||
// :completer.start(:async_op);
|
||||
var startStatement = new ExpressionStatement(new MethodInvocation(
|
||||
new VariableGet(completerVariable),
|
||||
new Name('start'),
|
||||
new Arguments([new VariableGet(nestedClosureVariable)]))
|
||||
..fileOffset = enclosingFunction.fileOffset);
|
||||
statements.add(startStatement);
|
||||
} else {
|
||||
// new Future.microtask(:async_op);
|
||||
var newMicrotaskStatement = new ExpressionStatement(new StaticInvocation(
|
||||
helper.futureMicrotaskConstructor,
|
||||
new Arguments([new VariableGet(nestedClosureVariable)],
|
||||
types: [const DynamicType()]))
|
||||
..fileOffset = enclosingFunction.fileOffset);
|
||||
statements.add(newMicrotaskStatement);
|
||||
}
|
||||
// new Future.microtask(:async_op);
|
||||
var newMicrotaskStatement = new ExpressionStatement(new StaticInvocation(
|
||||
helper.futureMicrotaskConstructor,
|
||||
new Arguments([new VariableGet(nestedClosureVariable)],
|
||||
types: [const DynamicType()]))
|
||||
..fileOffset = enclosingFunction.fileOffset);
|
||||
statements.add(newMicrotaskStatement);
|
||||
|
||||
// return :completer.future;
|
||||
var completerGet = new VariableGet(completerVariable);
|
||||
var returnStatement = new ReturnStatement(new PropertyGet(completerGet,
|
||||
@@ -997,11 +964,9 @@ class HelperNodes {
|
||||
final Procedure asyncThenWrapper;
|
||||
final Procedure awaitHelper;
|
||||
final Class completerClass;
|
||||
final Class asyncAwaitCompleterClass;
|
||||
final Member completerComplete;
|
||||
final Member completerCompleteError;
|
||||
final Member completerConstructor;
|
||||
final Member asyncAwaitCompleterConstructor;
|
||||
final Member completerFuture;
|
||||
final Library coreLibrary;
|
||||
final CoreTypes coreTypes;
|
||||
@@ -1036,11 +1001,9 @@ class HelperNodes {
|
||||
this.asyncThenWrapper,
|
||||
this.awaitHelper,
|
||||
this.completerClass,
|
||||
this.asyncAwaitCompleterClass,
|
||||
this.completerComplete,
|
||||
this.completerCompleteError,
|
||||
this.completerConstructor,
|
||||
this.asyncAwaitCompleterConstructor,
|
||||
this.completerFuture,
|
||||
this.coreLibrary,
|
||||
this.coreTypes,
|
||||
@@ -1076,11 +1039,9 @@ class HelperNodes {
|
||||
coreTypes.asyncThenWrapperHelperProcedure,
|
||||
coreTypes.awaitHelperProcedure,
|
||||
coreTypes.completerClass,
|
||||
coreTypes.asyncAwaitCompleterClass,
|
||||
coreTypes.completerComplete,
|
||||
coreTypes.completerCompleteError,
|
||||
coreTypes.completerSyncConstructor,
|
||||
coreTypes.asyncAwaitCompleterConstructor,
|
||||
coreTypes.completerFuture,
|
||||
coreTypes.coreLibrary,
|
||||
coreTypes,
|
||||
|
||||
@@ -48,9 +48,7 @@ abstract class Compiler {
|
||||
CompilerOptions options;
|
||||
|
||||
Compiler(this.fileSystem, Uri platformKernel,
|
||||
{this.strongMode: false,
|
||||
bool suppressWarnings: false,
|
||||
bool syncAsync: false}) {
|
||||
{this.strongMode: false, bool suppressWarnings: false}) {
|
||||
Uri packagesUri = (Platform.packageConfig != null)
|
||||
? Uri.parse(Platform.packageConfig)
|
||||
: null;
|
||||
@@ -61,14 +59,12 @@ abstract class Compiler {
|
||||
print("DFE: Platform.resolvedExecutable: ${Platform.resolvedExecutable}");
|
||||
print("DFE: platformKernel: ${platformKernel}");
|
||||
print("DFE: strongMode: ${strongMode}");
|
||||
print("DFE: syncAsync: ${syncAsync}");
|
||||
}
|
||||
|
||||
options = new CompilerOptions()
|
||||
..strongMode = strongMode
|
||||
..fileSystem = fileSystem
|
||||
..target = new VmTarget(
|
||||
new TargetFlags(strongMode: strongMode, syncAsync: syncAsync))
|
||||
..target = new VmTarget(new TargetFlags(strongMode: strongMode))
|
||||
..packagesFileUri = packagesUri
|
||||
..sdkSummary = platformKernel
|
||||
..verbose = verbose
|
||||
@@ -103,11 +99,9 @@ class IncrementalCompiler extends Compiler {
|
||||
IncrementalKernelGenerator generator;
|
||||
|
||||
IncrementalCompiler(FileSystem fileSystem, Uri platformKernel,
|
||||
{bool strongMode: false, bool suppressWarnings: false, syncAsync: false})
|
||||
{bool strongMode: false, bool suppressWarnings: false})
|
||||
: super(fileSystem, platformKernel,
|
||||
strongMode: strongMode,
|
||||
suppressWarnings: suppressWarnings,
|
||||
syncAsync: syncAsync);
|
||||
strongMode: strongMode, suppressWarnings: suppressWarnings);
|
||||
|
||||
@override
|
||||
Future<Program> compileInternal(Uri script) async {
|
||||
@@ -128,12 +122,9 @@ class SingleShotCompiler extends Compiler {
|
||||
SingleShotCompiler(FileSystem fileSystem, Uri platformKernel,
|
||||
{this.requireMain: false,
|
||||
bool strongMode: false,
|
||||
bool suppressWarnings: false,
|
||||
bool syncAsync: false})
|
||||
bool suppressWarnings: false})
|
||||
: super(fileSystem, platformKernel,
|
||||
strongMode: strongMode,
|
||||
suppressWarnings: suppressWarnings,
|
||||
syncAsync: syncAsync);
|
||||
strongMode: strongMode, suppressWarnings: suppressWarnings);
|
||||
|
||||
@override
|
||||
Future<Program> compileInternal(Uri script) async {
|
||||
@@ -147,9 +138,7 @@ final Map<int, Compiler> isolateCompilers = new Map<int, Compiler>();
|
||||
|
||||
Future<Compiler> lookupOrBuildNewIncrementalCompiler(
|
||||
int isolateId, List sourceFiles, Uri platformKernel,
|
||||
{bool strongMode: false,
|
||||
bool suppressWarnings: false,
|
||||
bool syncAsync: false}) async {
|
||||
{bool strongMode: false, bool suppressWarnings: false}) async {
|
||||
IncrementalCompiler compiler;
|
||||
if (isolateCompilers.containsKey(isolateId)) {
|
||||
compiler = isolateCompilers[isolateId];
|
||||
@@ -173,9 +162,7 @@ Future<Compiler> lookupOrBuildNewIncrementalCompiler(
|
||||
// isolate needs to receive a message indicating that particular
|
||||
// isolate was shut down. Message should be handled here in this script.
|
||||
compiler = new IncrementalCompiler(fileSystem, platformKernel,
|
||||
strongMode: strongMode,
|
||||
suppressWarnings: suppressWarnings,
|
||||
syncAsync: syncAsync);
|
||||
strongMode: strongMode, suppressWarnings: suppressWarnings);
|
||||
isolateCompilers[isolateId] = compiler;
|
||||
}
|
||||
return compiler;
|
||||
@@ -202,7 +189,6 @@ Future _processLoadRequest(request) async {
|
||||
final int isolateId = request[6];
|
||||
final List sourceFiles = request[7];
|
||||
final bool suppressWarnings = request[8];
|
||||
final bool syncAsync = request[9];
|
||||
|
||||
Compiler compiler;
|
||||
// TODO(aam): There should be no need to have an option to choose
|
||||
@@ -212,7 +198,7 @@ Future _processLoadRequest(request) async {
|
||||
if (incremental) {
|
||||
compiler = await lookupOrBuildNewIncrementalCompiler(
|
||||
isolateId, sourceFiles, platformKernel,
|
||||
suppressWarnings: suppressWarnings, syncAsync: syncAsync);
|
||||
suppressWarnings: suppressWarnings);
|
||||
} else {
|
||||
final FileSystem fileSystem = sourceFiles == null
|
||||
? StandardFileSystem.instance
|
||||
@@ -220,8 +206,7 @@ Future _processLoadRequest(request) async {
|
||||
compiler = new SingleShotCompiler(fileSystem, platformKernel,
|
||||
requireMain: sourceFiles == null,
|
||||
strongMode: strong,
|
||||
suppressWarnings: suppressWarnings,
|
||||
syncAsync: syncAsync);
|
||||
suppressWarnings: suppressWarnings);
|
||||
}
|
||||
|
||||
CompilationResult result;
|
||||
@@ -308,7 +293,6 @@ train(String scriptUri, String platformKernel) {
|
||||
1 /* isolateId chosen randomly */,
|
||||
null /* source files */,
|
||||
false /* suppress warnings */,
|
||||
false /* synchronous async */,
|
||||
];
|
||||
_processLoadRequest(request);
|
||||
}
|
||||
|
||||
@@ -17,43 +17,6 @@ import "dart:_internal" show VMLibraryHooks, patch;
|
||||
// Equivalent of calling FATAL from C++ code.
|
||||
_fatal(msg) native "DartAsync_fatal";
|
||||
|
||||
class _AsyncAwaitCompleter<T> implements Completer<T> {
|
||||
final _completer = new Completer<T>.sync();
|
||||
bool isSync;
|
||||
|
||||
_AsyncAwaitCompleter() : isSync = false;
|
||||
|
||||
void complete([FutureOr<T> value]) {
|
||||
if (isSync) {
|
||||
_completer.complete(value);
|
||||
} else if (value is Future<T>) {
|
||||
value.then(_completer.complete, onError: _completer.completeError);
|
||||
} else {
|
||||
scheduleMicrotask(() {
|
||||
_completer.complete(value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void completeError(e, [st]) {
|
||||
if (isSync) {
|
||||
_completer.completeError(e, st);
|
||||
} else {
|
||||
scheduleMicrotask(() {
|
||||
_completer.completeError(e, st);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void start(f) {
|
||||
f();
|
||||
isSync = true;
|
||||
}
|
||||
|
||||
Future<T> get future => _completer.future;
|
||||
bool get isCompleted => _completer.isCompleted;
|
||||
}
|
||||
|
||||
// We need to pass the value as first argument and leave the second and third
|
||||
// arguments empty (used for error handling).
|
||||
// See vm/ast_transformer.cc for usage.
|
||||
|
||||
@@ -157,7 +157,6 @@
|
||||
C(stress_async_stacks, false, false, bool, false, \
|
||||
"Stress test async stack traces") \
|
||||
P(strong, bool, false, "Enable strong mode.") \
|
||||
P(sync_async, bool, false, "Start `async` functions synchronously.") \
|
||||
R(support_ast_printer, false, bool, true, "Support the AST printer.") \
|
||||
R(support_compiler_stats, false, bool, true, "Support compiler stats.") \
|
||||
R(support_disassembler, false, bool, true, "Support the disassembler.") \
|
||||
|
||||
@@ -370,10 +370,6 @@ class KernelCompilationRequest : public ValueObject {
|
||||
suppress_warnings.type = Dart_CObject_kBool;
|
||||
suppress_warnings.value.as_bool = FLAG_suppress_fe_warnings;
|
||||
|
||||
Dart_CObject dart_sync_async;
|
||||
dart_sync_async.type = Dart_CObject_kBool;
|
||||
dart_sync_async.value.as_bool = FLAG_sync_async;
|
||||
|
||||
Dart_CObject* message_arr[] = {&tag,
|
||||
&send_port,
|
||||
&uri,
|
||||
@@ -382,8 +378,7 @@ class KernelCompilationRequest : public ValueObject {
|
||||
&dart_strong,
|
||||
&isolate_id,
|
||||
&files,
|
||||
&suppress_warnings,
|
||||
&dart_sync_async};
|
||||
&suppress_warnings};
|
||||
message.value.as_array.values = message_arr;
|
||||
message.value.as_array.length = ARRAY_SIZE(message_arr);
|
||||
// Send the message.
|
||||
|
||||
+24
-50
@@ -7574,42 +7574,30 @@ SequenceNode* Parser::CloseAsyncFunction(const Function& closure,
|
||||
Symbols::AsyncStackTraceVar(), false);
|
||||
ASSERT((existing_var != NULL) && existing_var->is_captured());
|
||||
|
||||
// Create a completer that executes a closure with the current body and
|
||||
// return the corresponding future.
|
||||
// Create and return a new future that executes a closure with the current
|
||||
// body.
|
||||
|
||||
// No need to capture parameters or other variables, since they have already
|
||||
// been captured in the corresponding scope as the body has been parsed within
|
||||
// a nested block (contained in the async function's block).
|
||||
|
||||
const Library& async_lib = Library::Handle(Z, Library::AsyncLibrary());
|
||||
const Class& future = Class::ZoneHandle(Z, I->object_store()->future_class());
|
||||
ASSERT(!future.IsNull());
|
||||
const Function& constructor = Function::ZoneHandle(
|
||||
Z, future.LookupFunction(Symbols::FutureMicrotask()));
|
||||
ASSERT(!constructor.IsNull());
|
||||
const Class& completer =
|
||||
Class::ZoneHandle(Z, I->object_store()->completer_class());
|
||||
ASSERT(!completer.IsNull());
|
||||
const Function& completer_constructor = Function::ZoneHandle(
|
||||
Z, completer.LookupFunction(Symbols::CompleterSyncConstructor()));
|
||||
ASSERT(!completer_constructor.IsNull());
|
||||
|
||||
LocalVariable* async_completer =
|
||||
current_block_->scope->LookupVariable(Symbols::AsyncCompleter(), false);
|
||||
|
||||
const TokenPosition token_pos = ST(closure_body->token_pos());
|
||||
|
||||
Function& completer_constructor = Function::ZoneHandle(Z);
|
||||
if (FLAG_sync_async) {
|
||||
const Class& completer_class = Class::Handle(
|
||||
Z, async_lib.LookupClassAllowPrivate(Symbols::_AsyncAwaitCompleter()));
|
||||
ASSERT(!completer_class.IsNull());
|
||||
completer_constructor = completer_class.LookupConstructorAllowPrivate(
|
||||
Symbols::_AsyncAwaitCompleterConstructor());
|
||||
ASSERT(!completer_constructor.IsNull());
|
||||
|
||||
// Add to AST:
|
||||
// :async_completer = new _AsyncAwaitCompleter();
|
||||
} else {
|
||||
const Class& completer =
|
||||
Class::Handle(Z, I->object_store()->completer_class());
|
||||
ASSERT(!completer.IsNull());
|
||||
completer_constructor =
|
||||
completer.LookupFunction(Symbols::CompleterSyncConstructor());
|
||||
ASSERT(!completer_constructor.IsNull());
|
||||
|
||||
// Add to AST:
|
||||
// :async_completer = new Completer.sync();
|
||||
}
|
||||
// Add to AST:
|
||||
// :async_completer = new Completer.sync();
|
||||
ArgumentListNode* empty_args = new (Z) ArgumentListNode(token_pos);
|
||||
ConstructorCallNode* completer_constructor_node =
|
||||
new (Z) ConstructorCallNode(token_pos, TypeArguments::ZoneHandle(Z),
|
||||
@@ -7636,6 +7624,8 @@ SequenceNode* Parser::CloseAsyncFunction(const Function& closure,
|
||||
new (Z) StoreLocalNode(token_pos, async_op_var, cn);
|
||||
current_block_->statements->Add(store_async_op);
|
||||
|
||||
const Library& async_lib = Library::Handle(Library::AsyncLibrary());
|
||||
|
||||
if (FLAG_causal_async_stacks) {
|
||||
// Add to AST:
|
||||
// :async_stack_trace = _asyncStackTraceHelper();
|
||||
@@ -7699,29 +7689,13 @@ SequenceNode* Parser::CloseAsyncFunction(const Function& closure,
|
||||
|
||||
current_block_->statements->Add(store_async_catch_error_callback);
|
||||
|
||||
if (FLAG_sync_async) {
|
||||
// Add to AST:
|
||||
// :async_completer.start(:async_op);
|
||||
ArgumentListNode* arguments = new (Z) ArgumentListNode(token_pos);
|
||||
arguments->Add(new (Z) LoadLocalNode(token_pos, async_op_var));
|
||||
InstanceCallNode* start_call = new (Z) InstanceCallNode(
|
||||
token_pos, new (Z) LoadLocalNode(token_pos, async_completer),
|
||||
Symbols::_AsyncAwaitStart(), arguments);
|
||||
current_block_->statements->Add(start_call);
|
||||
} else {
|
||||
// Add to AST:
|
||||
// new Future.microtask(:async_op);
|
||||
const Class& future = Class::Handle(Z, I->object_store()->future_class());
|
||||
ASSERT(!future.IsNull());
|
||||
const Function& constructor = Function::ZoneHandle(
|
||||
Z, future.LookupFunction(Symbols::FutureMicrotask()));
|
||||
ASSERT(!constructor.IsNull());
|
||||
ArgumentListNode* arguments = new (Z) ArgumentListNode(token_pos);
|
||||
arguments->Add(new (Z) LoadLocalNode(token_pos, async_op_var));
|
||||
ConstructorCallNode* future_node = new (Z) ConstructorCallNode(
|
||||
token_pos, TypeArguments::ZoneHandle(Z), constructor, arguments);
|
||||
current_block_->statements->Add(future_node);
|
||||
}
|
||||
// Add to AST:
|
||||
// new Future.microtask(:async_op);
|
||||
ArgumentListNode* arguments = new (Z) ArgumentListNode(token_pos);
|
||||
arguments->Add(new (Z) LoadLocalNode(token_pos, async_op_var));
|
||||
ConstructorCallNode* future_node = new (Z) ConstructorCallNode(
|
||||
token_pos, TypeArguments::ZoneHandle(Z), constructor, arguments);
|
||||
current_block_->statements->Add(future_node);
|
||||
|
||||
// Add to AST:
|
||||
// return :async_completer.future;
|
||||
|
||||
@@ -145,9 +145,6 @@ class ObjectPointerVisitor;
|
||||
V(CompleterComplete, "complete") \
|
||||
V(CompleterCompleteError, "completeError") \
|
||||
V(CompleterSyncConstructor, "Completer.sync") \
|
||||
V(_AsyncAwaitCompleter, "_AsyncAwaitCompleter") \
|
||||
V(_AsyncAwaitCompleterConstructor, "_AsyncAwaitCompleter.") \
|
||||
V(_AsyncAwaitStart, "start") \
|
||||
V(CompleterFuture, "future") \
|
||||
V(StreamIterator, "StreamIterator") \
|
||||
V(StreamIteratorConstructor, "StreamIterator.") \
|
||||
|
||||
@@ -132,53 +132,6 @@ class Timer {
|
||||
}
|
||||
}
|
||||
|
||||
class _AsyncAwaitCompleter<T> implements Completer<T> {
|
||||
final _completer = new Completer<T>.sync();
|
||||
bool isSync;
|
||||
|
||||
_AsyncAwaitCompleter() : isSync = false;
|
||||
|
||||
void complete([FutureOr<T> value]) {
|
||||
if (isSync) {
|
||||
_completer.complete(value);
|
||||
} else if (value is Future<T>) {
|
||||
value.then(_completer.complete, onError: _completer.completeError);
|
||||
} else {
|
||||
scheduleMicrotask(() {
|
||||
_completer.complete(value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void completeError(e, [st]) {
|
||||
if (isSync) {
|
||||
_completer.completeError(e, st);
|
||||
} else {
|
||||
scheduleMicrotask(() {
|
||||
_completer.completeError(e, st);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<T> get future => _completer.future;
|
||||
bool get isCompleted => _completer.isCompleted;
|
||||
}
|
||||
|
||||
/// Initiates the computation of an `async` function and starts the body
|
||||
/// synchronously.
|
||||
///
|
||||
/// Used as part of the runtime support for the async/await transformation.
|
||||
///
|
||||
/// This function sets up the first call into the transformed [bodyFunction].
|
||||
/// Independently, it takes the [completer] and returns the future of the
|
||||
/// completer for convenience of the transformed code.
|
||||
dynamic _asyncStartSync(
|
||||
_WrappedAsyncBody bodyFunction, _AsyncAwaitCompleter completer) {
|
||||
bodyFunction(async_error_codes.SUCCESS, null);
|
||||
completer.isSync = true;
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
/// Initiates the computation of an `async` function.
|
||||
///
|
||||
/// Used as part of the runtime support for the async/await transformation.
|
||||
|
||||
@@ -19,8 +19,8 @@ main() {
|
||||
return expect42(f());
|
||||
});
|
||||
|
||||
test("async starts synchronously", () {
|
||||
// Calling an "async" function starts immediately.
|
||||
test("async waits", () {
|
||||
// Calling an "async" function won't do anything immediately.
|
||||
var result = [];
|
||||
f() async {
|
||||
result.add(1);
|
||||
@@ -31,7 +31,7 @@ main() {
|
||||
var future = f();
|
||||
result.add(0);
|
||||
return future.whenComplete(() {
|
||||
expect(result, equals([1, 0]));
|
||||
expect(result, equals([0, 1]));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -184,6 +184,7 @@ main() {
|
||||
return new Future.error("err"); // Not awaited.
|
||||
}
|
||||
|
||||
;
|
||||
return throwsErr(f());
|
||||
});
|
||||
|
||||
|
||||
@@ -14,8 +14,6 @@ foo() {
|
||||
|
||||
bar() async {
|
||||
result += "bar";
|
||||
await null;
|
||||
result += "bar2";
|
||||
}
|
||||
|
||||
main() {
|
||||
@@ -23,13 +21,13 @@ main() {
|
||||
() async {
|
||||
var f = new Future(foo);
|
||||
var b = bar();
|
||||
Expect.equals("bar", result);
|
||||
Expect.equals("", result);
|
||||
scheduleMicrotask(() => result += "micro");
|
||||
await b;
|
||||
await f;
|
||||
|
||||
// Validates that bar is scheduled as a microtask, before foo.
|
||||
Expect.equals("barbar2microfoo", result);
|
||||
Expect.equals("barmicrofoo", result);
|
||||
asyncEnd();
|
||||
}();
|
||||
}
|
||||
|
||||
@@ -1,264 +0,0 @@
|
||||
// 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.
|
||||
|
||||
import 'dart:async';
|
||||
import 'package:expect/expect.dart';
|
||||
import 'package:async_helper/async_helper.dart';
|
||||
|
||||
class AsyncTracker {
|
||||
int runningAsyncs = 0;
|
||||
List expectedEvents;
|
||||
final List actualEvents = [];
|
||||
|
||||
AsyncTracker() {
|
||||
asyncStart();
|
||||
}
|
||||
|
||||
void start(String event) {
|
||||
actualEvents.add("start $event");
|
||||
runningAsyncs++;
|
||||
}
|
||||
|
||||
void stop(String event) {
|
||||
actualEvents.add("stop $event");
|
||||
if (--runningAsyncs == 0) {
|
||||
Expect.listEquals(expectedEvents, actualEvents);
|
||||
asyncEnd();
|
||||
}
|
||||
}
|
||||
|
||||
void add(e) {
|
||||
actualEvents.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
void test1() {
|
||||
var tracker = new AsyncTracker();
|
||||
|
||||
Future foo() async {
|
||||
tracker.add("error-foo");
|
||||
throw "foo";
|
||||
}
|
||||
|
||||
tracker.start("micro1");
|
||||
scheduleMicrotask(() {
|
||||
tracker.start("micro2");
|
||||
scheduleMicrotask(() {
|
||||
tracker.stop("micro2");
|
||||
});
|
||||
tracker.stop("micro1");
|
||||
});
|
||||
|
||||
tracker.start("foo");
|
||||
foo().catchError((e) {
|
||||
tracker.stop("foo");
|
||||
});
|
||||
tracker.start("micro3");
|
||||
scheduleMicrotask(() {
|
||||
tracker.stop("micro3");
|
||||
});
|
||||
|
||||
tracker.expectedEvents = [
|
||||
"start micro1",
|
||||
"start foo",
|
||||
"error-foo",
|
||||
"start micro3",
|
||||
"start micro2",
|
||||
"stop micro1",
|
||||
"stop foo",
|
||||
"stop micro3",
|
||||
"stop micro2",
|
||||
];
|
||||
}
|
||||
|
||||
void test2() {
|
||||
var tracker = new AsyncTracker();
|
||||
|
||||
Future bar() async {
|
||||
tracker.add("await null");
|
||||
await null;
|
||||
tracker.add("error-bar");
|
||||
throw "bar";
|
||||
}
|
||||
|
||||
tracker.start("micro1");
|
||||
scheduleMicrotask(() {
|
||||
tracker.start("micro2");
|
||||
scheduleMicrotask(() {
|
||||
tracker.start("micro3");
|
||||
scheduleMicrotask(() {
|
||||
tracker.stop("micro3");
|
||||
});
|
||||
tracker.stop("micro2");
|
||||
});
|
||||
tracker.stop("micro1");
|
||||
});
|
||||
|
||||
tracker.start("bar");
|
||||
bar().catchError((e) {
|
||||
tracker.stop("bar");
|
||||
});
|
||||
tracker.start("micro4");
|
||||
scheduleMicrotask(() {
|
||||
tracker.start("micro5");
|
||||
scheduleMicrotask(() {
|
||||
tracker.stop("micro5");
|
||||
});
|
||||
tracker.stop("micro4");
|
||||
});
|
||||
|
||||
tracker.expectedEvents = [
|
||||
"start micro1",
|
||||
"start bar",
|
||||
"await null",
|
||||
"start micro4",
|
||||
"start micro2",
|
||||
"stop micro1",
|
||||
"error-bar",
|
||||
"stop bar",
|
||||
"start micro5",
|
||||
"stop micro4",
|
||||
"start micro3",
|
||||
"stop micro2",
|
||||
"stop micro5",
|
||||
"stop micro3",
|
||||
];
|
||||
}
|
||||
|
||||
void test3() {
|
||||
var tracker = new AsyncTracker();
|
||||
|
||||
Future gee() async {
|
||||
tracker.add("error-gee");
|
||||
return new Future.error("gee");
|
||||
}
|
||||
|
||||
tracker.start("micro1");
|
||||
scheduleMicrotask(() {
|
||||
tracker.start("micro2");
|
||||
scheduleMicrotask(() {
|
||||
tracker.stop("micro2");
|
||||
});
|
||||
tracker.stop("micro1");
|
||||
});
|
||||
|
||||
tracker.start("gee");
|
||||
gee().catchError((e) {
|
||||
tracker.stop("gee");
|
||||
});
|
||||
tracker.start("micro3");
|
||||
scheduleMicrotask(() {
|
||||
tracker.stop("micro3");
|
||||
});
|
||||
|
||||
tracker.expectedEvents = [
|
||||
"start micro1",
|
||||
"start gee",
|
||||
"error-gee",
|
||||
"start micro3",
|
||||
"start micro2",
|
||||
"stop micro1",
|
||||
"stop gee",
|
||||
"stop micro3",
|
||||
"stop micro2",
|
||||
];
|
||||
}
|
||||
|
||||
void test4() {
|
||||
var tracker = new AsyncTracker();
|
||||
|
||||
Future toto() async {
|
||||
tracker.add("await null");
|
||||
await null;
|
||||
tracker.add("error-toto");
|
||||
return new Future.error("toto");
|
||||
}
|
||||
|
||||
tracker.start("micro1");
|
||||
scheduleMicrotask(() {
|
||||
tracker.start("micro2");
|
||||
scheduleMicrotask(() {
|
||||
tracker.start("micro3");
|
||||
scheduleMicrotask(() {
|
||||
tracker.stop("micro3");
|
||||
});
|
||||
tracker.stop("micro2");
|
||||
});
|
||||
tracker.stop("micro1");
|
||||
});
|
||||
|
||||
tracker.start("toto");
|
||||
toto().catchError((e) {
|
||||
tracker.stop("toto");
|
||||
});
|
||||
tracker.start("micro4");
|
||||
scheduleMicrotask(() {
|
||||
tracker.start("micro5");
|
||||
scheduleMicrotask(() {
|
||||
tracker.stop("micro5");
|
||||
});
|
||||
tracker.stop("micro4");
|
||||
});
|
||||
|
||||
tracker.expectedEvents = [
|
||||
"start micro1",
|
||||
"start toto",
|
||||
"await null",
|
||||
"start micro4",
|
||||
"start micro2",
|
||||
"stop micro1",
|
||||
"error-toto",
|
||||
"start micro5",
|
||||
"stop micro4",
|
||||
"start micro3",
|
||||
"stop micro2",
|
||||
"stop toto",
|
||||
"stop micro5",
|
||||
"stop micro3",
|
||||
];
|
||||
}
|
||||
|
||||
void test5() {
|
||||
var tracker = new AsyncTracker();
|
||||
|
||||
Future foo() async {
|
||||
tracker.add("throw");
|
||||
throw "foo";
|
||||
}
|
||||
|
||||
bar() async {
|
||||
tracker.start('micro');
|
||||
scheduleMicrotask(() {
|
||||
tracker.stop('micro');
|
||||
});
|
||||
try {
|
||||
tracker.start('foo');
|
||||
await foo();
|
||||
} catch (e) {
|
||||
tracker.stop('foo');
|
||||
}
|
||||
tracker.stop("bar");
|
||||
}
|
||||
|
||||
tracker.start('bar');
|
||||
|
||||
tracker.expectedEvents = [
|
||||
"start bar",
|
||||
"start micro",
|
||||
"start foo",
|
||||
"throw",
|
||||
"stop micro",
|
||||
"stop foo",
|
||||
"stop bar",
|
||||
];
|
||||
}
|
||||
|
||||
main() {
|
||||
asyncStart();
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
test4();
|
||||
asyncEnd();
|
||||
}
|
||||
@@ -40,9 +40,9 @@ foo1(Tracer tracer) async* {
|
||||
yield 3;
|
||||
tracer.trace("f");
|
||||
} finally {
|
||||
tracer.trace("g");
|
||||
tracer.trace("f");
|
||||
}
|
||||
tracer.trace("h");
|
||||
tracer.trace("g");
|
||||
}
|
||||
|
||||
foo2(Tracer tracer) async* {
|
||||
@@ -116,10 +116,10 @@ runTest(test, expectedTrace, expectedError, shouldCancel) {
|
||||
test() async {
|
||||
// TODO(sigurdm): These tests are too dependent on scheduling, and buffering
|
||||
// behavior.
|
||||
await runTest(foo1, "abcYdgC", null, true);
|
||||
await runTest(foo1, "abcdYefC", null, true);
|
||||
await runTest(foo2, "abcX", "Error", false);
|
||||
await runTest(foo3, "abcYX", "Error", false);
|
||||
await runTest(foo4, "abcYdYefX", "Error2", false);
|
||||
await runTest(foo4, "abcdYeYfX", "Error2", false);
|
||||
}
|
||||
|
||||
void main() {
|
||||
|
||||
@@ -5,23 +5,16 @@
|
||||
// VMOptions=--optimization-counter-threshold=5
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
import 'package:async_helper/async_helper.dart';
|
||||
|
||||
var X = 0;
|
||||
|
||||
foo() async {
|
||||
Expect.equals(X, 0);
|
||||
await 5;
|
||||
Expect.equals(X, 10);
|
||||
return await 499;
|
||||
Expect.equals(X, 10); // foo runs after main returns.
|
||||
return await 5;
|
||||
}
|
||||
|
||||
main() {
|
||||
asyncStart();
|
||||
var f = foo();
|
||||
f.then((res) {
|
||||
Expect.equals(499, res);
|
||||
asyncEnd();
|
||||
});
|
||||
f.then((res) => print("f completed with $res"));
|
||||
X = 10;
|
||||
}
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
// 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.
|
||||
|
||||
// Test that an async function does start immediately.
|
||||
// Test that an async function does not start immediately.
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
import "package:async_helper/async_helper.dart";
|
||||
@@ -18,5 +18,5 @@ foo() async {
|
||||
void main() {
|
||||
asyncStart();
|
||||
foo().then((_) => Expect.equals(2, x)).whenComplete(asyncEnd);
|
||||
Expect.equals(1, x);
|
||||
Expect.equals(0, x);
|
||||
}
|
||||
@@ -13,10 +13,6 @@ var delayedValue = new Completer();
|
||||
var delayedError = new Completer();
|
||||
|
||||
foo() async {
|
||||
// Because of this `await null` the function returns and lets the caller
|
||||
// install handlers. When the function finishes, it can then synchronously
|
||||
// propagate the values.
|
||||
await null;
|
||||
new Future.microtask(() => 'in microtask')
|
||||
.then(events.add)
|
||||
.then(delayedValue.complete);
|
||||
@@ -24,10 +20,6 @@ foo() async {
|
||||
}
|
||||
|
||||
bar() async {
|
||||
// Because of this `await null` the function returns and lets the caller
|
||||
// install handlers. When the function finishes, it can then synchronously
|
||||
// propagate the values.
|
||||
await null;
|
||||
new Future.microtask(() => throw 'in microtask error')
|
||||
.catchError(events.add)
|
||||
.then(delayedError.complete);
|
||||
|
||||
@@ -89,7 +89,6 @@ html/fileapi_directory_test: Fail # TODO(dart2js-team): Please triage this failu
|
||||
html/fileapi_entry_test: Pass, Fail # TODO(dart2js-team): Please triage this failure.
|
||||
html/fileapi_file_test: Fail # TODO(dart2js-team): Please triage this failure.
|
||||
html/media_stream_test: RuntimeError # Please triage.
|
||||
html/notification_permission_test: Timeout # Issue 32002
|
||||
html/speechrecognition_test: RuntimeError # Please triage.
|
||||
isolate/function_send_test: Skip # Crashes Chrome 62: https://bugs.chromium.org/p/chromium/issues/detail?id=775506
|
||||
isolate/kill_self_synchronously_test: RuntimeError
|
||||
|
||||
@@ -104,7 +104,6 @@ html/js_util_test: RuntimeError # Issue 29922
|
||||
html/media_stream_test: RuntimeError # Issue 29922
|
||||
html/mediasource_test: RuntimeError # Issue 29922
|
||||
html/no_linked_scripts_htmltest: Skip # Issue 29919
|
||||
html/notification_permission_test: Timeout # Issue 32002
|
||||
html/scripts_htmltest: Skip # Issue 29919
|
||||
html/transferables_test: CompileTimeError # Issue 30975
|
||||
html/transition_event_test: Pass, RuntimeError, Timeout # Issue 29922, this test seems flaky
|
||||
|
||||
@@ -40,8 +40,7 @@ String dart2jsHtml(String title, String scriptPath) {
|
||||
/// The [testName] is the short name of the test without any subdirectory path
|
||||
/// or extension, like "math_test". The [testJSDir] is the relative path to the
|
||||
/// build directory where the dartdevc-generated JS file is stored.
|
||||
String dartdevcHtml(String testName, String testJSDir, String buildDir,
|
||||
{bool syncAsync}) {
|
||||
String dartdevcHtml(String testName, String testJSDir, String buildDir) {
|
||||
var packagePaths = testPackages
|
||||
.map((package) => ' "$package": "/root_dart/$buildDir/gen/utils/'
|
||||
'dartdevc/pkg/$package",')
|
||||
@@ -87,7 +86,7 @@ window.ddcSettings = {
|
||||
requirejs(["$testName", "dart_sdk", "async_helper"],
|
||||
function($testName, sdk, async_helper) {
|
||||
sdk.dart.ignoreWhitelistedErrors(false);
|
||||
if ($syncAsync) sdk.dart.setStartAsyncSynchronously();
|
||||
|
||||
// TODO(rnystrom): This uses DDC's forked version of async_helper. Unfork
|
||||
// these packages when possible.
|
||||
async_helper.async_helper.asyncTestInitialize(function() {});
|
||||
|
||||
@@ -814,12 +814,6 @@ class StandardTestSuite extends TestSuite {
|
||||
var commonArguments =
|
||||
commonArgumentsFromFile(info.filePath, info.optionsFromFile);
|
||||
|
||||
// TODO(floitsch): Hack. When running the 2.0 tests always start
|
||||
// async functions synchronously.
|
||||
if (suiteName.endsWith("_2")) {
|
||||
commonArguments.insert(0, "--sync-async");
|
||||
}
|
||||
|
||||
var vmOptionsList = getVmOptions(info.optionsFromFile);
|
||||
assert(!vmOptionsList.isEmpty);
|
||||
|
||||
@@ -1032,37 +1026,13 @@ class StandardTestSuite extends TestSuite {
|
||||
} else {
|
||||
var jsDir =
|
||||
new Path(compilationTempDir).relativeTo(Repository.dir).toString();
|
||||
// Always run with synchronous starts of `async` functions.
|
||||
// If we want to make this dependent on other parameters or flags,
|
||||
// this flag could be become conditional.
|
||||
content = dartdevcHtml(nameNoExt, jsDir, buildDir, syncAsync: true);
|
||||
content = dartdevcHtml(nameNoExt, jsDir, buildDir);
|
||||
}
|
||||
}
|
||||
|
||||
var htmlPath = '$tempDir/test.html';
|
||||
new File(htmlPath).writeAsStringSync(content);
|
||||
|
||||
// TODO(floitsch): Hack. When running the 2.0 tests always start
|
||||
// async functions synchronously.
|
||||
if (suiteName.endsWith("_2") &&
|
||||
configuration.compiler == Compiler.dart2js) {
|
||||
if (optionsFromFile == null) {
|
||||
optionsFromFile = const <String, dynamic>{
|
||||
'sharedOptions': const ['--sync-async']
|
||||
};
|
||||
} else {
|
||||
optionsFromFile = new Map<String, dynamic>.from(optionsFromFile);
|
||||
var sharedOptions = optionsFromFile['sharedOptions'];
|
||||
if (sharedOptions == null) {
|
||||
sharedOptions = const <String>['--sync-async'];
|
||||
} else {
|
||||
sharedOptions = sharedOptions.toList();
|
||||
sharedOptions.insert(0, "--sync-async");
|
||||
}
|
||||
optionsFromFile['sharedOptions'] = sharedOptions;
|
||||
}
|
||||
}
|
||||
|
||||
// Construct the command(s) that compile all the inputs needed by the
|
||||
// browser test. For running Dart in DRT, this will be noop commands.
|
||||
var commands = <Command>[];
|
||||
|
||||
Reference in New Issue
Block a user