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