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

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: Address comments 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..5999c98bdba3525aa0db233f865872ee32f4f99a 100644
--- a/sdk/lib/_internal/compiler/implementation/ir/ir_builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ir/ir_builder.dart
@@ -137,6 +137,14 @@ class IrBuilderTask extends CompilerTask {
}
}
+class _GetterElements {
+ ir.Primitive result;
+ ir.Primitive index;
+ ir.Primitive receiver;
+
+ _GetterElements({this.result, this.index, this.receiver}) ;
+}
+
/**
* A tree visitor that builds [IrNodes]. The visit methods add statements using
* to the [builder] and return the last added statement for trees that represent
@@ -827,6 +835,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 +922,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,66 +954,84 @@ 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) {
- assert(isOpen);
+ _GetterElements translateGetter(ast.Send node, Selector selector) {
Element element = elements[node];
+ ir.Primitive result;
+ ir.Primitive receiver;
+ ir.Primitive index;
- // TODO(asgerf): Generate code for erroneous getter access
if (Elements.isErroneousElement(element)) {
- return giveup(node, 'Erroneous element on GetterSend');
+ giveup(node, 'Erroneous element on GetterSend');
+ return null;
}
- // 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);
- }
-
+ // Reference to constant local, top-level or static field
+
+ result = translateConstant(node);
+ } else if (Elements.isLocal(element)) {
+ // Reference to local variable
+
+ result = lookupLocal(element);
+ } else if (element == null ||
+ Elements.isInstanceField(element) ||
+ Elements.isInstanceMethod(element) ||
+ selector.isIndex ||
+ node.isSuperCall) {
// 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)) {
- ir.Primitive receiver = node.receiver == null
- ? lookupThis()
- : visit(node.receiver);
+ // 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.
+
+ receiver = visitReceiver(node.receiver);
+ List<ir.Primitive> arguments = new List<ir.Primitive>();
+ if (selector.isIndex) {
+ index = visit(node.arguments.head);
+ arguments.add(index);
+ }
+
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, []);
+ assert(selector.kind == SelectorKind.GETTER ||
+ selector.kind == SelectorKind.INDEX);
+ ir.Expression invoke =
+ createDynamicInvoke(node, selector, receiver, k, arguments);
add(new ir.LetCont(k, invoke));
- return v;
- }
+ result = v;
+ } else if (element.isField || element.isGetter ||
+ // Access to a static field or getter (non-static case handled above).
+ // Even if there is only a setter, we compile as if it was a getter,
+ // so the vm can fail at runtime.
- // Access to a static field or getter (non-static case handled above).
- if (element.isField || element.isGetter) {
+ element.isSetter) {
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, []);
+ assert(selector.kind == SelectorKind.GETTER ||
+ selector.kind == SelectorKind.SETTER);
+ ir.Expression invoke =
+ new ir.InvokeStatic(element, selector, k, []);
add(new ir.LetCont(k, invoke));
- return v;
- }
+ result = v;
+ } else if (Elements.isStaticOrTopLevelFunction(element)) {
+ // Convert a top-level or static function to a function object.
- // Convert a top-level or static function to a function object.
- if (Elements.isStaticOrTopLevelFunction(element)) {
- return translateConstant(node);
+ result = translateConstant(node);
+ } else {
+ throw "Unexpected SendSet getter: $node, $element";
}
+ return new _GetterElements(
+ result: result,index: index, receiver: receiver);
+ }
+
+ ir.Primitive visitGetterSend(ast.Send node) {
+ assert(isOpen);
+ return translateGetter(node, elements.getSelector(node)).result;
- throw "Unexpected GetterSend: $node, $element";
}
ir.Primitive buildNegation(ir.Primitive condition) {
@@ -1181,7 +1226,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 +1257,97 @@ 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);
- }
-
- // 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');
+ // 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));
- Selector selector = elements.getOperatorSelectorInComplexSendSet(node);
- getter = lookupLocal(selectorElement);
+ _GetterElements getterResult = translateGetter(node, getterSelector);
+ index = getterResult.index;
+ receiver = getterResult.receiver;
+ originalValue = getterResult.result;
+ // 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 +1421,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