mirror of
https://github.com/dart-lang/sdk
synced 2024-09-18 20:01:19 +00:00
Refactor output code for generators
sync*/async/async* generators have two parts: an entry, which does checks and computes the element type of the result, and a body, which is transformed after lowering to JavaScript. The split ensures that the code for checks is done at function call time, rather than e.g. in the moveNext method of a sync* iterator. A following CL with optimize the split to generate one function when there are no checks and the type argument is simple enough for textual substitution. Change-Id: I5414109ca851f9267871aa113a2e29b16236986d Reviewed-on: https://dart-review.googlesource.com/54308 Commit-Queue: Stephen Adams <sra@google.com> Reviewed-by: Sigmund Cherem <sigmund@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
parent
e67222a92b
commit
6efd3b3654
|
@ -1393,6 +1393,9 @@ abstract class ElementEnvironment {
|
|||
/// Calls [f] for each class member declared in [cls].
|
||||
void forEachLocalClassMember(ClassEntity cls, void f(MemberEntity member));
|
||||
|
||||
/// Calls [f] for each class member added to [cls] during compilation.
|
||||
void forEachInjectedClassMember(ClassEntity cls, void f(MemberEntity member));
|
||||
|
||||
/// Calls [f] for each class member declared or inherited in [cls] together
|
||||
/// with the class that declared the member.
|
||||
///
|
||||
|
|
|
@ -212,8 +212,8 @@ class KernelInferrerEngine extends InferrerEngineImpl<ir.Node> {
|
|||
}
|
||||
break;
|
||||
case MemberKind.closureField:
|
||||
break;
|
||||
case MemberKind.signature:
|
||||
case MemberKind.generatorBody:
|
||||
break;
|
||||
}
|
||||
failedAt(member, 'Unexpected member definition: $definition.');
|
||||
|
|
|
@ -144,6 +144,7 @@ class KernelSourceInformationBuilder
|
|||
return _buildFunction(name, base ?? node, node.function);
|
||||
}
|
||||
break;
|
||||
// TODO(sra): generatorBody
|
||||
default:
|
||||
}
|
||||
return _buildTreeNode(base ?? node, name: name);
|
||||
|
@ -209,6 +210,16 @@ class KernelSourceInformationBuilder
|
|||
return _buildBody(node, node.function.body);
|
||||
}
|
||||
break;
|
||||
case MemberKind.generatorBody:
|
||||
ir.Node node = definition.node;
|
||||
if (node is ir.FunctionDeclaration) {
|
||||
return _buildBody(node, node.function.body);
|
||||
} else if (node is ir.FunctionExpression) {
|
||||
return _buildBody(node, node.function.body);
|
||||
} else if (node is ir.Member && node.function != null) {
|
||||
return _buildBody(node, node.function.body);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
return _buildTreeNode(definition.node);
|
||||
|
|
|
@ -159,6 +159,9 @@ abstract class AsyncRewriterBase extends js.NodeVisitor {
|
|||
js.VariableUse get self => new js.VariableUse(selfName);
|
||||
String selfName;
|
||||
|
||||
/// The rewritten code can take type arguments. These are added if needed.
|
||||
List<String> typeArgumentNames = <String>[];
|
||||
|
||||
final DiagnosticReporter reporter;
|
||||
// For error reporting only.
|
||||
Spannable get spannable {
|
||||
|
@ -245,6 +248,15 @@ abstract class AsyncRewriterBase extends js.NodeVisitor {
|
|||
return result;
|
||||
}
|
||||
|
||||
List<js.Expression> processTypeArguments(List<js.Expression> types) {
|
||||
if (types == null) {
|
||||
String name = freshName('type');
|
||||
typeArgumentNames.add(name);
|
||||
return <js.Expression>[new js.VariableUse(name)];
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
/// All the pieces are collected in this map, to create a switch with a case
|
||||
/// for each label.
|
||||
///
|
||||
|
@ -532,6 +544,7 @@ abstract class AsyncRewriterBase extends js.NodeVisitor {
|
|||
/// Returns the rewritten function.
|
||||
js.Fun finishFunction(
|
||||
List<js.Parameter> parameters,
|
||||
List<js.Parameter> typeParameters,
|
||||
js.Statement rewrittenBody,
|
||||
js.VariableDeclarationList variableDeclarations,
|
||||
SourceInformation functionSourceInformation,
|
||||
|
@ -738,8 +751,11 @@ abstract class AsyncRewriterBase extends js.NodeVisitor {
|
|||
js.VariableDeclarationList variableDeclarations =
|
||||
new js.VariableDeclarationList(variables);
|
||||
|
||||
return finishFunction(node.params, rewrittenBody, variableDeclarations,
|
||||
node.sourceInformation, bodySourceInformation);
|
||||
// Names are already safe when added.
|
||||
List<js.Parameter> typeParameters =
|
||||
typeArgumentNames.map((name) => new js.Parameter(name)).toList();
|
||||
return finishFunction(node.params, typeParameters, rewrittenBody,
|
||||
variableDeclarations, node.sourceInformation, bodySourceInformation);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -1739,7 +1755,7 @@ class AsyncRewriter extends AsyncRewriterBase {
|
|||
///
|
||||
/// Specific to async methods.
|
||||
final js.Expression completerFactory;
|
||||
final js.Expression completerFactoryTypeArgument;
|
||||
List<js.Expression> completerFactoryTypeArguments;
|
||||
|
||||
final js.Expression wrapBody;
|
||||
|
||||
|
@ -1749,7 +1765,7 @@ class AsyncRewriter extends AsyncRewriterBase {
|
|||
this.asyncReturn,
|
||||
this.asyncRethrow,
|
||||
this.completerFactory,
|
||||
this.completerFactoryTypeArgument,
|
||||
this.completerFactoryTypeArguments,
|
||||
this.wrapBody,
|
||||
String safeVariableName(String proposedName),
|
||||
js.Name bodyName})
|
||||
|
@ -1803,7 +1819,7 @@ class AsyncRewriter extends AsyncRewriterBase {
|
|||
completer,
|
||||
js.js('#(#)', [
|
||||
completerFactory,
|
||||
completerFactoryTypeArgument
|
||||
completerFactoryTypeArguments
|
||||
]).withSourceInformation(sourceInformation),
|
||||
sourceInformation));
|
||||
if (analysis.hasExplicitReturns) {
|
||||
|
@ -1816,6 +1832,8 @@ class AsyncRewriter extends AsyncRewriterBase {
|
|||
@override
|
||||
void initializeNames() {
|
||||
completerName = freshName("completer");
|
||||
completerFactoryTypeArguments =
|
||||
processTypeArguments(completerFactoryTypeArguments);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -1833,6 +1851,7 @@ class AsyncRewriter extends AsyncRewriterBase {
|
|||
@override
|
||||
js.Fun finishFunction(
|
||||
List<js.Parameter> parameters,
|
||||
List<js.Parameter> typeParameters,
|
||||
js.Statement rewrittenBody,
|
||||
js.VariableDeclarationList variableDeclarations,
|
||||
SourceInformation functionSourceInformation,
|
||||
|
@ -1884,12 +1903,13 @@ class AsyncRewriter extends AsyncRewriterBase {
|
|||
"innerFunction": innerFunction,
|
||||
}).withSourceInformation(bodySourceInformation);
|
||||
return js.js("""
|
||||
function (#parameters) {
|
||||
function (#parameters, #typeParameters) {
|
||||
#variableDeclarations;
|
||||
var #bodyName = #wrapBodyCall;
|
||||
#returnAsyncStart;
|
||||
}""", {
|
||||
"parameters": parameters,
|
||||
"typeParameters": typeParameters,
|
||||
"variableDeclarations": variableDeclarations,
|
||||
"bodyName": bodyName,
|
||||
"wrapBodyCall": wrapBodyCall,
|
||||
|
@ -1904,7 +1924,7 @@ class SyncStarRewriter extends AsyncRewriterBase {
|
|||
/// Constructor creating the Iterable for a sync* method. Called with
|
||||
/// [bodyName].
|
||||
final js.Expression iterableFactory;
|
||||
final js.Expression iterableFactoryTypeArgument;
|
||||
List<js.Expression> iterableFactoryTypeArguments;
|
||||
|
||||
/// A JS Expression that creates a marker showing that iteration is over.
|
||||
///
|
||||
|
@ -1922,7 +1942,7 @@ class SyncStarRewriter extends AsyncRewriterBase {
|
|||
SyncStarRewriter(DiagnosticReporter diagnosticListener, spannable,
|
||||
{this.endOfIteration,
|
||||
this.iterableFactory,
|
||||
this.iterableFactoryTypeArgument,
|
||||
this.iterableFactoryTypeArguments,
|
||||
this.yieldStarExpression,
|
||||
this.uncaughtErrorExpression,
|
||||
String safeVariableName(String proposedName),
|
||||
|
@ -1949,6 +1969,7 @@ class SyncStarRewriter extends AsyncRewriterBase {
|
|||
@override
|
||||
js.Fun finishFunction(
|
||||
List<js.Parameter> parameters,
|
||||
List<js.Parameter> typeParameters,
|
||||
js.Statement rewrittenBody,
|
||||
js.VariableDeclarationList variableDeclarations,
|
||||
SourceInformation functionSourceInformation,
|
||||
|
@ -2017,19 +2038,20 @@ class SyncStarRewriter extends AsyncRewriterBase {
|
|||
js.Expression callIterableFactory =
|
||||
js.js("#iterableFactory(#innerFunction, #type)", {
|
||||
"iterableFactory": iterableFactory,
|
||||
"type": iterableFactoryTypeArgument,
|
||||
"type": iterableFactoryTypeArguments,
|
||||
"innerFunction": innerFunction,
|
||||
}).withSourceInformation(bodySourceInformation);
|
||||
js.Statement returnCallIterableFactory = new js.Return(callIterableFactory)
|
||||
.withSourceInformation(bodySourceInformation);
|
||||
return js.js("""
|
||||
function (#renamedParameters) {
|
||||
function (#renamedParameters, #typeParameters) {
|
||||
if (#needsThis)
|
||||
var #self = this;
|
||||
#returnCallIterableFactory;
|
||||
}
|
||||
""", {
|
||||
"renamedParameters": renamedParameters,
|
||||
"typeParameters": typeParameters,
|
||||
"needsThis": analysis.hasThis,
|
||||
"self": selfName,
|
||||
"returnCallIterableFactory": returnCallIterableFactory,
|
||||
|
@ -2075,7 +2097,10 @@ class SyncStarRewriter extends AsyncRewriterBase {
|
|||
}
|
||||
|
||||
@override
|
||||
void initializeNames() {}
|
||||
void initializeNames() {
|
||||
iterableFactoryTypeArguments =
|
||||
processTypeArguments(iterableFactoryTypeArguments);
|
||||
}
|
||||
}
|
||||
|
||||
class AsyncStarRewriter extends AsyncRewriterBase {
|
||||
|
@ -2115,7 +2140,7 @@ class AsyncStarRewriter extends AsyncRewriterBase {
|
|||
///
|
||||
/// Specific to async* methods.
|
||||
final js.Expression newController;
|
||||
final js.Expression newControllerTypeArgument;
|
||||
List<js.Expression> newControllerTypeArguments;
|
||||
|
||||
/// Used to get the `Stream` out of the [controllerName] variable.
|
||||
final js.Expression streamOfController;
|
||||
|
@ -2136,7 +2161,7 @@ class AsyncStarRewriter extends AsyncRewriterBase {
|
|||
{this.asyncStarHelper,
|
||||
this.streamOfController,
|
||||
this.newController,
|
||||
this.newControllerTypeArgument,
|
||||
this.newControllerTypeArguments,
|
||||
this.yieldExpression,
|
||||
this.yieldStarExpression,
|
||||
this.wrapBody,
|
||||
|
@ -2184,6 +2209,7 @@ class AsyncStarRewriter extends AsyncRewriterBase {
|
|||
@override
|
||||
js.Fun finishFunction(
|
||||
List<js.Parameter> parameters,
|
||||
List<js.Parameter> typeParameters,
|
||||
js.Statement rewrittenBody,
|
||||
js.VariableDeclarationList variableDeclarations,
|
||||
SourceInformation functionSourceInformation,
|
||||
|
@ -2277,12 +2303,13 @@ class AsyncStarRewriter extends AsyncRewriterBase {
|
|||
new js.Return(streamOfControllerCall)
|
||||
.withSourceInformation(bodySourceInformation);
|
||||
return js.js("""
|
||||
function (#parameters) {
|
||||
function (#parameters, #typeParameters) {
|
||||
#declareBodyName;
|
||||
#variableDeclarations;
|
||||
#returnStreamOfControllerCall;
|
||||
}""", {
|
||||
"parameters": parameters,
|
||||
"typeParameters": typeParameters,
|
||||
"declareBodyName": declareBodyName,
|
||||
"variableDeclarations": variableDeclarations,
|
||||
"returnStreamOfControllerCall": returnStreamOfControllerCall,
|
||||
|
@ -2329,7 +2356,7 @@ class AsyncStarRewriter extends AsyncRewriterBase {
|
|||
js.js('#(#, #)', [
|
||||
newController,
|
||||
bodyName,
|
||||
newControllerTypeArgument
|
||||
newControllerTypeArguments
|
||||
]).withSourceInformation(sourceInformation),
|
||||
sourceInformation));
|
||||
if (analysis.hasYield) {
|
||||
|
@ -2343,6 +2370,8 @@ class AsyncStarRewriter extends AsyncRewriterBase {
|
|||
void initializeNames() {
|
||||
controllerName = freshName("controller");
|
||||
nextWhenCanceledName = freshName("nextWhenCanceled");
|
||||
newControllerTypeArguments =
|
||||
processTypeArguments(newControllerTypeArguments);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -1165,7 +1165,8 @@ class JavaScriptBackend {
|
|||
if (element.asyncMarker == AsyncMarker.SYNC) return code;
|
||||
|
||||
AsyncRewriterBase rewriter = null;
|
||||
jsAst.Name name = namer.methodPropertyName(element);
|
||||
jsAst.Name name = namer.methodPropertyName(
|
||||
element is JGeneratorBody ? element.function : element);
|
||||
|
||||
switch (element.asyncMarker) {
|
||||
case AsyncMarker.ASYNC:
|
||||
|
@ -1178,7 +1179,7 @@ class JavaScriptBackend {
|
|||
emitter.staticFunctionAccess(commonElements.endOfIteration),
|
||||
iterableFactory: emitter
|
||||
.staticFunctionAccess(commonElements.syncStarIterableFactory),
|
||||
iterableFactoryTypeArgument:
|
||||
iterableFactoryTypeArguments:
|
||||
_fetchItemType(element, elementEnvironment),
|
||||
yieldStarExpression:
|
||||
emitter.staticFunctionAccess(commonElements.yieldStar),
|
||||
|
@ -1201,7 +1202,7 @@ class JavaScriptBackend {
|
|||
wrapBody: emitter.staticFunctionAccess(commonElements.wrapBody),
|
||||
newController: emitter.staticFunctionAccess(
|
||||
commonElements.asyncStarStreamControllerFactory),
|
||||
newControllerTypeArgument:
|
||||
newControllerTypeArguments:
|
||||
_fetchItemType(element, elementEnvironment),
|
||||
safeVariableName: namer.safeVariablePrefixForAsyncRewrite,
|
||||
yieldExpression:
|
||||
|
@ -1219,19 +1220,22 @@ class JavaScriptBackend {
|
|||
return rewriter.rewrite(code, bodySourceInformation, exitSourceInformation);
|
||||
}
|
||||
|
||||
/// Returns an expression that evaluates the type argument to the
|
||||
/// Returns an optional expression that evaluates the type argument to the
|
||||
/// Future/Stream/Iterable.
|
||||
jsAst.Expression _fetchItemType(
|
||||
/// Returns an empty list if the type is not needed.
|
||||
/// Returns `null` if the type expression is determined by
|
||||
/// the outside context and should be added as a function parameter.
|
||||
List<jsAst.Expression> _fetchItemType(
|
||||
FunctionEntity element, ElementEnvironment elementEnvironment) {
|
||||
DartType type =
|
||||
elementEnvironment.getFunctionAsyncOrSyncStarElementType(element);
|
||||
//DartType type =
|
||||
// elementEnvironment.getFunctionAsyncOrSyncStarElementType(element);
|
||||
|
||||
if (!type.containsFreeTypeVariables) {
|
||||
return rtiEncoder.getTypeRepresentation(emitter.emitter, type, null);
|
||||
}
|
||||
//if (!type.containsFreeTypeVariables) {
|
||||
// var ast = rtiEncoder.getTypeRepresentation(emitter.emitter, type, null);
|
||||
// return <jsAst.Expression>[ast];
|
||||
//}
|
||||
|
||||
// TODO(sra): Handle types that have type variables.
|
||||
return js('null');
|
||||
return null;
|
||||
}
|
||||
|
||||
AsyncRewriter _makeAsyncRewriter(
|
||||
|
@ -1250,7 +1254,7 @@ class JavaScriptBackend {
|
|||
? commonElements.asyncAwaitCompleterFactory
|
||||
: commonElements.syncCompleterFactory;
|
||||
|
||||
jsAst.Expression itemTypeExpression =
|
||||
List<jsAst.Expression> itemTypeExpression =
|
||||
_fetchItemType(element, elementEnvironment);
|
||||
|
||||
var rewriter = new AsyncRewriter(reporter, element,
|
||||
|
@ -1263,7 +1267,7 @@ class JavaScriptBackend {
|
|||
emitter.staticFunctionAccess(commonElements.asyncHelperRethrow),
|
||||
wrapBody: emitter.staticFunctionAccess(commonElements.wrapBody),
|
||||
completerFactory: emitter.staticFunctionAccess(completerFactory),
|
||||
completerFactoryTypeArgument: itemTypeExpression,
|
||||
completerFactoryTypeArguments: itemTypeExpression,
|
||||
safeVariableName: namer.safeVariablePrefixForAsyncRewrite,
|
||||
bodyName: namer.deriveAsyncBodyName(name));
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import '../elements/resolution_types.dart';
|
|||
import '../elements/types.dart';
|
||||
import '../js/js.dart' as jsAst;
|
||||
import '../js_model/closure.dart';
|
||||
import '../js_model/elements.dart' show JGeneratorBody;
|
||||
import '../universe/call_structure.dart' show CallStructure;
|
||||
import '../universe/selector.dart' show Selector, SelectorKind;
|
||||
import '../universe/world_builder.dart' show CodegenWorldBuilder;
|
||||
|
@ -782,13 +783,29 @@ class Namer {
|
|||
ctor, () => _proposeNameForConstructorBody(ctor));
|
||||
}
|
||||
|
||||
/// Name for a generator body.
|
||||
jsAst.Name generatorBodyInstanceMethodName(JGeneratorBody method) {
|
||||
assert(method.isInstanceMember);
|
||||
// TODO(sra): Except for methods declared in mixins, we can use a compact
|
||||
// naming scheme like we do for [ConstructorBodyEntity].
|
||||
FunctionEntity function = method.function;
|
||||
return _disambiguateInternalMember(method, () {
|
||||
String invocationName = operatorNameToIdentifier(function.name);
|
||||
return '${invocationName}\$body\$${method.enclosingClass.name}';
|
||||
});
|
||||
}
|
||||
|
||||
/// Annotated name for [method] encoding arity and named parameters.
|
||||
jsAst.Name instanceMethodName(FunctionEntity method) {
|
||||
// TODO(johnniwinther): Avoid the use of [ConstructorBodyEntity]. The
|
||||
// codegen model should be explicit about its constructor body elements.
|
||||
// TODO(johnniwinther): Avoid the use of [ConstructorBodyEntity] and
|
||||
// [JGeneratorBody]. The codegen model should be explicit about its
|
||||
// constructor body elements.
|
||||
if (method is ConstructorBodyEntity) {
|
||||
return constructorBodyName(method);
|
||||
}
|
||||
if (method is JGeneratorBody) {
|
||||
return generatorBodyInstanceMethodName(method);
|
||||
}
|
||||
return invocationName(new Selector.fromElement(method));
|
||||
}
|
||||
|
||||
|
@ -1337,6 +1354,8 @@ class Namer {
|
|||
String _proposeNameForMember(MemberEntity element) {
|
||||
if (element.isConstructor) {
|
||||
return _proposeNameForConstructor(element);
|
||||
} else if (element is JGeneratorBody) {
|
||||
return _proposeNameForMember(element.function) + r'$body';
|
||||
} else if (element.enclosingClass != null) {
|
||||
ClassEntity enclosingClass = element.enclosingClass;
|
||||
return '${enclosingClass.name}_${element.name}';
|
||||
|
|
|
@ -743,6 +743,7 @@ class ProgramBuilder {
|
|||
if (!onlyForRti && !_elementEnvironment.isMixinApplication(cls)) {
|
||||
List<MemberEntity> members = <MemberEntity>[];
|
||||
_elementEnvironment.forEachLocalClassMember(cls, members.add);
|
||||
_elementEnvironment.forEachInjectedClassMember(cls, members.add);
|
||||
_elementEnvironment.forEachConstructorBody(cls, members.add);
|
||||
_sorter.sortMembers(members).forEach(visitMember);
|
||||
}
|
||||
|
|
|
@ -143,6 +143,10 @@ class JsElementCreatorMixin {
|
|||
return new JConstructorBody(constructor);
|
||||
}
|
||||
|
||||
JGeneratorBody createGeneratorBody(FunctionEntity function) {
|
||||
return new JGeneratorBody(function);
|
||||
}
|
||||
|
||||
IndexedFunction createGetter(LibraryEntity library,
|
||||
ClassEntity enclosingClass, Name name, AsyncMarker asyncMarker,
|
||||
{bool isStatic, bool isExternal, bool isAbstract}) {
|
||||
|
@ -498,6 +502,17 @@ class JMethod extends JFunction {
|
|||
String get _kind => 'method';
|
||||
}
|
||||
|
||||
class JGeneratorBody extends JFunction {
|
||||
final FunctionEntity function;
|
||||
|
||||
JGeneratorBody(this.function)
|
||||
: super(function.library, function.enclosingClass, function.memberName,
|
||||
function.parameterStructure, function.asyncMarker,
|
||||
isStatic: function.isStatic, isExternal: false);
|
||||
|
||||
String get _kind => 'generator_body';
|
||||
}
|
||||
|
||||
class JGetter extends JFunction {
|
||||
final bool isAbstract;
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@ import '../elements/types.dart';
|
|||
import '../kernel/element_map.dart';
|
||||
import '../kernel/indexed.dart';
|
||||
|
||||
import '../js_model/elements.dart' show JGeneratorBody;
|
||||
|
||||
class GlobalLocalsMap {
|
||||
Map<MemberEntity, KernelToLocalsMap> _localsMaps =
|
||||
<MemberEntity, KernelToLocalsMap>{};
|
||||
|
@ -419,7 +421,9 @@ class JLocal extends IndexedLocal {
|
|||
/// True if this local represents a local parameter.
|
||||
final bool isRegularParameter;
|
||||
|
||||
JLocal(this.name, this.memberContext, {this.isRegularParameter: false});
|
||||
JLocal(this.name, this.memberContext, {this.isRegularParameter: false}) {
|
||||
assert(memberContext is! JGeneratorBody);
|
||||
}
|
||||
|
||||
String get _kind => 'local';
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import '../js_backend/namer.dart';
|
|||
import '../js_backend/native_data.dart';
|
||||
import '../js_emitter/code_emitter_task.dart';
|
||||
import '../js_model/closure.dart' show JRecordField, KernelScopeInfo;
|
||||
import '../js_model/elements.dart' show JGeneratorBody;
|
||||
import '../native/native.dart' as native;
|
||||
import '../ssa/type_builder.dart';
|
||||
import '../types/types.dart';
|
||||
|
@ -236,6 +237,9 @@ abstract class KernelToElementMapForBuilding implements KernelToElementMap {
|
|||
/// Returns the constructor body entity corresponding to [constructor].
|
||||
FunctionEntity getConstructorBody(ir.Constructor node);
|
||||
|
||||
/// Returns the constructor body entity corresponding to [function].
|
||||
JGeneratorBody getGeneratorBody(FunctionEntity function);
|
||||
|
||||
/// Make a record to ensure variables that are are declared in one scope and
|
||||
/// modified in another get their values updated correctly.
|
||||
Map<Local, JRecordField> makeRecordContainer(
|
||||
|
@ -261,6 +265,8 @@ enum MemberKind {
|
|||
// the closure class. It does not have a corresponding ir.Node or a method
|
||||
// body.
|
||||
signature,
|
||||
// A separated body of a generator (sync*/async/async*) function.
|
||||
generatorBody,
|
||||
}
|
||||
|
||||
/// Definition information for a [MemberEntity].
|
||||
|
|
|
@ -748,6 +748,13 @@ abstract class KernelToElementMapBase extends KernelToElementMapBaseMixin {
|
|||
});
|
||||
}
|
||||
|
||||
void _forEachInjectedClassMember(
|
||||
IndexedClass cls, void f(MemberEntity member)) {
|
||||
assert(checkFamily(cls));
|
||||
throw new UnsupportedError(
|
||||
'KernelToElementMapBase._forEachInjectedClassMember');
|
||||
}
|
||||
|
||||
void _forEachClassMember(
|
||||
IndexedClass cls, void f(ClassEntity cls, MemberEntity member)) {
|
||||
assert(checkFamily(cls));
|
||||
|
@ -1373,7 +1380,7 @@ class KernelToElementMapForImpactImpl extends KernelToElementMapBase
|
|||
/// Returns the element type of a async/sync*/async* function.
|
||||
@override
|
||||
DartType getFunctionAsyncOrSyncStarElementType(ir.FunctionNode functionNode) {
|
||||
DartType returnType = getFunctionType(functionNode).returnType;
|
||||
DartType returnType = getDartType(functionNode.returnType);
|
||||
switch (functionNode.asyncMarker) {
|
||||
case ir.AsyncMarker.SyncStar:
|
||||
return elementEnvironment.getAsyncOrSyncStarElementType(
|
||||
|
@ -1471,6 +1478,7 @@ class KernelElementEnvironment extends ElementEnvironment {
|
|||
|
||||
@override
|
||||
DartType getFunctionAsyncOrSyncStarElementType(FunctionEntity function) {
|
||||
// TODO(sra): Should be getting the DartType from the node.
|
||||
DartType returnType = getFunctionType(function).returnType;
|
||||
return getAsyncOrSyncStarElementType(function.asyncMarker, returnType);
|
||||
}
|
||||
|
@ -1580,6 +1588,12 @@ class KernelElementEnvironment extends ElementEnvironment {
|
|||
elementMap._forEachLocalClassMember(cls, f);
|
||||
}
|
||||
|
||||
@override
|
||||
void forEachInjectedClassMember(
|
||||
ClassEntity cls, void f(MemberEntity member)) {
|
||||
elementMap._forEachInjectedClassMember(cls, f);
|
||||
}
|
||||
|
||||
@override
|
||||
void forEachClassMember(
|
||||
ClassEntity cls, void f(ClassEntity declarer, MemberEntity member)) {
|
||||
|
@ -2257,6 +2271,12 @@ class JsKernelToElementMap extends KernelToElementMapBase
|
|||
|
||||
NativeBasicData nativeBasicData;
|
||||
|
||||
Map<FunctionEntity, JGeneratorBody> _generatorBodies =
|
||||
<FunctionEntity, JGeneratorBody>{};
|
||||
|
||||
Map<ClassEntity, List<MemberEntity>> _injectedClassMembers =
|
||||
<ClassEntity, List<MemberEntity>>{};
|
||||
|
||||
JsKernelToElementMap(
|
||||
DiagnosticReporter reporter,
|
||||
Environment environment,
|
||||
|
@ -2514,6 +2534,11 @@ class JsKernelToElementMap extends KernelToElementMapBase
|
|||
env.forEachConstructorBody(f);
|
||||
}
|
||||
|
||||
void _forEachInjectedClassMember(
|
||||
IndexedClass cls, void f(MemberEntity member)) {
|
||||
_injectedClassMembers[cls]?.forEach(f);
|
||||
}
|
||||
|
||||
JRecordField _constructRecordFieldEntry(
|
||||
InterfaceType memberThisType,
|
||||
ir.VariableDeclaration variable,
|
||||
|
@ -2911,6 +2936,31 @@ class JsKernelToElementMap extends KernelToElementMapBase
|
|||
String _getClosureVariableName(String name, int id) {
|
||||
return "_captured_${name}_$id";
|
||||
}
|
||||
|
||||
JGeneratorBody getGeneratorBody(covariant IndexedFunction function) {
|
||||
FunctionData functionData = _members.getData(function);
|
||||
ir.TreeNode node = functionData.definition.node;
|
||||
// TODO(sra): Maybe store this in the FunctionData.
|
||||
JGeneratorBody generatorBody = _generatorBodies[function];
|
||||
if (generatorBody == null) {
|
||||
generatorBody = createGeneratorBody(function);
|
||||
_members.register<IndexedFunction, FunctionData>(
|
||||
generatorBody,
|
||||
new GeneratorBodyFunctionData(
|
||||
functionData,
|
||||
new SpecialMemberDefinition(
|
||||
generatorBody, node, MemberKind.generatorBody)));
|
||||
|
||||
if (function.enclosingClass != null) {
|
||||
// TODO(sra): Integrate this with ClassEnvImpl.addConstructorBody ?
|
||||
(_injectedClassMembers[function.enclosingClass] ??= <MemberEntity>[])
|
||||
.add(generatorBody);
|
||||
}
|
||||
}
|
||||
return generatorBody;
|
||||
}
|
||||
|
||||
JGeneratorBody createGeneratorBody(FunctionEntity function);
|
||||
}
|
||||
|
||||
class KernelClassQueries extends ClassQueries {
|
||||
|
|
|
@ -829,6 +829,44 @@ class SignatureFunctionData implements FunctionData {
|
|||
}
|
||||
}
|
||||
|
||||
abstract class DelegatedFunctionData implements FunctionData {
|
||||
final FunctionData baseData;
|
||||
|
||||
DelegatedFunctionData(this.baseData);
|
||||
|
||||
FunctionType getFunctionType(covariant KernelToElementMapBase elementMap) {
|
||||
return baseData.getFunctionType(elementMap);
|
||||
}
|
||||
|
||||
List<TypeVariableType> getFunctionTypeVariables(
|
||||
KernelToElementMap elementMap) {
|
||||
return baseData.getFunctionTypeVariables(elementMap);
|
||||
}
|
||||
|
||||
void forEachParameter(KernelToElementMapForBuilding elementMap,
|
||||
void f(DartType type, String name, ConstantValue defaultValue)) {
|
||||
return baseData.forEachParameter(elementMap, f);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<ConstantValue> getMetadata(KernelToElementMap elementMap) {
|
||||
return const <ConstantValue>[];
|
||||
}
|
||||
|
||||
InterfaceType getMemberThisType(KernelToElementMapForBuilding elementMap) {
|
||||
return baseData.getMemberThisType(elementMap);
|
||||
}
|
||||
|
||||
ClassTypeVariableAccess get classTypeVariableAccess =>
|
||||
baseData.classTypeVariableAccess;
|
||||
}
|
||||
|
||||
class GeneratorBodyFunctionData extends DelegatedFunctionData {
|
||||
final MemberDefinition definition;
|
||||
GeneratorBodyFunctionData(FunctionData baseData, this.definition)
|
||||
: super(baseData);
|
||||
}
|
||||
|
||||
abstract class ConstructorData extends FunctionData {
|
||||
ConstantConstructor getConstructorConstant(
|
||||
KernelToElementMapBase elementMap, ConstructorEntity constructor);
|
||||
|
|
|
@ -551,6 +551,10 @@ class _CompilerElementEnvironment extends ElementEnvironment {
|
|||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void forEachInjectedClassMember(
|
||||
covariant ClassElement cls, void f(MemberElement member)) {}
|
||||
|
||||
@override
|
||||
void forEachClassMember(covariant ClassElement cls,
|
||||
void f(ClassElement declarer, MemberElement member)) {
|
||||
|
|
|
@ -30,6 +30,7 @@ import '../js_backend/runtime_types.dart' show RuntimeTypesSubstitutions;
|
|||
import '../js_emitter/js_emitter.dart' show NativeEmitter;
|
||||
import '../js_model/locals.dart'
|
||||
show forEachOrderedParameter, GlobalLocalsMap, JumpVisitor;
|
||||
import '../js_model/elements.dart' show JGeneratorBody;
|
||||
import '../kernel/element_map.dart';
|
||||
import '../kernel/kernel_backend_strategy.dart';
|
||||
import '../native/native.dart' as native;
|
||||
|
@ -70,6 +71,7 @@ class StackFrame {
|
|||
class KernelSsaGraphBuilder extends ir.Visitor
|
||||
with GraphBuilder, SsaBuilderFieldMixin {
|
||||
final MemberEntity targetElement;
|
||||
final MemberEntity initialTargetElement;
|
||||
|
||||
final ClosedWorld closedWorld;
|
||||
final CodegenWorldBuilder _worldBuilder;
|
||||
|
@ -124,7 +126,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
|
|||
StackFrame _currentFrame;
|
||||
|
||||
KernelSsaGraphBuilder(
|
||||
this.targetElement,
|
||||
this.initialTargetElement,
|
||||
InterfaceType instanceType,
|
||||
this.compiler,
|
||||
this._elementMap,
|
||||
|
@ -136,7 +138,8 @@ class KernelSsaGraphBuilder extends ir.Visitor
|
|||
this.closureDataLookup,
|
||||
this.nativeEmitter,
|
||||
this._sourceInformationStrategy)
|
||||
: _infoReporter = compiler.dumpInfoTask {
|
||||
: this.targetElement = _effectiveTargetElementFor(initialTargetElement),
|
||||
_infoReporter = compiler.dumpInfoTask {
|
||||
_enterFrame(targetElement);
|
||||
this.loopHandler = new KernelLoopHandler(this);
|
||||
typeBuilder = new KernelTypeBuilder(this, _elementMap, _globalLocalsMap);
|
||||
|
@ -157,6 +160,11 @@ class KernelSsaGraphBuilder extends ir.Visitor
|
|||
SourceInformationBuilder get _sourceInformationBuilder =>
|
||||
_currentFrame.sourceInformationBuilder;
|
||||
|
||||
static MemberEntity _effectiveTargetElementFor(MemberEntity member) {
|
||||
if (member is JGeneratorBody) return member.function;
|
||||
return member;
|
||||
}
|
||||
|
||||
void _enterFrame(MemberEntity member) {
|
||||
AsyncMarker asyncMarker = AsyncMarker.SYNC;
|
||||
ir.FunctionNode function = getFunctionNode(_elementMap, member);
|
||||
|
@ -183,7 +191,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
|
|||
// TODO(het): no reason to do this here...
|
||||
HInstruction.idCounter = 0;
|
||||
MemberDefinition definition =
|
||||
_elementMap.getMemberDefinition(targetElement);
|
||||
_elementMap.getMemberDefinition(initialTargetElement);
|
||||
|
||||
switch (definition.kind) {
|
||||
case MemberKind.regular:
|
||||
|
@ -247,6 +255,10 @@ class KernelSsaGraphBuilder extends ir.Visitor
|
|||
}
|
||||
buildMethodSignature(originalClosureNode);
|
||||
break;
|
||||
case MemberKind.generatorBody:
|
||||
buildGeneratorBody(
|
||||
initialTargetElement, _functionNodeOf(definition.node));
|
||||
break;
|
||||
}
|
||||
assert(graph.isValid());
|
||||
|
||||
|
@ -269,6 +281,13 @@ class KernelSsaGraphBuilder extends ir.Visitor
|
|||
});
|
||||
}
|
||||
|
||||
ir.FunctionNode _functionNodeOf(ir.TreeNode node) {
|
||||
if (node is ir.Member) return node.function;
|
||||
if (node is ir.FunctionDeclaration) return node.function;
|
||||
if (node is ir.FunctionExpression) return node.function;
|
||||
return null;
|
||||
}
|
||||
|
||||
ir.FunctionNode _ensureDefaultArgumentValues(ir.FunctionNode function) {
|
||||
// Register all [function]'s default argument values.
|
||||
//
|
||||
|
@ -386,8 +405,8 @@ class KernelSsaGraphBuilder extends ir.Visitor
|
|||
// Unused, so bind to `dynamic`.
|
||||
param = graph.addConstantNull(closedWorld);
|
||||
}
|
||||
localsHandler.directLocals[
|
||||
localsHandler.getTypeVariableAsLocal(typeVariableType)] = param;
|
||||
Local local = localsHandler.getTypeVariableAsLocal(typeVariableType);
|
||||
localsHandler.directLocals[local] = param;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -414,11 +433,14 @@ class KernelSsaGraphBuilder extends ir.Visitor
|
|||
// Unused, so bind to `dynamic`.
|
||||
param = graph.addConstantNull(closedWorld);
|
||||
}
|
||||
localsHandler.directLocals[
|
||||
localsHandler.getTypeVariableAsLocal(typeVariableType)] = param;
|
||||
Local local = localsHandler.getTypeVariableAsLocal(typeVariableType);
|
||||
localsHandler.directLocals[local] = param;
|
||||
functionTypeParameterLocals.add(local);
|
||||
});
|
||||
}
|
||||
|
||||
List<Local> functionTypeParameterLocals = <Local>[];
|
||||
|
||||
/// Builds a generative constructor.
|
||||
///
|
||||
/// Generative constructors are built in stages, in effect inlining the
|
||||
|
@ -622,7 +644,6 @@ class KernelSsaGraphBuilder extends ir.Visitor
|
|||
|
||||
void _invokeConstructorBody(ir.Constructor constructor,
|
||||
List<HInstruction> inputs, SourceInformation sourceInformation) {
|
||||
// TODO(sra): Inline the constructor body.
|
||||
MemberEntity constructorBody = _elementMap.getConstructorBody(constructor);
|
||||
HInvokeConstructorBody invoke = new HInvokeConstructorBody(
|
||||
constructorBody, inputs, commonMasks.nonNullType, sourceInformation);
|
||||
|
@ -941,6 +962,11 @@ class KernelSsaGraphBuilder extends ir.Visitor
|
|||
/// Procedures.
|
||||
void buildFunctionNode(
|
||||
FunctionEntity function, ir.FunctionNode functionNode) {
|
||||
if (functionNode.asyncMarker != ir.AsyncMarker.Sync) {
|
||||
buildGenerator(function, functionNode);
|
||||
return;
|
||||
}
|
||||
|
||||
openFunction(function, functionNode);
|
||||
|
||||
// If [functionNode] is `operator==` we explicitly add a null check at the
|
||||
|
@ -968,6 +994,76 @@ class KernelSsaGraphBuilder extends ir.Visitor
|
|||
closeFunction();
|
||||
}
|
||||
|
||||
/// Builds a SSA graph for a sync*/async/async* generator.
|
||||
void buildGenerator(FunctionEntity function, ir.FunctionNode functionNode) {
|
||||
// TODO(sra): Optimize by generating a merged entry + body when (1) there
|
||||
// are no checks in the entry and (2) the element type is simple.
|
||||
if (true == true) {
|
||||
buildGeneratorEntry(function, functionNode);
|
||||
} else {
|
||||
openFunction(function, functionNode);
|
||||
functionNode.body.accept(this);
|
||||
closeFunction();
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a SSA graph for a sync*/async/async* generator body.
|
||||
void buildGeneratorEntry(
|
||||
FunctionEntity function, ir.FunctionNode functionNode) {
|
||||
graph.isGeneratorEntry = true;
|
||||
|
||||
// TODO(sra): Omit entry checks.
|
||||
openFunction(function, functionNode);
|
||||
|
||||
// Generate type argument for generator class.
|
||||
|
||||
// Tail-call body.
|
||||
JGeneratorBody body = _elementMap.getGeneratorBody(function);
|
||||
// Is 'buildAsyncBody' the best location for the entry?
|
||||
var sourceInformation = _sourceInformationBuilder.buildAsyncBody();
|
||||
|
||||
// Forward all the parameters.
|
||||
List<HInstruction> inputs = <HInstruction>[];
|
||||
if (graph.thisInstruction != null) {
|
||||
inputs.add(graph.thisInstruction);
|
||||
}
|
||||
if (graph.explicitReceiverParameter != null) {
|
||||
inputs.add(graph.explicitReceiverParameter);
|
||||
}
|
||||
for (Local local in parameters.keys) {
|
||||
inputs.add(localsHandler.readLocal(local));
|
||||
}
|
||||
for (Local local in functionTypeParameterLocals) {
|
||||
inputs.add(localsHandler.readLocal(local));
|
||||
}
|
||||
|
||||
// Add the type parameter for the generator's element type.
|
||||
DartType elementType = _elementMap.elementEnvironment
|
||||
.getAsyncOrSyncStarElementType(function.asyncMarker, _returnType);
|
||||
inputs.add(typeBuilder.analyzeTypeArgument(elementType, function));
|
||||
|
||||
push(new HInvokeGeneratorBody(
|
||||
body,
|
||||
inputs,
|
||||
commonMasks.dynamicType, // TODO: better type.
|
||||
sourceInformation));
|
||||
|
||||
closeAndGotoExit(
|
||||
new HReturn(abstractValueDomain, pop(), sourceInformation));
|
||||
|
||||
closeFunction();
|
||||
}
|
||||
|
||||
/// Builds a SSA graph for a sync*/async/async* generator body.
|
||||
void buildGeneratorBody(
|
||||
JGeneratorBody function, ir.FunctionNode functionNode) {
|
||||
// TODO(sra): Omit entry checks.
|
||||
FunctionEntity entry = function.function;
|
||||
openFunction(entry, functionNode);
|
||||
functionNode.body.accept(this);
|
||||
closeFunction();
|
||||
}
|
||||
|
||||
void _potentiallyAddFunctionParameterTypeChecks(ir.FunctionNode function) {
|
||||
// Put the type checks in the first successor of the entry,
|
||||
// because that is where the type guards will also be inserted.
|
||||
|
|
|
@ -23,6 +23,7 @@ import '../js_backend/native_data.dart';
|
|||
import '../js_backend/namer.dart';
|
||||
import '../js_backend/runtime_types.dart';
|
||||
import '../js_emitter/code_emitter_task.dart';
|
||||
import '../js_model/elements.dart' show JGeneratorBody;
|
||||
import '../native/native.dart' as native;
|
||||
import '../options.dart';
|
||||
import '../types/abstract_value_domain.dart';
|
||||
|
@ -47,20 +48,24 @@ class SsaCodeGeneratorTask extends CompilerTask {
|
|||
|
||||
String get name => 'SSA code generator';
|
||||
|
||||
js.Fun buildJavaScriptFunction(
|
||||
FunctionEntity element, List<js.Parameter> parameters, js.Block body) {
|
||||
js.AsyncModifier asyncModifier = element.asyncMarker.isAsync
|
||||
js.Fun buildJavaScriptFunction(bool isGeneratorEntry, FunctionEntity element,
|
||||
List<js.Parameter> parameters, js.Block body) {
|
||||
js.Fun finish(js.AsyncModifier asyncModifier) {
|
||||
return new js.Fun(parameters, body, asyncModifier: asyncModifier)
|
||||
.withSourceInformation(sourceInformationFactory
|
||||
.createBuilderForContext(element)
|
||||
.buildDeclaration(element));
|
||||
}
|
||||
|
||||
if (isGeneratorEntry) return finish(const js.AsyncModifier.sync());
|
||||
|
||||
return finish(element.asyncMarker.isAsync
|
||||
? (element.asyncMarker.isYielding
|
||||
? const js.AsyncModifier.asyncStar()
|
||||
: const js.AsyncModifier.async())
|
||||
: (element.asyncMarker.isYielding
|
||||
? const js.AsyncModifier.syncStar()
|
||||
: const js.AsyncModifier.sync());
|
||||
|
||||
return new js.Fun(parameters, body, asyncModifier: asyncModifier)
|
||||
.withSourceInformation(sourceInformationFactory
|
||||
.createBuilderForContext(element)
|
||||
.buildDeclaration(element));
|
||||
: const js.AsyncModifier.sync()));
|
||||
}
|
||||
|
||||
js.Expression generateCode(
|
||||
|
@ -118,8 +123,8 @@ class SsaCodeGeneratorTask extends CompilerTask {
|
|||
work);
|
||||
codegen.visitGraph(graph);
|
||||
backend.tracer.traceGraph("codegen", graph);
|
||||
return buildJavaScriptFunction(
|
||||
work.element, codegen.parameters, codegen.body);
|
||||
return buildJavaScriptFunction(graph.isGeneratorEntry, work.element,
|
||||
codegen.parameters, codegen.body);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1782,6 +1787,27 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
|
|||
node.element, new CallStructure.unnamed(arguments.length)));
|
||||
}
|
||||
|
||||
void visitInvokeGeneratorBody(HInvokeGeneratorBody node) {
|
||||
JGeneratorBody element = node.element;
|
||||
if (element.isInstanceMember) {
|
||||
use(node.inputs[0]);
|
||||
js.Expression object = pop();
|
||||
List<js.Expression> arguments = visitArguments(node.inputs);
|
||||
js.Name methodName = _namer.instanceMethodName(element);
|
||||
push(js
|
||||
.propertyCall(object, methodName, arguments)
|
||||
.withSourceInformation(node.sourceInformation));
|
||||
} else {
|
||||
push(_emitter.staticFunctionAccess(element));
|
||||
List<js.Expression> arguments = visitArguments(node.inputs, start: 0);
|
||||
push(new js.Call(pop(), arguments,
|
||||
sourceInformation: node.sourceInformation));
|
||||
}
|
||||
|
||||
_registry
|
||||
.registerStaticUse(new StaticUse.generatorBodyInvoke(node.element));
|
||||
}
|
||||
|
||||
void visitOneShotInterceptor(HOneShotInterceptor node) {
|
||||
List<js.Expression> arguments = visitArguments(node.inputs);
|
||||
var isolate = new js.VariableUse(
|
||||
|
|
|
@ -60,6 +60,7 @@ abstract class HVisitor<R> {
|
|||
R visitInvokeStatic(HInvokeStatic node);
|
||||
R visitInvokeSuper(HInvokeSuper node);
|
||||
R visitInvokeConstructorBody(HInvokeConstructorBody node);
|
||||
R visitInvokeGeneratorBody(HInvokeGeneratorBody node);
|
||||
R visitIs(HIs node);
|
||||
R visitIsViaInterceptor(HIsViaInterceptor node);
|
||||
R visitLazyStatic(HLazyStatic node);
|
||||
|
@ -206,10 +207,15 @@ class HGraph {
|
|||
HBasicBlock exit;
|
||||
HThis thisInstruction;
|
||||
|
||||
/// `true` if a sync*/async/async* method is split into an entry and a body
|
||||
/// and this graph is for the entry, which should not be rewritten.
|
||||
bool isGeneratorEntry = false;
|
||||
|
||||
/// Receiver parameter, set for methods using interceptor calling convention.
|
||||
HParameterValue explicitReceiverParameter;
|
||||
bool isRecursiveMethod = false;
|
||||
bool calledInLoop = false;
|
||||
|
||||
final List<HBasicBlock> blocks = <HBasicBlock>[];
|
||||
|
||||
/// Nodes containing list allocations for which there is a known fixed length.
|
||||
|
@ -414,6 +420,8 @@ class HBaseVisitor extends HGraphVisitor implements HVisitor {
|
|||
visitInvokeClosure(HInvokeClosure node) => visitInvokeDynamic(node);
|
||||
visitInvokeConstructorBody(HInvokeConstructorBody node) =>
|
||||
visitInvokeStatic(node);
|
||||
visitInvokeGeneratorBody(HInvokeGeneratorBody node) =>
|
||||
visitInvokeStatic(node);
|
||||
visitInvokeDynamicMethod(HInvokeDynamicMethod node) =>
|
||||
visitInvokeDynamic(node);
|
||||
visitInvokeDynamicGetter(HInvokeDynamicGetter node) =>
|
||||
|
@ -1821,6 +1829,25 @@ class HInvokeConstructorBody extends HInvokeStatic {
|
|||
accept(HVisitor visitor) => visitor.visitInvokeConstructorBody(this);
|
||||
}
|
||||
|
||||
class HInvokeGeneratorBody extends HInvokeStatic {
|
||||
// Directly call the JGeneratorBody method. The generator body can be a static
|
||||
// method or a member. The target is directly called.
|
||||
// The 'inputs' are
|
||||
// [arg1, ..., argN] or
|
||||
// [receiver, arg1, ..., argN] or
|
||||
// [interceptor, receiver, arg1, ... argN].
|
||||
// The 'inputs' may or may not have an additional type argument used for
|
||||
// creating the generator (T for new Completer<T>() inside the body).
|
||||
HInvokeGeneratorBody(FunctionEntity element, List<HInstruction> inputs,
|
||||
AbstractValue type, SourceInformation sourceInformation)
|
||||
: super(element, inputs, type, const <DartType>[]) {
|
||||
this.sourceInformation = sourceInformation;
|
||||
}
|
||||
|
||||
String toString() => 'HInvokeGeneratorBody(${element.name})';
|
||||
accept(HVisitor visitor) => visitor.visitInvokeGeneratorBody(this);
|
||||
}
|
||||
|
||||
abstract class HFieldAccess extends HInstruction {
|
||||
final FieldEntity element;
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ class SsaFunctionCompiler implements FunctionCompiler {
|
|||
optimizer.optimize(work, graph, closedWorld);
|
||||
MemberEntity element = work.element;
|
||||
js.Expression result = generator.generateCode(work, graph, closedWorld);
|
||||
if (element is FunctionEntity) {
|
||||
if (element is FunctionEntity && !graph.isGeneratorEntry) {
|
||||
SourceInformationBuilder sourceInformationBuilder =
|
||||
backend.sourceInformationStrategy.createBuilderForContext(element);
|
||||
result = backend.rewriteAsync(
|
||||
|
|
|
@ -350,6 +350,11 @@ class HInstructionStringifier implements HVisitor<String> {
|
|||
return handleGenericInvoke("InvokeConstructorBody", target, invoke.inputs);
|
||||
}
|
||||
|
||||
String visitInvokeGeneratorBody(HInvokeGeneratorBody invoke) {
|
||||
String target = invoke.element.name;
|
||||
return handleGenericInvoke("InvokeGeneratorBody", target, invoke.inputs);
|
||||
}
|
||||
|
||||
String visitForeignCode(HForeignCode node) {
|
||||
var template = node.codeTemplate;
|
||||
String code = '${template.ast}';
|
||||
|
|
|
@ -305,6 +305,12 @@ class StaticUse {
|
|||
callStructure: callStructure);
|
||||
}
|
||||
|
||||
/// Direct invocation of a generator (body) [element], as a static call or
|
||||
/// through a this or super constructor call.
|
||||
factory StaticUse.generatorBodyInvoke(FunctionEntity element) {
|
||||
return new StaticUse.internal(element, StaticUseKind.INVOKE);
|
||||
}
|
||||
|
||||
/// Direct invocation of a method [element] with the given [callStructure].
|
||||
factory StaticUse.directInvoke(FunctionEntity element,
|
||||
CallStructure callStructure, List<DartType> typeArguments) {
|
||||
|
|
|
@ -31,7 +31,7 @@ void testAsyncTransform(String source, String expected) {
|
|||
asyncReturn: new VariableUse("returnHelper"),
|
||||
asyncRethrow: new VariableUse("rethrowHelper"),
|
||||
completerFactory: new VariableUse("NewCompleter"),
|
||||
completerFactoryTypeArgument: new VariableUse("CompleterType"),
|
||||
completerFactoryTypeArguments: [new VariableUse("CompleterType")],
|
||||
wrapBody: new VariableUse("_wrapJsFunctionForAsync"),
|
||||
safeVariableName: (String name) => "__$name",
|
||||
bodyName: new StringBackedName("body")));
|
||||
|
@ -44,7 +44,7 @@ void testSyncStarTransform(String source, String expected) {
|
|||
new SyncStarRewriter(null, null,
|
||||
endOfIteration: new VariableUse("endOfIteration"),
|
||||
iterableFactory: new VariableUse("NewIterable"),
|
||||
iterableFactoryTypeArgument: new VariableUse("IterableType"),
|
||||
iterableFactoryTypeArguments: [new VariableUse("IterableType")],
|
||||
yieldStarExpression: new VariableUse("yieldStar"),
|
||||
uncaughtErrorExpression: new VariableUse("uncaughtError"),
|
||||
safeVariableName: (String name) => "__$name",
|
||||
|
|
|
@ -10,6 +10,6 @@ main() {
|
|||
}
|
||||
|
||||
@NoInline()
|
||||
test() async /*2:test*/ {
|
||||
/*3:test*/ throw '>ExceptionMarker<';
|
||||
test() async /*2:test*/ /*kernel.3:test*/ {
|
||||
/*4:test*/ throw '>ExceptionMarker<';
|
||||
}
|
||||
|
|
|
@ -10,12 +10,12 @@ main() {
|
|||
}
|
||||
|
||||
@NoInline()
|
||||
test1() async /*2:test1*/ {
|
||||
test1() async /*3:test1*/ /*kernel.4:test1*/ {
|
||||
// This call is on the stack when the error is thrown.
|
||||
await /*3:test1*/ test2();
|
||||
await /*5:test1*/ test2();
|
||||
}
|
||||
|
||||
@NoInline()
|
||||
test2() async /*4:test2*/ {
|
||||
/*5:test2*/ throw '>ExceptionMarker<';
|
||||
test2() async /*7:test2*/ /*kernel.8:test2*/ {
|
||||
/*9:test2*/ throw '>ExceptionMarker<';
|
||||
}
|
||||
|
|
|
@ -12,12 +12,12 @@ test() async {
|
|||
// TODO(johnniwinther): Investigate why kernel doesn't point to the body
|
||||
// start brace.
|
||||
// ignore: UNUSED_LOCAL_VARIABLE
|
||||
var /*2:test*/ c = new /*3:test*/ Class();
|
||||
var /*2:test*/ /*3:test*/ c = new /*4:test*/ Class();
|
||||
}
|
||||
|
||||
class Class {
|
||||
@NoInline()
|
||||
/*4:Class*/ Class() {
|
||||
/*5:Class*/ throw '>ExceptionMarker<';
|
||||
/*5:Class*/ Class() {
|
||||
/*6:Class*/ throw '>ExceptionMarker<';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,11 +9,11 @@ main() {
|
|||
}
|
||||
|
||||
@NoInline()
|
||||
test1() async /*2:test1*/ {
|
||||
/*3:test1*/ test2();
|
||||
test1() async /*2:test1*/ /*kernel.3:test1*/ {
|
||||
/*9:test1*/ test2();
|
||||
}
|
||||
|
||||
@NoInline()
|
||||
test2() {
|
||||
/*4:test2*/ throw '>ExceptionMarker<';
|
||||
/*10:test2*/ throw '>ExceptionMarker<';
|
||||
}
|
||||
|
|
|
@ -12,5 +12,5 @@ main() {
|
|||
@NoInline()
|
||||
test() async {
|
||||
await null;
|
||||
/*1:test*/ throw '>ExceptionMarker<';
|
||||
/*9:test*/ throw '>ExceptionMarker<';
|
||||
}
|
||||
|
|
|
@ -222,7 +222,6 @@ uri_test: RuntimeError
|
|||
[ $compiler == dart2js && $fasta ]
|
||||
int_from_environment_test: Pass # Issue 31762
|
||||
int_parse_radix_test/none: Pass # Issue 31762
|
||||
map_entry_test: RuntimeError
|
||||
|
||||
[ $compiler == dart2js && $fasta && $host_checked && $strong ]
|
||||
cast_test: RuntimeError
|
||||
|
|
|
@ -511,17 +511,11 @@ type_parameter_test/09: Crash # Internal Error: Unexpected type variable in stat
|
|||
type_variable_scope_test/03: Crash # Internal Error: Unexpected type variable in static context.
|
||||
|
||||
[ $compiler == dart2js && !$checked ]
|
||||
async_covariant_type_test: RuntimeError # checked / strong mode test
|
||||
async_dcall_type_test: RuntimeError # checked / strong mode test
|
||||
asyncstar_covariant_type_test: RuntimeError # checked / strong mode test
|
||||
asyncstar_dcall_type_test: RuntimeError # checked / strong mode test
|
||||
covariance_field_test/01: RuntimeError
|
||||
covariance_field_test/02: RuntimeError
|
||||
covariance_field_test/03: RuntimeError
|
||||
covariance_field_test/04: RuntimeError
|
||||
covariance_field_test/05: RuntimeError
|
||||
syncstar_covariant_type_test: RuntimeError # checked / strong mode test
|
||||
syncstar_dcall_type_test: RuntimeError # checked / strong mode test
|
||||
|
||||
[ $compiler == dart2js && !$checked && !$enable_asserts ]
|
||||
assertion_test: RuntimeError, OK
|
||||
|
@ -1057,7 +1051,6 @@ function_subtype_not1_test: RuntimeError
|
|||
function_subtype_setter0_test: RuntimeError
|
||||
function_type_alias2_test: RuntimeError
|
||||
function_type_alias4_test: RuntimeError
|
||||
generic_async_star_test: RuntimeError
|
||||
generic_closure_test/01: RuntimeError
|
||||
generic_closure_test/none: RuntimeError
|
||||
generic_function_bounds_test: RuntimeError
|
||||
|
@ -1610,7 +1603,6 @@ function_subtype_not1_test: RuntimeError
|
|||
function_subtype_setter0_test: RuntimeError
|
||||
function_type_alias2_test: RuntimeError
|
||||
function_type_alias4_test: RuntimeError
|
||||
generic_async_star_test: RuntimeError
|
||||
generic_function_bounds_test: RuntimeError
|
||||
generic_function_dcall_test: RuntimeError
|
||||
generic_function_type_as_type_argument_test/01: MissingCompileTimeError
|
||||
|
|
Loading…
Reference in a new issue