blob: 2dd5cf7337c1b7486540a044ee93d3708270d191 [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
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000032#include "x64/lithium-x64.h"
33#include "x64/lithium-codegen-x64.h"
34
35namespace v8 {
36namespace internal {
37
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000038#define DEFINE_COMPILE(type) \
39 void L##type::CompileToNative(LCodeGen* generator) { \
40 generator->Do##type(this); \
41 }
42LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
43#undef DEFINE_COMPILE
44
45LOsrEntry::LOsrEntry() {
46 for (int i = 0; i < Register::kNumAllocatableRegisters; ++i) {
47 register_spills_[i] = NULL;
48 }
49 for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; ++i) {
50 double_register_spills_[i] = NULL;
51 }
52}
53
54
55void LOsrEntry::MarkSpilledRegister(int allocation_index,
56 LOperand* spill_operand) {
57 ASSERT(spill_operand->IsStackSlot());
58 ASSERT(register_spills_[allocation_index] == NULL);
59 register_spills_[allocation_index] = spill_operand;
60}
61
62
63void LOsrEntry::MarkSpilledDoubleRegister(int allocation_index,
64 LOperand* spill_operand) {
65 ASSERT(spill_operand->IsDoubleStackSlot());
66 ASSERT(double_register_spills_[allocation_index] == NULL);
67 double_register_spills_[allocation_index] = spill_operand;
68}
69
70
71void LInstruction::PrintTo(StringStream* stream) {
72 stream->Add("%s ", this->Mnemonic());
73 if (HasResult()) {
74 PrintOutputOperandTo(stream);
75 }
76
77 PrintDataTo(stream);
78
79 if (HasEnvironment()) {
80 stream->Add(" ");
81 environment()->PrintTo(stream);
82 }
83
84 if (HasPointerMap()) {
85 stream->Add(" ");
86 pointer_map()->PrintTo(stream);
87 }
88}
89
90
91template<int R, int I, int T>
92void LTemplateInstruction<R, I, T>::PrintDataTo(StringStream* stream) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000093 stream->Add("= ");
94 inputs_.PrintOperandsTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000095}
96
97
98template<int R, int I, int T>
99void LTemplateInstruction<R, I, T>::PrintOutputOperandTo(StringStream* stream) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000100 results_.PrintOperandsTo(stream);
101}
102
103
104template<typename T, int N>
105void OperandContainer<T, N>::PrintOperandsTo(StringStream* stream) {
106 for (int i = 0; i < N; i++) {
107 if (i > 0) stream->Add(" ");
108 elems_[i]->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000109 }
110}
111
112
113void LLabel::PrintDataTo(StringStream* stream) {
114 LGap::PrintDataTo(stream);
115 LLabel* rep = replacement();
116 if (rep != NULL) {
117 stream->Add(" Dead block replaced with B%d", rep->block_id());
118 }
119}
120
121
122bool LGap::IsRedundant() const {
123 for (int i = 0; i < 4; i++) {
124 if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) {
125 return false;
126 }
127 }
128
129 return true;
130}
131
132
133void LGap::PrintDataTo(StringStream* stream) {
134 for (int i = 0; i < 4; i++) {
135 stream->Add("(");
136 if (parallel_moves_[i] != NULL) {
137 parallel_moves_[i]->PrintDataTo(stream);
138 }
139 stream->Add(") ");
140 }
141}
142
143
144const char* LArithmeticD::Mnemonic() const {
145 switch (op()) {
146 case Token::ADD: return "add-d";
147 case Token::SUB: return "sub-d";
148 case Token::MUL: return "mul-d";
149 case Token::DIV: return "div-d";
150 case Token::MOD: return "mod-d";
151 default:
152 UNREACHABLE();
153 return NULL;
154 }
155}
156
157
158const char* LArithmeticT::Mnemonic() const {
159 switch (op()) {
160 case Token::ADD: return "add-t";
161 case Token::SUB: return "sub-t";
162 case Token::MUL: return "mul-t";
163 case Token::MOD: return "mod-t";
164 case Token::DIV: return "div-t";
165 default:
166 UNREACHABLE();
167 return NULL;
168 }
169}
170
171
172void LGoto::PrintDataTo(StringStream* stream) {
173 stream->Add("B%d", block_id());
174}
175
176
177void LBranch::PrintDataTo(StringStream* stream) {
178 stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000179 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000180}
181
182
183void LCmpIDAndBranch::PrintDataTo(StringStream* stream) {
184 stream->Add("if ");
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000185 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000186 stream->Add(" %s ", Token::String(op()));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000187 InputAt(1)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000188 stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
189}
190
191
192void LIsNullAndBranch::PrintDataTo(StringStream* stream) {
193 stream->Add("if ");
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000194 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000195 stream->Add(is_strict() ? " === null" : " == null");
196 stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
197}
198
199
200void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
201 stream->Add("if is_object(");
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000202 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000203 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
204}
205
206
207void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
208 stream->Add("if is_smi(");
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000209 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000210 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
211}
212
213
214void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
215 stream->Add("if has_instance_type(");
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(") then B%d else B%d", true_block_id(), false_block_id());
218}
219
220
221void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
222 stream->Add("if has_cached_array_index(");
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000223 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000224 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
225}
226
227
228void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
229 stream->Add("if class_of_test(");
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000230 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000231 stream->Add(", \"%o\") then B%d else B%d",
232 *hydrogen()->class_name(),
233 true_block_id(),
234 false_block_id());
235}
236
237
238void LTypeofIs::PrintDataTo(StringStream* stream) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000239 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000240 stream->Add(" == \"%s\"", *hydrogen()->type_literal()->ToCString());
241}
242
243
244void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
245 stream->Add("if typeof ");
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000246 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000247 stream->Add(" == \"%s\" then B%d else B%d",
248 *hydrogen()->type_literal()->ToCString(),
249 true_block_id(), false_block_id());
250}
251
252
253void LCallConstantFunction::PrintDataTo(StringStream* stream) {
254 stream->Add("#%d / ", arity());
255}
256
257
258void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
259 stream->Add("/%s ", hydrogen()->OpName());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000260 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000261}
262
263
264void LLoadContextSlot::PrintDataTo(StringStream* stream) {
265 stream->Add("(%d, %d)", context_chain_length(), slot_index());
266}
267
268
269void LCallKeyed::PrintDataTo(StringStream* stream) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000270 stream->Add("[ecx] #%d / ", arity());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000271}
272
273
274void LCallNamed::PrintDataTo(StringStream* stream) {
275 SmartPointer<char> name_string = name()->ToCString();
276 stream->Add("%s #%d / ", *name_string, arity());
277}
278
279
280void LCallGlobal::PrintDataTo(StringStream* stream) {
281 SmartPointer<char> name_string = name()->ToCString();
282 stream->Add("%s #%d / ", *name_string, arity());
283}
284
285
286void LCallKnownGlobal::PrintDataTo(StringStream* stream) {
287 stream->Add("#%d / ", arity());
288}
289
290
291void LCallNew::PrintDataTo(StringStream* stream) {
292 stream->Add("= ");
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000293 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000294 stream->Add(" #%d / ", arity());
295}
296
297
298void LClassOfTest::PrintDataTo(StringStream* stream) {
299 stream->Add("= class_of_test(");
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000300 InputAt(0)->PrintTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000301 stream->Add(", \"%o\")", *hydrogen()->class_name());
302}
303
304
305void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
306 arguments()->PrintTo(stream);
307
308 stream->Add(" length ");
309 length()->PrintTo(stream);
310
311 stream->Add(" index ");
312 index()->PrintTo(stream);
313}
314
315
316int LChunk::GetNextSpillIndex(bool is_double) {
317 return spill_slot_count_++;
318}
319
320
321LOperand* LChunk::GetNextSpillSlot(bool is_double) {
322 // All stack slots are Double stack slots on x64.
323 // Alternatively, at some point, start using half-size
324 // stack slots for int32 values.
325 int index = GetNextSpillIndex(is_double);
326 if (is_double) {
327 return LDoubleStackSlot::Create(index);
328 } else {
329 return LStackSlot::Create(index);
330 }
331}
332
333
334void LChunk::MarkEmptyBlocks() {
335 HPhase phase("Mark empty blocks", this);
336 for (int i = 0; i < graph()->blocks()->length(); ++i) {
337 HBasicBlock* block = graph()->blocks()->at(i);
338 int first = block->first_instruction_index();
339 int last = block->last_instruction_index();
340 LInstruction* first_instr = instructions()->at(first);
341 LInstruction* last_instr = instructions()->at(last);
342
343 LLabel* label = LLabel::cast(first_instr);
344 if (last_instr->IsGoto()) {
345 LGoto* goto_instr = LGoto::cast(last_instr);
346 if (!goto_instr->include_stack_check() &&
347 label->IsRedundant() &&
348 !label->is_loop_header()) {
349 bool can_eliminate = true;
350 for (int i = first + 1; i < last && can_eliminate; ++i) {
351 LInstruction* cur = instructions()->at(i);
352 if (cur->IsGap()) {
353 LGap* gap = LGap::cast(cur);
354 if (!gap->IsRedundant()) {
355 can_eliminate = false;
356 }
357 } else {
358 can_eliminate = false;
359 }
360 }
361
362 if (can_eliminate) {
363 label->set_replacement(GetLabel(goto_instr->block_id()));
364 }
365 }
366 }
367 }
368}
369
370
371void LStoreNamed::PrintDataTo(StringStream* stream) {
372 object()->PrintTo(stream);
373 stream->Add(".");
374 stream->Add(*String::cast(*name())->ToCString());
375 stream->Add(" <- ");
376 value()->PrintTo(stream);
377}
378
379
380void LStoreKeyed::PrintDataTo(StringStream* stream) {
381 object()->PrintTo(stream);
382 stream->Add("[");
383 key()->PrintTo(stream);
384 stream->Add("] <- ");
385 value()->PrintTo(stream);
386}
387
388
389int LChunk::AddInstruction(LInstruction* instr, HBasicBlock* block) {
390 LGap* gap = new LGap(block);
391 int index = -1;
392 if (instr->IsControl()) {
393 instructions_.Add(gap);
394 index = instructions_.length();
395 instructions_.Add(instr);
396 } else {
397 index = instructions_.length();
398 instructions_.Add(instr);
399 instructions_.Add(gap);
400 }
401 if (instr->HasPointerMap()) {
402 pointer_maps_.Add(instr->pointer_map());
403 instr->pointer_map()->set_lithium_position(index);
404 }
405 return index;
406}
407
408
409LConstantOperand* LChunk::DefineConstantOperand(HConstant* constant) {
410 return LConstantOperand::Create(constant->id());
411}
412
413
414int LChunk::GetParameterStackSlot(int index) const {
415 // The receiver is at index 0, the first parameter at index 1, so we
416 // shift all parameter indexes down by the number of parameters, and
417 // make sure they end up negative so they are distinguishable from
418 // spill slots.
419 int result = index - graph()->info()->scope()->num_parameters() - 1;
420 ASSERT(result < 0);
421 return result;
422}
423
424// A parameter relative to ebp in the arguments stub.
425int LChunk::ParameterAt(int index) {
426 ASSERT(-1 <= index); // -1 is the receiver.
427 return (1 + graph()->info()->scope()->num_parameters() - index) *
428 kPointerSize;
429}
430
431
432LGap* LChunk::GetGapAt(int index) const {
433 return LGap::cast(instructions_[index]);
434}
435
436
437bool LChunk::IsGapAt(int index) const {
438 return instructions_[index]->IsGap();
439}
440
441
442int LChunk::NearestGapPos(int index) const {
443 while (!IsGapAt(index)) index--;
444 return index;
445}
446
447
448void LChunk::AddGapMove(int index, LOperand* from, LOperand* to) {
449 GetGapAt(index)->GetOrCreateParallelMove(LGap::START)->AddMove(from, to);
450}
451
452
453Handle<Object> LChunk::LookupLiteral(LConstantOperand* operand) const {
454 return HConstant::cast(graph_->LookupValue(operand->index()))->handle();
455}
456
457
458Representation LChunk::LookupLiteralRepresentation(
459 LConstantOperand* operand) const {
460 return graph_->LookupValue(operand->index())->representation();
461}
462
463
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000464LChunk* LChunkBuilder::Build() {
465 ASSERT(is_unused());
466 chunk_ = new LChunk(graph());
467 HPhase phase("Building chunk", chunk_);
468 status_ = BUILDING;
469 const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
470 for (int i = 0; i < blocks->length(); i++) {
471 HBasicBlock* next = NULL;
472 if (i < blocks->length() - 1) next = blocks->at(i + 1);
473 DoBasicBlock(blocks->at(i), next);
474 if (is_aborted()) return NULL;
475 }
476 status_ = DONE;
477 return chunk_;
478}
479
480
481void LChunkBuilder::Abort(const char* format, ...) {
482 if (FLAG_trace_bailout) {
483 SmartPointer<char> debug_name = graph()->debug_name()->ToCString();
484 PrintF("Aborting LChunk building in @\"%s\": ", *debug_name);
485 va_list arguments;
486 va_start(arguments, format);
487 OS::VPrint(format, arguments);
488 va_end(arguments);
489 PrintF("\n");
490 }
491 status_ = ABORTED;
492}
493
494
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000495LRegister* LChunkBuilder::ToOperand(Register reg) {
496 return LRegister::Create(Register::ToAllocationIndex(reg));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000497}
498
499
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000500LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
501 return new LUnallocated(LUnallocated::FIXED_REGISTER,
502 Register::ToAllocationIndex(reg));
503}
504
505
506LUnallocated* LChunkBuilder::ToUnallocated(XMMRegister reg) {
507 return new LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
508 XMMRegister::ToAllocationIndex(reg));
509}
510
511
512LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
513 return Use(value, ToUnallocated(fixed_register));
514}
515
516
517LOperand* LChunkBuilder::UseFixedDouble(HValue* value, XMMRegister reg) {
518 return Use(value, ToUnallocated(reg));
519}
520
521
522LOperand* LChunkBuilder::UseRegister(HValue* value) {
523 return Use(value, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
524}
525
526
527LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
528 return Use(value,
529 new LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
530 LUnallocated::USED_AT_START));
531}
532
533
534LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
535 return Use(value, new LUnallocated(LUnallocated::WRITABLE_REGISTER));
536}
537
538
539LOperand* LChunkBuilder::Use(HValue* value) {
540 return Use(value, new LUnallocated(LUnallocated::NONE));
541}
542
543
544LOperand* LChunkBuilder::UseAtStart(HValue* value) {
545 return Use(value, new LUnallocated(LUnallocated::NONE,
546 LUnallocated::USED_AT_START));
547}
548
549
550LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
551 return value->IsConstant()
552 ? chunk_->DefineConstantOperand(HConstant::cast(value))
553 : Use(value);
554}
555
556
557LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
558 return value->IsConstant()
559 ? chunk_->DefineConstantOperand(HConstant::cast(value))
560 : UseAtStart(value);
561}
562
563
564LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
565 return value->IsConstant()
566 ? chunk_->DefineConstantOperand(HConstant::cast(value))
567 : UseRegister(value);
568}
569
570
571LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
572 return value->IsConstant()
573 ? chunk_->DefineConstantOperand(HConstant::cast(value))
574 : UseRegisterAtStart(value);
575}
576
577
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000578LOperand* LChunkBuilder::UseAny(HValue* value) {
579 return value->IsConstant()
580 ? chunk_->DefineConstantOperand(HConstant::cast(value))
581 : Use(value, new LUnallocated(LUnallocated::ANY));
582}
583
584
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000585LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
586 if (value->EmitAtUses()) {
587 HInstruction* instr = HInstruction::cast(value);
588 VisitInstruction(instr);
589 }
590 allocator_->RecordUse(value, operand);
591 return operand;
592}
593
594
595template<int I, int T>
596LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
597 LUnallocated* result) {
598 allocator_->RecordDefinition(current_instruction_, result);
599 instr->set_result(result);
600 return instr;
601}
602
603
604template<int I, int T>
605LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr) {
606 return Define(instr, new LUnallocated(LUnallocated::NONE));
607}
608
609
610template<int I, int T>
611LInstruction* LChunkBuilder::DefineAsRegister(
612 LTemplateInstruction<1, I, T>* instr) {
613 return Define(instr, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
614}
615
616
617template<int I, int T>
618LInstruction* LChunkBuilder::DefineAsSpilled(
619 LTemplateInstruction<1, I, T>* instr,
620 int index) {
621 return Define(instr, new LUnallocated(LUnallocated::FIXED_SLOT, index));
622}
623
624
625template<int I, int T>
626LInstruction* LChunkBuilder::DefineSameAsFirst(
627 LTemplateInstruction<1, I, T>* instr) {
628 return Define(instr, new LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
629}
630
631
632template<int I, int T>
633LInstruction* LChunkBuilder::DefineFixed(LTemplateInstruction<1, I, T>* instr,
634 Register reg) {
635 return Define(instr, ToUnallocated(reg));
636}
637
638
639template<int I, int T>
640LInstruction* LChunkBuilder::DefineFixedDouble(
641 LTemplateInstruction<1, I, T>* instr,
642 XMMRegister reg) {
643 return Define(instr, ToUnallocated(reg));
644}
645
646
647LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
648 HEnvironment* hydrogen_env = current_block_->last_environment();
649 instr->set_environment(CreateEnvironment(hydrogen_env));
650 return instr;
651}
652
653
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000654LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
655 LInstruction* instr, int ast_id) {
656 ASSERT(instructions_pending_deoptimization_environment_ == NULL);
657 ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
658 instructions_pending_deoptimization_environment_ = instr;
659 pending_deoptimization_ast_id_ = ast_id;
660 return instr;
661}
662
663
664void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
665 instructions_pending_deoptimization_environment_ = NULL;
666 pending_deoptimization_ast_id_ = AstNode::kNoNumber;
667}
668
669
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000670LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
671 HInstruction* hinstr,
672 CanDeoptimize can_deoptimize) {
673 allocator_->MarkAsCall();
674 instr = AssignPointerMap(instr);
675
676 if (hinstr->HasSideEffects()) {
677 ASSERT(hinstr->next()->IsSimulate());
678 HSimulate* sim = HSimulate::cast(hinstr->next());
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000679 instr = SetInstructionPendingDeoptimizationEnvironment(
680 instr, sim->ast_id());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000681 }
682
683 // If instruction does not have side-effects lazy deoptimization
684 // after the call will try to deoptimize to the point before the call.
685 // Thus we still need to attach environment to this call even if
686 // call sequence can not deoptimize eagerly.
687 bool needs_environment =
688 (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) || !hinstr->HasSideEffects();
689 if (needs_environment && !instr->HasEnvironment()) {
690 instr = AssignEnvironment(instr);
691 }
692
693 return instr;
694}
695
696
697LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) {
698 allocator_->MarkAsSaveDoubles();
699 return instr;
700}
701
702
703LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
704 ASSERT(!instr->HasPointerMap());
705 instr->set_pointer_map(new LPointerMap(position_));
706 return instr;
707}
708
709
710LUnallocated* LChunkBuilder::TempRegister() {
711 LUnallocated* operand = new LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
712 allocator_->RecordTemporary(operand);
713 return operand;
714}
715
716
717LOperand* LChunkBuilder::FixedTemp(Register reg) {
718 LUnallocated* operand = ToUnallocated(reg);
719 allocator_->RecordTemporary(operand);
720 return operand;
721}
722
723
724LOperand* LChunkBuilder::FixedTemp(XMMRegister reg) {
725 LUnallocated* operand = ToUnallocated(reg);
726 allocator_->RecordTemporary(operand);
727 return operand;
728}
729
730
731LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
732 return new LLabel(instr->block());
733}
734
735
736LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
737 return AssignEnvironment(new LDeoptimize);
738}
739
740
741LInstruction* LChunkBuilder::DoBit(Token::Value op,
742 HBitwiseBinaryOperation* instr) {
743 Abort("Unimplemented: %s", "DoBit");
744 return NULL;
745}
746
747
748LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
749 HArithmeticBinaryOperation* instr) {
750 Abort("Unimplemented: %s", "DoArithmeticD");
751 return NULL;
752}
753
754
755LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
756 HArithmeticBinaryOperation* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000757 ASSERT(op == Token::ADD ||
758 op == Token::DIV ||
759 op == Token::MOD ||
760 op == Token::MUL ||
761 op == Token::SUB);
762 HValue* left = instr->left();
763 HValue* right = instr->right();
764 ASSERT(left->representation().IsTagged());
765 ASSERT(right->representation().IsTagged());
766 LOperand* left_operand = UseFixed(left, rdx);
767 LOperand* right_operand = UseFixed(right, rax);
768 LArithmeticT* result = new LArithmeticT(op, left_operand, right_operand);
769 return MarkAsCall(DefineFixed(result, rax), instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000770}
771
772
773void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
774 ASSERT(is_building());
775 current_block_ = block;
776 next_block_ = next_block;
777 if (block->IsStartBlock()) {
778 block->UpdateEnvironment(graph_->start_environment());
779 argument_count_ = 0;
780 } else if (block->predecessors()->length() == 1) {
781 // We have a single predecessor => copy environment and outgoing
782 // argument count from the predecessor.
783 ASSERT(block->phis()->length() == 0);
784 HBasicBlock* pred = block->predecessors()->at(0);
785 HEnvironment* last_environment = pred->last_environment();
786 ASSERT(last_environment != NULL);
787 // Only copy the environment, if it is later used again.
788 if (pred->end()->SecondSuccessor() == NULL) {
789 ASSERT(pred->end()->FirstSuccessor() == block);
790 } else {
791 if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
792 pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
793 last_environment = last_environment->Copy();
794 }
795 }
796 block->UpdateEnvironment(last_environment);
797 ASSERT(pred->argument_count() >= 0);
798 argument_count_ = pred->argument_count();
799 } else {
800 // We are at a state join => process phis.
801 HBasicBlock* pred = block->predecessors()->at(0);
802 // No need to copy the environment, it cannot be used later.
803 HEnvironment* last_environment = pred->last_environment();
804 for (int i = 0; i < block->phis()->length(); ++i) {
805 HPhi* phi = block->phis()->at(i);
806 last_environment->SetValueAt(phi->merged_index(), phi);
807 }
808 for (int i = 0; i < block->deleted_phis()->length(); ++i) {
809 last_environment->SetValueAt(block->deleted_phis()->at(i),
810 graph_->GetConstantUndefined());
811 }
812 block->UpdateEnvironment(last_environment);
813 // Pick up the outgoing argument count of one of the predecessors.
814 argument_count_ = pred->argument_count();
815 }
816 HInstruction* current = block->first();
817 int start = chunk_->instructions()->length();
818 while (current != NULL && !is_aborted()) {
819 // Code for constants in registers is generated lazily.
820 if (!current->EmitAtUses()) {
821 VisitInstruction(current);
822 }
823 current = current->next();
824 }
825 int end = chunk_->instructions()->length() - 1;
826 if (end >= start) {
827 block->set_first_instruction_index(start);
828 block->set_last_instruction_index(end);
829 }
830 block->set_argument_count(argument_count_);
831 next_block_ = NULL;
832 current_block_ = NULL;
833}
834
835
836void LChunkBuilder::VisitInstruction(HInstruction* current) {
837 HInstruction* old_current = current_instruction_;
838 current_instruction_ = current;
839 allocator_->BeginInstruction();
840 if (current->has_position()) position_ = current->position();
841 LInstruction* instr = current->CompileToLithium(this);
842
843 if (instr != NULL) {
844 if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
845 instr = AssignPointerMap(instr);
846 }
847 if (FLAG_stress_environments && !instr->HasEnvironment()) {
848 instr = AssignEnvironment(instr);
849 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000850 if (current->IsTest() && !instr->IsGoto()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000851 ASSERT(instr->IsControl());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000852 HTest* test = HTest::cast(current);
853 instr->set_hydrogen_value(test->value());
854 HBasicBlock* first = test->FirstSuccessor();
855 HBasicBlock* second = test->SecondSuccessor();
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000856 ASSERT(first != NULL && second != NULL);
857 instr->SetBranchTargets(first->block_id(), second->block_id());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000858 } else {
859 instr->set_hydrogen_value(current);
860 }
861
862 int index = chunk_->AddInstruction(instr, current_block_);
863 allocator_->SummarizeInstruction(index);
864 } else {
865 // This instruction should be omitted.
866 allocator_->OmitInstruction();
867 }
868 current_instruction_ = old_current;
869}
870
871
872LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) {
873 if (hydrogen_env == NULL) return NULL;
874
875 LEnvironment* outer = CreateEnvironment(hydrogen_env->outer());
876 int ast_id = hydrogen_env->ast_id();
877 ASSERT(ast_id != AstNode::kNoNumber);
878 int value_count = hydrogen_env->length();
879 LEnvironment* result = new LEnvironment(hydrogen_env->closure(),
880 ast_id,
881 hydrogen_env->parameter_count(),
882 argument_count_,
883 value_count,
884 outer);
885 int argument_index = 0;
886 for (int i = 0; i < value_count; ++i) {
887 HValue* value = hydrogen_env->values()->at(i);
888 LOperand* op = NULL;
889 if (value->IsArgumentsObject()) {
890 op = NULL;
891 } else if (value->IsPushArgument()) {
892 op = new LArgument(argument_index++);
893 } else {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000894 op = UseAny(value);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000895 }
896 result->AddValue(op, value->representation());
897 }
898
899 return result;
900}
901
902
903LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
904 LGoto* result = new LGoto(instr->FirstSuccessor()->block_id(),
905 instr->include_stack_check());
906 return (instr->include_stack_check())
907 ? AssignPointerMap(result)
908 : result;
909}
910
911
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000912LInstruction* LChunkBuilder::DoTest(HTest* instr) {
913 HValue* v = instr->value();
914 if (v->EmitAtUses()) {
915 if (v->IsClassOfTest()) {
916 HClassOfTest* compare = HClassOfTest::cast(v);
917 ASSERT(compare->value()->representation().IsTagged());
918
919 return new LClassOfTestAndBranch(UseTempRegister(compare->value()),
920 TempRegister());
921 } else if (v->IsCompare()) {
922 HCompare* compare = HCompare::cast(v);
923 Token::Value op = compare->token();
924 HValue* left = compare->left();
925 HValue* right = compare->right();
926 Representation r = compare->GetInputRepresentation();
927 if (r.IsInteger32()) {
928 ASSERT(left->representation().IsInteger32());
929 ASSERT(right->representation().IsInteger32());
930
931 return new LCmpIDAndBranch(UseRegisterAtStart(left),
932 UseOrConstantAtStart(right));
933 } else if (r.IsDouble()) {
934 ASSERT(left->representation().IsDouble());
935 ASSERT(right->representation().IsDouble());
936
937 return new LCmpIDAndBranch(UseRegisterAtStart(left),
938 UseRegisterAtStart(right));
939 } else {
940 ASSERT(left->representation().IsTagged());
941 ASSERT(right->representation().IsTagged());
942 bool reversed = op == Token::GT || op == Token::LTE;
943 LOperand* left_operand = UseFixed(left, reversed ? rax : rdx);
944 LOperand* right_operand = UseFixed(right, reversed ? rdx : rax);
945 LCmpTAndBranch* result = new LCmpTAndBranch(left_operand,
946 right_operand);
947 return MarkAsCall(result, instr);
948 }
949 } else if (v->IsIsSmi()) {
950 HIsSmi* compare = HIsSmi::cast(v);
951 ASSERT(compare->value()->representation().IsTagged());
952
953 return new LIsSmiAndBranch(Use(compare->value()));
954 } else if (v->IsHasInstanceType()) {
955 HHasInstanceType* compare = HHasInstanceType::cast(v);
956 ASSERT(compare->value()->representation().IsTagged());
957
958 return new LHasInstanceTypeAndBranch(
959 UseRegisterAtStart(compare->value()));
960 } else if (v->IsHasCachedArrayIndex()) {
961 HHasCachedArrayIndex* compare = HHasCachedArrayIndex::cast(v);
962 ASSERT(compare->value()->representation().IsTagged());
963
964 return new LHasCachedArrayIndexAndBranch(
965 UseRegisterAtStart(compare->value()));
966 } else if (v->IsIsNull()) {
967 HIsNull* compare = HIsNull::cast(v);
968 ASSERT(compare->value()->representation().IsTagged());
969
970 // We only need a temp register for non-strict compare.
971 LOperand* temp = compare->is_strict() ? NULL : TempRegister();
972 return new LIsNullAndBranch(UseRegisterAtStart(compare->value()),
973 temp);
974 } else if (v->IsIsObject()) {
975 HIsObject* compare = HIsObject::cast(v);
976 ASSERT(compare->value()->representation().IsTagged());
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000977 return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000978 } else if (v->IsCompareJSObjectEq()) {
979 HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
980 return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()),
981 UseRegisterAtStart(compare->right()));
982 } else if (v->IsInstanceOf()) {
983 HInstanceOf* instance_of = HInstanceOf::cast(v);
984 LInstanceOfAndBranch* result =
985 new LInstanceOfAndBranch(
986 UseFixed(instance_of->left(), InstanceofStub::left()),
987 UseFixed(instance_of->right(), InstanceofStub::right()));
988 return MarkAsCall(result, instr);
989 } else if (v->IsTypeofIs()) {
990 HTypeofIs* typeof_is = HTypeofIs::cast(v);
991 return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
992 } else {
993 if (v->IsConstant()) {
994 if (HConstant::cast(v)->handle()->IsTrue()) {
995 return new LGoto(instr->FirstSuccessor()->block_id());
996 } else if (HConstant::cast(v)->handle()->IsFalse()) {
997 return new LGoto(instr->SecondSuccessor()->block_id());
998 }
999 }
1000 Abort("Undefined compare before branch");
1001 return NULL;
1002 }
1003 }
1004 return new LBranch(UseRegisterAtStart(v));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001005}
1006
1007
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001008LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
1009 Abort("Unimplemented: %s", "DoCompareMap");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001010 return NULL;
1011}
1012
1013
1014LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) {
1015 Abort("Unimplemented: %s", "DoArgumentsLength");
1016 return NULL;
1017}
1018
1019
1020LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
1021 Abort("Unimplemented: %s", "DoArgumentsElements");
1022 return NULL;
1023}
1024
1025
1026LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
1027 Abort("Unimplemented: %s", "DoInstanceOf");
1028 return NULL;
1029}
1030
1031
1032LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
1033 HInstanceOfKnownGlobal* instr) {
1034 Abort("Unimplemented: %s", "DoInstanceOfKnownGlobal");
1035 return NULL;
1036}
1037
1038
1039LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
1040 Abort("Unimplemented: %s", "DoApplyArguments");
1041 return NULL;
1042}
1043
1044
1045LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001046 ++argument_count_;
1047 LOperand* argument = UseOrConstant(instr->argument());
1048 return new LPushArgument(argument);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001049}
1050
1051
1052LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001053 return DefineAsRegister(new LGlobalObject);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001054}
1055
1056
1057LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001058 return DefineAsRegister(new LGlobalReceiver);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001059}
1060
1061
1062LInstruction* LChunkBuilder::DoCallConstantFunction(
1063 HCallConstantFunction* instr) {
1064 Abort("Unimplemented: %s", "DoCallConstantFunction");
1065 return NULL;
1066}
1067
1068
1069LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
1070 Abort("Unimplemented: %s", "DoUnaryMathOperation");
1071 return NULL;
1072}
1073
1074
1075LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
1076 Abort("Unimplemented: %s", "DoCallKeyed");
1077 return NULL;
1078}
1079
1080
1081LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
1082 Abort("Unimplemented: %s", "DoCallNamed");
1083 return NULL;
1084}
1085
1086
1087LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
1088 Abort("Unimplemented: %s", "DoCallGlobal");
1089 return NULL;
1090}
1091
1092
1093LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
1094 Abort("Unimplemented: %s", "DoCallKnownGlobal");
1095 return NULL;
1096}
1097
1098
1099LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001100 LOperand* constructor = UseFixed(instr->constructor(), rdi);
1101 argument_count_ -= instr->argument_count();
1102 LCallNew* result = new LCallNew(constructor);
1103 return MarkAsCall(DefineFixed(result, rax), instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001104}
1105
1106
1107LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
1108 Abort("Unimplemented: %s", "DoCallFunction");
1109 return NULL;
1110}
1111
1112
1113LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1114 Abort("Unimplemented: %s", "DoCallRuntime");
1115 return NULL;
1116}
1117
1118
1119LInstruction* LChunkBuilder::DoShr(HShr* instr) {
1120 Abort("Unimplemented: %s", "DoShr");
1121 return NULL;
1122}
1123
1124
1125LInstruction* LChunkBuilder::DoSar(HSar* instr) {
1126 Abort("Unimplemented: %s", "DoSar");
1127 return NULL;
1128}
1129
1130
1131LInstruction* LChunkBuilder::DoShl(HShl* instr) {
1132 Abort("Unimplemented: %s", "DoShl");
1133 return NULL;
1134}
1135
1136
1137LInstruction* LChunkBuilder::DoBitAnd(HBitAnd* instr) {
1138 Abort("Unimplemented: %s", "DoBitAnd");
1139 return NULL;
1140}
1141
1142
1143LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
1144 Abort("Unimplemented: %s", "DoBitNot");
1145 return NULL;
1146}
1147
1148
1149LInstruction* LChunkBuilder::DoBitOr(HBitOr* instr) {
1150 Abort("Unimplemented: %s", "DoBitOr");
1151 return NULL;
1152}
1153
1154
1155LInstruction* LChunkBuilder::DoBitXor(HBitXor* instr) {
1156 Abort("Unimplemented: %s", "DoBitXor");
1157 return NULL;
1158}
1159
1160
1161LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1162 Abort("Unimplemented: %s", "DoDiv");
1163 return NULL;
1164}
1165
1166
1167LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1168 Abort("Unimplemented: %s", "DoMod");
1169 return NULL;
1170}
1171
1172
1173LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1174 Abort("Unimplemented: %s", "DoMul");
1175 return NULL;
1176}
1177
1178
1179LInstruction* LChunkBuilder::DoSub(HSub* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001180 if (instr->representation().IsInteger32()) {
1181 ASSERT(instr->left()->representation().IsInteger32());
1182 ASSERT(instr->right()->representation().IsInteger32());
1183 LOperand* left = UseRegisterAtStart(instr->left());
1184 LOperand* right = UseOrConstantAtStart(instr->right());
1185 LSubI* sub = new LSubI(left, right);
1186 LInstruction* result = DefineSameAsFirst(sub);
1187 if (instr->CheckFlag(HValue::kCanOverflow)) {
1188 result = AssignEnvironment(result);
1189 }
1190 return result;
1191 } else if (instr->representation().IsDouble()) {
1192 return DoArithmeticD(Token::SUB, instr);
1193 } else {
1194 ASSERT(instr->representation().IsTagged());
1195 return DoArithmeticT(Token::SUB, instr);
1196 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001197}
1198
1199
1200LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001201 if (instr->representation().IsInteger32()) {
1202 ASSERT(instr->left()->representation().IsInteger32());
1203 ASSERT(instr->right()->representation().IsInteger32());
1204 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1205 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
1206 LAddI* add = new LAddI(left, right);
1207 LInstruction* result = DefineSameAsFirst(add);
1208 if (instr->CheckFlag(HValue::kCanOverflow)) {
1209 result = AssignEnvironment(result);
1210 }
1211 return result;
1212 } else if (instr->representation().IsDouble()) {
1213 Abort("Unimplemented: %s", "DoAdd on Doubles");
1214 } else {
1215 ASSERT(instr->representation().IsTagged());
1216 return DoArithmeticT(Token::ADD, instr);
1217 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001218 return NULL;
1219}
1220
1221
1222LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1223 Abort("Unimplemented: %s", "DoPower");
1224 return NULL;
1225}
1226
1227
1228LInstruction* LChunkBuilder::DoCompare(HCompare* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001229 Token::Value op = instr->token();
1230 Representation r = instr->GetInputRepresentation();
1231 if (r.IsInteger32()) {
1232 ASSERT(instr->left()->representation().IsInteger32());
1233 ASSERT(instr->right()->representation().IsInteger32());
1234 LOperand* left = UseRegisterAtStart(instr->left());
1235 LOperand* right = UseOrConstantAtStart(instr->right());
1236 return DefineAsRegister(new LCmpID(left, right));
1237 } else if (r.IsDouble()) {
1238 ASSERT(instr->left()->representation().IsDouble());
1239 ASSERT(instr->right()->representation().IsDouble());
1240 LOperand* left = UseRegisterAtStart(instr->left());
1241 LOperand* right = UseRegisterAtStart(instr->right());
1242 return DefineAsRegister(new LCmpID(left, right));
1243 } else {
1244 ASSERT(instr->left()->representation().IsTagged());
1245 ASSERT(instr->right()->representation().IsTagged());
1246 bool reversed = (op == Token::GT || op == Token::LTE);
1247 LOperand* left = UseFixed(instr->left(), reversed ? rax : rdx);
1248 LOperand* right = UseFixed(instr->right(), reversed ? rdx : rax);
1249 LCmpT* result = new LCmpT(left, right);
1250 return MarkAsCall(DefineFixed(result, rax), instr);
1251 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001252}
1253
1254
1255LInstruction* LChunkBuilder::DoCompareJSObjectEq(
1256 HCompareJSObjectEq* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001257 LOperand* left = UseRegisterAtStart(instr->left());
1258 LOperand* right = UseRegisterAtStart(instr->right());
1259 LCmpJSObjectEq* result = new LCmpJSObjectEq(left, right);
1260 return DefineAsRegister(result);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001261}
1262
1263
1264LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001265 ASSERT(instr->value()->representation().IsTagged());
1266 LOperand* value = UseRegisterAtStart(instr->value());
1267
1268 return DefineAsRegister(new LIsNull(value));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001269}
1270
1271
1272LInstruction* LChunkBuilder::DoIsObject(HIsObject* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001273 ASSERT(instr->value()->representation().IsTagged());
1274 LOperand* value = UseRegister(instr->value());
1275
1276 return DefineAsRegister(new LIsObject(value));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001277}
1278
1279
1280LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001281 ASSERT(instr->value()->representation().IsTagged());
1282 LOperand* value = UseAtStart(instr->value());
1283
1284 return DefineAsRegister(new LIsSmi(value));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001285}
1286
1287
1288LInstruction* LChunkBuilder::DoHasInstanceType(HHasInstanceType* instr) {
1289 Abort("Unimplemented: %s", "DoHasInstanceType");
1290 return NULL;
1291}
1292
1293
1294LInstruction* LChunkBuilder::DoHasCachedArrayIndex(
1295 HHasCachedArrayIndex* instr) {
1296 Abort("Unimplemented: %s", "DoHasCachedArrayIndex");
1297 return NULL;
1298}
1299
1300
1301LInstruction* LChunkBuilder::DoClassOfTest(HClassOfTest* instr) {
1302 Abort("Unimplemented: %s", "DoClassOfTest");
1303 return NULL;
1304}
1305
1306
1307LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
1308 Abort("Unimplemented: %s", "DoJSArrayLength");
1309 return NULL;
1310}
1311
1312
1313LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
1314 Abort("Unimplemented: %s", "DoFixedArrayLength");
1315 return NULL;
1316}
1317
1318
1319LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
1320 Abort("Unimplemented: %s", "DoValueOf");
1321 return NULL;
1322}
1323
1324
1325LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1326 Abort("Unimplemented: %s", "DoBoundsCheck");
1327 return NULL;
1328}
1329
1330
1331LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
1332 Abort("Unimplemented: %s", "DoThrow");
1333 return NULL;
1334}
1335
1336
1337LInstruction* LChunkBuilder::DoChange(HChange* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001338 Representation from = instr->from();
1339 Representation to = instr->to();
1340 if (from.IsTagged()) {
1341 if (to.IsDouble()) {
1342 LOperand* value = UseRegister(instr->value());
1343 LNumberUntagD* res = new LNumberUntagD(value);
1344 return AssignEnvironment(DefineAsRegister(res));
1345 } else {
1346 ASSERT(to.IsInteger32());
1347 LOperand* value = UseRegister(instr->value());
1348 bool needs_check = !instr->value()->type().IsSmi();
1349 if (needs_check) {
1350 LOperand* xmm_temp =
1351 (instr->CanTruncateToInt32() && CpuFeatures::IsSupported(SSE3))
1352 ? NULL
1353 : FixedTemp(xmm1);
1354 LTaggedToI* res = new LTaggedToI(value, xmm_temp);
1355 return AssignEnvironment(DefineSameAsFirst(res));
1356 } else {
1357 return DefineSameAsFirst(new LSmiUntag(value, needs_check));
1358 }
1359 }
1360 } else if (from.IsDouble()) {
1361 if (to.IsTagged()) {
1362 LOperand* value = UseRegister(instr->value());
1363 LOperand* temp = TempRegister();
1364
1365 // Make sure that temp and result_temp are different registers.
1366 LUnallocated* result_temp = TempRegister();
1367 LNumberTagD* result = new LNumberTagD(value, temp);
1368 return AssignPointerMap(Define(result, result_temp));
1369 } else {
1370 ASSERT(to.IsInteger32());
1371 bool needs_temp = instr->CanTruncateToInt32() &&
1372 !CpuFeatures::IsSupported(SSE3);
1373 LOperand* value = needs_temp ?
1374 UseTempRegister(instr->value()) : UseRegister(instr->value());
1375 LOperand* temp = needs_temp ? TempRegister() : NULL;
1376 return AssignEnvironment(DefineAsRegister(new LDoubleToI(value, temp)));
1377 }
1378 } else if (from.IsInteger32()) {
1379 if (to.IsTagged()) {
1380 HValue* val = instr->value();
1381 LOperand* value = UseRegister(val);
1382 if (val->HasRange() && val->range()->IsInSmiRange()) {
1383 return DefineSameAsFirst(new LSmiTag(value));
1384 } else {
1385 LNumberTagI* result = new LNumberTagI(value);
1386 return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1387 }
1388 } else {
1389 ASSERT(to.IsDouble());
1390 return DefineAsRegister(new LInteger32ToDouble(Use(instr->value())));
1391 }
1392 }
1393 UNREACHABLE();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001394 return NULL;
1395}
1396
1397
1398LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001399 LOperand* value = UseRegisterAtStart(instr->value());
1400 return AssignEnvironment(new LCheckSmi(value, zero));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001401}
1402
1403
1404LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
1405 Abort("Unimplemented: %s", "DoCheckInstanceType");
1406 return NULL;
1407}
1408
1409
1410LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001411 LOperand* temp = TempRegister();
1412 LCheckPrototypeMaps* result = new LCheckPrototypeMaps(temp);
1413 return AssignEnvironment(result);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001414}
1415
1416
1417LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001418 LOperand* value = UseRegisterAtStart(instr->value());
1419 return AssignEnvironment(new LCheckSmi(value, not_zero));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001420}
1421
1422
1423LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001424 LOperand* value = UseRegisterAtStart(instr->value());
1425 return AssignEnvironment(new LCheckFunction(value));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001426}
1427
1428
1429LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001430 LOperand* value = UseRegisterAtStart(instr->value());
1431 LCheckMap* result = new LCheckMap(value);
1432 return AssignEnvironment(result);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001433}
1434
1435
1436LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
1437 return new LReturn(UseFixed(instr->value(), rax));
1438}
1439
1440
1441LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
1442 Representation r = instr->representation();
1443 if (r.IsInteger32()) {
1444 int32_t value = instr->Integer32Value();
1445 return DefineAsRegister(new LConstantI(value));
1446 } else if (r.IsDouble()) {
1447 double value = instr->DoubleValue();
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001448 LOperand* temp = TempRegister();
1449 return DefineAsRegister(new LConstantD(value, temp));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001450 } else if (r.IsTagged()) {
1451 return DefineAsRegister(new LConstantT(instr->handle()));
1452 } else {
1453 UNREACHABLE();
1454 return NULL;
1455 }
1456}
1457
1458
1459LInstruction* LChunkBuilder::DoLoadGlobal(HLoadGlobal* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001460 LLoadGlobal* result = new LLoadGlobal;
1461 return instr->check_hole_value()
1462 ? AssignEnvironment(DefineAsRegister(result))
1463 : DefineAsRegister(result);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001464}
1465
1466
1467LInstruction* LChunkBuilder::DoStoreGlobal(HStoreGlobal* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001468 return new LStoreGlobal(UseRegisterAtStart(instr->value()));}
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001469
1470
1471LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
1472 Abort("Unimplemented: %s", "DoLoadContextSlot");
1473 return NULL;
1474}
1475
1476
1477LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001478 ASSERT(instr->representation().IsTagged());
1479 LOperand* obj = UseRegisterAtStart(instr->object());
1480 return DefineAsRegister(new LLoadNamedField(obj));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001481}
1482
1483
1484LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
1485 Abort("Unimplemented: %s", "DoLoadNamedGeneric");
1486 return NULL;
1487}
1488
1489
1490LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
1491 HLoadFunctionPrototype* instr) {
1492 Abort("Unimplemented: %s", "DoLoadFunctionPrototype");
1493 return NULL;
1494}
1495
1496
1497LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
1498 Abort("Unimplemented: %s", "DoLoadElements");
1499 return NULL;
1500}
1501
1502
1503LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
1504 HLoadKeyedFastElement* instr) {
1505 Abort("Unimplemented: %s", "DoLoadKeyedFastElement");
1506 return NULL;
1507}
1508
1509
1510LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
1511 Abort("Unimplemented: %s", "DoLoadKeyedGeneric");
1512 return NULL;
1513}
1514
1515
1516LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
1517 HStoreKeyedFastElement* instr) {
1518 Abort("Unimplemented: %s", "DoStoreKeyedFastElement");
1519 return NULL;
1520}
1521
1522
1523LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
1524 Abort("Unimplemented: %s", "DoStoreKeyedGeneric");
1525 return NULL;
1526}
1527
1528
1529LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001530 bool needs_write_barrier = instr->NeedsWriteBarrier();
1531
1532 LOperand* obj = needs_write_barrier
1533 ? UseTempRegister(instr->object())
1534 : UseRegisterAtStart(instr->object());
1535
1536 LOperand* val = needs_write_barrier
1537 ? UseTempRegister(instr->value())
1538 : UseRegister(instr->value());
1539
1540 // We only need a scratch register if we have a write barrier or we
1541 // have a store into the properties array (not in-object-property).
1542 LOperand* temp = (!instr->is_in_object() || needs_write_barrier)
1543 ? TempRegister() : NULL;
1544
1545 return new LStoreNamedField(obj, val, temp);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001546}
1547
1548
1549LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
1550 Abort("Unimplemented: %s", "DoStoreNamedGeneric");
1551 return NULL;
1552}
1553
1554
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001555LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
1556 Abort("Unimplemented: %s", "DoStringCharCodeAt");
1557 return NULL;
1558}
1559
1560
1561LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
1562 Abort("Unimplemented: %s", "DoStringLength");
1563 return NULL;
1564}
1565
1566
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001567LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
1568 Abort("Unimplemented: %s", "DoArrayLiteral");
1569 return NULL;
1570}
1571
1572
1573LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) {
1574 Abort("Unimplemented: %s", "DoObjectLiteral");
1575 return NULL;
1576}
1577
1578
1579LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
1580 Abort("Unimplemented: %s", "DoRegExpLiteral");
1581 return NULL;
1582}
1583
1584
1585LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
1586 Abort("Unimplemented: %s", "DoFunctionLiteral");
1587 return NULL;
1588}
1589
1590
1591LInstruction* LChunkBuilder::DoDeleteProperty(HDeleteProperty* instr) {
1592 Abort("Unimplemented: %s", "DoDeleteProperty");
1593 return NULL;
1594}
1595
1596
1597LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
1598 Abort("Unimplemented: %s", "DoOsrEntry");
1599 return NULL;
1600}
1601
1602
1603LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
1604 int spill_index = chunk()->GetParameterStackSlot(instr->index());
1605 return DefineAsSpilled(new LParameter, spill_index);
1606}
1607
1608
1609LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
1610 Abort("Unimplemented: %s", "DoUnknownOSRValue");
1611 return NULL;
1612}
1613
1614
1615LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
1616 Abort("Unimplemented: %s", "DoCallStub");
1617 return NULL;
1618}
1619
1620
1621LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
1622 Abort("Unimplemented: %s", "DoArgumentsObject");
1623 return NULL;
1624}
1625
1626
1627LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
1628 Abort("Unimplemented: %s", "DoAccessArgumentsAt");
1629 return NULL;
1630}
1631
1632
1633LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
1634 Abort("Unimplemented: %s", "DoTypeof");
1635 return NULL;
1636}
1637
1638
1639LInstruction* LChunkBuilder::DoTypeofIs(HTypeofIs* instr) {
1640 Abort("Unimplemented: %s", "DoTypeofIs");
1641 return NULL;
1642}
1643
1644LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
1645 HEnvironment* env = current_block_->last_environment();
1646 ASSERT(env != NULL);
1647
1648 env->set_ast_id(instr->ast_id());
1649
1650 env->Drop(instr->pop_count());
1651 for (int i = 0; i < instr->values()->length(); ++i) {
1652 HValue* value = instr->values()->at(i);
1653 if (instr->HasAssignedIndexAt(i)) {
1654 env->Bind(instr->GetAssignedIndexAt(i), value);
1655 } else {
1656 env->Push(value);
1657 }
1658 }
1659 ASSERT(env->length() == instr->environment_length());
1660
1661 // If there is an instruction pending deoptimization environment create a
1662 // lazy bailout instruction to capture the environment.
fschneider@chromium.org1df6b472011-01-26 08:23:03 +00001663 if (pending_deoptimization_ast_id_ == instr->ast_id()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001664 LLazyBailout* lazy_bailout = new LLazyBailout;
1665 LInstruction* result = AssignEnvironment(lazy_bailout);
fschneider@chromium.org1df6b472011-01-26 08:23:03 +00001666 instructions_pending_deoptimization_environment_->
1667 set_deoptimization_environment(result->environment());
1668 ClearInstructionPendingDeoptimizationEnvironment();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001669 return result;
1670 }
1671
1672 return NULL;
1673}
1674
1675
1676LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
1677 return MarkAsCall(new LStackCheck, instr);
1678}
1679
1680
1681LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001682 HEnvironment* outer = current_block_->last_environment();
1683 HConstant* undefined = graph()->GetConstantUndefined();
1684 HEnvironment* inner = outer->CopyForInlining(instr->closure(),
1685 instr->function(),
1686 false,
1687 undefined);
1688 current_block_->UpdateEnvironment(inner);
1689 chunk_->AddInlinedClosure(instr->closure());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001690 return NULL;
1691}
1692
1693
1694LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
1695 Abort("Unimplemented: %s", "DoLeaveInlined");
1696 return NULL;
1697}
1698
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001699} } // namespace v8::internal
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001700
1701#endif // V8_TARGET_ARCH_X64