Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(33)

Side by Side Diff: src/x64/lithium-x64.cc

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

Powered by Google App Engine
This is Rietveld 408576698