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

Side by Side Diff: src/hydrogen.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/hydrogen.h ('k') | src/hydrogen-instructions.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 "hydrogen.h"
29
30 #include "codegen.h"
31 #include "data-flow.h"
32 #include "full-codegen.h"
33 #include "hashmap.h"
34 #include "lithium-allocator.h"
35 #include "parser.h"
36 #include "scopes.h"
37
38 #if V8_TARGET_ARCH_IA32
39 #include "ia32/lithium-codegen-ia32.h"
40 #elif V8_TARGET_ARCH_X64
41 #include "x64/lithium-codegen-x64.h"
42 #elif V8_TARGET_ARCH_ARM
43 #include "arm/lithium-codegen-arm.h"
44 #else
45 #error Unsupported target architecture.
46 #endif
47
48 namespace v8 {
49 namespace internal {
50
51 HBasicBlock::HBasicBlock(HGraph* graph)
52 : block_id_(graph->GetNextBlockID()),
53 graph_(graph),
54 phis_(4),
55 first_(NULL),
56 last_(NULL),
57 end_(NULL),
58 loop_information_(NULL),
59 predecessors_(2),
60 dominator_(NULL),
61 dominated_blocks_(4),
62 last_environment_(NULL),
63 argument_count_(-1),
64 first_instruction_index_(-1),
65 last_instruction_index_(-1),
66 deleted_phis_(4),
67 is_inline_return_target_(false),
68 inverted_(false),
69 deopt_predecessor_(NULL) {
70 }
71
72
73 void HBasicBlock::AttachLoopInformation() {
74 ASSERT(!IsLoopHeader());
75 loop_information_ = new HLoopInformation(this);
76 }
77
78
79 void HBasicBlock::DetachLoopInformation() {
80 ASSERT(IsLoopHeader());
81 loop_information_ = NULL;
82 }
83
84
85 void HBasicBlock::AddPhi(HPhi* phi) {
86 ASSERT(!IsStartBlock());
87 phis_.Add(phi);
88 phi->SetBlock(this);
89 }
90
91
92 void HBasicBlock::RemovePhi(HPhi* phi) {
93 ASSERT(phi->block() == this);
94 ASSERT(phis_.Contains(phi));
95 ASSERT(phi->HasNoUses());
96 phi->ClearOperands();
97 phis_.RemoveElement(phi);
98 phi->SetBlock(NULL);
99 }
100
101
102 void HBasicBlock::AddInstruction(HInstruction* instr) {
103 ASSERT(!IsStartBlock() || !IsFinished());
104 ASSERT(!instr->IsLinked());
105 ASSERT(!IsFinished());
106 if (first_ == NULL) {
107 HBlockEntry* entry = new HBlockEntry();
108 entry->InitializeAsFirst(this);
109 first_ = entry;
110 }
111 instr->InsertAfter(GetLastInstruction());
112 }
113
114
115 HInstruction* HBasicBlock::GetLastInstruction() {
116 if (end_ != NULL) return end_->previous();
117 if (first_ == NULL) return NULL;
118 if (last_ == NULL) last_ = first_;
119 while (last_->next() != NULL) last_ = last_->next();
120 return last_;
121 }
122
123
124 HSimulate* HBasicBlock::CreateSimulate(int id) {
125 ASSERT(HasEnvironment());
126 HEnvironment* environment = last_environment();
127 ASSERT(id == AstNode::kNoNumber ||
128 environment->closure()->shared()->VerifyBailoutId(id));
129
130 int push_count = environment->push_count();
131 int pop_count = environment->pop_count();
132
133 int length = environment->values()->length();
134 HSimulate* instr = new HSimulate(id, pop_count, length);
135 for (int i = push_count - 1; i >= 0; --i) {
136 instr->AddPushedValue(environment->ExpressionStackAt(i));
137 }
138 for (int i = 0; i < environment->assigned_variables()->length(); ++i) {
139 int index = environment->assigned_variables()->at(i);
140 instr->AddAssignedValue(index, environment->Lookup(index));
141 }
142 environment->ClearHistory();
143 return instr;
144 }
145
146
147 void HBasicBlock::Finish(HControlInstruction* end) {
148 ASSERT(!IsFinished());
149 AddInstruction(end);
150 end_ = end;
151 if (end->FirstSuccessor() != NULL) {
152 end->FirstSuccessor()->RegisterPredecessor(this);
153 if (end->SecondSuccessor() != NULL) {
154 end->SecondSuccessor()->RegisterPredecessor(this);
155 }
156 }
157 }
158
159
160 void HBasicBlock::Goto(HBasicBlock* block, bool include_stack_check) {
161 AddSimulate(AstNode::kNoNumber);
162 HGoto* instr = new HGoto(block);
163 instr->set_include_stack_check(include_stack_check);
164 Finish(instr);
165 }
166
167
168 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) {
169 ASSERT(!HasEnvironment());
170 ASSERT(first() == NULL);
171 UpdateEnvironment(env);
172 }
173
174
175 void HBasicBlock::SetJoinId(int id) {
176 int length = predecessors_.length();
177 ASSERT(length > 0);
178 for (int i = 0; i < length; i++) {
179 HBasicBlock* predecessor = predecessors_[i];
180 ASSERT(predecessor->end()->IsGoto());
181 HSimulate* simulate = HSimulate::cast(predecessor->GetLastInstruction());
182 // We only need to verify the ID once.
183 ASSERT(i != 0 ||
184 predecessor->last_environment()->closure()->shared()
185 ->VerifyBailoutId(id));
186 simulate->set_ast_id(id);
187 }
188 }
189
190
191 bool HBasicBlock::Dominates(HBasicBlock* other) const {
192 HBasicBlock* current = other->dominator();
193 while (current != NULL) {
194 if (current == this) return true;
195 current = current->dominator();
196 }
197 return false;
198 }
199
200
201 void HBasicBlock::PostProcessLoopHeader(IterationStatement* stmt) {
202 ASSERT(IsLoopHeader());
203
204 SetJoinId(stmt->EntryId());
205 if (predecessors()->length() == 1) {
206 // This is a degenerated loop.
207 DetachLoopInformation();
208 return;
209 }
210
211 // Only the first entry into the loop is from outside the loop. All other
212 // entries must be back edges.
213 for (int i = 1; i < predecessors()->length(); ++i) {
214 loop_information()->RegisterBackEdge(predecessors()->at(i));
215 }
216 }
217
218
219 void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) {
220 if (!predecessors_.is_empty()) {
221 // Only loop header blocks can have a predecessor added after
222 // instructions have been added to the block (they have phis for all
223 // values in the environment, these phis may be eliminated later).
224 ASSERT(IsLoopHeader() || first_ == NULL);
225 HEnvironment* incoming_env = pred->last_environment();
226 if (IsLoopHeader()) {
227 ASSERT(phis()->length() == incoming_env->values()->length());
228 for (int i = 0; i < phis_.length(); ++i) {
229 phis_[i]->AddInput(incoming_env->values()->at(i));
230 }
231 } else {
232 last_environment()->AddIncomingEdge(this, pred->last_environment());
233 }
234 } else if (!HasEnvironment() && !IsFinished()) {
235 ASSERT(!IsLoopHeader());
236 SetInitialEnvironment(pred->last_environment()->Copy());
237 }
238
239 predecessors_.Add(pred);
240 }
241
242
243 void HBasicBlock::AddDominatedBlock(HBasicBlock* block) {
244 ASSERT(!dominated_blocks_.Contains(block));
245 // Keep the list of dominated blocks sorted such that if there is two
246 // succeeding block in this list, the predecessor is before the successor.
247 int index = 0;
248 while (index < dominated_blocks_.length() &&
249 dominated_blocks_[index]->block_id() < block->block_id()) {
250 ++index;
251 }
252 dominated_blocks_.InsertAt(index, block);
253 }
254
255
256 void HBasicBlock::AssignCommonDominator(HBasicBlock* other) {
257 if (dominator_ == NULL) {
258 dominator_ = other;
259 other->AddDominatedBlock(this);
260 } else if (other->dominator() != NULL) {
261 HBasicBlock* first = dominator_;
262 HBasicBlock* second = other;
263
264 while (first != second) {
265 if (first->block_id() > second->block_id()) {
266 first = first->dominator();
267 } else {
268 second = second->dominator();
269 }
270 ASSERT(first != NULL && second != NULL);
271 }
272
273 if (dominator_ != first) {
274 ASSERT(dominator_->dominated_blocks_.Contains(this));
275 dominator_->dominated_blocks_.RemoveElement(this);
276 dominator_ = first;
277 first->AddDominatedBlock(this);
278 }
279 }
280 }
281
282
283 int HBasicBlock::PredecessorIndexOf(HBasicBlock* predecessor) const {
284 for (int i = 0; i < predecessors_.length(); ++i) {
285 if (predecessors_[i] == predecessor) return i;
286 }
287 UNREACHABLE();
288 return -1;
289 }
290
291
292 #ifdef DEBUG
293 void HBasicBlock::Verify() {
294 // Check that every block is finished.
295 ASSERT(IsFinished());
296 ASSERT(block_id() >= 0);
297
298 // Verify that all blocks targetting a branch target, have the same boolean
299 // value on top of their expression stack.
300 if (!cond().is_null()) {
301 ASSERT(predecessors()->length() > 0);
302 for (int i = 1; i < predecessors()->length(); i++) {
303 HBasicBlock* pred = predecessors()->at(i);
304 HValue* top = pred->last_environment()->Top();
305 ASSERT(top->IsConstant());
306 Object* a = *HConstant::cast(top)->handle();
307 Object* b = *cond();
308 ASSERT(a == b);
309 }
310 }
311 }
312 #endif
313
314
315 void HLoopInformation::RegisterBackEdge(HBasicBlock* block) {
316 this->back_edges_.Add(block);
317 AddBlock(block);
318 }
319
320
321 HBasicBlock* HLoopInformation::GetLastBackEdge() const {
322 int max_id = -1;
323 HBasicBlock* result = NULL;
324 for (int i = 0; i < back_edges_.length(); ++i) {
325 HBasicBlock* cur = back_edges_[i];
326 if (cur->block_id() > max_id) {
327 max_id = cur->block_id();
328 result = cur;
329 }
330 }
331 return result;
332 }
333
334
335 void HLoopInformation::AddBlock(HBasicBlock* block) {
336 if (block == loop_header()) return;
337 if (block->parent_loop_header() == loop_header()) return;
338 if (block->parent_loop_header() != NULL) {
339 AddBlock(block->parent_loop_header());
340 } else {
341 block->set_parent_loop_header(loop_header());
342 blocks_.Add(block);
343 for (int i = 0; i < block->predecessors()->length(); ++i) {
344 AddBlock(block->predecessors()->at(i));
345 }
346 }
347 }
348
349
350 #ifdef DEBUG
351
352 // Checks reachability of the blocks in this graph and stores a bit in
353 // the BitVector "reachable()" for every block that can be reached
354 // from the start block of the graph. If "dont_visit" is non-null, the given
355 // block is treated as if it would not be part of the graph. "visited_count()"
356 // returns the number of reachable blocks.
357 class ReachabilityAnalyzer BASE_EMBEDDED {
358 public:
359 ReachabilityAnalyzer(HBasicBlock* entry_block,
360 int block_count,
361 HBasicBlock* dont_visit)
362 : visited_count_(0),
363 stack_(16),
364 reachable_(block_count),
365 dont_visit_(dont_visit) {
366 PushBlock(entry_block);
367 Analyze();
368 }
369
370 int visited_count() const { return visited_count_; }
371 const BitVector* reachable() const { return &reachable_; }
372
373 private:
374 void PushBlock(HBasicBlock* block) {
375 if (block != NULL && block != dont_visit_ &&
376 !reachable_.Contains(block->block_id())) {
377 reachable_.Add(block->block_id());
378 stack_.Add(block);
379 visited_count_++;
380 }
381 }
382
383 void Analyze() {
384 while (!stack_.is_empty()) {
385 HControlInstruction* end = stack_.RemoveLast()->end();
386 PushBlock(end->FirstSuccessor());
387 PushBlock(end->SecondSuccessor());
388 }
389 }
390
391 int visited_count_;
392 ZoneList<HBasicBlock*> stack_;
393 BitVector reachable_;
394 HBasicBlock* dont_visit_;
395 };
396
397
398 void HGraph::Verify() const {
399 for (int i = 0; i < blocks_.length(); i++) {
400 HBasicBlock* block = blocks_.at(i);
401
402 block->Verify();
403
404 // Check that every block contains at least one node and that only the last
405 // node is a control instruction.
406 HInstruction* current = block->first();
407 ASSERT(current != NULL && current->IsBlockEntry());
408 while (current != NULL) {
409 ASSERT((current->next() == NULL) == current->IsControlInstruction());
410 ASSERT(current->block() == block);
411 current->Verify();
412 current = current->next();
413 }
414
415 // Check that successors are correctly set.
416 HBasicBlock* first = block->end()->FirstSuccessor();
417 HBasicBlock* second = block->end()->SecondSuccessor();
418 ASSERT(second == NULL || first != NULL);
419
420 // Check that the predecessor array is correct.
421 if (first != NULL) {
422 ASSERT(first->predecessors()->Contains(block));
423 if (second != NULL) {
424 ASSERT(second->predecessors()->Contains(block));
425 }
426 }
427
428 // Check that phis have correct arguments.
429 for (int j = 0; j < block->phis()->length(); j++) {
430 HPhi* phi = block->phis()->at(j);
431 phi->Verify();
432 }
433
434 // Check that all join blocks have predecessors that end with an
435 // unconditional goto and agree on their environment node id.
436 if (block->predecessors()->length() >= 2) {
437 int id = block->predecessors()->first()->last_environment()->ast_id();
438 for (int k = 0; k < block->predecessors()->length(); k++) {
439 HBasicBlock* predecessor = block->predecessors()->at(k);
440 ASSERT(predecessor->end()->IsGoto());
441 ASSERT(predecessor->last_environment()->ast_id() == id);
442 }
443 }
444 }
445
446 // Check special property of first block to have no predecessors.
447 ASSERT(blocks_.at(0)->predecessors()->is_empty());
448
449 // Check that the graph is fully connected.
450 ReachabilityAnalyzer analyzer(entry_block_, blocks_.length(), NULL);
451 ASSERT(analyzer.visited_count() == blocks_.length());
452
453 // Check that entry block dominator is NULL.
454 ASSERT(entry_block_->dominator() == NULL);
455
456 // Check dominators.
457 for (int i = 0; i < blocks_.length(); ++i) {
458 HBasicBlock* block = blocks_.at(i);
459 if (block->dominator() == NULL) {
460 // Only start block may have no dominator assigned to.
461 ASSERT(i == 0);
462 } else {
463 // Assert that block is unreachable if dominator must not be visited.
464 ReachabilityAnalyzer dominator_analyzer(entry_block_,
465 blocks_.length(),
466 block->dominator());
467 ASSERT(!dominator_analyzer.reachable()->Contains(block->block_id()));
468 }
469 }
470 }
471
472 #endif
473
474
475 HConstant* HGraph::GetConstant(SetOncePointer<HConstant>* pointer,
476 Object* value) {
477 if (!pointer->is_set()) {
478 HConstant* constant = new HConstant(Handle<Object>(value),
479 Representation::Tagged());
480 constant->InsertAfter(GetConstantUndefined());
481 pointer->set(constant);
482 }
483 return pointer->get();
484 }
485
486
487 HConstant* HGraph::GetConstant1() {
488 return GetConstant(&constant_1_, Smi::FromInt(1));
489 }
490
491
492 HConstant* HGraph::GetConstantMinus1() {
493 return GetConstant(&constant_minus1_, Smi::FromInt(-1));
494 }
495
496
497 HConstant* HGraph::GetConstantTrue() {
498 return GetConstant(&constant_true_, HEAP->true_value());
499 }
500
501
502 HConstant* HGraph::GetConstantFalse() {
503 return GetConstant(&constant_false_, HEAP->false_value());
504 }
505
506
507 void HSubgraph::AppendOptional(HSubgraph* graph,
508 bool on_true_branch,
509 HValue* boolean_value) {
510 ASSERT(HasExit() && graph->HasExit());
511 HBasicBlock* other_block = graph_->CreateBasicBlock();
512 HBasicBlock* join_block = graph_->CreateBasicBlock();
513
514 HBasicBlock* true_branch = other_block;
515 HBasicBlock* false_branch = graph->entry_block();
516 if (on_true_branch) {
517 true_branch = graph->entry_block();
518 false_branch = other_block;
519 }
520
521 exit_block_->Finish(new HBranch(true_branch, false_branch, boolean_value));
522 other_block->Goto(join_block);
523 graph->exit_block()->Goto(join_block);
524 exit_block_ = join_block;
525 }
526
527
528 void HSubgraph::AppendJoin(HSubgraph* then_graph,
529 HSubgraph* else_graph,
530 AstNode* node) {
531 if (then_graph->HasExit() && else_graph->HasExit()) {
532 // We need to merge, create new merge block.
533 HBasicBlock* join_block = graph_->CreateBasicBlock();
534 then_graph->exit_block()->Goto(join_block);
535 else_graph->exit_block()->Goto(join_block);
536 join_block->SetJoinId(node->id());
537 exit_block_ = join_block;
538 } else if (then_graph->HasExit()) {
539 exit_block_ = then_graph->exit_block_;
540 } else if (else_graph->HasExit()) {
541 exit_block_ = else_graph->exit_block_;
542 } else {
543 exit_block_ = NULL;
544 }
545 }
546
547
548 void HSubgraph::ResolveContinue(IterationStatement* statement) {
549 HBasicBlock* continue_block = BundleContinue(statement);
550 if (continue_block != NULL) {
551 exit_block_ = JoinBlocks(exit_block(),
552 continue_block,
553 statement->ContinueId());
554 }
555 }
556
557
558 HBasicBlock* HSubgraph::BundleBreak(BreakableStatement* statement) {
559 return BundleBreakContinue(statement, false, statement->ExitId());
560 }
561
562
563 HBasicBlock* HSubgraph::BundleContinue(IterationStatement* statement) {
564 return BundleBreakContinue(statement, true, statement->ContinueId());
565 }
566
567
568 HBasicBlock* HSubgraph::BundleBreakContinue(BreakableStatement* statement,
569 bool is_continue,
570 int join_id) {
571 HBasicBlock* result = NULL;
572 const ZoneList<BreakContinueInfo*>* infos = break_continue_info();
573 for (int i = 0; i < infos->length(); ++i) {
574 BreakContinueInfo* info = infos->at(i);
575 if (info->is_continue() == is_continue &&
576 info->target() == statement &&
577 !info->IsResolved()) {
578 if (result == NULL) {
579 result = graph_->CreateBasicBlock();
580 }
581 info->block()->Goto(result);
582 info->Resolve();
583 }
584 }
585
586 if (result != NULL) result->SetJoinId(join_id);
587
588 return result;
589 }
590
591
592 HBasicBlock* HSubgraph::JoinBlocks(HBasicBlock* a, HBasicBlock* b, int id) {
593 if (a == NULL) return b;
594 if (b == NULL) return a;
595 HBasicBlock* target = graph_->CreateBasicBlock();
596 a->Goto(target);
597 b->Goto(target);
598 target->SetJoinId(id);
599 return target;
600 }
601
602
603 void HSubgraph::AppendEndless(HSubgraph* body, IterationStatement* statement) {
604 ConnectExitTo(body->entry_block());
605 body->ResolveContinue(statement);
606 body->ConnectExitTo(body->entry_block(), true);
607 exit_block_ = body->BundleBreak(statement);
608 body->entry_block()->PostProcessLoopHeader(statement);
609 }
610
611
612 void HSubgraph::AppendDoWhile(HSubgraph* body,
613 IterationStatement* statement,
614 HSubgraph* go_back,
615 HSubgraph* exit) {
616 ConnectExitTo(body->entry_block());
617 go_back->ConnectExitTo(body->entry_block(), true);
618
619 HBasicBlock* break_block = body->BundleBreak(statement);
620 exit_block_ =
621 JoinBlocks(exit->exit_block(), break_block, statement->ExitId());
622 body->entry_block()->PostProcessLoopHeader(statement);
623 }
624
625
626 void HSubgraph::AppendWhile(HSubgraph* condition,
627 HSubgraph* body,
628 IterationStatement* statement,
629 HSubgraph* continue_subgraph,
630 HSubgraph* exit) {
631 ConnectExitTo(condition->entry_block());
632
633 HBasicBlock* break_block = body->BundleBreak(statement);
634 exit_block_ =
635 JoinBlocks(exit->exit_block(), break_block, statement->ExitId());
636
637 if (continue_subgraph != NULL) {
638 body->ConnectExitTo(continue_subgraph->entry_block(), true);
639 continue_subgraph->entry_block()->SetJoinId(statement->EntryId());
640 exit_block_ = JoinBlocks(exit_block_,
641 continue_subgraph->exit_block(),
642 statement->ExitId());
643 } else {
644 body->ConnectExitTo(condition->entry_block(), true);
645 }
646 condition->entry_block()->PostProcessLoopHeader(statement);
647 }
648
649
650 void HSubgraph::Append(HSubgraph* next, BreakableStatement* stmt) {
651 exit_block_->Goto(next->entry_block());
652 exit_block_ = next->exit_block_;
653
654 if (stmt != NULL) {
655 next->entry_block()->SetJoinId(stmt->EntryId());
656 HBasicBlock* break_block = next->BundleBreak(stmt);
657 exit_block_ = JoinBlocks(exit_block(), break_block, stmt->ExitId());
658 }
659 }
660
661
662 void HSubgraph::FinishExit(HControlInstruction* instruction) {
663 ASSERT(HasExit());
664 exit_block_->Finish(instruction);
665 exit_block_->ClearEnvironment();
666 exit_block_ = NULL;
667 }
668
669
670 void HSubgraph::FinishBreakContinue(BreakableStatement* target,
671 bool is_continue) {
672 ASSERT(!exit_block_->IsFinished());
673 BreakContinueInfo* info = new BreakContinueInfo(target, exit_block_,
674 is_continue);
675 break_continue_info_.Add(info);
676 exit_block_ = NULL;
677 }
678
679
680 HGraph::HGraph(CompilationInfo* info)
681 : HSubgraph(this),
682 next_block_id_(0),
683 info_(info),
684 blocks_(8),
685 values_(16),
686 phi_list_(NULL) {
687 start_environment_ = new HEnvironment(NULL, info->scope(), info->closure());
688 start_environment_->set_ast_id(info->function()->id());
689 }
690
691
692 Handle<Code> HGraph::Compile() {
693 int values = GetMaximumValueID();
694 if (values > LAllocator::max_initial_value_ids()) {
695 if (FLAG_trace_bailout) PrintF("Function is too big\n");
696 return Handle<Code>::null();
697 }
698
699 LAllocator allocator(values, this);
700 LChunkBuilder builder(this, &allocator);
701 LChunk* chunk = builder.Build();
702 if (chunk == NULL) return Handle<Code>::null();
703
704 if (!FLAG_alloc_lithium) return Handle<Code>::null();
705
706 allocator.Allocate(chunk);
707
708 if (!FLAG_use_lithium) return Handle<Code>::null();
709
710 MacroAssembler assembler(NULL, 0);
711 LCodeGen generator(chunk, &assembler, info());
712
713 if (FLAG_eliminate_empty_blocks) {
714 chunk->MarkEmptyBlocks();
715 }
716
717 if (generator.GenerateCode()) {
718 if (FLAG_trace_codegen) {
719 PrintF("Crankshaft Compiler - ");
720 }
721 CodeGenerator::MakeCodePrologue(info());
722 Code::Flags flags =
723 Code::ComputeFlags(Code::OPTIMIZED_FUNCTION, NOT_IN_LOOP);
724 Handle<Code> code =
725 CodeGenerator::MakeCodeEpilogue(&assembler, flags, info());
726 generator.FinishCode(code);
727 CodeGenerator::PrintCode(code, info());
728 return code;
729 }
730 return Handle<Code>::null();
731 }
732
733
734 HBasicBlock* HGraph::CreateBasicBlock() {
735 HBasicBlock* result = new HBasicBlock(this);
736 blocks_.Add(result);
737 return result;
738 }
739
740
741 void HGraph::Canonicalize() {
742 HPhase phase("Canonicalize", this);
743 if (FLAG_use_canonicalizing) {
744 for (int i = 0; i < blocks()->length(); ++i) {
745 HBasicBlock* b = blocks()->at(i);
746 for (HInstruction* insn = b->first(); insn != NULL; insn = insn->next()) {
747 HValue* value = insn->Canonicalize();
748 if (value != insn) {
749 if (value != NULL) {
750 insn->ReplaceAndDelete(value);
751 } else {
752 insn->Delete();
753 }
754 }
755 }
756 }
757 }
758 }
759
760
761 void HGraph::OrderBlocks() {
762 HPhase phase("Block ordering");
763 BitVector visited(blocks_.length());
764
765 ZoneList<HBasicBlock*> reverse_result(8);
766 HBasicBlock* start = blocks_[0];
767 Postorder(start, &visited, &reverse_result, NULL);
768
769 blocks_.Clear();
770 int index = 0;
771 for (int i = reverse_result.length() - 1; i >= 0; --i) {
772 HBasicBlock* b = reverse_result[i];
773 blocks_.Add(b);
774 b->set_block_id(index++);
775 }
776 }
777
778
779 void HGraph::PostorderLoopBlocks(HLoopInformation* loop,
780 BitVector* visited,
781 ZoneList<HBasicBlock*>* order,
782 HBasicBlock* loop_header) {
783 for (int i = 0; i < loop->blocks()->length(); ++i) {
784 HBasicBlock* b = loop->blocks()->at(i);
785 Postorder(b->end()->SecondSuccessor(), visited, order, loop_header);
786 Postorder(b->end()->FirstSuccessor(), visited, order, loop_header);
787 if (b->IsLoopHeader() && b != loop->loop_header()) {
788 PostorderLoopBlocks(b->loop_information(), visited, order, loop_header);
789 }
790 }
791 }
792
793
794 void HGraph::Postorder(HBasicBlock* block,
795 BitVector* visited,
796 ZoneList<HBasicBlock*>* order,
797 HBasicBlock* loop_header) {
798 if (block == NULL || visited->Contains(block->block_id())) return;
799 if (block->parent_loop_header() != loop_header) return;
800 visited->Add(block->block_id());
801 if (block->IsLoopHeader()) {
802 PostorderLoopBlocks(block->loop_information(), visited, order, loop_header);
803 Postorder(block->end()->SecondSuccessor(), visited, order, block);
804 Postorder(block->end()->FirstSuccessor(), visited, order, block);
805 } else {
806 Postorder(block->end()->SecondSuccessor(), visited, order, loop_header);
807 Postorder(block->end()->FirstSuccessor(), visited, order, loop_header);
808 }
809 ASSERT(block->end()->FirstSuccessor() == NULL ||
810 order->Contains(block->end()->FirstSuccessor()) ||
811 block->end()->FirstSuccessor()->IsLoopHeader());
812 ASSERT(block->end()->SecondSuccessor() == NULL ||
813 order->Contains(block->end()->SecondSuccessor()) ||
814 block->end()->SecondSuccessor()->IsLoopHeader());
815 order->Add(block);
816 }
817
818
819 void HGraph::AssignDominators() {
820 HPhase phase("Assign dominators", this);
821 for (int i = 0; i < blocks_.length(); ++i) {
822 if (blocks_[i]->IsLoopHeader()) {
823 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->first());
824 } else {
825 for (int j = 0; j < blocks_[i]->predecessors()->length(); ++j) {
826 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j));
827 }
828 }
829 }
830 }
831
832
833 void HGraph::EliminateRedundantPhis() {
834 HPhase phase("Phi elimination", this);
835 ZoneList<HValue*> uses_to_replace(2);
836
837 // Worklist of phis that can potentially be eliminated. Initialized
838 // with all phi nodes. When elimination of a phi node modifies
839 // another phi node the modified phi node is added to the worklist.
840 ZoneList<HPhi*> worklist(blocks_.length());
841 for (int i = 0; i < blocks_.length(); ++i) {
842 worklist.AddAll(*blocks_[i]->phis());
843 }
844
845 while (!worklist.is_empty()) {
846 HPhi* phi = worklist.RemoveLast();
847 HBasicBlock* block = phi->block();
848
849 // Skip phi node if it was already replaced.
850 if (block == NULL) continue;
851
852 // Get replacement value if phi is redundant.
853 HValue* value = phi->GetRedundantReplacement();
854
855 if (value != NULL) {
856 // Iterate through uses finding the ones that should be
857 // replaced.
858 const ZoneList<HValue*>* uses = phi->uses();
859 for (int i = 0; i < uses->length(); ++i) {
860 HValue* use = uses->at(i);
861 if (!use->block()->IsStartBlock()) {
862 uses_to_replace.Add(use);
863 }
864 }
865 // Replace the uses and add phis modified to the work list.
866 for (int i = 0; i < uses_to_replace.length(); ++i) {
867 HValue* use = uses_to_replace[i];
868 phi->ReplaceAtUse(use, value);
869 if (use->IsPhi()) worklist.Add(HPhi::cast(use));
870 }
871 uses_to_replace.Rewind(0);
872 block->RemovePhi(phi);
873 } else if (phi->HasNoUses() &&
874 !phi->HasReceiverOperand() &&
875 FLAG_eliminate_dead_phis) {
876 // We can't eliminate phis that have the receiver as an operand
877 // because in case of throwing an error we need the correct
878 // receiver value in the environment to construct a corrent
879 // stack trace.
880 block->RemovePhi(phi);
881 block->RecordDeletedPhi(phi->merged_index());
882 }
883 }
884 }
885
886
887 bool HGraph::CollectPhis() {
888 const ZoneList<HBasicBlock*>* blocks = graph_->blocks();
889 phi_list_ = new ZoneList<HPhi*>(blocks->length());
890 for (int i = 0; i < blocks->length(); ++i) {
891 for (int j = 0; j < blocks->at(i)->phis()->length(); j++) {
892 HPhi* phi = blocks->at(i)->phis()->at(j);
893 phi_list_->Add(phi);
894 // We don't support phi uses of arguments for now.
895 if (phi->CheckFlag(HValue::kIsArguments)) return false;
896 }
897 }
898 return true;
899 }
900
901
902 void HGraph::InferTypes(ZoneList<HValue*>* worklist) {
903 BitVector in_worklist(GetMaximumValueID());
904 for (int i = 0; i < worklist->length(); ++i) {
905 ASSERT(!in_worklist.Contains(worklist->at(i)->id()));
906 in_worklist.Add(worklist->at(i)->id());
907 }
908
909 while (!worklist->is_empty()) {
910 HValue* current = worklist->RemoveLast();
911 in_worklist.Remove(current->id());
912 if (current->UpdateInferredType()) {
913 for (int j = 0; j < current->uses()->length(); j++) {
914 HValue* use = current->uses()->at(j);
915 if (!in_worklist.Contains(use->id())) {
916 in_worklist.Add(use->id());
917 worklist->Add(use);
918 }
919 }
920 }
921 }
922 }
923
924
925 class HRangeAnalysis BASE_EMBEDDED {
926 public:
927 explicit HRangeAnalysis(HGraph* graph) : graph_(graph), changed_ranges_(16) {}
928
929 void Analyze();
930
931 private:
932 void TraceRange(const char* msg, ...);
933 void Analyze(HBasicBlock* block);
934 void InferControlFlowRange(HBranch* branch, HBasicBlock* dest);
935 void InferControlFlowRange(Token::Value op, HValue* value, HValue* other);
936 void InferPhiRange(HPhi* phi);
937 void InferRange(HValue* value);
938 void RollBackTo(int index);
939 void AddRange(HValue* value, Range* range);
940
941 HGraph* graph_;
942 ZoneList<HValue*> changed_ranges_;
943 };
944
945
946 void HRangeAnalysis::TraceRange(const char* msg, ...) {
947 if (FLAG_trace_range) {
948 va_list arguments;
949 va_start(arguments, msg);
950 OS::VPrint(msg, arguments);
951 va_end(arguments);
952 }
953 }
954
955
956 void HRangeAnalysis::Analyze() {
957 HPhase phase("Range analysis", graph_);
958 Analyze(graph_->blocks()->at(0));
959 }
960
961
962 void HRangeAnalysis::Analyze(HBasicBlock* block) {
963 TraceRange("Analyzing block B%d\n", block->block_id());
964
965 int last_changed_range = changed_ranges_.length() - 1;
966
967 // Infer range based on control flow.
968 if (block->predecessors()->length() == 1) {
969 HBasicBlock* pred = block->predecessors()->first();
970 if (pred->end()->IsBranch()) {
971 InferControlFlowRange(HBranch::cast(pred->end()), block);
972 }
973 }
974
975 // Process phi instructions.
976 for (int i = 0; i < block->phis()->length(); ++i) {
977 HPhi* phi = block->phis()->at(i);
978 InferPhiRange(phi);
979 }
980
981 // Go through all instructions of the current block.
982 HInstruction* instr = block->first();
983 while (instr != block->end()) {
984 InferRange(instr);
985 instr = instr->next();
986 }
987
988 // Continue analysis in all dominated blocks.
989 for (int i = 0; i < block->dominated_blocks()->length(); ++i) {
990 Analyze(block->dominated_blocks()->at(i));
991 }
992
993 RollBackTo(last_changed_range);
994 }
995
996
997 void HRangeAnalysis::InferControlFlowRange(HBranch* branch, HBasicBlock* dest) {
998 ASSERT(branch->FirstSuccessor() == dest || branch->SecondSuccessor() == dest);
999 ASSERT(branch->FirstSuccessor() != dest || branch->SecondSuccessor() != dest);
1000
1001 if (branch->value()->IsCompare()) {
1002 HCompare* compare = HCompare::cast(branch->value());
1003 Token::Value op = compare->token();
1004 if (branch->SecondSuccessor() == dest) {
1005 op = Token::NegateCompareOp(op);
1006 }
1007 Token::Value inverted_op = Token::InvertCompareOp(op);
1008 InferControlFlowRange(op, compare->left(), compare->right());
1009 InferControlFlowRange(inverted_op, compare->right(), compare->left());
1010 }
1011 }
1012
1013
1014 // We know that value [op] other. Use this information to update the range on
1015 // value.
1016 void HRangeAnalysis::InferControlFlowRange(Token::Value op,
1017 HValue* value,
1018 HValue* other) {
1019 Range* range = other->range();
1020 if (range == NULL) range = new Range();
1021 Range* new_range = NULL;
1022
1023 TraceRange("Control flow range infer %d %s %d\n",
1024 value->id(),
1025 Token::Name(op),
1026 other->id());
1027
1028 if (op == Token::EQ || op == Token::EQ_STRICT) {
1029 // The same range has to apply for value.
1030 new_range = range->Copy();
1031 } else if (op == Token::LT || op == Token::LTE) {
1032 new_range = range->CopyClearLower();
1033 if (op == Token::LT) {
1034 new_range->Add(-1);
1035 }
1036 } else if (op == Token::GT || op == Token::GTE) {
1037 new_range = range->CopyClearUpper();
1038 if (op == Token::GT) {
1039 new_range->Add(1);
1040 }
1041 }
1042
1043 if (new_range != NULL && !new_range->IsMostGeneric()) {
1044 AddRange(value, new_range);
1045 }
1046 }
1047
1048
1049 void HRangeAnalysis::InferPhiRange(HPhi* phi) {
1050 // TODO(twuerthinger): Infer loop phi ranges.
1051 InferRange(phi);
1052 }
1053
1054
1055 void HRangeAnalysis::InferRange(HValue* value) {
1056 ASSERT(!value->HasRange());
1057 if (!value->representation().IsNone()) {
1058 value->ComputeInitialRange();
1059 Range* range = value->range();
1060 TraceRange("Initial inferred range of %d (%s) set to [%d,%d]\n",
1061 value->id(),
1062 value->Mnemonic(),
1063 range->lower(),
1064 range->upper());
1065 }
1066 }
1067
1068
1069 void HRangeAnalysis::RollBackTo(int index) {
1070 for (int i = index + 1; i < changed_ranges_.length(); ++i) {
1071 changed_ranges_[i]->RemoveLastAddedRange();
1072 }
1073 changed_ranges_.Rewind(index + 1);
1074 }
1075
1076
1077 void HRangeAnalysis::AddRange(HValue* value, Range* range) {
1078 Range* original_range = value->range();
1079 value->AddNewRange(range);
1080 changed_ranges_.Add(value);
1081 Range* new_range = value->range();
1082 TraceRange("Updated range of %d set to [%d,%d]\n",
1083 value->id(),
1084 new_range->lower(),
1085 new_range->upper());
1086 if (original_range != NULL) {
1087 TraceRange("Original range was [%d,%d]\n",
1088 original_range->lower(),
1089 original_range->upper());
1090 }
1091 TraceRange("New information was [%d,%d]\n",
1092 range->lower(),
1093 range->upper());
1094 }
1095
1096
1097 void TraceGVN(const char* msg, ...) {
1098 if (FLAG_trace_gvn) {
1099 va_list arguments;
1100 va_start(arguments, msg);
1101 OS::VPrint(msg, arguments);
1102 va_end(arguments);
1103 }
1104 }
1105
1106
1107 HValueMap::HValueMap(const HValueMap* other)
1108 : array_size_(other->array_size_),
1109 lists_size_(other->lists_size_),
1110 count_(other->count_),
1111 present_flags_(other->present_flags_),
1112 array_(ZONE->NewArray<HValueMapListElement>(other->array_size_)),
1113 lists_(ZONE->NewArray<HValueMapListElement>(other->lists_size_)),
1114 free_list_head_(other->free_list_head_) {
1115 memcpy(array_, other->array_, array_size_ * sizeof(HValueMapListElement));
1116 memcpy(lists_, other->lists_, lists_size_ * sizeof(HValueMapListElement));
1117 }
1118
1119
1120 void HValueMap::Kill(int flags) {
1121 int depends_flags = HValue::ConvertChangesToDependsFlags(flags);
1122 if ((present_flags_ & depends_flags) == 0) return;
1123 present_flags_ = 0;
1124 for (int i = 0; i < array_size_; ++i) {
1125 HValue* value = array_[i].value;
1126 if (value != NULL) {
1127 // Clear list of collisions first, so we know if it becomes empty.
1128 int kept = kNil; // List of kept elements.
1129 int next;
1130 for (int current = array_[i].next; current != kNil; current = next) {
1131 next = lists_[current].next;
1132 if ((lists_[current].value->flags() & depends_flags) != 0) {
1133 // Drop it.
1134 count_--;
1135 lists_[current].next = free_list_head_;
1136 free_list_head_ = current;
1137 } else {
1138 // Keep it.
1139 lists_[current].next = kept;
1140 kept = current;
1141 present_flags_ |= lists_[current].value->flags();
1142 }
1143 }
1144 array_[i].next = kept;
1145
1146 // Now possibly drop directly indexed element.
1147 if ((array_[i].value->flags() & depends_flags) != 0) { // Drop it.
1148 count_--;
1149 int head = array_[i].next;
1150 if (head == kNil) {
1151 array_[i].value = NULL;
1152 } else {
1153 array_[i].value = lists_[head].value;
1154 array_[i].next = lists_[head].next;
1155 lists_[head].next = free_list_head_;
1156 free_list_head_ = head;
1157 }
1158 } else {
1159 present_flags_ |= array_[i].value->flags(); // Keep it.
1160 }
1161 }
1162 }
1163 }
1164
1165
1166 HValue* HValueMap::Lookup(HValue* value) const {
1167 uint32_t hash = value->Hashcode();
1168 uint32_t pos = Bound(hash);
1169 if (array_[pos].value != NULL) {
1170 if (array_[pos].value->Equals(value)) return array_[pos].value;
1171 int next = array_[pos].next;
1172 while (next != kNil) {
1173 if (lists_[next].value->Equals(value)) return lists_[next].value;
1174 next = lists_[next].next;
1175 }
1176 }
1177 return NULL;
1178 }
1179
1180
1181 void HValueMap::Resize(int new_size) {
1182 ASSERT(new_size > count_);
1183 // Hashing the values into the new array has no more collisions than in the
1184 // old hash map, so we can use the existing lists_ array, if we are careful.
1185
1186 // Make sure we have at least one free element.
1187 if (free_list_head_ == kNil) {
1188 ResizeLists(lists_size_ << 1);
1189 }
1190
1191 HValueMapListElement* new_array =
1192 ZONE->NewArray<HValueMapListElement>(new_size);
1193 memset(new_array, 0, sizeof(HValueMapListElement) * new_size);
1194
1195 HValueMapListElement* old_array = array_;
1196 int old_size = array_size_;
1197
1198 int old_count = count_;
1199 count_ = 0;
1200 // Do not modify present_flags_. It is currently correct.
1201 array_size_ = new_size;
1202 array_ = new_array;
1203
1204 if (old_array != NULL) {
1205 // Iterate over all the elements in lists, rehashing them.
1206 for (int i = 0; i < old_size; ++i) {
1207 if (old_array[i].value != NULL) {
1208 int current = old_array[i].next;
1209 while (current != kNil) {
1210 Insert(lists_[current].value);
1211 int next = lists_[current].next;
1212 lists_[current].next = free_list_head_;
1213 free_list_head_ = current;
1214 current = next;
1215 }
1216 // Rehash the directly stored value.
1217 Insert(old_array[i].value);
1218 }
1219 }
1220 }
1221 USE(old_count);
1222 ASSERT(count_ == old_count);
1223 }
1224
1225
1226 void HValueMap::ResizeLists(int new_size) {
1227 ASSERT(new_size > lists_size_);
1228
1229 HValueMapListElement* new_lists =
1230 ZONE->NewArray<HValueMapListElement>(new_size);
1231 memset(new_lists, 0, sizeof(HValueMapListElement) * new_size);
1232
1233 HValueMapListElement* old_lists = lists_;
1234 int old_size = lists_size_;
1235
1236 lists_size_ = new_size;
1237 lists_ = new_lists;
1238
1239 if (old_lists != NULL) {
1240 memcpy(lists_, old_lists, old_size * sizeof(HValueMapListElement));
1241 }
1242 for (int i = old_size; i < lists_size_; ++i) {
1243 lists_[i].next = free_list_head_;
1244 free_list_head_ = i;
1245 }
1246 }
1247
1248
1249 void HValueMap::Insert(HValue* value) {
1250 ASSERT(value != NULL);
1251 // Resizing when half of the hashtable is filled up.
1252 if (count_ >= array_size_ >> 1) Resize(array_size_ << 1);
1253 ASSERT(count_ < array_size_);
1254 count_++;
1255 uint32_t pos = Bound(value->Hashcode());
1256 if (array_[pos].value == NULL) {
1257 array_[pos].value = value;
1258 array_[pos].next = kNil;
1259 } else {
1260 if (free_list_head_ == kNil) {
1261 ResizeLists(lists_size_ << 1);
1262 }
1263 int new_element_pos = free_list_head_;
1264 ASSERT(new_element_pos != kNil);
1265 free_list_head_ = lists_[free_list_head_].next;
1266 lists_[new_element_pos].value = value;
1267 lists_[new_element_pos].next = array_[pos].next;
1268 ASSERT(array_[pos].next == kNil || lists_[array_[pos].next].value != NULL);
1269 array_[pos].next = new_element_pos;
1270 }
1271 }
1272
1273
1274 class HStackCheckEliminator BASE_EMBEDDED {
1275 public:
1276 explicit HStackCheckEliminator(HGraph* graph) : graph_(graph) { }
1277
1278 void Process();
1279
1280 private:
1281 void RemoveStackCheck(HBasicBlock* block);
1282
1283 HGraph* graph_;
1284 };
1285
1286
1287 void HStackCheckEliminator::Process() {
1288 // For each loop block walk the dominator tree from the backwards branch to
1289 // the loop header. If a call instruction is encountered the backwards branch
1290 // is dominated by a call and the stack check in the backwards branch can be
1291 // removed.
1292 for (int i = 0; i < graph_->blocks()->length(); i++) {
1293 HBasicBlock* block = graph_->blocks()->at(i);
1294 if (block->IsLoopHeader()) {
1295 HBasicBlock* backedge = block->loop_information()->GetLastBackEdge();
1296 HBasicBlock* dominator = backedge;
1297 bool backedge_dominated_by_call = false;
1298 while (dominator != block && !backedge_dominated_by_call) {
1299 HInstruction* instr = dominator->first();
1300 while (instr != NULL && !backedge_dominated_by_call) {
1301 if (instr->IsCall()) {
1302 RemoveStackCheck(backedge);
1303 backedge_dominated_by_call = true;
1304 }
1305 instr = instr->next();
1306 }
1307 dominator = dominator->dominator();
1308 }
1309 }
1310 }
1311 }
1312
1313
1314 void HStackCheckEliminator::RemoveStackCheck(HBasicBlock* block) {
1315 HInstruction* instr = block->first();
1316 while (instr != NULL) {
1317 if (instr->IsGoto()) {
1318 HGoto::cast(instr)->set_include_stack_check(false);
1319 return;
1320 }
1321 instr = instr->next();
1322 }
1323 }
1324
1325
1326 class HGlobalValueNumberer BASE_EMBEDDED {
1327 public:
1328 explicit HGlobalValueNumberer(HGraph* graph)
1329 : graph_(graph),
1330 block_side_effects_(graph_->blocks()->length()),
1331 loop_side_effects_(graph_->blocks()->length()) {
1332 ASSERT(HEAP->allow_allocation(false));
1333 block_side_effects_.AddBlock(0, graph_->blocks()->length());
1334 loop_side_effects_.AddBlock(0, graph_->blocks()->length());
1335 }
1336 ~HGlobalValueNumberer() {
1337 ASSERT(!HEAP->allow_allocation(true));
1338 }
1339
1340 void Analyze();
1341
1342 private:
1343 void AnalyzeBlock(HBasicBlock* block, HValueMap* map);
1344 void ComputeBlockSideEffects();
1345 void LoopInvariantCodeMotion();
1346 void ProcessLoopBlock(HBasicBlock* block,
1347 HBasicBlock* before_loop,
1348 int loop_kills);
1349 bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header);
1350
1351 HGraph* graph_;
1352
1353 // A map of block IDs to their side effects.
1354 ZoneList<int> block_side_effects_;
1355
1356 // A map of loop header block IDs to their loop's side effects.
1357 ZoneList<int> loop_side_effects_;
1358 };
1359
1360
1361 void HGlobalValueNumberer::Analyze() {
1362 ComputeBlockSideEffects();
1363 if (FLAG_loop_invariant_code_motion) {
1364 LoopInvariantCodeMotion();
1365 }
1366 HValueMap* map = new HValueMap();
1367 AnalyzeBlock(graph_->blocks()->at(0), map);
1368 }
1369
1370
1371 void HGlobalValueNumberer::ComputeBlockSideEffects() {
1372 for (int i = graph_->blocks()->length() - 1; i >= 0; --i) {
1373 // Compute side effects for the block.
1374 HBasicBlock* block = graph_->blocks()->at(i);
1375 HInstruction* instr = block->first();
1376 int id = block->block_id();
1377 int side_effects = 0;
1378 while (instr != NULL) {
1379 side_effects |= (instr->flags() & HValue::ChangesFlagsMask());
1380 instr = instr->next();
1381 }
1382 block_side_effects_[id] |= side_effects;
1383
1384 // Loop headers are part of their loop.
1385 if (block->IsLoopHeader()) {
1386 loop_side_effects_[id] |= side_effects;
1387 }
1388
1389 // Propagate loop side effects upwards.
1390 if (block->HasParentLoopHeader()) {
1391 int header_id = block->parent_loop_header()->block_id();
1392 loop_side_effects_[header_id] |=
1393 block->IsLoopHeader() ? loop_side_effects_[id] : side_effects;
1394 }
1395 }
1396 }
1397
1398
1399 void HGlobalValueNumberer::LoopInvariantCodeMotion() {
1400 for (int i = graph_->blocks()->length() - 1; i >= 0; --i) {
1401 HBasicBlock* block = graph_->blocks()->at(i);
1402 if (block->IsLoopHeader()) {
1403 int side_effects = loop_side_effects_[block->block_id()];
1404 TraceGVN("Try loop invariant motion for block B%d effects=0x%x\n",
1405 block->block_id(),
1406 side_effects);
1407
1408 HBasicBlock* last = block->loop_information()->GetLastBackEdge();
1409 for (int j = block->block_id(); j <= last->block_id(); ++j) {
1410 ProcessLoopBlock(graph_->blocks()->at(j), block, side_effects);
1411 }
1412 }
1413 }
1414 }
1415
1416
1417 void HGlobalValueNumberer::ProcessLoopBlock(HBasicBlock* block,
1418 HBasicBlock* loop_header,
1419 int loop_kills) {
1420 HBasicBlock* pre_header = loop_header->predecessors()->at(0);
1421 int depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills);
1422 TraceGVN("Loop invariant motion for B%d depends_flags=0x%x\n",
1423 block->block_id(),
1424 depends_flags);
1425 HInstruction* instr = block->first();
1426 while (instr != NULL) {
1427 HInstruction* next = instr->next();
1428 if (instr->CheckFlag(HValue::kUseGVN) &&
1429 (instr->flags() & depends_flags) == 0) {
1430 TraceGVN("Checking instruction %d (%s)\n",
1431 instr->id(),
1432 instr->Mnemonic());
1433 bool inputs_loop_invariant = true;
1434 for (int i = 0; i < instr->OperandCount(); ++i) {
1435 if (instr->OperandAt(i)->IsDefinedAfter(pre_header)) {
1436 inputs_loop_invariant = false;
1437 }
1438 }
1439
1440 if (inputs_loop_invariant && ShouldMove(instr, loop_header)) {
1441 TraceGVN("Found loop invariant instruction %d\n", instr->id());
1442 // Move the instruction out of the loop.
1443 instr->Unlink();
1444 instr->InsertBefore(pre_header->end());
1445 }
1446 }
1447 instr = next;
1448 }
1449 }
1450
1451 // Only move instructions that postdominate the loop header (i.e. are
1452 // always executed inside the loop). This is to avoid unnecessary
1453 // deoptimizations assuming the loop is executed at least once.
1454 // TODO(fschneider): Better type feedback should give us information
1455 // about code that was never executed.
1456 bool HGlobalValueNumberer::ShouldMove(HInstruction* instr,
1457 HBasicBlock* loop_header) {
1458 if (!instr->IsChange() &&
1459 FLAG_aggressive_loop_invariant_motion) return true;
1460 HBasicBlock* block = instr->block();
1461 bool result = true;
1462 if (block != loop_header) {
1463 for (int i = 1; i < loop_header->predecessors()->length(); ++i) {
1464 bool found = false;
1465 HBasicBlock* pred = loop_header->predecessors()->at(i);
1466 while (pred != loop_header) {
1467 if (pred == block) found = true;
1468 pred = pred->dominator();
1469 }
1470 if (!found) {
1471 result = false;
1472 break;
1473 }
1474 }
1475 }
1476 return result;
1477 }
1478
1479
1480 void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) {
1481 TraceGVN("Analyzing block B%d\n", block->block_id());
1482
1483 // If this is a loop header kill everything killed by the loop.
1484 if (block->IsLoopHeader()) {
1485 map->Kill(loop_side_effects_[block->block_id()]);
1486 }
1487
1488 // Go through all instructions of the current block.
1489 HInstruction* instr = block->first();
1490 while (instr != NULL) {
1491 HInstruction* next = instr->next();
1492 int flags = (instr->flags() & HValue::ChangesFlagsMask());
1493 if (flags != 0) {
1494 ASSERT(!instr->CheckFlag(HValue::kUseGVN));
1495 // Clear all instructions in the map that are affected by side effects.
1496 map->Kill(flags);
1497 TraceGVN("Instruction %d kills\n", instr->id());
1498 } else if (instr->CheckFlag(HValue::kUseGVN)) {
1499 HValue* other = map->Lookup(instr);
1500 if (other != NULL) {
1501 ASSERT(instr->Equals(other) && other->Equals(instr));
1502 TraceGVN("Replacing value %d (%s) with value %d (%s)\n",
1503 instr->id(),
1504 instr->Mnemonic(),
1505 other->id(),
1506 other->Mnemonic());
1507 instr->ReplaceValue(other);
1508 instr->Delete();
1509 } else {
1510 map->Add(instr);
1511 }
1512 }
1513 instr = next;
1514 }
1515
1516 // Recursively continue analysis for all immediately dominated blocks.
1517 int length = block->dominated_blocks()->length();
1518 for (int i = 0; i < length; ++i) {
1519 HBasicBlock* dominated = block->dominated_blocks()->at(i);
1520 // No need to copy the map for the last child in the dominator tree.
1521 HValueMap* successor_map = (i == length - 1) ? map : map->Copy();
1522
1523 // If the dominated block is not a successor to this block we have to
1524 // kill everything killed on any path between this block and the
1525 // dominated block. Note we rely on the block ordering.
1526 bool is_successor = false;
1527 int predecessor_count = dominated->predecessors()->length();
1528 for (int j = 0; !is_successor && j < predecessor_count; ++j) {
1529 is_successor = (dominated->predecessors()->at(j) == block);
1530 }
1531
1532 if (!is_successor) {
1533 int side_effects = 0;
1534 for (int j = block->block_id() + 1; j < dominated->block_id(); ++j) {
1535 side_effects |= block_side_effects_[j];
1536 }
1537 successor_map->Kill(side_effects);
1538 }
1539
1540 AnalyzeBlock(dominated, successor_map);
1541 }
1542 }
1543
1544
1545 class HInferRepresentation BASE_EMBEDDED {
1546 public:
1547 explicit HInferRepresentation(HGraph* graph)
1548 : graph_(graph), worklist_(8), in_worklist_(graph->GetMaximumValueID()) {}
1549
1550 void Analyze();
1551
1552 private:
1553 Representation TryChange(HValue* current);
1554 void AddToWorklist(HValue* current);
1555 void InferBasedOnInputs(HValue* current);
1556 void AddDependantsToWorklist(HValue* current);
1557 void InferBasedOnUses(HValue* current);
1558
1559 HGraph* graph_;
1560 ZoneList<HValue*> worklist_;
1561 BitVector in_worklist_;
1562 };
1563
1564
1565 void HInferRepresentation::AddToWorklist(HValue* current) {
1566 if (current->representation().IsSpecialization()) return;
1567 if (!current->CheckFlag(HValue::kFlexibleRepresentation)) return;
1568 if (in_worklist_.Contains(current->id())) return;
1569 worklist_.Add(current);
1570 in_worklist_.Add(current->id());
1571 }
1572
1573
1574 // This method tries to specialize the representation type of the value
1575 // given as a parameter. The value is asked to infer its representation type
1576 // based on its inputs. If the inferred type is more specialized, then this
1577 // becomes the new representation type of the node.
1578 void HInferRepresentation::InferBasedOnInputs(HValue* current) {
1579 Representation r = current->representation();
1580 if (r.IsSpecialization()) return;
1581 ASSERT(current->CheckFlag(HValue::kFlexibleRepresentation));
1582 Representation inferred = current->InferredRepresentation();
1583 if (inferred.IsSpecialization()) {
1584 current->ChangeRepresentation(inferred);
1585 AddDependantsToWorklist(current);
1586 }
1587 }
1588
1589
1590 void HInferRepresentation::AddDependantsToWorklist(HValue* current) {
1591 for (int i = 0; i < current->uses()->length(); ++i) {
1592 AddToWorklist(current->uses()->at(i));
1593 }
1594 for (int i = 0; i < current->OperandCount(); ++i) {
1595 AddToWorklist(current->OperandAt(i));
1596 }
1597 }
1598
1599
1600 // This method calculates whether specializing the representation of the value
1601 // given as the parameter has a benefit in terms of less necessary type
1602 // conversions. If there is a benefit, then the representation of the value is
1603 // specialized.
1604 void HInferRepresentation::InferBasedOnUses(HValue* current) {
1605 Representation r = current->representation();
1606 if (r.IsSpecialization() || current->HasNoUses()) return;
1607 ASSERT(current->CheckFlag(HValue::kFlexibleRepresentation));
1608 Representation new_rep = TryChange(current);
1609 if (!new_rep.IsNone()) {
1610 if (!current->representation().Equals(new_rep)) {
1611 current->ChangeRepresentation(new_rep);
1612 AddDependantsToWorklist(current);
1613 }
1614 }
1615 }
1616
1617
1618 Representation HInferRepresentation::TryChange(HValue* current) {
1619 // Array of use counts for each representation.
1620 int use_count[Representation::kNumRepresentations];
1621 for (int i = 0; i < Representation::kNumRepresentations; i++) {
1622 use_count[i] = 0;
1623 }
1624
1625 for (int i = 0; i < current->uses()->length(); ++i) {
1626 HValue* use = current->uses()->at(i);
1627 int index = use->LookupOperandIndex(0, current);
1628 Representation req_rep = use->RequiredInputRepresentation(index);
1629 if (req_rep.IsNone()) continue;
1630 if (use->IsPhi()) {
1631 HPhi* phi = HPhi::cast(use);
1632 phi->AddIndirectUsesTo(&use_count[0]);
1633 }
1634 use_count[req_rep.kind()]++;
1635 }
1636 int tagged_count = use_count[Representation::kTagged];
1637 int double_count = use_count[Representation::kDouble];
1638 int int32_count = use_count[Representation::kInteger32];
1639 int non_tagged_count = double_count + int32_count;
1640
1641 // If a non-loop phi has tagged uses, don't convert it to untagged.
1642 if (current->IsPhi() && !current->block()->IsLoopHeader()) {
1643 if (tagged_count > 0) return Representation::None();
1644 }
1645
1646 if (non_tagged_count >= tagged_count) {
1647 // More untagged than tagged.
1648 if (double_count > 0) {
1649 // There is at least one usage that is a double => guess that the
1650 // correct representation is double.
1651 return Representation::Double();
1652 } else if (int32_count > 0) {
1653 return Representation::Integer32();
1654 }
1655 }
1656 return Representation::None();
1657 }
1658
1659
1660 void HInferRepresentation::Analyze() {
1661 HPhase phase("Infer representations", graph_);
1662
1663 // (1) Initialize bit vectors and count real uses. Each phi
1664 // gets a bit-vector of length <number of phis>.
1665 const ZoneList<HPhi*>* phi_list = graph_->phi_list();
1666 int num_phis = phi_list->length();
1667 ScopedVector<BitVector*> connected_phis(num_phis);
1668 for (int i = 0; i < num_phis; i++) {
1669 phi_list->at(i)->InitRealUses(i);
1670 connected_phis[i] = new BitVector(num_phis);
1671 connected_phis[i]->Add(i);
1672 }
1673
1674 // (2) Do a fixed point iteration to find the set of connected phis.
1675 // A phi is connected to another phi if its value is used either
1676 // directly or indirectly through a transitive closure of the def-use
1677 // relation.
1678 bool change = true;
1679 while (change) {
1680 change = false;
1681 for (int i = 0; i < num_phis; i++) {
1682 HPhi* phi = phi_list->at(i);
1683 for (int j = 0; j < phi->uses()->length(); j++) {
1684 HValue* use = phi->uses()->at(j);
1685 if (use->IsPhi()) {
1686 int phi_use = HPhi::cast(use)->phi_id();
1687 if (connected_phis[i]->UnionIsChanged(*connected_phis[phi_use])) {
1688 change = true;
1689 }
1690 }
1691 }
1692 }
1693 }
1694
1695 // (3) Sum up the non-phi use counts of all connected phis.
1696 // Don't include the non-phi uses of the phi itself.
1697 for (int i = 0; i < num_phis; i++) {
1698 HPhi* phi = phi_list->at(i);
1699 for (BitVector::Iterator it(connected_phis.at(i));
1700 !it.Done();
1701 it.Advance()) {
1702 int index = it.Current();
1703 if (index != i) {
1704 HPhi* it_use = phi_list->at(it.Current());
1705 phi->AddNonPhiUsesFrom(it_use);
1706 }
1707 }
1708 }
1709
1710 for (int i = 0; i < graph_->blocks()->length(); ++i) {
1711 HBasicBlock* block = graph_->blocks()->at(i);
1712 const ZoneList<HPhi*>* phis = block->phis();
1713 for (int j = 0; j < phis->length(); ++j) {
1714 AddToWorklist(phis->at(j));
1715 }
1716
1717 HInstruction* current = block->first();
1718 while (current != NULL) {
1719 AddToWorklist(current);
1720 current = current->next();
1721 }
1722 }
1723
1724 while (!worklist_.is_empty()) {
1725 HValue* current = worklist_.RemoveLast();
1726 in_worklist_.Remove(current->id());
1727 InferBasedOnInputs(current);
1728 InferBasedOnUses(current);
1729 }
1730 }
1731
1732
1733 void HGraph::InitializeInferredTypes() {
1734 HPhase phase("Inferring types", this);
1735 InitializeInferredTypes(0, this->blocks_.length() - 1);
1736 }
1737
1738
1739 void HGraph::InitializeInferredTypes(int from_inclusive, int to_inclusive) {
1740 for (int i = from_inclusive; i <= to_inclusive; ++i) {
1741 HBasicBlock* block = blocks_[i];
1742
1743 const ZoneList<HPhi*>* phis = block->phis();
1744 for (int j = 0; j < phis->length(); j++) {
1745 phis->at(j)->UpdateInferredType();
1746 }
1747
1748 HInstruction* current = block->first();
1749 while (current != NULL) {
1750 current->UpdateInferredType();
1751 current = current->next();
1752 }
1753
1754 if (block->IsLoopHeader()) {
1755 HBasicBlock* last_back_edge =
1756 block->loop_information()->GetLastBackEdge();
1757 InitializeInferredTypes(i + 1, last_back_edge->block_id());
1758 // Skip all blocks already processed by the recursive call.
1759 i = last_back_edge->block_id();
1760 // Update phis of the loop header now after the whole loop body is
1761 // guaranteed to be processed.
1762 ZoneList<HValue*> worklist(block->phis()->length());
1763 for (int j = 0; j < block->phis()->length(); ++j) {
1764 worklist.Add(block->phis()->at(j));
1765 }
1766 InferTypes(&worklist);
1767 }
1768 }
1769 }
1770
1771
1772 void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) {
1773 HValue* current = value;
1774 while (current != NULL) {
1775 if (visited->Contains(current->id())) return;
1776
1777 // For phis, we must propagate the check to all of its inputs.
1778 if (current->IsPhi()) {
1779 visited->Add(current->id());
1780 HPhi* phi = HPhi::cast(current);
1781 for (int i = 0; i < phi->OperandCount(); ++i) {
1782 PropagateMinusZeroChecks(phi->OperandAt(i), visited);
1783 }
1784 break;
1785 }
1786
1787 // For multiplication and division, we must propagate to the left and
1788 // the right side.
1789 if (current->IsMul()) {
1790 HMul* mul = HMul::cast(current);
1791 mul->EnsureAndPropagateNotMinusZero(visited);
1792 PropagateMinusZeroChecks(mul->left(), visited);
1793 PropagateMinusZeroChecks(mul->right(), visited);
1794 } else if (current->IsDiv()) {
1795 HDiv* div = HDiv::cast(current);
1796 div->EnsureAndPropagateNotMinusZero(visited);
1797 PropagateMinusZeroChecks(div->left(), visited);
1798 PropagateMinusZeroChecks(div->right(), visited);
1799 }
1800
1801 current = current->EnsureAndPropagateNotMinusZero(visited);
1802 }
1803 }
1804
1805
1806 void HGraph::InsertRepresentationChangeForUse(HValue* value,
1807 HValue* use,
1808 Representation to,
1809 bool is_truncating) {
1810 // Propagate flags for negative zero checks upwards from conversions
1811 // int32-to-tagged and int32-to-double.
1812 Representation from = value->representation();
1813 if (from.IsInteger32()) {
1814 ASSERT(to.IsTagged() || to.IsDouble());
1815 BitVector visited(GetMaximumValueID());
1816 PropagateMinusZeroChecks(value, &visited);
1817 }
1818
1819 // Insert the representation change right before its use. For phi-uses we
1820 // insert at the end of the corresponding predecessor.
1821 HBasicBlock* insert_block = use->block();
1822 if (use->IsPhi()) {
1823 int index = 0;
1824 while (use->OperandAt(index) != value) ++index;
1825 insert_block = insert_block->predecessors()->at(index);
1826 }
1827
1828 HInstruction* next = (insert_block == use->block())
1829 ? HInstruction::cast(use)
1830 : insert_block->end();
1831
1832 // For constants we try to make the representation change at compile
1833 // time. When a representation change is not possible without loss of
1834 // information we treat constants like normal instructions and insert the
1835 // change instructions for them.
1836 HInstruction* new_value = NULL;
1837 if (value->IsConstant()) {
1838 HConstant* constant = HConstant::cast(value);
1839 // Try to create a new copy of the constant with the new representation.
1840 new_value = is_truncating
1841 ? constant->CopyToTruncatedInt32()
1842 : constant->CopyToRepresentation(to);
1843 }
1844
1845 if (new_value == NULL) {
1846 new_value = new HChange(value, value->representation(), to);
1847 }
1848
1849 new_value->InsertBefore(next);
1850 value->ReplaceFirstAtUse(use, new_value, to);
1851 }
1852
1853
1854 int CompareConversionUses(HValue* a,
1855 HValue* b,
1856 Representation a_rep,
1857 Representation b_rep) {
1858 if (a_rep.kind() > b_rep.kind()) {
1859 // Make sure specializations are separated in the result array.
1860 return 1;
1861 }
1862 // Put truncating conversions before non-truncating conversions.
1863 bool a_truncate = a->CheckFlag(HValue::kTruncatingToInt32);
1864 bool b_truncate = b->CheckFlag(HValue::kTruncatingToInt32);
1865 if (a_truncate != b_truncate) {
1866 return a_truncate ? -1 : 1;
1867 }
1868 // Sort by increasing block ID.
1869 return a->block()->block_id() - b->block()->block_id();
1870 }
1871
1872
1873 void HGraph::InsertRepresentationChanges(HValue* current) {
1874 Representation r = current->representation();
1875 if (r.IsNone()) return;
1876 if (current->uses()->length() == 0) return;
1877
1878 // Collect the representation changes in a sorted list. This allows
1879 // us to avoid duplicate changes without searching the list.
1880 ZoneList<HValue*> to_convert(2);
1881 ZoneList<Representation> to_convert_reps(2);
1882 for (int i = 0; i < current->uses()->length(); ++i) {
1883 HValue* use = current->uses()->at(i);
1884 // The occurrences index means the index within the operand array of "use"
1885 // at which "current" is used. While iterating through the use array we
1886 // also have to iterate over the different occurrence indices.
1887 int occurrence_index = 0;
1888 if (use->UsesMultipleTimes(current)) {
1889 occurrence_index = current->uses()->CountOccurrences(use, 0, i - 1);
1890 if (FLAG_trace_representation) {
1891 PrintF("Instruction %d is used multiple times at %d; occurrence=%d\n",
1892 current->id(),
1893 use->id(),
1894 occurrence_index);
1895 }
1896 }
1897 int operand_index = use->LookupOperandIndex(occurrence_index, current);
1898 Representation req = use->RequiredInputRepresentation(operand_index);
1899 if (req.IsNone() || req.Equals(r)) continue;
1900 int index = 0;
1901 while (to_convert.length() > index &&
1902 CompareConversionUses(to_convert[index],
1903 use,
1904 to_convert_reps[index],
1905 req) < 0) {
1906 ++index;
1907 }
1908 if (FLAG_trace_representation) {
1909 PrintF("Inserting a representation change to %s of %d for use at %d\n",
1910 req.Mnemonic(),
1911 current->id(),
1912 use->id());
1913 }
1914 to_convert.InsertAt(index, use);
1915 to_convert_reps.InsertAt(index, req);
1916 }
1917
1918 for (int i = 0; i < to_convert.length(); ++i) {
1919 HValue* use = to_convert[i];
1920 Representation r_to = to_convert_reps[i];
1921 bool is_truncating = use->CheckFlag(HValue::kTruncatingToInt32);
1922 InsertRepresentationChangeForUse(current, use, r_to, is_truncating);
1923 }
1924
1925 if (current->uses()->is_empty()) {
1926 ASSERT(current->IsConstant());
1927 current->Delete();
1928 }
1929 }
1930
1931
1932 void HGraph::InsertRepresentationChanges() {
1933 HPhase phase("Insert representation changes", this);
1934
1935
1936 // Compute truncation flag for phis: Initially assume that all
1937 // int32-phis allow truncation and iteratively remove the ones that
1938 // are used in an operation that does not allow a truncating
1939 // conversion.
1940 // TODO(fschneider): Replace this with a worklist-based iteration.
1941 for (int i = 0; i < phi_list()->length(); i++) {
1942 HPhi* phi = phi_list()->at(i);
1943 if (phi->representation().IsInteger32()) {
1944 phi->SetFlag(HValue::kTruncatingToInt32);
1945 }
1946 }
1947 bool change = true;
1948 while (change) {
1949 change = false;
1950 for (int i = 0; i < phi_list()->length(); i++) {
1951 HPhi* phi = phi_list()->at(i);
1952 if (!phi->CheckFlag(HValue::kTruncatingToInt32)) continue;
1953 for (int j = 0; j < phi->uses()->length(); j++) {
1954 HValue* use = phi->uses()->at(j);
1955 if (!use->CheckFlag(HValue::kTruncatingToInt32)) {
1956 phi->ClearFlag(HValue::kTruncatingToInt32);
1957 change = true;
1958 break;
1959 }
1960 }
1961 }
1962 }
1963
1964 for (int i = 0; i < blocks_.length(); ++i) {
1965 // Process phi instructions first.
1966 for (int j = 0; j < blocks_[i]->phis()->length(); j++) {
1967 HPhi* phi = blocks_[i]->phis()->at(j);
1968 InsertRepresentationChanges(phi);
1969 }
1970
1971 // Process normal instructions.
1972 HInstruction* current = blocks_[i]->first();
1973 while (current != NULL) {
1974 InsertRepresentationChanges(current);
1975 current = current->next();
1976 }
1977 }
1978 }
1979
1980
1981 // Implementation of utility classes to represent an expression's context in
1982 // the AST.
1983 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind)
1984 : owner_(owner), kind_(kind), outer_(owner->ast_context()) {
1985 owner->set_ast_context(this); // Push.
1986 }
1987
1988
1989 AstContext::~AstContext() {
1990 owner_->set_ast_context(outer_); // Pop.
1991 }
1992
1993
1994
1995 // HGraphBuilder infrastructure for bailing out and checking bailouts.
1996 #define BAILOUT(reason) \
1997 do { \
1998 Bailout(reason); \
1999 return; \
2000 } while (false)
2001
2002
2003 #define CHECK_BAILOUT \
2004 do { \
2005 if (HasStackOverflow()) return; \
2006 } while (false)
2007
2008
2009 #define VISIT_FOR_EFFECT(expr) \
2010 do { \
2011 VisitForEffect(expr); \
2012 if (HasStackOverflow()) return; \
2013 } while (false)
2014
2015
2016 #define VISIT_FOR_VALUE(expr) \
2017 do { \
2018 VisitForValue(expr); \
2019 if (HasStackOverflow()) return; \
2020 } while (false)
2021
2022
2023 // 'thing' could be an expression, statement, or list of statements.
2024 #define ADD_TO_SUBGRAPH(graph, thing) \
2025 do { \
2026 AddToSubgraph(graph, thing); \
2027 if (HasStackOverflow()) return; \
2028 } while (false)
2029
2030
2031 class HGraphBuilder::SubgraphScope BASE_EMBEDDED {
2032 public:
2033 SubgraphScope(HGraphBuilder* builder, HSubgraph* new_subgraph)
2034 : builder_(builder) {
2035 old_subgraph_ = builder_->current_subgraph_;
2036 subgraph_ = new_subgraph;
2037 builder_->current_subgraph_ = subgraph_;
2038 }
2039
2040 ~SubgraphScope() {
2041 old_subgraph_->AddBreakContinueInfo(subgraph_);
2042 builder_->current_subgraph_ = old_subgraph_;
2043 }
2044
2045 HSubgraph* subgraph() const { return subgraph_; }
2046
2047 private:
2048 HGraphBuilder* builder_;
2049 HSubgraph* old_subgraph_;
2050 HSubgraph* subgraph_;
2051 };
2052
2053
2054 void HGraphBuilder::Bailout(const char* reason) {
2055 if (FLAG_trace_bailout) {
2056 SmartPointer<char> debug_name = graph()->debug_name()->ToCString();
2057 PrintF("Bailout in HGraphBuilder: @\"%s\": %s\n", *debug_name, reason);
2058 }
2059 SetStackOverflow();
2060 }
2061
2062
2063 void HGraphBuilder::VisitForEffect(Expression* expr) {
2064 #ifdef DEBUG
2065 int original_count = environment()->total_count();
2066 #endif
2067 BinaryOperation* binary_op = expr->AsBinaryOperation();
2068
2069 // We use special casing for expression types not handled properly by our
2070 // usual trick of pretending they're in a value context and cleaning up
2071 // later.
2072 if (binary_op != NULL && binary_op->op() == Token::COMMA) {
2073 VISIT_FOR_EFFECT(binary_op->left());
2074 VISIT_FOR_EFFECT(binary_op->right());
2075 } else {
2076 { EffectContext for_effect(this);
2077 Visit(expr);
2078 }
2079 if (HasStackOverflow() || !subgraph()->HasExit()) return;
2080 // Discard return value.
2081 Pop();
2082 // TODO(kasperl): Try to improve the way we compute the last added
2083 // instruction. The NULL check makes me uncomfortable.
2084 HValue* last = subgraph()->exit_block()->GetLastInstruction();
2085 // We need to ensure we emit a simulate after inlined functions in an
2086 // effect context, to avoid having a bailout target the fictional
2087 // environment with the return value on top.
2088 if ((last != NULL && last->HasSideEffects()) ||
2089 subgraph()->exit_block()->IsInlineReturnTarget()) {
2090 AddSimulate(expr->id());
2091 }
2092 }
2093
2094 ASSERT(environment()->total_count() == original_count);
2095 }
2096
2097
2098 void HGraphBuilder::VisitForValue(Expression* expr) {
2099 #ifdef DEBUG
2100 int original_height = environment()->values()->length();
2101 #endif
2102 { ValueContext for_value(this);
2103 Visit(expr);
2104 }
2105 if (HasStackOverflow() || !subgraph()->HasExit()) return;
2106 // TODO(kasperl): Try to improve the way we compute the last added
2107 // instruction. The NULL check makes me uncomfortable.
2108 HValue* last = subgraph()->exit_block()->GetLastInstruction();
2109 if (last != NULL && last->HasSideEffects()) {
2110 AddSimulate(expr->id());
2111 }
2112 ASSERT(environment()->values()->length() == original_height + 1);
2113 }
2114
2115
2116 HValue* HGraphBuilder::VisitArgument(Expression* expr) {
2117 VisitForValue(expr);
2118 if (HasStackOverflow() || !subgraph()->HasExit()) return NULL;
2119 return environment()->Top();
2120 }
2121
2122
2123 void HGraphBuilder::VisitArgumentList(ZoneList<Expression*>* arguments) {
2124 for (int i = 0; i < arguments->length(); i++) {
2125 VisitArgument(arguments->at(i));
2126 if (HasStackOverflow() || !current_subgraph_->HasExit()) return;
2127 }
2128 }
2129
2130
2131 HGraph* HGraphBuilder::CreateGraph(CompilationInfo* info) {
2132 ASSERT(current_subgraph_ == NULL);
2133 graph_ = new HGraph(info);
2134
2135 {
2136 HPhase phase("Block building");
2137 graph_->Initialize(CreateBasicBlock(graph_->start_environment()));
2138 current_subgraph_ = graph_;
2139
2140 Scope* scope = info->scope();
2141 SetupScope(scope);
2142 VisitDeclarations(scope->declarations());
2143
2144 AddInstruction(new HStackCheck());
2145
2146 ZoneList<Statement*>* stmts = info->function()->body();
2147 HSubgraph* body = CreateGotoSubgraph(environment());
2148 AddToSubgraph(body, stmts);
2149 if (HasStackOverflow()) return NULL;
2150 current_subgraph_->Append(body, NULL);
2151 body->entry_block()->SetJoinId(info->function()->id());
2152
2153 if (graph_->HasExit()) {
2154 graph_->FinishExit(new HReturn(graph_->GetConstantUndefined()));
2155 }
2156 }
2157
2158 graph_->OrderBlocks();
2159 graph_->AssignDominators();
2160 graph_->EliminateRedundantPhis();
2161 if (!graph_->CollectPhis()) {
2162 Bailout("Phi-use of arguments object");
2163 return NULL;
2164 }
2165
2166 HInferRepresentation rep(graph_);
2167 rep.Analyze();
2168
2169 if (FLAG_use_range) {
2170 HRangeAnalysis rangeAnalysis(graph_);
2171 rangeAnalysis.Analyze();
2172 }
2173
2174 graph_->InitializeInferredTypes();
2175 graph_->Canonicalize();
2176 graph_->InsertRepresentationChanges();
2177
2178 // Eliminate redundant stack checks on backwards branches.
2179 HStackCheckEliminator sce(graph_);
2180 sce.Process();
2181
2182 // Perform common subexpression elimination and loop-invariant code motion.
2183 if (FLAG_use_gvn) {
2184 HPhase phase("Global value numbering", graph_);
2185 HGlobalValueNumberer gvn(graph_);
2186 gvn.Analyze();
2187 }
2188
2189 return graph_;
2190 }
2191
2192
2193 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Statement* stmt) {
2194 SubgraphScope scope(this, graph);
2195 Visit(stmt);
2196 }
2197
2198
2199 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Expression* expr) {
2200 SubgraphScope scope(this, graph);
2201 VisitForValue(expr);
2202 }
2203
2204
2205 void HGraphBuilder::VisitCondition(Expression* expr,
2206 HBasicBlock* true_block,
2207 HBasicBlock* false_block,
2208 bool invert_true,
2209 bool invert_false) {
2210 VisitForControl(expr, true_block, false_block, invert_true, invert_false);
2211 CHECK_BAILOUT;
2212 #ifdef DEBUG
2213 HValue* value = true_block->predecessors()->at(0)->last_environment()->Top();
2214 true_block->set_cond(HConstant::cast(value)->handle());
2215
2216 value = false_block->predecessors()->at(0)->last_environment()->Top();
2217 false_block->set_cond(HConstant::cast(value)->handle());
2218 #endif
2219
2220 true_block->SetJoinId(expr->id());
2221 false_block->SetJoinId(expr->id());
2222 true_block->last_environment()->Pop();
2223 false_block->last_environment()->Pop();
2224 }
2225
2226
2227 void HGraphBuilder::AddConditionToSubgraph(HSubgraph* subgraph,
2228 Expression* expr,
2229 HSubgraph* true_graph,
2230 HSubgraph* false_graph) {
2231 SubgraphScope scope(this, subgraph);
2232 VisitCondition(expr,
2233 true_graph->entry_block(),
2234 false_graph->entry_block(),
2235 false,
2236 false);
2237 }
2238
2239
2240 void HGraphBuilder::VisitForControl(Expression* expr,
2241 HBasicBlock* true_block,
2242 HBasicBlock* false_block,
2243 bool invert_true,
2244 bool invert_false) {
2245 TestContext for_test(this, true_block, false_block,
2246 invert_true, invert_false);
2247 BinaryOperation* binary_op = expr->AsBinaryOperation();
2248 UnaryOperation* unary_op = expr->AsUnaryOperation();
2249
2250 if (unary_op != NULL && unary_op->op() == Token::NOT) {
2251 VisitForControl(unary_op->expression(),
2252 false_block,
2253 true_block,
2254 !invert_false,
2255 !invert_true);
2256 } else if (binary_op != NULL && binary_op->op() == Token::AND) {
2257 // Translate left subexpression.
2258 HBasicBlock* eval_right = graph()->CreateBasicBlock();
2259 VisitForControl(binary_op->left(),
2260 eval_right,
2261 false_block,
2262 false,
2263 invert_false);
2264 if (HasStackOverflow()) return;
2265 eval_right->SetJoinId(binary_op->left()->id());
2266
2267 // Translate right subexpression.
2268 eval_right->last_environment()->Pop();
2269 subgraph()->set_exit_block(eval_right);
2270 VisitForControl(binary_op->right(),
2271 true_block,
2272 false_block,
2273 invert_true,
2274 invert_false);
2275 } else if (binary_op != NULL && binary_op->op() == Token::OR) {
2276 // Translate left subexpression.
2277 HBasicBlock* eval_right = graph()->CreateBasicBlock();
2278 VisitForControl(binary_op->left(),
2279 true_block,
2280 eval_right,
2281 invert_true,
2282 false);
2283 if (HasStackOverflow()) return;
2284 eval_right->SetJoinId(binary_op->left()->id());
2285
2286 // Translate right subexpression
2287 eval_right->last_environment()->Pop();
2288 subgraph()->set_exit_block(eval_right);
2289 VisitForControl(binary_op->right(),
2290 true_block,
2291 false_block,
2292 invert_true,
2293 invert_false);
2294 } else {
2295 #ifdef DEBUG
2296 int original_length = environment()->values()->length();
2297 #endif
2298 // TODO(kmillikin): Refactor to avoid. This code is duplicated from
2299 // VisitForValue, except without pushing a value context on the
2300 // expression context stack.
2301 Visit(expr);
2302 if (HasStackOverflow() || !subgraph()->HasExit()) return;
2303 HValue* last = subgraph()->exit_block()->GetLastInstruction();
2304 if (last != NULL && last->HasSideEffects()) {
2305 AddSimulate(expr->id());
2306 }
2307 ASSERT(environment()->values()->length() == original_length + 1);
2308 HValue* value = Pop();
2309 HBasicBlock* materialize_true = graph()->CreateBasicBlock();
2310 HBasicBlock* materialize_false = graph()->CreateBasicBlock();
2311 CurrentBlock()->Finish(new HBranch(materialize_true,
2312 materialize_false,
2313 value));
2314 HValue* true_value = invert_true
2315 ? graph()->GetConstantFalse()
2316 : graph()->GetConstantTrue();
2317 materialize_true->set_inverted(invert_true);
2318 true_block->set_deopt_predecessor(materialize_true);
2319
2320 if (true_block->IsInlineReturnTarget()) {
2321 materialize_true->AddLeaveInlined(true_value, true_block);
2322 } else {
2323 materialize_true->last_environment()->Push(true_value);
2324 materialize_true->Goto(true_block);
2325 }
2326 HValue* false_value = invert_false
2327 ? graph()->GetConstantTrue()
2328 : graph()->GetConstantFalse();
2329 materialize_false->set_inverted(invert_false);
2330 false_block->set_deopt_predecessor(materialize_false);
2331
2332 if (false_block->IsInlineReturnTarget()) {
2333 materialize_false->AddLeaveInlined(false_value, false_block);
2334 } else {
2335 materialize_false->last_environment()->Push(false_value);
2336 materialize_false->Goto(false_block);
2337 }
2338 subgraph()->set_exit_block(NULL);
2339 }
2340 }
2341
2342
2343 void HGraphBuilder::AddToSubgraph(HSubgraph* graph,
2344 ZoneList<Statement*>* stmts) {
2345 SubgraphScope scope(this, graph);
2346 VisitStatements(stmts);
2347 }
2348
2349
2350 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
2351 ASSERT(current_subgraph_->HasExit());
2352 current_subgraph_->exit_block()->AddInstruction(instr);
2353 return instr;
2354 }
2355
2356
2357 void HGraphBuilder::AddSimulate(int id) {
2358 ASSERT(current_subgraph_->HasExit());
2359 current_subgraph_->exit_block()->AddSimulate(id);
2360 }
2361
2362
2363 void HGraphBuilder::AddPhi(HPhi* instr) {
2364 ASSERT(current_subgraph_->HasExit());
2365 current_subgraph_->exit_block()->AddPhi(instr);
2366 }
2367
2368
2369 void HGraphBuilder::PushAndAdd(HInstruction* instr) {
2370 Push(instr);
2371 AddInstruction(instr);
2372 }
2373
2374
2375 void HGraphBuilder::PushAndAdd(HInstruction* instr, int position) {
2376 instr->set_position(position);
2377 PushAndAdd(instr);
2378 }
2379
2380
2381 void HGraphBuilder::PushArgumentsForStubCall(int argument_count) {
2382 const int kMaxStubArguments = 4;
2383 ASSERT_GE(kMaxStubArguments, argument_count);
2384 // Push the arguments on the stack.
2385 HValue* arguments[kMaxStubArguments];
2386 for (int i = argument_count - 1; i >= 0; i--) {
2387 arguments[i] = Pop();
2388 }
2389 for (int i = 0; i < argument_count; i++) {
2390 AddInstruction(new HPushArgument(arguments[i]));
2391 }
2392 }
2393
2394
2395 void HGraphBuilder::ProcessCall(HCall* call, int source_position) {
2396 for (int i = call->argument_count() - 1; i >= 0; --i) {
2397 HValue* value = Pop();
2398 HPushArgument* push = new HPushArgument(value);
2399 call->SetArgumentAt(i, push);
2400 }
2401
2402 for (int i = 0; i < call->argument_count(); ++i) {
2403 AddInstruction(call->PushArgumentAt(i));
2404 }
2405
2406 PushAndAdd(call, source_position);
2407 }
2408
2409
2410 void HGraphBuilder::SetupScope(Scope* scope) {
2411 // We don't yet handle the function name for named function expressions.
2412 if (scope->function() != NULL) BAILOUT("named function expression");
2413
2414 // We can't handle heap-allocated locals.
2415 if (scope->num_heap_slots() > 0) BAILOUT("heap allocated locals");
2416
2417 HConstant* undefined_constant =
2418 new HConstant(FACTORY->undefined_value(), Representation::Tagged());
2419 AddInstruction(undefined_constant);
2420 graph_->set_undefined_constant(undefined_constant);
2421
2422 // Set the initial values of parameters including "this". "This" has
2423 // parameter index 0.
2424 int count = scope->num_parameters() + 1;
2425 for (int i = 0; i < count; ++i) {
2426 HInstruction* parameter = AddInstruction(new HParameter(i));
2427 environment()->Bind(i, parameter);
2428 }
2429
2430 // Set the initial values of stack-allocated locals.
2431 for (int i = count; i < environment()->values()->length(); ++i) {
2432 environment()->Bind(i, undefined_constant);
2433 }
2434
2435 // Handle the arguments and arguments shadow variables specially (they do
2436 // not have declarations).
2437 if (scope->arguments() != NULL) {
2438 HArgumentsObject* object = new HArgumentsObject;
2439 AddInstruction(object);
2440 graph()->SetArgumentsObject(object);
2441 environment()->Bind(scope->arguments(), object);
2442 environment()->Bind(scope->arguments_shadow(), object);
2443 }
2444 }
2445
2446
2447 void HGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) {
2448 for (int i = 0; i < statements->length(); i++) {
2449 Visit(statements->at(i));
2450 if (HasStackOverflow() || !current_subgraph_->HasExit()) break;
2451 }
2452 }
2453
2454
2455 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) {
2456 HBasicBlock* b = graph()->CreateBasicBlock();
2457 b->SetInitialEnvironment(env);
2458 return b;
2459 }
2460
2461
2462 HSubgraph* HGraphBuilder::CreateInlinedSubgraph(HEnvironment* outer,
2463 Handle<JSFunction> target,
2464 FunctionLiteral* function) {
2465 HConstant* undefined = graph()->GetConstantUndefined();
2466 HEnvironment* inner =
2467 outer->CopyForInlining(target, function, true, undefined);
2468 HSubgraph* subgraph = new HSubgraph(graph());
2469 subgraph->Initialize(CreateBasicBlock(inner));
2470 return subgraph;
2471 }
2472
2473
2474 HSubgraph* HGraphBuilder::CreateGotoSubgraph(HEnvironment* env) {
2475 HSubgraph* subgraph = new HSubgraph(graph());
2476 HEnvironment* new_env = env->CopyWithoutHistory();
2477 subgraph->Initialize(CreateBasicBlock(new_env));
2478 return subgraph;
2479 }
2480
2481
2482 HSubgraph* HGraphBuilder::CreateEmptySubgraph() {
2483 HSubgraph* subgraph = new HSubgraph(graph());
2484 subgraph->Initialize(graph()->CreateBasicBlock());
2485 return subgraph;
2486 }
2487
2488
2489 HSubgraph* HGraphBuilder::CreateBranchSubgraph(HEnvironment* env) {
2490 HSubgraph* subgraph = new HSubgraph(graph());
2491 HEnvironment* new_env = env->Copy();
2492 subgraph->Initialize(CreateBasicBlock(new_env));
2493 return subgraph;
2494 }
2495
2496
2497 HSubgraph* HGraphBuilder::CreateLoopHeaderSubgraph(HEnvironment* env) {
2498 HSubgraph* subgraph = new HSubgraph(graph());
2499 HBasicBlock* block = graph()->CreateBasicBlock();
2500 HEnvironment* new_env = env->CopyAsLoopHeader(block);
2501 block->SetInitialEnvironment(new_env);
2502 subgraph->Initialize(block);
2503 subgraph->entry_block()->AttachLoopInformation();
2504 return subgraph;
2505 }
2506
2507
2508 void HGraphBuilder::VisitBlock(Block* stmt) {
2509 if (stmt->labels() != NULL) {
2510 HSubgraph* block_graph = CreateGotoSubgraph(environment());
2511 ADD_TO_SUBGRAPH(block_graph, stmt->statements());
2512 current_subgraph_->Append(block_graph, stmt);
2513 } else {
2514 VisitStatements(stmt->statements());
2515 }
2516 }
2517
2518
2519 void HGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) {
2520 VisitForEffect(stmt->expression());
2521 }
2522
2523
2524 void HGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
2525 }
2526
2527
2528 void HGraphBuilder::VisitIfStatement(IfStatement* stmt) {
2529 if (stmt->condition()->ToBooleanIsTrue()) {
2530 Visit(stmt->then_statement());
2531 } else if (stmt->condition()->ToBooleanIsFalse()) {
2532 Visit(stmt->else_statement());
2533 } else {
2534 HSubgraph* then_graph = CreateEmptySubgraph();
2535 HSubgraph* else_graph = CreateEmptySubgraph();
2536 VisitCondition(stmt->condition(),
2537 then_graph->entry_block(),
2538 else_graph->entry_block(),
2539 false, false);
2540 if (HasStackOverflow()) return;
2541 ADD_TO_SUBGRAPH(then_graph, stmt->then_statement());
2542 ADD_TO_SUBGRAPH(else_graph, stmt->else_statement());
2543 current_subgraph_->AppendJoin(then_graph, else_graph, stmt);
2544 }
2545 }
2546
2547
2548 void HGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) {
2549 current_subgraph_->FinishBreakContinue(stmt->target(), true);
2550 }
2551
2552
2553 void HGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
2554 current_subgraph_->FinishBreakContinue(stmt->target(), false);
2555 }
2556
2557
2558 void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
2559 AstContext* context = call_context();
2560 if (context == NULL) {
2561 // Not an inlined return, so an actual one.
2562 VISIT_FOR_VALUE(stmt->expression());
2563 HValue* result = environment()->Pop();
2564 subgraph()->FinishExit(new HReturn(result));
2565 } else {
2566 // Return from an inlined function, visit the subexpression in the
2567 // expression context of the call.
2568 if (context->IsTest()) {
2569 TestContext* test = TestContext::cast(context);
2570 VisitForControl(stmt->expression(),
2571 test->if_true(),
2572 test->if_false(),
2573 false,
2574 false);
2575 } else {
2576 HValue* return_value = NULL;
2577 if (context->IsEffect()) {
2578 VISIT_FOR_EFFECT(stmt->expression());
2579 return_value = graph()->GetConstantUndefined();
2580 } else {
2581 ASSERT(context->IsValue());
2582 VISIT_FOR_VALUE(stmt->expression());
2583 return_value = environment()->Pop();
2584 }
2585 subgraph()->exit_block()->AddLeaveInlined(return_value,
2586 function_return_);
2587 subgraph()->set_exit_block(NULL);
2588 }
2589 }
2590 }
2591
2592
2593 void HGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) {
2594 BAILOUT("WithEnterStatement");
2595 }
2596
2597
2598 void HGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) {
2599 BAILOUT("WithExitStatement");
2600 }
2601
2602
2603 HCompare* HGraphBuilder::BuildSwitchCompare(HSubgraph* subgraph,
2604 HValue* switch_value,
2605 CaseClause* clause) {
2606 AddToSubgraph(subgraph, clause->label());
2607 if (HasStackOverflow()) return NULL;
2608 HValue* clause_value = subgraph->environment()->Pop();
2609 HCompare* compare = new HCompare(switch_value,
2610 clause_value,
2611 Token::EQ_STRICT);
2612 compare->SetInputRepresentation(Representation::Integer32());
2613 subgraph->exit_block()->AddInstruction(compare);
2614 return compare;
2615 }
2616
2617
2618 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
2619 VISIT_FOR_VALUE(stmt->tag());
2620 HValue* switch_value = Pop();
2621
2622 ZoneList<CaseClause*>* clauses = stmt->cases();
2623 int num_clauses = clauses->length();
2624 if (num_clauses == 0) return;
2625 if (num_clauses > 128) BAILOUT("SwitchStatement: too many clauses");
2626
2627 for (int i = 0; i < num_clauses; i++) {
2628 CaseClause* clause = clauses->at(i);
2629 if (clause->is_default()) continue;
2630 clause->RecordTypeFeedback(oracle());
2631 if (!clause->IsSmiCompare()) BAILOUT("SwitchStatement: non-smi compare");
2632 if (!clause->label()->IsSmiLiteral()) {
2633 BAILOUT("SwitchStatement: non-literal switch label");
2634 }
2635 }
2636
2637 // The single exit block of the whole switch statement.
2638 HBasicBlock* single_exit_block = graph_->CreateBasicBlock();
2639
2640 // Build a series of empty subgraphs for the comparisons.
2641 // The default clause does not have a comparison subgraph.
2642 ZoneList<HSubgraph*> compare_graphs(num_clauses);
2643 for (int i = 0; i < num_clauses; i++) {
2644 HSubgraph* subgraph = !clauses->at(i)->is_default()
2645 ? CreateEmptySubgraph()
2646 : NULL;
2647 compare_graphs.Add(subgraph);
2648 }
2649
2650 HSubgraph* prev_graph = current_subgraph_;
2651 HCompare* prev_compare_inst = NULL;
2652 for (int i = 0; i < num_clauses; i++) {
2653 CaseClause* clause = clauses->at(i);
2654 if (clause->is_default()) continue;
2655
2656 // Finish the previous graph by connecting it to the current.
2657 HSubgraph* subgraph = compare_graphs.at(i);
2658 if (prev_compare_inst == NULL) {
2659 ASSERT(prev_graph == current_subgraph_);
2660 prev_graph->exit_block()->Finish(new HGoto(subgraph->entry_block()));
2661 } else {
2662 HBasicBlock* empty = graph()->CreateBasicBlock();
2663 prev_graph->exit_block()->Finish(new HBranch(empty,
2664 subgraph->entry_block(),
2665 prev_compare_inst));
2666 }
2667
2668 // Build instructions for current subgraph.
2669 prev_compare_inst = BuildSwitchCompare(subgraph, switch_value, clause);
2670 if (HasStackOverflow()) return;
2671
2672 prev_graph = subgraph;
2673 }
2674
2675 // Finish last comparison if there was at least one comparison.
2676 // last_false_block is the (empty) false-block of the last comparison. If
2677 // there are no comparisons at all (a single default clause), it is just
2678 // the last block of the current subgraph.
2679 HBasicBlock* last_false_block = current_subgraph_->exit_block();
2680 if (prev_graph != current_subgraph_) {
2681 last_false_block = graph()->CreateBasicBlock();
2682 HBasicBlock* empty = graph()->CreateBasicBlock();
2683 prev_graph->exit_block()->Finish(new HBranch(empty,
2684 last_false_block,
2685 prev_compare_inst));
2686 }
2687
2688 // Build statement blocks, connect them to their comparison block and
2689 // to the previous statement block, if there is a fall-through.
2690 HSubgraph* previous_subgraph = NULL;
2691 for (int i = 0; i < num_clauses; i++) {
2692 CaseClause* clause = clauses->at(i);
2693 HSubgraph* subgraph = CreateEmptySubgraph();
2694
2695 if (clause->is_default()) {
2696 // Default clause: Connect it to the last false block.
2697 last_false_block->Finish(new HGoto(subgraph->entry_block()));
2698 } else {
2699 // Connect with the corresponding comparison.
2700 HBasicBlock* empty =
2701 compare_graphs.at(i)->exit_block()->end()->FirstSuccessor();
2702 empty->Finish(new HGoto(subgraph->entry_block()));
2703 }
2704
2705 // Check for fall-through from previous statement block.
2706 if (previous_subgraph != NULL && previous_subgraph->HasExit()) {
2707 previous_subgraph->exit_block()->
2708 Finish(new HGoto(subgraph->entry_block()));
2709 }
2710
2711 ADD_TO_SUBGRAPH(subgraph, clause->statements());
2712 HBasicBlock* break_block = subgraph->BundleBreak(stmt);
2713 if (break_block != NULL) {
2714 break_block->Finish(new HGoto(single_exit_block));
2715 }
2716
2717 previous_subgraph = subgraph;
2718 }
2719
2720 // If the last statement block has a fall-through, connect it to the
2721 // single exit block.
2722 if (previous_subgraph->HasExit()) {
2723 previous_subgraph->exit_block()->Finish(new HGoto(single_exit_block));
2724 }
2725
2726 // If there is no default clause finish the last comparison's false target.
2727 if (!last_false_block->IsFinished()) {
2728 last_false_block->Finish(new HGoto(single_exit_block));
2729 }
2730
2731 if (single_exit_block->HasPredecessor()) {
2732 current_subgraph_->set_exit_block(single_exit_block);
2733 } else {
2734 current_subgraph_->set_exit_block(NULL);
2735 }
2736 }
2737
2738 bool HGraph::HasOsrEntryAt(IterationStatement* statement) {
2739 return statement->OsrEntryId() == info()->osr_ast_id();
2740 }
2741
2742
2743 void HSubgraph::PreProcessOsrEntry(IterationStatement* statement) {
2744 if (!graph()->HasOsrEntryAt(statement)) return;
2745
2746 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock();
2747 HBasicBlock* osr_entry = graph()->CreateBasicBlock();
2748 HValue* true_value = graph()->GetConstantTrue();
2749 HBranch* branch = new HBranch(non_osr_entry, osr_entry, true_value);
2750 exit_block()->Finish(branch);
2751
2752 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock();
2753 non_osr_entry->Goto(loop_predecessor);
2754
2755 int osr_entry_id = statement->OsrEntryId();
2756 // We want the correct environment at the OsrEntry instruction. Build
2757 // it explicitly. The expression stack should be empty.
2758 int count = osr_entry->last_environment()->total_count();
2759 ASSERT(count == (osr_entry->last_environment()->parameter_count() +
2760 osr_entry->last_environment()->local_count()));
2761 for (int i = 0; i < count; ++i) {
2762 HUnknownOSRValue* unknown = new HUnknownOSRValue;
2763 osr_entry->AddInstruction(unknown);
2764 osr_entry->last_environment()->Bind(i, unknown);
2765 }
2766
2767 osr_entry->AddSimulate(osr_entry_id);
2768 osr_entry->AddInstruction(new HOsrEntry(osr_entry_id));
2769 osr_entry->Goto(loop_predecessor);
2770 loop_predecessor->SetJoinId(statement->EntryId());
2771 set_exit_block(loop_predecessor);
2772 }
2773
2774
2775 void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
2776 ASSERT(subgraph()->HasExit());
2777 subgraph()->PreProcessOsrEntry(stmt);
2778
2779 HSubgraph* body_graph = CreateLoopHeaderSubgraph(environment());
2780 ADD_TO_SUBGRAPH(body_graph, stmt->body());
2781 body_graph->ResolveContinue(stmt);
2782
2783 if (!body_graph->HasExit() || stmt->cond()->ToBooleanIsTrue()) {
2784 current_subgraph_->AppendEndless(body_graph, stmt);
2785 } else {
2786 HSubgraph* go_back = CreateEmptySubgraph();
2787 HSubgraph* exit = CreateEmptySubgraph();
2788 AddConditionToSubgraph(body_graph, stmt->cond(), go_back, exit);
2789 if (HasStackOverflow()) return;
2790 current_subgraph_->AppendDoWhile(body_graph, stmt, go_back, exit);
2791 }
2792 }
2793
2794
2795 bool HGraphBuilder::ShouldPeel(HSubgraph* cond, HSubgraph* body) {
2796 return FLAG_use_peeling;
2797 }
2798
2799
2800 void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
2801 ASSERT(subgraph()->HasExit());
2802 subgraph()->PreProcessOsrEntry(stmt);
2803
2804 HSubgraph* cond_graph = NULL;
2805 HSubgraph* body_graph = NULL;
2806 HSubgraph* exit_graph = NULL;
2807
2808 // If the condition is constant true, do not generate a condition subgraph.
2809 if (stmt->cond()->ToBooleanIsTrue()) {
2810 body_graph = CreateLoopHeaderSubgraph(environment());
2811 ADD_TO_SUBGRAPH(body_graph, stmt->body());
2812 } else {
2813 cond_graph = CreateLoopHeaderSubgraph(environment());
2814 body_graph = CreateEmptySubgraph();
2815 exit_graph = CreateEmptySubgraph();
2816 AddConditionToSubgraph(cond_graph, stmt->cond(), body_graph, exit_graph);
2817 if (HasStackOverflow()) return;
2818 ADD_TO_SUBGRAPH(body_graph, stmt->body());
2819 }
2820
2821 body_graph->ResolveContinue(stmt);
2822
2823 if (cond_graph != NULL) {
2824 AppendPeeledWhile(stmt, cond_graph, body_graph, exit_graph);
2825 } else {
2826 // TODO(fschneider): Implement peeling for endless loops as well.
2827 current_subgraph_->AppendEndless(body_graph, stmt);
2828 }
2829 }
2830
2831
2832 void HGraphBuilder::AppendPeeledWhile(IterationStatement* stmt,
2833 HSubgraph* cond_graph,
2834 HSubgraph* body_graph,
2835 HSubgraph* exit_graph) {
2836 HSubgraph* loop = NULL;
2837 if (body_graph->HasExit() && stmt != peeled_statement_ &&
2838 ShouldPeel(cond_graph, body_graph)) {
2839 // Save the last peeled iteration statement to prevent infinite recursion.
2840 IterationStatement* outer_peeled_statement = peeled_statement_;
2841 peeled_statement_ = stmt;
2842 loop = CreateGotoSubgraph(body_graph->environment());
2843 ADD_TO_SUBGRAPH(loop, stmt);
2844 peeled_statement_ = outer_peeled_statement;
2845 }
2846 current_subgraph_->AppendWhile(cond_graph, body_graph, stmt, loop,
2847 exit_graph);
2848 }
2849
2850
2851 void HGraphBuilder::VisitForStatement(ForStatement* stmt) {
2852 // Only visit the init statement in the peeled part of the loop.
2853 if (stmt->init() != NULL && peeled_statement_ != stmt) {
2854 Visit(stmt->init());
2855 CHECK_BAILOUT;
2856 }
2857 ASSERT(subgraph()->HasExit());
2858 subgraph()->PreProcessOsrEntry(stmt);
2859
2860 HSubgraph* cond_graph = NULL;
2861 HSubgraph* body_graph = NULL;
2862 HSubgraph* exit_graph = NULL;
2863 if (stmt->cond() != NULL) {
2864 cond_graph = CreateLoopHeaderSubgraph(environment());
2865 body_graph = CreateEmptySubgraph();
2866 exit_graph = CreateEmptySubgraph();
2867 AddConditionToSubgraph(cond_graph, stmt->cond(), body_graph, exit_graph);
2868 if (HasStackOverflow()) return;
2869 ADD_TO_SUBGRAPH(body_graph, stmt->body());
2870 } else {
2871 body_graph = CreateLoopHeaderSubgraph(environment());
2872 ADD_TO_SUBGRAPH(body_graph, stmt->body());
2873 }
2874
2875 HSubgraph* next_graph = NULL;
2876 body_graph->ResolveContinue(stmt);
2877
2878 if (stmt->next() != NULL && body_graph->HasExit()) {
2879 next_graph = CreateGotoSubgraph(body_graph->environment());
2880 ADD_TO_SUBGRAPH(next_graph, stmt->next());
2881 body_graph->Append(next_graph, NULL);
2882 next_graph->entry_block()->SetJoinId(stmt->ContinueId());
2883 }
2884
2885 if (cond_graph != NULL) {
2886 AppendPeeledWhile(stmt, cond_graph, body_graph, exit_graph);
2887 } else {
2888 current_subgraph_->AppendEndless(body_graph, stmt);
2889 }
2890 }
2891
2892
2893 void HGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
2894 BAILOUT("ForInStatement");
2895 }
2896
2897
2898 void HGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
2899 BAILOUT("TryCatchStatement");
2900 }
2901
2902
2903 void HGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
2904 BAILOUT("TryFinallyStatement");
2905 }
2906
2907
2908 void HGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
2909 BAILOUT("DebuggerStatement");
2910 }
2911
2912
2913 void HGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
2914 Handle<SharedFunctionInfo> shared_info =
2915 Compiler::BuildFunctionInfo(expr, graph_->info()->script());
2916 CHECK_BAILOUT;
2917 PushAndAdd(new HFunctionLiteral(shared_info, expr->pretenure()));
2918 }
2919
2920
2921 void HGraphBuilder::VisitSharedFunctionInfoLiteral(
2922 SharedFunctionInfoLiteral* expr) {
2923 BAILOUT("SharedFunctionInfoLiteral");
2924 }
2925
2926
2927 void HGraphBuilder::VisitConditional(Conditional* expr) {
2928 HSubgraph* then_graph = CreateEmptySubgraph();
2929 HSubgraph* else_graph = CreateEmptySubgraph();
2930 VisitCondition(expr->condition(),
2931 then_graph->entry_block(),
2932 else_graph->entry_block(),
2933 false, false);
2934 if (HasStackOverflow()) return;
2935 ADD_TO_SUBGRAPH(then_graph, expr->then_expression());
2936 ADD_TO_SUBGRAPH(else_graph, expr->else_expression());
2937 current_subgraph_->AppendJoin(then_graph, else_graph, expr);
2938 }
2939
2940
2941 void HGraphBuilder::LookupGlobalPropertyCell(VariableProxy* expr,
2942 LookupResult* lookup,
2943 bool is_store) {
2944 if (expr->is_this()) {
2945 BAILOUT("global this reference");
2946 }
2947 if (!graph()->info()->has_global_object()) {
2948 BAILOUT("no global object to optimize VariableProxy");
2949 }
2950 Handle<GlobalObject> global(graph()->info()->global_object());
2951 global->Lookup(*expr->name(), lookup);
2952 if (!lookup->IsProperty()) {
2953 BAILOUT("global variable cell not yet introduced");
2954 }
2955 if (lookup->type() != NORMAL) {
2956 BAILOUT("global variable has accessors");
2957 }
2958 if (is_store && lookup->IsReadOnly()) {
2959 BAILOUT("read-only global variable");
2960 }
2961 }
2962
2963
2964 void HGraphBuilder::HandleGlobalVariableLoad(VariableProxy* expr) {
2965 LookupResult lookup;
2966 LookupGlobalPropertyCell(expr, &lookup, false);
2967 CHECK_BAILOUT;
2968
2969 Handle<GlobalObject> global(graph()->info()->global_object());
2970 // TODO(3039103): Handle global property load through an IC call when access
2971 // checks are enabled.
2972 if (global->IsAccessCheckNeeded()) {
2973 BAILOUT("global object requires access check");
2974 }
2975 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
2976 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly();
2977 PushAndAdd(new HLoadGlobal(cell, check_hole));
2978 }
2979
2980
2981 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
2982 Variable* variable = expr->AsVariable();
2983 if (variable == NULL) {
2984 BAILOUT("reference to rewritten variable");
2985 } else if (variable->IsStackAllocated()) {
2986 if (environment()->Lookup(variable)->CheckFlag(HValue::kIsArguments)) {
2987 BAILOUT("unsupported context for arguments object");
2988 }
2989 Push(environment()->Lookup(variable));
2990 } else if (variable->is_global()) {
2991 HandleGlobalVariableLoad(expr);
2992 } else {
2993 BAILOUT("reference to non-stack-allocated/non-global variable");
2994 }
2995 }
2996
2997
2998 void HGraphBuilder::VisitLiteral(Literal* expr) {
2999 PushAndAdd(new HConstant(expr->handle(), Representation::Tagged()));
3000 }
3001
3002
3003 void HGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
3004 PushAndAdd(new HRegExpLiteral(expr->pattern(),
3005 expr->flags(),
3006 expr->literal_index()));
3007 }
3008
3009
3010 void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
3011 HObjectLiteral* literal = (new HObjectLiteral(expr->constant_properties(),
3012 expr->fast_elements(),
3013 expr->literal_index(),
3014 expr->depth()));
3015 PushAndAdd(literal);
3016
3017 expr->CalculateEmitStore();
3018
3019 for (int i = 0; i < expr->properties()->length(); i++) {
3020 ObjectLiteral::Property* property = expr->properties()->at(i);
3021 if (property->IsCompileTimeValue()) continue;
3022
3023 Literal* key = property->key();
3024 Expression* value = property->value();
3025
3026 switch (property->kind()) {
3027 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
3028 ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
3029 // Fall through.
3030 case ObjectLiteral::Property::COMPUTED:
3031 if (key->handle()->IsSymbol()) {
3032 if (property->emit_store()) {
3033 VISIT_FOR_VALUE(value);
3034 HValue* value = Pop();
3035 Handle<String> name = Handle<String>::cast(key->handle());
3036 AddInstruction(new HStoreNamedGeneric(literal, name, value));
3037 AddSimulate(key->id());
3038 } else {
3039 VISIT_FOR_EFFECT(value);
3040 }
3041 break;
3042 }
3043 // Fall through.
3044 case ObjectLiteral::Property::PROTOTYPE:
3045 case ObjectLiteral::Property::SETTER:
3046 case ObjectLiteral::Property::GETTER:
3047 BAILOUT("Object literal with complex property");
3048 default: UNREACHABLE();
3049 }
3050 }
3051 }
3052
3053
3054 void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
3055 ZoneList<Expression*>* subexprs = expr->values();
3056 int length = subexprs->length();
3057
3058 HArrayLiteral* literal = new HArrayLiteral(expr->constant_elements(),
3059 length,
3060 expr->literal_index(),
3061 expr->depth());
3062 PushAndAdd(literal);
3063 HValue* elements = AddInstruction(new HLoadElements(literal));
3064
3065 for (int i = 0; i < length; i++) {
3066 Expression* subexpr = subexprs->at(i);
3067 // If the subexpression is a literal or a simple materialized literal it
3068 // is already set in the cloned array.
3069 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
3070
3071 VISIT_FOR_VALUE(subexpr);
3072 HValue* value = Pop();
3073 if (!Smi::IsValid(i)) BAILOUT("Non-smi key in array literal");
3074 HValue* key = AddInstruction(new HConstant(Handle<Object>(Smi::FromInt(i)),
3075 Representation::Integer32()));
3076 AddInstruction(new HStoreKeyedFastElement(elements, key, value));
3077 AddSimulate(expr->GetIdForElement(i));
3078 }
3079 }
3080
3081
3082 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) {
3083 BAILOUT("CatchExtensionObject");
3084 }
3085
3086
3087 HBasicBlock* HGraphBuilder::BuildTypeSwitch(ZoneMapList* maps,
3088 ZoneList<HSubgraph*>* subgraphs,
3089 HValue* receiver,
3090 int join_id) {
3091 ASSERT(subgraphs->length() == (maps->length() + 1));
3092
3093 // Build map compare subgraphs for all but the first map.
3094 ZoneList<HSubgraph*> map_compare_subgraphs(maps->length() - 1);
3095 for (int i = maps->length() - 1; i > 0; --i) {
3096 HSubgraph* subgraph = CreateBranchSubgraph(environment());
3097 SubgraphScope scope(this, subgraph);
3098 HSubgraph* else_subgraph =
3099 (i == (maps->length() - 1))
3100 ? subgraphs->last()
3101 : map_compare_subgraphs.last();
3102 current_subgraph_->exit_block()->Finish(
3103 new HCompareMapAndBranch(receiver,
3104 maps->at(i),
3105 subgraphs->at(i)->entry_block(),
3106 else_subgraph->entry_block()));
3107 map_compare_subgraphs.Add(subgraph);
3108 }
3109
3110 // Generate first map check to end the current block.
3111 AddInstruction(new HCheckNonSmi(receiver));
3112 HSubgraph* else_subgraph =
3113 (maps->length() == 1) ? subgraphs->at(1) : map_compare_subgraphs.last();
3114 current_subgraph_->exit_block()->Finish(
3115 new HCompareMapAndBranch(receiver,
3116 Handle<Map>(maps->first()),
3117 subgraphs->first()->entry_block(),
3118 else_subgraph->entry_block()));
3119
3120 // Join all the call subgraphs in a new basic block and make
3121 // this basic block the current basic block.
3122 HBasicBlock* join_block = graph_->CreateBasicBlock();
3123 for (int i = 0; i < subgraphs->length(); ++i) {
3124 if (subgraphs->at(i)->HasExit()) {
3125 subgraphs->at(i)->exit_block()->Goto(join_block);
3126 }
3127 }
3128
3129 if (join_block->predecessors()->is_empty()) return NULL;
3130 join_block->SetJoinId(join_id);
3131 return join_block;
3132 }
3133
3134
3135 // Sets the lookup result and returns true if the store can be inlined.
3136 static bool ComputeStoredField(Handle<Map> type,
3137 Handle<String> name,
3138 LookupResult* lookup) {
3139 type->LookupInDescriptors(NULL, *name, lookup);
3140 if (!lookup->IsPropertyOrTransition()) return false;
3141 if (lookup->type() == FIELD) return true;
3142 return (lookup->type() == MAP_TRANSITION) &&
3143 (type->unused_property_fields() > 0);
3144 }
3145
3146
3147 static int ComputeStoredFieldIndex(Handle<Map> type,
3148 Handle<String> name,
3149 LookupResult* lookup) {
3150 ASSERT(lookup->type() == FIELD || lookup->type() == MAP_TRANSITION);
3151 if (lookup->type() == FIELD) {
3152 return lookup->GetLocalFieldIndexFromMap(*type);
3153 } else {
3154 Map* transition = lookup->GetTransitionMapFromMap(*type);
3155 return transition->PropertyIndexFor(*name) - type->inobject_properties();
3156 }
3157 }
3158
3159
3160 HInstruction* HGraphBuilder::BuildStoreNamedField(HValue* object,
3161 Handle<String> name,
3162 HValue* value,
3163 Handle<Map> type,
3164 LookupResult* lookup,
3165 bool smi_and_map_check) {
3166 if (smi_and_map_check) {
3167 AddInstruction(new HCheckNonSmi(object));
3168 AddInstruction(new HCheckMap(object, type));
3169 }
3170
3171 int index = ComputeStoredFieldIndex(type, name, lookup);
3172 bool is_in_object = index < 0;
3173 int offset = index * kPointerSize;
3174 if (index < 0) {
3175 // Negative property indices are in-object properties, indexed
3176 // from the end of the fixed part of the object.
3177 offset += type->instance_size();
3178 } else {
3179 offset += FixedArray::kHeaderSize;
3180 }
3181 HStoreNamedField* instr =
3182 new HStoreNamedField(object, name, value, is_in_object, offset);
3183 if (lookup->type() == MAP_TRANSITION) {
3184 Handle<Map> transition(lookup->GetTransitionMapFromMap(*type));
3185 instr->set_transition(transition);
3186 }
3187 return instr;
3188 }
3189
3190
3191 HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object,
3192 Handle<String> name,
3193 HValue* value) {
3194 return new HStoreNamedGeneric(object, name, value);
3195 }
3196
3197
3198 HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object,
3199 HValue* value,
3200 Expression* expr) {
3201 Property* prop = (expr->AsProperty() != NULL)
3202 ? expr->AsProperty()
3203 : expr->AsAssignment()->target()->AsProperty();
3204 Literal* key = prop->key()->AsLiteral();
3205 Handle<String> name = Handle<String>::cast(key->handle());
3206 ASSERT(!name.is_null());
3207
3208 LookupResult lookup;
3209 ZoneMapList* types = expr->GetReceiverTypes();
3210 bool is_monomorphic = expr->IsMonomorphic() &&
3211 ComputeStoredField(types->first(), name, &lookup);
3212
3213 return is_monomorphic
3214 ? BuildStoreNamedField(object, name, value, types->first(), &lookup,
3215 true) // Needs smi and map check.
3216 : BuildStoreNamedGeneric(object, name, value);
3217 }
3218
3219
3220 void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr,
3221 HValue* object,
3222 HValue* value,
3223 ZoneMapList* types,
3224 Handle<String> name) {
3225 int number_of_types = Min(types->length(), kMaxStorePolymorphism);
3226 ZoneMapList maps(number_of_types);
3227 ZoneList<HSubgraph*> subgraphs(number_of_types + 1);
3228 bool needs_generic = (types->length() > kMaxStorePolymorphism);
3229
3230 // Build subgraphs for each of the specific maps.
3231 //
3232 // TODO(ager): We should recognize when the prototype chains for
3233 // different maps are identical. In that case we can avoid
3234 // repeatedly generating the same prototype map checks.
3235 for (int i = 0; i < number_of_types; ++i) {
3236 Handle<Map> map = types->at(i);
3237 LookupResult lookup;
3238 if (ComputeStoredField(map, name, &lookup)) {
3239 maps.Add(map);
3240 HSubgraph* subgraph = CreateBranchSubgraph(environment());
3241 SubgraphScope scope(this, subgraph);
3242 HInstruction* instr =
3243 BuildStoreNamedField(object, name, value, map, &lookup, false);
3244 Push(value);
3245 instr->set_position(expr->position());
3246 AddInstruction(instr);
3247 subgraphs.Add(subgraph);
3248 } else {
3249 needs_generic = true;
3250 }
3251 }
3252
3253 // If none of the properties were named fields we generate a
3254 // generic store.
3255 if (maps.length() == 0) {
3256 HInstruction* instr = new HStoreNamedGeneric(object, name, value);
3257 Push(value);
3258 instr->set_position(expr->position());
3259 AddInstruction(instr);
3260 return;
3261 }
3262
3263 // Build subgraph for generic store through IC.
3264 {
3265 HSubgraph* subgraph = CreateBranchSubgraph(environment());
3266 SubgraphScope scope(this, subgraph);
3267 if (!needs_generic && FLAG_deoptimize_uncommon_cases) {
3268 subgraph->FinishExit(new HDeoptimize());
3269 } else {
3270 HInstruction* instr = new HStoreNamedGeneric(object, name, value);
3271 Push(value);
3272 instr->set_position(expr->position());
3273 AddInstruction(instr);
3274 }
3275 subgraphs.Add(subgraph);
3276 }
3277
3278 HBasicBlock* new_exit_block =
3279 BuildTypeSwitch(&maps, &subgraphs, object, expr->id());
3280 current_subgraph_->set_exit_block(new_exit_block);
3281 }
3282
3283
3284 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
3285 Property* prop = expr->target()->AsProperty();
3286 ASSERT(prop != NULL);
3287 expr->RecordTypeFeedback(oracle());
3288 VISIT_FOR_VALUE(prop->obj());
3289
3290 HValue* value = NULL;
3291 HInstruction* instr = NULL;
3292
3293 if (prop->key()->IsPropertyName()) {
3294 // Named store.
3295 VISIT_FOR_VALUE(expr->value());
3296 value = Pop();
3297 HValue* object = Pop();
3298
3299 Literal* key = prop->key()->AsLiteral();
3300 Handle<String> name = Handle<String>::cast(key->handle());
3301 ASSERT(!name.is_null());
3302
3303 ZoneMapList* types = expr->GetReceiverTypes();
3304 LookupResult lookup;
3305
3306 if (expr->IsMonomorphic()) {
3307 instr = BuildStoreNamed(object, value, expr);
3308
3309 } else if (types != NULL && types->length() > 1) {
3310 HandlePolymorphicStoreNamedField(expr, object, value, types, name);
3311 return;
3312
3313 } else {
3314 instr = new HStoreNamedGeneric(object, name, value);
3315 }
3316
3317 } else {
3318 // Keyed store.
3319 VISIT_FOR_VALUE(prop->key());
3320 VISIT_FOR_VALUE(expr->value());
3321 value = Pop();
3322 HValue* key = Pop();
3323 HValue* object = Pop();
3324
3325 bool is_fast_elements = expr->IsMonomorphic() &&
3326 expr->GetMonomorphicReceiverType()->has_fast_elements();
3327
3328 instr = is_fast_elements
3329 ? BuildStoreKeyedFastElement(object, key, value, expr)
3330 : BuildStoreKeyedGeneric(object, key, value);
3331 }
3332
3333 Push(value);
3334 instr->set_position(expr->position());
3335 AddInstruction(instr);
3336 }
3337
3338
3339 void HGraphBuilder::HandleGlobalVariableAssignment(VariableProxy* proxy,
3340 HValue* value,
3341 int position) {
3342 LookupResult lookup;
3343 LookupGlobalPropertyCell(proxy, &lookup, true);
3344 CHECK_BAILOUT;
3345
3346 Handle<GlobalObject> global(graph()->info()->global_object());
3347 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
3348 HInstruction* instr = new HStoreGlobal(value, cell);
3349 instr->set_position(position);
3350 AddInstruction(instr);
3351 }
3352
3353
3354 void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
3355 Expression* target = expr->target();
3356 VariableProxy* proxy = target->AsVariableProxy();
3357 Variable* var = proxy->AsVariable();
3358 Property* prop = target->AsProperty();
3359 ASSERT(var == NULL || prop == NULL);
3360
3361 // We have a second position recorded in the FullCodeGenerator to have
3362 // type feedback for the binary operation.
3363 BinaryOperation* operation = expr->binary_operation();
3364 operation->RecordTypeFeedback(oracle());
3365
3366 if (var != NULL) {
3367 if (!var->is_global() && !var->IsStackAllocated()) {
3368 BAILOUT("non-stack/non-global in compound assignment");
3369 }
3370
3371 VISIT_FOR_VALUE(operation);
3372
3373 if (var->is_global()) {
3374 HandleGlobalVariableAssignment(proxy, Top(), expr->position());
3375 } else {
3376 Bind(var, Top());
3377 }
3378 } else if (prop != NULL) {
3379 prop->RecordTypeFeedback(oracle());
3380
3381 if (prop->key()->IsPropertyName()) {
3382 // Named property.
3383 VISIT_FOR_VALUE(prop->obj());
3384 HValue* obj = Top();
3385
3386 HInstruction* load = NULL;
3387 if (prop->IsMonomorphic()) {
3388 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
3389 Handle<Map> map = prop->GetReceiverTypes()->first();
3390 load = BuildLoadNamed(obj, prop, map, name);
3391 } else {
3392 load = BuildLoadNamedGeneric(obj, prop);
3393 }
3394 PushAndAdd(load);
3395 if (load->HasSideEffects()) {
3396 AddSimulate(expr->compound_bailout_id());
3397 }
3398
3399 VISIT_FOR_VALUE(expr->value());
3400 HValue* right = Pop();
3401 HValue* left = Pop();
3402
3403 HInstruction* instr = BuildBinaryOperation(operation, left, right);
3404 PushAndAdd(instr);
3405 if (instr->HasSideEffects()) AddSimulate(operation->id());
3406
3407 HInstruction* store = BuildStoreNamed(obj, instr, prop);
3408 AddInstruction(store);
3409
3410 // Drop the simulated receiver and value and put back the value.
3411 Drop(2);
3412 Push(instr);
3413
3414 } else {
3415 // Keyed property.
3416 VISIT_FOR_VALUE(prop->obj());
3417 VISIT_FOR_VALUE(prop->key());
3418 HValue* obj = environment()->ExpressionStackAt(1);
3419 HValue* key = environment()->ExpressionStackAt(0);
3420
3421 bool is_fast_elements = prop->IsMonomorphic() &&
3422 prop->GetMonomorphicReceiverType()->has_fast_elements();
3423
3424 HInstruction* load = is_fast_elements
3425 ? BuildLoadKeyedFastElement(obj, key, prop)
3426 : BuildLoadKeyedGeneric(obj, key);
3427 PushAndAdd(load);
3428 if (load->HasSideEffects()) {
3429 AddSimulate(expr->compound_bailout_id());
3430 }
3431
3432 VISIT_FOR_VALUE(expr->value());
3433 HValue* right = Pop();
3434 HValue* left = Pop();
3435
3436 HInstruction* instr = BuildBinaryOperation(operation, left, right);
3437 PushAndAdd(instr);
3438 if (instr->HasSideEffects()) AddSimulate(operation->id());
3439
3440 HInstruction* store = is_fast_elements
3441 ? BuildStoreKeyedFastElement(obj, key, instr, prop)
3442 : BuildStoreKeyedGeneric(obj, key, instr);
3443 AddInstruction(store);
3444
3445 // Drop the simulated receiver, key and value and put back the value.
3446 Drop(3);
3447 Push(instr);
3448 }
3449 } else {
3450 BAILOUT("invalid lhs in compound assignment");
3451 }
3452 }
3453
3454
3455 void HGraphBuilder::VisitAssignment(Assignment* expr) {
3456 VariableProxy* proxy = expr->target()->AsVariableProxy();
3457 Variable* var = proxy->AsVariable();
3458 Property* prop = expr->target()->AsProperty();
3459 ASSERT(var == NULL || prop == NULL);
3460
3461 if (expr->is_compound()) {
3462 HandleCompoundAssignment(expr);
3463 return;
3464 }
3465
3466 if (var != NULL) {
3467 if (proxy->IsArguments()) BAILOUT("assignment to arguments");
3468 if (var->is_global()) {
3469 VISIT_FOR_VALUE(expr->value());
3470 HandleGlobalVariableAssignment(proxy, Top(), expr->position());
3471 } else {
3472 // We allow reference to the arguments object only in assignemtns
3473 // to local variables to make sure that the arguments object does
3474 // not escape and is not modified.
3475 VariableProxy* rhs = expr->value()->AsVariableProxy();
3476 if (rhs != NULL &&
3477 rhs->var()->IsStackAllocated() &&
3478 environment()->Lookup(rhs->var())->CheckFlag(HValue::kIsArguments)) {
3479 Push(environment()->Lookup(rhs->var()));
3480 } else {
3481 VISIT_FOR_VALUE(expr->value());
3482 }
3483
3484 Bind(proxy->var(), Top());
3485 }
3486 } else if (prop != NULL) {
3487 HandlePropertyAssignment(expr);
3488 } else {
3489 BAILOUT("unsupported invalid lhs");
3490 }
3491 }
3492
3493
3494 void HGraphBuilder::VisitThrow(Throw* expr) {
3495 VISIT_FOR_VALUE(expr->exception());
3496
3497 HValue* value = environment()->Pop();
3498 HControlInstruction* instr = new HThrow(value);
3499 instr->set_position(expr->position());
3500 current_subgraph_->FinishExit(instr);
3501 }
3502
3503
3504 void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr,
3505 HValue* object,
3506 ZoneMapList* types,
3507 Handle<String> name) {
3508 int number_of_types = Min(types->length(), kMaxLoadPolymorphism);
3509 ZoneMapList maps(number_of_types);
3510 ZoneList<HSubgraph*> subgraphs(number_of_types + 1);
3511 bool needs_generic = (types->length() > kMaxLoadPolymorphism);
3512
3513 // Build subgraphs for each of the specific maps.
3514 //
3515 // TODO(ager): We should recognize when the prototype chains for
3516 // different maps are identical. In that case we can avoid
3517 // repeatedly generating the same prototype map checks.
3518 for (int i = 0; i < number_of_types; ++i) {
3519 Handle<Map> map = types->at(i);
3520 LookupResult lookup;
3521 map->LookupInDescriptors(NULL, *name, &lookup);
3522 if (lookup.IsProperty() && lookup.type() == FIELD) {
3523 maps.Add(map);
3524 HSubgraph* subgraph = CreateBranchSubgraph(environment());
3525 SubgraphScope scope(this, subgraph);
3526 HInstruction* instr =
3527 BuildLoadNamedField(object, expr, map, &lookup, false);
3528 PushAndAdd(instr, expr->position());
3529 subgraphs.Add(subgraph);
3530 } else {
3531 needs_generic = true;
3532 }
3533 }
3534
3535 // If none of the properties were named fields we generate a
3536 // generic load.
3537 if (maps.length() == 0) {
3538 HInstruction* instr = BuildLoadNamedGeneric(object, expr);
3539 PushAndAdd(instr, expr->position());
3540 return;
3541 }
3542
3543 // Build subgraph for generic load through IC.
3544 {
3545 HSubgraph* subgraph = CreateBranchSubgraph(environment());
3546 SubgraphScope scope(this, subgraph);
3547 if (!needs_generic && FLAG_deoptimize_uncommon_cases) {
3548 subgraph->FinishExit(new HDeoptimize());
3549 } else {
3550 HInstruction* instr = BuildLoadNamedGeneric(object, expr);
3551 PushAndAdd(instr, expr->position());
3552 }
3553 subgraphs.Add(subgraph);
3554 }
3555
3556 HBasicBlock* new_exit_block =
3557 BuildTypeSwitch(&maps, &subgraphs, object, expr->id());
3558 current_subgraph_->set_exit_block(new_exit_block);
3559 }
3560
3561
3562 HInstruction* HGraphBuilder::BuildLoadNamedField(HValue* object,
3563 Property* expr,
3564 Handle<Map> type,
3565 LookupResult* lookup,
3566 bool smi_and_map_check) {
3567 if (smi_and_map_check) {
3568 AddInstruction(new HCheckNonSmi(object));
3569 AddInstruction(new HCheckMap(object, type));
3570 }
3571
3572 int index = lookup->GetLocalFieldIndexFromMap(*type);
3573 if (index < 0) {
3574 // Negative property indices are in-object properties, indexed
3575 // from the end of the fixed part of the object.
3576 int offset = (index * kPointerSize) + type->instance_size();
3577 return new HLoadNamedField(object, true, offset);
3578 } else {
3579 // Non-negative property indices are in the properties array.
3580 int offset = (index * kPointerSize) + FixedArray::kHeaderSize;
3581 return new HLoadNamedField(object, false, offset);
3582 }
3583 }
3584
3585
3586 HInstruction* HGraphBuilder::BuildLoadNamedGeneric(HValue* obj,
3587 Property* expr) {
3588 ASSERT(expr->key()->IsPropertyName());
3589 Handle<Object> name = expr->key()->AsLiteral()->handle();
3590 return new HLoadNamedGeneric(obj, name);
3591 }
3592
3593
3594 HInstruction* HGraphBuilder::BuildLoadNamed(HValue* obj,
3595 Property* expr,
3596 Handle<Map> map,
3597 Handle<String> name) {
3598 LookupResult lookup;
3599 map->LookupInDescriptors(NULL, *name, &lookup);
3600 if (lookup.IsProperty() && lookup.type() == FIELD) {
3601 return BuildLoadNamedField(obj,
3602 expr,
3603 map,
3604 &lookup,
3605 true);
3606 } else {
3607 return BuildLoadNamedGeneric(obj, expr);
3608 }
3609 }
3610
3611
3612 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object,
3613 HValue* key) {
3614 return new HLoadKeyedGeneric(object, key);
3615 }
3616
3617
3618 HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object,
3619 HValue* key,
3620 Property* expr) {
3621 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic());
3622 AddInstruction(new HCheckNonSmi(object));
3623 Handle<Map> map = expr->GetMonomorphicReceiverType();
3624 ASSERT(map->has_fast_elements());
3625 AddInstruction(new HCheckMap(object, map));
3626 HInstruction* elements = AddInstruction(new HLoadElements(object));
3627 HInstruction* length = AddInstruction(new HArrayLength(elements));
3628 AddInstruction(new HBoundsCheck(key, length));
3629 return new HLoadKeyedFastElement(elements, key);
3630 }
3631
3632
3633 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object,
3634 HValue* key,
3635 HValue* value) {
3636 return new HStoreKeyedGeneric(object, key, value);
3637 }
3638
3639
3640 HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object,
3641 HValue* key,
3642 HValue* val,
3643 Expression* expr) {
3644 ASSERT(expr->IsMonomorphic());
3645 AddInstruction(new HCheckNonSmi(object));
3646 Handle<Map> map = expr->GetMonomorphicReceiverType();
3647 ASSERT(map->has_fast_elements());
3648 AddInstruction(new HCheckMap(object, map));
3649 HInstruction* elements = AddInstruction(new HLoadElements(object));
3650 AddInstruction(new HCheckMap(elements, FACTORY->fixed_array_map()));
3651 bool is_array = (map->instance_type() == JS_ARRAY_TYPE);
3652 HInstruction* length = NULL;
3653 if (is_array) {
3654 length = AddInstruction(new HArrayLength(object));
3655 } else {
3656 length = AddInstruction(new HArrayLength(elements));
3657 }
3658 AddInstruction(new HBoundsCheck(key, length));
3659 return new HStoreKeyedFastElement(elements, key, val);
3660 }
3661
3662
3663 bool HGraphBuilder::TryArgumentsAccess(Property* expr) {
3664 VariableProxy* proxy = expr->obj()->AsVariableProxy();
3665 if (proxy == NULL) return false;
3666 if (!proxy->var()->IsStackAllocated()) return false;
3667 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) {
3668 return false;
3669 }
3670
3671 if (expr->key()->IsPropertyName()) {
3672 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
3673 if (!name->IsEqualTo(CStrVector("length"))) return false;
3674 HInstruction* elements = AddInstruction(new HArgumentsElements);
3675 PushAndAdd(new HArgumentsLength(elements));
3676 } else {
3677 VisitForValue(expr->key());
3678 if (HasStackOverflow()) return false;
3679 HValue* key = Pop();
3680 HInstruction* elements = AddInstruction(new HArgumentsElements);
3681 HInstruction* length = AddInstruction(new HArgumentsLength(elements));
3682 AddInstruction(new HBoundsCheck(key, length));
3683 PushAndAdd(new HAccessArgumentsAt(elements, length, key));
3684 }
3685 return true;
3686 }
3687
3688
3689 void HGraphBuilder::VisitProperty(Property* expr) {
3690 expr->RecordTypeFeedback(oracle());
3691
3692 if (TryArgumentsAccess(expr)) return;
3693 CHECK_BAILOUT;
3694
3695 VISIT_FOR_VALUE(expr->obj());
3696
3697 HInstruction* instr = NULL;
3698 if (expr->IsArrayLength()) {
3699 HValue* array = Pop();
3700 AddInstruction(new HCheckNonSmi(array));
3701 instr = new HArrayLength(array);
3702
3703 } else if (expr->key()->IsPropertyName()) {
3704 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
3705 ZoneMapList* types = expr->GetReceiverTypes();
3706
3707 HValue* obj = Pop();
3708 if (expr->IsMonomorphic()) {
3709 instr = BuildLoadNamed(obj, expr, types->first(), name);
3710 } else if (types != NULL && types->length() > 1) {
3711 HandlePolymorphicLoadNamedField(expr, obj, types, name);
3712 return;
3713
3714 } else {
3715 instr = BuildLoadNamedGeneric(obj, expr);
3716 }
3717
3718 } else {
3719 VISIT_FOR_VALUE(expr->key());
3720
3721 HValue* key = Pop();
3722 HValue* obj = Pop();
3723
3724 bool is_fast_elements = expr->IsMonomorphic() &&
3725 expr->GetMonomorphicReceiverType()->has_fast_elements();
3726
3727 instr = is_fast_elements
3728 ? BuildLoadKeyedFastElement(obj, key, expr)
3729 : BuildLoadKeyedGeneric(obj, key);
3730 }
3731 PushAndAdd(instr, expr->position());
3732 }
3733
3734
3735 void HGraphBuilder::AddCheckConstantFunction(Call* expr,
3736 HValue* receiver,
3737 Handle<Map> receiver_map,
3738 bool smi_and_map_check) {
3739 // Constant functions have the nice property that the map will change if they
3740 // are overwritten. Therefore it is enough to check the map of the holder and
3741 // its prototypes.
3742 if (smi_and_map_check) {
3743 AddInstruction(new HCheckNonSmi(receiver));
3744 AddInstruction(new HCheckMap(receiver, receiver_map));
3745 }
3746 if (!expr->holder().is_null()) {
3747 AddInstruction(new HCheckPrototypeMaps(receiver,
3748 expr->holder(),
3749 receiver_map));
3750 }
3751 }
3752
3753
3754 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
3755 HValue* receiver,
3756 ZoneMapList* types,
3757 Handle<String> name) {
3758 int argument_count = expr->arguments()->length() + 1; // Plus receiver.
3759 int number_of_types = Min(types->length(), kMaxCallPolymorphism);
3760 ZoneMapList maps(number_of_types);
3761 ZoneList<HSubgraph*> subgraphs(number_of_types + 1);
3762 bool needs_generic = (types->length() > kMaxCallPolymorphism);
3763
3764 // Build subgraphs for each of the specific maps.
3765 //
3766 // TODO(ager): We should recognize when the prototype chains for
3767 // different maps are identical. In that case we can avoid
3768 // repeatedly generating the same prototype map checks.
3769 for (int i = 0; i < number_of_types; ++i) {
3770 Handle<Map> map = types->at(i);
3771 if (expr->ComputeTarget(map, name)) {
3772 maps.Add(map);
3773 HSubgraph* subgraph = CreateBranchSubgraph(environment());
3774 SubgraphScope scope(this, subgraph);
3775 AddCheckConstantFunction(expr, receiver, map, false);
3776 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) {
3777 PrintF("Trying to inline the polymorphic call to %s\n",
3778 *name->ToCString());
3779 }
3780 if (!FLAG_polymorphic_inlining || !TryInline(expr)) {
3781 // Check for bailout, as trying to inline might fail due to bailout
3782 // during hydrogen processing.
3783 CHECK_BAILOUT;
3784 HCall* call = new HCallConstantFunction(expr->target(), argument_count);
3785 ProcessCall(call, expr->position());
3786 }
3787 subgraphs.Add(subgraph);
3788 } else {
3789 needs_generic = true;
3790 }
3791 }
3792
3793 // If we couldn't compute the target for any of the maps just
3794 // perform an IC call.
3795 if (maps.length() == 0) {
3796 HCall* call = new HCallNamed(name, argument_count);
3797 ProcessCall(call, expr->position());
3798 return;
3799 }
3800
3801 // Build subgraph for generic call through IC.
3802 {
3803 HSubgraph* subgraph = CreateBranchSubgraph(environment());
3804 SubgraphScope scope(this, subgraph);
3805 if (!needs_generic && FLAG_deoptimize_uncommon_cases) {
3806 subgraph->FinishExit(new HDeoptimize());
3807 } else {
3808 HCall* call = new HCallNamed(name, argument_count);
3809 ProcessCall(call, expr->position());
3810 }
3811 subgraphs.Add(subgraph);
3812 }
3813
3814 HBasicBlock* new_exit_block =
3815 BuildTypeSwitch(&maps, &subgraphs, receiver, expr->id());
3816 current_subgraph_->set_exit_block(new_exit_block);
3817 }
3818
3819
3820 void HGraphBuilder::TraceInline(Handle<JSFunction> target, bool result) {
3821 SmartPointer<char> callee = target->shared()->DebugName()->ToCString();
3822 SmartPointer<char> caller =
3823 graph()->info()->function()->debug_name()->ToCString();
3824 if (result) {
3825 PrintF("Inlined %s called from %s.\n", *callee, *caller);
3826 } else {
3827 PrintF("Do not inline %s called from %s.\n", *callee, *caller);
3828 }
3829 }
3830
3831
3832 bool HGraphBuilder::TryInline(Call* expr) {
3833 if (!FLAG_use_inlining) return false;
3834
3835 // Precondition: call is monomorphic and we have found a target with the
3836 // appropriate arity.
3837 Handle<JSFunction> target = expr->target();
3838
3839 // Do a quick check on source code length to avoid parsing large
3840 // inlining candidates.
3841 if (FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) {
3842 if (FLAG_trace_inlining) TraceInline(target, false);
3843 return false;
3844 }
3845
3846 // Target must be inlineable.
3847 if (!target->IsInlineable()) return false;
3848
3849 // No context change required.
3850 CompilationInfo* outer_info = graph()->info();
3851 if (target->context() != outer_info->closure()->context() ||
3852 outer_info->scope()->contains_with() ||
3853 outer_info->scope()->num_heap_slots() > 0) {
3854 return false;
3855 }
3856
3857 // Don't inline deeper than two calls.
3858 HEnvironment* env = environment();
3859 if (env->outer() != NULL && env->outer()->outer() != NULL) return false;
3860
3861 // Don't inline recursive functions.
3862 if (target->shared() == outer_info->closure()->shared()) return false;
3863
3864 // We don't want to add more than a certain number of nodes from inlining.
3865 if (FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) {
3866 if (FLAG_trace_inlining) TraceInline(target, false);
3867 return false;
3868 }
3869
3870 int count_before = AstNode::Count();
3871
3872 // Parse and allocate variables.
3873 Handle<SharedFunctionInfo> shared(target->shared());
3874 CompilationInfo inner_info(shared);
3875 if (!ParserApi::Parse(&inner_info) ||
3876 !Scope::Analyze(&inner_info)) {
3877 return false;
3878 }
3879 FunctionLiteral* function = inner_info.function();
3880
3881 // Count the number of AST nodes added by inlining this call.
3882 int nodes_added = AstNode::Count() - count_before;
3883 if (FLAG_limit_inlining && nodes_added > kMaxInlinedSize) {
3884 if (FLAG_trace_inlining) TraceInline(target, false);
3885 return false;
3886 }
3887
3888 // Check if we can handle all declarations in the inlined functions.
3889 VisitDeclarations(inner_info.scope()->declarations());
3890 if (HasStackOverflow()) {
3891 ClearStackOverflow();
3892 return false;
3893 }
3894
3895 // Don't inline functions that uses the arguments object or that
3896 // have a mismatching number of parameters.
3897 int arity = expr->arguments()->length();
3898 if (function->scope()->arguments() != NULL ||
3899 arity != target->shared()->formal_parameter_count()) {
3900 return false;
3901 }
3902
3903 // All statements in the body must be inlineable.
3904 for (int i = 0, count = function->body()->length(); i < count; ++i) {
3905 if (!function->body()->at(i)->IsInlineable()) return false;
3906 }
3907
3908 // Generate the deoptimization data for the unoptimized version of
3909 // the target function if we don't already have it.
3910 if (!shared->has_deoptimization_support()) {
3911 // Note that we compile here using the same AST that we will use for
3912 // generating the optimized inline code.
3913 inner_info.EnableDeoptimizationSupport();
3914 if (!FullCodeGenerator::MakeCode(&inner_info)) return false;
3915 shared->EnableDeoptimizationSupport(*inner_info.code());
3916 Compiler::RecordFunctionCompilation(
3917 Logger::FUNCTION_TAG,
3918 Handle<String>(shared->DebugName()),
3919 shared->start_position(),
3920 &inner_info);
3921 }
3922
3923 // Save the pending call context and type feedback oracle. Set up new ones
3924 // for the inlined function.
3925 ASSERT(shared->has_deoptimization_support());
3926 AstContext* saved_call_context = call_context();
3927 HBasicBlock* saved_function_return = function_return();
3928 TypeFeedbackOracle* saved_oracle = oracle();
3929 // On-stack replacement cannot target inlined functions. Since we don't
3930 // use a separate CompilationInfo structure for the inlined function, we
3931 // save and restore the AST ID in the original compilation info.
3932 int saved_osr_ast_id = graph()->info()->osr_ast_id();
3933
3934 TestContext* test_context = NULL;
3935 if (ast_context()->IsTest()) {
3936 // Inlined body is treated as if it occurs in an 'inlined' call context
3937 // with true and false blocks that will forward to the real ones.
3938 HBasicBlock* if_true = graph()->CreateBasicBlock();
3939 HBasicBlock* if_false = graph()->CreateBasicBlock();
3940 if_true->MarkAsInlineReturnTarget();
3941 if_false->MarkAsInlineReturnTarget();
3942 // AstContext constructor pushes on the context stack.
3943 bool invert_true = TestContext::cast(ast_context())->invert_true();
3944 bool invert_false = TestContext::cast(ast_context())->invert_false();
3945 test_context = new TestContext(this, if_true, if_false,
3946 invert_true, invert_false);
3947 function_return_ = NULL;
3948 } else {
3949 // Inlined body is treated as if it occurs in the original call context.
3950 function_return_ = graph()->CreateBasicBlock();
3951 function_return_->MarkAsInlineReturnTarget();
3952 }
3953 call_context_ = ast_context();
3954 TypeFeedbackOracle new_oracle(Handle<Code>(shared->code()));
3955 oracle_ = &new_oracle;
3956 graph()->info()->SetOsrAstId(AstNode::kNoNumber);
3957
3958 HSubgraph* body = CreateInlinedSubgraph(env, target, function);
3959 body->exit_block()->AddInstruction(new HEnterInlined(target, function));
3960 AddToSubgraph(body, function->body());
3961 if (HasStackOverflow()) {
3962 // Bail out if the inline function did, as we cannot residualize a call
3963 // instead.
3964 delete test_context;
3965 call_context_ = saved_call_context;
3966 function_return_ = saved_function_return;
3967 oracle_ = saved_oracle;
3968 graph()->info()->SetOsrAstId(saved_osr_ast_id);
3969 return false;
3970 }
3971
3972 // Update inlined nodes count.
3973 inlined_count_ += nodes_added;
3974
3975 if (FLAG_trace_inlining) TraceInline(target, true);
3976
3977 if (body->HasExit()) {
3978 // Add a return of undefined if control can fall off the body. In a
3979 // test context, undefined is false.
3980 HValue* return_value = NULL;
3981 HBasicBlock* target = NULL;
3982 if (test_context == NULL) {
3983 ASSERT(function_return_ != NULL);
3984 return_value = graph()->GetConstantUndefined();
3985 target = function_return_;
3986 } else {
3987 return_value = graph()->GetConstantFalse();
3988 target = test_context->if_false();
3989 }
3990 body->exit_block()->AddLeaveInlined(return_value, target);
3991 body->set_exit_block(NULL);
3992 }
3993
3994 // Record the environment at the inlined function call.
3995 AddSimulate(expr->ReturnId());
3996
3997 // Jump to the function entry (without re-recording the environment).
3998 subgraph()->exit_block()->Finish(new HGoto(body->entry_block()));
3999
4000 // Fix up the function exits.
4001 if (test_context != NULL) {
4002 HBasicBlock* if_true = test_context->if_true();
4003 HBasicBlock* if_false = test_context->if_false();
4004 if_true->SetJoinId(expr->id());
4005 if_false->SetJoinId(expr->id());
4006 ASSERT(ast_context() == test_context);
4007 delete test_context; // Destructor pops from expression context stack.
4008 // Forward to the real test context.
4009
4010 // Discard the lingering branch value (which may be true or false,
4011 // depending on whether the final condition was negated) and jump to the
4012 // true target with a true branch value.
4013 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true();
4014 bool invert_true = TestContext::cast(ast_context())->invert_true();
4015 HValue* true_value = invert_true
4016 ? graph()->GetConstantFalse()
4017 : graph()->GetConstantTrue();
4018 if_true->last_environment()->Pop();
4019 if (true_target->IsInlineReturnTarget()) {
4020 if_true->AddLeaveInlined(true_value, true_target);
4021 } else {
4022 if_true->last_environment()->Push(true_value);
4023 if_true->Goto(true_target);
4024 }
4025
4026 // Do the same for the false target.
4027 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false();
4028 bool invert_false = TestContext::cast(ast_context())->invert_false();
4029 HValue* false_value = invert_false
4030 ? graph()->GetConstantTrue()
4031 : graph()->GetConstantFalse();
4032 if_false->last_environment()->Pop();
4033 if (false_target->IsInlineReturnTarget()) {
4034 if_false->AddLeaveInlined(false_value, false_target);
4035 } else {
4036 if_false->last_environment()->Push(false_value);
4037 if_false->Goto(false_target);
4038 }
4039
4040 // TODO(kmillikin): Come up with a better way to handle this. It is too
4041 // subtle. NULL here indicates that the enclosing context has no control
4042 // flow to handle.
4043 subgraph()->set_exit_block(NULL);
4044
4045 } else {
4046 function_return_->SetJoinId(expr->id());
4047 subgraph()->set_exit_block(function_return_);
4048 }
4049
4050 call_context_ = saved_call_context;
4051 function_return_ = saved_function_return;
4052 oracle_ = saved_oracle;
4053 graph()->info()->SetOsrAstId(saved_osr_ast_id);
4054 return true;
4055 }
4056
4057
4058 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) {
4059 ASSERT(target->IsInlineReturnTarget());
4060 AddInstruction(new HLeaveInlined);
4061 HEnvironment* outer = last_environment()->outer();
4062 outer->Push(return_value);
4063 UpdateEnvironment(outer);
4064 Goto(target);
4065 }
4066
4067
4068 bool HGraphBuilder::TryMathFunctionInline(Call* expr) {
4069 // Try to inline calls like Math.* as operations in the calling function.
4070 MathFunctionId id = expr->target()->shared()->math_function_id();
4071 int argument_count = expr->arguments()->length() + 1; // Plus receiver.
4072 switch (id) {
4073 case kMathRound:
4074 case kMathFloor:
4075 case kMathAbs:
4076 case kMathSqrt:
4077 if (argument_count == 2) {
4078 HValue* argument = Pop();
4079 // Pop receiver.
4080 Pop();
4081 HUnaryMathOperation* op = new HUnaryMathOperation(argument, id);
4082 PushAndAdd(op, expr->position());
4083 return true;
4084 }
4085 break;
4086 default:
4087 // Either not a special math function or not yet supported for inlining.
4088 break;
4089 }
4090 return false;
4091 }
4092
4093
4094 bool HGraphBuilder::TryCallApply(Call* expr) {
4095 Expression* callee = expr->expression();
4096 Property* prop = callee->AsProperty();
4097 ASSERT(prop != NULL);
4098
4099 if (graph()->info()->scope()->arguments() == NULL) return false;
4100
4101 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
4102 if (!name->IsEqualTo(CStrVector("apply"))) return false;
4103
4104 ZoneList<Expression*>* args = expr->arguments();
4105 if (args->length() != 2) return false;
4106
4107 VariableProxy* arg_two = args->at(1)->AsVariableProxy();
4108 if (arg_two == NULL) return false;
4109 HValue* arg_two_value = environment()->Lookup(arg_two->var());
4110 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
4111
4112 if (!expr->IsMonomorphic()) return false;
4113
4114 // Found pattern f.apply(receiver, arguments).
4115 VisitForValue(prop->obj());
4116 if (HasStackOverflow()) return false;
4117 HValue* function = Pop();
4118 VisitForValue(args->at(0));
4119 if (HasStackOverflow()) return false;
4120 HValue* receiver = Pop();
4121 HInstruction* elements = AddInstruction(new HArgumentsElements);
4122 HInstruction* length = AddInstruction(new HArgumentsLength(elements));
4123 AddCheckConstantFunction(expr,
4124 function,
4125 expr->GetReceiverTypes()->first(),
4126 true);
4127 PushAndAdd(new HApplyArguments(function, receiver, length, elements),
4128 expr->position());
4129 return true;
4130 }
4131
4132
4133 void HGraphBuilder::VisitCall(Call* expr) {
4134 Expression* callee = expr->expression();
4135 int argument_count = expr->arguments()->length() + 1; // Plus receiver.
4136 HCall* call = NULL;
4137
4138 Property* prop = callee->AsProperty();
4139 if (prop != NULL) {
4140 if (!prop->key()->IsPropertyName()) {
4141 // Keyed function call.
4142 VisitArgument(prop->obj());
4143 CHECK_BAILOUT;
4144
4145 VISIT_FOR_VALUE(prop->key());
4146 // Push receiver and key like the non-optimized code generator expects it.
4147 HValue* key = Pop();
4148 HValue* receiver = Pop();
4149 Push(key);
4150 Push(receiver);
4151
4152 VisitArgumentList(expr->arguments());
4153 CHECK_BAILOUT;
4154
4155 call = new HCallKeyed(key, argument_count);
4156 ProcessCall(call, expr->position());
4157 HValue* result = Pop();
4158 // Drop the receiver from the environment and put back the result of
4159 // the call.
4160 Drop(1);
4161 Push(result);
4162 return;
4163 }
4164
4165 // Named function call.
4166 expr->RecordTypeFeedback(oracle());
4167
4168 if (TryCallApply(expr)) return;
4169 CHECK_BAILOUT;
4170
4171 HValue* receiver = VisitArgument(prop->obj());
4172 CHECK_BAILOUT;
4173 VisitArgumentList(expr->arguments());
4174 CHECK_BAILOUT;
4175
4176 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
4177
4178 expr->RecordTypeFeedback(oracle());
4179 ZoneMapList* types = expr->GetReceiverTypes();
4180
4181 if (expr->IsMonomorphic()) {
4182 AddCheckConstantFunction(expr, receiver, types->first(), true);
4183
4184 if (TryMathFunctionInline(expr) || TryInline(expr)) {
4185 return;
4186 } else {
4187 // Check for bailout, as the TryInline call in the if condition above
4188 // might return false due to bailout during hydrogen processing.
4189 CHECK_BAILOUT;
4190 call = new HCallConstantFunction(expr->target(), argument_count);
4191 }
4192 } else if (types != NULL && types->length() > 1) {
4193 HandlePolymorphicCallNamed(expr, receiver, types, name);
4194 return;
4195
4196 } else {
4197 call = new HCallNamed(name, argument_count);
4198 }
4199
4200 } else {
4201 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
4202 bool global_call = (var != NULL) && var->is_global() && !var->is_this();
4203
4204 if (!global_call) {
4205 ++argument_count;
4206 VisitArgument(expr->expression());
4207 CHECK_BAILOUT;
4208 }
4209
4210 if (global_call) {
4211 // If there is a global property cell for the name at compile time and
4212 // access check is not enabled we assume that the function will not change
4213 // and generate optimized code for calling the function.
4214 CompilationInfo* info = graph()->info();
4215 bool known_global_function = info->has_global_object() &&
4216 !info->global_object()->IsAccessCheckNeeded() &&
4217 expr->ComputeGlobalTarget(Handle<GlobalObject>(info->global_object()),
4218 var->name());
4219 if (known_global_function) {
4220 // Push the global object instead of the global receiver because
4221 // code generated by the full code generator expects it.
4222 PushAndAdd(new HGlobalObject);
4223 VisitArgumentList(expr->arguments());
4224 CHECK_BAILOUT;
4225
4226 VISIT_FOR_VALUE(expr->expression());
4227 HValue* function = Pop();
4228 AddInstruction(new HCheckFunction(function, expr->target()));
4229
4230 // Replace the global object with the global receiver.
4231 HGlobalReceiver* global_receiver = new HGlobalReceiver;
4232 // Index of the receiver from the top of the expression stack.
4233 const int receiver_index = argument_count - 1;
4234 AddInstruction(global_receiver);
4235 ASSERT(environment()->ExpressionStackAt(receiver_index)->
4236 IsGlobalObject());
4237 environment()->SetExpressionStackAt(receiver_index, global_receiver);
4238
4239 if (TryInline(expr)) return;
4240 // Check for bailout, as trying to inline might fail due to bailout
4241 // during hydrogen processing.
4242 CHECK_BAILOUT;
4243
4244 call = new HCallKnownGlobal(expr->target(), argument_count);
4245 } else {
4246 PushAndAdd(new HGlobalObject);
4247 VisitArgumentList(expr->arguments());
4248 CHECK_BAILOUT;
4249
4250 call = new HCallGlobal(var->name(), argument_count);
4251 }
4252
4253 } else {
4254 PushAndAdd(new HGlobalReceiver);
4255 VisitArgumentList(expr->arguments());
4256 CHECK_BAILOUT;
4257
4258 call = new HCallFunction(argument_count);
4259 }
4260 }
4261
4262 ProcessCall(call, expr->position());
4263 }
4264
4265
4266 void HGraphBuilder::VisitCallNew(CallNew* expr) {
4267 // The constructor function is also used as the receiver argument to the
4268 // JS construct call builtin.
4269 VisitArgument(expr->expression());
4270 CHECK_BAILOUT;
4271 VisitArgumentList(expr->arguments());
4272 CHECK_BAILOUT;
4273
4274 int argument_count = expr->arguments()->length() + 1; // Plus constructor.
4275 HCall* call = new HCallNew(argument_count);
4276
4277 ProcessCall(call, expr->position());
4278 }
4279
4280
4281 // Support for generating inlined runtime functions.
4282
4283 // Lookup table for generators for runtime calls that are generated inline.
4284 // Elements of the table are member pointers to functions of HGraphBuilder.
4285 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \
4286 &HGraphBuilder::Generate##Name,
4287
4288 const HGraphBuilder::InlineFunctionGenerator
4289 HGraphBuilder::kInlineFunctionGenerators[] = {
4290 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
4291 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
4292 };
4293 #undef INLINE_FUNCTION_GENERATOR_ADDRESS
4294
4295
4296 void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
4297 Handle<String> name = expr->name();
4298 if (name->IsEqualTo(CStrVector("_Log"))) {
4299 Push(graph()->GetConstantUndefined());
4300 return;
4301 }
4302
4303 const Runtime::Function* function = expr->function();
4304 if (expr->is_jsruntime()) {
4305 BAILOUT("call to a JavaScript runtime function");
4306 }
4307 ASSERT(function != NULL);
4308
4309 VisitArgumentList(expr->arguments());
4310 CHECK_BAILOUT;
4311
4312 int argument_count = expr->arguments()->length();
4313 if (function->intrinsic_type == Runtime::INLINE) {
4314 ASSERT(name->length() > 0);
4315 ASSERT(name->Get(0) == '_');
4316 // Call to an inline function.
4317 int lookup_index = static_cast<int>(function->function_id) -
4318 static_cast<int>(Runtime::kFirstInlineFunction);
4319 ASSERT(lookup_index >= 0);
4320 ASSERT(static_cast<size_t>(lookup_index) <
4321 ARRAY_SIZE(kInlineFunctionGenerators));
4322 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index];
4323
4324 // Call the inline code generator using the pointer-to-member.
4325 (this->*generator)(argument_count);
4326 } else {
4327 ASSERT(function->intrinsic_type == Runtime::RUNTIME);
4328 HCall* call = new HCallRuntime(name, expr->function(), argument_count);
4329 ProcessCall(call, RelocInfo::kNoPosition);
4330 }
4331 }
4332
4333
4334 void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
4335 Token::Value op = expr->op();
4336 if (op == Token::VOID) {
4337 VISIT_FOR_EFFECT(expr->expression());
4338 Push(graph()->GetConstantUndefined());
4339 } else if (op == Token::DELETE) {
4340 Property* prop = expr->expression()->AsProperty();
4341 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
4342 if (prop == NULL && var == NULL) {
4343 // Result of deleting non-property, non-variable reference is true.
4344 // Evaluate the subexpression for side effects.
4345 VISIT_FOR_EFFECT(expr->expression());
4346 Push(graph_->GetConstantTrue());
4347 } else if (var != NULL &&
4348 !var->is_global() &&
4349 var->AsSlot() != NULL &&
4350 var->AsSlot()->type() != Slot::LOOKUP) {
4351 // Result of deleting non-global, non-dynamic variables is false.
4352 // The subexpression does not have side effects.
4353 Push(graph_->GetConstantFalse());
4354 } else if (prop != NULL) {
4355 VISIT_FOR_VALUE(prop->obj());
4356 VISIT_FOR_VALUE(prop->key());
4357 HValue* key = Pop();
4358 HValue* obj = Pop();
4359 PushAndAdd(new HDeleteProperty(obj, key));
4360 } else if (var->is_global()) {
4361 BAILOUT("delete with global variable");
4362 } else {
4363 BAILOUT("delete with non-global variable");
4364 }
4365 } else if (op == Token::NOT) {
4366 HSubgraph* true_graph = CreateEmptySubgraph();
4367 HSubgraph* false_graph = CreateEmptySubgraph();
4368 VisitCondition(expr->expression(),
4369 false_graph->entry_block(),
4370 true_graph->entry_block(),
4371 true, true);
4372 if (HasStackOverflow()) return;
4373 true_graph->environment()->Push(graph_->GetConstantTrue());
4374 false_graph->environment()->Push(graph_->GetConstantFalse());
4375 current_subgraph_->AppendJoin(true_graph, false_graph, expr);
4376 } else if (op == Token::BIT_NOT || op == Token::SUB) {
4377 VISIT_FOR_VALUE(expr->expression());
4378 HValue* value = Pop();
4379 HInstruction* instr = NULL;
4380 switch (op) {
4381 case Token::BIT_NOT:
4382 instr = new HBitNot(value);
4383 break;
4384 case Token::SUB:
4385 instr = new HMul(graph_->GetConstantMinus1(), value);
4386 break;
4387 default:
4388 UNREACHABLE();
4389 break;
4390 }
4391 PushAndAdd(instr);
4392 } else if (op == Token::TYPEOF) {
4393 VISIT_FOR_VALUE(expr->expression());
4394 HValue* value = Pop();
4395 PushAndAdd(new HTypeof(value));
4396 } else {
4397 BAILOUT("Value: unsupported unary operation");
4398 }
4399 }
4400
4401
4402 void HGraphBuilder::VisitIncrementOperation(IncrementOperation* expr) {
4403 // IncrementOperation is never visited by the visitor. It only
4404 // occurs as a subexpression of CountOperation.
4405 UNREACHABLE();
4406 }
4407
4408
4409 HInstruction* HGraphBuilder::BuildIncrement(HValue* value, bool increment) {
4410 HConstant* delta = increment
4411 ? graph_->GetConstant1()
4412 : graph_->GetConstantMinus1();
4413 HInstruction* instr = new HAdd(value, delta);
4414 AssumeRepresentation(instr, Representation::Integer32());
4415 return instr;
4416 }
4417
4418
4419 void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
4420 IncrementOperation* increment = expr->increment();
4421 Expression* target = increment->expression();
4422 VariableProxy* proxy = target->AsVariableProxy();
4423 Variable* var = proxy->AsVariable();
4424 Property* prop = target->AsProperty();
4425 ASSERT(var == NULL || prop == NULL);
4426 bool inc = expr->op() == Token::INC;
4427
4428 if (var != NULL) {
4429 if (!var->is_global() && !var->IsStackAllocated()) {
4430 BAILOUT("non-stack/non-global variable in count operation");
4431 }
4432
4433 VISIT_FOR_VALUE(target);
4434
4435 HValue* value = Pop();
4436 HInstruction* instr = BuildIncrement(value, inc);
4437 AddInstruction(instr);
4438
4439 if (expr->is_prefix()) {
4440 Push(instr);
4441 } else {
4442 Push(value);
4443 }
4444
4445 if (var->is_global()) {
4446 HandleGlobalVariableAssignment(proxy, instr, expr->position());
4447 } else {
4448 ASSERT(var->IsStackAllocated());
4449 Bind(var, instr);
4450 }
4451
4452 } else if (prop != NULL) {
4453 prop->RecordTypeFeedback(oracle());
4454
4455 if (prop->key()->IsPropertyName()) {
4456 // Named property.
4457
4458 // Match the full code generator stack by simulate an extra stack element
4459 // for postfix operations in a value context.
4460 if (expr->is_postfix() && !ast_context()->IsEffect()) {
4461 Push(graph_->GetConstantUndefined());
4462 }
4463
4464 VISIT_FOR_VALUE(prop->obj());
4465 HValue* obj = Top();
4466
4467 HInstruction* load = NULL;
4468 if (prop->IsMonomorphic()) {
4469 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
4470 Handle<Map> map = prop->GetReceiverTypes()->first();
4471 load = BuildLoadNamed(obj, prop, map, name);
4472 } else {
4473 load = BuildLoadNamedGeneric(obj, prop);
4474 }
4475 PushAndAdd(load);
4476 if (load->HasSideEffects()) AddSimulate(increment->id());
4477
4478 HValue* value = Pop();
4479
4480 HInstruction* instr = BuildIncrement(value, inc);
4481 AddInstruction(instr);
4482
4483 HInstruction* store = BuildStoreNamed(obj, instr, prop);
4484 AddInstruction(store);
4485
4486 // Drop simulated receiver and push the result.
4487 // There is no deoptimization to after the increment, so we can simulate
4488 // the expression stack here.
4489 Drop(1);
4490 if (expr->is_prefix()) {
4491 Push(instr);
4492 } else {
4493 if (!ast_context()->IsEffect()) Drop(1); // Drop simulated zero.
4494 Push(value);
4495 }
4496
4497 } else {
4498 // Keyed property.
4499
4500 // Match the full code generator stack by simulate an extra stack element
4501 // for postfix operations in a value context.
4502 if (expr->is_postfix() && !ast_context()->IsEffect()) {
4503 Push(graph_->GetConstantUndefined());
4504 }
4505
4506 VISIT_FOR_VALUE(prop->obj());
4507 VISIT_FOR_VALUE(prop->key());
4508
4509 HValue* obj = environment()->ExpressionStackAt(1);
4510 HValue* key = environment()->ExpressionStackAt(0);
4511
4512 bool is_fast_elements = prop->IsMonomorphic() &&
4513 prop->GetMonomorphicReceiverType()->has_fast_elements();
4514
4515 HInstruction* load = is_fast_elements
4516 ? BuildLoadKeyedFastElement(obj, key, prop)
4517 : BuildLoadKeyedGeneric(obj, key);
4518 PushAndAdd(load);
4519 if (load->HasSideEffects()) AddSimulate(increment->id());
4520
4521 HValue* value = Pop();
4522
4523 HInstruction* instr = BuildIncrement(value, inc);
4524 AddInstruction(instr);
4525
4526 HInstruction* store = is_fast_elements
4527 ? BuildStoreKeyedFastElement(obj, key, instr, prop)
4528 : new HStoreKeyedGeneric(obj, key, instr);
4529 AddInstruction(store);
4530
4531 // Drop simulated receiver and key and push the result.
4532 // There is no deoptimization to after the increment, so we can simulate
4533 // the expression stack here.
4534 Drop(2);
4535 if (expr->is_prefix()) {
4536 Push(instr);
4537 } else {
4538 if (!ast_context()->IsEffect()) Drop(1); // Drop simulated zero.
4539 Push(value);
4540 }
4541 }
4542 } else {
4543 BAILOUT("invalid lhs in count operation");
4544 }
4545 }
4546
4547
4548 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr,
4549 HValue* left,
4550 HValue* right) {
4551 HInstruction* instr = NULL;
4552 switch (expr->op()) {
4553 case Token::ADD:
4554 instr = new HAdd(left, right);
4555 break;
4556 case Token::SUB:
4557 instr = new HSub(left, right);
4558 break;
4559 case Token::MUL:
4560 instr = new HMul(left, right);
4561 break;
4562 case Token::MOD:
4563 instr = new HMod(left, right);
4564 break;
4565 case Token::DIV:
4566 instr = new HDiv(left, right);
4567 break;
4568 case Token::BIT_XOR:
4569 instr = new HBitXor(left, right);
4570 break;
4571 case Token::BIT_AND:
4572 instr = new HBitAnd(left, right);
4573 break;
4574 case Token::BIT_OR:
4575 instr = new HBitOr(left, right);
4576 break;
4577 case Token::SAR:
4578 instr = new HSar(left, right);
4579 break;
4580 case Token::SHR:
4581 instr = new HShr(left, right);
4582 break;
4583 case Token::SHL:
4584 instr = new HShl(left, right);
4585 break;
4586 default:
4587 UNREACHABLE();
4588 }
4589 TypeInfo info = oracle()->BinaryType(expr, TypeFeedbackOracle::RESULT);
4590 // If we hit an uninitialized binary op stub we will get type info
4591 // for a smi operation. If one of the operands is a constant string
4592 // do not generate code assuming it is a smi operation.
4593 if (info.IsSmi() &&
4594 ((left->IsConstant() && HConstant::cast(left)->HasStringValue()) ||
4595 (right->IsConstant() && HConstant::cast(right)->HasStringValue()))) {
4596 return instr;
4597 }
4598 if (FLAG_trace_representation) {
4599 PrintF("Info: %s/%s\n", info.ToString(), ToRepresentation(info).Mnemonic());
4600 }
4601 AssumeRepresentation(instr, ToRepresentation(info));
4602 return instr;
4603 }
4604
4605
4606 // Check for the form (%_ClassOf(foo) === 'BarClass').
4607 static bool IsClassOfTest(CompareOperation* expr) {
4608 if (expr->op() != Token::EQ_STRICT) return false;
4609 CallRuntime* call = expr->left()->AsCallRuntime();
4610 if (call == NULL) return false;
4611 Literal* literal = expr->right()->AsLiteral();
4612 if (literal == NULL) return false;
4613 if (!literal->handle()->IsString()) return false;
4614 if (!call->name()->IsEqualTo(CStrVector("_ClassOf"))) return false;
4615 ASSERT(call->arguments()->length() == 1);
4616 return true;
4617 }
4618
4619
4620 void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
4621 if (expr->op() == Token::COMMA) {
4622 VISIT_FOR_EFFECT(expr->left());
4623 VISIT_FOR_VALUE(expr->right());
4624 } else if (expr->op() == Token::AND || expr->op() == Token::OR) {
4625 VISIT_FOR_VALUE(expr->left());
4626 ASSERT(current_subgraph_->HasExit());
4627
4628 HValue* left = Top();
4629 bool is_logical_and = (expr->op() == Token::AND);
4630
4631 HEnvironment* environment_copy = environment()->Copy();
4632 environment_copy->Pop();
4633 HSubgraph* right_subgraph;
4634 right_subgraph = CreateBranchSubgraph(environment_copy);
4635 ADD_TO_SUBGRAPH(right_subgraph, expr->right());
4636 current_subgraph_->AppendOptional(right_subgraph, is_logical_and, left);
4637 current_subgraph_->exit_block()->SetJoinId(expr->id());
4638 } else {
4639 VISIT_FOR_VALUE(expr->left());
4640 VISIT_FOR_VALUE(expr->right());
4641
4642 HValue* right = Pop();
4643 HValue* left = Pop();
4644 HInstruction* instr = BuildBinaryOperation(expr, left, right);
4645 PushAndAdd(instr, expr->position());
4646 }
4647 }
4648
4649
4650 void HGraphBuilder::AssumeRepresentation(HValue* value, Representation r) {
4651 if (value->CheckFlag(HValue::kFlexibleRepresentation)) {
4652 if (FLAG_trace_representation) {
4653 PrintF("Assume representation for %s to be %s (%d)\n",
4654 value->Mnemonic(),
4655 r.Mnemonic(),
4656 graph_->GetMaximumValueID());
4657 }
4658 value->ChangeRepresentation(r);
4659 // The representation of the value is dictated by type feedback.
4660 value->ClearFlag(HValue::kFlexibleRepresentation);
4661 } else if (FLAG_trace_representation) {
4662 PrintF("No representation assumed\n");
4663 }
4664 }
4665
4666
4667 Representation HGraphBuilder::ToRepresentation(TypeInfo info) {
4668 if (info.IsSmi()) return Representation::Integer32();
4669 if (info.IsInteger32()) return Representation::Integer32();
4670 if (info.IsDouble()) return Representation::Double();
4671 if (info.IsNumber()) return Representation::Double();
4672 return Representation::Tagged();
4673 }
4674
4675
4676 void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
4677 if (IsClassOfTest(expr)) {
4678 CallRuntime* call = expr->left()->AsCallRuntime();
4679 VISIT_FOR_VALUE(call->arguments()->at(0));
4680 HValue* value = Pop();
4681 Literal* literal = expr->right()->AsLiteral();
4682 Handle<String> rhs = Handle<String>::cast(literal->handle());
4683 HInstruction* instr = new HClassOfTest(value, rhs);
4684 PushAndAdd(instr, expr->position());
4685 return;
4686 }
4687
4688 // Check for the pattern: typeof <expression> == <string literal>.
4689 UnaryOperation* left_unary = expr->left()->AsUnaryOperation();
4690 Literal* right_literal = expr->right()->AsLiteral();
4691 if ((expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT) &&
4692 left_unary != NULL && left_unary->op() == Token::TYPEOF &&
4693 right_literal != NULL && right_literal->handle()->IsString()) {
4694 VISIT_FOR_VALUE(left_unary->expression());
4695 HValue* left = Pop();
4696 HInstruction* instr = new HTypeofIs(left,
4697 Handle<String>::cast(right_literal->handle()));
4698 PushAndAdd(instr, expr->position());
4699 return;
4700 }
4701
4702 VISIT_FOR_VALUE(expr->left());
4703 VISIT_FOR_VALUE(expr->right());
4704
4705 HValue* right = Pop();
4706 HValue* left = Pop();
4707 Token::Value op = expr->op();
4708
4709 TypeInfo info = oracle()->CompareType(expr, TypeFeedbackOracle::RESULT);
4710 HInstruction* instr = NULL;
4711 if (op == Token::INSTANCEOF) {
4712 instr = new HInstanceOf(left, right);
4713 } else if (op == Token::IN) {
4714 BAILOUT("Unsupported comparison: in");
4715 } else if (info.IsNonPrimitive()) {
4716 switch (op) {
4717 case Token::EQ:
4718 case Token::EQ_STRICT: {
4719 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(left));
4720 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(right));
4721 instr = new HCompareJSObjectEq(left, right);
4722 break;
4723 }
4724 default:
4725 BAILOUT("Unsupported non-primitive compare");
4726 break;
4727 }
4728 } else {
4729 HCompare* compare = new HCompare(left, right, op);
4730 Representation r = ToRepresentation(info);
4731 compare->SetInputRepresentation(r);
4732 instr = compare;
4733 }
4734 PushAndAdd(instr, expr->position());
4735 }
4736
4737
4738 void HGraphBuilder::VisitCompareToNull(CompareToNull* expr) {
4739 VISIT_FOR_VALUE(expr->expression());
4740
4741 HValue* value = Pop();
4742 HIsNull* compare = new HIsNull(value, expr->is_strict());
4743
4744 PushAndAdd(compare);
4745 }
4746
4747
4748 void HGraphBuilder::VisitThisFunction(ThisFunction* expr) {
4749 BAILOUT("ThisFunction");
4750 }
4751
4752
4753 void HGraphBuilder::VisitDeclaration(Declaration* decl) {
4754 // We allow only declarations that do not require code generation.
4755 // The following all require code generation: global variables and
4756 // functions, variables with slot type LOOKUP, declarations with
4757 // mode CONST, and functions.
4758 Variable* var = decl->proxy()->var();
4759 Slot* slot = var->AsSlot();
4760 if (var->is_global() ||
4761 (slot != NULL && slot->type() == Slot::LOOKUP) ||
4762 decl->mode() == Variable::CONST ||
4763 decl->fun() != NULL) {
4764 BAILOUT("unsupported declaration");
4765 }
4766 }
4767
4768
4769 // Generators for inline runtime functions.
4770 // Support for types.
4771 void HGraphBuilder::GenerateIsSmi(int argument_count) {
4772 ASSERT(argument_count == 1);
4773
4774 HValue* value = Pop();
4775 PushAndAdd(new HIsSmi(value));
4776 }
4777
4778
4779 void HGraphBuilder::GenerateIsSpecObject(int argument_count) {
4780 ASSERT(argument_count == 1);
4781
4782 HValue* value = Pop();
4783 HHasInstanceType* test =
4784 new HHasInstanceType(value, FIRST_JS_OBJECT_TYPE, LAST_TYPE);
4785 PushAndAdd(test);
4786 }
4787
4788
4789 void HGraphBuilder::GenerateIsFunction(int argument_count) {
4790 ASSERT(argument_count == 1);
4791
4792 HValue* value = Pop();
4793 HHasInstanceType* test =
4794 new HHasInstanceType(value, JS_FUNCTION_TYPE);
4795 PushAndAdd(test);
4796 }
4797
4798
4799 void HGraphBuilder::GenerateHasCachedArrayIndex(int argument_count) {
4800 ASSERT(argument_count == 1);
4801
4802 HValue* value = Pop();
4803 HHasCachedArrayIndex* spec_test = new HHasCachedArrayIndex(value);
4804 PushAndAdd(spec_test);
4805 }
4806
4807
4808 void HGraphBuilder::GenerateIsArray(int argument_count) {
4809 ASSERT(argument_count == 1);
4810
4811 HValue* value = Pop();
4812 HHasInstanceType* test =
4813 new HHasInstanceType(value, JS_ARRAY_TYPE);
4814 PushAndAdd(test);
4815 }
4816
4817
4818 void HGraphBuilder::GenerateIsRegExp(int argument_count) {
4819 ASSERT(argument_count == 1);
4820
4821 HValue* value = Pop();
4822 HHasInstanceType* test =
4823 new HHasInstanceType(value, JS_REGEXP_TYPE);
4824 PushAndAdd(test);
4825 }
4826
4827
4828 void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count) {
4829 BAILOUT("inlined runtime function: IsNonNegativeSmi");
4830 }
4831
4832
4833 void HGraphBuilder::GenerateIsObject(int argument_count) {
4834 BAILOUT("inlined runtime function: IsObject");
4835 }
4836
4837
4838 void HGraphBuilder::GenerateIsUndetectableObject(int argument_count) {
4839 BAILOUT("inlined runtime function: IsUndetectableObject");
4840 }
4841
4842
4843 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf(
4844 int argument_count) {
4845 BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf");
4846 }
4847
4848
4849 // Support for construct call checks.
4850 void HGraphBuilder::GenerateIsConstructCall(int argument_count) {
4851 BAILOUT("inlined runtime function: IsConstructCall");
4852 }
4853
4854
4855 // Support for arguments.length and arguments[?].
4856 void HGraphBuilder::GenerateArgumentsLength(int argument_count) {
4857 ASSERT(argument_count == 0);
4858 HInstruction* elements = AddInstruction(new HArgumentsElements);
4859 PushAndAdd(new HArgumentsLength(elements));
4860 }
4861
4862
4863 void HGraphBuilder::GenerateArguments(int argument_count) {
4864 ASSERT(argument_count == 1);
4865 HValue* index = Pop();
4866 HInstruction* elements = AddInstruction(new HArgumentsElements);
4867 HInstruction* length = AddInstruction(new HArgumentsLength(elements));
4868 PushAndAdd(new HAccessArgumentsAt(elements, length, index));
4869 }
4870
4871
4872 // Support for accessing the class and value fields of an object.
4873 void HGraphBuilder::GenerateClassOf(int argument_count) {
4874 // The special form detected by IsClassOfTest is detected before we get here
4875 // and does not cause a bailout.
4876 BAILOUT("inlined runtime function: ClassOf");
4877 }
4878
4879
4880 void HGraphBuilder::GenerateValueOf(int argument_count) {
4881 ASSERT(argument_count == 1);
4882
4883 HValue* value = Pop();
4884 HValueOf* op = new HValueOf(value);
4885 PushAndAdd(op);
4886 }
4887
4888
4889 void HGraphBuilder::GenerateSetValueOf(int argument_count) {
4890 BAILOUT("inlined runtime function: SetValueOf");
4891 }
4892
4893
4894 // Fast support for charCodeAt(n).
4895 void HGraphBuilder::GenerateStringCharCodeAt(int argument_count) {
4896 BAILOUT("inlined runtime function: StringCharCodeAt");
4897 }
4898
4899
4900 // Fast support for string.charAt(n) and string[n].
4901 void HGraphBuilder::GenerateStringCharFromCode(int argument_count) {
4902 BAILOUT("inlined runtime function: StringCharFromCode");
4903 }
4904
4905
4906 // Fast support for string.charAt(n) and string[n].
4907 void HGraphBuilder::GenerateStringCharAt(int argument_count) {
4908 ASSERT_EQ(2, argument_count);
4909 PushArgumentsForStubCall(argument_count);
4910 PushAndAdd(new HCallStub(CodeStub::StringCharAt, argument_count),
4911 RelocInfo::kNoPosition);
4912 }
4913
4914
4915 // Fast support for object equality testing.
4916 void HGraphBuilder::GenerateObjectEquals(int argument_count) {
4917 ASSERT(argument_count == 2);
4918
4919 HValue* right = Pop();
4920 HValue* left = Pop();
4921 PushAndAdd(new HCompareJSObjectEq(left, right));
4922 }
4923
4924
4925 void HGraphBuilder::GenerateLog(int argument_count) {
4926 UNREACHABLE(); // We caught this in VisitCallRuntime.
4927 }
4928
4929
4930 // Fast support for Math.random().
4931 void HGraphBuilder::GenerateRandomHeapNumber(int argument_count) {
4932 BAILOUT("inlined runtime function: RandomHeapNumber");
4933 }
4934
4935
4936 // Fast support for StringAdd.
4937 void HGraphBuilder::GenerateStringAdd(int argument_count) {
4938 ASSERT_EQ(2, argument_count);
4939 PushArgumentsForStubCall(argument_count);
4940 PushAndAdd(new HCallStub(CodeStub::StringAdd, argument_count),
4941 RelocInfo::kNoPosition);
4942 }
4943
4944
4945 // Fast support for SubString.
4946 void HGraphBuilder::GenerateSubString(int argument_count) {
4947 ASSERT_EQ(3, argument_count);
4948 PushArgumentsForStubCall(argument_count);
4949 PushAndAdd(new HCallStub(CodeStub::SubString, argument_count),
4950 RelocInfo::kNoPosition);
4951 }
4952
4953
4954 // Fast support for StringCompare.
4955 void HGraphBuilder::GenerateStringCompare(int argument_count) {
4956 ASSERT_EQ(2, argument_count);
4957 PushArgumentsForStubCall(argument_count);
4958 PushAndAdd(new HCallStub(CodeStub::StringCompare, argument_count),
4959 RelocInfo::kNoPosition);
4960 }
4961
4962
4963 // Support for direct calls from JavaScript to native RegExp code.
4964 void HGraphBuilder::GenerateRegExpExec(int argument_count) {
4965 ASSERT_EQ(4, argument_count);
4966 PushArgumentsForStubCall(argument_count);
4967 PushAndAdd(new HCallStub(CodeStub::RegExpExec, argument_count),
4968 RelocInfo::kNoPosition);
4969 }
4970
4971
4972 // Construct a RegExp exec result with two in-object properties.
4973 void HGraphBuilder::GenerateRegExpConstructResult(int argument_count) {
4974 ASSERT_EQ(3, argument_count);
4975 PushArgumentsForStubCall(argument_count);
4976 PushAndAdd(new HCallStub(CodeStub::RegExpConstructResult, argument_count),
4977 RelocInfo::kNoPosition);
4978 }
4979
4980
4981 // Support for fast native caches.
4982 void HGraphBuilder::GenerateGetFromCache(int argument_count) {
4983 BAILOUT("inlined runtime function: GetFromCache");
4984 }
4985
4986
4987 // Fast support for number to string.
4988 void HGraphBuilder::GenerateNumberToString(int argument_count) {
4989 ASSERT_EQ(1, argument_count);
4990 PushArgumentsForStubCall(argument_count);
4991 PushAndAdd(new HCallStub(CodeStub::NumberToString, argument_count),
4992 RelocInfo::kNoPosition);
4993 }
4994
4995
4996 // Fast swapping of elements. Takes three expressions, the object and two
4997 // indices. This should only be used if the indices are known to be
4998 // non-negative and within bounds of the elements array at the call site.
4999 void HGraphBuilder::GenerateSwapElements(int argument_count) {
5000 BAILOUT("inlined runtime function: SwapElements");
5001 }
5002
5003
5004 // Fast call for custom callbacks.
5005 void HGraphBuilder::GenerateCallFunction(int argument_count) {
5006 BAILOUT("inlined runtime function: CallFunction");
5007 }
5008
5009
5010 // Fast call to math functions.
5011 void HGraphBuilder::GenerateMathPow(int argument_count) {
5012 ASSERT_EQ(2, argument_count);
5013 PushArgumentsForStubCall(argument_count);
5014 PushAndAdd(new HCallStub(CodeStub::MathPow, argument_count),
5015 RelocInfo::kNoPosition);
5016 }
5017
5018
5019 void HGraphBuilder::GenerateMathSin(int argument_count) {
5020 ASSERT_EQ(1, argument_count);
5021 PushArgumentsForStubCall(argument_count);
5022 HCallStub* instr =
5023 new HCallStub(CodeStub::TranscendentalCache, argument_count);
5024 instr->set_transcendental_type(TranscendentalCache::SIN);
5025 PushAndAdd(instr, RelocInfo::kNoPosition);
5026 }
5027
5028
5029 void HGraphBuilder::GenerateMathCos(int argument_count) {
5030 ASSERT_EQ(1, argument_count);
5031 PushArgumentsForStubCall(argument_count);
5032 HCallStub* instr =
5033 new HCallStub(CodeStub::TranscendentalCache, argument_count);
5034 instr->set_transcendental_type(TranscendentalCache::COS);
5035 PushAndAdd(instr, RelocInfo::kNoPosition);
5036 }
5037
5038
5039 void HGraphBuilder::GenerateMathLog(int argument_count) {
5040 ASSERT_EQ(1, argument_count);
5041 PushArgumentsForStubCall(argument_count);
5042 HCallStub* instr =
5043 new HCallStub(CodeStub::TranscendentalCache, argument_count);
5044 instr->set_transcendental_type(TranscendentalCache::LOG);
5045 PushAndAdd(instr, RelocInfo::kNoPosition);
5046 }
5047
5048
5049 void HGraphBuilder::GenerateMathSqrt(int argument_count) {
5050 BAILOUT("inlined runtime function: MathSqrt");
5051 }
5052
5053
5054 // Check whether two RegExps are equivalent
5055 void HGraphBuilder::GenerateIsRegExpEquivalent(int argument_count) {
5056 BAILOUT("inlined runtime function: IsRegExpEquivalent");
5057 }
5058
5059
5060 void HGraphBuilder::GenerateGetCachedArrayIndex(int argument_count) {
5061 BAILOUT("inlined runtime function: GetCachedArrayIndex");
5062 }
5063
5064
5065 void HGraphBuilder::GenerateFastAsciiArrayJoin(int argument_count) {
5066 BAILOUT("inlined runtime function: FastAsciiArrayJoin");
5067 }
5068
5069
5070 #undef BAILOUT
5071 #undef CHECK_BAILOUT
5072 #undef VISIT_FOR_EFFECT
5073 #undef VISIT_FOR_VALUE
5074 #undef ADD_TO_SUBGRAPH
5075
5076
5077 HEnvironment::HEnvironment(HEnvironment* outer,
5078 Scope* scope,
5079 Handle<JSFunction> closure)
5080 : closure_(closure),
5081 values_(0),
5082 assigned_variables_(4),
5083 parameter_count_(0),
5084 local_count_(0),
5085 outer_(outer),
5086 pop_count_(0),
5087 push_count_(0),
5088 ast_id_(AstNode::kNoNumber) {
5089 Initialize(scope->num_parameters() + 1, scope->num_stack_slots(), 0);
5090 }
5091
5092
5093 HEnvironment::HEnvironment(const HEnvironment* other)
5094 : values_(0),
5095 assigned_variables_(0),
5096 parameter_count_(0),
5097 local_count_(0),
5098 outer_(NULL),
5099 pop_count_(0),
5100 push_count_(0),
5101 ast_id_(other->ast_id()) {
5102 Initialize(other);
5103 }
5104
5105
5106 void HEnvironment::Initialize(int parameter_count,
5107 int local_count,
5108 int stack_height) {
5109 parameter_count_ = parameter_count;
5110 local_count_ = local_count;
5111
5112 // Avoid reallocating the temporaries' backing store on the first Push.
5113 int total = parameter_count + local_count + stack_height;
5114 values_.Initialize(total + 4);
5115 for (int i = 0; i < total; ++i) values_.Add(NULL);
5116 }
5117
5118
5119 void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) {
5120 ASSERT(!block->IsLoopHeader());
5121 ASSERT(values_.length() == other->values_.length());
5122
5123 int length = values_.length();
5124 for (int i = 0; i < length; ++i) {
5125 HValue* value = values_[i];
5126 if (value != NULL && value->IsPhi() && value->block() == block) {
5127 // There is already a phi for the i'th value.
5128 HPhi* phi = HPhi::cast(value);
5129 // Assert index is correct and that we haven't missed an incoming edge.
5130 ASSERT(phi->merged_index() == i);
5131 ASSERT(phi->OperandCount() == block->predecessors()->length());
5132 phi->AddInput(other->values_[i]);
5133 } else if (values_[i] != other->values_[i]) {
5134 // There is a fresh value on the incoming edge, a phi is needed.
5135 ASSERT(values_[i] != NULL && other->values_[i] != NULL);
5136 HPhi* phi = new HPhi(i);
5137 HValue* old_value = values_[i];
5138 for (int j = 0; j < block->predecessors()->length(); j++) {
5139 phi->AddInput(old_value);
5140 }
5141 phi->AddInput(other->values_[i]);
5142 this->values_[i] = phi;
5143 block->AddPhi(phi);
5144 }
5145 }
5146 }
5147
5148
5149 void HEnvironment::Initialize(const HEnvironment* other) {
5150 closure_ = other->closure();
5151 values_.AddAll(other->values_);
5152 assigned_variables_.AddAll(other->assigned_variables_);
5153 parameter_count_ = other->parameter_count_;
5154 local_count_ = other->local_count_;
5155 if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy.
5156 pop_count_ = other->pop_count_;
5157 push_count_ = other->push_count_;
5158 ast_id_ = other->ast_id_;
5159 }
5160
5161
5162 int HEnvironment::IndexFor(Variable* variable) const {
5163 Slot* slot = variable->AsSlot();
5164 ASSERT(slot != NULL && slot->IsStackAllocated());
5165 if (slot->type() == Slot::PARAMETER) {
5166 return slot->index() + 1;
5167 } else {
5168 return parameter_count_ + slot->index();
5169 }
5170 }
5171
5172
5173 HEnvironment* HEnvironment::Copy() const {
5174 return new HEnvironment(this);
5175 }
5176
5177
5178 HEnvironment* HEnvironment::CopyWithoutHistory() const {
5179 HEnvironment* result = Copy();
5180 result->ClearHistory();
5181 return result;
5182 }
5183
5184
5185 HEnvironment* HEnvironment::CopyAsLoopHeader(HBasicBlock* loop_header) const {
5186 HEnvironment* new_env = Copy();
5187 for (int i = 0; i < values_.length(); ++i) {
5188 HPhi* phi = new HPhi(i);
5189 phi->AddInput(values_[i]);
5190 new_env->values_[i] = phi;
5191 loop_header->AddPhi(phi);
5192 }
5193 new_env->ClearHistory();
5194 return new_env;
5195 }
5196
5197
5198 HEnvironment* HEnvironment::CopyForInlining(Handle<JSFunction> target,
5199 FunctionLiteral* function,
5200 bool is_speculative,
5201 HConstant* undefined) const {
5202 // Outer environment is a copy of this one without the arguments.
5203 int arity = function->scope()->num_parameters();
5204 HEnvironment* outer = Copy();
5205 outer->Drop(arity + 1); // Including receiver.
5206 outer->ClearHistory();
5207 HEnvironment* inner = new HEnvironment(outer, function->scope(), target);
5208 // Get the argument values from the original environment.
5209 if (is_speculative) {
5210 for (int i = 0; i <= arity; ++i) { // Include receiver.
5211 HValue* push = ExpressionStackAt(arity - i);
5212 inner->SetValueAt(i, push);
5213 }
5214 } else {
5215 for (int i = 0; i <= arity; ++i) { // Include receiver.
5216 inner->SetValueAt(i, ExpressionStackAt(arity - i));
5217 }
5218 }
5219
5220 // Initialize the stack-allocated locals to undefined.
5221 int local_base = arity + 1;
5222 int local_count = function->scope()->num_stack_slots();
5223 for (int i = 0; i < local_count; ++i) {
5224 inner->SetValueAt(local_base + i, undefined);
5225 }
5226
5227 inner->set_ast_id(function->id());
5228 return inner;
5229 }
5230
5231
5232 void HEnvironment::PrintTo(StringStream* stream) {
5233 for (int i = 0; i < total_count(); i++) {
5234 if (i == 0) stream->Add("parameters\n");
5235 if (i == parameter_count()) stream->Add("locals\n");
5236 if (i == parameter_count() + local_count()) stream->Add("expressions");
5237 HValue* val = values_.at(i);
5238 stream->Add("%d: ", i);
5239 if (val != NULL) {
5240 val->PrintNameTo(stream);
5241 } else {
5242 stream->Add("NULL");
5243 }
5244 stream->Add("\n");
5245 }
5246 }
5247
5248
5249 void HEnvironment::PrintToStd() {
5250 HeapStringAllocator string_allocator;
5251 StringStream trace(&string_allocator);
5252 PrintTo(&trace);
5253 PrintF("%s", *trace.ToCString());
5254 }
5255
5256
5257 void HTracer::TraceCompilation(FunctionLiteral* function) {
5258 Tag tag(this, "compilation");
5259 Handle<String> name = function->debug_name();
5260 PrintStringProperty("name", *name->ToCString());
5261 PrintStringProperty("method", *name->ToCString());
5262 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis()));
5263 }
5264
5265
5266 void HTracer::TraceLithium(const char* name, LChunk* chunk) {
5267 Trace(name, chunk->graph(), chunk);
5268 }
5269
5270
5271 void HTracer::TraceHydrogen(const char* name, HGraph* graph) {
5272 Trace(name, graph, NULL);
5273 }
5274
5275
5276 void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) {
5277 Tag tag(this, "cfg");
5278 PrintStringProperty("name", name);
5279 const ZoneList<HBasicBlock*>* blocks = graph->blocks();
5280 for (int i = 0; i < blocks->length(); i++) {
5281 HBasicBlock* current = blocks->at(i);
5282 Tag block_tag(this, "block");
5283 PrintBlockProperty("name", current->block_id());
5284 PrintIntProperty("from_bci", -1);
5285 PrintIntProperty("to_bci", -1);
5286
5287 if (!current->predecessors()->is_empty()) {
5288 PrintIndent();
5289 trace_.Add("predecessors");
5290 for (int j = 0; j < current->predecessors()->length(); ++j) {
5291 trace_.Add(" \"B%d\"", current->predecessors()->at(j)->block_id());
5292 }
5293 trace_.Add("\n");
5294 } else {
5295 PrintEmptyProperty("predecessors");
5296 }
5297
5298 if (current->end() == NULL || current->end()->FirstSuccessor() == NULL) {
5299 PrintEmptyProperty("successors");
5300 } else if (current->end()->SecondSuccessor() == NULL) {
5301 PrintBlockProperty("successors",
5302 current->end()->FirstSuccessor()->block_id());
5303 } else {
5304 PrintBlockProperty("successors",
5305 current->end()->FirstSuccessor()->block_id(),
5306 current->end()->SecondSuccessor()->block_id());
5307 }
5308
5309 PrintEmptyProperty("xhandlers");
5310 PrintEmptyProperty("flags");
5311
5312 if (current->dominator() != NULL) {
5313 PrintBlockProperty("dominator", current->dominator()->block_id());
5314 }
5315
5316 if (chunk != NULL) {
5317 int first_index = current->first_instruction_index();
5318 int last_index = current->last_instruction_index();
5319 PrintIntProperty(
5320 "first_lir_id",
5321 LifetimePosition::FromInstructionIndex(first_index).Value());
5322 PrintIntProperty(
5323 "last_lir_id",
5324 LifetimePosition::FromInstructionIndex(last_index).Value());
5325 }
5326
5327 {
5328 Tag states_tag(this, "states");
5329 Tag locals_tag(this, "locals");
5330 int total = current->phis()->length();
5331 trace_.Add("size %d\n", total);
5332 trace_.Add("method \"None\"");
5333 for (int j = 0; j < total; ++j) {
5334 HPhi* phi = current->phis()->at(j);
5335 trace_.Add("%d ", phi->merged_index());
5336 phi->PrintNameTo(&trace_);
5337 trace_.Add(" ");
5338 phi->PrintTo(&trace_);
5339 trace_.Add("\n");
5340 }
5341 }
5342
5343 {
5344 Tag HIR_tag(this, "HIR");
5345 HInstruction* instruction = current->first();
5346 while (instruction != NULL) {
5347 int bci = 0;
5348 int uses = instruction->uses()->length();
5349 trace_.Add("%d %d ", bci, uses);
5350 instruction->PrintNameTo(&trace_);
5351 trace_.Add(" ");
5352 instruction->PrintTo(&trace_);
5353 trace_.Add(" <|@\n");
5354 instruction = instruction->next();
5355 }
5356 }
5357
5358
5359 if (chunk != NULL) {
5360 Tag LIR_tag(this, "LIR");
5361 int first_index = current->first_instruction_index();
5362 int last_index = current->last_instruction_index();
5363 if (first_index != -1 && last_index != -1) {
5364 const ZoneList<LInstruction*>* instructions = chunk->instructions();
5365 for (int i = first_index; i <= last_index; ++i) {
5366 LInstruction* linstr = instructions->at(i);
5367 if (linstr != NULL) {
5368 trace_.Add("%d ",
5369 LifetimePosition::FromInstructionIndex(i).Value());
5370 linstr->PrintTo(&trace_);
5371 trace_.Add(" <|@\n");
5372 }
5373 }
5374 }
5375 }
5376 }
5377 }
5378
5379
5380 void HTracer::TraceLiveRanges(const char* name, LAllocator* allocator) {
5381 Tag tag(this, "intervals");
5382 PrintStringProperty("name", name);
5383
5384 const ZoneList<LiveRange*>* fixed_d = allocator->fixed_double_live_ranges();
5385 for (int i = 0; i < fixed_d->length(); ++i) {
5386 TraceLiveRange(fixed_d->at(i), "fixed");
5387 }
5388
5389 const ZoneList<LiveRange*>* fixed = allocator->fixed_live_ranges();
5390 for (int i = 0; i < fixed->length(); ++i) {
5391 TraceLiveRange(fixed->at(i), "fixed");
5392 }
5393
5394 const ZoneList<LiveRange*>* live_ranges = allocator->live_ranges();
5395 for (int i = 0; i < live_ranges->length(); ++i) {
5396 TraceLiveRange(live_ranges->at(i), "object");
5397 }
5398 }
5399
5400
5401 void HTracer::TraceLiveRange(LiveRange* range, const char* type) {
5402 if (range != NULL && !range->IsEmpty()) {
5403 trace_.Add("%d %s", range->id(), type);
5404 if (range->HasRegisterAssigned()) {
5405 LOperand* op = range->CreateAssignedOperand();
5406 int assigned_reg = op->index();
5407 if (op->IsDoubleRegister()) {
5408 trace_.Add(" \"%s\"",
5409 DoubleRegister::AllocationIndexToString(assigned_reg));
5410 } else {
5411 ASSERT(op->IsRegister());
5412 trace_.Add(" \"%s\"", Register::AllocationIndexToString(assigned_reg));
5413 }
5414 } else if (range->IsSpilled()) {
5415 LOperand* op = range->TopLevel()->GetSpillOperand();
5416 if (op->IsDoubleStackSlot()) {
5417 trace_.Add(" \"double_stack:%d\"", op->index());
5418 } else {
5419 ASSERT(op->IsStackSlot());
5420 trace_.Add(" \"stack:%d\"", op->index());
5421 }
5422 }
5423 int parent_index = -1;
5424 if (range->IsChild()) {
5425 parent_index = range->parent()->id();
5426 } else {
5427 parent_index = range->id();
5428 }
5429 LOperand* op = range->FirstHint();
5430 int hint_index = -1;
5431 if (op != NULL && op->IsUnallocated()) hint_index = op->VirtualRegister();
5432 trace_.Add(" %d %d", parent_index, hint_index);
5433 UseInterval* cur_interval = range->first_interval();
5434 while (cur_interval != NULL) {
5435 trace_.Add(" [%d, %d[",
5436 cur_interval->start().Value(),
5437 cur_interval->end().Value());
5438 cur_interval = cur_interval->next();
5439 }
5440
5441 UsePosition* current_pos = range->first_pos();
5442 while (current_pos != NULL) {
5443 if (current_pos->RegisterIsBeneficial()) {
5444 trace_.Add(" %d M", current_pos->pos().Value());
5445 }
5446 current_pos = current_pos->next();
5447 }
5448
5449 trace_.Add(" \"\"\n");
5450 }
5451 }
5452
5453
5454 void HTracer::FlushToFile() {
5455 AppendChars(filename_, *trace_.ToCString(), trace_.length(), false);
5456 trace_.Reset();
5457 }
5458
5459
5460 void HStatistics::Print() {
5461 PrintF("Timing results:\n");
5462 int64_t sum = 0;
5463 for (int i = 0; i < timing_.length(); ++i) {
5464 sum += timing_[i];
5465 }
5466
5467 for (int i = 0; i < names_.length(); ++i) {
5468 PrintF("%30s", names_[i]);
5469 double ms = static_cast<double>(timing_[i]) / 1000;
5470 double percent = static_cast<double>(timing_[i]) * 100 / sum;
5471 PrintF(" - %0.3f ms / %0.3f %% \n", ms, percent);
5472 }
5473 PrintF("%30s - %0.3f ms \n", "Sum", static_cast<double>(sum) / 1000);
5474 PrintF("---------------------------------------------------------------\n");
5475 PrintF("%30s - %0.3f ms (%0.1f times slower than full code gen)\n",
5476 "Total",
5477 static_cast<double>(total_) / 1000,
5478 static_cast<double>(total_) / full_code_gen_);
5479 }
5480
5481
5482 void HStatistics::SaveTiming(const char* name, int64_t ticks) {
5483 if (name == HPhase::kFullCodeGen) {
5484 full_code_gen_ += ticks;
5485 } else if (name == HPhase::kTotal) {
5486 total_ += ticks;
5487 } else {
5488 for (int i = 0; i < names_.length(); ++i) {
5489 if (names_[i] == name) {
5490 timing_[i] += ticks;
5491 return;
5492 }
5493 }
5494 names_.Add(name);
5495 timing_.Add(ticks);
5496 }
5497 }
5498
5499
5500 const char* const HPhase::kFullCodeGen = "Full code generator";
5501 const char* const HPhase::kTotal = "Total";
5502
5503
5504 void HPhase::Begin(const char* name,
5505 HGraph* graph,
5506 LChunk* chunk,
5507 LAllocator* allocator) {
5508 name_ = name;
5509 graph_ = graph;
5510 chunk_ = chunk;
5511 allocator_ = allocator;
5512 if (allocator != NULL && chunk_ == NULL) {
5513 chunk_ = allocator->chunk();
5514 }
5515 if (FLAG_time_hydrogen) start_ = OS::Ticks();
5516 }
5517
5518
5519 void HPhase::End() const {
5520 if (FLAG_time_hydrogen) {
5521 int64_t end = OS::Ticks();
5522 HStatistics::Instance()->SaveTiming(name_, end - start_);
5523 }
5524
5525 if (FLAG_trace_hydrogen) {
5526 if (graph_ != NULL) HTracer::Instance()->TraceHydrogen(name_, graph_);
5527 if (chunk_ != NULL) HTracer::Instance()->TraceLithium(name_, chunk_);
5528 if (allocator_ != NULL) {
5529 HTracer::Instance()->TraceLiveRanges(name_, allocator_);
5530 }
5531 }
5532
5533 #ifdef DEBUG
5534 if (graph_ != NULL) graph_->Verify();
5535 if (chunk_ != NULL) chunk_->Verify();
5536 if (allocator_ != NULL) allocator_->Verify();
5537 #endif
5538 }
5539
5540 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698