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

Side by Side Diff: runtime/vm/parser.cc

Issue 956583003: Save exception and stack trace variables in async catch clauses and use them (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 5 years, 9 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/parser.h ('k') | runtime/vm/symbols.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/parser.h" 5 #include "vm/parser.h"
6 6
7 #include "lib/invocation_mirror.h" 7 #include "lib/invocation_mirror.h"
8 #include "platform/utils.h" 8 #include "platform/utils.h"
9 #include "vm/ast_transformer.h" 9 #include "vm/ast_transformer.h"
10 #include "vm/bootstrap.h" 10 #include "vm/bootstrap.h"
(...skipping 5955 matching lines...) Expand 10 before | Expand all | Expand 10 after
5966 stack_trace_param.token_pos = Scanner::kNoSourcePos; 5966 stack_trace_param.token_pos = Scanner::kNoSourcePos;
5967 stack_trace_param.type = &dynamic_type; 5967 stack_trace_param.type = &dynamic_type;
5968 stack_trace_param.name = &Symbols::StackTraceParameter(); 5968 stack_trace_param.name = &Symbols::StackTraceParameter();
5969 5969
5970 AddCatchParamsToScope( 5970 AddCatchParamsToScope(
5971 &exception_param, &stack_trace_param, current_block_->scope); 5971 &exception_param, &stack_trace_param, current_block_->scope);
5972 5972
5973 LocalVariable* context_var = current_block_->scope->LookupVariable( 5973 LocalVariable* context_var = current_block_->scope->LookupVariable(
5974 Symbols::SavedTryContextVar(), false); 5974 Symbols::SavedTryContextVar(), false);
5975 ASSERT(context_var != NULL); 5975 ASSERT(context_var != NULL);
5976
5976 LocalVariable* exception_var = current_block_->scope->LookupVariable( 5977 LocalVariable* exception_var = current_block_->scope->LookupVariable(
5977 Symbols::ExceptionVar(), false); 5978 Symbols::ExceptionVar(), false);
5979 ASSERT(exception_var != NULL);
5978 if (exception_param.var != NULL) { 5980 if (exception_param.var != NULL) {
5979 // Generate code to load the exception object (:exception_var) into 5981 // Generate code to load the exception object (:exception_var) into
5980 // the exception variable specified in this block. 5982 // the exception variable specified in this block.
5981 ASSERT(exception_var != NULL);
5982 current_block_->statements->Add(new(Z) StoreLocalNode( 5983 current_block_->statements->Add(new(Z) StoreLocalNode(
5983 Scanner::kNoSourcePos, 5984 Scanner::kNoSourcePos,
5984 exception_param.var, 5985 exception_param.var,
5985 new(Z) LoadLocalNode(Scanner::kNoSourcePos, exception_var))); 5986 new(Z) LoadLocalNode(Scanner::kNoSourcePos, exception_var)));
5986 } 5987 }
5988
5987 LocalVariable* stack_trace_var = 5989 LocalVariable* stack_trace_var =
5988 current_block_->scope->LookupVariable(Symbols::StackTraceVar(), false); 5990 current_block_->scope->LookupVariable(Symbols::StackTraceVar(), false);
5991 ASSERT(stack_trace_var != NULL);
5989 if (stack_trace_param.var != NULL) { 5992 if (stack_trace_param.var != NULL) {
5990 // A stack trace variable is specified in this block, so generate code 5993 // A stack trace variable is specified in this block, so generate code
5991 // to load the stack trace object (:stack_trace_var) into the stack 5994 // to load the stack trace object (:stack_trace_var) into the stack
5992 // trace variable specified in this block. 5995 // trace variable specified in this block.
5993 ASSERT(stack_trace_var != NULL);
5994 current_block_->statements->Add(new(Z) StoreLocalNode( 5996 current_block_->statements->Add(new(Z) StoreLocalNode(
5995 Scanner::kNoSourcePos, 5997 Scanner::kNoSourcePos,
5996 stack_trace_param.var, 5998 stack_trace_param.var,
5997 new(Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_var))); 5999 new(Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_var)));
5998 } 6000 }
5999 6001
6002 AddSavedExceptionAndStacktraceToScope(
6003 exception_var, stack_trace_var, current_block_->scope);
6004
6000 ASSERT(try_blocks_list_ != NULL); 6005 ASSERT(try_blocks_list_ != NULL);
6001 ASSERT(innermost_function().IsAsyncClosure() || 6006 ASSERT(innermost_function().IsAsyncClosure() ||
6002 innermost_function().IsAsyncFunction()); 6007 innermost_function().IsAsyncFunction());
6003 if ((try_blocks_list_->outer_try_block() != NULL) && 6008 if ((try_blocks_list_->outer_try_block() != NULL) &&
6004 (try_blocks_list_->outer_try_block()->try_block() 6009 (try_blocks_list_->outer_try_block()->try_block()
6005 ->scope->function_level() == 6010 ->scope->function_level() ==
6006 current_block_->scope->function_level())) { 6011 current_block_->scope->function_level())) {
6007 // We need to unchain three scope levels: catch clause, catch 6012 // We need to unchain three scope levels: catch clause, catch
6008 // parameters, and the general try block. 6013 // parameters, and the general try block.
6009 RestoreSavedTryContext( 6014 RestoreSavedTryContext(
(...skipping 2186 matching lines...) Expand 10 before | Expand all | Expand 10 after
8196 exception_param->var = var; 8201 exception_param->var = var;
8197 } 8202 }
8198 if (stack_trace_param->name != NULL) { 8203 if (stack_trace_param->name != NULL) {
8199 LocalVariable* var = new(Z) LocalVariable( 8204 LocalVariable* var = new(Z) LocalVariable(
8200 stack_trace_param->token_pos, 8205 stack_trace_param->token_pos,
8201 *stack_trace_param->name, 8206 *stack_trace_param->name,
8202 *stack_trace_param->type); 8207 *stack_trace_param->type);
8203 var->set_is_final(); 8208 var->set_is_final();
8204 bool added_to_scope = scope->AddVariable(var); 8209 bool added_to_scope = scope->AddVariable(var);
8205 if (!added_to_scope) { 8210 if (!added_to_scope) {
8211 // The name of the exception param is reused for the stack trace param.
8206 ReportError(stack_trace_param->token_pos, 8212 ReportError(stack_trace_param->token_pos,
8207 "name '%s' already exists in scope", 8213 "name '%s' already exists in scope",
8208 stack_trace_param->name->ToCString()); 8214 stack_trace_param->name->ToCString());
8209 } 8215 }
8210 stack_trace_param->var = var; 8216 stack_trace_param->var = var;
8211 } 8217 }
8212 } 8218 }
8213 8219
8214 8220
8221 // Populate local scope of the catch block with the saved exception and saved
8222 // stack trace.
8223 void Parser::AddSavedExceptionAndStacktraceToScope(
8224 LocalVariable* exception_var,
8225 LocalVariable* stack_trace_var,
8226 LocalScope* scope) {
8227 ASSERT(innermost_function().IsAsyncClosure() ||
8228 innermost_function().IsAsyncFunction() ||
8229 innermost_function().IsSyncGenClosure() ||
8230 innermost_function().IsSyncGenerator());
8231 // Add :saved_exception_var and :saved_stack_trace_var to scope.
8232 // They will automatically get captured.
8233 LocalVariable* saved_exception_var = new (Z) LocalVariable(
8234 Scanner::kNoSourcePos,
8235 Symbols::SavedExceptionVar(),
8236 Type::ZoneHandle(Z, Type::DynamicType()));
8237 saved_exception_var->set_is_final();
8238 scope->AddVariable(saved_exception_var);
8239 LocalVariable* saved_stack_trace_var = new (Z) LocalVariable(
8240 Scanner::kNoSourcePos,
8241 Symbols::SavedStackTraceVar(),
8242 Type::ZoneHandle(Z, Type::DynamicType()));
8243 saved_exception_var->set_is_final();
8244 scope->AddVariable(saved_stack_trace_var);
8245
8246 // Generate code to load the exception object (:exception_var) into
8247 // the saved exception variable (:saved_exception_var) used to rethrow.
8248 saved_exception_var = current_block_->scope->LookupVariable(
8249 Symbols::SavedExceptionVar(), false);
8250 ASSERT(saved_exception_var != NULL);
8251 ASSERT(exception_var != NULL);
8252 current_block_->statements->Add(new(Z) StoreLocalNode(
8253 Scanner::kNoSourcePos,
8254 saved_exception_var,
8255 new(Z) LoadLocalNode(Scanner::kNoSourcePos, exception_var)));
8256
8257 // Generate code to load the stack trace object (:stack_trace_var) into
8258 // the saved stacktrace variable (:saved_stack_trace_var) used to rethrow.
8259 saved_stack_trace_var = current_block_->scope->LookupVariable(
8260 Symbols::SavedStackTraceVar(), false);
8261 ASSERT(saved_stack_trace_var != NULL);
8262 ASSERT(stack_trace_var != NULL);
8263 current_block_->statements->Add(new(Z) StoreLocalNode(
8264 Scanner::kNoSourcePos,
8265 saved_stack_trace_var,
8266 new(Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_var)));
8267 }
8268
8269
8215 SequenceNode* Parser::ParseFinallyBlock() { 8270 SequenceNode* Parser::ParseFinallyBlock() {
8216 TRACE_PARSER("ParseFinallyBlock"); 8271 TRACE_PARSER("ParseFinallyBlock");
8217 OpenBlock(); 8272 OpenBlock();
8218 ExpectToken(Token::kLBRACE); 8273 ExpectToken(Token::kLBRACE);
8219 8274
8220 // In case of async closures we need to restore the saved try index of an 8275 // In case of async closures we need to restore the saved try index of an
8221 // outer try block (if it exists). The current try block has already been 8276 // outer try block (if it exists). The current try block has already been
8222 // removed from the stack of try blocks. 8277 // removed from the stack of try blocks.
8223 if ((innermost_function().IsAsyncClosure() || 8278 if ((innermost_function().IsAsyncClosure() ||
8224 innermost_function().IsAsyncFunction() || 8279 innermost_function().IsAsyncFunction() ||
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
8338 stack_trace_param.token_pos = TokenPos(); 8393 stack_trace_param.token_pos = TokenPos();
8339 stack_trace_param.name = ExpectIdentifier("identifier expected"); 8394 stack_trace_param.name = ExpectIdentifier("identifier expected");
8340 } 8395 }
8341 ExpectToken(Token::kRPAREN); 8396 ExpectToken(Token::kRPAREN);
8342 } 8397 }
8343 8398
8344 // Create a block containing the catch clause parameters and the 8399 // Create a block containing the catch clause parameters and the
8345 // following code: 8400 // following code:
8346 // 1) Store exception object and stack trace object into user-defined 8401 // 1) Store exception object and stack trace object into user-defined
8347 // variables (as needed). 8402 // variables (as needed).
8348 // 2) Nested block with source code from catch clause block. 8403 // 2) In async code, save exception object and stack trace object into
8404 // captured :saved_exception_var and :saved_stack_trace_var.
8405 // 3) Nested block with source code from catch clause block.
8349 OpenBlock(); 8406 OpenBlock();
8350 AddCatchParamsToScope(&exception_param, &stack_trace_param, 8407 AddCatchParamsToScope(&exception_param, &stack_trace_param,
8351 current_block_->scope); 8408 current_block_->scope);
8352 8409
8353 if (exception_param.var != NULL) { 8410 if (exception_param.var != NULL) {
8354 // Generate code to load the exception object (:exception_var) into 8411 // Generate code to load the exception object (:exception_var) into
8355 // the exception variable specified in this block. 8412 // the exception variable specified in this block.
8356 ASSERT(exception_var != NULL); 8413 ASSERT(exception_var != NULL);
8357 current_block_->statements->Add(new(Z) StoreLocalNode( 8414 current_block_->statements->Add(new(Z) StoreLocalNode(
8358 catch_pos, exception_param.var, new(Z) LoadLocalNode( 8415 catch_pos, exception_param.var, new(Z) LoadLocalNode(
(...skipping 27 matching lines...) Expand all
8386 current_block_->scope->function_level())) { 8443 current_block_->scope->function_level())) {
8387 // We need to unchain three scope levels: catch clause, catch 8444 // We need to unchain three scope levels: catch clause, catch
8388 // parameters, and the general try block. 8445 // parameters, and the general try block.
8389 RestoreSavedTryContext( 8446 RestoreSavedTryContext(
8390 current_block_->scope->parent()->parent()->parent(), 8447 current_block_->scope->parent()->parent()->parent(),
8391 try_blocks_list_->outer_try_block()->try_index(), 8448 try_blocks_list_->outer_try_block()->try_index(),
8392 current_block_->statements); 8449 current_block_->statements);
8393 } else { 8450 } else {
8394 parsed_function()->reset_saved_try_ctx_vars(); 8451 parsed_function()->reset_saved_try_ctx_vars();
8395 } 8452 }
8453 AddSavedExceptionAndStacktraceToScope(
8454 exception_var, stack_trace_var, current_block_->scope);
8396 } 8455 }
8397 8456
8398 current_block_->statements->Add(ParseNestedStatement(false, NULL)); 8457 current_block_->statements->Add(ParseNestedStatement(false, NULL));
8399 catch_blocks.Add(CloseBlock()); 8458 catch_blocks.Add(CloseBlock());
8400 8459
8401 const bool is_bad_type = 8460 const bool is_bad_type =
8402 exception_param.type->IsMalformed() || 8461 exception_param.type->IsMalformed() ||
8403 exception_param.type->IsMalbounded(); 8462 exception_param.type->IsMalbounded();
8404 if (exception_param.type->IsDynamicType() || is_bad_type) { 8463 if (exception_param.type->IsDynamicType() || is_bad_type) {
8405 // There is no exception type or else it is malformed or malbounded. 8464 // There is no exception type or else it is malformed or malbounded.
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
8530 current_block_->statements->Add(new(Z) StoreLocalNode( 8589 current_block_->statements->Add(new(Z) StoreLocalNode(
8531 Scanner::kNoSourcePos, 8590 Scanner::kNoSourcePos,
8532 async_saved_try_ctx, 8591 async_saved_try_ctx,
8533 new(Z) LoadLocalNode(Scanner::kNoSourcePos, saved_try_context))); 8592 new(Z) LoadLocalNode(Scanner::kNoSourcePos, saved_try_context)));
8534 parsed_function()->set_saved_try_ctx(saved_try_context); 8593 parsed_function()->set_saved_try_ctx(saved_try_context);
8535 parsed_function()->set_async_saved_try_ctx_name(async_saved_try_ctx_name); 8594 parsed_function()->set_async_saved_try_ctx_name(async_saved_try_ctx_name);
8536 } 8595 }
8537 8596
8538 8597
8539 // Restore the currently relevant :saved_try_context_var on the stack 8598 // Restore the currently relevant :saved_try_context_var on the stack
8540 // from the captured :async_saved_try_cts_var. 8599 // from the captured :async_saved_try_ctx_var_.
8541 // * Try blocks: Set the context variable for this try block. 8600 // * Try blocks: Set the context variable for this try block.
8542 // * Catch/finally blocks: Set the context variable for any outer try block (if 8601 // * Catch/finally blocks: Set the context variable for any outer try block (if
8543 // existent). 8602 // existent).
8544 // 8603 //
8545 // Also save the captured variable and the stack variable to be able to set 8604 // Also save the captured variable and the stack variable to be able to set
8546 // it after a function continues execution (await). 8605 // it after a function continues execution (await).
8547 void Parser::RestoreSavedTryContext(LocalScope* saved_try_context_scope, 8606 void Parser::RestoreSavedTryContext(LocalScope* saved_try_context_scope,
8548 int16_t try_index, 8607 int16_t try_index,
8549 SequenceNode* target) { 8608 SequenceNode* target) {
8550 LocalVariable* saved_try_ctx = saved_try_context_scope->LookupVariable( 8609 LocalVariable* saved_try_ctx = saved_try_context_scope->LookupVariable(
(...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after
8924 // Empty statement, nothing to do. 8983 // Empty statement, nothing to do.
8925 ConsumeToken(); 8984 ConsumeToken();
8926 } else if (token == Token::kRETHROW) { 8985 } else if (token == Token::kRETHROW) {
8927 // Rethrow of current exception. 8986 // Rethrow of current exception.
8928 ConsumeToken(); 8987 ConsumeToken();
8929 ExpectSemicolon(); 8988 ExpectSemicolon();
8930 // Check if it is ok to do a rethrow. 8989 // Check if it is ok to do a rethrow.
8931 if ((try_blocks_list_ == NULL) || !try_blocks_list_->inside_catch()) { 8990 if ((try_blocks_list_ == NULL) || !try_blocks_list_->inside_catch()) {
8932 ReportError(statement_pos, "rethrow of an exception is not valid here"); 8991 ReportError(statement_pos, "rethrow of an exception is not valid here");
8933 } 8992 }
8934 // The exception and stack trace variables are bound in the block 8993
8935 // containing the try. 8994 // If in async code, use :saved_exception_var and :saved_stack_trace_var
8936 LocalScope* scope = try_blocks_list_->try_block()->scope->parent(); 8995 // instead of :exception_var and :stack_trace_var.
8937 ASSERT(scope != NULL); 8996 LocalVariable* excp_var;
8938 LocalVariable* excp_var = 8997 LocalVariable* trace_var;
8939 scope->LocalLookupVariable(Symbols::ExceptionVar()); 8998 if (innermost_function().IsAsyncClosure() ||
8999 innermost_function().IsAsyncFunction() ||
9000 innermost_function().IsSyncGenClosure() ||
9001 innermost_function().IsSyncGenerator()) {
9002 // The saved exception and stack trace variables are bound in the block
9003 // containing the catch. So start looking in the current scope.
9004 LocalScope* scope = current_block_->scope;
9005 excp_var = scope->LookupVariable(Symbols::SavedExceptionVar(), false);
9006 trace_var = scope->LookupVariable(Symbols::SavedStackTraceVar(), false);
9007 } else {
9008 // The exception and stack trace variables are bound in the block
9009 // containing the try. Look in the try scope directly.
9010 LocalScope* scope = try_blocks_list_->try_block()->scope->parent();
9011 ASSERT(scope != NULL);
9012 excp_var = scope->LocalLookupVariable(Symbols::ExceptionVar());
9013 trace_var = scope->LocalLookupVariable(Symbols::StackTraceVar());
9014 }
8940 ASSERT(excp_var != NULL); 9015 ASSERT(excp_var != NULL);
8941 LocalVariable* trace_var =
8942 scope->LocalLookupVariable(Symbols::StackTraceVar());
8943 ASSERT(trace_var != NULL); 9016 ASSERT(trace_var != NULL);
9017
8944 statement = new(Z) ThrowNode( 9018 statement = new(Z) ThrowNode(
8945 statement_pos, 9019 statement_pos,
8946 new(Z) LoadLocalNode(statement_pos, excp_var), 9020 new(Z) LoadLocalNode(statement_pos, excp_var),
8947 new(Z) LoadLocalNode(statement_pos, trace_var)); 9021 new(Z) LoadLocalNode(statement_pos, trace_var));
8948 } else { 9022 } else {
8949 statement = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL); 9023 statement = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL);
8950 ExpectSemicolon(); 9024 ExpectSemicolon();
8951 } 9025 }
8952 return statement; 9026 return statement;
8953 } 9027 }
(...skipping 3614 matching lines...) Expand 10 before | Expand all | Expand 10 after
12568 void Parser::SkipQualIdent() { 12642 void Parser::SkipQualIdent() {
12569 ASSERT(IsIdentifier()); 12643 ASSERT(IsIdentifier());
12570 ConsumeToken(); 12644 ConsumeToken();
12571 if (CurrentToken() == Token::kPERIOD) { 12645 if (CurrentToken() == Token::kPERIOD) {
12572 ConsumeToken(); // Consume the kPERIOD token. 12646 ConsumeToken(); // Consume the kPERIOD token.
12573 ExpectIdentifier("identifier expected after '.'"); 12647 ExpectIdentifier("identifier expected after '.'");
12574 } 12648 }
12575 } 12649 }
12576 12650
12577 } // namespace dart 12651 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/parser.h ('k') | runtime/vm/symbols.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698