mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 18:31:32 +00:00
[dart2js] Construct _SyncStarIterator outside of transformed code
In the old scheme, sync* generators would have an entry and a body. The entry contained typed checks and the body had injected code to call a 'factory' helper method to construct the _SyncStarIterable. It was necessary to pass the element type to the body to be passed to the factory. int foo(T a, T b) sync* {yield f(a); yield f(b);} is compiled to something like foo(a, b) { T._as(a); T._as(b); return foo$body(a, b, type$.int); } foo$body(a, b, R) { return _syncStarFactory(function(){BODY}, R); } When type checks were disabled (`-O3`), it was often possible to generate a single function by merging these as there were no checks. The new scheme keeps the entry and body separate, and constructs the _SyncStarIterable in the entry: foo(a, b) { T._as(a); T._as(b); return _syncStarFactory(foo$body(a, b), type$.int); } foo$body(a, b) { return function(){BODY}; } This keeps the typed Dart 'level' distinct from the untyped JavaScript level. The new scheme is a bit more verbose but has the advantage that the call to `_syncStarFactory` can be inlined and optimized. Change-Id: I13802d9c9eefd9323841670d059b75a81569d6cb Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/296140 Reviewed-by: Mayank Patke <fishythefish@google.com> Commit-Queue: Stephen Adams <sra@google.com>
This commit is contained in:
parent
76f76b05bb
commit
b3fbb59d60
|
@ -1971,11 +1971,6 @@ class SyncStarRewriter extends AsyncRewriterBase {
|
|||
@override
|
||||
bool get isSyncStar => true;
|
||||
|
||||
/// Constructor creating the Iterable for a sync* method. Called with
|
||||
/// [bodyName].
|
||||
final js.Expression iterableFactory;
|
||||
List<js.Expression>? iterableFactoryTypeArguments;
|
||||
|
||||
/// A parameter to the [bodyName] function that passes the controlling
|
||||
/// `_SyncStarIterator`. This parameter is used to update the state of the
|
||||
/// iterator.
|
||||
|
@ -1991,9 +1986,7 @@ class SyncStarRewriter extends AsyncRewriterBase {
|
|||
final js.Expression yieldStarSelector;
|
||||
|
||||
SyncStarRewriter(DiagnosticReporter diagnosticListener, spannable,
|
||||
{required this.iterableFactory,
|
||||
required this.iterableFactoryTypeArguments,
|
||||
required this.iteratorCurrentValueProperty,
|
||||
{required this.iteratorCurrentValueProperty,
|
||||
required this.iteratorDatumProperty,
|
||||
required this.yieldStarSelector,
|
||||
required String safeVariableName(String proposedName),
|
||||
|
@ -2102,26 +2095,20 @@ class SyncStarRewriter extends AsyncRewriterBase {
|
|||
"varDecl": variableDeclarations,
|
||||
"returnInnerInnerFunction": returnInnerInnerFunction,
|
||||
}).withSourceInformation(functionSourceInformation);
|
||||
js.Expression callIterableFactory =
|
||||
js.js("#iterableFactory(#innerFunction, #type)", {
|
||||
"iterableFactory": iterableFactory,
|
||||
"type": iterableFactoryTypeArguments,
|
||||
"innerFunction": innerFunction,
|
||||
}).withSourceInformation(bodySourceInformation);
|
||||
js.Statement returnCallIterableFactory = js.Return(callIterableFactory)
|
||||
.withSourceInformation(bodySourceInformation);
|
||||
js.Statement returnInnerFunction =
|
||||
js.Return(innerFunction).withSourceInformation(bodySourceInformation);
|
||||
return js.js("""
|
||||
function (#renamedParameters, #typeParameters) {
|
||||
if (#needsThis)
|
||||
var #self = this;
|
||||
#returnCallIterableFactory;
|
||||
#returnInnerFunction;
|
||||
}
|
||||
""", {
|
||||
"renamedParameters": renamedParameters,
|
||||
"typeParameters": typeParameters,
|
||||
"needsThis": analysis.hasThis,
|
||||
"self": selfName,
|
||||
"returnCallIterableFactory": returnCallIterableFactory,
|
||||
"returnInnerFunction": returnInnerFunction,
|
||||
}).withSourceInformation(functionSourceInformation) as js.Fun;
|
||||
}
|
||||
|
||||
|
@ -2172,8 +2159,6 @@ class SyncStarRewriter extends AsyncRewriterBase {
|
|||
@override
|
||||
void initializeNames() {
|
||||
iteratorName = freshName('iterator');
|
||||
iterableFactoryTypeArguments =
|
||||
processTypeArguments(iterableFactoryTypeArguments);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -122,6 +122,11 @@ class BackendImpacts {
|
|||
);
|
||||
|
||||
late final BackendImpact syncStarBody = BackendImpact(
|
||||
// The transformed JavaScript code for the sync* body has direct assignments
|
||||
// to the properties for the instance fields of `_SyncStarIterator`.
|
||||
// BackendImpact cannot model direct field assigments, so instead the
|
||||
// impacts are modeled by a call to `_SyncStarIterator._modelGeneratedCode`
|
||||
// in `moveNext()`.
|
||||
dynamicUses: [
|
||||
Selector.fromElement(_commonElements.syncStarIteratorYieldStarMethod),
|
||||
],
|
||||
|
|
|
@ -1322,7 +1322,11 @@ class KernelSsaGraphBuilder extends ir.Visitor<void> with ir.VisitorVoidMixin {
|
|||
void _buildFunctionNode(
|
||||
FunctionEntity function, ir.FunctionNode functionNode) {
|
||||
if (functionNode.asyncMarker != ir.AsyncMarker.Sync) {
|
||||
_buildGenerator(function, functionNode);
|
||||
if (functionNode.asyncMarker == ir.AsyncMarker.SyncStar) {
|
||||
_buildSyncStarGenerator(function, functionNode);
|
||||
} else {
|
||||
_buildGenerator(function, functionNode);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1430,7 +1434,74 @@ class KernelSsaGraphBuilder extends ir.Visitor<void> with ir.VisitorVoidMixin {
|
|||
_closeFunction();
|
||||
}
|
||||
|
||||
/// Builds an SSA graph for a sync*/async/async* generator body.
|
||||
/// Builds an SSA graph for a sync* method. A sync* method is split into an
|
||||
/// entry function and a body function. The entry function calls the body
|
||||
/// function and wraps the result in an `_SyncStarIterable<T>`. The body
|
||||
/// function is a separate entity (GeneratorBodyEntity) that is compiled via
|
||||
/// SSA and the transformed into a reentrant state-machine.
|
||||
///
|
||||
/// Here we generate the entry function which is approximately like this:
|
||||
///
|
||||
/// Iterable<T> foo(parameters) {
|
||||
/// return _makeSyncStarIterable<T>(foo$body(parameters));
|
||||
/// }
|
||||
void _buildSyncStarGenerator(
|
||||
FunctionEntity function, ir.FunctionNode functionNode) {
|
||||
_openFunction(function,
|
||||
functionNode: functionNode,
|
||||
parameterStructure: function.parameterStructure,
|
||||
checks: _checksForFunction(function));
|
||||
|
||||
// Prepare to call the body generator.
|
||||
|
||||
// Is 'buildAsyncBody' the best location for the entry?
|
||||
var sourceInformation = _sourceInformationBuilder.buildAsyncBody();
|
||||
|
||||
// Forward all the parameters to the body.
|
||||
List<HInstruction> inputs = [];
|
||||
if (graph.thisInstruction != null) {
|
||||
inputs.add(graph.thisInstruction!);
|
||||
}
|
||||
if (graph.explicitReceiverParameter != null) {
|
||||
inputs.add(graph.explicitReceiverParameter!);
|
||||
}
|
||||
for (Local local in parameters.keys) {
|
||||
if (!elidedParameters.contains(local)) {
|
||||
inputs.add(localsHandler.readLocal(local));
|
||||
}
|
||||
}
|
||||
for (Local local in _functionTypeParameterLocals) {
|
||||
inputs.add(localsHandler.readLocal(local));
|
||||
}
|
||||
|
||||
JGeneratorBody body = _elementMap.getGeneratorBody(function);
|
||||
push(HInvokeGeneratorBody(
|
||||
body,
|
||||
inputs,
|
||||
_abstractValueDomain.dynamicType, // Untyped JavaScript thunk.
|
||||
sourceInformation));
|
||||
|
||||
// Call `_makeSyncStarIterable<T>(body)`. This usually gets inlined.
|
||||
|
||||
final elementType = _elementEnvironment.getAsyncOrSyncStarElementType(
|
||||
function.asyncMarker, _returnType!);
|
||||
FunctionEntity method = _commonElements.syncStarIterableFactory;
|
||||
List<HInstruction> arguments = [pop()];
|
||||
List<DartType> typeArguments = const [];
|
||||
if (_rtiNeed.methodNeedsTypeArguments(method)) {
|
||||
typeArguments = [elementType];
|
||||
_addTypeArguments(arguments, typeArguments, sourceInformation);
|
||||
}
|
||||
_pushStaticInvocation(method, arguments,
|
||||
_typeInferenceMap.getReturnTypeOf(method), typeArguments,
|
||||
sourceInformation: sourceInformation);
|
||||
|
||||
_closeAndGotoExit(HReturn(_abstractValueDomain, pop(), sourceInformation));
|
||||
|
||||
_closeFunction();
|
||||
}
|
||||
|
||||
/// Builds an SSA graph for a async/async* generator body.
|
||||
void _buildGeneratorBody(
|
||||
JGeneratorBody function, ir.FunctionNode functionNode) {
|
||||
FunctionEntity entry = function.function;
|
||||
|
|
|
@ -246,13 +246,7 @@ class SsaFunctionCompiler implements FunctionCompiler {
|
|||
js.Expression code,
|
||||
DartType? asyncTypeParameter,
|
||||
js.Name name) {
|
||||
final itemTypeExpression =
|
||||
_fetchItemTypeNewRti(commonElements, registry, asyncTypeParameter);
|
||||
|
||||
SyncStarRewriter rewriter = SyncStarRewriter(_reporter, element,
|
||||
iterableFactory: emitter
|
||||
.staticFunctionAccess(commonElements.syncStarIterableFactory),
|
||||
iterableFactoryTypeArguments: itemTypeExpression,
|
||||
iteratorCurrentValueProperty: namer.instanceFieldPropertyName(
|
||||
commonElements.syncStarIteratorCurrentField),
|
||||
iteratorDatumProperty: namer.instanceFieldPropertyName(
|
||||
|
@ -262,11 +256,6 @@ class SsaFunctionCompiler implements FunctionCompiler {
|
|||
safeVariableName: namer.safeVariablePrefixForAsyncRewrite,
|
||||
bodyName: namer.deriveAsyncBodyName(name));
|
||||
|
||||
registry.registerStaticUse(StaticUse.staticInvoke(
|
||||
commonElements.syncStarIterableFactory,
|
||||
CallStructure.unnamed(1, 1),
|
||||
[elementEnvironment.getFunctionAsyncOrSyncStarElementType(element)]));
|
||||
|
||||
return rewriter;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,8 +49,6 @@ void testSyncStarTransform(String source, String expected) {
|
|||
source,
|
||||
expected,
|
||||
SyncStarRewriter(SimpleErrorReporter(), null,
|
||||
iterableFactory: VariableUse("NewIterable"),
|
||||
iterableFactoryTypeArguments: [VariableUse("IterableType")],
|
||||
iteratorCurrentValueProperty: string('_current'),
|
||||
iteratorDatumProperty: string('_datum'),
|
||||
yieldStarSelector: string('_yieldStar'),
|
||||
|
@ -1295,7 +1293,7 @@ function(a) sync* {
|
|||
return foo();
|
||||
}""", """
|
||||
function(__a) {
|
||||
return NewIterable(function() {
|
||||
return function() {
|
||||
var a = __a;
|
||||
var __goto = 0, __handler = 2, __currentError;
|
||||
return function body(__iterator, __errorCode, __result) {
|
||||
|
@ -1319,6 +1317,6 @@ function(__a) {
|
|||
return __iterator._datum = __currentError, 3;
|
||||
}
|
||||
};
|
||||
}, IterableType);
|
||||
};
|
||||
}""");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue