Chromium Code Reviews| Index: sdk/lib/_internal/compiler/implementation/js_backend/backend.dart |
| =================================================================== |
| --- sdk/lib/_internal/compiler/implementation/js_backend/backend.dart (revision 15381) |
| +++ sdk/lib/_internal/compiler/implementation/js_backend/backend.dart (working copy) |
| @@ -635,14 +635,6 @@ |
| Element jsArrayLength; |
| Element jsStringLength; |
| Element getInterceptorMethod; |
| - Element arrayInterceptor; |
| - Element boolInterceptor; |
| - Element doubleInterceptor; |
| - Element functionInterceptor; |
| - Element intInterceptor; |
| - Element nullInterceptor; |
| - Element numberInterceptor; |
| - Element stringInterceptor; |
| bool _interceptorsAreInitialized = false; |
| final Namer namer; |
| @@ -679,8 +671,23 @@ |
| * name to the list of members that have that name. This map is used |
| * by the codegen to know whether a send must be intercepted or not. |
| */ |
| - final Map<SourceString, Set<Element>> interceptedElements; |
| + final Map<SourceString, Set<Element>> interceptedElements; |
| + /** |
| + * A map of specialized versions of the [getInterceptorMethod]. |
| + * Since [getInterceptorMethod] is a hot method at runtime, we're |
| + * always specializing it based on the incoming type. The keys in |
| + * the map are the names of these specialized versions. Note that |
| + * the generic version that contains all possible type checks is |
| + * also stored in this map. |
| + */ |
| + final Map<String, Collection<ClassElement>> specializedGetInterceptors; |
|
ahe
2012/11/27 14:29:45
What is the key?
ngeoffray
2012/11/27 15:50:54
It's in the comment above: the name of the special
|
| + |
| + /** |
| + * Set of classes whose instances are intercepted. |
| + */ |
| + final Set<ClassElement> interceptedClasses; |
| + |
| List<CompilerTask> get tasks { |
| return <CompilerTask>[builder, optimizer, generator, emitter]; |
| } |
| @@ -695,6 +702,9 @@ |
| usedInterceptors = new Set<Selector>(), |
| interceptedElements = new Map<SourceString, Set<Element>>(), |
| rti = new RuntimeTypeInformation(compiler), |
| + specializedGetInterceptors = |
| + new Map<String, Collection<ClassElement>>(), |
| + interceptedClasses = new Set<ClassElement>(), |
| super(compiler, JAVA_SCRIPT_CONSTANT_SYSTEM) { |
| emitter = disableEval |
| ? new CodeEmitterNoEvalTask(compiler, namer, generateSourceMap) |
| @@ -714,14 +724,7 @@ |
| bool isInterceptorClass(Element element) { |
| if (element == null) return false; |
| - return element == jsStringClass |
| - || element == jsArrayClass |
| - || element == jsIntClass |
| - || element == jsDoubleClass |
| - || element == jsNullClass |
| - || element == jsFunctionClass |
| - || element == jsBoolClass |
| - || element == jsNumberClass; |
| + return interceptedClasses.contains(element); |
| } |
| void addInterceptedSelector(Selector selector) { |
| @@ -746,6 +749,12 @@ |
| return result; |
| } |
| + List<ClassElement> getListOfInterceptedClasses() { |
| + return <ClassElement>[jsStringClass, jsArrayClass, jsIntClass, |
|
ahe
2012/11/27 14:29:45
I suggest you create this list in initializeInterc
ngeoffray
2012/11/27 15:50:54
Done.
|
| + jsDoubleClass, jsNumberClass, jsNullClass, |
| + jsFunctionClass, jsBoolClass]; |
| + } |
| + |
| void initializeInterceptorElements() { |
| objectInterceptorClass = |
| compiler.findInterceptor(const SourceString('ObjectInterceptor')); |
| @@ -774,22 +783,7 @@ |
| jsStringLength = |
| jsStringClass.lookupLocalMember(const SourceString('length')); |
| - arrayInterceptor = |
| - compiler.findInterceptor(const SourceString('arrayInterceptor')); |
| - boolInterceptor = |
| - compiler.findInterceptor(const SourceString('boolInterceptor')); |
| - doubleInterceptor = |
| - compiler.findInterceptor(const SourceString('doubleInterceptor')); |
| - functionInterceptor = |
| - compiler.findInterceptor(const SourceString('functionInterceptor')); |
| - intInterceptor = |
| - compiler.findInterceptor(const SourceString('intInterceptor')); |
| - nullInterceptor = |
| - compiler.findInterceptor(const SourceString('nullInterceptor')); |
| - stringInterceptor = |
| - compiler.findInterceptor(const SourceString('stringInterceptor')); |
| - numberInterceptor = |
| - compiler.findInterceptor(const SourceString('numberInterceptor')); |
| + interceptedClasses.addAll(getListOfInterceptedClasses()); |
| } |
| void addInterceptors(ClassElement cls) { |
| @@ -802,24 +796,34 @@ |
| includeSuperMembers: true); |
| } |
| + String registerSpecializedGetInterceptor( |
| + Set<ClassElement> interceptedClasses) { |
| + compiler.enqueuer.codegen.registerInstantiatedClass(objectInterceptorClass); |
| + if (interceptedClasses.contains(compiler.objectClass)) { |
| + // We can't use a specialized [getInterceptorMethod], so we make |
| + // sure we emit the one with all checks. |
| + String name = namer.getName(getInterceptorMethod); |
| + specializedGetInterceptors.putIfAbsent(name, () { |
|
ahe
2012/11/27 14:29:45
I don't understand why you do this. Why shouldn't
ngeoffray
2012/11/27 15:50:54
Because I did not want to call getListOfIntercepte
|
| + // It is important to take the order provided by this list, |
| + // because we want the int type check to happen before the |
| + // double type check: the double type check covers the int |
| + // type check. |
| + return getListOfInterceptedClasses(); |
| + }); |
| + return namer.isolateAccess(getInterceptorMethod); |
| + } else { |
| + String name = namer.getSpecializedName(getInterceptorMethod, |
| + interceptedClasses); |
| + specializedGetInterceptors[name] = interceptedClasses; |
| + return '${namer.CURRENT_ISOLATE}.$name'; |
| + } |
| + } |
| + |
| void registerInstantiatedClass(ClassElement cls, Enqueuer enqueuer) { |
| ClassElement result = null; |
| if (!_interceptorsAreInitialized) { |
| initializeInterceptorElements(); |
| _interceptorsAreInitialized = true; |
| - // The null interceptor and the function interceptor are |
| - // currently always instantiated if a new class is instantiated. |
| - // TODO(ngeoffray): do this elsewhere for the function |
| - // interceptor? |
| - if (jsNullClass != null) { |
| - addInterceptors(jsNullClass); |
| - enqueuer.registerInstantiatedClass(jsNullClass); |
| - } |
| - if (jsFunctionClass != null) { |
| - addInterceptors(jsFunctionClass); |
| - enqueuer.registerInstantiatedClass(jsFunctionClass); |
| - } |
| - enqueuer.addToWorkList(getInterceptorMethod); |
| } |
| if (cls == compiler.stringClass) { |
| result = jsStringClass; |
| @@ -827,12 +831,16 @@ |
| result = jsArrayClass; |
| } else if (cls == compiler.intClass) { |
| result = jsIntClass; |
| + enqueuer.registerInstantiatedClass(jsNumberClass); |
| } else if (cls == compiler.doubleClass) { |
| result = jsDoubleClass; |
| + enqueuer.registerInstantiatedClass(jsNumberClass); |
| } else if (cls == compiler.functionClass) { |
| result = jsFunctionClass; |
| } else if (cls == compiler.boolClass) { |
| result = jsBoolClass; |
| + } else if (cls == compiler.nullClass) { |
| + result = jsNullClass; |
| } |
| if (result == null) return; |