| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 // IrNodes are kept in a separate library to have precise control over their | 5 // IrNodes are kept in a separate library to have precise control over their |
| 6 // dependencies on other parts of the system. | 6 // dependencies on other parts of the system. |
| 7 library dart2js.ir_nodes; | 7 library dart2js.ir_nodes; |
| 8 | 8 |
| 9 import '../constants/expressions.dart'; | 9 import '../constants/expressions.dart'; |
| 10 import '../constants/values.dart' as values show ConstantValue; | 10 import '../constants/values.dart' as values show ConstantValue; |
| 11 import '../dart2jslib.dart' as dart2js show invariant; | 11 import '../dart2jslib.dart' as dart2js show invariant; |
| 12 import '../elements/elements.dart'; | 12 import '../elements/elements.dart'; |
| 13 import '../universe/universe.dart' show Selector, SelectorKind; | 13 import '../universe/universe.dart' show Selector, SelectorKind; |
| 14 import '../dart_types.dart' show DartType, GenericType; | 14 import '../dart_types.dart' show DartType, GenericType; |
| 15 import '../cps_ir/optimizers.dart'; | 15 import '../cps_ir/optimizers.dart'; |
| 16 import '../closure.dart' show ClosureClassElement; |
| 16 | 17 |
| 17 abstract class Node { | 18 abstract class Node { |
| 18 /// A pointer to the parent node. Is null until set by optimization passes. | 19 /// A pointer to the parent node. Is null until set by optimization passes. |
| 19 Node parent; | 20 Node parent; |
| 20 | 21 |
| 21 accept(Visitor visitor); | 22 accept(Visitor visitor); |
| 22 } | 23 } |
| 23 | 24 |
| 24 abstract class Expression extends Node { | 25 abstract class Expression extends Node { |
| 25 Expression plug(Expression expr) => throw 'impossible'; | 26 Expression plug(Expression expr) => throw 'impossible'; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 52 | 53 |
| 53 /// An expression that cannot throw or diverge and has no side-effects. | 54 /// An expression that cannot throw or diverge and has no side-effects. |
| 54 /// All primitives are named using the identity of the [Primitive] object. | 55 /// All primitives are named using the identity of the [Primitive] object. |
| 55 /// | 56 /// |
| 56 /// Primitives may allocate objects, this is not considered side-effect here. | 57 /// Primitives may allocate objects, this is not considered side-effect here. |
| 57 /// | 58 /// |
| 58 /// Although primitives may not mutate state, they may depend on state. | 59 /// Although primitives may not mutate state, they may depend on state. |
| 59 abstract class Primitive extends Definition<Primitive> { | 60 abstract class Primitive extends Definition<Primitive> { |
| 60 /// The [VariableElement] or [ParameterElement] from which the primitive | 61 /// The [VariableElement] or [ParameterElement] from which the primitive |
| 61 /// binding originated. | 62 /// binding originated. |
| 62 Element hint; | 63 Entity hint; |
| 63 | 64 |
| 64 /// Register in which the variable binding this primitive can be allocated. | 65 /// Register in which the variable binding this primitive can be allocated. |
| 65 /// Separate register spaces are used for primitives with different [element]. | 66 /// Separate register spaces are used for primitives with different [element]. |
| 66 /// Assigned by [RegisterAllocator], is null before that phase. | 67 /// Assigned by [RegisterAllocator], is null before that phase. |
| 67 int registerIndex; | 68 int registerIndex; |
| 68 | 69 |
| 69 /// Use the given element as a hint for naming this primitive. | 70 /// Use the given element as a hint for naming this primitive. |
| 70 /// | 71 /// |
| 71 /// Has no effect if this primitive already has a non-null [element]. | 72 /// Has no effect if this primitive already has a non-null [element]. |
| 72 void useElementAsHint(Element hint) { | 73 void useElementAsHint(Entity hint) { |
| 73 if (this.hint == null) { | 74 if (this.hint == null) { |
| 74 this.hint = hint; | 75 this.hint = hint; |
| 75 } | 76 } |
| 76 } | 77 } |
| 77 } | 78 } |
| 78 | 79 |
| 79 /// Operands to invocations and primitives are always variables. They point to | 80 /// Operands to invocations and primitives are always variables. They point to |
| 80 /// their definition and are doubly-linked into a list of occurrences. | 81 /// their definition and are doubly-linked into a list of occurrences. |
| 81 class Reference<T extends Definition<T>> { | 82 class Reference<T extends Definition<T>> { |
| 82 T definition; | 83 T definition; |
| (...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 453 | 454 |
| 454 accept(Visitor visitor) => visitor.visitBranch(this); | 455 accept(Visitor visitor) => visitor.visitBranch(this); |
| 455 } | 456 } |
| 456 | 457 |
| 457 /// Marker interface for nodes that are only handled in the JavaScript backend. | 458 /// Marker interface for nodes that are only handled in the JavaScript backend. |
| 458 /// | 459 /// |
| 459 /// These nodes are generated by the unsugar step and need special translation | 460 /// These nodes are generated by the unsugar step and need special translation |
| 460 /// to the Tree IR, which is implemented in JsTreeBuilder. | 461 /// to the Tree IR, which is implemented in JsTreeBuilder. |
| 461 abstract class JsSpecificNode {} | 462 abstract class JsSpecificNode {} |
| 462 | 463 |
| 464 /// Directly assigns to a field on a given object. |
| 465 class SetField extends Expression implements InteriorNode, JsSpecificNode { |
| 466 final Reference<Primitive> object; |
| 467 Element field; |
| 468 final Reference<Primitive> value; |
| 469 Expression body; |
| 470 |
| 471 SetField(Primitive object, this.field, Primitive value) |
| 472 : this.object = new Reference<Primitive>(object), |
| 473 this.value = new Reference<Primitive>(value); |
| 474 |
| 475 Expression plug(Expression expr) { |
| 476 assert(body == null); |
| 477 return body = expr; |
| 478 } |
| 479 |
| 480 accept(Visitor visitor) => visitor.visitSetField(this); |
| 481 } |
| 482 |
| 483 /// Directly reads from a field on a given object. |
| 484 class GetField extends Primitive implements JsSpecificNode { |
| 485 final Reference<Primitive> object; |
| 486 Element field; |
| 487 |
| 488 GetField(Primitive object, this.field) |
| 489 : this.object = new Reference<Primitive>(object); |
| 490 |
| 491 accept(Visitor visitor) => visitor.visitGetField(this); |
| 492 } |
| 493 |
| 494 /// Creates an object for holding boxed variables captured by a closure. |
| 495 class CreateBox extends Primitive implements JsSpecificNode { |
| 496 accept(Visitor visitor) => visitor.visitCreateBox(this); |
| 497 } |
| 498 |
| 499 /// Instantiates a synthetic class created by closure conversion. |
| 500 class CreateClosureClass extends Primitive implements JsSpecificNode { |
| 501 final ClosureClassElement classElement; |
| 502 |
| 503 /// Values and boxes for locals captured by the closure. |
| 504 /// The order corresponds to [ClosureClassElement.closureFields]. |
| 505 final List<Reference<Primitive>> arguments; |
| 506 |
| 507 CreateClosureClass(this.classElement, List<Primitive> arguments) |
| 508 : this.arguments = _referenceList(arguments); |
| 509 |
| 510 accept(Visitor visitor) => visitor.visitCreateClosureClass(this); |
| 511 } |
| 512 |
| 463 class Identical extends Primitive implements JsSpecificNode { | 513 class Identical extends Primitive implements JsSpecificNode { |
| 464 final Reference<Primitive> left; | 514 final Reference<Primitive> left; |
| 465 final Reference<Primitive> right; | 515 final Reference<Primitive> right; |
| 466 Identical(Primitive left, Primitive right) | 516 Identical(Primitive left, Primitive right) |
| 467 : left = new Reference<Primitive>(left), | 517 : left = new Reference<Primitive>(left), |
| 468 right = new Reference<Primitive>(right); | 518 right = new Reference<Primitive>(right); |
| 469 accept(Visitor visitor) => visitor.visitIdentical(this); | 519 accept(Visitor visitor) => visitor.visitIdentical(this); |
| 470 } | 520 } |
| 471 | 521 |
| 472 class Interceptor extends Primitive implements JsSpecificNode { | 522 class Interceptor extends Primitive implements JsSpecificNode { |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 537 /// Create a non-recursive function. | 587 /// Create a non-recursive function. |
| 538 class CreateFunction extends Primitive { | 588 class CreateFunction extends Primitive { |
| 539 final FunctionDefinition definition; | 589 final FunctionDefinition definition; |
| 540 | 590 |
| 541 CreateFunction(this.definition); | 591 CreateFunction(this.definition); |
| 542 | 592 |
| 543 accept(Visitor visitor) => visitor.visitCreateFunction(this); | 593 accept(Visitor visitor) => visitor.visitCreateFunction(this); |
| 544 } | 594 } |
| 545 | 595 |
| 546 class Parameter extends Primitive { | 596 class Parameter extends Primitive { |
| 547 Parameter(Element element) { | 597 Parameter(Entity hint) { |
| 548 super.hint = element; | 598 super.hint = hint; |
| 549 } | 599 } |
| 550 | 600 |
| 551 accept(Visitor visitor) => visitor.visitParameter(this); | 601 accept(Visitor visitor) => visitor.visitParameter(this); |
| 552 } | 602 } |
| 553 | 603 |
| 554 /// Continuations are normally bound by 'let cont'. A continuation with one | 604 /// Continuations are normally bound by 'let cont'. A continuation with one |
| 555 /// parameter and no body is used to represent a function's return continuation. | 605 /// parameter and no body is used to represent a function's return continuation. |
| 556 /// The return continuation is bound by the Function, not by 'let cont'. | 606 /// The return continuation is bound by the Function, not by 'let cont'. |
| 557 class Continuation extends Definition<Continuation> implements InteriorNode { | 607 class Continuation extends Definition<Continuation> implements InteriorNode { |
| 558 final List<Parameter> parameters; | 608 final List<Parameter> parameters; |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 750 T visitInvokeStatic(InvokeStatic node) => visitExpression(node); | 800 T visitInvokeStatic(InvokeStatic node) => visitExpression(node); |
| 751 T visitInvokeContinuation(InvokeContinuation node) => visitExpression(node); | 801 T visitInvokeContinuation(InvokeContinuation node) => visitExpression(node); |
| 752 T visitInvokeMethod(InvokeMethod node) => visitExpression(node); | 802 T visitInvokeMethod(InvokeMethod node) => visitExpression(node); |
| 753 T visitInvokeSuperMethod(InvokeSuperMethod node) => visitExpression(node); | 803 T visitInvokeSuperMethod(InvokeSuperMethod node) => visitExpression(node); |
| 754 T visitInvokeConstructor(InvokeConstructor node) => visitExpression(node); | 804 T visitInvokeConstructor(InvokeConstructor node) => visitExpression(node); |
| 755 T visitConcatenateStrings(ConcatenateStrings node) => visitExpression(node); | 805 T visitConcatenateStrings(ConcatenateStrings node) => visitExpression(node); |
| 756 T visitBranch(Branch node) => visitExpression(node); | 806 T visitBranch(Branch node) => visitExpression(node); |
| 757 T visitTypeOperator(TypeOperator node) => visitExpression(node); | 807 T visitTypeOperator(TypeOperator node) => visitExpression(node); |
| 758 T visitSetClosureVariable(SetClosureVariable node) => visitExpression(node); | 808 T visitSetClosureVariable(SetClosureVariable node) => visitExpression(node); |
| 759 T visitDeclareFunction(DeclareFunction node) => visitExpression(node); | 809 T visitDeclareFunction(DeclareFunction node) => visitExpression(node); |
| 810 T visitSetField(SetField node) => visitExpression(node); |
| 760 | 811 |
| 761 // Definitions. | 812 // Definitions. |
| 762 T visitLiteralList(LiteralList node) => visitPrimitive(node); | 813 T visitLiteralList(LiteralList node) => visitPrimitive(node); |
| 763 T visitLiteralMap(LiteralMap node) => visitPrimitive(node); | 814 T visitLiteralMap(LiteralMap node) => visitPrimitive(node); |
| 764 T visitConstant(Constant node) => visitPrimitive(node); | 815 T visitConstant(Constant node) => visitPrimitive(node); |
| 765 T visitThis(This node) => visitPrimitive(node); | 816 T visitThis(This node) => visitPrimitive(node); |
| 766 T visitReifyTypeVar(ReifyTypeVar node) => visitPrimitive(node); | 817 T visitReifyTypeVar(ReifyTypeVar node) => visitPrimitive(node); |
| 767 T visitCreateFunction(CreateFunction node) => visitPrimitive(node); | 818 T visitCreateFunction(CreateFunction node) => visitPrimitive(node); |
| 768 T visitGetClosureVariable(GetClosureVariable node) => visitPrimitive(node); | 819 T visitGetClosureVariable(GetClosureVariable node) => visitPrimitive(node); |
| 769 T visitParameter(Parameter node) => visitPrimitive(node); | 820 T visitParameter(Parameter node) => visitPrimitive(node); |
| 770 T visitContinuation(Continuation node) => visitDefinition(node); | 821 T visitContinuation(Continuation node) => visitDefinition(node); |
| 771 T visitClosureVariable(ClosureVariable node) => visitDefinition(node); | 822 T visitClosureVariable(ClosureVariable node) => visitDefinition(node); |
| 823 T visitGetField(GetField node) => visitDefinition(node); |
| 824 T visitCreateBox(CreateBox node) => visitDefinition(node); |
| 825 T visitCreateClosureClass(CreateClosureClass node) => visitDefinition(node); |
| 772 | 826 |
| 773 // Conditions. | 827 // Conditions. |
| 774 T visitIsTrue(IsTrue node) => visitCondition(node); | 828 T visitIsTrue(IsTrue node) => visitCondition(node); |
| 775 | 829 |
| 776 // JavaScript specific nodes. | 830 // JavaScript specific nodes. |
| 777 T visitIdentical(Identical node) => visitPrimitive(node); | 831 T visitIdentical(Identical node) => visitPrimitive(node); |
| 778 T visitInterceptor(Interceptor node) => visitPrimitive(node); | 832 T visitInterceptor(Interceptor node) => visitPrimitive(node); |
| 779 } | 833 } |
| 780 | 834 |
| 781 /// Recursively visits the entire CPS term, and calls abstract `process*` | 835 /// Recursively visits the entire CPS term, and calls abstract `process*` |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 991 processIdentical(node); | 1045 processIdentical(node); |
| 992 processReference(node.left); | 1046 processReference(node.left); |
| 993 processReference(node.right); | 1047 processReference(node.right); |
| 994 } | 1048 } |
| 995 | 1049 |
| 996 processInterceptor(Interceptor node) {} | 1050 processInterceptor(Interceptor node) {} |
| 997 visitInterceptor(Interceptor node) { | 1051 visitInterceptor(Interceptor node) { |
| 998 processInterceptor(node); | 1052 processInterceptor(node); |
| 999 processReference(node.input); | 1053 processReference(node.input); |
| 1000 } | 1054 } |
| 1055 |
| 1056 processCreateClosureClass(CreateClosureClass node) {} |
| 1057 visitCreateClosureClass(CreateClosureClass node) { |
| 1058 processCreateClosureClass(node); |
| 1059 node.arguments.forEach(processReference); |
| 1060 } |
| 1061 |
| 1062 processSetField(SetField node) {} |
| 1063 visitSetField(SetField node) { |
| 1064 processSetField(node); |
| 1065 processReference(node.object); |
| 1066 processReference(node.value); |
| 1067 visit(node.body); |
| 1068 } |
| 1069 |
| 1070 processGetField(GetField node) {} |
| 1071 visitGetField(GetField node) { |
| 1072 processGetField(node); |
| 1073 processReference(node.object); |
| 1074 } |
| 1075 |
| 1076 processCreateBox(CreateBox node) {} |
| 1077 visitCreateBox(CreateBox node) { |
| 1078 processCreateBox(node); |
| 1079 } |
| 1001 } | 1080 } |
| 1002 | 1081 |
| 1003 /// Keeps track of currently unused register indices. | 1082 /// Keeps track of currently unused register indices. |
| 1004 class RegisterArray { | 1083 class RegisterArray { |
| 1005 int nextIndex = 0; | 1084 int nextIndex = 0; |
| 1006 final List<int> freeStack = <int>[]; | 1085 final List<int> freeStack = <int>[]; |
| 1007 | 1086 |
| 1008 /// Returns an index that is currently unused. | 1087 /// Returns an index that is currently unused. |
| 1009 int makeIndex() { | 1088 int makeIndex() { |
| 1010 if (freeStack.isEmpty) { | 1089 if (freeStack.isEmpty) { |
| 1011 return nextIndex++; | 1090 return nextIndex++; |
| 1012 } else { | 1091 } else { |
| 1013 return freeStack.removeLast(); | 1092 return freeStack.removeLast(); |
| 1014 } | 1093 } |
| 1015 } | 1094 } |
| 1016 | 1095 |
| 1017 void releaseIndex(int index) { | 1096 void releaseIndex(int index) { |
| 1018 freeStack.add(index); | 1097 freeStack.add(index); |
| 1019 } | 1098 } |
| 1020 } | 1099 } |
| 1021 | 1100 |
| 1022 /// Assigns indices to each primitive in the IR such that primitives that are | 1101 /// Assigns indices to each primitive in the IR such that primitives that are |
| 1023 /// live simultaneously never get assigned the same index. | 1102 /// live simultaneously never get assigned the same index. |
| 1024 /// This information is used by the dart tree builder to generate fewer | 1103 /// This information is used by the dart tree builder to generate fewer |
| 1025 /// redundant variables. | 1104 /// redundant variables. |
| 1026 /// Currently, the liveness analysis is very simple and is often inadequate | 1105 /// Currently, the liveness analysis is very simple and is often inadequate |
| 1027 /// for removing all of the redundant variables. | 1106 /// for removing all of the redundant variables. |
| 1028 class RegisterAllocator extends Visitor { | 1107 class RegisterAllocator extends Visitor { |
| 1029 /// Separate register spaces for each source-level variable/parameter. | 1108 /// Separate register spaces for each source-level variable/parameter. |
| 1030 /// Note that null is used as key for primitives without elements. | 1109 /// Note that null is used as key for primitives without hints. |
| 1031 final Map<Element, RegisterArray> elementRegisters = | 1110 final Map<Local, RegisterArray> elementRegisters = <Local, RegisterArray>{}; |
| 1032 <Element, RegisterArray>{}; | |
| 1033 | 1111 |
| 1034 RegisterArray getRegisterArray(Element element) { | 1112 RegisterArray getRegisterArray(Local local) { |
| 1035 RegisterArray registers = elementRegisters[element]; | 1113 RegisterArray registers = elementRegisters[local]; |
| 1036 if (registers == null) { | 1114 if (registers == null) { |
| 1037 registers = new RegisterArray(); | 1115 registers = new RegisterArray(); |
| 1038 elementRegisters[element] = registers; | 1116 elementRegisters[local] = registers; |
| 1039 } | 1117 } |
| 1040 return registers; | 1118 return registers; |
| 1041 } | 1119 } |
| 1042 | 1120 |
| 1043 void allocate(Primitive primitive) { | 1121 void allocate(Primitive primitive) { |
| 1044 if (primitive.registerIndex == null) { | 1122 if (primitive.registerIndex == null) { |
| 1045 primitive.registerIndex = getRegisterArray(primitive.hint).makeIndex(); | 1123 primitive.registerIndex = getRegisterArray(primitive.hint).makeIndex(); |
| 1046 } | 1124 } |
| 1047 } | 1125 } |
| 1048 | 1126 |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1196 release(node.parameters[i]); | 1274 release(node.parameters[i]); |
| 1197 } | 1275 } |
| 1198 } | 1276 } |
| 1199 | 1277 |
| 1200 void visitIsTrue(IsTrue node) { | 1278 void visitIsTrue(IsTrue node) { |
| 1201 visitReference(node.value); | 1279 visitReference(node.value); |
| 1202 } | 1280 } |
| 1203 | 1281 |
| 1204 // JavaScript specific nodes. | 1282 // JavaScript specific nodes. |
| 1205 | 1283 |
| 1284 void visitSetField(SetField node) { |
| 1285 visit(node.body); |
| 1286 visitReference(node.value); |
| 1287 visitReference(node.object); |
| 1288 } |
| 1289 |
| 1290 void visitGetField(GetField node) { |
| 1291 visitReference(node.object); |
| 1292 } |
| 1293 |
| 1294 void visitCreateBox(CreateBox node) { |
| 1295 } |
| 1296 |
| 1297 void visitCreateClosureClass(CreateClosureClass node) { |
| 1298 node.arguments.forEach(visitReference); |
| 1299 } |
| 1300 |
| 1206 void visitIdentical(Identical node) { | 1301 void visitIdentical(Identical node) { |
| 1207 visitReference(node.left); | 1302 visitReference(node.left); |
| 1208 visitReference(node.right); | 1303 visitReference(node.right); |
| 1209 } | 1304 } |
| 1210 | 1305 |
| 1211 void visitInterceptor(Interceptor node) { | 1306 void visitInterceptor(Interceptor node) { |
| 1212 visitReference(node.input); | 1307 visitReference(node.input); |
| 1213 } | 1308 } |
| 1214 } | 1309 } |
| OLD | NEW |