| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of dart2js.js_emitter.full_emitter; | 5 part of dart2js.js_emitter.full_emitter; |
| 6 | 6 |
| 7 class ClassEmitter extends CodeEmitterHelper { | 7 class ClassEmitter extends CodeEmitterHelper { |
| 8 | |
| 9 ClassStubGenerator get _stubGenerator => | 8 ClassStubGenerator get _stubGenerator => |
| 10 new ClassStubGenerator(compiler, namer, backend); | 9 new ClassStubGenerator(compiler, namer, backend); |
| 11 | 10 |
| 12 /** | 11 /** |
| 13 * Documentation wanted -- johnniwinther | 12 * Documentation wanted -- johnniwinther |
| 14 */ | 13 */ |
| 15 void emitClass(Class cls, ClassBuilder enclosingBuilder, Fragment fragment) { | 14 void emitClass(Class cls, ClassBuilder enclosingBuilder, Fragment fragment) { |
| 16 ClassElement classElement = cls.element; | 15 ClassElement classElement = cls.element; |
| 17 | 16 |
| 18 assert(invariant(classElement, classElement.isDeclaration)); | 17 assert(invariant(classElement, classElement.isDeclaration)); |
| 19 | 18 |
| 20 emitter.needsClassSupport = true; | 19 emitter.needsClassSupport = true; |
| 21 | 20 |
| 22 ClassElement superclass = classElement.superclass; | 21 ClassElement superclass = classElement.superclass; |
| 23 jsAst.Name superName; | 22 jsAst.Name superName; |
| 24 if (superclass != null) { | 23 if (superclass != null) { |
| 25 superName = namer.className(superclass); | 24 superName = namer.className(superclass); |
| 26 } | 25 } |
| 27 | 26 |
| 28 if (cls.isMixinApplication) { | 27 if (cls.isMixinApplication) { |
| 29 MixinApplication mixinApplication = cls; | 28 MixinApplication mixinApplication = cls; |
| 30 jsAst.Name mixinName = mixinApplication.mixinClass.name; | 29 jsAst.Name mixinName = mixinApplication.mixinClass.name; |
| 31 superName = | 30 superName = new CompoundName([superName, Namer.literalPlus, mixinName]); |
| 32 new CompoundName([superName, Namer.literalPlus, mixinName]); | |
| 33 emitter.needsMixinSupport = true; | 31 emitter.needsMixinSupport = true; |
| 34 } | 32 } |
| 35 | 33 |
| 36 ClassBuilder builder = new ClassBuilder.forClass(classElement, namer); | 34 ClassBuilder builder = new ClassBuilder.forClass(classElement, namer); |
| 37 builder.superName = superName; | 35 builder.superName = superName; |
| 38 emitConstructorsForCSP(cls); | 36 emitConstructorsForCSP(cls); |
| 39 emitFields(cls, builder); | 37 emitFields(cls, builder); |
| 40 emitCheckedClassSetters(cls, builder); | 38 emitCheckedClassSetters(cls, builder); |
| 41 emitClassGettersSettersForCSP(cls, builder); | 39 emitClassGettersSettersForCSP(cls, builder); |
| 42 emitInstanceMembers(cls, builder); | 40 emitInstanceMembers(cls, builder); |
| 43 emitStubs(cls.callStubs, builder); | 41 emitStubs(cls.callStubs, builder); |
| 44 emitStubs(cls.typeVariableReaderStubs, builder); | 42 emitStubs(cls.typeVariableReaderStubs, builder); |
| 45 emitRuntimeTypeInformation(cls, builder); | 43 emitRuntimeTypeInformation(cls, builder); |
| 46 emitNativeInfo(cls, builder); | 44 emitNativeInfo(cls, builder); |
| 47 | 45 |
| 48 if (classElement == backend.helpers.closureClass) { | 46 if (classElement == backend.helpers.closureClass) { |
| 49 // We add a special getter here to allow for tearing off a closure from | 47 // We add a special getter here to allow for tearing off a closure from |
| 50 // itself. | 48 // itself. |
| 51 jsAst.Fun function = js('function() { return this; }'); | 49 jsAst.Fun function = js('function() { return this; }'); |
| 52 jsAst.Name name = namer.getterForMember(Names.call); | 50 jsAst.Name name = namer.getterForMember(Names.call); |
| 53 builder.addProperty(name, function); | 51 builder.addProperty(name, function); |
| 54 } | 52 } |
| 55 | 53 |
| 56 emitClassBuilderWithReflectionData(cls, builder, enclosingBuilder, | 54 emitClassBuilderWithReflectionData( |
| 57 fragment); | 55 cls, builder, enclosingBuilder, fragment); |
| 58 } | 56 } |
| 57 |
| 59 /** | 58 /** |
| 60 * Emits the precompiled constructor when in CSP mode. | 59 * Emits the precompiled constructor when in CSP mode. |
| 61 */ | 60 */ |
| 62 void emitConstructorsForCSP(Class cls) { | 61 void emitConstructorsForCSP(Class cls) { |
| 63 List<jsAst.Name> fieldNames = <jsAst.Name>[]; | 62 List<jsAst.Name> fieldNames = <jsAst.Name>[]; |
| 64 | 63 |
| 65 if (!compiler.options.useContentSecurityPolicy) return; | 64 if (!compiler.options.useContentSecurityPolicy) return; |
| 66 | 65 |
| 67 if (!cls.onlyForRti && !cls.isNative) { | 66 if (!cls.onlyForRti && !cls.isNative) { |
| 68 fieldNames = cls.fields.map((Field field) => field.name).toList(); | 67 fieldNames = cls.fields.map((Field field) => field.name).toList(); |
| 69 } | 68 } |
| 70 | 69 |
| 71 ClassElement classElement = cls.element; | 70 ClassElement classElement = cls.element; |
| 72 | 71 |
| 73 jsAst.Expression constructorAst = | 72 jsAst.Expression constructorAst = |
| 74 _stubGenerator.generateClassConstructor(classElement, fieldNames); | 73 _stubGenerator.generateClassConstructor(classElement, fieldNames); |
| 75 | 74 |
| 76 jsAst.Name constructorName = namer.className(classElement); | 75 jsAst.Name constructorName = namer.className(classElement); |
| 77 OutputUnit outputUnit = | 76 OutputUnit outputUnit = |
| 78 compiler.deferredLoadTask.outputUnitForElement(classElement); | 77 compiler.deferredLoadTask.outputUnitForElement(classElement); |
| 79 emitter.assemblePrecompiledConstructor( | 78 emitter.assemblePrecompiledConstructor( |
| 80 outputUnit, constructorName, constructorAst, fieldNames); | 79 outputUnit, constructorName, constructorAst, fieldNames); |
| 81 } | 80 } |
| 82 | 81 |
| 83 /// Returns `true` if fields added. | 82 /// Returns `true` if fields added. |
| 84 bool emitFields(FieldContainer container, | 83 bool emitFields(FieldContainer container, ClassBuilder builder, |
| 85 ClassBuilder builder, | 84 {bool classIsNative: false, bool emitStatics: false}) { |
| 86 { bool classIsNative: false, | |
| 87 bool emitStatics: false }) { | |
| 88 Iterable<Field> fields; | 85 Iterable<Field> fields; |
| 89 if (container is Class) { | 86 if (container is Class) { |
| 90 if (emitStatics) { | 87 if (emitStatics) { |
| 91 fields = container.staticFieldsForReflection; | 88 fields = container.staticFieldsForReflection; |
| 92 } else if (container.onlyForRti) { | 89 } else if (container.onlyForRti) { |
| 93 return false; | 90 return false; |
| 94 } else { | 91 } else { |
| 95 fields = container.fields; | 92 fields = container.fields; |
| 96 } | 93 } |
| 97 } else { | 94 } else { |
| 98 assert(container is Library); | 95 assert(container is Library); |
| 99 assert(emitStatics); | 96 assert(emitStatics); |
| 100 fields = container.staticFieldsForReflection; | 97 fields = container.staticFieldsForReflection; |
| 101 } | 98 } |
| 102 | 99 |
| 103 var fieldMetadata = []; | 100 var fieldMetadata = []; |
| 104 bool hasMetadata = false; | 101 bool hasMetadata = false; |
| 105 bool fieldsAdded = false; | 102 bool fieldsAdded = false; |
| 106 | 103 |
| 107 for (Field field in fields) { | 104 for (Field field in fields) { |
| 108 FieldElement fieldElement = field.element; | 105 FieldElement fieldElement = field.element; |
| 109 jsAst.Name name = field.name; | 106 jsAst.Name name = field.name; |
| 110 jsAst.Name accessorName = field.accessorName; | 107 jsAst.Name accessorName = field.accessorName; |
| 111 bool needsGetter = field.needsGetter; | 108 bool needsGetter = field.needsGetter; |
| 112 bool needsSetter = field.needsUncheckedSetter; | 109 bool needsSetter = field.needsUncheckedSetter; |
| 113 | 110 |
| 114 // Ignore needsCheckedSetter - that is handled below. | 111 // Ignore needsCheckedSetter - that is handled below. |
| 115 bool needsAccessor = (needsGetter || needsSetter); | 112 bool needsAccessor = (needsGetter || needsSetter); |
| 116 // We need to output the fields for non-native classes so we can auto- | 113 // We need to output the fields for non-native classes so we can auto- |
| 117 // generate the constructor. For native classes there are no | 114 // generate the constructor. For native classes there are no |
| 118 // constructors, so we don't need the fields unless we are generating | 115 // constructors, so we don't need the fields unless we are generating |
| 119 // accessors at runtime. | 116 // accessors at runtime. |
| 120 bool needsFieldsForConstructor = !emitStatics && !classIsNative; | 117 bool needsFieldsForConstructor = !emitStatics && !classIsNative; |
| 121 if (needsFieldsForConstructor || needsAccessor) { | 118 if (needsFieldsForConstructor || needsAccessor) { |
| 122 var metadata = | 119 var metadata = |
| 123 task.metadataCollector.buildMetadataFunction(fieldElement); | 120 task.metadataCollector.buildMetadataFunction(fieldElement); |
| 124 if (metadata != null) { | 121 if (metadata != null) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 136 fieldNameParts.add(name); | 133 fieldNameParts.add(name); |
| 137 } else { | 134 } else { |
| 138 // Emit (possibly renaming) field name so we can add accessors at | 135 // Emit (possibly renaming) field name so we can add accessors at |
| 139 // runtime. | 136 // runtime. |
| 140 if (name != accessorName) { | 137 if (name != accessorName) { |
| 141 fieldNameParts.add(accessorName); | 138 fieldNameParts.add(accessorName); |
| 142 fieldNameParts.add(js.stringPart(':')); | 139 fieldNameParts.add(js.stringPart(':')); |
| 143 } | 140 } |
| 144 fieldNameParts.add(name); | 141 fieldNameParts.add(name); |
| 145 if (field.needsInterceptedGetter) { | 142 if (field.needsInterceptedGetter) { |
| 146 emitter.interceptorEmitter.interceptorInvocationNames.add( | 143 emitter.interceptorEmitter.interceptorInvocationNames |
| 147 namer.getterForElement(fieldElement)); | 144 .add(namer.getterForElement(fieldElement)); |
| 148 } | 145 } |
| 149 // TODO(16168): The setter creator only looks at the getter-name. | 146 // TODO(16168): The setter creator only looks at the getter-name. |
| 150 // Even though the setter could avoid the interceptor convention we | 147 // Even though the setter could avoid the interceptor convention we |
| 151 // currently still need to add the additional argument. | 148 // currently still need to add the additional argument. |
| 152 if (field.needsInterceptedGetter || field.needsInterceptedSetter) { | 149 if (field.needsInterceptedGetter || field.needsInterceptedSetter) { |
| 153 emitter.interceptorEmitter.interceptorInvocationNames.add( | 150 emitter.interceptorEmitter.interceptorInvocationNames |
| 154 namer.setterForElement(fieldElement)); | 151 .add(namer.setterForElement(fieldElement)); |
| 155 } | 152 } |
| 156 | 153 |
| 157 int code = field.getterFlags + (field.setterFlags << 2); | 154 int code = field.getterFlags + (field.setterFlags << 2); |
| 158 if (code == 0) { | 155 if (code == 0) { |
| 159 reporter.internalError(fieldElement, | 156 reporter.internalError( |
| 160 'Field code is 0 ($fieldElement).'); | 157 fieldElement, 'Field code is 0 ($fieldElement).'); |
| 161 } | 158 } |
| 162 fieldNameParts.add( | 159 fieldNameParts.add( |
| 163 js.stringPart(FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE])); | 160 js.stringPart(FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE])); |
| 164 } | 161 } |
| 165 // Fields can only be reflected if their declaring class is reflectable | 162 // Fields can only be reflected if their declaring class is reflectable |
| 166 // (as they are only accessible via [ClassMirror.declarations]). | 163 // (as they are only accessible via [ClassMirror.declarations]). |
| 167 // However, set/get operations can be performed on them, so they are | 164 // However, set/get operations can be performed on them, so they are |
| 168 // reflectable in some sense, which leads to [isAccessibleByReflection] | 165 // reflectable in some sense, which leads to [isAccessibleByReflection] |
| 169 // reporting `true`. | 166 // reporting `true`. |
| 170 if (backend.isAccessibleByReflection(fieldElement)) { | 167 if (backend.isAccessibleByReflection(fieldElement)) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 191 | 188 |
| 192 /// Emits checked setters for fields. | 189 /// Emits checked setters for fields. |
| 193 void emitCheckedClassSetters(Class cls, ClassBuilder builder) { | 190 void emitCheckedClassSetters(Class cls, ClassBuilder builder) { |
| 194 if (cls.onlyForRti) return; | 191 if (cls.onlyForRti) return; |
| 195 | 192 |
| 196 for (StubMethod method in cls.checkedSetters) { | 193 for (StubMethod method in cls.checkedSetters) { |
| 197 Element member = method.element; | 194 Element member = method.element; |
| 198 assert(member != null); | 195 assert(member != null); |
| 199 jsAst.Expression code = method.code; | 196 jsAst.Expression code = method.code; |
| 200 jsAst.Name setterName = method.name; | 197 jsAst.Name setterName = method.name; |
| 201 compiler.dumpInfoTask.registerElementAst(member, | 198 compiler.dumpInfoTask |
| 202 builder.addProperty(setterName, code)); | 199 .registerElementAst(member, builder.addProperty(setterName, code)); |
| 203 generateReflectionDataForFieldGetterOrSetter( | 200 generateReflectionDataForFieldGetterOrSetter(member, setterName, builder, |
| 204 member, setterName, builder, isGetter: false); | 201 isGetter: false); |
| 205 } | 202 } |
| 206 } | 203 } |
| 207 | 204 |
| 208 /// Emits getters/setters for fields if compiling in CSP mode. | 205 /// Emits getters/setters for fields if compiling in CSP mode. |
| 209 void emitClassGettersSettersForCSP(Class cls, ClassBuilder builder) { | 206 void emitClassGettersSettersForCSP(Class cls, ClassBuilder builder) { |
| 210 | |
| 211 if (!compiler.options.useContentSecurityPolicy || cls.onlyForRti) return; | 207 if (!compiler.options.useContentSecurityPolicy || cls.onlyForRti) return; |
| 212 | 208 |
| 213 for (Field field in cls.fields) { | 209 for (Field field in cls.fields) { |
| 214 Element member = field.element; | 210 Element member = field.element; |
| 215 reporter.withCurrentElement(member, () { | 211 reporter.withCurrentElement(member, () { |
| 216 if (field.needsGetter) { | 212 if (field.needsGetter) { |
| 217 emitGetterForCSP(member, field.name, field.accessorName, builder); | 213 emitGetterForCSP(member, field.name, field.accessorName, builder); |
| 218 } | 214 } |
| 219 if (field.needsUncheckedSetter) { | 215 if (field.needsUncheckedSetter) { |
| 220 emitSetterForCSP(member, field.name, field.accessorName, builder); | 216 emitSetterForCSP(member, field.name, field.accessorName, builder); |
| 221 } | 217 } |
| 222 }); | 218 }); |
| 223 } | 219 } |
| 224 } | 220 } |
| 225 | 221 |
| 226 void emitStubs(Iterable<StubMethod> stubs, ClassBuilder builder) { | 222 void emitStubs(Iterable<StubMethod> stubs, ClassBuilder builder) { |
| 227 for (Method method in stubs) { | 223 for (Method method in stubs) { |
| 228 jsAst.Property property = builder.addProperty(method.name, method.code); | 224 jsAst.Property property = builder.addProperty(method.name, method.code); |
| 229 compiler.dumpInfoTask.registerElementAst(method.element, property); | 225 compiler.dumpInfoTask.registerElementAst(method.element, property); |
| 230 } | 226 } |
| 231 } | 227 } |
| 232 | 228 |
| 233 /** | 229 /** |
| 234 * Documentation wanted -- johnniwinther | 230 * Documentation wanted -- johnniwinther |
| 235 * | 231 * |
| 236 * Invariant: [classElement] must be a declaration element. | 232 * Invariant: [classElement] must be a declaration element. |
| 237 */ | 233 */ |
| 238 void emitInstanceMembers(Class cls, | 234 void emitInstanceMembers(Class cls, ClassBuilder builder) { |
| 239 ClassBuilder builder) { | |
| 240 ClassElement classElement = cls.element; | 235 ClassElement classElement = cls.element; |
| 241 assert(invariant(classElement, classElement.isDeclaration)); | 236 assert(invariant(classElement, classElement.isDeclaration)); |
| 242 | 237 |
| 243 if (cls.onlyForRti || cls.isMixinApplication) return; | 238 if (cls.onlyForRti || cls.isMixinApplication) return; |
| 244 | 239 |
| 245 // TODO(herhut): This is a no-op. Should it be removed? | 240 // TODO(herhut): This is a no-op. Should it be removed? |
| 246 for (Field field in cls.fields) { | 241 for (Field field in cls.fields) { |
| 247 emitter.containerBuilder.addMemberField(field, builder); | 242 emitter.containerBuilder.addMemberField(field, builder); |
| 248 } | 243 } |
| 249 | 244 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 274 } | 269 } |
| 275 } | 270 } |
| 276 | 271 |
| 277 void emitNativeInfo(Class cls, ClassBuilder builder) { | 272 void emitNativeInfo(Class cls, ClassBuilder builder) { |
| 278 jsAst.Expression nativeInfo = NativeGenerator.encodeNativeInfo(cls); | 273 jsAst.Expression nativeInfo = NativeGenerator.encodeNativeInfo(cls); |
| 279 if (nativeInfo != null) { | 274 if (nativeInfo != null) { |
| 280 builder.addPropertyByName(namer.nativeSpecProperty, nativeInfo); | 275 builder.addPropertyByName(namer.nativeSpecProperty, nativeInfo); |
| 281 } | 276 } |
| 282 } | 277 } |
| 283 | 278 |
| 284 void emitClassBuilderWithReflectionData(Class cls, | 279 void emitClassBuilderWithReflectionData(Class cls, ClassBuilder classBuilder, |
| 285 ClassBuilder classBuilder, | 280 ClassBuilder enclosingBuilder, Fragment fragment) { |
| 286 ClassBuilder enclosingBuilder, | |
| 287 Fragment fragment) { | |
| 288 ClassElement classElement = cls.element; | 281 ClassElement classElement = cls.element; |
| 289 jsAst.Name className = cls.name; | 282 jsAst.Name className = cls.name; |
| 290 | 283 |
| 291 var metadata = task.metadataCollector.buildMetadataFunction(classElement); | 284 var metadata = task.metadataCollector.buildMetadataFunction(classElement); |
| 292 if (metadata != null) { | 285 if (metadata != null) { |
| 293 classBuilder.addPropertyByName("@", metadata); | 286 classBuilder.addPropertyByName("@", metadata); |
| 294 } | 287 } |
| 295 | 288 |
| 296 if (backend.isAccessibleByReflection(classElement)) { | 289 if (backend.isAccessibleByReflection(classElement)) { |
| 297 List<DartType> typeVars = classElement.typeVariables; | 290 List<DartType> typeVars = classElement.typeVariables; |
| 298 Iterable typeVariableProperties = emitter.typeVariableHandler | 291 Iterable typeVariableProperties = |
| 299 .typeVariablesOf(classElement); | 292 emitter.typeVariableHandler.typeVariablesOf(classElement); |
| 300 | 293 |
| 301 ClassElement superclass = classElement.superclass; | 294 ClassElement superclass = classElement.superclass; |
| 302 bool hasSuper = superclass != null; | 295 bool hasSuper = superclass != null; |
| 303 if ((!typeVariableProperties.isEmpty && !hasSuper) || | 296 if ((!typeVariableProperties.isEmpty && !hasSuper) || |
| 304 (hasSuper && !equalElements(superclass.typeVariables, typeVars))) { | 297 (hasSuper && !equalElements(superclass.typeVariables, typeVars))) { |
| 305 classBuilder.addPropertyByName('<>', | 298 classBuilder.addPropertyByName( |
| 306 new jsAst.ArrayInitializer(typeVariableProperties.toList())); | 299 '<>', new jsAst.ArrayInitializer(typeVariableProperties.toList())); |
| 307 } | 300 } |
| 308 } | 301 } |
| 309 | 302 |
| 310 List<jsAst.Property> statics = new List<jsAst.Property>(); | 303 List<jsAst.Property> statics = new List<jsAst.Property>(); |
| 311 ClassBuilder staticsBuilder = | 304 ClassBuilder staticsBuilder = |
| 312 new ClassBuilder.forStatics(classElement, namer); | 305 new ClassBuilder.forStatics(classElement, namer); |
| 313 if (emitFields(cls, staticsBuilder, emitStatics: true)) { | 306 if (emitFields(cls, staticsBuilder, emitStatics: true)) { |
| 314 jsAst.ObjectInitializer initializer = | 307 jsAst.ObjectInitializer initializer = |
| 315 staticsBuilder.toObjectInitializer(); | 308 staticsBuilder.toObjectInitializer(); |
| 316 compiler.dumpInfoTask.registerElementAst(classElement, | 309 compiler.dumpInfoTask.registerElementAst(classElement, initializer); |
| 317 initializer); | |
| 318 jsAst.Node property = initializer.properties.single; | 310 jsAst.Node property = initializer.properties.single; |
| 319 compiler.dumpInfoTask.registerElementAst(classElement, property); | 311 compiler.dumpInfoTask.registerElementAst(classElement, property); |
| 320 statics.add(property); | 312 statics.add(property); |
| 321 } | 313 } |
| 322 | 314 |
| 323 // TODO(herhut): Do not grab statics out of the properties. | 315 // TODO(herhut): Do not grab statics out of the properties. |
| 324 ClassBuilder classProperties = | 316 ClassBuilder classProperties = |
| 325 emitter.elementDescriptors[fragment].remove(classElement); | 317 emitter.elementDescriptors[fragment].remove(classElement); |
| 326 if (classProperties != null) { | 318 if (classProperties != null) { |
| 327 statics.addAll(classProperties.properties); | 319 statics.addAll(classProperties.properties); |
| 328 } | 320 } |
| 329 | 321 |
| 330 if (!statics.isEmpty) { | 322 if (!statics.isEmpty) { |
| 331 classBuilder.addProperty( | 323 classBuilder.addProperty( |
| 332 namer.staticsPropertyName, // 'static' or its minified name. | 324 namer.staticsPropertyName, // 'static' or its minified name. |
| 333 new jsAst.ObjectInitializer(statics, isOneLiner: false)); | 325 new jsAst.ObjectInitializer(statics, isOneLiner: false)); |
| 334 } | 326 } |
| 335 | 327 |
| 336 // TODO(ahe): This method (generateClass) should return a jsAst.Expression. | 328 // TODO(ahe): This method (generateClass) should return a jsAst.Expression. |
| 337 jsAst.ObjectInitializer propertyValue = | 329 jsAst.ObjectInitializer propertyValue = classBuilder.toObjectInitializer(); |
| 338 classBuilder.toObjectInitializer(); | 330 compiler.dumpInfoTask |
| 339 compiler.dumpInfoTask.registerElementAst(classBuilder.element, propertyValue
); | 331 .registerElementAst(classBuilder.element, propertyValue); |
| 340 enclosingBuilder.addProperty(className, propertyValue); | 332 enclosingBuilder.addProperty(className, propertyValue); |
| 341 | 333 |
| 342 String reflectionName = emitter.getReflectionName(classElement, className); | 334 String reflectionName = emitter.getReflectionName(classElement, className); |
| 343 if (reflectionName != null) { | 335 if (reflectionName != null) { |
| 344 if (!backend.isAccessibleByReflection(classElement) || cls.onlyForRti) { | 336 if (!backend.isAccessibleByReflection(classElement) || cls.onlyForRti) { |
| 345 // TODO(herhut): Fix use of reflection name here. | 337 // TODO(herhut): Fix use of reflection name here. |
| 346 enclosingBuilder.addPropertyByName("+$reflectionName", js.number(0)); | 338 enclosingBuilder.addPropertyByName("+$reflectionName", js.number(0)); |
| 347 } else { | 339 } else { |
| 348 List<jsAst.Expression> types = <jsAst.Expression>[]; | 340 List<jsAst.Expression> types = <jsAst.Expression>[]; |
| 349 if (classElement.supertype != null) { | 341 if (classElement.supertype != null) { |
| 350 types.add(task.metadataCollector.reifyType(classElement.supertype)); | 342 types.add(task.metadataCollector.reifyType(classElement.supertype)); |
| 351 } | 343 } |
| 352 for (DartType interface in classElement.interfaces) { | 344 for (DartType interface in classElement.interfaces) { |
| 353 types.add(task.metadataCollector.reifyType(interface)); | 345 types.add(task.metadataCollector.reifyType(interface)); |
| 354 } | 346 } |
| 355 // TODO(herhut): Fix use of reflection name here. | 347 // TODO(herhut): Fix use of reflection name here. |
| 356 enclosingBuilder.addPropertyByName("+$reflectionName", | 348 enclosingBuilder.addPropertyByName( |
| 357 new jsAst.ArrayInitializer(types)); | 349 "+$reflectionName", new jsAst.ArrayInitializer(types)); |
| 358 } | 350 } |
| 359 } | 351 } |
| 360 } | 352 } |
| 361 | 353 |
| 362 void recordMangledField(Element member, | 354 void recordMangledField( |
| 363 jsAst.Name accessorName, | 355 Element member, jsAst.Name accessorName, String memberName) { |
| 364 String memberName) { | |
| 365 if (!backend.shouldRetainGetter(member)) return; | 356 if (!backend.shouldRetainGetter(member)) return; |
| 366 String previousName; | 357 String previousName; |
| 367 if (member.isInstanceMember) { | 358 if (member.isInstanceMember) { |
| 368 previousName = emitter.mangledFieldNames.putIfAbsent( | 359 previousName = emitter.mangledFieldNames |
| 369 namer.deriveGetterName(accessorName), | 360 .putIfAbsent(namer.deriveGetterName(accessorName), () => memberName); |
| 370 () => memberName); | |
| 371 } else { | 361 } else { |
| 372 previousName = emitter.mangledGlobalFieldNames.putIfAbsent( | 362 previousName = emitter.mangledGlobalFieldNames |
| 373 accessorName, | 363 .putIfAbsent(accessorName, () => memberName); |
| 374 () => memberName); | |
| 375 } | 364 } |
| 376 assert(invariant(member, previousName == memberName, | 365 assert(invariant(member, previousName == memberName, |
| 377 message: '$previousName != ${memberName}')); | 366 message: '$previousName != ${memberName}')); |
| 378 } | 367 } |
| 379 | 368 |
| 380 void emitGetterForCSP(Element member, jsAst.Name fieldName, | 369 void emitGetterForCSP(Element member, jsAst.Name fieldName, |
| 381 jsAst.Name accessorName, | 370 jsAst.Name accessorName, ClassBuilder builder) { |
| 382 ClassBuilder builder) { | |
| 383 jsAst.Expression function = | 371 jsAst.Expression function = |
| 384 _stubGenerator.generateGetter(member, fieldName); | 372 _stubGenerator.generateGetter(member, fieldName); |
| 385 | 373 |
| 386 jsAst.Name getterName = namer.deriveGetterName(accessorName); | 374 jsAst.Name getterName = namer.deriveGetterName(accessorName); |
| 387 ClassElement cls = member.enclosingClass; | 375 ClassElement cls = member.enclosingClass; |
| 388 jsAst.Name className = namer.className(cls); | 376 jsAst.Name className = namer.className(cls); |
| 389 OutputUnit outputUnit = | 377 OutputUnit outputUnit = |
| 390 compiler.deferredLoadTask.outputUnitForElement(member); | 378 compiler.deferredLoadTask.outputUnitForElement(member); |
| 391 emitter.cspPrecompiledFunctionFor(outputUnit).add( | 379 emitter |
| 392 js('#.prototype.# = #', [className, getterName, function])); | 380 .cspPrecompiledFunctionFor(outputUnit) |
| 381 .add(js('#.prototype.# = #', [className, getterName, function])); |
| 393 if (backend.isAccessibleByReflection(member)) { | 382 if (backend.isAccessibleByReflection(member)) { |
| 394 emitter.cspPrecompiledFunctionFor(outputUnit).add( | 383 emitter.cspPrecompiledFunctionFor(outputUnit).add(js( |
| 395 js('#.prototype.#.${namer.reflectableField} = 1', | 384 '#.prototype.#.${namer.reflectableField} = 1', |
| 396 [className, getterName])); | 385 [className, getterName])); |
| 397 } | 386 } |
| 398 } | 387 } |
| 399 | 388 |
| 400 void emitSetterForCSP(Element member, jsAst.Name fieldName, | 389 void emitSetterForCSP(Element member, jsAst.Name fieldName, |
| 401 jsAst.Name accessorName, | 390 jsAst.Name accessorName, ClassBuilder builder) { |
| 402 ClassBuilder builder) { | |
| 403 jsAst.Expression function = | 391 jsAst.Expression function = |
| 404 _stubGenerator.generateSetter(member, fieldName); | 392 _stubGenerator.generateSetter(member, fieldName); |
| 405 | 393 |
| 406 jsAst.Name setterName = namer.deriveSetterName(accessorName); | 394 jsAst.Name setterName = namer.deriveSetterName(accessorName); |
| 407 ClassElement cls = member.enclosingClass; | 395 ClassElement cls = member.enclosingClass; |
| 408 jsAst.Name className = namer.className(cls); | 396 jsAst.Name className = namer.className(cls); |
| 409 OutputUnit outputUnit = | 397 OutputUnit outputUnit = |
| 410 compiler.deferredLoadTask.outputUnitForElement(member); | 398 compiler.deferredLoadTask.outputUnitForElement(member); |
| 411 emitter.cspPrecompiledFunctionFor(outputUnit).add( | 399 emitter |
| 412 js('#.prototype.# = #', [className, setterName, function])); | 400 .cspPrecompiledFunctionFor(outputUnit) |
| 401 .add(js('#.prototype.# = #', [className, setterName, function])); |
| 413 if (backend.isAccessibleByReflection(member)) { | 402 if (backend.isAccessibleByReflection(member)) { |
| 414 emitter.cspPrecompiledFunctionFor(outputUnit).add( | 403 emitter.cspPrecompiledFunctionFor(outputUnit).add(js( |
| 415 js('#.prototype.#.${namer.reflectableField} = 1', | 404 '#.prototype.#.${namer.reflectableField} = 1', |
| 416 [className, setterName])); | 405 [className, setterName])); |
| 417 } | 406 } |
| 418 } | 407 } |
| 419 | 408 |
| 420 void generateReflectionDataForFieldGetterOrSetter(Element member, | 409 void generateReflectionDataForFieldGetterOrSetter( |
| 421 jsAst.Name name, | 410 Element member, jsAst.Name name, ClassBuilder builder, |
| 422 ClassBuilder builder, | 411 {bool isGetter}) { |
| 423 {bool isGetter}) { | |
| 424 Selector selector = isGetter | 412 Selector selector = isGetter |
| 425 ? new Selector.getter( | 413 ? new Selector.getter(new Name(member.name, member.library)) |
| 426 new Name(member.name, member.library)) | |
| 427 : new Selector.setter( | 414 : new Selector.setter( |
| 428 new Name(member.name, member.library, isSetter: true)); | 415 new Name(member.name, member.library, isSetter: true)); |
| 429 String reflectionName = emitter.getReflectionName(selector, name); | 416 String reflectionName = emitter.getReflectionName(selector, name); |
| 430 if (reflectionName != null) { | 417 if (reflectionName != null) { |
| 431 var reflectable = | 418 var reflectable = |
| 432 js(backend.isAccessibleByReflection(member) ? '1' : '0'); | 419 js(backend.isAccessibleByReflection(member) ? '1' : '0'); |
| 433 builder.addPropertyByName('+$reflectionName', reflectable); | 420 builder.addPropertyByName('+$reflectionName', reflectable); |
| 434 } | 421 } |
| 435 } | 422 } |
| 436 } | 423 } |
| OLD | NEW |