Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7)

Side by Side Diff: pkg/compiler/lib/src/js_emitter/old_emitter/class_emitter.dart

Issue 869543004: dart2js: store fields in the model and make the emitters use it. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments. Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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, 15 void emitClass(Class cls,
16 ClassBuilder enclosingBuilder, 16 ClassBuilder enclosingBuilder,
17 Map<String, jsAst.Expression> additionalProperties) { 17 Map<String, jsAst.Expression> additionalProperties) {
18 ClassElement classElement = cls.element; 18 ClassElement classElement = cls.element;
19 final onlyForRti =
20 emitter.typeTestRegistry.rtiNeededClasses.contains(classElement);
21 19
22 assert(invariant(classElement, classElement.isDeclaration)); 20 assert(invariant(classElement, classElement.isDeclaration));
23 assert(invariant(classElement, !classElement.isNative || onlyForRti)); 21 assert(invariant(classElement, !cls.isNative || cls.onlyForRti));
24 22
25 emitter.needsClassSupport = true; 23 emitter.needsClassSupport = true;
26 String className = namer.getNameOfClass(classElement);
27 24
28 ClassElement superclass = classElement.superclass; 25 ClassElement superclass = classElement.superclass;
29 String superName = ""; 26 String superName = "";
30 if (superclass != null) { 27 if (superclass != null) {
31 superName = namer.getNameOfClass(superclass); 28 superName = namer.getNameOfClass(superclass);
32 } 29 }
33 30
34 if (cls.isMixinApplication) { 31 if (cls.isMixinApplication) {
35 MixinApplication mixinApplication = cls; 32 MixinApplication mixinApplication = cls;
36 String mixinName = mixinApplication.mixinClass.name; 33 String mixinName = mixinApplication.mixinClass.name;
37 superName = '$superName+$mixinName'; 34 superName = '$superName+$mixinName';
38 emitter.needsMixinSupport = true; 35 emitter.needsMixinSupport = true;
39 } 36 }
40 37
41 ClassBuilder builder = new ClassBuilder(classElement, namer); 38 ClassBuilder builder = new ClassBuilder(classElement, namer);
42 builder.superName = superName; 39 builder.superName = superName;
43 emitConstructorsForCSP(classElement, onlyForRti: onlyForRti); 40 emitConstructorsForCSP(cls);
44 emitFields(classElement, builder, onlyForRti: onlyForRti); 41 emitFields(cls, builder);
45 emitCheckedClassSetters(classElement, builder, onlyForRti: onlyForRti); 42 emitCheckedClassSetters(cls, builder);
46 emitClassGettersSettersForCSP(classElement, builder, 43 emitClassGettersSettersForCSP(cls, builder);
47 onlyForRti: onlyForRti); 44 emitInstanceMembers(classElement, builder, onlyForRti: cls.onlyForRti);
48 emitInstanceMembers(classElement, builder, onlyForRti: onlyForRti);
49 emitRuntimeTypeInformation(cls, builder); 45 emitRuntimeTypeInformation(cls, builder);
50 if (additionalProperties != null) { 46 if (additionalProperties != null) {
51 additionalProperties.forEach(builder.addProperty); 47 additionalProperties.forEach(builder.addProperty);
52 } 48 }
53 49
54 if (classElement == backend.closureClass) { 50 if (classElement == backend.closureClass) {
55 // We add a special getter here to allow for tearing off a closure from 51 // We add a special getter here to allow for tearing off a closure from
56 // itself. 52 // itself.
57 String name = namer.getMappedInstanceName(Compiler.CALL_OPERATOR_NAME); 53 String name = namer.getMappedInstanceName(Compiler.CALL_OPERATOR_NAME);
58 jsAst.Fun function = js('function() { return this; }'); 54 jsAst.Fun function = js('function() { return this; }');
59 builder.addProperty(namer.getterNameFromAccessorName(name), function); 55 builder.addProperty(namer.getterNameFromAccessorName(name), function);
60 } 56 }
61 57
62 emitTypeVariableReaders(classElement, builder); 58 emitTypeVariableReaders(classElement, builder);
63 59
64 emitClassBuilderWithReflectionData( 60 emitClassBuilderWithReflectionData(cls, builder, enclosingBuilder);
65 className, classElement, builder, enclosingBuilder);
66 } 61 }
67 /** 62 /**
68 * Emits the precompiled constructor when in CSP mode. 63 * Emits the precompiled constructor when in CSP mode.
69 */ 64 */
70 void emitConstructorsForCSP(ClassElement classElement, 65 void emitConstructorsForCSP(Class cls) {
71 {bool onlyForRti: false}) { 66 List<String> fieldNames = <String>[];
72 List<String> fields = <String>[];
73 67
74 if (!compiler.useContentSecurityPolicy) return; 68 if (!compiler.useContentSecurityPolicy) return;
75 69
76 if (!onlyForRti && !classElement.isNative) { 70 if (!cls.onlyForRti && !cls.isNative) {
77 visitFields(classElement, false, 71 fieldNames = cls.fields.map((Field field) => field.name).toList();
78 (Element member,
79 String name,
80 String accessorName,
81 bool needsGetter,
82 bool needsSetter,
83 bool needsCheckedSetter) {
84 fields.add(name);
85 });
86 } 72 }
73
74 ClassElement classElement = cls.element;
75
87 jsAst.Expression constructorAst = 76 jsAst.Expression constructorAst =
88 _stubGenerator.generateClassConstructor(classElement, fields); 77 _stubGenerator.generateClassConstructor(classElement, fieldNames);
89 78
90 String constructorName = namer.getNameOfClass(classElement); 79 String constructorName = namer.getNameOfClass(classElement);
91 OutputUnit outputUnit = 80 OutputUnit outputUnit =
92 compiler.deferredLoadTask.outputUnitForElement(classElement); 81 compiler.deferredLoadTask.outputUnitForElement(classElement);
93 emitter.emitPrecompiledConstructor( 82 emitter.emitPrecompiledConstructor(
94 outputUnit, constructorName, constructorAst, fields); 83 outputUnit, constructorName, constructorAst, fieldNames);
95 } 84 }
96 85
97 /// Returns `true` if fields added. 86 /// Returns `true` if fields added.
98 bool emitFields(Element element, 87 bool emitFields(FieldContainer container,
99 ClassBuilder builder, 88 ClassBuilder builder,
100 { bool classIsNative: false, 89 { bool classIsNative: false,
101 bool emitStatics: false, 90 bool emitStatics: false }) {
102 bool onlyForRti: false }) { 91 Iterable<Field> fields;
103 assert(!emitStatics || !onlyForRti); 92 if (container is Class) {
104 if (element.isLibrary) { 93 if (emitStatics) {
105 assert(invariant(element, emitStatics)); 94 fields = container.staticFieldsForReflection;
106 } else if (!element.isClass) { 95 } else if (container.onlyForRti) {
107 throw new SpannableAssertionFailure( 96 return false;
108 element, 'Must be a ClassElement or a LibraryElement'); 97 } else {
98 fields = container.fields;
99 }
100 } else {
101 assert(container is Library);
102 assert(emitStatics);
103 fields = container.staticFieldsForReflection;
109 } 104 }
105
110 var fieldMetadata = []; 106 var fieldMetadata = [];
111 bool hasMetadata = false; 107 bool hasMetadata = false;
112 bool fieldsAdded = false; 108 bool fieldsAdded = false;
113 109
114 if (!onlyForRti) { 110 for (Field field in fields) {
115 visitFields(element, emitStatics, 111 VariableElement fieldElement = field.element;
116 (VariableElement field, 112 String name = field.name;
117 String name, 113 String accessorName = field.accessorName;
118 String accessorName, 114 bool needsGetter = field.needsGetter;
119 bool needsGetter, 115 bool needsSetter = field.needsUncheckedSetter;
120 bool needsSetter, 116
121 bool needsCheckedSetter) {
122 // Ignore needsCheckedSetter - that is handled below. 117 // Ignore needsCheckedSetter - that is handled below.
123 bool needsAccessor = (needsGetter || needsSetter); 118 bool needsAccessor = (needsGetter || needsSetter);
124 // We need to output the fields for non-native classes so we can auto- 119 // We need to output the fields for non-native classes so we can auto-
125 // generate the constructor. For native classes there are no 120 // generate the constructor. For native classes there are no
126 // constructors, so we don't need the fields unless we are generating 121 // constructors, so we don't need the fields unless we are generating
127 // accessors at runtime. 122 // accessors at runtime.
128 bool needsFieldsForConstructor = !emitStatics && !classIsNative; 123 bool needsFieldsForConstructor = !emitStatics && !classIsNative;
129 if (needsFieldsForConstructor || needsAccessor) { 124 if (needsFieldsForConstructor || needsAccessor) {
130 var metadata = emitter.metadataEmitter.buildMetadataFunction(field); 125 var metadata =
131 if (metadata != null) { 126 emitter.metadataEmitter.buildMetadataFunction(fieldElement);
132 hasMetadata = true; 127 if (metadata != null) {
128 hasMetadata = true;
129 } else {
130 metadata = new jsAst.LiteralNull();
131 }
132 fieldMetadata.add(metadata);
133 recordMangledField(fieldElement, accessorName,
134 namer.privateName(fieldElement.library, fieldElement.name));
135 String fieldName = name;
136 String fieldCode = '';
137 String reflectionMarker = '';
138 if (!needsAccessor) {
139 // Emit field for constructor generation.
140 assert(!classIsNative);
141 } else {
142 // Emit (possibly renaming) field name so we can add accessors at
143 // runtime.
144 if (name != accessorName) {
145 fieldName = '$accessorName:$name';
146 }
147
148 if (field.needsInterceptedGetter) {
149 emitter.interceptorEmitter.interceptorInvocationNames.add(
150 namer.getterName(fieldElement));
151 }
152 // TODO(16168): The setter creator only looks at the getter-name.
153 // Even though the setter could avoid the interceptor convention we
154 // currently still need to add the additional argument.
155 if (field.needsInterceptedGetter || field.needsInterceptedSetter) {
156 emitter.interceptorEmitter.interceptorInvocationNames.add(
157 namer.setterName(fieldElement));
158 }
159
160 int code = field.getterFlags + (field.setterFlags << 2);
161 if (code == 0) {
162 compiler.internalError(fieldElement,
163 'Field code is 0 ($fieldElement).');
133 } else { 164 } else {
134 metadata = new jsAst.LiteralNull(); 165 fieldCode = FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE];
135 } 166 }
136 fieldMetadata.add(metadata);
137 recordMangledField(field, accessorName,
138 namer.privateName(field.library, field.name));
139 String fieldName = name;
140 String fieldCode = '';
141 String reflectionMarker = '';
142 if (!needsAccessor) {
143 // Emit field for constructor generation.
144 assert(!classIsNative);
145 } else {
146 // Emit (possibly renaming) field name so we can add accessors at
147 // runtime.
148 if (name != accessorName) {
149 fieldName = '$accessorName:$name';
150 }
151
152 int getterCode = 0;
153 if (needsAccessor && backend.fieldHasInterceptedGetter(field)) {
154 emitter.interceptorEmitter.interceptorInvocationNames.add(
155 namer.getterName(field));
156 }
157 if (needsAccessor && backend.fieldHasInterceptedGetter(field)) {
158 emitter.interceptorEmitter.interceptorInvocationNames.add(
159 namer.setterName(field));
160 }
161 if (needsGetter) {
162 if (field.isInstanceMember) {
163 // 01: function() { return this.field; }
164 // 10: function(receiver) { return receiver.field; }
165 // 11: function(receiver) { return this.field; }
166 bool isIntercepted = backend.fieldHasInterceptedGetter(field);
167 getterCode += isIntercepted ? 2 : 0;
168 getterCode += backend.isInterceptorClass(element) ? 0 : 1;
169 // TODO(sra): 'isInterceptorClass' might not be the correct test
170 // for methods forced to use the interceptor convention because
171 // the method's class was elsewhere mixed-in to an interceptor.
172 assert(!field.isInstanceMember || getterCode != 0);
173 if (isIntercepted) {
174 emitter.interceptorEmitter.interceptorInvocationNames.add(
175 namer.getterName(field));
176 }
177 } else {
178 getterCode = 1;
179 }
180 }
181 int setterCode = 0;
182 if (needsSetter) {
183 if (field.isInstanceMember) {
184 // 01: function(value) { this.field = value; }
185 // 10: function(receiver, value) { receiver.field = value; }
186 // 11: function(receiver, value) { this.field = value; }
187 bool isIntercepted = backend.fieldHasInterceptedSetter(field);
188 setterCode += isIntercepted ? 2 : 0;
189 setterCode += backend.isInterceptorClass(element) ? 0 : 1;
190 assert(!field.isInstanceMember || setterCode != 0);
191 if (isIntercepted) {
192 emitter.interceptorEmitter.interceptorInvocationNames.add(
193 namer.setterName(field));
194 }
195 } else {
196 setterCode = 1;
197 }
198 }
199 int code = getterCode + (setterCode << 2);
200 if (code == 0) {
201 compiler.internalError(field,
202 'Field code is 0 ($element/$field).');
203 } else {
204 fieldCode = FIELD_CODE_CHARACTERS[code - FIRST_FIELD_CODE];
205 }
206 }
207 if (backend.isAccessibleByReflection(field)) {
208 DartType type = field.type;
209 reflectionMarker = '-${emitter.metadataEmitter.reifyType(type)}';
210 }
211 String builtFieldname = '$fieldName$fieldCode$reflectionMarker';
212 builder.addField(builtFieldname);
213 // Add 1 because adding a field to the class also requires a comma
214 compiler.dumpInfoTask.recordFieldNameSize(field,
215 builtFieldname.length + 1);
216 fieldsAdded = true;
217 } 167 }
218 }); 168 if (backend.isAccessibleByReflection(fieldElement)) {
169 DartType type = fieldElement.type;
170 reflectionMarker = '-${emitter.metadataEmitter.reifyType(type)}';
171 }
172 String builtFieldname = '$fieldName$fieldCode$reflectionMarker';
173 builder.addField(builtFieldname);
174 // Add 1 because adding a field to the class also requires a comma
175 compiler.dumpInfoTask.recordFieldNameSize(fieldElement,
176 builtFieldname.length + 1);
177 fieldsAdded = true;
178 }
219 } 179 }
220 180
221 if (hasMetadata) { 181 if (hasMetadata) {
222 builder.fieldMetadata = fieldMetadata; 182 builder.fieldMetadata = fieldMetadata;
223 } 183 }
224 return fieldsAdded; 184 return fieldsAdded;
225 } 185 }
226 186
227 /// Emits checked setters for fields. 187 /// Emits checked setters for fields.
228 void emitCheckedClassSetters(ClassElement classElement, 188 void emitCheckedClassSetters(Class cls, ClassBuilder builder) {
229 ClassBuilder builder, 189 if (cls.onlyForRti) return;
230 {bool onlyForRti: false}) {
231 if (onlyForRti) return;
232 190
233 visitFields(classElement, false, 191 for (Field field in cls.fields) {
234 (VariableElement member, 192 if (field.needsCheckedSetter) {
235 String name, 193 assert(!field.needsUncheckedSetter);
236 String accessorName, 194 compiler.withCurrentElement(field.element, () {
237 bool needsGetter, 195 generateCheckedSetter(
238 bool needsSetter, 196 field.element, field.name, field.accessorName, builder);
239 bool needsCheckedSetter) { 197 });
240 compiler.withCurrentElement(member, () { 198 }
241 if (needsCheckedSetter) { 199 }
242 assert(!needsSetter);
243 generateCheckedSetter(member, name, accessorName, builder);
244 }
245 });
246 });
247 } 200 }
248 201
249 /// Emits getters/setters for fields if compiling in CSP mode. 202 /// Emits getters/setters for fields if compiling in CSP mode.
250 void emitClassGettersSettersForCSP(ClassElement classElement, 203 void emitClassGettersSettersForCSP(Class cls, ClassBuilder builder) {
251 ClassBuilder builder,
252 {bool onlyForRti: false}) {
253 204
254 if (!compiler.useContentSecurityPolicy || onlyForRti) return; 205 if (!compiler.useContentSecurityPolicy || cls.onlyForRti) return;
255 206
256 visitFields(classElement, false, 207 for (Field field in cls.fields) {
257 (VariableElement member, 208 Element member = field.element;
258 String name,
259 String accessorName,
260 bool needsGetter,
261 bool needsSetter,
262 bool needsCheckedSetter) {
263 compiler.withCurrentElement(member, () { 209 compiler.withCurrentElement(member, () {
264 if (needsGetter) { 210 if (field.needsGetter) {
265 emitGetterForCSP(member, name, accessorName, builder); 211 emitGetterForCSP(member, field.name, field.accessorName, builder);
266 } 212 }
267 if (needsSetter) { 213 if (field.needsUncheckedSetter) {
268 emitSetterForCSP(member, name, accessorName, builder); 214 emitSetterForCSP(member, field.name, field.accessorName, builder);
269 } 215 }
270 }); 216 });
271 }); 217 }
272 } 218 }
273 219
274 /** 220 /**
275 * Documentation wanted -- johnniwinther 221 * Documentation wanted -- johnniwinther
276 * 222 *
277 * Invariant: [classElement] must be a declaration element. 223 * Invariant: [classElement] must be a declaration element.
278 */ 224 */
279 void emitInstanceMembers(ClassElement classElement, 225 void emitInstanceMembers(ClassElement classElement,
280 ClassBuilder builder, 226 ClassBuilder builder,
281 {bool onlyForRti: false}) { 227 {bool onlyForRti: false}) {
(...skipping 29 matching lines...) Expand all
311 assert(builder.functionType == null); 257 assert(builder.functionType == null);
312 if (cls.functionTypeIndex != null) { 258 if (cls.functionTypeIndex != null) {
313 builder.functionType = '${cls.functionTypeIndex}'; 259 builder.functionType = '${cls.functionTypeIndex}';
314 } 260 }
315 261
316 for (Method method in cls.isChecks) { 262 for (Method method in cls.isChecks) {
317 builder.addProperty(method.name, method.code); 263 builder.addProperty(method.name, method.code);
318 } 264 }
319 } 265 }
320 266
321 void emitClassBuilderWithReflectionData(String className, 267 void emitClassBuilderWithReflectionData(Class cls,
322 ClassElement classElement,
323 ClassBuilder classBuilder, 268 ClassBuilder classBuilder,
324 ClassBuilder enclosingBuilder) { 269 ClassBuilder enclosingBuilder) {
270 ClassElement classElement = cls.element;
271 String className = cls.name;
272
325 var metadata = emitter.metadataEmitter.buildMetadataFunction(classElement); 273 var metadata = emitter.metadataEmitter.buildMetadataFunction(classElement);
326 if (metadata != null) { 274 if (metadata != null) {
327 classBuilder.addProperty("@", metadata); 275 classBuilder.addProperty("@", metadata);
328 } 276 }
329 277
330 if (backend.isAccessibleByReflection(classElement)) { 278 if (backend.isAccessibleByReflection(classElement)) {
331 List<DartType> typeVars = classElement.typeVariables; 279 List<DartType> typeVars = classElement.typeVariables;
332 Iterable typeVariableProperties = emitter.typeVariableHandler 280 Iterable typeVariableProperties = emitter.typeVariableHandler
333 .typeVariablesOf(classElement).map(js.number); 281 .typeVariablesOf(classElement).map(js.number);
334 282
335 ClassElement superclass = classElement.superclass; 283 ClassElement superclass = classElement.superclass;
336 bool hasSuper = superclass != null; 284 bool hasSuper = superclass != null;
337 if ((!typeVariableProperties.isEmpty && !hasSuper) || 285 if ((!typeVariableProperties.isEmpty && !hasSuper) ||
338 (hasSuper && !equalElements(superclass.typeVariables, typeVars))) { 286 (hasSuper && !equalElements(superclass.typeVariables, typeVars))) {
339 classBuilder.addProperty('<>', 287 classBuilder.addProperty('<>',
340 new jsAst.ArrayInitializer(typeVariableProperties.toList())); 288 new jsAst.ArrayInitializer(typeVariableProperties.toList()));
341 } 289 }
342 } 290 }
343 291
344 List<jsAst.Property> statics = new List<jsAst.Property>(); 292 List<jsAst.Property> statics = new List<jsAst.Property>();
345 ClassBuilder staticsBuilder = new ClassBuilder(classElement, namer); 293 ClassBuilder staticsBuilder = new ClassBuilder(classElement, namer);
346 if (emitFields(classElement, staticsBuilder, emitStatics: true)) { 294 if (emitFields(cls, staticsBuilder, emitStatics: true)) {
347 jsAst.ObjectInitializer initializer = 295 jsAst.ObjectInitializer initializer =
348 staticsBuilder.toObjectInitializer(); 296 staticsBuilder.toObjectInitializer();
349 compiler.dumpInfoTask.registerElementAst(classElement, 297 compiler.dumpInfoTask.registerElementAst(classElement,
350 initializer); 298 initializer);
351 jsAst.Node property = initializer.properties.single; 299 jsAst.Node property = initializer.properties.single;
352 compiler.dumpInfoTask.registerElementAst(classElement, property); 300 compiler.dumpInfoTask.registerElementAst(classElement, property);
353 statics.add(property); 301 statics.add(property);
354 } 302 }
355 303
356 ClassBuilder classProperties = 304 ClassBuilder classProperties =
(...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after
631 js.number(index)); 579 js.number(index));
632 } 580 }
633 jsAst.Expression convertRtiToRuntimeType = emitter 581 jsAst.Expression convertRtiToRuntimeType = emitter
634 .staticFunctionAccess(backend.findHelper('convertRtiToRuntimeType')); 582 .staticFunctionAccess(backend.findHelper('convertRtiToRuntimeType'));
635 compiler.dumpInfoTask.registerElementAst(element, 583 compiler.dumpInfoTask.registerElementAst(element,
636 builder.addProperty(name, 584 builder.addProperty(name,
637 js('function () { return #(#) }', 585 js('function () { return #(#) }',
638 [convertRtiToRuntimeType, computeTypeVariable]))); 586 [convertRtiToRuntimeType, computeTypeVariable])));
639 } 587 }
640 } 588 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698