Index: sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
index 32d3ab8e05ae37f41f8813b6101e0916f4cbd6be..d0669b331870bb7927aaa425df4c238801d20f99 100644 |
--- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
@@ -2631,6 +2631,8 @@ class CodeEmitterTask extends CompilerTask { |
for (Element element in Elements.sortedByPosition(staticNonFinalFields)) { |
// [:interceptedNames:] is handled in [emitInterceptedNames]. |
if (element == backend.interceptedNames) continue; |
+ // `mapTypeToInterceptor` is handled in [emitMapTypeToInterceptor]. |
+ if (element == backend.mapTypeToInterceptor) continue; |
compiler.withCurrentElement(element, () { |
Constant initialValue = handler.getInitialValueFor(element); |
jsAst.Expression init = |
@@ -3056,6 +3058,9 @@ class CodeEmitterTask extends CompilerTask { |
bool hasNumber = false; |
bool hasString = false; |
bool hasNative = false; |
+ bool anyNativeClasses = compiler.enqueuer.codegen.nativeEnqueuer |
+ .hasInstantiatedNativeClasses(); |
+ |
for (ClassElement cls in classes) { |
if (cls == backend.jsArrayClass || |
cls == backend.jsMutableArrayClass || |
@@ -3068,10 +3073,18 @@ class CodeEmitterTask extends CompilerTask { |
else if (cls == backend.jsNumberClass) hasNumber = true; |
else if (cls == backend.jsStringClass) hasString = true; |
else { |
- // TODO(sra): The set of classes includes classes mixed-in to |
- // interceptor classes. |
- // assert(cls == compiler.objectClass || cls.isNative()); |
- if (cls.isNative()) hasNative = true; |
+ // The set of classes includes classes mixed-in to interceptor classes |
+ // and user extensions of native classes. |
+ // |
+ // The set of classes also includes the 'primitive' interceptor |
+ // PlainJavaScriptObject even when it has not been resolved, since it is |
+ // only resolved through the reference in getNativeInterceptor when |
+ // getNativeInterceptor is marked as used. Guard against probing |
+ // unresolved PlainJavaScriptObject by testing for anyNativeClasses. |
+ |
+ if (anyNativeClasses) { |
+ if (Elements.isNativeOrExtendsNative(cls)) hasNative = true; |
+ } |
} |
} |
if (hasDouble) { |
@@ -3081,8 +3094,7 @@ class CodeEmitterTask extends CompilerTask { |
if (classes == backend.interceptedClasses) { |
// I.e. this is the general interceptor. |
- hasNative = compiler.enqueuer.codegen.nativeEnqueuer |
- .hasInstantiatedNativeClasses(); |
+ hasNative = anyNativeClasses; |
} |
jsAst.Block block = new jsAst.Block.empty(); |
@@ -3245,9 +3257,13 @@ class CodeEmitterTask extends CompilerTask { |
for (ClassElement element in sortedClasses) { |
if (rtiNeededClasses.contains(element)) { |
regularClasses.add(element); |
- } else if (element.isNative()) { |
- // For now, native classes cannot be deferred. |
+ } else if (Elements.isNativeOrExtendsNative(element)) { |
+ // For now, native classes and related classes cannot be deferred. |
nativeClasses.add(element); |
+ if (!element.isNative()) { |
+ assert(invariant(element, !isDeferred(element))); |
+ regularClasses.add(element); |
+ } |
} else if (isDeferred(element)) { |
deferredClasses.add(element); |
} else { |
@@ -3511,6 +3527,37 @@ class CodeEmitterTask extends CompilerTask { |
buffer.write(N); |
} |
+ /** |
+ * Emit initializer for [mapTypeToInterceptor] data structure used by |
+ * [findInterceptorForType]. See declaration of [mapTypeToInterceptor] in |
+ * `interceptors.dart`. |
+ */ |
+ void emitMapTypeToInterceptor(CodeBuffer buffer) { |
+ // TODO(sra): Perhaps inject a constant instead? |
+ // TODO(sra): Filter by subclasses of native types. |
+ List<jsAst.Expression> elements = <jsAst.Expression>[]; |
+ ConstantHandler handler = compiler.constantHandler; |
+ List<Constant> constants = handler.getConstantsForEmission(); |
+ for (Constant constant in constants) { |
+ if (constant is TypeConstant) { |
+ TypeConstant typeConstant = constant; |
+ Element element = typeConstant.representedType.element; |
+ if (element is ClassElement) { |
+ ClassElement classElement = element; |
+ elements.add(backend.emitter.constantReference(constant)); |
+ elements.add(js(namer.isolateAccess(classElement))); |
+ } |
+ } |
+ } |
+ |
+ jsAst.ArrayInitializer array = new jsAst.ArrayInitializer.from(elements); |
+ String name = backend.namer.getName(backend.mapTypeToInterceptor); |
+ jsAst.Expression assignment = js('$isolateProperties.$name = #', array); |
+ |
+ buffer.write(jsAst.prettyPrint(assignment, compiler)); |
+ buffer.write(N); |
+ } |
+ |
void emitInitFunction(CodeBuffer buffer) { |
jsAst.Fun fun = js.fun([], [ |
js('$isolateProperties = {}'), |
@@ -3843,6 +3890,7 @@ class CodeEmitterTask extends CompilerTask { |
emitStaticNonFinalFieldInitializations(mainBuffer); |
emitOneShotInterceptors(mainBuffer); |
emitInterceptedNames(mainBuffer); |
+ emitMapTypeToInterceptor(mainBuffer); |
emitLazilyInitializedStaticFields(mainBuffer); |
mainBuffer.add(nativeBuffer); |