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 b238df675acd8f619b59dfa13fac8e256c34415f..922eb5f207f8ad32875f802092cd43c8083f1d3b 100644 |
| --- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
| +++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
| @@ -94,6 +94,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]. |
| @@ -114,7 +125,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 supertype of a class that uses |
|
ngeoffray
2013/02/18 09:27:58
supertype -> subtype?
karlklose
2013/02/18 16:02:01
Done.
|
| + // 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; |
|
ngeoffray
2013/02/18 09:27:58
Shouldn't that be in codegenWorld as well?
karlklose
2013/02/18 16:02:01
This is in the shared world. I am not sure it is w
ngeoffray
2013/02/19 09:00:41
Why not? The codegen world will have less or equal
karlklose
2013/02/19 12:39:28
Moved to the backend.
|
| + !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) { |
| @@ -789,7 +837,7 @@ $lazyInitializerLogic |
| void generateIsTest(Element other) { |
| js.Expression code; |
| - if (compiler.objectClass == other) return; |
| + if (other == compiler.objectClass && classElement != other) return; |
|
ngeoffray
2013/02/18 09:27:58
Why this change? It looks like you're getting rid
karlklose
2013/02/18 16:02:01
We may need the $isObject flag on objects now, whe
ngeoffray
2013/02/19 09:00:41
So why did you remove it in the new version of the
|
| if (nativeEmitter.requiresNativeIsCheck(other)) { |
| code = js.fun([], js.block1(js.return_(new js.LiteralBool(true)))); |
| } else { |
| @@ -871,8 +919,7 @@ $lazyInitializerLogic |
| 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 |
| @@ -893,6 +940,16 @@ $lazyInitializerLogic |
| } |
| }; |
| } |
| + |
| + // 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) { |
| + js.Expression nativeCheck = rti.getNativeCheck(cls); |
| + String holder = namer.isolateAccess(cls); |
| + buffer.add('$holder.${rti.getNativeCheckName()}$_=$_'); |
| + buffer.addBuffer(js.prettyPrint(nativeCheck, compiler)); |
| + buffer.add('$N'); |
| + }); |
| } |
| void visitNativeMixins(ClassElement classElement, |