1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include "v8.h"
29
30 #if defined(V8_TARGET_ARCH_IA32)
31
32 #include "lithium-allocator-inl.h"
33 #include "ia32/lithium-ia32.h"
34 #include "ia32/lithium-codegen-ia32.h"
35
36 namespace v8 {
37 namespace internal {
38
39 #define DEFINE_COMPILE(type) \
40 void L##type::CompileToNative(LCodeGen* generator) { \
41 generator->Do##type(this); \
42 }
LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)43 LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
44 #undef DEFINE_COMPILE
45
46 LOsrEntry::LOsrEntry() {
47 for (int i = 0; i < Register::kNumAllocatableRegisters; ++i) {
48 register_spills_[i] = NULL;
49 }
50 for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; ++i) {
51 double_register_spills_[i] = NULL;
52 }
53 }
54
55
MarkSpilledRegister(int allocation_index,LOperand * spill_operand)56 void LOsrEntry::MarkSpilledRegister(int allocation_index,
57 LOperand* spill_operand) {
58 ASSERT(spill_operand->IsStackSlot());
59 ASSERT(register_spills_[allocation_index] == NULL);
60 register_spills_[allocation_index] = spill_operand;
61 }
62
63
MarkSpilledDoubleRegister(int allocation_index,LOperand * spill_operand)64 void LOsrEntry::MarkSpilledDoubleRegister(int allocation_index,
65 LOperand* spill_operand) {
66 ASSERT(spill_operand->IsDoubleStackSlot());
67 ASSERT(double_register_spills_[allocation_index] == NULL);
68 double_register_spills_[allocation_index] = spill_operand;
69 }
70
71
72 #ifdef DEBUG
VerifyCall()73 void LInstruction::VerifyCall() {
74 // Call instructions can use only fixed registers as temporaries and
75 // outputs because all registers are blocked by the calling convention.
76 // Inputs operands must use a fixed register or use-at-start policy or
77 // a non-register policy.
78 ASSERT(Output() == NULL ||
79 LUnallocated::cast(Output())->HasFixedPolicy() ||
80 !LUnallocated::cast(Output())->HasRegisterPolicy());
81 for (UseIterator it(this); !it.Done(); it.Advance()) {
82 LUnallocated* operand = LUnallocated::cast(it.Current());
83 ASSERT(operand->HasFixedPolicy() ||
84 operand->IsUsedAtStart());
85 }
86 for (TempIterator it(this); !it.Done(); it.Advance()) {
87 LUnallocated* operand = LUnallocated::cast(it.Current());
88 ASSERT(operand->HasFixedPolicy() ||!operand->HasRegisterPolicy());
89 }
90 }
91 #endif
92
93
PrintTo(StringStream * stream)94 void LInstruction::PrintTo(StringStream* stream) {
95 stream->Add("%s ", this->Mnemonic());
96
97 PrintOutputOperandTo(stream);
98
99 PrintDataTo(stream);
100
101 if (HasEnvironment()) {
102 stream->Add(" ");
103 environment()->PrintTo(stream);
104 }
105
106 if (HasPointerMap()) {
107 stream->Add(" ");
108 pointer_map()->PrintTo(stream);
109 }
110 }
111
112
PrintDataTo(StringStream * stream)113 void LInstruction::PrintDataTo(StringStream* stream) {
114 stream->Add("= ");
115 for (int i = 0; i < InputCount(); i++) {
116 if (i > 0) stream->Add(" ");
117 InputAt(i)->PrintTo(stream);
118 }
119 }
120
121
PrintOutputOperandTo(StringStream * stream)122 void LInstruction::PrintOutputOperandTo(StringStream* stream) {
123 if (HasResult()) result()->PrintTo(stream);
124 }
125
126
PrintDataTo(StringStream * stream)127 void LLabel::PrintDataTo(StringStream* stream) {
128 LGap::PrintDataTo(stream);
129 LLabel* rep = replacement();
130 if (rep != NULL) {
131 stream->Add(" Dead block replaced with B%d", rep->block_id());
132 }
133 }
134
135
IsRedundant() const136 bool LGap::IsRedundant() const {
137 for (int i = 0; i < 4; i++) {
138 if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) {
139 return false;
140 }
141 }
142
143 return true;
144 }
145
146
PrintDataTo(StringStream * stream)147 void LGap::PrintDataTo(StringStream* stream) {
148 for (int i = 0; i < 4; i++) {
149 stream->Add("(");
150 if (parallel_moves_[i] != NULL) {
151 parallel_moves_[i]->PrintDataTo(stream);
152 }
153 stream->Add(") ");
154 }
155 }
156
157
Mnemonic() const158 const char* LArithmeticD::Mnemonic() const {
159 switch (op()) {
160 case Token::ADD: return "add-d";
161 case Token::SUB: return "sub-d";
162 case Token::MUL: return "mul-d";
163 case Token::DIV: return "div-d";
164 case Token::MOD: return "mod-d";
165 default:
166 UNREACHABLE();
167 return NULL;
168 }
169 }
170
171
Mnemonic() const172 const char* LArithmeticT::Mnemonic() const {
173 switch (op()) {
174 case Token::ADD: return "add-t";
175 case Token::SUB: return "sub-t";
176 case Token::MUL: return "mul-t";
177 case Token::MOD: return "mod-t";
178 case Token::DIV: return "div-t";
179 case Token::BIT_AND: return "bit-and-t";
180 case Token::BIT_OR: return "bit-or-t";
181 case Token::BIT_XOR: return "bit-xor-t";
182 case Token::SHL: return "sal-t";
183 case Token::SAR: return "sar-t";
184 case Token::SHR: return "shr-t";
185 default:
186 UNREACHABLE();
187 return NULL;
188 }
189 }
190
191
PrintDataTo(StringStream * stream)192 void LGoto::PrintDataTo(StringStream* stream) {
193 stream->Add("B%d", block_id());
194 }
195
196
PrintDataTo(StringStream * stream)197 void LBranch::PrintDataTo(StringStream* stream) {
198 stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
199 InputAt(0)->PrintTo(stream);
200 }
201
202
PrintDataTo(StringStream * stream)203 void LCmpIDAndBranch::PrintDataTo(StringStream* stream) {
204 stream->Add("if ");
205 InputAt(0)->PrintTo(stream);
206 stream->Add(" %s ", Token::String(op()));
207 InputAt(1)->PrintTo(stream);
208 stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
209 }
210
211
PrintDataTo(StringStream * stream)212 void LIsNilAndBranch::PrintDataTo(StringStream* stream) {
213 stream->Add("if ");
214 InputAt(0)->PrintTo(stream);
215 stream->Add(kind() == kStrictEquality ? " === " : " == ");
216 stream->Add(nil() == kNullValue ? "null" : "undefined");
217 stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
218 }
219
220
PrintDataTo(StringStream * stream)221 void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
222 stream->Add("if is_object(");
223 InputAt(0)->PrintTo(stream);
224 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
225 }
226
227
PrintDataTo(StringStream * stream)228 void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
229 stream->Add("if is_string(");
230 InputAt(0)->PrintTo(stream);
231 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
232 }
233
234
PrintDataTo(StringStream * stream)235 void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
236 stream->Add("if is_smi(");
237 InputAt(0)->PrintTo(stream);
238 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
239 }
240
241
PrintDataTo(StringStream * stream)242 void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) {
243 stream->Add("if is_undetectable(");
244 InputAt(0)->PrintTo(stream);
245 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
246 }
247
248
PrintDataTo(StringStream * stream)249 void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
250 stream->Add("if string_compare(");
251 InputAt(1)->PrintTo(stream);
252 InputAt(2)->PrintTo(stream);
253 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
254 }
255
256
PrintDataTo(StringStream * stream)257 void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
258 stream->Add("if has_instance_type(");
259 InputAt(0)->PrintTo(stream);
260 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
261 }
262
263
PrintDataTo(StringStream * stream)264 void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
265 stream->Add("if has_cached_array_index(");
266 InputAt(0)->PrintTo(stream);
267 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
268 }
269
270
PrintDataTo(StringStream * stream)271 void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
272 stream->Add("if class_of_test(");
273 InputAt(0)->PrintTo(stream);
274 stream->Add(", \"%o\") then B%d else B%d",
275 *hydrogen()->class_name(),
276 true_block_id(),
277 false_block_id());
278 }
279
280
PrintDataTo(StringStream * stream)281 void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
282 stream->Add("if typeof ");
283 InputAt(0)->PrintTo(stream);
284 stream->Add(" == \"%s\" then B%d else B%d",
285 *hydrogen()->type_literal()->ToCString(),
286 true_block_id(), false_block_id());
287 }
288
289
PrintDataTo(StringStream * stream)290 void LCallConstantFunction::PrintDataTo(StringStream* stream) {
291 stream->Add("#%d / ", arity());
292 }
293
294
PrintDataTo(StringStream * stream)295 void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
296 stream->Add("/%s ", hydrogen()->OpName());
297 InputAt(0)->PrintTo(stream);
298 }
299
300
PrintDataTo(StringStream * stream)301 void LMathPowHalf::PrintDataTo(StringStream* stream) {
302 stream->Add("/pow_half ");
303 InputAt(0)->PrintTo(stream);
304 }
305
306
PrintDataTo(StringStream * stream)307 void LLoadContextSlot::PrintDataTo(StringStream* stream) {
308 InputAt(0)->PrintTo(stream);
309 stream->Add("[%d]", slot_index());
310 }
311
312
PrintDataTo(StringStream * stream)313 void LStoreContextSlot::PrintDataTo(StringStream* stream) {
314 InputAt(0)->PrintTo(stream);
315 stream->Add("[%d] <- ", slot_index());
316 InputAt(1)->PrintTo(stream);
317 }
318
319
PrintDataTo(StringStream * stream)320 void LInvokeFunction::PrintDataTo(StringStream* stream) {
321 stream->Add("= ");
322 InputAt(0)->PrintTo(stream);
323 stream->Add(" ");
324 InputAt(1)->PrintTo(stream);
325 stream->Add(" #%d / ", arity());
326 }
327
328
PrintDataTo(StringStream * stream)329 void LCallKeyed::PrintDataTo(StringStream* stream) {
330 stream->Add("[ecx] #%d / ", arity());
331 }
332
333
PrintDataTo(StringStream * stream)334 void LCallNamed::PrintDataTo(StringStream* stream) {
335 SmartArrayPointer<char> name_string = name()->ToCString();
336 stream->Add("%s #%d / ", *name_string, arity());
337 }
338
339
PrintDataTo(StringStream * stream)340 void LCallGlobal::PrintDataTo(StringStream* stream) {
341 SmartArrayPointer<char> name_string = name()->ToCString();
342 stream->Add("%s #%d / ", *name_string, arity());
343 }
344
345
PrintDataTo(StringStream * stream)346 void LCallKnownGlobal::PrintDataTo(StringStream* stream) {
347 stream->Add("#%d / ", arity());
348 }
349
350
PrintDataTo(StringStream * stream)351 void LCallNew::PrintDataTo(StringStream* stream) {
352 stream->Add("= ");
353 InputAt(0)->PrintTo(stream);
354 stream->Add(" #%d / ", arity());
355 }
356
357
PrintDataTo(StringStream * stream)358 void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
359 arguments()->PrintTo(stream);
360
361 stream->Add(" length ");
362 length()->PrintTo(stream);
363
364 stream->Add(" index ");
365 index()->PrintTo(stream);
366 }
367
368
GetNextSpillIndex(bool is_double)369 int LChunk::GetNextSpillIndex(bool is_double) {
370 // Skip a slot if for a double-width slot.
371 if (is_double) spill_slot_count_++;
372 return spill_slot_count_++;
373 }
374
375
GetNextSpillSlot(bool is_double)376 LOperand* LChunk::GetNextSpillSlot(bool is_double) {
377 int index = GetNextSpillIndex(is_double);
378 if (is_double) {
379 return LDoubleStackSlot::Create(index);
380 } else {
381 return LStackSlot::Create(index);
382 }
383 }
384
385
MarkEmptyBlocks()386 void LChunk::MarkEmptyBlocks() {
387 HPhase phase("L_Mark empty blocks", this);
388 for (int i = 0; i < graph()->blocks()->length(); ++i) {
389 HBasicBlock* block = graph()->blocks()->at(i);
390 int first = block->first_instruction_index();
391 int last = block->last_instruction_index();
392 LInstruction* first_instr = instructions()->at(first);
393 LInstruction* last_instr = instructions()->at(last);
394
395 LLabel* label = LLabel::cast(first_instr);
396 if (last_instr->IsGoto()) {
397 LGoto* goto_instr = LGoto::cast(last_instr);
398 if (label->IsRedundant() &&
399 !label->is_loop_header()) {
400 bool can_eliminate = true;
401 for (int i = first + 1; i < last && can_eliminate; ++i) {
402 LInstruction* cur = instructions()->at(i);
403 if (cur->IsGap()) {
404 LGap* gap = LGap::cast(cur);
405 if (!gap->IsRedundant()) {
406 can_eliminate = false;
407 }
408 } else {
409 can_eliminate = false;
410 }
411 }
412
413 if (can_eliminate) {
414 label->set_replacement(GetLabel(goto_instr->block_id()));
415 }
416 }
417 }
418 }
419 }
420
421
PrintDataTo(StringStream * stream)422 void LStoreNamedField::PrintDataTo(StringStream* stream) {
423 object()->PrintTo(stream);
424 stream->Add(".");
425 stream->Add(*String::cast(*name())->ToCString());
426 stream->Add(" <- ");
427 value()->PrintTo(stream);
428 }
429
430
PrintDataTo(StringStream * stream)431 void LStoreNamedGeneric::PrintDataTo(StringStream* stream) {
432 object()->PrintTo(stream);
433 stream->Add(".");
434 stream->Add(*String::cast(*name())->ToCString());
435 stream->Add(" <- ");
436 value()->PrintTo(stream);
437 }
438
439
PrintDataTo(StringStream * stream)440 void LStoreKeyedFastElement::PrintDataTo(StringStream* stream) {
441 object()->PrintTo(stream);
442 stream->Add("[");
443 key()->PrintTo(stream);
444 stream->Add("] <- ");
445 value()->PrintTo(stream);
446 }
447
448
PrintDataTo(StringStream * stream)449 void LStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) {
450 elements()->PrintTo(stream);
451 stream->Add("[");
452 key()->PrintTo(stream);
453 stream->Add("] <- ");
454 value()->PrintTo(stream);
455 }
456
457
PrintDataTo(StringStream * stream)458 void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
459 object()->PrintTo(stream);
460 stream->Add("[");
461 key()->PrintTo(stream);
462 stream->Add("] <- ");
463 value()->PrintTo(stream);
464 }
465
466
PrintDataTo(StringStream * stream)467 void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
468 object()->PrintTo(stream);
469 stream->Add(" %p -> %p", *original_map(), *transitioned_map());
470 }
471
472
AddInstruction(LInstruction * instr,HBasicBlock * block)473 void LChunk::AddInstruction(LInstruction* instr, HBasicBlock* block) {
474 LInstructionGap* gap = new(graph_->zone()) LInstructionGap(block);
475 int index = -1;
476 if (instr->IsControl()) {
477 instructions_.Add(gap);
478 index = instructions_.length();
479 instructions_.Add(instr);
480 } else {
481 index = instructions_.length();
482 instructions_.Add(instr);
483 instructions_.Add(gap);
484 }
485 if (instr->HasPointerMap()) {
486 pointer_maps_.Add(instr->pointer_map());
487 instr->pointer_map()->set_lithium_position(index);
488 }
489 }
490
491
DefineConstantOperand(HConstant * constant)492 LConstantOperand* LChunk::DefineConstantOperand(HConstant* constant) {
493 return LConstantOperand::Create(constant->id());
494 }
495
496
GetParameterStackSlot(int index) const497 int LChunk::GetParameterStackSlot(int index) const {
498 // The receiver is at index 0, the first parameter at index 1, so we
499 // shift all parameter indexes down by the number of parameters, and
500 // make sure they end up negative so they are distinguishable from
501 // spill slots.
502 int result = index - info()->scope()->num_parameters() - 1;
503 ASSERT(result < 0);
504 return result;
505 }
506
507 // A parameter relative to ebp in the arguments stub.
ParameterAt(int index)508 int LChunk::ParameterAt(int index) {
509 ASSERT(-1 <= index); // -1 is the receiver.
510 return (1 + info()->scope()->num_parameters() - index) *
511 kPointerSize;
512 }
513
514
GetGapAt(int index) const515 LGap* LChunk::GetGapAt(int index) const {
516 return LGap::cast(instructions_[index]);
517 }
518
519
IsGapAt(int index) const520 bool LChunk::IsGapAt(int index) const {
521 return instructions_[index]->IsGap();
522 }
523
524
NearestGapPos(int index) const525 int LChunk::NearestGapPos(int index) const {
526 while (!IsGapAt(index)) index--;
527 return index;
528 }
529
530
AddGapMove(int index,LOperand * from,LOperand * to)531 void LChunk::AddGapMove(int index, LOperand* from, LOperand* to) {
532 GetGapAt(index)->GetOrCreateParallelMove(LGap::START)->AddMove(from, to);
533 }
534
535
LookupLiteral(LConstantOperand * operand) const536 Handle<Object> LChunk::LookupLiteral(LConstantOperand* operand) const {
537 return HConstant::cast(graph_->LookupValue(operand->index()))->handle();
538 }
539
540
LookupLiteralRepresentation(LConstantOperand * operand) const541 Representation LChunk::LookupLiteralRepresentation(
542 LConstantOperand* operand) const {
543 return graph_->LookupValue(operand->index())->representation();
544 }
545
546
Build()547 LChunk* LChunkBuilder::Build() {
548 ASSERT(is_unused());
549 chunk_ = new(zone()) LChunk(info(), graph());
550 HPhase phase("L_Building chunk", chunk_);
551 status_ = BUILDING;
552 const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
553 for (int i = 0; i < blocks->length(); i++) {
554 HBasicBlock* next = NULL;
555 if (i < blocks->length() - 1) next = blocks->at(i + 1);
556 DoBasicBlock(blocks->at(i), next);
557 if (is_aborted()) return NULL;
558 }
559 status_ = DONE;
560 return chunk_;
561 }
562
563
Abort(const char * format,...)564 void LChunkBuilder::Abort(const char* format, ...) {
565 if (FLAG_trace_bailout) {
566 SmartArrayPointer<char> name(
567 info()->shared_info()->DebugName()->ToCString());
568 PrintF("Aborting LChunk building in @\"%s\": ", *name);
569 va_list arguments;
570 va_start(arguments, format);
571 OS::VPrint(format, arguments);
572 va_end(arguments);
573 PrintF("\n");
574 }
575 status_ = ABORTED;
576 }
577
578
ToUnallocated(Register reg)579 LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
580 return new(zone()) LUnallocated(LUnallocated::FIXED_REGISTER,
581 Register::ToAllocationIndex(reg));
582 }
583
584
ToUnallocated(XMMRegister reg)585 LUnallocated* LChunkBuilder::ToUnallocated(XMMRegister reg) {
586 return new(zone()) LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
587 XMMRegister::ToAllocationIndex(reg));
588 }
589
590
UseFixed(HValue * value,Register fixed_register)591 LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
592 return Use(value, ToUnallocated(fixed_register));
593 }
594
595
UseFixedDouble(HValue * value,XMMRegister reg)596 LOperand* LChunkBuilder::UseFixedDouble(HValue* value, XMMRegister reg) {
597 return Use(value, ToUnallocated(reg));
598 }
599
600
UseRegister(HValue * value)601 LOperand* LChunkBuilder::UseRegister(HValue* value) {
602 return Use(value, new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
603 }
604
605
UseRegisterAtStart(HValue * value)606 LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
607 return Use(value,
608 new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
609 LUnallocated::USED_AT_START));
610 }
611
612
UseTempRegister(HValue * value)613 LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
614 return Use(value, new(zone()) LUnallocated(LUnallocated::WRITABLE_REGISTER));
615 }
616
617
Use(HValue * value)618 LOperand* LChunkBuilder::Use(HValue* value) {
619 return Use(value, new(zone()) LUnallocated(LUnallocated::NONE));
620 }
621
622
UseAtStart(HValue * value)623 LOperand* LChunkBuilder::UseAtStart(HValue* value) {
624 return Use(value, new(zone()) LUnallocated(LUnallocated::NONE,
625 LUnallocated::USED_AT_START));
626 }
627
628
UseOrConstant(HValue * value)629 LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
630 return value->IsConstant()
631 ? chunk_->DefineConstantOperand(HConstant::cast(value))
632 : Use(value);
633 }
634
635
UseOrConstantAtStart(HValue * value)636 LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
637 return value->IsConstant()
638 ? chunk_->DefineConstantOperand(HConstant::cast(value))
639 : UseAtStart(value);
640 }
641
642
UseRegisterOrConstant(HValue * value)643 LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
644 return value->IsConstant()
645 ? chunk_->DefineConstantOperand(HConstant::cast(value))
646 : UseRegister(value);
647 }
648
649
UseRegisterOrConstantAtStart(HValue * value)650 LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
651 return value->IsConstant()
652 ? chunk_->DefineConstantOperand(HConstant::cast(value))
653 : UseRegisterAtStart(value);
654 }
655
656
UseAny(HValue * value)657 LOperand* LChunkBuilder::UseAny(HValue* value) {
658 return value->IsConstant()
659 ? chunk_->DefineConstantOperand(HConstant::cast(value))
660 : Use(value, new(zone()) LUnallocated(LUnallocated::ANY));
661 }
662
663
Use(HValue * value,LUnallocated * operand)664 LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
665 if (value->EmitAtUses()) {
666 HInstruction* instr = HInstruction::cast(value);
667 VisitInstruction(instr);
668 }
669 operand->set_virtual_register(value->id());
670 return operand;
671 }
672
673
674 template<int I, int T>
Define(LTemplateInstruction<1,I,T> * instr,LUnallocated * result)675 LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
676 LUnallocated* result) {
677 result->set_virtual_register(current_instruction_->id());
678 instr->set_result(result);
679 return instr;
680 }
681
682
683 template<int I, int T>
DefineAsRegister(LTemplateInstruction<1,I,T> * instr)684 LInstruction* LChunkBuilder::DefineAsRegister(
685 LTemplateInstruction<1, I, T>* instr) {
686 return Define(instr,
687 new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
688 }
689
690
691 template<int I, int T>
DefineAsSpilled(LTemplateInstruction<1,I,T> * instr,int index)692 LInstruction* LChunkBuilder::DefineAsSpilled(
693 LTemplateInstruction<1, I, T>* instr,
694 int index) {
695 return Define(instr,
696 new(zone()) LUnallocated(LUnallocated::FIXED_SLOT, index));
697 }
698
699
700 template<int I, int T>
DefineSameAsFirst(LTemplateInstruction<1,I,T> * instr)701 LInstruction* LChunkBuilder::DefineSameAsFirst(
702 LTemplateInstruction<1, I, T>* instr) {
703 return Define(instr,
704 new(zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
705 }
706
707
708 template<int I, int T>
DefineFixed(LTemplateInstruction<1,I,T> * instr,Register reg)709 LInstruction* LChunkBuilder::DefineFixed(LTemplateInstruction<1, I, T>* instr,
710 Register reg) {
711 return Define(instr, ToUnallocated(reg));
712 }
713
714
715 template<int I, int T>
DefineFixedDouble(LTemplateInstruction<1,I,T> * instr,XMMRegister reg)716 LInstruction* LChunkBuilder::DefineFixedDouble(
717 LTemplateInstruction<1, I, T>* instr,
718 XMMRegister reg) {
719 return Define(instr, ToUnallocated(reg));
720 }
721
722
AssignEnvironment(LInstruction * instr)723 LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
724 HEnvironment* hydrogen_env = current_block_->last_environment();
725 int argument_index_accumulator = 0;
726 instr->set_environment(CreateEnvironment(hydrogen_env,
727 &argument_index_accumulator));
728 return instr;
729 }
730
731
SetInstructionPendingDeoptimizationEnvironment(LInstruction * instr,int ast_id)732 LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
733 LInstruction* instr, int ast_id) {
734 ASSERT(instruction_pending_deoptimization_environment_ == NULL);
735 ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
736 instruction_pending_deoptimization_environment_ = instr;
737 pending_deoptimization_ast_id_ = ast_id;
738 return instr;
739 }
740
741
ClearInstructionPendingDeoptimizationEnvironment()742 void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
743 instruction_pending_deoptimization_environment_ = NULL;
744 pending_deoptimization_ast_id_ = AstNode::kNoNumber;
745 }
746
747
MarkAsCall(LInstruction * instr,HInstruction * hinstr,CanDeoptimize can_deoptimize)748 LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
749 HInstruction* hinstr,
750 CanDeoptimize can_deoptimize) {
751 #ifdef DEBUG
752 instr->VerifyCall();
753 #endif
754 instr->MarkAsCall();
755 instr = AssignPointerMap(instr);
756
757 if (hinstr->HasObservableSideEffects()) {
758 ASSERT(hinstr->next()->IsSimulate());
759 HSimulate* sim = HSimulate::cast(hinstr->next());
760 instr = SetInstructionPendingDeoptimizationEnvironment(
761 instr, sim->ast_id());
762 }
763
764 // If instruction does not have side-effects lazy deoptimization
765 // after the call will try to deoptimize to the point before the call.
766 // Thus we still need to attach environment to this call even if
767 // call sequence can not deoptimize eagerly.
768 bool needs_environment =
769 (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) ||
770 !hinstr->HasObservableSideEffects();
771 if (needs_environment && !instr->HasEnvironment()) {
772 instr = AssignEnvironment(instr);
773 }
774
775 return instr;
776 }
777
778
MarkAsSaveDoubles(LInstruction * instr)779 LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) {
780 instr->MarkAsSaveDoubles();
781 return instr;
782 }
783
784
AssignPointerMap(LInstruction * instr)785 LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
786 ASSERT(!instr->HasPointerMap());
787 instr->set_pointer_map(new(zone()) LPointerMap(position_));
788 return instr;
789 }
790
791
TempRegister()792 LUnallocated* LChunkBuilder::TempRegister() {
793 LUnallocated* operand =
794 new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
795 operand->set_virtual_register(allocator_->GetVirtualRegister());
796 if (!allocator_->AllocationOk()) {
797 Abort("Not enough virtual registers (temps).");
798 }
799 return operand;
800 }
801
802
FixedTemp(Register reg)803 LOperand* LChunkBuilder::FixedTemp(Register reg) {
804 LUnallocated* operand = ToUnallocated(reg);
805 ASSERT(operand->HasFixedPolicy());
806 return operand;
807 }
808
809
FixedTemp(XMMRegister reg)810 LOperand* LChunkBuilder::FixedTemp(XMMRegister reg) {
811 LUnallocated* operand = ToUnallocated(reg);
812 ASSERT(operand->HasFixedPolicy());
813 return operand;
814 }
815
816
DoBlockEntry(HBlockEntry * instr)817 LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
818 return new(zone()) LLabel(instr->block());
819 }
820
821
DoSoftDeoptimize(HSoftDeoptimize * instr)822 LInstruction* LChunkBuilder::DoSoftDeoptimize(HSoftDeoptimize* instr) {
823 return AssignEnvironment(new(zone()) LDeoptimize);
824 }
825
826
DoDeoptimize(HDeoptimize * instr)827 LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
828 return AssignEnvironment(new(zone()) LDeoptimize);
829 }
830
831
DoShift(Token::Value op,HBitwiseBinaryOperation * instr)832 LInstruction* LChunkBuilder::DoShift(Token::Value op,
833 HBitwiseBinaryOperation* instr) {
834 if (instr->representation().IsTagged()) {
835 ASSERT(instr->left()->representation().IsTagged());
836 ASSERT(instr->right()->representation().IsTagged());
837
838 LOperand* context = UseFixed(instr->context(), esi);
839 LOperand* left = UseFixed(instr->left(), edx);
840 LOperand* right = UseFixed(instr->right(), eax);
841 LArithmeticT* result = new(zone()) LArithmeticT(op, context, left, right);
842 return MarkAsCall(DefineFixed(result, eax), instr);
843 }
844
845 ASSERT(instr->representation().IsInteger32());
846 ASSERT(instr->left()->representation().IsInteger32());
847 ASSERT(instr->right()->representation().IsInteger32());
848 LOperand* left = UseRegisterAtStart(instr->left());
849
850 HValue* right_value = instr->right();
851 LOperand* right = NULL;
852 int constant_value = 0;
853 if (right_value->IsConstant()) {
854 HConstant* constant = HConstant::cast(right_value);
855 right = chunk_->DefineConstantOperand(constant);
856 constant_value = constant->Integer32Value() & 0x1f;
857 } else {
858 right = UseFixed(right_value, ecx);
859 }
860
861 // Shift operations can only deoptimize if we do a logical shift by 0 and
862 // the result cannot be truncated to int32.
863 bool may_deopt = (op == Token::SHR && constant_value == 0);
864 bool does_deopt = false;
865 if (may_deopt) {
866 for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
867 if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) {
868 does_deopt = true;
869 break;
870 }
871 }
872 }
873
874 LInstruction* result =
875 DefineSameAsFirst(new(zone()) LShiftI(op, left, right, does_deopt));
876 return does_deopt ? AssignEnvironment(result) : result;
877 }
878
879
DoArithmeticD(Token::Value op,HArithmeticBinaryOperation * instr)880 LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
881 HArithmeticBinaryOperation* instr) {
882 ASSERT(instr->representation().IsDouble());
883 ASSERT(instr->left()->representation().IsDouble());
884 ASSERT(instr->right()->representation().IsDouble());
885 ASSERT(op != Token::MOD);
886 LOperand* left = UseRegisterAtStart(instr->left());
887 LOperand* right = UseRegisterAtStart(instr->right());
888 LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
889 return DefineSameAsFirst(result);
890 }
891
892
DoArithmeticT(Token::Value op,HArithmeticBinaryOperation * instr)893 LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
894 HArithmeticBinaryOperation* instr) {
895 ASSERT(op == Token::ADD ||
896 op == Token::DIV ||
897 op == Token::MOD ||
898 op == Token::MUL ||
899 op == Token::SUB);
900 HValue* left = instr->left();
901 HValue* right = instr->right();
902 ASSERT(left->representation().IsTagged());
903 ASSERT(right->representation().IsTagged());
904 LOperand* context = UseFixed(instr->context(), esi);
905 LOperand* left_operand = UseFixed(left, edx);
906 LOperand* right_operand = UseFixed(right, eax);
907 LArithmeticT* result =
908 new(zone()) LArithmeticT(op, context, left_operand, right_operand);
909 return MarkAsCall(DefineFixed(result, eax), instr);
910 }
911
912
DoBasicBlock(HBasicBlock * block,HBasicBlock * next_block)913 void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
914 ASSERT(is_building());
915 current_block_ = block;
916 next_block_ = next_block;
917 if (block->IsStartBlock()) {
918 block->UpdateEnvironment(graph_->start_environment());
919 argument_count_ = 0;
920 } else if (block->predecessors()->length() == 1) {
921 // We have a single predecessor => copy environment and outgoing
922 // argument count from the predecessor.
923 ASSERT(block->phis()->length() == 0);
924 HBasicBlock* pred = block->predecessors()->at(0);
925 HEnvironment* last_environment = pred->last_environment();
926 ASSERT(last_environment != NULL);
927 // Only copy the environment, if it is later used again.
928 if (pred->end()->SecondSuccessor() == NULL) {
929 ASSERT(pred->end()->FirstSuccessor() == block);
930 } else {
931 if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
932 pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
933 last_environment = last_environment->Copy();
934 }
935 }
936 block->UpdateEnvironment(last_environment);
937 ASSERT(pred->argument_count() >= 0);
938 argument_count_ = pred->argument_count();
939 } else {
940 // We are at a state join => process phis.
941 HBasicBlock* pred = block->predecessors()->at(0);
942 // No need to copy the environment, it cannot be used later.
943 HEnvironment* last_environment = pred->last_environment();
944 for (int i = 0; i < block->phis()->length(); ++i) {
945 HPhi* phi = block->phis()->at(i);
946 last_environment->SetValueAt(phi->merged_index(), phi);
947 }
948 for (int i = 0; i < block->deleted_phis()->length(); ++i) {
949 last_environment->SetValueAt(block->deleted_phis()->at(i),
950 graph_->GetConstantUndefined());
951 }
952 block->UpdateEnvironment(last_environment);
953 // Pick up the outgoing argument count of one of the predecessors.
954 argument_count_ = pred->argument_count();
955 }
956 HInstruction* current = block->first();
957 int start = chunk_->instructions()->length();
958 while (current != NULL && !is_aborted()) {
959 // Code for constants in registers is generated lazily.
960 if (!current->EmitAtUses()) {
961 VisitInstruction(current);
962 }
963 current = current->next();
964 }
965 int end = chunk_->instructions()->length() - 1;
966 if (end >= start) {
967 block->set_first_instruction_index(start);
968 block->set_last_instruction_index(end);
969 }
970 block->set_argument_count(argument_count_);
971 next_block_ = NULL;
972 current_block_ = NULL;
973 }
974
975
VisitInstruction(HInstruction * current)976 void LChunkBuilder::VisitInstruction(HInstruction* current) {
977 HInstruction* old_current = current_instruction_;
978 current_instruction_ = current;
979 if (current->has_position()) position_ = current->position();
980 LInstruction* instr = current->CompileToLithium(this);
981
982 if (instr != NULL) {
983 if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
984 instr = AssignPointerMap(instr);
985 }
986 if (FLAG_stress_environments && !instr->HasEnvironment()) {
987 instr = AssignEnvironment(instr);
988 }
989 instr->set_hydrogen_value(current);
990 chunk_->AddInstruction(instr, current_block_);
991 }
992 current_instruction_ = old_current;
993 }
994
995
CreateEnvironment(HEnvironment * hydrogen_env,int * argument_index_accumulator)996 LEnvironment* LChunkBuilder::CreateEnvironment(
997 HEnvironment* hydrogen_env,
998 int* argument_index_accumulator) {
999 if (hydrogen_env == NULL) return NULL;
1000
1001 LEnvironment* outer =
1002 CreateEnvironment(hydrogen_env->outer(), argument_index_accumulator);
1003 int ast_id = hydrogen_env->ast_id();
1004 ASSERT(ast_id != AstNode::kNoNumber ||
1005 hydrogen_env->frame_type() != JS_FUNCTION);
1006 int value_count = hydrogen_env->length();
1007 LEnvironment* result =
1008 new(zone()) LEnvironment(hydrogen_env->closure(),
1009 hydrogen_env->frame_type(),
1010 ast_id,
1011 hydrogen_env->parameter_count(),
1012 argument_count_,
1013 value_count,
1014 outer);
1015 int argument_index = *argument_index_accumulator;
1016 for (int i = 0; i < value_count; ++i) {
1017 if (hydrogen_env->is_special_index(i)) continue;
1018
1019 HValue* value = hydrogen_env->values()->at(i);
1020 LOperand* op = NULL;
1021 if (value->IsArgumentsObject()) {
1022 op = NULL;
1023 } else if (value->IsPushArgument()) {
1024 op = new(zone()) LArgument(argument_index++);
1025 } else {
1026 op = UseAny(value);
1027 }
1028 result->AddValue(op, value->representation());
1029 }
1030
1031 if (hydrogen_env->frame_type() == JS_FUNCTION) {
1032 *argument_index_accumulator = argument_index;
1033 }
1034
1035 return result;
1036 }
1037
1038
DoGoto(HGoto * instr)1039 LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
1040 return new(zone()) LGoto(instr->FirstSuccessor()->block_id());
1041 }
1042
1043
DoBranch(HBranch * instr)1044 LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
1045 HValue* value = instr->value();
1046 if (value->EmitAtUses()) {
1047 ASSERT(value->IsConstant());
1048 ASSERT(!value->representation().IsDouble());
1049 HBasicBlock* successor = HConstant::cast(value)->ToBoolean()
1050 ? instr->FirstSuccessor()
1051 : instr->SecondSuccessor();
1052 return new(zone()) LGoto(successor->block_id());
1053 }
1054
1055 // Untagged integers or doubles, smis and booleans don't require a
1056 // deoptimization environment nor a temp register.
1057 Representation rep = value->representation();
1058 HType type = value->type();
1059 if (!rep.IsTagged() || type.IsSmi() || type.IsBoolean()) {
1060 return new(zone()) LBranch(UseRegister(value), NULL);
1061 }
1062
1063 ToBooleanStub::Types expected = instr->expected_input_types();
1064 // We need a temporary register when we have to access the map *or* we have
1065 // no type info yet, in which case we handle all cases (including the ones
1066 // involving maps).
1067 bool needs_temp = expected.NeedsMap() || expected.IsEmpty();
1068 LOperand* temp = needs_temp ? TempRegister() : NULL;
1069 return AssignEnvironment(new(zone()) LBranch(UseRegister(value), temp));
1070 }
1071
1072
DoCompareMap(HCompareMap * instr)1073 LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
1074 ASSERT(instr->value()->representation().IsTagged());
1075 LOperand* value = UseRegisterAtStart(instr->value());
1076 return new(zone()) LCmpMapAndBranch(value);
1077 }
1078
1079
DoArgumentsLength(HArgumentsLength * length)1080 LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) {
1081 return DefineAsRegister(new(zone()) LArgumentsLength(Use(length->value())));
1082 }
1083
1084
DoArgumentsElements(HArgumentsElements * elems)1085 LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
1086 return DefineAsRegister(new(zone()) LArgumentsElements);
1087 }
1088
1089
DoInstanceOf(HInstanceOf * instr)1090 LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
1091 LOperand* left = UseFixed(instr->left(), InstanceofStub::left());
1092 LOperand* right = UseFixed(instr->right(), InstanceofStub::right());
1093 LOperand* context = UseFixed(instr->context(), esi);
1094 LInstanceOf* result = new(zone()) LInstanceOf(context, left, right);
1095 return MarkAsCall(DefineFixed(result, eax), instr);
1096 }
1097
1098
DoInstanceOfKnownGlobal(HInstanceOfKnownGlobal * instr)1099 LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
1100 HInstanceOfKnownGlobal* instr) {
1101 LInstanceOfKnownGlobal* result =
1102 new(zone()) LInstanceOfKnownGlobal(
1103 UseFixed(instr->context(), esi),
1104 UseFixed(instr->left(), InstanceofStub::left()),
1105 FixedTemp(edi));
1106 return MarkAsCall(DefineFixed(result, eax), instr);
1107 }
1108
1109
DoWrapReceiver(HWrapReceiver * instr)1110 LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
1111 LOperand* receiver = UseRegister(instr->receiver());
1112 LOperand* function = UseRegisterAtStart(instr->function());
1113 LOperand* temp = TempRegister();
1114 LWrapReceiver* result =
1115 new(zone()) LWrapReceiver(receiver, function, temp);
1116 return AssignEnvironment(DefineSameAsFirst(result));
1117 }
1118
1119
DoApplyArguments(HApplyArguments * instr)1120 LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
1121 LOperand* function = UseFixed(instr->function(), edi);
1122 LOperand* receiver = UseFixed(instr->receiver(), eax);
1123 LOperand* length = UseFixed(instr->length(), ebx);
1124 LOperand* elements = UseFixed(instr->elements(), ecx);
1125 LApplyArguments* result = new(zone()) LApplyArguments(function,
1126 receiver,
1127 length,
1128 elements);
1129 return MarkAsCall(DefineFixed(result, eax), instr, CAN_DEOPTIMIZE_EAGERLY);
1130 }
1131
1132
DoPushArgument(HPushArgument * instr)1133 LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
1134 ++argument_count_;
1135 LOperand* argument = UseAny(instr->argument());
1136 return new(zone()) LPushArgument(argument);
1137 }
1138
1139
DoThisFunction(HThisFunction * instr)1140 LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
1141 return instr->HasNoUses()
1142 ? NULL
1143 : DefineAsRegister(new(zone()) LThisFunction);
1144 }
1145
1146
DoContext(HContext * instr)1147 LInstruction* LChunkBuilder::DoContext(HContext* instr) {
1148 return instr->HasNoUses() ? NULL : DefineAsRegister(new(zone()) LContext);
1149 }
1150
1151
DoOuterContext(HOuterContext * instr)1152 LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
1153 LOperand* context = UseRegisterAtStart(instr->value());
1154 return DefineAsRegister(new(zone()) LOuterContext(context));
1155 }
1156
1157
DoDeclareGlobals(HDeclareGlobals * instr)1158 LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
1159 LOperand* context = UseFixed(instr->context(), esi);
1160 return MarkAsCall(new(zone()) LDeclareGlobals(context), instr);
1161 }
1162
1163
DoGlobalObject(HGlobalObject * instr)1164 LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
1165 LOperand* context = UseRegisterAtStart(instr->value());
1166 return DefineAsRegister(new(zone()) LGlobalObject(context));
1167 }
1168
1169
DoGlobalReceiver(HGlobalReceiver * instr)1170 LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
1171 LOperand* global_object = UseRegisterAtStart(instr->value());
1172 return DefineAsRegister(new(zone()) LGlobalReceiver(global_object));
1173 }
1174
1175
DoCallConstantFunction(HCallConstantFunction * instr)1176 LInstruction* LChunkBuilder::DoCallConstantFunction(
1177 HCallConstantFunction* instr) {
1178 argument_count_ -= instr->argument_count();
1179 return MarkAsCall(DefineFixed(new(zone()) LCallConstantFunction, eax), instr);
1180 }
1181
1182
DoInvokeFunction(HInvokeFunction * instr)1183 LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
1184 LOperand* context = UseFixed(instr->context(), esi);
1185 LOperand* function = UseFixed(instr->function(), edi);
1186 argument_count_ -= instr->argument_count();
1187 LInvokeFunction* result = new(zone()) LInvokeFunction(context, function);
1188 return MarkAsCall(DefineFixed(result, eax), instr, CANNOT_DEOPTIMIZE_EAGERLY);
1189 }
1190
1191
DoUnaryMathOperation(HUnaryMathOperation * instr)1192 LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
1193 BuiltinFunctionId op = instr->op();
1194 if (op == kMathLog) {
1195 ASSERT(instr->representation().IsDouble());
1196 ASSERT(instr->value()->representation().IsDouble());
1197 LOperand* context = UseAny(instr->context()); // Not actually used.
1198 LOperand* input = UseRegisterAtStart(instr->value());
1199 LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(context,
1200 input);
1201 return DefineSameAsFirst(result);
1202 } else if (op == kMathSin || op == kMathCos || op == kMathTan) {
1203 LOperand* context = UseFixed(instr->context(), esi);
1204 LOperand* input = UseFixedDouble(instr->value(), xmm1);
1205 LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(context,
1206 input);
1207 return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
1208 } else {
1209 LOperand* input = UseRegisterAtStart(instr->value());
1210 LOperand* context = UseAny(instr->context()); // Deferred use by MathAbs.
1211 if (op == kMathPowHalf) {
1212 LOperand* temp = TempRegister();
1213 LMathPowHalf* result = new(zone()) LMathPowHalf(context, input, temp);
1214 return DefineSameAsFirst(result);
1215 }
1216 LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(context,
1217 input);
1218 switch (op) {
1219 case kMathAbs:
1220 return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1221 case kMathFloor:
1222 return AssignEnvironment(DefineAsRegister(result));
1223 case kMathRound:
1224 return AssignEnvironment(DefineAsRegister(result));
1225 case kMathSqrt:
1226 return DefineSameAsFirst(result);
1227 default:
1228 UNREACHABLE();
1229 return NULL;
1230 }
1231 }
1232 }
1233
1234
DoCallKeyed(HCallKeyed * instr)1235 LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
1236 ASSERT(instr->key()->representation().IsTagged());
1237 LOperand* context = UseFixed(instr->context(), esi);
1238 LOperand* key = UseFixed(instr->key(), ecx);
1239 argument_count_ -= instr->argument_count();
1240 LCallKeyed* result = new(zone()) LCallKeyed(context, key);
1241 return MarkAsCall(DefineFixed(result, eax), instr);
1242 }
1243
1244
DoCallNamed(HCallNamed * instr)1245 LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
1246 LOperand* context = UseFixed(instr->context(), esi);
1247 argument_count_ -= instr->argument_count();
1248 LCallNamed* result = new(zone()) LCallNamed(context);
1249 return MarkAsCall(DefineFixed(result, eax), instr);
1250 }
1251
1252
DoCallGlobal(HCallGlobal * instr)1253 LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
1254 LOperand* context = UseFixed(instr->context(), esi);
1255 argument_count_ -= instr->argument_count();
1256 LCallGlobal* result = new(zone()) LCallGlobal(context);
1257 return MarkAsCall(DefineFixed(result, eax), instr);
1258 }
1259
1260
DoCallKnownGlobal(HCallKnownGlobal * instr)1261 LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
1262 argument_count_ -= instr->argument_count();
1263 return MarkAsCall(DefineFixed(new(zone()) LCallKnownGlobal, eax), instr);
1264 }
1265
1266
DoCallNew(HCallNew * instr)1267 LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
1268 LOperand* context = UseFixed(instr->context(), esi);
1269 LOperand* constructor = UseFixed(instr->constructor(), edi);
1270 argument_count_ -= instr->argument_count();
1271 LCallNew* result = new(zone()) LCallNew(context, constructor);
1272 return MarkAsCall(DefineFixed(result, eax), instr);
1273 }
1274
1275
DoCallFunction(HCallFunction * instr)1276 LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
1277 LOperand* context = UseFixed(instr->context(), esi);
1278 LOperand* function = UseFixed(instr->function(), edi);
1279 argument_count_ -= instr->argument_count();
1280 LCallFunction* result = new(zone()) LCallFunction(context, function);
1281 return MarkAsCall(DefineFixed(result, eax), instr);
1282 }
1283
1284
DoCallRuntime(HCallRuntime * instr)1285 LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1286 argument_count_ -= instr->argument_count();
1287 LOperand* context = UseFixed(instr->context(), esi);
1288 return MarkAsCall(DefineFixed(new(zone()) LCallRuntime(context), eax), instr);
1289 }
1290
1291
DoShr(HShr * instr)1292 LInstruction* LChunkBuilder::DoShr(HShr* instr) {
1293 return DoShift(Token::SHR, instr);
1294 }
1295
1296
DoSar(HSar * instr)1297 LInstruction* LChunkBuilder::DoSar(HSar* instr) {
1298 return DoShift(Token::SAR, instr);
1299 }
1300
1301
DoShl(HShl * instr)1302 LInstruction* LChunkBuilder::DoShl(HShl* instr) {
1303 return DoShift(Token::SHL, instr);
1304 }
1305
1306
DoBitwise(HBitwise * instr)1307 LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
1308 if (instr->representation().IsInteger32()) {
1309 ASSERT(instr->left()->representation().IsInteger32());
1310 ASSERT(instr->right()->representation().IsInteger32());
1311
1312 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1313 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
1314 return DefineSameAsFirst(new(zone()) LBitI(left, right));
1315 } else {
1316 ASSERT(instr->representation().IsTagged());
1317 ASSERT(instr->left()->representation().IsTagged());
1318 ASSERT(instr->right()->representation().IsTagged());
1319
1320 LOperand* context = UseFixed(instr->context(), esi);
1321 LOperand* left = UseFixed(instr->left(), edx);
1322 LOperand* right = UseFixed(instr->right(), eax);
1323 LArithmeticT* result =
1324 new(zone()) LArithmeticT(instr->op(), context, left, right);
1325 return MarkAsCall(DefineFixed(result, eax), instr);
1326 }
1327 }
1328
1329
DoBitNot(HBitNot * instr)1330 LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
1331 ASSERT(instr->value()->representation().IsInteger32());
1332 ASSERT(instr->representation().IsInteger32());
1333 LOperand* input = UseRegisterAtStart(instr->value());
1334 LBitNotI* result = new(zone()) LBitNotI(input);
1335 return DefineSameAsFirst(result);
1336 }
1337
1338
DoDiv(HDiv * instr)1339 LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1340 if (instr->representation().IsDouble()) {
1341 return DoArithmeticD(Token::DIV, instr);
1342 } else if (instr->representation().IsInteger32()) {
1343 // The temporary operand is necessary to ensure that right is not allocated
1344 // into edx.
1345 LOperand* temp = FixedTemp(edx);
1346 LOperand* dividend = UseFixed(instr->left(), eax);
1347 LOperand* divisor = UseRegister(instr->right());
1348 LDivI* result = new(zone()) LDivI(dividend, divisor, temp);
1349 return AssignEnvironment(DefineFixed(result, eax));
1350 } else {
1351 ASSERT(instr->representation().IsTagged());
1352 return DoArithmeticT(Token::DIV, instr);
1353 }
1354 }
1355
1356
DoMod(HMod * instr)1357 LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1358 if (instr->representation().IsInteger32()) {
1359 ASSERT(instr->left()->representation().IsInteger32());
1360 ASSERT(instr->right()->representation().IsInteger32());
1361
1362 LInstruction* result;
1363 if (instr->HasPowerOf2Divisor()) {
1364 ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
1365 LOperand* value = UseRegisterAtStart(instr->left());
1366 LModI* mod =
1367 new(zone()) LModI(value, UseOrConstant(instr->right()), NULL);
1368 result = DefineSameAsFirst(mod);
1369 } else {
1370 // The temporary operand is necessary to ensure that right is
1371 // not allocated into edx.
1372 LOperand* temp = FixedTemp(edx);
1373 LOperand* value = UseFixed(instr->left(), eax);
1374 LOperand* divisor = UseRegister(instr->right());
1375 LModI* mod = new(zone()) LModI(value, divisor, temp);
1376 result = DefineFixed(mod, edx);
1377 }
1378
1379 return (instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
1380 instr->CheckFlag(HValue::kCanBeDivByZero))
1381 ? AssignEnvironment(result)
1382 : result;
1383 } else if (instr->representation().IsTagged()) {
1384 return DoArithmeticT(Token::MOD, instr);
1385 } else {
1386 ASSERT(instr->representation().IsDouble());
1387 // We call a C function for double modulo. It can't trigger a GC.
1388 // We need to use fixed result register for the call.
1389 // TODO(fschneider): Allow any register as input registers.
1390 LOperand* left = UseFixedDouble(instr->left(), xmm2);
1391 LOperand* right = UseFixedDouble(instr->right(), xmm1);
1392 LArithmeticD* result = new(zone()) LArithmeticD(Token::MOD, left, right);
1393 return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
1394 }
1395 }
1396
1397
DoMul(HMul * instr)1398 LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1399 if (instr->representation().IsInteger32()) {
1400 ASSERT(instr->left()->representation().IsInteger32());
1401 ASSERT(instr->right()->representation().IsInteger32());
1402 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1403 LOperand* right = UseOrConstant(instr->MostConstantOperand());
1404 LOperand* temp = NULL;
1405 if (instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1406 temp = TempRegister();
1407 }
1408 LMulI* mul = new(zone()) LMulI(left, right, temp);
1409 if (instr->CheckFlag(HValue::kCanOverflow) ||
1410 instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1411 AssignEnvironment(mul);
1412 }
1413 return DefineSameAsFirst(mul);
1414 } else if (instr->representation().IsDouble()) {
1415 return DoArithmeticD(Token::MUL, instr);
1416 } else {
1417 ASSERT(instr->representation().IsTagged());
1418 return DoArithmeticT(Token::MUL, instr);
1419 }
1420 }
1421
1422
DoSub(HSub * instr)1423 LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1424 if (instr->representation().IsInteger32()) {
1425 ASSERT(instr->left()->representation().IsInteger32());
1426 ASSERT(instr->right()->representation().IsInteger32());
1427 LOperand* left = UseRegisterAtStart(instr->left());
1428 LOperand* right = UseOrConstantAtStart(instr->right());
1429 LSubI* sub = new(zone()) LSubI(left, right);
1430 LInstruction* result = DefineSameAsFirst(sub);
1431 if (instr->CheckFlag(HValue::kCanOverflow)) {
1432 result = AssignEnvironment(result);
1433 }
1434 return result;
1435 } else if (instr->representation().IsDouble()) {
1436 return DoArithmeticD(Token::SUB, instr);
1437 } else {
1438 ASSERT(instr->representation().IsTagged());
1439 return DoArithmeticT(Token::SUB, instr);
1440 }
1441 }
1442
1443
DoAdd(HAdd * instr)1444 LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1445 if (instr->representation().IsInteger32()) {
1446 ASSERT(instr->left()->representation().IsInteger32());
1447 ASSERT(instr->right()->representation().IsInteger32());
1448 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1449 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
1450 LAddI* add = new(zone()) LAddI(left, right);
1451 LInstruction* result = DefineSameAsFirst(add);
1452 if (instr->CheckFlag(HValue::kCanOverflow)) {
1453 result = AssignEnvironment(result);
1454 }
1455 return result;
1456 } else if (instr->representation().IsDouble()) {
1457 return DoArithmeticD(Token::ADD, instr);
1458 } else {
1459 ASSERT(instr->representation().IsTagged());
1460 return DoArithmeticT(Token::ADD, instr);
1461 }
1462 }
1463
1464
DoPower(HPower * instr)1465 LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1466 ASSERT(instr->representation().IsDouble());
1467 // We call a C function for double power. It can't trigger a GC.
1468 // We need to use fixed result register for the call.
1469 Representation exponent_type = instr->right()->representation();
1470 ASSERT(instr->left()->representation().IsDouble());
1471 LOperand* left = UseFixedDouble(instr->left(), xmm2);
1472 LOperand* right = exponent_type.IsDouble() ?
1473 UseFixedDouble(instr->right(), xmm1) :
1474 UseFixed(instr->right(), eax);
1475 LPower* result = new(zone()) LPower(left, right);
1476 return MarkAsCall(DefineFixedDouble(result, xmm3), instr,
1477 CAN_DEOPTIMIZE_EAGERLY);
1478 }
1479
1480
DoRandom(HRandom * instr)1481 LInstruction* LChunkBuilder::DoRandom(HRandom* instr) {
1482 ASSERT(instr->representation().IsDouble());
1483 ASSERT(instr->global_object()->representation().IsTagged());
1484 LOperand* global_object = UseFixed(instr->global_object(), eax);
1485 LRandom* result = new(zone()) LRandom(global_object);
1486 return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
1487 }
1488
1489
DoCompareGeneric(HCompareGeneric * instr)1490 LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
1491 ASSERT(instr->left()->representation().IsTagged());
1492 ASSERT(instr->right()->representation().IsTagged());
1493 LOperand* context = UseFixed(instr->context(), esi);
1494 LOperand* left = UseFixed(instr->left(), edx);
1495 LOperand* right = UseFixed(instr->right(), eax);
1496 LCmpT* result = new(zone()) LCmpT(context, left, right);
1497 return MarkAsCall(DefineFixed(result, eax), instr);
1498 }
1499
1500
DoCompareIDAndBranch(HCompareIDAndBranch * instr)1501 LInstruction* LChunkBuilder::DoCompareIDAndBranch(
1502 HCompareIDAndBranch* instr) {
1503 Representation r = instr->GetInputRepresentation();
1504 if (r.IsInteger32()) {
1505 ASSERT(instr->left()->representation().IsInteger32());
1506 ASSERT(instr->right()->representation().IsInteger32());
1507 LOperand* left = UseRegisterOrConstantAtStart(instr->left());
1508 LOperand* right = UseOrConstantAtStart(instr->right());
1509 return new(zone()) LCmpIDAndBranch(left, right);
1510 } else {
1511 ASSERT(r.IsDouble());
1512 ASSERT(instr->left()->representation().IsDouble());
1513 ASSERT(instr->right()->representation().IsDouble());
1514 LOperand* left;
1515 LOperand* right;
1516 if (instr->left()->IsConstant() && instr->right()->IsConstant()) {
1517 left = UseRegisterOrConstantAtStart(instr->left());
1518 right = UseRegisterOrConstantAtStart(instr->right());
1519 } else {
1520 left = UseRegisterAtStart(instr->left());
1521 right = UseRegisterAtStart(instr->right());
1522 }
1523 return new(zone()) LCmpIDAndBranch(left, right);
1524 }
1525 }
1526
1527
DoCompareObjectEqAndBranch(HCompareObjectEqAndBranch * instr)1528 LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
1529 HCompareObjectEqAndBranch* instr) {
1530 LOperand* left = UseRegisterAtStart(instr->left());
1531 LOperand* right = UseAtStart(instr->right());
1532 return new(zone()) LCmpObjectEqAndBranch(left, right);
1533 }
1534
1535
DoCompareConstantEqAndBranch(HCompareConstantEqAndBranch * instr)1536 LInstruction* LChunkBuilder::DoCompareConstantEqAndBranch(
1537 HCompareConstantEqAndBranch* instr) {
1538 return new(zone()) LCmpConstantEqAndBranch(
1539 UseRegisterAtStart(instr->value()));
1540 }
1541
1542
DoIsNilAndBranch(HIsNilAndBranch * instr)1543 LInstruction* LChunkBuilder::DoIsNilAndBranch(HIsNilAndBranch* instr) {
1544 // We only need a temp register for non-strict compare.
1545 LOperand* temp = instr->kind() == kStrictEquality ? NULL : TempRegister();
1546 return new(zone()) LIsNilAndBranch(UseRegisterAtStart(instr->value()), temp);
1547 }
1548
1549
DoIsObjectAndBranch(HIsObjectAndBranch * instr)1550 LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
1551 ASSERT(instr->value()->representation().IsTagged());
1552 LOperand* temp = TempRegister();
1553 return new(zone()) LIsObjectAndBranch(UseRegister(instr->value()), temp);
1554 }
1555
1556
DoIsStringAndBranch(HIsStringAndBranch * instr)1557 LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
1558 ASSERT(instr->value()->representation().IsTagged());
1559 LOperand* temp = TempRegister();
1560 return new LIsStringAndBranch(UseRegister(instr->value()), temp);
1561 }
1562
1563
DoIsSmiAndBranch(HIsSmiAndBranch * instr)1564 LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
1565 ASSERT(instr->value()->representation().IsTagged());
1566 return new(zone()) LIsSmiAndBranch(Use(instr->value()));
1567 }
1568
1569
DoIsUndetectableAndBranch(HIsUndetectableAndBranch * instr)1570 LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
1571 HIsUndetectableAndBranch* instr) {
1572 ASSERT(instr ->value()->representation().IsTagged());
1573 return new(zone()) LIsUndetectableAndBranch(
1574 UseRegisterAtStart(instr->value()), TempRegister());
1575 }
1576
1577
DoStringCompareAndBranch(HStringCompareAndBranch * instr)1578 LInstruction* LChunkBuilder::DoStringCompareAndBranch(
1579 HStringCompareAndBranch* instr) {
1580 ASSERT(instr->left()->representation().IsTagged());
1581 ASSERT(instr->right()->representation().IsTagged());
1582 LOperand* context = UseFixed(instr->context(), esi);
1583 LOperand* left = UseFixed(instr->left(), edx);
1584 LOperand* right = UseFixed(instr->right(), eax);
1585
1586 LStringCompareAndBranch* result = new
1587 LStringCompareAndBranch(context, left, right);
1588
1589 return MarkAsCall(result, instr);
1590 }
1591
1592
DoHasInstanceTypeAndBranch(HHasInstanceTypeAndBranch * instr)1593 LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
1594 HHasInstanceTypeAndBranch* instr) {
1595 ASSERT(instr->value()->representation().IsTagged());
1596 return new(zone()) LHasInstanceTypeAndBranch(
1597 UseRegisterAtStart(instr->value()),
1598 TempRegister());
1599 }
1600
1601
DoGetCachedArrayIndex(HGetCachedArrayIndex * instr)1602 LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
1603 HGetCachedArrayIndex* instr) {
1604 ASSERT(instr->value()->representation().IsTagged());
1605 LOperand* value = UseRegisterAtStart(instr->value());
1606
1607 return DefineAsRegister(new(zone()) LGetCachedArrayIndex(value));
1608 }
1609
1610
DoHasCachedArrayIndexAndBranch(HHasCachedArrayIndexAndBranch * instr)1611 LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch(
1612 HHasCachedArrayIndexAndBranch* instr) {
1613 ASSERT(instr->value()->representation().IsTagged());
1614 return new(zone()) LHasCachedArrayIndexAndBranch(
1615 UseRegisterAtStart(instr->value()));
1616 }
1617
1618
DoClassOfTestAndBranch(HClassOfTestAndBranch * instr)1619 LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
1620 HClassOfTestAndBranch* instr) {
1621 ASSERT(instr->value()->representation().IsTagged());
1622 return new(zone()) LClassOfTestAndBranch(UseRegister(instr->value()),
1623 TempRegister(),
1624 TempRegister());
1625 }
1626
1627
DoJSArrayLength(HJSArrayLength * instr)1628 LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
1629 LOperand* array = UseRegisterAtStart(instr->value());
1630 return DefineAsRegister(new(zone()) LJSArrayLength(array));
1631 }
1632
1633
DoFixedArrayBaseLength(HFixedArrayBaseLength * instr)1634 LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
1635 HFixedArrayBaseLength* instr) {
1636 LOperand* array = UseRegisterAtStart(instr->value());
1637 return DefineAsRegister(new(zone()) LFixedArrayBaseLength(array));
1638 }
1639
1640
DoElementsKind(HElementsKind * instr)1641 LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) {
1642 LOperand* object = UseRegisterAtStart(instr->value());
1643 return DefineAsRegister(new(zone()) LElementsKind(object));
1644 }
1645
1646
DoValueOf(HValueOf * instr)1647 LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
1648 LOperand* object = UseRegister(instr->value());
1649 LValueOf* result = new(zone()) LValueOf(object, TempRegister());
1650 return DefineSameAsFirst(result);
1651 }
1652
1653
DoDateField(HDateField * instr)1654 LInstruction* LChunkBuilder::DoDateField(HDateField* instr) {
1655 LOperand* date = UseFixed(instr->value(), eax);
1656 LDateField* result =
1657 new(zone()) LDateField(date, FixedTemp(ecx), instr->index());
1658 return MarkAsCall(DefineFixed(result, eax), instr);
1659 }
1660
1661
DoBoundsCheck(HBoundsCheck * instr)1662 LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1663 return AssignEnvironment(new(zone()) LBoundsCheck(
1664 UseRegisterOrConstantAtStart(instr->index()),
1665 UseAtStart(instr->length())));
1666 }
1667
1668
DoAbnormalExit(HAbnormalExit * instr)1669 LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
1670 // The control instruction marking the end of a block that completed
1671 // abruptly (e.g., threw an exception). There is nothing specific to do.
1672 return NULL;
1673 }
1674
1675
DoThrow(HThrow * instr)1676 LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
1677 LOperand* context = UseFixed(instr->context(), esi);
1678 LOperand* value = UseFixed(instr->value(), eax);
1679 return MarkAsCall(new(zone()) LThrow(context, value), instr);
1680 }
1681
1682
DoUseConst(HUseConst * instr)1683 LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) {
1684 return NULL;
1685 }
1686
1687
DoForceRepresentation(HForceRepresentation * bad)1688 LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
1689 // All HForceRepresentation instructions should be eliminated in the
1690 // representation change phase of Hydrogen.
1691 UNREACHABLE();
1692 return NULL;
1693 }
1694
1695
DoChange(HChange * instr)1696 LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1697 Representation from = instr->from();
1698 Representation to = instr->to();
1699 if (from.IsTagged()) {
1700 if (to.IsDouble()) {
1701 LOperand* value = UseRegister(instr->value());
1702 // Temp register only necessary for minus zero check.
1703 LOperand* temp = instr->deoptimize_on_minus_zero()
1704 ? TempRegister()
1705 : NULL;
1706 LNumberUntagD* res = new(zone()) LNumberUntagD(value, temp);
1707 return AssignEnvironment(DefineAsRegister(res));
1708 } else {
1709 ASSERT(to.IsInteger32());
1710 LOperand* value = UseRegister(instr->value());
1711 bool needs_check = !instr->value()->type().IsSmi();
1712 if (needs_check) {
1713 bool truncating = instr->CanTruncateToInt32();
1714 LOperand* xmm_temp =
1715 (truncating && CpuFeatures::IsSupported(SSE3))
1716 ? NULL
1717 : FixedTemp(xmm1);
1718 LTaggedToI* res = new(zone()) LTaggedToI(value, xmm_temp);
1719 return AssignEnvironment(DefineSameAsFirst(res));
1720 } else {
1721 return DefineSameAsFirst(new(zone()) LSmiUntag(value, needs_check));
1722 }
1723 }
1724 } else if (from.IsDouble()) {
1725 if (to.IsTagged()) {
1726 LOperand* value = UseRegister(instr->value());
1727 LOperand* temp = TempRegister();
1728
1729 // Make sure that temp and result_temp are different registers.
1730 LUnallocated* result_temp = TempRegister();
1731 LNumberTagD* result = new(zone()) LNumberTagD(value, temp);
1732 return AssignPointerMap(Define(result, result_temp));
1733 } else {
1734 ASSERT(to.IsInteger32());
1735 bool truncating = instr->CanTruncateToInt32();
1736 bool needs_temp = truncating && !CpuFeatures::IsSupported(SSE3);
1737 LOperand* value = needs_temp ?
1738 UseTempRegister(instr->value()) : UseRegister(instr->value());
1739 LOperand* temp = needs_temp ? TempRegister() : NULL;
1740 return AssignEnvironment(
1741 DefineAsRegister(new(zone()) LDoubleToI(value, temp)));
1742 }
1743 } else if (from.IsInteger32()) {
1744 if (to.IsTagged()) {
1745 HValue* val = instr->value();
1746 LOperand* value = UseRegister(val);
1747 if (val->HasRange() && val->range()->IsInSmiRange()) {
1748 return DefineSameAsFirst(new(zone()) LSmiTag(value));
1749 } else {
1750 LNumberTagI* result = new(zone()) LNumberTagI(value);
1751 return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1752 }
1753 } else {
1754 ASSERT(to.IsDouble());
1755 return DefineAsRegister(
1756 new(zone()) LInteger32ToDouble(Use(instr->value())));
1757 }
1758 }
1759 UNREACHABLE();
1760 return NULL;
1761 }
1762
1763
DoCheckNonSmi(HCheckNonSmi * instr)1764 LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
1765 LOperand* value = UseAtStart(instr->value());
1766 return AssignEnvironment(new(zone()) LCheckNonSmi(value));
1767 }
1768
1769
DoCheckInstanceType(HCheckInstanceType * instr)1770 LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
1771 LOperand* value = UseRegisterAtStart(instr->value());
1772 LOperand* temp = TempRegister();
1773 LCheckInstanceType* result = new(zone()) LCheckInstanceType(value, temp);
1774 return AssignEnvironment(result);
1775 }
1776
1777
DoCheckPrototypeMaps(HCheckPrototypeMaps * instr)1778 LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
1779 LOperand* temp = TempRegister();
1780 LCheckPrototypeMaps* result = new(zone()) LCheckPrototypeMaps(temp);
1781 return AssignEnvironment(result);
1782 }
1783
1784
DoCheckSmi(HCheckSmi * instr)1785 LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
1786 LOperand* value = UseAtStart(instr->value());
1787 return AssignEnvironment(new(zone()) LCheckSmi(value));
1788 }
1789
1790
DoCheckFunction(HCheckFunction * instr)1791 LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
1792 // If the target is in new space, we'll emit a global cell compare and so
1793 // want the value in a register. If the target gets promoted before we
1794 // emit code, we will still get the register but will do an immediate
1795 // compare instead of the cell compare. This is safe.
1796 LOperand* value = Isolate::Current()->heap()->InNewSpace(*instr->target())
1797 ? UseRegisterAtStart(instr->value())
1798 : UseAtStart(instr->value());
1799 return AssignEnvironment(new(zone()) LCheckFunction(value));
1800 }
1801
1802
DoCheckMap(HCheckMap * instr)1803 LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) {
1804 LOperand* value = UseRegisterAtStart(instr->value());
1805 LCheckMap* result = new(zone()) LCheckMap(value);
1806 return AssignEnvironment(result);
1807 }
1808
1809
DoClampToUint8(HClampToUint8 * instr)1810 LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
1811 HValue* value = instr->value();
1812 Representation input_rep = value->representation();
1813 if (input_rep.IsDouble()) {
1814 LOperand* reg = UseRegister(value);
1815 return DefineAsRegister(new(zone()) LClampDToUint8(reg));
1816 } else if (input_rep.IsInteger32()) {
1817 LOperand* reg = UseFixed(value, eax);
1818 return DefineFixed(new(zone()) LClampIToUint8(reg), eax);
1819 } else {
1820 ASSERT(input_rep.IsTagged());
1821 LOperand* reg = UseFixed(value, eax);
1822 // Register allocator doesn't (yet) support allocation of double
1823 // temps. Reserve xmm1 explicitly.
1824 LOperand* temp = FixedTemp(xmm1);
1825 LClampTToUint8* result = new(zone()) LClampTToUint8(reg, temp);
1826 return AssignEnvironment(DefineFixed(result, eax));
1827 }
1828 }
1829
1830
DoReturn(HReturn * instr)1831 LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
1832 return new(zone()) LReturn(UseFixed(instr->value(), eax));
1833 }
1834
1835
DoConstant(HConstant * instr)1836 LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
1837 Representation r = instr->representation();
1838 if (r.IsInteger32()) {
1839 return DefineAsRegister(new(zone()) LConstantI);
1840 } else if (r.IsDouble()) {
1841 double value = instr->DoubleValue();
1842 LOperand* temp = (BitCast<uint64_t, double>(value) != 0)
1843 ? TempRegister()
1844 : NULL;
1845 return DefineAsRegister(new(zone()) LConstantD(temp));
1846 } else if (r.IsTagged()) {
1847 return DefineAsRegister(new(zone()) LConstantT);
1848 } else {
1849 UNREACHABLE();
1850 return NULL;
1851 }
1852 }
1853
1854
DoLoadGlobalCell(HLoadGlobalCell * instr)1855 LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) {
1856 LLoadGlobalCell* result = new(zone()) LLoadGlobalCell;
1857 return instr->RequiresHoleCheck()
1858 ? AssignEnvironment(DefineAsRegister(result))
1859 : DefineAsRegister(result);
1860 }
1861
1862
DoLoadGlobalGeneric(HLoadGlobalGeneric * instr)1863 LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
1864 LOperand* context = UseFixed(instr->context(), esi);
1865 LOperand* global_object = UseFixed(instr->global_object(), eax);
1866 LLoadGlobalGeneric* result =
1867 new(zone()) LLoadGlobalGeneric(context, global_object);
1868 return MarkAsCall(DefineFixed(result, eax), instr);
1869 }
1870
1871
DoStoreGlobalCell(HStoreGlobalCell * instr)1872 LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
1873 LStoreGlobalCell* result =
1874 new(zone()) LStoreGlobalCell(UseRegister(instr->value()));
1875 return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
1876 }
1877
1878
DoStoreGlobalGeneric(HStoreGlobalGeneric * instr)1879 LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) {
1880 LOperand* context = UseFixed(instr->context(), esi);
1881 LOperand* global_object = UseFixed(instr->global_object(), edx);
1882 LOperand* value = UseFixed(instr->value(), eax);
1883 LStoreGlobalGeneric* result =
1884 new(zone()) LStoreGlobalGeneric(context, global_object, value);
1885 return MarkAsCall(result, instr);
1886 }
1887
1888
DoLoadContextSlot(HLoadContextSlot * instr)1889 LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
1890 LOperand* context = UseRegisterAtStart(instr->value());
1891 LInstruction* result =
1892 DefineAsRegister(new(zone()) LLoadContextSlot(context));
1893 return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
1894 }
1895
1896
DoStoreContextSlot(HStoreContextSlot * instr)1897 LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
1898 LOperand* value;
1899 LOperand* temp;
1900 LOperand* context = UseRegister(instr->context());
1901 if (instr->NeedsWriteBarrier()) {
1902 value = UseTempRegister(instr->value());
1903 temp = TempRegister();
1904 } else {
1905 value = UseRegister(instr->value());
1906 temp = NULL;
1907 }
1908 LInstruction* result = new(zone()) LStoreContextSlot(context, value, temp);
1909 return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
1910 }
1911
1912
DoLoadNamedField(HLoadNamedField * instr)1913 LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
1914 ASSERT(instr->representation().IsTagged());
1915 LOperand* obj = UseRegisterAtStart(instr->object());
1916 return DefineAsRegister(new(zone()) LLoadNamedField(obj));
1917 }
1918
1919
DoLoadNamedFieldPolymorphic(HLoadNamedFieldPolymorphic * instr)1920 LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic(
1921 HLoadNamedFieldPolymorphic* instr) {
1922 ASSERT(instr->representation().IsTagged());
1923 if (instr->need_generic()) {
1924 LOperand* context = UseFixed(instr->context(), esi);
1925 LOperand* obj = UseFixed(instr->object(), eax);
1926 LLoadNamedFieldPolymorphic* result =
1927 new(zone()) LLoadNamedFieldPolymorphic(context, obj);
1928 return MarkAsCall(DefineFixed(result, eax), instr);
1929 } else {
1930 LOperand* context = UseAny(instr->context()); // Not actually used.
1931 LOperand* obj = UseRegisterAtStart(instr->object());
1932 LLoadNamedFieldPolymorphic* result =
1933 new(zone()) LLoadNamedFieldPolymorphic(context, obj);
1934 return AssignEnvironment(DefineAsRegister(result));
1935 }
1936 }
1937
1938
DoLoadNamedGeneric(HLoadNamedGeneric * instr)1939 LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
1940 LOperand* context = UseFixed(instr->context(), esi);
1941 LOperand* object = UseFixed(instr->object(), eax);
1942 LLoadNamedGeneric* result = new(zone()) LLoadNamedGeneric(context, object);
1943 return MarkAsCall(DefineFixed(result, eax), instr);
1944 }
1945
1946
DoLoadFunctionPrototype(HLoadFunctionPrototype * instr)1947 LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
1948 HLoadFunctionPrototype* instr) {
1949 return AssignEnvironment(DefineAsRegister(
1950 new(zone()) LLoadFunctionPrototype(UseRegister(instr->function()),
1951 TempRegister())));
1952 }
1953
1954
DoLoadElements(HLoadElements * instr)1955 LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
1956 LOperand* input = UseRegisterAtStart(instr->value());
1957 return DefineAsRegister(new(zone()) LLoadElements(input));
1958 }
1959
1960
DoLoadExternalArrayPointer(HLoadExternalArrayPointer * instr)1961 LInstruction* LChunkBuilder::DoLoadExternalArrayPointer(
1962 HLoadExternalArrayPointer* instr) {
1963 LOperand* input = UseRegisterAtStart(instr->value());
1964 return DefineAsRegister(new(zone()) LLoadExternalArrayPointer(input));
1965 }
1966
1967
DoLoadKeyedFastElement(HLoadKeyedFastElement * instr)1968 LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
1969 HLoadKeyedFastElement* instr) {
1970 ASSERT(instr->representation().IsTagged());
1971 ASSERT(instr->key()->representation().IsInteger32());
1972 LOperand* obj = UseRegisterAtStart(instr->object());
1973 LOperand* key = UseRegisterOrConstantAtStart(instr->key());
1974 LLoadKeyedFastElement* result = new(zone()) LLoadKeyedFastElement(obj, key);
1975 if (instr->RequiresHoleCheck()) AssignEnvironment(result);
1976 return DefineAsRegister(result);
1977 }
1978
1979
DoLoadKeyedFastDoubleElement(HLoadKeyedFastDoubleElement * instr)1980 LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement(
1981 HLoadKeyedFastDoubleElement* instr) {
1982 ASSERT(instr->representation().IsDouble());
1983 ASSERT(instr->key()->representation().IsInteger32());
1984 LOperand* elements = UseRegisterAtStart(instr->elements());
1985 LOperand* key = UseRegisterOrConstantAtStart(instr->key());
1986 LLoadKeyedFastDoubleElement* result =
1987 new(zone()) LLoadKeyedFastDoubleElement(elements, key);
1988 return AssignEnvironment(DefineAsRegister(result));
1989 }
1990
1991
DoLoadKeyedSpecializedArrayElement(HLoadKeyedSpecializedArrayElement * instr)1992 LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
1993 HLoadKeyedSpecializedArrayElement* instr) {
1994 ElementsKind elements_kind = instr->elements_kind();
1995 ASSERT(
1996 (instr->representation().IsInteger32() &&
1997 (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
1998 (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
1999 (instr->representation().IsDouble() &&
2000 ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
2001 (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
2002 ASSERT(instr->key()->representation().IsInteger32());
2003 LOperand* external_pointer = UseRegister(instr->external_pointer());
2004 LOperand* key = UseRegisterOrConstant(instr->key());
2005 LLoadKeyedSpecializedArrayElement* result =
2006 new(zone()) LLoadKeyedSpecializedArrayElement(external_pointer,
2007 key);
2008 LInstruction* load_instr = DefineAsRegister(result);
2009 // An unsigned int array load might overflow and cause a deopt, make sure it
2010 // has an environment.
2011 return (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS)
2012 ? AssignEnvironment(load_instr)
2013 : load_instr;
2014 }
2015
2016
DoLoadKeyedGeneric(HLoadKeyedGeneric * instr)2017 LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
2018 LOperand* context = UseFixed(instr->context(), esi);
2019 LOperand* object = UseFixed(instr->object(), edx);
2020 LOperand* key = UseFixed(instr->key(), eax);
2021
2022 LLoadKeyedGeneric* result =
2023 new(zone()) LLoadKeyedGeneric(context, object, key);
2024 return MarkAsCall(DefineFixed(result, eax), instr);
2025 }
2026
2027
DoStoreKeyedFastElement(HStoreKeyedFastElement * instr)2028 LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
2029 HStoreKeyedFastElement* instr) {
2030 bool needs_write_barrier = instr->NeedsWriteBarrier();
2031 ASSERT(instr->value()->representation().IsTagged());
2032 ASSERT(instr->object()->representation().IsTagged());
2033 ASSERT(instr->key()->representation().IsInteger32());
2034
2035 LOperand* obj = UseRegister(instr->object());
2036 LOperand* val = needs_write_barrier
2037 ? UseTempRegister(instr->value())
2038 : UseRegisterAtStart(instr->value());
2039 LOperand* key = needs_write_barrier
2040 ? UseTempRegister(instr->key())
2041 : UseRegisterOrConstantAtStart(instr->key());
2042 return new(zone()) LStoreKeyedFastElement(obj, key, val);
2043 }
2044
2045
DoStoreKeyedFastDoubleElement(HStoreKeyedFastDoubleElement * instr)2046 LInstruction* LChunkBuilder::DoStoreKeyedFastDoubleElement(
2047 HStoreKeyedFastDoubleElement* instr) {
2048 ASSERT(instr->value()->representation().IsDouble());
2049 ASSERT(instr->elements()->representation().IsTagged());
2050 ASSERT(instr->key()->representation().IsInteger32());
2051
2052 LOperand* elements = UseRegisterAtStart(instr->elements());
2053 LOperand* val = UseTempRegister(instr->value());
2054 LOperand* key = UseRegisterOrConstantAtStart(instr->key());
2055
2056 return new(zone()) LStoreKeyedFastDoubleElement(elements, key, val);
2057 }
2058
2059
DoStoreKeyedSpecializedArrayElement(HStoreKeyedSpecializedArrayElement * instr)2060 LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
2061 HStoreKeyedSpecializedArrayElement* instr) {
2062 ElementsKind elements_kind = instr->elements_kind();
2063 ASSERT(
2064 (instr->value()->representation().IsInteger32() &&
2065 (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
2066 (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
2067 (instr->value()->representation().IsDouble() &&
2068 ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
2069 (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
2070 ASSERT(instr->external_pointer()->representation().IsExternal());
2071 ASSERT(instr->key()->representation().IsInteger32());
2072
2073 LOperand* external_pointer = UseRegister(instr->external_pointer());
2074 LOperand* key = UseRegisterOrConstant(instr->key());
2075 LOperand* val = NULL;
2076 if (elements_kind == EXTERNAL_BYTE_ELEMENTS ||
2077 elements_kind == EXTERNAL_UNSIGNED_BYTE_ELEMENTS ||
2078 elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
2079 // We need a byte register in this case for the value.
2080 val = UseFixed(instr->value(), eax);
2081 } else {
2082 val = UseRegister(instr->value());
2083 }
2084
2085 return new(zone()) LStoreKeyedSpecializedArrayElement(external_pointer,
2086 key,
2087 val);
2088 }
2089
2090
DoStoreKeyedGeneric(HStoreKeyedGeneric * instr)2091 LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
2092 LOperand* context = UseFixed(instr->context(), esi);
2093 LOperand* object = UseFixed(instr->object(), edx);
2094 LOperand* key = UseFixed(instr->key(), ecx);
2095 LOperand* value = UseFixed(instr->value(), eax);
2096
2097 ASSERT(instr->object()->representation().IsTagged());
2098 ASSERT(instr->key()->representation().IsTagged());
2099 ASSERT(instr->value()->representation().IsTagged());
2100
2101 LStoreKeyedGeneric* result =
2102 new(zone()) LStoreKeyedGeneric(context, object, key, value);
2103 return MarkAsCall(result, instr);
2104 }
2105
2106
DoTransitionElementsKind(HTransitionElementsKind * instr)2107 LInstruction* LChunkBuilder::DoTransitionElementsKind(
2108 HTransitionElementsKind* instr) {
2109 if (instr->original_map()->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
2110 instr->transitioned_map()->elements_kind() == FAST_ELEMENTS) {
2111 LOperand* object = UseRegister(instr->object());
2112 LOperand* new_map_reg = TempRegister();
2113 LOperand* temp_reg = TempRegister();
2114 LTransitionElementsKind* result =
2115 new(zone()) LTransitionElementsKind(object, new_map_reg, temp_reg);
2116 return DefineSameAsFirst(result);
2117 } else {
2118 LOperand* object = UseFixed(instr->object(), eax);
2119 LOperand* fixed_object_reg = FixedTemp(edx);
2120 LOperand* new_map_reg = FixedTemp(ebx);
2121 LTransitionElementsKind* result =
2122 new(zone()) LTransitionElementsKind(object,
2123 new_map_reg,
2124 fixed_object_reg);
2125 return MarkAsCall(DefineFixed(result, eax), instr);
2126 }
2127 }
2128
2129
DoStoreNamedField(HStoreNamedField * instr)2130 LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
2131 bool needs_write_barrier = instr->NeedsWriteBarrier();
2132
2133 LOperand* obj;
2134 if (needs_write_barrier) {
2135 obj = instr->is_in_object()
2136 ? UseRegister(instr->object())
2137 : UseTempRegister(instr->object());
2138 } else {
2139 obj = UseRegisterAtStart(instr->object());
2140 }
2141
2142 LOperand* val = needs_write_barrier
2143 ? UseTempRegister(instr->value())
2144 : UseRegister(instr->value());
2145
2146 // We only need a scratch register if we have a write barrier or we
2147 // have a store into the properties array (not in-object-property).
2148 LOperand* temp = (!instr->is_in_object() || needs_write_barrier)
2149 ? TempRegister()
2150 : NULL;
2151
2152 return new(zone()) LStoreNamedField(obj, val, temp);
2153 }
2154
2155
DoStoreNamedGeneric(HStoreNamedGeneric * instr)2156 LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
2157 LOperand* context = UseFixed(instr->context(), esi);
2158 LOperand* object = UseFixed(instr->object(), edx);
2159 LOperand* value = UseFixed(instr->value(), eax);
2160
2161 LStoreNamedGeneric* result =
2162 new(zone()) LStoreNamedGeneric(context, object, value);
2163 return MarkAsCall(result, instr);
2164 }
2165
2166
DoStringAdd(HStringAdd * instr)2167 LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
2168 LOperand* context = UseFixed(instr->context(), esi);
2169 LOperand* left = UseOrConstantAtStart(instr->left());
2170 LOperand* right = UseOrConstantAtStart(instr->right());
2171 LStringAdd* string_add = new(zone()) LStringAdd(context, left, right);
2172 return MarkAsCall(DefineFixed(string_add, eax), instr);
2173 }
2174
2175
DoStringCharCodeAt(HStringCharCodeAt * instr)2176 LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
2177 LOperand* string = UseTempRegister(instr->string());
2178 LOperand* index = UseTempRegister(instr->index());
2179 LOperand* context = UseAny(instr->context());
2180 LStringCharCodeAt* result =
2181 new(zone()) LStringCharCodeAt(context, string, index);
2182 return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
2183 }
2184
2185
DoStringCharFromCode(HStringCharFromCode * instr)2186 LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
2187 LOperand* char_code = UseRegister(instr->value());
2188 LOperand* context = UseAny(instr->context());
2189 LStringCharFromCode* result =
2190 new(zone()) LStringCharFromCode(context, char_code);
2191 return AssignPointerMap(DefineAsRegister(result));
2192 }
2193
2194
DoStringLength(HStringLength * instr)2195 LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
2196 LOperand* string = UseRegisterAtStart(instr->value());
2197 return DefineAsRegister(new(zone()) LStringLength(string));
2198 }
2199
2200
DoAllocateObject(HAllocateObject * instr)2201 LInstruction* LChunkBuilder::DoAllocateObject(HAllocateObject* instr) {
2202 LOperand* context = UseFixed(instr->context(), esi);
2203 LOperand* temp = TempRegister();
2204 LAllocateObject* result = new(zone()) LAllocateObject(context, temp);
2205 return AssignPointerMap(DefineAsRegister(result));
2206 }
2207
2208
DoFastLiteral(HFastLiteral * instr)2209 LInstruction* LChunkBuilder::DoFastLiteral(HFastLiteral* instr) {
2210 LOperand* context = UseFixed(instr->context(), esi);
2211 return MarkAsCall(
2212 DefineFixed(new(zone()) LFastLiteral(context), eax), instr);
2213 }
2214
2215
DoArrayLiteral(HArrayLiteral * instr)2216 LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
2217 LOperand* context = UseFixed(instr->context(), esi);
2218 return MarkAsCall(
2219 DefineFixed(new(zone()) LArrayLiteral(context), eax), instr);
2220 }
2221
2222
DoObjectLiteral(HObjectLiteral * instr)2223 LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) {
2224 LOperand* context = UseFixed(instr->context(), esi);
2225 return MarkAsCall(
2226 DefineFixed(new(zone()) LObjectLiteral(context), eax), instr);
2227 }
2228
2229
DoRegExpLiteral(HRegExpLiteral * instr)2230 LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
2231 LOperand* context = UseFixed(instr->context(), esi);
2232 return MarkAsCall(
2233 DefineFixed(new(zone()) LRegExpLiteral(context), eax), instr);
2234 }
2235
2236
DoFunctionLiteral(HFunctionLiteral * instr)2237 LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
2238 LOperand* context = UseFixed(instr->context(), esi);
2239 return MarkAsCall(
2240 DefineFixed(new(zone()) LFunctionLiteral(context), eax), instr);
2241 }
2242
2243
DoDeleteProperty(HDeleteProperty * instr)2244 LInstruction* LChunkBuilder::DoDeleteProperty(HDeleteProperty* instr) {
2245 LOperand* context = UseFixed(instr->context(), esi);
2246 LOperand* object = UseAtStart(instr->object());
2247 LOperand* key = UseOrConstantAtStart(instr->key());
2248 LDeleteProperty* result = new(zone()) LDeleteProperty(context, object, key);
2249 return MarkAsCall(DefineFixed(result, eax), instr);
2250 }
2251
2252
DoOsrEntry(HOsrEntry * instr)2253 LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
2254 allocator_->MarkAsOsrEntry();
2255 current_block_->last_environment()->set_ast_id(instr->ast_id());
2256 return AssignEnvironment(new(zone()) LOsrEntry);
2257 }
2258
2259
DoParameter(HParameter * instr)2260 LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2261 int spill_index = chunk()->GetParameterStackSlot(instr->index());
2262 return DefineAsSpilled(new(zone()) LParameter, spill_index);
2263 }
2264
2265
DoUnknownOSRValue(HUnknownOSRValue * instr)2266 LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
2267 int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width.
2268 if (spill_index > LUnallocated::kMaxFixedIndex) {
2269 Abort("Too many spill slots needed for OSR");
2270 spill_index = 0;
2271 }
2272 return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index);
2273 }
2274
2275
DoCallStub(HCallStub * instr)2276 LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
2277 LOperand* context = UseFixed(instr->context(), esi);
2278 argument_count_ -= instr->argument_count();
2279 LCallStub* result = new(zone()) LCallStub(context);
2280 return MarkAsCall(DefineFixed(result, eax), instr);
2281 }
2282
2283
DoArgumentsObject(HArgumentsObject * instr)2284 LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
2285 // There are no real uses of the arguments object.
2286 // arguments.length and element access are supported directly on
2287 // stack arguments, and any real arguments object use causes a bailout.
2288 // So this value is never used.
2289 return NULL;
2290 }
2291
2292
DoAccessArgumentsAt(HAccessArgumentsAt * instr)2293 LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
2294 LOperand* arguments = UseRegister(instr->arguments());
2295 LOperand* length = UseTempRegister(instr->length());
2296 LOperand* index = Use(instr->index());
2297 LAccessArgumentsAt* result =
2298 new(zone()) LAccessArgumentsAt(arguments, length, index);
2299 return AssignEnvironment(DefineAsRegister(result));
2300 }
2301
2302
DoToFastProperties(HToFastProperties * instr)2303 LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
2304 LOperand* object = UseFixed(instr->value(), eax);
2305 LToFastProperties* result = new(zone()) LToFastProperties(object);
2306 return MarkAsCall(DefineFixed(result, eax), instr);
2307 }
2308
2309
DoTypeof(HTypeof * instr)2310 LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2311 LOperand* context = UseFixed(instr->context(), esi);
2312 LOperand* value = UseAtStart(instr->value());
2313 LTypeof* result = new(zone()) LTypeof(context, value);
2314 return MarkAsCall(DefineFixed(result, eax), instr);
2315 }
2316
2317
DoTypeofIsAndBranch(HTypeofIsAndBranch * instr)2318 LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
2319 return new(zone()) LTypeofIsAndBranch(UseTempRegister(instr->value()));
2320 }
2321
2322
DoIsConstructCallAndBranch(HIsConstructCallAndBranch * instr)2323 LInstruction* LChunkBuilder::DoIsConstructCallAndBranch(
2324 HIsConstructCallAndBranch* instr) {
2325 return new(zone()) LIsConstructCallAndBranch(TempRegister());
2326 }
2327
2328
DoSimulate(HSimulate * instr)2329 LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2330 HEnvironment* env = current_block_->last_environment();
2331 ASSERT(env != NULL);
2332
2333 env->set_ast_id(instr->ast_id());
2334
2335 env->Drop(instr->pop_count());
2336 for (int i = 0; i < instr->values()->length(); ++i) {
2337 HValue* value = instr->values()->at(i);
2338 if (instr->HasAssignedIndexAt(i)) {
2339 env->Bind(instr->GetAssignedIndexAt(i), value);
2340 } else {
2341 env->Push(value);
2342 }
2343 }
2344
2345 // If there is an instruction pending deoptimization environment create a
2346 // lazy bailout instruction to capture the environment.
2347 if (pending_deoptimization_ast_id_ != AstNode::kNoNumber) {
2348 ASSERT(pending_deoptimization_ast_id_ == instr->ast_id());
2349 LLazyBailout* lazy_bailout = new(zone()) LLazyBailout;
2350 LInstruction* result = AssignEnvironment(lazy_bailout);
2351 instruction_pending_deoptimization_environment_->
2352 set_deoptimization_environment(result->environment());
2353 ClearInstructionPendingDeoptimizationEnvironment();
2354 return result;
2355 }
2356
2357 return NULL;
2358 }
2359
2360
DoStackCheck(HStackCheck * instr)2361 LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2362 if (instr->is_function_entry()) {
2363 LOperand* context = UseFixed(instr->context(), esi);
2364 return MarkAsCall(new(zone()) LStackCheck(context), instr);
2365 } else {
2366 ASSERT(instr->is_backwards_branch());
2367 LOperand* context = UseAny(instr->context());
2368 return AssignEnvironment(
2369 AssignPointerMap(new(zone()) LStackCheck(context)));
2370 }
2371 }
2372
2373
DoEnterInlined(HEnterInlined * instr)2374 LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
2375 HEnvironment* outer = current_block_->last_environment();
2376 HConstant* undefined = graph()->GetConstantUndefined();
2377 HEnvironment* inner = outer->CopyForInlining(instr->closure(),
2378 instr->arguments_count(),
2379 instr->function(),
2380 undefined,
2381 instr->call_kind(),
2382 instr->is_construct());
2383 if (instr->arguments() != NULL) {
2384 inner->Bind(instr->arguments(), graph()->GetArgumentsObject());
2385 }
2386 current_block_->UpdateEnvironment(inner);
2387 chunk_->AddInlinedClosure(instr->closure());
2388 return NULL;
2389 }
2390
2391
DoLeaveInlined(HLeaveInlined * instr)2392 LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2393 HEnvironment* outer = current_block_->last_environment()->
2394 DiscardInlined(false);
2395 current_block_->UpdateEnvironment(outer);
2396 return NULL;
2397 }
2398
2399
DoIn(HIn * instr)2400 LInstruction* LChunkBuilder::DoIn(HIn* instr) {
2401 LOperand* context = UseFixed(instr->context(), esi);
2402 LOperand* key = UseOrConstantAtStart(instr->key());
2403 LOperand* object = UseOrConstantAtStart(instr->object());
2404 LIn* result = new(zone()) LIn(context, key, object);
2405 return MarkAsCall(DefineFixed(result, eax), instr);
2406 }
2407
2408
DoForInPrepareMap(HForInPrepareMap * instr)2409 LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
2410 LOperand* context = UseFixed(instr->context(), esi);
2411 LOperand* object = UseFixed(instr->enumerable(), eax);
2412 LForInPrepareMap* result = new(zone()) LForInPrepareMap(context, object);
2413 return MarkAsCall(DefineFixed(result, eax), instr, CAN_DEOPTIMIZE_EAGERLY);
2414 }
2415
2416
DoForInCacheArray(HForInCacheArray * instr)2417 LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
2418 LOperand* map = UseRegister(instr->map());
2419 return AssignEnvironment(DefineAsRegister(
2420 new(zone()) LForInCacheArray(map)));
2421 }
2422
2423
DoCheckMapValue(HCheckMapValue * instr)2424 LInstruction* LChunkBuilder::DoCheckMapValue(HCheckMapValue* instr) {
2425 LOperand* value = UseRegisterAtStart(instr->value());
2426 LOperand* map = UseRegisterAtStart(instr->map());
2427 return AssignEnvironment(new(zone()) LCheckMapValue(value, map));
2428 }
2429
2430
DoLoadFieldByIndex(HLoadFieldByIndex * instr)2431 LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
2432 LOperand* object = UseRegister(instr->object());
2433 LOperand* index = UseTempRegister(instr->index());
2434 return DefineSameAsFirst(new(zone()) LLoadFieldByIndex(object, index));
2435 }
2436
2437
2438 } } // namespace v8::internal
2439
2440 #endif // V8_TARGET_ARCH_IA32
2441