1 // Copyright 2011 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 #include "lithium-allocator-inl.h"
31 #include "arm/lithium-arm.h"
32 #include "arm/lithium-codegen-arm.h"
33
34 namespace v8 {
35 namespace internal {
36
37 #define DEFINE_COMPILE(type) \
38 void L##type::CompileToNative(LCodeGen* generator) { \
39 generator->Do##type(this); \
40 }
LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)41 LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
42 #undef DEFINE_COMPILE
43
44 LOsrEntry::LOsrEntry() {
45 for (int i = 0; i < Register::kNumAllocatableRegisters; ++i) {
46 register_spills_[i] = NULL;
47 }
48 for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; ++i) {
49 double_register_spills_[i] = NULL;
50 }
51 }
52
53
MarkSpilledRegister(int allocation_index,LOperand * spill_operand)54 void LOsrEntry::MarkSpilledRegister(int allocation_index,
55 LOperand* spill_operand) {
56 ASSERT(spill_operand->IsStackSlot());
57 ASSERT(register_spills_[allocation_index] == NULL);
58 register_spills_[allocation_index] = spill_operand;
59 }
60
61
62 #ifdef DEBUG
VerifyCall()63 void LInstruction::VerifyCall() {
64 // Call instructions can use only fixed registers as
65 // temporaries and outputs because all registers
66 // are blocked by the calling convention.
67 // Inputs must use a fixed register.
68 ASSERT(Output() == NULL ||
69 LUnallocated::cast(Output())->HasFixedPolicy() ||
70 !LUnallocated::cast(Output())->HasRegisterPolicy());
71 for (UseIterator it(this); it.HasNext(); it.Advance()) {
72 LOperand* operand = it.Next();
73 ASSERT(LUnallocated::cast(operand)->HasFixedPolicy() ||
74 !LUnallocated::cast(operand)->HasRegisterPolicy());
75 }
76 for (TempIterator it(this); it.HasNext(); it.Advance()) {
77 LOperand* operand = it.Next();
78 ASSERT(LUnallocated::cast(operand)->HasFixedPolicy() ||
79 !LUnallocated::cast(operand)->HasRegisterPolicy());
80 }
81 }
82 #endif
83
84
MarkSpilledDoubleRegister(int allocation_index,LOperand * spill_operand)85 void LOsrEntry::MarkSpilledDoubleRegister(int allocation_index,
86 LOperand* spill_operand) {
87 ASSERT(spill_operand->IsDoubleStackSlot());
88 ASSERT(double_register_spills_[allocation_index] == NULL);
89 double_register_spills_[allocation_index] = spill_operand;
90 }
91
92
PrintTo(StringStream * stream)93 void LInstruction::PrintTo(StringStream* stream) {
94 stream->Add("%s ", this->Mnemonic());
95
96 PrintOutputOperandTo(stream);
97
98 PrintDataTo(stream);
99
100 if (HasEnvironment()) {
101 stream->Add(" ");
102 environment()->PrintTo(stream);
103 }
104
105 if (HasPointerMap()) {
106 stream->Add(" ");
107 pointer_map()->PrintTo(stream);
108 }
109 }
110
111
112 template<int R, int I, int T>
PrintDataTo(StringStream * stream)113 void LTemplateInstruction<R, I, T>::PrintDataTo(StringStream* stream) {
114 stream->Add("= ");
115 inputs_.PrintOperandsTo(stream);
116 }
117
118
119 template<int R, int I, int T>
PrintOutputOperandTo(StringStream * stream)120 void LTemplateInstruction<R, I, T>::PrintOutputOperandTo(StringStream* stream) {
121 results_.PrintOperandsTo(stream);
122 }
123
124
125 template<typename T, int N>
PrintOperandsTo(StringStream * stream)126 void OperandContainer<T, N>::PrintOperandsTo(StringStream* stream) {
127 for (int i = 0; i < N; i++) {
128 if (i > 0) stream->Add(" ");
129 elems_[i]->PrintTo(stream);
130 }
131 }
132
133
PrintDataTo(StringStream * stream)134 void LLabel::PrintDataTo(StringStream* stream) {
135 LGap::PrintDataTo(stream);
136 LLabel* rep = replacement();
137 if (rep != NULL) {
138 stream->Add(" Dead block replaced with B%d", rep->block_id());
139 }
140 }
141
142
IsRedundant() const143 bool LGap::IsRedundant() const {
144 for (int i = 0; i < 4; i++) {
145 if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) {
146 return false;
147 }
148 }
149
150 return true;
151 }
152
153
PrintDataTo(StringStream * stream) const154 void LGap::PrintDataTo(StringStream* stream) const {
155 for (int i = 0; i < 4; i++) {
156 stream->Add("(");
157 if (parallel_moves_[i] != NULL) {
158 parallel_moves_[i]->PrintDataTo(stream);
159 }
160 stream->Add(") ");
161 }
162 }
163
164
Mnemonic() const165 const char* LArithmeticD::Mnemonic() const {
166 switch (op()) {
167 case Token::ADD: return "add-d";
168 case Token::SUB: return "sub-d";
169 case Token::MUL: return "mul-d";
170 case Token::DIV: return "div-d";
171 case Token::MOD: return "mod-d";
172 default:
173 UNREACHABLE();
174 return NULL;
175 }
176 }
177
178
Mnemonic() const179 const char* LArithmeticT::Mnemonic() const {
180 switch (op()) {
181 case Token::ADD: return "add-t";
182 case Token::SUB: return "sub-t";
183 case Token::MUL: return "mul-t";
184 case Token::MOD: return "mod-t";
185 case Token::DIV: return "div-t";
186 case Token::BIT_AND: return "bit-and-t";
187 case Token::BIT_OR: return "bit-or-t";
188 case Token::BIT_XOR: return "bit-xor-t";
189 case Token::SHL: return "shl-t";
190 case Token::SAR: return "sar-t";
191 case Token::SHR: return "shr-t";
192 default:
193 UNREACHABLE();
194 return NULL;
195 }
196 }
197
198
PrintDataTo(StringStream * stream)199 void LGoto::PrintDataTo(StringStream* stream) {
200 stream->Add("B%d", block_id());
201 }
202
203
PrintDataTo(StringStream * stream)204 void LBranch::PrintDataTo(StringStream* stream) {
205 stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
206 InputAt(0)->PrintTo(stream);
207 }
208
209
PrintDataTo(StringStream * stream)210 void LCmpIDAndBranch::PrintDataTo(StringStream* stream) {
211 stream->Add("if ");
212 InputAt(0)->PrintTo(stream);
213 stream->Add(" %s ", Token::String(op()));
214 InputAt(1)->PrintTo(stream);
215 stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
216 }
217
218
PrintDataTo(StringStream * stream)219 void LIsNullAndBranch::PrintDataTo(StringStream* stream) {
220 stream->Add("if ");
221 InputAt(0)->PrintTo(stream);
222 stream->Add(is_strict() ? " === null" : " == null");
223 stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
224 }
225
226
PrintDataTo(StringStream * stream)227 void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
228 stream->Add("if is_object(");
229 InputAt(0)->PrintTo(stream);
230 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
231 }
232
233
PrintDataTo(StringStream * stream)234 void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
235 stream->Add("if is_smi(");
236 InputAt(0)->PrintTo(stream);
237 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
238 }
239
240
PrintDataTo(StringStream * stream)241 void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
242 stream->Add("if has_instance_type(");
243 InputAt(0)->PrintTo(stream);
244 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
245 }
246
247
PrintDataTo(StringStream * stream)248 void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
249 stream->Add("if has_cached_array_index(");
250 InputAt(0)->PrintTo(stream);
251 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
252 }
253
254
PrintDataTo(StringStream * stream)255 void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
256 stream->Add("if class_of_test(");
257 InputAt(0)->PrintTo(stream);
258 stream->Add(", \"%o\") then B%d else B%d",
259 *hydrogen()->class_name(),
260 true_block_id(),
261 false_block_id());
262 }
263
264
PrintDataTo(StringStream * stream)265 void LTypeofIs::PrintDataTo(StringStream* stream) {
266 InputAt(0)->PrintTo(stream);
267 stream->Add(" == \"%s\"", *hydrogen()->type_literal()->ToCString());
268 }
269
270
PrintDataTo(StringStream * stream)271 void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
272 stream->Add("if typeof ");
273 InputAt(0)->PrintTo(stream);
274 stream->Add(" == \"%s\" then B%d else B%d",
275 *hydrogen()->type_literal()->ToCString(),
276 true_block_id(), false_block_id());
277 }
278
279
PrintDataTo(StringStream * stream)280 void LCallConstantFunction::PrintDataTo(StringStream* stream) {
281 stream->Add("#%d / ", arity());
282 }
283
284
PrintDataTo(StringStream * stream)285 void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
286 stream->Add("/%s ", hydrogen()->OpName());
287 InputAt(0)->PrintTo(stream);
288 }
289
290
PrintDataTo(StringStream * stream)291 void LLoadContextSlot::PrintDataTo(StringStream* stream) {
292 InputAt(0)->PrintTo(stream);
293 stream->Add("[%d]", slot_index());
294 }
295
296
PrintDataTo(StringStream * stream)297 void LStoreContextSlot::PrintDataTo(StringStream* stream) {
298 InputAt(0)->PrintTo(stream);
299 stream->Add("[%d] <- ", slot_index());
300 InputAt(1)->PrintTo(stream);
301 }
302
303
PrintDataTo(StringStream * stream)304 void LCallKeyed::PrintDataTo(StringStream* stream) {
305 stream->Add("[r2] #%d / ", arity());
306 }
307
308
PrintDataTo(StringStream * stream)309 void LCallNamed::PrintDataTo(StringStream* stream) {
310 SmartPointer<char> name_string = name()->ToCString();
311 stream->Add("%s #%d / ", *name_string, arity());
312 }
313
314
PrintDataTo(StringStream * stream)315 void LCallGlobal::PrintDataTo(StringStream* stream) {
316 SmartPointer<char> name_string = name()->ToCString();
317 stream->Add("%s #%d / ", *name_string, arity());
318 }
319
320
PrintDataTo(StringStream * stream)321 void LCallKnownGlobal::PrintDataTo(StringStream* stream) {
322 stream->Add("#%d / ", arity());
323 }
324
325
PrintDataTo(StringStream * stream)326 void LCallNew::PrintDataTo(StringStream* stream) {
327 stream->Add("= ");
328 InputAt(0)->PrintTo(stream);
329 stream->Add(" #%d / ", arity());
330 }
331
332
PrintDataTo(StringStream * stream)333 void LClassOfTest::PrintDataTo(StringStream* stream) {
334 stream->Add("= class_of_test(");
335 InputAt(0)->PrintTo(stream);
336 stream->Add(", \"%o\")", *hydrogen()->class_name());
337 }
338
339
PrintDataTo(StringStream * stream)340 void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
341 arguments()->PrintTo(stream);
342
343 stream->Add(" length ");
344 length()->PrintTo(stream);
345
346 stream->Add(" index ");
347 index()->PrintTo(stream);
348 }
349
350
PrintDataTo(StringStream * stream)351 void LStoreNamedField::PrintDataTo(StringStream* stream) {
352 object()->PrintTo(stream);
353 stream->Add(".");
354 stream->Add(*String::cast(*name())->ToCString());
355 stream->Add(" <- ");
356 value()->PrintTo(stream);
357 }
358
359
PrintDataTo(StringStream * stream)360 void LStoreNamedGeneric::PrintDataTo(StringStream* stream) {
361 object()->PrintTo(stream);
362 stream->Add(".");
363 stream->Add(*String::cast(*name())->ToCString());
364 stream->Add(" <- ");
365 value()->PrintTo(stream);
366 }
367
368
PrintDataTo(StringStream * stream)369 void LStoreKeyedFastElement::PrintDataTo(StringStream* stream) {
370 object()->PrintTo(stream);
371 stream->Add("[");
372 key()->PrintTo(stream);
373 stream->Add("] <- ");
374 value()->PrintTo(stream);
375 }
376
377
PrintDataTo(StringStream * stream)378 void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
379 object()->PrintTo(stream);
380 stream->Add("[");
381 key()->PrintTo(stream);
382 stream->Add("] <- ");
383 value()->PrintTo(stream);
384 }
385
386
LChunk(CompilationInfo * info,HGraph * graph)387 LChunk::LChunk(CompilationInfo* info, HGraph* graph)
388 : spill_slot_count_(0),
389 info_(info),
390 graph_(graph),
391 instructions_(32),
392 pointer_maps_(8),
393 inlined_closures_(1) {
394 }
395
396
GetNextSpillIndex(bool is_double)397 int LChunk::GetNextSpillIndex(bool is_double) {
398 // Skip a slot if for a double-width slot.
399 if (is_double) spill_slot_count_++;
400 return spill_slot_count_++;
401 }
402
403
GetNextSpillSlot(bool is_double)404 LOperand* LChunk::GetNextSpillSlot(bool is_double) {
405 int index = GetNextSpillIndex(is_double);
406 if (is_double) {
407 return LDoubleStackSlot::Create(index);
408 } else {
409 return LStackSlot::Create(index);
410 }
411 }
412
413
MarkEmptyBlocks()414 void LChunk::MarkEmptyBlocks() {
415 HPhase phase("Mark empty blocks", this);
416 for (int i = 0; i < graph()->blocks()->length(); ++i) {
417 HBasicBlock* block = graph()->blocks()->at(i);
418 int first = block->first_instruction_index();
419 int last = block->last_instruction_index();
420 LInstruction* first_instr = instructions()->at(first);
421 LInstruction* last_instr = instructions()->at(last);
422
423 LLabel* label = LLabel::cast(first_instr);
424 if (last_instr->IsGoto()) {
425 LGoto* goto_instr = LGoto::cast(last_instr);
426 if (!goto_instr->include_stack_check() &&
427 label->IsRedundant() &&
428 !label->is_loop_header()) {
429 bool can_eliminate = true;
430 for (int i = first + 1; i < last && can_eliminate; ++i) {
431 LInstruction* cur = instructions()->at(i);
432 if (cur->IsGap()) {
433 LGap* gap = LGap::cast(cur);
434 if (!gap->IsRedundant()) {
435 can_eliminate = false;
436 }
437 } else {
438 can_eliminate = false;
439 }
440 }
441
442 if (can_eliminate) {
443 label->set_replacement(GetLabel(goto_instr->block_id()));
444 }
445 }
446 }
447 }
448 }
449
450
AddInstruction(LInstruction * instr,HBasicBlock * block)451 void LChunk::AddInstruction(LInstruction* instr, HBasicBlock* block) {
452 LGap* gap = new LGap(block);
453 int index = -1;
454 if (instr->IsControl()) {
455 instructions_.Add(gap);
456 index = instructions_.length();
457 instructions_.Add(instr);
458 } else {
459 index = instructions_.length();
460 instructions_.Add(instr);
461 instructions_.Add(gap);
462 }
463 if (instr->HasPointerMap()) {
464 pointer_maps_.Add(instr->pointer_map());
465 instr->pointer_map()->set_lithium_position(index);
466 }
467 }
468
469
DefineConstantOperand(HConstant * constant)470 LConstantOperand* LChunk::DefineConstantOperand(HConstant* constant) {
471 return LConstantOperand::Create(constant->id());
472 }
473
474
GetParameterStackSlot(int index) const475 int LChunk::GetParameterStackSlot(int index) const {
476 // The receiver is at index 0, the first parameter at index 1, so we
477 // shift all parameter indexes down by the number of parameters, and
478 // make sure they end up negative so they are distinguishable from
479 // spill slots.
480 int result = index - info()->scope()->num_parameters() - 1;
481 ASSERT(result < 0);
482 return result;
483 }
484
485 // A parameter relative to ebp in the arguments stub.
ParameterAt(int index)486 int LChunk::ParameterAt(int index) {
487 ASSERT(-1 <= index); // -1 is the receiver.
488 return (1 + info()->scope()->num_parameters() - index) *
489 kPointerSize;
490 }
491
492
GetGapAt(int index) const493 LGap* LChunk::GetGapAt(int index) const {
494 return LGap::cast(instructions_[index]);
495 }
496
497
IsGapAt(int index) const498 bool LChunk::IsGapAt(int index) const {
499 return instructions_[index]->IsGap();
500 }
501
502
NearestGapPos(int index) const503 int LChunk::NearestGapPos(int index) const {
504 while (!IsGapAt(index)) index--;
505 return index;
506 }
507
508
AddGapMove(int index,LOperand * from,LOperand * to)509 void LChunk::AddGapMove(int index, LOperand* from, LOperand* to) {
510 GetGapAt(index)->GetOrCreateParallelMove(LGap::START)->AddMove(from, to);
511 }
512
513
LookupLiteral(LConstantOperand * operand) const514 Handle<Object> LChunk::LookupLiteral(LConstantOperand* operand) const {
515 return HConstant::cast(graph_->LookupValue(operand->index()))->handle();
516 }
517
518
LookupLiteralRepresentation(LConstantOperand * operand) const519 Representation LChunk::LookupLiteralRepresentation(
520 LConstantOperand* operand) const {
521 return graph_->LookupValue(operand->index())->representation();
522 }
523
524
Build()525 LChunk* LChunkBuilder::Build() {
526 ASSERT(is_unused());
527 chunk_ = new LChunk(info(), graph());
528 HPhase phase("Building chunk", chunk_);
529 status_ = BUILDING;
530 const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
531 for (int i = 0; i < blocks->length(); i++) {
532 HBasicBlock* next = NULL;
533 if (i < blocks->length() - 1) next = blocks->at(i + 1);
534 DoBasicBlock(blocks->at(i), next);
535 if (is_aborted()) return NULL;
536 }
537 status_ = DONE;
538 return chunk_;
539 }
540
541
Abort(const char * format,...)542 void LChunkBuilder::Abort(const char* format, ...) {
543 if (FLAG_trace_bailout) {
544 SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
545 PrintF("Aborting LChunk building in @\"%s\": ", *name);
546 va_list arguments;
547 va_start(arguments, format);
548 OS::VPrint(format, arguments);
549 va_end(arguments);
550 PrintF("\n");
551 }
552 status_ = ABORTED;
553 }
554
555
ToOperand(Register reg)556 LRegister* LChunkBuilder::ToOperand(Register reg) {
557 return LRegister::Create(Register::ToAllocationIndex(reg));
558 }
559
560
ToUnallocated(Register reg)561 LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
562 return new LUnallocated(LUnallocated::FIXED_REGISTER,
563 Register::ToAllocationIndex(reg));
564 }
565
566
ToUnallocated(DoubleRegister reg)567 LUnallocated* LChunkBuilder::ToUnallocated(DoubleRegister reg) {
568 return new LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
569 DoubleRegister::ToAllocationIndex(reg));
570 }
571
572
UseFixed(HValue * value,Register fixed_register)573 LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
574 return Use(value, ToUnallocated(fixed_register));
575 }
576
577
UseFixedDouble(HValue * value,DoubleRegister reg)578 LOperand* LChunkBuilder::UseFixedDouble(HValue* value, DoubleRegister reg) {
579 return Use(value, ToUnallocated(reg));
580 }
581
582
UseRegister(HValue * value)583 LOperand* LChunkBuilder::UseRegister(HValue* value) {
584 return Use(value, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
585 }
586
587
UseRegisterAtStart(HValue * value)588 LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
589 return Use(value,
590 new LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
591 LUnallocated::USED_AT_START));
592 }
593
594
UseTempRegister(HValue * value)595 LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
596 return Use(value, new LUnallocated(LUnallocated::WRITABLE_REGISTER));
597 }
598
599
Use(HValue * value)600 LOperand* LChunkBuilder::Use(HValue* value) {
601 return Use(value, new LUnallocated(LUnallocated::NONE));
602 }
603
604
UseAtStart(HValue * value)605 LOperand* LChunkBuilder::UseAtStart(HValue* value) {
606 return Use(value, new LUnallocated(LUnallocated::NONE,
607 LUnallocated::USED_AT_START));
608 }
609
610
UseOrConstant(HValue * value)611 LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
612 return value->IsConstant()
613 ? chunk_->DefineConstantOperand(HConstant::cast(value))
614 : Use(value);
615 }
616
617
UseOrConstantAtStart(HValue * value)618 LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
619 return value->IsConstant()
620 ? chunk_->DefineConstantOperand(HConstant::cast(value))
621 : UseAtStart(value);
622 }
623
624
UseRegisterOrConstant(HValue * value)625 LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
626 return value->IsConstant()
627 ? chunk_->DefineConstantOperand(HConstant::cast(value))
628 : UseRegister(value);
629 }
630
631
UseRegisterOrConstantAtStart(HValue * value)632 LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
633 return value->IsConstant()
634 ? chunk_->DefineConstantOperand(HConstant::cast(value))
635 : UseRegisterAtStart(value);
636 }
637
638
UseAny(HValue * value)639 LOperand* LChunkBuilder::UseAny(HValue* value) {
640 return value->IsConstant()
641 ? chunk_->DefineConstantOperand(HConstant::cast(value))
642 : Use(value, new LUnallocated(LUnallocated::ANY));
643 }
644
645
Use(HValue * value,LUnallocated * operand)646 LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
647 if (value->EmitAtUses()) {
648 HInstruction* instr = HInstruction::cast(value);
649 VisitInstruction(instr);
650 }
651 allocator_->RecordUse(value, operand);
652 return operand;
653 }
654
655
656 template<int I, int T>
Define(LTemplateInstruction<1,I,T> * instr,LUnallocated * result)657 LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
658 LUnallocated* result) {
659 allocator_->RecordDefinition(current_instruction_, result);
660 instr->set_result(result);
661 return instr;
662 }
663
664
665 template<int I, int T>
Define(LTemplateInstruction<1,I,T> * instr)666 LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr) {
667 return Define(instr, new LUnallocated(LUnallocated::NONE));
668 }
669
670
671 template<int I, int T>
DefineAsRegister(LTemplateInstruction<1,I,T> * instr)672 LInstruction* LChunkBuilder::DefineAsRegister(
673 LTemplateInstruction<1, I, T>* instr) {
674 return Define(instr, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
675 }
676
677
678 template<int I, int T>
DefineAsSpilled(LTemplateInstruction<1,I,T> * instr,int index)679 LInstruction* LChunkBuilder::DefineAsSpilled(
680 LTemplateInstruction<1, I, T>* instr, int index) {
681 return Define(instr, new LUnallocated(LUnallocated::FIXED_SLOT, index));
682 }
683
684
685 template<int I, int T>
DefineSameAsFirst(LTemplateInstruction<1,I,T> * instr)686 LInstruction* LChunkBuilder::DefineSameAsFirst(
687 LTemplateInstruction<1, I, T>* instr) {
688 return Define(instr, new LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
689 }
690
691
692 template<int I, int T>
DefineFixed(LTemplateInstruction<1,I,T> * instr,Register reg)693 LInstruction* LChunkBuilder::DefineFixed(
694 LTemplateInstruction<1, I, T>* instr, Register reg) {
695 return Define(instr, ToUnallocated(reg));
696 }
697
698
699 template<int I, int T>
DefineFixedDouble(LTemplateInstruction<1,I,T> * instr,DoubleRegister reg)700 LInstruction* LChunkBuilder::DefineFixedDouble(
701 LTemplateInstruction<1, I, T>* instr, DoubleRegister reg) {
702 return Define(instr, ToUnallocated(reg));
703 }
704
705
AssignEnvironment(LInstruction * instr)706 LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
707 HEnvironment* hydrogen_env = current_block_->last_environment();
708 instr->set_environment(CreateEnvironment(hydrogen_env));
709 return instr;
710 }
711
712
SetInstructionPendingDeoptimizationEnvironment(LInstruction * instr,int ast_id)713 LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
714 LInstruction* instr, int ast_id) {
715 ASSERT(instruction_pending_deoptimization_environment_ == NULL);
716 ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
717 instruction_pending_deoptimization_environment_ = instr;
718 pending_deoptimization_ast_id_ = ast_id;
719 return instr;
720 }
721
722
ClearInstructionPendingDeoptimizationEnvironment()723 void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
724 instruction_pending_deoptimization_environment_ = NULL;
725 pending_deoptimization_ast_id_ = AstNode::kNoNumber;
726 }
727
728
MarkAsCall(LInstruction * instr,HInstruction * hinstr,CanDeoptimize can_deoptimize)729 LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
730 HInstruction* hinstr,
731 CanDeoptimize can_deoptimize) {
732 #ifdef DEBUG
733 instr->VerifyCall();
734 #endif
735 instr->MarkAsCall();
736 instr = AssignPointerMap(instr);
737
738 if (hinstr->HasSideEffects()) {
739 ASSERT(hinstr->next()->IsSimulate());
740 HSimulate* sim = HSimulate::cast(hinstr->next());
741 instr = SetInstructionPendingDeoptimizationEnvironment(
742 instr, sim->ast_id());
743 }
744
745 // If instruction does not have side-effects lazy deoptimization
746 // after the call will try to deoptimize to the point before the call.
747 // Thus we still need to attach environment to this call even if
748 // call sequence can not deoptimize eagerly.
749 bool needs_environment =
750 (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) || !hinstr->HasSideEffects();
751 if (needs_environment && !instr->HasEnvironment()) {
752 instr = AssignEnvironment(instr);
753 }
754
755 return instr;
756 }
757
758
MarkAsSaveDoubles(LInstruction * instr)759 LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) {
760 instr->MarkAsSaveDoubles();
761 return instr;
762 }
763
764
AssignPointerMap(LInstruction * instr)765 LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
766 ASSERT(!instr->HasPointerMap());
767 instr->set_pointer_map(new LPointerMap(position_));
768 return instr;
769 }
770
771
TempRegister()772 LUnallocated* LChunkBuilder::TempRegister() {
773 LUnallocated* operand = new LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
774 allocator_->RecordTemporary(operand);
775 return operand;
776 }
777
778
FixedTemp(Register reg)779 LOperand* LChunkBuilder::FixedTemp(Register reg) {
780 LUnallocated* operand = ToUnallocated(reg);
781 allocator_->RecordTemporary(operand);
782 return operand;
783 }
784
785
FixedTemp(DoubleRegister reg)786 LOperand* LChunkBuilder::FixedTemp(DoubleRegister reg) {
787 LUnallocated* operand = ToUnallocated(reg);
788 allocator_->RecordTemporary(operand);
789 return operand;
790 }
791
792
DoBlockEntry(HBlockEntry * instr)793 LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
794 return new LLabel(instr->block());
795 }
796
797
DoDeoptimize(HDeoptimize * instr)798 LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
799 return AssignEnvironment(new LDeoptimize);
800 }
801
802
DoBit(Token::Value op,HBitwiseBinaryOperation * instr)803 LInstruction* LChunkBuilder::DoBit(Token::Value op,
804 HBitwiseBinaryOperation* instr) {
805 if (instr->representation().IsInteger32()) {
806 ASSERT(instr->left()->representation().IsInteger32());
807 ASSERT(instr->right()->representation().IsInteger32());
808
809 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
810 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
811 return DefineSameAsFirst(new LBitI(op, left, right));
812 } else {
813 ASSERT(instr->representation().IsTagged());
814 ASSERT(instr->left()->representation().IsTagged());
815 ASSERT(instr->right()->representation().IsTagged());
816
817 LOperand* left = UseFixed(instr->left(), r1);
818 LOperand* right = UseFixed(instr->right(), r0);
819 LArithmeticT* result = new LArithmeticT(op, left, right);
820 return MarkAsCall(DefineFixed(result, r0), instr);
821 }
822 }
823
824
DoShift(Token::Value op,HBitwiseBinaryOperation * instr)825 LInstruction* LChunkBuilder::DoShift(Token::Value op,
826 HBitwiseBinaryOperation* instr) {
827 if (instr->representation().IsTagged()) {
828 ASSERT(instr->left()->representation().IsTagged());
829 ASSERT(instr->right()->representation().IsTagged());
830
831 LOperand* left = UseFixed(instr->left(), r1);
832 LOperand* right = UseFixed(instr->right(), r0);
833 LArithmeticT* result = new LArithmeticT(op, left, right);
834 return MarkAsCall(DefineFixed(result, r0), instr);
835 }
836
837 ASSERT(instr->representation().IsInteger32());
838 ASSERT(instr->OperandAt(0)->representation().IsInteger32());
839 ASSERT(instr->OperandAt(1)->representation().IsInteger32());
840 LOperand* left = UseRegisterAtStart(instr->OperandAt(0));
841
842 HValue* right_value = instr->OperandAt(1);
843 LOperand* right = NULL;
844 int constant_value = 0;
845 if (right_value->IsConstant()) {
846 HConstant* constant = HConstant::cast(right_value);
847 right = chunk_->DefineConstantOperand(constant);
848 constant_value = constant->Integer32Value() & 0x1f;
849 } else {
850 right = UseRegister(right_value);
851 }
852
853 // Shift operations can only deoptimize if we do a logical shift
854 // by 0 and the result cannot be truncated to int32.
855 bool can_deopt = (op == Token::SHR && constant_value == 0);
856 if (can_deopt) {
857 bool can_truncate = true;
858 for (int i = 0; i < instr->uses()->length(); i++) {
859 if (!instr->uses()->at(i)->CheckFlag(HValue::kTruncatingToInt32)) {
860 can_truncate = false;
861 break;
862 }
863 }
864 can_deopt = !can_truncate;
865 }
866
867 LInstruction* result =
868 DefineSameAsFirst(new LShiftI(op, left, right, can_deopt));
869 if (can_deopt) AssignEnvironment(result);
870 return result;
871 }
872
873
DoArithmeticD(Token::Value op,HArithmeticBinaryOperation * instr)874 LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
875 HArithmeticBinaryOperation* instr) {
876 ASSERT(instr->representation().IsDouble());
877 ASSERT(instr->left()->representation().IsDouble());
878 ASSERT(instr->right()->representation().IsDouble());
879 ASSERT(op != Token::MOD);
880 LOperand* left = UseRegisterAtStart(instr->left());
881 LOperand* right = UseRegisterAtStart(instr->right());
882 LArithmeticD* result = new LArithmeticD(op, left, right);
883 return DefineSameAsFirst(result);
884 }
885
886
DoArithmeticT(Token::Value op,HArithmeticBinaryOperation * instr)887 LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
888 HArithmeticBinaryOperation* instr) {
889 ASSERT(op == Token::ADD ||
890 op == Token::DIV ||
891 op == Token::MOD ||
892 op == Token::MUL ||
893 op == Token::SUB);
894 HValue* left = instr->left();
895 HValue* right = instr->right();
896 ASSERT(left->representation().IsTagged());
897 ASSERT(right->representation().IsTagged());
898 LOperand* left_operand = UseFixed(left, r1);
899 LOperand* right_operand = UseFixed(right, r0);
900 LArithmeticT* result = new LArithmeticT(op, left_operand, right_operand);
901 return MarkAsCall(DefineFixed(result, r0), instr);
902 }
903
904
DoBasicBlock(HBasicBlock * block,HBasicBlock * next_block)905 void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
906 ASSERT(is_building());
907 current_block_ = block;
908 next_block_ = next_block;
909 if (block->IsStartBlock()) {
910 block->UpdateEnvironment(graph_->start_environment());
911 argument_count_ = 0;
912 } else if (block->predecessors()->length() == 1) {
913 // We have a single predecessor => copy environment and outgoing
914 // argument count from the predecessor.
915 ASSERT(block->phis()->length() == 0);
916 HBasicBlock* pred = block->predecessors()->at(0);
917 HEnvironment* last_environment = pred->last_environment();
918 ASSERT(last_environment != NULL);
919 // Only copy the environment, if it is later used again.
920 if (pred->end()->SecondSuccessor() == NULL) {
921 ASSERT(pred->end()->FirstSuccessor() == block);
922 } else {
923 if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
924 pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
925 last_environment = last_environment->Copy();
926 }
927 }
928 block->UpdateEnvironment(last_environment);
929 ASSERT(pred->argument_count() >= 0);
930 argument_count_ = pred->argument_count();
931 } else {
932 // We are at a state join => process phis.
933 HBasicBlock* pred = block->predecessors()->at(0);
934 // No need to copy the environment, it cannot be used later.
935 HEnvironment* last_environment = pred->last_environment();
936 for (int i = 0; i < block->phis()->length(); ++i) {
937 HPhi* phi = block->phis()->at(i);
938 last_environment->SetValueAt(phi->merged_index(), phi);
939 }
940 for (int i = 0; i < block->deleted_phis()->length(); ++i) {
941 last_environment->SetValueAt(block->deleted_phis()->at(i),
942 graph_->GetConstantUndefined());
943 }
944 block->UpdateEnvironment(last_environment);
945 // Pick up the outgoing argument count of one of the predecessors.
946 argument_count_ = pred->argument_count();
947 }
948 HInstruction* current = block->first();
949 int start = chunk_->instructions()->length();
950 while (current != NULL && !is_aborted()) {
951 // Code for constants in registers is generated lazily.
952 if (!current->EmitAtUses()) {
953 VisitInstruction(current);
954 }
955 current = current->next();
956 }
957 int end = chunk_->instructions()->length() - 1;
958 if (end >= start) {
959 block->set_first_instruction_index(start);
960 block->set_last_instruction_index(end);
961 }
962 block->set_argument_count(argument_count_);
963 next_block_ = NULL;
964 current_block_ = NULL;
965 }
966
967
VisitInstruction(HInstruction * current)968 void LChunkBuilder::VisitInstruction(HInstruction* current) {
969 HInstruction* old_current = current_instruction_;
970 current_instruction_ = current;
971 if (current->has_position()) position_ = current->position();
972 LInstruction* instr = current->CompileToLithium(this);
973
974 if (instr != NULL) {
975 if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
976 instr = AssignPointerMap(instr);
977 }
978 if (FLAG_stress_environments && !instr->HasEnvironment()) {
979 instr = AssignEnvironment(instr);
980 }
981 if (current->IsTest() && !instr->IsGoto()) {
982 ASSERT(instr->IsControl());
983 HTest* test = HTest::cast(current);
984 instr->set_hydrogen_value(test->value());
985 HBasicBlock* first = test->FirstSuccessor();
986 HBasicBlock* second = test->SecondSuccessor();
987 ASSERT(first != NULL && second != NULL);
988 instr->SetBranchTargets(first->block_id(), second->block_id());
989 } else {
990 instr->set_hydrogen_value(current);
991 }
992
993 chunk_->AddInstruction(instr, current_block_);
994 }
995 current_instruction_ = old_current;
996 }
997
998
CreateEnvironment(HEnvironment * hydrogen_env)999 LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) {
1000 if (hydrogen_env == NULL) return NULL;
1001
1002 LEnvironment* outer = CreateEnvironment(hydrogen_env->outer());
1003 int ast_id = hydrogen_env->ast_id();
1004 ASSERT(ast_id != AstNode::kNoNumber);
1005 int value_count = hydrogen_env->length();
1006 LEnvironment* result = new LEnvironment(hydrogen_env->closure(),
1007 ast_id,
1008 hydrogen_env->parameter_count(),
1009 argument_count_,
1010 value_count,
1011 outer);
1012 int argument_index = 0;
1013 for (int i = 0; i < value_count; ++i) {
1014 HValue* value = hydrogen_env->values()->at(i);
1015 LOperand* op = NULL;
1016 if (value->IsArgumentsObject()) {
1017 op = NULL;
1018 } else if (value->IsPushArgument()) {
1019 op = new LArgument(argument_index++);
1020 } else {
1021 op = UseAny(value);
1022 }
1023 result->AddValue(op, value->representation());
1024 }
1025
1026 return result;
1027 }
1028
1029
DoGoto(HGoto * instr)1030 LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
1031 LInstruction* result = new LGoto(instr->FirstSuccessor()->block_id(),
1032 instr->include_stack_check());
1033 if (instr->include_stack_check()) result = AssignPointerMap(result);
1034 return result;
1035 }
1036
1037
DoTest(HTest * instr)1038 LInstruction* LChunkBuilder::DoTest(HTest* instr) {
1039 HValue* v = instr->value();
1040 if (v->EmitAtUses()) {
1041 if (v->IsClassOfTest()) {
1042 HClassOfTest* compare = HClassOfTest::cast(v);
1043 ASSERT(compare->value()->representation().IsTagged());
1044
1045 return new LClassOfTestAndBranch(UseTempRegister(compare->value()),
1046 TempRegister());
1047 } else if (v->IsCompare()) {
1048 HCompare* compare = HCompare::cast(v);
1049 Token::Value op = compare->token();
1050 HValue* left = compare->left();
1051 HValue* right = compare->right();
1052 Representation r = compare->GetInputRepresentation();
1053 if (r.IsInteger32()) {
1054 ASSERT(left->representation().IsInteger32());
1055 ASSERT(right->representation().IsInteger32());
1056 return new LCmpIDAndBranch(UseRegisterAtStart(left),
1057 UseRegisterAtStart(right));
1058 } else if (r.IsDouble()) {
1059 ASSERT(left->representation().IsDouble());
1060 ASSERT(right->representation().IsDouble());
1061 return new LCmpIDAndBranch(UseRegisterAtStart(left),
1062 UseRegisterAtStart(right));
1063 } else {
1064 ASSERT(left->representation().IsTagged());
1065 ASSERT(right->representation().IsTagged());
1066 bool reversed = op == Token::GT || op == Token::LTE;
1067 LOperand* left_operand = UseFixed(left, reversed ? r0 : r1);
1068 LOperand* right_operand = UseFixed(right, reversed ? r1 : r0);
1069 LInstruction* result = new LCmpTAndBranch(left_operand,
1070 right_operand);
1071 return MarkAsCall(result, instr);
1072 }
1073 } else if (v->IsIsSmi()) {
1074 HIsSmi* compare = HIsSmi::cast(v);
1075 ASSERT(compare->value()->representation().IsTagged());
1076
1077 return new LIsSmiAndBranch(Use(compare->value()));
1078 } else if (v->IsHasInstanceType()) {
1079 HHasInstanceType* compare = HHasInstanceType::cast(v);
1080 ASSERT(compare->value()->representation().IsTagged());
1081 return new LHasInstanceTypeAndBranch(
1082 UseRegisterAtStart(compare->value()));
1083 } else if (v->IsHasCachedArrayIndex()) {
1084 HHasCachedArrayIndex* compare = HHasCachedArrayIndex::cast(v);
1085 ASSERT(compare->value()->representation().IsTagged());
1086
1087 return new LHasCachedArrayIndexAndBranch(
1088 UseRegisterAtStart(compare->value()));
1089 } else if (v->IsIsNull()) {
1090 HIsNull* compare = HIsNull::cast(v);
1091 ASSERT(compare->value()->representation().IsTagged());
1092
1093 return new LIsNullAndBranch(UseRegisterAtStart(compare->value()));
1094 } else if (v->IsIsObject()) {
1095 HIsObject* compare = HIsObject::cast(v);
1096 ASSERT(compare->value()->representation().IsTagged());
1097
1098 LOperand* temp = TempRegister();
1099 return new LIsObjectAndBranch(UseRegister(compare->value()), temp);
1100 } else if (v->IsCompareJSObjectEq()) {
1101 HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
1102 return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()),
1103 UseRegisterAtStart(compare->right()));
1104 } else if (v->IsInstanceOf()) {
1105 HInstanceOf* instance_of = HInstanceOf::cast(v);
1106 LInstruction* result =
1107 new LInstanceOfAndBranch(UseFixed(instance_of->left(), r0),
1108 UseFixed(instance_of->right(), r1));
1109 return MarkAsCall(result, instr);
1110 } else if (v->IsTypeofIs()) {
1111 HTypeofIs* typeof_is = HTypeofIs::cast(v);
1112 return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
1113 } else if (v->IsIsConstructCall()) {
1114 return new LIsConstructCallAndBranch(TempRegister());
1115 } else {
1116 if (v->IsConstant()) {
1117 if (HConstant::cast(v)->ToBoolean()) {
1118 return new LGoto(instr->FirstSuccessor()->block_id());
1119 } else {
1120 return new LGoto(instr->SecondSuccessor()->block_id());
1121 }
1122 }
1123 Abort("Undefined compare before branch");
1124 return NULL;
1125 }
1126 }
1127 return new LBranch(UseRegisterAtStart(v));
1128 }
1129
1130
DoCompareMap(HCompareMap * instr)1131 LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
1132 ASSERT(instr->value()->representation().IsTagged());
1133 LOperand* value = UseRegisterAtStart(instr->value());
1134 LOperand* temp = TempRegister();
1135 return new LCmpMapAndBranch(value, temp);
1136 }
1137
1138
DoArgumentsLength(HArgumentsLength * length)1139 LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) {
1140 return DefineAsRegister(new LArgumentsLength(UseRegister(length->value())));
1141 }
1142
1143
DoArgumentsElements(HArgumentsElements * elems)1144 LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
1145 return DefineAsRegister(new LArgumentsElements);
1146 }
1147
1148
DoInstanceOf(HInstanceOf * instr)1149 LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
1150 LInstanceOf* result =
1151 new LInstanceOf(UseFixed(instr->left(), r0),
1152 UseFixed(instr->right(), r1));
1153 return MarkAsCall(DefineFixed(result, r0), instr);
1154 }
1155
1156
DoInstanceOfKnownGlobal(HInstanceOfKnownGlobal * instr)1157 LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
1158 HInstanceOfKnownGlobal* instr) {
1159 LInstanceOfKnownGlobal* result =
1160 new LInstanceOfKnownGlobal(UseFixed(instr->value(), r0), FixedTemp(r4));
1161 return MarkAsCall(DefineFixed(result, r0), instr);
1162 }
1163
1164
DoApplyArguments(HApplyArguments * instr)1165 LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
1166 LOperand* function = UseFixed(instr->function(), r1);
1167 LOperand* receiver = UseFixed(instr->receiver(), r0);
1168 LOperand* length = UseFixed(instr->length(), r2);
1169 LOperand* elements = UseFixed(instr->elements(), r3);
1170 LApplyArguments* result = new LApplyArguments(function,
1171 receiver,
1172 length,
1173 elements);
1174 return MarkAsCall(DefineFixed(result, r0), instr, CAN_DEOPTIMIZE_EAGERLY);
1175 }
1176
1177
DoPushArgument(HPushArgument * instr)1178 LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
1179 ++argument_count_;
1180 LOperand* argument = Use(instr->argument());
1181 return new LPushArgument(argument);
1182 }
1183
1184
DoContext(HContext * instr)1185 LInstruction* LChunkBuilder::DoContext(HContext* instr) {
1186 return DefineAsRegister(new LContext);
1187 }
1188
1189
DoOuterContext(HOuterContext * instr)1190 LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
1191 LOperand* context = UseRegisterAtStart(instr->value());
1192 return DefineAsRegister(new LOuterContext(context));
1193 }
1194
1195
DoGlobalObject(HGlobalObject * instr)1196 LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
1197 LOperand* context = UseRegisterAtStart(instr->value());
1198 return DefineAsRegister(new LGlobalObject(context));
1199 }
1200
1201
DoGlobalReceiver(HGlobalReceiver * instr)1202 LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
1203 LOperand* global_object = UseRegisterAtStart(instr->value());
1204 return DefineAsRegister(new LGlobalReceiver(global_object));
1205 }
1206
1207
DoCallConstantFunction(HCallConstantFunction * instr)1208 LInstruction* LChunkBuilder::DoCallConstantFunction(
1209 HCallConstantFunction* instr) {
1210 argument_count_ -= instr->argument_count();
1211 return MarkAsCall(DefineFixed(new LCallConstantFunction, r0), instr);
1212 }
1213
1214
DoUnaryMathOperation(HUnaryMathOperation * instr)1215 LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
1216 BuiltinFunctionId op = instr->op();
1217 if (op == kMathLog || op == kMathSin || op == kMathCos) {
1218 LOperand* input = UseFixedDouble(instr->value(), d2);
1219 LUnaryMathOperation* result = new LUnaryMathOperation(input, NULL);
1220 return MarkAsCall(DefineFixedDouble(result, d2), instr);
1221 } else {
1222 LOperand* input = UseRegisterAtStart(instr->value());
1223 LOperand* temp = (op == kMathFloor) ? TempRegister() : NULL;
1224 LUnaryMathOperation* result = new LUnaryMathOperation(input, temp);
1225 switch (op) {
1226 case kMathAbs:
1227 return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1228 case kMathFloor:
1229 return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
1230 case kMathSqrt:
1231 return DefineSameAsFirst(result);
1232 case kMathRound:
1233 return AssignEnvironment(DefineAsRegister(result));
1234 case kMathPowHalf:
1235 return DefineSameAsFirst(result);
1236 default:
1237 UNREACHABLE();
1238 return NULL;
1239 }
1240 }
1241 }
1242
1243
DoCallKeyed(HCallKeyed * instr)1244 LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
1245 ASSERT(instr->key()->representation().IsTagged());
1246 argument_count_ -= instr->argument_count();
1247 LOperand* key = UseFixed(instr->key(), r2);
1248 return MarkAsCall(DefineFixed(new LCallKeyed(key), r0), instr);
1249 }
1250
1251
DoCallNamed(HCallNamed * instr)1252 LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
1253 argument_count_ -= instr->argument_count();
1254 return MarkAsCall(DefineFixed(new LCallNamed, r0), instr);
1255 }
1256
1257
DoCallGlobal(HCallGlobal * instr)1258 LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
1259 argument_count_ -= instr->argument_count();
1260 return MarkAsCall(DefineFixed(new LCallGlobal, r0), instr);
1261 }
1262
1263
DoCallKnownGlobal(HCallKnownGlobal * instr)1264 LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
1265 argument_count_ -= instr->argument_count();
1266 return MarkAsCall(DefineFixed(new LCallKnownGlobal, r0), instr);
1267 }
1268
1269
DoCallNew(HCallNew * instr)1270 LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
1271 LOperand* constructor = UseFixed(instr->constructor(), r1);
1272 argument_count_ -= instr->argument_count();
1273 LCallNew* result = new LCallNew(constructor);
1274 return MarkAsCall(DefineFixed(result, r0), instr);
1275 }
1276
1277
DoCallFunction(HCallFunction * instr)1278 LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
1279 argument_count_ -= instr->argument_count();
1280 return MarkAsCall(DefineFixed(new LCallFunction, r0), instr);
1281 }
1282
1283
DoCallRuntime(HCallRuntime * instr)1284 LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1285 argument_count_ -= instr->argument_count();
1286 return MarkAsCall(DefineFixed(new LCallRuntime, r0), instr);
1287 }
1288
1289
DoShr(HShr * instr)1290 LInstruction* LChunkBuilder::DoShr(HShr* instr) {
1291 return DoShift(Token::SHR, instr);
1292 }
1293
1294
DoSar(HSar * instr)1295 LInstruction* LChunkBuilder::DoSar(HSar* instr) {
1296 return DoShift(Token::SAR, instr);
1297 }
1298
1299
DoShl(HShl * instr)1300 LInstruction* LChunkBuilder::DoShl(HShl* instr) {
1301 return DoShift(Token::SHL, instr);
1302 }
1303
1304
DoBitAnd(HBitAnd * instr)1305 LInstruction* LChunkBuilder::DoBitAnd(HBitAnd* instr) {
1306 return DoBit(Token::BIT_AND, instr);
1307 }
1308
1309
DoBitNot(HBitNot * instr)1310 LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
1311 ASSERT(instr->value()->representation().IsInteger32());
1312 ASSERT(instr->representation().IsInteger32());
1313 return DefineSameAsFirst(new LBitNotI(UseRegisterAtStart(instr->value())));
1314 }
1315
1316
DoBitOr(HBitOr * instr)1317 LInstruction* LChunkBuilder::DoBitOr(HBitOr* instr) {
1318 return DoBit(Token::BIT_OR, instr);
1319 }
1320
1321
DoBitXor(HBitXor * instr)1322 LInstruction* LChunkBuilder::DoBitXor(HBitXor* instr) {
1323 return DoBit(Token::BIT_XOR, instr);
1324 }
1325
1326
DoDiv(HDiv * instr)1327 LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1328 if (instr->representation().IsDouble()) {
1329 return DoArithmeticD(Token::DIV, instr);
1330 } else if (instr->representation().IsInteger32()) {
1331 // TODO(1042) The fixed register allocation
1332 // is needed because we call TypeRecordingBinaryOpStub from
1333 // the generated code, which requires registers r0
1334 // and r1 to be used. We should remove that
1335 // when we provide a native implementation.
1336 LOperand* dividend = UseFixed(instr->left(), r0);
1337 LOperand* divisor = UseFixed(instr->right(), r1);
1338 return AssignEnvironment(AssignPointerMap(
1339 DefineFixed(new LDivI(dividend, divisor), r0)));
1340 } else {
1341 return DoArithmeticT(Token::DIV, instr);
1342 }
1343 }
1344
1345
DoMod(HMod * instr)1346 LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1347 if (instr->representation().IsInteger32()) {
1348 ASSERT(instr->left()->representation().IsInteger32());
1349 ASSERT(instr->right()->representation().IsInteger32());
1350
1351 LModI* mod;
1352 if (instr->HasPowerOf2Divisor()) {
1353 ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
1354 LOperand* value = UseRegisterAtStart(instr->left());
1355 mod = new LModI(value, UseOrConstant(instr->right()));
1356 } else {
1357 LOperand* dividend = UseRegister(instr->left());
1358 LOperand* divisor = UseRegisterAtStart(instr->right());
1359 mod = new LModI(dividend,
1360 divisor,
1361 TempRegister(),
1362 FixedTemp(d1),
1363 FixedTemp(d2));
1364 }
1365
1366 return AssignEnvironment(DefineSameAsFirst(mod));
1367 } else if (instr->representation().IsTagged()) {
1368 return DoArithmeticT(Token::MOD, instr);
1369 } else {
1370 ASSERT(instr->representation().IsDouble());
1371 // We call a C function for double modulo. It can't trigger a GC.
1372 // We need to use fixed result register for the call.
1373 // TODO(fschneider): Allow any register as input registers.
1374 LOperand* left = UseFixedDouble(instr->left(), d1);
1375 LOperand* right = UseFixedDouble(instr->right(), d2);
1376 LArithmeticD* result = new LArithmeticD(Token::MOD, left, right);
1377 return MarkAsCall(DefineFixedDouble(result, d1), instr);
1378 }
1379 }
1380
1381
DoMul(HMul * instr)1382 LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1383 if (instr->representation().IsInteger32()) {
1384 ASSERT(instr->left()->representation().IsInteger32());
1385 ASSERT(instr->right()->representation().IsInteger32());
1386 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1387 LOperand* right = UseOrConstant(instr->MostConstantOperand());
1388 LOperand* temp = NULL;
1389 if (instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1390 temp = TempRegister();
1391 }
1392 LMulI* mul = new LMulI(left, right, temp);
1393 return AssignEnvironment(DefineSameAsFirst(mul));
1394 } else if (instr->representation().IsDouble()) {
1395 return DoArithmeticD(Token::MUL, instr);
1396 } else {
1397 return DoArithmeticT(Token::MUL, instr);
1398 }
1399 }
1400
1401
DoSub(HSub * instr)1402 LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1403 if (instr->representation().IsInteger32()) {
1404 ASSERT(instr->left()->representation().IsInteger32());
1405 ASSERT(instr->right()->representation().IsInteger32());
1406 LOperand* left = UseRegisterAtStart(instr->left());
1407 LOperand* right = UseOrConstantAtStart(instr->right());
1408 LSubI* sub = new LSubI(left, right);
1409 LInstruction* result = DefineSameAsFirst(sub);
1410 if (instr->CheckFlag(HValue::kCanOverflow)) {
1411 result = AssignEnvironment(result);
1412 }
1413 return result;
1414 } else if (instr->representation().IsDouble()) {
1415 return DoArithmeticD(Token::SUB, instr);
1416 } else {
1417 return DoArithmeticT(Token::SUB, instr);
1418 }
1419 }
1420
1421
DoAdd(HAdd * instr)1422 LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1423 if (instr->representation().IsInteger32()) {
1424 ASSERT(instr->left()->representation().IsInteger32());
1425 ASSERT(instr->right()->representation().IsInteger32());
1426 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1427 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
1428 LAddI* add = new LAddI(left, right);
1429 LInstruction* result = DefineSameAsFirst(add);
1430 if (instr->CheckFlag(HValue::kCanOverflow)) {
1431 result = AssignEnvironment(result);
1432 }
1433 return result;
1434 } else if (instr->representation().IsDouble()) {
1435 return DoArithmeticD(Token::ADD, instr);
1436 } else {
1437 ASSERT(instr->representation().IsTagged());
1438 return DoArithmeticT(Token::ADD, instr);
1439 }
1440 }
1441
1442
DoPower(HPower * instr)1443 LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1444 ASSERT(instr->representation().IsDouble());
1445 // We call a C function for double power. It can't trigger a GC.
1446 // We need to use fixed result register for the call.
1447 Representation exponent_type = instr->right()->representation();
1448 ASSERT(instr->left()->representation().IsDouble());
1449 LOperand* left = UseFixedDouble(instr->left(), d1);
1450 LOperand* right = exponent_type.IsDouble() ?
1451 UseFixedDouble(instr->right(), d2) :
1452 UseFixed(instr->right(), r0);
1453 LPower* result = new LPower(left, right);
1454 return MarkAsCall(DefineFixedDouble(result, d3),
1455 instr,
1456 CAN_DEOPTIMIZE_EAGERLY);
1457 }
1458
1459
DoCompare(HCompare * instr)1460 LInstruction* LChunkBuilder::DoCompare(HCompare* instr) {
1461 Token::Value op = instr->token();
1462 Representation r = instr->GetInputRepresentation();
1463 if (r.IsInteger32()) {
1464 ASSERT(instr->left()->representation().IsInteger32());
1465 ASSERT(instr->right()->representation().IsInteger32());
1466 LOperand* left = UseRegisterAtStart(instr->left());
1467 LOperand* right = UseRegisterAtStart(instr->right());
1468 return DefineAsRegister(new LCmpID(left, right));
1469 } else if (r.IsDouble()) {
1470 ASSERT(instr->left()->representation().IsDouble());
1471 ASSERT(instr->right()->representation().IsDouble());
1472 LOperand* left = UseRegisterAtStart(instr->left());
1473 LOperand* right = UseRegisterAtStart(instr->right());
1474 return DefineAsRegister(new LCmpID(left, right));
1475 } else {
1476 ASSERT(instr->left()->representation().IsTagged());
1477 ASSERT(instr->right()->representation().IsTagged());
1478 bool reversed = (op == Token::GT || op == Token::LTE);
1479 LOperand* left = UseFixed(instr->left(), reversed ? r0 : r1);
1480 LOperand* right = UseFixed(instr->right(), reversed ? r1 : r0);
1481 LCmpT* result = new LCmpT(left, right);
1482 return MarkAsCall(DefineFixed(result, r0), instr);
1483 }
1484 }
1485
1486
DoCompareJSObjectEq(HCompareJSObjectEq * instr)1487 LInstruction* LChunkBuilder::DoCompareJSObjectEq(
1488 HCompareJSObjectEq* instr) {
1489 LOperand* left = UseRegisterAtStart(instr->left());
1490 LOperand* right = UseRegisterAtStart(instr->right());
1491 LCmpJSObjectEq* result = new LCmpJSObjectEq(left, right);
1492 return DefineAsRegister(result);
1493 }
1494
1495
DoIsNull(HIsNull * instr)1496 LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) {
1497 ASSERT(instr->value()->representation().IsTagged());
1498 LOperand* value = UseRegisterAtStart(instr->value());
1499
1500 return DefineAsRegister(new LIsNull(value));
1501 }
1502
1503
DoIsObject(HIsObject * instr)1504 LInstruction* LChunkBuilder::DoIsObject(HIsObject* instr) {
1505 ASSERT(instr->value()->representation().IsTagged());
1506 LOperand* value = UseRegisterAtStart(instr->value());
1507
1508 return DefineAsRegister(new LIsObject(value));
1509 }
1510
1511
DoIsSmi(HIsSmi * instr)1512 LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) {
1513 ASSERT(instr->value()->representation().IsTagged());
1514 LOperand* value = UseAtStart(instr->value());
1515
1516 return DefineAsRegister(new LIsSmi(value));
1517 }
1518
1519
DoHasInstanceType(HHasInstanceType * instr)1520 LInstruction* LChunkBuilder::DoHasInstanceType(HHasInstanceType* instr) {
1521 ASSERT(instr->value()->representation().IsTagged());
1522 LOperand* value = UseRegisterAtStart(instr->value());
1523
1524 return DefineAsRegister(new LHasInstanceType(value));
1525 }
1526
1527
DoGetCachedArrayIndex(HGetCachedArrayIndex * instr)1528 LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
1529 HGetCachedArrayIndex* instr) {
1530 ASSERT(instr->value()->representation().IsTagged());
1531 LOperand* value = UseRegisterAtStart(instr->value());
1532
1533 return DefineAsRegister(new LGetCachedArrayIndex(value));
1534 }
1535
1536
DoHasCachedArrayIndex(HHasCachedArrayIndex * instr)1537 LInstruction* LChunkBuilder::DoHasCachedArrayIndex(
1538 HHasCachedArrayIndex* instr) {
1539 ASSERT(instr->value()->representation().IsTagged());
1540 LOperand* value = UseRegister(instr->value());
1541
1542 return DefineAsRegister(new LHasCachedArrayIndex(value));
1543 }
1544
1545
DoClassOfTest(HClassOfTest * instr)1546 LInstruction* LChunkBuilder::DoClassOfTest(HClassOfTest* instr) {
1547 ASSERT(instr->value()->representation().IsTagged());
1548 LOperand* value = UseTempRegister(instr->value());
1549 return DefineSameAsFirst(new LClassOfTest(value));
1550 }
1551
1552
DoJSArrayLength(HJSArrayLength * instr)1553 LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
1554 LOperand* array = UseRegisterAtStart(instr->value());
1555 return DefineAsRegister(new LJSArrayLength(array));
1556 }
1557
1558
DoExternalArrayLength(HExternalArrayLength * instr)1559 LInstruction* LChunkBuilder::DoExternalArrayLength(
1560 HExternalArrayLength* instr) {
1561 LOperand* array = UseRegisterAtStart(instr->value());
1562 return DefineAsRegister(new LExternalArrayLength(array));
1563 }
1564
1565
DoFixedArrayLength(HFixedArrayLength * instr)1566 LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
1567 LOperand* array = UseRegisterAtStart(instr->value());
1568 return DefineAsRegister(new LFixedArrayLength(array));
1569 }
1570
1571
DoValueOf(HValueOf * instr)1572 LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
1573 LOperand* object = UseRegister(instr->value());
1574 LValueOf* result = new LValueOf(object, TempRegister());
1575 return AssignEnvironment(DefineSameAsFirst(result));
1576 }
1577
1578
DoBoundsCheck(HBoundsCheck * instr)1579 LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1580 return AssignEnvironment(new LBoundsCheck(UseRegisterAtStart(instr->index()),
1581 UseRegister(instr->length())));
1582 }
1583
1584
DoAbnormalExit(HAbnormalExit * instr)1585 LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
1586 // The control instruction marking the end of a block that completed
1587 // abruptly (e.g., threw an exception). There is nothing specific to do.
1588 return NULL;
1589 }
1590
1591
DoThrow(HThrow * instr)1592 LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
1593 LOperand* value = UseFixed(instr->value(), r0);
1594 return MarkAsCall(new LThrow(value), instr);
1595 }
1596
1597
DoChange(HChange * instr)1598 LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1599 Representation from = instr->from();
1600 Representation to = instr->to();
1601 if (from.IsTagged()) {
1602 if (to.IsDouble()) {
1603 LOperand* value = UseRegister(instr->value());
1604 LNumberUntagD* res = new LNumberUntagD(value);
1605 return AssignEnvironment(DefineAsRegister(res));
1606 } else {
1607 ASSERT(to.IsInteger32());
1608 LOperand* value = UseRegister(instr->value());
1609 bool needs_check = !instr->value()->type().IsSmi();
1610 LInstruction* res = NULL;
1611 if (!needs_check) {
1612 res = DefineSameAsFirst(new LSmiUntag(value, needs_check));
1613 } else {
1614 LOperand* temp1 = TempRegister();
1615 LOperand* temp2 = instr->CanTruncateToInt32() ? TempRegister()
1616 : NULL;
1617 LOperand* temp3 = instr->CanTruncateToInt32() ? FixedTemp(d3)
1618 : NULL;
1619 res = DefineSameAsFirst(new LTaggedToI(value, temp1, temp2, temp3));
1620 res = AssignEnvironment(res);
1621 }
1622 return res;
1623 }
1624 } else if (from.IsDouble()) {
1625 if (to.IsTagged()) {
1626 LOperand* value = UseRegister(instr->value());
1627 LOperand* temp1 = TempRegister();
1628 LOperand* temp2 = TempRegister();
1629
1630 // Make sure that the temp and result_temp registers are
1631 // different.
1632 LUnallocated* result_temp = TempRegister();
1633 LNumberTagD* result = new LNumberTagD(value, temp1, temp2);
1634 Define(result, result_temp);
1635 return AssignPointerMap(result);
1636 } else {
1637 ASSERT(to.IsInteger32());
1638 LOperand* value = UseRegister(instr->value());
1639 LDoubleToI* res =
1640 new LDoubleToI(value,
1641 TempRegister(),
1642 instr->CanTruncateToInt32() ? TempRegister() : NULL);
1643 return AssignEnvironment(DefineAsRegister(res));
1644 }
1645 } else if (from.IsInteger32()) {
1646 if (to.IsTagged()) {
1647 HValue* val = instr->value();
1648 LOperand* value = UseRegister(val);
1649 if (val->HasRange() && val->range()->IsInSmiRange()) {
1650 return DefineSameAsFirst(new LSmiTag(value));
1651 } else {
1652 LNumberTagI* result = new LNumberTagI(value);
1653 return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1654 }
1655 } else {
1656 ASSERT(to.IsDouble());
1657 LOperand* value = Use(instr->value());
1658 return DefineAsRegister(new LInteger32ToDouble(value));
1659 }
1660 }
1661 UNREACHABLE();
1662 return NULL;
1663 }
1664
1665
DoCheckNonSmi(HCheckNonSmi * instr)1666 LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
1667 LOperand* value = UseRegisterAtStart(instr->value());
1668 return AssignEnvironment(new LCheckNonSmi(value));
1669 }
1670
1671
DoCheckInstanceType(HCheckInstanceType * instr)1672 LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
1673 LOperand* value = UseRegisterAtStart(instr->value());
1674 LInstruction* result = new LCheckInstanceType(value);
1675 return AssignEnvironment(result);
1676 }
1677
1678
DoCheckPrototypeMaps(HCheckPrototypeMaps * instr)1679 LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
1680 LOperand* temp1 = TempRegister();
1681 LOperand* temp2 = TempRegister();
1682 LInstruction* result = new LCheckPrototypeMaps(temp1, temp2);
1683 return AssignEnvironment(result);
1684 }
1685
1686
DoCheckSmi(HCheckSmi * instr)1687 LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
1688 LOperand* value = UseRegisterAtStart(instr->value());
1689 return AssignEnvironment(new LCheckSmi(value));
1690 }
1691
1692
DoCheckFunction(HCheckFunction * instr)1693 LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
1694 LOperand* value = UseRegisterAtStart(instr->value());
1695 return AssignEnvironment(new LCheckFunction(value));
1696 }
1697
1698
DoCheckMap(HCheckMap * instr)1699 LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) {
1700 LOperand* value = UseRegisterAtStart(instr->value());
1701 LInstruction* result = new LCheckMap(value);
1702 return AssignEnvironment(result);
1703 }
1704
1705
DoReturn(HReturn * instr)1706 LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
1707 return new LReturn(UseFixed(instr->value(), r0));
1708 }
1709
1710
DoConstant(HConstant * instr)1711 LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
1712 Representation r = instr->representation();
1713 if (r.IsInteger32()) {
1714 return DefineAsRegister(new LConstantI);
1715 } else if (r.IsDouble()) {
1716 return DefineAsRegister(new LConstantD);
1717 } else if (r.IsTagged()) {
1718 return DefineAsRegister(new LConstantT);
1719 } else {
1720 UNREACHABLE();
1721 return NULL;
1722 }
1723 }
1724
1725
DoLoadGlobalCell(HLoadGlobalCell * instr)1726 LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) {
1727 LLoadGlobalCell* result = new LLoadGlobalCell;
1728 return instr->check_hole_value()
1729 ? AssignEnvironment(DefineAsRegister(result))
1730 : DefineAsRegister(result);
1731 }
1732
1733
DoLoadGlobalGeneric(HLoadGlobalGeneric * instr)1734 LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
1735 LOperand* global_object = UseFixed(instr->global_object(), r0);
1736 LLoadGlobalGeneric* result = new LLoadGlobalGeneric(global_object);
1737 return MarkAsCall(DefineFixed(result, r0), instr);
1738 }
1739
1740
DoStoreGlobalCell(HStoreGlobalCell * instr)1741 LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
1742 if (instr->check_hole_value()) {
1743 LOperand* temp = TempRegister();
1744 LOperand* value = UseRegister(instr->value());
1745 return AssignEnvironment(new LStoreGlobalCell(value, temp));
1746 } else {
1747 LOperand* value = UseRegisterAtStart(instr->value());
1748 return new LStoreGlobalCell(value, NULL);
1749 }
1750 }
1751
1752
DoStoreGlobalGeneric(HStoreGlobalGeneric * instr)1753 LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) {
1754 LOperand* global_object = UseFixed(instr->global_object(), r1);
1755 LOperand* value = UseFixed(instr->value(), r0);
1756 LStoreGlobalGeneric* result =
1757 new LStoreGlobalGeneric(global_object, value);
1758 return MarkAsCall(result, instr);
1759 }
1760
1761
DoLoadContextSlot(HLoadContextSlot * instr)1762 LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
1763 LOperand* context = UseRegisterAtStart(instr->value());
1764 return DefineAsRegister(new LLoadContextSlot(context));
1765 }
1766
1767
DoStoreContextSlot(HStoreContextSlot * instr)1768 LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
1769 LOperand* context;
1770 LOperand* value;
1771 if (instr->NeedsWriteBarrier()) {
1772 context = UseTempRegister(instr->context());
1773 value = UseTempRegister(instr->value());
1774 } else {
1775 context = UseRegister(instr->context());
1776 value = UseRegister(instr->value());
1777 }
1778 return new LStoreContextSlot(context, value);
1779 }
1780
1781
DoLoadNamedField(HLoadNamedField * instr)1782 LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
1783 return DefineAsRegister(
1784 new LLoadNamedField(UseRegisterAtStart(instr->object())));
1785 }
1786
1787
DoLoadNamedFieldPolymorphic(HLoadNamedFieldPolymorphic * instr)1788 LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic(
1789 HLoadNamedFieldPolymorphic* instr) {
1790 ASSERT(instr->representation().IsTagged());
1791 if (instr->need_generic()) {
1792 LOperand* obj = UseFixed(instr->object(), r0);
1793 LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj);
1794 return MarkAsCall(DefineFixed(result, r0), instr);
1795 } else {
1796 LOperand* obj = UseRegisterAtStart(instr->object());
1797 LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj);
1798 return AssignEnvironment(DefineAsRegister(result));
1799 }
1800 }
1801
1802
DoLoadNamedGeneric(HLoadNamedGeneric * instr)1803 LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
1804 LOperand* object = UseFixed(instr->object(), r0);
1805 LInstruction* result = DefineFixed(new LLoadNamedGeneric(object), r0);
1806 return MarkAsCall(result, instr);
1807 }
1808
1809
DoLoadFunctionPrototype(HLoadFunctionPrototype * instr)1810 LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
1811 HLoadFunctionPrototype* instr) {
1812 return AssignEnvironment(DefineAsRegister(
1813 new LLoadFunctionPrototype(UseRegister(instr->function()))));
1814 }
1815
1816
DoLoadElements(HLoadElements * instr)1817 LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
1818 LOperand* input = UseRegisterAtStart(instr->value());
1819 return DefineAsRegister(new LLoadElements(input));
1820 }
1821
1822
DoLoadExternalArrayPointer(HLoadExternalArrayPointer * instr)1823 LInstruction* LChunkBuilder::DoLoadExternalArrayPointer(
1824 HLoadExternalArrayPointer* instr) {
1825 LOperand* input = UseRegisterAtStart(instr->value());
1826 return DefineAsRegister(new LLoadExternalArrayPointer(input));
1827 }
1828
1829
DoLoadKeyedFastElement(HLoadKeyedFastElement * instr)1830 LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
1831 HLoadKeyedFastElement* instr) {
1832 ASSERT(instr->representation().IsTagged());
1833 ASSERT(instr->key()->representation().IsInteger32());
1834 LOperand* obj = UseRegisterAtStart(instr->object());
1835 LOperand* key = UseRegisterAtStart(instr->key());
1836 LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key);
1837 return AssignEnvironment(DefineSameAsFirst(result));
1838 }
1839
1840
DoLoadKeyedSpecializedArrayElement(HLoadKeyedSpecializedArrayElement * instr)1841 LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
1842 HLoadKeyedSpecializedArrayElement* instr) {
1843 ExternalArrayType array_type = instr->array_type();
1844 Representation representation(instr->representation());
1845 ASSERT((representation.IsInteger32() && array_type != kExternalFloatArray) ||
1846 (representation.IsDouble() && array_type == kExternalFloatArray));
1847 ASSERT(instr->key()->representation().IsInteger32());
1848 LOperand* external_pointer = UseRegister(instr->external_pointer());
1849 LOperand* key = UseRegister(instr->key());
1850 LLoadKeyedSpecializedArrayElement* result =
1851 new LLoadKeyedSpecializedArrayElement(external_pointer, key);
1852 LInstruction* load_instr = DefineAsRegister(result);
1853 // An unsigned int array load might overflow and cause a deopt, make sure it
1854 // has an environment.
1855 return (array_type == kExternalUnsignedIntArray) ?
1856 AssignEnvironment(load_instr) : load_instr;
1857 }
1858
1859
DoLoadKeyedGeneric(HLoadKeyedGeneric * instr)1860 LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
1861 LOperand* object = UseFixed(instr->object(), r1);
1862 LOperand* key = UseFixed(instr->key(), r0);
1863
1864 LInstruction* result =
1865 DefineFixed(new LLoadKeyedGeneric(object, key), r0);
1866 return MarkAsCall(result, instr);
1867 }
1868
1869
DoStoreKeyedFastElement(HStoreKeyedFastElement * instr)1870 LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
1871 HStoreKeyedFastElement* instr) {
1872 bool needs_write_barrier = instr->NeedsWriteBarrier();
1873 ASSERT(instr->value()->representation().IsTagged());
1874 ASSERT(instr->object()->representation().IsTagged());
1875 ASSERT(instr->key()->representation().IsInteger32());
1876
1877 LOperand* obj = UseTempRegister(instr->object());
1878 LOperand* val = needs_write_barrier
1879 ? UseTempRegister(instr->value())
1880 : UseRegisterAtStart(instr->value());
1881 LOperand* key = needs_write_barrier
1882 ? UseTempRegister(instr->key())
1883 : UseRegisterOrConstantAtStart(instr->key());
1884
1885 return AssignEnvironment(new LStoreKeyedFastElement(obj, key, val));
1886 }
1887
1888
DoStoreKeyedSpecializedArrayElement(HStoreKeyedSpecializedArrayElement * instr)1889 LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
1890 HStoreKeyedSpecializedArrayElement* instr) {
1891 Representation representation(instr->value()->representation());
1892 ExternalArrayType array_type = instr->array_type();
1893 ASSERT((representation.IsInteger32() && array_type != kExternalFloatArray) ||
1894 (representation.IsDouble() && array_type == kExternalFloatArray));
1895 ASSERT(instr->external_pointer()->representation().IsExternal());
1896 ASSERT(instr->key()->representation().IsInteger32());
1897
1898 LOperand* external_pointer = UseRegister(instr->external_pointer());
1899 bool val_is_temp_register = array_type == kExternalPixelArray ||
1900 array_type == kExternalFloatArray;
1901 LOperand* val = val_is_temp_register
1902 ? UseTempRegister(instr->value())
1903 : UseRegister(instr->value());
1904 LOperand* key = UseRegister(instr->key());
1905
1906 return new LStoreKeyedSpecializedArrayElement(external_pointer,
1907 key,
1908 val);
1909 }
1910
1911
DoStoreKeyedGeneric(HStoreKeyedGeneric * instr)1912 LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
1913 LOperand* obj = UseFixed(instr->object(), r2);
1914 LOperand* key = UseFixed(instr->key(), r1);
1915 LOperand* val = UseFixed(instr->value(), r0);
1916
1917 ASSERT(instr->object()->representation().IsTagged());
1918 ASSERT(instr->key()->representation().IsTagged());
1919 ASSERT(instr->value()->representation().IsTagged());
1920
1921 return MarkAsCall(new LStoreKeyedGeneric(obj, key, val), instr);
1922 }
1923
1924
DoStoreNamedField(HStoreNamedField * instr)1925 LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
1926 bool needs_write_barrier = instr->NeedsWriteBarrier();
1927
1928 LOperand* obj = needs_write_barrier
1929 ? UseTempRegister(instr->object())
1930 : UseRegisterAtStart(instr->object());
1931
1932 LOperand* val = needs_write_barrier
1933 ? UseTempRegister(instr->value())
1934 : UseRegister(instr->value());
1935
1936 return new LStoreNamedField(obj, val);
1937 }
1938
1939
DoStoreNamedGeneric(HStoreNamedGeneric * instr)1940 LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
1941 LOperand* obj = UseFixed(instr->object(), r1);
1942 LOperand* val = UseFixed(instr->value(), r0);
1943
1944 LInstruction* result = new LStoreNamedGeneric(obj, val);
1945 return MarkAsCall(result, instr);
1946 }
1947
1948
DoStringCharCodeAt(HStringCharCodeAt * instr)1949 LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
1950 LOperand* string = UseRegister(instr->string());
1951 LOperand* index = UseRegisterOrConstant(instr->index());
1952 LStringCharCodeAt* result = new LStringCharCodeAt(string, index);
1953 return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
1954 }
1955
1956
DoStringCharFromCode(HStringCharFromCode * instr)1957 LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
1958 LOperand* char_code = UseRegister(instr->value());
1959 LStringCharFromCode* result = new LStringCharFromCode(char_code);
1960 return AssignPointerMap(DefineAsRegister(result));
1961 }
1962
1963
DoStringLength(HStringLength * instr)1964 LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
1965 LOperand* string = UseRegisterAtStart(instr->value());
1966 return DefineAsRegister(new LStringLength(string));
1967 }
1968
1969
DoArrayLiteral(HArrayLiteral * instr)1970 LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
1971 return MarkAsCall(DefineFixed(new LArrayLiteral, r0), instr);
1972 }
1973
1974
DoObjectLiteral(HObjectLiteral * instr)1975 LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) {
1976 return MarkAsCall(DefineFixed(new LObjectLiteral, r0), instr);
1977 }
1978
1979
DoRegExpLiteral(HRegExpLiteral * instr)1980 LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
1981 return MarkAsCall(DefineFixed(new LRegExpLiteral, r0), instr);
1982 }
1983
1984
DoFunctionLiteral(HFunctionLiteral * instr)1985 LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
1986 return MarkAsCall(DefineFixed(new LFunctionLiteral, r0), instr);
1987 }
1988
1989
DoDeleteProperty(HDeleteProperty * instr)1990 LInstruction* LChunkBuilder::DoDeleteProperty(HDeleteProperty* instr) {
1991 LOperand* object = UseFixed(instr->object(), r0);
1992 LOperand* key = UseFixed(instr->key(), r1);
1993 LDeleteProperty* result = new LDeleteProperty(object, key);
1994 return MarkAsCall(DefineFixed(result, r0), instr);
1995 }
1996
1997
DoOsrEntry(HOsrEntry * instr)1998 LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
1999 allocator_->MarkAsOsrEntry();
2000 current_block_->last_environment()->set_ast_id(instr->ast_id());
2001 return AssignEnvironment(new LOsrEntry);
2002 }
2003
2004
DoParameter(HParameter * instr)2005 LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2006 int spill_index = chunk()->GetParameterStackSlot(instr->index());
2007 return DefineAsSpilled(new LParameter, spill_index);
2008 }
2009
2010
DoUnknownOSRValue(HUnknownOSRValue * instr)2011 LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
2012 int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width.
2013 if (spill_index > LUnallocated::kMaxFixedIndex) {
2014 Abort("Too many spill slots needed for OSR");
2015 spill_index = 0;
2016 }
2017 return DefineAsSpilled(new LUnknownOSRValue, spill_index);
2018 }
2019
2020
DoCallStub(HCallStub * instr)2021 LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
2022 argument_count_ -= instr->argument_count();
2023 return MarkAsCall(DefineFixed(new LCallStub, r0), instr);
2024 }
2025
2026
DoArgumentsObject(HArgumentsObject * instr)2027 LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
2028 // There are no real uses of the arguments object.
2029 // arguments.length and element access are supported directly on
2030 // stack arguments, and any real arguments object use causes a bailout.
2031 // So this value is never used.
2032 return NULL;
2033 }
2034
2035
DoAccessArgumentsAt(HAccessArgumentsAt * instr)2036 LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
2037 LOperand* arguments = UseRegister(instr->arguments());
2038 LOperand* length = UseTempRegister(instr->length());
2039 LOperand* index = UseRegister(instr->index());
2040 LAccessArgumentsAt* result = new LAccessArgumentsAt(arguments, length, index);
2041 return AssignEnvironment(DefineAsRegister(result));
2042 }
2043
2044
DoToFastProperties(HToFastProperties * instr)2045 LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
2046 LOperand* object = UseFixed(instr->value(), r0);
2047 LToFastProperties* result = new LToFastProperties(object);
2048 return MarkAsCall(DefineFixed(result, r0), instr);
2049 }
2050
2051
DoTypeof(HTypeof * instr)2052 LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2053 LTypeof* result = new LTypeof(UseFixed(instr->value(), r0));
2054 return MarkAsCall(DefineFixed(result, r0), instr);
2055 }
2056
2057
DoTypeofIs(HTypeofIs * instr)2058 LInstruction* LChunkBuilder::DoTypeofIs(HTypeofIs* instr) {
2059 return DefineSameAsFirst(new LTypeofIs(UseRegister(instr->value())));
2060 }
2061
2062
DoIsConstructCall(HIsConstructCall * instr)2063 LInstruction* LChunkBuilder::DoIsConstructCall(HIsConstructCall* instr) {
2064 return DefineAsRegister(new LIsConstructCall());
2065 }
2066
2067
DoSimulate(HSimulate * instr)2068 LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2069 HEnvironment* env = current_block_->last_environment();
2070 ASSERT(env != NULL);
2071
2072 env->set_ast_id(instr->ast_id());
2073
2074 env->Drop(instr->pop_count());
2075 for (int i = 0; i < instr->values()->length(); ++i) {
2076 HValue* value = instr->values()->at(i);
2077 if (instr->HasAssignedIndexAt(i)) {
2078 env->Bind(instr->GetAssignedIndexAt(i), value);
2079 } else {
2080 env->Push(value);
2081 }
2082 }
2083
2084 // If there is an instruction pending deoptimization environment create a
2085 // lazy bailout instruction to capture the environment.
2086 if (pending_deoptimization_ast_id_ == instr->ast_id()) {
2087 LInstruction* result = new LLazyBailout;
2088 result = AssignEnvironment(result);
2089 instruction_pending_deoptimization_environment_->
2090 set_deoptimization_environment(result->environment());
2091 ClearInstructionPendingDeoptimizationEnvironment();
2092 return result;
2093 }
2094
2095 return NULL;
2096 }
2097
2098
DoStackCheck(HStackCheck * instr)2099 LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2100 return MarkAsCall(new LStackCheck, instr);
2101 }
2102
2103
DoEnterInlined(HEnterInlined * instr)2104 LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
2105 HEnvironment* outer = current_block_->last_environment();
2106 HConstant* undefined = graph()->GetConstantUndefined();
2107 HEnvironment* inner = outer->CopyForInlining(instr->closure(),
2108 instr->function(),
2109 false,
2110 undefined);
2111 current_block_->UpdateEnvironment(inner);
2112 chunk_->AddInlinedClosure(instr->closure());
2113 return NULL;
2114 }
2115
2116
DoLeaveInlined(HLeaveInlined * instr)2117 LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2118 HEnvironment* outer = current_block_->last_environment()->outer();
2119 current_block_->UpdateEnvironment(outer);
2120 return NULL;
2121 }
2122
2123
2124 } } // namespace v8::internal
2125