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