Chromium Code Reviews| Index: sdk/lib/_internal/compiler/implementation/js_backend/type_variable_handler.dart |
| diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/type_variable_handler.dart b/sdk/lib/_internal/compiler/implementation/js_backend/type_variable_handler.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..84ca5ded7c6377ecd655d64b836d0cff1daa1c21 |
| --- /dev/null |
| +++ b/sdk/lib/_internal/compiler/implementation/js_backend/type_variable_handler.dart |
| @@ -0,0 +1,139 @@ |
| +// 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 js_backend; |
| + |
| +/** |
| + * Handles construction of TypeVariable constants needed at runtime. |
| + */ |
| +class TypeVariableHandler { |
| + JavaScriptBackend backend; |
| + FunctionElement typeVariableConstructor; |
| + CompileTimeConstantEvaluator evaluator; |
| + |
| + ClassElement get typeVariableClass => backend.typeVariableClass; |
|
ahe
2013/10/15 14:56:31
Please declare getters after the constructor.
zarah
2013/10/16 07:00:47
Done.
|
| + CodeEmitterTask get emitter => backend.emitter; |
| + Compiler get compiler => backend.compiler; |
| + |
| + /** |
| + * Contains all instantiated classes that have type variables and are needed |
| + * for reflection. |
| + */ |
| + List<ClassElement> typeVariableClasses = new List<ClassElement>(); |
| + |
| + /** |
| + * Maps a class element to a list with indices that point to type variables |
| + * constants for each of the class' type variables. |
| + */ |
| + Map<ClassElement, List<int>> typeVariables = |
| + new Map<ClassElement, List<int>>(); |
| + |
| + /** |
| + * Maps a TypeVariableType to the index pointing to the constant representing |
| + * the corresponding type variable at runtime. |
| + */ |
| + Map<TypeVariableType, int> typeVariableConstants = |
| + new Map<TypeVariableType, int>(); |
| + |
| + TypeVariableHandler(this.backend); |
| + |
| + void registerClassWithTypeVariables(ClassElement cls) { |
| + typeVariableClasses.add(cls); |
| + } |
| + |
| + void onResolutionQueueEmpty(Enqueuer enqueuer) { |
| + if (typeVariableConstructor == null) { |
| + if (!typeVariableClass.constructors.isEmpty && |
| + !typeVariableClass.constructors.tail.isEmpty) { |
| + compiler.reportInternalError( |
| + typeVariableClass, |
| + 'Class $typeVariableClass should only have one constructor'); |
| + } |
| + typeVariableConstructor = typeVariableClass.constructors.head; |
| + backend.enqueueClass( |
| + enqueuer, typeVariableClass, compiler.globalDependencies); |
| + backend.enqueueInResolution( |
| + typeVariableConstructor, compiler.globalDependencies); |
| + } |
| + } |
| + |
| + void onCodegenQueueEmpty() { |
| + evaluator = new CompileTimeConstantEvaluator( |
| + compiler.constantHandler, compiler.globalDependencies, compiler); |
| + |
| + for (ClassElement cls in typeVariableClasses) { |
| + if (!backend.isNeededForReflection(cls)) continue; |
| + InterfaceType typeVariableType = typeVariableClass.computeType(compiler); |
| + List<int> constants = <int>[]; |
| + for (TypeVariableType currentTypeVariable in cls.typeVariables) { |
| + List<Constant> createArguments(FunctionElement constructor) { |
| + if (constructor != typeVariableConstructor) |
|
ahe
2013/10/15 14:59:56
Braces.
zarah
2013/10/16 07:00:47
Done.
|
| + compiler.internalErrorOnElement( |
| + currentTypeVariable.element, |
| + 'Unexpected constructor $constructor'); |
| + Constant name = backend.constantSystem.createString( |
| + new DartString.literal(currentTypeVariable.name.slowToString()), |
| + null); |
| + Constant bound = backend.constantSystem.createInt( |
| + emitter.reifyType(currentTypeVariable.element.bound)); |
| + Constant type = evaluator.makeTypeConstant(cls); |
| + return [type, name, bound]; |
| + } |
| + |
| + Constant c = evaluator.makeConstructedConstant( |
| + currentTypeVariable.element, typeVariableType, |
| + typeVariableConstructor, createArguments); |
| + backend.registerCompileTimeConstant(c, compiler.globalDependencies); |
| + compiler.constantHandler.addCompileTimeConstantForEmission(c); |
| + constants.add(reifyTypeVariableConstant(c, currentTypeVariable)); |
| + } |
| + typeVariables[cls] = constants; |
| + } |
| + typeVariableClasses.clear(); |
| + } |
| + |
| + /** |
| + * Adds [c] to the global metadata list and returns the index pointing to the |
| + * entry. |
| + * |
| + * If the corresponding type variable has already been encountered an |
| + * entry in the list has already been reserved and the constant is added |
| + * there, otherwise a new entry for [c] is created. |
| + */ |
| + int reifyTypeVariableConstant(Constant c, TypeVariableType variable) { |
| + String name = |
| + jsAst.prettyPrint(emitter.constantReference(c), compiler).getText(); |
| + int index; |
| + if (typeVariableConstants.containsKey(variable)) { |
| + index = typeVariableConstants[variable]; |
| + emitter.globalMetadata[index] = name; |
| + } else { |
| + index = emitter.addGlobalMetadata(name); |
| + typeVariableConstants[variable] = index; |
| + } |
| + return index; |
| + } |
| + |
| + /** |
| + * Returns the index pointing to the constant representing this type variable. |
| + * |
| + * If the constant has not yet been constructed, an entry is allocated in |
| + * the global metadata list and the index pointing to this entry is returned. |
|
ahe
2013/10/15 14:59:56
Add a reference to [emitter.globalMetadata].
zarah
2013/10/16 07:00:47
Done.
|
| + * When the corresponding constant is constructed later, |
| + * [reifyTypeVariableConstant] will be called and the constant will be added |
| + * on the allocated entry. |
| + */ |
| + int reifyTypeVariable(TypeVariableType variable) { |
| + if (typeVariableConstants.containsKey(variable)) { |
| + return typeVariableConstants[variable]; |
| + } |
| + |
| + emitter.globalMetadata.add('Placeholder for ${variable.element}'); |
| + return typeVariableConstants[variable] = emitter.globalMetadata.length - 1; |
| + } |
| + |
| + List<int> typeVariablesOf(ClassElement classElement) { |
| + return typeVariables[classElement]; |
| + } |
| +} |