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