blob: b51633e706a152f27462e09ea128f839e3edb961 [file] [log] [blame]
Ben Murdoch086aeea2011-05-13 15:57:08 +01001// Copyright 2011 the V8 project authors. All rights reserved.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "arm/lithium-arm.h"
29#include "arm/lithium-codegen-arm.h"
30
31namespace v8 {
32namespace internal {
33
34#define DEFINE_COMPILE(type) \
35 void L##type::CompileToNative(LCodeGen* generator) { \
36 generator->Do##type(this); \
37 }
38LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
39#undef DEFINE_COMPILE
40
41LOsrEntry::LOsrEntry() {
42 for (int i = 0; i < Register::kNumAllocatableRegisters; ++i) {
43 register_spills_[i] = NULL;
44 }
45 for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; ++i) {
46 double_register_spills_[i] = NULL;
47 }
48}
49
50
51void LOsrEntry::MarkSpilledRegister(int allocation_index,
52 LOperand* spill_operand) {
53 ASSERT(spill_operand->IsStackSlot());
54 ASSERT(register_spills_[allocation_index] == NULL);
55 register_spills_[allocation_index] = spill_operand;
56}
57
58
59void LOsrEntry::MarkSpilledDoubleRegister(int allocation_index,
60 LOperand* spill_operand) {
61 ASSERT(spill_operand->IsDoubleStackSlot());
62 ASSERT(double_register_spills_[allocation_index] == NULL);
63 double_register_spills_[allocation_index] = spill_operand;
64}
65
66
67void LInstruction::PrintTo(StringStream* stream) const {
68 stream->Add("%s ", this->Mnemonic());
69 if (HasResult()) {
70 result()->PrintTo(stream);
71 stream->Add(" ");
72 }
73 PrintDataTo(stream);
74
75 if (HasEnvironment()) {
76 stream->Add(" ");
77 environment()->PrintTo(stream);
78 }
79
80 if (HasPointerMap()) {
81 stream->Add(" ");
82 pointer_map()->PrintTo(stream);
83 }
84}
85
86
87void LLabel::PrintDataTo(StringStream* stream) const {
88 LGap::PrintDataTo(stream);
89 LLabel* rep = replacement();
90 if (rep != NULL) {
91 stream->Add(" Dead block replaced with B%d", rep->block_id());
92 }
93}
94
95
Ben Murdochb0fe1622011-05-05 13:52:32 +010096bool LGap::IsRedundant() const {
97 for (int i = 0; i < 4; i++) {
98 if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) {
99 return false;
100 }
101 }
102
103 return true;
104}
105
106
107void LGap::PrintDataTo(StringStream* stream) const {
108 for (int i = 0; i < 4; i++) {
109 stream->Add("(");
110 if (parallel_moves_[i] != NULL) {
111 parallel_moves_[i]->PrintDataTo(stream);
112 }
113 stream->Add(") ");
114 }
115}
116
117
118const char* LArithmeticD::Mnemonic() const {
119 switch (op()) {
120 case Token::ADD: return "add-d";
121 case Token::SUB: return "sub-d";
122 case Token::MUL: return "mul-d";
123 case Token::DIV: return "div-d";
124 case Token::MOD: return "mod-d";
125 default:
126 UNREACHABLE();
127 return NULL;
128 }
129}
130
131
132const char* LArithmeticT::Mnemonic() const {
133 switch (op()) {
134 case Token::ADD: return "add-t";
135 case Token::SUB: return "sub-t";
136 case Token::MUL: return "mul-t";
137 case Token::MOD: return "mod-t";
138 case Token::DIV: return "div-t";
139 default:
140 UNREACHABLE();
141 return NULL;
142 }
143}
144
145
146
147void LBinaryOperation::PrintDataTo(StringStream* stream) const {
148 stream->Add("= ");
149 left()->PrintTo(stream);
150 stream->Add(" ");
151 right()->PrintTo(stream);
152}
153
154
155void LGoto::PrintDataTo(StringStream* stream) const {
156 stream->Add("B%d", block_id());
157}
158
159
160void LBranch::PrintDataTo(StringStream* stream) const {
161 stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
162 input()->PrintTo(stream);
163}
164
165
166void LCmpIDAndBranch::PrintDataTo(StringStream* stream) const {
167 stream->Add("if ");
168 left()->PrintTo(stream);
169 stream->Add(" %s ", Token::String(op()));
170 right()->PrintTo(stream);
171 stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
172}
173
174
175void LIsNullAndBranch::PrintDataTo(StringStream* stream) const {
176 stream->Add("if ");
177 input()->PrintTo(stream);
178 stream->Add(is_strict() ? " === null" : " == null");
179 stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
180}
181
182
183void LIsObjectAndBranch::PrintDataTo(StringStream* stream) const {
184 stream->Add("if is_object(");
185 input()->PrintTo(stream);
186 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
187}
188
189
190void LIsSmiAndBranch::PrintDataTo(StringStream* stream) const {
191 stream->Add("if is_smi(");
192 input()->PrintTo(stream);
193 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
194}
195
196
197void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) const {
198 stream->Add("if has_instance_type(");
199 input()->PrintTo(stream);
200 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
201}
202
203
204void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) const {
205 stream->Add("if has_cached_array_index(");
206 input()->PrintTo(stream);
207 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
208}
209
210
211void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) const {
212 stream->Add("if class_of_test(");
213 input()->PrintTo(stream);
214 stream->Add(", \"%o\") then B%d else B%d",
215 *hydrogen()->class_name(),
216 true_block_id(),
217 false_block_id());
218}
219
220
221void LTypeofIs::PrintDataTo(StringStream* stream) const {
222 input()->PrintTo(stream);
223 stream->Add(" == \"%s\"", *hydrogen()->type_literal()->ToCString());
224}
225
226
227void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) const {
228 stream->Add("if typeof ");
229 input()->PrintTo(stream);
230 stream->Add(" == \"%s\" then B%d else B%d",
231 *hydrogen()->type_literal()->ToCString(),
232 true_block_id(), false_block_id());
233}
234
235
236void LCallConstantFunction::PrintDataTo(StringStream* stream) const {
237 stream->Add("#%d / ", arity());
238}
239
240
241void LUnaryMathOperation::PrintDataTo(StringStream* stream) const {
242 stream->Add("/%s ", hydrogen()->OpName());
243 input()->PrintTo(stream);
244}
245
246
Ben Murdochb8e0da22011-05-16 14:20:40 +0100247void LLoadContextSlot::PrintDataTo(StringStream* stream) {
248 stream->Add("(%d, %d)", context_chain_length(), slot_index());
249}
250
251
Ben Murdochb0fe1622011-05-05 13:52:32 +0100252void LCallKeyed::PrintDataTo(StringStream* stream) const {
253 stream->Add("[r2] #%d / ", arity());
254}
255
256
257void LCallNamed::PrintDataTo(StringStream* stream) const {
258 SmartPointer<char> name_string = name()->ToCString();
259 stream->Add("%s #%d / ", *name_string, arity());
260}
261
262
263void LCallGlobal::PrintDataTo(StringStream* stream) const {
264 SmartPointer<char> name_string = name()->ToCString();
265 stream->Add("%s #%d / ", *name_string, arity());
266}
267
268
269void LCallKnownGlobal::PrintDataTo(StringStream* stream) const {
270 stream->Add("#%d / ", arity());
271}
272
273
274void LCallNew::PrintDataTo(StringStream* stream) const {
275 LUnaryOperation::PrintDataTo(stream);
276 stream->Add(" #%d / ", arity());
277}
278
279
280void LClassOfTest::PrintDataTo(StringStream* stream) const {
281 stream->Add("= class_of_test(");
282 input()->PrintTo(stream);
283 stream->Add(", \"%o\")", *hydrogen()->class_name());
284}
285
286
287void LUnaryOperation::PrintDataTo(StringStream* stream) const {
288 stream->Add("= ");
289 input()->PrintTo(stream);
290}
291
292
293void LAccessArgumentsAt::PrintDataTo(StringStream* stream) const {
294 arguments()->PrintTo(stream);
295
296 stream->Add(" length ");
297 length()->PrintTo(stream);
298
299 stream->Add(" index ");
300 index()->PrintTo(stream);
301}
302
303
304LChunk::LChunk(HGraph* graph)
305 : spill_slot_count_(0),
306 graph_(graph),
307 instructions_(32),
308 pointer_maps_(8),
309 inlined_closures_(1) {
310}
311
312
313void LChunk::Verify() const {
314 // TODO(twuerthinger): Implement verification for chunk.
315}
316
317
318int LChunk::GetNextSpillIndex(bool is_double) {
319 // Skip a slot if for a double-width slot.
320 if (is_double) spill_slot_count_++;
321 return spill_slot_count_++;
322}
323
324
325LOperand* LChunk::GetNextSpillSlot(bool is_double) {
326 int index = GetNextSpillIndex(is_double);
327 if (is_double) {
328 return LDoubleStackSlot::Create(index);
329 } else {
330 return LStackSlot::Create(index);
331 }
332}
333
334
335void LChunk::MarkEmptyBlocks() {
336 HPhase phase("Mark empty blocks", this);
337 for (int i = 0; i < graph()->blocks()->length(); ++i) {
338 HBasicBlock* block = graph()->blocks()->at(i);
339 int first = block->first_instruction_index();
340 int last = block->last_instruction_index();
341 LInstruction* first_instr = instructions()->at(first);
342 LInstruction* last_instr = instructions()->at(last);
343
344 LLabel* label = LLabel::cast(first_instr);
345 if (last_instr->IsGoto()) {
346 LGoto* goto_instr = LGoto::cast(last_instr);
347 if (!goto_instr->include_stack_check() &&
348 label->IsRedundant() &&
349 !label->is_loop_header()) {
350 bool can_eliminate = true;
351 for (int i = first + 1; i < last && can_eliminate; ++i) {
352 LInstruction* cur = instructions()->at(i);
353 if (cur->IsGap()) {
354 LGap* gap = LGap::cast(cur);
355 if (!gap->IsRedundant()) {
356 can_eliminate = false;
357 }
358 } else {
359 can_eliminate = false;
360 }
361 }
362
363 if (can_eliminate) {
364 label->set_replacement(GetLabel(goto_instr->block_id()));
365 }
366 }
367 }
368 }
369}
370
371
372void LStoreNamed::PrintDataTo(StringStream* stream) const {
373 object()->PrintTo(stream);
374 stream->Add(".");
375 stream->Add(*String::cast(*name())->ToCString());
376 stream->Add(" <- ");
377 value()->PrintTo(stream);
378}
379
380
381void LStoreKeyed::PrintDataTo(StringStream* stream) const {
382 object()->PrintTo(stream);
383 stream->Add("[");
384 key()->PrintTo(stream);
385 stream->Add("] <- ");
386 value()->PrintTo(stream);
387}
388
389
390int LChunk::AddInstruction(LInstruction* instr, HBasicBlock* block) {
391 LGap* gap = new LGap(block);
392 int index = -1;
393 if (instr->IsControl()) {
394 instructions_.Add(gap);
395 index = instructions_.length();
396 instructions_.Add(instr);
397 } else {
398 index = instructions_.length();
399 instructions_.Add(instr);
400 instructions_.Add(gap);
401 }
402 if (instr->HasPointerMap()) {
403 pointer_maps_.Add(instr->pointer_map());
404 instr->pointer_map()->set_lithium_position(index);
405 }
406 return index;
407}
408
409
410LConstantOperand* LChunk::DefineConstantOperand(HConstant* constant) {
411 return LConstantOperand::Create(constant->id());
412}
413
414
415int LChunk::GetParameterStackSlot(int index) const {
416 // The receiver is at index 0, the first parameter at index 1, so we
417 // shift all parameter indexes down by the number of parameters, and
418 // make sure they end up negative so they are distinguishable from
419 // spill slots.
420 int result = index - graph()->info()->scope()->num_parameters() - 1;
421 ASSERT(result < 0);
422 return result;
423}
424
425// A parameter relative to ebp in the arguments stub.
426int LChunk::ParameterAt(int index) {
427 ASSERT(-1 <= index); // -1 is the receiver.
428 return (1 + graph()->info()->scope()->num_parameters() - index) *
429 kPointerSize;
430}
431
432
433LGap* LChunk::GetGapAt(int index) const {
434 return LGap::cast(instructions_[index]);
435}
436
437
438bool LChunk::IsGapAt(int index) const {
439 return instructions_[index]->IsGap();
440}
441
442
443int LChunk::NearestGapPos(int index) const {
444 while (!IsGapAt(index)) index--;
445 return index;
446}
447
448
449void LChunk::AddGapMove(int index, LOperand* from, LOperand* to) {
450 GetGapAt(index)->GetOrCreateParallelMove(LGap::START)->AddMove(from, to);
451}
452
453
Ben Murdochb0fe1622011-05-05 13:52:32 +0100454Handle<Object> LChunk::LookupLiteral(LConstantOperand* operand) const {
455 return HConstant::cast(graph_->LookupValue(operand->index()))->handle();
456}
457
458
459Representation LChunk::LookupLiteralRepresentation(
460 LConstantOperand* operand) const {
461 return graph_->LookupValue(operand->index())->representation();
462}
463
464
465LChunk* LChunkBuilder::Build() {
466 ASSERT(is_unused());
467 chunk_ = new LChunk(graph());
468 HPhase phase("Building chunk", chunk_);
469 status_ = BUILDING;
470 const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
471 for (int i = 0; i < blocks->length(); i++) {
472 HBasicBlock* next = NULL;
473 if (i < blocks->length() - 1) next = blocks->at(i + 1);
474 DoBasicBlock(blocks->at(i), next);
475 if (is_aborted()) return NULL;
476 }
477 status_ = DONE;
478 return chunk_;
479}
480
481
482void LChunkBuilder::Abort(const char* format, ...) {
483 if (FLAG_trace_bailout) {
484 SmartPointer<char> debug_name = graph()->debug_name()->ToCString();
485 PrintF("Aborting LChunk building in @\"%s\": ", *debug_name);
486 va_list arguments;
487 va_start(arguments, format);
488 OS::VPrint(format, arguments);
489 va_end(arguments);
490 PrintF("\n");
491 }
492 status_ = ABORTED;
493}
494
495
496LRegister* LChunkBuilder::ToOperand(Register reg) {
497 return LRegister::Create(Register::ToAllocationIndex(reg));
498}
499
500
501LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
502 return new LUnallocated(LUnallocated::FIXED_REGISTER,
503 Register::ToAllocationIndex(reg));
504}
505
506
507LUnallocated* LChunkBuilder::ToUnallocated(DoubleRegister reg) {
508 return new LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
509 DoubleRegister::ToAllocationIndex(reg));
510}
511
512
513LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
514 return Use(value, ToUnallocated(fixed_register));
515}
516
517
518LOperand* LChunkBuilder::UseFixedDouble(HValue* value, DoubleRegister reg) {
519 return Use(value, ToUnallocated(reg));
520}
521
522
523LOperand* LChunkBuilder::UseRegister(HValue* value) {
524 return Use(value, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
525}
526
527
528LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
529 return Use(value,
530 new LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
531 LUnallocated::USED_AT_START));
532}
533
534
535LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
536 return Use(value, new LUnallocated(LUnallocated::WRITABLE_REGISTER));
537}
538
539
540LOperand* LChunkBuilder::Use(HValue* value) {
541 return Use(value, new LUnallocated(LUnallocated::NONE));
542}
543
544
545LOperand* LChunkBuilder::UseAtStart(HValue* value) {
546 return Use(value, new LUnallocated(LUnallocated::NONE,
547 LUnallocated::USED_AT_START));
548}
549
550
551LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
552 return value->IsConstant()
553 ? chunk_->DefineConstantOperand(HConstant::cast(value))
554 : Use(value);
555}
556
557
558LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
559 return value->IsConstant()
560 ? chunk_->DefineConstantOperand(HConstant::cast(value))
561 : UseAtStart(value);
562}
563
564
565LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
566 return value->IsConstant()
567 ? chunk_->DefineConstantOperand(HConstant::cast(value))
568 : UseRegister(value);
569}
570
571
572LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
573 return value->IsConstant()
574 ? chunk_->DefineConstantOperand(HConstant::cast(value))
575 : UseRegisterAtStart(value);
576}
577
578
Ben Murdochb8e0da22011-05-16 14:20:40 +0100579LOperand* LChunkBuilder::UseAny(HValue* value) {
580 return value->IsConstant()
581 ? chunk_->DefineConstantOperand(HConstant::cast(value))
582 : Use(value, new LUnallocated(LUnallocated::ANY));
583}
584
585
Ben Murdochb0fe1622011-05-05 13:52:32 +0100586LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
587 if (value->EmitAtUses()) {
588 HInstruction* instr = HInstruction::cast(value);
589 VisitInstruction(instr);
590 }
591 allocator_->RecordUse(value, operand);
592 return operand;
593}
594
595
596LInstruction* LChunkBuilder::Define(LInstruction* instr) {
597 return Define(instr, new LUnallocated(LUnallocated::NONE));
598}
599
600
601LInstruction* LChunkBuilder::DefineAsRegister(LInstruction* instr) {
602 return Define(instr, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
603}
604
605
606LInstruction* LChunkBuilder::DefineAsSpilled(LInstruction* instr, int index) {
607 return Define(instr, new LUnallocated(LUnallocated::FIXED_SLOT, index));
608}
609
610
Ben Murdochb0fe1622011-05-05 13:52:32 +0100611LInstruction* LChunkBuilder::DefineSameAsFirst(LInstruction* instr) {
612 return Define(instr, new LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
613}
614
615
616LInstruction* LChunkBuilder::DefineFixed(LInstruction* instr, Register reg) {
617 return Define(instr, ToUnallocated(reg));
618}
619
620
621LInstruction* LChunkBuilder::DefineFixedDouble(LInstruction* instr,
622 DoubleRegister reg) {
623 return Define(instr, ToUnallocated(reg));
624}
625
626
627LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
628 HEnvironment* hydrogen_env = current_block_->last_environment();
629 instr->set_environment(CreateEnvironment(hydrogen_env));
630 return instr;
631}
632
633
634LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
635 LInstruction* instr, int ast_id) {
636 ASSERT(instructions_pending_deoptimization_environment_ == NULL);
637 ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
638 instructions_pending_deoptimization_environment_ = instr;
639 pending_deoptimization_ast_id_ = ast_id;
640 return instr;
641}
642
643
644void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
645 instructions_pending_deoptimization_environment_ = NULL;
646 pending_deoptimization_ast_id_ = AstNode::kNoNumber;
647}
648
649
650LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
651 HInstruction* hinstr,
652 CanDeoptimize can_deoptimize) {
653 allocator_->MarkAsCall();
654 instr = AssignPointerMap(instr);
655
656 if (hinstr->HasSideEffects()) {
657 ASSERT(hinstr->next()->IsSimulate());
658 HSimulate* sim = HSimulate::cast(hinstr->next());
659 instr = SetInstructionPendingDeoptimizationEnvironment(
660 instr, sim->ast_id());
661 }
662
663 // If instruction does not have side-effects lazy deoptimization
664 // after the call will try to deoptimize to the point before the call.
665 // Thus we still need to attach environment to this call even if
666 // call sequence can not deoptimize eagerly.
667 bool needs_environment =
668 (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) || !hinstr->HasSideEffects();
669 if (needs_environment && !instr->HasEnvironment()) {
670 instr = AssignEnvironment(instr);
671 }
672
673 return instr;
674}
675
676
677LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
678 ASSERT(!instr->HasPointerMap());
679 instr->set_pointer_map(new LPointerMap(position_));
680 return instr;
681}
682
683
684LInstruction* LChunkBuilder::Define(LInstruction* instr, LUnallocated* result) {
685 allocator_->RecordDefinition(current_instruction_, result);
686 instr->set_result(result);
687 return instr;
688}
689
690
Ben Murdochb0fe1622011-05-05 13:52:32 +0100691LUnallocated* LChunkBuilder::TempRegister() {
692 LUnallocated* operand = new LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
693 allocator_->RecordTemporary(operand);
694 return operand;
695}
696
697
698LOperand* LChunkBuilder::FixedTemp(Register reg) {
699 LUnallocated* operand = ToUnallocated(reg);
700 allocator_->RecordTemporary(operand);
701 return operand;
702}
703
704
705LOperand* LChunkBuilder::FixedTemp(DoubleRegister reg) {
706 LUnallocated* operand = ToUnallocated(reg);
707 allocator_->RecordTemporary(operand);
708 return operand;
709}
710
711
712LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
713 return new LLabel(instr->block());
714}
715
716
717LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
718 return AssignEnvironment(new LDeoptimize);
719}
720
721
722LInstruction* LChunkBuilder::DoBit(Token::Value op,
723 HBitwiseBinaryOperation* instr) {
724 ASSERT(instr->representation().IsInteger32());
725 ASSERT(instr->left()->representation().IsInteger32());
726 ASSERT(instr->right()->representation().IsInteger32());
727
728 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
729 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
730 return DefineSameAsFirst(new LBitI(op, left, right));
731}
732
733
734LInstruction* LChunkBuilder::DoShift(Token::Value op,
735 HBitwiseBinaryOperation* instr) {
736 ASSERT(instr->representation().IsInteger32());
737 ASSERT(instr->OperandAt(0)->representation().IsInteger32());
738 ASSERT(instr->OperandAt(1)->representation().IsInteger32());
739 LOperand* left = UseRegisterAtStart(instr->OperandAt(0));
740
741 HValue* right_value = instr->OperandAt(1);
742 LOperand* right = NULL;
743 int constant_value = 0;
744 if (right_value->IsConstant()) {
745 HConstant* constant = HConstant::cast(right_value);
746 right = chunk_->DefineConstantOperand(constant);
747 constant_value = constant->Integer32Value() & 0x1f;
748 } else {
749 right = UseRegister(right_value);
750 }
751
752 // Shift operations can only deoptimize if we do a logical shift
753 // by 0 and the result cannot be truncated to int32.
754 bool can_deopt = (op == Token::SHR && constant_value == 0);
755 if (can_deopt) {
756 bool can_truncate = true;
757 for (int i = 0; i < instr->uses()->length(); i++) {
758 if (!instr->uses()->at(i)->CheckFlag(HValue::kTruncatingToInt32)) {
759 can_truncate = false;
760 break;
761 }
762 }
763 can_deopt = !can_truncate;
764 }
765
766 LInstruction* result =
767 DefineSameAsFirst(new LShiftI(op, left, right, can_deopt));
768 if (can_deopt) AssignEnvironment(result);
769 return result;
770}
771
772
773LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
774 HArithmeticBinaryOperation* instr) {
775 ASSERT(instr->representation().IsDouble());
776 ASSERT(instr->left()->representation().IsDouble());
777 ASSERT(instr->right()->representation().IsDouble());
778 LOperand* left = UseRegisterAtStart(instr->left());
779 LOperand* right = UseRegisterAtStart(instr->right());
780 LArithmeticD* result = new LArithmeticD(op, left, right);
781 return DefineSameAsFirst(result);
782}
783
784
785LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
786 HArithmeticBinaryOperation* instr) {
787 ASSERT(op == Token::ADD ||
788 op == Token::DIV ||
789 op == Token::MOD ||
790 op == Token::MUL ||
791 op == Token::SUB);
792 HValue* left = instr->left();
793 HValue* right = instr->right();
794 ASSERT(left->representation().IsTagged());
795 ASSERT(right->representation().IsTagged());
796 LOperand* left_operand = UseFixed(left, r1);
797 LOperand* right_operand = UseFixed(right, r0);
798 LInstruction* result = new LArithmeticT(op, left_operand, right_operand);
799 return MarkAsCall(DefineFixed(result, r0), instr);
800}
801
802void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
803 ASSERT(is_building());
804 current_block_ = block;
805 next_block_ = next_block;
806 if (block->IsStartBlock()) {
807 block->UpdateEnvironment(graph_->start_environment());
808 argument_count_ = 0;
809 } else if (block->predecessors()->length() == 1) {
810 // We have a single predecessor => copy environment and outgoing
811 // argument count from the predecessor.
812 ASSERT(block->phis()->length() == 0);
813 HBasicBlock* pred = block->predecessors()->at(0);
814 HEnvironment* last_environment = pred->last_environment();
815 ASSERT(last_environment != NULL);
816 // Only copy the environment, if it is later used again.
817 if (pred->end()->SecondSuccessor() == NULL) {
818 ASSERT(pred->end()->FirstSuccessor() == block);
819 } else {
820 if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
821 pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
822 last_environment = last_environment->Copy();
823 }
824 }
825 block->UpdateEnvironment(last_environment);
826 ASSERT(pred->argument_count() >= 0);
827 argument_count_ = pred->argument_count();
828 } else {
829 // We are at a state join => process phis.
830 HBasicBlock* pred = block->predecessors()->at(0);
831 // No need to copy the environment, it cannot be used later.
832 HEnvironment* last_environment = pred->last_environment();
833 for (int i = 0; i < block->phis()->length(); ++i) {
834 HPhi* phi = block->phis()->at(i);
835 last_environment->SetValueAt(phi->merged_index(), phi);
836 }
837 for (int i = 0; i < block->deleted_phis()->length(); ++i) {
838 last_environment->SetValueAt(block->deleted_phis()->at(i),
839 graph_->GetConstantUndefined());
840 }
841 block->UpdateEnvironment(last_environment);
842 // Pick up the outgoing argument count of one of the predecessors.
843 argument_count_ = pred->argument_count();
844 }
845 HInstruction* current = block->first();
846 int start = chunk_->instructions()->length();
847 while (current != NULL && !is_aborted()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100848 // Code for constants in registers is generated lazily.
849 if (!current->EmitAtUses()) {
850 VisitInstruction(current);
851 }
852 current = current->next();
853 }
854 int end = chunk_->instructions()->length() - 1;
855 if (end >= start) {
856 block->set_first_instruction_index(start);
857 block->set_last_instruction_index(end);
858 }
859 block->set_argument_count(argument_count_);
860 next_block_ = NULL;
861 current_block_ = NULL;
862}
863
864
865void LChunkBuilder::VisitInstruction(HInstruction* current) {
866 HInstruction* old_current = current_instruction_;
867 current_instruction_ = current;
868 allocator_->BeginInstruction();
869 if (current->has_position()) position_ = current->position();
870 LInstruction* instr = current->CompileToLithium(this);
871
872 if (instr != NULL) {
873 if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
874 instr = AssignPointerMap(instr);
875 }
876 if (FLAG_stress_environments && !instr->HasEnvironment()) {
877 instr = AssignEnvironment(instr);
878 }
879 if (current->IsBranch()) {
880 instr->set_hydrogen_value(HBranch::cast(current)->value());
881 } else {
882 instr->set_hydrogen_value(current);
883 }
884
885 int index = chunk_->AddInstruction(instr, current_block_);
886 allocator_->SummarizeInstruction(index);
887 } else {
888 // This instruction should be omitted.
889 allocator_->OmitInstruction();
890 }
891 current_instruction_ = old_current;
892}
893
894
Ben Murdochb0fe1622011-05-05 13:52:32 +0100895LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) {
896 if (hydrogen_env == NULL) return NULL;
897
898 LEnvironment* outer = CreateEnvironment(hydrogen_env->outer());
899 int ast_id = hydrogen_env->ast_id();
900 ASSERT(ast_id != AstNode::kNoNumber);
Steve Block9fac8402011-05-12 15:51:54 +0100901 int value_count = hydrogen_env->length();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100902 LEnvironment* result = new LEnvironment(hydrogen_env->closure(),
903 ast_id,
904 hydrogen_env->parameter_count(),
905 argument_count_,
906 value_count,
907 outer);
908 int argument_index = 0;
909 for (int i = 0; i < value_count; ++i) {
910 HValue* value = hydrogen_env->values()->at(i);
911 LOperand* op = NULL;
912 if (value->IsArgumentsObject()) {
913 op = NULL;
914 } else if (value->IsPushArgument()) {
915 op = new LArgument(argument_index++);
916 } else {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100917 op = UseAny(value);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100918 }
919 result->AddValue(op, value->representation());
920 }
921
922 return result;
923}
924
925
926LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
927 LInstruction* result = new LGoto(instr->FirstSuccessor()->block_id(),
928 instr->include_stack_check());
929 if (instr->include_stack_check()) result = AssignPointerMap(result);
930 return result;
931}
932
933
934LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
935 HValue* v = instr->value();
936 HBasicBlock* first = instr->FirstSuccessor();
937 HBasicBlock* second = instr->SecondSuccessor();
938 ASSERT(first != NULL && second != NULL);
939 int first_id = first->block_id();
940 int second_id = second->block_id();
941
942 if (v->EmitAtUses()) {
943 if (v->IsClassOfTest()) {
944 HClassOfTest* compare = HClassOfTest::cast(v);
945 ASSERT(compare->value()->representation().IsTagged());
946
947 return new LClassOfTestAndBranch(UseTempRegister(compare->value()),
948 TempRegister(),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100949 first_id,
950 second_id);
951 } else if (v->IsCompare()) {
952 HCompare* compare = HCompare::cast(v);
953 Token::Value op = compare->token();
954 HValue* left = compare->left();
955 HValue* right = compare->right();
Ben Murdochb8e0da22011-05-16 14:20:40 +0100956 Representation r = compare->GetInputRepresentation();
957 if (r.IsInteger32()) {
958 ASSERT(left->representation().IsInteger32());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100959 ASSERT(right->representation().IsInteger32());
Ben Murdochb8e0da22011-05-16 14:20:40 +0100960 return new LCmpIDAndBranch(UseRegisterAtStart(left),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100961 UseOrConstantAtStart(right),
962 first_id,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100963 second_id);
964 } else if (r.IsDouble()) {
965 ASSERT(left->representation().IsDouble());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100966 ASSERT(right->representation().IsDouble());
Ben Murdochb8e0da22011-05-16 14:20:40 +0100967 return new LCmpIDAndBranch(UseRegisterAtStart(left),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100968 UseRegisterAtStart(right),
969 first_id,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100970 second_id);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100971 } else {
972 ASSERT(left->representation().IsTagged());
973 ASSERT(right->representation().IsTagged());
974 bool reversed = op == Token::GT || op == Token::LTE;
975 LOperand* left_operand = UseFixed(left, reversed ? r0 : r1);
976 LOperand* right_operand = UseFixed(right, reversed ? r1 : r0);
977 LInstruction* result = new LCmpTAndBranch(left_operand,
978 right_operand,
979 first_id,
980 second_id);
981 return MarkAsCall(result, instr);
982 }
983 } else if (v->IsIsSmi()) {
984 HIsSmi* compare = HIsSmi::cast(v);
985 ASSERT(compare->value()->representation().IsTagged());
986
987 return new LIsSmiAndBranch(Use(compare->value()),
988 first_id,
989 second_id);
990 } else if (v->IsHasInstanceType()) {
991 HHasInstanceType* compare = HHasInstanceType::cast(v);
992 ASSERT(compare->value()->representation().IsTagged());
993
994 return new LHasInstanceTypeAndBranch(UseRegisterAtStart(compare->value()),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100995 first_id,
996 second_id);
997 } else if (v->IsHasCachedArrayIndex()) {
998 HHasCachedArrayIndex* compare = HHasCachedArrayIndex::cast(v);
999 ASSERT(compare->value()->representation().IsTagged());
1000
1001 return new LHasCachedArrayIndexAndBranch(
1002 UseRegisterAtStart(compare->value()), first_id, second_id);
1003 } else if (v->IsIsNull()) {
1004 HIsNull* compare = HIsNull::cast(v);
1005 ASSERT(compare->value()->representation().IsTagged());
1006
Ben Murdochb0fe1622011-05-05 13:52:32 +01001007 return new LIsNullAndBranch(UseRegisterAtStart(compare->value()),
Ben Murdochb0fe1622011-05-05 13:52:32 +01001008 first_id,
1009 second_id);
1010 } else if (v->IsIsObject()) {
1011 HIsObject* compare = HIsObject::cast(v);
1012 ASSERT(compare->value()->representation().IsTagged());
1013
1014 LOperand* temp1 = TempRegister();
1015 LOperand* temp2 = TempRegister();
1016 return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()),
1017 temp1,
1018 temp2,
1019 first_id,
1020 second_id);
1021 } else if (v->IsCompareJSObjectEq()) {
1022 HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
1023 return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()),
1024 UseRegisterAtStart(compare->right()),
1025 first_id,
1026 second_id);
1027 } else if (v->IsInstanceOf()) {
1028 HInstanceOf* instance_of = HInstanceOf::cast(v);
1029 LInstruction* result =
1030 new LInstanceOfAndBranch(Use(instance_of->left()),
1031 Use(instance_of->right()),
1032 first_id,
1033 second_id);
1034 return MarkAsCall(result, instr);
1035 } else if (v->IsTypeofIs()) {
1036 HTypeofIs* typeof_is = HTypeofIs::cast(v);
1037 return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()),
1038 first_id,
1039 second_id);
1040 } else {
1041 if (v->IsConstant()) {
1042 if (HConstant::cast(v)->handle()->IsTrue()) {
1043 return new LGoto(first_id);
1044 } else if (HConstant::cast(v)->handle()->IsFalse()) {
1045 return new LGoto(second_id);
1046 }
1047 }
1048 Abort("Undefined compare before branch");
1049 return NULL;
1050 }
1051 }
1052 return new LBranch(UseRegisterAtStart(v), first_id, second_id);
1053}
1054
1055
1056LInstruction* LChunkBuilder::DoCompareMapAndBranch(
1057 HCompareMapAndBranch* instr) {
1058 ASSERT(instr->value()->representation().IsTagged());
1059 LOperand* value = UseRegisterAtStart(instr->value());
Steve Block9fac8402011-05-12 15:51:54 +01001060 LOperand* temp = TempRegister();
1061 return new LCmpMapAndBranch(value, temp);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001062}
1063
1064
1065LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01001066 return DefineAsRegister(new LArgumentsLength(UseRegister(length->value())));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001067}
1068
1069
1070LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
1071 return DefineAsRegister(new LArgumentsElements);
1072}
1073
1074
1075LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
1076 LInstruction* result =
Steve Block9fac8402011-05-12 15:51:54 +01001077 new LInstanceOf(UseFixed(instr->left(), r0),
1078 UseFixed(instr->right(), r1));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001079 return MarkAsCall(DefineFixed(result, r0), instr);
1080}
1081
1082
Ben Murdoch086aeea2011-05-13 15:57:08 +01001083LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
1084 HInstanceOfKnownGlobal* instr) {
1085 LInstruction* result =
1086 new LInstanceOfKnownGlobal(UseFixed(instr->value(), r0));
1087 return MarkAsCall(DefineFixed(result, r0), instr);
1088}
1089
1090
Ben Murdochb0fe1622011-05-05 13:52:32 +01001091LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
1092 LOperand* function = UseFixed(instr->function(), r1);
1093 LOperand* receiver = UseFixed(instr->receiver(), r0);
1094 LOperand* length = UseRegisterAtStart(instr->length());
1095 LOperand* elements = UseRegisterAtStart(instr->elements());
1096 LInstruction* result = new LApplyArguments(function,
1097 receiver,
1098 length,
1099 elements);
1100 return MarkAsCall(DefineFixed(result, r0), instr, CAN_DEOPTIMIZE_EAGERLY);
1101}
1102
1103
1104LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
1105 ++argument_count_;
1106 LOperand* argument = Use(instr->argument());
1107 return new LPushArgument(argument);
1108}
1109
1110
1111LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
1112 return DefineAsRegister(new LGlobalObject);
1113}
1114
1115
1116LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
1117 return DefineAsRegister(new LGlobalReceiver);
1118}
1119
1120
1121LInstruction* LChunkBuilder::DoCallConstantFunction(
1122 HCallConstantFunction* instr) {
1123 argument_count_ -= instr->argument_count();
1124 return MarkAsCall(DefineFixed(new LCallConstantFunction, r0), instr);
1125}
1126
1127
1128LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
1129 BuiltinFunctionId op = instr->op();
1130 LOperand* input = UseRegisterAtStart(instr->value());
Ben Murdochb8e0da22011-05-16 14:20:40 +01001131 LOperand* temp = (op == kMathFloor) ? TempRegister() : NULL;
1132 LInstruction* result = new LUnaryMathOperation(input, temp);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001133 switch (op) {
1134 case kMathAbs:
1135 return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1136 case kMathFloor:
1137 return AssignEnvironment(DefineAsRegister(result));
1138 case kMathSqrt:
1139 return DefineSameAsFirst(result);
Steve Block9fac8402011-05-12 15:51:54 +01001140 case kMathRound:
1141 Abort("MathRound LUnaryMathOperation not implemented");
1142 return NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001143 case kMathPowHalf:
1144 Abort("MathPowHalf LUnaryMathOperation not implemented");
1145 return NULL;
1146 case kMathLog:
1147 Abort("MathLog LUnaryMathOperation not implemented");
1148 return NULL;
1149 case kMathCos:
1150 Abort("MathCos LUnaryMathOperation not implemented");
1151 return NULL;
1152 case kMathSin:
1153 Abort("MathSin LUnaryMathOperation not implemented");
1154 return NULL;
1155 default:
1156 UNREACHABLE();
1157 return NULL;
1158 }
1159}
1160
1161
1162LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
1163 ASSERT(instr->key()->representation().IsTagged());
1164 argument_count_ -= instr->argument_count();
1165 UseFixed(instr->key(), r2);
1166 return MarkAsCall(DefineFixed(new LCallKeyed, r0), instr);
1167}
1168
1169
1170LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
1171 argument_count_ -= instr->argument_count();
1172 return MarkAsCall(DefineFixed(new LCallNamed, r0), instr);
1173}
1174
1175
1176LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
1177 argument_count_ -= instr->argument_count();
1178 return MarkAsCall(DefineFixed(new LCallGlobal, r0), instr);
1179}
1180
1181
1182LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
1183 argument_count_ -= instr->argument_count();
1184 return MarkAsCall(DefineFixed(new LCallKnownGlobal, r0), instr);
1185}
1186
1187
1188LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
1189 LOperand* constructor = UseFixed(instr->constructor(), r1);
1190 argument_count_ -= instr->argument_count();
1191 LInstruction* result = new LCallNew(constructor);
1192 return MarkAsCall(DefineFixed(result, r0), instr);
1193}
1194
1195
1196LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
1197 argument_count_ -= instr->argument_count();
1198 return MarkAsCall(DefineFixed(new LCallFunction, r0), instr);
1199}
1200
1201
1202LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1203 argument_count_ -= instr->argument_count();
1204 return MarkAsCall(DefineFixed(new LCallRuntime, r0), instr);
1205}
1206
1207
1208LInstruction* LChunkBuilder::DoShr(HShr* instr) {
1209 return DoShift(Token::SHR, instr);
1210}
1211
1212
1213LInstruction* LChunkBuilder::DoSar(HSar* instr) {
1214 return DoShift(Token::SAR, instr);
1215}
1216
1217
1218LInstruction* LChunkBuilder::DoShl(HShl* instr) {
1219 return DoShift(Token::SHL, instr);
1220}
1221
1222
1223LInstruction* LChunkBuilder::DoBitAnd(HBitAnd* instr) {
1224 return DoBit(Token::BIT_AND, instr);
1225}
1226
1227
1228LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
1229 ASSERT(instr->value()->representation().IsInteger32());
1230 ASSERT(instr->representation().IsInteger32());
1231 return DefineSameAsFirst(new LBitNotI(UseRegisterAtStart(instr->value())));
1232}
1233
1234
1235LInstruction* LChunkBuilder::DoBitOr(HBitOr* instr) {
1236 return DoBit(Token::BIT_OR, instr);
1237}
1238
1239
1240LInstruction* LChunkBuilder::DoBitXor(HBitXor* instr) {
1241 return DoBit(Token::BIT_XOR, instr);
1242}
1243
1244
1245LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1246 if (instr->representation().IsDouble()) {
1247 return DoArithmeticD(Token::DIV, instr);
1248 } else if (instr->representation().IsInteger32()) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001249 // TODO(1042) The fixed register allocation
1250 // is needed because we call GenericBinaryOpStub from
1251 // the generated code, which requires registers r0
1252 // and r1 to be used. We should remove that
1253 // when we provide a native implementation.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001254 LOperand* value = UseFixed(instr->left(), r0);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001255 LOperand* divisor = UseFixed(instr->right(), r1);
1256 return AssignEnvironment(AssignPointerMap(
1257 DefineFixed(new LDivI(value, divisor), r0)));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001258 } else {
1259 return DoArithmeticT(Token::DIV, instr);
1260 }
1261}
1262
1263
1264LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1265 if (instr->representation().IsInteger32()) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001266 // TODO(1042) The fixed register allocation
1267 // is needed because we call GenericBinaryOpStub from
1268 // the generated code, which requires registers r0
1269 // and r1 to be used. We should remove that
1270 // when we provide a native implementation.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001271 ASSERT(instr->left()->representation().IsInteger32());
1272 ASSERT(instr->right()->representation().IsInteger32());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001273 LOperand* value = UseFixed(instr->left(), r0);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001274 LOperand* divisor = UseFixed(instr->right(), r1);
1275 LInstruction* result = DefineFixed(new LModI(value, divisor), r0);
1276 result = AssignEnvironment(AssignPointerMap(result));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001277 return result;
1278 } else if (instr->representation().IsTagged()) {
1279 return DoArithmeticT(Token::MOD, instr);
1280 } else {
1281 ASSERT(instr->representation().IsDouble());
1282 // We call a C function for double modulo. It can't trigger a GC.
1283 // We need to use fixed result register for the call.
1284 // TODO(fschneider): Allow any register as input registers.
1285 LOperand* left = UseFixedDouble(instr->left(), d1);
1286 LOperand* right = UseFixedDouble(instr->right(), d2);
1287 LArithmeticD* result = new LArithmeticD(Token::MOD, left, right);
1288 return MarkAsCall(DefineFixedDouble(result, d1), instr);
1289 }
1290}
1291
1292
1293LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1294 if (instr->representation().IsInteger32()) {
1295 ASSERT(instr->left()->representation().IsInteger32());
1296 ASSERT(instr->right()->representation().IsInteger32());
1297 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1298 LOperand* right = UseOrConstant(instr->MostConstantOperand());
1299 LOperand* temp = NULL;
1300 if (instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1301 temp = TempRegister();
1302 }
1303 LMulI* mul = new LMulI(left, right, temp);
1304 return AssignEnvironment(DefineSameAsFirst(mul));
1305 } else if (instr->representation().IsDouble()) {
1306 return DoArithmeticD(Token::MUL, instr);
1307 } else {
1308 return DoArithmeticT(Token::MUL, instr);
1309 }
1310}
1311
1312
1313LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1314 if (instr->representation().IsInteger32()) {
1315 ASSERT(instr->left()->representation().IsInteger32());
1316 ASSERT(instr->right()->representation().IsInteger32());
1317 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1318 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
1319 LSubI* sub = new LSubI(left, right);
1320 LInstruction* result = DefineSameAsFirst(sub);
1321 if (instr->CheckFlag(HValue::kCanOverflow)) {
1322 result = AssignEnvironment(result);
1323 }
1324 return result;
1325 } else if (instr->representation().IsDouble()) {
1326 return DoArithmeticD(Token::SUB, instr);
1327 } else {
1328 return DoArithmeticT(Token::SUB, instr);
1329 }
1330}
1331
1332
1333LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1334 if (instr->representation().IsInteger32()) {
1335 ASSERT(instr->left()->representation().IsInteger32());
1336 ASSERT(instr->right()->representation().IsInteger32());
1337 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1338 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
1339 LAddI* add = new LAddI(left, right);
1340 LInstruction* result = DefineSameAsFirst(add);
1341 if (instr->CheckFlag(HValue::kCanOverflow)) {
1342 result = AssignEnvironment(result);
1343 }
1344 return result;
1345 } else if (instr->representation().IsDouble()) {
1346 return DoArithmeticD(Token::ADD, instr);
1347 } else {
1348 ASSERT(instr->representation().IsTagged());
1349 return DoArithmeticT(Token::ADD, instr);
1350 }
1351}
1352
1353
1354LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1355 Abort("LPower instruction not implemented on ARM");
1356 return NULL;
1357}
1358
1359
1360LInstruction* LChunkBuilder::DoCompare(HCompare* instr) {
1361 Token::Value op = instr->token();
Ben Murdochb8e0da22011-05-16 14:20:40 +01001362 Representation r = instr->GetInputRepresentation();
1363 if (r.IsInteger32()) {
1364 ASSERT(instr->left()->representation().IsInteger32());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001365 ASSERT(instr->right()->representation().IsInteger32());
1366 LOperand* left = UseRegisterAtStart(instr->left());
1367 LOperand* right = UseOrConstantAtStart(instr->right());
Ben Murdochb8e0da22011-05-16 14:20:40 +01001368 return DefineAsRegister(new LCmpID(left, right));
1369 } else if (r.IsDouble()) {
1370 ASSERT(instr->left()->representation().IsDouble());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001371 ASSERT(instr->right()->representation().IsDouble());
1372 LOperand* left = UseRegisterAtStart(instr->left());
1373 LOperand* right = UseRegisterAtStart(instr->right());
Ben Murdochb8e0da22011-05-16 14:20:40 +01001374 return DefineAsRegister(new LCmpID(left, right));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001375 } else {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001376 ASSERT(instr->left()->representation().IsTagged());
1377 ASSERT(instr->right()->representation().IsTagged());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001378 bool reversed = (op == Token::GT || op == Token::LTE);
1379 LOperand* left = UseFixed(instr->left(), reversed ? r0 : r1);
1380 LOperand* right = UseFixed(instr->right(), reversed ? r1 : r0);
1381 LInstruction* result = new LCmpT(left, right);
1382 return MarkAsCall(DefineFixed(result, r0), instr);
1383 }
1384}
1385
1386
1387LInstruction* LChunkBuilder::DoCompareJSObjectEq(
1388 HCompareJSObjectEq* instr) {
1389 LOperand* left = UseRegisterAtStart(instr->left());
1390 LOperand* right = UseRegisterAtStart(instr->right());
1391 LInstruction* result = new LCmpJSObjectEq(left, right);
1392 return DefineAsRegister(result);
1393}
1394
1395
1396LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) {
1397 ASSERT(instr->value()->representation().IsTagged());
1398 LOperand* value = UseRegisterAtStart(instr->value());
1399
Ben Murdochb8e0da22011-05-16 14:20:40 +01001400 return DefineAsRegister(new LIsNull(value));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001401}
1402
1403
1404LInstruction* LChunkBuilder::DoIsObject(HIsObject* instr) {
1405 ASSERT(instr->value()->representation().IsTagged());
1406 LOperand* value = UseRegisterAtStart(instr->value());
1407
1408 return DefineAsRegister(new LIsObject(value, TempRegister()));
1409}
1410
1411
1412LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) {
1413 ASSERT(instr->value()->representation().IsTagged());
1414 LOperand* value = UseAtStart(instr->value());
1415
1416 return DefineAsRegister(new LIsSmi(value));
1417}
1418
1419
1420LInstruction* LChunkBuilder::DoHasInstanceType(HHasInstanceType* instr) {
1421 ASSERT(instr->value()->representation().IsTagged());
1422 LOperand* value = UseRegisterAtStart(instr->value());
1423
1424 return DefineAsRegister(new LHasInstanceType(value));
1425}
1426
1427
1428LInstruction* LChunkBuilder::DoHasCachedArrayIndex(
1429 HHasCachedArrayIndex* instr) {
1430 ASSERT(instr->value()->representation().IsTagged());
1431 LOperand* value = UseRegister(instr->value());
1432
1433 return DefineAsRegister(new LHasCachedArrayIndex(value));
1434}
1435
1436
1437LInstruction* LChunkBuilder::DoClassOfTest(HClassOfTest* instr) {
1438 ASSERT(instr->value()->representation().IsTagged());
1439 LOperand* value = UseTempRegister(instr->value());
Ben Murdochb8e0da22011-05-16 14:20:40 +01001440 return DefineSameAsFirst(new LClassOfTest(value));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001441}
1442
1443
Steve Block9fac8402011-05-12 15:51:54 +01001444LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
1445 LOperand* array = UseRegisterAtStart(instr->value());
1446 return DefineAsRegister(new LJSArrayLength(array));
1447}
Ben Murdochb0fe1622011-05-05 13:52:32 +01001448
Ben Murdochb0fe1622011-05-05 13:52:32 +01001449
Steve Block9fac8402011-05-12 15:51:54 +01001450LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
1451 LOperand* array = UseRegisterAtStart(instr->value());
1452 return DefineAsRegister(new LFixedArrayLength(array));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001453}
1454
1455
1456LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
1457 LOperand* object = UseRegister(instr->value());
1458 LInstruction* result = new LValueOf(object, TempRegister());
1459 return AssignEnvironment(DefineSameAsFirst(result));
1460}
1461
1462
1463LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1464 return AssignEnvironment(new LBoundsCheck(UseRegisterAtStart(instr->index()),
Ben Murdoch086aeea2011-05-13 15:57:08 +01001465 UseRegister(instr->length())));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001466}
1467
1468
1469LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
1470 LOperand* value = UseFixed(instr->value(), r0);
1471 return MarkAsCall(new LThrow(value), instr);
1472}
1473
1474
1475LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1476 Representation from = instr->from();
1477 Representation to = instr->to();
1478 if (from.IsTagged()) {
1479 if (to.IsDouble()) {
1480 LOperand* value = UseRegister(instr->value());
1481 LInstruction* res = new LNumberUntagD(value);
1482 return AssignEnvironment(DefineAsRegister(res));
1483 } else {
1484 ASSERT(to.IsInteger32());
1485 LOperand* value = UseRegister(instr->value());
1486 bool needs_check = !instr->value()->type().IsSmi();
1487 LInstruction* res = NULL;
1488 if (needs_check) {
1489 res = DefineSameAsFirst(new LTaggedToI(value, FixedTemp(d1)));
1490 } else {
1491 res = DefineSameAsFirst(new LSmiUntag(value, needs_check));
1492 }
1493 if (needs_check) {
1494 res = AssignEnvironment(res);
1495 }
1496 return res;
1497 }
1498 } else if (from.IsDouble()) {
1499 if (to.IsTagged()) {
1500 LOperand* value = UseRegister(instr->value());
1501 LOperand* temp1 = TempRegister();
1502 LOperand* temp2 = TempRegister();
1503
1504 // Make sure that the temp and result_temp registers are
1505 // different.
1506 LUnallocated* result_temp = TempRegister();
1507 LInstruction* result = new LNumberTagD(value, temp1, temp2);
1508 Define(result, result_temp);
1509 return AssignPointerMap(result);
1510 } else {
1511 ASSERT(to.IsInteger32());
1512 LOperand* value = UseRegister(instr->value());
1513 LInstruction* res = new LDoubleToI(value);
1514 return AssignEnvironment(DefineAsRegister(res));
1515 }
1516 } else if (from.IsInteger32()) {
1517 if (to.IsTagged()) {
1518 HValue* val = instr->value();
1519 LOperand* value = UseRegister(val);
1520 if (val->HasRange() && val->range()->IsInSmiRange()) {
1521 return DefineSameAsFirst(new LSmiTag(value));
1522 } else {
1523 LInstruction* result = new LNumberTagI(value);
1524 return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1525 }
1526 } else {
1527 ASSERT(to.IsDouble());
1528 LOperand* value = Use(instr->value());
1529 return DefineAsRegister(new LInteger32ToDouble(value));
1530 }
1531 }
1532 UNREACHABLE();
1533 return NULL;
1534}
1535
1536
1537LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
1538 LOperand* value = UseRegisterAtStart(instr->value());
1539 return AssignEnvironment(new LCheckSmi(value, eq));
1540}
1541
1542
1543LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
1544 LOperand* value = UseRegisterAtStart(instr->value());
Ben Murdoch086aeea2011-05-13 15:57:08 +01001545 LInstruction* result = new LCheckInstanceType(value);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001546 return AssignEnvironment(result);
1547}
1548
1549
1550LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
Steve Block9fac8402011-05-12 15:51:54 +01001551 LOperand* temp1 = TempRegister();
1552 LOperand* temp2 = TempRegister();
Ben Murdochb8e0da22011-05-16 14:20:40 +01001553 LInstruction* result = new LCheckPrototypeMaps(temp1, temp2);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001554 return AssignEnvironment(result);
1555}
1556
1557
1558LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
1559 LOperand* value = UseRegisterAtStart(instr->value());
1560 return AssignEnvironment(new LCheckSmi(value, ne));
1561}
1562
1563
1564LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
1565 LOperand* value = UseRegisterAtStart(instr->value());
1566 return AssignEnvironment(new LCheckFunction(value));
1567}
1568
1569
1570LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) {
1571 LOperand* value = UseRegisterAtStart(instr->value());
1572 LInstruction* result = new LCheckMap(value);
1573 return AssignEnvironment(result);
1574}
1575
1576
1577LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
1578 return new LReturn(UseFixed(instr->value(), r0));
1579}
1580
1581
1582LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
1583 Representation r = instr->representation();
1584 if (r.IsInteger32()) {
1585 int32_t value = instr->Integer32Value();
1586 return DefineAsRegister(new LConstantI(value));
1587 } else if (r.IsDouble()) {
1588 double value = instr->DoubleValue();
1589 return DefineAsRegister(new LConstantD(value));
1590 } else if (r.IsTagged()) {
1591 return DefineAsRegister(new LConstantT(instr->handle()));
1592 } else {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001593 UNREACHABLE();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001594 return NULL;
1595 }
1596}
1597
1598
1599LInstruction* LChunkBuilder::DoLoadGlobal(HLoadGlobal* instr) {
1600 LInstruction* result = new LLoadGlobal();
1601 return instr->check_hole_value()
1602 ? AssignEnvironment(DefineAsRegister(result))
1603 : DefineAsRegister(result);
1604}
1605
1606
1607LInstruction* LChunkBuilder::DoStoreGlobal(HStoreGlobal* instr) {
1608 return new LStoreGlobal(UseRegisterAtStart(instr->value()));
1609}
1610
1611
Ben Murdochb8e0da22011-05-16 14:20:40 +01001612LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
1613 return DefineAsRegister(new LLoadContextSlot);
1614}
1615
1616
Ben Murdochb0fe1622011-05-05 13:52:32 +01001617LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
1618 return DefineAsRegister(
1619 new LLoadNamedField(UseRegisterAtStart(instr->object())));
1620}
1621
1622
1623LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
1624 LOperand* object = UseFixed(instr->object(), r0);
1625 LInstruction* result = DefineFixed(new LLoadNamedGeneric(object), r0);
1626 return MarkAsCall(result, instr);
1627}
1628
1629
Steve Block9fac8402011-05-12 15:51:54 +01001630LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
1631 HLoadFunctionPrototype* instr) {
1632 return AssignEnvironment(DefineAsRegister(
1633 new LLoadFunctionPrototype(UseRegister(instr->function()))));
1634}
1635
1636
Ben Murdochb0fe1622011-05-05 13:52:32 +01001637LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
1638 LOperand* input = UseRegisterAtStart(instr->value());
1639 return DefineSameAsFirst(new LLoadElements(input));
1640}
1641
1642
1643LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
1644 HLoadKeyedFastElement* instr) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001645 ASSERT(instr->representation().IsTagged());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001646 ASSERT(instr->key()->representation().IsInteger32());
Ben Murdochb8e0da22011-05-16 14:20:40 +01001647 LOperand* obj = UseRegisterAtStart(instr->object());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001648 LOperand* key = UseRegisterAtStart(instr->key());
Ben Murdochb8e0da22011-05-16 14:20:40 +01001649 LInstruction* result = new LLoadKeyedFastElement(obj, key);
1650 return AssignEnvironment(DefineSameAsFirst(result));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001651}
1652
1653
1654LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
1655 LOperand* object = UseFixed(instr->object(), r1);
1656 LOperand* key = UseFixed(instr->key(), r0);
1657
1658 LInstruction* result =
1659 DefineFixed(new LLoadKeyedGeneric(object, key), r0);
1660 return MarkAsCall(result, instr);
1661}
1662
1663
1664LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
1665 HStoreKeyedFastElement* instr) {
1666 bool needs_write_barrier = instr->NeedsWriteBarrier();
1667 ASSERT(instr->value()->representation().IsTagged());
1668 ASSERT(instr->object()->representation().IsTagged());
1669 ASSERT(instr->key()->representation().IsInteger32());
1670
1671 LOperand* obj = UseTempRegister(instr->object());
1672 LOperand* val = needs_write_barrier
1673 ? UseTempRegister(instr->value())
1674 : UseRegisterAtStart(instr->value());
1675 LOperand* key = needs_write_barrier
1676 ? UseTempRegister(instr->key())
1677 : UseRegisterOrConstantAtStart(instr->key());
1678
1679 return AssignEnvironment(new LStoreKeyedFastElement(obj, key, val));
1680}
1681
1682
1683LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
1684 LOperand* obj = UseFixed(instr->object(), r2);
1685 LOperand* key = UseFixed(instr->key(), r1);
1686 LOperand* val = UseFixed(instr->value(), r0);
1687
1688 ASSERT(instr->object()->representation().IsTagged());
1689 ASSERT(instr->key()->representation().IsTagged());
1690 ASSERT(instr->value()->representation().IsTagged());
1691
1692 return MarkAsCall(new LStoreKeyedGeneric(obj, key, val), instr);
1693}
1694
1695
1696LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01001697 bool needs_write_barrier = instr->NeedsWriteBarrier();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001698
1699 LOperand* obj = needs_write_barrier
1700 ? UseTempRegister(instr->object())
1701 : UseRegisterAtStart(instr->object());
1702
1703 LOperand* val = needs_write_barrier
1704 ? UseTempRegister(instr->value())
1705 : UseRegister(instr->value());
1706
Ben Murdochb8e0da22011-05-16 14:20:40 +01001707 return new LStoreNamedField(obj, val);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001708}
1709
1710
1711LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
1712 LOperand* obj = UseFixed(instr->object(), r1);
1713 LOperand* val = UseFixed(instr->value(), r0);
1714
Ben Murdochb8e0da22011-05-16 14:20:40 +01001715 LInstruction* result = new LStoreNamedGeneric(obj, val);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001716 return MarkAsCall(result, instr);
1717}
1718
1719
1720LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
1721 return MarkAsCall(DefineFixed(new LArrayLiteral, r0), instr);
1722}
1723
1724
1725LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) {
1726 return MarkAsCall(DefineFixed(new LObjectLiteral, r0), instr);
1727}
1728
1729
1730LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
1731 return MarkAsCall(DefineFixed(new LRegExpLiteral, r0), instr);
1732}
1733
1734
1735LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
1736 return MarkAsCall(DefineFixed(new LFunctionLiteral, r0), instr);
1737}
1738
1739
1740LInstruction* LChunkBuilder::DoDeleteProperty(HDeleteProperty* instr) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001741 LOperand* object = UseRegisterAtStart(instr->object());
1742 LOperand* key = UseRegisterAtStart(instr->key());
1743 LInstruction* result = new LDeleteProperty(object, key);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001744 return MarkAsCall(DefineFixed(result, r0), instr);
1745}
1746
1747
1748LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
1749 allocator_->MarkAsOsrEntry();
1750 current_block_->last_environment()->set_ast_id(instr->ast_id());
1751 return AssignEnvironment(new LOsrEntry);
1752}
1753
1754
1755LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
1756 int spill_index = chunk()->GetParameterStackSlot(instr->index());
1757 return DefineAsSpilled(new LParameter, spill_index);
1758}
1759
1760
1761LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
1762 int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width.
1763 return DefineAsSpilled(new LUnknownOSRValue, spill_index);
1764}
1765
1766
1767LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
1768 argument_count_ -= instr->argument_count();
1769 return MarkAsCall(DefineFixed(new LCallStub, r0), instr);
1770}
1771
1772
1773LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
1774 // There are no real uses of the arguments object (we bail out in all other
1775 // cases).
1776 return NULL;
1777}
1778
1779
1780LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
1781 LOperand* arguments = UseRegister(instr->arguments());
1782 LOperand* length = UseTempRegister(instr->length());
Ben Murdoch086aeea2011-05-13 15:57:08 +01001783 LOperand* index = UseRegister(instr->index());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001784 LInstruction* result = new LAccessArgumentsAt(arguments, length, index);
1785 return DefineAsRegister(AssignEnvironment(result));
1786}
1787
1788
1789LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01001790 LInstruction* result = new LTypeof(UseRegisterAtStart(instr->value()));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001791 return MarkAsCall(DefineFixed(result, r0), instr);
1792}
1793
1794
1795LInstruction* LChunkBuilder::DoTypeofIs(HTypeofIs* instr) {
1796 return DefineSameAsFirst(new LTypeofIs(UseRegister(instr->value())));
1797}
1798
1799LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
1800 HEnvironment* env = current_block_->last_environment();
1801 ASSERT(env != NULL);
1802
1803 env->set_ast_id(instr->ast_id());
1804
1805 env->Drop(instr->pop_count());
1806 for (int i = 0; i < instr->values()->length(); ++i) {
1807 HValue* value = instr->values()->at(i);
1808 if (instr->HasAssignedIndexAt(i)) {
1809 env->Bind(instr->GetAssignedIndexAt(i), value);
1810 } else {
1811 env->Push(value);
1812 }
1813 }
1814
Steve Block9fac8402011-05-12 15:51:54 +01001815 ASSERT(env->length() == instr->environment_length());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001816
1817 // If there is an instruction pending deoptimization environment create a
1818 // lazy bailout instruction to capture the environment.
1819 if (pending_deoptimization_ast_id_ == instr->ast_id()) {
1820 LInstruction* result = new LLazyBailout;
1821 result = AssignEnvironment(result);
1822 instructions_pending_deoptimization_environment_->
1823 set_deoptimization_environment(result->environment());
1824 ClearInstructionPendingDeoptimizationEnvironment();
1825 return result;
1826 }
1827
1828 return NULL;
1829}
1830
1831
1832LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
1833 return MarkAsCall(new LStackCheck, instr);
1834}
1835
1836
1837LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
1838 HEnvironment* outer = current_block_->last_environment();
1839 HConstant* undefined = graph()->GetConstantUndefined();
1840 HEnvironment* inner = outer->CopyForInlining(instr->closure(),
1841 instr->function(),
1842 false,
1843 undefined);
1844 current_block_->UpdateEnvironment(inner);
1845 chunk_->AddInlinedClosure(instr->closure());
1846 return NULL;
1847}
1848
1849
1850LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
1851 HEnvironment* outer = current_block_->last_environment()->outer();
1852 current_block_->UpdateEnvironment(outer);
1853 return NULL;
1854}
1855
1856
Ben Murdochb0fe1622011-05-05 13:52:32 +01001857} } // namespace v8::internal