blob: 56b991d301aef53fe81d4a0c13bf434f3901e2bc [file] [log] [blame]
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001// 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
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000028#include "v8.h"
29
30#if defined(V8_TARGET_ARCH_X64)
31
ricow@chromium.org83aa5492011-02-07 12:42:56 +000032#include "lithium-allocator-inl.h"
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000033#include "x64/lithium-x64.h"
34#include "x64/lithium-codegen-x64.h"
35
36namespace v8 {
37namespace internal {
38
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000039#define DEFINE_COMPILE(type) \
40 void L##type::CompileToNative(LCodeGen* generator) { \
41 generator->Do##type(this); \
42 }
43LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
44#undef DEFINE_COMPILE
45
46LOsrEntry::LOsrEntry() {
47 for (int i = 0; i < Register::kNumAllocatableRegisters; ++i) {
48 register_spills_[i] = NULL;
49 }
50 for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; ++i) {
51 double_register_spills_[i] = NULL;
52 }
53}
54
55
56void LOsrEntry::MarkSpilledRegister(int allocation_index,
57 LOperand* spill_operand) {
58 ASSERT(spill_operand->IsStackSlot());
59 ASSERT(register_spills_[allocation_index] == NULL);
60 register_spills_[allocation_index] = spill_operand;
61}
62
63
64void LOsrEntry::MarkSpilledDoubleRegister(int allocation_index,
65 LOperand* spill_operand) {
66 ASSERT(spill_operand->IsDoubleStackSlot());
67 ASSERT(double_register_spills_[allocation_index] == NULL);
68 double_register_spills_[allocation_index] = spill_operand;
69}
70
71
ricow@chromium.org83aa5492011-02-07 12:42:56 +000072#ifdef DEBUG
73void LInstruction::VerifyCall() {
74 // Call instructions can use only fixed registers as
75 // temporaries and outputs because all registers
76 // are blocked by the calling convention.
77 // Inputs can use either fixed register or have a short lifetime (be
78 // used at start of the instruction).
79 ASSERT(Output() == NULL ||
80 LUnallocated::cast(Output())->HasFixedPolicy() ||
81 !LUnallocated::cast(Output())->HasRegisterPolicy());
82 for (UseIterator it(this); it.HasNext(); it.Advance()) {
83 LOperand* operand = it.Next();
84 ASSERT(LUnallocated::cast(operand)->HasFixedPolicy() ||
85 LUnallocated::cast(operand)->IsUsedAtStart() ||
86 !LUnallocated::cast(operand)->HasRegisterPolicy());
87 }
88 for (TempIterator it(this); it.HasNext(); it.Advance()) {
89 LOperand* operand = it.Next();
90 ASSERT(LUnallocated::cast(operand)->HasFixedPolicy() ||
91 !LUnallocated::cast(operand)->HasRegisterPolicy());
92 }
93}
94#endif
95
96
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000097void LInstruction::PrintTo(StringStream* stream) {
98 stream->Add("%s ", this->Mnemonic());
ricow@chromium.org83aa5492011-02-07 12:42:56 +000099
100 PrintOutputOperandTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000101
102 PrintDataTo(stream);
103
104 if (HasEnvironment()) {
105 stream->Add(" ");
106 environment()->PrintTo(stream);
107 }
108
109 if (HasPointerMap()) {
110 stream->Add(" ");
111 pointer_map()->PrintTo(stream);
112 }
113}
114
115
116template<int R, int I, int T>
117void LTemplateInstruction<R, I, T>::PrintDataTo(StringStream* stream) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000118 stream->Add("= ");
119 inputs_.PrintOperandsTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000120}
121
122
123template<int R, int I, int T>
124void LTemplateInstruction<R, I, T>::PrintOutputOperandTo(StringStream* stream) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000125 results_.PrintOperandsTo(stream);
126}
127
128
129template<typename T, int N>
130void OperandContainer<T, N>::PrintOperandsTo(StringStream* stream) {
131 for (int i = 0; i < N; i++) {
132 if (i > 0) stream->Add(" ");
133 elems_[i]->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000134 }
135}
136
137
138void LLabel::PrintDataTo(StringStream* stream) {
139 LGap::PrintDataTo(stream);
140 LLabel* rep = replacement();
141 if (rep != NULL) {
142 stream->Add(" Dead block replaced with B%d", rep->block_id());
143 }
144}
145
146
147bool LGap::IsRedundant() const {
148 for (int i = 0; i < 4; i++) {
149 if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) {
150 return false;
151 }
152 }
153
154 return true;
155}
156
157
158void LGap::PrintDataTo(StringStream* stream) {
159 for (int i = 0; i < 4; i++) {
160 stream->Add("(");
161 if (parallel_moves_[i] != NULL) {
162 parallel_moves_[i]->PrintDataTo(stream);
163 }
164 stream->Add(") ");
165 }
166}
167
168
169const char* LArithmeticD::Mnemonic() const {
170 switch (op()) {
171 case Token::ADD: return "add-d";
172 case Token::SUB: return "sub-d";
173 case Token::MUL: return "mul-d";
174 case Token::DIV: return "div-d";
175 case Token::MOD: return "mod-d";
176 default:
177 UNREACHABLE();
178 return NULL;
179 }
180}
181
182
183const char* LArithmeticT::Mnemonic() const {
184 switch (op()) {
185 case Token::ADD: return "add-t";
186 case Token::SUB: return "sub-t";
187 case Token::MUL: return "mul-t";
188 case Token::MOD: return "mod-t";
189 case Token::DIV: return "div-t";
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000190 case Token::BIT_AND: return "bit-and-t";
191 case Token::BIT_OR: return "bit-or-t";
192 case Token::BIT_XOR: return "bit-xor-t";
193 case Token::SHL: return "sal-t";
194 case Token::SAR: return "sar-t";
195 case Token::SHR: return "shr-t";
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000196 default:
197 UNREACHABLE();
198 return NULL;
199 }
200}
201
202
203void LGoto::PrintDataTo(StringStream* stream) {
204 stream->Add("B%d", block_id());
205}
206
207
208void LBranch::PrintDataTo(StringStream* stream) {
209 stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000210 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000211}
212
213
214void LCmpIDAndBranch::PrintDataTo(StringStream* stream) {
215 stream->Add("if ");
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000216 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000217 stream->Add(" %s ", Token::String(op()));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000218 InputAt(1)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000219 stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
220}
221
222
223void LIsNullAndBranch::PrintDataTo(StringStream* stream) {
224 stream->Add("if ");
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000225 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000226 stream->Add(is_strict() ? " === null" : " == null");
227 stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
228}
229
230
231void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
232 stream->Add("if is_object(");
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000233 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000234 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
235}
236
237
238void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
239 stream->Add("if is_smi(");
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000240 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000241 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
242}
243
244
245void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
246 stream->Add("if has_instance_type(");
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000247 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000248 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
249}
250
251
252void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
253 stream->Add("if has_cached_array_index(");
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000254 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000255 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
256}
257
258
259void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
260 stream->Add("if class_of_test(");
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000261 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000262 stream->Add(", \"%o\") then B%d else B%d",
263 *hydrogen()->class_name(),
264 true_block_id(),
265 false_block_id());
266}
267
268
269void LTypeofIs::PrintDataTo(StringStream* stream) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000270 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000271 stream->Add(" == \"%s\"", *hydrogen()->type_literal()->ToCString());
272}
273
274
275void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
276 stream->Add("if typeof ");
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000277 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000278 stream->Add(" == \"%s\" then B%d else B%d",
279 *hydrogen()->type_literal()->ToCString(),
280 true_block_id(), false_block_id());
281}
282
283
284void LCallConstantFunction::PrintDataTo(StringStream* stream) {
285 stream->Add("#%d / ", arity());
286}
287
288
289void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
290 stream->Add("/%s ", hydrogen()->OpName());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000291 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000292}
293
294
295void LLoadContextSlot::PrintDataTo(StringStream* stream) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000296 InputAt(0)->PrintTo(stream);
297 stream->Add("[%d]", slot_index());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000298}
299
300
301void LCallKeyed::PrintDataTo(StringStream* stream) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000302 stream->Add("[ecx] #%d / ", arity());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000303}
304
305
306void LCallNamed::PrintDataTo(StringStream* stream) {
307 SmartPointer<char> name_string = name()->ToCString();
308 stream->Add("%s #%d / ", *name_string, arity());
309}
310
311
312void LCallGlobal::PrintDataTo(StringStream* stream) {
313 SmartPointer<char> name_string = name()->ToCString();
314 stream->Add("%s #%d / ", *name_string, arity());
315}
316
317
318void LCallKnownGlobal::PrintDataTo(StringStream* stream) {
319 stream->Add("#%d / ", arity());
320}
321
322
323void LCallNew::PrintDataTo(StringStream* stream) {
324 stream->Add("= ");
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000325 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000326 stream->Add(" #%d / ", arity());
327}
328
329
330void LClassOfTest::PrintDataTo(StringStream* stream) {
331 stream->Add("= class_of_test(");
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000332 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000333 stream->Add(", \"%o\")", *hydrogen()->class_name());
334}
335
336
337void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
338 arguments()->PrintTo(stream);
339
340 stream->Add(" length ");
341 length()->PrintTo(stream);
342
343 stream->Add(" index ");
344 index()->PrintTo(stream);
345}
346
347
348int LChunk::GetNextSpillIndex(bool is_double) {
349 return spill_slot_count_++;
350}
351
352
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000353LOperand* LChunk::GetNextSpillSlot(bool is_double) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000354 // All stack slots are Double stack slots on x64.
355 // Alternatively, at some point, start using half-size
356 // stack slots for int32 values.
357 int index = GetNextSpillIndex(is_double);
358 if (is_double) {
359 return LDoubleStackSlot::Create(index);
360 } else {
361 return LStackSlot::Create(index);
362 }
363}
364
365
366void LChunk::MarkEmptyBlocks() {
367 HPhase phase("Mark empty blocks", this);
368 for (int i = 0; i < graph()->blocks()->length(); ++i) {
369 HBasicBlock* block = graph()->blocks()->at(i);
370 int first = block->first_instruction_index();
371 int last = block->last_instruction_index();
372 LInstruction* first_instr = instructions()->at(first);
373 LInstruction* last_instr = instructions()->at(last);
374
375 LLabel* label = LLabel::cast(first_instr);
376 if (last_instr->IsGoto()) {
377 LGoto* goto_instr = LGoto::cast(last_instr);
378 if (!goto_instr->include_stack_check() &&
379 label->IsRedundant() &&
380 !label->is_loop_header()) {
381 bool can_eliminate = true;
382 for (int i = first + 1; i < last && can_eliminate; ++i) {
383 LInstruction* cur = instructions()->at(i);
384 if (cur->IsGap()) {
385 LGap* gap = LGap::cast(cur);
386 if (!gap->IsRedundant()) {
387 can_eliminate = false;
388 }
389 } else {
390 can_eliminate = false;
391 }
392 }
393
394 if (can_eliminate) {
395 label->set_replacement(GetLabel(goto_instr->block_id()));
396 }
397 }
398 }
399 }
400}
401
402
403void LStoreNamed::PrintDataTo(StringStream* stream) {
404 object()->PrintTo(stream);
405 stream->Add(".");
406 stream->Add(*String::cast(*name())->ToCString());
407 stream->Add(" <- ");
408 value()->PrintTo(stream);
409}
410
411
412void LStoreKeyed::PrintDataTo(StringStream* stream) {
413 object()->PrintTo(stream);
414 stream->Add("[");
415 key()->PrintTo(stream);
416 stream->Add("] <- ");
417 value()->PrintTo(stream);
418}
419
420
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000421void LChunk::AddInstruction(LInstruction* instr, HBasicBlock* block) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000422 LGap* gap = new LGap(block);
423 int index = -1;
424 if (instr->IsControl()) {
425 instructions_.Add(gap);
426 index = instructions_.length();
427 instructions_.Add(instr);
428 } else {
429 index = instructions_.length();
430 instructions_.Add(instr);
431 instructions_.Add(gap);
432 }
433 if (instr->HasPointerMap()) {
434 pointer_maps_.Add(instr->pointer_map());
435 instr->pointer_map()->set_lithium_position(index);
436 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000437}
438
439
440LConstantOperand* LChunk::DefineConstantOperand(HConstant* constant) {
441 return LConstantOperand::Create(constant->id());
442}
443
444
445int LChunk::GetParameterStackSlot(int index) const {
446 // The receiver is at index 0, the first parameter at index 1, so we
447 // shift all parameter indexes down by the number of parameters, and
448 // make sure they end up negative so they are distinguishable from
449 // spill slots.
450 int result = index - graph()->info()->scope()->num_parameters() - 1;
451 ASSERT(result < 0);
452 return result;
453}
454
455// A parameter relative to ebp in the arguments stub.
456int LChunk::ParameterAt(int index) {
457 ASSERT(-1 <= index); // -1 is the receiver.
458 return (1 + graph()->info()->scope()->num_parameters() - index) *
459 kPointerSize;
460}
461
462
463LGap* LChunk::GetGapAt(int index) const {
464 return LGap::cast(instructions_[index]);
465}
466
467
468bool LChunk::IsGapAt(int index) const {
469 return instructions_[index]->IsGap();
470}
471
472
473int LChunk::NearestGapPos(int index) const {
474 while (!IsGapAt(index)) index--;
475 return index;
476}
477
478
479void LChunk::AddGapMove(int index, LOperand* from, LOperand* to) {
480 GetGapAt(index)->GetOrCreateParallelMove(LGap::START)->AddMove(from, to);
481}
482
483
484Handle<Object> LChunk::LookupLiteral(LConstantOperand* operand) const {
485 return HConstant::cast(graph_->LookupValue(operand->index()))->handle();
486}
487
488
489Representation LChunk::LookupLiteralRepresentation(
490 LConstantOperand* operand) const {
491 return graph_->LookupValue(operand->index())->representation();
492}
493
494
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000495LChunk* LChunkBuilder::Build() {
496 ASSERT(is_unused());
497 chunk_ = new LChunk(graph());
498 HPhase phase("Building chunk", chunk_);
499 status_ = BUILDING;
500 const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
501 for (int i = 0; i < blocks->length(); i++) {
502 HBasicBlock* next = NULL;
503 if (i < blocks->length() - 1) next = blocks->at(i + 1);
504 DoBasicBlock(blocks->at(i), next);
505 if (is_aborted()) return NULL;
506 }
507 status_ = DONE;
508 return chunk_;
509}
510
511
512void LChunkBuilder::Abort(const char* format, ...) {
513 if (FLAG_trace_bailout) {
514 SmartPointer<char> debug_name = graph()->debug_name()->ToCString();
515 PrintF("Aborting LChunk building in @\"%s\": ", *debug_name);
516 va_list arguments;
517 va_start(arguments, format);
518 OS::VPrint(format, arguments);
519 va_end(arguments);
520 PrintF("\n");
521 }
522 status_ = ABORTED;
523}
524
525
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000526LRegister* LChunkBuilder::ToOperand(Register reg) {
527 return LRegister::Create(Register::ToAllocationIndex(reg));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000528}
529
530
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000531LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
532 return new LUnallocated(LUnallocated::FIXED_REGISTER,
533 Register::ToAllocationIndex(reg));
534}
535
536
537LUnallocated* LChunkBuilder::ToUnallocated(XMMRegister reg) {
538 return new LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
539 XMMRegister::ToAllocationIndex(reg));
540}
541
542
543LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
544 return Use(value, ToUnallocated(fixed_register));
545}
546
547
548LOperand* LChunkBuilder::UseFixedDouble(HValue* value, XMMRegister reg) {
549 return Use(value, ToUnallocated(reg));
550}
551
552
553LOperand* LChunkBuilder::UseRegister(HValue* value) {
554 return Use(value, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
555}
556
557
558LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
559 return Use(value,
560 new LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
561 LUnallocated::USED_AT_START));
562}
563
564
565LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
566 return Use(value, new LUnallocated(LUnallocated::WRITABLE_REGISTER));
567}
568
569
570LOperand* LChunkBuilder::Use(HValue* value) {
571 return Use(value, new LUnallocated(LUnallocated::NONE));
572}
573
574
575LOperand* LChunkBuilder::UseAtStart(HValue* value) {
576 return Use(value, new LUnallocated(LUnallocated::NONE,
577 LUnallocated::USED_AT_START));
578}
579
580
581LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
582 return value->IsConstant()
583 ? chunk_->DefineConstantOperand(HConstant::cast(value))
584 : Use(value);
585}
586
587
588LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
589 return value->IsConstant()
590 ? chunk_->DefineConstantOperand(HConstant::cast(value))
591 : UseAtStart(value);
592}
593
594
595LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
596 return value->IsConstant()
597 ? chunk_->DefineConstantOperand(HConstant::cast(value))
598 : UseRegister(value);
599}
600
601
602LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
603 return value->IsConstant()
604 ? chunk_->DefineConstantOperand(HConstant::cast(value))
605 : UseRegisterAtStart(value);
606}
607
608
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000609LOperand* LChunkBuilder::UseAny(HValue* value) {
610 return value->IsConstant()
611 ? chunk_->DefineConstantOperand(HConstant::cast(value))
612 : Use(value, new LUnallocated(LUnallocated::ANY));
613}
614
615
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000616LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
617 if (value->EmitAtUses()) {
618 HInstruction* instr = HInstruction::cast(value);
619 VisitInstruction(instr);
620 }
621 allocator_->RecordUse(value, operand);
622 return operand;
623}
624
625
626template<int I, int T>
627LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
628 LUnallocated* result) {
629 allocator_->RecordDefinition(current_instruction_, result);
630 instr->set_result(result);
631 return instr;
632}
633
634
635template<int I, int T>
636LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr) {
637 return Define(instr, new LUnallocated(LUnallocated::NONE));
638}
639
640
641template<int I, int T>
642LInstruction* LChunkBuilder::DefineAsRegister(
643 LTemplateInstruction<1, I, T>* instr) {
644 return Define(instr, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
645}
646
647
648template<int I, int T>
649LInstruction* LChunkBuilder::DefineAsSpilled(
650 LTemplateInstruction<1, I, T>* instr,
651 int index) {
652 return Define(instr, new LUnallocated(LUnallocated::FIXED_SLOT, index));
653}
654
655
656template<int I, int T>
657LInstruction* LChunkBuilder::DefineSameAsFirst(
658 LTemplateInstruction<1, I, T>* instr) {
659 return Define(instr, new LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
660}
661
662
663template<int I, int T>
664LInstruction* LChunkBuilder::DefineFixed(LTemplateInstruction<1, I, T>* instr,
665 Register reg) {
666 return Define(instr, ToUnallocated(reg));
667}
668
669
670template<int I, int T>
671LInstruction* LChunkBuilder::DefineFixedDouble(
672 LTemplateInstruction<1, I, T>* instr,
673 XMMRegister reg) {
674 return Define(instr, ToUnallocated(reg));
675}
676
677
678LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
679 HEnvironment* hydrogen_env = current_block_->last_environment();
680 instr->set_environment(CreateEnvironment(hydrogen_env));
681 return instr;
682}
683
684
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000685LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
686 LInstruction* instr, int ast_id) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000687 ASSERT(instruction_pending_deoptimization_environment_ == NULL);
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000688 ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000689 instruction_pending_deoptimization_environment_ = instr;
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000690 pending_deoptimization_ast_id_ = ast_id;
691 return instr;
692}
693
694
695void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000696 instruction_pending_deoptimization_environment_ = NULL;
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000697 pending_deoptimization_ast_id_ = AstNode::kNoNumber;
698}
699
700
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000701LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
702 HInstruction* hinstr,
703 CanDeoptimize can_deoptimize) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000704#ifdef DEBUG
705 instr->VerifyCall();
706#endif
707 instr->MarkAsCall();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000708 instr = AssignPointerMap(instr);
709
710 if (hinstr->HasSideEffects()) {
711 ASSERT(hinstr->next()->IsSimulate());
712 HSimulate* sim = HSimulate::cast(hinstr->next());
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000713 instr = SetInstructionPendingDeoptimizationEnvironment(
714 instr, sim->ast_id());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000715 }
716
717 // If instruction does not have side-effects lazy deoptimization
718 // after the call will try to deoptimize to the point before the call.
719 // Thus we still need to attach environment to this call even if
720 // call sequence can not deoptimize eagerly.
721 bool needs_environment =
722 (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) || !hinstr->HasSideEffects();
723 if (needs_environment && !instr->HasEnvironment()) {
724 instr = AssignEnvironment(instr);
725 }
726
727 return instr;
728}
729
730
731LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000732 instr->MarkAsSaveDoubles();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000733 return instr;
734}
735
736
737LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
738 ASSERT(!instr->HasPointerMap());
739 instr->set_pointer_map(new LPointerMap(position_));
740 return instr;
741}
742
743
744LUnallocated* LChunkBuilder::TempRegister() {
745 LUnallocated* operand = new LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
746 allocator_->RecordTemporary(operand);
747 return operand;
748}
749
750
751LOperand* LChunkBuilder::FixedTemp(Register reg) {
752 LUnallocated* operand = ToUnallocated(reg);
753 allocator_->RecordTemporary(operand);
754 return operand;
755}
756
757
758LOperand* LChunkBuilder::FixedTemp(XMMRegister reg) {
759 LUnallocated* operand = ToUnallocated(reg);
760 allocator_->RecordTemporary(operand);
761 return operand;
762}
763
764
765LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
766 return new LLabel(instr->block());
767}
768
769
770LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
771 return AssignEnvironment(new LDeoptimize);
772}
773
774
775LInstruction* LChunkBuilder::DoBit(Token::Value op,
776 HBitwiseBinaryOperation* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000777 if (instr->representation().IsInteger32()) {
778 ASSERT(instr->left()->representation().IsInteger32());
779 ASSERT(instr->right()->representation().IsInteger32());
780
781 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
782 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
783 return DefineSameAsFirst(new LBitI(op, left, right));
784 } else {
785 ASSERT(instr->representation().IsTagged());
786 ASSERT(instr->left()->representation().IsTagged());
787 ASSERT(instr->right()->representation().IsTagged());
788
789 LOperand* left = UseFixed(instr->left(), rdx);
790 LOperand* right = UseFixed(instr->right(), rax);
791 LArithmeticT* result = new LArithmeticT(op, left, right);
792 return MarkAsCall(DefineFixed(result, rax), instr);
793 }
794}
795
796
797LInstruction* LChunkBuilder::DoShift(Token::Value op,
798 HBitwiseBinaryOperation* instr) {
799 if (instr->representation().IsTagged()) {
800 ASSERT(instr->left()->representation().IsTagged());
801 ASSERT(instr->right()->representation().IsTagged());
802
803 LOperand* left = UseFixed(instr->left(), rdx);
804 LOperand* right = UseFixed(instr->right(), rax);
805 LArithmeticT* result = new LArithmeticT(op, left, right);
806 return MarkAsCall(DefineFixed(result, rax), instr);
807 }
808
809 ASSERT(instr->representation().IsInteger32());
810 ASSERT(instr->OperandAt(0)->representation().IsInteger32());
811 ASSERT(instr->OperandAt(1)->representation().IsInteger32());
812 LOperand* left = UseRegisterAtStart(instr->OperandAt(0));
813
814 HValue* right_value = instr->OperandAt(1);
815 LOperand* right = NULL;
816 int constant_value = 0;
817 if (right_value->IsConstant()) {
818 HConstant* constant = HConstant::cast(right_value);
819 right = chunk_->DefineConstantOperand(constant);
820 constant_value = constant->Integer32Value() & 0x1f;
821 } else {
822 right = UseFixed(right_value, rcx);
823 }
824
825 // Shift operations can only deoptimize if we do a logical shift
826 // by 0 and the result cannot be truncated to int32.
827 bool can_deopt = (op == Token::SHR && constant_value == 0);
828 if (can_deopt) {
829 bool can_truncate = true;
830 for (int i = 0; i < instr->uses()->length(); i++) {
831 if (!instr->uses()->at(i)->CheckFlag(HValue::kTruncatingToInt32)) {
832 can_truncate = false;
833 break;
834 }
835 }
836 can_deopt = !can_truncate;
837 }
838
839 LShiftI* result = new LShiftI(op, left, right, can_deopt);
840 return can_deopt
841 ? AssignEnvironment(DefineSameAsFirst(result))
842 : DefineSameAsFirst(result);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000843}
844
845
846LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
847 HArithmeticBinaryOperation* instr) {
848 Abort("Unimplemented: %s", "DoArithmeticD");
849 return NULL;
850}
851
852
853LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
854 HArithmeticBinaryOperation* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000855 ASSERT(op == Token::ADD ||
856 op == Token::DIV ||
857 op == Token::MOD ||
858 op == Token::MUL ||
859 op == Token::SUB);
860 HValue* left = instr->left();
861 HValue* right = instr->right();
862 ASSERT(left->representation().IsTagged());
863 ASSERT(right->representation().IsTagged());
864 LOperand* left_operand = UseFixed(left, rdx);
865 LOperand* right_operand = UseFixed(right, rax);
866 LArithmeticT* result = new LArithmeticT(op, left_operand, right_operand);
867 return MarkAsCall(DefineFixed(result, rax), instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000868}
869
870
871void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
872 ASSERT(is_building());
873 current_block_ = block;
874 next_block_ = next_block;
875 if (block->IsStartBlock()) {
876 block->UpdateEnvironment(graph_->start_environment());
877 argument_count_ = 0;
878 } else if (block->predecessors()->length() == 1) {
879 // We have a single predecessor => copy environment and outgoing
880 // argument count from the predecessor.
881 ASSERT(block->phis()->length() == 0);
882 HBasicBlock* pred = block->predecessors()->at(0);
883 HEnvironment* last_environment = pred->last_environment();
884 ASSERT(last_environment != NULL);
885 // Only copy the environment, if it is later used again.
886 if (pred->end()->SecondSuccessor() == NULL) {
887 ASSERT(pred->end()->FirstSuccessor() == block);
888 } else {
889 if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
890 pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
891 last_environment = last_environment->Copy();
892 }
893 }
894 block->UpdateEnvironment(last_environment);
895 ASSERT(pred->argument_count() >= 0);
896 argument_count_ = pred->argument_count();
897 } else {
898 // We are at a state join => process phis.
899 HBasicBlock* pred = block->predecessors()->at(0);
900 // No need to copy the environment, it cannot be used later.
901 HEnvironment* last_environment = pred->last_environment();
902 for (int i = 0; i < block->phis()->length(); ++i) {
903 HPhi* phi = block->phis()->at(i);
904 last_environment->SetValueAt(phi->merged_index(), phi);
905 }
906 for (int i = 0; i < block->deleted_phis()->length(); ++i) {
907 last_environment->SetValueAt(block->deleted_phis()->at(i),
908 graph_->GetConstantUndefined());
909 }
910 block->UpdateEnvironment(last_environment);
911 // Pick up the outgoing argument count of one of the predecessors.
912 argument_count_ = pred->argument_count();
913 }
914 HInstruction* current = block->first();
915 int start = chunk_->instructions()->length();
916 while (current != NULL && !is_aborted()) {
917 // Code for constants in registers is generated lazily.
918 if (!current->EmitAtUses()) {
919 VisitInstruction(current);
920 }
921 current = current->next();
922 }
923 int end = chunk_->instructions()->length() - 1;
924 if (end >= start) {
925 block->set_first_instruction_index(start);
926 block->set_last_instruction_index(end);
927 }
928 block->set_argument_count(argument_count_);
929 next_block_ = NULL;
930 current_block_ = NULL;
931}
932
933
934void LChunkBuilder::VisitInstruction(HInstruction* current) {
935 HInstruction* old_current = current_instruction_;
936 current_instruction_ = current;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000937 if (current->has_position()) position_ = current->position();
938 LInstruction* instr = current->CompileToLithium(this);
939
940 if (instr != NULL) {
941 if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
942 instr = AssignPointerMap(instr);
943 }
944 if (FLAG_stress_environments && !instr->HasEnvironment()) {
945 instr = AssignEnvironment(instr);
946 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000947 if (current->IsTest() && !instr->IsGoto()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000948 ASSERT(instr->IsControl());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000949 HTest* test = HTest::cast(current);
950 instr->set_hydrogen_value(test->value());
951 HBasicBlock* first = test->FirstSuccessor();
952 HBasicBlock* second = test->SecondSuccessor();
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000953 ASSERT(first != NULL && second != NULL);
954 instr->SetBranchTargets(first->block_id(), second->block_id());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000955 } else {
956 instr->set_hydrogen_value(current);
957 }
958
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000959 chunk_->AddInstruction(instr, current_block_);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000960 }
961 current_instruction_ = old_current;
962}
963
964
965LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) {
966 if (hydrogen_env == NULL) return NULL;
967
968 LEnvironment* outer = CreateEnvironment(hydrogen_env->outer());
969 int ast_id = hydrogen_env->ast_id();
970 ASSERT(ast_id != AstNode::kNoNumber);
971 int value_count = hydrogen_env->length();
972 LEnvironment* result = new LEnvironment(hydrogen_env->closure(),
973 ast_id,
974 hydrogen_env->parameter_count(),
975 argument_count_,
976 value_count,
977 outer);
978 int argument_index = 0;
979 for (int i = 0; i < value_count; ++i) {
980 HValue* value = hydrogen_env->values()->at(i);
981 LOperand* op = NULL;
982 if (value->IsArgumentsObject()) {
983 op = NULL;
984 } else if (value->IsPushArgument()) {
985 op = new LArgument(argument_index++);
986 } else {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000987 op = UseAny(value);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000988 }
989 result->AddValue(op, value->representation());
990 }
991
992 return result;
993}
994
995
996LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
997 LGoto* result = new LGoto(instr->FirstSuccessor()->block_id(),
998 instr->include_stack_check());
999 return (instr->include_stack_check())
1000 ? AssignPointerMap(result)
1001 : result;
1002}
1003
1004
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001005LInstruction* LChunkBuilder::DoTest(HTest* instr) {
1006 HValue* v = instr->value();
1007 if (v->EmitAtUses()) {
1008 if (v->IsClassOfTest()) {
1009 HClassOfTest* compare = HClassOfTest::cast(v);
1010 ASSERT(compare->value()->representation().IsTagged());
1011
1012 return new LClassOfTestAndBranch(UseTempRegister(compare->value()),
1013 TempRegister());
1014 } else if (v->IsCompare()) {
1015 HCompare* compare = HCompare::cast(v);
1016 Token::Value op = compare->token();
1017 HValue* left = compare->left();
1018 HValue* right = compare->right();
1019 Representation r = compare->GetInputRepresentation();
1020 if (r.IsInteger32()) {
1021 ASSERT(left->representation().IsInteger32());
1022 ASSERT(right->representation().IsInteger32());
1023
1024 return new LCmpIDAndBranch(UseRegisterAtStart(left),
1025 UseOrConstantAtStart(right));
1026 } else if (r.IsDouble()) {
1027 ASSERT(left->representation().IsDouble());
1028 ASSERT(right->representation().IsDouble());
1029
1030 return new LCmpIDAndBranch(UseRegisterAtStart(left),
1031 UseRegisterAtStart(right));
1032 } else {
1033 ASSERT(left->representation().IsTagged());
1034 ASSERT(right->representation().IsTagged());
1035 bool reversed = op == Token::GT || op == Token::LTE;
1036 LOperand* left_operand = UseFixed(left, reversed ? rax : rdx);
1037 LOperand* right_operand = UseFixed(right, reversed ? rdx : rax);
1038 LCmpTAndBranch* result = new LCmpTAndBranch(left_operand,
1039 right_operand);
1040 return MarkAsCall(result, instr);
1041 }
1042 } else if (v->IsIsSmi()) {
1043 HIsSmi* compare = HIsSmi::cast(v);
1044 ASSERT(compare->value()->representation().IsTagged());
1045
1046 return new LIsSmiAndBranch(Use(compare->value()));
1047 } else if (v->IsHasInstanceType()) {
1048 HHasInstanceType* compare = HHasInstanceType::cast(v);
1049 ASSERT(compare->value()->representation().IsTagged());
1050
1051 return new LHasInstanceTypeAndBranch(
1052 UseRegisterAtStart(compare->value()));
1053 } else if (v->IsHasCachedArrayIndex()) {
1054 HHasCachedArrayIndex* compare = HHasCachedArrayIndex::cast(v);
1055 ASSERT(compare->value()->representation().IsTagged());
1056
1057 return new LHasCachedArrayIndexAndBranch(
1058 UseRegisterAtStart(compare->value()));
1059 } else if (v->IsIsNull()) {
1060 HIsNull* compare = HIsNull::cast(v);
1061 ASSERT(compare->value()->representation().IsTagged());
1062
1063 // We only need a temp register for non-strict compare.
1064 LOperand* temp = compare->is_strict() ? NULL : TempRegister();
1065 return new LIsNullAndBranch(UseRegisterAtStart(compare->value()),
1066 temp);
1067 } else if (v->IsIsObject()) {
1068 HIsObject* compare = HIsObject::cast(v);
1069 ASSERT(compare->value()->representation().IsTagged());
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001070 return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001071 } else if (v->IsCompareJSObjectEq()) {
1072 HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
1073 return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()),
1074 UseRegisterAtStart(compare->right()));
1075 } else if (v->IsInstanceOf()) {
1076 HInstanceOf* instance_of = HInstanceOf::cast(v);
1077 LInstanceOfAndBranch* result =
1078 new LInstanceOfAndBranch(
1079 UseFixed(instance_of->left(), InstanceofStub::left()),
1080 UseFixed(instance_of->right(), InstanceofStub::right()));
1081 return MarkAsCall(result, instr);
1082 } else if (v->IsTypeofIs()) {
1083 HTypeofIs* typeof_is = HTypeofIs::cast(v);
1084 return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001085 } else if (v->IsIsConstructCall()) {
1086 return new LIsConstructCallAndBranch(TempRegister());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001087 } else {
1088 if (v->IsConstant()) {
1089 if (HConstant::cast(v)->handle()->IsTrue()) {
1090 return new LGoto(instr->FirstSuccessor()->block_id());
1091 } else if (HConstant::cast(v)->handle()->IsFalse()) {
1092 return new LGoto(instr->SecondSuccessor()->block_id());
1093 }
1094 }
1095 Abort("Undefined compare before branch");
1096 return NULL;
1097 }
1098 }
1099 return new LBranch(UseRegisterAtStart(v));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001100}
1101
1102
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001103LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001104 ASSERT(instr->value()->representation().IsTagged());
1105 LOperand* value = UseRegisterAtStart(instr->value());
1106 return new LCmpMapAndBranch(value);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001107}
1108
1109
1110LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) {
1111 Abort("Unimplemented: %s", "DoArgumentsLength");
1112 return NULL;
1113}
1114
1115
1116LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
1117 Abort("Unimplemented: %s", "DoArgumentsElements");
1118 return NULL;
1119}
1120
1121
1122LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
1123 Abort("Unimplemented: %s", "DoInstanceOf");
1124 return NULL;
1125}
1126
1127
1128LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
1129 HInstanceOfKnownGlobal* instr) {
1130 Abort("Unimplemented: %s", "DoInstanceOfKnownGlobal");
1131 return NULL;
1132}
1133
1134
1135LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
1136 Abort("Unimplemented: %s", "DoApplyArguments");
1137 return NULL;
1138}
1139
1140
1141LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001142 ++argument_count_;
1143 LOperand* argument = UseOrConstant(instr->argument());
1144 return new LPushArgument(argument);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001145}
1146
1147
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001148LInstruction* LChunkBuilder::DoContext(HContext* instr) {
1149 Abort("Unimplemented: DoContext");
1150 return NULL;
1151}
1152
1153
1154LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
1155 Abort("Unimplemented: DoOuterContext");
1156 return NULL;
1157}
1158
1159
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001160LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001161 return DefineAsRegister(new LGlobalObject);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001162}
1163
1164
1165LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001166 return DefineAsRegister(new LGlobalReceiver);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001167}
1168
1169
1170LInstruction* LChunkBuilder::DoCallConstantFunction(
1171 HCallConstantFunction* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001172 argument_count_ -= instr->argument_count();
1173 return MarkAsCall(DefineFixed(new LCallConstantFunction, rax), instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001174}
1175
1176
1177LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
1178 Abort("Unimplemented: %s", "DoUnaryMathOperation");
1179 return NULL;
1180}
1181
1182
1183LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
1184 Abort("Unimplemented: %s", "DoCallKeyed");
1185 return NULL;
1186}
1187
1188
1189LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001190 argument_count_ -= instr->argument_count();
1191 return MarkAsCall(DefineFixed(new LCallNamed, rax), instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001192}
1193
1194
1195LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
1196 Abort("Unimplemented: %s", "DoCallGlobal");
1197 return NULL;
1198}
1199
1200
1201LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001202 argument_count_ -= instr->argument_count();
1203 return MarkAsCall(DefineFixed(new LCallKnownGlobal, rax), instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001204}
1205
1206
1207LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001208 LOperand* constructor = UseFixed(instr->constructor(), rdi);
1209 argument_count_ -= instr->argument_count();
1210 LCallNew* result = new LCallNew(constructor);
1211 return MarkAsCall(DefineFixed(result, rax), instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001212}
1213
1214
1215LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
1216 Abort("Unimplemented: %s", "DoCallFunction");
1217 return NULL;
1218}
1219
1220
1221LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001222 argument_count_ -= instr->argument_count();
1223 return MarkAsCall(DefineFixed(new LCallRuntime, rax), instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001224}
1225
1226
1227LInstruction* LChunkBuilder::DoShr(HShr* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001228 return DoShift(Token::SHR, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001229}
1230
1231
1232LInstruction* LChunkBuilder::DoSar(HSar* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001233 return DoShift(Token::SAR, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001234}
1235
1236
1237LInstruction* LChunkBuilder::DoShl(HShl* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001238 return DoShift(Token::SHL, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001239}
1240
1241
1242LInstruction* LChunkBuilder::DoBitAnd(HBitAnd* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001243 return DoBit(Token::BIT_AND, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001244}
1245
1246
1247LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001248 ASSERT(instr->value()->representation().IsInteger32());
1249 ASSERT(instr->representation().IsInteger32());
1250 LOperand* input = UseRegisterAtStart(instr->value());
1251 LBitNotI* result = new LBitNotI(input);
1252 return DefineSameAsFirst(result);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001253}
1254
1255
1256LInstruction* LChunkBuilder::DoBitOr(HBitOr* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001257 return DoBit(Token::BIT_OR, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001258}
1259
1260
1261LInstruction* LChunkBuilder::DoBitXor(HBitXor* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001262 return DoBit(Token::BIT_XOR, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001263}
1264
1265
1266LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001267 if (instr->representation().IsDouble()) {
1268 return DoArithmeticD(Token::DIV, instr);
1269 } else if (instr->representation().IsInteger32()) {
1270 // The temporary operand is necessary to ensure that right is not allocated
1271 // into rdx.
1272 LOperand* temp = FixedTemp(rdx);
1273 LOperand* dividend = UseFixed(instr->left(), rax);
1274 LOperand* divisor = UseRegister(instr->right());
1275 LDivI* result = new LDivI(dividend, divisor, temp);
1276 return AssignEnvironment(DefineFixed(result, rax));
1277 } else {
1278 ASSERT(instr->representation().IsTagged());
1279 return DoArithmeticT(Token::DIV, instr);
1280 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001281}
1282
1283
1284LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1285 Abort("Unimplemented: %s", "DoMod");
1286 return NULL;
1287}
1288
1289
1290LInstruction* LChunkBuilder::DoMul(HMul* instr) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001291 if (instr->representation().IsInteger32()) {
1292 ASSERT(instr->left()->representation().IsInteger32());
1293 ASSERT(instr->right()->representation().IsInteger32());
1294 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1295 LOperand* right = UseOrConstant(instr->MostConstantOperand());
1296 LMulI* mul = new LMulI(left, right);
1297 return AssignEnvironment(DefineSameAsFirst(mul));
1298 } else if (instr->representation().IsDouble()) {
1299 return DoArithmeticD(Token::MUL, instr);
1300 } else {
1301 ASSERT(instr->representation().IsTagged());
1302 return DoArithmeticT(Token::MUL, instr);
1303 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001304}
1305
1306
1307LInstruction* LChunkBuilder::DoSub(HSub* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001308 if (instr->representation().IsInteger32()) {
1309 ASSERT(instr->left()->representation().IsInteger32());
1310 ASSERT(instr->right()->representation().IsInteger32());
1311 LOperand* left = UseRegisterAtStart(instr->left());
1312 LOperand* right = UseOrConstantAtStart(instr->right());
1313 LSubI* sub = new LSubI(left, right);
1314 LInstruction* result = DefineSameAsFirst(sub);
1315 if (instr->CheckFlag(HValue::kCanOverflow)) {
1316 result = AssignEnvironment(result);
1317 }
1318 return result;
1319 } else if (instr->representation().IsDouble()) {
1320 return DoArithmeticD(Token::SUB, instr);
1321 } else {
1322 ASSERT(instr->representation().IsTagged());
1323 return DoArithmeticT(Token::SUB, instr);
1324 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001325}
1326
1327
1328LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001329 if (instr->representation().IsInteger32()) {
1330 ASSERT(instr->left()->representation().IsInteger32());
1331 ASSERT(instr->right()->representation().IsInteger32());
1332 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1333 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
1334 LAddI* add = new LAddI(left, right);
1335 LInstruction* result = DefineSameAsFirst(add);
1336 if (instr->CheckFlag(HValue::kCanOverflow)) {
1337 result = AssignEnvironment(result);
1338 }
1339 return result;
1340 } else if (instr->representation().IsDouble()) {
1341 Abort("Unimplemented: %s", "DoAdd on Doubles");
1342 } else {
1343 ASSERT(instr->representation().IsTagged());
1344 return DoArithmeticT(Token::ADD, instr);
1345 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001346 return NULL;
1347}
1348
1349
1350LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1351 Abort("Unimplemented: %s", "DoPower");
1352 return NULL;
1353}
1354
1355
1356LInstruction* LChunkBuilder::DoCompare(HCompare* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001357 Token::Value op = instr->token();
1358 Representation r = instr->GetInputRepresentation();
1359 if (r.IsInteger32()) {
1360 ASSERT(instr->left()->representation().IsInteger32());
1361 ASSERT(instr->right()->representation().IsInteger32());
1362 LOperand* left = UseRegisterAtStart(instr->left());
1363 LOperand* right = UseOrConstantAtStart(instr->right());
1364 return DefineAsRegister(new LCmpID(left, right));
1365 } else if (r.IsDouble()) {
1366 ASSERT(instr->left()->representation().IsDouble());
1367 ASSERT(instr->right()->representation().IsDouble());
1368 LOperand* left = UseRegisterAtStart(instr->left());
1369 LOperand* right = UseRegisterAtStart(instr->right());
1370 return DefineAsRegister(new LCmpID(left, right));
1371 } else {
1372 ASSERT(instr->left()->representation().IsTagged());
1373 ASSERT(instr->right()->representation().IsTagged());
1374 bool reversed = (op == Token::GT || op == Token::LTE);
1375 LOperand* left = UseFixed(instr->left(), reversed ? rax : rdx);
1376 LOperand* right = UseFixed(instr->right(), reversed ? rdx : rax);
1377 LCmpT* result = new LCmpT(left, right);
1378 return MarkAsCall(DefineFixed(result, rax), instr);
1379 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001380}
1381
1382
1383LInstruction* LChunkBuilder::DoCompareJSObjectEq(
1384 HCompareJSObjectEq* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001385 LOperand* left = UseRegisterAtStart(instr->left());
1386 LOperand* right = UseRegisterAtStart(instr->right());
1387 LCmpJSObjectEq* result = new LCmpJSObjectEq(left, right);
1388 return DefineAsRegister(result);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001389}
1390
1391
1392LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001393 ASSERT(instr->value()->representation().IsTagged());
1394 LOperand* value = UseRegisterAtStart(instr->value());
1395
1396 return DefineAsRegister(new LIsNull(value));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001397}
1398
1399
1400LInstruction* LChunkBuilder::DoIsObject(HIsObject* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001401 ASSERT(instr->value()->representation().IsTagged());
1402 LOperand* value = UseRegister(instr->value());
1403
1404 return DefineAsRegister(new LIsObject(value));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001405}
1406
1407
1408LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001409 ASSERT(instr->value()->representation().IsTagged());
1410 LOperand* value = UseAtStart(instr->value());
1411
1412 return DefineAsRegister(new LIsSmi(value));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001413}
1414
1415
1416LInstruction* LChunkBuilder::DoHasInstanceType(HHasInstanceType* instr) {
1417 Abort("Unimplemented: %s", "DoHasInstanceType");
1418 return NULL;
1419}
1420
1421
1422LInstruction* LChunkBuilder::DoHasCachedArrayIndex(
1423 HHasCachedArrayIndex* instr) {
1424 Abort("Unimplemented: %s", "DoHasCachedArrayIndex");
1425 return NULL;
1426}
1427
1428
1429LInstruction* LChunkBuilder::DoClassOfTest(HClassOfTest* instr) {
1430 Abort("Unimplemented: %s", "DoClassOfTest");
1431 return NULL;
1432}
1433
1434
1435LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001436 LOperand* array = UseRegisterAtStart(instr->value());
1437 return DefineAsRegister(new LJSArrayLength(array));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001438}
1439
1440
1441LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001442 LOperand* array = UseRegisterAtStart(instr->value());
1443 return DefineAsRegister(new LFixedArrayLength(array));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001444}
1445
1446
1447LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
1448 Abort("Unimplemented: %s", "DoValueOf");
1449 return NULL;
1450}
1451
1452
1453LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001454 return AssignEnvironment(new LBoundsCheck(UseRegisterAtStart(instr->index()),
1455 Use(instr->length())));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001456}
1457
1458
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001459LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
1460 // The control instruction marking the end of a block that completed
1461 // abruptly (e.g., threw an exception). There is nothing specific to do.
1462 return NULL;
1463}
1464
1465
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001466LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001467 LOperand* value = UseFixed(instr->value(), rax);
1468 return MarkAsCall(new LThrow(value), instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001469}
1470
1471
1472LInstruction* LChunkBuilder::DoChange(HChange* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001473 Representation from = instr->from();
1474 Representation to = instr->to();
1475 if (from.IsTagged()) {
1476 if (to.IsDouble()) {
1477 LOperand* value = UseRegister(instr->value());
1478 LNumberUntagD* res = new LNumberUntagD(value);
1479 return AssignEnvironment(DefineAsRegister(res));
1480 } else {
1481 ASSERT(to.IsInteger32());
1482 LOperand* value = UseRegister(instr->value());
1483 bool needs_check = !instr->value()->type().IsSmi();
1484 if (needs_check) {
1485 LOperand* xmm_temp =
1486 (instr->CanTruncateToInt32() && CpuFeatures::IsSupported(SSE3))
1487 ? NULL
1488 : FixedTemp(xmm1);
1489 LTaggedToI* res = new LTaggedToI(value, xmm_temp);
1490 return AssignEnvironment(DefineSameAsFirst(res));
1491 } else {
1492 return DefineSameAsFirst(new LSmiUntag(value, needs_check));
1493 }
1494 }
1495 } else if (from.IsDouble()) {
1496 if (to.IsTagged()) {
1497 LOperand* value = UseRegister(instr->value());
1498 LOperand* temp = TempRegister();
1499
1500 // Make sure that temp and result_temp are different registers.
1501 LUnallocated* result_temp = TempRegister();
1502 LNumberTagD* result = new LNumberTagD(value, temp);
1503 return AssignPointerMap(Define(result, result_temp));
1504 } else {
1505 ASSERT(to.IsInteger32());
1506 bool needs_temp = instr->CanTruncateToInt32() &&
1507 !CpuFeatures::IsSupported(SSE3);
1508 LOperand* value = needs_temp ?
1509 UseTempRegister(instr->value()) : UseRegister(instr->value());
1510 LOperand* temp = needs_temp ? TempRegister() : NULL;
1511 return AssignEnvironment(DefineAsRegister(new LDoubleToI(value, temp)));
1512 }
1513 } else if (from.IsInteger32()) {
1514 if (to.IsTagged()) {
1515 HValue* val = instr->value();
1516 LOperand* value = UseRegister(val);
1517 if (val->HasRange() && val->range()->IsInSmiRange()) {
1518 return DefineSameAsFirst(new LSmiTag(value));
1519 } else {
1520 LNumberTagI* result = new LNumberTagI(value);
1521 return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1522 }
1523 } else {
1524 ASSERT(to.IsDouble());
1525 return DefineAsRegister(new LInteger32ToDouble(Use(instr->value())));
1526 }
1527 }
1528 UNREACHABLE();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001529 return NULL;
1530}
1531
1532
1533LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001534 LOperand* value = UseRegisterAtStart(instr->value());
1535 return AssignEnvironment(new LCheckSmi(value, zero));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001536}
1537
1538
1539LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001540 LOperand* value = UseRegisterAtStart(instr->value());
1541 LCheckInstanceType* result = new LCheckInstanceType(value);
1542 return AssignEnvironment(result);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001543}
1544
1545
1546LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001547 LOperand* temp = TempRegister();
1548 LCheckPrototypeMaps* result = new LCheckPrototypeMaps(temp);
1549 return AssignEnvironment(result);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001550}
1551
1552
1553LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001554 LOperand* value = UseRegisterAtStart(instr->value());
1555 return AssignEnvironment(new LCheckSmi(value, not_zero));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001556}
1557
1558
1559LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001560 LOperand* value = UseRegisterAtStart(instr->value());
1561 return AssignEnvironment(new LCheckFunction(value));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001562}
1563
1564
1565LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001566 LOperand* value = UseRegisterAtStart(instr->value());
1567 LCheckMap* result = new LCheckMap(value);
1568 return AssignEnvironment(result);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001569}
1570
1571
1572LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
1573 return new LReturn(UseFixed(instr->value(), rax));
1574}
1575
1576
1577LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
1578 Representation r = instr->representation();
1579 if (r.IsInteger32()) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001580 return DefineAsRegister(new LConstantI);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001581 } else if (r.IsDouble()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001582 LOperand* temp = TempRegister();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001583 return DefineAsRegister(new LConstantD(temp));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001584 } else if (r.IsTagged()) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001585 return DefineAsRegister(new LConstantT);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001586 } else {
1587 UNREACHABLE();
1588 return NULL;
1589 }
1590}
1591
1592
1593LInstruction* LChunkBuilder::DoLoadGlobal(HLoadGlobal* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001594 LLoadGlobal* result = new LLoadGlobal;
1595 return instr->check_hole_value()
1596 ? AssignEnvironment(DefineAsRegister(result))
1597 : DefineAsRegister(result);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001598}
1599
1600
1601LInstruction* LChunkBuilder::DoStoreGlobal(HStoreGlobal* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001602 LStoreGlobal* result = new LStoreGlobal(UseRegister(instr->value()),
1603 TempRegister());
1604 return instr->check_hole_value() ? AssignEnvironment(result) : result;
1605}
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001606
1607
1608LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
1609 Abort("Unimplemented: %s", "DoLoadContextSlot");
1610 return NULL;
1611}
1612
1613
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001614LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
1615 Abort("Unimplemented: DoStoreContextSlot");
1616 return NULL;
1617}
1618
1619
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001620LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001621 ASSERT(instr->representation().IsTagged());
1622 LOperand* obj = UseRegisterAtStart(instr->object());
1623 return DefineAsRegister(new LLoadNamedField(obj));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001624}
1625
1626
1627LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001628 LOperand* object = UseFixed(instr->object(), rax);
1629 LLoadNamedGeneric* result = new LLoadNamedGeneric(object);
1630 return MarkAsCall(DefineFixed(result, rax), instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001631}
1632
1633
1634LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
1635 HLoadFunctionPrototype* instr) {
1636 Abort("Unimplemented: %s", "DoLoadFunctionPrototype");
1637 return NULL;
1638}
1639
1640
1641LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001642 LOperand* input = UseRegisterAtStart(instr->value());
1643 return DefineSameAsFirst(new LLoadElements(input));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001644}
1645
1646
1647LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
1648 HLoadKeyedFastElement* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001649 ASSERT(instr->representation().IsTagged());
1650 ASSERT(instr->key()->representation().IsInteger32());
1651 LOperand* obj = UseRegisterAtStart(instr->object());
1652 LOperand* key = UseRegisterAtStart(instr->key());
1653 LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key);
1654 return AssignEnvironment(DefineSameAsFirst(result));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001655}
1656
1657
1658LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
1659 Abort("Unimplemented: %s", "DoLoadKeyedGeneric");
1660 return NULL;
1661}
1662
1663
1664LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
1665 HStoreKeyedFastElement* instr) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001666 bool needs_write_barrier = instr->NeedsWriteBarrier();
1667 ASSERT(instr->value()->representation().IsTagged());
1668 ASSERT(instr->object()->representation().IsTagged());
1669 ASSERT(instr->key()->representation().IsInteger32());
1670
1671 LOperand* obj = UseTempRegister(instr->object());
1672 LOperand* val = needs_write_barrier
1673 ? UseTempRegister(instr->value())
1674 : UseRegisterAtStart(instr->value());
1675 LOperand* key = needs_write_barrier
1676 ? UseTempRegister(instr->key())
1677 : UseRegisterOrConstantAtStart(instr->key());
1678
1679 return AssignEnvironment(new LStoreKeyedFastElement(obj, key, val));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001680}
1681
1682
1683LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
1684 Abort("Unimplemented: %s", "DoStoreKeyedGeneric");
1685 return NULL;
1686}
1687
1688
1689LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001690 bool needs_write_barrier = instr->NeedsWriteBarrier();
1691
1692 LOperand* obj = needs_write_barrier
1693 ? UseTempRegister(instr->object())
1694 : UseRegisterAtStart(instr->object());
1695
1696 LOperand* val = needs_write_barrier
1697 ? UseTempRegister(instr->value())
1698 : UseRegister(instr->value());
1699
1700 // We only need a scratch register if we have a write barrier or we
1701 // have a store into the properties array (not in-object-property).
1702 LOperand* temp = (!instr->is_in_object() || needs_write_barrier)
1703 ? TempRegister() : NULL;
1704
1705 return new LStoreNamedField(obj, val, temp);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001706}
1707
1708
1709LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
1710 Abort("Unimplemented: %s", "DoStoreNamedGeneric");
1711 return NULL;
1712}
1713
1714
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001715LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
1716 Abort("Unimplemented: %s", "DoStringCharCodeAt");
1717 return NULL;
1718}
1719
1720
1721LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
1722 Abort("Unimplemented: %s", "DoStringLength");
1723 return NULL;
1724}
1725
1726
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001727LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001728 return MarkAsCall(DefineFixed(new LArrayLiteral, rax), instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001729}
1730
1731
1732LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001733 return MarkAsCall(DefineFixed(new LObjectLiteral, rax), instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001734}
1735
1736
1737LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
1738 Abort("Unimplemented: %s", "DoRegExpLiteral");
1739 return NULL;
1740}
1741
1742
1743LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001744 return MarkAsCall(DefineFixed(new LFunctionLiteral, rax), instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001745}
1746
1747
1748LInstruction* LChunkBuilder::DoDeleteProperty(HDeleteProperty* instr) {
1749 Abort("Unimplemented: %s", "DoDeleteProperty");
1750 return NULL;
1751}
1752
1753
1754LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
1755 Abort("Unimplemented: %s", "DoOsrEntry");
1756 return NULL;
1757}
1758
1759
1760LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
1761 int spill_index = chunk()->GetParameterStackSlot(instr->index());
1762 return DefineAsSpilled(new LParameter, spill_index);
1763}
1764
1765
1766LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
1767 Abort("Unimplemented: %s", "DoUnknownOSRValue");
1768 return NULL;
1769}
1770
1771
1772LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001773 argument_count_ -= instr->argument_count();
1774 return MarkAsCall(DefineFixed(new LCallStub, rax), instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001775}
1776
1777
1778LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
1779 Abort("Unimplemented: %s", "DoArgumentsObject");
1780 return NULL;
1781}
1782
1783
1784LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
1785 Abort("Unimplemented: %s", "DoAccessArgumentsAt");
1786 return NULL;
1787}
1788
1789
1790LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
1791 Abort("Unimplemented: %s", "DoTypeof");
1792 return NULL;
1793}
1794
1795
1796LInstruction* LChunkBuilder::DoTypeofIs(HTypeofIs* instr) {
1797 Abort("Unimplemented: %s", "DoTypeofIs");
1798 return NULL;
1799}
1800
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001801
1802LInstruction* LChunkBuilder::DoIsConstructCall(HIsConstructCall* instr) {
1803 return DefineAsRegister(new LIsConstructCall);
1804}
1805
1806
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001807LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
1808 HEnvironment* env = current_block_->last_environment();
1809 ASSERT(env != NULL);
1810
1811 env->set_ast_id(instr->ast_id());
1812
1813 env->Drop(instr->pop_count());
1814 for (int i = 0; i < instr->values()->length(); ++i) {
1815 HValue* value = instr->values()->at(i);
1816 if (instr->HasAssignedIndexAt(i)) {
1817 env->Bind(instr->GetAssignedIndexAt(i), value);
1818 } else {
1819 env->Push(value);
1820 }
1821 }
1822 ASSERT(env->length() == instr->environment_length());
1823
1824 // If there is an instruction pending deoptimization environment create a
1825 // lazy bailout instruction to capture the environment.
fschneider@chromium.org1df6b472011-01-26 08:23:03 +00001826 if (pending_deoptimization_ast_id_ == instr->ast_id()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001827 LLazyBailout* lazy_bailout = new LLazyBailout;
1828 LInstruction* result = AssignEnvironment(lazy_bailout);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001829 instruction_pending_deoptimization_environment_->
fschneider@chromium.org1df6b472011-01-26 08:23:03 +00001830 set_deoptimization_environment(result->environment());
1831 ClearInstructionPendingDeoptimizationEnvironment();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001832 return result;
1833 }
1834
1835 return NULL;
1836}
1837
1838
1839LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
1840 return MarkAsCall(new LStackCheck, instr);
1841}
1842
1843
1844LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001845 HEnvironment* outer = current_block_->last_environment();
1846 HConstant* undefined = graph()->GetConstantUndefined();
1847 HEnvironment* inner = outer->CopyForInlining(instr->closure(),
1848 instr->function(),
1849 false,
1850 undefined);
1851 current_block_->UpdateEnvironment(inner);
1852 chunk_->AddInlinedClosure(instr->closure());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001853 return NULL;
1854}
1855
1856
1857LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001858 HEnvironment* outer = current_block_->last_environment()->outer();
1859 current_block_->UpdateEnvironment(outer);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001860 return NULL;
1861}
1862
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001863} } // namespace v8::internal
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001864
1865#endif // V8_TARGET_ARCH_X64