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 |