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