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

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

Issue 63983005: Simplify the desugaring of catch clauses. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Incorporated a round of review comments. Created 7 years, 1 month 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
hausner 2013/11/12 19:21:45 Please keep unrelated changes separate. The includ
Florian Schneider 2013/11/13 10:25:42 I think we all agree changing includes to include
7 #include "lib/invocation_mirror.h" 7 #include "lib/invocation_mirror.h"
8 #include "vm/bigint_operations.h" 8 #include "platform/utils.h"
9 #include "vm/bootstrap.h" 9 #include "vm/bootstrap.h"
10 #include "vm/class_finalizer.h" 10 #include "vm/class_finalizer.h"
11 #include "vm/compiler.h" 11 #include "vm/compiler.h"
12 #include "vm/compiler_stats.h" 12 #include "vm/compiler_stats.h"
13 #include "vm/dart_api_impl.h" 13 #include "vm/dart_api_impl.h"
14 #include "vm/dart_entry.h" 14 #include "vm/dart_entry.h"
15 #include "vm/flags.h" 15 #include "vm/flags.h"
16 #include "vm/growable_array.h" 16 #include "vm/growable_array.h"
17 #include "vm/handles.h"
18 #include "vm/heap.h"
19 #include "vm/isolate.h"
17 #include "vm/longjump.h" 20 #include "vm/longjump.h"
21 #include "vm/native_arguments.h"
18 #include "vm/native_entry.h" 22 #include "vm/native_entry.h"
19 #include "vm/object.h" 23 #include "vm/object.h"
20 #include "vm/object_store.h" 24 #include "vm/object_store.h"
25 #include "vm/os.h"
21 #include "vm/resolver.h" 26 #include "vm/resolver.h"
27 #include "vm/scanner.h"
22 #include "vm/scopes.h" 28 #include "vm/scopes.h"
23 #include "vm/stack_frame.h" 29 #include "vm/stack_frame.h"
24 #include "vm/symbols.h" 30 #include "vm/symbols.h"
31 #include "vm/timer.h"
32 #include "vm/zone.h"
25 33
26 namespace dart { 34 namespace dart {
27 35
28 DEFINE_FLAG(bool, enable_asserts, false, "Enable assert statements."); 36 DEFINE_FLAG(bool, enable_asserts, false, "Enable assert statements.");
29 DEFINE_FLAG(bool, enable_type_checks, false, "Enable type checks."); 37 DEFINE_FLAG(bool, enable_type_checks, false, "Enable type checks.");
30 DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations."); 38 DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations.");
31 DEFINE_FLAG(bool, warning_as_error, false, "Treat warnings as errors."); 39 DEFINE_FLAG(bool, warning_as_error, false, "Treat warnings as errors.");
32 DEFINE_FLAG(bool, silent_warnings, false, "Silence warnings."); 40 DEFINE_FLAG(bool, silent_warnings, false, "Silence warnings.");
33 DEFINE_FLAG(bool, warn_mixin_typedef, true, "Warning on legacy mixin typedef"); 41 DEFINE_FLAG(bool, warn_mixin_typedef, true, "Warning on legacy mixin typedef");
34 DECLARE_FLAG(bool, error_on_bad_type); 42 DECLARE_FLAG(bool, error_on_bad_type);
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
187 195
188 // Class which describes an inlined finally block which is used to generate 196 // Class which describes an inlined finally block which is used to generate
189 // inlined code for the finally blocks when there is an exit from a try 197 // inlined code for the finally blocks when there is an exit from a try
190 // block using 'return', 'break' or 'continue'. 198 // block using 'return', 'break' or 'continue'.
191 class Parser::TryBlocks : public ZoneAllocated { 199 class Parser::TryBlocks : public ZoneAllocated {
192 public: 200 public:
193 TryBlocks(Block* try_block, TryBlocks* outer_try_block, intptr_t try_index) 201 TryBlocks(Block* try_block, TryBlocks* outer_try_block, intptr_t try_index)
194 : try_block_(try_block), 202 : try_block_(try_block),
195 inlined_finally_nodes_(), 203 inlined_finally_nodes_(),
196 outer_try_block_(outer_try_block), 204 outer_try_block_(outer_try_block),
197 try_index_(try_index) { } 205 try_index_(try_index),
206 inside_catch_(false) { }
198 207
199 TryBlocks* outer_try_block() const { return outer_try_block_; } 208 TryBlocks* outer_try_block() const { return outer_try_block_; }
200 Block* try_block() const { return try_block_; } 209 Block* try_block() const { return try_block_; }
201 intptr_t try_index() const { return try_index_; } 210 intptr_t try_index() const { return try_index_; }
211 bool inside_catch() const { return inside_catch_; }
212 void enter_catch() { inside_catch_ = true; }
202 213
203 void AddNodeForFinallyInlining(AstNode* node); 214 void AddNodeForFinallyInlining(AstNode* node);
204 AstNode* GetNodeToInlineFinally(int index) { 215 AstNode* GetNodeToInlineFinally(int index) {
205 if (0 <= index && index < inlined_finally_nodes_.length()) { 216 if (0 <= index && index < inlined_finally_nodes_.length()) {
206 return inlined_finally_nodes_[index]; 217 return inlined_finally_nodes_[index];
207 } 218 }
208 return NULL; 219 return NULL;
209 } 220 }
210 221
211 private: 222 private:
212 Block* try_block_; 223 Block* try_block_;
213 GrowableArray<AstNode*> inlined_finally_nodes_; 224 GrowableArray<AstNode*> inlined_finally_nodes_;
214 TryBlocks* outer_try_block_; 225 TryBlocks* outer_try_block_;
215 const intptr_t try_index_; 226 const intptr_t try_index_;
227 bool inside_catch_;
216 228
217 DISALLOW_COPY_AND_ASSIGN(TryBlocks); 229 DISALLOW_COPY_AND_ASSIGN(TryBlocks);
218 }; 230 };
219 231
220 232
221 void Parser::TryBlocks::AddNodeForFinallyInlining(AstNode* node) { 233 void Parser::TryBlocks::AddNodeForFinallyInlining(AstNode* node) {
222 inlined_finally_nodes_.Add(node); 234 inlined_finally_nodes_.Add(node);
223 } 235 }
224 236
225 237
(...skipping 839 matching lines...) Expand 10 before | Expand all | Expand 10 after
1065 } 1077 }
1066 LocalVariable* catch_excp_var = 1078 LocalVariable* catch_excp_var =
1067 current_block_->scope->LocalLookupVariable(Symbols::ExceptionVar()); 1079 current_block_->scope->LocalLookupVariable(Symbols::ExceptionVar());
1068 if (catch_excp_var == NULL) { 1080 if (catch_excp_var == NULL) {
1069 catch_excp_var = new LocalVariable(token_pos, 1081 catch_excp_var = new LocalVariable(token_pos,
1070 Symbols::ExceptionVar(), 1082 Symbols::ExceptionVar(),
1071 Type::ZoneHandle(Type::DynamicType())); 1083 Type::ZoneHandle(Type::DynamicType()));
1072 current_block_->scope->AddVariable(catch_excp_var); 1084 current_block_->scope->AddVariable(catch_excp_var);
1073 } 1085 }
1074 LocalVariable* catch_trace_var = 1086 LocalVariable* catch_trace_var =
1075 current_block_->scope->LocalLookupVariable(Symbols::StacktraceVar()); 1087 current_block_->scope->LocalLookupVariable(Symbols::StackTraceVar());
1076 if (catch_trace_var == NULL) { 1088 if (catch_trace_var == NULL) {
1077 catch_trace_var = new LocalVariable(token_pos, 1089 catch_trace_var = new LocalVariable(token_pos,
1078 Symbols::StacktraceVar(), 1090 Symbols::StackTraceVar(),
1079 Type::ZoneHandle(Type::DynamicType())); 1091 Type::ZoneHandle(Type::DynamicType()));
1080 current_block_->scope->AddVariable(catch_trace_var); 1092 current_block_->scope->AddVariable(catch_trace_var);
1081 } 1093 }
1082 1094
1083 OpenBlock(); // Start try block. 1095 OpenBlock(); // Start try block.
1084 AstNode* expr = ParseExpr(kAllowConst, kConsumeCascades); 1096 AstNode* expr = ParseExpr(kAllowConst, kConsumeCascades);
1085 const Field& field = Field::ZoneHandle(func.saved_static_field()); 1097 const Field& field = Field::ZoneHandle(func.saved_static_field());
1086 ASSERT(!field.is_const()); 1098 ASSERT(!field.is_const());
1087 StoreStaticFieldNode* store = new StoreStaticFieldNode(field.token_pos(), 1099 StoreStaticFieldNode* store = new StoreStaticFieldNode(field.token_pos(),
1088 field, 1100 field,
1089 expr); 1101 expr);
1090 current_block_->statements->Add(store); 1102 current_block_->statements->Add(store);
1091 SequenceNode* try_block = CloseBlock(); // End try block. 1103 SequenceNode* try_block = CloseBlock(); // End try block.
1092 1104
1093 OpenBlock(); // Start catch handler list. 1105 OpenBlock(); // Start catch handler list.
1094 SourceLabel* end_catch_label =
1095 SourceLabel::New(token_pos, NULL, SourceLabel::kCatch);
1096 current_block_->scope->AddLabel(end_catch_label);
1097
1098 OpenBlock(); // Start catch clause. 1106 OpenBlock(); // Start catch clause.
1099 AstNode* compare_transition_sentinel = new ComparisonNode( 1107 AstNode* compare_transition_sentinel = new ComparisonNode(
1100 token_pos, 1108 token_pos,
1101 Token::kEQ_STRICT, 1109 Token::kEQ_STRICT,
1102 new LoadStaticFieldNode(token_pos, field), 1110 new LoadStaticFieldNode(token_pos, field),
1103 new LiteralNode(field.token_pos(), Object::transition_sentinel())); 1111 new LiteralNode(field.token_pos(), Object::transition_sentinel()));
1104 1112
1105 SequenceNode* store_null = new SequenceNode(token_pos, NULL); 1113 SequenceNode* store_null = new SequenceNode(token_pos, NULL);
1106 store_null->Add(new StoreStaticFieldNode( 1114 store_null->Add(new StoreStaticFieldNode(
1107 field.token_pos(), 1115 field.token_pos(),
1108 field, 1116 field,
1109 new LiteralNode(token_pos, Instance::ZoneHandle()))); 1117 new LiteralNode(token_pos, Instance::ZoneHandle())));
1110 AstNode* transition_sentinel_check = 1118 AstNode* transition_sentinel_check =
1111 new IfNode(token_pos, compare_transition_sentinel, store_null, NULL); 1119 new IfNode(token_pos, compare_transition_sentinel, store_null, NULL);
1112 current_block_->statements->Add(transition_sentinel_check); 1120 current_block_->statements->Add(transition_sentinel_check);
1113 1121
1114 current_block_->statements->Add( 1122 current_block_->statements->Add(
1115 new ThrowNode(token_pos, 1123 new ThrowNode(token_pos,
1116 new LoadLocalNode(token_pos, catch_excp_var), 1124 new LoadLocalNode(token_pos, catch_excp_var),
1117 new LoadLocalNode(token_pos, catch_trace_var))); 1125 new LoadLocalNode(token_pos, catch_trace_var)));
1118 current_block_->statements->Add(
1119 new JumpNode(token_pos, Token::kCONTINUE, end_catch_label));
1120 SequenceNode* catch_clause = CloseBlock(); // End catch clause. 1126 SequenceNode* catch_clause = CloseBlock(); // End catch clause.
1121 1127
1122 current_block_->statements->Add(catch_clause); 1128 current_block_->statements->Add(catch_clause);
1123 SequenceNode* catch_handler_list = CloseBlock(); // End catch handler list. 1129 SequenceNode* catch_handler_list = CloseBlock(); // End catch handler list.
1124 CatchClauseNode* catch_block = 1130 CatchClauseNode* catch_block =
1125 new CatchClauseNode(token_pos, 1131 new CatchClauseNode(token_pos,
1126 catch_handler_list, 1132 catch_handler_list,
1127 Array::ZoneHandle(Object::empty_array().raw()), 1133 Array::ZoneHandle(Object::empty_array().raw()),
1128 context_var, 1134 context_var,
1129 catch_excp_var, 1135 catch_excp_var,
1130 catch_trace_var, 1136 catch_trace_var,
1131 CatchClauseNode::kInvalidTryIndex, 1137 CatchClauseNode::kInvalidTryIndex,
1132 false); // No stack trace needed. 1138 false); // No stack trace needed.
1133 1139
1134 AstNode* try_catch_node = new TryCatchNode(token_pos, 1140 AstNode* try_catch_node = new TryCatchNode(token_pos,
1135 try_block, 1141 try_block,
1136 end_catch_label,
1137 context_var, 1142 context_var,
1138 catch_block, 1143 catch_block,
1139 NULL, // No finally block. 1144 NULL, // No finally block.
1140 AllocateTryIndex()); 1145 AllocateTryIndex());
1141 current_block_->statements->Add(try_catch_node); 1146 current_block_->statements->Add(try_catch_node);
1142 return CloseBlock(); 1147 return CloseBlock();
1143 } 1148 }
1144 1149
1145 1150
1146 // Create AstNodes for an implicit instance getter method: 1151 // Create AstNodes for an implicit instance getter method:
(...skipping 5491 matching lines...) Expand 10 before | Expand all | Expand 10 after
6638 condition = InsertClosureCallNodes(condition); 6643 condition = InsertClosureCallNodes(condition);
6639 condition = new UnaryOpNode(condition_pos, Token::kNOT, condition); 6644 condition = new UnaryOpNode(condition_pos, Token::kNOT, condition);
6640 AstNode* assert_throw = MakeAssertCall(condition_pos, condition_end); 6645 AstNode* assert_throw = MakeAssertCall(condition_pos, condition_end);
6641 return new IfNode(condition_pos, 6646 return new IfNode(condition_pos,
6642 condition, 6647 condition,
6643 NodeAsSequenceNode(condition_pos, assert_throw, NULL), 6648 NodeAsSequenceNode(condition_pos, assert_throw, NULL),
6644 NULL); 6649 NULL);
6645 } 6650 }
6646 6651
6647 6652
6648 struct CatchParamDesc { 6653 struct CatchParameter {
hausner 2013/11/12 19:21:45 Please do not rename CatchParamDesc. I understand
Kevin Millikin (Google) 2013/11/13 13:47:02 I changed it back, but it's not *just* a matter of
6649 CatchParamDesc() 6654 CatchParameter()
6650 : token_pos(0), type(NULL), var(NULL) { } 6655 : token_pos(0), type(NULL), name(NULL), var(NULL) { }
6651 intptr_t token_pos; 6656 intptr_t token_pos;
6652 const AbstractType* type; 6657 const AbstractType* type;
6653 const String* var; 6658 const String* name;
6659 LocalVariable* var;
6654 }; 6660 };
6655 6661
6656 6662
6657 // Populate local scope of the catch block with the catch parameters. 6663 // Populate local scope of the catch block with the catch parameters.
6658 void Parser::AddCatchParamsToScope(const CatchParamDesc& exception_param, 6664 void Parser::AddCatchParamsToScope(CatchParameter* exception_param,
6659 const CatchParamDesc& stack_trace_param, 6665 CatchParameter* stack_trace_param,
6660 LocalScope* scope) { 6666 LocalScope* scope) {
6661 if (exception_param.var != NULL) { 6667 if (exception_param->name != NULL) {
6662 LocalVariable* var = new LocalVariable(exception_param.token_pos, 6668 LocalVariable* var = new LocalVariable(exception_param->token_pos,
6663 *exception_param.var, 6669 *exception_param->name,
6664 *exception_param.type); 6670 *exception_param->type);
6665 var->set_is_final(); 6671 var->set_is_final();
6666 bool added_to_scope = scope->AddVariable(var); 6672 bool added_to_scope = scope->AddVariable(var);
6667 ASSERT(added_to_scope); 6673 ASSERT(added_to_scope);
6674 exception_param->var = var;
6668 } 6675 }
6669 if (stack_trace_param.var != NULL) { 6676 if (stack_trace_param->name != NULL) {
6670 LocalVariable* var = new LocalVariable(TokenPos(), 6677 LocalVariable* var = new LocalVariable(stack_trace_param->token_pos,
6671 *stack_trace_param.var, 6678 *stack_trace_param->name,
6672 *stack_trace_param.type); 6679 *stack_trace_param->type);
6673 var->set_is_final(); 6680 var->set_is_final();
6674 bool added_to_scope = scope->AddVariable(var); 6681 bool added_to_scope = scope->AddVariable(var);
6675 if (!added_to_scope) { 6682 if (!added_to_scope) {
6676 ErrorMsg(stack_trace_param.token_pos, 6683 ErrorMsg(stack_trace_param->token_pos,
6677 "name '%s' already exists in scope", 6684 "name '%s' already exists in scope",
6678 stack_trace_param.var->ToCString()); 6685 stack_trace_param->name->ToCString());
6679 } 6686 }
6687 stack_trace_param->var = var;
6680 } 6688 }
6681 } 6689 }
6682 6690
6683 6691
6684 SequenceNode* Parser::ParseFinallyBlock() { 6692 SequenceNode* Parser::ParseFinallyBlock() {
6685 TRACE_PARSER("ParseFinallyBlock"); 6693 TRACE_PARSER("ParseFinallyBlock");
6686 OpenBlock(); 6694 OpenBlock();
6687 ExpectToken(Token::kLBRACE); 6695 ExpectToken(Token::kLBRACE);
6688 ParseStatementSequence(); 6696 ParseStatementSequence();
6689 ExpectToken(Token::kRBRACE); 6697 ExpectToken(Token::kRBRACE);
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
6738 InlinedFinallyNode* finally_node) { 6746 InlinedFinallyNode* finally_node) {
6739 if (node->IsReturnNode()) { 6747 if (node->IsReturnNode()) {
6740 node->AsReturnNode()->AddInlinedFinallyNode(finally_node); 6748 node->AsReturnNode()->AddInlinedFinallyNode(finally_node);
6741 } else { 6749 } else {
6742 ASSERT(node->IsJumpNode()); 6750 ASSERT(node->IsJumpNode());
6743 node->AsJumpNode()->AddInlinedFinallyNode(finally_node); 6751 node->AsJumpNode()->AddInlinedFinallyNode(finally_node);
6744 } 6752 }
6745 } 6753 }
6746 6754
6747 6755
6748 AstNode* Parser::ParseTryStatement(String* label_name) { 6756 SequenceNode* Parser::ParseCatchClauses(
6749 TRACE_PARSER("ParseTryStatement"); 6757 intptr_t handler_pos,
6750 6758 LocalVariable* exception_var,
6751 // We create three stack slots for exceptions here: 6759 LocalVariable* stack_trace_var,
6752 // ':saved_try_context_var' - Used to save the context before start of the try 6760 const GrowableObjectArray& handler_types,
6753 // block. The context register is restored from 6761 bool* needs_stack_trace) {
6754 // this slot before processing the catch block 6762 // All catch blocks are merged into an if-then-else sequence of the
6755 // handler. 6763 // different types specified using the 'is' operator. While parsing
6756 // ':exception_var' - Used to save the current exception object that was 6764 // record the type tests (either a ComparisonNode or else the LiteralNode
6757 // thrown. 6765 // true for a generic catch) and the catch bodies in a pair of parallel
6758 // ':stacktrace_var' - Used to save the current stack trace object into which 6766 // lists. Afterward, construct the nested if-then-else.
6759 // the stack trace was copied into when an exception was 6767 GrowableArray<AstNode*> type_tests;
6760 // thrown. 6768 GrowableArray<SequenceNode*> catch_blocks;
6761 // :exception_var and :stacktrace_var get set with the exception object 6769 while ((CurrentToken() == Token::kCATCH) || IsLiteral("on")) {
6762 // and the stacktrace object when an exception is thrown. 6770 // Open a block that contains the if or an unconditional body. It's
6763 // These three implicit variables can never be captured variables. 6771 // closed in the loop that builds the if-then-else nest.
6764 LocalVariable* context_var =
6765 current_block_->scope->LocalLookupVariable(Symbols::SavedTryContextVar());
6766 if (context_var == NULL) {
6767 context_var = new LocalVariable(TokenPos(),
6768 Symbols::SavedTryContextVar(),
6769 Type::ZoneHandle(Type::DynamicType()));
6770 current_block_->scope->AddVariable(context_var);
6771 }
6772 LocalVariable* catch_excp_var =
6773 current_block_->scope->LocalLookupVariable(Symbols::ExceptionVar());
6774 if (catch_excp_var == NULL) {
6775 catch_excp_var = new LocalVariable(TokenPos(),
6776 Symbols::ExceptionVar(),
6777 Type::ZoneHandle(Type::DynamicType()));
6778 current_block_->scope->AddVariable(catch_excp_var);
6779 }
6780 LocalVariable* catch_trace_var =
6781 current_block_->scope->LocalLookupVariable(Symbols::StacktraceVar());
6782 if (catch_trace_var == NULL) {
6783 catch_trace_var = new LocalVariable(TokenPos(),
6784 Symbols::StacktraceVar(),
6785 Type::ZoneHandle(Type::DynamicType()));
6786 current_block_->scope->AddVariable(catch_trace_var);
6787 }
6788
6789 const intptr_t try_pos = TokenPos();
6790 ConsumeToken(); // Consume the 'try'.
6791
6792 SourceLabel* try_label = NULL;
6793 if (label_name != NULL) {
6794 try_label = SourceLabel::New(try_pos, label_name, SourceLabel::kStatement);
6795 OpenBlock(); 6772 OpenBlock();
6796 current_block_->scope->AddLabel(try_label);
6797 }
6798
6799 // Now parse the 'try' block.
6800 OpenBlock();
6801 PushTryBlock(current_block_);
6802 ExpectToken(Token::kLBRACE);
6803 ParseStatementSequence();
6804 ExpectToken(Token::kRBRACE);
6805 SequenceNode* try_block = CloseBlock();
6806
6807 if ((CurrentToken() != Token::kCATCH) && !IsLiteral("on") &&
6808 (CurrentToken() != Token::kFINALLY)) {
6809 ErrorMsg("catch or finally clause expected");
6810 }
6811
6812 // Now create a label for the end of catch block processing so that we can
6813 // jump over the catch block code after executing the try block.
6814 SourceLabel* end_catch_label =
6815 SourceLabel::New(TokenPos(), NULL, SourceLabel::kCatch);
6816
6817 // Now parse the 'catch' blocks if any and merge all of them into
6818 // an if-then sequence of the different types specified using the 'is'
6819 // operator.
6820 bool generic_catch_seen = false;
6821 const intptr_t handler_pos = TokenPos();
6822 OpenBlock(); // Start the catch block sequence.
6823 current_block_->scope->AddLabel(end_catch_label);
6824 const GrowableObjectArray& handler_types =
6825 GrowableObjectArray::Handle(GrowableObjectArray::New());
6826 bool needs_stacktrace = false;
6827 while ((CurrentToken() == Token::kCATCH) || IsLiteral("on")) {
6828 const intptr_t catch_pos = TokenPos(); 6773 const intptr_t catch_pos = TokenPos();
6829 CatchParamDesc exception_param; 6774 CatchParameter exception_param;
6830 CatchParamDesc stack_trace_param; 6775 CatchParameter stack_trace_param;
6831 if (IsLiteral("on")) { 6776 if (IsLiteral("on")) {
6832 ConsumeToken(); 6777 ConsumeToken();
6833 exception_param.type = &AbstractType::ZoneHandle( 6778 exception_param.type = &AbstractType::ZoneHandle(
6834 ParseType(ClassFinalizer::kCanonicalize)); 6779 ParseType(ClassFinalizer::kCanonicalize));
6835 } else { 6780 } else {
6836 exception_param.type = &AbstractType::ZoneHandle(Type::DynamicType()); 6781 exception_param.type = &AbstractType::ZoneHandle(Type::DynamicType());
6837 } 6782 }
6838 if (CurrentToken() == Token::kCATCH) { 6783 if (CurrentToken() == Token::kCATCH) {
6839 ConsumeToken(); // Consume the 'catch'. 6784 ConsumeToken(); // Consume the 'catch'.
6840 ExpectToken(Token::kLPAREN); 6785 ExpectToken(Token::kLPAREN);
6841 exception_param.token_pos = TokenPos(); 6786 exception_param.token_pos = TokenPos();
6842 exception_param.var = ExpectIdentifier("identifier expected"); 6787 exception_param.name = ExpectIdentifier("identifier expected");
6843 if (CurrentToken() == Token::kCOMMA) { 6788 if (CurrentToken() == Token::kCOMMA) {
6844 ConsumeToken(); 6789 ConsumeToken();
6845 // TODO(hausner): Make implicit type be StackTrace, not dynamic. 6790 // TODO(hausner): Make implicit type be StackTrace, not dynamic.
6846 stack_trace_param.type = 6791 stack_trace_param.type =
6847 &AbstractType::ZoneHandle(Type::DynamicType()); 6792 &AbstractType::ZoneHandle(Type::DynamicType());
6848 stack_trace_param.token_pos = TokenPos(); 6793 stack_trace_param.token_pos = TokenPos();
6849 stack_trace_param.var = ExpectIdentifier("identifier expected"); 6794 stack_trace_param.name = ExpectIdentifier("identifier expected");
6850 } 6795 }
6851 ExpectToken(Token::kRPAREN); 6796 ExpectToken(Token::kRPAREN);
6852 } 6797 }
6853 6798
6854 // Create a block containing the catch clause parameters and 6799 // Create a block containing the catch clause parameters and the
6855 // the following code: 6800 // following code:
6856 // 1) Store exception object and stack trace object into user-defined 6801 // 1) Store exception object and stack trace object into user-defined
6857 // variables (as needed). 6802 // variables (as needed).
6858 // 2) Nested block with source code from catch clause block. 6803 // 2) Nested block with source code from catch clause block.
6859 // 3) Unconditional JUMP to the end of the try block.
6860 OpenBlock(); 6804 OpenBlock();
hausner 2013/11/12 01:12:10 You are nesting 3 blocks now per case clause: one
hausner 2013/11/12 19:21:45 Ok, I get it now.
6861 AddCatchParamsToScope(exception_param, 6805 AddCatchParamsToScope(&exception_param, &stack_trace_param,
6862 stack_trace_param,
6863 current_block_->scope); 6806 current_block_->scope);
6864 6807
6865 if (exception_param.var != NULL) { 6808 if (exception_param.var != NULL) {
6866 // Generate code to load the exception object (:exception_var) into 6809 // Generate code to load the exception object (:exception_var) into
6867 // the exception variable specified in this block. 6810 // the exception variable specified in this block.
6868 LocalVariable* var = LookupLocalScope(*exception_param.var); 6811 ASSERT(exception_var != NULL);
6869 ASSERT(var != NULL);
6870 ASSERT(catch_excp_var != NULL);
6871 current_block_->statements->Add( 6812 current_block_->statements->Add(
6872 new StoreLocalNode(catch_pos, var, 6813 new StoreLocalNode(catch_pos, exception_param.var,
6873 new LoadLocalNode(catch_pos, catch_excp_var))); 6814 new LoadLocalNode(catch_pos, exception_var)));
6874 } 6815 }
6875 if (stack_trace_param.var != NULL) { 6816 if (stack_trace_param.var != NULL) {
6876 // A stack trace variable is specified in this block, so generate code 6817 // A stack trace variable is specified in this block, so generate code
6877 // to load the stack trace object (:stacktrace_var) into the stack trace 6818 // to load the stack trace object (:stack_trace_var) into the stack
6878 // variable specified in this block. 6819 // trace variable specified in this block.
6879 needs_stacktrace = true; 6820 *needs_stack_trace = true;
6880 ArgumentListNode* no_args = new ArgumentListNode(catch_pos); 6821 ArgumentListNode* no_args = new ArgumentListNode(catch_pos);
6881 LocalVariable* trace = LookupLocalScope(*stack_trace_param.var); 6822 ASSERT(stack_trace_var != NULL);
6882 ASSERT(catch_trace_var != NULL);
6883 current_block_->statements->Add( 6823 current_block_->statements->Add(
6884 new StoreLocalNode(catch_pos, trace, 6824 new StoreLocalNode(catch_pos, stack_trace_param.var,
6885 new LoadLocalNode(catch_pos, catch_trace_var))); 6825 new LoadLocalNode(catch_pos, stack_trace_var)));
6886 current_block_->statements->Add( 6826 current_block_->statements->Add(
6887 new InstanceCallNode( 6827 new InstanceCallNode(
6888 catch_pos, 6828 catch_pos,
6889 new LoadLocalNode(catch_pos, trace), 6829 new LoadLocalNode(catch_pos, stack_trace_param.var),
6890 Library::PrivateCoreLibName(Symbols::_setupFullStackTrace()), 6830 Library::PrivateCoreLibName(Symbols::_setupFullStackTrace()),
6891 no_args)); 6831 no_args));
6892 } 6832 }
6893 6833
6894 // Add nested block with user-defined code. 6834 // Add nested block with user-defined code. This blocks allows
6835 // declarations in the body to shadow the catch parameters.
6895 CheckToken(Token::kLBRACE); 6836 CheckToken(Token::kLBRACE);
6896 current_block_->statements->Add(ParseNestedStatement(false, NULL)); 6837 current_block_->statements->Add(ParseNestedStatement(false, NULL));
6897 6838 catch_blocks.Add(CloseBlock());
6898 // Add unconditional jump to end of catch clause list. 6839
6899 current_block_->statements->Add( 6840 const bool is_bad_type =
6900 new JumpNode(catch_pos, Token::kCONTINUE, end_catch_label)); 6841 exception_param.type->IsMalformed() ||
6901 6842 exception_param.type->IsMalbounded();
6902 SequenceNode* catch_clause = CloseBlock(); 6843 if (exception_param.type->IsDynamicType() || is_bad_type) {
6903 6844 // There is no exception type or else it is malformed or malbounded.
6904 const bool is_bad_type = exception_param.type->IsMalformed() || 6845 // In the first cast, unconditionally execute the catch body. In the
hausner 2013/11/12 01:12:10 case
Kevin Millikin (Google) 2013/11/13 13:47:02 Done.
6905 exception_param.type->IsMalbounded(); 6846 // second case, unconditionally throw.
6906 if (!is_bad_type && !exception_param.type->IsDynamicType()) { 6847 type_tests.Add(new LiteralNode(catch_pos, Bool::True()));
6907 // Has a type specification that is not malformed or malbounded. 6848 if (is_bad_type) {
6908 // Now form an 'if type check' to guard the catch handler code. 6849 // Replace the body with one that throws.
6850 SequenceNode* block = new SequenceNode(catch_pos, NULL);
6851 block->Add(ThrowTypeError(catch_pos, *exception_param.type));
6852 catch_blocks.Last() = block;
6853 }
6854 // This catch clause will handle all exceptions. We can safely forget
6855 // all previous catch clause types.
6856 handler_types.SetLength(0);
hausner 2013/11/12 19:21:45 Remember here with a bool variable that we've seen
Kevin Millikin (Google) 2013/11/13 13:47:02 Done.
6857 handler_types.Add(*exception_param.type);
6858 } else {
6859 // Has a type specification that is not malformed or malbounded. Now
6860 // form an 'if type check' to guard the catch handler code.
6909 if (!exception_param.type->IsInstantiated() && 6861 if (!exception_param.type->IsInstantiated() &&
6910 (current_block_->scope->function_level() > 0)) { 6862 (current_block_->scope->function_level() > 0)) {
6911 // Make sure that the instantiator is captured. 6863 // Make sure that the instantiator is captured.
6912 CaptureInstantiator(); 6864 CaptureInstantiator();
6913 } 6865 }
6914 TypeNode* exception_type = new TypeNode(catch_pos, *exception_param.type); 6866 TypeNode* exception_type = new TypeNode(catch_pos, *exception_param.type);
6915 AstNode* exception_var = new LoadLocalNode(catch_pos, catch_excp_var); 6867 AstNode* exception_value = new LoadLocalNode(catch_pos, exception_var);
6916 if (!exception_type->type().IsInstantiated()) { 6868 if (!exception_type->type().IsInstantiated()) {
6917 EnsureExpressionTemp(); 6869 EnsureExpressionTemp();
6918 } 6870 }
6919 AstNode* type_cond_expr = new ComparisonNode( 6871 type_tests.Add(new ComparisonNode(catch_pos, Token::kIS, exception_value,
6920 catch_pos, Token::kIS, exception_var, exception_type); 6872 exception_type));
6921 current_block_->statements->Add( 6873
6922 new IfNode(catch_pos, type_cond_expr, catch_clause, NULL)); 6874 // Do not add uninstantiated types (e.g. type parameter T or generic
6923 6875 // type List<T>), since the debugger won't be able to instantiate it
6924 // Do not add uninstantiated types (e.g. type parameter T or 6876 // when walking the stack.
6925 // generic type List<T>), since the debugger won't be able to 6877 //
6926 // instantiate it when walking the stack. 6878 // This means that the debugger is not able to determine whether an
6927 // This means that the debugger is not able to determine whether 6879 // exception is caught if the catch clause uses generic types. It
6928 // an exception is caught if the catch clause uses generic types. 6880 // will report the exception as uncaught when in fact it might be
6929 // It will report the exception as uncaught when in fact it might 6881 // caught and handled when we unwind the stack.
6930 // be caught and handled when we unwind the stack.
6931 if (exception_param.type->IsInstantiated()) { 6882 if (exception_param.type->IsInstantiated()) {
hausner 2013/11/12 19:21:45 Also guard this with the boolean flag so that no m
Kevin Millikin (Google) 2013/11/13 13:47:02 Done.
6932 handler_types.Add(*exception_param.type); 6883 handler_types.Add(*exception_param.type);
6933 } 6884 }
6934 } else { 6885 }
6935 if (is_bad_type) { 6886
6936 current_block_->statements->Add(ThrowTypeError(catch_pos, 6887 ASSERT(type_tests.length() == catch_blocks.length());
6937 *exception_param.type)); 6888 }
6938 // We still add the dead code below to satisfy the code generator. 6889
6939 } 6890 // Build the if/then/else nest from the inside out. Keep the AST simple
6940 // No exception type exists in the catch clause so execute the 6891 // for the case of a single generic catch clause.
6941 // catch handler code unconditionally. 6892 SequenceNode* current = NULL;
6942 current_block_->statements->Add(catch_clause); 6893 if (type_tests.is_empty() || !type_tests.Last()->IsLiteralNode()) {
hausner 2013/11/12 19:21:45 You can use the "catch all seen" flag to determine
6943 generic_catch_seen = true; 6894 // Create a clause body that rethrows the exception if there are no
6944 // This catch clause will handle all exceptions. We can safely forget 6895 // catch clauses or if the last clause is not entered unconditionally.
6945 // all previous catch clause types. 6896 // In the second case, this body is the last (innermost) else block.
6946 handler_types.SetLength(0); 6897 current = new SequenceNode(handler_pos, NULL);
6947 handler_types.Add(*exception_param.type); 6898 current->Add(
6948 } 6899 new ThrowNode(handler_pos,
6949 } 6900 new LoadLocalNode(handler_pos, exception_var),
6950 6901 new LoadLocalNode(handler_pos, stack_trace_var)));
6951 SequenceNode* catch_handler_list = CloseBlock(); 6902 } else {
6903 ASSERT(type_tests.Last()->AsLiteralNode()->literal().raw() ==
6904 Bool::True().raw());
6905 // The last body is entered unconditionally. Start building the
6906 // if/then/else nest with that body as the innermost else block.
6907 // Note that it is nested inside an extra block which we opened
6908 // before we knew the body was entered unconditionally.
6909 type_tests.RemoveLast();
6910 current_block_->statements->Add(catch_blocks.RemoveLast());
6911 current = CloseBlock();
6912 }
6913
6914 while (!type_tests.is_empty()) {
6915 AstNode* type_test = type_tests.RemoveLast();
6916 SequenceNode* catch_block = catch_blocks.RemoveLast();
6917 current_block_->statements->Add(
6918 new IfNode(type_test->token_pos(), type_test, catch_block, current));
6919 current = CloseBlock();
6920 }
6921 return current;
6922 }
6923
6924
6925 AstNode* Parser::ParseTryStatement(String* label_name) {
6926 TRACE_PARSER("ParseTryStatement");
6927
6928 // We create three variables for exceptions here:
6929 // ':saved_try_context_var' - Used to save the context before the start of
6930 // the try block. The context register is
6931 // restored from this variable before
6932 // processing the catch block handler.
6933 // ':exception_var' - Used to save the current exception object that was
6934 // thrown.
6935 // ':stack_trace_var' - Used to save the current stack trace object which
6936 // the stack trace was copied into when an exception
6937 // was thrown.
6938 // :exception_var and :stack_trace_var get set with the exception object
6939 // and the stack trace object when an exception is thrown. These three
6940 // implicit variables can never be captured.
6941 LocalVariable* context_var =
6942 current_block_->scope->LocalLookupVariable(Symbols::SavedTryContextVar());
6943 if (context_var == NULL) {
6944 context_var = new LocalVariable(TokenPos(),
6945 Symbols::SavedTryContextVar(),
6946 Type::ZoneHandle(Type::DynamicType()));
6947 current_block_->scope->AddVariable(context_var);
6948 }
6949 LocalVariable* exception_var =
6950 current_block_->scope->LocalLookupVariable(Symbols::ExceptionVar());
6951 if (exception_var == NULL) {
6952 exception_var = new LocalVariable(TokenPos(),
6953 Symbols::ExceptionVar(),
6954 Type::ZoneHandle(Type::DynamicType()));
6955 current_block_->scope->AddVariable(exception_var);
6956 }
6957 LocalVariable* stack_trace_var =
6958 current_block_->scope->LocalLookupVariable(Symbols::StackTraceVar());
6959 if (stack_trace_var == NULL) {
6960 stack_trace_var = new LocalVariable(TokenPos(),
6961 Symbols::StackTraceVar(),
6962 Type::ZoneHandle(Type::DynamicType()));
6963 current_block_->scope->AddVariable(stack_trace_var);
6964 }
6965
6966 const intptr_t try_pos = TokenPos();
6967 ConsumeToken(); // Consume the 'try'.
6968
6969 SourceLabel* try_label = NULL;
6970 if (label_name != NULL) {
6971 try_label = SourceLabel::New(try_pos, label_name, SourceLabel::kStatement);
6972 OpenBlock();
6973 current_block_->scope->AddLabel(try_label);
6974 }
6975
6976 // Now parse the 'try' block.
6977 OpenBlock();
6978 PushTryBlock(current_block_);
6979 ExpectToken(Token::kLBRACE);
6980 ParseStatementSequence();
6981 ExpectToken(Token::kRBRACE);
6982 SequenceNode* try_block = CloseBlock();
6983
6984 if ((CurrentToken() != Token::kCATCH) && !IsLiteral("on") &&
6985 (CurrentToken() != Token::kFINALLY)) {
6986 ErrorMsg("catch or finally clause expected");
6987 }
6988
6989 // Now parse the 'catch' blocks if any.
6990 try_blocks_list_->enter_catch();
6991 const intptr_t handler_pos = TokenPos();
6992 const GrowableObjectArray& handler_types =
6993 GrowableObjectArray::Handle(GrowableObjectArray::New());
6994 bool needs_stack_trace = false;
6995 SequenceNode* catch_handler_list =
6996 ParseCatchClauses(handler_pos, exception_var, stack_trace_var,
6997 handler_types, &needs_stack_trace);
6998
6952 TryBlocks* inner_try_block = PopTryBlock(); 6999 TryBlocks* inner_try_block = PopTryBlock();
6953 const intptr_t try_index = inner_try_block->try_index(); 7000 const intptr_t try_index = inner_try_block->try_index();
6954 TryBlocks* outer_try_block = try_blocks_list_; 7001 TryBlocks* outer_try_block = try_blocks_list_;
6955 const intptr_t outer_try_index = (outer_try_block != NULL) 7002 const intptr_t outer_try_index = (outer_try_block != NULL)
6956 ? outer_try_block->try_index() 7003 ? outer_try_block->try_index()
6957 : CatchClauseNode::kInvalidTryIndex; 7004 : CatchClauseNode::kInvalidTryIndex;
6958 7005
6959 // Finally parse the 'finally' block. 7006 // Finally parse the 'finally' block.
6960 SequenceNode* finally_block = NULL; 7007 SequenceNode* finally_block = NULL;
6961 if (CurrentToken() == Token::kFINALLY) { 7008 if (CurrentToken() == Token::kFINALLY) {
(...skipping 11 matching lines...) Expand all
6973 context_var, 7020 context_var,
6974 outer_try_index); 7021 outer_try_index);
6975 AddFinallyBlockToNode(node_to_inline, node); 7022 AddFinallyBlockToNode(node_to_inline, node);
6976 node_index += 1; 7023 node_index += 1;
6977 node_to_inline = inner_try_block->GetNodeToInlineFinally(node_index); 7024 node_to_inline = inner_try_block->GetNodeToInlineFinally(node_index);
6978 tokens_iterator_.SetCurrentPosition(finally_pos); 7025 tokens_iterator_.SetCurrentPosition(finally_pos);
6979 } 7026 }
6980 finally_block = ParseFinallyBlock(); 7027 finally_block = ParseFinallyBlock();
6981 } 7028 }
6982 7029
6983 if (!generic_catch_seen) { 7030 CatchClauseNode* catch_clause =
6984 // No generic catch handler exists so rethrow the exception so that
6985 // the next catch handler can deal with it.
6986 catch_handler_list->Add(
6987 new ThrowNode(handler_pos,
6988 new LoadLocalNode(handler_pos, catch_excp_var),
6989 new LoadLocalNode(handler_pos, catch_trace_var)));
6990 }
6991 CatchClauseNode* catch_block =
6992 new CatchClauseNode(handler_pos, 7031 new CatchClauseNode(handler_pos,
6993 catch_handler_list, 7032 catch_handler_list,
6994 Array::ZoneHandle(Array::MakeArray(handler_types)), 7033 Array::ZoneHandle(Array::MakeArray(handler_types)),
6995 context_var, 7034 context_var,
6996 catch_excp_var, 7035 exception_var,
6997 catch_trace_var, 7036 stack_trace_var,
6998 (finally_block != NULL) 7037 (finally_block != NULL)
6999 ? AllocateTryIndex() 7038 ? AllocateTryIndex()
7000 : CatchClauseNode::kInvalidTryIndex, 7039 : CatchClauseNode::kInvalidTryIndex,
7001 needs_stacktrace); 7040 needs_stack_trace);
7002 7041
7003 // Now create the try/catch ast node and return it. If there is a label 7042 // Now create the try/catch ast node and return it. If there is a label
7004 // on the try/catch, close the block that's embedding the try statement 7043 // on the try/catch, close the block that's embedding the try statement
7005 // and attach the label to it. 7044 // and attach the label to it.
7006 AstNode* try_catch_node = 7045 AstNode* try_catch_node =
7007 new TryCatchNode(try_pos, try_block, end_catch_label, 7046 new TryCatchNode(try_pos, try_block, context_var, catch_clause,
7008 context_var, catch_block, finally_block, try_index); 7047 finally_block, try_index);
7009 7048
7010 if (try_label != NULL) { 7049 if (try_label != NULL) {
7011 current_block_->statements->Add(try_catch_node); 7050 current_block_->statements->Add(try_catch_node);
7012 SequenceNode* sequence = CloseBlock(); 7051 SequenceNode* sequence = CloseBlock();
7013 sequence->set_label(try_label); 7052 sequence->set_label(try_label);
7014 try_catch_node = sequence; 7053 try_catch_node = sequence;
7015 } 7054 }
7016 return try_catch_node; 7055 return try_catch_node;
7017 } 7056 }
7018 7057
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
7155 AddNodeForFinallyInlining(statement); 7194 AddNodeForFinallyInlining(statement);
7156 ExpectSemicolon(); 7195 ExpectSemicolon();
7157 } else if (CurrentToken() == Token::kSEMICOLON) { 7196 } else if (CurrentToken() == Token::kSEMICOLON) {
7158 // Empty statement, nothing to do. 7197 // Empty statement, nothing to do.
7159 ConsumeToken(); 7198 ConsumeToken();
7160 } else if (CurrentToken() == Token::kRETHROW) { 7199 } else if (CurrentToken() == Token::kRETHROW) {
7161 // Rethrow of current exception. 7200 // Rethrow of current exception.
7162 ConsumeToken(); 7201 ConsumeToken();
7163 ExpectSemicolon(); 7202 ExpectSemicolon();
7164 // Check if it is ok to do a rethrow. 7203 // Check if it is ok to do a rethrow.
7165 SourceLabel* label = current_block_->scope->LookupInnermostCatchLabel(); 7204 if ((try_blocks_list_ == NULL) || !try_blocks_list_->inside_catch()) {
hausner 2013/11/12 19:21:45 I think you can eliminate the LookupInnermostCatch
Kevin Millikin (Google) 2013/11/13 13:47:02 Yes, thank you. Done.
7166 if (label == NULL ||
7167 label->FunctionLevel() != current_block_->scope->function_level()) {
7168 ErrorMsg(statement_pos, "rethrow of an exception is not valid here"); 7205 ErrorMsg(statement_pos, "rethrow of an exception is not valid here");
7169 } 7206 }
7170 ASSERT(label->owner() != NULL); 7207 // The exception and stack trace variables are bound in the block
7171 LocalScope* scope = label->owner()->parent(); 7208 // containing the try.
7209 LocalScope* scope = try_blocks_list_->try_block()->scope->parent();
7172 ASSERT(scope != NULL); 7210 ASSERT(scope != NULL);
7173 LocalVariable* excp_var = 7211 LocalVariable* excp_var =
7174 scope->LocalLookupVariable(Symbols::ExceptionVar()); 7212 scope->LocalLookupVariable(Symbols::ExceptionVar());
7175 ASSERT(excp_var != NULL); 7213 ASSERT(excp_var != NULL);
7176 LocalVariable* trace_var = 7214 LocalVariable* trace_var =
7177 scope->LocalLookupVariable(Symbols::StacktraceVar()); 7215 scope->LocalLookupVariable(Symbols::StackTraceVar());
7178 ASSERT(trace_var != NULL); 7216 ASSERT(trace_var != NULL);
7179 statement = new ThrowNode(statement_pos, 7217 statement = new ThrowNode(statement_pos,
7180 new LoadLocalNode(statement_pos, excp_var), 7218 new LoadLocalNode(statement_pos, excp_var),
7181 new LoadLocalNode(statement_pos, trace_var)); 7219 new LoadLocalNode(statement_pos, trace_var));
7182 } else { 7220 } else {
7183 statement = ParseExpr(kAllowConst, kConsumeCascades); 7221 statement = ParseExpr(kAllowConst, kConsumeCascades);
7184 ExpectSemicolon(); 7222 ExpectSemicolon();
7185 } 7223 }
7186 return statement; 7224 return statement;
7187 } 7225 }
(...skipping 3544 matching lines...) Expand 10 before | Expand all | Expand 10 after
10732 void Parser::SkipQualIdent() { 10770 void Parser::SkipQualIdent() {
10733 ASSERT(IsIdentifier()); 10771 ASSERT(IsIdentifier());
10734 ConsumeToken(); 10772 ConsumeToken();
10735 if (CurrentToken() == Token::kPERIOD) { 10773 if (CurrentToken() == Token::kPERIOD) {
10736 ConsumeToken(); // Consume the kPERIOD token. 10774 ConsumeToken(); // Consume the kPERIOD token.
10737 ExpectIdentifier("identifier expected after '.'"); 10775 ExpectIdentifier("identifier expected after '.'");
10738 } 10776 }
10739 } 10777 }
10740 10778
10741 } // namespace dart 10779 } // 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