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