| 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,25 @@
|
| * 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;
|
| +
|
| + /**
|
| + * Set of classes whose instances are intercepted. Implemented as a
|
| + * [LinkedHashMap] to preserve the insertion order.
|
| + * TODO(ngeoffray): Use a BitSet instead.
|
| + */
|
| + final Map<ClassElement, ClassElement> interceptedClasses;
|
| +
|
| List<CompilerTask> get tasks {
|
| return <CompilerTask>[builder, optimizer, generator, emitter];
|
| }
|
| @@ -695,6 +704,9 @@
|
| usedInterceptors = new Set<Selector>(),
|
| interceptedElements = new Map<SourceString, Set<Element>>(),
|
| rti = new RuntimeTypeInformation(compiler),
|
| + specializedGetInterceptors =
|
| + new Map<String, Collection<ClassElement>>(),
|
| + interceptedClasses = new LinkedHashMap<ClassElement, ClassElement>(),
|
| super(compiler, JAVA_SCRIPT_CONSTANT_SYSTEM) {
|
| emitter = disableEval
|
| ? new CodeEmitterNoEvalTask(compiler, namer, generateSourceMap)
|
| @@ -714,14 +726,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.containsKey(element);
|
| }
|
|
|
| void addInterceptedSelector(Selector selector) {
|
| @@ -746,50 +751,39 @@
|
| return result;
|
| }
|
|
|
| + List<ClassElement> getListOfInterceptedClasses() {
|
| + return <ClassElement>[jsStringClass, jsArrayClass, jsIntClass,
|
| + jsDoubleClass, jsNumberClass, jsNullClass,
|
| + jsFunctionClass, jsBoolClass];
|
| + }
|
| +
|
| void initializeInterceptorElements() {
|
| objectInterceptorClass =
|
| compiler.findInterceptor(const SourceString('ObjectInterceptor'));
|
| getInterceptorMethod =
|
| compiler.findInterceptor(const SourceString('getInterceptor'));
|
| - jsStringClass =
|
| - compiler.findInterceptor(const SourceString('JSString'));
|
| - jsArrayClass =
|
| - compiler.findInterceptor(const SourceString('JSArray'));
|
| - jsNumberClass =
|
| - compiler.findInterceptor(const SourceString('JSNumber'));
|
| - jsIntClass =
|
| - compiler.findInterceptor(const SourceString('JSInt'));
|
| - jsDoubleClass =
|
| - compiler.findInterceptor(const SourceString('JSDouble'));
|
| - jsNullClass =
|
| - compiler.findInterceptor(const SourceString('JSNull'));
|
| - jsFunctionClass =
|
| - compiler.findInterceptor(const SourceString('JSFunction'));
|
| - jsBoolClass =
|
| - compiler.findInterceptor(const SourceString('JSBool'));
|
| + List<ClassElement> classes = [
|
| + jsStringClass = compiler.findInterceptor(const SourceString('JSString')),
|
| + jsArrayClass = compiler.findInterceptor(const SourceString('JSArray')),
|
| + jsNumberClass = compiler.findInterceptor(const SourceString('JSNumber')),
|
| + jsIntClass = compiler.findInterceptor(const SourceString('JSInt')),
|
| + jsDoubleClass = compiler.findInterceptor(const SourceString('JSDouble')),
|
| + jsNullClass = compiler.findInterceptor(const SourceString('JSNull')),
|
| + jsFunctionClass =
|
| + compiler.findInterceptor(const SourceString('JSFunction')),
|
| + jsBoolClass = compiler.findInterceptor(const SourceString('JSBool'))];
|
| +
|
| jsArrayClass.ensureResolved(compiler);
|
| jsArrayLength =
|
| jsArrayClass.lookupLocalMember(const SourceString('length'));
|
| +
|
| jsStringClass.ensureResolved(compiler);
|
| 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'));
|
| + for (ClassElement cls in classes) {
|
| + interceptedClasses[cls] = null;
|
| + }
|
| }
|
|
|
| void addInterceptors(ClassElement cls) {
|
| @@ -802,24 +796,32 @@
|
| includeSuperMembers: true);
|
| }
|
|
|
| + String registerSpecializedGetInterceptor(Set<ClassElement> classes) {
|
| + compiler.enqueuer.codegen.registerInstantiatedClass(objectInterceptorClass);
|
| + if (classes.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, () {
|
| + // 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 interceptedClasses.keys;
|
| + });
|
| + return namer.isolateAccess(getInterceptorMethod);
|
| + } else {
|
| + String name = namer.getSpecializedName(getInterceptorMethod, classes);
|
| + specializedGetInterceptors[name] = classes;
|
| + 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 +829,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;
|
|
|