Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / v8 / src / compiler / instruction.cc
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/compiler/common-operator.h"
6 #include "src/compiler/generic-node-inl.h"
7 #include "src/compiler/graph.h"
8 #include "src/compiler/instruction.h"
9
10 namespace v8 {
11 namespace internal {
12 namespace compiler {
13
14 std::ostream& operator<<(std::ostream& os,
15                          const PrintableInstructionOperand& printable) {
16   const InstructionOperand& op = *printable.op_;
17   const RegisterConfiguration* conf = printable.register_configuration_;
18   switch (op.kind()) {
19     case InstructionOperand::INVALID:
20       return os << "(0)";
21     case InstructionOperand::UNALLOCATED: {
22       const UnallocatedOperand* unalloc = UnallocatedOperand::cast(&op);
23       os << "v" << unalloc->virtual_register();
24       if (unalloc->basic_policy() == UnallocatedOperand::FIXED_SLOT) {
25         return os << "(=" << unalloc->fixed_slot_index() << "S)";
26       }
27       switch (unalloc->extended_policy()) {
28         case UnallocatedOperand::NONE:
29           return os;
30         case UnallocatedOperand::FIXED_REGISTER:
31           return os << "(=" << conf->general_register_name(
32                                    unalloc->fixed_register_index()) << ")";
33         case UnallocatedOperand::FIXED_DOUBLE_REGISTER:
34           return os << "(=" << conf->double_register_name(
35                                    unalloc->fixed_register_index()) << ")";
36         case UnallocatedOperand::MUST_HAVE_REGISTER:
37           return os << "(R)";
38         case UnallocatedOperand::SAME_AS_FIRST_INPUT:
39           return os << "(1)";
40         case UnallocatedOperand::ANY:
41           return os << "(-)";
42       }
43     }
44     case InstructionOperand::CONSTANT:
45       return os << "[constant:" << op.index() << "]";
46     case InstructionOperand::IMMEDIATE:
47       return os << "[immediate:" << op.index() << "]";
48     case InstructionOperand::STACK_SLOT:
49       return os << "[stack:" << op.index() << "]";
50     case InstructionOperand::DOUBLE_STACK_SLOT:
51       return os << "[double_stack:" << op.index() << "]";
52     case InstructionOperand::REGISTER:
53       return os << "[" << conf->general_register_name(op.index()) << "|R]";
54     case InstructionOperand::DOUBLE_REGISTER:
55       return os << "[" << conf->double_register_name(op.index()) << "|R]";
56   }
57   UNREACHABLE();
58   return os;
59 }
60
61
62 template <InstructionOperand::Kind kOperandKind, int kNumCachedOperands>
63 SubKindOperand<kOperandKind, kNumCachedOperands>*
64     SubKindOperand<kOperandKind, kNumCachedOperands>::cache = NULL;
65
66
67 template <InstructionOperand::Kind kOperandKind, int kNumCachedOperands>
68 void SubKindOperand<kOperandKind, kNumCachedOperands>::SetUpCache() {
69   if (cache) return;
70   cache = new SubKindOperand[kNumCachedOperands];
71   for (int i = 0; i < kNumCachedOperands; i++) {
72     cache[i].ConvertTo(kOperandKind, i);
73   }
74 }
75
76
77 template <InstructionOperand::Kind kOperandKind, int kNumCachedOperands>
78 void SubKindOperand<kOperandKind, kNumCachedOperands>::TearDownCache() {
79   delete[] cache;
80   cache = NULL;
81 }
82
83
84 void InstructionOperand::SetUpCaches() {
85 #define INSTRUCTION_OPERAND_SETUP(name, type, number) \
86   name##Operand::SetUpCache();
87   INSTRUCTION_OPERAND_LIST(INSTRUCTION_OPERAND_SETUP)
88 #undef INSTRUCTION_OPERAND_SETUP
89 }
90
91
92 void InstructionOperand::TearDownCaches() {
93 #define INSTRUCTION_OPERAND_TEARDOWN(name, type, number) \
94   name##Operand::TearDownCache();
95   INSTRUCTION_OPERAND_LIST(INSTRUCTION_OPERAND_TEARDOWN)
96 #undef INSTRUCTION_OPERAND_TEARDOWN
97 }
98
99
100 std::ostream& operator<<(std::ostream& os,
101                          const PrintableMoveOperands& printable) {
102   const MoveOperands& mo = *printable.move_operands_;
103   PrintableInstructionOperand printable_op = {printable.register_configuration_,
104                                               mo.destination()};
105
106   os << printable_op;
107   if (!mo.source()->Equals(mo.destination())) {
108     printable_op.op_ = mo.source();
109     os << " = " << printable_op;
110   }
111   return os << ";";
112 }
113
114
115 bool ParallelMove::IsRedundant() const {
116   for (int i = 0; i < move_operands_.length(); ++i) {
117     if (!move_operands_[i].IsRedundant()) return false;
118   }
119   return true;
120 }
121
122
123 std::ostream& operator<<(std::ostream& os,
124                          const PrintableParallelMove& printable) {
125   const ParallelMove& pm = *printable.parallel_move_;
126   bool first = true;
127   for (ZoneList<MoveOperands>::iterator move = pm.move_operands()->begin();
128        move != pm.move_operands()->end(); ++move) {
129     if (move->IsEliminated()) continue;
130     if (!first) os << " ";
131     first = false;
132     PrintableMoveOperands pmo = {printable.register_configuration_, move};
133     os << pmo;
134   }
135   return os;
136 }
137
138
139 void PointerMap::RecordPointer(InstructionOperand* op, Zone* zone) {
140   // Do not record arguments as pointers.
141   if (op->IsStackSlot() && op->index() < 0) return;
142   DCHECK(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
143   pointer_operands_.Add(op, zone);
144 }
145
146
147 void PointerMap::RemovePointer(InstructionOperand* op) {
148   // Do not record arguments as pointers.
149   if (op->IsStackSlot() && op->index() < 0) return;
150   DCHECK(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
151   for (int i = 0; i < pointer_operands_.length(); ++i) {
152     if (pointer_operands_[i]->Equals(op)) {
153       pointer_operands_.Remove(i);
154       --i;
155     }
156   }
157 }
158
159
160 void PointerMap::RecordUntagged(InstructionOperand* op, Zone* zone) {
161   // Do not record arguments as pointers.
162   if (op->IsStackSlot() && op->index() < 0) return;
163   DCHECK(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
164   untagged_operands_.Add(op, zone);
165 }
166
167
168 std::ostream& operator<<(std::ostream& os, const PointerMap& pm) {
169   os << "{";
170   for (ZoneList<InstructionOperand*>::iterator op =
171            pm.pointer_operands_.begin();
172        op != pm.pointer_operands_.end(); ++op) {
173     if (op != pm.pointer_operands_.begin()) os << ";";
174     os << *op;
175   }
176   return os << "}";
177 }
178
179
180 std::ostream& operator<<(std::ostream& os, const ArchOpcode& ao) {
181   switch (ao) {
182 #define CASE(Name) \
183   case k##Name:    \
184     return os << #Name;
185     ARCH_OPCODE_LIST(CASE)
186 #undef CASE
187   }
188   UNREACHABLE();
189   return os;
190 }
191
192
193 std::ostream& operator<<(std::ostream& os, const AddressingMode& am) {
194   switch (am) {
195     case kMode_None:
196       return os;
197 #define CASE(Name)   \
198   case kMode_##Name: \
199     return os << #Name;
200       TARGET_ADDRESSING_MODE_LIST(CASE)
201 #undef CASE
202   }
203   UNREACHABLE();
204   return os;
205 }
206
207
208 std::ostream& operator<<(std::ostream& os, const FlagsMode& fm) {
209   switch (fm) {
210     case kFlags_none:
211       return os;
212     case kFlags_branch:
213       return os << "branch";
214     case kFlags_set:
215       return os << "set";
216   }
217   UNREACHABLE();
218   return os;
219 }
220
221
222 std::ostream& operator<<(std::ostream& os, const FlagsCondition& fc) {
223   switch (fc) {
224     case kEqual:
225       return os << "equal";
226     case kNotEqual:
227       return os << "not equal";
228     case kSignedLessThan:
229       return os << "signed less than";
230     case kSignedGreaterThanOrEqual:
231       return os << "signed greater than or equal";
232     case kSignedLessThanOrEqual:
233       return os << "signed less than or equal";
234     case kSignedGreaterThan:
235       return os << "signed greater than";
236     case kUnsignedLessThan:
237       return os << "unsigned less than";
238     case kUnsignedGreaterThanOrEqual:
239       return os << "unsigned greater than or equal";
240     case kUnsignedLessThanOrEqual:
241       return os << "unsigned less than or equal";
242     case kUnsignedGreaterThan:
243       return os << "unsigned greater than";
244     case kUnorderedEqual:
245       return os << "unordered equal";
246     case kUnorderedNotEqual:
247       return os << "unordered not equal";
248     case kUnorderedLessThan:
249       return os << "unordered less than";
250     case kUnorderedGreaterThanOrEqual:
251       return os << "unordered greater than or equal";
252     case kUnorderedLessThanOrEqual:
253       return os << "unordered less than or equal";
254     case kUnorderedGreaterThan:
255       return os << "unordered greater than";
256     case kOverflow:
257       return os << "overflow";
258     case kNotOverflow:
259       return os << "not overflow";
260   }
261   UNREACHABLE();
262   return os;
263 }
264
265
266 std::ostream& operator<<(std::ostream& os,
267                          const PrintableInstruction& printable) {
268   const Instruction& instr = *printable.instr_;
269   PrintableInstructionOperand printable_op = {printable.register_configuration_,
270                                               NULL};
271   if (instr.OutputCount() > 1) os << "(";
272   for (size_t i = 0; i < instr.OutputCount(); i++) {
273     if (i > 0) os << ", ";
274     printable_op.op_ = instr.OutputAt(i);
275     os << printable_op;
276   }
277
278   if (instr.OutputCount() > 1) os << ") = ";
279   if (instr.OutputCount() == 1) os << " = ";
280
281   if (instr.IsGapMoves()) {
282     const GapInstruction* gap = GapInstruction::cast(&instr);
283     os << (instr.IsBlockStart() ? " block-start" : "gap ");
284     for (int i = GapInstruction::FIRST_INNER_POSITION;
285          i <= GapInstruction::LAST_INNER_POSITION; i++) {
286       os << "(";
287       if (gap->parallel_moves_[i] != NULL) {
288         PrintableParallelMove ppm = {printable.register_configuration_,
289                                      gap->parallel_moves_[i]};
290         os << ppm;
291       }
292       os << ") ";
293     }
294   } else if (instr.IsSourcePosition()) {
295     const SourcePositionInstruction* pos =
296         SourcePositionInstruction::cast(&instr);
297     os << "position (" << pos->source_position().raw() << ")";
298   } else {
299     os << ArchOpcodeField::decode(instr.opcode());
300     AddressingMode am = AddressingModeField::decode(instr.opcode());
301     if (am != kMode_None) {
302       os << " : " << AddressingModeField::decode(instr.opcode());
303     }
304     FlagsMode fm = FlagsModeField::decode(instr.opcode());
305     if (fm != kFlags_none) {
306       os << " && " << fm << " if "
307          << FlagsConditionField::decode(instr.opcode());
308     }
309   }
310   if (instr.InputCount() > 0) {
311     for (size_t i = 0; i < instr.InputCount(); i++) {
312       printable_op.op_ = instr.InputAt(i);
313       os << " " << printable_op;
314     }
315   }
316   return os;
317 }
318
319
320 std::ostream& operator<<(std::ostream& os, const Constant& constant) {
321   switch (constant.type()) {
322     case Constant::kInt32:
323       return os << constant.ToInt32();
324     case Constant::kInt64:
325       return os << constant.ToInt64() << "l";
326     case Constant::kFloat32:
327       return os << constant.ToFloat32() << "f";
328     case Constant::kFloat64:
329       return os << constant.ToFloat64();
330     case Constant::kExternalReference:
331       return os << static_cast<const void*>(
332                        constant.ToExternalReference().address());
333     case Constant::kHeapObject:
334       return os << Brief(*constant.ToHeapObject());
335   }
336   UNREACHABLE();
337   return os;
338 }
339
340
341 static BasicBlock::RpoNumber GetRpo(BasicBlock* block) {
342   if (block == NULL) return BasicBlock::RpoNumber::Invalid();
343   return block->GetRpoNumber();
344 }
345
346
347 static BasicBlock::RpoNumber GetLoopEndRpo(const BasicBlock* block) {
348   if (!block->IsLoopHeader()) return BasicBlock::RpoNumber::Invalid();
349   return BasicBlock::RpoNumber::FromInt(block->loop_end());
350 }
351
352
353 InstructionBlock::InstructionBlock(Zone* zone, const BasicBlock* block)
354     : successors_(static_cast<int>(block->SuccessorCount()),
355                   BasicBlock::RpoNumber::Invalid(), zone),
356       predecessors_(static_cast<int>(block->PredecessorCount()),
357                     BasicBlock::RpoNumber::Invalid(), zone),
358       phis_(zone),
359       id_(block->id()),
360       ao_number_(block->GetAoNumber()),
361       rpo_number_(block->GetRpoNumber()),
362       loop_header_(GetRpo(block->loop_header())),
363       loop_end_(GetLoopEndRpo(block)),
364       code_start_(-1),
365       code_end_(-1),
366       deferred_(block->deferred()) {
367   // Map successors and precessors
368   size_t index = 0;
369   for (BasicBlock::Successors::const_iterator it = block->successors_begin();
370        it != block->successors_end(); ++it, ++index) {
371     successors_[index] = (*it)->GetRpoNumber();
372   }
373   index = 0;
374   for (BasicBlock::Predecessors::const_iterator
375            it = block->predecessors_begin();
376        it != block->predecessors_end(); ++it, ++index) {
377     predecessors_[index] = (*it)->GetRpoNumber();
378   }
379 }
380
381
382 size_t InstructionBlock::PredecessorIndexOf(
383     BasicBlock::RpoNumber rpo_number) const {
384   size_t j = 0;
385   for (InstructionBlock::Predecessors::const_iterator i = predecessors_.begin();
386        i != predecessors_.end(); ++i, ++j) {
387     if (*i == rpo_number) break;
388   }
389   return j;
390 }
391
392
393 InstructionBlocks* InstructionSequence::InstructionBlocksFor(
394     Zone* zone, const Schedule* schedule) {
395   InstructionBlocks* blocks = zone->NewArray<InstructionBlocks>(1);
396   new (blocks) InstructionBlocks(
397       static_cast<int>(schedule->rpo_order()->size()), NULL, zone);
398   size_t rpo_number = 0;
399   for (BasicBlockVector::const_iterator it = schedule->rpo_order()->begin();
400        it != schedule->rpo_order()->end(); ++it, ++rpo_number) {
401     DCHECK_EQ(NULL, (*blocks)[rpo_number]);
402     DCHECK((*it)->GetRpoNumber().ToSize() == rpo_number);
403     (*blocks)[rpo_number] = new (zone) InstructionBlock(zone, *it);
404   }
405   return blocks;
406 }
407
408
409 InstructionSequence::InstructionSequence(Zone* instruction_zone,
410                                          InstructionBlocks* instruction_blocks)
411     : zone_(instruction_zone),
412       instruction_blocks_(instruction_blocks),
413       constants_(ConstantMap::key_compare(),
414                  ConstantMap::allocator_type(zone())),
415       immediates_(zone()),
416       instructions_(zone()),
417       next_virtual_register_(0),
418       pointer_maps_(zone()),
419       doubles_(std::less<int>(), VirtualRegisterSet::allocator_type(zone())),
420       references_(std::less<int>(), VirtualRegisterSet::allocator_type(zone())),
421       deoptimization_entries_(zone()) {}
422
423
424 Label* InstructionSequence::GetLabel(BasicBlock::RpoNumber rpo) {
425   return GetBlockStart(rpo)->label();
426 }
427
428
429 BlockStartInstruction* InstructionSequence::GetBlockStart(
430     BasicBlock::RpoNumber rpo) {
431   InstructionBlock* block = InstructionBlockAt(rpo);
432   BlockStartInstruction* block_start =
433       BlockStartInstruction::cast(InstructionAt(block->code_start()));
434   DCHECK_EQ(rpo.ToInt(), block_start->rpo_number().ToInt());
435   return block_start;
436 }
437
438
439 void InstructionSequence::StartBlock(BasicBlock* basic_block) {
440   InstructionBlock* block = InstructionBlockAt(basic_block->GetRpoNumber());
441   block->set_code_start(static_cast<int>(instructions_.size()));
442   BlockStartInstruction* block_start =
443       BlockStartInstruction::New(zone(), basic_block);
444   AddInstruction(block_start);
445 }
446
447
448 void InstructionSequence::EndBlock(BasicBlock* basic_block) {
449   int end = static_cast<int>(instructions_.size());
450   InstructionBlock* block = InstructionBlockAt(basic_block->GetRpoNumber());
451   DCHECK(block->code_start() >= 0 && block->code_start() < end);
452   block->set_code_end(end);
453 }
454
455
456 int InstructionSequence::AddInstruction(Instruction* instr) {
457   // TODO(titzer): the order of these gaps is a holdover from Lithium.
458   GapInstruction* gap = GapInstruction::New(zone());
459   if (instr->IsControl()) instructions_.push_back(gap);
460   int index = static_cast<int>(instructions_.size());
461   instructions_.push_back(instr);
462   if (!instr->IsControl()) instructions_.push_back(gap);
463   if (instr->NeedsPointerMap()) {
464     DCHECK(instr->pointer_map() == NULL);
465     PointerMap* pointer_map = new (zone()) PointerMap(zone());
466     pointer_map->set_instruction_position(index);
467     instr->set_pointer_map(pointer_map);
468     pointer_maps_.push_back(pointer_map);
469   }
470   return index;
471 }
472
473
474 const InstructionBlock* InstructionSequence::GetInstructionBlock(
475     int instruction_index) const {
476   // TODO(turbofan): Optimize this.
477   for (;;) {
478     DCHECK_LE(0, instruction_index);
479     Instruction* instruction = InstructionAt(instruction_index--);
480     if (instruction->IsBlockStart()) {
481       return instruction_blocks_->at(
482           BlockStartInstruction::cast(instruction)->rpo_number().ToSize());
483     }
484   }
485 }
486
487
488 bool InstructionSequence::IsReference(int virtual_register) const {
489   return references_.find(virtual_register) != references_.end();
490 }
491
492
493 bool InstructionSequence::IsDouble(int virtual_register) const {
494   return doubles_.find(virtual_register) != doubles_.end();
495 }
496
497
498 void InstructionSequence::MarkAsReference(int virtual_register) {
499   references_.insert(virtual_register);
500 }
501
502
503 void InstructionSequence::MarkAsDouble(int virtual_register) {
504   doubles_.insert(virtual_register);
505 }
506
507
508 void InstructionSequence::AddGapMove(int index, InstructionOperand* from,
509                                      InstructionOperand* to) {
510   GapAt(index)->GetOrCreateParallelMove(GapInstruction::START, zone())->AddMove(
511       from, to, zone());
512 }
513
514
515 InstructionSequence::StateId InstructionSequence::AddFrameStateDescriptor(
516     FrameStateDescriptor* descriptor) {
517   int deoptimization_id = static_cast<int>(deoptimization_entries_.size());
518   deoptimization_entries_.push_back(descriptor);
519   return StateId::FromInt(deoptimization_id);
520 }
521
522 FrameStateDescriptor* InstructionSequence::GetFrameStateDescriptor(
523     InstructionSequence::StateId state_id) {
524   return deoptimization_entries_[state_id.ToInt()];
525 }
526
527
528 int InstructionSequence::GetFrameStateDescriptorCount() {
529   return static_cast<int>(deoptimization_entries_.size());
530 }
531
532
533 FrameStateDescriptor::FrameStateDescriptor(
534     Zone* zone, const FrameStateCallInfo& state_info, size_t parameters_count,
535     size_t locals_count, size_t stack_count, FrameStateDescriptor* outer_state)
536     : type_(state_info.type()),
537       bailout_id_(state_info.bailout_id()),
538       frame_state_combine_(state_info.state_combine()),
539       parameters_count_(parameters_count),
540       locals_count_(locals_count),
541       stack_count_(stack_count),
542       types_(zone),
543       outer_state_(outer_state),
544       jsfunction_(state_info.jsfunction()) {
545   types_.resize(GetSize(), kMachNone);
546 }
547
548 size_t FrameStateDescriptor::GetSize(OutputFrameStateCombine combine) const {
549   size_t size = parameters_count() + locals_count() + stack_count() +
550                 (HasContext() ? 1 : 0);
551   switch (combine.kind()) {
552     case OutputFrameStateCombine::kPushOutput:
553       size += combine.GetPushCount();
554       break;
555     case OutputFrameStateCombine::kPokeAt:
556       break;
557   }
558   return size;
559 }
560
561
562 size_t FrameStateDescriptor::GetTotalSize() const {
563   size_t total_size = 0;
564   for (const FrameStateDescriptor* iter = this; iter != NULL;
565        iter = iter->outer_state_) {
566     total_size += iter->GetSize();
567   }
568   return total_size;
569 }
570
571
572 size_t FrameStateDescriptor::GetFrameCount() const {
573   size_t count = 0;
574   for (const FrameStateDescriptor* iter = this; iter != NULL;
575        iter = iter->outer_state_) {
576     ++count;
577   }
578   return count;
579 }
580
581
582 size_t FrameStateDescriptor::GetJSFrameCount() const {
583   size_t count = 0;
584   for (const FrameStateDescriptor* iter = this; iter != NULL;
585        iter = iter->outer_state_) {
586     if (iter->type_ == JS_FRAME) {
587       ++count;
588     }
589   }
590   return count;
591 }
592
593
594 MachineType FrameStateDescriptor::GetType(size_t index) const {
595   return types_[index];
596 }
597
598
599 void FrameStateDescriptor::SetType(size_t index, MachineType type) {
600   DCHECK(index < GetSize());
601   types_[index] = type;
602 }
603
604
605 std::ostream& operator<<(std::ostream& os,
606                          const PrintableInstructionSequence& printable) {
607   const InstructionSequence& code = *printable.sequence_;
608   for (size_t i = 0; i < code.immediates_.size(); ++i) {
609     Constant constant = code.immediates_[i];
610     os << "IMM#" << i << ": " << constant << "\n";
611   }
612   int i = 0;
613   for (ConstantMap::const_iterator it = code.constants_.begin();
614        it != code.constants_.end(); ++i, ++it) {
615     os << "CST#" << i << ": v" << it->first << " = " << it->second << "\n";
616   }
617   for (int i = 0; i < code.InstructionBlockCount(); i++) {
618     BasicBlock::RpoNumber rpo = BasicBlock::RpoNumber::FromInt(i);
619     const InstructionBlock* block = code.InstructionBlockAt(rpo);
620     CHECK(block->rpo_number() == rpo);
621
622     os << "RPO#" << block->rpo_number();
623     os << ": AO#" << block->ao_number();
624     os << ": B" << block->id();
625     if (block->IsDeferred()) os << " (deferred)";
626     if (block->IsLoopHeader()) {
627       os << " loop blocks: [" << block->rpo_number() << ", "
628          << block->loop_end() << ")";
629     }
630     os << "  instructions: [" << block->code_start() << ", "
631        << block->code_end() << ")\n  predecessors:";
632
633     for (auto pred : block->predecessors()) {
634       const InstructionBlock* pred_block = code.InstructionBlockAt(pred);
635       os << " B" << pred_block->id();
636     }
637     os << "\n";
638
639     for (auto phi : block->phis()) {
640       os << "     phi: v" << phi->virtual_register() << " =";
641       for (auto op_vreg : phi->operands()) {
642         os << " v" << op_vreg;
643       }
644       os << "\n";
645     }
646
647     ScopedVector<char> buf(32);
648     PrintableInstruction printable_instr;
649     printable_instr.register_configuration_ = printable.register_configuration_;
650     for (int j = block->first_instruction_index();
651          j <= block->last_instruction_index(); j++) {
652       // TODO(svenpanne) Add some basic formatting to our streams.
653       SNPrintF(buf, "%5d", j);
654       printable_instr.instr_ = code.InstructionAt(j);
655       os << "   " << buf.start() << ": " << printable_instr << "\n";
656     }
657
658     for (auto succ : block->successors()) {
659       const InstructionBlock* succ_block = code.InstructionBlockAt(succ);
660       os << " B" << succ_block->id();
661     }
662     os << "\n";
663   }
664   return os;
665 }
666
667 }  // namespace compiler
668 }  // namespace internal
669 }  // namespace v8