Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(149)

Unified Diff: sdk/lib/_internal/compiler/implementation/ir/ir_builder.dart

Issue 349923004: Add support for superSend to the new IR and dart backend. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Also handle sendSet Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: sdk/lib/_internal/compiler/implementation/ir/ir_builder.dart
diff --git a/sdk/lib/_internal/compiler/implementation/ir/ir_builder.dart b/sdk/lib/_internal/compiler/implementation/ir/ir_builder.dart
index e038212d854ff7303f9edd8fd12b0acc31baa2f5..eaaf7be5458756606815ffe8b7157773a8897cb3 100644
--- a/sdk/lib/_internal/compiler/implementation/ir/ir_builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ir/ir_builder.dart
@@ -827,6 +827,7 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
ir.Primitive visitIdentifier(ast.Identifier node) {
assert(isOpen);
+ // "this" is the only identifier that should be met by the visitor.
assert(node.isThis());
return lookupThis();
}
@@ -913,13 +914,31 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
node.argumentsNode);
}
+ /// If [node] is null, returns this.
+ /// If [node] is super, returns null (for special handling)
+ /// Otherwise visits [node] and returns the result.
+ ir.Primitive visitReceiver(ast.Expression node) {
+ if (node == null) return lookupThis();
+ if (node.isSuper()) return null;
+ return visit(node);
+ }
+
+ /// Makes an [InvokeMethod] unless [node.receiver.isSuper()], in that case
+ /// makes an [InvokeSuperMethod] ignoring [receiver].
+ ir.Expression createDynamicInvoke(ast.Send node,
+ Selector selector,
+ ir.Definition receiver,
+ ir.Continuation k,
+ List<ir.Definition> arguments) {
+ return node.receiver != null && node.receiver.isSuper()
+ ? new ir.InvokeSuperMethod(selector, k, arguments)
+ : new ir.InvokeMethod(receiver, selector, k, arguments);
+ }
+
ir.Primitive visitDynamicSend(ast.Send node) {
assert(isOpen);
- if (node.receiver == null || node.receiver.isSuper()) {
- return giveup(node, 'DynamicSend without receiver, or super receiver');
- }
Selector selector = elements.getSelector(node);
- ir.Primitive receiver = visit(node.receiver);
+ ir.Primitive receiver = visitReceiver(node.receiver);
List<ir.Primitive> arguments = new List<ir.Primitive>();
for (ast.Node n in node.arguments) {
arguments.add(visit(n));
@@ -927,14 +946,16 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
ir.Parameter v = new ir.Parameter(null);
ir.Continuation k = new ir.Continuation([v]);
ir.Expression invoke =
- new ir.InvokeMethod(receiver, selector, k, arguments);
+ createDynamicInvoke(node, selector, receiver, k, arguments);
add(new ir.LetCont(k, invoke));
return v;
}
ir.Primitive visitGetterSend(ast.Send node) {
+ // This code should be kept in sync with the getter part of visitSendSet
assert(isOpen);
Element element = elements[node];
+ Selector selector = elements.getSelector(node);
// TODO(asgerf): Generate code for erroneous getter access
if (Elements.isErroneousElement(element)) {
@@ -958,14 +979,12 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
if (element == null ||
Elements.isInstanceField(element) ||
Elements.isInstanceMethod(element)) {
- ir.Primitive receiver = node.receiver == null
- ? lookupThis()
- : visit(node.receiver);
+ ir.Primitive receiver = visitReceiver(node.receiver);
ir.Parameter v = new ir.Parameter(null);
ir.Continuation k = new ir.Continuation([v]);
- Selector selector = elements.getSelector(node);
assert(selector.kind == SelectorKind.GETTER);
- ir.InvokeMethod invoke = new ir.InvokeMethod(receiver, selector, k, []);
+ ir.Expression invoke =
+ createDynamicInvoke(node, selector, receiver, k, []);
add(new ir.LetCont(k, invoke));
return v;
}
@@ -974,9 +993,8 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
if (element.isField || element.isGetter) {
ir.Parameter v = new ir.Parameter(null);
ir.Continuation k = new ir.Continuation([v]);
- Selector selector = elements.getSelector(node);
- assert(selector.kind == SelectorKind.GETTER);
- ir.InvokeStatic invoke = new ir.InvokeStatic(element, selector, k, []);
+ ir.Expression invoke =
+ new ir.InvokeStatic(element, selector, k, []);
add(new ir.LetCont(k, invoke));
return v;
}
@@ -1181,7 +1199,11 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
ir.Primitive visitSuperSend(ast.Send node) {
assert(isOpen);
- return giveup(node, 'SuperSend');
+ if (node.isPropertyAccess) {
+ return visitGetterSend(node);
+ } else {
+ return visitDynamicSend(node);
+ }
}
ir.Primitive visitTypeReferenceSend(ast.Send node) {
@@ -1208,98 +1230,161 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
assert(isOpen);
Element element = elements[node];
ast.Operator op = node.assignmentOperator;
- ir.Primitive result;
- ir.Primitive getter;
- if (op.source == '=') {
- if (Elements.isLocal(element)) {
- // Exactly one argument expected for a simple assignment.
- assert(!node.arguments.isEmpty);
- assert(node.arguments.tail.isEmpty);
- result = visit(node.arguments.head);
- result.useElementAsHint(element);
- assignedVars[variableIndex[element]] = result;
- return result;
- } else if (Elements.isStaticOrTopLevel(element)) {
- assert(element.isField || element.isSetter);
- assert(!node.arguments.isEmpty && node.arguments.tail.isEmpty);
- ir.Parameter v = new ir.Parameter(null);
- ir.Continuation k = new ir.Continuation([v]);
- Selector selector = elements.getSelector(node);
- ir.Definition arg = visit(node.arguments.head);
- ir.InvokeStatic invoke =
- new ir.InvokeStatic(element, selector, k, [arg]);
- add(new ir.LetCont(k, invoke));
- return arg;
- } else if (node.receiver == null) {
- // Nodes that fall in this case:
- // - Unresolved top-level
- // - Assignment to final variable (will not be resolved)
- return giveup(node, 'SendSet: non-local, non-static, but no receiver');
- } else {
- if (element != null && Elements.isUnresolved(element)) {
- return giveup(node);
+ // For complex operators, this is the result of getting (before assigning)
+ ir.Primitive originalValue;
+ // For []+= style operators, this saves the index.
+ ir.Primitive index;
+ ir.Primitive receiver;
+ // This is what gets assigned.
+ ir.Primitive valueToStore;
+ Selector selector = elements.getSelector(node);
+ Selector operatorSelector =
+ elements.getOperatorSelectorInComplexSendSet(node);
+ Selector getterSelector =
+ elements.getGetterSelectorInComplexSendSet(node);
+ assert(
+ // Indexing send-sets have an argument for the index.
+ (selector.isIndexSet ? 1 : 0) +
+ // Non-increment send-sets have one more argument.
+ (ast.Operator.INCREMENT_OPERATORS.contains(op.source) ? 0 : 1)
+ == node.argumentCount());
+
+ ast.Node assignArg = selector.isIndexSet
+ ? node.arguments.tail.head
+ : node.arguments.head;
+
+ // Get the value into valueToStore
+ if (op.source == "=") {
+ if (selector.isIndexSet) {
+ receiver = visitReceiver(node.receiver);
+ index = visit(node.arguments.head);
+ } else if (element == null || Elements.isInstanceField(element)) {
+ receiver = visitReceiver(node.receiver);
+ }
+ valueToStore = visit(assignArg);
+ } else {
+ // Get the original value into getter
+ assert(ast.Operator.COMPLEX_OPERATORS.contains(op.source));
+
+ // This code should be kept in sync with visitGetterSend
+ // We have to handle index-set specially, to ensure the index only is
+ // computed once - therefore the duplication.
+ ir.Primitive getter() {
asgerf 2014/06/27 08:09:56 As discussed offline, we should look for a way to
sigurdm 2014/06/27 09:20:21 Done.
+ if (Elements.isErroneousElement(element)) {
+ return giveup(node, 'Erroneous element on GetterSend');
}
- // Setter or index-setter invocation
- assert(node.receiver != null);
-
- if (node.receiver.isSuper()) return giveup(node, 'Super SendSet');
-
- ir.Primitive receiver = node.receiver == null
- ? lookupThis()
- : visit(node.receiver);
- ir.Parameter v = new ir.Parameter(null);
- ir.Continuation k = new ir.Continuation([v]);
- Selector selector = elements.getSelector(node);
- assert(selector.kind == SelectorKind.SETTER ||
- selector.kind == SelectorKind.INDEX);
- List<ir.Definition> args = node.arguments.mapToList(visit,
- growable:false);
- ir.InvokeMethod invoke =
- new ir.InvokeMethod(receiver, selector, k, args);
- add(new ir.LetCont(k, invoke));
- return args.last;
- }
- } else if (ast.Operator.COMPLEX_OPERATORS.contains(op.source)) {
- Element selectorElement = elements[node.selector];
- if (selectorElement != null && !selectorElement.isAssignable) {
- return giveup(node, 'Unresolved or non-assignable compound assignment');
- }
- if (!Elements.isLocal(selectorElement)) {
- return giveup(node, 'Non-local compound assignment');
+ // Reference to constant local, top-level or static field
+ if (element != null && element.isConst) {
+ return translateConstant(node);
+ }
+
+ // Reference to local variable
+ if (Elements.isLocal(element)) {
+ return lookupLocal(element);
+ }
+
+ // Dynamic dispatch to a getter. Sometimes resolution will suggest a
+ // target element, but in these cases we must still emit a dynamic
+ // dispatch. The target element may be an instance method in case we are
+ // converting a method to a function object.
+ if (element == null ||
+ Elements.isInstanceField(element) ||
+ Elements.isInstanceMethod(element) ||
+ getterSelector.isIndex ||
+ node.isSuperCall) {
+
+ receiver = visitReceiver(node.receiver);
+ List<ir.Primitive> arguments = new List<ir.Primitive>();
+ if (getterSelector.isIndex) {
+ index = visit(node.arguments.head);
+ arguments.add(index);
+ }
+
+ ir.Parameter v = new ir.Parameter(null);
+ ir.Continuation k = new ir.Continuation([v]);
+ assert(getterSelector.kind == SelectorKind.GETTER ||
+ getterSelector.kind == SelectorKind.INDEX);
+ ir.Expression invoke =
+ createDynamicInvoke(node, getterSelector, receiver, k, arguments);
+ add(new ir.LetCont(k, invoke));
+ return v;
+ }
+
+ // Access to a static field or getter (non-static case handled above).
+ if (element.isField || element.isGetter ||
+ // Even if there is only a setter, we compile as if it was a getter,
+ // so the vm can fail at runtime.
+ element.isSetter) {
+ ir.Parameter v = new ir.Parameter(null);
+ ir.Continuation k = new ir.Continuation([v]);
+ assert(getterSelector.kind == SelectorKind.GETTER);
+ ir.Expression invoke =
+ new ir.InvokeStatic(element, getterSelector, k, []);
+ add(new ir.LetCont(k, invoke));
+ return v;
+ }
+
+ // Convert a top-level or static function to a function object.
+ if (Elements.isStaticOrTopLevelFunction(element)) {
+ return translateConstant(node);
+ }
+
+ throw "Unexpected SendSet getter: $node, $element";
}
- Selector selector = elements.getOperatorSelectorInComplexSendSet(node);
- getter = lookupLocal(selectorElement);
+ originalValue = getter();
+ // Do the modification of the value in getter.
ir.Primitive arg;
if (ast.Operator.INCREMENT_OPERATORS.contains(op.source)) {
- assert(node.arguments.isEmpty);
arg = makePrimConst(constantSystem.createInt(1));
add(new ir.LetPrim(arg));
} else {
- assert(!node.arguments.isEmpty);
- assert(node.arguments.tail.isEmpty);
- arg = visit(node.arguments.head);
+ arg = visit(assignArg);
}
- arg.useElementAsHint(element);
- result = new ir.Parameter(null);
- ir.Continuation k = new ir.Continuation([result]);
- ir.Expression invoke = new ir.InvokeMethod(getter, selector, k, [arg]);
+ valueToStore = new ir.Parameter(null);
+ ir.Continuation k = new ir.Continuation([valueToStore]);
+ ir.Expression invoke =
+ new ir.InvokeMethod(originalValue, operatorSelector, k, [arg]);
add(new ir.LetCont(k, invoke));
+ }
- assignedVars[variableIndex[element]] = result;
-
- if (ast.Operator.INCREMENT_OPERATORS.contains(op.source) &&
- !node.isPrefix) {
- assert(getter != null);
- return getter;
- } else {
- return result;
+ // Set the value
+ if (Elements.isLocal(element)) {
+ valueToStore.useElementAsHint(element);
+ assignedVars[variableIndex[element]] = valueToStore;
+ } else if (Elements.isStaticOrTopLevel(element)) {
+ assert(element.isField || element.isSetter);
+ ir.Parameter v = new ir.Parameter(null);
+ ir.Continuation k = new ir.Continuation([v]);
+ Selector selector = elements.getSelector(node);
+ ir.InvokeStatic invoke =
+ new ir.InvokeStatic(element, selector, k, [valueToStore]);
+ add(new ir.LetCont(k, invoke));
+ } else {
+ if (element != null && Elements.isUnresolved(element)) {
+ return giveup(node, 'SendSet: non-local, non-static, unresolved');
}
+ // Setter or index-setter invocation
+ ir.Parameter v = new ir.Parameter(null);
+ ir.Continuation k = new ir.Continuation([v]);
+ Selector selector = elements.getSelector(node);
+ assert(selector.kind == SelectorKind.SETTER ||
+ selector.kind == SelectorKind.INDEX);
+ List<ir.Definition> arguments = selector.isIndexSet
+ ? [index, valueToStore]
+ : [valueToStore];
+ ir.Expression invoke =
+ createDynamicInvoke(node, selector, receiver, k, arguments);
+ add(new ir.LetCont(k, invoke));
+ }
+
+ if (node.isPostfix) {
+ assert(originalValue != null);
+ return originalValue;
} else {
- compiler.internalError(node, "Unknown assignment operator ${op.source}");
- return null;
+ return valueToStore;
}
}
@@ -1373,8 +1458,10 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
ir.FunctionDefinition nullIfGiveup(ir.FunctionDefinition action()) {
try {
return action();
- } catch(e) {
- if (e == ABORT_IRNODE_BUILDER) return null;
+ } catch(e, tr) {
+ if (e == ABORT_IRNODE_BUILDER) {
+ return null;
+ }
rethrow;
}
}

Powered by Google App Engine
This is Rietveld 408576698