Chromium Code Reviews| 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 f210452a62ca79f4c87100395718d62112933112..ade9ed0322363ebdcf644d3b3e707daff66badac 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,30 @@ class SsaBuilder extends NewResolvedVisitor { |
| } |
| @override |
| + void visitIfNotNullDynamicPropertyGet( |
| + ast.Send node, |
| + ast.Node receiver, |
| + Selector selector, |
| + _) { |
| + // exp?.x compiled as: |
| + // t1 = exp; |
| + // result = t1 == null ? null : t1.x; |
| + visit(receiver); |
|
sra1
2015/05/22 21:17:28
I think we should visit(receiver) in the visitCond
Siggi Cherem (dart-lang)
2015/05/22 22:36:08
Done.
|
| + HInstruction expression = pop(); |
| + SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| + brancher.handleConditional(() => pushCheckNull(expression), |
|
sra1
2015/05/22 21:17:28
It would look cleaner if this was on a new line.
Siggi Cherem (dart-lang)
2015/05/22 22:36:08
Done.
|
| + () => stack.add(graph.addConstantNull(compiler)), |
|
Siggi Cherem (dart-lang)
2015/05/22 03:50:49
technically we know that t1 is null too, does it m
|
| + () => 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 +3498,32 @@ class SsaBuilder extends NewResolvedVisitor { |
| generateStaticGetterGet(node, getter); |
| } |
| + void generatePossiblyConditionalInstanceSetter(ast.Send send, |
| + HInstruction receiver, |
| + 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) |
| + // t1 = null; |
| + // else |
| + // t1 = e.x = e2 |
| + brancher.handleConditional( |
| + () => pushCheckNull(receiver), |
| + () => stack.add(graph.addConstantNull(compiler)), |
| + () => generateInstanceSetterWithCompiledReceiver( |
| + send, receiver, pushValue(), |
| + selector: selector, location: location)); |
| + } else { |
| + generateInstanceSetterWithCompiledReceiver(send, receiver, pushValue(), |
| + selector: selector, location: location); |
| + } |
| + } |
| + |
| void generateInstanceSetterWithCompiledReceiver(ast.Send send, |
| HInstruction receiver, |
| HInstruction value, |
| @@ -3730,10 +3786,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 +3815,20 @@ class SsaBuilder extends NewResolvedVisitor { |
| } |
| @override |
| + visitIfNotNullDynamicPropertyInvoke( |
| + ast.Send node, |
| + ast.Node receiver, |
| + ast.NodeList arguments, |
| + Selector selector, |
| + _) { |
| + HInstruction receiver = generateInstanceSendReceiver(node); |
| + SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| + brancher.handleConditional(() => pushCheckNull(receiver), |
| + () => stack.add(graph.addConstantNull(compiler)), |
|
sra1
2015/05/22 21:17:28
We probably want to preserve the variant of null (
Siggi Cherem (dart-lang)
2015/05/22 22:36:08
Done.
|
| + () => _generateDynamicSend(node, receiver)); |
| + } |
| + |
| + @override |
| visitThisPropertyInvoke( |
| ast.Send node, |
| ast.NodeList arguments, |
| @@ -5505,11 +5579,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 +5624,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,18 +5659,33 @@ 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) { |
| @@ -5596,8 +5693,8 @@ class SsaBuilder extends NewResolvedVisitor { |
| assert(!link.isEmpty && link.tail.isEmpty); |
| if (Elements.isInstanceSend(node, elements)) { |
| HInstruction receiver = generateInstanceSendReceiver(node); |
| - visit(link.head); |
| - generateInstanceSetterWithCompiledReceiver(node, receiver, pop()); |
| + generatePossiblyConditionalInstanceSetter(node, receiver, |
| + () => visitAndPop(link.head)); |
| } else { |
| visit(link.head); |
| generateNonInstanceSetter(node, element, pop()); |
| @@ -5608,20 +5705,61 @@ 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; |
| + } |
| + |
| + if (Elements.isInstanceSend(node, elements)) { |
| + final HInstruction receiver = generateInstanceSendReceiver(node); |
| + void generateAssignment() { |
| + // desugarizes `e.x op= e2` as: `e.x = e.x op e2` |
|
sra1
2015/05/22 21:17:28
Desugars ... to: ...
|
| + 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 ? null : (t1.x = t1.x op e2); |
| + SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| + brancher.handleConditional( |
| + () => pushCheckNull(receiver), |
| + () => stack.add(graph.addConstantNull(compiler)), |
| + generateAssignment); |
| + } else { |
| + generateAssignment(); |
| + } |
| return; |
| - } else if (Elements.isInstanceSend(node, elements)) { |
| - receiver = generateInstanceSendReceiver(node); |
| - generateInstanceGetterWithCompiledReceiver( |
| - node, elements.getGetterSelectorInComplexSendSet(node), receiver); |
| - } else if (getter.isErroneous) { |
| + } |
| + |
| + if (getter.isErroneous) { |
| generateStaticUnresolvedGet(node, getter); |
| } else if (getter.isField) { |
| generateStaticFieldGet(node, getter); |
| @@ -5635,14 +5773,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 +7591,16 @@ class SsaBranchBuilder { |
| _handleDiamondBranch(visitCondition, visitThen, visitElse, true); |
| } |
| + handleIfNull(void left(), void right()) { |
| + // x ?? y is transformed into: x == null ? y : x |
| + left(); |
| + HInstruction leftExpression = builder.pop(); |
| + handleConditional( |
| + () => builder.pushCheckNull(leftExpression), |
|
sra1
2015/05/22 21:17:28
left() should be called in here.
Siggi Cherem (dart-lang)
2015/05/22 22:36:08
Done
|
| + right, |
| + () => builder.stack.add(leftExpression)); |
| + } |
| + |
| void handleLogicalAndOr(void left(), void right(), {bool isAnd}) { |
| // x && y is transformed into: |
| // t0 = boolify(x); |