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

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

Powered by Google App Engine
This is Rietveld 408576698