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

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

Issue 1109403002: cps-ir: Support compilation of methods that use interceptor calling convention. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comment. Created 5 years, 7 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
« no previous file with comments | « pkg/compiler/lib/src/js_backend/codegen/type_test_emitter.dart ('k') | pkg/pkg.status » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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' 9 import '../../elements/elements.dart' show
10 show ClassElement, FieldElement, FunctionElement, Element; 10 ClassElement,
11 FieldElement,
12 FunctionElement,
13 Local,
14 ExecutableElement;
11 import '../../js_backend/codegen/glue.dart'; 15 import '../../js_backend/codegen/glue.dart';
12 import '../../dart2jslib.dart' show Selector, World; 16 import '../../dart2jslib.dart' show Selector, World;
13 17
18 class ExplicitReceiverParameterEntity implements Local {
19 String get name => 'receiver';
20 final ExecutableElement executableContext;
21 ExplicitReceiverParameterEntity(this.executableContext);
22 toString() => 'ExplicitReceiverParameterEntity($executableContext)';
23 }
24
14 /// Rewrites the initial CPS IR to make Dart semantics explicit and inserts 25 /// Rewrites the initial CPS IR to make Dart semantics explicit and inserts
15 /// special nodes that respect JavaScript behavior. 26 /// special nodes that respect JavaScript behavior.
16 /// 27 ///
17 /// Performs the following rewrites: 28 /// Performs the following rewrites:
18 /// - rewrite [IsTrue] in a [Branch] to do boolean conversion. 29 /// - Rewrite [IsTrue] in a [Branch] to do boolean conversion.
19 /// - converts two-parameter exception handlers to one-parameter ones. 30 /// - Add interceptors at call sites that use interceptor calling convention.
31 /// - Add explicit receiver argument for methods that are called in interceptor
32 /// calling convention.
33 /// - Convert two-parameter exception handlers to one-parameter ones.
20 class UnsugarVisitor extends RecursiveVisitor { 34 class UnsugarVisitor extends RecursiveVisitor {
21 Glue _glue; 35 Glue _glue;
22 ParentVisitor _parentVisitor = new ParentVisitor(); 36 ParentVisitor _parentVisitor = new ParentVisitor();
23 37
38 Parameter thisParameter;
39 Parameter explicitReceiverParameter;
40
24 UnsugarVisitor(this._glue); 41 UnsugarVisitor(this._glue);
25 42
26 void rewrite(FunctionDefinition function) { 43 void rewrite(FunctionDefinition function) {
44 bool inInterceptedMethod = _glue.isInterceptedMethod(function.element);
45
46 if (function.element.name == '==' &&
47 function.parameters.length == 1 &&
48 !_glue.operatorEqHandlesNullArgument(function.element)) {
49 // Insert the null check that the language semantics requires us to
50 // perform before calling operator ==.
51 insertEqNullCheck(function);
52 }
53
54 if (inInterceptedMethod) {
55 thisParameter = function.thisParameter;
56 ThisParameterLocal holder = thisParameter.hint;
57 explicitReceiverParameter = new Parameter(
58 new ExplicitReceiverParameterEntity(
59 holder.executableContext));
60 function.parameters.insert(0, explicitReceiverParameter);
61 }
62
27 // Set all parent pointers. 63 // Set all parent pointers.
28 _parentVisitor.visit(function); 64 _parentVisitor.visit(function);
65
66 if (inInterceptedMethod) {
67 explicitReceiverParameter.substituteFor(thisParameter);
68 }
69
29 visit(function); 70 visit(function);
30 } 71 }
31 72
32 @override 73 @override
33 visit(Node node) { 74 visit(Node node) {
34 Node result = node.accept(this); 75 Node result = node.accept(this);
35 return result != null ? result : node; 76 return result != null ? result : node;
36 } 77 }
37 78
38 Constant get trueConstant { 79 Constant get trueConstant {
39 return new Constant( 80 return new Constant(
40 new BoolConstantExpression( 81 new BoolConstantExpression(
41 true, 82 true,
42 new TrueConstantValue())); 83 new TrueConstantValue()));
43 } 84 }
44 85
86 Constant get falseConstant {
87 return new Constant(
88 new BoolConstantExpression(
89 false,
90 new FalseConstantValue()));
91 }
92
93 Constant get nullConstant {
94 return new Constant(
95 new NullConstantExpression(
96 new NullConstantValue()));
97 }
98
45 void insertLetPrim(Primitive primitive, Expression node) { 99 void insertLetPrim(Primitive primitive, Expression node) {
46 LetPrim let = new LetPrim(primitive); 100 LetPrim let = new LetPrim(primitive);
47 InteriorNode parent = node.parent; 101 InteriorNode parent = node.parent;
48 parent.body = let; 102 parent.body = let;
49 let.body = node; 103 let.body = node;
50 node.parent = let; 104 node.parent = let;
51 let.parent = parent; 105 let.parent = parent;
52 } 106 }
53 107
108 void insertEqNullCheck(FunctionDefinition function) {
109 // Replace
110 //
111 // body;
112 //
113 // with
114 //
115 // if (identical(arg, null))
116 // return false;
117 // else
118 // body;
119 //
120 Continuation originalBody = new Continuation(<Parameter>[]);
121 originalBody.body = function.body.body;
122
123 Continuation returnFalse = new Continuation(<Parameter>[]);
124 Primitive falsePrimitive = falseConstant;
125 returnFalse.body =
126 new LetPrim(falsePrimitive,
127 new InvokeContinuation(
128 function.body.returnContinuation, <Primitive>[falsePrimitive]));
129
130 Primitive nullPrimitive = nullConstant;
131 Primitive test = new Identical(function.parameters.single, nullPrimitive);
132
133 Expression newBody =
134 new LetCont.many(<Continuation>[returnFalse, originalBody],
135 new LetPrim(nullPrimitive,
136 new LetPrim(test,
137 new Branch(
138 new IsTrue(test),
139 returnFalse,
140 originalBody))));
141 function.body.body = newBody;
142 }
143
54 /// Insert a static call to [function] at the point of [node] with result 144 /// Insert a static call to [function] at the point of [node] with result
55 /// [result]. 145 /// [result].
56 /// 146 ///
57 /// Rewrite [node] to 147 /// Rewrite [node] to
58 /// 148 ///
59 /// let cont continuation(result) = node 149 /// let cont continuation(result) = node
60 /// in invoke function arguments continuation 150 /// in invoke function arguments continuation
61 void insertStaticCall(FunctionElement function, List<Primitive> arguments, 151 void insertStaticCall(FunctionElement function, List<Primitive> arguments,
62 Parameter result, 152 Parameter result,
63 Expression node) { 153 Expression node) {
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
111 // The subexpression of throw is wrapped in the JavaScript output. 201 // The subexpression of throw is wrapped in the JavaScript output.
112 Parameter value = new Parameter(null); 202 Parameter value = new Parameter(null);
113 insertStaticCall(_glue.getWrapExceptionHelper(), [node.value.definition], 203 insertStaticCall(_glue.getWrapExceptionHelper(), [node.value.definition],
114 value, node); 204 value, node);
115 node.value.unlink(); 205 node.value.unlink();
116 node.value = new Reference<Primitive>(value); 206 node.value = new Reference<Primitive>(value);
117 } 207 }
118 208
119 processInvokeMethod(InvokeMethod node) { 209 processInvokeMethod(InvokeMethod node) {
120 Selector selector = node.selector; 210 Selector selector = node.selector;
121 // TODO(karlklose): should we rewrite all selectors?
122 if (!_glue.isInterceptedSelector(selector)) return; 211 if (!_glue.isInterceptedSelector(selector)) return;
123 212
124 Primitive receiver = node.receiver.definition; 213 Primitive receiver = node.receiver.definition;
125 Set<ClassElement> interceptedClasses = 214 Primitive newReceiver;
215
216 if (receiver == explicitReceiverParameter) {
217 // If the receiver is the explicit receiver, we are calling a method in
218 // the same interceptor:
219 // Change 'receiver.foo()' to 'this.foo(receiver)'.
220 newReceiver = thisParameter;
221 } else {
222 // TODO(sra): Move the computation of interceptedClasses to a much later
223 // phase and take into account the remaining uses of the interceptor.
224 Set<ClassElement> interceptedClasses =
126 _glue.getInterceptedClassesOn(selector); 225 _glue.getInterceptedClassesOn(selector);
127 _glue.registerSpecializedGetInterceptor(interceptedClasses); 226 _glue.registerSpecializedGetInterceptor(interceptedClasses);
227 newReceiver = new Interceptor(receiver, interceptedClasses);
228 insertLetPrim(newReceiver, node);
229 }
128 230
129 Primitive intercepted = new Interceptor(receiver, interceptedClasses);
130 insertLetPrim(intercepted, node);
131 node.arguments.insert(0, node.receiver); 231 node.arguments.insert(0, node.receiver);
132 node.callingConvention = CallingConvention.JS_INTERCEPTED; 232 node.callingConvention = CallingConvention.JS_INTERCEPTED;
133 assert(node.isValid); 233 assert(node.isValid);
134 node.receiver = new Reference<Primitive>(intercepted); 234 node.receiver = new Reference<Primitive>(newReceiver);
135 }
136
137 Primitive makeNull() {
138 NullConstantValue nullConst = new NullConstantValue();
139 return new Constant(new NullConstantExpression(nullConst));
140 } 235 }
141 236
142 processInvokeMethodDirectly(InvokeMethodDirectly node) { 237 processInvokeMethodDirectly(InvokeMethodDirectly node) {
143 if (_glue.isInterceptedMethod(node.target)) { 238 if (_glue.isInterceptedMethod(node.target)) {
144 Primitive nullPrim = makeNull(); 239 Primitive nullPrim = nullConstant;
145 insertLetPrim(nullPrim, node); 240 insertLetPrim(nullPrim, node);
146 node.arguments.insert(0, node.receiver); 241 node.arguments.insert(0, node.receiver);
242 // TODO(sra): `null` is not adequate. Interceptors project the class
243 // hierarchy onto an interceptor hierarchy. A super call that does a
244 // method call will use the javascript 'this' parameter to avoid calling
245 // getInterceptor again, so the receiver must be the interceptor (likely
246 // `this`), not `null`.
147 node.receiver = new Reference<Primitive>(nullPrim); 247 node.receiver = new Reference<Primitive>(nullPrim);
148 } 248 }
149 } 249 }
150 250
151 processBranch(Branch node) { 251 processBranch(Branch node) {
152 // TODO(karlklose): implement the checked mode part of boolean conversion. 252 // TODO(karlklose): implement the checked mode part of boolean conversion.
153 InteriorNode parent = node.parent; 253 InteriorNode parent = node.parent;
154 IsTrue condition = node.condition; 254 IsTrue condition = node.condition;
155 Primitive t = trueConstant; 255 Primitive t = trueConstant;
156 Primitive i = new Identical(condition.value.definition, t); 256 Primitive i = new Identical(condition.value.definition, t);
157 LetPrim newNode = new LetPrim(t, 257 LetPrim newNode = new LetPrim(t,
158 new LetPrim(i, 258 new LetPrim(i,
159 new Branch(new IsTrue(i), 259 new Branch(new IsTrue(i),
160 node.trueContinuation.definition, 260 node.trueContinuation.definition,
161 node.falseContinuation.definition))); 261 node.falseContinuation.definition)));
162 condition.value.unlink(); 262 condition.value.unlink();
163 node.trueContinuation.unlink(); 263 node.trueContinuation.unlink();
164 node.falseContinuation.unlink(); 264 node.falseContinuation.unlink();
165 parent.body = newNode; 265 parent.body = newNode;
166 } 266 }
167 } 267 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/js_backend/codegen/type_test_emitter.dart ('k') | pkg/pkg.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698