OLD | NEW |
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 #ifndef RUNTIME_VM_FLOW_GRAPH_BUILDER_H_ | 5 #ifndef RUNTIME_VM_FLOW_GRAPH_BUILDER_H_ |
6 #define RUNTIME_VM_FLOW_GRAPH_BUILDER_H_ | 6 #define RUNTIME_VM_FLOW_GRAPH_BUILDER_H_ |
7 | 7 |
8 #include "platform/assert.h" | 8 #include "platform/assert.h" |
9 #include "platform/globals.h" | 9 #include "platform/globals.h" |
10 #include "vm/allocation.h" | 10 #include "vm/allocation.h" |
(...skipping 12 matching lines...) Expand all Loading... |
23 class LocalVariable; | 23 class LocalVariable; |
24 class ParsedFunction; | 24 class ParsedFunction; |
25 class String; | 25 class String; |
26 class TypeArguments; | 26 class TypeArguments; |
27 | 27 |
28 class NestedStatement; | 28 class NestedStatement; |
29 class TestGraphVisitor; | 29 class TestGraphVisitor; |
30 | 30 |
31 // A class to collect the exits from an inlined function during graph | 31 // A class to collect the exits from an inlined function during graph |
32 // construction so they can be plugged into the caller's flow graph. | 32 // construction so they can be plugged into the caller's flow graph. |
33 class InlineExitCollector: public ZoneAllocated { | 33 class InlineExitCollector : public ZoneAllocated { |
34 public: | 34 public: |
35 InlineExitCollector(FlowGraph* caller_graph, Definition* call) | 35 InlineExitCollector(FlowGraph* caller_graph, Definition* call) |
36 : caller_graph_(caller_graph), call_(call), exits_(4) { } | 36 : caller_graph_(caller_graph), call_(call), exits_(4) {} |
37 | 37 |
38 void AddExit(ReturnInstr* exit); | 38 void AddExit(ReturnInstr* exit); |
39 | 39 |
40 void Union(const InlineExitCollector* other); | 40 void Union(const InlineExitCollector* other); |
41 | 41 |
42 // Before replacing a call with a graph, the outer environment needs to be | 42 // Before replacing a call with a graph, the outer environment needs to be |
43 // attached to each instruction in the callee graph and the caller graph | 43 // attached to each instruction in the callee graph and the caller graph |
44 // needs to have its block and instruction ID state updated. | 44 // needs to have its block and instruction ID state updated. |
45 // Additionally we need to remove all unreachable exits from the list of | 45 // Additionally we need to remove all unreachable exits from the list of |
46 // collected exits. | 46 // collected exits. |
(...skipping 16 matching lines...) Expand all Loading... |
63 | 63 |
64 BlockEntryInstr* ExitBlockAt(intptr_t i) const { | 64 BlockEntryInstr* ExitBlockAt(intptr_t i) const { |
65 ASSERT(exits_[i].exit_block != NULL); | 65 ASSERT(exits_[i].exit_block != NULL); |
66 return exits_[i].exit_block; | 66 return exits_[i].exit_block; |
67 } | 67 } |
68 | 68 |
69 Instruction* LastInstructionAt(intptr_t i) const { | 69 Instruction* LastInstructionAt(intptr_t i) const { |
70 return ReturnAt(i)->previous(); | 70 return ReturnAt(i)->previous(); |
71 } | 71 } |
72 | 72 |
73 Value* ValueAt(intptr_t i) const { | 73 Value* ValueAt(intptr_t i) const { return ReturnAt(i)->value(); } |
74 return ReturnAt(i)->value(); | |
75 } | |
76 | 74 |
77 ReturnInstr* ReturnAt(intptr_t i) const { | 75 ReturnInstr* ReturnAt(intptr_t i) const { return exits_[i].exit_return; } |
78 return exits_[i].exit_return; | |
79 } | |
80 | 76 |
81 static int LowestBlockIdFirst(const Data* a, const Data* b); | 77 static int LowestBlockIdFirst(const Data* a, const Data* b); |
82 void SortExits(); | 78 void SortExits(); |
83 void RemoveUnreachableExits(FlowGraph* callee_graph); | 79 void RemoveUnreachableExits(FlowGraph* callee_graph); |
84 | 80 |
85 Definition* JoinReturns(BlockEntryInstr** exit_block, | 81 Definition* JoinReturns(BlockEntryInstr** exit_block, |
86 Instruction** last_instruction, | 82 Instruction** last_instruction, |
87 intptr_t try_index); | 83 intptr_t try_index); |
88 | 84 |
89 Isolate* isolate() const { return caller_graph_->isolate(); } | 85 Isolate* isolate() const { return caller_graph_->isolate(); } |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
133 intptr_t catch_try_index() const { return catch_try_index_; } | 129 intptr_t catch_try_index() const { return catch_try_index_; } |
134 | 130 |
135 intptr_t next_await_counter() { return jump_count_++; } | 131 intptr_t next_await_counter() { return jump_count_++; } |
136 | 132 |
137 ZoneGrowableArray<JoinEntryInstr*>* await_joins() const { | 133 ZoneGrowableArray<JoinEntryInstr*>* await_joins() const { |
138 return await_joins_; | 134 return await_joins_; |
139 } | 135 } |
140 | 136 |
141 void AddCatchEntry(CatchBlockEntryInstr* entry); | 137 void AddCatchEntry(CatchBlockEntryInstr* entry); |
142 | 138 |
143 GraphEntryInstr* graph_entry() const { | 139 GraphEntryInstr* graph_entry() const { return graph_entry_; } |
144 return graph_entry_; | |
145 } | |
146 | 140 |
147 intptr_t num_copied_params() const { | 141 intptr_t num_copied_params() const { return num_copied_params_; } |
148 return num_copied_params_; | 142 intptr_t num_non_copied_params() const { return num_non_copied_params_; } |
149 } | 143 intptr_t num_stack_locals() const { return num_stack_locals_; } |
150 intptr_t num_non_copied_params() const { | |
151 return num_non_copied_params_; | |
152 } | |
153 intptr_t num_stack_locals() const { | |
154 return num_stack_locals_; | |
155 } | |
156 | 144 |
157 bool IsInlining() const { return (exit_collector_ != NULL); } | 145 bool IsInlining() const { return (exit_collector_ != NULL); } |
158 InlineExitCollector* exit_collector() const { return exit_collector_; } | 146 InlineExitCollector* exit_collector() const { return exit_collector_; } |
159 | 147 |
160 ZoneGrowableArray<const LibraryPrefix*>* deferred_prefixes() const { | 148 ZoneGrowableArray<const LibraryPrefix*>* deferred_prefixes() const { |
161 return parsed_function_.deferred_prefixes(); | 149 return parsed_function_.deferred_prefixes(); |
162 } | 150 } |
163 | 151 |
164 intptr_t temp_count() const { return temp_count_; } | 152 intptr_t temp_count() const { return temp_count_; } |
165 intptr_t AllocateTemp() { return temp_count_++; } | 153 intptr_t AllocateTemp() { return temp_count_++; } |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
234 // function from an AstNode and next temporary index to a graph fragment | 222 // function from an AstNode and next temporary index to a graph fragment |
235 // with a single entry and at most one exit. The fragment is represented by | 223 // with a single entry and at most one exit. The fragment is represented by |
236 // an (entry, exit) pair of Instruction pointers: | 224 // an (entry, exit) pair of Instruction pointers: |
237 // | 225 // |
238 // - (NULL, NULL): an empty and open graph fragment | 226 // - (NULL, NULL): an empty and open graph fragment |
239 // - (i0, NULL): a closed graph fragment which has only non-local exits | 227 // - (i0, NULL): a closed graph fragment which has only non-local exits |
240 // - (i0, i1): an open graph fragment | 228 // - (i0, i1): an open graph fragment |
241 class EffectGraphVisitor : public AstNodeVisitor { | 229 class EffectGraphVisitor : public AstNodeVisitor { |
242 public: | 230 public: |
243 explicit EffectGraphVisitor(FlowGraphBuilder* owner) | 231 explicit EffectGraphVisitor(FlowGraphBuilder* owner) |
244 : owner_(owner), | 232 : owner_(owner), entry_(NULL), exit_(NULL) {} |
245 entry_(NULL), | |
246 exit_(NULL) { } | |
247 | 233 |
248 #define DECLARE_VISIT(BaseName) \ | 234 #define DECLARE_VISIT(BaseName) \ |
249 virtual void Visit##BaseName##Node(BaseName##Node* node); | 235 virtual void Visit##BaseName##Node(BaseName##Node* node); |
250 | 236 |
251 FOR_EACH_NODE(DECLARE_VISIT) | 237 FOR_EACH_NODE(DECLARE_VISIT) |
252 #undef DECLARE_VISIT | 238 #undef DECLARE_VISIT |
253 | 239 |
254 FlowGraphBuilder* owner() const { return owner_; } | 240 FlowGraphBuilder* owner() const { return owner_; } |
255 Instruction* entry() const { return entry_; } | 241 Instruction* entry() const { return entry_; } |
256 Instruction* exit() const { return exit_; } | 242 Instruction* exit() const { return exit_; } |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
302 Value* value, | 288 Value* value, |
303 TokenPosition token_pos); | 289 TokenPosition token_pos); |
304 Definition* BuildStoreExprTemp(Value* value, TokenPosition token_pos); | 290 Definition* BuildStoreExprTemp(Value* value, TokenPosition token_pos); |
305 Definition* BuildLoadExprTemp(TokenPosition token_pos); | 291 Definition* BuildLoadExprTemp(TokenPosition token_pos); |
306 | 292 |
307 Definition* BuildStoreLocal(const LocalVariable& local, | 293 Definition* BuildStoreLocal(const LocalVariable& local, |
308 Value* value, | 294 Value* value, |
309 TokenPosition token_pos); | 295 TokenPosition token_pos); |
310 Definition* BuildLoadLocal(const LocalVariable& local, | 296 Definition* BuildLoadLocal(const LocalVariable& local, |
311 TokenPosition token_pos); | 297 TokenPosition token_pos); |
312 LoadLocalInstr* BuildLoadThisVar(LocalScope* scope, | 298 LoadLocalInstr* BuildLoadThisVar(LocalScope* scope, TokenPosition token_pos); |
313 TokenPosition token_pos); | 299 LoadFieldInstr* BuildNativeGetter(NativeBodyNode* node, |
314 LoadFieldInstr* BuildNativeGetter( | 300 MethodRecognizer::Kind kind, |
315 NativeBodyNode* node, | 301 intptr_t offset, |
316 MethodRecognizer::Kind kind, | 302 const Type& type, |
317 intptr_t offset, | 303 intptr_t class_id); |
318 const Type& type, | |
319 intptr_t class_id); | |
320 // Assumes setter parameter is named 'value'. Returns null constant. | 304 // Assumes setter parameter is named 'value'. Returns null constant. |
321 ConstantInstr* DoNativeSetterStoreValue( | 305 ConstantInstr* DoNativeSetterStoreValue(NativeBodyNode* node, |
322 NativeBodyNode* node, | 306 intptr_t offset, |
323 intptr_t offset, | 307 StoreBarrierType emit_store_barrier); |
324 StoreBarrierType emit_store_barrier); | |
325 | 308 |
326 // Helpers for translating parts of the AST. | 309 // Helpers for translating parts of the AST. |
327 void BuildPushArguments(const ArgumentListNode& node, | 310 void BuildPushArguments(const ArgumentListNode& node, |
328 ZoneGrowableArray<PushArgumentInstr*>* values); | 311 ZoneGrowableArray<PushArgumentInstr*>* values); |
329 | 312 |
330 // Creates an instantiated type argument vector used in preparation of an | 313 // Creates an instantiated type argument vector used in preparation of an |
331 // allocation call. | 314 // allocation call. |
332 // May be called only if allocating an object of a parameterized class. | 315 // May be called only if allocating an object of a parameterized class. |
333 Value* BuildInstantiatedTypeArguments( | 316 Value* BuildInstantiatedTypeArguments(TokenPosition token_pos, |
334 TokenPosition token_pos, | 317 const TypeArguments& type_arguments); |
335 const TypeArguments& type_arguments); | |
336 | 318 |
337 void BuildTypecheckPushArguments( | 319 void BuildTypecheckPushArguments( |
338 TokenPosition token_pos, | 320 TokenPosition token_pos, |
339 PushArgumentInstr** push_instantiator_type_arguments); | 321 PushArgumentInstr** push_instantiator_type_arguments); |
340 void BuildTypecheckArguments(TokenPosition token_pos, | 322 void BuildTypecheckArguments(TokenPosition token_pos, |
341 Value** instantiator_type_arguments); | 323 Value** instantiator_type_arguments); |
342 Value* BuildInstantiator(TokenPosition token_pos); | 324 Value* BuildInstantiator(TokenPosition token_pos); |
343 Value* BuildInstantiatorTypeArguments(TokenPosition token_pos, | 325 Value* BuildInstantiatorTypeArguments(TokenPosition token_pos, |
344 const Class& instantiator_class, | 326 const Class& instantiator_class, |
345 Value* instantiator); | 327 Value* instantiator); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
387 void CloseFragment() { exit_ = NULL; } | 369 void CloseFragment() { exit_ = NULL; } |
388 | 370 |
389 // Returns a local variable index for a temporary local that is | 371 // Returns a local variable index for a temporary local that is |
390 // on top of the current expression stack. | 372 // on top of the current expression stack. |
391 intptr_t GetCurrentTempLocalIndex() const; | 373 intptr_t GetCurrentTempLocalIndex() const; |
392 | 374 |
393 Value* BuildObjectAllocation(ConstructorCallNode* node); | 375 Value* BuildObjectAllocation(ConstructorCallNode* node); |
394 void BuildConstructorCall(ConstructorCallNode* node, | 376 void BuildConstructorCall(ConstructorCallNode* node, |
395 PushArgumentInstr* alloc_value); | 377 PushArgumentInstr* alloc_value); |
396 | 378 |
397 void BuildSaveContext(const LocalVariable& variable, | 379 void BuildSaveContext(const LocalVariable& variable, TokenPosition token_pos); |
398 TokenPosition token_pos); | |
399 void BuildRestoreContext(const LocalVariable& variable, | 380 void BuildRestoreContext(const LocalVariable& variable, |
400 TokenPosition token_pos); | 381 TokenPosition token_pos); |
401 | 382 |
402 Definition* BuildStoreContext(Value* value, TokenPosition token_pos); | 383 Definition* BuildStoreContext(Value* value, TokenPosition token_pos); |
403 Definition* BuildCurrentContext(TokenPosition token_pos); | 384 Definition* BuildCurrentContext(TokenPosition token_pos); |
404 | 385 |
405 void BuildThrowNode(ThrowNode* node); | 386 void BuildThrowNode(ThrowNode* node); |
406 | 387 |
407 StaticCallInstr* BuildStaticNoSuchMethodCall( | 388 StaticCallInstr* BuildStaticNoSuchMethodCall( |
408 const Class& target_class, | 389 const Class& target_class, |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
445 void BuildInstanceCallConditional(InstanceCallNode* node); | 426 void BuildInstanceCallConditional(InstanceCallNode* node); |
446 | 427 |
447 Thread* thread() const { return owner()->thread(); } | 428 Thread* thread() const { return owner()->thread(); } |
448 Isolate* isolate() const { return owner()->isolate(); } | 429 Isolate* isolate() const { return owner()->isolate(); } |
449 Zone* zone() const { return owner()->zone(); } | 430 Zone* zone() const { return owner()->zone(); } |
450 | 431 |
451 private: | 432 private: |
452 friend class TempLocalScope; // For ReturnDefinition. | 433 friend class TempLocalScope; // For ReturnDefinition. |
453 | 434 |
454 // Helper to drop the result value. | 435 // Helper to drop the result value. |
455 virtual void ReturnValue(Value* value) { | 436 virtual void ReturnValue(Value* value) { Do(new DropTempsInstr(0, value)); } |
456 Do(new DropTempsInstr(0, value)); | |
457 } | |
458 | 437 |
459 // Specify a definition of the final result. Adds the definition to | 438 // Specify a definition of the final result. Adds the definition to |
460 // the graph, but normally overridden in subclasses. | 439 // the graph, but normally overridden in subclasses. |
461 virtual void ReturnDefinition(Definition* definition) { | 440 virtual void ReturnDefinition(Definition* definition) { |
462 // Constants have no effect, do not add them to graph otherwise SSA | 441 // Constants have no effect, do not add them to graph otherwise SSA |
463 // builder will get confused. | 442 // builder will get confused. |
464 if (!definition->IsConstant()) { | 443 if (!definition->IsConstant()) { |
465 Do(definition); | 444 Do(definition); |
466 } | 445 } |
467 } | 446 } |
468 | 447 |
469 // Shared global state. | 448 // Shared global state. |
470 FlowGraphBuilder* owner_; | 449 FlowGraphBuilder* owner_; |
471 | 450 |
472 // Output parameters. | 451 // Output parameters. |
473 Instruction* entry_; | 452 Instruction* entry_; |
474 Instruction* exit_; | 453 Instruction* exit_; |
475 }; | 454 }; |
476 | 455 |
477 | 456 |
478 // Translate an AstNode to a control-flow graph fragment for both its effects | 457 // Translate an AstNode to a control-flow graph fragment for both its effects |
479 // and value (e.g., for an expression in a value context). Implements a | 458 // and value (e.g., for an expression in a value context). Implements a |
480 // function from an AstNode and next temporary index to a graph fragment (as | 459 // function from an AstNode and next temporary index to a graph fragment (as |
481 // in the EffectGraphVisitor), a next temporary index, and an intermediate | 460 // in the EffectGraphVisitor), a next temporary index, and an intermediate |
482 // language Value. | 461 // language Value. |
483 class ValueGraphVisitor : public EffectGraphVisitor { | 462 class ValueGraphVisitor : public EffectGraphVisitor { |
484 public: | 463 public: |
485 explicit ValueGraphVisitor(FlowGraphBuilder* owner) | 464 explicit ValueGraphVisitor(FlowGraphBuilder* owner) |
486 : EffectGraphVisitor(owner), value_(NULL) { } | 465 : EffectGraphVisitor(owner), value_(NULL) {} |
487 | 466 |
488 // Visit functions overridden by this class. | 467 // Visit functions overridden by this class. |
489 virtual void VisitAssignableNode(AssignableNode* node); | 468 virtual void VisitAssignableNode(AssignableNode* node); |
490 virtual void VisitConstructorCallNode(ConstructorCallNode* node); | 469 virtual void VisitConstructorCallNode(ConstructorCallNode* node); |
491 virtual void VisitBinaryOpNode(BinaryOpNode* node); | 470 virtual void VisitBinaryOpNode(BinaryOpNode* node); |
492 virtual void VisitConditionalExprNode(ConditionalExprNode* node); | 471 virtual void VisitConditionalExprNode(ConditionalExprNode* node); |
493 virtual void VisitLoadLocalNode(LoadLocalNode* node); | 472 virtual void VisitLoadLocalNode(LoadLocalNode* node); |
494 virtual void VisitStoreIndexedNode(StoreIndexedNode* node); | 473 virtual void VisitStoreIndexedNode(StoreIndexedNode* node); |
495 virtual void VisitInstanceSetterNode(InstanceSetterNode* node); | 474 virtual void VisitInstanceSetterNode(InstanceSetterNode* node); |
496 virtual void VisitInstanceGetterNode(InstanceGetterNode* node); | 475 virtual void VisitInstanceGetterNode(InstanceGetterNode* node); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
533 // - Both NULL: only non-local exits, truly closed | 512 // - Both NULL: only non-local exits, truly closed |
534 // - Neither NULL: true and false successors at the given addresses | 513 // - Neither NULL: true and false successors at the given addresses |
535 // | 514 // |
536 // We expect that AstNode in test contexts either have only nonlocal exits | 515 // We expect that AstNode in test contexts either have only nonlocal exits |
537 // or else control flow has both true and false successors. | 516 // or else control flow has both true and false successors. |
538 // | 517 // |
539 // The cis and token_pos are used in checked mode to verify that the | 518 // The cis and token_pos are used in checked mode to verify that the |
540 // condition of the test is of type bool. | 519 // condition of the test is of type bool. |
541 class TestGraphVisitor : public ValueGraphVisitor { | 520 class TestGraphVisitor : public ValueGraphVisitor { |
542 public: | 521 public: |
543 TestGraphVisitor(FlowGraphBuilder* owner, | 522 TestGraphVisitor(FlowGraphBuilder* owner, TokenPosition condition_token_pos) |
544 TokenPosition condition_token_pos) | |
545 : ValueGraphVisitor(owner), | 523 : ValueGraphVisitor(owner), |
546 true_successor_addresses_(1), | 524 true_successor_addresses_(1), |
547 false_successor_addresses_(1), | 525 false_successor_addresses_(1), |
548 condition_token_pos_(condition_token_pos) { } | 526 condition_token_pos_(condition_token_pos) {} |
549 | 527 |
550 void IfFalseGoto(JoinEntryInstr* join) const; | 528 void IfFalseGoto(JoinEntryInstr* join) const; |
551 void IfTrueGoto(JoinEntryInstr* join) const; | 529 void IfTrueGoto(JoinEntryInstr* join) const; |
552 | 530 |
553 BlockEntryInstr* CreateTrueSuccessor() const; | 531 BlockEntryInstr* CreateTrueSuccessor() const; |
554 BlockEntryInstr* CreateFalseSuccessor() const; | 532 BlockEntryInstr* CreateFalseSuccessor() const; |
555 | 533 |
556 virtual void VisitBinaryOpNode(BinaryOpNode* node); | 534 virtual void VisitBinaryOpNode(BinaryOpNode* node); |
557 | 535 |
558 TokenPosition condition_token_pos() const { return condition_token_pos_; } | 536 TokenPosition condition_token_pos() const { return condition_token_pos_; } |
559 | 537 |
560 private: | 538 private: |
561 // Construct and concatenate a Branch instruction to this graph fragment. | 539 // Construct and concatenate a Branch instruction to this graph fragment. |
562 // Closes the fragment and sets the output parameters. | 540 // Closes the fragment and sets the output parameters. |
563 virtual void ReturnValue(Value* value); | 541 virtual void ReturnValue(Value* value); |
564 | 542 |
565 // Either merges the definition into a BranchInstr (Comparison, BooleanNegate) | 543 // Either merges the definition into a BranchInstr (Comparison, BooleanNegate) |
566 // or adds the definition to the graph and returns a use of its value. | 544 // or adds the definition to the graph and returns a use of its value. |
567 virtual void ReturnDefinition(Definition* definition); | 545 virtual void ReturnDefinition(Definition* definition); |
568 | 546 |
569 void MergeBranchWithComparison(ComparisonInstr* comp); | 547 void MergeBranchWithComparison(ComparisonInstr* comp); |
570 void MergeBranchWithNegate(BooleanNegateInstr* comp); | 548 void MergeBranchWithNegate(BooleanNegateInstr* comp); |
571 | 549 |
572 BlockEntryInstr* CreateSuccessorFor( | 550 BlockEntryInstr* CreateSuccessorFor( |
573 const GrowableArray<TargetEntryInstr**>& branches) const; | 551 const GrowableArray<TargetEntryInstr**>& branches) const; |
574 | 552 |
575 void ConnectBranchesTo( | 553 void ConnectBranchesTo(const GrowableArray<TargetEntryInstr**>& branches, |
576 const GrowableArray<TargetEntryInstr**>& branches, | 554 JoinEntryInstr* join) const; |
577 JoinEntryInstr* join) const; | |
578 | 555 |
579 // Output parameters. | 556 // Output parameters. |
580 GrowableArray<TargetEntryInstr**> true_successor_addresses_; | 557 GrowableArray<TargetEntryInstr**> true_successor_addresses_; |
581 GrowableArray<TargetEntryInstr**> false_successor_addresses_; | 558 GrowableArray<TargetEntryInstr**> false_successor_addresses_; |
582 | 559 |
583 TokenPosition condition_token_pos_; | 560 TokenPosition condition_token_pos_; |
584 }; | 561 }; |
585 | 562 |
586 } // namespace dart | 563 } // namespace dart |
587 | 564 |
588 #endif // RUNTIME_VM_FLOW_GRAPH_BUILDER_H_ | 565 #endif // RUNTIME_VM_FLOW_GRAPH_BUILDER_H_ |
OLD | NEW |