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