1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 #if V8_TARGET_ARCH_IA32
9 #include "src/base/bits.h"
10 #include "src/code-factory.h"
11 #include "src/code-stubs.h"
12 #include "src/codegen.h"
13 #include "src/deoptimizer.h"
14 #include "src/hydrogen-osr.h"
15 #include "src/ia32/lithium-codegen-ia32.h"
16 #include "src/ic/ic.h"
17 #include "src/ic/stub-cache.h"
22 // When invoking builtins, we need to record the safepoint in the middle of
23 // the invoke instruction sequence generated by the macro assembler.
24 class SafepointGenerator FINAL : public CallWrapper {
26 SafepointGenerator(LCodeGen* codegen,
27 LPointerMap* pointers,
28 Safepoint::DeoptMode mode)
32 virtual ~SafepointGenerator() {}
34 virtual void BeforeCall(int call_size) const OVERRIDE {}
36 virtual void AfterCall() const OVERRIDE {
37 codegen_->RecordSafepoint(pointers_, deopt_mode_);
42 LPointerMap* pointers_;
43 Safepoint::DeoptMode deopt_mode_;
49 bool LCodeGen::GenerateCode() {
50 LPhase phase("Z_Code generation", chunk());
54 // Open a frame scope to indicate that there is a frame on the stack. The
55 // MANUAL indicates that the scope shouldn't actually generate code to set up
56 // the frame (that is done in GeneratePrologue).
57 FrameScope frame_scope(masm_, StackFrame::MANUAL);
59 support_aligned_spilled_doubles_ = info()->IsOptimizing();
61 dynamic_frame_alignment_ = info()->IsOptimizing() &&
62 ((chunk()->num_double_slots() > 2 &&
63 !chunk()->graph()->is_recursive()) ||
64 !info()->osr_ast_id().IsNone());
66 return GeneratePrologue() &&
68 GenerateDeferredCode() &&
69 GenerateJumpTable() &&
70 GenerateSafepointTable();
74 void LCodeGen::FinishCode(Handle<Code> code) {
76 code->set_stack_slots(GetStackSlotCount());
77 code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
78 if (code->is_optimized_code()) RegisterWeakObjectsInOptimizedCode(code);
79 PopulateDeoptimizationData(code);
80 if (!info()->IsStub()) {
81 Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
87 void LCodeGen::MakeSureStackPagesMapped(int offset) {
88 const int kPageSize = 4 * KB;
89 for (offset -= kPageSize; offset > 0; offset -= kPageSize) {
90 __ mov(Operand(esp, offset), eax);
96 void LCodeGen::SaveCallerDoubles() {
97 DCHECK(info()->saves_caller_doubles());
98 DCHECK(NeedsEagerFrame());
99 Comment(";;; Save clobbered callee double registers");
101 BitVector* doubles = chunk()->allocated_double_registers();
102 BitVector::Iterator save_iterator(doubles);
103 while (!save_iterator.Done()) {
104 __ movsd(MemOperand(esp, count * kDoubleSize),
105 XMMRegister::FromAllocationIndex(save_iterator.Current()));
106 save_iterator.Advance();
112 void LCodeGen::RestoreCallerDoubles() {
113 DCHECK(info()->saves_caller_doubles());
114 DCHECK(NeedsEagerFrame());
115 Comment(";;; Restore clobbered callee double registers");
116 BitVector* doubles = chunk()->allocated_double_registers();
117 BitVector::Iterator save_iterator(doubles);
119 while (!save_iterator.Done()) {
120 __ movsd(XMMRegister::FromAllocationIndex(save_iterator.Current()),
121 MemOperand(esp, count * kDoubleSize));
122 save_iterator.Advance();
128 bool LCodeGen::GeneratePrologue() {
129 DCHECK(is_generating());
131 if (info()->IsOptimizing()) {
132 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
135 if (strlen(FLAG_stop_at) > 0 &&
136 info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
141 // Sloppy mode functions and builtins need to replace the receiver with the
142 // global proxy when called as functions (without an explicit receiver
144 if (info_->this_has_uses() &&
145 info_->strict_mode() == SLOPPY &&
146 !info_->is_native()) {
148 // +1 for return address.
149 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize;
150 __ mov(ecx, Operand(esp, receiver_offset));
152 __ cmp(ecx, isolate()->factory()->undefined_value());
153 __ j(not_equal, &ok, Label::kNear);
155 __ mov(ecx, GlobalObjectOperand());
156 __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalProxyOffset));
158 __ mov(Operand(esp, receiver_offset), ecx);
163 if (support_aligned_spilled_doubles_ && dynamic_frame_alignment_) {
164 // Move state of dynamic frame alignment into edx.
165 __ Move(edx, Immediate(kNoAlignmentPadding));
167 Label do_not_pad, align_loop;
168 STATIC_ASSERT(kDoubleSize == 2 * kPointerSize);
169 // Align esp + 4 to a multiple of 2 * kPointerSize.
170 __ test(esp, Immediate(kPointerSize));
171 __ j(not_zero, &do_not_pad, Label::kNear);
172 __ push(Immediate(0));
174 __ mov(edx, Immediate(kAlignmentPaddingPushed));
175 // Copy arguments, receiver, and return address.
176 __ mov(ecx, Immediate(scope()->num_parameters() + 2));
178 __ bind(&align_loop);
179 __ mov(eax, Operand(ebx, 1 * kPointerSize));
180 __ mov(Operand(ebx, 0), eax);
181 __ add(Operand(ebx), Immediate(kPointerSize));
183 __ j(not_zero, &align_loop, Label::kNear);
184 __ mov(Operand(ebx, 0), Immediate(kAlignmentZapValue));
185 __ bind(&do_not_pad);
189 info()->set_prologue_offset(masm_->pc_offset());
190 if (NeedsEagerFrame()) {
191 DCHECK(!frame_is_built_);
192 frame_is_built_ = true;
193 if (info()->IsStub()) {
196 __ Prologue(info()->IsCodePreAgingActive());
198 info()->AddNoFrameRange(0, masm_->pc_offset());
201 if (info()->IsOptimizing() &&
202 dynamic_frame_alignment_ &&
204 __ test(esp, Immediate(kPointerSize));
205 __ Assert(zero, kFrameIsExpectedToBeAligned);
208 // Reserve space for the stack slots needed by the code.
209 int slots = GetStackSlotCount();
210 DCHECK(slots != 0 || !info()->IsOptimizing());
213 if (dynamic_frame_alignment_) {
216 __ push(Immediate(kNoAlignmentPadding));
219 if (FLAG_debug_code) {
220 __ sub(Operand(esp), Immediate(slots * kPointerSize));
222 MakeSureStackPagesMapped(slots * kPointerSize);
225 __ mov(Operand(eax), Immediate(slots));
228 __ mov(MemOperand(esp, eax, times_4, 0),
229 Immediate(kSlotsZapValue));
231 __ j(not_zero, &loop);
234 __ sub(Operand(esp), Immediate(slots * kPointerSize));
236 MakeSureStackPagesMapped(slots * kPointerSize);
240 if (support_aligned_spilled_doubles_) {
241 Comment(";;; Store dynamic frame alignment tag for spilled doubles");
242 // Store dynamic frame alignment state in the first local.
243 int offset = JavaScriptFrameConstants::kDynamicAlignmentStateOffset;
244 if (dynamic_frame_alignment_) {
245 __ mov(Operand(ebp, offset), edx);
247 __ mov(Operand(ebp, offset), Immediate(kNoAlignmentPadding));
252 if (info()->saves_caller_doubles()) SaveCallerDoubles();
255 // Possibly allocate a local context.
256 int heap_slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
257 if (heap_slots > 0) {
258 Comment(";;; Allocate local context");
259 bool need_write_barrier = true;
260 // Argument to NewContext is the function, which is still in edi.
261 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
262 FastNewContextStub stub(isolate(), heap_slots);
264 // Result of FastNewContextStub is always in new space.
265 need_write_barrier = false;
268 __ CallRuntime(Runtime::kNewFunctionContext, 1);
270 RecordSafepoint(Safepoint::kNoLazyDeopt);
271 // Context is returned in eax. It replaces the context passed to us.
272 // It's saved in the stack and kept live in esi.
274 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), eax);
276 // Copy parameters into context if necessary.
277 int num_parameters = scope()->num_parameters();
278 for (int i = 0; i < num_parameters; i++) {
279 Variable* var = scope()->parameter(i);
280 if (var->IsContextSlot()) {
281 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
282 (num_parameters - 1 - i) * kPointerSize;
283 // Load parameter from stack.
284 __ mov(eax, Operand(ebp, parameter_offset));
285 // Store it in the context.
286 int context_offset = Context::SlotOffset(var->index());
287 __ mov(Operand(esi, context_offset), eax);
288 // Update the write barrier. This clobbers eax and ebx.
289 if (need_write_barrier) {
290 __ RecordWriteContextSlot(esi,
295 } else if (FLAG_debug_code) {
297 __ JumpIfInNewSpace(esi, eax, &done, Label::kNear);
298 __ Abort(kExpectedNewSpaceObject);
303 Comment(";;; End allocate local context");
307 if (FLAG_trace && info()->IsOptimizing()) {
308 // We have not executed any compiled code yet, so esi still holds the
310 __ CallRuntime(Runtime::kTraceEnter, 0);
312 return !is_aborted();
316 void LCodeGen::GenerateOsrPrologue() {
317 // Generate the OSR entry prologue at the first unknown OSR value, or if there
318 // are none, at the OSR entrypoint instruction.
319 if (osr_pc_offset_ >= 0) return;
321 osr_pc_offset_ = masm()->pc_offset();
323 // Move state of dynamic frame alignment into edx.
324 __ Move(edx, Immediate(kNoAlignmentPadding));
326 if (support_aligned_spilled_doubles_ && dynamic_frame_alignment_) {
327 Label do_not_pad, align_loop;
328 // Align ebp + 4 to a multiple of 2 * kPointerSize.
329 __ test(ebp, Immediate(kPointerSize));
330 __ j(zero, &do_not_pad, Label::kNear);
331 __ push(Immediate(0));
333 __ mov(edx, Immediate(kAlignmentPaddingPushed));
335 // Move all parts of the frame over one word. The frame consists of:
336 // unoptimized frame slots, alignment state, context, frame pointer, return
337 // address, receiver, and the arguments.
338 __ mov(ecx, Immediate(scope()->num_parameters() +
339 5 + graph()->osr()->UnoptimizedFrameSlots()));
341 __ bind(&align_loop);
342 __ mov(eax, Operand(ebx, 1 * kPointerSize));
343 __ mov(Operand(ebx, 0), eax);
344 __ add(Operand(ebx), Immediate(kPointerSize));
346 __ j(not_zero, &align_loop, Label::kNear);
347 __ mov(Operand(ebx, 0), Immediate(kAlignmentZapValue));
348 __ sub(Operand(ebp), Immediate(kPointerSize));
349 __ bind(&do_not_pad);
352 // Save the first local, which is overwritten by the alignment state.
353 Operand alignment_loc = MemOperand(ebp, -3 * kPointerSize);
354 __ push(alignment_loc);
356 // Set the dynamic frame alignment state.
357 __ mov(alignment_loc, edx);
359 // Adjust the frame size, subsuming the unoptimized frame into the
361 int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots();
363 __ sub(esp, Immediate((slots - 1) * kPointerSize));
367 void LCodeGen::GenerateBodyInstructionPre(LInstruction* instr) {
368 if (instr->IsCall()) {
369 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
371 if (!instr->IsLazyBailout() && !instr->IsGap()) {
372 safepoints_.BumpLastLazySafepointIndex();
377 void LCodeGen::GenerateBodyInstructionPost(LInstruction* instr) { }
380 bool LCodeGen::GenerateJumpTable() {
382 if (jump_table_.length() > 0) {
383 Comment(";;; -------------------- Jump table --------------------");
385 for (int i = 0; i < jump_table_.length(); i++) {
386 Deoptimizer::JumpTableEntry* table_entry = &jump_table_[i];
387 __ bind(&table_entry->label);
388 Address entry = table_entry->address;
389 DeoptComment(table_entry->reason);
390 if (table_entry->needs_frame) {
391 DCHECK(!info()->saves_caller_doubles());
392 __ push(Immediate(ExternalReference::ForDeoptEntry(entry)));
393 if (needs_frame.is_bound()) {
394 __ jmp(&needs_frame);
396 __ bind(&needs_frame);
397 __ push(MemOperand(ebp, StandardFrameConstants::kContextOffset));
398 // This variant of deopt can only be used with stubs. Since we don't
399 // have a function pointer to install in the stack frame that we're
400 // building, install a special marker there instead.
401 DCHECK(info()->IsStub());
402 __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
403 // Push a PC inside the function so that the deopt code can find where
404 // the deopt comes from. It doesn't have to be the precise return
405 // address of a "calling" LAZY deopt, it only has to be somewhere
406 // inside the code body.
407 Label push_approx_pc;
408 __ call(&push_approx_pc);
409 __ bind(&push_approx_pc);
410 // Push the continuation which was stashed were the ebp should
411 // be. Replace it with the saved ebp.
412 __ push(MemOperand(esp, 3 * kPointerSize));
413 __ mov(MemOperand(esp, 4 * kPointerSize), ebp);
414 __ lea(ebp, MemOperand(esp, 4 * kPointerSize));
415 __ ret(0); // Call the continuation without clobbering registers.
418 if (info()->saves_caller_doubles()) RestoreCallerDoubles();
419 __ call(entry, RelocInfo::RUNTIME_ENTRY);
422 return !is_aborted();
426 bool LCodeGen::GenerateDeferredCode() {
427 DCHECK(is_generating());
428 if (deferred_.length() > 0) {
429 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
430 LDeferredCode* code = deferred_[i];
433 instructions_->at(code->instruction_index())->hydrogen_value();
434 RecordAndWritePosition(
435 chunk()->graph()->SourcePositionToScriptPosition(value->position()));
437 Comment(";;; <@%d,#%d> "
438 "-------------------- Deferred %s --------------------",
439 code->instruction_index(),
440 code->instr()->hydrogen_value()->id(),
441 code->instr()->Mnemonic());
442 __ bind(code->entry());
443 if (NeedsDeferredFrame()) {
444 Comment(";;; Build frame");
445 DCHECK(!frame_is_built_);
446 DCHECK(info()->IsStub());
447 frame_is_built_ = true;
448 // Build the frame in such a way that esi isn't trashed.
449 __ push(ebp); // Caller's frame pointer.
450 __ push(Operand(ebp, StandardFrameConstants::kContextOffset));
451 __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
452 __ lea(ebp, Operand(esp, 2 * kPointerSize));
453 Comment(";;; Deferred code");
456 if (NeedsDeferredFrame()) {
457 __ bind(code->done());
458 Comment(";;; Destroy frame");
459 DCHECK(frame_is_built_);
460 frame_is_built_ = false;
464 __ jmp(code->exit());
468 // Deferred code is the last part of the instruction sequence. Mark
469 // the generated code as done unless we bailed out.
470 if (!is_aborted()) status_ = DONE;
471 return !is_aborted();
475 bool LCodeGen::GenerateSafepointTable() {
477 if (!info()->IsStub()) {
478 // For lazy deoptimization we need space to patch a call after every call.
479 // Ensure there is always space for such patching, even if the code ends
481 int target_offset = masm()->pc_offset() + Deoptimizer::patch_size();
482 while (masm()->pc_offset() < target_offset) {
486 safepoints_.Emit(masm(), GetStackSlotCount());
487 return !is_aborted();
491 Register LCodeGen::ToRegister(int index) const {
492 return Register::FromAllocationIndex(index);
496 XMMRegister LCodeGen::ToDoubleRegister(int index) const {
497 return XMMRegister::FromAllocationIndex(index);
501 XMMRegister LCodeGen::ToSIMD128Register(int index) const {
502 return XMMRegister::FromAllocationIndex(index);
506 Register LCodeGen::ToRegister(LOperand* op) const {
507 DCHECK(op->IsRegister());
508 return ToRegister(op->index());
512 XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
513 DCHECK(op->IsDoubleRegister());
514 return ToDoubleRegister(op->index());
518 XMMRegister LCodeGen::ToFloat32x4Register(LOperand* op) const {
519 DCHECK(op->IsFloat32x4Register());
520 return ToSIMD128Register(op->index());
524 XMMRegister LCodeGen::ToFloat64x2Register(LOperand* op) const {
525 DCHECK(op->IsFloat64x2Register());
526 return ToSIMD128Register(op->index());
530 XMMRegister LCodeGen::ToInt32x4Register(LOperand* op) const {
531 DCHECK(op->IsInt32x4Register());
532 return ToSIMD128Register(op->index());
536 XMMRegister LCodeGen::ToSIMD128Register(LOperand* op) const {
537 DCHECK(op->IsFloat32x4Register() || op->IsFloat64x2Register() ||
538 op->IsInt32x4Register());
539 return ToSIMD128Register(op->index());
543 int32_t LCodeGen::ToInteger32(LConstantOperand* op) const {
544 return ToRepresentation(op, Representation::Integer32());
548 int32_t LCodeGen::ToRepresentation(LConstantOperand* op,
549 const Representation& r) const {
550 HConstant* constant = chunk_->LookupConstant(op);
551 int32_t value = constant->Integer32Value();
552 if (r.IsInteger32()) return value;
553 DCHECK(r.IsSmiOrTagged());
554 return reinterpret_cast<int32_t>(Smi::FromInt(value));
558 Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
559 HConstant* constant = chunk_->LookupConstant(op);
560 DCHECK(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
561 return constant->handle(isolate());
565 double LCodeGen::ToDouble(LConstantOperand* op) const {
566 HConstant* constant = chunk_->LookupConstant(op);
567 DCHECK(constant->HasDoubleValue());
568 return constant->DoubleValue();
572 ExternalReference LCodeGen::ToExternalReference(LConstantOperand* op) const {
573 HConstant* constant = chunk_->LookupConstant(op);
574 DCHECK(constant->HasExternalReferenceValue());
575 return constant->ExternalReferenceValue();
579 bool LCodeGen::IsInteger32(LConstantOperand* op) const {
580 return chunk_->LookupLiteralRepresentation(op).IsSmiOrInteger32();
584 bool LCodeGen::IsSmi(LConstantOperand* op) const {
585 return chunk_->LookupLiteralRepresentation(op).IsSmi();
589 static int ArgumentsOffsetWithoutFrame(int index) {
591 return -(index + 1) * kPointerSize + kPCOnStackSize;
595 Operand LCodeGen::ToOperand(LOperand* op) const {
596 if (op->IsRegister()) return Operand(ToRegister(op));
597 if (op->IsDoubleRegister()) return Operand(ToDoubleRegister(op));
598 if (op->IsFloat32x4Register()) return Operand(ToFloat32x4Register(op));
599 if (op->IsFloat64x2Register()) return Operand(ToFloat64x2Register(op));
600 if (op->IsInt32x4Register()) return Operand(ToInt32x4Register(op));
601 DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot() ||
602 op->IsFloat32x4StackSlot() || op->IsFloat64x2StackSlot() ||
603 op->IsInt32x4StackSlot());
604 if (NeedsEagerFrame()) {
605 return Operand(ebp, StackSlotOffset(op->index()));
607 // Retrieve parameter without eager stack-frame relative to the
609 return Operand(esp, ArgumentsOffsetWithoutFrame(op->index()));
614 Operand LCodeGen::HighOperand(LOperand* op) {
615 DCHECK(op->IsDoubleStackSlot());
616 if (NeedsEagerFrame()) {
617 return Operand(ebp, StackSlotOffset(op->index()) + kPointerSize);
619 // Retrieve parameter without eager stack-frame relative to the
622 esp, ArgumentsOffsetWithoutFrame(op->index()) + kPointerSize);
627 void LCodeGen::WriteTranslation(LEnvironment* environment,
628 Translation* translation) {
629 if (environment == NULL) return;
631 // The translation includes one command per value in the environment.
632 int translation_size = environment->translation_size();
633 // The output frame height does not include the parameters.
634 int height = translation_size - environment->parameter_count();
636 WriteTranslation(environment->outer(), translation);
637 bool has_closure_id = !info()->closure().is_null() &&
638 !info()->closure().is_identical_to(environment->closure());
639 int closure_id = has_closure_id
640 ? DefineDeoptimizationLiteral(environment->closure())
641 : Translation::kSelfLiteralId;
642 switch (environment->frame_type()) {
644 translation->BeginJSFrame(environment->ast_id(), closure_id, height);
647 translation->BeginConstructStubFrame(closure_id, translation_size);
650 DCHECK(translation_size == 1);
652 translation->BeginGetterStubFrame(closure_id);
655 DCHECK(translation_size == 2);
657 translation->BeginSetterStubFrame(closure_id);
659 case ARGUMENTS_ADAPTOR:
660 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
663 translation->BeginCompiledStubFrame();
669 int object_index = 0;
670 int dematerialized_index = 0;
671 for (int i = 0; i < translation_size; ++i) {
672 LOperand* value = environment->values()->at(i);
673 AddToTranslation(environment,
676 environment->HasTaggedValueAt(i),
677 environment->HasUint32ValueAt(i),
679 &dematerialized_index);
684 void LCodeGen::AddToTranslation(LEnvironment* environment,
685 Translation* translation,
689 int* object_index_pointer,
690 int* dematerialized_index_pointer) {
691 if (op == LEnvironment::materialization_marker()) {
692 int object_index = (*object_index_pointer)++;
693 if (environment->ObjectIsDuplicateAt(object_index)) {
694 int dupe_of = environment->ObjectDuplicateOfAt(object_index);
695 translation->DuplicateObject(dupe_of);
698 int object_length = environment->ObjectLengthAt(object_index);
699 if (environment->ObjectIsArgumentsAt(object_index)) {
700 translation->BeginArgumentsObject(object_length);
702 translation->BeginCapturedObject(object_length);
704 int dematerialized_index = *dematerialized_index_pointer;
705 int env_offset = environment->translation_size() + dematerialized_index;
706 *dematerialized_index_pointer += object_length;
707 for (int i = 0; i < object_length; ++i) {
708 LOperand* value = environment->values()->at(env_offset + i);
709 AddToTranslation(environment,
712 environment->HasTaggedValueAt(env_offset + i),
713 environment->HasUint32ValueAt(env_offset + i),
714 object_index_pointer,
715 dematerialized_index_pointer);
720 if (op->IsStackSlot()) {
722 translation->StoreStackSlot(op->index());
723 } else if (is_uint32) {
724 translation->StoreUint32StackSlot(op->index());
726 translation->StoreInt32StackSlot(op->index());
728 } else if (op->IsDoubleStackSlot()) {
729 translation->StoreDoubleStackSlot(op->index());
730 } else if (op->IsFloat32x4StackSlot()) {
731 translation->StoreSIMD128StackSlot(op->index(),
732 Translation::FLOAT32x4_STACK_SLOT);
733 } else if (op->IsFloat64x2StackSlot()) {
734 translation->StoreSIMD128StackSlot(op->index(),
735 Translation::FLOAT64x2_STACK_SLOT);
736 } else if (op->IsInt32x4StackSlot()) {
737 translation->StoreSIMD128StackSlot(op->index(),
738 Translation::INT32x4_STACK_SLOT);
739 } else if (op->IsRegister()) {
740 Register reg = ToRegister(op);
742 translation->StoreRegister(reg);
743 } else if (is_uint32) {
744 translation->StoreUint32Register(reg);
746 translation->StoreInt32Register(reg);
748 } else if (op->IsDoubleRegister()) {
749 XMMRegister reg = ToDoubleRegister(op);
750 translation->StoreDoubleRegister(reg);
751 } else if (op->IsFloat32x4Register()) {
752 XMMRegister reg = ToFloat32x4Register(op);
753 translation->StoreSIMD128Register(reg, Translation::FLOAT32x4_REGISTER);
754 } else if (op->IsFloat64x2Register()) {
755 XMMRegister reg = ToFloat64x2Register(op);
756 translation->StoreSIMD128Register(reg, Translation::FLOAT64x2_REGISTER);
757 } else if (op->IsInt32x4Register()) {
758 XMMRegister reg = ToInt32x4Register(op);
759 translation->StoreSIMD128Register(reg, Translation::INT32x4_REGISTER);
760 } else if (op->IsConstantOperand()) {
761 HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
762 int src_index = DefineDeoptimizationLiteral(constant->handle(isolate()));
763 translation->StoreLiteral(src_index);
770 void LCodeGen::CallCodeGeneric(Handle<Code> code,
771 RelocInfo::Mode mode,
773 SafepointMode safepoint_mode) {
774 DCHECK(instr != NULL);
776 RecordSafepointWithLazyDeopt(instr, safepoint_mode);
778 // Signal that we don't inline smi code before these stubs in the
779 // optimizing code generator.
780 if (code->kind() == Code::BINARY_OP_IC ||
781 code->kind() == Code::COMPARE_IC) {
787 void LCodeGen::CallCode(Handle<Code> code,
788 RelocInfo::Mode mode,
789 LInstruction* instr) {
790 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT);
794 void LCodeGen::CallRuntime(const Runtime::Function* fun,
797 SaveFPRegsMode save_doubles) {
798 DCHECK(instr != NULL);
799 DCHECK(instr->HasPointerMap());
801 __ CallRuntime(fun, argc, save_doubles);
803 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
805 DCHECK(info()->is_calling());
809 void LCodeGen::LoadContextFromDeferred(LOperand* context) {
810 if (context->IsRegister()) {
811 if (!ToRegister(context).is(esi)) {
812 __ mov(esi, ToRegister(context));
814 } else if (context->IsStackSlot()) {
815 __ mov(esi, ToOperand(context));
816 } else if (context->IsConstantOperand()) {
817 HConstant* constant =
818 chunk_->LookupConstant(LConstantOperand::cast(context));
819 __ LoadObject(esi, Handle<Object>::cast(constant->handle(isolate())));
825 void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
829 LoadContextFromDeferred(context);
831 __ CallRuntimeSaveDoubles(id);
832 RecordSafepointWithRegisters(
833 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
835 DCHECK(info()->is_calling());
839 void LCodeGen::RegisterEnvironmentForDeoptimization(
840 LEnvironment* environment, Safepoint::DeoptMode mode) {
841 environment->set_has_been_used();
842 if (!environment->HasBeenRegistered()) {
843 // Physical stack frame layout:
844 // -x ............. -4 0 ..................................... y
845 // [incoming arguments] [spill slots] [pushed outgoing arguments]
847 // Layout of the environment:
848 // 0 ..................................................... size-1
849 // [parameters] [locals] [expression stack including arguments]
851 // Layout of the translation:
852 // 0 ........................................................ size - 1 + 4
853 // [expression stack including arguments] [locals] [4 words] [parameters]
854 // |>------------ translation_size ------------<|
857 int jsframe_count = 0;
858 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
860 if (e->frame_type() == JS_FUNCTION) {
864 Translation translation(&translations_, frame_count, jsframe_count, zone());
865 WriteTranslation(environment, &translation);
866 int deoptimization_index = deoptimizations_.length();
867 int pc_offset = masm()->pc_offset();
868 environment->Register(deoptimization_index,
870 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
871 deoptimizations_.Add(environment, zone());
876 void LCodeGen::DeoptimizeIf(Condition cc, LInstruction* instr,
878 Deoptimizer::BailoutType bailout_type) {
879 LEnvironment* environment = instr->environment();
880 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
881 DCHECK(environment->HasBeenRegistered());
882 int id = environment->deoptimization_index();
883 DCHECK(info()->IsOptimizing() || info()->IsStub());
885 Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type);
887 Abort(kBailoutWasNotPrepared);
891 if (DeoptEveryNTimes()) {
892 ExternalReference count = ExternalReference::stress_deopt_count(isolate());
896 __ mov(eax, Operand::StaticVariable(count));
897 __ sub(eax, Immediate(1));
898 __ j(not_zero, &no_deopt, Label::kNear);
899 if (FLAG_trap_on_deopt) __ int3();
900 __ mov(eax, Immediate(FLAG_deopt_every_n_times));
901 __ mov(Operand::StaticVariable(count), eax);
904 DCHECK(frame_is_built_);
905 __ call(entry, RelocInfo::RUNTIME_ENTRY);
907 __ mov(Operand::StaticVariable(count), eax);
912 if (info()->ShouldTrapOnDeopt()) {
914 if (cc != no_condition) __ j(NegateCondition(cc), &done, Label::kNear);
919 Deoptimizer::Reason reason(instr->hydrogen_value()->position().raw(),
920 instr->Mnemonic(), detail);
921 DCHECK(info()->IsStub() || frame_is_built_);
922 if (cc == no_condition && frame_is_built_) {
923 DeoptComment(reason);
924 __ call(entry, RelocInfo::RUNTIME_ENTRY);
926 Deoptimizer::JumpTableEntry table_entry(entry, reason, bailout_type,
928 // We often have several deopts to the same entry, reuse the last
929 // jump entry if this is the case.
930 if (jump_table_.is_empty() ||
931 !table_entry.IsEquivalentTo(jump_table_.last())) {
932 jump_table_.Add(table_entry, zone());
934 if (cc == no_condition) {
935 __ jmp(&jump_table_.last().label);
937 __ j(cc, &jump_table_.last().label);
943 void LCodeGen::DeoptimizeIf(Condition cc, LInstruction* instr,
944 const char* detail) {
945 Deoptimizer::BailoutType bailout_type = info()->IsStub()
947 : Deoptimizer::EAGER;
948 DeoptimizeIf(cc, instr, detail, bailout_type);
952 void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
953 int length = deoptimizations_.length();
954 if (length == 0) return;
955 Handle<DeoptimizationInputData> data =
956 DeoptimizationInputData::New(isolate(), length, TENURED);
958 Handle<ByteArray> translations =
959 translations_.CreateByteArray(isolate()->factory());
960 data->SetTranslationByteArray(*translations);
961 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
962 data->SetOptimizationId(Smi::FromInt(info_->optimization_id()));
963 if (info_->IsOptimizing()) {
964 // Reference to shared function info does not change between phases.
965 AllowDeferredHandleDereference allow_handle_dereference;
966 data->SetSharedFunctionInfo(*info_->shared_info());
968 data->SetSharedFunctionInfo(Smi::FromInt(0));
971 Handle<FixedArray> literals =
972 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
973 { AllowDeferredHandleDereference copy_handles;
974 for (int i = 0; i < deoptimization_literals_.length(); i++) {
975 literals->set(i, *deoptimization_literals_[i]);
977 data->SetLiteralArray(*literals);
980 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
981 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
983 // Populate the deoptimization entries.
984 for (int i = 0; i < length; i++) {
985 LEnvironment* env = deoptimizations_[i];
986 data->SetAstId(i, env->ast_id());
987 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
988 data->SetArgumentsStackHeight(i,
989 Smi::FromInt(env->arguments_stack_height()));
990 data->SetPc(i, Smi::FromInt(env->pc_offset()));
992 code->set_deoptimization_data(*data);
996 int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
997 int result = deoptimization_literals_.length();
998 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
999 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
1001 deoptimization_literals_.Add(literal, zone());
1006 void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
1007 DCHECK(deoptimization_literals_.length() == 0);
1009 const ZoneList<Handle<JSFunction> >* inlined_closures =
1010 chunk()->inlined_closures();
1012 for (int i = 0, length = inlined_closures->length();
1015 DefineDeoptimizationLiteral(inlined_closures->at(i));
1018 inlined_function_count_ = deoptimization_literals_.length();
1022 void LCodeGen::RecordSafepointWithLazyDeopt(
1023 LInstruction* instr, SafepointMode safepoint_mode) {
1024 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
1025 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
1027 DCHECK(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
1028 RecordSafepointWithRegisters(
1029 instr->pointer_map(), 0, Safepoint::kLazyDeopt);
1034 void LCodeGen::RecordSafepoint(
1035 LPointerMap* pointers,
1036 Safepoint::Kind kind,
1038 Safepoint::DeoptMode deopt_mode) {
1039 DCHECK(kind == expected_safepoint_kind_);
1040 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
1041 Safepoint safepoint =
1042 safepoints_.DefineSafepoint(masm(), kind, arguments, deopt_mode);
1043 for (int i = 0; i < operands->length(); i++) {
1044 LOperand* pointer = operands->at(i);
1045 if (pointer->IsStackSlot()) {
1046 safepoint.DefinePointerSlot(pointer->index(), zone());
1047 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
1048 safepoint.DefinePointerRegister(ToRegister(pointer), zone());
1054 void LCodeGen::RecordSafepoint(LPointerMap* pointers,
1055 Safepoint::DeoptMode mode) {
1056 RecordSafepoint(pointers, Safepoint::kSimple, 0, mode);
1060 void LCodeGen::RecordSafepoint(Safepoint::DeoptMode mode) {
1061 LPointerMap empty_pointers(zone());
1062 RecordSafepoint(&empty_pointers, mode);
1066 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
1068 Safepoint::DeoptMode mode) {
1069 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, mode);
1073 void LCodeGen::RecordAndWritePosition(int position) {
1074 if (position == RelocInfo::kNoPosition) return;
1075 masm()->positions_recorder()->RecordPosition(position);
1076 masm()->positions_recorder()->WriteRecordedPositions();
1080 static const char* LabelType(LLabel* label) {
1081 if (label->is_loop_header()) return " (loop header)";
1082 if (label->is_osr_entry()) return " (OSR entry)";
1087 void LCodeGen::DoLabel(LLabel* label) {
1088 Comment(";;; <@%d,#%d> -------------------- B%d%s --------------------",
1089 current_instruction_,
1090 label->hydrogen_value()->id(),
1093 __ bind(label->label());
1094 current_block_ = label->block_id();
1099 void LCodeGen::DoParallelMove(LParallelMove* move) {
1100 resolver_.Resolve(move);
1104 void LCodeGen::DoGap(LGap* gap) {
1105 for (int i = LGap::FIRST_INNER_POSITION;
1106 i <= LGap::LAST_INNER_POSITION;
1108 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
1109 LParallelMove* move = gap->GetParallelMove(inner_pos);
1110 if (move != NULL) DoParallelMove(move);
1115 void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
1120 void LCodeGen::DoParameter(LParameter* instr) {
1125 void LCodeGen::DoCallStub(LCallStub* instr) {
1126 DCHECK(ToRegister(instr->context()).is(esi));
1127 DCHECK(ToRegister(instr->result()).is(eax));
1128 switch (instr->hydrogen()->major_key()) {
1129 case CodeStub::RegExpExec: {
1130 RegExpExecStub stub(isolate());
1131 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
1134 case CodeStub::SubString: {
1135 SubStringStub stub(isolate());
1136 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
1139 case CodeStub::StringCompare: {
1140 StringCompareStub stub(isolate());
1141 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
1150 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
1151 GenerateOsrPrologue();
1155 void LCodeGen::DoModByPowerOf2I(LModByPowerOf2I* instr) {
1156 Register dividend = ToRegister(instr->dividend());
1157 int32_t divisor = instr->divisor();
1158 DCHECK(dividend.is(ToRegister(instr->result())));
1160 // Theoretically, a variation of the branch-free code for integer division by
1161 // a power of 2 (calculating the remainder via an additional multiplication
1162 // (which gets simplified to an 'and') and subtraction) should be faster, and
1163 // this is exactly what GCC and clang emit. Nevertheless, benchmarks seem to
1164 // indicate that positive dividends are heavily favored, so the branching
1165 // version performs better.
1166 HMod* hmod = instr->hydrogen();
1167 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
1168 Label dividend_is_not_negative, done;
1169 if (hmod->CheckFlag(HValue::kLeftCanBeNegative)) {
1170 __ test(dividend, dividend);
1171 __ j(not_sign, ÷nd_is_not_negative, Label::kNear);
1172 // Note that this is correct even for kMinInt operands.
1174 __ and_(dividend, mask);
1176 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1177 DeoptimizeIf(zero, instr, "minus zero");
1179 __ jmp(&done, Label::kNear);
1182 __ bind(÷nd_is_not_negative);
1183 __ and_(dividend, mask);
1188 void LCodeGen::DoModByConstI(LModByConstI* instr) {
1189 Register dividend = ToRegister(instr->dividend());
1190 int32_t divisor = instr->divisor();
1191 DCHECK(ToRegister(instr->result()).is(eax));
1194 DeoptimizeIf(no_condition, instr, "division by zero");
1198 __ TruncatingDiv(dividend, Abs(divisor));
1199 __ imul(edx, edx, Abs(divisor));
1200 __ mov(eax, dividend);
1203 // Check for negative zero.
1204 HMod* hmod = instr->hydrogen();
1205 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1206 Label remainder_not_zero;
1207 __ j(not_zero, &remainder_not_zero, Label::kNear);
1208 __ cmp(dividend, Immediate(0));
1209 DeoptimizeIf(less, instr, "minus zero");
1210 __ bind(&remainder_not_zero);
1215 void LCodeGen::DoModI(LModI* instr) {
1216 HMod* hmod = instr->hydrogen();
1218 Register left_reg = ToRegister(instr->left());
1219 DCHECK(left_reg.is(eax));
1220 Register right_reg = ToRegister(instr->right());
1221 DCHECK(!right_reg.is(eax));
1222 DCHECK(!right_reg.is(edx));
1223 Register result_reg = ToRegister(instr->result());
1224 DCHECK(result_reg.is(edx));
1227 // Check for x % 0, idiv would signal a divide error. We have to
1228 // deopt in this case because we can't return a NaN.
1229 if (hmod->CheckFlag(HValue::kCanBeDivByZero)) {
1230 __ test(right_reg, Operand(right_reg));
1231 DeoptimizeIf(zero, instr, "division by zero");
1234 // Check for kMinInt % -1, idiv would signal a divide error. We
1235 // have to deopt if we care about -0, because we can't return that.
1236 if (hmod->CheckFlag(HValue::kCanOverflow)) {
1237 Label no_overflow_possible;
1238 __ cmp(left_reg, kMinInt);
1239 __ j(not_equal, &no_overflow_possible, Label::kNear);
1240 __ cmp(right_reg, -1);
1241 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1242 DeoptimizeIf(equal, instr, "minus zero");
1244 __ j(not_equal, &no_overflow_possible, Label::kNear);
1245 __ Move(result_reg, Immediate(0));
1246 __ jmp(&done, Label::kNear);
1248 __ bind(&no_overflow_possible);
1251 // Sign extend dividend in eax into edx:eax.
1254 // If we care about -0, test if the dividend is <0 and the result is 0.
1255 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1256 Label positive_left;
1257 __ test(left_reg, Operand(left_reg));
1258 __ j(not_sign, &positive_left, Label::kNear);
1260 __ test(result_reg, Operand(result_reg));
1261 DeoptimizeIf(zero, instr, "minus zero");
1262 __ jmp(&done, Label::kNear);
1263 __ bind(&positive_left);
1270 void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) {
1271 Register dividend = ToRegister(instr->dividend());
1272 int32_t divisor = instr->divisor();
1273 Register result = ToRegister(instr->result());
1274 DCHECK(divisor == kMinInt || base::bits::IsPowerOfTwo32(Abs(divisor)));
1275 DCHECK(!result.is(dividend));
1277 // Check for (0 / -x) that will produce negative zero.
1278 HDiv* hdiv = instr->hydrogen();
1279 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
1280 __ test(dividend, dividend);
1281 DeoptimizeIf(zero, instr, "minus zero");
1283 // Check for (kMinInt / -1).
1284 if (hdiv->CheckFlag(HValue::kCanOverflow) && divisor == -1) {
1285 __ cmp(dividend, kMinInt);
1286 DeoptimizeIf(zero, instr, "overflow");
1288 // Deoptimize if remainder will not be 0.
1289 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
1290 divisor != 1 && divisor != -1) {
1291 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
1292 __ test(dividend, Immediate(mask));
1293 DeoptimizeIf(not_zero, instr, "lost precision");
1295 __ Move(result, dividend);
1296 int32_t shift = WhichPowerOf2Abs(divisor);
1298 // The arithmetic shift is always OK, the 'if' is an optimization only.
1299 if (shift > 1) __ sar(result, 31);
1300 __ shr(result, 32 - shift);
1301 __ add(result, dividend);
1302 __ sar(result, shift);
1304 if (divisor < 0) __ neg(result);
1308 void LCodeGen::DoDivByConstI(LDivByConstI* instr) {
1309 Register dividend = ToRegister(instr->dividend());
1310 int32_t divisor = instr->divisor();
1311 DCHECK(ToRegister(instr->result()).is(edx));
1314 DeoptimizeIf(no_condition, instr, "division by zero");
1318 // Check for (0 / -x) that will produce negative zero.
1319 HDiv* hdiv = instr->hydrogen();
1320 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
1321 __ test(dividend, dividend);
1322 DeoptimizeIf(zero, instr, "minus zero");
1325 __ TruncatingDiv(dividend, Abs(divisor));
1326 if (divisor < 0) __ neg(edx);
1328 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
1330 __ imul(eax, eax, divisor);
1331 __ sub(eax, dividend);
1332 DeoptimizeIf(not_equal, instr, "lost precision");
1337 // TODO(svenpanne) Refactor this to avoid code duplication with DoFlooringDivI.
1338 void LCodeGen::DoDivI(LDivI* instr) {
1339 HBinaryOperation* hdiv = instr->hydrogen();
1340 Register dividend = ToRegister(instr->dividend());
1341 Register divisor = ToRegister(instr->divisor());
1342 Register remainder = ToRegister(instr->temp());
1343 DCHECK(dividend.is(eax));
1344 DCHECK(remainder.is(edx));
1345 DCHECK(ToRegister(instr->result()).is(eax));
1346 DCHECK(!divisor.is(eax));
1347 DCHECK(!divisor.is(edx));
1350 if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
1351 __ test(divisor, divisor);
1352 DeoptimizeIf(zero, instr, "division by zero");
1355 // Check for (0 / -x) that will produce negative zero.
1356 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
1357 Label dividend_not_zero;
1358 __ test(dividend, dividend);
1359 __ j(not_zero, ÷nd_not_zero, Label::kNear);
1360 __ test(divisor, divisor);
1361 DeoptimizeIf(sign, instr, "minus zero");
1362 __ bind(÷nd_not_zero);
1365 // Check for (kMinInt / -1).
1366 if (hdiv->CheckFlag(HValue::kCanOverflow)) {
1367 Label dividend_not_min_int;
1368 __ cmp(dividend, kMinInt);
1369 __ j(not_zero, ÷nd_not_min_int, Label::kNear);
1370 __ cmp(divisor, -1);
1371 DeoptimizeIf(zero, instr, "overflow");
1372 __ bind(÷nd_not_min_int);
1375 // Sign extend to edx (= remainder).
1379 if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
1380 // Deoptimize if remainder is not 0.
1381 __ test(remainder, remainder);
1382 DeoptimizeIf(not_zero, instr, "lost precision");
1387 void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
1388 Register dividend = ToRegister(instr->dividend());
1389 int32_t divisor = instr->divisor();
1390 DCHECK(dividend.is(ToRegister(instr->result())));
1392 // If the divisor is positive, things are easy: There can be no deopts and we
1393 // can simply do an arithmetic right shift.
1394 if (divisor == 1) return;
1395 int32_t shift = WhichPowerOf2Abs(divisor);
1397 __ sar(dividend, shift);
1401 // If the divisor is negative, we have to negate and handle edge cases.
1403 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1404 DeoptimizeIf(zero, instr, "minus zero");
1407 // Dividing by -1 is basically negation, unless we overflow.
1408 if (divisor == -1) {
1409 if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
1410 DeoptimizeIf(overflow, instr, "overflow");
1415 // If the negation could not overflow, simply shifting is OK.
1416 if (!instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
1417 __ sar(dividend, shift);
1421 Label not_kmin_int, done;
1422 __ j(no_overflow, ¬_kmin_int, Label::kNear);
1423 __ mov(dividend, Immediate(kMinInt / divisor));
1424 __ jmp(&done, Label::kNear);
1425 __ bind(¬_kmin_int);
1426 __ sar(dividend, shift);
1431 void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) {
1432 Register dividend = ToRegister(instr->dividend());
1433 int32_t divisor = instr->divisor();
1434 DCHECK(ToRegister(instr->result()).is(edx));
1437 DeoptimizeIf(no_condition, instr, "division by zero");
1441 // Check for (0 / -x) that will produce negative zero.
1442 HMathFloorOfDiv* hdiv = instr->hydrogen();
1443 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
1444 __ test(dividend, dividend);
1445 DeoptimizeIf(zero, instr, "minus zero");
1448 // Easy case: We need no dynamic check for the dividend and the flooring
1449 // division is the same as the truncating division.
1450 if ((divisor > 0 && !hdiv->CheckFlag(HValue::kLeftCanBeNegative)) ||
1451 (divisor < 0 && !hdiv->CheckFlag(HValue::kLeftCanBePositive))) {
1452 __ TruncatingDiv(dividend, Abs(divisor));
1453 if (divisor < 0) __ neg(edx);
1457 // In the general case we may need to adjust before and after the truncating
1458 // division to get a flooring division.
1459 Register temp = ToRegister(instr->temp3());
1460 DCHECK(!temp.is(dividend) && !temp.is(eax) && !temp.is(edx));
1461 Label needs_adjustment, done;
1462 __ cmp(dividend, Immediate(0));
1463 __ j(divisor > 0 ? less : greater, &needs_adjustment, Label::kNear);
1464 __ TruncatingDiv(dividend, Abs(divisor));
1465 if (divisor < 0) __ neg(edx);
1466 __ jmp(&done, Label::kNear);
1467 __ bind(&needs_adjustment);
1468 __ lea(temp, Operand(dividend, divisor > 0 ? 1 : -1));
1469 __ TruncatingDiv(temp, Abs(divisor));
1470 if (divisor < 0) __ neg(edx);
1476 // TODO(svenpanne) Refactor this to avoid code duplication with DoDivI.
1477 void LCodeGen::DoFlooringDivI(LFlooringDivI* instr) {
1478 HBinaryOperation* hdiv = instr->hydrogen();
1479 Register dividend = ToRegister(instr->dividend());
1480 Register divisor = ToRegister(instr->divisor());
1481 Register remainder = ToRegister(instr->temp());
1482 Register result = ToRegister(instr->result());
1483 DCHECK(dividend.is(eax));
1484 DCHECK(remainder.is(edx));
1485 DCHECK(result.is(eax));
1486 DCHECK(!divisor.is(eax));
1487 DCHECK(!divisor.is(edx));
1490 if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
1491 __ test(divisor, divisor);
1492 DeoptimizeIf(zero, instr, "division by zero");
1495 // Check for (0 / -x) that will produce negative zero.
1496 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
1497 Label dividend_not_zero;
1498 __ test(dividend, dividend);
1499 __ j(not_zero, ÷nd_not_zero, Label::kNear);
1500 __ test(divisor, divisor);
1501 DeoptimizeIf(sign, instr, "minus zero");
1502 __ bind(÷nd_not_zero);
1505 // Check for (kMinInt / -1).
1506 if (hdiv->CheckFlag(HValue::kCanOverflow)) {
1507 Label dividend_not_min_int;
1508 __ cmp(dividend, kMinInt);
1509 __ j(not_zero, ÷nd_not_min_int, Label::kNear);
1510 __ cmp(divisor, -1);
1511 DeoptimizeIf(zero, instr, "overflow");
1512 __ bind(÷nd_not_min_int);
1515 // Sign extend to edx (= remainder).
1520 __ test(remainder, remainder);
1521 __ j(zero, &done, Label::kNear);
1522 __ xor_(remainder, divisor);
1523 __ sar(remainder, 31);
1524 __ add(result, remainder);
1529 void LCodeGen::DoMulI(LMulI* instr) {
1530 Register left = ToRegister(instr->left());
1531 LOperand* right = instr->right();
1533 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1534 __ mov(ToRegister(instr->temp()), left);
1537 if (right->IsConstantOperand()) {
1538 // Try strength reductions on the multiplication.
1539 // All replacement instructions are at most as long as the imul
1540 // and have better latency.
1541 int constant = ToInteger32(LConstantOperand::cast(right));
1542 if (constant == -1) {
1544 } else if (constant == 0) {
1545 __ xor_(left, Operand(left));
1546 } else if (constant == 2) {
1547 __ add(left, Operand(left));
1548 } else if (!instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1549 // If we know that the multiplication can't overflow, it's safe to
1550 // use instructions that don't set the overflow flag for the
1557 __ lea(left, Operand(left, left, times_2, 0));
1563 __ lea(left, Operand(left, left, times_4, 0));
1569 __ lea(left, Operand(left, left, times_8, 0));
1575 __ imul(left, left, constant);
1579 __ imul(left, left, constant);
1582 if (instr->hydrogen()->representation().IsSmi()) {
1585 __ imul(left, ToOperand(right));
1588 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1589 DeoptimizeIf(overflow, instr, "overflow");
1592 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1593 // Bail out if the result is supposed to be negative zero.
1595 __ test(left, Operand(left));
1596 __ j(not_zero, &done, Label::kNear);
1597 if (right->IsConstantOperand()) {
1598 if (ToInteger32(LConstantOperand::cast(right)) < 0) {
1599 DeoptimizeIf(no_condition, instr, "minus zero");
1600 } else if (ToInteger32(LConstantOperand::cast(right)) == 0) {
1601 __ cmp(ToRegister(instr->temp()), Immediate(0));
1602 DeoptimizeIf(less, instr, "minus zero");
1605 // Test the non-zero operand for negative sign.
1606 __ or_(ToRegister(instr->temp()), ToOperand(right));
1607 DeoptimizeIf(sign, instr, "minus zero");
1614 void LCodeGen::DoBitI(LBitI* instr) {
1615 LOperand* left = instr->left();
1616 LOperand* right = instr->right();
1617 DCHECK(left->Equals(instr->result()));
1618 DCHECK(left->IsRegister());
1620 if (right->IsConstantOperand()) {
1621 int32_t right_operand =
1622 ToRepresentation(LConstantOperand::cast(right),
1623 instr->hydrogen()->representation());
1624 switch (instr->op()) {
1625 case Token::BIT_AND:
1626 __ and_(ToRegister(left), right_operand);
1629 __ or_(ToRegister(left), right_operand);
1631 case Token::BIT_XOR:
1632 if (right_operand == int32_t(~0)) {
1633 __ not_(ToRegister(left));
1635 __ xor_(ToRegister(left), right_operand);
1643 switch (instr->op()) {
1644 case Token::BIT_AND:
1645 __ and_(ToRegister(left), ToOperand(right));
1648 __ or_(ToRegister(left), ToOperand(right));
1650 case Token::BIT_XOR:
1651 __ xor_(ToRegister(left), ToOperand(right));
1661 void LCodeGen::DoShiftI(LShiftI* instr) {
1662 LOperand* left = instr->left();
1663 LOperand* right = instr->right();
1664 DCHECK(left->Equals(instr->result()));
1665 DCHECK(left->IsRegister());
1666 if (right->IsRegister()) {
1667 DCHECK(ToRegister(right).is(ecx));
1669 switch (instr->op()) {
1671 __ ror_cl(ToRegister(left));
1674 __ sar_cl(ToRegister(left));
1677 __ shr_cl(ToRegister(left));
1678 if (instr->can_deopt()) {
1679 __ test(ToRegister(left), ToRegister(left));
1680 DeoptimizeIf(sign, instr, "negative value");
1684 __ shl_cl(ToRegister(left));
1691 int value = ToInteger32(LConstantOperand::cast(right));
1692 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1693 switch (instr->op()) {
1695 if (shift_count == 0 && instr->can_deopt()) {
1696 __ test(ToRegister(left), ToRegister(left));
1697 DeoptimizeIf(sign, instr, "negative value");
1699 __ ror(ToRegister(left), shift_count);
1703 if (shift_count != 0) {
1704 __ sar(ToRegister(left), shift_count);
1708 if (shift_count != 0) {
1709 __ shr(ToRegister(left), shift_count);
1710 } else if (instr->can_deopt()) {
1711 __ test(ToRegister(left), ToRegister(left));
1712 DeoptimizeIf(sign, instr, "negative value");
1716 if (shift_count != 0) {
1717 if (instr->hydrogen_value()->representation().IsSmi() &&
1718 instr->can_deopt()) {
1719 if (shift_count != 1) {
1720 __ shl(ToRegister(left), shift_count - 1);
1722 __ SmiTag(ToRegister(left));
1723 DeoptimizeIf(overflow, instr, "overflow");
1725 __ shl(ToRegister(left), shift_count);
1737 void LCodeGen::DoSubI(LSubI* instr) {
1738 LOperand* left = instr->left();
1739 LOperand* right = instr->right();
1740 DCHECK(left->Equals(instr->result()));
1742 if (right->IsConstantOperand()) {
1743 __ sub(ToOperand(left),
1744 ToImmediate(right, instr->hydrogen()->representation()));
1746 __ sub(ToRegister(left), ToOperand(right));
1748 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1749 DeoptimizeIf(overflow, instr, "overflow");
1754 void LCodeGen::DoConstantI(LConstantI* instr) {
1755 __ Move(ToRegister(instr->result()), Immediate(instr->value()));
1759 void LCodeGen::DoConstantS(LConstantS* instr) {
1760 __ Move(ToRegister(instr->result()), Immediate(instr->value()));
1764 void LCodeGen::DoConstantD(LConstantD* instr) {
1765 double v = instr->value();
1766 uint64_t int_val = bit_cast<uint64_t, double>(v);
1767 int32_t lower = static_cast<int32_t>(int_val);
1768 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
1769 DCHECK(instr->result()->IsDoubleRegister());
1771 XMMRegister res = ToDoubleRegister(instr->result());
1775 Register temp = ToRegister(instr->temp());
1776 if (CpuFeatures::IsSupported(SSE4_1)) {
1777 CpuFeatureScope scope2(masm(), SSE4_1);
1779 __ Move(temp, Immediate(lower));
1780 __ movd(res, Operand(temp));
1781 __ Move(temp, Immediate(upper));
1782 __ pinsrd(res, Operand(temp), 1);
1785 __ Move(temp, Immediate(upper));
1786 __ pinsrd(res, Operand(temp), 1);
1789 __ Move(temp, Immediate(upper));
1790 __ movd(res, Operand(temp));
1793 XMMRegister xmm_scratch = double_scratch0();
1794 __ Move(temp, Immediate(lower));
1795 __ movd(xmm_scratch, Operand(temp));
1796 __ orps(res, xmm_scratch);
1803 void LCodeGen::DoConstantE(LConstantE* instr) {
1804 __ lea(ToRegister(instr->result()), Operand::StaticVariable(instr->value()));
1808 void LCodeGen::DoConstantT(LConstantT* instr) {
1809 Register reg = ToRegister(instr->result());
1810 Handle<Object> object = instr->value(isolate());
1811 AllowDeferredHandleDereference smi_check;
1812 __ LoadObject(reg, object);
1816 void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
1817 Register result = ToRegister(instr->result());
1818 Register map = ToRegister(instr->value());
1819 __ EnumLength(result, map);
1823 void LCodeGen::DoDateField(LDateField* instr) {
1824 Register object = ToRegister(instr->date());
1825 Register result = ToRegister(instr->result());
1826 Register scratch = ToRegister(instr->temp());
1827 Smi* index = instr->index();
1828 Label runtime, done;
1829 DCHECK(object.is(result));
1830 DCHECK(object.is(eax));
1832 __ test(object, Immediate(kSmiTagMask));
1833 DeoptimizeIf(zero, instr, "Smi");
1834 __ CmpObjectType(object, JS_DATE_TYPE, scratch);
1835 DeoptimizeIf(not_equal, instr, "not a date object");
1837 if (index->value() == 0) {
1838 __ mov(result, FieldOperand(object, JSDate::kValueOffset));
1840 if (index->value() < JSDate::kFirstUncachedField) {
1841 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
1842 __ mov(scratch, Operand::StaticVariable(stamp));
1843 __ cmp(scratch, FieldOperand(object, JSDate::kCacheStampOffset));
1844 __ j(not_equal, &runtime, Label::kNear);
1845 __ mov(result, FieldOperand(object, JSDate::kValueOffset +
1846 kPointerSize * index->value()));
1847 __ jmp(&done, Label::kNear);
1850 __ PrepareCallCFunction(2, scratch);
1851 __ mov(Operand(esp, 0), object);
1852 __ mov(Operand(esp, 1 * kPointerSize), Immediate(index));
1853 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
1859 Operand LCodeGen::BuildSeqStringOperand(Register string,
1861 String::Encoding encoding) {
1862 if (index->IsConstantOperand()) {
1863 int offset = ToRepresentation(LConstantOperand::cast(index),
1864 Representation::Integer32());
1865 if (encoding == String::TWO_BYTE_ENCODING) {
1866 offset *= kUC16Size;
1868 STATIC_ASSERT(kCharSize == 1);
1869 return FieldOperand(string, SeqString::kHeaderSize + offset);
1871 return FieldOperand(
1872 string, ToRegister(index),
1873 encoding == String::ONE_BYTE_ENCODING ? times_1 : times_2,
1874 SeqString::kHeaderSize);
1878 void LCodeGen::DoSeqStringGetChar(LSeqStringGetChar* instr) {
1879 String::Encoding encoding = instr->hydrogen()->encoding();
1880 Register result = ToRegister(instr->result());
1881 Register string = ToRegister(instr->string());
1883 if (FLAG_debug_code) {
1885 __ mov(string, FieldOperand(string, HeapObject::kMapOffset));
1886 __ movzx_b(string, FieldOperand(string, Map::kInstanceTypeOffset));
1888 __ and_(string, Immediate(kStringRepresentationMask | kStringEncodingMask));
1889 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
1890 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
1891 __ cmp(string, Immediate(encoding == String::ONE_BYTE_ENCODING
1892 ? one_byte_seq_type : two_byte_seq_type));
1893 __ Check(equal, kUnexpectedStringType);
1897 Operand operand = BuildSeqStringOperand(string, instr->index(), encoding);
1898 if (encoding == String::ONE_BYTE_ENCODING) {
1899 __ movzx_b(result, operand);
1901 __ movzx_w(result, operand);
1906 void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
1907 String::Encoding encoding = instr->hydrogen()->encoding();
1908 Register string = ToRegister(instr->string());
1910 if (FLAG_debug_code) {
1911 Register value = ToRegister(instr->value());
1912 Register index = ToRegister(instr->index());
1913 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
1914 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
1916 instr->hydrogen()->encoding() == String::ONE_BYTE_ENCODING
1917 ? one_byte_seq_type : two_byte_seq_type;
1918 __ EmitSeqStringSetCharCheck(string, index, value, encoding_mask);
1921 Operand operand = BuildSeqStringOperand(string, instr->index(), encoding);
1922 if (instr->value()->IsConstantOperand()) {
1923 int value = ToRepresentation(LConstantOperand::cast(instr->value()),
1924 Representation::Integer32());
1925 DCHECK_LE(0, value);
1926 if (encoding == String::ONE_BYTE_ENCODING) {
1927 DCHECK_LE(value, String::kMaxOneByteCharCode);
1928 __ mov_b(operand, static_cast<int8_t>(value));
1930 DCHECK_LE(value, String::kMaxUtf16CodeUnit);
1931 __ mov_w(operand, static_cast<int16_t>(value));
1934 Register value = ToRegister(instr->value());
1935 if (encoding == String::ONE_BYTE_ENCODING) {
1936 __ mov_b(operand, value);
1938 __ mov_w(operand, value);
1944 void LCodeGen::DoAddI(LAddI* instr) {
1945 LOperand* left = instr->left();
1946 LOperand* right = instr->right();
1948 if (LAddI::UseLea(instr->hydrogen()) && !left->Equals(instr->result())) {
1949 if (right->IsConstantOperand()) {
1950 int32_t offset = ToRepresentation(LConstantOperand::cast(right),
1951 instr->hydrogen()->representation());
1952 __ lea(ToRegister(instr->result()), MemOperand(ToRegister(left), offset));
1954 Operand address(ToRegister(left), ToRegister(right), times_1, 0);
1955 __ lea(ToRegister(instr->result()), address);
1958 if (right->IsConstantOperand()) {
1959 __ add(ToOperand(left),
1960 ToImmediate(right, instr->hydrogen()->representation()));
1962 __ add(ToRegister(left), ToOperand(right));
1964 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1965 DeoptimizeIf(overflow, instr, "overflow");
1971 void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
1972 LOperand* left = instr->left();
1973 LOperand* right = instr->right();
1974 DCHECK(left->Equals(instr->result()));
1975 HMathMinMax::Operation operation = instr->hydrogen()->operation();
1976 if (instr->hydrogen()->representation().IsSmiOrInteger32()) {
1978 Condition condition = (operation == HMathMinMax::kMathMin)
1981 if (right->IsConstantOperand()) {
1982 Operand left_op = ToOperand(left);
1983 Immediate immediate = ToImmediate(LConstantOperand::cast(instr->right()),
1984 instr->hydrogen()->representation());
1985 __ cmp(left_op, immediate);
1986 __ j(condition, &return_left, Label::kNear);
1987 __ mov(left_op, immediate);
1989 Register left_reg = ToRegister(left);
1990 Operand right_op = ToOperand(right);
1991 __ cmp(left_reg, right_op);
1992 __ j(condition, &return_left, Label::kNear);
1993 __ mov(left_reg, right_op);
1995 __ bind(&return_left);
1997 DCHECK(instr->hydrogen()->representation().IsDouble());
1998 Label check_nan_left, check_zero, return_left, return_right;
1999 Condition condition = (operation == HMathMinMax::kMathMin) ? below : above;
2000 XMMRegister left_reg = ToDoubleRegister(left);
2001 XMMRegister right_reg = ToDoubleRegister(right);
2002 __ ucomisd(left_reg, right_reg);
2003 __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN.
2004 __ j(equal, &check_zero, Label::kNear); // left == right.
2005 __ j(condition, &return_left, Label::kNear);
2006 __ jmp(&return_right, Label::kNear);
2008 __ bind(&check_zero);
2009 XMMRegister xmm_scratch = double_scratch0();
2010 __ xorps(xmm_scratch, xmm_scratch);
2011 __ ucomisd(left_reg, xmm_scratch);
2012 __ j(not_equal, &return_left, Label::kNear); // left == right != 0.
2013 // At this point, both left and right are either 0 or -0.
2014 if (operation == HMathMinMax::kMathMin) {
2015 __ orpd(left_reg, right_reg);
2017 // Since we operate on +0 and/or -0, addsd and andsd have the same effect.
2018 __ addsd(left_reg, right_reg);
2020 __ jmp(&return_left, Label::kNear);
2022 __ bind(&check_nan_left);
2023 __ ucomisd(left_reg, left_reg); // NaN check.
2024 __ j(parity_even, &return_left, Label::kNear); // left == NaN.
2025 __ bind(&return_right);
2026 __ movaps(left_reg, right_reg);
2028 __ bind(&return_left);
2033 void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
2034 XMMRegister left = ToDoubleRegister(instr->left());
2035 XMMRegister right = ToDoubleRegister(instr->right());
2036 XMMRegister result = ToDoubleRegister(instr->result());
2037 switch (instr->op()) {
2039 __ addsd(left, right);
2042 __ subsd(left, right);
2045 __ mulsd(left, right);
2048 __ divsd(left, right);
2049 // Don't delete this mov. It may improve performance on some CPUs,
2050 // when there is a mulsd depending on the result
2051 __ movaps(left, left);
2054 // Pass two doubles as arguments on the stack.
2055 __ PrepareCallCFunction(4, eax);
2056 __ movsd(Operand(esp, 0 * kDoubleSize), left);
2057 __ movsd(Operand(esp, 1 * kDoubleSize), right);
2059 ExternalReference::mod_two_doubles_operation(isolate()),
2062 // Return value is in st(0) on ia32.
2063 // Store it into the result register.
2064 __ sub(Operand(esp), Immediate(kDoubleSize));
2065 __ fstp_d(Operand(esp, 0));
2066 __ movsd(result, Operand(esp, 0));
2067 __ add(Operand(esp), Immediate(kDoubleSize));
2077 void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
2078 DCHECK(ToRegister(instr->context()).is(esi));
2079 DCHECK(ToRegister(instr->left()).is(edx));
2080 DCHECK(ToRegister(instr->right()).is(eax));
2081 DCHECK(ToRegister(instr->result()).is(eax));
2084 CodeFactory::BinaryOpIC(isolate(), instr->op(), NO_OVERWRITE).code();
2085 CallCode(code, RelocInfo::CODE_TARGET, instr);
2089 template<class InstrType>
2090 void LCodeGen::EmitBranch(InstrType instr, Condition cc) {
2091 int left_block = instr->TrueDestination(chunk_);
2092 int right_block = instr->FalseDestination(chunk_);
2094 int next_block = GetNextEmittedBlock();
2096 if (right_block == left_block || cc == no_condition) {
2097 EmitGoto(left_block);
2098 } else if (left_block == next_block) {
2099 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
2100 } else if (right_block == next_block) {
2101 __ j(cc, chunk_->GetAssemblyLabel(left_block));
2103 __ j(cc, chunk_->GetAssemblyLabel(left_block));
2104 __ jmp(chunk_->GetAssemblyLabel(right_block));
2109 template<class InstrType>
2110 void LCodeGen::EmitFalseBranch(InstrType instr, Condition cc) {
2111 int false_block = instr->FalseDestination(chunk_);
2112 if (cc == no_condition) {
2113 __ jmp(chunk_->GetAssemblyLabel(false_block));
2115 __ j(cc, chunk_->GetAssemblyLabel(false_block));
2120 void LCodeGen::DoBranch(LBranch* instr) {
2121 Representation r = instr->hydrogen()->value()->representation();
2122 if (r.IsSmiOrInteger32()) {
2123 Register reg = ToRegister(instr->value());
2124 __ test(reg, Operand(reg));
2125 EmitBranch(instr, not_zero);
2126 } else if (r.IsDouble()) {
2127 DCHECK(!info()->IsStub());
2128 XMMRegister reg = ToDoubleRegister(instr->value());
2129 XMMRegister xmm_scratch = double_scratch0();
2130 __ xorps(xmm_scratch, xmm_scratch);
2131 __ ucomisd(reg, xmm_scratch);
2132 EmitBranch(instr, not_equal);
2133 } else if (r.IsSIMD128()) {
2134 DCHECK(!info()->IsStub());
2135 EmitBranch(instr, no_condition);
2137 DCHECK(r.IsTagged());
2138 Register reg = ToRegister(instr->value());
2139 HType type = instr->hydrogen()->value()->type();
2140 if (type.IsBoolean()) {
2141 DCHECK(!info()->IsStub());
2142 __ cmp(reg, factory()->true_value());
2143 EmitBranch(instr, equal);
2144 } else if (type.IsSmi()) {
2145 DCHECK(!info()->IsStub());
2146 __ test(reg, Operand(reg));
2147 EmitBranch(instr, not_equal);
2148 } else if (type.IsJSArray()) {
2149 DCHECK(!info()->IsStub());
2150 EmitBranch(instr, no_condition);
2151 } else if (type.IsHeapNumber()) {
2152 DCHECK(!info()->IsStub());
2153 XMMRegister xmm_scratch = double_scratch0();
2154 __ xorps(xmm_scratch, xmm_scratch);
2155 __ ucomisd(xmm_scratch, FieldOperand(reg, HeapNumber::kValueOffset));
2156 EmitBranch(instr, not_equal);
2157 } else if (type.IsString()) {
2158 DCHECK(!info()->IsStub());
2159 __ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0));
2160 EmitBranch(instr, not_equal);
2162 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
2163 if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
2165 if (expected.Contains(ToBooleanStub::UNDEFINED)) {
2166 // undefined -> false.
2167 __ cmp(reg, factory()->undefined_value());
2168 __ j(equal, instr->FalseLabel(chunk_));
2170 if (expected.Contains(ToBooleanStub::BOOLEAN)) {
2172 __ cmp(reg, factory()->true_value());
2173 __ j(equal, instr->TrueLabel(chunk_));
2175 __ cmp(reg, factory()->false_value());
2176 __ j(equal, instr->FalseLabel(chunk_));
2178 if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
2180 __ cmp(reg, factory()->null_value());
2181 __ j(equal, instr->FalseLabel(chunk_));
2184 if (expected.Contains(ToBooleanStub::SMI)) {
2185 // Smis: 0 -> false, all other -> true.
2186 __ test(reg, Operand(reg));
2187 __ j(equal, instr->FalseLabel(chunk_));
2188 __ JumpIfSmi(reg, instr->TrueLabel(chunk_));
2189 } else if (expected.NeedsMap()) {
2190 // If we need a map later and have a Smi -> deopt.
2191 __ test(reg, Immediate(kSmiTagMask));
2192 DeoptimizeIf(zero, instr, "Smi");
2195 Register map = no_reg; // Keep the compiler happy.
2196 if (expected.NeedsMap()) {
2197 map = ToRegister(instr->temp());
2198 DCHECK(!map.is(reg));
2199 __ mov(map, FieldOperand(reg, HeapObject::kMapOffset));
2201 if (expected.CanBeUndetectable()) {
2202 // Undetectable -> false.
2203 __ test_b(FieldOperand(map, Map::kBitFieldOffset),
2204 1 << Map::kIsUndetectable);
2205 __ j(not_zero, instr->FalseLabel(chunk_));
2209 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
2210 // spec object -> true.
2211 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
2212 __ j(above_equal, instr->TrueLabel(chunk_));
2215 if (expected.Contains(ToBooleanStub::STRING)) {
2216 // String value -> false iff empty.
2218 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
2219 __ j(above_equal, ¬_string, Label::kNear);
2220 __ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0));
2221 __ j(not_zero, instr->TrueLabel(chunk_));
2222 __ jmp(instr->FalseLabel(chunk_));
2223 __ bind(¬_string);
2226 if (expected.Contains(ToBooleanStub::SYMBOL)) {
2227 // Symbol value -> true.
2228 __ CmpInstanceType(map, SYMBOL_TYPE);
2229 __ j(equal, instr->TrueLabel(chunk_));
2232 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
2233 // heap number -> false iff +0, -0, or NaN.
2234 Label not_heap_number;
2235 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
2236 factory()->heap_number_map());
2237 __ j(not_equal, ¬_heap_number, Label::kNear);
2238 XMMRegister xmm_scratch = double_scratch0();
2239 __ xorps(xmm_scratch, xmm_scratch);
2240 __ ucomisd(xmm_scratch, FieldOperand(reg, HeapNumber::kValueOffset));
2241 __ j(zero, instr->FalseLabel(chunk_));
2242 __ jmp(instr->TrueLabel(chunk_));
2243 __ bind(¬_heap_number);
2246 if (!expected.IsGeneric()) {
2247 // We've seen something for the first time -> deopt.
2248 // This can only happen if we are not generic already.
2249 DeoptimizeIf(no_condition, instr, "unexpected object");
2256 void LCodeGen::EmitGoto(int block) {
2257 if (!IsNextEmittedBlock(block)) {
2258 __ jmp(chunk_->GetAssemblyLabel(LookupDestination(block)));
2263 void LCodeGen::DoGoto(LGoto* instr) {
2264 EmitGoto(instr->block_id());
2268 Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
2269 Condition cond = no_condition;
2272 case Token::EQ_STRICT:
2276 case Token::NE_STRICT:
2280 cond = is_unsigned ? below : less;
2283 cond = is_unsigned ? above : greater;
2286 cond = is_unsigned ? below_equal : less_equal;
2289 cond = is_unsigned ? above_equal : greater_equal;
2292 case Token::INSTANCEOF:
2300 void LCodeGen::DoCompareNumericAndBranch(LCompareNumericAndBranch* instr) {
2301 LOperand* left = instr->left();
2302 LOperand* right = instr->right();
2304 instr->is_double() ||
2305 instr->hydrogen()->left()->CheckFlag(HInstruction::kUint32) ||
2306 instr->hydrogen()->right()->CheckFlag(HInstruction::kUint32);
2307 Condition cc = TokenToCondition(instr->op(), is_unsigned);
2309 if (left->IsConstantOperand() && right->IsConstantOperand()) {
2310 // We can statically evaluate the comparison.
2311 double left_val = ToDouble(LConstantOperand::cast(left));
2312 double right_val = ToDouble(LConstantOperand::cast(right));
2313 int next_block = EvalComparison(instr->op(), left_val, right_val) ?
2314 instr->TrueDestination(chunk_) : instr->FalseDestination(chunk_);
2315 EmitGoto(next_block);
2317 if (instr->is_double()) {
2318 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
2319 // Don't base result on EFLAGS when a NaN is involved. Instead
2320 // jump to the false block.
2321 __ j(parity_even, instr->FalseLabel(chunk_));
2323 if (right->IsConstantOperand()) {
2324 __ cmp(ToOperand(left),
2325 ToImmediate(right, instr->hydrogen()->representation()));
2326 } else if (left->IsConstantOperand()) {
2327 __ cmp(ToOperand(right),
2328 ToImmediate(left, instr->hydrogen()->representation()));
2329 // We commuted the operands, so commute the condition.
2330 cc = CommuteCondition(cc);
2332 __ cmp(ToRegister(left), ToOperand(right));
2335 EmitBranch(instr, cc);
2340 void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
2341 Register left = ToRegister(instr->left());
2343 if (instr->right()->IsConstantOperand()) {
2344 Handle<Object> right = ToHandle(LConstantOperand::cast(instr->right()));
2345 __ CmpObject(left, right);
2347 Operand right = ToOperand(instr->right());
2348 __ cmp(left, right);
2350 EmitBranch(instr, equal);
2354 void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) {
2355 if (instr->hydrogen()->representation().IsTagged()) {
2356 Register input_reg = ToRegister(instr->object());
2357 __ cmp(input_reg, factory()->the_hole_value());
2358 EmitBranch(instr, equal);
2362 XMMRegister input_reg = ToDoubleRegister(instr->object());
2363 __ ucomisd(input_reg, input_reg);
2364 EmitFalseBranch(instr, parity_odd);
2366 __ sub(esp, Immediate(kDoubleSize));
2367 __ movsd(MemOperand(esp, 0), input_reg);
2369 __ add(esp, Immediate(kDoubleSize));
2370 int offset = sizeof(kHoleNanUpper32);
2371 __ cmp(MemOperand(esp, -offset), Immediate(kHoleNanUpper32));
2372 EmitBranch(instr, equal);
2376 void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
2377 Representation rep = instr->hydrogen()->value()->representation();
2378 DCHECK(!rep.IsInteger32());
2379 Register scratch = ToRegister(instr->temp());
2381 if (rep.IsDouble()) {
2382 XMMRegister value = ToDoubleRegister(instr->value());
2383 XMMRegister xmm_scratch = double_scratch0();
2384 __ xorps(xmm_scratch, xmm_scratch);
2385 __ ucomisd(xmm_scratch, value);
2386 EmitFalseBranch(instr, not_equal);
2387 __ movmskpd(scratch, value);
2388 __ test(scratch, Immediate(1));
2389 EmitBranch(instr, not_zero);
2391 Register value = ToRegister(instr->value());
2392 Handle<Map> map = masm()->isolate()->factory()->heap_number_map();
2393 __ CheckMap(value, map, instr->FalseLabel(chunk()), DO_SMI_CHECK);
2394 __ cmp(FieldOperand(value, HeapNumber::kExponentOffset),
2396 EmitFalseBranch(instr, no_overflow);
2397 __ cmp(FieldOperand(value, HeapNumber::kMantissaOffset),
2398 Immediate(0x00000000));
2399 EmitBranch(instr, equal);
2404 Condition LCodeGen::EmitIsObject(Register input,
2406 Label* is_not_object,
2408 __ JumpIfSmi(input, is_not_object);
2410 __ cmp(input, isolate()->factory()->null_value());
2411 __ j(equal, is_object);
2413 __ mov(temp1, FieldOperand(input, HeapObject::kMapOffset));
2414 // Undetectable objects behave like undefined.
2415 __ test_b(FieldOperand(temp1, Map::kBitFieldOffset),
2416 1 << Map::kIsUndetectable);
2417 __ j(not_zero, is_not_object);
2419 __ movzx_b(temp1, FieldOperand(temp1, Map::kInstanceTypeOffset));
2420 __ cmp(temp1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
2421 __ j(below, is_not_object);
2422 __ cmp(temp1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
2427 void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
2428 Register reg = ToRegister(instr->value());
2429 Register temp = ToRegister(instr->temp());
2431 Condition true_cond = EmitIsObject(
2432 reg, temp, instr->FalseLabel(chunk_), instr->TrueLabel(chunk_));
2434 EmitBranch(instr, true_cond);
2438 Condition LCodeGen::EmitIsString(Register input,
2440 Label* is_not_string,
2441 SmiCheck check_needed = INLINE_SMI_CHECK) {
2442 if (check_needed == INLINE_SMI_CHECK) {
2443 __ JumpIfSmi(input, is_not_string);
2446 Condition cond = masm_->IsObjectStringType(input, temp1, temp1);
2452 void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
2453 Register reg = ToRegister(instr->value());
2454 Register temp = ToRegister(instr->temp());
2456 SmiCheck check_needed =
2457 instr->hydrogen()->value()->type().IsHeapObject()
2458 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
2460 Condition true_cond = EmitIsString(
2461 reg, temp, instr->FalseLabel(chunk_), check_needed);
2463 EmitBranch(instr, true_cond);
2467 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
2468 Operand input = ToOperand(instr->value());
2470 __ test(input, Immediate(kSmiTagMask));
2471 EmitBranch(instr, zero);
2475 void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
2476 Register input = ToRegister(instr->value());
2477 Register temp = ToRegister(instr->temp());
2479 if (!instr->hydrogen()->value()->type().IsHeapObject()) {
2480 STATIC_ASSERT(kSmiTag == 0);
2481 __ JumpIfSmi(input, instr->FalseLabel(chunk_));
2483 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
2484 __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
2485 1 << Map::kIsUndetectable);
2486 EmitBranch(instr, not_zero);
2490 static Condition ComputeCompareCondition(Token::Value op) {
2492 case Token::EQ_STRICT:
2502 return greater_equal;
2505 return no_condition;
2510 void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
2511 Token::Value op = instr->op();
2513 Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
2514 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2516 Condition condition = ComputeCompareCondition(op);
2517 __ test(eax, Operand(eax));
2519 EmitBranch(instr, condition);
2523 static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
2524 InstanceType from = instr->from();
2525 InstanceType to = instr->to();
2526 if (from == FIRST_TYPE) return to;
2527 DCHECK(from == to || to == LAST_TYPE);
2532 static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
2533 InstanceType from = instr->from();
2534 InstanceType to = instr->to();
2535 if (from == to) return equal;
2536 if (to == LAST_TYPE) return above_equal;
2537 if (from == FIRST_TYPE) return below_equal;
2543 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
2544 Register input = ToRegister(instr->value());
2545 Register temp = ToRegister(instr->temp());
2547 if (!instr->hydrogen()->value()->type().IsHeapObject()) {
2548 __ JumpIfSmi(input, instr->FalseLabel(chunk_));
2551 __ CmpObjectType(input, TestType(instr->hydrogen()), temp);
2552 EmitBranch(instr, BranchCondition(instr->hydrogen()));
2556 void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
2557 Register input = ToRegister(instr->value());
2558 Register result = ToRegister(instr->result());
2560 __ AssertString(input);
2562 __ mov(result, FieldOperand(input, String::kHashFieldOffset));
2563 __ IndexFromHash(result, result);
2567 void LCodeGen::DoHasCachedArrayIndexAndBranch(
2568 LHasCachedArrayIndexAndBranch* instr) {
2569 Register input = ToRegister(instr->value());
2571 __ test(FieldOperand(input, String::kHashFieldOffset),
2572 Immediate(String::kContainsCachedArrayIndexMask));
2573 EmitBranch(instr, equal);
2577 // Branches to a label or falls through with the answer in the z flag. Trashes
2578 // the temp registers, but not the input.
2579 void LCodeGen::EmitClassOfTest(Label* is_true,
2581 Handle<String>class_name,
2585 DCHECK(!input.is(temp));
2586 DCHECK(!input.is(temp2));
2587 DCHECK(!temp.is(temp2));
2588 __ JumpIfSmi(input, is_false);
2590 if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
2591 // Assuming the following assertions, we can use the same compares to test
2592 // for both being a function type and being in the object type range.
2593 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
2594 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2595 FIRST_SPEC_OBJECT_TYPE + 1);
2596 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2597 LAST_SPEC_OBJECT_TYPE - 1);
2598 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
2599 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
2600 __ j(below, is_false);
2601 __ j(equal, is_true);
2602 __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
2603 __ j(equal, is_true);
2605 // Faster code path to avoid two compares: subtract lower bound from the
2606 // actual type and do a signed compare with the width of the type range.
2607 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
2608 __ movzx_b(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
2609 __ sub(Operand(temp2), Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
2610 __ cmp(Operand(temp2), Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
2611 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
2612 __ j(above, is_false);
2615 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
2616 // Check if the constructor in the map is a function.
2617 __ mov(temp, FieldOperand(temp, Map::kConstructorOffset));
2618 // Objects with a non-function constructor have class 'Object'.
2619 __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2);
2620 if (String::Equals(class_name, isolate()->factory()->Object_string())) {
2621 __ j(not_equal, is_true);
2623 __ j(not_equal, is_false);
2626 // temp now contains the constructor function. Grab the
2627 // instance class name from there.
2628 __ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
2629 __ mov(temp, FieldOperand(temp,
2630 SharedFunctionInfo::kInstanceClassNameOffset));
2631 // The class name we are testing against is internalized since it's a literal.
2632 // The name in the constructor is internalized because of the way the context
2633 // is booted. This routine isn't expected to work for random API-created
2634 // classes and it doesn't have to because you can't access it with natives
2635 // syntax. Since both sides are internalized it is sufficient to use an
2636 // identity comparison.
2637 __ cmp(temp, class_name);
2638 // End with the answer in the z flag.
2642 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
2643 Register input = ToRegister(instr->value());
2644 Register temp = ToRegister(instr->temp());
2645 Register temp2 = ToRegister(instr->temp2());
2647 Handle<String> class_name = instr->hydrogen()->class_name();
2649 EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_),
2650 class_name, input, temp, temp2);
2652 EmitBranch(instr, equal);
2656 void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
2657 Register reg = ToRegister(instr->value());
2658 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
2659 EmitBranch(instr, equal);
2663 void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
2664 // Object and function are in fixed registers defined by the stub.
2665 DCHECK(ToRegister(instr->context()).is(esi));
2666 InstanceofStub stub(isolate(), InstanceofStub::kArgsInRegisters);
2667 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
2669 Label true_value, done;
2670 __ test(eax, Operand(eax));
2671 __ j(zero, &true_value, Label::kNear);
2672 __ mov(ToRegister(instr->result()), factory()->false_value());
2673 __ jmp(&done, Label::kNear);
2674 __ bind(&true_value);
2675 __ mov(ToRegister(instr->result()), factory()->true_value());
2680 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
2681 class DeferredInstanceOfKnownGlobal FINAL : public LDeferredCode {
2683 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
2684 LInstanceOfKnownGlobal* instr)
2685 : LDeferredCode(codegen), instr_(instr) { }
2686 virtual void Generate() OVERRIDE {
2687 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
2689 virtual LInstruction* instr() OVERRIDE { return instr_; }
2690 Label* map_check() { return &map_check_; }
2692 LInstanceOfKnownGlobal* instr_;
2696 DeferredInstanceOfKnownGlobal* deferred;
2697 deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr);
2699 Label done, false_result;
2700 Register object = ToRegister(instr->value());
2701 Register temp = ToRegister(instr->temp());
2703 // A Smi is not an instance of anything.
2704 __ JumpIfSmi(object, &false_result, Label::kNear);
2706 // This is the inlined call site instanceof cache. The two occurences of the
2707 // hole value will be patched to the last map/result pair generated by the
2710 Register map = ToRegister(instr->temp());
2711 __ mov(map, FieldOperand(object, HeapObject::kMapOffset));
2712 __ bind(deferred->map_check()); // Label for calculating code patching.
2713 Handle<Cell> cache_cell = factory()->NewCell(factory()->the_hole_value());
2714 __ cmp(map, Operand::ForCell(cache_cell)); // Patched to cached map.
2715 __ j(not_equal, &cache_miss, Label::kNear);
2716 __ mov(eax, factory()->the_hole_value()); // Patched to either true or false.
2717 __ jmp(&done, Label::kNear);
2719 // The inlined call site cache did not match. Check for null and string
2720 // before calling the deferred code.
2721 __ bind(&cache_miss);
2722 // Null is not an instance of anything.
2723 __ cmp(object, factory()->null_value());
2724 __ j(equal, &false_result, Label::kNear);
2726 // String values are not instances of anything.
2727 Condition is_string = masm_->IsObjectStringType(object, temp, temp);
2728 __ j(is_string, &false_result, Label::kNear);
2730 // Go to the deferred code.
2731 __ jmp(deferred->entry());
2733 __ bind(&false_result);
2734 __ mov(ToRegister(instr->result()), factory()->false_value());
2736 // Here result has either true or false. Deferred code also produces true or
2738 __ bind(deferred->exit());
2743 void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
2745 PushSafepointRegistersScope scope(this);
2747 InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
2748 flags = static_cast<InstanceofStub::Flags>(
2749 flags | InstanceofStub::kArgsInRegisters);
2750 flags = static_cast<InstanceofStub::Flags>(
2751 flags | InstanceofStub::kCallSiteInlineCheck);
2752 flags = static_cast<InstanceofStub::Flags>(
2753 flags | InstanceofStub::kReturnTrueFalseObject);
2754 InstanceofStub stub(isolate(), flags);
2756 // Get the temp register reserved by the instruction. This needs to be a
2757 // register which is pushed last by PushSafepointRegisters as top of the
2758 // stack is used to pass the offset to the location of the map check to
2760 Register temp = ToRegister(instr->temp());
2761 DCHECK(MacroAssembler::SafepointRegisterStackIndex(temp) == 0);
2762 __ LoadHeapObject(InstanceofStub::right(), instr->function());
2763 static const int kAdditionalDelta = 13;
2764 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
2765 __ mov(temp, Immediate(delta));
2766 __ StoreToSafepointRegisterSlot(temp, temp);
2767 CallCodeGeneric(stub.GetCode(),
2768 RelocInfo::CODE_TARGET,
2770 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
2771 // Get the deoptimization index of the LLazyBailout-environment that
2772 // corresponds to this instruction.
2773 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
2774 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
2776 // Put the result value into the eax slot and restore all registers.
2777 __ StoreToSafepointRegisterSlot(eax, eax);
2781 void LCodeGen::DoCmpT(LCmpT* instr) {
2782 Token::Value op = instr->op();
2784 Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
2785 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2787 Condition condition = ComputeCompareCondition(op);
2788 Label true_value, done;
2789 __ test(eax, Operand(eax));
2790 __ j(condition, &true_value, Label::kNear);
2791 __ mov(ToRegister(instr->result()), factory()->false_value());
2792 __ jmp(&done, Label::kNear);
2793 __ bind(&true_value);
2794 __ mov(ToRegister(instr->result()), factory()->true_value());
2799 void LCodeGen::EmitReturn(LReturn* instr, bool dynamic_frame_alignment) {
2800 int extra_value_count = dynamic_frame_alignment ? 2 : 1;
2802 if (instr->has_constant_parameter_count()) {
2803 int parameter_count = ToInteger32(instr->constant_parameter_count());
2804 if (dynamic_frame_alignment && FLAG_debug_code) {
2806 (parameter_count + extra_value_count) * kPointerSize),
2807 Immediate(kAlignmentZapValue));
2808 __ Assert(equal, kExpectedAlignmentMarker);
2810 __ Ret((parameter_count + extra_value_count) * kPointerSize, ecx);
2812 Register reg = ToRegister(instr->parameter_count());
2813 // The argument count parameter is a smi
2815 Register return_addr_reg = reg.is(ecx) ? ebx : ecx;
2816 if (dynamic_frame_alignment && FLAG_debug_code) {
2817 DCHECK(extra_value_count == 2);
2818 __ cmp(Operand(esp, reg, times_pointer_size,
2819 extra_value_count * kPointerSize),
2820 Immediate(kAlignmentZapValue));
2821 __ Assert(equal, kExpectedAlignmentMarker);
2824 // emit code to restore stack based on instr->parameter_count()
2825 __ pop(return_addr_reg); // save return address
2826 if (dynamic_frame_alignment) {
2827 __ inc(reg); // 1 more for alignment
2829 __ shl(reg, kPointerSizeLog2);
2831 __ jmp(return_addr_reg);
2836 void LCodeGen::DoReturn(LReturn* instr) {
2837 if (FLAG_trace && info()->IsOptimizing()) {
2838 // Preserve the return value on the stack and rely on the runtime call
2839 // to return the value in the same register. We're leaving the code
2840 // managed by the register allocator and tearing down the frame, it's
2841 // safe to write to the context register.
2843 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2844 __ CallRuntime(Runtime::kTraceExit, 1);
2846 if (info()->saves_caller_doubles()) RestoreCallerDoubles();
2847 if (dynamic_frame_alignment_) {
2848 // Fetch the state of the dynamic frame alignment.
2849 __ mov(edx, Operand(ebp,
2850 JavaScriptFrameConstants::kDynamicAlignmentStateOffset));
2852 int no_frame_start = -1;
2853 if (NeedsEagerFrame()) {
2856 no_frame_start = masm_->pc_offset();
2858 if (dynamic_frame_alignment_) {
2860 __ cmp(edx, Immediate(kNoAlignmentPadding));
2861 __ j(equal, &no_padding, Label::kNear);
2863 EmitReturn(instr, true);
2864 __ bind(&no_padding);
2867 EmitReturn(instr, false);
2868 if (no_frame_start != -1) {
2869 info()->AddNoFrameRange(no_frame_start, masm_->pc_offset());
2874 void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
2875 Register result = ToRegister(instr->result());
2876 __ mov(result, Operand::ForCell(instr->hydrogen()->cell().handle()));
2877 if (instr->hydrogen()->RequiresHoleCheck()) {
2878 __ cmp(result, factory()->the_hole_value());
2879 DeoptimizeIf(equal, instr, "hole");
2885 void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
2886 DCHECK(FLAG_vector_ics);
2887 Register vector = ToRegister(instr->temp_vector());
2888 DCHECK(vector.is(VectorLoadICDescriptor::VectorRegister()));
2889 __ mov(vector, instr->hydrogen()->feedback_vector());
2890 // No need to allocate this register.
2891 DCHECK(VectorLoadICDescriptor::SlotRegister().is(eax));
2892 __ mov(VectorLoadICDescriptor::SlotRegister(),
2893 Immediate(Smi::FromInt(instr->hydrogen()->slot())));
2897 void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
2898 DCHECK(ToRegister(instr->context()).is(esi));
2899 DCHECK(ToRegister(instr->global_object())
2900 .is(LoadDescriptor::ReceiverRegister()));
2901 DCHECK(ToRegister(instr->result()).is(eax));
2903 __ mov(LoadDescriptor::NameRegister(), instr->name());
2904 if (FLAG_vector_ics) {
2905 EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr);
2907 ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL;
2908 Handle<Code> ic = CodeFactory::LoadIC(isolate(), mode).code();
2909 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2913 void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
2914 Register value = ToRegister(instr->value());
2915 Handle<PropertyCell> cell_handle = instr->hydrogen()->cell().handle();
2917 // If the cell we are storing to contains the hole it could have
2918 // been deleted from the property dictionary. In that case, we need
2919 // to update the property details in the property dictionary to mark
2920 // it as no longer deleted. We deoptimize in that case.
2921 if (instr->hydrogen()->RequiresHoleCheck()) {
2922 __ cmp(Operand::ForCell(cell_handle), factory()->the_hole_value());
2923 DeoptimizeIf(equal, instr, "hole");
2927 __ mov(Operand::ForCell(cell_handle), value);
2928 // Cells are always rescanned, so no write barrier here.
2932 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
2933 Register context = ToRegister(instr->context());
2934 Register result = ToRegister(instr->result());
2935 __ mov(result, ContextOperand(context, instr->slot_index()));
2937 if (instr->hydrogen()->RequiresHoleCheck()) {
2938 __ cmp(result, factory()->the_hole_value());
2939 if (instr->hydrogen()->DeoptimizesOnHole()) {
2940 DeoptimizeIf(equal, instr, "hole");
2943 __ j(not_equal, &is_not_hole, Label::kNear);
2944 __ mov(result, factory()->undefined_value());
2945 __ bind(&is_not_hole);
2951 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2952 Register context = ToRegister(instr->context());
2953 Register value = ToRegister(instr->value());
2955 Label skip_assignment;
2957 Operand target = ContextOperand(context, instr->slot_index());
2958 if (instr->hydrogen()->RequiresHoleCheck()) {
2959 __ cmp(target, factory()->the_hole_value());
2960 if (instr->hydrogen()->DeoptimizesOnHole()) {
2961 DeoptimizeIf(equal, instr, "hole");
2963 __ j(not_equal, &skip_assignment, Label::kNear);
2967 __ mov(target, value);
2968 if (instr->hydrogen()->NeedsWriteBarrier()) {
2969 SmiCheck check_needed =
2970 instr->hydrogen()->value()->type().IsHeapObject()
2971 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
2972 Register temp = ToRegister(instr->temp());
2973 int offset = Context::SlotOffset(instr->slot_index());
2974 __ RecordWriteContextSlot(context,
2979 EMIT_REMEMBERED_SET,
2983 __ bind(&skip_assignment);
2987 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
2988 HObjectAccess access = instr->hydrogen()->access();
2989 int offset = access.offset();
2991 if (access.IsExternalMemory()) {
2992 Register result = ToRegister(instr->result());
2993 MemOperand operand = instr->object()->IsConstantOperand()
2994 ? MemOperand::StaticVariable(ToExternalReference(
2995 LConstantOperand::cast(instr->object())))
2996 : MemOperand(ToRegister(instr->object()), offset);
2997 __ Load(result, operand, access.representation());
3001 Register object = ToRegister(instr->object());
3002 if (instr->hydrogen()->representation().IsDouble()) {
3003 XMMRegister result = ToDoubleRegister(instr->result());
3004 __ movsd(result, FieldOperand(object, offset));
3008 Register result = ToRegister(instr->result());
3009 if (!access.IsInobject()) {
3010 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
3013 __ Load(result, FieldOperand(object, offset), access.representation());
3017 void LCodeGen::EmitPushTaggedOperand(LOperand* operand) {
3018 DCHECK(!operand->IsDoubleRegister());
3019 if (operand->IsConstantOperand()) {
3020 Handle<Object> object = ToHandle(LConstantOperand::cast(operand));
3021 AllowDeferredHandleDereference smi_check;
3022 if (object->IsSmi()) {
3023 __ Push(Handle<Smi>::cast(object));
3025 __ PushHeapObject(Handle<HeapObject>::cast(object));
3027 } else if (operand->IsRegister()) {
3028 __ push(ToRegister(operand));
3030 __ push(ToOperand(operand));
3035 void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
3036 DCHECK(ToRegister(instr->context()).is(esi));
3037 DCHECK(ToRegister(instr->object()).is(LoadDescriptor::ReceiverRegister()));
3038 DCHECK(ToRegister(instr->result()).is(eax));
3040 __ mov(LoadDescriptor::NameRegister(), instr->name());
3041 if (FLAG_vector_ics) {
3042 EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr);
3044 Handle<Code> ic = CodeFactory::LoadIC(isolate(), NOT_CONTEXTUAL).code();
3045 CallCode(ic, RelocInfo::CODE_TARGET, instr);
3049 void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
3050 Register function = ToRegister(instr->function());
3051 Register temp = ToRegister(instr->temp());
3052 Register result = ToRegister(instr->result());
3054 // Get the prototype or initial map from the function.
3056 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
3058 // Check that the function has a prototype or an initial map.
3059 __ cmp(Operand(result), Immediate(factory()->the_hole_value()));
3060 DeoptimizeIf(equal, instr, "hole");
3062 // If the function does not have an initial map, we're done.
3064 __ CmpObjectType(result, MAP_TYPE, temp);
3065 __ j(not_equal, &done, Label::kNear);
3067 // Get the prototype from the initial map.
3068 __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
3075 void LCodeGen::DoLoadRoot(LLoadRoot* instr) {
3076 Register result = ToRegister(instr->result());
3077 __ LoadRoot(result, instr->index());
3081 void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
3082 Register arguments = ToRegister(instr->arguments());
3083 Register result = ToRegister(instr->result());
3084 if (instr->length()->IsConstantOperand() &&
3085 instr->index()->IsConstantOperand()) {
3086 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
3087 int const_length = ToInteger32(LConstantOperand::cast(instr->length()));
3088 int index = (const_length - const_index) + 1;
3089 __ mov(result, Operand(arguments, index * kPointerSize));
3091 Register length = ToRegister(instr->length());
3092 Operand index = ToOperand(instr->index());
3093 // There are two words between the frame pointer and the last argument.
3094 // Subtracting from length accounts for one of them add one more.
3095 __ sub(length, index);
3096 __ mov(result, Operand(arguments, length, times_4, kPointerSize));
3101 void LCodeGen::DoDeferredSIMD128ToTagged(LInstruction* instr,
3102 Runtime::FunctionId id) {
3103 // TODO(3095996): Get rid of this. For now, we need to make the
3104 // result register contain a valid pointer because it is already
3105 // contained in the register pointer map.
3106 Register reg = ToRegister(instr->result());
3107 __ Move(reg, Immediate(0));
3109 PushSafepointRegistersScope scope(this);
3110 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3111 __ CallRuntimeSaveDoubles(id);
3112 RecordSafepointWithRegisters(
3113 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
3114 __ StoreToSafepointRegisterSlot(reg, eax);
3118 void LCodeGen::HandleExternalArrayOpRequiresTemp(
3120 Representation key_representation,
3121 ElementsKind elements_kind) {
3122 if (ExternalArrayOpRequiresPreScale(key_representation, elements_kind)) {
3123 int pre_shift_size = ElementsKindToShiftSize(elements_kind) -
3124 static_cast<int>(maximal_scale_factor);
3125 if (key_representation.IsSmi()) {
3126 pre_shift_size -= kSmiTagSize;
3128 DCHECK(pre_shift_size > 0);
3129 __ shl(ToRegister(key), pre_shift_size);
3131 __ SmiUntag(ToRegister(key));
3136 void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
3137 ElementsKind elements_kind = instr->elements_kind();
3138 LOperand* key = instr->key();
3139 if (!key->IsConstantOperand() &&
3140 ExternalArrayOpRequiresTemp(
3141 instr->hydrogen()->key()->representation(), elements_kind)) {
3142 HandleExternalArrayOpRequiresTemp(
3143 key, instr->hydrogen()->key()->representation(), elements_kind);
3146 Operand operand(BuildFastArrayOperand(
3149 instr->hydrogen()->key()->representation(),
3151 instr->base_offset()));
3152 if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
3153 elements_kind == FLOAT32_ELEMENTS) {
3154 XMMRegister result(ToDoubleRegister(instr->result()));
3155 __ movss(result, operand);
3156 __ cvtss2sd(result, result);
3157 } else if (elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
3158 elements_kind == FLOAT64_ELEMENTS) {
3159 __ movsd(ToDoubleRegister(instr->result()), operand);
3160 } else if (IsSIMD128ElementsKind(elements_kind)) {
3161 __ movups(ToSIMD128Register(instr->result()), operand);
3163 Register result(ToRegister(instr->result()));
3164 switch (elements_kind) {
3165 case EXTERNAL_INT8_ELEMENTS:
3167 __ movsx_b(result, operand);
3169 case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
3170 case EXTERNAL_UINT8_ELEMENTS:
3171 case UINT8_ELEMENTS:
3172 case UINT8_CLAMPED_ELEMENTS:
3173 __ movzx_b(result, operand);
3175 case EXTERNAL_INT16_ELEMENTS:
3176 case INT16_ELEMENTS:
3177 __ movsx_w(result, operand);
3179 case EXTERNAL_UINT16_ELEMENTS:
3180 case UINT16_ELEMENTS:
3181 __ movzx_w(result, operand);
3183 case EXTERNAL_INT32_ELEMENTS:
3184 case INT32_ELEMENTS:
3185 __ mov(result, operand);
3187 case EXTERNAL_UINT32_ELEMENTS:
3188 case UINT32_ELEMENTS:
3189 __ mov(result, operand);
3190 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
3191 __ test(result, Operand(result));
3192 DeoptimizeIf(negative, instr, "negative value");
3195 case EXTERNAL_FLOAT32_ELEMENTS:
3196 case EXTERNAL_FLOAT64_ELEMENTS:
3197 case EXTERNAL_FLOAT32x4_ELEMENTS:
3198 case EXTERNAL_FLOAT64x2_ELEMENTS:
3199 case EXTERNAL_INT32x4_ELEMENTS:
3200 case FLOAT32_ELEMENTS:
3201 case FLOAT64_ELEMENTS:
3202 case FLOAT32x4_ELEMENTS:
3203 case FLOAT64x2_ELEMENTS:
3204 case INT32x4_ELEMENTS:
3205 case FAST_SMI_ELEMENTS:
3207 case FAST_DOUBLE_ELEMENTS:
3208 case FAST_HOLEY_SMI_ELEMENTS:
3209 case FAST_HOLEY_ELEMENTS:
3210 case FAST_HOLEY_DOUBLE_ELEMENTS:
3211 case DICTIONARY_ELEMENTS:
3212 case SLOPPY_ARGUMENTS_ELEMENTS:
3220 void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
3221 if (instr->hydrogen()->RequiresHoleCheck()) {
3222 Operand hole_check_operand = BuildFastArrayOperand(
3223 instr->elements(), instr->key(),
3224 instr->hydrogen()->key()->representation(),
3225 FAST_DOUBLE_ELEMENTS,
3226 instr->base_offset() + sizeof(kHoleNanLower32));
3227 __ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
3228 DeoptimizeIf(equal, instr, "hole");
3231 Operand double_load_operand = BuildFastArrayOperand(
3234 instr->hydrogen()->key()->representation(),
3235 FAST_DOUBLE_ELEMENTS,
3236 instr->base_offset());
3237 XMMRegister result = ToDoubleRegister(instr->result());
3238 __ movsd(result, double_load_operand);
3242 void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
3243 Register result = ToRegister(instr->result());
3247 BuildFastArrayOperand(instr->elements(), instr->key(),
3248 instr->hydrogen()->key()->representation(),
3249 FAST_ELEMENTS, instr->base_offset()));
3251 // Check for the hole value.
3252 if (instr->hydrogen()->RequiresHoleCheck()) {
3253 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
3254 __ test(result, Immediate(kSmiTagMask));
3255 DeoptimizeIf(not_equal, instr, "not a Smi");
3257 __ cmp(result, factory()->the_hole_value());
3258 DeoptimizeIf(equal, instr, "hole");
3264 void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
3265 if (instr->is_typed_elements()) {
3266 DoLoadKeyedExternalArray(instr);
3267 } else if (instr->hydrogen()->representation().IsDouble()) {
3268 DoLoadKeyedFixedDoubleArray(instr);
3270 DoLoadKeyedFixedArray(instr);
3275 Operand LCodeGen::BuildFastArrayOperand(
3276 LOperand* elements_pointer,
3278 Representation key_representation,
3279 ElementsKind elements_kind,
3280 uint32_t base_offset) {
3281 Register elements_pointer_reg = ToRegister(elements_pointer);
3282 int element_shift_size = ElementsKindToShiftSize(elements_kind);
3283 int shift_size = element_shift_size;
3284 if (key->IsConstantOperand()) {
3285 int constant_value = ToInteger32(LConstantOperand::cast(key));
3286 if (constant_value & 0xF0000000) {
3287 Abort(kArrayIndexConstantValueTooBig);
3289 return Operand(elements_pointer_reg,
3290 ((constant_value) << shift_size)
3293 if (ExternalArrayOpRequiresPreScale(key_representation, elements_kind)) {
3294 // Make sure the key is pre-scaled against maximal_scale_factor.
3295 shift_size = static_cast<int>(maximal_scale_factor);
3296 } else if (key_representation.IsSmi() && (shift_size >= 1)) {
3297 // Take the tag bit into account while computing the shift size.
3298 shift_size -= kSmiTagSize;
3300 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
3301 return Operand(elements_pointer_reg,
3309 void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
3310 DCHECK(ToRegister(instr->context()).is(esi));
3311 DCHECK(ToRegister(instr->object()).is(LoadDescriptor::ReceiverRegister()));
3312 DCHECK(ToRegister(instr->key()).is(LoadDescriptor::NameRegister()));
3314 if (FLAG_vector_ics) {
3315 EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr);
3318 Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
3319 CallCode(ic, RelocInfo::CODE_TARGET, instr);
3323 void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
3324 Register result = ToRegister(instr->result());
3326 if (instr->hydrogen()->from_inlined()) {
3327 __ lea(result, Operand(esp, -2 * kPointerSize));
3329 // Check for arguments adapter frame.
3330 Label done, adapted;
3331 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3332 __ mov(result, Operand(result, StandardFrameConstants::kContextOffset));
3333 __ cmp(Operand(result),
3334 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3335 __ j(equal, &adapted, Label::kNear);
3337 // No arguments adaptor frame.
3338 __ mov(result, Operand(ebp));
3339 __ jmp(&done, Label::kNear);
3341 // Arguments adaptor frame present.
3343 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3345 // Result is the frame pointer for the frame if not adapted and for the real
3346 // frame below the adaptor frame if adapted.
3352 void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
3353 Operand elem = ToOperand(instr->elements());
3354 Register result = ToRegister(instr->result());
3358 // If no arguments adaptor frame the number of arguments is fixed.
3360 __ mov(result, Immediate(scope()->num_parameters()));
3361 __ j(equal, &done, Label::kNear);
3363 // Arguments adaptor frame present. Get argument length from there.
3364 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3365 __ mov(result, Operand(result,
3366 ArgumentsAdaptorFrameConstants::kLengthOffset));
3367 __ SmiUntag(result);
3369 // Argument length is in result register.
3374 void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
3375 Register receiver = ToRegister(instr->receiver());
3376 Register function = ToRegister(instr->function());
3378 // If the receiver is null or undefined, we have to pass the global
3379 // object as a receiver to normal functions. Values have to be
3380 // passed unchanged to builtins and strict-mode functions.
3381 Label receiver_ok, global_object;
3382 Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear;
3383 Register scratch = ToRegister(instr->temp());
3385 if (!instr->hydrogen()->known_function()) {
3386 // Do not transform the receiver to object for strict mode
3389 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
3390 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kStrictModeByteOffset),
3391 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
3392 __ j(not_equal, &receiver_ok, dist);
3394 // Do not transform the receiver to object for builtins.
3395 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kNativeByteOffset),
3396 1 << SharedFunctionInfo::kNativeBitWithinByte);
3397 __ j(not_equal, &receiver_ok, dist);
3400 // Normal function. Replace undefined or null with global receiver.
3401 __ cmp(receiver, factory()->null_value());
3402 __ j(equal, &global_object, Label::kNear);
3403 __ cmp(receiver, factory()->undefined_value());
3404 __ j(equal, &global_object, Label::kNear);
3406 // The receiver should be a JS object.
3407 __ test(receiver, Immediate(kSmiTagMask));
3408 DeoptimizeIf(equal, instr, "Smi");
3409 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, scratch);
3410 DeoptimizeIf(below, instr, "not a JavaScript object");
3412 __ jmp(&receiver_ok, Label::kNear);
3413 __ bind(&global_object);
3414 __ mov(receiver, FieldOperand(function, JSFunction::kContextOffset));
3415 const int global_offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX);
3416 __ mov(receiver, Operand(receiver, global_offset));
3417 const int proxy_offset = GlobalObject::kGlobalProxyOffset;
3418 __ mov(receiver, FieldOperand(receiver, proxy_offset));
3419 __ bind(&receiver_ok);
3423 void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
3424 Register receiver = ToRegister(instr->receiver());
3425 Register function = ToRegister(instr->function());
3426 Register length = ToRegister(instr->length());
3427 Register elements = ToRegister(instr->elements());
3428 DCHECK(receiver.is(eax)); // Used for parameter count.
3429 DCHECK(function.is(edi)); // Required by InvokeFunction.
3430 DCHECK(ToRegister(instr->result()).is(eax));
3432 // Copy the arguments to this function possibly from the
3433 // adaptor frame below it.
3434 const uint32_t kArgumentsLimit = 1 * KB;
3435 __ cmp(length, kArgumentsLimit);
3436 DeoptimizeIf(above, instr, "too many arguments");
3439 __ mov(receiver, length);
3441 // Loop through the arguments pushing them onto the execution
3444 // length is a small non-negative integer, due to the test above.
3445 __ test(length, Operand(length));
3446 __ j(zero, &invoke, Label::kNear);
3448 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize));
3450 __ j(not_zero, &loop);
3452 // Invoke the function.
3454 DCHECK(instr->HasPointerMap());
3455 LPointerMap* pointers = instr->pointer_map();
3456 SafepointGenerator safepoint_generator(
3457 this, pointers, Safepoint::kLazyDeopt);
3458 ParameterCount actual(eax);
3459 __ InvokeFunction(function, actual, CALL_FUNCTION, safepoint_generator);
3463 void LCodeGen::DoDebugBreak(LDebugBreak* instr) {
3468 void LCodeGen::DoPushArgument(LPushArgument* instr) {
3469 LOperand* argument = instr->value();
3470 EmitPushTaggedOperand(argument);
3474 void LCodeGen::DoDrop(LDrop* instr) {
3475 __ Drop(instr->count());
3479 void LCodeGen::DoThisFunction(LThisFunction* instr) {
3480 Register result = ToRegister(instr->result());
3481 __ mov(result, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
3485 void LCodeGen::DoContext(LContext* instr) {
3486 Register result = ToRegister(instr->result());
3487 if (info()->IsOptimizing()) {
3488 __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
3490 // If there is no frame, the context must be in esi.
3491 DCHECK(result.is(esi));
3496 void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
3497 DCHECK(ToRegister(instr->context()).is(esi));
3498 __ push(esi); // The context is the first argument.
3499 __ push(Immediate(instr->hydrogen()->pairs()));
3500 __ push(Immediate(Smi::FromInt(instr->hydrogen()->flags())));
3501 CallRuntime(Runtime::kDeclareGlobals, 3, instr);
3505 void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
3506 int formal_parameter_count,
3508 LInstruction* instr,
3509 EDIState edi_state) {
3510 bool dont_adapt_arguments =
3511 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel;
3512 bool can_invoke_directly =
3513 dont_adapt_arguments || formal_parameter_count == arity;
3515 if (can_invoke_directly) {
3516 if (edi_state == EDI_UNINITIALIZED) {
3517 __ LoadHeapObject(edi, function);
3521 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
3523 // Set eax to arguments count if adaption is not needed. Assumes that eax
3524 // is available to write to at this point.
3525 if (dont_adapt_arguments) {
3529 // Invoke function directly.
3530 if (function.is_identical_to(info()->closure())) {
3533 __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
3535 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
3537 // We need to adapt arguments.
3538 LPointerMap* pointers = instr->pointer_map();
3539 SafepointGenerator generator(
3540 this, pointers, Safepoint::kLazyDeopt);
3541 ParameterCount count(arity);
3542 ParameterCount expected(formal_parameter_count);
3543 __ InvokeFunction(function, expected, count, CALL_FUNCTION, generator);
3548 void LCodeGen::DoTailCallThroughMegamorphicCache(
3549 LTailCallThroughMegamorphicCache* instr) {
3550 Register receiver = ToRegister(instr->receiver());
3551 Register name = ToRegister(instr->name());
3552 DCHECK(receiver.is(LoadDescriptor::ReceiverRegister()));
3553 DCHECK(name.is(LoadDescriptor::NameRegister()));
3555 Register scratch = ebx;
3556 Register extra = eax;
3557 DCHECK(!scratch.is(receiver) && !scratch.is(name));
3558 DCHECK(!extra.is(receiver) && !extra.is(name));
3560 // Important for the tail-call.
3561 bool must_teardown_frame = NeedsEagerFrame();
3563 // The probe will tail call to a handler if found.
3564 isolate()->stub_cache()->GenerateProbe(masm(), instr->hydrogen()->flags(),
3565 must_teardown_frame, receiver, name,
3568 // Tail call to miss if we ended up here.
3569 if (must_teardown_frame) __ leave();
3570 LoadIC::GenerateMiss(masm());
3574 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
3575 DCHECK(ToRegister(instr->result()).is(eax));
3577 LPointerMap* pointers = instr->pointer_map();
3578 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
3580 if (instr->target()->IsConstantOperand()) {
3581 LConstantOperand* target = LConstantOperand::cast(instr->target());
3582 Handle<Code> code = Handle<Code>::cast(ToHandle(target));
3583 generator.BeforeCall(__ CallSize(code, RelocInfo::CODE_TARGET));
3584 __ call(code, RelocInfo::CODE_TARGET);
3586 DCHECK(instr->target()->IsRegister());
3587 Register target = ToRegister(instr->target());
3588 generator.BeforeCall(__ CallSize(Operand(target)));
3589 __ add(target, Immediate(Code::kHeaderSize - kHeapObjectTag));
3592 generator.AfterCall();
3596 void LCodeGen::DoCallJSFunction(LCallJSFunction* instr) {
3597 DCHECK(ToRegister(instr->function()).is(edi));
3598 DCHECK(ToRegister(instr->result()).is(eax));
3600 if (instr->hydrogen()->pass_argument_count()) {
3601 __ mov(eax, instr->arity());
3605 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
3607 bool is_self_call = false;
3608 if (instr->hydrogen()->function()->IsConstant()) {
3609 HConstant* fun_const = HConstant::cast(instr->hydrogen()->function());
3610 Handle<JSFunction> jsfun =
3611 Handle<JSFunction>::cast(fun_const->handle(isolate()));
3612 is_self_call = jsfun.is_identical_to(info()->closure());
3618 __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
3621 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
3625 void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
3626 Register input_reg = ToRegister(instr->value());
3627 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
3628 factory()->heap_number_map());
3629 DeoptimizeIf(not_equal, instr, "not a heap number");
3631 Label slow, allocated, done;
3632 Register tmp = input_reg.is(eax) ? ecx : eax;
3633 Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx;
3635 // Preserve the value of all registers.
3636 PushSafepointRegistersScope scope(this);
3638 __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
3639 // Check the sign of the argument. If the argument is positive, just
3640 // return it. We do not need to patch the stack since |input| and
3641 // |result| are the same register and |input| will be restored
3642 // unchanged by popping safepoint registers.
3643 __ test(tmp, Immediate(HeapNumber::kSignMask));
3644 __ j(zero, &done, Label::kNear);
3646 __ AllocateHeapNumber(tmp, tmp2, no_reg, &slow);
3647 __ jmp(&allocated, Label::kNear);
3649 // Slow case: Call the runtime system to do the number allocation.
3651 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0,
3652 instr, instr->context());
3653 // Set the pointer to the new heap number in tmp.
3654 if (!tmp.is(eax)) __ mov(tmp, eax);
3655 // Restore input_reg after call to runtime.
3656 __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
3658 __ bind(&allocated);
3659 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset));
3660 __ and_(tmp2, ~HeapNumber::kSignMask);
3661 __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2);
3662 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
3663 __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2);
3664 __ StoreToSafepointRegisterSlot(input_reg, tmp);
3670 void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) {
3671 Register input_reg = ToRegister(instr->value());
3672 __ test(input_reg, Operand(input_reg));
3674 __ j(not_sign, &is_positive, Label::kNear);
3675 __ neg(input_reg); // Sets flags.
3676 DeoptimizeIf(negative, instr, "overflow");
3677 __ bind(&is_positive);
3681 void LCodeGen::DoMathAbs(LMathAbs* instr) {
3682 // Class for deferred case.
3683 class DeferredMathAbsTaggedHeapNumber FINAL : public LDeferredCode {
3685 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
3687 : LDeferredCode(codegen), instr_(instr) { }
3688 virtual void Generate() OVERRIDE {
3689 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
3691 virtual LInstruction* instr() OVERRIDE { return instr_; }
3696 DCHECK(instr->value()->Equals(instr->result()));
3697 Representation r = instr->hydrogen()->value()->representation();
3700 XMMRegister scratch = double_scratch0();
3701 XMMRegister input_reg = ToDoubleRegister(instr->value());
3702 __ xorps(scratch, scratch);
3703 __ subsd(scratch, input_reg);
3704 __ andps(input_reg, scratch);
3705 } else if (r.IsSmiOrInteger32()) {
3706 EmitIntegerMathAbs(instr);
3707 } else { // Tagged case.
3708 DeferredMathAbsTaggedHeapNumber* deferred =
3709 new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr);
3710 Register input_reg = ToRegister(instr->value());
3712 __ JumpIfNotSmi(input_reg, deferred->entry());
3713 EmitIntegerMathAbs(instr);
3714 __ bind(deferred->exit());
3719 void LCodeGen::DoMathFloor(LMathFloor* instr) {
3720 XMMRegister xmm_scratch = double_scratch0();
3721 Register output_reg = ToRegister(instr->result());
3722 XMMRegister input_reg = ToDoubleRegister(instr->value());
3724 if (CpuFeatures::IsSupported(SSE4_1)) {
3725 CpuFeatureScope scope(masm(), SSE4_1);
3726 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3727 // Deoptimize on negative zero.
3729 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3730 __ ucomisd(input_reg, xmm_scratch);
3731 __ j(not_equal, &non_zero, Label::kNear);
3732 __ movmskpd(output_reg, input_reg);
3733 __ test(output_reg, Immediate(1));
3734 DeoptimizeIf(not_zero, instr, "minus zero");
3737 __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
3738 __ cvttsd2si(output_reg, Operand(xmm_scratch));
3739 // Overflow is signalled with minint.
3740 __ cmp(output_reg, 0x1);
3741 DeoptimizeIf(overflow, instr, "overflow");
3743 Label negative_sign, done;
3744 // Deoptimize on unordered.
3745 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3746 __ ucomisd(input_reg, xmm_scratch);
3747 DeoptimizeIf(parity_even, instr, "NaN");
3748 __ j(below, &negative_sign, Label::kNear);
3750 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3751 // Check for negative zero.
3752 Label positive_sign;
3753 __ j(above, &positive_sign, Label::kNear);
3754 __ movmskpd(output_reg, input_reg);
3755 __ test(output_reg, Immediate(1));
3756 DeoptimizeIf(not_zero, instr, "minus zero");
3757 __ Move(output_reg, Immediate(0));
3758 __ jmp(&done, Label::kNear);
3759 __ bind(&positive_sign);
3762 // Use truncating instruction (OK because input is positive).
3763 __ cvttsd2si(output_reg, Operand(input_reg));
3764 // Overflow is signalled with minint.
3765 __ cmp(output_reg, 0x1);
3766 DeoptimizeIf(overflow, instr, "overflow");
3767 __ jmp(&done, Label::kNear);
3769 // Non-zero negative reaches here.
3770 __ bind(&negative_sign);
3771 // Truncate, then compare and compensate.
3772 __ cvttsd2si(output_reg, Operand(input_reg));
3773 __ Cvtsi2sd(xmm_scratch, output_reg);
3774 __ ucomisd(input_reg, xmm_scratch);
3775 __ j(equal, &done, Label::kNear);
3776 __ sub(output_reg, Immediate(1));
3777 DeoptimizeIf(overflow, instr, "overflow");
3784 void LCodeGen::DoMathRound(LMathRound* instr) {
3785 Register output_reg = ToRegister(instr->result());
3786 XMMRegister input_reg = ToDoubleRegister(instr->value());
3787 XMMRegister xmm_scratch = double_scratch0();
3788 XMMRegister input_temp = ToDoubleRegister(instr->temp());
3789 ExternalReference one_half = ExternalReference::address_of_one_half();
3790 ExternalReference minus_one_half =
3791 ExternalReference::address_of_minus_one_half();
3793 Label done, round_to_zero, below_one_half, do_not_compensate;
3794 Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear;
3796 __ movsd(xmm_scratch, Operand::StaticVariable(one_half));
3797 __ ucomisd(xmm_scratch, input_reg);
3798 __ j(above, &below_one_half, Label::kNear);
3800 // CVTTSD2SI rounds towards zero, since 0.5 <= x, we use floor(0.5 + x).
3801 __ addsd(xmm_scratch, input_reg);
3802 __ cvttsd2si(output_reg, Operand(xmm_scratch));
3803 // Overflow is signalled with minint.
3804 __ cmp(output_reg, 0x1);
3805 DeoptimizeIf(overflow, instr, "overflow");
3806 __ jmp(&done, dist);
3808 __ bind(&below_one_half);
3809 __ movsd(xmm_scratch, Operand::StaticVariable(minus_one_half));
3810 __ ucomisd(xmm_scratch, input_reg);
3811 __ j(below_equal, &round_to_zero, Label::kNear);
3813 // CVTTSD2SI rounds towards zero, we use ceil(x - (-0.5)) and then
3814 // compare and compensate.
3815 __ movaps(input_temp, input_reg); // Do not alter input_reg.
3816 __ subsd(input_temp, xmm_scratch);
3817 __ cvttsd2si(output_reg, Operand(input_temp));
3818 // Catch minint due to overflow, and to prevent overflow when compensating.
3819 __ cmp(output_reg, 0x1);
3820 DeoptimizeIf(overflow, instr, "overflow");
3822 __ Cvtsi2sd(xmm_scratch, output_reg);
3823 __ ucomisd(xmm_scratch, input_temp);
3824 __ j(equal, &done, dist);
3825 __ sub(output_reg, Immediate(1));
3826 // No overflow because we already ruled out minint.
3827 __ jmp(&done, dist);
3829 __ bind(&round_to_zero);
3830 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
3831 // we can ignore the difference between a result of -0 and +0.
3832 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3833 // If the sign is positive, we return +0.
3834 __ movmskpd(output_reg, input_reg);
3835 __ test(output_reg, Immediate(1));
3836 DeoptimizeIf(not_zero, instr, "minus zero");
3838 __ Move(output_reg, Immediate(0));
3843 void LCodeGen::DoMathFround(LMathFround* instr) {
3844 XMMRegister input_reg = ToDoubleRegister(instr->value());
3845 XMMRegister output_reg = ToDoubleRegister(instr->result());
3846 __ cvtsd2ss(output_reg, input_reg);
3847 __ cvtss2sd(output_reg, output_reg);
3851 void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
3852 Operand input = ToOperand(instr->value());
3853 XMMRegister output = ToDoubleRegister(instr->result());
3854 __ sqrtsd(output, input);
3858 void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
3859 XMMRegister xmm_scratch = double_scratch0();
3860 XMMRegister input_reg = ToDoubleRegister(instr->value());
3861 Register scratch = ToRegister(instr->temp());
3862 DCHECK(ToDoubleRegister(instr->result()).is(input_reg));
3864 // Note that according to ECMA-262 15.8.2.13:
3865 // Math.pow(-Infinity, 0.5) == Infinity
3866 // Math.sqrt(-Infinity) == NaN
3868 // Check base for -Infinity. According to IEEE-754, single-precision
3869 // -Infinity has the highest 9 bits set and the lowest 23 bits cleared.
3870 __ mov(scratch, 0xFF800000);
3871 __ movd(xmm_scratch, scratch);
3872 __ cvtss2sd(xmm_scratch, xmm_scratch);
3873 __ ucomisd(input_reg, xmm_scratch);
3874 // Comparing -Infinity with NaN results in "unordered", which sets the
3875 // zero flag as if both were equal. However, it also sets the carry flag.
3876 __ j(not_equal, &sqrt, Label::kNear);
3877 __ j(carry, &sqrt, Label::kNear);
3878 // If input is -Infinity, return Infinity.
3879 __ xorps(input_reg, input_reg);
3880 __ subsd(input_reg, xmm_scratch);
3881 __ jmp(&done, Label::kNear);
3885 __ xorps(xmm_scratch, xmm_scratch);
3886 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
3887 __ sqrtsd(input_reg, input_reg);
3892 void LCodeGen::DoPower(LPower* instr) {
3893 Representation exponent_type = instr->hydrogen()->right()->representation();
3894 // Having marked this as a call, we can use any registers.
3895 // Just make sure that the input/output registers are the expected ones.
3896 Register tagged_exponent = MathPowTaggedDescriptor::exponent();
3897 DCHECK(!instr->right()->IsDoubleRegister() ||
3898 ToDoubleRegister(instr->right()).is(xmm1));
3899 DCHECK(!instr->right()->IsRegister() ||
3900 ToRegister(instr->right()).is(tagged_exponent));
3901 DCHECK(ToDoubleRegister(instr->left()).is(xmm2));
3902 DCHECK(ToDoubleRegister(instr->result()).is(xmm3));
3904 if (exponent_type.IsSmi()) {
3905 MathPowStub stub(isolate(), MathPowStub::TAGGED);
3907 } else if (exponent_type.IsTagged()) {
3909 __ JumpIfSmi(tagged_exponent, &no_deopt);
3910 DCHECK(!ecx.is(tagged_exponent));
3911 __ CmpObjectType(tagged_exponent, HEAP_NUMBER_TYPE, ecx);
3912 DeoptimizeIf(not_equal, instr, "not a heap number");
3914 MathPowStub stub(isolate(), MathPowStub::TAGGED);
3916 } else if (exponent_type.IsInteger32()) {
3917 MathPowStub stub(isolate(), MathPowStub::INTEGER);
3920 DCHECK(exponent_type.IsDouble());
3921 MathPowStub stub(isolate(), MathPowStub::DOUBLE);
3927 void LCodeGen::DoMathLog(LMathLog* instr) {
3928 DCHECK(instr->value()->Equals(instr->result()));
3929 XMMRegister input_reg = ToDoubleRegister(instr->value());
3930 XMMRegister xmm_scratch = double_scratch0();
3931 Label positive, done, zero;
3932 __ xorps(xmm_scratch, xmm_scratch);
3933 __ ucomisd(input_reg, xmm_scratch);
3934 __ j(above, &positive, Label::kNear);
3935 __ j(not_carry, &zero, Label::kNear);
3936 ExternalReference nan =
3937 ExternalReference::address_of_canonical_non_hole_nan();
3938 __ movsd(input_reg, Operand::StaticVariable(nan));
3939 __ jmp(&done, Label::kNear);
3941 ExternalReference ninf =
3942 ExternalReference::address_of_negative_infinity();
3943 __ movsd(input_reg, Operand::StaticVariable(ninf));
3944 __ jmp(&done, Label::kNear);
3947 __ sub(Operand(esp), Immediate(kDoubleSize));
3948 __ movsd(Operand(esp, 0), input_reg);
3949 __ fld_d(Operand(esp, 0));
3951 __ fstp_d(Operand(esp, 0));
3952 __ movsd(input_reg, Operand(esp, 0));
3953 __ add(Operand(esp), Immediate(kDoubleSize));
3958 void LCodeGen::DoMathClz32(LMathClz32* instr) {
3959 Register input = ToRegister(instr->value());
3960 Register result = ToRegister(instr->result());
3961 Label not_zero_input;
3962 __ bsr(result, input);
3964 __ j(not_zero, ¬_zero_input);
3965 __ Move(result, Immediate(63)); // 63^31 == 32
3967 __ bind(¬_zero_input);
3968 __ xor_(result, Immediate(31)); // for x in [0..31], 31^x == 31-x.
3972 void LCodeGen::DoMathExp(LMathExp* instr) {
3973 XMMRegister input = ToDoubleRegister(instr->value());
3974 XMMRegister result = ToDoubleRegister(instr->result());
3975 XMMRegister temp0 = double_scratch0();
3976 Register temp1 = ToRegister(instr->temp1());
3977 Register temp2 = ToRegister(instr->temp2());
3979 MathExpGenerator::EmitMathExp(masm(), input, result, temp0, temp1, temp2);
3983 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
3984 DCHECK(ToRegister(instr->context()).is(esi));
3985 DCHECK(ToRegister(instr->function()).is(edi));
3986 DCHECK(instr->HasPointerMap());
3988 Handle<JSFunction> known_function = instr->hydrogen()->known_function();
3989 if (known_function.is_null()) {
3990 LPointerMap* pointers = instr->pointer_map();
3991 SafepointGenerator generator(
3992 this, pointers, Safepoint::kLazyDeopt);
3993 ParameterCount count(instr->arity());
3994 __ InvokeFunction(edi, count, CALL_FUNCTION, generator);
3996 CallKnownFunction(known_function,
3997 instr->hydrogen()->formal_parameter_count(),
4000 EDI_CONTAINS_TARGET);
4005 void LCodeGen::DoCallFunction(LCallFunction* instr) {
4006 DCHECK(ToRegister(instr->context()).is(esi));
4007 DCHECK(ToRegister(instr->function()).is(edi));
4008 DCHECK(ToRegister(instr->result()).is(eax));
4010 int arity = instr->arity();
4011 CallFunctionStub stub(isolate(), arity, instr->hydrogen()->function_flags());
4012 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
4016 void LCodeGen::DoCallNew(LCallNew* instr) {
4017 DCHECK(ToRegister(instr->context()).is(esi));
4018 DCHECK(ToRegister(instr->constructor()).is(edi));
4019 DCHECK(ToRegister(instr->result()).is(eax));
4021 // No cell in ebx for construct type feedback in optimized code
4022 __ mov(ebx, isolate()->factory()->undefined_value());
4023 CallConstructStub stub(isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
4024 __ Move(eax, Immediate(instr->arity()));
4025 CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
4029 void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
4030 DCHECK(ToRegister(instr->context()).is(esi));
4031 DCHECK(ToRegister(instr->constructor()).is(edi));
4032 DCHECK(ToRegister(instr->result()).is(eax));
4034 __ Move(eax, Immediate(instr->arity()));
4035 __ mov(ebx, isolate()->factory()->undefined_value());
4036 ElementsKind kind = instr->hydrogen()->elements_kind();
4037 AllocationSiteOverrideMode override_mode =
4038 (AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE)
4039 ? DISABLE_ALLOCATION_SITES
4042 if (instr->arity() == 0) {
4043 ArrayNoArgumentConstructorStub stub(isolate(), kind, override_mode);
4044 CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
4045 } else if (instr->arity() == 1) {
4047 if (IsFastPackedElementsKind(kind)) {
4049 // We might need a change here
4050 // look at the first argument
4051 __ mov(ecx, Operand(esp, 0));
4053 __ j(zero, &packed_case, Label::kNear);
4055 ElementsKind holey_kind = GetHoleyElementsKind(kind);
4056 ArraySingleArgumentConstructorStub stub(isolate(),
4059 CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
4060 __ jmp(&done, Label::kNear);
4061 __ bind(&packed_case);
4064 ArraySingleArgumentConstructorStub stub(isolate(), kind, override_mode);
4065 CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
4068 ArrayNArgumentsConstructorStub stub(isolate(), kind, override_mode);
4069 CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
4074 void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
4075 DCHECK(ToRegister(instr->context()).is(esi));
4076 CallRuntime(instr->function(), instr->arity(), instr, instr->save_doubles());
4080 void LCodeGen::DoStoreCodeEntry(LStoreCodeEntry* instr) {
4081 Register function = ToRegister(instr->function());
4082 Register code_object = ToRegister(instr->code_object());
4083 __ lea(code_object, FieldOperand(code_object, Code::kHeaderSize));
4084 __ mov(FieldOperand(function, JSFunction::kCodeEntryOffset), code_object);
4088 void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) {
4089 Register result = ToRegister(instr->result());
4090 Register base = ToRegister(instr->base_object());
4091 if (instr->offset()->IsConstantOperand()) {
4092 LConstantOperand* offset = LConstantOperand::cast(instr->offset());
4093 __ lea(result, Operand(base, ToInteger32(offset)));
4095 Register offset = ToRegister(instr->offset());
4096 __ lea(result, Operand(base, offset, times_1, 0));
4101 void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
4102 Representation representation = instr->hydrogen()->field_representation();
4104 HObjectAccess access = instr->hydrogen()->access();
4105 int offset = access.offset();
4107 if (access.IsExternalMemory()) {
4108 DCHECK(!instr->hydrogen()->NeedsWriteBarrier());
4109 MemOperand operand = instr->object()->IsConstantOperand()
4110 ? MemOperand::StaticVariable(
4111 ToExternalReference(LConstantOperand::cast(instr->object())))
4112 : MemOperand(ToRegister(instr->object()), offset);
4113 if (instr->value()->IsConstantOperand()) {
4114 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
4115 __ mov(operand, Immediate(ToInteger32(operand_value)));
4117 Register value = ToRegister(instr->value());
4118 __ Store(value, operand, representation);
4123 Register object = ToRegister(instr->object());
4124 __ AssertNotSmi(object);
4126 DCHECK(!representation.IsSmi() ||
4127 !instr->value()->IsConstantOperand() ||
4128 IsSmi(LConstantOperand::cast(instr->value())));
4129 if (representation.IsDouble()) {
4130 DCHECK(access.IsInobject());
4131 DCHECK(!instr->hydrogen()->has_transition());
4132 DCHECK(!instr->hydrogen()->NeedsWriteBarrier());
4133 XMMRegister value = ToDoubleRegister(instr->value());
4134 __ movsd(FieldOperand(object, offset), value);
4138 if (instr->hydrogen()->has_transition()) {
4139 Handle<Map> transition = instr->hydrogen()->transition_map();
4140 AddDeprecationDependency(transition);
4141 __ mov(FieldOperand(object, HeapObject::kMapOffset), transition);
4142 if (instr->hydrogen()->NeedsWriteBarrierForMap()) {
4143 Register temp = ToRegister(instr->temp());
4144 Register temp_map = ToRegister(instr->temp_map());
4145 // Update the write barrier for the map field.
4146 __ RecordWriteForMap(object, transition, temp_map, temp, kSaveFPRegs);
4151 Register write_register = object;
4152 if (!access.IsInobject()) {
4153 write_register = ToRegister(instr->temp());
4154 __ mov(write_register, FieldOperand(object, JSObject::kPropertiesOffset));
4157 MemOperand operand = FieldOperand(write_register, offset);
4158 if (instr->value()->IsConstantOperand()) {
4159 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
4160 if (operand_value->IsRegister()) {
4161 Register value = ToRegister(operand_value);
4162 __ Store(value, operand, representation);
4163 } else if (representation.IsInteger32()) {
4164 Immediate immediate = ToImmediate(operand_value, representation);
4165 DCHECK(!instr->hydrogen()->NeedsWriteBarrier());
4166 __ mov(operand, immediate);
4168 Handle<Object> handle_value = ToHandle(operand_value);
4169 DCHECK(!instr->hydrogen()->NeedsWriteBarrier());
4170 __ mov(operand, handle_value);
4173 Register value = ToRegister(instr->value());
4174 __ Store(value, operand, representation);
4177 if (instr->hydrogen()->NeedsWriteBarrier()) {
4178 Register value = ToRegister(instr->value());
4179 Register temp = access.IsInobject() ? ToRegister(instr->temp()) : object;
4180 // Update the write barrier for the object for in-object properties.
4181 __ RecordWriteField(write_register,
4186 EMIT_REMEMBERED_SET,
4187 instr->hydrogen()->SmiCheckForWriteBarrier(),
4188 instr->hydrogen()->PointersToHereCheckForValue());
4193 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
4194 DCHECK(ToRegister(instr->context()).is(esi));
4195 DCHECK(ToRegister(instr->object()).is(StoreDescriptor::ReceiverRegister()));
4196 DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
4198 __ mov(StoreDescriptor::NameRegister(), instr->name());
4199 Handle<Code> ic = StoreIC::initialize_stub(isolate(), instr->strict_mode());
4200 CallCode(ic, RelocInfo::CODE_TARGET, instr);
4204 void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
4205 Condition cc = instr->hydrogen()->allow_equality() ? above : above_equal;
4206 if (instr->index()->IsConstantOperand()) {
4207 __ cmp(ToOperand(instr->length()),
4208 ToImmediate(LConstantOperand::cast(instr->index()),
4209 instr->hydrogen()->length()->representation()));
4210 cc = CommuteCondition(cc);
4211 } else if (instr->length()->IsConstantOperand()) {
4212 __ cmp(ToOperand(instr->index()),
4213 ToImmediate(LConstantOperand::cast(instr->length()),
4214 instr->hydrogen()->index()->representation()));
4216 __ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
4218 if (FLAG_debug_code && instr->hydrogen()->skip_check()) {
4220 __ j(NegateCondition(cc), &done, Label::kNear);
4224 DeoptimizeIf(cc, instr, "out of bounds");
4229 void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
4230 ElementsKind elements_kind = instr->elements_kind();
4231 LOperand* key = instr->key();
4232 if (!key->IsConstantOperand() &&
4233 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
4235 HandleExternalArrayOpRequiresTemp(
4236 key, instr->hydrogen()->key()->representation(), elements_kind);
4239 Operand operand(BuildFastArrayOperand(
4242 instr->hydrogen()->key()->representation(),
4244 instr->base_offset()));
4245 if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
4246 elements_kind == FLOAT32_ELEMENTS) {
4247 XMMRegister xmm_scratch = double_scratch0();
4248 __ cvtsd2ss(xmm_scratch, ToDoubleRegister(instr->value()));
4249 __ movss(operand, xmm_scratch);
4250 } else if (elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
4251 elements_kind == FLOAT64_ELEMENTS) {
4252 __ movsd(operand, ToDoubleRegister(instr->value()));
4253 } else if (IsSIMD128ElementsKind(elements_kind)) {
4254 __ movups(operand, ToSIMD128Register(instr->value()));
4256 Register value = ToRegister(instr->value());
4257 switch (elements_kind) {
4258 case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
4259 case EXTERNAL_UINT8_ELEMENTS:
4260 case EXTERNAL_INT8_ELEMENTS:
4261 case UINT8_ELEMENTS:
4263 case UINT8_CLAMPED_ELEMENTS:
4264 __ mov_b(operand, value);
4266 case EXTERNAL_INT16_ELEMENTS:
4267 case EXTERNAL_UINT16_ELEMENTS:
4268 case UINT16_ELEMENTS:
4269 case INT16_ELEMENTS:
4270 __ mov_w(operand, value);
4272 case EXTERNAL_INT32_ELEMENTS:
4273 case EXTERNAL_UINT32_ELEMENTS:
4274 case UINT32_ELEMENTS:
4275 case INT32_ELEMENTS:
4276 __ mov(operand, value);
4278 case EXTERNAL_FLOAT32_ELEMENTS:
4279 case EXTERNAL_FLOAT64_ELEMENTS:
4280 case EXTERNAL_FLOAT32x4_ELEMENTS:
4281 case EXTERNAL_FLOAT64x2_ELEMENTS:
4282 case EXTERNAL_INT32x4_ELEMENTS:
4283 case FLOAT32_ELEMENTS:
4284 case FLOAT64_ELEMENTS:
4285 case FLOAT32x4_ELEMENTS:
4286 case FLOAT64x2_ELEMENTS:
4287 case INT32x4_ELEMENTS:
4288 case FAST_SMI_ELEMENTS:
4290 case FAST_DOUBLE_ELEMENTS:
4291 case FAST_HOLEY_SMI_ELEMENTS:
4292 case FAST_HOLEY_ELEMENTS:
4293 case FAST_HOLEY_DOUBLE_ELEMENTS:
4294 case DICTIONARY_ELEMENTS:
4295 case SLOPPY_ARGUMENTS_ELEMENTS:
4303 void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
4304 ExternalReference canonical_nan_reference =
4305 ExternalReference::address_of_canonical_non_hole_nan();
4306 Operand double_store_operand = BuildFastArrayOperand(
4309 instr->hydrogen()->key()->representation(),
4310 FAST_DOUBLE_ELEMENTS,
4311 instr->base_offset());
4313 XMMRegister value = ToDoubleRegister(instr->value());
4315 if (instr->NeedsCanonicalization()) {
4318 __ ucomisd(value, value);
4319 __ j(parity_odd, &have_value, Label::kNear); // NaN.
4321 __ movsd(value, Operand::StaticVariable(canonical_nan_reference));
4322 __ bind(&have_value);
4325 __ movsd(double_store_operand, value);
4329 void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
4330 Register elements = ToRegister(instr->elements());
4331 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
4333 Operand operand = BuildFastArrayOperand(
4336 instr->hydrogen()->key()->representation(),
4338 instr->base_offset());
4339 if (instr->value()->IsRegister()) {
4340 __ mov(operand, ToRegister(instr->value()));
4342 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
4343 if (IsSmi(operand_value)) {
4344 Immediate immediate = ToImmediate(operand_value, Representation::Smi());
4345 __ mov(operand, immediate);
4347 DCHECK(!IsInteger32(operand_value));
4348 Handle<Object> handle_value = ToHandle(operand_value);
4349 __ mov(operand, handle_value);
4353 if (instr->hydrogen()->NeedsWriteBarrier()) {
4354 DCHECK(instr->value()->IsRegister());
4355 Register value = ToRegister(instr->value());
4356 DCHECK(!instr->key()->IsConstantOperand());
4357 SmiCheck check_needed =
4358 instr->hydrogen()->value()->type().IsHeapObject()
4359 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
4360 // Compute address of modified element and store it into key register.
4361 __ lea(key, operand);
4362 __ RecordWrite(elements,
4366 EMIT_REMEMBERED_SET,
4368 instr->hydrogen()->PointersToHereCheckForValue());
4373 void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
4374 // By cases...external, fast-double, fast
4375 if (instr->is_typed_elements()) {
4376 DoStoreKeyedExternalArray(instr);
4377 } else if (instr->hydrogen()->value()->representation().IsDouble()) {
4378 DoStoreKeyedFixedDoubleArray(instr);
4380 DoStoreKeyedFixedArray(instr);
4385 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
4386 DCHECK(ToRegister(instr->context()).is(esi));
4387 DCHECK(ToRegister(instr->object()).is(StoreDescriptor::ReceiverRegister()));
4388 DCHECK(ToRegister(instr->key()).is(StoreDescriptor::NameRegister()));
4389 DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
4392 CodeFactory::KeyedStoreIC(isolate(), instr->strict_mode()).code();
4393 CallCode(ic, RelocInfo::CODE_TARGET, instr);
4397 void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) {
4398 Register object = ToRegister(instr->object());
4399 Register temp = ToRegister(instr->temp());
4400 Label no_memento_found;
4401 __ TestJSArrayForAllocationMemento(object, temp, &no_memento_found);
4402 DeoptimizeIf(equal, instr, "memento found");
4403 __ bind(&no_memento_found);
4407 void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
4408 Register object_reg = ToRegister(instr->object());
4410 Handle<Map> from_map = instr->original_map();
4411 Handle<Map> to_map = instr->transitioned_map();
4412 ElementsKind from_kind = instr->from_kind();
4413 ElementsKind to_kind = instr->to_kind();
4415 Label not_applicable;
4416 bool is_simple_map_transition =
4417 IsSimpleMapChangeTransition(from_kind, to_kind);
4418 Label::Distance branch_distance =
4419 is_simple_map_transition ? Label::kNear : Label::kFar;
4420 __ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
4421 __ j(not_equal, ¬_applicable, branch_distance);
4422 if (is_simple_map_transition) {
4423 Register new_map_reg = ToRegister(instr->new_map_temp());
4424 __ mov(FieldOperand(object_reg, HeapObject::kMapOffset),
4427 DCHECK_NE(instr->temp(), NULL);
4428 __ RecordWriteForMap(object_reg, to_map, new_map_reg,
4429 ToRegister(instr->temp()),
4432 DCHECK(ToRegister(instr->context()).is(esi));
4433 DCHECK(object_reg.is(eax));
4434 PushSafepointRegistersScope scope(this);
4435 __ mov(ebx, to_map);
4436 bool is_js_array = from_map->instance_type() == JS_ARRAY_TYPE;
4437 TransitionElementsKindStub stub(isolate(), from_kind, to_kind, is_js_array);
4439 RecordSafepointWithLazyDeopt(instr,
4440 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
4442 __ bind(¬_applicable);
4446 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
4447 class DeferredStringCharCodeAt FINAL : public LDeferredCode {
4449 DeferredStringCharCodeAt(LCodeGen* codegen,
4450 LStringCharCodeAt* instr)
4451 : LDeferredCode(codegen), instr_(instr) { }
4452 virtual void Generate() OVERRIDE {
4453 codegen()->DoDeferredStringCharCodeAt(instr_);
4455 virtual LInstruction* instr() OVERRIDE { return instr_; }
4457 LStringCharCodeAt* instr_;
4460 DeferredStringCharCodeAt* deferred =
4461 new(zone()) DeferredStringCharCodeAt(this, instr);
4463 StringCharLoadGenerator::Generate(masm(),
4465 ToRegister(instr->string()),
4466 ToRegister(instr->index()),
4467 ToRegister(instr->result()),
4469 __ bind(deferred->exit());
4473 void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
4474 Register string = ToRegister(instr->string());
4475 Register result = ToRegister(instr->result());
4477 // TODO(3095996): Get rid of this. For now, we need to make the
4478 // result register contain a valid pointer because it is already
4479 // contained in the register pointer map.
4480 __ Move(result, Immediate(0));
4482 PushSafepointRegistersScope scope(this);
4484 // Push the index as a smi. This is safe because of the checks in
4485 // DoStringCharCodeAt above.
4486 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
4487 if (instr->index()->IsConstantOperand()) {
4488 Immediate immediate = ToImmediate(LConstantOperand::cast(instr->index()),
4489 Representation::Smi());
4492 Register index = ToRegister(instr->index());
4496 CallRuntimeFromDeferred(Runtime::kStringCharCodeAtRT, 2,
4497 instr, instr->context());
4500 __ StoreToSafepointRegisterSlot(result, eax);
4504 void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
4505 class DeferredStringCharFromCode FINAL : public LDeferredCode {
4507 DeferredStringCharFromCode(LCodeGen* codegen,
4508 LStringCharFromCode* instr)
4509 : LDeferredCode(codegen), instr_(instr) { }
4510 virtual void Generate() OVERRIDE {
4511 codegen()->DoDeferredStringCharFromCode(instr_);
4513 virtual LInstruction* instr() OVERRIDE { return instr_; }
4515 LStringCharFromCode* instr_;
4518 DeferredStringCharFromCode* deferred =
4519 new(zone()) DeferredStringCharFromCode(this, instr);
4521 DCHECK(instr->hydrogen()->value()->representation().IsInteger32());
4522 Register char_code = ToRegister(instr->char_code());
4523 Register result = ToRegister(instr->result());
4524 DCHECK(!char_code.is(result));
4526 __ cmp(char_code, String::kMaxOneByteCharCode);
4527 __ j(above, deferred->entry());
4528 __ Move(result, Immediate(factory()->single_character_string_cache()));
4529 __ mov(result, FieldOperand(result,
4530 char_code, times_pointer_size,
4531 FixedArray::kHeaderSize));
4532 __ cmp(result, factory()->undefined_value());
4533 __ j(equal, deferred->entry());
4534 __ bind(deferred->exit());
4538 void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
4539 Register char_code = ToRegister(instr->char_code());
4540 Register result = ToRegister(instr->result());
4542 // TODO(3095996): Get rid of this. For now, we need to make the
4543 // result register contain a valid pointer because it is already
4544 // contained in the register pointer map.
4545 __ Move(result, Immediate(0));
4547 PushSafepointRegistersScope scope(this);
4548 __ SmiTag(char_code);
4550 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context());
4551 __ StoreToSafepointRegisterSlot(result, eax);
4555 void LCodeGen::DoStringAdd(LStringAdd* instr) {
4556 DCHECK(ToRegister(instr->context()).is(esi));
4557 DCHECK(ToRegister(instr->left()).is(edx));
4558 DCHECK(ToRegister(instr->right()).is(eax));
4559 StringAddStub stub(isolate(),
4560 instr->hydrogen()->flags(),
4561 instr->hydrogen()->pretenure_flag());
4562 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
4566 void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
4567 LOperand* input = instr->value();
4568 LOperand* output = instr->result();
4569 DCHECK(input->IsRegister() || input->IsStackSlot());
4570 DCHECK(output->IsDoubleRegister());
4571 __ Cvtsi2sd(ToDoubleRegister(output), ToOperand(input));
4575 void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
4576 LOperand* input = instr->value();
4577 LOperand* output = instr->result();
4578 __ LoadUint32(ToDoubleRegister(output), ToRegister(input));
4582 void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
4583 class DeferredNumberTagI FINAL : public LDeferredCode {
4585 DeferredNumberTagI(LCodeGen* codegen,
4587 : LDeferredCode(codegen), instr_(instr) { }
4588 virtual void Generate() OVERRIDE {
4589 codegen()->DoDeferredNumberTagIU(
4590 instr_, instr_->value(), instr_->temp(), SIGNED_INT32);
4592 virtual LInstruction* instr() OVERRIDE { return instr_; }
4594 LNumberTagI* instr_;
4597 LOperand* input = instr->value();
4598 DCHECK(input->IsRegister() && input->Equals(instr->result()));
4599 Register reg = ToRegister(input);
4601 DeferredNumberTagI* deferred =
4602 new(zone()) DeferredNumberTagI(this, instr);
4604 __ j(overflow, deferred->entry());
4605 __ bind(deferred->exit());
4609 void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
4610 class DeferredNumberTagU FINAL : public LDeferredCode {
4612 DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
4613 : LDeferredCode(codegen), instr_(instr) { }
4614 virtual void Generate() OVERRIDE {
4615 codegen()->DoDeferredNumberTagIU(
4616 instr_, instr_->value(), instr_->temp(), UNSIGNED_INT32);
4618 virtual LInstruction* instr() OVERRIDE { return instr_; }
4620 LNumberTagU* instr_;
4623 LOperand* input = instr->value();
4624 DCHECK(input->IsRegister() && input->Equals(instr->result()));
4625 Register reg = ToRegister(input);
4627 DeferredNumberTagU* deferred =
4628 new(zone()) DeferredNumberTagU(this, instr);
4629 __ cmp(reg, Immediate(Smi::kMaxValue));
4630 __ j(above, deferred->entry());
4632 __ bind(deferred->exit());
4636 void LCodeGen::DoDeferredNumberTagIU(LInstruction* instr,
4639 IntegerSignedness signedness) {
4641 Register reg = ToRegister(value);
4642 Register tmp = ToRegister(temp);
4643 XMMRegister xmm_scratch = double_scratch0();
4645 if (signedness == SIGNED_INT32) {
4646 // There was overflow, so bits 30 and 31 of the original integer
4647 // disagree. Try to allocate a heap number in new space and store
4648 // the value in there. If that fails, call the runtime system.
4650 __ xor_(reg, 0x80000000);
4651 __ Cvtsi2sd(xmm_scratch, Operand(reg));
4653 __ LoadUint32(xmm_scratch, reg);
4656 if (FLAG_inline_new) {
4657 __ AllocateHeapNumber(reg, tmp, no_reg, &slow);
4658 __ jmp(&done, Label::kNear);
4661 // Slow case: Call the runtime system to do the number allocation.
4664 // TODO(3095996): Put a valid pointer value in the stack slot where the
4665 // result register is stored, as this register is in the pointer map, but
4666 // contains an integer value.
4667 __ Move(reg, Immediate(0));
4669 // Preserve the value of all registers.
4670 PushSafepointRegistersScope scope(this);
4672 // NumberTagI and NumberTagD use the context from the frame, rather than
4673 // the environment's HContext or HInlinedContext value.
4674 // They only call Runtime::kAllocateHeapNumber.
4675 // The corresponding HChange instructions are added in a phase that does
4676 // not have easy access to the local context.
4677 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4678 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
4679 RecordSafepointWithRegisters(
4680 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
4681 __ StoreToSafepointRegisterSlot(reg, eax);
4684 // Done. Put the value in xmm_scratch into the value of the allocated heap
4687 __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), xmm_scratch);
4691 void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
4692 class DeferredNumberTagD FINAL : public LDeferredCode {
4694 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
4695 : LDeferredCode(codegen), instr_(instr) { }
4696 virtual void Generate() OVERRIDE {
4697 codegen()->DoDeferredNumberTagD(instr_);
4699 virtual LInstruction* instr() OVERRIDE { return instr_; }
4701 LNumberTagD* instr_;
4704 Register reg = ToRegister(instr->result());
4706 DeferredNumberTagD* deferred =
4707 new(zone()) DeferredNumberTagD(this, instr);
4708 if (FLAG_inline_new) {
4709 Register tmp = ToRegister(instr->temp());
4710 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry());
4712 __ jmp(deferred->entry());
4714 __ bind(deferred->exit());
4715 XMMRegister input_reg = ToDoubleRegister(instr->value());
4716 __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
4720 void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
4721 // TODO(3095996): Get rid of this. For now, we need to make the
4722 // result register contain a valid pointer because it is already
4723 // contained in the register pointer map.
4724 Register reg = ToRegister(instr->result());
4725 __ Move(reg, Immediate(0));
4727 PushSafepointRegistersScope scope(this);
4728 // NumberTagI and NumberTagD use the context from the frame, rather than
4729 // the environment's HContext or HInlinedContext value.
4730 // They only call Runtime::kAllocateHeapNumber.
4731 // The corresponding HChange instructions are added in a phase that does
4732 // not have easy access to the local context.
4733 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4734 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
4735 RecordSafepointWithRegisters(
4736 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
4737 __ StoreToSafepointRegisterSlot(reg, eax);
4741 void LCodeGen::DoSmiTag(LSmiTag* instr) {
4742 HChange* hchange = instr->hydrogen();
4743 Register input = ToRegister(instr->value());
4744 if (hchange->CheckFlag(HValue::kCanOverflow) &&
4745 hchange->value()->CheckFlag(HValue::kUint32)) {
4746 __ test(input, Immediate(0xc0000000));
4747 DeoptimizeIf(not_zero, instr, "overflow");
4750 if (hchange->CheckFlag(HValue::kCanOverflow) &&
4751 !hchange->value()->CheckFlag(HValue::kUint32)) {
4752 DeoptimizeIf(overflow, instr, "overflow");
4757 void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
4758 LOperand* input = instr->value();
4759 Register result = ToRegister(input);
4760 DCHECK(input->IsRegister() && input->Equals(instr->result()));
4761 if (instr->needs_check()) {
4762 __ test(result, Immediate(kSmiTagMask));
4763 DeoptimizeIf(not_zero, instr, "not a Smi");
4765 __ AssertSmi(result);
4767 __ SmiUntag(result);
4771 void LCodeGen::EmitNumberUntagD(LNumberUntagD* instr, Register input_reg,
4772 Register temp_reg, XMMRegister result_reg,
4773 NumberUntagDMode mode) {
4774 bool can_convert_undefined_to_nan =
4775 instr->hydrogen()->can_convert_undefined_to_nan();
4776 bool deoptimize_on_minus_zero = instr->hydrogen()->deoptimize_on_minus_zero();
4778 Label convert, load_smi, done;
4780 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) {
4782 __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
4784 // Heap number map check.
4785 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
4786 factory()->heap_number_map());
4787 if (can_convert_undefined_to_nan) {
4788 __ j(not_equal, &convert, Label::kNear);
4790 DeoptimizeIf(not_equal, instr, "not a heap number");
4793 // Heap number to XMM conversion.
4794 __ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
4796 if (deoptimize_on_minus_zero) {
4797 XMMRegister xmm_scratch = double_scratch0();
4798 __ xorps(xmm_scratch, xmm_scratch);
4799 __ ucomisd(result_reg, xmm_scratch);
4800 __ j(not_zero, &done, Label::kNear);
4801 __ movmskpd(temp_reg, result_reg);
4802 __ test_b(temp_reg, 1);
4803 DeoptimizeIf(not_zero, instr, "minus zero");
4805 __ jmp(&done, Label::kNear);
4807 if (can_convert_undefined_to_nan) {
4810 // Convert undefined (and hole) to NaN.
4811 __ cmp(input_reg, factory()->undefined_value());
4812 DeoptimizeIf(not_equal, instr, "not a heap number/undefined");
4814 ExternalReference nan =
4815 ExternalReference::address_of_canonical_non_hole_nan();
4816 __ movsd(result_reg, Operand::StaticVariable(nan));
4817 __ jmp(&done, Label::kNear);
4820 DCHECK(mode == NUMBER_CANDIDATE_IS_SMI);
4824 // Smi to XMM conversion. Clobbering a temp is faster than re-tagging the
4825 // input register since we avoid dependencies.
4826 __ mov(temp_reg, input_reg);
4827 __ SmiUntag(temp_reg); // Untag smi before converting to float.
4828 __ Cvtsi2sd(result_reg, Operand(temp_reg));
4833 void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr, Label* done) {
4834 Register input_reg = ToRegister(instr->value());
4836 // The input was optimistically untagged; revert it.
4837 STATIC_ASSERT(kSmiTagSize == 1);
4838 __ lea(input_reg, Operand(input_reg, times_2, kHeapObjectTag));
4840 if (instr->truncating()) {
4841 Label no_heap_number, check_bools, check_false;
4843 // Heap number map check.
4844 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
4845 factory()->heap_number_map());
4846 __ j(not_equal, &no_heap_number, Label::kNear);
4847 __ TruncateHeapNumberToI(input_reg, input_reg);
4850 __ bind(&no_heap_number);
4851 // Check for Oddballs. Undefined/False is converted to zero and True to one
4852 // for truncating conversions.
4853 __ cmp(input_reg, factory()->undefined_value());
4854 __ j(not_equal, &check_bools, Label::kNear);
4855 __ Move(input_reg, Immediate(0));
4858 __ bind(&check_bools);
4859 __ cmp(input_reg, factory()->true_value());
4860 __ j(not_equal, &check_false, Label::kNear);
4861 __ Move(input_reg, Immediate(1));
4864 __ bind(&check_false);
4865 __ cmp(input_reg, factory()->false_value());
4866 DeoptimizeIf(not_equal, instr, "not a heap number/undefined/true/false");
4867 __ Move(input_reg, Immediate(0));
4869 XMMRegister scratch = ToDoubleRegister(instr->temp());
4870 DCHECK(!scratch.is(xmm0));
4871 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
4872 isolate()->factory()->heap_number_map());
4873 DeoptimizeIf(not_equal, instr, "not a heap number");
4874 __ movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
4875 __ cvttsd2si(input_reg, Operand(xmm0));
4876 __ Cvtsi2sd(scratch, Operand(input_reg));
4877 __ ucomisd(xmm0, scratch);
4878 DeoptimizeIf(not_equal, instr, "lost precision");
4879 DeoptimizeIf(parity_even, instr, "NaN");
4880 if (instr->hydrogen()->GetMinusZeroMode() == FAIL_ON_MINUS_ZERO) {
4881 __ test(input_reg, Operand(input_reg));
4882 __ j(not_zero, done);
4883 __ movmskpd(input_reg, xmm0);
4884 __ and_(input_reg, 1);
4885 DeoptimizeIf(not_zero, instr, "minus zero");
4891 void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
4892 class DeferredTaggedToI FINAL : public LDeferredCode {
4894 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
4895 : LDeferredCode(codegen), instr_(instr) { }
4896 virtual void Generate() OVERRIDE {
4897 codegen()->DoDeferredTaggedToI(instr_, done());
4899 virtual LInstruction* instr() OVERRIDE { return instr_; }
4904 LOperand* input = instr->value();
4905 DCHECK(input->IsRegister());
4906 Register input_reg = ToRegister(input);
4907 DCHECK(input_reg.is(ToRegister(instr->result())));
4909 if (instr->hydrogen()->value()->representation().IsSmi()) {
4910 __ SmiUntag(input_reg);
4912 DeferredTaggedToI* deferred =
4913 new(zone()) DeferredTaggedToI(this, instr);
4914 // Optimistically untag the input.
4915 // If the input is a HeapObject, SmiUntag will set the carry flag.
4916 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
4917 __ SmiUntag(input_reg);
4918 // Branch to deferred code if the input was tagged.
4919 // The deferred code will take care of restoring the tag.
4920 __ j(carry, deferred->entry());
4921 __ bind(deferred->exit());
4926 void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
4927 LOperand* input = instr->value();
4928 DCHECK(input->IsRegister());
4929 LOperand* temp = instr->temp();
4930 DCHECK(temp->IsRegister());
4931 LOperand* result = instr->result();
4932 DCHECK(result->IsDoubleRegister());
4934 Register input_reg = ToRegister(input);
4935 Register temp_reg = ToRegister(temp);
4937 HValue* value = instr->hydrogen()->value();
4938 NumberUntagDMode mode = value->representation().IsSmi()
4939 ? NUMBER_CANDIDATE_IS_SMI : NUMBER_CANDIDATE_IS_ANY_TAGGED;
4941 XMMRegister result_reg = ToDoubleRegister(result);
4942 EmitNumberUntagD(instr, input_reg, temp_reg, result_reg, mode);
4946 void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
4947 LOperand* input = instr->value();
4948 DCHECK(input->IsDoubleRegister());
4949 LOperand* result = instr->result();
4950 DCHECK(result->IsRegister());
4951 Register result_reg = ToRegister(result);
4953 if (instr->truncating()) {
4954 XMMRegister input_reg = ToDoubleRegister(input);
4955 __ TruncateDoubleToI(result_reg, input_reg);
4957 Label lost_precision, is_nan, minus_zero, done;
4958 XMMRegister input_reg = ToDoubleRegister(input);
4959 XMMRegister xmm_scratch = double_scratch0();
4960 Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear;
4961 __ DoubleToI(result_reg, input_reg, xmm_scratch,
4962 instr->hydrogen()->GetMinusZeroMode(), &lost_precision,
4963 &is_nan, &minus_zero, dist);
4964 __ jmp(&done, dist);
4965 __ bind(&lost_precision);
4966 DeoptimizeIf(no_condition, instr, "lost precision");
4968 DeoptimizeIf(no_condition, instr, "NaN");
4969 __ bind(&minus_zero);
4970 DeoptimizeIf(no_condition, instr, "minus zero");
4976 void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) {
4977 LOperand* input = instr->value();
4978 DCHECK(input->IsDoubleRegister());
4979 LOperand* result = instr->result();
4980 DCHECK(result->IsRegister());
4981 Register result_reg = ToRegister(result);
4983 Label lost_precision, is_nan, minus_zero, done;
4984 XMMRegister input_reg = ToDoubleRegister(input);
4985 XMMRegister xmm_scratch = double_scratch0();
4986 Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear;
4987 __ DoubleToI(result_reg, input_reg, xmm_scratch,
4988 instr->hydrogen()->GetMinusZeroMode(), &lost_precision, &is_nan,
4990 __ jmp(&done, dist);
4991 __ bind(&lost_precision);
4992 DeoptimizeIf(no_condition, instr, "lost precision");
4994 DeoptimizeIf(no_condition, instr, "NaN");
4995 __ bind(&minus_zero);
4996 DeoptimizeIf(no_condition, instr, "minus zero");
4998 __ SmiTag(result_reg);
4999 DeoptimizeIf(overflow, instr, "overflow");
5003 void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
5004 LOperand* input = instr->value();
5005 __ test(ToOperand(input), Immediate(kSmiTagMask));
5006 DeoptimizeIf(not_zero, instr, "not a Smi");
5010 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
5011 if (!instr->hydrogen()->value()->type().IsHeapObject()) {
5012 LOperand* input = instr->value();
5013 __ test(ToOperand(input), Immediate(kSmiTagMask));
5014 DeoptimizeIf(zero, instr, "Smi");
5019 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
5020 Register input = ToRegister(instr->value());
5021 Register temp = ToRegister(instr->temp());
5023 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
5025 if (instr->hydrogen()->is_interval_check()) {
5028 instr->hydrogen()->GetCheckInterval(&first, &last);
5030 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
5031 static_cast<int8_t>(first));
5033 // If there is only one type in the interval check for equality.
5034 if (first == last) {
5035 DeoptimizeIf(not_equal, instr, "wrong instance type");
5037 DeoptimizeIf(below, instr, "wrong instance type");
5038 // Omit check for the last type.
5039 if (last != LAST_TYPE) {
5040 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
5041 static_cast<int8_t>(last));
5042 DeoptimizeIf(above, instr, "wrong instance type");
5048 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
5050 if (base::bits::IsPowerOfTwo32(mask)) {
5051 DCHECK(tag == 0 || base::bits::IsPowerOfTwo32(tag));
5052 __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), mask);
5053 DeoptimizeIf(tag == 0 ? not_zero : zero, instr, "wrong instance type");
5055 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
5056 __ and_(temp, mask);
5058 DeoptimizeIf(not_equal, instr, "wrong instance type");
5064 void LCodeGen::DoCheckValue(LCheckValue* instr) {
5065 Handle<HeapObject> object = instr->hydrogen()->object().handle();
5066 if (instr->hydrogen()->object_in_new_space()) {
5067 Register reg = ToRegister(instr->value());
5068 Handle<Cell> cell = isolate()->factory()->NewCell(object);
5069 __ cmp(reg, Operand::ForCell(cell));
5071 Operand operand = ToOperand(instr->value());
5072 __ cmp(operand, object);
5074 DeoptimizeIf(not_equal, instr, "value mismatch");
5078 void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) {
5080 PushSafepointRegistersScope scope(this);
5083 __ CallRuntimeSaveDoubles(Runtime::kTryMigrateInstance);
5084 RecordSafepointWithRegisters(
5085 instr->pointer_map(), 1, Safepoint::kNoLazyDeopt);
5087 __ test(eax, Immediate(kSmiTagMask));
5089 DeoptimizeIf(zero, instr, "instance migration failed");
5093 void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
5094 class DeferredCheckMaps FINAL : public LDeferredCode {
5096 DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object)
5097 : LDeferredCode(codegen), instr_(instr), object_(object) {
5098 SetExit(check_maps());
5100 virtual void Generate() OVERRIDE {
5101 codegen()->DoDeferredInstanceMigration(instr_, object_);
5103 Label* check_maps() { return &check_maps_; }
5104 virtual LInstruction* instr() OVERRIDE { return instr_; }
5111 if (instr->hydrogen()->IsStabilityCheck()) {
5112 const UniqueSet<Map>* maps = instr->hydrogen()->maps();
5113 for (int i = 0; i < maps->size(); ++i) {
5114 AddStabilityDependency(maps->at(i).handle());
5119 LOperand* input = instr->value();
5120 DCHECK(input->IsRegister());
5121 Register reg = ToRegister(input);
5123 DeferredCheckMaps* deferred = NULL;
5124 if (instr->hydrogen()->HasMigrationTarget()) {
5125 deferred = new(zone()) DeferredCheckMaps(this, instr, reg);
5126 __ bind(deferred->check_maps());
5129 const UniqueSet<Map>* maps = instr->hydrogen()->maps();
5131 for (int i = 0; i < maps->size() - 1; i++) {
5132 Handle<Map> map = maps->at(i).handle();
5133 __ CompareMap(reg, map);
5134 __ j(equal, &success, Label::kNear);
5137 Handle<Map> map = maps->at(maps->size() - 1).handle();
5138 __ CompareMap(reg, map);
5139 if (instr->hydrogen()->HasMigrationTarget()) {
5140 __ j(not_equal, deferred->entry());
5142 DeoptimizeIf(not_equal, instr, "wrong map");
5149 void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
5150 XMMRegister value_reg = ToDoubleRegister(instr->unclamped());
5151 XMMRegister xmm_scratch = double_scratch0();
5152 Register result_reg = ToRegister(instr->result());
5153 __ ClampDoubleToUint8(value_reg, xmm_scratch, result_reg);
5157 void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
5158 DCHECK(instr->unclamped()->Equals(instr->result()));
5159 Register value_reg = ToRegister(instr->result());
5160 __ ClampUint8(value_reg);
5164 void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
5165 DCHECK(instr->unclamped()->Equals(instr->result()));
5166 Register input_reg = ToRegister(instr->unclamped());
5167 XMMRegister temp_xmm_reg = ToDoubleRegister(instr->temp_xmm());
5168 XMMRegister xmm_scratch = double_scratch0();
5169 Label is_smi, done, heap_number;
5171 __ JumpIfSmi(input_reg, &is_smi);
5173 // Check for heap number
5174 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5175 factory()->heap_number_map());
5176 __ j(equal, &heap_number, Label::kNear);
5178 // Check for undefined. Undefined is converted to zero for clamping
5180 __ cmp(input_reg, factory()->undefined_value());
5181 DeoptimizeIf(not_equal, instr, "not a heap number/undefined");
5182 __ mov(input_reg, 0);
5183 __ jmp(&done, Label::kNear);
5186 __ bind(&heap_number);
5187 __ movsd(xmm_scratch, FieldOperand(input_reg, HeapNumber::kValueOffset));
5188 __ ClampDoubleToUint8(xmm_scratch, temp_xmm_reg, input_reg);
5189 __ jmp(&done, Label::kNear);
5193 __ SmiUntag(input_reg);
5194 __ ClampUint8(input_reg);
5199 void LCodeGen::DoDoubleBits(LDoubleBits* instr) {
5200 XMMRegister value_reg = ToDoubleRegister(instr->value());
5201 Register result_reg = ToRegister(instr->result());
5202 if (instr->hydrogen()->bits() == HDoubleBits::HIGH) {
5203 if (CpuFeatures::IsSupported(SSE4_1)) {
5204 CpuFeatureScope scope2(masm(), SSE4_1);
5205 __ pextrd(result_reg, value_reg, 1);
5207 XMMRegister xmm_scratch = double_scratch0();
5208 __ pshufd(xmm_scratch, value_reg, 1);
5209 __ movd(result_reg, xmm_scratch);
5212 __ movd(result_reg, value_reg);
5217 void LCodeGen::DoConstructDouble(LConstructDouble* instr) {
5218 Register hi_reg = ToRegister(instr->hi());
5219 Register lo_reg = ToRegister(instr->lo());
5220 XMMRegister result_reg = ToDoubleRegister(instr->result());
5222 if (CpuFeatures::IsSupported(SSE4_1)) {
5223 CpuFeatureScope scope2(masm(), SSE4_1);
5224 __ movd(result_reg, lo_reg);
5225 __ pinsrd(result_reg, hi_reg, 1);
5227 XMMRegister xmm_scratch = double_scratch0();
5228 __ movd(result_reg, hi_reg);
5229 __ psllq(result_reg, 32);
5230 __ movd(xmm_scratch, lo_reg);
5231 __ orps(result_reg, xmm_scratch);
5236 void LCodeGen::DoAllocate(LAllocate* instr) {
5237 class DeferredAllocate FINAL : public LDeferredCode {
5239 DeferredAllocate(LCodeGen* codegen, LAllocate* instr)
5240 : LDeferredCode(codegen), instr_(instr) { }
5241 virtual void Generate() OVERRIDE {
5242 codegen()->DoDeferredAllocate(instr_);
5244 virtual LInstruction* instr() OVERRIDE { return instr_; }
5249 DeferredAllocate* deferred = new(zone()) DeferredAllocate(this, instr);
5251 Register result = ToRegister(instr->result());
5252 Register temp = ToRegister(instr->temp());
5254 // Allocate memory for the object.
5255 AllocationFlags flags = TAG_OBJECT;
5256 if (instr->hydrogen()->MustAllocateDoubleAligned()) {
5257 flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
5259 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
5260 DCHECK(!instr->hydrogen()->IsOldDataSpaceAllocation());
5261 DCHECK(!instr->hydrogen()->IsNewSpaceAllocation());
5262 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
5263 } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
5264 DCHECK(!instr->hydrogen()->IsNewSpaceAllocation());
5265 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_DATA_SPACE);
5268 if (instr->size()->IsConstantOperand()) {
5269 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5270 if (size <= Page::kMaxRegularHeapObjectSize) {
5271 __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
5273 __ jmp(deferred->entry());
5276 Register size = ToRegister(instr->size());
5277 __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
5280 __ bind(deferred->exit());
5282 if (instr->hydrogen()->MustPrefillWithFiller()) {
5283 if (instr->size()->IsConstantOperand()) {
5284 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5285 __ mov(temp, (size / kPointerSize) - 1);
5287 temp = ToRegister(instr->size());
5288 __ shr(temp, kPointerSizeLog2);
5293 __ mov(FieldOperand(result, temp, times_pointer_size, 0),
5294 isolate()->factory()->one_pointer_filler_map());
5296 __ j(not_zero, &loop);
5301 void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
5302 Register result = ToRegister(instr->result());
5304 // TODO(3095996): Get rid of this. For now, we need to make the
5305 // result register contain a valid pointer because it is already
5306 // contained in the register pointer map.
5307 __ Move(result, Immediate(Smi::FromInt(0)));
5309 PushSafepointRegistersScope scope(this);
5310 if (instr->size()->IsRegister()) {
5311 Register size = ToRegister(instr->size());
5312 DCHECK(!size.is(result));
5313 __ SmiTag(ToRegister(instr->size()));
5316 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5317 if (size >= 0 && size <= Smi::kMaxValue) {
5318 __ push(Immediate(Smi::FromInt(size)));
5320 // We should never get here at runtime => abort
5326 int flags = AllocateDoubleAlignFlag::encode(
5327 instr->hydrogen()->MustAllocateDoubleAligned());
5328 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
5329 DCHECK(!instr->hydrogen()->IsOldDataSpaceAllocation());
5330 DCHECK(!instr->hydrogen()->IsNewSpaceAllocation());
5331 flags = AllocateTargetSpace::update(flags, OLD_POINTER_SPACE);
5332 } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
5333 DCHECK(!instr->hydrogen()->IsNewSpaceAllocation());
5334 flags = AllocateTargetSpace::update(flags, OLD_DATA_SPACE);
5336 flags = AllocateTargetSpace::update(flags, NEW_SPACE);
5338 __ push(Immediate(Smi::FromInt(flags)));
5340 CallRuntimeFromDeferred(
5341 Runtime::kAllocateInTargetSpace, 2, instr, instr->context());
5342 __ StoreToSafepointRegisterSlot(result, eax);
5346 void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
5347 DCHECK(ToRegister(instr->value()).is(eax));
5349 CallRuntime(Runtime::kToFastProperties, 1, instr);
5353 void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
5354 DCHECK(ToRegister(instr->context()).is(esi));
5356 // Registers will be used as follows:
5357 // ecx = literals array.
5358 // ebx = regexp literal.
5359 // eax = regexp literal clone.
5361 int literal_offset =
5362 FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index());
5363 __ LoadHeapObject(ecx, instr->hydrogen()->literals());
5364 __ mov(ebx, FieldOperand(ecx, literal_offset));
5365 __ cmp(ebx, factory()->undefined_value());
5366 __ j(not_equal, &materialized, Label::kNear);
5368 // Create regexp literal using runtime function
5369 // Result will be in eax.
5371 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
5372 __ push(Immediate(instr->hydrogen()->pattern()));
5373 __ push(Immediate(instr->hydrogen()->flags()));
5374 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
5377 __ bind(&materialized);
5378 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
5379 Label allocated, runtime_allocate;
5380 __ Allocate(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
5381 __ jmp(&allocated, Label::kNear);
5383 __ bind(&runtime_allocate);
5385 __ push(Immediate(Smi::FromInt(size)));
5386 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
5389 __ bind(&allocated);
5390 // Copy the content into the newly allocated memory.
5391 // (Unroll copy loop once for better throughput).
5392 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
5393 __ mov(edx, FieldOperand(ebx, i));
5394 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
5395 __ mov(FieldOperand(eax, i), edx);
5396 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
5398 if ((size % (2 * kPointerSize)) != 0) {
5399 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
5400 __ mov(FieldOperand(eax, size - kPointerSize), edx);
5405 void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
5406 DCHECK(ToRegister(instr->context()).is(esi));
5407 // Use the fast case closure allocation code that allocates in new
5408 // space for nested functions that don't need literals cloning.
5409 bool pretenure = instr->hydrogen()->pretenure();
5410 if (!pretenure && instr->hydrogen()->has_no_literals()) {
5411 FastNewClosureStub stub(isolate(), instr->hydrogen()->strict_mode(),
5412 instr->hydrogen()->kind());
5413 __ mov(ebx, Immediate(instr->hydrogen()->shared_info()));
5414 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
5417 __ push(Immediate(instr->hydrogen()->shared_info()));
5418 __ push(Immediate(pretenure ? factory()->true_value()
5419 : factory()->false_value()));
5420 CallRuntime(Runtime::kNewClosure, 3, instr);
5425 void LCodeGen::DoTypeof(LTypeof* instr) {
5426 DCHECK(ToRegister(instr->context()).is(esi));
5427 LOperand* input = instr->value();
5428 EmitPushTaggedOperand(input);
5429 CallRuntime(Runtime::kTypeof, 1, instr);
5433 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
5434 Register input = ToRegister(instr->value());
5435 Condition final_branch_condition = EmitTypeofIs(instr, input);
5436 if (final_branch_condition != no_condition) {
5437 EmitBranch(instr, final_branch_condition);
5442 Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) {
5443 Label* true_label = instr->TrueLabel(chunk_);
5444 Label* false_label = instr->FalseLabel(chunk_);
5445 Handle<String> type_name = instr->type_literal();
5446 int left_block = instr->TrueDestination(chunk_);
5447 int right_block = instr->FalseDestination(chunk_);
5448 int next_block = GetNextEmittedBlock();
5450 Label::Distance true_distance = left_block == next_block ? Label::kNear
5452 Label::Distance false_distance = right_block == next_block ? Label::kNear
5454 Condition final_branch_condition = no_condition;
5455 if (String::Equals(type_name, factory()->number_string())) {
5456 __ JumpIfSmi(input, true_label, true_distance);
5457 __ cmp(FieldOperand(input, HeapObject::kMapOffset),
5458 factory()->heap_number_map());
5459 final_branch_condition = equal;
5461 } else if (String::Equals(type_name, factory()->string_string())) {
5462 __ JumpIfSmi(input, false_label, false_distance);
5463 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
5464 __ j(above_equal, false_label, false_distance);
5465 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
5466 1 << Map::kIsUndetectable);
5467 final_branch_condition = zero;
5469 } else if (String::Equals(type_name, factory()->symbol_string())) {
5470 __ JumpIfSmi(input, false_label, false_distance);
5471 __ CmpObjectType(input, SYMBOL_TYPE, input);
5472 final_branch_condition = equal;
5474 } else if (String::Equals(type_name, factory()->boolean_string())) {
5475 __ cmp(input, factory()->true_value());
5476 __ j(equal, true_label, true_distance);
5477 __ cmp(input, factory()->false_value());
5478 final_branch_condition = equal;
5480 } else if (String::Equals(type_name, factory()->undefined_string())) {
5481 __ cmp(input, factory()->undefined_value());
5482 __ j(equal, true_label, true_distance);
5483 __ JumpIfSmi(input, false_label, false_distance);
5484 // Check for undetectable objects => true.
5485 __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
5486 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
5487 1 << Map::kIsUndetectable);
5488 final_branch_condition = not_zero;
5490 } else if (String::Equals(type_name, factory()->function_string())) {
5491 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
5492 __ JumpIfSmi(input, false_label, false_distance);
5493 __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
5494 __ j(equal, true_label, true_distance);
5495 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
5496 final_branch_condition = equal;
5498 } else if (String::Equals(type_name, factory()->object_string())) {
5499 __ JumpIfSmi(input, false_label, false_distance);
5500 __ cmp(input, factory()->null_value());
5501 __ j(equal, true_label, true_distance);
5502 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
5503 __ j(below, false_label, false_distance);
5504 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
5505 __ j(above, false_label, false_distance);
5506 // Check for undetectable objects => false.
5507 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
5508 1 << Map::kIsUndetectable);
5509 final_branch_condition = zero;
5512 __ jmp(false_label, false_distance);
5514 return final_branch_condition;
5518 void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
5519 Register temp = ToRegister(instr->temp());
5521 EmitIsConstructCall(temp);
5522 EmitBranch(instr, equal);
5526 void LCodeGen::EmitIsConstructCall(Register temp) {
5527 // Get the frame pointer for the calling frame.
5528 __ mov(temp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
5530 // Skip the arguments adaptor frame if it exists.
5531 Label check_frame_marker;
5532 __ cmp(Operand(temp, StandardFrameConstants::kContextOffset),
5533 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
5534 __ j(not_equal, &check_frame_marker, Label::kNear);
5535 __ mov(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
5537 // Check the marker in the calling frame.
5538 __ bind(&check_frame_marker);
5539 __ cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
5540 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
5544 void LCodeGen::EnsureSpaceForLazyDeopt(int space_needed) {
5545 if (!info()->IsStub()) {
5546 // Ensure that we have enough space after the previous lazy-bailout
5547 // instruction for patching the code here.
5548 int current_pc = masm()->pc_offset();
5549 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
5550 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
5551 __ Nop(padding_size);
5554 last_lazy_deopt_pc_ = masm()->pc_offset();
5558 void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
5559 last_lazy_deopt_pc_ = masm()->pc_offset();
5560 DCHECK(instr->HasEnvironment());
5561 LEnvironment* env = instr->environment();
5562 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5563 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
5567 void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
5568 Deoptimizer::BailoutType type = instr->hydrogen()->type();
5569 // TODO(danno): Stubs expect all deopts to be lazy for historical reasons (the
5570 // needed return address), even though the implementation of LAZY and EAGER is
5571 // now identical. When LAZY is eventually completely folded into EAGER, remove
5572 // the special case below.
5573 if (info()->IsStub() && type == Deoptimizer::EAGER) {
5574 type = Deoptimizer::LAZY;
5576 DeoptimizeIf(no_condition, instr, instr->hydrogen()->reason(), type);
5580 void LCodeGen::DoDummy(LDummy* instr) {
5581 // Nothing to see here, move on!
5585 void LCodeGen::DoDummyUse(LDummyUse* instr) {
5586 // Nothing to see here, move on!
5590 void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
5591 PushSafepointRegistersScope scope(this);
5592 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
5593 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
5594 RecordSafepointWithLazyDeopt(
5595 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
5596 DCHECK(instr->HasEnvironment());
5597 LEnvironment* env = instr->environment();
5598 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
5602 void LCodeGen::DoStackCheck(LStackCheck* instr) {
5603 class DeferredStackCheck FINAL : public LDeferredCode {
5605 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
5606 : LDeferredCode(codegen), instr_(instr) { }
5607 virtual void Generate() OVERRIDE {
5608 codegen()->DoDeferredStackCheck(instr_);
5610 virtual LInstruction* instr() OVERRIDE { return instr_; }
5612 LStackCheck* instr_;
5615 DCHECK(instr->HasEnvironment());
5616 LEnvironment* env = instr->environment();
5617 // There is no LLazyBailout instruction for stack-checks. We have to
5618 // prepare for lazy deoptimization explicitly here.
5619 if (instr->hydrogen()->is_function_entry()) {
5620 // Perform stack overflow check.
5622 ExternalReference stack_limit =
5623 ExternalReference::address_of_stack_limit(isolate());
5624 __ cmp(esp, Operand::StaticVariable(stack_limit));
5625 __ j(above_equal, &done, Label::kNear);
5627 DCHECK(instr->context()->IsRegister());
5628 DCHECK(ToRegister(instr->context()).is(esi));
5629 CallCode(isolate()->builtins()->StackCheck(),
5630 RelocInfo::CODE_TARGET,
5634 DCHECK(instr->hydrogen()->is_backwards_branch());
5635 // Perform stack overflow check if this goto needs it before jumping.
5636 DeferredStackCheck* deferred_stack_check =
5637 new(zone()) DeferredStackCheck(this, instr);
5638 ExternalReference stack_limit =
5639 ExternalReference::address_of_stack_limit(isolate());
5640 __ cmp(esp, Operand::StaticVariable(stack_limit));
5641 __ j(below, deferred_stack_check->entry());
5642 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
5643 __ bind(instr->done_label());
5644 deferred_stack_check->SetExit(instr->done_label());
5645 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5646 // Don't record a deoptimization index for the safepoint here.
5647 // This will be done explicitly when emitting call and the safepoint in
5648 // the deferred code.
5653 void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
5654 // This is a pseudo-instruction that ensures that the environment here is
5655 // properly registered for deoptimization and records the assembler's PC
5657 LEnvironment* environment = instr->environment();
5659 // If the environment were already registered, we would have no way of
5660 // backpatching it with the spill slot operands.
5661 DCHECK(!environment->HasBeenRegistered());
5662 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
5664 GenerateOsrPrologue();
5668 void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
5669 DCHECK(ToRegister(instr->context()).is(esi));
5670 __ cmp(eax, isolate()->factory()->undefined_value());
5671 DeoptimizeIf(equal, instr, "undefined");
5673 __ cmp(eax, isolate()->factory()->null_value());
5674 DeoptimizeIf(equal, instr, "null");
5676 __ test(eax, Immediate(kSmiTagMask));
5677 DeoptimizeIf(zero, instr, "Smi");
5679 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
5680 __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx);
5681 DeoptimizeIf(below_equal, instr, "wrong instance type");
5683 Label use_cache, call_runtime;
5684 __ CheckEnumCache(&call_runtime);
5686 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
5687 __ jmp(&use_cache, Label::kNear);
5689 // Get the set of properties to enumerate.
5690 __ bind(&call_runtime);
5692 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
5694 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
5695 isolate()->factory()->meta_map());
5696 DeoptimizeIf(not_equal, instr, "wrong map");
5697 __ bind(&use_cache);
5701 void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
5702 Register map = ToRegister(instr->map());
5703 Register result = ToRegister(instr->result());
5704 Label load_cache, done;
5705 __ EnumLength(result, map);
5706 __ cmp(result, Immediate(Smi::FromInt(0)));
5707 __ j(not_equal, &load_cache, Label::kNear);
5708 __ mov(result, isolate()->factory()->empty_fixed_array());
5709 __ jmp(&done, Label::kNear);
5711 __ bind(&load_cache);
5712 __ LoadInstanceDescriptors(map, result);
5714 FieldOperand(result, DescriptorArray::kEnumCacheOffset));
5716 FieldOperand(result, FixedArray::SizeFor(instr->idx())));
5718 __ test(result, result);
5719 DeoptimizeIf(equal, instr, "no cache");
5723 void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
5724 Register object = ToRegister(instr->value());
5725 __ cmp(ToRegister(instr->map()),
5726 FieldOperand(object, HeapObject::kMapOffset));
5727 DeoptimizeIf(not_equal, instr, "wrong map");
5731 void LCodeGen::DoDeferredLoadMutableDouble(LLoadFieldByIndex* instr,
5734 PushSafepointRegistersScope scope(this);
5738 __ CallRuntimeSaveDoubles(Runtime::kLoadMutableDouble);
5739 RecordSafepointWithRegisters(
5740 instr->pointer_map(), 2, Safepoint::kNoLazyDeopt);
5741 __ StoreToSafepointRegisterSlot(object, eax);
5745 void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
5746 class DeferredLoadMutableDouble FINAL : public LDeferredCode {
5748 DeferredLoadMutableDouble(LCodeGen* codegen,
5749 LLoadFieldByIndex* instr,
5752 : LDeferredCode(codegen),
5757 virtual void Generate() OVERRIDE {
5758 codegen()->DoDeferredLoadMutableDouble(instr_, object_, index_);
5760 virtual LInstruction* instr() OVERRIDE { return instr_; }
5762 LLoadFieldByIndex* instr_;
5767 Register object = ToRegister(instr->object());
5768 Register index = ToRegister(instr->index());
5770 DeferredLoadMutableDouble* deferred;
5771 deferred = new(zone()) DeferredLoadMutableDouble(
5772 this, instr, object, index);
5774 Label out_of_object, done;
5775 __ test(index, Immediate(Smi::FromInt(1)));
5776 __ j(not_zero, deferred->entry());
5780 __ cmp(index, Immediate(0));
5781 __ j(less, &out_of_object, Label::kNear);
5782 __ mov(object, FieldOperand(object,
5784 times_half_pointer_size,
5785 JSObject::kHeaderSize));
5786 __ jmp(&done, Label::kNear);
5788 __ bind(&out_of_object);
5789 __ mov(object, FieldOperand(object, JSObject::kPropertiesOffset));
5791 // Index is now equal to out of object property index plus 1.
5792 __ mov(object, FieldOperand(object,
5794 times_half_pointer_size,
5795 FixedArray::kHeaderSize - kPointerSize));
5796 __ bind(deferred->exit());
5801 void LCodeGen::DoStoreFrameContext(LStoreFrameContext* instr) {
5802 Register context = ToRegister(instr->context());
5803 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), context);
5807 void LCodeGen::DoAllocateBlockContext(LAllocateBlockContext* instr) {
5808 Handle<ScopeInfo> scope_info = instr->scope_info();
5809 __ Push(scope_info);
5810 __ push(ToRegister(instr->function()));
5811 CallRuntime(Runtime::kPushBlockContext, 2, instr);
5812 RecordSafepoint(Safepoint::kNoLazyDeopt);
5817 void LCodeGen::HandleSIMD128ToTagged(LSIMD128ToTagged* instr) {
5818 class DeferredSIMD128ToTagged FINAL : public LDeferredCode {
5820 DeferredSIMD128ToTagged(LCodeGen* codegen,
5821 LInstruction* instr,
5822 Runtime::FunctionId id)
5823 : LDeferredCode(codegen), instr_(instr), id_(id) { }
5824 virtual void Generate() OVERRIDE {
5825 codegen()->DoDeferredSIMD128ToTagged(instr_, id_);
5827 virtual LInstruction* instr() OVERRIDE { return instr_; }
5829 LInstruction* instr_;
5830 Runtime::FunctionId id_;
5833 XMMRegister input_reg = ToSIMD128Register(instr->value());
5834 Register reg = ToRegister(instr->result());
5835 Register tmp = ToRegister(instr->temp());
5836 Register tmp2 = ToRegister(instr->temp2());
5838 DeferredSIMD128ToTagged* deferred = new(zone()) DeferredSIMD128ToTagged(
5839 this, instr, static_cast<Runtime::FunctionId>(T::kRuntimeAllocatorId()));
5841 if (FLAG_inline_new) {
5842 if (T::kInstanceType == FLOAT32x4_TYPE) {
5843 __ AllocateFloat32x4(reg, tmp, tmp2, deferred->entry());
5844 } else if (T::kInstanceType == INT32x4_TYPE) {
5845 __ AllocateInt32x4(reg, tmp, tmp2, deferred->entry());
5846 } else if (T::kInstanceType == FLOAT64x2_TYPE) {
5847 __ AllocateFloat64x2(reg, tmp, tmp2, deferred->entry());
5850 __ jmp(deferred->entry());
5852 __ bind(deferred->exit());
5854 // Load the inner FixedTypedArray object.
5855 __ mov(tmp, FieldOperand(reg, T::kValueOffset));
5857 __ movups(FieldOperand(tmp, FixedTypedArrayBase::kDataOffset), input_reg);
5861 void LCodeGen::DoSIMD128ToTagged(LSIMD128ToTagged* instr) {
5862 if (instr->value()->IsFloat32x4Register()) {
5863 HandleSIMD128ToTagged<Float32x4>(instr);
5864 } else if (instr->value()->IsFloat64x2Register()) {
5865 HandleSIMD128ToTagged<Float64x2>(instr);
5867 DCHECK(instr->value()->IsInt32x4Register());
5868 HandleSIMD128ToTagged<Int32x4>(instr);
5874 void LCodeGen::HandleTaggedToSIMD128(LTaggedToSIMD128* instr) {
5875 LOperand* input = instr->value();
5876 DCHECK(input->IsRegister());
5877 LOperand* result = instr->result();
5878 DCHECK(result->IsSIMD128Register());
5880 Register input_reg = ToRegister(input);
5881 Register temp_reg = ToRegister(instr->temp());
5882 XMMRegister result_reg = ToSIMD128Register(result);
5884 __ test(input_reg, Immediate(kSmiTagMask));
5885 DeoptimizeIf(zero, instr, "value is smi");
5886 __ CmpObjectType(input_reg, T::kInstanceType, temp_reg);
5887 DeoptimizeIf(not_equal, instr, "value is not simd128");
5889 // Load the inner FixedTypedArray object.
5890 __ mov(temp_reg, FieldOperand(input_reg, T::kValueOffset));
5893 result_reg, FieldOperand(temp_reg, FixedTypedArrayBase::kDataOffset));
5897 void LCodeGen::DoTaggedToSIMD128(LTaggedToSIMD128* instr) {
5898 if (instr->representation().IsFloat32x4()) {
5899 HandleTaggedToSIMD128<Float32x4>(instr);
5900 } else if (instr->representation().IsFloat64x2()) {
5901 HandleTaggedToSIMD128<Float64x2>(instr);
5903 DCHECK(instr->representation().IsInt32x4());
5904 HandleTaggedToSIMD128<Int32x4>(instr);
5909 void LCodeGen::DoNullarySIMDOperation(LNullarySIMDOperation* instr) {
5910 switch (instr->op()) {
5911 case kFloat32x4Zero: {
5912 XMMRegister result_reg = ToFloat32x4Register(instr->result());
5913 __ xorps(result_reg, result_reg);
5916 case kFloat64x2Zero: {
5917 XMMRegister result_reg = ToFloat64x2Register(instr->result());
5918 __ xorpd(result_reg, result_reg);
5921 case kInt32x4Zero: {
5922 XMMRegister result_reg = ToInt32x4Register(instr->result());
5923 __ xorps(result_reg, result_reg);
5933 void LCodeGen::DoUnarySIMDOperation(LUnarySIMDOperation* instr) {
5935 switch (instr->op()) {
5936 case kFloat32x4Coercion: {
5937 XMMRegister input_reg = ToFloat32x4Register(instr->value());
5938 XMMRegister result_reg = ToFloat32x4Register(instr->result());
5939 if (!result_reg.is(input_reg)) {
5940 __ movaps(result_reg, input_reg);
5944 case kFloat64x2Coercion: {
5945 XMMRegister input_reg = ToFloat64x2Register(instr->value());
5946 XMMRegister result_reg = ToFloat64x2Register(instr->result());
5947 if (!result_reg.is(input_reg)) {
5948 __ movaps(result_reg, input_reg);
5952 case kInt32x4Coercion: {
5953 XMMRegister input_reg = ToInt32x4Register(instr->value());
5954 XMMRegister result_reg = ToInt32x4Register(instr->result());
5955 if (!result_reg.is(input_reg)) {
5956 __ movaps(result_reg, input_reg);
5960 case kSIMD128Change: {
5961 Comment(";;; deoptimize: can not perform representation change"
5962 "for float32x4 or int32x4");
5963 DeoptimizeIf(no_condition, instr, "cannot perform representation change"
5964 "for float32x4 or int32x4");
5969 case kFloat32x4Reciprocal:
5970 case kFloat32x4ReciprocalSqrt:
5971 case kFloat32x4Sqrt: {
5972 DCHECK(instr->value()->Equals(instr->result()));
5973 DCHECK(instr->hydrogen()->value()->representation().IsFloat32x4());
5974 XMMRegister input_reg = ToFloat32x4Register(instr->value());
5975 switch (instr->op()) {
5977 __ absps(input_reg);
5980 __ negateps(input_reg);
5982 case kFloat32x4Reciprocal:
5983 __ rcpps(input_reg, input_reg);
5985 case kFloat32x4ReciprocalSqrt:
5986 __ rsqrtps(input_reg, input_reg);
5988 case kFloat32x4Sqrt:
5989 __ sqrtps(input_reg, input_reg);
5999 case kFloat64x2Sqrt: {
6000 DCHECK(instr->value()->Equals(instr->result()));
6001 DCHECK(instr->hydrogen()->value()->representation().IsFloat64x2());
6002 XMMRegister input_reg = ToFloat64x2Register(instr->value());
6003 switch (instr->op()) {
6005 __ abspd(input_reg);
6008 __ negatepd(input_reg);
6010 case kFloat64x2Sqrt:
6011 __ sqrtpd(input_reg, input_reg);
6021 DCHECK(instr->hydrogen()->value()->representation().IsInt32x4());
6022 XMMRegister input_reg = ToInt32x4Register(instr->value());
6023 switch (instr->op()) {
6025 __ notps(input_reg);
6028 __ pnegd(input_reg);
6036 case kFloat32x4BitsToInt32x4:
6037 case kFloat32x4ToInt32x4: {
6038 DCHECK(instr->hydrogen()->value()->representation().IsFloat32x4());
6039 XMMRegister input_reg = ToFloat32x4Register(instr->value());
6040 XMMRegister result_reg = ToInt32x4Register(instr->result());
6041 if (instr->op() == kFloat32x4BitsToInt32x4) {
6042 if (!result_reg.is(input_reg)) {
6043 __ movaps(result_reg, input_reg);
6046 DCHECK(instr->op() == kFloat32x4ToInt32x4);
6047 __ cvtps2dq(result_reg, input_reg);
6051 case kInt32x4BitsToFloat32x4:
6052 case kInt32x4ToFloat32x4: {
6053 DCHECK(instr->hydrogen()->value()->representation().IsInt32x4());
6054 XMMRegister input_reg = ToInt32x4Register(instr->value());
6055 XMMRegister result_reg = ToFloat32x4Register(instr->result());
6056 if (instr->op() == kInt32x4BitsToFloat32x4) {
6057 if (!result_reg.is(input_reg)) {
6058 __ movaps(result_reg, input_reg);
6061 DCHECK(instr->op() == kInt32x4ToFloat32x4);
6062 __ cvtdq2ps(result_reg, input_reg);
6066 case kFloat32x4Splat: {
6067 DCHECK(instr->hydrogen()->value()->representation().IsDouble());
6068 XMMRegister input_reg = ToDoubleRegister(instr->value());
6069 XMMRegister result_reg = ToFloat32x4Register(instr->result());
6070 XMMRegister xmm_scratch = xmm0;
6071 __ xorps(xmm_scratch, xmm_scratch);
6072 __ cvtsd2ss(xmm_scratch, input_reg);
6073 __ shufps(xmm_scratch, xmm_scratch, 0x0);
6074 __ movaps(result_reg, xmm_scratch);
6077 case kInt32x4Splat: {
6078 DCHECK(instr->hydrogen()->value()->representation().IsInteger32());
6079 Register input_reg = ToRegister(instr->value());
6080 XMMRegister result_reg = ToInt32x4Register(instr->result());
6081 __ movd(result_reg, input_reg);
6082 __ shufps(result_reg, result_reg, 0x0);
6085 case kInt32x4GetSignMask: {
6086 DCHECK(instr->hydrogen()->value()->representation().IsInt32x4());
6087 XMMRegister input_reg = ToInt32x4Register(instr->value());
6088 Register result = ToRegister(instr->result());
6089 __ movmskps(result, input_reg);
6092 case kFloat32x4GetSignMask: {
6093 DCHECK(instr->hydrogen()->value()->representation().IsFloat32x4());
6094 XMMRegister input_reg = ToFloat32x4Register(instr->value());
6095 Register result = ToRegister(instr->result());
6096 __ movmskps(result, input_reg);
6099 case kFloat32x4GetW:
6101 case kFloat32x4GetZ:
6103 case kFloat32x4GetY:
6105 case kFloat32x4GetX: {
6106 DCHECK(instr->hydrogen()->value()->representation().IsFloat32x4());
6107 XMMRegister input_reg = ToFloat32x4Register(instr->value());
6108 XMMRegister result = ToDoubleRegister(instr->result());
6109 XMMRegister xmm_scratch = result.is(input_reg) ? xmm0 : result;
6111 if (select == 0x0) {
6112 __ xorps(xmm_scratch, xmm_scratch);
6113 __ cvtss2sd(xmm_scratch, input_reg);
6114 if (!xmm_scratch.is(result)) {
6115 __ movaps(result, xmm_scratch);
6118 __ pshufd(xmm_scratch, input_reg, select);
6119 if (!xmm_scratch.is(result)) {
6120 __ xorps(result, result);
6122 __ cvtss2sd(result, xmm_scratch);
6126 case kFloat64x2GetSignMask: {
6127 DCHECK(instr->hydrogen()->value()->representation().IsFloat64x2());
6128 XMMRegister input_reg = ToFloat64x2Register(instr->value());
6129 Register result = ToRegister(instr->result());
6130 __ movmskpd(result, input_reg);
6133 case kFloat64x2GetX: {
6134 DCHECK(instr->hydrogen()->value()->representation().IsFloat64x2());
6135 XMMRegister input_reg = ToFloat64x2Register(instr->value());
6136 XMMRegister result = ToDoubleRegister(instr->result());
6138 if (!input_reg.is(result)) {
6139 __ movaps(result, input_reg);
6143 case kFloat64x2GetY: {
6144 DCHECK(instr->hydrogen()->value()->representation().IsFloat64x2());
6145 XMMRegister input_reg = ToFloat64x2Register(instr->value());
6146 XMMRegister result = ToDoubleRegister(instr->result());
6148 if (!input_reg.is(result)) {
6149 __ movaps(result, input_reg);
6151 __ shufpd(result, input_reg, 0x1);
6158 case kInt32x4GetFlagX:
6159 case kInt32x4GetFlagY:
6160 case kInt32x4GetFlagZ:
6161 case kInt32x4GetFlagW: {
6162 DCHECK(instr->hydrogen()->value()->representation().IsInt32x4());
6164 switch (instr->op()) {
6165 case kInt32x4GetFlagX:
6169 case kInt32x4GetFlagY:
6174 case kInt32x4GetFlagZ:
6179 case kInt32x4GetFlagW:
6188 XMMRegister input_reg = ToInt32x4Register(instr->value());
6189 Register result = ToRegister(instr->result());
6190 if (select == 0x0) {
6191 __ movd(result, input_reg);
6193 if (CpuFeatures::IsSupported(SSE4_1)) {
6194 CpuFeatureScope scope(masm(), SSE4_1);
6195 __ extractps(result, input_reg, select);
6197 XMMRegister xmm_scratch = xmm0;
6198 __ pshufd(xmm_scratch, input_reg, select);
6199 __ movd(result, xmm_scratch);
6204 Label false_value, done;
6205 __ test(result, result);
6206 __ j(zero, &false_value, Label::kNear);
6207 __ LoadRoot(result, Heap::kTrueValueRootIndex);
6208 __ jmp(&done, Label::kNear);
6209 __ bind(&false_value);
6210 __ LoadRoot(result, Heap::kFalseValueRootIndex);
6222 void LCodeGen::DoBinarySIMDOperation(LBinarySIMDOperation* instr) {
6223 uint8_t imm8 = 0; // for with operation
6224 switch (instr->op()) {
6230 case kFloat32x4Max: {
6231 DCHECK(instr->left()->Equals(instr->result()));
6232 DCHECK(instr->hydrogen()->left()->representation().IsFloat32x4());
6233 DCHECK(instr->hydrogen()->right()->representation().IsFloat32x4());
6234 XMMRegister left_reg = ToFloat32x4Register(instr->left());
6235 XMMRegister right_reg = ToFloat32x4Register(instr->right());
6236 switch (instr->op()) {
6238 __ addps(left_reg, right_reg);
6241 __ subps(left_reg, right_reg);
6244 __ mulps(left_reg, right_reg);
6247 __ divps(left_reg, right_reg);
6250 __ minps(left_reg, right_reg);
6253 __ maxps(left_reg, right_reg);
6261 case kFloat32x4Scale: {
6262 DCHECK(instr->left()->Equals(instr->result()));
6263 DCHECK(instr->hydrogen()->left()->representation().IsFloat32x4());
6264 DCHECK(instr->hydrogen()->right()->representation().IsDouble());
6265 XMMRegister left_reg = ToFloat32x4Register(instr->left());
6266 XMMRegister right_reg = ToDoubleRegister(instr->right());
6267 XMMRegister scratch_reg = xmm0;
6268 __ xorps(scratch_reg, scratch_reg);
6269 __ cvtsd2ss(scratch_reg, right_reg);
6270 __ shufps(scratch_reg, scratch_reg, 0x0);
6271 __ mulps(left_reg, scratch_reg);
6279 case kFloat64x2Max: {
6280 DCHECK(instr->left()->Equals(instr->result()));
6281 DCHECK(instr->hydrogen()->left()->representation().IsFloat64x2());
6282 DCHECK(instr->hydrogen()->right()->representation().IsFloat64x2());
6283 XMMRegister left_reg = ToFloat64x2Register(instr->left());
6284 XMMRegister right_reg = ToFloat64x2Register(instr->right());
6285 switch (instr->op()) {
6287 __ addpd(left_reg, right_reg);
6290 __ subpd(left_reg, right_reg);
6293 __ mulpd(left_reg, right_reg);
6296 __ divpd(left_reg, right_reg);
6299 __ minpd(left_reg, right_reg);
6302 __ maxpd(left_reg, right_reg);
6310 case kFloat64x2Scale: {
6311 DCHECK(instr->left()->Equals(instr->result()));
6312 DCHECK(instr->hydrogen()->left()->representation().IsFloat64x2());
6313 DCHECK(instr->hydrogen()->right()->representation().IsDouble());
6314 XMMRegister left_reg = ToFloat64x2Register(instr->left());
6315 XMMRegister right_reg = ToDoubleRegister(instr->right());
6316 __ shufpd(right_reg, right_reg, 0x0);
6317 __ mulpd(left_reg, right_reg);
6320 case kFloat32x4Shuffle: {
6321 DCHECK(instr->left()->Equals(instr->result()));
6322 DCHECK(instr->hydrogen()->left()->representation().IsFloat32x4());
6323 if (instr->hydrogen()->right()->IsConstant() &&
6324 HConstant::cast(instr->hydrogen()->right())->HasInteger32Value()) {
6325 int32_t value = ToInteger32(LConstantOperand::cast(instr->right()));
6326 uint8_t select = static_cast<uint8_t>(value & 0xFF);
6327 XMMRegister left_reg = ToFloat32x4Register(instr->left());
6328 __ shufps(left_reg, left_reg, select);
6331 Comment(";;; deoptimize: non-constant selector for shuffle");
6332 DeoptimizeIf(no_condition, instr, "non-constant selector for shuffle");
6336 case kInt32x4Shuffle: {
6337 DCHECK(instr->left()->Equals(instr->result()));
6338 DCHECK(instr->hydrogen()->left()->representation().IsInt32x4());
6339 if (instr->hydrogen()->right()->IsConstant() &&
6340 HConstant::cast(instr->hydrogen()->right())->HasInteger32Value()) {
6341 int32_t value = ToInteger32(LConstantOperand::cast(instr->right()));
6342 uint8_t select = static_cast<uint8_t>(value & 0xFF);
6343 XMMRegister left_reg = ToInt32x4Register(instr->left());
6344 __ pshufd(left_reg, left_reg, select);
6347 Comment(";;; deoptimize: non-constant selector for shuffle");
6348 DeoptimizeIf(no_condition, instr, "non-constant selector for shuffle");
6352 case kInt32x4ShiftLeft:
6353 case kInt32x4ShiftRight:
6354 case kInt32x4ShiftRightArithmetic: {
6355 DCHECK(instr->left()->Equals(instr->result()));
6356 DCHECK(instr->hydrogen()->left()->representation().IsInt32x4());
6357 if (instr->hydrogen()->right()->IsConstant() &&
6358 HConstant::cast(instr->hydrogen()->right())->HasInteger32Value()) {
6359 int32_t value = ToInteger32(LConstantOperand::cast(instr->right()));
6360 uint8_t shift = static_cast<uint8_t>(value & 0xFF);
6361 XMMRegister left_reg = ToInt32x4Register(instr->left());
6362 switch (instr->op()) {
6363 case kInt32x4ShiftLeft:
6364 __ pslld(left_reg, shift);
6366 case kInt32x4ShiftRight:
6367 __ psrld(left_reg, shift);
6369 case kInt32x4ShiftRightArithmetic:
6370 __ psrad(left_reg, shift);
6377 XMMRegister left_reg = ToInt32x4Register(instr->left());
6378 Register shift = ToRegister(instr->right());
6379 XMMRegister xmm_scratch = double_scratch0();
6380 __ movd(xmm_scratch, shift);
6381 switch (instr->op()) {
6382 case kInt32x4ShiftLeft:
6383 __ pslld(left_reg, xmm_scratch);
6385 case kInt32x4ShiftRight:
6386 __ psrld(left_reg, xmm_scratch);
6388 case kInt32x4ShiftRightArithmetic:
6389 __ psrad(left_reg, xmm_scratch);
6397 case kFloat32x4LessThan:
6398 case kFloat32x4LessThanOrEqual:
6399 case kFloat32x4Equal:
6400 case kFloat32x4NotEqual:
6401 case kFloat32x4GreaterThanOrEqual:
6402 case kFloat32x4GreaterThan: {
6403 DCHECK(instr->hydrogen()->left()->representation().IsFloat32x4());
6404 DCHECK(instr->hydrogen()->right()->representation().IsFloat32x4());
6405 XMMRegister left_reg = ToFloat32x4Register(instr->left());
6406 XMMRegister right_reg = ToFloat32x4Register(instr->right());
6407 XMMRegister result_reg = ToInt32x4Register(instr->result());
6408 switch (instr->op()) {
6409 case kFloat32x4LessThan:
6410 if (result_reg.is(left_reg)) {
6411 __ cmpltps(result_reg, right_reg);
6412 } else if (result_reg.is(right_reg)) {
6413 __ cmpnltps(result_reg, left_reg);
6415 __ movaps(result_reg, left_reg);
6416 __ cmpltps(result_reg, right_reg);
6419 case kFloat32x4LessThanOrEqual:
6420 if (result_reg.is(left_reg)) {
6421 __ cmpleps(result_reg, right_reg);
6422 } else if (result_reg.is(right_reg)) {
6423 __ cmpnleps(result_reg, left_reg);
6425 __ movaps(result_reg, left_reg);
6426 __ cmpleps(result_reg, right_reg);
6429 case kFloat32x4Equal:
6430 if (result_reg.is(left_reg)) {
6431 __ cmpeqps(result_reg, right_reg);
6432 } else if (result_reg.is(right_reg)) {
6433 __ cmpeqps(result_reg, left_reg);
6435 __ movaps(result_reg, left_reg);
6436 __ cmpeqps(result_reg, right_reg);
6439 case kFloat32x4NotEqual:
6440 if (result_reg.is(left_reg)) {
6441 __ cmpneqps(result_reg, right_reg);
6442 } else if (result_reg.is(right_reg)) {
6443 __ cmpneqps(result_reg, left_reg);
6445 __ movaps(result_reg, left_reg);
6446 __ cmpneqps(result_reg, right_reg);
6449 case kFloat32x4GreaterThanOrEqual:
6450 if (result_reg.is(left_reg)) {
6451 __ cmpnltps(result_reg, right_reg);
6452 } else if (result_reg.is(right_reg)) {
6453 __ cmpltps(result_reg, left_reg);
6455 __ movaps(result_reg, left_reg);
6456 __ cmpnltps(result_reg, right_reg);
6459 case kFloat32x4GreaterThan:
6460 if (result_reg.is(left_reg)) {
6461 __ cmpnleps(result_reg, right_reg);
6462 } else if (result_reg.is(right_reg)) {
6463 __ cmpleps(result_reg, left_reg);
6465 __ movaps(result_reg, left_reg);
6466 __ cmpnleps(result_reg, right_reg);
6481 case kInt32x4GreaterThan:
6483 case kInt32x4LessThan: {
6484 DCHECK(instr->left()->Equals(instr->result()));
6485 DCHECK(instr->hydrogen()->left()->representation().IsInt32x4());
6486 DCHECK(instr->hydrogen()->right()->representation().IsInt32x4());
6487 XMMRegister left_reg = ToInt32x4Register(instr->left());
6488 XMMRegister right_reg = ToInt32x4Register(instr->right());
6489 switch (instr->op()) {
6491 __ andps(left_reg, right_reg);
6494 __ orps(left_reg, right_reg);
6497 __ xorps(left_reg, right_reg);
6500 __ paddd(left_reg, right_reg);
6503 __ psubd(left_reg, right_reg);
6506 if (CpuFeatures::IsSupported(SSE4_1)) {
6507 CpuFeatureScope scope(masm(), SSE4_1);
6508 __ pmulld(left_reg, right_reg);
6510 // The algorithm is from http://stackoverflow.com/questions/10500766/sse-multiplication-of-4-32-bit-integers
6511 XMMRegister xmm_scratch = xmm0;
6512 __ movaps(xmm_scratch, left_reg);
6513 __ pmuludq(left_reg, right_reg);
6514 __ psrldq(xmm_scratch, 4);
6515 __ psrldq(right_reg, 4);
6516 __ pmuludq(xmm_scratch, right_reg);
6517 __ pshufd(left_reg, left_reg, 8);
6518 __ pshufd(xmm_scratch, xmm_scratch, 8);
6519 __ punpackldq(left_reg, xmm_scratch);
6522 case kInt32x4GreaterThan:
6523 __ pcmpgtd(left_reg, right_reg);
6526 __ pcmpeqd(left_reg, right_reg);
6528 case kInt32x4LessThan: {
6529 XMMRegister xmm_scratch = xmm0;
6530 __ movaps(xmm_scratch, right_reg);
6531 __ pcmpgtd(xmm_scratch, left_reg);
6532 __ movaps(left_reg, xmm_scratch);
6541 case kFloat32x4WithW:
6543 case kFloat32x4WithZ:
6545 case kFloat32x4WithY:
6547 case kFloat32x4WithX: {
6548 DCHECK(instr->left()->Equals(instr->result()));
6549 DCHECK(instr->hydrogen()->left()->representation().IsFloat32x4());
6550 DCHECK(instr->hydrogen()->right()->representation().IsDouble());
6551 XMMRegister left_reg = ToFloat32x4Register(instr->left());
6552 XMMRegister right_reg = ToDoubleRegister(instr->right());
6553 XMMRegister xmm_scratch = xmm0;
6554 __ xorps(xmm_scratch, xmm_scratch);
6555 __ cvtsd2ss(xmm_scratch, right_reg);
6556 if (CpuFeatures::IsSupported(SSE4_1)) {
6558 CpuFeatureScope scope(masm(), SSE4_1);
6559 __ insertps(left_reg, xmm_scratch, imm8);
6561 __ sub(esp, Immediate(kFloat32x4Size));
6562 __ movups(Operand(esp, 0), left_reg);
6563 __ movss(Operand(esp, imm8 * kFloatSize), xmm_scratch);
6564 __ movups(left_reg, Operand(esp, 0));
6565 __ add(esp, Immediate(kFloat32x4Size));
6569 case kFloat64x2WithX: {
6570 DCHECK(instr->left()->Equals(instr->result()));
6571 DCHECK(instr->hydrogen()->left()->representation().IsFloat64x2());
6572 DCHECK(instr->hydrogen()->right()->representation().IsDouble());
6573 XMMRegister left_reg = ToFloat64x2Register(instr->left());
6574 XMMRegister right_reg = ToDoubleRegister(instr->right());
6575 __ sub(esp, Immediate(kFloat64x2Size));
6576 __ movups(Operand(esp, 0), left_reg);
6577 __ movsd(Operand(esp, 0 * kDoubleSize), right_reg);
6578 __ movups(left_reg, Operand(esp, 0));
6579 __ add(esp, Immediate(kFloat64x2Size));
6582 case kFloat64x2WithY: {
6583 DCHECK(instr->left()->Equals(instr->result()));
6584 DCHECK(instr->hydrogen()->left()->representation().IsFloat64x2());
6585 DCHECK(instr->hydrogen()->right()->representation().IsDouble());
6586 XMMRegister left_reg = ToFloat64x2Register(instr->left());
6587 XMMRegister right_reg = ToDoubleRegister(instr->right());
6588 __ sub(esp, Immediate(kFloat64x2Size));
6589 __ movups(Operand(esp, 0), left_reg);
6590 __ movsd(Operand(esp, 1 * kDoubleSize), right_reg);
6591 __ movups(left_reg, Operand(esp, 0));
6592 __ add(esp, Immediate(kFloat64x2Size));
6595 case kFloat64x2Constructor: {
6596 DCHECK(instr->hydrogen()->left()->representation().IsDouble());
6597 DCHECK(instr->hydrogen()->right()->representation().IsDouble());
6598 XMMRegister left_reg = ToDoubleRegister(instr->left());
6599 XMMRegister right_reg = ToDoubleRegister(instr->right());
6600 XMMRegister result_reg = ToFloat64x2Register(instr->result());
6601 __ sub(esp, Immediate(kFloat64x2Size));
6602 __ movsd(Operand(esp, 0 * kDoubleSize), left_reg);
6603 __ movsd(Operand(esp, 1 * kDoubleSize), right_reg);
6604 __ movups(result_reg, Operand(esp, 0));
6605 __ add(esp, Immediate(kFloat64x2Size));
6614 case kInt32x4WithX: {
6615 DCHECK(instr->left()->Equals(instr->result()));
6616 DCHECK(instr->hydrogen()->left()->representation().IsInt32x4());
6617 DCHECK(instr->hydrogen()->right()->representation().IsInteger32());
6618 XMMRegister left_reg = ToInt32x4Register(instr->left());
6619 Register right_reg = ToRegister(instr->right());
6620 if (CpuFeatures::IsSupported(SSE4_1)) {
6621 CpuFeatureScope scope(masm(), SSE4_1);
6622 __ pinsrd(left_reg, right_reg, imm8);
6624 __ sub(esp, Immediate(kInt32x4Size));
6625 __ movdqu(Operand(esp, 0), left_reg);
6626 __ mov(Operand(esp, imm8 * kFloatSize), right_reg);
6627 __ movdqu(left_reg, Operand(esp, 0));
6628 __ add(esp, Immediate(kInt32x4Size));
6632 case kInt32x4WithFlagW:
6634 case kInt32x4WithFlagZ:
6636 case kInt32x4WithFlagY:
6638 case kInt32x4WithFlagX: {
6639 DCHECK(instr->left()->Equals(instr->result()));
6640 DCHECK(instr->hydrogen()->left()->representation().IsInt32x4());
6641 DCHECK(instr->hydrogen()->right()->representation().IsTagged());
6642 HType type = instr->hydrogen()->right()->type();
6643 XMMRegister left_reg = ToInt32x4Register(instr->left());
6644 Register right_reg = ToRegister(instr->right());
6645 Label load_false_value, done;
6646 if (type.IsBoolean()) {
6647 __ sub(esp, Immediate(kInt32x4Size));
6648 __ movups(Operand(esp, 0), left_reg);
6649 __ CompareRoot(right_reg, Heap::kTrueValueRootIndex);
6650 __ j(not_equal, &load_false_value, Label::kNear);
6652 Comment(";;; deoptimize: other types for int32x4.withFlagX/Y/Z/W.");
6653 DeoptimizeIf(no_condition, instr,
6654 "other types for int32x4.withFlagX/Y/Z/W");
6658 __ mov(Operand(esp, imm8 * kFloatSize), Immediate(0xFFFFFFFF));
6659 __ jmp(&done, Label::kNear);
6660 __ bind(&load_false_value);
6661 __ mov(Operand(esp, imm8 * kFloatSize), Immediate(0x0));
6663 __ movups(left_reg, Operand(esp, 0));
6664 __ add(esp, Immediate(kInt32x4Size));
6674 void LCodeGen::DoTernarySIMDOperation(LTernarySIMDOperation* instr) {
6675 switch (instr->op()) {
6676 case kFloat32x4Select: {
6677 DCHECK(instr->hydrogen()->first()->representation().IsInt32x4());
6678 DCHECK(instr->hydrogen()->second()->representation().IsFloat32x4());
6679 DCHECK(instr->hydrogen()->third()->representation().IsFloat32x4());
6681 XMMRegister mask_reg = ToInt32x4Register(instr->first());
6682 XMMRegister left_reg = ToFloat32x4Register(instr->second());
6683 XMMRegister right_reg = ToFloat32x4Register(instr->third());
6684 XMMRegister result_reg = ToFloat32x4Register(instr->result());
6685 XMMRegister temp_reg = xmm0;
6688 __ movaps(temp_reg, mask_reg);
6691 // temp_reg = temp_reg & falseValue.
6692 __ andps(temp_reg, right_reg);
6694 if (!result_reg.is(mask_reg)) {
6695 if (result_reg.is(left_reg)) {
6696 // result_reg = result_reg & trueValue.
6697 __ andps(result_reg, mask_reg);
6698 // out = result_reg | temp_reg.
6699 __ orps(result_reg, temp_reg);
6701 __ movaps(result_reg, mask_reg);
6702 // result_reg = result_reg & trueValue.
6703 __ andps(result_reg, left_reg);
6704 // out = result_reg | temp_reg.
6705 __ orps(result_reg, temp_reg);
6708 // result_reg = result_reg & trueValue.
6709 __ andps(result_reg, left_reg);
6710 // out = result_reg | temp_reg.
6711 __ orps(result_reg, temp_reg);
6715 case kInt32x4Select: {
6716 DCHECK(instr->hydrogen()->first()->representation().IsInt32x4());
6717 DCHECK(instr->hydrogen()->second()->representation().IsInt32x4());
6718 DCHECK(instr->hydrogen()->third()->representation().IsInt32x4());
6720 XMMRegister mask_reg = ToInt32x4Register(instr->first());
6721 XMMRegister left_reg = ToInt32x4Register(instr->second());
6722 XMMRegister right_reg = ToInt32x4Register(instr->third());
6723 XMMRegister result_reg = ToInt32x4Register(instr->result());
6724 XMMRegister temp_reg = xmm0;
6727 __ movaps(temp_reg, mask_reg);
6730 // temp_reg = temp_reg & falseValue.
6731 __ andps(temp_reg, right_reg);
6733 if (!result_reg.is(mask_reg)) {
6734 if (result_reg.is(left_reg)) {
6735 // result_reg = result_reg & trueValue.
6736 __ andps(result_reg, mask_reg);
6737 // out = result_reg | temp_reg.
6738 __ orps(result_reg, temp_reg);
6740 __ movaps(result_reg, mask_reg);
6741 // result_reg = result_reg & trueValue.
6742 __ andps(result_reg, left_reg);
6743 // out = result_reg | temp_reg.
6744 __ orps(result_reg, temp_reg);
6747 // result_reg = result_reg & trueValue.
6748 __ andps(result_reg, left_reg);
6749 // out = result_reg | temp_reg.
6750 __ orps(result_reg, temp_reg);
6754 case kFloat32x4ShuffleMix: {
6755 DCHECK(instr->first()->Equals(instr->result()));
6756 DCHECK(instr->hydrogen()->first()->representation().IsFloat32x4());
6757 DCHECK(instr->hydrogen()->second()->representation().IsFloat32x4());
6758 DCHECK(instr->hydrogen()->third()->representation().IsInteger32());
6759 if (instr->hydrogen()->third()->IsConstant() &&
6760 HConstant::cast(instr->hydrogen()->third())->HasInteger32Value()) {
6761 int32_t value = ToInteger32(LConstantOperand::cast(instr->third()));
6762 uint8_t select = static_cast<uint8_t>(value & 0xFF);
6763 XMMRegister first_reg = ToFloat32x4Register(instr->first());
6764 XMMRegister second_reg = ToFloat32x4Register(instr->second());
6765 __ shufps(first_reg, second_reg, select);
6768 Comment(";;; deoptimize: non-constant selector for shuffle");
6769 DeoptimizeIf(no_condition, instr, "non-constant selector for shuffle");
6773 case kFloat32x4Clamp: {
6774 DCHECK(instr->first()->Equals(instr->result()));
6775 DCHECK(instr->hydrogen()->first()->representation().IsFloat32x4());
6776 DCHECK(instr->hydrogen()->second()->representation().IsFloat32x4());
6777 DCHECK(instr->hydrogen()->third()->representation().IsFloat32x4());
6779 XMMRegister value_reg = ToFloat32x4Register(instr->first());
6780 XMMRegister lower_reg = ToFloat32x4Register(instr->second());
6781 XMMRegister upper_reg = ToFloat32x4Register(instr->third());
6782 __ minps(value_reg, upper_reg);
6783 __ maxps(value_reg, lower_reg);
6786 case kFloat64x2Clamp: {
6787 DCHECK(instr->first()->Equals(instr->result()));
6788 DCHECK(instr->hydrogen()->first()->representation().IsFloat64x2());
6789 DCHECK(instr->hydrogen()->second()->representation().IsFloat64x2());
6790 DCHECK(instr->hydrogen()->third()->representation().IsFloat64x2());
6792 XMMRegister value_reg = ToFloat64x2Register(instr->first());
6793 XMMRegister lower_reg = ToFloat64x2Register(instr->second());
6794 XMMRegister upper_reg = ToFloat64x2Register(instr->third());
6795 __ minpd(value_reg, upper_reg);
6796 __ maxpd(value_reg, lower_reg);
6806 void LCodeGen::DoQuarternarySIMDOperation(LQuarternarySIMDOperation* instr) {
6807 switch (instr->op()) {
6808 case kFloat32x4Constructor: {
6809 DCHECK(instr->hydrogen()->x()->representation().IsDouble());
6810 DCHECK(instr->hydrogen()->y()->representation().IsDouble());
6811 DCHECK(instr->hydrogen()->z()->representation().IsDouble());
6812 DCHECK(instr->hydrogen()->w()->representation().IsDouble());
6813 XMMRegister x_reg = ToDoubleRegister(instr->x());
6814 XMMRegister y_reg = ToDoubleRegister(instr->y());
6815 XMMRegister z_reg = ToDoubleRegister(instr->z());
6816 XMMRegister w_reg = ToDoubleRegister(instr->w());
6817 XMMRegister result_reg = ToFloat32x4Register(instr->result());
6818 __ sub(esp, Immediate(kFloat32x4Size));
6819 __ xorps(xmm0, xmm0);
6820 __ cvtsd2ss(xmm0, x_reg);
6821 __ movss(Operand(esp, 0 * kFloatSize), xmm0);
6822 __ xorps(xmm0, xmm0);
6823 __ cvtsd2ss(xmm0, y_reg);
6824 __ movss(Operand(esp, 1 * kFloatSize), xmm0);
6825 __ xorps(xmm0, xmm0);
6826 __ cvtsd2ss(xmm0, z_reg);
6827 __ movss(Operand(esp, 2 * kFloatSize), xmm0);
6828 __ xorps(xmm0, xmm0);
6829 __ cvtsd2ss(xmm0, w_reg);
6830 __ movss(Operand(esp, 3 * kFloatSize), xmm0);
6831 __ movups(result_reg, Operand(esp, 0 * kFloatSize));
6832 __ add(esp, Immediate(kFloat32x4Size));
6835 case kInt32x4Constructor: {
6836 DCHECK(instr->hydrogen()->x()->representation().IsInteger32());
6837 DCHECK(instr->hydrogen()->y()->representation().IsInteger32());
6838 DCHECK(instr->hydrogen()->z()->representation().IsInteger32());
6839 DCHECK(instr->hydrogen()->w()->representation().IsInteger32());
6840 Register x_reg = ToRegister(instr->x());
6841 Register y_reg = ToRegister(instr->y());
6842 Register z_reg = ToRegister(instr->z());
6843 Register w_reg = ToRegister(instr->w());
6844 XMMRegister result_reg = ToInt32x4Register(instr->result());
6845 __ sub(esp, Immediate(kInt32x4Size));
6846 __ mov(Operand(esp, 0 * kInt32Size), x_reg);
6847 __ mov(Operand(esp, 1 * kInt32Size), y_reg);
6848 __ mov(Operand(esp, 2 * kInt32Size), z_reg);
6849 __ mov(Operand(esp, 3 * kInt32Size), w_reg);
6850 __ movups(result_reg, Operand(esp, 0 * kInt32Size));
6851 __ add(esp, Immediate(kInt32x4Size));
6854 case kInt32x4Bool: {
6855 DCHECK(instr->hydrogen()->x()->representation().IsTagged());
6856 DCHECK(instr->hydrogen()->y()->representation().IsTagged());
6857 DCHECK(instr->hydrogen()->z()->representation().IsTagged());
6858 DCHECK(instr->hydrogen()->w()->representation().IsTagged());
6859 HType x_type = instr->hydrogen()->x()->type();
6860 HType y_type = instr->hydrogen()->y()->type();
6861 HType z_type = instr->hydrogen()->z()->type();
6862 HType w_type = instr->hydrogen()->w()->type();
6863 if (!x_type.IsBoolean() || !y_type.IsBoolean() ||
6864 !z_type.IsBoolean() || !w_type.IsBoolean()) {
6865 Comment(";;; deoptimize: other types for int32x4.bool.");
6866 DeoptimizeIf(no_condition, instr, "other types for int32x4.bool");
6869 XMMRegister result_reg = ToInt32x4Register(instr->result());
6870 Register x_reg = ToRegister(instr->x());
6871 Register y_reg = ToRegister(instr->y());
6872 Register z_reg = ToRegister(instr->z());
6873 Register w_reg = ToRegister(instr->w());
6874 Label load_false_x, done_x, load_false_y, done_y,
6875 load_false_z, done_z, load_false_w, done_w;
6876 __ sub(esp, Immediate(kInt32x4Size));
6878 __ CompareRoot(x_reg, Heap::kTrueValueRootIndex);
6879 __ j(not_equal, &load_false_x, Label::kNear);
6880 __ mov(Operand(esp, 0 * kInt32Size), Immediate(-1));
6881 __ jmp(&done_x, Label::kNear);
6882 __ bind(&load_false_x);
6883 __ mov(Operand(esp, 0 * kInt32Size), Immediate(0x0));
6886 __ CompareRoot(y_reg, Heap::kTrueValueRootIndex);
6887 __ j(not_equal, &load_false_y, Label::kNear);
6888 __ mov(Operand(esp, 1 * kInt32Size), Immediate(-1));
6889 __ jmp(&done_y, Label::kNear);
6890 __ bind(&load_false_y);
6891 __ mov(Operand(esp, 1 * kInt32Size), Immediate(0x0));
6894 __ CompareRoot(z_reg, Heap::kTrueValueRootIndex);
6895 __ j(not_equal, &load_false_z, Label::kNear);
6896 __ mov(Operand(esp, 2 * kInt32Size), Immediate(-1));
6897 __ jmp(&done_z, Label::kNear);
6898 __ bind(&load_false_z);
6899 __ mov(Operand(esp, 2 * kInt32Size), Immediate(0x0));
6902 __ CompareRoot(w_reg, Heap::kTrueValueRootIndex);
6903 __ j(not_equal, &load_false_w, Label::kNear);
6904 __ mov(Operand(esp, 3 * kInt32Size), Immediate(-1));
6905 __ jmp(&done_w, Label::kNear);
6906 __ bind(&load_false_w);
6907 __ mov(Operand(esp, 3 * kInt32Size), Immediate(0x0));
6910 __ movups(result_reg, Operand(esp, 0));
6911 __ add(esp, Immediate(kInt32x4Size));
6923 } } // namespace v8::internal
6925 #endif // V8_TARGET_ARCH_IA32