| 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 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 emitGetInterceptorMethod(buffer, name, classes); | 194 emitGetInterceptorMethod(buffer, name, classes); |
| 195 } | 195 } |
| 196 } | 196 } |
| 197 | 197 |
| 198 // Returns a statement that takes care of performance critical | 198 // Returns a statement that takes care of performance critical |
| 199 // 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 |
| 200 // fast path. | 200 // fast path. |
| 201 jsAst.Statement fastPathForOneShotInterceptor(Selector selector, | 201 jsAst.Statement fastPathForOneShotInterceptor(Selector selector, |
| 202 Set<ClassElement> classes) { | 202 Set<ClassElement> classes) { |
| 203 | 203 |
| 204 if (selector.isOperator()) { | 204 if (selector.isOperator) { |
| 205 String name = selector.name; | 205 String name = selector.name; |
| 206 if (name == '==') { | 206 if (name == '==') { |
| 207 return js.statement('''{ | 207 return js.statement('''{ |
| 208 if (receiver == null) return a0 == null; | 208 if (receiver == null) return a0 == null; |
| 209 if (typeof receiver != "object") | 209 if (typeof receiver != "object") |
| 210 return a0 != null && receiver === a0; | 210 return a0 != null && receiver === a0; |
| 211 }'''); | 211 }'''); |
| 212 } | 212 } |
| 213 if (!classes.contains(backend.jsIntClass) | 213 if (!classes.contains(backend.jsIntClass) |
| 214 && !classes.contains(backend.jsNumberClass) | 214 && !classes.contains(backend.jsNumberClass) |
| (...skipping 16 matching lines...) Expand all Loading... |
| 231 } else if (name == 'unary-') { | 231 } else if (name == 'unary-') { |
| 232 return js.statement( | 232 return js.statement( |
| 233 'if (typeof receiver == "number") return -receiver'); | 233 'if (typeof receiver == "number") return -receiver'); |
| 234 } else { | 234 } else { |
| 235 assert(name == '~'); | 235 assert(name == '~'); |
| 236 return js.statement(''' | 236 return js.statement(''' |
| 237 if (typeof receiver == "number" && Math.floor(receiver) == receiver) | 237 if (typeof receiver == "number" && Math.floor(receiver) == receiver) |
| 238 return (~receiver) >>> 0; | 238 return (~receiver) >>> 0; |
| 239 '''); | 239 '''); |
| 240 } | 240 } |
| 241 } else if (selector.isIndex() || selector.isIndexSet()) { | 241 } else if (selector.isIndex || selector.isIndexSet) { |
| 242 // For an index operation, this code generates: | 242 // For an index operation, this code generates: |
| 243 // | 243 // |
| 244 // if (receiver.constructor == Array || typeof receiver == "string") { | 244 // if (receiver.constructor == Array || typeof receiver == "string") { |
| 245 // if (a0 >>> 0 === a0 && a0 < receiver.length) { | 245 // if (a0 >>> 0 === a0 && a0 < receiver.length) { |
| 246 // return receiver[a0]; | 246 // return receiver[a0]; |
| 247 // } | 247 // } |
| 248 // } | 248 // } |
| 249 // | 249 // |
| 250 // For an index set operation, this code generates: | 250 // For an index set operation, this code generates: |
| 251 // | 251 // |
| 252 // if (receiver.constructor == Array && !receiver.immutable$list) { | 252 // if (receiver.constructor == Array && !receiver.immutable$list) { |
| 253 // if (a0 >>> 0 === a0 && a0 < receiver.length) { | 253 // if (a0 >>> 0 === a0 && a0 < receiver.length) { |
| 254 // return receiver[a0] = a1; | 254 // return receiver[a0] = a1; |
| 255 // } | 255 // } |
| 256 // } | 256 // } |
| 257 bool containsArray = classes.contains(backend.jsArrayClass); | 257 bool containsArray = classes.contains(backend.jsArrayClass); |
| 258 bool containsString = classes.contains(backend.jsStringClass); | 258 bool containsString = classes.contains(backend.jsStringClass); |
| 259 bool containsJsIndexable = classes.any((cls) { | 259 bool containsJsIndexable = classes.any((cls) { |
| 260 return compiler.world.isSubtype( | 260 return compiler.world.isSubtype( |
| 261 backend.jsIndexingBehaviorInterface, cls); | 261 backend.jsIndexingBehaviorInterface, cls); |
| 262 }); | 262 }); |
| 263 // 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 |
| 264 // checked mode, so we don't optimize the interceptor if the | 264 // checked mode, so we don't optimize the interceptor if the |
| 265 // compiler has type assertions enabled. | 265 // compiler has type assertions enabled. |
| 266 if (selector.isIndexSet() | 266 if (selector.isIndexSet |
| 267 && (compiler.enableTypeAssertions || !containsArray)) { | 267 && (compiler.enableTypeAssertions || !containsArray)) { |
| 268 return null; | 268 return null; |
| 269 } | 269 } |
| 270 if (!containsArray && !containsString) { | 270 if (!containsArray && !containsString) { |
| 271 return null; | 271 return null; |
| 272 } | 272 } |
| 273 jsAst.Expression arrayCheck = js('receiver.constructor == Array'); | 273 jsAst.Expression arrayCheck = js('receiver.constructor == Array'); |
| 274 jsAst.Expression indexableCheck = | 274 jsAst.Expression indexableCheck = |
| 275 backend.generateIsJsIndexableCall(js('receiver'), js('receiver')); | 275 backend.generateIsJsIndexableCall(js('receiver'), js('receiver')); |
| 276 | 276 |
| 277 jsAst.Expression orExp(left, right) { | 277 jsAst.Expression orExp(left, right) { |
| 278 return left == null ? right : js('# || #', [left, right]); | 278 return left == null ? right : js('# || #', [left, right]); |
| 279 } | 279 } |
| 280 | 280 |
| 281 if (selector.isIndex()) { | 281 if (selector.isIndex) { |
| 282 jsAst.Expression typeCheck; | 282 jsAst.Expression typeCheck; |
| 283 if (containsArray) { | 283 if (containsArray) { |
| 284 typeCheck = arrayCheck; | 284 typeCheck = arrayCheck; |
| 285 } | 285 } |
| 286 | 286 |
| 287 if (containsString) { | 287 if (containsString) { |
| 288 typeCheck = orExp(typeCheck, js('typeof receiver == "string"')); | 288 typeCheck = orExp(typeCheck, js('typeof receiver == "string"')); |
| 289 } | 289 } |
| 290 | 290 |
| 291 if (containsJsIndexable) { | 291 if (containsJsIndexable) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 323 for (String name in names) { | 323 for (String name in names) { |
| 324 Selector selector = backend.oneShotInterceptors[name]; | 324 Selector selector = backend.oneShotInterceptors[name]; |
| 325 Set<ClassElement> classes = | 325 Set<ClassElement> classes = |
| 326 backend.getInterceptedClassesOn(selector.name); | 326 backend.getInterceptedClassesOn(selector.name); |
| 327 String getInterceptorName = | 327 String getInterceptorName = |
| 328 namer.getInterceptorName(backend.getInterceptorMethod, classes); | 328 namer.getInterceptorName(backend.getInterceptorMethod, classes); |
| 329 | 329 |
| 330 List<String> parameterNames = <String>[]; | 330 List<String> parameterNames = <String>[]; |
| 331 parameterNames.add('receiver'); | 331 parameterNames.add('receiver'); |
| 332 | 332 |
| 333 if (selector.isSetter()) { | 333 if (selector.isSetter) { |
| 334 parameterNames.add('value'); | 334 parameterNames.add('value'); |
| 335 } else { | 335 } else { |
| 336 for (int i = 0; i < selector.argumentCount; i++) { | 336 for (int i = 0; i < selector.argumentCount; i++) { |
| 337 parameterNames.add('a$i'); | 337 parameterNames.add('a$i'); |
| 338 } | 338 } |
| 339 } | 339 } |
| 340 | 340 |
| 341 String invocationName = backend.namer.invocationName(selector); | 341 String invocationName = backend.namer.invocationName(selector); |
| 342 String globalObject = namer.globalObjectFor(compiler.interceptorsLibrary); | 342 String globalObject = namer.globalObjectFor(compiler.interceptorsLibrary); |
| 343 | 343 |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 448 jsAst.ArrayInitializer array = new jsAst.ArrayInitializer.from(elements); | 448 jsAst.ArrayInitializer array = new jsAst.ArrayInitializer.from(elements); |
| 449 String name = | 449 String name = |
| 450 backend.namer.getNameOfGlobalField(backend.mapTypeToInterceptor); | 450 backend.namer.getNameOfGlobalField(backend.mapTypeToInterceptor); |
| 451 jsAst.Expression assignment = | 451 jsAst.Expression assignment = |
| 452 js('${task.isolateProperties}.# = #', [name, array]); | 452 js('${task.isolateProperties}.# = #', [name, array]); |
| 453 | 453 |
| 454 buffer.write(jsAst.prettyPrint(assignment, compiler)); | 454 buffer.write(jsAst.prettyPrint(assignment, compiler)); |
| 455 buffer.write(N); | 455 buffer.write(N); |
| 456 } | 456 } |
| 457 } | 457 } |
| OLD | NEW |