Index: pkg/compiler/lib/src/js_emitter/old_emitter/type_test_emitter.dart |
diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/type_test_emitter.dart b/pkg/compiler/lib/src/js_emitter/old_emitter/type_test_emitter.dart |
deleted file mode 100644 |
index 5fc4d0cae242c9f5f54a8cdca0456b9e3bd5334d..0000000000000000000000000000000000000000 |
--- a/pkg/compiler/lib/src/js_emitter/old_emitter/type_test_emitter.dart |
+++ /dev/null |
@@ -1,448 +0,0 @@ |
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-part of dart2js.js_emitter; |
- |
-class TypeTestEmitter extends CodeEmitterHelper { |
- static const int MAX_FUNCTION_TYPE_PREDICATES = 10; |
- |
- /** |
- * Raw ClassElement symbols occuring in is-checks and type assertions. If the |
- * program contains parameterized checks `x is Set<int>` and |
- * `x is Set<String>` then the ClassElement `Set` will occur once in |
- * [checkedClasses]. |
- */ |
- Set<ClassElement> checkedClasses; |
- |
- /** |
- * The set of function types that checked, both explicity through tests of |
- * typedefs and implicitly through type annotations in checked mode. |
- */ |
- Set<FunctionType> checkedFunctionTypes; |
- |
- Map<ClassElement, Set<FunctionType>> checkedGenericFunctionTypes = |
- new Map<ClassElement, Set<FunctionType>>(); |
- |
- Set<FunctionType> checkedNonGenericFunctionTypes = |
- new Set<FunctionType>(); |
- |
- final Set<ClassElement> rtiNeededClasses = new Set<ClassElement>(); |
- |
- Iterable<ClassElement> cachedClassesUsingTypeVariableTests; |
- |
- Iterable<ClassElement> get classesUsingTypeVariableTests { |
- if (cachedClassesUsingTypeVariableTests == null) { |
- cachedClassesUsingTypeVariableTests = compiler.codegenWorld.isChecks |
- .where((DartType t) => t is TypeVariableType) |
- .map((TypeVariableType v) => v.element.enclosingClass) |
- .toList(); |
- } |
- return cachedClassesUsingTypeVariableTests; |
- } |
- |
- void emitIsTests(ClassElement classElement, ClassBuilder builder) { |
- assert(invariant(classElement, classElement.isDeclaration)); |
- |
- void generateIsTest(Element other) { |
- if (other == compiler.objectClass && other != classElement) { |
- // Avoid emitting [:$isObject:] on all classes but [Object]. |
- return; |
- } |
- builder.addProperty(namer.operatorIs(other), js('true')); |
- } |
- |
- void generateFunctionTypeSignature(FunctionElement method, |
- FunctionType type) { |
- assert(method.isImplementation); |
- jsAst.Expression thisAccess = new jsAst.This(); |
- Node node = method.node; |
- ClosureClassMap closureData = |
- compiler.closureToClassMapper.closureMappingCache[node]; |
- if (closureData != null) { |
- ClosureFieldElement thisLocal = |
- closureData.getFreeVariableElement(closureData.thisLocal); |
- if (thisLocal != null) { |
- String thisName = namer.instanceFieldPropertyName(thisLocal); |
- thisAccess = js('this.#', thisName); |
- } |
- } |
- RuntimeTypes rti = backend.rti; |
- jsAst.Expression encoding = rti.getSignatureEncoding(type, thisAccess); |
- String operatorSignature = namer.operatorSignature(); |
- if (!type.containsTypeVariables) { |
- builder.functionType = '${emitter.metadataEmitter.reifyType(type)}'; |
- } else { |
- builder.addProperty(operatorSignature, encoding); |
- } |
- } |
- |
- void generateSubstitution(ClassElement cls, {bool emitNull: false}) { |
- if (cls.typeVariables.isEmpty) return; |
- RuntimeTypes rti = backend.rti; |
- jsAst.Expression expression; |
- bool needsNativeCheck = emitter.nativeEmitter.requiresNativeIsCheck(cls); |
- expression = rti.getSupertypeSubstitution( |
- classElement, cls, alwaysGenerateFunction: true); |
- if (expression == null && (emitNull || needsNativeCheck)) { |
- expression = new jsAst.LiteralNull(); |
- } |
- if (expression != null) { |
- builder.addProperty(namer.substitutionName(cls), expression); |
- } |
- } |
- |
- generateIsTestsOn(classElement, generateIsTest, |
- generateFunctionTypeSignature, |
- generateSubstitution); |
- } |
- |
- /** |
- * Generate "is tests" for [cls]: itself, and the "is tests" for the |
- * classes it implements and type argument substitution functions for these |
- * tests. We don't need to add the "is tests" of the super class because |
- * they will be inherited at runtime, but we may need to generate the |
- * substitutions, because they may have changed. |
- */ |
- void generateIsTestsOn(ClassElement cls, |
- void emitIsTest(Element element), |
- FunctionTypeSignatureEmitter emitFunctionTypeSignature, |
- SubstitutionEmitter emitSubstitution) { |
- if (checkedClasses.contains(cls)) { |
- emitIsTest(cls); |
- emitSubstitution(cls); |
- } |
- |
- RuntimeTypes rti = backend.rti; |
- ClassElement superclass = cls.superclass; |
- |
- bool haveSameTypeVariables(ClassElement a, ClassElement b) { |
- if (a.isClosure) return true; |
- return backend.rti.isTrivialSubstitution(a, b); |
- } |
- |
- if (superclass != null && superclass != compiler.objectClass && |
- !haveSameTypeVariables(cls, superclass)) { |
- // We cannot inherit the generated substitutions, because the type |
- // variable layout for this class is different. Instead we generate |
- // substitutions for all checks and make emitSubstitution a NOP for the |
- // rest of this function. |
- Set<ClassElement> emitted = new Set<ClassElement>(); |
- // TODO(karlklose): move the computation of these checks to |
- // RuntimeTypeInformation. |
- while (superclass != null) { |
- if (backend.classNeedsRti(superclass)) { |
- emitSubstitution(superclass, emitNull: true); |
- emitted.add(superclass); |
- } |
- superclass = superclass.superclass; |
- } |
- for (DartType supertype in cls.allSupertypes) { |
- ClassElement superclass = supertype.element; |
- if (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 |
- // [:null:] to overwrite a (possibly) existing substitution from the |
- // super classes. |
- emitSubstitution(check, emitNull: true); |
- emitted.add(check); |
- } |
- } |
- } |
- void emitNothing(_, {emitNull}) {}; |
- emitSubstitution = emitNothing; |
- } |
- |
- Set<Element> generated = new Set<Element>(); |
- // A class that defines a [:call:] method implicitly implements |
- // [Function] and needs checks for all typedefs that are used in is-checks. |
- if (checkedClasses.contains(compiler.functionClass) || |
- !checkedFunctionTypes.isEmpty) { |
- Element call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); |
- if (call == null) { |
- // If [cls] is a closure, it has a synthetic call operator method. |
- call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); |
- } |
- if (call != null && call.isFunction) { |
- generateInterfacesIsTests(compiler.functionClass, |
- emitIsTest, |
- emitSubstitution, |
- generated); |
- FunctionType callType = call.computeType(compiler); |
- Map<FunctionType, bool> functionTypeChecks = |
- getFunctionTypeChecksOn(callType); |
- generateFunctionTypeTests( |
- call, callType, functionTypeChecks, |
- emitFunctionTypeSignature); |
- } |
- } |
- |
- for (DartType interfaceType in cls.interfaces) { |
- generateInterfacesIsTests(interfaceType.element, emitIsTest, |
- emitSubstitution, generated); |
- } |
- } |
- |
- /** |
- * Generate "is tests" where [cls] is being implemented. |
- */ |
- void generateInterfacesIsTests(ClassElement cls, |
- void emitIsTest(ClassElement element), |
- SubstitutionEmitter emitSubstitution, |
- Set<Element> alreadyGenerated) { |
- void tryEmitTest(ClassElement check) { |
- if (!alreadyGenerated.contains(check) && checkedClasses.contains(check)) { |
- alreadyGenerated.add(check); |
- emitIsTest(check); |
- emitSubstitution(check); |
- } |
- }; |
- |
- tryEmitTest(cls); |
- |
- for (DartType interfaceType in cls.interfaces) { |
- Element element = interfaceType.element; |
- tryEmitTest(element); |
- generateInterfacesIsTests(element, emitIsTest, emitSubstitution, |
- alreadyGenerated); |
- } |
- |
- // We need to also emit "is checks" for the superclass and its supertypes. |
- ClassElement superclass = cls.superclass; |
- if (superclass != null) { |
- tryEmitTest(superclass); |
- generateInterfacesIsTests(superclass, emitIsTest, emitSubstitution, |
- alreadyGenerated); |
- } |
- } |
- |
- /** |
- * Returns a mapping containing all checked function types for which [type] |
- * can be a subtype. A function type is mapped to [:true:] if [type] is |
- * statically known to be a subtype of it and to [:false:] if [type] might |
- * be a subtype, provided with the right type arguments. |
- */ |
- // TODO(johnniwinther): Change to return a mapping from function types to |
- // a set of variable points and use this to detect statically/dynamically |
- // known subtype relations. |
- Map<FunctionType, bool> getFunctionTypeChecksOn(DartType type) { |
- Map<FunctionType, bool> functionTypeMap = new Map<FunctionType, bool>(); |
- for (FunctionType functionType in checkedFunctionTypes) { |
- int maybeSubtype = |
- compiler.types.computeSubtypeRelation(type, functionType); |
- if (maybeSubtype == Types.IS_SUBTYPE) { |
- functionTypeMap[functionType] = true; |
- } else if (maybeSubtype == Types.MAYBE_SUBTYPE) { |
- functionTypeMap[functionType] = false; |
- } |
- } |
- // TODO(johnniwinther): Ensure stable ordering of the keys. |
- return functionTypeMap; |
- } |
- |
- /** |
- * Generates function type checks on [method] with type [methodType] against |
- * the function type checks in [functionTypeChecks]. |
- */ |
- void generateFunctionTypeTests( |
- Element method, |
- FunctionType methodType, |
- Map<FunctionType, bool> functionTypeChecks, |
- FunctionTypeSignatureEmitter emitFunctionTypeSignature) { |
- |
- // TODO(ahe): We should be able to remove this forEach loop. |
- functionTypeChecks.forEach((FunctionType functionType, bool knownSubtype) { |
- registerDynamicFunctionTypeCheck(functionType); |
- }); |
- |
- emitFunctionTypeSignature(method, methodType); |
- } |
- |
- void registerDynamicFunctionTypeCheck(FunctionType functionType) { |
- ClassElement classElement = Types.getClassContext(functionType); |
- if (classElement != null) { |
- checkedGenericFunctionTypes.putIfAbsent(classElement, |
- () => new Set<FunctionType>()).add(functionType); |
- } else { |
- checkedNonGenericFunctionTypes.add(functionType); |
- } |
- } |
- |
- void emitRuntimeTypeSupport(CodeBuffer buffer, OutputUnit outputUnit) { |
- emitter.addComment('Runtime type support', buffer); |
- RuntimeTypes rti = backend.rti; |
- TypeChecks typeChecks = rti.requiredChecks; |
- |
- // Add checks to the constructors of instantiated classes. |
- // TODO(sigurdm): We should avoid running through this list for each |
- // output unit. |
- |
- jsAst.Statement variables = js.statement('var TRUE = !0, _;'); |
- List<jsAst.Statement> statements = <jsAst.Statement>[]; |
- |
- for (ClassElement cls in typeChecks) { |
- OutputUnit destination = |
- compiler.deferredLoadTask.outputUnitForElement(cls); |
- if (destination != outputUnit) continue; |
- // TODO(9556). The properties added to 'holder' should be generated |
- // directly as properties of the class object, not added later. |
- |
- // Each element is a pair: [propertyName, valueExpression] |
- List<List> properties = <List>[]; |
- |
- for (TypeCheck check in typeChecks[cls]) { |
- ClassElement checkedClass = check.cls; |
- properties.add([namer.operatorIs(checkedClass), js('TRUE')]); |
- Substitution substitution = check.substitution; |
- if (substitution != null) { |
- jsAst.Expression body = substitution.getCode(rti, false); |
- properties.add([namer.substitutionName(checkedClass), body]); |
- } |
- } |
- |
- jsAst.Expression holder = namer.elementAccess(cls); |
- if (properties.length > 1) { |
- // Use temporary shortened reference. |
- statements.add(js.statement('_ = #;', holder)); |
- holder = js('#', '_'); |
- } |
- for (List nameAndValue in properties) { |
- statements.add( |
- js.statement('#.# = #', |
- [holder, nameAndValue[0], nameAndValue[1]])); |
- } |
- } |
- |
- if (statements.isNotEmpty) { |
- buffer.write(';'); |
- buffer.write( |
- jsAst.prettyPrint( |
- js.statement('(function() { #; #; })()', [variables, statements]), |
- compiler)); |
- buffer.write('$N'); |
- } |
- } |
- |
- /** |
- * Returns the classes with constructors used as a 'holder' in |
- * [emitRuntimeTypeSupport]. |
- * TODO(9556): Some cases will go away when the class objects are created as |
- * complete. Not all classes will go away while constructors are referenced |
- * from type substitutions. |
- */ |
- Set<ClassElement> classesModifiedByEmitRuntimeTypeSupport() { |
- TypeChecks typeChecks = backend.rti.requiredChecks; |
- Set<ClassElement> result = new Set<ClassElement>(); |
- for (ClassElement cls in typeChecks) { |
- for (TypeCheck check in typeChecks[cls]) { |
- result.add(cls); |
- break; |
- } |
- } |
- return result; |
- } |
- |
- Set<ClassElement> computeRtiNeededClasses() { |
- void addClassWithSuperclasses(ClassElement cls) { |
- rtiNeededClasses.add(cls); |
- for (ClassElement superclass = cls.superclass; |
- superclass != null; |
- superclass = superclass.superclass) { |
- rtiNeededClasses.add(superclass); |
- } |
- } |
- |
- void addClassesWithSuperclasses(Iterable<ClassElement> classes) { |
- for (ClassElement cls in classes) { |
- addClassWithSuperclasses(cls); |
- } |
- } |
- |
- // 1. Add classes that are referenced by type arguments or substitutions in |
- // argument checks. |
- // TODO(karlklose): merge this case with 2 when unifying argument and |
- // object checks. |
- RuntimeTypes rti = backend.rti; |
- rti.getRequiredArgumentClasses(backend) |
- .forEach(addClassWithSuperclasses); |
- |
- // 2. Add classes that are referenced by substitutions in object checks and |
- // their superclasses. |
- TypeChecks requiredChecks = |
- rti.computeChecks(rtiNeededClasses, checkedClasses); |
- Set<ClassElement> classesUsedInSubstitutions = |
- rti.getClassesUsedInSubstitutions(backend, requiredChecks); |
- addClassesWithSuperclasses(classesUsedInSubstitutions); |
- |
- // 3. Add classes that contain checked generic function types. These are |
- // needed to store the signature encoding. |
- for (FunctionType type in checkedFunctionTypes) { |
- ClassElement contextClass = Types.getClassContext(type); |
- if (contextClass != null) { |
- rtiNeededClasses.add(contextClass); |
- } |
- } |
- |
- bool canTearOff(Element function) { |
- if (!function.isFunction || |
- function.isConstructor || |
- function.isAccessor) { |
- return false; |
- } else if (function.isInstanceMember) { |
- if (!function.enclosingClass.isClosure) { |
- return compiler.codegenWorld.hasInvokedGetter( |
- function, compiler.world); |
- } |
- } |
- return false; |
- } |
- |
- bool canBeReflectedAsFunction(Element element) { |
- return element.kind == ElementKind.FUNCTION || |
- element.kind == ElementKind.GETTER || |
- element.kind == ElementKind.SETTER || |
- element.kind == ElementKind.GENERATIVE_CONSTRUCTOR; |
- } |
- |
- bool canBeReified(Element element) { |
- return (canTearOff(element) || backend.isAccessibleByReflection(element)); |
- } |
- |
- // Find all types referenced from the types of elements that can be |
- // reflected on 'as functions'. |
- backend.generatedCode.keys.where((element) { |
- return canBeReflectedAsFunction(element) && canBeReified(element); |
- }).forEach((FunctionElement function) { |
- DartType type = function.computeType(compiler); |
- for (ClassElement cls in backend.rti.getReferencedClasses(type)) { |
- while (cls != null) { |
- rtiNeededClasses.add(cls); |
- cls = cls.superclass; |
- } |
- } |
- }); |
- |
- return rtiNeededClasses; |
- } |
- |
- void computeRequiredTypeChecks() { |
- assert(checkedClasses == null && checkedFunctionTypes == null); |
- |
- backend.rti.addImplicitChecks(compiler.codegenWorld, |
- classesUsingTypeVariableTests); |
- |
- checkedClasses = new Set<ClassElement>(); |
- checkedFunctionTypes = new Set<FunctionType>(); |
- compiler.codegenWorld.isChecks.forEach((DartType t) { |
- if (t is InterfaceType) { |
- checkedClasses.add(t.element); |
- } else if (t is FunctionType) { |
- checkedFunctionTypes.add(t); |
- } |
- }); |
- } |
-} |