[vm/compiler] first vm implementation of block expression
Rationale:
Implementation of control-flow collections is
done through the notion of block expressions.
This is a first implementation to get this
working. It takes a few shortcuts (like disabling
OSR inside block expressions for now) that may be
refined later.
https://github.com/dart-lang/language/issues/78
https://github.com/dart-lang/language/issues/47
Change-Id: I966bf10942075052fcfd9bac00298a179efc551b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/94441
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
diff --git a/pkg/vm/lib/transformations/type_flow/summary_collector.dart b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
index f4e50e7..23f8d8b 100644
--- a/pkg/vm/lib/transformations/type_flow/summary_collector.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
@@ -870,6 +870,12 @@
}
@override
+ TypeExpr visitBlockExpression(BlockExpression node) {
+ _visit(node.body);
+ return _visit(node.value);
+ }
+
+ @override
TypeExpr visitListLiteral(ListLiteral node) {
node.expressions.forEach(_visit);
Class concreteClass =
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 7a3404e..ac67edd 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -1338,10 +1338,8 @@
return BuildFunctionExpression();
case kLet:
return BuildLet(position);
- case kBlockExpression: {
- UNIMPLEMENTED();
- break;
- }
+ case kBlockExpression:
+ return BuildBlockExpression();
case kBigIntLiteral:
return BuildBigIntLiteral(position);
case kStringLiteral:
@@ -1484,6 +1482,18 @@
--flow_graph_builder_->try_depth_;
}
+intptr_t StreamingFlowGraphBuilder::block_expression_depth() {
+ return flow_graph_builder_->block_expression_depth_;
+}
+
+void StreamingFlowGraphBuilder::block_expression_depth_inc() {
+ ++flow_graph_builder_->block_expression_depth_;
+}
+
+void StreamingFlowGraphBuilder::block_expression_depth_dec() {
+ --flow_graph_builder_->block_expression_depth_;
+}
+
intptr_t StreamingFlowGraphBuilder::CurrentTryIndex() {
return flow_graph_builder_->CurrentTryIndex();
}
@@ -1838,7 +1848,7 @@
const intptr_t saved_context_depth = B->context_depth_;
const ProgramState state(B->breakable_block_, B->switch_block_,
B->loop_depth_, B->for_in_depth_, B->try_depth_,
- B->catch_depth_);
+ B->catch_depth_, B->block_expression_depth_);
Fragment instructions;
@@ -3798,6 +3808,24 @@
return instructions;
}
+Fragment StreamingFlowGraphBuilder::BuildBlockExpression() {
+ block_expression_depth_inc();
+ const intptr_t offset = ReaderOffset() - 1; // Include the tag.
+
+ Fragment instructions;
+
+ instructions += EnterScope(offset);
+ const intptr_t list_length = ReadListLength(); // read number of statements.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ instructions += BuildStatement(); // read ith statement.
+ }
+ instructions += BuildExpression(); // read expression (inside scope).
+ instructions += ExitScope(offset);
+
+ block_expression_depth_dec();
+ return instructions;
+}
+
Fragment StreamingFlowGraphBuilder::BuildBigIntLiteral(
TokenPosition* position) {
if (position != NULL) *position = TokenPosition::kNoSource;
@@ -4134,6 +4162,7 @@
}
Fragment StreamingFlowGraphBuilder::BuildWhileStatement() {
+ ASSERT(block_expression_depth() == 0); // no while in block-expr
loop_depth_inc();
const TokenPosition position = ReadPosition(); // read position.
TestFragment condition = TranslateConditionForControl(); // read condition.
@@ -4161,6 +4190,7 @@
}
Fragment StreamingFlowGraphBuilder::BuildDoStatement() {
+ ASSERT(block_expression_depth() == 0); // no do-while in block-expr
loop_depth_inc();
const TokenPosition position = ReadPosition(); // read position.
Fragment body = BuildStatement(); // read body.
@@ -4243,7 +4273,11 @@
body += Goto(join);
Fragment loop(join);
- loop += CheckStackOverflow(position);
+
+ // Avoid OSR point inside block-expressions.
+ // TODO(ajcbik): make sure OSR works inside BE too
+ if (block_expression_depth() == 0) loop += CheckStackOverflow(position);
+
if (condition.entry != nullptr) {
loop <<= condition.entry;
} else {
@@ -4316,7 +4350,11 @@
body += Goto(join);
Fragment loop(join);
- loop += CheckStackOverflow(position);
+
+ // Avoid OSR point inside block-expressions.
+ // TODO(ajcbik): make sure OSR works inside BE too
+ if (block_expression_depth() == 0) loop += CheckStackOverflow(position);
+
loop += condition;
} else {
instructions += condition;
@@ -4621,6 +4659,7 @@
}
Fragment StreamingFlowGraphBuilder::BuildTryCatch() {
+ ASSERT(block_expression_depth() == 0); // no try-catch in block-expr
InlineBailout("kernel::FlowgraphBuilder::VisitTryCatch");
intptr_t try_handler_index = AllocateTryIndex();
@@ -4750,6 +4789,7 @@
}
Fragment StreamingFlowGraphBuilder::BuildTryFinally() {
+ ASSERT(block_expression_depth() == 0); // no try-finally in block-expr
// Note on streaming:
// We only stream this TryFinally if we can stream everything inside it,
// so creating a "TryFinallyBlock" with a kernel binary offset instead of an
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
index b12d4e3..b554501 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
@@ -112,6 +112,9 @@
void catch_depth_dec();
void try_depth_inc();
void try_depth_dec();
+ intptr_t block_expression_depth();
+ void block_expression_depth_inc();
+ void block_expression_depth_dec();
intptr_t CurrentTryIndex();
intptr_t AllocateTryIndex();
LocalVariable* CurrentException();
@@ -314,6 +317,7 @@
Fragment BuildMapLiteral(bool is_const, TokenPosition* position);
Fragment BuildFunctionExpression();
Fragment BuildLet(TokenPosition* position);
+ Fragment BuildBlockExpression();
Fragment BuildBigIntLiteral(TokenPosition* position);
Fragment BuildStringLiteral(TokenPosition* position);
Fragment BuildIntLiteral(uint8_t payload, TokenPosition* position);
diff --git a/runtime/vm/compiler/frontend/kernel_fingerprints.cc b/runtime/vm/compiler/frontend/kernel_fingerprints.cc
index c9cdd92..1a88f1ba 100644
--- a/runtime/vm/compiler/frontend/kernel_fingerprints.cc
+++ b/runtime/vm/compiler/frontend/kernel_fingerprints.cc
@@ -512,10 +512,10 @@
CalculateVariableDeclarationFingerprint(); // read variable declaration.
CalculateExpressionFingerprint(); // read expression.
return;
- case kBlockExpression: {
- UNIMPLEMENTED();
+ case kBlockExpression:
+ CalculateStatementListFingerprint();
+ CalculateExpressionFingerprint(); // read expression.
return;
- }
case kInstantiation:
CalculateExpressionFingerprint(); // read expression.
CalculateListOfDartTypesFingerprint(); // read type arguments.
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 9da71ef..7fa7051 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -54,6 +54,7 @@
try_depth_(0),
catch_depth_(0),
for_in_depth_(0),
+ block_expression_depth_(0),
graph_entry_(NULL),
scopes_(NULL),
breakable_block_(NULL),
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.h b/runtime/vm/compiler/frontend/kernel_to_il.h
index a2cb7ca..f1aeb23 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.h
+++ b/runtime/vm/compiler/frontend/kernel_to_il.h
@@ -283,6 +283,7 @@
intptr_t try_depth_;
intptr_t catch_depth_;
intptr_t for_in_depth_;
+ intptr_t block_expression_depth_;
GraphEntryInstr* graph_entry_;
@@ -355,13 +356,15 @@
intptr_t loop_depth,
intptr_t for_in_depth,
intptr_t try_depth,
- intptr_t catch_depth)
+ intptr_t catch_depth,
+ intptr_t block_expression_depth)
: breakable_block_(breakable_block),
switch_block_(switch_block),
loop_depth_(loop_depth),
for_in_depth_(for_in_depth),
try_depth_(try_depth),
- catch_depth_(catch_depth) {}
+ catch_depth_(catch_depth),
+ block_expression_depth_(block_expression_depth) {}
void assignTo(FlowGraphBuilder* builder) const {
builder->breakable_block_ = breakable_block_;
@@ -370,6 +373,7 @@
builder->for_in_depth_ = for_in_depth_;
builder->try_depth_ = try_depth_;
builder->catch_depth_ = catch_depth_;
+ builder->block_expression_depth_ = block_expression_depth_;
}
private:
@@ -379,6 +383,7 @@
const intptr_t for_in_depth_;
const intptr_t try_depth_;
const intptr_t catch_depth_;
+ const intptr_t block_expression_depth_;
};
class SwitchBlock {
@@ -505,7 +510,8 @@
builder_->loop_depth_,
builder_->for_in_depth_,
builder_->try_depth_ - 1,
- builder_->catch_depth_) {
+ builder_->catch_depth_,
+ builder_->block_expression_depth_) {
builder_->try_finally_block_ = this;
}
~TryFinallyBlock() { builder_->try_finally_block_ = outer_; }
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index d0b79b9..ebd4ed7 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -2262,10 +2262,10 @@
SkipVariableDeclaration(); // read variable declaration.
SkipExpression(); // read expression.
return;
- case kBlockExpression: {
- UNIMPLEMENTED();
+ case kBlockExpression:
+ SkipStatementList();
+ SkipExpression(); // read expression.
return;
- }
case kInstantiation:
SkipExpression(); // read expression.
SkipListOfDartTypes(); // read type arguments.
diff --git a/runtime/vm/compiler/frontend/scope_builder.cc b/runtime/vm/compiler/frontend/scope_builder.cc
index 7ab81b7..8ea2448 100644
--- a/runtime/vm/compiler/frontend/scope_builder.cc
+++ b/runtime/vm/compiler/frontend/scope_builder.cc
@@ -840,7 +840,19 @@
return;
}
case kBlockExpression: {
- UNIMPLEMENTED();
+ PositionScope scope(&helper_.reader_);
+ intptr_t offset = helper_.ReaderOffset() - 1; // -1 to include tag byte.
+
+ EnterScope(offset);
+
+ intptr_t list_length =
+ helper_.ReadListLength(); // read number of statements.
+ for (intptr_t i = 0; i < list_length; ++i) {
+ VisitStatement(); // read ith statement.
+ }
+ VisitExpression(); // read expression.
+
+ ExitScope(helper_.reader_.min_position(), helper_.reader_.max_position());
return;
}
case kBigIntLiteral: