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 part of dart2js.js_emitter; | 5 part of dart2js.js_emitter; |
6 | 6 |
7 class InterceptorEmitter extends CodeEmitterHelper { | 7 class InterceptorEmitter extends CodeEmitterHelper { |
8 final Set<String> interceptorInvocationNames = new Set<String>(); | 8 final Set<String> interceptorInvocationNames = new Set<String>(); |
9 | 9 |
10 void recordMangledNameOfMemberMethod(FunctionElement member, String name) { | 10 void recordMangledNameOfMemberMethod(FunctionElement member, String name) { |
(...skipping 11 matching lines...) Expand all Loading... |
22 InterceptorConstant interceptorConstant = constant; | 22 InterceptorConstant interceptorConstant = constant; |
23 classes.add(interceptorConstant.dispatchedType.element); | 23 classes.add(interceptorConstant.dispatchedType.element); |
24 } | 24 } |
25 } | 25 } |
26 return classes; | 26 return classes; |
27 } | 27 } |
28 | 28 |
29 void emitGetInterceptorMethod(CodeBuffer buffer, | 29 void emitGetInterceptorMethod(CodeBuffer buffer, |
30 String key, | 30 String key, |
31 Set<ClassElement> classes) { | 31 Set<ClassElement> classes) { |
32 jsAst.Statement buildReturnInterceptor(ClassElement cls) { | 32 jsAst.Expression interceptorFor(ClassElement cls) { |
33 return js.return_(js(namer.isolateAccess(cls))['prototype']); | 33 return js('#.prototype', namer.elementAccess(cls)); |
34 } | 34 } |
35 | 35 |
36 /** | 36 /** |
37 * Build a JavaScrit AST node for doing a type check on | 37 * Build a JavaScrit AST node for doing a type check on |
38 * [cls]. [cls] must be an interceptor class. | 38 * [cls]. [cls] must be a non-native interceptor class. |
39 */ | 39 */ |
40 jsAst.Statement buildInterceptorCheck(ClassElement cls) { | 40 jsAst.Statement buildInterceptorCheck(ClassElement cls) { |
41 jsAst.Expression condition; | 41 jsAst.Expression condition; |
42 assert(backend.isInterceptorClass(cls)); | 42 assert(backend.isInterceptorClass(cls)); |
43 if (cls == backend.jsBoolClass) { | 43 if (cls == backend.jsBoolClass) { |
44 condition = js('(typeof receiver) == "boolean"'); | 44 condition = js('(typeof receiver) == "boolean"'); |
45 } else if (cls == backend.jsIntClass || | 45 } else if (cls == backend.jsIntClass || |
46 cls == backend.jsDoubleClass || | 46 cls == backend.jsDoubleClass || |
47 cls == backend.jsNumberClass) { | 47 cls == backend.jsNumberClass) { |
48 throw 'internal error'; | 48 throw 'internal error'; |
49 } else if (cls == backend.jsArrayClass || | 49 } else if (cls == backend.jsArrayClass || |
50 cls == backend.jsMutableArrayClass || | 50 cls == backend.jsMutableArrayClass || |
51 cls == backend.jsFixedArrayClass || | 51 cls == backend.jsFixedArrayClass || |
52 cls == backend.jsExtendableArrayClass) { | 52 cls == backend.jsExtendableArrayClass) { |
53 condition = js('receiver.constructor == Array'); | 53 condition = js('receiver.constructor == Array'); |
54 } else if (cls == backend.jsStringClass) { | 54 } else if (cls == backend.jsStringClass) { |
55 condition = js('(typeof receiver) == "string"'); | 55 condition = js('(typeof receiver) == "string"'); |
56 } else if (cls == backend.jsNullClass) { | 56 } else if (cls == backend.jsNullClass) { |
57 condition = js('receiver == null'); | 57 condition = js('receiver == null'); |
58 } else { | 58 } else { |
59 throw 'internal error'; | 59 throw 'internal error'; |
60 } | 60 } |
61 return js.if_(condition, buildReturnInterceptor(cls)); | 61 return js.statement('if (#) return #', [condition, interceptorFor(cls)]); |
62 } | 62 } |
63 | 63 |
64 bool hasArray = false; | 64 bool hasArray = false; |
65 bool hasBool = false; | 65 bool hasBool = false; |
66 bool hasDouble = false; | 66 bool hasDouble = false; |
67 bool hasInt = false; | 67 bool hasInt = false; |
68 bool hasNull = false; | 68 bool hasNull = false; |
69 bool hasNumber = false; | 69 bool hasNumber = false; |
70 bool hasString = false; | 70 bool hasString = false; |
71 bool hasNative = false; | 71 bool hasNative = false; |
(...skipping 29 matching lines...) Expand all Loading... |
101 if (hasDouble) { | 101 if (hasDouble) { |
102 hasNumber = true; | 102 hasNumber = true; |
103 } | 103 } |
104 if (hasInt) hasNumber = true; | 104 if (hasInt) hasNumber = true; |
105 | 105 |
106 if (classes.containsAll(backend.interceptedClasses)) { | 106 if (classes.containsAll(backend.interceptedClasses)) { |
107 // I.e. this is the general interceptor. | 107 // I.e. this is the general interceptor. |
108 hasNative = anyNativeClasses; | 108 hasNative = anyNativeClasses; |
109 } | 109 } |
110 | 110 |
111 jsAst.Block block = new jsAst.Block.empty(); | 111 List<Statement> statements = <Statement>[]; |
112 | 112 |
113 if (hasNumber) { | 113 if (hasNumber) { |
114 jsAst.Statement whenNumber; | 114 jsAst.Statement whenNumber; |
115 | 115 |
116 /// Note: there are two number classes in play: Dart's [num], | 116 /// Note: there are two number classes in play: Dart's [num], |
117 /// and JavaScript's Number (typeof receiver == 'number'). This | 117 /// and JavaScript's Number (typeof receiver == 'number'). This |
118 /// is the fallback used when we have determined that receiver | 118 /// is the fallback used when we have determined that receiver |
119 /// is a JavaScript Number. | 119 /// is a JavaScript Number. |
120 jsAst.Return returnNumberClass = buildReturnInterceptor( | 120 jsAst.Expression interceptorForNumber = interceptorFor( |
121 hasDouble ? backend.jsDoubleClass : backend.jsNumberClass); | 121 hasDouble ? backend.jsDoubleClass : backend.jsNumberClass); |
122 | 122 |
123 if (hasInt) { | 123 if (hasInt) { |
124 jsAst.Expression isInt = js('Math.floor(receiver) == receiver'); | 124 whenNumber = js.statement('''{ |
125 whenNumber = js.block([ | 125 if (Math.floor(receiver) == receiver) return #; |
126 js.if_(isInt, buildReturnInterceptor(backend.jsIntClass)), | 126 return #; |
127 returnNumberClass]); | 127 }''', [interceptorFor(backend.jsIntClass), interceptorForNumber]); |
128 } else { | 128 } else { |
129 whenNumber = returnNumberClass; | 129 whenNumber = js.statement('return #', interceptorForNumber); |
130 } | 130 } |
131 block.statements.add( | 131 statements.add( |
132 js.if_('(typeof receiver) == "number"', | 132 js.statement('if (typeof receiver == "number") #;', whenNumber)); |
133 whenNumber)); | |
134 } | 133 } |
135 | 134 |
136 if (hasString) { | 135 if (hasString) { |
137 block.statements.add(buildInterceptorCheck(backend.jsStringClass)); | 136 statements.add(buildInterceptorCheck(backend.jsStringClass)); |
138 } | 137 } |
139 if (hasNull) { | 138 if (hasNull) { |
140 block.statements.add(buildInterceptorCheck(backend.jsNullClass)); | 139 statements.add(buildInterceptorCheck(backend.jsNullClass)); |
141 } else { | 140 } else { |
142 // Returning "undefined" or "null" here will provoke a JavaScript | 141 // Returning "undefined" or "null" here will provoke a JavaScript |
143 // TypeError which is later identified as a null-error by | 142 // TypeError which is later identified as a null-error by |
144 // [unwrapException] in js_helper.dart. | 143 // [unwrapException] in js_helper.dart. |
145 block.statements.add(js.if_('receiver == null', | 144 statements.add( |
146 js.return_(js('receiver')))); | 145 js.statement('if (receiver == null) return receiver')); |
147 } | 146 } |
148 if (hasBool) { | 147 if (hasBool) { |
149 block.statements.add(buildInterceptorCheck(backend.jsBoolClass)); | 148 statements.add(buildInterceptorCheck(backend.jsBoolClass)); |
150 } | 149 } |
151 // TODO(ahe): It might be faster to check for Array before | 150 // TODO(ahe): It might be faster to check for Array before |
152 // function and bool. | 151 // function and bool. |
153 if (hasArray) { | 152 if (hasArray) { |
154 block.statements.add(buildInterceptorCheck(backend.jsArrayClass)); | 153 statements.add(buildInterceptorCheck(backend.jsArrayClass)); |
155 } | 154 } |
156 | 155 |
157 if (hasNative) { | 156 if (hasNative) { |
158 block.statements.add( | 157 statements.add(js.statement(r'''{ |
159 js.if_( | 158 if (typeof receiver != "object") return receiver; |
160 js('(typeof receiver) != "object"'), | 159 if (receiver instanceof #) return receiver; |
161 js.return_(js('receiver')))); | 160 return #(receiver); |
162 | 161 }''', [ |
163 // if (receiver instanceof $.Object) return receiver; | 162 namer.elementAccess(compiler.objectClass), |
164 // return $.getNativeInterceptor(receiver); | 163 namer.elementAccess(backend.getNativeInterceptorMethod)])); |
165 block.statements.add( | |
166 js.if_(js('receiver instanceof #', | |
167 js(namer.isolateAccess(compiler.objectClass))), | |
168 js.return_(js('receiver')))); | |
169 block.statements.add( | |
170 js.return_( | |
171 js(namer.isolateAccess(backend.getNativeInterceptorMethod))( | |
172 ['receiver']))); | |
173 | 164 |
174 } else { | 165 } else { |
175 ClassElement jsUnknown = backend.jsUnknownJavaScriptObjectClass; | 166 ClassElement jsUnknown = backend.jsUnknownJavaScriptObjectClass; |
176 if (compiler.codegenWorld.instantiatedClasses.contains(jsUnknown)) { | 167 if (compiler.codegenWorld.instantiatedClasses.contains(jsUnknown)) { |
177 block.statements.add( | 168 statements.add( |
178 js.if_(js('!(receiver instanceof #)', | 169 js.statement('if (!(receiver instanceof #)) return #;', |
179 js(namer.isolateAccess(compiler.objectClass))), | 170 [namer.elementAccess(compiler.objectClass), |
180 buildReturnInterceptor(jsUnknown))); | 171 interceptorFor(jsUnknown)])); |
181 } | 172 } |
182 | 173 |
183 block.statements.add(js.return_(js('receiver'))); | 174 statements.add(js.statement('return receiver')); |
184 } | 175 } |
185 | 176 |
186 buffer.write(jsAst.prettyPrint( | 177 buffer.write(jsAst.prettyPrint( |
187 js('${namer.globalObjectFor(compiler.interceptorsLibrary)}.$key = #', | 178 js('''${namer.globalObjectFor(compiler.interceptorsLibrary)}.# = |
188 js.fun(['receiver'], block)), | 179 function(receiver) { #; }''', |
| 180 [key, statements]), |
189 compiler)); | 181 compiler)); |
190 buffer.write(N); | 182 buffer.write(N); |
191 } | 183 } |
192 | 184 |
193 /** | 185 /** |
194 * Emit all versions of the [:getInterceptor:] method. | 186 * Emit all versions of the [:getInterceptor:] method. |
195 */ | 187 */ |
196 void emitGetInterceptorMethods(CodeBuffer buffer) { | 188 void emitGetInterceptorMethods(CodeBuffer buffer) { |
197 task.addComment('getInterceptor methods', buffer); | 189 task.addComment('getInterceptor methods', buffer); |
198 Map<String, Set<ClassElement>> specializedGetInterceptors = | 190 Map<String, Set<ClassElement>> specializedGetInterceptors = |
199 backend.specializedGetInterceptors; | 191 backend.specializedGetInterceptors; |
200 for (String name in specializedGetInterceptors.keys.toList()..sort()) { | 192 for (String name in specializedGetInterceptors.keys.toList()..sort()) { |
201 Set<ClassElement> classes = specializedGetInterceptors[name]; | 193 Set<ClassElement> classes = specializedGetInterceptors[name]; |
202 emitGetInterceptorMethod(buffer, name, classes); | 194 emitGetInterceptorMethod(buffer, name, classes); |
203 } | 195 } |
204 } | 196 } |
205 | 197 |
206 // Returns a statement that takes care of performance critical | 198 // Returns a statement that takes care of performance critical |
207 // common case for a one-shot interceptor, or null if there is no | 199 // common case for a one-shot interceptor, or null if there is no |
208 // fast path. | 200 // fast path. |
209 jsAst.Statement fastPathForOneShotInterceptor(Selector selector, | 201 jsAst.Statement fastPathForOneShotInterceptor(Selector selector, |
210 Set<ClassElement> classes) { | 202 Set<ClassElement> classes) { |
211 jsAst.Expression isNumber(String variable) { | |
212 return js('typeof $variable == "number"'); | |
213 } | |
214 | |
215 jsAst.Expression isNotObject(String variable) { | |
216 return js('typeof $variable != "object"'); | |
217 } | |
218 | |
219 jsAst.Expression isInt(String variable) { | |
220 return isNumber(variable).binary('&&', | |
221 js('Math.floor($variable) == $variable')); | |
222 } | |
223 | |
224 jsAst.Expression tripleShiftZero(jsAst.Expression receiver) { | |
225 return receiver.binary('>>>', js('0')); | |
226 } | |
227 | 203 |
228 if (selector.isOperator()) { | 204 if (selector.isOperator()) { |
229 String name = selector.name; | 205 String name = selector.name; |
230 if (name == '==') { | 206 if (name == '==') { |
231 // Unfolds to: | 207 return js.statement('''{ |
232 // if (receiver == null) return a0 == null; | 208 if (receiver == null) return a0 == null; |
233 // if (typeof receiver != 'object') { | 209 if (typeof receiver != "object") |
234 // return a0 != null && receiver === a0; | 210 return a0 != null && receiver === a0; |
235 // } | 211 }'''); |
236 List<jsAst.Statement> body = <jsAst.Statement>[]; | |
237 body.add(js.if_('receiver == null', js.return_(js('a0 == null')))); | |
238 body.add(js.if_( | |
239 isNotObject('receiver'), | |
240 js.return_(js('a0 != null && receiver === a0')))); | |
241 return new jsAst.Block(body); | |
242 } | 212 } |
243 if (!classes.contains(backend.jsIntClass) | 213 if (!classes.contains(backend.jsIntClass) |
244 && !classes.contains(backend.jsNumberClass) | 214 && !classes.contains(backend.jsNumberClass) |
245 && !classes.contains(backend.jsDoubleClass)) { | 215 && !classes.contains(backend.jsDoubleClass)) { |
246 return null; | 216 return null; |
247 } | 217 } |
248 if (selector.argumentCount == 1) { | 218 if (selector.argumentCount == 1) { |
249 // The following operators do not map to a JavaScript | 219 // The following operators do not map to a JavaScript operator. |
250 // operator. | |
251 if (name == '~/' || name == '<<' || name == '%' || name == '>>') { | 220 if (name == '~/' || name == '<<' || name == '%' || name == '>>') { |
252 return null; | 221 return null; |
253 } | 222 } |
254 jsAst.Expression result = js('receiver').binary(name, js('a0')); | 223 jsAst.Expression result = js('receiver $name a0'); |
255 if (name == '&' || name == '|' || name == '^') { | 224 if (name == '&' || name == '|' || name == '^') { |
256 result = tripleShiftZero(result); | 225 result = js('# >>> 0', result); |
257 } | 226 } |
258 // Unfolds to: | 227 return js.statement( |
259 // if (typeof receiver == "number" && typeof a0 == "number") | 228 'if (typeof receiver == "number" && typeof a0 == "number")' |
260 // return receiver op a0; | 229 ' return #;', |
261 return js.if_( | 230 result); |
262 isNumber('receiver').binary('&&', isNumber('a0')), | |
263 js.return_(result)); | |
264 } else if (name == 'unary-') { | 231 } else if (name == 'unary-') { |
265 // [: if (typeof receiver == "number") return -receiver :]. | 232 return js.statement( |
266 return js.if_(isNumber('receiver'), | 233 'if (typeof receiver == "number") return -receiver'); |
267 js.return_(js('-receiver'))); | |
268 } else { | 234 } else { |
269 assert(name == '~'); | 235 assert(name == '~'); |
270 return js.if_(isInt('receiver'), | 236 return js.statement(''' |
271 js.return_(js('~receiver >>> 0'))); | 237 if (typeof receiver == "number" && Math.floor(receiver) == receiver) |
| 238 return (~receiver) >>> 0; |
| 239 '''); |
272 } | 240 } |
273 } else if (selector.isIndex() || selector.isIndexSet()) { | 241 } else if (selector.isIndex() || selector.isIndexSet()) { |
274 // For an index operation, this code generates: | 242 // For an index operation, this code generates: |
275 // | 243 // |
276 // if (receiver.constructor == Array || typeof receiver == "string") { | 244 // if (receiver.constructor == Array || typeof receiver == "string") { |
277 // if (a0 >>> 0 === a0 && a0 < receiver.length) { | 245 // if (a0 >>> 0 === a0 && a0 < receiver.length) { |
278 // return receiver[a0]; | 246 // return receiver[a0]; |
279 // } | 247 // } |
280 // } | 248 // } |
281 // | 249 // |
(...skipping 13 matching lines...) Expand all Loading... |
295 // The index set operator requires a check on its set value in | 263 // The index set operator requires a check on its set value in |
296 // checked mode, so we don't optimize the interceptor if the | 264 // checked mode, so we don't optimize the interceptor if the |
297 // compiler has type assertions enabled. | 265 // compiler has type assertions enabled. |
298 if (selector.isIndexSet() | 266 if (selector.isIndexSet() |
299 && (compiler.enableTypeAssertions || !containsArray)) { | 267 && (compiler.enableTypeAssertions || !containsArray)) { |
300 return null; | 268 return null; |
301 } | 269 } |
302 if (!containsArray && !containsString) { | 270 if (!containsArray && !containsString) { |
303 return null; | 271 return null; |
304 } | 272 } |
305 jsAst.Expression isIntAndAboveZero = js('a0 >>> 0 === a0'); | |
306 jsAst.Expression belowLength = js('a0 < receiver.length'); | |
307 jsAst.Expression arrayCheck = js('receiver.constructor == Array'); | 273 jsAst.Expression arrayCheck = js('receiver.constructor == Array'); |
308 jsAst.Expression indexableCheck = | 274 jsAst.Expression indexableCheck = |
309 backend.generateIsJsIndexableCall(js('receiver'), js('receiver')); | 275 backend.generateIsJsIndexableCall(js('receiver'), js('receiver')); |
310 | 276 |
311 jsAst.Expression orExp(left, right) { | 277 jsAst.Expression orExp(left, right) { |
312 return left == null ? right : left.binary('||', right); | 278 return left == null ? right : js('# || #', [left, right]); |
313 } | 279 } |
314 | 280 |
315 if (selector.isIndex()) { | 281 if (selector.isIndex()) { |
316 jsAst.Expression stringCheck = js('typeof receiver == "string"'); | |
317 jsAst.Expression typeCheck; | 282 jsAst.Expression typeCheck; |
318 if (containsArray) { | 283 if (containsArray) { |
319 typeCheck = arrayCheck; | 284 typeCheck = arrayCheck; |
320 } | 285 } |
321 | 286 |
322 if (containsString) { | 287 if (containsString) { |
323 typeCheck = orExp(typeCheck, stringCheck); | 288 typeCheck = orExp(typeCheck, js('typeof receiver == "string"')); |
324 } | 289 } |
325 | 290 |
326 if (containsJsIndexable) { | 291 if (containsJsIndexable) { |
327 typeCheck = orExp(typeCheck, indexableCheck); | 292 typeCheck = orExp(typeCheck, indexableCheck); |
328 } | 293 } |
329 | 294 |
330 return js.if_(typeCheck, | 295 return js.statement(''' |
331 js.if_(isIntAndAboveZero.binary('&&', belowLength), | 296 if (#) |
332 js.return_(js('receiver[a0]')))); | 297 if ((a0 >>> 0) === a0 && a0 < receiver.length) |
| 298 return receiver[a0]; |
| 299 ''', typeCheck); |
333 } else { | 300 } else { |
334 jsAst.Expression typeCheck; | 301 jsAst.Expression typeCheck; |
335 if (containsArray) { | 302 if (containsArray) { |
336 typeCheck = arrayCheck; | 303 typeCheck = arrayCheck; |
337 } | 304 } |
338 | 305 |
339 if (containsJsIndexable) { | 306 if (containsJsIndexable) { |
340 typeCheck = orExp(typeCheck, indexableCheck); | 307 typeCheck = orExp(typeCheck, indexableCheck); |
341 } | 308 } |
342 | 309 |
343 jsAst.Expression isImmutableArray = typeCheck.binary( | 310 return js.statement(r''' |
344 '&&', js(r'!receiver.immutable$list')); | 311 if (# && !receiver.immutable$list && |
345 return js.if_(isImmutableArray.binary( | 312 (a0 >>> 0) === a0 && a0 < receiver.length) |
346 '&&', isIntAndAboveZero.binary('&&', belowLength)), | 313 return receiver[a0] = a1; |
347 js.return_(js('receiver[a0] = a1'))); | 314 ''', typeCheck); |
348 } | 315 } |
349 } | 316 } |
350 return null; | 317 return null; |
351 } | 318 } |
352 | 319 |
353 void emitOneShotInterceptors(CodeBuffer buffer) { | 320 void emitOneShotInterceptors(CodeBuffer buffer) { |
354 List<String> names = backend.oneShotInterceptors.keys.toList(); | 321 List<String> names = backend.oneShotInterceptors.keys.toList(); |
355 names.sort(); | 322 names.sort(); |
356 for (String name in names) { | 323 for (String name in names) { |
357 Selector selector = backend.oneShotInterceptors[name]; | 324 Selector selector = backend.oneShotInterceptors[name]; |
358 Set<ClassElement> classes = | 325 Set<ClassElement> classes = |
359 backend.getInterceptedClassesOn(selector.name); | 326 backend.getInterceptedClassesOn(selector.name); |
360 String getInterceptorName = | 327 String getInterceptorName = |
361 namer.getInterceptorName(backend.getInterceptorMethod, classes); | 328 namer.getInterceptorName(backend.getInterceptorMethod, classes); |
362 | 329 |
363 List<jsAst.Parameter> parameters = <jsAst.Parameter>[]; | 330 List<String> parameterNames = <String>[]; |
364 List<jsAst.Expression> arguments = <jsAst.Expression>[]; | 331 parameterNames.add('receiver'); |
365 parameters.add(new jsAst.Parameter('receiver')); | |
366 arguments.add(js('receiver')); | |
367 | 332 |
368 if (selector.isSetter()) { | 333 if (selector.isSetter()) { |
369 parameters.add(new jsAst.Parameter('value')); | 334 parameterNames.add('value'); |
370 arguments.add(js('value')); | |
371 } else { | 335 } else { |
372 for (int i = 0; i < selector.argumentCount; i++) { | 336 for (int i = 0; i < selector.argumentCount; i++) { |
373 String argName = 'a$i'; | 337 parameterNames.add('a$i'); |
374 parameters.add(new jsAst.Parameter(argName)); | |
375 arguments.add(js(argName)); | |
376 } | 338 } |
377 } | 339 } |
378 | 340 |
379 List<jsAst.Statement> body = <jsAst.Statement>[]; | |
380 jsAst.Statement optimizedPath = | |
381 fastPathForOneShotInterceptor(selector, classes); | |
382 if (optimizedPath != null) { | |
383 body.add(optimizedPath); | |
384 } | |
385 | |
386 String invocationName = backend.namer.invocationName(selector); | 341 String invocationName = backend.namer.invocationName(selector); |
387 String globalObject = namer.globalObjectFor(compiler.interceptorsLibrary); | 342 String globalObject = namer.globalObjectFor(compiler.interceptorsLibrary); |
388 body.add(js.return_( | |
389 js(globalObject)[getInterceptorName]('receiver')[invocationName]( | |
390 arguments))); | |
391 | 343 |
392 jsAst.Expression assignment = | 344 jsAst.Statement optimizedPath = |
393 js('${globalObject}.$name = #', js.fun(parameters, body)); | 345 fastPathForOneShotInterceptor(selector, classes); |
| 346 if (optimizedPath == null) optimizedPath = js.statement(';'); |
| 347 |
| 348 jsAst.Expression assignment = js('${globalObject}.# = function(#) {' |
| 349 ' #;' |
| 350 ' return #.#(receiver).#(#) }', |
| 351 [name, parameterNames, |
| 352 optimizedPath, |
| 353 globalObject, getInterceptorName, invocationName, parameterNames]); |
394 | 354 |
395 buffer.write(jsAst.prettyPrint(assignment, compiler)); | 355 buffer.write(jsAst.prettyPrint(assignment, compiler)); |
396 buffer.write(N); | 356 buffer.write(N); |
397 } | 357 } |
398 } | 358 } |
399 | 359 |
400 /** | 360 /** |
401 * If [JSInvocationMirror._invokeOn] has been compiled, emit all the | 361 * If [JSInvocationMirror._invokeOn] has been compiled, emit all the |
402 * possible selector names that are intercepted into the | 362 * possible selector names that are intercepted into the |
403 * [interceptedNames] top-level variable. The implementation of | 363 * [interceptedNames] top-level variable. The implementation of |
(...skipping 14 matching lines...) Expand all Loading... |
418 var invocationNames = interceptorInvocationNames.toList()..sort(); | 378 var invocationNames = interceptorInvocationNames.toList()..sort(); |
419 List<jsAst.ArrayElement> elements = invocationNames.map( | 379 List<jsAst.ArrayElement> elements = invocationNames.map( |
420 (String invocationName) { | 380 (String invocationName) { |
421 jsAst.Literal str = js.string(invocationName); | 381 jsAst.Literal str = js.string(invocationName); |
422 return new jsAst.ArrayElement(index++, str); | 382 return new jsAst.ArrayElement(index++, str); |
423 }).toList(); | 383 }).toList(); |
424 jsAst.ArrayInitializer array = | 384 jsAst.ArrayInitializer array = |
425 new jsAst.ArrayInitializer(invocationNames.length, elements); | 385 new jsAst.ArrayInitializer(invocationNames.length, elements); |
426 | 386 |
427 jsAst.Expression assignment = | 387 jsAst.Expression assignment = |
428 js('${task.isolateProperties}.$name = #', array); | 388 js('${task.isolateProperties}.# = #', [name, array]); |
429 | 389 |
430 buffer.write(jsAst.prettyPrint(assignment, compiler)); | 390 buffer.write(jsAst.prettyPrint(assignment, compiler)); |
431 buffer.write(N); | 391 buffer.write(N); |
432 } | 392 } |
433 | 393 |
434 /** | 394 /** |
435 * Emit initializer for [mapTypeToInterceptor] data structure used by | 395 * Emit initializer for [mapTypeToInterceptor] data structure used by |
436 * [findInterceptorForType]. See declaration of [mapTypeToInterceptor] in | 396 * [findInterceptorForType]. See declaration of [mapTypeToInterceptor] in |
437 * `interceptors.dart`. | 397 * `interceptors.dart`. |
438 */ | 398 */ |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
483 var map = new jsAst.ObjectInitializer(properties); | 443 var map = new jsAst.ObjectInitializer(properties); |
484 elements.add(map); | 444 elements.add(map); |
485 } | 445 } |
486 } | 446 } |
487 } | 447 } |
488 | 448 |
489 jsAst.ArrayInitializer array = new jsAst.ArrayInitializer.from(elements); | 449 jsAst.ArrayInitializer array = new jsAst.ArrayInitializer.from(elements); |
490 String name = | 450 String name = |
491 backend.namer.getNameOfGlobalField(backend.mapTypeToInterceptor); | 451 backend.namer.getNameOfGlobalField(backend.mapTypeToInterceptor); |
492 jsAst.Expression assignment = | 452 jsAst.Expression assignment = |
493 js('${task.isolateProperties}.$name = #', array); | 453 js('${task.isolateProperties}.# = #', [name, array]); |
494 | 454 |
495 buffer.write(jsAst.prettyPrint(assignment, compiler)); | 455 buffer.write(jsAst.prettyPrint(assignment, compiler)); |
496 buffer.write(N); | 456 buffer.write(N); |
497 } | 457 } |
498 } | 458 } |
OLD | NEW |