| Index: runtime/vm/ast_transformer.cc
|
| diff --git a/runtime/vm/ast_transformer.cc b/runtime/vm/ast_transformer.cc
|
| index 6ef865f0e246a4e88846d46a2240b562078efbf2..0f00369f64adc47a079c7c5b722f7ce411d0137d 100644
|
| --- a/runtime/vm/ast_transformer.cc
|
| +++ b/runtime/vm/ast_transformer.cc
|
| @@ -42,6 +42,19 @@ void AwaitTransformer::Visit##BaseName##Node(BaseName##Node* node) { \
|
| FOR_EACH_UNREACHABLE_NODE(DEFINE_UNREACHABLE)
|
| #undef DEFINE_UNREACHABLE
|
|
|
| +AwaitTransformer::AwaitTransformer(SequenceNode* preamble,
|
| + const Library& library,
|
| + ParsedFunction* const parsed_function,
|
| + LocalScope* function_top)
|
| + : preamble_(preamble),
|
| + temp_cnt_(0),
|
| + library_(library),
|
| + parsed_function_(parsed_function),
|
| + function_top_(function_top),
|
| + isolate_(Isolate::Current()) {
|
| + ASSERT(function_top_ != NULL);
|
| +}
|
| +
|
|
|
| AstNode* AwaitTransformer::Transform(AstNode* expr) {
|
| expr->Visit(this);
|
| @@ -55,19 +68,29 @@ LocalVariable* AwaitTransformer::EnsureCurrentTempVar() {
|
| I, String::NewFormatted("%s%d", await_temp_prefix, temp_cnt_));
|
| const String& symbol = String::ZoneHandle(I, Symbols::New(cnt_str));
|
| ASSERT(!symbol.IsNull());
|
| - LocalVariable* await_tmp =
|
| - parsed_function_->await_temps_scope()->LookupVariable(symbol, false);
|
| + // Look up the variable through the preamble scope.
|
| + LocalVariable* await_tmp = preamble_->scope()->LookupVariable(symbol, false);
|
| if (await_tmp == NULL) {
|
| - await_tmp = new(I) LocalVariable(
|
| - Scanner::kNoSourcePos,
|
| - symbol,
|
| - Type::ZoneHandle(I, Type::DynamicType()));
|
| - parsed_function_->await_temps_scope()->AddVariable(await_tmp);
|
| + // If we need a new temp variable, we add it to the function's top scope.
|
| + await_tmp = new (I) LocalVariable(
|
| + Scanner::kNoSourcePos, symbol, Type::ZoneHandle(Type::DynamicType()));
|
| + function_top_->AddVariable(await_tmp);
|
| + // After adding it to the top scope, we can look it up from the preamble.
|
| + // The following call includes an ASSERT check.
|
| + await_tmp = GetVariableInScope(preamble_->scope(), symbol);
|
| }
|
| return await_tmp;
|
| }
|
|
|
|
|
| +LocalVariable* AwaitTransformer::GetVariableInScope(LocalScope* scope,
|
| + const String& symbol) {
|
| + LocalVariable* var = scope->LookupVariable(symbol, false);
|
| + ASSERT(var != NULL);
|
| + return var;
|
| +}
|
| +
|
| +
|
| LocalVariable* AwaitTransformer::AddToPreambleNewTempVar(AstNode* node) {
|
| LocalVariable* tmp_var = EnsureCurrentTempVar();
|
| preamble_->Add(new(I) StoreLocalNode(Scanner::kNoSourcePos, tmp_var, node));
|
| @@ -100,23 +123,24 @@ void AwaitTransformer::VisitAwaitNode(AwaitNode* node) {
|
| // :saved_try_ctx_var = :await_saved_try_ctx_var_y;
|
| // :await_temp_var_(X+1) = :result_param;
|
|
|
| - LocalVariable* async_op = preamble_->scope()->LookupVariable(
|
| - Symbols::AsyncOperation(), false);
|
| - ASSERT(async_op != NULL);
|
| - LocalVariable* result_param = preamble_->scope()->LookupVariable(
|
| - Symbols::AsyncOperationParam(), false);
|
| - ASSERT(result_param != NULL);
|
| + LocalVariable* async_op = GetVariableInScope(
|
| + preamble_->scope(), Symbols::AsyncOperation());
|
| + LocalVariable* result_param = GetVariableInScope(
|
| + preamble_->scope(), Symbols::AsyncOperationParam());
|
|
|
| node->expr()->Visit(this);
|
| preamble_->Add(new(I) StoreLocalNode(
|
| Scanner::kNoSourcePos, result_param, result_));
|
| LoadLocalNode* load_result_param = new(I) LoadLocalNode(
|
| Scanner::kNoSourcePos, result_param);
|
| - SequenceNode* is_future_branch = new(I) SequenceNode(
|
| - Scanner::kNoSourcePos, preamble_->scope());
|
| - AwaitMarkerNode* await_marker =
|
| - new(I) AwaitMarkerNode(AwaitMarkerNode::kNewContinuationState);
|
| - await_marker->set_scope(preamble_->scope());
|
| + LocalScope* is_future_scope = ChainNewScope(preamble_->scope());
|
| + SequenceNode* is_future_branch = new (I) SequenceNode(
|
| + Scanner::kNoSourcePos, is_future_scope);
|
| + AwaitMarkerNode* await_marker = new (I) AwaitMarkerNode(
|
| + AwaitMarkerNode::kNewContinuationState);
|
| + await_marker->set_scope(is_future_scope);
|
| + GetVariableInScope(is_future_scope, Symbols::AwaitJumpVar());
|
| + GetVariableInScope(is_future_scope, Symbols::AwaitContextVar());
|
| is_future_branch->Add(await_marker);
|
| ArgumentListNode* args = new(I) ArgumentListNode(Scanner::kNoSourcePos);
|
| args->Add(new(I) LoadLocalNode(Scanner::kNoSourcePos, async_op));
|
| @@ -141,14 +165,18 @@ void AwaitTransformer::VisitAwaitNode(AwaitNode* node) {
|
| NULL));
|
| preamble_->Add(new (I) AwaitMarkerNode(
|
| AwaitMarkerNode::kTargetForContinuation));
|
| +
|
| // If this expression is part of a try block, also append the code for
|
| // restoring the saved try context that lives on the stack.
|
| - if (parsed_function_->saved_try_ctx() != NULL) {
|
| + const String& async_saved_try_ctx_name =
|
| + String::Handle(I, parsed_function_->async_saved_try_ctx_name());
|
| + if (!async_saved_try_ctx_name.IsNull()) {
|
| + LocalVariable* async_saved_try_ctx =
|
| + GetVariableInScope(preamble_->scope(), async_saved_try_ctx_name);
|
| preamble_->Add(new (I) StoreLocalNode(
|
| Scanner::kNoSourcePos,
|
| parsed_function_->saved_try_ctx(),
|
| - new (I) LoadLocalNode(
|
| - Scanner::kNoSourcePos, parsed_function_->async_saved_try_ctx())));
|
| + new (I) LoadLocalNode(Scanner::kNoSourcePos, async_saved_try_ctx)));
|
| }
|
|
|
| LocalVariable* result = AddToPreambleNewTempVar(new(I) LoadLocalNode(
|
| @@ -179,8 +207,8 @@ AstNode* AwaitTransformer::LazyTransform(const Token::Kind logical_op,
|
| AstNode* result = NULL;
|
| const Token::Kind compare_logical_op = (logical_op == Token::kAND) ?
|
| Token::kEQ : Token::kNE;
|
| - SequenceNode* eval = new(I) SequenceNode(
|
| - Scanner::kNoSourcePos, preamble_->scope());
|
| + SequenceNode* eval = new (I) SequenceNode(
|
| + Scanner::kNoSourcePos, ChainNewScope(preamble_->scope()));
|
| SequenceNode* saved_preamble = preamble_;
|
| preamble_ = eval;
|
| result = Transform(right);
|
| @@ -199,6 +227,12 @@ AstNode* AwaitTransformer::LazyTransform(const Token::Kind logical_op,
|
| }
|
|
|
|
|
| +LocalScope* AwaitTransformer::ChainNewScope(LocalScope* parent) {
|
| + return new (I) LocalScope(
|
| + parent, parent->function_level(), parent->loop_level());
|
| +}
|
| +
|
| +
|
| void AwaitTransformer::VisitBinaryOpNode(BinaryOpNode* node) {
|
| node->left()->Visit(this);
|
| AstNode* new_left = result_;
|
| @@ -263,13 +297,13 @@ void AwaitTransformer::VisitUnaryOpNode(UnaryOpNode* node) {
|
| //
|
| void AwaitTransformer::VisitConditionalExprNode(ConditionalExprNode* node) {
|
| AstNode* new_condition = Transform(node->condition());
|
| - SequenceNode* new_true = new(I) SequenceNode(
|
| - Scanner::kNoSourcePos, preamble_->scope());
|
| + SequenceNode* new_true = new (I) SequenceNode(
|
| + Scanner::kNoSourcePos, ChainNewScope(preamble_->scope()));
|
| SequenceNode* saved_preamble = preamble_;
|
| preamble_ = new_true;
|
| AstNode* new_true_result = Transform(node->true_expr());
|
| - SequenceNode* new_false = new(I) SequenceNode(
|
| - Scanner::kNoSourcePos, preamble_->scope());
|
| + SequenceNode* new_false = new (I) SequenceNode(
|
| + Scanner::kNoSourcePos, ChainNewScope(preamble_->scope()));
|
| preamble_ = new_false;
|
| AstNode* new_false_result = Transform(node->false_expr());
|
| preamble_ = saved_preamble;
|
|
|