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