| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library tree_ir_builder; | 5 library tree_ir_builder; |
| 6 | 6 |
| 7 import '../common.dart'; | 7 import '../common.dart'; |
| 8 import '../constants/values.dart'; | 8 import '../constants/values.dart'; |
| 9 import '../cps_ir/cps_ir_nodes.dart' as cps_ir; | 9 import '../cps_ir/cps_ir_nodes.dart' as cps_ir; |
| 10 import '../elements/elements.dart'; | 10 import '../elements/elements.dart'; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 <cps_ir.Primitive, Variable>{}; | 55 <cps_ir.Primitive, Variable>{}; |
| 56 final Map<cps_ir.MutableVariable, Variable> mutable2variable = | 56 final Map<cps_ir.MutableVariable, Variable> mutable2variable = |
| 57 <cps_ir.MutableVariable, Variable>{}; | 57 <cps_ir.MutableVariable, Variable>{}; |
| 58 final Set<cps_ir.Constant> inlinedConstants = new Set<cps_ir.Constant>(); | 58 final Set<cps_ir.Constant> inlinedConstants = new Set<cps_ir.Constant>(); |
| 59 | 59 |
| 60 // Continuations with more than one use are replaced with Tree labels. This | 60 // Continuations with more than one use are replaced with Tree labels. This |
| 61 // is the mapping from continuations to labels. | 61 // is the mapping from continuations to labels. |
| 62 final Map<cps_ir.Continuation, Label> labels = <cps_ir.Continuation, Label>{}; | 62 final Map<cps_ir.Continuation, Label> labels = <cps_ir.Continuation, Label>{}; |
| 63 | 63 |
| 64 ExecutableElement currentElement; | 64 ExecutableElement currentElement; |
| 65 |
| 65 /// The parameter to be translated to 'this'. This can either be the receiver | 66 /// The parameter to be translated to 'this'. This can either be the receiver |
| 66 /// parameter, the interceptor parameter, or null if the method has neither. | 67 /// parameter, the interceptor parameter, or null if the method has neither. |
| 67 cps_ir.Parameter thisParameter; | 68 cps_ir.Parameter thisParameter; |
| 68 cps_ir.Continuation returnContinuation; | 69 cps_ir.Continuation returnContinuation; |
| 69 | 70 |
| 70 Builder(this.internalError, this.glue); | 71 Builder(this.internalError, this.glue); |
| 71 | 72 |
| 72 /// Variable used in [buildPhiAssignments] as a temporary when swapping | 73 /// Variable used in [buildPhiAssignments] as a temporary when swapping |
| 73 /// variables. | 74 /// variables. |
| 74 Variable phiTempVar; | 75 Variable phiTempVar; |
| 75 | 76 |
| 76 Variable addMutableVariable(cps_ir.MutableVariable irVariable) { | 77 Variable addMutableVariable(cps_ir.MutableVariable irVariable) { |
| 77 assert(!mutable2variable.containsKey(irVariable)); | 78 assert(!mutable2variable.containsKey(irVariable)); |
| 78 Variable variable = new Variable(currentElement, irVariable.hint); | 79 Variable variable = new Variable(currentElement, irVariable.hint); |
| 79 mutable2variable[irVariable] = variable; | 80 mutable2variable[irVariable] = variable; |
| 80 return variable; | 81 return variable; |
| 81 } | 82 } |
| 82 | 83 |
| 83 Variable getMutableVariable(cps_ir.MutableVariable mutableVariable) { | 84 Variable getMutableVariable(cps_ir.MutableVariable mutableVariable) { |
| 84 return mutable2variable[mutableVariable]; | 85 return mutable2variable[mutableVariable]; |
| 85 } | 86 } |
| 86 | 87 |
| 87 VariableUse getMutableVariableUse( | 88 VariableUse getMutableVariableUse( |
| 88 cps_ir.Reference<cps_ir.MutableVariable> reference, | 89 cps_ir.Reference<cps_ir.MutableVariable> reference, |
| 89 SourceInformation sourceInformation) { | 90 SourceInformation sourceInformation) { |
| 90 Variable variable = getMutableVariable(reference.definition); | 91 Variable variable = getMutableVariable(reference.definition); |
| 91 return new VariableUse(variable, sourceInformation: sourceInformation); | 92 return new VariableUse(variable, sourceInformation: sourceInformation); |
| 92 } | 93 } |
| 93 | 94 |
| 94 /// Obtains the variable representing the given primitive. Returns null for | 95 /// Obtains the variable representing the given primitive. Returns null for |
| 95 /// primitives that have no reference and do not need a variable. | 96 /// primitives that have no reference and do not need a variable. |
| 96 Variable getVariable(cps_ir.Primitive primitive) { | 97 Variable getVariable(cps_ir.Primitive primitive) { |
| 97 primitive = primitive.effectiveDefinition; | 98 primitive = primitive.effectiveDefinition; |
| 98 return primitive2variable.putIfAbsent(primitive, | 99 return primitive2variable.putIfAbsent( |
| 99 () => new Variable(currentElement, primitive.hint)); | 100 primitive, () => new Variable(currentElement, primitive.hint)); |
| 100 } | 101 } |
| 101 | 102 |
| 102 /// Obtains a reference to the tree Variable corresponding to the IR primitive | 103 /// Obtains a reference to the tree Variable corresponding to the IR primitive |
| 103 /// referred to by [reference]. | 104 /// referred to by [reference]. |
| 104 /// This increments the reference count for the given variable, so the | 105 /// This increments the reference count for the given variable, so the |
| 105 /// returned expression must be used in the tree. | 106 /// returned expression must be used in the tree. |
| 106 Expression getVariableUse(cps_ir.Reference<cps_ir.Primitive> reference, | 107 Expression getVariableUse(cps_ir.Reference<cps_ir.Primitive> reference, |
| 107 {SourceInformation sourceInformation}) { | 108 {SourceInformation sourceInformation}) { |
| 108 cps_ir.Primitive prim = reference.definition.effectiveDefinition; | 109 cps_ir.Primitive prim = reference.definition.effectiveDefinition; |
| 109 if (prim is cps_ir.Constant && inlinedConstants.contains(prim)) { | 110 if (prim is cps_ir.Constant && inlinedConstants.contains(prim)) { |
| 110 return new Constant(prim.value); | 111 return new Constant(prim.value); |
| 111 } | 112 } |
| 112 if (thisParameter != null && prim == thisParameter) { | 113 if (thisParameter != null && prim == thisParameter) { |
| 113 return new This(); | 114 return new This(); |
| 114 } | 115 } |
| 115 return new VariableUse( | 116 return new VariableUse(getVariable(prim), |
| 116 getVariable(prim), sourceInformation: sourceInformation); | 117 sourceInformation: sourceInformation); |
| 117 } | 118 } |
| 118 | 119 |
| 119 Expression getVariableUseOrNull( | 120 Expression getVariableUseOrNull( |
| 120 cps_ir.Reference<cps_ir.Primitive> reference) { | 121 cps_ir.Reference<cps_ir.Primitive> reference) { |
| 121 return reference == null ? null : getVariableUse(reference); | 122 return reference == null ? null : getVariableUse(reference); |
| 122 } | 123 } |
| 123 | 124 |
| 124 Label getLabel(cps_ir.Continuation cont) { | 125 Label getLabel(cps_ir.Continuation cont) { |
| 125 return labels.putIfAbsent(cont, () => new Label()); | 126 return labels.putIfAbsent(cont, () => new Label()); |
| 126 } | 127 } |
| 127 | 128 |
| 128 FunctionDefinition buildFunction(cps_ir.FunctionDefinition node) { | 129 FunctionDefinition buildFunction(cps_ir.FunctionDefinition node) { |
| 129 currentElement = node.element; | 130 currentElement = node.element; |
| 130 List<Variable> parameters = node.parameters.map(getVariable).toList(); | 131 List<Variable> parameters = node.parameters.map(getVariable).toList(); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 144 } | 145 } |
| 145 | 146 |
| 146 /// Returns a list of variables corresponding to the arguments to a method | 147 /// Returns a list of variables corresponding to the arguments to a method |
| 147 /// call or similar construct. | 148 /// call or similar construct. |
| 148 /// | 149 /// |
| 149 /// The `readCount` for these variables will be incremented. | 150 /// The `readCount` for these variables will be incremented. |
| 150 /// | 151 /// |
| 151 /// The list will be typed as a list of [Expression] to allow inplace updates | 152 /// The list will be typed as a list of [Expression] to allow inplace updates |
| 152 /// on the list during the rewrite phases. | 153 /// on the list during the rewrite phases. |
| 153 List<Expression> translateArguments(List<cps_ir.Reference> args) { | 154 List<Expression> translateArguments(List<cps_ir.Reference> args) { |
| 154 return new List<Expression>.generate(args.length, | 155 return new List<Expression>.generate( |
| 155 (int index) => getVariableUse(args[index]), | 156 args.length, (int index) => getVariableUse(args[index]), |
| 156 growable: false); | 157 growable: false); |
| 157 } | 158 } |
| 158 | 159 |
| 159 /// Simultaneously assigns each argument to the corresponding parameter, | 160 /// Simultaneously assigns each argument to the corresponding parameter, |
| 160 /// then continues at the statement created by [buildRest]. | 161 /// then continues at the statement created by [buildRest]. |
| 161 Statement buildPhiAssignments( | 162 Statement buildPhiAssignments(List<cps_ir.Parameter> parameters, |
| 162 List<cps_ir.Parameter> parameters, | 163 List<Expression> arguments, Statement buildRest()) { |
| 163 List<Expression> arguments, | |
| 164 Statement buildRest()) { | |
| 165 assert(parameters.length == arguments.length); | 164 assert(parameters.length == arguments.length); |
| 166 // We want a parallel assignment to all parameters simultaneously. | 165 // We want a parallel assignment to all parameters simultaneously. |
| 167 // Since we do not have parallel assignments in dart_tree, we must linearize | 166 // Since we do not have parallel assignments in dart_tree, we must linearize |
| 168 // the assignments without attempting to read a previously-overwritten | 167 // the assignments without attempting to read a previously-overwritten |
| 169 // value. For example {x,y = y,x} cannot be linearized to {x = y; y = x}, | 168 // value. For example {x,y = y,x} cannot be linearized to {x = y; y = x}, |
| 170 // for this we must introduce a temporary variable: {t = x; x = y; y = t}. | 169 // for this we must introduce a temporary variable: {t = x; x = y; y = t}. |
| 171 | 170 |
| 172 // [rightHand] is the inverse of [arguments], that is, it maps variables | 171 // [rightHand] is the inverse of [arguments], that is, it maps variables |
| 173 // to the assignments on which is occurs as the right-hand side. | 172 // to the assignments on which is occurs as the right-hand side. |
| 174 Map<Variable, List<int>> rightHand = <Variable, List<int>>{}; | 173 Map<Variable, List<int>> rightHand = <Variable, List<int>>{}; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 210 Variable param = getVariable(parameters[i]); | 209 Variable param = getVariable(parameters[i]); |
| 211 Expression arg = arguments[i]; | 210 Expression arg = arguments[i]; |
| 212 if (param == null || (arg is VariableUse && param == arg.variable)) { | 211 if (param == null || (arg is VariableUse && param == arg.variable)) { |
| 213 return; // No assignment necessary. | 212 return; // No assignment necessary. |
| 214 } | 213 } |
| 215 if (assignmentSrc[i] != null) { | 214 if (assignmentSrc[i] != null) { |
| 216 // Cycle found; store argument in a temporary variable. | 215 // Cycle found; store argument in a temporary variable. |
| 217 // The temporary will then be used as right-hand side when the | 216 // The temporary will then be used as right-hand side when the |
| 218 // assignment gets added. | 217 // assignment gets added. |
| 219 VariableUse source = assignmentSrc[i]; | 218 VariableUse source = assignmentSrc[i]; |
| 220 if (source.variable != phiTempVar) { // Only move to temporary once. | 219 if (source.variable != phiTempVar) { |
| 220 // Only move to temporary once. |
| 221 assignmentSrc[i] = new VariableUse(phiTempVar); | 221 assignmentSrc[i] = new VariableUse(phiTempVar); |
| 222 addAssignment(phiTempVar, arg); | 222 addAssignment(phiTempVar, arg); |
| 223 } | 223 } |
| 224 return; | 224 return; |
| 225 } | 225 } |
| 226 assignmentSrc[i] = arg; | 226 assignmentSrc[i] = arg; |
| 227 List<int> paramUses = rightHand[param]; | 227 List<int> paramUses = rightHand[param]; |
| 228 if (paramUses != null) { | 228 if (paramUses != null) { |
| 229 for (int useIndex in paramUses) { | 229 for (int useIndex in paramUses) { |
| 230 visitAssignment(useIndex); | 230 visitAssignment(useIndex); |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 // | 357 // |
| 358 // The continuation bodies are not always translated directly here because | 358 // The continuation bodies are not always translated directly here because |
| 359 // they may have been already translated: | 359 // they may have been already translated: |
| 360 // * For singly-used continuations, the continuation's body is | 360 // * For singly-used continuations, the continuation's body is |
| 361 // translated at the site of the continuation invocation. | 361 // translated at the site of the continuation invocation. |
| 362 // * For recursive continuations, there is a single non-recursive | 362 // * For recursive continuations, there is a single non-recursive |
| 363 // invocation. The continuation's body is translated at the site | 363 // invocation. The continuation's body is translated at the site |
| 364 // of the non-recursive continuation invocation. | 364 // of the non-recursive continuation invocation. |
| 365 // See [visitInvokeContinuation] for the implementation. | 365 // See [visitInvokeContinuation] for the implementation. |
| 366 NodeCallback visitLetCont(cps_ir.LetCont node) => (Statement next) { | 366 NodeCallback visitLetCont(cps_ir.LetCont node) => (Statement next) { |
| 367 for (cps_ir.Continuation continuation in node.continuations) { | 367 for (cps_ir.Continuation continuation in node.continuations) { |
| 368 // This happens after the body of the LetCont has been translated. | 368 // This happens after the body of the LetCont has been translated. |
| 369 // Labels are created on-demand if the continuation could not be inlined, | 369 // Labels are created on-demand if the continuation could not be inlin
ed, |
| 370 // so the existence of the label indicates if a labeled statement should | 370 // so the existence of the label indicates if a labeled statement shou
ld |
| 371 // be emitted. | 371 // be emitted. |
| 372 Label label = labels[continuation]; | 372 Label label = labels[continuation]; |
| 373 if (label != null && !continuation.isRecursive) { | 373 if (label != null && !continuation.isRecursive) { |
| 374 // Recursively build the body. We only do this for join continuations, | 374 // Recursively build the body. We only do this for join continuation
s, |
| 375 // so we should not risk overly deep recursion. | 375 // so we should not risk overly deep recursion. |
| 376 next = new LabeledStatement( | 376 next = new LabeledStatement( |
| 377 label, | 377 label, next, translateExpression(continuation.body)); |
| 378 next, | 378 } |
| 379 translateExpression(continuation.body)); | 379 } |
| 380 } | 380 return next; |
| 381 } | 381 }; |
| 382 return next; | |
| 383 }; | |
| 384 | 382 |
| 385 NodeCallback visitLetHandler(cps_ir.LetHandler node) => (Statement next) { | 383 NodeCallback visitLetHandler(cps_ir.LetHandler node) => (Statement next) { |
| 386 List<Variable> catchParameters = | 384 List<Variable> catchParameters = |
| 387 node.handler.parameters.map(getVariable).toList(); | 385 node.handler.parameters.map(getVariable).toList(); |
| 388 Statement catchBody = translateExpression(node.handler.body); | 386 Statement catchBody = translateExpression(node.handler.body); |
| 389 return new Try(next, catchParameters, catchBody); | 387 return new Try(next, catchParameters, catchBody); |
| 390 }; | 388 }; |
| 391 | 389 |
| 392 NodeCallback visitLetMutable(cps_ir.LetMutable node) { | 390 NodeCallback visitLetMutable(cps_ir.LetMutable node) { |
| 393 Variable variable = addMutableVariable(node.variable); | 391 Variable variable = addMutableVariable(node.variable); |
| 394 Expression value = getVariableUse(node.valueRef); | 392 Expression value = getVariableUse(node.valueRef); |
| 395 return (Statement next) => Assign.makeStatement(variable, value, next); | 393 return (Statement next) => Assign.makeStatement(variable, value, next); |
| 396 } | 394 } |
| 397 | 395 |
| 398 /************************** TAIL EXPRESSIONS **************************/ | 396 /************************** TAIL EXPRESSIONS **************************/ |
| 399 // | 397 // |
| 400 // Visit methods for tail expressions must return a statement directly | 398 // Visit methods for tail expressions must return a statement directly |
| (...skipping 11 matching lines...) Expand all Loading... |
| 412 Statement visitInvokeContinuation(cps_ir.InvokeContinuation node) { | 410 Statement visitInvokeContinuation(cps_ir.InvokeContinuation node) { |
| 413 // Invocations of the return continuation are translated to returns. | 411 // Invocations of the return continuation are translated to returns. |
| 414 // Other continuation invocations are replaced with assignments of the | 412 // Other continuation invocations are replaced with assignments of the |
| 415 // arguments to formal parameter variables, followed by the body if | 413 // arguments to formal parameter variables, followed by the body if |
| 416 // the continuation is singly reference or a break if it is multiply | 414 // the continuation is singly reference or a break if it is multiply |
| 417 // referenced. | 415 // referenced. |
| 418 cps_ir.Continuation cont = node.continuation; | 416 cps_ir.Continuation cont = node.continuation; |
| 419 if (cont == returnContinuation) { | 417 if (cont == returnContinuation) { |
| 420 assert(node.argumentRefs.length == 1); | 418 assert(node.argumentRefs.length == 1); |
| 421 return new Return(getVariableUse(node.argumentRefs.single), | 419 return new Return(getVariableUse(node.argumentRefs.single), |
| 422 sourceInformation: node.sourceInformation); | 420 sourceInformation: node.sourceInformation); |
| 423 } else { | 421 } else { |
| 424 List<Expression> arguments = translateArguments(node.argumentRefs); | 422 List<Expression> arguments = translateArguments(node.argumentRefs); |
| 425 return buildPhiAssignments(cont.parameters, arguments, | 423 return buildPhiAssignments(cont.parameters, arguments, () { |
| 426 () { | 424 // Translate invocations of recursive and non-recursive |
| 427 // Translate invocations of recursive and non-recursive | 425 // continuations differently. |
| 428 // continuations differently. | 426 // * Non-recursive continuations |
| 429 // * Non-recursive continuations | 427 // - If there is one use, translate the continuation body |
| 430 // - If there is one use, translate the continuation body | 428 // inline at the invocation site. |
| 431 // inline at the invocation site. | 429 // - If there are multiple uses, translate to Break. |
| 432 // - If there are multiple uses, translate to Break. | 430 // * Recursive continuations |
| 433 // * Recursive continuations | 431 // - There is a single non-recursive invocation. Translate |
| 434 // - There is a single non-recursive invocation. Translate | 432 // the continuation body inline as a labeled loop at the |
| 435 // the continuation body inline as a labeled loop at the | 433 // invocation site. |
| 436 // invocation site. | 434 // - Translate the recursive invocations to Continue. |
| 437 // - Translate the recursive invocations to Continue. | 435 if (cont.isRecursive) { |
| 438 if (cont.isRecursive) { | 436 return node.isRecursive |
| 439 return node.isRecursive | 437 ? new Continue(getLabel(cont)) |
| 440 ? new Continue(getLabel(cont)) | 438 : new WhileTrue(getLabel(cont), translateExpression(cont.body)); |
| 441 : new WhileTrue(getLabel(cont), | 439 } else { |
| 442 translateExpression(cont.body)); | 440 return cont.hasExactlyOneUse && !node.isEscapingTry |
| 443 } else { | 441 ? translateExpression(cont.body) |
| 444 return cont.hasExactlyOneUse && !node.isEscapingTry | 442 : new Break(getLabel(cont)); |
| 445 ? translateExpression(cont.body) | 443 } |
| 446 : new Break(getLabel(cont)); | 444 }); |
| 447 } | |
| 448 }); | |
| 449 } | 445 } |
| 450 } | 446 } |
| 451 | 447 |
| 452 /// Translates a branch condition to a tree expression. | 448 /// Translates a branch condition to a tree expression. |
| 453 Expression translateCondition(cps_ir.Branch branch) { | 449 Expression translateCondition(cps_ir.Branch branch) { |
| 454 Expression value = getVariableUse( | 450 Expression value = getVariableUse(branch.conditionRef, |
| 455 branch.conditionRef, sourceInformation: branch.sourceInformation); | 451 sourceInformation: branch.sourceInformation); |
| 456 if (branch.isStrictCheck) { | 452 if (branch.isStrictCheck) { |
| 457 return new ApplyBuiltinOperator( | 453 return new ApplyBuiltinOperator( |
| 458 BuiltinOperator.StrictEq, | 454 BuiltinOperator.StrictEq, |
| 459 <Expression>[value, new Constant(new TrueConstantValue())], | 455 <Expression>[value, new Constant(new TrueConstantValue())], |
| 460 branch.sourceInformation); | 456 branch.sourceInformation); |
| 461 } else { | 457 } else { |
| 462 return value; | 458 return value; |
| 463 } | 459 } |
| 464 } | 460 } |
| 465 | 461 |
| 466 Statement visitBranch(cps_ir.Branch node) { | 462 Statement visitBranch(cps_ir.Branch node) { |
| 467 Expression condition = translateCondition(node); | 463 Expression condition = translateCondition(node); |
| 468 Statement thenStatement, elseStatement; | 464 Statement thenStatement, elseStatement; |
| 469 cps_ir.Continuation cont = node.trueContinuation; | 465 cps_ir.Continuation cont = node.trueContinuation; |
| 470 assert(cont.parameters.isEmpty); | 466 assert(cont.parameters.isEmpty); |
| 471 thenStatement = cont.hasExactlyOneUse | 467 thenStatement = cont.hasExactlyOneUse |
| 472 ? translateExpression(cont.body) | 468 ? translateExpression(cont.body) |
| 473 : new Break(labels[cont]); | 469 : new Break(labels[cont]); |
| 474 cont = node.falseContinuation; | 470 cont = node.falseContinuation; |
| 475 assert(cont.parameters.isEmpty); | 471 assert(cont.parameters.isEmpty); |
| 476 elseStatement = cont.hasExactlyOneUse | 472 elseStatement = cont.hasExactlyOneUse |
| 477 ? translateExpression(cont.body) | 473 ? translateExpression(cont.body) |
| 478 : new Break(labels[cont]); | 474 : new Break(labels[cont]); |
| 479 return new If( | 475 return new If( |
| 480 condition, thenStatement, elseStatement, node.sourceInformation); | 476 condition, thenStatement, elseStatement, node.sourceInformation); |
| 481 } | 477 } |
| 482 | 478 |
| 483 | |
| 484 /************************** PRIMITIVES **************************/ | 479 /************************** PRIMITIVES **************************/ |
| 485 // | 480 // |
| 486 // Visit methods for primitives must return an expression. | 481 // Visit methods for primitives must return an expression. |
| 487 // | 482 // |
| 488 | 483 |
| 489 Expression visitSetField(cps_ir.SetField node) { | 484 Expression visitSetField(cps_ir.SetField node) { |
| 490 return new SetField(getVariableUse(node.objectRef), | 485 return new SetField(getVariableUse(node.objectRef), node.field, |
| 491 node.field, | 486 getVariableUse(node.valueRef), node.sourceInformation); |
| 492 getVariableUse(node.valueRef), | |
| 493 node.sourceInformation); | |
| 494 } | 487 } |
| 495 | 488 |
| 496 Expression visitInterceptor(cps_ir.Interceptor node) { | 489 Expression visitInterceptor(cps_ir.Interceptor node) { |
| 497 return new Interceptor(getVariableUse(node.inputRef), | 490 return new Interceptor(getVariableUse(node.inputRef), |
| 498 node.interceptedClasses, | 491 node.interceptedClasses, node.sourceInformation); |
| 499 node.sourceInformation); | |
| 500 } | 492 } |
| 501 | 493 |
| 502 Expression visitCreateInstance(cps_ir.CreateInstance node) { | 494 Expression visitCreateInstance(cps_ir.CreateInstance node) { |
| 503 return new CreateInstance( | 495 return new CreateInstance( |
| 504 node.classElement, | 496 node.classElement, |
| 505 translateArguments(node.argumentRefs), | 497 translateArguments(node.argumentRefs), |
| 506 getVariableUseOrNull(node.typeInformationRef), | 498 getVariableUseOrNull(node.typeInformationRef), |
| 507 node.sourceInformation); | 499 node.sourceInformation); |
| 508 } | 500 } |
| 509 | 501 |
| 510 Expression visitGetField(cps_ir.GetField node) { | 502 Expression visitGetField(cps_ir.GetField node) { |
| 511 return new GetField(getVariableUse(node.objectRef), node.field, | 503 return new GetField( |
| 512 node.sourceInformation, objectIsNotNull: !node.object.type.isNullable); | 504 getVariableUse(node.objectRef), node.field, node.sourceInformation, |
| 505 objectIsNotNull: !node.object.type.isNullable); |
| 513 } | 506 } |
| 514 | 507 |
| 515 Expression visitCreateBox(cps_ir.CreateBox node) { | 508 Expression visitCreateBox(cps_ir.CreateBox node) { |
| 516 return new CreateBox(); | 509 return new CreateBox(); |
| 517 } | 510 } |
| 518 | 511 |
| 519 Expression visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) { | 512 Expression visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) { |
| 520 return new CreateInvocationMirror( | 513 return new CreateInvocationMirror( |
| 521 node.selector, | 514 node.selector, translateArguments(node.argumentRefs)); |
| 522 translateArguments(node.argumentRefs)); | |
| 523 } | 515 } |
| 524 | 516 |
| 525 Expression visitGetMutable(cps_ir.GetMutable node) { | 517 Expression visitGetMutable(cps_ir.GetMutable node) { |
| 526 return getMutableVariableUse(node.variableRef, node.sourceInformation); | 518 return getMutableVariableUse(node.variableRef, node.sourceInformation); |
| 527 } | 519 } |
| 528 | 520 |
| 529 Expression visitSetMutable(cps_ir.SetMutable node) { | 521 Expression visitSetMutable(cps_ir.SetMutable node) { |
| 530 Variable variable = getMutableVariable(node.variable); | 522 Variable variable = getMutableVariable(node.variable); |
| 531 Expression value = getVariableUse(node.valueRef); | 523 Expression value = getVariableUse(node.valueRef); |
| 532 return new Assign( | 524 return new Assign(variable, value, |
| 533 variable, value, sourceInformation: node.sourceInformation); | 525 sourceInformation: node.sourceInformation); |
| 534 } | 526 } |
| 535 | 527 |
| 536 Expression visitConstant(cps_ir.Constant node) { | 528 Expression visitConstant(cps_ir.Constant node) { |
| 537 return new Constant(node.value, sourceInformation: node.sourceInformation); | 529 return new Constant(node.value, sourceInformation: node.sourceInformation); |
| 538 } | 530 } |
| 539 | 531 |
| 540 Expression visitLiteralList(cps_ir.LiteralList node) { | 532 Expression visitLiteralList(cps_ir.LiteralList node) { |
| 541 return new LiteralList( | 533 return new LiteralList(node.dartType, translateArguments(node.valueRefs)); |
| 542 node.dartType, | |
| 543 translateArguments(node.valueRefs)); | |
| 544 } | 534 } |
| 545 | 535 |
| 546 Expression visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) { | 536 Expression visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) { |
| 547 return new ReifyRuntimeType( | 537 return new ReifyRuntimeType( |
| 548 getVariableUse(node.valueRef), node.sourceInformation); | 538 getVariableUse(node.valueRef), node.sourceInformation); |
| 549 } | 539 } |
| 550 | 540 |
| 551 Expression visitReadTypeVariable(cps_ir.ReadTypeVariable node) { | 541 Expression visitReadTypeVariable(cps_ir.ReadTypeVariable node) { |
| 552 return new ReadTypeVariable( | 542 return new ReadTypeVariable( |
| 553 node.variable, | 543 node.variable, getVariableUse(node.targetRef), node.sourceInformation); |
| 554 getVariableUse(node.targetRef), | |
| 555 node.sourceInformation); | |
| 556 } | 544 } |
| 557 | 545 |
| 558 Expression visitTypeExpression(cps_ir.TypeExpression node) { | 546 Expression visitTypeExpression(cps_ir.TypeExpression node) { |
| 559 return new TypeExpression( | 547 return new TypeExpression(node.kind, node.dartType, |
| 560 node.kind, | |
| 561 node.dartType, | |
| 562 node.argumentRefs.map(getVariableUse).toList()); | 548 node.argumentRefs.map(getVariableUse).toList()); |
| 563 } | 549 } |
| 564 | 550 |
| 565 Expression visitTypeTest(cps_ir.TypeTest node) { | 551 Expression visitTypeTest(cps_ir.TypeTest node) { |
| 566 Expression value = getVariableUse(node.valueRef); | 552 Expression value = getVariableUse(node.valueRef); |
| 567 List<Expression> typeArgs = translateArguments(node.typeArgumentRefs); | 553 List<Expression> typeArgs = translateArguments(node.typeArgumentRefs); |
| 568 return new TypeOperator(value, node.dartType, typeArgs, isTypeTest: true); | 554 return new TypeOperator(value, node.dartType, typeArgs, isTypeTest: true); |
| 569 } | 555 } |
| 570 | 556 |
| 571 Expression visitTypeTestViaFlag(cps_ir.TypeTestViaFlag node) { | 557 Expression visitTypeTestViaFlag(cps_ir.TypeTestViaFlag node) { |
| 572 Expression value = getVariableUse(node.interceptorRef); | 558 Expression value = getVariableUse(node.interceptorRef); |
| 573 // TODO(sra): Move !! to cps_ir level. | 559 // TODO(sra): Move !! to cps_ir level. |
| 574 return new Not(new Not(new GetTypeTestProperty(value, node.dartType))); | 560 return new Not(new Not(new GetTypeTestProperty(value, node.dartType))); |
| 575 } | 561 } |
| 576 | 562 |
| 577 Expression visitGetStatic(cps_ir.GetStatic node) { | 563 Expression visitGetStatic(cps_ir.GetStatic node) { |
| 578 return new GetStatic(node.element, node.sourceInformation); | 564 return new GetStatic(node.element, node.sourceInformation); |
| 579 } | 565 } |
| 580 | 566 |
| 581 Expression visitSetStatic(cps_ir.SetStatic node) { | 567 Expression visitSetStatic(cps_ir.SetStatic node) { |
| 582 return new SetStatic( | 568 return new SetStatic( |
| 583 node.element, | 569 node.element, getVariableUse(node.valueRef), node.sourceInformation); |
| 584 getVariableUse(node.valueRef), | |
| 585 node.sourceInformation); | |
| 586 } | 570 } |
| 587 | 571 |
| 588 Expression visitApplyBuiltinOperator(cps_ir.ApplyBuiltinOperator node) { | 572 Expression visitApplyBuiltinOperator(cps_ir.ApplyBuiltinOperator node) { |
| 589 if (node.operator == BuiltinOperator.IsFalsy) { | 573 if (node.operator == BuiltinOperator.IsFalsy) { |
| 590 return new Not(getVariableUse(node.argumentRefs.single)); | 574 return new Not(getVariableUse(node.argumentRefs.single)); |
| 591 } | 575 } |
| 592 return new ApplyBuiltinOperator( | 576 return new ApplyBuiltinOperator(node.operator, |
| 593 node.operator, | 577 translateArguments(node.argumentRefs), node.sourceInformation); |
| 594 translateArguments(node.argumentRefs), | |
| 595 node.sourceInformation); | |
| 596 } | 578 } |
| 597 | 579 |
| 598 Expression visitApplyBuiltinMethod(cps_ir.ApplyBuiltinMethod node) { | 580 Expression visitApplyBuiltinMethod(cps_ir.ApplyBuiltinMethod node) { |
| 599 return new ApplyBuiltinMethod(node.method, | 581 return new ApplyBuiltinMethod(node.method, getVariableUse(node.receiverRef), |
| 600 getVariableUse(node.receiverRef), | |
| 601 translateArguments(node.argumentRefs), | 582 translateArguments(node.argumentRefs), |
| 602 receiverIsNotNull: !node.receiver.type.isNullable); | 583 receiverIsNotNull: !node.receiver.type.isNullable); |
| 603 } | 584 } |
| 604 | 585 |
| 605 Expression visitGetLength(cps_ir.GetLength node) { | 586 Expression visitGetLength(cps_ir.GetLength node) { |
| 606 return new GetLength(getVariableUse(node.objectRef)); | 587 return new GetLength(getVariableUse(node.objectRef)); |
| 607 } | 588 } |
| 608 | 589 |
| 609 Expression visitGetIndex(cps_ir.GetIndex node) { | 590 Expression visitGetIndex(cps_ir.GetIndex node) { |
| 610 return new GetIndex(getVariableUse(node.objectRef), | 591 return new GetIndex( |
| 611 getVariableUse(node.indexRef)); | 592 getVariableUse(node.objectRef), getVariableUse(node.indexRef)); |
| 612 } | 593 } |
| 613 | 594 |
| 614 Expression visitSetIndex(cps_ir.SetIndex node) { | 595 Expression visitSetIndex(cps_ir.SetIndex node) { |
| 615 return new SetIndex(getVariableUse(node.objectRef), | 596 return new SetIndex(getVariableUse(node.objectRef), |
| 616 getVariableUse(node.indexRef), | 597 getVariableUse(node.indexRef), getVariableUse(node.valueRef)); |
| 617 getVariableUse(node.valueRef)); | |
| 618 } | 598 } |
| 619 | 599 |
| 620 Expression visitInvokeStatic(cps_ir.InvokeStatic node) { | 600 Expression visitInvokeStatic(cps_ir.InvokeStatic node) { |
| 621 List<Expression> arguments = translateArguments(node.argumentRefs); | 601 List<Expression> arguments = translateArguments(node.argumentRefs); |
| 622 return new InvokeStatic(node.target, node.selector, arguments, | 602 return new InvokeStatic( |
| 623 node.sourceInformation); | 603 node.target, node.selector, arguments, node.sourceInformation); |
| 624 } | 604 } |
| 625 | 605 |
| 626 List<Expression> insertReceiverArgument(Expression receiver, | 606 List<Expression> insertReceiverArgument( |
| 627 List<Expression> arguments) { | 607 Expression receiver, List<Expression> arguments) { |
| 628 return new List<Expression>.generate(arguments.length + 1, | 608 return new List<Expression>.generate( |
| 629 (n) => n == 0 ? receiver : arguments[n - 1], | 609 arguments.length + 1, (n) => n == 0 ? receiver : arguments[n - 1], |
| 630 growable: false); | 610 growable: false); |
| 631 } | 611 } |
| 632 | 612 |
| 633 Expression visitInvokeMethod(cps_ir.InvokeMethod node) { | 613 Expression visitInvokeMethod(cps_ir.InvokeMethod node) { |
| 634 switch (node.callingConvention) { | 614 switch (node.callingConvention) { |
| 635 case cps_ir.CallingConvention.Normal: | 615 case cps_ir.CallingConvention.Normal: |
| 636 InvokeMethod invoke = new InvokeMethod( | 616 InvokeMethod invoke = new InvokeMethod( |
| 637 getVariableUse(node.receiverRef), | 617 getVariableUse(node.receiverRef), |
| 638 node.selector, | 618 node.selector, |
| 639 node.mask, | 619 node.mask, |
| (...skipping 12 matching lines...) Expand all Loading... |
| 652 node.mask, | 632 node.mask, |
| 653 arguments, | 633 arguments, |
| 654 node.sourceInformation); | 634 node.sourceInformation); |
| 655 // Sometimes we know the Dart receiver is non-null because it has been | 635 // Sometimes we know the Dart receiver is non-null because it has been |
| 656 // refined, which implies that the JS receiver also can not be null at | 636 // refined, which implies that the JS receiver also can not be null at |
| 657 // the use-site. Interceptors are not refined, so this information is | 637 // the use-site. Interceptors are not refined, so this information is |
| 658 // not always available on the JS receiver. | 638 // not always available on the JS receiver. |
| 659 // Also check the JS receiver's type, however, because sometimes we know | 639 // Also check the JS receiver's type, however, because sometimes we know |
| 660 // an interceptor is non-null because it intercepts JSNull. | 640 // an interceptor is non-null because it intercepts JSNull. |
| 661 invoke.receiverIsNotNull = | 641 invoke.receiverIsNotNull = |
| 662 !node.receiver.type.isNullable || | 642 !node.receiver.type.isNullable || !node.interceptor.type.isNullable; |
| 663 !node.interceptor.type.isNullable; | |
| 664 return invoke; | 643 return invoke; |
| 665 | 644 |
| 666 case cps_ir.CallingConvention.DummyIntercepted: | 645 case cps_ir.CallingConvention.DummyIntercepted: |
| 667 List<Expression> arguments = insertReceiverArgument( | 646 List<Expression> arguments = insertReceiverArgument( |
| 668 new Constant(new IntConstantValue(0)), | 647 new Constant(new IntConstantValue(0)), |
| 669 translateArguments(node.argumentRefs)); | 648 translateArguments(node.argumentRefs)); |
| 670 InvokeMethod invoke = new InvokeMethod( | 649 InvokeMethod invoke = new InvokeMethod(getVariableUse(node.receiverRef), |
| 671 getVariableUse(node.receiverRef), | 650 node.selector, node.mask, arguments, node.sourceInformation); |
| 672 node.selector, | |
| 673 node.mask, | |
| 674 arguments, | |
| 675 node.sourceInformation); | |
| 676 invoke.receiverIsNotNull = !node.receiver.type.isNullable; | 651 invoke.receiverIsNotNull = !node.receiver.type.isNullable; |
| 677 return invoke; | 652 return invoke; |
| 678 | 653 |
| 679 case cps_ir.CallingConvention.OneShotIntercepted: | 654 case cps_ir.CallingConvention.OneShotIntercepted: |
| 680 List<Expression> arguments = insertReceiverArgument( | 655 List<Expression> arguments = insertReceiverArgument( |
| 681 getVariableUse(node.receiverRef), | 656 getVariableUse(node.receiverRef), |
| 682 translateArguments(node.argumentRefs)); | 657 translateArguments(node.argumentRefs)); |
| 683 return new OneShotInterceptor( | 658 return new OneShotInterceptor( |
| 684 node.selector, | 659 node.selector, node.mask, arguments, node.sourceInformation); |
| 685 node.mask, | |
| 686 arguments, | |
| 687 node.sourceInformation); | |
| 688 } | 660 } |
| 689 } | 661 } |
| 690 | 662 |
| 691 Expression visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) { | 663 Expression visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) { |
| 692 if (node.interceptorRef != null) { | 664 if (node.interceptorRef != null) { |
| 693 return new InvokeMethodDirectly(getVariableUse(node.interceptorRef), | 665 return new InvokeMethodDirectly( |
| 666 getVariableUse(node.interceptorRef), |
| 694 node.target, | 667 node.target, |
| 695 node.selector, | 668 node.selector, |
| 696 insertReceiverArgument(getVariableUse(node.receiverRef), | 669 insertReceiverArgument(getVariableUse(node.receiverRef), |
| 697 translateArguments(node.argumentRefs)), | 670 translateArguments(node.argumentRefs)), |
| 698 node.sourceInformation); | 671 node.sourceInformation); |
| 699 } else { | 672 } else { |
| 700 return new InvokeMethodDirectly(getVariableUse(node.receiverRef), | 673 return new InvokeMethodDirectly( |
| 674 getVariableUse(node.receiverRef), |
| 701 node.target, | 675 node.target, |
| 702 node.selector, | 676 node.selector, |
| 703 translateArguments(node.argumentRefs), | 677 translateArguments(node.argumentRefs), |
| 704 node.sourceInformation); | 678 node.sourceInformation); |
| 705 } | 679 } |
| 706 } | 680 } |
| 707 | 681 |
| 708 Expression visitTypeCast(cps_ir.TypeCast node) { | 682 Expression visitTypeCast(cps_ir.TypeCast node) { |
| 709 Expression value = getVariableUse(node.valueRef); | 683 Expression value = getVariableUse(node.valueRef); |
| 710 List<Expression> typeArgs = translateArguments(node.typeArgumentRefs); | 684 List<Expression> typeArgs = translateArguments(node.typeArgumentRefs); |
| 711 return new TypeOperator(value, node.dartType, typeArgs, isTypeTest: false); | 685 return new TypeOperator(value, node.dartType, typeArgs, isTypeTest: false); |
| 712 } | 686 } |
| 713 | 687 |
| 714 Expression visitInvokeConstructor(cps_ir.InvokeConstructor node) { | 688 Expression visitInvokeConstructor(cps_ir.InvokeConstructor node) { |
| 715 List<Expression> arguments = translateArguments(node.argumentRefs); | 689 List<Expression> arguments = translateArguments(node.argumentRefs); |
| 716 return new InvokeConstructor( | 690 return new InvokeConstructor(node.dartType, node.target, node.selector, |
| 717 node.dartType, | 691 arguments, node.sourceInformation); |
| 718 node.target, | |
| 719 node.selector, | |
| 720 arguments, | |
| 721 node.sourceInformation); | |
| 722 } | 692 } |
| 723 | 693 |
| 724 visitForeignCode(cps_ir.ForeignCode node) { | 694 visitForeignCode(cps_ir.ForeignCode node) { |
| 725 List<Expression> arguments = | 695 List<Expression> arguments = |
| 726 node.argumentRefs.map(getVariableUse).toList(growable: false); | 696 node.argumentRefs.map(getVariableUse).toList(growable: false); |
| 727 List<bool> nullableArguments = node.argumentRefs | 697 List<bool> nullableArguments = node.argumentRefs |
| 728 .map((argument) => argument.definition.type.isNullable) | 698 .map((argument) => argument.definition.type.isNullable) |
| 729 .toList(growable: false); | 699 .toList(growable: false); |
| 730 if (node.codeTemplate.isExpression) { | 700 if (node.codeTemplate.isExpression) { |
| 731 return new ForeignExpression( | 701 return new ForeignExpression( |
| (...skipping 13 matching lines...) Expand all Loading... |
| 745 arguments, | 715 arguments, |
| 746 node.nativeBehavior, | 716 node.nativeBehavior, |
| 747 nullableArguments, | 717 nullableArguments, |
| 748 node.dependency, | 718 node.dependency, |
| 749 node.sourceInformation); | 719 node.sourceInformation); |
| 750 }; | 720 }; |
| 751 } | 721 } |
| 752 } | 722 } |
| 753 | 723 |
| 754 visitReceiverCheck(cps_ir.ReceiverCheck node) => (Statement next) { | 724 visitReceiverCheck(cps_ir.ReceiverCheck node) => (Statement next) { |
| 755 // The CPS IR uses 'isNullCheck' because the semantics are important. | 725 // The CPS IR uses 'isNullCheck' because the semantics are important. |
| 756 // In the Tree IR, syntax is more important, so the receiver check uses | 726 // In the Tree IR, syntax is more important, so the receiver check uses |
| 757 // "useInvoke" to denote if an invocation should be emitted. | 727 // "useInvoke" to denote if an invocation should be emitted. |
| 758 return new ReceiverCheck( | 728 return new ReceiverCheck( |
| 759 condition: getVariableUseOrNull(node.conditionRef), | 729 condition: getVariableUseOrNull(node.conditionRef), |
| 760 value: getVariableUse(node.valueRef), | 730 value: getVariableUse(node.valueRef), |
| 761 selector: node.selector, | 731 selector: node.selector, |
| 762 useSelector: node.useSelector, | 732 useSelector: node.useSelector, |
| 763 useInvoke: !node.isNullCheck, | 733 useInvoke: !node.isNullCheck, |
| 764 next: next, | 734 next: next, |
| 765 sourceInformation: node.sourceInformation); | 735 sourceInformation: node.sourceInformation); |
| 766 }; | 736 }; |
| 767 | 737 |
| 768 Expression visitGetLazyStatic(cps_ir.GetLazyStatic node) { | 738 Expression visitGetLazyStatic(cps_ir.GetLazyStatic node) { |
| 769 return new GetStatic.lazy(node.element, node.sourceInformation); | 739 return new GetStatic.lazy(node.element, node.sourceInformation); |
| 770 } | 740 } |
| 771 | 741 |
| 772 @override | 742 @override |
| 773 NodeCallback visitYield(cps_ir.Yield node) { | 743 NodeCallback visitYield(cps_ir.Yield node) { |
| 774 return (Statement next) { | 744 return (Statement next) { |
| 775 return new Yield(getVariableUse(node.inputRef), node.hasStar, next); | 745 return new Yield(getVariableUse(node.inputRef), node.hasStar, next); |
| 776 }; | 746 }; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 788 | 758 |
| 789 /********** UNUSED VISIT METHODS *************/ | 759 /********** UNUSED VISIT METHODS *************/ |
| 790 | 760 |
| 791 unexpectedNode(cps_ir.Node node) { | 761 unexpectedNode(cps_ir.Node node) { |
| 792 internalError(CURRENT_ELEMENT_SPANNABLE, 'Unexpected IR node: $node'); | 762 internalError(CURRENT_ELEMENT_SPANNABLE, 'Unexpected IR node: $node'); |
| 793 } | 763 } |
| 794 | 764 |
| 795 visitFunctionDefinition(cps_ir.FunctionDefinition node) { | 765 visitFunctionDefinition(cps_ir.FunctionDefinition node) { |
| 796 unexpectedNode(node); | 766 unexpectedNode(node); |
| 797 } | 767 } |
| 768 |
| 798 visitParameter(cps_ir.Parameter node) => unexpectedNode(node); | 769 visitParameter(cps_ir.Parameter node) => unexpectedNode(node); |
| 799 visitContinuation(cps_ir.Continuation node) => unexpectedNode(node); | 770 visitContinuation(cps_ir.Continuation node) => unexpectedNode(node); |
| 800 visitMutableVariable(cps_ir.MutableVariable node) => unexpectedNode(node); | 771 visitMutableVariable(cps_ir.MutableVariable node) => unexpectedNode(node); |
| 801 visitRethrow(cps_ir.Rethrow node) => unexpectedNode(node); | 772 visitRethrow(cps_ir.Rethrow node) => unexpectedNode(node); |
| 802 visitBoundsCheck(cps_ir.BoundsCheck node) => unexpectedNode(node); | 773 visitBoundsCheck(cps_ir.BoundsCheck node) => unexpectedNode(node); |
| 803 } | 774 } |
| OLD | NEW |