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

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

Issue 9443002: Added LongJump for bailout. When trying to fix all crashes, CHECK_ALIVE did not scale well as bail… (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 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
« no previous file with comments | « runtime/vm/flow_graph_builder.h ('k') | no next file » | 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/flow_graph_builder.h" 5 #include "vm/flow_graph_builder.h"
6 6
7 #include "vm/flags.h" 7 #include "vm/flags.h"
8 #include "vm/intermediate_language.h" 8 #include "vm/intermediate_language.h"
9 #include "vm/longjump.h"
9 #include "vm/os.h" 10 #include "vm/os.h"
10 #include "vm/parser.h" 11 #include "vm/parser.h"
11 12
12 namespace dart { 13 namespace dart {
13 14
14 DEFINE_FLAG(bool, trace_bailout, false, "Print bailout from graph builder.");
15 DEFINE_FLAG(bool, print_flow_graph, false, "Print the IR flow graph."); 15 DEFINE_FLAG(bool, print_flow_graph, false, "Print the IR flow graph.");
16 DECLARE_FLAG(bool, enable_type_checks); 16 DECLARE_FLAG(bool, enable_type_checks);
17 17
18 void EffectGraphVisitor::Append(const EffectGraphVisitor& other_fragment) { 18 void EffectGraphVisitor::Append(const EffectGraphVisitor& other_fragment) {
19 ASSERT(is_open()); 19 ASSERT(is_open());
20 if (other_fragment.is_empty()) return; 20 if (other_fragment.is_empty()) return;
21 if (is_empty()) { 21 if (is_empty()) {
22 entry_ = other_fragment.entry(); 22 entry_ = other_fragment.entry();
23 exit_ = other_fragment.exit(); 23 exit_ = other_fragment.exit();
24 } else { 24 } else {
25 exit()->set_successor(other_fragment.entry()); 25 exit()->SetSuccessor(other_fragment.entry());
26 exit_ = other_fragment.exit(); 26 exit_ = other_fragment.exit();
27 } 27 }
28 } 28 }
29 29
30 30
31 void EffectGraphVisitor::AddInstruction(Instruction* instruction) { 31 void EffectGraphVisitor::AddInstruction(Instruction* instruction) {
32 ASSERT(is_open()); 32 ASSERT(is_open());
33 if (is_empty()) { 33 if (is_empty()) {
34 entry_ = exit_ = instruction; 34 entry_ = exit_ = instruction;
35 } else { 35 } else {
36 exit()->set_successor(instruction); 36 exit()->SetSuccessor(instruction);
37 exit_ = instruction; 37 exit_ = instruction;
38 } 38 }
39 } 39 }
40 40
41 41
42 void EffectGraphVisitor::Join(const TestGraphVisitor& test_fragment, 42 void EffectGraphVisitor::Join(const TestGraphVisitor& test_fragment,
43 const EffectGraphVisitor& true_fragment, 43 const EffectGraphVisitor& true_fragment,
44 const EffectGraphVisitor& false_fragment) { 44 const EffectGraphVisitor& false_fragment) {
45 // We have: a test graph fragment with zero, one, or two available exits; 45 // We have: a test graph fragment with zero, one, or two available exits;
46 // and a pair of effect graph fragments with zero or one available exits. 46 // and a pair of effect graph fragments with zero or one available exits.
47 // We want to append the branch and (if necessary) a join node to this 47 // We want to append the branch and (if necessary) a join node to this
48 // graph fragment. 48 // graph fragment.
49 ASSERT(is_open()); 49 ASSERT(is_open());
50 50
51 // 1. Connect the test to this graph. 51 // 1. Connect the test to this graph.
52 Append(test_fragment); 52 Append(test_fragment);
53 53
54 // 2. Connect the true and false bodies to the test if they are reachable, 54 // 2. Connect the true and false bodies to the test if they are reachable,
55 // and if so record their exits (if any). 55 // and if so record their exits (if any).
56 if (test_fragment.can_be_true()) { 56 if (test_fragment.can_be_true()) {
57 Instruction* true_exit = NULL; 57 Instruction* true_exit = NULL;
58 Instruction* false_exit = NULL; 58 Instruction* false_exit = NULL;
59 TargetEntryInstr* true_entry = new TargetEntryInstr(); 59 TargetEntryInstr* true_entry = new TargetEntryInstr();
60 *test_fragment.true_successor_address() = true_entry; 60 *test_fragment.true_successor_address() = true_entry;
61 true_entry->set_successor(true_fragment.entry()); 61 true_entry->SetSuccessor(true_fragment.entry());
62 true_exit = true_fragment.is_empty() ? true_entry : true_fragment.exit(); 62 true_exit = true_fragment.is_empty() ? true_entry : true_fragment.exit();
63 63
64 TargetEntryInstr* false_entry = new TargetEntryInstr(); 64 TargetEntryInstr* false_entry = new TargetEntryInstr();
65 *test_fragment.false_successor_address() = false_entry; 65 *test_fragment.false_successor_address() = false_entry;
66 false_entry->set_successor(false_fragment.entry()); 66 false_entry->SetSuccessor(false_fragment.entry());
67 false_exit = 67 false_exit =
68 false_fragment.is_empty() ? false_entry : false_fragment.exit(); 68 false_fragment.is_empty() ? false_entry : false_fragment.exit();
69 69
70 exit_ = new JoinEntryInstr(); 70 exit_ = new JoinEntryInstr();
71 true_exit->set_successor(exit_); 71 true_exit->SetSuccessor(exit_);
72 false_exit->set_successor(exit_); 72 false_exit->SetSuccessor(exit_);
73 } 73 }
74 } 74 }
75 75
76 76
77 void EffectGraphVisitor::TieLoop(const TestGraphVisitor& test_fragment, 77 void EffectGraphVisitor::TieLoop(const TestGraphVisitor& test_fragment,
78 const EffectGraphVisitor& body_fragment) { 78 const EffectGraphVisitor& body_fragment) {
79 // We have: a test graph fragment with zero, one, or two available exits; 79 // We have: a test graph fragment with zero, one, or two available exits;
80 // and an effect graph fragment with zero or one available exits. We want 80 // and an effect graph fragment with zero or one available exits. We want
81 // to append the 'while loop' consisting of the test graph fragment as 81 // to append the 'while loop' consisting of the test graph fragment as
82 // condition and the effect graph fragment as body. 82 // condition and the effect graph fragment as body.
83 ASSERT(is_open()); 83 ASSERT(is_open());
84 84
85 // 1. Connect the body to the test if it is reachable, and if so record 85 // 1. Connect the body to the test if it is reachable, and if so record
86 // its exit (if any). 86 // its exit (if any).
87 Instruction* body_exit = NULL; 87 Instruction* body_exit = NULL;
88 if (test_fragment.can_be_true()) { 88 if (test_fragment.can_be_true()) {
89 TargetEntryInstr* body_entry = new TargetEntryInstr(); 89 TargetEntryInstr* body_entry = new TargetEntryInstr();
90 *test_fragment.true_successor_address() = body_entry; 90 *test_fragment.true_successor_address() = body_entry;
91 body_entry->set_successor(body_fragment.entry()); 91 body_entry->SetSuccessor(body_fragment.entry());
92 body_exit = body_fragment.is_empty() ? body_entry : body_fragment.exit(); 92 body_exit = body_fragment.is_empty() ? body_entry : body_fragment.exit();
93 } 93 }
94 94
95 // 2. Connect the test to this graph, including the body if reachable and 95 // 2. Connect the test to this graph, including the body if reachable and
96 // using a fresh join node if the body is reachable and has an open exit. 96 // using a fresh join node if the body is reachable and has an open exit.
97 if (body_exit == NULL) { 97 if (body_exit == NULL) {
98 Append(test_fragment); 98 Append(test_fragment);
99 } else { 99 } else {
100 JoinEntryInstr* join = new JoinEntryInstr(); 100 JoinEntryInstr* join = new JoinEntryInstr();
101 AddInstruction(join); 101 AddInstruction(join);
102 join->set_successor(test_fragment.entry()); 102 join->SetSuccessor(test_fragment.entry());
103 body_exit->set_successor(join); 103 body_exit->SetSuccessor(join);
104 } 104 }
105 105
106 // 3. Set the exit to the graph to be empty or a fresh target node 106 // 3. Set the exit to the graph to be empty or a fresh target node
107 // depending on whether the false branch of the test is reachable. 107 // depending on whether the false branch of the test is reachable.
108 if (test_fragment.can_be_false()) { 108 if (test_fragment.can_be_false()) {
109 exit_ = *test_fragment.false_successor_address() = new TargetEntryInstr(); 109 exit_ = *test_fragment.false_successor_address() = new TargetEntryInstr();
110 } else { 110 } else {
111 exit_ = NULL; 111 exit_ = NULL;
112 } 112 }
113 } 113 }
114 114
115 115
116 void TestGraphVisitor::BranchOnValue(Value* value) { 116 void TestGraphVisitor::BranchOnValue(Value* value) {
117 BranchInstr* branch = new BranchInstr(value); 117 BranchInstr* branch = new BranchInstr(value);
118 AddInstruction(branch); 118 AddInstruction(branch);
119 CloseFragment(); 119 CloseFragment();
120 true_successor_address_ = branch->true_successor_address(); 120 true_successor_address_ = branch->true_successor_address();
121 false_successor_address_ = branch->false_successor_address(); 121 false_successor_address_ = branch->false_successor_address();
122 } 122 }
123 123
124 124
125 void EffectGraphVisitor::Bailout(const char* reason) { 125 void EffectGraphVisitor::Bailout(const char* reason) {
126 if (FLAG_trace_bailout) {
127 OS::Print("Flow Graph Bailout: %s\n", reason);
128 }
129 owner()->Bailout(reason); 126 owner()->Bailout(reason);
130 } 127 }
131 128
132 129
133 // 'bailout' is a statement (without a semicolon), typically a return. 130 // 'bailout' is a statement (without a semicolon), typically a return.
134 #define CHECK_ALIVE(bailout) \ 131 #define CHECK_ALIVE(bailout) \
135 do { \ 132 do { \
136 if (owner()->HasBailedOut() || !is_open()) { \ 133 if (!is_open()) { \
137 bailout; \ 134 bailout; \
138 } \ 135 } \
139 } while (false) 136 } while (false)
140 137
141 138
142 // <Statement> ::= Return { value: <Expression> 139 // <Statement> ::= Return { value: <Expression>
143 // inlined_finally_list: <InlinedFinally>* } 140 // inlined_finally_list: <InlinedFinally>* }
144 void EffectGraphVisitor::VisitReturnNode(ReturnNode* node) { 141 void EffectGraphVisitor::VisitReturnNode(ReturnNode* node) {
145 ValueGraphVisitor for_value(owner(), temp_index()); 142 ValueGraphVisitor for_value(owner(), temp_index());
146 node->value()->Visit(&for_value); 143 node->value()->Visit(&for_value);
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 CHECK_ALIVE(return); 227 CHECK_ALIVE(return);
231 BranchOnValueOf(assert); 228 BranchOnValueOf(assert);
232 } 229 }
233 230
234 231
235 // <Expression> :: BinaryOp { kind: Token::Kind 232 // <Expression> :: BinaryOp { kind: Token::Kind
236 // left: <Expression> 233 // left: <Expression>
237 // right: <Expression> } 234 // right: <Expression> }
238 InstanceCallComp* EffectGraphVisitor::TranslateBinaryOp( 235 InstanceCallComp* EffectGraphVisitor::TranslateBinaryOp(
239 const BinaryOpNode& node) { 236 const BinaryOpNode& node) {
237 // Operators "&&" and "||" cannot be overloaded therefore do not call
238 // operator.
240 if ((node.kind() == Token::kAND) || (node.kind() == Token::kOR)) { 239 if ((node.kind() == Token::kAND) || (node.kind() == Token::kOR)) {
241 Bailout("EffectGraphVisitor::VisitBinaryOpNode"); 240 Bailout("EffectGraphVisitor::VisitBinaryOpNode AND/OR");
242 return NULL;
243 } 241 }
244 ValueGraphVisitor for_left_value(owner(), temp_index()); 242 ValueGraphVisitor for_left_value(owner(), temp_index());
245 node.left()->Visit(&for_left_value); 243 node.left()->Visit(&for_left_value);
246 Append(for_left_value); 244 Append(for_left_value);
247 CHECK_ALIVE(return NULL); 245 CHECK_ALIVE(return NULL);
248 ValueGraphVisitor for_right_value(owner(), for_left_value.temp_index()); 246 ValueGraphVisitor for_right_value(owner(), for_left_value.temp_index());
249 node.right()->Visit(&for_right_value); 247 node.right()->Visit(&for_right_value);
250 Append(for_right_value); 248 Append(for_right_value);
251 CHECK_ALIVE(return NULL); 249 CHECK_ALIVE(return NULL);
252 ZoneGrowableArray<Value*>* arguments = new ZoneGrowableArray<Value*>(2); 250 ZoneGrowableArray<Value*>* arguments = new ZoneGrowableArray<Value*>(2);
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
321 ReturnValueOf(call); 319 ReturnValueOf(call);
322 } 320 }
323 321
324 void TestGraphVisitor::VisitComparisonNode(ComparisonNode* node) { 322 void TestGraphVisitor::VisitComparisonNode(ComparisonNode* node) {
325 InstanceCallComp* call = TranslateComparison(*node); 323 InstanceCallComp* call = TranslateComparison(*node);
326 CHECK_ALIVE(return); 324 CHECK_ALIVE(return);
327 BranchOnValueOf(call); 325 BranchOnValueOf(call);
328 } 326 }
329 327
330 328
329
330 InstanceCallComp* EffectGraphVisitor::TranslateUnaryOp(
331 const UnaryOpNode& node) {
332 // "!" cannot be overloaded, therefore do not call operator.
333 if (node.kind() == Token::kNOT) {
334 Bailout("EffectGraphVisitor::VisitUnaryOpNode NOT");
335 }
336 ValueGraphVisitor for_value(owner(), temp_index());
337 node.operand()->Visit(&for_value);
338 Append(for_value);
339 ZoneGrowableArray<Value*>* argument = new ZoneGrowableArray<Value*>(1);
340 argument->Add(for_value.value());
341 return new InstanceCallComp(node.Name(), argument);
Kevin Millikin (Google) 2012/02/23 09:31:43 We might want to make the InstanceCallComp (and ot
srdjan 2012/02/23 16:06:12 I do not think that cost of allocating ZoneGrowabl
342 }
343
344
331 void EffectGraphVisitor::VisitUnaryOpNode(UnaryOpNode* node) { 345 void EffectGraphVisitor::VisitUnaryOpNode(UnaryOpNode* node) {
332 Bailout("EffectGraphVisitor::VisitUnaryOpNode"); 346 InstanceCallComp* call = TranslateUnaryOp(*node);
347 DoComputation(call);
333 } 348 }
334 void ValueGraphVisitor::VisitUnaryOpNode(UnaryOpNode* node) { 349 void ValueGraphVisitor::VisitUnaryOpNode(UnaryOpNode* node) {
335 Bailout("ValueGraphVisitor::VisitUnaryOpNode"); 350 InstanceCallComp* call = TranslateUnaryOp(*node);
351 ReturnValueOf(call);
336 } 352 }
337 void TestGraphVisitor::VisitUnaryOpNode(UnaryOpNode* node) { 353 void TestGraphVisitor::VisitUnaryOpNode(UnaryOpNode* node) {
338 Bailout("TestGraphVisitor::VisitUnaryOpNode"); 354 InstanceCallComp* call = TranslateUnaryOp(*node);
355 BranchOnValueOf(call);
339 } 356 }
340 357
341 358
342 void EffectGraphVisitor::VisitIncrOpLocalNode(IncrOpLocalNode* node) { 359 void EffectGraphVisitor::VisitIncrOpLocalNode(IncrOpLocalNode* node) {
343 Bailout("EffectGraphVisitor::VisitIncrOpLocalNode"); 360 Bailout("EffectGraphVisitor::VisitIncrOpLocalNode");
344 } 361 }
345 void ValueGraphVisitor::VisitIncrOpLocalNode(IncrOpLocalNode* node) { 362 void ValueGraphVisitor::VisitIncrOpLocalNode(IncrOpLocalNode* node) {
346 Bailout("ValueGraphVisitor::VisitIncrOpLocalNode"); 363 Bailout("ValueGraphVisitor::VisitIncrOpLocalNode");
347 } 364 }
348 void TestGraphVisitor::VisitIncrOpLocalNode(IncrOpLocalNode* node) { 365 void TestGraphVisitor::VisitIncrOpLocalNode(IncrOpLocalNode* node) {
(...skipping 500 matching lines...) Expand 10 before | Expand all | Expand 10 after
849 Bailout("EffectGraphVisitor::VisitInlinedFinallyNode"); 866 Bailout("EffectGraphVisitor::VisitInlinedFinallyNode");
850 } 867 }
851 void ValueGraphVisitor::VisitInlinedFinallyNode(InlinedFinallyNode* node) { 868 void ValueGraphVisitor::VisitInlinedFinallyNode(InlinedFinallyNode* node) {
852 Bailout("ValueGraphVisitor::VisitInlinedFinallyNode"); 869 Bailout("ValueGraphVisitor::VisitInlinedFinallyNode");
853 } 870 }
854 void TestGraphVisitor::VisitInlinedFinallyNode(InlinedFinallyNode* node) { 871 void TestGraphVisitor::VisitInlinedFinallyNode(InlinedFinallyNode* node) {
855 Bailout("TestGraphVisitor::VisitInlinedFinallyNode"); 872 Bailout("TestGraphVisitor::VisitInlinedFinallyNode");
856 } 873 }
857 874
858 875
859 void FlowGraphBuilder::TraceBailout() const {
860 if (FLAG_trace_bailout && HasBailedOut()) {
861 OS::Print("Failed: %s in %s\n",
862 bailout_reason_,
863 parsed_function().function().ToFullyQualifiedCString());
864 }
865 }
866
867
868 void FlowGraphBuilder::PrintGraph() const { 876 void FlowGraphBuilder::PrintGraph() const {
869 if (!FLAG_print_flow_graph || HasBailedOut()) return;
870
871 OS::Print("==== %s\n", 877 OS::Print("==== %s\n",
872 parsed_function().function().ToFullyQualifiedCString()); 878 parsed_function().function().ToFullyQualifiedCString());
873 879
874 for (intptr_t i = postorder_.length() - 1; i >= 0; --i) { 880 for (intptr_t i = postorder_block_entries_.length() - 1; i >= 0; --i) {
875 OS::Print("%8d: ", postorder_.length() - i); 881 // Print the block entry.
876 postorder_[i]->Print(i, postorder_); 882 Instruction* current = postorder_block_entries_[i]->Print();
883 // And all the successors until an exit, branch, or a block entry.
884 while (current != NULL && !current->IsBlockEntry()) {
885 OS::Print("\n");
886 current = current->Print();
887 }
888 if (current != NULL && current->IsBlockEntry()) {
889 OS::Print(" goto %d", current->GetBlockNumber());
890 }
877 OS::Print("\n"); 891 OS::Print("\n");
878 } 892 }
879 OS::Print("\n");
880 } 893 }
881 894
882 895
883 void FlowGraphBuilder::BuildGraph() { 896 void FlowGraphBuilder::BuildGraph() {
884 EffectGraphVisitor for_effect(this, 0); 897 EffectGraphVisitor for_effect(this, 0);
898 for_effect.AddInstruction(new TargetEntryInstr());
885 parsed_function().node_sequence()->Visit(&for_effect); 899 parsed_function().node_sequence()->Visit(&for_effect);
886 TraceBailout(); 900 if (for_effect.entry() != NULL) {
887 if (!HasBailedOut() && (for_effect.entry() != NULL)) { 901 // Accumulate basic block entries via postorder traversal.
888 for_effect.entry()->Postorder(&postorder_); 902 for_effect.entry()->Postorder(&postorder_block_entries_);
903 // Number the blocks in reverse postorder starting with 0.
904 intptr_t index = postorder_block_entries_.length() - 1;
905 intptr_t number = 0;
906 while (index >= 0) {
907 postorder_block_entries_[index--]->SetBlockNumber(number++);
908 }
889 } 909 }
890 PrintGraph(); 910 if (FLAG_print_flow_graph) {
911 PrintGraph();
912 }
891 } 913 }
892 914
915
916 void FlowGraphBuilder::Bailout(const char* reason) {
917 const char* kFormat = "FlowGraphBuilder Bailout: %s";
918 intptr_t len = OS::SNPrint(NULL, 0, kFormat, reason) + 1;
919 char* chars = reinterpret_cast<char*>(
920 Isolate::Current()->current_zone()->Allocate(len));
921 OS::SNPrint(chars, len, kFormat, reason);
922 const Error& error = Error::Handle(
923 LanguageError::New(String::Handle(String::New(chars))));
924 Isolate::Current()->long_jump_base()->Jump(1, error);
925 }
926
927
893 } // namespace dart 928 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_builder.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698