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 library dart2js.js_emitter.full_emitter.class_emitter; | 5 library dart2js.js_emitter.full_emitter.class_emitter; |
6 | 6 |
7 import '../../common.dart'; | 7 import '../../common.dart'; |
8 import '../../common/names.dart' show Names; | 8 import '../../common/names.dart' show Names; |
9 import '../../elements/resolution_types.dart' show ResolutionDartType; | 9 import '../../elements/resolution_types.dart' show ResolutionDartType; |
10 import '../../deferred_load.dart' show OutputUnit; | 10 import '../../deferred_load.dart' show OutputUnit; |
11 import '../../elements/elements.dart' | 11 import '../../elements/elements.dart' |
12 show ClassElement, Element, FieldElement, MemberElement, Name; | 12 show ClassElement, FieldElement, MemberElement, Name; |
13 import '../../js/js.dart' as jsAst; | 13 import '../../js/js.dart' as jsAst; |
14 import '../../js/js.dart' show js; | 14 import '../../js/js.dart' show js; |
15 import '../../js_backend/js_backend.dart' show CompoundName, Namer; | 15 import '../../js_backend/js_backend.dart' show CompoundName, Namer; |
16 import '../../universe/selector.dart' show Selector; | 16 import '../../universe/selector.dart' show Selector; |
17 import '../../util/util.dart' show equalElements; | 17 import '../../util/util.dart' show equalElements; |
18 import '../../world.dart' show ClosedWorld; | 18 import '../../world.dart' show ClosedWorld; |
19 import '../js_emitter.dart' hide Emitter, EmitterFactory; | 19 import '../js_emitter.dart' hide Emitter, EmitterFactory; |
20 import '../model.dart'; | 20 import '../model.dart'; |
21 import 'emitter.dart'; | 21 import 'emitter.dart'; |
22 | 22 |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
133 | 133 |
134 // Ignore needsCheckedSetter - that is handled below. | 134 // Ignore needsCheckedSetter - that is handled below. |
135 bool needsAccessor = (needsGetter || needsSetter); | 135 bool needsAccessor = (needsGetter || needsSetter); |
136 // We need to output the fields for non-native classes so we can auto- | 136 // We need to output the fields for non-native classes so we can auto- |
137 // generate the constructor. For native classes there are no | 137 // generate the constructor. For native classes there are no |
138 // constructors, so we don't need the fields unless we are generating | 138 // constructors, so we don't need the fields unless we are generating |
139 // accessors at runtime. | 139 // accessors at runtime. |
140 bool needsFieldsForConstructor = !emitStatics && !classIsNative; | 140 bool needsFieldsForConstructor = !emitStatics && !classIsNative; |
141 if (needsFieldsForConstructor || needsAccessor) { | 141 if (needsFieldsForConstructor || needsAccessor) { |
142 var metadata = | 142 var metadata = |
143 task.metadataCollector.buildMetadataFunction(fieldElement); | 143 task.metadataCollector.buildFieldMetadataFunction(fieldElement); |
144 if (metadata != null) { | 144 if (metadata != null) { |
145 hasMetadata = true; | 145 hasMetadata = true; |
146 } else { | 146 } else { |
147 metadata = new jsAst.LiteralNull(); | 147 metadata = new jsAst.LiteralNull(); |
148 } | 148 } |
149 fieldMetadata.add(metadata); | 149 fieldMetadata.add(metadata); |
150 recordMangledField(fieldElement, accessorName, | 150 recordMangledField(fieldElement, accessorName, |
151 namer.privateName(fieldElement.memberName)); | 151 namer.privateName(fieldElement.memberName)); |
152 List<jsAst.Literal> fieldNameParts = <jsAst.Literal>[]; | 152 List<jsAst.Literal> fieldNameParts = <jsAst.Literal>[]; |
153 if (!needsAccessor) { | 153 if (!needsAccessor) { |
(...skipping 26 matching lines...) Expand all Loading... |
180 fieldElement, 'Field code is 0 ($fieldElement).'); | 180 fieldElement, 'Field code is 0 ($fieldElement).'); |
181 } | 181 } |
182 fieldNameParts.add( | 182 fieldNameParts.add( |
183 js.stringPart(FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE])); | 183 js.stringPart(FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE])); |
184 } | 184 } |
185 // Fields can only be reflected if their declaring class is reflectable | 185 // Fields can only be reflected if their declaring class is reflectable |
186 // (as they are only accessible via [ClassMirror.declarations]). | 186 // (as they are only accessible via [ClassMirror.declarations]). |
187 // However, set/get operations can be performed on them, so they are | 187 // However, set/get operations can be performed on them, so they are |
188 // reflectable in some sense, which leads to [isAccessibleByReflection] | 188 // reflectable in some sense, which leads to [isAccessibleByReflection] |
189 // reporting `true`. | 189 // reporting `true`. |
190 if (backend.mirrorsData.isAccessibleByReflection(fieldElement)) { | 190 if (backend.mirrorsData.isMemberAccessibleByReflection(fieldElement)) { |
191 fieldNameParts.add(new jsAst.LiteralString('-')); | 191 fieldNameParts.add(new jsAst.LiteralString('-')); |
192 if (fieldElement.isTopLevel || | 192 if (fieldElement.isTopLevel || |
193 backend.mirrorsData | 193 backend.mirrorsData |
194 .isAccessibleByReflection(fieldElement.enclosingClass)) { | 194 .isClassAccessibleByReflection(fieldElement.enclosingClass)) { |
195 ResolutionDartType type = fieldElement.type; | 195 ResolutionDartType type = fieldElement.type; |
196 fieldNameParts.add(task.metadataCollector.reifyType(type)); | 196 fieldNameParts.add(task.metadataCollector.reifyType(type)); |
197 } | 197 } |
198 } | 198 } |
199 jsAst.Literal fieldNameAst = js.concatenateStrings(fieldNameParts); | 199 jsAst.Literal fieldNameAst = js.concatenateStrings(fieldNameParts); |
200 builder.addField(fieldNameAst); | 200 builder.addField(fieldNameAst); |
201 // Add 1 because adding a field to the class also requires a comma | 201 // Add 1 because adding a field to the class also requires a comma |
202 compiler.dumpInfoTask.registerElementAst(fieldElement, fieldNameAst); | 202 compiler.dumpInfoTask.registerElementAst(fieldElement, fieldNameAst); |
203 fieldsAdded = true; | 203 fieldsAdded = true; |
204 } | 204 } |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 if (nativeInfo != null) { | 297 if (nativeInfo != null) { |
298 builder.addPropertyByName(namer.nativeSpecProperty, nativeInfo); | 298 builder.addPropertyByName(namer.nativeSpecProperty, nativeInfo); |
299 } | 299 } |
300 } | 300 } |
301 | 301 |
302 void emitClassBuilderWithReflectionData(Class cls, ClassBuilder classBuilder, | 302 void emitClassBuilderWithReflectionData(Class cls, ClassBuilder classBuilder, |
303 ClassBuilder enclosingBuilder, Fragment fragment) { | 303 ClassBuilder enclosingBuilder, Fragment fragment) { |
304 ClassElement classElement = cls.element; | 304 ClassElement classElement = cls.element; |
305 jsAst.Name className = cls.name; | 305 jsAst.Name className = cls.name; |
306 | 306 |
307 var metadata = task.metadataCollector.buildMetadataFunction(classElement); | 307 var metadata = |
| 308 task.metadataCollector.buildClassMetadataFunction(classElement); |
308 if (metadata != null) { | 309 if (metadata != null) { |
309 classBuilder.addPropertyByName("@", metadata); | 310 classBuilder.addPropertyByName("@", metadata); |
310 } | 311 } |
311 | 312 |
312 if (backend.mirrorsData.isAccessibleByReflection(classElement)) { | 313 if (backend.mirrorsData.isClassAccessibleByReflection(classElement)) { |
313 List<ResolutionDartType> typeVars = classElement.typeVariables; | 314 List<ResolutionDartType> typeVars = classElement.typeVariables; |
314 Iterable typeVariableProperties = | 315 Iterable typeVariableProperties = |
315 emitter.typeVariableCodegenAnalysis.typeVariablesOf(classElement); | 316 emitter.typeVariableCodegenAnalysis.typeVariablesOf(classElement); |
316 | 317 |
317 ClassElement superclass = classElement.superclass; | 318 ClassElement superclass = classElement.superclass; |
318 bool hasSuper = superclass != null; | 319 bool hasSuper = superclass != null; |
319 if ((!typeVariableProperties.isEmpty && !hasSuper) || | 320 if ((!typeVariableProperties.isEmpty && !hasSuper) || |
320 (hasSuper && !equalElements(superclass.typeVariables, typeVars))) { | 321 (hasSuper && !equalElements(superclass.typeVariables, typeVars))) { |
321 classBuilder.addPropertyByName( | 322 classBuilder.addPropertyByName( |
322 '<>', new jsAst.ArrayInitializer(typeVariableProperties.toList())); | 323 '<>', new jsAst.ArrayInitializer(typeVariableProperties.toList())); |
(...skipping 26 matching lines...) Expand all Loading... |
349 } | 350 } |
350 | 351 |
351 // TODO(ahe): This method (generateClass) should return a jsAst.Expression. | 352 // TODO(ahe): This method (generateClass) should return a jsAst.Expression. |
352 jsAst.ObjectInitializer propertyValue = classBuilder.toObjectInitializer(); | 353 jsAst.ObjectInitializer propertyValue = classBuilder.toObjectInitializer(); |
353 compiler.dumpInfoTask | 354 compiler.dumpInfoTask |
354 .registerElementAst(classBuilder.element, propertyValue); | 355 .registerElementAst(classBuilder.element, propertyValue); |
355 enclosingBuilder.addProperty(className, propertyValue); | 356 enclosingBuilder.addProperty(className, propertyValue); |
356 | 357 |
357 String reflectionName = emitter.getReflectionName(classElement, className); | 358 String reflectionName = emitter.getReflectionName(classElement, className); |
358 if (reflectionName != null) { | 359 if (reflectionName != null) { |
359 if (!backend.mirrorsData.isAccessibleByReflection(classElement) || | 360 if (!backend.mirrorsData.isClassAccessibleByReflection(classElement) || |
360 cls.onlyForRti) { | 361 cls.onlyForRti) { |
361 // TODO(herhut): Fix use of reflection name here. | 362 // TODO(herhut): Fix use of reflection name here. |
362 enclosingBuilder.addPropertyByName("+$reflectionName", js.number(0)); | 363 enclosingBuilder.addPropertyByName("+$reflectionName", js.number(0)); |
363 } else { | 364 } else { |
364 List<jsAst.Expression> types = <jsAst.Expression>[]; | 365 List<jsAst.Expression> types = <jsAst.Expression>[]; |
365 if (classElement.supertype != null) { | 366 if (classElement.supertype != null) { |
366 types.add(task.metadataCollector.reifyType(classElement.supertype)); | 367 types.add(task.metadataCollector.reifyType(classElement.supertype)); |
367 } | 368 } |
368 for (ResolutionDartType interface in classElement.interfaces) { | 369 for (ResolutionDartType interface in classElement.interfaces) { |
369 types.add(task.metadataCollector.reifyType(interface)); | 370 types.add(task.metadataCollector.reifyType(interface)); |
370 } | 371 } |
371 // TODO(herhut): Fix use of reflection name here. | 372 // TODO(herhut): Fix use of reflection name here. |
372 enclosingBuilder.addPropertyByName( | 373 enclosingBuilder.addPropertyByName( |
373 "+$reflectionName", new jsAst.ArrayInitializer(types)); | 374 "+$reflectionName", new jsAst.ArrayInitializer(types)); |
374 } | 375 } |
375 } | 376 } |
376 } | 377 } |
377 | 378 |
378 void recordMangledField( | 379 void recordMangledField( |
379 Element member, jsAst.Name accessorName, String memberName) { | 380 FieldElement member, jsAst.Name accessorName, String memberName) { |
380 if (!backend.mirrorsData.shouldRetainGetter(member)) return; | 381 if (!backend.mirrorsData.shouldRetainGetter(member)) return; |
381 String previousName; | 382 String previousName; |
382 if (member.isInstanceMember) { | 383 if (member.isInstanceMember) { |
383 previousName = emitter.mangledFieldNames | 384 previousName = emitter.mangledFieldNames |
384 .putIfAbsent(namer.deriveGetterName(accessorName), () => memberName); | 385 .putIfAbsent(namer.deriveGetterName(accessorName), () => memberName); |
385 } else { | 386 } else { |
386 previousName = emitter.mangledGlobalFieldNames | 387 previousName = emitter.mangledGlobalFieldNames |
387 .putIfAbsent(accessorName, () => memberName); | 388 .putIfAbsent(accessorName, () => memberName); |
388 } | 389 } |
389 assert(invariant(member, previousName == memberName, | 390 assert(invariant(member, previousName == memberName, |
390 message: '$previousName != ${memberName}')); | 391 message: '$previousName != ${memberName}')); |
391 } | 392 } |
392 | 393 |
393 void emitGetterForCSP(FieldElement member, jsAst.Name fieldName, | 394 void emitGetterForCSP(FieldElement member, jsAst.Name fieldName, |
394 jsAst.Name accessorName, ClassBuilder builder) { | 395 jsAst.Name accessorName, ClassBuilder builder) { |
395 jsAst.Expression function = | 396 jsAst.Expression function = |
396 _stubGenerator.generateGetter(member, fieldName); | 397 _stubGenerator.generateGetter(member, fieldName); |
397 | 398 |
398 jsAst.Name getterName = namer.deriveGetterName(accessorName); | 399 jsAst.Name getterName = namer.deriveGetterName(accessorName); |
399 ClassElement cls = member.enclosingClass; | 400 ClassElement cls = member.enclosingClass; |
400 jsAst.Name className = namer.className(cls); | 401 jsAst.Name className = namer.className(cls); |
401 OutputUnit outputUnit = | 402 OutputUnit outputUnit = |
402 compiler.deferredLoadTask.outputUnitForElement(member); | 403 compiler.deferredLoadTask.outputUnitForElement(member); |
403 emitter | 404 emitter |
404 .cspPrecompiledFunctionFor(outputUnit) | 405 .cspPrecompiledFunctionFor(outputUnit) |
405 .add(js('#.prototype.# = #', [className, getterName, function])); | 406 .add(js('#.prototype.# = #', [className, getterName, function])); |
406 if (backend.mirrorsData.isAccessibleByReflection(member)) { | 407 if (backend.mirrorsData.isMemberAccessibleByReflection(member)) { |
407 emitter.cspPrecompiledFunctionFor(outputUnit).add(js( | 408 emitter.cspPrecompiledFunctionFor(outputUnit).add(js( |
408 '#.prototype.#.${namer.reflectableField} = 1', | 409 '#.prototype.#.${namer.reflectableField} = 1', |
409 [className, getterName])); | 410 [className, getterName])); |
410 } | 411 } |
411 } | 412 } |
412 | 413 |
413 void emitSetterForCSP(FieldElement member, jsAst.Name fieldName, | 414 void emitSetterForCSP(FieldElement member, jsAst.Name fieldName, |
414 jsAst.Name accessorName, ClassBuilder builder) { | 415 jsAst.Name accessorName, ClassBuilder builder) { |
415 jsAst.Expression function = | 416 jsAst.Expression function = |
416 _stubGenerator.generateSetter(member, fieldName); | 417 _stubGenerator.generateSetter(member, fieldName); |
417 | 418 |
418 jsAst.Name setterName = namer.deriveSetterName(accessorName); | 419 jsAst.Name setterName = namer.deriveSetterName(accessorName); |
419 ClassElement cls = member.enclosingClass; | 420 ClassElement cls = member.enclosingClass; |
420 jsAst.Name className = namer.className(cls); | 421 jsAst.Name className = namer.className(cls); |
421 OutputUnit outputUnit = | 422 OutputUnit outputUnit = |
422 compiler.deferredLoadTask.outputUnitForElement(member); | 423 compiler.deferredLoadTask.outputUnitForElement(member); |
423 emitter | 424 emitter |
424 .cspPrecompiledFunctionFor(outputUnit) | 425 .cspPrecompiledFunctionFor(outputUnit) |
425 .add(js('#.prototype.# = #', [className, setterName, function])); | 426 .add(js('#.prototype.# = #', [className, setterName, function])); |
426 if (backend.mirrorsData.isAccessibleByReflection(member)) { | 427 if (backend.mirrorsData.isMemberAccessibleByReflection(member)) { |
427 emitter.cspPrecompiledFunctionFor(outputUnit).add(js( | 428 emitter.cspPrecompiledFunctionFor(outputUnit).add(js( |
428 '#.prototype.#.${namer.reflectableField} = 1', | 429 '#.prototype.#.${namer.reflectableField} = 1', |
429 [className, setterName])); | 430 [className, setterName])); |
430 } | 431 } |
431 } | 432 } |
432 | 433 |
433 void generateReflectionDataForFieldGetterOrSetter( | 434 void generateReflectionDataForFieldGetterOrSetter( |
434 Element member, jsAst.Name name, ClassBuilder builder, | 435 MemberElement member, jsAst.Name name, ClassBuilder builder, |
435 {bool isGetter}) { | 436 {bool isGetter}) { |
436 Selector selector = isGetter | 437 Selector selector = isGetter |
437 ? new Selector.getter(new Name(member.name, member.library)) | 438 ? new Selector.getter(new Name(member.name, member.library)) |
438 : new Selector.setter( | 439 : new Selector.setter( |
439 new Name(member.name, member.library, isSetter: true)); | 440 new Name(member.name, member.library, isSetter: true)); |
440 String reflectionName = emitter.getReflectionName(selector, name); | 441 String reflectionName = emitter.getReflectionName(selector, name); |
441 if (reflectionName != null) { | 442 if (reflectionName != null) { |
442 var reflectable = | 443 var reflectable = js( |
443 js(backend.mirrorsData.isAccessibleByReflection(member) ? '1' : '0'); | 444 backend.mirrorsData.isMemberAccessibleByReflection(member) |
| 445 ? '1' |
| 446 : '0'); |
444 builder.addPropertyByName('+$reflectionName', reflectable); | 447 builder.addPropertyByName('+$reflectionName', reflectable); |
445 } | 448 } |
446 } | 449 } |
447 } | 450 } |
OLD | NEW |