OLD | NEW |
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 library dart2js.js_emitter.interceptor_stub_generator; | 5 library dart2js.js_emitter.interceptor_stub_generator; |
6 | 6 |
7 import '../compiler.dart' show Compiler; | 7 import 'package:js_runtime/shared/embedded_names.dart' as embeddedNames; |
| 8 |
| 9 import '../common_elements.dart'; |
8 import '../constants/values.dart'; | 10 import '../constants/values.dart'; |
9 import '../elements/entities.dart'; | 11 import '../elements/entities.dart'; |
10 import '../elements/types.dart' show InterfaceType; | 12 import '../elements/types.dart' show InterfaceType; |
11 import '../js/js.dart' as jsAst; | 13 import '../js/js.dart' as jsAst; |
12 import '../js/js.dart' show js; | 14 import '../js/js.dart' show js; |
13 import '../js_backend/js_backend.dart' | 15 import '../js_backend/namer.dart' show Namer; |
14 show | 16 import '../js_backend/constant_handler_javascript.dart' |
15 CustomElementsCodegenAnalysis, | 17 show JavaScriptConstantCompiler; |
16 JavaScriptBackend, | 18 import '../js_backend/custom_elements_analysis.dart' |
17 JavaScriptConstantCompiler, | 19 show CustomElementsCodegenAnalysis; |
18 Namer; | 20 import '../js_backend/native_data.dart'; |
| 21 import '../js_backend/interceptor_data.dart'; |
| 22 import '../native/enqueue.dart'; |
| 23 import '../options.dart'; |
19 import '../universe/selector.dart' show Selector; | 24 import '../universe/selector.dart' show Selector; |
| 25 import '../universe/world_builder.dart' show CodegenWorldBuilder; |
20 import '../world.dart' show ClosedWorld; | 26 import '../world.dart' show ClosedWorld; |
21 | 27 |
22 import 'code_emitter_task.dart' show Emitter; | 28 import 'code_emitter_task.dart' show CodeEmitterTask, Emitter; |
23 | 29 |
24 class InterceptorStubGenerator { | 30 class InterceptorStubGenerator { |
25 final Compiler compiler; | 31 final CompilerOptions _options; |
26 final Namer namer; | 32 final CommonElements _commonElements; |
27 final JavaScriptBackend backend; | 33 final CodeEmitterTask _emitterTask; |
28 final ClosedWorld closedWorld; | 34 final NativeCodegenEnqueuer _nativeCodegenEnqueuer; |
| 35 final JavaScriptConstantCompiler _constants; |
| 36 final Namer _namer; |
| 37 final NativeData _nativeData; |
| 38 final InterceptorData _interceptorData; |
| 39 final OneShotInterceptorData _oneShotInterceptorData; |
| 40 final CustomElementsCodegenAnalysis _customElementsCodegenAnalysis; |
| 41 final CodegenWorldBuilder _codegenWorldBuilder; |
| 42 final ClosedWorld _closedWorld; |
29 | 43 |
30 InterceptorStubGenerator( | 44 InterceptorStubGenerator( |
31 this.compiler, this.namer, this.backend, this.closedWorld); | 45 this._options, |
| 46 this._commonElements, |
| 47 this._emitterTask, |
| 48 this._nativeCodegenEnqueuer, |
| 49 this._constants, |
| 50 this._namer, |
| 51 this._nativeData, |
| 52 this._interceptorData, |
| 53 this._oneShotInterceptorData, |
| 54 this._customElementsCodegenAnalysis, |
| 55 this._codegenWorldBuilder, |
| 56 this._closedWorld); |
32 | 57 |
33 Emitter get emitter => backend.emitter.emitter; | 58 Emitter get _emitter => _emitterTask.emitter; |
34 | 59 |
35 jsAst.Expression generateGetInterceptorMethod(Set<ClassEntity> classes) { | 60 jsAst.Expression generateGetInterceptorMethod(Set<ClassEntity> classes) { |
36 jsAst.Expression interceptorFor(ClassEntity cls) { | 61 jsAst.Expression interceptorFor(ClassEntity cls) { |
37 return backend.emitter.interceptorPrototypeAccess(cls); | 62 return _emitterTask.interceptorPrototypeAccess(cls); |
38 } | 63 } |
39 | 64 |
40 /** | 65 /** |
41 * Build a JavaScrit AST node for doing a type check on | 66 * Build a JavaScrit AST node for doing a type check on |
42 * [cls]. [cls] must be a non-native interceptor class. | 67 * [cls]. [cls] must be a non-native interceptor class. |
43 */ | 68 */ |
44 jsAst.Statement buildInterceptorCheck(ClassEntity cls) { | 69 jsAst.Statement buildInterceptorCheck(ClassEntity cls) { |
45 jsAst.Expression condition; | 70 jsAst.Expression condition; |
46 assert(backend.interceptorData.isInterceptedClass(cls)); | 71 assert(_interceptorData.isInterceptedClass(cls)); |
47 if (cls == compiler.commonElements.jsBoolClass) { | 72 if (cls == _commonElements.jsBoolClass) { |
48 condition = js('(typeof receiver) == "boolean"'); | 73 condition = js('(typeof receiver) == "boolean"'); |
49 } else if (cls == compiler.commonElements.jsIntClass || | 74 } else if (cls == _commonElements.jsIntClass || |
50 cls == compiler.commonElements.jsDoubleClass || | 75 cls == _commonElements.jsDoubleClass || |
51 cls == compiler.commonElements.jsNumberClass) { | 76 cls == _commonElements.jsNumberClass) { |
52 throw 'internal error'; | 77 throw 'internal error'; |
53 } else if (cls == compiler.commonElements.jsArrayClass || | 78 } else if (cls == _commonElements.jsArrayClass || |
54 cls == compiler.commonElements.jsMutableArrayClass || | 79 cls == _commonElements.jsMutableArrayClass || |
55 cls == compiler.commonElements.jsFixedArrayClass || | 80 cls == _commonElements.jsFixedArrayClass || |
56 cls == compiler.commonElements.jsExtendableArrayClass) { | 81 cls == _commonElements.jsExtendableArrayClass) { |
57 condition = js('receiver.constructor == Array'); | 82 condition = js('receiver.constructor == Array'); |
58 } else if (cls == compiler.commonElements.jsStringClass) { | 83 } else if (cls == _commonElements.jsStringClass) { |
59 condition = js('(typeof receiver) == "string"'); | 84 condition = js('(typeof receiver) == "string"'); |
60 } else if (cls == compiler.commonElements.jsNullClass) { | 85 } else if (cls == _commonElements.jsNullClass) { |
61 condition = js('receiver == null'); | 86 condition = js('receiver == null'); |
62 } else { | 87 } else { |
63 throw 'internal error'; | 88 throw 'internal error'; |
64 } | 89 } |
65 return js.statement('if (#) return #', [condition, interceptorFor(cls)]); | 90 return js.statement('if (#) return #', [condition, interceptorFor(cls)]); |
66 } | 91 } |
67 | 92 |
68 bool hasArray = false; | 93 bool hasArray = false; |
69 bool hasBool = false; | 94 bool hasBool = false; |
70 bool hasDouble = false; | 95 bool hasDouble = false; |
71 bool hasInt = false; | 96 bool hasInt = false; |
72 bool hasNull = false; | 97 bool hasNull = false; |
73 bool hasNumber = false; | 98 bool hasNumber = false; |
74 bool hasString = false; | 99 bool hasString = false; |
75 bool hasNative = false; | 100 bool hasNative = false; |
76 bool anyNativeClasses = | 101 bool anyNativeClasses = _nativeCodegenEnqueuer.hasInstantiatedNativeClasses; |
77 backend.nativeCodegenEnqueuer.hasInstantiatedNativeClasses; | |
78 | 102 |
79 for (ClassEntity cls in classes) { | 103 for (ClassEntity cls in classes) { |
80 if (cls == compiler.commonElements.jsArrayClass || | 104 if (cls == _commonElements.jsArrayClass || |
81 cls == compiler.commonElements.jsMutableArrayClass || | 105 cls == _commonElements.jsMutableArrayClass || |
82 cls == compiler.commonElements.jsFixedArrayClass || | 106 cls == _commonElements.jsFixedArrayClass || |
83 cls == compiler.commonElements.jsExtendableArrayClass) | 107 cls == _commonElements.jsExtendableArrayClass) |
84 hasArray = true; | 108 hasArray = true; |
85 else if (cls == compiler.commonElements.jsBoolClass) | 109 else if (cls == _commonElements.jsBoolClass) |
86 hasBool = true; | 110 hasBool = true; |
87 else if (cls == compiler.commonElements.jsDoubleClass) | 111 else if (cls == _commonElements.jsDoubleClass) |
88 hasDouble = true; | 112 hasDouble = true; |
89 else if (cls == compiler.commonElements.jsIntClass) | 113 else if (cls == _commonElements.jsIntClass) |
90 hasInt = true; | 114 hasInt = true; |
91 else if (cls == compiler.commonElements.jsNullClass) | 115 else if (cls == _commonElements.jsNullClass) |
92 hasNull = true; | 116 hasNull = true; |
93 else if (cls == compiler.commonElements.jsNumberClass) | 117 else if (cls == _commonElements.jsNumberClass) |
94 hasNumber = true; | 118 hasNumber = true; |
95 else if (cls == compiler.commonElements.jsStringClass) | 119 else if (cls == _commonElements.jsStringClass) |
96 hasString = true; | 120 hasString = true; |
97 else { | 121 else { |
98 // The set of classes includes classes mixed-in to interceptor classes | 122 // The set of classes includes classes mixed-in to interceptor classes |
99 // and user extensions of native classes. | 123 // and user extensions of native classes. |
100 // | 124 // |
101 // The set of classes also includes the 'primitive' interceptor | 125 // The set of classes also includes the 'primitive' interceptor |
102 // PlainJavaScriptObject even when it has not been resolved, since it is | 126 // PlainJavaScriptObject even when it has not been resolved, since it is |
103 // only resolved through the reference in getNativeInterceptor when | 127 // only resolved through the reference in getNativeInterceptor when |
104 // getNativeInterceptor is marked as used. Guard against probing | 128 // getNativeInterceptor is marked as used. Guard against probing |
105 // unresolved PlainJavaScriptObject by testing for anyNativeClasses. | 129 // unresolved PlainJavaScriptObject by testing for anyNativeClasses. |
106 | 130 |
107 if (anyNativeClasses) { | 131 if (anyNativeClasses) { |
108 if (backend.nativeData.isNativeOrExtendsNative(cls)) hasNative = true; | 132 if (_nativeData.isNativeOrExtendsNative(cls)) hasNative = true; |
109 } | 133 } |
110 } | 134 } |
111 } | 135 } |
112 if (hasDouble) { | 136 if (hasDouble) { |
113 hasNumber = true; | 137 hasNumber = true; |
114 } | 138 } |
115 if (hasInt) hasNumber = true; | 139 if (hasInt) hasNumber = true; |
116 | 140 |
117 if (classes.containsAll(backend.interceptorData.interceptedClasses)) { | 141 if (classes.containsAll(_interceptorData.interceptedClasses)) { |
118 // I.e. this is the general interceptor. | 142 // I.e. this is the general interceptor. |
119 hasNative = anyNativeClasses; | 143 hasNative = anyNativeClasses; |
120 } | 144 } |
121 | 145 |
122 List<jsAst.Statement> statements = <jsAst.Statement>[]; | 146 List<jsAst.Statement> statements = <jsAst.Statement>[]; |
123 | 147 |
124 if (hasNumber) { | 148 if (hasNumber) { |
125 jsAst.Statement whenNumber; | 149 jsAst.Statement whenNumber; |
126 | 150 |
127 /// Note: there are two number classes in play: Dart's [num], | 151 /// Note: there are two number classes in play: Dart's [num], |
128 /// and JavaScript's Number (typeof receiver == 'number'). This | 152 /// and JavaScript's Number (typeof receiver == 'number'). This |
129 /// is the fallback used when we have determined that receiver | 153 /// is the fallback used when we have determined that receiver |
130 /// is a JavaScript Number. | 154 /// is a JavaScript Number. |
131 jsAst.Expression interceptorForNumber = interceptorFor(hasDouble | 155 jsAst.Expression interceptorForNumber = interceptorFor(hasDouble |
132 ? compiler.commonElements.jsDoubleClass | 156 ? _commonElements.jsDoubleClass |
133 : compiler.commonElements.jsNumberClass); | 157 : _commonElements.jsNumberClass); |
134 | 158 |
135 if (hasInt) { | 159 if (hasInt) { |
136 whenNumber = js.statement( | 160 whenNumber = js.statement( |
137 '''{ | 161 '''{ |
138 if (Math.floor(receiver) == receiver) return #; | 162 if (Math.floor(receiver) == receiver) return #; |
139 return #; | 163 return #; |
140 }''', | 164 }''', |
141 [ | 165 [interceptorFor(_commonElements.jsIntClass), interceptorForNumber]); |
142 interceptorFor(compiler.commonElements.jsIntClass), | |
143 interceptorForNumber | |
144 ]); | |
145 } else { | 166 } else { |
146 whenNumber = js.statement('return #', interceptorForNumber); | 167 whenNumber = js.statement('return #', interceptorForNumber); |
147 } | 168 } |
148 statements | 169 statements |
149 .add(js.statement('if (typeof receiver == "number") #;', whenNumber)); | 170 .add(js.statement('if (typeof receiver == "number") #;', whenNumber)); |
150 } | 171 } |
151 | 172 |
152 if (hasString) { | 173 if (hasString) { |
153 statements | 174 statements.add(buildInterceptorCheck(_commonElements.jsStringClass)); |
154 .add(buildInterceptorCheck(compiler.commonElements.jsStringClass)); | |
155 } | 175 } |
156 if (hasNull) { | 176 if (hasNull) { |
157 statements | 177 statements.add(buildInterceptorCheck(_commonElements.jsNullClass)); |
158 .add(buildInterceptorCheck(compiler.commonElements.jsNullClass)); | |
159 } else { | 178 } else { |
160 // Returning "undefined" or "null" here will provoke a JavaScript | 179 // Returning "undefined" or "null" here will provoke a JavaScript |
161 // TypeError which is later identified as a null-error by | 180 // TypeError which is later identified as a null-error by |
162 // [unwrapException] in js_helper.dart. | 181 // [unwrapException] in js_helper.dart. |
163 statements.add(js.statement('if (receiver == null) return receiver')); | 182 statements.add(js.statement('if (receiver == null) return receiver')); |
164 } | 183 } |
165 if (hasBool) { | 184 if (hasBool) { |
166 statements | 185 statements.add(buildInterceptorCheck(_commonElements.jsBoolClass)); |
167 .add(buildInterceptorCheck(compiler.commonElements.jsBoolClass)); | |
168 } | 186 } |
169 // TODO(ahe): It might be faster to check for Array before | 187 // TODO(ahe): It might be faster to check for Array before |
170 // function and bool. | 188 // function and bool. |
171 if (hasArray) { | 189 if (hasArray) { |
172 statements | 190 statements.add(buildInterceptorCheck(_commonElements.jsArrayClass)); |
173 .add(buildInterceptorCheck(compiler.commonElements.jsArrayClass)); | |
174 } | 191 } |
175 | 192 |
176 if (hasNative) { | 193 if (hasNative) { |
177 statements.add(js.statement( | 194 statements.add(js.statement( |
178 r'''{ | 195 r'''{ |
179 if (typeof receiver != "object") { | 196 if (typeof receiver != "object") { |
180 if (typeof receiver == "function" ) return #; | 197 if (typeof receiver == "function" ) return #; |
181 return receiver; | 198 return receiver; |
182 } | 199 } |
183 if (receiver instanceof #) return receiver; | 200 if (receiver instanceof #) return receiver; |
184 return #(receiver); | 201 return #(receiver); |
185 }''', | 202 }''', |
186 [ | 203 [ |
187 interceptorFor(compiler.commonElements.jsJavaScriptFunctionClass), | 204 interceptorFor(_commonElements.jsJavaScriptFunctionClass), |
188 backend.emitter | 205 _emitter.constructorAccess(_commonElements.objectClass), |
189 .constructorAccess(compiler.commonElements.objectClass), | 206 _emitter.staticFunctionAccess( |
190 backend.emitter.staticFunctionAccess( | 207 _commonElements.getNativeInterceptorMethod) |
191 compiler.commonElements.getNativeInterceptorMethod) | |
192 ])); | 208 ])); |
193 } else { | 209 } else { |
194 ClassEntity jsUnknown = | 210 ClassEntity jsUnknown = _commonElements.jsUnknownJavaScriptObjectClass; |
195 compiler.commonElements.jsUnknownJavaScriptObjectClass; | 211 if (_codegenWorldBuilder.directlyInstantiatedClasses |
196 if (compiler.codegenWorldBuilder.directlyInstantiatedClasses | |
197 .contains(jsUnknown)) { | 212 .contains(jsUnknown)) { |
198 statements.add(js.statement('if (!(receiver instanceof #)) return #;', [ | 213 statements.add(js.statement('if (!(receiver instanceof #)) return #;', [ |
199 backend.emitter | 214 _emitter.constructorAccess(_commonElements.objectClass), |
200 .constructorAccess(compiler.commonElements.objectClass), | |
201 interceptorFor(jsUnknown) | 215 interceptorFor(jsUnknown) |
202 ])); | 216 ])); |
203 } | 217 } |
204 | 218 |
205 statements.add(js.statement('return receiver')); | 219 statements.add(js.statement('return receiver')); |
206 } | 220 } |
207 | 221 |
208 return js('''function(receiver) { #; }''', new jsAst.Block(statements)); | 222 return js('''function(receiver) { #; }''', new jsAst.Block(statements)); |
209 } | 223 } |
210 | 224 |
| 225 jsAst.Call _generateIsJsIndexableCall( |
| 226 jsAst.Expression use1, jsAst.Expression use2) { |
| 227 String dispatchPropertyName = embeddedNames.DISPATCH_PROPERTY_NAME; |
| 228 jsAst.Expression dispatchProperty = |
| 229 _emitter.generateEmbeddedGlobalAccess(dispatchPropertyName); |
| 230 |
| 231 // We pass the dispatch property record to the isJsIndexable |
| 232 // helper rather than reading it inside the helper to increase the |
| 233 // chance of making the dispatch record access monomorphic. |
| 234 jsAst.PropertyAccess record = |
| 235 new jsAst.PropertyAccess(use2, dispatchProperty); |
| 236 |
| 237 List<jsAst.Expression> arguments = <jsAst.Expression>[use1, record]; |
| 238 FunctionEntity helper = _commonElements.isJsIndexable; |
| 239 jsAst.Expression helperExpression = _emitter.staticFunctionAccess(helper); |
| 240 return new jsAst.Call(helperExpression, arguments); |
| 241 } |
| 242 |
211 // Returns a statement that takes care of performance critical | 243 // Returns a statement that takes care of performance critical |
212 // common case for a one-shot interceptor, or null if there is no | 244 // common case for a one-shot interceptor, or null if there is no |
213 // fast path. | 245 // fast path. |
214 jsAst.Statement _fastPathForOneShotInterceptor( | 246 jsAst.Statement _fastPathForOneShotInterceptor( |
215 Selector selector, Set<ClassEntity> classes) { | 247 Selector selector, Set<ClassEntity> classes) { |
216 if (selector.isOperator) { | 248 if (selector.isOperator) { |
217 String name = selector.name; | 249 String name = selector.name; |
218 if (name == '==') { | 250 if (name == '==') { |
219 return js.statement('''{ | 251 return js.statement('''{ |
220 if (receiver == null) return a0 == null; | 252 if (receiver == null) return a0 == null; |
221 if (typeof receiver != "object") | 253 if (typeof receiver != "object") |
222 return a0 != null && receiver === a0; | 254 return a0 != null && receiver === a0; |
223 }'''); | 255 }'''); |
224 } | 256 } |
225 if (!classes.contains(compiler.commonElements.jsIntClass) && | 257 if (!classes.contains(_commonElements.jsIntClass) && |
226 !classes.contains(compiler.commonElements.jsNumberClass) && | 258 !classes.contains(_commonElements.jsNumberClass) && |
227 !classes.contains(compiler.commonElements.jsDoubleClass)) { | 259 !classes.contains(_commonElements.jsDoubleClass)) { |
228 return null; | 260 return null; |
229 } | 261 } |
230 if (selector.argumentCount == 1) { | 262 if (selector.argumentCount == 1) { |
231 // The following operators do not map to a JavaScript operator. | 263 // The following operators do not map to a JavaScript operator. |
232 if (name == '~/' || name == '<<' || name == '%' || name == '>>') { | 264 if (name == '~/' || name == '<<' || name == '%' || name == '>>') { |
233 return null; | 265 return null; |
234 } | 266 } |
235 jsAst.Expression result = js('receiver $name a0'); | 267 jsAst.Expression result = js('receiver $name a0'); |
236 if (name == '&' || name == '|' || name == '^') { | 268 if (name == '&' || name == '|' || name == '^') { |
237 result = js('# >>> 0', result); | 269 result = js('# >>> 0', result); |
(...skipping 26 matching lines...) Expand all Loading... |
264 // | 296 // |
265 // For an index set operation, this code generates: | 297 // For an index set operation, this code generates: |
266 // | 298 // |
267 // if (typeof a0 === "number") { | 299 // if (typeof a0 === "number") { |
268 // if (receiver.constructor == Array && !receiver.immutable$list) { | 300 // if (receiver.constructor == Array && !receiver.immutable$list) { |
269 // if (a0 >>> 0 === a0 && a0 < receiver.length) { | 301 // if (a0 >>> 0 === a0 && a0 < receiver.length) { |
270 // return receiver[a0] = a1; | 302 // return receiver[a0] = a1; |
271 // } | 303 // } |
272 // } | 304 // } |
273 // } | 305 // } |
274 bool containsArray = | 306 bool containsArray = classes.contains(_commonElements.jsArrayClass); |
275 classes.contains(compiler.commonElements.jsArrayClass); | 307 bool containsString = classes.contains(_commonElements.jsStringClass); |
276 bool containsString = | 308 bool containsJsIndexable = _closedWorld |
277 classes.contains(compiler.commonElements.jsStringClass); | 309 .isImplemented(_commonElements.jsIndexingBehaviorInterface) && |
278 bool containsJsIndexable = closedWorld.isImplemented( | |
279 compiler.commonElements.jsIndexingBehaviorInterface) && | |
280 classes.any((cls) { | 310 classes.any((cls) { |
281 return closedWorld.isSubtypeOf( | 311 return _closedWorld.isSubtypeOf( |
282 cls, compiler.commonElements.jsIndexingBehaviorInterface); | 312 cls, _commonElements.jsIndexingBehaviorInterface); |
283 }); | 313 }); |
284 // The index set operator requires a check on its set value in | 314 // The index set operator requires a check on its set value in |
285 // checked mode, so we don't optimize the interceptor if the | 315 // checked mode, so we don't optimize the interceptor if the |
286 // compiler has type assertions enabled. | 316 // _compiler has type assertions enabled. |
287 if (selector.isIndexSet && | 317 if (selector.isIndexSet && |
288 (compiler.options.enableTypeAssertions || !containsArray)) { | 318 (_options.enableTypeAssertions || !containsArray)) { |
289 return null; | 319 return null; |
290 } | 320 } |
291 if (!containsArray && !containsString) { | 321 if (!containsArray && !containsString) { |
292 return null; | 322 return null; |
293 } | 323 } |
294 jsAst.Expression arrayCheck = js('receiver.constructor == Array'); | 324 jsAst.Expression arrayCheck = js('receiver.constructor == Array'); |
295 jsAst.Expression indexableCheck = | 325 jsAst.Expression indexableCheck = |
296 backend.generateIsJsIndexableCall(js('receiver'), js('receiver')); | 326 _generateIsJsIndexableCall(js('receiver'), js('receiver')); |
297 | 327 |
298 jsAst.Expression orExp(left, right) { | 328 jsAst.Expression orExp(left, right) { |
299 return left == null ? right : js('# || #', [left, right]); | 329 return left == null ? right : js('# || #', [left, right]); |
300 } | 330 } |
301 | 331 |
302 if (selector.isIndex) { | 332 if (selector.isIndex) { |
303 jsAst.Expression typeCheck; | 333 jsAst.Expression typeCheck; |
304 if (containsArray) { | 334 if (containsArray) { |
305 typeCheck = arrayCheck; | 335 typeCheck = arrayCheck; |
306 } | 336 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
339 return receiver[a0] = a1; | 369 return receiver[a0] = a1; |
340 ''', | 370 ''', |
341 typeCheck); | 371 typeCheck); |
342 } | 372 } |
343 } | 373 } |
344 return null; | 374 return null; |
345 } | 375 } |
346 | 376 |
347 jsAst.Expression generateOneShotInterceptor(jsAst.Name name) { | 377 jsAst.Expression generateOneShotInterceptor(jsAst.Name name) { |
348 Selector selector = | 378 Selector selector = |
349 backend.oneShotInterceptorData.getOneShotInterceptorSelector(name); | 379 _oneShotInterceptorData.getOneShotInterceptorSelector(name); |
350 Set<ClassEntity> classes = | 380 Set<ClassEntity> classes = |
351 backend.interceptorData.getInterceptedClassesOn(selector.name); | 381 _interceptorData.getInterceptedClassesOn(selector.name); |
352 jsAst.Name getInterceptorName = namer.nameForGetInterceptor(classes); | 382 jsAst.Name getInterceptorName = _namer.nameForGetInterceptor(classes); |
353 | 383 |
354 List<String> parameterNames = <String>[]; | 384 List<String> parameterNames = <String>[]; |
355 parameterNames.add('receiver'); | 385 parameterNames.add('receiver'); |
356 | 386 |
357 if (selector.isSetter) { | 387 if (selector.isSetter) { |
358 parameterNames.add('value'); | 388 parameterNames.add('value'); |
359 } else { | 389 } else { |
360 for (int i = 0; i < selector.argumentCount; i++) { | 390 for (int i = 0; i < selector.argumentCount; i++) { |
361 parameterNames.add('a$i'); | 391 parameterNames.add('a$i'); |
362 } | 392 } |
363 } | 393 } |
364 | 394 |
365 jsAst.Name invocationName = backend.namer.invocationName(selector); | 395 jsAst.Name invocationName = _namer.invocationName(selector); |
366 String globalObject = namer | 396 String globalObject = |
367 .globalObjectForLibrary(compiler.commonElements.interceptorsLibrary); | 397 _namer.globalObjectForLibrary(_commonElements.interceptorsLibrary); |
368 | 398 |
369 jsAst.Statement optimizedPath = | 399 jsAst.Statement optimizedPath = |
370 _fastPathForOneShotInterceptor(selector, classes); | 400 _fastPathForOneShotInterceptor(selector, classes); |
371 if (optimizedPath == null) optimizedPath = js.statement(';'); | 401 if (optimizedPath == null) optimizedPath = js.statement(';'); |
372 | 402 |
373 return js('function(#) { #; return #.#(receiver).#(#) }', [ | 403 return js('function(#) { #; return #.#(receiver).#(#) }', [ |
374 parameterNames, | 404 parameterNames, |
375 optimizedPath, | 405 optimizedPath, |
376 globalObject, | 406 globalObject, |
377 getInterceptorName, | 407 getInterceptorName, |
378 invocationName, | 408 invocationName, |
379 parameterNames | 409 parameterNames |
380 ]); | 410 ]); |
381 } | 411 } |
382 | 412 |
383 jsAst.ArrayInitializer generateTypeToInterceptorMap() { | 413 jsAst.ArrayInitializer generateTypeToInterceptorMap() { |
384 // TODO(sra): Perhaps inject a constant instead? | 414 // TODO(sra): Perhaps inject a constant instead? |
385 CustomElementsCodegenAnalysis analysis = | 415 CustomElementsCodegenAnalysis analysis = _customElementsCodegenAnalysis; |
386 backend.customElementsCodegenAnalysis; | |
387 if (!analysis.needsTable) return null; | 416 if (!analysis.needsTable) return null; |
388 | 417 |
389 List<jsAst.Expression> elements = <jsAst.Expression>[]; | 418 List<jsAst.Expression> elements = <jsAst.Expression>[]; |
390 JavaScriptConstantCompiler handler = backend.constants; | |
391 List<ConstantValue> constants = | 419 List<ConstantValue> constants = |
392 handler.getConstantsForEmission(emitter.compareConstants); | 420 _constants.getConstantsForEmission(_emitter.compareConstants); |
393 for (ConstantValue constant in constants) { | 421 for (ConstantValue constant in constants) { |
394 if (constant is TypeConstantValue && | 422 if (constant is TypeConstantValue && |
395 constant.representedType is InterfaceType) { | 423 constant.representedType is InterfaceType) { |
396 InterfaceType type = constant.representedType; | 424 InterfaceType type = constant.representedType; |
397 ClassEntity classElement = type.element; | 425 ClassEntity classElement = type.element; |
398 if (!analysis.needsClass(classElement)) continue; | 426 if (!analysis.needsClass(classElement)) continue; |
399 | 427 |
400 elements.add(emitter.constantReference(constant)); | 428 elements.add(_emitter.constantReference(constant)); |
401 elements.add(backend.emitter.interceptorClassAccess(classElement)); | 429 elements.add(_emitter.interceptorClassAccess(classElement)); |
402 | 430 |
403 // Create JavaScript Object map for by-name lookup of generative | 431 // Create JavaScript Object map for by-name lookup of generative |
404 // constructors. For example, the class A has three generative | 432 // constructors. For example, the class A has three generative |
405 // constructors | 433 // constructors |
406 // | 434 // |
407 // class A { | 435 // class A { |
408 // A() {} | 436 // A() {} |
409 // A.foo() {} | 437 // A.foo() {} |
410 // A.bar() {} | 438 // A.bar() {} |
411 // } | 439 // } |
412 // | 440 // |
413 // Which are described by the map | 441 // Which are described by the map |
414 // | 442 // |
415 // {"": A.A$, "foo": A.A$foo, "bar": A.A$bar} | 443 // {"": A.A$, "foo": A.A$foo, "bar": A.A$bar} |
416 // | 444 // |
417 // We expect most of the time the map will be a singleton. | 445 // We expect most of the time the map will be a singleton. |
418 var properties = []; | 446 var properties = []; |
419 for (ConstructorEntity member in analysis.constructors(classElement)) { | 447 for (ConstructorEntity member in analysis.constructors(classElement)) { |
420 properties.add(new jsAst.Property(js.string(member.name), | 448 properties.add(new jsAst.Property( |
421 backend.emitter.staticFunctionAccess(member))); | 449 js.string(member.name), _emitter.staticFunctionAccess(member))); |
422 } | 450 } |
423 | 451 |
424 var map = new jsAst.ObjectInitializer(properties); | 452 var map = new jsAst.ObjectInitializer(properties); |
425 elements.add(map); | 453 elements.add(map); |
426 } | 454 } |
427 } | 455 } |
428 | 456 |
429 return new jsAst.ArrayInitializer(elements); | 457 return new jsAst.ArrayInitializer(elements); |
430 } | 458 } |
431 } | 459 } |
OLD | NEW |