Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(415)

Side by Side Diff: src/arm/lithium-arm.cc

Issue 6529055: [Isolates] Merge crankshaft (r5922 from bleeding_edge). (Closed)
Patch Set: Win32 port Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/arm/lithium-arm.h ('k') | src/arm/lithium-codegen-arm.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2010 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
28 #include "arm/lithium-arm.h"
29 #include "arm/lithium-codegen-arm.h"
30
31 namespace v8 {
32 namespace internal {
33
34 #define DEFINE_COMPILE(type) \
35 void L##type::CompileToNative(LCodeGen* generator) { \
36 generator->Do##type(this); \
37 }
38 LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
39 #undef DEFINE_COMPILE
40
41 LOsrEntry::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
51 void 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
59 void 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
67 void 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
87 void 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
96 bool LParallelMove::IsRedundant() const {
97 for (int i = 0; i < move_operands_.length(); ++i) {
98 if (!move_operands_[i].IsRedundant()) return false;
99 }
100 return true;
101 }
102
103
104 void LParallelMove::PrintDataTo(StringStream* stream) const {
105 for (int i = move_operands_.length() - 1; i >= 0; --i) {
106 if (!move_operands_[i].IsEliminated()) {
107 LOperand* from = move_operands_[i].from();
108 LOperand* to = move_operands_[i].to();
109 if (from->Equals(to)) {
110 to->PrintTo(stream);
111 } else {
112 to->PrintTo(stream);
113 stream->Add(" = ");
114 from->PrintTo(stream);
115 }
116 stream->Add("; ");
117 }
118 }
119 }
120
121
122 bool 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
133 void LGap::PrintDataTo(StringStream* stream) const {
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
144 const 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
158 const 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
172
173 void LBinaryOperation::PrintDataTo(StringStream* stream) const {
174 stream->Add("= ");
175 left()->PrintTo(stream);
176 stream->Add(" ");
177 right()->PrintTo(stream);
178 }
179
180
181 void LGoto::PrintDataTo(StringStream* stream) const {
182 stream->Add("B%d", block_id());
183 }
184
185
186 void LBranch::PrintDataTo(StringStream* stream) const {
187 stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
188 input()->PrintTo(stream);
189 }
190
191
192 void LCmpIDAndBranch::PrintDataTo(StringStream* stream) const {
193 stream->Add("if ");
194 left()->PrintTo(stream);
195 stream->Add(" %s ", Token::String(op()));
196 right()->PrintTo(stream);
197 stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
198 }
199
200
201 void LIsNullAndBranch::PrintDataTo(StringStream* stream) const {
202 stream->Add("if ");
203 input()->PrintTo(stream);
204 stream->Add(is_strict() ? " === null" : " == null");
205 stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
206 }
207
208
209 void LIsSmiAndBranch::PrintDataTo(StringStream* stream) const {
210 stream->Add("if is_smi(");
211 input()->PrintTo(stream);
212 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
213 }
214
215
216 void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) const {
217 stream->Add("if has_instance_type(");
218 input()->PrintTo(stream);
219 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
220 }
221
222
223 void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) const {
224 stream->Add("if has_cached_array_index(");
225 input()->PrintTo(stream);
226 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
227 }
228
229
230 void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) const {
231 stream->Add("if class_of_test(");
232 input()->PrintTo(stream);
233 stream->Add(", \"%o\") then B%d else B%d",
234 *hydrogen()->class_name(),
235 true_block_id(),
236 false_block_id());
237 }
238
239
240 void LTypeofIs::PrintDataTo(StringStream* stream) const {
241 input()->PrintTo(stream);
242 stream->Add(" == \"%s\"", *hydrogen()->type_literal()->ToCString());
243 }
244
245
246 void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) const {
247 stream->Add("if typeof ");
248 input()->PrintTo(stream);
249 stream->Add(" == \"%s\" then B%d else B%d",
250 *hydrogen()->type_literal()->ToCString(),
251 true_block_id(), false_block_id());
252 }
253
254
255 void LCallConstantFunction::PrintDataTo(StringStream* stream) const {
256 stream->Add("#%d / ", arity());
257 }
258
259
260 void LUnaryMathOperation::PrintDataTo(StringStream* stream) const {
261 stream->Add("/%s ", hydrogen()->OpName());
262 input()->PrintTo(stream);
263 }
264
265
266 void LCallKeyed::PrintDataTo(StringStream* stream) const {
267 stream->Add("[r2] #%d / ", arity());
268 }
269
270
271 void LCallNamed::PrintDataTo(StringStream* stream) const {
272 SmartPointer<char> name_string = name()->ToCString();
273 stream->Add("%s #%d / ", *name_string, arity());
274 }
275
276
277 void LCallGlobal::PrintDataTo(StringStream* stream) const {
278 SmartPointer<char> name_string = name()->ToCString();
279 stream->Add("%s #%d / ", *name_string, arity());
280 }
281
282
283 void LCallKnownGlobal::PrintDataTo(StringStream* stream) const {
284 stream->Add("#%d / ", arity());
285 }
286
287
288 void LCallNew::PrintDataTo(StringStream* stream) const {
289 LUnaryOperation::PrintDataTo(stream);
290 stream->Add(" #%d / ", arity());
291 }
292
293
294 void LClassOfTest::PrintDataTo(StringStream* stream) const {
295 stream->Add("= class_of_test(");
296 input()->PrintTo(stream);
297 stream->Add(", \"%o\")", *hydrogen()->class_name());
298 }
299
300
301 void LUnaryOperation::PrintDataTo(StringStream* stream) const {
302 stream->Add("= ");
303 input()->PrintTo(stream);
304 }
305
306
307 void LAccessArgumentsAt::PrintDataTo(StringStream* stream) const {
308 arguments()->PrintTo(stream);
309
310 stream->Add(" length ");
311 length()->PrintTo(stream);
312
313 stream->Add(" index ");
314 index()->PrintTo(stream);
315 }
316
317
318 LChunk::LChunk(HGraph* graph)
319 : spill_slot_count_(0),
320 graph_(graph),
321 instructions_(32),
322 pointer_maps_(8),
323 inlined_closures_(1) {
324 }
325
326
327 void LChunk::Verify() const {
328 // TODO(twuerthinger): Implement verification for chunk.
329 }
330
331
332 int LChunk::GetNextSpillIndex(bool is_double) {
333 // Skip a slot if for a double-width slot.
334 if (is_double) spill_slot_count_++;
335 return spill_slot_count_++;
336 }
337
338
339 LOperand* LChunk::GetNextSpillSlot(bool is_double) {
340 int index = GetNextSpillIndex(is_double);
341 if (is_double) {
342 return LDoubleStackSlot::Create(index);
343 } else {
344 return LStackSlot::Create(index);
345 }
346 }
347
348
349 void LChunk::MarkEmptyBlocks() {
350 HPhase phase("Mark empty blocks", this);
351 for (int i = 0; i < graph()->blocks()->length(); ++i) {
352 HBasicBlock* block = graph()->blocks()->at(i);
353 int first = block->first_instruction_index();
354 int last = block->last_instruction_index();
355 LInstruction* first_instr = instructions()->at(first);
356 LInstruction* last_instr = instructions()->at(last);
357
358 LLabel* label = LLabel::cast(first_instr);
359 if (last_instr->IsGoto()) {
360 LGoto* goto_instr = LGoto::cast(last_instr);
361 if (!goto_instr->include_stack_check() &&
362 label->IsRedundant() &&
363 !label->is_loop_header()) {
364 bool can_eliminate = true;
365 for (int i = first + 1; i < last && can_eliminate; ++i) {
366 LInstruction* cur = instructions()->at(i);
367 if (cur->IsGap()) {
368 LGap* gap = LGap::cast(cur);
369 if (!gap->IsRedundant()) {
370 can_eliminate = false;
371 }
372 } else {
373 can_eliminate = false;
374 }
375 }
376
377 if (can_eliminate) {
378 label->set_replacement(GetLabel(goto_instr->block_id()));
379 }
380 }
381 }
382 }
383 }
384
385
386 void LStoreNamed::PrintDataTo(StringStream* stream) const {
387 object()->PrintTo(stream);
388 stream->Add(".");
389 stream->Add(*String::cast(*name())->ToCString());
390 stream->Add(" <- ");
391 value()->PrintTo(stream);
392 }
393
394
395 void LStoreKeyed::PrintDataTo(StringStream* stream) const {
396 object()->PrintTo(stream);
397 stream->Add("[");
398 key()->PrintTo(stream);
399 stream->Add("] <- ");
400 value()->PrintTo(stream);
401 }
402
403
404 int LChunk::AddInstruction(LInstruction* instr, HBasicBlock* block) {
405 LGap* gap = new LGap(block);
406 int index = -1;
407 if (instr->IsControl()) {
408 instructions_.Add(gap);
409 index = instructions_.length();
410 instructions_.Add(instr);
411 } else {
412 index = instructions_.length();
413 instructions_.Add(instr);
414 instructions_.Add(gap);
415 }
416 if (instr->HasPointerMap()) {
417 pointer_maps_.Add(instr->pointer_map());
418 instr->pointer_map()->set_lithium_position(index);
419 }
420 return index;
421 }
422
423
424 LConstantOperand* LChunk::DefineConstantOperand(HConstant* constant) {
425 return LConstantOperand::Create(constant->id());
426 }
427
428
429 int LChunk::GetParameterStackSlot(int index) const {
430 // The receiver is at index 0, the first parameter at index 1, so we
431 // shift all parameter indexes down by the number of parameters, and
432 // make sure they end up negative so they are distinguishable from
433 // spill slots.
434 int result = index - graph()->info()->scope()->num_parameters() - 1;
435 ASSERT(result < 0);
436 return result;
437 }
438
439 // A parameter relative to ebp in the arguments stub.
440 int LChunk::ParameterAt(int index) {
441 ASSERT(-1 <= index); // -1 is the receiver.
442 return (1 + graph()->info()->scope()->num_parameters() - index) *
443 kPointerSize;
444 }
445
446
447 LGap* LChunk::GetGapAt(int index) const {
448 return LGap::cast(instructions_[index]);
449 }
450
451
452 bool LChunk::IsGapAt(int index) const {
453 return instructions_[index]->IsGap();
454 }
455
456
457 int LChunk::NearestGapPos(int index) const {
458 while (!IsGapAt(index)) index--;
459 return index;
460 }
461
462
463 int LChunk::NearestNextGapPos(int index) const {
464 while (!IsGapAt(index)) index++;
465 return index;
466 }
467
468
469 void LChunk::AddGapMove(int index, LOperand* from, LOperand* to) {
470 GetGapAt(index)->GetOrCreateParallelMove(LGap::START)->AddMove(from, to);
471 }
472
473
474 class LGapNode: public ZoneObject {
475 public:
476 explicit LGapNode(LOperand* operand)
477 : operand_(operand), resolved_(false), visited_id_(-1) { }
478
479 LOperand* operand() const { return operand_; }
480 bool IsResolved() const { return !IsAssigned() || resolved_; }
481 void MarkResolved() {
482 ASSERT(!IsResolved());
483 resolved_ = true;
484 }
485 int visited_id() const { return visited_id_; }
486 void set_visited_id(int id) {
487 ASSERT(id > visited_id_);
488 visited_id_ = id;
489 }
490
491 bool IsAssigned() const { return assigned_from_.is_set(); }
492 LGapNode* assigned_from() const { return assigned_from_.get(); }
493 void set_assigned_from(LGapNode* n) { assigned_from_.set(n); }
494
495 private:
496 LOperand* operand_;
497 SetOncePointer<LGapNode> assigned_from_;
498 bool resolved_;
499 int visited_id_;
500 };
501
502
503 LGapResolver::LGapResolver(const ZoneList<LMoveOperands>* moves,
504 LOperand* marker_operand)
505 : nodes_(4),
506 identified_cycles_(4),
507 result_(4),
508 marker_operand_(marker_operand),
509 next_visited_id_(0) {
510 for (int i = 0; i < moves->length(); ++i) {
511 LMoveOperands move = moves->at(i);
512 if (!move.IsRedundant()) RegisterMove(move);
513 }
514 }
515
516
517 const ZoneList<LMoveOperands>* LGapResolver::ResolveInReverseOrder() {
518 for (int i = 0; i < identified_cycles_.length(); ++i) {
519 ResolveCycle(identified_cycles_[i]);
520 }
521
522 int unresolved_nodes;
523 do {
524 unresolved_nodes = 0;
525 for (int j = 0; j < nodes_.length(); j++) {
526 LGapNode* node = nodes_[j];
527 if (!node->IsResolved() && node->assigned_from()->IsResolved()) {
528 AddResultMove(node->assigned_from(), node);
529 node->MarkResolved();
530 }
531 if (!node->IsResolved()) ++unresolved_nodes;
532 }
533 } while (unresolved_nodes > 0);
534 return &result_;
535 }
536
537
538 void LGapResolver::AddResultMove(LGapNode* from, LGapNode* to) {
539 AddResultMove(from->operand(), to->operand());
540 }
541
542
543 void LGapResolver::AddResultMove(LOperand* from, LOperand* to) {
544 result_.Add(LMoveOperands(from, to));
545 }
546
547
548 void LGapResolver::ResolveCycle(LGapNode* start) {
549 ZoneList<LOperand*> circle_operands(8);
550 circle_operands.Add(marker_operand_);
551 LGapNode* cur = start;
552 do {
553 cur->MarkResolved();
554 circle_operands.Add(cur->operand());
555 cur = cur->assigned_from();
556 } while (cur != start);
557 circle_operands.Add(marker_operand_);
558
559 for (int i = circle_operands.length() - 1; i > 0; --i) {
560 LOperand* from = circle_operands[i];
561 LOperand* to = circle_operands[i - 1];
562 AddResultMove(from, to);
563 }
564 }
565
566
567 bool LGapResolver::CanReach(LGapNode* a, LGapNode* b, int visited_id) {
568 ASSERT(a != b);
569 LGapNode* cur = a;
570 while (cur != b && cur->visited_id() != visited_id && cur->IsAssigned()) {
571 cur->set_visited_id(visited_id);
572 cur = cur->assigned_from();
573 }
574
575 return cur == b;
576 }
577
578
579 bool LGapResolver::CanReach(LGapNode* a, LGapNode* b) {
580 ASSERT(a != b);
581 return CanReach(a, b, next_visited_id_++);
582 }
583
584
585 void LGapResolver::RegisterMove(LMoveOperands move) {
586 if (move.from()->IsConstantOperand()) {
587 // Constant moves should be last in the machine code. Therefore add them
588 // first to the result set.
589 AddResultMove(move.from(), move.to());
590 } else {
591 LGapNode* from = LookupNode(move.from());
592 LGapNode* to = LookupNode(move.to());
593 if (to->IsAssigned() && to->assigned_from() == from) {
594 move.Eliminate();
595 return;
596 }
597 ASSERT(!to->IsAssigned());
598 if (CanReach(from, to)) {
599 // This introduces a circle. Save.
600 identified_cycles_.Add(from);
601 }
602 to->set_assigned_from(from);
603 }
604 }
605
606
607 LGapNode* LGapResolver::LookupNode(LOperand* operand) {
608 for (int i = 0; i < nodes_.length(); ++i) {
609 if (nodes_[i]->operand()->Equals(operand)) return nodes_[i];
610 }
611
612 // No node found => create a new one.
613 LGapNode* result = new LGapNode(operand);
614 nodes_.Add(result);
615 return result;
616 }
617
618
619 Handle<Object> LChunk::LookupLiteral(LConstantOperand* operand) const {
620 return HConstant::cast(graph_->LookupValue(operand->index()))->handle();
621 }
622
623
624 Representation LChunk::LookupLiteralRepresentation(
625 LConstantOperand* operand) const {
626 return graph_->LookupValue(operand->index())->representation();
627 }
628
629
630 LChunk* LChunkBuilder::Build() {
631 ASSERT(is_unused());
632 chunk_ = new LChunk(graph());
633 HPhase phase("Building chunk", chunk_);
634 status_ = BUILDING;
635 const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
636 for (int i = 0; i < blocks->length(); i++) {
637 HBasicBlock* next = NULL;
638 if (i < blocks->length() - 1) next = blocks->at(i + 1);
639 DoBasicBlock(blocks->at(i), next);
640 if (is_aborted()) return NULL;
641 }
642 status_ = DONE;
643 return chunk_;
644 }
645
646
647 void LChunkBuilder::Abort(const char* format, ...) {
648 if (FLAG_trace_bailout) {
649 SmartPointer<char> debug_name = graph()->debug_name()->ToCString();
650 PrintF("Aborting LChunk building in @\"%s\": ", *debug_name);
651 va_list arguments;
652 va_start(arguments, format);
653 OS::VPrint(format, arguments);
654 va_end(arguments);
655 PrintF("\n");
656 }
657 status_ = ABORTED;
658 }
659
660
661 LRegister* LChunkBuilder::ToOperand(Register reg) {
662 return LRegister::Create(Register::ToAllocationIndex(reg));
663 }
664
665
666 LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
667 return new LUnallocated(LUnallocated::FIXED_REGISTER,
668 Register::ToAllocationIndex(reg));
669 }
670
671
672 LUnallocated* LChunkBuilder::ToUnallocated(DoubleRegister reg) {
673 return new LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
674 DoubleRegister::ToAllocationIndex(reg));
675 }
676
677
678 LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
679 return Use(value, ToUnallocated(fixed_register));
680 }
681
682
683 LOperand* LChunkBuilder::UseFixedDouble(HValue* value, DoubleRegister reg) {
684 return Use(value, ToUnallocated(reg));
685 }
686
687
688 LOperand* LChunkBuilder::UseRegister(HValue* value) {
689 return Use(value, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
690 }
691
692
693 LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
694 return Use(value,
695 new LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
696 LUnallocated::USED_AT_START));
697 }
698
699
700 LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
701 return Use(value, new LUnallocated(LUnallocated::WRITABLE_REGISTER));
702 }
703
704
705 LOperand* LChunkBuilder::Use(HValue* value) {
706 return Use(value, new LUnallocated(LUnallocated::NONE));
707 }
708
709
710 LOperand* LChunkBuilder::UseAtStart(HValue* value) {
711 return Use(value, new LUnallocated(LUnallocated::NONE,
712 LUnallocated::USED_AT_START));
713 }
714
715
716 LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
717 return value->IsConstant()
718 ? chunk_->DefineConstantOperand(HConstant::cast(value))
719 : Use(value);
720 }
721
722
723 LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
724 return value->IsConstant()
725 ? chunk_->DefineConstantOperand(HConstant::cast(value))
726 : UseAtStart(value);
727 }
728
729
730 LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
731 return value->IsConstant()
732 ? chunk_->DefineConstantOperand(HConstant::cast(value))
733 : UseRegister(value);
734 }
735
736
737 LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
738 return value->IsConstant()
739 ? chunk_->DefineConstantOperand(HConstant::cast(value))
740 : UseRegisterAtStart(value);
741 }
742
743
744 LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
745 if (value->EmitAtUses()) {
746 HInstruction* instr = HInstruction::cast(value);
747 VisitInstruction(instr);
748 }
749 allocator_->RecordUse(value, operand);
750 return operand;
751 }
752
753
754 LInstruction* LChunkBuilder::Define(LInstruction* instr) {
755 return Define(instr, new LUnallocated(LUnallocated::NONE));
756 }
757
758
759 LInstruction* LChunkBuilder::DefineAsRegister(LInstruction* instr) {
760 return Define(instr, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
761 }
762
763
764 LInstruction* LChunkBuilder::DefineAsSpilled(LInstruction* instr, int index) {
765 return Define(instr, new LUnallocated(LUnallocated::FIXED_SLOT, index));
766 }
767
768
769 LInstruction* LChunkBuilder::DefineSameAsAny(LInstruction* instr) {
770 return Define(instr, new LUnallocated(LUnallocated::SAME_AS_ANY_INPUT));
771 }
772
773
774 LInstruction* LChunkBuilder::DefineSameAsFirst(LInstruction* instr) {
775 return Define(instr, new LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
776 }
777
778
779 LInstruction* LChunkBuilder::DefineFixed(LInstruction* instr, Register reg) {
780 return Define(instr, ToUnallocated(reg));
781 }
782
783
784 LInstruction* LChunkBuilder::DefineFixedDouble(LInstruction* instr,
785 DoubleRegister reg) {
786 return Define(instr, ToUnallocated(reg));
787 }
788
789
790 LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
791 HEnvironment* hydrogen_env = current_block_->last_environment();
792 instr->set_environment(CreateEnvironment(hydrogen_env));
793 return instr;
794 }
795
796
797 LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
798 LInstruction* instr, int ast_id) {
799 ASSERT(instructions_pending_deoptimization_environment_ == NULL);
800 ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
801 instructions_pending_deoptimization_environment_ = instr;
802 pending_deoptimization_ast_id_ = ast_id;
803 return instr;
804 }
805
806
807 void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
808 instructions_pending_deoptimization_environment_ = NULL;
809 pending_deoptimization_ast_id_ = AstNode::kNoNumber;
810 }
811
812
813 LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
814 HInstruction* hinstr,
815 CanDeoptimize can_deoptimize) {
816 allocator_->MarkAsCall();
817 instr = AssignPointerMap(instr);
818
819 if (hinstr->HasSideEffects()) {
820 ASSERT(hinstr->next()->IsSimulate());
821 HSimulate* sim = HSimulate::cast(hinstr->next());
822 instr = SetInstructionPendingDeoptimizationEnvironment(
823 instr, sim->ast_id());
824 }
825
826 // If instruction does not have side-effects lazy deoptimization
827 // after the call will try to deoptimize to the point before the call.
828 // Thus we still need to attach environment to this call even if
829 // call sequence can not deoptimize eagerly.
830 bool needs_environment =
831 (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) || !hinstr->HasSideEffects();
832 if (needs_environment && !instr->HasEnvironment()) {
833 instr = AssignEnvironment(instr);
834 }
835
836 return instr;
837 }
838
839
840 LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
841 ASSERT(!instr->HasPointerMap());
842 instr->set_pointer_map(new LPointerMap(position_));
843 return instr;
844 }
845
846
847 LInstruction* LChunkBuilder::Define(LInstruction* instr, LUnallocated* result) {
848 allocator_->RecordDefinition(current_instruction_, result);
849 instr->set_result(result);
850 return instr;
851 }
852
853
854 LOperand* LChunkBuilder::Temp() {
855 LUnallocated* operand = new LUnallocated(LUnallocated::NONE);
856 allocator_->RecordTemporary(operand);
857 return operand;
858 }
859
860
861 LUnallocated* LChunkBuilder::TempRegister() {
862 LUnallocated* operand = new LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
863 allocator_->RecordTemporary(operand);
864 return operand;
865 }
866
867
868 LOperand* LChunkBuilder::FixedTemp(Register reg) {
869 LUnallocated* operand = ToUnallocated(reg);
870 allocator_->RecordTemporary(operand);
871 return operand;
872 }
873
874
875 LOperand* LChunkBuilder::FixedTemp(DoubleRegister reg) {
876 LUnallocated* operand = ToUnallocated(reg);
877 allocator_->RecordTemporary(operand);
878 return operand;
879 }
880
881
882 LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
883 return new LLabel(instr->block());
884 }
885
886
887 LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
888 return AssignEnvironment(new LDeoptimize);
889 }
890
891
892 LInstruction* LChunkBuilder::DoBit(Token::Value op,
893 HBitwiseBinaryOperation* instr) {
894 ASSERT(instr->representation().IsInteger32());
895 ASSERT(instr->left()->representation().IsInteger32());
896 ASSERT(instr->right()->representation().IsInteger32());
897
898 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
899 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
900 return DefineSameAsFirst(new LBitI(op, left, right));
901 }
902
903
904 LInstruction* LChunkBuilder::DoShift(Token::Value op,
905 HBitwiseBinaryOperation* instr) {
906 ASSERT(instr->representation().IsInteger32());
907 ASSERT(instr->OperandAt(0)->representation().IsInteger32());
908 ASSERT(instr->OperandAt(1)->representation().IsInteger32());
909 LOperand* left = UseRegisterAtStart(instr->OperandAt(0));
910
911 HValue* right_value = instr->OperandAt(1);
912 LOperand* right = NULL;
913 int constant_value = 0;
914 if (right_value->IsConstant()) {
915 HConstant* constant = HConstant::cast(right_value);
916 right = chunk_->DefineConstantOperand(constant);
917 constant_value = constant->Integer32Value() & 0x1f;
918 } else {
919 right = UseRegister(right_value);
920 }
921
922 // Shift operations can only deoptimize if we do a logical shift
923 // by 0 and the result cannot be truncated to int32.
924 bool can_deopt = (op == Token::SHR && constant_value == 0);
925 if (can_deopt) {
926 bool can_truncate = true;
927 for (int i = 0; i < instr->uses()->length(); i++) {
928 if (!instr->uses()->at(i)->CheckFlag(HValue::kTruncatingToInt32)) {
929 can_truncate = false;
930 break;
931 }
932 }
933 can_deopt = !can_truncate;
934 }
935
936 LInstruction* result =
937 DefineSameAsFirst(new LShiftI(op, left, right, can_deopt));
938 if (can_deopt) AssignEnvironment(result);
939 return result;
940 }
941
942
943 LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
944 HArithmeticBinaryOperation* instr) {
945 ASSERT(instr->representation().IsDouble());
946 ASSERT(instr->left()->representation().IsDouble());
947 ASSERT(instr->right()->representation().IsDouble());
948 LOperand* left = UseRegisterAtStart(instr->left());
949 LOperand* right = UseRegisterAtStart(instr->right());
950 LArithmeticD* result = new LArithmeticD(op, left, right);
951 return DefineSameAsFirst(result);
952 }
953
954
955 LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
956 HArithmeticBinaryOperation* instr) {
957 ASSERT(op == Token::ADD ||
958 op == Token::DIV ||
959 op == Token::MOD ||
960 op == Token::MUL ||
961 op == Token::SUB);
962 HValue* left = instr->left();
963 HValue* right = instr->right();
964 ASSERT(left->representation().IsTagged());
965 ASSERT(right->representation().IsTagged());
966 LOperand* left_operand = UseFixed(left, r1);
967 LOperand* right_operand = UseFixed(right, r0);
968 LInstruction* result = new LArithmeticT(op, left_operand, right_operand);
969 return MarkAsCall(DefineFixed(result, r0), instr);
970 }
971
972 void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
973 ASSERT(is_building());
974 current_block_ = block;
975 next_block_ = next_block;
976 if (block->IsStartBlock()) {
977 block->UpdateEnvironment(graph_->start_environment());
978 argument_count_ = 0;
979 } else if (block->predecessors()->length() == 1) {
980 // We have a single predecessor => copy environment and outgoing
981 // argument count from the predecessor.
982 ASSERT(block->phis()->length() == 0);
983 HBasicBlock* pred = block->predecessors()->at(0);
984 HEnvironment* last_environment = pred->last_environment();
985 ASSERT(last_environment != NULL);
986 // Only copy the environment, if it is later used again.
987 if (pred->end()->SecondSuccessor() == NULL) {
988 ASSERT(pred->end()->FirstSuccessor() == block);
989 } else {
990 if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
991 pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
992 last_environment = last_environment->Copy();
993 }
994 }
995 block->UpdateEnvironment(last_environment);
996 ASSERT(pred->argument_count() >= 0);
997 argument_count_ = pred->argument_count();
998 } else {
999 // We are at a state join => process phis.
1000 HBasicBlock* pred = block->predecessors()->at(0);
1001 // No need to copy the environment, it cannot be used later.
1002 HEnvironment* last_environment = pred->last_environment();
1003 for (int i = 0; i < block->phis()->length(); ++i) {
1004 HPhi* phi = block->phis()->at(i);
1005 last_environment->SetValueAt(phi->merged_index(), phi);
1006 }
1007 for (int i = 0; i < block->deleted_phis()->length(); ++i) {
1008 last_environment->SetValueAt(block->deleted_phis()->at(i),
1009 graph_->GetConstantUndefined());
1010 }
1011 block->UpdateEnvironment(last_environment);
1012 // Pick up the outgoing argument count of one of the predecessors.
1013 argument_count_ = pred->argument_count();
1014 }
1015 HInstruction* current = block->first();
1016 int start = chunk_->instructions()->length();
1017 while (current != NULL && !is_aborted()) {
1018 if (FLAG_trace_environment) {
1019 PrintF("Process instruction %d\n", current->id());
1020 }
1021 // Code for constants in registers is generated lazily.
1022 if (!current->EmitAtUses()) {
1023 VisitInstruction(current);
1024 }
1025 current = current->next();
1026 }
1027 int end = chunk_->instructions()->length() - 1;
1028 if (end >= start) {
1029 block->set_first_instruction_index(start);
1030 block->set_last_instruction_index(end);
1031 }
1032 block->set_argument_count(argument_count_);
1033 next_block_ = NULL;
1034 current_block_ = NULL;
1035 }
1036
1037
1038 void LChunkBuilder::VisitInstruction(HInstruction* current) {
1039 HInstruction* old_current = current_instruction_;
1040 current_instruction_ = current;
1041 allocator_->BeginInstruction();
1042 if (current->has_position()) position_ = current->position();
1043 LInstruction* instr = current->CompileToLithium(this);
1044
1045 if (instr != NULL) {
1046 if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
1047 instr = AssignPointerMap(instr);
1048 }
1049 if (FLAG_stress_environments && !instr->HasEnvironment()) {
1050 instr = AssignEnvironment(instr);
1051 }
1052 if (current->IsBranch()) {
1053 instr->set_hydrogen_value(HBranch::cast(current)->value());
1054 } else {
1055 instr->set_hydrogen_value(current);
1056 }
1057
1058 int index = chunk_->AddInstruction(instr, current_block_);
1059 allocator_->SummarizeInstruction(index);
1060 } else {
1061 // This instruction should be omitted.
1062 allocator_->OmitInstruction();
1063 }
1064 current_instruction_ = old_current;
1065 }
1066
1067
1068 void LEnvironment::WriteTranslation(LCodeGen* cgen,
1069 Translation* translation) const {
1070 if (this == NULL) return;
1071
1072 // The translation includes one command per value in the environment.
1073 int translation_size = values()->length();
1074 // The output frame height does not include the parameters.
1075 int height = translation_size - parameter_count();
1076
1077 outer()->WriteTranslation(cgen, translation);
1078 int closure_id = cgen->DefineDeoptimizationLiteral(closure());
1079 translation->BeginFrame(ast_id(), closure_id, height);
1080 for (int i = 0; i < translation_size; ++i) {
1081 LOperand* value = values()->at(i);
1082 // spilled_registers_ and spilled_double_registers_ are either
1083 // both NULL or both set.
1084 if (spilled_registers_ != NULL && value != NULL) {
1085 if (value->IsRegister() &&
1086 spilled_registers_[value->index()] != NULL) {
1087 translation->MarkDuplicate();
1088 cgen->AddToTranslation(translation,
1089 spilled_registers_[value->index()],
1090 HasTaggedValueAt(i));
1091 } else if (value->IsDoubleRegister() &&
1092 spilled_double_registers_[value->index()] != NULL) {
1093 translation->MarkDuplicate();
1094 cgen->AddToTranslation(translation,
1095 spilled_double_registers_[value->index()],
1096 false);
1097 }
1098 }
1099
1100 cgen->AddToTranslation(translation, value, HasTaggedValueAt(i));
1101 }
1102 }
1103
1104
1105 void LEnvironment::PrintTo(StringStream* stream) const {
1106 stream->Add("[id=%d|", ast_id());
1107 stream->Add("[parameters=%d|", parameter_count());
1108 stream->Add("[arguments_stack_height=%d|", arguments_stack_height());
1109 for (int i = 0; i < values_.length(); ++i) {
1110 if (i != 0) stream->Add(";");
1111 if (values_[i] == NULL) {
1112 stream->Add("[hole]");
1113 } else {
1114 values_[i]->PrintTo(stream);
1115 }
1116 }
1117 stream->Add("]");
1118 }
1119
1120
1121 LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) {
1122 if (hydrogen_env == NULL) return NULL;
1123
1124 LEnvironment* outer = CreateEnvironment(hydrogen_env->outer());
1125 int ast_id = hydrogen_env->ast_id();
1126 ASSERT(ast_id != AstNode::kNoNumber);
1127 int value_count = hydrogen_env->values()->length();
1128 LEnvironment* result = new LEnvironment(hydrogen_env->closure(),
1129 ast_id,
1130 hydrogen_env->parameter_count(),
1131 argument_count_,
1132 value_count,
1133 outer);
1134 int argument_index = 0;
1135 for (int i = 0; i < value_count; ++i) {
1136 HValue* value = hydrogen_env->values()->at(i);
1137 LOperand* op = NULL;
1138 if (value->IsArgumentsObject()) {
1139 op = NULL;
1140 } else if (value->IsPushArgument()) {
1141 op = new LArgument(argument_index++);
1142 } else {
1143 op = UseOrConstant(value);
1144 if (op->IsUnallocated()) {
1145 LUnallocated* unalloc = LUnallocated::cast(op);
1146 unalloc->set_policy(LUnallocated::ANY);
1147 }
1148 }
1149 result->AddValue(op, value->representation());
1150 }
1151
1152 return result;
1153 }
1154
1155
1156 LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
1157 LInstruction* result = new LGoto(instr->FirstSuccessor()->block_id(),
1158 instr->include_stack_check());
1159 if (instr->include_stack_check()) result = AssignPointerMap(result);
1160 return result;
1161 }
1162
1163
1164 LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
1165 HValue* v = instr->value();
1166 HBasicBlock* first = instr->FirstSuccessor();
1167 HBasicBlock* second = instr->SecondSuccessor();
1168 ASSERT(first != NULL && second != NULL);
1169 int first_id = first->block_id();
1170 int second_id = second->block_id();
1171
1172 if (v->EmitAtUses()) {
1173 if (v->IsClassOfTest()) {
1174 HClassOfTest* compare = HClassOfTest::cast(v);
1175 ASSERT(compare->value()->representation().IsTagged());
1176
1177 return new LClassOfTestAndBranch(UseTempRegister(compare->value()),
1178 TempRegister(),
1179 TempRegister(),
1180 first_id,
1181 second_id);
1182 } else if (v->IsCompare()) {
1183 HCompare* compare = HCompare::cast(v);
1184 Token::Value op = compare->token();
1185 HValue* left = compare->left();
1186 HValue* right = compare->right();
1187 if (left->representation().IsInteger32()) {
1188 ASSERT(right->representation().IsInteger32());
1189 return new LCmpIDAndBranch(op,
1190 UseRegisterAtStart(left),
1191 UseOrConstantAtStart(right),
1192 first_id,
1193 second_id,
1194 false);
1195 } else if (left->representation().IsDouble()) {
1196 ASSERT(right->representation().IsDouble());
1197 return new LCmpIDAndBranch(op,
1198 UseRegisterAtStart(left),
1199 UseRegisterAtStart(right),
1200 first_id,
1201 second_id,
1202 true);
1203 } else {
1204 ASSERT(left->representation().IsTagged());
1205 ASSERT(right->representation().IsTagged());
1206 bool reversed = op == Token::GT || op == Token::LTE;
1207 LOperand* left_operand = UseFixed(left, reversed ? r0 : r1);
1208 LOperand* right_operand = UseFixed(right, reversed ? r1 : r0);
1209 LInstruction* result = new LCmpTAndBranch(left_operand,
1210 right_operand,
1211 first_id,
1212 second_id);
1213 return MarkAsCall(result, instr);
1214 }
1215 } else if (v->IsIsSmi()) {
1216 HIsSmi* compare = HIsSmi::cast(v);
1217 ASSERT(compare->value()->representation().IsTagged());
1218
1219 return new LIsSmiAndBranch(Use(compare->value()),
1220 first_id,
1221 second_id);
1222 } else if (v->IsHasInstanceType()) {
1223 HHasInstanceType* compare = HHasInstanceType::cast(v);
1224 ASSERT(compare->value()->representation().IsTagged());
1225
1226 return new LHasInstanceTypeAndBranch(UseRegisterAtStart(compare->value()),
1227 TempRegister(),
1228 first_id,
1229 second_id);
1230 } else if (v->IsHasCachedArrayIndex()) {
1231 HHasCachedArrayIndex* compare = HHasCachedArrayIndex::cast(v);
1232 ASSERT(compare->value()->representation().IsTagged());
1233
1234 return new LHasCachedArrayIndexAndBranch(
1235 UseRegisterAtStart(compare->value()), first_id, second_id);
1236 } else if (v->IsIsNull()) {
1237 HIsNull* compare = HIsNull::cast(v);
1238 ASSERT(compare->value()->representation().IsTagged());
1239
1240 // We only need a temp register for non-strict compare.
1241 LOperand* temp = compare->is_strict() ? NULL : TempRegister();
1242 return new LIsNullAndBranch(UseRegisterAtStart(compare->value()),
1243 compare->is_strict(),
1244 temp,
1245 first_id,
1246 second_id);
1247 } else if (v->IsCompareJSObjectEq()) {
1248 HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
1249 return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()),
1250 UseRegisterAtStart(compare->right()),
1251 first_id,
1252 second_id);
1253 } else if (v->IsInstanceOf()) {
1254 HInstanceOf* instance_of = HInstanceOf::cast(v);
1255 LInstruction* result =
1256 new LInstanceOfAndBranch(Use(instance_of->left()),
1257 Use(instance_of->right()),
1258 first_id,
1259 second_id);
1260 return MarkAsCall(result, instr);
1261 } else if (v->IsTypeofIs()) {
1262 HTypeofIs* typeof_is = HTypeofIs::cast(v);
1263 return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()),
1264 first_id,
1265 second_id);
1266 } else {
1267 if (v->IsConstant()) {
1268 if (HConstant::cast(v)->handle()->IsTrue()) {
1269 return new LGoto(first_id);
1270 } else if (HConstant::cast(v)->handle()->IsFalse()) {
1271 return new LGoto(second_id);
1272 }
1273 }
1274 Abort("Undefined compare before branch");
1275 return NULL;
1276 }
1277 }
1278 return new LBranch(UseRegisterAtStart(v), first_id, second_id);
1279 }
1280
1281
1282 LInstruction* LChunkBuilder::DoCompareMapAndBranch(
1283 HCompareMapAndBranch* instr) {
1284 ASSERT(instr->value()->representation().IsTagged());
1285 LOperand* value = UseRegisterAtStart(instr->value());
1286 HBasicBlock* first = instr->FirstSuccessor();
1287 HBasicBlock* second = instr->SecondSuccessor();
1288 return new LCmpMapAndBranch(value,
1289 instr->map(),
1290 first->block_id(),
1291 second->block_id());
1292 }
1293
1294
1295 LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) {
1296 return DefineAsRegister(new LArgumentsLength(Use(length->value())));
1297 }
1298
1299
1300 LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
1301 return DefineAsRegister(new LArgumentsElements);
1302 }
1303
1304
1305 LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
1306 LInstruction* result =
1307 new LInstanceOf(Use(instr->left()), Use(instr->right()));
1308 return MarkAsCall(DefineFixed(result, r0), instr);
1309 }
1310
1311
1312 LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
1313 LOperand* function = UseFixed(instr->function(), r1);
1314 LOperand* receiver = UseFixed(instr->receiver(), r0);
1315 LOperand* length = UseRegisterAtStart(instr->length());
1316 LOperand* elements = UseRegisterAtStart(instr->elements());
1317 LInstruction* result = new LApplyArguments(function,
1318 receiver,
1319 length,
1320 elements);
1321 return MarkAsCall(DefineFixed(result, r0), instr, CAN_DEOPTIMIZE_EAGERLY);
1322 }
1323
1324
1325 LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
1326 ++argument_count_;
1327 LOperand* argument = Use(instr->argument());
1328 return new LPushArgument(argument);
1329 }
1330
1331
1332 LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
1333 return DefineAsRegister(new LGlobalObject);
1334 }
1335
1336
1337 LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
1338 return DefineAsRegister(new LGlobalReceiver);
1339 }
1340
1341
1342 LInstruction* LChunkBuilder::DoCallConstantFunction(
1343 HCallConstantFunction* instr) {
1344 argument_count_ -= instr->argument_count();
1345 return MarkAsCall(DefineFixed(new LCallConstantFunction, r0), instr);
1346 }
1347
1348
1349 LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
1350 MathFunctionId op = instr->op();
1351 LOperand* input = UseRegisterAtStart(instr->value());
1352 LInstruction* result = new LUnaryMathOperation(input);
1353 switch (op) {
1354 case kMathAbs:
1355 return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1356 case kMathFloor:
1357 return AssignEnvironment(DefineAsRegister(result));
1358 case kMathSqrt:
1359 return DefineSameAsFirst(result);
1360 default:
1361 UNREACHABLE();
1362 return NULL;
1363 }
1364 }
1365
1366
1367 LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
1368 ASSERT(instr->key()->representation().IsTagged());
1369 argument_count_ -= instr->argument_count();
1370 UseFixed(instr->key(), r2);
1371 return MarkAsCall(DefineFixed(new LCallKeyed, r0), instr);
1372 }
1373
1374
1375 LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
1376 argument_count_ -= instr->argument_count();
1377 return MarkAsCall(DefineFixed(new LCallNamed, r0), instr);
1378 }
1379
1380
1381 LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
1382 argument_count_ -= instr->argument_count();
1383 return MarkAsCall(DefineFixed(new LCallGlobal, r0), instr);
1384 }
1385
1386
1387 LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
1388 argument_count_ -= instr->argument_count();
1389 return MarkAsCall(DefineFixed(new LCallKnownGlobal, r0), instr);
1390 }
1391
1392
1393 LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
1394 LOperand* constructor = UseFixed(instr->constructor(), r1);
1395 argument_count_ -= instr->argument_count();
1396 LInstruction* result = new LCallNew(constructor);
1397 return MarkAsCall(DefineFixed(result, r0), instr);
1398 }
1399
1400
1401 LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
1402 argument_count_ -= instr->argument_count();
1403 return MarkAsCall(DefineFixed(new LCallFunction, r0), instr);
1404 }
1405
1406
1407 LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1408 argument_count_ -= instr->argument_count();
1409 return MarkAsCall(DefineFixed(new LCallRuntime, r0), instr);
1410 }
1411
1412
1413 LInstruction* LChunkBuilder::DoShr(HShr* instr) {
1414 return DoShift(Token::SHR, instr);
1415 }
1416
1417
1418 LInstruction* LChunkBuilder::DoSar(HSar* instr) {
1419 return DoShift(Token::SAR, instr);
1420 }
1421
1422
1423 LInstruction* LChunkBuilder::DoShl(HShl* instr) {
1424 return DoShift(Token::SHL, instr);
1425 }
1426
1427
1428 LInstruction* LChunkBuilder::DoBitAnd(HBitAnd* instr) {
1429 return DoBit(Token::BIT_AND, instr);
1430 }
1431
1432
1433 LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
1434 ASSERT(instr->value()->representation().IsInteger32());
1435 ASSERT(instr->representation().IsInteger32());
1436 return DefineSameAsFirst(new LBitNotI(UseRegisterAtStart(instr->value())));
1437 }
1438
1439
1440 LInstruction* LChunkBuilder::DoBitOr(HBitOr* instr) {
1441 return DoBit(Token::BIT_OR, instr);
1442 }
1443
1444
1445 LInstruction* LChunkBuilder::DoBitXor(HBitXor* instr) {
1446 return DoBit(Token::BIT_XOR, instr);
1447 }
1448
1449
1450 LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1451 if (instr->representation().IsDouble()) {
1452 return DoArithmeticD(Token::DIV, instr);
1453 } else if (instr->representation().IsInteger32()) {
1454 // The temporary operand is necessary to ensure that right is not allocated
1455 // into edx.
1456 FixedTemp(r1);
1457 LOperand* value = UseFixed(instr->left(), r0);
1458 LOperand* divisor = UseRegister(instr->right());
1459 return AssignEnvironment(DefineFixed(new LDivI(value, divisor), r0));
1460 } else {
1461 return DoArithmeticT(Token::DIV, instr);
1462 }
1463 }
1464
1465
1466 LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1467 if (instr->representation().IsInteger32()) {
1468 ASSERT(instr->left()->representation().IsInteger32());
1469 ASSERT(instr->right()->representation().IsInteger32());
1470 // The temporary operand is necessary to ensure that right is not allocated
1471 // into edx.
1472 FixedTemp(r1);
1473 LOperand* value = UseFixed(instr->left(), r0);
1474 LOperand* divisor = UseRegister(instr->right());
1475 LInstruction* result = DefineFixed(new LModI(value, divisor), r1);
1476 if (instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
1477 instr->CheckFlag(HValue::kCanBeDivByZero)) {
1478 result = AssignEnvironment(result);
1479 }
1480 return result;
1481 } else if (instr->representation().IsTagged()) {
1482 return DoArithmeticT(Token::MOD, instr);
1483 } else {
1484 ASSERT(instr->representation().IsDouble());
1485 // We call a C function for double modulo. It can't trigger a GC.
1486 // We need to use fixed result register for the call.
1487 // TODO(fschneider): Allow any register as input registers.
1488 LOperand* left = UseFixedDouble(instr->left(), d1);
1489 LOperand* right = UseFixedDouble(instr->right(), d2);
1490 LArithmeticD* result = new LArithmeticD(Token::MOD, left, right);
1491 return MarkAsCall(DefineFixedDouble(result, d1), instr);
1492 }
1493 }
1494
1495
1496 LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1497 if (instr->representation().IsInteger32()) {
1498 ASSERT(instr->left()->representation().IsInteger32());
1499 ASSERT(instr->right()->representation().IsInteger32());
1500 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1501 LOperand* right = UseOrConstant(instr->MostConstantOperand());
1502 LOperand* temp = NULL;
1503 if (instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1504 temp = TempRegister();
1505 }
1506 LMulI* mul = new LMulI(left, right, temp);
1507 return AssignEnvironment(DefineSameAsFirst(mul));
1508 } else if (instr->representation().IsDouble()) {
1509 return DoArithmeticD(Token::MUL, instr);
1510 } else {
1511 return DoArithmeticT(Token::MUL, instr);
1512 }
1513 }
1514
1515
1516 LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1517 if (instr->representation().IsInteger32()) {
1518 ASSERT(instr->left()->representation().IsInteger32());
1519 ASSERT(instr->right()->representation().IsInteger32());
1520 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1521 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
1522 LSubI* sub = new LSubI(left, right);
1523 LInstruction* result = DefineSameAsFirst(sub);
1524 if (instr->CheckFlag(HValue::kCanOverflow)) {
1525 result = AssignEnvironment(result);
1526 }
1527 return result;
1528 } else if (instr->representation().IsDouble()) {
1529 return DoArithmeticD(Token::SUB, instr);
1530 } else {
1531 return DoArithmeticT(Token::SUB, instr);
1532 }
1533 }
1534
1535
1536 LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1537 if (instr->representation().IsInteger32()) {
1538 ASSERT(instr->left()->representation().IsInteger32());
1539 ASSERT(instr->right()->representation().IsInteger32());
1540 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1541 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
1542 LAddI* add = new LAddI(left, right);
1543 LInstruction* result = DefineSameAsFirst(add);
1544 if (instr->CheckFlag(HValue::kCanOverflow)) {
1545 result = AssignEnvironment(result);
1546 }
1547 return result;
1548 } else if (instr->representation().IsDouble()) {
1549 return DoArithmeticD(Token::ADD, instr);
1550 } else {
1551 ASSERT(instr->representation().IsTagged());
1552 return DoArithmeticT(Token::ADD, instr);
1553 }
1554 }
1555
1556
1557 LInstruction* LChunkBuilder::DoCompare(HCompare* instr) {
1558 Token::Value op = instr->token();
1559 if (instr->left()->representation().IsInteger32()) {
1560 ASSERT(instr->right()->representation().IsInteger32());
1561 LOperand* left = UseRegisterAtStart(instr->left());
1562 LOperand* right = UseOrConstantAtStart(instr->right());
1563 return DefineAsRegister(new LCmpID(op, left, right, false));
1564 } else if (instr->left()->representation().IsDouble()) {
1565 ASSERT(instr->right()->representation().IsDouble());
1566 LOperand* left = UseRegisterAtStart(instr->left());
1567 LOperand* right = UseRegisterAtStart(instr->right());
1568 return DefineAsRegister(new LCmpID(op, left, right, true));
1569 } else {
1570 bool reversed = (op == Token::GT || op == Token::LTE);
1571 LOperand* left = UseFixed(instr->left(), reversed ? r0 : r1);
1572 LOperand* right = UseFixed(instr->right(), reversed ? r1 : r0);
1573 LInstruction* result = new LCmpT(left, right);
1574 return MarkAsCall(DefineFixed(result, r0), instr);
1575 }
1576 }
1577
1578
1579 LInstruction* LChunkBuilder::DoCompareJSObjectEq(
1580 HCompareJSObjectEq* instr) {
1581 LOperand* left = UseRegisterAtStart(instr->left());
1582 LOperand* right = UseRegisterAtStart(instr->right());
1583 LInstruction* result = new LCmpJSObjectEq(left, right);
1584 return DefineAsRegister(result);
1585 }
1586
1587
1588 LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) {
1589 ASSERT(instr->value()->representation().IsTagged());
1590 LOperand* value = UseRegisterAtStart(instr->value());
1591
1592 return DefineAsRegister(new LIsNull(value,
1593 instr->is_strict()));
1594 }
1595
1596
1597 LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) {
1598 ASSERT(instr->value()->representation().IsTagged());
1599 LOperand* value = UseAtStart(instr->value());
1600
1601 return DefineAsRegister(new LIsSmi(value));
1602 }
1603
1604
1605 LInstruction* LChunkBuilder::DoHasInstanceType(HHasInstanceType* instr) {
1606 ASSERT(instr->value()->representation().IsTagged());
1607 LOperand* value = UseRegisterAtStart(instr->value());
1608
1609 return DefineAsRegister(new LHasInstanceType(value));
1610 }
1611
1612
1613 LInstruction* LChunkBuilder::DoHasCachedArrayIndex(
1614 HHasCachedArrayIndex* instr) {
1615 ASSERT(instr->value()->representation().IsTagged());
1616 LOperand* value = UseRegister(instr->value());
1617
1618 return DefineAsRegister(new LHasCachedArrayIndex(value));
1619 }
1620
1621
1622 LInstruction* LChunkBuilder::DoClassOfTest(HClassOfTest* instr) {
1623 ASSERT(instr->value()->representation().IsTagged());
1624 LOperand* value = UseTempRegister(instr->value());
1625
1626 return DefineSameAsFirst(new LClassOfTest(value, TempRegister()));
1627 }
1628
1629
1630 LInstruction* LChunkBuilder::DoArrayLength(HArrayLength* instr) {
1631 LOperand* array = NULL;
1632 LOperand* temporary = NULL;
1633
1634 if (instr->value()->IsLoadElements()) {
1635 array = UseRegisterAtStart(instr->value());
1636 } else {
1637 array = UseRegister(instr->value());
1638 temporary = TempRegister();
1639 }
1640
1641 LInstruction* result = new LArrayLength(array, temporary);
1642 return AssignEnvironment(DefineAsRegister(result));
1643 }
1644
1645
1646 LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
1647 LOperand* object = UseRegister(instr->value());
1648 LInstruction* result = new LValueOf(object, TempRegister());
1649 return AssignEnvironment(DefineSameAsFirst(result));
1650 }
1651
1652
1653 LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1654 return AssignEnvironment(new LBoundsCheck(UseRegisterAtStart(instr->index()),
1655 Use(instr->length())));
1656 }
1657
1658
1659 LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
1660 LOperand* value = UseFixed(instr->value(), r0);
1661 return MarkAsCall(new LThrow(value), instr);
1662 }
1663
1664
1665 LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1666 Representation from = instr->from();
1667 Representation to = instr->to();
1668 if (from.IsTagged()) {
1669 if (to.IsDouble()) {
1670 LOperand* value = UseRegister(instr->value());
1671 LInstruction* res = new LNumberUntagD(value);
1672 return AssignEnvironment(DefineAsRegister(res));
1673 } else {
1674 ASSERT(to.IsInteger32());
1675 LOperand* value = UseRegister(instr->value());
1676 bool needs_check = !instr->value()->type().IsSmi();
1677 LInstruction* res = NULL;
1678 if (needs_check) {
1679 res = DefineSameAsFirst(new LTaggedToI(value, FixedTemp(d1)));
1680 } else {
1681 res = DefineSameAsFirst(new LSmiUntag(value, needs_check));
1682 }
1683 if (needs_check) {
1684 res = AssignEnvironment(res);
1685 }
1686 return res;
1687 }
1688 } else if (from.IsDouble()) {
1689 if (to.IsTagged()) {
1690 LOperand* value = UseRegister(instr->value());
1691 LOperand* temp = TempRegister();
1692
1693 // Make sure that temp and result_temp are different registers.
1694 LUnallocated* result_temp = TempRegister();
1695 LInstruction* result = new LNumberTagD(value, temp);
1696 Define(result, result_temp);
1697 return AssignPointerMap(result);
1698 } else {
1699 ASSERT(to.IsInteger32());
1700 LOperand* value = UseRegister(instr->value());
1701 LInstruction* res = new LDoubleToI(value);
1702 return AssignEnvironment(DefineAsRegister(res));
1703 }
1704 } else if (from.IsInteger32()) {
1705 if (to.IsTagged()) {
1706 HValue* val = instr->value();
1707 LOperand* value = UseRegister(val);
1708 if (val->HasRange() && val->range()->IsInSmiRange()) {
1709 return DefineSameAsFirst(new LSmiTag(value));
1710 } else {
1711 LInstruction* result = new LNumberTagI(value);
1712 return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1713 }
1714 } else {
1715 ASSERT(to.IsDouble());
1716 LOperand* value = Use(instr->value());
1717 return DefineAsRegister(new LInteger32ToDouble(value));
1718 }
1719 }
1720 UNREACHABLE();
1721 return NULL;
1722 }
1723
1724
1725 LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
1726 LOperand* value = UseRegisterAtStart(instr->value());
1727 return AssignEnvironment(new LCheckSmi(value, eq));
1728 }
1729
1730
1731 LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
1732 LOperand* value = UseRegisterAtStart(instr->value());
1733 LOperand* temp = TempRegister();
1734 LInstruction* result = new LCheckInstanceType(value, temp);
1735 return AssignEnvironment(result);
1736 }
1737
1738
1739 LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
1740 LOperand* temp = TempRegister();
1741 LInstruction* result =
1742 new LCheckPrototypeMaps(temp,
1743 instr->holder(),
1744 instr->receiver_map());
1745 return AssignEnvironment(result);
1746 }
1747
1748
1749 LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
1750 LOperand* value = UseRegisterAtStart(instr->value());
1751 return AssignEnvironment(new LCheckSmi(value, ne));
1752 }
1753
1754
1755 LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
1756 LOperand* value = UseRegisterAtStart(instr->value());
1757 return AssignEnvironment(new LCheckFunction(value));
1758 }
1759
1760
1761 LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) {
1762 LOperand* value = UseRegisterAtStart(instr->value());
1763 LInstruction* result = new LCheckMap(value);
1764 return AssignEnvironment(result);
1765 }
1766
1767
1768 LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
1769 return new LReturn(UseFixed(instr->value(), r0));
1770 }
1771
1772
1773 LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
1774 Representation r = instr->representation();
1775 if (r.IsInteger32()) {
1776 int32_t value = instr->Integer32Value();
1777 return DefineAsRegister(new LConstantI(value));
1778 } else if (r.IsDouble()) {
1779 double value = instr->DoubleValue();
1780 return DefineAsRegister(new LConstantD(value));
1781 } else if (r.IsTagged()) {
1782 return DefineAsRegister(new LConstantT(instr->handle()));
1783 } else {
1784 Abort("unsupported constant of type double");
1785 return NULL;
1786 }
1787 }
1788
1789
1790 LInstruction* LChunkBuilder::DoLoadGlobal(HLoadGlobal* instr) {
1791 LInstruction* result = new LLoadGlobal();
1792 return instr->check_hole_value()
1793 ? AssignEnvironment(DefineAsRegister(result))
1794 : DefineAsRegister(result);
1795 }
1796
1797
1798 LInstruction* LChunkBuilder::DoStoreGlobal(HStoreGlobal* instr) {
1799 return new LStoreGlobal(UseRegisterAtStart(instr->value()));
1800 }
1801
1802
1803 LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
1804 return DefineAsRegister(
1805 new LLoadNamedField(UseRegisterAtStart(instr->object())));
1806 }
1807
1808
1809 LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
1810 LOperand* object = UseFixed(instr->object(), r0);
1811 LInstruction* result = DefineFixed(new LLoadNamedGeneric(object), r0);
1812 return MarkAsCall(result, instr);
1813 }
1814
1815
1816 LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
1817 LOperand* input = UseRegisterAtStart(instr->value());
1818 return DefineSameAsFirst(new LLoadElements(input));
1819 }
1820
1821
1822 LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
1823 HLoadKeyedFastElement* instr) {
1824 Representation r = instr->representation();
1825 LOperand* obj = UseRegisterAtStart(instr->object());
1826 ASSERT(instr->key()->representation().IsInteger32());
1827 LOperand* key = UseRegisterAtStart(instr->key());
1828 LOperand* load_result = NULL;
1829 // Double needs an extra temp, because the result is converted from heap
1830 // number to a double register.
1831 if (r.IsDouble()) load_result = TempRegister();
1832 LInstruction* result = new LLoadKeyedFastElement(obj,
1833 key,
1834 load_result);
1835 if (r.IsDouble()) {
1836 result = DefineAsRegister(result);
1837 } else {
1838 result = DefineSameAsFirst(result);
1839 }
1840 return AssignEnvironment(result);
1841 }
1842
1843
1844 LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
1845 LOperand* object = UseFixed(instr->object(), r1);
1846 LOperand* key = UseFixed(instr->key(), r0);
1847
1848 LInstruction* result =
1849 DefineFixed(new LLoadKeyedGeneric(object, key), r0);
1850 return MarkAsCall(result, instr);
1851 }
1852
1853
1854 LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
1855 HStoreKeyedFastElement* instr) {
1856 bool needs_write_barrier = instr->NeedsWriteBarrier();
1857 ASSERT(instr->value()->representation().IsTagged());
1858 ASSERT(instr->object()->representation().IsTagged());
1859 ASSERT(instr->key()->representation().IsInteger32());
1860
1861 LOperand* obj = UseTempRegister(instr->object());
1862 LOperand* val = needs_write_barrier
1863 ? UseTempRegister(instr->value())
1864 : UseRegisterAtStart(instr->value());
1865 LOperand* key = needs_write_barrier
1866 ? UseTempRegister(instr->key())
1867 : UseRegisterOrConstantAtStart(instr->key());
1868
1869 return AssignEnvironment(new LStoreKeyedFastElement(obj, key, val));
1870 }
1871
1872
1873 LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
1874 LOperand* obj = UseFixed(instr->object(), r2);
1875 LOperand* key = UseFixed(instr->key(), r1);
1876 LOperand* val = UseFixed(instr->value(), r0);
1877
1878 ASSERT(instr->object()->representation().IsTagged());
1879 ASSERT(instr->key()->representation().IsTagged());
1880 ASSERT(instr->value()->representation().IsTagged());
1881
1882 return MarkAsCall(new LStoreKeyedGeneric(obj, key, val), instr);
1883 }
1884
1885
1886 LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
1887 bool needs_write_barrier = !instr->value()->type().IsSmi();
1888
1889 LOperand* obj = needs_write_barrier
1890 ? UseTempRegister(instr->object())
1891 : UseRegisterAtStart(instr->object());
1892
1893 LOperand* val = needs_write_barrier
1894 ? UseTempRegister(instr->value())
1895 : UseRegister(instr->value());
1896
1897 // We only need a scratch register if we have a write barrier or we
1898 // have a store into the properties array (not in-object-property).
1899 LOperand* temp = (!instr->is_in_object() || needs_write_barrier)
1900 ? TempRegister() : NULL;
1901
1902 return new LStoreNamedField(obj,
1903 instr->name(),
1904 val,
1905 instr->is_in_object(),
1906 instr->offset(),
1907 temp,
1908 needs_write_barrier,
1909 instr->transition());
1910 }
1911
1912
1913 LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
1914 LOperand* obj = UseFixed(instr->object(), r1);
1915 LOperand* val = UseFixed(instr->value(), r0);
1916
1917 LInstruction* result = new LStoreNamedGeneric(obj, instr->name(), val);
1918 return MarkAsCall(result, instr);
1919 }
1920
1921
1922 LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
1923 return MarkAsCall(DefineFixed(new LArrayLiteral, r0), instr);
1924 }
1925
1926
1927 LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) {
1928 return MarkAsCall(DefineFixed(new LObjectLiteral, r0), instr);
1929 }
1930
1931
1932 LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
1933 return MarkAsCall(DefineFixed(new LRegExpLiteral, r0), instr);
1934 }
1935
1936
1937 LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
1938 return MarkAsCall(DefineFixed(new LFunctionLiteral, r0), instr);
1939 }
1940
1941
1942 LInstruction* LChunkBuilder::DoDeleteProperty(HDeleteProperty* instr) {
1943 LInstruction* result = new LDeleteProperty(Use(instr->object()),
1944 UseOrConstant(instr->key()));
1945 return MarkAsCall(DefineFixed(result, r0), instr);
1946 }
1947
1948
1949 LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
1950 allocator_->MarkAsOsrEntry();
1951 current_block_->last_environment()->set_ast_id(instr->ast_id());
1952 return AssignEnvironment(new LOsrEntry);
1953 }
1954
1955
1956 LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
1957 int spill_index = chunk()->GetParameterStackSlot(instr->index());
1958 return DefineAsSpilled(new LParameter, spill_index);
1959 }
1960
1961
1962 LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
1963 int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width.
1964 return DefineAsSpilled(new LUnknownOSRValue, spill_index);
1965 }
1966
1967
1968 LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
1969 argument_count_ -= instr->argument_count();
1970 return MarkAsCall(DefineFixed(new LCallStub, r0), instr);
1971 }
1972
1973
1974 LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
1975 // There are no real uses of the arguments object (we bail out in all other
1976 // cases).
1977 return NULL;
1978 }
1979
1980
1981 LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
1982 LOperand* arguments = UseRegister(instr->arguments());
1983 LOperand* length = UseTempRegister(instr->length());
1984 LOperand* index = Use(instr->index());
1985 LInstruction* result = new LAccessArgumentsAt(arguments, length, index);
1986 return DefineAsRegister(AssignEnvironment(result));
1987 }
1988
1989
1990 LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
1991 LInstruction* result = new LTypeof(Use(instr->value()));
1992 return MarkAsCall(DefineFixed(result, r0), instr);
1993 }
1994
1995
1996 LInstruction* LChunkBuilder::DoTypeofIs(HTypeofIs* instr) {
1997 return DefineSameAsFirst(new LTypeofIs(UseRegister(instr->value())));
1998 }
1999
2000 LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2001 HEnvironment* env = current_block_->last_environment();
2002 ASSERT(env != NULL);
2003
2004 env->set_ast_id(instr->ast_id());
2005
2006 env->Drop(instr->pop_count());
2007 for (int i = 0; i < instr->values()->length(); ++i) {
2008 HValue* value = instr->values()->at(i);
2009 if (instr->HasAssignedIndexAt(i)) {
2010 env->Bind(instr->GetAssignedIndexAt(i), value);
2011 } else {
2012 env->Push(value);
2013 }
2014 }
2015
2016 if (FLAG_trace_environment) {
2017 PrintF("Reconstructed environment ast_id=%d, instr_id=%d\n",
2018 instr->ast_id(),
2019 instr->id());
2020 env->PrintToStd();
2021 }
2022 ASSERT(env->values()->length() == instr->environment_height());
2023
2024 // If there is an instruction pending deoptimization environment create a
2025 // lazy bailout instruction to capture the environment.
2026 if (pending_deoptimization_ast_id_ == instr->ast_id()) {
2027 LInstruction* result = new LLazyBailout;
2028 result = AssignEnvironment(result);
2029 instructions_pending_deoptimization_environment_->
2030 set_deoptimization_environment(result->environment());
2031 ClearInstructionPendingDeoptimizationEnvironment();
2032 return result;
2033 }
2034
2035 return NULL;
2036 }
2037
2038
2039 LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2040 return MarkAsCall(new LStackCheck, instr);
2041 }
2042
2043
2044 LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
2045 HEnvironment* outer = current_block_->last_environment();
2046 HConstant* undefined = graph()->GetConstantUndefined();
2047 HEnvironment* inner = outer->CopyForInlining(instr->closure(),
2048 instr->function(),
2049 false,
2050 undefined);
2051 current_block_->UpdateEnvironment(inner);
2052 chunk_->AddInlinedClosure(instr->closure());
2053 return NULL;
2054 }
2055
2056
2057 LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2058 HEnvironment* outer = current_block_->last_environment()->outer();
2059 current_block_->UpdateEnvironment(outer);
2060 return NULL;
2061 }
2062
2063
2064 void LPointerMap::RecordPointer(LOperand* op) {
2065 // Do not record arguments as pointers.
2066 if (op->IsStackSlot() && op->index() < 0) return;
2067 ASSERT(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
2068 pointer_operands_.Add(op);
2069 }
2070
2071
2072 void LPointerMap::PrintTo(StringStream* stream) const {
2073 stream->Add("{");
2074 for (int i = 0; i < pointer_operands_.length(); ++i) {
2075 if (i != 0) stream->Add(";");
2076 pointer_operands_[i]->PrintTo(stream);
2077 }
2078 stream->Add("} @%d", position());
2079 }
2080
2081 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/arm/lithium-arm.h ('k') | src/arm/lithium-codegen-arm.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698