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 |