| 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; | 5 part of dart2js.js_emitter; |
| 6 | 6 |
| 7 class ClassEmitter extends CodeEmitterHelper { | 7 class ClassEmitter extends CodeEmitterHelper { |
| 8 | 8 |
| 9 ClassStubGenerator get _stubGenerator => | 9 ClassStubGenerator get _stubGenerator => |
| 10 new ClassStubGenerator(compiler, namer, backend); | 10 new ClassStubGenerator(compiler, namer, backend); |
| 11 | 11 |
| 12 /** | 12 /** |
| 13 * Documentation wanted -- johnniwinther | 13 * Documentation wanted -- johnniwinther |
| 14 */ | 14 */ |
| 15 void emitClass(Class cls, ClassBuilder enclosingBuilder) { | 15 void emitClass(Class cls, ClassBuilder enclosingBuilder) { |
| 16 ClassElement classElement = cls.element; | 16 ClassElement classElement = cls.element; |
| 17 | 17 |
| 18 assert(invariant(classElement, classElement.isDeclaration)); | 18 assert(invariant(classElement, classElement.isDeclaration)); |
| 19 | 19 |
| 20 emitter.needsClassSupport = true; | 20 emitter.needsClassSupport = true; |
| 21 | 21 |
| 22 ClassElement superclass = classElement.superclass; | 22 ClassElement superclass = classElement.superclass; |
| 23 String superName = ""; | 23 String superName = ""; |
| 24 if (superclass != null) { | 24 if (superclass != null) { |
| 25 superName = namer.getNameOfClass(superclass); | 25 superName = namer.className(superclass); |
| 26 } | 26 } |
| 27 | 27 |
| 28 if (cls.isMixinApplication) { | 28 if (cls.isMixinApplication) { |
| 29 MixinApplication mixinApplication = cls; | 29 MixinApplication mixinApplication = cls; |
| 30 String mixinName = mixinApplication.mixinClass.name; | 30 String mixinName = mixinApplication.mixinClass.name; |
| 31 superName = '$superName+$mixinName'; | 31 superName = '$superName+$mixinName'; |
| 32 emitter.needsMixinSupport = true; | 32 emitter.needsMixinSupport = true; |
| 33 } | 33 } |
| 34 | 34 |
| 35 ClassBuilder builder = new ClassBuilder(classElement, namer); | 35 ClassBuilder builder = new ClassBuilder(classElement, namer); |
| 36 builder.superName = superName; | 36 builder.superName = superName; |
| 37 emitConstructorsForCSP(cls); | 37 emitConstructorsForCSP(cls); |
| 38 emitFields(cls, builder); | 38 emitFields(cls, builder); |
| 39 emitCheckedClassSetters(cls, builder); | 39 emitCheckedClassSetters(cls, builder); |
| 40 emitClassGettersSettersForCSP(cls, builder); | 40 emitClassGettersSettersForCSP(cls, builder); |
| 41 emitInstanceMembers(cls, builder); | 41 emitInstanceMembers(cls, builder); |
| 42 emitCallStubs(cls, builder); | 42 emitCallStubs(cls, builder); |
| 43 emitRuntimeTypeInformation(cls, builder); | 43 emitRuntimeTypeInformation(cls, builder); |
| 44 emitNativeInfo(cls, builder); | 44 emitNativeInfo(cls, builder); |
| 45 | 45 |
| 46 if (classElement == backend.closureClass) { | 46 if (classElement == backend.closureClass) { |
| 47 // 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 |
| 48 // itself. | 48 // itself. |
| 49 String name = namer.getMappedInstanceName(Compiler.CALL_OPERATOR_NAME); | |
| 50 jsAst.Fun function = js('function() { return this; }'); | 49 jsAst.Fun function = js('function() { return this; }'); |
| 51 builder.addProperty(namer.getterNameFromAccessorName(name), function); | 50 String name = namer.getterForPublicMember(Compiler.CALL_OPERATOR_NAME); |
| 51 builder.addProperty(name, function); |
| 52 } | 52 } |
| 53 | 53 |
| 54 emitTypeVariableReaders(classElement, builder); | 54 emitTypeVariableReaders(classElement, builder); |
| 55 | 55 |
| 56 emitClassBuilderWithReflectionData(cls, builder, enclosingBuilder); | 56 emitClassBuilderWithReflectionData(cls, builder, enclosingBuilder); |
| 57 } | 57 } |
| 58 /** | 58 /** |
| 59 * Emits the precompiled constructor when in CSP mode. | 59 * Emits the precompiled constructor when in CSP mode. |
| 60 */ | 60 */ |
| 61 void emitConstructorsForCSP(Class cls) { | 61 void emitConstructorsForCSP(Class cls) { |
| 62 List<String> fieldNames = <String>[]; | 62 List<String> fieldNames = <String>[]; |
| 63 | 63 |
| 64 if (!compiler.useContentSecurityPolicy) return; | 64 if (!compiler.useContentSecurityPolicy) return; |
| 65 | 65 |
| 66 if (!cls.onlyForRti && !cls.isNative) { | 66 if (!cls.onlyForRti && !cls.isNative) { |
| 67 fieldNames = cls.fields.map((Field field) => field.name).toList(); | 67 fieldNames = cls.fields.map((Field field) => field.name).toList(); |
| 68 } | 68 } |
| 69 | 69 |
| 70 ClassElement classElement = cls.element; | 70 ClassElement classElement = cls.element; |
| 71 | 71 |
| 72 jsAst.Expression constructorAst = | 72 jsAst.Expression constructorAst = |
| 73 _stubGenerator.generateClassConstructor(classElement, fieldNames); | 73 _stubGenerator.generateClassConstructor(classElement, fieldNames); |
| 74 | 74 |
| 75 String constructorName = namer.getNameOfClass(classElement); | 75 String constructorName = namer.className(classElement); |
| 76 OutputUnit outputUnit = | 76 OutputUnit outputUnit = |
| 77 compiler.deferredLoadTask.outputUnitForElement(classElement); | 77 compiler.deferredLoadTask.outputUnitForElement(classElement); |
| 78 emitter.emitPrecompiledConstructor( | 78 emitter.emitPrecompiledConstructor( |
| 79 outputUnit, constructorName, constructorAst, fieldNames); | 79 outputUnit, constructorName, constructorAst, fieldNames); |
| 80 } | 80 } |
| 81 | 81 |
| 82 /// Returns `true` if fields added. | 82 /// Returns `true` if fields added. |
| 83 bool emitFields(FieldContainer container, | 83 bool emitFields(FieldContainer container, |
| 84 ClassBuilder builder, | 84 ClassBuilder builder, |
| 85 { bool classIsNative: false, | 85 { bool classIsNative: false, |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 136 assert(!classIsNative); | 136 assert(!classIsNative); |
| 137 } else { | 137 } else { |
| 138 // Emit (possibly renaming) field name so we can add accessors at | 138 // Emit (possibly renaming) field name so we can add accessors at |
| 139 // runtime. | 139 // runtime. |
| 140 if (name != accessorName) { | 140 if (name != accessorName) { |
| 141 fieldName = '$accessorName:$name'; | 141 fieldName = '$accessorName:$name'; |
| 142 } | 142 } |
| 143 | 143 |
| 144 if (field.needsInterceptedGetter) { | 144 if (field.needsInterceptedGetter) { |
| 145 emitter.interceptorEmitter.interceptorInvocationNames.add( | 145 emitter.interceptorEmitter.interceptorInvocationNames.add( |
| 146 namer.getterName(fieldElement)); | 146 namer.getterForElement(fieldElement)); |
| 147 } | 147 } |
| 148 // TODO(16168): The setter creator only looks at the getter-name. | 148 // TODO(16168): The setter creator only looks at the getter-name. |
| 149 // Even though the setter could avoid the interceptor convention we | 149 // Even though the setter could avoid the interceptor convention we |
| 150 // currently still need to add the additional argument. | 150 // currently still need to add the additional argument. |
| 151 if (field.needsInterceptedGetter || field.needsInterceptedSetter) { | 151 if (field.needsInterceptedGetter || field.needsInterceptedSetter) { |
| 152 emitter.interceptorEmitter.interceptorInvocationNames.add( | 152 emitter.interceptorEmitter.interceptorInvocationNames.add( |
| 153 namer.setterName(fieldElement)); | 153 namer.setterForElement(fieldElement)); |
| 154 } | 154 } |
| 155 | 155 |
| 156 int code = field.getterFlags + (field.setterFlags << 2); | 156 int code = field.getterFlags + (field.setterFlags << 2); |
| 157 if (code == 0) { | 157 if (code == 0) { |
| 158 compiler.internalError(fieldElement, | 158 compiler.internalError(fieldElement, |
| 159 'Field code is 0 ($fieldElement).'); | 159 'Field code is 0 ($fieldElement).'); |
| 160 } else { | 160 } else { |
| 161 fieldCode = FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE]; | 161 fieldCode = FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE]; |
| 162 } | 162 } |
| 163 } | 163 } |
| (...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 487 DartType type = member.type; | 487 DartType type = member.type; |
| 488 return type.treatAsDynamic || (type.element == compiler.objectClass); | 488 return type.treatAsDynamic || (type.element == compiler.objectClass); |
| 489 } | 489 } |
| 490 | 490 |
| 491 void generateCheckedSetter(Element member, | 491 void generateCheckedSetter(Element member, |
| 492 String fieldName, | 492 String fieldName, |
| 493 String accessorName, | 493 String accessorName, |
| 494 ClassBuilder builder) { | 494 ClassBuilder builder) { |
| 495 jsAst.Expression code = backend.generatedCode[member]; | 495 jsAst.Expression code = backend.generatedCode[member]; |
| 496 assert(code != null); | 496 assert(code != null); |
| 497 String setterName = namer.setterNameFromAccessorName(accessorName); | 497 String setterName = namer.deriveSetterName(accessorName); |
| 498 compiler.dumpInfoTask.registerElementAst(member, | 498 compiler.dumpInfoTask.registerElementAst(member, |
| 499 builder.addProperty(setterName, code)); | 499 builder.addProperty(setterName, code)); |
| 500 generateReflectionDataForFieldGetterOrSetter( | 500 generateReflectionDataForFieldGetterOrSetter( |
| 501 member, setterName, builder, isGetter: false); | 501 member, setterName, builder, isGetter: false); |
| 502 } | 502 } |
| 503 | 503 |
| 504 void emitGetterForCSP(Element member, String fieldName, String accessorName, | 504 void emitGetterForCSP(Element member, String fieldName, String accessorName, |
| 505 ClassBuilder builder) { | 505 ClassBuilder builder) { |
| 506 jsAst.Expression function = | 506 jsAst.Expression function = |
| 507 _stubGenerator.generateGetter(member, fieldName); | 507 _stubGenerator.generateGetter(member, fieldName); |
| 508 | 508 |
| 509 String getterName = namer.getterNameFromAccessorName(accessorName); | 509 String getterName = namer.deriveGetterName(accessorName); |
| 510 ClassElement cls = member.enclosingClass; | 510 ClassElement cls = member.enclosingClass; |
| 511 String className = namer.getNameOfClass(cls); | 511 String className = namer.className(cls); |
| 512 OutputUnit outputUnit = | 512 OutputUnit outputUnit = |
| 513 compiler.deferredLoadTask.outputUnitForElement(member); | 513 compiler.deferredLoadTask.outputUnitForElement(member); |
| 514 emitter.cspPrecompiledFunctionFor(outputUnit).add( | 514 emitter.cspPrecompiledFunctionFor(outputUnit).add( |
| 515 js('#.prototype.# = #', [className, getterName, function])); | 515 js('#.prototype.# = #', [className, getterName, function])); |
| 516 if (backend.isAccessibleByReflection(member)) { | 516 if (backend.isAccessibleByReflection(member)) { |
| 517 emitter.cspPrecompiledFunctionFor(outputUnit).add( | 517 emitter.cspPrecompiledFunctionFor(outputUnit).add( |
| 518 js('#.prototype.#.${namer.reflectableField} = 1', | 518 js('#.prototype.#.${namer.reflectableField} = 1', |
| 519 [className, getterName])); | 519 [className, getterName])); |
| 520 } | 520 } |
| 521 } | 521 } |
| 522 | 522 |
| 523 void emitSetterForCSP(Element member, String fieldName, String accessorName, | 523 void emitSetterForCSP(Element member, String fieldName, String accessorName, |
| 524 ClassBuilder builder) { | 524 ClassBuilder builder) { |
| 525 jsAst.Expression function = | 525 jsAst.Expression function = |
| 526 _stubGenerator.generateSetter(member, fieldName); | 526 _stubGenerator.generateSetter(member, fieldName); |
| 527 | 527 |
| 528 String setterName = namer.setterNameFromAccessorName(accessorName); | 528 String setterName = namer.deriveSetterName(accessorName); |
| 529 ClassElement cls = member.enclosingClass; | 529 ClassElement cls = member.enclosingClass; |
| 530 String className = namer.getNameOfClass(cls); | 530 String className = namer.className(cls); |
| 531 OutputUnit outputUnit = | 531 OutputUnit outputUnit = |
| 532 compiler.deferredLoadTask.outputUnitForElement(member); | 532 compiler.deferredLoadTask.outputUnitForElement(member); |
| 533 emitter.cspPrecompiledFunctionFor(outputUnit).add( | 533 emitter.cspPrecompiledFunctionFor(outputUnit).add( |
| 534 js('#.prototype.# = #', [className, setterName, function])); | 534 js('#.prototype.# = #', [className, setterName, function])); |
| 535 if (backend.isAccessibleByReflection(member)) { | 535 if (backend.isAccessibleByReflection(member)) { |
| 536 emitter.cspPrecompiledFunctionFor(outputUnit).add( | 536 emitter.cspPrecompiledFunctionFor(outputUnit).add( |
| 537 js('#.prototype.#.${namer.reflectableField} = 1', | 537 js('#.prototype.#.${namer.reflectableField} = 1', |
| 538 [className, setterName])); | 538 [className, setterName])); |
| 539 } | 539 } |
| 540 } | 540 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 563 emitTypeVariableReader(cls, builder, parameter.element); | 563 emitTypeVariableReader(cls, builder, parameter.element); |
| 564 } | 564 } |
| 565 } | 565 } |
| 566 superclass = superclass.superclass; | 566 superclass = superclass.superclass; |
| 567 } | 567 } |
| 568 } | 568 } |
| 569 | 569 |
| 570 void emitTypeVariableReader(ClassElement cls, | 570 void emitTypeVariableReader(ClassElement cls, |
| 571 ClassBuilder builder, | 571 ClassBuilder builder, |
| 572 TypeVariableElement element) { | 572 TypeVariableElement element) { |
| 573 String name = namer.readTypeVariableName(element); | 573 String name = namer.nameForReadTypeVariable(element); |
| 574 int index = RuntimeTypes.getTypeVariableIndex(element); | 574 int index = RuntimeTypes.getTypeVariableIndex(element); |
| 575 jsAst.Expression computeTypeVariable; | 575 jsAst.Expression computeTypeVariable; |
| 576 | 576 |
| 577 Substitution substitution = | 577 Substitution substitution = |
| 578 backend.rti.computeSubstitution( | 578 backend.rti.computeSubstitution( |
| 579 cls, element.typeDeclaration, alwaysGenerateFunction: true); | 579 cls, element.typeDeclaration, alwaysGenerateFunction: true); |
| 580 if (substitution != null) { | 580 if (substitution != null) { |
| 581 computeTypeVariable = | 581 computeTypeVariable = |
| 582 js(r'#.apply(null, this.$builtinTypeInfo)', | 582 js(r'#.apply(null, this.$builtinTypeInfo)', |
| 583 substitution.getCodeForVariable(index, backend.rti)); | 583 substitution.getCodeForVariable(index, backend.rti)); |
| 584 } else { | 584 } else { |
| 585 // TODO(ahe): These can be generated dynamically. | 585 // TODO(ahe): These can be generated dynamically. |
| 586 computeTypeVariable = | 586 computeTypeVariable = |
| 587 js(r'this.$builtinTypeInfo && this.$builtinTypeInfo[#]', | 587 js(r'this.$builtinTypeInfo && this.$builtinTypeInfo[#]', |
| 588 js.number(index)); | 588 js.number(index)); |
| 589 } | 589 } |
| 590 jsAst.Expression convertRtiToRuntimeType = emitter | 590 jsAst.Expression convertRtiToRuntimeType = emitter |
| 591 .staticFunctionAccess(backend.findHelper('convertRtiToRuntimeType')); | 591 .staticFunctionAccess(backend.findHelper('convertRtiToRuntimeType')); |
| 592 compiler.dumpInfoTask.registerElementAst(element, | 592 compiler.dumpInfoTask.registerElementAst(element, |
| 593 builder.addProperty(name, | 593 builder.addProperty(name, |
| 594 js('function () { return #(#) }', | 594 js('function () { return #(#) }', |
| 595 [convertRtiToRuntimeType, computeTypeVariable]))); | 595 [convertRtiToRuntimeType, computeTypeVariable]))); |
| 596 } | 596 } |
| 597 } | 597 } |
| OLD | NEW |