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