| Index: pkg/compiler/lib/src/ssa/builder.dart
|
| diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
|
| index 93de3b9d117507622aecfa3857dde2f0f6db1ada..38a47424bde247df22b3fb40e1c96183d0c9e892 100644
|
| --- a/pkg/compiler/lib/src/ssa/builder.dart
|
| +++ b/pkg/compiler/lib/src/ssa/builder.dart
|
| @@ -1518,12 +1518,6 @@ class SsaBuilder extends NewResolvedVisitor {
|
| return graph.addConstant(getConstantForNode(node), compiler);
|
| }
|
|
|
| - bool isLazilyInitialized(VariableElement element) {
|
| - ConstantExpression initialValue =
|
| - backend.constants.getConstantForVariable(element);
|
| - return initialValue == null;
|
| - }
|
| -
|
| TypeMask cachedTypeOfThis;
|
|
|
| TypeMask getTypeOfThis() {
|
| @@ -3245,95 +3239,122 @@ class SsaBuilder extends NewResolvedVisitor {
|
| }
|
| }
|
|
|
| - void generateGetter(ast.Send send, Element element) {
|
| - if (element != null && element.isForeign(backend)) {
|
| - visitForeignGetter(send);
|
| - } else if (Elements.isStaticOrTopLevelField(element)) {
|
| - ConstantExpression constant;
|
| - if (element.isField && !element.isAssignable) {
|
| + /// Generate read access of an unresolved static or top level entity.
|
| + void generateStaticUnresolvedGet(ast.Send node, Element element) {
|
| + if (element is ErroneousElement) {
|
| + // An erroneous element indicates an unresolved static getter.
|
| + generateThrowNoSuchMethod(
|
| + node,
|
| + noSuchMethodTargetSymbolString(element, 'get'),
|
| + argumentNodes: const Link<ast.Node>());
|
| + } else {
|
| + // This happens when [element] has parse errors.
|
| + assert(invariant(node, element.isErroneous));
|
| + // TODO(ahe): Do something like the above, that is, emit a runtime
|
| + // error.
|
| + stack.add(graph.addConstantNull(compiler));
|
| + }
|
| + }
|
| +
|
| + /// Read a static or top level [field] of constant value.
|
| + void generateStaticConstGet(
|
| + ast.Send node,
|
| + FieldElement field,
|
| + ConstantExpression constant) {
|
| + ConstantValue value = constant.value;
|
| + HConstant instruction;
|
| + // Constants that are referred via a deferred prefix should be referred
|
| + // by reference.
|
| + PrefixElement prefix = compiler.deferredLoadTask
|
| + .deferredPrefixElement(node, elements);
|
| + if (prefix != null) {
|
| + instruction = graph.addDeferredConstant(value, prefix, compiler);
|
| + } else {
|
| + instruction = graph.addConstant(value, compiler);
|
| + }
|
| + stack.add(instruction);
|
| + // The inferrer may have found a better type than the constant
|
| + // handler in the case of lists, because the constant handler
|
| + // does not look at elements in the list.
|
| + TypeMask type =
|
| + TypeMaskFactory.inferredTypeForElement(field, compiler);
|
| + if (!type.containsAll(compiler.world) &&
|
| + !instruction.isConstantNull()) {
|
| + // TODO(13429): The inferrer should know that an element
|
| + // cannot be null.
|
| + instruction.instructionType = type.nonNullable();
|
| + }
|
| + }
|
| +
|
| + /// Read a static or top level [field].
|
| + void generateStaticFieldGet(ast.Send node, FieldElement field) {
|
| + generateIsDeferredLoadedCheckIfNeeded(node);
|
| +
|
| + ConstantExpression constant =
|
| + backend.constants.getConstantForVariable(field);
|
| + if (constant != null) {
|
| + if (!field.isAssignable) {
|
| // A static final or const. Get its constant value and inline it if
|
| // the value can be compiled eagerly.
|
| - constant = backend.constants.getConstantForVariable(element);
|
| - }
|
| - if (constant != null) {
|
| - ConstantValue value = constant.value;
|
| - HConstant instruction;
|
| - // Constants that are referred via a deferred prefix should be referred
|
| - // by reference.
|
| - PrefixElement prefix = compiler.deferredLoadTask
|
| - .deferredPrefixElement(send, elements);
|
| - if (prefix != null) {
|
| - instruction = graph.addDeferredConstant(value, prefix, compiler);
|
| - } else {
|
| - instruction = graph.addConstant(value, compiler);
|
| - }
|
| - stack.add(instruction);
|
| - // The inferrer may have found a better type than the constant
|
| - // handler in the case of lists, because the constant handler
|
| - // does not look at elements in the list.
|
| - TypeMask type =
|
| - TypeMaskFactory.inferredTypeForElement(element, compiler);
|
| - if (!type.containsAll(compiler.world) &&
|
| - !instruction.isConstantNull()) {
|
| - // TODO(13429): The inferrer should know that an element
|
| - // cannot be null.
|
| - instruction.instructionType = type.nonNullable();
|
| - }
|
| - } else if (element.isField && isLazilyInitialized(element)) {
|
| - HInstruction instruction = new HLazyStatic(
|
| - element,
|
| - TypeMaskFactory.inferredTypeForElement(element, compiler));
|
| - push(instruction);
|
| + generateStaticConstGet(node, field, constant);
|
| } else {
|
| - if (element.isGetter) {
|
| - pushInvokeStatic(send, element, <HInstruction>[]);
|
| - } else {
|
| - // TODO(5346): Try to avoid the need for calling [declaration] before
|
| - // creating an [HStatic].
|
| - HInstruction instruction = new HStatic(
|
| - element.declaration,
|
| - TypeMaskFactory.inferredTypeForElement(element, compiler));
|
| - push(instruction);
|
| - }
|
| - }
|
| - } else if (Elements.isInstanceSend(send, elements)) {
|
| - HInstruction receiver = generateInstanceSendReceiver(send);
|
| - generateInstanceGetterWithCompiledReceiver(
|
| - send, elements.getSelector(send), receiver);
|
| - } else if (Elements.isStaticOrTopLevelFunction(element)) {
|
| - // TODO(5346): Try to avoid the need for calling [declaration] before
|
| - // creating an [HStatic].
|
| - push(new HStatic(element.declaration, backend.nonNullType));
|
| - // TODO(ahe): This should be registered in codegen.
|
| - registry.registerGetOfStaticFunction(element.declaration);
|
| - } else if (Elements.isErroneous(element)) {
|
| - if (element is ErroneousElement) {
|
| - // An erroneous element indicates an unresolved static getter.
|
| - generateThrowNoSuchMethod(
|
| - send,
|
| - noSuchMethodTargetSymbolString(element, 'get'),
|
| - argumentNodes: const Link<ast.Node>());
|
| - } else {
|
| - // TODO(ahe): Do something like the above, that is, emit a runtime
|
| - // error.
|
| - stack.add(graph.addConstantNull(compiler));
|
| + // TODO(5346): Try to avoid the need for calling [declaration] before
|
| + // creating an [HStatic].
|
| + HInstruction instruction = new HStatic(
|
| + field.declaration,
|
| + TypeMaskFactory.inferredTypeForElement(field, compiler));
|
| + push(instruction);
|
| }
|
| } else {
|
| - if (send.asSendSet() == null) {
|
| - internalError(send, "Unhandled local: $element");
|
| - }
|
| - // TODO(johnniwinther): Remove this when [generateGetter] is no longer
|
| - // called from [visitSendSet] (for compound assignments).
|
| - handleLocalGet(element);
|
| + HInstruction instruction = new HLazyStatic(
|
| + field,
|
| + TypeMaskFactory.inferredTypeForElement(field, compiler));
|
| + push(instruction);
|
| + }
|
| + }
|
| +
|
| + /// Generate a getter invocation of the static or top level [getter].
|
| + void generateStaticGetterGet(ast.Send node, MethodElement getter) {
|
| + if (getter.isDeferredLoaderGetter) {
|
| + generateDeferredLoaderGet(node, getter);
|
| + } else {
|
| + generateIsDeferredLoadedCheckIfNeeded(node);
|
| + pushInvokeStatic(node, getter, <HInstruction>[]);
|
| }
|
| }
|
|
|
| + /// Generate a dynamic getter invocation.
|
| + void generateDynamicGet(ast.Send node) {
|
| + HInstruction receiver = generateInstanceSendReceiver(node);
|
| + generateInstanceGetterWithCompiledReceiver(
|
| + node, elements.getSelector(node), receiver);
|
| + }
|
| +
|
| + /// Generate a closurization of the static or top level [function].
|
| + void generateStaticFunctionGet(ast.Send node, MethodElement function) {
|
| + generateIsDeferredLoadedCheckIfNeeded(node);
|
| + // TODO(5346): Try to avoid the need for calling [declaration] before
|
| + // creating an [HStatic].
|
| + push(new HStatic(function.declaration, backend.nonNullType));
|
| + // TODO(ahe): This should be registered in codegen.
|
| + registry.registerGetOfStaticFunction(function.declaration);
|
| + }
|
| +
|
| /// Read a local variable, function or parameter.
|
| void handleLocalGet(LocalElement local) {
|
| stack.add(localsHandler.readLocal(local));
|
| }
|
|
|
| @override
|
| + void visitDynamicPropertyGet(
|
| + ast.Send node,
|
| + ast.Node receiver,
|
| + Selector selector,
|
| + _) {
|
| + generateDynamicGet(node);
|
| + }
|
| +
|
| + @override
|
| void visitLocalVariableGet(ast.Send node, LocalVariableElement variable, _) {
|
| handleLocalGet(variable);
|
| }
|
| @@ -3348,6 +3369,62 @@ class SsaBuilder extends NewResolvedVisitor {
|
| handleLocalGet(function);
|
| }
|
|
|
| + @override
|
| + void visitStaticFieldGet(
|
| + ast.Send node,
|
| + FieldElement field,
|
| + _) {
|
| + generateStaticFieldGet(node, field);
|
| + }
|
| +
|
| + @override
|
| + void visitStaticFunctionGet(
|
| + ast.Send node,
|
| + MethodElement function,
|
| + _) {
|
| + generateStaticFunctionGet(node, function);
|
| + }
|
| +
|
| + @override
|
| + void visitStaticGetterGet(
|
| + ast.Send node,
|
| + FunctionElement getter,
|
| + _) {
|
| + generateStaticGetterGet(node, getter);
|
| + }
|
| +
|
| + @override
|
| + void visitThisPropertyGet(
|
| + ast.Send node,
|
| + Selector selector,
|
| + _) {
|
| + generateDynamicGet(node);
|
| + }
|
| +
|
| + @override
|
| + void visitTopLevelFieldGet(
|
| + ast.Send node,
|
| + FieldElement field,
|
| + _) {
|
| + generateStaticFieldGet(node, field);
|
| + }
|
| +
|
| + @override
|
| + void visitTopLevelFunctionGet(
|
| + ast.Send node,
|
| + MethodElement function,
|
| + _) {
|
| + generateStaticFunctionGet(node, function);
|
| + }
|
| +
|
| + @override
|
| + void visitTopLevelGetterGet(
|
| + ast.Send node,
|
| + FunctionElement getter,
|
| + _) {
|
| + generateStaticGetterGet(node, getter);
|
| + }
|
| +
|
| void generateInstanceSetterWithCompiledReceiver(ast.Send send,
|
| HInstruction receiver,
|
| HInstruction value,
|
| @@ -4014,9 +4091,8 @@ class SsaBuilder extends NewResolvedVisitor {
|
| <HInstruction>[]));
|
| }
|
|
|
| - visitForeignSend(ast.Send node) {
|
| - Selector selector = elements.getSelector(node);
|
| - String name = selector.name;
|
| + void handleForeignSend(ast.Send node, FunctionElement element) {
|
| + String name = element.name;
|
| if (name == 'JS') {
|
| handleForeignJs(node);
|
| } else if (name == 'JS_CURRENT_ISOLATE_CONTEXT') {
|
| @@ -4091,15 +4167,13 @@ class SsaBuilder extends NewResolvedVisitor {
|
| } else if (name == 'JS_STRING_CONCAT') {
|
| handleJsStringConcat(node);
|
| } else {
|
| - throw "Unknown foreign: ${selector}";
|
| + throw "Unknown foreign: ${element}";
|
| }
|
| }
|
|
|
| - visitForeignGetter(ast.Send node) {
|
| - Element element = elements[node];
|
| + generateDeferredLoaderGet(ast.Send node, FunctionElement deferredLoader) {
|
| // Until now we only handle these as getters.
|
| - invariant(node, element.isDeferredLoaderGetter);
|
| - FunctionElement deferredLoader = element;
|
| + invariant(node, deferredLoader.isDeferredLoaderGetter);
|
| Element loadFunction = compiler.loadLibraryFunction;
|
| PrefixElement prefixElement = deferredLoader.enclosingElement;
|
| String loadId = compiler.deferredLoadTask
|
| @@ -4798,72 +4872,156 @@ class SsaBuilder extends NewResolvedVisitor {
|
| }
|
| assert(invariant(node, node.arguments.tail.isEmpty,
|
| message: "Invalid assertion: $node"));
|
| - buildStaticFunctionInvoke(
|
| + generateStaticFunctionInvoke(
|
| node, backend.assertMethod, CallStructure.ONE_ARG);
|
| }
|
|
|
| visitStaticSend(ast.Send node) {
|
| - CallStructure callStructure = elements.getSelector(node).callStructure;
|
| - Element element = elements[node];
|
| - if (elements.isAssert(node)) {
|
| - element = backend.assertMethod;
|
| - }
|
| - if (element.isForeign(backend) && element.isFunction) {
|
| - visitForeignSend(node);
|
| - return;
|
| - }
|
| - if (element.isErroneous) {
|
| - if (element is ErroneousElement) {
|
| - // An erroneous element indicates that the funciton could not be
|
| - // resolved (a warning has been issued).
|
| - generateThrowNoSuchMethod(node,
|
| - noSuchMethodTargetSymbolString(element),
|
| - argumentNodes: node.arguments);
|
| - } else {
|
| - // TODO(ahe): Do something like [generateWrongArgumentCountError].
|
| - stack.add(graph.addConstantNull(compiler));
|
| - }
|
| - return;
|
| - }
|
| - invariant(element, !element.isGenerativeConstructor);
|
| - generateIsDeferredLoadedCheckIfNeeded(node);
|
| - if (element.isFunction) {
|
| - // TODO(5347): Try to avoid the need for calling [implementation] before
|
| - // calling [makeStaticArgumentList].
|
| - if (!callStructure.signatureApplies(element.implementation)) {
|
| - generateWrongArgumentCountError(node, element, node.arguments);
|
| - return;
|
| - }
|
| - buildStaticFunctionInvoke(node, element, callStructure);
|
| - } else {
|
| - generateGetter(node, element);
|
| - List<HInstruction> inputs = <HInstruction>[pop()];
|
| - addDynamicSendArgumentsToList(node, inputs);
|
| - Selector closureSelector = callStructure.callSelector;
|
| - pushWithPosition(
|
| - new HInvokeClosure(closureSelector, inputs, backend.dynamicType),
|
| - node);
|
| - }
|
| + internalError(node, "Unexpected visitStaticSend");
|
| }
|
|
|
| - void buildStaticFunctionInvoke(
|
| + /// Generate an invocation to the static or top level [function].
|
| + void generateStaticFunctionInvoke(
|
| ast.Send node,
|
| - FunctionElement element,
|
| + FunctionElement function,
|
| CallStructure callStructure) {
|
| List<HInstruction> inputs = makeStaticArgumentList(
|
| callStructure,
|
| node.arguments,
|
| - element.implementation);
|
| + function.implementation);
|
|
|
| - if (element == compiler.identicalFunction) {
|
| + if (function == compiler.identicalFunction) {
|
| pushWithPosition(
|
| new HIdentity(inputs[0], inputs[1], null, backend.boolType), node);
|
| return;
|
| } else {
|
| - pushInvokeStatic(node, element, inputs);
|
| + pushInvokeStatic(node, function, inputs);
|
| + }
|
| + }
|
| +
|
| + /// Generate an invocation to a static or top level function with the wrong
|
| + /// number of arguments.
|
| + void generateStaticFunctionIncompatibleInvoke(ast.Send node,
|
| + Element element) {
|
| + generateWrongArgumentCountError(node, element, node.arguments);
|
| + }
|
| +
|
| + @override
|
| + void visitStaticFieldInvoke(
|
| + ast.Send node,
|
| + FieldElement field,
|
| + ast.NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + generateStaticFieldGet(node, field);
|
| + generateCallInvoke(node, pop());
|
| + }
|
| +
|
| + @override
|
| + void visitStaticFunctionInvoke(
|
| + ast.Send node,
|
| + MethodElement function,
|
| + ast.NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + generateStaticFunctionInvoke(node, function, callStructure);
|
| + }
|
| +
|
| + @override
|
| + void visitStaticFunctionIncompatibleInvoke(
|
| + ast.Send node,
|
| + MethodElement function,
|
| + ast.NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + generateStaticFunctionIncompatibleInvoke(node, function);
|
| + }
|
| +
|
| + @override
|
| + void visitStaticGetterInvoke(
|
| + ast.Send node,
|
| + FunctionElement getter,
|
| + ast.NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + generateStaticGetterGet(node, getter);
|
| + generateCallInvoke(node, pop());
|
| + }
|
| +
|
| + @override
|
| + void visitTopLevelFieldInvoke(
|
| + ast.Send node,
|
| + FieldElement field,
|
| + ast.NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + generateStaticFieldGet(node, field);
|
| + generateCallInvoke(node, pop());
|
| + }
|
| +
|
| + @override
|
| + void visitTopLevelFunctionInvoke(
|
| + ast.Send node,
|
| + MethodElement function,
|
| + ast.NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + if (function.isForeign(backend)) {
|
| + handleForeignSend(node, function);
|
| + } else {
|
| + generateStaticFunctionInvoke(node, function, callStructure);
|
| }
|
| }
|
|
|
| + @override
|
| + void visitTopLevelFunctionIncompatibleInvoke(
|
| + ast.Send node,
|
| + MethodElement function,
|
| + ast.NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + generateStaticFunctionIncompatibleInvoke(node, function);
|
| + }
|
| +
|
| + @override
|
| + void visitTopLevelGetterInvoke(
|
| + ast.Send node,
|
| + FunctionElement getter,
|
| + ast.NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + generateStaticGetterGet(node, getter);
|
| + generateCallInvoke(node, pop());
|
| + }
|
| +
|
| + @override
|
| + void visitUnresolvedGet(
|
| + ast.Send node,
|
| + Element element,
|
| + _) {
|
| + generateStaticUnresolvedGet(node, element);
|
| + }
|
| +
|
| + @override
|
| + void visitUnresolvedInvoke(
|
| + ast.Send node,
|
| + Element element,
|
| + ast.NodeList arguments,
|
| + Selector selector,
|
| + _) {
|
| + if (element is ErroneousElement) {
|
| + // An erroneous element indicates that the funciton could not be
|
| + // resolved (a warning has been issued).
|
| + generateThrowNoSuchMethod(node,
|
| + noSuchMethodTargetSymbolString(element),
|
| + argumentNodes: node.arguments);
|
| + } else {
|
| + // TODO(ahe): Do something like [generateWrongArgumentCountError].
|
| + stack.add(graph.addConstantNull(compiler));
|
| + }
|
| + return;
|
| + }
|
| +
|
| HConstant addConstantString(String string) {
|
| ast.DartString dartString = new ast.DartString.literal(string);
|
| ConstantValue constant = constantSystem.createString(dartString);
|
| @@ -4985,8 +5143,7 @@ class SsaBuilder extends NewResolvedVisitor {
|
| }
|
|
|
| visitGetterSend(ast.Send node) {
|
| - generateIsDeferredLoadedCheckIfNeeded(node);
|
| - generateGetter(node, elements[node]);
|
| + internalError(node, "Unexpected visitGetterSend");
|
| }
|
|
|
| // TODO(antonm): migrate rest of SsaFromAstMixin to internalError.
|
| @@ -5390,8 +5547,18 @@ class SsaBuilder extends NewResolvedVisitor {
|
| receiver = generateInstanceSendReceiver(node);
|
| generateInstanceGetterWithCompiledReceiver(
|
| node, elements.getGetterSelectorInComplexSendSet(node), receiver);
|
| + } else if (getter.isErroneous) {
|
| + generateStaticUnresolvedGet(node, getter);
|
| + } else if (getter.isField) {
|
| + generateStaticFieldGet(node, getter);
|
| + } else if (getter.isGetter) {
|
| + generateStaticGetterGet(node, getter);
|
| + } else if (getter.isFunction) {
|
| + generateStaticFunctionGet(node, getter);
|
| + } else if (getter.isLocal) {
|
| + handleLocalGet(getter);
|
| } else {
|
| - generateGetter(node, getter);
|
| + internalError(node, "Unexpected getter: $getter");
|
| }
|
| HInstruction getterInstruction = pop();
|
| handleComplexOperatorSend(node, getterInstruction, node.arguments);
|
|
|