blob: d5590f5c05646c05533febd3ecfd3e861efdbed3 [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.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100386 if (kind == DOUBLE_REGISTERS) current_frame_slots_++;
387 return current_frame_slots_++;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000388}
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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001746LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
1747 DCHECK(instr->value()->representation().IsTagged());
1748 LOperand* value = UseRegisterAtStart(instr->value());
1749 LOperand* temp = TempRegister();
1750 return new(zone()) LIsStringAndBranch(value, temp);
1751}
1752
1753
1754LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
1755 DCHECK(instr->value()->representation().IsTagged());
1756 return new(zone()) LIsSmiAndBranch(Use(instr->value()));
1757}
1758
1759
1760LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
1761 HIsUndetectableAndBranch* instr) {
1762 DCHECK(instr->value()->representation().IsTagged());
1763 LOperand* value = UseRegisterAtStart(instr->value());
1764 return new(zone()) LIsUndetectableAndBranch(value, TempRegister());
1765}
1766
1767
1768LInstruction* LChunkBuilder::DoStringCompareAndBranch(
1769 HStringCompareAndBranch* instr) {
1770 DCHECK(instr->left()->representation().IsTagged());
1771 DCHECK(instr->right()->representation().IsTagged());
1772 LOperand* context = UseFixed(instr->context(), cp);
1773 LOperand* left = UseFixed(instr->left(), r1);
1774 LOperand* right = UseFixed(instr->right(), r0);
1775 LStringCompareAndBranch* result =
1776 new(zone()) LStringCompareAndBranch(context, left, right);
1777 return MarkAsCall(result, instr);
1778}
1779
1780
1781LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
1782 HHasInstanceTypeAndBranch* instr) {
1783 DCHECK(instr->value()->representation().IsTagged());
1784 LOperand* value = UseRegisterAtStart(instr->value());
1785 return new(zone()) LHasInstanceTypeAndBranch(value);
1786}
1787
1788
1789LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
1790 HGetCachedArrayIndex* instr) {
1791 DCHECK(instr->value()->representation().IsTagged());
1792 LOperand* value = UseRegisterAtStart(instr->value());
1793
1794 return DefineAsRegister(new(zone()) LGetCachedArrayIndex(value));
1795}
1796
1797
1798LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch(
1799 HHasCachedArrayIndexAndBranch* instr) {
1800 DCHECK(instr->value()->representation().IsTagged());
1801 return new(zone()) LHasCachedArrayIndexAndBranch(
1802 UseRegisterAtStart(instr->value()));
1803}
1804
1805
1806LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
1807 HClassOfTestAndBranch* instr) {
1808 DCHECK(instr->value()->representation().IsTagged());
1809 LOperand* value = UseRegister(instr->value());
1810 return new(zone()) LClassOfTestAndBranch(value, TempRegister());
1811}
1812
1813
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001814LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) {
1815 LOperand* string = UseRegisterAtStart(instr->string());
1816 LOperand* index = UseRegisterOrConstantAtStart(instr->index());
1817 return DefineAsRegister(new(zone()) LSeqStringGetChar(string, index));
1818}
1819
1820
1821LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
1822 LOperand* string = UseRegisterAtStart(instr->string());
1823 LOperand* index = FLAG_debug_code
1824 ? UseRegisterAtStart(instr->index())
1825 : UseRegisterOrConstantAtStart(instr->index());
1826 LOperand* value = UseRegisterAtStart(instr->value());
1827 LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), cp) : NULL;
1828 return new(zone()) LSeqStringSetChar(context, string, index, value);
1829}
1830
1831
1832LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1833 if (!FLAG_debug_code && instr->skip_check()) return NULL;
1834 LOperand* index = UseRegisterOrConstantAtStart(instr->index());
1835 LOperand* length = !index->IsConstantOperand()
1836 ? UseRegisterOrConstantAtStart(instr->length())
1837 : UseRegisterAtStart(instr->length());
1838 LInstruction* result = new(zone()) LBoundsCheck(index, length);
1839 if (!FLAG_debug_code || !instr->skip_check()) {
1840 result = AssignEnvironment(result);
1841 }
1842 return result;
1843}
1844
1845
1846LInstruction* LChunkBuilder::DoBoundsCheckBaseIndexInformation(
1847 HBoundsCheckBaseIndexInformation* instr) {
1848 UNREACHABLE();
1849 return NULL;
1850}
1851
1852
1853LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
1854 // The control instruction marking the end of a block that completed
1855 // abruptly (e.g., threw an exception). There is nothing specific to do.
1856 return NULL;
1857}
1858
1859
1860LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) {
1861 return NULL;
1862}
1863
1864
1865LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
1866 // All HForceRepresentation instructions should be eliminated in the
1867 // representation change phase of Hydrogen.
1868 UNREACHABLE();
1869 return NULL;
1870}
1871
1872
1873LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1874 Representation from = instr->from();
1875 Representation to = instr->to();
1876 HValue* val = instr->value();
1877 if (from.IsSmi()) {
1878 if (to.IsTagged()) {
1879 LOperand* value = UseRegister(val);
1880 return DefineSameAsFirst(new(zone()) LDummyUse(value));
1881 }
1882 from = Representation::Tagged();
1883 }
1884 if (from.IsTagged()) {
1885 if (to.IsDouble()) {
1886 LOperand* value = UseRegister(val);
1887 LInstruction* result = DefineAsRegister(new(zone()) LNumberUntagD(value));
1888 if (!val->representation().IsSmi()) result = AssignEnvironment(result);
1889 return result;
1890 } else if (to.IsSmi()) {
1891 LOperand* value = UseRegister(val);
1892 if (val->type().IsSmi()) {
1893 return DefineSameAsFirst(new(zone()) LDummyUse(value));
1894 }
1895 return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
1896 } else {
1897 DCHECK(to.IsInteger32());
1898 if (val->type().IsSmi() || val->representation().IsSmi()) {
1899 LOperand* value = UseRegisterAtStart(val);
1900 return DefineAsRegister(new(zone()) LSmiUntag(value, false));
1901 } else {
1902 LOperand* value = UseRegister(val);
1903 LOperand* temp1 = TempRegister();
1904 LOperand* temp2 = TempDoubleRegister();
1905 LInstruction* result =
1906 DefineSameAsFirst(new(zone()) LTaggedToI(value, temp1, temp2));
1907 if (!val->representation().IsSmi()) result = AssignEnvironment(result);
1908 return result;
1909 }
1910 }
1911 } else if (from.IsDouble()) {
1912 if (to.IsTagged()) {
1913 info()->MarkAsDeferredCalling();
1914 LOperand* value = UseRegister(val);
1915 LOperand* temp1 = TempRegister();
1916 LOperand* temp2 = TempRegister();
1917 LUnallocated* result_temp = TempRegister();
1918 LNumberTagD* result = new(zone()) LNumberTagD(value, temp1, temp2);
1919 return AssignPointerMap(Define(result, result_temp));
1920 } else if (to.IsSmi()) {
1921 LOperand* value = UseRegister(val);
1922 return AssignEnvironment(
1923 DefineAsRegister(new(zone()) LDoubleToSmi(value)));
1924 } else {
1925 DCHECK(to.IsInteger32());
1926 LOperand* value = UseRegister(val);
1927 LInstruction* result = DefineAsRegister(new(zone()) LDoubleToI(value));
1928 if (!instr->CanTruncateToInt32()) result = AssignEnvironment(result);
1929 return result;
1930 }
1931 } else if (from.IsInteger32()) {
1932 info()->MarkAsDeferredCalling();
1933 if (to.IsTagged()) {
1934 if (!instr->CheckFlag(HValue::kCanOverflow)) {
1935 LOperand* value = UseRegisterAtStart(val);
1936 return DefineAsRegister(new(zone()) LSmiTag(value));
1937 } else if (val->CheckFlag(HInstruction::kUint32)) {
1938 LOperand* value = UseRegisterAtStart(val);
1939 LOperand* temp1 = TempRegister();
1940 LOperand* temp2 = TempRegister();
1941 LNumberTagU* result = new(zone()) LNumberTagU(value, temp1, temp2);
1942 return AssignPointerMap(DefineAsRegister(result));
1943 } else {
1944 LOperand* value = UseRegisterAtStart(val);
1945 LOperand* temp1 = TempRegister();
1946 LOperand* temp2 = TempRegister();
1947 LNumberTagI* result = new(zone()) LNumberTagI(value, temp1, temp2);
1948 return AssignPointerMap(DefineAsRegister(result));
1949 }
1950 } else if (to.IsSmi()) {
1951 LOperand* value = UseRegister(val);
1952 LInstruction* result = DefineAsRegister(new(zone()) LSmiTag(value));
1953 if (instr->CheckFlag(HValue::kCanOverflow)) {
1954 result = AssignEnvironment(result);
1955 }
1956 return result;
1957 } else {
1958 DCHECK(to.IsDouble());
1959 if (val->CheckFlag(HInstruction::kUint32)) {
1960 return DefineAsRegister(new(zone()) LUint32ToDouble(UseRegister(val)));
1961 } else {
1962 return DefineAsRegister(new(zone()) LInteger32ToDouble(Use(val)));
1963 }
1964 }
1965 }
1966 UNREACHABLE();
1967 return NULL;
1968}
1969
1970
1971LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
1972 LOperand* value = UseRegisterAtStart(instr->value());
1973 LInstruction* result = new(zone()) LCheckNonSmi(value);
1974 if (!instr->value()->type().IsHeapObject()) {
1975 result = AssignEnvironment(result);
1976 }
1977 return result;
1978}
1979
1980
1981LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
1982 LOperand* value = UseRegisterAtStart(instr->value());
1983 return AssignEnvironment(new(zone()) LCheckSmi(value));
1984}
1985
1986
1987LInstruction* LChunkBuilder::DoCheckArrayBufferNotNeutered(
1988 HCheckArrayBufferNotNeutered* instr) {
1989 LOperand* view = UseRegisterAtStart(instr->value());
1990 LCheckArrayBufferNotNeutered* result =
1991 new (zone()) LCheckArrayBufferNotNeutered(view);
1992 return AssignEnvironment(result);
1993}
1994
1995
1996LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
1997 LOperand* value = UseRegisterAtStart(instr->value());
1998 LInstruction* result = new(zone()) LCheckInstanceType(value);
1999 return AssignEnvironment(result);
2000}
2001
2002
2003LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
2004 LOperand* value = UseRegisterAtStart(instr->value());
2005 return AssignEnvironment(new(zone()) LCheckValue(value));
2006}
2007
2008
2009LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
2010 if (instr->IsStabilityCheck()) return new(zone()) LCheckMaps;
2011 LOperand* value = UseRegisterAtStart(instr->value());
2012 LInstruction* result = AssignEnvironment(new(zone()) LCheckMaps(value));
2013 if (instr->HasMigrationTarget()) {
2014 info()->MarkAsDeferredCalling();
2015 result = AssignPointerMap(result);
2016 }
2017 return result;
2018}
2019
2020
2021LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
2022 HValue* value = instr->value();
2023 Representation input_rep = value->representation();
2024 LOperand* reg = UseRegister(value);
2025 if (input_rep.IsDouble()) {
2026 return DefineAsRegister(new(zone()) LClampDToUint8(reg));
2027 } else if (input_rep.IsInteger32()) {
2028 return DefineAsRegister(new(zone()) LClampIToUint8(reg));
2029 } else {
2030 DCHECK(input_rep.IsSmiOrTagged());
2031 // Register allocator doesn't (yet) support allocation of double
2032 // temps. Reserve d1 explicitly.
2033 LClampTToUint8* result =
2034 new(zone()) LClampTToUint8(reg, TempDoubleRegister());
2035 return AssignEnvironment(DefineAsRegister(result));
2036 }
2037}
2038
2039
2040LInstruction* LChunkBuilder::DoDoubleBits(HDoubleBits* instr) {
2041 HValue* value = instr->value();
2042 DCHECK(value->representation().IsDouble());
2043 return DefineAsRegister(new(zone()) LDoubleBits(UseRegister(value)));
2044}
2045
2046
2047LInstruction* LChunkBuilder::DoConstructDouble(HConstructDouble* instr) {
2048 LOperand* lo = UseRegister(instr->lo());
2049 LOperand* hi = UseRegister(instr->hi());
2050 return DefineAsRegister(new(zone()) LConstructDouble(hi, lo));
2051}
2052
2053
2054LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
2055 LOperand* context = info()->IsStub()
2056 ? UseFixed(instr->context(), cp)
2057 : NULL;
2058 LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count());
2059 return new(zone()) LReturn(UseFixed(instr->value(), r0), context,
2060 parameter_count);
2061}
2062
2063
2064LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
2065 Representation r = instr->representation();
2066 if (r.IsSmi()) {
2067 return DefineAsRegister(new(zone()) LConstantS);
2068 } else if (r.IsInteger32()) {
2069 return DefineAsRegister(new(zone()) LConstantI);
2070 } else if (r.IsDouble()) {
2071 return DefineAsRegister(new(zone()) LConstantD);
2072 } else if (r.IsExternal()) {
2073 return DefineAsRegister(new(zone()) LConstantE);
2074 } else if (r.IsTagged()) {
2075 return DefineAsRegister(new(zone()) LConstantT);
2076 } else {
2077 UNREACHABLE();
2078 return NULL;
2079 }
2080}
2081
2082
2083LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
2084 LOperand* context = UseFixed(instr->context(), cp);
2085 LOperand* global_object =
2086 UseFixed(instr->global_object(), LoadDescriptor::ReceiverRegister());
2087 LOperand* vector = NULL;
2088 if (instr->HasVectorAndSlot()) {
2089 vector = FixedTemp(LoadWithVectorDescriptor::VectorRegister());
2090 }
2091 LLoadGlobalGeneric* result =
2092 new(zone()) LLoadGlobalGeneric(context, global_object, vector);
2093 return MarkAsCall(DefineFixed(result, r0), instr);
2094}
2095
2096
2097LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
2098 LOperand* context = UseRegisterAtStart(instr->value());
2099 LInstruction* result =
2100 DefineAsRegister(new(zone()) LLoadContextSlot(context));
2101 if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
2102 result = AssignEnvironment(result);
2103 }
2104 return result;
2105}
2106
2107
2108LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
2109 LOperand* context;
2110 LOperand* value;
2111 if (instr->NeedsWriteBarrier()) {
2112 context = UseTempRegister(instr->context());
2113 value = UseTempRegister(instr->value());
2114 } else {
2115 context = UseRegister(instr->context());
2116 value = UseRegister(instr->value());
2117 }
2118 LInstruction* result = new(zone()) LStoreContextSlot(context, value);
2119 if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
2120 result = AssignEnvironment(result);
2121 }
2122 return result;
2123}
2124
2125
2126LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
2127 LOperand* obj = UseRegisterAtStart(instr->object());
2128 return DefineAsRegister(new(zone()) LLoadNamedField(obj));
2129}
2130
2131
2132LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
2133 LOperand* context = UseFixed(instr->context(), cp);
2134 LOperand* object =
2135 UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
2136 LOperand* vector = NULL;
2137 if (instr->HasVectorAndSlot()) {
2138 vector = FixedTemp(LoadWithVectorDescriptor::VectorRegister());
2139 }
2140
2141 LInstruction* result =
2142 DefineFixed(new(zone()) LLoadNamedGeneric(context, object, vector), r0);
2143 return MarkAsCall(result, instr);
2144}
2145
2146
2147LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
2148 HLoadFunctionPrototype* instr) {
2149 return AssignEnvironment(DefineAsRegister(
2150 new(zone()) LLoadFunctionPrototype(UseRegister(instr->function()))));
2151}
2152
2153
2154LInstruction* LChunkBuilder::DoLoadRoot(HLoadRoot* instr) {
2155 return DefineAsRegister(new(zone()) LLoadRoot);
2156}
2157
2158
2159LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
2160 DCHECK(instr->key()->representation().IsSmiOrInteger32());
2161 ElementsKind elements_kind = instr->elements_kind();
2162 LOperand* key = UseRegisterOrConstantAtStart(instr->key());
2163 LInstruction* result = NULL;
2164
2165 if (!instr->is_fixed_typed_array()) {
2166 LOperand* obj = NULL;
2167 if (instr->representation().IsDouble()) {
2168 obj = UseRegister(instr->elements());
2169 } else {
2170 DCHECK(instr->representation().IsSmiOrTagged());
2171 obj = UseRegisterAtStart(instr->elements());
2172 }
2173 result = DefineAsRegister(new (zone()) LLoadKeyed(obj, key, nullptr));
2174 } else {
2175 DCHECK(
2176 (instr->representation().IsInteger32() &&
2177 !IsDoubleOrFloatElementsKind(elements_kind)) ||
2178 (instr->representation().IsDouble() &&
2179 IsDoubleOrFloatElementsKind(elements_kind)));
2180 LOperand* backing_store = UseRegister(instr->elements());
2181 LOperand* backing_store_owner = UseAny(instr->backing_store_owner());
2182 result = DefineAsRegister(
2183 new (zone()) LLoadKeyed(backing_store, key, backing_store_owner));
2184 }
2185
2186 bool needs_environment;
2187 if (instr->is_fixed_typed_array()) {
2188 // see LCodeGen::DoLoadKeyedExternalArray
2189 needs_environment = elements_kind == UINT32_ELEMENTS &&
2190 !instr->CheckFlag(HInstruction::kUint32);
2191 } else {
2192 // see LCodeGen::DoLoadKeyedFixedDoubleArray and
2193 // LCodeGen::DoLoadKeyedFixedArray
2194 needs_environment =
2195 instr->RequiresHoleCheck() ||
2196 (instr->hole_mode() == CONVERT_HOLE_TO_UNDEFINED && info()->IsStub());
2197 }
2198
2199 if (needs_environment) {
2200 result = AssignEnvironment(result);
2201 }
2202 return result;
2203}
2204
2205
2206LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
2207 LOperand* context = UseFixed(instr->context(), cp);
2208 LOperand* object =
2209 UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
2210 LOperand* key = UseFixed(instr->key(), LoadDescriptor::NameRegister());
2211 LOperand* vector = NULL;
2212 if (instr->HasVectorAndSlot()) {
2213 vector = FixedTemp(LoadWithVectorDescriptor::VectorRegister());
2214 }
2215
2216 LInstruction* result =
2217 DefineFixed(new(zone()) LLoadKeyedGeneric(context, object, key, vector),
2218 r0);
2219 return MarkAsCall(result, instr);
2220}
2221
2222
2223LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
2224 if (!instr->is_fixed_typed_array()) {
2225 DCHECK(instr->elements()->representation().IsTagged());
2226 bool needs_write_barrier = instr->NeedsWriteBarrier();
2227 LOperand* object = NULL;
2228 LOperand* key = NULL;
2229 LOperand* val = NULL;
2230
2231 if (instr->value()->representation().IsDouble()) {
2232 object = UseRegisterAtStart(instr->elements());
2233 val = UseRegister(instr->value());
2234 key = UseRegisterOrConstantAtStart(instr->key());
2235 } else {
2236 DCHECK(instr->value()->representation().IsSmiOrTagged());
2237 if (needs_write_barrier) {
2238 object = UseTempRegister(instr->elements());
2239 val = UseTempRegister(instr->value());
2240 key = UseTempRegister(instr->key());
2241 } else {
2242 object = UseRegisterAtStart(instr->elements());
2243 val = UseRegisterAtStart(instr->value());
2244 key = UseRegisterOrConstantAtStart(instr->key());
2245 }
2246 }
2247
2248 return new (zone()) LStoreKeyed(object, key, val, nullptr);
2249 }
2250
2251 DCHECK(
2252 (instr->value()->representation().IsInteger32() &&
2253 !IsDoubleOrFloatElementsKind(instr->elements_kind())) ||
2254 (instr->value()->representation().IsDouble() &&
2255 IsDoubleOrFloatElementsKind(instr->elements_kind())));
2256 DCHECK(instr->elements()->representation().IsExternal());
2257 LOperand* val = UseRegister(instr->value());
2258 LOperand* key = UseRegisterOrConstantAtStart(instr->key());
2259 LOperand* backing_store = UseRegister(instr->elements());
2260 LOperand* backing_store_owner = UseAny(instr->backing_store_owner());
2261 return new (zone()) LStoreKeyed(backing_store, key, val, backing_store_owner);
2262}
2263
2264
2265LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
2266 LOperand* context = UseFixed(instr->context(), cp);
2267 LOperand* obj =
2268 UseFixed(instr->object(), StoreDescriptor::ReceiverRegister());
2269 LOperand* key = UseFixed(instr->key(), StoreDescriptor::NameRegister());
2270 LOperand* val = UseFixed(instr->value(), StoreDescriptor::ValueRegister());
2271
2272 DCHECK(instr->object()->representation().IsTagged());
2273 DCHECK(instr->key()->representation().IsTagged());
2274 DCHECK(instr->value()->representation().IsTagged());
2275
2276 LOperand* slot = NULL;
2277 LOperand* vector = NULL;
2278 if (instr->HasVectorAndSlot()) {
2279 slot = FixedTemp(VectorStoreICDescriptor::SlotRegister());
2280 vector = FixedTemp(VectorStoreICDescriptor::VectorRegister());
2281 }
2282
2283 LStoreKeyedGeneric* result =
2284 new (zone()) LStoreKeyedGeneric(context, obj, key, val, slot, vector);
2285 return MarkAsCall(result, instr);
2286}
2287
2288
2289LInstruction* LChunkBuilder::DoTransitionElementsKind(
2290 HTransitionElementsKind* instr) {
2291 if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
2292 LOperand* object = UseRegister(instr->object());
2293 LOperand* new_map_reg = TempRegister();
2294 LTransitionElementsKind* result =
2295 new(zone()) LTransitionElementsKind(object, NULL, new_map_reg);
2296 return result;
2297 } else {
2298 LOperand* object = UseFixed(instr->object(), r0);
2299 LOperand* context = UseFixed(instr->context(), cp);
2300 LTransitionElementsKind* result =
2301 new(zone()) LTransitionElementsKind(object, context, NULL);
2302 return MarkAsCall(result, instr);
2303 }
2304}
2305
2306
2307LInstruction* LChunkBuilder::DoTrapAllocationMemento(
2308 HTrapAllocationMemento* instr) {
2309 LOperand* object = UseRegister(instr->object());
2310 LOperand* temp = TempRegister();
2311 LTrapAllocationMemento* result =
2312 new(zone()) LTrapAllocationMemento(object, temp);
2313 return AssignEnvironment(result);
2314}
2315
2316
2317LInstruction* LChunkBuilder::DoMaybeGrowElements(HMaybeGrowElements* instr) {
2318 info()->MarkAsDeferredCalling();
2319 LOperand* context = UseFixed(instr->context(), cp);
2320 LOperand* object = Use(instr->object());
2321 LOperand* elements = Use(instr->elements());
2322 LOperand* key = UseRegisterOrConstant(instr->key());
2323 LOperand* current_capacity = UseRegisterOrConstant(instr->current_capacity());
2324
2325 LMaybeGrowElements* result = new (zone())
2326 LMaybeGrowElements(context, object, elements, key, current_capacity);
2327 DefineFixed(result, r0);
2328 return AssignPointerMap(AssignEnvironment(result));
2329}
2330
2331
2332LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
2333 bool is_in_object = instr->access().IsInobject();
2334 bool needs_write_barrier = instr->NeedsWriteBarrier();
2335 bool needs_write_barrier_for_map = instr->has_transition() &&
2336 instr->NeedsWriteBarrierForMap();
2337
2338 LOperand* obj;
2339 if (needs_write_barrier) {
2340 obj = is_in_object
2341 ? UseRegister(instr->object())
2342 : UseTempRegister(instr->object());
2343 } else {
2344 obj = needs_write_barrier_for_map
2345 ? UseRegister(instr->object())
2346 : UseRegisterAtStart(instr->object());
2347 }
2348
2349 LOperand* val;
2350 if (needs_write_barrier) {
2351 val = UseTempRegister(instr->value());
2352 } else if (instr->field_representation().IsDouble()) {
2353 val = UseRegisterAtStart(instr->value());
2354 } else {
2355 val = UseRegister(instr->value());
2356 }
2357
2358 // We need a temporary register for write barrier of the map field.
2359 LOperand* temp = needs_write_barrier_for_map ? TempRegister() : NULL;
2360
2361 return new(zone()) LStoreNamedField(obj, val, temp);
2362}
2363
2364
2365LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
2366 LOperand* context = UseFixed(instr->context(), cp);
2367 LOperand* obj =
2368 UseFixed(instr->object(), StoreDescriptor::ReceiverRegister());
2369 LOperand* val = UseFixed(instr->value(), StoreDescriptor::ValueRegister());
2370 LOperand* slot = NULL;
2371 LOperand* vector = NULL;
2372 if (instr->HasVectorAndSlot()) {
2373 slot = FixedTemp(VectorStoreICDescriptor::SlotRegister());
2374 vector = FixedTemp(VectorStoreICDescriptor::VectorRegister());
2375 }
2376
2377 LStoreNamedGeneric* result =
2378 new (zone()) LStoreNamedGeneric(context, obj, val, slot, vector);
2379 return MarkAsCall(result, instr);
2380}
2381
2382
2383LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
2384 LOperand* context = UseFixed(instr->context(), cp);
2385 LOperand* left = UseFixed(instr->left(), r1);
2386 LOperand* right = UseFixed(instr->right(), r0);
2387 return MarkAsCall(
2388 DefineFixed(new(zone()) LStringAdd(context, left, right), r0),
2389 instr);
2390}
2391
2392
2393LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
2394 LOperand* string = UseTempRegister(instr->string());
2395 LOperand* index = UseTempRegister(instr->index());
2396 LOperand* context = UseAny(instr->context());
2397 LStringCharCodeAt* result =
2398 new(zone()) LStringCharCodeAt(context, string, index);
2399 return AssignPointerMap(DefineAsRegister(result));
2400}
2401
2402
2403LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
2404 LOperand* char_code = UseRegister(instr->value());
2405 LOperand* context = UseAny(instr->context());
2406 LStringCharFromCode* result =
2407 new(zone()) LStringCharFromCode(context, char_code);
2408 return AssignPointerMap(DefineAsRegister(result));
2409}
2410
2411
2412LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
2413 info()->MarkAsDeferredCalling();
2414 LOperand* context = UseAny(instr->context());
2415 LOperand* size = UseRegisterOrConstant(instr->size());
2416 LOperand* temp1 = TempRegister();
2417 LOperand* temp2 = TempRegister();
2418 LAllocate* result = new(zone()) LAllocate(context, size, temp1, temp2);
2419 return AssignPointerMap(DefineAsRegister(result));
2420}
2421
2422
2423LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
2424 DCHECK(argument_count_ == 0);
2425 allocator_->MarkAsOsrEntry();
2426 current_block_->last_environment()->set_ast_id(instr->ast_id());
2427 return AssignEnvironment(new(zone()) LOsrEntry);
2428}
2429
2430
2431LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2432 LParameter* result = new(zone()) LParameter;
2433 if (instr->kind() == HParameter::STACK_PARAMETER) {
2434 int spill_index = chunk()->GetParameterStackSlot(instr->index());
2435 return DefineAsSpilled(result, spill_index);
2436 } else {
2437 DCHECK(info()->IsStub());
Ben Murdoch097c5b22016-05-18 11:27:45 +01002438 CallInterfaceDescriptor descriptor = graph()->descriptor();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002439 int index = static_cast<int>(instr->index());
2440 Register reg = descriptor.GetRegisterParameter(index);
2441 return DefineFixed(result, reg);
2442 }
2443}
2444
2445
2446LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
2447 // Use an index that corresponds to the location in the unoptimized frame,
2448 // which the optimized frame will subsume.
2449 int env_index = instr->index();
2450 int spill_index = 0;
2451 if (instr->environment()->is_parameter_index(env_index)) {
2452 spill_index = chunk()->GetParameterStackSlot(env_index);
2453 } else {
2454 spill_index = env_index - instr->environment()->first_local_index();
2455 if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
2456 Retry(kTooManySpillSlotsNeededForOSR);
2457 spill_index = 0;
2458 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01002459 spill_index += StandardFrameConstants::kFixedSlotCount;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002460 }
2461 return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index);
2462}
2463
2464
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002465LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
2466 // There are no real uses of the arguments object.
2467 // arguments.length and element access are supported directly on
2468 // stack arguments, and any real arguments object use causes a bailout.
2469 // So this value is never used.
2470 return NULL;
2471}
2472
2473
2474LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
2475 instr->ReplayEnvironment(current_block_->last_environment());
2476
2477 // There are no real uses of a captured object.
2478 return NULL;
2479}
2480
2481
2482LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
2483 info()->MarkAsRequiresFrame();
2484 LOperand* args = UseRegister(instr->arguments());
2485 LOperand* length = UseRegisterOrConstantAtStart(instr->length());
2486 LOperand* index = UseRegisterOrConstantAtStart(instr->index());
2487 return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index));
2488}
2489
2490
2491LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
2492 LOperand* object = UseFixed(instr->value(), r0);
2493 LToFastProperties* result = new(zone()) LToFastProperties(object);
2494 return MarkAsCall(DefineFixed(result, r0), instr);
2495}
2496
2497
2498LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2499 LOperand* context = UseFixed(instr->context(), cp);
2500 LOperand* value = UseFixed(instr->value(), r3);
2501 LTypeof* result = new (zone()) LTypeof(context, value);
2502 return MarkAsCall(DefineFixed(result, r0), instr);
2503}
2504
2505
2506LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
2507 return new(zone()) LTypeofIsAndBranch(UseRegister(instr->value()));
2508}
2509
2510
2511LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2512 instr->ReplayEnvironment(current_block_->last_environment());
2513 return NULL;
2514}
2515
2516
2517LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2518 if (instr->is_function_entry()) {
2519 LOperand* context = UseFixed(instr->context(), cp);
2520 return MarkAsCall(new(zone()) LStackCheck(context), instr);
2521 } else {
2522 DCHECK(instr->is_backwards_branch());
2523 LOperand* context = UseAny(instr->context());
2524 return AssignEnvironment(
2525 AssignPointerMap(new(zone()) LStackCheck(context)));
2526 }
2527}
2528
2529
2530LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
2531 HEnvironment* outer = current_block_->last_environment();
2532 outer->set_ast_id(instr->ReturnId());
2533 HConstant* undefined = graph()->GetConstantUndefined();
2534 HEnvironment* inner = outer->CopyForInlining(instr->closure(),
2535 instr->arguments_count(),
2536 instr->function(),
2537 undefined,
2538 instr->inlining_kind());
2539 // Only replay binding of arguments object if it wasn't removed from graph.
2540 if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
2541 inner->Bind(instr->arguments_var(), instr->arguments_object());
2542 }
2543 inner->BindContext(instr->closure_context());
2544 inner->set_entry(instr);
2545 current_block_->UpdateEnvironment(inner);
2546 chunk_->AddInlinedFunction(instr->shared());
2547 return NULL;
2548}
2549
2550
2551LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2552 LInstruction* pop = NULL;
2553
2554 HEnvironment* env = current_block_->last_environment();
2555
2556 if (env->entry()->arguments_pushed()) {
2557 int argument_count = env->arguments_environment()->parameter_count();
2558 pop = new(zone()) LDrop(argument_count);
2559 DCHECK(instr->argument_delta() == -argument_count);
2560 }
2561
2562 HEnvironment* outer = current_block_->last_environment()->
2563 DiscardInlined(false);
2564 current_block_->UpdateEnvironment(outer);
2565
2566 return pop;
2567}
2568
2569
2570LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
2571 LOperand* context = UseFixed(instr->context(), cp);
2572 LOperand* object = UseFixed(instr->enumerable(), r0);
2573 LForInPrepareMap* result = new(zone()) LForInPrepareMap(context, object);
2574 return MarkAsCall(DefineFixed(result, r0), instr, CAN_DEOPTIMIZE_EAGERLY);
2575}
2576
2577
2578LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
2579 LOperand* map = UseRegister(instr->map());
2580 return AssignEnvironment(DefineAsRegister(new(zone()) LForInCacheArray(map)));
2581}
2582
2583
2584LInstruction* LChunkBuilder::DoCheckMapValue(HCheckMapValue* instr) {
2585 LOperand* value = UseRegisterAtStart(instr->value());
2586 LOperand* map = UseRegisterAtStart(instr->map());
2587 return AssignEnvironment(new(zone()) LCheckMapValue(value, map));
2588}
2589
2590
2591LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
2592 LOperand* object = UseRegister(instr->object());
2593 LOperand* index = UseTempRegister(instr->index());
2594 LLoadFieldByIndex* load = new(zone()) LLoadFieldByIndex(object, index);
2595 LInstruction* result = DefineSameAsFirst(load);
2596 return AssignPointerMap(result);
2597}
2598
2599
2600LInstruction* LChunkBuilder::DoStoreFrameContext(HStoreFrameContext* instr) {
2601 LOperand* context = UseRegisterAtStart(instr->context());
2602 return new(zone()) LStoreFrameContext(context);
2603}
2604
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002605} // namespace internal
2606} // namespace v8