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