blob: 82de5d3e186b0601eae6b344bcb7daf88b559712 [file] [log] [blame]
Ben Murdoch086aeea2011-05-13 15:57:08 +01001// Copyright 2011 the V8 project authors. All rights reserved.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002// 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
Steve Block1e0659c2011-05-24 12:43:12 +010028#include "lithium-allocator-inl.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010029#include "arm/lithium-arm.h"
30#include "arm/lithium-codegen-arm.h"
31
32namespace v8 {
33namespace internal {
34
35#define DEFINE_COMPILE(type) \
36 void L##type::CompileToNative(LCodeGen* generator) { \
37 generator->Do##type(this); \
38 }
39LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
40#undef DEFINE_COMPILE
41
42LOsrEntry::LOsrEntry() {
43 for (int i = 0; i < Register::kNumAllocatableRegisters; ++i) {
44 register_spills_[i] = NULL;
45 }
46 for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; ++i) {
47 double_register_spills_[i] = NULL;
48 }
49}
50
51
52void LOsrEntry::MarkSpilledRegister(int allocation_index,
53 LOperand* spill_operand) {
54 ASSERT(spill_operand->IsStackSlot());
55 ASSERT(register_spills_[allocation_index] == NULL);
56 register_spills_[allocation_index] = spill_operand;
57}
58
59
Steve Block1e0659c2011-05-24 12:43:12 +010060#ifdef DEBUG
61void LInstruction::VerifyCall() {
62 // Call instructions can use only fixed registers as
63 // temporaries and outputs because all registers
64 // are blocked by the calling convention.
65 // Inputs must use a fixed register.
66 ASSERT(Output() == NULL ||
67 LUnallocated::cast(Output())->HasFixedPolicy() ||
68 !LUnallocated::cast(Output())->HasRegisterPolicy());
69 for (UseIterator it(this); it.HasNext(); it.Advance()) {
70 LOperand* operand = it.Next();
71 ASSERT(LUnallocated::cast(operand)->HasFixedPolicy() ||
72 !LUnallocated::cast(operand)->HasRegisterPolicy());
73 }
74 for (TempIterator it(this); it.HasNext(); it.Advance()) {
75 LOperand* operand = it.Next();
76 ASSERT(LUnallocated::cast(operand)->HasFixedPolicy() ||
77 !LUnallocated::cast(operand)->HasRegisterPolicy());
78 }
79}
80#endif
81
82
Ben Murdochb0fe1622011-05-05 13:52:32 +010083void LOsrEntry::MarkSpilledDoubleRegister(int allocation_index,
84 LOperand* spill_operand) {
85 ASSERT(spill_operand->IsDoubleStackSlot());
86 ASSERT(double_register_spills_[allocation_index] == NULL);
87 double_register_spills_[allocation_index] = spill_operand;
88}
89
90
Steve Block1e0659c2011-05-24 12:43:12 +010091void LInstruction::PrintTo(StringStream* stream) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010092 stream->Add("%s ", this->Mnemonic());
Steve Block1e0659c2011-05-24 12:43:12 +010093
94 PrintOutputOperandTo(stream);
95
Ben Murdochb0fe1622011-05-05 13:52:32 +010096 PrintDataTo(stream);
97
98 if (HasEnvironment()) {
99 stream->Add(" ");
100 environment()->PrintTo(stream);
101 }
102
103 if (HasPointerMap()) {
104 stream->Add(" ");
105 pointer_map()->PrintTo(stream);
106 }
107}
108
109
Steve Block1e0659c2011-05-24 12:43:12 +0100110template<int R, int I, int T>
111void LTemplateInstruction<R, I, T>::PrintDataTo(StringStream* stream) {
112 stream->Add("= ");
113 inputs_.PrintOperandsTo(stream);
114}
115
116
117template<int R, int I, int T>
118void LTemplateInstruction<R, I, T>::PrintOutputOperandTo(StringStream* stream) {
119 results_.PrintOperandsTo(stream);
120}
121
122
123template<typename T, int N>
124void OperandContainer<T, N>::PrintOperandsTo(StringStream* stream) {
125 for (int i = 0; i < N; i++) {
126 if (i > 0) stream->Add(" ");
127 elems_[i]->PrintTo(stream);
128 }
129}
130
131
132void LLabel::PrintDataTo(StringStream* stream) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100133 LGap::PrintDataTo(stream);
134 LLabel* rep = replacement();
135 if (rep != NULL) {
136 stream->Add(" Dead block replaced with B%d", rep->block_id());
137 }
138}
139
140
Ben Murdochb0fe1622011-05-05 13:52:32 +0100141bool LGap::IsRedundant() const {
142 for (int i = 0; i < 4; i++) {
143 if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) {
144 return false;
145 }
146 }
147
148 return true;
149}
150
151
152void LGap::PrintDataTo(StringStream* stream) const {
153 for (int i = 0; i < 4; i++) {
154 stream->Add("(");
155 if (parallel_moves_[i] != NULL) {
156 parallel_moves_[i]->PrintDataTo(stream);
157 }
158 stream->Add(") ");
159 }
160}
161
162
163const char* LArithmeticD::Mnemonic() const {
164 switch (op()) {
165 case Token::ADD: return "add-d";
166 case Token::SUB: return "sub-d";
167 case Token::MUL: return "mul-d";
168 case Token::DIV: return "div-d";
169 case Token::MOD: return "mod-d";
170 default:
171 UNREACHABLE();
172 return NULL;
173 }
174}
175
176
177const char* LArithmeticT::Mnemonic() const {
178 switch (op()) {
179 case Token::ADD: return "add-t";
180 case Token::SUB: return "sub-t";
181 case Token::MUL: return "mul-t";
182 case Token::MOD: return "mod-t";
183 case Token::DIV: return "div-t";
Steve Block1e0659c2011-05-24 12:43:12 +0100184 case Token::BIT_AND: return "bit-and-t";
185 case Token::BIT_OR: return "bit-or-t";
186 case Token::BIT_XOR: return "bit-xor-t";
187 case Token::SHL: return "shl-t";
188 case Token::SAR: return "sar-t";
189 case Token::SHR: return "shr-t";
Ben Murdochb0fe1622011-05-05 13:52:32 +0100190 default:
191 UNREACHABLE();
192 return NULL;
193 }
194}
195
196
Steve Block1e0659c2011-05-24 12:43:12 +0100197void LGoto::PrintDataTo(StringStream* stream) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100198 stream->Add("B%d", block_id());
199}
200
201
Steve Block1e0659c2011-05-24 12:43:12 +0100202void LBranch::PrintDataTo(StringStream* stream) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100203 stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
Steve Block1e0659c2011-05-24 12:43:12 +0100204 InputAt(0)->PrintTo(stream);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100205}
206
207
Steve Block1e0659c2011-05-24 12:43:12 +0100208void LCmpIDAndBranch::PrintDataTo(StringStream* stream) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100209 stream->Add("if ");
Steve Block1e0659c2011-05-24 12:43:12 +0100210 InputAt(0)->PrintTo(stream);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100211 stream->Add(" %s ", Token::String(op()));
Steve Block1e0659c2011-05-24 12:43:12 +0100212 InputAt(1)->PrintTo(stream);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100213 stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
214}
215
216
Steve Block1e0659c2011-05-24 12:43:12 +0100217void LIsNullAndBranch::PrintDataTo(StringStream* stream) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100218 stream->Add("if ");
Steve Block1e0659c2011-05-24 12:43:12 +0100219 InputAt(0)->PrintTo(stream);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100220 stream->Add(is_strict() ? " === null" : " == null");
221 stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
222}
223
224
Steve Block1e0659c2011-05-24 12:43:12 +0100225void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100226 stream->Add("if is_object(");
Steve Block1e0659c2011-05-24 12:43:12 +0100227 InputAt(0)->PrintTo(stream);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100228 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
229}
230
231
Steve Block1e0659c2011-05-24 12:43:12 +0100232void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100233 stream->Add("if is_smi(");
Steve Block1e0659c2011-05-24 12:43:12 +0100234 InputAt(0)->PrintTo(stream);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100235 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
236}
237
238
Steve Block1e0659c2011-05-24 12:43:12 +0100239void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100240 stream->Add("if has_instance_type(");
Steve Block1e0659c2011-05-24 12:43:12 +0100241 InputAt(0)->PrintTo(stream);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100242 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
243}
244
245
Steve Block1e0659c2011-05-24 12:43:12 +0100246void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100247 stream->Add("if has_cached_array_index(");
Steve Block1e0659c2011-05-24 12:43:12 +0100248 InputAt(0)->PrintTo(stream);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100249 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
250}
251
252
Steve Block1e0659c2011-05-24 12:43:12 +0100253void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100254 stream->Add("if class_of_test(");
Steve Block1e0659c2011-05-24 12:43:12 +0100255 InputAt(0)->PrintTo(stream);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100256 stream->Add(", \"%o\") then B%d else B%d",
257 *hydrogen()->class_name(),
258 true_block_id(),
259 false_block_id());
260}
261
262
Steve Block1e0659c2011-05-24 12:43:12 +0100263void LTypeofIs::PrintDataTo(StringStream* stream) {
264 InputAt(0)->PrintTo(stream);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100265 stream->Add(" == \"%s\"", *hydrogen()->type_literal()->ToCString());
266}
267
268
Steve Block1e0659c2011-05-24 12:43:12 +0100269void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100270 stream->Add("if typeof ");
Steve Block1e0659c2011-05-24 12:43:12 +0100271 InputAt(0)->PrintTo(stream);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100272 stream->Add(" == \"%s\" then B%d else B%d",
273 *hydrogen()->type_literal()->ToCString(),
274 true_block_id(), false_block_id());
275}
276
277
Steve Block1e0659c2011-05-24 12:43:12 +0100278void LCallConstantFunction::PrintDataTo(StringStream* stream) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100279 stream->Add("#%d / ", arity());
280}
281
282
Steve Block1e0659c2011-05-24 12:43:12 +0100283void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100284 stream->Add("/%s ", hydrogen()->OpName());
Steve Block1e0659c2011-05-24 12:43:12 +0100285 InputAt(0)->PrintTo(stream);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100286}
287
288
Ben Murdochb8e0da22011-05-16 14:20:40 +0100289void LLoadContextSlot::PrintDataTo(StringStream* stream) {
Steve Block1e0659c2011-05-24 12:43:12 +0100290 InputAt(0)->PrintTo(stream);
291 stream->Add("[%d]", slot_index());
Ben Murdochb8e0da22011-05-16 14:20:40 +0100292}
293
294
Steve Block1e0659c2011-05-24 12:43:12 +0100295void LStoreContextSlot::PrintDataTo(StringStream* stream) {
296 InputAt(0)->PrintTo(stream);
297 stream->Add("[%d] <- ", slot_index());
298 InputAt(1)->PrintTo(stream);
299}
300
301
302void LCallKeyed::PrintDataTo(StringStream* stream) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100303 stream->Add("[r2] #%d / ", arity());
304}
305
306
Steve Block1e0659c2011-05-24 12:43:12 +0100307void LCallNamed::PrintDataTo(StringStream* stream) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100308 SmartPointer<char> name_string = name()->ToCString();
309 stream->Add("%s #%d / ", *name_string, arity());
310}
311
312
Steve Block1e0659c2011-05-24 12:43:12 +0100313void LCallGlobal::PrintDataTo(StringStream* stream) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100314 SmartPointer<char> name_string = name()->ToCString();
315 stream->Add("%s #%d / ", *name_string, arity());
316}
317
318
Steve Block1e0659c2011-05-24 12:43:12 +0100319void LCallKnownGlobal::PrintDataTo(StringStream* stream) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100320 stream->Add("#%d / ", arity());
321}
322
323
Steve Block1e0659c2011-05-24 12:43:12 +0100324void LCallNew::PrintDataTo(StringStream* stream) {
325 stream->Add("= ");
326 InputAt(0)->PrintTo(stream);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100327 stream->Add(" #%d / ", arity());
328}
329
330
Steve Block1e0659c2011-05-24 12:43:12 +0100331void LClassOfTest::PrintDataTo(StringStream* stream) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100332 stream->Add("= class_of_test(");
Steve Block1e0659c2011-05-24 12:43:12 +0100333 InputAt(0)->PrintTo(stream);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100334 stream->Add(", \"%o\")", *hydrogen()->class_name());
335}
336
337
Steve Block1e0659c2011-05-24 12:43:12 +0100338void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100339 arguments()->PrintTo(stream);
340
341 stream->Add(" length ");
342 length()->PrintTo(stream);
343
344 stream->Add(" index ");
345 index()->PrintTo(stream);
346}
347
348
Steve Block1e0659c2011-05-24 12:43:12 +0100349void LStoreNamed::PrintDataTo(StringStream* stream) {
350 object()->PrintTo(stream);
351 stream->Add(".");
352 stream->Add(*String::cast(*name())->ToCString());
353 stream->Add(" <- ");
354 value()->PrintTo(stream);
355}
356
357
358void LStoreKeyed::PrintDataTo(StringStream* stream) {
359 object()->PrintTo(stream);
360 stream->Add("[");
361 key()->PrintTo(stream);
362 stream->Add("] <- ");
363 value()->PrintTo(stream);
364}
365
366
Ben Murdochb0fe1622011-05-05 13:52:32 +0100367LChunk::LChunk(HGraph* graph)
368 : spill_slot_count_(0),
369 graph_(graph),
370 instructions_(32),
371 pointer_maps_(8),
372 inlined_closures_(1) {
373}
374
375
Ben Murdochb0fe1622011-05-05 13:52:32 +0100376int LChunk::GetNextSpillIndex(bool is_double) {
377 // Skip a slot if for a double-width slot.
378 if (is_double) spill_slot_count_++;
379 return spill_slot_count_++;
380}
381
382
383LOperand* LChunk::GetNextSpillSlot(bool is_double) {
384 int index = GetNextSpillIndex(is_double);
385 if (is_double) {
386 return LDoubleStackSlot::Create(index);
387 } else {
388 return LStackSlot::Create(index);
389 }
390}
391
392
393void LChunk::MarkEmptyBlocks() {
394 HPhase phase("Mark empty blocks", this);
395 for (int i = 0; i < graph()->blocks()->length(); ++i) {
396 HBasicBlock* block = graph()->blocks()->at(i);
397 int first = block->first_instruction_index();
398 int last = block->last_instruction_index();
399 LInstruction* first_instr = instructions()->at(first);
400 LInstruction* last_instr = instructions()->at(last);
401
402 LLabel* label = LLabel::cast(first_instr);
403 if (last_instr->IsGoto()) {
404 LGoto* goto_instr = LGoto::cast(last_instr);
405 if (!goto_instr->include_stack_check() &&
406 label->IsRedundant() &&
407 !label->is_loop_header()) {
408 bool can_eliminate = true;
409 for (int i = first + 1; i < last && can_eliminate; ++i) {
410 LInstruction* cur = instructions()->at(i);
411 if (cur->IsGap()) {
412 LGap* gap = LGap::cast(cur);
413 if (!gap->IsRedundant()) {
414 can_eliminate = false;
415 }
416 } else {
417 can_eliminate = false;
418 }
419 }
420
421 if (can_eliminate) {
422 label->set_replacement(GetLabel(goto_instr->block_id()));
423 }
424 }
425 }
426 }
427}
428
429
Steve Block1e0659c2011-05-24 12:43:12 +0100430void LChunk::AddInstruction(LInstruction* instr, HBasicBlock* block) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100431 LGap* gap = new LGap(block);
432 int index = -1;
433 if (instr->IsControl()) {
434 instructions_.Add(gap);
435 index = instructions_.length();
436 instructions_.Add(instr);
437 } else {
438 index = instructions_.length();
439 instructions_.Add(instr);
440 instructions_.Add(gap);
441 }
442 if (instr->HasPointerMap()) {
443 pointer_maps_.Add(instr->pointer_map());
444 instr->pointer_map()->set_lithium_position(index);
445 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100446}
447
448
449LConstantOperand* LChunk::DefineConstantOperand(HConstant* constant) {
450 return LConstantOperand::Create(constant->id());
451}
452
453
454int LChunk::GetParameterStackSlot(int index) const {
455 // The receiver is at index 0, the first parameter at index 1, so we
456 // shift all parameter indexes down by the number of parameters, and
457 // make sure they end up negative so they are distinguishable from
458 // spill slots.
459 int result = index - graph()->info()->scope()->num_parameters() - 1;
460 ASSERT(result < 0);
461 return result;
462}
463
464// A parameter relative to ebp in the arguments stub.
465int LChunk::ParameterAt(int index) {
466 ASSERT(-1 <= index); // -1 is the receiver.
467 return (1 + graph()->info()->scope()->num_parameters() - index) *
468 kPointerSize;
469}
470
471
472LGap* LChunk::GetGapAt(int index) const {
473 return LGap::cast(instructions_[index]);
474}
475
476
477bool LChunk::IsGapAt(int index) const {
478 return instructions_[index]->IsGap();
479}
480
481
482int LChunk::NearestGapPos(int index) const {
483 while (!IsGapAt(index)) index--;
484 return index;
485}
486
487
488void LChunk::AddGapMove(int index, LOperand* from, LOperand* to) {
489 GetGapAt(index)->GetOrCreateParallelMove(LGap::START)->AddMove(from, to);
490}
491
492
Ben Murdochb0fe1622011-05-05 13:52:32 +0100493Handle<Object> LChunk::LookupLiteral(LConstantOperand* operand) const {
494 return HConstant::cast(graph_->LookupValue(operand->index()))->handle();
495}
496
497
498Representation LChunk::LookupLiteralRepresentation(
499 LConstantOperand* operand) const {
500 return graph_->LookupValue(operand->index())->representation();
501}
502
503
504LChunk* LChunkBuilder::Build() {
505 ASSERT(is_unused());
506 chunk_ = new LChunk(graph());
507 HPhase phase("Building chunk", chunk_);
508 status_ = BUILDING;
509 const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
510 for (int i = 0; i < blocks->length(); i++) {
511 HBasicBlock* next = NULL;
512 if (i < blocks->length() - 1) next = blocks->at(i + 1);
513 DoBasicBlock(blocks->at(i), next);
514 if (is_aborted()) return NULL;
515 }
516 status_ = DONE;
517 return chunk_;
518}
519
520
521void LChunkBuilder::Abort(const char* format, ...) {
522 if (FLAG_trace_bailout) {
523 SmartPointer<char> debug_name = graph()->debug_name()->ToCString();
524 PrintF("Aborting LChunk building in @\"%s\": ", *debug_name);
525 va_list arguments;
526 va_start(arguments, format);
527 OS::VPrint(format, arguments);
528 va_end(arguments);
529 PrintF("\n");
530 }
531 status_ = ABORTED;
532}
533
534
535LRegister* LChunkBuilder::ToOperand(Register reg) {
536 return LRegister::Create(Register::ToAllocationIndex(reg));
537}
538
539
540LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
541 return new LUnallocated(LUnallocated::FIXED_REGISTER,
542 Register::ToAllocationIndex(reg));
543}
544
545
546LUnallocated* LChunkBuilder::ToUnallocated(DoubleRegister reg) {
547 return new LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
548 DoubleRegister::ToAllocationIndex(reg));
549}
550
551
552LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
553 return Use(value, ToUnallocated(fixed_register));
554}
555
556
557LOperand* LChunkBuilder::UseFixedDouble(HValue* value, DoubleRegister reg) {
558 return Use(value, ToUnallocated(reg));
559}
560
561
562LOperand* LChunkBuilder::UseRegister(HValue* value) {
563 return Use(value, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
564}
565
566
567LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
568 return Use(value,
569 new LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
570 LUnallocated::USED_AT_START));
571}
572
573
574LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
575 return Use(value, new LUnallocated(LUnallocated::WRITABLE_REGISTER));
576}
577
578
579LOperand* LChunkBuilder::Use(HValue* value) {
580 return Use(value, new LUnallocated(LUnallocated::NONE));
581}
582
583
584LOperand* LChunkBuilder::UseAtStart(HValue* value) {
585 return Use(value, new LUnallocated(LUnallocated::NONE,
586 LUnallocated::USED_AT_START));
587}
588
589
590LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
591 return value->IsConstant()
592 ? chunk_->DefineConstantOperand(HConstant::cast(value))
593 : Use(value);
594}
595
596
597LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
598 return value->IsConstant()
599 ? chunk_->DefineConstantOperand(HConstant::cast(value))
600 : UseAtStart(value);
601}
602
603
604LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
605 return value->IsConstant()
606 ? chunk_->DefineConstantOperand(HConstant::cast(value))
607 : UseRegister(value);
608}
609
610
611LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
612 return value->IsConstant()
613 ? chunk_->DefineConstantOperand(HConstant::cast(value))
614 : UseRegisterAtStart(value);
615}
616
617
Ben Murdochb8e0da22011-05-16 14:20:40 +0100618LOperand* LChunkBuilder::UseAny(HValue* value) {
619 return value->IsConstant()
620 ? chunk_->DefineConstantOperand(HConstant::cast(value))
621 : Use(value, new LUnallocated(LUnallocated::ANY));
622}
623
624
Ben Murdochb0fe1622011-05-05 13:52:32 +0100625LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
626 if (value->EmitAtUses()) {
627 HInstruction* instr = HInstruction::cast(value);
628 VisitInstruction(instr);
629 }
630 allocator_->RecordUse(value, operand);
631 return operand;
632}
633
634
Steve Block1e0659c2011-05-24 12:43:12 +0100635template<int I, int T>
636LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
637 LUnallocated* result) {
638 allocator_->RecordDefinition(current_instruction_, result);
639 instr->set_result(result);
640 return instr;
641}
642
643
644template<int I, int T>
645LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100646 return Define(instr, new LUnallocated(LUnallocated::NONE));
647}
648
649
Steve Block1e0659c2011-05-24 12:43:12 +0100650template<int I, int T>
651LInstruction* LChunkBuilder::DefineAsRegister(
652 LTemplateInstruction<1, I, T>* instr) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100653 return Define(instr, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
654}
655
656
Steve Block1e0659c2011-05-24 12:43:12 +0100657template<int I, int T>
658LInstruction* LChunkBuilder::DefineAsSpilled(
659 LTemplateInstruction<1, I, T>* instr, int index) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100660 return Define(instr, new LUnallocated(LUnallocated::FIXED_SLOT, index));
661}
662
663
Steve Block1e0659c2011-05-24 12:43:12 +0100664template<int I, int T>
665LInstruction* LChunkBuilder::DefineSameAsFirst(
666 LTemplateInstruction<1, I, T>* instr) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100667 return Define(instr, new LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
668}
669
670
Steve Block1e0659c2011-05-24 12:43:12 +0100671template<int I, int T>
672LInstruction* LChunkBuilder::DefineFixed(
673 LTemplateInstruction<1, I, T>* instr, Register reg) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100674 return Define(instr, ToUnallocated(reg));
675}
676
677
Steve Block1e0659c2011-05-24 12:43:12 +0100678template<int I, int T>
679LInstruction* LChunkBuilder::DefineFixedDouble(
680 LTemplateInstruction<1, I, T>* instr, DoubleRegister reg) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100681 return Define(instr, ToUnallocated(reg));
682}
683
684
685LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
686 HEnvironment* hydrogen_env = current_block_->last_environment();
687 instr->set_environment(CreateEnvironment(hydrogen_env));
688 return instr;
689}
690
691
692LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
693 LInstruction* instr, int ast_id) {
Steve Block1e0659c2011-05-24 12:43:12 +0100694 ASSERT(instruction_pending_deoptimization_environment_ == NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100695 ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
Steve Block1e0659c2011-05-24 12:43:12 +0100696 instruction_pending_deoptimization_environment_ = instr;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100697 pending_deoptimization_ast_id_ = ast_id;
698 return instr;
699}
700
701
702void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
Steve Block1e0659c2011-05-24 12:43:12 +0100703 instruction_pending_deoptimization_environment_ = NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100704 pending_deoptimization_ast_id_ = AstNode::kNoNumber;
705}
706
707
708LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
709 HInstruction* hinstr,
710 CanDeoptimize can_deoptimize) {
Steve Block1e0659c2011-05-24 12:43:12 +0100711#ifdef DEBUG
712 instr->VerifyCall();
713#endif
714 instr->MarkAsCall();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100715 instr = AssignPointerMap(instr);
716
717 if (hinstr->HasSideEffects()) {
718 ASSERT(hinstr->next()->IsSimulate());
719 HSimulate* sim = HSimulate::cast(hinstr->next());
720 instr = SetInstructionPendingDeoptimizationEnvironment(
721 instr, sim->ast_id());
722 }
723
724 // If instruction does not have side-effects lazy deoptimization
725 // after the call will try to deoptimize to the point before the call.
726 // Thus we still need to attach environment to this call even if
727 // call sequence can not deoptimize eagerly.
728 bool needs_environment =
729 (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) || !hinstr->HasSideEffects();
730 if (needs_environment && !instr->HasEnvironment()) {
731 instr = AssignEnvironment(instr);
732 }
733
734 return instr;
735}
736
737
Steve Block1e0659c2011-05-24 12:43:12 +0100738LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) {
739 instr->MarkAsSaveDoubles();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100740 return instr;
741}
742
743
Steve Block1e0659c2011-05-24 12:43:12 +0100744LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
745 ASSERT(!instr->HasPointerMap());
746 instr->set_pointer_map(new LPointerMap(position_));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100747 return instr;
748}
749
750
Ben Murdochb0fe1622011-05-05 13:52:32 +0100751LUnallocated* LChunkBuilder::TempRegister() {
752 LUnallocated* operand = new LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
753 allocator_->RecordTemporary(operand);
754 return operand;
755}
756
757
758LOperand* LChunkBuilder::FixedTemp(Register reg) {
759 LUnallocated* operand = ToUnallocated(reg);
760 allocator_->RecordTemporary(operand);
761 return operand;
762}
763
764
765LOperand* LChunkBuilder::FixedTemp(DoubleRegister reg) {
766 LUnallocated* operand = ToUnallocated(reg);
767 allocator_->RecordTemporary(operand);
768 return operand;
769}
770
771
772LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
773 return new LLabel(instr->block());
774}
775
776
777LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
778 return AssignEnvironment(new LDeoptimize);
779}
780
781
782LInstruction* LChunkBuilder::DoBit(Token::Value op,
783 HBitwiseBinaryOperation* instr) {
Steve Block1e0659c2011-05-24 12:43:12 +0100784 if (instr->representation().IsInteger32()) {
785 ASSERT(instr->left()->representation().IsInteger32());
786 ASSERT(instr->right()->representation().IsInteger32());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100787
Steve Block1e0659c2011-05-24 12:43:12 +0100788 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
789 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
790 return DefineSameAsFirst(new LBitI(op, left, right));
791 } else {
792 ASSERT(instr->representation().IsTagged());
793 ASSERT(instr->left()->representation().IsTagged());
794 ASSERT(instr->right()->representation().IsTagged());
795
796 LOperand* left = UseFixed(instr->left(), r1);
797 LOperand* right = UseFixed(instr->right(), r0);
798 LArithmeticT* result = new LArithmeticT(op, left, right);
799 return MarkAsCall(DefineFixed(result, r0), instr);
800 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100801}
802
803
804LInstruction* LChunkBuilder::DoShift(Token::Value op,
805 HBitwiseBinaryOperation* instr) {
Steve Block1e0659c2011-05-24 12:43:12 +0100806 if (instr->representation().IsTagged()) {
807 ASSERT(instr->left()->representation().IsTagged());
808 ASSERT(instr->right()->representation().IsTagged());
809
810 LOperand* left = UseFixed(instr->left(), r1);
811 LOperand* right = UseFixed(instr->right(), r0);
812 LArithmeticT* result = new LArithmeticT(op, left, right);
813 return MarkAsCall(DefineFixed(result, r0), instr);
814 }
815
Ben Murdochb0fe1622011-05-05 13:52:32 +0100816 ASSERT(instr->representation().IsInteger32());
817 ASSERT(instr->OperandAt(0)->representation().IsInteger32());
818 ASSERT(instr->OperandAt(1)->representation().IsInteger32());
819 LOperand* left = UseRegisterAtStart(instr->OperandAt(0));
820
821 HValue* right_value = instr->OperandAt(1);
822 LOperand* right = NULL;
823 int constant_value = 0;
824 if (right_value->IsConstant()) {
825 HConstant* constant = HConstant::cast(right_value);
826 right = chunk_->DefineConstantOperand(constant);
827 constant_value = constant->Integer32Value() & 0x1f;
828 } else {
829 right = UseRegister(right_value);
830 }
831
832 // Shift operations can only deoptimize if we do a logical shift
833 // by 0 and the result cannot be truncated to int32.
834 bool can_deopt = (op == Token::SHR && constant_value == 0);
835 if (can_deopt) {
836 bool can_truncate = true;
837 for (int i = 0; i < instr->uses()->length(); i++) {
838 if (!instr->uses()->at(i)->CheckFlag(HValue::kTruncatingToInt32)) {
839 can_truncate = false;
840 break;
841 }
842 }
843 can_deopt = !can_truncate;
844 }
845
846 LInstruction* result =
847 DefineSameAsFirst(new LShiftI(op, left, right, can_deopt));
848 if (can_deopt) AssignEnvironment(result);
849 return result;
850}
851
852
853LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
854 HArithmeticBinaryOperation* instr) {
855 ASSERT(instr->representation().IsDouble());
856 ASSERT(instr->left()->representation().IsDouble());
857 ASSERT(instr->right()->representation().IsDouble());
858 LOperand* left = UseRegisterAtStart(instr->left());
859 LOperand* right = UseRegisterAtStart(instr->right());
860 LArithmeticD* result = new LArithmeticD(op, left, right);
861 return DefineSameAsFirst(result);
862}
863
864
865LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
866 HArithmeticBinaryOperation* instr) {
867 ASSERT(op == Token::ADD ||
868 op == Token::DIV ||
869 op == Token::MOD ||
870 op == Token::MUL ||
871 op == Token::SUB);
872 HValue* left = instr->left();
873 HValue* right = instr->right();
874 ASSERT(left->representation().IsTagged());
875 ASSERT(right->representation().IsTagged());
876 LOperand* left_operand = UseFixed(left, r1);
877 LOperand* right_operand = UseFixed(right, r0);
Steve Block1e0659c2011-05-24 12:43:12 +0100878 LArithmeticT* result = new LArithmeticT(op, left_operand, right_operand);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100879 return MarkAsCall(DefineFixed(result, r0), instr);
880}
881
Steve Block1e0659c2011-05-24 12:43:12 +0100882
Ben Murdochb0fe1622011-05-05 13:52:32 +0100883void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
884 ASSERT(is_building());
885 current_block_ = block;
886 next_block_ = next_block;
887 if (block->IsStartBlock()) {
888 block->UpdateEnvironment(graph_->start_environment());
889 argument_count_ = 0;
890 } else if (block->predecessors()->length() == 1) {
891 // We have a single predecessor => copy environment and outgoing
892 // argument count from the predecessor.
893 ASSERT(block->phis()->length() == 0);
894 HBasicBlock* pred = block->predecessors()->at(0);
895 HEnvironment* last_environment = pred->last_environment();
896 ASSERT(last_environment != NULL);
897 // Only copy the environment, if it is later used again.
898 if (pred->end()->SecondSuccessor() == NULL) {
899 ASSERT(pred->end()->FirstSuccessor() == block);
900 } else {
901 if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
902 pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
903 last_environment = last_environment->Copy();
904 }
905 }
906 block->UpdateEnvironment(last_environment);
907 ASSERT(pred->argument_count() >= 0);
908 argument_count_ = pred->argument_count();
909 } else {
910 // We are at a state join => process phis.
911 HBasicBlock* pred = block->predecessors()->at(0);
912 // No need to copy the environment, it cannot be used later.
913 HEnvironment* last_environment = pred->last_environment();
914 for (int i = 0; i < block->phis()->length(); ++i) {
915 HPhi* phi = block->phis()->at(i);
916 last_environment->SetValueAt(phi->merged_index(), phi);
917 }
918 for (int i = 0; i < block->deleted_phis()->length(); ++i) {
919 last_environment->SetValueAt(block->deleted_phis()->at(i),
920 graph_->GetConstantUndefined());
921 }
922 block->UpdateEnvironment(last_environment);
923 // Pick up the outgoing argument count of one of the predecessors.
924 argument_count_ = pred->argument_count();
925 }
926 HInstruction* current = block->first();
927 int start = chunk_->instructions()->length();
928 while (current != NULL && !is_aborted()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100929 // Code for constants in registers is generated lazily.
930 if (!current->EmitAtUses()) {
931 VisitInstruction(current);
932 }
933 current = current->next();
934 }
935 int end = chunk_->instructions()->length() - 1;
936 if (end >= start) {
937 block->set_first_instruction_index(start);
938 block->set_last_instruction_index(end);
939 }
940 block->set_argument_count(argument_count_);
941 next_block_ = NULL;
942 current_block_ = NULL;
943}
944
945
946void LChunkBuilder::VisitInstruction(HInstruction* current) {
947 HInstruction* old_current = current_instruction_;
948 current_instruction_ = current;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100949 if (current->has_position()) position_ = current->position();
950 LInstruction* instr = current->CompileToLithium(this);
951
952 if (instr != NULL) {
953 if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
954 instr = AssignPointerMap(instr);
955 }
956 if (FLAG_stress_environments && !instr->HasEnvironment()) {
957 instr = AssignEnvironment(instr);
958 }
Steve Block1e0659c2011-05-24 12:43:12 +0100959 if (current->IsTest() && !instr->IsGoto()) {
960 ASSERT(instr->IsControl());
961 HTest* test = HTest::cast(current);
962 instr->set_hydrogen_value(test->value());
963 HBasicBlock* first = test->FirstSuccessor();
964 HBasicBlock* second = test->SecondSuccessor();
965 ASSERT(first != NULL && second != NULL);
966 instr->SetBranchTargets(first->block_id(), second->block_id());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100967 } else {
968 instr->set_hydrogen_value(current);
969 }
970
Steve Block1e0659c2011-05-24 12:43:12 +0100971 chunk_->AddInstruction(instr, current_block_);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100972 }
973 current_instruction_ = old_current;
974}
975
976
Ben Murdochb0fe1622011-05-05 13:52:32 +0100977LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) {
978 if (hydrogen_env == NULL) return NULL;
979
980 LEnvironment* outer = CreateEnvironment(hydrogen_env->outer());
981 int ast_id = hydrogen_env->ast_id();
982 ASSERT(ast_id != AstNode::kNoNumber);
Steve Block9fac8402011-05-12 15:51:54 +0100983 int value_count = hydrogen_env->length();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100984 LEnvironment* result = new LEnvironment(hydrogen_env->closure(),
985 ast_id,
986 hydrogen_env->parameter_count(),
987 argument_count_,
988 value_count,
989 outer);
990 int argument_index = 0;
991 for (int i = 0; i < value_count; ++i) {
992 HValue* value = hydrogen_env->values()->at(i);
993 LOperand* op = NULL;
994 if (value->IsArgumentsObject()) {
995 op = NULL;
996 } else if (value->IsPushArgument()) {
997 op = new LArgument(argument_index++);
998 } else {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100999 op = UseAny(value);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001000 }
1001 result->AddValue(op, value->representation());
1002 }
1003
1004 return result;
1005}
1006
1007
1008LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
1009 LInstruction* result = new LGoto(instr->FirstSuccessor()->block_id(),
1010 instr->include_stack_check());
1011 if (instr->include_stack_check()) result = AssignPointerMap(result);
1012 return result;
1013}
1014
1015
Steve Block1e0659c2011-05-24 12:43:12 +01001016LInstruction* LChunkBuilder::DoTest(HTest* instr) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001017 HValue* v = instr->value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001018 if (v->EmitAtUses()) {
1019 if (v->IsClassOfTest()) {
1020 HClassOfTest* compare = HClassOfTest::cast(v);
1021 ASSERT(compare->value()->representation().IsTagged());
1022
1023 return new LClassOfTestAndBranch(UseTempRegister(compare->value()),
Steve Block1e0659c2011-05-24 12:43:12 +01001024 TempRegister());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001025 } else if (v->IsCompare()) {
1026 HCompare* compare = HCompare::cast(v);
1027 Token::Value op = compare->token();
1028 HValue* left = compare->left();
1029 HValue* right = compare->right();
Ben Murdochb8e0da22011-05-16 14:20:40 +01001030 Representation r = compare->GetInputRepresentation();
1031 if (r.IsInteger32()) {
1032 ASSERT(left->representation().IsInteger32());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001033 ASSERT(right->representation().IsInteger32());
Ben Murdochb8e0da22011-05-16 14:20:40 +01001034 return new LCmpIDAndBranch(UseRegisterAtStart(left),
Steve Block1e0659c2011-05-24 12:43:12 +01001035 UseRegisterAtStart(right));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001036 } else if (r.IsDouble()) {
1037 ASSERT(left->representation().IsDouble());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001038 ASSERT(right->representation().IsDouble());
Ben Murdochb8e0da22011-05-16 14:20:40 +01001039 return new LCmpIDAndBranch(UseRegisterAtStart(left),
Steve Block1e0659c2011-05-24 12:43:12 +01001040 UseRegisterAtStart(right));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001041 } else {
1042 ASSERT(left->representation().IsTagged());
1043 ASSERT(right->representation().IsTagged());
1044 bool reversed = op == Token::GT || op == Token::LTE;
1045 LOperand* left_operand = UseFixed(left, reversed ? r0 : r1);
1046 LOperand* right_operand = UseFixed(right, reversed ? r1 : r0);
1047 LInstruction* result = new LCmpTAndBranch(left_operand,
Steve Block1e0659c2011-05-24 12:43:12 +01001048 right_operand);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001049 return MarkAsCall(result, instr);
1050 }
1051 } else if (v->IsIsSmi()) {
1052 HIsSmi* compare = HIsSmi::cast(v);
1053 ASSERT(compare->value()->representation().IsTagged());
1054
Steve Block1e0659c2011-05-24 12:43:12 +01001055 return new LIsSmiAndBranch(Use(compare->value()));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001056 } else if (v->IsHasInstanceType()) {
1057 HHasInstanceType* compare = HHasInstanceType::cast(v);
1058 ASSERT(compare->value()->representation().IsTagged());
Steve Block1e0659c2011-05-24 12:43:12 +01001059 return new LHasInstanceTypeAndBranch(
1060 UseRegisterAtStart(compare->value()));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001061 } else if (v->IsHasCachedArrayIndex()) {
1062 HHasCachedArrayIndex* compare = HHasCachedArrayIndex::cast(v);
1063 ASSERT(compare->value()->representation().IsTagged());
1064
1065 return new LHasCachedArrayIndexAndBranch(
Steve Block1e0659c2011-05-24 12:43:12 +01001066 UseRegisterAtStart(compare->value()));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001067 } else if (v->IsIsNull()) {
1068 HIsNull* compare = HIsNull::cast(v);
1069 ASSERT(compare->value()->representation().IsTagged());
1070
Steve Block1e0659c2011-05-24 12:43:12 +01001071 return new LIsNullAndBranch(UseRegisterAtStart(compare->value()));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001072 } else if (v->IsIsObject()) {
1073 HIsObject* compare = HIsObject::cast(v);
1074 ASSERT(compare->value()->representation().IsTagged());
1075
Steve Block1e0659c2011-05-24 12:43:12 +01001076 LOperand* temp = TempRegister();
1077 return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()), temp);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001078 } else if (v->IsCompareJSObjectEq()) {
1079 HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
1080 return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()),
Steve Block1e0659c2011-05-24 12:43:12 +01001081 UseRegisterAtStart(compare->right()));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001082 } else if (v->IsInstanceOf()) {
1083 HInstanceOf* instance_of = HInstanceOf::cast(v);
1084 LInstruction* result =
Steve Block1e0659c2011-05-24 12:43:12 +01001085 new LInstanceOfAndBranch(UseFixed(instance_of->left(), r0),
1086 UseFixed(instance_of->right(), r1));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001087 return MarkAsCall(result, instr);
1088 } else if (v->IsTypeofIs()) {
1089 HTypeofIs* typeof_is = HTypeofIs::cast(v);
Steve Block1e0659c2011-05-24 12:43:12 +01001090 return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
1091 } else if (v->IsIsConstructCall()) {
1092 return new LIsConstructCallAndBranch(TempRegister());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001093 } else {
1094 if (v->IsConstant()) {
1095 if (HConstant::cast(v)->handle()->IsTrue()) {
Steve Block1e0659c2011-05-24 12:43:12 +01001096 return new LGoto(instr->FirstSuccessor()->block_id());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001097 } else if (HConstant::cast(v)->handle()->IsFalse()) {
Steve Block1e0659c2011-05-24 12:43:12 +01001098 return new LGoto(instr->SecondSuccessor()->block_id());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001099 }
1100 }
1101 Abort("Undefined compare before branch");
1102 return NULL;
1103 }
1104 }
Steve Block1e0659c2011-05-24 12:43:12 +01001105 return new LBranch(UseRegisterAtStart(v));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001106}
1107
1108
Steve Block1e0659c2011-05-24 12:43:12 +01001109LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001110 ASSERT(instr->value()->representation().IsTagged());
1111 LOperand* value = UseRegisterAtStart(instr->value());
Steve Block9fac8402011-05-12 15:51:54 +01001112 LOperand* temp = TempRegister();
1113 return new LCmpMapAndBranch(value, temp);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001114}
1115
1116
1117LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01001118 return DefineAsRegister(new LArgumentsLength(UseRegister(length->value())));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001119}
1120
1121
1122LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
1123 return DefineAsRegister(new LArgumentsElements);
1124}
1125
1126
1127LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
Steve Block1e0659c2011-05-24 12:43:12 +01001128 LInstanceOf* result =
Steve Block9fac8402011-05-12 15:51:54 +01001129 new LInstanceOf(UseFixed(instr->left(), r0),
1130 UseFixed(instr->right(), r1));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001131 return MarkAsCall(DefineFixed(result, r0), instr);
1132}
1133
1134
Ben Murdoch086aeea2011-05-13 15:57:08 +01001135LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
1136 HInstanceOfKnownGlobal* instr) {
Steve Block1e0659c2011-05-24 12:43:12 +01001137 LInstanceOfKnownGlobal* result =
1138 new LInstanceOfKnownGlobal(UseFixed(instr->value(), r0), FixedTemp(r4));
1139 MarkAsSaveDoubles(result);
1140 return AssignEnvironment(AssignPointerMap(DefineFixed(result, r0)));
Ben Murdoch086aeea2011-05-13 15:57:08 +01001141}
1142
1143
Ben Murdochb0fe1622011-05-05 13:52:32 +01001144LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
1145 LOperand* function = UseFixed(instr->function(), r1);
1146 LOperand* receiver = UseFixed(instr->receiver(), r0);
Steve Block1e0659c2011-05-24 12:43:12 +01001147 LOperand* length = UseFixed(instr->length(), r2);
1148 LOperand* elements = UseFixed(instr->elements(), r3);
1149 LApplyArguments* result = new LApplyArguments(function,
1150 receiver,
1151 length,
1152 elements);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001153 return MarkAsCall(DefineFixed(result, r0), instr, CAN_DEOPTIMIZE_EAGERLY);
1154}
1155
1156
1157LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
1158 ++argument_count_;
1159 LOperand* argument = Use(instr->argument());
1160 return new LPushArgument(argument);
1161}
1162
1163
Steve Block1e0659c2011-05-24 12:43:12 +01001164LInstruction* LChunkBuilder::DoContext(HContext* instr) {
1165 return DefineAsRegister(new LContext);
1166}
1167
1168
1169LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
1170 LOperand* context = UseRegisterAtStart(instr->value());
1171 return DefineAsRegister(new LOuterContext(context));
1172}
1173
1174
Ben Murdochb0fe1622011-05-05 13:52:32 +01001175LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
Steve Block1e0659c2011-05-24 12:43:12 +01001176 LOperand* context = UseRegisterAtStart(instr->value());
1177 return DefineAsRegister(new LGlobalObject(context));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001178}
1179
1180
1181LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
Steve Block1e0659c2011-05-24 12:43:12 +01001182 LOperand* global_object = UseRegisterAtStart(instr->value());
1183 return DefineAsRegister(new LGlobalReceiver(global_object));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001184}
1185
1186
1187LInstruction* LChunkBuilder::DoCallConstantFunction(
1188 HCallConstantFunction* instr) {
1189 argument_count_ -= instr->argument_count();
1190 return MarkAsCall(DefineFixed(new LCallConstantFunction, r0), instr);
1191}
1192
1193
1194LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
1195 BuiltinFunctionId op = instr->op();
1196 LOperand* input = UseRegisterAtStart(instr->value());
Ben Murdochb8e0da22011-05-16 14:20:40 +01001197 LOperand* temp = (op == kMathFloor) ? TempRegister() : NULL;
Steve Block1e0659c2011-05-24 12:43:12 +01001198 LUnaryMathOperation* result = new LUnaryMathOperation(input, temp);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001199 switch (op) {
1200 case kMathAbs:
1201 return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1202 case kMathFloor:
Steve Block1e0659c2011-05-24 12:43:12 +01001203 return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001204 case kMathSqrt:
1205 return DefineSameAsFirst(result);
Steve Block9fac8402011-05-12 15:51:54 +01001206 case kMathRound:
1207 Abort("MathRound LUnaryMathOperation not implemented");
1208 return NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001209 case kMathPowHalf:
1210 Abort("MathPowHalf LUnaryMathOperation not implemented");
1211 return NULL;
1212 case kMathLog:
1213 Abort("MathLog LUnaryMathOperation not implemented");
1214 return NULL;
1215 case kMathCos:
1216 Abort("MathCos LUnaryMathOperation not implemented");
1217 return NULL;
1218 case kMathSin:
1219 Abort("MathSin LUnaryMathOperation not implemented");
1220 return NULL;
1221 default:
1222 UNREACHABLE();
1223 return NULL;
1224 }
1225}
1226
1227
1228LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
1229 ASSERT(instr->key()->representation().IsTagged());
1230 argument_count_ -= instr->argument_count();
Steve Block1e0659c2011-05-24 12:43:12 +01001231 LOperand* key = UseFixed(instr->key(), r2);
1232 return MarkAsCall(DefineFixed(new LCallKeyed(key), r0), instr);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001233}
1234
1235
1236LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
1237 argument_count_ -= instr->argument_count();
1238 return MarkAsCall(DefineFixed(new LCallNamed, r0), instr);
1239}
1240
1241
1242LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
1243 argument_count_ -= instr->argument_count();
1244 return MarkAsCall(DefineFixed(new LCallGlobal, r0), instr);
1245}
1246
1247
1248LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
1249 argument_count_ -= instr->argument_count();
1250 return MarkAsCall(DefineFixed(new LCallKnownGlobal, r0), instr);
1251}
1252
1253
1254LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
1255 LOperand* constructor = UseFixed(instr->constructor(), r1);
1256 argument_count_ -= instr->argument_count();
Steve Block1e0659c2011-05-24 12:43:12 +01001257 LCallNew* result = new LCallNew(constructor);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001258 return MarkAsCall(DefineFixed(result, r0), instr);
1259}
1260
1261
1262LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
1263 argument_count_ -= instr->argument_count();
1264 return MarkAsCall(DefineFixed(new LCallFunction, r0), instr);
1265}
1266
1267
1268LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1269 argument_count_ -= instr->argument_count();
1270 return MarkAsCall(DefineFixed(new LCallRuntime, r0), instr);
1271}
1272
1273
1274LInstruction* LChunkBuilder::DoShr(HShr* instr) {
1275 return DoShift(Token::SHR, instr);
1276}
1277
1278
1279LInstruction* LChunkBuilder::DoSar(HSar* instr) {
1280 return DoShift(Token::SAR, instr);
1281}
1282
1283
1284LInstruction* LChunkBuilder::DoShl(HShl* instr) {
1285 return DoShift(Token::SHL, instr);
1286}
1287
1288
1289LInstruction* LChunkBuilder::DoBitAnd(HBitAnd* instr) {
1290 return DoBit(Token::BIT_AND, instr);
1291}
1292
1293
1294LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
1295 ASSERT(instr->value()->representation().IsInteger32());
1296 ASSERT(instr->representation().IsInteger32());
1297 return DefineSameAsFirst(new LBitNotI(UseRegisterAtStart(instr->value())));
1298}
1299
1300
1301LInstruction* LChunkBuilder::DoBitOr(HBitOr* instr) {
1302 return DoBit(Token::BIT_OR, instr);
1303}
1304
1305
1306LInstruction* LChunkBuilder::DoBitXor(HBitXor* instr) {
1307 return DoBit(Token::BIT_XOR, instr);
1308}
1309
1310
1311LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1312 if (instr->representation().IsDouble()) {
1313 return DoArithmeticD(Token::DIV, instr);
1314 } else if (instr->representation().IsInteger32()) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001315 // TODO(1042) The fixed register allocation
1316 // is needed because we call GenericBinaryOpStub from
1317 // the generated code, which requires registers r0
1318 // and r1 to be used. We should remove that
1319 // when we provide a native implementation.
Steve Block1e0659c2011-05-24 12:43:12 +01001320 LOperand* dividend = UseFixed(instr->left(), r0);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001321 LOperand* divisor = UseFixed(instr->right(), r1);
1322 return AssignEnvironment(AssignPointerMap(
Steve Block1e0659c2011-05-24 12:43:12 +01001323 DefineFixed(new LDivI(dividend, divisor), r0)));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001324 } else {
1325 return DoArithmeticT(Token::DIV, instr);
1326 }
1327}
1328
1329
1330LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1331 if (instr->representation().IsInteger32()) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001332 // TODO(1042) The fixed register allocation
1333 // is needed because we call GenericBinaryOpStub from
1334 // the generated code, which requires registers r0
1335 // and r1 to be used. We should remove that
1336 // when we provide a native implementation.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001337 ASSERT(instr->left()->representation().IsInteger32());
1338 ASSERT(instr->right()->representation().IsInteger32());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001339 LOperand* value = UseFixed(instr->left(), r0);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001340 LOperand* divisor = UseFixed(instr->right(), r1);
1341 LInstruction* result = DefineFixed(new LModI(value, divisor), r0);
1342 result = AssignEnvironment(AssignPointerMap(result));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001343 return result;
1344 } else if (instr->representation().IsTagged()) {
1345 return DoArithmeticT(Token::MOD, instr);
1346 } else {
1347 ASSERT(instr->representation().IsDouble());
1348 // We call a C function for double modulo. It can't trigger a GC.
1349 // We need to use fixed result register for the call.
1350 // TODO(fschneider): Allow any register as input registers.
1351 LOperand* left = UseFixedDouble(instr->left(), d1);
1352 LOperand* right = UseFixedDouble(instr->right(), d2);
1353 LArithmeticD* result = new LArithmeticD(Token::MOD, left, right);
1354 return MarkAsCall(DefineFixedDouble(result, d1), instr);
1355 }
1356}
1357
1358
1359LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1360 if (instr->representation().IsInteger32()) {
1361 ASSERT(instr->left()->representation().IsInteger32());
1362 ASSERT(instr->right()->representation().IsInteger32());
1363 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1364 LOperand* right = UseOrConstant(instr->MostConstantOperand());
1365 LOperand* temp = NULL;
1366 if (instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1367 temp = TempRegister();
1368 }
1369 LMulI* mul = new LMulI(left, right, temp);
1370 return AssignEnvironment(DefineSameAsFirst(mul));
1371 } else if (instr->representation().IsDouble()) {
1372 return DoArithmeticD(Token::MUL, instr);
1373 } else {
1374 return DoArithmeticT(Token::MUL, instr);
1375 }
1376}
1377
1378
1379LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1380 if (instr->representation().IsInteger32()) {
1381 ASSERT(instr->left()->representation().IsInteger32());
1382 ASSERT(instr->right()->representation().IsInteger32());
Steve Block1e0659c2011-05-24 12:43:12 +01001383 LOperand* left = UseRegisterAtStart(instr->left());
1384 LOperand* right = UseOrConstantAtStart(instr->right());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001385 LSubI* sub = new LSubI(left, right);
1386 LInstruction* result = DefineSameAsFirst(sub);
1387 if (instr->CheckFlag(HValue::kCanOverflow)) {
1388 result = AssignEnvironment(result);
1389 }
1390 return result;
1391 } else if (instr->representation().IsDouble()) {
1392 return DoArithmeticD(Token::SUB, instr);
1393 } else {
1394 return DoArithmeticT(Token::SUB, instr);
1395 }
1396}
1397
1398
1399LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1400 if (instr->representation().IsInteger32()) {
1401 ASSERT(instr->left()->representation().IsInteger32());
1402 ASSERT(instr->right()->representation().IsInteger32());
1403 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1404 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
1405 LAddI* add = new LAddI(left, right);
1406 LInstruction* result = DefineSameAsFirst(add);
1407 if (instr->CheckFlag(HValue::kCanOverflow)) {
1408 result = AssignEnvironment(result);
1409 }
1410 return result;
1411 } else if (instr->representation().IsDouble()) {
1412 return DoArithmeticD(Token::ADD, instr);
1413 } else {
1414 ASSERT(instr->representation().IsTagged());
1415 return DoArithmeticT(Token::ADD, instr);
1416 }
1417}
1418
1419
1420LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1421 Abort("LPower instruction not implemented on ARM");
1422 return NULL;
1423}
1424
1425
1426LInstruction* LChunkBuilder::DoCompare(HCompare* instr) {
1427 Token::Value op = instr->token();
Ben Murdochb8e0da22011-05-16 14:20:40 +01001428 Representation r = instr->GetInputRepresentation();
1429 if (r.IsInteger32()) {
1430 ASSERT(instr->left()->representation().IsInteger32());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001431 ASSERT(instr->right()->representation().IsInteger32());
1432 LOperand* left = UseRegisterAtStart(instr->left());
Steve Block1e0659c2011-05-24 12:43:12 +01001433 LOperand* right = UseRegisterAtStart(instr->right());
Ben Murdochb8e0da22011-05-16 14:20:40 +01001434 return DefineAsRegister(new LCmpID(left, right));
1435 } else if (r.IsDouble()) {
1436 ASSERT(instr->left()->representation().IsDouble());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001437 ASSERT(instr->right()->representation().IsDouble());
1438 LOperand* left = UseRegisterAtStart(instr->left());
1439 LOperand* right = UseRegisterAtStart(instr->right());
Ben Murdochb8e0da22011-05-16 14:20:40 +01001440 return DefineAsRegister(new LCmpID(left, right));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001441 } else {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001442 ASSERT(instr->left()->representation().IsTagged());
1443 ASSERT(instr->right()->representation().IsTagged());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001444 bool reversed = (op == Token::GT || op == Token::LTE);
1445 LOperand* left = UseFixed(instr->left(), reversed ? r0 : r1);
1446 LOperand* right = UseFixed(instr->right(), reversed ? r1 : r0);
Steve Block1e0659c2011-05-24 12:43:12 +01001447 LCmpT* result = new LCmpT(left, right);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001448 return MarkAsCall(DefineFixed(result, r0), instr);
1449 }
1450}
1451
1452
1453LInstruction* LChunkBuilder::DoCompareJSObjectEq(
1454 HCompareJSObjectEq* instr) {
1455 LOperand* left = UseRegisterAtStart(instr->left());
1456 LOperand* right = UseRegisterAtStart(instr->right());
Steve Block1e0659c2011-05-24 12:43:12 +01001457 LCmpJSObjectEq* result = new LCmpJSObjectEq(left, right);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001458 return DefineAsRegister(result);
1459}
1460
1461
1462LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) {
1463 ASSERT(instr->value()->representation().IsTagged());
1464 LOperand* value = UseRegisterAtStart(instr->value());
1465
Ben Murdochb8e0da22011-05-16 14:20:40 +01001466 return DefineAsRegister(new LIsNull(value));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001467}
1468
1469
1470LInstruction* LChunkBuilder::DoIsObject(HIsObject* instr) {
1471 ASSERT(instr->value()->representation().IsTagged());
1472 LOperand* value = UseRegisterAtStart(instr->value());
1473
Steve Block1e0659c2011-05-24 12:43:12 +01001474 return DefineAsRegister(new LIsObject(value));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001475}
1476
1477
1478LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) {
1479 ASSERT(instr->value()->representation().IsTagged());
1480 LOperand* value = UseAtStart(instr->value());
1481
1482 return DefineAsRegister(new LIsSmi(value));
1483}
1484
1485
1486LInstruction* LChunkBuilder::DoHasInstanceType(HHasInstanceType* instr) {
1487 ASSERT(instr->value()->representation().IsTagged());
1488 LOperand* value = UseRegisterAtStart(instr->value());
1489
1490 return DefineAsRegister(new LHasInstanceType(value));
1491}
1492
1493
1494LInstruction* LChunkBuilder::DoHasCachedArrayIndex(
1495 HHasCachedArrayIndex* instr) {
1496 ASSERT(instr->value()->representation().IsTagged());
1497 LOperand* value = UseRegister(instr->value());
1498
1499 return DefineAsRegister(new LHasCachedArrayIndex(value));
1500}
1501
1502
1503LInstruction* LChunkBuilder::DoClassOfTest(HClassOfTest* instr) {
1504 ASSERT(instr->value()->representation().IsTagged());
1505 LOperand* value = UseTempRegister(instr->value());
Ben Murdochb8e0da22011-05-16 14:20:40 +01001506 return DefineSameAsFirst(new LClassOfTest(value));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001507}
1508
1509
Steve Block9fac8402011-05-12 15:51:54 +01001510LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
1511 LOperand* array = UseRegisterAtStart(instr->value());
1512 return DefineAsRegister(new LJSArrayLength(array));
1513}
Ben Murdochb0fe1622011-05-05 13:52:32 +01001514
Ben Murdochb0fe1622011-05-05 13:52:32 +01001515
Steve Block1e0659c2011-05-24 12:43:12 +01001516LInstruction* LChunkBuilder::DoPixelArrayLength(HPixelArrayLength* instr) {
1517 LOperand* array = UseRegisterAtStart(instr->value());
1518 return DefineAsRegister(new LPixelArrayLength(array));
1519}
1520
1521
Steve Block9fac8402011-05-12 15:51:54 +01001522LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
1523 LOperand* array = UseRegisterAtStart(instr->value());
1524 return DefineAsRegister(new LFixedArrayLength(array));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001525}
1526
1527
1528LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
1529 LOperand* object = UseRegister(instr->value());
Steve Block1e0659c2011-05-24 12:43:12 +01001530 LValueOf* result = new LValueOf(object, TempRegister());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001531 return AssignEnvironment(DefineSameAsFirst(result));
1532}
1533
1534
1535LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1536 return AssignEnvironment(new LBoundsCheck(UseRegisterAtStart(instr->index()),
Ben Murdoch086aeea2011-05-13 15:57:08 +01001537 UseRegister(instr->length())));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001538}
1539
1540
Steve Block1e0659c2011-05-24 12:43:12 +01001541LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
1542 // The control instruction marking the end of a block that completed
1543 // abruptly (e.g., threw an exception). There is nothing specific to do.
1544 return NULL;
1545}
1546
1547
Ben Murdochb0fe1622011-05-05 13:52:32 +01001548LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
1549 LOperand* value = UseFixed(instr->value(), r0);
1550 return MarkAsCall(new LThrow(value), instr);
1551}
1552
1553
1554LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1555 Representation from = instr->from();
1556 Representation to = instr->to();
1557 if (from.IsTagged()) {
1558 if (to.IsDouble()) {
1559 LOperand* value = UseRegister(instr->value());
Steve Block1e0659c2011-05-24 12:43:12 +01001560 LNumberUntagD* res = new LNumberUntagD(value);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001561 return AssignEnvironment(DefineAsRegister(res));
1562 } else {
1563 ASSERT(to.IsInteger32());
1564 LOperand* value = UseRegister(instr->value());
1565 bool needs_check = !instr->value()->type().IsSmi();
1566 LInstruction* res = NULL;
1567 if (needs_check) {
1568 res = DefineSameAsFirst(new LTaggedToI(value, FixedTemp(d1)));
1569 } else {
1570 res = DefineSameAsFirst(new LSmiUntag(value, needs_check));
1571 }
1572 if (needs_check) {
1573 res = AssignEnvironment(res);
1574 }
1575 return res;
1576 }
1577 } else if (from.IsDouble()) {
1578 if (to.IsTagged()) {
1579 LOperand* value = UseRegister(instr->value());
1580 LOperand* temp1 = TempRegister();
1581 LOperand* temp2 = TempRegister();
1582
1583 // Make sure that the temp and result_temp registers are
1584 // different.
1585 LUnallocated* result_temp = TempRegister();
Steve Block1e0659c2011-05-24 12:43:12 +01001586 LNumberTagD* result = new LNumberTagD(value, temp1, temp2);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001587 Define(result, result_temp);
1588 return AssignPointerMap(result);
1589 } else {
1590 ASSERT(to.IsInteger32());
1591 LOperand* value = UseRegister(instr->value());
Steve Block1e0659c2011-05-24 12:43:12 +01001592 LDoubleToI* res = new LDoubleToI(value, TempRegister());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001593 return AssignEnvironment(DefineAsRegister(res));
1594 }
1595 } else if (from.IsInteger32()) {
1596 if (to.IsTagged()) {
1597 HValue* val = instr->value();
1598 LOperand* value = UseRegister(val);
1599 if (val->HasRange() && val->range()->IsInSmiRange()) {
1600 return DefineSameAsFirst(new LSmiTag(value));
1601 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01001602 LNumberTagI* result = new LNumberTagI(value);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001603 return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1604 }
1605 } else {
1606 ASSERT(to.IsDouble());
1607 LOperand* value = Use(instr->value());
1608 return DefineAsRegister(new LInteger32ToDouble(value));
1609 }
1610 }
1611 UNREACHABLE();
1612 return NULL;
1613}
1614
1615
1616LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
1617 LOperand* value = UseRegisterAtStart(instr->value());
1618 return AssignEnvironment(new LCheckSmi(value, eq));
1619}
1620
1621
1622LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
1623 LOperand* value = UseRegisterAtStart(instr->value());
Ben Murdoch086aeea2011-05-13 15:57:08 +01001624 LInstruction* result = new LCheckInstanceType(value);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001625 return AssignEnvironment(result);
1626}
1627
1628
1629LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
Steve Block9fac8402011-05-12 15:51:54 +01001630 LOperand* temp1 = TempRegister();
1631 LOperand* temp2 = TempRegister();
Ben Murdochb8e0da22011-05-16 14:20:40 +01001632 LInstruction* result = new LCheckPrototypeMaps(temp1, temp2);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001633 return AssignEnvironment(result);
1634}
1635
1636
1637LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
1638 LOperand* value = UseRegisterAtStart(instr->value());
1639 return AssignEnvironment(new LCheckSmi(value, ne));
1640}
1641
1642
1643LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
1644 LOperand* value = UseRegisterAtStart(instr->value());
1645 return AssignEnvironment(new LCheckFunction(value));
1646}
1647
1648
1649LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) {
1650 LOperand* value = UseRegisterAtStart(instr->value());
1651 LInstruction* result = new LCheckMap(value);
1652 return AssignEnvironment(result);
1653}
1654
1655
1656LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
1657 return new LReturn(UseFixed(instr->value(), r0));
1658}
1659
1660
1661LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
1662 Representation r = instr->representation();
1663 if (r.IsInteger32()) {
Steve Block1e0659c2011-05-24 12:43:12 +01001664 return DefineAsRegister(new LConstantI);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001665 } else if (r.IsDouble()) {
Steve Block1e0659c2011-05-24 12:43:12 +01001666 return DefineAsRegister(new LConstantD);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001667 } else if (r.IsTagged()) {
Steve Block1e0659c2011-05-24 12:43:12 +01001668 return DefineAsRegister(new LConstantT);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001669 } else {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001670 UNREACHABLE();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001671 return NULL;
1672 }
1673}
1674
1675
1676LInstruction* LChunkBuilder::DoLoadGlobal(HLoadGlobal* instr) {
Steve Block1e0659c2011-05-24 12:43:12 +01001677 LLoadGlobal* result = new LLoadGlobal();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001678 return instr->check_hole_value()
1679 ? AssignEnvironment(DefineAsRegister(result))
1680 : DefineAsRegister(result);
1681}
1682
1683
1684LInstruction* LChunkBuilder::DoStoreGlobal(HStoreGlobal* instr) {
Steve Block1e0659c2011-05-24 12:43:12 +01001685 if (instr->check_hole_value()) {
1686 LOperand* temp = TempRegister();
1687 LOperand* value = UseRegister(instr->value());
1688 return AssignEnvironment(new LStoreGlobal(value, temp));
1689 } else {
1690 LOperand* value = UseRegisterAtStart(instr->value());
1691 return new LStoreGlobal(value, NULL);
1692 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001693}
1694
1695
Ben Murdochb8e0da22011-05-16 14:20:40 +01001696LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
Steve Block1e0659c2011-05-24 12:43:12 +01001697 LOperand* context = UseRegisterAtStart(instr->value());
1698 return DefineAsRegister(new LLoadContextSlot(context));
1699}
1700
1701
1702LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
1703 LOperand* context = UseTempRegister(instr->context());
1704 LOperand* value;
1705 if (instr->NeedsWriteBarrier()) {
1706 value = UseTempRegister(instr->value());
1707 } else {
1708 value = UseRegister(instr->value());
1709 }
1710 return new LStoreContextSlot(context, value);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001711}
1712
1713
Ben Murdochb0fe1622011-05-05 13:52:32 +01001714LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
1715 return DefineAsRegister(
1716 new LLoadNamedField(UseRegisterAtStart(instr->object())));
1717}
1718
1719
1720LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
1721 LOperand* object = UseFixed(instr->object(), r0);
1722 LInstruction* result = DefineFixed(new LLoadNamedGeneric(object), r0);
1723 return MarkAsCall(result, instr);
1724}
1725
1726
Steve Block9fac8402011-05-12 15:51:54 +01001727LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
1728 HLoadFunctionPrototype* instr) {
1729 return AssignEnvironment(DefineAsRegister(
1730 new LLoadFunctionPrototype(UseRegister(instr->function()))));
1731}
1732
1733
Ben Murdochb0fe1622011-05-05 13:52:32 +01001734LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
1735 LOperand* input = UseRegisterAtStart(instr->value());
Steve Block1e0659c2011-05-24 12:43:12 +01001736 return DefineAsRegister(new LLoadElements(input));
1737}
1738
1739
1740LInstruction* LChunkBuilder::DoLoadPixelArrayExternalPointer(
1741 HLoadPixelArrayExternalPointer* instr) {
1742 LOperand* input = UseRegisterAtStart(instr->value());
1743 return DefineAsRegister(new LLoadPixelArrayExternalPointer(input));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001744}
1745
1746
1747LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
1748 HLoadKeyedFastElement* instr) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001749 ASSERT(instr->representation().IsTagged());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001750 ASSERT(instr->key()->representation().IsInteger32());
Ben Murdochb8e0da22011-05-16 14:20:40 +01001751 LOperand* obj = UseRegisterAtStart(instr->object());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001752 LOperand* key = UseRegisterAtStart(instr->key());
Steve Block1e0659c2011-05-24 12:43:12 +01001753 LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001754 return AssignEnvironment(DefineSameAsFirst(result));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001755}
1756
1757
Steve Block1e0659c2011-05-24 12:43:12 +01001758LInstruction* LChunkBuilder::DoLoadPixelArrayElement(
1759 HLoadPixelArrayElement* instr) {
1760 ASSERT(instr->representation().IsInteger32());
1761 ASSERT(instr->key()->representation().IsInteger32());
1762 LOperand* external_pointer =
1763 UseRegisterAtStart(instr->external_pointer());
1764 LOperand* key = UseRegisterAtStart(instr->key());
1765 LLoadPixelArrayElement* result =
1766 new LLoadPixelArrayElement(external_pointer, key);
1767 return DefineAsRegister(result);
1768}
1769
1770
Ben Murdochb0fe1622011-05-05 13:52:32 +01001771LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
1772 LOperand* object = UseFixed(instr->object(), r1);
1773 LOperand* key = UseFixed(instr->key(), r0);
1774
1775 LInstruction* result =
1776 DefineFixed(new LLoadKeyedGeneric(object, key), r0);
1777 return MarkAsCall(result, instr);
1778}
1779
1780
1781LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
1782 HStoreKeyedFastElement* instr) {
1783 bool needs_write_barrier = instr->NeedsWriteBarrier();
1784 ASSERT(instr->value()->representation().IsTagged());
1785 ASSERT(instr->object()->representation().IsTagged());
1786 ASSERT(instr->key()->representation().IsInteger32());
1787
1788 LOperand* obj = UseTempRegister(instr->object());
1789 LOperand* val = needs_write_barrier
1790 ? UseTempRegister(instr->value())
1791 : UseRegisterAtStart(instr->value());
1792 LOperand* key = needs_write_barrier
1793 ? UseTempRegister(instr->key())
1794 : UseRegisterOrConstantAtStart(instr->key());
1795
1796 return AssignEnvironment(new LStoreKeyedFastElement(obj, key, val));
1797}
1798
1799
1800LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
1801 LOperand* obj = UseFixed(instr->object(), r2);
1802 LOperand* key = UseFixed(instr->key(), r1);
1803 LOperand* val = UseFixed(instr->value(), r0);
1804
1805 ASSERT(instr->object()->representation().IsTagged());
1806 ASSERT(instr->key()->representation().IsTagged());
1807 ASSERT(instr->value()->representation().IsTagged());
1808
1809 return MarkAsCall(new LStoreKeyedGeneric(obj, key, val), instr);
1810}
1811
1812
1813LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01001814 bool needs_write_barrier = instr->NeedsWriteBarrier();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001815
1816 LOperand* obj = needs_write_barrier
1817 ? UseTempRegister(instr->object())
1818 : UseRegisterAtStart(instr->object());
1819
1820 LOperand* val = needs_write_barrier
1821 ? UseTempRegister(instr->value())
1822 : UseRegister(instr->value());
1823
Ben Murdochb8e0da22011-05-16 14:20:40 +01001824 return new LStoreNamedField(obj, val);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001825}
1826
1827
1828LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
1829 LOperand* obj = UseFixed(instr->object(), r1);
1830 LOperand* val = UseFixed(instr->value(), r0);
1831
Ben Murdochb8e0da22011-05-16 14:20:40 +01001832 LInstruction* result = new LStoreNamedGeneric(obj, val);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001833 return MarkAsCall(result, instr);
1834}
1835
1836
Steve Block1e0659c2011-05-24 12:43:12 +01001837LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
1838 LOperand* string = UseRegister(instr->string());
1839 LOperand* index = UseRegisterOrConstant(instr->index());
1840 LStringCharCodeAt* result = new LStringCharCodeAt(string, index);
1841 return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
1842}
1843
1844
1845LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
1846 LOperand* string = UseRegisterAtStart(instr->value());
1847 return DefineAsRegister(new LStringLength(string));
1848}
1849
1850
Ben Murdochb0fe1622011-05-05 13:52:32 +01001851LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
1852 return MarkAsCall(DefineFixed(new LArrayLiteral, r0), instr);
1853}
1854
1855
1856LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) {
1857 return MarkAsCall(DefineFixed(new LObjectLiteral, r0), instr);
1858}
1859
1860
1861LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
1862 return MarkAsCall(DefineFixed(new LRegExpLiteral, r0), instr);
1863}
1864
1865
1866LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
1867 return MarkAsCall(DefineFixed(new LFunctionLiteral, r0), instr);
1868}
1869
1870
1871LInstruction* LChunkBuilder::DoDeleteProperty(HDeleteProperty* instr) {
Steve Block1e0659c2011-05-24 12:43:12 +01001872 LOperand* object = UseFixed(instr->object(), r0);
1873 LOperand* key = UseFixed(instr->key(), r1);
1874 LDeleteProperty* result = new LDeleteProperty(object, key);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001875 return MarkAsCall(DefineFixed(result, r0), instr);
1876}
1877
1878
1879LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
1880 allocator_->MarkAsOsrEntry();
1881 current_block_->last_environment()->set_ast_id(instr->ast_id());
1882 return AssignEnvironment(new LOsrEntry);
1883}
1884
1885
1886LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
1887 int spill_index = chunk()->GetParameterStackSlot(instr->index());
1888 return DefineAsSpilled(new LParameter, spill_index);
1889}
1890
1891
1892LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
1893 int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width.
1894 return DefineAsSpilled(new LUnknownOSRValue, spill_index);
1895}
1896
1897
1898LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
1899 argument_count_ -= instr->argument_count();
1900 return MarkAsCall(DefineFixed(new LCallStub, r0), instr);
1901}
1902
1903
1904LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
1905 // There are no real uses of the arguments object (we bail out in all other
1906 // cases).
1907 return NULL;
1908}
1909
1910
1911LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
1912 LOperand* arguments = UseRegister(instr->arguments());
1913 LOperand* length = UseTempRegister(instr->length());
Ben Murdoch086aeea2011-05-13 15:57:08 +01001914 LOperand* index = UseRegister(instr->index());
Steve Block1e0659c2011-05-24 12:43:12 +01001915 LAccessArgumentsAt* result = new LAccessArgumentsAt(arguments, length, index);
1916 return AssignEnvironment(DefineAsRegister(result));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001917}
1918
1919
1920LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
Steve Block1e0659c2011-05-24 12:43:12 +01001921 LTypeof* result = new LTypeof(UseFixed(instr->value(), r0));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001922 return MarkAsCall(DefineFixed(result, r0), instr);
1923}
1924
1925
1926LInstruction* LChunkBuilder::DoTypeofIs(HTypeofIs* instr) {
1927 return DefineSameAsFirst(new LTypeofIs(UseRegister(instr->value())));
1928}
1929
Steve Block1e0659c2011-05-24 12:43:12 +01001930
1931LInstruction* LChunkBuilder::DoIsConstructCall(HIsConstructCall* instr) {
1932 return DefineAsRegister(new LIsConstructCall());
1933}
1934
1935
Ben Murdochb0fe1622011-05-05 13:52:32 +01001936LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
1937 HEnvironment* env = current_block_->last_environment();
1938 ASSERT(env != NULL);
1939
1940 env->set_ast_id(instr->ast_id());
1941
1942 env->Drop(instr->pop_count());
1943 for (int i = 0; i < instr->values()->length(); ++i) {
1944 HValue* value = instr->values()->at(i);
1945 if (instr->HasAssignedIndexAt(i)) {
1946 env->Bind(instr->GetAssignedIndexAt(i), value);
1947 } else {
1948 env->Push(value);
1949 }
1950 }
1951
Steve Block9fac8402011-05-12 15:51:54 +01001952 ASSERT(env->length() == instr->environment_length());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001953
1954 // If there is an instruction pending deoptimization environment create a
1955 // lazy bailout instruction to capture the environment.
1956 if (pending_deoptimization_ast_id_ == instr->ast_id()) {
1957 LInstruction* result = new LLazyBailout;
1958 result = AssignEnvironment(result);
Steve Block1e0659c2011-05-24 12:43:12 +01001959 instruction_pending_deoptimization_environment_->
Ben Murdochb0fe1622011-05-05 13:52:32 +01001960 set_deoptimization_environment(result->environment());
1961 ClearInstructionPendingDeoptimizationEnvironment();
1962 return result;
1963 }
1964
1965 return NULL;
1966}
1967
1968
1969LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
1970 return MarkAsCall(new LStackCheck, instr);
1971}
1972
1973
1974LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
1975 HEnvironment* outer = current_block_->last_environment();
1976 HConstant* undefined = graph()->GetConstantUndefined();
1977 HEnvironment* inner = outer->CopyForInlining(instr->closure(),
1978 instr->function(),
1979 false,
1980 undefined);
1981 current_block_->UpdateEnvironment(inner);
1982 chunk_->AddInlinedClosure(instr->closure());
1983 return NULL;
1984}
1985
1986
1987LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
1988 HEnvironment* outer = current_block_->last_environment()->outer();
1989 current_block_->UpdateEnvironment(outer);
1990 return NULL;
1991}
1992
1993
Ben Murdochb0fe1622011-05-05 13:52:32 +01001994} } // namespace v8::internal