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