| 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 |