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

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

Issue 2646733006: Use entities in native_emitter.dart (Closed)
Patch Set: Updated cf. comments. Created 3 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
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 library dart2js.js_emitter.native_emitter; 5 library dart2js.js_emitter.native_emitter;
6 6
7 import '../common.dart'; 7 import '../common.dart';
8 import '../compiler.dart' show Compiler; 8 import '../compiler.dart' show Compiler;
9 import '../elements/resolution_types.dart' 9 import '../elements/types.dart' show DartType, FunctionType;
10 show ResolutionDartType, ResolutionFunctionType; 10 import '../elements/entities.dart';
11 import '../elements/elements.dart'
12 show
13 ClassElement,
14 Element,
15 FunctionElement,
16 FunctionSignature,
17 MethodElement,
18 ParameterElement;
19 import '../js/js.dart' as jsAst; 11 import '../js/js.dart' as jsAst;
20 import '../js/js.dart' show js; 12 import '../js/js.dart' show js;
21 import '../js_backend/backend_helpers.dart' show BackendHelpers; 13 import '../js_backend/backend_helpers.dart' show BackendHelpers;
22 import '../js_backend/js_backend.dart' show JavaScriptBackend; 14 import '../js_backend/js_backend.dart' show JavaScriptBackend;
23 import 'full_emitter/emitter.dart' as full_js_emitter; 15 import '../universe/world_builder.dart' show CodegenWorldBuilder;
24 16
25 import 'code_emitter_task.dart' show CodeEmitterTask; 17 import 'code_emitter_task.dart' show CodeEmitterTask;
26 import 'model.dart'; 18 import 'model.dart';
27 19
28 class NativeEmitter { 20 class NativeEmitter {
29 // TODO(floitsch): the native-emitter should not know about ClassBuilders.
30 final Map<Element, full_js_emitter.ClassBuilder> cachedBuilders;
31
32 final CodeEmitterTask emitterTask; 21 final CodeEmitterTask emitterTask;
33 22
34 // Whether the application contains native classes. 23 // Whether the application contains native classes.
35 bool hasNativeClasses = false; 24 bool hasNativeClasses = false;
36 25
37 // Caches the native subtypes of a native class. 26 // Caches the native subtypes of a native class.
38 Map<ClassElement, List<ClassElement>> subtypes; 27 Map<ClassEntity, List<ClassEntity>> subtypes =
28 <ClassEntity, List<ClassEntity>>{};
39 29
40 // Caches the direct native subtypes of a native class. 30 // Caches the direct native subtypes of a native class.
41 Map<ClassElement, List<ClassElement>> directSubtypes; 31 Map<ClassEntity, List<ClassEntity>> directSubtypes =
32 <ClassEntity, List<ClassEntity>>{};
42 33
43 // Caches the methods that have a native body. 34 // Caches the methods that have a native body.
44 Set<FunctionElement> nativeMethods; 35 Set<FunctionEntity> nativeMethods = new Set<FunctionEntity>();
45 36
46 NativeEmitter(CodeEmitterTask emitterTask) 37 NativeEmitter(CodeEmitterTask emitterTask) : this.emitterTask = emitterTask;
47 : this.emitterTask = emitterTask,
48 subtypes = new Map<ClassElement, List<ClassElement>>(),
49 directSubtypes = new Map<ClassElement, List<ClassElement>>(),
50 nativeMethods = new Set<FunctionElement>(),
51 cachedBuilders = emitterTask.compiler.cacheStrategy.newMap();
52 38
53 Compiler get compiler => emitterTask.compiler; 39 Compiler get compiler => emitterTask.compiler;
54 40
55 JavaScriptBackend get backend => compiler.backend; 41 JavaScriptBackend get backend => compiler.backend;
56 42
57 BackendHelpers get helpers => backend.helpers; 43 BackendHelpers get helpers => backend.helpers;
58 44
45 CodegenWorldBuilder get worldBuilder => compiler.codegenWorldBuilder;
46
59 /** 47 /**
60 * Prepares native classes for emission. Returns the unneeded classes. 48 * Prepares native classes for emission. Returns the unneeded classes.
61 * 49 *
62 * Removes trivial classes (that can be represented by a super type) and 50 * Removes trivial classes (that can be represented by a super type) and
63 * generates properties that have to be added to classes (native or not). 51 * generates properties that have to be added to classes (native or not).
64 * 52 *
65 * Updates the `nativeLeafTags`, `nativeNonLeafTags` and `nativeExtensions` 53 * Updates the `nativeLeafTags`, `nativeNonLeafTags` and `nativeExtensions`
66 * fields of the given classes. This data must be emitted with the 54 * fields of the given classes. This data must be emitted with the
67 * corresponding classes. 55 * corresponding classes.
68 * 56 *
(...skipping 12 matching lines...) Expand all
81 * of native classes. 69 * of native classes.
82 * 70 *
83 * [interceptorClassesNeededByConstants] contains the interceptors that are 71 * [interceptorClassesNeededByConstants] contains the interceptors that are
84 * referenced by constants. 72 * referenced by constants.
85 * 73 *
86 * [classesModifiedByEmitRTISupport] contains the list of classes that must 74 * [classesModifiedByEmitRTISupport] contains the list of classes that must
87 * exist, because runtime-type support adds information to the class. 75 * exist, because runtime-type support adds information to the class.
88 */ 76 */
89 Set<Class> prepareNativeClasses( 77 Set<Class> prepareNativeClasses(
90 List<Class> classes, 78 List<Class> classes,
91 Set<ClassElement> interceptorClassesNeededByConstants, 79 Set<ClassEntity> interceptorClassesNeededByConstants,
92 Set<ClassElement> classesModifiedByEmitRTISupport) { 80 Set<ClassEntity> classesModifiedByEmitRTISupport) {
93 assert(classes.every((Class cls) => cls != null)); 81 assert(classes.every((Class cls) => cls != null));
94 82
95 hasNativeClasses = classes.isNotEmpty; 83 hasNativeClasses = classes.isNotEmpty;
96 84
97 // Compute a pre-order traversal of the subclass forest. We actually want a 85 // Compute a pre-order traversal of the subclass forest. We actually want a
98 // post-order traversal but it is easier to compute the pre-order and use it 86 // post-order traversal but it is easier to compute the pre-order and use it
99 // in reverse. 87 // in reverse.
100 List<Class> preOrder = <Class>[]; 88 List<Class> preOrder = <Class>[];
101 Set<Class> seen = new Set<Class>(); 89 Set<Class> seen = new Set<Class>();
102 90
(...skipping 22 matching lines...) Expand all
125 // needed class. 113 // needed class.
126 114
127 Set<Class> neededClasses = new Set<Class>(); 115 Set<Class> neededClasses = new Set<Class>();
128 Set<Class> nonLeafClasses = new Set<Class>(); 116 Set<Class> nonLeafClasses = new Set<Class>();
129 117
130 Map<Class, List<Class>> extensionPoints = computeExtensionPoints(preOrder); 118 Map<Class, List<Class>> extensionPoints = computeExtensionPoints(preOrder);
131 119
132 neededClasses.add(objectClass); 120 neededClasses.add(objectClass);
133 121
134 for (Class cls in preOrder.reversed) { 122 for (Class cls in preOrder.reversed) {
135 ClassElement classElement = cls.element; 123 ClassEntity classElement = cls.element;
136 // Post-order traversal ensures we visit the subclasses before their 124 // Post-order traversal ensures we visit the subclasses before their
137 // superclass. This makes it easy to tell if a class is needed because a 125 // superclass. This makes it easy to tell if a class is needed because a
138 // subclass is needed. 126 // subclass is needed.
139 bool needed = false; 127 bool needed = false;
140 if (!cls.isNative) { 128 if (!cls.isNative) {
141 // Mixin applications (native+mixin) are non-native, so [classElement] 129 // Mixin applications (native+mixin) are non-native, so [classElement]
142 // has already been emitted as a regular class. Mark [classElement] as 130 // has already been emitted as a regular class. Mark [classElement] as
143 // 'needed' to ensure the native superclass is needed. 131 // 'needed' to ensure the native superclass is needed.
144 needed = true; 132 needed = true;
145 } else if (!isTrivialClass(cls)) { 133 } else if (!isTrivialClass(cls)) {
146 needed = true; 134 needed = true;
147 } else if (interceptorClassesNeededByConstants.contains(classElement)) { 135 } else if (interceptorClassesNeededByConstants.contains(classElement)) {
148 needed = true; 136 needed = true;
149 } else if (classesModifiedByEmitRTISupport.contains(classElement)) { 137 } else if (classesModifiedByEmitRTISupport.contains(classElement)) {
150 // TODO(9556): Remove this test when [emitRuntimeTypeSupport] no longer 138 // TODO(9556): Remove this test when [emitRuntimeTypeSupport] no longer
151 // adds information to a class prototype or constructor. 139 // adds information to a class prototype or constructor.
152 needed = true; 140 needed = true;
153 } else if (extensionPoints.containsKey(cls)) { 141 } else if (extensionPoints.containsKey(cls)) {
154 needed = true; 142 needed = true;
155 } 143 }
156 if (backend.isJsInterop(classElement)) { 144 if (backend.isJsInteropClass(classElement)) {
157 needed = true; // TODO(jacobr): we don't need all interop classes. 145 needed = true; // TODO(jacobr): we don't need all interop classes.
158 } else if (cls.isNative && 146 } else if (cls.isNative &&
159 backend.nativeData.hasNativeTagsForcedNonLeaf(classElement)) { 147 backend.nativeData.hasNativeTagsForcedNonLeaf(classElement)) {
160 needed = true; 148 needed = true;
161 nonLeafClasses.add(cls); 149 nonLeafClasses.add(cls);
162 } 150 }
163 151
164 if (needed || neededClasses.contains(cls)) { 152 if (needed || neededClasses.contains(cls)) {
165 neededClasses.add(cls); 153 neededClasses.add(cls);
166 neededClasses.add(cls.superclass); 154 neededClasses.add(cls.superclass);
167 nonLeafClasses.add(cls.superclass); 155 nonLeafClasses.add(cls.superclass);
168 } 156 }
169 } 157 }
170 158
171 // Collect all the tags that map to each native class. 159 // Collect all the tags that map to each native class.
172 160
173 Map<Class, Set<String>> leafTags = new Map<Class, Set<String>>(); 161 Map<Class, Set<String>> leafTags = new Map<Class, Set<String>>();
174 Map<Class, Set<String>> nonleafTags = new Map<Class, Set<String>>(); 162 Map<Class, Set<String>> nonleafTags = new Map<Class, Set<String>>();
175 163
176 for (Class cls in classes) { 164 for (Class cls in classes) {
177 if (!cls.isNative) continue; 165 if (!cls.isNative) continue;
178 ClassElement element = cls.element; 166 ClassEntity element = cls.element;
179 if (backend.isJsInterop(element)) continue; 167 if (backend.isJsInteropClass(element)) continue;
180 List<String> nativeTags = 168 List<String> nativeTags =
181 backend.nativeData.getNativeTagsOfClass(cls.element); 169 backend.nativeData.getNativeTagsOfClass(cls.element);
182 170
183 if (nonLeafClasses.contains(cls) || extensionPoints.containsKey(cls)) { 171 if (nonLeafClasses.contains(cls) || extensionPoints.containsKey(cls)) {
184 nonleafTags 172 nonleafTags
185 .putIfAbsent(cls, () => new Set<String>()) 173 .putIfAbsent(cls, () => new Set<String>())
186 .addAll(nativeTags); 174 .addAll(nativeTags);
187 } else { 175 } else {
188 Class sufficingInterceptor = cls; 176 Class sufficingInterceptor = cls;
189 while (!neededClasses.contains(sufficingInterceptor)) { 177 while (!neededClasses.contains(sufficingInterceptor)) {
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 } 256 }
269 257
270 return cls.methods.isEmpty && 258 return cls.methods.isEmpty &&
271 cls.isChecks.isEmpty && 259 cls.isChecks.isEmpty &&
272 cls.callStubs.isEmpty && 260 cls.callStubs.isEmpty &&
273 !cls.superclass.isMixinApplication && 261 !cls.superclass.isMixinApplication &&
274 !cls.fields.any(needsAccessor); 262 !cls.fields.any(needsAccessor);
275 } 263 }
276 264
277 void potentiallyConvertDartClosuresToJs(List<jsAst.Statement> statements, 265 void potentiallyConvertDartClosuresToJs(List<jsAst.Statement> statements,
278 FunctionElement member, List<jsAst.Parameter> stubParameters) { 266 FunctionEntity member, List<jsAst.Parameter> stubParameters) {
279 FunctionSignature parameters = member.functionSignature; 267 FunctionEntity converter = helpers.closureConverter;
280 MethodElement converter = helpers.closureConverter;
281 jsAst.Expression closureConverter = 268 jsAst.Expression closureConverter =
282 emitterTask.staticFunctionAccess(converter); 269 emitterTask.staticFunctionAccess(converter);
283 parameters.forEachParameter((ParameterElement parameter) { 270 worldBuilder.forEachParameter(member, (DartType type, String name) {
284 String name = parameter.name;
285 // If [name] is not in [stubParameters], then the parameter is an optional 271 // If [name] is not in [stubParameters], then the parameter is an optional
286 // parameter that was not provided for this stub. 272 // parameter that was not provided for this stub.
287 for (jsAst.Parameter stubParameter in stubParameters) { 273 for (jsAst.Parameter stubParameter in stubParameters) {
288 if (stubParameter.name == name) { 274 if (stubParameter.name == name) {
289 ResolutionDartType type = parameter.type.unaliased; 275 type = type.unaliased;
290 if (type is ResolutionFunctionType) { 276 if (type.isFunctionType) {
291 // The parameter type is a function type either directly or through 277 // The parameter type is a function type either directly or through
292 // typedef(s). 278 // typedef(s).
293 ResolutionFunctionType functionType = type; 279 FunctionType functionType = type;
294 int arity = functionType.computeArity(); 280 int arity = functionType.parameterTypes.length;
295 statements.add(js 281 statements.add(js
296 .statement('# = #(#, $arity)', [name, closureConverter, name])); 282 .statement('# = #(#, $arity)', [name, closureConverter, name]));
297 break; 283 break;
298 } 284 }
299 } 285 }
300 } 286 }
301 }); 287 });
302 } 288 }
303 289
304 List<jsAst.Statement> generateParameterStubStatements( 290 List<jsAst.Statement> generateParameterStubStatements(
305 FunctionElement member, 291 FunctionEntity member,
306 bool isInterceptedMethod, 292 bool isInterceptedMethod,
307 jsAst.Name invocationName, 293 jsAst.Name invocationName,
308 List<jsAst.Parameter> stubParameters, 294 List<jsAst.Parameter> stubParameters,
309 List<jsAst.Expression> argumentsBuffer, 295 List<jsAst.Expression> argumentsBuffer,
310 int indexOfLastOptionalArgumentInParameters) { 296 int indexOfLastOptionalArgumentInParameters) {
311 // The target JS function may check arguments.length so we need to 297 // The target JS function may check arguments.length so we need to
312 // make sure not to pass any unspecified optional arguments to it. 298 // make sure not to pass any unspecified optional arguments to it.
313 // For example, for the following Dart method: 299 // For example, for the following Dart method:
314 // foo({x, y, z}); 300 // foo({x, y, z});
315 // The call: 301 // The call:
(...skipping 15 matching lines...) Expand all
331 317
332 if (isInterceptedMethod) { 318 if (isInterceptedMethod) {
333 receiver = argumentsBuffer[0]; 319 receiver = argumentsBuffer[0];
334 arguments = argumentsBuffer.sublist( 320 arguments = argumentsBuffer.sublist(
335 1, indexOfLastOptionalArgumentInParameters + 1); 321 1, indexOfLastOptionalArgumentInParameters + 1);
336 } else { 322 } else {
337 // Native methods that are not intercepted must be static. 323 // Native methods that are not intercepted must be static.
338 assert(invariant(member, member.isStatic)); 324 assert(invariant(member, member.isStatic));
339 arguments = argumentsBuffer.sublist( 325 arguments = argumentsBuffer.sublist(
340 0, indexOfLastOptionalArgumentInParameters + 1); 326 0, indexOfLastOptionalArgumentInParameters + 1);
341 if (backend.isJsInterop(member)) { 327 if (backend.isJsInteropMethod(member)) {
342 // fixedBackendPath is allowed to have the form foo.bar.baz for 328 // fixedBackendPath is allowed to have the form foo.bar.baz for
343 // interop. This template is uncached to avoid possibly running out of 329 // interop. This template is uncached to avoid possibly running out of
344 // memory when Dart2Js is run in server mode. In reality the risk of 330 // memory when Dart2Js is run in server mode. In reality the risk of
345 // caching these templates causing an issue is very low as each class 331 // caching these templates causing an issue is very low as each class
346 // and library that uses typed JavaScript interop will create only 1 332 // and library that uses typed JavaScript interop will create only 1
347 // unique template. 333 // unique template.
348 receiver = js 334 receiver = js
349 .uncachedExpressionTemplate(backend.namer.fixedBackendPath(member)) 335 .uncachedExpressionTemplate(
336 backend.namer.fixedBackendMethodPath(member))
350 .instantiate([]); 337 .instantiate([]);
351 } else { 338 } else {
352 receiver = js('this'); 339 receiver = js('this');
353 } 340 }
354 } 341 }
355 statements 342 statements
356 .add(js.statement('return #.#(#)', [receiver, target, arguments])); 343 .add(js.statement('return #.#(#)', [receiver, target, arguments]));
357 344
358 return statements; 345 return statements;
359 } 346 }
360 347
361 bool isSupertypeOfNativeClass(ClassElement element) { 348 bool isSupertypeOfNativeClass(ClassEntity element) {
362 if (backend.classesMixedIntoInterceptedClasses.contains(element)) { 349 if (backend.classesMixedIntoInterceptedClasses.contains(element)) {
363 return true; 350 return true;
364 } 351 }
365 352
366 return subtypes[element] != null; 353 return subtypes[element] != null;
367 } 354 }
368 355
369 bool requiresNativeIsCheck(Element element) { 356 bool requiresNativeIsCheck(ClassEntity element) {
370 // TODO(sra): Remove this function. It determines if a native type may 357 // TODO(sra): Remove this function. It determines if a native type may
371 // satisfy a check against [element], in which case an interceptor must be 358 // satisfy a check against [element], in which case an interceptor must be
372 // used. We should also use an interceptor if the check can't be satisfied 359 // used. We should also use an interceptor if the check can't be satisfied
373 // by a native class in case we get a native instance that tries to spoof 360 // by a native class in case we get a native instance that tries to spoof
374 // the type info. i.e the criteria for whether or not to use an interceptor 361 // the type info. i.e the criteria for whether or not to use an interceptor
375 // is whether the receiver can be native, not the type of the test. 362 // is whether the receiver can be native, not the type of the test.
376 if (element == null || !element.isClass) return false; 363 ClassEntity cls = element;
377 ClassElement cls = element;
378 if (backend.isNativeOrExtendsNative(cls)) return true; 364 if (backend.isNativeOrExtendsNative(cls)) return true;
379 return isSupertypeOfNativeClass(element); 365 return isSupertypeOfNativeClass(element);
380 } 366 }
381 } 367 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart ('k') | pkg/compiler/lib/src/native/enqueue.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698