Chromium Code Reviews| 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 '../compiler.dart' show Compiler; |
| 8 import '../constants/values.dart'; | 8 import '../constants/values.dart'; |
| 9 import '../elements/resolution_types.dart' show ResolutionInterfaceType; | 9 import '../elements/entities.dart'; |
| 10 import '../elements/elements.dart' show ClassElement, Element; | 10 import '../elements/types.dart' show InterfaceType; |
| 11 import '../js/js.dart' as jsAst; | 11 import '../js/js.dart' as jsAst; |
| 12 import '../js/js.dart' show js; | 12 import '../js/js.dart' show js; |
| 13 import '../js_backend/backend_helpers.dart' show BackendHelpers; | 13 import '../js_backend/backend_helpers.dart' show BackendHelpers; |
| 14 import '../js_backend/js_backend.dart' | 14 import '../js_backend/js_backend.dart' |
| 15 show | 15 show |
| 16 CustomElementsAnalysis, | 16 CustomElementsAnalysis, |
| 17 JavaScriptBackend, | 17 JavaScriptBackend, |
| 18 JavaScriptConstantCompiler, | 18 JavaScriptConstantCompiler, |
| 19 Namer; | 19 Namer; |
| 20 import '../universe/selector.dart' show Selector; | 20 import '../universe/selector.dart' show Selector; |
| 21 import '../world.dart' show ClosedWorld; | 21 import '../world.dart' show ClosedWorld; |
| 22 | 22 |
| 23 import 'code_emitter_task.dart' show Emitter; | 23 import 'code_emitter_task.dart' show Emitter; |
| 24 | 24 |
| 25 class InterceptorStubGenerator { | 25 class InterceptorStubGenerator { |
| 26 final Compiler compiler; | 26 final Compiler compiler; |
| 27 final Namer namer; | 27 final Namer namer; |
| 28 final JavaScriptBackend backend; | 28 final JavaScriptBackend backend; |
| 29 final ClosedWorld closedWorld; | 29 final ClosedWorld closedWorld; |
| 30 | 30 |
| 31 InterceptorStubGenerator( | 31 InterceptorStubGenerator( |
| 32 this.compiler, this.namer, this.backend, this.closedWorld); | 32 this.compiler, this.namer, this.backend, this.closedWorld); |
| 33 | 33 |
| 34 Emitter get emitter => backend.emitter.emitter; | 34 Emitter get emitter => backend.emitter.emitter; |
| 35 | 35 |
| 36 BackendHelpers get helpers => backend.helpers; | 36 BackendHelpers get helpers => backend.helpers; |
| 37 | 37 |
| 38 jsAst.Expression generateGetInterceptorMethod(Set<ClassElement> classes) { | 38 jsAst.Expression generateGetInterceptorMethod(Set<ClassEntity> classes) { |
| 39 jsAst.Expression interceptorFor(ClassElement cls) { | 39 jsAst.Expression interceptorFor(ClassEntity cls) { |
| 40 return backend.emitter.interceptorPrototypeAccess(cls); | 40 return backend.emitter.interceptorPrototypeAccess(cls); |
| 41 } | 41 } |
| 42 | 42 |
| 43 /** | 43 /** |
| 44 * Build a JavaScrit AST node for doing a type check on | 44 * Build a JavaScrit AST node for doing a type check on |
| 45 * [cls]. [cls] must be a non-native interceptor class. | 45 * [cls]. [cls] must be a non-native interceptor class. |
| 46 */ | 46 */ |
| 47 jsAst.Statement buildInterceptorCheck(ClassElement cls) { | 47 jsAst.Statement buildInterceptorCheck(ClassEntity cls) { |
| 48 jsAst.Expression condition; | 48 jsAst.Expression condition; |
| 49 assert(backend.isInterceptorClass(cls)); | 49 assert(backend.isInterceptorClass(cls)); |
| 50 if (cls == helpers.jsBoolClass) { | 50 if (cls == helpers.jsBoolClass) { |
| 51 condition = js('(typeof receiver) == "boolean"'); | 51 condition = js('(typeof receiver) == "boolean"'); |
| 52 } else if (cls == helpers.jsIntClass || | 52 } else if (cls == helpers.jsIntClass || |
| 53 cls == helpers.jsDoubleClass || | 53 cls == helpers.jsDoubleClass || |
| 54 cls == helpers.jsNumberClass) { | 54 cls == helpers.jsNumberClass) { |
| 55 throw 'internal error'; | 55 throw 'internal error'; |
| 56 } else if (cls == helpers.jsArrayClass || | 56 } else if (cls == helpers.jsArrayClass || |
| 57 cls == helpers.jsMutableArrayClass || | 57 cls == helpers.jsMutableArrayClass || |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 72 bool hasBool = false; | 72 bool hasBool = false; |
| 73 bool hasDouble = false; | 73 bool hasDouble = false; |
| 74 bool hasInt = false; | 74 bool hasInt = false; |
| 75 bool hasNull = false; | 75 bool hasNull = false; |
| 76 bool hasNumber = false; | 76 bool hasNumber = false; |
| 77 bool hasString = false; | 77 bool hasString = false; |
| 78 bool hasNative = false; | 78 bool hasNative = false; |
| 79 bool anyNativeClasses = | 79 bool anyNativeClasses = |
| 80 compiler.enqueuer.codegen.nativeEnqueuer.hasInstantiatedNativeClasses; | 80 compiler.enqueuer.codegen.nativeEnqueuer.hasInstantiatedNativeClasses; |
| 81 | 81 |
| 82 for (ClassElement cls in classes) { | 82 for (ClassEntity cls in classes) { |
| 83 if (cls == helpers.jsArrayClass || | 83 if (cls == helpers.jsArrayClass || |
| 84 cls == helpers.jsMutableArrayClass || | 84 cls == helpers.jsMutableArrayClass || |
| 85 cls == helpers.jsFixedArrayClass || | 85 cls == helpers.jsFixedArrayClass || |
| 86 cls == helpers.jsExtendableArrayClass) | 86 cls == helpers.jsExtendableArrayClass) |
| 87 hasArray = true; | 87 hasArray = true; |
| 88 else if (cls == helpers.jsBoolClass) | 88 else if (cls == helpers.jsBoolClass) |
| 89 hasBool = true; | 89 hasBool = true; |
| 90 else if (cls == helpers.jsDoubleClass) | 90 else if (cls == helpers.jsDoubleClass) |
| 91 hasDouble = true; | 91 hasDouble = true; |
| 92 else if (cls == helpers.jsIntClass) | 92 else if (cls == helpers.jsIntClass) |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 179 return #(receiver); | 179 return #(receiver); |
| 180 }''', | 180 }''', |
| 181 [ | 181 [ |
| 182 interceptorFor(helpers.jsJavaScriptFunctionClass), | 182 interceptorFor(helpers.jsJavaScriptFunctionClass), |
| 183 backend.emitter | 183 backend.emitter |
| 184 .constructorAccess(compiler.commonElements.objectClass), | 184 .constructorAccess(compiler.commonElements.objectClass), |
| 185 backend.emitter | 185 backend.emitter |
| 186 .staticFunctionAccess(helpers.getNativeInterceptorMethod) | 186 .staticFunctionAccess(helpers.getNativeInterceptorMethod) |
| 187 ])); | 187 ])); |
| 188 } else { | 188 } else { |
| 189 ClassElement jsUnknown = helpers.jsUnknownJavaScriptObjectClass; | 189 ClassEntity jsUnknown = helpers.jsUnknownJavaScriptObjectClass; |
| 190 if (compiler.codegenWorldBuilder.directlyInstantiatedClasses | 190 if (compiler.codegenWorldBuilder.directlyInstantiatedClasses |
| 191 .contains(jsUnknown)) { | 191 .contains(jsUnknown)) { |
| 192 statements.add(js.statement('if (!(receiver instanceof #)) return #;', [ | 192 statements.add(js.statement('if (!(receiver instanceof #)) return #;', [ |
| 193 backend.emitter | 193 backend.emitter |
| 194 .constructorAccess(compiler.commonElements.objectClass), | 194 .constructorAccess(compiler.commonElements.objectClass), |
| 195 interceptorFor(jsUnknown) | 195 interceptorFor(jsUnknown) |
| 196 ])); | 196 ])); |
| 197 } | 197 } |
| 198 | 198 |
| 199 statements.add(js.statement('return receiver')); | 199 statements.add(js.statement('return receiver')); |
| 200 } | 200 } |
| 201 | 201 |
| 202 return js('''function(receiver) { #; }''', new jsAst.Block(statements)); | 202 return js('''function(receiver) { #; }''', new jsAst.Block(statements)); |
| 203 } | 203 } |
| 204 | 204 |
| 205 // Returns a statement that takes care of performance critical | 205 // Returns a statement that takes care of performance critical |
| 206 // common case for a one-shot interceptor, or null if there is no | 206 // common case for a one-shot interceptor, or null if there is no |
| 207 // fast path. | 207 // fast path. |
| 208 jsAst.Statement _fastPathForOneShotInterceptor( | 208 jsAst.Statement _fastPathForOneShotInterceptor( |
| 209 Selector selector, Set<ClassElement> classes) { | 209 Selector selector, Set<ClassEntity> classes) { |
| 210 if (selector.isOperator) { | 210 if (selector.isOperator) { |
| 211 String name = selector.name; | 211 String name = selector.name; |
| 212 if (name == '==') { | 212 if (name == '==') { |
| 213 return js.statement('''{ | 213 return js.statement('''{ |
| 214 if (receiver == null) return a0 == null; | 214 if (receiver == null) return a0 == null; |
| 215 if (typeof receiver != "object") | 215 if (typeof receiver != "object") |
| 216 return a0 != null && receiver === a0; | 216 return a0 != null && receiver === a0; |
| 217 }'''); | 217 }'''); |
| 218 } | 218 } |
| 219 if (!classes.contains(helpers.jsIntClass) && | 219 if (!classes.contains(helpers.jsIntClass) && |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 331 return receiver[a0] = a1; | 331 return receiver[a0] = a1; |
| 332 ''', | 332 ''', |
| 333 typeCheck); | 333 typeCheck); |
| 334 } | 334 } |
| 335 } | 335 } |
| 336 return null; | 336 return null; |
| 337 } | 337 } |
| 338 | 338 |
| 339 jsAst.Expression generateOneShotInterceptor(jsAst.Name name) { | 339 jsAst.Expression generateOneShotInterceptor(jsAst.Name name) { |
| 340 Selector selector = backend.oneShotInterceptors[name]; | 340 Selector selector = backend.oneShotInterceptors[name]; |
| 341 Set<ClassElement> classes = backend.getInterceptedClassesOn(selector.name); | 341 Set<ClassEntity> classes = backend.getInterceptedClassesOn(selector.name); |
| 342 jsAst.Name getInterceptorName = namer.nameForGetInterceptor(classes); | 342 jsAst.Name getInterceptorName = namer.nameForGetInterceptor(classes); |
| 343 | 343 |
| 344 List<String> parameterNames = <String>[]; | 344 List<String> parameterNames = <String>[]; |
| 345 parameterNames.add('receiver'); | 345 parameterNames.add('receiver'); |
| 346 | 346 |
| 347 if (selector.isSetter) { | 347 if (selector.isSetter) { |
| 348 parameterNames.add('value'); | 348 parameterNames.add('value'); |
| 349 } else { | 349 } else { |
| 350 for (int i = 0; i < selector.argumentCount; i++) { | 350 for (int i = 0; i < selector.argumentCount; i++) { |
| 351 parameterNames.add('a$i'); | 351 parameterNames.add('a$i'); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 373 // TODO(sra): Perhaps inject a constant instead? | 373 // TODO(sra): Perhaps inject a constant instead? |
| 374 CustomElementsAnalysis analysis = backend.customElementsAnalysis; | 374 CustomElementsAnalysis analysis = backend.customElementsAnalysis; |
| 375 if (!analysis.needsTable) return null; | 375 if (!analysis.needsTable) return null; |
| 376 | 376 |
| 377 List<jsAst.Expression> elements = <jsAst.Expression>[]; | 377 List<jsAst.Expression> elements = <jsAst.Expression>[]; |
| 378 JavaScriptConstantCompiler handler = backend.constants; | 378 JavaScriptConstantCompiler handler = backend.constants; |
| 379 List<ConstantValue> constants = | 379 List<ConstantValue> constants = |
| 380 handler.getConstantsForEmission(emitter.compareConstants); | 380 handler.getConstantsForEmission(emitter.compareConstants); |
| 381 for (ConstantValue constant in constants) { | 381 for (ConstantValue constant in constants) { |
| 382 if (constant is TypeConstantValue && | 382 if (constant is TypeConstantValue && |
| 383 constant.representedType is ResolutionInterfaceType) { | 383 constant.representedType is InterfaceType) { |
| 384 ResolutionInterfaceType type = constant.representedType; | 384 InterfaceType type = constant.representedType; |
| 385 Element element = type.element; | 385 ClassEntity classElement = type.element; |
| 386 if (element is ClassElement) { | 386 if (!analysis.needsClass(classElement)) continue; |
|
Siggi Cherem (dart-lang)
2017/01/19 16:48:22
Just to double-check, this `if` was practically in
Johnni Winther
2017/01/20 07:57:04
All [InterfaceType]s point to a [ClassEntity], if
| |
| 387 ClassElement classElement = element; | |
| 388 if (!analysis.needsClass(classElement)) continue; | |
| 389 | 387 |
| 390 elements.add(emitter.constantReference(constant)); | 388 elements.add(emitter.constantReference(constant)); |
| 391 elements.add(backend.emitter.interceptorClassAccess(classElement)); | 389 elements.add(backend.emitter.interceptorClassAccess(classElement)); |
| 392 | 390 |
| 393 // Create JavaScript Object map for by-name lookup of generative | 391 // Create JavaScript Object map for by-name lookup of generative |
| 394 // constructors. For example, the class A has three generative | 392 // constructors. For example, the class A has three generative |
| 395 // constructors | 393 // constructors |
| 396 // | 394 // |
| 397 // class A { | 395 // class A { |
| 398 // A() {} | 396 // A() {} |
| 399 // A.foo() {} | 397 // A.foo() {} |
| 400 // A.bar() {} | 398 // A.bar() {} |
| 401 // } | 399 // } |
| 402 // | 400 // |
| 403 // Which are described by the map | 401 // Which are described by the map |
| 404 // | 402 // |
| 405 // {"": A.A$, "foo": A.A$foo, "bar": A.A$bar} | 403 // {"": A.A$, "foo": A.A$foo, "bar": A.A$bar} |
| 406 // | 404 // |
| 407 // We expect most of the time the map will be a singleton. | 405 // We expect most of the time the map will be a singleton. |
| 408 var properties = []; | 406 var properties = []; |
| 409 for (Element member in analysis.constructors(classElement)) { | 407 for (FunctionEntity member in analysis.constructors(classElement)) { |
| 410 properties.add(new jsAst.Property(js.string(member.name), | 408 properties.add(new jsAst.Property(js.string(member.name), |
| 411 backend.emitter.staticFunctionAccess(member))); | 409 backend.emitter.staticFunctionAccess(member))); |
| 412 } | 410 } |
| 413 | 411 |
| 414 var map = new jsAst.ObjectInitializer(properties); | 412 var map = new jsAst.ObjectInitializer(properties); |
| 415 elements.add(map); | 413 elements.add(map); |
| 416 } | |
| 417 } | 414 } |
| 418 } | 415 } |
| 419 | 416 |
| 420 return new jsAst.ArrayInitializer(elements); | 417 return new jsAst.ArrayInitializer(elements); |
| 421 } | 418 } |
| 422 } | 419 } |
| OLD | NEW |