V8 Project
lithium-codegen-x64.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 
7 #if V8_TARGET_ARCH_X64
8 
9 #include "src/base/bits.h"
10 #include "src/code-factory.h"
11 #include "src/code-stubs.h"
12 #include "src/hydrogen-osr.h"
13 #include "src/ic/ic.h"
14 #include "src/ic/stub-cache.h"
16 
17 namespace v8 {
18 namespace internal {
19 
20 
21 // When invoking builtins, we need to record the safepoint in the middle of
22 // the invoke instruction sequence generated by the macro assembler.
23 class SafepointGenerator FINAL : public CallWrapper {
24  public:
25  SafepointGenerator(LCodeGen* codegen,
26  LPointerMap* pointers,
27  Safepoint::DeoptMode mode)
28  : codegen_(codegen),
29  pointers_(pointers),
30  deopt_mode_(mode) { }
31  virtual ~SafepointGenerator() {}
32 
33  virtual void BeforeCall(int call_size) const OVERRIDE {}
34 
35  virtual void AfterCall() const OVERRIDE {
36  codegen_->RecordSafepoint(pointers_, deopt_mode_);
37  }
38 
39  private:
40  LCodeGen* codegen_;
41  LPointerMap* pointers_;
42  Safepoint::DeoptMode deopt_mode_;
43 };
44 
45 
46 #define __ masm()->
47 
49  LPhase phase("Z_Code generation", chunk());
50  DCHECK(is_unused());
51  status_ = GENERATING;
52 
53  // Open a frame scope to indicate that there is a frame on the stack. The
54  // MANUAL indicates that the scope shouldn't actually generate code to set up
55  // the frame (that is done in GeneratePrologue).
56  FrameScope frame_scope(masm_, StackFrame::MANUAL);
57 
58  return GeneratePrologue() &&
59  GenerateBody() &&
63 }
64 
65 
66 void LCodeGen::FinishCode(Handle<Code> code) {
67  DCHECK(is_done());
68  code->set_stack_slots(GetStackSlotCount());
69  code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
70  if (code->is_optimized_code()) RegisterWeakObjectsInOptimizedCode(code);
72 }
73 
74 
75 #ifdef _MSC_VER
76 void LCodeGen::MakeSureStackPagesMapped(int offset) {
77  const int kPageSize = 4 * KB;
78  for (offset -= kPageSize; offset > 0; offset -= kPageSize) {
79  __ movp(Operand(rsp, offset), rax);
80  }
81 }
82 #endif
83 
84 
86  DCHECK(info()->saves_caller_doubles());
88  Comment(";;; Save clobbered callee double registers");
89  int count = 0;
90  BitVector* doubles = chunk()->allocated_double_registers();
91  BitVector::Iterator save_iterator(doubles);
92  while (!save_iterator.Done()) {
93  __ movsd(MemOperand(rsp, count * kDoubleSize),
94  XMMRegister::FromAllocationIndex(save_iterator.Current()));
95  save_iterator.Advance();
96  count++;
97  }
98 }
99 
100 
102  DCHECK(info()->saves_caller_doubles());
104  Comment(";;; Restore clobbered callee double registers");
105  BitVector* doubles = chunk()->allocated_double_registers();
106  BitVector::Iterator save_iterator(doubles);
107  int count = 0;
108  while (!save_iterator.Done()) {
109  __ movsd(XMMRegister::FromAllocationIndex(save_iterator.Current()),
110  MemOperand(rsp, count * kDoubleSize));
111  save_iterator.Advance();
112  count++;
113  }
114 }
115 
116 
118  DCHECK(is_generating());
119 
120  if (info()->IsOptimizing()) {
122 
123 #ifdef DEBUG
124  if (strlen(FLAG_stop_at) > 0 &&
125  info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
126  __ int3();
127  }
128 #endif
129 
130  // Sloppy mode functions need to replace the receiver with the global proxy
131  // when called as functions (without an explicit receiver object).
132  if (info_->this_has_uses() &&
133  info_->strict_mode() == SLOPPY &&
134  !info_->is_native()) {
135  Label ok;
136  StackArgumentsAccessor args(rsp, scope()->num_parameters());
137  __ movp(rcx, args.GetReceiverOperand());
138 
139  __ CompareRoot(rcx, Heap::kUndefinedValueRootIndex);
140  __ j(not_equal, &ok, Label::kNear);
141 
142  __ movp(rcx, GlobalObjectOperand());
144 
145  __ movp(args.GetReceiverOperand(), rcx);
146 
147  __ bind(&ok);
148  }
149  }
150 
151  info()->set_prologue_offset(masm_->pc_offset());
152  if (NeedsEagerFrame()) {
154  frame_is_built_ = true;
155  if (info()->IsStub()) {
156  __ StubPrologue();
157  } else {
158  __ Prologue(info()->IsCodePreAgingActive());
159  }
160  info()->AddNoFrameRange(0, masm_->pc_offset());
161  }
162 
163  // Reserve space for the stack slots needed by the code.
164  int slots = GetStackSlotCount();
165  if (slots > 0) {
166  if (FLAG_debug_code) {
167  __ subp(rsp, Immediate(slots * kPointerSize));
168 #ifdef _MSC_VER
169  MakeSureStackPagesMapped(slots * kPointerSize);
170 #endif
171  __ Push(rax);
172  __ Set(rax, slots);
174  Label loop;
175  __ bind(&loop);
178  __ decl(rax);
179  __ j(not_zero, &loop);
180  __ Pop(rax);
181  } else {
182  __ subp(rsp, Immediate(slots * kPointerSize));
183 #ifdef _MSC_VER
184  MakeSureStackPagesMapped(slots * kPointerSize);
185 #endif
186  }
187 
188  if (info()->saves_caller_doubles()) {
190  }
191  }
192 
193  // Possibly allocate a local context.
194  int heap_slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
195  if (heap_slots > 0) {
196  Comment(";;; Allocate local context");
197  bool need_write_barrier = true;
198  // Argument to NewContext is the function, which is still in rdi.
199  if (heap_slots <= FastNewContextStub::kMaximumSlots) {
200  FastNewContextStub stub(isolate(), heap_slots);
201  __ CallStub(&stub);
202  // Result of FastNewContextStub is always in new space.
203  need_write_barrier = false;
204  } else {
205  __ Push(rdi);
206  __ CallRuntime(Runtime::kNewFunctionContext, 1);
207  }
208  RecordSafepoint(Safepoint::kNoLazyDeopt);
209  // Context is returned in rax. It replaces the context passed to us.
210  // It's saved in the stack and kept live in rsi.
211  __ movp(rsi, rax);
213 
214  // Copy any necessary parameters into the context.
215  int num_parameters = scope()->num_parameters();
216  for (int i = 0; i < num_parameters; i++) {
217  Variable* var = scope()->parameter(i);
218  if (var->IsContextSlot()) {
219  int parameter_offset = StandardFrameConstants::kCallerSPOffset +
220  (num_parameters - 1 - i) * kPointerSize;
221  // Load parameter from stack.
222  __ movp(rax, Operand(rbp, parameter_offset));
223  // Store it in the context.
224  int context_offset = Context::SlotOffset(var->index());
225  __ movp(Operand(rsi, context_offset), rax);
226  // Update the write barrier. This clobbers rax and rbx.
227  if (need_write_barrier) {
228  __ RecordWriteContextSlot(rsi, context_offset, rax, rbx, kSaveFPRegs);
229  } else if (FLAG_debug_code) {
230  Label done;
231  __ JumpIfInNewSpace(rsi, rax, &done, Label::kNear);
232  __ Abort(kExpectedNewSpaceObject);
233  __ bind(&done);
234  }
235  }
236  }
237  Comment(";;; End allocate local context");
238  }
239 
240  // Trace the call.
241  if (FLAG_trace && info()->IsOptimizing()) {
242  __ CallRuntime(Runtime::kTraceEnter, 0);
243  }
244  return !is_aborted();
245 }
246 
247 
249  // Generate the OSR entry prologue at the first unknown OSR value, or if there
250  // are none, at the OSR entrypoint instruction.
251  if (osr_pc_offset_ >= 0) return;
252 
253  osr_pc_offset_ = masm()->pc_offset();
254 
255  // Adjust the frame size, subsuming the unoptimized frame into the
256  // optimized frame.
257  int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots();
258  DCHECK(slots >= 0);
259  __ subp(rsp, Immediate(slots * kPointerSize));
260 }
261 
262 
263 void LCodeGen::GenerateBodyInstructionPre(LInstruction* instr) {
264  if (instr->IsCall()) {
266  }
267  if (!instr->IsLazyBailout() && !instr->IsGap()) {
268  safepoints_.BumpLastLazySafepointIndex();
269  }
270 }
271 
272 
273 void LCodeGen::GenerateBodyInstructionPost(LInstruction* instr) {
274  if (FLAG_debug_code && FLAG_enable_slow_asserts && instr->HasResult() &&
275  instr->hydrogen_value()->representation().IsInteger32() &&
276  instr->result()->IsRegister()) {
277  __ AssertZeroExtended(ToRegister(instr->result()));
278  }
279 
280  if (instr->HasResult() && instr->MustSignExtendResult(chunk())) {
281  // We sign extend the dehoisted key at the definition point when the pointer
282  // size is 64-bit. For x32 port, we sign extend the dehoisted key at the use
283  // points and MustSignExtendResult is always false. We can't use
284  // STATIC_ASSERT here as the pointer size is 32-bit for x32.
286  if (instr->result()->IsRegister()) {
287  Register result_reg = ToRegister(instr->result());
288  __ movsxlq(result_reg, result_reg);
289  } else {
290  // Sign extend the 32bit result in the stack slots.
291  DCHECK(instr->result()->IsStackSlot());
292  Operand src = ToOperand(instr->result());
293  __ movsxlq(kScratchRegister, src);
294  __ movq(src, kScratchRegister);
295  }
296  }
297 }
298 
299 
301  Label needs_frame;
302  if (jump_table_.length() > 0) {
303  Comment(";;; -------------------- Jump table --------------------");
304  }
305  for (int i = 0; i < jump_table_.length(); i++) {
306  Deoptimizer::JumpTableEntry* table_entry = &jump_table_[i];
307  __ bind(&table_entry->label);
308  Address entry = table_entry->address;
309  DeoptComment(table_entry->reason);
310  if (table_entry->needs_frame) {
311  DCHECK(!info()->saves_caller_doubles());
312  __ Move(kScratchRegister, ExternalReference::ForDeoptEntry(entry));
313  if (needs_frame.is_bound()) {
314  __ jmp(&needs_frame);
315  } else {
316  __ bind(&needs_frame);
318  __ pushq(rbp);
319  __ movp(rbp, rsp);
320  __ Push(rsi);
321  // This variant of deopt can only be used with stubs. Since we don't
322  // have a function pointer to install in the stack frame that we're
323  // building, install a special marker there instead.
324  DCHECK(info()->IsStub());
326  __ Push(rsi);
327  __ movp(rsi, MemOperand(rsp, kPointerSize));
328  __ call(kScratchRegister);
329  }
330  } else {
331  if (info()->saves_caller_doubles()) {
332  DCHECK(info()->IsStub());
334  }
335  __ call(entry, RelocInfo::RUNTIME_ENTRY);
336  }
337  }
338  return !is_aborted();
339 }
340 
341 
343  DCHECK(is_generating());
344  if (deferred_.length() > 0) {
345  for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
346  LDeferredCode* code = deferred_[i];
347 
348  HValue* value =
349  instructions_->at(code->instruction_index())->hydrogen_value();
351  chunk()->graph()->SourcePositionToScriptPosition(value->position()));
352 
353  Comment(";;; <@%d,#%d> "
354  "-------------------- Deferred %s --------------------",
355  code->instruction_index(),
356  code->instr()->hydrogen_value()->id(),
357  code->instr()->Mnemonic());
358  __ bind(code->entry());
359  if (NeedsDeferredFrame()) {
360  Comment(";;; Build frame");
362  DCHECK(info()->IsStub());
363  frame_is_built_ = true;
364  // Build the frame in such a way that esi isn't trashed.
365  __ pushq(rbp); // Caller's frame pointer.
368  __ leap(rbp, Operand(rsp, 2 * kPointerSize));
369  Comment(";;; Deferred code");
370  }
371  code->Generate();
372  if (NeedsDeferredFrame()) {
373  __ bind(code->done());
374  Comment(";;; Destroy frame");
376  frame_is_built_ = false;
377  __ movp(rsp, rbp);
378  __ popq(rbp);
379  }
380  __ jmp(code->exit());
381  }
382  }
383 
384  // Deferred code is the last part of the instruction sequence. Mark
385  // the generated code as done unless we bailed out.
386  if (!is_aborted()) status_ = DONE;
387  return !is_aborted();
388 }
389 
390 
392  DCHECK(is_done());
393  safepoints_.Emit(masm(), GetStackSlotCount());
394  return !is_aborted();
395 }
396 
397 
398 Register LCodeGen::ToRegister(int index) const {
399  return Register::FromAllocationIndex(index);
400 }
401 
402 
403 XMMRegister LCodeGen::ToDoubleRegister(int index) const {
404  return XMMRegister::FromAllocationIndex(index);
405 }
406 
407 
408 Register LCodeGen::ToRegister(LOperand* op) const {
409  DCHECK(op->IsRegister());
410  return ToRegister(op->index());
411 }
412 
413 
414 XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
415  DCHECK(op->IsDoubleRegister());
416  return ToDoubleRegister(op->index());
417 }
418 
419 
420 bool LCodeGen::IsInteger32Constant(LConstantOperand* op) const {
421  return chunk_->LookupLiteralRepresentation(op).IsSmiOrInteger32();
422 }
423 
424 
425 bool LCodeGen::IsDehoistedKeyConstant(LConstantOperand* op) const {
426  return op->IsConstantOperand() &&
427  chunk_->IsDehoistedKey(chunk_->LookupConstant(op));
428 }
429 
430 
431 bool LCodeGen::IsSmiConstant(LConstantOperand* op) const {
432  return chunk_->LookupLiteralRepresentation(op).IsSmi();
433 }
434 
435 
436 int32_t LCodeGen::ToInteger32(LConstantOperand* op) const {
438 }
439 
440 
441 int32_t LCodeGen::ToRepresentation(LConstantOperand* op,
442  const Representation& r) const {
443  HConstant* constant = chunk_->LookupConstant(op);
444  int32_t value = constant->Integer32Value();
445  if (r.IsInteger32()) return value;
446  DCHECK(SmiValuesAre31Bits() && r.IsSmiOrTagged());
447  return static_cast<int32_t>(reinterpret_cast<intptr_t>(Smi::FromInt(value)));
448 }
449 
450 
451 Smi* LCodeGen::ToSmi(LConstantOperand* op) const {
452  HConstant* constant = chunk_->LookupConstant(op);
453  return Smi::FromInt(constant->Integer32Value());
454 }
455 
456 
457 double LCodeGen::ToDouble(LConstantOperand* op) const {
458  HConstant* constant = chunk_->LookupConstant(op);
459  DCHECK(constant->HasDoubleValue());
460  return constant->DoubleValue();
461 }
462 
463 
464 ExternalReference LCodeGen::ToExternalReference(LConstantOperand* op) const {
465  HConstant* constant = chunk_->LookupConstant(op);
466  DCHECK(constant->HasExternalReferenceValue());
467  return constant->ExternalReferenceValue();
468 }
469 
470 
471 Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
472  HConstant* constant = chunk_->LookupConstant(op);
473  DCHECK(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
474  return constant->handle(isolate());
475 }
476 
477 
478 static int ArgumentsOffsetWithoutFrame(int index) {
479  DCHECK(index < 0);
480  return -(index + 1) * kPointerSize + kPCOnStackSize;
481 }
482 
483 
484 Operand LCodeGen::ToOperand(LOperand* op) const {
485  // Does not handle registers. In X64 assembler, plain registers are not
486  // representable as an Operand.
487  DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
488  if (NeedsEagerFrame()) {
489  return Operand(rbp, StackSlotOffset(op->index()));
490  } else {
491  // Retrieve parameter without eager stack-frame relative to the
492  // stack-pointer.
493  return Operand(rsp, ArgumentsOffsetWithoutFrame(op->index()));
494  }
495 }
496 
497 
498 void LCodeGen::WriteTranslation(LEnvironment* environment,
499  Translation* translation) {
500  if (environment == NULL) return;
501 
502  // The translation includes one command per value in the environment.
503  int translation_size = environment->translation_size();
504  // The output frame height does not include the parameters.
505  int height = translation_size - environment->parameter_count();
506 
507  WriteTranslation(environment->outer(), translation);
508  bool has_closure_id = !info()->closure().is_null() &&
509  !info()->closure().is_identical_to(environment->closure());
510  int closure_id = has_closure_id
511  ? DefineDeoptimizationLiteral(environment->closure())
512  : Translation::kSelfLiteralId;
513 
514  switch (environment->frame_type()) {
515  case JS_FUNCTION:
516  translation->BeginJSFrame(environment->ast_id(), closure_id, height);
517  break;
518  case JS_CONSTRUCT:
519  translation->BeginConstructStubFrame(closure_id, translation_size);
520  break;
521  case JS_GETTER:
522  DCHECK(translation_size == 1);
523  DCHECK(height == 0);
524  translation->BeginGetterStubFrame(closure_id);
525  break;
526  case JS_SETTER:
527  DCHECK(translation_size == 2);
528  DCHECK(height == 0);
529  translation->BeginSetterStubFrame(closure_id);
530  break;
531  case ARGUMENTS_ADAPTOR:
532  translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
533  break;
534  case STUB:
535  translation->BeginCompiledStubFrame();
536  break;
537  }
538 
539  int object_index = 0;
540  int dematerialized_index = 0;
541  for (int i = 0; i < translation_size; ++i) {
542  LOperand* value = environment->values()->at(i);
543  AddToTranslation(environment,
544  translation,
545  value,
546  environment->HasTaggedValueAt(i),
547  environment->HasUint32ValueAt(i),
548  &object_index,
549  &dematerialized_index);
550  }
551 }
552 
553 
554 void LCodeGen::AddToTranslation(LEnvironment* environment,
555  Translation* translation,
556  LOperand* op,
557  bool is_tagged,
558  bool is_uint32,
559  int* object_index_pointer,
560  int* dematerialized_index_pointer) {
561  if (op == LEnvironment::materialization_marker()) {
562  int object_index = (*object_index_pointer)++;
563  if (environment->ObjectIsDuplicateAt(object_index)) {
564  int dupe_of = environment->ObjectDuplicateOfAt(object_index);
565  translation->DuplicateObject(dupe_of);
566  return;
567  }
568  int object_length = environment->ObjectLengthAt(object_index);
569  if (environment->ObjectIsArgumentsAt(object_index)) {
570  translation->BeginArgumentsObject(object_length);
571  } else {
572  translation->BeginCapturedObject(object_length);
573  }
574  int dematerialized_index = *dematerialized_index_pointer;
575  int env_offset = environment->translation_size() + dematerialized_index;
576  *dematerialized_index_pointer += object_length;
577  for (int i = 0; i < object_length; ++i) {
578  LOperand* value = environment->values()->at(env_offset + i);
579  AddToTranslation(environment,
580  translation,
581  value,
582  environment->HasTaggedValueAt(env_offset + i),
583  environment->HasUint32ValueAt(env_offset + i),
584  object_index_pointer,
585  dematerialized_index_pointer);
586  }
587  return;
588  }
589 
590  if (op->IsStackSlot()) {
591  if (is_tagged) {
592  translation->StoreStackSlot(op->index());
593  } else if (is_uint32) {
594  translation->StoreUint32StackSlot(op->index());
595  } else {
596  translation->StoreInt32StackSlot(op->index());
597  }
598  } else if (op->IsDoubleStackSlot()) {
599  translation->StoreDoubleStackSlot(op->index());
600  } else if (op->IsRegister()) {
601  Register reg = ToRegister(op);
602  if (is_tagged) {
603  translation->StoreRegister(reg);
604  } else if (is_uint32) {
605  translation->StoreUint32Register(reg);
606  } else {
607  translation->StoreInt32Register(reg);
608  }
609  } else if (op->IsDoubleRegister()) {
610  XMMRegister reg = ToDoubleRegister(op);
611  translation->StoreDoubleRegister(reg);
612  } else if (op->IsConstantOperand()) {
613  HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
614  int src_index = DefineDeoptimizationLiteral(constant->handle(isolate()));
615  translation->StoreLiteral(src_index);
616  } else {
617  UNREACHABLE();
618  }
619 }
620 
621 
622 void LCodeGen::CallCodeGeneric(Handle<Code> code,
624  LInstruction* instr,
625  SafepointMode safepoint_mode,
626  int argc) {
627  DCHECK(instr != NULL);
628  __ call(code, mode);
629  RecordSafepointWithLazyDeopt(instr, safepoint_mode, argc);
630 
631  // Signal that we don't inline smi code before these stubs in the
632  // optimizing code generator.
633  if (code->kind() == Code::BINARY_OP_IC ||
634  code->kind() == Code::COMPARE_IC) {
635  __ nop();
636  }
637 }
638 
639 
640 void LCodeGen::CallCode(Handle<Code> code,
642  LInstruction* instr) {
643  CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT, 0);
644 }
645 
646 
647 void LCodeGen::CallRuntime(const Runtime::Function* function,
648  int num_arguments,
649  LInstruction* instr,
650  SaveFPRegsMode save_doubles) {
651  DCHECK(instr != NULL);
652  DCHECK(instr->HasPointerMap());
653 
654  __ CallRuntime(function, num_arguments, save_doubles);
655 
657 }
658 
659 
660 void LCodeGen::LoadContextFromDeferred(LOperand* context) {
661  if (context->IsRegister()) {
662  if (!ToRegister(context).is(rsi)) {
663  __ movp(rsi, ToRegister(context));
664  }
665  } else if (context->IsStackSlot()) {
666  __ movp(rsi, ToOperand(context));
667  } else if (context->IsConstantOperand()) {
668  HConstant* constant =
669  chunk_->LookupConstant(LConstantOperand::cast(context));
670  __ Move(rsi, Handle<Object>::cast(constant->handle(isolate())));
671  } else {
672  UNREACHABLE();
673  }
674 }
675 
676 
677 
679  int argc,
680  LInstruction* instr,
681  LOperand* context) {
682  LoadContextFromDeferred(context);
683 
684  __ CallRuntimeSaveDoubles(id);
686  instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
687 }
688 
689 
690 void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
691  Safepoint::DeoptMode mode) {
692  environment->set_has_been_used();
693  if (!environment->HasBeenRegistered()) {
694  // Physical stack frame layout:
695  // -x ............. -4 0 ..................................... y
696  // [incoming arguments] [spill slots] [pushed outgoing arguments]
697 
698  // Layout of the environment:
699  // 0 ..................................................... size-1
700  // [parameters] [locals] [expression stack including arguments]
701 
702  // Layout of the translation:
703  // 0 ........................................................ size - 1 + 4
704  // [expression stack including arguments] [locals] [4 words] [parameters]
705  // |>------------ translation_size ------------<|
706 
707  int frame_count = 0;
708  int jsframe_count = 0;
709  for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
710  ++frame_count;
711  if (e->frame_type() == JS_FUNCTION) {
712  ++jsframe_count;
713  }
714  }
715  Translation translation(&translations_, frame_count, jsframe_count, zone());
716  WriteTranslation(environment, &translation);
717  int deoptimization_index = deoptimizations_.length();
718  int pc_offset = masm()->pc_offset();
719  environment->Register(deoptimization_index,
720  translation.index(),
721  (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
722  deoptimizations_.Add(environment, environment->zone());
723  }
724 }
725 
726 
727 void LCodeGen::DeoptimizeIf(Condition cc, LInstruction* instr,
728  const char* detail,
729  Deoptimizer::BailoutType bailout_type) {
730  LEnvironment* environment = instr->environment();
731  RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
732  DCHECK(environment->HasBeenRegistered());
733  int id = environment->deoptimization_index();
734  DCHECK(info()->IsOptimizing() || info()->IsStub());
735  Address entry =
736  Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type);
737  if (entry == NULL) {
738  Abort(kBailoutWasNotPrepared);
739  return;
740  }
741 
742  if (DeoptEveryNTimes()) {
743  ExternalReference count = ExternalReference::stress_deopt_count(isolate());
744  Label no_deopt;
745  __ pushfq();
746  __ pushq(rax);
747  Operand count_operand = masm()->ExternalOperand(count, kScratchRegister);
748  __ movl(rax, count_operand);
749  __ subl(rax, Immediate(1));
750  __ j(not_zero, &no_deopt, Label::kNear);
751  if (FLAG_trap_on_deopt) __ int3();
752  __ movl(rax, Immediate(FLAG_deopt_every_n_times));
753  __ movl(count_operand, rax);
754  __ popq(rax);
755  __ popfq();
757  __ call(entry, RelocInfo::RUNTIME_ENTRY);
758  __ bind(&no_deopt);
759  __ movl(count_operand, rax);
760  __ popq(rax);
761  __ popfq();
762  }
763 
764  if (info()->ShouldTrapOnDeopt()) {
765  Label done;
766  if (cc != no_condition) {
767  __ j(NegateCondition(cc), &done, Label::kNear);
768  }
769  __ int3();
770  __ bind(&done);
771  }
772 
773  Deoptimizer::Reason reason(instr->hydrogen_value()->position().raw(),
774  instr->Mnemonic(), detail);
775  DCHECK(info()->IsStub() || frame_is_built_);
776  // Go through jump table if we need to handle condition, build frame, or
777  // restore caller doubles.
778  if (cc == no_condition && frame_is_built_ &&
779  !info()->saves_caller_doubles()) {
780  DeoptComment(reason);
781  __ call(entry, RelocInfo::RUNTIME_ENTRY);
782  } else {
783  Deoptimizer::JumpTableEntry table_entry(entry, reason, bailout_type,
784  !frame_is_built_);
785  // We often have several deopts to the same entry, reuse the last
786  // jump entry if this is the case.
787  if (jump_table_.is_empty() ||
788  !table_entry.IsEquivalentTo(jump_table_.last())) {
789  jump_table_.Add(table_entry, zone());
790  }
791  if (cc == no_condition) {
792  __ jmp(&jump_table_.last().label);
793  } else {
794  __ j(cc, &jump_table_.last().label);
795  }
796  }
797 }
798 
799 
800 void LCodeGen::DeoptimizeIf(Condition cc, LInstruction* instr,
801  const char* detail) {
802  Deoptimizer::BailoutType bailout_type = info()->IsStub()
805  DeoptimizeIf(cc, instr, detail, bailout_type);
806 }
807 
808 
809 void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
810  int length = deoptimizations_.length();
811  if (length == 0) return;
812  Handle<DeoptimizationInputData> data =
813  DeoptimizationInputData::New(isolate(), length, TENURED);
814 
815  Handle<ByteArray> translations =
816  translations_.CreateByteArray(isolate()->factory());
817  data->SetTranslationByteArray(*translations);
818  data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
819  data->SetOptimizationId(Smi::FromInt(info_->optimization_id()));
820  if (info_->IsOptimizing()) {
821  // Reference to shared function info does not change between phases.
822  AllowDeferredHandleDereference allow_handle_dereference;
823  data->SetSharedFunctionInfo(*info_->shared_info());
824  } else {
825  data->SetSharedFunctionInfo(Smi::FromInt(0));
826  }
827 
828  Handle<FixedArray> literals =
829  factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
830  { AllowDeferredHandleDereference copy_handles;
831  for (int i = 0; i < deoptimization_literals_.length(); i++) {
833  }
834  data->SetLiteralArray(*literals);
835  }
836 
837  data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
838  data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
839 
840  // Populate the deoptimization entries.
841  for (int i = 0; i < length; i++) {
843  data->SetAstId(i, env->ast_id());
844  data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
845  data->SetArgumentsStackHeight(i,
846  Smi::FromInt(env->arguments_stack_height()));
847  data->SetPc(i, Smi::FromInt(env->pc_offset()));
848  }
849  code->set_deoptimization_data(*data);
850 }
851 
852 
853 int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
854  int result = deoptimization_literals_.length();
855  for (int i = 0; i < deoptimization_literals_.length(); ++i) {
856  if (deoptimization_literals_[i].is_identical_to(literal)) return i;
857  }
858  deoptimization_literals_.Add(literal, zone());
859  return result;
860 }
861 
862 
864  DCHECK(deoptimization_literals_.length() == 0);
865 
866  const ZoneList<Handle<JSFunction> >* inlined_closures =
867  chunk()->inlined_closures();
868 
869  for (int i = 0, length = inlined_closures->length();
870  i < length;
871  i++) {
872  DefineDeoptimizationLiteral(inlined_closures->at(i));
873  }
874 
876 }
877 
878 
880  LInstruction* instr, SafepointMode safepoint_mode, int argc) {
881  if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
882  RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
883  } else {
884  DCHECK(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS);
886  instr->pointer_map(), argc, Safepoint::kLazyDeopt);
887  }
888 }
889 
890 
892  LPointerMap* pointers,
893  Safepoint::Kind kind,
894  int arguments,
895  Safepoint::DeoptMode deopt_mode) {
897 
898  const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
899 
900  Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
901  kind, arguments, deopt_mode);
902  for (int i = 0; i < operands->length(); i++) {
903  LOperand* pointer = operands->at(i);
904  if (pointer->IsStackSlot()) {
905  safepoint.DefinePointerSlot(pointer->index(), zone());
906  } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
907  safepoint.DefinePointerRegister(ToRegister(pointer), zone());
908  }
909  }
910 }
911 
912 
913 void LCodeGen::RecordSafepoint(LPointerMap* pointers,
914  Safepoint::DeoptMode deopt_mode) {
915  RecordSafepoint(pointers, Safepoint::kSimple, 0, deopt_mode);
916 }
917 
918 
919 void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) {
920  LPointerMap empty_pointers(zone());
921  RecordSafepoint(&empty_pointers, deopt_mode);
922 }
923 
924 
925 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
926  int arguments,
927  Safepoint::DeoptMode deopt_mode) {
928  RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, deopt_mode);
929 }
930 
931 
932 void LCodeGen::RecordAndWritePosition(int position) {
933  if (position == RelocInfo::kNoPosition) return;
934  masm()->positions_recorder()->RecordPosition(position);
935  masm()->positions_recorder()->WriteRecordedPositions();
936 }
937 
938 
939 static const char* LabelType(LLabel* label) {
940  if (label->is_loop_header()) return " (loop header)";
941  if (label->is_osr_entry()) return " (OSR entry)";
942  return "";
943 }
944 
945 
946 void LCodeGen::DoLabel(LLabel* label) {
947  Comment(";;; <@%d,#%d> -------------------- B%d%s --------------------",
948  current_instruction_,
949  label->hydrogen_value()->id(),
950  label->block_id(),
951  LabelType(label));
952  __ bind(label->label());
953  current_block_ = label->block_id();
954  DoGap(label);
955 }
956 
957 
958 void LCodeGen::DoParallelMove(LParallelMove* move) {
959  resolver_.Resolve(move);
960 }
961 
962 
963 void LCodeGen::DoGap(LGap* gap) {
964  for (int i = LGap::FIRST_INNER_POSITION;
966  i++) {
967  LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
968  LParallelMove* move = gap->GetParallelMove(inner_pos);
969  if (move != NULL) DoParallelMove(move);
970  }
971 }
972 
973 
974 void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
975  DoGap(instr);
976 }
977 
978 
979 void LCodeGen::DoParameter(LParameter* instr) {
980  // Nothing to do.
981 }
982 
983 
984 void LCodeGen::DoCallStub(LCallStub* instr) {
985  DCHECK(ToRegister(instr->context()).is(rsi));
986  DCHECK(ToRegister(instr->result()).is(rax));
987  switch (instr->hydrogen()->major_key()) {
988  case CodeStub::RegExpExec: {
989  RegExpExecStub stub(isolate());
990  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
991  break;
992  }
993  case CodeStub::SubString: {
994  SubStringStub stub(isolate());
995  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
996  break;
997  }
998  case CodeStub::StringCompare: {
999  StringCompareStub stub(isolate());
1000  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
1001  break;
1002  }
1003  default:
1004  UNREACHABLE();
1005  }
1006 }
1007 
1008 
1009 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
1011 }
1012 
1013 
1014 void LCodeGen::DoModByPowerOf2I(LModByPowerOf2I* instr) {
1015  Register dividend = ToRegister(instr->dividend());
1016  int32_t divisor = instr->divisor();
1017  DCHECK(dividend.is(ToRegister(instr->result())));
1018 
1019  // Theoretically, a variation of the branch-free code for integer division by
1020  // a power of 2 (calculating the remainder via an additional multiplication
1021  // (which gets simplified to an 'and') and subtraction) should be faster, and
1022  // this is exactly what GCC and clang emit. Nevertheless, benchmarks seem to
1023  // indicate that positive dividends are heavily favored, so the branching
1024  // version performs better.
1025  HMod* hmod = instr->hydrogen();
1026  int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
1027  Label dividend_is_not_negative, done;
1028  if (hmod->CheckFlag(HValue::kLeftCanBeNegative)) {
1029  __ testl(dividend, dividend);
1030  __ j(not_sign, &dividend_is_not_negative, Label::kNear);
1031  // Note that this is correct even for kMinInt operands.
1032  __ negl(dividend);
1033  __ andl(dividend, Immediate(mask));
1034  __ negl(dividend);
1035  if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1036  DeoptimizeIf(zero, instr, "minus zero");
1037  }
1038  __ jmp(&done, Label::kNear);
1039  }
1040 
1041  __ bind(&dividend_is_not_negative);
1042  __ andl(dividend, Immediate(mask));
1043  __ bind(&done);
1044 }
1045 
1046 
1047 void LCodeGen::DoModByConstI(LModByConstI* instr) {
1048  Register dividend = ToRegister(instr->dividend());
1049  int32_t divisor = instr->divisor();
1050  DCHECK(ToRegister(instr->result()).is(rax));
1051 
1052  if (divisor == 0) {
1053  DeoptimizeIf(no_condition, instr, "division by zero");
1054  return;
1055  }
1056 
1057  __ TruncatingDiv(dividend, Abs(divisor));
1058  __ imull(rdx, rdx, Immediate(Abs(divisor)));
1059  __ movl(rax, dividend);
1060  __ subl(rax, rdx);
1061 
1062  // Check for negative zero.
1063  HMod* hmod = instr->hydrogen();
1064  if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1065  Label remainder_not_zero;
1066  __ j(not_zero, &remainder_not_zero, Label::kNear);
1067  __ cmpl(dividend, Immediate(0));
1068  DeoptimizeIf(less, instr, "minus zero");
1069  __ bind(&remainder_not_zero);
1070  }
1071 }
1072 
1073 
1074 void LCodeGen::DoModI(LModI* instr) {
1075  HMod* hmod = instr->hydrogen();
1076 
1077  Register left_reg = ToRegister(instr->left());
1078  DCHECK(left_reg.is(rax));
1079  Register right_reg = ToRegister(instr->right());
1080  DCHECK(!right_reg.is(rax));
1081  DCHECK(!right_reg.is(rdx));
1082  Register result_reg = ToRegister(instr->result());
1083  DCHECK(result_reg.is(rdx));
1084 
1085  Label done;
1086  // Check for x % 0, idiv would signal a divide error. We have to
1087  // deopt in this case because we can't return a NaN.
1088  if (hmod->CheckFlag(HValue::kCanBeDivByZero)) {
1089  __ testl(right_reg, right_reg);
1090  DeoptimizeIf(zero, instr, "division by zero");
1091  }
1092 
1093  // Check for kMinInt % -1, idiv would signal a divide error. We
1094  // have to deopt if we care about -0, because we can't return that.
1095  if (hmod->CheckFlag(HValue::kCanOverflow)) {
1096  Label no_overflow_possible;
1097  __ cmpl(left_reg, Immediate(kMinInt));
1098  __ j(not_zero, &no_overflow_possible, Label::kNear);
1099  __ cmpl(right_reg, Immediate(-1));
1100  if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1101  DeoptimizeIf(equal, instr, "minus zero");
1102  } else {
1103  __ j(not_equal, &no_overflow_possible, Label::kNear);
1104  __ Set(result_reg, 0);
1105  __ jmp(&done, Label::kNear);
1106  }
1107  __ bind(&no_overflow_possible);
1108  }
1109 
1110  // Sign extend dividend in eax into edx:eax, since we are using only the low
1111  // 32 bits of the values.
1112  __ cdq();
1113 
1114  // If we care about -0, test if the dividend is <0 and the result is 0.
1115  if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1116  Label positive_left;
1117  __ testl(left_reg, left_reg);
1118  __ j(not_sign, &positive_left, Label::kNear);
1119  __ idivl(right_reg);
1120  __ testl(result_reg, result_reg);
1121  DeoptimizeIf(zero, instr, "minus zero");
1122  __ jmp(&done, Label::kNear);
1123  __ bind(&positive_left);
1124  }
1125  __ idivl(right_reg);
1126  __ bind(&done);
1127 }
1128 
1129 
1130 void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
1131  Register dividend = ToRegister(instr->dividend());
1132  int32_t divisor = instr->divisor();
1133  DCHECK(dividend.is(ToRegister(instr->result())));
1134 
1135  // If the divisor is positive, things are easy: There can be no deopts and we
1136  // can simply do an arithmetic right shift.
1137  if (divisor == 1) return;
1138  int32_t shift = WhichPowerOf2Abs(divisor);
1139  if (divisor > 1) {
1140  __ sarl(dividend, Immediate(shift));
1141  return;
1142  }
1143 
1144  // If the divisor is negative, we have to negate and handle edge cases.
1145  __ negl(dividend);
1146  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1147  DeoptimizeIf(zero, instr, "minus zero");
1148  }
1149 
1150  // Dividing by -1 is basically negation, unless we overflow.
1151  if (divisor == -1) {
1152  if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
1153  DeoptimizeIf(overflow, instr, "overflow");
1154  }
1155  return;
1156  }
1157 
1158  // If the negation could not overflow, simply shifting is OK.
1159  if (!instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
1160  __ sarl(dividend, Immediate(shift));
1161  return;
1162  }
1163 
1164  Label not_kmin_int, done;
1165  __ j(no_overflow, &not_kmin_int, Label::kNear);
1166  __ movl(dividend, Immediate(kMinInt / divisor));
1167  __ jmp(&done, Label::kNear);
1168  __ bind(&not_kmin_int);
1169  __ sarl(dividend, Immediate(shift));
1170  __ bind(&done);
1171 }
1172 
1173 
1174 void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) {
1175  Register dividend = ToRegister(instr->dividend());
1176  int32_t divisor = instr->divisor();
1177  DCHECK(ToRegister(instr->result()).is(rdx));
1178 
1179  if (divisor == 0) {
1180  DeoptimizeIf(no_condition, instr, "division by zero");
1181  return;
1182  }
1183 
1184  // Check for (0 / -x) that will produce negative zero.
1185  HMathFloorOfDiv* hdiv = instr->hydrogen();
1186  if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
1187  __ testl(dividend, dividend);
1188  DeoptimizeIf(zero, instr, "minus zero");
1189  }
1190 
1191  // Easy case: We need no dynamic check for the dividend and the flooring
1192  // division is the same as the truncating division.
1193  if ((divisor > 0 && !hdiv->CheckFlag(HValue::kLeftCanBeNegative)) ||
1194  (divisor < 0 && !hdiv->CheckFlag(HValue::kLeftCanBePositive))) {
1195  __ TruncatingDiv(dividend, Abs(divisor));
1196  if (divisor < 0) __ negl(rdx);
1197  return;
1198  }
1199 
1200  // In the general case we may need to adjust before and after the truncating
1201  // division to get a flooring division.
1202  Register temp = ToRegister(instr->temp3());
1203  DCHECK(!temp.is(dividend) && !temp.is(rax) && !temp.is(rdx));
1204  Label needs_adjustment, done;
1205  __ cmpl(dividend, Immediate(0));
1206  __ j(divisor > 0 ? less : greater, &needs_adjustment, Label::kNear);
1207  __ TruncatingDiv(dividend, Abs(divisor));
1208  if (divisor < 0) __ negl(rdx);
1209  __ jmp(&done, Label::kNear);
1210  __ bind(&needs_adjustment);
1211  __ leal(temp, Operand(dividend, divisor > 0 ? 1 : -1));
1212  __ TruncatingDiv(temp, Abs(divisor));
1213  if (divisor < 0) __ negl(rdx);
1214  __ decl(rdx);
1215  __ bind(&done);
1216 }
1217 
1218 
1219 // TODO(svenpanne) Refactor this to avoid code duplication with DoDivI.
1220 void LCodeGen::DoFlooringDivI(LFlooringDivI* instr) {
1221  HBinaryOperation* hdiv = instr->hydrogen();
1222  Register dividend = ToRegister(instr->dividend());
1223  Register divisor = ToRegister(instr->divisor());
1224  Register remainder = ToRegister(instr->temp());
1225  Register result = ToRegister(instr->result());
1226  DCHECK(dividend.is(rax));
1227  DCHECK(remainder.is(rdx));
1228  DCHECK(result.is(rax));
1229  DCHECK(!divisor.is(rax));
1230  DCHECK(!divisor.is(rdx));
1231 
1232  // Check for x / 0.
1233  if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
1234  __ testl(divisor, divisor);
1235  DeoptimizeIf(zero, instr, "division by zero");
1236  }
1237 
1238  // Check for (0 / -x) that will produce negative zero.
1239  if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
1240  Label dividend_not_zero;
1241  __ testl(dividend, dividend);
1242  __ j(not_zero, &dividend_not_zero, Label::kNear);
1243  __ testl(divisor, divisor);
1244  DeoptimizeIf(sign, instr, "minus zero");
1245  __ bind(&dividend_not_zero);
1246  }
1247 
1248  // Check for (kMinInt / -1).
1249  if (hdiv->CheckFlag(HValue::kCanOverflow)) {
1250  Label dividend_not_min_int;
1251  __ cmpl(dividend, Immediate(kMinInt));
1252  __ j(not_zero, &dividend_not_min_int, Label::kNear);
1253  __ cmpl(divisor, Immediate(-1));
1254  DeoptimizeIf(zero, instr, "overflow");
1255  __ bind(&dividend_not_min_int);
1256  }
1257 
1258  // Sign extend to rdx (= remainder).
1259  __ cdq();
1260  __ idivl(divisor);
1261 
1262  Label done;
1263  __ testl(remainder, remainder);
1264  __ j(zero, &done, Label::kNear);
1265  __ xorl(remainder, divisor);
1266  __ sarl(remainder, Immediate(31));
1267  __ addl(result, remainder);
1268  __ bind(&done);
1269 }
1270 
1271 
1272 void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) {
1273  Register dividend = ToRegister(instr->dividend());
1274  int32_t divisor = instr->divisor();
1275  Register result = ToRegister(instr->result());
1276  DCHECK(divisor == kMinInt || base::bits::IsPowerOfTwo32(Abs(divisor)));
1277  DCHECK(!result.is(dividend));
1278 
1279  // Check for (0 / -x) that will produce negative zero.
1280  HDiv* hdiv = instr->hydrogen();
1281  if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
1282  __ testl(dividend, dividend);
1283  DeoptimizeIf(zero, instr, "minus zero");
1284  }
1285  // Check for (kMinInt / -1).
1286  if (hdiv->CheckFlag(HValue::kCanOverflow) && divisor == -1) {
1287  __ cmpl(dividend, Immediate(kMinInt));
1288  DeoptimizeIf(zero, instr, "overflow");
1289  }
1290  // Deoptimize if remainder will not be 0.
1291  if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
1292  divisor != 1 && divisor != -1) {
1293  int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
1294  __ testl(dividend, Immediate(mask));
1295  DeoptimizeIf(not_zero, instr, "lost precision");
1296  }
1297  __ Move(result, dividend);
1298  int32_t shift = WhichPowerOf2Abs(divisor);
1299  if (shift > 0) {
1300  // The arithmetic shift is always OK, the 'if' is an optimization only.
1301  if (shift > 1) __ sarl(result, Immediate(31));
1302  __ shrl(result, Immediate(32 - shift));
1303  __ addl(result, dividend);
1304  __ sarl(result, Immediate(shift));
1305  }
1306  if (divisor < 0) __ negl(result);
1307 }
1308 
1309 
1310 void LCodeGen::DoDivByConstI(LDivByConstI* instr) {
1311  Register dividend = ToRegister(instr->dividend());
1312  int32_t divisor = instr->divisor();
1313  DCHECK(ToRegister(instr->result()).is(rdx));
1314 
1315  if (divisor == 0) {
1316  DeoptimizeIf(no_condition, instr, "division by zero");
1317  return;
1318  }
1319 
1320  // Check for (0 / -x) that will produce negative zero.
1321  HDiv* hdiv = instr->hydrogen();
1322  if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
1323  __ testl(dividend, dividend);
1324  DeoptimizeIf(zero, instr, "minus zero");
1325  }
1326 
1327  __ TruncatingDiv(dividend, Abs(divisor));
1328  if (divisor < 0) __ negl(rdx);
1329 
1330  if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
1331  __ movl(rax, rdx);
1332  __ imull(rax, rax, Immediate(divisor));
1333  __ subl(rax, dividend);
1334  DeoptimizeIf(not_equal, instr, "lost precision");
1335  }
1336 }
1337 
1338 
1339 // TODO(svenpanne) Refactor this to avoid code duplication with DoFlooringDivI.
1340 void LCodeGen::DoDivI(LDivI* instr) {
1341  HBinaryOperation* hdiv = instr->hydrogen();
1342  Register dividend = ToRegister(instr->dividend());
1343  Register divisor = ToRegister(instr->divisor());
1344  Register remainder = ToRegister(instr->temp());
1345  DCHECK(dividend.is(rax));
1346  DCHECK(remainder.is(rdx));
1347  DCHECK(ToRegister(instr->result()).is(rax));
1348  DCHECK(!divisor.is(rax));
1349  DCHECK(!divisor.is(rdx));
1350 
1351  // Check for x / 0.
1352  if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
1353  __ testl(divisor, divisor);
1354  DeoptimizeIf(zero, instr, "division by zero");
1355  }
1356 
1357  // Check for (0 / -x) that will produce negative zero.
1358  if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
1359  Label dividend_not_zero;
1360  __ testl(dividend, dividend);
1361  __ j(not_zero, &dividend_not_zero, Label::kNear);
1362  __ testl(divisor, divisor);
1363  DeoptimizeIf(sign, instr, "minus zero");
1364  __ bind(&dividend_not_zero);
1365  }
1366 
1367  // Check for (kMinInt / -1).
1368  if (hdiv->CheckFlag(HValue::kCanOverflow)) {
1369  Label dividend_not_min_int;
1370  __ cmpl(dividend, Immediate(kMinInt));
1371  __ j(not_zero, &dividend_not_min_int, Label::kNear);
1372  __ cmpl(divisor, Immediate(-1));
1373  DeoptimizeIf(zero, instr, "overflow");
1374  __ bind(&dividend_not_min_int);
1375  }
1376 
1377  // Sign extend to rdx (= remainder).
1378  __ cdq();
1379  __ idivl(divisor);
1380 
1381  if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
1382  // Deoptimize if remainder is not 0.
1383  __ testl(remainder, remainder);
1384  DeoptimizeIf(not_zero, instr, "lost precision");
1385  }
1386 }
1387 
1388 
1389 void LCodeGen::DoMulI(LMulI* instr) {
1390  Register left = ToRegister(instr->left());
1391  LOperand* right = instr->right();
1392 
1393  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1394  if (instr->hydrogen_value()->representation().IsSmi()) {
1395  __ movp(kScratchRegister, left);
1396  } else {
1397  __ movl(kScratchRegister, left);
1398  }
1399  }
1400 
1401  bool can_overflow =
1402  instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
1403  if (right->IsConstantOperand()) {
1404  int32_t right_value = ToInteger32(LConstantOperand::cast(right));
1405  if (right_value == -1) {
1406  __ negl(left);
1407  } else if (right_value == 0) {
1408  __ xorl(left, left);
1409  } else if (right_value == 2) {
1410  __ addl(left, left);
1411  } else if (!can_overflow) {
1412  // If the multiplication is known to not overflow, we
1413  // can use operations that don't set the overflow flag
1414  // correctly.
1415  switch (right_value) {
1416  case 1:
1417  // Do nothing.
1418  break;
1419  case 3:
1420  __ leal(left, Operand(left, left, times_2, 0));
1421  break;
1422  case 4:
1423  __ shll(left, Immediate(2));
1424  break;
1425  case 5:
1426  __ leal(left, Operand(left, left, times_4, 0));
1427  break;
1428  case 8:
1429  __ shll(left, Immediate(3));
1430  break;
1431  case 9:
1432  __ leal(left, Operand(left, left, times_8, 0));
1433  break;
1434  case 16:
1435  __ shll(left, Immediate(4));
1436  break;
1437  default:
1438  __ imull(left, left, Immediate(right_value));
1439  break;
1440  }
1441  } else {
1442  __ imull(left, left, Immediate(right_value));
1443  }
1444  } else if (right->IsStackSlot()) {
1445  if (instr->hydrogen_value()->representation().IsSmi()) {
1446  __ SmiToInteger64(left, left);
1447  __ imulp(left, ToOperand(right));
1448  } else {
1449  __ imull(left, ToOperand(right));
1450  }
1451  } else {
1452  if (instr->hydrogen_value()->representation().IsSmi()) {
1453  __ SmiToInteger64(left, left);
1454  __ imulp(left, ToRegister(right));
1455  } else {
1456  __ imull(left, ToRegister(right));
1457  }
1458  }
1459 
1460  if (can_overflow) {
1461  DeoptimizeIf(overflow, instr, "overflow");
1462  }
1463 
1464  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1465  // Bail out if the result is supposed to be negative zero.
1466  Label done;
1467  if (instr->hydrogen_value()->representation().IsSmi()) {
1468  __ testp(left, left);
1469  } else {
1470  __ testl(left, left);
1471  }
1472  __ j(not_zero, &done, Label::kNear);
1473  if (right->IsConstantOperand()) {
1474  // Constant can't be represented as 32-bit Smi due to immediate size
1475  // limit.
1477  ? !instr->hydrogen_value()->representation().IsSmi()
1478  : SmiValuesAre31Bits());
1479  if (ToInteger32(LConstantOperand::cast(right)) < 0) {
1480  DeoptimizeIf(no_condition, instr, "minus zero");
1481  } else if (ToInteger32(LConstantOperand::cast(right)) == 0) {
1482  __ cmpl(kScratchRegister, Immediate(0));
1483  DeoptimizeIf(less, instr, "minus zero");
1484  }
1485  } else if (right->IsStackSlot()) {
1486  if (instr->hydrogen_value()->representation().IsSmi()) {
1487  __ orp(kScratchRegister, ToOperand(right));
1488  } else {
1489  __ orl(kScratchRegister, ToOperand(right));
1490  }
1491  DeoptimizeIf(sign, instr, "minus zero");
1492  } else {
1493  // Test the non-zero operand for negative sign.
1494  if (instr->hydrogen_value()->representation().IsSmi()) {
1495  __ orp(kScratchRegister, ToRegister(right));
1496  } else {
1497  __ orl(kScratchRegister, ToRegister(right));
1498  }
1499  DeoptimizeIf(sign, instr, "minus zero");
1500  }
1501  __ bind(&done);
1502  }
1503 }
1504 
1505 
1506 void LCodeGen::DoBitI(LBitI* instr) {
1507  LOperand* left = instr->left();
1508  LOperand* right = instr->right();
1509  DCHECK(left->Equals(instr->result()));
1510  DCHECK(left->IsRegister());
1511 
1512  if (right->IsConstantOperand()) {
1513  int32_t right_operand =
1514  ToRepresentation(LConstantOperand::cast(right),
1515  instr->hydrogen()->right()->representation());
1516  switch (instr->op()) {
1517  case Token::BIT_AND:
1518  __ andl(ToRegister(left), Immediate(right_operand));
1519  break;
1520  case Token::BIT_OR:
1521  __ orl(ToRegister(left), Immediate(right_operand));
1522  break;
1523  case Token::BIT_XOR:
1524  if (right_operand == int32_t(~0)) {
1525  __ notl(ToRegister(left));
1526  } else {
1527  __ xorl(ToRegister(left), Immediate(right_operand));
1528  }
1529  break;
1530  default:
1531  UNREACHABLE();
1532  break;
1533  }
1534  } else if (right->IsStackSlot()) {
1535  switch (instr->op()) {
1536  case Token::BIT_AND:
1537  if (instr->IsInteger32()) {
1538  __ andl(ToRegister(left), ToOperand(right));
1539  } else {
1540  __ andp(ToRegister(left), ToOperand(right));
1541  }
1542  break;
1543  case Token::BIT_OR:
1544  if (instr->IsInteger32()) {
1545  __ orl(ToRegister(left), ToOperand(right));
1546  } else {
1547  __ orp(ToRegister(left), ToOperand(right));
1548  }
1549  break;
1550  case Token::BIT_XOR:
1551  if (instr->IsInteger32()) {
1552  __ xorl(ToRegister(left), ToOperand(right));
1553  } else {
1554  __ xorp(ToRegister(left), ToOperand(right));
1555  }
1556  break;
1557  default:
1558  UNREACHABLE();
1559  break;
1560  }
1561  } else {
1562  DCHECK(right->IsRegister());
1563  switch (instr->op()) {
1564  case Token::BIT_AND:
1565  if (instr->IsInteger32()) {
1566  __ andl(ToRegister(left), ToRegister(right));
1567  } else {
1568  __ andp(ToRegister(left), ToRegister(right));
1569  }
1570  break;
1571  case Token::BIT_OR:
1572  if (instr->IsInteger32()) {
1573  __ orl(ToRegister(left), ToRegister(right));
1574  } else {
1575  __ orp(ToRegister(left), ToRegister(right));
1576  }
1577  break;
1578  case Token::BIT_XOR:
1579  if (instr->IsInteger32()) {
1580  __ xorl(ToRegister(left), ToRegister(right));
1581  } else {
1582  __ xorp(ToRegister(left), ToRegister(right));
1583  }
1584  break;
1585  default:
1586  UNREACHABLE();
1587  break;
1588  }
1589  }
1590 }
1591 
1592 
1593 void LCodeGen::DoShiftI(LShiftI* instr) {
1594  LOperand* left = instr->left();
1595  LOperand* right = instr->right();
1596  DCHECK(left->Equals(instr->result()));
1597  DCHECK(left->IsRegister());
1598  if (right->IsRegister()) {
1599  DCHECK(ToRegister(right).is(rcx));
1600 
1601  switch (instr->op()) {
1602  case Token::ROR:
1603  __ rorl_cl(ToRegister(left));
1604  break;
1605  case Token::SAR:
1606  __ sarl_cl(ToRegister(left));
1607  break;
1608  case Token::SHR:
1609  __ shrl_cl(ToRegister(left));
1610  if (instr->can_deopt()) {
1611  __ testl(ToRegister(left), ToRegister(left));
1612  DeoptimizeIf(negative, instr, "negative value");
1613  }
1614  break;
1615  case Token::SHL:
1616  __ shll_cl(ToRegister(left));
1617  break;
1618  default:
1619  UNREACHABLE();
1620  break;
1621  }
1622  } else {
1623  int32_t value = ToInteger32(LConstantOperand::cast(right));
1624  uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1625  switch (instr->op()) {
1626  case Token::ROR:
1627  if (shift_count != 0) {
1628  __ rorl(ToRegister(left), Immediate(shift_count));
1629  }
1630  break;
1631  case Token::SAR:
1632  if (shift_count != 0) {
1633  __ sarl(ToRegister(left), Immediate(shift_count));
1634  }
1635  break;
1636  case Token::SHR:
1637  if (shift_count != 0) {
1638  __ shrl(ToRegister(left), Immediate(shift_count));
1639  } else if (instr->can_deopt()) {
1640  __ testl(ToRegister(left), ToRegister(left));
1641  DeoptimizeIf(negative, instr, "negative value");
1642  }
1643  break;
1644  case Token::SHL:
1645  if (shift_count != 0) {
1646  if (instr->hydrogen_value()->representation().IsSmi()) {
1647  if (SmiValuesAre32Bits()) {
1648  __ shlp(ToRegister(left), Immediate(shift_count));
1649  } else {
1651  if (instr->can_deopt()) {
1652  if (shift_count != 1) {
1653  __ shll(ToRegister(left), Immediate(shift_count - 1));
1654  }
1655  __ Integer32ToSmi(ToRegister(left), ToRegister(left));
1656  DeoptimizeIf(overflow, instr, "overflow");
1657  } else {
1658  __ shll(ToRegister(left), Immediate(shift_count));
1659  }
1660  }
1661  } else {
1662  __ shll(ToRegister(left), Immediate(shift_count));
1663  }
1664  }
1665  break;
1666  default:
1667  UNREACHABLE();
1668  break;
1669  }
1670  }
1671 }
1672 
1673 
1674 void LCodeGen::DoSubI(LSubI* instr) {
1675  LOperand* left = instr->left();
1676  LOperand* right = instr->right();
1677  DCHECK(left->Equals(instr->result()));
1678 
1679  if (right->IsConstantOperand()) {
1680  int32_t right_operand =
1681  ToRepresentation(LConstantOperand::cast(right),
1682  instr->hydrogen()->right()->representation());
1683  __ subl(ToRegister(left), Immediate(right_operand));
1684  } else if (right->IsRegister()) {
1685  if (instr->hydrogen_value()->representation().IsSmi()) {
1686  __ subp(ToRegister(left), ToRegister(right));
1687  } else {
1688  __ subl(ToRegister(left), ToRegister(right));
1689  }
1690  } else {
1691  if (instr->hydrogen_value()->representation().IsSmi()) {
1692  __ subp(ToRegister(left), ToOperand(right));
1693  } else {
1694  __ subl(ToRegister(left), ToOperand(right));
1695  }
1696  }
1697 
1698  if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1699  DeoptimizeIf(overflow, instr, "overflow");
1700  }
1701 }
1702 
1703 
1704 void LCodeGen::DoConstantI(LConstantI* instr) {
1705  Register dst = ToRegister(instr->result());
1706  if (instr->value() == 0) {
1707  __ xorl(dst, dst);
1708  } else {
1709  __ movl(dst, Immediate(instr->value()));
1710  }
1711 }
1712 
1713 
1714 void LCodeGen::DoConstantS(LConstantS* instr) {
1715  __ Move(ToRegister(instr->result()), instr->value());
1716 }
1717 
1718 
1719 void LCodeGen::DoConstantD(LConstantD* instr) {
1720  DCHECK(instr->result()->IsDoubleRegister());
1721  XMMRegister res = ToDoubleRegister(instr->result());
1722  double v = instr->value();
1723  uint64_t int_val = bit_cast<uint64_t, double>(v);
1724  // Use xor to produce +0.0 in a fast and compact way, but avoid to
1725  // do so if the constant is -0.0.
1726  if (int_val == 0) {
1727  __ xorps(res, res);
1728  } else {
1729  Register tmp = ToRegister(instr->temp());
1730  __ Set(tmp, int_val);
1731  __ movq(res, tmp);
1732  }
1733 }
1734 
1735 
1736 void LCodeGen::DoConstantE(LConstantE* instr) {
1737  __ LoadAddress(ToRegister(instr->result()), instr->value());
1738 }
1739 
1740 
1741 void LCodeGen::DoConstantT(LConstantT* instr) {
1742  Handle<Object> object = instr->value(isolate());
1744  __ Move(ToRegister(instr->result()), object);
1745 }
1746 
1747 
1748 void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
1749  Register result = ToRegister(instr->result());
1750  Register map = ToRegister(instr->value());
1751  __ EnumLength(result, map);
1752 }
1753 
1754 
1755 void LCodeGen::DoDateField(LDateField* instr) {
1756  Register object = ToRegister(instr->date());
1757  Register result = ToRegister(instr->result());
1758  Smi* index = instr->index();
1759  Label runtime, done, not_date_object;
1760  DCHECK(object.is(result));
1761  DCHECK(object.is(rax));
1762 
1763  Condition cc = masm()->CheckSmi(object);
1764  DeoptimizeIf(cc, instr, "Smi");
1765  __ CmpObjectType(object, JS_DATE_TYPE, kScratchRegister);
1766  DeoptimizeIf(not_equal, instr, "not a date object");
1767 
1768  if (index->value() == 0) {
1769  __ movp(result, FieldOperand(object, JSDate::kValueOffset));
1770  } else {
1771  if (index->value() < JSDate::kFirstUncachedField) {
1772  ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
1773  Operand stamp_operand = __ ExternalOperand(stamp);
1774  __ movp(kScratchRegister, stamp_operand);
1775  __ cmpp(kScratchRegister, FieldOperand(object,
1777  __ j(not_equal, &runtime, Label::kNear);
1778  __ movp(result, FieldOperand(object, JSDate::kValueOffset +
1779  kPointerSize * index->value()));
1780  __ jmp(&done, Label::kNear);
1781  }
1782  __ bind(&runtime);
1783  __ PrepareCallCFunction(2);
1784  __ movp(arg_reg_1, object);
1785  __ Move(arg_reg_2, index, Assembler::RelocInfoNone());
1786  __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
1787  __ bind(&done);
1788  }
1789 }
1790 
1791 
1792 Operand LCodeGen::BuildSeqStringOperand(Register string,
1793  LOperand* index,
1794  String::Encoding encoding) {
1795  if (index->IsConstantOperand()) {
1796  int offset = ToInteger32(LConstantOperand::cast(index));
1797  if (encoding == String::TWO_BYTE_ENCODING) {
1798  offset *= kUC16Size;
1799  }
1800  STATIC_ASSERT(kCharSize == 1);
1801  return FieldOperand(string, SeqString::kHeaderSize + offset);
1802  }
1803  return FieldOperand(
1804  string, ToRegister(index),
1805  encoding == String::ONE_BYTE_ENCODING ? times_1 : times_2,
1807 }
1808 
1809 
1810 void LCodeGen::DoSeqStringGetChar(LSeqStringGetChar* instr) {
1811  String::Encoding encoding = instr->hydrogen()->encoding();
1812  Register result = ToRegister(instr->result());
1813  Register string = ToRegister(instr->string());
1814 
1815  if (FLAG_debug_code) {
1816  __ Push(string);
1817  __ movp(string, FieldOperand(string, HeapObject::kMapOffset));
1818  __ movzxbp(string, FieldOperand(string, Map::kInstanceTypeOffset));
1819 
1820  __ andb(string, Immediate(kStringRepresentationMask | kStringEncodingMask));
1821  static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
1822  static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
1823  __ cmpp(string, Immediate(encoding == String::ONE_BYTE_ENCODING
1824  ? one_byte_seq_type : two_byte_seq_type));
1825  __ Check(equal, kUnexpectedStringType);
1826  __ Pop(string);
1827  }
1828 
1829  Operand operand = BuildSeqStringOperand(string, instr->index(), encoding);
1830  if (encoding == String::ONE_BYTE_ENCODING) {
1831  __ movzxbl(result, operand);
1832  } else {
1833  __ movzxwl(result, operand);
1834  }
1835 }
1836 
1837 
1838 void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
1839  String::Encoding encoding = instr->hydrogen()->encoding();
1840  Register string = ToRegister(instr->string());
1841 
1842  if (FLAG_debug_code) {
1843  Register value = ToRegister(instr->value());
1844  Register index = ToRegister(instr->index());
1845  static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
1846  static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
1847  int encoding_mask =
1848  instr->hydrogen()->encoding() == String::ONE_BYTE_ENCODING
1849  ? one_byte_seq_type : two_byte_seq_type;
1850  __ EmitSeqStringSetCharCheck(string, index, value, encoding_mask);
1851  }
1852 
1853  Operand operand = BuildSeqStringOperand(string, instr->index(), encoding);
1854  if (instr->value()->IsConstantOperand()) {
1855  int value = ToInteger32(LConstantOperand::cast(instr->value()));
1856  DCHECK_LE(0, value);
1857  if (encoding == String::ONE_BYTE_ENCODING) {
1859  __ movb(operand, Immediate(value));
1860  } else {
1862  __ movw(operand, Immediate(value));
1863  }
1864  } else {
1865  Register value = ToRegister(instr->value());
1866  if (encoding == String::ONE_BYTE_ENCODING) {
1867  __ movb(operand, value);
1868  } else {
1869  __ movw(operand, value);
1870  }
1871  }
1872 }
1873 
1874 
1875 void LCodeGen::DoAddI(LAddI* instr) {
1876  LOperand* left = instr->left();
1877  LOperand* right = instr->right();
1878 
1879  Representation target_rep = instr->hydrogen()->representation();
1880  bool is_p = target_rep.IsSmi() || target_rep.IsExternal();
1881 
1882  if (LAddI::UseLea(instr->hydrogen()) && !left->Equals(instr->result())) {
1883  if (right->IsConstantOperand()) {
1884  // No support for smi-immediates for 32-bit SMI.
1885  DCHECK(SmiValuesAre32Bits() ? !target_rep.IsSmi() : SmiValuesAre31Bits());
1886  int32_t offset =
1887  ToRepresentation(LConstantOperand::cast(right),
1888  instr->hydrogen()->right()->representation());
1889  if (is_p) {
1890  __ leap(ToRegister(instr->result()),
1891  MemOperand(ToRegister(left), offset));
1892  } else {
1893  __ leal(ToRegister(instr->result()),
1894  MemOperand(ToRegister(left), offset));
1895  }
1896  } else {
1897  Operand address(ToRegister(left), ToRegister(right), times_1, 0);
1898  if (is_p) {
1899  __ leap(ToRegister(instr->result()), address);
1900  } else {
1901  __ leal(ToRegister(instr->result()), address);
1902  }
1903  }
1904  } else {
1905  if (right->IsConstantOperand()) {
1906  // No support for smi-immediates for 32-bit SMI.
1907  DCHECK(SmiValuesAre32Bits() ? !target_rep.IsSmi() : SmiValuesAre31Bits());
1908  int32_t right_operand =
1909  ToRepresentation(LConstantOperand::cast(right),
1910  instr->hydrogen()->right()->representation());
1911  if (is_p) {
1912  __ addp(ToRegister(left), Immediate(right_operand));
1913  } else {
1914  __ addl(ToRegister(left), Immediate(right_operand));
1915  }
1916  } else if (right->IsRegister()) {
1917  if (is_p) {
1918  __ addp(ToRegister(left), ToRegister(right));
1919  } else {
1920  __ addl(ToRegister(left), ToRegister(right));
1921  }
1922  } else {
1923  if (is_p) {
1924  __ addp(ToRegister(left), ToOperand(right));
1925  } else {
1926  __ addl(ToRegister(left), ToOperand(right));
1927  }
1928  }
1929  if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1930  DeoptimizeIf(overflow, instr, "overflow");
1931  }
1932  }
1933 }
1934 
1935 
1936 void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
1937  LOperand* left = instr->left();
1938  LOperand* right = instr->right();
1939  DCHECK(left->Equals(instr->result()));
1940  HMathMinMax::Operation operation = instr->hydrogen()->operation();
1941  if (instr->hydrogen()->representation().IsSmiOrInteger32()) {
1942  Label return_left;
1943  Condition condition = (operation == HMathMinMax::kMathMin)
1944  ? less_equal
1945  : greater_equal;
1946  Register left_reg = ToRegister(left);
1947  if (right->IsConstantOperand()) {
1948  Immediate right_imm = Immediate(
1949  ToRepresentation(LConstantOperand::cast(right),
1950  instr->hydrogen()->right()->representation()));
1952  ? !instr->hydrogen()->representation().IsSmi()
1953  : SmiValuesAre31Bits());
1954  __ cmpl(left_reg, right_imm);
1955  __ j(condition, &return_left, Label::kNear);
1956  __ movp(left_reg, right_imm);
1957  } else if (right->IsRegister()) {
1958  Register right_reg = ToRegister(right);
1959  if (instr->hydrogen_value()->representation().IsSmi()) {
1960  __ cmpp(left_reg, right_reg);
1961  } else {
1962  __ cmpl(left_reg, right_reg);
1963  }
1964  __ j(condition, &return_left, Label::kNear);
1965  __ movp(left_reg, right_reg);
1966  } else {
1967  Operand right_op = ToOperand(right);
1968  if (instr->hydrogen_value()->representation().IsSmi()) {
1969  __ cmpp(left_reg, right_op);
1970  } else {
1971  __ cmpl(left_reg, right_op);
1972  }
1973  __ j(condition, &return_left, Label::kNear);
1974  __ movp(left_reg, right_op);
1975  }
1976  __ bind(&return_left);
1977  } else {
1978  DCHECK(instr->hydrogen()->representation().IsDouble());
1979  Label check_nan_left, check_zero, return_left, return_right;
1980  Condition condition = (operation == HMathMinMax::kMathMin) ? below : above;
1981  XMMRegister left_reg = ToDoubleRegister(left);
1982  XMMRegister right_reg = ToDoubleRegister(right);
1983  __ ucomisd(left_reg, right_reg);
1984  __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN.
1985  __ j(equal, &check_zero, Label::kNear); // left == right.
1986  __ j(condition, &return_left, Label::kNear);
1987  __ jmp(&return_right, Label::kNear);
1988 
1989  __ bind(&check_zero);
1990  XMMRegister xmm_scratch = double_scratch0();
1991  __ xorps(xmm_scratch, xmm_scratch);
1992  __ ucomisd(left_reg, xmm_scratch);
1993  __ j(not_equal, &return_left, Label::kNear); // left == right != 0.
1994  // At this point, both left and right are either 0 or -0.
1995  if (operation == HMathMinMax::kMathMin) {
1996  __ orps(left_reg, right_reg);
1997  } else {
1998  // Since we operate on +0 and/or -0, addsd and andsd have the same effect.
1999  __ addsd(left_reg, right_reg);
2000  }
2001  __ jmp(&return_left, Label::kNear);
2002 
2003  __ bind(&check_nan_left);
2004  __ ucomisd(left_reg, left_reg); // NaN check.
2005  __ j(parity_even, &return_left, Label::kNear);
2006  __ bind(&return_right);
2007  __ movaps(left_reg, right_reg);
2008 
2009  __ bind(&return_left);
2010  }
2011 }
2012 
2013 
2014 void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
2015  XMMRegister left = ToDoubleRegister(instr->left());
2016  XMMRegister right = ToDoubleRegister(instr->right());
2017  XMMRegister result = ToDoubleRegister(instr->result());
2018  // All operations except MOD are computed in-place.
2019  DCHECK(instr->op() == Token::MOD || left.is(result));
2020  switch (instr->op()) {
2021  case Token::ADD:
2022  __ addsd(left, right);
2023  break;
2024  case Token::SUB:
2025  __ subsd(left, right);
2026  break;
2027  case Token::MUL:
2028  __ mulsd(left, right);
2029  break;
2030  case Token::DIV:
2031  __ divsd(left, right);
2032  // Don't delete this mov. It may improve performance on some CPUs,
2033  // when there is a mulsd depending on the result
2034  __ movaps(left, left);
2035  break;
2036  case Token::MOD: {
2037  XMMRegister xmm_scratch = double_scratch0();
2038  __ PrepareCallCFunction(2);
2039  __ movaps(xmm_scratch, left);
2040  DCHECK(right.is(xmm1));
2041  __ CallCFunction(
2042  ExternalReference::mod_two_doubles_operation(isolate()), 2);
2043  __ movaps(result, xmm_scratch);
2044  break;
2045  }
2046  default:
2047  UNREACHABLE();
2048  break;
2049  }
2050 }
2051 
2052 
2053 void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
2054  DCHECK(ToRegister(instr->context()).is(rsi));
2055  DCHECK(ToRegister(instr->left()).is(rdx));
2056  DCHECK(ToRegister(instr->right()).is(rax));
2057  DCHECK(ToRegister(instr->result()).is(rax));
2058 
2059  Handle<Code> code =
2060  CodeFactory::BinaryOpIC(isolate(), instr->op(), NO_OVERWRITE).code();
2061  CallCode(code, RelocInfo::CODE_TARGET, instr);
2062 }
2063 
2064 
2065 template<class InstrType>
2066 void LCodeGen::EmitBranch(InstrType instr, Condition cc) {
2067  int left_block = instr->TrueDestination(chunk_);
2068  int right_block = instr->FalseDestination(chunk_);
2069 
2070  int next_block = GetNextEmittedBlock();
2071 
2072  if (right_block == left_block || cc == no_condition) {
2073  EmitGoto(left_block);
2074  } else if (left_block == next_block) {
2075  __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
2076  } else if (right_block == next_block) {
2077  __ j(cc, chunk_->GetAssemblyLabel(left_block));
2078  } else {
2079  __ j(cc, chunk_->GetAssemblyLabel(left_block));
2080  if (cc != always) {
2081  __ jmp(chunk_->GetAssemblyLabel(right_block));
2082  }
2083  }
2084 }
2085 
2086 
2087 template<class InstrType>
2088 void LCodeGen::EmitFalseBranch(InstrType instr, Condition cc) {
2089  int false_block = instr->FalseDestination(chunk_);
2090  __ j(cc, chunk_->GetAssemblyLabel(false_block));
2091 }
2092 
2093 
2094 void LCodeGen::DoDebugBreak(LDebugBreak* instr) {
2095  __ int3();
2096 }
2097 
2098 
2099 void LCodeGen::DoBranch(LBranch* instr) {
2100  Representation r = instr->hydrogen()->value()->representation();
2101  if (r.IsInteger32()) {
2102  DCHECK(!info()->IsStub());
2103  Register reg = ToRegister(instr->value());
2104  __ testl(reg, reg);
2105  EmitBranch(instr, not_zero);
2106  } else if (r.IsSmi()) {
2107  DCHECK(!info()->IsStub());
2108  Register reg = ToRegister(instr->value());
2109  __ testp(reg, reg);
2110  EmitBranch(instr, not_zero);
2111  } else if (r.IsDouble()) {
2112  DCHECK(!info()->IsStub());
2113  XMMRegister reg = ToDoubleRegister(instr->value());
2114  XMMRegister xmm_scratch = double_scratch0();
2115  __ xorps(xmm_scratch, xmm_scratch);
2116  __ ucomisd(reg, xmm_scratch);
2117  EmitBranch(instr, not_equal);
2118  } else {
2119  DCHECK(r.IsTagged());
2120  Register reg = ToRegister(instr->value());
2121  HType type = instr->hydrogen()->value()->type();
2122  if (type.IsBoolean()) {
2123  DCHECK(!info()->IsStub());
2124  __ CompareRoot(reg, Heap::kTrueValueRootIndex);
2125  EmitBranch(instr, equal);
2126  } else if (type.IsSmi()) {
2127  DCHECK(!info()->IsStub());
2128  __ SmiCompare(reg, Smi::FromInt(0));
2129  EmitBranch(instr, not_equal);
2130  } else if (type.IsJSArray()) {
2131  DCHECK(!info()->IsStub());
2132  EmitBranch(instr, no_condition);
2133  } else if (type.IsHeapNumber()) {
2134  DCHECK(!info()->IsStub());
2135  XMMRegister xmm_scratch = double_scratch0();
2136  __ xorps(xmm_scratch, xmm_scratch);
2137  __ ucomisd(xmm_scratch, FieldOperand(reg, HeapNumber::kValueOffset));
2138  EmitBranch(instr, not_equal);
2139  } else if (type.IsString()) {
2140  DCHECK(!info()->IsStub());
2141  __ cmpp(FieldOperand(reg, String::kLengthOffset), Immediate(0));
2142  EmitBranch(instr, not_equal);
2143  } else {
2144  ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
2145  // Avoid deopts in the case where we've never executed this path before.
2146  if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
2147 
2148  if (expected.Contains(ToBooleanStub::UNDEFINED)) {
2149  // undefined -> false.
2150  __ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
2151  __ j(equal, instr->FalseLabel(chunk_));
2152  }
2153  if (expected.Contains(ToBooleanStub::BOOLEAN)) {
2154  // true -> true.
2155  __ CompareRoot(reg, Heap::kTrueValueRootIndex);
2156  __ j(equal, instr->TrueLabel(chunk_));
2157  // false -> false.
2158  __ CompareRoot(reg, Heap::kFalseValueRootIndex);
2159  __ j(equal, instr->FalseLabel(chunk_));
2160  }
2161  if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
2162  // 'null' -> false.
2163  __ CompareRoot(reg, Heap::kNullValueRootIndex);
2164  __ j(equal, instr->FalseLabel(chunk_));
2165  }
2166 
2167  if (expected.Contains(ToBooleanStub::SMI)) {
2168  // Smis: 0 -> false, all other -> true.
2169  __ Cmp(reg, Smi::FromInt(0));
2170  __ j(equal, instr->FalseLabel(chunk_));
2171  __ JumpIfSmi(reg, instr->TrueLabel(chunk_));
2172  } else if (expected.NeedsMap()) {
2173  // If we need a map later and have a Smi -> deopt.
2174  __ testb(reg, Immediate(kSmiTagMask));
2175  DeoptimizeIf(zero, instr, "Smi");
2176  }
2177 
2178  const Register map = kScratchRegister;
2179  if (expected.NeedsMap()) {
2181 
2182  if (expected.CanBeUndetectable()) {
2183  // Undetectable -> false.
2185  Immediate(1 << Map::kIsUndetectable));
2186  __ j(not_zero, instr->FalseLabel(chunk_));
2187  }
2188  }
2189 
2190  if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
2191  // spec object -> true.
2192  __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
2193  __ j(above_equal, instr->TrueLabel(chunk_));
2194  }
2195 
2196  if (expected.Contains(ToBooleanStub::STRING)) {
2197  // String value -> false iff empty.
2198  Label not_string;
2199  __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
2200  __ j(above_equal, &not_string, Label::kNear);
2201  __ cmpp(FieldOperand(reg, String::kLengthOffset), Immediate(0));
2202  __ j(not_zero, instr->TrueLabel(chunk_));
2203  __ jmp(instr->FalseLabel(chunk_));
2204  __ bind(&not_string);
2205  }
2206 
2207  if (expected.Contains(ToBooleanStub::SYMBOL)) {
2208  // Symbol value -> true.
2209  __ CmpInstanceType(map, SYMBOL_TYPE);
2210  __ j(equal, instr->TrueLabel(chunk_));
2211  }
2212 
2213  if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
2214  // heap number -> false iff +0, -0, or NaN.
2215  Label not_heap_number;
2216  __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
2217  __ j(not_equal, &not_heap_number, Label::kNear);
2218  XMMRegister xmm_scratch = double_scratch0();
2219  __ xorps(xmm_scratch, xmm_scratch);
2220  __ ucomisd(xmm_scratch, FieldOperand(reg, HeapNumber::kValueOffset));
2221  __ j(zero, instr->FalseLabel(chunk_));
2222  __ jmp(instr->TrueLabel(chunk_));
2223  __ bind(&not_heap_number);
2224  }
2225 
2226  if (!expected.IsGeneric()) {
2227  // We've seen something for the first time -> deopt.
2228  // This can only happen if we are not generic already.
2229  DeoptimizeIf(no_condition, instr, "unexpected object");
2230  }
2231  }
2232  }
2233 }
2234 
2235 
2236 void LCodeGen::EmitGoto(int block) {
2237  if (!IsNextEmittedBlock(block)) {
2238  __ jmp(chunk_->GetAssemblyLabel(chunk_->LookupDestination(block)));
2239  }
2240 }
2241 
2242 
2243 void LCodeGen::DoGoto(LGoto* instr) {
2244  EmitGoto(instr->block_id());
2245 }
2246 
2247 
2248 inline Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
2249  Condition cond = no_condition;
2250  switch (op) {
2251  case Token::EQ:
2252  case Token::EQ_STRICT:
2253  cond = equal;
2254  break;
2255  case Token::NE:
2256  case Token::NE_STRICT:
2257  cond = not_equal;
2258  break;
2259  case Token::LT:
2260  cond = is_unsigned ? below : less;
2261  break;
2262  case Token::GT:
2263  cond = is_unsigned ? above : greater;
2264  break;
2265  case Token::LTE:
2266  cond = is_unsigned ? below_equal : less_equal;
2267  break;
2268  case Token::GTE:
2269  cond = is_unsigned ? above_equal : greater_equal;
2270  break;
2271  case Token::IN:
2272  case Token::INSTANCEOF:
2273  default:
2274  UNREACHABLE();
2275  }
2276  return cond;
2277 }
2278 
2279 
2280 void LCodeGen::DoCompareNumericAndBranch(LCompareNumericAndBranch* instr) {
2281  LOperand* left = instr->left();
2282  LOperand* right = instr->right();
2283  bool is_unsigned =
2284  instr->is_double() ||
2285  instr->hydrogen()->left()->CheckFlag(HInstruction::kUint32) ||
2286  instr->hydrogen()->right()->CheckFlag(HInstruction::kUint32);
2287  Condition cc = TokenToCondition(instr->op(), is_unsigned);
2288 
2289  if (left->IsConstantOperand() && right->IsConstantOperand()) {
2290  // We can statically evaluate the comparison.
2291  double left_val = ToDouble(LConstantOperand::cast(left));
2292  double right_val = ToDouble(LConstantOperand::cast(right));
2293  int next_block = EvalComparison(instr->op(), left_val, right_val) ?
2294  instr->TrueDestination(chunk_) : instr->FalseDestination(chunk_);
2295  EmitGoto(next_block);
2296  } else {
2297  if (instr->is_double()) {
2298  // Don't base result on EFLAGS when a NaN is involved. Instead
2299  // jump to the false block.
2300  __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
2301  __ j(parity_even, instr->FalseLabel(chunk_));
2302  } else {
2303  int32_t value;
2304  if (right->IsConstantOperand()) {
2305  value = ToInteger32(LConstantOperand::cast(right));
2306  if (instr->hydrogen_value()->representation().IsSmi()) {
2307  __ Cmp(ToRegister(left), Smi::FromInt(value));
2308  } else {
2309  __ cmpl(ToRegister(left), Immediate(value));
2310  }
2311  } else if (left->IsConstantOperand()) {
2312  value = ToInteger32(LConstantOperand::cast(left));
2313  if (instr->hydrogen_value()->representation().IsSmi()) {
2314  if (right->IsRegister()) {
2315  __ Cmp(ToRegister(right), Smi::FromInt(value));
2316  } else {
2317  __ Cmp(ToOperand(right), Smi::FromInt(value));
2318  }
2319  } else if (right->IsRegister()) {
2320  __ cmpl(ToRegister(right), Immediate(value));
2321  } else {
2322  __ cmpl(ToOperand(right), Immediate(value));
2323  }
2324  // We commuted the operands, so commute the condition.
2325  cc = CommuteCondition(cc);
2326  } else if (instr->hydrogen_value()->representation().IsSmi()) {
2327  if (right->IsRegister()) {
2328  __ cmpp(ToRegister(left), ToRegister(right));
2329  } else {
2330  __ cmpp(ToRegister(left), ToOperand(right));
2331  }
2332  } else {
2333  if (right->IsRegister()) {
2334  __ cmpl(ToRegister(left), ToRegister(right));
2335  } else {
2336  __ cmpl(ToRegister(left), ToOperand(right));
2337  }
2338  }
2339  }
2340  EmitBranch(instr, cc);
2341  }
2342 }
2343 
2344 
2345 void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
2346  Register left = ToRegister(instr->left());
2347 
2348  if (instr->right()->IsConstantOperand()) {
2349  Handle<Object> right = ToHandle(LConstantOperand::cast(instr->right()));
2350  __ Cmp(left, right);
2351  } else {
2352  Register right = ToRegister(instr->right());
2353  __ cmpp(left, right);
2354  }
2355  EmitBranch(instr, equal);
2356 }
2357 
2358 
2359 void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) {
2360  if (instr->hydrogen()->representation().IsTagged()) {
2361  Register input_reg = ToRegister(instr->object());
2362  __ Cmp(input_reg, factory()->the_hole_value());
2363  EmitBranch(instr, equal);
2364  return;
2365  }
2366 
2367  XMMRegister input_reg = ToDoubleRegister(instr->object());
2368  __ ucomisd(input_reg, input_reg);
2369  EmitFalseBranch(instr, parity_odd);
2370 
2371  __ subp(rsp, Immediate(kDoubleSize));
2372  __ movsd(MemOperand(rsp, 0), input_reg);
2373  __ addp(rsp, Immediate(kDoubleSize));
2374 
2375  int offset = sizeof(kHoleNanUpper32);
2376  __ cmpl(MemOperand(rsp, -offset), Immediate(kHoleNanUpper32));
2377  EmitBranch(instr, equal);
2378 }
2379 
2380 
2381 void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
2382  Representation rep = instr->hydrogen()->value()->representation();
2383  DCHECK(!rep.IsInteger32());
2384 
2385  if (rep.IsDouble()) {
2386  XMMRegister value = ToDoubleRegister(instr->value());
2387  XMMRegister xmm_scratch = double_scratch0();
2388  __ xorps(xmm_scratch, xmm_scratch);
2389  __ ucomisd(xmm_scratch, value);
2390  EmitFalseBranch(instr, not_equal);
2391  __ movmskpd(kScratchRegister, value);
2392  __ testl(kScratchRegister, Immediate(1));
2393  EmitBranch(instr, not_zero);
2394  } else {
2395  Register value = ToRegister(instr->value());
2396  Handle<Map> map = masm()->isolate()->factory()->heap_number_map();
2397  __ CheckMap(value, map, instr->FalseLabel(chunk()), DO_SMI_CHECK);
2398  __ cmpl(FieldOperand(value, HeapNumber::kExponentOffset),
2399  Immediate(0x1));
2400  EmitFalseBranch(instr, no_overflow);
2401  __ cmpl(FieldOperand(value, HeapNumber::kMantissaOffset),
2402  Immediate(0x00000000));
2403  EmitBranch(instr, equal);
2404  }
2405 }
2406 
2407 
2408 Condition LCodeGen::EmitIsObject(Register input,
2409  Label* is_not_object,
2410  Label* is_object) {
2411  DCHECK(!input.is(kScratchRegister));
2412 
2413  __ JumpIfSmi(input, is_not_object);
2414 
2415  __ CompareRoot(input, Heap::kNullValueRootIndex);
2416  __ j(equal, is_object);
2417 
2419  // Undetectable objects behave like undefined.
2421  Immediate(1 << Map::kIsUndetectable));
2422  __ j(not_zero, is_not_object);
2423 
2424  __ movzxbl(kScratchRegister,
2427  __ j(below, is_not_object);
2429  return below_equal;
2430 }
2431 
2432 
2433 void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
2434  Register reg = ToRegister(instr->value());
2435 
2436  Condition true_cond = EmitIsObject(
2437  reg, instr->FalseLabel(chunk_), instr->TrueLabel(chunk_));
2438 
2439  EmitBranch(instr, true_cond);
2440 }
2441 
2442 
2443 Condition LCodeGen::EmitIsString(Register input,
2444  Register temp1,
2445  Label* is_not_string,
2446  SmiCheck check_needed = INLINE_SMI_CHECK) {
2447  if (check_needed == INLINE_SMI_CHECK) {
2448  __ JumpIfSmi(input, is_not_string);
2449  }
2450 
2451  Condition cond = masm_->IsObjectStringType(input, temp1, temp1);
2452 
2453  return cond;
2454 }
2455 
2456 
2457 void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
2458  Register reg = ToRegister(instr->value());
2459  Register temp = ToRegister(instr->temp());
2460 
2461  SmiCheck check_needed =
2462  instr->hydrogen()->value()->type().IsHeapObject()
2464 
2465  Condition true_cond = EmitIsString(
2466  reg, temp, instr->FalseLabel(chunk_), check_needed);
2467 
2468  EmitBranch(instr, true_cond);
2469 }
2470 
2471 
2472 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
2473  Condition is_smi;
2474  if (instr->value()->IsRegister()) {
2475  Register input = ToRegister(instr->value());
2476  is_smi = masm()->CheckSmi(input);
2477  } else {
2478  Operand input = ToOperand(instr->value());
2479  is_smi = masm()->CheckSmi(input);
2480  }
2481  EmitBranch(instr, is_smi);
2482 }
2483 
2484 
2485 void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
2486  Register input = ToRegister(instr->value());
2487  Register temp = ToRegister(instr->temp());
2488 
2489  if (!instr->hydrogen()->value()->type().IsHeapObject()) {
2490  __ JumpIfSmi(input, instr->FalseLabel(chunk_));
2491  }
2492  __ movp(temp, FieldOperand(input, HeapObject::kMapOffset));
2493  __ testb(FieldOperand(temp, Map::kBitFieldOffset),
2494  Immediate(1 << Map::kIsUndetectable));
2495  EmitBranch(instr, not_zero);
2496 }
2497 
2498 
2499 void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
2500  DCHECK(ToRegister(instr->context()).is(rsi));
2501  Token::Value op = instr->op();
2502 
2503  Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
2504  CallCode(ic, RelocInfo::CODE_TARGET, instr);
2505 
2506  Condition condition = TokenToCondition(op, false);
2507  __ testp(rax, rax);
2508 
2509  EmitBranch(instr, condition);
2510 }
2511 
2512 
2513 static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
2514  InstanceType from = instr->from();
2515  InstanceType to = instr->to();
2516  if (from == FIRST_TYPE) return to;
2517  DCHECK(from == to || to == LAST_TYPE);
2518  return from;
2519 }
2520 
2521 
2522 static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
2523  InstanceType from = instr->from();
2524  InstanceType to = instr->to();
2525  if (from == to) return equal;
2526  if (to == LAST_TYPE) return above_equal;
2527  if (from == FIRST_TYPE) return below_equal;
2528  UNREACHABLE();
2529  return equal;
2530 }
2531 
2532 
2533 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
2534  Register input = ToRegister(instr->value());
2535 
2536  if (!instr->hydrogen()->value()->type().IsHeapObject()) {
2537  __ JumpIfSmi(input, instr->FalseLabel(chunk_));
2538  }
2539 
2540  __ CmpObjectType(input, TestType(instr->hydrogen()), kScratchRegister);
2541  EmitBranch(instr, BranchCondition(instr->hydrogen()));
2542 }
2543 
2544 
2545 void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
2546  Register input = ToRegister(instr->value());
2547  Register result = ToRegister(instr->result());
2548 
2549  __ AssertString(input);
2550 
2551  __ movl(result, FieldOperand(input, String::kHashFieldOffset));
2553  __ IndexFromHash(result, result);
2554 }
2555 
2556 
2557 void LCodeGen::DoHasCachedArrayIndexAndBranch(
2558  LHasCachedArrayIndexAndBranch* instr) {
2559  Register input = ToRegister(instr->value());
2560 
2563  EmitBranch(instr, equal);
2564 }
2565 
2566 
2567 // Branches to a label or falls through with the answer in the z flag.
2568 // Trashes the temp register.
2569 void LCodeGen::EmitClassOfTest(Label* is_true,
2570  Label* is_false,
2571  Handle<String> class_name,
2572  Register input,
2573  Register temp,
2574  Register temp2) {
2575  DCHECK(!input.is(temp));
2576  DCHECK(!input.is(temp2));
2577  DCHECK(!temp.is(temp2));
2578 
2579  __ JumpIfSmi(input, is_false);
2580 
2581  if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
2582  // Assuming the following assertions, we can use the same compares to test
2583  // for both being a function type and being in the object type range.
2588  LAST_SPEC_OBJECT_TYPE - 1);
2590  __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
2591  __ j(below, is_false);
2592  __ j(equal, is_true);
2593  __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
2594  __ j(equal, is_true);
2595  } else {
2596  // Faster code path to avoid two compares: subtract lower bound from the
2597  // actual type and do a signed compare with the width of the type range.
2598  __ movp(temp, FieldOperand(input, HeapObject::kMapOffset));
2599  __ movzxbl(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
2600  __ subp(temp2, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
2601  __ cmpp(temp2, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
2603  __ j(above, is_false);
2604  }
2605 
2606  // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
2607  // Check if the constructor in the map is a function.
2608  __ movp(temp, FieldOperand(temp, Map::kConstructorOffset));
2609 
2610  // Objects with a non-function constructor have class 'Object'.
2611  __ CmpObjectType(temp, JS_FUNCTION_TYPE, kScratchRegister);
2612  if (String::Equals(class_name, isolate()->factory()->Object_string())) {
2613  __ j(not_equal, is_true);
2614  } else {
2615  __ j(not_equal, is_false);
2616  }
2617 
2618  // temp now contains the constructor function. Grab the
2619  // instance class name from there.
2621  __ movp(temp, FieldOperand(temp,
2623  // The class name we are testing against is internalized since it's a literal.
2624  // The name in the constructor is internalized because of the way the context
2625  // is booted. This routine isn't expected to work for random API-created
2626  // classes and it doesn't have to because you can't access it with natives
2627  // syntax. Since both sides are internalized it is sufficient to use an
2628  // identity comparison.
2629  DCHECK(class_name->IsInternalizedString());
2630  __ Cmp(temp, class_name);
2631  // End with the answer in the z flag.
2632 }
2633 
2634 
2635 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
2636  Register input = ToRegister(instr->value());
2637  Register temp = ToRegister(instr->temp());
2638  Register temp2 = ToRegister(instr->temp2());
2639  Handle<String> class_name = instr->hydrogen()->class_name();
2640 
2641  EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_),
2642  class_name, input, temp, temp2);
2643 
2644  EmitBranch(instr, equal);
2645 }
2646 
2647 
2648 void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
2649  Register reg = ToRegister(instr->value());
2650 
2651  __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
2652  EmitBranch(instr, equal);
2653 }
2654 
2655 
2656 void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
2657  DCHECK(ToRegister(instr->context()).is(rsi));
2658  InstanceofStub stub(isolate(), InstanceofStub::kNoFlags);
2659  __ Push(ToRegister(instr->left()));
2660  __ Push(ToRegister(instr->right()));
2661  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
2662  Label true_value, done;
2663  __ testp(rax, rax);
2664  __ j(zero, &true_value, Label::kNear);
2665  __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
2666  __ jmp(&done, Label::kNear);
2667  __ bind(&true_value);
2668  __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex);
2669  __ bind(&done);
2670 }
2671 
2672 
2673 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
2674  class DeferredInstanceOfKnownGlobal FINAL : public LDeferredCode {
2675  public:
2676  DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
2677  LInstanceOfKnownGlobal* instr)
2678  : LDeferredCode(codegen), instr_(instr) { }
2679  virtual void Generate() OVERRIDE {
2680  codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
2681  }
2682  virtual LInstruction* instr() OVERRIDE { return instr_; }
2683  Label* map_check() { return &map_check_; }
2684  private:
2685  LInstanceOfKnownGlobal* instr_;
2686  Label map_check_;
2687  };
2688 
2689  DCHECK(ToRegister(instr->context()).is(rsi));
2690  DeferredInstanceOfKnownGlobal* deferred;
2691  deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr);
2692 
2693  Label done, false_result;
2694  Register object = ToRegister(instr->value());
2695 
2696  // A Smi is not an instance of anything.
2697  __ JumpIfSmi(object, &false_result, Label::kNear);
2698 
2699  // This is the inlined call site instanceof cache. The two occurences of the
2700  // hole value will be patched to the last map/result pair generated by the
2701  // instanceof stub.
2702  Label cache_miss;
2703  // Use a temp register to avoid memory operands with variable lengths.
2704  Register map = ToRegister(instr->temp());
2705  __ movp(map, FieldOperand(object, HeapObject::kMapOffset));
2706  __ bind(deferred->map_check()); // Label for calculating code patching.
2707  Handle<Cell> cache_cell = factory()->NewCell(factory()->the_hole_value());
2708  __ Move(kScratchRegister, cache_cell, RelocInfo::CELL);
2709  __ cmpp(map, Operand(kScratchRegister, 0));
2710  __ j(not_equal, &cache_miss, Label::kNear);
2711  // Patched to load either true or false.
2712  __ LoadRoot(ToRegister(instr->result()), Heap::kTheHoleValueRootIndex);
2713 #ifdef DEBUG
2714  // Check that the code size between patch label and patch sites is invariant.
2715  Label end_of_patched_code;
2716  __ bind(&end_of_patched_code);
2717  DCHECK(true);
2718 #endif
2719  __ jmp(&done, Label::kNear);
2720 
2721  // The inlined call site cache did not match. Check for null and string
2722  // before calling the deferred code.
2723  __ bind(&cache_miss); // Null is not an instance of anything.
2724  __ CompareRoot(object, Heap::kNullValueRootIndex);
2725  __ j(equal, &false_result, Label::kNear);
2726 
2727  // String values are not instances of anything.
2728  __ JumpIfNotString(object, kScratchRegister, deferred->entry());
2729 
2730  __ bind(&false_result);
2731  __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
2732 
2733  __ bind(deferred->exit());
2734  __ bind(&done);
2735 }
2736 
2737 
2738 void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
2739  Label* map_check) {
2740  {
2741  PushSafepointRegistersScope scope(this);
2744  InstanceofStub stub(isolate(), flags);
2745 
2746  __ Push(ToRegister(instr->value()));
2747  __ Push(instr->function());
2748 
2749  static const int kAdditionalDelta = kPointerSize == kInt64Size ? 10 : 16;
2750  int delta =
2751  masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
2752  DCHECK(delta >= 0);
2753  __ PushImm32(delta);
2754 
2755  // We are pushing three values on the stack but recording a
2756  // safepoint with two arguments because stub is going to
2757  // remove the third argument from the stack before jumping
2758  // to instanceof builtin on the slow path.
2759  CallCodeGeneric(stub.GetCode(),
2761  instr,
2763  2);
2764  DCHECK(delta == masm_->SizeOfCodeGeneratedSince(map_check));
2765  LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
2766  safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
2767  // Move result to a register that survives the end of the
2768  // PushSafepointRegisterScope.
2769  __ movp(kScratchRegister, rax);
2770  }
2772  Label load_false;
2773  Label done;
2774  __ j(not_zero, &load_false, Label::kNear);
2775  __ LoadRoot(rax, Heap::kTrueValueRootIndex);
2776  __ jmp(&done, Label::kNear);
2777  __ bind(&load_false);
2778  __ LoadRoot(rax, Heap::kFalseValueRootIndex);
2779  __ bind(&done);
2780 }
2781 
2782 
2783 void LCodeGen::DoCmpT(LCmpT* instr) {
2784  DCHECK(ToRegister(instr->context()).is(rsi));
2785  Token::Value op = instr->op();
2786 
2787  Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
2788  CallCode(ic, RelocInfo::CODE_TARGET, instr);
2789 
2790  Condition condition = TokenToCondition(op, false);
2791  Label true_value, done;
2792  __ testp(rax, rax);
2793  __ j(condition, &true_value, Label::kNear);
2794  __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
2795  __ jmp(&done, Label::kNear);
2796  __ bind(&true_value);
2797  __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex);
2798  __ bind(&done);
2799 }
2800 
2801 
2802 void LCodeGen::DoReturn(LReturn* instr) {
2803  if (FLAG_trace && info()->IsOptimizing()) {
2804  // Preserve the return value on the stack and rely on the runtime call
2805  // to return the value in the same register. We're leaving the code
2806  // managed by the register allocator and tearing down the frame, it's
2807  // safe to write to the context register.
2808  __ Push(rax);
2810  __ CallRuntime(Runtime::kTraceExit, 1);
2811  }
2812  if (info()->saves_caller_doubles()) {
2814  }
2815  int no_frame_start = -1;
2816  if (NeedsEagerFrame()) {
2817  __ movp(rsp, rbp);
2818  __ popq(rbp);
2819  no_frame_start = masm_->pc_offset();
2820  }
2821  if (instr->has_constant_parameter_count()) {
2822  __ Ret((ToInteger32(instr->constant_parameter_count()) + 1) * kPointerSize,
2823  rcx);
2824  } else {
2825  Register reg = ToRegister(instr->parameter_count());
2826  // The argument count parameter is a smi
2827  __ SmiToInteger32(reg, reg);
2828  Register return_addr_reg = reg.is(rcx) ? rbx : rcx;
2829  __ PopReturnAddressTo(return_addr_reg);
2830  __ shlp(reg, Immediate(kPointerSizeLog2));
2831  __ addp(rsp, reg);
2832  __ jmp(return_addr_reg);
2833  }
2834  if (no_frame_start != -1) {
2835  info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
2836  }
2837 }
2838 
2839 
2840 void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
2841  Register result = ToRegister(instr->result());
2842  __ LoadGlobalCell(result, instr->hydrogen()->cell().handle());
2843  if (instr->hydrogen()->RequiresHoleCheck()) {
2844  __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
2845  DeoptimizeIf(equal, instr, "hole");
2846  }
2847 }
2848 
2849 
2850 template <class T>
2852  DCHECK(FLAG_vector_ics);
2853  Register vector = ToRegister(instr->temp_vector());
2855  __ Move(vector, instr->hydrogen()->feedback_vector());
2856  // No need to allocate this register.
2859  Smi::FromInt(instr->hydrogen()->slot()));
2860 }
2861 
2862 
2863 void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
2864  DCHECK(ToRegister(instr->context()).is(rsi));
2865  DCHECK(ToRegister(instr->global_object())
2867  DCHECK(ToRegister(instr->result()).is(rax));
2868 
2869  __ Move(LoadDescriptor::NameRegister(), instr->name());
2870  if (FLAG_vector_ics) {
2871  EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr);
2872  }
2873  ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL;
2874  Handle<Code> ic = CodeFactory::LoadIC(isolate(), mode).code();
2875  CallCode(ic, RelocInfo::CODE_TARGET, instr);
2876 }
2877 
2878 
2879 void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
2880  Register value = ToRegister(instr->value());
2881  Handle<Cell> cell_handle = instr->hydrogen()->cell().handle();
2882 
2883  // If the cell we are storing to contains the hole it could have
2884  // been deleted from the property dictionary. In that case, we need
2885  // to update the property details in the property dictionary to mark
2886  // it as no longer deleted. We deoptimize in that case.
2887  if (instr->hydrogen()->RequiresHoleCheck()) {
2888  // We have a temp because CompareRoot might clobber kScratchRegister.
2889  Register cell = ToRegister(instr->temp());
2890  DCHECK(!value.is(cell));
2891  __ Move(cell, cell_handle, RelocInfo::CELL);
2892  __ CompareRoot(Operand(cell, 0), Heap::kTheHoleValueRootIndex);
2893  DeoptimizeIf(equal, instr, "hole");
2894  // Store the value.
2895  __ movp(Operand(cell, 0), value);
2896  } else {
2897  // Store the value.
2898  __ Move(kScratchRegister, cell_handle, RelocInfo::CELL);
2899  __ movp(Operand(kScratchRegister, 0), value);
2900  }
2901  // Cells are always rescanned, so no write barrier here.
2902 }
2903 
2904 
2905 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
2906  Register context = ToRegister(instr->context());
2907  Register result = ToRegister(instr->result());
2908  __ movp(result, ContextOperand(context, instr->slot_index()));
2909  if (instr->hydrogen()->RequiresHoleCheck()) {
2910  __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
2911  if (instr->hydrogen()->DeoptimizesOnHole()) {
2912  DeoptimizeIf(equal, instr, "hole");
2913  } else {
2914  Label is_not_hole;
2915  __ j(not_equal, &is_not_hole, Label::kNear);
2916  __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
2917  __ bind(&is_not_hole);
2918  }
2919  }
2920 }
2921 
2922 
2923 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2924  Register context = ToRegister(instr->context());
2925  Register value = ToRegister(instr->value());
2926 
2927  Operand target = ContextOperand(context, instr->slot_index());
2928 
2929  Label skip_assignment;
2930  if (instr->hydrogen()->RequiresHoleCheck()) {
2931  __ CompareRoot(target, Heap::kTheHoleValueRootIndex);
2932  if (instr->hydrogen()->DeoptimizesOnHole()) {
2933  DeoptimizeIf(equal, instr, "hole");
2934  } else {
2935  __ j(not_equal, &skip_assignment);
2936  }
2937  }
2938  __ movp(target, value);
2939 
2940  if (instr->hydrogen()->NeedsWriteBarrier()) {
2941  SmiCheck check_needed =
2942  instr->hydrogen()->value()->type().IsHeapObject()
2944  int offset = Context::SlotOffset(instr->slot_index());
2945  Register scratch = ToRegister(instr->temp());
2946  __ RecordWriteContextSlot(context,
2947  offset,
2948  value,
2949  scratch,
2950  kSaveFPRegs,
2952  check_needed);
2953  }
2954 
2955  __ bind(&skip_assignment);
2956 }
2957 
2958 
2959 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
2960  HObjectAccess access = instr->hydrogen()->access();
2961  int offset = access.offset();
2962 
2963  if (access.IsExternalMemory()) {
2964  Register result = ToRegister(instr->result());
2965  if (instr->object()->IsConstantOperand()) {
2966  DCHECK(result.is(rax));
2967  __ load_rax(ToExternalReference(LConstantOperand::cast(instr->object())));
2968  } else {
2969  Register object = ToRegister(instr->object());
2970  __ Load(result, MemOperand(object, offset), access.representation());
2971  }
2972  return;
2973  }
2974 
2975  Register object = ToRegister(instr->object());
2976  if (instr->hydrogen()->representation().IsDouble()) {
2977  XMMRegister result = ToDoubleRegister(instr->result());
2978  __ movsd(result, FieldOperand(object, offset));
2979  return;
2980  }
2981 
2982  Register result = ToRegister(instr->result());
2983  if (!access.IsInobject()) {
2984  __ movp(result, FieldOperand(object, JSObject::kPropertiesOffset));
2985  object = result;
2986  }
2987 
2988  Representation representation = access.representation();
2989  if (representation.IsSmi() && SmiValuesAre32Bits() &&
2990  instr->hydrogen()->representation().IsInteger32()) {
2991  if (FLAG_debug_code) {
2992  Register scratch = kScratchRegister;
2993  __ Load(scratch, FieldOperand(object, offset), representation);
2994  __ AssertSmi(scratch);
2995  }
2996 
2997  // Read int value directly from upper half of the smi.
2998  STATIC_ASSERT(kSmiTag == 0);
2999  DCHECK(kSmiTagSize + kSmiShiftSize == 32);
3000  offset += kPointerSize / 2;
3001  representation = Representation::Integer32();
3002  }
3003  __ Load(result, FieldOperand(object, offset), representation);
3004 }
3005 
3006 
3007 void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
3008  DCHECK(ToRegister(instr->context()).is(rsi));
3010  DCHECK(ToRegister(instr->result()).is(rax));
3011 
3012  __ Move(LoadDescriptor::NameRegister(), instr->name());
3013  if (FLAG_vector_ics) {
3014  EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr);
3015  }
3016  Handle<Code> ic = CodeFactory::LoadIC(isolate(), NOT_CONTEXTUAL).code();
3017  CallCode(ic, RelocInfo::CODE_TARGET, instr);
3018 }
3019 
3020 
3021 void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
3022  Register function = ToRegister(instr->function());
3023  Register result = ToRegister(instr->result());
3024 
3025  // Get the prototype or initial map from the function.
3026  __ movp(result,
3028 
3029  // Check that the function has a prototype or an initial map.
3030  __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
3031  DeoptimizeIf(equal, instr, "hole");
3032 
3033  // If the function does not have an initial map, we're done.
3034  Label done;
3035  __ CmpObjectType(result, MAP_TYPE, kScratchRegister);
3036  __ j(not_equal, &done, Label::kNear);
3037 
3038  // Get the prototype from the initial map.
3039  __ movp(result, FieldOperand(result, Map::kPrototypeOffset));
3040 
3041  // All done.
3042  __ bind(&done);
3043 }
3044 
3045 
3046 void LCodeGen::DoLoadRoot(LLoadRoot* instr) {
3047  Register result = ToRegister(instr->result());
3048  __ LoadRoot(result, instr->index());
3049 }
3050 
3051 
3052 void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
3053  Register arguments = ToRegister(instr->arguments());
3054  Register result = ToRegister(instr->result());
3055 
3056  if (instr->length()->IsConstantOperand() &&
3057  instr->index()->IsConstantOperand()) {
3058  int32_t const_index = ToInteger32(LConstantOperand::cast(instr->index()));
3059  int32_t const_length = ToInteger32(LConstantOperand::cast(instr->length()));
3060  if (const_index >= 0 && const_index < const_length) {
3061  StackArgumentsAccessor args(arguments, const_length,
3063  __ movp(result, args.GetArgumentOperand(const_index));
3064  } else if (FLAG_debug_code) {
3065  __ int3();
3066  }
3067  } else {
3068  Register length = ToRegister(instr->length());
3069  // There are two words between the frame pointer and the last argument.
3070  // Subtracting from length accounts for one of them add one more.
3071  if (instr->index()->IsRegister()) {
3072  __ subl(length, ToRegister(instr->index()));
3073  } else {
3074  __ subl(length, ToOperand(instr->index()));
3075  }
3076  StackArgumentsAccessor args(arguments, length,
3078  __ movp(result, args.GetArgumentOperand(0));
3079  }
3080 }
3081 
3082 
3083 void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
3084  ElementsKind elements_kind = instr->elements_kind();
3085  LOperand* key = instr->key();
3086  if (kPointerSize == kInt32Size && !key->IsConstantOperand()) {
3087  Register key_reg = ToRegister(key);
3088  Representation key_representation =
3089  instr->hydrogen()->key()->representation();
3090  if (ExternalArrayOpRequiresTemp(key_representation, elements_kind)) {
3091  __ SmiToInteger64(key_reg, key_reg);
3092  } else if (instr->hydrogen()->IsDehoisted()) {
3093  // Sign extend key because it could be a 32 bit negative value
3094  // and the dehoisted address computation happens in 64 bits
3095  __ movsxlq(key_reg, key_reg);
3096  }
3097  }
3098  Operand operand(BuildFastArrayOperand(
3099  instr->elements(),
3100  key,
3101  instr->hydrogen()->key()->representation(),
3102  elements_kind,
3103  instr->base_offset()));
3104 
3105  if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
3106  elements_kind == FLOAT32_ELEMENTS) {
3107  XMMRegister result(ToDoubleRegister(instr->result()));
3108  __ movss(result, operand);
3109  __ cvtss2sd(result, result);
3110  } else if (elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
3111  elements_kind == FLOAT64_ELEMENTS) {
3112  __ movsd(ToDoubleRegister(instr->result()), operand);
3113  } else {
3114  Register result(ToRegister(instr->result()));
3115  switch (elements_kind) {
3117  case INT8_ELEMENTS:
3118  __ movsxbl(result, operand);
3119  break;
3122  case UINT8_ELEMENTS:
3124  __ movzxbl(result, operand);
3125  break;
3127  case INT16_ELEMENTS:
3128  __ movsxwl(result, operand);
3129  break;
3131  case UINT16_ELEMENTS:
3132  __ movzxwl(result, operand);
3133  break;
3135  case INT32_ELEMENTS:
3136  __ movl(result, operand);
3137  break;
3139  case UINT32_ELEMENTS:
3140  __ movl(result, operand);
3141  if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
3142  __ testl(result, result);
3143  DeoptimizeIf(negative, instr, "negative value");
3144  }
3145  break;
3148  case FLOAT32_ELEMENTS:
3149  case FLOAT64_ELEMENTS:
3150  case FAST_ELEMENTS:
3151  case FAST_SMI_ELEMENTS:
3152  case FAST_DOUBLE_ELEMENTS:
3153  case FAST_HOLEY_ELEMENTS:
3156  case DICTIONARY_ELEMENTS:
3158  UNREACHABLE();
3159  break;
3160  }
3161  }
3162 }
3163 
3164 
3165 void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
3166  XMMRegister result(ToDoubleRegister(instr->result()));
3167  LOperand* key = instr->key();
3168  if (kPointerSize == kInt32Size && !key->IsConstantOperand() &&
3169  instr->hydrogen()->IsDehoisted()) {
3170  // Sign extend key because it could be a 32 bit negative value
3171  // and the dehoisted address computation happens in 64 bits
3172  __ movsxlq(ToRegister(key), ToRegister(key));
3173  }
3174  if (instr->hydrogen()->RequiresHoleCheck()) {
3175  Operand hole_check_operand = BuildFastArrayOperand(
3176  instr->elements(),
3177  key,
3178  instr->hydrogen()->key()->representation(),
3180  instr->base_offset() + sizeof(kHoleNanLower32));
3181  __ cmpl(hole_check_operand, Immediate(kHoleNanUpper32));
3182  DeoptimizeIf(equal, instr, "hole");
3183  }
3184 
3185  Operand double_load_operand = BuildFastArrayOperand(
3186  instr->elements(),
3187  key,
3188  instr->hydrogen()->key()->representation(),
3190  instr->base_offset());
3191  __ movsd(result, double_load_operand);
3192 }
3193 
3194 
3195 void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
3196  HLoadKeyed* hinstr = instr->hydrogen();
3197  Register result = ToRegister(instr->result());
3198  LOperand* key = instr->key();
3199  bool requires_hole_check = hinstr->RequiresHoleCheck();
3200  Representation representation = hinstr->representation();
3201  int offset = instr->base_offset();
3202 
3203  if (kPointerSize == kInt32Size && !key->IsConstantOperand() &&
3204  instr->hydrogen()->IsDehoisted()) {
3205  // Sign extend key because it could be a 32 bit negative value
3206  // and the dehoisted address computation happens in 64 bits
3207  __ movsxlq(ToRegister(key), ToRegister(key));
3208  }
3209  if (representation.IsInteger32() && SmiValuesAre32Bits() &&
3210  hinstr->elements_kind() == FAST_SMI_ELEMENTS) {
3211  DCHECK(!requires_hole_check);
3212  if (FLAG_debug_code) {
3213  Register scratch = kScratchRegister;
3214  __ Load(scratch,
3215  BuildFastArrayOperand(instr->elements(),
3216  key,
3217  instr->hydrogen()->key()->representation(),
3218  FAST_ELEMENTS,
3219  offset),
3221  __ AssertSmi(scratch);
3222  }
3223  // Read int value directly from upper half of the smi.
3224  STATIC_ASSERT(kSmiTag == 0);
3225  DCHECK(kSmiTagSize + kSmiShiftSize == 32);
3226  offset += kPointerSize / 2;
3227  }
3228 
3229  __ Load(result,
3230  BuildFastArrayOperand(instr->elements(), key,
3231  instr->hydrogen()->key()->representation(),
3232  FAST_ELEMENTS, offset),
3233  representation);
3234 
3235  // Check for the hole value.
3236  if (requires_hole_check) {
3237  if (IsFastSmiElementsKind(hinstr->elements_kind())) {
3238  Condition smi = __ CheckSmi(result);
3239  DeoptimizeIf(NegateCondition(smi), instr, "not a Smi");
3240  } else {
3241  __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
3242  DeoptimizeIf(equal, instr, "hole");
3243  }
3244  }
3245 }
3246 
3247 
3248 void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
3249  if (instr->is_typed_elements()) {
3250  DoLoadKeyedExternalArray(instr);
3251  } else if (instr->hydrogen()->representation().IsDouble()) {
3253  } else {
3254  DoLoadKeyedFixedArray(instr);
3255  }
3256 }
3257 
3258 
3260  LOperand* elements_pointer,
3261  LOperand* key,
3262  Representation key_representation,
3263  ElementsKind elements_kind,
3264  uint32_t offset) {
3265  Register elements_pointer_reg = ToRegister(elements_pointer);
3266  int shift_size = ElementsKindToShiftSize(elements_kind);
3267  if (key->IsConstantOperand()) {
3268  int32_t constant_value = ToInteger32(LConstantOperand::cast(key));
3269  if (constant_value & 0xF0000000) {
3270  Abort(kArrayIndexConstantValueTooBig);
3271  }
3272  return Operand(elements_pointer_reg,
3273  (constant_value << shift_size) + offset);
3274  } else {
3275  // Take the tag bit into account while computing the shift size.
3276  if (key_representation.IsSmi() && (shift_size >= 1)) {
3278  shift_size -= kSmiTagSize;
3279  }
3280  ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
3281  return Operand(elements_pointer_reg,
3282  ToRegister(key),
3283  scale_factor,
3284  offset);
3285  }
3286 }
3287 
3288 
3289 void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
3290  DCHECK(ToRegister(instr->context()).is(rsi));
3293 
3294  if (FLAG_vector_ics) {
3295  EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr);
3296  }
3297 
3298  Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
3299  CallCode(ic, RelocInfo::CODE_TARGET, instr);
3300 }
3301 
3302 
3303 void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
3304  Register result = ToRegister(instr->result());
3305 
3306  if (instr->hydrogen()->from_inlined()) {
3307  __ leap(result, Operand(rsp, -kFPOnStackSize + -kPCOnStackSize));
3308  } else {
3309  // Check for arguments adapter frame.
3310  Label done, adapted;
3311  __ movp(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
3312  __ Cmp(Operand(result, StandardFrameConstants::kContextOffset),
3314  __ j(equal, &adapted, Label::kNear);
3315 
3316  // No arguments adaptor frame.
3317  __ movp(result, rbp);
3318  __ jmp(&done, Label::kNear);
3319 
3320  // Arguments adaptor frame present.
3321  __ bind(&adapted);
3322  __ movp(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
3323 
3324  // Result is the frame pointer for the frame if not adapted and for the real
3325  // frame below the adaptor frame if adapted.
3326  __ bind(&done);
3327  }
3328 }
3329 
3330 
3331 void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
3332  Register result = ToRegister(instr->result());
3333 
3334  Label done;
3335 
3336  // If no arguments adaptor frame the number of arguments is fixed.
3337  if (instr->elements()->IsRegister()) {
3338  __ cmpp(rbp, ToRegister(instr->elements()));
3339  } else {
3340  __ cmpp(rbp, ToOperand(instr->elements()));
3341  }
3342  __ movl(result, Immediate(scope()->num_parameters()));
3343  __ j(equal, &done, Label::kNear);
3344 
3345  // Arguments adaptor frame present. Get argument length from there.
3346  __ movp(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
3347  __ SmiToInteger32(result,
3348  Operand(result,
3350 
3351  // Argument length is in result register.
3352  __ bind(&done);
3353 }
3354 
3355 
3356 void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
3357  Register receiver = ToRegister(instr->receiver());
3358  Register function = ToRegister(instr->function());
3359 
3360  // If the receiver is null or undefined, we have to pass the global
3361  // object as a receiver to normal functions. Values have to be
3362  // passed unchanged to builtins and strict-mode functions.
3363  Label global_object, receiver_ok;
3364  Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear;
3365 
3366  if (!instr->hydrogen()->known_function()) {
3367  // Do not transform the receiver to object for strict mode
3368  // functions.
3369  __ movp(kScratchRegister,
3372  SharedFunctionInfo::kStrictModeByteOffset),
3374  __ j(not_equal, &receiver_ok, dist);
3375 
3376  // Do not transform the receiver to object for builtins.
3378  SharedFunctionInfo::kNativeByteOffset),
3380  __ j(not_equal, &receiver_ok, dist);
3381  }
3382 
3383  // Normal function. Replace undefined or null with global receiver.
3384  __ CompareRoot(receiver, Heap::kNullValueRootIndex);
3385  __ j(equal, &global_object, Label::kNear);
3386  __ CompareRoot(receiver, Heap::kUndefinedValueRootIndex);
3387  __ j(equal, &global_object, Label::kNear);
3388 
3389  // The receiver should be a JS object.
3390  Condition is_smi = __ CheckSmi(receiver);
3391  DeoptimizeIf(is_smi, instr, "Smi");
3392  __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, kScratchRegister);
3393  DeoptimizeIf(below, instr, "not a JavaScript object");
3394 
3395  __ jmp(&receiver_ok, Label::kNear);
3396  __ bind(&global_object);
3397  __ movp(receiver, FieldOperand(function, JSFunction::kContextOffset));
3398  __ movp(receiver,
3399  Operand(receiver,
3401  __ movp(receiver, FieldOperand(receiver, GlobalObject::kGlobalProxyOffset));
3402 
3403  __ bind(&receiver_ok);
3404 }
3405 
3406 
3407 void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
3408  Register receiver = ToRegister(instr->receiver());
3409  Register function = ToRegister(instr->function());
3410  Register length = ToRegister(instr->length());
3411  Register elements = ToRegister(instr->elements());
3412  DCHECK(receiver.is(rax)); // Used for parameter count.
3413  DCHECK(function.is(rdi)); // Required by InvokeFunction.
3414  DCHECK(ToRegister(instr->result()).is(rax));
3415 
3416  // Copy the arguments to this function possibly from the
3417  // adaptor frame below it.
3418  const uint32_t kArgumentsLimit = 1 * KB;
3419  __ cmpp(length, Immediate(kArgumentsLimit));
3420  DeoptimizeIf(above, instr, "too many arguments");
3421 
3422  __ Push(receiver);
3423  __ movp(receiver, length);
3424 
3425  // Loop through the arguments pushing them onto the execution
3426  // stack.
3427  Label invoke, loop;
3428  // length is a small non-negative integer, due to the test above.
3429  __ testl(length, length);
3430  __ j(zero, &invoke, Label::kNear);
3431  __ bind(&loop);
3432  StackArgumentsAccessor args(elements, length,
3434  __ Push(args.GetArgumentOperand(0));
3435  __ decl(length);
3436  __ j(not_zero, &loop);
3437 
3438  // Invoke the function.
3439  __ bind(&invoke);
3440  DCHECK(instr->HasPointerMap());
3441  LPointerMap* pointers = instr->pointer_map();
3442  SafepointGenerator safepoint_generator(
3443  this, pointers, Safepoint::kLazyDeopt);
3444  ParameterCount actual(rax);
3445  __ InvokeFunction(function, actual, CALL_FUNCTION, safepoint_generator);
3446 }
3447 
3448 
3449 void LCodeGen::DoPushArgument(LPushArgument* instr) {
3450  LOperand* argument = instr->value();
3451  EmitPushTaggedOperand(argument);
3452 }
3453 
3454 
3455 void LCodeGen::DoDrop(LDrop* instr) {
3456  __ Drop(instr->count());
3457 }
3458 
3459 
3460 void LCodeGen::DoThisFunction(LThisFunction* instr) {
3461  Register result = ToRegister(instr->result());
3462  __ movp(result, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
3463 }
3464 
3465 
3466 void LCodeGen::DoContext(LContext* instr) {
3467  Register result = ToRegister(instr->result());
3468  if (info()->IsOptimizing()) {
3469  __ movp(result, Operand(rbp, StandardFrameConstants::kContextOffset));
3470  } else {
3471  // If there is no frame, the context must be in rsi.
3472  DCHECK(result.is(rsi));
3473  }
3474 }
3475 
3476 
3477 void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
3478  DCHECK(ToRegister(instr->context()).is(rsi));
3479  __ Push(rsi); // The context is the first argument.
3480  __ Push(instr->hydrogen()->pairs());
3481  __ Push(Smi::FromInt(instr->hydrogen()->flags()));
3482  CallRuntime(Runtime::kDeclareGlobals, 3, instr);
3483 }
3484 
3485 
3486 void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
3487  int formal_parameter_count,
3488  int arity,
3489  LInstruction* instr,
3490  RDIState rdi_state) {
3491  bool dont_adapt_arguments =
3492  formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel;
3493  bool can_invoke_directly =
3494  dont_adapt_arguments || formal_parameter_count == arity;
3495 
3496  LPointerMap* pointers = instr->pointer_map();
3497 
3498  if (can_invoke_directly) {
3499  if (rdi_state == RDI_UNINITIALIZED) {
3500  __ Move(rdi, function);
3501  }
3502 
3503  // Change context.
3505 
3506  // Set rax to arguments count if adaption is not needed. Assumes that rax
3507  // is available to write to at this point.
3508  if (dont_adapt_arguments) {
3509  __ Set(rax, arity);
3510  }
3511 
3512  // Invoke function.
3513  if (function.is_identical_to(info()->closure())) {
3514  __ CallSelf();
3515  } else {
3517  }
3518 
3519  // Set up deoptimization.
3521  } else {
3522  // We need to adapt arguments.
3523  SafepointGenerator generator(
3524  this, pointers, Safepoint::kLazyDeopt);
3525  ParameterCount count(arity);
3526  ParameterCount expected(formal_parameter_count);
3527  __ InvokeFunction(function, expected, count, CALL_FUNCTION, generator);
3528  }
3529 }
3530 
3531 
3532 void LCodeGen::DoTailCallThroughMegamorphicCache(
3533  LTailCallThroughMegamorphicCache* instr) {
3534  Register receiver = ToRegister(instr->receiver());
3535  Register name = ToRegister(instr->name());
3536  DCHECK(receiver.is(LoadDescriptor::ReceiverRegister()));
3538 
3539  Register scratch = rbx;
3540  DCHECK(!scratch.is(receiver) && !scratch.is(name));
3541 
3542  // Important for the tail-call.
3543  bool must_teardown_frame = NeedsEagerFrame();
3544 
3545  // The probe will tail call to a handler if found.
3546  isolate()->stub_cache()->GenerateProbe(masm(), instr->hydrogen()->flags(),
3547  must_teardown_frame, receiver, name,
3548  scratch, no_reg);
3549 
3550  // Tail call to miss if we ended up here.
3551  if (must_teardown_frame) __ leave();
3552  LoadIC::GenerateMiss(masm());
3553 }
3554 
3555 
3556 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
3557  DCHECK(ToRegister(instr->result()).is(rax));
3558 
3559  LPointerMap* pointers = instr->pointer_map();
3560  SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
3561 
3562  if (instr->target()->IsConstantOperand()) {
3563  LConstantOperand* target = LConstantOperand::cast(instr->target());
3564  Handle<Code> code = Handle<Code>::cast(ToHandle(target));
3565  generator.BeforeCall(__ CallSize(code));
3566  __ call(code, RelocInfo::CODE_TARGET);
3567  } else {
3568  DCHECK(instr->target()->IsRegister());
3569  Register target = ToRegister(instr->target());
3570  generator.BeforeCall(__ CallSize(target));
3571  __ addp(target, Immediate(Code::kHeaderSize - kHeapObjectTag));
3572  __ call(target);
3573  }
3574  generator.AfterCall();
3575 }
3576 
3577 
3578 void LCodeGen::DoCallJSFunction(LCallJSFunction* instr) {
3579  DCHECK(ToRegister(instr->function()).is(rdi));
3580  DCHECK(ToRegister(instr->result()).is(rax));
3581 
3582  if (instr->hydrogen()->pass_argument_count()) {
3583  __ Set(rax, instr->arity());
3584  }
3585 
3586  // Change context.
3588 
3589  LPointerMap* pointers = instr->pointer_map();
3590  SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
3591 
3592  bool is_self_call = false;
3593  if (instr->hydrogen()->function()->IsConstant()) {
3594  Handle<JSFunction> jsfun = Handle<JSFunction>::null();
3595  HConstant* fun_const = HConstant::cast(instr->hydrogen()->function());
3596  jsfun = Handle<JSFunction>::cast(fun_const->handle(isolate()));
3597  is_self_call = jsfun.is_identical_to(info()->closure());
3598  }
3599 
3600  if (is_self_call) {
3601  __ CallSelf();
3602  } else {
3603  Operand target = FieldOperand(rdi, JSFunction::kCodeEntryOffset);
3604  generator.BeforeCall(__ CallSize(target));
3605  __ Call(target);
3606  }
3607  generator.AfterCall();
3608 }
3609 
3610 
3611 void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
3612  Register input_reg = ToRegister(instr->value());
3613  __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
3614  Heap::kHeapNumberMapRootIndex);
3615  DeoptimizeIf(not_equal, instr, "not a heap number");
3616 
3617  Label slow, allocated, done;
3618  Register tmp = input_reg.is(rax) ? rcx : rax;
3619  Register tmp2 = tmp.is(rcx) ? rdx : input_reg.is(rcx) ? rdx : rcx;
3620 
3621  // Preserve the value of all registers.
3622  PushSafepointRegistersScope scope(this);
3623 
3624  __ movl(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
3625  // Check the sign of the argument. If the argument is positive, just
3626  // return it. We do not need to patch the stack since |input| and
3627  // |result| are the same register and |input| will be restored
3628  // unchanged by popping safepoint registers.
3629  __ testl(tmp, Immediate(HeapNumber::kSignMask));
3630  __ j(zero, &done);
3631 
3632  __ AllocateHeapNumber(tmp, tmp2, &slow);
3633  __ jmp(&allocated, Label::kNear);
3634 
3635  // Slow case: Call the runtime system to do the number allocation.
3636  __ bind(&slow);
3638  Runtime::kAllocateHeapNumber, 0, instr, instr->context());
3639  // Set the pointer to the new heap number in tmp.
3640  if (!tmp.is(rax)) __ movp(tmp, rax);
3641  // Restore input_reg after call to runtime.
3642  __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
3643 
3644  __ bind(&allocated);
3645  __ movq(tmp2, FieldOperand(input_reg, HeapNumber::kValueOffset));
3646  __ shlq(tmp2, Immediate(1));
3647  __ shrq(tmp2, Immediate(1));
3648  __ movq(FieldOperand(tmp, HeapNumber::kValueOffset), tmp2);
3649  __ StoreToSafepointRegisterSlot(input_reg, tmp);
3650 
3651  __ bind(&done);
3652 }
3653 
3654 
3655 void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) {
3656  Register input_reg = ToRegister(instr->value());
3657  __ testl(input_reg, input_reg);
3658  Label is_positive;
3659  __ j(not_sign, &is_positive, Label::kNear);
3660  __ negl(input_reg); // Sets flags.
3661  DeoptimizeIf(negative, instr, "overflow");
3662  __ bind(&is_positive);
3663 }
3664 
3665 
3666 void LCodeGen::EmitSmiMathAbs(LMathAbs* instr) {
3667  Register input_reg = ToRegister(instr->value());
3668  __ testp(input_reg, input_reg);
3669  Label is_positive;
3670  __ j(not_sign, &is_positive, Label::kNear);
3671  __ negp(input_reg); // Sets flags.
3672  DeoptimizeIf(negative, instr, "overflow");
3673  __ bind(&is_positive);
3674 }
3675 
3676 
3677 void LCodeGen::DoMathAbs(LMathAbs* instr) {
3678  // Class for deferred case.
3679  class DeferredMathAbsTaggedHeapNumber FINAL : public LDeferredCode {
3680  public:
3681  DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr)
3682  : LDeferredCode(codegen), instr_(instr) { }
3683  virtual void Generate() OVERRIDE {
3684  codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
3685  }
3686  virtual LInstruction* instr() OVERRIDE { return instr_; }
3687  private:
3688  LMathAbs* instr_;
3689  };
3690 
3691  DCHECK(instr->value()->Equals(instr->result()));
3692  Representation r = instr->hydrogen()->value()->representation();
3693 
3694  if (r.IsDouble()) {
3695  XMMRegister scratch = double_scratch0();
3696  XMMRegister input_reg = ToDoubleRegister(instr->value());
3697  __ xorps(scratch, scratch);
3698  __ subsd(scratch, input_reg);
3699  __ andps(input_reg, scratch);
3700  } else if (r.IsInteger32()) {
3701  EmitIntegerMathAbs(instr);
3702  } else if (r.IsSmi()) {
3703  EmitSmiMathAbs(instr);
3704  } else { // Tagged case.
3705  DeferredMathAbsTaggedHeapNumber* deferred =
3706  new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr);
3707  Register input_reg = ToRegister(instr->value());
3708  // Smi check.
3709  __ JumpIfNotSmi(input_reg, deferred->entry());
3710  EmitSmiMathAbs(instr);
3711  __ bind(deferred->exit());
3712  }
3713 }
3714 
3715 
3716 void LCodeGen::DoMathFloor(LMathFloor* instr) {
3717  XMMRegister xmm_scratch = double_scratch0();
3718  Register output_reg = ToRegister(instr->result());
3719  XMMRegister input_reg = ToDoubleRegister(instr->value());
3720 
3722  CpuFeatureScope scope(masm(), SSE4_1);
3723  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3724  // Deoptimize if minus zero.
3725  __ movq(output_reg, input_reg);
3726  __ subq(output_reg, Immediate(1));
3727  DeoptimizeIf(overflow, instr, "minus zero");
3728  }
3729  __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
3730  __ cvttsd2si(output_reg, xmm_scratch);
3731  __ cmpl(output_reg, Immediate(0x1));
3732  DeoptimizeIf(overflow, instr, "overflow");
3733  } else {
3734  Label negative_sign, done;
3735  // Deoptimize on unordered.
3736  __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3737  __ ucomisd(input_reg, xmm_scratch);
3738  DeoptimizeIf(parity_even, instr, "NaN");
3739  __ j(below, &negative_sign, Label::kNear);
3740 
3741  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3742  // Check for negative zero.
3743  Label positive_sign;
3744  __ j(above, &positive_sign, Label::kNear);
3745  __ movmskpd(output_reg, input_reg);
3746  __ testq(output_reg, Immediate(1));
3747  DeoptimizeIf(not_zero, instr, "minus zero");
3748  __ Set(output_reg, 0);
3749  __ jmp(&done);
3750  __ bind(&positive_sign);
3751  }
3752 
3753  // Use truncating instruction (OK because input is positive).
3754  __ cvttsd2si(output_reg, input_reg);
3755  // Overflow is signalled with minint.
3756  __ cmpl(output_reg, Immediate(0x1));
3757  DeoptimizeIf(overflow, instr, "overflow");
3758  __ jmp(&done, Label::kNear);
3759 
3760  // Non-zero negative reaches here.
3761  __ bind(&negative_sign);
3762  // Truncate, then compare and compensate.
3763  __ cvttsd2si(output_reg, input_reg);
3764  __ Cvtlsi2sd(xmm_scratch, output_reg);
3765  __ ucomisd(input_reg, xmm_scratch);
3766  __ j(equal, &done, Label::kNear);
3767  __ subl(output_reg, Immediate(1));
3768  DeoptimizeIf(overflow, instr, "overflow");
3769 
3770  __ bind(&done);
3771  }
3772 }
3773 
3774 
3775 void LCodeGen::DoMathRound(LMathRound* instr) {
3776  const XMMRegister xmm_scratch = double_scratch0();
3777  Register output_reg = ToRegister(instr->result());
3778  XMMRegister input_reg = ToDoubleRegister(instr->value());
3779  XMMRegister input_temp = ToDoubleRegister(instr->temp());
3780  static int64_t one_half = V8_INT64_C(0x3FE0000000000000); // 0.5
3781  static int64_t minus_one_half = V8_INT64_C(0xBFE0000000000000); // -0.5
3782 
3783  Label done, round_to_zero, below_one_half;
3784  Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear;
3785  __ movq(kScratchRegister, one_half);
3786  __ movq(xmm_scratch, kScratchRegister);
3787  __ ucomisd(xmm_scratch, input_reg);
3788  __ j(above, &below_one_half, Label::kNear);
3789 
3790  // CVTTSD2SI rounds towards zero, since 0.5 <= x, we use floor(0.5 + x).
3791  __ addsd(xmm_scratch, input_reg);
3792  __ cvttsd2si(output_reg, xmm_scratch);
3793  // Overflow is signalled with minint.
3794  __ cmpl(output_reg, Immediate(0x1));
3795  DeoptimizeIf(overflow, instr, "overflow");
3796  __ jmp(&done, dist);
3797 
3798  __ bind(&below_one_half);
3799  __ movq(kScratchRegister, minus_one_half);
3800  __ movq(xmm_scratch, kScratchRegister);
3801  __ ucomisd(xmm_scratch, input_reg);
3802  __ j(below_equal, &round_to_zero, Label::kNear);
3803 
3804  // CVTTSD2SI rounds towards zero, we use ceil(x - (-0.5)) and then
3805  // compare and compensate.
3806  __ movq(input_temp, input_reg); // Do not alter input_reg.
3807  __ subsd(input_temp, xmm_scratch);
3808  __ cvttsd2si(output_reg, input_temp);
3809  // Catch minint due to overflow, and to prevent overflow when compensating.
3810  __ cmpl(output_reg, Immediate(0x1));
3811  DeoptimizeIf(overflow, instr, "overflow");
3812 
3813  __ Cvtlsi2sd(xmm_scratch, output_reg);
3814  __ ucomisd(xmm_scratch, input_temp);
3815  __ j(equal, &done, dist);
3816  __ subl(output_reg, Immediate(1));
3817  // No overflow because we already ruled out minint.
3818  __ jmp(&done, dist);
3819 
3820  __ bind(&round_to_zero);
3821  // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
3822  // we can ignore the difference between a result of -0 and +0.
3823  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3824  __ movq(output_reg, input_reg);
3825  __ testq(output_reg, output_reg);
3826  DeoptimizeIf(negative, instr, "minus zero");
3827  }
3828  __ Set(output_reg, 0);
3829  __ bind(&done);
3830 }
3831 
3832 
3833 void LCodeGen::DoMathFround(LMathFround* instr) {
3834  XMMRegister input_reg = ToDoubleRegister(instr->value());
3835  XMMRegister output_reg = ToDoubleRegister(instr->result());
3836  __ cvtsd2ss(output_reg, input_reg);
3837  __ cvtss2sd(output_reg, output_reg);
3838 }
3839 
3840 
3841 void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
3842  XMMRegister output = ToDoubleRegister(instr->result());
3843  if (instr->value()->IsDoubleRegister()) {
3844  XMMRegister input = ToDoubleRegister(instr->value());
3845  __ sqrtsd(output, input);
3846  } else {
3847  Operand input = ToOperand(instr->value());
3848  __ sqrtsd(output, input);
3849  }
3850 }
3851 
3852 
3853 void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
3854  XMMRegister xmm_scratch = double_scratch0();
3855  XMMRegister input_reg = ToDoubleRegister(instr->value());
3856  DCHECK(ToDoubleRegister(instr->result()).is(input_reg));
3857 
3858  // Note that according to ECMA-262 15.8.2.13:
3859  // Math.pow(-Infinity, 0.5) == Infinity
3860  // Math.sqrt(-Infinity) == NaN
3861  Label done, sqrt;
3862  // Check base for -Infinity. According to IEEE-754, double-precision
3863  // -Infinity has the highest 12 bits set and the lowest 52 bits cleared.
3864  __ movq(kScratchRegister, V8_INT64_C(0xFFF0000000000000));
3865  __ movq(xmm_scratch, kScratchRegister);
3866  __ ucomisd(xmm_scratch, input_reg);
3867  // Comparing -Infinity with NaN results in "unordered", which sets the
3868  // zero flag as if both were equal. However, it also sets the carry flag.
3869  __ j(not_equal, &sqrt, Label::kNear);
3870  __ j(carry, &sqrt, Label::kNear);
3871  // If input is -Infinity, return Infinity.
3872  __ xorps(input_reg, input_reg);
3873  __ subsd(input_reg, xmm_scratch);
3874  __ jmp(&done, Label::kNear);
3875 
3876  // Square root.
3877  __ bind(&sqrt);
3878  __ xorps(xmm_scratch, xmm_scratch);
3879  __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
3880  __ sqrtsd(input_reg, input_reg);
3881  __ bind(&done);
3882 }
3883 
3884 
3885 void LCodeGen::DoPower(LPower* instr) {
3886  Representation exponent_type = instr->hydrogen()->right()->representation();
3887  // Having marked this as a call, we can use any registers.
3888  // Just make sure that the input/output registers are the expected ones.
3889 
3890  Register tagged_exponent = MathPowTaggedDescriptor::exponent();
3891  DCHECK(!instr->right()->IsRegister() ||
3892  ToRegister(instr->right()).is(tagged_exponent));
3893  DCHECK(!instr->right()->IsDoubleRegister() ||
3894  ToDoubleRegister(instr->right()).is(xmm1));
3895  DCHECK(ToDoubleRegister(instr->left()).is(xmm2));
3896  DCHECK(ToDoubleRegister(instr->result()).is(xmm3));
3897 
3898  if (exponent_type.IsSmi()) {
3899  MathPowStub stub(isolate(), MathPowStub::TAGGED);
3900  __ CallStub(&stub);
3901  } else if (exponent_type.IsTagged()) {
3902  Label no_deopt;
3903  __ JumpIfSmi(tagged_exponent, &no_deopt, Label::kNear);
3904  __ CmpObjectType(tagged_exponent, HEAP_NUMBER_TYPE, rcx);
3905  DeoptimizeIf(not_equal, instr, "not a heap number");
3906  __ bind(&no_deopt);
3907  MathPowStub stub(isolate(), MathPowStub::TAGGED);
3908  __ CallStub(&stub);
3909  } else if (exponent_type.IsInteger32()) {
3910  MathPowStub stub(isolate(), MathPowStub::INTEGER);
3911  __ CallStub(&stub);
3912  } else {
3913  DCHECK(exponent_type.IsDouble());
3914  MathPowStub stub(isolate(), MathPowStub::DOUBLE);
3915  __ CallStub(&stub);
3916  }
3917 }
3918 
3919 
3920 void LCodeGen::DoMathExp(LMathExp* instr) {
3921  XMMRegister input = ToDoubleRegister(instr->value());
3922  XMMRegister result = ToDoubleRegister(instr->result());
3923  XMMRegister temp0 = double_scratch0();
3924  Register temp1 = ToRegister(instr->temp1());
3925  Register temp2 = ToRegister(instr->temp2());
3926 
3927  MathExpGenerator::EmitMathExp(masm(), input, result, temp0, temp1, temp2);
3928 }
3929 
3930 
3931 void LCodeGen::DoMathLog(LMathLog* instr) {
3932  DCHECK(instr->value()->Equals(instr->result()));
3933  XMMRegister input_reg = ToDoubleRegister(instr->value());
3934  XMMRegister xmm_scratch = double_scratch0();
3935  Label positive, done, zero;
3936  __ xorps(xmm_scratch, xmm_scratch);
3937  __ ucomisd(input_reg, xmm_scratch);
3938  __ j(above, &positive, Label::kNear);
3939  __ j(not_carry, &zero, Label::kNear);
3940  ExternalReference nan =
3941  ExternalReference::address_of_canonical_non_hole_nan();
3942  Operand nan_operand = masm()->ExternalOperand(nan);
3943  __ movsd(input_reg, nan_operand);
3944  __ jmp(&done, Label::kNear);
3945  __ bind(&zero);
3946  ExternalReference ninf =
3947  ExternalReference::address_of_negative_infinity();
3948  Operand ninf_operand = masm()->ExternalOperand(ninf);
3949  __ movsd(input_reg, ninf_operand);
3950  __ jmp(&done, Label::kNear);
3951  __ bind(&positive);
3952  __ fldln2();
3953  __ subp(rsp, Immediate(kDoubleSize));
3954  __ movsd(Operand(rsp, 0), input_reg);
3955  __ fld_d(Operand(rsp, 0));
3956  __ fyl2x();
3957  __ fstp_d(Operand(rsp, 0));
3958  __ movsd(input_reg, Operand(rsp, 0));
3959  __ addp(rsp, Immediate(kDoubleSize));
3960  __ bind(&done);
3961 }
3962 
3963 
3964 void LCodeGen::DoMathClz32(LMathClz32* instr) {
3965  Register input = ToRegister(instr->value());
3966  Register result = ToRegister(instr->result());
3967  Label not_zero_input;
3968  __ bsrl(result, input);
3969 
3970  __ j(not_zero, &not_zero_input);
3971  __ Set(result, 63); // 63^31 == 32
3972 
3973  __ bind(&not_zero_input);
3974  __ xorl(result, Immediate(31)); // for x in [0..31], 31^x == 31-x.
3975 }
3976 
3977 
3978 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
3979  DCHECK(ToRegister(instr->context()).is(rsi));
3980  DCHECK(ToRegister(instr->function()).is(rdi));
3981  DCHECK(instr->HasPointerMap());
3982 
3983  Handle<JSFunction> known_function = instr->hydrogen()->known_function();
3984  if (known_function.is_null()) {
3985  LPointerMap* pointers = instr->pointer_map();
3986  SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
3987  ParameterCount count(instr->arity());
3988  __ InvokeFunction(rdi, count, CALL_FUNCTION, generator);
3989  } else {
3990  CallKnownFunction(known_function,
3991  instr->hydrogen()->formal_parameter_count(),
3992  instr->arity(),
3993  instr,
3995  }
3996 }
3997 
3998 
3999 void LCodeGen::DoCallFunction(LCallFunction* instr) {
4000  DCHECK(ToRegister(instr->context()).is(rsi));
4001  DCHECK(ToRegister(instr->function()).is(rdi));
4002  DCHECK(ToRegister(instr->result()).is(rax));
4003 
4004  int arity = instr->arity();
4005  CallFunctionStub stub(isolate(), arity, instr->hydrogen()->function_flags());
4006  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
4007 }
4008 
4009 
4010 void LCodeGen::DoCallNew(LCallNew* instr) {
4011  DCHECK(ToRegister(instr->context()).is(rsi));
4012  DCHECK(ToRegister(instr->constructor()).is(rdi));
4013  DCHECK(ToRegister(instr->result()).is(rax));
4014 
4015  __ Set(rax, instr->arity());
4016  // No cell in ebx for construct type feedback in optimized code
4017  __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex);
4018  CallConstructStub stub(isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
4019  CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
4020 }
4021 
4022 
4023 void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
4024  DCHECK(ToRegister(instr->context()).is(rsi));
4025  DCHECK(ToRegister(instr->constructor()).is(rdi));
4026  DCHECK(ToRegister(instr->result()).is(rax));
4027 
4028  __ Set(rax, instr->arity());
4029  __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex);
4030  ElementsKind kind = instr->hydrogen()->elements_kind();
4031  AllocationSiteOverrideMode override_mode =
4034  : DONT_OVERRIDE;
4035 
4036  if (instr->arity() == 0) {
4037  ArrayNoArgumentConstructorStub stub(isolate(), kind, override_mode);
4038  CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
4039  } else if (instr->arity() == 1) {
4040  Label done;
4041  if (IsFastPackedElementsKind(kind)) {
4042  Label packed_case;
4043  // We might need a change here
4044  // look at the first argument
4045  __ movp(rcx, Operand(rsp, 0));
4046  __ testp(rcx, rcx);
4047  __ j(zero, &packed_case, Label::kNear);
4048 
4049  ElementsKind holey_kind = GetHoleyElementsKind(kind);
4050  ArraySingleArgumentConstructorStub stub(isolate(),
4051  holey_kind,
4052  override_mode);
4053  CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
4054  __ jmp(&done, Label::kNear);
4055  __ bind(&packed_case);
4056  }
4057 
4058  ArraySingleArgumentConstructorStub stub(isolate(), kind, override_mode);
4059  CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
4060  __ bind(&done);
4061  } else {
4062  ArrayNArgumentsConstructorStub stub(isolate(), kind, override_mode);
4063  CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
4064  }
4065 }
4066 
4067 
4068 void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
4069  DCHECK(ToRegister(instr->context()).is(rsi));
4070  CallRuntime(instr->function(), instr->arity(), instr, instr->save_doubles());
4071 }
4072 
4073 
4074 void LCodeGen::DoStoreCodeEntry(LStoreCodeEntry* instr) {
4075  Register function = ToRegister(instr->function());
4076  Register code_object = ToRegister(instr->code_object());
4077  __ leap(code_object, FieldOperand(code_object, Code::kHeaderSize));
4078  __ movp(FieldOperand(function, JSFunction::kCodeEntryOffset), code_object);
4079 }
4080 
4081 
4082 void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) {
4083  Register result = ToRegister(instr->result());
4084  Register base = ToRegister(instr->base_object());
4085  if (instr->offset()->IsConstantOperand()) {
4086  LConstantOperand* offset = LConstantOperand::cast(instr->offset());
4087  __ leap(result, Operand(base, ToInteger32(offset)));
4088  } else {
4089  Register offset = ToRegister(instr->offset());
4090  __ leap(result, Operand(base, offset, times_1, 0));
4091  }
4092 }
4093 
4094 
4095 void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
4096  HStoreNamedField* hinstr = instr->hydrogen();
4097  Representation representation = instr->representation();
4098 
4099  HObjectAccess access = hinstr->access();
4100  int offset = access.offset();
4101 
4102  if (access.IsExternalMemory()) {
4103  DCHECK(!hinstr->NeedsWriteBarrier());
4104  Register value = ToRegister(instr->value());
4105  if (instr->object()->IsConstantOperand()) {
4106  DCHECK(value.is(rax));
4107  LConstantOperand* object = LConstantOperand::cast(instr->object());
4108  __ store_rax(ToExternalReference(object));
4109  } else {
4110  Register object = ToRegister(instr->object());
4111  __ Store(MemOperand(object, offset), value, representation);
4112  }
4113  return;
4114  }
4115 
4116  Register object = ToRegister(instr->object());
4117  __ AssertNotSmi(object);
4118 
4119  DCHECK(!representation.IsSmi() ||
4120  !instr->value()->IsConstantOperand() ||
4121  IsInteger32Constant(LConstantOperand::cast(instr->value())));
4122  if (representation.IsDouble()) {
4123  DCHECK(access.IsInobject());
4124  DCHECK(!hinstr->has_transition());
4125  DCHECK(!hinstr->NeedsWriteBarrier());
4126  XMMRegister value = ToDoubleRegister(instr->value());
4127  __ movsd(FieldOperand(object, offset), value);
4128  return;
4129  }
4130 
4131  if (hinstr->has_transition()) {
4132  Handle<Map> transition = hinstr->transition_map();
4133  AddDeprecationDependency(transition);
4134  if (!hinstr->NeedsWriteBarrierForMap()) {
4135  __ Move(FieldOperand(object, HeapObject::kMapOffset), transition);
4136  } else {
4137  Register temp = ToRegister(instr->temp());
4138  __ Move(kScratchRegister, transition);
4140  // Update the write barrier for the map field.
4141  __ RecordWriteForMap(object,
4143  temp,
4144  kSaveFPRegs);
4145  }
4146  }
4147 
4148  // Do the store.
4149  Register write_register = object;
4150  if (!access.IsInobject()) {
4151  write_register = ToRegister(instr->temp());
4152  __ movp(write_register, FieldOperand(object, JSObject::kPropertiesOffset));
4153  }
4154 
4155  if (representation.IsSmi() && SmiValuesAre32Bits() &&
4156  hinstr->value()->representation().IsInteger32()) {
4157  DCHECK(hinstr->store_mode() == STORE_TO_INITIALIZED_ENTRY);
4158  if (FLAG_debug_code) {
4159  Register scratch = kScratchRegister;
4160  __ Load(scratch, FieldOperand(write_register, offset), representation);
4161  __ AssertSmi(scratch);
4162  }
4163  // Store int value directly to upper half of the smi.
4164  STATIC_ASSERT(kSmiTag == 0);
4165  DCHECK(kSmiTagSize + kSmiShiftSize == 32);
4166  offset += kPointerSize / 2;
4167  representation = Representation::Integer32();
4168  }
4169 
4170  Operand operand = FieldOperand(write_register, offset);
4171 
4172  if (instr->value()->IsRegister()) {
4173  Register value = ToRegister(instr->value());
4174  __ Store(operand, value, representation);
4175  } else {
4176  LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
4177  if (IsInteger32Constant(operand_value)) {
4178  DCHECK(!hinstr->NeedsWriteBarrier());
4179  int32_t value = ToInteger32(operand_value);
4180  if (representation.IsSmi()) {
4181  __ Move(operand, Smi::FromInt(value));
4182 
4183  } else {
4184  __ movl(operand, Immediate(value));
4185  }
4186 
4187  } else {
4188  Handle<Object> handle_value = ToHandle(operand_value);
4189  DCHECK(!hinstr->NeedsWriteBarrier());
4190  __ Move(operand, handle_value);
4191  }
4192  }
4193 
4194  if (hinstr->NeedsWriteBarrier()) {
4195  Register value = ToRegister(instr->value());
4196  Register temp = access.IsInobject() ? ToRegister(instr->temp()) : object;
4197  // Update the write barrier for the object for in-object properties.
4198  __ RecordWriteField(write_register,
4199  offset,
4200  value,
4201  temp,
4202  kSaveFPRegs,
4204  hinstr->SmiCheckForWriteBarrier(),
4205  hinstr->PointersToHereCheckForValue());
4206  }
4207 }
4208 
4209 
4210 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
4211  DCHECK(ToRegister(instr->context()).is(rsi));
4213  DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
4214 
4215  __ Move(StoreDescriptor::NameRegister(), instr->hydrogen()->name());
4216  Handle<Code> ic = StoreIC::initialize_stub(isolate(), instr->strict_mode());
4217  CallCode(ic, RelocInfo::CODE_TARGET, instr);
4218 }
4219 
4220 
4221 void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
4222  Representation representation = instr->hydrogen()->length()->representation();
4223  DCHECK(representation.Equals(instr->hydrogen()->index()->representation()));
4224  DCHECK(representation.IsSmiOrInteger32());
4225 
4226  Condition cc = instr->hydrogen()->allow_equality() ? below : below_equal;
4227  if (instr->length()->IsConstantOperand()) {
4228  int32_t length = ToInteger32(LConstantOperand::cast(instr->length()));
4229  Register index = ToRegister(instr->index());
4230  if (representation.IsSmi()) {
4231  __ Cmp(index, Smi::FromInt(length));
4232  } else {
4233  __ cmpl(index, Immediate(length));
4234  }
4235  cc = CommuteCondition(cc);
4236  } else if (instr->index()->IsConstantOperand()) {
4237  int32_t index = ToInteger32(LConstantOperand::cast(instr->index()));
4238  if (instr->length()->IsRegister()) {
4239  Register length = ToRegister(instr->length());
4240  if (representation.IsSmi()) {
4241  __ Cmp(length, Smi::FromInt(index));
4242  } else {
4243  __ cmpl(length, Immediate(index));
4244  }
4245  } else {
4246  Operand length = ToOperand(instr->length());
4247  if (representation.IsSmi()) {
4248  __ Cmp(length, Smi::FromInt(index));
4249  } else {
4250  __ cmpl(length, Immediate(index));
4251  }
4252  }
4253  } else {
4254  Register index = ToRegister(instr->index());
4255  if (instr->length()->IsRegister()) {
4256  Register length = ToRegister(instr->length());
4257  if (representation.IsSmi()) {
4258  __ cmpp(length, index);
4259  } else {
4260  __ cmpl(length, index);
4261  }
4262  } else {
4263  Operand length = ToOperand(instr->length());
4264  if (representation.IsSmi()) {
4265  __ cmpp(length, index);
4266  } else {
4267  __ cmpl(length, index);
4268  }
4269  }
4270  }
4271  if (FLAG_debug_code && instr->hydrogen()->skip_check()) {
4272  Label done;
4273  __ j(NegateCondition(cc), &done, Label::kNear);
4274  __ int3();
4275  __ bind(&done);
4276  } else {
4277  DeoptimizeIf(cc, instr, "out of bounds");
4278  }
4279 }
4280 
4281 
4282 void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
4283  ElementsKind elements_kind = instr->elements_kind();
4284  LOperand* key = instr->key();
4285  if (kPointerSize == kInt32Size && !key->IsConstantOperand()) {
4286  Register key_reg = ToRegister(key);
4287  Representation key_representation =
4288  instr->hydrogen()->key()->representation();
4289  if (ExternalArrayOpRequiresTemp(key_representation, elements_kind)) {
4290  __ SmiToInteger64(key_reg, key_reg);
4291  } else if (instr->hydrogen()->IsDehoisted()) {
4292  // Sign extend key because it could be a 32 bit negative value
4293  // and the dehoisted address computation happens in 64 bits
4294  __ movsxlq(key_reg, key_reg);
4295  }
4296  }
4297  Operand operand(BuildFastArrayOperand(
4298  instr->elements(),
4299  key,
4300  instr->hydrogen()->key()->representation(),
4301  elements_kind,
4302  instr->base_offset()));
4303 
4304  if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
4305  elements_kind == FLOAT32_ELEMENTS) {
4306  XMMRegister value(ToDoubleRegister(instr->value()));
4307  __ cvtsd2ss(value, value);
4308  __ movss(operand, value);
4309  } else if (elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
4310  elements_kind == FLOAT64_ELEMENTS) {
4311  __ movsd(operand, ToDoubleRegister(instr->value()));
4312  } else {
4313  Register value(ToRegister(instr->value()));
4314  switch (elements_kind) {
4318  case INT8_ELEMENTS:
4319  case UINT8_ELEMENTS:
4321  __ movb(operand, value);
4322  break;
4325  case INT16_ELEMENTS:
4326  case UINT16_ELEMENTS:
4327  __ movw(operand, value);
4328  break;
4331  case INT32_ELEMENTS:
4332  case UINT32_ELEMENTS:
4333  __ movl(operand, value);
4334  break;
4337  case FLOAT32_ELEMENTS:
4338  case FLOAT64_ELEMENTS:
4339  case FAST_ELEMENTS:
4340  case FAST_SMI_ELEMENTS:
4341  case FAST_DOUBLE_ELEMENTS:
4342  case FAST_HOLEY_ELEMENTS:
4345  case DICTIONARY_ELEMENTS:
4347  UNREACHABLE();
4348  break;
4349  }
4350  }
4351 }
4352 
4353 
4354 void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
4355  XMMRegister value = ToDoubleRegister(instr->value());
4356  LOperand* key = instr->key();
4357  if (kPointerSize == kInt32Size && !key->IsConstantOperand() &&
4358  instr->hydrogen()->IsDehoisted()) {
4359  // Sign extend key because it could be a 32 bit negative value
4360  // and the dehoisted address computation happens in 64 bits
4361  __ movsxlq(ToRegister(key), ToRegister(key));
4362  }
4363  if (instr->NeedsCanonicalization()) {
4364  Label have_value;
4365 
4366  __ ucomisd(value, value);
4367  __ j(parity_odd, &have_value, Label::kNear); // NaN.
4368 
4369  __ Set(kScratchRegister,
4370  bit_cast<uint64_t>(
4372  __ movq(value, kScratchRegister);
4373 
4374  __ bind(&have_value);
4375  }
4376 
4377  Operand double_store_operand = BuildFastArrayOperand(
4378  instr->elements(),
4379  key,
4380  instr->hydrogen()->key()->representation(),
4382  instr->base_offset());
4383 
4384  __ movsd(double_store_operand, value);
4385 }
4386 
4387 
4388 void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
4389  HStoreKeyed* hinstr = instr->hydrogen();
4390  LOperand* key = instr->key();
4391  int offset = instr->base_offset();
4392  Representation representation = hinstr->value()->representation();
4393 
4394  if (kPointerSize == kInt32Size && !key->IsConstantOperand() &&
4395  instr->hydrogen()->IsDehoisted()) {
4396  // Sign extend key because it could be a 32 bit negative value
4397  // and the dehoisted address computation happens in 64 bits
4398  __ movsxlq(ToRegister(key), ToRegister(key));
4399  }
4400  if (representation.IsInteger32() && SmiValuesAre32Bits()) {
4401  DCHECK(hinstr->store_mode() == STORE_TO_INITIALIZED_ENTRY);
4402  DCHECK(hinstr->elements_kind() == FAST_SMI_ELEMENTS);
4403  if (FLAG_debug_code) {
4404  Register scratch = kScratchRegister;
4405  __ Load(scratch,
4406  BuildFastArrayOperand(instr->elements(),
4407  key,
4408  instr->hydrogen()->key()->representation(),
4409  FAST_ELEMENTS,
4410  offset),
4412  __ AssertSmi(scratch);
4413  }
4414  // Store int value directly to upper half of the smi.
4415  STATIC_ASSERT(kSmiTag == 0);
4416  DCHECK(kSmiTagSize + kSmiShiftSize == 32);
4417  offset += kPointerSize / 2;
4418  }
4419 
4420  Operand operand =
4421  BuildFastArrayOperand(instr->elements(),
4422  key,
4423  instr->hydrogen()->key()->representation(),
4424  FAST_ELEMENTS,
4425  offset);
4426  if (instr->value()->IsRegister()) {
4427  __ Store(operand, ToRegister(instr->value()), representation);
4428  } else {
4429  LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
4430  if (IsInteger32Constant(operand_value)) {
4431  int32_t value = ToInteger32(operand_value);
4432  if (representation.IsSmi()) {
4433  __ Move(operand, Smi::FromInt(value));
4434 
4435  } else {
4436  __ movl(operand, Immediate(value));
4437  }
4438  } else {
4439  Handle<Object> handle_value = ToHandle(operand_value);
4440  __ Move(operand, handle_value);
4441  }
4442  }
4443 
4444  if (hinstr->NeedsWriteBarrier()) {
4445  Register elements = ToRegister(instr->elements());
4446  DCHECK(instr->value()->IsRegister());
4447  Register value = ToRegister(instr->value());
4448  DCHECK(!key->IsConstantOperand());
4449  SmiCheck check_needed = hinstr->value()->type().IsHeapObject()
4451  // Compute address of modified element and store it into key register.
4452  Register key_reg(ToRegister(key));
4453  __ leap(key_reg, operand);
4454  __ RecordWrite(elements,
4455  key_reg,
4456  value,
4457  kSaveFPRegs,
4459  check_needed,
4460  hinstr->PointersToHereCheckForValue());
4461  }
4462 }
4463 
4464 
4465 void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
4466  if (instr->is_typed_elements()) {
4468  } else if (instr->hydrogen()->value()->representation().IsDouble()) {
4470  } else {
4471  DoStoreKeyedFixedArray(instr);
4472  }
4473 }
4474 
4475 
4476 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
4477  DCHECK(ToRegister(instr->context()).is(rsi));
4480  DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
4481 
4482  Handle<Code> ic =
4483  CodeFactory::KeyedStoreIC(isolate(), instr->strict_mode()).code();
4484  CallCode(ic, RelocInfo::CODE_TARGET, instr);
4485 }
4486 
4487 
4488 void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
4489  Register object_reg = ToRegister(instr->object());
4490 
4491  Handle<Map> from_map = instr->original_map();
4492  Handle<Map> to_map = instr->transitioned_map();
4493  ElementsKind from_kind = instr->from_kind();
4494  ElementsKind to_kind = instr->to_kind();
4495 
4496  Label not_applicable;
4497  __ Cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
4498  __ j(not_equal, &not_applicable);
4499  if (IsSimpleMapChangeTransition(from_kind, to_kind)) {
4500  Register new_map_reg = ToRegister(instr->new_map_temp());
4501  __ Move(new_map_reg, to_map, RelocInfo::EMBEDDED_OBJECT);
4502  __ movp(FieldOperand(object_reg, HeapObject::kMapOffset), new_map_reg);
4503  // Write barrier.
4504  __ RecordWriteForMap(object_reg, new_map_reg, ToRegister(instr->temp()),
4505  kDontSaveFPRegs);
4506  } else {
4507  DCHECK(object_reg.is(rax));
4508  DCHECK(ToRegister(instr->context()).is(rsi));
4509  PushSafepointRegistersScope scope(this);
4510  __ Move(rbx, to_map);
4511  bool is_js_array = from_map->instance_type() == JS_ARRAY_TYPE;
4512  TransitionElementsKindStub stub(isolate(), from_kind, to_kind, is_js_array);
4513  __ CallStub(&stub);
4515  }
4516  __ bind(&not_applicable);
4517 }
4518 
4519 
4520 void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) {
4521  Register object = ToRegister(instr->object());
4522  Register temp = ToRegister(instr->temp());
4523  Label no_memento_found;
4524  __ TestJSArrayForAllocationMemento(object, temp, &no_memento_found);
4525  DeoptimizeIf(equal, instr, "memento found");
4526  __ bind(&no_memento_found);
4527 }
4528 
4529 
4530 void LCodeGen::DoStringAdd(LStringAdd* instr) {
4531  DCHECK(ToRegister(instr->context()).is(rsi));
4532  DCHECK(ToRegister(instr->left()).is(rdx));
4533  DCHECK(ToRegister(instr->right()).is(rax));
4534  StringAddStub stub(isolate(),
4535  instr->hydrogen()->flags(),
4536  instr->hydrogen()->pretenure_flag());
4537  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
4538 }
4539 
4540 
4541 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
4542  class DeferredStringCharCodeAt FINAL : public LDeferredCode {
4543  public:
4544  DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
4545  : LDeferredCode(codegen), instr_(instr) { }
4546  virtual void Generate() OVERRIDE {
4547  codegen()->DoDeferredStringCharCodeAt(instr_);
4548  }
4549  virtual LInstruction* instr() OVERRIDE { return instr_; }
4550  private:
4551  LStringCharCodeAt* instr_;
4552  };
4553 
4554  DeferredStringCharCodeAt* deferred =
4555  new(zone()) DeferredStringCharCodeAt(this, instr);
4556 
4558  ToRegister(instr->string()),
4559  ToRegister(instr->index()),
4560  ToRegister(instr->result()),
4561  deferred->entry());
4562  __ bind(deferred->exit());
4563 }
4564 
4565 
4566 void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
4567  Register string = ToRegister(instr->string());
4568  Register result = ToRegister(instr->result());
4569 
4570  // TODO(3095996): Get rid of this. For now, we need to make the
4571  // result register contain a valid pointer because it is already
4572  // contained in the register pointer map.
4573  __ Set(result, 0);
4574 
4575  PushSafepointRegistersScope scope(this);
4576  __ Push(string);
4577  // Push the index as a smi. This is safe because of the checks in
4578  // DoStringCharCodeAt above.
4580  if (instr->index()->IsConstantOperand()) {
4581  int32_t const_index = ToInteger32(LConstantOperand::cast(instr->index()));
4582  __ Push(Smi::FromInt(const_index));
4583  } else {
4584  Register index = ToRegister(instr->index());
4585  __ Integer32ToSmi(index, index);
4586  __ Push(index);
4587  }
4589  Runtime::kStringCharCodeAtRT, 2, instr, instr->context());
4590  __ AssertSmi(rax);
4591  __ SmiToInteger32(rax, rax);
4592  __ StoreToSafepointRegisterSlot(result, rax);
4593 }
4594 
4595 
4596 void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
4597  class DeferredStringCharFromCode FINAL : public LDeferredCode {
4598  public:
4599  DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
4600  : LDeferredCode(codegen), instr_(instr) { }
4601  virtual void Generate() OVERRIDE {
4602  codegen()->DoDeferredStringCharFromCode(instr_);
4603  }
4604  virtual LInstruction* instr() OVERRIDE { return instr_; }
4605  private:
4606  LStringCharFromCode* instr_;
4607  };
4608 
4609  DeferredStringCharFromCode* deferred =
4610  new(zone()) DeferredStringCharFromCode(this, instr);
4611 
4612  DCHECK(instr->hydrogen()->value()->representation().IsInteger32());
4613  Register char_code = ToRegister(instr->char_code());
4614  Register result = ToRegister(instr->result());
4615  DCHECK(!char_code.is(result));
4616 
4617  __ cmpl(char_code, Immediate(String::kMaxOneByteCharCode));
4618  __ j(above, deferred->entry());
4619  __ movsxlq(char_code, char_code);
4620  __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex);
4621  __ movp(result, FieldOperand(result,
4622  char_code, times_pointer_size,
4624  __ CompareRoot(result, Heap::kUndefinedValueRootIndex);
4625  __ j(equal, deferred->entry());
4626  __ bind(deferred->exit());
4627 }
4628 
4629 
4630 void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
4631  Register char_code = ToRegister(instr->char_code());
4632  Register result = ToRegister(instr->result());
4633 
4634  // TODO(3095996): Get rid of this. For now, we need to make the
4635  // result register contain a valid pointer because it is already
4636  // contained in the register pointer map.
4637  __ Set(result, 0);
4638 
4639  PushSafepointRegistersScope scope(this);
4640  __ Integer32ToSmi(char_code, char_code);
4641  __ Push(char_code);
4642  CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context());
4643  __ StoreToSafepointRegisterSlot(result, rax);
4644 }
4645 
4646 
4647 void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
4648  LOperand* input = instr->value();
4649  DCHECK(input->IsRegister() || input->IsStackSlot());
4650  LOperand* output = instr->result();
4651  DCHECK(output->IsDoubleRegister());
4652  if (input->IsRegister()) {
4653  __ Cvtlsi2sd(ToDoubleRegister(output), ToRegister(input));
4654  } else {
4655  __ Cvtlsi2sd(ToDoubleRegister(output), ToOperand(input));
4656  }
4657 }
4658 
4659 
4660 void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
4661  LOperand* input = instr->value();
4662  LOperand* output = instr->result();
4663 
4664  __ LoadUint32(ToDoubleRegister(output), ToRegister(input));
4665 }
4666 
4667 
4668 void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
4669  class DeferredNumberTagI FINAL : public LDeferredCode {
4670  public:
4671  DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
4672  : LDeferredCode(codegen), instr_(instr) { }
4673  virtual void Generate() OVERRIDE {
4674  codegen()->DoDeferredNumberTagIU(instr_, instr_->value(), instr_->temp1(),
4675  instr_->temp2(), SIGNED_INT32);
4676  }
4677  virtual LInstruction* instr() OVERRIDE { return instr_; }
4678  private:
4679  LNumberTagI* instr_;
4680  };
4681 
4682  LOperand* input = instr->value();
4683  DCHECK(input->IsRegister() && input->Equals(instr->result()));
4684  Register reg = ToRegister(input);
4685 
4686  if (SmiValuesAre32Bits()) {
4687  __ Integer32ToSmi(reg, reg);
4688  } else {
4690  DeferredNumberTagI* deferred = new(zone()) DeferredNumberTagI(this, instr);
4691  __ Integer32ToSmi(reg, reg);
4692  __ j(overflow, deferred->entry());
4693  __ bind(deferred->exit());
4694  }
4695 }
4696 
4697 
4698 void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
4699  class DeferredNumberTagU FINAL : public LDeferredCode {
4700  public:
4701  DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
4702  : LDeferredCode(codegen), instr_(instr) { }
4703  virtual void Generate() OVERRIDE {
4704  codegen()->DoDeferredNumberTagIU(instr_, instr_->value(), instr_->temp1(),
4705  instr_->temp2(), UNSIGNED_INT32);
4706  }
4707  virtual LInstruction* instr() OVERRIDE { return instr_; }
4708  private:
4709  LNumberTagU* instr_;
4710  };
4711 
4712  LOperand* input = instr->value();
4713  DCHECK(input->IsRegister() && input->Equals(instr->result()));
4714  Register reg = ToRegister(input);
4715 
4716  DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr);
4717  __ cmpl(reg, Immediate(Smi::kMaxValue));
4718  __ j(above, deferred->entry());
4719  __ Integer32ToSmi(reg, reg);
4720  __ bind(deferred->exit());
4721 }
4722 
4723 
4724 void LCodeGen::DoDeferredNumberTagIU(LInstruction* instr,
4725  LOperand* value,
4726  LOperand* temp1,
4727  LOperand* temp2,
4728  IntegerSignedness signedness) {
4729  Label done, slow;
4730  Register reg = ToRegister(value);
4731  Register tmp = ToRegister(temp1);
4732  XMMRegister temp_xmm = ToDoubleRegister(temp2);
4733 
4734  // Load value into temp_xmm which will be preserved across potential call to
4735  // runtime (MacroAssembler::EnterExitFrameEpilogue preserves only allocatable
4736  // XMM registers on x64).
4737  if (signedness == SIGNED_INT32) {
4739  // There was overflow, so bits 30 and 31 of the original integer
4740  // disagree. Try to allocate a heap number in new space and store
4741  // the value in there. If that fails, call the runtime system.
4742  __ SmiToInteger32(reg, reg);
4743  __ xorl(reg, Immediate(0x80000000));
4744  __ cvtlsi2sd(temp_xmm, reg);
4745  } else {
4746  DCHECK(signedness == UNSIGNED_INT32);
4747  __ LoadUint32(temp_xmm, reg);
4748  }
4749 
4750  if (FLAG_inline_new) {
4751  __ AllocateHeapNumber(reg, tmp, &slow);
4752  __ jmp(&done, kPointerSize == kInt64Size ? Label::kNear : Label::kFar);
4753  }
4754 
4755  // Slow case: Call the runtime system to do the number allocation.
4756  __ bind(&slow);
4757  {
4758  // Put a valid pointer value in the stack slot where the result
4759  // register is stored, as this register is in the pointer map, but contains
4760  // an integer value.
4761  __ Set(reg, 0);
4762 
4763  // Preserve the value of all registers.
4764  PushSafepointRegistersScope scope(this);
4765 
4766  // NumberTagIU uses the context from the frame, rather than
4767  // the environment's HContext or HInlinedContext value.
4768  // They only call Runtime::kAllocateHeapNumber.
4769  // The corresponding HChange instructions are added in a phase that does
4770  // not have easy access to the local context.
4772  __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
4774  instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
4775  __ StoreToSafepointRegisterSlot(reg, rax);
4776  }
4777 
4778  // Done. Put the value in temp_xmm into the value of the allocated heap
4779  // number.
4780  __ bind(&done);
4781  __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), temp_xmm);
4782 }
4783 
4784 
4785 void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
4786  class DeferredNumberTagD FINAL : public LDeferredCode {
4787  public:
4788  DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
4789  : LDeferredCode(codegen), instr_(instr) { }
4790  virtual void Generate() OVERRIDE {
4791  codegen()->DoDeferredNumberTagD(instr_);
4792  }
4793  virtual LInstruction* instr() OVERRIDE { return instr_; }
4794  private:
4795  LNumberTagD* instr_;
4796  };
4797 
4798  XMMRegister input_reg = ToDoubleRegister(instr->value());
4799  Register reg = ToRegister(instr->result());
4800  Register tmp = ToRegister(instr->temp());
4801 
4802  DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr);
4803  if (FLAG_inline_new) {
4804  __ AllocateHeapNumber(reg, tmp, deferred->entry());
4805  } else {
4806  __ jmp(deferred->entry());
4807  }
4808  __ bind(deferred->exit());
4809  __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
4810 }
4811 
4812 
4813 void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
4814  // TODO(3095996): Get rid of this. For now, we need to make the
4815  // result register contain a valid pointer because it is already
4816  // contained in the register pointer map.
4817  Register reg = ToRegister(instr->result());
4818  __ Move(reg, Smi::FromInt(0));
4819 
4820  {
4821  PushSafepointRegistersScope scope(this);
4822  // NumberTagD uses the context from the frame, rather than
4823  // the environment's HContext or HInlinedContext value.
4824  // They only call Runtime::kAllocateHeapNumber.
4825  // The corresponding HChange instructions are added in a phase that does
4826  // not have easy access to the local context.
4828  __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
4830  instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
4831  __ movp(kScratchRegister, rax);
4832  }
4833  __ movp(reg, kScratchRegister);
4834 }
4835 
4836 
4837 void LCodeGen::DoSmiTag(LSmiTag* instr) {
4838  HChange* hchange = instr->hydrogen();
4839  Register input = ToRegister(instr->value());
4840  Register output = ToRegister(instr->result());
4841  if (hchange->CheckFlag(HValue::kCanOverflow) &&
4842  hchange->value()->CheckFlag(HValue::kUint32)) {
4843  Condition is_smi = __ CheckUInteger32ValidSmiValue(input);
4844  DeoptimizeIf(NegateCondition(is_smi), instr, "overflow");
4845  }
4846  __ Integer32ToSmi(output, input);
4847  if (hchange->CheckFlag(HValue::kCanOverflow) &&
4848  !hchange->value()->CheckFlag(HValue::kUint32)) {
4849  DeoptimizeIf(overflow, instr, "overflow");
4850  }
4851 }
4852 
4853 
4854 void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
4855  DCHECK(instr->value()->Equals(instr->result()));
4856  Register input = ToRegister(instr->value());
4857  if (instr->needs_check()) {
4858  Condition is_smi = __ CheckSmi(input);
4859  DeoptimizeIf(NegateCondition(is_smi), instr, "not a Smi");
4860  } else {
4861  __ AssertSmi(input);
4862  }
4863  __ SmiToInteger32(input, input);
4864 }
4865 
4866 
4867 void LCodeGen::EmitNumberUntagD(LNumberUntagD* instr, Register input_reg,
4868  XMMRegister result_reg, NumberUntagDMode mode) {
4869  bool can_convert_undefined_to_nan =
4870  instr->hydrogen()->can_convert_undefined_to_nan();
4871  bool deoptimize_on_minus_zero = instr->hydrogen()->deoptimize_on_minus_zero();
4872 
4873  Label convert, load_smi, done;
4874 
4876  // Smi check.
4877  __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
4878 
4879  // Heap number map check.
4880  __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
4881  Heap::kHeapNumberMapRootIndex);
4882 
4883  // On x64 it is safe to load at heap number offset before evaluating the map
4884  // check, since all heap objects are at least two words long.
4885  __ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
4886 
4887  if (can_convert_undefined_to_nan) {
4888  __ j(not_equal, &convert, Label::kNear);
4889  } else {
4890  DeoptimizeIf(not_equal, instr, "not a heap number");
4891  }
4892 
4893  if (deoptimize_on_minus_zero) {
4894  XMMRegister xmm_scratch = double_scratch0();
4895  __ xorps(xmm_scratch, xmm_scratch);
4896  __ ucomisd(xmm_scratch, result_reg);
4897  __ j(not_equal, &done, Label::kNear);
4898  __ movmskpd(kScratchRegister, result_reg);
4899  __ testq(kScratchRegister, Immediate(1));
4900  DeoptimizeIf(not_zero, instr, "minus zero");
4901  }
4902  __ jmp(&done, Label::kNear);
4903 
4904  if (can_convert_undefined_to_nan) {
4905  __ bind(&convert);
4906 
4907  // Convert undefined (and hole) to NaN. Compute NaN as 0/0.
4908  __ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex);
4909  DeoptimizeIf(not_equal, instr, "not a heap number/undefined");
4910 
4911  __ xorps(result_reg, result_reg);
4912  __ divsd(result_reg, result_reg);
4913  __ jmp(&done, Label::kNear);
4914  }
4915  } else {
4917  }
4918 
4919  // Smi to XMM conversion
4920  __ bind(&load_smi);
4921  __ SmiToInteger32(kScratchRegister, input_reg);
4922  __ Cvtlsi2sd(result_reg, kScratchRegister);
4923  __ bind(&done);
4924 }
4925 
4926 
4927 void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr, Label* done) {
4928  Register input_reg = ToRegister(instr->value());
4929 
4930  if (instr->truncating()) {
4931  Label no_heap_number, check_bools, check_false;
4932 
4933  // Heap number map check.
4934  __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
4935  Heap::kHeapNumberMapRootIndex);
4936  __ j(not_equal, &no_heap_number, Label::kNear);
4937  __ TruncateHeapNumberToI(input_reg, input_reg);
4938  __ jmp(done);
4939 
4940  __ bind(&no_heap_number);
4941  // Check for Oddballs. Undefined/False is converted to zero and True to one
4942  // for truncating conversions.
4943  __ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex);
4944  __ j(not_equal, &check_bools, Label::kNear);
4945  __ Set(input_reg, 0);
4946  __ jmp(done);
4947 
4948  __ bind(&check_bools);
4949  __ CompareRoot(input_reg, Heap::kTrueValueRootIndex);
4950  __ j(not_equal, &check_false, Label::kNear);
4951  __ Set(input_reg, 1);
4952  __ jmp(done);
4953 
4954  __ bind(&check_false);
4955  __ CompareRoot(input_reg, Heap::kFalseValueRootIndex);
4956  DeoptimizeIf(not_equal, instr, "not a heap number/undefined/true/false");
4957  __ Set(input_reg, 0);
4958  } else {
4959  XMMRegister scratch = ToDoubleRegister(instr->temp());
4960  DCHECK(!scratch.is(xmm0));
4961  __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
4962  Heap::kHeapNumberMapRootIndex);
4963  DeoptimizeIf(not_equal, instr, "not a heap number");
4964  __ movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
4965  __ cvttsd2si(input_reg, xmm0);
4966  __ Cvtlsi2sd(scratch, input_reg);
4967  __ ucomisd(xmm0, scratch);
4968  DeoptimizeIf(not_equal, instr, "lost precision");
4969  DeoptimizeIf(parity_even, instr, "NaN");
4970  if (instr->hydrogen()->GetMinusZeroMode() == FAIL_ON_MINUS_ZERO) {
4971  __ testl(input_reg, input_reg);
4972  __ j(not_zero, done);
4973  __ movmskpd(input_reg, xmm0);
4974  __ andl(input_reg, Immediate(1));
4975  DeoptimizeIf(not_zero, instr, "minus zero");
4976  }
4977  }
4978 }
4979 
4980 
4981 void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
4982  class DeferredTaggedToI FINAL : public LDeferredCode {
4983  public:
4984  DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
4985  : LDeferredCode(codegen), instr_(instr) { }
4986  virtual void Generate() OVERRIDE {
4987  codegen()->DoDeferredTaggedToI(instr_, done());
4988  }
4989  virtual LInstruction* instr() OVERRIDE { return instr_; }
4990  private:
4991  LTaggedToI* instr_;
4992  };
4993 
4994  LOperand* input = instr->value();
4995  DCHECK(input->IsRegister());
4996  DCHECK(input->Equals(instr->result()));
4997  Register input_reg = ToRegister(input);
4998 
4999  if (instr->hydrogen()->value()->representation().IsSmi()) {
5000  __ SmiToInteger32(input_reg, input_reg);
5001  } else {
5002  DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr);
5003  __ JumpIfNotSmi(input_reg, deferred->entry());
5004  __ SmiToInteger32(input_reg, input_reg);
5005  __ bind(deferred->exit());
5006  }
5007 }
5008 
5009 
5010 void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
5011  LOperand* input = instr->value();
5012  DCHECK(input->IsRegister());
5013  LOperand* result = instr->result();
5014  DCHECK(result->IsDoubleRegister());
5015 
5016  Register input_reg = ToRegister(input);
5017  XMMRegister result_reg = ToDoubleRegister(result);
5018 
5019  HValue* value = instr->hydrogen()->value();
5020  NumberUntagDMode mode = value->representation().IsSmi()
5022 
5023  EmitNumberUntagD(instr, input_reg, result_reg, mode);
5024 }
5025 
5026 
5027 void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
5028  LOperand* input = instr->value();
5029  DCHECK(input->IsDoubleRegister());
5030  LOperand* result = instr->result();
5031  DCHECK(result->IsRegister());
5032 
5033  XMMRegister input_reg = ToDoubleRegister(input);
5034  Register result_reg = ToRegister(result);
5035 
5036  if (instr->truncating()) {
5037  __ TruncateDoubleToI(result_reg, input_reg);
5038  } else {
5039  Label lost_precision, is_nan, minus_zero, done;
5040  XMMRegister xmm_scratch = double_scratch0();
5041  Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear;
5042  __ DoubleToI(result_reg, input_reg, xmm_scratch,
5043  instr->hydrogen()->GetMinusZeroMode(), &lost_precision,
5044  &is_nan, &minus_zero, dist);
5045  __ jmp(&done, dist);
5046  __ bind(&lost_precision);
5047  DeoptimizeIf(no_condition, instr, "lost precision");
5048  __ bind(&is_nan);
5049  DeoptimizeIf(no_condition, instr, "NaN");
5050  __ bind(&minus_zero);
5051  DeoptimizeIf(no_condition, instr, "minus zero");
5052  __ bind(&done);
5053  }
5054 }
5055 
5056 
5057 void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) {
5058  LOperand* input = instr->value();
5059  DCHECK(input->IsDoubleRegister());
5060  LOperand* result = instr->result();
5061  DCHECK(result->IsRegister());
5062 
5063  XMMRegister input_reg = ToDoubleRegister(input);
5064  Register result_reg = ToRegister(result);
5065 
5066  Label lost_precision, is_nan, minus_zero, done;
5067  XMMRegister xmm_scratch = double_scratch0();
5068  Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear;
5069  __ DoubleToI(result_reg, input_reg, xmm_scratch,
5070  instr->hydrogen()->GetMinusZeroMode(), &lost_precision, &is_nan,
5071  &minus_zero, dist);
5072  __ jmp(&done, dist);
5073  __ bind(&lost_precision);
5074  DeoptimizeIf(no_condition, instr, "lost precision");
5075  __ bind(&is_nan);
5076  DeoptimizeIf(no_condition, instr, "NaN");
5077  __ bind(&minus_zero);
5078  DeoptimizeIf(no_condition, instr, "minus zero");
5079  __ bind(&done);
5080  __ Integer32ToSmi(result_reg, result_reg);
5081  DeoptimizeIf(overflow, instr, "overflow");
5082 }
5083 
5084 
5085 void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
5086  LOperand* input = instr->value();
5087  Condition cc = masm()->CheckSmi(ToRegister(input));
5088  DeoptimizeIf(NegateCondition(cc), instr, "not a Smi");
5089 }
5090 
5091 
5092 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
5093  if (!instr->hydrogen()->value()->type().IsHeapObject()) {
5094  LOperand* input = instr->value();
5095  Condition cc = masm()->CheckSmi(ToRegister(input));
5096  DeoptimizeIf(cc, instr, "Smi");
5097  }
5098 }
5099 
5100 
5101 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
5102  Register input = ToRegister(instr->value());
5103 
5105 
5106  if (instr->hydrogen()->is_interval_check()) {
5107  InstanceType first;
5108  InstanceType last;
5109  instr->hydrogen()->GetCheckInterval(&first, &last);
5110 
5112  Immediate(static_cast<int8_t>(first)));
5113 
5114  // If there is only one type in the interval check for equality.
5115  if (first == last) {
5116  DeoptimizeIf(not_equal, instr, "wrong instance type");
5117  } else {
5118  DeoptimizeIf(below, instr, "wrong instance type");
5119  // Omit check for the last type.
5120  if (last != LAST_TYPE) {
5122  Immediate(static_cast<int8_t>(last)));
5123  DeoptimizeIf(above, instr, "wrong instance type");
5124  }
5125  }
5126  } else {
5127  uint8_t mask;
5128  uint8_t tag;
5129  instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
5130 
5131  if (base::bits::IsPowerOfTwo32(mask)) {
5132  DCHECK(tag == 0 || base::bits::IsPowerOfTwo32(tag));
5134  Immediate(mask));
5135  DeoptimizeIf(tag == 0 ? not_zero : zero, instr, "wrong instance type");
5136  } else {
5137  __ movzxbl(kScratchRegister,
5139  __ andb(kScratchRegister, Immediate(mask));
5140  __ cmpb(kScratchRegister, Immediate(tag));
5141  DeoptimizeIf(not_equal, instr, "wrong instance type");
5142  }
5143  }
5144 }
5145 
5146 
5147 void LCodeGen::DoCheckValue(LCheckValue* instr) {
5148  Register reg = ToRegister(instr->value());
5149  __ Cmp(reg, instr->hydrogen()->object().handle());
5150  DeoptimizeIf(not_equal, instr, "value mismatch");
5151 }
5152 
5153 
5154 void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) {
5155  {
5156  PushSafepointRegistersScope scope(this);
5157  __ Push(object);
5158  __ Set(rsi, 0);
5159  __ CallRuntimeSaveDoubles(Runtime::kTryMigrateInstance);
5161  instr->pointer_map(), 1, Safepoint::kNoLazyDeopt);
5162 
5163  __ testp(rax, Immediate(kSmiTagMask));
5164  }
5165  DeoptimizeIf(zero, instr, "instance migration failed");
5166 }
5167 
5168 
5169 void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
5170  class DeferredCheckMaps FINAL : public LDeferredCode {
5171  public:
5172  DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object)
5173  : LDeferredCode(codegen), instr_(instr), object_(object) {
5174  SetExit(check_maps());
5175  }
5176  virtual void Generate() OVERRIDE {
5177  codegen()->DoDeferredInstanceMigration(instr_, object_);
5178  }
5179  Label* check_maps() { return &check_maps_; }
5180  virtual LInstruction* instr() OVERRIDE { return instr_; }
5181  private:
5182  LCheckMaps* instr_;
5183  Label check_maps_;
5184  Register object_;
5185  };
5186 
5187  if (instr->hydrogen()->IsStabilityCheck()) {
5188  const UniqueSet<Map>* maps = instr->hydrogen()->maps();
5189  for (int i = 0; i < maps->size(); ++i) {
5190  AddStabilityDependency(maps->at(i).handle());
5191  }
5192  return;
5193  }
5194 
5195  LOperand* input = instr->value();
5196  DCHECK(input->IsRegister());
5197  Register reg = ToRegister(input);
5198 
5199  DeferredCheckMaps* deferred = NULL;
5200  if (instr->hydrogen()->HasMigrationTarget()) {
5201  deferred = new(zone()) DeferredCheckMaps(this, instr, reg);
5202  __ bind(deferred->check_maps());
5203  }
5204 
5205  const UniqueSet<Map>* maps = instr->hydrogen()->maps();
5206  Label success;
5207  for (int i = 0; i < maps->size() - 1; i++) {
5208  Handle<Map> map = maps->at(i).handle();
5209  __ CompareMap(reg, map);
5210  __ j(equal, &success, Label::kNear);
5211  }
5212 
5213  Handle<Map> map = maps->at(maps->size() - 1).handle();
5214  __ CompareMap(reg, map);
5215  if (instr->hydrogen()->HasMigrationTarget()) {
5216  __ j(not_equal, deferred->entry());
5217  } else {
5218  DeoptimizeIf(not_equal, instr, "wrong map");
5219  }
5220 
5221  __ bind(&success);
5222 }
5223 
5224 
5225 void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
5226  XMMRegister value_reg = ToDoubleRegister(instr->unclamped());
5227  XMMRegister xmm_scratch = double_scratch0();
5228  Register result_reg = ToRegister(instr->result());
5229  __ ClampDoubleToUint8(value_reg, xmm_scratch, result_reg);
5230 }
5231 
5232 
5233 void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
5234  DCHECK(instr->unclamped()->Equals(instr->result()));
5235  Register value_reg = ToRegister(instr->result());
5236  __ ClampUint8(value_reg);
5237 }
5238 
5239 
5240 void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
5241  DCHECK(instr->unclamped()->Equals(instr->result()));
5242  Register input_reg = ToRegister(instr->unclamped());
5243  XMMRegister temp_xmm_reg = ToDoubleRegister(instr->temp_xmm());
5244  XMMRegister xmm_scratch = double_scratch0();
5245  Label is_smi, done, heap_number;
5246  Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear;
5247  __ JumpIfSmi(input_reg, &is_smi, dist);
5248 
5249  // Check for heap number
5250  __ Cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5251  factory()->heap_number_map());
5252  __ j(equal, &heap_number, Label::kNear);
5253 
5254  // Check for undefined. Undefined is converted to zero for clamping
5255  // conversions.
5256  __ Cmp(input_reg, factory()->undefined_value());
5257  DeoptimizeIf(not_equal, instr, "not a heap number/undefined");
5258  __ xorl(input_reg, input_reg);
5259  __ jmp(&done, Label::kNear);
5260 
5261  // Heap number
5262  __ bind(&heap_number);
5263  __ movsd(xmm_scratch, FieldOperand(input_reg, HeapNumber::kValueOffset));
5264  __ ClampDoubleToUint8(xmm_scratch, temp_xmm_reg, input_reg);
5265  __ jmp(&done, Label::kNear);
5266 
5267  // smi
5268  __ bind(&is_smi);
5269  __ SmiToInteger32(input_reg, input_reg);
5270  __ ClampUint8(input_reg);
5271 
5272  __ bind(&done);
5273 }
5274 
5275 
5276 void LCodeGen::DoDoubleBits(LDoubleBits* instr) {
5277  XMMRegister value_reg = ToDoubleRegister(instr->value());
5278  Register result_reg = ToRegister(instr->result());
5279  if (instr->hydrogen()->bits() == HDoubleBits::HIGH) {
5280  __ movq(result_reg, value_reg);
5281  __ shrq(result_reg, Immediate(32));
5282  } else {
5283  __ movd(result_reg, value_reg);
5284  }
5285 }
5286 
5287 
5288 void LCodeGen::DoConstructDouble(LConstructDouble* instr) {
5289  Register hi_reg = ToRegister(instr->hi());
5290  Register lo_reg = ToRegister(instr->lo());
5291  XMMRegister result_reg = ToDoubleRegister(instr->result());
5292  XMMRegister xmm_scratch = double_scratch0();
5293  __ movd(result_reg, hi_reg);
5294  __ psllq(result_reg, 32);
5295  __ movd(xmm_scratch, lo_reg);
5296  __ orps(result_reg, xmm_scratch);
5297 }
5298 
5299 
5300 void LCodeGen::DoAllocate(LAllocate* instr) {
5301  class DeferredAllocate FINAL : public LDeferredCode {
5302  public:
5303  DeferredAllocate(LCodeGen* codegen, LAllocate* instr)
5304  : LDeferredCode(codegen), instr_(instr) { }
5305  virtual void Generate() OVERRIDE {
5306  codegen()->DoDeferredAllocate(instr_);
5307  }
5308  virtual LInstruction* instr() OVERRIDE { return instr_; }
5309  private:
5310  LAllocate* instr_;
5311  };
5312 
5313  DeferredAllocate* deferred =
5314  new(zone()) DeferredAllocate(this, instr);
5315 
5316  Register result = ToRegister(instr->result());
5317  Register temp = ToRegister(instr->temp());
5318 
5319  // Allocate memory for the object.
5321  if (instr->hydrogen()->MustAllocateDoubleAligned()) {
5322  flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
5323  }
5324  if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
5325  DCHECK(!instr->hydrogen()->IsOldDataSpaceAllocation());
5326  DCHECK(!instr->hydrogen()->IsNewSpaceAllocation());
5328  } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
5329  DCHECK(!instr->hydrogen()->IsNewSpaceAllocation());
5331  }
5332 
5333  if (instr->size()->IsConstantOperand()) {
5334  int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5336  __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
5337  } else {
5338  __ jmp(deferred->entry());
5339  }
5340  } else {
5341  Register size = ToRegister(instr->size());
5342  __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
5343  }
5344 
5345  __ bind(deferred->exit());
5346 
5347  if (instr->hydrogen()->MustPrefillWithFiller()) {
5348  if (instr->size()->IsConstantOperand()) {
5349  int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5350  __ movl(temp, Immediate((size / kPointerSize) - 1));
5351  } else {
5352  temp = ToRegister(instr->size());
5353  __ sarp(temp, Immediate(kPointerSizeLog2));
5354  __ decl(temp);
5355  }
5356  Label loop;
5357  __ bind(&loop);
5358  __ Move(FieldOperand(result, temp, times_pointer_size, 0),
5359  isolate()->factory()->one_pointer_filler_map());
5360  __ decl(temp);
5361  __ j(not_zero, &loop);
5362  }
5363 }
5364 
5365 
5366 void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
5367  Register result = ToRegister(instr->result());
5368 
5369  // TODO(3095996): Get rid of this. For now, we need to make the
5370  // result register contain a valid pointer because it is already
5371  // contained in the register pointer map.
5372  __ Move(result, Smi::FromInt(0));
5373 
5374  PushSafepointRegistersScope scope(this);
5375  if (instr->size()->IsRegister()) {
5376  Register size = ToRegister(instr->size());
5377  DCHECK(!size.is(result));
5378  __ Integer32ToSmi(size, size);
5379  __ Push(size);
5380  } else {
5381  int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5383  }
5384 
5385  int flags = 0;
5386  if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
5387  DCHECK(!instr->hydrogen()->IsOldDataSpaceAllocation());
5388  DCHECK(!instr->hydrogen()->IsNewSpaceAllocation());
5390  } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
5391  DCHECK(!instr->hydrogen()->IsNewSpaceAllocation());
5393  } else {
5395  }
5397 
5399  Runtime::kAllocateInTargetSpace, 2, instr, instr->context());
5400  __ StoreToSafepointRegisterSlot(result, rax);
5401 }
5402 
5403 
5404 void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
5405  DCHECK(ToRegister(instr->value()).is(rax));
5406  __ Push(rax);
5407  CallRuntime(Runtime::kToFastProperties, 1, instr);
5408 }
5409 
5410 
5411 void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
5412  DCHECK(ToRegister(instr->context()).is(rsi));
5413  Label materialized;
5414  // Registers will be used as follows:
5415  // rcx = literals array.
5416  // rbx = regexp literal.
5417  // rax = regexp literal clone.
5418  int literal_offset =
5419  FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index());
5420  __ Move(rcx, instr->hydrogen()->literals());
5421  __ movp(rbx, FieldOperand(rcx, literal_offset));
5422  __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
5423  __ j(not_equal, &materialized, Label::kNear);
5424 
5425  // Create regexp literal using runtime function
5426  // Result will be in rax.
5427  __ Push(rcx);
5428  __ Push(Smi::FromInt(instr->hydrogen()->literal_index()));
5429  __ Push(instr->hydrogen()->pattern());
5430  __ Push(instr->hydrogen()->flags());
5431  CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
5432  __ movp(rbx, rax);
5433 
5434  __ bind(&materialized);
5436  Label allocated, runtime_allocate;
5437  __ Allocate(size, rax, rcx, rdx, &runtime_allocate, TAG_OBJECT);
5438  __ jmp(&allocated, Label::kNear);
5439 
5440  __ bind(&runtime_allocate);
5441  __ Push(rbx);
5443  CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
5444  __ Pop(rbx);
5445 
5446  __ bind(&allocated);
5447  // Copy the content into the newly allocated memory.
5448  // (Unroll copy loop once for better throughput).
5449  for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
5450  __ movp(rdx, FieldOperand(rbx, i));
5451  __ movp(rcx, FieldOperand(rbx, i + kPointerSize));
5452  __ movp(FieldOperand(rax, i), rdx);
5453  __ movp(FieldOperand(rax, i + kPointerSize), rcx);
5454  }
5455  if ((size % (2 * kPointerSize)) != 0) {
5456  __ movp(rdx, FieldOperand(rbx, size - kPointerSize));
5457  __ movp(FieldOperand(rax, size - kPointerSize), rdx);
5458  }
5459 }
5460 
5461 
5462 void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
5463  DCHECK(ToRegister(instr->context()).is(rsi));
5464  // Use the fast case closure allocation code that allocates in new
5465  // space for nested functions that don't need literals cloning.
5466  bool pretenure = instr->hydrogen()->pretenure();
5467  if (!pretenure && instr->hydrogen()->has_no_literals()) {
5468  FastNewClosureStub stub(isolate(), instr->hydrogen()->strict_mode(),
5469  instr->hydrogen()->kind());
5470  __ Move(rbx, instr->hydrogen()->shared_info());
5471  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
5472  } else {
5473  __ Push(rsi);
5474  __ Push(instr->hydrogen()->shared_info());
5475  __ PushRoot(pretenure ? Heap::kTrueValueRootIndex :
5476  Heap::kFalseValueRootIndex);
5477  CallRuntime(Runtime::kNewClosure, 3, instr);
5478  }
5479 }
5480 
5481 
5482 void LCodeGen::DoTypeof(LTypeof* instr) {
5483  DCHECK(ToRegister(instr->context()).is(rsi));
5484  LOperand* input = instr->value();
5485  EmitPushTaggedOperand(input);
5486  CallRuntime(Runtime::kTypeof, 1, instr);
5487 }
5488 
5489 
5490 void LCodeGen::EmitPushTaggedOperand(LOperand* operand) {
5491  DCHECK(!operand->IsDoubleRegister());
5492  if (operand->IsConstantOperand()) {
5493  __ Push(ToHandle(LConstantOperand::cast(operand)));
5494  } else if (operand->IsRegister()) {
5495  __ Push(ToRegister(operand));
5496  } else {
5497  __ Push(ToOperand(operand));
5498  }
5499 }
5500 
5501 
5502 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
5503  Register input = ToRegister(instr->value());
5504  Condition final_branch_condition = EmitTypeofIs(instr, input);
5505  if (final_branch_condition != no_condition) {
5506  EmitBranch(instr, final_branch_condition);
5507  }
5508 }
5509 
5510 
5511 Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) {
5512  Label* true_label = instr->TrueLabel(chunk_);
5513  Label* false_label = instr->FalseLabel(chunk_);
5514  Handle<String> type_name = instr->type_literal();
5515  int left_block = instr->TrueDestination(chunk_);
5516  int right_block = instr->FalseDestination(chunk_);
5517  int next_block = GetNextEmittedBlock();
5518 
5519  Label::Distance true_distance = left_block == next_block ? Label::kNear
5520  : Label::kFar;
5521  Label::Distance false_distance = right_block == next_block ? Label::kNear
5522  : Label::kFar;
5523  Condition final_branch_condition = no_condition;
5524  Factory* factory = isolate()->factory();
5525  if (String::Equals(type_name, factory->number_string())) {
5526  __ JumpIfSmi(input, true_label, true_distance);
5527  __ CompareRoot(FieldOperand(input, HeapObject::kMapOffset),
5528  Heap::kHeapNumberMapRootIndex);
5529 
5530  final_branch_condition = equal;
5531 
5532  } else if (String::Equals(type_name, factory->string_string())) {
5533  __ JumpIfSmi(input, false_label, false_distance);
5534  __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
5535  __ j(above_equal, false_label, false_distance);
5536  __ testb(FieldOperand(input, Map::kBitFieldOffset),
5537  Immediate(1 << Map::kIsUndetectable));
5538  final_branch_condition = zero;
5539 
5540  } else if (String::Equals(type_name, factory->symbol_string())) {
5541  __ JumpIfSmi(input, false_label, false_distance);
5542  __ CmpObjectType(input, SYMBOL_TYPE, input);
5543  final_branch_condition = equal;
5544 
5545  } else if (String::Equals(type_name, factory->boolean_string())) {
5546  __ CompareRoot(input, Heap::kTrueValueRootIndex);
5547  __ j(equal, true_label, true_distance);
5548  __ CompareRoot(input, Heap::kFalseValueRootIndex);
5549  final_branch_condition = equal;
5550 
5551  } else if (String::Equals(type_name, factory->undefined_string())) {
5552  __ CompareRoot(input, Heap::kUndefinedValueRootIndex);
5553  __ j(equal, true_label, true_distance);
5554  __ JumpIfSmi(input, false_label, false_distance);
5555  // Check for undetectable objects => true.
5556  __ movp(input, FieldOperand(input, HeapObject::kMapOffset));
5557  __ testb(FieldOperand(input, Map::kBitFieldOffset),
5558  Immediate(1 << Map::kIsUndetectable));
5559  final_branch_condition = not_zero;
5560 
5561  } else if (String::Equals(type_name, factory->function_string())) {
5563  __ JumpIfSmi(input, false_label, false_distance);
5564  __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
5565  __ j(equal, true_label, true_distance);
5566  __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
5567  final_branch_condition = equal;
5568 
5569  } else if (String::Equals(type_name, factory->object_string())) {
5570  __ JumpIfSmi(input, false_label, false_distance);
5571  __ CompareRoot(input, Heap::kNullValueRootIndex);
5572  __ j(equal, true_label, true_distance);
5573  __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
5574  __ j(below, false_label, false_distance);
5575  __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
5576  __ j(above, false_label, false_distance);
5577  // Check for undetectable objects => false.
5578  __ testb(FieldOperand(input, Map::kBitFieldOffset),
5579  Immediate(1 << Map::kIsUndetectable));
5580  final_branch_condition = zero;
5581 
5582  } else {
5583  __ jmp(false_label, false_distance);
5584  }
5585 
5586  return final_branch_condition;
5587 }
5588 
5589 
5590 void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
5591  Register temp = ToRegister(instr->temp());
5592 
5593  EmitIsConstructCall(temp);
5594  EmitBranch(instr, equal);
5595 }
5596 
5597 
5598 void LCodeGen::EmitIsConstructCall(Register temp) {
5599  // Get the frame pointer for the calling frame.
5600  __ movp(temp, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
5601 
5602  // Skip the arguments adaptor frame if it exists.
5603  Label check_frame_marker;
5604  __ Cmp(Operand(temp, StandardFrameConstants::kContextOffset),
5606  __ j(not_equal, &check_frame_marker, Label::kNear);
5607  __ movp(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
5608 
5609  // Check the marker in the calling frame.
5610  __ bind(&check_frame_marker);
5611  __ Cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
5612  Smi::FromInt(StackFrame::CONSTRUCT));
5613 }
5614 
5615 
5616 void LCodeGen::EnsureSpaceForLazyDeopt(int space_needed) {
5617  if (!info()->IsStub()) {
5618  // Ensure that we have enough space after the previous lazy-bailout
5619  // instruction for patching the code here.
5620  int current_pc = masm()->pc_offset();
5621  if (current_pc < last_lazy_deopt_pc_ + space_needed) {
5622  int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
5623  __ Nop(padding_size);
5624  }
5625  }
5626  last_lazy_deopt_pc_ = masm()->pc_offset();
5627 }
5628 
5629 
5630 void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
5631  last_lazy_deopt_pc_ = masm()->pc_offset();
5632  DCHECK(instr->HasEnvironment());
5633  LEnvironment* env = instr->environment();
5634  RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5635  safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
5636 }
5637 
5638 
5639 void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
5640  Deoptimizer::BailoutType type = instr->hydrogen()->type();
5641  // TODO(danno): Stubs expect all deopts to be lazy for historical reasons (the
5642  // needed return address), even though the implementation of LAZY and EAGER is
5643  // now identical. When LAZY is eventually completely folded into EAGER, remove
5644  // the special case below.
5645  if (info()->IsStub() && type == Deoptimizer::EAGER) {
5646  type = Deoptimizer::LAZY;
5647  }
5648  DeoptimizeIf(no_condition, instr, instr->hydrogen()->reason(), type);
5649 }
5650 
5651 
5652 void LCodeGen::DoDummy(LDummy* instr) {
5653  // Nothing to see here, move on!
5654 }
5655 
5656 
5657 void LCodeGen::DoDummyUse(LDummyUse* instr) {
5658  // Nothing to see here, move on!
5659 }
5660 
5661 
5662 void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
5663  PushSafepointRegistersScope scope(this);
5665  __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
5667  DCHECK(instr->HasEnvironment());
5668  LEnvironment* env = instr->environment();
5669  safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
5670 }
5671 
5672 
5673 void LCodeGen::DoStackCheck(LStackCheck* instr) {
5674  class DeferredStackCheck FINAL : public LDeferredCode {
5675  public:
5676  DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
5677  : LDeferredCode(codegen), instr_(instr) { }
5678  virtual void Generate() OVERRIDE {
5679  codegen()->DoDeferredStackCheck(instr_);
5680  }
5681  virtual LInstruction* instr() OVERRIDE { return instr_; }
5682  private:
5683  LStackCheck* instr_;
5684  };
5685 
5686  DCHECK(instr->HasEnvironment());
5687  LEnvironment* env = instr->environment();
5688  // There is no LLazyBailout instruction for stack-checks. We have to
5689  // prepare for lazy deoptimization explicitly here.
5690  if (instr->hydrogen()->is_function_entry()) {
5691  // Perform stack overflow check.
5692  Label done;
5693  __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
5694  __ j(above_equal, &done, Label::kNear);
5695 
5696  DCHECK(instr->context()->IsRegister());
5697  DCHECK(ToRegister(instr->context()).is(rsi));
5698  CallCode(isolate()->builtins()->StackCheck(),
5700  instr);
5701  __ bind(&done);
5702  } else {
5703  DCHECK(instr->hydrogen()->is_backwards_branch());
5704  // Perform stack overflow check if this goto needs it before jumping.
5705  DeferredStackCheck* deferred_stack_check =
5706  new(zone()) DeferredStackCheck(this, instr);
5707  __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
5708  __ j(below, deferred_stack_check->entry());
5710  __ bind(instr->done_label());
5711  deferred_stack_check->SetExit(instr->done_label());
5712  RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5713  // Don't record a deoptimization index for the safepoint here.
5714  // This will be done explicitly when emitting call and the safepoint in
5715  // the deferred code.
5716  }
5717 }
5718 
5719 
5720 void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
5721  // This is a pseudo-instruction that ensures that the environment here is
5722  // properly registered for deoptimization and records the assembler's PC
5723  // offset.
5724  LEnvironment* environment = instr->environment();
5725 
5726  // If the environment were already registered, we would have no way of
5727  // backpatching it with the spill slot operands.
5728  DCHECK(!environment->HasBeenRegistered());
5729  RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
5730 
5732 }
5733 
5734 
5735 void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
5736  DCHECK(ToRegister(instr->context()).is(rsi));
5737  __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
5738  DeoptimizeIf(equal, instr, "undefined");
5739 
5740  Register null_value = rdi;
5741  __ LoadRoot(null_value, Heap::kNullValueRootIndex);
5742  __ cmpp(rax, null_value);
5743  DeoptimizeIf(equal, instr, "null");
5744 
5745  Condition cc = masm()->CheckSmi(rax);
5746  DeoptimizeIf(cc, instr, "Smi");
5747 
5749  __ CmpObjectType(rax, LAST_JS_PROXY_TYPE, rcx);
5750  DeoptimizeIf(below_equal, instr, "wrong instance type");
5751 
5752  Label use_cache, call_runtime;
5753  __ CheckEnumCache(null_value, &call_runtime);
5754 
5756  __ jmp(&use_cache, Label::kNear);
5757 
5758  // Get the set of properties to enumerate.
5759  __ bind(&call_runtime);
5760  __ Push(rax);
5761  CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
5762 
5763  __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
5764  Heap::kMetaMapRootIndex);
5765  DeoptimizeIf(not_equal, instr, "wrong map");
5766  __ bind(&use_cache);
5767 }
5768 
5769 
5770 void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
5771  Register map = ToRegister(instr->map());
5772  Register result = ToRegister(instr->result());
5773  Label load_cache, done;
5774  __ EnumLength(result, map);
5775  __ Cmp(result, Smi::FromInt(0));
5776  __ j(not_equal, &load_cache, Label::kNear);
5777  __ LoadRoot(result, Heap::kEmptyFixedArrayRootIndex);
5778  __ jmp(&done, Label::kNear);
5779  __ bind(&load_cache);
5780  __ LoadInstanceDescriptors(map, result);
5781  __ movp(result,
5783  __ movp(result,
5784  FieldOperand(result, FixedArray::SizeFor(instr->idx())));
5785  __ bind(&done);
5786  Condition cc = masm()->CheckSmi(result);
5787  DeoptimizeIf(cc, instr, "no cache");
5788 }
5789 
5790 
5791 void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
5792  Register object = ToRegister(instr->value());
5793  __ cmpp(ToRegister(instr->map()),
5795  DeoptimizeIf(not_equal, instr, "wrong map");
5796 }
5797 
5798 
5799 void LCodeGen::DoDeferredLoadMutableDouble(LLoadFieldByIndex* instr,
5800  Register object,
5801  Register index) {
5802  PushSafepointRegistersScope scope(this);
5803  __ Push(object);
5804  __ Push(index);
5805  __ xorp(rsi, rsi);
5806  __ CallRuntimeSaveDoubles(Runtime::kLoadMutableDouble);
5808  instr->pointer_map(), 2, Safepoint::kNoLazyDeopt);
5809  __ StoreToSafepointRegisterSlot(object, rax);
5810 }
5811 
5812 
5813 void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
5814  class DeferredLoadMutableDouble FINAL : public LDeferredCode {
5815  public:
5816  DeferredLoadMutableDouble(LCodeGen* codegen,
5817  LLoadFieldByIndex* instr,
5818  Register object,
5819  Register index)
5820  : LDeferredCode(codegen),
5821  instr_(instr),
5822  object_(object),
5823  index_(index) {
5824  }
5825  virtual void Generate() OVERRIDE {
5826  codegen()->DoDeferredLoadMutableDouble(instr_, object_, index_);
5827  }
5828  virtual LInstruction* instr() OVERRIDE { return instr_; }
5829  private:
5830  LLoadFieldByIndex* instr_;
5831  Register object_;
5832  Register index_;
5833  };
5834 
5835  Register object = ToRegister(instr->object());
5836  Register index = ToRegister(instr->index());
5837 
5838  DeferredLoadMutableDouble* deferred;
5839  deferred = new(zone()) DeferredLoadMutableDouble(this, instr, object, index);
5840 
5841  Label out_of_object, done;
5842  __ Move(kScratchRegister, Smi::FromInt(1));
5843  __ testp(index, kScratchRegister);
5844  __ j(not_zero, deferred->entry());
5845 
5846  __ sarp(index, Immediate(1));
5847 
5848  __ SmiToInteger32(index, index);
5849  __ cmpl(index, Immediate(0));
5850  __ j(less, &out_of_object, Label::kNear);
5851  __ movp(object, FieldOperand(object,
5852  index,
5855  __ jmp(&done, Label::kNear);
5856 
5857  __ bind(&out_of_object);
5858  __ movp(object, FieldOperand(object, JSObject::kPropertiesOffset));
5859  __ negl(index);
5860  // Index is now equal to out of object property index plus 1.
5861  __ movp(object, FieldOperand(object,
5862  index,
5865  __ bind(deferred->exit());
5866  __ bind(&done);
5867 }
5868 
5869 
5870 void LCodeGen::DoStoreFrameContext(LStoreFrameContext* instr) {
5871  Register context = ToRegister(instr->context());
5872  __ movp(Operand(rbp, StandardFrameConstants::kContextOffset), context);
5873 }
5874 
5875 
5876 void LCodeGen::DoAllocateBlockContext(LAllocateBlockContext* instr) {
5877  Handle<ScopeInfo> scope_info = instr->scope_info();
5878  __ Push(scope_info);
5879  __ Push(ToRegister(instr->function()));
5880  CallRuntime(Runtime::kPushBlockContext, 2, instr);
5881  RecordSafepoint(Safepoint::kNoLazyDeopt);
5882 }
5883 
5884 
5885 #undef __
5886 
5887 } } // namespace v8::internal
5888 
5889 #endif // V8_TARGET_ARCH_X64
static AllocationSiteMode GetMode(ElementsKind boilerplate_elements_kind)
Definition: objects-inl.h:1591
static RelocInfo::Mode RelocInfoNone()
static U update(U previous, T value)
Definition: utils.h:223
static const int kHeaderSize
Definition: objects.h:5373
static int SlotOffset(int index)
Definition: contexts.h:552
static bool IsSupported(CpuFeature f)
Definition: assembler.h:184
static Handle< DeoptimizationInputData > New(Isolate *isolate, int deopt_entry_count, PretenureFlag pretenure)
Definition: objects.cc:7918
static Address GetDeoptimizationEntry(Isolate *isolate, int id, BailoutType type, GetEntryMode mode=ENSURE_ENTRY_CODE)
Definition: deoptimizer.cc:672
static const int kEnumCacheOffset
Definition: objects.h:3028
static const int kHeaderSize
Definition: objects.h:2393
static int OffsetOfElementAt(int index)
Definition: objects.h:2455
static int SizeFor(int length)
Definition: objects.h:2452
static double canonical_not_the_hole_nan_as_double()
Definition: objects-inl.h:2210
static const int kGlobalProxyOffset
Definition: objects.h:7461
static Handle< T > cast(Handle< S > that)
Definition: handles.h:116
static Handle< T > null()
Definition: handles.h:123
static const uint32_t kSignMask
Definition: objects.h:1522
static const int kValueOffset
Definition: objects.h:1506
static const int kMapOffset
Definition: objects.h:1427
static const int kValueOffset
Definition: objects.h:7623
static const int kCacheStampOffset
Definition: objects.h:7631
static const int kSharedFunctionInfoOffset
Definition: objects.h:7379
static const int kContextOffset
Definition: objects.h:7381
static const int kCodeEntryOffset
Definition: objects.h:7376
static const int kPrototypeOrInitialMapOffset
Definition: objects.h:7377
static const int kHeaderSize
Definition: objects.h:2195
static const int kPropertiesOffset
Definition: objects.h:2193
static const int kSize
Definition: objects.h:7772
static const int kInObjectFieldCount
Definition: objects.h:7826
bool IsNextEmittedBlock(int block_id) const
void DoStoreKeyedFixedArray(LStoreKeyed *instr)
DwVfpRegister ToDoubleRegister(LOperand *op) const
void RecordSafepointWithRegisters(LPointerMap *pointers, int arguments, Safepoint::DeoptMode mode)
TranslationBuffer translations_
MemOperand BuildSeqStringOperand(Register string, LOperand *index, String::Encoding encoding)
bool IsSmiConstant(LConstantOperand *op) const
Condition EmitIsString(Register input, Register temp1, Label *is_not_string, SmiCheck check_needed)
void DoDeferredStackCheck(LStackCheck *instr)
SafepointTableBuilder safepoints_
void EmitVectorLoadICRegisters(T *instr)
static Condition TokenToCondition(Token::Value op, bool is_unsigned)
ZoneList< Handle< Object > > deoptimization_literals_
void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal *instr, Label *map_check, Label *bool_load)
void PopulateDeoptimizationLiteralsWithInlinedFunctions()
void AddToTranslation(LEnvironment *environment, Translation *translation, LOperand *op, bool is_tagged, bool is_uint32, int *object_index_pointer, int *dematerialized_index_pointer)
ZoneList< LEnvironment * > deoptimizations_
void EmitIntegerMathAbs(LMathAbs *instr)
int32_t ToRepresentation(LConstantOperand *op, const Representation &r) const
void CallRuntimeFromDeferred(Runtime::FunctionId id, int argc, LInstruction *instr, LOperand *context)
void EmitIsConstructCall(Register temp1, Register temp2)
void EmitPushTaggedOperand(LOperand *operand)
int32_t ToInteger32(LConstantOperand *op) const
LPlatformChunk * chunk() const
void FinishCode(Handle< Code > code)
ExternalReference ToExternalReference(LConstantOperand *op) const
Condition EmitTypeofIs(Label *true_label, Label *false_label, Register input, Handle< String > type_name)
void DoDeferredAllocate(LAllocate *instr)
void RecordSafepoint(LPointerMap *pointers, Safepoint::Kind kind, int arguments, Safepoint::DeoptMode mode)
void DoDeferredTaggedToI(LTaggedToI *instr)
LowDwVfpRegister double_scratch0()
void CallCodeGeneric(Handle< Code > code, RelocInfo::Mode mode, LInstruction *instr, SafepointMode safepoint_mode, TargetAddressStorageMode storage_mode=CAN_INLINE_TARGET_ADDRESS)
void DoDeferredStringCharCodeAt(LStringCharCodeAt *instr)
void CallCode(Handle< Code > code, RelocInfo::Mode mode, LInstruction *instr, TargetAddressStorageMode storage_mode=CAN_INLINE_TARGET_ADDRESS)
Safepoint::Kind expected_safepoint_kind_
ZoneList< LDeferredCode * > deferred_
void DoDeferredNumberTagIU(LInstruction *instr, LOperand *value, LOperand *temp1, LOperand *temp2, IntegerSignedness signedness)
Handle< Object > ToHandle(LConstantOperand *op) const
void GenerateBodyInstructionPost(LInstruction *instr) OVERRIDE
void RegisterEnvironmentForDeoptimization(LEnvironment *environment, Safepoint::DeoptMode mode)
void LoadContextFromDeferred(LOperand *context)
bool IsDehoistedKeyConstant(LConstantOperand *op) const
Operand BuildFastArrayOperand(LOperand *elements_pointer, LOperand *key, Representation key_representation, ElementsKind elements_kind, uint32_t base_offset)
void DoDeferredInstanceMigration(LCheckMaps *instr, Register object)
void DoDeferredLoadMutableDouble(LLoadFieldByIndex *instr, Register result, Register object, Register index)
int DefineDeoptimizationLiteral(Handle< Object > literal)
void DeoptimizeIf(Condition condition, LInstruction *instr, const char *detail, Deoptimizer::BailoutType bailout_type)
void CallKnownFunction(Handle< JSFunction > function, int formal_parameter_count, int arity, LInstruction *instr, R1State r1_state)
void WriteTranslation(LEnvironment *environment, Translation *translation)
void DoDeferredMathAbsTaggedHeapNumber(LMathAbs *instr)
void DoLoadKeyedFixedDoubleArray(LLoadKeyed *instr)
Operand ToOperand(LOperand *op)
void EmitClassOfTest(Label *if_true, Label *if_false, Handle< String > class_name, Register input, Register temporary, Register temporary2)
void DoLoadKeyedExternalArray(LLoadKeyed *instr)
double ToDouble(LConstantOperand *op) const
Register ToRegister(LOperand *op) const
void DoStoreKeyedExternalArray(LStoreKeyed *instr)
void RecordAndWritePosition(int position) OVERRIDE
void PopulateDeoptimizationData(Handle< Code > code)
void DoParallelMove(LParallelMove *move)
Smi * ToSmi(LConstantOperand *op) const
void CallRuntime(const Runtime::Function *function, int num_arguments, LInstruction *instr, SaveFPRegsMode save_doubles=kDontSaveFPRegs)
bool IsInteger32Constant(LConstantOperand *op) const
void DoDeferredStringCharFromCode(LStringCharFromCode *instr)
ZoneList< Deoptimizer::JumpTableEntry > jump_table_
Condition EmitIsObject(Register input, Register temp1, Label *is_not_object, Label *is_object)
void EnsureSpaceForLazyDeopt(int space_needed) OVERRIDE
void EmitNumberUntagD(LNumberUntagD *instr, Register input, DwVfpRegister result, NumberUntagDMode mode)
void GenerateBodyInstructionPre(LInstruction *instr) OVERRIDE
void RecordSafepointWithLazyDeopt(LInstruction *instr, SafepointMode safepoint_mode)
void EmitFalseBranch(InstrType instr, Condition condition)
void DoLoadKeyedFixedArray(LLoadKeyed *instr)
LCodeGen(LChunk *chunk, MacroAssembler *assembler, CompilationInfo *info)
void EmitBranch(InstrType instr, Condition condition)
void DoDeferredNumberTagD(LNumberTagD *instr)
void DoStoreKeyedFixedDoubleArray(LStoreKeyed *instr)
void EmitSmiMathAbs(LMathAbs *instr)
void Add(const T &element, AllocationPolicy allocator=AllocationPolicy())
Definition: list-inl.h:17
static const Register ReceiverRegister()
static const Register NameRegister()
static void GenerateMiss(MacroAssembler *masm)
static const int kIsUndetectable
Definition: objects.h:6244
static const int kBitFieldOffset
Definition: objects.h:6228
static const int kInstanceTypeOffset
Definition: objects.h:6229
static const int kConstructorOffset
Definition: objects.h:6191
static const int kPrototypeOffset
Definition: objects.h:6190
static void EmitMathExp(MacroAssembler *masm, DwVfpRegister input, DwVfpRegister result, DwVfpRegister double_scratch1, DwVfpRegister double_scratch2, Register temp1, Register temp2, Register temp3)
static const Register exponent()
static const int kHashShift
Definition: objects.h:8499
static const int kHashFieldOffset
Definition: objects.h:8486
static const int kMaxRegularHeapObjectSize
Definition: spaces.h:754
static void MaybeCallEntryHook(MacroAssembler *masm)
static const int kNoPosition
Definition: assembler.h:317
static Representation Smi()
static Representation Integer32()
int num_parameters() const
Definition: scopes.h:321
Variable * parameter(int index) const
Definition: scopes.h:316
static const int kHeaderSize
Definition: objects.h:8941
static const int kDontAdaptArgumentsSentinel
Definition: objects.h:6888
static const int kInstanceClassNameOffset
Definition: objects.h:6897
static const int kNativeBitWithinByte
Definition: objects.h:7046
static const int kStrictModeBitWithinByte
Definition: objects.h:7043
static const int kMaxValue
Definition: objects.h:1272
static Smi * FromInt(int value)
Definition: objects-inl.h:1321
static const int kContextOffset
Definition: frames.h:162
static const int kCallerSPOffset
Definition: frames.h:167
static const int kMarkerOffset
Definition: frames.h:161
static const int kCallerFPOffset
Definition: frames.h:165
static const Register ReceiverRegister()
static const Register NameRegister()
static const Register ValueRegister()
static Handle< Code > initialize_stub(Isolate *isolate, StrictMode strict_mode)
Definition: ic.cc:1346
static void Generate(MacroAssembler *masm, Register string, Register index, Register result, Label *call_runtime)
static const unsigned int kContainsCachedArrayIndexMask
Definition: objects.h:8618
static const int32_t kMaxOneByteCharCode
Definition: objects.h:8811
static const int kMaxLength
Definition: objects.h:8820
static const int kLengthOffset
Definition: objects.h:8802
static const int kMaxUtf16CodeUnit
Definition: objects.h:8813
bool Equals(String *other)
Definition: objects-inl.h:3336
static const Register VectorRegister()
#define OVERRIDE
#define FINAL
#define __
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 literals(0o77, 0b11)") DEFINE_BOOL(harmony_object_literals
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 mode(MIPS only)") DEFINE_BOOL(enable_always_align_csp
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 UNREACHABLE()
Definition: logging.h:30
#define DCHECK_LE(v1, v2)
Definition: logging.h:210
#define DCHECK(condition)
Definition: logging.h:205
@ CALL_FUNCTION
AllocationFlags
@ DOUBLE_ALIGNMENT
@ PRETENURE_OLD_POINTER_SPACE
@ TAG_OBJECT
@ PRETENURE_OLD_DATA_SPACE
#define V8_INT64_C(x)
Definition: macros.h:358
int int32_t
Definition: unicode.cc:24
bool IsPowerOfTwo32(uint32_t value)
Definition: bits.h:77
static int Push(SpecialRPOStackFrame *stack, int depth, BasicBlock *child, int unvisited)
Definition: scheduler.cc:773
Vector< const char > CStrVector(const char *data)
Definition: vector.h:158
const int kPointerSize
Definition: globals.h:129
const uint32_t kStringEncodingMask
Definition: objects.h:555
MemOperand ContextOperand(Register context, int index)
static bool ExternalArrayOpRequiresTemp(Representation key_representation, ElementsKind elements_kind)
@ DO_SMI_CHECK
Definition: globals.h:641
const int KB
Definition: globals.h:106
Condition CommuteCondition(Condition cond)
Definition: constants-arm.h:93
bool EvalComparison(Token::Value op, double op1, double op2)
Definition: assembler.cc:1488
@ TRACK_ALLOCATION_SITE
Definition: objects.h:8085
@ kSeqStringTag
Definition: objects.h:563
@ ARGUMENTS_ADAPTOR
Definition: hydrogen.h:546
const XMMRegister xmm1
const int kPCOnStackSize
Definition: globals.h:135
const Register kScratchRegister
const uint32_t kTwoByteStringTag
Definition: objects.h:556
const int kSmiTagSize
Definition: v8.h:5743
const XMMRegister xmm2
const int kDoubleSize
Definition: globals.h:127
Operand FieldOperand(Register object, int offset)
const Register rsi
const Register rbp
const int kPointerSizeLog2
Definition: globals.h:147
@ LAST_NONCALLABLE_SPEC_OBJECT_TYPE
Definition: objects.h:785
@ NUM_OF_CALLABLE_SPEC_OBJECT_TYPES
Definition: objects.h:788
@ JS_DATE_TYPE
Definition: objects.h:730
@ FIRST_NONCALLABLE_SPEC_OBJECT_TYPE
Definition: objects.h:784
@ FIRST_JS_PROXY_TYPE
Definition: objects.h:778
@ JS_ARRAY_TYPE
Definition: objects.h:738
@ FIRST_NONSTRING_TYPE
Definition: objects.h:758
@ FIRST_SPEC_OBJECT_TYPE
Definition: objects.h:781
@ LAST_SPEC_OBJECT_TYPE
Definition: objects.h:782
@ HEAP_NUMBER_TYPE
Definition: objects.h:669
@ JS_FUNCTION_TYPE
Definition: objects.h:749
@ JS_FUNCTION_PROXY_TYPE
Definition: objects.h:726
@ LAST_JS_PROXY_TYPE
Definition: objects.h:779
@ EXTERNAL_UINT16_ELEMENTS
Definition: elements-kind.h:36
@ UINT8_CLAMPED_ELEMENTS
Definition: elements-kind.h:52
@ EXTERNAL_INT16_ELEMENTS
Definition: elements-kind.h:35
@ EXTERNAL_UINT8_ELEMENTS
Definition: elements-kind.h:34
@ EXTERNAL_INT32_ELEMENTS
Definition: elements-kind.h:37
@ FAST_HOLEY_DOUBLE_ELEMENTS
Definition: elements-kind.h:27
@ SLOPPY_ARGUMENTS_ELEMENTS
Definition: elements-kind.h:31
@ EXTERNAL_INT8_ELEMENTS
Definition: elements-kind.h:33
@ EXTERNAL_FLOAT32_ELEMENTS
Definition: elements-kind.h:39
@ EXTERNAL_FLOAT64_ELEMENTS
Definition: elements-kind.h:40
@ FAST_HOLEY_SMI_ELEMENTS
Definition: elements-kind.h:17
@ EXTERNAL_UINT32_ELEMENTS
Definition: elements-kind.h:38
@ EXTERNAL_UINT8_CLAMPED_ELEMENTS
Definition: elements-kind.h:41
bool IsSimpleMapChangeTransition(ElementsKind from_kind, ElementsKind to_kind)
const XMMRegister xmm3
const uint32_t kOneByteStringTag
Definition: objects.h:557
@ NO_OVERWRITE
Definition: ic-state.h:58
int ElementsKindToShiftSize(ElementsKind elements_kind)
int32_t WhichPowerOf2Abs(int32_t x)
Definition: utils.h:168
int StackSlotOffset(int index)
Definition: lithium.cc:254
@ FAIL_ON_MINUS_ZERO
Definition: globals.h:768
const Register rdi
const int kUC16Size
Definition: globals.h:187
bool IsFastPackedElementsKind(ElementsKind kind)
const int kInt64Size
Definition: globals.h:126
const bool FLAG_enable_slow_asserts
Definition: checks.h:31
@ NUMBER_CANDIDATE_IS_SMI
Definition: lithium.h:756
@ NUMBER_CANDIDATE_IS_ANY_TAGGED
Definition: lithium.h:757
ElementsKind GetHoleyElementsKind(ElementsKind packed_kind)
const int kInt32Size
Definition: globals.h:125
AllocationSiteOverrideMode
Definition: code-stubs.h:716
@ DISABLE_ALLOCATION_SITES
Definition: code-stubs.h:718
const XMMRegister xmm0
const Register rbx
Condition NegateCondition(Condition cond)
Definition: constants-arm.h:86
static InstanceType TestType(HHasInstanceTypeAndBranch *instr)
const int kMinInt
Definition: globals.h:110
T Abs(T a)
Definition: utils.h:153
const uint32_t kStringRepresentationMask
Definition: objects.h:561
@ ARGUMENTS_DONT_CONTAIN_RECEIVER
Definition: codegen-x64.h:50
byte * Address
Definition: globals.h:101
static Condition BranchCondition(HHasInstanceTypeAndBranch *instr)
@ NOT_CONTEXTUAL
Definition: objects.h:174
static bool SmiValuesAre32Bits()
Definition: v8.h:5808
@ OLD_DATA_SPACE
Definition: globals.h:361
@ OLD_POINTER_SPACE
Definition: globals.h:360
const int kFPOnStackSize
Definition: globals.h:136
const int kHeapObjectTag
Definition: v8.h:5737
const int kSmiShiftSize
Definition: v8.h:5805
const Register no_reg
const Register rdx
static int ArgumentsOffsetWithoutFrame(int index)
const Register arg_reg_1
static bool SmiValuesAre31Bits()
Definition: v8.h:5807
static const char * LabelType(LLabel *label)
const Register rax
MemOperand GlobalObjectOperand()
STATIC_ASSERT(sizeof(CPURegister)==sizeof(Register))
const intptr_t kSmiTagMask
Definition: v8.h:5744
@ NO_CALL_CONSTRUCTOR_FLAGS
Definition: globals.h:478
const int kSmiTag
Definition: v8.h:5742
bool IsFastSmiElementsKind(ElementsKind kind)
const Register rcx
const uint32_t kHoleNanLower32
Definition: globals.h:657
const uint32_t kSlotsZapValue
Definition: globals.h:273
const int kCharSize
Definition: globals.h:122
const Register rsp
const uint32_t kHoleNanUpper32
Definition: globals.h:656
PerThreadAssertScopeDebugOnly< DEFERRED_HANDLE_DEREFERENCE_ASSERT, true > AllowDeferredHandleDereference
Definition: assert-scope.h:130
const Register arg_reg_2
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20
#define IN
bool is(DwVfpRegister reg) const
static Register FromAllocationIndex(int index)
bool is(Register reg) const
static XMMRegister FromAllocationIndex(int index)
#define T(name, string, precedence)
Definition: token.cc:25