Chromium Code Reviews| 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 '../dart2jslib.dart' as dart2js; | 7 import '../dart2jslib.dart' as dart2js; |
| 8 import '../dart_types.dart'; | 8 import '../dart_types.dart'; |
| 9 import '../elements/elements.dart'; | 9 import '../elements/elements.dart'; |
| 10 import '../cps_ir/cps_ir_nodes.dart' as cps_ir; | 10 import '../cps_ir/cps_ir_nodes.dart' as cps_ir; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 60 /// A stack of singly-used labels that can be safely inlined at their use | 60 /// A stack of singly-used labels that can be safely inlined at their use |
| 61 /// site. | 61 /// site. |
| 62 /// | 62 /// |
| 63 /// Code for continuations with exactly one use is inlined at the use site. | 63 /// Code for continuations with exactly one use is inlined at the use site. |
| 64 /// This is not safe if the code is moved inside the scope of an exception | 64 /// This is not safe if the code is moved inside the scope of an exception |
| 65 /// handler (i.e., into a try block). We keep a stack of singly-referenced | 65 /// handler (i.e., into a try block). We keep a stack of singly-referenced |
| 66 /// continuations that are in scope without crossing a binding for a handler. | 66 /// continuations that are in scope without crossing a binding for a handler. |
| 67 List<cps_ir.Continuation> safeForInlining = <cps_ir.Continuation>[]; | 67 List<cps_ir.Continuation> safeForInlining = <cps_ir.Continuation>[]; |
| 68 | 68 |
| 69 ExecutableElement currentElement; | 69 ExecutableElement currentElement; |
| 70 cps_ir.Parameter thisParameter; | |
| 70 cps_ir.Continuation returnContinuation; | 71 cps_ir.Continuation returnContinuation; |
| 71 | 72 |
| 72 Builder parent; | 73 Builder parent; |
| 73 | 74 |
| 74 Builder(this.internalError, [this.parent]); | 75 Builder(this.internalError, [this.parent]); |
| 75 | 76 |
| 76 Builder createInnerBuilder() { | 77 Builder createInnerBuilder() { |
| 77 return new Builder(internalError, this); | 78 return new Builder(internalError, this); |
| 78 } | 79 } |
| 79 | 80 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 113 while (variables.length <= primitive.registerIndex) { | 114 while (variables.length <= primitive.registerIndex) { |
| 114 variables.add(new Variable(currentElement, primitive.hint)); | 115 variables.add(new Variable(currentElement, primitive.hint)); |
| 115 } | 116 } |
| 116 return variables[primitive.registerIndex]; | 117 return variables[primitive.registerIndex]; |
| 117 } | 118 } |
| 118 | 119 |
| 119 /// Obtains a reference to the tree Variable corresponding to the IR primitive | 120 /// Obtains a reference to the tree Variable corresponding to the IR primitive |
| 120 /// referred to by [reference]. | 121 /// referred to by [reference]. |
| 121 /// This increments the reference count for the given variable, so the | 122 /// This increments the reference count for the given variable, so the |
| 122 /// returned expression must be used in the tree. | 123 /// returned expression must be used in the tree. |
| 123 VariableUse getVariableUse(cps_ir.Reference<cps_ir.Primitive> reference) { | 124 Expression getVariableUse(cps_ir.Reference<cps_ir.Primitive> reference) { |
| 125 if (thisParameter != null && reference.definition == thisParameter) { | |
|
asgerf
2015/03/19 11:31:13
Seems unnecessary. Reference.definition should nev
sra1
2015/03/19 16:54:24
I'm going to keep as-is - you should not try to ma
| |
| 126 return new This(); | |
| 127 } | |
| 124 Variable variable = getVariable(reference.definition); | 128 Variable variable = getVariable(reference.definition); |
| 125 if (variable == null) { | 129 if (variable == null) { |
| 126 // Note: this may fail because you forgot to implement a visit-function | 130 // Note: this may fail because you forgot to implement a visit-function |
| 127 // in the RegisterAllocator. | 131 // in the RegisterAllocator. |
| 128 internalError( | 132 internalError( |
| 129 CURRENT_ELEMENT_SPANNABLE, | 133 CURRENT_ELEMENT_SPANNABLE, |
| 130 "Reference to ${reference.definition} has no register"); | 134 "Reference to ${reference.definition} has no register"); |
| 131 } | 135 } |
| 132 return new VariableUse(variable); | 136 return new VariableUse(variable); |
| 133 } | 137 } |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 163 Variable addFunctionParameter(cps_ir.Definition variable) { | 167 Variable addFunctionParameter(cps_ir.Definition variable) { |
| 164 if (variable is cps_ir.Parameter) { | 168 if (variable is cps_ir.Parameter) { |
| 165 return getVariable(variable); | 169 return getVariable(variable); |
| 166 } else { | 170 } else { |
| 167 return addMutableVariable(variable as cps_ir.MutableVariable); | 171 return addMutableVariable(variable as cps_ir.MutableVariable); |
| 168 } | 172 } |
| 169 } | 173 } |
| 170 | 174 |
| 171 FunctionDefinition buildFunction(cps_ir.FunctionDefinition node) { | 175 FunctionDefinition buildFunction(cps_ir.FunctionDefinition node) { |
| 172 currentElement = node.element; | 176 currentElement = node.element; |
| 177 thisParameter = node.thisParameter; | |
| 173 List<Variable> parameters = | 178 List<Variable> parameters = |
| 174 node.parameters.map(addFunctionParameter).toList(); | 179 node.parameters.map(addFunctionParameter).toList(); |
| 175 Statement body; | 180 Statement body; |
| 176 if (!node.isAbstract) { | 181 if (!node.isAbstract) { |
| 177 returnContinuation = node.body.returnContinuation; | 182 returnContinuation = node.body.returnContinuation; |
| 178 phiTempVar = new Variable(node.element, null); | 183 phiTempVar = new Variable(node.element, null); |
| 179 body = visit(node.body); | 184 body = visit(node.body); |
| 180 } | 185 } |
| 181 | 186 |
| 182 return new FunctionDefinition(node.element, parameters, | 187 return new FunctionDefinition(node.element, parameters, |
| 183 body, node.localConstants, node.defaultParameterValues); | 188 body, node.localConstants, node.defaultParameterValues); |
| 184 } | 189 } |
| 185 | 190 |
| 186 ConstructorDefinition buildConstructor(cps_ir.ConstructorDefinition node) { | 191 ConstructorDefinition buildConstructor(cps_ir.ConstructorDefinition node) { |
| 187 currentElement = node.element; | 192 currentElement = node.element; |
| 193 thisParameter = node.thisParameter; | |
| 188 List<Variable> parameters = | 194 List<Variable> parameters = |
| 189 node.parameters.map(addFunctionParameter).toList(); | 195 node.parameters.map(addFunctionParameter).toList(); |
| 190 List<Initializer> initializers; | 196 List<Initializer> initializers; |
| 191 Statement body; | 197 Statement body; |
| 192 if (!node.isAbstract) { | 198 if (!node.isAbstract) { |
| 193 initializers = node.initializers.map(visit).toList(); | 199 initializers = node.initializers.map(visit).toList(); |
| 194 returnContinuation = node.body.returnContinuation; | 200 returnContinuation = node.body.returnContinuation; |
| 195 | 201 |
| 196 phiTempVar = new Variable(node.element, null); | 202 phiTempVar = new Variable(node.element, null); |
| 197 body = visit(node.body); | 203 body = visit(node.body); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 212 return new List<Expression>.generate(args.length, | 218 return new List<Expression>.generate(args.length, |
| 213 (int index) => getVariableUse(args[index]), | 219 (int index) => getVariableUse(args[index]), |
| 214 growable: false); | 220 growable: false); |
| 215 } | 221 } |
| 216 | 222 |
| 217 /// Returns the list of variables corresponding to the arguments to a join | 223 /// Returns the list of variables corresponding to the arguments to a join |
| 218 /// continuation. | 224 /// continuation. |
| 219 /// | 225 /// |
| 220 /// The `readCount` of these variables will not be incremented. Instead, | 226 /// The `readCount` of these variables will not be incremented. Instead, |
| 221 /// [buildPhiAssignments] will handle the increment, if necessary. | 227 /// [buildPhiAssignments] will handle the increment, if necessary. |
| 222 List<Variable> translatePhiArguments(List<cps_ir.Reference> args) { | 228 /* List<Variable> translatePhiArguments(List<cps_ir.Reference> args) { |
| 223 return new List<Variable>.generate(args.length, | 229 return new List<Variable>.generate(args.length, |
| 224 (int index) => getVariable(args[index].definition), | 230 (int index) => getVariable(args[index].definition), |
| 225 growable: false); | 231 growable: false); |
| 226 } | 232 }*/ |
| 227 | 233 |
| 228 Statement buildContinuationAssignment( | 234 Statement buildContinuationAssignment( |
| 229 cps_ir.Parameter parameter, | 235 cps_ir.Parameter parameter, |
| 230 Expression argument, | 236 Expression argument, |
| 231 Statement buildRest()) { | 237 Statement buildRest()) { |
| 232 Variable variable = getVariable(parameter); | 238 Variable variable = getVariable(parameter); |
| 233 Statement assignment; | 239 Statement assignment; |
| 234 if (variable == null) { | 240 if (variable == null) { |
| 235 assignment = new ExpressionStatement(argument, null); | 241 assignment = new ExpressionStatement(argument, null); |
| 236 } else { | 242 } else { |
| 237 assignment = new Assign(variable, argument, null); | 243 assignment = new Assign(variable, argument, null); |
| 238 } | 244 } |
| 239 assignment.next = buildRest(); | 245 assignment.next = buildRest(); |
| 240 return assignment; | 246 return assignment; |
| 241 } | 247 } |
| 242 | 248 |
| 243 /// Simultaneously assigns each argument to the corresponding parameter, | 249 /// Simultaneously assigns each argument to the corresponding parameter, |
| 244 /// then continues at the statement created by [buildRest]. | 250 /// then continues at the statement created by [buildRest]. |
| 245 Statement buildPhiAssignments( | 251 Statement buildPhiAssignments( |
| 246 List<cps_ir.Parameter> parameters, | 252 List<cps_ir.Parameter> parameters, |
| 247 List<Variable> arguments, | 253 List<Expression> arguments, |
| 248 Statement buildRest()) { | 254 Statement buildRest()) { |
| 249 assert(parameters.length == arguments.length); | 255 assert(parameters.length == arguments.length); |
| 250 // We want a parallel assignment to all parameters simultaneously. | 256 // We want a parallel assignment to all parameters simultaneously. |
| 251 // Since we do not have parallel assignments in dart_tree, we must linearize | 257 // Since we do not have parallel assignments in dart_tree, we must linearize |
| 252 // the assignments without attempting to read a previously-overwritten | 258 // the assignments without attempting to read a previously-overwritten |
| 253 // value. For example {x,y = y,x} cannot be linearized to {x = y; y = x}, | 259 // value. For example {x,y = y,x} cannot be linearized to {x = y; y = x}, |
| 254 // for this we must introduce a temporary variable: {t = x; x = y; y = t}. | 260 // for this we must introduce a temporary variable: {t = x; x = y; y = t}. |
| 255 | 261 |
| 256 // [rightHand] is the inverse of [arguments], that is, it maps variables | 262 // [rightHand] is the inverse of [arguments], that is, it maps variables |
| 257 // to the assignments on which is occurs as the right-hand side. | 263 // to the assignments on which is occurs as the right-hand side. |
| 258 Map<Variable, List<int>> rightHand = <Variable, List<int>>{}; | 264 Map<Variable, List<int>> rightHand = <Variable, List<int>>{}; |
| 259 for (int i = 0; i < parameters.length; i++) { | 265 for (int i = 0; i < parameters.length; i++) { |
| 260 Variable param = getVariable(parameters[i]); | 266 Variable param = getVariable(parameters[i]); |
| 261 Variable arg = arguments[i]; | 267 Expression arg = arguments[i]; |
| 262 if (param == null || param == arg) { | 268 if (arg is VariableUse) { |
| 263 continue; // No assignment necessary. | 269 if (param == null || param == arg.variable) { |
| 270 // No assignment necessary. | |
| 271 --arg.variable.readCount; | |
| 272 continue; | |
| 273 } | |
| 274 // v1 = v0 | |
| 275 List<int> list = rightHand[arg.variable]; | |
| 276 if (list == null) { | |
| 277 rightHand[arg.variable] = list = <int>[]; | |
| 278 } | |
| 279 list.add(i); | |
| 280 } else { | |
| 281 // v1 = this; | |
| 264 } | 282 } |
| 265 List<int> list = rightHand[arg]; | |
| 266 if (list == null) { | |
| 267 rightHand[arg] = list = <int>[]; | |
| 268 } | |
| 269 list.add(i); | |
| 270 } | 283 } |
| 271 | 284 |
| 272 Statement first, current; | 285 Statement first, current; |
| 273 void addAssignment(Variable dst, Variable src) { | 286 void addAssignment(Variable dst, Expression src) { |
| 274 if (first == null) { | 287 if (first == null) { |
| 275 first = current = new Assign(dst, new VariableUse(src), null); | 288 first = current = new Assign(dst, src, null); |
| 276 } else { | 289 } else { |
| 277 current = current.next = new Assign(dst, new VariableUse(src), null); | 290 current = current.next = new Assign(dst, src, null); |
| 278 } | 291 } |
| 279 } | 292 } |
| 280 | 293 |
| 281 List<Variable> assignmentSrc = new List<Variable>(parameters.length); | 294 List<Expression> assignmentSrc = new List<Expression>(parameters.length); |
| 282 List<bool> done = new List<bool>(parameters.length); | 295 List<bool> done = new List<bool>.filled(parameters.length, false); |
| 283 void visitAssignment(int i) { | 296 void visitAssignment(int i) { |
| 284 if (done[i] == true) { | 297 if (done[i]) { |
| 285 return; | 298 return; |
| 286 } | 299 } |
| 287 Variable param = getVariable(parameters[i]); | 300 Variable param = getVariable(parameters[i]); |
| 288 Variable arg = arguments[i]; | 301 Expression arg = arguments[i]; |
| 289 if (param == null || param == arg) { | 302 if (param == null || (arg is VariableUse && param == arg.variable)) { |
| 290 return; // No assignment necessary. | 303 return; // No assignment necessary. |
| 291 } | 304 } |
| 292 if (assignmentSrc[i] != null) { | 305 if (assignmentSrc[i] != null) { |
| 293 // Cycle found; store argument in a temporary variable. | 306 // Cycle found; store argument in a temporary variable. |
| 294 // The temporary will then be used as right-hand side when the | 307 // The temporary will then be used as right-hand side when the |
| 295 // assignment gets added. | 308 // assignment gets added. |
| 296 if (assignmentSrc[i] != phiTempVar) { // Only move to temporary once. | 309 VariableUse source = assignmentSrc[i]; |
| 297 assignmentSrc[i] = phiTempVar; | 310 if (source.variable != phiTempVar) { // Only move to temporary once. |
| 311 assignmentSrc[i] = new VariableUse(phiTempVar); | |
| 298 addAssignment(phiTempVar, arg); | 312 addAssignment(phiTempVar, arg); |
| 299 } | 313 } |
| 300 return; | 314 return; |
| 301 } | 315 } |
| 302 assignmentSrc[i] = arg; | 316 assignmentSrc[i] = arg; |
| 303 List<int> paramUses = rightHand[param]; | 317 List<int> paramUses = rightHand[param]; |
| 304 if (paramUses != null) { | 318 if (paramUses != null) { |
| 305 for (int useIndex in paramUses) { | 319 for (int useIndex in paramUses) { |
| 306 visitAssignment(useIndex); | 320 visitAssignment(useIndex); |
| 307 } | 321 } |
| 308 } | 322 } |
| 309 addAssignment(param, assignmentSrc[i]); | 323 addAssignment(param, assignmentSrc[i]); |
| 310 done[i] = true; | 324 done[i] = true; |
| 311 } | 325 } |
| 312 | 326 |
| 313 for (int i = 0; i < parameters.length; i++) { | 327 for (int i = 0; i < parameters.length; i++) { |
| 314 if (done[i] == null) { | 328 if (!done[i]) { |
| 315 visitAssignment(i); | 329 visitAssignment(i); |
| 316 } | 330 } |
| 317 } | 331 } |
| 318 | 332 |
| 319 if (first == null) { | 333 if (first == null) { |
| 320 first = buildRest(); | 334 first = buildRest(); |
| 321 } else { | 335 } else { |
| 322 current.next = buildRest(); | 336 current.next = buildRest(); |
| 323 } | 337 } |
| 324 return first; | 338 return first; |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 519 // Invocations of the return continuation are translated to returns. | 533 // Invocations of the return continuation are translated to returns. |
| 520 // Other continuation invocations are replaced with assignments of the | 534 // Other continuation invocations are replaced with assignments of the |
| 521 // arguments to formal parameter variables, followed by the body if | 535 // arguments to formal parameter variables, followed by the body if |
| 522 // the continuation is singly reference or a break if it is multiply | 536 // the continuation is singly reference or a break if it is multiply |
| 523 // referenced. | 537 // referenced. |
| 524 cps_ir.Continuation cont = node.continuation.definition; | 538 cps_ir.Continuation cont = node.continuation.definition; |
| 525 if (cont == returnContinuation) { | 539 if (cont == returnContinuation) { |
| 526 assert(node.arguments.length == 1); | 540 assert(node.arguments.length == 1); |
| 527 return new Return(getVariableUse(node.arguments.single)); | 541 return new Return(getVariableUse(node.arguments.single)); |
| 528 } else { | 542 } else { |
| 529 List<Variable> arguments = translatePhiArguments(node.arguments); | 543 List<Expression> arguments = translateArguments(node.arguments); |
| 530 return buildPhiAssignments(cont.parameters, arguments, | 544 return buildPhiAssignments(cont.parameters, arguments, |
| 531 () { | 545 () { |
| 532 // Translate invocations of recursive and non-recursive | 546 // Translate invocations of recursive and non-recursive |
| 533 // continuations differently. | 547 // continuations differently. |
| 534 // * Non-recursive continuations | 548 // * Non-recursive continuations |
| 535 // - If there is one use, translate the continuation body | 549 // - If there is one use, translate the continuation body |
| 536 // inline at the invocation site. | 550 // inline at the invocation site. |
| 537 // - If there are multiple uses, translate to Break. | 551 // - If there are multiple uses, translate to Break. |
| 538 // * Recursive continuations | 552 // * Recursive continuations |
| 539 // - There is a single non-recursive invocation. Translate | 553 // - There is a single non-recursive invocation. Translate |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 568 assert(cont.parameters.isEmpty); | 582 assert(cont.parameters.isEmpty); |
| 569 elseStatement = | 583 elseStatement = |
| 570 cont.hasExactlyOneUse ? visit(cont.body) : new Break(labels[cont]); | 584 cont.hasExactlyOneUse ? visit(cont.body) : new Break(labels[cont]); |
| 571 return new If(condition, thenStatement, elseStatement); | 585 return new If(condition, thenStatement, elseStatement); |
| 572 } | 586 } |
| 573 | 587 |
| 574 Expression visitConstant(cps_ir.Constant node) { | 588 Expression visitConstant(cps_ir.Constant node) { |
| 575 return new Constant(node.expression); | 589 return new Constant(node.expression); |
| 576 } | 590 } |
| 577 | 591 |
| 578 Expression visitThis(cps_ir.This node) { | |
| 579 return new This(); | |
| 580 } | |
| 581 | |
| 582 Expression visitReifyTypeVar(cps_ir.ReifyTypeVar node) { | 592 Expression visitReifyTypeVar(cps_ir.ReifyTypeVar node) { |
| 583 return new ReifyTypeVar(node.typeVariable); | 593 return new ReifyTypeVar(node.typeVariable); |
| 584 } | 594 } |
| 585 | 595 |
| 586 Expression visitLiteralList(cps_ir.LiteralList node) { | 596 Expression visitLiteralList(cps_ir.LiteralList node) { |
| 587 return new LiteralList( | 597 return new LiteralList( |
| 588 node.type, | 598 node.type, |
| 589 translateArguments(node.values)); | 599 translateArguments(node.values)); |
| 590 } | 600 } |
| 591 | 601 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 640 } | 650 } |
| 641 | 651 |
| 642 Expression visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) { | 652 Expression visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) { |
| 643 return new ReifyRuntimeType(getVariableUse(node.value)); | 653 return new ReifyRuntimeType(getVariableUse(node.value)); |
| 644 } | 654 } |
| 645 | 655 |
| 646 Expression visitReadTypeVariable(cps_ir.ReadTypeVariable node) { | 656 Expression visitReadTypeVariable(cps_ir.ReadTypeVariable node) { |
| 647 return new ReadTypeVariable(node.variable, getVariableUse(node.target)); | 657 return new ReadTypeVariable(node.variable, getVariableUse(node.target)); |
| 648 } | 658 } |
| 649 } | 659 } |
| OLD | NEW |