9ab86da19c
There are four operations that work on Vectors: Vector creation, looking up an item in a Vector, assigning a value to an item in a Vector, and copying a Vector. The first three operations are allowed to only use integer literals as number operands (length for Vector creation, index for item lookup and assignment). Corresponding AST nodes are created for these operations. Vectors are used to represent contexts in Closure Conversion. The parent context is stored as item 0 in its children contexts. The "golden" tests for this transformation are adjusted accordingly. The support for Vectors is added to ast-to-text, ast-to-binary, and binary-to-ast transformations. R=asgerf@google.com, kmillikin@google.com Review-Url: https://codereview.chromium.org/2767773004 .
121 lines
4.1 KiB
Dart
121 lines
4.1 KiB
Dart
// Copyright (c) 2017, the Dart 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 file.
|
|
|
|
library kernel.transformations.closure.rewriter;
|
|
|
|
import '../../ast.dart';
|
|
import 'converter.dart' show ClosureConverter;
|
|
|
|
/// Used by the [Context] to initialize and update the context variable
|
|
/// used to capture the variables closed over by functions.
|
|
abstract class AstRewriter {
|
|
/// The declared variable that holds the context.
|
|
VariableDeclaration contextDeclaration;
|
|
|
|
/// Expression that is used to initialize the vector representing the context.
|
|
/// It's [length] field is modified by the [extend] operation
|
|
VectorCreation vectorCreation;
|
|
|
|
/// Creates a new [AstRewriter] for a (nested) [Block].
|
|
BlockRewriter forNestedBlock(Block block);
|
|
|
|
/// Inserts an allocation of a context and initializes [contextDeclaration]
|
|
/// and [vectorCreation].
|
|
void insertContextDeclaration(Expression accessParent);
|
|
|
|
/// Inserts an expression or statement that extends the context.
|
|
void insertExtendContext(VectorSet extender);
|
|
|
|
void _createDeclaration() {
|
|
assert(contextDeclaration == null && vectorCreation == null);
|
|
|
|
// Context size is set to 1 initially, because the 0-th element of it works
|
|
// as a link to the parent context.
|
|
vectorCreation = new VectorCreation(1);
|
|
contextDeclaration = new VariableDeclaration.forValue(vectorCreation,
|
|
type: new VectorType());
|
|
contextDeclaration.name = "#context";
|
|
}
|
|
}
|
|
|
|
/// Adds a local variable for the context and adds update [Statement]s to the
|
|
/// current block.
|
|
class BlockRewriter extends AstRewriter {
|
|
Block _currentBlock;
|
|
int _insertionIndex;
|
|
|
|
BlockRewriter(this._currentBlock) : _insertionIndex = 0;
|
|
|
|
BlockRewriter forNestedBlock(Block block) {
|
|
return _currentBlock != block ? new BlockRewriter(block) : this;
|
|
}
|
|
|
|
void transformStatements(Block block, ClosureConverter converter) {
|
|
while (_insertionIndex < _currentBlock.statements.length) {
|
|
var original = _currentBlock.statements[_insertionIndex];
|
|
var transformed = original.accept(converter);
|
|
assert(_currentBlock.statements[_insertionIndex] == original);
|
|
if (transformed == null) {
|
|
_currentBlock.statements.removeAt(_insertionIndex);
|
|
} else {
|
|
_currentBlock.statements[_insertionIndex++] = transformed;
|
|
transformed.parent = _currentBlock;
|
|
}
|
|
}
|
|
}
|
|
|
|
void _insertStatement(Statement statement) {
|
|
_currentBlock.statements.insert(_insertionIndex++, statement);
|
|
statement.parent = _currentBlock;
|
|
}
|
|
|
|
void insertContextDeclaration(Expression accessParent) {
|
|
_createDeclaration();
|
|
_insertStatement(contextDeclaration);
|
|
if (accessParent is! NullLiteral) {
|
|
// Index 0 of a context always points to the parent.
|
|
_insertStatement(new ExpressionStatement(
|
|
new VectorSet(new VariableGet(contextDeclaration), 0, accessParent)));
|
|
}
|
|
}
|
|
|
|
void insertExtendContext(VectorSet extender) {
|
|
_insertStatement(new ExpressionStatement(extender));
|
|
}
|
|
}
|
|
|
|
/// Creates and updates the context as [Let] bindings around the initializer
|
|
/// expression.
|
|
class InitializerRewriter extends AstRewriter {
|
|
final Expression initializingExpression;
|
|
|
|
InitializerRewriter(this.initializingExpression) {
|
|
assert(initializingExpression.parent is FieldInitializer);
|
|
}
|
|
|
|
@override
|
|
BlockRewriter forNestedBlock(Block block) {
|
|
return new BlockRewriter(block);
|
|
}
|
|
|
|
@override
|
|
void insertContextDeclaration(Expression accessParent) {
|
|
_createDeclaration();
|
|
FieldInitializer parent = initializingExpression.parent;
|
|
Let binding = new Let(contextDeclaration, initializingExpression);
|
|
initializingExpression.parent = binding;
|
|
parent.value = binding;
|
|
binding.parent = parent;
|
|
}
|
|
|
|
@override
|
|
void insertExtendContext(VectorSet extender) {
|
|
Let parent = initializingExpression.parent;
|
|
Let binding = new Let(new VariableDeclaration(null, initializer: extender),
|
|
initializingExpression);
|
|
parent.body = binding;
|
|
binding.parent = parent;
|
|
}
|
|
}
|