| 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     emitStubs(cls.callStubs, builder); |   42     emitStubs(cls.callStubs, builder); | 
|   43     emitStubs(cls.typeVariableReaderStubs, builder); |   43     emitStubs(cls.typeVariableReaderStubs, builder); | 
|   44     emitRuntimeTypeInformation(cls, builder); |   44     emitRuntimeTypeInformation(cls, builder); | 
|   45     emitNativeInfo(cls, builder); |   45     emitNativeInfo(cls, builder); | 
|   46  |   46  | 
 |   47     if (classElement == backend.closureClass) { | 
 |   48       // We add a special getter here to allow for tearing off a closure from | 
 |   49       // itself. | 
 |   50       jsAst.Fun function = js('function() { return this; }'); | 
 |   51       String name = namer.getterForPublicMember(Compiler.CALL_OPERATOR_NAME); | 
 |   52       builder.addProperty(name, function); | 
 |   53     } | 
 |   54  | 
|   47     emitClassBuilderWithReflectionData(cls, builder, enclosingBuilder); |   55     emitClassBuilderWithReflectionData(cls, builder, enclosingBuilder); | 
|   48   } |   56   } | 
|   49   /** |   57   /** | 
|   50   * Emits the precompiled constructor when in CSP mode. |   58   * Emits the precompiled constructor when in CSP mode. | 
|   51   */ |   59   */ | 
|   52   void emitConstructorsForCSP(Class cls) { |   60   void emitConstructorsForCSP(Class cls) { | 
|   53     List<String> fieldNames = <String>[]; |   61     List<String> fieldNames = <String>[]; | 
|   54  |   62  | 
|   55     if (!compiler.useContentSecurityPolicy) return; |   63     if (!compiler.useContentSecurityPolicy) return; | 
|   56  |   64  | 
|   57     if (!cls.onlyForRti && !cls.isNative) { |   65     if (!cls.onlyForRti && !cls.isNative) { | 
|   58       fieldNames = cls.fields.map((Field field) => field.name).toList(); |   66       fieldNames = cls.fields.map((Field field) => field.name).toList(); | 
|   59     } |   67     } | 
|   60  |   68  | 
|   61     ClassElement classElement = cls.element; |   69     ClassElement classElement = cls.element; | 
|   62  |   70  | 
|   63     jsAst.Expression constructorAst = |   71     jsAst.Expression constructorAst = | 
|   64         _stubGenerator.generateClassConstructor(classElement, fieldNames); |   72         _stubGenerator.generateClassConstructor(classElement, fieldNames); | 
|   65  |   73  | 
|   66     String constructorName = namer.getNameOfClass(classElement); |   74     String constructorName = namer.className(classElement); | 
|   67     OutputUnit outputUnit = |   75     OutputUnit outputUnit = | 
|   68         compiler.deferredLoadTask.outputUnitForElement(classElement); |   76         compiler.deferredLoadTask.outputUnitForElement(classElement); | 
|   69     emitter.emitPrecompiledConstructor( |   77     emitter.emitPrecompiledConstructor( | 
|   70         outputUnit, constructorName, constructorAst, fieldNames); |   78         outputUnit, constructorName, constructorAst, fieldNames); | 
|   71   } |   79   } | 
|   72  |   80  | 
|   73   /// Returns `true` if fields added. |   81   /// Returns `true` if fields added. | 
|   74   bool emitFields(FieldContainer container, |   82   bool emitFields(FieldContainer container, | 
|   75                   ClassBuilder builder, |   83                   ClassBuilder builder, | 
|   76                   { bool classIsNative: false, |   84                   { bool classIsNative: false, | 
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  127           assert(!classIsNative); |  135           assert(!classIsNative); | 
|  128         } else { |  136         } else { | 
|  129           // Emit (possibly renaming) field name so we can add accessors at |  137           // Emit (possibly renaming) field name so we can add accessors at | 
|  130           // runtime. |  138           // runtime. | 
|  131           if (name != accessorName) { |  139           if (name != accessorName) { | 
|  132             fieldName = '$accessorName:$name'; |  140             fieldName = '$accessorName:$name'; | 
|  133           } |  141           } | 
|  134  |  142  | 
|  135           if (field.needsInterceptedGetter) { |  143           if (field.needsInterceptedGetter) { | 
|  136             emitter.interceptorEmitter.interceptorInvocationNames.add( |  144             emitter.interceptorEmitter.interceptorInvocationNames.add( | 
|  137                 namer.getterName(fieldElement)); |  145                 namer.getterForElement(fieldElement)); | 
|  138           } |  146           } | 
|  139           // TODO(16168): The setter creator only looks at the getter-name. |  147           // TODO(16168): The setter creator only looks at the getter-name. | 
|  140           // Even though the setter could avoid the interceptor convention we |  148           // Even though the setter could avoid the interceptor convention we | 
|  141           // currently still need to add the additional argument. |  149           // currently still need to add the additional argument. | 
|  142           if (field.needsInterceptedGetter || field.needsInterceptedSetter) { |  150           if (field.needsInterceptedGetter || field.needsInterceptedSetter) { | 
|  143             emitter.interceptorEmitter.interceptorInvocationNames.add( |  151             emitter.interceptorEmitter.interceptorInvocationNames.add( | 
|  144                 namer.setterName(fieldElement)); |  152                 namer.setterForElement(fieldElement)); | 
|  145           } |  153           } | 
|  146  |  154  | 
|  147           int code = field.getterFlags + (field.setterFlags << 2); |  155           int code = field.getterFlags + (field.setterFlags << 2); | 
|  148           if (code == 0) { |  156           if (code == 0) { | 
|  149             compiler.internalError(fieldElement, |  157             compiler.internalError(fieldElement, | 
|  150                 'Field code is 0 ($fieldElement).'); |  158                 'Field code is 0 ($fieldElement).'); | 
|  151           } else { |  159           } else { | 
|  152             fieldCode = FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE]; |  160             fieldCode = FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE]; | 
|  153           } |  161           } | 
|  154         } |  162         } | 
| (...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  476     DartType type = member.type; |  484     DartType type = member.type; | 
|  477     return type.treatAsDynamic || (type.element == compiler.objectClass); |  485     return type.treatAsDynamic || (type.element == compiler.objectClass); | 
|  478   } |  486   } | 
|  479  |  487  | 
|  480   void generateCheckedSetter(Element member, |  488   void generateCheckedSetter(Element member, | 
|  481                              String fieldName, |  489                              String fieldName, | 
|  482                              String accessorName, |  490                              String accessorName, | 
|  483                              ClassBuilder builder) { |  491                              ClassBuilder builder) { | 
|  484     jsAst.Expression code = backend.generatedCode[member]; |  492     jsAst.Expression code = backend.generatedCode[member]; | 
|  485     assert(code != null); |  493     assert(code != null); | 
|  486     String setterName = namer.setterNameFromAccessorName(accessorName); |  494     String setterName = namer.deriveSetterName(accessorName); | 
|  487     compiler.dumpInfoTask.registerElementAst(member, |  495     compiler.dumpInfoTask.registerElementAst(member, | 
|  488         builder.addProperty(setterName, code)); |  496         builder.addProperty(setterName, code)); | 
|  489     generateReflectionDataForFieldGetterOrSetter( |  497     generateReflectionDataForFieldGetterOrSetter( | 
|  490         member, setterName, builder, isGetter: false); |  498         member, setterName, builder, isGetter: false); | 
|  491   } |  499   } | 
|  492  |  500  | 
|  493   void emitGetterForCSP(Element member, String fieldName, String accessorName, |  501   void emitGetterForCSP(Element member, String fieldName, String accessorName, | 
|  494                         ClassBuilder builder) { |  502                         ClassBuilder builder) { | 
|  495     jsAst.Expression function = |  503     jsAst.Expression function = | 
|  496         _stubGenerator.generateGetter(member, fieldName); |  504         _stubGenerator.generateGetter(member, fieldName); | 
|  497  |  505  | 
|  498     String getterName = namer.getterNameFromAccessorName(accessorName); |  506     String getterName = namer.deriveGetterName(accessorName); | 
|  499     ClassElement cls = member.enclosingClass; |  507     ClassElement cls = member.enclosingClass; | 
|  500     String className = namer.getNameOfClass(cls); |  508     String className = namer.className(cls); | 
|  501     OutputUnit outputUnit = |  509     OutputUnit outputUnit = | 
|  502         compiler.deferredLoadTask.outputUnitForElement(member); |  510         compiler.deferredLoadTask.outputUnitForElement(member); | 
|  503     emitter.cspPrecompiledFunctionFor(outputUnit).add( |  511     emitter.cspPrecompiledFunctionFor(outputUnit).add( | 
|  504         js('#.prototype.# = #', [className, getterName, function])); |  512         js('#.prototype.# = #', [className, getterName, function])); | 
|  505     if (backend.isAccessibleByReflection(member)) { |  513     if (backend.isAccessibleByReflection(member)) { | 
|  506       emitter.cspPrecompiledFunctionFor(outputUnit).add( |  514       emitter.cspPrecompiledFunctionFor(outputUnit).add( | 
|  507           js('#.prototype.#.${namer.reflectableField} = 1', |  515           js('#.prototype.#.${namer.reflectableField} = 1', | 
|  508               [className, getterName])); |  516               [className, getterName])); | 
|  509     } |  517     } | 
|  510   } |  518   } | 
|  511  |  519  | 
|  512   void emitSetterForCSP(Element member, String fieldName, String accessorName, |  520   void emitSetterForCSP(Element member, String fieldName, String accessorName, | 
|  513                         ClassBuilder builder) { |  521                         ClassBuilder builder) { | 
|  514     jsAst.Expression function = |  522     jsAst.Expression function = | 
|  515         _stubGenerator.generateSetter(member, fieldName); |  523         _stubGenerator.generateSetter(member, fieldName); | 
|  516  |  524  | 
|  517     String setterName = namer.setterNameFromAccessorName(accessorName); |  525     String setterName = namer.deriveSetterName(accessorName); | 
|  518     ClassElement cls = member.enclosingClass; |  526     ClassElement cls = member.enclosingClass; | 
|  519     String className = namer.getNameOfClass(cls); |  527     String className = namer.className(cls); | 
|  520     OutputUnit outputUnit = |  528     OutputUnit outputUnit = | 
|  521         compiler.deferredLoadTask.outputUnitForElement(member); |  529         compiler.deferredLoadTask.outputUnitForElement(member); | 
|  522     emitter.cspPrecompiledFunctionFor(outputUnit).add( |  530     emitter.cspPrecompiledFunctionFor(outputUnit).add( | 
|  523         js('#.prototype.# = #', [className, setterName, function])); |  531         js('#.prototype.# = #', [className, setterName, function])); | 
|  524     if (backend.isAccessibleByReflection(member)) { |  532     if (backend.isAccessibleByReflection(member)) { | 
|  525       emitter.cspPrecompiledFunctionFor(outputUnit).add( |  533       emitter.cspPrecompiledFunctionFor(outputUnit).add( | 
|  526           js('#.prototype.#.${namer.reflectableField} = 1', |  534           js('#.prototype.#.${namer.reflectableField} = 1', | 
|  527               [className, setterName])); |  535               [className, setterName])); | 
|  528     } |  536     } | 
|  529   } |  537   } | 
|  530  |  538  | 
|  531   void generateReflectionDataForFieldGetterOrSetter(Element member, |  539   void generateReflectionDataForFieldGetterOrSetter(Element member, | 
|  532                                                     String name, |  540                                                     String name, | 
|  533                                                     ClassBuilder builder, |  541                                                     ClassBuilder builder, | 
|  534                                                     {bool isGetter}) { |  542                                                     {bool isGetter}) { | 
|  535     Selector selector = isGetter |  543     Selector selector = isGetter | 
|  536         ? new Selector.getter(member.name, member.library) |  544         ? new Selector.getter(member.name, member.library) | 
|  537         : new Selector.setter(member.name, member.library); |  545         : new Selector.setter(member.name, member.library); | 
|  538     String reflectionName = emitter.getReflectionName(selector, name); |  546     String reflectionName = emitter.getReflectionName(selector, name); | 
|  539     if (reflectionName != null) { |  547     if (reflectionName != null) { | 
|  540       var reflectable = |  548       var reflectable = | 
|  541           js(backend.isAccessibleByReflection(member) ? '1' : '0'); |  549           js(backend.isAccessibleByReflection(member) ? '1' : '0'); | 
|  542       builder.addProperty('+$reflectionName', reflectable); |  550       builder.addProperty('+$reflectionName', reflectable); | 
|  543     } |  551     } | 
|  544   } |  552   } | 
|  545 } |  553 } | 
| OLD | NEW |