| Index: runtime/vm/parser.cc
|
| ===================================================================
|
| --- runtime/vm/parser.cc (revision 44249)
|
| +++ runtime/vm/parser.cc (working copy)
|
| @@ -279,16 +279,16 @@
|
| // Class which describes an inlined finally block which is used to generate
|
| // inlined code for the finally blocks when there is an exit from a try
|
| // block using 'return', 'break' or 'continue'.
|
| -class Parser::TryBlocks : public ZoneAllocated {
|
| +class Parser::TryStack : public ZoneAllocated {
|
| public:
|
| - TryBlocks(Block* try_block, TryBlocks* outer_try_block, intptr_t try_index)
|
| + TryStack(Block* try_block, TryStack* outer_try, intptr_t try_index)
|
| : try_block_(try_block),
|
| inlined_finally_nodes_(),
|
| - outer_try_block_(outer_try_block),
|
| + outer_try_(outer_try),
|
| try_index_(try_index),
|
| inside_catch_(false) { }
|
|
|
| - TryBlocks* outer_try_block() const { return outer_try_block_; }
|
| + TryStack* outer_try() const { return outer_try_; }
|
| Block* try_block() const { return try_block_; }
|
| intptr_t try_index() const { return try_index_; }
|
| bool inside_catch() const { return inside_catch_; }
|
| @@ -305,15 +305,15 @@
|
| private:
|
| Block* try_block_;
|
| GrowableArray<AstNode*> inlined_finally_nodes_;
|
| - TryBlocks* outer_try_block_;
|
| + TryStack* outer_try_;
|
| const intptr_t try_index_;
|
| bool inside_catch_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(TryBlocks);
|
| + DISALLOW_COPY_AND_ASSIGN(TryStack);
|
| };
|
|
|
|
|
| -void Parser::TryBlocks::AddNodeForFinallyInlining(AstNode* node) {
|
| +void Parser::TryStack::AddNodeForFinallyInlining(AstNode* node) {
|
| inlined_finally_nodes_.Add(node);
|
| }
|
|
|
| @@ -335,7 +335,7 @@
|
| literal_token_(LiteralToken::Handle(zone())),
|
| current_class_(Class::Handle(zone())),
|
| library_(Library::Handle(zone(), library.raw())),
|
| - try_blocks_list_(NULL),
|
| + try_stack_(NULL),
|
| last_used_try_index_(0),
|
| unregister_pending_function_(false),
|
| async_temp_scope_(NULL),
|
| @@ -368,7 +368,7 @@
|
| library_(Library::Handle(zone(), Class::Handle(
|
| zone(),
|
| parsed_function->function().origin()).library())),
|
| - try_blocks_list_(NULL),
|
| + try_stack_(NULL),
|
| last_used_try_index_(0),
|
| unregister_pending_function_(false),
|
| async_temp_scope_(NULL),
|
| @@ -5982,8 +5982,8 @@
|
| TRACE_PARSER("CloseAsyncGeneratorTryBlock");
|
| // The generated try-catch-finally that wraps the async generator function
|
| // body is the outermost try statement.
|
| - ASSERT(try_blocks_list_ != NULL);
|
| - ASSERT(try_blocks_list_->outer_try_block() == NULL);
|
| + ASSERT(try_stack_ != NULL);
|
| + ASSERT(try_stack_->outer_try() == NULL);
|
| // We only get here when parsing an async generator body.
|
| ASSERT(innermost_function().IsAsyncGenClosure());
|
|
|
| @@ -5992,7 +5992,7 @@
|
| // The try-block (closure body code) has been parsed. We are now
|
| // generating the code for the catch block.
|
| LocalScope* try_scope = current_block_->scope;
|
| - try_blocks_list_->enter_catch();
|
| + try_stack_->enter_catch();
|
| OpenBlock(); // Catch handler list.
|
| OpenBlock(); // Catch block.
|
|
|
| @@ -6073,8 +6073,8 @@
|
| current_block_->statements->Add(catch_block);
|
| SequenceNode* catch_handler_list = CloseBlock();
|
|
|
| - TryBlocks* try_block = PopTryBlock();
|
| - ASSERT(try_blocks_list_ == NULL); // We popped the outermost try block.
|
| + TryStack* try_statement = PopTry();
|
| + ASSERT(try_stack_ == NULL); // We popped the outermost try block.
|
|
|
| // Finally block: closing the stream and returning. (Note: the return
|
| // is necessary otherwise the back-end will append a rethrow of the
|
| @@ -6098,7 +6098,7 @@
|
| current_block_->statements->Add(return_node);
|
|
|
| finally_clause = CloseBlock();
|
| - AstNode* node_to_inline = try_block->GetNodeToInlineFinally(node_index);
|
| + AstNode* node_to_inline = try_statement->GetNodeToInlineFinally(node_index);
|
| if (node_to_inline != NULL) {
|
| InlinedFinallyNode* node =
|
| new(Z) InlinedFinallyNode(try_end_pos,
|
| @@ -6128,7 +6128,7 @@
|
| AllocateTryIndex(),
|
| true);
|
|
|
| - const intptr_t try_index = try_block->try_index();
|
| + const intptr_t try_index = try_statement->try_index();
|
|
|
| AstNode* try_catch_node =
|
| new(Z) TryCatchNode(Scanner::kNoSourcePos,
|
| @@ -6144,12 +6144,12 @@
|
|
|
| SequenceNode* Parser::CloseAsyncTryBlock(SequenceNode* try_block) {
|
| // This is the outermost try-catch of the function.
|
| - ASSERT(try_blocks_list_ != NULL);
|
| - ASSERT(try_blocks_list_->outer_try_block() == NULL);
|
| + ASSERT(try_stack_ != NULL);
|
| + ASSERT(try_stack_->outer_try() == NULL);
|
| ASSERT(innermost_function().IsAsyncClosure());
|
| LocalScope* try_scope = current_block_->scope;
|
|
|
| - try_blocks_list_->enter_catch();
|
| + try_stack_->enter_catch();
|
|
|
| OpenBlock(); // Catch handler list.
|
| OpenBlock(); // Catch block.
|
| @@ -6234,8 +6234,8 @@
|
| handler_types.SetLength(0);
|
| handler_types.Add(*exception_param.type);
|
|
|
| - TryBlocks* inner_try_block = PopTryBlock();
|
| - const intptr_t try_index = inner_try_block->try_index();
|
| + TryStack* try_statement = PopTry();
|
| + const intptr_t try_index = try_statement->try_index();
|
|
|
| CatchClauseNode* catch_clause = new (Z) CatchClauseNode(
|
| Scanner::kNoSourcePos,
|
| @@ -6280,8 +6280,8 @@
|
| // Open the try block.
|
| OpenBlock();
|
| // This is the outermost try-catch in the function.
|
| - ASSERT(try_blocks_list_ == NULL);
|
| - PushTryBlock(current_block_);
|
| + ASSERT(try_stack_ == NULL);
|
| + PushTry(current_block_);
|
|
|
| SetupSavedTryContext(context_var);
|
| }
|
| @@ -8153,20 +8153,18 @@
|
|
|
| // If the await or yield being parsed is in a try block, the continuation code
|
| // needs to restore the corresponding stack-based variable :saved_try_ctx_var,
|
| -// and possibly the stack-based variable :saved_try_ctx_var of the outer try
|
| -// block.
|
| +// and the stack-based variable :saved_try_ctx_var of the outer try block.
|
| // The inner :saved_try_ctx_var is used by a finally clause handling an
|
| -// exception thrown by the continuation code in a catch clause. If no finally
|
| -// clause exists, the catch or finally clause of the outer try block, if any,
|
| -// uses the outer :saved_try_ctx_var to handle the exception.
|
| +// exception thrown by the continuation code in a try block or catch block.
|
| +// If no finally clause exists, the catch or finally clause of the outer try
|
| +// block, if any, uses the outer :saved_try_ctx_var to handle the exception.
|
| //
|
| -// * Try blocks: Set the context variable for this try block.
|
| -// * Catch blocks: Set the context variable for this try block and for any outer
|
| -// try block (if existent).
|
| -// * Finally blocks: Set the context variable for any outer try block (if
|
| -// existent). Note that this try block is popped before
|
| -// parsing the finally clause, so the outer try block (if
|
| -// existent) is at the top of the try block list.
|
| +// * Try blocks and catch blocks:
|
| +// Set the context variable for this try block and for the outer try block.
|
| +// * Finally blocks:
|
| +// Set the context variable for the outer try block. Note that the try
|
| +// declaring the finally is popped before parsing the finally clause, so the
|
| +// outer try block is at the top of the try block list.
|
| //
|
| // TODO(regis): Could we return the variables instead of their containing
|
| // scopes? Check if they are already setup at this point.
|
| @@ -8178,20 +8176,21 @@
|
| *try_index = CatchClauseNode::kInvalidTryIndex;
|
| *outer_try_scope = NULL;
|
| *outer_try_index = CatchClauseNode::kInvalidTryIndex;
|
| - if (try_blocks_list_ != NULL) {
|
| - LocalScope* scope = try_blocks_list_->try_block()->scope;
|
| + if (try_stack_ != NULL) {
|
| + LocalScope* scope = try_stack_->try_block()->scope;
|
| const int current_function_level = current_block_->scope->function_level();
|
| if (scope->function_level() == current_function_level) {
|
| // The block declaring :saved_try_ctx_var variable is the parent of the
|
| // pushed try block.
|
| *try_scope = scope->parent();
|
| - *try_index = try_blocks_list_->try_index();
|
| - if (try_blocks_list_->inside_catch() &&
|
| - (try_blocks_list_->outer_try_block() != NULL)) {
|
| - scope = try_blocks_list_->outer_try_block()->try_block()->scope;
|
| + *try_index = try_stack_->try_index();
|
| + if (try_stack_->outer_try() != NULL) {
|
| + // TODO(regis): Collecting the outer try scope is not necessary if we
|
| + // are in a finally block. Add support for try_stack_->inside_finally().
|
| + scope = try_stack_->outer_try()->try_block()->scope;
|
| if (scope->function_level() == current_function_level) {
|
| *outer_try_scope = scope->parent();
|
| - *outer_try_index = try_blocks_list_->outer_try_block()->try_index();
|
| + *outer_try_index = try_stack_->outer_try()->try_index();
|
| }
|
| }
|
| }
|
| @@ -8706,12 +8705,12 @@
|
| // outer try block (if it exists). The current try block has already been
|
| // removed from the stack of try blocks.
|
| if (is_async) {
|
| - if (try_blocks_list_ != NULL) {
|
| - LocalScope* scope = try_blocks_list_->try_block()->scope;
|
| + if (try_stack_ != NULL) {
|
| + LocalScope* scope = try_stack_->try_block()->scope;
|
| if (scope->function_level() == current_block_->scope->function_level()) {
|
| current_block_->statements->Add(
|
| AwaitTransformer::RestoreSavedTryContext(
|
| - Z, scope->parent(), try_blocks_list_->try_index()));
|
| + Z, scope->parent(), try_stack_->try_index()));
|
| }
|
| }
|
| // We need to save the exception variables as in catch clauses, whether
|
| @@ -8732,18 +8731,16 @@
|
| }
|
|
|
|
|
| -void Parser::PushTryBlock(Block* try_block) {
|
| +void Parser::PushTry(Block* try_block) {
|
| intptr_t try_index = AllocateTryIndex();
|
| - TryBlocks* block = new(Z) TryBlocks(
|
| - try_block, try_blocks_list_, try_index);
|
| - try_blocks_list_ = block;
|
| + try_stack_ = new(Z) TryStack(try_block, try_stack_, try_index);
|
| }
|
|
|
|
|
| -Parser::TryBlocks* Parser::PopTryBlock() {
|
| - TryBlocks* innermost_try_block = try_blocks_list_;
|
| - try_blocks_list_ = try_blocks_list_->outer_try_block();
|
| - return innermost_try_block;
|
| +Parser::TryStack* Parser::PopTry() {
|
| + TryStack* innermost_try = try_stack_;
|
| + try_stack_ = try_stack_->outer_try();
|
| + return innermost_try;
|
| }
|
|
|
|
|
| @@ -8752,7 +8749,7 @@
|
| return;
|
| }
|
| ASSERT(node->IsReturnNode() || node->IsJumpNode());
|
| - TryBlocks* iterator = try_blocks_list_;
|
| + TryStack* iterator = try_stack_;
|
| while (iterator != NULL) {
|
| // For continue and break node check if the target label is in scope.
|
| if (node->IsJumpNode()) {
|
| @@ -8769,7 +8766,7 @@
|
| }
|
| }
|
| iterator->AddNodeForFinallyInlining(node);
|
| - iterator = iterator->outer_try_block();
|
| + iterator = iterator->outer_try();
|
| }
|
| }
|
|
|
| @@ -8966,9 +8963,9 @@
|
| // In case of async closures, restore :saved_try_context_var before executing
|
| // the catch clauses.
|
| if (is_async && (current != NULL)) {
|
| - ASSERT(try_blocks_list_ != NULL);
|
| + ASSERT(try_stack_ != NULL);
|
| SequenceNode* async_code = new(Z) SequenceNode(handler_pos, NULL);
|
| - const TryBlocks* try_block = try_blocks_list_->outer_try_block();
|
| + const TryStack* try_block = try_stack_->outer_try();
|
| if (try_block != NULL) {
|
| LocalScope* scope = try_block->try_block()->scope;
|
| if (scope->function_level() ==
|
| @@ -9126,7 +9123,7 @@
|
|
|
| // Now parse the 'try' block.
|
| OpenBlock();
|
| - PushTryBlock(current_block_);
|
| + PushTry(current_block_);
|
| ExpectToken(Token::kLBRACE);
|
|
|
| if (is_async) {
|
| @@ -9143,7 +9140,7 @@
|
| }
|
|
|
| // Now parse the 'catch' blocks if any.
|
| - try_blocks_list_->enter_catch();
|
| + try_stack_->enter_catch();
|
| const intptr_t handler_pos = TokenPos();
|
| const GrowableObjectArray& handler_types =
|
| GrowableObjectArray::Handle(Z, GrowableObjectArray::New());
|
| @@ -9158,12 +9155,11 @@
|
| handler_types,
|
| &needs_stack_trace);
|
|
|
| - TryBlocks* inner_try_block = PopTryBlock();
|
| - const intptr_t try_index = inner_try_block->try_index();
|
| - TryBlocks* outer_try_block = try_blocks_list_;
|
| - const intptr_t outer_try_index = (outer_try_block != NULL)
|
| - ? outer_try_block->try_index()
|
| - : CatchClauseNode::kInvalidTryIndex;
|
| + TryStack* try_statement = PopTry();
|
| + const intptr_t try_index = try_statement->try_index();
|
| + TryStack* outer_try = try_stack_;
|
| + const intptr_t outer_try_index = (outer_try != NULL) ?
|
| + outer_try->try_index() : CatchClauseNode::kInvalidTryIndex;
|
|
|
| // Finally parse the 'finally' block.
|
| SequenceNode* finally_block = NULL;
|
| @@ -9172,8 +9168,7 @@
|
| const intptr_t finally_pos = TokenPos();
|
| // Add the finally block to the exit points recorded so far.
|
| intptr_t node_index = 0;
|
| - AstNode* node_to_inline =
|
| - inner_try_block->GetNodeToInlineFinally(node_index);
|
| + AstNode* node_to_inline = try_statement->GetNodeToInlineFinally(node_index);
|
| while (node_to_inline != NULL) {
|
| finally_block = ParseFinallyBlock(
|
| is_async,
|
| @@ -9187,7 +9182,7 @@
|
| outer_try_index);
|
| AddFinallyBlockToNode(is_async, node_to_inline, node);
|
| node_index += 1;
|
| - node_to_inline = inner_try_block->GetNodeToInlineFinally(node_index);
|
| + node_to_inline = try_statement->GetNodeToInlineFinally(node_index);
|
| tokens_iterator_.SetCurrentPosition(finally_pos);
|
| }
|
| finally_block = ParseFinallyBlock(
|
| @@ -9533,7 +9528,7 @@
|
| ConsumeToken();
|
| ExpectSemicolon();
|
| // Check if it is ok to do a rethrow.
|
| - if ((try_blocks_list_ == NULL) || !try_blocks_list_->inside_catch()) {
|
| + if ((try_stack_ == NULL) || !try_stack_->inside_catch()) {
|
| ReportError(statement_pos, "rethrow of an exception is not valid here");
|
| }
|
|
|
| @@ -9541,7 +9536,7 @@
|
| // instead of :exception_var and :stack_trace_var.
|
| // These variables are bound in the block containing the try.
|
| // Look in the try scope directly.
|
| - LocalScope* scope = try_blocks_list_->try_block()->scope->parent();
|
| + LocalScope* scope = try_stack_->try_block()->scope->parent();
|
| ASSERT(scope != NULL);
|
| LocalVariable* excp_var;
|
| LocalVariable* trace_var;
|
|
|