Index: pkg/compiler/lib/src/js_emitter/old_emitter/class_emitter.dart |
diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/class_emitter.dart b/pkg/compiler/lib/src/js_emitter/old_emitter/class_emitter.dart |
deleted file mode 100644 |
index 13e2df190681008572bc6c6b58a45d41942953b3..0000000000000000000000000000000000000000 |
--- a/pkg/compiler/lib/src/js_emitter/old_emitter/class_emitter.dart |
+++ /dev/null |
@@ -1,609 +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 ClassEmitter extends CodeEmitterHelper { |
- |
- ClassStubGenerator get _stubGenerator => |
- new ClassStubGenerator(compiler, namer, backend); |
- |
- /** |
- * Documentation wanted -- johnniwinther |
- * |
- * Invariant: [classElement] must be a declaration element. |
- */ |
- void generateClass(ClassElement classElement, |
- ClassBuilder properties, |
- Map<String, jsAst.Expression> additionalProperties) { |
- final onlyForRti = |
- emitter.typeTestEmitter.rtiNeededClasses.contains(classElement); |
- |
- assert(invariant(classElement, classElement.isDeclaration)); |
- assert(invariant(classElement, !classElement.isNative || onlyForRti)); |
- |
- emitter.needsDefineClass = true; |
- String className = namer.getNameOfClass(classElement); |
- |
- ClassElement superclass = classElement.superclass; |
- String superName = ""; |
- if (superclass != null) { |
- superName = namer.getNameOfClass(superclass); |
- } |
- |
- if (classElement.isMixinApplication) { |
- String mixinName = namer.getNameOfClass(computeMixinClass(classElement)); |
- superName = '$superName+$mixinName'; |
- emitter.needsMixinSupport = true; |
- } |
- |
- ClassBuilder builder = new ClassBuilder(classElement, namer); |
- emitClassConstructor(classElement, builder, onlyForRti: onlyForRti); |
- emitFields(classElement, builder, superName, onlyForRti: onlyForRti); |
- emitClassGettersSetters(classElement, builder, onlyForRti: onlyForRti); |
- emitInstanceMembers(classElement, builder, onlyForRti: onlyForRti); |
- emitter.typeTestEmitter.emitIsTests(classElement, builder); |
- if (additionalProperties != null) { |
- additionalProperties.forEach(builder.addProperty); |
- } |
- |
- if (classElement == backend.closureClass) { |
- // We add a special getter here to allow for tearing off a closure from |
- // itself. |
- String name = namer.getMappedInstanceName(Compiler.CALL_OPERATOR_NAME); |
- jsAst.Fun function = js('function() { return this; }'); |
- builder.addProperty(namer.getterNameFromAccessorName(name), function); |
- } |
- |
- emitTypeVariableReaders(classElement, builder); |
- |
- emitClassBuilderWithReflectionData( |
- className, classElement, builder, properties); |
- } |
- |
- void emitClassConstructor(ClassElement classElement, |
- ClassBuilder builder, |
- {bool onlyForRti: false}) { |
- List<String> fields = <String>[]; |
- if (!onlyForRti && !classElement.isNative) { |
- visitFields(classElement, false, |
- (Element member, |
- String name, |
- String accessorName, |
- bool needsGetter, |
- bool needsSetter, |
- bool needsCheckedSetter) { |
- fields.add(name); |
- }); |
- } |
- |
- jsAst.Expression constructorAst = |
- _stubGenerator.generateClassConstructor(classElement, fields); |
- |
- String constructorName = namer.getNameOfClass(classElement); |
- OutputUnit outputUnit = |
- compiler.deferredLoadTask.outputUnitForElement(classElement); |
- emitter.emitPrecompiledConstructor( |
- outputUnit, constructorName, constructorAst); |
- } |
- |
- /// Returns `true` if fields added. |
- bool emitFields(Element element, |
- ClassBuilder builder, |
- String superName, |
- { bool classIsNative: false, |
- bool emitStatics: false, |
- bool onlyForRti: false }) { |
- assert(!emitStatics || !onlyForRti); |
- if (element.isLibrary) { |
- assert(invariant(element, emitStatics)); |
- } else if (!element.isClass) { |
- throw new SpannableAssertionFailure( |
- element, 'Must be a ClassElement or a LibraryElement'); |
- } |
- if (emitStatics) { |
- assert(invariant(element, superName == null, message: superName)); |
- } else { |
- assert(invariant(element, superName != null)); |
- builder.superName = superName; |
- } |
- var fieldMetadata = []; |
- bool hasMetadata = false; |
- bool fieldsAdded = false; |
- |
- if (!onlyForRti) { |
- visitFields(element, emitStatics, |
- (VariableElement field, |
- String name, |
- String accessorName, |
- bool needsGetter, |
- bool needsSetter, |
- bool needsCheckedSetter) { |
- // Ignore needsCheckedSetter - that is handled below. |
- bool needsAccessor = (needsGetter || needsSetter); |
- // We need to output the fields for non-native classes so we can auto- |
- // generate the constructor. For native classes there are no |
- // constructors, so we don't need the fields unless we are generating |
- // accessors at runtime. |
- if (!classIsNative || needsAccessor) { |
- var metadata = emitter.metadataEmitter.buildMetadataFunction(field); |
- if (metadata != null) { |
- hasMetadata = true; |
- } else { |
- metadata = new jsAst.LiteralNull(); |
- } |
- fieldMetadata.add(metadata); |
- recordMangledField(field, accessorName, |
- namer.privateName(field.library, field.name)); |
- String fieldName = name; |
- String fieldCode = ''; |
- String reflectionMarker = ''; |
- if (!needsAccessor) { |
- // Emit field for constructor generation. |
- assert(!classIsNative); |
- } else { |
- // Emit (possibly renaming) field name so we can add accessors at |
- // runtime. |
- if (name != accessorName) { |
- fieldName = '$accessorName:$name'; |
- } |
- |
- int getterCode = 0; |
- if (needsAccessor && backend.fieldHasInterceptedGetter(field)) { |
- emitter.interceptorEmitter.interceptorInvocationNames.add( |
- namer.getterName(field)); |
- } |
- if (needsAccessor && backend.fieldHasInterceptedGetter(field)) { |
- emitter.interceptorEmitter.interceptorInvocationNames.add( |
- namer.setterName(field)); |
- } |
- if (needsGetter) { |
- if (field.isInstanceMember) { |
- // 01: function() { return this.field; } |
- // 10: function(receiver) { return receiver.field; } |
- // 11: function(receiver) { return this.field; } |
- bool isIntercepted = backend.fieldHasInterceptedGetter(field); |
- getterCode += isIntercepted ? 2 : 0; |
- getterCode += backend.isInterceptorClass(element) ? 0 : 1; |
- // TODO(sra): 'isInterceptorClass' might not be the correct test |
- // for methods forced to use the interceptor convention because |
- // the method's class was elsewhere mixed-in to an interceptor. |
- assert(!field.isInstanceMember || getterCode != 0); |
- if (isIntercepted) { |
- emitter.interceptorEmitter.interceptorInvocationNames.add( |
- namer.getterName(field)); |
- } |
- } else { |
- getterCode = 1; |
- } |
- } |
- int setterCode = 0; |
- if (needsSetter) { |
- if (field.isInstanceMember) { |
- // 01: function(value) { this.field = value; } |
- // 10: function(receiver, value) { receiver.field = value; } |
- // 11: function(receiver, value) { this.field = value; } |
- bool isIntercepted = backend.fieldHasInterceptedSetter(field); |
- setterCode += isIntercepted ? 2 : 0; |
- setterCode += backend.isInterceptorClass(element) ? 0 : 1; |
- assert(!field.isInstanceMember || setterCode != 0); |
- if (isIntercepted) { |
- emitter.interceptorEmitter.interceptorInvocationNames.add( |
- namer.setterName(field)); |
- } |
- } else { |
- setterCode = 1; |
- } |
- } |
- int code = getterCode + (setterCode << 2); |
- if (code == 0) { |
- compiler.internalError(field, |
- 'Field code is 0 ($element/$field).'); |
- } else { |
- fieldCode = FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE]; |
- } |
- } |
- if (backend.isAccessibleByReflection(field)) { |
- DartType type = field.type; |
- reflectionMarker = '-${emitter.metadataEmitter.reifyType(type)}'; |
- } |
- String builtFieldname = '$fieldName$fieldCode$reflectionMarker'; |
- builder.addField(builtFieldname); |
- // Add 1 because adding a field to the class also requires a comma |
- compiler.dumpInfoTask.recordFieldNameSize(field, |
- builtFieldname.length + 1); |
- fieldsAdded = true; |
- } |
- }); |
- } |
- |
- if (hasMetadata) { |
- builder.fieldMetadata = fieldMetadata; |
- } |
- return fieldsAdded; |
- } |
- |
- void emitClassGettersSetters(ClassElement classElement, |
- ClassBuilder builder, |
- {bool onlyForRti: false}) { |
- if (onlyForRti) return; |
- |
- visitFields(classElement, false, |
- (VariableElement member, |
- String name, |
- String accessorName, |
- bool needsGetter, |
- bool needsSetter, |
- bool needsCheckedSetter) { |
- compiler.withCurrentElement(member, () { |
- if (needsCheckedSetter) { |
- assert(!needsSetter); |
- generateCheckedSetter(member, name, accessorName, builder); |
- } |
- if (needsGetter) { |
- generateGetter(member, name, accessorName, builder); |
- } |
- if (needsSetter) { |
- generateSetter(member, name, accessorName, builder); |
- } |
- }); |
- }); |
- } |
- |
- /** |
- * Documentation wanted -- johnniwinther |
- * |
- * Invariant: [classElement] must be a declaration element. |
- */ |
- void emitInstanceMembers(ClassElement classElement, |
- ClassBuilder builder, |
- {bool onlyForRti: false}) { |
- assert(invariant(classElement, classElement.isDeclaration)); |
- |
- if (onlyForRti || classElement.isMixinApplication) return; |
- |
- void visitMember(ClassElement enclosing, Element member) { |
- assert(invariant(classElement, member.isDeclaration)); |
- if (member.isInstanceMember) { |
- emitter.containerBuilder.addMember(member, builder); |
- } |
- } |
- |
- classElement.implementation.forEachMember( |
- visitMember, |
- includeBackendMembers: true); |
- |
- if (identical(classElement, compiler.objectClass) |
- && compiler.enabledNoSuchMethod) { |
- // Emit the noSuchMethod handlers on the Object prototype now, |
- // so that the code in the dynamicFunction helper can find |
- // them. Note that this helper is invoked before analyzing the |
- // full JS script. |
- if (!emitter.nativeEmitter.handleNoSuchMethod) { |
- emitter.nsmEmitter.emitNoSuchMethodHandlers(builder.addProperty); |
- } |
- } |
- } |
- |
- void emitClassBuilderWithReflectionData(String className, |
- ClassElement classElement, |
- ClassBuilder classBuilder, |
- ClassBuilder enclosingBuilder) { |
- var metadata = emitter.metadataEmitter.buildMetadataFunction(classElement); |
- if (metadata != null) { |
- classBuilder.addProperty("@", metadata); |
- } |
- |
- if (backend.isAccessibleByReflection(classElement)) { |
- List<DartType> typeVars = classElement.typeVariables; |
- Iterable typeVariableProperties = emitter.typeVariableHandler |
- .typeVariablesOf(classElement).map(js.number); |
- |
- ClassElement superclass = classElement.superclass; |
- bool hasSuper = superclass != null; |
- if ((!typeVariableProperties.isEmpty && !hasSuper) || |
- (hasSuper && !equalElements(superclass.typeVariables, typeVars))) { |
- classBuilder.addProperty('<>', |
- new jsAst.ArrayInitializer.from(typeVariableProperties)); |
- } |
- } |
- |
- List<jsAst.Property> statics = new List<jsAst.Property>(); |
- ClassBuilder staticsBuilder = new ClassBuilder(classElement, namer); |
- if (emitFields(classElement, staticsBuilder, null, emitStatics: true)) { |
- jsAst.ObjectInitializer initializer = |
- staticsBuilder.toObjectInitializer(); |
- compiler.dumpInfoTask.registerElementAst(classElement, |
- initializer); |
- jsAst.Node property = initializer.properties.single; |
- compiler.dumpInfoTask.registerElementAst(classElement, property); |
- statics.add(property); |
- } |
- |
- ClassBuilder classProperties = |
- emitter.elementDescriptors.remove(classElement); |
- if (classProperties != null) { |
- statics.addAll(classProperties.properties); |
- } |
- |
- if (!statics.isEmpty) { |
- classBuilder.addProperty('static', new jsAst.ObjectInitializer(statics)); |
- } |
- |
- // TODO(ahe): This method (generateClass) should return a jsAst.Expression. |
- jsAst.ObjectInitializer propertyValue = classBuilder.toObjectInitializer(); |
- compiler.dumpInfoTask.registerElementAst(classBuilder.element, propertyValue); |
- enclosingBuilder.addProperty(className, propertyValue); |
- |
- String reflectionName = emitter.getReflectionName(classElement, className); |
- if (reflectionName != null) { |
- if (!backend.isAccessibleByReflection(classElement)) { |
- enclosingBuilder.addProperty("+$reflectionName", js.number(0)); |
- } else { |
- List<int> types = <int>[]; |
- if (classElement.supertype != null) { |
- types.add(emitter.metadataEmitter.reifyType(classElement.supertype)); |
- } |
- for (DartType interface in classElement.interfaces) { |
- types.add(emitter.metadataEmitter.reifyType(interface)); |
- } |
- enclosingBuilder.addProperty("+$reflectionName", |
- new jsAst.ArrayInitializer.from(types.map(js.number))); |
- } |
- } |
- } |
- |
- /** |
- * Invokes [f] for each of the fields of [element]. |
- * |
- * [element] must be a [ClassElement] or a [LibraryElement]. |
- * |
- * If [element] is a [ClassElement], the static fields of the class are |
- * visited if [visitStatics] is true and the instance fields are visited if |
- * [visitStatics] is false. |
- * |
- * If [element] is a [LibraryElement], [visitStatics] must be true. |
- * |
- * When visiting the instance fields of a class, the fields of its superclass |
- * are also visited if the class is instantiated. |
- * |
- * Invariant: [element] must be a declaration element. |
- */ |
- void visitFields(Element element, bool visitStatics, AcceptField f) { |
- assert(invariant(element, element.isDeclaration)); |
- |
- bool isClass = false; |
- bool isLibrary = false; |
- if (element.isClass) { |
- isClass = true; |
- } else if (element.isLibrary) { |
- isLibrary = true; |
- assert(invariant(element, visitStatics)); |
- } else { |
- throw new SpannableAssertionFailure( |
- element, 'Expected a ClassElement or a LibraryElement.'); |
- } |
- |
- // If the class is never instantiated we still need to set it up for |
- // inheritance purposes, but we can simplify its JavaScript constructor. |
- bool isInstantiated = |
- compiler.codegenWorld.directlyInstantiatedClasses.contains(element); |
- |
- void visitField(Element holder, VariableElement field) { |
- assert(invariant(element, field.isDeclaration)); |
- String name = field.name; |
- |
- // Keep track of whether or not we're dealing with a field mixin |
- // into a native class. |
- bool isMixinNativeField = |
- isClass && element.isNative && holder.isMixinApplication; |
- |
- // See if we can dynamically create getters and setters. |
- // We can only generate getters and setters for [element] since |
- // the fields of super classes could be overwritten with getters or |
- // setters. |
- bool needsGetter = false; |
- bool needsSetter = false; |
- if (isLibrary || isMixinNativeField || holder == element) { |
- needsGetter = fieldNeedsGetter(field); |
- needsSetter = fieldNeedsSetter(field); |
- } |
- |
- if ((isInstantiated && !holder.isNative) |
- || needsGetter |
- || needsSetter) { |
- String accessorName = namer.fieldAccessorName(field); |
- String fieldName = namer.fieldPropertyName(field); |
- bool needsCheckedSetter = false; |
- if (compiler.enableTypeAssertions |
- && needsSetter |
- && !canAvoidGeneratedCheckedSetter(field)) { |
- needsCheckedSetter = true; |
- needsSetter = false; |
- } |
- // Getters and setters with suffixes will be generated dynamically. |
- f(field, fieldName, accessorName, needsGetter, needsSetter, |
- needsCheckedSetter); |
- } |
- } |
- |
- if (isLibrary) { |
- LibraryElement library = element; |
- library.implementation.forEachLocalMember((Element member) { |
- if (member.isField) visitField(library, member); |
- }); |
- } else if (visitStatics) { |
- ClassElement cls = element; |
- cls.implementation.forEachStaticField(visitField); |
- } else { |
- ClassElement cls = element; |
- // TODO(kasperl): We should make sure to only emit one version of |
- // overridden fields. Right now, we rely on the ordering so the |
- // fields pulled in from mixins are replaced with the fields from |
- // the class definition. |
- |
- // If a class is not instantiated then we add the field just so we can |
- // generate the field getter/setter dynamically. Since this is only |
- // allowed on fields that are in [element] we don't need to visit |
- // superclasses for non-instantiated classes. |
- cls.implementation.forEachInstanceField( |
- visitField, includeSuperAndInjectedMembers: isInstantiated); |
- } |
- } |
- |
- void recordMangledField(Element member, |
- String accessorName, |
- String memberName) { |
- if (!backend.shouldRetainGetter(member)) return; |
- String previousName; |
- if (member.isInstanceMember) { |
- previousName = emitter.mangledFieldNames.putIfAbsent( |
- '${namer.getterPrefix}$accessorName', |
- () => memberName); |
- } else { |
- previousName = emitter.mangledGlobalFieldNames.putIfAbsent( |
- accessorName, |
- () => memberName); |
- } |
- assert(invariant(member, previousName == memberName, |
- message: '$previousName != ${memberName}')); |
- } |
- |
- bool fieldNeedsGetter(VariableElement field) { |
- assert(field.isField); |
- if (fieldAccessNeverThrows(field)) return false; |
- return backend.shouldRetainGetter(field) |
- || compiler.codegenWorld.hasInvokedGetter(field, compiler.world); |
- } |
- |
- bool fieldNeedsSetter(VariableElement field) { |
- assert(field.isField); |
- if (fieldAccessNeverThrows(field)) return false; |
- return (!field.isFinal && !field.isConst) |
- && (backend.shouldRetainSetter(field) |
- || compiler.codegenWorld.hasInvokedSetter(field, compiler.world)); |
- } |
- |
- // We never access a field in a closure (a captured variable) without knowing |
- // that it is there. Therefore we don't need to use a getter (that will throw |
- // if the getter method is missing), but can always access the field directly. |
- static bool fieldAccessNeverThrows(VariableElement field) { |
- return field is ClosureFieldElement; |
- } |
- |
- bool canAvoidGeneratedCheckedSetter(VariableElement member) { |
- // We never generate accessors for top-level/static fields. |
- if (!member.isInstanceMember) return true; |
- DartType type = member.type; |
- return type.treatAsDynamic || (type.element == compiler.objectClass); |
- } |
- |
- void generateCheckedSetter(Element member, |
- String fieldName, |
- String accessorName, |
- ClassBuilder builder) { |
- jsAst.Expression code = backend.generatedCode[member]; |
- assert(code != null); |
- String setterName = namer.setterNameFromAccessorName(accessorName); |
- compiler.dumpInfoTask.registerElementAst(member, |
- builder.addProperty(setterName, code)); |
- generateReflectionDataForFieldGetterOrSetter( |
- member, setterName, builder, isGetter: false); |
- } |
- |
- void generateGetter(Element member, String fieldName, String accessorName, |
- ClassBuilder builder) { |
- jsAst.Expression function = |
- _stubGenerator.generateGetter(member, fieldName); |
- |
- String getterName = namer.getterNameFromAccessorName(accessorName); |
- ClassElement cls = member.enclosingClass; |
- String className = namer.getNameOfClass(cls); |
- OutputUnit outputUnit = |
- compiler.deferredLoadTask.outputUnitForElement(member); |
- emitter.cspPrecompiledFunctionFor(outputUnit).add( |
- js('#.prototype.# = #', [className, getterName, function])); |
- if (backend.isAccessibleByReflection(member)) { |
- emitter.cspPrecompiledFunctionFor(outputUnit).add( |
- js('#.prototype.#.${namer.reflectableField} = 1', |
- [className, getterName])); |
- } |
- } |
- |
- void generateSetter(Element member, String fieldName, String accessorName, |
- ClassBuilder builder) { |
- jsAst.Expression function = |
- _stubGenerator.generateSetter(member, fieldName); |
- |
- String setterName = namer.setterNameFromAccessorName(accessorName); |
- ClassElement cls = member.enclosingClass; |
- String className = namer.getNameOfClass(cls); |
- OutputUnit outputUnit = |
- compiler.deferredLoadTask.outputUnitForElement(member); |
- emitter.cspPrecompiledFunctionFor(outputUnit).add( |
- js('#.prototype.# = #', [className, setterName, function])); |
- if (backend.isAccessibleByReflection(member)) { |
- emitter.cspPrecompiledFunctionFor(outputUnit).add( |
- js('#.prototype.#.${namer.reflectableField} = 1', |
- [className, setterName])); |
- } |
- } |
- |
- void generateReflectionDataForFieldGetterOrSetter(Element member, |
- String name, |
- ClassBuilder builder, |
- {bool isGetter}) { |
- Selector selector = isGetter |
- ? new Selector.getter(member.name, member.library) |
- : new Selector.setter(member.name, member.library); |
- String reflectionName = emitter.getReflectionName(selector, name); |
- if (reflectionName != null) { |
- var reflectable = |
- js(backend.isAccessibleByReflection(member) ? '1' : '0'); |
- builder.addProperty('+$reflectionName', reflectable); |
- } |
- } |
- |
- void emitTypeVariableReaders(ClassElement cls, ClassBuilder builder) { |
- List typeVariables = []; |
- ClassElement superclass = cls; |
- while (superclass != null) { |
- for (TypeVariableType parameter in superclass.typeVariables) { |
- if (backend.emitter.readTypeVariables.contains(parameter.element)) { |
- emitTypeVariableReader(cls, builder, parameter.element); |
- } |
- } |
- superclass = superclass.superclass; |
- } |
- } |
- |
- void emitTypeVariableReader(ClassElement cls, |
- ClassBuilder builder, |
- TypeVariableElement element) { |
- String name = namer.readTypeVariableName(element); |
- jsAst.Expression index = |
- js.number(RuntimeTypes.getTypeVariableIndex(element)); |
- jsAst.Expression computeTypeVariable; |
- |
- Substitution substitution = |
- backend.rti.computeSubstitution( |
- cls, element.typeDeclaration, alwaysGenerateFunction: true); |
- if (substitution != null) { |
- jsAst.Expression typeArguments = |
- js(r'#.apply(null, this.$builtinTypeInfo)', |
- substitution.getCode(backend.rti, true)); |
- computeTypeVariable = js('#[#]', [typeArguments, index]); |
- } else { |
- // TODO(ahe): These can be generated dynamically. |
- computeTypeVariable = |
- js(r'this.$builtinTypeInfo && this.$builtinTypeInfo[#]', index); |
- } |
- jsAst.Expression convertRtiToRuntimeType = |
- namer.elementAccess(backend.findHelper('convertRtiToRuntimeType')); |
- compiler.dumpInfoTask.registerElementAst(element, |
- builder.addProperty(name, |
- js('function () { return #(#) }', |
- [convertRtiToRuntimeType, computeTypeVariable]))); |
- } |
-} |