blob: 5b7169b7e9db08b39178c3fac7c10a27698ef419 [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
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000654LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
655 HInstruction* hinstr,
656 CanDeoptimize can_deoptimize) {
657 allocator_->MarkAsCall();
658 instr = AssignPointerMap(instr);
659
660 if (hinstr->HasSideEffects()) {
661 ASSERT(hinstr->next()->IsSimulate());
662 HSimulate* sim = HSimulate::cast(hinstr->next());
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000663 ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
664 pending_deoptimization_ast_id_ = sim->ast_id();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000665 }
666
667 // If instruction does not have side-effects lazy deoptimization
668 // after the call will try to deoptimize to the point before the call.
669 // Thus we still need to attach environment to this call even if
670 // call sequence can not deoptimize eagerly.
671 bool needs_environment =
672 (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) || !hinstr->HasSideEffects();
673 if (needs_environment && !instr->HasEnvironment()) {
674 instr = AssignEnvironment(instr);
675 }
676
677 return instr;
678}
679
680
681LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) {
682 allocator_->MarkAsSaveDoubles();
683 return instr;
684}
685
686
687LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
688 ASSERT(!instr->HasPointerMap());
689 instr->set_pointer_map(new LPointerMap(position_));
690 return instr;
691}
692
693
694LUnallocated* LChunkBuilder::TempRegister() {
695 LUnallocated* operand = new LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
696 allocator_->RecordTemporary(operand);
697 return operand;
698}
699
700
701LOperand* LChunkBuilder::FixedTemp(Register reg) {
702 LUnallocated* operand = ToUnallocated(reg);
703 allocator_->RecordTemporary(operand);
704 return operand;
705}
706
707
708LOperand* LChunkBuilder::FixedTemp(XMMRegister reg) {
709 LUnallocated* operand = ToUnallocated(reg);
710 allocator_->RecordTemporary(operand);
711 return operand;
712}
713
714
715LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
716 return new LLabel(instr->block());
717}
718
719
720LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
721 return AssignEnvironment(new LDeoptimize);
722}
723
724
725LInstruction* LChunkBuilder::DoBit(Token::Value op,
726 HBitwiseBinaryOperation* instr) {
727 Abort("Unimplemented: %s", "DoBit");
728 return NULL;
729}
730
731
732LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
733 HArithmeticBinaryOperation* instr) {
734 Abort("Unimplemented: %s", "DoArithmeticD");
735 return NULL;
736}
737
738
739LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
740 HArithmeticBinaryOperation* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000741 ASSERT(op == Token::ADD ||
742 op == Token::DIV ||
743 op == Token::MOD ||
744 op == Token::MUL ||
745 op == Token::SUB);
746 HValue* left = instr->left();
747 HValue* right = instr->right();
748 ASSERT(left->representation().IsTagged());
749 ASSERT(right->representation().IsTagged());
750 LOperand* left_operand = UseFixed(left, rdx);
751 LOperand* right_operand = UseFixed(right, rax);
752 LArithmeticT* result = new LArithmeticT(op, left_operand, right_operand);
753 return MarkAsCall(DefineFixed(result, rax), instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000754}
755
756
757void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
758 ASSERT(is_building());
759 current_block_ = block;
760 next_block_ = next_block;
761 if (block->IsStartBlock()) {
762 block->UpdateEnvironment(graph_->start_environment());
763 argument_count_ = 0;
764 } else if (block->predecessors()->length() == 1) {
765 // We have a single predecessor => copy environment and outgoing
766 // argument count from the predecessor.
767 ASSERT(block->phis()->length() == 0);
768 HBasicBlock* pred = block->predecessors()->at(0);
769 HEnvironment* last_environment = pred->last_environment();
770 ASSERT(last_environment != NULL);
771 // Only copy the environment, if it is later used again.
772 if (pred->end()->SecondSuccessor() == NULL) {
773 ASSERT(pred->end()->FirstSuccessor() == block);
774 } else {
775 if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
776 pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
777 last_environment = last_environment->Copy();
778 }
779 }
780 block->UpdateEnvironment(last_environment);
781 ASSERT(pred->argument_count() >= 0);
782 argument_count_ = pred->argument_count();
783 } else {
784 // We are at a state join => process phis.
785 HBasicBlock* pred = block->predecessors()->at(0);
786 // No need to copy the environment, it cannot be used later.
787 HEnvironment* last_environment = pred->last_environment();
788 for (int i = 0; i < block->phis()->length(); ++i) {
789 HPhi* phi = block->phis()->at(i);
790 last_environment->SetValueAt(phi->merged_index(), phi);
791 }
792 for (int i = 0; i < block->deleted_phis()->length(); ++i) {
793 last_environment->SetValueAt(block->deleted_phis()->at(i),
794 graph_->GetConstantUndefined());
795 }
796 block->UpdateEnvironment(last_environment);
797 // Pick up the outgoing argument count of one of the predecessors.
798 argument_count_ = pred->argument_count();
799 }
800 HInstruction* current = block->first();
801 int start = chunk_->instructions()->length();
802 while (current != NULL && !is_aborted()) {
803 // Code for constants in registers is generated lazily.
804 if (!current->EmitAtUses()) {
805 VisitInstruction(current);
806 }
807 current = current->next();
808 }
809 int end = chunk_->instructions()->length() - 1;
810 if (end >= start) {
811 block->set_first_instruction_index(start);
812 block->set_last_instruction_index(end);
813 }
814 block->set_argument_count(argument_count_);
815 next_block_ = NULL;
816 current_block_ = NULL;
817}
818
819
820void LChunkBuilder::VisitInstruction(HInstruction* current) {
821 HInstruction* old_current = current_instruction_;
822 current_instruction_ = current;
823 allocator_->BeginInstruction();
824 if (current->has_position()) position_ = current->position();
825 LInstruction* instr = current->CompileToLithium(this);
826
827 if (instr != NULL) {
828 if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
829 instr = AssignPointerMap(instr);
830 }
831 if (FLAG_stress_environments && !instr->HasEnvironment()) {
832 instr = AssignEnvironment(instr);
833 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000834 if (current->IsTest() && !instr->IsGoto()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000835 ASSERT(instr->IsControl());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000836 HTest* test = HTest::cast(current);
837 instr->set_hydrogen_value(test->value());
838 HBasicBlock* first = test->FirstSuccessor();
839 HBasicBlock* second = test->SecondSuccessor();
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000840 ASSERT(first != NULL && second != NULL);
841 instr->SetBranchTargets(first->block_id(), second->block_id());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000842 } else {
843 instr->set_hydrogen_value(current);
844 }
845
846 int index = chunk_->AddInstruction(instr, current_block_);
847 allocator_->SummarizeInstruction(index);
848 } else {
849 // This instruction should be omitted.
850 allocator_->OmitInstruction();
851 }
852 current_instruction_ = old_current;
853}
854
855
856LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) {
857 if (hydrogen_env == NULL) return NULL;
858
859 LEnvironment* outer = CreateEnvironment(hydrogen_env->outer());
860 int ast_id = hydrogen_env->ast_id();
861 ASSERT(ast_id != AstNode::kNoNumber);
862 int value_count = hydrogen_env->length();
863 LEnvironment* result = new LEnvironment(hydrogen_env->closure(),
864 ast_id,
865 hydrogen_env->parameter_count(),
866 argument_count_,
867 value_count,
868 outer);
869 int argument_index = 0;
870 for (int i = 0; i < value_count; ++i) {
871 HValue* value = hydrogen_env->values()->at(i);
872 LOperand* op = NULL;
873 if (value->IsArgumentsObject()) {
874 op = NULL;
875 } else if (value->IsPushArgument()) {
876 op = new LArgument(argument_index++);
877 } else {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000878 op = UseAny(value);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000879 }
880 result->AddValue(op, value->representation());
881 }
882
883 return result;
884}
885
886
887LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
888 LGoto* result = new LGoto(instr->FirstSuccessor()->block_id(),
889 instr->include_stack_check());
890 return (instr->include_stack_check())
891 ? AssignPointerMap(result)
892 : result;
893}
894
895
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000896LInstruction* LChunkBuilder::DoTest(HTest* instr) {
897 HValue* v = instr->value();
898 if (v->EmitAtUses()) {
899 if (v->IsClassOfTest()) {
900 HClassOfTest* compare = HClassOfTest::cast(v);
901 ASSERT(compare->value()->representation().IsTagged());
902
903 return new LClassOfTestAndBranch(UseTempRegister(compare->value()),
904 TempRegister());
905 } else if (v->IsCompare()) {
906 HCompare* compare = HCompare::cast(v);
907 Token::Value op = compare->token();
908 HValue* left = compare->left();
909 HValue* right = compare->right();
910 Representation r = compare->GetInputRepresentation();
911 if (r.IsInteger32()) {
912 ASSERT(left->representation().IsInteger32());
913 ASSERT(right->representation().IsInteger32());
914
915 return new LCmpIDAndBranch(UseRegisterAtStart(left),
916 UseOrConstantAtStart(right));
917 } else if (r.IsDouble()) {
918 ASSERT(left->representation().IsDouble());
919 ASSERT(right->representation().IsDouble());
920
921 return new LCmpIDAndBranch(UseRegisterAtStart(left),
922 UseRegisterAtStart(right));
923 } else {
924 ASSERT(left->representation().IsTagged());
925 ASSERT(right->representation().IsTagged());
926 bool reversed = op == Token::GT || op == Token::LTE;
927 LOperand* left_operand = UseFixed(left, reversed ? rax : rdx);
928 LOperand* right_operand = UseFixed(right, reversed ? rdx : rax);
929 LCmpTAndBranch* result = new LCmpTAndBranch(left_operand,
930 right_operand);
931 return MarkAsCall(result, instr);
932 }
933 } else if (v->IsIsSmi()) {
934 HIsSmi* compare = HIsSmi::cast(v);
935 ASSERT(compare->value()->representation().IsTagged());
936
937 return new LIsSmiAndBranch(Use(compare->value()));
938 } else if (v->IsHasInstanceType()) {
939 HHasInstanceType* compare = HHasInstanceType::cast(v);
940 ASSERT(compare->value()->representation().IsTagged());
941
942 return new LHasInstanceTypeAndBranch(
943 UseRegisterAtStart(compare->value()));
944 } else if (v->IsHasCachedArrayIndex()) {
945 HHasCachedArrayIndex* compare = HHasCachedArrayIndex::cast(v);
946 ASSERT(compare->value()->representation().IsTagged());
947
948 return new LHasCachedArrayIndexAndBranch(
949 UseRegisterAtStart(compare->value()));
950 } else if (v->IsIsNull()) {
951 HIsNull* compare = HIsNull::cast(v);
952 ASSERT(compare->value()->representation().IsTagged());
953
954 // We only need a temp register for non-strict compare.
955 LOperand* temp = compare->is_strict() ? NULL : TempRegister();
956 return new LIsNullAndBranch(UseRegisterAtStart(compare->value()),
957 temp);
958 } else if (v->IsIsObject()) {
959 HIsObject* compare = HIsObject::cast(v);
960 ASSERT(compare->value()->representation().IsTagged());
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000961 return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000962 } else if (v->IsCompareJSObjectEq()) {
963 HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
964 return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()),
965 UseRegisterAtStart(compare->right()));
966 } else if (v->IsInstanceOf()) {
967 HInstanceOf* instance_of = HInstanceOf::cast(v);
968 LInstanceOfAndBranch* result =
969 new LInstanceOfAndBranch(
970 UseFixed(instance_of->left(), InstanceofStub::left()),
971 UseFixed(instance_of->right(), InstanceofStub::right()));
972 return MarkAsCall(result, instr);
973 } else if (v->IsTypeofIs()) {
974 HTypeofIs* typeof_is = HTypeofIs::cast(v);
975 return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
976 } else {
977 if (v->IsConstant()) {
978 if (HConstant::cast(v)->handle()->IsTrue()) {
979 return new LGoto(instr->FirstSuccessor()->block_id());
980 } else if (HConstant::cast(v)->handle()->IsFalse()) {
981 return new LGoto(instr->SecondSuccessor()->block_id());
982 }
983 }
984 Abort("Undefined compare before branch");
985 return NULL;
986 }
987 }
988 return new LBranch(UseRegisterAtStart(v));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000989}
990
991
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000992LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
993 Abort("Unimplemented: %s", "DoCompareMap");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000994 return NULL;
995}
996
997
998LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) {
999 Abort("Unimplemented: %s", "DoArgumentsLength");
1000 return NULL;
1001}
1002
1003
1004LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
1005 Abort("Unimplemented: %s", "DoArgumentsElements");
1006 return NULL;
1007}
1008
1009
1010LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
1011 Abort("Unimplemented: %s", "DoInstanceOf");
1012 return NULL;
1013}
1014
1015
1016LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
1017 HInstanceOfKnownGlobal* instr) {
1018 Abort("Unimplemented: %s", "DoInstanceOfKnownGlobal");
1019 return NULL;
1020}
1021
1022
1023LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
1024 Abort("Unimplemented: %s", "DoApplyArguments");
1025 return NULL;
1026}
1027
1028
1029LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
1030 Abort("Unimplemented: %s", "DoPushArgument");
1031 return NULL;
1032}
1033
1034
1035LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001036 return DefineAsRegister(new LGlobalObject);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001037}
1038
1039
1040LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
1041 Abort("Unimplemented: %s", "DoGlobalReceiver");
1042 return NULL;
1043}
1044
1045
1046LInstruction* LChunkBuilder::DoCallConstantFunction(
1047 HCallConstantFunction* instr) {
1048 Abort("Unimplemented: %s", "DoCallConstantFunction");
1049 return NULL;
1050}
1051
1052
1053LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
1054 Abort("Unimplemented: %s", "DoUnaryMathOperation");
1055 return NULL;
1056}
1057
1058
1059LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
1060 Abort("Unimplemented: %s", "DoCallKeyed");
1061 return NULL;
1062}
1063
1064
1065LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
1066 Abort("Unimplemented: %s", "DoCallNamed");
1067 return NULL;
1068}
1069
1070
1071LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
1072 Abort("Unimplemented: %s", "DoCallGlobal");
1073 return NULL;
1074}
1075
1076
1077LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
1078 Abort("Unimplemented: %s", "DoCallKnownGlobal");
1079 return NULL;
1080}
1081
1082
1083LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
1084 Abort("Unimplemented: %s", "DoCallNew");
1085 return NULL;
1086}
1087
1088
1089LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
1090 Abort("Unimplemented: %s", "DoCallFunction");
1091 return NULL;
1092}
1093
1094
1095LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1096 Abort("Unimplemented: %s", "DoCallRuntime");
1097 return NULL;
1098}
1099
1100
1101LInstruction* LChunkBuilder::DoShr(HShr* instr) {
1102 Abort("Unimplemented: %s", "DoShr");
1103 return NULL;
1104}
1105
1106
1107LInstruction* LChunkBuilder::DoSar(HSar* instr) {
1108 Abort("Unimplemented: %s", "DoSar");
1109 return NULL;
1110}
1111
1112
1113LInstruction* LChunkBuilder::DoShl(HShl* instr) {
1114 Abort("Unimplemented: %s", "DoShl");
1115 return NULL;
1116}
1117
1118
1119LInstruction* LChunkBuilder::DoBitAnd(HBitAnd* instr) {
1120 Abort("Unimplemented: %s", "DoBitAnd");
1121 return NULL;
1122}
1123
1124
1125LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
1126 Abort("Unimplemented: %s", "DoBitNot");
1127 return NULL;
1128}
1129
1130
1131LInstruction* LChunkBuilder::DoBitOr(HBitOr* instr) {
1132 Abort("Unimplemented: %s", "DoBitOr");
1133 return NULL;
1134}
1135
1136
1137LInstruction* LChunkBuilder::DoBitXor(HBitXor* instr) {
1138 Abort("Unimplemented: %s", "DoBitXor");
1139 return NULL;
1140}
1141
1142
1143LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1144 Abort("Unimplemented: %s", "DoDiv");
1145 return NULL;
1146}
1147
1148
1149LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1150 Abort("Unimplemented: %s", "DoMod");
1151 return NULL;
1152}
1153
1154
1155LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1156 Abort("Unimplemented: %s", "DoMul");
1157 return NULL;
1158}
1159
1160
1161LInstruction* LChunkBuilder::DoSub(HSub* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001162 if (instr->representation().IsInteger32()) {
1163 ASSERT(instr->left()->representation().IsInteger32());
1164 ASSERT(instr->right()->representation().IsInteger32());
1165 LOperand* left = UseRegisterAtStart(instr->left());
1166 LOperand* right = UseOrConstantAtStart(instr->right());
1167 LSubI* sub = new LSubI(left, right);
1168 LInstruction* result = DefineSameAsFirst(sub);
1169 if (instr->CheckFlag(HValue::kCanOverflow)) {
1170 result = AssignEnvironment(result);
1171 }
1172 return result;
1173 } else if (instr->representation().IsDouble()) {
1174 return DoArithmeticD(Token::SUB, instr);
1175 } else {
1176 ASSERT(instr->representation().IsTagged());
1177 return DoArithmeticT(Token::SUB, instr);
1178 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001179}
1180
1181
1182LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001183 if (instr->representation().IsInteger32()) {
1184 ASSERT(instr->left()->representation().IsInteger32());
1185 ASSERT(instr->right()->representation().IsInteger32());
1186 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1187 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
1188 LAddI* add = new LAddI(left, right);
1189 LInstruction* result = DefineSameAsFirst(add);
1190 if (instr->CheckFlag(HValue::kCanOverflow)) {
1191 result = AssignEnvironment(result);
1192 }
1193 return result;
1194 } else if (instr->representation().IsDouble()) {
1195 Abort("Unimplemented: %s", "DoAdd on Doubles");
1196 } else {
1197 ASSERT(instr->representation().IsTagged());
1198 return DoArithmeticT(Token::ADD, instr);
1199 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001200 return NULL;
1201}
1202
1203
1204LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1205 Abort("Unimplemented: %s", "DoPower");
1206 return NULL;
1207}
1208
1209
1210LInstruction* LChunkBuilder::DoCompare(HCompare* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001211 Token::Value op = instr->token();
1212 Representation r = instr->GetInputRepresentation();
1213 if (r.IsInteger32()) {
1214 ASSERT(instr->left()->representation().IsInteger32());
1215 ASSERT(instr->right()->representation().IsInteger32());
1216 LOperand* left = UseRegisterAtStart(instr->left());
1217 LOperand* right = UseOrConstantAtStart(instr->right());
1218 return DefineAsRegister(new LCmpID(left, right));
1219 } else if (r.IsDouble()) {
1220 ASSERT(instr->left()->representation().IsDouble());
1221 ASSERT(instr->right()->representation().IsDouble());
1222 LOperand* left = UseRegisterAtStart(instr->left());
1223 LOperand* right = UseRegisterAtStart(instr->right());
1224 return DefineAsRegister(new LCmpID(left, right));
1225 } else {
1226 ASSERT(instr->left()->representation().IsTagged());
1227 ASSERT(instr->right()->representation().IsTagged());
1228 bool reversed = (op == Token::GT || op == Token::LTE);
1229 LOperand* left = UseFixed(instr->left(), reversed ? rax : rdx);
1230 LOperand* right = UseFixed(instr->right(), reversed ? rdx : rax);
1231 LCmpT* result = new LCmpT(left, right);
1232 return MarkAsCall(DefineFixed(result, rax), instr);
1233 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001234}
1235
1236
1237LInstruction* LChunkBuilder::DoCompareJSObjectEq(
1238 HCompareJSObjectEq* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001239 LOperand* left = UseRegisterAtStart(instr->left());
1240 LOperand* right = UseRegisterAtStart(instr->right());
1241 LCmpJSObjectEq* result = new LCmpJSObjectEq(left, right);
1242 return DefineAsRegister(result);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001243}
1244
1245
1246LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001247 ASSERT(instr->value()->representation().IsTagged());
1248 LOperand* value = UseRegisterAtStart(instr->value());
1249
1250 return DefineAsRegister(new LIsNull(value));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001251}
1252
1253
1254LInstruction* LChunkBuilder::DoIsObject(HIsObject* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001255 ASSERT(instr->value()->representation().IsTagged());
1256 LOperand* value = UseRegister(instr->value());
1257
1258 return DefineAsRegister(new LIsObject(value));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001259}
1260
1261
1262LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001263 ASSERT(instr->value()->representation().IsTagged());
1264 LOperand* value = UseAtStart(instr->value());
1265
1266 return DefineAsRegister(new LIsSmi(value));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001267}
1268
1269
1270LInstruction* LChunkBuilder::DoHasInstanceType(HHasInstanceType* instr) {
1271 Abort("Unimplemented: %s", "DoHasInstanceType");
1272 return NULL;
1273}
1274
1275
1276LInstruction* LChunkBuilder::DoHasCachedArrayIndex(
1277 HHasCachedArrayIndex* instr) {
1278 Abort("Unimplemented: %s", "DoHasCachedArrayIndex");
1279 return NULL;
1280}
1281
1282
1283LInstruction* LChunkBuilder::DoClassOfTest(HClassOfTest* instr) {
1284 Abort("Unimplemented: %s", "DoClassOfTest");
1285 return NULL;
1286}
1287
1288
1289LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
1290 Abort("Unimplemented: %s", "DoJSArrayLength");
1291 return NULL;
1292}
1293
1294
1295LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
1296 Abort("Unimplemented: %s", "DoFixedArrayLength");
1297 return NULL;
1298}
1299
1300
1301LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
1302 Abort("Unimplemented: %s", "DoValueOf");
1303 return NULL;
1304}
1305
1306
1307LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1308 Abort("Unimplemented: %s", "DoBoundsCheck");
1309 return NULL;
1310}
1311
1312
1313LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
1314 Abort("Unimplemented: %s", "DoThrow");
1315 return NULL;
1316}
1317
1318
1319LInstruction* LChunkBuilder::DoChange(HChange* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001320 Representation from = instr->from();
1321 Representation to = instr->to();
1322 if (from.IsTagged()) {
1323 if (to.IsDouble()) {
1324 LOperand* value = UseRegister(instr->value());
1325 LNumberUntagD* res = new LNumberUntagD(value);
1326 return AssignEnvironment(DefineAsRegister(res));
1327 } else {
1328 ASSERT(to.IsInteger32());
1329 LOperand* value = UseRegister(instr->value());
1330 bool needs_check = !instr->value()->type().IsSmi();
1331 if (needs_check) {
1332 LOperand* xmm_temp =
1333 (instr->CanTruncateToInt32() && CpuFeatures::IsSupported(SSE3))
1334 ? NULL
1335 : FixedTemp(xmm1);
1336 LTaggedToI* res = new LTaggedToI(value, xmm_temp);
1337 return AssignEnvironment(DefineSameAsFirst(res));
1338 } else {
1339 return DefineSameAsFirst(new LSmiUntag(value, needs_check));
1340 }
1341 }
1342 } else if (from.IsDouble()) {
1343 if (to.IsTagged()) {
1344 LOperand* value = UseRegister(instr->value());
1345 LOperand* temp = TempRegister();
1346
1347 // Make sure that temp and result_temp are different registers.
1348 LUnallocated* result_temp = TempRegister();
1349 LNumberTagD* result = new LNumberTagD(value, temp);
1350 return AssignPointerMap(Define(result, result_temp));
1351 } else {
1352 ASSERT(to.IsInteger32());
1353 bool needs_temp = instr->CanTruncateToInt32() &&
1354 !CpuFeatures::IsSupported(SSE3);
1355 LOperand* value = needs_temp ?
1356 UseTempRegister(instr->value()) : UseRegister(instr->value());
1357 LOperand* temp = needs_temp ? TempRegister() : NULL;
1358 return AssignEnvironment(DefineAsRegister(new LDoubleToI(value, temp)));
1359 }
1360 } else if (from.IsInteger32()) {
1361 if (to.IsTagged()) {
1362 HValue* val = instr->value();
1363 LOperand* value = UseRegister(val);
1364 if (val->HasRange() && val->range()->IsInSmiRange()) {
1365 return DefineSameAsFirst(new LSmiTag(value));
1366 } else {
1367 LNumberTagI* result = new LNumberTagI(value);
1368 return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1369 }
1370 } else {
1371 ASSERT(to.IsDouble());
1372 return DefineAsRegister(new LInteger32ToDouble(Use(instr->value())));
1373 }
1374 }
1375 UNREACHABLE();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001376 return NULL;
1377}
1378
1379
1380LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
1381 Abort("Unimplemented: %s", "DoCheckNonSmi");
1382 return NULL;
1383}
1384
1385
1386LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
1387 Abort("Unimplemented: %s", "DoCheckInstanceType");
1388 return NULL;
1389}
1390
1391
1392LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
1393 Abort("Unimplemented: %s", "DoCheckPrototypeMaps");
1394 return NULL;
1395}
1396
1397
1398LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
1399 Abort("Unimplemented: %s", "DoCheckSmi");
1400 return NULL;
1401}
1402
1403
1404LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
1405 Abort("Unimplemented: %s", "DoCheckFunction");
1406 return NULL;
1407}
1408
1409
1410LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) {
1411 Abort("Unimplemented: %s", "DoCheckMap");
1412 return NULL;
1413}
1414
1415
1416LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
1417 return new LReturn(UseFixed(instr->value(), rax));
1418}
1419
1420
1421LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
1422 Representation r = instr->representation();
1423 if (r.IsInteger32()) {
1424 int32_t value = instr->Integer32Value();
1425 return DefineAsRegister(new LConstantI(value));
1426 } else if (r.IsDouble()) {
1427 double value = instr->DoubleValue();
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001428 LOperand* temp = TempRegister();
1429 return DefineAsRegister(new LConstantD(value, temp));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001430 } else if (r.IsTagged()) {
1431 return DefineAsRegister(new LConstantT(instr->handle()));
1432 } else {
1433 UNREACHABLE();
1434 return NULL;
1435 }
1436}
1437
1438
1439LInstruction* LChunkBuilder::DoLoadGlobal(HLoadGlobal* instr) {
1440 Abort("Unimplemented: %s", "DoLoadGlobal");
1441 return NULL;
1442}
1443
1444
1445LInstruction* LChunkBuilder::DoStoreGlobal(HStoreGlobal* instr) {
1446 Abort("Unimplemented: %s", "DoStoreGlobal");
1447 return NULL;
1448}
1449
1450
1451LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
1452 Abort("Unimplemented: %s", "DoLoadContextSlot");
1453 return NULL;
1454}
1455
1456
1457LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
1458 Abort("Unimplemented: %s", "DoLoadNamedField");
1459 return NULL;
1460}
1461
1462
1463LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
1464 Abort("Unimplemented: %s", "DoLoadNamedGeneric");
1465 return NULL;
1466}
1467
1468
1469LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
1470 HLoadFunctionPrototype* instr) {
1471 Abort("Unimplemented: %s", "DoLoadFunctionPrototype");
1472 return NULL;
1473}
1474
1475
1476LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
1477 Abort("Unimplemented: %s", "DoLoadElements");
1478 return NULL;
1479}
1480
1481
1482LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
1483 HLoadKeyedFastElement* instr) {
1484 Abort("Unimplemented: %s", "DoLoadKeyedFastElement");
1485 return NULL;
1486}
1487
1488
1489LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
1490 Abort("Unimplemented: %s", "DoLoadKeyedGeneric");
1491 return NULL;
1492}
1493
1494
1495LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
1496 HStoreKeyedFastElement* instr) {
1497 Abort("Unimplemented: %s", "DoStoreKeyedFastElement");
1498 return NULL;
1499}
1500
1501
1502LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
1503 Abort("Unimplemented: %s", "DoStoreKeyedGeneric");
1504 return NULL;
1505}
1506
1507
1508LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
1509 Abort("Unimplemented: %s", "DoStoreNamedField");
1510 return NULL;
1511}
1512
1513
1514LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
1515 Abort("Unimplemented: %s", "DoStoreNamedGeneric");
1516 return NULL;
1517}
1518
1519
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001520LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
1521 Abort("Unimplemented: %s", "DoStringCharCodeAt");
1522 return NULL;
1523}
1524
1525
1526LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
1527 Abort("Unimplemented: %s", "DoStringLength");
1528 return NULL;
1529}
1530
1531
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001532LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
1533 Abort("Unimplemented: %s", "DoArrayLiteral");
1534 return NULL;
1535}
1536
1537
1538LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) {
1539 Abort("Unimplemented: %s", "DoObjectLiteral");
1540 return NULL;
1541}
1542
1543
1544LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
1545 Abort("Unimplemented: %s", "DoRegExpLiteral");
1546 return NULL;
1547}
1548
1549
1550LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
1551 Abort("Unimplemented: %s", "DoFunctionLiteral");
1552 return NULL;
1553}
1554
1555
1556LInstruction* LChunkBuilder::DoDeleteProperty(HDeleteProperty* instr) {
1557 Abort("Unimplemented: %s", "DoDeleteProperty");
1558 return NULL;
1559}
1560
1561
1562LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
1563 Abort("Unimplemented: %s", "DoOsrEntry");
1564 return NULL;
1565}
1566
1567
1568LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
1569 int spill_index = chunk()->GetParameterStackSlot(instr->index());
1570 return DefineAsSpilled(new LParameter, spill_index);
1571}
1572
1573
1574LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
1575 Abort("Unimplemented: %s", "DoUnknownOSRValue");
1576 return NULL;
1577}
1578
1579
1580LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
1581 Abort("Unimplemented: %s", "DoCallStub");
1582 return NULL;
1583}
1584
1585
1586LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
1587 Abort("Unimplemented: %s", "DoArgumentsObject");
1588 return NULL;
1589}
1590
1591
1592LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
1593 Abort("Unimplemented: %s", "DoAccessArgumentsAt");
1594 return NULL;
1595}
1596
1597
1598LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
1599 Abort("Unimplemented: %s", "DoTypeof");
1600 return NULL;
1601}
1602
1603
1604LInstruction* LChunkBuilder::DoTypeofIs(HTypeofIs* instr) {
1605 Abort("Unimplemented: %s", "DoTypeofIs");
1606 return NULL;
1607}
1608
1609LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
1610 HEnvironment* env = current_block_->last_environment();
1611 ASSERT(env != NULL);
1612
1613 env->set_ast_id(instr->ast_id());
1614
1615 env->Drop(instr->pop_count());
1616 for (int i = 0; i < instr->values()->length(); ++i) {
1617 HValue* value = instr->values()->at(i);
1618 if (instr->HasAssignedIndexAt(i)) {
1619 env->Bind(instr->GetAssignedIndexAt(i), value);
1620 } else {
1621 env->Push(value);
1622 }
1623 }
1624 ASSERT(env->length() == instr->environment_length());
1625
1626 // If there is an instruction pending deoptimization environment create a
1627 // lazy bailout instruction to capture the environment.
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001628 if (pending_deoptimization_ast_id_ != AstNode::kNoNumber) {
1629 ASSERT(pending_deoptimization_ast_id_ == instr->ast_id());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001630 LLazyBailout* lazy_bailout = new LLazyBailout;
1631 LInstruction* result = AssignEnvironment(lazy_bailout);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001632 pending_deoptimization_ast_id_ = AstNode::kNoNumber;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001633 return result;
1634 }
1635
1636 return NULL;
1637}
1638
1639
1640LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
1641 return MarkAsCall(new LStackCheck, instr);
1642}
1643
1644
1645LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
1646 Abort("Unimplemented: %s", "DoEnterInlined");
1647 return NULL;
1648}
1649
1650
1651LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
1652 Abort("Unimplemented: %s", "DoLeaveInlined");
1653 return NULL;
1654}
1655
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001656} } // namespace v8::internal
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001657
1658#endif // V8_TARGET_ARCH_X64