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