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

Side by Side Diff: pkg/fletchc/lib/src/fletch_backend.dart

Issue 1659163007: Rename fletch -> dartino (Closed) Base URL: https://github.com/dartino/sdk.git@master
Patch Set: Created 4 years, 10 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) 2015, the Dartino 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.md file.
4
5 library fletchc.fletch_backend;
6
7 import 'dart:async' show
8 Future;
9
10 import 'dart:collection' show
11 Queue;
12
13 import 'package:compiler/src/common/backend_api.dart' show
14 Backend,
15 ImpactTransformer;
16
17 import 'package:compiler/src/common/tasks.dart' show
18 CompilerTask;
19
20 import 'package:compiler/src/enqueue.dart' show
21 Enqueuer,
22 ResolutionEnqueuer;
23
24 import 'package:compiler/src/diagnostics/messages.dart' show
25 MessageKind;
26
27 import 'package:compiler/src/diagnostics/diagnostic_listener.dart' show
28 DiagnosticMessage;
29
30 import 'package:compiler/src/common/registry.dart' show
31 Registry;
32
33 import 'package:compiler/src/dart_types.dart' show
34 DartType,
35 InterfaceType;
36
37 import 'package:compiler/src/tree/tree.dart' show
38 DartString,
39 EmptyStatement,
40 Expression;
41
42 import 'package:compiler/src/elements/elements.dart' show
43 AbstractFieldElement,
44 AstElement,
45 ClassElement,
46 ConstructorElement,
47 Element,
48 ExecutableElement,
49 FieldElement,
50 FormalElement,
51 FunctionElement,
52 FunctionSignature,
53 FunctionTypedElement,
54 LibraryElement,
55 MemberElement,
56 Name,
57 ParameterElement,
58 PublicName;
59
60 import 'package:compiler/src/universe/selector.dart' show
61 Selector;
62
63 import 'package:compiler/src/universe/use.dart' show
64 DynamicUse,
65 StaticUse,
66 TypeUse,
67 TypeUseKind;
68
69 import 'package:compiler/src/universe/call_structure.dart' show
70 CallStructure;
71
72 import 'package:compiler/src/common.dart' show
73 Spannable;
74
75 import 'package:compiler/src/elements/modelx.dart' show
76 FunctionElementX;
77
78 import 'package:compiler/src/dart_backend/dart_backend.dart' show
79 DartConstantTask;
80
81 import 'package:compiler/src/constants/constant_system.dart' show
82 ConstantSystem;
83
84 import 'package:compiler/src/compile_time_constants.dart' show
85 BackendConstantEnvironment;
86
87 import 'package:compiler/src/constants/values.dart' show
88 ConstantValue,
89 ConstructedConstantValue,
90 FunctionConstantValue,
91 ListConstantValue,
92 MapConstantValue,
93 StringConstantValue;
94
95 import 'package:compiler/src/constants/expressions.dart' show
96 ConstantExpression;
97
98 import 'package:compiler/src/resolution/tree_elements.dart' show
99 TreeElements;
100
101 import 'package:compiler/src/library_loader.dart' show
102 LibraryLoader;
103
104 import 'package:persistent/persistent.dart' show
105 PersistentMap;
106
107 import 'fletch_function_builder.dart' show
108 FletchFunctionBuilder;
109
110 import 'fletch_class_builder.dart' show
111 FletchClassBuilder;
112
113 import 'fletch_system_builder.dart' show
114 FletchSystemBuilder;
115
116 import '../incremental_backend.dart' show
117 IncrementalFletchBackend;
118
119 import 'fletch_enqueuer.dart' show
120 FletchEnqueueTask,
121 shouldReportEnqueuingOfElement;
122
123 import 'fletch_registry.dart' show
124 ClosureKind,
125 FletchRegistry;
126
127 import 'diagnostic.dart' show
128 throwInternalError;
129
130 import 'package:compiler/src/common/names.dart' show
131 Identifiers,
132 Names;
133
134 import 'package:compiler/src/universe/world_impact.dart' show
135 TransformedWorldImpact,
136 WorldImpact,
137 WorldImpactBuilder;
138
139 import 'class_debug_info.dart';
140 import 'codegen_visitor.dart';
141 import 'debug_info.dart';
142 import 'debug_info_constructor_codegen.dart';
143 import 'debug_info_function_codegen.dart';
144 import 'debug_info_lazy_field_initializer_codegen.dart';
145 import 'fletch_context.dart';
146 import 'fletch_selector.dart';
147 import 'function_codegen.dart';
148 import 'lazy_field_initializer_codegen.dart';
149 import 'constructor_codegen.dart';
150 import 'closure_environment.dart';
151
152 import '../bytecodes.dart';
153 import '../vm_commands.dart';
154 import '../fletch_system.dart';
155 import 'package:compiler/src/common/resolution.dart';
156
157 const FletchSystem BASE_FLETCH_SYSTEM = const FletchSystem(
158 const PersistentMap<int, FletchFunction>(),
159 const PersistentMap<Element, FletchFunction>(),
160 const PersistentMap<ConstructorElement, FletchFunction>(),
161 const PersistentMap<int, int>(),
162 const PersistentMap<int, FletchClass>(),
163 const PersistentMap<ClassElement, FletchClass>(),
164 const PersistentMap<int, FletchConstant>(),
165 const PersistentMap<ConstantValue, FletchConstant>(),
166 const PersistentMap<int, String>(),
167 const PersistentMap<int, int>(),
168 const PersistentMap<int, int>(),
169 const PersistentMap<ParameterStubSignature, FletchFunction>());
170
171 class FletchBackend extends Backend
172 implements IncrementalFletchBackend {
173 static const String growableListName = '_GrowableList';
174 static const String constantListName = '_ConstantList';
175 static const String constantByteListName = '_ConstantByteList';
176 static const String constantMapName = '_ConstantMap';
177 static const String fletchNoSuchMethodErrorName = 'FletchNoSuchMethodError';
178 static const String noSuchMethodName = '_noSuchMethod';
179 static const String noSuchMethodTrampolineName = '_noSuchMethodTrampoline';
180
181 final FletchContext context;
182
183 final DartConstantTask constantCompilerTask;
184
185 /// Constructors that need to have an initilizer compiled. See
186 /// [compilePendingConstructorInitializers].
187 final Queue<FletchFunctionBuilder> pendingConstructorInitializers =
188 new Queue<FletchFunctionBuilder>();
189
190 final Set<FunctionElement> externals = new Set<FunctionElement>();
191
192 // TODO(ahe): This should be queried from World.
193 final Map<ClassElement, Set<ClassElement>> directSubclasses =
194 <ClassElement, Set<ClassElement>>{};
195
196 /// Set of classes that have special meaning to the Fletch VM. They're
197 /// created using [PushBuiltinClass] instead of [PushNewClass].
198 // TODO(ahe): Move this to FletchSystem?
199 final Set<ClassElement> builtinClasses = new Set<ClassElement>();
200
201 // TODO(ahe): This should be invalidated by a new [FletchSystem].
202 final Map<MemberElement, ClosureEnvironment> closureEnvironments =
203 <MemberElement, ClosureEnvironment>{};
204
205 // TODO(ahe): This should be moved to [FletchSystem].
206 final Map<FunctionElement, FletchClassBuilder> closureClasses =
207 <FunctionElement, FletchClassBuilder>{};
208
209 // TODO(ahe): This should be moved to [FletchSystem].
210 final Map<FieldElement, FletchFunctionBuilder> lazyFieldInitializers =
211 <FieldElement, FletchFunctionBuilder>{};
212
213 // TODO(ahe): This should be moved to [FletchSystem].
214 Map<FletchClassBuilder, FletchFunctionBuilder> tearoffFunctions;
215
216 FletchCompilerImplementation get compiler => super.compiler;
217
218 LibraryElement fletchSystemLibrary;
219 LibraryElement fletchFFILibrary;
220 LibraryElement collectionLibrary;
221 LibraryElement mathLibrary;
222 LibraryElement get asyncLibrary => compiler.asyncLibrary;
223 LibraryElement fletchLibrary;
224
225 FunctionElement fletchSystemEntry;
226
227 FunctionElement fletchExternalInvokeMain;
228
229 FunctionElement fletchExternalYield;
230
231 FunctionElement fletchExternalNativeError;
232
233 FunctionElement fletchExternalCoroutineChange;
234
235 FunctionElement fletchUnresolved;
236 FunctionElement fletchCompileError;
237
238 FletchClassBuilder compiledObjectClass;
239
240 ClassElement smiClass;
241 ClassElement mintClass;
242 ClassElement growableListClass;
243 ClassElement fletchNoSuchMethodErrorClass;
244 ClassElement bigintClass;
245 ClassElement uint32DigitsClass;
246
247 FletchClassBuilder compiledClosureClass;
248
249 /// Holds a reference to the class Coroutine if it exists.
250 ClassElement coroutineClass;
251
252 FletchSystemBuilder systemBuilder;
253
254 final Set<FunctionElement> alwaysEnqueue = new Set<FunctionElement>();
255
256 FletchImpactTransformer impactTransformer;
257
258 FletchBackend(FletchCompilerImplementation compiler)
259 : this.context = compiler.context,
260 this.constantCompilerTask = new DartConstantTask(compiler),
261 this.systemBuilder = new FletchSystemBuilder(BASE_FLETCH_SYSTEM),
262 super(compiler) {
263 this.impactTransformer = new FletchImpactTransformer(this);
264 }
265
266 void newSystemBuilder(FletchSystem predecessorSystem) {
267 systemBuilder = new FletchSystemBuilder(predecessorSystem);
268 }
269
270 // TODO(zarah): Move to FletchSystemBuilder.
271 FletchClassBuilder getClassBuilderOfExistingClass(int id) {
272 FletchClassBuilder classBuilder = systemBuilder.lookupClassBuilder(id);
273 if (classBuilder != null) return classBuilder;
274 FletchClass klass = systemBuilder.lookupClass(id);
275 if (klass.element != null) return registerClassElement(klass.element);
276 // [klass] is a tearoff class
277 return systemBuilder.newPatchClassBuilder(id, compiledClosureClass);
278 }
279
280 FletchClassBuilder registerClassElement(ClassElement element) {
281 if (element == null) return null;
282 assert(element.isDeclaration);
283
284 FletchClassBuilder classBuilder =
285 systemBuilder.lookupClassBuilderByElement(element);
286 if (classBuilder != null) return classBuilder;
287
288 directSubclasses[element] = new Set<ClassElement>();
289 FletchClassBuilder superclass = registerClassElement(element.superclass);
290 if (superclass != null) {
291 Set<ClassElement> subclasses = directSubclasses[element.superclass];
292 subclasses.add(element);
293 }
294 classBuilder = systemBuilder.newClassBuilder(
295 element, superclass, builtinClasses.contains(element));
296
297 // TODO(ajohnsen): Currently, the FletchRegistry does not enqueue fields.
298 // This is a workaround, where we basically add getters for all fields.
299 classBuilder.updateImplicitAccessors(this);
300
301 Element callMember = element.lookupLocalMember(Identifiers.call);
302 if (callMember != null && callMember.isFunction) {
303 FunctionElement function = callMember;
304 classBuilder.createIsFunctionEntry(
305 this, function.functionSignature.parameterCount);
306 }
307 return classBuilder;
308 }
309
310 FletchClassBuilder createCallableStubClass(
311 int fields, int arity, FletchClassBuilder superclass) {
312 FletchClassBuilder classBuilder = systemBuilder.newClassBuilder(
313 null, superclass, false, extraFields: fields);
314 classBuilder.createIsFunctionEntry(this, arity);
315 return classBuilder;
316 }
317
318 List<CompilerTask> get tasks => <CompilerTask>[];
319
320 ConstantSystem get constantSystem {
321 return constantCompilerTask.constantCompiler.constantSystem;
322 }
323
324 BackendConstantEnvironment get constants => constantCompilerTask;
325
326 bool classNeedsRti(ClassElement cls) => false;
327
328 bool methodNeedsRti(FunctionElement function) => false;
329
330 void enqueueHelpers(ResolutionEnqueuer world, Registry incomingRegistry) {
331 FletchRegistry registry = new FletchRegistry(compiler);
332 compiler.patchAnnotationClass = patchAnnotationClass;
333
334 bool hasMissingHelpers = false;
335 loadHelperMethods((String name) {
336 LibraryElement library = fletchSystemLibrary;
337 Element helper = library.findLocal(name);
338 // TODO(ahe): Make it cleaner.
339 if (helper != null && helper.isAbstractField) {
340 AbstractFieldElement abstractField = helper;
341 helper = abstractField.getter;
342 }
343 if (helper == null) {
344 hasMissingHelpers = true;
345 compiler.reporter.reportErrorMessage(
346 library, MessageKind.GENERIC,
347 {'text': "Required implementation method '$name' not found."});
348 }
349 return helper;
350 });
351 if (hasMissingHelpers) {
352 throwInternalError(
353 "Some implementation methods are missing, see details above");
354 }
355 world.registerStaticUse(
356 new StaticUse.staticInvoke(fletchCompileError, CallStructure.ONE_ARG));
357 world.registerStaticUse(
358 new StaticUse.staticInvoke(fletchSystemEntry, CallStructure.ONE_ARG));
359 world.registerStaticUse(
360 new StaticUse.staticInvoke(fletchUnresolved, CallStructure.ONE_ARG));
361
362 loadHelperClasses((
363 String name,
364 LibraryElement library,
365 {bool builtin: false}) {
366 var classImpl = library.findLocal(name);
367 if (classImpl == null) classImpl = library.implementation.find(name);
368 if (classImpl == null) {
369 compiler.reporter.reportErrorMessage(
370 library, MessageKind.GENERIC,
371 {'text': "Required implementation class '$name' not found."});
372 hasMissingHelpers = true;
373 return null;
374 }
375 if (hasMissingHelpers) return null;
376 if (builtin) builtinClasses.add(classImpl);
377 {
378 // TODO(ahe): Register in ResolutionCallbacks. The lines in this block
379 // should not happen at this point in time.
380 classImpl.ensureResolved(compiler.resolution);
381 world.registerInstantiatedType(classImpl.rawType);
382 // TODO(ahe): This is a hack to let both the world and the codegen know
383 // about the instantiated type.
384 registry.registerInstantiatedType(classImpl.rawType);
385 }
386 return registerClassElement(classImpl);
387 });
388 if (hasMissingHelpers) {
389 throwInternalError(
390 "Some implementation classes are missing, see details above");
391 }
392
393 // Register list constructors to world.
394 // TODO(ahe): Register growableListClass through ResolutionCallbacks.
395 growableListClass.constructors.forEach((Element element) {
396 world.registerStaticUse(new StaticUse.constructorInvoke(element, null));
397 });
398
399 // TODO(ajohnsen): Remove? String interpolation does not enqueue '+'.
400 // Investigate what else it may enqueue, could be StringBuilder, and then
401 // consider using that instead.
402 world.registerDynamicUse(
403 new DynamicUse(new Selector.binaryOperator('+'), null));
404
405 world.registerDynamicUse(new DynamicUse(
406 new Selector.call(new PublicName('add'), CallStructure.ONE_ARG), null));
407
408 alwaysEnqueue.add(
409 compiler.coreClasses.objectClass.implementation.lookupLocalMember(
410 noSuchMethodTrampolineName));
411 alwaysEnqueue.add(
412 compiler.coreClasses.objectClass.implementation.lookupLocalMember(
413 noSuchMethodName));
414
415 if (coroutineClass != null) {
416 builtinClasses.add(coroutineClass);
417 alwaysEnqueue.add(coroutineClass.lookupLocalMember("_coroutineStart"));
418 }
419
420 for (FunctionElement element in alwaysEnqueue) {
421 world.registerStaticUse(new StaticUse.foreignUse(element));
422 }
423 }
424
425 void loadHelperMethods(
426 FunctionElement findHelper(String name)) {
427
428 FunctionElement findExternal(String name) {
429 FunctionElement helper = findHelper(name);
430 if (helper != null) externals.add(helper);
431 return helper;
432 }
433
434 fletchSystemEntry = findHelper('entry');
435 fletchExternalInvokeMain = findExternal('invokeMain');
436 fletchExternalYield = findExternal('yield');
437 fletchExternalCoroutineChange = findExternal('coroutineChange');
438 fletchExternalNativeError = findExternal('nativeError');
439 fletchUnresolved = findExternal('unresolved');
440 fletchCompileError = findExternal('compileError');
441 }
442
443 void loadHelperClasses(
444 FletchClassBuilder loadClass(
445 String name,
446 LibraryElement library,
447 {bool builtin})) {
448 compiledObjectClass =
449 loadClass("Object", compiler.coreLibrary, builtin: true);
450 compiledClosureClass =
451 loadClass("_TearOffClosure", compiler.coreLibrary, builtin: true);
452 smiClass = loadClass("_Smi", compiler.coreLibrary, builtin: true)?.element;
453 mintClass =
454 loadClass("_Mint", compiler.coreLibrary, builtin: true)?.element;
455 loadClass("_OneByteString", compiler.coreLibrary, builtin: true);
456 loadClass("_TwoByteString", compiler.coreLibrary, builtin: true);
457 // TODO(ahe): Register _ConstantList through ResolutionCallbacks.
458 loadClass(constantListName, fletchSystemLibrary, builtin: true);
459 loadClass(constantByteListName, fletchSystemLibrary, builtin: true);
460 loadClass(constantMapName, fletchSystemLibrary, builtin: true);
461 loadClass("_DoubleImpl", compiler.coreLibrary, builtin: true);
462 loadClass("Null", compiler.coreLibrary, builtin: true);
463 loadClass("bool", compiler.coreLibrary, builtin: true);
464 loadClass("StackOverflowError", compiler.coreLibrary, builtin: true);
465 loadClass("Port", fletchLibrary, builtin: true);
466 loadClass("Process", fletchLibrary, builtin: true);
467 loadClass("ProcessDeath", fletchLibrary, builtin: true);
468 loadClass("ForeignMemory", fletchFFILibrary, builtin: true);
469 if (context.enableBigint) {
470 bigintClass = loadClass("_Bigint", compiler.coreLibrary)?.element;
471 uint32DigitsClass =
472 loadClass("_Uint32Digits", compiler.coreLibrary)?.element;
473 }
474 growableListClass =
475 loadClass(growableListName, fletchSystemLibrary)?.element;
476 fletchNoSuchMethodErrorClass =
477 loadClass(fletchNoSuchMethodErrorName,
478 fletchSystemLibrary,
479 builtin: true)?.element;
480
481 // This class is optional.
482 coroutineClass = fletchSystemLibrary.implementation.find("Coroutine");
483 if (coroutineClass != null) {
484 coroutineClass.ensureResolved(compiler.resolution);
485 }
486 }
487
488 void onElementResolved(Element element, TreeElements elements) {
489 if (alwaysEnqueue.contains(element)) {
490 var registry = new FletchRegistry(compiler);
491 if (element.isStatic || element.isTopLevel) {
492 registry.registerStaticUse(new StaticUse.foreignUse(element));
493 } else {
494 registry.registerDynamicUse(new Selector.fromElement(element));
495 }
496 }
497 }
498
499 ClassElement get intImplementation => smiClass;
500
501 /// Class of annotations to mark patches in patch files.
502 ///
503 /// The patch parser (pkg/compiler/lib/src/patch_parser.dart). The patch
504 /// parser looks for an annotation on the form "@patch", where "patch" is
505 /// compile-time constant instance of [patchAnnotationClass].
506 ClassElement get patchAnnotationClass {
507 // TODO(ahe): Introduce a proper constant class to identify constants. For
508 // now, we simply put "const patch = "patch";" in fletch._system.
509 return super.stringImplementation;
510 }
511
512 FletchClassBuilder createClosureClass(
513 FunctionElement closure,
514 ClosureEnvironment closureEnvironment) {
515 return closureClasses.putIfAbsent(closure, () {
516 ClosureInfo info = closureEnvironment.closures[closure];
517 int fields = info.free.length;
518 if (info.isThisFree) fields++;
519 return createCallableStubClass(
520 fields,
521 closure.functionSignature.parameterCount,
522 compiledClosureClass);
523 });
524 }
525
526 /**
527 * Create a tearoff class for function [function].
528 *
529 * The class will have one method named 'call', accepting the same arguments
530 * as [function]. The method will load the arguments received and statically
531 * call [function] (essential a tail-call).
532 *
533 * If [function] is an instance member, the class will have one field, the
534 * instance.
535 */
536 FletchClassBuilder createTearoffClass(FletchFunctionBase function) {
537 FletchClassBuilder tearoffClass =
538 systemBuilder.getTearoffClassBuilder(function, compiledClosureClass);
539 if (tearoffClass != null) return tearoffClass;
540 FunctionSignature signature = function.signature;
541 bool hasThis = function.isInstanceMember;
542 tearoffClass = createCallableStubClass(
543 hasThis ? 1 : 0,
544 signature.parameterCount,
545 compiledClosureClass);
546
547 FletchFunctionBuilder functionBuilder =
548 systemBuilder.newTearOff(function, tearoffClass.classId);
549
550 BytecodeAssembler assembler = functionBuilder.assembler;
551 int argumentCount = signature.parameterCount;
552 if (hasThis) {
553 argumentCount++;
554 // If the tearoff has a 'this' value, load it. It's the only field
555 // in the tearoff class.
556 assembler
557 ..loadParameter(0)
558 ..loadField(0);
559 }
560 for (int i = 0; i < signature.parameterCount; i++) {
561 // The closure-class is at parameter index 0, so argument i is at
562 // i + 1.
563 assembler.loadParameter(i + 1);
564 }
565 int constId = functionBuilder.allocateConstantFromFunction(
566 function.functionId);
567 // TODO(ajohnsen): Create a tail-call bytecode, so we don't have to
568 // load all the arguments.
569 assembler
570 ..invokeStatic(constId, argumentCount)
571 ..ret()
572 ..methodEnd();
573
574 String symbol = context.getCallSymbol(signature);
575 int id = context.getSymbolId(symbol);
576 int fletchSelector = FletchSelector.encodeMethod(
577 id,
578 signature.parameterCount);
579 tearoffClass.addToMethodTable(fletchSelector, functionBuilder);
580
581 if (!function.isInstanceMember) return tearoffClass;
582
583 ClassElement classElement =
584 systemBuilder.lookupClassBuilder(function.memberOf).element;
585 if (classElement == null) return tearoffClass;
586
587 // Create == function that tests for equality.
588 int isSelector = context.toFletchTearoffIsSelector(
589 function.name,
590 classElement);
591 tearoffClass.addIsSelector(isSelector);
592
593 FletchFunctionBuilder equal = systemBuilder.newFunctionBuilder(
594 FletchFunctionKind.NORMAL,
595 2);
596
597 BytecodeLabel isFalse = new BytecodeLabel();
598 equal.assembler
599 // First test for class. This ensures it's the exact function that
600 // we expect.
601 ..loadParameter(1)
602 ..invokeTest(isSelector, 0)
603 ..branchIfFalse(isFalse)
604 // Then test that the receiver is identical.
605 ..loadParameter(0)
606 ..loadField(0)
607 ..loadParameter(1)
608 ..loadField(0)
609 ..identicalNonNumeric()
610 ..branchIfFalse(isFalse)
611 ..loadLiteralTrue()
612 ..ret()
613 ..bind(isFalse)
614 ..loadLiteralFalse()
615 ..ret()
616 ..methodEnd();
617
618 id = context.getSymbolId("==");
619 int equalsSelector = FletchSelector.encodeMethod(id, 1);
620 tearoffClass.addToMethodTable(equalsSelector, equal);
621
622 // Create hashCode getter. We simply add the object hashCode and the
623 // method id of the tearoff'ed function.
624 FletchFunctionBuilder hashCode = systemBuilder.newFunctionBuilder(
625 FletchFunctionKind.ACCESSOR,
626 1);
627
628 int hashCodeSelector = FletchSelector.encodeGetter(
629 context.getSymbolId("hashCode"));
630
631 // TODO(ajohnsen): Use plus, we plus is always enqueued. Consider using
632 // xor when we have a way to enqueue it from here.
633 int plusSelector = FletchSelector.encodeMethod(
634 context.getSymbolId("+"), 1);
635
636 hashCode.assembler
637 ..loadParameter(0)
638 ..loadField(0)
639 ..invokeMethod(hashCodeSelector, 0)
640 ..loadLiteral(function.functionId)
641 ..invokeMethod(plusSelector, 1)
642 ..ret()
643 ..methodEnd();
644
645 tearoffClass.addToMethodTable(hashCodeSelector, hashCode);
646
647 return tearoffClass;
648 }
649
650 FletchFunctionBase getFunctionForElement(FunctionElement element) {
651 assert(element.memberContext == element);
652
653 FletchFunctionBase function =
654 systemBuilder.lookupFunctionByElement(element);
655 if (function != null) return function;
656
657 return createFletchFunctionBuilder(element);
658 }
659
660 /// Get the constructor initializer function for [constructor]. The function
661 /// will be created the first time it's called for [constructor].
662 ///
663 /// See [compilePendingConstructorInitializers] for an overview of
664 /// constructor intializers and constructor bodies.
665 FletchFunctionBase getConstructorInitializerFunction(
666 ConstructorElement constructor) {
667 assert(constructor.isDeclaration);
668 constructor = constructor.implementation;
669 FletchFunctionBase base =
670 systemBuilder.lookupConstructorInitializerByElement(constructor);
671 if (base != null) return base;
672
673 FletchFunctionBuilder builder = systemBuilder.newConstructorInitializer(
674 constructor);
675 pendingConstructorInitializers.addFirst(builder);
676
677 return builder;
678 }
679
680 FletchFunctionBuilder createFletchFunctionBuilder(FunctionElement function) {
681 assert(function.memberContext == function);
682
683 FletchClassBuilder holderClass;
684 if (function.isInstanceMember || function.isGenerativeConstructor) {
685 ClassElement enclosingClass = function.enclosingClass.declaration;
686 holderClass = registerClassElement(enclosingClass);
687 }
688 return internalCreateFletchFunctionBuilder(
689 function,
690 function.name,
691 holderClass);
692 }
693
694 FletchFunctionBuilder internalCreateFletchFunctionBuilder(
695 FunctionElement function,
696 String name,
697 FletchClassBuilder holderClass) {
698 FletchFunctionBuilder functionBuilder =
699 systemBuilder.lookupFunctionBuilderByElement(function.declaration);
700 if (functionBuilder != null) return functionBuilder;
701
702 FunctionTypedElement implementation = function.implementation;
703 int memberOf = holderClass != null ? holderClass.classId : null;
704 return systemBuilder.newFunctionBuilderWithSignature(
705 name,
706 function,
707 // Parameter initializers are expressed in the potential
708 // implementation.
709 implementation.functionSignature,
710 memberOf,
711 kind: function.isAccessor
712 ? FletchFunctionKind.ACCESSOR
713 : FletchFunctionKind.NORMAL,
714 mapByElement: function.declaration);
715 }
716
717 ClassDebugInfo createClassDebugInfo(FletchClass klass) {
718 return new ClassDebugInfo(klass);
719 }
720
721 DebugInfo createDebugInfo(
722 FletchFunction function,
723 FletchSystem currentSystem) {
724 DebugInfo debugInfo = new DebugInfo(function);
725 AstElement element = function.element;
726 if (element == null) return debugInfo;
727 List<Bytecode> expectedBytecodes = function.bytecodes;
728 element = element.implementation;
729 TreeElements elements = element.resolvedAst.elements;
730 ClosureEnvironment closureEnvironment = createClosureEnvironment(
731 element,
732 elements);
733 CodegenVisitor codegen;
734 FletchFunctionBuilder builder =
735 new FletchFunctionBuilder.fromFletchFunction(function);
736 if (function.isLazyFieldInitializer) {
737 codegen = new DebugInfoLazyFieldInitializerCodegen(
738 debugInfo,
739 builder,
740 context,
741 elements,
742 closureEnvironment,
743 element,
744 compiler);
745 } else if (function.isInitializerList) {
746 ClassElement enclosingClass = element.enclosingClass;
747 // TODO(ajohnsen): Don't depend on the class builder.
748 FletchClassBuilder classBuilder =
749 systemBuilder.lookupClassBuilderByElement(enclosingClass.declaration);
750 codegen = new DebugInfoConstructorCodegen(
751 debugInfo,
752 builder,
753 context,
754 elements,
755 closureEnvironment,
756 element,
757 classBuilder,
758 compiler);
759 } else {
760 codegen = new DebugInfoFunctionCodegen(
761 debugInfo,
762 builder,
763 context,
764 elements,
765 closureEnvironment,
766 element,
767 compiler);
768 }
769 if (isNative(element)) {
770 compiler.reporter.withCurrentElement(element, () {
771 codegenNativeFunction(element, codegen);
772 });
773 } else if (isExternal(element)) {
774 compiler.reporter.withCurrentElement(element, () {
775 codegenExternalFunction(element, codegen);
776 });
777 } else {
778 compiler.reporter.withCurrentElement(element, () { codegen.compile(); });
779 }
780 // The debug codegen should generate the same bytecodes as the original
781 // codegen. If that is not the case debug information will be useless.
782 if (!Bytecode.identicalBytecodes(expectedBytecodes,
783 codegen.assembler.bytecodes)) {
784 throw 'Debug info code different from running code.';
785 }
786 return debugInfo;
787 }
788
789 codegen(_) {
790 new UnsupportedError(
791 "Method [codegen] not supported, use [compileElement] instead");
792 }
793
794 /// Invoked by [FletchEnqueuer] once per element that needs to be compiled.
795 ///
796 /// This is used to generate the bytecodes for [declaration].
797 void compileElement(
798 AstElement declaration,
799 TreeElements treeElements,
800 FletchRegistry registry) {
801 AstElement element = declaration.implementation;
802 compiler.reporter.withCurrentElement(element, () {
803 assert(declaration.isDeclaration);
804 context.compiler.reportVerboseInfo(element, 'Compiling $element');
805 if (element.isFunction ||
806 element.isGetter ||
807 element.isSetter ||
808 element.isGenerativeConstructor ||
809 element.isFactoryConstructor) {
810 // For a generative constructor, this means compile the constructor
811 // body. See [compilePendingConstructorInitializers] for an overview of
812 // how constructor initializers and constructor bodies are compiled.
813 codegenFunction(element, treeElements, registry);
814 } else if (element.isField) {
815 context.compiler.reportVerboseInfo(
816 element, "Asked to compile a field, but don't know how");
817 } else {
818 compiler.reporter.internalError(
819 element, "Uninimplemented element kind: ${element.kind}");
820 }
821 });
822 }
823
824 /// Invoked by [FletchEnqueuer] once per [selector] that may invoke
825 /// [declaration].
826 ///
827 /// This is used to generate stubs for [declaration].
828 void compileElementUsage(
829 AstElement declaration,
830 Selector selector,
831 TreeElements treeElements,
832 FletchRegistry registry) {
833 AstElement element = declaration.implementation;
834 compiler.reporter.withCurrentElement(element, () {
835 assert(declaration.isDeclaration);
836 context.compiler.reportVerboseInfo(element, 'Compiling $element');
837 if (!element.isInstanceMember && !isLocalFunction(element)) {
838 // No stub needed. Optional arguments are handled at call-site.
839 } else if (element.isFunction) {
840 FletchFunctionBase function =
841 systemBuilder.lookupFunctionByElement(element.declaration);
842 CallStructure callStructure = selector.callStructure;
843 FunctionSignature signature = function.signature;
844 if (selector.isGetter) {
845 if (shouldReportEnqueuingOfElement(compiler, element)) {
846 context.compiler.reportVerboseInfo(
847 element, 'Adding tear-off stub');
848 }
849 createTearoffGetterForFunction(
850 function, isSpecialCallMethod: element.name == "call");
851 } else if (selector.isCall &&
852 callStructure.signatureApplies(signature) &&
853 !isExactParameterMatch(signature, callStructure)) {
854 if (shouldReportEnqueuingOfElement(compiler, element)) {
855 context.compiler.reportVerboseInfo(
856 element, 'Adding stub for $selector');
857 }
858 createParameterStub(function, selector);
859 }
860 } else if (element.isGetter || element.isSetter) {
861 // No stub needed. If a getter returns a closure, the VM's
862 // no-such-method handling will do the right thing.
863 } else {
864 context.compiler.reportVerboseInfo(
865 element, "Asked to compile this, but don't know how");
866 }
867 });
868 }
869
870 /// Invoked by [FletchEnqueuer] once per `call` [selector] that may invoke
871 /// [declaration] as an implicit closure (for example, a tear-off).
872 ///
873 /// This is used to generate parameter stubs for the closures.
874 void compileClosurizationUsage(
875 AstElement declaration,
876 Selector selector,
877 TreeElements treeElements,
878 FletchRegistry registry,
879 ClosureKind kind) {
880 AstElement element = declaration.implementation;
881 compiler.reporter.withCurrentElement(element, () {
882 assert(declaration.isDeclaration);
883 if (shouldReportEnqueuingOfElement(compiler, element)) {
884 context.compiler.reportVerboseInfo(
885 element, 'Need tear-off parameter stub $selector');
886 }
887 FletchFunctionBase function =
888 systemBuilder.lookupFunctionByElement(element.declaration);
889 if (function == null) {
890 compiler.reporter.internalError(
891 element, "Has no fletch function, but used as tear-off");
892 }
893 if (selector.isGetter) {
894 // This is a special tear-off getter.
895
896 // TODO(ahe): This code should probably use [kind] to detect the
897 // various cases instead of [isLocalFunction] and looking at names.
898
899 assert(selector.memberName == Names.CALL_NAME);
900 if (isLocalFunction(element) ||
901 memberName(element) == Names.CALL_NAME) {
902 createTearoffGetterForFunction(
903 function, isSpecialCallMethod: true);
904 return;
905 }
906 int stub = systemBuilder.lookupTearOffById(function.functionId);
907 if (stub == null) {
908 compiler.reporter.internalError(
909 element, "No tear-off stub to compile `call` tear-off");
910 } else {
911 function = systemBuilder.lookupFunction(stub);
912 createTearoffGetterForFunction(function, isSpecialCallMethod: true);
913 return;
914 }
915 }
916 switch (kind) {
917 case ClosureKind.tearOff:
918 case ClosureKind.superTearOff:
919 if (memberName(element) == Names.CALL_NAME) {
920 // This is really a functionLikeTearOff.
921 break;
922 }
923 // A tear-off has a corresponding stub in a closure class. Look up
924 // that stub:
925 int stub = systemBuilder.lookupTearOffById(function.functionId);
926 if (stub == null) {
927 compiler.reporter
928 .internalError(element, "Couldn't find tear-off stub");
929 } else {
930 function = systemBuilder.lookupFunction(stub);
931 }
932 break;
933
934 case ClosureKind.localFunction:
935 // A local function already is a member of its closure class, and
936 // doesn't have a stub.
937 break;
938
939 case ClosureKind.functionLike:
940 case ClosureKind.functionLikeTearOff:
941 compiler.reporter.internalError(element, "Unimplemented: $kind");
942 break;
943 }
944
945 if (!isExactParameterMatch(function.signature, selector.callStructure)) {
946 createParameterStub(function, selector);
947 }
948 });
949 }
950
951 void codegenFunction(
952 FunctionElement function,
953 TreeElements elements,
954 FletchRegistry registry) {
955 registry.registerStaticUse(new StaticUse.foreignUse(fletchSystemEntry));
956
957 ClosureEnvironment closureEnvironment = createClosureEnvironment(
958 function,
959 elements);
960
961 FletchFunctionBuilder functionBuilder;
962
963 if (function.memberContext != function) {
964 functionBuilder = internalCreateFletchFunctionBuilder(
965 function,
966 Identifiers.call,
967 createClosureClass(function, closureEnvironment));
968 } else {
969 functionBuilder = createFletchFunctionBuilder(function);
970 }
971
972 FunctionCodegen codegen = new FunctionCodegen(
973 functionBuilder,
974 context,
975 elements,
976 registry,
977 closureEnvironment,
978 function);
979
980 if (isNative(function)) {
981 codegenNativeFunction(function, codegen);
982 } else if (isExternal(function)) {
983 codegenExternalFunction(function, codegen);
984 } else {
985 codegen.compile();
986 }
987
988 if (functionBuilder.isInstanceMember && !function.isGenerativeConstructor) {
989 // Inject the function into the method table of the 'holderClass' class.
990 // Note that while constructor bodies has a this argument, we don't inject
991 // them into the method table.
992 String symbol = context.getSymbolForFunction(
993 functionBuilder.name,
994 function.functionSignature,
995 function.library);
996 int id = context.getSymbolId(symbol);
997 int arity = function.functionSignature.parameterCount;
998 SelectorKind kind = SelectorKind.Method;
999 if (function.isGetter) kind = SelectorKind.Getter;
1000 if (function.isSetter) kind = SelectorKind.Setter;
1001 int fletchSelector = FletchSelector.encode(id, kind, arity);
1002 FletchClassBuilder classBuilder =
1003 systemBuilder.lookupClassBuilder(functionBuilder.memberOf);
1004 classBuilder.addToMethodTable(fletchSelector, functionBuilder);
1005 // Inject method into all mixin usages.
1006 getMixinApplicationsOfClass(classBuilder).forEach((ClassElement usage) {
1007 FletchClassBuilder compiledUsage = registerClassElement(usage);
1008 compiledUsage.addToMethodTable(fletchSelector, functionBuilder);
1009 });
1010 }
1011
1012 if (compiler.verbose) {
1013 context.compiler.reportVerboseInfo(
1014 function, functionBuilder.verboseToString());
1015 }
1016 }
1017
1018 List<ClassElement> getMixinApplicationsOfClass(FletchClassBuilder builder) {
1019 ClassElement element = builder.element;
1020 if (element == null) return [];
1021 List<ClassElement> mixinUsage =
1022 compiler.world.mixinUsesOf(element).toList();
1023 for (int i = 0; i < mixinUsage.length; i++) {
1024 ClassElement usage = mixinUsage[i];
1025 // Recursively add mixin-usage of the current 'usage'.
1026 assert(!compiler.world.mixinUsesOf(usage).any(mixinUsage.contains));
1027 mixinUsage.addAll(compiler.world.mixinUsesOf(usage));
1028 }
1029 return mixinUsage;
1030 }
1031
1032 void codegenNativeFunction(
1033 FunctionElement function,
1034 FunctionCodegen codegen) {
1035 String name = '.${function.name}';
1036
1037 ClassElement enclosingClass = function.enclosingClass;
1038 if (enclosingClass != null) name = '${enclosingClass.name}$name';
1039
1040 FletchNativeDescriptor descriptor = context.nativeDescriptors[name];
1041 if (descriptor == null) {
1042 throw "Unsupported native function: $name";
1043 }
1044
1045 if (name == "Coroutine._coroutineNewStack") {
1046 // The static native method `Coroutine._coroutineNewStack` will invoke
1047 // the instance method `Coroutine._coroutineStart`.
1048 if (coroutineClass == null) {
1049 compiler.reporter.internalError(
1050 function, "required class [Coroutine] not found");
1051 }
1052 FunctionElement coroutineStart =
1053 coroutineClass.lookupLocalMember("_coroutineStart");
1054 Selector selector = new Selector.fromElement(coroutineStart);
1055 new FletchRegistry(compiler)
1056 ..registerDynamicUse(selector);
1057 } else if (name == "Process._spawn") {
1058 // The native method `Process._spawn` will do a closure invoke with 0, 1,
1059 // or 2 arguments.
1060 new FletchRegistry(compiler)
1061 ..registerDynamicUse(new Selector.callClosure(0))
1062 ..registerDynamicUse(new Selector.callClosure(1))
1063 ..registerDynamicUse(new Selector.callClosure(2));
1064 }
1065
1066 int arity = codegen.assembler.functionArity;
1067 if (name == "Port.send" ||
1068 name == "Port._sendList" ||
1069 name == "Port._sendExit") {
1070 codegen.assembler.invokeNativeYield(arity, descriptor.index);
1071 } else {
1072 codegen.assembler.invokeNative(arity, descriptor.index);
1073 }
1074
1075 EmptyStatement empty = function.node.body.asEmptyStatement();
1076 if (empty != null) {
1077 // A native method without a body.
1078 codegen.assembler
1079 ..emitThrow()
1080 ..methodEnd();
1081 } else {
1082 codegen.compile();
1083 }
1084 }
1085
1086 void codegenExternalFunction(
1087 FunctionElement function,
1088 FunctionCodegen codegen) {
1089 if (function == fletchExternalYield) {
1090 codegenExternalYield(function, codegen);
1091 } else if (function == context.compiler.identicalFunction.implementation) {
1092 codegenIdentical(function, codegen);
1093 } else if (function == fletchExternalInvokeMain) {
1094 codegenExternalInvokeMain(function, codegen);
1095 } else if (function.name == noSuchMethodTrampolineName &&
1096 function.library == compiler.coreLibrary) {
1097 codegenExternalNoSuchMethodTrampoline(function, codegen);
1098 } else {
1099 DiagnosticMessage message = context.compiler.reporter
1100 .createMessage(function.node,
1101 MessageKind.GENERIC,
1102 {'text':
1103 'External function "${function.name}" is not supported'});
1104 compiler.reporter.reportError(message);
1105 codegen
1106 ..doCompileError(message)
1107 ..assembler.ret()
1108 ..assembler.methodEnd();
1109 }
1110 }
1111
1112 void codegenIdentical(
1113 FunctionElement function,
1114 FunctionCodegen codegen) {
1115 codegen.assembler
1116 ..loadParameter(0)
1117 ..loadParameter(1)
1118 ..identical()
1119 ..ret()
1120 ..methodEnd();
1121 }
1122
1123 void codegenExternalYield(
1124 FunctionElement function,
1125 FunctionCodegen codegen) {
1126 codegen.assembler
1127 ..loadParameter(0)
1128 ..processYield()
1129 ..ret()
1130 ..methodEnd();
1131 }
1132
1133 void codegenExternalInvokeMain(
1134 FunctionElement function,
1135 FunctionCodegen codegen) {
1136 compiler.reporter.internalError(
1137 function, "[codegenExternalInvokeMain] not implemented.");
1138 // TODO(ahe): This code shouldn't normally be called, only if invokeMain is
1139 // torn off. Perhaps we should just say we don't support that.
1140 }
1141
1142 void codegenExternalNoSuchMethodTrampoline(
1143 FunctionElement function,
1144 FunctionCodegen codegen) {
1145 // NOTE: The number of arguments to the [noSuchMethodName] function must be
1146 // kept in sync with:
1147 // src/vm/interpreter.cc:HandleEnterNoSuchMethod
1148 int id = context.getSymbolId(
1149 context.mangleName(new Name(noSuchMethodName, compiler.coreLibrary)));
1150 int fletchSelector = FletchSelector.encodeMethod(id, 3);
1151 BytecodeLabel skipGetter = new BytecodeLabel();
1152 codegen.assembler
1153 ..enterNoSuchMethod(skipGetter)
1154 // First invoke the getter.
1155 ..invokeSelector(2)
1156 // Then invoke 'call', with the receiver being the result of the
1157 // previous invokeSelector.
1158 ..invokeSelector(1)
1159 ..exitNoSuchMethod()
1160 ..bind(skipGetter)
1161 ..invokeMethod(fletchSelector, 1)
1162 ..exitNoSuchMethod()
1163 ..methodEnd();
1164 }
1165
1166 bool isNative(Element element) {
1167 if (element is FunctionElement) {
1168 for (var metadata in element.metadata) {
1169 // TODO(ahe): This code should ensure that @native resolves to precisely
1170 // the native variable in dart:fletch._system.
1171 if (metadata.constant == null) continue;
1172 ConstantValue value = context.getConstantValue(metadata.constant);
1173 if (!value.isString) continue;
1174 StringConstantValue stringValue = value;
1175 if (stringValue.toDartString().slowToString() != 'native') continue;
1176 return true;
1177 }
1178 }
1179 return false;
1180 }
1181
1182 bool isExternal(Element element) {
1183 if (element is FunctionElement) return element.isExternal;
1184 return false;
1185 }
1186
1187 bool get canHandleCompilationFailed => true;
1188
1189 ClosureEnvironment createClosureEnvironment(
1190 ExecutableElement element,
1191 TreeElements elements) {
1192 MemberElement member = element.memberContext;
1193 return closureEnvironments.putIfAbsent(member, () {
1194 ClosureVisitor environment = new ClosureVisitor(member, elements);
1195 return environment.compute();
1196 });
1197 }
1198
1199 void markFunctionConstantAsUsed(FunctionConstantValue value) {
1200 // TODO(ajohnsen): Use registry in CodegenVisitor to register the used
1201 // constants.
1202 FunctionElement function = value.element;
1203 createTearoffClass(createFletchFunctionBuilder(function));
1204 // Be sure to actually enqueue the function for compilation.
1205 FletchRegistry registry = new FletchRegistry(compiler);
1206 registry.registerStaticUse(new StaticUse.foreignUse(function));
1207 }
1208
1209 FletchFunctionBase createParameterStub(
1210 FletchFunctionBase function,
1211 Selector selector) {
1212 CallStructure callStructure = selector.callStructure;
1213 assert(callStructure.signatureApplies(function.signature));
1214 ParameterStubSignature signature = new ParameterStubSignature(
1215 function.functionId, callStructure);
1216 FletchFunctionBase stub = systemBuilder.lookupParameterStub(signature);
1217 if (stub != null) return stub;
1218
1219 int arity = selector.argumentCount;
1220 if (function.isInstanceMember) arity++;
1221
1222 FletchFunctionBuilder builder = systemBuilder.newFunctionBuilder(
1223 FletchFunctionKind.PARAMETER_STUB,
1224 arity);
1225
1226 BytecodeAssembler assembler = builder.assembler;
1227
1228 void loadInitializerOrNull(ParameterElement parameter) {
1229 Expression initializer = parameter.initializer;
1230 if (initializer != null) {
1231 ConstantExpression expression = context.compileConstant(
1232 initializer,
1233 parameter.memberContext.resolvedAst.elements,
1234 isConst: true);
1235 int constId = builder.allocateConstant(
1236 context.getConstantValue(expression));
1237 assembler.loadConst(constId);
1238 } else {
1239 assembler.loadLiteralNull();
1240 }
1241 }
1242
1243 // Load this.
1244 if (function.isInstanceMember) assembler.loadParameter(0);
1245
1246 int index = function.isInstanceMember ? 1 : 0;
1247 function.signature.orderedForEachParameter((ParameterElement parameter) {
1248 if (!parameter.isOptional) {
1249 assembler.loadParameter(index);
1250 } else if (parameter.isNamed) {
1251 int parameterIndex = selector.namedArguments.indexOf(parameter.name);
1252 if (parameterIndex >= 0) {
1253 if (function.isInstanceMember) parameterIndex++;
1254 int position = selector.positionalArgumentCount + parameterIndex;
1255 assembler.loadParameter(position);
1256 } else {
1257 loadInitializerOrNull(parameter);
1258 }
1259 } else {
1260 if (index < arity) {
1261 assembler.loadParameter(index);
1262 } else {
1263 loadInitializerOrNull(parameter);
1264 }
1265 }
1266 index++;
1267 });
1268
1269 // TODO(ajohnsen): We have to be extra careful when overriding a
1270 // method that takes optional arguments. We really should
1271 // enumerate all the stubs in the superclasses and make sure
1272 // they're overridden.
1273 int constId = builder.allocateConstantFromFunction(function.functionId);
1274 assembler
1275 ..invokeStatic(constId, index)
1276 ..ret()
1277 ..methodEnd();
1278
1279 if (function.isInstanceMember) {
1280 int fletchSelector = context.toFletchSelector(selector);
1281 FletchClassBuilder classBuilder = getClassBuilderOfExistingClass(function. memberOf);
1282 classBuilder.addToMethodTable(fletchSelector, builder);
1283
1284 // Inject parameter stub into all mixin usages.
1285 getMixinApplicationsOfClass(classBuilder).forEach((ClassElement usage) {
1286 FletchClassBuilder classBuilder =
1287 systemBuilder.lookupClassBuilderByElement(usage);
1288 classBuilder.addToMethodTable(fletchSelector, builder);
1289 });
1290 }
1291
1292 systemBuilder.registerParameterStub(signature, builder);
1293
1294 return builder;
1295 }
1296
1297 /// Create a tear-off getter for [function]. If [isSpecialCallMethod] is
1298 /// `true`, this is the special case for `someClosure.call` which should
1299 /// always return `someClosure`. This implies that when [isSpecialCallMethod]
1300 /// is true, we assume [function] is already a member of a closure class (or
1301 /// a class with a `call` method [ClosureKind.functionLike]) and that the
1302 /// getter should be added to that class.
1303 void createTearoffGetterForFunction(
1304 FletchFunctionBuilder function,
1305 {bool isSpecialCallMethod}) {
1306 if (isSpecialCallMethod == null) {
1307 throw new ArgumentError("isSpecialCallMethod");
1308 }
1309 FletchFunctionBuilder getter = systemBuilder.newFunctionBuilder(
1310 FletchFunctionKind.ACCESSOR,
1311 1);
1312 // If the getter is of 'call', return the instance instead.
1313 if (isSpecialCallMethod) {
1314 getter.assembler
1315 ..loadParameter(0)
1316 ..ret()
1317 ..methodEnd();
1318 } else {
1319 FletchClassBuilder tearoffClass = createTearoffClass(function);
1320 int constId = getter.allocateConstantFromClass(tearoffClass.classId);
1321 getter.assembler
1322 ..loadParameter(0)
1323 ..allocate(constId, tearoffClass.fields)
1324 ..ret()
1325 ..methodEnd();
1326 }
1327 // If the name is private, we need the library.
1328 // Invariant: We only generate public stubs, e.g. 'call'.
1329 LibraryElement library;
1330 if (function.element != null) {
1331 library = function.element.library;
1332 }
1333 // TODO(sigurdm): Avoid allocating new name here.
1334 Name name = new Name(function.name, library);
1335 int fletchSelector = context.toFletchSelector(
1336 new Selector.getter(name));
1337 FletchClassBuilder classBuilder = systemBuilder.lookupClassBuilder(
1338 function.memberOf);
1339 classBuilder.addToMethodTable(fletchSelector, getter);
1340
1341 // Inject getter into all mixin usages.
1342 getMixinApplicationsOfClass(classBuilder).forEach((ClassElement usage) {
1343 FletchClassBuilder classBuilder =
1344 systemBuilder.lookupClassBuilderByElement(usage);
1345 classBuilder.addToMethodTable(fletchSelector, getter);
1346 });
1347 }
1348
1349 void compileTypeTest(ClassElement element, InterfaceType type) {
1350 assert(element.isDeclaration);
1351 int fletchSelector = context.toFletchIsSelector(type.element);
1352 FletchClassBuilder builder =
1353 systemBuilder.lookupClassBuilderByElement(element);
1354 if (builder != null) {
1355 context.compiler.reportVerboseInfo(
1356 element, 'Adding is-selector for $type');
1357 builder.addIsSelector(fletchSelector);
1358 }
1359 }
1360
1361 int assembleProgram() => 0;
1362
1363 FletchDelta computeDelta() {
1364
1365 if (fletchSystemLibrary == null && compiler.compilationFailed) {
1366 // TODO(ahe): Ensure fletchSystemLibrary is not null.
1367 return null;
1368 }
1369
1370 List<VmCommand> commands = <VmCommand>[
1371 const NewMap(MapId.methods),
1372 const NewMap(MapId.classes),
1373 const NewMap(MapId.constants),
1374 ];
1375
1376 FletchSystem system = systemBuilder.computeSystem(context, commands);
1377
1378 commands.add(const PushNewInteger(0));
1379 commands.add(new PushFromMap(
1380 MapId.methods,
1381 system.lookupFunctionByElement(fletchSystemEntry).functionId));
1382
1383 return new FletchDelta(system, systemBuilder.predecessorSystem, commands);
1384 }
1385
1386 bool enableCodegenWithErrorsIfSupported(Spannable spannable) {
1387 return true;
1388 }
1389
1390 bool enableDeferredLoadingIfSupported(Spannable spannable, Registry registry) {
1391 return false;
1392 }
1393
1394 bool registerDeferredLoading(Spannable node, Registry registry) {
1395 compiler.reporter.reportWarningMessage(
1396 node,
1397 MessageKind.GENERIC,
1398 {'text': "Deferred loading is not supported."});
1399 return false;
1400 }
1401
1402 bool get supportsReflection => false;
1403
1404 // TODO(sigurdm): Support async/await on the mobile platform.
1405 bool get supportsAsyncAwait {
1406 return !compiler.platformConfigUri.path.contains("embedded");
1407 }
1408
1409 Future onLibraryScanned(LibraryElement library, LibraryLoader loader) {
1410 if (library.isPlatformLibrary) {
1411 String path = library.canonicalUri.path;
1412 switch(path) {
1413 case 'fletch._system':
1414 fletchSystemLibrary = library;
1415 break;
1416 case 'fletch.ffi':
1417 fletchFFILibrary = library;
1418 break;
1419 case 'fletch.collection':
1420 collectionLibrary = library;
1421 break;
1422 case 'math':
1423 mathLibrary = library;
1424 break;
1425 case 'fletch':
1426 fletchLibrary = library;
1427 break;
1428 }
1429
1430 if (!library.isPatched) {
1431 // Apply patch, if any.
1432 Uri patchUri = compiler.resolvePatchUri(library.canonicalUri.path);
1433 if (patchUri != null) {
1434 return compiler.patchParser.patchLibrary(loader, patchUri, library);
1435 }
1436 }
1437 }
1438 return null;
1439 }
1440
1441 bool isBackendLibrary(LibraryElement library) {
1442 return library == fletchSystemLibrary;
1443 }
1444
1445 /// Return non-null to enable patching. Possible return values are 'new' and
1446 /// 'old'. Referring to old and new emitter. Since the new emitter is the
1447 /// future, we assume 'old' will go away. So it seems the best option for
1448 /// Fletch is 'new'.
1449 String get patchVersion => 'new';
1450
1451 FunctionElement resolveExternalFunction(FunctionElement element) {
1452 if (element.isPatched) {
1453 FunctionElementX patch = element.patch;
1454 compiler.reporter.withCurrentElement(patch, () {
1455 patch.parseNode(compiler.parsing);
1456 patch.computeType(compiler.resolution);
1457 });
1458 element = patch;
1459 // TODO(ahe): Don't use ensureResolved (fix TODO in isNative instead).
1460 element.metadata.forEach((m) => m.ensureResolved(compiler.resolution));
1461 } else if (element.library == fletchSystemLibrary) {
1462 // Nothing needed for now.
1463 } else if (element.library == compiler.coreLibrary) {
1464 // Nothing needed for now.
1465 } else if (element.library == mathLibrary) {
1466 // Nothing needed for now.
1467 } else if (element.library == asyncLibrary) {
1468 // Nothing needed for now.
1469 } else if (element.library == fletchLibrary) {
1470 // Nothing needed for now.
1471 } else if (externals.contains(element)) {
1472 // Nothing needed for now.
1473 } else {
1474 compiler.reporter.reportErrorMessage(
1475 element, MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION);
1476 }
1477 return element;
1478 }
1479
1480 int compileLazyFieldInitializer(
1481 FieldElement field,
1482 FletchRegistry registry) {
1483 int index = context.getStaticFieldIndex(field, null);
1484
1485 if (field.initializer == null) return index;
1486
1487 if (lazyFieldInitializers.containsKey(field)) return index;
1488
1489 FletchFunctionBuilder functionBuilder = systemBuilder.newFunctionBuilder(
1490 FletchFunctionKind.LAZY_FIELD_INITIALIZER,
1491 0,
1492 name: "${field.name} lazy initializer",
1493 element: field);
1494 lazyFieldInitializers[field] = functionBuilder;
1495
1496 TreeElements elements = field.resolvedAst.elements;
1497
1498 ClosureEnvironment closureEnvironment = createClosureEnvironment(
1499 field,
1500 elements);
1501
1502 LazyFieldInitializerCodegen codegen = new LazyFieldInitializerCodegen(
1503 functionBuilder,
1504 context,
1505 elements,
1506 registry,
1507 closureEnvironment,
1508 field);
1509
1510 codegen.compile();
1511
1512 return index;
1513 }
1514
1515 /// Compiles the initializer part of a constructor.
1516 ///
1517 /// See [compilePendingConstructorInitializers] for an overview of how
1518 /// constructor initializer and bodies are compiled.
1519 void compileConstructorInitializer(FletchFunctionBuilder functionBuilder) {
1520 ConstructorElement constructor = functionBuilder.element;
1521 assert(constructor.isImplementation);
1522 compiler.reporter.withCurrentElement(constructor, () {
1523 assert(functionBuilder ==
1524 systemBuilder.lookupConstructorInitializerByElement(constructor));
1525 context.compiler.reportVerboseInfo(
1526 constructor, 'Compiling constructor initializer $constructor');
1527
1528 TreeElements elements = constructor.resolvedAst.elements;
1529
1530 // TODO(ahe): We shouldn't create a registry, but we have to as long as
1531 // the enqueuer doesn't support elements with more than one compilation
1532 // artifact.
1533 FletchRegistry registry = new FletchRegistry(compiler);
1534
1535 FletchClassBuilder classBuilder =
1536 registerClassElement(constructor.enclosingClass.declaration);
1537
1538 ClosureEnvironment closureEnvironment =
1539 createClosureEnvironment(constructor, elements);
1540
1541 ConstructorCodegen codegen = new ConstructorCodegen(
1542 functionBuilder,
1543 context,
1544 elements,
1545 registry,
1546 closureEnvironment,
1547 constructor,
1548 classBuilder);
1549
1550 codegen.compile();
1551
1552 if (compiler.verbose) {
1553 context.compiler.reportVerboseInfo(
1554 constructor, functionBuilder.verboseToString());
1555 }
1556 });
1557 }
1558
1559 /**
1560 * Generate a getter for field [fieldIndex].
1561 */
1562 int makeGetter(int fieldIndex) {
1563 return systemBuilder.getGetterByFieldIndex(fieldIndex);
1564 }
1565
1566 /**
1567 * Generate a setter for field [fieldIndex].
1568 */
1569 int makeSetter(int fieldIndex) {
1570 return systemBuilder.getSetterByFieldIndex(fieldIndex);
1571 }
1572
1573 void generateUnimplementedError(
1574 Spannable spannable,
1575 String reason,
1576 FletchFunctionBuilder function,
1577 {bool suppressHint: false}) {
1578 if (!suppressHint) {
1579 compiler.reporter.reportHintMessage(
1580 spannable, MessageKind.GENERIC, {'text': reason});
1581 }
1582 var constString = constantSystem.createString(
1583 new DartString.literal(reason));
1584 context.markConstantUsed(constString);
1585 function
1586 ..assembler.loadConst(function.allocateConstant(constString))
1587 ..assembler.emitThrow();
1588 }
1589
1590 void forEachSubclassOf(ClassElement cls, void f(ClassElement cls)) {
1591 Queue<ClassElement> queue = new Queue<ClassElement>();
1592 queue.add(cls);
1593 while (queue.isNotEmpty) {
1594 ClassElement cls = queue.removeFirst();
1595 if (compiler.world.isInstantiated(cls.declaration)) {
1596 queue.addAll(compiler.world.strictSubclassesOf(cls));
1597 }
1598 f(cls);
1599 }
1600 }
1601
1602 void newElement(Element element) {
1603 if (element.isField && element.isInstanceMember) {
1604 forEachSubclassOf(element.enclosingClass, (ClassElement cls) {
1605 FletchClassBuilder builder = registerClassElement(cls);
1606 builder.addField(element);
1607 });
1608 }
1609 }
1610
1611 void replaceFunctionUsageElement(Element element, List<Element> users) {
1612 for (Element user in users) {
1613 systemBuilder.replaceUsage(user, element);
1614 }
1615 }
1616
1617 void forgetElement(Element element) {
1618 // TODO(ahe): The front-end should remove the element from
1619 // elementsWithCompileTimeErrors.
1620 compiler.elementsWithCompileTimeErrors.remove(element);
1621 FletchFunctionBase function =
1622 systemBuilder.lookupFunctionByElement(element);
1623 if (function == null) return;
1624 systemBuilder.forgetFunction(function);
1625 }
1626
1627 void removeField(FieldElement element) {
1628 if (!element.isInstanceMember) return;
1629 ClassElement enclosingClass = element.enclosingClass;
1630 forEachSubclassOf(enclosingClass, (ClassElement cls) {
1631 FletchClassBuilder builder = registerClassElement(cls);
1632 builder.removeField(element);
1633 });
1634 }
1635
1636 void removeFunction(FunctionElement element) {
1637 FletchFunctionBase function =
1638 systemBuilder.lookupFunctionByElement(element);
1639 if (function == null) return;
1640 if (element.isInstanceMember) {
1641 ClassElement enclosingClass = element.enclosingClass;
1642 FletchClassBuilder builder = registerClassElement(enclosingClass);
1643 builder.removeFromMethodTable(function);
1644 }
1645 }
1646
1647 /// Invoked during codegen enqueuing to compile constructor initializers.
1648 ///
1649 /// There's only one [Element] representing a constructor, but Fletch uses
1650 /// two different functions for implementing a constructor.
1651 ///
1652 /// The first function takes care of allocating the instance and initializing
1653 /// fields (called the constructor initializer), the other function
1654 /// implements the body of the constructor (what is between the curly
1655 /// braces). A constructor initializer never calls constructor initializers
1656 /// of a superclass. Instead field initializers from the superclass are
1657 /// inlined in the constructor initializer. The constructor initializer will
1658 /// call all the constructor bodies from superclasses in the correct order.
1659 ///
1660 /// The constructor bodies are basically special instance methods that can
1661 /// only be called from constructor initializers. Unlike constructor bodies,
1662 /// we only need constructor initializer for classes that are directly
1663 /// instantiated (excluding, for example, abstract classes).
1664 ///
1665 /// Given this, we compile constructor bodies when the normal enqueuer tells
1666 /// us to compile a generative constructor (see [codegen]), and track
1667 /// constructor initializers in a separate queue.
1668 void compilePendingConstructorInitializers() {
1669 while (pendingConstructorInitializers.isNotEmpty) {
1670 compileConstructorInitializer(
1671 pendingConstructorInitializers.removeLast());
1672 }
1673 }
1674
1675 bool onQueueEmpty(Enqueuer enqueuer, Iterable<ClassElement> recentClasses) {
1676 if (enqueuer is! ResolutionEnqueuer) {
1677 compilePendingConstructorInitializers();
1678 }
1679 return true;
1680 }
1681
1682 FletchEnqueueTask makeEnqueuer() => new FletchEnqueueTask(compiler);
1683
1684 static bool isExactParameterMatch(
1685 FunctionSignature signature,
1686 CallStructure callStructure) {
1687 if (!callStructure.signatureApplies(signature)) {
1688 return false;
1689 }
1690 if (!signature.hasOptionalParameters) {
1691 // There are no optional parameters, and the signature applies, so this
1692 // is an exact match.
1693 return true;
1694 }
1695 if (!signature.optionalParametersAreNamed) {
1696 // The optional parameters aren't named which means that they are
1697 // optional positional parameters. So we have an exact match if the
1698 // number of parameters matches the number of arguments.
1699 return callStructure.argumentCount == signature.parameterCount;
1700 }
1701 // Otherwise, the optional parameters are named, and we have an exact match
1702 // if the named arguments in the call occur in the same order as the
1703 // parameters in the signature.
1704 if (callStructure.namedArguments.length !=
1705 signature.optionalParameterCount) {
1706 return false;
1707 }
1708 int index = 0;
1709 for (var parameter in signature.orderedOptionalParameters) {
1710 if (parameter.name != callStructure.namedArguments[index++]) return false;
1711 }
1712 return true;
1713 }
1714
1715 static FletchBackend createInstance(FletchCompilerImplementation compiler) {
1716 return new FletchBackend(compiler);
1717 }
1718
1719 Uri resolvePatchUri(String libraryName, Uri libraryRoot) {
1720 throw "Not implemented";
1721 }
1722
1723 }
1724
1725 class FletchImpactTransformer extends ImpactTransformer {
1726 final FletchBackend backend;
1727
1728 FletchImpactTransformer(this.backend);
1729
1730 @override
1731 WorldImpact transformResolutionImpact(ResolutionImpact worldImpact) {
1732 TransformedWorldImpact transformed =
1733 new TransformedWorldImpact(worldImpact);
1734
1735 bool anyChange = false;
1736
1737 if (worldImpact.constSymbolNames.isNotEmpty) {
1738 ClassElement symbolClass =
1739 backend.compiler.coreClasses.symbolClass.declaration;
1740 transformed.registerTypeUse(
1741 new TypeUse.instantiation(symbolClass.rawType));
1742 transformed.registerStaticUse(
1743 new StaticUse.foreignUse(
1744 symbolClass.lookupConstructor("")));
1745 anyChange = true;
1746 }
1747
1748 for (MapLiteralUse mapLiteralUse in worldImpact.mapLiterals) {
1749 if (mapLiteralUse.isConstant) continue;
1750 transformed.registerTypeUse(
1751 new TypeUse.instantiation(backend.mapImplementation.rawType));
1752 transformed.registerStaticUse(
1753 new StaticUse.constructorInvoke(
1754 backend.mapImplementation.lookupConstructor(""),
1755 CallStructure.NO_ARGS));
1756 anyChange = true;
1757 }
1758 return anyChange ? transformed : worldImpact;
1759 }
1760
1761 @override
1762 transformCodegenImpact(impact) => throw "unimplemented";
1763 }
1764
1765 bool isLocalFunction(Element element) {
1766 if (!element.isFunction) return false;
1767 if (element is ExecutableElement) {
1768 return element.memberContext != element;
1769 }
1770 return false;
1771 }
1772
1773 Name memberName(AstElement element) {
1774 if (isLocalFunction(element)) return null;
1775 MemberElement member = element;
1776 return member.memberName;
1777 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698