lithium-s390.cc revision f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3
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/crankshaft/s390/lithium-s390.h"
6
7#include <sstream>
8
9#include "src/crankshaft/hydrogen-osr.h"
10#include "src/crankshaft/lithium-inl.h"
11#include "src/crankshaft/s390/lithium-codegen-s390.h"
12
13namespace v8 {
14namespace internal {
15
16#define DEFINE_COMPILE(type)                           \
17  void L##type::CompileToNative(LCodeGen* generator) { \
18    generator->Do##type(this);                         \
19  }
20LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
21#undef DEFINE_COMPILE
22
23#ifdef DEBUG
24void LInstruction::VerifyCall() {
25  // Call instructions can use only fixed registers as temporaries and
26  // outputs because all registers are blocked by the calling convention.
27  // Inputs operands must use a fixed register or use-at-start policy or
28  // a non-register policy.
29  DCHECK(Output() == NULL || LUnallocated::cast(Output())->HasFixedPolicy() ||
30         !LUnallocated::cast(Output())->HasRegisterPolicy());
31  for (UseIterator it(this); !it.Done(); it.Advance()) {
32    LUnallocated* operand = LUnallocated::cast(it.Current());
33    DCHECK(operand->HasFixedPolicy() || operand->IsUsedAtStart());
34  }
35  for (TempIterator it(this); !it.Done(); it.Advance()) {
36    LUnallocated* operand = LUnallocated::cast(it.Current());
37    DCHECK(operand->HasFixedPolicy() || !operand->HasRegisterPolicy());
38  }
39}
40#endif
41
42void LInstruction::PrintTo(StringStream* stream) {
43  stream->Add("%s ", this->Mnemonic());
44
45  PrintOutputOperandTo(stream);
46
47  PrintDataTo(stream);
48
49  if (HasEnvironment()) {
50    stream->Add(" ");
51    environment()->PrintTo(stream);
52  }
53
54  if (HasPointerMap()) {
55    stream->Add(" ");
56    pointer_map()->PrintTo(stream);
57  }
58}
59
60void LInstruction::PrintDataTo(StringStream* stream) {
61  stream->Add("= ");
62  for (int i = 0; i < InputCount(); i++) {
63    if (i > 0) stream->Add(" ");
64    if (InputAt(i) == NULL) {
65      stream->Add("NULL");
66    } else {
67      InputAt(i)->PrintTo(stream);
68    }
69  }
70}
71
72void LInstruction::PrintOutputOperandTo(StringStream* stream) {
73  if (HasResult()) result()->PrintTo(stream);
74}
75
76void LLabel::PrintDataTo(StringStream* stream) {
77  LGap::PrintDataTo(stream);
78  LLabel* rep = replacement();
79  if (rep != NULL) {
80    stream->Add(" Dead block replaced with B%d", rep->block_id());
81  }
82}
83
84bool LGap::IsRedundant() const {
85  for (int i = 0; i < 4; i++) {
86    if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) {
87      return false;
88    }
89  }
90
91  return true;
92}
93
94void LGap::PrintDataTo(StringStream* stream) {
95  for (int i = 0; i < 4; i++) {
96    stream->Add("(");
97    if (parallel_moves_[i] != NULL) {
98      parallel_moves_[i]->PrintDataTo(stream);
99    }
100    stream->Add(") ");
101  }
102}
103
104const char* LArithmeticD::Mnemonic() const {
105  switch (op()) {
106    case Token::ADD:
107      return "add-d";
108    case Token::SUB:
109      return "sub-d";
110    case Token::MUL:
111      return "mul-d";
112    case Token::DIV:
113      return "div-d";
114    case Token::MOD:
115      return "mod-d";
116    default:
117      UNREACHABLE();
118      return NULL;
119  }
120}
121
122const char* LArithmeticT::Mnemonic() const {
123  switch (op()) {
124    case Token::ADD:
125      return "add-t";
126    case Token::SUB:
127      return "sub-t";
128    case Token::MUL:
129      return "mul-t";
130    case Token::MOD:
131      return "mod-t";
132    case Token::DIV:
133      return "div-t";
134    case Token::BIT_AND:
135      return "bit-and-t";
136    case Token::BIT_OR:
137      return "bit-or-t";
138    case Token::BIT_XOR:
139      return "bit-xor-t";
140    case Token::ROR:
141      return "ror-t";
142    case Token::SHL:
143      return "shl-t";
144    case Token::SAR:
145      return "sar-t";
146    case Token::SHR:
147      return "shr-t";
148    default:
149      UNREACHABLE();
150      return NULL;
151  }
152}
153
154bool LGoto::HasInterestingComment(LCodeGen* gen) const {
155  return !gen->IsNextEmittedBlock(block_id());
156}
157
158void LGoto::PrintDataTo(StringStream* stream) {
159  stream->Add("B%d", block_id());
160}
161
162void LBranch::PrintDataTo(StringStream* stream) {
163  stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
164  value()->PrintTo(stream);
165}
166
167void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
168  stream->Add("if ");
169  left()->PrintTo(stream);
170  stream->Add(" %s ", Token::String(op()));
171  right()->PrintTo(stream);
172  stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
173}
174
175void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
176  stream->Add("if is_string(");
177  value()->PrintTo(stream);
178  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
179}
180
181void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
182  stream->Add("if is_smi(");
183  value()->PrintTo(stream);
184  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
185}
186
187void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) {
188  stream->Add("if is_undetectable(");
189  value()->PrintTo(stream);
190  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
191}
192
193void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
194  stream->Add("if string_compare(");
195  left()->PrintTo(stream);
196  right()->PrintTo(stream);
197  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
198}
199
200void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
201  stream->Add("if has_instance_type(");
202  value()->PrintTo(stream);
203  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
204}
205
206void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
207  stream->Add("if has_cached_array_index(");
208  value()->PrintTo(stream);
209  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
210}
211
212void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
213  stream->Add("if class_of_test(");
214  value()->PrintTo(stream);
215  stream->Add(", \"%o\") then B%d else B%d", *hydrogen()->class_name(),
216              true_block_id(), false_block_id());
217}
218
219void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
220  stream->Add("if typeof ");
221  value()->PrintTo(stream);
222  stream->Add(" == \"%s\" then B%d else B%d",
223              hydrogen()->type_literal()->ToCString().get(), true_block_id(),
224              false_block_id());
225}
226
227void LStoreCodeEntry::PrintDataTo(StringStream* stream) {
228  stream->Add(" = ");
229  function()->PrintTo(stream);
230  stream->Add(".code_entry = ");
231  code_object()->PrintTo(stream);
232}
233
234void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
235  stream->Add(" = ");
236  base_object()->PrintTo(stream);
237  stream->Add(" + ");
238  offset()->PrintTo(stream);
239}
240
241void LCallWithDescriptor::PrintDataTo(StringStream* stream) {
242  for (int i = 0; i < InputCount(); i++) {
243    InputAt(i)->PrintTo(stream);
244    stream->Add(" ");
245  }
246  stream->Add("#%d / ", arity());
247}
248
249void LLoadContextSlot::PrintDataTo(StringStream* stream) {
250  context()->PrintTo(stream);
251  stream->Add("[%d]", slot_index());
252}
253
254void LStoreContextSlot::PrintDataTo(StringStream* stream) {
255  context()->PrintTo(stream);
256  stream->Add("[%d] <- ", slot_index());
257  value()->PrintTo(stream);
258}
259
260void LInvokeFunction::PrintDataTo(StringStream* stream) {
261  stream->Add("= ");
262  function()->PrintTo(stream);
263  stream->Add(" #%d / ", arity());
264}
265
266void LCallNewArray::PrintDataTo(StringStream* stream) {
267  stream->Add("= ");
268  constructor()->PrintTo(stream);
269  stream->Add(" #%d / ", arity());
270  ElementsKind kind = hydrogen()->elements_kind();
271  stream->Add(" (%s) ", ElementsKindToString(kind));
272}
273
274void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
275  arguments()->PrintTo(stream);
276  stream->Add(" length ");
277  length()->PrintTo(stream);
278  stream->Add(" index ");
279  index()->PrintTo(stream);
280}
281
282void LStoreNamedField::PrintDataTo(StringStream* stream) {
283  object()->PrintTo(stream);
284  std::ostringstream os;
285  os << hydrogen()->access() << " <- ";
286  stream->Add(os.str().c_str());
287  value()->PrintTo(stream);
288}
289
290void LLoadKeyed::PrintDataTo(StringStream* stream) {
291  elements()->PrintTo(stream);
292  stream->Add("[");
293  key()->PrintTo(stream);
294  if (hydrogen()->IsDehoisted()) {
295    stream->Add(" + %d]", base_offset());
296  } else {
297    stream->Add("]");
298  }
299}
300
301void LStoreKeyed::PrintDataTo(StringStream* stream) {
302  elements()->PrintTo(stream);
303  stream->Add("[");
304  key()->PrintTo(stream);
305  if (hydrogen()->IsDehoisted()) {
306    stream->Add(" + %d] <-", base_offset());
307  } else {
308    stream->Add("] <- ");
309  }
310
311  if (value() == NULL) {
312    DCHECK(hydrogen()->IsConstantHoleStore() &&
313           hydrogen()->value()->representation().IsDouble());
314    stream->Add("<the hole(nan)>");
315  } else {
316    value()->PrintTo(stream);
317  }
318}
319
320void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
321  object()->PrintTo(stream);
322  stream->Add(" %p -> %p", *original_map(), *transitioned_map());
323}
324
325int LPlatformChunk::GetNextSpillIndex(RegisterKind kind) {
326  // Skip a slot if for a double-width slot.
327  if (kind == DOUBLE_REGISTERS) current_frame_slots_++;
328  return current_frame_slots_++;
329}
330
331LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind) {
332  int index = GetNextSpillIndex(kind);
333  if (kind == DOUBLE_REGISTERS) {
334    return LDoubleStackSlot::Create(index, zone());
335  } else {
336    DCHECK(kind == GENERAL_REGISTERS);
337    return LStackSlot::Create(index, zone());
338  }
339}
340
341LPlatformChunk* LChunkBuilder::Build() {
342  DCHECK(is_unused());
343  chunk_ = new (zone()) LPlatformChunk(info(), graph());
344  LPhase phase("L_Building chunk", chunk_);
345  status_ = BUILDING;
346
347  // If compiling for OSR, reserve space for the unoptimized frame,
348  // which will be subsumed into this frame.
349  if (graph()->has_osr()) {
350    for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
351      chunk_->GetNextSpillIndex(GENERAL_REGISTERS);
352    }
353  }
354
355  const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
356  for (int i = 0; i < blocks->length(); i++) {
357    HBasicBlock* next = NULL;
358    if (i < blocks->length() - 1) next = blocks->at(i + 1);
359    DoBasicBlock(blocks->at(i), next);
360    if (is_aborted()) return NULL;
361  }
362  status_ = DONE;
363  return chunk_;
364}
365
366LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
367  return new (zone()) LUnallocated(LUnallocated::FIXED_REGISTER, reg.code());
368}
369
370LUnallocated* LChunkBuilder::ToUnallocated(DoubleRegister reg) {
371  return new (zone())
372      LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER, reg.code());
373}
374
375LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
376  return Use(value, ToUnallocated(fixed_register));
377}
378
379LOperand* LChunkBuilder::UseFixedDouble(HValue* value, DoubleRegister reg) {
380  return Use(value, ToUnallocated(reg));
381}
382
383LOperand* LChunkBuilder::UseRegister(HValue* value) {
384  return Use(value,
385             new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
386}
387
388LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
389  return Use(value, new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
390                                              LUnallocated::USED_AT_START));
391}
392
393LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
394  return Use(value, new (zone()) LUnallocated(LUnallocated::WRITABLE_REGISTER));
395}
396
397LOperand* LChunkBuilder::Use(HValue* value) {
398  return Use(value, new (zone()) LUnallocated(LUnallocated::NONE));
399}
400
401LOperand* LChunkBuilder::UseAtStart(HValue* value) {
402  return Use(value, new (zone()) LUnallocated(LUnallocated::NONE,
403                                              LUnallocated::USED_AT_START));
404}
405
406LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
407  return value->IsConstant()
408             ? chunk_->DefineConstantOperand(HConstant::cast(value))
409             : Use(value);
410}
411
412LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
413  return value->IsConstant()
414             ? chunk_->DefineConstantOperand(HConstant::cast(value))
415             : UseAtStart(value);
416}
417
418LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
419  return value->IsConstant()
420             ? chunk_->DefineConstantOperand(HConstant::cast(value))
421             : UseRegister(value);
422}
423
424LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
425  return value->IsConstant()
426             ? chunk_->DefineConstantOperand(HConstant::cast(value))
427             : UseRegisterAtStart(value);
428}
429
430LOperand* LChunkBuilder::UseConstant(HValue* value) {
431  return chunk_->DefineConstantOperand(HConstant::cast(value));
432}
433
434LOperand* LChunkBuilder::UseAny(HValue* value) {
435  return value->IsConstant()
436             ? chunk_->DefineConstantOperand(HConstant::cast(value))
437             : Use(value, new (zone()) LUnallocated(LUnallocated::ANY));
438}
439
440LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
441  if (value->EmitAtUses()) {
442    HInstruction* instr = HInstruction::cast(value);
443    VisitInstruction(instr);
444  }
445  operand->set_virtual_register(value->id());
446  return operand;
447}
448
449LInstruction* LChunkBuilder::Define(LTemplateResultInstruction<1>* instr,
450                                    LUnallocated* result) {
451  result->set_virtual_register(current_instruction_->id());
452  instr->set_result(result);
453  return instr;
454}
455
456LInstruction* LChunkBuilder::DefineAsRegister(
457    LTemplateResultInstruction<1>* instr) {
458  return Define(instr,
459                new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
460}
461
462LInstruction* LChunkBuilder::DefineAsSpilled(
463    LTemplateResultInstruction<1>* instr, int index) {
464  return Define(instr,
465                new (zone()) LUnallocated(LUnallocated::FIXED_SLOT, index));
466}
467
468LInstruction* LChunkBuilder::DefineSameAsFirst(
469    LTemplateResultInstruction<1>* instr) {
470  return Define(instr,
471                new (zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
472}
473
474LInstruction* LChunkBuilder::DefineFixed(LTemplateResultInstruction<1>* instr,
475                                         Register reg) {
476  return Define(instr, ToUnallocated(reg));
477}
478
479LInstruction* LChunkBuilder::DefineFixedDouble(
480    LTemplateResultInstruction<1>* instr, DoubleRegister reg) {
481  return Define(instr, ToUnallocated(reg));
482}
483
484LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
485  HEnvironment* hydrogen_env = current_block_->last_environment();
486  return LChunkBuilderBase::AssignEnvironment(instr, hydrogen_env);
487}
488
489LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
490                                        HInstruction* hinstr,
491                                        CanDeoptimize can_deoptimize) {
492  info()->MarkAsNonDeferredCalling();
493#ifdef DEBUG
494  instr->VerifyCall();
495#endif
496  instr->MarkAsCall();
497  instr = AssignPointerMap(instr);
498
499  // If instruction does not have side-effects lazy deoptimization
500  // after the call will try to deoptimize to the point before the call.
501  // Thus we still need to attach environment to this call even if
502  // call sequence can not deoptimize eagerly.
503  bool needs_environment = (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) ||
504                           !hinstr->HasObservableSideEffects();
505  if (needs_environment && !instr->HasEnvironment()) {
506    instr = AssignEnvironment(instr);
507    // We can't really figure out if the environment is needed or not.
508    instr->environment()->set_has_been_used();
509  }
510
511  return instr;
512}
513
514LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
515  DCHECK(!instr->HasPointerMap());
516  instr->set_pointer_map(new (zone()) LPointerMap(zone()));
517  return instr;
518}
519
520LUnallocated* LChunkBuilder::TempRegister() {
521  LUnallocated* operand =
522      new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
523  int vreg = allocator_->GetVirtualRegister();
524  if (!allocator_->AllocationOk()) {
525    Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
526    vreg = 0;
527  }
528  operand->set_virtual_register(vreg);
529  return operand;
530}
531
532LUnallocated* LChunkBuilder::TempDoubleRegister() {
533  LUnallocated* operand =
534      new (zone()) LUnallocated(LUnallocated::MUST_HAVE_DOUBLE_REGISTER);
535  int vreg = allocator_->GetVirtualRegister();
536  if (!allocator_->AllocationOk()) {
537    Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
538    vreg = 0;
539  }
540  operand->set_virtual_register(vreg);
541  return operand;
542}
543
544LOperand* LChunkBuilder::FixedTemp(Register reg) {
545  LUnallocated* operand = ToUnallocated(reg);
546  DCHECK(operand->HasFixedPolicy());
547  return operand;
548}
549
550LOperand* LChunkBuilder::FixedTemp(DoubleRegister reg) {
551  LUnallocated* operand = ToUnallocated(reg);
552  DCHECK(operand->HasFixedPolicy());
553  return operand;
554}
555
556LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
557  return new (zone()) LLabel(instr->block());
558}
559
560LInstruction* LChunkBuilder::DoDummyUse(HDummyUse* instr) {
561  return DefineAsRegister(new (zone()) LDummyUse(UseAny(instr->value())));
562}
563
564LInstruction* LChunkBuilder::DoEnvironmentMarker(HEnvironmentMarker* instr) {
565  UNREACHABLE();
566  return NULL;
567}
568
569LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
570  return AssignEnvironment(new (zone()) LDeoptimize);
571}
572
573LInstruction* LChunkBuilder::DoShift(Token::Value op,
574                                     HBitwiseBinaryOperation* instr) {
575  if (instr->representation().IsSmiOrInteger32()) {
576    DCHECK(instr->left()->representation().Equals(instr->representation()));
577    DCHECK(instr->right()->representation().Equals(instr->representation()));
578    LOperand* left = UseRegisterAtStart(instr->left());
579
580    HValue* right_value = instr->right();
581    LOperand* right = NULL;
582    int constant_value = 0;
583    bool does_deopt = false;
584    if (right_value->IsConstant()) {
585      HConstant* constant = HConstant::cast(right_value);
586      right = chunk_->DefineConstantOperand(constant);
587      constant_value = constant->Integer32Value() & 0x1f;
588      // Left shifts can deoptimize if we shift by > 0 and the result cannot be
589      // truncated to smi.
590      if (instr->representation().IsSmi() && constant_value > 0) {
591        does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToSmi);
592      }
593    } else {
594      right = UseRegisterAtStart(right_value);
595    }
596
597    // Shift operations can only deoptimize if we do a logical shift
598    // by 0 and the result cannot be truncated to int32.
599    if (op == Token::SHR && constant_value == 0) {
600      does_deopt = !instr->CheckFlag(HInstruction::kUint32);
601    }
602
603    LInstruction* result =
604        DefineAsRegister(new (zone()) LShiftI(op, left, right, does_deopt));
605    return does_deopt ? AssignEnvironment(result) : result;
606  } else {
607    return DoArithmeticT(op, instr);
608  }
609}
610
611LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
612                                           HArithmeticBinaryOperation* instr) {
613  DCHECK(instr->representation().IsDouble());
614  DCHECK(instr->left()->representation().IsDouble());
615  DCHECK(instr->right()->representation().IsDouble());
616  if (op == Token::MOD) {
617    LOperand* left = UseFixedDouble(instr->left(), d1);
618    LOperand* right = UseFixedDouble(instr->right(), d2);
619    LArithmeticD* result = new (zone()) LArithmeticD(op, left, right);
620    // We call a C function for double modulo. It can't trigger a GC. We need
621    // to use fixed result register for the call.
622    // TODO(fschneider): Allow any register as input registers.
623    return MarkAsCall(DefineFixedDouble(result, d1), instr);
624  } else {
625    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
626    LOperand* right = UseRegisterAtStart(instr->BetterRightOperand());
627    LArithmeticD* result = new (zone()) LArithmeticD(op, left, right);
628    return DefineSameAsFirst(result);
629  }
630}
631
632LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
633                                           HBinaryOperation* instr) {
634  HValue* left = instr->left();
635  HValue* right = instr->right();
636  DCHECK(left->representation().IsTagged());
637  DCHECK(right->representation().IsTagged());
638  LOperand* context = UseFixed(instr->context(), cp);
639  LOperand* left_operand = UseFixed(left, r3);
640  LOperand* right_operand = UseFixed(right, r2);
641  LArithmeticT* result =
642      new (zone()) LArithmeticT(op, context, left_operand, right_operand);
643  return MarkAsCall(DefineFixed(result, r2), instr);
644}
645
646void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
647  DCHECK(is_building());
648  current_block_ = block;
649  next_block_ = next_block;
650  if (block->IsStartBlock()) {
651    block->UpdateEnvironment(graph_->start_environment());
652    argument_count_ = 0;
653  } else if (block->predecessors()->length() == 1) {
654    // We have a single predecessor => copy environment and outgoing
655    // argument count from the predecessor.
656    DCHECK(block->phis()->length() == 0);
657    HBasicBlock* pred = block->predecessors()->at(0);
658    HEnvironment* last_environment = pred->last_environment();
659    DCHECK(last_environment != NULL);
660    // Only copy the environment, if it is later used again.
661    if (pred->end()->SecondSuccessor() == NULL) {
662      DCHECK(pred->end()->FirstSuccessor() == block);
663    } else {
664      if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
665          pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
666        last_environment = last_environment->Copy();
667      }
668    }
669    block->UpdateEnvironment(last_environment);
670    DCHECK(pred->argument_count() >= 0);
671    argument_count_ = pred->argument_count();
672  } else {
673    // We are at a state join => process phis.
674    HBasicBlock* pred = block->predecessors()->at(0);
675    // No need to copy the environment, it cannot be used later.
676    HEnvironment* last_environment = pred->last_environment();
677    for (int i = 0; i < block->phis()->length(); ++i) {
678      HPhi* phi = block->phis()->at(i);
679      if (phi->HasMergedIndex()) {
680        last_environment->SetValueAt(phi->merged_index(), phi);
681      }
682    }
683    for (int i = 0; i < block->deleted_phis()->length(); ++i) {
684      if (block->deleted_phis()->at(i) < last_environment->length()) {
685        last_environment->SetValueAt(block->deleted_phis()->at(i),
686                                     graph_->GetConstantUndefined());
687      }
688    }
689    block->UpdateEnvironment(last_environment);
690    // Pick up the outgoing argument count of one of the predecessors.
691    argument_count_ = pred->argument_count();
692  }
693  HInstruction* current = block->first();
694  int start = chunk_->instructions()->length();
695  while (current != NULL && !is_aborted()) {
696    // Code for constants in registers is generated lazily.
697    if (!current->EmitAtUses()) {
698      VisitInstruction(current);
699    }
700    current = current->next();
701  }
702  int end = chunk_->instructions()->length() - 1;
703  if (end >= start) {
704    block->set_first_instruction_index(start);
705    block->set_last_instruction_index(end);
706  }
707  block->set_argument_count(argument_count_);
708  next_block_ = NULL;
709  current_block_ = NULL;
710}
711
712void LChunkBuilder::VisitInstruction(HInstruction* current) {
713  HInstruction* old_current = current_instruction_;
714  current_instruction_ = current;
715
716  LInstruction* instr = NULL;
717  if (current->CanReplaceWithDummyUses()) {
718    if (current->OperandCount() == 0) {
719      instr = DefineAsRegister(new (zone()) LDummy());
720    } else {
721      DCHECK(!current->OperandAt(0)->IsControlInstruction());
722      instr = DefineAsRegister(new (zone())
723                                   LDummyUse(UseAny(current->OperandAt(0))));
724    }
725    for (int i = 1; i < current->OperandCount(); ++i) {
726      if (current->OperandAt(i)->IsControlInstruction()) continue;
727      LInstruction* dummy =
728          new (zone()) LDummyUse(UseAny(current->OperandAt(i)));
729      dummy->set_hydrogen_value(current);
730      chunk_->AddInstruction(dummy, current_block_);
731    }
732  } else {
733    HBasicBlock* successor;
734    if (current->IsControlInstruction() &&
735        HControlInstruction::cast(current)->KnownSuccessorBlock(&successor) &&
736        successor != NULL) {
737      instr = new (zone()) LGoto(successor);
738    } else {
739      instr = current->CompileToLithium(this);
740    }
741  }
742
743  argument_count_ += current->argument_delta();
744  DCHECK(argument_count_ >= 0);
745
746  if (instr != NULL) {
747    AddInstruction(instr, current);
748  }
749
750  current_instruction_ = old_current;
751}
752
753void LChunkBuilder::AddInstruction(LInstruction* instr,
754                                   HInstruction* hydrogen_val) {
755  // Associate the hydrogen instruction first, since we may need it for
756  // the ClobbersRegisters() or ClobbersDoubleRegisters() calls below.
757  instr->set_hydrogen_value(hydrogen_val);
758
759#if DEBUG
760  // Make sure that the lithium instruction has either no fixed register
761  // constraints in temps or the result OR no uses that are only used at
762  // start. If this invariant doesn't hold, the register allocator can decide
763  // to insert a split of a range immediately before the instruction due to an
764  // already allocated register needing to be used for the instruction's fixed
765  // register constraint. In this case, The register allocator won't see an
766  // interference between the split child and the use-at-start (it would if
767  // the it was just a plain use), so it is free to move the split child into
768  // the same register that is used for the use-at-start.
769  // See https://code.google.com/p/chromium/issues/detail?id=201590
770  if (!(instr->ClobbersRegisters() &&
771        instr->ClobbersDoubleRegisters(isolate()))) {
772    int fixed = 0;
773    int used_at_start = 0;
774    for (UseIterator it(instr); !it.Done(); it.Advance()) {
775      LUnallocated* operand = LUnallocated::cast(it.Current());
776      if (operand->IsUsedAtStart()) ++used_at_start;
777    }
778    if (instr->Output() != NULL) {
779      if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
780    }
781    for (TempIterator it(instr); !it.Done(); it.Advance()) {
782      LUnallocated* operand = LUnallocated::cast(it.Current());
783      if (operand->HasFixedPolicy()) ++fixed;
784    }
785    DCHECK(fixed == 0 || used_at_start == 0);
786  }
787#endif
788
789  if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
790    instr = AssignPointerMap(instr);
791  }
792  if (FLAG_stress_environments && !instr->HasEnvironment()) {
793    instr = AssignEnvironment(instr);
794  }
795  chunk_->AddInstruction(instr, current_block_);
796
797  CreateLazyBailoutForCall(current_block_, instr, hydrogen_val);
798}
799
800LInstruction* LChunkBuilder::DoPrologue(HPrologue* instr) {
801  LInstruction* result = new (zone()) LPrologue();
802  if (info_->scope()->NeedsContext()) {
803    result = MarkAsCall(result, instr);
804  }
805  return result;
806}
807
808LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
809  return new (zone()) LGoto(instr->FirstSuccessor());
810}
811
812LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
813  HValue* value = instr->value();
814  Representation r = value->representation();
815  HType type = value->type();
816  ToBooleanICStub::Types expected = instr->expected_input_types();
817  if (expected.IsEmpty()) expected = ToBooleanICStub::Types::Generic();
818
819  bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
820                   type.IsJSArray() || type.IsHeapNumber() || type.IsString();
821  LInstruction* branch = new (zone()) LBranch(UseRegister(value));
822  if (!easy_case &&
823      ((!expected.Contains(ToBooleanICStub::SMI) && expected.NeedsMap()) ||
824       !expected.IsGeneric())) {
825    branch = AssignEnvironment(branch);
826  }
827  return branch;
828}
829
830LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
831  return new (zone()) LDebugBreak();
832}
833
834LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
835  DCHECK(instr->value()->representation().IsTagged());
836  LOperand* value = UseRegister(instr->value());
837  LOperand* temp = TempRegister();
838  return new (zone()) LCmpMapAndBranch(value, temp);
839}
840
841LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* instr) {
842  info()->MarkAsRequiresFrame();
843  LOperand* value = UseRegister(instr->value());
844  return DefineAsRegister(new (zone()) LArgumentsLength(value));
845}
846
847LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
848  info()->MarkAsRequiresFrame();
849  return DefineAsRegister(new (zone()) LArgumentsElements);
850}
851
852LInstruction* LChunkBuilder::DoHasInPrototypeChainAndBranch(
853    HHasInPrototypeChainAndBranch* instr) {
854  LOperand* object = UseRegister(instr->object());
855  LOperand* prototype = UseRegister(instr->prototype());
856  LHasInPrototypeChainAndBranch* result =
857      new (zone()) LHasInPrototypeChainAndBranch(object, prototype);
858  return AssignEnvironment(result);
859}
860
861LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
862  LOperand* receiver = UseRegisterAtStart(instr->receiver());
863  LOperand* function = UseRegisterAtStart(instr->function());
864  LWrapReceiver* result = new (zone()) LWrapReceiver(receiver, function);
865  return AssignEnvironment(DefineAsRegister(result));
866}
867
868LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
869  LOperand* function = UseFixed(instr->function(), r3);
870  LOperand* receiver = UseFixed(instr->receiver(), r2);
871  LOperand* length = UseFixed(instr->length(), r4);
872  LOperand* elements = UseFixed(instr->elements(), r5);
873  LApplyArguments* result =
874      new (zone()) LApplyArguments(function, receiver, length, elements);
875  return MarkAsCall(DefineFixed(result, r2), instr, CAN_DEOPTIMIZE_EAGERLY);
876}
877
878LInstruction* LChunkBuilder::DoPushArguments(HPushArguments* instr) {
879  int argc = instr->OperandCount();
880  for (int i = 0; i < argc; ++i) {
881    LOperand* argument = Use(instr->argument(i));
882    AddInstruction(new (zone()) LPushArgument(argument), instr);
883  }
884  return NULL;
885}
886
887LInstruction* LChunkBuilder::DoStoreCodeEntry(
888    HStoreCodeEntry* store_code_entry) {
889  LOperand* function = UseRegister(store_code_entry->function());
890  LOperand* code_object = UseTempRegister(store_code_entry->code_object());
891  return new (zone()) LStoreCodeEntry(function, code_object);
892}
893
894LInstruction* LChunkBuilder::DoInnerAllocatedObject(
895    HInnerAllocatedObject* instr) {
896  LOperand* base_object = UseRegisterAtStart(instr->base_object());
897  LOperand* offset = UseRegisterOrConstantAtStart(instr->offset());
898  return DefineAsRegister(new (zone())
899                              LInnerAllocatedObject(base_object, offset));
900}
901
902LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
903  return instr->HasNoUses() ? NULL
904                            : DefineAsRegister(new (zone()) LThisFunction);
905}
906
907LInstruction* LChunkBuilder::DoContext(HContext* instr) {
908  if (instr->HasNoUses()) return NULL;
909
910  if (info()->IsStub()) {
911    return DefineFixed(new (zone()) LContext, cp);
912  }
913
914  return DefineAsRegister(new (zone()) LContext);
915}
916
917LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
918  LOperand* context = UseFixed(instr->context(), cp);
919  return MarkAsCall(new (zone()) LDeclareGlobals(context), instr);
920}
921
922LInstruction* LChunkBuilder::DoCallWithDescriptor(HCallWithDescriptor* instr) {
923  CallInterfaceDescriptor descriptor = instr->descriptor();
924  DCHECK_EQ(descriptor.GetParameterCount() +
925                LCallWithDescriptor::kImplicitRegisterParameterCount,
926            instr->OperandCount());
927
928  LOperand* target = UseRegisterOrConstantAtStart(instr->target());
929  ZoneList<LOperand*> ops(instr->OperandCount(), zone());
930  // Target
931  ops.Add(target, zone());
932  // Context
933  LOperand* op = UseFixed(instr->OperandAt(1), cp);
934  ops.Add(op, zone());
935  // Load register parameters.
936  int i = 0;
937  for (; i < descriptor.GetRegisterParameterCount(); i++) {
938    op = UseFixed(instr->OperandAt(
939                      i + LCallWithDescriptor::kImplicitRegisterParameterCount),
940                  descriptor.GetRegisterParameter(i));
941    ops.Add(op, zone());
942  }
943  // Push stack parameters.
944  for (; i < descriptor.GetParameterCount(); i++) {
945    op = UseAny(instr->OperandAt(
946        i + LCallWithDescriptor::kImplicitRegisterParameterCount));
947    AddInstruction(new (zone()) LPushArgument(op), instr);
948  }
949
950  LCallWithDescriptor* result =
951      new (zone()) LCallWithDescriptor(descriptor, ops, zone());
952  if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
953    result->MarkAsSyntacticTailCall();
954  }
955  return MarkAsCall(DefineFixed(result, r2), instr);
956}
957
958LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
959  LOperand* context = UseFixed(instr->context(), cp);
960  LOperand* function = UseFixed(instr->function(), r3);
961  LInvokeFunction* result = new (zone()) LInvokeFunction(context, function);
962  if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
963    result->MarkAsSyntacticTailCall();
964  }
965  return MarkAsCall(DefineFixed(result, r2), instr, CANNOT_DEOPTIMIZE_EAGERLY);
966}
967
968LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
969  switch (instr->op()) {
970    case kMathFloor:
971      return DoMathFloor(instr);
972    case kMathRound:
973      return DoMathRound(instr);
974    case kMathFround:
975      return DoMathFround(instr);
976    case kMathAbs:
977      return DoMathAbs(instr);
978    case kMathLog:
979      return DoMathLog(instr);
980    case kMathCos:
981      return DoMathCos(instr);
982    case kMathSin:
983      return DoMathSin(instr);
984    case kMathExp:
985      return DoMathExp(instr);
986    case kMathSqrt:
987      return DoMathSqrt(instr);
988    case kMathPowHalf:
989      return DoMathPowHalf(instr);
990    case kMathClz32:
991      return DoMathClz32(instr);
992    default:
993      UNREACHABLE();
994      return NULL;
995  }
996}
997
998LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
999  LOperand* input = UseRegister(instr->value());
1000  LMathFloor* result = new (zone()) LMathFloor(input);
1001  return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
1002}
1003
1004LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
1005  LOperand* input = UseRegister(instr->value());
1006  LOperand* temp = TempDoubleRegister();
1007  LMathRound* result = new (zone()) LMathRound(input, temp);
1008  return AssignEnvironment(DefineAsRegister(result));
1009}
1010
1011LInstruction* LChunkBuilder::DoMathFround(HUnaryMathOperation* instr) {
1012  LOperand* input = UseRegister(instr->value());
1013  LMathFround* result = new (zone()) LMathFround(input);
1014  return DefineAsRegister(result);
1015}
1016
1017LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
1018  Representation r = instr->value()->representation();
1019  LOperand* context = (r.IsDouble() || r.IsSmiOrInteger32())
1020                          ? NULL
1021                          : UseFixed(instr->context(), cp);
1022  LOperand* input = UseRegister(instr->value());
1023  LInstruction* result =
1024      DefineAsRegister(new (zone()) LMathAbs(context, input));
1025  if (!r.IsDouble() && !r.IsSmiOrInteger32()) result = AssignPointerMap(result);
1026  if (!r.IsDouble()) result = AssignEnvironment(result);
1027  return result;
1028}
1029
1030LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
1031  DCHECK(instr->representation().IsDouble());
1032  DCHECK(instr->value()->representation().IsDouble());
1033  LOperand* input = UseFixedDouble(instr->value(), d0);
1034  return MarkAsCall(DefineFixedDouble(new (zone()) LMathLog(input), d0), instr);
1035}
1036
1037LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
1038  LOperand* input = UseRegisterAtStart(instr->value());
1039  LMathClz32* result = new (zone()) LMathClz32(input);
1040  return DefineAsRegister(result);
1041}
1042
1043LInstruction* LChunkBuilder::DoMathCos(HUnaryMathOperation* instr) {
1044  DCHECK(instr->representation().IsDouble());
1045  DCHECK(instr->value()->representation().IsDouble());
1046  LOperand* input = UseFixedDouble(instr->value(), d0);
1047  return MarkAsCall(DefineFixedDouble(new (zone()) LMathCos(input), d0), instr);
1048}
1049
1050LInstruction* LChunkBuilder::DoMathSin(HUnaryMathOperation* instr) {
1051  DCHECK(instr->representation().IsDouble());
1052  DCHECK(instr->value()->representation().IsDouble());
1053  LOperand* input = UseFixedDouble(instr->value(), d0);
1054  return MarkAsCall(DefineFixedDouble(new (zone()) LMathSin(input), d0), instr);
1055}
1056
1057LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
1058  DCHECK(instr->representation().IsDouble());
1059  DCHECK(instr->value()->representation().IsDouble());
1060  LOperand* input = UseFixedDouble(instr->value(), d0);
1061  return MarkAsCall(DefineFixedDouble(new (zone()) LMathExp(input), d0), instr);
1062}
1063
1064LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
1065  LOperand* input = UseRegisterAtStart(instr->value());
1066  LMathSqrt* result = new (zone()) LMathSqrt(input);
1067  return DefineAsRegister(result);
1068}
1069
1070LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
1071  LOperand* input = UseRegisterAtStart(instr->value());
1072  LMathPowHalf* result = new (zone()) LMathPowHalf(input);
1073  return DefineAsRegister(result);
1074}
1075
1076LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
1077  LOperand* context = UseFixed(instr->context(), cp);
1078  LOperand* constructor = UseFixed(instr->constructor(), r3);
1079  LCallNewArray* result = new (zone()) LCallNewArray(context, constructor);
1080  return MarkAsCall(DefineFixed(result, r2), instr);
1081}
1082
1083LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1084  LOperand* context = UseFixed(instr->context(), cp);
1085  return MarkAsCall(DefineFixed(new (zone()) LCallRuntime(context), r2), instr);
1086}
1087
1088LInstruction* LChunkBuilder::DoRor(HRor* instr) {
1089  return DoShift(Token::ROR, instr);
1090}
1091
1092LInstruction* LChunkBuilder::DoShr(HShr* instr) {
1093  return DoShift(Token::SHR, instr);
1094}
1095
1096LInstruction* LChunkBuilder::DoSar(HSar* instr) {
1097  return DoShift(Token::SAR, instr);
1098}
1099
1100LInstruction* LChunkBuilder::DoShl(HShl* instr) {
1101  return DoShift(Token::SHL, instr);
1102}
1103
1104LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
1105  if (instr->representation().IsSmiOrInteger32()) {
1106    DCHECK(instr->left()->representation().Equals(instr->representation()));
1107    DCHECK(instr->right()->representation().Equals(instr->representation()));
1108    DCHECK(instr->CheckFlag(HValue::kTruncatingToInt32));
1109
1110    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1111    LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
1112    return DefineAsRegister(new (zone()) LBitI(left, right));
1113  } else {
1114    return DoArithmeticT(instr->op(), instr);
1115  }
1116}
1117
1118LInstruction* LChunkBuilder::DoDivByPowerOf2I(HDiv* instr) {
1119  DCHECK(instr->representation().IsSmiOrInteger32());
1120  DCHECK(instr->left()->representation().Equals(instr->representation()));
1121  DCHECK(instr->right()->representation().Equals(instr->representation()));
1122  LOperand* dividend = UseRegister(instr->left());
1123  int32_t divisor = instr->right()->GetInteger32Constant();
1124  LInstruction* result =
1125      DefineAsRegister(new (zone()) LDivByPowerOf2I(dividend, divisor));
1126  if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1127      (instr->CheckFlag(HValue::kCanOverflow) && divisor == -1) ||
1128      (!instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
1129       divisor != 1 && divisor != -1)) {
1130    result = AssignEnvironment(result);
1131  }
1132  return result;
1133}
1134
1135LInstruction* LChunkBuilder::DoDivByConstI(HDiv* instr) {
1136  DCHECK(instr->representation().IsInteger32());
1137  DCHECK(instr->left()->representation().Equals(instr->representation()));
1138  DCHECK(instr->right()->representation().Equals(instr->representation()));
1139  LOperand* dividend = UseRegister(instr->left());
1140  int32_t divisor = instr->right()->GetInteger32Constant();
1141  LInstruction* result =
1142      DefineAsRegister(new (zone()) LDivByConstI(dividend, divisor));
1143  if (divisor == 0 ||
1144      (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1145      !instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
1146    result = AssignEnvironment(result);
1147  }
1148  return result;
1149}
1150
1151LInstruction* LChunkBuilder::DoDivI(HDiv* instr) {
1152  DCHECK(instr->representation().IsSmiOrInteger32());
1153  DCHECK(instr->left()->representation().Equals(instr->representation()));
1154  DCHECK(instr->right()->representation().Equals(instr->representation()));
1155  LOperand* dividend = UseRegister(instr->left());
1156  LOperand* divisor = UseRegister(instr->right());
1157  LInstruction* result =
1158      DefineAsRegister(new (zone()) LDivI(dividend, divisor));
1159  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1160      instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
1161      (instr->CheckFlag(HValue::kCanOverflow) &&
1162       !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32)) ||
1163      (!instr->IsMathFloorOfDiv() &&
1164       !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
1165    result = AssignEnvironment(result);
1166  }
1167  return result;
1168}
1169
1170LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1171  if (instr->representation().IsSmiOrInteger32()) {
1172    if (instr->RightIsPowerOf2()) {
1173      return DoDivByPowerOf2I(instr);
1174    } else if (instr->right()->IsConstant()) {
1175      return DoDivByConstI(instr);
1176    } else {
1177      return DoDivI(instr);
1178    }
1179  } else if (instr->representation().IsDouble()) {
1180    return DoArithmeticD(Token::DIV, instr);
1181  } else {
1182    return DoArithmeticT(Token::DIV, instr);
1183  }
1184}
1185
1186LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
1187  LOperand* dividend = UseRegisterAtStart(instr->left());
1188  int32_t divisor = instr->right()->GetInteger32Constant();
1189  LInstruction* result =
1190      DefineAsRegister(new (zone()) LFlooringDivByPowerOf2I(dividend, divisor));
1191  if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1192      (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
1193    result = AssignEnvironment(result);
1194  }
1195  return result;
1196}
1197
1198LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) {
1199  DCHECK(instr->representation().IsInteger32());
1200  DCHECK(instr->left()->representation().Equals(instr->representation()));
1201  DCHECK(instr->right()->representation().Equals(instr->representation()));
1202  LOperand* dividend = UseRegister(instr->left());
1203  int32_t divisor = instr->right()->GetInteger32Constant();
1204  LOperand* temp =
1205      ((divisor > 0 && !instr->CheckFlag(HValue::kLeftCanBeNegative)) ||
1206       (divisor < 0 && !instr->CheckFlag(HValue::kLeftCanBePositive)))
1207          ? NULL
1208          : TempRegister();
1209  LInstruction* result = DefineAsRegister(
1210      new (zone()) LFlooringDivByConstI(dividend, divisor, temp));
1211  if (divisor == 0 ||
1212      (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0)) {
1213    result = AssignEnvironment(result);
1214  }
1215  return result;
1216}
1217
1218LInstruction* LChunkBuilder::DoFlooringDivI(HMathFloorOfDiv* instr) {
1219  DCHECK(instr->representation().IsSmiOrInteger32());
1220  DCHECK(instr->left()->representation().Equals(instr->representation()));
1221  DCHECK(instr->right()->representation().Equals(instr->representation()));
1222  LOperand* dividend = UseRegister(instr->left());
1223  LOperand* divisor = UseRegister(instr->right());
1224  LInstruction* result =
1225      DefineAsRegister(new (zone()) LFlooringDivI(dividend, divisor));
1226  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1227      instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
1228      (instr->CheckFlag(HValue::kCanOverflow) &&
1229       !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
1230    result = AssignEnvironment(result);
1231  }
1232  return result;
1233}
1234
1235LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
1236  if (instr->RightIsPowerOf2()) {
1237    return DoFlooringDivByPowerOf2I(instr);
1238  } else if (instr->right()->IsConstant()) {
1239    return DoFlooringDivByConstI(instr);
1240  } else {
1241    return DoFlooringDivI(instr);
1242  }
1243}
1244
1245LInstruction* LChunkBuilder::DoModByPowerOf2I(HMod* instr) {
1246  DCHECK(instr->representation().IsSmiOrInteger32());
1247  DCHECK(instr->left()->representation().Equals(instr->representation()));
1248  DCHECK(instr->right()->representation().Equals(instr->representation()));
1249  LOperand* dividend = UseRegisterAtStart(instr->left());
1250  int32_t divisor = instr->right()->GetInteger32Constant();
1251  LInstruction* result =
1252      DefineSameAsFirst(new (zone()) LModByPowerOf2I(dividend, divisor));
1253  if (instr->CheckFlag(HValue::kLeftCanBeNegative) &&
1254      instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1255    result = AssignEnvironment(result);
1256  }
1257  return result;
1258}
1259
1260LInstruction* LChunkBuilder::DoModByConstI(HMod* instr) {
1261  DCHECK(instr->representation().IsSmiOrInteger32());
1262  DCHECK(instr->left()->representation().Equals(instr->representation()));
1263  DCHECK(instr->right()->representation().Equals(instr->representation()));
1264  LOperand* dividend = UseRegister(instr->left());
1265  int32_t divisor = instr->right()->GetInteger32Constant();
1266  LInstruction* result =
1267      DefineAsRegister(new (zone()) LModByConstI(dividend, divisor));
1268  if (divisor == 0 || instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1269    result = AssignEnvironment(result);
1270  }
1271  return result;
1272}
1273
1274LInstruction* LChunkBuilder::DoModI(HMod* instr) {
1275  DCHECK(instr->representation().IsSmiOrInteger32());
1276  DCHECK(instr->left()->representation().Equals(instr->representation()));
1277  DCHECK(instr->right()->representation().Equals(instr->representation()));
1278  LOperand* dividend = UseRegister(instr->left());
1279  LOperand* divisor = UseRegister(instr->right());
1280  LInstruction* result =
1281      DefineAsRegister(new (zone()) LModI(dividend, divisor));
1282  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1283      instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1284    result = AssignEnvironment(result);
1285  }
1286  return result;
1287}
1288
1289LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1290  if (instr->representation().IsSmiOrInteger32()) {
1291    if (instr->RightIsPowerOf2()) {
1292      return DoModByPowerOf2I(instr);
1293    } else if (instr->right()->IsConstant()) {
1294      return DoModByConstI(instr);
1295    } else {
1296      return DoModI(instr);
1297    }
1298  } else if (instr->representation().IsDouble()) {
1299    return DoArithmeticD(Token::MOD, instr);
1300  } else {
1301    return DoArithmeticT(Token::MOD, instr);
1302  }
1303}
1304
1305LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1306  if (instr->representation().IsSmiOrInteger32()) {
1307    DCHECK(instr->left()->representation().Equals(instr->representation()));
1308    DCHECK(instr->right()->representation().Equals(instr->representation()));
1309    HValue* left = instr->BetterLeftOperand();
1310    HValue* right = instr->BetterRightOperand();
1311    LOperand* left_op;
1312    LOperand* right_op;
1313    bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
1314    bool bailout_on_minus_zero = instr->CheckFlag(HValue::kBailoutOnMinusZero);
1315
1316    int32_t constant_value = 0;
1317    if (right->IsConstant()) {
1318      HConstant* constant = HConstant::cast(right);
1319      constant_value = constant->Integer32Value();
1320      // Constants -1, 0 and 1 can be optimized if the result can overflow.
1321      // For other constants, it can be optimized only without overflow.
1322      if (!can_overflow || ((constant_value >= -1) && (constant_value <= 1))) {
1323        left_op = UseRegisterAtStart(left);
1324        right_op = UseConstant(right);
1325      } else {
1326        if (bailout_on_minus_zero) {
1327          left_op = UseRegister(left);
1328        } else {
1329          left_op = UseRegisterAtStart(left);
1330        }
1331        right_op = UseRegister(right);
1332      }
1333    } else {
1334      if (bailout_on_minus_zero) {
1335        left_op = UseRegister(left);
1336      } else {
1337        left_op = UseRegisterAtStart(left);
1338      }
1339      right_op = UseRegister(right);
1340    }
1341    LMulI* mul = new (zone()) LMulI(left_op, right_op);
1342    if (right_op->IsConstantOperand()
1343            ? ((can_overflow && constant_value == -1) ||
1344               (bailout_on_minus_zero && constant_value <= 0))
1345            : (can_overflow || bailout_on_minus_zero)) {
1346      AssignEnvironment(mul);
1347    }
1348    return DefineAsRegister(mul);
1349
1350  } else if (instr->representation().IsDouble()) {
1351    return DoArithmeticD(Token::MUL, instr);
1352  } else {
1353    return DoArithmeticT(Token::MUL, instr);
1354  }
1355}
1356
1357LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1358  if (instr->representation().IsSmiOrInteger32()) {
1359    DCHECK(instr->left()->representation().Equals(instr->representation()));
1360    DCHECK(instr->right()->representation().Equals(instr->representation()));
1361
1362    if (instr->left()->IsConstant() &&
1363        !instr->CheckFlag(HValue::kCanOverflow)) {
1364      // If lhs is constant, do reverse subtraction instead.
1365      return DoRSub(instr);
1366    }
1367
1368    LOperand* left = UseRegisterAtStart(instr->left());
1369    LOperand* right = UseOrConstantAtStart(instr->right());
1370    LSubI* sub = new (zone()) LSubI(left, right);
1371    LInstruction* result = DefineAsRegister(sub);
1372    if (instr->CheckFlag(HValue::kCanOverflow)) {
1373      result = AssignEnvironment(result);
1374    }
1375    return result;
1376  } else if (instr->representation().IsDouble()) {
1377    return DoArithmeticD(Token::SUB, instr);
1378  } else {
1379    return DoArithmeticT(Token::SUB, instr);
1380  }
1381}
1382
1383LInstruction* LChunkBuilder::DoRSub(HSub* instr) {
1384  DCHECK(instr->representation().IsSmiOrInteger32());
1385  DCHECK(instr->left()->representation().Equals(instr->representation()));
1386  DCHECK(instr->right()->representation().Equals(instr->representation()));
1387  DCHECK(!instr->CheckFlag(HValue::kCanOverflow));
1388
1389  // Note: The lhs of the subtraction becomes the rhs of the
1390  // reverse-subtraction.
1391  LOperand* left = UseRegisterAtStart(instr->right());
1392  LOperand* right = UseOrConstantAtStart(instr->left());
1393  LRSubI* rsb = new (zone()) LRSubI(left, right);
1394  LInstruction* result = DefineAsRegister(rsb);
1395  return result;
1396}
1397
1398LInstruction* LChunkBuilder::DoMultiplyAdd(HMul* mul, HValue* addend) {
1399  LOperand* multiplier_op = UseRegister(mul->left());
1400  LOperand* multiplicand_op = UseRegister(mul->right());
1401  LOperand* addend_op = UseRegister(addend);
1402  return DefineAsRegister(
1403      new (zone()) LMultiplyAddD(addend_op, multiplier_op, multiplicand_op));
1404}
1405
1406LInstruction* LChunkBuilder::DoMultiplySub(HValue* minuend, HMul* mul) {
1407  LOperand* minuend_op = UseRegister(minuend);
1408  LOperand* multiplier_op = UseRegister(mul->left());
1409  LOperand* multiplicand_op = UseRegister(mul->right());
1410
1411  return DefineAsRegister(
1412      new (zone()) LMultiplySubD(minuend_op, multiplier_op, multiplicand_op));
1413}
1414
1415LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1416  if (instr->representation().IsSmiOrInteger32()) {
1417    DCHECK(instr->left()->representation().Equals(instr->representation()));
1418    DCHECK(instr->right()->representation().Equals(instr->representation()));
1419    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1420    LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
1421    LAddI* add = new (zone()) LAddI(left, right);
1422    LInstruction* result = DefineAsRegister(add);
1423    if (instr->CheckFlag(HValue::kCanOverflow)) {
1424      result = AssignEnvironment(result);
1425    }
1426    return result;
1427  } else if (instr->representation().IsExternal()) {
1428    DCHECK(instr->IsConsistentExternalRepresentation());
1429    DCHECK(!instr->CheckFlag(HValue::kCanOverflow));
1430    LOperand* left = UseRegisterAtStart(instr->left());
1431    LOperand* right = UseOrConstantAtStart(instr->right());
1432    LAddI* add = new (zone()) LAddI(left, right);
1433    LInstruction* result = DefineAsRegister(add);
1434    return result;
1435  } else if (instr->representation().IsDouble()) {
1436    return DoArithmeticD(Token::ADD, instr);
1437  } else {
1438    return DoArithmeticT(Token::ADD, instr);
1439  }
1440}
1441
1442LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
1443  LOperand* left = NULL;
1444  LOperand* right = NULL;
1445  if (instr->representation().IsSmiOrInteger32()) {
1446    DCHECK(instr->left()->representation().Equals(instr->representation()));
1447    DCHECK(instr->right()->representation().Equals(instr->representation()));
1448    left = UseRegisterAtStart(instr->BetterLeftOperand());
1449    right = UseOrConstantAtStart(instr->BetterRightOperand());
1450  } else {
1451    DCHECK(instr->representation().IsDouble());
1452    DCHECK(instr->left()->representation().IsDouble());
1453    DCHECK(instr->right()->representation().IsDouble());
1454    left = UseRegister(instr->left());
1455    right = UseRegister(instr->right());
1456  }
1457  return DefineAsRegister(new (zone()) LMathMinMax(left, right));
1458}
1459
1460LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1461  DCHECK(instr->representation().IsDouble());
1462  // We call a C function for double power. It can't trigger a GC.
1463  // We need to use fixed result register for the call.
1464  Representation exponent_type = instr->right()->representation();
1465  DCHECK(instr->left()->representation().IsDouble());
1466  LOperand* left = UseFixedDouble(instr->left(), d1);
1467  LOperand* right = exponent_type.IsDouble()
1468                        ? UseFixedDouble(instr->right(), d2)
1469                        : UseFixed(instr->right(), r4);
1470  LPower* result = new (zone()) LPower(left, right);
1471  return MarkAsCall(DefineFixedDouble(result, d3), instr,
1472                    CAN_DEOPTIMIZE_EAGERLY);
1473}
1474
1475LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
1476  DCHECK(instr->left()->representation().IsTagged());
1477  DCHECK(instr->right()->representation().IsTagged());
1478  LOperand* context = UseFixed(instr->context(), cp);
1479  LOperand* left = UseFixed(instr->left(), r3);
1480  LOperand* right = UseFixed(instr->right(), r2);
1481  LCmpT* result = new (zone()) LCmpT(context, left, right);
1482  return MarkAsCall(DefineFixed(result, r2), instr);
1483}
1484
1485LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
1486    HCompareNumericAndBranch* instr) {
1487  Representation r = instr->representation();
1488  if (r.IsSmiOrInteger32()) {
1489    DCHECK(instr->left()->representation().Equals(r));
1490    DCHECK(instr->right()->representation().Equals(r));
1491    LOperand* left = UseRegisterOrConstantAtStart(instr->left());
1492    LOperand* right = UseRegisterOrConstantAtStart(instr->right());
1493    return new (zone()) LCompareNumericAndBranch(left, right);
1494  } else {
1495    DCHECK(r.IsDouble());
1496    DCHECK(instr->left()->representation().IsDouble());
1497    DCHECK(instr->right()->representation().IsDouble());
1498    LOperand* left = UseRegisterAtStart(instr->left());
1499    LOperand* right = UseRegisterAtStart(instr->right());
1500    return new (zone()) LCompareNumericAndBranch(left, right);
1501  }
1502}
1503
1504LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
1505    HCompareObjectEqAndBranch* instr) {
1506  LOperand* left = UseRegisterAtStart(instr->left());
1507  LOperand* right = UseRegisterAtStart(instr->right());
1508  return new (zone()) LCmpObjectEqAndBranch(left, right);
1509}
1510
1511LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
1512    HCompareHoleAndBranch* instr) {
1513  LOperand* value = UseRegisterAtStart(instr->value());
1514  return new (zone()) LCmpHoleAndBranch(value);
1515}
1516
1517LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
1518  DCHECK(instr->value()->representation().IsTagged());
1519  LOperand* value = UseRegisterAtStart(instr->value());
1520  LOperand* temp = TempRegister();
1521  return new (zone()) LIsStringAndBranch(value, temp);
1522}
1523
1524LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
1525  DCHECK(instr->value()->representation().IsTagged());
1526  return new (zone()) LIsSmiAndBranch(Use(instr->value()));
1527}
1528
1529LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
1530    HIsUndetectableAndBranch* instr) {
1531  DCHECK(instr->value()->representation().IsTagged());
1532  LOperand* value = UseRegisterAtStart(instr->value());
1533  return new (zone()) LIsUndetectableAndBranch(value, TempRegister());
1534}
1535
1536LInstruction* LChunkBuilder::DoStringCompareAndBranch(
1537    HStringCompareAndBranch* instr) {
1538  DCHECK(instr->left()->representation().IsTagged());
1539  DCHECK(instr->right()->representation().IsTagged());
1540  LOperand* context = UseFixed(instr->context(), cp);
1541  LOperand* left = UseFixed(instr->left(), r3);
1542  LOperand* right = UseFixed(instr->right(), r2);
1543  LStringCompareAndBranch* result =
1544      new (zone()) LStringCompareAndBranch(context, left, right);
1545  return MarkAsCall(result, instr);
1546}
1547
1548LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
1549    HHasInstanceTypeAndBranch* instr) {
1550  DCHECK(instr->value()->representation().IsTagged());
1551  LOperand* value = UseRegisterAtStart(instr->value());
1552  return new (zone()) LHasInstanceTypeAndBranch(value);
1553}
1554
1555LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
1556    HGetCachedArrayIndex* instr) {
1557  DCHECK(instr->value()->representation().IsTagged());
1558  LOperand* value = UseRegisterAtStart(instr->value());
1559
1560  return DefineAsRegister(new (zone()) LGetCachedArrayIndex(value));
1561}
1562
1563LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch(
1564    HHasCachedArrayIndexAndBranch* instr) {
1565  DCHECK(instr->value()->representation().IsTagged());
1566  return new (zone())
1567      LHasCachedArrayIndexAndBranch(UseRegisterAtStart(instr->value()));
1568}
1569
1570LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
1571    HClassOfTestAndBranch* instr) {
1572  DCHECK(instr->value()->representation().IsTagged());
1573  LOperand* value = UseRegister(instr->value());
1574  return new (zone()) LClassOfTestAndBranch(value, TempRegister());
1575}
1576
1577LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) {
1578  LOperand* string = UseRegisterAtStart(instr->string());
1579  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
1580  return DefineAsRegister(new (zone()) LSeqStringGetChar(string, index));
1581}
1582
1583LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
1584  LOperand* string = UseRegisterAtStart(instr->string());
1585  LOperand* index = FLAG_debug_code
1586                        ? UseRegisterAtStart(instr->index())
1587                        : UseRegisterOrConstantAtStart(instr->index());
1588  LOperand* value = UseRegisterAtStart(instr->value());
1589  LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), cp) : NULL;
1590  return new (zone()) LSeqStringSetChar(context, string, index, value);
1591}
1592
1593LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1594  if (!FLAG_debug_code && instr->skip_check()) return NULL;
1595  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
1596  LOperand* length = !index->IsConstantOperand()
1597                         ? UseRegisterOrConstantAtStart(instr->length())
1598                         : UseRegisterAtStart(instr->length());
1599  LInstruction* result = new (zone()) LBoundsCheck(index, length);
1600  if (!FLAG_debug_code || !instr->skip_check()) {
1601    result = AssignEnvironment(result);
1602  }
1603  return result;
1604}
1605
1606LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
1607  // The control instruction marking the end of a block that completed
1608  // abruptly (e.g., threw an exception).  There is nothing specific to do.
1609  return NULL;
1610}
1611
1612LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) { return NULL; }
1613
1614LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
1615  // All HForceRepresentation instructions should be eliminated in the
1616  // representation change phase of Hydrogen.
1617  UNREACHABLE();
1618  return NULL;
1619}
1620
1621LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1622  Representation from = instr->from();
1623  Representation to = instr->to();
1624  HValue* val = instr->value();
1625  if (from.IsSmi()) {
1626    if (to.IsTagged()) {
1627      LOperand* value = UseRegister(val);
1628      return DefineSameAsFirst(new (zone()) LDummyUse(value));
1629    }
1630    from = Representation::Tagged();
1631  }
1632  if (from.IsTagged()) {
1633    if (to.IsDouble()) {
1634      LOperand* value = UseRegister(val);
1635      LInstruction* result =
1636          DefineAsRegister(new (zone()) LNumberUntagD(value));
1637      if (!val->representation().IsSmi()) result = AssignEnvironment(result);
1638      return result;
1639    } else if (to.IsSmi()) {
1640      LOperand* value = UseRegister(val);
1641      if (val->type().IsSmi()) {
1642        return DefineSameAsFirst(new (zone()) LDummyUse(value));
1643      }
1644      return AssignEnvironment(
1645          DefineSameAsFirst(new (zone()) LCheckSmi(value)));
1646    } else {
1647      DCHECK(to.IsInteger32());
1648      if (val->type().IsSmi() || val->representation().IsSmi()) {
1649        LOperand* value = UseRegisterAtStart(val);
1650        return DefineAsRegister(new (zone()) LSmiUntag(value, false));
1651      } else {
1652        LOperand* value = UseRegister(val);
1653        LOperand* temp1 = TempRegister();
1654        LOperand* temp2 = TempDoubleRegister();
1655        LInstruction* result =
1656            DefineSameAsFirst(new (zone()) LTaggedToI(value, temp1, temp2));
1657        if (!val->representation().IsSmi()) result = AssignEnvironment(result);
1658        return result;
1659      }
1660    }
1661  } else if (from.IsDouble()) {
1662    if (to.IsTagged()) {
1663      info()->MarkAsDeferredCalling();
1664      LOperand* value = UseRegister(val);
1665      LOperand* temp1 = TempRegister();
1666      LOperand* temp2 = TempRegister();
1667      LUnallocated* result_temp = TempRegister();
1668      LNumberTagD* result = new (zone()) LNumberTagD(value, temp1, temp2);
1669      return AssignPointerMap(Define(result, result_temp));
1670    } else if (to.IsSmi()) {
1671      LOperand* value = UseRegister(val);
1672      return AssignEnvironment(
1673          DefineAsRegister(new (zone()) LDoubleToSmi(value)));
1674    } else {
1675      DCHECK(to.IsInteger32());
1676      LOperand* value = UseRegister(val);
1677      LInstruction* result = DefineAsRegister(new (zone()) LDoubleToI(value));
1678      if (!instr->CanTruncateToInt32()) result = AssignEnvironment(result);
1679      return result;
1680    }
1681  } else if (from.IsInteger32()) {
1682    info()->MarkAsDeferredCalling();
1683    if (to.IsTagged()) {
1684      if (!instr->CheckFlag(HValue::kCanOverflow)) {
1685        LOperand* value = UseRegisterAtStart(val);
1686        return DefineAsRegister(new (zone()) LSmiTag(value));
1687      } else if (val->CheckFlag(HInstruction::kUint32)) {
1688        LOperand* value = UseRegisterAtStart(val);
1689        LOperand* temp1 = TempRegister();
1690        LOperand* temp2 = TempRegister();
1691        LNumberTagU* result = new (zone()) LNumberTagU(value, temp1, temp2);
1692        return AssignPointerMap(DefineAsRegister(result));
1693      } else {
1694        LOperand* value = UseRegisterAtStart(val);
1695        LOperand* temp1 = TempRegister();
1696        LOperand* temp2 = TempRegister();
1697        LNumberTagI* result = new (zone()) LNumberTagI(value, temp1, temp2);
1698        return AssignPointerMap(DefineAsRegister(result));
1699      }
1700    } else if (to.IsSmi()) {
1701      LOperand* value = UseRegister(val);
1702      LInstruction* result = DefineAsRegister(new (zone()) LSmiTag(value));
1703      if (instr->CheckFlag(HValue::kCanOverflow)) {
1704        result = AssignEnvironment(result);
1705      }
1706      return result;
1707    } else {
1708      DCHECK(to.IsDouble());
1709      if (val->CheckFlag(HInstruction::kUint32)) {
1710        return DefineAsRegister(new (zone()) LUint32ToDouble(UseRegister(val)));
1711      } else {
1712        return DefineAsRegister(new (zone()) LInteger32ToDouble(Use(val)));
1713      }
1714    }
1715  }
1716  UNREACHABLE();
1717  return NULL;
1718}
1719
1720LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
1721  LOperand* value = UseRegisterAtStart(instr->value());
1722  LInstruction* result = new (zone()) LCheckNonSmi(value);
1723  if (!instr->value()->type().IsHeapObject()) {
1724    result = AssignEnvironment(result);
1725  }
1726  return result;
1727}
1728
1729LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
1730  LOperand* value = UseRegisterAtStart(instr->value());
1731  return AssignEnvironment(new (zone()) LCheckSmi(value));
1732}
1733
1734LInstruction* LChunkBuilder::DoCheckArrayBufferNotNeutered(
1735    HCheckArrayBufferNotNeutered* instr) {
1736  LOperand* view = UseRegisterAtStart(instr->value());
1737  LCheckArrayBufferNotNeutered* result =
1738      new (zone()) LCheckArrayBufferNotNeutered(view);
1739  return AssignEnvironment(result);
1740}
1741
1742LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
1743  LOperand* value = UseRegisterAtStart(instr->value());
1744  LInstruction* result = new (zone()) LCheckInstanceType(value);
1745  return AssignEnvironment(result);
1746}
1747
1748LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
1749  LOperand* value = UseRegisterAtStart(instr->value());
1750  return AssignEnvironment(new (zone()) LCheckValue(value));
1751}
1752
1753LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
1754  if (instr->IsStabilityCheck()) return new (zone()) LCheckMaps;
1755  LOperand* value = UseRegisterAtStart(instr->value());
1756  LOperand* temp = TempRegister();
1757  LInstruction* result =
1758      AssignEnvironment(new (zone()) LCheckMaps(value, temp));
1759  if (instr->HasMigrationTarget()) {
1760    info()->MarkAsDeferredCalling();
1761    result = AssignPointerMap(result);
1762  }
1763  return result;
1764}
1765
1766LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
1767  HValue* value = instr->value();
1768  Representation input_rep = value->representation();
1769  LOperand* reg = UseRegister(value);
1770  if (input_rep.IsDouble()) {
1771    return DefineAsRegister(new (zone()) LClampDToUint8(reg));
1772  } else if (input_rep.IsInteger32()) {
1773    return DefineAsRegister(new (zone()) LClampIToUint8(reg));
1774  } else {
1775    DCHECK(input_rep.IsSmiOrTagged());
1776    LClampTToUint8* result =
1777        new (zone()) LClampTToUint8(reg, TempDoubleRegister());
1778    return AssignEnvironment(DefineAsRegister(result));
1779  }
1780}
1781
1782LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
1783  LOperand* context = info()->IsStub() ? UseFixed(instr->context(), cp) : NULL;
1784  LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count());
1785  return new (zone())
1786      LReturn(UseFixed(instr->value(), r2), context, parameter_count);
1787}
1788
1789LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
1790  Representation r = instr->representation();
1791  if (r.IsSmi()) {
1792    return DefineAsRegister(new (zone()) LConstantS);
1793  } else if (r.IsInteger32()) {
1794    return DefineAsRegister(new (zone()) LConstantI);
1795  } else if (r.IsDouble()) {
1796    return DefineAsRegister(new (zone()) LConstantD);
1797  } else if (r.IsExternal()) {
1798    return DefineAsRegister(new (zone()) LConstantE);
1799  } else if (r.IsTagged()) {
1800    return DefineAsRegister(new (zone()) LConstantT);
1801  } else {
1802    UNREACHABLE();
1803    return NULL;
1804  }
1805}
1806
1807LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
1808  LOperand* context = UseFixed(instr->context(), cp);
1809  LOperand* vector = FixedTemp(LoadWithVectorDescriptor::VectorRegister());
1810
1811  LLoadGlobalGeneric* result = new (zone()) LLoadGlobalGeneric(context, vector);
1812  return MarkAsCall(DefineFixed(result, r2), instr);
1813}
1814
1815LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
1816  LOperand* context = UseRegisterAtStart(instr->value());
1817  LInstruction* result =
1818      DefineAsRegister(new (zone()) LLoadContextSlot(context));
1819  if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
1820    result = AssignEnvironment(result);
1821  }
1822  return result;
1823}
1824
1825LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
1826  LOperand* context;
1827  LOperand* value;
1828  if (instr->NeedsWriteBarrier()) {
1829    context = UseTempRegister(instr->context());
1830    value = UseTempRegister(instr->value());
1831  } else {
1832    context = UseRegister(instr->context());
1833    value = UseRegister(instr->value());
1834  }
1835  LInstruction* result = new (zone()) LStoreContextSlot(context, value);
1836  if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
1837    result = AssignEnvironment(result);
1838  }
1839  return result;
1840}
1841
1842LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
1843  LOperand* obj = UseRegisterAtStart(instr->object());
1844  return DefineAsRegister(new (zone()) LLoadNamedField(obj));
1845}
1846
1847LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
1848  LOperand* context = UseFixed(instr->context(), cp);
1849  LOperand* object =
1850      UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
1851  LOperand* vector = FixedTemp(LoadWithVectorDescriptor::VectorRegister());
1852
1853  LInstruction* result =
1854      DefineFixed(new (zone()) LLoadNamedGeneric(context, object, vector), r2);
1855  return MarkAsCall(result, instr);
1856}
1857
1858LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
1859    HLoadFunctionPrototype* instr) {
1860  return AssignEnvironment(DefineAsRegister(
1861      new (zone()) LLoadFunctionPrototype(UseRegister(instr->function()))));
1862}
1863
1864LInstruction* LChunkBuilder::DoLoadRoot(HLoadRoot* instr) {
1865  return DefineAsRegister(new (zone()) LLoadRoot);
1866}
1867
1868LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
1869  DCHECK(instr->key()->representation().IsSmiOrInteger32());
1870  ElementsKind elements_kind = instr->elements_kind();
1871  LOperand* key = UseRegisterOrConstantAtStart(instr->key());
1872  LInstruction* result = NULL;
1873
1874  if (!instr->is_fixed_typed_array()) {
1875    LOperand* obj = NULL;
1876    if (instr->representation().IsDouble()) {
1877      obj = UseRegister(instr->elements());
1878    } else {
1879      obj = UseRegisterAtStart(instr->elements());
1880    }
1881    result = DefineAsRegister(new (zone()) LLoadKeyed(obj, key, nullptr));
1882  } else {
1883    DCHECK((instr->representation().IsInteger32() &&
1884            !IsDoubleOrFloatElementsKind(elements_kind)) ||
1885           (instr->representation().IsDouble() &&
1886            IsDoubleOrFloatElementsKind(elements_kind)));
1887    LOperand* backing_store = UseRegister(instr->elements());
1888    LOperand* backing_store_owner = UseAny(instr->backing_store_owner());
1889    result = DefineAsRegister(
1890        new (zone()) LLoadKeyed(backing_store, key, backing_store_owner));
1891  }
1892
1893  bool needs_environment;
1894  if (instr->is_fixed_typed_array()) {
1895    // see LCodeGen::DoLoadKeyedExternalArray
1896    needs_environment = elements_kind == UINT32_ELEMENTS &&
1897                        !instr->CheckFlag(HInstruction::kUint32);
1898  } else {
1899    // see LCodeGen::DoLoadKeyedFixedDoubleArray and
1900    // LCodeGen::DoLoadKeyedFixedArray
1901    needs_environment =
1902        instr->RequiresHoleCheck() ||
1903        (instr->hole_mode() == CONVERT_HOLE_TO_UNDEFINED && info()->IsStub());
1904  }
1905
1906  if (needs_environment) {
1907    result = AssignEnvironment(result);
1908  }
1909  return result;
1910}
1911
1912LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
1913  LOperand* context = UseFixed(instr->context(), cp);
1914  LOperand* object =
1915      UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
1916  LOperand* key = UseFixed(instr->key(), LoadDescriptor::NameRegister());
1917  LOperand* vector = FixedTemp(LoadWithVectorDescriptor::VectorRegister());
1918
1919  LInstruction* result = DefineFixed(
1920      new (zone()) LLoadKeyedGeneric(context, object, key, vector), r2);
1921  return MarkAsCall(result, instr);
1922}
1923
1924LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
1925  if (!instr->is_fixed_typed_array()) {
1926    DCHECK(instr->elements()->representation().IsTagged());
1927    bool needs_write_barrier = instr->NeedsWriteBarrier();
1928    LOperand* object = NULL;
1929    LOperand* key = NULL;
1930    LOperand* val = NULL;
1931
1932    if (instr->value()->representation().IsDouble()) {
1933      object = UseRegisterAtStart(instr->elements());
1934      val = UseRegister(instr->value());
1935      key = UseRegisterOrConstantAtStart(instr->key());
1936    } else {
1937      if (needs_write_barrier) {
1938        object = UseTempRegister(instr->elements());
1939        val = UseTempRegister(instr->value());
1940        key = UseTempRegister(instr->key());
1941      } else {
1942        object = UseRegisterAtStart(instr->elements());
1943        val = UseRegisterAtStart(instr->value());
1944        key = UseRegisterOrConstantAtStart(instr->key());
1945      }
1946    }
1947
1948    return new (zone()) LStoreKeyed(object, key, val, nullptr);
1949  }
1950
1951  DCHECK((instr->value()->representation().IsInteger32() &&
1952          !IsDoubleOrFloatElementsKind(instr->elements_kind())) ||
1953         (instr->value()->representation().IsDouble() &&
1954          IsDoubleOrFloatElementsKind(instr->elements_kind())));
1955  DCHECK(instr->elements()->representation().IsExternal());
1956  LOperand* val = UseRegister(instr->value());
1957  LOperand* key = UseRegisterOrConstantAtStart(instr->key());
1958  LOperand* backing_store = UseRegister(instr->elements());
1959  LOperand* backing_store_owner = UseAny(instr->backing_store_owner());
1960  return new (zone()) LStoreKeyed(backing_store, key, val, backing_store_owner);
1961}
1962
1963LInstruction* LChunkBuilder::DoTransitionElementsKind(
1964    HTransitionElementsKind* instr) {
1965  if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
1966    LOperand* object = UseRegister(instr->object());
1967    LOperand* new_map_reg = TempRegister();
1968    LTransitionElementsKind* result =
1969        new (zone()) LTransitionElementsKind(object, NULL, new_map_reg);
1970    return result;
1971  } else {
1972    LOperand* object = UseFixed(instr->object(), r2);
1973    LOperand* context = UseFixed(instr->context(), cp);
1974    LTransitionElementsKind* result =
1975        new (zone()) LTransitionElementsKind(object, context, NULL);
1976    return MarkAsCall(result, instr);
1977  }
1978}
1979
1980LInstruction* LChunkBuilder::DoTrapAllocationMemento(
1981    HTrapAllocationMemento* instr) {
1982  LOperand* object = UseRegister(instr->object());
1983  LOperand* temp1 = TempRegister();
1984  LOperand* temp2 = TempRegister();
1985  LTrapAllocationMemento* result =
1986      new (zone()) LTrapAllocationMemento(object, temp1, temp2);
1987  return AssignEnvironment(result);
1988}
1989
1990LInstruction* LChunkBuilder::DoMaybeGrowElements(HMaybeGrowElements* instr) {
1991  info()->MarkAsDeferredCalling();
1992  LOperand* context = UseFixed(instr->context(), cp);
1993  LOperand* object = Use(instr->object());
1994  LOperand* elements = Use(instr->elements());
1995  LOperand* key = UseRegisterOrConstant(instr->key());
1996  LOperand* current_capacity = UseRegisterOrConstant(instr->current_capacity());
1997
1998  LMaybeGrowElements* result = new (zone())
1999      LMaybeGrowElements(context, object, elements, key, current_capacity);
2000  DefineFixed(result, r2);
2001  return AssignPointerMap(AssignEnvironment(result));
2002}
2003
2004LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
2005  bool is_in_object = instr->access().IsInobject();
2006  bool needs_write_barrier = instr->NeedsWriteBarrier();
2007  bool needs_write_barrier_for_map =
2008      instr->has_transition() && instr->NeedsWriteBarrierForMap();
2009
2010  LOperand* obj;
2011  if (needs_write_barrier) {
2012    obj = is_in_object ? UseRegister(instr->object())
2013                       : UseTempRegister(instr->object());
2014  } else {
2015    obj = needs_write_barrier_for_map ? UseRegister(instr->object())
2016                                      : UseRegisterAtStart(instr->object());
2017  }
2018
2019  LOperand* val;
2020  if (needs_write_barrier) {
2021    val = UseTempRegister(instr->value());
2022  } else if (instr->field_representation().IsDouble()) {
2023    val = UseRegisterAtStart(instr->value());
2024  } else {
2025    val = UseRegister(instr->value());
2026  }
2027
2028  // We need a temporary register for write barrier of the map field.
2029  LOperand* temp = needs_write_barrier_for_map ? TempRegister() : NULL;
2030
2031  return new (zone()) LStoreNamedField(obj, val, temp);
2032}
2033
2034LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
2035  LOperand* context = UseFixed(instr->context(), cp);
2036  LOperand* left = UseFixed(instr->left(), r3);
2037  LOperand* right = UseFixed(instr->right(), r2);
2038  return MarkAsCall(
2039      DefineFixed(new (zone()) LStringAdd(context, left, right), r2), instr);
2040}
2041
2042LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
2043  LOperand* string = UseTempRegister(instr->string());
2044  LOperand* index = UseTempRegister(instr->index());
2045  LOperand* context = UseAny(instr->context());
2046  LStringCharCodeAt* result =
2047      new (zone()) LStringCharCodeAt(context, string, index);
2048  return AssignPointerMap(DefineAsRegister(result));
2049}
2050
2051LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
2052  LOperand* char_code = UseRegister(instr->value());
2053  LOperand* context = UseAny(instr->context());
2054  LStringCharFromCode* result =
2055      new (zone()) LStringCharFromCode(context, char_code);
2056  return AssignPointerMap(DefineAsRegister(result));
2057}
2058
2059LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
2060  LOperand* size = UseRegisterOrConstant(instr->size());
2061  LOperand* temp1 = TempRegister();
2062  LOperand* temp2 = TempRegister();
2063  if (instr->IsAllocationFolded()) {
2064    LFastAllocate* result = new (zone()) LFastAllocate(size, temp1, temp2);
2065    return DefineAsRegister(result);
2066  } else {
2067    info()->MarkAsDeferredCalling();
2068    LOperand* context = UseAny(instr->context());
2069    LAllocate* result = new (zone()) LAllocate(context, size, temp1, temp2);
2070    return AssignPointerMap(DefineAsRegister(result));
2071  }
2072}
2073
2074LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
2075  DCHECK(argument_count_ == 0);
2076  allocator_->MarkAsOsrEntry();
2077  current_block_->last_environment()->set_ast_id(instr->ast_id());
2078  return AssignEnvironment(new (zone()) LOsrEntry);
2079}
2080
2081LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2082  LParameter* result = new (zone()) LParameter;
2083  if (instr->kind() == HParameter::STACK_PARAMETER) {
2084    int spill_index = chunk()->GetParameterStackSlot(instr->index());
2085    return DefineAsSpilled(result, spill_index);
2086  } else {
2087    DCHECK(info()->IsStub());
2088    CallInterfaceDescriptor descriptor = graph()->descriptor();
2089    int index = static_cast<int>(instr->index());
2090    Register reg = descriptor.GetRegisterParameter(index);
2091    return DefineFixed(result, reg);
2092  }
2093}
2094
2095LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
2096  // Use an index that corresponds to the location in the unoptimized frame,
2097  // which the optimized frame will subsume.
2098  int env_index = instr->index();
2099  int spill_index = 0;
2100  if (instr->environment()->is_parameter_index(env_index)) {
2101    spill_index = chunk()->GetParameterStackSlot(env_index);
2102  } else {
2103    spill_index = env_index - instr->environment()->first_local_index();
2104    if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
2105      Retry(kTooManySpillSlotsNeededForOSR);
2106      spill_index = 0;
2107    }
2108    spill_index += StandardFrameConstants::kFixedSlotCount;
2109  }
2110  return DefineAsSpilled(new (zone()) LUnknownOSRValue, spill_index);
2111}
2112
2113LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
2114  // There are no real uses of the arguments object.
2115  // arguments.length and element access are supported directly on
2116  // stack arguments, and any real arguments object use causes a bailout.
2117  // So this value is never used.
2118  return NULL;
2119}
2120
2121LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
2122  instr->ReplayEnvironment(current_block_->last_environment());
2123
2124  // There are no real uses of a captured object.
2125  return NULL;
2126}
2127
2128LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
2129  info()->MarkAsRequiresFrame();
2130  LOperand* args = UseRegister(instr->arguments());
2131  LOperand* length = UseRegisterOrConstantAtStart(instr->length());
2132  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
2133  return DefineAsRegister(new (zone()) LAccessArgumentsAt(args, length, index));
2134}
2135
2136LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2137  LOperand* context = UseFixed(instr->context(), cp);
2138  LOperand* value = UseFixed(instr->value(), r5);
2139  LTypeof* result = new (zone()) LTypeof(context, value);
2140  return MarkAsCall(DefineFixed(result, r2), instr);
2141}
2142
2143LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
2144  return new (zone()) LTypeofIsAndBranch(UseRegister(instr->value()));
2145}
2146
2147LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2148  instr->ReplayEnvironment(current_block_->last_environment());
2149  return NULL;
2150}
2151
2152LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2153  if (instr->is_function_entry()) {
2154    LOperand* context = UseFixed(instr->context(), cp);
2155    return MarkAsCall(new (zone()) LStackCheck(context), instr);
2156  } else {
2157    DCHECK(instr->is_backwards_branch());
2158    LOperand* context = UseAny(instr->context());
2159    return AssignEnvironment(
2160        AssignPointerMap(new (zone()) LStackCheck(context)));
2161  }
2162}
2163
2164LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
2165  HEnvironment* outer = current_block_->last_environment();
2166  outer->set_ast_id(instr->ReturnId());
2167  HConstant* undefined = graph()->GetConstantUndefined();
2168  HEnvironment* inner = outer->CopyForInlining(
2169      instr->closure(), instr->arguments_count(), instr->function(), undefined,
2170      instr->inlining_kind(), instr->syntactic_tail_call_mode());
2171  // Only replay binding of arguments object if it wasn't removed from graph.
2172  if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
2173    inner->Bind(instr->arguments_var(), instr->arguments_object());
2174  }
2175  inner->BindContext(instr->closure_context());
2176  inner->set_entry(instr);
2177  current_block_->UpdateEnvironment(inner);
2178  chunk_->AddInlinedFunction(instr->shared());
2179  return NULL;
2180}
2181
2182LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2183  LInstruction* pop = NULL;
2184
2185  HEnvironment* env = current_block_->last_environment();
2186
2187  if (env->entry()->arguments_pushed()) {
2188    int argument_count = env->arguments_environment()->parameter_count();
2189    pop = new (zone()) LDrop(argument_count);
2190    DCHECK(instr->argument_delta() == -argument_count);
2191  }
2192
2193  HEnvironment* outer =
2194      current_block_->last_environment()->DiscardInlined(false);
2195  current_block_->UpdateEnvironment(outer);
2196
2197  return pop;
2198}
2199
2200LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
2201  LOperand* context = UseFixed(instr->context(), cp);
2202  LOperand* object = UseFixed(instr->enumerable(), r2);
2203  LForInPrepareMap* result = new (zone()) LForInPrepareMap(context, object);
2204  return MarkAsCall(DefineFixed(result, r2), instr, CAN_DEOPTIMIZE_EAGERLY);
2205}
2206
2207LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
2208  LOperand* map = UseRegister(instr->map());
2209  return AssignEnvironment(
2210      DefineAsRegister(new (zone()) LForInCacheArray(map)));
2211}
2212
2213LInstruction* LChunkBuilder::DoCheckMapValue(HCheckMapValue* instr) {
2214  LOperand* value = UseRegisterAtStart(instr->value());
2215  LOperand* map = UseRegisterAtStart(instr->map());
2216  return AssignEnvironment(new (zone()) LCheckMapValue(value, map));
2217}
2218
2219LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
2220  LOperand* object = UseRegister(instr->object());
2221  LOperand* index = UseTempRegister(instr->index());
2222  LLoadFieldByIndex* load = new (zone()) LLoadFieldByIndex(object, index);
2223  LInstruction* result = DefineSameAsFirst(load);
2224  return AssignPointerMap(result);
2225}
2226
2227}  // namespace internal
2228}  // namespace v8
2229