| 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 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 112 /// referred to by [reference]. | 112 /// referred to by [reference]. |
| 113 /// This increments the reference count for the given variable, so the | 113 /// This increments the reference count for the given variable, so the |
| 114 /// returned expression must be used in the tree. | 114 /// returned expression must be used in the tree. |
| 115 Expression getVariableUse(cps_ir.Reference<cps_ir.Primitive> reference) { | 115 Expression getVariableUse(cps_ir.Reference<cps_ir.Primitive> reference) { |
| 116 if (thisParameter != null && reference.definition == thisParameter) { | 116 if (thisParameter != null && reference.definition == thisParameter) { |
| 117 return new This(); | 117 return new This(); |
| 118 } | 118 } |
| 119 return new VariableUse(getVariable(reference.definition)); | 119 return new VariableUse(getVariable(reference.definition)); |
| 120 } | 120 } |
| 121 | 121 |
| 122 RootNode build(cps_ir.RootNode node) { | |
| 123 // TODO(asgerf): Don't have build AND buildXXX as public API. | |
| 124 if (node is cps_ir.FieldDefinition) { | |
| 125 return buildField(node); | |
| 126 } else if (node is cps_ir.ConstructorDefinition) { | |
| 127 return buildConstructor(node); | |
| 128 } else { | |
| 129 assert(dart2js.invariant( | |
| 130 CURRENT_ELEMENT_SPANNABLE, | |
| 131 node is cps_ir.FunctionDefinition, | |
| 132 message: 'expected FunctionDefinition or FieldDefinition, ' | |
| 133 ' found $node')); | |
| 134 return buildFunction(node); | |
| 135 } | |
| 136 } | |
| 137 | |
| 138 FieldDefinition buildField(cps_ir.FieldDefinition node) { | |
| 139 Statement body; | |
| 140 if (!node.isEmpty) { | |
| 141 currentElement = node.element; | |
| 142 returnContinuation = node.body.returnContinuation; | |
| 143 | |
| 144 phiTempVar = new Variable(node.element, null); | |
| 145 | |
| 146 body = visit(node.body); | |
| 147 } | |
| 148 return new FieldDefinition(node.element, body); | |
| 149 } | |
| 150 | |
| 151 Variable addFunctionParameter(cps_ir.Definition variable) { | 122 Variable addFunctionParameter(cps_ir.Definition variable) { |
| 152 if (variable is cps_ir.Parameter) { | 123 if (variable is cps_ir.Parameter) { |
| 153 return getVariable(variable); | 124 return getVariable(variable); |
| 154 } else { | 125 } else { |
| 155 return addMutableVariable(variable as cps_ir.MutableVariable) | 126 return addMutableVariable(variable as cps_ir.MutableVariable) |
| 156 ..isCaptured = true; | 127 ..isCaptured = true; |
| 157 } | 128 } |
| 158 } | 129 } |
| 159 | 130 |
| 160 FunctionDefinition buildFunction(cps_ir.FunctionDefinition node) { | 131 FunctionDefinition buildFunction(cps_ir.FunctionDefinition node) { |
| 161 currentElement = node.element; | 132 currentElement = node.element; |
| 162 if (parent != null) { | 133 if (parent != null) { |
| 163 // Local function's 'this' refers to enclosing method's 'this' | 134 // Local function's 'this' refers to enclosing method's 'this' |
| 164 thisParameter = parent.thisParameter; | 135 thisParameter = parent.thisParameter; |
| 165 } else { | 136 } else { |
| 166 thisParameter = node.thisParameter; | 137 thisParameter = node.thisParameter; |
| 167 } | 138 } |
| 168 List<Variable> parameters = | 139 List<Variable> parameters = |
| 169 node.parameters.map(addFunctionParameter).toList(); | 140 node.parameters.map(addFunctionParameter).toList(); |
| 170 Statement body; | 141 returnContinuation = node.returnContinuation; |
| 171 if (!node.isEmpty) { | 142 phiTempVar = new Variable(node.element, null); |
| 172 returnContinuation = node.body.returnContinuation; | 143 Statement body = visit(node.body); |
| 173 phiTempVar = new Variable(node.element, null); | 144 return new FunctionDefinition(node.element, parameters, body); |
| 174 body = visit(node.body); | |
| 175 } | |
| 176 | |
| 177 return new FunctionDefinition(node.element, parameters, | |
| 178 body, node.localConstants, node.defaultParameterValues); | |
| 179 } | |
| 180 | |
| 181 ConstructorDefinition buildConstructor(cps_ir.ConstructorDefinition node) { | |
| 182 currentElement = node.element; | |
| 183 thisParameter = node.thisParameter; | |
| 184 List<Variable> parameters = | |
| 185 node.parameters.map(addFunctionParameter).toList(); | |
| 186 List<Initializer> initializers; | |
| 187 Statement body; | |
| 188 if (!node.isEmpty) { | |
| 189 initializers = node.initializers.map(visit).toList(); | |
| 190 returnContinuation = node.body.returnContinuation; | |
| 191 | |
| 192 phiTempVar = new Variable(node.element, null); | |
| 193 body = visit(node.body); | |
| 194 } | |
| 195 | |
| 196 return new ConstructorDefinition(node.element, parameters, | |
| 197 body, initializers, node.localConstants, node.defaultParameterValues); | |
| 198 } | 145 } |
| 199 | 146 |
| 200 /// 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 |
| 201 /// call or similar construct. | 148 /// call or similar construct. |
| 202 /// | 149 /// |
| 203 /// The `readCount` for these variables will be incremented. | 150 /// The `readCount` for these variables will be incremented. |
| 204 /// | 151 /// |
| 205 /// 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 |
| 206 /// on the list during the rewrite phases. | 153 /// on the list during the rewrite phases. |
| 207 List<Expression> translateArguments(List<cps_ir.Reference> args) { | 154 List<Expression> translateArguments(List<cps_ir.Reference> args) { |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 visitInterceptor(cps_ir.Interceptor node) => unexpectedNode(node); | 274 visitInterceptor(cps_ir.Interceptor node) => unexpectedNode(node); |
| 328 visitCreateInstance(cps_ir.CreateInstance node) => unexpectedNode(node); | 275 visitCreateInstance(cps_ir.CreateInstance node) => unexpectedNode(node); |
| 329 visitGetField(cps_ir.GetField node) => unexpectedNode(node); | 276 visitGetField(cps_ir.GetField node) => unexpectedNode(node); |
| 330 visitCreateBox(cps_ir.CreateBox node) => unexpectedNode(node); | 277 visitCreateBox(cps_ir.CreateBox node) => unexpectedNode(node); |
| 331 visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) { | 278 visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) { |
| 332 return unexpectedNode(node); | 279 return unexpectedNode(node); |
| 333 } | 280 } |
| 334 | 281 |
| 335 // Executable definitions are not visited directly. They have 'build' | 282 // Executable definitions are not visited directly. They have 'build' |
| 336 // functions as entry points. | 283 // functions as entry points. |
| 337 visitFieldDefinition(cps_ir.FieldDefinition node) { | |
| 338 return unexpectedNode(node); | |
| 339 } | |
| 340 visitFunctionDefinition(cps_ir.FunctionDefinition node) { | 284 visitFunctionDefinition(cps_ir.FunctionDefinition node) { |
| 341 return unexpectedNode(node); | 285 return unexpectedNode(node); |
| 342 } | 286 } |
| 343 visitConstructorDefinition(cps_ir.ConstructorDefinition node) { | |
| 344 return unexpectedNode(node); | |
| 345 } | |
| 346 | |
| 347 Initializer visitFieldInitializer(cps_ir.FieldInitializer node) { | |
| 348 returnContinuation = node.body.returnContinuation; | |
| 349 return new FieldInitializer(node.element, visit(node.body.body)); | |
| 350 } | |
| 351 | |
| 352 Initializer visitSuperInitializer(cps_ir.SuperInitializer node) { | |
| 353 List<Statement> arguments = | |
| 354 node.arguments.map((cps_ir.Body argument) { | |
| 355 returnContinuation = argument.returnContinuation; | |
| 356 return visit(argument.body); | |
| 357 }).toList(); | |
| 358 return new SuperInitializer(node.target, node.selector, arguments); | |
| 359 } | |
| 360 | 287 |
| 361 Statement visitLetPrim(cps_ir.LetPrim node) { | 288 Statement visitLetPrim(cps_ir.LetPrim node) { |
| 362 Variable variable = getVariable(node.primitive); | 289 Variable variable = getVariable(node.primitive); |
| 363 | 290 |
| 364 // Don't translate unused primitives. | 291 // Don't translate unused primitives. |
| 365 if (variable == null) return visit(node.body); | 292 if (variable == null) return visit(node.body); |
| 366 | 293 |
| 367 Node definition = visit(node.primitive); | 294 Expression value = visit(node.primitive); |
| 368 | 295 return Assign.makeStatement(variable, value, visit(node.body)); |
| 369 // visitPrimitive returns a Statement without successor if it cannot occur | |
| 370 // in expression context (currently only the case for FunctionDeclarations). | |
| 371 if (definition is Statement) { | |
| 372 definition.next = visit(node.body); | |
| 373 return definition; | |
| 374 } else { | |
| 375 return Assign.makeStatement(variable, definition, visit(node.body)); | |
| 376 } | |
| 377 } | |
| 378 | |
| 379 Statement visitBody(cps_ir.Body node) { | |
| 380 return visit(node.body); | |
| 381 } | 296 } |
| 382 | 297 |
| 383 Statement visitLetCont(cps_ir.LetCont node) { | 298 Statement visitLetCont(cps_ir.LetCont node) { |
| 384 // Introduce labels for continuations that need them. | 299 // Introduce labels for continuations that need them. |
| 385 int safeForInliningLengthOnEntry = safeForInlining.length; | 300 int safeForInliningLengthOnEntry = safeForInlining.length; |
| 386 for (cps_ir.Continuation continuation in node.continuations) { | 301 for (cps_ir.Continuation continuation in node.continuations) { |
| 387 if (continuation.hasMultipleUses) { | 302 if (continuation.hasMultipleUses) { |
| 388 labels[continuation] = new Label(); | 303 labels[continuation] = new Label(); |
| 389 } else { | 304 } else { |
| 390 safeForInlining.add(continuation); | 305 safeForInlining.add(continuation); |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 479 () => visit(cont.body) : () => new Break(labels[cont]); | 394 () => visit(cont.body) : () => new Break(labels[cont]); |
| 480 return buildContinuationAssignment(cont.parameters.single, expression, | 395 return buildContinuationAssignment(cont.parameters.single, expression, |
| 481 nextBuilder); | 396 nextBuilder); |
| 482 } | 397 } |
| 483 } | 398 } |
| 484 | 399 |
| 485 Statement visitLetMutable(cps_ir.LetMutable node) { | 400 Statement visitLetMutable(cps_ir.LetMutable node) { |
| 486 Variable variable = addMutableVariable(node.variable); | 401 Variable variable = addMutableVariable(node.variable); |
| 487 Expression value = getVariableUse(node.value); | 402 Expression value = getVariableUse(node.value); |
| 488 Statement body = visit(node.body); | 403 Statement body = visit(node.body); |
| 489 // If the variable was captured by an inner function in the body, this | |
| 490 // must be declared here so we assign to a fresh copy of the variable. | |
| 491 if (variable.isCaptured) { | |
| 492 return new VariableDeclaration(variable, value, body); | |
| 493 } | |
| 494 return Assign.makeStatement(variable, value, body); | 404 return Assign.makeStatement(variable, value, body); |
| 495 } | 405 } |
| 496 | 406 |
| 497 Expression visitGetMutableVariable(cps_ir.GetMutableVariable node) { | 407 Expression visitGetMutableVariable(cps_ir.GetMutableVariable node) { |
| 498 return getMutableVariableUse(node.variable); | 408 return getMutableVariableUse(node.variable); |
| 499 } | 409 } |
| 500 | 410 |
| 501 Statement visitSetMutableVariable(cps_ir.SetMutableVariable node) { | 411 Statement visitSetMutableVariable(cps_ir.SetMutableVariable node) { |
| 502 Variable variable = getMutableVariable(node.variable.definition); | 412 Variable variable = getMutableVariable(node.variable.definition); |
| 503 Expression value = getVariableUse(node.value); | 413 Expression value = getVariableUse(node.value); |
| 504 return Assign.makeStatement(variable, value, visit(node.body)); | 414 return Assign.makeStatement(variable, value, visit(node.body)); |
| 505 } | 415 } |
| 506 | 416 |
| 507 Statement visitDeclareFunction(cps_ir.DeclareFunction node) { | |
| 508 Variable variable = addMutableVariable(node.variable); | |
| 509 FunctionDefinition function = makeSubFunction(node.definition); | |
| 510 return new FunctionDeclaration(variable, function, visit(node.body)); | |
| 511 } | |
| 512 | |
| 513 Statement visitTypeOperator(cps_ir.TypeOperator node) { | 417 Statement visitTypeOperator(cps_ir.TypeOperator node) { |
| 514 Expression value = getVariableUse(node.value); | 418 Expression value = getVariableUse(node.value); |
| 515 List<Expression> typeArgs = translateArguments(node.typeArguments); | 419 List<Expression> typeArgs = translateArguments(node.typeArguments); |
| 516 Expression concat = | 420 Expression concat = |
| 517 new TypeOperator(value, node.type, typeArgs, | 421 new TypeOperator(value, node.type, typeArgs, |
| 518 isTypeTest: node.isTypeTest); | 422 isTypeTest: node.isTypeTest); |
| 519 return continueWithExpression(node.continuation, concat); | 423 return continueWithExpression(node.continuation, concat); |
| 520 } | 424 } |
| 521 | 425 |
| 522 Statement visitInvokeConstructor(cps_ir.InvokeConstructor node) { | 426 Statement visitInvokeConstructor(cps_ir.InvokeConstructor node) { |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 582 assert(cont.parameters.isEmpty); | 486 assert(cont.parameters.isEmpty); |
| 583 elseStatement = | 487 elseStatement = |
| 584 cont.hasExactlyOneUse ? visit(cont.body) : new Break(labels[cont]); | 488 cont.hasExactlyOneUse ? visit(cont.body) : new Break(labels[cont]); |
| 585 return new If(condition, thenStatement, elseStatement); | 489 return new If(condition, thenStatement, elseStatement); |
| 586 } | 490 } |
| 587 | 491 |
| 588 Expression visitConstant(cps_ir.Constant node) { | 492 Expression visitConstant(cps_ir.Constant node) { |
| 589 return new Constant(node.expression); | 493 return new Constant(node.expression); |
| 590 } | 494 } |
| 591 | 495 |
| 592 Expression visitReifyTypeVar(cps_ir.ReifyTypeVar node) { | |
| 593 return new ReifyTypeVar(node.typeVariable); | |
| 594 } | |
| 595 | |
| 596 Expression visitLiteralList(cps_ir.LiteralList node) { | 496 Expression visitLiteralList(cps_ir.LiteralList node) { |
| 597 return new LiteralList( | 497 return new LiteralList( |
| 598 node.type, | 498 node.type, |
| 599 translateArguments(node.values)); | 499 translateArguments(node.values)); |
| 600 } | 500 } |
| 601 | 501 |
| 602 Expression visitLiteralMap(cps_ir.LiteralMap node) { | 502 Expression visitLiteralMap(cps_ir.LiteralMap node) { |
| 603 return new LiteralMap( | 503 return new LiteralMap( |
| 604 node.type, | 504 node.type, |
| 605 new List<LiteralMapEntry>.generate(node.entries.length, (int index) { | 505 new List<LiteralMapEntry>.generate(node.entries.length, (int index) { |
| 606 return new LiteralMapEntry( | 506 return new LiteralMapEntry( |
| 607 getVariableUse(node.entries[index].key), | 507 getVariableUse(node.entries[index].key), |
| 608 getVariableUse(node.entries[index].value)); | 508 getVariableUse(node.entries[index].value)); |
| 609 }) | 509 }) |
| 610 ); | 510 ); |
| 611 } | 511 } |
| 612 | 512 |
| 613 FunctionDefinition makeSubFunction(cps_ir.FunctionDefinition function) { | 513 FunctionDefinition makeSubFunction(cps_ir.FunctionDefinition function) { |
| 614 return createInnerBuilder().buildFunction(function); | 514 return createInnerBuilder().buildFunction(function); |
| 615 } | 515 } |
| 616 | 516 |
| 617 Node visitCreateFunction(cps_ir.CreateFunction node) { | 517 Expression visitCreateFunction(cps_ir.CreateFunction node) { |
| 618 FunctionDefinition def = makeSubFunction(node.definition); | 518 FunctionDefinition def = makeSubFunction(node.definition); |
| 619 FunctionType type = node.definition.element.type; | 519 FunctionType type = node.definition.element.type; |
| 620 bool hasReturnType = !type.returnType.treatAsDynamic; | 520 bool hasReturnType = !type.returnType.treatAsDynamic; |
| 621 if (hasReturnType) { | 521 return new FunctionExpression(def); |
| 622 // This function cannot occur in expression context. | |
| 623 // The successor will be filled in by visitLetPrim. | |
| 624 return new FunctionDeclaration(getVariable(node), def, null); | |
| 625 } else { | |
| 626 return new FunctionExpression(def); | |
| 627 } | |
| 628 } | 522 } |
| 629 | 523 |
| 630 visitParameter(cps_ir.Parameter node) { | 524 visitParameter(cps_ir.Parameter node) { |
| 631 // Continuation parameters are not visited (continuations themselves are | 525 // Continuation parameters are not visited (continuations themselves are |
| 632 // not visited yet). | 526 // not visited yet). |
| 633 unexpectedNode(node); | 527 unexpectedNode(node); |
| 634 } | 528 } |
| 635 | 529 |
| 636 visitContinuation(cps_ir.Continuation node) { | 530 visitContinuation(cps_ir.Continuation node) { |
| 637 // Until continuations with multiple uses are supported, they are not | 531 // Until continuations with multiple uses are supported, they are not |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 677 | 571 |
| 678 Statement visitSetStatic(cps_ir.SetStatic node) { | 572 Statement visitSetStatic(cps_ir.SetStatic node) { |
| 679 SetStatic setStatic = new SetStatic( | 573 SetStatic setStatic = new SetStatic( |
| 680 node.element, | 574 node.element, |
| 681 getVariableUse(node.value), | 575 getVariableUse(node.value), |
| 682 node.sourceInformation); | 576 node.sourceInformation); |
| 683 return new ExpressionStatement(setStatic, visit(node.body)); | 577 return new ExpressionStatement(setStatic, visit(node.body)); |
| 684 } | 578 } |
| 685 } | 579 } |
| 686 | 580 |
| OLD | NEW |