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