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

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, 10 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
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);
5978 if (exception_param.var != NULL) { 5979 if (exception_param.var != NULL) {
5979 // Generate code to load the exception object (:exception_var) into 5980 // Generate code to load the exception object (:exception_var) into
5980 // the exception variable specified in this block. 5981 // the exception variable specified in this block.
5981 ASSERT(exception_var != NULL); 5982 ASSERT(exception_var != NULL);
hausner 2015/02/24 20:57:31 Maybe it makes sense to pull this assert out of th
regis 2015/02/24 22:05:13 Done. Note that it was asserted in the constructor
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);
5989 if (stack_trace_param.var != NULL) { 5991 if (stack_trace_param.var != NULL) {
5990 // A stack trace variable is specified in this block, so generate code 5992 // 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 5993 // to load the stack trace object (:stack_trace_var) into the stack
5992 // trace variable specified in this block. 5994 // trace variable specified in this block.
5993 ASSERT(stack_trace_var != NULL); 5995 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 2175 matching lines...) Expand 10 before | Expand all | Expand 10 after
8185 void Parser::AddCatchParamsToScope(CatchParamDesc* exception_param, 8190 void Parser::AddCatchParamsToScope(CatchParamDesc* exception_param,
8186 CatchParamDesc* stack_trace_param, 8191 CatchParamDesc* stack_trace_param,
8187 LocalScope* scope) { 8192 LocalScope* scope) {
8188 if (exception_param->name != NULL) { 8193 if (exception_param->name != NULL) {
8189 LocalVariable* var = new(Z) LocalVariable( 8194 LocalVariable* var = new(Z) LocalVariable(
8190 exception_param->token_pos, 8195 exception_param->token_pos,
8191 *exception_param->name, 8196 *exception_param->name,
8192 *exception_param->type); 8197 *exception_param->type);
8193 var->set_is_final(); 8198 var->set_is_final();
8194 bool added_to_scope = scope->AddVariable(var); 8199 bool added_to_scope = scope->AddVariable(var);
8195 ASSERT(added_to_scope); 8200 ASSERT(added_to_scope); // TODO(regis): Why do we check below but not here?
hausner 2015/02/24 20:57:31 FWIW, I don't know either.
regis 2015/02/24 22:05:13 I get it now. The error can only be reported below
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) {
8206 ReportError(stack_trace_param->token_pos, 8211 ReportError(stack_trace_param->token_pos,
8207 "name '%s' already exists in scope", 8212 "name '%s' already exists in scope",
8208 stack_trace_param->name->ToCString()); 8213 stack_trace_param->name->ToCString());
8209 } 8214 }
8210 stack_trace_param->var = var; 8215 stack_trace_param->var = var;
8211 } 8216 }
8212 } 8217 }
8213 8218
8214 8219
8220 // Populate local scope of the catch block with the saved exception and saved
8221 // stack trace.
8222 void Parser::AddSavedExceptionAndStacktraceToScope(
Ivan Posva 2015/02/24 20:52:39 These variables are being added unconditionally he
regis 2015/02/24 22:05:13 Done.
8223 LocalVariable* exception_var,
8224 LocalVariable* stack_trace_var,
8225 LocalScope* scope) {
8226 // Add :saved_exception_var and :saved_stack_trace_var to scope.
8227 LocalVariable* saved_exception_var = new (Z) LocalVariable(
8228 Scanner::kNoSourcePos,
8229 Symbols::SavedExceptionVar(),
8230 Type::ZoneHandle(Z, Type::DynamicType()));
8231 scope->AddVariable(saved_exception_var);
8232 saved_exception_var->set_is_captured();
Ivan Posva 2015/02/24 20:52:39 These variables should be automatically captured a
hausner 2015/02/24 20:57:31 Capturing explicitly should not be necessary. Afte
regis 2015/02/24 22:05:13 Removed the explicit capturing and marked as final
8233 LocalVariable* saved_stack_trace_var = new (Z) LocalVariable(
8234 Scanner::kNoSourcePos,
8235 Symbols::SavedStackTraceVar(),
8236 Type::ZoneHandle(Z, Type::DynamicType()));
8237 scope->AddVariable(saved_stack_trace_var);
8238 saved_stack_trace_var->set_is_captured();
8239
8240 // Generate code to load the exception object (:exception_var) into
8241 // the saved exception variable (:saved_exception_var) used to rethrow.
8242 saved_exception_var = current_block_->scope->LookupVariable(
8243 Symbols::SavedExceptionVar(), false);
8244 ASSERT(saved_exception_var != NULL);
8245 ASSERT(exception_var != NULL);
8246 current_block_->statements->Add(new(Z) StoreLocalNode(
8247 Scanner::kNoSourcePos,
8248 saved_exception_var,
8249 new(Z) LoadLocalNode(Scanner::kNoSourcePos, exception_var)));
8250
8251 // Generate code to load the stack trace object (:stack_trace_var) into
8252 // the saved stacktrace variable (:saved_stack_trace_var) used to rethrow.
8253 saved_stack_trace_var = current_block_->scope->LookupVariable(
8254 Symbols::SavedStackTraceVar(), false);
8255 ASSERT(saved_stack_trace_var != NULL);
8256 ASSERT(stack_trace_var != NULL);
8257 current_block_->statements->Add(new(Z) StoreLocalNode(
8258 Scanner::kNoSourcePos,
8259 saved_stack_trace_var,
8260 new(Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_var)));
8261 }
8262
8263
8215 SequenceNode* Parser::ParseFinallyBlock() { 8264 SequenceNode* Parser::ParseFinallyBlock() {
8216 TRACE_PARSER("ParseFinallyBlock"); 8265 TRACE_PARSER("ParseFinallyBlock");
8217 OpenBlock(); 8266 OpenBlock();
8218 ExpectToken(Token::kLBRACE); 8267 ExpectToken(Token::kLBRACE);
8219 8268
8220 // In case of async closures we need to restore the saved try index of an 8269 // 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 8270 // outer try block (if it exists). The current try block has already been
8222 // removed from the stack of try blocks. 8271 // removed from the stack of try blocks.
8223 if ((innermost_function().IsAsyncClosure() || 8272 if ((innermost_function().IsAsyncClosure() ||
8224 innermost_function().IsAsyncFunction() || 8273 innermost_function().IsAsyncFunction() ||
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
8338 stack_trace_param.token_pos = TokenPos(); 8387 stack_trace_param.token_pos = TokenPos();
8339 stack_trace_param.name = ExpectIdentifier("identifier expected"); 8388 stack_trace_param.name = ExpectIdentifier("identifier expected");
8340 } 8389 }
8341 ExpectToken(Token::kRPAREN); 8390 ExpectToken(Token::kRPAREN);
8342 } 8391 }
8343 8392
8344 // Create a block containing the catch clause parameters and the 8393 // Create a block containing the catch clause parameters and the
8345 // following code: 8394 // following code:
8346 // 1) Store exception object and stack trace object into user-defined 8395 // 1) Store exception object and stack trace object into user-defined
8347 // variables (as needed). 8396 // variables (as needed).
8348 // 2) Nested block with source code from catch clause block. 8397 // 2) In async code, save exception object and stack trace object into
8398 // captured :saved_exception_var and :saved_stack_trace_var.
8399 // 3) Nested block with source code from catch clause block.
8349 OpenBlock(); 8400 OpenBlock();
8350 AddCatchParamsToScope(&exception_param, &stack_trace_param, 8401 AddCatchParamsToScope(&exception_param, &stack_trace_param,
8351 current_block_->scope); 8402 current_block_->scope);
8352 8403
8353 if (exception_param.var != NULL) { 8404 if (exception_param.var != NULL) {
8354 // Generate code to load the exception object (:exception_var) into 8405 // Generate code to load the exception object (:exception_var) into
8355 // the exception variable specified in this block. 8406 // the exception variable specified in this block.
8356 ASSERT(exception_var != NULL); 8407 ASSERT(exception_var != NULL);
8357 current_block_->statements->Add(new(Z) StoreLocalNode( 8408 current_block_->statements->Add(new(Z) StoreLocalNode(
8358 catch_pos, exception_param.var, new(Z) LoadLocalNode( 8409 catch_pos, exception_param.var, new(Z) LoadLocalNode(
(...skipping 27 matching lines...) Expand all
8386 current_block_->scope->function_level())) { 8437 current_block_->scope->function_level())) {
8387 // We need to unchain three scope levels: catch clause, catch 8438 // We need to unchain three scope levels: catch clause, catch
8388 // parameters, and the general try block. 8439 // parameters, and the general try block.
8389 RestoreSavedTryContext( 8440 RestoreSavedTryContext(
8390 current_block_->scope->parent()->parent()->parent(), 8441 current_block_->scope->parent()->parent()->parent(),
8391 try_blocks_list_->outer_try_block()->try_index(), 8442 try_blocks_list_->outer_try_block()->try_index(),
8392 current_block_->statements); 8443 current_block_->statements);
8393 } else { 8444 } else {
8394 parsed_function()->reset_saved_try_ctx_vars(); 8445 parsed_function()->reset_saved_try_ctx_vars();
8395 } 8446 }
8447 AddSavedExceptionAndStacktraceToScope(
8448 exception_var, stack_trace_var, current_block_->scope);
8396 } 8449 }
8397 8450
8398 current_block_->statements->Add(ParseNestedStatement(false, NULL)); 8451 current_block_->statements->Add(ParseNestedStatement(false, NULL));
8399 catch_blocks.Add(CloseBlock()); 8452 catch_blocks.Add(CloseBlock());
8400 8453
8401 const bool is_bad_type = 8454 const bool is_bad_type =
8402 exception_param.type->IsMalformed() || 8455 exception_param.type->IsMalformed() ||
8403 exception_param.type->IsMalbounded(); 8456 exception_param.type->IsMalbounded();
8404 if (exception_param.type->IsDynamicType() || is_bad_type) { 8457 if (exception_param.type->IsDynamicType() || is_bad_type) {
8405 // There is no exception type or else it is malformed or malbounded. 8458 // 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( 8583 current_block_->statements->Add(new(Z) StoreLocalNode(
8531 Scanner::kNoSourcePos, 8584 Scanner::kNoSourcePos,
8532 async_saved_try_ctx, 8585 async_saved_try_ctx,
8533 new(Z) LoadLocalNode(Scanner::kNoSourcePos, saved_try_context))); 8586 new(Z) LoadLocalNode(Scanner::kNoSourcePos, saved_try_context)));
8534 parsed_function()->set_saved_try_ctx(saved_try_context); 8587 parsed_function()->set_saved_try_ctx(saved_try_context);
8535 parsed_function()->set_async_saved_try_ctx_name(async_saved_try_ctx_name); 8588 parsed_function()->set_async_saved_try_ctx_name(async_saved_try_ctx_name);
8536 } 8589 }
8537 8590
8538 8591
8539 // Restore the currently relevant :saved_try_context_var on the stack 8592 // Restore the currently relevant :saved_try_context_var on the stack
8540 // from the captured :async_saved_try_cts_var. 8593 // from the captured :async_saved_try_ctx_var_.
8541 // * Try blocks: Set the context variable for this try block. 8594 // * Try blocks: Set the context variable for this try block.
8542 // * Catch/finally blocks: Set the context variable for any outer try block (if 8595 // * Catch/finally blocks: Set the context variable for any outer try block (if
8543 // existent). 8596 // existent).
8544 // 8597 //
8545 // Also save the captured variable and the stack variable to be able to set 8598 // Also save the captured variable and the stack variable to be able to set
8546 // it after a function continues execution (await). 8599 // it after a function continues execution (await).
8547 void Parser::RestoreSavedTryContext(LocalScope* saved_try_context_scope, 8600 void Parser::RestoreSavedTryContext(LocalScope* saved_try_context_scope,
8548 int16_t try_index, 8601 int16_t try_index,
8549 SequenceNode* target) { 8602 SequenceNode* target) {
8550 LocalVariable* saved_try_ctx = saved_try_context_scope->LookupVariable( 8603 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. 8977 // Empty statement, nothing to do.
8925 ConsumeToken(); 8978 ConsumeToken();
8926 } else if (token == Token::kRETHROW) { 8979 } else if (token == Token::kRETHROW) {
8927 // Rethrow of current exception. 8980 // Rethrow of current exception.
8928 ConsumeToken(); 8981 ConsumeToken();
8929 ExpectSemicolon(); 8982 ExpectSemicolon();
8930 // Check if it is ok to do a rethrow. 8983 // Check if it is ok to do a rethrow.
8931 if ((try_blocks_list_ == NULL) || !try_blocks_list_->inside_catch()) { 8984 if ((try_blocks_list_ == NULL) || !try_blocks_list_->inside_catch()) {
8932 ReportError(statement_pos, "rethrow of an exception is not valid here"); 8985 ReportError(statement_pos, "rethrow of an exception is not valid here");
8933 } 8986 }
8934 // The exception and stack trace variables are bound in the block 8987
8935 // containing the try. 8988 // If in async code, use :saved_exception_var and :saved_stack_trace_var
8936 LocalScope* scope = try_blocks_list_->try_block()->scope->parent(); 8989 // instead of :exception_var and :stack_trace_var.
8937 ASSERT(scope != NULL); 8990 LocalVariable* excp_var;
8938 LocalVariable* excp_var = 8991 LocalVariable* trace_var;
8939 scope->LocalLookupVariable(Symbols::ExceptionVar()); 8992 if (innermost_function().IsAsyncClosure() ||
8993 innermost_function().IsAsyncFunction() ||
8994 innermost_function().IsSyncGenClosure() ||
8995 innermost_function().IsSyncGenerator()) {
8996 // The saved exception and stack trace variables are bound in the block
8997 // containing the catch.
8998 LocalScope* scope = current_block_->scope;
8999 excp_var = scope->LookupVariable(Symbols::SavedExceptionVar(), false);
Ivan Posva 2015/02/24 20:52:39 Why is this not LocalLookupVariable?
hausner 2015/02/24 20:57:31 I think Ivan is right, this should only look up in
regis 2015/02/24 22:05:13 As explained by the comments (obviously not clearl
9000 trace_var = scope->LookupVariable(Symbols::SavedStackTraceVar(), false);
9001 } else {
9002 // The exception and stack trace variables are bound in the block
9003 // containing the try.
9004 LocalScope* scope = try_blocks_list_->try_block()->scope->parent();
9005 ASSERT(scope != NULL);
9006 excp_var = scope->LocalLookupVariable(Symbols::ExceptionVar());
9007 trace_var = scope->LocalLookupVariable(Symbols::StackTraceVar());
9008 }
8940 ASSERT(excp_var != NULL); 9009 ASSERT(excp_var != NULL);
8941 LocalVariable* trace_var =
8942 scope->LocalLookupVariable(Symbols::StackTraceVar());
8943 ASSERT(trace_var != NULL); 9010 ASSERT(trace_var != NULL);
9011
8944 statement = new(Z) ThrowNode( 9012 statement = new(Z) ThrowNode(
8945 statement_pos, 9013 statement_pos,
8946 new(Z) LoadLocalNode(statement_pos, excp_var), 9014 new(Z) LoadLocalNode(statement_pos, excp_var),
8947 new(Z) LoadLocalNode(statement_pos, trace_var)); 9015 new(Z) LoadLocalNode(statement_pos, trace_var));
8948 } else { 9016 } else {
8949 statement = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL); 9017 statement = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL);
8950 ExpectSemicolon(); 9018 ExpectSemicolon();
8951 } 9019 }
8952 return statement; 9020 return statement;
8953 } 9021 }
(...skipping 3614 matching lines...) Expand 10 before | Expand all | Expand 10 after
12568 void Parser::SkipQualIdent() { 12636 void Parser::SkipQualIdent() {
12569 ASSERT(IsIdentifier()); 12637 ASSERT(IsIdentifier());
12570 ConsumeToken(); 12638 ConsumeToken();
12571 if (CurrentToken() == Token::kPERIOD) { 12639 if (CurrentToken() == Token::kPERIOD) {
12572 ConsumeToken(); // Consume the kPERIOD token. 12640 ConsumeToken(); // Consume the kPERIOD token.
12573 ExpectIdentifier("identifier expected after '.'"); 12641 ExpectIdentifier("identifier expected after '.'");
12574 } 12642 }
12575 } 12643 }
12576 12644
12577 } // namespace dart 12645 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698