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

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

Issue 859843002: dart2js: use model in native emitter. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Revert debug code. 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) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 NativeEmitter { 7 class NativeEmitter {
8 8
9 final Map<Element, ClassBuilder> cachedBuilders; 9 final Map<Element, ClassBuilder> cachedBuilders;
10 10
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
57 * improves performance when more classes can be treated as leaves. 57 * improves performance when more classes can be treated as leaves.
58 * 58 *
59 * [classes] contains native classes, mixin applications, and user subclasses 59 * [classes] contains native classes, mixin applications, and user subclasses
60 * of native classes. ONLY the native classes are generated here. [classes] 60 * of native classes. ONLY the native classes are generated here. [classes]
61 * is sorted in desired output order. 61 * is sorted in desired output order.
62 * 62 *
63 * [additionalProperties] is used to collect properties that are pushed up 63 * [additionalProperties] is used to collect properties that are pushed up
64 * from the above optimizations onto a non-native class, e.g, `Interceptor`. 64 * from the above optimizations onto a non-native class, e.g, `Interceptor`.
65 */ 65 */
66 void generateNativeClasses( 66 void generateNativeClasses(
67 List<ClassElement> classes, 67 List<Class> classes,
68 Map<ClassElement, Map<String, jsAst.Expression>> additionalProperties) { 68 Map<ClassElement, Map<String, jsAst.Expression>> additionalProperties) {
69 // Compute a pre-order traversal of the subclass forest. We actually want a 69 // Compute a pre-order traversal of the subclass forest. We actually want a
70 // post-order traversal but it is easier to compute the pre-order and use it 70 // post-order traversal but it is easier to compute the pre-order and use it
71 // in reverse. 71 // in reverse.
72 72
73 List<ClassElement> preOrder = <ClassElement>[]; 73 List<Class> preOrder = <Class>[];
74 Set<ClassElement> seen = new Set<ClassElement>(); 74 Set<Class> seen = new Set<Class>();
75 seen..add(compiler.objectClass) 75
76 ..add(backend.jsInterceptorClass); 76 Class objectClass = null;
77 void walk(ClassElement element) { 77 Class jsInterceptorClass = null;
78 if (seen.contains(element)) return; 78 void walk(Class cls) {
79 seen.add(element); 79 if (cls.element == compiler.objectClass) {
80 walk(element.superclass); 80 objectClass = cls;
81 preOrder.add(element); 81 return;
82 }
83 if (cls.element == backend.jsInterceptorClass) {
84 jsInterceptorClass = cls;
85 return;
86 }
87 if (seen.contains(cls)) return;
88 seen.add(cls);
89 walk(cls.superclass);
90 preOrder.add(cls);
82 } 91 }
83 classes.forEach(walk); 92 classes.forEach(walk);
84 93
85 // Generate code for each native class into [ClassBuilder]s. 94 // Generate code for each native class into [ClassBuilder]s.
86 95
87 Map<ClassElement, ClassBuilder> builders = 96 Map<Class, ClassBuilder> builders = new Map<Class, ClassBuilder>();
88 new Map<ClassElement, ClassBuilder>(); 97 for (Class cls in classes) {
89 for (ClassElement classElement in classes) { 98 if (cls.isNative) {
90 if (classElement.isNative) { 99 ClassBuilder builder = generateNativeClass(cls);
91 ClassBuilder builder = generateNativeClass(classElement); 100 builders[cls] = builder;
92 builders[classElement] = builder;
93 } 101 }
94 } 102 }
95 103
96 // Find which classes are needed and which are non-leaf classes. Any class 104 // Find which classes are needed and which are non-leaf classes. Any class
97 // that is not needed can be treated as a leaf class equivalent to some 105 // that is not needed can be treated as a leaf class equivalent to some
98 // needed class. 106 // needed class.
99 107
100 Set<ClassElement> neededClasses = new Set<ClassElement>(); 108 Set<Class> neededClasses = new Set<Class>();
101 Set<ClassElement> nonleafClasses = new Set<ClassElement>(); 109 Set<Class> nonleafClasses = new Set<Class>();
102 110
103 Map<ClassElement, List<ClassElement>> extensionPoints = 111 Map<Class, List<Class>> extensionPoints = computeExtensionPoints(preOrder);
104 computeExtensionPoints(preOrder);
105 112
106 neededClasses.add(compiler.objectClass); 113 neededClasses.add(objectClass);
107 114
108 Set<ClassElement> neededByConstant = 115 Set<ClassElement> neededByConstant =
109 emitterTask.interceptorsReferencedFromConstants(); 116 emitterTask.interceptorsReferencedFromConstants();
110 Set<ClassElement> modifiedClasses = 117 Set<ClassElement> modifiedClasses =
111 emitterTask.typeTestRegistry.classesModifiedByEmitRuntimeTypeSupport(); 118 emitterTask.typeTestRegistry.classesModifiedByEmitRuntimeTypeSupport();
112 119
113 for (ClassElement classElement in preOrder.reversed) { 120 for (Class cls in preOrder.reversed) {
121 ClassElement classElement = cls.element;
114 // Post-order traversal ensures we visit the subclasses before their 122 // Post-order traversal ensures we visit the subclasses before their
115 // superclass. This makes it easy to tell if a class is needed because a 123 // superclass. This makes it easy to tell if a class is needed because a
116 // subclass is needed. 124 // subclass is needed.
117 ClassBuilder builder = builders[classElement]; 125 ClassBuilder builder = builders[cls];
118 bool needed = false; 126 bool needed = false;
119 if (builder == null) { 127 if (builder == null) {
120 // Mixin applications (native+mixin) are non-native, so [classElement] 128 // Mixin applications (native+mixin) are non-native, so [classElement]
121 // has already been emitted as a regular class. Mark [classElement] as 129 // has already been emitted as a regular class. Mark [classElement] as
122 // 'needed' to ensure the native superclass is needed. 130 // 'needed' to ensure the native superclass is needed.
123 needed = true; 131 needed = true;
124 } else if (!builder.isTrivial) { 132 } else if (!builder.isTrivial) {
125 needed = true; 133 needed = true;
126 } else if (neededByConstant.contains(classElement)) { 134 } else if (neededByConstant.contains(classElement)) {
127 needed = true; 135 needed = true;
128 } else if (modifiedClasses.contains(classElement)) { 136 } else if (modifiedClasses.contains(classElement)) {
129 // TODO(9556): Remove this test when [emitRuntimeTypeSupport] no longer 137 // TODO(9556): Remove this test when [emitRuntimeTypeSupport] no longer
130 // adds information to a class prototype or constructor. 138 // adds information to a class prototype or constructor.
131 needed = true; 139 needed = true;
132 } else if (extensionPoints.containsKey(classElement)) { 140 } else if (extensionPoints.containsKey(cls)) {
133 needed = true; 141 needed = true;
134 } 142 }
135 if (classElement.isNative && 143 if (cls.isNative &&
136 native.nativeTagsForcedNonLeaf(classElement)) { 144 native.nativeTagsForcedNonLeaf(classElement)) {
137 needed = true; 145 needed = true;
138 nonleafClasses.add(classElement); 146 nonleafClasses.add(cls);
139 } 147 }
140 148
141 if (needed || neededClasses.contains(classElement)) { 149 if (needed || neededClasses.contains(cls)) {
142 neededClasses.add(classElement); 150 neededClasses.add(cls);
143 neededClasses.add(classElement.superclass); 151 neededClasses.add(cls.superclass);
144 nonleafClasses.add(classElement.superclass); 152 nonleafClasses.add(cls.superclass);
145 } 153 }
146 } 154 }
147 155
148 // Collect all the tags that map to each native class. 156 // Collect all the tags that map to each native class.
149 157
150 Map<ClassElement, Set<String>> leafTags = 158 Map<Class, Set<String>> leafTags = new Map<Class, Set<String>>();
151 new Map<ClassElement, Set<String>>(); 159 Map<Class, Set<String>> nonleafTags = new Map<Class, Set<String>>();
152 Map<ClassElement, Set<String>> nonleafTags =
153 new Map<ClassElement, Set<String>>();
154 160
155 for (ClassElement classElement in classes) { 161 for (Class cls in classes) {
156 if (!classElement.isNative) continue; 162 if (!cls.isNative) continue;
157 List<String> nativeTags = native.nativeTagsOfClass(classElement); 163 List<String> nativeTags = native.nativeTagsOfClass(cls.element);
158 164
159 if (nonleafClasses.contains(classElement) || 165 if (nonleafClasses.contains(cls) ||
160 extensionPoints.containsKey(classElement)) { 166 extensionPoints.containsKey(cls)) {
161 nonleafTags 167 nonleafTags
162 .putIfAbsent(classElement, () => new Set<String>()) 168 .putIfAbsent(cls, () => new Set<String>())
163 .addAll(nativeTags); 169 .addAll(nativeTags);
164 } else { 170 } else {
165 ClassElement sufficingInterceptor = classElement; 171 Class sufficingInterceptor = cls;
166 while (!neededClasses.contains(sufficingInterceptor)) { 172 while (!neededClasses.contains(sufficingInterceptor)) {
167 sufficingInterceptor = sufficingInterceptor.superclass; 173 sufficingInterceptor = sufficingInterceptor.superclass;
168 } 174 }
169 if (sufficingInterceptor == compiler.objectClass) { 175 if (sufficingInterceptor == objectClass) {
170 sufficingInterceptor = backend.jsInterceptorClass; 176 sufficingInterceptor = jsInterceptorClass;
171 } 177 }
172 leafTags 178 leafTags
173 .putIfAbsent(sufficingInterceptor, () => new Set<String>()) 179 .putIfAbsent(sufficingInterceptor, () => new Set<String>())
174 .addAll(nativeTags); 180 .addAll(nativeTags);
175 } 181 }
176 } 182 }
177 183
178 // Add properties containing the information needed to construct maps used 184 // Add properties containing the information needed to construct maps used
179 // by getNativeInterceptor and custom elements. 185 // by getNativeInterceptor and custom elements.
180 if (compiler.enqueuer.codegen.nativeEnqueuer 186 if (compiler.enqueuer.codegen.nativeEnqueuer
181 .hasInstantiatedNativeClasses()) { 187 .hasInstantiatedNativeClasses()) {
182 void generateClassInfo(ClassElement classElement) { 188 void generateClassInfo(Class cls) {
183 // Property has the form: 189 // Property has the form:
184 // 190 //
185 // "%": "leafTag1|leafTag2|...;nonleafTag1|...;Class1|Class2|...", 191 // "%": "leafTag1|leafTag2|...;nonleafTag1|...;Class1|Class2|...",
186 // 192 //
187 // If there is no data following a semicolon, the semicolon can be 193 // If there is no data following a semicolon, the semicolon can be
188 // omitted. 194 // omitted.
189 195
190 String formatTags(Iterable<String> tags) { 196 String formatTags(Iterable<String> tags) {
191 if (tags == null) return ''; 197 if (tags == null) return '';
192 return (tags.toList()..sort()).join('|'); 198 return (tags.toList()..sort()).join('|');
193 } 199 }
194 200
195 List<ClassElement> extensions = extensionPoints[classElement]; 201 List<Class> extensions = extensionPoints[cls];
196 202
197 String leafStr = formatTags(leafTags[classElement]); 203 String leafStr = formatTags(leafTags[cls]);
198 String nonleafStr = formatTags(nonleafTags[classElement]); 204 String nonleafStr = formatTags(nonleafTags[cls]);
199 205
200 StringBuffer sb = new StringBuffer(leafStr); 206 StringBuffer sb = new StringBuffer(leafStr);
201 if (nonleafStr != '') { 207 if (nonleafStr != '') {
202 sb..write(';')..write(nonleafStr); 208 sb..write(';')..write(nonleafStr);
203 } 209 }
204 if (extensions != null) { 210 if (extensions != null) {
205 sb..write(';') 211 sb..write(';')
206 ..writeAll(extensions.map(backend.namer.getNameOfClass), '|'); 212 ..writeAll(extensions.map((Class cls) => cls.name), '|');
207 } 213 }
208 String encoding = sb.toString(); 214 String encoding = sb.toString();
209 215
210 ClassBuilder builder = builders[classElement]; 216 ClassBuilder builder = builders[cls];
211 if (builder == null) { 217 if (builder == null) {
212 // No builder because this is an intermediate mixin application or 218 // No builder because this is an intermediate mixin application or
213 // Interceptor - these are not direct native classes. 219 // Interceptor - these are not direct native classes.
214 if (encoding != '') { 220 if (encoding != '') {
215 Map<String, jsAst.Expression> properties = 221 Map<String, jsAst.Expression> properties =
216 additionalProperties.putIfAbsent(classElement, 222 additionalProperties.putIfAbsent(cls.element,
217 () => new Map<String, jsAst.Expression>()); 223 () => new Map<String, jsAst.Expression>());
218 properties[backend.namer.nativeSpecProperty] = js.string(encoding); 224 properties[backend.namer.nativeSpecProperty] = js.string(encoding);
219 } 225 }
220 } else { 226 } else {
221 builder.addProperty( 227 builder.addProperty(
222 backend.namer.nativeSpecProperty, js.string(encoding)); 228 backend.namer.nativeSpecProperty, js.string(encoding));
223 } 229 }
224 } 230 }
225 generateClassInfo(backend.jsInterceptorClass); 231 generateClassInfo(jsInterceptorClass);
226 for (ClassElement classElement in classes) { 232 for (Class cls in classes) {
227 generateClassInfo(classElement); 233 generateClassInfo(cls);
228 } 234 }
229 } 235 }
230 236
231 // Emit the native class interceptors that were actually used. 237 // Emit the native class interceptors that were actually used.
232 for (ClassElement classElement in classes) { 238 for (Class cls in classes) {
233 if (!classElement.isNative) continue; 239 ClassElement classElement = cls.element;
234 if (neededClasses.contains(classElement)) { 240 if (!cls.isNative) continue;
241 if (neededClasses.contains(cls)) {
235 // Define interceptor class for [classElement]. 242 // Define interceptor class for [classElement].
236 emitterTask.oldEmitter.classEmitter.emitClassBuilderWithReflectionData( 243 emitterTask.oldEmitter.classEmitter.emitClassBuilderWithReflectionData(
237 backend.namer.getNameOfClass(classElement), 244 cls.name,
238 classElement, builders[classElement], 245 classElement, builders[cls],
239 emitterTask.oldEmitter.getElementDescriptor(classElement)); 246 emitterTask.oldEmitter.getElementDescriptor(classElement));
240 emitterTask.oldEmitter.needsClassSupport = true; 247 emitterTask.oldEmitter.needsClassSupport = true;
241 } 248 }
242 } 249 }
243 } 250 }
244 251
245 /** 252 /**
246 * Computes the native classes that are extended (subclassed) by non-native 253 * Computes the native classes that are extended (subclassed) by non-native
247 * classes and the set non-mative classes that extend them. (A List is used 254 * classes and the set non-mative classes that extend them. (A List is used
248 * instead of a Set for out stability). 255 * instead of a Set for out stability).
249 */ 256 */
250 Map<ClassElement, List<ClassElement>> computeExtensionPoints( 257 Map<Class, List<Class>> computeExtensionPoints(List<Class> classes) {
251 List<ClassElement> classes) { 258 Class nativeSuperclassOf(Class cls) {
252 ClassElement nativeSuperclassOf(ClassElement element) { 259 if (cls == null) return null;
253 if (element == null) return null; 260 if (cls.isNative) return cls;
254 if (element.isNative) return element; 261 return nativeSuperclassOf(cls.superclass);
255 return nativeSuperclassOf(element.superclass);
256 } 262 }
257 263
258 ClassElement nativeAncestorOf(ClassElement element) { 264 Class nativeAncestorOf(Class cls) {
259 return nativeSuperclassOf(element.superclass); 265 return nativeSuperclassOf(cls.superclass);
260 } 266 }
261 267
262 Map<ClassElement, List<ClassElement>> map = 268 Map<Class, List<Class>> map = new Map<Class, List<Class>>();
263 new Map<ClassElement, List<ClassElement>>();
264 269
265 for (ClassElement classElement in classes) { 270 for (Class cls in classes) {
266 if (classElement.isNative) continue; 271 if (cls.isNative) continue;
267 ClassElement nativeAncestor = nativeAncestorOf(classElement); 272 Class nativeAncestor = nativeAncestorOf(cls);
268 if (nativeAncestor != null) { 273 if (nativeAncestor != null) {
269 map 274 map
270 .putIfAbsent(nativeAncestor, () => <ClassElement>[]) 275 .putIfAbsent(nativeAncestor, () => <Class>[])
271 .add(classElement); 276 .add(cls);
272 } 277 }
273 } 278 }
274 return map; 279 return map;
275 } 280 }
276 281
277 ClassBuilder generateNativeClass(ClassElement classElement) { 282 ClassBuilder generateNativeClass(Class cls) {
283 ClassElement classElement = cls.element;
284
278 // TODO(sra): Issue #13731- this is commented out as part of custom element 285 // TODO(sra): Issue #13731- this is commented out as part of custom element
279 // constructor work. 286 // constructor work.
280 //assert(!classElement.hasBackendMembers); 287 //assert(!classElement.hasBackendMembers);
281 hasNativeClasses = true; 288 hasNativeClasses = true;
282 289
283 ClassElement superclass = classElement.superclass; 290 Class superclass = cls.superclass;
284 assert(superclass != null); 291 assert(superclass != null);
285 // Fix superclass. TODO(sra): make native classes inherit from Interceptor. 292 assert(superclass.element != compiler.objectClass);
286 assert(superclass != compiler.objectClass);
287 if (superclass == compiler.objectClass) {
288 superclass = backend.jsInterceptorClass;
289 }
290
291 String superName = backend.namer.getNameOfClass(superclass);
292 293
293 ClassBuilder builder; 294 ClassBuilder builder;
294 if (compiler.hasIncrementalSupport) { 295 if (compiler.hasIncrementalSupport) {
295 builder = cachedBuilders[classElement]; 296 builder = cachedBuilders[classElement];
296 if (builder != null) return builder; 297 if (builder != null) return builder;
297 builder = new ClassBuilder(classElement, backend.namer); 298 builder = new ClassBuilder(classElement, backend.namer);
298 cachedBuilders[classElement] = builder; 299 cachedBuilders[classElement] = builder;
299 } else { 300 } else {
300 builder = new ClassBuilder(classElement, backend.namer); 301 builder = new ClassBuilder(classElement, backend.namer);
301 } 302 }
302 builder.superName = superName; 303 builder.superName = superclass.name;
303 304
304 emitterTask.oldEmitter.classEmitter.emitClassConstructor( 305 emitterTask.oldEmitter.classEmitter.emitClassConstructor(
305 classElement, builder); 306 classElement, builder);
306 bool hasFields = emitterTask.oldEmitter.classEmitter.emitFields( 307 bool hasFields = emitterTask.oldEmitter.classEmitter.emitFields(
307 classElement, builder, classIsNative: true); 308 classElement, builder, classIsNative: true);
308 int propertyCount = builder.properties.length; 309 int propertyCount = builder.properties.length;
309 emitterTask.oldEmitter.classEmitter.emitClassGettersSetters( 310 emitterTask.oldEmitter.classEmitter.emitClassGettersSetters(
310 classElement, builder); 311 classElement, builder);
311 emitterTask.oldEmitter.classEmitter.emitInstanceMembers( 312 emitterTask.oldEmitter.classEmitter.emitInstanceMembers(
312 classElement, builder); 313 classElement, builder);
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
470 targetOutput.add(';'); 471 targetOutput.add(';');
471 } 472 }
472 targetOutput.addBuffer(jsAst.prettyPrint( 473 targetOutput.addBuffer(jsAst.prettyPrint(
473 new jsAst.ExpressionStatement(init), compiler)); 474 new jsAst.ExpressionStatement(init), compiler));
474 targetOutput.add('\n'); 475 targetOutput.add('\n');
475 } 476 }
476 477
477 targetOutput.add('\n'); 478 targetOutput.add('\n');
478 } 479 }
479 } 480 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698