Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(305)

Side by Side Diff: pkg/compiler/lib/src/js_backend/codegen/unsugar.dart

Issue 1020243002: cps_ir: interceptor calling convention, operator== prologue (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 library dart2js.unsugar_cps; 1 library dart2js.unsugar_cps;
2 2
3 import '../../cps_ir/cps_ir_nodes.dart'; 3 import '../../cps_ir/cps_ir_nodes.dart';
4 4
5 // TODO(karlklose): share the [ParentVisitor]. 5 // TODO(karlklose): share the [ParentVisitor].
6 import '../../cps_ir/optimizers.dart'; 6 import '../../cps_ir/optimizers.dart';
7 import '../../constants/expressions.dart'; 7 import '../../constants/expressions.dart';
8 import '../../constants/values.dart'; 8 import '../../constants/values.dart';
9 import '../../elements/elements.dart' show ClassElement, FieldElement, Element; 9 import '../../elements/elements.dart' show
10 ClassElement,
11 ExecutableElement,
12 FieldElement,
13 Local;
10 import '../../js_backend/codegen/glue.dart'; 14 import '../../js_backend/codegen/glue.dart';
11 import '../../dart2jslib.dart' show Selector, World; 15 import '../../dart2jslib.dart' show Selector, World;
12 16
17
18 class ExplicitReceiverParameterEntity implements Local {
19 final String name;
Kevin Millikin (Google) 2015/03/26 15:14:17 Consider hardcoding the name 'receiver' here rathe
20 final ExecutableElement executableContext;
21 ExplicitReceiverParameterEntity(this.name, this.executableContext);
22 toString() => 'ExplicitReceiverParameterEntity($executableContext)';
23 }
24
25
26
13 /// Rewrites the initial CPS IR to make Dart semantics explicit and inserts 27 /// Rewrites the initial CPS IR to make Dart semantics explicit and inserts
14 /// special nodes that respect JavaScript behavior. 28 /// special nodes that respect JavaScript behavior.
15 /// 29 ///
16 /// Performs the following rewrites: 30 /// Performs the following rewrites:
17 /// - rewrite [IsTrue] in a [Branch] to do boolean conversion. 31 /// - Rewrite [IsTrue] in a [Branch] to do boolean conversion.
32 /// - Add explicit receiver argument for methods that are called in interceptor
33 /// calling convention.
34 /// - Use current or new interceptor at call sites taht use interceptor calling
Kevin Millikin (Google) 2015/03/26 15:14:17 'taht' ==> 'that'
35 /// convention.
36 /// - Rewrite operator== to test the argument for null.
Kevin Millikin (Google) 2015/03/26 15:14:17 'first argument' or 'receiver argument'?
18 class UnsugarVisitor extends RecursiveVisitor { 37 class UnsugarVisitor extends RecursiveVisitor {
19 Glue _glue; 38 Glue _glue;
20 39
40 bool inInterceptedMethod = false;
41 Parameter thisParameter = null;
42 Parameter explicitReceiverParameter = null;
43
21 UnsugarVisitor(this._glue); 44 UnsugarVisitor(this._glue);
22 45
23 void rewrite(FunctionDefinition function) { 46 void rewrite(FunctionDefinition function) {
47
48 if (function.element.name == '==' && function.parameters.length == 1) {
49 // If [functionElement] is `operator==` we explicitely add a null check at
50 // the beginning of the method. This is to avoid having call sites do the
51 // null check.
52 if (_glue.requiresEqNullCheck(function.element)) {
53 insertEqNullCheck(function);
54 }
55 }
56
57 // For interceptor calling convention, the receiver is passed as a
58 // parameter.
59 bool inInterceptedMethod = false;
60 if (_glue.isInterceptedMethod(function.element)) {
61 inInterceptedMethod = true;
62 thisParameter = function.thisParameter;
63 explicitReceiverParameter =
64 new Parameter(
65 new ExplicitReceiverParameterEntity('receiver',
66 thisParameter.hint.executableContext));
67 function.parameters.insert(0, explicitReceiverParameter);
68 }
69
24 // Set all parent pointers. 70 // Set all parent pointers.
25 new ParentVisitor().visit(function); 71 new ParentVisitor().visit(function);
72
73 // Replace all references to This with the explicit receiver parameter.
74 if (inInterceptedMethod) {
75 explicitReceiverParameter.substituteFor(thisParameter);
76 explicitReceiverParameter.firstRef = thisParameter.firstRef;
Kevin Millikin (Google) 2015/03/26 15:14:17 substituteFor will do this (and doing it here is o
77 thisParameter.firstRef = null;
Kevin Millikin (Google) 2015/03/26 15:14:17 And we should almost certainly do this in substitu
78 }
79
26 visit(function); 80 visit(function);
27 } 81 }
28 82
29 @override 83 @override
30 visit(Node node) { 84 visit(Node node) {
31 Node result = node.accept(this); 85 Node result = node.accept(this);
32 return result != null ? result : node; 86 return result != null ? result : node;
33 } 87 }
34 88
35 Constant get trueConstant { 89 Constant makeTrue() {
Kevin Millikin (Google) 2015/03/26 15:14:17 Oooh, these seem like good utilities to have in cl
36 return new Constant( 90 return new Constant(
37 new PrimitiveConstantExpression( 91 new PrimitiveConstantExpression(
38 new TrueConstantValue())); 92 new TrueConstantValue()));
39 } 93 }
40 94
95 Constant makeFalse() {
96 return new Constant(
97 new PrimitiveConstantExpression(
98 new FalseConstantValue()));
99 }
100
101 Primitive makeNull() {
102 return new Constant(
103 new PrimitiveConstantExpression(
104 new NullConstantValue()));
105 }
106
41 void insertLetPrim(Primitive primitive, Expression node) { 107 void insertLetPrim(Primitive primitive, Expression node) {
42 LetPrim let = new LetPrim(primitive); 108 LetPrim let = new LetPrim(primitive);
43 InteriorNode parent = node.parent; 109 InteriorNode parent = node.parent;
44 parent.body = let; 110 parent.body = let;
45 let.body = node; 111 let.body = node;
46 node.parent = let; 112 node.parent = let;
47 let.parent = parent; 113 let.parent = parent;
48 } 114 }
49 115
116 void insertEqNullCheck(FunctionDefinition function) {
117 // Replace
118 //
119 // body;
120 //
121 // with
122 //
123 // if (identical(arg, null))
124 // return false;
125 // else
126 // body;
127 //
128 Continuation originalBody = new Continuation(<Parameter>[]);
129 originalBody.body = function.body.body;
130
131 Continuation returnFalse = new Continuation(<Parameter>[]);
132 Primitive falsePrimitive = makeFalse();
133 returnFalse.body =
134 new LetPrim(falsePrimitive,
135 new InvokeContinuation(
136 function.body.returnContinuation, <Primitive>[falsePrimitive]));
137
138 Primitive nullPrimitive = makeNull();
139 Primitive test = new Identical(function.parameters.single, nullPrimitive);
140
141 Expression newBody =
142 new LetCont.many(<Continuation>[returnFalse, originalBody],
143 new LetPrim(nullPrimitive,
144 new LetPrim(test,
145 new Branch(
146 new IsTrue(test),
147 returnFalse,
148 originalBody))));
149 function.body.body = newBody;
150 }
151
50 processInvokeMethod(InvokeMethod node) { 152 processInvokeMethod(InvokeMethod node) {
51 Selector selector = node.selector; 153 Selector selector = node.selector;
52 // TODO(karlklose): should we rewrite all selectors? 154 // TODO(karlklose): should we rewrite all selectors? sra: No. It would add
Kevin Millikin (Google) 2015/03/26 15:14:17 I don't understand the question or the answer. Ma
155 // a lot of code. We would need to do so only if we permit native classes
156 // to implement noSuchMethod.
53 if (!_glue.isInterceptedSelector(selector)) return; 157 if (!_glue.isInterceptedSelector(selector)) return;
54 158
55 Primitive receiver = node.receiver.definition; 159 Primitive receiver = node.receiver.definition;
160
161 // If the receiver is the explicit receiver, we are calling a method in the
162 // same interceptor.
163 if (receiver == explicitReceiverParameter) {
164 // receiver.foo() --> this.foo(receiver);
165 node.arguments.insert(0, node.receiver);
166 node.callingConvention = CallingConvention.JS_INTERCEPTED;
167 Reference<Primitive> receiverRef = node.receiver;
Kevin Millikin (Google) 2015/03/26 15:14:17 This is unused.
168 node.receiver = new Reference<Primitive>(thisParameter);
169 assert(node.isValid);
170 return;
171 }
172
173 // TODO(sra): Move the computation of interceptedClasses to a much later
174 // phase and take into account the remaining uses of the interceptor.
56 Set<ClassElement> interceptedClasses = 175 Set<ClassElement> interceptedClasses =
Kevin Millikin (Google) 2015/03/26 15:14:17 I think there's enough shared code here and above
57 _glue.getInterceptedClassesOn(selector); 176 _glue.getInterceptedClassesOn(selector);
58 _glue.registerSpecializedGetInterceptor(interceptedClasses); 177 _glue.registerSpecializedGetInterceptor(interceptedClasses);
59 178
60 Primitive intercepted = new Interceptor(receiver, interceptedClasses); 179 Primitive intercepted = new Interceptor(receiver, interceptedClasses);
61 insertLetPrim(intercepted, node); 180 insertLetPrim(intercepted, node);
62 node.arguments.insert(0, node.receiver); 181 node.arguments.insert(0, node.receiver);
63 node.callingConvention = CallingConvention.JS_INTERCEPTED; 182 node.callingConvention = CallingConvention.JS_INTERCEPTED;
183 node.receiver = new Reference<Primitive>(intercepted);
64 assert(node.isValid); 184 assert(node.isValid);
65 node.receiver = new Reference<Primitive>(intercepted);
66 }
67
68 Primitive makeNull() {
69 NullConstantValue nullConst = new NullConstantValue();
70 return new Constant(new PrimitiveConstantExpression(nullConst));
71 } 185 }
72 186
73 processInvokeMethodDirectly(InvokeMethodDirectly node) { 187 processInvokeMethodDirectly(InvokeMethodDirectly node) {
74 if (_glue.isInterceptedMethod(node.target)) { 188 if (_glue.isInterceptedMethod(node.target)) {
75 Primitive nullPrim = makeNull(); 189 Primitive nullPrim = makeNull();
76 insertLetPrim(nullPrim, node); 190 insertLetPrim(nullPrim, node);
77 node.arguments.insert(0, node.receiver); 191 node.arguments.insert(0, node.receiver);
78 node.receiver = new Reference<Primitive>(nullPrim); 192 node.receiver = new Reference<Primitive>(nullPrim);
193
194 // TODO(sra): `null` is not adequate. Interceptors project the class
195 // hierarchy onto an interceptor hierarchy. A super call that does a
196 // method call will use the javascript 'this' parameter to avoid calling
197 // getInterceptor again, so the receiver must be the interceptor (likely
198 // `this`), not `null`.
79 } 199 }
80 } 200 }
81 201
82 processBranch(Branch node) { 202 processBranch(Branch node) {
83 // TODO(karlklose): implement the checked mode part of boolean conversion. 203 // TODO(karlklose): implement the checked mode part of boolean conversion.
84 InteriorNode parent = node.parent; 204 InteriorNode parent = node.parent;
85 IsTrue condition = node.condition; 205 IsTrue condition = node.condition;
86 Primitive t = trueConstant; 206 Primitive t = makeTrue();
87 Primitive i = new Identical(condition.value.definition, t); 207 Primitive i = new Identical(condition.value.definition, t);
88 LetPrim newNode = new LetPrim(t, 208 LetPrim newNode =
89 new LetPrim(i, 209 new LetPrim(t,
90 new Branch(new IsTrue(i), 210 new LetPrim(i,
91 node.trueContinuation.definition, 211 new Branch(
92 node.falseContinuation.definition))); 212 new IsTrue(i),
213 node.trueContinuation.definition,
214 node.falseContinuation.definition)));
93 condition.value.unlink(); 215 condition.value.unlink();
94 node.trueContinuation.unlink(); 216 node.trueContinuation.unlink();
95 node.falseContinuation.unlink(); 217 node.falseContinuation.unlink();
96 parent.body = newNode; 218 parent.body = newNode;
97 } 219 }
98 } 220 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698