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

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

Issue 1659163007: Rename fletch -> dartino (Closed) Base URL: https://github.com/dartino/sdk.git@master
Patch Set: address comments 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
« no previous file with comments | « pkg/fletchc/lib/src/closure_environment.dart ('k') | pkg/fletchc/lib/src/console_print.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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.codegen_visitor;
6
7 import 'package:compiler/src/resolution/semantic_visitor.dart';
8
9 import 'package:compiler/src/resolution/operators.dart' show
10 AssignmentOperator,
11 BinaryOperator,
12 IncDecOperator,
13 UnaryOperator;
14
15 import 'package:compiler/src/constants/expressions.dart' show
16 BoolFromEnvironmentConstantExpression,
17 IntFromEnvironmentConstantExpression,
18 StringFromEnvironmentConstantExpression,
19 ConstantExpression,
20 ConstructedConstantExpression,
21 TypeConstantExpression;
22
23 import 'package:compiler/src/resolution/tree_elements.dart' show
24 TreeElements;
25
26 import 'package:compiler/src/util/util.dart' show
27 Link;
28
29 import 'package:compiler/src/common/names.dart' show
30 Names,
31 Selectors;
32
33 import 'package:compiler/src/universe/use.dart' show DynamicUse, StaticUse;
34
35 import 'package:compiler/src/elements/elements.dart';
36 import 'package:compiler/src/tree/tree.dart';
37 import 'package:compiler/src/universe/call_structure.dart' show
38 CallStructure;
39 import 'package:compiler/src/universe/selector.dart' show
40 Selector;
41 import 'package:compiler/src/diagnostics/spannable.dart' show
42 Spannable;
43 import 'package:compiler/src/dart_types.dart';
44
45 import 'fletch_context.dart';
46
47 import 'fletch_backend.dart';
48
49 import 'fletch_constants.dart' show
50 FletchClassConstant,
51 FletchClassInstanceConstant;
52
53 import 'fletch_function_builder.dart' show
54 FletchFunctionBuilder;
55
56 import 'fletch_class_builder.dart' show
57 FletchClassBuilder;
58
59 import 'fletch_selector.dart';
60
61 import '../fletch_system.dart';
62
63 import 'closure_environment.dart';
64
65 import '../incremental/fletchc_incremental.dart' show
66 IncrementalCompilationFailed; // TODO(ahe): Remove this import.
67
68 import 'fletch_registry.dart' show
69 ClosureKind,
70 FletchRegistry;
71
72 import 'package:compiler/src/diagnostics/diagnostic_listener.dart' show
73 DiagnosticMessage;
74
75 import 'package:compiler/src/diagnostics/messages.dart' show
76 MessageKind;
77
78 import 'package:compiler/src/constants/values.dart' show
79 ConstantValue;
80
81 enum VisitState {
82 Value,
83 Effect,
84 Test,
85 }
86
87 /**
88 * A reference to a local value, including how it should be used
89 * (loaded/stored).
90 */
91 abstract class LocalValue {
92 final int slot;
93 final Element element;
94 LocalValue(this.slot, this.element);
95
96 void initialize(BytecodeAssembler assembler);
97
98 void load(BytecodeAssembler assembler);
99
100 void loadRaw(BytecodeAssembler assembler) {
101 load(assembler);
102 }
103
104 void store(BytecodeAssembler assembler);
105 }
106
107 /**
108 * A reference to a local value that is boxed.
109 */
110 class BoxedLocalValue extends LocalValue {
111 BoxedLocalValue(int slot, Element element) : super(slot, element);
112
113 void initialize(BytecodeAssembler assembler) {
114 assembler.allocateBoxed();
115 }
116
117 void load(BytecodeAssembler assembler) {
118 assembler.loadBoxedSlot(slot);
119 }
120
121 void loadRaw(BytecodeAssembler assembler) {
122 assembler.loadSlot(slot);
123 }
124
125 void store(BytecodeAssembler assembler) {
126 assembler.storeBoxedSlot(slot);
127 }
128
129 String toString() => "Boxed($element, $slot)";
130 }
131
132 /**
133 * A reference to a local value that is boxed.
134 */
135 class UnboxedLocalValue extends LocalValue {
136 UnboxedLocalValue(int slot, Element element) : super(slot, element);
137
138 void initialize(BytecodeAssembler assembler) {}
139
140 void load(BytecodeAssembler assembler) {
141 assembler.loadSlot(slot);
142 }
143
144 void store(BytecodeAssembler assembler) {
145 assembler.storeSlot(slot);
146 }
147
148 String toString() => "Local($element, $slot)";
149 }
150
151 /**
152 * A reference to a local value that is boxed.
153 */
154 class BoxedParameterValue extends LocalValue {
155 BoxedParameterValue(
156 int parameter,
157 Element element,
158 BytecodeAssembler assembler)
159 : super(assembler.computeParameterSlot(parameter), element);
160
161 void initialize(BytecodeAssembler assembler) {
162 assembler.allocateBoxed();
163 }
164
165 void load(BytecodeAssembler assembler) {
166 assembler.loadBoxedParameterSlot(slot);
167 }
168
169 void loadRaw(BytecodeAssembler assembler) {
170 assembler.loadParameterSlot(slot);
171 }
172
173 void store(BytecodeAssembler assembler) {
174 assembler.storeBoxedParameterSlot(slot);
175 }
176
177 String toString() => "BoxedParameter($element, $slot)";
178 }
179
180 /**
181 * A reference to a local value that is boxed.
182 */
183 class UnboxedParameterValue extends LocalValue {
184 UnboxedParameterValue(
185 int parameter,
186 Element element,
187 BytecodeAssembler assembler)
188 : super(assembler.computeParameterSlot(parameter), element);
189
190 void initialize(BytecodeAssembler assembler) {}
191
192 void load(BytecodeAssembler assembler) {
193 assembler.loadParameterSlot(slot);
194 }
195
196 void store(BytecodeAssembler assembler) {
197 assembler.storeParameterSlot(slot);
198 }
199
200 String toString() => "Parameter($element, $slot)";
201 }
202
203 class JumpInfo {
204 final int stackSize;
205 final BytecodeLabel continueLabel;
206 final BytecodeLabel breakLabel;
207 JumpInfo(this.stackSize, this.continueLabel, this.breakLabel);
208 }
209
210 class TryBlock {
211 final int stackSize;
212 final BytecodeLabel finallyLabel;
213 final BytecodeLabel finallyReturnLabel;
214 TryBlock(this.stackSize, this.finallyLabel, this.finallyReturnLabel);
215 }
216
217 abstract class CodegenVisitor
218 extends SemanticVisitor
219 with GetBulkMixin,
220 SetBulkMixin,
221 ErrorBulkMixin,
222 InvokeBulkMixin,
223 IndexSetBulkMixin,
224 CompoundBulkMixin,
225 UnaryBulkMixin,
226 BaseBulkMixin,
227 BinaryBulkMixin,
228 PrefixBulkMixin,
229 PostfixBulkMixin,
230 NewBulkMixin,
231 VariableBulkMixin,
232 ParameterBulkMixin,
233 FunctionBulkMixin,
234 ConstructorBulkMixin,
235 InitializerBulkMixin,
236 BaseImplementationOfStaticsMixin,
237 BaseImplementationOfLocalsMixin,
238 SetIfNullBulkMixin
239 implements SemanticSendVisitor, SemanticDeclarationVisitor {
240 // A literal int can have up to 31 bits of information (32 minus sign).
241 static const int LITERAL_INT_MAX = 0x3FFFFFFF;
242 static const int MAX_INT64 = (1 << 63) - 1;
243 static const int MIN_INT64 = -(1 << 63);
244
245 final FletchContext context;
246
247 final ClosureEnvironment closureEnvironment;
248
249 final ExecutableElement element;
250
251 final FletchFunctionBuilder functionBuilder;
252
253 final Map<Element, LocalValue> scope = <Element, LocalValue>{};
254
255 final Map<Node, JumpInfo> jumpInfo = <Node, JumpInfo>{};
256
257 // Stack of try blocks (inner-most first), in the lexical scope.
258 Link<TryBlock> tryBlockStack = const Link<TryBlock>();
259
260 VisitState visitState;
261 BytecodeLabel trueLabel;
262 BytecodeLabel falseLabel;
263
264 // TODO(ajohnsen): Merge computation into constructor.
265 // The slot at which 'this' is stored. In closures, this is overwritten.
266 LocalValue thisValue;
267
268 TreeElements initializerElements;
269
270 List<Element> blockLocals = <Element>[];
271
272 /// A FunctionExpression in this set is a named local function declaration.
273 /// Many calls to such functions are statically bound. So if `f` is a named
274 /// local function declaration, `f()` doesn't need to be registered as a
275 /// dynamic send.
276 // TODO(ahe): Get rid of this by refactoring initializeLocal. See TODO there.
277 final Set<FunctionExpression> functionDeclarations =
278 new Set<FunctionExpression>();
279
280 CodegenVisitor(this.functionBuilder,
281 this.context,
282 TreeElements elements,
283 this.closureEnvironment,
284 this.element)
285 : super(elements) {
286 if (functionBuilder.isInstanceMember) {
287 thisValue = new UnboxedParameterValue(0, null, assembler);
288 }
289 }
290
291 TreeElements get elements {
292 if (initializerElements != null) return initializerElements;
293 return super.elements;
294 }
295
296 BytecodeAssembler get assembler => functionBuilder.assembler;
297
298 SemanticSendVisitor get sendVisitor => this;
299 SemanticDeclarationVisitor get declVisitor => this;
300
301 void compile();
302
303 ConstantExpression compileConstant(
304 Node node,
305 {TreeElements elements,
306 bool isConst}) {
307 if (elements == null) elements = this.elements;
308 return context.compileConstant(node, elements, isConst: isConst);
309 }
310
311 ConstantExpression inspectConstant(
312 Node node,
313 {TreeElements elements,
314 bool isConst}) {
315 if (elements == null) elements = this.elements;
316 return context.inspectConstant(node, elements, isConst: isConst);
317 }
318
319 bool isConstNull(Node node) {
320 ConstantExpression expression = inspectConstant(node, isConst: false);
321 if (expression == null) return false;
322 return context.getConstantValue(expression).isNull;
323 }
324
325 int allocateConstantFromNode(Node node, {TreeElements elements}) {
326 ConstantExpression expression = compileConstant(
327 node,
328 elements: elements,
329 isConst: false);
330 return functionBuilder.allocateConstant(
331 context.getConstantValue(expression));
332 }
333
334 int allocateConstantClassInstance(int classId) {
335 var constant = new FletchClassInstanceConstant(classId);
336 context.markConstantUsed(constant);
337 return functionBuilder.allocateConstant(constant);
338 }
339
340 int allocateStringConstant(String string) {
341 return functionBuilder.allocateConstant(
342 context.backend.constantSystem.createString(
343 new DartString.literal(string)));
344 }
345
346 ClosureInfo get closureInfo => closureEnvironment.closures[element];
347
348 LocalValue createLocalValueFor(
349 LocalElement element,
350 {int slot,
351 bool isCapturedValueBoxed: true}) {
352 if (slot == null) slot = assembler.stackSize;
353 if (closureEnvironment.shouldBeBoxed(element)) {
354 if (isCapturedValueBoxed) {
355 return new BoxedLocalValue(slot, element);
356 }
357 LocalValue value = new BoxedLocalValue(assembler.stackSize, element);
358 assembler.loadSlot(slot);
359 value.initialize(assembler);
360 return value;
361 }
362
363 return new UnboxedLocalValue(slot, element);
364 }
365
366 LocalValue createLocalValueForParameter(
367 ParameterElement parameter,
368 int index,
369 {bool isCapturedValueBoxed: true}) {
370 // TODO(kasperl): Use [ParameterElement.constant] instead when
371 // [ConstantValue] can be computed on-the-fly from a [ConstantExpression].
372 Expression initializer = parameter.initializer;
373 if (initializer != null) {
374 // If the parameter has an initializer expression, we ask the context
375 // to compile it right away to make sure we enqueue all dependent
376 // elements correctly before we start assembling the program.
377 context.compileConstant(
378 initializer,
379 parameter.memberContext.resolvedAst.elements,
380 isConst: true);
381 }
382
383 if (closureEnvironment.shouldBeBoxed(parameter)) {
384 if (isCapturedValueBoxed) {
385 return new BoxedParameterValue(index, parameter, assembler);
386 }
387 LocalValue value = new BoxedLocalValue(assembler.stackSize, parameter);
388 assembler.loadParameter(index);
389 value.initialize(assembler);
390 return value;
391 }
392 return new UnboxedParameterValue(index, parameter, assembler);
393 }
394
395 void pushVariableDeclaration(LocalValue value) {
396 scope[value.element] = value;
397 }
398
399 void popVariableDeclaration(Element local) {
400 scope.remove(local);
401 }
402
403 void registerDynamicUse(Selector selector);
404
405 void registerStaticUse(StaticUse use);
406
407 void registerInstantiatedClass(ClassElement klass);
408
409 void registerIsCheck(DartType type);
410
411 void registerLocalInvoke(LocalElement element, Selector selector);
412
413 /// Register that [element] is a closure. This can happen for a tear-off, or
414 /// for local functions. See [ClosureKind] for more information about the
415 /// various kinds of implicit or explicit closurizations that can occur.
416 void registerClosurization(FunctionElement element, ClosureKind kind);
417
418 int compileLazyFieldInitializer(FieldElement field);
419
420 void invokeMethod(Node node, Selector selector) {
421 registerDynamicUse(selector);
422 String symbol = context.getSymbolFromSelector(selector);
423 int id = context.getSymbolId(symbol);
424 int arity = selector.argumentCount;
425 int fletchSelector = FletchSelector.encodeMethod(id, arity);
426 assembler.invokeMethod(fletchSelector, arity, selector.name);
427 }
428
429 void invokeGetter(Node node, Name name) {
430 registerDynamicUse(new Selector.getter(name));
431 String symbol = context.mangleName(name);
432 int id = context.getSymbolId(symbol);
433 int fletchSelector = FletchSelector.encodeGetter(id);
434 assembler.invokeMethod(fletchSelector, 0);
435 }
436
437 void invokeSetter(Node node, Name name) {
438 registerDynamicUse(new Selector.setter(name));
439 String symbol = context.mangleName(name);
440 int id = context.getSymbolId(symbol);
441 int fletchSelector = FletchSelector.encodeSetter(id);
442 assembler.invokeMethod(fletchSelector, 1);
443 }
444
445 void invokeFactory(Node node, int constId, int arity) {
446 assembler.invokeFactory(constId, arity);
447 }
448
449 void invokeStatic(Node node, int constId, int arity) {
450 assembler.invokeStatic(constId, arity);
451 }
452
453 void generateIdentical(Node node) {
454 assembler.identical();
455 }
456
457 void generateIdenticalNonNumeric(Node node) {
458 assembler.identicalNonNumeric();
459 }
460
461 void generateReturn(Node node) {
462 assembler.ret();
463 }
464
465 void generateReturnNull(Node node) {
466 assembler.returnNull();
467 }
468
469 void generateThrow(Node node) {
470 assembler.emitThrow();
471 }
472
473 void generateSwitchCaseMatch(CaseMatch caseMatch, BytecodeLabel ifTrue) {
474 assembler.dup();
475 int constId = allocateConstantFromNode(caseMatch.expression);
476 assembler.loadConst(constId);
477 // For debugging, ignore the equality checks in connection
478 // with case matches by not associating the calls with
479 // any node.
480 invokeMethod(null, new Selector.binaryOperator('=='));
481 assembler.branchIfTrue(ifTrue);
482 }
483
484 FletchFunctionBase requireFunction(FunctionElement element) {
485 // TODO(johnniwinther): More precise use.
486 registerStaticUse(new StaticUse.foreignUse(element));
487 return context.backend.getFunctionForElement(element);
488 }
489
490 FletchFunctionBase requireConstructorInitializer(
491 ConstructorElement constructor) {
492 assert(constructor.isGenerativeConstructor);
493 registerInstantiatedClass(constructor.enclosingClass);
494 registerStaticUse(new StaticUse.foreignUse(constructor));
495 return context.backend.getConstructorInitializerFunction(constructor);
496 }
497
498 void doStaticFunctionInvoke(
499 Node node,
500 FletchFunctionBase function,
501 NodeList arguments,
502 CallStructure callStructure,
503 {bool factoryInvoke: false}) {
504 if (function.isInstanceMember) loadThis();
505 FunctionSignature signature = function.signature;
506 int functionId;
507 int arity;
508 if (signature.hasOptionalParameters &&
509 signature.optionalParametersAreNamed) {
510 if (FletchBackend.isExactParameterMatch(signature, callStructure)) {
511 functionId = function.functionId;
512 } else if (callStructure.signatureApplies(signature)) {
513 // TODO(ajohnsen): Inline parameter stub?
514 FletchFunctionBase stub = context.backend.createParameterStub(
515 function,
516 callStructure.callSelector);
517 functionId = stub.functionId;
518 } else {
519 doUnresolved(function.name);
520 return;
521 }
522 for (Node argument in arguments) {
523 visitForValue(argument);
524 }
525 arity = callStructure.argumentCount;
526 } else if (callStructure != null &&
527 callStructure.namedArguments.isNotEmpty) {
528 doUnresolved(function.name);
529 return;
530 } else {
531 functionId = function.functionId;
532 arity = loadPositionalArguments(arguments, signature, function.name);
533 }
534 if (function.isInstanceMember) arity++;
535 int constId = functionBuilder.allocateConstantFromFunction(functionId);
536 if (factoryInvoke) {
537 invokeFactory(node, constId, arity);
538 } else {
539 invokeStatic(node, constId, arity);
540 }
541 }
542
543 void loadThis() {
544 thisValue.load(assembler);
545 }
546
547 /**
548 * Load the [arguments] for caling [function], with potential positional
549 * arguments.
550 *
551 * Return the number of arguments pushed onto the stack.
552 */
553 int loadPositionalArguments(
554 NodeList arguments,
555 FunctionSignature signature,
556 String name) {
557 int argumentCount = 0;
558 Iterator<Node> it = arguments.iterator;
559 signature.orderedForEachParameter((ParameterElement parameter) {
560 if (it.moveNext()) {
561 visitForValue(it.current);
562 } else {
563 if (parameter.isOptional) {
564 doParameterInitializer(parameter);
565 } else {
566 doUnresolved(name);
567 }
568 }
569 argumentCount++;
570 });
571 if (it.moveNext()) doUnresolved(name);
572 return argumentCount;
573 }
574
575 void doParameterInitializer(ParameterElement parameter) {
576 Expression initializer = parameter.initializer;
577 if (initializer == null) {
578 assembler.loadLiteralNull();
579 } else {
580 var previousElements = initializerElements;
581 initializerElements = parameter.resolvedAst.elements;
582 visitForValue(initializer);
583 initializerElements = previousElements;
584 }
585 }
586
587 void doVisitForValue(Node node) {
588 VisitState oldState = visitState;
589 visitState = VisitState.Value;
590 node.accept(this);
591 visitState = oldState;
592 }
593
594 // Visit the expression [node] and push the result on top of the stack.
595 void visitForValue(Node node) {
596 doVisitForValue(node);
597 }
598
599 // Visit the expression [node] and push the result on top of the stack.
600 // This method bypasses debug information collection and using this
601 // method will not generate breakpoints for the expression evaluation.
602 // This is useful when dealing with internal details that the programmer
603 // shouldn't care about such as the string concatenation aspects of
604 // of string interpolation.
605 void visitForValueNoDebugInfo(Node node) {
606 doVisitForValue(node);
607 }
608
609 // Visit the expression [node] without pushing the result on top of the stack.
610 void visitForEffect(Node node) {
611 VisitState oldState = visitState;
612 visitState = VisitState.Effect;
613 node.accept(this);
614 visitState = oldState;
615 }
616
617 // Visit the expression [node] with the result being a branch to either
618 // [trueLabel] or [falseLabel].
619 void visitForTest(
620 Node node,
621 BytecodeLabel trueLabel,
622 BytecodeLabel falseLabel) {
623 VisitState oldState = visitState;
624 visitState = VisitState.Test;
625 BytecodeLabel oldTrueLabel = this.trueLabel;
626 this.trueLabel = trueLabel;
627 BytecodeLabel oldFalseLabel = this.falseLabel;
628 this.falseLabel = falseLabel;
629
630 assert(trueLabel != null || falseLabel != null);
631 node.accept(this);
632
633 visitState = oldState;
634 this.trueLabel = oldTrueLabel;
635 this.falseLabel = oldFalseLabel;
636 }
637
638 void negateTest() {
639 assert(visitState == VisitState.Test);
640 BytecodeLabel temporary = trueLabel;
641 trueLabel = falseLabel;
642 falseLabel = temporary;
643 }
644
645 void applyVisitState() {
646 if (visitState == VisitState.Effect) {
647 assembler.pop();
648 } else if (visitState == VisitState.Test) {
649 if (trueLabel == null) {
650 assembler.branchIfFalse(falseLabel);
651 } else if (falseLabel == null) {
652 assembler.branchIfTrue(trueLabel);
653 } else {
654 assembler.branchIfTrue(trueLabel);
655 assembler.branch(falseLabel);
656 }
657 }
658 }
659
660 void visitNamedArgument(NamedArgument node) {
661 Expression expression = node.expression;
662 if (expression != null) {
663 visitForValue(expression);
664 } else {
665 assembler.loadLiteralNull();
666 }
667 applyVisitState();
668 }
669
670 void doLocalVariableCompound(
671 Node node,
672 LocalVariableElement variable,
673 AssignmentOperator operator,
674 Node rhs) {
675 LocalValue value = scope[variable];
676 value.load(assembler);
677 visitForValue(rhs);
678 String operatorName = operator.binaryOperator.name;
679 invokeMethod(node, new Selector.binaryOperator(operatorName));
680 value.store(assembler);
681 }
682
683 void visitLocalVariableCompound(
684 Send node,
685 LocalVariableElement variable,
686 AssignmentOperator operator,
687 Node rhs,
688 _) {
689 doLocalVariableCompound(node, variable, operator, rhs);
690 applyVisitState();
691 }
692
693 void visitParameterCompound(
694 Send node,
695 LocalParameterElement parameter,
696 AssignmentOperator operator,
697 Node rhs,
698 _) {
699 doLocalVariableCompound(node, parameter, operator, rhs);
700 applyVisitState();
701 }
702
703 void doStaticFieldCompound(
704 Node node,
705 FieldElement field,
706 AssignmentOperator operator,
707 Node rhs) {
708 doStaticFieldGet(field);
709 visitForValue(rhs);
710 Selector selector = new Selector.binaryOperator(
711 operator.binaryOperator.name);
712 invokeMethod(node, selector);
713 doStaticFieldSet(field);
714 }
715
716 void visitTopLevelFieldCompound(
717 Send node,
718 FieldElement field,
719 AssignmentOperator operator,
720 Node rhs,
721 _) {
722 doStaticFieldCompound(node, field, operator, rhs);
723 applyVisitState();
724 }
725
726 void visitStaticFieldCompound(
727 Send node,
728 FieldElement field,
729 AssignmentOperator operator,
730 Node rhs,
731 _) {
732 doStaticFieldCompound(node, field, operator, rhs);
733 applyVisitState();
734 }
735
736 void doBinaryOperator(
737 Node node,
738 Node left,
739 Node right,
740 BinaryOperator operator) {
741 visitForValue(left);
742 visitForValue(right);
743 // For '==', if either side is a null literal, use identicalNonNumeric.
744 if (operator == BinaryOperator.EQ &&
745 (isConstNull(left) || isConstNull(right))) {
746 generateIdenticalNonNumeric(node);
747 return;
748 }
749
750 Selector selector = new Selector.binaryOperator(operator.name);
751 invokeMethod(node, selector);
752 }
753
754 void visitEquals(
755 Send node,
756 Node left,
757 Node right,
758 _) {
759 // TODO(ajohnsen): Inject null check (in callee).
760 doBinaryOperator(node, left, right, BinaryOperator.EQ);
761 applyVisitState();
762 }
763
764 void visitNotEquals(
765 Send node,
766 Node left,
767 Node right,
768 _) {
769 doBinaryOperator(node, left, right, BinaryOperator.EQ);
770 if (visitState == VisitState.Test) {
771 negateTest();
772 } else {
773 assembler.negate();
774 }
775 applyVisitState();
776 }
777
778 void visitBinary(
779 Send node,
780 Node left,
781 BinaryOperator operator,
782 Node right,
783 _) {
784 doBinaryOperator(node, left, right, operator);
785 applyVisitState();
786 }
787
788 void visitUnary(
789 Send node,
790 UnaryOperator operator,
791 Node value,
792 _) {
793 visitForValue(value);
794 Selector selector = new Selector.unaryOperator(operator.name);
795 invokeMethod(node, selector);
796 applyVisitState();
797 }
798
799 void visitNot(
800 Send node,
801 Node value,
802 _) {
803 if (visitState == VisitState.Test) {
804 visitForTest(value, falseLabel, trueLabel);
805 } else {
806 visitForValue(value);
807 assembler.negate();
808 applyVisitState();
809 }
810 }
811
812 void visitIndex(
813 Send node,
814 Node receiver,
815 Node index,
816 _) {
817 visitForValue(receiver);
818 visitForValue(index);
819 Selector selector = new Selector.index();
820 invokeMethod(node, selector);
821 applyVisitState();
822 }
823
824 void visitIndexSet(
825 SendSet node,
826 Node receiver,
827 Node index,
828 Node value,
829 _) {
830 visitForValue(receiver);
831 visitForValue(index);
832 visitForValue(value);
833 Selector selector = new Selector.indexSet();
834 invokeMethod(node, selector);
835 applyVisitState();
836 }
837
838 void visitLogicalAnd(
839 Send node,
840 Node left,
841 Node right,
842 _) {
843 if (visitState == VisitState.Test) {
844 if (falseLabel == null) {
845 BytecodeLabel ifFalse = new BytecodeLabel();
846 visitForTest(left, null, ifFalse);
847 visitForTest(right, trueLabel, null);
848 assembler.bind(ifFalse);
849 } else {
850 visitForTest(left, null, falseLabel);
851 visitForTest(right, trueLabel, falseLabel);
852 }
853 return;
854 }
855
856 BytecodeLabel isFalse = new BytecodeLabel();
857 assembler.loadLiteralFalse();
858
859 visitForTest(left, null, isFalse);
860 visitForTest(right, null, isFalse);
861 assembler.pop();
862 assembler.loadLiteralTrue();
863
864 assembler.bind(isFalse);
865 applyVisitState();
866 }
867
868 void visitLogicalOr(
869 Send node,
870 Node left,
871 Node right,
872 _) {
873 if (visitState == VisitState.Test) {
874 if (trueLabel == null) {
875 BytecodeLabel ifTrue = new BytecodeLabel();
876 visitForTest(left, ifTrue, null);
877 visitForTest(right, null, falseLabel);
878 assembler.bind(ifTrue);
879 } else {
880 visitForTest(left, trueLabel, null);
881 visitForTest(right, trueLabel, falseLabel);
882 }
883 return;
884 }
885
886 BytecodeLabel isTrue = new BytecodeLabel();
887 assembler.loadLiteralTrue();
888
889 visitForTest(left, isTrue, null);
890 visitForTest(right, isTrue, null);
891 assembler.pop();
892 assembler.loadLiteralFalse();
893
894 assembler.bind(isTrue);
895 applyVisitState();
896 }
897
898 void visitConditional(Conditional node) {
899 BytecodeLabel isFalse = new BytecodeLabel();
900 BytecodeLabel done = new BytecodeLabel();
901
902 assembler.loadLiteralNull();
903
904 visitForTest(node.condition, null, isFalse);
905
906 assembler.pop();
907 visitForValue(node.thenExpression);
908 assembler.branch(done);
909
910 assembler.bind(isFalse);
911 assembler.pop();
912 visitForValue(node.elseExpression);
913
914 assembler.bind(done);
915
916 applyVisitState();
917 }
918
919 void callIsSelector(
920 Node node,
921 DartType type,
922 // TODO(ahe): Remove [diagnosticLocation] when malformed types are
923 // handled.
924 Spannable diagnosticLocation) {
925 if (type == null || type.isMalformed) {
926 assembler.pop();
927 generateUnimplementedError(
928 diagnosticLocation, "Unhandled type test for malformed $type.");
929 return;
930 }
931
932 registerIsCheck(type);
933
934 if (type.isDynamic) {
935 assembler.pop();
936 assembler.loadLiteralTrue();
937 return;
938 }
939
940 if (type.isTypedef) {
941 // TODO(ajohnsen): This only matches with the number of arguments, not
942 // the actual argument types.
943 TypedefType typedefType = type;
944 int arity = typedefType.element.functionSignature.parameterCount;
945 int fletchSelector = context.toFletchIsSelector(
946 context.backend.compiler.coreClasses.functionClass, arity);
947 assembler.invokeTest(fletchSelector, 0);
948 return;
949 }
950
951 if (!type.isInterfaceType) {
952 assembler.pop();
953 generateUnimplementedError(
954 diagnosticLocation, "Unhandled type test for $type.");
955 return;
956 }
957
958 Element element = type.element;
959 int fletchSelector = context.toFletchIsSelector(element);
960 assembler.invokeTest(fletchSelector, 0);
961 }
962
963 void doIs(
964 Node node,
965 Node expression,
966 DartType type,
967 // TODO(ahe): Remove [diagnosticLocation] when callIsSelector does not
968 // require it.
969 Spannable diagnosticLocation) {
970 visitForValue(expression);
971 callIsSelector(node, type, diagnosticLocation);
972 }
973
974 void visitIs(
975 Send node,
976 Node expression,
977 DartType type,
978 _) {
979 doIs(node, expression, type, node.arguments.first);
980 applyVisitState();
981 }
982
983 void visitIsNot(
984 Send node,
985 Node expression,
986 DartType type,
987 _) {
988 doIs(node, expression, type, node.arguments.first);
989 if (visitState == VisitState.Test) {
990 negateTest();
991 } else {
992 assembler.negate();
993 }
994 applyVisitState();
995 }
996
997 void visitAs(
998 Send node,
999 Node expression,
1000 DartType type,
1001 _) {
1002 // TODO(ajohnsen): To actual type check.
1003 visitForValue(expression);
1004 applyVisitState();
1005 }
1006
1007 void visitThisGet(
1008 Node node,
1009 _) {
1010 loadThis();
1011 applyVisitState();
1012 }
1013
1014 void doIdenticalCall(Node node, NodeList arguments) {
1015 assert(arguments.slowLength() == 2);
1016 for (Node argument in arguments) {
1017 visitForValue(argument);
1018 }
1019 generateIdentical(node);
1020 }
1021
1022 void handleStaticFunctionGet(
1023 Send node,
1024 MethodElement function,
1025 _) {
1026 registerClosurization(function, ClosureKind.tearOff);
1027 FletchFunctionBase target = requireFunction(function);
1028 FletchClassBuilder classBuilder =
1029 context.backend.createTearoffClass(target);
1030 assert(classBuilder.fields == 0);
1031 int constId = allocateConstantClassInstance(classBuilder.classId);
1032 assembler.loadConst(constId);
1033 applyVisitState();
1034 }
1035
1036 void doMainCall(Send node, NodeList arguments) {
1037 FunctionElement function = context.compiler.mainFunction;
1038 if (function.isMalformed) {
1039 DiagnosticMessage message =
1040 context.compiler.elementsWithCompileTimeErrors[function];
1041 if (message == null) {
1042 // TODO(johnniwinther): The error should always be associated with the
1043 // element.
1044 // Example triggering this:
1045 // ```
1046 // [
1047 // main() {}
1048 // ```
1049 message = context.compiler.reporter.createMessage(
1050 function, MessageKind.GENERIC, {'text': 'main is malformed.'});
1051 }
1052 doCompileError(message);
1053 return;
1054 }
1055 if (context.compiler.libraryLoader.libraries.any(checkCompileError)) return;
1056
1057 // Load up to 'parameterCount' arguments, padding with nulls.
1058 int parameterCount = function.functionSignature.parameterCount;
1059 int argumentCount = 0;
1060 for (Node argument in arguments) {
1061 if (argumentCount == parameterCount) break;
1062 visitForValue(argument);
1063 argumentCount++;
1064 }
1065 for (int i = argumentCount; i < parameterCount; i++) {
1066 assembler.loadLiteralNull();
1067 }
1068
1069 FletchFunctionBase base = requireFunction(function);
1070 int constId = functionBuilder.allocateConstantFromFunction(base.functionId);
1071 invokeStatic(node, constId, parameterCount);
1072 }
1073
1074 void doStaticallyBoundInvoke(
1075 Send node,
1076 MethodElement element,
1077 NodeList arguments,
1078 CallStructure callStructure) {
1079 if (checkCompileError(element)) return;
1080 if (element.declaration == context.compiler.identicalFunction) {
1081 doIdenticalCall(node, arguments);
1082 return;
1083 }
1084 if (element.isExternal) {
1085 // Patch known functions directly.
1086 if (element == context.backend.fletchExternalInvokeMain) {
1087 doMainCall(node, arguments);
1088 return;
1089 } else if (element == context.backend.fletchExternalCoroutineChange) {
1090 for (Node argument in arguments) {
1091 visitForValue(argument);
1092 }
1093 assembler.coroutineChange();
1094 return;
1095 }
1096 // TODO(ajohnsen): Define a known set of external functions we allow
1097 // calls to?
1098 }
1099 FletchFunctionBase target = requireFunction(element);
1100 doStaticFunctionInvoke(node, target, arguments, callStructure);
1101 }
1102
1103 void handleStaticFunctionInvoke(
1104 Send node,
1105 MethodElement element,
1106 NodeList arguments,
1107 CallStructure callStructure,
1108 _) {
1109 doStaticallyBoundInvoke(
1110 node, element.declaration, arguments, callStructure);
1111 applyVisitState();
1112 }
1113
1114 void visitSuperMethodInvoke(
1115 Send node,
1116 MethodElement element,
1117 NodeList arguments,
1118 CallStructure callStructure,
1119 _) {
1120 doStaticallyBoundInvoke(node, element, arguments, callStructure);
1121 applyVisitState();
1122 }
1123
1124 void doSuperCall(Node node, FunctionElement function) {
1125 registerStaticUse(new StaticUse.foreignUse(function));
1126 int arity = function.functionSignature.parameterCount + 1;
1127 FletchFunctionBase base = requireFunction(function);
1128 int constId = functionBuilder.allocateConstantFromFunction(base.functionId);
1129 invokeStatic(node, constId, arity);
1130 }
1131
1132 void visitSuperGetterGet(
1133 Send node,
1134 FunctionElement getter,
1135 _) {
1136 loadThis();
1137 doSuperCall(node, getter);
1138 applyVisitState();
1139 }
1140
1141 void visitSuperMethodGet(
1142 Send node,
1143 MethodElement method,
1144 _) {
1145 registerClosurization(method, ClosureKind.superTearOff);
1146 loadThis();
1147 FletchFunctionBase target = requireFunction(method);
1148 FletchClassBuilder classBuilder =
1149 context.backend.createTearoffClass(target);
1150 assert(classBuilder.fields == 1);
1151 int constId = functionBuilder.allocateConstantFromClass(
1152 classBuilder.classId);
1153 assembler.allocate(constId, classBuilder.fields);
1154 applyVisitState();
1155 }
1156
1157 void visitSuperSetterSet(
1158 SendSet node,
1159 FunctionElement setter,
1160 Node rhs,
1161 _) {
1162 loadThis();
1163 visitForValue(rhs);
1164 doSuperCall(node, setter);
1165 applyVisitState();
1166 }
1167
1168 void visitSuperIndex(
1169 Send node,
1170 FunctionElement function,
1171 Node index,
1172 _) {
1173 loadThis();
1174 visitForValue(index);
1175 doSuperCall(node, function);
1176 applyVisitState();
1177 }
1178
1179 void visitSuperIndexSet(
1180 Send node,
1181 FunctionElement function,
1182 Node index,
1183 Node rhs,
1184 _) {
1185 loadThis();
1186 visitForValue(index);
1187 visitForValue(rhs);
1188 doSuperCall(node, function);
1189 applyVisitState();
1190 }
1191
1192 void visitSuperCompoundIndexSet(
1193 Send node,
1194 FunctionElement getter,
1195 FunctionElement setter,
1196 Node index,
1197 AssignmentOperator operator,
1198 Node rhs,
1199 _) {
1200 visitForValue(index);
1201 loadThis();
1202 assembler.loadLocal(1);
1203 doSuperCall(node, getter);
1204 loadThis();
1205 // Load index
1206 assembler.loadLocal(2);
1207 // Load value from index call and call operator.
1208 assembler.loadLocal(2);
1209 visitForValue(rhs);
1210 invokeMethod(node, getAssignmentSelector(operator));
1211 doSuperCall(node, setter);
1212 // Override 'index' with result value, and pop everything else.
1213 assembler.storeLocal(2);
1214 assembler.popMany(2);
1215 applyVisitState();
1216 }
1217
1218 void visitSuperIndexPostfix(
1219 SendSet node,
1220 FunctionElement getter,
1221 FunctionElement setter,
1222 Node index,
1223 IncDecOperator operator,
1224 _) {
1225 // TODO(ajohnsen): Fast-case when for effect.
1226 visitForValue(index);
1227 loadThis();
1228 assembler.loadLocal(1);
1229 doSuperCall(node, getter);
1230 loadThis();
1231 // Load index
1232 assembler.loadLocal(2);
1233 // Load value from index call and inc/dec.
1234 assembler.loadLocal(2);
1235 assembler.loadLiteral(1);
1236 invokeMethod(node, getIncDecSelector(operator));
1237 // We can now call []= with 'this', 'index' and 'value'.
1238 doSuperCall(node, setter);
1239 assembler.pop();
1240 // Pop result, override 'index' with initial indexed value, and pop again.
1241 assembler.storeLocal(1);
1242 assembler.pop();
1243 applyVisitState();
1244 }
1245
1246 void visitSuperBinary(
1247 Send node,
1248 FunctionElement function,
1249 BinaryOperator operator,
1250 Node argument,
1251 _) {
1252 loadThis();
1253 visitForValue(argument);
1254 doSuperCall(node, function);
1255 applyVisitState();
1256 }
1257
1258 void visitSuperEquals(
1259 Send node,
1260 FunctionElement function,
1261 Node argument,
1262 _) {
1263 loadThis();
1264 visitForValue(argument);
1265 doSuperCall(node, function);
1266 applyVisitState();
1267 }
1268
1269 void visitSuperUnary(
1270 Send node,
1271 UnaryOperator operator,
1272 FunctionElement function,
1273 _) {
1274 loadThis();
1275 doSuperCall(node, function);
1276 applyVisitState();
1277 }
1278
1279 int computeFieldIndex(FieldElement field) {
1280 ClassElement classElement = element.enclosingClass;
1281 int fieldIndex;
1282 FletchClassBuilder classBuilder;
1283 do {
1284 // We need to find the mixin application of the class, where the field
1285 // is stored. Iterate until it's found.
1286 classBuilder = context.backend.registerClassElement(classElement);
1287 classElement = classElement.implementation;
1288 int i = 0;
1289 classElement.forEachInstanceField((_, FieldElement member) {
1290 if (member == field) {
1291 assert(fieldIndex == null);
1292 fieldIndex = i;
1293 }
1294 i++;
1295 });
1296 classElement = classElement.superclass;
1297 } while (fieldIndex == null);
1298 fieldIndex += classBuilder.superclassFields;
1299 return fieldIndex;
1300 }
1301
1302 void visitSuperFieldGet(
1303 Send node,
1304 FieldElement field,
1305 _) {
1306 loadThis();
1307 assembler.loadField(computeFieldIndex(field));
1308 applyVisitState();
1309 }
1310
1311 void visitSuperFieldSet(
1312 SendSet node,
1313 FieldElement field,
1314 Node rhs,
1315 _) {
1316 loadThis();
1317 visitForValue(rhs);
1318 assembler.storeField(computeFieldIndex(field));
1319 applyVisitState();
1320 }
1321
1322 void handleStaticFieldInvoke(
1323 Node node,
1324 FieldElement field,
1325 NodeList arguments,
1326 CallStructure callStructure,
1327 _) {
1328 doStaticFieldGet(field);
1329 for (Node argument in arguments) {
1330 visitForValue(argument);
1331 }
1332 invokeMethod(node, callStructure.callSelector);
1333 applyVisitState();
1334 }
1335
1336 void visitDynamicPropertyInvoke(
1337 Send node,
1338 Node receiver,
1339 NodeList arguments,
1340 Selector selector,
1341 _) {
1342 visitForValue(receiver);
1343 for (Node argument in arguments) {
1344 visitForValue(argument);
1345 }
1346 invokeMethod(node, selector);
1347 applyVisitState();
1348 }
1349
1350 void visitIfNull(
1351 Send node,
1352 Node left,
1353 Node right,
1354 _) {
1355 BytecodeLabel end = new BytecodeLabel();
1356 visitForValue(left);
1357 assembler.dup();
1358 assembler.loadLiteralNull();
1359 assembler.identicalNonNumeric();
1360 assembler.branchIfFalse(end);
1361 assembler.pop();
1362 visitForValue(right);
1363 assembler.bind(end);
1364 applyVisitState();
1365 }
1366
1367 void doIfNotNull(Node receiver, void ifNotNull()) {
1368 BytecodeLabel end = new BytecodeLabel();
1369 visitForValue(receiver);
1370 assembler.dup();
1371 assembler.loadLiteralNull();
1372 assembler.identicalNonNumeric();
1373 assembler.branchIfTrue(end);
1374 ifNotNull();
1375 assembler.bind(end);
1376 }
1377
1378 void visitIfNotNullDynamicPropertyInvoke(
1379 Send node,
1380 Node receiver,
1381 NodeList arguments,
1382 Selector selector,
1383 _) {
1384 doIfNotNull(receiver, () {
1385 for (Node argument in arguments) {
1386 visitForValue(argument);
1387 }
1388 invokeMethod(node, selector);
1389 });
1390 applyVisitState();
1391 }
1392
1393 void visitExpressionInvoke(
1394 Send node,
1395 Expression receiver,
1396 NodeList arguments,
1397 CallStructure callStructure,
1398 _) {
1399 visitForValue(receiver);
1400 for (Node argument in arguments) {
1401 visitForValue(argument);
1402 }
1403 invokeMethod(node, new Selector.call(Names.call, callStructure));
1404 applyVisitState();
1405 }
1406
1407 void visitThisPropertyInvoke(
1408 Send node,
1409 NodeList arguments,
1410 Selector selector,
1411 _) {
1412 loadThis();
1413
1414 // If the property is statically known to be a field, instead invoke the
1415 // getter and then invoke 'call(...)' on the value.
1416 // TODO(ajohnsen): This is a fix that only works when the field is
1417 // statically known - that is not always the case. Implement VM support?
1418 Element target = elements[node];
1419 if (target != null && target.isField) {
1420 invokeGetter(node, new Name(target.name, element.library));
1421 selector = new Selector.callClosureFrom(selector);
1422 }
1423 for (Node argument in arguments) {
1424 visitForValue(argument);
1425 }
1426 invokeMethod(node, selector);
1427 applyVisitState();
1428 }
1429
1430 void visitThisInvoke(
1431 Send node,
1432 NodeList arguments,
1433 CallStructure callStructure,
1434 _) {
1435 loadThis();
1436 for (Node argument in arguments) {
1437 visitForValue(argument);
1438 }
1439 invokeMethod(node, callStructure.callSelector);
1440 applyVisitState();
1441 }
1442
1443 void visitClassTypeLiteralGet(
1444 Send node,
1445 ConstantExpression constant,
1446 _) {
1447 generateUnimplementedError(
1448 node, "[visitClassTypeLiteralGet] isn't implemented.");
1449 applyVisitState();
1450 }
1451
1452 void visitDynamicPropertyGet(
1453 Send node,
1454 Node receiver,
1455 Name name,
1456 _) {
1457 if (name.text == "runtimeType") {
1458 // TODO(ahe): Implement runtimeType.
1459 generateUnimplementedError(
1460 node,
1461 "'runtimeType' isn't supported in Fletch. See https://goo.gl/ELH6Zc");
1462 applyVisitState();
1463 return;
1464 }
1465 visitForValue(receiver);
1466 invokeGetter(node, name);
1467 applyVisitState();
1468 }
1469
1470 void visitIfNotNullDynamicPropertyGet(
1471 Send node,
1472 Node receiver,
1473 Name name,
1474 _) {
1475 doIfNotNull(receiver, () {
1476 invokeGetter(node, name);
1477 });
1478 applyVisitState();
1479 }
1480
1481 void visitThisPropertyGet(
1482 Send node,
1483 Name name,
1484 _) {
1485 loadThis();
1486 invokeGetter(node, name);
1487 applyVisitState();
1488 }
1489
1490 void visitThisPropertySet(
1491 Send node,
1492 Name name,
1493 Node rhs,
1494 _) {
1495 loadThis();
1496 visitForValue(rhs);
1497 invokeSetter(node, name);
1498 applyVisitState();
1499 }
1500
1501 void doStaticFieldGet(FieldElement field) {
1502 if (checkCompileError(field)) return;
1503 if (field.isConst) {
1504 int constId = allocateConstantFromNode(
1505 field.initializer,
1506 elements: field.resolvedAst.elements);
1507 assembler.loadConst(constId);
1508 } else {
1509 int index = compileLazyFieldInitializer(field);
1510 if (field.initializer != null) {
1511 assembler.loadStaticInit(index);
1512 } else {
1513 assembler.loadStatic(index);
1514 }
1515 }
1516 }
1517
1518 void handleStaticFieldGet(
1519 Send node,
1520 FieldElement field,
1521 _) {
1522 doStaticFieldGet(field);
1523 applyVisitState();
1524 }
1525
1526 void visitAssert(Assert node) {
1527 // TODO(ajohnsen): Emit assert in checked mode.
1528 }
1529
1530 void visitDynamicPropertySet(
1531 Send node,
1532 Node receiver,
1533 Name name,
1534 Node rhs,
1535 _) {
1536 visitForValue(receiver);
1537 visitForValue(rhs);
1538 invokeSetter(node, name);
1539 applyVisitState();
1540 }
1541
1542 void visitIfNotNullDynamicPropertySet(
1543 SendSet node,
1544 Node receiver,
1545 Name name,
1546 Node rhs,
1547 _) {
1548 doIfNotNull(receiver, () {
1549 visitForValue(rhs);
1550 invokeSetter(node, name);
1551 });
1552 applyVisitState();
1553 }
1554
1555 void doStaticFieldSet(
1556 FieldElement field) {
1557 int index = context.getStaticFieldIndex(field, element);
1558 assembler.storeStatic(index);
1559 }
1560
1561 void handleStaticFieldSet(
1562 SendSet node,
1563 FieldElement field,
1564 Node rhs,
1565 _) {
1566 visitForValue(rhs);
1567 doStaticFieldSet(field);
1568 applyVisitState();
1569 }
1570
1571 void visitStringJuxtaposition(StringJuxtaposition node) {
1572 // TODO(ajohnsen): This could probably be optimized to string constants in
1573 // some cases.
1574 visitForValue(node.first);
1575 visitForValue(node.second);
1576 // TODO(ajohnsen): Cache these in context/backend.
1577 Selector concat = new Selector.binaryOperator('+');
1578 invokeMethod(node, concat);
1579 applyVisitState();
1580 }
1581
1582 void visitStringInterpolation(StringInterpolation node) {
1583 // TODO(ajohnsen): Cache this in context/backend.
1584 Selector concat = new Selector.binaryOperator('+');
1585 visitForValueNoDebugInfo(node.string);
1586 for (StringInterpolationPart part in node.parts) {
1587 visitForValue(part.expression);
1588 invokeMethod(part.expression, Selectors.toString_);
1589 LiteralString string = part.string;
1590 if (string.dartString.isNotEmpty) {
1591 visitForValueNoDebugInfo(string);
1592 invokeMethod(null, concat);
1593 }
1594 invokeMethod(null, concat);
1595 }
1596 applyVisitState();
1597 }
1598
1599 void visitLiteralNull(LiteralNull node) {
1600 if (visitState == VisitState.Value) {
1601 assembler.loadLiteralNull();
1602 } else if (visitState == VisitState.Test) {
1603 if (falseLabel != null) assembler.branch(falseLabel);
1604 }
1605 }
1606
1607 void visitLiteralSymbol(LiteralSymbol node) {
1608 int constId = allocateConstantFromNode(node);
1609 assembler.loadConst(constId);
1610 applyVisitState();
1611 }
1612
1613 void visitLiteralBool(LiteralBool node) {
1614 var expression = compileConstant(node, isConst: false);
1615 bool isTrue = expression != null &&
1616 context.getConstantValue(expression).isTrue;
1617
1618 if (visitState == VisitState.Value) {
1619 if (isTrue) {
1620 assembler.loadLiteralTrue();
1621 } else {
1622 assembler.loadLiteralFalse();
1623 }
1624 } else if (visitState == VisitState.Test) {
1625 if (isTrue) {
1626 if (trueLabel != null) assembler.branch(trueLabel);
1627 } else {
1628 if (falseLabel != null) assembler.branch(falseLabel);
1629 }
1630 }
1631 }
1632
1633 void visitLiteralInt(LiteralInt node) {
1634 if (visitState == VisitState.Value) {
1635 int value = node.value;
1636 assert(value >= 0);
1637 if (value > LITERAL_INT_MAX) {
1638 if ((value < MIN_INT64 || value > MAX_INT64) && !context.enableBigint) {
1639 generateUnimplementedError(
1640 node,
1641 'Program compiled without support for big integers');
1642 } else {
1643 int constId = allocateConstantFromNode(node);
1644 assembler.loadConst(constId);
1645 }
1646 } else {
1647 assembler.loadLiteral(value);
1648 }
1649 } else if (visitState == VisitState.Test) {
1650 if (falseLabel != null) assembler.branch(falseLabel);
1651 }
1652 }
1653
1654 void visitLiteral(Literal node) {
1655 if (visitState == VisitState.Value) {
1656 assembler.loadConst(allocateConstantFromNode(node));
1657 } else if (visitState == VisitState.Test) {
1658 if (falseLabel != null) assembler.branch(falseLabel);
1659 }
1660 }
1661
1662 void visitLiteralList(LiteralList node) {
1663 if (node.isConst) {
1664 int constId = allocateConstantFromNode(node);
1665 assembler.loadConst(constId);
1666 applyVisitState();
1667 return;
1668 }
1669 ClassElement literalClass = context.backend.growableListClass;
1670 ConstructorElement constructor = literalClass.lookupDefaultConstructor();
1671 if (constructor == null) {
1672 internalError(node, "Failed to lookup default list constructor");
1673 }
1674 // Call with empty arguments, as we call the default constructor.
1675 callConstructor(
1676 node, constructor, new NodeList.empty(), CallStructure.NO_ARGS);
1677 Selector add = new Selector.call(new Name('add', null),
1678 CallStructure.ONE_ARG);
1679 for (Node element in node.elements) {
1680 assembler.dup();
1681 visitForValue(element);
1682 invokeMethod(node, add);
1683 assembler.pop();
1684 }
1685 applyVisitState();
1686 }
1687
1688 void visitLiteralMap(LiteralMap node) {
1689 if (node.isConst) {
1690 int constId = allocateConstantFromNode(node);
1691 assembler.loadConst(constId);
1692 applyVisitState();
1693 return;
1694 }
1695 ClassElement literalClass =
1696 context.backend.mapImplementation.implementation;
1697 ConstructorElement constructor = literalClass.lookupConstructor("");
1698 if (constructor == null) {
1699 internalError(literalClass, "Failed to lookup default map constructor");
1700 return;
1701 }
1702 // The default constructor is a redirecting factory constructor. Follow it.
1703 constructor = constructor.effectiveTarget;
1704 FletchFunctionBase function = requireFunction(constructor.declaration);
1705 doStaticFunctionInvoke(
1706 node,
1707 function,
1708 new NodeList.empty(),
1709 CallStructure.NO_ARGS,
1710 factoryInvoke: true);
1711
1712 Selector selector = new Selector.indexSet();
1713 for (Node element in node.entries) {
1714 assembler.dup();
1715 visitForValue(element);
1716 invokeMethod(node, selector);
1717 assembler.pop();
1718 }
1719 applyVisitState();
1720 }
1721
1722 void visitLiteralMapEntry(LiteralMapEntry node) {
1723 assert(visitState == VisitState.Value);
1724 visitForValue(node.key);
1725 visitForValue(node.value);
1726 }
1727
1728 void visitLiteralString(LiteralString node) {
1729 if (visitState == VisitState.Value) {
1730 assembler.loadConst(allocateConstantFromNode(node));
1731 registerInstantiatedClass(
1732 context.compiler.backend.stringImplementation);
1733 } else if (visitState == VisitState.Test) {
1734 if (falseLabel != null) assembler.branch(falseLabel);
1735 }
1736 }
1737
1738 void visitCascadeReceiver(CascadeReceiver node) {
1739 visitForValue(node.expression);
1740 assembler.dup();
1741 assert(visitState == VisitState.Value);
1742 }
1743
1744 void visitCascade(Cascade node) {
1745 visitForEffect(node.expression);
1746 applyVisitState();
1747 }
1748
1749 void visitParenthesizedExpression(ParenthesizedExpression node) {
1750 // Visit expression in the same VisitState.
1751 node.expression.accept(this);
1752 }
1753
1754 void visitLocalFunctionGet(Send node, LocalFunctionElement function, _) {
1755 registerClosurization(function, ClosureKind.localFunction);
1756 handleLocalGet(node, function, _);
1757 }
1758
1759 void handleLocalGet(
1760 Send node,
1761 LocalElement element,
1762 _) {
1763 scope[element].load(assembler);
1764 applyVisitState();
1765 }
1766
1767 void handleLocalSet(
1768 SendSet node,
1769 LocalElement element,
1770 Node rhs,
1771 _) {
1772 visitForValue(rhs);
1773 scope[element].store(assembler);
1774 applyVisitState();
1775 }
1776
1777 void visitLocalFunctionInvoke(
1778 Send node,
1779 LocalFunctionElement function,
1780 NodeList arguments,
1781 CallStructure callStructure,
1782 _) {
1783 // TODO(ahe): We could use loadPositionalArguments if [element] is a local
1784 // function to avoid generating additional stubs and to avoid registering
1785 // this as a dynamic call.
1786 registerLocalInvoke(function, callStructure.callSelector);
1787 handleLocalInvoke(node, function, arguments, callStructure, _);
1788 }
1789
1790 void handleLocalInvoke(
1791 Node node,
1792 LocalElement element,
1793 NodeList arguments,
1794 CallStructure callStructure,
1795 _) {
1796 scope[element].load(assembler);
1797 for (Node argument in arguments) {
1798 visitForValue(argument);
1799 }
1800 invokeMethod(node, callStructure.callSelector);
1801 applyVisitState();
1802 }
1803
1804 static Selector getIncDecSelector(IncDecOperator operator) {
1805 String name = operator == IncDecOperator.INC ? '+' : '-';
1806 return new Selector.binaryOperator(name);
1807 }
1808
1809 static Selector getAssignmentSelector(AssignmentOperator operator) {
1810 String name = operator.binaryOperator.name;
1811 return new Selector.binaryOperator(name);
1812 }
1813
1814 void doLocalVariableIncrement(
1815 Node node,
1816 LocalVariableElement element,
1817 IncDecOperator operator,
1818 bool prefix) {
1819 // TODO(ajohnsen): Candidate for bytecode: Inc/Dec local with non-Smi
1820 // bailout.
1821 LocalValue value = scope[element];
1822 value.load(assembler);
1823 // For postfix, keep local, unmodified version, to 'return' after store.
1824 if (!prefix) assembler.dup();
1825 assembler.loadLiteral(1);
1826 invokeMethod(node, getIncDecSelector(operator));
1827 value.store(assembler);
1828 if (!prefix) assembler.pop();
1829 }
1830
1831 void visitLocalVariablePrefix(
1832 SendSet node,
1833 LocalVariableElement element,
1834 IncDecOperator operator,
1835 _) {
1836 doLocalVariableIncrement(node, element, operator, true);
1837 applyVisitState();
1838 }
1839
1840 void visitParameterPrefix(
1841 Send node,
1842 LocalParameterElement parameter,
1843 IncDecOperator operator,
1844 _) {
1845 doLocalVariableIncrement(node, parameter, operator, true);
1846 applyVisitState();
1847 }
1848
1849 void visitLocalVariablePostfix(
1850 SendSet node,
1851 LocalVariableElement element,
1852 IncDecOperator operator,
1853 _) {
1854 // If visitState is for effect, we can ignore the return value, thus always
1855 // generate code for the simpler 'prefix' case.
1856 bool prefix = (visitState == VisitState.Effect);
1857 doLocalVariableIncrement(node, element, operator, prefix);
1858 applyVisitState();
1859 }
1860
1861 void visitParameterPostfix(
1862 SendSet node,
1863 LocalParameterElement parameter,
1864 IncDecOperator operator,
1865 _) {
1866 // If visitState is for effect, we can ignore the return value, thus always
1867 // generate code for the simpler 'prefix' case.
1868 bool prefix = (visitState == VisitState.Effect);
1869 doLocalVariableIncrement(node, parameter, operator, prefix);
1870 applyVisitState();
1871 }
1872
1873 void doStaticFieldPrefix(
1874 Node node,
1875 FieldElement field,
1876 IncDecOperator operator) {
1877 doStaticFieldGet(field);
1878 assembler.loadLiteral(1);
1879 invokeMethod(node, getIncDecSelector(operator));
1880 doStaticFieldSet(field);
1881 }
1882
1883 void doStaticFieldPostfix(
1884 Node node,
1885 FieldElement field,
1886 IncDecOperator operator) {
1887 doStaticFieldGet(field);
1888 // For postfix, keep local, unmodified version, to 'return' after store.
1889 assembler.dup();
1890 assembler.loadLiteral(1);
1891 invokeMethod(node, getIncDecSelector(operator));
1892 doStaticFieldSet(field);
1893 assembler.pop();
1894 }
1895
1896 void visitStaticFieldPostfix(
1897 Send node,
1898 FieldElement field,
1899 IncDecOperator operator,
1900 _) {
1901 if (visitState == VisitState.Effect) {
1902 doStaticFieldPrefix(node, field, operator);
1903 } else {
1904 doStaticFieldPostfix(node, field, operator);
1905 }
1906 applyVisitState();
1907 }
1908
1909 void visitStaticFieldPrefix(
1910 Send node,
1911 FieldElement field,
1912 IncDecOperator operator,
1913 _) {
1914 doStaticFieldPrefix(node, field, operator);
1915 applyVisitState();
1916 }
1917
1918 void visitTopLevelFieldPostfix(
1919 Send node,
1920 FieldElement field,
1921 IncDecOperator operator,
1922 _) {
1923 if (visitState == VisitState.Effect) {
1924 doStaticFieldPrefix(node, field, operator);
1925 } else {
1926 doStaticFieldPostfix(node, field, operator);
1927 }
1928 applyVisitState();
1929 }
1930
1931 void visitTopLevelFieldPrefix(
1932 Send node,
1933 FieldElement field,
1934 IncDecOperator operator,
1935 _) {
1936 doStaticFieldPrefix(node, field, operator);
1937 applyVisitState();
1938 }
1939
1940 void doDynamicPropertyCompound(
1941 Node node,
1942 Name name,
1943 AssignmentOperator operator,
1944 Node rhs) {
1945 // Dup receiver for setter.
1946 assembler.dup();
1947 invokeGetter(node, name);
1948 visitForValue(rhs);
1949 invokeMethod(node, getAssignmentSelector(operator));
1950 invokeSetter(node, name);
1951 }
1952
1953 void visitDynamicPropertyCompound(
1954 Send node,
1955 Node receiver,
1956 Name name,
1957 AssignmentOperator operator,
1958 Node rhs,
1959 _) {
1960 visitForValue(receiver);
1961 doDynamicPropertyCompound(
1962 node,
1963 name,
1964 operator,
1965 rhs);
1966 applyVisitState();
1967 }
1968
1969 void visitIfNotNullDynamicPropertyCompound(
1970 Send node,
1971 Node receiver,
1972 Name name,
1973 AssignmentOperator operator,
1974 Node rhs,
1975 _) {
1976 doIfNotNull(receiver, () {
1977 doDynamicPropertyCompound(
1978 node,
1979 name,
1980 operator,
1981 rhs);
1982 });
1983 applyVisitState();
1984 }
1985
1986 void visitThisPropertyCompound(
1987 Send node,
1988 Name name,
1989 AssignmentOperator operator,
1990 Node rhs,
1991 _) {
1992 loadThis();
1993 doDynamicPropertyCompound(
1994 node,
1995 name,
1996 operator,
1997 rhs);
1998 applyVisitState();
1999 }
2000
2001 void doDynamicPrefix(
2002 Node node,
2003 Name name,
2004 IncDecOperator operator) {
2005 assembler.dup();
2006 invokeGetter(node, name);
2007 assembler.loadLiteral(1);
2008 invokeMethod(node, getIncDecSelector(operator));
2009 invokeSetter(node, name);
2010 }
2011
2012 void doIndexPrefix(
2013 SendSet node,
2014 Node receiver,
2015 Node index,
2016 IncDecOperator operator) {
2017 visitForValue(receiver);
2018 visitForValue(index);
2019 // Load already evaluated receiver and index for '[]' call.
2020 assembler.loadLocal(1);
2021 assembler.loadLocal(1);
2022 invokeMethod(node, new Selector.index());
2023 assembler.loadLiteral(1);
2024 invokeMethod(node, getIncDecSelector(operator));
2025 // Use existing evaluated receiver and index for '[]=' call.
2026 invokeMethod(node, new Selector.indexSet());
2027 }
2028
2029 void visitIndexPrefix(
2030 SendSet node,
2031 Node receiver,
2032 Node index,
2033 IncDecOperator operator,
2034 _) {
2035 doIndexPrefix(node, receiver, index, operator);
2036 applyVisitState();
2037 }
2038
2039 void visitIndexPostfix(
2040 Send node,
2041 Node receiver,
2042 Node index,
2043 IncDecOperator operator,
2044 _) {
2045 if (visitState == VisitState.Effect) {
2046 doIndexPrefix(node, receiver, index, operator);
2047 applyVisitState();
2048 return;
2049 }
2050
2051 // Reserve slot for result.
2052 assembler.loadLiteralNull();
2053 visitForValue(receiver);
2054 visitForValue(index);
2055 // Load already evaluated receiver and index for '[]' call.
2056 assembler.loadLocal(1);
2057 assembler.loadLocal(1);
2058 invokeMethod(node, new Selector.index());
2059 assembler.storeLocal(3);
2060 assembler.loadLiteral(1);
2061 invokeMethod(node, getIncDecSelector(operator));
2062 // Use existing evaluated receiver and index for '[]=' call.
2063 invokeMethod(node, new Selector.indexSet());
2064 assembler.pop();
2065 applyVisitState();
2066 }
2067
2068 void visitCompoundIndexSet(
2069 Send node,
2070 Node receiver,
2071 Node index,
2072 AssignmentOperator operator,
2073 Node rhs,
2074 _) {
2075 visitForValue(receiver);
2076 visitForValue(index);
2077 // Load already evaluated receiver and index for '[]' call.
2078 assembler.loadLocal(1);
2079 assembler.loadLocal(1);
2080 invokeMethod(node, new Selector.index());
2081 visitForValue(rhs);
2082 invokeMethod(node, getAssignmentSelector(operator));
2083 // Use existing evaluated receiver and index for '[]=' call.
2084 invokeMethod(node, new Selector.indexSet());
2085 applyVisitState();
2086 }
2087
2088 void visitThisPropertyPrefix(
2089 Send node,
2090 Name name,
2091 IncDecOperator operator,
2092 _) {
2093 loadThis();
2094 doDynamicPrefix(node, name, operator);
2095 applyVisitState();
2096 }
2097
2098 void visitThisPropertyPostfix(
2099 Send node,
2100 Name name,
2101 IncDecOperator operator,
2102 _) {
2103 // If visitState is for effect, we can ignore the return value, thus always
2104 // generate code for the simpler 'prefix' case.
2105 if (visitState == VisitState.Effect) {
2106 loadThis();
2107 doDynamicPrefix(node, name, operator);
2108 applyVisitState();
2109 return;
2110 }
2111
2112 loadThis();
2113 invokeGetter(node, name);
2114 // For postfix, keep local, unmodified version, to 'return' after store.
2115 assembler.dup();
2116 assembler.loadLiteral(1);
2117 invokeMethod(node, getIncDecSelector(operator));
2118 loadThis();
2119 assembler.loadLocal(1);
2120 invokeSetter(node, name);
2121 assembler.popMany(2);
2122 applyVisitState();
2123 }
2124
2125 void visitDynamicPropertyPrefix(
2126 Send node,
2127 Node receiver,
2128 Name name,
2129 IncDecOperator operator,
2130 _) {
2131 visitForValue(receiver);
2132 doDynamicPrefix(node, name, operator);
2133 applyVisitState();
2134 }
2135
2136 void visitIfNotNullDynamicPropertyPrefix(
2137 Send node,
2138 Node receiver,
2139 Name name,
2140 IncDecOperator operator,
2141 _) {
2142 doIfNotNull(receiver, () {
2143 doDynamicPrefix(node, name, operator);
2144 });
2145 applyVisitState();
2146 }
2147
2148 void doDynamicPostfix(
2149 Send node,
2150 Node receiver,
2151 Name name,
2152 IncDecOperator operator) {
2153 int receiverSlot = assembler.stackSize - 1;
2154 assembler.loadSlot(receiverSlot);
2155 invokeGetter(node, name);
2156 // For postfix, keep local, unmodified version, to 'return' after store.
2157 assembler.dup();
2158 assembler.loadLiteral(1);
2159 invokeMethod(node, getIncDecSelector(operator));
2160 assembler.loadSlot(receiverSlot);
2161 assembler.loadLocal(1);
2162 invokeSetter(node, name);
2163 assembler.popMany(2);
2164 assembler.storeLocal(1);
2165 // Pop receiver.
2166 assembler.pop();
2167 }
2168
2169 void visitDynamicPropertyPostfix(
2170 Send node,
2171 Node receiver,
2172 Name name,
2173 IncDecOperator operator,
2174 _) {
2175 // If visitState is for effect, we can ignore the return value, thus always
2176 // generate code for the simpler 'prefix' case.
2177 if (visitState == VisitState.Effect) {
2178 visitForValue(receiver);
2179 doDynamicPrefix(node, name, operator);
2180 applyVisitState();
2181 return;
2182 }
2183
2184 visitForValue(receiver);
2185 doDynamicPostfix(node, receiver, name, operator);
2186 applyVisitState();
2187 }
2188
2189 void visitIfNotNullDynamicPropertyPostfix(
2190 Send node,
2191 Node receiver,
2192 Name name,
2193 IncDecOperator operator,
2194 _) {
2195 doIfNotNull(receiver, () {
2196 doDynamicPostfix(
2197 node, receiver, name, operator);
2198 });
2199 applyVisitState();
2200 }
2201
2202 void visitThrow(Throw node) {
2203 visitForValue(node.expression);
2204 generateThrow(node);
2205 // TODO(ahe): It seems suboptimal that each throw is followed by a pop.
2206 applyVisitState();
2207 }
2208
2209 void visitRethrow(Rethrow node) {
2210 if (tryBlockStack.isEmpty) {
2211 doCompileError(context.compiler.reporter.createMessage(
2212 node, MessageKind.GENERIC, {"text": "Rethrow outside try"}));
2213 } else {
2214 TryBlock block = tryBlockStack.head;
2215 assembler.loadSlot(block.stackSize - 1);
2216 // TODO(ahe): It seems suboptimal that each throw is followed by a pop.
2217 generateThrow(node);
2218 }
2219 assembler.pop();
2220 }
2221
2222 void callConstructor(Node node,
2223 ConstructorElement constructor,
2224 NodeList arguments,
2225 CallStructure callStructure) {
2226 FletchFunctionBase function = requireConstructorInitializer(constructor);
2227 doStaticFunctionInvoke(node, function, arguments, callStructure);
2228 }
2229
2230 void doConstConstructorInvoke(ConstantExpression constant) {
2231 var value = context.getConstantValue(constant);
2232 context.markConstantUsed(value);
2233 int constId = functionBuilder.allocateConstant(value);
2234 assembler.loadConst(constId);
2235 }
2236
2237 void visitConstConstructorInvoke(
2238 NewExpression node,
2239 ConstructedConstantExpression constant,
2240 _) {
2241 // TODO(johnniwinther): We should not end up here with an bad constructor.
2242 if (!checkCompileError(elements[node.send])) {
2243 doConstConstructorInvoke(constant);
2244 }
2245 applyVisitState();
2246 }
2247
2248 void visitBoolFromEnvironmentConstructorInvoke(
2249 NewExpression node,
2250 BoolFromEnvironmentConstantExpression constant,
2251 _) {
2252 doConstConstructorInvoke(constant);
2253 applyVisitState();
2254 }
2255
2256 void visitIntFromEnvironmentConstructorInvoke(
2257 NewExpression node,
2258 IntFromEnvironmentConstantExpression constant,
2259 _) {
2260 doConstConstructorInvoke(constant);
2261 applyVisitState();
2262 }
2263
2264 void visitStringFromEnvironmentConstructorInvoke(
2265 NewExpression node,
2266 StringFromEnvironmentConstantExpression constant,
2267 _) {
2268 doConstConstructorInvoke(constant);
2269 applyVisitState();
2270 }
2271
2272 void visitGenerativeConstructorInvoke(
2273 NewExpression node,
2274 ConstructorElement constructor,
2275 InterfaceType type,
2276 NodeList arguments,
2277 CallStructure callStructure,
2278 _) {
2279 if (!checkCompileError(constructor)) {
2280 callConstructor(node, constructor.declaration, arguments, callStructure);
2281 }
2282 applyVisitState();
2283 }
2284
2285 void visitFactoryConstructorInvoke(
2286 NewExpression node,
2287 ConstructorElement constructor,
2288 InterfaceType type,
2289 NodeList arguments,
2290 CallStructure callStructure,
2291 _) {
2292 // If the constructor has an implementation, the implementation is the
2293 // factory we want to invoke. Redirect to
2294 // visitRedirectingFactoryConstructorInvoke, so we handle both cases of
2295 // either a factory or a redirecting factory.
2296 if (constructor.implementation != constructor) {
2297 ConstructorElement implementation = constructor.implementation;
2298 visitRedirectingFactoryConstructorInvoke(
2299 node,
2300 constructor,
2301 type,
2302 implementation.effectiveTarget,
2303 null,
2304 arguments,
2305 callStructure,
2306 null);
2307 return;
2308 }
2309 // TODO(ahe): Remove ".declaration" when issue 23135 is fixed.
2310 FletchFunctionBase function = requireFunction(constructor.declaration);
2311 doStaticFunctionInvoke(
2312 node, function, arguments, callStructure, factoryInvoke: true);
2313 applyVisitState();
2314 }
2315
2316 void visitConstructorIncompatibleInvoke(
2317 NewExpression node,
2318 ConstructorElement constructor,
2319 InterfaceType type,
2320 NodeList arguments,
2321 CallStructure callStructure,
2322 _) {
2323 if (!checkCompileError(constructor)) {
2324 doUnresolved(constructor.name);
2325 }
2326 applyVisitState();
2327 }
2328
2329 void visitRedirectingGenerativeConstructorInvoke(
2330 NewExpression node,
2331 ConstructorElement constructor,
2332 InterfaceType type,
2333 NodeList arguments,
2334 CallStructure callStructure,
2335 _) {
2336 visitGenerativeConstructorInvoke(
2337 node,
2338 constructor,
2339 type,
2340 arguments,
2341 callStructure,
2342 null);
2343 }
2344
2345 void visitRedirectingFactoryConstructorInvoke(
2346 NewExpression node,
2347 ConstructorElement constructor,
2348 InterfaceType type,
2349 ConstructorElement effectiveTarget,
2350 InterfaceType effectiveTargetType,
2351 NodeList arguments,
2352 CallStructure callStructure,
2353 _) {
2354 if (effectiveTarget.isGenerativeConstructor) {
2355 visitGenerativeConstructorInvoke(
2356 node,
2357 effectiveTarget,
2358 effectiveTargetType,
2359 arguments,
2360 callStructure,
2361 null);
2362 } else {
2363 visitFactoryConstructorInvoke(
2364 node,
2365 effectiveTarget,
2366 effectiveTargetType,
2367 arguments,
2368 callStructure,
2369 null);
2370 }
2371 }
2372
2373 void visitUnresolvedConstructorInvoke(
2374 NewExpression node,
2375 Element constructor,
2376 DartType type,
2377 NodeList arguments,
2378 Selector selector,
2379 _) {
2380 if (!checkCompileError(constructor.enclosingClass)) {
2381 doUnresolved(node.send.toString());
2382 }
2383 applyVisitState();
2384 }
2385
2386 void visitUnresolvedClassConstructorInvoke(
2387 NewExpression node,
2388 Element element,
2389 DartType type,
2390 NodeList arguments,
2391 Selector selector,
2392 _) {
2393 doUnresolved(node.send.toString());
2394 applyVisitState();
2395 }
2396
2397 void visitAbstractClassConstructorInvoke(
2398 NewExpression node,
2399 ConstructorElement element,
2400 InterfaceType type,
2401 NodeList arguments,
2402 CallStructure callStructure,
2403 _) {
2404 generateUnimplementedError(node, "Cannot allocate abstract class");
2405 applyVisitState();
2406 }
2407
2408 void visitUnresolvedRedirectingFactoryConstructorInvoke(
2409 NewExpression node,
2410 ConstructorElement constructor,
2411 InterfaceType type,
2412 NodeList arguments,
2413 CallStructure callStructure,
2414 _) {
2415 doUnresolved(node.send.toString());
2416 applyVisitState();
2417 }
2418
2419 void doStaticGetterGet(Send node, FunctionElement getter) {
2420 if (getter == context.backend.fletchExternalNativeError) {
2421 assembler.loadSlot(0);
2422 return;
2423 }
2424
2425 if (getter.isDeferredLoaderGetter) {
2426 generateUnimplementedError(node, "Deferred loading is not supported.");
2427 return;
2428 }
2429
2430 FletchFunctionBase base = requireFunction(getter);
2431 int constId = functionBuilder.allocateConstantFromFunction(base.functionId);
2432 invokeStatic(node, constId, 0);
2433 }
2434
2435 void handleStaticGetterGet(Send node, FunctionElement getter, _) {
2436 doStaticGetterGet(node, getter);
2437 applyVisitState();
2438 }
2439
2440 void handleStaticGetterInvoke(
2441 Send node,
2442 FunctionElement getter,
2443 NodeList arguments,
2444 CallStructure callStructure,
2445 _) {
2446 doStaticGetterGet(node, getter);
2447 for (Node argument in arguments) {
2448 visitForValue(argument);
2449 }
2450 invokeMethod(node, callStructure.callSelector);
2451 applyVisitState();
2452 }
2453
2454 void handleStaticSetterSet(
2455 Send node,
2456 FunctionElement setter,
2457 Node rhs,
2458 _) {
2459 visitForValue(rhs);
2460 FletchFunctionBase base = requireFunction(setter);
2461 int constId = functionBuilder.allocateConstantFromFunction(base.functionId);
2462 invokeStatic(node, constId, 1);
2463 applyVisitState();
2464 }
2465
2466 /**
2467 * Load the captured variables of [function], expressed in [info].
2468 *
2469 * If [function] captures itself, its field index is returned.
2470 */
2471 int pushCapturedVariables(FunctionElement function) {
2472 ClosureInfo info = closureEnvironment.closures[function];
2473 if (info == null) {
2474 // TODO(ahe): Do not throw here, instead fix bug in incremental compiler
2475 // (see test closure_capture).
2476 throw new IncrementalCompilationFailed(
2477 "Internal error: no closure info for $function");
2478 }
2479 int index = 0;
2480 if (info.isThisFree) {
2481 loadThis();
2482 index++;
2483 }
2484 int thisClosureIndex = -1;
2485 for (LocalElement element in info.free) {
2486 if (element == function) {
2487 // If we capture ourself, remember index and assign into closure after
2488 // allocation.
2489 assembler.loadLiteralNull();
2490 assert(thisClosureIndex == -1);
2491 thisClosureIndex = index;
2492 } else {
2493 // Load the raw value (the 'Box' when by reference).
2494 scope[element].loadRaw(assembler);
2495 }
2496 index++;
2497 }
2498 return thisClosureIndex;
2499 }
2500
2501 void visitFunctionExpression(FunctionExpression node) {
2502 FunctionElement function = elements[node];
2503
2504 // If the closure captures itself, thisClosureIndex is the field-index in
2505 // the closure.
2506 int thisClosureIndex = pushCapturedVariables(function);
2507 bool needToStoreThisReference = thisClosureIndex >= 0;
2508
2509 FletchClassBuilder classBuilder = context.backend.createClosureClass(
2510 function,
2511 closureEnvironment);
2512 int classConstant = functionBuilder.allocateConstantFromClass(
2513 classBuilder.classId);
2514
2515 // NOTE: Currently we emit a storeField instruction in case a closure
2516 // captures itself. Changing fields makes it a mutable object.
2517 // We can therefore not allocate the object with `immutable = true`.
2518 // TODO(fletchc-team): Could we restrict this limitation.
2519 bool immutable = !closureEnvironment.closures[function].free.any(
2520 closureEnvironment.shouldBeBoxed) && !needToStoreThisReference;
2521
2522 assembler.allocate(
2523 classConstant, classBuilder.fields, immutable: immutable);
2524
2525 if (needToStoreThisReference) {
2526 assert(!immutable);
2527 assembler.dup();
2528 assembler.storeField(thisClosureIndex);
2529 }
2530
2531 if (!functionDeclarations.contains(node)) {
2532 registerClosurization(function, ClosureKind.localFunction);
2533 }
2534 applyVisitState();
2535 }
2536
2537 void visitExpression(Expression node) {
2538 generateUnimplementedError(
2539 node, "Missing visit of expression: ${node.runtimeType}");
2540 applyVisitState();
2541 }
2542
2543 void visitStatement(Node node) {
2544 generateUnimplementedError(
2545 node, "Missing visit of statement: ${node.runtimeType}");
2546 assembler.pop();
2547 }
2548
2549 void doStatements(NodeList statements) {
2550 List<Element> oldBlockLocals = blockLocals;
2551 blockLocals = <Element>[];
2552 int stackSize = assembler.stackSize;
2553
2554 for (Node statement in statements) {
2555 statement.accept(this);
2556 }
2557
2558 int stackSizeDifference = assembler.stackSize - stackSize;
2559 if (stackSizeDifference != blockLocals.length) {
2560 internalError(
2561 statements,
2562 "Unbalanced number of block locals and stack slots used by block.");
2563 }
2564
2565 if (blockLocals.length > 0) assembler.popMany(blockLocals.length);
2566
2567 for (int i = blockLocals.length - 1; i >= 0; --i) {
2568 popVariableDeclaration(blockLocals[i]);
2569 }
2570
2571 blockLocals = oldBlockLocals;
2572 }
2573
2574 void visitBlock(Block node) {
2575 var breakLabel = new BytecodeLabel();
2576 jumpInfo[node] = new JumpInfo(assembler.stackSize, null, breakLabel);
2577 doStatements(node.statements);
2578 assembler.bind(breakLabel);
2579 }
2580
2581 void visitEmptyStatement(EmptyStatement node) {
2582 }
2583
2584 void visitExpressionStatement(ExpressionStatement node) {
2585 visitForEffect(node.expression);
2586 }
2587
2588 // Called before 'return', as an option to replace the already evaluated
2589 // return value. One example is setters.
2590 bool get hasAssignmentSemantics => false;
2591 void optionalReplaceResultValue() { }
2592
2593 void visitReturn(Return node) {
2594 Expression expression = node.expression;
2595 bool returnNull = true;
2596 if (expression != null && !isConstNull(expression)) {
2597 visitForValue(expression);
2598 returnNull = false;
2599 }
2600
2601 // Avoid using the return-null bytecode if we have assignment semantics.
2602 if (returnNull && hasAssignmentSemantics) {
2603 assembler.loadLiteralNull();
2604 returnNull = false;
2605 }
2606
2607 if (returnNull) {
2608 callFinallyBlocks(0, false);
2609 generateReturnNull(node);
2610 } else {
2611 callFinallyBlocks(0, true);
2612 optionalReplaceResultValue();
2613 generateReturn(node);
2614 }
2615 }
2616
2617 // Find the JumpInfo matching the target of [node].
2618 JumpInfo getJumpTargetInfo(GotoStatement node) {
2619 JumpTarget target = elements.getTargetOf(node);
2620 if (target == null) {
2621 generateUnimplementedError(node, "'$node' not in loop");
2622 assembler.pop();
2623 return null;
2624 }
2625 Node statement = target.statement;
2626 JumpInfo info = jumpInfo[statement];
2627 if (info == null) {
2628 generateUnimplementedError(node, "'$node' has no target");
2629 assembler.pop();
2630 }
2631 return info;
2632 }
2633
2634 void callFinallyBlocks(int targetStackSize, bool preserveTop) {
2635 int popCount = 0;
2636 for (var block in tryBlockStack) {
2637 // Break once all exited finally blocks are processed. Finally blocks
2638 // are ordered by stack size which coincides with scoping. Blocks with
2639 // stack sizes at least equal to target size are being exited.
2640 if (block.stackSize < targetStackSize) break;
2641 if (block.finallyLabel == null) continue;
2642 if (preserveTop) {
2643 // We reuse the exception slot as a temporary buffer for the top
2644 // element, which is located -1 relative to the block's stack size.
2645 assembler.storeSlot(block.stackSize - 1);
2646 }
2647 // TODO(ajohnsen): Don't pop, but let subroutineCall take a 'pop count'
2648 // argument, just like popAndBranch.
2649 if (assembler.stackSize > block.stackSize) {
2650 int sizeDifference = assembler.stackSize - block.stackSize;
2651 popCount += sizeDifference;
2652 assembler.popMany(sizeDifference);
2653 }
2654 assembler.subroutineCall(block.finallyLabel, block.finallyReturnLabel);
2655 if (preserveTop) {
2656 assembler.loadSlot(block.stackSize - 1);
2657 popCount--;
2658 }
2659 }
2660 // Reallign stack (should be removed, according to above TODO).
2661 for (int i = 0; i < popCount; i++) {
2662 // Note we dup, to make sure the top element is the return value.
2663 assembler.dup();
2664 }
2665 }
2666
2667 void unbalancedBranch(GotoStatement node, bool isBreak) {
2668 JumpInfo info = getJumpTargetInfo(node);
2669 if (info == null) return;
2670 callFinallyBlocks(info.stackSize, false);
2671 BytecodeLabel label = isBreak ? info.breakLabel : info.continueLabel;
2672 int diff = assembler.stackSize - info.stackSize;
2673 assembler.popAndBranch(diff, label);
2674 }
2675
2676 void visitBreakStatement(BreakStatement node) {
2677 var breakLabel = new BytecodeLabel();
2678 jumpInfo[node] = new JumpInfo(assembler.stackSize, null, breakLabel);
2679 unbalancedBranch(node, true);
2680 assembler.bind(breakLabel);
2681 }
2682
2683 void visitContinueStatement(ContinueStatement node) {
2684 unbalancedBranch(node, false);
2685 }
2686
2687 void visitIf(If node) {
2688 ConstantExpression conditionConstant =
2689 inspectConstant(node.condition, isConst: false);
2690
2691 if (conditionConstant != null) {
2692 BytecodeLabel end = new BytecodeLabel();
2693 jumpInfo[node] = new JumpInfo(assembler.stackSize, null, end);
2694 if (context.getConstantValue(conditionConstant).isTrue) {
2695 doScopedStatement(node.thenPart);
2696 } else if (node.hasElsePart) {
2697 doScopedStatement(node.elsePart);
2698 }
2699 assembler.bind(end);
2700 return;
2701 }
2702
2703 BytecodeLabel ifFalse = new BytecodeLabel();
2704
2705 visitForTest(node.condition, null, ifFalse);
2706 if (node.hasElsePart) {
2707 BytecodeLabel end = new BytecodeLabel();
2708 jumpInfo[node] = new JumpInfo(assembler.stackSize, null, end);
2709 doScopedStatement(node.thenPart);
2710 assembler.branch(end);
2711 assembler.bind(ifFalse);
2712 doScopedStatement(node.elsePart);
2713 assembler.bind(end);
2714 } else {
2715 jumpInfo[node] = new JumpInfo(assembler.stackSize, null, ifFalse);
2716 doScopedStatement(node.thenPart);
2717 assembler.bind(ifFalse);
2718 }
2719 }
2720
2721 void visitFor(For node) {
2722 List<Element> oldBlockLocals = blockLocals;
2723 blockLocals = <Element>[];
2724
2725 BytecodeLabel start = new BytecodeLabel();
2726 BytecodeLabel end = new BytecodeLabel();
2727 BytecodeLabel afterBody = new BytecodeLabel();
2728
2729 Node initializer = node.initializer;
2730 if (initializer != null) visitForEffect(initializer);
2731
2732 jumpInfo[node] = new JumpInfo(assembler.stackSize, afterBody, end);
2733
2734 assembler.bind(start);
2735
2736 Expression condition = node.condition;
2737 if (condition != null) {
2738 visitForTest(condition, null, end);
2739 }
2740
2741 doScopedStatement(node.body);
2742
2743 assembler.bind(afterBody);
2744
2745 for (int i = blockLocals.length - 1; i >= 0; --i) {
2746 LocalElement local = blockLocals[i];
2747 // If the locals are captured by reference, load the current value and
2748 // store it in a new boxed.
2749 if (closureEnvironment.shouldBeBoxed(local)) {
2750 LocalValue value = scope[local];
2751 value.load(assembler);
2752 value.initialize(assembler);
2753 assembler.storeSlot(value.slot);
2754 assembler.pop();
2755 }
2756 }
2757
2758 for (Node update in node.update) {
2759 visitForEffect(update);
2760 }
2761 assembler.branch(start);
2762
2763 assembler.bind(end);
2764
2765 for (int i = blockLocals.length - 1; i >= 0; --i) {
2766 assembler.pop();
2767 popVariableDeclaration(blockLocals[i]);
2768 }
2769
2770 blockLocals = oldBlockLocals;
2771 }
2772
2773 void visitSyncForIn(SyncForIn node) {
2774 visitForIn(node);
2775 }
2776
2777 void visitForIn(ForIn node) {
2778 BytecodeLabel start = new BytecodeLabel();
2779 BytecodeLabel end = new BytecodeLabel();
2780
2781 // Evalutate expression and iterator.
2782 visitForValue(node.expression);
2783 invokeGetter(node.expression, Names.iterator);
2784
2785 jumpInfo[node] = new JumpInfo(assembler.stackSize, start, end);
2786
2787 assembler.bind(start);
2788
2789 assembler.dup();
2790 invokeMethod(node, Selectors.moveNext);
2791 assembler.branchIfFalse(end);
2792
2793 bool isVariableDeclaration = node.declaredIdentifier.asSend() == null;
2794 Element element = elements[node];
2795 if (isVariableDeclaration) {
2796 // Create local value and load the current element to it.
2797 LocalValue value = createLocalValueFor(element);
2798 assembler.dup();
2799 invokeGetter(node, Names.current);
2800 value.initialize(assembler);
2801 pushVariableDeclaration(value);
2802 } else {
2803 if (element == null || element.isInstanceMember) {
2804 loadThis();
2805 assembler.loadLocal(1);
2806 invokeGetter(node, Names.current);
2807 Selector selector = elements.getSelector(node.declaredIdentifier);
2808 invokeSetter(node, selector.memberName);
2809 } else {
2810 assembler.dup();
2811 invokeGetter(node, Names.current);
2812 if (element.isLocal) {
2813 scope[element].store(assembler);
2814 } else if (element.isField) {
2815 doStaticFieldSet(element);
2816 } else if (element.isMalformed) {
2817 doUnresolved(element.name);
2818 assembler.pop();
2819 } else {
2820 internalError(node, "Unhandled store in for-in");
2821 }
2822 }
2823 assembler.pop();
2824 }
2825
2826 doScopedStatement(node.body);
2827
2828 if (isVariableDeclaration) {
2829 // Pop the local again.
2830 assembler.pop();
2831 popVariableDeclaration(element);
2832 }
2833
2834 assembler.branch(start);
2835
2836 assembler.bind(end);
2837
2838 // Pop iterator.
2839 assembler.pop();
2840 }
2841
2842 void visitLabeledStatement(LabeledStatement node) {
2843 node.statement.accept(this);
2844 }
2845
2846 // Visit the statement in a scope, where locals are popped when left.
2847 void doScopedStatement(Node statement) {
2848 Block block = statement.asBlock();
2849 if (block != null) {
2850 doStatements(block.statements);
2851 } else {
2852 doStatements(new NodeList.singleton(statement));
2853 }
2854 }
2855
2856 void visitWhile(While node) {
2857 BytecodeLabel start = new BytecodeLabel();
2858 BytecodeLabel end = new BytecodeLabel();
2859 jumpInfo[node] = new JumpInfo(assembler.stackSize, start, end);
2860 assembler.bind(start);
2861 visitForTest(node.condition, null, end);
2862 doScopedStatement(node.body);
2863 assembler.branch(start);
2864 assembler.bind(end);
2865 }
2866
2867 void visitDoWhile(DoWhile node) {
2868 BytecodeLabel start = new BytecodeLabel();
2869 BytecodeLabel end = new BytecodeLabel();
2870 BytecodeLabel skipBody = new BytecodeLabel();
2871 jumpInfo[node] = new JumpInfo(assembler.stackSize, skipBody, end);
2872 assembler.bind(start);
2873 doScopedStatement(node.body);
2874 assembler.bind(skipBody);
2875 visitForTest(node.condition, start, null);
2876 assembler.bind(end);
2877 }
2878
2879 LocalValue initializeLocal(LocalElement element, Expression initializer) {
2880 int slot = assembler.stackSize;
2881 if (initializer != null) {
2882 // TODO(ahe): If we can move this to the caller, then we don't need
2883 // functionDeclarations.
2884 visitForValue(initializer);
2885 } else {
2886 generateEmptyInitializer(element.node);
2887 }
2888 LocalValue value = createLocalValueFor(element, slot: slot);
2889 value.initialize(assembler);
2890 pushVariableDeclaration(value);
2891 blockLocals.add(element);
2892 return value;
2893 }
2894
2895 void generateEmptyInitializer(Node node) {
2896 assembler.loadLiteralNull();
2897 }
2898
2899 void visitVariableDefinitions(VariableDefinitions node) {
2900 for (Node definition in node.definitions) {
2901 LocalVariableElement element = elements[definition];
2902 initializeLocal(element, element.initializer);
2903 }
2904 }
2905
2906 void visitFunctionDeclaration(FunctionDeclaration node) {
2907 FunctionExpression function = node.function;
2908 functionDeclarations.add(function);
2909 initializeLocal(elements[function], function);
2910 }
2911
2912 void visitSwitchStatement(SwitchStatement node) {
2913 BytecodeLabel end = new BytecodeLabel();
2914
2915 visitForValue(node.expression);
2916
2917 jumpInfo[node] = new JumpInfo(assembler.stackSize, null, end);
2918
2919 // Install cross-case jump targets.
2920 for (SwitchCase switchCase in node.cases) {
2921 BytecodeLabel continueLabel = new BytecodeLabel();
2922 jumpInfo[switchCase] = new JumpInfo(
2923 assembler.stackSize,
2924 continueLabel,
2925 null);
2926 }
2927
2928 for (SwitchCase switchCase in node.cases) {
2929 BytecodeLabel ifTrue = jumpInfo[switchCase].continueLabel;
2930 BytecodeLabel next = new BytecodeLabel();
2931 if (!switchCase.isDefaultCase) {
2932 for (Node labelOrCaseMatch in switchCase.labelsAndCases) {
2933 CaseMatch caseMatch = labelOrCaseMatch.asCaseMatch();
2934 if (caseMatch == null) continue;
2935 generateSwitchCaseMatch(caseMatch, ifTrue);
2936 }
2937 assembler.branch(next);
2938 }
2939 assembler.bind(ifTrue);
2940 doStatements(switchCase.statements);
2941 assembler.branch(end);
2942 assembler.bind(next);
2943 }
2944
2945 assembler.bind(end);
2946 assembler.pop();
2947 }
2948
2949 void doCatchBlock(CatchBlock node, int exceptionSlot, BytecodeLabel end) {
2950 BytecodeLabel wrongType = new BytecodeLabel();
2951
2952 TypeAnnotation type = node.type;
2953 if (type != null) {
2954 assembler.loadSlot(exceptionSlot);
2955 callIsSelector(type, elements.getType(type), type);
2956 assembler.branchIfFalse(wrongType);
2957 }
2958
2959 List<Element> locals = <Element>[];
2960 Node exception = node.exception;
2961 if (exception != null) {
2962 LocalVariableElement element = elements[exception];
2963 LocalValue value = createLocalValueFor(element);
2964 assembler.loadSlot(exceptionSlot);
2965 value.initialize(assembler);
2966 pushVariableDeclaration(value);
2967 locals.add(element);
2968
2969 Node trace = node.trace;
2970 if (trace != null) {
2971 LocalVariableElement element = elements[trace];
2972 LocalValue value = createLocalValueFor(element);
2973 assembler.loadLiteralNull();
2974 value.initialize(assembler);
2975 pushVariableDeclaration(value);
2976 // TODO(ajohnsen): Set trace.
2977 locals.add(element);
2978 }
2979 }
2980
2981 node.block.accept(this);
2982
2983 assembler.popMany(locals.length);
2984 for (Element e in locals) {
2985 popVariableDeclaration(e);
2986 }
2987
2988 assembler.branch(end);
2989
2990 assembler.bind(wrongType);
2991 }
2992
2993 void visitTryStatement(TryStatement node) {
2994 BytecodeLabel end = new BytecodeLabel();
2995 BytecodeLabel finallyLabel = new BytecodeLabel();
2996 BytecodeLabel finallyReturnLabel = new BytecodeLabel();
2997
2998 Block finallyBlock = node.finallyBlock;
2999 bool hasFinally = finallyBlock != null;
3000
3001 // Reserve slot for exception.
3002 int exceptionSlot = assembler.stackSize;
3003 assembler.loadLiteralNull();
3004
3005 jumpInfo[node] = new JumpInfo(assembler.stackSize, null, end);
3006
3007 int startBytecodeSize = assembler.byteSize;
3008
3009 tryBlockStack = tryBlockStack.prepend(
3010 new TryBlock(
3011 assembler.stackSize,
3012 hasFinally ? finallyLabel : null,
3013 hasFinally ? finallyReturnLabel: null));
3014
3015 node.tryBlock.accept(this);
3016
3017 // Go to end if no exceptions was thrown.
3018 assembler.branch(end);
3019 int endBytecodeSize = assembler.byteSize;
3020
3021 // Add catch-frame to the assembler.
3022 assembler.addCatchFrameRange(startBytecodeSize, endBytecodeSize);
3023
3024 for (Node catchBlock in node.catchBlocks) {
3025 doCatchBlock(catchBlock, exceptionSlot, end);
3026 }
3027
3028 tryBlockStack = tryBlockStack.tail;
3029
3030 if (hasFinally) {
3031 if (!node.catchBlocks.isEmpty) {
3032 assembler.addCatchFrameRange(endBytecodeSize, assembler.byteSize);
3033 }
3034 // Catch exception from catch blocks.
3035 assembler.subroutineCall(finallyLabel, finallyReturnLabel);
3036 }
3037
3038 // The exception was not caught. Rethrow.
3039 generateThrow(node);
3040
3041 assembler.bind(end);
3042
3043 if (hasFinally) {
3044 BytecodeLabel done = new BytecodeLabel();
3045 assembler.subroutineCall(finallyLabel, finallyReturnLabel);
3046 assembler.branch(done);
3047
3048 assembler.bind(finallyLabel);
3049 assembler.applyStackSizeFix(1);
3050 finallyBlock.accept(this);
3051 assembler.subroutineReturn(finallyReturnLabel);
3052
3053 assembler.bind(done);
3054 }
3055
3056 // Pop exception slot.
3057 assembler.pop();
3058 }
3059
3060 void doUnresolved(String name) {
3061 var constString = context.backend.constantSystem.createString(
3062 new DartString.literal(name));
3063 context.markConstantUsed(constString);
3064 assembler.loadConst(functionBuilder.allocateConstant(constString));
3065 FunctionElement function = context.backend.fletchUnresolved;
3066 FletchFunctionBase base = requireFunction(function);
3067 int constId = functionBuilder.allocateConstantFromFunction(base.functionId);
3068 assembler.invokeStatic(constId, 1);
3069 }
3070
3071 bool checkCompileError(Element element) {
3072 DiagnosticMessage message =
3073 context.compiler.elementsWithCompileTimeErrors[element];
3074 if (message != null) {
3075 doCompileError(message);
3076 return true;
3077 }
3078 return false;
3079 }
3080
3081 String formatError(DiagnosticMessage diagnosticMessage) {
3082 return diagnosticMessage.message.computeMessage();
3083 }
3084
3085
3086 void doCompileError(DiagnosticMessage errorMessage) {
3087 FunctionElement function = context.backend.fletchCompileError;
3088 FletchFunctionBase base = requireFunction(function);
3089 int constId = functionBuilder.allocateConstantFromFunction(base.functionId);
3090 String errorString = formatError(errorMessage);
3091 ConstantValue stringConstant =
3092 context.backend.constantSystem.createString(
3093 new DartString.literal(errorString));
3094 int messageConstId = functionBuilder.allocateConstant(stringConstant);
3095 context.markConstantUsed(stringConstant);
3096 assembler.loadConst(messageConstId);
3097 registerInstantiatedClass(context.backend.stringImplementation);
3098 assembler.invokeStatic(constId, 1);
3099 }
3100
3101 void visitUnresolvedInvoke(
3102 Send node,
3103 Element element,
3104 Node arguments,
3105 Selector selector,
3106 _) {
3107 if (!checkCompileError(element)) {
3108 doUnresolved(node.selector.toString());
3109 }
3110 applyVisitState();
3111 }
3112
3113 void visitUnresolvedGet(
3114 Send node,
3115 Element element,
3116 _) {
3117 doUnresolved(node.selector.toString());
3118 applyVisitState();
3119 }
3120
3121 void visitUnresolvedSet(
3122 Send node,
3123 Element element,
3124 Node rhs,
3125 _) {
3126 doUnresolved(node.selector.toString());
3127 applyVisitState();
3128 }
3129
3130 void handleStaticFunctionIncompatibleInvoke(
3131 Send node,
3132 MethodElement function,
3133 NodeList arguments,
3134 CallStructure callStructure,
3135 _) {
3136 if (!checkCompileError(function)) {
3137 doUnresolved(function.name);
3138 }
3139 applyVisitState();
3140 }
3141
3142 void internalError(Spannable spannable, String reason) {
3143 context.compiler.reporter.internalError(spannable, reason);
3144 }
3145
3146 void generateUnimplementedError(Spannable spannable, String reason) {
3147 context.backend.generateUnimplementedError(
3148 spannable,
3149 reason,
3150 functionBuilder);
3151 }
3152
3153 String toString() => "FunctionCompiler(${element.name})";
3154
3155 void handleFinalStaticFieldSet(
3156 SendSet node,
3157 FieldElement field,
3158 Node rhs,
3159 _) {
3160 generateUnimplementedError(
3161 node, "[handleFinalStaticFieldSet] isn't implemented.");
3162 applyVisitState();
3163 }
3164
3165 void handleImmutableLocalSet(
3166 SendSet node,
3167 LocalElement element,
3168 Node rhs,
3169 _) {
3170 generateUnimplementedError(
3171 node, "[handleImmutableLocalSet] isn't implemented.");
3172 applyVisitState();
3173 }
3174
3175 void handleStaticSetterGet(
3176 Send node,
3177 FunctionElement setter,
3178 _) {
3179 generateUnimplementedError(
3180 node, "[handleStaticSetterGet] isn't implemented.");
3181 applyVisitState();
3182 }
3183
3184 void handleStaticSetterInvoke(
3185 Send node,
3186 FunctionElement setter,
3187 NodeList arguments,
3188 CallStructure callStructure,
3189 _) {
3190 generateUnimplementedError(
3191 node, "[handleStaticSetterInvoke] isn't implemented.");
3192 applyVisitState();
3193 }
3194
3195 void handleStaticGetterSet(
3196 Send node,
3197 FunctionElement getter,
3198 Node rhs,
3199 _) {
3200 generateUnimplementedError(
3201 node, "[handleStaticGetterSet] isn't implemented.");
3202 applyVisitState();
3203 }
3204
3205 void handleStaticFunctionSet(
3206 SendSet node,
3207 MethodElement function,
3208 Node rhs,
3209 _) {
3210 generateUnimplementedError(
3211 node, "[handleStaticFunctionSet] isn't implemented.");
3212 applyVisitState();
3213 }
3214
3215 @override
3216 void bulkHandleSetIfNull(Node node, _) {
3217 generateUnimplementedError(
3218 node, "[bulkHandleSetIfNull] isn't implemented.");
3219 applyVisitState();
3220 }
3221
3222 void previsitDeferredAccess(Send node, PrefixElement prefix, _) {
3223 // We don't support deferred access, so nothing to do for now.
3224 }
3225
3226 void bulkHandleNode(Node node, String msg, _) {
3227 generateUnimplementedError(node, msg.replaceAll('#', node.toString()));
3228 applyVisitState();
3229 }
3230
3231 void visitNode(Node node) {
3232 internalError(node, "[visitNode] isn't implemented.");
3233 }
3234
3235 void apply(Node node, _) {
3236 internalError(node, "[apply] isn't implemented.");
3237 }
3238
3239 void applyInitializers(FunctionExpression initializers, _) {
3240 internalError(initializers, "[applyInitializers] isn't implemented.");
3241 }
3242
3243 void applyParameters(NodeList parameters, _) {
3244 internalError(parameters, "[applyParameters] isn't implemented.");
3245 }
3246 }
3247
3248 abstract class FletchRegistryMixin {
3249 FletchRegistry get registry;
3250 FletchContext get context;
3251
3252 void registerDynamicUse(Selector selector) {
3253 registry.registerDynamicUse(selector);
3254 }
3255
3256 void registerStaticUse(StaticUse staticUse) {
3257 registry.registerStaticUse(staticUse);
3258 }
3259
3260 void registerInstantiatedClass(ClassElement klass) {
3261 registry.registerInstantiatedClass(klass);
3262 }
3263
3264 void registerIsCheck(DartType type) {
3265 registry.registerIsCheck(type);
3266 }
3267
3268 void registerLocalInvoke(LocalElement element, Selector selector) {
3269 registry.registerLocalInvoke(element, selector);
3270 }
3271
3272 void registerClosurization(FunctionElement element, ClosureKind kind) {
3273 if (kind == ClosureKind.localFunction) {
3274 // TODO(ahe): Get rid of the call to [registerStaticUse]. It is
3275 // currently needed to ensure that local function expression closures are
3276 // compiled correctly. For example, `[() {}].last()`, notice that `last`
3277 // is a getter. This happens for both named and unnamed.
3278 registerStaticUse(new StaticUse.foreignUse(element));
3279 }
3280 registry.registerClosurization(element, kind);
3281 }
3282
3283 int compileLazyFieldInitializer(FieldElement field) {
3284 return context.backend.compileLazyFieldInitializer(field, registry);
3285 }
3286 }
OLDNEW
« no previous file with comments | « pkg/fletchc/lib/src/closure_environment.dart ('k') | pkg/fletchc/lib/src/console_print.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698