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

Unified Diff: pkg/compiler/lib/src/ssa/builder.dart

Issue 1151163004: Implementation of null-aware operators. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 7 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
« no previous file with comments | « pkg/compiler/lib/src/scanner/utf8_bytes_scanner.dart ('k') | pkg/compiler/lib/src/tree/nodes.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 43ae3058c746f7c62192cf13e459b15c25397a16..42182c94ed847e5bdc6088710733f1ef8df99d9e 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -3142,6 +3142,12 @@ class SsaBuilder extends NewResolvedVisitor {
}
@override
+ void visitIfNull(ast.Send node, ast.Node left, ast.Node right, _) {
+ SsaBranchBuilder brancher = new SsaBranchBuilder(this, node);
+ brancher.handleIfNull(() => visit(left), () => visit(right));
+ }
+
+ @override
void visitLogicalAnd(ast.Send node, ast.Node left, ast.Node right, _) {
SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, node);
branchBuilder.handleLogicalAndOrWithLeftNode(
@@ -3398,6 +3404,36 @@ class SsaBuilder extends NewResolvedVisitor {
}
@override
+ void visitIfNotNullDynamicPropertyGet(
+ ast.Send node,
+ ast.Node receiver,
+ Selector selector,
+ _) {
+ // exp?.x compiled as:
+ // t1 = exp;
+ // result = t1 == null ? t1 : t1.x;
+ // This is equivalent to t1 == null ? null : t1.x, but in the current form
+ // we will be able to later compress it as:
+ // t1 || t1.x
+ HInstruction expression;
+ SsaBranchBuilder brancher = new SsaBranchBuilder(this, node);
+ brancher.handleConditional(
+ () {
+ expression = visitAndPop(receiver);
+ pushCheckNull(expression);
+ },
+ () => stack.add(expression),
+ () => generateInstanceGetterWithCompiledReceiver(
+ node, elements.getSelector(node), expression));
+ }
+
+ /// Pushes a boolean checking [expression] against null.
+ pushCheckNull(HInstruction expression) {
+ push(new HIdentity(expression, graph.addConstantNull(compiler),
+ null, backend.boolType));
+ }
+
+ @override
void visitLocalVariableGet(ast.Send node, LocalVariableElement variable, _) {
handleLocalGet(variable);
}
@@ -3468,6 +3504,37 @@ class SsaBuilder extends NewResolvedVisitor {
generateStaticGetterGet(node, getter);
}
+ void generatePossiblyConditionalInstanceSetter(ast.Send send,
+ HInstruction pushReceiver(),
+ HInstruction pushValue(),
+ {Selector selector,
+ ast.Node location}) {
+ if (send.isConditional) {
+ SsaBranchBuilder brancher = new SsaBranchBuilder(this, send);
+ // compile e?.x = e2 to:
+ //
+ // t1 = e
+ // if (t1 == null)
+ // result = t1 // same as result = null
+ // else
+ // result = e.x = e2
+ HInstruction receiver;
+ brancher.handleConditional(
+ () {
+ receiver = pushReceiver();
+ pushCheckNull(receiver);
+ },
+ () => stack.add(receiver),
+ () => generateInstanceSetterWithCompiledReceiver(
+ send, receiver, pushValue(),
+ selector: selector, location: location));
+ } else {
+ generateInstanceSetterWithCompiledReceiver(
+ send, pushReceiver(), pushValue(),
+ selector: selector, location: location);
+ }
+ }
+
void generateInstanceSetterWithCompiledReceiver(ast.Send send,
HInstruction receiver,
HInstruction value,
@@ -3730,10 +3797,14 @@ class SsaBuilder extends NewResolvedVisitor {
/// Generate a dynamic method, getter or setter invocation.
void generateDynamicSend(ast.Send node) {
+ HInstruction receiver = generateInstanceSendReceiver(node);
+ _generateDynamicSend(node, receiver);
+ }
+
+ void _generateDynamicSend(ast.Send node, HInstruction receiver) {
Selector selector = elements.getSelector(node);
List<HInstruction> inputs = <HInstruction>[];
- HInstruction receiver = generateInstanceSendReceiver(node);
inputs.add(receiver);
addDynamicSendArgumentsToList(node, inputs);
@@ -3755,6 +3826,25 @@ class SsaBuilder extends NewResolvedVisitor {
}
@override
+ visitIfNotNullDynamicPropertyInvoke(
+ ast.Send node,
+ ast.Node receiver,
+ ast.NodeList arguments,
+ Selector selector,
+ _) {
+ /// Desugar `exp?.m()` to `(t1 = exp) == null ? t1 : t1.m()`
+ HInstruction receiver;
+ SsaBranchBuilder brancher = new SsaBranchBuilder(this, node);
+ brancher.handleConditional(
+ () {
+ receiver = generateInstanceSendReceiver(node);
+ pushCheckNull(receiver);
+ },
+ () => stack.add(receiver),
+ () => _generateDynamicSend(node, receiver));
+ }
+
+ @override
visitThisPropertyInvoke(
ast.Send node,
ast.NodeList arguments,
@@ -5505,11 +5595,22 @@ class SsaBuilder extends NewResolvedVisitor {
}
ast.Operator op = node.assignmentOperator;
if (node.isSuperCall) {
- HInstruction result;
List<HInstruction> setterInputs = <HInstruction>[];
+ void generateSuperSendSet() {
+ Selector setterSelector = elements.getSelector(node);
+ if (Elements.isUnresolved(element)
+ || !setterSelector.applies(element, compiler.world)) {
+ generateSuperNoSuchMethodSend(
+ node, setterSelector, setterInputs);
+ pop();
+ } else {
+ add(buildInvokeSuper(setterSelector, element, setterInputs));
+ }
+ }
if (identical(node.assignmentOperator.source, '=')) {
addDynamicSendArgumentsToList(node, setterInputs);
- result = setterInputs.last;
+ generateSuperSendSet();
+ stack.add(setterInputs.last);
} else {
Element getter = elements[node.selector];
List<HInstruction> getterInputs = <HInstruction>[];
@@ -5539,25 +5640,22 @@ class SsaBuilder extends NewResolvedVisitor {
getterSelector, getter, getterInputs);
add(getterInstruction);
}
- handleComplexOperatorSend(node, getterInstruction, arguments);
- setterInputs.add(pop());
- if (node.isPostfix) {
- result = getterInstruction;
+ if (node.isIfNullAssignment) {
+ SsaBranchBuilder brancher = new SsaBranchBuilder(this, node);
+ brancher.handleIfNull(() => stack.add(getterInstruction),
+ () {
+ addDynamicSendArgumentsToList(node, setterInputs);
+ generateSuperSendSet();
+ stack.add(setterInputs.last);
+ });
} else {
- result = setterInputs.last;
+ handleComplexOperatorSend(node, getterInstruction, arguments);
+ setterInputs.add(pop());
+ generateSuperSendSet();
+ stack.add(node.isPostfix ? getterInstruction : setterInputs.last);
}
}
- Selector setterSelector = elements.getSelector(node);
- if (Elements.isUnresolved(element)
- || !setterSelector.applies(element, compiler.world)) {
- generateSuperNoSuchMethodSend(
- node, setterSelector, setterInputs);
- pop();
- } else {
- add(buildInvokeSuper(setterSelector, element, setterInputs));
- }
- stack.add(result);
} else if (node.isIndex) {
if ("=" == op.source) {
generateDynamicSend(node);
@@ -5577,27 +5675,42 @@ class SsaBuilder extends NewResolvedVisitor {
elements.getGetterSelectorInComplexSendSet(node),
[receiver, index]);
HInstruction getterInstruction = pop();
-
- handleComplexOperatorSend(node, getterInstruction, arguments);
- HInstruction value = pop();
-
- pushInvokeDynamic(
- node, elements.getSelector(node), [receiver, index, value]);
- pop();
-
- if (node.isPostfix) {
- stack.add(getterInstruction);
+ if (node.isIfNullAssignment) {
+ // Compile x[i] ??= e as:
+ // t1 = x[i]
+ // if (t1 == null)
+ // t1 = x[i] = e;
+ // result = t1
+ SsaBranchBuilder brancher = new SsaBranchBuilder(this, node);
+ brancher.handleIfNull(() => stack.add(getterInstruction),
+ () {
+ visit(arguments.head);
+ HInstruction value = pop();
+ pushInvokeDynamic(
+ node, elements.getSelector(node), [receiver, index, value]);
+ pop();
+ stack.add(value);
+ });
} else {
- stack.add(value);
+ handleComplexOperatorSend(node, getterInstruction, arguments);
+ HInstruction value = pop();
+ pushInvokeDynamic(
+ node, elements.getSelector(node), [receiver, index, value]);
+ pop();
+ if (node.isPostfix) {
+ stack.add(getterInstruction);
+ } else {
+ stack.add(value);
+ }
}
}
} else if ("=" == op.source) {
Link<ast.Node> link = node.arguments;
assert(!link.isEmpty && link.tail.isEmpty);
if (Elements.isInstanceSend(node, elements)) {
- HInstruction receiver = generateInstanceSendReceiver(node);
- visit(link.head);
- generateInstanceSetterWithCompiledReceiver(node, receiver, pop());
+ generatePossiblyConditionalInstanceSetter(node,
+ () => generateInstanceSendReceiver(node),
+ () => visitAndPop(link.head));
} else {
visit(link.head);
generateNonInstanceSetter(node, element, pop());
@@ -5608,20 +5721,64 @@ class SsaBuilder extends NewResolvedVisitor {
assert("++" == op.source || "--" == op.source ||
node.assignmentOperator.source.endsWith("="));
- // [receiver] is only used if the node is an instance send.
- HInstruction receiver = null;
Element getter = elements[node.selector];
if (!Elements.isUnresolved(getter) && getter.impliesType) {
- ast.Identifier selector = node.selector;
- generateThrowNoSuchMethod(node, selector.source,
- argumentNodes: node.arguments);
+ if (node.isIfNullAssignment) {
+ // C ??= x is compiled just as C.
+ stack.add(addConstant(node.selector));
+ } else {
+ ast.Identifier selector = node.selector;
+ generateThrowNoSuchMethod(node, selector.source,
+ argumentNodes: node.arguments);
+ }
return;
- } else if (Elements.isInstanceSend(node, elements)) {
- receiver = generateInstanceSendReceiver(node);
- generateInstanceGetterWithCompiledReceiver(
- node, elements.getGetterSelectorInComplexSendSet(node), receiver);
- } else if (getter.isErroneous) {
+ }
+
+ if (Elements.isInstanceSend(node, elements)) {
+ void generateAssignment(HInstruction receiver) {
+ // desugars `e.x op= e2` to `e.x = e.x op e2`
+ generateInstanceGetterWithCompiledReceiver(
+ node, elements.getGetterSelectorInComplexSendSet(node), receiver);
+ HInstruction getterInstruction = pop();
+ if (node.isIfNullAssignment) {
+ SsaBranchBuilder brancher = new SsaBranchBuilder(this, node);
+ brancher.handleIfNull(() => stack.add(getterInstruction),
+ () {
+ visit(node.arguments.head);
+ generateInstanceSetterWithCompiledReceiver(
+ node, receiver, pop());
+ });
+ } else {
+ handleComplexOperatorSend(node, getterInstruction, node.arguments);
+ HInstruction value = pop();
+ generateInstanceSetterWithCompiledReceiver(node, receiver, value);
+ }
+ if (node.isPostfix) {
+ pop();
+ stack.add(getterInstruction);
+ }
+ }
+ if (node.isConditional) {
+ // generate `e?.x op= e2` as:
+ // t1 = e
+ // t1 == null ? t1 : (t1.x = t1.x op e2);
+ HInstruction receiver;
+ SsaBranchBuilder brancher = new SsaBranchBuilder(this, node);
+ brancher.handleConditional(
+ () {
+ receiver = generateInstanceSendReceiver(node);
+ pushCheckNull(receiver);
+ },
+ () => stack.add(receiver),
+ () => generateAssignment(receiver));
+ } else {
+ generateAssignment(generateInstanceSendReceiver(node));
+ }
+ return;
+ }
+
+ if (getter.isErroneous) {
generateStaticUnresolvedGet(node, getter);
} else if (getter.isField) {
generateStaticFieldGet(node, getter);
@@ -5635,14 +5792,16 @@ class SsaBuilder extends NewResolvedVisitor {
internalError(node, "Unexpected getter: $getter");
}
HInstruction getterInstruction = pop();
- handleComplexOperatorSend(node, getterInstruction, node.arguments);
- HInstruction value = pop();
- assert(value != null);
- if (Elements.isInstanceSend(node, elements)) {
- assert(receiver != null);
- generateInstanceSetterWithCompiledReceiver(node, receiver, value);
+ if (node.isIfNullAssignment) {
+ SsaBranchBuilder brancher = new SsaBranchBuilder(this, node);
+ brancher.handleIfNull(() => stack.add(getterInstruction),
+ () {
+ visit(node.arguments.head);
+ generateNonInstanceSetter(node, element, pop());
+ });
} else {
- assert(receiver == null);
+ handleComplexOperatorSend(node, getterInstruction, node.arguments);
+ HInstruction value = pop();
generateNonInstanceSetter(node, element, value);
}
if (node.isPostfix) {
@@ -7451,6 +7610,19 @@ class SsaBranchBuilder {
_handleDiamondBranch(visitCondition, visitThen, visitElse, true);
}
+ handleIfNull(void left(), void right()) {
+ // x ?? y is transformed into: x == null ? y : x
+ HInstruction leftExpression;
+ handleConditional(
+ () {
+ left();
+ leftExpression = builder.pop();
+ builder.pushCheckNull(leftExpression);
+ },
+ right,
+ () => builder.stack.add(leftExpression));
+ }
+
void handleLogicalAndOr(void left(), void right(), {bool isAnd}) {
// x && y is transformed into:
// t0 = boolify(x);
« no previous file with comments | « pkg/compiler/lib/src/scanner/utf8_bytes_scanner.dart ('k') | pkg/compiler/lib/src/tree/nodes.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698