Chromium Code Reviews| 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 be37c5daea62adebfd90ddd7547fe647d576cced..413fbb9cc54d728797adcc1ef284bd21d8a09bbc 100644 |
| --- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
| +++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
| @@ -98,6 +98,17 @@ class CodeEmitterTask extends CompilerTask { |
| Set<ClassElement> checkedClasses; |
| /** |
| + * Set of JS native classes (or 'Object') that need a [:$nativeCheck:] method, |
| + * because they could be used as a type argument in an is-check. |
| + * |
| + * For example, in the following program, the class int needs a native check |
| + * to correctly match integers in the is-check: |
| + * class Check<T> { foo(o) => o is T; } |
| + * main() => new Check<int>().foo(3); |
| + */ |
| + Set<ClassElement> requiredNativeChecks; |
| + |
| + /** |
| * Raw Typedef symbols occuring in is-checks and type assertions. If the |
| * program contains `x is F<int>` and `x is F<bool>` then the TypedefElement |
| * `F` will occur once in [checkedTypedefs]. |
| @@ -118,7 +129,44 @@ class CodeEmitterTask extends CompilerTask { |
| } |
| void computeRequiredTypeChecks() { |
| - assert(checkedClasses == null); |
| + assert(checkedClasses == null && |
| + checkedTypedefs == null && |
| + requiredNativeChecks == null); |
| + |
| + // Compute type arguments of classes that potentially use their type |
| + // variables in is-checks and compute the (small) set of classes that |
| + // need native check methods (consult the documentation of |
| + // [requiredNativeChecks] for more information). |
| + requiredNativeChecks = new Set<ClassElement>(); |
| + Link<ClassElement> classes = compiler.world.classesUsingTypeVariableTests; |
| + if (!classes.isEmpty) { |
| + // Find all instantiated types that are a subtype of a class that uses |
| + // one of its type arguments in an is-check and add the arguments to the |
| + // set of is-checks. |
| + for (DartType type in compiler.codegenWorld.instantiatedTypes) { |
| + if (type.kind != TypeKind.INTERFACE) continue; |
| + InterfaceType classType = type; |
| + for (classes = compiler.world.classesUsingTypeVariableTests; |
| + !classes.isEmpty; |
| + classes = classes.tail) { |
| + // We need the type as instance of its superclass anyway, so we just |
| + // try to compute the substitution; if the result is [:null:], the |
| + // classes are not related. |
| + InterfaceType instance = classType.asInstanceOf(classes.head); |
| + if (instance == null) continue; |
| + Link<DartType> typeArguments = instance.typeArguments; |
| + for (DartType argument in typeArguments) { |
| + Element element = argument.element; |
| + JavaScriptBackend backend = compiler.backend; |
| + if (backend.rti.needsNativeCheck(element)) { |
| + requiredNativeChecks.add(element); |
| + } |
| + compiler.codegenWorld.isChecks.add(argument); |
| + } |
| + } |
| + } |
| + } |
| + |
| checkedClasses = new Set<ClassElement>(); |
| checkedTypedefs = new Set<TypedefElement>(); |
| compiler.codegenWorld.isChecks.forEach((DartType t) { |
| @@ -1074,7 +1122,7 @@ class CodeEmitterTask extends CompilerTask { |
| void generateIsTest(Element other) { |
| jsAst.Expression code; |
| - if (compiler.objectClass == other) return; |
| + if (other == compiler.objectClass && classElement != other) return; |
|
karlklose
2013/02/19 08:57:38
Actually we do not need to emit it, because we gen
|
| if (nativeEmitter.requiresNativeIsCheck(other)) { |
| code = js.fun([], [js.return_(true)]); |
| } else { |
| @@ -1135,7 +1183,7 @@ class CodeEmitterTask extends CompilerTask { |
| } |
| } |
| - void emitRuntimeClassesAndTests(CodeBuffer buffer) { |
| + void emitRuntimeTypeSupport(CodeBuffer buffer) { |
| RuntimeTypeInformation rti = backend.rti; |
| TypeChecks typeChecks = rti.getRequiredChecks(); |
| @@ -1154,8 +1202,7 @@ class CodeEmitterTask extends CompilerTask { |
| if (!needsHolder(cls)) return; |
| String holder = namer.isolateAccess(cls); |
| String name = namer.getName(cls); |
| - buffer.add("$holder$_=$_{builtin\$cls:$_'$name'"); |
| - buffer.add('}$N'); |
| + buffer.add("$holder$_=$_{builtin\$cls:$_'$name'}$N"); |
| } |
| // Create representation objects for classes that we do not have a class |
| @@ -1176,6 +1223,16 @@ class CodeEmitterTask extends CompilerTask { |
| } |
| }; |
| } |
| + |
| + // Emit native check methods for the class representations of native types |
| + // that could be used in an is-check against a type variable. |
| + requiredNativeChecks.forEach((ClassElement cls) { |
| + jsAst.Expression nativeCheck = rti.getNativeCheck(cls); |
| + String holder = namer.isolateAccess(cls); |
| + buffer.add('$holder.${namer.getNativeCheckName()}$_=$_'); |
| + buffer.addBuffer(jsAst.prettyPrint(nativeCheck, compiler)); |
| + buffer.add('$N'); |
| + }); |
| } |
| void visitNativeMixins(ClassElement classElement, |
| @@ -1558,6 +1615,11 @@ class CodeEmitterTask extends CompilerTask { |
| emitted.add(superclass); |
| } |
| for (DartType supertype in cls.allSupertypes) { |
| + ClassElement superclass = supertype.element; |
| + if (compiler.world.classesUsingTypeVariableTests.contains(superclass)) { |
| + emitSubstitution(superclass, emitNull: true); |
| + emitted.add(superclass); |
| + } |
| for (ClassElement check in checkedClasses) { |
| if (supertype.element == check && !emitted.contains(check)) { |
| // Generate substitution. If no substitution is necessary, emit |
| @@ -2605,7 +2667,7 @@ if (typeof document !== 'undefined' && document.readyState !== 'complete') { |
| // We need to finish the classes before we construct compile time |
| // constants. |
| emitFinishClassesInvocationIfNecessary(mainBuffer); |
| - emitRuntimeClassesAndTests(mainBuffer); |
| + emitRuntimeTypeSupport(mainBuffer); |
| emitCompileTimeConstants(mainBuffer); |
| // Static field initializations require the classes and compile-time |
| // constants to be set up. |