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

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

Issue 1207343003: dart2js: Create program_builder directory and move corresponding files. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 5 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
(Empty)
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
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.
4
5 library dart2js.js_emitter.program_builder;
6
7 import 'js_emitter.dart' show computeMixinClass;
8 import 'model.dart';
9
10 import '../common.dart';
11 import '../js/js.dart' as js;
12
13 import '../js_backend/js_backend.dart' show
14 Namer,
15 JavaScriptBackend,
16 JavaScriptConstantCompiler;
17
18 import 'js_emitter.dart' show
19 ClassStubGenerator,
20 CodeEmitterTask,
21 InterceptorStubGenerator,
22 MainCallStubGenerator,
23 ParameterStubGenerator,
24 RuntimeTypeGenerator,
25 TypeTestProperties;
26
27 import '../elements/elements.dart' show ParameterElement, MethodElement;
28
29 import '../universe/universe.dart' show Universe, TypeMaskSet;
30 import '../deferred_load.dart' show DeferredLoadTask, OutputUnit;
31
32 part 'registry.dart';
33
34 class ProgramBuilder {
35 final Compiler _compiler;
36 final Namer namer;
37 final CodeEmitterTask _task;
38
39 final Registry _registry;
40
41 /// True if the program should store function types in the metadata.
42 bool _storeFunctionTypesInMetadata = false;
43
44 ProgramBuilder(Compiler compiler,
45 this.namer,
46 this._task)
47 : this._compiler = compiler,
48 this._registry = new Registry(compiler);
49
50 JavaScriptBackend get backend => _compiler.backend;
51 Universe get universe => _compiler.codegenWorld;
52
53 /// Mapping from [ClassElement] to constructed [Class]. We need this to
54 /// update the superclass in the [Class].
55 final Map<ClassElement, Class> _classes = <ClassElement, Class>{};
56
57 /// Mapping from [OutputUnit] to constructed [Fragment]. We need this to
58 /// generate the deferredLoadingMap (to know which hunks to load).
59 final Map<OutputUnit, Fragment> _outputs = <OutputUnit, Fragment>{};
60
61 /// Mapping from [ConstantValue] to constructed [Constant]. We need this to
62 /// update field-initializers to point to the ConstantModel.
63 final Map<ConstantValue, Constant> _constants = <ConstantValue, Constant>{};
64
65 Set<Class> _unneededNativeClasses;
66
67 Program buildProgram({bool storeFunctionTypesInMetadata: false}) {
68 this._storeFunctionTypesInMetadata = storeFunctionTypesInMetadata;
69 // Note: In rare cases (mostly tests) output units can be empty. This
70 // happens when the deferred code is dead-code eliminated but we still need
71 // to check that the library has been loaded.
72 _compiler.deferredLoadTask.allOutputUnits.forEach(
73 _registry.registerOutputUnit);
74 _task.outputClassLists.forEach(_registry.registerElements);
75 _task.outputStaticLists.forEach(_registry.registerElements);
76 _task.outputConstantLists.forEach(_registerConstants);
77 _task.outputStaticNonFinalFieldLists.forEach(_registry.registerElements);
78
79 // TODO(kasperl): There's code that implicitly needs access to the special
80 // $ holder so we have to register that. Can we track if we have to?
81 _registry.registerHolder(r'$');
82
83 // We need to run the native-preparation before we build the output. The
84 // preparation code, in turn needs the classes to be set up.
85 // We thus build the classes before building their containers.
86 _task.outputClassLists.forEach((OutputUnit _, List<ClassElement> classes) {
87 classes.forEach(_buildClass);
88 });
89
90 // Resolve the superclass references after we've processed all the classes.
91 _classes.forEach((ClassElement element, Class c) {
92 if (element.superclass != null) {
93 c.setSuperclass(_classes[element.superclass]);
94 assert(c.superclass != null);
95 }
96 if (c is MixinApplication) {
97 c.setMixinClass(_classes[computeMixinClass(element)]);
98 assert(c.mixinClass != null);
99 }
100 });
101
102 List<Class> nativeClasses = _task.nativeClassesAndSubclasses
103 .map((ClassElement classElement) => _classes[classElement])
104 .toList();
105
106 _unneededNativeClasses =
107 _task.nativeEmitter.prepareNativeClasses(nativeClasses);
108
109 MainFragment mainFragment = _buildMainFragment(_registry.mainLibrariesMap);
110 Iterable<Fragment> deferredFragments =
111 _registry.deferredLibrariesMap.map(_buildDeferredFragment);
112
113 List<Fragment> fragments = new List<Fragment>(_registry.librariesMapCount);
114 fragments[0] = mainFragment;
115 fragments.setAll(1, deferredFragments);
116
117 _markEagerClasses();
118
119 List<Holder> holders = _registry.holders.toList(growable: false);
120
121 bool needsNativeSupport = _compiler.enqueuer.codegen.nativeEnqueuer
122 .hasInstantiatedNativeClasses();
123
124 assert(!needsNativeSupport || nativeClasses.isNotEmpty);
125
126 List<js.TokenFinalizer> finalizers = [_task.metadataCollector];
127 if (backend.namer is js.TokenFinalizer) {
128 var namingFinalizer = backend.namer;
129 finalizers.add(namingFinalizer);
130 }
131
132 return new Program(
133 fragments,
134 holders,
135 _buildLoadMap(),
136 _buildTypeToInterceptorMap(),
137 _task.metadataCollector,
138 finalizers,
139 needsNativeSupport: needsNativeSupport,
140 outputContainsConstantList: _task.outputContainsConstantList,
141 hasIsolateSupport: _compiler.hasIsolateSupport);
142 }
143
144 void _markEagerClasses() {
145 _markEagerInterceptorClasses();
146 }
147
148 /// Builds a map from loadId to outputs-to-load.
149 Map<String, List<Fragment>> _buildLoadMap() {
150 Map<String, List<Fragment>> loadMap = <String, List<Fragment>>{};
151 _compiler.deferredLoadTask.hunksToLoad
152 .forEach((String loadId, List<OutputUnit> outputUnits) {
153 loadMap[loadId] = outputUnits
154 .map((OutputUnit unit) => _outputs[unit])
155 .toList(growable: false);
156 });
157 return loadMap;
158 }
159
160 js.Expression _buildTypeToInterceptorMap() {
161 InterceptorStubGenerator stubGenerator =
162 new InterceptorStubGenerator(_compiler, namer, backend);
163 return stubGenerator.generateTypeToInterceptorMap();
164 }
165
166 MainFragment _buildMainFragment(LibrariesMap librariesMap) {
167 // Construct the main output from the libraries and the registered holders.
168 MainFragment result = new MainFragment(
169 librariesMap.outputUnit,
170 "", // The empty string is the name for the main output file.
171 _buildInvokeMain(),
172 _buildLibraries(librariesMap),
173 _buildStaticNonFinalFields(librariesMap),
174 _buildStaticLazilyInitializedFields(librariesMap),
175 _buildConstants(librariesMap));
176 _outputs[librariesMap.outputUnit] = result;
177 return result;
178 }
179
180 js.Statement _buildInvokeMain() {
181 MainCallStubGenerator generator =
182 new MainCallStubGenerator(_compiler, backend, backend.emitter);
183 return generator.generateInvokeMain();
184 }
185
186 DeferredFragment _buildDeferredFragment(LibrariesMap librariesMap) {
187 DeferredFragment result = new DeferredFragment(
188 librariesMap.outputUnit,
189 backend.deferredPartFileName(librariesMap.name, addExtension: false),
190 librariesMap.name,
191 _buildLibraries(librariesMap),
192 _buildStaticNonFinalFields(librariesMap),
193 _buildStaticLazilyInitializedFields(librariesMap),
194 _buildConstants(librariesMap));
195 _outputs[librariesMap.outputUnit] = result;
196 return result;
197 }
198
199 List<Constant> _buildConstants(LibrariesMap librariesMap) {
200 List<ConstantValue> constantValues =
201 _task.outputConstantLists[librariesMap.outputUnit];
202 if (constantValues == null) return const <Constant>[];
203 return constantValues.map((ConstantValue value) => _constants[value])
204 .toList(growable: false);
205 }
206
207 List<StaticField> _buildStaticNonFinalFields(LibrariesMap librariesMap) {
208 List<VariableElement> staticNonFinalFields =
209 _task.outputStaticNonFinalFieldLists[librariesMap.outputUnit];
210 if (staticNonFinalFields == null) return const <StaticField>[];
211
212 return staticNonFinalFields
213 .map(_buildStaticField)
214 .toList(growable: false);
215 }
216
217 StaticField _buildStaticField(Element element) {
218 JavaScriptConstantCompiler handler = backend.constants;
219 ConstantValue initialValue = handler.getInitialValueFor(element);
220 // TODO(zarah): The holder should not be registered during building of
221 // a static field.
222 _registry.registerHolder(namer.globalObjectForConstant(initialValue));
223 js.Expression code = _task.emitter.constantReference(initialValue);
224 js.Name name = namer.globalPropertyName(element);
225 bool isFinal = false;
226 bool isLazy = false;
227
228 // TODO(floitsch): we shouldn't update the registry in the middle of
229 // building a static field. (Note that the $ holder is already registered
230 // earlier).
231 return new StaticField(element,
232 name, _registry.registerHolder(r'$'), code,
233 isFinal, isLazy);
234 }
235
236 List<StaticField> _buildStaticLazilyInitializedFields(
237 LibrariesMap librariesMap) {
238 // TODO(floitsch): lazy fields should just be in their respective
239 // libraries.
240 if (librariesMap != _registry.mainLibrariesMap) {
241 return const <StaticField>[];
242 }
243
244 JavaScriptConstantCompiler handler = backend.constants;
245 List<VariableElement> lazyFields =
246 handler.getLazilyInitializedFieldsForEmission();
247 return Elements.sortedByPosition(lazyFields)
248 .map(_buildLazyField)
249 .where((field) => field != null) // Happens when the field was unused.
250 .toList(growable: false);
251 }
252
253 StaticField _buildLazyField(Element element) {
254 js.Expression code = backend.generatedCode[element];
255 // The code is null if we ended up not needing the lazily
256 // initialized field after all because of constant folding
257 // before code generation.
258 if (code == null) return null;
259
260 js.Name name = namer.globalPropertyName(element);
261 bool isFinal = element.isFinal;
262 bool isLazy = true;
263 // TODO(floitsch): we shouldn't update the registry in the middle of
264 // building a static field. (Note that the $ holder is already registered
265 // earlier).
266 return new StaticField(element,
267 name, _registry.registerHolder(r'$'), code,
268 isFinal, isLazy);
269 }
270
271 List<Library> _buildLibraries(LibrariesMap librariesMap) {
272 List<Library> libraries = new List<Library>(librariesMap.length);
273 int count = 0;
274 librariesMap.forEach((LibraryElement library, List<Element> elements) {
275 libraries[count++] = _buildLibrary(library, elements);
276 });
277 return libraries;
278 }
279
280 // Note that a library-element may have multiple [Library]s, if it is split
281 // into multiple output units.
282 Library _buildLibrary(LibraryElement library, List<Element> elements) {
283 String uri = library.canonicalUri.toString();
284
285 List<StaticMethod> statics = elements
286 .where((e) => e is FunctionElement)
287 .map(_buildStaticMethod)
288 .toList();
289
290 if (library == backend.interceptorsLibrary) {
291 statics.addAll(_generateGetInterceptorMethods());
292 statics.addAll(_generateOneShotInterceptors());
293 }
294
295 List<Class> classes = elements
296 .where((e) => e is ClassElement)
297 .map((ClassElement classElement) => _classes[classElement])
298 .where((Class cls) =>
299 !cls.isNative || !_unneededNativeClasses.contains(cls))
300 .toList(growable: false);
301
302 bool visitStatics = true;
303 List<Field> staticFieldsForReflection = _buildFields(library, visitStatics);
304
305 return new Library(library, uri, statics, classes,
306 staticFieldsForReflection);
307 }
308
309 /// HACK for Incremental Compilation.
310 ///
311 /// Returns a class that contains the fields of a class.
312 Class buildFieldsHackForIncrementalCompilation(ClassElement element) {
313 assert(_compiler.hasIncrementalSupport);
314
315 List<Field> instanceFields = _buildFields(element, false);
316 js.Name name = namer.className(element);
317
318 return new Class(
319 element, name, null, [], instanceFields, [], [], [], [], [], null,
320 isDirectlyInstantiated: true,
321 onlyForRti: false,
322 isNative: element.isNative);
323 }
324
325 Class _buildClass(ClassElement element) {
326 bool onlyForRti = _task.typeTestRegistry.rtiNeededClasses.contains(element);
327
328 List<Method> methods = [];
329 List<StubMethod> callStubs = <StubMethod>[];
330
331 ClassStubGenerator classStubGenerator =
332 new ClassStubGenerator(_compiler, namer, backend);
333 RuntimeTypeGenerator runtimeTypeGenerator =
334 new RuntimeTypeGenerator(_compiler, _task, namer);
335
336 void visitMember(ClassElement enclosing, Element member) {
337 assert(invariant(element, member.isDeclaration));
338 assert(invariant(element, element == enclosing));
339
340 if (Elements.isNonAbstractInstanceMember(member)) {
341 // TODO(herhut): Remove once _buildMethod can no longer return null.
342 Method method = _buildMethod(member);
343 if (method != null) methods.add(method);
344 }
345 if (member.isGetter || member.isField) {
346 Map<Selector, TypeMaskSet> selectors =
347 _compiler.codegenWorld.invocationsByName(member.name);
348 if (selectors != null && !selectors.isEmpty) {
349
350 Map<js.Name, js.Expression> callStubsForMember =
351 classStubGenerator.generateCallStubsForGetter(member, selectors);
352 callStubsForMember.forEach((js.Name name, js.Expression code) {
353 callStubs.add(_buildStubMethod(name, code, element: member));
354 });
355 }
356 }
357 }
358
359 List<StubMethod> typeVariableReaderStubs =
360 runtimeTypeGenerator.generateTypeVariableReaderStubs(element);
361
362 List<StubMethod> noSuchMethodStubs = <StubMethod>[];
363 if (backend.enabledNoSuchMethod && element == _compiler.objectClass) {
364 Map<js.Name, Selector> selectors =
365 classStubGenerator.computeSelectorsForNsmHandlers();
366 selectors.forEach((js.Name name, Selector selector) {
367 noSuchMethodStubs
368 .add(classStubGenerator.generateStubForNoSuchMethod(name,
369 selector));
370 });
371 }
372
373 if (element == backend.closureClass) {
374 // We add a special getter here to allow for tearing off a closure from
375 // itself.
376 js.Name name = namer.getterForMember(Selector.CALL_NAME);
377 js.Fun function = js.js('function() { return this; }');
378 callStubs.add(_buildStubMethod(name, function));
379 }
380
381 ClassElement implementation = element.implementation;
382
383 // MixinApplications run through the members of their mixin. Here, we are
384 // only interested in direct members.
385 if (!onlyForRti && !element.isMixinApplication) {
386 implementation.forEachMember(visitMember, includeBackendMembers: true);
387 }
388
389 List<Field> instanceFields =
390 onlyForRti ? const <Field>[] : _buildFields(element, false);
391 List<Field> staticFieldsForReflection =
392 onlyForRti ? const <Field>[] : _buildFields(element, true);
393
394 TypeTestProperties typeTests =
395 runtimeTypeGenerator.generateIsTests(
396 element,
397 storeFunctionTypeInMetadata: _storeFunctionTypesInMetadata);
398
399 List<StubMethod> isChecks = <StubMethod>[];
400 typeTests.properties.forEach((js.Name name, js.Node code) {
401 isChecks.add(_buildStubMethod(name, code));
402 });
403
404 js.Name name = namer.className(element);
405 String holderName = namer.globalObjectFor(element);
406 // TODO(floitsch): we shouldn't update the registry in the middle of
407 // building a class.
408 Holder holder = _registry.registerHolder(holderName);
409 bool isInstantiated =
410 _compiler.codegenWorld.directlyInstantiatedClasses.contains(element);
411
412 Class result;
413 if (element.isMixinApplication && !onlyForRti) {
414 assert(!element.isNative);
415 assert(methods.isEmpty);
416
417 result = new MixinApplication(element,
418 name, holder,
419 instanceFields,
420 staticFieldsForReflection,
421 callStubs,
422 typeVariableReaderStubs,
423 isChecks,
424 typeTests.functionTypeIndex,
425 isDirectlyInstantiated: isInstantiated,
426 onlyForRti: onlyForRti);
427 } else {
428 result = new Class(element,
429 name, holder, methods, instanceFields,
430 staticFieldsForReflection,
431 callStubs,
432 typeVariableReaderStubs,
433 noSuchMethodStubs,
434 isChecks,
435 typeTests.functionTypeIndex,
436 isDirectlyInstantiated: isInstantiated,
437 onlyForRti: onlyForRti,
438 isNative: element.isNative);
439 }
440 _classes[element] = result;
441 return result;
442 }
443
444 bool _methodNeedsStubs(FunctionElement method) {
445 return !method.functionSignature.optionalParameters.isEmpty;
446 }
447
448 bool _methodCanBeReflected(FunctionElement method) {
449 return backend.isAccessibleByReflection(method) ||
450 // During incremental compilation, we have to assume that reflection
451 // *might* get enabled.
452 _compiler.hasIncrementalSupport;
453 }
454
455 bool _methodCanBeApplied(FunctionElement method) {
456 return _compiler.enabledFunctionApply &&
457 _compiler.world.getMightBePassedToApply(method);
458 }
459
460 // TODO(herhut): Refactor incremental compilation and remove method.
461 Method buildMethodHackForIncrementalCompilation(FunctionElement element) {
462 assert(_compiler.hasIncrementalSupport);
463 if (element.isInstanceMember) {
464 return _buildMethod(element);
465 } else {
466 return _buildStaticMethod(element);
467 }
468 }
469
470 /* Map | List */ _computeParameterDefaultValues(FunctionSignature signature) {
471 var /* Map | List */ optionalParameterDefaultValues;
472 if (signature.optionalParametersAreNamed) {
473 optionalParameterDefaultValues = new Map<String, ConstantValue>();
474 signature.forEachOptionalParameter((ParameterElement parameter) {
475 ConstantValue def =
476 backend.constants.getConstantValueForVariable(parameter);
477 optionalParameterDefaultValues[parameter.name] = def;
478 });
479 } else {
480 optionalParameterDefaultValues = <ConstantValue>[];
481 signature.forEachOptionalParameter((ParameterElement parameter) {
482 ConstantValue def =
483 backend.constants.getConstantValueForVariable(parameter);
484 optionalParameterDefaultValues.add(def);
485 });
486 }
487 return optionalParameterDefaultValues;
488 }
489
490 DartMethod _buildMethod(MethodElement element) {
491 js.Name name = namer.methodPropertyName(element);
492 js.Expression code = backend.generatedCode[element];
493
494 // TODO(kasperl): Figure out under which conditions code is null.
495 if (code == null) return null;
496
497 bool canTearOff = false;
498 js.Name tearOffName;
499 bool isClosure = false;
500 bool isNotApplyTarget = !element.isFunction || element.isAccessor;
501
502 bool canBeReflected = _methodCanBeReflected(element);
503 bool canBeApplied = _methodCanBeApplied(element);
504
505 js.Name aliasName = backend.isAliasedSuperMember(element)
506 ? namer.aliasedSuperMemberPropertyName(element)
507 : null;
508
509 if (isNotApplyTarget) {
510 canTearOff = false;
511 } else {
512 if (element.enclosingClass.isClosure) {
513 canTearOff = false;
514 isClosure = true;
515 } else {
516 // Careful with operators.
517 canTearOff = universe.hasInvokedGetter(element, _compiler.world) ||
518 (canBeReflected && !element.isOperator);
519 assert(canTearOff ||
520 !universe.methodsNeedingSuperGetter.contains(element));
521 tearOffName = namer.getterForElement(element);
522 }
523 }
524
525 if (canTearOff) {
526 assert(invariant(element, !element.isGenerativeConstructor));
527 assert(invariant(element, !element.isGenerativeConstructorBody));
528 assert(invariant(element, !element.isConstructor));
529 }
530
531 js.Name callName = null;
532 if (canTearOff) {
533 Selector callSelector =
534 new Selector.fromElement(element).toCallSelector();
535 callName = namer.invocationName(callSelector);
536 }
537
538 DartType memberType;
539 if (element.isGenerativeConstructorBody) {
540 // TODO(herhut): Why does this need to be normalized away? We never need
541 // this information anyway as they cannot be torn off or
542 // reflected.
543 var body = element;
544 memberType = body.constructor.type;
545 } else {
546 memberType = element.type;
547 }
548
549 js.Expression functionType;
550 if (canTearOff || canBeReflected) {
551 OutputUnit outputUnit =
552 _compiler.deferredLoadTask.outputUnitForElement(element);
553 functionType = _generateFunctionType(memberType, outputUnit);
554 }
555
556 int requiredParameterCount;
557 var /* List | Map */ optionalParameterDefaultValues;
558 if (canBeApplied || canBeReflected) {
559 FunctionSignature signature = element.functionSignature;
560 requiredParameterCount = signature.requiredParameterCount;
561 optionalParameterDefaultValues =
562 _computeParameterDefaultValues(signature);
563 }
564
565 return new InstanceMethod(element, name, code,
566 _generateParameterStubs(element, canTearOff), callName,
567 needsTearOff: canTearOff, tearOffName: tearOffName,
568 isClosure: isClosure, aliasName: aliasName,
569 canBeApplied: canBeApplied, canBeReflected: canBeReflected,
570 requiredParameterCount: requiredParameterCount,
571 optionalParameterDefaultValues: optionalParameterDefaultValues,
572 functionType: functionType);
573 }
574
575 js.Expression _generateFunctionType(DartType type, OutputUnit outputUnit) {
576 if (type.containsTypeVariables) {
577 js.Expression thisAccess = js.js(r'this.$receiver');
578 return backend.rti.getSignatureEncoding(type, thisAccess);
579 } else {
580 return backend.emitter.metadataCollector
581 .reifyTypeForOutputUnit(type, outputUnit);
582 }
583 }
584
585 List<ParameterStubMethod> _generateParameterStubs(MethodElement element,
586 bool canTearOff) {
587
588 if (!_methodNeedsStubs(element)) return const <ParameterStubMethod>[];
589
590 ParameterStubGenerator generator =
591 new ParameterStubGenerator(_compiler, namer, backend);
592 return generator.generateParameterStubs(element, canTearOff: canTearOff);
593 }
594
595 /// Builds a stub method.
596 ///
597 /// Stub methods may have an element that can be used for code-size
598 /// attribution.
599 Method _buildStubMethod(js.Name name, js.Expression code,
600 {Element element}) {
601 return new StubMethod(name, code, element: element);
602 }
603
604 // The getInterceptor methods directly access the prototype of classes.
605 // We must evaluate these classes eagerly so that the prototype is
606 // accessible.
607 void _markEagerInterceptorClasses() {
608 Map<js.Name, Set<ClassElement>> specializedGetInterceptors =
609 backend.specializedGetInterceptors;
610 for (Set<ClassElement> classes in specializedGetInterceptors.values) {
611 for (ClassElement element in classes) {
612 Class cls = _classes[element];
613 if (cls != null) cls.isEager = true;
614 }
615 }
616 }
617
618 Iterable<StaticStubMethod> _generateGetInterceptorMethods() {
619 InterceptorStubGenerator stubGenerator =
620 new InterceptorStubGenerator(_compiler, namer, backend);
621
622 String holderName = namer.globalObjectFor(backend.interceptorsLibrary);
623 // TODO(floitsch): we shouldn't update the registry in the middle of
624 // generating the interceptor methods.
625 Holder holder = _registry.registerHolder(holderName);
626
627 Map<js.Name, Set<ClassElement>> specializedGetInterceptors =
628 backend.specializedGetInterceptors;
629 List<js.Name> names = specializedGetInterceptors.keys.toList()..sort();
630 return names.map((js.Name name) {
631 Set<ClassElement> classes = specializedGetInterceptors[name];
632 js.Expression code = stubGenerator.generateGetInterceptorMethod(classes);
633 return new StaticStubMethod(name, holder, code);
634 });
635 }
636
637 List<Field> _buildFields(Element holder, bool visitStatics) {
638 List<Field> fields = <Field>[];
639 _task.oldEmitter.classEmitter.visitFields(
640 holder, visitStatics, (VariableElement field,
641 js.Name name,
642 js.Name accessorName,
643 bool needsGetter,
644 bool needsSetter,
645 bool needsCheckedSetter) {
646 assert(invariant(field, field.isDeclaration));
647
648 int getterFlags = 0;
649 if (needsGetter) {
650 if (visitStatics || !backend.fieldHasInterceptedGetter(field)) {
651 getterFlags = 1;
652 } else {
653 getterFlags += 2;
654 // TODO(sra): 'isInterceptorClass' might not be the correct test
655 // for methods forced to use the interceptor convention because
656 // the method's class was elsewhere mixed-in to an interceptor.
657 if (!backend.isInterceptorClass(holder)) {
658 getterFlags += 1;
659 }
660 }
661 }
662
663 int setterFlags = 0;
664 if (needsSetter) {
665 if (visitStatics || !backend.fieldHasInterceptedSetter(field)) {
666 setterFlags = 1;
667 } else {
668 setterFlags += 2;
669 if (!backend.isInterceptorClass(holder)) {
670 setterFlags += 1;
671 }
672 }
673 }
674
675 fields.add(new Field(field, name, accessorName,
676 getterFlags, setterFlags,
677 needsCheckedSetter));
678 });
679
680 return fields;
681 }
682
683 Iterable<StaticStubMethod> _generateOneShotInterceptors() {
684 InterceptorStubGenerator stubGenerator =
685 new InterceptorStubGenerator(_compiler, namer, backend);
686
687 String holderName = namer.globalObjectFor(backend.interceptorsLibrary);
688 // TODO(floitsch): we shouldn't update the registry in the middle of
689 // generating the interceptor methods.
690 Holder holder = _registry.registerHolder(holderName);
691
692 List<js.Name> names = backend.oneShotInterceptors.keys.toList()..sort();
693 return names.map((js.Name name) {
694 js.Expression code = stubGenerator.generateOneShotInterceptor(name);
695 return new StaticStubMethod(name, holder, code);
696 });
697 }
698
699 StaticDartMethod _buildStaticMethod(FunctionElement element) {
700 js.Name name = namer.methodPropertyName(element);
701 String holder = namer.globalObjectFor(element);
702 js.Expression code = backend.generatedCode[element];
703
704 bool isApplyTarget = !element.isConstructor && !element.isAccessor;
705 bool canBeApplied = _methodCanBeApplied(element);
706 bool canBeReflected = _methodCanBeReflected(element);
707
708 bool needsTearOff = isApplyTarget &&
709 (canBeReflected ||
710 universe.staticFunctionsNeedingGetter.contains(element));
711
712 js.Name tearOffName =
713 needsTearOff ? namer.staticClosureName(element) : null;
714
715
716 js.Name callName = null;
717 if (needsTearOff) {
718 Selector callSelector =
719 new Selector.fromElement(element).toCallSelector();
720 callName = namer.invocationName(callSelector);
721 }
722 js.Expression functionType;
723 DartType type = element.type;
724 if (needsTearOff || canBeReflected) {
725 OutputUnit outputUnit =
726 _compiler.deferredLoadTask.outputUnitForElement(element);
727 functionType = _generateFunctionType(type, outputUnit);
728 }
729
730 int requiredParameterCount;
731 var /* List | Map */ optionalParameterDefaultValues;
732 if (canBeApplied || canBeReflected) {
733 FunctionSignature signature = element.functionSignature;
734 requiredParameterCount = signature.requiredParameterCount;
735 optionalParameterDefaultValues =
736 _computeParameterDefaultValues(signature);
737 }
738
739 // TODO(floitsch): we shouldn't update the registry in the middle of
740 // building a static method.
741 return new StaticDartMethod(element,
742 name, _registry.registerHolder(holder), code,
743 _generateParameterStubs(element, needsTearOff),
744 callName,
745 needsTearOff: needsTearOff,
746 tearOffName: tearOffName,
747 canBeApplied: canBeApplied,
748 canBeReflected: canBeReflected,
749 requiredParameterCount: requiredParameterCount,
750 optionalParameterDefaultValues:
751 optionalParameterDefaultValues,
752 functionType: functionType);
753 }
754
755 void _registerConstants(OutputUnit outputUnit,
756 Iterable<ConstantValue> constantValues) {
757 // `constantValues` is null if an outputUnit doesn't contain any constants.
758 if (constantValues == null) return;
759 for (ConstantValue constantValue in constantValues) {
760 _registry.registerConstant(outputUnit, constantValue);
761 assert(!_constants.containsKey(constantValue));
762 js.Name name = namer.constantName(constantValue);
763 String constantObject = namer.globalObjectForConstant(constantValue);
764 Holder holder = _registry.registerHolder(constantObject);
765 Constant constant = new Constant(name, holder, constantValue);
766 _constants[constantValue] = constant;
767 }
768 }
769 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698