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 |