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