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

Side by Side Diff: pkg/compiler/lib/src/js_emitter/interceptor_stub_generator.dart

Issue 1413213004: Move remaining helpers to BackendHelpers (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 5 years, 1 month 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
OLDNEW
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 part of dart2js.js_emitter; 5 part of dart2js.js_emitter;
6 6
7 class InterceptorStubGenerator { 7 class InterceptorStubGenerator {
8 final Compiler compiler; 8 final Compiler compiler;
9 final Namer namer; 9 final Namer namer;
10 final JavaScriptBackend backend; 10 final JavaScriptBackend backend;
11 11
12 InterceptorStubGenerator(this.compiler, this.namer, this.backend); 12 InterceptorStubGenerator(this.compiler, this.namer, this.backend);
13 13
14 Emitter get emitter => backend.emitter.emitter; 14 Emitter get emitter => backend.emitter.emitter;
15 15
16 BackendHelpers get helpers => backend.helpers;
17
16 jsAst.Expression generateGetInterceptorMethod(Set<ClassElement> classes) { 18 jsAst.Expression generateGetInterceptorMethod(Set<ClassElement> classes) {
17 jsAst.Expression interceptorFor(ClassElement cls) { 19 jsAst.Expression interceptorFor(ClassElement cls) {
18 return backend.emitter.interceptorPrototypeAccess(cls); 20 return backend.emitter.interceptorPrototypeAccess(cls);
19 } 21 }
20 22
21 /** 23 /**
22 * Build a JavaScrit AST node for doing a type check on 24 * Build a JavaScrit AST node for doing a type check on
23 * [cls]. [cls] must be a non-native interceptor class. 25 * [cls]. [cls] must be a non-native interceptor class.
24 */ 26 */
25 jsAst.Statement buildInterceptorCheck(ClassElement cls) { 27 jsAst.Statement buildInterceptorCheck(ClassElement cls) {
26 jsAst.Expression condition; 28 jsAst.Expression condition;
27 assert(backend.isInterceptorClass(cls)); 29 assert(backend.isInterceptorClass(cls));
28 if (cls == backend.jsBoolClass) { 30 if (cls == helpers.jsBoolClass) {
29 condition = js('(typeof receiver) == "boolean"'); 31 condition = js('(typeof receiver) == "boolean"');
30 } else if (cls == backend.jsIntClass || 32 } else if (cls == helpers.jsIntClass ||
31 cls == backend.jsDoubleClass || 33 cls == helpers.jsDoubleClass ||
32 cls == backend.jsNumberClass) { 34 cls == helpers.jsNumberClass) {
33 throw 'internal error'; 35 throw 'internal error';
34 } else if (cls == backend.jsArrayClass || 36 } else if (cls == helpers.jsArrayClass ||
35 cls == backend.jsMutableArrayClass || 37 cls == helpers.jsMutableArrayClass ||
36 cls == backend.jsFixedArrayClass || 38 cls == helpers.jsFixedArrayClass ||
37 cls == backend.jsExtendableArrayClass) { 39 cls == helpers.jsExtendableArrayClass) {
38 condition = js('receiver.constructor == Array'); 40 condition = js('receiver.constructor == Array');
39 } else if (cls == backend.jsStringClass) { 41 } else if (cls == helpers.jsStringClass) {
40 condition = js('(typeof receiver) == "string"'); 42 condition = js('(typeof receiver) == "string"');
41 } else if (cls == backend.jsNullClass) { 43 } else if (cls == helpers.jsNullClass) {
42 condition = js('receiver == null'); 44 condition = js('receiver == null');
43 } else { 45 } else {
44 throw 'internal error'; 46 throw 'internal error';
45 } 47 }
46 return js.statement('if (#) return #', [condition, interceptorFor(cls)]); 48 return js.statement('if (#) return #', [condition, interceptorFor(cls)]);
47 } 49 }
48 50
49 bool hasArray = false; 51 bool hasArray = false;
50 bool hasBool = false; 52 bool hasBool = false;
51 bool hasDouble = false; 53 bool hasDouble = false;
52 bool hasInt = false; 54 bool hasInt = false;
53 bool hasNull = false; 55 bool hasNull = false;
54 bool hasNumber = false; 56 bool hasNumber = false;
55 bool hasString = false; 57 bool hasString = false;
56 bool hasNative = false; 58 bool hasNative = false;
57 bool anyNativeClasses = compiler.enqueuer.codegen.nativeEnqueuer 59 bool anyNativeClasses = compiler.enqueuer.codegen.nativeEnqueuer
58 .hasInstantiatedNativeClasses(); 60 .hasInstantiatedNativeClasses();
59 61
60 for (ClassElement cls in classes) { 62 for (ClassElement cls in classes) {
61 if (cls == backend.jsArrayClass || 63 if (cls == helpers.jsArrayClass ||
62 cls == backend.jsMutableArrayClass || 64 cls == helpers.jsMutableArrayClass ||
63 cls == backend.jsFixedArrayClass || 65 cls == helpers.jsFixedArrayClass ||
64 cls == backend.jsExtendableArrayClass) hasArray = true; 66 cls == helpers.jsExtendableArrayClass) hasArray = true;
65 else if (cls == backend.jsBoolClass) hasBool = true; 67 else if (cls == helpers.jsBoolClass) hasBool = true;
66 else if (cls == backend.jsDoubleClass) hasDouble = true; 68 else if (cls == helpers.jsDoubleClass) hasDouble = true;
67 else if (cls == backend.jsIntClass) hasInt = true; 69 else if (cls == helpers.jsIntClass) hasInt = true;
68 else if (cls == backend.jsNullClass) hasNull = true; 70 else if (cls == helpers.jsNullClass) hasNull = true;
69 else if (cls == backend.jsNumberClass) hasNumber = true; 71 else if (cls == helpers.jsNumberClass) hasNumber = true;
70 else if (cls == backend.jsStringClass) hasString = true; 72 else if (cls == helpers.jsStringClass) hasString = true;
71 else { 73 else {
72 // The set of classes includes classes mixed-in to interceptor classes 74 // The set of classes includes classes mixed-in to interceptor classes
73 // and user extensions of native classes. 75 // and user extensions of native classes.
74 // 76 //
75 // The set of classes also includes the 'primitive' interceptor 77 // The set of classes also includes the 'primitive' interceptor
76 // PlainJavaScriptObject even when it has not been resolved, since it is 78 // PlainJavaScriptObject even when it has not been resolved, since it is
77 // only resolved through the reference in getNativeInterceptor when 79 // only resolved through the reference in getNativeInterceptor when
78 // getNativeInterceptor is marked as used. Guard against probing 80 // getNativeInterceptor is marked as used. Guard against probing
79 // unresolved PlainJavaScriptObject by testing for anyNativeClasses. 81 // unresolved PlainJavaScriptObject by testing for anyNativeClasses.
80 82
(...skipping 15 matching lines...) Expand all
96 List<jsAst.Statement> statements = <jsAst.Statement>[]; 98 List<jsAst.Statement> statements = <jsAst.Statement>[];
97 99
98 if (hasNumber) { 100 if (hasNumber) {
99 jsAst.Statement whenNumber; 101 jsAst.Statement whenNumber;
100 102
101 /// Note: there are two number classes in play: Dart's [num], 103 /// Note: there are two number classes in play: Dart's [num],
102 /// and JavaScript's Number (typeof receiver == 'number'). This 104 /// and JavaScript's Number (typeof receiver == 'number'). This
103 /// is the fallback used when we have determined that receiver 105 /// is the fallback used when we have determined that receiver
104 /// is a JavaScript Number. 106 /// is a JavaScript Number.
105 jsAst.Expression interceptorForNumber = interceptorFor( 107 jsAst.Expression interceptorForNumber = interceptorFor(
106 hasDouble ? backend.jsDoubleClass : backend.jsNumberClass); 108 hasDouble ? helpers.jsDoubleClass : helpers.jsNumberClass);
107 109
108 if (hasInt) { 110 if (hasInt) {
109 whenNumber = js.statement('''{ 111 whenNumber = js.statement('''{
110 if (Math.floor(receiver) == receiver) return #; 112 if (Math.floor(receiver) == receiver) return #;
111 return #; 113 return #;
112 }''', [interceptorFor(backend.jsIntClass), interceptorForNumber]); 114 }''', [interceptorFor(helpers.jsIntClass), interceptorForNumber]);
113 } else { 115 } else {
114 whenNumber = js.statement('return #', interceptorForNumber); 116 whenNumber = js.statement('return #', interceptorForNumber);
115 } 117 }
116 statements.add( 118 statements.add(
117 js.statement('if (typeof receiver == "number") #;', whenNumber)); 119 js.statement('if (typeof receiver == "number") #;', whenNumber));
118 } 120 }
119 121
120 if (hasString) { 122 if (hasString) {
121 statements.add(buildInterceptorCheck(backend.jsStringClass)); 123 statements.add(buildInterceptorCheck(helpers.jsStringClass));
122 } 124 }
123 if (hasNull) { 125 if (hasNull) {
124 statements.add(buildInterceptorCheck(backend.jsNullClass)); 126 statements.add(buildInterceptorCheck(helpers.jsNullClass));
125 } else { 127 } else {
126 // Returning "undefined" or "null" here will provoke a JavaScript 128 // Returning "undefined" or "null" here will provoke a JavaScript
127 // TypeError which is later identified as a null-error by 129 // TypeError which is later identified as a null-error by
128 // [unwrapException] in js_helper.dart. 130 // [unwrapException] in js_helper.dart.
129 statements.add( 131 statements.add(
130 js.statement('if (receiver == null) return receiver')); 132 js.statement('if (receiver == null) return receiver'));
131 } 133 }
132 if (hasBool) { 134 if (hasBool) {
133 statements.add(buildInterceptorCheck(backend.jsBoolClass)); 135 statements.add(buildInterceptorCheck(helpers.jsBoolClass));
134 } 136 }
135 // TODO(ahe): It might be faster to check for Array before 137 // TODO(ahe): It might be faster to check for Array before
136 // function and bool. 138 // function and bool.
137 if (hasArray) { 139 if (hasArray) {
138 statements.add(buildInterceptorCheck(backend.jsArrayClass)); 140 statements.add(buildInterceptorCheck(helpers.jsArrayClass));
139 } 141 }
140 142
141 if (hasNative) { 143 if (hasNative) {
142 statements.add(js.statement(r'''{ 144 statements.add(js.statement(r'''{
143 if (typeof receiver != "object") { 145 if (typeof receiver != "object") {
144 if (typeof receiver == "function" ) return #; 146 if (typeof receiver == "function" ) return #;
145 return receiver; 147 return receiver;
146 } 148 }
147 if (receiver instanceof #) return receiver; 149 if (receiver instanceof #) return receiver;
148 return #(receiver); 150 return #(receiver);
149 }''', [ 151 }''', [
150 interceptorFor(backend.jsJavaScriptFunctionClass), 152 interceptorFor(helpers.jsJavaScriptFunctionClass),
151 backend.emitter.constructorAccess(compiler.coreClasses.objectClass), 153 backend.emitter.constructorAccess(compiler.coreClasses.objectClass),
152 backend.emitter 154 backend.emitter
153 .staticFunctionAccess(backend.getNativeInterceptorMethod)])); 155 .staticFunctionAccess(helpers.getNativeInterceptorMethod)]));
154 156
155 } else { 157 } else {
156 ClassElement jsUnknown = backend.jsUnknownJavaScriptObjectClass; 158 ClassElement jsUnknown = helpers.jsUnknownJavaScriptObjectClass;
157 if (compiler.codegenWorld 159 if (compiler.codegenWorld
158 .directlyInstantiatedClasses.contains(jsUnknown)) { 160 .directlyInstantiatedClasses.contains(jsUnknown)) {
159 statements.add( 161 statements.add(
160 js.statement('if (!(receiver instanceof #)) return #;', 162 js.statement('if (!(receiver instanceof #)) return #;',
161 [backend.emitter.constructorAccess( 163 [backend.emitter.constructorAccess(
162 compiler.coreClasses.objectClass), 164 compiler.coreClasses.objectClass),
163 interceptorFor(jsUnknown)])); 165 interceptorFor(jsUnknown)]));
164 } 166 }
165 167
166 statements.add(js.statement('return receiver')); 168 statements.add(js.statement('return receiver'));
(...skipping 10 matching lines...) Expand all
177 179
178 if (selector.isOperator) { 180 if (selector.isOperator) {
179 String name = selector.name; 181 String name = selector.name;
180 if (name == '==') { 182 if (name == '==') {
181 return js.statement('''{ 183 return js.statement('''{
182 if (receiver == null) return a0 == null; 184 if (receiver == null) return a0 == null;
183 if (typeof receiver != "object") 185 if (typeof receiver != "object")
184 return a0 != null && receiver === a0; 186 return a0 != null && receiver === a0;
185 }'''); 187 }''');
186 } 188 }
187 if (!classes.contains(backend.jsIntClass) 189 if (!classes.contains(helpers.jsIntClass)
188 && !classes.contains(backend.jsNumberClass) 190 && !classes.contains(helpers.jsNumberClass)
189 && !classes.contains(backend.jsDoubleClass)) { 191 && !classes.contains(helpers.jsDoubleClass)) {
190 return null; 192 return null;
191 } 193 }
192 if (selector.argumentCount == 1) { 194 if (selector.argumentCount == 1) {
193 // The following operators do not map to a JavaScript operator. 195 // The following operators do not map to a JavaScript operator.
194 if (name == '~/' || name == '<<' || name == '%' || name == '>>') { 196 if (name == '~/' || name == '<<' || name == '%' || name == '>>') {
195 return null; 197 return null;
196 } 198 }
197 jsAst.Expression result = js('receiver $name a0'); 199 jsAst.Expression result = js('receiver $name a0');
198 if (name == '&' || name == '|' || name == '^') { 200 if (name == '&' || name == '|' || name == '^') {
199 result = js('# >>> 0', result); 201 result = js('# >>> 0', result);
(...skipping 21 matching lines...) Expand all
221 // } 223 // }
222 // } 224 // }
223 // 225 //
224 // For an index set operation, this code generates: 226 // For an index set operation, this code generates:
225 // 227 //
226 // if (receiver.constructor == Array && !receiver.immutable$list) { 228 // if (receiver.constructor == Array && !receiver.immutable$list) {
227 // if (a0 >>> 0 === a0 && a0 < receiver.length) { 229 // if (a0 >>> 0 === a0 && a0 < receiver.length) {
228 // return receiver[a0] = a1; 230 // return receiver[a0] = a1;
229 // } 231 // }
230 // } 232 // }
231 bool containsArray = classes.contains(backend.jsArrayClass); 233 bool containsArray = classes.contains(helpers.jsArrayClass);
232 bool containsString = classes.contains(backend.jsStringClass); 234 bool containsString = classes.contains(helpers.jsStringClass);
233 bool containsJsIndexable = 235 bool containsJsIndexable =
234 backend.jsIndexingBehaviorInterface.isResolved && classes.any((cls) { 236 helpers.jsIndexingBehaviorInterface.isResolved && classes.any((cls) {
235 return compiler.world.isSubtypeOf(cls, 237 return compiler.world.isSubtypeOf(cls,
236 backend.jsIndexingBehaviorInterface); 238 helpers.jsIndexingBehaviorInterface);
237 }); 239 });
238 // The index set operator requires a check on its set value in 240 // The index set operator requires a check on its set value in
239 // checked mode, so we don't optimize the interceptor if the 241 // checked mode, so we don't optimize the interceptor if the
240 // compiler has type assertions enabled. 242 // compiler has type assertions enabled.
241 if (selector.isIndexSet 243 if (selector.isIndexSet
242 && (compiler.enableTypeAssertions || !containsArray)) { 244 && (compiler.enableTypeAssertions || !containsArray)) {
243 return null; 245 return null;
244 } 246 }
245 if (!containsArray && !containsString) { 247 if (!containsArray && !containsString) {
246 return null; 248 return null;
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 305
304 if (selector.isSetter) { 306 if (selector.isSetter) {
305 parameterNames.add('value'); 307 parameterNames.add('value');
306 } else { 308 } else {
307 for (int i = 0; i < selector.argumentCount; i++) { 309 for (int i = 0; i < selector.argumentCount; i++) {
308 parameterNames.add('a$i'); 310 parameterNames.add('a$i');
309 } 311 }
310 } 312 }
311 313
312 jsAst.Name invocationName = backend.namer.invocationName(selector); 314 jsAst.Name invocationName = backend.namer.invocationName(selector);
313 String globalObject = namer.globalObjectFor(backend.interceptorsLibrary); 315 String globalObject = namer.globalObjectFor(helpers.interceptorsLibrary);
314 316
315 jsAst.Statement optimizedPath = 317 jsAst.Statement optimizedPath =
316 _fastPathForOneShotInterceptor(selector, classes); 318 _fastPathForOneShotInterceptor(selector, classes);
317 if (optimizedPath == null) optimizedPath = js.statement(';'); 319 if (optimizedPath == null) optimizedPath = js.statement(';');
318 320
319 return js( 321 return js(
320 'function(#) { #; return #.#(receiver).#(#) }', 322 'function(#) { #; return #.#(receiver).#(#) }',
321 [parameterNames, 323 [parameterNames,
322 optimizedPath, 324 optimizedPath,
323 globalObject, getInterceptorName, invocationName, parameterNames]); 325 globalObject, getInterceptorName, invocationName, parameterNames]);
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 370
369 var map = new jsAst.ObjectInitializer(properties); 371 var map = new jsAst.ObjectInitializer(properties);
370 elements.add(map); 372 elements.add(map);
371 } 373 }
372 } 374 }
373 } 375 }
374 376
375 return new jsAst.ArrayInitializer(elements); 377 return new jsAst.ArrayInitializer(elements);
376 } 378 }
377 } 379 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698