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); |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
121 var metadata = | 121 var metadata = |
122 task.metadataCollector.buildMetadataFunction(fieldElement); | 122 task.metadataCollector.buildMetadataFunction(fieldElement); |
123 if (metadata != null) { | 123 if (metadata != null) { |
124 hasMetadata = true; | 124 hasMetadata = true; |
125 } else { | 125 } else { |
126 metadata = new jsAst.LiteralNull(); | 126 metadata = new jsAst.LiteralNull(); |
127 } | 127 } |
128 fieldMetadata.add(metadata); | 128 fieldMetadata.add(metadata); |
129 recordMangledField(fieldElement, accessorName, | 129 recordMangledField(fieldElement, accessorName, |
130 namer.privateName(fieldElement.memberName)); | 130 namer.privateName(fieldElement.memberName)); |
131 String fieldName = name; | 131 List<jsAst.Literal> fieldNameParts = <jsAst.Literal>[]; |
132 String fieldCode = ''; | |
133 String reflectionMarker = ''; | |
134 if (!needsAccessor) { | 132 if (!needsAccessor) { |
135 // Emit field for constructor generation. | 133 // Emit field for constructor generation. |
136 assert(!classIsNative); | 134 assert(!classIsNative); |
| 135 fieldNameParts.add(js.stringPart(name)); |
137 } else { | 136 } else { |
138 // Emit (possibly renaming) field name so we can add accessors at | 137 // Emit (possibly renaming) field name so we can add accessors at |
139 // runtime. | 138 // runtime. |
140 if (name != accessorName) { | 139 if (name != accessorName) { |
141 fieldName = '$accessorName:$name'; | 140 fieldNameParts.add(js.stringPart(accessorName)); |
| 141 fieldNameParts.add(js.stringPart(':')); |
142 } | 142 } |
143 | 143 fieldNameParts.add(js.stringPart(name)); |
144 if (field.needsInterceptedGetter) { | 144 if (field.needsInterceptedGetter) { |
145 emitter.interceptorEmitter.interceptorInvocationNames.add( | 145 emitter.interceptorEmitter.interceptorInvocationNames.add( |
146 namer.getterForElement(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.setterForElement(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 { | |
161 fieldCode = FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE]; | |
162 } | 160 } |
| 161 fieldNameParts.add( |
| 162 js.stringPart(FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE])); |
163 } | 163 } |
164 // Fields can only be reflected if their declaring class is reflectable | 164 // Fields can only be reflected if their declaring class is reflectable |
165 // (as they are only accessible via [ClassMirror.declarations]). | 165 // (as they are only accessible via [ClassMirror.declarations]). |
166 // However, set/get operations can be performed on them, so they are | 166 // However, set/get operations can be performed on them, so they are |
167 // reflectable in some sense, which leads to [isAccessibleByReflection] | 167 // reflectable in some sense, which leads to [isAccessibleByReflection] |
168 // reporting `true`. | 168 // reporting `true`. |
169 if (backend.isAccessibleByReflection(fieldElement)) { | 169 if (backend.isAccessibleByReflection(fieldElement)) { |
| 170 fieldNameParts.add(new jsAst.LiteralString('-')); |
170 if (fieldElement.isTopLevel || | 171 if (fieldElement.isTopLevel || |
171 backend.isAccessibleByReflection(fieldElement.enclosingClass)) { | 172 backend.isAccessibleByReflection(fieldElement.enclosingClass)) { |
172 DartType type = fieldElement.type; | 173 DartType type = fieldElement.type; |
173 reflectionMarker = '-${task.metadataCollector.reifyType(type)}'; | 174 fieldNameParts.add(task.metadataCollector.reifyType(type)); |
174 } else { | |
175 reflectionMarker = '-'; | |
176 } | 175 } |
177 } | 176 } |
178 String builtFieldname = '$fieldName$fieldCode$reflectionMarker'; | 177 jsAst.Literal fieldNameAst = js.concatenateStrings(fieldNameParts); |
179 builder.addField(builtFieldname); | 178 builder.addField(fieldNameAst); |
180 // Add 1 because adding a field to the class also requires a comma | 179 // Add 1 because adding a field to the class also requires a comma |
181 compiler.dumpInfoTask.recordFieldNameSize(fieldElement, | 180 compiler.dumpInfoTask.registerElementAst(fieldElement, fieldNameAst); |
182 builtFieldname.length + 1); | |
183 fieldsAdded = true; | 181 fieldsAdded = true; |
184 } | 182 } |
185 } | 183 } |
186 | 184 |
187 if (hasMetadata) { | 185 if (hasMetadata) { |
188 builder.fieldMetadata = fieldMetadata; | 186 builder.fieldMetadata = fieldMetadata; |
189 } | 187 } |
190 return fieldsAdded; | 188 return fieldsAdded; |
191 } | 189 } |
192 | 190 |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
260 // them. Note that this helper is invoked before analyzing the | 258 // them. Note that this helper is invoked before analyzing the |
261 // full JS script. | 259 // full JS script. |
262 emitter.nsmEmitter.emitNoSuchMethodHandlers(builder.addProperty); | 260 emitter.nsmEmitter.emitNoSuchMethodHandlers(builder.addProperty); |
263 } | 261 } |
264 } | 262 } |
265 | 263 |
266 /// Emits the members from the model. | 264 /// Emits the members from the model. |
267 void emitRuntimeTypeInformation(Class cls, ClassBuilder builder) { | 265 void emitRuntimeTypeInformation(Class cls, ClassBuilder builder) { |
268 assert(builder.functionType == null); | 266 assert(builder.functionType == null); |
269 if (cls.functionTypeIndex != null) { | 267 if (cls.functionTypeIndex != null) { |
270 builder.functionType = '${cls.functionTypeIndex}'; | 268 builder.functionType = cls.functionTypeIndex; |
271 } | 269 } |
272 | 270 |
273 for (Method method in cls.isChecks) { | 271 for (Method method in cls.isChecks) { |
274 builder.addProperty(method.name, method.code); | 272 builder.addProperty(method.name, method.code); |
275 } | 273 } |
276 } | 274 } |
277 | 275 |
278 void emitNativeInfo(Class cls, ClassBuilder builder) { | 276 void emitNativeInfo(Class cls, ClassBuilder builder) { |
279 if (cls.nativeInfo != null) { | 277 if (cls.nativeInfo != null) { |
280 builder.addProperty(namer.nativeSpecProperty, js.string(cls.nativeInfo)); | 278 builder.addProperty(namer.nativeSpecProperty, js.string(cls.nativeInfo)); |
281 } | 279 } |
282 } | 280 } |
283 | 281 |
284 void emitClassBuilderWithReflectionData(Class cls, | 282 void emitClassBuilderWithReflectionData(Class cls, |
285 ClassBuilder classBuilder, | 283 ClassBuilder classBuilder, |
286 ClassBuilder enclosingBuilder, | 284 ClassBuilder enclosingBuilder, |
287 Fragment fragment) { | 285 Fragment fragment) { |
288 ClassElement classElement = cls.element; | 286 ClassElement classElement = cls.element; |
289 String className = cls.name; | 287 String className = cls.name; |
290 | 288 |
291 var metadata = task.metadataCollector.buildMetadataFunction(classElement); | 289 var metadata = task.metadataCollector.buildMetadataFunction(classElement); |
292 if (metadata != null) { | 290 if (metadata != null) { |
293 classBuilder.addProperty("@", metadata); | 291 classBuilder.addProperty("@", metadata); |
294 } | 292 } |
295 | 293 |
296 if (backend.isAccessibleByReflection(classElement)) { | 294 if (backend.isAccessibleByReflection(classElement)) { |
297 List<DartType> typeVars = classElement.typeVariables; | 295 List<DartType> typeVars = classElement.typeVariables; |
298 Iterable typeVariableProperties = emitter.typeVariableHandler | 296 Iterable typeVariableProperties = emitter.typeVariableHandler |
299 .typeVariablesOf(classElement).map(js.number); | 297 .typeVariablesOf(classElement); |
300 | 298 |
301 ClassElement superclass = classElement.superclass; | 299 ClassElement superclass = classElement.superclass; |
302 bool hasSuper = superclass != null; | 300 bool hasSuper = superclass != null; |
303 if ((!typeVariableProperties.isEmpty && !hasSuper) || | 301 if ((!typeVariableProperties.isEmpty && !hasSuper) || |
304 (hasSuper && !equalElements(superclass.typeVariables, typeVars))) { | 302 (hasSuper && !equalElements(superclass.typeVariables, typeVars))) { |
305 classBuilder.addProperty('<>', | 303 classBuilder.addProperty('<>', |
306 new jsAst.ArrayInitializer(typeVariableProperties.toList())); | 304 new jsAst.ArrayInitializer(typeVariableProperties.toList())); |
307 } | 305 } |
308 } | 306 } |
309 | 307 |
(...skipping 14 matching lines...) Expand all Loading... |
324 emitter.elementDescriptors[fragment].remove(classElement); | 322 emitter.elementDescriptors[fragment].remove(classElement); |
325 if (classProperties != null) { | 323 if (classProperties != null) { |
326 statics.addAll(classProperties.properties); | 324 statics.addAll(classProperties.properties); |
327 } | 325 } |
328 | 326 |
329 if (!statics.isEmpty) { | 327 if (!statics.isEmpty) { |
330 classBuilder.addProperty('static', new jsAst.ObjectInitializer(statics)); | 328 classBuilder.addProperty('static', new jsAst.ObjectInitializer(statics)); |
331 } | 329 } |
332 | 330 |
333 // TODO(ahe): This method (generateClass) should return a jsAst.Expression. | 331 // TODO(ahe): This method (generateClass) should return a jsAst.Expression. |
334 jsAst.ObjectInitializer propertyValue = classBuilder.toObjectInitializer(); | 332 jsAst.ObjectInitializer propertyValue = |
| 333 classBuilder.toObjectInitializer(); |
335 compiler.dumpInfoTask.registerElementAst(classBuilder.element, propertyValue
); | 334 compiler.dumpInfoTask.registerElementAst(classBuilder.element, propertyValue
); |
336 enclosingBuilder.addProperty(className, propertyValue); | 335 enclosingBuilder.addProperty(className, propertyValue); |
337 | 336 |
338 String reflectionName = emitter.getReflectionName(classElement, className); | 337 String reflectionName = emitter.getReflectionName(classElement, className); |
339 if (reflectionName != null) { | 338 if (reflectionName != null) { |
340 if (!backend.isAccessibleByReflection(classElement)) { | 339 if (!backend.isAccessibleByReflection(classElement)) { |
341 enclosingBuilder.addProperty("+$reflectionName", js.number(0)); | 340 enclosingBuilder.addProperty("+$reflectionName", js.number(0)); |
342 } else { | 341 } else { |
343 List<int> types = <int>[]; | 342 List<jsAst.Expression> types = <jsAst.Expression>[]; |
344 if (classElement.supertype != null) { | 343 if (classElement.supertype != null) { |
345 types.add(task.metadataCollector.reifyType(classElement.supertype)); | 344 types.add(task.metadataCollector.reifyType(classElement.supertype)); |
346 } | 345 } |
347 for (DartType interface in classElement.interfaces) { | 346 for (DartType interface in classElement.interfaces) { |
348 types.add(task.metadataCollector.reifyType(interface)); | 347 types.add(task.metadataCollector.reifyType(interface)); |
349 } | 348 } |
350 enclosingBuilder.addProperty("+$reflectionName", js.numArray(types)); | 349 enclosingBuilder.addProperty("+$reflectionName", |
| 350 new jsAst.ArrayInitializer(types)); |
351 } | 351 } |
352 } | 352 } |
353 } | 353 } |
354 | 354 |
355 /** | 355 /** |
356 * Invokes [f] for each of the fields of [element]. | 356 * Invokes [f] for each of the fields of [element]. |
357 * | 357 * |
358 * [element] must be a [ClassElement] or a [LibraryElement]. | 358 * [element] must be a [ClassElement] or a [LibraryElement]. |
359 * | 359 * |
360 * If [element] is a [ClassElement], the static fields of the class are | 360 * If [element] is a [ClassElement], the static fields of the class are |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
556 ? new Selector.getter(member.name, member.library) | 556 ? new Selector.getter(member.name, member.library) |
557 : new Selector.setter(member.name, member.library); | 557 : new Selector.setter(member.name, member.library); |
558 String reflectionName = emitter.getReflectionName(selector, name); | 558 String reflectionName = emitter.getReflectionName(selector, name); |
559 if (reflectionName != null) { | 559 if (reflectionName != null) { |
560 var reflectable = | 560 var reflectable = |
561 js(backend.isAccessibleByReflection(member) ? '1' : '0'); | 561 js(backend.isAccessibleByReflection(member) ? '1' : '0'); |
562 builder.addProperty('+$reflectionName', reflectable); | 562 builder.addProperty('+$reflectionName', reflectable); |
563 } | 563 } |
564 } | 564 } |
565 } | 565 } |
OLD | NEW |