| 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 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; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 /** | 23 /** |
| 24 * Build a JavaScrit AST node for doing a type check on | 24 * Build a JavaScrit AST node for doing a type check on |
| 25 * [cls]. [cls] must be a non-native interceptor class. | 25 * [cls]. [cls] must be a non-native interceptor class. |
| 26 */ | 26 */ |
| 27 jsAst.Statement buildInterceptorCheck(ClassElement cls) { | 27 jsAst.Statement buildInterceptorCheck(ClassElement cls) { |
| 28 jsAst.Expression condition; | 28 jsAst.Expression condition; |
| 29 assert(backend.isInterceptorClass(cls)); | 29 assert(backend.isInterceptorClass(cls)); |
| 30 if (cls == helpers.jsBoolClass) { | 30 if (cls == helpers.jsBoolClass) { |
| 31 condition = js('(typeof receiver) == "boolean"'); | 31 condition = js('(typeof receiver) == "boolean"'); |
| 32 } else if (cls == helpers.jsIntClass || | 32 } else if (cls == helpers.jsIntClass || |
| 33 cls == helpers.jsDoubleClass || | 33 cls == helpers.jsDoubleClass || |
| 34 cls == helpers.jsNumberClass) { | 34 cls == helpers.jsNumberClass) { |
| 35 throw 'internal error'; | 35 throw 'internal error'; |
| 36 } else if (cls == helpers.jsArrayClass || | 36 } else if (cls == helpers.jsArrayClass || |
| 37 cls == helpers.jsMutableArrayClass || | 37 cls == helpers.jsMutableArrayClass || |
| 38 cls == helpers.jsFixedArrayClass || | 38 cls == helpers.jsFixedArrayClass || |
| 39 cls == helpers.jsExtendableArrayClass) { | 39 cls == helpers.jsExtendableArrayClass) { |
| 40 condition = js('receiver.constructor == Array'); | 40 condition = js('receiver.constructor == Array'); |
| 41 } else if (cls == helpers.jsStringClass) { | 41 } else if (cls == helpers.jsStringClass) { |
| 42 condition = js('(typeof receiver) == "string"'); | 42 condition = js('(typeof receiver) == "string"'); |
| 43 } else if (cls == helpers.jsNullClass) { | 43 } else if (cls == helpers.jsNullClass) { |
| 44 condition = js('receiver == null'); | 44 condition = js('receiver == null'); |
| 45 } else { | 45 } else { |
| 46 throw 'internal error'; | 46 throw 'internal error'; |
| 47 } | 47 } |
| 48 return js.statement('if (#) return #', [condition, interceptorFor(cls)]); | 48 return js.statement('if (#) return #', [condition, interceptorFor(cls)]); |
| 49 } | 49 } |
| 50 | 50 |
| 51 bool hasArray = false; | 51 bool hasArray = false; |
| 52 bool hasBool = false; | 52 bool hasBool = false; |
| 53 bool hasDouble = false; | 53 bool hasDouble = false; |
| 54 bool hasInt = false; | 54 bool hasInt = false; |
| 55 bool hasNull = false; | 55 bool hasNull = false; |
| 56 bool hasNumber = false; | 56 bool hasNumber = false; |
| 57 bool hasString = false; | 57 bool hasString = false; |
| 58 bool hasNative = false; | 58 bool hasNative = false; |
| 59 bool anyNativeClasses = compiler.enqueuer.codegen.nativeEnqueuer | 59 bool anyNativeClasses = |
| 60 .hasInstantiatedNativeClasses(); | 60 compiler.enqueuer.codegen.nativeEnqueuer.hasInstantiatedNativeClasses(); |
| 61 | 61 |
| 62 for (ClassElement cls in classes) { | 62 for (ClassElement cls in classes) { |
| 63 if (cls == helpers.jsArrayClass || | 63 if (cls == helpers.jsArrayClass || |
| 64 cls == helpers.jsMutableArrayClass || | 64 cls == helpers.jsMutableArrayClass || |
| 65 cls == helpers.jsFixedArrayClass || | 65 cls == helpers.jsFixedArrayClass || |
| 66 cls == helpers.jsExtendableArrayClass) hasArray = true; | 66 cls == helpers.jsExtendableArrayClass) |
| 67 else if (cls == helpers.jsBoolClass) hasBool = true; | 67 hasArray = true; |
| 68 else if (cls == helpers.jsDoubleClass) hasDouble = true; | 68 else if (cls == helpers.jsBoolClass) |
| 69 else if (cls == helpers.jsIntClass) hasInt = true; | 69 hasBool = true; |
| 70 else if (cls == helpers.jsNullClass) hasNull = true; | 70 else if (cls == helpers.jsDoubleClass) |
| 71 else if (cls == helpers.jsNumberClass) hasNumber = true; | 71 hasDouble = true; |
| 72 else if (cls == helpers.jsStringClass) hasString = true; | 72 else if (cls == helpers.jsIntClass) |
| 73 hasInt = true; |
| 74 else if (cls == helpers.jsNullClass) |
| 75 hasNull = true; |
| 76 else if (cls == helpers.jsNumberClass) |
| 77 hasNumber = true; |
| 78 else if (cls == helpers.jsStringClass) |
| 79 hasString = true; |
| 73 else { | 80 else { |
| 74 // The set of classes includes classes mixed-in to interceptor classes | 81 // The set of classes includes classes mixed-in to interceptor classes |
| 75 // and user extensions of native classes. | 82 // and user extensions of native classes. |
| 76 // | 83 // |
| 77 // The set of classes also includes the 'primitive' interceptor | 84 // The set of classes also includes the 'primitive' interceptor |
| 78 // PlainJavaScriptObject even when it has not been resolved, since it is | 85 // PlainJavaScriptObject even when it has not been resolved, since it is |
| 79 // only resolved through the reference in getNativeInterceptor when | 86 // only resolved through the reference in getNativeInterceptor when |
| 80 // getNativeInterceptor is marked as used. Guard against probing | 87 // getNativeInterceptor is marked as used. Guard against probing |
| 81 // unresolved PlainJavaScriptObject by testing for anyNativeClasses. | 88 // unresolved PlainJavaScriptObject by testing for anyNativeClasses. |
| 82 | 89 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 101 jsAst.Statement whenNumber; | 108 jsAst.Statement whenNumber; |
| 102 | 109 |
| 103 /// Note: there are two number classes in play: Dart's [num], | 110 /// Note: there are two number classes in play: Dart's [num], |
| 104 /// and JavaScript's Number (typeof receiver == 'number'). This | 111 /// and JavaScript's Number (typeof receiver == 'number'). This |
| 105 /// is the fallback used when we have determined that receiver | 112 /// is the fallback used when we have determined that receiver |
| 106 /// is a JavaScript Number. | 113 /// is a JavaScript Number. |
| 107 jsAst.Expression interceptorForNumber = interceptorFor( | 114 jsAst.Expression interceptorForNumber = interceptorFor( |
| 108 hasDouble ? helpers.jsDoubleClass : helpers.jsNumberClass); | 115 hasDouble ? helpers.jsDoubleClass : helpers.jsNumberClass); |
| 109 | 116 |
| 110 if (hasInt) { | 117 if (hasInt) { |
| 111 whenNumber = js.statement('''{ | 118 whenNumber = js.statement( |
| 119 '''{ |
| 112 if (Math.floor(receiver) == receiver) return #; | 120 if (Math.floor(receiver) == receiver) return #; |
| 113 return #; | 121 return #; |
| 114 }''', [interceptorFor(helpers.jsIntClass), interceptorForNumber]); | 122 }''', |
| 123 [interceptorFor(helpers.jsIntClass), interceptorForNumber]); |
| 115 } else { | 124 } else { |
| 116 whenNumber = js.statement('return #', interceptorForNumber); | 125 whenNumber = js.statement('return #', interceptorForNumber); |
| 117 } | 126 } |
| 118 statements.add( | 127 statements |
| 119 js.statement('if (typeof receiver == "number") #;', whenNumber)); | 128 .add(js.statement('if (typeof receiver == "number") #;', whenNumber)); |
| 120 } | 129 } |
| 121 | 130 |
| 122 if (hasString) { | 131 if (hasString) { |
| 123 statements.add(buildInterceptorCheck(helpers.jsStringClass)); | 132 statements.add(buildInterceptorCheck(helpers.jsStringClass)); |
| 124 } | 133 } |
| 125 if (hasNull) { | 134 if (hasNull) { |
| 126 statements.add(buildInterceptorCheck(helpers.jsNullClass)); | 135 statements.add(buildInterceptorCheck(helpers.jsNullClass)); |
| 127 } else { | 136 } else { |
| 128 // Returning "undefined" or "null" here will provoke a JavaScript | 137 // Returning "undefined" or "null" here will provoke a JavaScript |
| 129 // TypeError which is later identified as a null-error by | 138 // TypeError which is later identified as a null-error by |
| 130 // [unwrapException] in js_helper.dart. | 139 // [unwrapException] in js_helper.dart. |
| 131 statements.add( | 140 statements.add(js.statement('if (receiver == null) return receiver')); |
| 132 js.statement('if (receiver == null) return receiver')); | |
| 133 } | 141 } |
| 134 if (hasBool) { | 142 if (hasBool) { |
| 135 statements.add(buildInterceptorCheck(helpers.jsBoolClass)); | 143 statements.add(buildInterceptorCheck(helpers.jsBoolClass)); |
| 136 } | 144 } |
| 137 // TODO(ahe): It might be faster to check for Array before | 145 // TODO(ahe): It might be faster to check for Array before |
| 138 // function and bool. | 146 // function and bool. |
| 139 if (hasArray) { | 147 if (hasArray) { |
| 140 statements.add(buildInterceptorCheck(helpers.jsArrayClass)); | 148 statements.add(buildInterceptorCheck(helpers.jsArrayClass)); |
| 141 } | 149 } |
| 142 | 150 |
| 143 if (hasNative) { | 151 if (hasNative) { |
| 144 statements.add(js.statement(r'''{ | 152 statements.add(js.statement( |
| 153 r'''{ |
| 145 if (typeof receiver != "object") { | 154 if (typeof receiver != "object") { |
| 146 if (typeof receiver == "function" ) return #; | 155 if (typeof receiver == "function" ) return #; |
| 147 return receiver; | 156 return receiver; |
| 148 } | 157 } |
| 149 if (receiver instanceof #) return receiver; | 158 if (receiver instanceof #) return receiver; |
| 150 return #(receiver); | 159 return #(receiver); |
| 151 }''', [ | 160 }''', |
| 152 interceptorFor(helpers.jsJavaScriptFunctionClass), | 161 [ |
| 153 backend.emitter.constructorAccess(compiler.coreClasses.objectClass), | 162 interceptorFor(helpers.jsJavaScriptFunctionClass), |
| 154 backend.emitter | 163 backend.emitter.constructorAccess(compiler.coreClasses.objectClass), |
| 155 .staticFunctionAccess(helpers.getNativeInterceptorMethod)])); | 164 backend.emitter |
| 156 | 165 .staticFunctionAccess(helpers.getNativeInterceptorMethod) |
| 166 ])); |
| 157 } else { | 167 } else { |
| 158 ClassElement jsUnknown = helpers.jsUnknownJavaScriptObjectClass; | 168 ClassElement jsUnknown = helpers.jsUnknownJavaScriptObjectClass; |
| 159 if (compiler.codegenWorld | 169 if (compiler.codegenWorld.directlyInstantiatedClasses |
| 160 .directlyInstantiatedClasses.contains(jsUnknown)) { | 170 .contains(jsUnknown)) { |
| 161 statements.add( | 171 statements.add(js.statement('if (!(receiver instanceof #)) return #;', [ |
| 162 js.statement('if (!(receiver instanceof #)) return #;', | 172 backend.emitter.constructorAccess(compiler.coreClasses.objectClass), |
| 163 [backend.emitter.constructorAccess( | 173 interceptorFor(jsUnknown) |
| 164 compiler.coreClasses.objectClass), | 174 ])); |
| 165 interceptorFor(jsUnknown)])); | |
| 166 } | 175 } |
| 167 | 176 |
| 168 statements.add(js.statement('return receiver')); | 177 statements.add(js.statement('return receiver')); |
| 169 } | 178 } |
| 170 | 179 |
| 171 return js('''function(receiver) { #; }''', new jsAst.Block(statements)); | 180 return js('''function(receiver) { #; }''', new jsAst.Block(statements)); |
| 172 } | 181 } |
| 173 | 182 |
| 174 // Returns a statement that takes care of performance critical | 183 // Returns a statement that takes care of performance critical |
| 175 // common case for a one-shot interceptor, or null if there is no | 184 // common case for a one-shot interceptor, or null if there is no |
| 176 // fast path. | 185 // fast path. |
| 177 jsAst.Statement _fastPathForOneShotInterceptor(Selector selector, | 186 jsAst.Statement _fastPathForOneShotInterceptor( |
| 178 Set<ClassElement> classes) { | 187 Selector selector, Set<ClassElement> classes) { |
| 179 | |
| 180 if (selector.isOperator) { | 188 if (selector.isOperator) { |
| 181 String name = selector.name; | 189 String name = selector.name; |
| 182 if (name == '==') { | 190 if (name == '==') { |
| 183 return js.statement('''{ | 191 return js.statement('''{ |
| 184 if (receiver == null) return a0 == null; | 192 if (receiver == null) return a0 == null; |
| 185 if (typeof receiver != "object") | 193 if (typeof receiver != "object") |
| 186 return a0 != null && receiver === a0; | 194 return a0 != null && receiver === a0; |
| 187 }'''); | 195 }'''); |
| 188 } | 196 } |
| 189 if (!classes.contains(helpers.jsIntClass) | 197 if (!classes.contains(helpers.jsIntClass) && |
| 190 && !classes.contains(helpers.jsNumberClass) | 198 !classes.contains(helpers.jsNumberClass) && |
| 191 && !classes.contains(helpers.jsDoubleClass)) { | 199 !classes.contains(helpers.jsDoubleClass)) { |
| 192 return null; | 200 return null; |
| 193 } | 201 } |
| 194 if (selector.argumentCount == 1) { | 202 if (selector.argumentCount == 1) { |
| 195 // The following operators do not map to a JavaScript operator. | 203 // The following operators do not map to a JavaScript operator. |
| 196 if (name == '~/' || name == '<<' || name == '%' || name == '>>') { | 204 if (name == '~/' || name == '<<' || name == '%' || name == '>>') { |
| 197 return null; | 205 return null; |
| 198 } | 206 } |
| 199 jsAst.Expression result = js('receiver $name a0'); | 207 jsAst.Expression result = js('receiver $name a0'); |
| 200 if (name == '&' || name == '|' || name == '^') { | 208 if (name == '&' || name == '|' || name == '^') { |
| 201 result = js('# >>> 0', result); | 209 result = js('# >>> 0', result); |
| 202 } | 210 } |
| 203 return js.statement( | 211 return js.statement( |
| 204 'if (typeof receiver == "number" && typeof a0 == "number")' | 212 'if (typeof receiver == "number" && typeof a0 == "number")' |
| 205 ' return #;', | 213 ' return #;', |
| 206 result); | 214 result); |
| 207 } else if (name == 'unary-') { | 215 } else if (name == 'unary-') { |
| 208 return js.statement( | 216 return js |
| 209 'if (typeof receiver == "number") return -receiver'); | 217 .statement('if (typeof receiver == "number") return -receiver'); |
| 210 } else { | 218 } else { |
| 211 assert(name == '~'); | 219 assert(name == '~'); |
| 212 return js.statement(''' | 220 return js.statement(''' |
| 213 if (typeof receiver == "number" && Math.floor(receiver) == receiver) | 221 if (typeof receiver == "number" && Math.floor(receiver) == receiver) |
| 214 return (~receiver) >>> 0; | 222 return (~receiver) >>> 0; |
| 215 '''); | 223 '''); |
| 216 } | 224 } |
| 217 } else if (selector.isIndex || selector.isIndexSet) { | 225 } else if (selector.isIndex || selector.isIndexSet) { |
| 218 // For an index operation, this code generates: | 226 // For an index operation, this code generates: |
| 219 // | 227 // |
| (...skipping 11 matching lines...) Expand all Loading... |
| 231 // if (typeof a0 === "number") { | 239 // if (typeof a0 === "number") { |
| 232 // if (receiver.constructor == Array && !receiver.immutable$list) { | 240 // if (receiver.constructor == Array && !receiver.immutable$list) { |
| 233 // if (a0 >>> 0 === a0 && a0 < receiver.length) { | 241 // if (a0 >>> 0 === a0 && a0 < receiver.length) { |
| 234 // return receiver[a0] = a1; | 242 // return receiver[a0] = a1; |
| 235 // } | 243 // } |
| 236 // } | 244 // } |
| 237 // } | 245 // } |
| 238 bool containsArray = classes.contains(helpers.jsArrayClass); | 246 bool containsArray = classes.contains(helpers.jsArrayClass); |
| 239 bool containsString = classes.contains(helpers.jsStringClass); | 247 bool containsString = classes.contains(helpers.jsStringClass); |
| 240 bool containsJsIndexable = | 248 bool containsJsIndexable = |
| 241 helpers.jsIndexingBehaviorInterface.isResolved && classes.any((cls) { | 249 helpers.jsIndexingBehaviorInterface.isResolved && |
| 242 return compiler.world.isSubtypeOf(cls, | 250 classes.any((cls) { |
| 243 helpers.jsIndexingBehaviorInterface); | 251 return compiler.world |
| 244 }); | 252 .isSubtypeOf(cls, helpers.jsIndexingBehaviorInterface); |
| 253 }); |
| 245 // The index set operator requires a check on its set value in | 254 // The index set operator requires a check on its set value in |
| 246 // checked mode, so we don't optimize the interceptor if the | 255 // checked mode, so we don't optimize the interceptor if the |
| 247 // compiler has type assertions enabled. | 256 // compiler has type assertions enabled. |
| 248 if (selector.isIndexSet | 257 if (selector.isIndexSet && |
| 249 && (compiler.options.enableTypeAssertions || !containsArray)) { | 258 (compiler.options.enableTypeAssertions || !containsArray)) { |
| 250 return null; | 259 return null; |
| 251 } | 260 } |
| 252 if (!containsArray && !containsString) { | 261 if (!containsArray && !containsString) { |
| 253 return null; | 262 return null; |
| 254 } | 263 } |
| 255 jsAst.Expression arrayCheck = js('receiver.constructor == Array'); | 264 jsAst.Expression arrayCheck = js('receiver.constructor == Array'); |
| 256 jsAst.Expression indexableCheck = | 265 jsAst.Expression indexableCheck = |
| 257 backend.generateIsJsIndexableCall(js('receiver'), js('receiver')); | 266 backend.generateIsJsIndexableCall(js('receiver'), js('receiver')); |
| 258 | 267 |
| 259 jsAst.Expression orExp(left, right) { | 268 jsAst.Expression orExp(left, right) { |
| 260 return left == null ? right : js('# || #', [left, right]); | 269 return left == null ? right : js('# || #', [left, right]); |
| 261 } | 270 } |
| 262 | 271 |
| 263 if (selector.isIndex) { | 272 if (selector.isIndex) { |
| 264 jsAst.Expression typeCheck; | 273 jsAst.Expression typeCheck; |
| 265 if (containsArray) { | 274 if (containsArray) { |
| 266 typeCheck = arrayCheck; | 275 typeCheck = arrayCheck; |
| 267 } | 276 } |
| 268 | 277 |
| 269 if (containsString) { | 278 if (containsString) { |
| 270 typeCheck = orExp(typeCheck, js('typeof receiver == "string"')); | 279 typeCheck = orExp(typeCheck, js('typeof receiver == "string"')); |
| 271 } | 280 } |
| 272 | 281 |
| 273 if (containsJsIndexable) { | 282 if (containsJsIndexable) { |
| 274 typeCheck = orExp(typeCheck, indexableCheck); | 283 typeCheck = orExp(typeCheck, indexableCheck); |
| 275 } | 284 } |
| 276 | 285 |
| 277 return js.statement(''' | 286 return js.statement( |
| 287 ''' |
| 278 if (typeof a0 === "number") | 288 if (typeof a0 === "number") |
| 279 if (#) | 289 if (#) |
| 280 if ((a0 >>> 0) === a0 && a0 < receiver.length) | 290 if ((a0 >>> 0) === a0 && a0 < receiver.length) |
| 281 return receiver[a0]; | 291 return receiver[a0]; |
| 282 ''', typeCheck); | 292 ''', |
| 293 typeCheck); |
| 283 } else { | 294 } else { |
| 284 jsAst.Expression typeCheck; | 295 jsAst.Expression typeCheck; |
| 285 if (containsArray) { | 296 if (containsArray) { |
| 286 typeCheck = arrayCheck; | 297 typeCheck = arrayCheck; |
| 287 } | 298 } |
| 288 | 299 |
| 289 if (containsJsIndexable) { | 300 if (containsJsIndexable) { |
| 290 typeCheck = orExp(typeCheck, indexableCheck); | 301 typeCheck = orExp(typeCheck, indexableCheck); |
| 291 } | 302 } |
| 292 | 303 |
| 293 return js.statement(r''' | 304 return js.statement( |
| 305 r''' |
| 294 if (typeof a0 === "number") | 306 if (typeof a0 === "number") |
| 295 if (# && !receiver.immutable$list && | 307 if (# && !receiver.immutable$list && |
| 296 (a0 >>> 0) === a0 && a0 < receiver.length) | 308 (a0 >>> 0) === a0 && a0 < receiver.length) |
| 297 return receiver[a0] = a1; | 309 return receiver[a0] = a1; |
| 298 ''', typeCheck); | 310 ''', |
| 311 typeCheck); |
| 299 } | 312 } |
| 300 } | 313 } |
| 301 return null; | 314 return null; |
| 302 } | 315 } |
| 303 | 316 |
| 304 jsAst.Expression generateOneShotInterceptor(jsAst.Name name) { | 317 jsAst.Expression generateOneShotInterceptor(jsAst.Name name) { |
| 305 Selector selector = backend.oneShotInterceptors[name]; | 318 Selector selector = backend.oneShotInterceptors[name]; |
| 306 Set<ClassElement> classes = | 319 Set<ClassElement> classes = backend.getInterceptedClassesOn(selector.name); |
| 307 backend.getInterceptedClassesOn(selector.name); | |
| 308 jsAst.Name getInterceptorName = namer.nameForGetInterceptor(classes); | 320 jsAst.Name getInterceptorName = namer.nameForGetInterceptor(classes); |
| 309 | 321 |
| 310 List<String> parameterNames = <String>[]; | 322 List<String> parameterNames = <String>[]; |
| 311 parameterNames.add('receiver'); | 323 parameterNames.add('receiver'); |
| 312 | 324 |
| 313 if (selector.isSetter) { | 325 if (selector.isSetter) { |
| 314 parameterNames.add('value'); | 326 parameterNames.add('value'); |
| 315 } else { | 327 } else { |
| 316 for (int i = 0; i < selector.argumentCount; i++) { | 328 for (int i = 0; i < selector.argumentCount; i++) { |
| 317 parameterNames.add('a$i'); | 329 parameterNames.add('a$i'); |
| 318 } | 330 } |
| 319 } | 331 } |
| 320 | 332 |
| 321 jsAst.Name invocationName = backend.namer.invocationName(selector); | 333 jsAst.Name invocationName = backend.namer.invocationName(selector); |
| 322 String globalObject = namer.globalObjectFor(helpers.interceptorsLibrary); | 334 String globalObject = namer.globalObjectFor(helpers.interceptorsLibrary); |
| 323 | 335 |
| 324 jsAst.Statement optimizedPath = | 336 jsAst.Statement optimizedPath = |
| 325 _fastPathForOneShotInterceptor(selector, classes); | 337 _fastPathForOneShotInterceptor(selector, classes); |
| 326 if (optimizedPath == null) optimizedPath = js.statement(';'); | 338 if (optimizedPath == null) optimizedPath = js.statement(';'); |
| 327 | 339 |
| 328 return js( | 340 return js('function(#) { #; return #.#(receiver).#(#) }', [ |
| 329 'function(#) { #; return #.#(receiver).#(#) }', | 341 parameterNames, |
| 330 [parameterNames, | 342 optimizedPath, |
| 331 optimizedPath, | 343 globalObject, |
| 332 globalObject, getInterceptorName, invocationName, parameterNames]); | 344 getInterceptorName, |
| 345 invocationName, |
| 346 parameterNames |
| 347 ]); |
| 333 } | 348 } |
| 334 | 349 |
| 335 jsAst.ArrayInitializer generateTypeToInterceptorMap() { | 350 jsAst.ArrayInitializer generateTypeToInterceptorMap() { |
| 336 // TODO(sra): Perhaps inject a constant instead? | 351 // TODO(sra): Perhaps inject a constant instead? |
| 337 CustomElementsAnalysis analysis = backend.customElementsAnalysis; | 352 CustomElementsAnalysis analysis = backend.customElementsAnalysis; |
| 338 if (!analysis.needsTable) return null; | 353 if (!analysis.needsTable) return null; |
| 339 | 354 |
| 340 List<jsAst.Expression> elements = <jsAst.Expression>[]; | 355 List<jsAst.Expression> elements = <jsAst.Expression>[]; |
| 341 JavaScriptConstantCompiler handler = backend.constants; | 356 JavaScriptConstantCompiler handler = backend.constants; |
| 342 List<ConstantValue> constants = | 357 List<ConstantValue> constants = |
| (...skipping 19 matching lines...) Expand all Loading... |
| 362 // A.bar() {} | 377 // A.bar() {} |
| 363 // } | 378 // } |
| 364 // | 379 // |
| 365 // Which are described by the map | 380 // Which are described by the map |
| 366 // | 381 // |
| 367 // {"": A.A$, "foo": A.A$foo, "bar": A.A$bar} | 382 // {"": A.A$, "foo": A.A$foo, "bar": A.A$bar} |
| 368 // | 383 // |
| 369 // We expect most of the time the map will be a singleton. | 384 // We expect most of the time the map will be a singleton. |
| 370 var properties = []; | 385 var properties = []; |
| 371 for (Element member in analysis.constructors(classElement)) { | 386 for (Element member in analysis.constructors(classElement)) { |
| 372 properties.add( | 387 properties.add(new jsAst.Property(js.string(member.name), |
| 373 new jsAst.Property( | 388 backend.emitter.staticFunctionAccess(member))); |
| 374 js.string(member.name), | |
| 375 backend.emitter.staticFunctionAccess(member))); | |
| 376 } | 389 } |
| 377 | 390 |
| 378 var map = new jsAst.ObjectInitializer(properties); | 391 var map = new jsAst.ObjectInitializer(properties); |
| 379 elements.add(map); | 392 elements.add(map); |
| 380 } | 393 } |
| 381 } | 394 } |
| 382 } | 395 } |
| 383 | 396 |
| 384 return new jsAst.ArrayInitializer(elements); | 397 return new jsAst.ArrayInitializer(elements); |
| 385 } | 398 } |
| 386 } | 399 } |
| OLD | NEW |