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

Unified 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, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/fletchc/lib/src/codegen_visitor.dart
diff --git a/pkg/fletchc/lib/src/codegen_visitor.dart b/pkg/fletchc/lib/src/codegen_visitor.dart
deleted file mode 100644
index cb450ac180cdf8aafbf7ad87ea9ba9994b344f29..0000000000000000000000000000000000000000
--- a/pkg/fletchc/lib/src/codegen_visitor.dart
+++ /dev/null
@@ -1,3286 +0,0 @@
-// Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE.md file.
-
-library fletchc.codegen_visitor;
-
-import 'package:compiler/src/resolution/semantic_visitor.dart';
-
-import 'package:compiler/src/resolution/operators.dart' show
- AssignmentOperator,
- BinaryOperator,
- IncDecOperator,
- UnaryOperator;
-
-import 'package:compiler/src/constants/expressions.dart' show
- BoolFromEnvironmentConstantExpression,
- IntFromEnvironmentConstantExpression,
- StringFromEnvironmentConstantExpression,
- ConstantExpression,
- ConstructedConstantExpression,
- TypeConstantExpression;
-
-import 'package:compiler/src/resolution/tree_elements.dart' show
- TreeElements;
-
-import 'package:compiler/src/util/util.dart' show
- Link;
-
-import 'package:compiler/src/common/names.dart' show
- Names,
- Selectors;
-
-import 'package:compiler/src/universe/use.dart' show DynamicUse, StaticUse;
-
-import 'package:compiler/src/elements/elements.dart';
-import 'package:compiler/src/tree/tree.dart';
-import 'package:compiler/src/universe/call_structure.dart' show
- CallStructure;
-import 'package:compiler/src/universe/selector.dart' show
- Selector;
-import 'package:compiler/src/diagnostics/spannable.dart' show
- Spannable;
-import 'package:compiler/src/dart_types.dart';
-
-import 'fletch_context.dart';
-
-import 'fletch_backend.dart';
-
-import 'fletch_constants.dart' show
- FletchClassConstant,
- FletchClassInstanceConstant;
-
-import 'fletch_function_builder.dart' show
- FletchFunctionBuilder;
-
-import 'fletch_class_builder.dart' show
- FletchClassBuilder;
-
-import 'fletch_selector.dart';
-
-import '../fletch_system.dart';
-
-import 'closure_environment.dart';
-
-import '../incremental/fletchc_incremental.dart' show
- IncrementalCompilationFailed; // TODO(ahe): Remove this import.
-
-import 'fletch_registry.dart' show
- ClosureKind,
- FletchRegistry;
-
-import 'package:compiler/src/diagnostics/diagnostic_listener.dart' show
- DiagnosticMessage;
-
-import 'package:compiler/src/diagnostics/messages.dart' show
- MessageKind;
-
-import 'package:compiler/src/constants/values.dart' show
- ConstantValue;
-
-enum VisitState {
- Value,
- Effect,
- Test,
-}
-
-/**
- * A reference to a local value, including how it should be used
- * (loaded/stored).
- */
-abstract class LocalValue {
- final int slot;
- final Element element;
- LocalValue(this.slot, this.element);
-
- void initialize(BytecodeAssembler assembler);
-
- void load(BytecodeAssembler assembler);
-
- void loadRaw(BytecodeAssembler assembler) {
- load(assembler);
- }
-
- void store(BytecodeAssembler assembler);
-}
-
-/**
- * A reference to a local value that is boxed.
- */
-class BoxedLocalValue extends LocalValue {
- BoxedLocalValue(int slot, Element element) : super(slot, element);
-
- void initialize(BytecodeAssembler assembler) {
- assembler.allocateBoxed();
- }
-
- void load(BytecodeAssembler assembler) {
- assembler.loadBoxedSlot(slot);
- }
-
- void loadRaw(BytecodeAssembler assembler) {
- assembler.loadSlot(slot);
- }
-
- void store(BytecodeAssembler assembler) {
- assembler.storeBoxedSlot(slot);
- }
-
- String toString() => "Boxed($element, $slot)";
-}
-
-/**
- * A reference to a local value that is boxed.
- */
-class UnboxedLocalValue extends LocalValue {
- UnboxedLocalValue(int slot, Element element) : super(slot, element);
-
- void initialize(BytecodeAssembler assembler) {}
-
- void load(BytecodeAssembler assembler) {
- assembler.loadSlot(slot);
- }
-
- void store(BytecodeAssembler assembler) {
- assembler.storeSlot(slot);
- }
-
- String toString() => "Local($element, $slot)";
-}
-
-/**
- * A reference to a local value that is boxed.
- */
-class BoxedParameterValue extends LocalValue {
- BoxedParameterValue(
- int parameter,
- Element element,
- BytecodeAssembler assembler)
- : super(assembler.computeParameterSlot(parameter), element);
-
- void initialize(BytecodeAssembler assembler) {
- assembler.allocateBoxed();
- }
-
- void load(BytecodeAssembler assembler) {
- assembler.loadBoxedParameterSlot(slot);
- }
-
- void loadRaw(BytecodeAssembler assembler) {
- assembler.loadParameterSlot(slot);
- }
-
- void store(BytecodeAssembler assembler) {
- assembler.storeBoxedParameterSlot(slot);
- }
-
- String toString() => "BoxedParameter($element, $slot)";
-}
-
-/**
- * A reference to a local value that is boxed.
- */
-class UnboxedParameterValue extends LocalValue {
- UnboxedParameterValue(
- int parameter,
- Element element,
- BytecodeAssembler assembler)
- : super(assembler.computeParameterSlot(parameter), element);
-
- void initialize(BytecodeAssembler assembler) {}
-
- void load(BytecodeAssembler assembler) {
- assembler.loadParameterSlot(slot);
- }
-
- void store(BytecodeAssembler assembler) {
- assembler.storeParameterSlot(slot);
- }
-
- String toString() => "Parameter($element, $slot)";
-}
-
-class JumpInfo {
- final int stackSize;
- final BytecodeLabel continueLabel;
- final BytecodeLabel breakLabel;
- JumpInfo(this.stackSize, this.continueLabel, this.breakLabel);
-}
-
-class TryBlock {
- final int stackSize;
- final BytecodeLabel finallyLabel;
- final BytecodeLabel finallyReturnLabel;
- TryBlock(this.stackSize, this.finallyLabel, this.finallyReturnLabel);
-}
-
-abstract class CodegenVisitor
- extends SemanticVisitor
- with GetBulkMixin,
- SetBulkMixin,
- ErrorBulkMixin,
- InvokeBulkMixin,
- IndexSetBulkMixin,
- CompoundBulkMixin,
- UnaryBulkMixin,
- BaseBulkMixin,
- BinaryBulkMixin,
- PrefixBulkMixin,
- PostfixBulkMixin,
- NewBulkMixin,
- VariableBulkMixin,
- ParameterBulkMixin,
- FunctionBulkMixin,
- ConstructorBulkMixin,
- InitializerBulkMixin,
- BaseImplementationOfStaticsMixin,
- BaseImplementationOfLocalsMixin,
- SetIfNullBulkMixin
- implements SemanticSendVisitor, SemanticDeclarationVisitor {
- // A literal int can have up to 31 bits of information (32 minus sign).
- static const int LITERAL_INT_MAX = 0x3FFFFFFF;
- static const int MAX_INT64 = (1 << 63) - 1;
- static const int MIN_INT64 = -(1 << 63);
-
- final FletchContext context;
-
- final ClosureEnvironment closureEnvironment;
-
- final ExecutableElement element;
-
- final FletchFunctionBuilder functionBuilder;
-
- final Map<Element, LocalValue> scope = <Element, LocalValue>{};
-
- final Map<Node, JumpInfo> jumpInfo = <Node, JumpInfo>{};
-
- // Stack of try blocks (inner-most first), in the lexical scope.
- Link<TryBlock> tryBlockStack = const Link<TryBlock>();
-
- VisitState visitState;
- BytecodeLabel trueLabel;
- BytecodeLabel falseLabel;
-
- // TODO(ajohnsen): Merge computation into constructor.
- // The slot at which 'this' is stored. In closures, this is overwritten.
- LocalValue thisValue;
-
- TreeElements initializerElements;
-
- List<Element> blockLocals = <Element>[];
-
- /// A FunctionExpression in this set is a named local function declaration.
- /// Many calls to such functions are statically bound. So if `f` is a named
- /// local function declaration, `f()` doesn't need to be registered as a
- /// dynamic send.
- // TODO(ahe): Get rid of this by refactoring initializeLocal. See TODO there.
- final Set<FunctionExpression> functionDeclarations =
- new Set<FunctionExpression>();
-
- CodegenVisitor(this.functionBuilder,
- this.context,
- TreeElements elements,
- this.closureEnvironment,
- this.element)
- : super(elements) {
- if (functionBuilder.isInstanceMember) {
- thisValue = new UnboxedParameterValue(0, null, assembler);
- }
- }
-
- TreeElements get elements {
- if (initializerElements != null) return initializerElements;
- return super.elements;
- }
-
- BytecodeAssembler get assembler => functionBuilder.assembler;
-
- SemanticSendVisitor get sendVisitor => this;
- SemanticDeclarationVisitor get declVisitor => this;
-
- void compile();
-
- ConstantExpression compileConstant(
- Node node,
- {TreeElements elements,
- bool isConst}) {
- if (elements == null) elements = this.elements;
- return context.compileConstant(node, elements, isConst: isConst);
- }
-
- ConstantExpression inspectConstant(
- Node node,
- {TreeElements elements,
- bool isConst}) {
- if (elements == null) elements = this.elements;
- return context.inspectConstant(node, elements, isConst: isConst);
- }
-
- bool isConstNull(Node node) {
- ConstantExpression expression = inspectConstant(node, isConst: false);
- if (expression == null) return false;
- return context.getConstantValue(expression).isNull;
- }
-
- int allocateConstantFromNode(Node node, {TreeElements elements}) {
- ConstantExpression expression = compileConstant(
- node,
- elements: elements,
- isConst: false);
- return functionBuilder.allocateConstant(
- context.getConstantValue(expression));
- }
-
- int allocateConstantClassInstance(int classId) {
- var constant = new FletchClassInstanceConstant(classId);
- context.markConstantUsed(constant);
- return functionBuilder.allocateConstant(constant);
- }
-
- int allocateStringConstant(String string) {
- return functionBuilder.allocateConstant(
- context.backend.constantSystem.createString(
- new DartString.literal(string)));
- }
-
- ClosureInfo get closureInfo => closureEnvironment.closures[element];
-
- LocalValue createLocalValueFor(
- LocalElement element,
- {int slot,
- bool isCapturedValueBoxed: true}) {
- if (slot == null) slot = assembler.stackSize;
- if (closureEnvironment.shouldBeBoxed(element)) {
- if (isCapturedValueBoxed) {
- return new BoxedLocalValue(slot, element);
- }
- LocalValue value = new BoxedLocalValue(assembler.stackSize, element);
- assembler.loadSlot(slot);
- value.initialize(assembler);
- return value;
- }
-
- return new UnboxedLocalValue(slot, element);
- }
-
- LocalValue createLocalValueForParameter(
- ParameterElement parameter,
- int index,
- {bool isCapturedValueBoxed: true}) {
- // TODO(kasperl): Use [ParameterElement.constant] instead when
- // [ConstantValue] can be computed on-the-fly from a [ConstantExpression].
- Expression initializer = parameter.initializer;
- if (initializer != null) {
- // If the parameter has an initializer expression, we ask the context
- // to compile it right away to make sure we enqueue all dependent
- // elements correctly before we start assembling the program.
- context.compileConstant(
- initializer,
- parameter.memberContext.resolvedAst.elements,
- isConst: true);
- }
-
- if (closureEnvironment.shouldBeBoxed(parameter)) {
- if (isCapturedValueBoxed) {
- return new BoxedParameterValue(index, parameter, assembler);
- }
- LocalValue value = new BoxedLocalValue(assembler.stackSize, parameter);
- assembler.loadParameter(index);
- value.initialize(assembler);
- return value;
- }
- return new UnboxedParameterValue(index, parameter, assembler);
- }
-
- void pushVariableDeclaration(LocalValue value) {
- scope[value.element] = value;
- }
-
- void popVariableDeclaration(Element local) {
- scope.remove(local);
- }
-
- void registerDynamicUse(Selector selector);
-
- void registerStaticUse(StaticUse use);
-
- void registerInstantiatedClass(ClassElement klass);
-
- void registerIsCheck(DartType type);
-
- void registerLocalInvoke(LocalElement element, Selector selector);
-
- /// Register that [element] is a closure. This can happen for a tear-off, or
- /// for local functions. See [ClosureKind] for more information about the
- /// various kinds of implicit or explicit closurizations that can occur.
- void registerClosurization(FunctionElement element, ClosureKind kind);
-
- int compileLazyFieldInitializer(FieldElement field);
-
- void invokeMethod(Node node, Selector selector) {
- registerDynamicUse(selector);
- String symbol = context.getSymbolFromSelector(selector);
- int id = context.getSymbolId(symbol);
- int arity = selector.argumentCount;
- int fletchSelector = FletchSelector.encodeMethod(id, arity);
- assembler.invokeMethod(fletchSelector, arity, selector.name);
- }
-
- void invokeGetter(Node node, Name name) {
- registerDynamicUse(new Selector.getter(name));
- String symbol = context.mangleName(name);
- int id = context.getSymbolId(symbol);
- int fletchSelector = FletchSelector.encodeGetter(id);
- assembler.invokeMethod(fletchSelector, 0);
- }
-
- void invokeSetter(Node node, Name name) {
- registerDynamicUse(new Selector.setter(name));
- String symbol = context.mangleName(name);
- int id = context.getSymbolId(symbol);
- int fletchSelector = FletchSelector.encodeSetter(id);
- assembler.invokeMethod(fletchSelector, 1);
- }
-
- void invokeFactory(Node node, int constId, int arity) {
- assembler.invokeFactory(constId, arity);
- }
-
- void invokeStatic(Node node, int constId, int arity) {
- assembler.invokeStatic(constId, arity);
- }
-
- void generateIdentical(Node node) {
- assembler.identical();
- }
-
- void generateIdenticalNonNumeric(Node node) {
- assembler.identicalNonNumeric();
- }
-
- void generateReturn(Node node) {
- assembler.ret();
- }
-
- void generateReturnNull(Node node) {
- assembler.returnNull();
- }
-
- void generateThrow(Node node) {
- assembler.emitThrow();
- }
-
- void generateSwitchCaseMatch(CaseMatch caseMatch, BytecodeLabel ifTrue) {
- assembler.dup();
- int constId = allocateConstantFromNode(caseMatch.expression);
- assembler.loadConst(constId);
- // For debugging, ignore the equality checks in connection
- // with case matches by not associating the calls with
- // any node.
- invokeMethod(null, new Selector.binaryOperator('=='));
- assembler.branchIfTrue(ifTrue);
- }
-
- FletchFunctionBase requireFunction(FunctionElement element) {
- // TODO(johnniwinther): More precise use.
- registerStaticUse(new StaticUse.foreignUse(element));
- return context.backend.getFunctionForElement(element);
- }
-
- FletchFunctionBase requireConstructorInitializer(
- ConstructorElement constructor) {
- assert(constructor.isGenerativeConstructor);
- registerInstantiatedClass(constructor.enclosingClass);
- registerStaticUse(new StaticUse.foreignUse(constructor));
- return context.backend.getConstructorInitializerFunction(constructor);
- }
-
- void doStaticFunctionInvoke(
- Node node,
- FletchFunctionBase function,
- NodeList arguments,
- CallStructure callStructure,
- {bool factoryInvoke: false}) {
- if (function.isInstanceMember) loadThis();
- FunctionSignature signature = function.signature;
- int functionId;
- int arity;
- if (signature.hasOptionalParameters &&
- signature.optionalParametersAreNamed) {
- if (FletchBackend.isExactParameterMatch(signature, callStructure)) {
- functionId = function.functionId;
- } else if (callStructure.signatureApplies(signature)) {
- // TODO(ajohnsen): Inline parameter stub?
- FletchFunctionBase stub = context.backend.createParameterStub(
- function,
- callStructure.callSelector);
- functionId = stub.functionId;
- } else {
- doUnresolved(function.name);
- return;
- }
- for (Node argument in arguments) {
- visitForValue(argument);
- }
- arity = callStructure.argumentCount;
- } else if (callStructure != null &&
- callStructure.namedArguments.isNotEmpty) {
- doUnresolved(function.name);
- return;
- } else {
- functionId = function.functionId;
- arity = loadPositionalArguments(arguments, signature, function.name);
- }
- if (function.isInstanceMember) arity++;
- int constId = functionBuilder.allocateConstantFromFunction(functionId);
- if (factoryInvoke) {
- invokeFactory(node, constId, arity);
- } else {
- invokeStatic(node, constId, arity);
- }
- }
-
- void loadThis() {
- thisValue.load(assembler);
- }
-
- /**
- * Load the [arguments] for caling [function], with potential positional
- * arguments.
- *
- * Return the number of arguments pushed onto the stack.
- */
- int loadPositionalArguments(
- NodeList arguments,
- FunctionSignature signature,
- String name) {
- int argumentCount = 0;
- Iterator<Node> it = arguments.iterator;
- signature.orderedForEachParameter((ParameterElement parameter) {
- if (it.moveNext()) {
- visitForValue(it.current);
- } else {
- if (parameter.isOptional) {
- doParameterInitializer(parameter);
- } else {
- doUnresolved(name);
- }
- }
- argumentCount++;
- });
- if (it.moveNext()) doUnresolved(name);
- return argumentCount;
- }
-
- void doParameterInitializer(ParameterElement parameter) {
- Expression initializer = parameter.initializer;
- if (initializer == null) {
- assembler.loadLiteralNull();
- } else {
- var previousElements = initializerElements;
- initializerElements = parameter.resolvedAst.elements;
- visitForValue(initializer);
- initializerElements = previousElements;
- }
- }
-
- void doVisitForValue(Node node) {
- VisitState oldState = visitState;
- visitState = VisitState.Value;
- node.accept(this);
- visitState = oldState;
- }
-
- // Visit the expression [node] and push the result on top of the stack.
- void visitForValue(Node node) {
- doVisitForValue(node);
- }
-
- // Visit the expression [node] and push the result on top of the stack.
- // This method bypasses debug information collection and using this
- // method will not generate breakpoints for the expression evaluation.
- // This is useful when dealing with internal details that the programmer
- // shouldn't care about such as the string concatenation aspects of
- // of string interpolation.
- void visitForValueNoDebugInfo(Node node) {
- doVisitForValue(node);
- }
-
- // Visit the expression [node] without pushing the result on top of the stack.
- void visitForEffect(Node node) {
- VisitState oldState = visitState;
- visitState = VisitState.Effect;
- node.accept(this);
- visitState = oldState;
- }
-
- // Visit the expression [node] with the result being a branch to either
- // [trueLabel] or [falseLabel].
- void visitForTest(
- Node node,
- BytecodeLabel trueLabel,
- BytecodeLabel falseLabel) {
- VisitState oldState = visitState;
- visitState = VisitState.Test;
- BytecodeLabel oldTrueLabel = this.trueLabel;
- this.trueLabel = trueLabel;
- BytecodeLabel oldFalseLabel = this.falseLabel;
- this.falseLabel = falseLabel;
-
- assert(trueLabel != null || falseLabel != null);
- node.accept(this);
-
- visitState = oldState;
- this.trueLabel = oldTrueLabel;
- this.falseLabel = oldFalseLabel;
- }
-
- void negateTest() {
- assert(visitState == VisitState.Test);
- BytecodeLabel temporary = trueLabel;
- trueLabel = falseLabel;
- falseLabel = temporary;
- }
-
- void applyVisitState() {
- if (visitState == VisitState.Effect) {
- assembler.pop();
- } else if (visitState == VisitState.Test) {
- if (trueLabel == null) {
- assembler.branchIfFalse(falseLabel);
- } else if (falseLabel == null) {
- assembler.branchIfTrue(trueLabel);
- } else {
- assembler.branchIfTrue(trueLabel);
- assembler.branch(falseLabel);
- }
- }
- }
-
- void visitNamedArgument(NamedArgument node) {
- Expression expression = node.expression;
- if (expression != null) {
- visitForValue(expression);
- } else {
- assembler.loadLiteralNull();
- }
- applyVisitState();
- }
-
- void doLocalVariableCompound(
- Node node,
- LocalVariableElement variable,
- AssignmentOperator operator,
- Node rhs) {
- LocalValue value = scope[variable];
- value.load(assembler);
- visitForValue(rhs);
- String operatorName = operator.binaryOperator.name;
- invokeMethod(node, new Selector.binaryOperator(operatorName));
- value.store(assembler);
- }
-
- void visitLocalVariableCompound(
- Send node,
- LocalVariableElement variable,
- AssignmentOperator operator,
- Node rhs,
- _) {
- doLocalVariableCompound(node, variable, operator, rhs);
- applyVisitState();
- }
-
- void visitParameterCompound(
- Send node,
- LocalParameterElement parameter,
- AssignmentOperator operator,
- Node rhs,
- _) {
- doLocalVariableCompound(node, parameter, operator, rhs);
- applyVisitState();
- }
-
- void doStaticFieldCompound(
- Node node,
- FieldElement field,
- AssignmentOperator operator,
- Node rhs) {
- doStaticFieldGet(field);
- visitForValue(rhs);
- Selector selector = new Selector.binaryOperator(
- operator.binaryOperator.name);
- invokeMethod(node, selector);
- doStaticFieldSet(field);
- }
-
- void visitTopLevelFieldCompound(
- Send node,
- FieldElement field,
- AssignmentOperator operator,
- Node rhs,
- _) {
- doStaticFieldCompound(node, field, operator, rhs);
- applyVisitState();
- }
-
- void visitStaticFieldCompound(
- Send node,
- FieldElement field,
- AssignmentOperator operator,
- Node rhs,
- _) {
- doStaticFieldCompound(node, field, operator, rhs);
- applyVisitState();
- }
-
- void doBinaryOperator(
- Node node,
- Node left,
- Node right,
- BinaryOperator operator) {
- visitForValue(left);
- visitForValue(right);
- // For '==', if either side is a null literal, use identicalNonNumeric.
- if (operator == BinaryOperator.EQ &&
- (isConstNull(left) || isConstNull(right))) {
- generateIdenticalNonNumeric(node);
- return;
- }
-
- Selector selector = new Selector.binaryOperator(operator.name);
- invokeMethod(node, selector);
- }
-
- void visitEquals(
- Send node,
- Node left,
- Node right,
- _) {
- // TODO(ajohnsen): Inject null check (in callee).
- doBinaryOperator(node, left, right, BinaryOperator.EQ);
- applyVisitState();
- }
-
- void visitNotEquals(
- Send node,
- Node left,
- Node right,
- _) {
- doBinaryOperator(node, left, right, BinaryOperator.EQ);
- if (visitState == VisitState.Test) {
- negateTest();
- } else {
- assembler.negate();
- }
- applyVisitState();
- }
-
- void visitBinary(
- Send node,
- Node left,
- BinaryOperator operator,
- Node right,
- _) {
- doBinaryOperator(node, left, right, operator);
- applyVisitState();
- }
-
- void visitUnary(
- Send node,
- UnaryOperator operator,
- Node value,
- _) {
- visitForValue(value);
- Selector selector = new Selector.unaryOperator(operator.name);
- invokeMethod(node, selector);
- applyVisitState();
- }
-
- void visitNot(
- Send node,
- Node value,
- _) {
- if (visitState == VisitState.Test) {
- visitForTest(value, falseLabel, trueLabel);
- } else {
- visitForValue(value);
- assembler.negate();
- applyVisitState();
- }
- }
-
- void visitIndex(
- Send node,
- Node receiver,
- Node index,
- _) {
- visitForValue(receiver);
- visitForValue(index);
- Selector selector = new Selector.index();
- invokeMethod(node, selector);
- applyVisitState();
- }
-
- void visitIndexSet(
- SendSet node,
- Node receiver,
- Node index,
- Node value,
- _) {
- visitForValue(receiver);
- visitForValue(index);
- visitForValue(value);
- Selector selector = new Selector.indexSet();
- invokeMethod(node, selector);
- applyVisitState();
- }
-
- void visitLogicalAnd(
- Send node,
- Node left,
- Node right,
- _) {
- if (visitState == VisitState.Test) {
- if (falseLabel == null) {
- BytecodeLabel ifFalse = new BytecodeLabel();
- visitForTest(left, null, ifFalse);
- visitForTest(right, trueLabel, null);
- assembler.bind(ifFalse);
- } else {
- visitForTest(left, null, falseLabel);
- visitForTest(right, trueLabel, falseLabel);
- }
- return;
- }
-
- BytecodeLabel isFalse = new BytecodeLabel();
- assembler.loadLiteralFalse();
-
- visitForTest(left, null, isFalse);
- visitForTest(right, null, isFalse);
- assembler.pop();
- assembler.loadLiteralTrue();
-
- assembler.bind(isFalse);
- applyVisitState();
- }
-
- void visitLogicalOr(
- Send node,
- Node left,
- Node right,
- _) {
- if (visitState == VisitState.Test) {
- if (trueLabel == null) {
- BytecodeLabel ifTrue = new BytecodeLabel();
- visitForTest(left, ifTrue, null);
- visitForTest(right, null, falseLabel);
- assembler.bind(ifTrue);
- } else {
- visitForTest(left, trueLabel, null);
- visitForTest(right, trueLabel, falseLabel);
- }
- return;
- }
-
- BytecodeLabel isTrue = new BytecodeLabel();
- assembler.loadLiteralTrue();
-
- visitForTest(left, isTrue, null);
- visitForTest(right, isTrue, null);
- assembler.pop();
- assembler.loadLiteralFalse();
-
- assembler.bind(isTrue);
- applyVisitState();
- }
-
- void visitConditional(Conditional node) {
- BytecodeLabel isFalse = new BytecodeLabel();
- BytecodeLabel done = new BytecodeLabel();
-
- assembler.loadLiteralNull();
-
- visitForTest(node.condition, null, isFalse);
-
- assembler.pop();
- visitForValue(node.thenExpression);
- assembler.branch(done);
-
- assembler.bind(isFalse);
- assembler.pop();
- visitForValue(node.elseExpression);
-
- assembler.bind(done);
-
- applyVisitState();
- }
-
- void callIsSelector(
- Node node,
- DartType type,
- // TODO(ahe): Remove [diagnosticLocation] when malformed types are
- // handled.
- Spannable diagnosticLocation) {
- if (type == null || type.isMalformed) {
- assembler.pop();
- generateUnimplementedError(
- diagnosticLocation, "Unhandled type test for malformed $type.");
- return;
- }
-
- registerIsCheck(type);
-
- if (type.isDynamic) {
- assembler.pop();
- assembler.loadLiteralTrue();
- return;
- }
-
- if (type.isTypedef) {
- // TODO(ajohnsen): This only matches with the number of arguments, not
- // the actual argument types.
- TypedefType typedefType = type;
- int arity = typedefType.element.functionSignature.parameterCount;
- int fletchSelector = context.toFletchIsSelector(
- context.backend.compiler.coreClasses.functionClass, arity);
- assembler.invokeTest(fletchSelector, 0);
- return;
- }
-
- if (!type.isInterfaceType) {
- assembler.pop();
- generateUnimplementedError(
- diagnosticLocation, "Unhandled type test for $type.");
- return;
- }
-
- Element element = type.element;
- int fletchSelector = context.toFletchIsSelector(element);
- assembler.invokeTest(fletchSelector, 0);
- }
-
- void doIs(
- Node node,
- Node expression,
- DartType type,
- // TODO(ahe): Remove [diagnosticLocation] when callIsSelector does not
- // require it.
- Spannable diagnosticLocation) {
- visitForValue(expression);
- callIsSelector(node, type, diagnosticLocation);
- }
-
- void visitIs(
- Send node,
- Node expression,
- DartType type,
- _) {
- doIs(node, expression, type, node.arguments.first);
- applyVisitState();
- }
-
- void visitIsNot(
- Send node,
- Node expression,
- DartType type,
- _) {
- doIs(node, expression, type, node.arguments.first);
- if (visitState == VisitState.Test) {
- negateTest();
- } else {
- assembler.negate();
- }
- applyVisitState();
- }
-
- void visitAs(
- Send node,
- Node expression,
- DartType type,
- _) {
- // TODO(ajohnsen): To actual type check.
- visitForValue(expression);
- applyVisitState();
- }
-
- void visitThisGet(
- Node node,
- _) {
- loadThis();
- applyVisitState();
- }
-
- void doIdenticalCall(Node node, NodeList arguments) {
- assert(arguments.slowLength() == 2);
- for (Node argument in arguments) {
- visitForValue(argument);
- }
- generateIdentical(node);
- }
-
- void handleStaticFunctionGet(
- Send node,
- MethodElement function,
- _) {
- registerClosurization(function, ClosureKind.tearOff);
- FletchFunctionBase target = requireFunction(function);
- FletchClassBuilder classBuilder =
- context.backend.createTearoffClass(target);
- assert(classBuilder.fields == 0);
- int constId = allocateConstantClassInstance(classBuilder.classId);
- assembler.loadConst(constId);
- applyVisitState();
- }
-
- void doMainCall(Send node, NodeList arguments) {
- FunctionElement function = context.compiler.mainFunction;
- if (function.isMalformed) {
- DiagnosticMessage message =
- context.compiler.elementsWithCompileTimeErrors[function];
- if (message == null) {
- // TODO(johnniwinther): The error should always be associated with the
- // element.
- // Example triggering this:
- // ```
- // [
- // main() {}
- // ```
- message = context.compiler.reporter.createMessage(
- function, MessageKind.GENERIC, {'text': 'main is malformed.'});
- }
- doCompileError(message);
- return;
- }
- if (context.compiler.libraryLoader.libraries.any(checkCompileError)) return;
-
- // Load up to 'parameterCount' arguments, padding with nulls.
- int parameterCount = function.functionSignature.parameterCount;
- int argumentCount = 0;
- for (Node argument in arguments) {
- if (argumentCount == parameterCount) break;
- visitForValue(argument);
- argumentCount++;
- }
- for (int i = argumentCount; i < parameterCount; i++) {
- assembler.loadLiteralNull();
- }
-
- FletchFunctionBase base = requireFunction(function);
- int constId = functionBuilder.allocateConstantFromFunction(base.functionId);
- invokeStatic(node, constId, parameterCount);
- }
-
- void doStaticallyBoundInvoke(
- Send node,
- MethodElement element,
- NodeList arguments,
- CallStructure callStructure) {
- if (checkCompileError(element)) return;
- if (element.declaration == context.compiler.identicalFunction) {
- doIdenticalCall(node, arguments);
- return;
- }
- if (element.isExternal) {
- // Patch known functions directly.
- if (element == context.backend.fletchExternalInvokeMain) {
- doMainCall(node, arguments);
- return;
- } else if (element == context.backend.fletchExternalCoroutineChange) {
- for (Node argument in arguments) {
- visitForValue(argument);
- }
- assembler.coroutineChange();
- return;
- }
- // TODO(ajohnsen): Define a known set of external functions we allow
- // calls to?
- }
- FletchFunctionBase target = requireFunction(element);
- doStaticFunctionInvoke(node, target, arguments, callStructure);
- }
-
- void handleStaticFunctionInvoke(
- Send node,
- MethodElement element,
- NodeList arguments,
- CallStructure callStructure,
- _) {
- doStaticallyBoundInvoke(
- node, element.declaration, arguments, callStructure);
- applyVisitState();
- }
-
- void visitSuperMethodInvoke(
- Send node,
- MethodElement element,
- NodeList arguments,
- CallStructure callStructure,
- _) {
- doStaticallyBoundInvoke(node, element, arguments, callStructure);
- applyVisitState();
- }
-
- void doSuperCall(Node node, FunctionElement function) {
- registerStaticUse(new StaticUse.foreignUse(function));
- int arity = function.functionSignature.parameterCount + 1;
- FletchFunctionBase base = requireFunction(function);
- int constId = functionBuilder.allocateConstantFromFunction(base.functionId);
- invokeStatic(node, constId, arity);
- }
-
- void visitSuperGetterGet(
- Send node,
- FunctionElement getter,
- _) {
- loadThis();
- doSuperCall(node, getter);
- applyVisitState();
- }
-
- void visitSuperMethodGet(
- Send node,
- MethodElement method,
- _) {
- registerClosurization(method, ClosureKind.superTearOff);
- loadThis();
- FletchFunctionBase target = requireFunction(method);
- FletchClassBuilder classBuilder =
- context.backend.createTearoffClass(target);
- assert(classBuilder.fields == 1);
- int constId = functionBuilder.allocateConstantFromClass(
- classBuilder.classId);
- assembler.allocate(constId, classBuilder.fields);
- applyVisitState();
- }
-
- void visitSuperSetterSet(
- SendSet node,
- FunctionElement setter,
- Node rhs,
- _) {
- loadThis();
- visitForValue(rhs);
- doSuperCall(node, setter);
- applyVisitState();
- }
-
- void visitSuperIndex(
- Send node,
- FunctionElement function,
- Node index,
- _) {
- loadThis();
- visitForValue(index);
- doSuperCall(node, function);
- applyVisitState();
- }
-
- void visitSuperIndexSet(
- Send node,
- FunctionElement function,
- Node index,
- Node rhs,
- _) {
- loadThis();
- visitForValue(index);
- visitForValue(rhs);
- doSuperCall(node, function);
- applyVisitState();
- }
-
- void visitSuperCompoundIndexSet(
- Send node,
- FunctionElement getter,
- FunctionElement setter,
- Node index,
- AssignmentOperator operator,
- Node rhs,
- _) {
- visitForValue(index);
- loadThis();
- assembler.loadLocal(1);
- doSuperCall(node, getter);
- loadThis();
- // Load index
- assembler.loadLocal(2);
- // Load value from index call and call operator.
- assembler.loadLocal(2);
- visitForValue(rhs);
- invokeMethod(node, getAssignmentSelector(operator));
- doSuperCall(node, setter);
- // Override 'index' with result value, and pop everything else.
- assembler.storeLocal(2);
- assembler.popMany(2);
- applyVisitState();
- }
-
- void visitSuperIndexPostfix(
- SendSet node,
- FunctionElement getter,
- FunctionElement setter,
- Node index,
- IncDecOperator operator,
- _) {
- // TODO(ajohnsen): Fast-case when for effect.
- visitForValue(index);
- loadThis();
- assembler.loadLocal(1);
- doSuperCall(node, getter);
- loadThis();
- // Load index
- assembler.loadLocal(2);
- // Load value from index call and inc/dec.
- assembler.loadLocal(2);
- assembler.loadLiteral(1);
- invokeMethod(node, getIncDecSelector(operator));
- // We can now call []= with 'this', 'index' and 'value'.
- doSuperCall(node, setter);
- assembler.pop();
- // Pop result, override 'index' with initial indexed value, and pop again.
- assembler.storeLocal(1);
- assembler.pop();
- applyVisitState();
- }
-
- void visitSuperBinary(
- Send node,
- FunctionElement function,
- BinaryOperator operator,
- Node argument,
- _) {
- loadThis();
- visitForValue(argument);
- doSuperCall(node, function);
- applyVisitState();
- }
-
- void visitSuperEquals(
- Send node,
- FunctionElement function,
- Node argument,
- _) {
- loadThis();
- visitForValue(argument);
- doSuperCall(node, function);
- applyVisitState();
- }
-
- void visitSuperUnary(
- Send node,
- UnaryOperator operator,
- FunctionElement function,
- _) {
- loadThis();
- doSuperCall(node, function);
- applyVisitState();
- }
-
- int computeFieldIndex(FieldElement field) {
- ClassElement classElement = element.enclosingClass;
- int fieldIndex;
- FletchClassBuilder classBuilder;
- do {
- // We need to find the mixin application of the class, where the field
- // is stored. Iterate until it's found.
- classBuilder = context.backend.registerClassElement(classElement);
- classElement = classElement.implementation;
- int i = 0;
- classElement.forEachInstanceField((_, FieldElement member) {
- if (member == field) {
- assert(fieldIndex == null);
- fieldIndex = i;
- }
- i++;
- });
- classElement = classElement.superclass;
- } while (fieldIndex == null);
- fieldIndex += classBuilder.superclassFields;
- return fieldIndex;
- }
-
- void visitSuperFieldGet(
- Send node,
- FieldElement field,
- _) {
- loadThis();
- assembler.loadField(computeFieldIndex(field));
- applyVisitState();
- }
-
- void visitSuperFieldSet(
- SendSet node,
- FieldElement field,
- Node rhs,
- _) {
- loadThis();
- visitForValue(rhs);
- assembler.storeField(computeFieldIndex(field));
- applyVisitState();
- }
-
- void handleStaticFieldInvoke(
- Node node,
- FieldElement field,
- NodeList arguments,
- CallStructure callStructure,
- _) {
- doStaticFieldGet(field);
- for (Node argument in arguments) {
- visitForValue(argument);
- }
- invokeMethod(node, callStructure.callSelector);
- applyVisitState();
- }
-
- void visitDynamicPropertyInvoke(
- Send node,
- Node receiver,
- NodeList arguments,
- Selector selector,
- _) {
- visitForValue(receiver);
- for (Node argument in arguments) {
- visitForValue(argument);
- }
- invokeMethod(node, selector);
- applyVisitState();
- }
-
- void visitIfNull(
- Send node,
- Node left,
- Node right,
- _) {
- BytecodeLabel end = new BytecodeLabel();
- visitForValue(left);
- assembler.dup();
- assembler.loadLiteralNull();
- assembler.identicalNonNumeric();
- assembler.branchIfFalse(end);
- assembler.pop();
- visitForValue(right);
- assembler.bind(end);
- applyVisitState();
- }
-
- void doIfNotNull(Node receiver, void ifNotNull()) {
- BytecodeLabel end = new BytecodeLabel();
- visitForValue(receiver);
- assembler.dup();
- assembler.loadLiteralNull();
- assembler.identicalNonNumeric();
- assembler.branchIfTrue(end);
- ifNotNull();
- assembler.bind(end);
- }
-
- void visitIfNotNullDynamicPropertyInvoke(
- Send node,
- Node receiver,
- NodeList arguments,
- Selector selector,
- _) {
- doIfNotNull(receiver, () {
- for (Node argument in arguments) {
- visitForValue(argument);
- }
- invokeMethod(node, selector);
- });
- applyVisitState();
- }
-
- void visitExpressionInvoke(
- Send node,
- Expression receiver,
- NodeList arguments,
- CallStructure callStructure,
- _) {
- visitForValue(receiver);
- for (Node argument in arguments) {
- visitForValue(argument);
- }
- invokeMethod(node, new Selector.call(Names.call, callStructure));
- applyVisitState();
- }
-
- void visitThisPropertyInvoke(
- Send node,
- NodeList arguments,
- Selector selector,
- _) {
- loadThis();
-
- // If the property is statically known to be a field, instead invoke the
- // getter and then invoke 'call(...)' on the value.
- // TODO(ajohnsen): This is a fix that only works when the field is
- // statically known - that is not always the case. Implement VM support?
- Element target = elements[node];
- if (target != null && target.isField) {
- invokeGetter(node, new Name(target.name, element.library));
- selector = new Selector.callClosureFrom(selector);
- }
- for (Node argument in arguments) {
- visitForValue(argument);
- }
- invokeMethod(node, selector);
- applyVisitState();
- }
-
- void visitThisInvoke(
- Send node,
- NodeList arguments,
- CallStructure callStructure,
- _) {
- loadThis();
- for (Node argument in arguments) {
- visitForValue(argument);
- }
- invokeMethod(node, callStructure.callSelector);
- applyVisitState();
- }
-
- void visitClassTypeLiteralGet(
- Send node,
- ConstantExpression constant,
- _) {
- generateUnimplementedError(
- node, "[visitClassTypeLiteralGet] isn't implemented.");
- applyVisitState();
- }
-
- void visitDynamicPropertyGet(
- Send node,
- Node receiver,
- Name name,
- _) {
- if (name.text == "runtimeType") {
- // TODO(ahe): Implement runtimeType.
- generateUnimplementedError(
- node,
- "'runtimeType' isn't supported in Fletch. See https://goo.gl/ELH6Zc");
- applyVisitState();
- return;
- }
- visitForValue(receiver);
- invokeGetter(node, name);
- applyVisitState();
- }
-
- void visitIfNotNullDynamicPropertyGet(
- Send node,
- Node receiver,
- Name name,
- _) {
- doIfNotNull(receiver, () {
- invokeGetter(node, name);
- });
- applyVisitState();
- }
-
- void visitThisPropertyGet(
- Send node,
- Name name,
- _) {
- loadThis();
- invokeGetter(node, name);
- applyVisitState();
- }
-
- void visitThisPropertySet(
- Send node,
- Name name,
- Node rhs,
- _) {
- loadThis();
- visitForValue(rhs);
- invokeSetter(node, name);
- applyVisitState();
- }
-
- void doStaticFieldGet(FieldElement field) {
- if (checkCompileError(field)) return;
- if (field.isConst) {
- int constId = allocateConstantFromNode(
- field.initializer,
- elements: field.resolvedAst.elements);
- assembler.loadConst(constId);
- } else {
- int index = compileLazyFieldInitializer(field);
- if (field.initializer != null) {
- assembler.loadStaticInit(index);
- } else {
- assembler.loadStatic(index);
- }
- }
- }
-
- void handleStaticFieldGet(
- Send node,
- FieldElement field,
- _) {
- doStaticFieldGet(field);
- applyVisitState();
- }
-
- void visitAssert(Assert node) {
- // TODO(ajohnsen): Emit assert in checked mode.
- }
-
- void visitDynamicPropertySet(
- Send node,
- Node receiver,
- Name name,
- Node rhs,
- _) {
- visitForValue(receiver);
- visitForValue(rhs);
- invokeSetter(node, name);
- applyVisitState();
- }
-
- void visitIfNotNullDynamicPropertySet(
- SendSet node,
- Node receiver,
- Name name,
- Node rhs,
- _) {
- doIfNotNull(receiver, () {
- visitForValue(rhs);
- invokeSetter(node, name);
- });
- applyVisitState();
- }
-
- void doStaticFieldSet(
- FieldElement field) {
- int index = context.getStaticFieldIndex(field, element);
- assembler.storeStatic(index);
- }
-
- void handleStaticFieldSet(
- SendSet node,
- FieldElement field,
- Node rhs,
- _) {
- visitForValue(rhs);
- doStaticFieldSet(field);
- applyVisitState();
- }
-
- void visitStringJuxtaposition(StringJuxtaposition node) {
- // TODO(ajohnsen): This could probably be optimized to string constants in
- // some cases.
- visitForValue(node.first);
- visitForValue(node.second);
- // TODO(ajohnsen): Cache these in context/backend.
- Selector concat = new Selector.binaryOperator('+');
- invokeMethod(node, concat);
- applyVisitState();
- }
-
- void visitStringInterpolation(StringInterpolation node) {
- // TODO(ajohnsen): Cache this in context/backend.
- Selector concat = new Selector.binaryOperator('+');
- visitForValueNoDebugInfo(node.string);
- for (StringInterpolationPart part in node.parts) {
- visitForValue(part.expression);
- invokeMethod(part.expression, Selectors.toString_);
- LiteralString string = part.string;
- if (string.dartString.isNotEmpty) {
- visitForValueNoDebugInfo(string);
- invokeMethod(null, concat);
- }
- invokeMethod(null, concat);
- }
- applyVisitState();
- }
-
- void visitLiteralNull(LiteralNull node) {
- if (visitState == VisitState.Value) {
- assembler.loadLiteralNull();
- } else if (visitState == VisitState.Test) {
- if (falseLabel != null) assembler.branch(falseLabel);
- }
- }
-
- void visitLiteralSymbol(LiteralSymbol node) {
- int constId = allocateConstantFromNode(node);
- assembler.loadConst(constId);
- applyVisitState();
- }
-
- void visitLiteralBool(LiteralBool node) {
- var expression = compileConstant(node, isConst: false);
- bool isTrue = expression != null &&
- context.getConstantValue(expression).isTrue;
-
- if (visitState == VisitState.Value) {
- if (isTrue) {
- assembler.loadLiteralTrue();
- } else {
- assembler.loadLiteralFalse();
- }
- } else if (visitState == VisitState.Test) {
- if (isTrue) {
- if (trueLabel != null) assembler.branch(trueLabel);
- } else {
- if (falseLabel != null) assembler.branch(falseLabel);
- }
- }
- }
-
- void visitLiteralInt(LiteralInt node) {
- if (visitState == VisitState.Value) {
- int value = node.value;
- assert(value >= 0);
- if (value > LITERAL_INT_MAX) {
- if ((value < MIN_INT64 || value > MAX_INT64) && !context.enableBigint) {
- generateUnimplementedError(
- node,
- 'Program compiled without support for big integers');
- } else {
- int constId = allocateConstantFromNode(node);
- assembler.loadConst(constId);
- }
- } else {
- assembler.loadLiteral(value);
- }
- } else if (visitState == VisitState.Test) {
- if (falseLabel != null) assembler.branch(falseLabel);
- }
- }
-
- void visitLiteral(Literal node) {
- if (visitState == VisitState.Value) {
- assembler.loadConst(allocateConstantFromNode(node));
- } else if (visitState == VisitState.Test) {
- if (falseLabel != null) assembler.branch(falseLabel);
- }
- }
-
- void visitLiteralList(LiteralList node) {
- if (node.isConst) {
- int constId = allocateConstantFromNode(node);
- assembler.loadConst(constId);
- applyVisitState();
- return;
- }
- ClassElement literalClass = context.backend.growableListClass;
- ConstructorElement constructor = literalClass.lookupDefaultConstructor();
- if (constructor == null) {
- internalError(node, "Failed to lookup default list constructor");
- }
- // Call with empty arguments, as we call the default constructor.
- callConstructor(
- node, constructor, new NodeList.empty(), CallStructure.NO_ARGS);
- Selector add = new Selector.call(new Name('add', null),
- CallStructure.ONE_ARG);
- for (Node element in node.elements) {
- assembler.dup();
- visitForValue(element);
- invokeMethod(node, add);
- assembler.pop();
- }
- applyVisitState();
- }
-
- void visitLiteralMap(LiteralMap node) {
- if (node.isConst) {
- int constId = allocateConstantFromNode(node);
- assembler.loadConst(constId);
- applyVisitState();
- return;
- }
- ClassElement literalClass =
- context.backend.mapImplementation.implementation;
- ConstructorElement constructor = literalClass.lookupConstructor("");
- if (constructor == null) {
- internalError(literalClass, "Failed to lookup default map constructor");
- return;
- }
- // The default constructor is a redirecting factory constructor. Follow it.
- constructor = constructor.effectiveTarget;
- FletchFunctionBase function = requireFunction(constructor.declaration);
- doStaticFunctionInvoke(
- node,
- function,
- new NodeList.empty(),
- CallStructure.NO_ARGS,
- factoryInvoke: true);
-
- Selector selector = new Selector.indexSet();
- for (Node element in node.entries) {
- assembler.dup();
- visitForValue(element);
- invokeMethod(node, selector);
- assembler.pop();
- }
- applyVisitState();
- }
-
- void visitLiteralMapEntry(LiteralMapEntry node) {
- assert(visitState == VisitState.Value);
- visitForValue(node.key);
- visitForValue(node.value);
- }
-
- void visitLiteralString(LiteralString node) {
- if (visitState == VisitState.Value) {
- assembler.loadConst(allocateConstantFromNode(node));
- registerInstantiatedClass(
- context.compiler.backend.stringImplementation);
- } else if (visitState == VisitState.Test) {
- if (falseLabel != null) assembler.branch(falseLabel);
- }
- }
-
- void visitCascadeReceiver(CascadeReceiver node) {
- visitForValue(node.expression);
- assembler.dup();
- assert(visitState == VisitState.Value);
- }
-
- void visitCascade(Cascade node) {
- visitForEffect(node.expression);
- applyVisitState();
- }
-
- void visitParenthesizedExpression(ParenthesizedExpression node) {
- // Visit expression in the same VisitState.
- node.expression.accept(this);
- }
-
- void visitLocalFunctionGet(Send node, LocalFunctionElement function, _) {
- registerClosurization(function, ClosureKind.localFunction);
- handleLocalGet(node, function, _);
- }
-
- void handleLocalGet(
- Send node,
- LocalElement element,
- _) {
- scope[element].load(assembler);
- applyVisitState();
- }
-
- void handleLocalSet(
- SendSet node,
- LocalElement element,
- Node rhs,
- _) {
- visitForValue(rhs);
- scope[element].store(assembler);
- applyVisitState();
- }
-
- void visitLocalFunctionInvoke(
- Send node,
- LocalFunctionElement function,
- NodeList arguments,
- CallStructure callStructure,
- _) {
- // TODO(ahe): We could use loadPositionalArguments if [element] is a local
- // function to avoid generating additional stubs and to avoid registering
- // this as a dynamic call.
- registerLocalInvoke(function, callStructure.callSelector);
- handleLocalInvoke(node, function, arguments, callStructure, _);
- }
-
- void handleLocalInvoke(
- Node node,
- LocalElement element,
- NodeList arguments,
- CallStructure callStructure,
- _) {
- scope[element].load(assembler);
- for (Node argument in arguments) {
- visitForValue(argument);
- }
- invokeMethod(node, callStructure.callSelector);
- applyVisitState();
- }
-
- static Selector getIncDecSelector(IncDecOperator operator) {
- String name = operator == IncDecOperator.INC ? '+' : '-';
- return new Selector.binaryOperator(name);
- }
-
- static Selector getAssignmentSelector(AssignmentOperator operator) {
- String name = operator.binaryOperator.name;
- return new Selector.binaryOperator(name);
- }
-
- void doLocalVariableIncrement(
- Node node,
- LocalVariableElement element,
- IncDecOperator operator,
- bool prefix) {
- // TODO(ajohnsen): Candidate for bytecode: Inc/Dec local with non-Smi
- // bailout.
- LocalValue value = scope[element];
- value.load(assembler);
- // For postfix, keep local, unmodified version, to 'return' after store.
- if (!prefix) assembler.dup();
- assembler.loadLiteral(1);
- invokeMethod(node, getIncDecSelector(operator));
- value.store(assembler);
- if (!prefix) assembler.pop();
- }
-
- void visitLocalVariablePrefix(
- SendSet node,
- LocalVariableElement element,
- IncDecOperator operator,
- _) {
- doLocalVariableIncrement(node, element, operator, true);
- applyVisitState();
- }
-
- void visitParameterPrefix(
- Send node,
- LocalParameterElement parameter,
- IncDecOperator operator,
- _) {
- doLocalVariableIncrement(node, parameter, operator, true);
- applyVisitState();
- }
-
- void visitLocalVariablePostfix(
- SendSet node,
- LocalVariableElement element,
- IncDecOperator operator,
- _) {
- // If visitState is for effect, we can ignore the return value, thus always
- // generate code for the simpler 'prefix' case.
- bool prefix = (visitState == VisitState.Effect);
- doLocalVariableIncrement(node, element, operator, prefix);
- applyVisitState();
- }
-
- void visitParameterPostfix(
- SendSet node,
- LocalParameterElement parameter,
- IncDecOperator operator,
- _) {
- // If visitState is for effect, we can ignore the return value, thus always
- // generate code for the simpler 'prefix' case.
- bool prefix = (visitState == VisitState.Effect);
- doLocalVariableIncrement(node, parameter, operator, prefix);
- applyVisitState();
- }
-
- void doStaticFieldPrefix(
- Node node,
- FieldElement field,
- IncDecOperator operator) {
- doStaticFieldGet(field);
- assembler.loadLiteral(1);
- invokeMethod(node, getIncDecSelector(operator));
- doStaticFieldSet(field);
- }
-
- void doStaticFieldPostfix(
- Node node,
- FieldElement field,
- IncDecOperator operator) {
- doStaticFieldGet(field);
- // For postfix, keep local, unmodified version, to 'return' after store.
- assembler.dup();
- assembler.loadLiteral(1);
- invokeMethod(node, getIncDecSelector(operator));
- doStaticFieldSet(field);
- assembler.pop();
- }
-
- void visitStaticFieldPostfix(
- Send node,
- FieldElement field,
- IncDecOperator operator,
- _) {
- if (visitState == VisitState.Effect) {
- doStaticFieldPrefix(node, field, operator);
- } else {
- doStaticFieldPostfix(node, field, operator);
- }
- applyVisitState();
- }
-
- void visitStaticFieldPrefix(
- Send node,
- FieldElement field,
- IncDecOperator operator,
- _) {
- doStaticFieldPrefix(node, field, operator);
- applyVisitState();
- }
-
- void visitTopLevelFieldPostfix(
- Send node,
- FieldElement field,
- IncDecOperator operator,
- _) {
- if (visitState == VisitState.Effect) {
- doStaticFieldPrefix(node, field, operator);
- } else {
- doStaticFieldPostfix(node, field, operator);
- }
- applyVisitState();
- }
-
- void visitTopLevelFieldPrefix(
- Send node,
- FieldElement field,
- IncDecOperator operator,
- _) {
- doStaticFieldPrefix(node, field, operator);
- applyVisitState();
- }
-
- void doDynamicPropertyCompound(
- Node node,
- Name name,
- AssignmentOperator operator,
- Node rhs) {
- // Dup receiver for setter.
- assembler.dup();
- invokeGetter(node, name);
- visitForValue(rhs);
- invokeMethod(node, getAssignmentSelector(operator));
- invokeSetter(node, name);
- }
-
- void visitDynamicPropertyCompound(
- Send node,
- Node receiver,
- Name name,
- AssignmentOperator operator,
- Node rhs,
- _) {
- visitForValue(receiver);
- doDynamicPropertyCompound(
- node,
- name,
- operator,
- rhs);
- applyVisitState();
- }
-
- void visitIfNotNullDynamicPropertyCompound(
- Send node,
- Node receiver,
- Name name,
- AssignmentOperator operator,
- Node rhs,
- _) {
- doIfNotNull(receiver, () {
- doDynamicPropertyCompound(
- node,
- name,
- operator,
- rhs);
- });
- applyVisitState();
- }
-
- void visitThisPropertyCompound(
- Send node,
- Name name,
- AssignmentOperator operator,
- Node rhs,
- _) {
- loadThis();
- doDynamicPropertyCompound(
- node,
- name,
- operator,
- rhs);
- applyVisitState();
- }
-
- void doDynamicPrefix(
- Node node,
- Name name,
- IncDecOperator operator) {
- assembler.dup();
- invokeGetter(node, name);
- assembler.loadLiteral(1);
- invokeMethod(node, getIncDecSelector(operator));
- invokeSetter(node, name);
- }
-
- void doIndexPrefix(
- SendSet node,
- Node receiver,
- Node index,
- IncDecOperator operator) {
- visitForValue(receiver);
- visitForValue(index);
- // Load already evaluated receiver and index for '[]' call.
- assembler.loadLocal(1);
- assembler.loadLocal(1);
- invokeMethod(node, new Selector.index());
- assembler.loadLiteral(1);
- invokeMethod(node, getIncDecSelector(operator));
- // Use existing evaluated receiver and index for '[]=' call.
- invokeMethod(node, new Selector.indexSet());
- }
-
- void visitIndexPrefix(
- SendSet node,
- Node receiver,
- Node index,
- IncDecOperator operator,
- _) {
- doIndexPrefix(node, receiver, index, operator);
- applyVisitState();
- }
-
- void visitIndexPostfix(
- Send node,
- Node receiver,
- Node index,
- IncDecOperator operator,
- _) {
- if (visitState == VisitState.Effect) {
- doIndexPrefix(node, receiver, index, operator);
- applyVisitState();
- return;
- }
-
- // Reserve slot for result.
- assembler.loadLiteralNull();
- visitForValue(receiver);
- visitForValue(index);
- // Load already evaluated receiver and index for '[]' call.
- assembler.loadLocal(1);
- assembler.loadLocal(1);
- invokeMethod(node, new Selector.index());
- assembler.storeLocal(3);
- assembler.loadLiteral(1);
- invokeMethod(node, getIncDecSelector(operator));
- // Use existing evaluated receiver and index for '[]=' call.
- invokeMethod(node, new Selector.indexSet());
- assembler.pop();
- applyVisitState();
- }
-
- void visitCompoundIndexSet(
- Send node,
- Node receiver,
- Node index,
- AssignmentOperator operator,
- Node rhs,
- _) {
- visitForValue(receiver);
- visitForValue(index);
- // Load already evaluated receiver and index for '[]' call.
- assembler.loadLocal(1);
- assembler.loadLocal(1);
- invokeMethod(node, new Selector.index());
- visitForValue(rhs);
- invokeMethod(node, getAssignmentSelector(operator));
- // Use existing evaluated receiver and index for '[]=' call.
- invokeMethod(node, new Selector.indexSet());
- applyVisitState();
- }
-
- void visitThisPropertyPrefix(
- Send node,
- Name name,
- IncDecOperator operator,
- _) {
- loadThis();
- doDynamicPrefix(node, name, operator);
- applyVisitState();
- }
-
- void visitThisPropertyPostfix(
- Send node,
- Name name,
- IncDecOperator operator,
- _) {
- // If visitState is for effect, we can ignore the return value, thus always
- // generate code for the simpler 'prefix' case.
- if (visitState == VisitState.Effect) {
- loadThis();
- doDynamicPrefix(node, name, operator);
- applyVisitState();
- return;
- }
-
- loadThis();
- invokeGetter(node, name);
- // For postfix, keep local, unmodified version, to 'return' after store.
- assembler.dup();
- assembler.loadLiteral(1);
- invokeMethod(node, getIncDecSelector(operator));
- loadThis();
- assembler.loadLocal(1);
- invokeSetter(node, name);
- assembler.popMany(2);
- applyVisitState();
- }
-
- void visitDynamicPropertyPrefix(
- Send node,
- Node receiver,
- Name name,
- IncDecOperator operator,
- _) {
- visitForValue(receiver);
- doDynamicPrefix(node, name, operator);
- applyVisitState();
- }
-
- void visitIfNotNullDynamicPropertyPrefix(
- Send node,
- Node receiver,
- Name name,
- IncDecOperator operator,
- _) {
- doIfNotNull(receiver, () {
- doDynamicPrefix(node, name, operator);
- });
- applyVisitState();
- }
-
- void doDynamicPostfix(
- Send node,
- Node receiver,
- Name name,
- IncDecOperator operator) {
- int receiverSlot = assembler.stackSize - 1;
- assembler.loadSlot(receiverSlot);
- invokeGetter(node, name);
- // For postfix, keep local, unmodified version, to 'return' after store.
- assembler.dup();
- assembler.loadLiteral(1);
- invokeMethod(node, getIncDecSelector(operator));
- assembler.loadSlot(receiverSlot);
- assembler.loadLocal(1);
- invokeSetter(node, name);
- assembler.popMany(2);
- assembler.storeLocal(1);
- // Pop receiver.
- assembler.pop();
- }
-
- void visitDynamicPropertyPostfix(
- Send node,
- Node receiver,
- Name name,
- IncDecOperator operator,
- _) {
- // If visitState is for effect, we can ignore the return value, thus always
- // generate code for the simpler 'prefix' case.
- if (visitState == VisitState.Effect) {
- visitForValue(receiver);
- doDynamicPrefix(node, name, operator);
- applyVisitState();
- return;
- }
-
- visitForValue(receiver);
- doDynamicPostfix(node, receiver, name, operator);
- applyVisitState();
- }
-
- void visitIfNotNullDynamicPropertyPostfix(
- Send node,
- Node receiver,
- Name name,
- IncDecOperator operator,
- _) {
- doIfNotNull(receiver, () {
- doDynamicPostfix(
- node, receiver, name, operator);
- });
- applyVisitState();
- }
-
- void visitThrow(Throw node) {
- visitForValue(node.expression);
- generateThrow(node);
- // TODO(ahe): It seems suboptimal that each throw is followed by a pop.
- applyVisitState();
- }
-
- void visitRethrow(Rethrow node) {
- if (tryBlockStack.isEmpty) {
- doCompileError(context.compiler.reporter.createMessage(
- node, MessageKind.GENERIC, {"text": "Rethrow outside try"}));
- } else {
- TryBlock block = tryBlockStack.head;
- assembler.loadSlot(block.stackSize - 1);
- // TODO(ahe): It seems suboptimal that each throw is followed by a pop.
- generateThrow(node);
- }
- assembler.pop();
- }
-
- void callConstructor(Node node,
- ConstructorElement constructor,
- NodeList arguments,
- CallStructure callStructure) {
- FletchFunctionBase function = requireConstructorInitializer(constructor);
- doStaticFunctionInvoke(node, function, arguments, callStructure);
- }
-
- void doConstConstructorInvoke(ConstantExpression constant) {
- var value = context.getConstantValue(constant);
- context.markConstantUsed(value);
- int constId = functionBuilder.allocateConstant(value);
- assembler.loadConst(constId);
- }
-
- void visitConstConstructorInvoke(
- NewExpression node,
- ConstructedConstantExpression constant,
- _) {
- // TODO(johnniwinther): We should not end up here with an bad constructor.
- if (!checkCompileError(elements[node.send])) {
- doConstConstructorInvoke(constant);
- }
- applyVisitState();
- }
-
- void visitBoolFromEnvironmentConstructorInvoke(
- NewExpression node,
- BoolFromEnvironmentConstantExpression constant,
- _) {
- doConstConstructorInvoke(constant);
- applyVisitState();
- }
-
- void visitIntFromEnvironmentConstructorInvoke(
- NewExpression node,
- IntFromEnvironmentConstantExpression constant,
- _) {
- doConstConstructorInvoke(constant);
- applyVisitState();
- }
-
- void visitStringFromEnvironmentConstructorInvoke(
- NewExpression node,
- StringFromEnvironmentConstantExpression constant,
- _) {
- doConstConstructorInvoke(constant);
- applyVisitState();
- }
-
- void visitGenerativeConstructorInvoke(
- NewExpression node,
- ConstructorElement constructor,
- InterfaceType type,
- NodeList arguments,
- CallStructure callStructure,
- _) {
- if (!checkCompileError(constructor)) {
- callConstructor(node, constructor.declaration, arguments, callStructure);
- }
- applyVisitState();
- }
-
- void visitFactoryConstructorInvoke(
- NewExpression node,
- ConstructorElement constructor,
- InterfaceType type,
- NodeList arguments,
- CallStructure callStructure,
- _) {
- // If the constructor has an implementation, the implementation is the
- // factory we want to invoke. Redirect to
- // visitRedirectingFactoryConstructorInvoke, so we handle both cases of
- // either a factory or a redirecting factory.
- if (constructor.implementation != constructor) {
- ConstructorElement implementation = constructor.implementation;
- visitRedirectingFactoryConstructorInvoke(
- node,
- constructor,
- type,
- implementation.effectiveTarget,
- null,
- arguments,
- callStructure,
- null);
- return;
- }
- // TODO(ahe): Remove ".declaration" when issue 23135 is fixed.
- FletchFunctionBase function = requireFunction(constructor.declaration);
- doStaticFunctionInvoke(
- node, function, arguments, callStructure, factoryInvoke: true);
- applyVisitState();
- }
-
- void visitConstructorIncompatibleInvoke(
- NewExpression node,
- ConstructorElement constructor,
- InterfaceType type,
- NodeList arguments,
- CallStructure callStructure,
- _) {
- if (!checkCompileError(constructor)) {
- doUnresolved(constructor.name);
- }
- applyVisitState();
- }
-
- void visitRedirectingGenerativeConstructorInvoke(
- NewExpression node,
- ConstructorElement constructor,
- InterfaceType type,
- NodeList arguments,
- CallStructure callStructure,
- _) {
- visitGenerativeConstructorInvoke(
- node,
- constructor,
- type,
- arguments,
- callStructure,
- null);
- }
-
- void visitRedirectingFactoryConstructorInvoke(
- NewExpression node,
- ConstructorElement constructor,
- InterfaceType type,
- ConstructorElement effectiveTarget,
- InterfaceType effectiveTargetType,
- NodeList arguments,
- CallStructure callStructure,
- _) {
- if (effectiveTarget.isGenerativeConstructor) {
- visitGenerativeConstructorInvoke(
- node,
- effectiveTarget,
- effectiveTargetType,
- arguments,
- callStructure,
- null);
- } else {
- visitFactoryConstructorInvoke(
- node,
- effectiveTarget,
- effectiveTargetType,
- arguments,
- callStructure,
- null);
- }
- }
-
- void visitUnresolvedConstructorInvoke(
- NewExpression node,
- Element constructor,
- DartType type,
- NodeList arguments,
- Selector selector,
- _) {
- if (!checkCompileError(constructor.enclosingClass)) {
- doUnresolved(node.send.toString());
- }
- applyVisitState();
- }
-
- void visitUnresolvedClassConstructorInvoke(
- NewExpression node,
- Element element,
- DartType type,
- NodeList arguments,
- Selector selector,
- _) {
- doUnresolved(node.send.toString());
- applyVisitState();
- }
-
- void visitAbstractClassConstructorInvoke(
- NewExpression node,
- ConstructorElement element,
- InterfaceType type,
- NodeList arguments,
- CallStructure callStructure,
- _) {
- generateUnimplementedError(node, "Cannot allocate abstract class");
- applyVisitState();
- }
-
- void visitUnresolvedRedirectingFactoryConstructorInvoke(
- NewExpression node,
- ConstructorElement constructor,
- InterfaceType type,
- NodeList arguments,
- CallStructure callStructure,
- _) {
- doUnresolved(node.send.toString());
- applyVisitState();
- }
-
- void doStaticGetterGet(Send node, FunctionElement getter) {
- if (getter == context.backend.fletchExternalNativeError) {
- assembler.loadSlot(0);
- return;
- }
-
- if (getter.isDeferredLoaderGetter) {
- generateUnimplementedError(node, "Deferred loading is not supported.");
- return;
- }
-
- FletchFunctionBase base = requireFunction(getter);
- int constId = functionBuilder.allocateConstantFromFunction(base.functionId);
- invokeStatic(node, constId, 0);
- }
-
- void handleStaticGetterGet(Send node, FunctionElement getter, _) {
- doStaticGetterGet(node, getter);
- applyVisitState();
- }
-
- void handleStaticGetterInvoke(
- Send node,
- FunctionElement getter,
- NodeList arguments,
- CallStructure callStructure,
- _) {
- doStaticGetterGet(node, getter);
- for (Node argument in arguments) {
- visitForValue(argument);
- }
- invokeMethod(node, callStructure.callSelector);
- applyVisitState();
- }
-
- void handleStaticSetterSet(
- Send node,
- FunctionElement setter,
- Node rhs,
- _) {
- visitForValue(rhs);
- FletchFunctionBase base = requireFunction(setter);
- int constId = functionBuilder.allocateConstantFromFunction(base.functionId);
- invokeStatic(node, constId, 1);
- applyVisitState();
- }
-
- /**
- * Load the captured variables of [function], expressed in [info].
- *
- * If [function] captures itself, its field index is returned.
- */
- int pushCapturedVariables(FunctionElement function) {
- ClosureInfo info = closureEnvironment.closures[function];
- if (info == null) {
- // TODO(ahe): Do not throw here, instead fix bug in incremental compiler
- // (see test closure_capture).
- throw new IncrementalCompilationFailed(
- "Internal error: no closure info for $function");
- }
- int index = 0;
- if (info.isThisFree) {
- loadThis();
- index++;
- }
- int thisClosureIndex = -1;
- for (LocalElement element in info.free) {
- if (element == function) {
- // If we capture ourself, remember index and assign into closure after
- // allocation.
- assembler.loadLiteralNull();
- assert(thisClosureIndex == -1);
- thisClosureIndex = index;
- } else {
- // Load the raw value (the 'Box' when by reference).
- scope[element].loadRaw(assembler);
- }
- index++;
- }
- return thisClosureIndex;
- }
-
- void visitFunctionExpression(FunctionExpression node) {
- FunctionElement function = elements[node];
-
- // If the closure captures itself, thisClosureIndex is the field-index in
- // the closure.
- int thisClosureIndex = pushCapturedVariables(function);
- bool needToStoreThisReference = thisClosureIndex >= 0;
-
- FletchClassBuilder classBuilder = context.backend.createClosureClass(
- function,
- closureEnvironment);
- int classConstant = functionBuilder.allocateConstantFromClass(
- classBuilder.classId);
-
- // NOTE: Currently we emit a storeField instruction in case a closure
- // captures itself. Changing fields makes it a mutable object.
- // We can therefore not allocate the object with `immutable = true`.
- // TODO(fletchc-team): Could we restrict this limitation.
- bool immutable = !closureEnvironment.closures[function].free.any(
- closureEnvironment.shouldBeBoxed) && !needToStoreThisReference;
-
- assembler.allocate(
- classConstant, classBuilder.fields, immutable: immutable);
-
- if (needToStoreThisReference) {
- assert(!immutable);
- assembler.dup();
- assembler.storeField(thisClosureIndex);
- }
-
- if (!functionDeclarations.contains(node)) {
- registerClosurization(function, ClosureKind.localFunction);
- }
- applyVisitState();
- }
-
- void visitExpression(Expression node) {
- generateUnimplementedError(
- node, "Missing visit of expression: ${node.runtimeType}");
- applyVisitState();
- }
-
- void visitStatement(Node node) {
- generateUnimplementedError(
- node, "Missing visit of statement: ${node.runtimeType}");
- assembler.pop();
- }
-
- void doStatements(NodeList statements) {
- List<Element> oldBlockLocals = blockLocals;
- blockLocals = <Element>[];
- int stackSize = assembler.stackSize;
-
- for (Node statement in statements) {
- statement.accept(this);
- }
-
- int stackSizeDifference = assembler.stackSize - stackSize;
- if (stackSizeDifference != blockLocals.length) {
- internalError(
- statements,
- "Unbalanced number of block locals and stack slots used by block.");
- }
-
- if (blockLocals.length > 0) assembler.popMany(blockLocals.length);
-
- for (int i = blockLocals.length - 1; i >= 0; --i) {
- popVariableDeclaration(blockLocals[i]);
- }
-
- blockLocals = oldBlockLocals;
- }
-
- void visitBlock(Block node) {
- var breakLabel = new BytecodeLabel();
- jumpInfo[node] = new JumpInfo(assembler.stackSize, null, breakLabel);
- doStatements(node.statements);
- assembler.bind(breakLabel);
- }
-
- void visitEmptyStatement(EmptyStatement node) {
- }
-
- void visitExpressionStatement(ExpressionStatement node) {
- visitForEffect(node.expression);
- }
-
- // Called before 'return', as an option to replace the already evaluated
- // return value. One example is setters.
- bool get hasAssignmentSemantics => false;
- void optionalReplaceResultValue() { }
-
- void visitReturn(Return node) {
- Expression expression = node.expression;
- bool returnNull = true;
- if (expression != null && !isConstNull(expression)) {
- visitForValue(expression);
- returnNull = false;
- }
-
- // Avoid using the return-null bytecode if we have assignment semantics.
- if (returnNull && hasAssignmentSemantics) {
- assembler.loadLiteralNull();
- returnNull = false;
- }
-
- if (returnNull) {
- callFinallyBlocks(0, false);
- generateReturnNull(node);
- } else {
- callFinallyBlocks(0, true);
- optionalReplaceResultValue();
- generateReturn(node);
- }
- }
-
- // Find the JumpInfo matching the target of [node].
- JumpInfo getJumpTargetInfo(GotoStatement node) {
- JumpTarget target = elements.getTargetOf(node);
- if (target == null) {
- generateUnimplementedError(node, "'$node' not in loop");
- assembler.pop();
- return null;
- }
- Node statement = target.statement;
- JumpInfo info = jumpInfo[statement];
- if (info == null) {
- generateUnimplementedError(node, "'$node' has no target");
- assembler.pop();
- }
- return info;
- }
-
- void callFinallyBlocks(int targetStackSize, bool preserveTop) {
- int popCount = 0;
- for (var block in tryBlockStack) {
- // Break once all exited finally blocks are processed. Finally blocks
- // are ordered by stack size which coincides with scoping. Blocks with
- // stack sizes at least equal to target size are being exited.
- if (block.stackSize < targetStackSize) break;
- if (block.finallyLabel == null) continue;
- if (preserveTop) {
- // We reuse the exception slot as a temporary buffer for the top
- // element, which is located -1 relative to the block's stack size.
- assembler.storeSlot(block.stackSize - 1);
- }
- // TODO(ajohnsen): Don't pop, but let subroutineCall take a 'pop count'
- // argument, just like popAndBranch.
- if (assembler.stackSize > block.stackSize) {
- int sizeDifference = assembler.stackSize - block.stackSize;
- popCount += sizeDifference;
- assembler.popMany(sizeDifference);
- }
- assembler.subroutineCall(block.finallyLabel, block.finallyReturnLabel);
- if (preserveTop) {
- assembler.loadSlot(block.stackSize - 1);
- popCount--;
- }
- }
- // Reallign stack (should be removed, according to above TODO).
- for (int i = 0; i < popCount; i++) {
- // Note we dup, to make sure the top element is the return value.
- assembler.dup();
- }
- }
-
- void unbalancedBranch(GotoStatement node, bool isBreak) {
- JumpInfo info = getJumpTargetInfo(node);
- if (info == null) return;
- callFinallyBlocks(info.stackSize, false);
- BytecodeLabel label = isBreak ? info.breakLabel : info.continueLabel;
- int diff = assembler.stackSize - info.stackSize;
- assembler.popAndBranch(diff, label);
- }
-
- void visitBreakStatement(BreakStatement node) {
- var breakLabel = new BytecodeLabel();
- jumpInfo[node] = new JumpInfo(assembler.stackSize, null, breakLabel);
- unbalancedBranch(node, true);
- assembler.bind(breakLabel);
- }
-
- void visitContinueStatement(ContinueStatement node) {
- unbalancedBranch(node, false);
- }
-
- void visitIf(If node) {
- ConstantExpression conditionConstant =
- inspectConstant(node.condition, isConst: false);
-
- if (conditionConstant != null) {
- BytecodeLabel end = new BytecodeLabel();
- jumpInfo[node] = new JumpInfo(assembler.stackSize, null, end);
- if (context.getConstantValue(conditionConstant).isTrue) {
- doScopedStatement(node.thenPart);
- } else if (node.hasElsePart) {
- doScopedStatement(node.elsePart);
- }
- assembler.bind(end);
- return;
- }
-
- BytecodeLabel ifFalse = new BytecodeLabel();
-
- visitForTest(node.condition, null, ifFalse);
- if (node.hasElsePart) {
- BytecodeLabel end = new BytecodeLabel();
- jumpInfo[node] = new JumpInfo(assembler.stackSize, null, end);
- doScopedStatement(node.thenPart);
- assembler.branch(end);
- assembler.bind(ifFalse);
- doScopedStatement(node.elsePart);
- assembler.bind(end);
- } else {
- jumpInfo[node] = new JumpInfo(assembler.stackSize, null, ifFalse);
- doScopedStatement(node.thenPart);
- assembler.bind(ifFalse);
- }
- }
-
- void visitFor(For node) {
- List<Element> oldBlockLocals = blockLocals;
- blockLocals = <Element>[];
-
- BytecodeLabel start = new BytecodeLabel();
- BytecodeLabel end = new BytecodeLabel();
- BytecodeLabel afterBody = new BytecodeLabel();
-
- Node initializer = node.initializer;
- if (initializer != null) visitForEffect(initializer);
-
- jumpInfo[node] = new JumpInfo(assembler.stackSize, afterBody, end);
-
- assembler.bind(start);
-
- Expression condition = node.condition;
- if (condition != null) {
- visitForTest(condition, null, end);
- }
-
- doScopedStatement(node.body);
-
- assembler.bind(afterBody);
-
- for (int i = blockLocals.length - 1; i >= 0; --i) {
- LocalElement local = blockLocals[i];
- // If the locals are captured by reference, load the current value and
- // store it in a new boxed.
- if (closureEnvironment.shouldBeBoxed(local)) {
- LocalValue value = scope[local];
- value.load(assembler);
- value.initialize(assembler);
- assembler.storeSlot(value.slot);
- assembler.pop();
- }
- }
-
- for (Node update in node.update) {
- visitForEffect(update);
- }
- assembler.branch(start);
-
- assembler.bind(end);
-
- for (int i = blockLocals.length - 1; i >= 0; --i) {
- assembler.pop();
- popVariableDeclaration(blockLocals[i]);
- }
-
- blockLocals = oldBlockLocals;
- }
-
- void visitSyncForIn(SyncForIn node) {
- visitForIn(node);
- }
-
- void visitForIn(ForIn node) {
- BytecodeLabel start = new BytecodeLabel();
- BytecodeLabel end = new BytecodeLabel();
-
- // Evalutate expression and iterator.
- visitForValue(node.expression);
- invokeGetter(node.expression, Names.iterator);
-
- jumpInfo[node] = new JumpInfo(assembler.stackSize, start, end);
-
- assembler.bind(start);
-
- assembler.dup();
- invokeMethod(node, Selectors.moveNext);
- assembler.branchIfFalse(end);
-
- bool isVariableDeclaration = node.declaredIdentifier.asSend() == null;
- Element element = elements[node];
- if (isVariableDeclaration) {
- // Create local value and load the current element to it.
- LocalValue value = createLocalValueFor(element);
- assembler.dup();
- invokeGetter(node, Names.current);
- value.initialize(assembler);
- pushVariableDeclaration(value);
- } else {
- if (element == null || element.isInstanceMember) {
- loadThis();
- assembler.loadLocal(1);
- invokeGetter(node, Names.current);
- Selector selector = elements.getSelector(node.declaredIdentifier);
- invokeSetter(node, selector.memberName);
- } else {
- assembler.dup();
- invokeGetter(node, Names.current);
- if (element.isLocal) {
- scope[element].store(assembler);
- } else if (element.isField) {
- doStaticFieldSet(element);
- } else if (element.isMalformed) {
- doUnresolved(element.name);
- assembler.pop();
- } else {
- internalError(node, "Unhandled store in for-in");
- }
- }
- assembler.pop();
- }
-
- doScopedStatement(node.body);
-
- if (isVariableDeclaration) {
- // Pop the local again.
- assembler.pop();
- popVariableDeclaration(element);
- }
-
- assembler.branch(start);
-
- assembler.bind(end);
-
- // Pop iterator.
- assembler.pop();
- }
-
- void visitLabeledStatement(LabeledStatement node) {
- node.statement.accept(this);
- }
-
- // Visit the statement in a scope, where locals are popped when left.
- void doScopedStatement(Node statement) {
- Block block = statement.asBlock();
- if (block != null) {
- doStatements(block.statements);
- } else {
- doStatements(new NodeList.singleton(statement));
- }
- }
-
- void visitWhile(While node) {
- BytecodeLabel start = new BytecodeLabel();
- BytecodeLabel end = new BytecodeLabel();
- jumpInfo[node] = new JumpInfo(assembler.stackSize, start, end);
- assembler.bind(start);
- visitForTest(node.condition, null, end);
- doScopedStatement(node.body);
- assembler.branch(start);
- assembler.bind(end);
- }
-
- void visitDoWhile(DoWhile node) {
- BytecodeLabel start = new BytecodeLabel();
- BytecodeLabel end = new BytecodeLabel();
- BytecodeLabel skipBody = new BytecodeLabel();
- jumpInfo[node] = new JumpInfo(assembler.stackSize, skipBody, end);
- assembler.bind(start);
- doScopedStatement(node.body);
- assembler.bind(skipBody);
- visitForTest(node.condition, start, null);
- assembler.bind(end);
- }
-
- LocalValue initializeLocal(LocalElement element, Expression initializer) {
- int slot = assembler.stackSize;
- if (initializer != null) {
- // TODO(ahe): If we can move this to the caller, then we don't need
- // functionDeclarations.
- visitForValue(initializer);
- } else {
- generateEmptyInitializer(element.node);
- }
- LocalValue value = createLocalValueFor(element, slot: slot);
- value.initialize(assembler);
- pushVariableDeclaration(value);
- blockLocals.add(element);
- return value;
- }
-
- void generateEmptyInitializer(Node node) {
- assembler.loadLiteralNull();
- }
-
- void visitVariableDefinitions(VariableDefinitions node) {
- for (Node definition in node.definitions) {
- LocalVariableElement element = elements[definition];
- initializeLocal(element, element.initializer);
- }
- }
-
- void visitFunctionDeclaration(FunctionDeclaration node) {
- FunctionExpression function = node.function;
- functionDeclarations.add(function);
- initializeLocal(elements[function], function);
- }
-
- void visitSwitchStatement(SwitchStatement node) {
- BytecodeLabel end = new BytecodeLabel();
-
- visitForValue(node.expression);
-
- jumpInfo[node] = new JumpInfo(assembler.stackSize, null, end);
-
- // Install cross-case jump targets.
- for (SwitchCase switchCase in node.cases) {
- BytecodeLabel continueLabel = new BytecodeLabel();
- jumpInfo[switchCase] = new JumpInfo(
- assembler.stackSize,
- continueLabel,
- null);
- }
-
- for (SwitchCase switchCase in node.cases) {
- BytecodeLabel ifTrue = jumpInfo[switchCase].continueLabel;
- BytecodeLabel next = new BytecodeLabel();
- if (!switchCase.isDefaultCase) {
- for (Node labelOrCaseMatch in switchCase.labelsAndCases) {
- CaseMatch caseMatch = labelOrCaseMatch.asCaseMatch();
- if (caseMatch == null) continue;
- generateSwitchCaseMatch(caseMatch, ifTrue);
- }
- assembler.branch(next);
- }
- assembler.bind(ifTrue);
- doStatements(switchCase.statements);
- assembler.branch(end);
- assembler.bind(next);
- }
-
- assembler.bind(end);
- assembler.pop();
- }
-
- void doCatchBlock(CatchBlock node, int exceptionSlot, BytecodeLabel end) {
- BytecodeLabel wrongType = new BytecodeLabel();
-
- TypeAnnotation type = node.type;
- if (type != null) {
- assembler.loadSlot(exceptionSlot);
- callIsSelector(type, elements.getType(type), type);
- assembler.branchIfFalse(wrongType);
- }
-
- List<Element> locals = <Element>[];
- Node exception = node.exception;
- if (exception != null) {
- LocalVariableElement element = elements[exception];
- LocalValue value = createLocalValueFor(element);
- assembler.loadSlot(exceptionSlot);
- value.initialize(assembler);
- pushVariableDeclaration(value);
- locals.add(element);
-
- Node trace = node.trace;
- if (trace != null) {
- LocalVariableElement element = elements[trace];
- LocalValue value = createLocalValueFor(element);
- assembler.loadLiteralNull();
- value.initialize(assembler);
- pushVariableDeclaration(value);
- // TODO(ajohnsen): Set trace.
- locals.add(element);
- }
- }
-
- node.block.accept(this);
-
- assembler.popMany(locals.length);
- for (Element e in locals) {
- popVariableDeclaration(e);
- }
-
- assembler.branch(end);
-
- assembler.bind(wrongType);
- }
-
- void visitTryStatement(TryStatement node) {
- BytecodeLabel end = new BytecodeLabel();
- BytecodeLabel finallyLabel = new BytecodeLabel();
- BytecodeLabel finallyReturnLabel = new BytecodeLabel();
-
- Block finallyBlock = node.finallyBlock;
- bool hasFinally = finallyBlock != null;
-
- // Reserve slot for exception.
- int exceptionSlot = assembler.stackSize;
- assembler.loadLiteralNull();
-
- jumpInfo[node] = new JumpInfo(assembler.stackSize, null, end);
-
- int startBytecodeSize = assembler.byteSize;
-
- tryBlockStack = tryBlockStack.prepend(
- new TryBlock(
- assembler.stackSize,
- hasFinally ? finallyLabel : null,
- hasFinally ? finallyReturnLabel: null));
-
- node.tryBlock.accept(this);
-
- // Go to end if no exceptions was thrown.
- assembler.branch(end);
- int endBytecodeSize = assembler.byteSize;
-
- // Add catch-frame to the assembler.
- assembler.addCatchFrameRange(startBytecodeSize, endBytecodeSize);
-
- for (Node catchBlock in node.catchBlocks) {
- doCatchBlock(catchBlock, exceptionSlot, end);
- }
-
- tryBlockStack = tryBlockStack.tail;
-
- if (hasFinally) {
- if (!node.catchBlocks.isEmpty) {
- assembler.addCatchFrameRange(endBytecodeSize, assembler.byteSize);
- }
- // Catch exception from catch blocks.
- assembler.subroutineCall(finallyLabel, finallyReturnLabel);
- }
-
- // The exception was not caught. Rethrow.
- generateThrow(node);
-
- assembler.bind(end);
-
- if (hasFinally) {
- BytecodeLabel done = new BytecodeLabel();
- assembler.subroutineCall(finallyLabel, finallyReturnLabel);
- assembler.branch(done);
-
- assembler.bind(finallyLabel);
- assembler.applyStackSizeFix(1);
- finallyBlock.accept(this);
- assembler.subroutineReturn(finallyReturnLabel);
-
- assembler.bind(done);
- }
-
- // Pop exception slot.
- assembler.pop();
- }
-
- void doUnresolved(String name) {
- var constString = context.backend.constantSystem.createString(
- new DartString.literal(name));
- context.markConstantUsed(constString);
- assembler.loadConst(functionBuilder.allocateConstant(constString));
- FunctionElement function = context.backend.fletchUnresolved;
- FletchFunctionBase base = requireFunction(function);
- int constId = functionBuilder.allocateConstantFromFunction(base.functionId);
- assembler.invokeStatic(constId, 1);
- }
-
- bool checkCompileError(Element element) {
- DiagnosticMessage message =
- context.compiler.elementsWithCompileTimeErrors[element];
- if (message != null) {
- doCompileError(message);
- return true;
- }
- return false;
- }
-
- String formatError(DiagnosticMessage diagnosticMessage) {
- return diagnosticMessage.message.computeMessage();
- }
-
-
- void doCompileError(DiagnosticMessage errorMessage) {
- FunctionElement function = context.backend.fletchCompileError;
- FletchFunctionBase base = requireFunction(function);
- int constId = functionBuilder.allocateConstantFromFunction(base.functionId);
- String errorString = formatError(errorMessage);
- ConstantValue stringConstant =
- context.backend.constantSystem.createString(
- new DartString.literal(errorString));
- int messageConstId = functionBuilder.allocateConstant(stringConstant);
- context.markConstantUsed(stringConstant);
- assembler.loadConst(messageConstId);
- registerInstantiatedClass(context.backend.stringImplementation);
- assembler.invokeStatic(constId, 1);
- }
-
- void visitUnresolvedInvoke(
- Send node,
- Element element,
- Node arguments,
- Selector selector,
- _) {
- if (!checkCompileError(element)) {
- doUnresolved(node.selector.toString());
- }
- applyVisitState();
- }
-
- void visitUnresolvedGet(
- Send node,
- Element element,
- _) {
- doUnresolved(node.selector.toString());
- applyVisitState();
- }
-
- void visitUnresolvedSet(
- Send node,
- Element element,
- Node rhs,
- _) {
- doUnresolved(node.selector.toString());
- applyVisitState();
- }
-
- void handleStaticFunctionIncompatibleInvoke(
- Send node,
- MethodElement function,
- NodeList arguments,
- CallStructure callStructure,
- _) {
- if (!checkCompileError(function)) {
- doUnresolved(function.name);
- }
- applyVisitState();
- }
-
- void internalError(Spannable spannable, String reason) {
- context.compiler.reporter.internalError(spannable, reason);
- }
-
- void generateUnimplementedError(Spannable spannable, String reason) {
- context.backend.generateUnimplementedError(
- spannable,
- reason,
- functionBuilder);
- }
-
- String toString() => "FunctionCompiler(${element.name})";
-
- void handleFinalStaticFieldSet(
- SendSet node,
- FieldElement field,
- Node rhs,
- _) {
- generateUnimplementedError(
- node, "[handleFinalStaticFieldSet] isn't implemented.");
- applyVisitState();
- }
-
- void handleImmutableLocalSet(
- SendSet node,
- LocalElement element,
- Node rhs,
- _) {
- generateUnimplementedError(
- node, "[handleImmutableLocalSet] isn't implemented.");
- applyVisitState();
- }
-
- void handleStaticSetterGet(
- Send node,
- FunctionElement setter,
- _) {
- generateUnimplementedError(
- node, "[handleStaticSetterGet] isn't implemented.");
- applyVisitState();
- }
-
- void handleStaticSetterInvoke(
- Send node,
- FunctionElement setter,
- NodeList arguments,
- CallStructure callStructure,
- _) {
- generateUnimplementedError(
- node, "[handleStaticSetterInvoke] isn't implemented.");
- applyVisitState();
- }
-
- void handleStaticGetterSet(
- Send node,
- FunctionElement getter,
- Node rhs,
- _) {
- generateUnimplementedError(
- node, "[handleStaticGetterSet] isn't implemented.");
- applyVisitState();
- }
-
- void handleStaticFunctionSet(
- SendSet node,
- MethodElement function,
- Node rhs,
- _) {
- generateUnimplementedError(
- node, "[handleStaticFunctionSet] isn't implemented.");
- applyVisitState();
- }
-
- @override
- void bulkHandleSetIfNull(Node node, _) {
- generateUnimplementedError(
- node, "[bulkHandleSetIfNull] isn't implemented.");
- applyVisitState();
- }
-
- void previsitDeferredAccess(Send node, PrefixElement prefix, _) {
- // We don't support deferred access, so nothing to do for now.
- }
-
- void bulkHandleNode(Node node, String msg, _) {
- generateUnimplementedError(node, msg.replaceAll('#', node.toString()));
- applyVisitState();
- }
-
- void visitNode(Node node) {
- internalError(node, "[visitNode] isn't implemented.");
- }
-
- void apply(Node node, _) {
- internalError(node, "[apply] isn't implemented.");
- }
-
- void applyInitializers(FunctionExpression initializers, _) {
- internalError(initializers, "[applyInitializers] isn't implemented.");
- }
-
- void applyParameters(NodeList parameters, _) {
- internalError(parameters, "[applyParameters] isn't implemented.");
- }
-}
-
-abstract class FletchRegistryMixin {
- FletchRegistry get registry;
- FletchContext get context;
-
- void registerDynamicUse(Selector selector) {
- registry.registerDynamicUse(selector);
- }
-
- void registerStaticUse(StaticUse staticUse) {
- registry.registerStaticUse(staticUse);
- }
-
- void registerInstantiatedClass(ClassElement klass) {
- registry.registerInstantiatedClass(klass);
- }
-
- void registerIsCheck(DartType type) {
- registry.registerIsCheck(type);
- }
-
- void registerLocalInvoke(LocalElement element, Selector selector) {
- registry.registerLocalInvoke(element, selector);
- }
-
- void registerClosurization(FunctionElement element, ClosureKind kind) {
- if (kind == ClosureKind.localFunction) {
- // TODO(ahe): Get rid of the call to [registerStaticUse]. It is
- // currently needed to ensure that local function expression closures are
- // compiled correctly. For example, `[() {}].last()`, notice that `last`
- // is a getter. This happens for both named and unnamed.
- registerStaticUse(new StaticUse.foreignUse(element));
- }
- registry.registerClosurization(element, kind);
- }
-
- int compileLazyFieldInitializer(FieldElement field) {
- return context.backend.compileLazyFieldInitializer(field, registry);
- }
-}
« 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