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