• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 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 "v8.h"
29 #include "hydrogen.h"
30 
31 #include "codegen.h"
32 #include "full-codegen.h"
33 #include "hashmap.h"
34 #include "lithium-allocator.h"
35 #include "parser.h"
36 #include "scopeinfo.h"
37 #include "scopes.h"
38 #include "stub-cache.h"
39 
40 #if V8_TARGET_ARCH_IA32
41 #include "ia32/lithium-codegen-ia32.h"
42 #elif V8_TARGET_ARCH_X64
43 #include "x64/lithium-codegen-x64.h"
44 #elif V8_TARGET_ARCH_ARM
45 #include "arm/lithium-codegen-arm.h"
46 #elif V8_TARGET_ARCH_MIPS
47 #include "mips/lithium-codegen-mips.h"
48 #else
49 #error Unsupported target architecture.
50 #endif
51 
52 namespace v8 {
53 namespace internal {
54 
HBasicBlock(HGraph * graph)55 HBasicBlock::HBasicBlock(HGraph* graph)
56     : block_id_(graph->GetNextBlockID()),
57       graph_(graph),
58       phis_(4),
59       first_(NULL),
60       last_(NULL),
61       end_(NULL),
62       loop_information_(NULL),
63       predecessors_(2),
64       dominator_(NULL),
65       dominated_blocks_(4),
66       last_environment_(NULL),
67       argument_count_(-1),
68       first_instruction_index_(-1),
69       last_instruction_index_(-1),
70       deleted_phis_(4),
71       parent_loop_header_(NULL),
72       is_inline_return_target_(false),
73       is_deoptimizing_(false),
74       dominates_loop_successors_(false) { }
75 
76 
AttachLoopInformation()77 void HBasicBlock::AttachLoopInformation() {
78   ASSERT(!IsLoopHeader());
79   loop_information_ = new(zone()) HLoopInformation(this);
80 }
81 
82 
DetachLoopInformation()83 void HBasicBlock::DetachLoopInformation() {
84   ASSERT(IsLoopHeader());
85   loop_information_ = NULL;
86 }
87 
88 
AddPhi(HPhi * phi)89 void HBasicBlock::AddPhi(HPhi* phi) {
90   ASSERT(!IsStartBlock());
91   phis_.Add(phi);
92   phi->SetBlock(this);
93 }
94 
95 
RemovePhi(HPhi * phi)96 void HBasicBlock::RemovePhi(HPhi* phi) {
97   ASSERT(phi->block() == this);
98   ASSERT(phis_.Contains(phi));
99   ASSERT(phi->HasNoUses() || !phi->is_live());
100   phi->Kill();
101   phis_.RemoveElement(phi);
102   phi->SetBlock(NULL);
103 }
104 
105 
AddInstruction(HInstruction * instr)106 void HBasicBlock::AddInstruction(HInstruction* instr) {
107   ASSERT(!IsStartBlock() || !IsFinished());
108   ASSERT(!instr->IsLinked());
109   ASSERT(!IsFinished());
110   if (first_ == NULL) {
111     HBlockEntry* entry = new(zone()) HBlockEntry();
112     entry->InitializeAsFirst(this);
113     first_ = last_ = entry;
114   }
115   instr->InsertAfter(last_);
116   last_ = instr;
117 }
118 
119 
CreateDeoptimize(HDeoptimize::UseEnvironment has_uses)120 HDeoptimize* HBasicBlock::CreateDeoptimize(
121     HDeoptimize::UseEnvironment has_uses) {
122   ASSERT(HasEnvironment());
123   if (has_uses == HDeoptimize::kNoUses) return new(zone()) HDeoptimize(0);
124 
125   HEnvironment* environment = last_environment();
126   HDeoptimize* instr = new(zone()) HDeoptimize(environment->length());
127   for (int i = 0; i < environment->length(); i++) {
128     HValue* val = environment->values()->at(i);
129     instr->AddEnvironmentValue(val);
130   }
131 
132   return instr;
133 }
134 
135 
CreateSimulate(int ast_id)136 HSimulate* HBasicBlock::CreateSimulate(int ast_id) {
137   ASSERT(HasEnvironment());
138   HEnvironment* environment = last_environment();
139   ASSERT(ast_id == AstNode::kNoNumber ||
140          environment->closure()->shared()->VerifyBailoutId(ast_id));
141 
142   int push_count = environment->push_count();
143   int pop_count = environment->pop_count();
144 
145   HSimulate* instr = new(zone()) HSimulate(ast_id, pop_count);
146   for (int i = push_count - 1; i >= 0; --i) {
147     instr->AddPushedValue(environment->ExpressionStackAt(i));
148   }
149   for (int i = 0; i < environment->assigned_variables()->length(); ++i) {
150     int index = environment->assigned_variables()->at(i);
151     instr->AddAssignedValue(index, environment->Lookup(index));
152   }
153   environment->ClearHistory();
154   return instr;
155 }
156 
157 
Finish(HControlInstruction * end)158 void HBasicBlock::Finish(HControlInstruction* end) {
159   ASSERT(!IsFinished());
160   AddInstruction(end);
161   end_ = end;
162   for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
163     it.Current()->RegisterPredecessor(this);
164   }
165 }
166 
167 
Goto(HBasicBlock * block,bool drop_extra)168 void HBasicBlock::Goto(HBasicBlock* block, bool drop_extra) {
169   if (block->IsInlineReturnTarget()) {
170     AddInstruction(new(zone()) HLeaveInlined);
171     last_environment_ = last_environment()->DiscardInlined(drop_extra);
172   }
173   AddSimulate(AstNode::kNoNumber);
174   HGoto* instr = new(zone()) HGoto(block);
175   Finish(instr);
176 }
177 
178 
AddLeaveInlined(HValue * return_value,HBasicBlock * target,bool drop_extra)179 void HBasicBlock::AddLeaveInlined(HValue* return_value,
180                                   HBasicBlock* target,
181                                   bool drop_extra) {
182   ASSERT(target->IsInlineReturnTarget());
183   ASSERT(return_value != NULL);
184   AddInstruction(new(zone()) HLeaveInlined);
185   last_environment_ = last_environment()->DiscardInlined(drop_extra);
186   last_environment()->Push(return_value);
187   AddSimulate(AstNode::kNoNumber);
188   HGoto* instr = new(zone()) HGoto(target);
189   Finish(instr);
190 }
191 
192 
SetInitialEnvironment(HEnvironment * env)193 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) {
194   ASSERT(!HasEnvironment());
195   ASSERT(first() == NULL);
196   UpdateEnvironment(env);
197 }
198 
199 
SetJoinId(int ast_id)200 void HBasicBlock::SetJoinId(int ast_id) {
201   int length = predecessors_.length();
202   ASSERT(length > 0);
203   for (int i = 0; i < length; i++) {
204     HBasicBlock* predecessor = predecessors_[i];
205     ASSERT(predecessor->end()->IsGoto());
206     HSimulate* simulate = HSimulate::cast(predecessor->end()->previous());
207     // We only need to verify the ID once.
208     ASSERT(i != 0 ||
209            predecessor->last_environment()->closure()->shared()
210                ->VerifyBailoutId(ast_id));
211     simulate->set_ast_id(ast_id);
212   }
213 }
214 
215 
Dominates(HBasicBlock * other) const216 bool HBasicBlock::Dominates(HBasicBlock* other) const {
217   HBasicBlock* current = other->dominator();
218   while (current != NULL) {
219     if (current == this) return true;
220     current = current->dominator();
221   }
222   return false;
223 }
224 
225 
LoopNestingDepth() const226 int HBasicBlock::LoopNestingDepth() const {
227   const HBasicBlock* current = this;
228   int result  = (current->IsLoopHeader()) ? 1 : 0;
229   while (current->parent_loop_header() != NULL) {
230     current = current->parent_loop_header();
231     result++;
232   }
233   return result;
234 }
235 
236 
PostProcessLoopHeader(IterationStatement * stmt)237 void HBasicBlock::PostProcessLoopHeader(IterationStatement* stmt) {
238   ASSERT(IsLoopHeader());
239 
240   SetJoinId(stmt->EntryId());
241   if (predecessors()->length() == 1) {
242     // This is a degenerated loop.
243     DetachLoopInformation();
244     return;
245   }
246 
247   // Only the first entry into the loop is from outside the loop. All other
248   // entries must be back edges.
249   for (int i = 1; i < predecessors()->length(); ++i) {
250     loop_information()->RegisterBackEdge(predecessors()->at(i));
251   }
252 }
253 
254 
RegisterPredecessor(HBasicBlock * pred)255 void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) {
256   if (HasPredecessor()) {
257     // Only loop header blocks can have a predecessor added after
258     // instructions have been added to the block (they have phis for all
259     // values in the environment, these phis may be eliminated later).
260     ASSERT(IsLoopHeader() || first_ == NULL);
261     HEnvironment* incoming_env = pred->last_environment();
262     if (IsLoopHeader()) {
263       ASSERT(phis()->length() == incoming_env->length());
264       for (int i = 0; i < phis_.length(); ++i) {
265         phis_[i]->AddInput(incoming_env->values()->at(i));
266       }
267     } else {
268       last_environment()->AddIncomingEdge(this, pred->last_environment());
269     }
270   } else if (!HasEnvironment() && !IsFinished()) {
271     ASSERT(!IsLoopHeader());
272     SetInitialEnvironment(pred->last_environment()->Copy());
273   }
274 
275   predecessors_.Add(pred);
276 }
277 
278 
AddDominatedBlock(HBasicBlock * block)279 void HBasicBlock::AddDominatedBlock(HBasicBlock* block) {
280   ASSERT(!dominated_blocks_.Contains(block));
281   // Keep the list of dominated blocks sorted such that if there is two
282   // succeeding block in this list, the predecessor is before the successor.
283   int index = 0;
284   while (index < dominated_blocks_.length() &&
285          dominated_blocks_[index]->block_id() < block->block_id()) {
286     ++index;
287   }
288   dominated_blocks_.InsertAt(index, block);
289 }
290 
291 
AssignCommonDominator(HBasicBlock * other)292 void HBasicBlock::AssignCommonDominator(HBasicBlock* other) {
293   if (dominator_ == NULL) {
294     dominator_ = other;
295     other->AddDominatedBlock(this);
296   } else if (other->dominator() != NULL) {
297     HBasicBlock* first = dominator_;
298     HBasicBlock* second = other;
299 
300     while (first != second) {
301       if (first->block_id() > second->block_id()) {
302         first = first->dominator();
303       } else {
304         second = second->dominator();
305       }
306       ASSERT(first != NULL && second != NULL);
307     }
308 
309     if (dominator_ != first) {
310       ASSERT(dominator_->dominated_blocks_.Contains(this));
311       dominator_->dominated_blocks_.RemoveElement(this);
312       dominator_ = first;
313       first->AddDominatedBlock(this);
314     }
315   }
316 }
317 
318 
AssignLoopSuccessorDominators()319 void HBasicBlock::AssignLoopSuccessorDominators() {
320   // Mark blocks that dominate all subsequent reachable blocks inside their
321   // loop. Exploit the fact that blocks are sorted in reverse post order. When
322   // the loop is visited in increasing block id order, if the number of
323   // non-loop-exiting successor edges at the dominator_candidate block doesn't
324   // exceed the number of previously encountered predecessor edges, there is no
325   // path from the loop header to any block with higher id that doesn't go
326   // through the dominator_candidate block. In this case, the
327   // dominator_candidate block is guaranteed to dominate all blocks reachable
328   // from it with higher ids.
329   HBasicBlock* last = loop_information()->GetLastBackEdge();
330   int outstanding_successors = 1;  // one edge from the pre-header
331   // Header always dominates everything.
332   MarkAsLoopSuccessorDominator();
333   for (int j = block_id(); j <= last->block_id(); ++j) {
334     HBasicBlock* dominator_candidate = graph_->blocks()->at(j);
335     for (HPredecessorIterator it(dominator_candidate); !it.Done();
336          it.Advance()) {
337       HBasicBlock* predecessor = it.Current();
338       // Don't count back edges.
339       if (predecessor->block_id() < dominator_candidate->block_id()) {
340         outstanding_successors--;
341       }
342     }
343 
344     // If more successors than predecessors have been seen in the loop up to
345     // now, it's not possible to guarantee that the current block dominates
346     // all of the blocks with higher IDs. In this case, assume conservatively
347     // that those paths through loop that don't go through the current block
348     // contain all of the loop's dependencies. Also be careful to record
349     // dominator information about the current loop that's being processed,
350     // and not nested loops, which will be processed when
351     // AssignLoopSuccessorDominators gets called on their header.
352     ASSERT(outstanding_successors >= 0);
353     HBasicBlock* parent_loop_header = dominator_candidate->parent_loop_header();
354     if (outstanding_successors == 0 &&
355         (parent_loop_header == this && !dominator_candidate->IsLoopHeader())) {
356       dominator_candidate->MarkAsLoopSuccessorDominator();
357     }
358     HControlInstruction* end = dominator_candidate->end();
359     for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
360       HBasicBlock* successor = it.Current();
361       // Only count successors that remain inside the loop and don't loop back
362       // to a loop header.
363       if (successor->block_id() > dominator_candidate->block_id() &&
364           successor->block_id() <= last->block_id()) {
365         // Backwards edges must land on loop headers.
366         ASSERT(successor->block_id() > dominator_candidate->block_id() ||
367                successor->IsLoopHeader());
368         outstanding_successors++;
369       }
370     }
371   }
372 }
373 
374 
PredecessorIndexOf(HBasicBlock * predecessor) const375 int HBasicBlock::PredecessorIndexOf(HBasicBlock* predecessor) const {
376   for (int i = 0; i < predecessors_.length(); ++i) {
377     if (predecessors_[i] == predecessor) return i;
378   }
379   UNREACHABLE();
380   return -1;
381 }
382 
383 
384 #ifdef DEBUG
Verify()385 void HBasicBlock::Verify() {
386   // Check that every block is finished.
387   ASSERT(IsFinished());
388   ASSERT(block_id() >= 0);
389 
390   // Check that the incoming edges are in edge split form.
391   if (predecessors_.length() > 1) {
392     for (int i = 0; i < predecessors_.length(); ++i) {
393       ASSERT(predecessors_[i]->end()->SecondSuccessor() == NULL);
394     }
395   }
396 }
397 #endif
398 
399 
RegisterBackEdge(HBasicBlock * block)400 void HLoopInformation::RegisterBackEdge(HBasicBlock* block) {
401   this->back_edges_.Add(block);
402   AddBlock(block);
403 }
404 
405 
GetLastBackEdge() const406 HBasicBlock* HLoopInformation::GetLastBackEdge() const {
407   int max_id = -1;
408   HBasicBlock* result = NULL;
409   for (int i = 0; i < back_edges_.length(); ++i) {
410     HBasicBlock* cur = back_edges_[i];
411     if (cur->block_id() > max_id) {
412       max_id = cur->block_id();
413       result = cur;
414     }
415   }
416   return result;
417 }
418 
419 
AddBlock(HBasicBlock * block)420 void HLoopInformation::AddBlock(HBasicBlock* block) {
421   if (block == loop_header()) return;
422   if (block->parent_loop_header() == loop_header()) return;
423   if (block->parent_loop_header() != NULL) {
424     AddBlock(block->parent_loop_header());
425   } else {
426     block->set_parent_loop_header(loop_header());
427     blocks_.Add(block);
428     for (int i = 0; i < block->predecessors()->length(); ++i) {
429       AddBlock(block->predecessors()->at(i));
430     }
431   }
432 }
433 
434 
435 #ifdef DEBUG
436 
437 // Checks reachability of the blocks in this graph and stores a bit in
438 // the BitVector "reachable()" for every block that can be reached
439 // from the start block of the graph. If "dont_visit" is non-null, the given
440 // block is treated as if it would not be part of the graph. "visited_count()"
441 // returns the number of reachable blocks.
442 class ReachabilityAnalyzer BASE_EMBEDDED {
443  public:
ReachabilityAnalyzer(HBasicBlock * entry_block,int block_count,HBasicBlock * dont_visit)444   ReachabilityAnalyzer(HBasicBlock* entry_block,
445                        int block_count,
446                        HBasicBlock* dont_visit)
447       : visited_count_(0),
448         stack_(16),
449         reachable_(block_count, ZONE),
450         dont_visit_(dont_visit) {
451     PushBlock(entry_block);
452     Analyze();
453   }
454 
visited_count() const455   int visited_count() const { return visited_count_; }
reachable() const456   const BitVector* reachable() const { return &reachable_; }
457 
458  private:
PushBlock(HBasicBlock * block)459   void PushBlock(HBasicBlock* block) {
460     if (block != NULL && block != dont_visit_ &&
461         !reachable_.Contains(block->block_id())) {
462       reachable_.Add(block->block_id());
463       stack_.Add(block);
464       visited_count_++;
465     }
466   }
467 
Analyze()468   void Analyze() {
469     while (!stack_.is_empty()) {
470       HControlInstruction* end = stack_.RemoveLast()->end();
471       for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
472         PushBlock(it.Current());
473       }
474     }
475   }
476 
477   int visited_count_;
478   ZoneList<HBasicBlock*> stack_;
479   BitVector reachable_;
480   HBasicBlock* dont_visit_;
481 };
482 
483 
Verify(bool do_full_verify) const484 void HGraph::Verify(bool do_full_verify) const {
485   for (int i = 0; i < blocks_.length(); i++) {
486     HBasicBlock* block = blocks_.at(i);
487 
488     block->Verify();
489 
490     // Check that every block contains at least one node and that only the last
491     // node is a control instruction.
492     HInstruction* current = block->first();
493     ASSERT(current != NULL && current->IsBlockEntry());
494     while (current != NULL) {
495       ASSERT((current->next() == NULL) == current->IsControlInstruction());
496       ASSERT(current->block() == block);
497       current->Verify();
498       current = current->next();
499     }
500 
501     // Check that successors are correctly set.
502     HBasicBlock* first = block->end()->FirstSuccessor();
503     HBasicBlock* second = block->end()->SecondSuccessor();
504     ASSERT(second == NULL || first != NULL);
505 
506     // Check that the predecessor array is correct.
507     if (first != NULL) {
508       ASSERT(first->predecessors()->Contains(block));
509       if (second != NULL) {
510         ASSERT(second->predecessors()->Contains(block));
511       }
512     }
513 
514     // Check that phis have correct arguments.
515     for (int j = 0; j < block->phis()->length(); j++) {
516       HPhi* phi = block->phis()->at(j);
517       phi->Verify();
518     }
519 
520     // Check that all join blocks have predecessors that end with an
521     // unconditional goto and agree on their environment node id.
522     if (block->predecessors()->length() >= 2) {
523       int id = block->predecessors()->first()->last_environment()->ast_id();
524       for (int k = 0; k < block->predecessors()->length(); k++) {
525         HBasicBlock* predecessor = block->predecessors()->at(k);
526         ASSERT(predecessor->end()->IsGoto());
527         ASSERT(predecessor->last_environment()->ast_id() == id);
528       }
529     }
530   }
531 
532   // Check special property of first block to have no predecessors.
533   ASSERT(blocks_.at(0)->predecessors()->is_empty());
534 
535   if (do_full_verify) {
536     // Check that the graph is fully connected.
537     ReachabilityAnalyzer analyzer(entry_block_, blocks_.length(), NULL);
538     ASSERT(analyzer.visited_count() == blocks_.length());
539 
540     // Check that entry block dominator is NULL.
541     ASSERT(entry_block_->dominator() == NULL);
542 
543     // Check dominators.
544     for (int i = 0; i < blocks_.length(); ++i) {
545       HBasicBlock* block = blocks_.at(i);
546       if (block->dominator() == NULL) {
547         // Only start block may have no dominator assigned to.
548         ASSERT(i == 0);
549       } else {
550         // Assert that block is unreachable if dominator must not be visited.
551         ReachabilityAnalyzer dominator_analyzer(entry_block_,
552                                                 blocks_.length(),
553                                                 block->dominator());
554         ASSERT(!dominator_analyzer.reachable()->Contains(block->block_id()));
555       }
556     }
557   }
558 }
559 
560 #endif
561 
562 
GetConstant(SetOncePointer<HConstant> * pointer,Object * value)563 HConstant* HGraph::GetConstant(SetOncePointer<HConstant>* pointer,
564                                Object* value) {
565   if (!pointer->is_set()) {
566     HConstant* constant = new(zone()) HConstant(Handle<Object>(value),
567                                                 Representation::Tagged());
568     constant->InsertAfter(GetConstantUndefined());
569     pointer->set(constant);
570   }
571   return pointer->get();
572 }
573 
574 
GetConstant1()575 HConstant* HGraph::GetConstant1() {
576   return GetConstant(&constant_1_, Smi::FromInt(1));
577 }
578 
579 
GetConstantMinus1()580 HConstant* HGraph::GetConstantMinus1() {
581   return GetConstant(&constant_minus1_, Smi::FromInt(-1));
582 }
583 
584 
GetConstantTrue()585 HConstant* HGraph::GetConstantTrue() {
586   return GetConstant(&constant_true_, isolate()->heap()->true_value());
587 }
588 
589 
GetConstantFalse()590 HConstant* HGraph::GetConstantFalse() {
591   return GetConstant(&constant_false_, isolate()->heap()->false_value());
592 }
593 
594 
GetConstantHole()595 HConstant* HGraph::GetConstantHole() {
596   return GetConstant(&constant_hole_, isolate()->heap()->the_hole_value());
597 }
598 
599 
HGraphBuilder(CompilationInfo * info,TypeFeedbackOracle * oracle)600 HGraphBuilder::HGraphBuilder(CompilationInfo* info,
601                              TypeFeedbackOracle* oracle)
602     : function_state_(NULL),
603       initial_function_state_(this, info, oracle, NORMAL_RETURN),
604       ast_context_(NULL),
605       break_scope_(NULL),
606       graph_(NULL),
607       current_block_(NULL),
608       inlined_count_(0),
609       zone_(info->isolate()->zone()),
610       inline_bailout_(false) {
611   // This is not initialized in the initializer list because the
612   // constructor for the initial state relies on function_state_ == NULL
613   // to know it's the initial state.
614   function_state_= &initial_function_state_;
615 }
616 
CreateJoin(HBasicBlock * first,HBasicBlock * second,int join_id)617 HBasicBlock* HGraphBuilder::CreateJoin(HBasicBlock* first,
618                                        HBasicBlock* second,
619                                        int join_id) {
620   if (first == NULL) {
621     return second;
622   } else if (second == NULL) {
623     return first;
624   } else {
625     HBasicBlock* join_block = graph_->CreateBasicBlock();
626     first->Goto(join_block);
627     second->Goto(join_block);
628     join_block->SetJoinId(join_id);
629     return join_block;
630   }
631 }
632 
633 
JoinContinue(IterationStatement * statement,HBasicBlock * exit_block,HBasicBlock * continue_block)634 HBasicBlock* HGraphBuilder::JoinContinue(IterationStatement* statement,
635                                          HBasicBlock* exit_block,
636                                          HBasicBlock* continue_block) {
637   if (continue_block != NULL) {
638     if (exit_block != NULL) exit_block->Goto(continue_block);
639     continue_block->SetJoinId(statement->ContinueId());
640     return continue_block;
641   }
642   return exit_block;
643 }
644 
645 
CreateLoop(IterationStatement * statement,HBasicBlock * loop_entry,HBasicBlock * body_exit,HBasicBlock * loop_successor,HBasicBlock * break_block)646 HBasicBlock* HGraphBuilder::CreateLoop(IterationStatement* statement,
647                                        HBasicBlock* loop_entry,
648                                        HBasicBlock* body_exit,
649                                        HBasicBlock* loop_successor,
650                                        HBasicBlock* break_block) {
651   if (body_exit != NULL) body_exit->Goto(loop_entry);
652   loop_entry->PostProcessLoopHeader(statement);
653   if (break_block != NULL) {
654     if (loop_successor != NULL) loop_successor->Goto(break_block);
655     break_block->SetJoinId(statement->ExitId());
656     return break_block;
657   }
658   return loop_successor;
659 }
660 
661 
FinishExit(HControlInstruction * instruction)662 void HBasicBlock::FinishExit(HControlInstruction* instruction) {
663   Finish(instruction);
664   ClearEnvironment();
665 }
666 
667 
HGraph(CompilationInfo * info)668 HGraph::HGraph(CompilationInfo* info)
669     : isolate_(info->isolate()),
670       next_block_id_(0),
671       entry_block_(NULL),
672       blocks_(8),
673       values_(16),
674       phi_list_(NULL) {
675   start_environment_ =
676       new(zone()) HEnvironment(NULL, info->scope(), info->closure());
677   start_environment_->set_ast_id(AstNode::kFunctionEntryId);
678   entry_block_ = CreateBasicBlock();
679   entry_block_->SetInitialEnvironment(start_environment_);
680 }
681 
682 
Compile(CompilationInfo * info)683 Handle<Code> HGraph::Compile(CompilationInfo* info) {
684   int values = GetMaximumValueID();
685   if (values > LUnallocated::kMaxVirtualRegisters) {
686     if (FLAG_trace_bailout) {
687       PrintF("Not enough virtual registers for (values).\n");
688     }
689     return Handle<Code>::null();
690   }
691   LAllocator allocator(values, this);
692   LChunkBuilder builder(info, this, &allocator);
693   LChunk* chunk = builder.Build();
694   if (chunk == NULL) return Handle<Code>::null();
695 
696   if (!allocator.Allocate(chunk)) {
697     if (FLAG_trace_bailout) {
698       PrintF("Not enough virtual registers (regalloc).\n");
699     }
700     return Handle<Code>::null();
701   }
702 
703   MacroAssembler assembler(info->isolate(), NULL, 0);
704   LCodeGen generator(chunk, &assembler, info);
705 
706   chunk->MarkEmptyBlocks();
707 
708   if (generator.GenerateCode()) {
709     if (FLAG_trace_codegen) {
710       PrintF("Crankshaft Compiler - ");
711     }
712     CodeGenerator::MakeCodePrologue(info);
713     Code::Flags flags = Code::ComputeFlags(Code::OPTIMIZED_FUNCTION);
714     Handle<Code> code =
715         CodeGenerator::MakeCodeEpilogue(&assembler, flags, info);
716     generator.FinishCode(code);
717     CodeGenerator::PrintCode(code, info);
718     return code;
719   }
720   return Handle<Code>::null();
721 }
722 
723 
CreateBasicBlock()724 HBasicBlock* HGraph::CreateBasicBlock() {
725   HBasicBlock* result = new(zone()) HBasicBlock(this);
726   blocks_.Add(result);
727   return result;
728 }
729 
730 
Canonicalize()731 void HGraph::Canonicalize() {
732   if (!FLAG_use_canonicalizing) return;
733   HPhase phase("H_Canonicalize", this);
734   for (int i = 0; i < blocks()->length(); ++i) {
735     HInstruction* instr = blocks()->at(i)->first();
736     while (instr != NULL) {
737       HValue* value = instr->Canonicalize();
738       if (value != instr) instr->DeleteAndReplaceWith(value);
739       instr = instr->next();
740     }
741   }
742 }
743 
744 
OrderBlocks()745 void HGraph::OrderBlocks() {
746   HPhase phase("H_Block ordering");
747   BitVector visited(blocks_.length(), zone());
748 
749   ZoneList<HBasicBlock*> reverse_result(8);
750   HBasicBlock* start = blocks_[0];
751   Postorder(start, &visited, &reverse_result, NULL);
752 
753   blocks_.Rewind(0);
754   int index = 0;
755   for (int i = reverse_result.length() - 1; i >= 0; --i) {
756     HBasicBlock* b = reverse_result[i];
757     blocks_.Add(b);
758     b->set_block_id(index++);
759   }
760 }
761 
762 
PostorderLoopBlocks(HLoopInformation * loop,BitVector * visited,ZoneList<HBasicBlock * > * order,HBasicBlock * loop_header)763 void HGraph::PostorderLoopBlocks(HLoopInformation* loop,
764                                  BitVector* visited,
765                                  ZoneList<HBasicBlock*>* order,
766                                  HBasicBlock* loop_header) {
767   for (int i = 0; i < loop->blocks()->length(); ++i) {
768     HBasicBlock* b = loop->blocks()->at(i);
769     for (HSuccessorIterator it(b->end()); !it.Done(); it.Advance()) {
770       Postorder(it.Current(), visited, order, loop_header);
771     }
772     if (b->IsLoopHeader() && b != loop->loop_header()) {
773       PostorderLoopBlocks(b->loop_information(), visited, order, loop_header);
774     }
775   }
776 }
777 
778 
Postorder(HBasicBlock * block,BitVector * visited,ZoneList<HBasicBlock * > * order,HBasicBlock * loop_header)779 void HGraph::Postorder(HBasicBlock* block,
780                        BitVector* visited,
781                        ZoneList<HBasicBlock*>* order,
782                        HBasicBlock* loop_header) {
783   if (block == NULL || visited->Contains(block->block_id())) return;
784   if (block->parent_loop_header() != loop_header) return;
785   visited->Add(block->block_id());
786   if (block->IsLoopHeader()) {
787     PostorderLoopBlocks(block->loop_information(), visited, order, loop_header);
788     for (HSuccessorIterator it(block->end()); !it.Done(); it.Advance()) {
789       Postorder(it.Current(), visited, order, block);
790     }
791   } else {
792     ASSERT(block->IsFinished());
793     for (HSuccessorIterator it(block->end()); !it.Done(); it.Advance()) {
794       Postorder(it.Current(), visited, order, loop_header);
795     }
796   }
797   ASSERT(block->end()->FirstSuccessor() == NULL ||
798          order->Contains(block->end()->FirstSuccessor()) ||
799          block->end()->FirstSuccessor()->IsLoopHeader());
800   ASSERT(block->end()->SecondSuccessor() == NULL ||
801          order->Contains(block->end()->SecondSuccessor()) ||
802          block->end()->SecondSuccessor()->IsLoopHeader());
803   order->Add(block);
804 }
805 
806 
AssignDominators()807 void HGraph::AssignDominators() {
808   HPhase phase("H_Assign dominators", this);
809   for (int i = 0; i < blocks_.length(); ++i) {
810     HBasicBlock* block = blocks_[i];
811     if (block->IsLoopHeader()) {
812       // Only the first predecessor of a loop header is from outside the loop.
813       // All others are back edges, and thus cannot dominate the loop header.
814       block->AssignCommonDominator(block->predecessors()->first());
815       block->AssignLoopSuccessorDominators();
816     } else {
817       for (int j = blocks_[i]->predecessors()->length() - 1; j >= 0; --j) {
818         blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j));
819       }
820     }
821   }
822 }
823 
824 // Mark all blocks that are dominated by an unconditional soft deoptimize to
825 // prevent code motion across those blocks.
PropagateDeoptimizingMark()826 void HGraph::PropagateDeoptimizingMark() {
827   HPhase phase("H_Propagate deoptimizing mark", this);
828   MarkAsDeoptimizingRecursively(entry_block());
829 }
830 
MarkAsDeoptimizingRecursively(HBasicBlock * block)831 void HGraph::MarkAsDeoptimizingRecursively(HBasicBlock* block) {
832   for (int i = 0; i < block->dominated_blocks()->length(); ++i) {
833     HBasicBlock* dominated = block->dominated_blocks()->at(i);
834     if (block->IsDeoptimizing()) dominated->MarkAsDeoptimizing();
835     MarkAsDeoptimizingRecursively(dominated);
836   }
837 }
838 
EliminateRedundantPhis()839 void HGraph::EliminateRedundantPhis() {
840   HPhase phase("H_Redundant phi elimination", this);
841 
842   // Worklist of phis that can potentially be eliminated. Initialized with
843   // all phi nodes. When elimination of a phi node modifies another phi node
844   // the modified phi node is added to the worklist.
845   ZoneList<HPhi*> worklist(blocks_.length());
846   for (int i = 0; i < blocks_.length(); ++i) {
847     worklist.AddAll(*blocks_[i]->phis());
848   }
849 
850   while (!worklist.is_empty()) {
851     HPhi* phi = worklist.RemoveLast();
852     HBasicBlock* block = phi->block();
853 
854     // Skip phi node if it was already replaced.
855     if (block == NULL) continue;
856 
857     // Get replacement value if phi is redundant.
858     HValue* replacement = phi->GetRedundantReplacement();
859 
860     if (replacement != NULL) {
861       // Iterate through the uses and replace them all.
862       for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
863         HValue* value = it.value();
864         value->SetOperandAt(it.index(), replacement);
865         if (value->IsPhi()) worklist.Add(HPhi::cast(value));
866       }
867       block->RemovePhi(phi);
868     }
869   }
870 }
871 
872 
EliminateUnreachablePhis()873 void HGraph::EliminateUnreachablePhis() {
874   HPhase phase("H_Unreachable phi elimination", this);
875 
876   // Initialize worklist.
877   ZoneList<HPhi*> phi_list(blocks_.length());
878   ZoneList<HPhi*> worklist(blocks_.length());
879   for (int i = 0; i < blocks_.length(); ++i) {
880     for (int j = 0; j < blocks_[i]->phis()->length(); j++) {
881       HPhi* phi = blocks_[i]->phis()->at(j);
882       phi_list.Add(phi);
883       // We can't eliminate phis in the receiver position in the environment
884       // because in case of throwing an error we need this value to
885       // construct a stack trace.
886       if (phi->HasRealUses() || phi->IsReceiver())  {
887         phi->set_is_live(true);
888         worklist.Add(phi);
889       }
890     }
891   }
892 
893   // Iteratively mark live phis.
894   while (!worklist.is_empty()) {
895     HPhi* phi = worklist.RemoveLast();
896     for (int i = 0; i < phi->OperandCount(); i++) {
897       HValue* operand = phi->OperandAt(i);
898       if (operand->IsPhi() && !HPhi::cast(operand)->is_live()) {
899         HPhi::cast(operand)->set_is_live(true);
900         worklist.Add(HPhi::cast(operand));
901       }
902     }
903   }
904 
905   // Remove unreachable phis.
906   for (int i = 0; i < phi_list.length(); i++) {
907     HPhi* phi = phi_list[i];
908     if (!phi->is_live()) {
909       HBasicBlock* block = phi->block();
910       block->RemovePhi(phi);
911       block->RecordDeletedPhi(phi->merged_index());
912     }
913   }
914 }
915 
916 
CheckArgumentsPhiUses()917 bool HGraph::CheckArgumentsPhiUses() {
918   int block_count = blocks_.length();
919   for (int i = 0; i < block_count; ++i) {
920     for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
921       HPhi* phi = blocks_[i]->phis()->at(j);
922       // We don't support phi uses of arguments for now.
923       if (phi->CheckFlag(HValue::kIsArguments)) return false;
924     }
925   }
926   return true;
927 }
928 
929 
CheckConstPhiUses()930 bool HGraph::CheckConstPhiUses() {
931   int block_count = blocks_.length();
932   for (int i = 0; i < block_count; ++i) {
933     for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
934       HPhi* phi = blocks_[i]->phis()->at(j);
935       // Check for the hole value (from an uninitialized const).
936       for (int k = 0; k < phi->OperandCount(); k++) {
937         if (phi->OperandAt(k) == GetConstantHole()) return false;
938       }
939     }
940   }
941   return true;
942 }
943 
944 
CollectPhis()945 void HGraph::CollectPhis() {
946   int block_count = blocks_.length();
947   phi_list_ = new ZoneList<HPhi*>(block_count);
948   for (int i = 0; i < block_count; ++i) {
949     for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
950       HPhi* phi = blocks_[i]->phis()->at(j);
951       phi_list_->Add(phi);
952     }
953   }
954 }
955 
956 
InferTypes(ZoneList<HValue * > * worklist)957 void HGraph::InferTypes(ZoneList<HValue*>* worklist) {
958   BitVector in_worklist(GetMaximumValueID(), zone());
959   for (int i = 0; i < worklist->length(); ++i) {
960     ASSERT(!in_worklist.Contains(worklist->at(i)->id()));
961     in_worklist.Add(worklist->at(i)->id());
962   }
963 
964   while (!worklist->is_empty()) {
965     HValue* current = worklist->RemoveLast();
966     in_worklist.Remove(current->id());
967     if (current->UpdateInferredType()) {
968       for (HUseIterator it(current->uses()); !it.Done(); it.Advance()) {
969         HValue* use = it.value();
970         if (!in_worklist.Contains(use->id())) {
971           in_worklist.Add(use->id());
972           worklist->Add(use);
973         }
974       }
975     }
976   }
977 }
978 
979 
980 class HRangeAnalysis BASE_EMBEDDED {
981  public:
HRangeAnalysis(HGraph * graph)982   explicit HRangeAnalysis(HGraph* graph) :
983       graph_(graph), zone_(graph->isolate()->zone()), changed_ranges_(16) { }
984 
985   void Analyze();
986 
987  private:
988   void TraceRange(const char* msg, ...);
989   void Analyze(HBasicBlock* block);
990   void InferControlFlowRange(HCompareIDAndBranch* test, HBasicBlock* dest);
991   void UpdateControlFlowRange(Token::Value op, HValue* value, HValue* other);
992   void InferRange(HValue* value);
993   void RollBackTo(int index);
994   void AddRange(HValue* value, Range* range);
995 
996   HGraph* graph_;
997   Zone* zone_;
998   ZoneList<HValue*> changed_ranges_;
999 };
1000 
1001 
TraceRange(const char * msg,...)1002 void HRangeAnalysis::TraceRange(const char* msg, ...) {
1003   if (FLAG_trace_range) {
1004     va_list arguments;
1005     va_start(arguments, msg);
1006     OS::VPrint(msg, arguments);
1007     va_end(arguments);
1008   }
1009 }
1010 
1011 
Analyze()1012 void HRangeAnalysis::Analyze() {
1013   HPhase phase("H_Range analysis", graph_);
1014   Analyze(graph_->entry_block());
1015 }
1016 
1017 
Analyze(HBasicBlock * block)1018 void HRangeAnalysis::Analyze(HBasicBlock* block) {
1019   TraceRange("Analyzing block B%d\n", block->block_id());
1020 
1021   int last_changed_range = changed_ranges_.length() - 1;
1022 
1023   // Infer range based on control flow.
1024   if (block->predecessors()->length() == 1) {
1025     HBasicBlock* pred = block->predecessors()->first();
1026     if (pred->end()->IsCompareIDAndBranch()) {
1027       InferControlFlowRange(HCompareIDAndBranch::cast(pred->end()), block);
1028     }
1029   }
1030 
1031   // Process phi instructions.
1032   for (int i = 0; i < block->phis()->length(); ++i) {
1033     HPhi* phi = block->phis()->at(i);
1034     InferRange(phi);
1035   }
1036 
1037   // Go through all instructions of the current block.
1038   HInstruction* instr = block->first();
1039   while (instr != block->end()) {
1040     InferRange(instr);
1041     instr = instr->next();
1042   }
1043 
1044   // Continue analysis in all dominated blocks.
1045   for (int i = 0; i < block->dominated_blocks()->length(); ++i) {
1046     Analyze(block->dominated_blocks()->at(i));
1047   }
1048 
1049   RollBackTo(last_changed_range);
1050 }
1051 
1052 
InferControlFlowRange(HCompareIDAndBranch * test,HBasicBlock * dest)1053 void HRangeAnalysis::InferControlFlowRange(HCompareIDAndBranch* test,
1054                                            HBasicBlock* dest) {
1055   ASSERT((test->FirstSuccessor() == dest) == (test->SecondSuccessor() != dest));
1056   if (test->GetInputRepresentation().IsInteger32()) {
1057     Token::Value op = test->token();
1058     if (test->SecondSuccessor() == dest) {
1059       op = Token::NegateCompareOp(op);
1060     }
1061     Token::Value inverted_op = Token::InvertCompareOp(op);
1062     UpdateControlFlowRange(op, test->left(), test->right());
1063     UpdateControlFlowRange(inverted_op, test->right(), test->left());
1064   }
1065 }
1066 
1067 
1068 // We know that value [op] other. Use this information to update the range on
1069 // value.
UpdateControlFlowRange(Token::Value op,HValue * value,HValue * other)1070 void HRangeAnalysis::UpdateControlFlowRange(Token::Value op,
1071                                             HValue* value,
1072                                             HValue* other) {
1073   Range temp_range;
1074   Range* range = other->range() != NULL ? other->range() : &temp_range;
1075   Range* new_range = NULL;
1076 
1077   TraceRange("Control flow range infer %d %s %d\n",
1078              value->id(),
1079              Token::Name(op),
1080              other->id());
1081 
1082   if (op == Token::EQ || op == Token::EQ_STRICT) {
1083     // The same range has to apply for value.
1084     new_range = range->Copy(zone_);
1085   } else if (op == Token::LT || op == Token::LTE) {
1086     new_range = range->CopyClearLower(zone_);
1087     if (op == Token::LT) {
1088       new_range->AddConstant(-1);
1089     }
1090   } else if (op == Token::GT || op == Token::GTE) {
1091     new_range = range->CopyClearUpper(zone_);
1092     if (op == Token::GT) {
1093       new_range->AddConstant(1);
1094     }
1095   }
1096 
1097   if (new_range != NULL && !new_range->IsMostGeneric()) {
1098     AddRange(value, new_range);
1099   }
1100 }
1101 
1102 
InferRange(HValue * value)1103 void HRangeAnalysis::InferRange(HValue* value) {
1104   ASSERT(!value->HasRange());
1105   if (!value->representation().IsNone()) {
1106     value->ComputeInitialRange(zone_);
1107     Range* range = value->range();
1108     TraceRange("Initial inferred range of %d (%s) set to [%d,%d]\n",
1109                value->id(),
1110                value->Mnemonic(),
1111                range->lower(),
1112                range->upper());
1113   }
1114 }
1115 
1116 
RollBackTo(int index)1117 void HRangeAnalysis::RollBackTo(int index) {
1118   for (int i = index + 1; i < changed_ranges_.length(); ++i) {
1119     changed_ranges_[i]->RemoveLastAddedRange();
1120   }
1121   changed_ranges_.Rewind(index + 1);
1122 }
1123 
1124 
AddRange(HValue * value,Range * range)1125 void HRangeAnalysis::AddRange(HValue* value, Range* range) {
1126   Range* original_range = value->range();
1127   value->AddNewRange(range, zone_);
1128   changed_ranges_.Add(value);
1129   Range* new_range = value->range();
1130   TraceRange("Updated range of %d set to [%d,%d]\n",
1131              value->id(),
1132              new_range->lower(),
1133              new_range->upper());
1134   if (original_range != NULL) {
1135     TraceRange("Original range was [%d,%d]\n",
1136                original_range->lower(),
1137                original_range->upper());
1138   }
1139   TraceRange("New information was [%d,%d]\n",
1140              range->lower(),
1141              range->upper());
1142 }
1143 
1144 
TraceGVN(const char * msg,...)1145 void TraceGVN(const char* msg, ...) {
1146   if (FLAG_trace_gvn) {
1147     va_list arguments;
1148     va_start(arguments, msg);
1149     OS::VPrint(msg, arguments);
1150     va_end(arguments);
1151   }
1152 }
1153 
1154 
HValueMap(Zone * zone,const HValueMap * other)1155 HValueMap::HValueMap(Zone* zone, const HValueMap* other)
1156     : array_size_(other->array_size_),
1157       lists_size_(other->lists_size_),
1158       count_(other->count_),
1159       present_flags_(other->present_flags_),
1160       array_(zone->NewArray<HValueMapListElement>(other->array_size_)),
1161       lists_(zone->NewArray<HValueMapListElement>(other->lists_size_)),
1162       free_list_head_(other->free_list_head_) {
1163   memcpy(array_, other->array_, array_size_ * sizeof(HValueMapListElement));
1164   memcpy(lists_, other->lists_, lists_size_ * sizeof(HValueMapListElement));
1165 }
1166 
1167 
Kill(GVNFlagSet flags)1168 void HValueMap::Kill(GVNFlagSet flags) {
1169   GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(flags);
1170   if (!present_flags_.ContainsAnyOf(depends_flags)) return;
1171   present_flags_.RemoveAll();
1172   for (int i = 0; i < array_size_; ++i) {
1173     HValue* value = array_[i].value;
1174     if (value != NULL) {
1175       // Clear list of collisions first, so we know if it becomes empty.
1176       int kept = kNil;  // List of kept elements.
1177       int next;
1178       for (int current = array_[i].next; current != kNil; current = next) {
1179         next = lists_[current].next;
1180         HValue* value = lists_[current].value;
1181         if (value->gvn_flags().ContainsAnyOf(depends_flags)) {
1182           // Drop it.
1183           count_--;
1184           lists_[current].next = free_list_head_;
1185           free_list_head_ = current;
1186         } else {
1187           // Keep it.
1188           lists_[current].next = kept;
1189           kept = current;
1190           present_flags_.Add(value->gvn_flags());
1191         }
1192       }
1193       array_[i].next = kept;
1194 
1195       // Now possibly drop directly indexed element.
1196       value = array_[i].value;
1197       if (value->gvn_flags().ContainsAnyOf(depends_flags)) {  // Drop it.
1198         count_--;
1199         int head = array_[i].next;
1200         if (head == kNil) {
1201           array_[i].value = NULL;
1202         } else {
1203           array_[i].value = lists_[head].value;
1204           array_[i].next = lists_[head].next;
1205           lists_[head].next = free_list_head_;
1206           free_list_head_ = head;
1207         }
1208       } else {
1209         present_flags_.Add(value->gvn_flags());  // Keep it.
1210       }
1211     }
1212   }
1213 }
1214 
1215 
Lookup(HValue * value) const1216 HValue* HValueMap::Lookup(HValue* value) const {
1217   uint32_t hash = static_cast<uint32_t>(value->Hashcode());
1218   uint32_t pos = Bound(hash);
1219   if (array_[pos].value != NULL) {
1220     if (array_[pos].value->Equals(value)) return array_[pos].value;
1221     int next = array_[pos].next;
1222     while (next != kNil) {
1223       if (lists_[next].value->Equals(value)) return lists_[next].value;
1224       next = lists_[next].next;
1225     }
1226   }
1227   return NULL;
1228 }
1229 
1230 
Resize(int new_size)1231 void HValueMap::Resize(int new_size) {
1232   ASSERT(new_size > count_);
1233   // Hashing the values into the new array has no more collisions than in the
1234   // old hash map, so we can use the existing lists_ array, if we are careful.
1235 
1236   // Make sure we have at least one free element.
1237   if (free_list_head_ == kNil) {
1238     ResizeLists(lists_size_ << 1);
1239   }
1240 
1241   HValueMapListElement* new_array =
1242       ZONE->NewArray<HValueMapListElement>(new_size);
1243   memset(new_array, 0, sizeof(HValueMapListElement) * new_size);
1244 
1245   HValueMapListElement* old_array = array_;
1246   int old_size = array_size_;
1247 
1248   int old_count = count_;
1249   count_ = 0;
1250   // Do not modify present_flags_.  It is currently correct.
1251   array_size_ = new_size;
1252   array_ = new_array;
1253 
1254   if (old_array != NULL) {
1255     // Iterate over all the elements in lists, rehashing them.
1256     for (int i = 0; i < old_size; ++i) {
1257       if (old_array[i].value != NULL) {
1258         int current = old_array[i].next;
1259         while (current != kNil) {
1260           Insert(lists_[current].value);
1261           int next = lists_[current].next;
1262           lists_[current].next = free_list_head_;
1263           free_list_head_ = current;
1264           current = next;
1265         }
1266         // Rehash the directly stored value.
1267         Insert(old_array[i].value);
1268       }
1269     }
1270   }
1271   USE(old_count);
1272   ASSERT(count_ == old_count);
1273 }
1274 
1275 
ResizeLists(int new_size)1276 void HValueMap::ResizeLists(int new_size) {
1277   ASSERT(new_size > lists_size_);
1278 
1279   HValueMapListElement* new_lists =
1280       ZONE->NewArray<HValueMapListElement>(new_size);
1281   memset(new_lists, 0, sizeof(HValueMapListElement) * new_size);
1282 
1283   HValueMapListElement* old_lists = lists_;
1284   int old_size = lists_size_;
1285 
1286   lists_size_ = new_size;
1287   lists_ = new_lists;
1288 
1289   if (old_lists != NULL) {
1290     memcpy(lists_, old_lists, old_size * sizeof(HValueMapListElement));
1291   }
1292   for (int i = old_size; i < lists_size_; ++i) {
1293     lists_[i].next = free_list_head_;
1294     free_list_head_ = i;
1295   }
1296 }
1297 
1298 
Insert(HValue * value)1299 void HValueMap::Insert(HValue* value) {
1300   ASSERT(value != NULL);
1301   // Resizing when half of the hashtable is filled up.
1302   if (count_ >= array_size_ >> 1) Resize(array_size_ << 1);
1303   ASSERT(count_ < array_size_);
1304   count_++;
1305   uint32_t pos = Bound(static_cast<uint32_t>(value->Hashcode()));
1306   if (array_[pos].value == NULL) {
1307     array_[pos].value = value;
1308     array_[pos].next = kNil;
1309   } else {
1310     if (free_list_head_ == kNil) {
1311       ResizeLists(lists_size_ << 1);
1312     }
1313     int new_element_pos = free_list_head_;
1314     ASSERT(new_element_pos != kNil);
1315     free_list_head_ = lists_[free_list_head_].next;
1316     lists_[new_element_pos].value = value;
1317     lists_[new_element_pos].next = array_[pos].next;
1318     ASSERT(array_[pos].next == kNil || lists_[array_[pos].next].value != NULL);
1319     array_[pos].next = new_element_pos;
1320   }
1321 }
1322 
1323 
1324 class HStackCheckEliminator BASE_EMBEDDED {
1325  public:
HStackCheckEliminator(HGraph * graph)1326   explicit HStackCheckEliminator(HGraph* graph) : graph_(graph) { }
1327 
1328   void Process();
1329 
1330  private:
1331   HGraph* graph_;
1332 };
1333 
1334 
Process()1335 void HStackCheckEliminator::Process() {
1336   // For each loop block walk the dominator tree from the backwards branch to
1337   // the loop header. If a call instruction is encountered the backwards branch
1338   // is dominated by a call and the stack check in the backwards branch can be
1339   // removed.
1340   for (int i = 0; i < graph_->blocks()->length(); i++) {
1341     HBasicBlock* block = graph_->blocks()->at(i);
1342     if (block->IsLoopHeader()) {
1343       HBasicBlock* back_edge = block->loop_information()->GetLastBackEdge();
1344       HBasicBlock* dominator = back_edge;
1345       while (true) {
1346         HInstruction* instr = dominator->first();
1347         while (instr != NULL) {
1348           if (instr->IsCall()) {
1349             block->loop_information()->stack_check()->Eliminate();
1350             break;
1351           }
1352           instr = instr->next();
1353         }
1354 
1355         // Done when the loop header is processed.
1356         if (dominator == block) break;
1357 
1358         // Move up the dominator tree.
1359         dominator = dominator->dominator();
1360       }
1361     }
1362   }
1363 }
1364 
1365 
1366 // Simple sparse set with O(1) add, contains, and clear.
1367 class SparseSet {
1368  public:
SparseSet(Zone * zone,int capacity)1369   SparseSet(Zone* zone, int capacity)
1370       : capacity_(capacity),
1371         length_(0),
1372         dense_(zone->NewArray<int>(capacity)),
1373         sparse_(zone->NewArray<int>(capacity)) {
1374 #ifndef NVALGRIND
1375     // Initialize the sparse array to make valgrind happy.
1376     memset(sparse_, 0, sizeof(sparse_[0]) * capacity);
1377 #endif
1378   }
1379 
Contains(int n) const1380   bool Contains(int n) const {
1381     ASSERT(0 <= n && n < capacity_);
1382     int d = sparse_[n];
1383     return 0 <= d && d < length_ && dense_[d] == n;
1384   }
1385 
Add(int n)1386   bool Add(int n) {
1387     if (Contains(n)) return false;
1388     dense_[length_] = n;
1389     sparse_[n] = length_;
1390     ++length_;
1391     return true;
1392   }
1393 
Clear()1394   void Clear() { length_ = 0; }
1395 
1396  private:
1397   int capacity_;
1398   int length_;
1399   int* dense_;
1400   int* sparse_;
1401 
1402   DISALLOW_COPY_AND_ASSIGN(SparseSet);
1403 };
1404 
1405 
1406 class HGlobalValueNumberer BASE_EMBEDDED {
1407  public:
HGlobalValueNumberer(HGraph * graph,CompilationInfo * info)1408   explicit HGlobalValueNumberer(HGraph* graph, CompilationInfo* info)
1409       : graph_(graph),
1410         info_(info),
1411         removed_side_effects_(false),
1412         block_side_effects_(graph->blocks()->length()),
1413         loop_side_effects_(graph->blocks()->length()),
1414         visited_on_paths_(graph->zone(), graph->blocks()->length()) {
1415     ASSERT(info->isolate()->heap()->allow_allocation(false));
1416     block_side_effects_.AddBlock(GVNFlagSet(), graph_->blocks()->length());
1417     loop_side_effects_.AddBlock(GVNFlagSet(), graph_->blocks()->length());
1418   }
~HGlobalValueNumberer()1419   ~HGlobalValueNumberer() {
1420     ASSERT(!info_->isolate()->heap()->allow_allocation(true));
1421   }
1422 
1423   // Returns true if values with side effects are removed.
1424   bool Analyze();
1425 
1426  private:
1427   GVNFlagSet CollectSideEffectsOnPathsToDominatedBlock(
1428       HBasicBlock* dominator,
1429       HBasicBlock* dominated);
1430   void AnalyzeBlock(HBasicBlock* block, HValueMap* map);
1431   void ComputeBlockSideEffects();
1432   void LoopInvariantCodeMotion();
1433   void ProcessLoopBlock(HBasicBlock* block,
1434                         HBasicBlock* before_loop,
1435                         GVNFlagSet loop_kills,
1436                         GVNFlagSet* accumulated_first_time_depends,
1437                         GVNFlagSet* accumulated_first_time_changes);
1438   bool AllowCodeMotion();
1439   bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header);
1440 
graph()1441   HGraph* graph() { return graph_; }
info()1442   CompilationInfo* info() { return info_; }
zone()1443   Zone* zone() { return graph_->zone(); }
1444 
1445   HGraph* graph_;
1446   CompilationInfo* info_;
1447   bool removed_side_effects_;
1448 
1449   // A map of block IDs to their side effects.
1450   ZoneList<GVNFlagSet> block_side_effects_;
1451 
1452   // A map of loop header block IDs to their loop's side effects.
1453   ZoneList<GVNFlagSet> loop_side_effects_;
1454 
1455   // Used when collecting side effects on paths from dominator to
1456   // dominated.
1457   SparseSet visited_on_paths_;
1458 };
1459 
1460 
Analyze()1461 bool HGlobalValueNumberer::Analyze() {
1462   removed_side_effects_ = false;
1463   ComputeBlockSideEffects();
1464   if (FLAG_loop_invariant_code_motion) {
1465     LoopInvariantCodeMotion();
1466   }
1467   HValueMap* map = new(zone()) HValueMap();
1468   AnalyzeBlock(graph_->entry_block(), map);
1469   return removed_side_effects_;
1470 }
1471 
1472 
ComputeBlockSideEffects()1473 void HGlobalValueNumberer::ComputeBlockSideEffects() {
1474   // The Analyze phase of GVN can be called multiple times. Clear loop side
1475   // effects before computing them to erase the contents from previous Analyze
1476   // passes.
1477   for (int i = 0; i < loop_side_effects_.length(); ++i) {
1478     loop_side_effects_[i].RemoveAll();
1479   }
1480   for (int i = graph_->blocks()->length() - 1; i >= 0; --i) {
1481     // Compute side effects for the block.
1482     HBasicBlock* block = graph_->blocks()->at(i);
1483     HInstruction* instr = block->first();
1484     int id = block->block_id();
1485     GVNFlagSet side_effects;
1486     while (instr != NULL) {
1487       side_effects.Add(instr->ChangesFlags());
1488       if (instr->IsSoftDeoptimize()) {
1489         block_side_effects_[id].RemoveAll();
1490         side_effects.RemoveAll();
1491         break;
1492       }
1493       instr = instr->next();
1494     }
1495     block_side_effects_[id].Add(side_effects);
1496 
1497     // Loop headers are part of their loop.
1498     if (block->IsLoopHeader()) {
1499       loop_side_effects_[id].Add(side_effects);
1500     }
1501 
1502     // Propagate loop side effects upwards.
1503     if (block->HasParentLoopHeader()) {
1504       int header_id = block->parent_loop_header()->block_id();
1505       loop_side_effects_[header_id].Add(block->IsLoopHeader()
1506                                         ? loop_side_effects_[id]
1507                                         : side_effects);
1508     }
1509   }
1510 }
1511 
1512 
LoopInvariantCodeMotion()1513 void HGlobalValueNumberer::LoopInvariantCodeMotion() {
1514   for (int i = graph_->blocks()->length() - 1; i >= 0; --i) {
1515     HBasicBlock* block = graph_->blocks()->at(i);
1516     if (block->IsLoopHeader()) {
1517       GVNFlagSet side_effects = loop_side_effects_[block->block_id()];
1518       TraceGVN("Try loop invariant motion for block B%d effects=0x%x\n",
1519                block->block_id(),
1520                side_effects.ToIntegral());
1521 
1522       GVNFlagSet accumulated_first_time_depends;
1523       GVNFlagSet accumulated_first_time_changes;
1524       HBasicBlock* last = block->loop_information()->GetLastBackEdge();
1525       for (int j = block->block_id(); j <= last->block_id(); ++j) {
1526         ProcessLoopBlock(graph_->blocks()->at(j), block, side_effects,
1527                          &accumulated_first_time_depends,
1528                          &accumulated_first_time_changes);
1529       }
1530     }
1531   }
1532 }
1533 
1534 
ProcessLoopBlock(HBasicBlock * block,HBasicBlock * loop_header,GVNFlagSet loop_kills,GVNFlagSet * first_time_depends,GVNFlagSet * first_time_changes)1535 void HGlobalValueNumberer::ProcessLoopBlock(
1536     HBasicBlock* block,
1537     HBasicBlock* loop_header,
1538     GVNFlagSet loop_kills,
1539     GVNFlagSet* first_time_depends,
1540     GVNFlagSet* first_time_changes) {
1541   HBasicBlock* pre_header = loop_header->predecessors()->at(0);
1542   GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills);
1543   TraceGVN("Loop invariant motion for B%d depends_flags=0x%x\n",
1544            block->block_id(),
1545            depends_flags.ToIntegral());
1546   HInstruction* instr = block->first();
1547   while (instr != NULL) {
1548     HInstruction* next = instr->next();
1549     bool hoisted = false;
1550     if (instr->CheckFlag(HValue::kUseGVN)) {
1551       TraceGVN("Checking instruction %d (%s) instruction GVN flags 0x%X, "
1552                "loop kills 0x%X\n",
1553                instr->id(),
1554                instr->Mnemonic(),
1555                instr->gvn_flags().ToIntegral(),
1556                depends_flags.ToIntegral());
1557       bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags);
1558       if (instr->IsTransitionElementsKind()) {
1559         // It's possible to hoist transitions out of a loop as long as the
1560         // hoisting wouldn't move the transition past a DependsOn of one of it's
1561         // changes or any instructions that might change an objects map or
1562         // elements contents.
1563         GVNFlagSet changes = instr->ChangesFlags();
1564         GVNFlagSet hoist_depends_blockers =
1565             HValue::ConvertChangesToDependsFlags(changes);
1566         // In addition to not hoisting transitions above other instructions that
1567         // change dependencies that the transition changes, it must not be
1568         // hoisted above map changes and stores to an elements backing store
1569         // that the transition might change.
1570         GVNFlagSet hoist_change_blockers = changes;
1571         hoist_change_blockers.Add(kChangesMaps);
1572         HTransitionElementsKind* trans = HTransitionElementsKind::cast(instr);
1573         if (trans->original_map()->has_fast_double_elements()) {
1574           hoist_change_blockers.Add(kChangesDoubleArrayElements);
1575         }
1576         if (trans->transitioned_map()->has_fast_double_elements()) {
1577           hoist_change_blockers.Add(kChangesArrayElements);
1578         }
1579         TraceGVN("Checking dependencies on HTransitionElementsKind %d (%s) "
1580                  "hoist depends blockers 0x%X, hoist change blockers 0x%X, "
1581                  "accumulated depends 0x%X, accumulated changes 0x%X\n",
1582                  instr->id(),
1583                  instr->Mnemonic(),
1584                  hoist_depends_blockers.ToIntegral(),
1585                  hoist_change_blockers.ToIntegral(),
1586                  first_time_depends->ToIntegral(),
1587                  first_time_changes->ToIntegral());
1588         // It's possible to hoist transition from the current loop loop only if
1589         // they dominate all of the successor blocks in the same loop and there
1590         // are not any instructions that have Changes/DependsOn that intervene
1591         // between it and the beginning of the loop header.
1592         bool in_nested_loop = block != loop_header &&
1593             ((block->parent_loop_header() != loop_header) ||
1594              block->IsLoopHeader());
1595         can_hoist = !in_nested_loop &&
1596             block->IsLoopSuccessorDominator() &&
1597             !first_time_depends->ContainsAnyOf(hoist_depends_blockers) &&
1598             !first_time_changes->ContainsAnyOf(hoist_change_blockers);
1599       }
1600 
1601       if (can_hoist) {
1602         bool inputs_loop_invariant = true;
1603         for (int i = 0; i < instr->OperandCount(); ++i) {
1604           if (instr->OperandAt(i)->IsDefinedAfter(pre_header)) {
1605             inputs_loop_invariant = false;
1606           }
1607         }
1608 
1609         if (inputs_loop_invariant && ShouldMove(instr, loop_header)) {
1610           TraceGVN("Hoisting loop invariant instruction %d\n", instr->id());
1611           // Move the instruction out of the loop.
1612           instr->Unlink();
1613           instr->InsertBefore(pre_header->end());
1614           if (instr->HasSideEffects()) removed_side_effects_ = true;
1615           hoisted = true;
1616         }
1617       }
1618     }
1619     if (!hoisted) {
1620       // If an instruction is not hoisted, we have to account for its side
1621       // effects when hoisting later HTransitionElementsKind instructions.
1622       first_time_depends->Add(instr->DependsOnFlags());
1623       first_time_changes->Add(instr->ChangesFlags());
1624     }
1625     instr = next;
1626   }
1627 }
1628 
1629 
AllowCodeMotion()1630 bool HGlobalValueNumberer::AllowCodeMotion() {
1631   return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount;
1632 }
1633 
1634 
ShouldMove(HInstruction * instr,HBasicBlock * loop_header)1635 bool HGlobalValueNumberer::ShouldMove(HInstruction* instr,
1636                                       HBasicBlock* loop_header) {
1637   // If we've disabled code motion or we're in a block that unconditionally
1638   // deoptimizes, don't move any instructions.
1639   return AllowCodeMotion() && !instr->block()->IsDeoptimizing();
1640 }
1641 
1642 
CollectSideEffectsOnPathsToDominatedBlock(HBasicBlock * dominator,HBasicBlock * dominated)1643 GVNFlagSet HGlobalValueNumberer::CollectSideEffectsOnPathsToDominatedBlock(
1644     HBasicBlock* dominator, HBasicBlock* dominated) {
1645   GVNFlagSet side_effects;
1646   for (int i = 0; i < dominated->predecessors()->length(); ++i) {
1647     HBasicBlock* block = dominated->predecessors()->at(i);
1648     if (dominator->block_id() < block->block_id() &&
1649         block->block_id() < dominated->block_id() &&
1650         visited_on_paths_.Add(block->block_id())) {
1651       side_effects.Add(block_side_effects_[block->block_id()]);
1652       if (block->IsLoopHeader()) {
1653         side_effects.Add(loop_side_effects_[block->block_id()]);
1654       }
1655       side_effects.Add(CollectSideEffectsOnPathsToDominatedBlock(
1656           dominator, block));
1657     }
1658   }
1659   return side_effects;
1660 }
1661 
1662 
AnalyzeBlock(HBasicBlock * block,HValueMap * map)1663 void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) {
1664   TraceGVN("Analyzing block B%d%s\n",
1665            block->block_id(),
1666            block->IsLoopHeader() ? " (loop header)" : "");
1667 
1668   // If this is a loop header kill everything killed by the loop.
1669   if (block->IsLoopHeader()) {
1670     map->Kill(loop_side_effects_[block->block_id()]);
1671   }
1672 
1673   // Go through all instructions of the current block.
1674   HInstruction* instr = block->first();
1675   while (instr != NULL) {
1676     HInstruction* next = instr->next();
1677     GVNFlagSet flags = instr->ChangesFlags();
1678     if (!flags.IsEmpty()) {
1679       // Clear all instructions in the map that are affected by side effects.
1680       map->Kill(flags);
1681       TraceGVN("Instruction %d kills\n", instr->id());
1682     }
1683     if (instr->CheckFlag(HValue::kUseGVN)) {
1684       ASSERT(!instr->HasObservableSideEffects());
1685       HValue* other = map->Lookup(instr);
1686       if (other != NULL) {
1687         ASSERT(instr->Equals(other) && other->Equals(instr));
1688         TraceGVN("Replacing value %d (%s) with value %d (%s)\n",
1689                  instr->id(),
1690                  instr->Mnemonic(),
1691                  other->id(),
1692                  other->Mnemonic());
1693         if (instr->HasSideEffects()) removed_side_effects_ = true;
1694         instr->DeleteAndReplaceWith(other);
1695       } else {
1696         map->Add(instr);
1697       }
1698     }
1699     instr = next;
1700   }
1701 
1702   // Recursively continue analysis for all immediately dominated blocks.
1703   int length = block->dominated_blocks()->length();
1704   for (int i = 0; i < length; ++i) {
1705     HBasicBlock* dominated = block->dominated_blocks()->at(i);
1706     // No need to copy the map for the last child in the dominator tree.
1707     HValueMap* successor_map = (i == length - 1) ? map : map->Copy(zone());
1708 
1709     // Kill everything killed on any path between this block and the
1710     // dominated block.
1711     // We don't have to traverse these paths if the value map is
1712     // already empty.
1713     // If the range of block ids (block_id, dominated_id) is empty
1714     // there are no such paths.
1715     if (!successor_map->IsEmpty() &&
1716         block->block_id() + 1 < dominated->block_id()) {
1717       visited_on_paths_.Clear();
1718       successor_map->Kill(CollectSideEffectsOnPathsToDominatedBlock(block,
1719                                                                     dominated));
1720     }
1721     AnalyzeBlock(dominated, successor_map);
1722   }
1723 }
1724 
1725 
1726 class HInferRepresentation BASE_EMBEDDED {
1727  public:
HInferRepresentation(HGraph * graph)1728   explicit HInferRepresentation(HGraph* graph)
1729       : graph_(graph),
1730         worklist_(8),
1731         in_worklist_(graph->GetMaximumValueID(), graph->zone()) { }
1732 
1733   void Analyze();
1734 
1735  private:
1736   Representation TryChange(HValue* current);
1737   void AddToWorklist(HValue* current);
1738   void InferBasedOnInputs(HValue* current);
1739   void AddDependantsToWorklist(HValue* current);
1740   void InferBasedOnUses(HValue* current);
1741 
zone()1742   Zone* zone() { return graph_->zone(); }
1743 
1744   HGraph* graph_;
1745   ZoneList<HValue*> worklist_;
1746   BitVector in_worklist_;
1747 };
1748 
1749 
AddToWorklist(HValue * current)1750 void HInferRepresentation::AddToWorklist(HValue* current) {
1751   if (current->representation().IsSpecialization()) return;
1752   if (!current->CheckFlag(HValue::kFlexibleRepresentation)) return;
1753   if (in_worklist_.Contains(current->id())) return;
1754   worklist_.Add(current);
1755   in_worklist_.Add(current->id());
1756 }
1757 
1758 
1759 // This method tries to specialize the representation type of the value
1760 // given as a parameter. The value is asked to infer its representation type
1761 // based on its inputs. If the inferred type is more specialized, then this
1762 // becomes the new representation type of the node.
InferBasedOnInputs(HValue * current)1763 void HInferRepresentation::InferBasedOnInputs(HValue* current) {
1764   Representation r = current->representation();
1765   if (r.IsSpecialization()) return;
1766   ASSERT(current->CheckFlag(HValue::kFlexibleRepresentation));
1767   Representation inferred = current->InferredRepresentation();
1768   if (inferred.IsSpecialization()) {
1769     if (FLAG_trace_representation) {
1770       PrintF("Changing #%d representation %s -> %s based on inputs\n",
1771              current->id(),
1772              r.Mnemonic(),
1773              inferred.Mnemonic());
1774     }
1775     current->ChangeRepresentation(inferred);
1776     AddDependantsToWorklist(current);
1777   }
1778 }
1779 
1780 
AddDependantsToWorklist(HValue * value)1781 void HInferRepresentation::AddDependantsToWorklist(HValue* value) {
1782   for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
1783     AddToWorklist(it.value());
1784   }
1785   for (int i = 0; i < value->OperandCount(); ++i) {
1786     AddToWorklist(value->OperandAt(i));
1787   }
1788 }
1789 
1790 
1791 // This method calculates whether specializing the representation of the value
1792 // given as the parameter has a benefit in terms of less necessary type
1793 // conversions. If there is a benefit, then the representation of the value is
1794 // specialized.
InferBasedOnUses(HValue * value)1795 void HInferRepresentation::InferBasedOnUses(HValue* value) {
1796   Representation r = value->representation();
1797   if (r.IsSpecialization() || value->HasNoUses()) return;
1798   ASSERT(value->CheckFlag(HValue::kFlexibleRepresentation));
1799   Representation new_rep = TryChange(value);
1800   if (!new_rep.IsNone()) {
1801     if (!value->representation().Equals(new_rep)) {
1802       if (FLAG_trace_representation) {
1803         PrintF("Changing #%d representation %s -> %s based on uses\n",
1804                value->id(),
1805                r.Mnemonic(),
1806                new_rep.Mnemonic());
1807       }
1808       value->ChangeRepresentation(new_rep);
1809       AddDependantsToWorklist(value);
1810     }
1811   }
1812 }
1813 
1814 
TryChange(HValue * value)1815 Representation HInferRepresentation::TryChange(HValue* value) {
1816   // Array of use counts for each representation.
1817   int use_count[Representation::kNumRepresentations] = { 0 };
1818 
1819   for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
1820     HValue* use = it.value();
1821     Representation rep = use->RequiredInputRepresentation(it.index());
1822     if (rep.IsNone()) continue;
1823     if (use->IsPhi()) HPhi::cast(use)->AddIndirectUsesTo(&use_count[0]);
1824     use_count[rep.kind()] += use->LoopWeight();
1825   }
1826   int tagged_count = use_count[Representation::kTagged];
1827   int double_count = use_count[Representation::kDouble];
1828   int int32_count = use_count[Representation::kInteger32];
1829   int non_tagged_count = double_count + int32_count;
1830 
1831   // If a non-loop phi has tagged uses, don't convert it to untagged.
1832   if (value->IsPhi() && !value->block()->IsLoopHeader() && tagged_count > 0) {
1833     return Representation::None();
1834   }
1835 
1836   // Prefer unboxing over boxing, the latter is more expensive.
1837   if (tagged_count > non_tagged_count) return Representation::None();
1838 
1839   // Prefer Integer32 over Double, if possible.
1840   if (int32_count > 0 && value->IsConvertibleToInteger()) {
1841     return Representation::Integer32();
1842   }
1843 
1844   if (double_count > 0) return Representation::Double();
1845 
1846   return Representation::None();
1847 }
1848 
1849 
Analyze()1850 void HInferRepresentation::Analyze() {
1851   HPhase phase("H_Infer representations", graph_);
1852 
1853   // (1) Initialize bit vectors and count real uses. Each phi gets a
1854   // bit-vector of length <number of phis>.
1855   const ZoneList<HPhi*>* phi_list = graph_->phi_list();
1856   int phi_count = phi_list->length();
1857   ZoneList<BitVector*> connected_phis(phi_count);
1858   for (int i = 0; i < phi_count; ++i) {
1859     phi_list->at(i)->InitRealUses(i);
1860     BitVector* connected_set = new(zone()) BitVector(phi_count, graph_->zone());
1861     connected_set->Add(i);
1862     connected_phis.Add(connected_set);
1863   }
1864 
1865   // (2) Do a fixed point iteration to find the set of connected phis.  A
1866   // phi is connected to another phi if its value is used either directly or
1867   // indirectly through a transitive closure of the def-use relation.
1868   bool change = true;
1869   while (change) {
1870     change = false;
1871     // We normally have far more "forward edges" than "backward edges",
1872     // so we terminate faster when we walk backwards.
1873     for (int i = phi_count - 1; i >= 0; --i) {
1874       HPhi* phi = phi_list->at(i);
1875       for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
1876         HValue* use = it.value();
1877         if (use->IsPhi()) {
1878           int id = HPhi::cast(use)->phi_id();
1879           if (connected_phis[i]->UnionIsChanged(*connected_phis[id]))
1880             change = true;
1881         }
1882       }
1883     }
1884   }
1885 
1886   // (3) Use the phi reachability information from step 2 to
1887   //     (a) sum up the non-phi use counts of all connected phis.
1888   //     (b) push information about values which can't be converted to integer
1889   //         without deoptimization through the phi use-def chains, avoiding
1890   //         unnecessary deoptimizations later.
1891   for (int i = 0; i < phi_count; ++i) {
1892     HPhi* phi = phi_list->at(i);
1893     bool cti = phi->AllOperandsConvertibleToInteger();
1894     for (BitVector::Iterator it(connected_phis.at(i));
1895          !it.Done();
1896          it.Advance()) {
1897       int index = it.Current();
1898       HPhi* it_use = phi_list->at(it.Current());
1899       if (index != i) phi->AddNonPhiUsesFrom(it_use);  // Don't count twice!
1900       if (!cti) it_use->set_is_convertible_to_integer(false);
1901     }
1902   }
1903 
1904   // Initialize work list
1905   for (int i = 0; i < graph_->blocks()->length(); ++i) {
1906     HBasicBlock* block = graph_->blocks()->at(i);
1907     const ZoneList<HPhi*>* phis = block->phis();
1908     for (int j = 0; j < phis->length(); ++j) {
1909       AddToWorklist(phis->at(j));
1910     }
1911 
1912     HInstruction* current = block->first();
1913     while (current != NULL) {
1914       AddToWorklist(current);
1915       current = current->next();
1916     }
1917   }
1918 
1919   // Do a fixed point iteration, trying to improve representations
1920   while (!worklist_.is_empty()) {
1921     HValue* current = worklist_.RemoveLast();
1922     in_worklist_.Remove(current->id());
1923     InferBasedOnInputs(current);
1924     InferBasedOnUses(current);
1925   }
1926 }
1927 
1928 
InitializeInferredTypes()1929 void HGraph::InitializeInferredTypes() {
1930   HPhase phase("H_Inferring types", this);
1931   InitializeInferredTypes(0, this->blocks_.length() - 1);
1932 }
1933 
1934 
InitializeInferredTypes(int from_inclusive,int to_inclusive)1935 void HGraph::InitializeInferredTypes(int from_inclusive, int to_inclusive) {
1936   for (int i = from_inclusive; i <= to_inclusive; ++i) {
1937     HBasicBlock* block = blocks_[i];
1938 
1939     const ZoneList<HPhi*>* phis = block->phis();
1940     for (int j = 0; j < phis->length(); j++) {
1941       phis->at(j)->UpdateInferredType();
1942     }
1943 
1944     HInstruction* current = block->first();
1945     while (current != NULL) {
1946       current->UpdateInferredType();
1947       current = current->next();
1948     }
1949 
1950     if (block->IsLoopHeader()) {
1951       HBasicBlock* last_back_edge =
1952           block->loop_information()->GetLastBackEdge();
1953       InitializeInferredTypes(i + 1, last_back_edge->block_id());
1954       // Skip all blocks already processed by the recursive call.
1955       i = last_back_edge->block_id();
1956       // Update phis of the loop header now after the whole loop body is
1957       // guaranteed to be processed.
1958       ZoneList<HValue*> worklist(block->phis()->length());
1959       for (int j = 0; j < block->phis()->length(); ++j) {
1960         worklist.Add(block->phis()->at(j));
1961       }
1962       InferTypes(&worklist);
1963     }
1964   }
1965 }
1966 
1967 
PropagateMinusZeroChecks(HValue * value,BitVector * visited)1968 void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) {
1969   HValue* current = value;
1970   while (current != NULL) {
1971     if (visited->Contains(current->id())) return;
1972 
1973     // For phis, we must propagate the check to all of its inputs.
1974     if (current->IsPhi()) {
1975       visited->Add(current->id());
1976       HPhi* phi = HPhi::cast(current);
1977       for (int i = 0; i < phi->OperandCount(); ++i) {
1978         PropagateMinusZeroChecks(phi->OperandAt(i), visited);
1979       }
1980       break;
1981     }
1982 
1983     // For multiplication and division, we must propagate to the left and
1984     // the right side.
1985     if (current->IsMul()) {
1986       HMul* mul = HMul::cast(current);
1987       mul->EnsureAndPropagateNotMinusZero(visited);
1988       PropagateMinusZeroChecks(mul->left(), visited);
1989       PropagateMinusZeroChecks(mul->right(), visited);
1990     } else if (current->IsDiv()) {
1991       HDiv* div = HDiv::cast(current);
1992       div->EnsureAndPropagateNotMinusZero(visited);
1993       PropagateMinusZeroChecks(div->left(), visited);
1994       PropagateMinusZeroChecks(div->right(), visited);
1995     }
1996 
1997     current = current->EnsureAndPropagateNotMinusZero(visited);
1998   }
1999 }
2000 
2001 
InsertRepresentationChangeForUse(HValue * value,HValue * use_value,int use_index,Representation to)2002 void HGraph::InsertRepresentationChangeForUse(HValue* value,
2003                                               HValue* use_value,
2004                                               int use_index,
2005                                               Representation to) {
2006   // Insert the representation change right before its use. For phi-uses we
2007   // insert at the end of the corresponding predecessor.
2008   HInstruction* next = NULL;
2009   if (use_value->IsPhi()) {
2010     next = use_value->block()->predecessors()->at(use_index)->end();
2011   } else {
2012     next = HInstruction::cast(use_value);
2013   }
2014 
2015   // For constants we try to make the representation change at compile
2016   // time. When a representation change is not possible without loss of
2017   // information we treat constants like normal instructions and insert the
2018   // change instructions for them.
2019   HInstruction* new_value = NULL;
2020   bool is_truncating = use_value->CheckFlag(HValue::kTruncatingToInt32);
2021   bool deoptimize_on_undefined =
2022       use_value->CheckFlag(HValue::kDeoptimizeOnUndefined);
2023   if (value->IsConstant()) {
2024     HConstant* constant = HConstant::cast(value);
2025     // Try to create a new copy of the constant with the new representation.
2026     new_value = is_truncating
2027         ? constant->CopyToTruncatedInt32()
2028         : constant->CopyToRepresentation(to);
2029   }
2030 
2031   if (new_value == NULL) {
2032     new_value = new(zone()) HChange(value, to,
2033                                     is_truncating, deoptimize_on_undefined);
2034   }
2035 
2036   new_value->InsertBefore(next);
2037   use_value->SetOperandAt(use_index, new_value);
2038 }
2039 
2040 
InsertRepresentationChangesForValue(HValue * value)2041 void HGraph::InsertRepresentationChangesForValue(HValue* value) {
2042   Representation r = value->representation();
2043   if (r.IsNone()) return;
2044   if (value->HasNoUses()) return;
2045 
2046   for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
2047     HValue* use_value = it.value();
2048     int use_index = it.index();
2049     Representation req = use_value->RequiredInputRepresentation(use_index);
2050     if (req.IsNone() || req.Equals(r)) continue;
2051     InsertRepresentationChangeForUse(value, use_value, use_index, req);
2052   }
2053   if (value->HasNoUses()) {
2054     ASSERT(value->IsConstant());
2055     value->DeleteAndReplaceWith(NULL);
2056   }
2057 
2058   // The only purpose of a HForceRepresentation is to represent the value
2059   // after the (possible) HChange instruction.  We make it disappear.
2060   if (value->IsForceRepresentation()) {
2061     value->DeleteAndReplaceWith(HForceRepresentation::cast(value)->value());
2062   }
2063 }
2064 
2065 
InsertRepresentationChanges()2066 void HGraph::InsertRepresentationChanges() {
2067   HPhase phase("H_Representation changes", this);
2068 
2069   // Compute truncation flag for phis: Initially assume that all
2070   // int32-phis allow truncation and iteratively remove the ones that
2071   // are used in an operation that does not allow a truncating
2072   // conversion.
2073   // TODO(fschneider): Replace this with a worklist-based iteration.
2074   for (int i = 0; i < phi_list()->length(); i++) {
2075     HPhi* phi = phi_list()->at(i);
2076     if (phi->representation().IsInteger32()) {
2077       phi->SetFlag(HValue::kTruncatingToInt32);
2078     }
2079   }
2080   bool change = true;
2081   while (change) {
2082     change = false;
2083     for (int i = 0; i < phi_list()->length(); i++) {
2084       HPhi* phi = phi_list()->at(i);
2085       if (!phi->CheckFlag(HValue::kTruncatingToInt32)) continue;
2086       if (!phi->CheckUsesForFlag(HValue::kTruncatingToInt32)) {
2087         phi->ClearFlag(HValue::kTruncatingToInt32);
2088         change = true;
2089       }
2090     }
2091   }
2092 
2093   for (int i = 0; i < blocks_.length(); ++i) {
2094     // Process phi instructions first.
2095     const ZoneList<HPhi*>* phis = blocks_[i]->phis();
2096     for (int j = 0; j < phis->length(); j++) {
2097       InsertRepresentationChangesForValue(phis->at(j));
2098     }
2099 
2100     // Process normal instructions.
2101     HInstruction* current = blocks_[i]->first();
2102     while (current != NULL) {
2103       InsertRepresentationChangesForValue(current);
2104       current = current->next();
2105     }
2106   }
2107 }
2108 
2109 
RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi * phi)2110 void HGraph::RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi* phi) {
2111   if (phi->CheckFlag(HValue::kDeoptimizeOnUndefined)) return;
2112   phi->SetFlag(HValue::kDeoptimizeOnUndefined);
2113   for (int i = 0; i < phi->OperandCount(); ++i) {
2114     HValue* input = phi->OperandAt(i);
2115     if (input->IsPhi()) {
2116       RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi::cast(input));
2117     }
2118   }
2119 }
2120 
2121 
MarkDeoptimizeOnUndefined()2122 void HGraph::MarkDeoptimizeOnUndefined() {
2123   HPhase phase("H_MarkDeoptimizeOnUndefined", this);
2124   // Compute DeoptimizeOnUndefined flag for phis.
2125   // Any phi that can reach a use with DeoptimizeOnUndefined set must
2126   // have DeoptimizeOnUndefined set.  Currently only HCompareIDAndBranch, with
2127   // double input representation, has this flag set.
2128   // The flag is used by HChange tagged->double, which must deoptimize
2129   // if one of its uses has this flag set.
2130   for (int i = 0; i < phi_list()->length(); i++) {
2131     HPhi* phi = phi_list()->at(i);
2132     if (phi->representation().IsDouble()) {
2133       for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
2134         if (it.value()->CheckFlag(HValue::kDeoptimizeOnUndefined)) {
2135           RecursivelyMarkPhiDeoptimizeOnUndefined(phi);
2136           break;
2137         }
2138       }
2139     }
2140   }
2141 }
2142 
2143 
ComputeMinusZeroChecks()2144 void HGraph::ComputeMinusZeroChecks() {
2145   BitVector visited(GetMaximumValueID(), zone());
2146   for (int i = 0; i < blocks_.length(); ++i) {
2147     for (HInstruction* current = blocks_[i]->first();
2148          current != NULL;
2149          current = current->next()) {
2150       if (current->IsChange()) {
2151         HChange* change = HChange::cast(current);
2152         // Propagate flags for negative zero checks upwards from conversions
2153         // int32-to-tagged and int32-to-double.
2154         Representation from = change->value()->representation();
2155         ASSERT(from.Equals(change->from()));
2156         if (from.IsInteger32()) {
2157           ASSERT(change->to().IsTagged() || change->to().IsDouble());
2158           ASSERT(visited.IsEmpty());
2159           PropagateMinusZeroChecks(change->value(), &visited);
2160           visited.Clear();
2161         }
2162       }
2163     }
2164   }
2165 }
2166 
2167 
2168 // Implementation of utility class to encapsulate the translation state for
2169 // a (possibly inlined) function.
FunctionState(HGraphBuilder * owner,CompilationInfo * info,TypeFeedbackOracle * oracle,ReturnHandlingFlag return_handling)2170 FunctionState::FunctionState(HGraphBuilder* owner,
2171                              CompilationInfo* info,
2172                              TypeFeedbackOracle* oracle,
2173                              ReturnHandlingFlag return_handling)
2174     : owner_(owner),
2175       compilation_info_(info),
2176       oracle_(oracle),
2177       call_context_(NULL),
2178       return_handling_(return_handling),
2179       function_return_(NULL),
2180       test_context_(NULL),
2181       outer_(owner->function_state()) {
2182   if (outer_ != NULL) {
2183     // State for an inline function.
2184     if (owner->ast_context()->IsTest()) {
2185       HBasicBlock* if_true = owner->graph()->CreateBasicBlock();
2186       HBasicBlock* if_false = owner->graph()->CreateBasicBlock();
2187       if_true->MarkAsInlineReturnTarget();
2188       if_false->MarkAsInlineReturnTarget();
2189       Expression* cond = TestContext::cast(owner->ast_context())->condition();
2190       // The AstContext constructor pushed on the context stack.  This newed
2191       // instance is the reason that AstContext can't be BASE_EMBEDDED.
2192       test_context_ = new TestContext(owner, cond, if_true, if_false);
2193     } else {
2194       function_return_ = owner->graph()->CreateBasicBlock();
2195       function_return()->MarkAsInlineReturnTarget();
2196     }
2197     // Set this after possibly allocating a new TestContext above.
2198     call_context_ = owner->ast_context();
2199   }
2200 
2201   // Push on the state stack.
2202   owner->set_function_state(this);
2203 }
2204 
2205 
~FunctionState()2206 FunctionState::~FunctionState() {
2207   delete test_context_;
2208   owner_->set_function_state(outer_);
2209 }
2210 
2211 
2212 // Implementation of utility classes to represent an expression's context in
2213 // the AST.
AstContext(HGraphBuilder * owner,Expression::Context kind)2214 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind)
2215     : owner_(owner),
2216       kind_(kind),
2217       outer_(owner->ast_context()),
2218       for_typeof_(false) {
2219   owner->set_ast_context(this);  // Push.
2220 #ifdef DEBUG
2221   ASSERT(owner->environment()->frame_type() == JS_FUNCTION);
2222   original_length_ = owner->environment()->length();
2223 #endif
2224 }
2225 
2226 
~AstContext()2227 AstContext::~AstContext() {
2228   owner_->set_ast_context(outer_);  // Pop.
2229 }
2230 
2231 
~EffectContext()2232 EffectContext::~EffectContext() {
2233   ASSERT(owner()->HasStackOverflow() ||
2234          owner()->current_block() == NULL ||
2235          (owner()->environment()->length() == original_length_ &&
2236           owner()->environment()->frame_type() == JS_FUNCTION));
2237 }
2238 
2239 
~ValueContext()2240 ValueContext::~ValueContext() {
2241   ASSERT(owner()->HasStackOverflow() ||
2242          owner()->current_block() == NULL ||
2243          (owner()->environment()->length() == original_length_ + 1 &&
2244           owner()->environment()->frame_type() == JS_FUNCTION));
2245 }
2246 
2247 
ReturnValue(HValue * value)2248 void EffectContext::ReturnValue(HValue* value) {
2249   // The value is simply ignored.
2250 }
2251 
2252 
ReturnValue(HValue * value)2253 void ValueContext::ReturnValue(HValue* value) {
2254   // The value is tracked in the bailout environment, and communicated
2255   // through the environment as the result of the expression.
2256   if (!arguments_allowed() && value->CheckFlag(HValue::kIsArguments)) {
2257     owner()->Bailout("bad value context for arguments value");
2258   }
2259   owner()->Push(value);
2260 }
2261 
2262 
ReturnValue(HValue * value)2263 void TestContext::ReturnValue(HValue* value) {
2264   BuildBranch(value);
2265 }
2266 
2267 
ReturnInstruction(HInstruction * instr,int ast_id)2268 void EffectContext::ReturnInstruction(HInstruction* instr, int ast_id) {
2269   ASSERT(!instr->IsControlInstruction());
2270   owner()->AddInstruction(instr);
2271   if (instr->HasObservableSideEffects()) owner()->AddSimulate(ast_id);
2272 }
2273 
2274 
ReturnControl(HControlInstruction * instr,int ast_id)2275 void EffectContext::ReturnControl(HControlInstruction* instr, int ast_id) {
2276   ASSERT(!instr->HasObservableSideEffects());
2277   HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock();
2278   HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock();
2279   instr->SetSuccessorAt(0, empty_true);
2280   instr->SetSuccessorAt(1, empty_false);
2281   owner()->current_block()->Finish(instr);
2282   HBasicBlock* join = owner()->CreateJoin(empty_true, empty_false, ast_id);
2283   owner()->set_current_block(join);
2284 }
2285 
2286 
ReturnInstruction(HInstruction * instr,int ast_id)2287 void ValueContext::ReturnInstruction(HInstruction* instr, int ast_id) {
2288   ASSERT(!instr->IsControlInstruction());
2289   if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) {
2290     return owner()->Bailout("bad value context for arguments object value");
2291   }
2292   owner()->AddInstruction(instr);
2293   owner()->Push(instr);
2294   if (instr->HasObservableSideEffects()) owner()->AddSimulate(ast_id);
2295 }
2296 
2297 
ReturnControl(HControlInstruction * instr,int ast_id)2298 void ValueContext::ReturnControl(HControlInstruction* instr, int ast_id) {
2299   ASSERT(!instr->HasObservableSideEffects());
2300   if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) {
2301     return owner()->Bailout("bad value context for arguments object value");
2302   }
2303   HBasicBlock* materialize_false = owner()->graph()->CreateBasicBlock();
2304   HBasicBlock* materialize_true = owner()->graph()->CreateBasicBlock();
2305   instr->SetSuccessorAt(0, materialize_true);
2306   instr->SetSuccessorAt(1, materialize_false);
2307   owner()->current_block()->Finish(instr);
2308   owner()->set_current_block(materialize_true);
2309   owner()->Push(owner()->graph()->GetConstantTrue());
2310   owner()->set_current_block(materialize_false);
2311   owner()->Push(owner()->graph()->GetConstantFalse());
2312   HBasicBlock* join =
2313     owner()->CreateJoin(materialize_true, materialize_false, ast_id);
2314   owner()->set_current_block(join);
2315 }
2316 
2317 
ReturnInstruction(HInstruction * instr,int ast_id)2318 void TestContext::ReturnInstruction(HInstruction* instr, int ast_id) {
2319   ASSERT(!instr->IsControlInstruction());
2320   HGraphBuilder* builder = owner();
2321   builder->AddInstruction(instr);
2322   // We expect a simulate after every expression with side effects, though
2323   // this one isn't actually needed (and wouldn't work if it were targeted).
2324   if (instr->HasObservableSideEffects()) {
2325     builder->Push(instr);
2326     builder->AddSimulate(ast_id);
2327     builder->Pop();
2328   }
2329   BuildBranch(instr);
2330 }
2331 
2332 
ReturnControl(HControlInstruction * instr,int ast_id)2333 void TestContext::ReturnControl(HControlInstruction* instr, int ast_id) {
2334   ASSERT(!instr->HasObservableSideEffects());
2335   HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock();
2336   HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock();
2337   instr->SetSuccessorAt(0, empty_true);
2338   instr->SetSuccessorAt(1, empty_false);
2339   owner()->current_block()->Finish(instr);
2340   empty_true->Goto(if_true(), owner()->function_state()->drop_extra());
2341   empty_false->Goto(if_false(), owner()->function_state()->drop_extra());
2342   owner()->set_current_block(NULL);
2343 }
2344 
2345 
BuildBranch(HValue * value)2346 void TestContext::BuildBranch(HValue* value) {
2347   // We expect the graph to be in edge-split form: there is no edge that
2348   // connects a branch node to a join node.  We conservatively ensure that
2349   // property by always adding an empty block on the outgoing edges of this
2350   // branch.
2351   HGraphBuilder* builder = owner();
2352   if (value != NULL && value->CheckFlag(HValue::kIsArguments)) {
2353     builder->Bailout("arguments object value in a test context");
2354   }
2355   HBasicBlock* empty_true = builder->graph()->CreateBasicBlock();
2356   HBasicBlock* empty_false = builder->graph()->CreateBasicBlock();
2357   unsigned test_id = condition()->test_id();
2358   ToBooleanStub::Types expected(builder->oracle()->ToBooleanTypes(test_id));
2359   HBranch* test = new(zone()) HBranch(value, empty_true, empty_false, expected);
2360   builder->current_block()->Finish(test);
2361 
2362   empty_true->Goto(if_true(), owner()->function_state()->drop_extra());
2363   empty_false->Goto(if_false(), owner()->function_state()->drop_extra());
2364   builder->set_current_block(NULL);
2365 }
2366 
2367 
2368 // HGraphBuilder infrastructure for bailing out and checking bailouts.
2369 #define CHECK_BAILOUT(call)                     \
2370   do {                                          \
2371     call;                                       \
2372     if (HasStackOverflow()) return;             \
2373   } while (false)
2374 
2375 
2376 #define CHECK_ALIVE(call)                                       \
2377   do {                                                          \
2378     call;                                                       \
2379     if (HasStackOverflow() || current_block() == NULL) return;  \
2380   } while (false)
2381 
2382 
Bailout(const char * reason)2383 void HGraphBuilder::Bailout(const char* reason) {
2384   if (FLAG_trace_bailout) {
2385     SmartArrayPointer<char> name(
2386         info()->shared_info()->DebugName()->ToCString());
2387     PrintF("Bailout in HGraphBuilder: @\"%s\": %s\n", *name, reason);
2388   }
2389   SetStackOverflow();
2390 }
2391 
2392 
VisitForEffect(Expression * expr)2393 void HGraphBuilder::VisitForEffect(Expression* expr) {
2394   EffectContext for_effect(this);
2395   Visit(expr);
2396 }
2397 
2398 
VisitForValue(Expression * expr,ArgumentsAllowedFlag flag)2399 void HGraphBuilder::VisitForValue(Expression* expr, ArgumentsAllowedFlag flag) {
2400   ValueContext for_value(this, flag);
2401   Visit(expr);
2402 }
2403 
2404 
VisitForTypeOf(Expression * expr)2405 void HGraphBuilder::VisitForTypeOf(Expression* expr) {
2406   ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED);
2407   for_value.set_for_typeof(true);
2408   Visit(expr);
2409 }
2410 
2411 
2412 
VisitForControl(Expression * expr,HBasicBlock * true_block,HBasicBlock * false_block)2413 void HGraphBuilder::VisitForControl(Expression* expr,
2414                                     HBasicBlock* true_block,
2415                                     HBasicBlock* false_block) {
2416   TestContext for_test(this, expr, true_block, false_block);
2417   Visit(expr);
2418 }
2419 
2420 
VisitArgument(Expression * expr)2421 HValue* HGraphBuilder::VisitArgument(Expression* expr) {
2422   VisitForValue(expr);
2423   if (HasStackOverflow() || current_block() == NULL) return NULL;
2424   HValue* value = Pop();
2425   Push(AddInstruction(new(zone()) HPushArgument(value)));
2426   return value;
2427 }
2428 
2429 
VisitArgumentList(ZoneList<Expression * > * arguments)2430 void HGraphBuilder::VisitArgumentList(ZoneList<Expression*>* arguments) {
2431   for (int i = 0; i < arguments->length(); i++) {
2432     CHECK_ALIVE(VisitArgument(arguments->at(i)));
2433   }
2434 }
2435 
2436 
VisitExpressions(ZoneList<Expression * > * exprs)2437 void HGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs) {
2438   for (int i = 0; i < exprs->length(); ++i) {
2439     CHECK_ALIVE(VisitForValue(exprs->at(i)));
2440   }
2441 }
2442 
2443 
CreateGraph()2444 HGraph* HGraphBuilder::CreateGraph() {
2445   graph_ = new(zone()) HGraph(info());
2446   if (FLAG_hydrogen_stats) HStatistics::Instance()->Initialize(info());
2447 
2448   {
2449     HPhase phase("H_Block building");
2450     current_block_ = graph()->entry_block();
2451 
2452     Scope* scope = info()->scope();
2453     if (scope->HasIllegalRedeclaration()) {
2454       Bailout("function with illegal redeclaration");
2455       return NULL;
2456     }
2457     if (scope->calls_eval()) {
2458       Bailout("function calls eval");
2459       return NULL;
2460     }
2461     SetUpScope(scope);
2462 
2463     // Add an edge to the body entry.  This is warty: the graph's start
2464     // environment will be used by the Lithium translation as the initial
2465     // environment on graph entry, but it has now been mutated by the
2466     // Hydrogen translation of the instructions in the start block.  This
2467     // environment uses values which have not been defined yet.  These
2468     // Hydrogen instructions will then be replayed by the Lithium
2469     // translation, so they cannot have an environment effect.  The edge to
2470     // the body's entry block (along with some special logic for the start
2471     // block in HInstruction::InsertAfter) seals the start block from
2472     // getting unwanted instructions inserted.
2473     //
2474     // TODO(kmillikin): Fix this.  Stop mutating the initial environment.
2475     // Make the Hydrogen instructions in the initial block into Hydrogen
2476     // values (but not instructions), present in the initial environment and
2477     // not replayed by the Lithium translation.
2478     HEnvironment* initial_env = environment()->CopyWithoutHistory();
2479     HBasicBlock* body_entry = CreateBasicBlock(initial_env);
2480     current_block()->Goto(body_entry);
2481     body_entry->SetJoinId(AstNode::kFunctionEntryId);
2482     set_current_block(body_entry);
2483 
2484     // Handle implicit declaration of the function name in named function
2485     // expressions before other declarations.
2486     if (scope->is_function_scope() && scope->function() != NULL) {
2487       HandleDeclaration(scope->function(), CONST, NULL, NULL);
2488     }
2489     VisitDeclarations(scope->declarations());
2490     AddSimulate(AstNode::kDeclarationsId);
2491 
2492     HValue* context = environment()->LookupContext();
2493     AddInstruction(
2494         new(zone()) HStackCheck(context, HStackCheck::kFunctionEntry));
2495 
2496     VisitStatements(info()->function()->body());
2497     if (HasStackOverflow()) return NULL;
2498 
2499     if (current_block() != NULL) {
2500       HReturn* instr = new(zone()) HReturn(graph()->GetConstantUndefined());
2501       current_block()->FinishExit(instr);
2502       set_current_block(NULL);
2503     }
2504   }
2505 
2506   graph()->OrderBlocks();
2507   graph()->AssignDominators();
2508 
2509 #ifdef DEBUG
2510   // Do a full verify after building the graph and computing dominators.
2511   graph()->Verify(true);
2512 #endif
2513 
2514   graph()->PropagateDeoptimizingMark();
2515   if (!graph()->CheckConstPhiUses()) {
2516     Bailout("Unsupported phi use of const variable");
2517     return NULL;
2518   }
2519   graph()->EliminateRedundantPhis();
2520   if (!graph()->CheckArgumentsPhiUses()) {
2521     Bailout("Unsupported phi use of arguments");
2522     return NULL;
2523   }
2524   if (FLAG_eliminate_dead_phis) graph()->EliminateUnreachablePhis();
2525   graph()->CollectPhis();
2526 
2527   if (graph()->has_osr_loop_entry()) {
2528     const ZoneList<HPhi*>* phis = graph()->osr_loop_entry()->phis();
2529     for (int j = 0; j < phis->length(); j++) {
2530       HPhi* phi = phis->at(j);
2531       graph()->osr_values()->at(phi->merged_index())->set_incoming_value(phi);
2532     }
2533   }
2534 
2535   HInferRepresentation rep(graph());
2536   rep.Analyze();
2537 
2538   graph()->MarkDeoptimizeOnUndefined();
2539   graph()->InsertRepresentationChanges();
2540 
2541   graph()->InitializeInferredTypes();
2542   graph()->Canonicalize();
2543 
2544   // Perform common subexpression elimination and loop-invariant code motion.
2545   if (FLAG_use_gvn) {
2546     HPhase phase("H_Global value numbering", graph());
2547     HGlobalValueNumberer gvn(graph(), info());
2548     bool removed_side_effects = gvn.Analyze();
2549     // Trigger a second analysis pass to further eliminate duplicate values that
2550     // could only be discovered by removing side-effect-generating instructions
2551     // during the first pass.
2552     if (FLAG_smi_only_arrays && removed_side_effects) {
2553       removed_side_effects = gvn.Analyze();
2554       ASSERT(!removed_side_effects);
2555     }
2556   }
2557 
2558   if (FLAG_use_range) {
2559     HRangeAnalysis rangeAnalysis(graph());
2560     rangeAnalysis.Analyze();
2561   }
2562   graph()->ComputeMinusZeroChecks();
2563 
2564   // Eliminate redundant stack checks on backwards branches.
2565   HStackCheckEliminator sce(graph());
2566   sce.Process();
2567 
2568   // Replace the results of check instructions with the original value, if the
2569   // result is used. This is safe now, since we don't do code motion after this
2570   // point. It enables better register allocation since the value produced by
2571   // check instructions is really a copy of the original value.
2572   graph()->ReplaceCheckedValues();
2573 
2574   return graph();
2575 }
2576 
2577 
ReplaceCheckedValues()2578 void HGraph::ReplaceCheckedValues() {
2579   HPhase phase("H_Replace checked values", this);
2580   for (int i = 0; i < blocks()->length(); ++i) {
2581     HInstruction* instr = blocks()->at(i)->first();
2582     while (instr != NULL) {
2583       if (instr->IsBoundsCheck()) {
2584         // Replace all uses of the checked value with the original input.
2585         ASSERT(instr->UseCount() > 0);
2586         instr->ReplaceAllUsesWith(HBoundsCheck::cast(instr)->index());
2587       }
2588       instr = instr->next();
2589     }
2590   }
2591 }
2592 
2593 
AddInstruction(HInstruction * instr)2594 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
2595   ASSERT(current_block() != NULL);
2596   current_block()->AddInstruction(instr);
2597   return instr;
2598 }
2599 
2600 
AddSimulate(int ast_id)2601 void HGraphBuilder::AddSimulate(int ast_id) {
2602   ASSERT(current_block() != NULL);
2603   current_block()->AddSimulate(ast_id);
2604 }
2605 
2606 
AddPhi(HPhi * instr)2607 void HGraphBuilder::AddPhi(HPhi* instr) {
2608   ASSERT(current_block() != NULL);
2609   current_block()->AddPhi(instr);
2610 }
2611 
2612 
PushAndAdd(HInstruction * instr)2613 void HGraphBuilder::PushAndAdd(HInstruction* instr) {
2614   Push(instr);
2615   AddInstruction(instr);
2616 }
2617 
2618 
2619 template <class Instruction>
PreProcessCall(Instruction * call)2620 HInstruction* HGraphBuilder::PreProcessCall(Instruction* call) {
2621   int count = call->argument_count();
2622   ZoneList<HValue*> arguments(count);
2623   for (int i = 0; i < count; ++i) {
2624     arguments.Add(Pop());
2625   }
2626 
2627   while (!arguments.is_empty()) {
2628     AddInstruction(new(zone()) HPushArgument(arguments.RemoveLast()));
2629   }
2630   return call;
2631 }
2632 
2633 
SetUpScope(Scope * scope)2634 void HGraphBuilder::SetUpScope(Scope* scope) {
2635   HConstant* undefined_constant = new(zone()) HConstant(
2636       isolate()->factory()->undefined_value(), Representation::Tagged());
2637   AddInstruction(undefined_constant);
2638   graph_->set_undefined_constant(undefined_constant);
2639 
2640   HArgumentsObject* object = new(zone()) HArgumentsObject;
2641   AddInstruction(object);
2642   graph()->SetArgumentsObject(object);
2643 
2644   // Set the initial values of parameters including "this".  "This" has
2645   // parameter index 0.
2646   ASSERT_EQ(scope->num_parameters() + 1, environment()->parameter_count());
2647 
2648   for (int i = 0; i < environment()->parameter_count(); ++i) {
2649     HInstruction* parameter = AddInstruction(new(zone()) HParameter(i));
2650     environment()->Bind(i, parameter);
2651   }
2652 
2653   // First special is HContext.
2654   HInstruction* context = AddInstruction(new(zone()) HContext);
2655   environment()->BindContext(context);
2656 
2657   // Initialize specials and locals to undefined.
2658   for (int i = environment()->parameter_count() + 1;
2659        i < environment()->length();
2660        ++i) {
2661     environment()->Bind(i, undefined_constant);
2662   }
2663 
2664   // Handle the arguments and arguments shadow variables specially (they do
2665   // not have declarations).
2666   if (scope->arguments() != NULL) {
2667     if (!scope->arguments()->IsStackAllocated()) {
2668       return Bailout("context-allocated arguments");
2669     }
2670 
2671     environment()->Bind(scope->arguments(),
2672                         graph()->GetArgumentsObject());
2673   }
2674 }
2675 
2676 
VisitStatements(ZoneList<Statement * > * statements)2677 void HGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) {
2678   for (int i = 0; i < statements->length(); i++) {
2679     CHECK_ALIVE(Visit(statements->at(i)));
2680   }
2681 }
2682 
2683 
CreateBasicBlock(HEnvironment * env)2684 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) {
2685   HBasicBlock* b = graph()->CreateBasicBlock();
2686   b->SetInitialEnvironment(env);
2687   return b;
2688 }
2689 
2690 
CreateLoopHeaderBlock()2691 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() {
2692   HBasicBlock* header = graph()->CreateBasicBlock();
2693   HEnvironment* entry_env = environment()->CopyAsLoopHeader(header);
2694   header->SetInitialEnvironment(entry_env);
2695   header->AttachLoopInformation();
2696   return header;
2697 }
2698 
2699 
VisitBlock(Block * stmt)2700 void HGraphBuilder::VisitBlock(Block* stmt) {
2701   ASSERT(!HasStackOverflow());
2702   ASSERT(current_block() != NULL);
2703   ASSERT(current_block()->HasPredecessor());
2704   if (stmt->block_scope() != NULL) {
2705     return Bailout("ScopedBlock");
2706   }
2707   BreakAndContinueInfo break_info(stmt);
2708   { BreakAndContinueScope push(&break_info, this);
2709     CHECK_BAILOUT(VisitStatements(stmt->statements()));
2710   }
2711   HBasicBlock* break_block = break_info.break_block();
2712   if (break_block != NULL) {
2713     if (current_block() != NULL) current_block()->Goto(break_block);
2714     break_block->SetJoinId(stmt->ExitId());
2715     set_current_block(break_block);
2716   }
2717 }
2718 
2719 
VisitExpressionStatement(ExpressionStatement * stmt)2720 void HGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) {
2721   ASSERT(!HasStackOverflow());
2722   ASSERT(current_block() != NULL);
2723   ASSERT(current_block()->HasPredecessor());
2724   VisitForEffect(stmt->expression());
2725 }
2726 
2727 
VisitEmptyStatement(EmptyStatement * stmt)2728 void HGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
2729   ASSERT(!HasStackOverflow());
2730   ASSERT(current_block() != NULL);
2731   ASSERT(current_block()->HasPredecessor());
2732 }
2733 
2734 
VisitIfStatement(IfStatement * stmt)2735 void HGraphBuilder::VisitIfStatement(IfStatement* stmt) {
2736   ASSERT(!HasStackOverflow());
2737   ASSERT(current_block() != NULL);
2738   ASSERT(current_block()->HasPredecessor());
2739   if (stmt->condition()->ToBooleanIsTrue()) {
2740     AddSimulate(stmt->ThenId());
2741     Visit(stmt->then_statement());
2742   } else if (stmt->condition()->ToBooleanIsFalse()) {
2743     AddSimulate(stmt->ElseId());
2744     Visit(stmt->else_statement());
2745   } else {
2746     HBasicBlock* cond_true = graph()->CreateBasicBlock();
2747     HBasicBlock* cond_false = graph()->CreateBasicBlock();
2748     CHECK_BAILOUT(VisitForControl(stmt->condition(), cond_true, cond_false));
2749 
2750     if (cond_true->HasPredecessor()) {
2751       cond_true->SetJoinId(stmt->ThenId());
2752       set_current_block(cond_true);
2753       CHECK_BAILOUT(Visit(stmt->then_statement()));
2754       cond_true = current_block();
2755     } else {
2756       cond_true = NULL;
2757     }
2758 
2759     if (cond_false->HasPredecessor()) {
2760       cond_false->SetJoinId(stmt->ElseId());
2761       set_current_block(cond_false);
2762       CHECK_BAILOUT(Visit(stmt->else_statement()));
2763       cond_false = current_block();
2764     } else {
2765       cond_false = NULL;
2766     }
2767 
2768     HBasicBlock* join = CreateJoin(cond_true, cond_false, stmt->IfId());
2769     set_current_block(join);
2770   }
2771 }
2772 
2773 
Get(BreakableStatement * stmt,BreakType type,int * drop_extra)2774 HBasicBlock* HGraphBuilder::BreakAndContinueScope::Get(
2775     BreakableStatement* stmt,
2776     BreakType type,
2777     int* drop_extra) {
2778   *drop_extra = 0;
2779   BreakAndContinueScope* current = this;
2780   while (current != NULL && current->info()->target() != stmt) {
2781     *drop_extra += current->info()->drop_extra();
2782     current = current->next();
2783   }
2784   ASSERT(current != NULL);  // Always found (unless stack is malformed).
2785 
2786   if (type == BREAK) {
2787     *drop_extra += current->info()->drop_extra();
2788   }
2789 
2790   HBasicBlock* block = NULL;
2791   switch (type) {
2792     case BREAK:
2793       block = current->info()->break_block();
2794       if (block == NULL) {
2795         block = current->owner()->graph()->CreateBasicBlock();
2796         current->info()->set_break_block(block);
2797       }
2798       break;
2799 
2800     case CONTINUE:
2801       block = current->info()->continue_block();
2802       if (block == NULL) {
2803         block = current->owner()->graph()->CreateBasicBlock();
2804         current->info()->set_continue_block(block);
2805       }
2806       break;
2807   }
2808 
2809   return block;
2810 }
2811 
2812 
VisitContinueStatement(ContinueStatement * stmt)2813 void HGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) {
2814   ASSERT(!HasStackOverflow());
2815   ASSERT(current_block() != NULL);
2816   ASSERT(current_block()->HasPredecessor());
2817   int drop_extra = 0;
2818   HBasicBlock* continue_block = break_scope()->Get(stmt->target(),
2819                                                    CONTINUE,
2820                                                    &drop_extra);
2821   Drop(drop_extra);
2822   current_block()->Goto(continue_block);
2823   set_current_block(NULL);
2824 }
2825 
2826 
VisitBreakStatement(BreakStatement * stmt)2827 void HGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
2828   ASSERT(!HasStackOverflow());
2829   ASSERT(current_block() != NULL);
2830   ASSERT(current_block()->HasPredecessor());
2831   int drop_extra = 0;
2832   HBasicBlock* break_block = break_scope()->Get(stmt->target(),
2833                                                 BREAK,
2834                                                 &drop_extra);
2835   Drop(drop_extra);
2836   current_block()->Goto(break_block);
2837   set_current_block(NULL);
2838 }
2839 
2840 
VisitReturnStatement(ReturnStatement * stmt)2841 void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
2842   ASSERT(!HasStackOverflow());
2843   ASSERT(current_block() != NULL);
2844   ASSERT(current_block()->HasPredecessor());
2845   AstContext* context = call_context();
2846   if (context == NULL) {
2847     // Not an inlined return, so an actual one.
2848     CHECK_ALIVE(VisitForValue(stmt->expression()));
2849     HValue* result = environment()->Pop();
2850     current_block()->FinishExit(new(zone()) HReturn(result));
2851   } else if (function_state()->is_construct()) {
2852     // Return from an inlined construct call.  In a test context the return
2853     // value will always evaluate to true, in a value context the return value
2854     // needs to be a JSObject.
2855     if (context->IsTest()) {
2856       TestContext* test = TestContext::cast(context);
2857       CHECK_ALIVE(VisitForEffect(stmt->expression()));
2858       current_block()->Goto(test->if_true(), function_state()->drop_extra());
2859     } else if (context->IsEffect()) {
2860       CHECK_ALIVE(VisitForEffect(stmt->expression()));
2861       current_block()->Goto(function_return(), function_state()->drop_extra());
2862     } else {
2863       ASSERT(context->IsValue());
2864       CHECK_ALIVE(VisitForValue(stmt->expression()));
2865       HValue* return_value = Pop();
2866       HValue* receiver = environment()->Lookup(0);
2867       HHasInstanceTypeAndBranch* typecheck =
2868           new(zone()) HHasInstanceTypeAndBranch(return_value,
2869                                                 FIRST_SPEC_OBJECT_TYPE,
2870                                                 LAST_SPEC_OBJECT_TYPE);
2871       HBasicBlock* if_spec_object = graph()->CreateBasicBlock();
2872       HBasicBlock* not_spec_object = graph()->CreateBasicBlock();
2873       typecheck->SetSuccessorAt(0, if_spec_object);
2874       typecheck->SetSuccessorAt(1, not_spec_object);
2875       current_block()->Finish(typecheck);
2876       if_spec_object->AddLeaveInlined(return_value,
2877                                       function_return(),
2878                                       function_state()->drop_extra());
2879       not_spec_object->AddLeaveInlined(receiver,
2880                                        function_return(),
2881                                        function_state()->drop_extra());
2882     }
2883   } else {
2884     // Return from an inlined function, visit the subexpression in the
2885     // expression context of the call.
2886     if (context->IsTest()) {
2887       TestContext* test = TestContext::cast(context);
2888       VisitForControl(stmt->expression(),
2889                       test->if_true(),
2890                       test->if_false());
2891     } else if (context->IsEffect()) {
2892       CHECK_ALIVE(VisitForEffect(stmt->expression()));
2893       current_block()->Goto(function_return(), function_state()->drop_extra());
2894     } else {
2895       ASSERT(context->IsValue());
2896       CHECK_ALIVE(VisitForValue(stmt->expression()));
2897       HValue* return_value = Pop();
2898       current_block()->AddLeaveInlined(return_value,
2899                                        function_return(),
2900                                        function_state()->drop_extra());
2901     }
2902   }
2903   set_current_block(NULL);
2904 }
2905 
2906 
VisitWithStatement(WithStatement * stmt)2907 void HGraphBuilder::VisitWithStatement(WithStatement* stmt) {
2908   ASSERT(!HasStackOverflow());
2909   ASSERT(current_block() != NULL);
2910   ASSERT(current_block()->HasPredecessor());
2911   return Bailout("WithStatement");
2912 }
2913 
2914 
VisitSwitchStatement(SwitchStatement * stmt)2915 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
2916   ASSERT(!HasStackOverflow());
2917   ASSERT(current_block() != NULL);
2918   ASSERT(current_block()->HasPredecessor());
2919   // We only optimize switch statements with smi-literal smi comparisons,
2920   // with a bounded number of clauses.
2921   const int kCaseClauseLimit = 128;
2922   ZoneList<CaseClause*>* clauses = stmt->cases();
2923   int clause_count = clauses->length();
2924   if (clause_count > kCaseClauseLimit) {
2925     return Bailout("SwitchStatement: too many clauses");
2926   }
2927 
2928   HValue* context = environment()->LookupContext();
2929 
2930   CHECK_ALIVE(VisitForValue(stmt->tag()));
2931   AddSimulate(stmt->EntryId());
2932   HValue* tag_value = Pop();
2933   HBasicBlock* first_test_block = current_block();
2934 
2935   SwitchType switch_type = UNKNOWN_SWITCH;
2936 
2937   // 1. Extract clause type
2938   for (int i = 0; i < clause_count; ++i) {
2939     CaseClause* clause = clauses->at(i);
2940     if (clause->is_default()) continue;
2941 
2942     if (switch_type == UNKNOWN_SWITCH) {
2943       if (clause->label()->IsSmiLiteral()) {
2944         switch_type = SMI_SWITCH;
2945       } else if (clause->label()->IsStringLiteral()) {
2946         switch_type = STRING_SWITCH;
2947       } else {
2948         return Bailout("SwitchStatement: non-literal switch label");
2949       }
2950     } else if ((switch_type == STRING_SWITCH &&
2951                 !clause->label()->IsStringLiteral()) ||
2952                (switch_type == SMI_SWITCH &&
2953                 !clause->label()->IsSmiLiteral())) {
2954       return Bailout("SwitchStatemnt: mixed label types are not supported");
2955     }
2956   }
2957 
2958   HUnaryControlInstruction* string_check = NULL;
2959   HBasicBlock* not_string_block = NULL;
2960 
2961   // Test switch's tag value if all clauses are string literals
2962   if (switch_type == STRING_SWITCH) {
2963     string_check = new(zone()) HIsStringAndBranch(tag_value);
2964     first_test_block = graph()->CreateBasicBlock();
2965     not_string_block = graph()->CreateBasicBlock();
2966 
2967     string_check->SetSuccessorAt(0, first_test_block);
2968     string_check->SetSuccessorAt(1, not_string_block);
2969     current_block()->Finish(string_check);
2970 
2971     set_current_block(first_test_block);
2972   }
2973 
2974   // 2. Build all the tests, with dangling true branches
2975   int default_id = AstNode::kNoNumber;
2976   for (int i = 0; i < clause_count; ++i) {
2977     CaseClause* clause = clauses->at(i);
2978     if (clause->is_default()) {
2979       default_id = clause->EntryId();
2980       continue;
2981     }
2982     if (switch_type == SMI_SWITCH) {
2983       clause->RecordTypeFeedback(oracle());
2984     }
2985 
2986     // Generate a compare and branch.
2987     CHECK_ALIVE(VisitForValue(clause->label()));
2988     HValue* label_value = Pop();
2989 
2990     HBasicBlock* next_test_block = graph()->CreateBasicBlock();
2991     HBasicBlock* body_block = graph()->CreateBasicBlock();
2992 
2993     HControlInstruction* compare;
2994 
2995     if (switch_type == SMI_SWITCH) {
2996       if (!clause->IsSmiCompare()) {
2997         // Finish with deoptimize and add uses of enviroment values to
2998         // account for invisible uses.
2999         current_block()->FinishExitWithDeoptimization(HDeoptimize::kUseAll);
3000         set_current_block(NULL);
3001         break;
3002       }
3003 
3004       HCompareIDAndBranch* compare_ =
3005           new(zone()) HCompareIDAndBranch(tag_value,
3006                                           label_value,
3007                                           Token::EQ_STRICT);
3008       compare_->SetInputRepresentation(Representation::Integer32());
3009       compare = compare_;
3010     } else {
3011       compare = new(zone()) HStringCompareAndBranch(context, tag_value,
3012                                                      label_value,
3013                                                      Token::EQ_STRICT);
3014     }
3015 
3016     compare->SetSuccessorAt(0, body_block);
3017     compare->SetSuccessorAt(1, next_test_block);
3018     current_block()->Finish(compare);
3019 
3020     set_current_block(next_test_block);
3021   }
3022 
3023   // Save the current block to use for the default or to join with the
3024   // exit.  This block is NULL if we deoptimized.
3025   HBasicBlock* last_block = current_block();
3026 
3027   if (not_string_block != NULL) {
3028     int join_id = (default_id != AstNode::kNoNumber)
3029         ? default_id
3030         : stmt->ExitId();
3031     last_block = CreateJoin(last_block, not_string_block, join_id);
3032   }
3033 
3034   // 3. Loop over the clauses and the linked list of tests in lockstep,
3035   // translating the clause bodies.
3036   HBasicBlock* curr_test_block = first_test_block;
3037   HBasicBlock* fall_through_block = NULL;
3038 
3039   BreakAndContinueInfo break_info(stmt);
3040   { BreakAndContinueScope push(&break_info, this);
3041     for (int i = 0; i < clause_count; ++i) {
3042       CaseClause* clause = clauses->at(i);
3043 
3044       // Identify the block where normal (non-fall-through) control flow
3045       // goes to.
3046       HBasicBlock* normal_block = NULL;
3047       if (clause->is_default()) {
3048         if (last_block != NULL) {
3049           normal_block = last_block;
3050           last_block = NULL;  // Cleared to indicate we've handled it.
3051         }
3052       } else if (!curr_test_block->end()->IsDeoptimize()) {
3053         normal_block = curr_test_block->end()->FirstSuccessor();
3054         curr_test_block = curr_test_block->end()->SecondSuccessor();
3055       }
3056 
3057       // Identify a block to emit the body into.
3058       if (normal_block == NULL) {
3059         if (fall_through_block == NULL) {
3060           // (a) Unreachable.
3061           if (clause->is_default()) {
3062             continue;  // Might still be reachable clause bodies.
3063           } else {
3064             break;
3065           }
3066         } else {
3067           // (b) Reachable only as fall through.
3068           set_current_block(fall_through_block);
3069         }
3070       } else if (fall_through_block == NULL) {
3071         // (c) Reachable only normally.
3072         set_current_block(normal_block);
3073       } else {
3074         // (d) Reachable both ways.
3075         HBasicBlock* join = CreateJoin(fall_through_block,
3076                                        normal_block,
3077                                        clause->EntryId());
3078         set_current_block(join);
3079       }
3080 
3081       CHECK_BAILOUT(VisitStatements(clause->statements()));
3082       fall_through_block = current_block();
3083     }
3084   }
3085 
3086   // Create an up-to-3-way join.  Use the break block if it exists since
3087   // it's already a join block.
3088   HBasicBlock* break_block = break_info.break_block();
3089   if (break_block == NULL) {
3090     set_current_block(CreateJoin(fall_through_block,
3091                                  last_block,
3092                                  stmt->ExitId()));
3093   } else {
3094     if (fall_through_block != NULL) fall_through_block->Goto(break_block);
3095     if (last_block != NULL) last_block->Goto(break_block);
3096     break_block->SetJoinId(stmt->ExitId());
3097     set_current_block(break_block);
3098   }
3099 }
3100 
3101 
HasOsrEntryAt(IterationStatement * statement)3102 bool HGraphBuilder::HasOsrEntryAt(IterationStatement* statement) {
3103   return statement->OsrEntryId() == info()->osr_ast_id();
3104 }
3105 
3106 
PreProcessOsrEntry(IterationStatement * statement)3107 bool HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) {
3108   if (!HasOsrEntryAt(statement)) return false;
3109 
3110   HBasicBlock* non_osr_entry = graph()->CreateBasicBlock();
3111   HBasicBlock* osr_entry = graph()->CreateBasicBlock();
3112   HValue* true_value = graph()->GetConstantTrue();
3113   HBranch* test = new(zone()) HBranch(true_value, non_osr_entry, osr_entry);
3114   current_block()->Finish(test);
3115 
3116   HBasicBlock* loop_predecessor = graph()->CreateBasicBlock();
3117   non_osr_entry->Goto(loop_predecessor);
3118 
3119   set_current_block(osr_entry);
3120   int osr_entry_id = statement->OsrEntryId();
3121   int first_expression_index = environment()->first_expression_index();
3122   int length = environment()->length();
3123   ZoneList<HUnknownOSRValue*>* osr_values =
3124       new(zone()) ZoneList<HUnknownOSRValue*>(length);
3125 
3126   for (int i = 0; i < first_expression_index; ++i) {
3127     HUnknownOSRValue* osr_value = new(zone()) HUnknownOSRValue;
3128     AddInstruction(osr_value);
3129     environment()->Bind(i, osr_value);
3130     osr_values->Add(osr_value);
3131   }
3132 
3133   if (first_expression_index != length) {
3134     environment()->Drop(length - first_expression_index);
3135     for (int i = first_expression_index; i < length; ++i) {
3136       HUnknownOSRValue* osr_value = new(zone()) HUnknownOSRValue;
3137       AddInstruction(osr_value);
3138       environment()->Push(osr_value);
3139       osr_values->Add(osr_value);
3140     }
3141   }
3142 
3143   graph()->set_osr_values(osr_values);
3144 
3145   AddSimulate(osr_entry_id);
3146   AddInstruction(new(zone()) HOsrEntry(osr_entry_id));
3147   HContext* context = new(zone()) HContext;
3148   AddInstruction(context);
3149   environment()->BindContext(context);
3150   current_block()->Goto(loop_predecessor);
3151   loop_predecessor->SetJoinId(statement->EntryId());
3152   set_current_block(loop_predecessor);
3153   return true;
3154 }
3155 
3156 
VisitLoopBody(IterationStatement * stmt,HBasicBlock * loop_entry,BreakAndContinueInfo * break_info)3157 void HGraphBuilder::VisitLoopBody(IterationStatement* stmt,
3158                                   HBasicBlock* loop_entry,
3159                                   BreakAndContinueInfo* break_info) {
3160   BreakAndContinueScope push(break_info, this);
3161   AddSimulate(stmt->StackCheckId());
3162   HValue* context = environment()->LookupContext();
3163   HStackCheck* stack_check =
3164     new(zone()) HStackCheck(context, HStackCheck::kBackwardsBranch);
3165   AddInstruction(stack_check);
3166   ASSERT(loop_entry->IsLoopHeader());
3167   loop_entry->loop_information()->set_stack_check(stack_check);
3168   CHECK_BAILOUT(Visit(stmt->body()));
3169 }
3170 
3171 
VisitDoWhileStatement(DoWhileStatement * stmt)3172 void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
3173   ASSERT(!HasStackOverflow());
3174   ASSERT(current_block() != NULL);
3175   ASSERT(current_block()->HasPredecessor());
3176   ASSERT(current_block() != NULL);
3177   bool osr_entry = PreProcessOsrEntry(stmt);
3178   HBasicBlock* loop_entry = CreateLoopHeaderBlock();
3179   current_block()->Goto(loop_entry);
3180   set_current_block(loop_entry);
3181   if (osr_entry) graph()->set_osr_loop_entry(loop_entry);
3182 
3183   BreakAndContinueInfo break_info(stmt);
3184   CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
3185   HBasicBlock* body_exit =
3186       JoinContinue(stmt, current_block(), break_info.continue_block());
3187   HBasicBlock* loop_successor = NULL;
3188   if (body_exit != NULL && !stmt->cond()->ToBooleanIsTrue()) {
3189     set_current_block(body_exit);
3190     // The block for a true condition, the actual predecessor block of the
3191     // back edge.
3192     body_exit = graph()->CreateBasicBlock();
3193     loop_successor = graph()->CreateBasicBlock();
3194     CHECK_BAILOUT(VisitForControl(stmt->cond(), body_exit, loop_successor));
3195     if (body_exit->HasPredecessor()) {
3196       body_exit->SetJoinId(stmt->BackEdgeId());
3197     } else {
3198       body_exit = NULL;
3199     }
3200     if (loop_successor->HasPredecessor()) {
3201       loop_successor->SetJoinId(stmt->ExitId());
3202     } else {
3203       loop_successor = NULL;
3204     }
3205   }
3206   HBasicBlock* loop_exit = CreateLoop(stmt,
3207                                       loop_entry,
3208                                       body_exit,
3209                                       loop_successor,
3210                                       break_info.break_block());
3211   set_current_block(loop_exit);
3212 }
3213 
3214 
VisitWhileStatement(WhileStatement * stmt)3215 void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
3216   ASSERT(!HasStackOverflow());
3217   ASSERT(current_block() != NULL);
3218   ASSERT(current_block()->HasPredecessor());
3219   ASSERT(current_block() != NULL);
3220   bool osr_entry = PreProcessOsrEntry(stmt);
3221   HBasicBlock* loop_entry = CreateLoopHeaderBlock();
3222   current_block()->Goto(loop_entry);
3223   set_current_block(loop_entry);
3224   if (osr_entry) graph()->set_osr_loop_entry(loop_entry);
3225 
3226 
3227   // If the condition is constant true, do not generate a branch.
3228   HBasicBlock* loop_successor = NULL;
3229   if (!stmt->cond()->ToBooleanIsTrue()) {
3230     HBasicBlock* body_entry = graph()->CreateBasicBlock();
3231     loop_successor = graph()->CreateBasicBlock();
3232     CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor));
3233     if (body_entry->HasPredecessor()) {
3234       body_entry->SetJoinId(stmt->BodyId());
3235       set_current_block(body_entry);
3236     }
3237     if (loop_successor->HasPredecessor()) {
3238       loop_successor->SetJoinId(stmt->ExitId());
3239     } else {
3240       loop_successor = NULL;
3241     }
3242   }
3243 
3244   BreakAndContinueInfo break_info(stmt);
3245   if (current_block() != NULL) {
3246     CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
3247   }
3248   HBasicBlock* body_exit =
3249       JoinContinue(stmt, current_block(), break_info.continue_block());
3250   HBasicBlock* loop_exit = CreateLoop(stmt,
3251                                       loop_entry,
3252                                       body_exit,
3253                                       loop_successor,
3254                                       break_info.break_block());
3255   set_current_block(loop_exit);
3256 }
3257 
3258 
VisitForStatement(ForStatement * stmt)3259 void HGraphBuilder::VisitForStatement(ForStatement* stmt) {
3260   ASSERT(!HasStackOverflow());
3261   ASSERT(current_block() != NULL);
3262   ASSERT(current_block()->HasPredecessor());
3263   if (stmt->init() != NULL) {
3264     CHECK_ALIVE(Visit(stmt->init()));
3265   }
3266   ASSERT(current_block() != NULL);
3267   bool osr_entry = PreProcessOsrEntry(stmt);
3268   HBasicBlock* loop_entry = CreateLoopHeaderBlock();
3269   current_block()->Goto(loop_entry);
3270   set_current_block(loop_entry);
3271   if (osr_entry) graph()->set_osr_loop_entry(loop_entry);
3272 
3273   HBasicBlock* loop_successor = NULL;
3274   if (stmt->cond() != NULL) {
3275     HBasicBlock* body_entry = graph()->CreateBasicBlock();
3276     loop_successor = graph()->CreateBasicBlock();
3277     CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor));
3278     if (body_entry->HasPredecessor()) {
3279       body_entry->SetJoinId(stmt->BodyId());
3280       set_current_block(body_entry);
3281     }
3282     if (loop_successor->HasPredecessor()) {
3283       loop_successor->SetJoinId(stmt->ExitId());
3284     } else {
3285       loop_successor = NULL;
3286     }
3287   }
3288 
3289   BreakAndContinueInfo break_info(stmt);
3290   if (current_block() != NULL) {
3291     CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
3292   }
3293   HBasicBlock* body_exit =
3294       JoinContinue(stmt, current_block(), break_info.continue_block());
3295 
3296   if (stmt->next() != NULL && body_exit != NULL) {
3297     set_current_block(body_exit);
3298     CHECK_BAILOUT(Visit(stmt->next()));
3299     body_exit = current_block();
3300   }
3301 
3302   HBasicBlock* loop_exit = CreateLoop(stmt,
3303                                       loop_entry,
3304                                       body_exit,
3305                                       loop_successor,
3306                                       break_info.break_block());
3307   set_current_block(loop_exit);
3308 }
3309 
3310 
VisitForInStatement(ForInStatement * stmt)3311 void HGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
3312   ASSERT(!HasStackOverflow());
3313   ASSERT(current_block() != NULL);
3314   ASSERT(current_block()->HasPredecessor());
3315 
3316   if (!FLAG_optimize_for_in) {
3317     return Bailout("ForInStatement optimization is disabled");
3318   }
3319 
3320   if (!oracle()->IsForInFastCase(stmt)) {
3321     return Bailout("ForInStatement is not fast case");
3322   }
3323 
3324   if (!stmt->each()->IsVariableProxy() ||
3325       !stmt->each()->AsVariableProxy()->var()->IsStackLocal()) {
3326     return Bailout("ForInStatement with non-local each variable");
3327   }
3328 
3329   Variable* each_var = stmt->each()->AsVariableProxy()->var();
3330 
3331   CHECK_ALIVE(VisitForValue(stmt->enumerable()));
3332   HValue* enumerable = Top();  // Leave enumerable at the top.
3333 
3334   HInstruction* map = AddInstruction(new(zone()) HForInPrepareMap(
3335       environment()->LookupContext(), enumerable));
3336   AddSimulate(stmt->PrepareId());
3337 
3338   HInstruction* array = AddInstruction(
3339       new(zone()) HForInCacheArray(
3340           enumerable,
3341           map,
3342           DescriptorArray::kEnumCacheBridgeCacheIndex));
3343 
3344   HInstruction* array_length = AddInstruction(
3345       new(zone()) HFixedArrayBaseLength(array));
3346 
3347   HInstruction* start_index = AddInstruction(new(zone()) HConstant(
3348       Handle<Object>(Smi::FromInt(0)), Representation::Integer32()));
3349 
3350   Push(map);
3351   Push(array);
3352   Push(array_length);
3353   Push(start_index);
3354 
3355   HInstruction* index_cache = AddInstruction(
3356       new(zone()) HForInCacheArray(
3357           enumerable,
3358           map,
3359           DescriptorArray::kEnumCacheBridgeIndicesCacheIndex));
3360   HForInCacheArray::cast(array)->set_index_cache(
3361       HForInCacheArray::cast(index_cache));
3362 
3363   bool osr_entry = PreProcessOsrEntry(stmt);
3364   HBasicBlock* loop_entry = CreateLoopHeaderBlock();
3365   current_block()->Goto(loop_entry);
3366   set_current_block(loop_entry);
3367   if (osr_entry) graph()->set_osr_loop_entry(loop_entry);
3368 
3369   HValue* index = environment()->ExpressionStackAt(0);
3370   HValue* limit = environment()->ExpressionStackAt(1);
3371 
3372   // Check that we still have more keys.
3373   HCompareIDAndBranch* compare_index =
3374       new(zone()) HCompareIDAndBranch(index, limit, Token::LT);
3375   compare_index->SetInputRepresentation(Representation::Integer32());
3376 
3377   HBasicBlock* loop_body = graph()->CreateBasicBlock();
3378   HBasicBlock* loop_successor = graph()->CreateBasicBlock();
3379 
3380   compare_index->SetSuccessorAt(0, loop_body);
3381   compare_index->SetSuccessorAt(1, loop_successor);
3382   current_block()->Finish(compare_index);
3383 
3384   set_current_block(loop_successor);
3385   Drop(5);
3386 
3387   set_current_block(loop_body);
3388 
3389   HValue* key = AddInstruction(
3390       new(zone()) HLoadKeyedFastElement(
3391           environment()->ExpressionStackAt(2),  // Enum cache.
3392           environment()->ExpressionStackAt(0),  // Iteration index.
3393           HLoadKeyedFastElement::OMIT_HOLE_CHECK));
3394 
3395   // Check if the expected map still matches that of the enumerable.
3396   // If not just deoptimize.
3397   AddInstruction(new(zone()) HCheckMapValue(
3398       environment()->ExpressionStackAt(4),
3399       environment()->ExpressionStackAt(3)));
3400 
3401   Bind(each_var, key);
3402 
3403   BreakAndContinueInfo break_info(stmt, 5);
3404   CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
3405 
3406   HBasicBlock* body_exit =
3407       JoinContinue(stmt, current_block(), break_info.continue_block());
3408 
3409   if (body_exit != NULL) {
3410     set_current_block(body_exit);
3411 
3412     HValue* current_index = Pop();
3413     HInstruction* new_index = new(zone()) HAdd(environment()->LookupContext(),
3414                                                current_index,
3415                                                graph()->GetConstant1());
3416     new_index->AssumeRepresentation(Representation::Integer32());
3417     PushAndAdd(new_index);
3418     body_exit = current_block();
3419   }
3420 
3421   HBasicBlock* loop_exit = CreateLoop(stmt,
3422                                       loop_entry,
3423                                       body_exit,
3424                                       loop_successor,
3425                                       break_info.break_block());
3426 
3427   set_current_block(loop_exit);
3428 }
3429 
3430 
VisitTryCatchStatement(TryCatchStatement * stmt)3431 void HGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
3432   ASSERT(!HasStackOverflow());
3433   ASSERT(current_block() != NULL);
3434   ASSERT(current_block()->HasPredecessor());
3435   return Bailout("TryCatchStatement");
3436 }
3437 
3438 
VisitTryFinallyStatement(TryFinallyStatement * stmt)3439 void HGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
3440   ASSERT(!HasStackOverflow());
3441   ASSERT(current_block() != NULL);
3442   ASSERT(current_block()->HasPredecessor());
3443   return Bailout("TryFinallyStatement");
3444 }
3445 
3446 
VisitDebuggerStatement(DebuggerStatement * stmt)3447 void HGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
3448   ASSERT(!HasStackOverflow());
3449   ASSERT(current_block() != NULL);
3450   ASSERT(current_block()->HasPredecessor());
3451   return Bailout("DebuggerStatement");
3452 }
3453 
3454 
SearchSharedFunctionInfo(Code * unoptimized_code,FunctionLiteral * expr)3455 static Handle<SharedFunctionInfo> SearchSharedFunctionInfo(
3456     Code* unoptimized_code, FunctionLiteral* expr) {
3457   int start_position = expr->start_position();
3458   RelocIterator it(unoptimized_code);
3459   for (;!it.done(); it.next()) {
3460     RelocInfo* rinfo = it.rinfo();
3461     if (rinfo->rmode() != RelocInfo::EMBEDDED_OBJECT) continue;
3462     Object* obj = rinfo->target_object();
3463     if (obj->IsSharedFunctionInfo()) {
3464       SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
3465       if (shared->start_position() == start_position) {
3466         return Handle<SharedFunctionInfo>(shared);
3467       }
3468     }
3469   }
3470 
3471   return Handle<SharedFunctionInfo>();
3472 }
3473 
3474 
VisitFunctionLiteral(FunctionLiteral * expr)3475 void HGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
3476   ASSERT(!HasStackOverflow());
3477   ASSERT(current_block() != NULL);
3478   ASSERT(current_block()->HasPredecessor());
3479   Handle<SharedFunctionInfo> shared_info =
3480       SearchSharedFunctionInfo(info()->shared_info()->code(),
3481                                expr);
3482   if (shared_info.is_null()) {
3483     shared_info = Compiler::BuildFunctionInfo(expr, info()->script());
3484   }
3485   // We also have a stack overflow if the recursive compilation did.
3486   if (HasStackOverflow()) return;
3487   HValue* context = environment()->LookupContext();
3488   HFunctionLiteral* instr =
3489       new(zone()) HFunctionLiteral(context, shared_info, expr->pretenure());
3490   return ast_context()->ReturnInstruction(instr, expr->id());
3491 }
3492 
3493 
VisitSharedFunctionInfoLiteral(SharedFunctionInfoLiteral * expr)3494 void HGraphBuilder::VisitSharedFunctionInfoLiteral(
3495     SharedFunctionInfoLiteral* expr) {
3496   ASSERT(!HasStackOverflow());
3497   ASSERT(current_block() != NULL);
3498   ASSERT(current_block()->HasPredecessor());
3499   return Bailout("SharedFunctionInfoLiteral");
3500 }
3501 
3502 
VisitConditional(Conditional * expr)3503 void HGraphBuilder::VisitConditional(Conditional* expr) {
3504   ASSERT(!HasStackOverflow());
3505   ASSERT(current_block() != NULL);
3506   ASSERT(current_block()->HasPredecessor());
3507   HBasicBlock* cond_true = graph()->CreateBasicBlock();
3508   HBasicBlock* cond_false = graph()->CreateBasicBlock();
3509   CHECK_BAILOUT(VisitForControl(expr->condition(), cond_true, cond_false));
3510 
3511   // Visit the true and false subexpressions in the same AST context as the
3512   // whole expression.
3513   if (cond_true->HasPredecessor()) {
3514     cond_true->SetJoinId(expr->ThenId());
3515     set_current_block(cond_true);
3516     CHECK_BAILOUT(Visit(expr->then_expression()));
3517     cond_true = current_block();
3518   } else {
3519     cond_true = NULL;
3520   }
3521 
3522   if (cond_false->HasPredecessor()) {
3523     cond_false->SetJoinId(expr->ElseId());
3524     set_current_block(cond_false);
3525     CHECK_BAILOUT(Visit(expr->else_expression()));
3526     cond_false = current_block();
3527   } else {
3528     cond_false = NULL;
3529   }
3530 
3531   if (!ast_context()->IsTest()) {
3532     HBasicBlock* join = CreateJoin(cond_true, cond_false, expr->id());
3533     set_current_block(join);
3534     if (join != NULL && !ast_context()->IsEffect()) {
3535       return ast_context()->ReturnValue(Pop());
3536     }
3537   }
3538 }
3539 
3540 
LookupGlobalProperty(Variable * var,LookupResult * lookup,bool is_store)3541 HGraphBuilder::GlobalPropertyAccess HGraphBuilder::LookupGlobalProperty(
3542     Variable* var, LookupResult* lookup, bool is_store) {
3543   if (var->is_this() || !info()->has_global_object()) {
3544     return kUseGeneric;
3545   }
3546   Handle<GlobalObject> global(info()->global_object());
3547   global->Lookup(*var->name(), lookup);
3548   if (!lookup->IsFound() ||
3549       lookup->type() != NORMAL ||
3550       (is_store && lookup->IsReadOnly()) ||
3551       lookup->holder() != *global) {
3552     return kUseGeneric;
3553   }
3554 
3555   return kUseCell;
3556 }
3557 
3558 
BuildContextChainWalk(Variable * var)3559 HValue* HGraphBuilder::BuildContextChainWalk(Variable* var) {
3560   ASSERT(var->IsContextSlot());
3561   HValue* context = environment()->LookupContext();
3562   int length = info()->scope()->ContextChainLength(var->scope());
3563   while (length-- > 0) {
3564     HInstruction* context_instruction = new(zone()) HOuterContext(context);
3565     AddInstruction(context_instruction);
3566     context = context_instruction;
3567   }
3568   return context;
3569 }
3570 
3571 
VisitVariableProxy(VariableProxy * expr)3572 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
3573   ASSERT(!HasStackOverflow());
3574   ASSERT(current_block() != NULL);
3575   ASSERT(current_block()->HasPredecessor());
3576   Variable* variable = expr->var();
3577   switch (variable->location()) {
3578     case Variable::UNALLOCATED: {
3579       if (variable->mode() == LET || variable->mode() == CONST_HARMONY) {
3580         return Bailout("reference to global harmony declared variable");
3581       }
3582       // Handle known global constants like 'undefined' specially to avoid a
3583       // load from a global cell for them.
3584       Handle<Object> constant_value =
3585           isolate()->factory()->GlobalConstantFor(variable->name());
3586       if (!constant_value.is_null()) {
3587         HConstant* instr =
3588             new(zone()) HConstant(constant_value, Representation::Tagged());
3589         return ast_context()->ReturnInstruction(instr, expr->id());
3590       }
3591 
3592       LookupResult lookup(isolate());
3593       GlobalPropertyAccess type =
3594           LookupGlobalProperty(variable, &lookup, false);
3595 
3596       if (type == kUseCell &&
3597           info()->global_object()->IsAccessCheckNeeded()) {
3598         type = kUseGeneric;
3599       }
3600 
3601       if (type == kUseCell) {
3602         Handle<GlobalObject> global(info()->global_object());
3603         Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
3604         HLoadGlobalCell* instr =
3605             new(zone()) HLoadGlobalCell(cell, lookup.GetPropertyDetails());
3606         return ast_context()->ReturnInstruction(instr, expr->id());
3607       } else {
3608         HValue* context = environment()->LookupContext();
3609         HGlobalObject* global_object = new(zone()) HGlobalObject(context);
3610         AddInstruction(global_object);
3611         HLoadGlobalGeneric* instr =
3612             new(zone()) HLoadGlobalGeneric(context,
3613                                            global_object,
3614                                            variable->name(),
3615                                            ast_context()->is_for_typeof());
3616         instr->set_position(expr->position());
3617         return ast_context()->ReturnInstruction(instr, expr->id());
3618       }
3619     }
3620 
3621     case Variable::PARAMETER:
3622     case Variable::LOCAL: {
3623       HValue* value = environment()->Lookup(variable);
3624       if (value == graph()->GetConstantHole()) {
3625         ASSERT(variable->mode() == CONST ||
3626                variable->mode() == CONST_HARMONY ||
3627                variable->mode() == LET);
3628         return Bailout("reference to uninitialized variable");
3629       }
3630       return ast_context()->ReturnValue(value);
3631     }
3632 
3633     case Variable::CONTEXT: {
3634       HValue* context = BuildContextChainWalk(variable);
3635       HLoadContextSlot* instr = new(zone()) HLoadContextSlot(context, variable);
3636       return ast_context()->ReturnInstruction(instr, expr->id());
3637     }
3638 
3639     case Variable::LOOKUP:
3640       return Bailout("reference to a variable which requires dynamic lookup");
3641   }
3642 }
3643 
3644 
VisitLiteral(Literal * expr)3645 void HGraphBuilder::VisitLiteral(Literal* expr) {
3646   ASSERT(!HasStackOverflow());
3647   ASSERT(current_block() != NULL);
3648   ASSERT(current_block()->HasPredecessor());
3649   HConstant* instr =
3650       new(zone()) HConstant(expr->handle(), Representation::Tagged());
3651   return ast_context()->ReturnInstruction(instr, expr->id());
3652 }
3653 
3654 
VisitRegExpLiteral(RegExpLiteral * expr)3655 void HGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
3656   ASSERT(!HasStackOverflow());
3657   ASSERT(current_block() != NULL);
3658   ASSERT(current_block()->HasPredecessor());
3659   HValue* context = environment()->LookupContext();
3660 
3661   HRegExpLiteral* instr = new(zone()) HRegExpLiteral(context,
3662                                                      expr->pattern(),
3663                                                      expr->flags(),
3664                                                      expr->literal_index());
3665   return ast_context()->ReturnInstruction(instr, expr->id());
3666 }
3667 
3668 
3669 // Determines whether the given array or object literal boilerplate satisfies
3670 // all limits to be considered for fast deep-copying and computes the total
3671 // size of all objects that are part of the graph.
IsFastLiteral(Handle<JSObject> boilerplate,int max_depth,int * max_properties,int * total_size)3672 static bool IsFastLiteral(Handle<JSObject> boilerplate,
3673                           int max_depth,
3674                           int* max_properties,
3675                           int* total_size) {
3676   ASSERT(max_depth >= 0 && *max_properties >= 0);
3677   if (max_depth == 0) return false;
3678 
3679   Handle<FixedArrayBase> elements(boilerplate->elements());
3680   if (elements->length() > 0 &&
3681       elements->map() != boilerplate->GetHeap()->fixed_cow_array_map()) {
3682     if (boilerplate->HasFastDoubleElements()) {
3683       *total_size += FixedDoubleArray::SizeFor(elements->length());
3684     } else if (boilerplate->HasFastElements()) {
3685       int length = elements->length();
3686       for (int i = 0; i < length; i++) {
3687         if ((*max_properties)-- == 0) return false;
3688         Handle<Object> value = JSObject::GetElement(boilerplate, i);
3689         if (value->IsJSObject()) {
3690           Handle<JSObject> value_object = Handle<JSObject>::cast(value);
3691           if (!IsFastLiteral(value_object,
3692                              max_depth - 1,
3693                              max_properties,
3694                              total_size)) {
3695             return false;
3696           }
3697         }
3698       }
3699       *total_size += FixedArray::SizeFor(length);
3700     } else {
3701       return false;
3702     }
3703   }
3704 
3705   Handle<FixedArray> properties(boilerplate->properties());
3706   if (properties->length() > 0) {
3707     return false;
3708   } else {
3709     int nof = boilerplate->map()->inobject_properties();
3710     for (int i = 0; i < nof; i++) {
3711       if ((*max_properties)-- == 0) return false;
3712       Handle<Object> value(boilerplate->InObjectPropertyAt(i));
3713       if (value->IsJSObject()) {
3714         Handle<JSObject> value_object = Handle<JSObject>::cast(value);
3715         if (!IsFastLiteral(value_object,
3716                            max_depth - 1,
3717                            max_properties,
3718                            total_size)) {
3719           return false;
3720         }
3721       }
3722     }
3723   }
3724 
3725   *total_size += boilerplate->map()->instance_size();
3726   return true;
3727 }
3728 
3729 
VisitObjectLiteral(ObjectLiteral * expr)3730 void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
3731   ASSERT(!HasStackOverflow());
3732   ASSERT(current_block() != NULL);
3733   ASSERT(current_block()->HasPredecessor());
3734   Handle<JSFunction> closure = function_state()->compilation_info()->closure();
3735   HValue* context = environment()->LookupContext();
3736   HInstruction* literal;
3737 
3738   // Check whether to use fast or slow deep-copying for boilerplate.
3739   int total_size = 0;
3740   int max_properties = HFastLiteral::kMaxLiteralProperties;
3741   Handle<Object> boilerplate(closure->literals()->get(expr->literal_index()));
3742   if (boilerplate->IsJSObject() &&
3743       IsFastLiteral(Handle<JSObject>::cast(boilerplate),
3744                     HFastLiteral::kMaxLiteralDepth,
3745                     &max_properties,
3746                     &total_size)) {
3747     Handle<JSObject> boilerplate_object = Handle<JSObject>::cast(boilerplate);
3748     literal = new(zone()) HFastLiteral(context,
3749                                        boilerplate_object,
3750                                        total_size,
3751                                        expr->literal_index(),
3752                                        expr->depth());
3753   } else {
3754     literal = new(zone()) HObjectLiteral(context,
3755                                          expr->constant_properties(),
3756                                          expr->fast_elements(),
3757                                          expr->literal_index(),
3758                                          expr->depth(),
3759                                          expr->has_function());
3760   }
3761 
3762   // The object is expected in the bailout environment during computation
3763   // of the property values and is the value of the entire expression.
3764   PushAndAdd(literal);
3765 
3766   expr->CalculateEmitStore();
3767 
3768   for (int i = 0; i < expr->properties()->length(); i++) {
3769     ObjectLiteral::Property* property = expr->properties()->at(i);
3770     if (property->IsCompileTimeValue()) continue;
3771 
3772     Literal* key = property->key();
3773     Expression* value = property->value();
3774 
3775     switch (property->kind()) {
3776       case ObjectLiteral::Property::MATERIALIZED_LITERAL:
3777         ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
3778         // Fall through.
3779       case ObjectLiteral::Property::COMPUTED:
3780         if (key->handle()->IsSymbol()) {
3781           if (property->emit_store()) {
3782             property->RecordTypeFeedback(oracle());
3783             CHECK_ALIVE(VisitForValue(value));
3784             HValue* value = Pop();
3785             HInstruction* store = BuildStoreNamed(literal, value, property);
3786             AddInstruction(store);
3787             if (store->HasObservableSideEffects()) AddSimulate(key->id());
3788           } else {
3789             CHECK_ALIVE(VisitForEffect(value));
3790           }
3791           break;
3792         }
3793         // Fall through.
3794       case ObjectLiteral::Property::PROTOTYPE:
3795       case ObjectLiteral::Property::SETTER:
3796       case ObjectLiteral::Property::GETTER:
3797         return Bailout("Object literal with complex property");
3798       default: UNREACHABLE();
3799     }
3800   }
3801 
3802   if (expr->has_function()) {
3803     // Return the result of the transformation to fast properties
3804     // instead of the original since this operation changes the map
3805     // of the object. This makes sure that the original object won't
3806     // be used by other optimized code before it is transformed
3807     // (e.g. because of code motion).
3808     HToFastProperties* result = new(zone()) HToFastProperties(Pop());
3809     AddInstruction(result);
3810     return ast_context()->ReturnValue(result);
3811   } else {
3812     return ast_context()->ReturnValue(Pop());
3813   }
3814 }
3815 
3816 
VisitArrayLiteral(ArrayLiteral * expr)3817 void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
3818   ASSERT(!HasStackOverflow());
3819   ASSERT(current_block() != NULL);
3820   ASSERT(current_block()->HasPredecessor());
3821   ZoneList<Expression*>* subexprs = expr->values();
3822   int length = subexprs->length();
3823   HValue* context = environment()->LookupContext();
3824   HInstruction* literal;
3825 
3826   Handle<FixedArray> literals(environment()->closure()->literals());
3827   Handle<Object> raw_boilerplate(literals->get(expr->literal_index()));
3828 
3829   if (raw_boilerplate->IsUndefined()) {
3830     raw_boilerplate = Runtime::CreateArrayLiteralBoilerplate(
3831         isolate(), literals, expr->constant_elements());
3832     if (raw_boilerplate.is_null()) {
3833       return Bailout("array boilerplate creation failed");
3834     }
3835     literals->set(expr->literal_index(), *raw_boilerplate);
3836     if (JSObject::cast(*raw_boilerplate)->elements()->map() ==
3837         isolate()->heap()->fixed_cow_array_map()) {
3838       isolate()->counters()->cow_arrays_created_runtime()->Increment();
3839     }
3840   }
3841 
3842   Handle<JSObject> boilerplate = Handle<JSObject>::cast(raw_boilerplate);
3843   ElementsKind boilerplate_elements_kind =
3844         Handle<JSObject>::cast(boilerplate)->GetElementsKind();
3845 
3846   // Check whether to use fast or slow deep-copying for boilerplate.
3847   int total_size = 0;
3848   int max_properties = HFastLiteral::kMaxLiteralProperties;
3849   if (IsFastLiteral(boilerplate,
3850                     HFastLiteral::kMaxLiteralDepth,
3851                     &max_properties,
3852                     &total_size)) {
3853     literal = new(zone()) HFastLiteral(context,
3854                                        boilerplate,
3855                                        total_size,
3856                                        expr->literal_index(),
3857                                        expr->depth());
3858   } else {
3859     literal = new(zone()) HArrayLiteral(context,
3860                                         boilerplate,
3861                                         length,
3862                                         expr->literal_index(),
3863                                         expr->depth());
3864   }
3865 
3866   // The array is expected in the bailout environment during computation
3867   // of the property values and is the value of the entire expression.
3868   PushAndAdd(literal);
3869 
3870   HLoadElements* elements = NULL;
3871 
3872   for (int i = 0; i < length; i++) {
3873     Expression* subexpr = subexprs->at(i);
3874     // If the subexpression is a literal or a simple materialized literal it
3875     // is already set in the cloned array.
3876     if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
3877 
3878     CHECK_ALIVE(VisitForValue(subexpr));
3879     HValue* value = Pop();
3880     if (!Smi::IsValid(i)) return Bailout("Non-smi key in array literal");
3881 
3882     elements = new(zone()) HLoadElements(literal);
3883     AddInstruction(elements);
3884 
3885     HValue* key = AddInstruction(
3886         new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)),
3887                               Representation::Integer32()));
3888 
3889     switch (boilerplate_elements_kind) {
3890       case FAST_SMI_ONLY_ELEMENTS:
3891         // Smi-only arrays need a smi check.
3892         AddInstruction(new(zone()) HCheckSmi(value));
3893         // Fall through.
3894       case FAST_ELEMENTS:
3895         AddInstruction(new(zone()) HStoreKeyedFastElement(
3896             elements,
3897             key,
3898             value,
3899             boilerplate_elements_kind));
3900         break;
3901       case FAST_DOUBLE_ELEMENTS:
3902         AddInstruction(new(zone()) HStoreKeyedFastDoubleElement(elements,
3903                                                                 key,
3904                                                                 value));
3905         break;
3906       default:
3907         UNREACHABLE();
3908         break;
3909     }
3910 
3911     AddSimulate(expr->GetIdForElement(i));
3912   }
3913   return ast_context()->ReturnValue(Pop());
3914 }
3915 
3916 
3917 // Sets the lookup result and returns true if the store can be inlined.
ComputeStoredField(Handle<Map> type,Handle<String> name,LookupResult * lookup)3918 static bool ComputeStoredField(Handle<Map> type,
3919                                Handle<String> name,
3920                                LookupResult* lookup) {
3921   type->LookupInDescriptors(NULL, *name, lookup);
3922   if (!lookup->IsFound()) return false;
3923   if (lookup->type() == FIELD) return true;
3924   return (lookup->type() == MAP_TRANSITION) &&
3925       (type->unused_property_fields() > 0);
3926 }
3927 
3928 
ComputeStoredFieldIndex(Handle<Map> type,Handle<String> name,LookupResult * lookup)3929 static int ComputeStoredFieldIndex(Handle<Map> type,
3930                                    Handle<String> name,
3931                                    LookupResult* lookup) {
3932   ASSERT(lookup->type() == FIELD || lookup->type() == MAP_TRANSITION);
3933   if (lookup->type() == FIELD) {
3934     return lookup->GetLocalFieldIndexFromMap(*type);
3935   } else {
3936     Map* transition = lookup->GetTransitionMapFromMap(*type);
3937     return transition->PropertyIndexFor(*name) - type->inobject_properties();
3938   }
3939 }
3940 
3941 
BuildStoreNamedField(HValue * object,Handle<String> name,HValue * value,Handle<Map> type,LookupResult * lookup,bool smi_and_map_check)3942 HInstruction* HGraphBuilder::BuildStoreNamedField(HValue* object,
3943                                                   Handle<String> name,
3944                                                   HValue* value,
3945                                                   Handle<Map> type,
3946                                                   LookupResult* lookup,
3947                                                   bool smi_and_map_check) {
3948   if (smi_and_map_check) {
3949     AddInstruction(new(zone()) HCheckNonSmi(object));
3950     AddInstruction(new(zone()) HCheckMap(object, type, NULL,
3951                                          ALLOW_ELEMENT_TRANSITION_MAPS));
3952   }
3953 
3954   int index = ComputeStoredFieldIndex(type, name, lookup);
3955   bool is_in_object = index < 0;
3956   int offset = index * kPointerSize;
3957   if (index < 0) {
3958     // Negative property indices are in-object properties, indexed
3959     // from the end of the fixed part of the object.
3960     offset += type->instance_size();
3961   } else {
3962     offset += FixedArray::kHeaderSize;
3963   }
3964   HStoreNamedField* instr =
3965       new(zone()) HStoreNamedField(object, name, value, is_in_object, offset);
3966   if (lookup->type() == MAP_TRANSITION) {
3967     Handle<Map> transition(lookup->GetTransitionMapFromMap(*type));
3968     instr->set_transition(transition);
3969     // TODO(fschneider): Record the new map type of the object in the IR to
3970     // enable elimination of redundant checks after the transition store.
3971     instr->SetGVNFlag(kChangesMaps);
3972   }
3973   return instr;
3974 }
3975 
3976 
BuildStoreNamedGeneric(HValue * object,Handle<String> name,HValue * value)3977 HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object,
3978                                                     Handle<String> name,
3979                                                     HValue* value) {
3980   HValue* context = environment()->LookupContext();
3981   return new(zone()) HStoreNamedGeneric(
3982                          context,
3983                          object,
3984                          name,
3985                          value,
3986                          function_strict_mode_flag());
3987 }
3988 
3989 
BuildStoreNamed(HValue * object,HValue * value,ObjectLiteral::Property * prop)3990 HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object,
3991                                              HValue* value,
3992                                              ObjectLiteral::Property* prop) {
3993   Literal* key = prop->key()->AsLiteral();
3994   Handle<String> name = Handle<String>::cast(key->handle());
3995   ASSERT(!name.is_null());
3996 
3997   LookupResult lookup(isolate());
3998   Handle<Map> type = prop->GetReceiverType();
3999   bool is_monomorphic = prop->IsMonomorphic() &&
4000       ComputeStoredField(type, name, &lookup);
4001 
4002   return is_monomorphic
4003       ? BuildStoreNamedField(object, name, value, type, &lookup,
4004                              true)  // Needs smi and map check.
4005       : BuildStoreNamedGeneric(object, name, value);
4006 }
4007 
4008 
BuildStoreNamed(HValue * object,HValue * value,Expression * expr)4009 HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object,
4010                                              HValue* value,
4011                                              Expression* expr) {
4012   Property* prop = (expr->AsProperty() != NULL)
4013       ? expr->AsProperty()
4014       : expr->AsAssignment()->target()->AsProperty();
4015   Literal* key = prop->key()->AsLiteral();
4016   Handle<String> name = Handle<String>::cast(key->handle());
4017   ASSERT(!name.is_null());
4018 
4019   LookupResult lookup(isolate());
4020   SmallMapList* types = expr->GetReceiverTypes();
4021   bool is_monomorphic = expr->IsMonomorphic() &&
4022       ComputeStoredField(types->first(), name, &lookup);
4023 
4024   return is_monomorphic
4025       ? BuildStoreNamedField(object, name, value, types->first(), &lookup,
4026                              true)  // Needs smi and map check.
4027       : BuildStoreNamedGeneric(object, name, value);
4028 }
4029 
4030 
HandlePolymorphicStoreNamedField(Assignment * expr,HValue * object,HValue * value,SmallMapList * types,Handle<String> name)4031 void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr,
4032                                                      HValue* object,
4033                                                      HValue* value,
4034                                                      SmallMapList* types,
4035                                                      Handle<String> name) {
4036   // TODO(ager): We should recognize when the prototype chains for different
4037   // maps are identical. In that case we can avoid repeatedly generating the
4038   // same prototype map checks.
4039   int count = 0;
4040   HBasicBlock* join = NULL;
4041   for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) {
4042     Handle<Map> map = types->at(i);
4043     LookupResult lookup(isolate());
4044     if (ComputeStoredField(map, name, &lookup)) {
4045       if (count == 0) {
4046         AddInstruction(new(zone()) HCheckNonSmi(object));  // Only needed once.
4047         join = graph()->CreateBasicBlock();
4048       }
4049       ++count;
4050       HBasicBlock* if_true = graph()->CreateBasicBlock();
4051       HBasicBlock* if_false = graph()->CreateBasicBlock();
4052       HCompareMap* compare =
4053           new(zone()) HCompareMap(object, map, if_true, if_false);
4054       current_block()->Finish(compare);
4055 
4056       set_current_block(if_true);
4057       HInstruction* instr =
4058           BuildStoreNamedField(object, name, value, map, &lookup, false);
4059       instr->set_position(expr->position());
4060       // Goto will add the HSimulate for the store.
4061       AddInstruction(instr);
4062       if (!ast_context()->IsEffect()) Push(value);
4063       current_block()->Goto(join);
4064 
4065       set_current_block(if_false);
4066     }
4067   }
4068 
4069   // Finish up.  Unconditionally deoptimize if we've handled all the maps we
4070   // know about and do not want to handle ones we've never seen.  Otherwise
4071   // use a generic IC.
4072   if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
4073     current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses);
4074   } else {
4075     HInstruction* instr = BuildStoreNamedGeneric(object, name, value);
4076     instr->set_position(expr->position());
4077     AddInstruction(instr);
4078 
4079     if (join != NULL) {
4080       if (!ast_context()->IsEffect()) Push(value);
4081       current_block()->Goto(join);
4082     } else {
4083       // The HSimulate for the store should not see the stored value in
4084       // effect contexts (it is not materialized at expr->id() in the
4085       // unoptimized code).
4086       if (instr->HasObservableSideEffects()) {
4087         if (ast_context()->IsEffect()) {
4088           AddSimulate(expr->id());
4089         } else {
4090           Push(value);
4091           AddSimulate(expr->id());
4092           Drop(1);
4093         }
4094       }
4095       return ast_context()->ReturnValue(value);
4096     }
4097   }
4098 
4099   ASSERT(join != NULL);
4100   join->SetJoinId(expr->id());
4101   set_current_block(join);
4102   if (!ast_context()->IsEffect()) return ast_context()->ReturnValue(Pop());
4103 }
4104 
4105 
HandlePropertyAssignment(Assignment * expr)4106 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
4107   Property* prop = expr->target()->AsProperty();
4108   ASSERT(prop != NULL);
4109   expr->RecordTypeFeedback(oracle());
4110   CHECK_ALIVE(VisitForValue(prop->obj()));
4111 
4112   HValue* value = NULL;
4113   HInstruction* instr = NULL;
4114 
4115   if (prop->key()->IsPropertyName()) {
4116     // Named store.
4117     CHECK_ALIVE(VisitForValue(expr->value()));
4118     value = Pop();
4119     HValue* object = Pop();
4120 
4121     Literal* key = prop->key()->AsLiteral();
4122     Handle<String> name = Handle<String>::cast(key->handle());
4123     ASSERT(!name.is_null());
4124 
4125     SmallMapList* types = expr->GetReceiverTypes();
4126     LookupResult lookup(isolate());
4127 
4128     if (expr->IsMonomorphic()) {
4129       instr = BuildStoreNamed(object, value, expr);
4130 
4131     } else if (types != NULL && types->length() > 1) {
4132       HandlePolymorphicStoreNamedField(expr, object, value, types, name);
4133       return;
4134 
4135     } else {
4136       instr = BuildStoreNamedGeneric(object, name, value);
4137     }
4138 
4139   } else {
4140     // Keyed store.
4141     CHECK_ALIVE(VisitForValue(prop->key()));
4142     CHECK_ALIVE(VisitForValue(expr->value()));
4143     value = Pop();
4144     HValue* key = Pop();
4145     HValue* object = Pop();
4146     bool has_side_effects = false;
4147     HandleKeyedElementAccess(object, key, value, expr, expr->AssignmentId(),
4148                              expr->position(),
4149                              true,  // is_store
4150                              &has_side_effects);
4151     Push(value);
4152     ASSERT(has_side_effects);  // Stores always have side effects.
4153     AddSimulate(expr->AssignmentId());
4154     return ast_context()->ReturnValue(Pop());
4155   }
4156   Push(value);
4157   instr->set_position(expr->position());
4158   AddInstruction(instr);
4159   if (instr->HasObservableSideEffects()) AddSimulate(expr->AssignmentId());
4160   return ast_context()->ReturnValue(Pop());
4161 }
4162 
4163 
4164 // Because not every expression has a position and there is not common
4165 // superclass of Assignment and CountOperation, we cannot just pass the
4166 // owning expression instead of position and ast_id separately.
HandleGlobalVariableAssignment(Variable * var,HValue * value,int position,int ast_id)4167 void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var,
4168                                                    HValue* value,
4169                                                    int position,
4170                                                    int ast_id) {
4171   LookupResult lookup(isolate());
4172   GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true);
4173   if (type == kUseCell) {
4174     Handle<GlobalObject> global(info()->global_object());
4175     Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
4176     HInstruction* instr =
4177         new(zone()) HStoreGlobalCell(value, cell, lookup.GetPropertyDetails());
4178     instr->set_position(position);
4179     AddInstruction(instr);
4180     if (instr->HasObservableSideEffects()) AddSimulate(ast_id);
4181   } else {
4182     HValue* context =  environment()->LookupContext();
4183     HGlobalObject* global_object = new(zone()) HGlobalObject(context);
4184     AddInstruction(global_object);
4185     HStoreGlobalGeneric* instr =
4186         new(zone()) HStoreGlobalGeneric(context,
4187                                         global_object,
4188                                         var->name(),
4189                                         value,
4190                                         function_strict_mode_flag());
4191     instr->set_position(position);
4192     AddInstruction(instr);
4193     ASSERT(instr->HasObservableSideEffects());
4194     if (instr->HasObservableSideEffects()) AddSimulate(ast_id);
4195   }
4196 }
4197 
4198 
HandleCompoundAssignment(Assignment * expr)4199 void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
4200   Expression* target = expr->target();
4201   VariableProxy* proxy = target->AsVariableProxy();
4202   Property* prop = target->AsProperty();
4203   ASSERT(proxy == NULL || prop == NULL);
4204 
4205   // We have a second position recorded in the FullCodeGenerator to have
4206   // type feedback for the binary operation.
4207   BinaryOperation* operation = expr->binary_operation();
4208 
4209   if (proxy != NULL) {
4210     Variable* var = proxy->var();
4211     if (var->mode() == LET)  {
4212       return Bailout("unsupported let compound assignment");
4213     }
4214 
4215     CHECK_ALIVE(VisitForValue(operation));
4216 
4217     switch (var->location()) {
4218       case Variable::UNALLOCATED:
4219         HandleGlobalVariableAssignment(var,
4220                                        Top(),
4221                                        expr->position(),
4222                                        expr->AssignmentId());
4223         break;
4224 
4225       case Variable::PARAMETER:
4226       case Variable::LOCAL:
4227         if (var->mode() == CONST)  {
4228           return Bailout("unsupported const compound assignment");
4229         }
4230         Bind(var, Top());
4231         break;
4232 
4233       case Variable::CONTEXT: {
4234         // Bail out if we try to mutate a parameter value in a function
4235         // using the arguments object.  We do not (yet) correctly handle the
4236         // arguments property of the function.
4237         if (info()->scope()->arguments() != NULL) {
4238           // Parameters will be allocated to context slots.  We have no
4239           // direct way to detect that the variable is a parameter so we do
4240           // a linear search of the parameter variables.
4241           int count = info()->scope()->num_parameters();
4242           for (int i = 0; i < count; ++i) {
4243             if (var == info()->scope()->parameter(i)) {
4244               Bailout(
4245                   "assignment to parameter, function uses arguments object");
4246             }
4247           }
4248         }
4249 
4250         HStoreContextSlot::Mode mode;
4251 
4252         switch (var->mode()) {
4253           case LET:
4254             mode = HStoreContextSlot::kCheckDeoptimize;
4255             break;
4256           case CONST:
4257             return ast_context()->ReturnValue(Pop());
4258           case CONST_HARMONY:
4259             // This case is checked statically so no need to
4260             // perform checks here
4261             UNREACHABLE();
4262           default:
4263             mode = HStoreContextSlot::kNoCheck;
4264         }
4265 
4266         HValue* context = BuildContextChainWalk(var);
4267         HStoreContextSlot* instr =
4268             new(zone()) HStoreContextSlot(context, var->index(), mode, Top());
4269         AddInstruction(instr);
4270         if (instr->HasObservableSideEffects()) {
4271           AddSimulate(expr->AssignmentId());
4272         }
4273         break;
4274       }
4275 
4276       case Variable::LOOKUP:
4277         return Bailout("compound assignment to lookup slot");
4278     }
4279     return ast_context()->ReturnValue(Pop());
4280 
4281   } else if (prop != NULL) {
4282     prop->RecordTypeFeedback(oracle());
4283 
4284     if (prop->key()->IsPropertyName()) {
4285       // Named property.
4286       CHECK_ALIVE(VisitForValue(prop->obj()));
4287       HValue* obj = Top();
4288 
4289       HInstruction* load = NULL;
4290       if (prop->IsMonomorphic()) {
4291         Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
4292         Handle<Map> map = prop->GetReceiverTypes()->first();
4293         load = BuildLoadNamed(obj, prop, map, name);
4294       } else {
4295         load = BuildLoadNamedGeneric(obj, prop);
4296       }
4297       PushAndAdd(load);
4298       if (load->HasObservableSideEffects()) AddSimulate(expr->CompoundLoadId());
4299 
4300       CHECK_ALIVE(VisitForValue(expr->value()));
4301       HValue* right = Pop();
4302       HValue* left = Pop();
4303 
4304       HInstruction* instr = BuildBinaryOperation(operation, left, right);
4305       PushAndAdd(instr);
4306       if (instr->HasObservableSideEffects()) AddSimulate(operation->id());
4307 
4308       HInstruction* store = BuildStoreNamed(obj, instr, prop);
4309       AddInstruction(store);
4310       // Drop the simulated receiver and value.  Return the value.
4311       Drop(2);
4312       Push(instr);
4313       if (store->HasObservableSideEffects()) AddSimulate(expr->AssignmentId());
4314       return ast_context()->ReturnValue(Pop());
4315 
4316     } else {
4317       // Keyed property.
4318       CHECK_ALIVE(VisitForValue(prop->obj()));
4319       CHECK_ALIVE(VisitForValue(prop->key()));
4320       HValue* obj = environment()->ExpressionStackAt(1);
4321       HValue* key = environment()->ExpressionStackAt(0);
4322 
4323       bool has_side_effects = false;
4324       HValue* load = HandleKeyedElementAccess(
4325           obj, key, NULL, prop, expr->CompoundLoadId(), RelocInfo::kNoPosition,
4326           false,  // is_store
4327           &has_side_effects);
4328       Push(load);
4329       if (has_side_effects) AddSimulate(expr->CompoundLoadId());
4330 
4331 
4332       CHECK_ALIVE(VisitForValue(expr->value()));
4333       HValue* right = Pop();
4334       HValue* left = Pop();
4335 
4336       HInstruction* instr = BuildBinaryOperation(operation, left, right);
4337       PushAndAdd(instr);
4338       if (instr->HasObservableSideEffects()) AddSimulate(operation->id());
4339 
4340       expr->RecordTypeFeedback(oracle());
4341       HandleKeyedElementAccess(obj, key, instr, expr, expr->AssignmentId(),
4342                                RelocInfo::kNoPosition,
4343                                true,  // is_store
4344                                &has_side_effects);
4345 
4346       // Drop the simulated receiver, key, and value.  Return the value.
4347       Drop(3);
4348       Push(instr);
4349       ASSERT(has_side_effects);  // Stores always have side effects.
4350       AddSimulate(expr->AssignmentId());
4351       return ast_context()->ReturnValue(Pop());
4352     }
4353 
4354   } else {
4355     return Bailout("invalid lhs in compound assignment");
4356   }
4357 }
4358 
4359 
VisitAssignment(Assignment * expr)4360 void HGraphBuilder::VisitAssignment(Assignment* expr) {
4361   ASSERT(!HasStackOverflow());
4362   ASSERT(current_block() != NULL);
4363   ASSERT(current_block()->HasPredecessor());
4364   VariableProxy* proxy = expr->target()->AsVariableProxy();
4365   Property* prop = expr->target()->AsProperty();
4366   ASSERT(proxy == NULL || prop == NULL);
4367 
4368   if (expr->is_compound()) {
4369     HandleCompoundAssignment(expr);
4370     return;
4371   }
4372 
4373   if (prop != NULL) {
4374     HandlePropertyAssignment(expr);
4375   } else if (proxy != NULL) {
4376     Variable* var = proxy->var();
4377 
4378     if (var->mode() == CONST) {
4379       if (expr->op() != Token::INIT_CONST) {
4380         CHECK_ALIVE(VisitForValue(expr->value()));
4381         return ast_context()->ReturnValue(Pop());
4382       }
4383 
4384       if (var->IsStackAllocated()) {
4385         // We insert a use of the old value to detect unsupported uses of const
4386         // variables (e.g. initialization inside a loop).
4387         HValue* old_value = environment()->Lookup(var);
4388         AddInstruction(new HUseConst(old_value));
4389       }
4390     } else if (var->mode() == CONST_HARMONY) {
4391       if (expr->op() != Token::INIT_CONST_HARMONY) {
4392         return Bailout("non-initializer assignment to const");
4393       }
4394     }
4395 
4396     if (proxy->IsArguments()) return Bailout("assignment to arguments");
4397 
4398     // Handle the assignment.
4399     switch (var->location()) {
4400       case Variable::UNALLOCATED:
4401         CHECK_ALIVE(VisitForValue(expr->value()));
4402         HandleGlobalVariableAssignment(var,
4403                                        Top(),
4404                                        expr->position(),
4405                                        expr->AssignmentId());
4406         return ast_context()->ReturnValue(Pop());
4407 
4408       case Variable::PARAMETER:
4409       case Variable::LOCAL: {
4410         // Perform an initialization check for let declared variables
4411         // or parameters.
4412         if (var->mode() == LET && expr->op() == Token::ASSIGN) {
4413           HValue* env_value = environment()->Lookup(var);
4414           if (env_value == graph()->GetConstantHole()) {
4415             return Bailout("assignment to let variable before initialization");
4416           }
4417         }
4418         // We do not allow the arguments object to occur in a context where it
4419         // may escape, but assignments to stack-allocated locals are
4420         // permitted.
4421         CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED));
4422         HValue* value = Pop();
4423         Bind(var, value);
4424         return ast_context()->ReturnValue(value);
4425       }
4426 
4427       case Variable::CONTEXT: {
4428         // Bail out if we try to mutate a parameter value in a function using
4429         // the arguments object.  We do not (yet) correctly handle the
4430         // arguments property of the function.
4431         if (info()->scope()->arguments() != NULL) {
4432           // Parameters will rewrite to context slots.  We have no direct way
4433           // to detect that the variable is a parameter.
4434           int count = info()->scope()->num_parameters();
4435           for (int i = 0; i < count; ++i) {
4436             if (var == info()->scope()->parameter(i)) {
4437               return Bailout("assignment to parameter in arguments object");
4438             }
4439           }
4440         }
4441 
4442         CHECK_ALIVE(VisitForValue(expr->value()));
4443         HStoreContextSlot::Mode mode;
4444         if (expr->op() == Token::ASSIGN) {
4445           switch (var->mode()) {
4446             case LET:
4447               mode = HStoreContextSlot::kCheckDeoptimize;
4448               break;
4449             case CONST:
4450               return ast_context()->ReturnValue(Pop());
4451             case CONST_HARMONY:
4452               // This case is checked statically so no need to
4453               // perform checks here
4454               UNREACHABLE();
4455             default:
4456               mode = HStoreContextSlot::kNoCheck;
4457           }
4458         } else if (expr->op() == Token::INIT_VAR ||
4459                    expr->op() == Token::INIT_LET ||
4460                    expr->op() == Token::INIT_CONST_HARMONY) {
4461           mode = HStoreContextSlot::kNoCheck;
4462         } else {
4463           ASSERT(expr->op() == Token::INIT_CONST);
4464 
4465           mode = HStoreContextSlot::kCheckIgnoreAssignment;
4466         }
4467 
4468         HValue* context = BuildContextChainWalk(var);
4469         HStoreContextSlot* instr = new(zone()) HStoreContextSlot(
4470             context, var->index(), mode, Top());
4471         AddInstruction(instr);
4472         if (instr->HasObservableSideEffects()) {
4473           AddSimulate(expr->AssignmentId());
4474         }
4475         return ast_context()->ReturnValue(Pop());
4476       }
4477 
4478       case Variable::LOOKUP:
4479         return Bailout("assignment to LOOKUP variable");
4480     }
4481   } else {
4482     return Bailout("invalid left-hand side in assignment");
4483   }
4484 }
4485 
4486 
VisitThrow(Throw * expr)4487 void HGraphBuilder::VisitThrow(Throw* expr) {
4488   ASSERT(!HasStackOverflow());
4489   ASSERT(current_block() != NULL);
4490   ASSERT(current_block()->HasPredecessor());
4491   // We don't optimize functions with invalid left-hand sides in
4492   // assignments, count operations, or for-in.  Consequently throw can
4493   // currently only occur in an effect context.
4494   ASSERT(ast_context()->IsEffect());
4495   CHECK_ALIVE(VisitForValue(expr->exception()));
4496 
4497   HValue* context = environment()->LookupContext();
4498   HValue* value = environment()->Pop();
4499   HThrow* instr = new(zone()) HThrow(context, value);
4500   instr->set_position(expr->position());
4501   AddInstruction(instr);
4502   AddSimulate(expr->id());
4503   current_block()->FinishExit(new(zone()) HAbnormalExit);
4504   set_current_block(NULL);
4505 }
4506 
4507 
BuildLoadNamedField(HValue * object,Property * expr,Handle<Map> type,LookupResult * lookup,bool smi_and_map_check)4508 HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object,
4509                                                     Property* expr,
4510                                                     Handle<Map> type,
4511                                                     LookupResult* lookup,
4512                                                     bool smi_and_map_check) {
4513   if (smi_and_map_check) {
4514     AddInstruction(new(zone()) HCheckNonSmi(object));
4515     AddInstruction(new(zone()) HCheckMap(object, type, NULL,
4516                                          ALLOW_ELEMENT_TRANSITION_MAPS));
4517   }
4518 
4519   int index = lookup->GetLocalFieldIndexFromMap(*type);
4520   if (index < 0) {
4521     // Negative property indices are in-object properties, indexed
4522     // from the end of the fixed part of the object.
4523     int offset = (index * kPointerSize) + type->instance_size();
4524     return new(zone()) HLoadNamedField(object, true, offset);
4525   } else {
4526     // Non-negative property indices are in the properties array.
4527     int offset = (index * kPointerSize) + FixedArray::kHeaderSize;
4528     return new(zone()) HLoadNamedField(object, false, offset);
4529   }
4530 }
4531 
4532 
BuildLoadNamedGeneric(HValue * obj,Property * expr)4533 HInstruction* HGraphBuilder::BuildLoadNamedGeneric(HValue* obj,
4534                                                    Property* expr) {
4535   if (expr->IsUninitialized() && !FLAG_always_opt) {
4536     AddInstruction(new(zone()) HSoftDeoptimize);
4537     current_block()->MarkAsDeoptimizing();
4538   }
4539   ASSERT(expr->key()->IsPropertyName());
4540   Handle<Object> name = expr->key()->AsLiteral()->handle();
4541   HValue* context = environment()->LookupContext();
4542   return new(zone()) HLoadNamedGeneric(context, obj, name);
4543 }
4544 
4545 
BuildLoadNamed(HValue * obj,Property * expr,Handle<Map> map,Handle<String> name)4546 HInstruction* HGraphBuilder::BuildLoadNamed(HValue* obj,
4547                                             Property* expr,
4548                                             Handle<Map> map,
4549                                             Handle<String> name) {
4550   LookupResult lookup(isolate());
4551   map->LookupInDescriptors(NULL, *name, &lookup);
4552   if (lookup.IsFound() && lookup.type() == FIELD) {
4553     return BuildLoadNamedField(obj,
4554                                expr,
4555                                map,
4556                                &lookup,
4557                                true);
4558   } else if (lookup.IsFound() && lookup.type() == CONSTANT_FUNCTION) {
4559     AddInstruction(new(zone()) HCheckNonSmi(obj));
4560     AddInstruction(new(zone()) HCheckMap(obj, map, NULL,
4561                                          ALLOW_ELEMENT_TRANSITION_MAPS));
4562     Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*map));
4563     return new(zone()) HConstant(function, Representation::Tagged());
4564   } else {
4565     return BuildLoadNamedGeneric(obj, expr);
4566   }
4567 }
4568 
4569 
BuildLoadKeyedGeneric(HValue * object,HValue * key)4570 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object,
4571                                                    HValue* key) {
4572   HValue* context = environment()->LookupContext();
4573   return new(zone()) HLoadKeyedGeneric(context, object, key);
4574 }
4575 
4576 
BuildExternalArrayElementAccess(HValue * external_elements,HValue * checked_key,HValue * val,ElementsKind elements_kind,bool is_store)4577 HInstruction* HGraphBuilder::BuildExternalArrayElementAccess(
4578     HValue* external_elements,
4579     HValue* checked_key,
4580     HValue* val,
4581     ElementsKind elements_kind,
4582     bool is_store) {
4583   if (is_store) {
4584     ASSERT(val != NULL);
4585     switch (elements_kind) {
4586       case EXTERNAL_PIXEL_ELEMENTS: {
4587         val = AddInstruction(new(zone()) HClampToUint8(val));
4588         break;
4589       }
4590       case EXTERNAL_BYTE_ELEMENTS:
4591       case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4592       case EXTERNAL_SHORT_ELEMENTS:
4593       case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4594       case EXTERNAL_INT_ELEMENTS:
4595       case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
4596         if (!val->representation().IsInteger32()) {
4597           val = AddInstruction(new(zone()) HChange(
4598               val,
4599               Representation::Integer32(),
4600               true,  // Truncate to int32.
4601               false));  // Don't deoptimize undefined (irrelevant here).
4602         }
4603         break;
4604       }
4605       case EXTERNAL_FLOAT_ELEMENTS:
4606       case EXTERNAL_DOUBLE_ELEMENTS:
4607         break;
4608       case FAST_SMI_ONLY_ELEMENTS:
4609       case FAST_ELEMENTS:
4610       case FAST_DOUBLE_ELEMENTS:
4611       case DICTIONARY_ELEMENTS:
4612       case NON_STRICT_ARGUMENTS_ELEMENTS:
4613         UNREACHABLE();
4614         break;
4615     }
4616     return new(zone()) HStoreKeyedSpecializedArrayElement(
4617         external_elements, checked_key, val, elements_kind);
4618   } else {
4619     ASSERT(val == NULL);
4620     return new(zone()) HLoadKeyedSpecializedArrayElement(
4621         external_elements, checked_key, elements_kind);
4622   }
4623 }
4624 
4625 
BuildFastElementAccess(HValue * elements,HValue * checked_key,HValue * val,ElementsKind elements_kind,bool is_store)4626 HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements,
4627                                                     HValue* checked_key,
4628                                                     HValue* val,
4629                                                     ElementsKind elements_kind,
4630                                                     bool is_store) {
4631   if (is_store) {
4632     ASSERT(val != NULL);
4633     switch (elements_kind) {
4634       case FAST_DOUBLE_ELEMENTS:
4635         return new(zone()) HStoreKeyedFastDoubleElement(
4636             elements, checked_key, val);
4637       case FAST_SMI_ONLY_ELEMENTS:
4638         // Smi-only arrays need a smi check.
4639         AddInstruction(new(zone()) HCheckSmi(val));
4640         // Fall through.
4641       case FAST_ELEMENTS:
4642         return new(zone()) HStoreKeyedFastElement(
4643             elements, checked_key, val, elements_kind);
4644       default:
4645         UNREACHABLE();
4646         return NULL;
4647     }
4648   }
4649   // It's an element load (!is_store).
4650   if (elements_kind == FAST_DOUBLE_ELEMENTS) {
4651     return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key);
4652   } else {  // FAST_ELEMENTS or FAST_SMI_ONLY_ELEMENTS.
4653     return new(zone()) HLoadKeyedFastElement(elements, checked_key);
4654   }
4655 }
4656 
4657 
BuildMonomorphicElementAccess(HValue * object,HValue * key,HValue * val,Handle<Map> map,bool is_store)4658 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object,
4659                                                            HValue* key,
4660                                                            HValue* val,
4661                                                            Handle<Map> map,
4662                                                            bool is_store) {
4663   HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMap(object, map));
4664   bool fast_smi_only_elements = map->has_fast_smi_only_elements();
4665   bool fast_elements = map->has_fast_elements();
4666   HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object));
4667   if (is_store && (fast_elements || fast_smi_only_elements)) {
4668     AddInstruction(new(zone()) HCheckMap(
4669         elements, isolate()->factory()->fixed_array_map()));
4670   }
4671   HInstruction* length = NULL;
4672   HInstruction* checked_key = NULL;
4673   if (map->has_external_array_elements()) {
4674     length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
4675     checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
4676     HLoadExternalArrayPointer* external_elements =
4677         new(zone()) HLoadExternalArrayPointer(elements);
4678     AddInstruction(external_elements);
4679     return BuildExternalArrayElementAccess(external_elements, checked_key,
4680                                            val, map->elements_kind(), is_store);
4681   }
4682   ASSERT(fast_smi_only_elements ||
4683          fast_elements ||
4684          map->has_fast_double_elements());
4685   if (map->instance_type() == JS_ARRAY_TYPE) {
4686     length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck));
4687   } else {
4688     length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
4689   }
4690   checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
4691   return BuildFastElementAccess(elements, checked_key, val,
4692                                 map->elements_kind(), is_store);
4693 }
4694 
4695 
HandlePolymorphicElementAccess(HValue * object,HValue * key,HValue * val,Expression * prop,int ast_id,int position,bool is_store,bool * has_side_effects)4696 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
4697                                                       HValue* key,
4698                                                       HValue* val,
4699                                                       Expression* prop,
4700                                                       int ast_id,
4701                                                       int position,
4702                                                       bool is_store,
4703                                                       bool* has_side_effects) {
4704   *has_side_effects = false;
4705   AddInstruction(new(zone()) HCheckNonSmi(object));
4706   SmallMapList* maps = prop->GetReceiverTypes();
4707   bool todo_external_array = false;
4708 
4709   static const int kNumElementTypes = kElementsKindCount;
4710   bool type_todo[kNumElementTypes];
4711   for (int i = 0; i < kNumElementTypes; ++i) {
4712     type_todo[i] = false;
4713   }
4714 
4715   // Elements_kind transition support.
4716   MapHandleList transition_target(maps->length());
4717   // Collect possible transition targets.
4718   MapHandleList possible_transitioned_maps(maps->length());
4719   for (int i = 0; i < maps->length(); ++i) {
4720     Handle<Map> map = maps->at(i);
4721     ElementsKind elements_kind = map->elements_kind();
4722     if (elements_kind == FAST_DOUBLE_ELEMENTS ||
4723         elements_kind == FAST_ELEMENTS) {
4724       possible_transitioned_maps.Add(map);
4725     }
4726   }
4727   // Get transition target for each map (NULL == no transition).
4728   for (int i = 0; i < maps->length(); ++i) {
4729     Handle<Map> map = maps->at(i);
4730     Handle<Map> transitioned_map =
4731         map->FindTransitionedMap(&possible_transitioned_maps);
4732     transition_target.Add(transitioned_map);
4733   }
4734 
4735   int num_untransitionable_maps = 0;
4736   Handle<Map> untransitionable_map;
4737   for (int i = 0; i < maps->length(); ++i) {
4738     Handle<Map> map = maps->at(i);
4739     ASSERT(map->IsMap());
4740     if (!transition_target.at(i).is_null()) {
4741       AddInstruction(new(zone()) HTransitionElementsKind(
4742           object, map, transition_target.at(i)));
4743     } else {
4744       type_todo[map->elements_kind()] = true;
4745       if (map->elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) {
4746         todo_external_array = true;
4747       }
4748       num_untransitionable_maps++;
4749       untransitionable_map = map;
4750     }
4751   }
4752 
4753   // If only one map is left after transitioning, handle this case
4754   // monomorphically.
4755   if (num_untransitionable_maps == 1) {
4756     HInstruction* instr = NULL;
4757     if (untransitionable_map->has_slow_elements_kind()) {
4758       instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val)
4759                                       : BuildLoadKeyedGeneric(object, key));
4760     } else {
4761       instr = AddInstruction(BuildMonomorphicElementAccess(
4762           object, key, val, untransitionable_map, is_store));
4763     }
4764     *has_side_effects |= instr->HasObservableSideEffects();
4765     instr->set_position(position);
4766     return is_store ? NULL : instr;
4767   }
4768 
4769   AddInstruction(HCheckInstanceType::NewIsSpecObject(object));
4770   HBasicBlock* join = graph()->CreateBasicBlock();
4771 
4772   HInstruction* elements_kind_instr =
4773       AddInstruction(new(zone()) HElementsKind(object));
4774   HCompareConstantEqAndBranch* elements_kind_branch = NULL;
4775   HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object));
4776   HLoadExternalArrayPointer* external_elements = NULL;
4777   HInstruction* checked_key = NULL;
4778 
4779   // Generated code assumes that FAST_SMI_ONLY_ELEMENTS, FAST_ELEMENTS,
4780   // FAST_DOUBLE_ELEMENTS and DICTIONARY_ELEMENTS are handled before external
4781   // arrays.
4782   STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
4783   STATIC_ASSERT(FAST_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
4784   STATIC_ASSERT(FAST_DOUBLE_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
4785   STATIC_ASSERT(DICTIONARY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
4786 
4787   for (ElementsKind elements_kind = FIRST_ELEMENTS_KIND;
4788        elements_kind <= LAST_ELEMENTS_KIND;
4789        elements_kind = ElementsKind(elements_kind + 1)) {
4790     // After having handled FAST_ELEMENTS, FAST_SMI_ONLY_ELEMENTS,
4791     // FAST_DOUBLE_ELEMENTS and DICTIONARY_ELEMENTS, we need to add some code
4792     // that's executed for all external array cases.
4793     STATIC_ASSERT(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND ==
4794                   LAST_ELEMENTS_KIND);
4795     if (elements_kind == FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND
4796         && todo_external_array) {
4797       HInstruction* length =
4798           AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
4799       checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
4800       external_elements = new(zone()) HLoadExternalArrayPointer(elements);
4801       AddInstruction(external_elements);
4802     }
4803     if (type_todo[elements_kind]) {
4804       HBasicBlock* if_true = graph()->CreateBasicBlock();
4805       HBasicBlock* if_false = graph()->CreateBasicBlock();
4806       elements_kind_branch = new(zone()) HCompareConstantEqAndBranch(
4807           elements_kind_instr, elements_kind, Token::EQ_STRICT);
4808       elements_kind_branch->SetSuccessorAt(0, if_true);
4809       elements_kind_branch->SetSuccessorAt(1, if_false);
4810       current_block()->Finish(elements_kind_branch);
4811 
4812       set_current_block(if_true);
4813       HInstruction* access;
4814       if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4815           elements_kind == FAST_ELEMENTS ||
4816           elements_kind == FAST_DOUBLE_ELEMENTS) {
4817         if (is_store && elements_kind != FAST_DOUBLE_ELEMENTS) {
4818           AddInstruction(new(zone()) HCheckMap(
4819               elements, isolate()->factory()->fixed_array_map(),
4820               elements_kind_branch));
4821         }
4822         // TODO(jkummerow): The need for these two blocks could be avoided
4823         // in one of two ways:
4824         // (1) Introduce ElementsKinds for JSArrays that are distinct from
4825         //     those for fast objects.
4826         // (2) Put the common instructions into a third "join" block. This
4827         //     requires additional AST IDs that we can deopt to from inside
4828         //     that join block. They must be added to the Property class (when
4829         //     it's a keyed property) and registered in the full codegen.
4830         HBasicBlock* if_jsarray = graph()->CreateBasicBlock();
4831         HBasicBlock* if_fastobject = graph()->CreateBasicBlock();
4832         HHasInstanceTypeAndBranch* typecheck =
4833             new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE);
4834         typecheck->SetSuccessorAt(0, if_jsarray);
4835         typecheck->SetSuccessorAt(1, if_fastobject);
4836         current_block()->Finish(typecheck);
4837 
4838         set_current_block(if_jsarray);
4839         HInstruction* length;
4840         length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck));
4841         checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
4842         access = AddInstruction(BuildFastElementAccess(
4843             elements, checked_key, val, elements_kind, is_store));
4844         if (!is_store) {
4845           Push(access);
4846         }
4847 
4848         *has_side_effects |= access->HasObservableSideEffects();
4849         if (position != -1) {
4850           access->set_position(position);
4851         }
4852         if_jsarray->Goto(join);
4853 
4854         set_current_block(if_fastobject);
4855         length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
4856         checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
4857         access = AddInstruction(BuildFastElementAccess(
4858             elements, checked_key, val, elements_kind, is_store));
4859       } else if (elements_kind == DICTIONARY_ELEMENTS) {
4860         if (is_store) {
4861           access = AddInstruction(BuildStoreKeyedGeneric(object, key, val));
4862         } else {
4863           access = AddInstruction(BuildLoadKeyedGeneric(object, key));
4864         }
4865       } else {  // External array elements.
4866         access = AddInstruction(BuildExternalArrayElementAccess(
4867             external_elements, checked_key, val, elements_kind, is_store));
4868       }
4869       *has_side_effects |= access->HasObservableSideEffects();
4870       access->set_position(position);
4871       if (!is_store) {
4872         Push(access);
4873       }
4874       current_block()->Goto(join);
4875       set_current_block(if_false);
4876     }
4877   }
4878 
4879   // Deopt if none of the cases matched.
4880   current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses);
4881   join->SetJoinId(ast_id);
4882   set_current_block(join);
4883   return is_store ? NULL : Pop();
4884 }
4885 
4886 
HandleKeyedElementAccess(HValue * obj,HValue * key,HValue * val,Expression * expr,int ast_id,int position,bool is_store,bool * has_side_effects)4887 HValue* HGraphBuilder::HandleKeyedElementAccess(HValue* obj,
4888                                                 HValue* key,
4889                                                 HValue* val,
4890                                                 Expression* expr,
4891                                                 int ast_id,
4892                                                 int position,
4893                                                 bool is_store,
4894                                                 bool* has_side_effects) {
4895   ASSERT(!expr->IsPropertyName());
4896   HInstruction* instr = NULL;
4897   if (expr->IsMonomorphic()) {
4898     Handle<Map> map = expr->GetMonomorphicReceiverType();
4899     if (map->has_slow_elements_kind()) {
4900       instr = is_store ? BuildStoreKeyedGeneric(obj, key, val)
4901                        : BuildLoadKeyedGeneric(obj, key);
4902     } else {
4903       AddInstruction(new(zone()) HCheckNonSmi(obj));
4904       instr = BuildMonomorphicElementAccess(obj, key, val, map, is_store);
4905     }
4906   } else if (expr->GetReceiverTypes() != NULL &&
4907              !expr->GetReceiverTypes()->is_empty()) {
4908     return HandlePolymorphicElementAccess(
4909         obj, key, val, expr, ast_id, position, is_store, has_side_effects);
4910   } else {
4911     if (is_store) {
4912       instr = BuildStoreKeyedGeneric(obj, key, val);
4913     } else {
4914       instr = BuildLoadKeyedGeneric(obj, key);
4915     }
4916   }
4917   instr->set_position(position);
4918   AddInstruction(instr);
4919   *has_side_effects = instr->HasObservableSideEffects();
4920   return instr;
4921 }
4922 
4923 
BuildStoreKeyedGeneric(HValue * object,HValue * key,HValue * value)4924 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object,
4925                                                     HValue* key,
4926                                                     HValue* value) {
4927   HValue* context = environment()->LookupContext();
4928   return new(zone()) HStoreKeyedGeneric(
4929                          context,
4930                          object,
4931                          key,
4932                          value,
4933                          function_strict_mode_flag());
4934 }
4935 
TryArgumentsAccess(Property * expr)4936 bool HGraphBuilder::TryArgumentsAccess(Property* expr) {
4937   VariableProxy* proxy = expr->obj()->AsVariableProxy();
4938   if (proxy == NULL) return false;
4939   if (!proxy->var()->IsStackAllocated()) return false;
4940   if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) {
4941     return false;
4942   }
4943 
4944   // Our implementation of arguments (based on this stack frame or an
4945   // adapter below it) does not work for inlined functions.
4946   if (function_state()->outer() != NULL) {
4947     Bailout("arguments access in inlined function");
4948     return true;
4949   }
4950 
4951   HInstruction* result = NULL;
4952   if (expr->key()->IsPropertyName()) {
4953     Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
4954     if (!name->IsEqualTo(CStrVector("length"))) return false;
4955     HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
4956     result = new(zone()) HArgumentsLength(elements);
4957   } else {
4958     Push(graph()->GetArgumentsObject());
4959     VisitForValue(expr->key());
4960     if (HasStackOverflow() || current_block() == NULL) return true;
4961     HValue* key = Pop();
4962     Drop(1);  // Arguments object.
4963     HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
4964     HInstruction* length = AddInstruction(
4965         new(zone()) HArgumentsLength(elements));
4966     HInstruction* checked_key =
4967         AddInstruction(new(zone()) HBoundsCheck(key, length));
4968     result = new(zone()) HAccessArgumentsAt(elements, length, checked_key);
4969   }
4970   ast_context()->ReturnInstruction(result, expr->id());
4971   return true;
4972 }
4973 
4974 
VisitProperty(Property * expr)4975 void HGraphBuilder::VisitProperty(Property* expr) {
4976   ASSERT(!HasStackOverflow());
4977   ASSERT(current_block() != NULL);
4978   ASSERT(current_block()->HasPredecessor());
4979   expr->RecordTypeFeedback(oracle());
4980 
4981   if (TryArgumentsAccess(expr)) return;
4982 
4983   CHECK_ALIVE(VisitForValue(expr->obj()));
4984 
4985   HInstruction* instr = NULL;
4986   if (expr->AsProperty()->IsArrayLength()) {
4987     HValue* array = Pop();
4988     AddInstruction(new(zone()) HCheckNonSmi(array));
4989     HInstruction* mapcheck =
4990         AddInstruction(HCheckInstanceType::NewIsJSArray(array));
4991     instr = new(zone()) HJSArrayLength(array, mapcheck);
4992 
4993   } else if (expr->IsStringLength()) {
4994     HValue* string = Pop();
4995     AddInstruction(new(zone()) HCheckNonSmi(string));
4996     AddInstruction(HCheckInstanceType::NewIsString(string));
4997     instr = new(zone()) HStringLength(string);
4998   } else if (expr->IsStringAccess()) {
4999     CHECK_ALIVE(VisitForValue(expr->key()));
5000     HValue* index = Pop();
5001     HValue* string = Pop();
5002     HValue* context = environment()->LookupContext();
5003     HStringCharCodeAt* char_code =
5004       BuildStringCharCodeAt(context, string, index);
5005     AddInstruction(char_code);
5006     instr = new(zone()) HStringCharFromCode(context, char_code);
5007 
5008   } else if (expr->IsFunctionPrototype()) {
5009     HValue* function = Pop();
5010     AddInstruction(new(zone()) HCheckNonSmi(function));
5011     instr = new(zone()) HLoadFunctionPrototype(function);
5012 
5013   } else if (expr->key()->IsPropertyName()) {
5014     Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
5015     SmallMapList* types = expr->GetReceiverTypes();
5016 
5017     HValue* obj = Pop();
5018     if (expr->IsMonomorphic()) {
5019       instr = BuildLoadNamed(obj, expr, types->first(), name);
5020     } else if (types != NULL && types->length() > 1) {
5021       AddInstruction(new(zone()) HCheckNonSmi(obj));
5022       HValue* context = environment()->LookupContext();
5023       instr = new(zone()) HLoadNamedFieldPolymorphic(context, obj, types, name);
5024     } else {
5025       instr = BuildLoadNamedGeneric(obj, expr);
5026     }
5027 
5028   } else {
5029     CHECK_ALIVE(VisitForValue(expr->key()));
5030 
5031     HValue* key = Pop();
5032     HValue* obj = Pop();
5033 
5034     bool has_side_effects = false;
5035     HValue* load = HandleKeyedElementAccess(
5036         obj, key, NULL, expr, expr->id(), expr->position(),
5037         false,  // is_store
5038         &has_side_effects);
5039     if (has_side_effects) {
5040       if (ast_context()->IsEffect()) {
5041         AddSimulate(expr->id());
5042       } else {
5043         Push(load);
5044         AddSimulate(expr->id());
5045         Drop(1);
5046       }
5047     }
5048     return ast_context()->ReturnValue(load);
5049   }
5050   instr->set_position(expr->position());
5051   return ast_context()->ReturnInstruction(instr, expr->id());
5052 }
5053 
5054 
AddCheckConstantFunction(Call * expr,HValue * receiver,Handle<Map> receiver_map,bool smi_and_map_check)5055 void HGraphBuilder::AddCheckConstantFunction(Call* expr,
5056                                              HValue* receiver,
5057                                              Handle<Map> receiver_map,
5058                                              bool smi_and_map_check) {
5059   // Constant functions have the nice property that the map will change if they
5060   // are overwritten.  Therefore it is enough to check the map of the holder and
5061   // its prototypes.
5062   if (smi_and_map_check) {
5063     AddInstruction(new(zone()) HCheckNonSmi(receiver));
5064     AddInstruction(new(zone()) HCheckMap(receiver, receiver_map, NULL,
5065                                          ALLOW_ELEMENT_TRANSITION_MAPS));
5066   }
5067   if (!expr->holder().is_null()) {
5068     AddInstruction(new(zone()) HCheckPrototypeMaps(
5069         Handle<JSObject>(JSObject::cast(receiver_map->prototype())),
5070         expr->holder()));
5071   }
5072 }
5073 
5074 
HandlePolymorphicCallNamed(Call * expr,HValue * receiver,SmallMapList * types,Handle<String> name)5075 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
5076                                                HValue* receiver,
5077                                                SmallMapList* types,
5078                                                Handle<String> name) {
5079   // TODO(ager): We should recognize when the prototype chains for different
5080   // maps are identical. In that case we can avoid repeatedly generating the
5081   // same prototype map checks.
5082   int argument_count = expr->arguments()->length() + 1;  // Includes receiver.
5083   int count = 0;
5084   HBasicBlock* join = NULL;
5085   for (int i = 0; i < types->length() && count < kMaxCallPolymorphism; ++i) {
5086     Handle<Map> map = types->at(i);
5087     if (expr->ComputeTarget(map, name)) {
5088       if (count == 0) {
5089         // Only needed once.
5090         AddInstruction(new(zone()) HCheckNonSmi(receiver));
5091         join = graph()->CreateBasicBlock();
5092       }
5093       ++count;
5094       HBasicBlock* if_true = graph()->CreateBasicBlock();
5095       HBasicBlock* if_false = graph()->CreateBasicBlock();
5096       HCompareMap* compare =
5097           new(zone()) HCompareMap(receiver, map, if_true, if_false);
5098       current_block()->Finish(compare);
5099 
5100       set_current_block(if_true);
5101       AddCheckConstantFunction(expr, receiver, map, false);
5102       if (FLAG_trace_inlining && FLAG_polymorphic_inlining) {
5103         PrintF("Trying to inline the polymorphic call to %s\n",
5104                *name->ToCString());
5105       }
5106       if (FLAG_polymorphic_inlining && TryInlineCall(expr)) {
5107         // Trying to inline will signal that we should bailout from the
5108         // entire compilation by setting stack overflow on the visitor.
5109         if (HasStackOverflow()) return;
5110       } else {
5111         HCallConstantFunction* call =
5112             new(zone()) HCallConstantFunction(expr->target(), argument_count);
5113         call->set_position(expr->position());
5114         PreProcessCall(call);
5115         AddInstruction(call);
5116         if (!ast_context()->IsEffect()) Push(call);
5117       }
5118 
5119       if (current_block() != NULL) current_block()->Goto(join);
5120       set_current_block(if_false);
5121     }
5122   }
5123 
5124   // Finish up.  Unconditionally deoptimize if we've handled all the maps we
5125   // know about and do not want to handle ones we've never seen.  Otherwise
5126   // use a generic IC.
5127   if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
5128     current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses);
5129   } else {
5130     HValue* context = environment()->LookupContext();
5131     HCallNamed* call = new(zone()) HCallNamed(context, name, argument_count);
5132     call->set_position(expr->position());
5133     PreProcessCall(call);
5134 
5135     if (join != NULL) {
5136       AddInstruction(call);
5137       if (!ast_context()->IsEffect()) Push(call);
5138       current_block()->Goto(join);
5139     } else {
5140       return ast_context()->ReturnInstruction(call, expr->id());
5141     }
5142   }
5143 
5144   // We assume that control flow is always live after an expression.  So
5145   // even without predecessors to the join block, we set it as the exit
5146   // block and continue by adding instructions there.
5147   ASSERT(join != NULL);
5148   if (join->HasPredecessor()) {
5149     set_current_block(join);
5150     join->SetJoinId(expr->id());
5151     if (!ast_context()->IsEffect()) return ast_context()->ReturnValue(Pop());
5152   } else {
5153     set_current_block(NULL);
5154   }
5155 }
5156 
5157 
TraceInline(Handle<JSFunction> target,Handle<JSFunction> caller,const char * reason)5158 void HGraphBuilder::TraceInline(Handle<JSFunction> target,
5159                                 Handle<JSFunction> caller,
5160                                 const char* reason) {
5161   if (FLAG_trace_inlining) {
5162     SmartArrayPointer<char> target_name =
5163         target->shared()->DebugName()->ToCString();
5164     SmartArrayPointer<char> caller_name =
5165         caller->shared()->DebugName()->ToCString();
5166     if (reason == NULL) {
5167       PrintF("Inlined %s called from %s.\n", *target_name, *caller_name);
5168     } else {
5169       PrintF("Did not inline %s called from %s (%s).\n",
5170              *target_name, *caller_name, reason);
5171     }
5172   }
5173 }
5174 
5175 
TryInline(CallKind call_kind,Handle<JSFunction> target,ZoneList<Expression * > * arguments,HValue * receiver,int ast_id,int return_id,ReturnHandlingFlag return_handling)5176 bool HGraphBuilder::TryInline(CallKind call_kind,
5177                               Handle<JSFunction> target,
5178                               ZoneList<Expression*>* arguments,
5179                               HValue* receiver,
5180                               int ast_id,
5181                               int return_id,
5182                               ReturnHandlingFlag return_handling) {
5183   if (!FLAG_use_inlining) return false;
5184 
5185   // Precondition: call is monomorphic and we have found a target with the
5186   // appropriate arity.
5187   Handle<JSFunction> caller = info()->closure();
5188   Handle<SharedFunctionInfo> target_shared(target->shared());
5189 
5190   // Do a quick check on source code length to avoid parsing large
5191   // inlining candidates.
5192   if ((FLAG_limit_inlining && target_shared->SourceSize() > kMaxSourceSize)
5193       || target_shared->SourceSize() > kUnlimitedMaxSourceSize) {
5194     TraceInline(target, caller, "target text too big");
5195     return false;
5196   }
5197 
5198   // Target must be inlineable.
5199   if (!target->IsInlineable()) {
5200     TraceInline(target, caller, "target not inlineable");
5201     return false;
5202   }
5203   if (target_shared->dont_inline() || target_shared->dont_optimize()) {
5204     TraceInline(target, caller, "target contains unsupported syntax [early]");
5205     return false;
5206   }
5207 
5208   int nodes_added = target_shared->ast_node_count();
5209   if ((FLAG_limit_inlining && nodes_added > kMaxInlinedSize) ||
5210       nodes_added > kUnlimitedMaxInlinedSize) {
5211     TraceInline(target, caller, "target AST is too large [early]");
5212     return false;
5213   }
5214 
5215 #if !defined(V8_TARGET_ARCH_IA32)
5216   // Target must be able to use caller's context.
5217   CompilationInfo* outer_info = info();
5218   if (target->context() != outer_info->closure()->context() ||
5219       outer_info->scope()->contains_with() ||
5220       outer_info->scope()->num_heap_slots() > 0) {
5221     TraceInline(target, caller, "target requires context change");
5222     return false;
5223   }
5224 #endif
5225 
5226 
5227   // Don't inline deeper than kMaxInliningLevels calls.
5228   HEnvironment* env = environment();
5229   int current_level = 1;
5230   while (env->outer() != NULL) {
5231     if (current_level == Compiler::kMaxInliningLevels) {
5232       TraceInline(target, caller, "inline depth limit reached");
5233       return false;
5234     }
5235     if (env->outer()->frame_type() == JS_FUNCTION) {
5236       current_level++;
5237     }
5238     env = env->outer();
5239   }
5240 
5241   // Don't inline recursive functions.
5242   for (FunctionState* state = function_state();
5243        state != NULL;
5244        state = state->outer()) {
5245     if (state->compilation_info()->closure()->shared() == *target_shared) {
5246       TraceInline(target, caller, "target is recursive");
5247       return false;
5248     }
5249   }
5250 
5251   // We don't want to add more than a certain number of nodes from inlining.
5252   if ((FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) ||
5253       inlined_count_ > kUnlimitedMaxInlinedNodes) {
5254     TraceInline(target, caller, "cumulative AST node limit reached");
5255     return false;
5256   }
5257 
5258   // Parse and allocate variables.
5259   CompilationInfo target_info(target);
5260   if (!ParserApi::Parse(&target_info, kNoParsingFlags) ||
5261       !Scope::Analyze(&target_info)) {
5262     if (target_info.isolate()->has_pending_exception()) {
5263       // Parse or scope error, never optimize this function.
5264       SetStackOverflow();
5265       target_shared->DisableOptimization();
5266     }
5267     TraceInline(target, caller, "parse failure");
5268     return false;
5269   }
5270 
5271   if (target_info.scope()->num_heap_slots() > 0) {
5272     TraceInline(target, caller, "target has context-allocated variables");
5273     return false;
5274   }
5275   FunctionLiteral* function = target_info.function();
5276 
5277   // The following conditions must be checked again after re-parsing, because
5278   // earlier the information might not have been complete due to lazy parsing.
5279   nodes_added = function->ast_node_count();
5280   if ((FLAG_limit_inlining && nodes_added > kMaxInlinedSize) ||
5281       nodes_added > kUnlimitedMaxInlinedSize) {
5282     TraceInline(target, caller, "target AST is too large [late]");
5283     return false;
5284   }
5285   AstProperties::Flags* flags(function->flags());
5286   if (flags->Contains(kDontInline) || flags->Contains(kDontOptimize)) {
5287     TraceInline(target, caller, "target contains unsupported syntax [late]");
5288     return false;
5289   }
5290 
5291   // If the function uses the arguments object check that inlining of functions
5292   // with arguments object is enabled and the arguments-variable is
5293   // stack allocated.
5294   if (function->scope()->arguments() != NULL) {
5295     if (!FLAG_inline_arguments) {
5296       TraceInline(target, caller, "target uses arguments object");
5297       return false;
5298     }
5299 
5300     if (!function->scope()->arguments()->IsStackAllocated()) {
5301       TraceInline(target,
5302                   caller,
5303                   "target uses non-stackallocated arguments object");
5304       return false;
5305     }
5306   }
5307 
5308   // All declarations must be inlineable.
5309   ZoneList<Declaration*>* decls = target_info.scope()->declarations();
5310   int decl_count = decls->length();
5311   for (int i = 0; i < decl_count; ++i) {
5312     if (!decls->at(i)->IsInlineable()) {
5313       TraceInline(target, caller, "target has non-trivial declaration");
5314       return false;
5315     }
5316   }
5317 
5318   // Generate the deoptimization data for the unoptimized version of
5319   // the target function if we don't already have it.
5320   if (!target_shared->has_deoptimization_support()) {
5321     // Note that we compile here using the same AST that we will use for
5322     // generating the optimized inline code.
5323     target_info.EnableDeoptimizationSupport();
5324     if (!FullCodeGenerator::MakeCode(&target_info)) {
5325       TraceInline(target, caller, "could not generate deoptimization info");
5326       return false;
5327     }
5328     if (target_shared->scope_info() == ScopeInfo::Empty()) {
5329       // The scope info might not have been set if a lazily compiled
5330       // function is inlined before being called for the first time.
5331       Handle<ScopeInfo> target_scope_info =
5332           ScopeInfo::Create(target_info.scope());
5333       target_shared->set_scope_info(*target_scope_info);
5334     }
5335     target_shared->EnableDeoptimizationSupport(*target_info.code());
5336     Compiler::RecordFunctionCompilation(Logger::FUNCTION_TAG,
5337                                         &target_info,
5338                                         target_shared);
5339   }
5340 
5341   // ----------------------------------------------------------------
5342   // After this point, we've made a decision to inline this function (so
5343   // TryInline should always return true).
5344 
5345   // Save the pending call context and type feedback oracle. Set up new ones
5346   // for the inlined function.
5347   ASSERT(target_shared->has_deoptimization_support());
5348   TypeFeedbackOracle target_oracle(
5349       Handle<Code>(target_shared->code()),
5350       Handle<Context>(target->context()->global_context()),
5351       isolate());
5352   // The function state is new-allocated because we need to delete it
5353   // in two different places.
5354   FunctionState* target_state = new FunctionState(
5355       this, &target_info, &target_oracle, return_handling);
5356 
5357   HConstant* undefined = graph()->GetConstantUndefined();
5358   HEnvironment* inner_env =
5359       environment()->CopyForInlining(target,
5360                                      arguments->length(),
5361                                      function,
5362                                      undefined,
5363                                      call_kind,
5364                                      function_state()->is_construct());
5365 #ifdef V8_TARGET_ARCH_IA32
5366   // IA32 only, overwrite the caller's context in the deoptimization
5367   // environment with the correct one.
5368   //
5369   // TODO(kmillikin): implement the same inlining on other platforms so we
5370   // can remove the unsightly ifdefs in this function.
5371   HConstant* context = new HConstant(Handle<Context>(target->context()),
5372                                      Representation::Tagged());
5373   AddInstruction(context);
5374   inner_env->BindContext(context);
5375 #endif
5376   AddSimulate(return_id);
5377   current_block()->UpdateEnvironment(inner_env);
5378   AddInstruction(new(zone()) HEnterInlined(target,
5379                                            arguments->length(),
5380                                            function,
5381                                            call_kind,
5382                                            function_state()->is_construct(),
5383                                            function->scope()->arguments()));
5384   // If the function uses arguments object create and bind one.
5385   if (function->scope()->arguments() != NULL) {
5386     ASSERT(function->scope()->arguments()->IsStackAllocated());
5387     environment()->Bind(function->scope()->arguments(),
5388                         graph()->GetArgumentsObject());
5389   }
5390   VisitDeclarations(target_info.scope()->declarations());
5391   VisitStatements(function->body());
5392   if (HasStackOverflow()) {
5393     // Bail out if the inline function did, as we cannot residualize a call
5394     // instead.
5395     TraceInline(target, caller, "inline graph construction failed");
5396     target_shared->DisableOptimization();
5397     inline_bailout_ = true;
5398     delete target_state;
5399     return true;
5400   }
5401 
5402   // Update inlined nodes count.
5403   inlined_count_ += nodes_added;
5404 
5405   TraceInline(target, caller, NULL);
5406 
5407   if (current_block() != NULL) {
5408     // Add default return value (i.e. undefined for normals calls or the newly
5409     // allocated receiver for construct calls) if control can fall off the
5410     // body.  In a test context, undefined is false and any JSObject is true.
5411     if (call_context()->IsValue()) {
5412       ASSERT(function_return() != NULL);
5413       HValue* return_value = function_state()->is_construct()
5414           ? receiver
5415           : undefined;
5416       current_block()->AddLeaveInlined(return_value,
5417                                        function_return(),
5418                                        function_state()->drop_extra());
5419     } else if (call_context()->IsEffect()) {
5420       ASSERT(function_return() != NULL);
5421       current_block()->Goto(function_return(), function_state()->drop_extra());
5422     } else {
5423       ASSERT(call_context()->IsTest());
5424       ASSERT(inlined_test_context() != NULL);
5425       HBasicBlock* target = function_state()->is_construct()
5426           ? inlined_test_context()->if_true()
5427           : inlined_test_context()->if_false();
5428       current_block()->Goto(target, function_state()->drop_extra());
5429     }
5430   }
5431 
5432   // Fix up the function exits.
5433   if (inlined_test_context() != NULL) {
5434     HBasicBlock* if_true = inlined_test_context()->if_true();
5435     HBasicBlock* if_false = inlined_test_context()->if_false();
5436 
5437     // Pop the return test context from the expression context stack.
5438     ASSERT(ast_context() == inlined_test_context());
5439     ClearInlinedTestContext();
5440     delete target_state;
5441 
5442     // Forward to the real test context.
5443     if (if_true->HasPredecessor()) {
5444       if_true->SetJoinId(ast_id);
5445       HBasicBlock* true_target = TestContext::cast(ast_context())->if_true();
5446       if_true->Goto(true_target, function_state()->drop_extra());
5447     }
5448     if (if_false->HasPredecessor()) {
5449       if_false->SetJoinId(ast_id);
5450       HBasicBlock* false_target = TestContext::cast(ast_context())->if_false();
5451       if_false->Goto(false_target, function_state()->drop_extra());
5452     }
5453     set_current_block(NULL);
5454     return true;
5455 
5456   } else if (function_return()->HasPredecessor()) {
5457     function_return()->SetJoinId(ast_id);
5458     set_current_block(function_return());
5459   } else {
5460     set_current_block(NULL);
5461   }
5462   delete target_state;
5463   return true;
5464 }
5465 
5466 
TryInlineCall(Call * expr,bool drop_extra)5467 bool HGraphBuilder::TryInlineCall(Call* expr, bool drop_extra) {
5468   // The function call we are inlining is a method call if the call
5469   // is a property call.
5470   CallKind call_kind = (expr->expression()->AsProperty() == NULL)
5471       ? CALL_AS_FUNCTION
5472       : CALL_AS_METHOD;
5473 
5474   return TryInline(call_kind,
5475                    expr->target(),
5476                    expr->arguments(),
5477                    NULL,
5478                    expr->id(),
5479                    expr->ReturnId(),
5480                    drop_extra ? DROP_EXTRA_ON_RETURN : NORMAL_RETURN);
5481 }
5482 
5483 
TryInlineConstruct(CallNew * expr,HValue * receiver)5484 bool HGraphBuilder::TryInlineConstruct(CallNew* expr, HValue* receiver) {
5485   return TryInline(CALL_AS_FUNCTION,
5486                    expr->target(),
5487                    expr->arguments(),
5488                    receiver,
5489                    expr->id(),
5490                    expr->ReturnId(),
5491                    CONSTRUCT_CALL_RETURN);
5492 }
5493 
5494 
TryInlineBuiltinFunctionCall(Call * expr,bool drop_extra)5495 bool HGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr, bool drop_extra) {
5496   if (!expr->target()->shared()->HasBuiltinFunctionId()) return false;
5497   BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
5498   switch (id) {
5499     case kMathRound:
5500     case kMathAbs:
5501     case kMathSqrt:
5502     case kMathLog:
5503     case kMathSin:
5504     case kMathCos:
5505     case kMathTan:
5506       if (expr->arguments()->length() == 1) {
5507         HValue* argument = Pop();
5508         HValue* context = environment()->LookupContext();
5509         Drop(1);  // Receiver.
5510         HUnaryMathOperation* op =
5511             new(zone()) HUnaryMathOperation(context, argument, id);
5512         op->set_position(expr->position());
5513         if (drop_extra) Drop(1);  // Optionally drop the function.
5514         ast_context()->ReturnInstruction(op, expr->id());
5515         return true;
5516       }
5517       break;
5518     default:
5519       // Not supported for inlining yet.
5520       break;
5521   }
5522   return false;
5523 }
5524 
5525 
TryInlineBuiltinMethodCall(Call * expr,HValue * receiver,Handle<Map> receiver_map,CheckType check_type)5526 bool HGraphBuilder::TryInlineBuiltinMethodCall(Call* expr,
5527                                                HValue* receiver,
5528                                                Handle<Map> receiver_map,
5529                                                CheckType check_type) {
5530   ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null());
5531   // Try to inline calls like Math.* as operations in the calling function.
5532   if (!expr->target()->shared()->HasBuiltinFunctionId()) return false;
5533   BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
5534   int argument_count = expr->arguments()->length() + 1;  // Plus receiver.
5535   switch (id) {
5536     case kStringCharCodeAt:
5537     case kStringCharAt:
5538       if (argument_count == 2 && check_type == STRING_CHECK) {
5539         HValue* index = Pop();
5540         HValue* string = Pop();
5541         HValue* context = environment()->LookupContext();
5542         ASSERT(!expr->holder().is_null());
5543         AddInstruction(new(zone()) HCheckPrototypeMaps(
5544             oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK),
5545             expr->holder()));
5546         HStringCharCodeAt* char_code =
5547             BuildStringCharCodeAt(context, string, index);
5548         if (id == kStringCharCodeAt) {
5549           ast_context()->ReturnInstruction(char_code, expr->id());
5550           return true;
5551         }
5552         AddInstruction(char_code);
5553         HStringCharFromCode* result =
5554             new(zone()) HStringCharFromCode(context, char_code);
5555         ast_context()->ReturnInstruction(result, expr->id());
5556         return true;
5557       }
5558       break;
5559     case kMathRound:
5560     case kMathFloor:
5561     case kMathAbs:
5562     case kMathSqrt:
5563     case kMathLog:
5564     case kMathSin:
5565     case kMathCos:
5566     case kMathTan:
5567       if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) {
5568         AddCheckConstantFunction(expr, receiver, receiver_map, true);
5569         HValue* argument = Pop();
5570         HValue* context = environment()->LookupContext();
5571         Drop(1);  // Receiver.
5572         HUnaryMathOperation* op =
5573             new(zone()) HUnaryMathOperation(context, argument, id);
5574         op->set_position(expr->position());
5575         ast_context()->ReturnInstruction(op, expr->id());
5576         return true;
5577       }
5578       break;
5579     case kMathPow:
5580       if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) {
5581         AddCheckConstantFunction(expr, receiver, receiver_map, true);
5582         HValue* right = Pop();
5583         HValue* left = Pop();
5584         Pop();  // Pop receiver.
5585         HValue* context = environment()->LookupContext();
5586         HInstruction* result = NULL;
5587         // Use sqrt() if exponent is 0.5 or -0.5.
5588         if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) {
5589           double exponent = HConstant::cast(right)->DoubleValue();
5590           if (exponent == 0.5) {
5591             result =
5592                 new(zone()) HUnaryMathOperation(context, left, kMathPowHalf);
5593           } else if (exponent == -0.5) {
5594             HConstant* double_one =
5595                 new(zone()) HConstant(Handle<Object>(Smi::FromInt(1)),
5596                                       Representation::Double());
5597             AddInstruction(double_one);
5598             HUnaryMathOperation* square_root =
5599                 new(zone()) HUnaryMathOperation(context, left, kMathPowHalf);
5600             AddInstruction(square_root);
5601             // MathPowHalf doesn't have side effects so there's no need for
5602             // an environment simulation here.
5603             ASSERT(!square_root->HasObservableSideEffects());
5604             result = new(zone()) HDiv(context, double_one, square_root);
5605           } else if (exponent == 2.0) {
5606             result = new(zone()) HMul(context, left, left);
5607           }
5608         } else if (right->IsConstant() &&
5609                    HConstant::cast(right)->HasInteger32Value() &&
5610                    HConstant::cast(right)->Integer32Value() == 2) {
5611           result = new(zone()) HMul(context, left, left);
5612         }
5613 
5614         if (result == NULL) {
5615           result = new(zone()) HPower(left, right);
5616         }
5617         ast_context()->ReturnInstruction(result, expr->id());
5618         return true;
5619       }
5620       break;
5621     case kMathRandom:
5622       if (argument_count == 1 && check_type == RECEIVER_MAP_CHECK) {
5623         AddCheckConstantFunction(expr, receiver, receiver_map, true);
5624         Drop(1);  // Receiver.
5625         HValue* context = environment()->LookupContext();
5626         HGlobalObject* global_object = new(zone()) HGlobalObject(context);
5627         AddInstruction(global_object);
5628         HRandom* result = new(zone()) HRandom(global_object);
5629         ast_context()->ReturnInstruction(result, expr->id());
5630         return true;
5631       }
5632       break;
5633     case kMathMax:
5634     case kMathMin:
5635       if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) {
5636         AddCheckConstantFunction(expr, receiver, receiver_map, true);
5637         HValue* right = Pop();
5638         HValue* left = Pop();
5639         Pop();  // Pop receiver.
5640 
5641         HValue* left_operand = left;
5642         HValue* right_operand = right;
5643 
5644         // If we do not have two integers, we convert to double for comparison.
5645         if (!left->representation().IsInteger32() ||
5646             !right->representation().IsInteger32()) {
5647           if (!left->representation().IsDouble()) {
5648             HChange* left_convert = new(zone()) HChange(
5649                 left,
5650                 Representation::Double(),
5651                 false,  // Do not truncate when converting to double.
5652                 true);  // Deoptimize for undefined.
5653             left_convert->SetFlag(HValue::kBailoutOnMinusZero);
5654             left_operand = AddInstruction(left_convert);
5655           }
5656           if (!right->representation().IsDouble()) {
5657             HChange* right_convert = new(zone()) HChange(
5658                 right,
5659                 Representation::Double(),
5660                 false,  // Do not truncate when converting to double.
5661                 true);  // Deoptimize for undefined.
5662             right_convert->SetFlag(HValue::kBailoutOnMinusZero);
5663             right_operand = AddInstruction(right_convert);
5664           }
5665         }
5666 
5667         ASSERT(left_operand->representation().Equals(
5668                right_operand->representation()));
5669         ASSERT(!left_operand->representation().IsTagged());
5670 
5671         Token::Value op = (id == kMathMin) ? Token::LT : Token::GT;
5672 
5673         HCompareIDAndBranch* compare =
5674             new(zone()) HCompareIDAndBranch(left_operand, right_operand, op);
5675         compare->SetInputRepresentation(left_operand->representation());
5676 
5677         HBasicBlock* return_left = graph()->CreateBasicBlock();
5678         HBasicBlock* return_right = graph()->CreateBasicBlock();
5679 
5680         compare->SetSuccessorAt(0, return_left);
5681         compare->SetSuccessorAt(1, return_right);
5682         current_block()->Finish(compare);
5683 
5684         set_current_block(return_left);
5685         Push(left);
5686         set_current_block(return_right);
5687         // The branch above always returns the right operand if either of
5688         // them is NaN, but the spec requires that max/min(NaN, X) = NaN.
5689         // We add another branch that checks if the left operand is NaN or not.
5690         if (left_operand->representation().IsDouble()) {
5691           // If left_operand != left_operand then it is NaN.
5692           HCompareIDAndBranch* compare_nan = new(zone()) HCompareIDAndBranch(
5693               left_operand, left_operand, Token::EQ);
5694           compare_nan->SetInputRepresentation(left_operand->representation());
5695           HBasicBlock* left_is_number = graph()->CreateBasicBlock();
5696           HBasicBlock* left_is_nan = graph()->CreateBasicBlock();
5697           compare_nan->SetSuccessorAt(0, left_is_number);
5698           compare_nan->SetSuccessorAt(1, left_is_nan);
5699           current_block()->Finish(compare_nan);
5700           set_current_block(left_is_nan);
5701           Push(left);
5702           set_current_block(left_is_number);
5703           Push(right);
5704           return_right = CreateJoin(left_is_number, left_is_nan, expr->id());
5705         } else {
5706           Push(right);
5707         }
5708 
5709         HBasicBlock* join = CreateJoin(return_left, return_right, expr->id());
5710         set_current_block(join);
5711         ast_context()->ReturnValue(Pop());
5712         return true;
5713       }
5714       break;
5715     default:
5716       // Not yet supported for inlining.
5717       break;
5718   }
5719   return false;
5720 }
5721 
5722 
TryCallApply(Call * expr)5723 bool HGraphBuilder::TryCallApply(Call* expr) {
5724   Expression* callee = expr->expression();
5725   Property* prop = callee->AsProperty();
5726   ASSERT(prop != NULL);
5727 
5728   if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) {
5729     return false;
5730   }
5731   Handle<Map> function_map = expr->GetReceiverTypes()->first();
5732   if (function_map->instance_type() != JS_FUNCTION_TYPE ||
5733       !expr->target()->shared()->HasBuiltinFunctionId() ||
5734       expr->target()->shared()->builtin_function_id() != kFunctionApply) {
5735     return false;
5736   }
5737 
5738   if (info()->scope()->arguments() == NULL) return false;
5739 
5740   ZoneList<Expression*>* args = expr->arguments();
5741   if (args->length() != 2) return false;
5742 
5743   VariableProxy* arg_two = args->at(1)->AsVariableProxy();
5744   if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
5745   HValue* arg_two_value = environment()->Lookup(arg_two->var());
5746   if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
5747 
5748   // Found pattern f.apply(receiver, arguments).
5749   VisitForValue(prop->obj());
5750   if (HasStackOverflow() || current_block() == NULL) return true;
5751   HValue* function = Top();
5752   AddCheckConstantFunction(expr, function, function_map, true);
5753   Drop(1);
5754 
5755   VisitForValue(args->at(0));
5756   if (HasStackOverflow() || current_block() == NULL) return true;
5757   HValue* receiver = Pop();
5758 
5759   if (function_state()->outer() == NULL) {
5760     HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
5761     HInstruction* length =
5762         AddInstruction(new(zone()) HArgumentsLength(elements));
5763     HValue* wrapped_receiver =
5764         AddInstruction(new(zone()) HWrapReceiver(receiver, function));
5765     HInstruction* result =
5766         new(zone()) HApplyArguments(function,
5767                                     wrapped_receiver,
5768                                     length,
5769                                     elements);
5770     result->set_position(expr->position());
5771     ast_context()->ReturnInstruction(result, expr->id());
5772     return true;
5773   } else {
5774     // We are inside inlined function and we know exactly what is inside
5775     // arguments object.
5776     HValue* context = environment()->LookupContext();
5777 
5778     HValue* wrapped_receiver =
5779         AddInstruction(new(zone()) HWrapReceiver(receiver, function));
5780     PushAndAdd(new(zone()) HPushArgument(wrapped_receiver));
5781 
5782     HEnvironment* arguments_env = environment()->arguments_environment();
5783 
5784     int parameter_count = arguments_env->parameter_count();
5785     for (int i = 1; i < arguments_env->parameter_count(); i++) {
5786       PushAndAdd(new(zone()) HPushArgument(arguments_env->Lookup(i)));
5787     }
5788 
5789     HInvokeFunction* call = new(zone()) HInvokeFunction(
5790         context,
5791         function,
5792         parameter_count);
5793     Drop(parameter_count);
5794     call->set_position(expr->position());
5795     ast_context()->ReturnInstruction(call, expr->id());
5796     return true;
5797   }
5798 }
5799 
5800 
VisitCall(Call * expr)5801 void HGraphBuilder::VisitCall(Call* expr) {
5802   ASSERT(!HasStackOverflow());
5803   ASSERT(current_block() != NULL);
5804   ASSERT(current_block()->HasPredecessor());
5805   Expression* callee = expr->expression();
5806   int argument_count = expr->arguments()->length() + 1;  // Plus receiver.
5807   HInstruction* call = NULL;
5808 
5809   Property* prop = callee->AsProperty();
5810   if (prop != NULL) {
5811     if (!prop->key()->IsPropertyName()) {
5812       // Keyed function call.
5813       CHECK_ALIVE(VisitArgument(prop->obj()));
5814 
5815       CHECK_ALIVE(VisitForValue(prop->key()));
5816       // Push receiver and key like the non-optimized code generator expects it.
5817       HValue* key = Pop();
5818       HValue* receiver = Pop();
5819       Push(key);
5820       Push(receiver);
5821 
5822       CHECK_ALIVE(VisitArgumentList(expr->arguments()));
5823 
5824       HValue* context = environment()->LookupContext();
5825       call = new(zone()) HCallKeyed(context, key, argument_count);
5826       call->set_position(expr->position());
5827       Drop(argument_count + 1);  // 1 is the key.
5828       return ast_context()->ReturnInstruction(call, expr->id());
5829     }
5830 
5831     // Named function call.
5832     expr->RecordTypeFeedback(oracle(), CALL_AS_METHOD);
5833 
5834     if (TryCallApply(expr)) return;
5835 
5836     CHECK_ALIVE(VisitForValue(prop->obj()));
5837     CHECK_ALIVE(VisitExpressions(expr->arguments()));
5838 
5839     Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
5840 
5841     SmallMapList* types = expr->GetReceiverTypes();
5842 
5843     HValue* receiver =
5844         environment()->ExpressionStackAt(expr->arguments()->length());
5845     if (expr->IsMonomorphic()) {
5846       Handle<Map> receiver_map = (types == NULL || types->is_empty())
5847           ? Handle<Map>::null()
5848           : types->first();
5849       if (TryInlineBuiltinMethodCall(expr,
5850                                      receiver,
5851                                      receiver_map,
5852                                      expr->check_type())) {
5853         if (FLAG_trace_inlining) {
5854           PrintF("Inlining builtin ");
5855           expr->target()->ShortPrint();
5856           PrintF("\n");
5857         }
5858         return;
5859       }
5860 
5861       if (CallStubCompiler::HasCustomCallGenerator(expr->target()) ||
5862           expr->check_type() != RECEIVER_MAP_CHECK) {
5863         // When the target has a custom call IC generator, use the IC,
5864         // because it is likely to generate better code.  Also use the IC
5865         // when a primitive receiver check is required.
5866         HValue* context = environment()->LookupContext();
5867         call = PreProcessCall(
5868             new(zone()) HCallNamed(context, name, argument_count));
5869       } else {
5870         AddCheckConstantFunction(expr, receiver, receiver_map, true);
5871 
5872         if (TryInlineCall(expr)) return;
5873         call = PreProcessCall(
5874             new(zone()) HCallConstantFunction(expr->target(),
5875                                               argument_count));
5876       }
5877     } else if (types != NULL && types->length() > 1) {
5878       ASSERT(expr->check_type() == RECEIVER_MAP_CHECK);
5879       HandlePolymorphicCallNamed(expr, receiver, types, name);
5880       return;
5881 
5882     } else {
5883       HValue* context = environment()->LookupContext();
5884       call = PreProcessCall(
5885           new(zone()) HCallNamed(context, name, argument_count));
5886     }
5887 
5888   } else {
5889     expr->RecordTypeFeedback(oracle(), CALL_AS_FUNCTION);
5890     VariableProxy* proxy = expr->expression()->AsVariableProxy();
5891     bool global_call = proxy != NULL && proxy->var()->IsUnallocated();
5892 
5893     if (proxy != NULL && proxy->var()->is_possibly_eval()) {
5894       return Bailout("possible direct call to eval");
5895     }
5896 
5897     if (global_call) {
5898       Variable* var = proxy->var();
5899       bool known_global_function = false;
5900       // If there is a global property cell for the name at compile time and
5901       // access check is not enabled we assume that the function will not change
5902       // and generate optimized code for calling the function.
5903       LookupResult lookup(isolate());
5904       GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false);
5905       if (type == kUseCell &&
5906           !info()->global_object()->IsAccessCheckNeeded()) {
5907         Handle<GlobalObject> global(info()->global_object());
5908         known_global_function = expr->ComputeGlobalTarget(global, &lookup);
5909       }
5910       if (known_global_function) {
5911         // Push the global object instead of the global receiver because
5912         // code generated by the full code generator expects it.
5913         HValue* context = environment()->LookupContext();
5914         HGlobalObject* global_object = new(zone()) HGlobalObject(context);
5915         PushAndAdd(global_object);
5916         CHECK_ALIVE(VisitExpressions(expr->arguments()));
5917 
5918         CHECK_ALIVE(VisitForValue(expr->expression()));
5919         HValue* function = Pop();
5920         AddInstruction(new(zone()) HCheckFunction(function, expr->target()));
5921 
5922         // Replace the global object with the global receiver.
5923         HGlobalReceiver* global_receiver =
5924             new(zone()) HGlobalReceiver(global_object);
5925         // Index of the receiver from the top of the expression stack.
5926         const int receiver_index = argument_count - 1;
5927         AddInstruction(global_receiver);
5928         ASSERT(environment()->ExpressionStackAt(receiver_index)->
5929                IsGlobalObject());
5930         environment()->SetExpressionStackAt(receiver_index, global_receiver);
5931 
5932         if (TryInlineBuiltinFunctionCall(expr, false)) {  // Nothing to drop.
5933           if (FLAG_trace_inlining) {
5934             PrintF("Inlining builtin ");
5935             expr->target()->ShortPrint();
5936             PrintF("\n");
5937           }
5938           return;
5939         }
5940         if (TryInlineCall(expr)) return;
5941         call = PreProcessCall(new(zone()) HCallKnownGlobal(expr->target(),
5942                                                            argument_count));
5943       } else {
5944         HValue* context = environment()->LookupContext();
5945         HGlobalObject* receiver = new(zone()) HGlobalObject(context);
5946         AddInstruction(receiver);
5947         PushAndAdd(new(zone()) HPushArgument(receiver));
5948         CHECK_ALIVE(VisitArgumentList(expr->arguments()));
5949 
5950         call = new(zone()) HCallGlobal(context, var->name(), argument_count);
5951         Drop(argument_count);
5952       }
5953 
5954     } else if (expr->IsMonomorphic()) {
5955       // The function is on the stack in the unoptimized code during
5956       // evaluation of the arguments.
5957       CHECK_ALIVE(VisitForValue(expr->expression()));
5958       HValue* function = Top();
5959       HValue* context = environment()->LookupContext();
5960       HGlobalObject* global = new(zone()) HGlobalObject(context);
5961       HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global);
5962       AddInstruction(global);
5963       PushAndAdd(receiver);
5964       CHECK_ALIVE(VisitExpressions(expr->arguments()));
5965       AddInstruction(new(zone()) HCheckFunction(function, expr->target()));
5966 
5967       if (TryInlineBuiltinFunctionCall(expr, true)) {  // Drop the function.
5968         if (FLAG_trace_inlining) {
5969           PrintF("Inlining builtin ");
5970           expr->target()->ShortPrint();
5971           PrintF("\n");
5972         }
5973         return;
5974       }
5975 
5976       if (TryInlineCall(expr, true)) {   // Drop function from environment.
5977         return;
5978       } else {
5979         call = PreProcessCall(new(zone()) HInvokeFunction(context,
5980                                                           function,
5981                                                           argument_count));
5982         Drop(1);  // The function.
5983       }
5984 
5985     } else {
5986       CHECK_ALIVE(VisitForValue(expr->expression()));
5987       HValue* function = Top();
5988       HValue* context = environment()->LookupContext();
5989       HGlobalObject* global_object = new(zone()) HGlobalObject(context);
5990       HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global_object);
5991       AddInstruction(global_object);
5992       AddInstruction(receiver);
5993       PushAndAdd(new(zone()) HPushArgument(receiver));
5994       CHECK_ALIVE(VisitArgumentList(expr->arguments()));
5995 
5996       call = new(zone()) HCallFunction(context, function, argument_count);
5997       Drop(argument_count + 1);
5998     }
5999   }
6000 
6001   call->set_position(expr->position());
6002   return ast_context()->ReturnInstruction(call, expr->id());
6003 }
6004 
6005 
6006 // Checks whether allocation using the given constructor can be inlined.
IsAllocationInlineable(Handle<JSFunction> constructor)6007 static bool IsAllocationInlineable(Handle<JSFunction> constructor) {
6008   return constructor->has_initial_map() &&
6009       constructor->initial_map()->instance_type() == JS_OBJECT_TYPE;
6010 }
6011 
6012 
VisitCallNew(CallNew * expr)6013 void HGraphBuilder::VisitCallNew(CallNew* expr) {
6014   ASSERT(!HasStackOverflow());
6015   ASSERT(current_block() != NULL);
6016   ASSERT(current_block()->HasPredecessor());
6017   expr->RecordTypeFeedback(oracle());
6018   int argument_count = expr->arguments()->length() + 1;  // Plus constructor.
6019   HValue* context = environment()->LookupContext();
6020 
6021   if (FLAG_inline_construct &&
6022       expr->IsMonomorphic() &&
6023       IsAllocationInlineable(expr->target())) {
6024     // The constructor function is on the stack in the unoptimized code
6025     // during evaluation of the arguments.
6026     CHECK_ALIVE(VisitForValue(expr->expression()));
6027     HValue* function = Top();
6028     CHECK_ALIVE(VisitExpressions(expr->arguments()));
6029     Handle<JSFunction> constructor = expr->target();
6030     HValue* check = AddInstruction(
6031         new(zone()) HCheckFunction(function, constructor));
6032 
6033     // Force completion of inobject slack tracking before generating
6034     // allocation code to finalize instance size.
6035     if (constructor->shared()->IsInobjectSlackTrackingInProgress()) {
6036       constructor->shared()->CompleteInobjectSlackTracking();
6037     }
6038 
6039     // Replace the constructor function with a newly allocated receiver.
6040     HInstruction* receiver = new(zone()) HAllocateObject(context, constructor);
6041     // Index of the receiver from the top of the expression stack.
6042     const int receiver_index = argument_count - 1;
6043     AddInstruction(receiver);
6044     ASSERT(environment()->ExpressionStackAt(receiver_index) == function);
6045     environment()->SetExpressionStackAt(receiver_index, receiver);
6046 
6047     if (TryInlineConstruct(expr, receiver)) return;
6048 
6049     // TODO(mstarzinger): For now we remove the previous HAllocateObject and
6050     // add HPushArgument for the arguments in case inlining failed.  What we
6051     // actually should do is emit HInvokeFunction on the constructor instead
6052     // of using HCallNew as a fallback.
6053     receiver->DeleteAndReplaceWith(NULL);
6054     check->DeleteAndReplaceWith(NULL);
6055     environment()->SetExpressionStackAt(receiver_index, function);
6056     HInstruction* call = PreProcessCall(
6057         new(zone()) HCallNew(context, function, argument_count));
6058     call->set_position(expr->position());
6059     return ast_context()->ReturnInstruction(call, expr->id());
6060   } else {
6061     // The constructor function is both an operand to the instruction and an
6062     // argument to the construct call.
6063     HValue* constructor = NULL;
6064     CHECK_ALIVE(constructor = VisitArgument(expr->expression()));
6065     CHECK_ALIVE(VisitArgumentList(expr->arguments()));
6066     HInstruction* call =
6067         new(zone()) HCallNew(context, constructor, argument_count);
6068     Drop(argument_count);
6069     call->set_position(expr->position());
6070     return ast_context()->ReturnInstruction(call, expr->id());
6071   }
6072 }
6073 
6074 
6075 // Support for generating inlined runtime functions.
6076 
6077 // Lookup table for generators for runtime calls that are  generated inline.
6078 // Elements of the table are member pointers to functions of HGraphBuilder.
6079 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize)  \
6080     &HGraphBuilder::Generate##Name,
6081 
6082 const HGraphBuilder::InlineFunctionGenerator
6083     HGraphBuilder::kInlineFunctionGenerators[] = {
6084         INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
6085         INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
6086 };
6087 #undef INLINE_FUNCTION_GENERATOR_ADDRESS
6088 
6089 
VisitCallRuntime(CallRuntime * expr)6090 void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
6091   ASSERT(!HasStackOverflow());
6092   ASSERT(current_block() != NULL);
6093   ASSERT(current_block()->HasPredecessor());
6094   if (expr->is_jsruntime()) {
6095     return Bailout("call to a JavaScript runtime function");
6096   }
6097 
6098   const Runtime::Function* function = expr->function();
6099   ASSERT(function != NULL);
6100   if (function->intrinsic_type == Runtime::INLINE) {
6101     ASSERT(expr->name()->length() > 0);
6102     ASSERT(expr->name()->Get(0) == '_');
6103     // Call to an inline function.
6104     int lookup_index = static_cast<int>(function->function_id) -
6105         static_cast<int>(Runtime::kFirstInlineFunction);
6106     ASSERT(lookup_index >= 0);
6107     ASSERT(static_cast<size_t>(lookup_index) <
6108            ARRAY_SIZE(kInlineFunctionGenerators));
6109     InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index];
6110 
6111     // Call the inline code generator using the pointer-to-member.
6112     (this->*generator)(expr);
6113   } else {
6114     ASSERT(function->intrinsic_type == Runtime::RUNTIME);
6115     CHECK_ALIVE(VisitArgumentList(expr->arguments()));
6116 
6117     HValue* context = environment()->LookupContext();
6118     Handle<String> name = expr->name();
6119     int argument_count = expr->arguments()->length();
6120     HCallRuntime* call =
6121         new(zone()) HCallRuntime(context, name, function, argument_count);
6122     call->set_position(RelocInfo::kNoPosition);
6123     Drop(argument_count);
6124     return ast_context()->ReturnInstruction(call, expr->id());
6125   }
6126 }
6127 
6128 
VisitUnaryOperation(UnaryOperation * expr)6129 void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
6130   ASSERT(!HasStackOverflow());
6131   ASSERT(current_block() != NULL);
6132   ASSERT(current_block()->HasPredecessor());
6133   switch (expr->op()) {
6134     case Token::DELETE: return VisitDelete(expr);
6135     case Token::VOID: return VisitVoid(expr);
6136     case Token::TYPEOF: return VisitTypeof(expr);
6137     case Token::ADD: return VisitAdd(expr);
6138     case Token::SUB: return VisitSub(expr);
6139     case Token::BIT_NOT: return VisitBitNot(expr);
6140     case Token::NOT: return VisitNot(expr);
6141     default: UNREACHABLE();
6142   }
6143 }
6144 
VisitDelete(UnaryOperation * expr)6145 void HGraphBuilder::VisitDelete(UnaryOperation* expr) {
6146   Property* prop = expr->expression()->AsProperty();
6147   VariableProxy* proxy = expr->expression()->AsVariableProxy();
6148   if (prop != NULL) {
6149     CHECK_ALIVE(VisitForValue(prop->obj()));
6150     CHECK_ALIVE(VisitForValue(prop->key()));
6151     HValue* key = Pop();
6152     HValue* obj = Pop();
6153     HValue* context = environment()->LookupContext();
6154     HDeleteProperty* instr = new(zone()) HDeleteProperty(context, obj, key);
6155     return ast_context()->ReturnInstruction(instr, expr->id());
6156   } else if (proxy != NULL) {
6157     Variable* var = proxy->var();
6158     if (var->IsUnallocated()) {
6159       Bailout("delete with global variable");
6160     } else if (var->IsStackAllocated() || var->IsContextSlot()) {
6161       // Result of deleting non-global variables is false.  'this' is not
6162       // really a variable, though we implement it as one.  The
6163       // subexpression does not have side effects.
6164       HValue* value = var->is_this()
6165           ? graph()->GetConstantTrue()
6166           : graph()->GetConstantFalse();
6167       return ast_context()->ReturnValue(value);
6168     } else {
6169       Bailout("delete with non-global variable");
6170     }
6171   } else {
6172     // Result of deleting non-property, non-variable reference is true.
6173     // Evaluate the subexpression for side effects.
6174     CHECK_ALIVE(VisitForEffect(expr->expression()));
6175     return ast_context()->ReturnValue(graph()->GetConstantTrue());
6176   }
6177 }
6178 
6179 
VisitVoid(UnaryOperation * expr)6180 void HGraphBuilder::VisitVoid(UnaryOperation* expr) {
6181   CHECK_ALIVE(VisitForEffect(expr->expression()));
6182   return ast_context()->ReturnValue(graph()->GetConstantUndefined());
6183 }
6184 
6185 
VisitTypeof(UnaryOperation * expr)6186 void HGraphBuilder::VisitTypeof(UnaryOperation* expr) {
6187   CHECK_ALIVE(VisitForTypeOf(expr->expression()));
6188   HValue* value = Pop();
6189   HValue* context = environment()->LookupContext();
6190   HInstruction* instr = new(zone()) HTypeof(context, value);
6191   return ast_context()->ReturnInstruction(instr, expr->id());
6192 }
6193 
6194 
VisitAdd(UnaryOperation * expr)6195 void HGraphBuilder::VisitAdd(UnaryOperation* expr) {
6196   CHECK_ALIVE(VisitForValue(expr->expression()));
6197   HValue* value = Pop();
6198   HValue* context = environment()->LookupContext();
6199   HInstruction* instr =
6200       new(zone()) HMul(context, value, graph_->GetConstant1());
6201   return ast_context()->ReturnInstruction(instr, expr->id());
6202 }
6203 
6204 
VisitSub(UnaryOperation * expr)6205 void HGraphBuilder::VisitSub(UnaryOperation* expr) {
6206   CHECK_ALIVE(VisitForValue(expr->expression()));
6207   HValue* value = Pop();
6208   HValue* context = environment()->LookupContext();
6209   HInstruction* instr =
6210       new(zone()) HMul(context, value, graph_->GetConstantMinus1());
6211   TypeInfo info = oracle()->UnaryType(expr);
6212   if (info.IsUninitialized()) {
6213     AddInstruction(new(zone()) HSoftDeoptimize);
6214     current_block()->MarkAsDeoptimizing();
6215     info = TypeInfo::Unknown();
6216   }
6217   Representation rep = ToRepresentation(info);
6218   TraceRepresentation(expr->op(), info, instr, rep);
6219   instr->AssumeRepresentation(rep);
6220   return ast_context()->ReturnInstruction(instr, expr->id());
6221 }
6222 
6223 
VisitBitNot(UnaryOperation * expr)6224 void HGraphBuilder::VisitBitNot(UnaryOperation* expr) {
6225   CHECK_ALIVE(VisitForValue(expr->expression()));
6226   HValue* value = Pop();
6227   TypeInfo info = oracle()->UnaryType(expr);
6228   if (info.IsUninitialized()) {
6229     AddInstruction(new(zone()) HSoftDeoptimize);
6230     current_block()->MarkAsDeoptimizing();
6231   }
6232   HInstruction* instr = new(zone()) HBitNot(value);
6233   return ast_context()->ReturnInstruction(instr, expr->id());
6234 }
6235 
6236 
VisitNot(UnaryOperation * expr)6237 void HGraphBuilder::VisitNot(UnaryOperation* expr) {
6238   if (ast_context()->IsTest()) {
6239     TestContext* context = TestContext::cast(ast_context());
6240     VisitForControl(expr->expression(),
6241                     context->if_false(),
6242                     context->if_true());
6243     return;
6244   }
6245 
6246   if (ast_context()->IsEffect()) {
6247     VisitForEffect(expr->expression());
6248     return;
6249   }
6250 
6251   ASSERT(ast_context()->IsValue());
6252   HBasicBlock* materialize_false = graph()->CreateBasicBlock();
6253   HBasicBlock* materialize_true = graph()->CreateBasicBlock();
6254   CHECK_BAILOUT(VisitForControl(expr->expression(),
6255                                 materialize_false,
6256                                 materialize_true));
6257 
6258   if (materialize_false->HasPredecessor()) {
6259     materialize_false->SetJoinId(expr->MaterializeFalseId());
6260     set_current_block(materialize_false);
6261     Push(graph()->GetConstantFalse());
6262   } else {
6263     materialize_false = NULL;
6264   }
6265 
6266   if (materialize_true->HasPredecessor()) {
6267     materialize_true->SetJoinId(expr->MaterializeTrueId());
6268     set_current_block(materialize_true);
6269     Push(graph()->GetConstantTrue());
6270   } else {
6271     materialize_true = NULL;
6272   }
6273 
6274   HBasicBlock* join =
6275     CreateJoin(materialize_false, materialize_true, expr->id());
6276   set_current_block(join);
6277   if (join != NULL) return ast_context()->ReturnValue(Pop());
6278 }
6279 
6280 
BuildIncrement(bool returns_original_input,CountOperation * expr)6281 HInstruction* HGraphBuilder::BuildIncrement(bool returns_original_input,
6282                                             CountOperation* expr) {
6283   // The input to the count operation is on top of the expression stack.
6284   TypeInfo info = oracle()->IncrementType(expr);
6285   Representation rep = ToRepresentation(info);
6286   if (rep.IsTagged()) {
6287     rep = Representation::Integer32();
6288   }
6289 
6290   if (returns_original_input) {
6291     // We need an explicit HValue representing ToNumber(input).  The
6292     // actual HChange instruction we need is (sometimes) added in a later
6293     // phase, so it is not available now to be used as an input to HAdd and
6294     // as the return value.
6295     HInstruction* number_input = new(zone()) HForceRepresentation(Pop(), rep);
6296     AddInstruction(number_input);
6297     Push(number_input);
6298   }
6299 
6300   // The addition has no side effects, so we do not need
6301   // to simulate the expression stack after this instruction.
6302   // Any later failures deopt to the load of the input or earlier.
6303   HConstant* delta = (expr->op() == Token::INC)
6304       ? graph_->GetConstant1()
6305       : graph_->GetConstantMinus1();
6306   HValue* context = environment()->LookupContext();
6307   HInstruction* instr = new(zone()) HAdd(context, Top(), delta);
6308   TraceRepresentation(expr->op(), info, instr, rep);
6309   instr->AssumeRepresentation(rep);
6310   AddInstruction(instr);
6311   return instr;
6312 }
6313 
6314 
VisitCountOperation(CountOperation * expr)6315 void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
6316   ASSERT(!HasStackOverflow());
6317   ASSERT(current_block() != NULL);
6318   ASSERT(current_block()->HasPredecessor());
6319   Expression* target = expr->expression();
6320   VariableProxy* proxy = target->AsVariableProxy();
6321   Property* prop = target->AsProperty();
6322   if (proxy == NULL && prop == NULL) {
6323     return Bailout("invalid lhs in count operation");
6324   }
6325 
6326   // Match the full code generator stack by simulating an extra stack
6327   // element for postfix operations in a non-effect context.  The return
6328   // value is ToNumber(input).
6329   bool returns_original_input =
6330       expr->is_postfix() && !ast_context()->IsEffect();
6331   HValue* input = NULL;  // ToNumber(original_input).
6332   HValue* after = NULL;  // The result after incrementing or decrementing.
6333 
6334   if (proxy != NULL) {
6335     Variable* var = proxy->var();
6336     if (var->mode() == CONST)  {
6337       return Bailout("unsupported count operation with const");
6338     }
6339     // Argument of the count operation is a variable, not a property.
6340     ASSERT(prop == NULL);
6341     CHECK_ALIVE(VisitForValue(target));
6342 
6343     after = BuildIncrement(returns_original_input, expr);
6344     input = returns_original_input ? Top() : Pop();
6345     Push(after);
6346 
6347     switch (var->location()) {
6348       case Variable::UNALLOCATED:
6349         HandleGlobalVariableAssignment(var,
6350                                        after,
6351                                        expr->position(),
6352                                        expr->AssignmentId());
6353         break;
6354 
6355       case Variable::PARAMETER:
6356       case Variable::LOCAL:
6357         Bind(var, after);
6358         break;
6359 
6360       case Variable::CONTEXT: {
6361         // Bail out if we try to mutate a parameter value in a function
6362         // using the arguments object.  We do not (yet) correctly handle the
6363         // arguments property of the function.
6364         if (info()->scope()->arguments() != NULL) {
6365           // Parameters will rewrite to context slots.  We have no direct
6366           // way to detect that the variable is a parameter so we use a
6367           // linear search of the parameter list.
6368           int count = info()->scope()->num_parameters();
6369           for (int i = 0; i < count; ++i) {
6370             if (var == info()->scope()->parameter(i)) {
6371               return Bailout("assignment to parameter in arguments object");
6372             }
6373           }
6374         }
6375 
6376         HValue* context = BuildContextChainWalk(var);
6377         HStoreContextSlot::Mode mode =
6378             (var->mode() == LET || var->mode() == CONST_HARMONY)
6379             ? HStoreContextSlot::kCheckDeoptimize : HStoreContextSlot::kNoCheck;
6380         HStoreContextSlot* instr =
6381             new(zone()) HStoreContextSlot(context, var->index(), mode, after);
6382         AddInstruction(instr);
6383         if (instr->HasObservableSideEffects()) {
6384           AddSimulate(expr->AssignmentId());
6385         }
6386         break;
6387       }
6388 
6389       case Variable::LOOKUP:
6390         return Bailout("lookup variable in count operation");
6391     }
6392 
6393   } else {
6394     // Argument of the count operation is a property.
6395     ASSERT(prop != NULL);
6396     prop->RecordTypeFeedback(oracle());
6397 
6398     if (prop->key()->IsPropertyName()) {
6399       // Named property.
6400       if (returns_original_input) Push(graph_->GetConstantUndefined());
6401 
6402       CHECK_ALIVE(VisitForValue(prop->obj()));
6403       HValue* obj = Top();
6404 
6405       HInstruction* load = NULL;
6406       if (prop->IsMonomorphic()) {
6407         Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
6408         Handle<Map> map = prop->GetReceiverTypes()->first();
6409         load = BuildLoadNamed(obj, prop, map, name);
6410       } else {
6411         load = BuildLoadNamedGeneric(obj, prop);
6412       }
6413       PushAndAdd(load);
6414       if (load->HasObservableSideEffects()) AddSimulate(expr->CountId());
6415 
6416       after = BuildIncrement(returns_original_input, expr);
6417       input = Pop();
6418 
6419       HInstruction* store = BuildStoreNamed(obj, after, prop);
6420       AddInstruction(store);
6421 
6422       // Overwrite the receiver in the bailout environment with the result
6423       // of the operation, and the placeholder with the original value if
6424       // necessary.
6425       environment()->SetExpressionStackAt(0, after);
6426       if (returns_original_input) environment()->SetExpressionStackAt(1, input);
6427       if (store->HasObservableSideEffects()) AddSimulate(expr->AssignmentId());
6428 
6429     } else {
6430       // Keyed property.
6431       if (returns_original_input) Push(graph_->GetConstantUndefined());
6432 
6433       CHECK_ALIVE(VisitForValue(prop->obj()));
6434       CHECK_ALIVE(VisitForValue(prop->key()));
6435       HValue* obj = environment()->ExpressionStackAt(1);
6436       HValue* key = environment()->ExpressionStackAt(0);
6437 
6438       bool has_side_effects = false;
6439       HValue* load = HandleKeyedElementAccess(
6440           obj, key, NULL, prop, expr->CountId(), RelocInfo::kNoPosition,
6441           false,  // is_store
6442           &has_side_effects);
6443       Push(load);
6444       if (has_side_effects) AddSimulate(expr->CountId());
6445 
6446       after = BuildIncrement(returns_original_input, expr);
6447       input = Pop();
6448 
6449       expr->RecordTypeFeedback(oracle());
6450       HandleKeyedElementAccess(obj, key, after, expr, expr->AssignmentId(),
6451                                RelocInfo::kNoPosition,
6452                                true,  // is_store
6453                                &has_side_effects);
6454 
6455       // Drop the key from the bailout environment.  Overwrite the receiver
6456       // with the result of the operation, and the placeholder with the
6457       // original value if necessary.
6458       Drop(1);
6459       environment()->SetExpressionStackAt(0, after);
6460       if (returns_original_input) environment()->SetExpressionStackAt(1, input);
6461       ASSERT(has_side_effects);  // Stores always have side effects.
6462       AddSimulate(expr->AssignmentId());
6463     }
6464   }
6465 
6466   Drop(returns_original_input ? 2 : 1);
6467   return ast_context()->ReturnValue(expr->is_postfix() ? input : after);
6468 }
6469 
6470 
BuildStringCharCodeAt(HValue * context,HValue * string,HValue * index)6471 HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* context,
6472                                                         HValue* string,
6473                                                         HValue* index) {
6474   AddInstruction(new(zone()) HCheckNonSmi(string));
6475   AddInstruction(HCheckInstanceType::NewIsString(string));
6476   HStringLength* length = new(zone()) HStringLength(string);
6477   AddInstruction(length);
6478   HInstruction* checked_index =
6479       AddInstruction(new(zone()) HBoundsCheck(index, length));
6480   return new(zone()) HStringCharCodeAt(context, string, checked_index);
6481 }
6482 
6483 
BuildBinaryOperation(BinaryOperation * expr,HValue * left,HValue * right)6484 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr,
6485                                                   HValue* left,
6486                                                   HValue* right) {
6487   HValue* context = environment()->LookupContext();
6488   TypeInfo info = oracle()->BinaryType(expr);
6489   if (info.IsUninitialized()) {
6490     AddInstruction(new(zone()) HSoftDeoptimize);
6491     current_block()->MarkAsDeoptimizing();
6492     info = TypeInfo::Unknown();
6493   }
6494   HInstruction* instr = NULL;
6495   switch (expr->op()) {
6496     case Token::ADD:
6497       if (info.IsString()) {
6498         AddInstruction(new(zone()) HCheckNonSmi(left));
6499         AddInstruction(HCheckInstanceType::NewIsString(left));
6500         AddInstruction(new(zone()) HCheckNonSmi(right));
6501         AddInstruction(HCheckInstanceType::NewIsString(right));
6502         instr = new(zone()) HStringAdd(context, left, right);
6503       } else {
6504         instr = HAdd::NewHAdd(zone(), context, left, right);
6505       }
6506       break;
6507     case Token::SUB:
6508       instr = HSub::NewHSub(zone(), context, left, right);
6509       break;
6510     case Token::MUL:
6511       instr = HMul::NewHMul(zone(), context, left, right);
6512       break;
6513     case Token::MOD:
6514       instr = HMod::NewHMod(zone(), context, left, right);
6515       break;
6516     case Token::DIV:
6517       instr = HDiv::NewHDiv(zone(), context, left, right);
6518       break;
6519     case Token::BIT_XOR:
6520     case Token::BIT_AND:
6521     case Token::BIT_OR:
6522       instr = HBitwise::NewHBitwise(zone(), expr->op(), context, left, right);
6523       break;
6524     case Token::SAR:
6525       instr = HSar::NewHSar(zone(), context, left, right);
6526       break;
6527     case Token::SHR:
6528       instr = HShr::NewHShr(zone(), context, left, right);
6529       break;
6530     case Token::SHL:
6531       instr = HShl::NewHShl(zone(), context, left, right);
6532       break;
6533     default:
6534       UNREACHABLE();
6535   }
6536 
6537   // If we hit an uninitialized binary op stub we will get type info
6538   // for a smi operation. If one of the operands is a constant string
6539   // do not generate code assuming it is a smi operation.
6540   if (info.IsSmi() &&
6541       ((left->IsConstant() && HConstant::cast(left)->HasStringValue()) ||
6542        (right->IsConstant() && HConstant::cast(right)->HasStringValue()))) {
6543     return instr;
6544   }
6545   Representation rep = ToRepresentation(info);
6546   // We only generate either int32 or generic tagged bitwise operations.
6547   if (instr->IsBitwiseBinaryOperation() && rep.IsDouble()) {
6548     rep = Representation::Integer32();
6549   }
6550   TraceRepresentation(expr->op(), info, instr, rep);
6551   instr->AssumeRepresentation(rep);
6552   return instr;
6553 }
6554 
6555 
6556 // Check for the form (%_ClassOf(foo) === 'BarClass').
IsClassOfTest(CompareOperation * expr)6557 static bool IsClassOfTest(CompareOperation* expr) {
6558   if (expr->op() != Token::EQ_STRICT) return false;
6559   CallRuntime* call = expr->left()->AsCallRuntime();
6560   if (call == NULL) return false;
6561   Literal* literal = expr->right()->AsLiteral();
6562   if (literal == NULL) return false;
6563   if (!literal->handle()->IsString()) return false;
6564   if (!call->name()->IsEqualTo(CStrVector("_ClassOf"))) return false;
6565   ASSERT(call->arguments()->length() == 1);
6566   return true;
6567 }
6568 
6569 
VisitBinaryOperation(BinaryOperation * expr)6570 void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
6571   ASSERT(!HasStackOverflow());
6572   ASSERT(current_block() != NULL);
6573   ASSERT(current_block()->HasPredecessor());
6574   switch (expr->op()) {
6575     case Token::COMMA:
6576       return VisitComma(expr);
6577     case Token::OR:
6578     case Token::AND:
6579       return VisitLogicalExpression(expr);
6580     default:
6581       return VisitArithmeticExpression(expr);
6582   }
6583 }
6584 
6585 
VisitComma(BinaryOperation * expr)6586 void HGraphBuilder::VisitComma(BinaryOperation* expr) {
6587   CHECK_ALIVE(VisitForEffect(expr->left()));
6588   // Visit the right subexpression in the same AST context as the entire
6589   // expression.
6590   Visit(expr->right());
6591 }
6592 
6593 
VisitLogicalExpression(BinaryOperation * expr)6594 void HGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
6595   bool is_logical_and = expr->op() == Token::AND;
6596   if (ast_context()->IsTest()) {
6597     TestContext* context = TestContext::cast(ast_context());
6598     // Translate left subexpression.
6599     HBasicBlock* eval_right = graph()->CreateBasicBlock();
6600     if (is_logical_and) {
6601       CHECK_BAILOUT(VisitForControl(expr->left(),
6602                                     eval_right,
6603                                     context->if_false()));
6604     } else {
6605       CHECK_BAILOUT(VisitForControl(expr->left(),
6606                                     context->if_true(),
6607                                     eval_right));
6608     }
6609 
6610     // Translate right subexpression by visiting it in the same AST
6611     // context as the entire expression.
6612     if (eval_right->HasPredecessor()) {
6613       eval_right->SetJoinId(expr->RightId());
6614       set_current_block(eval_right);
6615       Visit(expr->right());
6616     }
6617 
6618   } else if (ast_context()->IsValue()) {
6619     CHECK_ALIVE(VisitForValue(expr->left()));
6620     ASSERT(current_block() != NULL);
6621 
6622     // We need an extra block to maintain edge-split form.
6623     HBasicBlock* empty_block = graph()->CreateBasicBlock();
6624     HBasicBlock* eval_right = graph()->CreateBasicBlock();
6625     unsigned test_id = expr->left()->test_id();
6626     ToBooleanStub::Types expected(oracle()->ToBooleanTypes(test_id));
6627     HBranch* test = is_logical_and
6628       ? new(zone()) HBranch(Top(), eval_right, empty_block, expected)
6629       : new(zone()) HBranch(Top(), empty_block, eval_right, expected);
6630     current_block()->Finish(test);
6631 
6632     set_current_block(eval_right);
6633     Drop(1);  // Value of the left subexpression.
6634     CHECK_BAILOUT(VisitForValue(expr->right()));
6635 
6636     HBasicBlock* join_block =
6637       CreateJoin(empty_block, current_block(), expr->id());
6638     set_current_block(join_block);
6639     return ast_context()->ReturnValue(Pop());
6640 
6641   } else {
6642     ASSERT(ast_context()->IsEffect());
6643     // In an effect context, we don't need the value of the left subexpression,
6644     // only its control flow and side effects.  We need an extra block to
6645     // maintain edge-split form.
6646     HBasicBlock* empty_block = graph()->CreateBasicBlock();
6647     HBasicBlock* right_block = graph()->CreateBasicBlock();
6648     if (is_logical_and) {
6649       CHECK_BAILOUT(VisitForControl(expr->left(), right_block, empty_block));
6650     } else {
6651       CHECK_BAILOUT(VisitForControl(expr->left(), empty_block, right_block));
6652     }
6653 
6654     // TODO(kmillikin): Find a way to fix this.  It's ugly that there are
6655     // actually two empty blocks (one here and one inserted by
6656     // TestContext::BuildBranch, and that they both have an HSimulate though the
6657     // second one is not a merge node, and that we really have no good AST ID to
6658     // put on that first HSimulate.
6659 
6660     if (empty_block->HasPredecessor()) {
6661       empty_block->SetJoinId(expr->id());
6662     } else {
6663       empty_block = NULL;
6664     }
6665 
6666     if (right_block->HasPredecessor()) {
6667       right_block->SetJoinId(expr->RightId());
6668       set_current_block(right_block);
6669       CHECK_BAILOUT(VisitForEffect(expr->right()));
6670       right_block = current_block();
6671     } else {
6672       right_block = NULL;
6673     }
6674 
6675     HBasicBlock* join_block =
6676       CreateJoin(empty_block, right_block, expr->id());
6677     set_current_block(join_block);
6678     // We did not materialize any value in the predecessor environments,
6679     // so there is no need to handle it here.
6680   }
6681 }
6682 
6683 
VisitArithmeticExpression(BinaryOperation * expr)6684 void HGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) {
6685   CHECK_ALIVE(VisitForValue(expr->left()));
6686   CHECK_ALIVE(VisitForValue(expr->right()));
6687   HValue* right = Pop();
6688   HValue* left = Pop();
6689   HInstruction* instr = BuildBinaryOperation(expr, left, right);
6690   instr->set_position(expr->position());
6691   return ast_context()->ReturnInstruction(instr, expr->id());
6692 }
6693 
6694 
TraceRepresentation(Token::Value op,TypeInfo info,HValue * value,Representation rep)6695 void HGraphBuilder::TraceRepresentation(Token::Value op,
6696                                         TypeInfo info,
6697                                         HValue* value,
6698                                         Representation rep) {
6699   if (!FLAG_trace_representation) return;
6700   // TODO(svenpanne) Under which circumstances are we actually not flexible?
6701   // At first glance, this looks a bit weird...
6702   bool flexible = value->CheckFlag(HValue::kFlexibleRepresentation);
6703   PrintF("Operation %s has type info %s, %schange representation assumption "
6704          "for %s (ID %d) from %s to %s\n",
6705          Token::Name(op),
6706          info.ToString(),
6707          flexible ? "" : " DO NOT ",
6708          value->Mnemonic(),
6709          graph_->GetMaximumValueID(),
6710          value->representation().Mnemonic(),
6711          rep.Mnemonic());
6712 }
6713 
6714 
ToRepresentation(TypeInfo info)6715 Representation HGraphBuilder::ToRepresentation(TypeInfo info) {
6716   if (info.IsSmi()) return Representation::Integer32();
6717   if (info.IsInteger32()) return Representation::Integer32();
6718   if (info.IsDouble()) return Representation::Double();
6719   if (info.IsNumber()) return Representation::Double();
6720   return Representation::Tagged();
6721 }
6722 
6723 
HandleLiteralCompareTypeof(CompareOperation * expr,HTypeof * typeof_expr,Handle<String> check)6724 void HGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr,
6725                                                HTypeof* typeof_expr,
6726                                                Handle<String> check) {
6727   // Note: The HTypeof itself is removed during canonicalization, if possible.
6728   HValue* value = typeof_expr->value();
6729   HTypeofIsAndBranch* instr = new(zone()) HTypeofIsAndBranch(value, check);
6730   instr->set_position(expr->position());
6731   return ast_context()->ReturnControl(instr, expr->id());
6732 }
6733 
6734 
MatchLiteralCompareNil(HValue * left,Token::Value op,HValue * right,Handle<Object> nil,HValue ** expr)6735 static bool MatchLiteralCompareNil(HValue* left,
6736                                    Token::Value op,
6737                                    HValue* right,
6738                                    Handle<Object> nil,
6739                                    HValue** expr) {
6740   if (left->IsConstant() &&
6741       HConstant::cast(left)->handle().is_identical_to(nil) &&
6742       Token::IsEqualityOp(op)) {
6743     *expr = right;
6744     return true;
6745   }
6746   return false;
6747 }
6748 
6749 
MatchLiteralCompareTypeof(HValue * left,Token::Value op,HValue * right,HTypeof ** typeof_expr,Handle<String> * check)6750 static bool MatchLiteralCompareTypeof(HValue* left,
6751                                       Token::Value op,
6752                                       HValue* right,
6753                                       HTypeof** typeof_expr,
6754                                       Handle<String>* check) {
6755   if (left->IsTypeof() &&
6756       Token::IsEqualityOp(op) &&
6757       right->IsConstant() &&
6758       HConstant::cast(right)->HasStringValue()) {
6759     *typeof_expr = HTypeof::cast(left);
6760     *check = Handle<String>::cast(HConstant::cast(right)->handle());
6761     return true;
6762   }
6763   return false;
6764 }
6765 
6766 
IsLiteralCompareTypeof(HValue * left,Token::Value op,HValue * right,HTypeof ** typeof_expr,Handle<String> * check)6767 static bool IsLiteralCompareTypeof(HValue* left,
6768                                    Token::Value op,
6769                                    HValue* right,
6770                                    HTypeof** typeof_expr,
6771                                    Handle<String>* check) {
6772   return MatchLiteralCompareTypeof(left, op, right, typeof_expr, check) ||
6773       MatchLiteralCompareTypeof(right, op, left, typeof_expr, check);
6774 }
6775 
6776 
IsLiteralCompareNil(HValue * left,Token::Value op,HValue * right,Handle<Object> nil,HValue ** expr)6777 static bool IsLiteralCompareNil(HValue* left,
6778                                 Token::Value op,
6779                                 HValue* right,
6780                                 Handle<Object> nil,
6781                                 HValue** expr) {
6782   return MatchLiteralCompareNil(left, op, right, nil, expr) ||
6783       MatchLiteralCompareNil(right, op, left, nil, expr);
6784 }
6785 
6786 
IsLiteralCompareBool(HValue * left,Token::Value op,HValue * right)6787 static bool IsLiteralCompareBool(HValue* left,
6788                                  Token::Value op,
6789                                  HValue* right) {
6790   return op == Token::EQ_STRICT &&
6791       ((left->IsConstant() && HConstant::cast(left)->handle()->IsBoolean()) ||
6792        (right->IsConstant() && HConstant::cast(right)->handle()->IsBoolean()));
6793 }
6794 
6795 
VisitCompareOperation(CompareOperation * expr)6796 void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
6797   ASSERT(!HasStackOverflow());
6798   ASSERT(current_block() != NULL);
6799   ASSERT(current_block()->HasPredecessor());
6800   if (IsClassOfTest(expr)) {
6801     CallRuntime* call = expr->left()->AsCallRuntime();
6802     ASSERT(call->arguments()->length() == 1);
6803     CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
6804     HValue* value = Pop();
6805     Literal* literal = expr->right()->AsLiteral();
6806     Handle<String> rhs = Handle<String>::cast(literal->handle());
6807     HClassOfTestAndBranch* instr =
6808         new(zone()) HClassOfTestAndBranch(value, rhs);
6809     instr->set_position(expr->position());
6810     return ast_context()->ReturnControl(instr, expr->id());
6811   }
6812 
6813   TypeInfo type_info = oracle()->CompareType(expr);
6814   // Check if this expression was ever executed according to type feedback.
6815   // Note that for the special typeof/null/undefined cases we get unknown here.
6816   if (type_info.IsUninitialized()) {
6817     AddInstruction(new(zone()) HSoftDeoptimize);
6818     current_block()->MarkAsDeoptimizing();
6819     type_info = TypeInfo::Unknown();
6820   }
6821 
6822   CHECK_ALIVE(VisitForValue(expr->left()));
6823   CHECK_ALIVE(VisitForValue(expr->right()));
6824 
6825   HValue* context = environment()->LookupContext();
6826   HValue* right = Pop();
6827   HValue* left = Pop();
6828   Token::Value op = expr->op();
6829 
6830   HTypeof* typeof_expr = NULL;
6831   Handle<String> check;
6832   if (IsLiteralCompareTypeof(left, op, right, &typeof_expr, &check)) {
6833     return HandleLiteralCompareTypeof(expr, typeof_expr, check);
6834   }
6835   HValue* sub_expr = NULL;
6836   Factory* f = graph()->isolate()->factory();
6837   if (IsLiteralCompareNil(left, op, right, f->undefined_value(), &sub_expr)) {
6838     return HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue);
6839   }
6840   if (IsLiteralCompareNil(left, op, right, f->null_value(), &sub_expr)) {
6841     return HandleLiteralCompareNil(expr, sub_expr, kNullValue);
6842   }
6843   if (IsLiteralCompareBool(left, op, right)) {
6844     HCompareObjectEqAndBranch* result =
6845         new(zone()) HCompareObjectEqAndBranch(left, right);
6846     result->set_position(expr->position());
6847     return ast_context()->ReturnControl(result, expr->id());
6848   }
6849 
6850   if (op == Token::INSTANCEOF) {
6851     // Check to see if the rhs of the instanceof is a global function not
6852     // residing in new space. If it is we assume that the function will stay the
6853     // same.
6854     Handle<JSFunction> target = Handle<JSFunction>::null();
6855     VariableProxy* proxy = expr->right()->AsVariableProxy();
6856     bool global_function = (proxy != NULL) && proxy->var()->IsUnallocated();
6857     if (global_function &&
6858         info()->has_global_object() &&
6859         !info()->global_object()->IsAccessCheckNeeded()) {
6860       Handle<String> name = proxy->name();
6861       Handle<GlobalObject> global(info()->global_object());
6862       LookupResult lookup(isolate());
6863       global->Lookup(*name, &lookup);
6864       if (lookup.IsFound() &&
6865           lookup.type() == NORMAL &&
6866           lookup.GetValue()->IsJSFunction()) {
6867         Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue()));
6868         // If the function is in new space we assume it's more likely to
6869         // change and thus prefer the general IC code.
6870         if (!isolate()->heap()->InNewSpace(*candidate)) {
6871           target = candidate;
6872         }
6873       }
6874     }
6875 
6876     // If the target is not null we have found a known global function that is
6877     // assumed to stay the same for this instanceof.
6878     if (target.is_null()) {
6879       HInstanceOf* result = new(zone()) HInstanceOf(context, left, right);
6880       result->set_position(expr->position());
6881       return ast_context()->ReturnInstruction(result, expr->id());
6882     } else {
6883       AddInstruction(new(zone()) HCheckFunction(right, target));
6884       HInstanceOfKnownGlobal* result =
6885           new(zone()) HInstanceOfKnownGlobal(context, left, target);
6886       result->set_position(expr->position());
6887       return ast_context()->ReturnInstruction(result, expr->id());
6888     }
6889   } else if (op == Token::IN) {
6890     HIn* result = new(zone()) HIn(context, left, right);
6891     result->set_position(expr->position());
6892     return ast_context()->ReturnInstruction(result, expr->id());
6893   } else if (type_info.IsNonPrimitive()) {
6894     switch (op) {
6895       case Token::EQ:
6896       case Token::EQ_STRICT: {
6897         // Can we get away with map check and not instance type check?
6898         Handle<Map> map = oracle()->GetCompareMap(expr);
6899         if (!map.is_null()) {
6900           AddInstruction(new(zone()) HCheckNonSmi(left));
6901           AddInstruction(new(zone()) HCheckMap(left, map, NULL,
6902                                                ALLOW_ELEMENT_TRANSITION_MAPS));
6903           AddInstruction(new(zone()) HCheckNonSmi(right));
6904           AddInstruction(new(zone()) HCheckMap(right, map, NULL,
6905                                                ALLOW_ELEMENT_TRANSITION_MAPS));
6906           HCompareObjectEqAndBranch* result =
6907               new(zone()) HCompareObjectEqAndBranch(left, right);
6908           result->set_position(expr->position());
6909           return ast_context()->ReturnControl(result, expr->id());
6910         } else {
6911           AddInstruction(new(zone()) HCheckNonSmi(left));
6912           AddInstruction(HCheckInstanceType::NewIsSpecObject(left));
6913           AddInstruction(new(zone()) HCheckNonSmi(right));
6914           AddInstruction(HCheckInstanceType::NewIsSpecObject(right));
6915           HCompareObjectEqAndBranch* result =
6916               new(zone()) HCompareObjectEqAndBranch(left, right);
6917           result->set_position(expr->position());
6918           return ast_context()->ReturnControl(result, expr->id());
6919         }
6920       }
6921       default:
6922         return Bailout("Unsupported non-primitive compare");
6923     }
6924   } else if (type_info.IsString() && oracle()->IsSymbolCompare(expr) &&
6925              (op == Token::EQ || op == Token::EQ_STRICT)) {
6926     AddInstruction(new(zone()) HCheckNonSmi(left));
6927     AddInstruction(HCheckInstanceType::NewIsSymbol(left));
6928     AddInstruction(new(zone()) HCheckNonSmi(right));
6929     AddInstruction(HCheckInstanceType::NewIsSymbol(right));
6930     HCompareObjectEqAndBranch* result =
6931         new(zone()) HCompareObjectEqAndBranch(left, right);
6932     result->set_position(expr->position());
6933     return ast_context()->ReturnControl(result, expr->id());
6934   } else {
6935     Representation r = ToRepresentation(type_info);
6936     if (r.IsTagged()) {
6937       HCompareGeneric* result =
6938           new(zone()) HCompareGeneric(context, left, right, op);
6939       result->set_position(expr->position());
6940       return ast_context()->ReturnInstruction(result, expr->id());
6941     } else {
6942       HCompareIDAndBranch* result =
6943           new(zone()) HCompareIDAndBranch(left, right, op);
6944       result->set_position(expr->position());
6945       result->SetInputRepresentation(r);
6946       return ast_context()->ReturnControl(result, expr->id());
6947     }
6948   }
6949 }
6950 
6951 
HandleLiteralCompareNil(CompareOperation * expr,HValue * value,NilValue nil)6952 void HGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
6953                                             HValue* value,
6954                                             NilValue nil) {
6955   ASSERT(!HasStackOverflow());
6956   ASSERT(current_block() != NULL);
6957   ASSERT(current_block()->HasPredecessor());
6958   EqualityKind kind =
6959       expr->op() == Token::EQ_STRICT ? kStrictEquality : kNonStrictEquality;
6960   HIsNilAndBranch* instr = new(zone()) HIsNilAndBranch(value, kind, nil);
6961   instr->set_position(expr->position());
6962   return ast_context()->ReturnControl(instr, expr->id());
6963 }
6964 
6965 
VisitThisFunction(ThisFunction * expr)6966 void HGraphBuilder::VisitThisFunction(ThisFunction* expr) {
6967   ASSERT(!HasStackOverflow());
6968   ASSERT(current_block() != NULL);
6969   ASSERT(current_block()->HasPredecessor());
6970   HThisFunction* self = new(zone()) HThisFunction(
6971       function_state()->compilation_info()->closure());
6972   return ast_context()->ReturnInstruction(self, expr->id());
6973 }
6974 
6975 
VisitDeclarations(ZoneList<Declaration * > * declarations)6976 void HGraphBuilder::VisitDeclarations(ZoneList<Declaration*>* declarations) {
6977   int length = declarations->length();
6978   int global_count = 0;
6979   for (int i = 0; i < declarations->length(); i++) {
6980     Declaration* decl = declarations->at(i);
6981     FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration();
6982     HandleDeclaration(decl->proxy(),
6983                       decl->mode(),
6984                       fun_decl != NULL ? fun_decl->fun() : NULL,
6985                       &global_count);
6986   }
6987 
6988   // Batch declare global functions and variables.
6989   if (global_count > 0) {
6990     Handle<FixedArray> array =
6991         isolate()->factory()->NewFixedArray(2 * global_count, TENURED);
6992     for (int j = 0, i = 0; i < length; i++) {
6993       Declaration* decl = declarations->at(i);
6994       Variable* var = decl->proxy()->var();
6995 
6996       if (var->IsUnallocated()) {
6997         array->set(j++, *(var->name()));
6998         FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration();
6999         if (fun_decl == NULL) {
7000           if (var->binding_needs_init()) {
7001             // In case this binding needs initialization use the hole.
7002             array->set_the_hole(j++);
7003           } else {
7004             array->set_undefined(j++);
7005           }
7006         } else {
7007           Handle<SharedFunctionInfo> function =
7008               Compiler::BuildFunctionInfo(fun_decl->fun(), info()->script());
7009           // Check for stack-overflow exception.
7010           if (function.is_null()) {
7011             SetStackOverflow();
7012             return;
7013           }
7014           array->set(j++, *function);
7015         }
7016       }
7017     }
7018     int flags = DeclareGlobalsEvalFlag::encode(info()->is_eval()) |
7019                 DeclareGlobalsNativeFlag::encode(info()->is_native()) |
7020                 DeclareGlobalsLanguageMode::encode(info()->language_mode());
7021     HInstruction* result =
7022         new(zone()) HDeclareGlobals(environment()->LookupContext(),
7023                                     array,
7024                                     flags);
7025     AddInstruction(result);
7026   }
7027 }
7028 
7029 
HandleDeclaration(VariableProxy * proxy,VariableMode mode,FunctionLiteral * function,int * global_count)7030 void HGraphBuilder::HandleDeclaration(VariableProxy* proxy,
7031                                       VariableMode mode,
7032                                       FunctionLiteral* function,
7033                                       int* global_count) {
7034   Variable* var = proxy->var();
7035   bool binding_needs_init =
7036       (mode == CONST || mode == CONST_HARMONY || mode == LET);
7037   switch (var->location()) {
7038     case Variable::UNALLOCATED:
7039       ++(*global_count);
7040       return;
7041     case Variable::PARAMETER:
7042     case Variable::LOCAL:
7043     case Variable::CONTEXT:
7044       if (binding_needs_init || function != NULL) {
7045         HValue* value = NULL;
7046         if (function != NULL) {
7047           CHECK_ALIVE(VisitForValue(function));
7048           value = Pop();
7049         } else {
7050           value = graph()->GetConstantHole();
7051         }
7052         if (var->IsContextSlot()) {
7053           HValue* context = environment()->LookupContext();
7054           HStoreContextSlot* store = new HStoreContextSlot(
7055               context, var->index(), HStoreContextSlot::kNoCheck, value);
7056           AddInstruction(store);
7057           if (store->HasObservableSideEffects()) AddSimulate(proxy->id());
7058         } else {
7059           environment()->Bind(var, value);
7060         }
7061       }
7062       break;
7063     case Variable::LOOKUP:
7064       return Bailout("unsupported lookup slot in declaration");
7065   }
7066 }
7067 
7068 
VisitVariableDeclaration(VariableDeclaration * decl)7069 void HGraphBuilder::VisitVariableDeclaration(VariableDeclaration* decl) {
7070   UNREACHABLE();
7071 }
7072 
7073 
VisitFunctionDeclaration(FunctionDeclaration * decl)7074 void HGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* decl) {
7075   UNREACHABLE();
7076 }
7077 
7078 
VisitModuleDeclaration(ModuleDeclaration * decl)7079 void HGraphBuilder::VisitModuleDeclaration(ModuleDeclaration* decl) {
7080   UNREACHABLE();
7081 }
7082 
7083 
VisitImportDeclaration(ImportDeclaration * decl)7084 void HGraphBuilder::VisitImportDeclaration(ImportDeclaration* decl) {
7085   UNREACHABLE();
7086 }
7087 
7088 
VisitExportDeclaration(ExportDeclaration * decl)7089 void HGraphBuilder::VisitExportDeclaration(ExportDeclaration* decl) {
7090   UNREACHABLE();
7091 }
7092 
7093 
VisitModuleLiteral(ModuleLiteral * module)7094 void HGraphBuilder::VisitModuleLiteral(ModuleLiteral* module) {
7095   // TODO(rossberg)
7096 }
7097 
7098 
VisitModuleVariable(ModuleVariable * module)7099 void HGraphBuilder::VisitModuleVariable(ModuleVariable* module) {
7100   // TODO(rossberg)
7101 }
7102 
7103 
VisitModulePath(ModulePath * module)7104 void HGraphBuilder::VisitModulePath(ModulePath* module) {
7105   // TODO(rossberg)
7106 }
7107 
7108 
VisitModuleUrl(ModuleUrl * module)7109 void HGraphBuilder::VisitModuleUrl(ModuleUrl* module) {
7110   // TODO(rossberg)
7111 }
7112 
7113 
7114 // Generators for inline runtime functions.
7115 // Support for types.
GenerateIsSmi(CallRuntime * call)7116 void HGraphBuilder::GenerateIsSmi(CallRuntime* call) {
7117   ASSERT(call->arguments()->length() == 1);
7118   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
7119   HValue* value = Pop();
7120   HIsSmiAndBranch* result = new(zone()) HIsSmiAndBranch(value);
7121   return ast_context()->ReturnControl(result, call->id());
7122 }
7123 
7124 
GenerateIsSpecObject(CallRuntime * call)7125 void HGraphBuilder::GenerateIsSpecObject(CallRuntime* call) {
7126   ASSERT(call->arguments()->length() == 1);
7127   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
7128   HValue* value = Pop();
7129   HHasInstanceTypeAndBranch* result =
7130       new(zone()) HHasInstanceTypeAndBranch(value,
7131                                             FIRST_SPEC_OBJECT_TYPE,
7132                                             LAST_SPEC_OBJECT_TYPE);
7133   return ast_context()->ReturnControl(result, call->id());
7134 }
7135 
7136 
GenerateIsFunction(CallRuntime * call)7137 void HGraphBuilder::GenerateIsFunction(CallRuntime* call) {
7138   ASSERT(call->arguments()->length() == 1);
7139   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
7140   HValue* value = Pop();
7141   HHasInstanceTypeAndBranch* result =
7142       new(zone()) HHasInstanceTypeAndBranch(value, JS_FUNCTION_TYPE);
7143   return ast_context()->ReturnControl(result, call->id());
7144 }
7145 
7146 
GenerateHasCachedArrayIndex(CallRuntime * call)7147 void HGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) {
7148   ASSERT(call->arguments()->length() == 1);
7149   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
7150   HValue* value = Pop();
7151   HHasCachedArrayIndexAndBranch* result =
7152       new(zone()) HHasCachedArrayIndexAndBranch(value);
7153   return ast_context()->ReturnControl(result, call->id());
7154 }
7155 
7156 
GenerateIsArray(CallRuntime * call)7157 void HGraphBuilder::GenerateIsArray(CallRuntime* call) {
7158   ASSERT(call->arguments()->length() == 1);
7159   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
7160   HValue* value = Pop();
7161   HHasInstanceTypeAndBranch* result =
7162       new(zone()) HHasInstanceTypeAndBranch(value, JS_ARRAY_TYPE);
7163   return ast_context()->ReturnControl(result, call->id());
7164 }
7165 
7166 
GenerateIsRegExp(CallRuntime * call)7167 void HGraphBuilder::GenerateIsRegExp(CallRuntime* call) {
7168   ASSERT(call->arguments()->length() == 1);
7169   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
7170   HValue* value = Pop();
7171   HHasInstanceTypeAndBranch* result =
7172       new(zone()) HHasInstanceTypeAndBranch(value, JS_REGEXP_TYPE);
7173   return ast_context()->ReturnControl(result, call->id());
7174 }
7175 
7176 
GenerateIsObject(CallRuntime * call)7177 void HGraphBuilder::GenerateIsObject(CallRuntime* call) {
7178   ASSERT(call->arguments()->length() == 1);
7179   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
7180   HValue* value = Pop();
7181   HIsObjectAndBranch* result = new(zone()) HIsObjectAndBranch(value);
7182   return ast_context()->ReturnControl(result, call->id());
7183 }
7184 
7185 
GenerateIsNonNegativeSmi(CallRuntime * call)7186 void HGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) {
7187   return Bailout("inlined runtime function: IsNonNegativeSmi");
7188 }
7189 
7190 
GenerateIsUndetectableObject(CallRuntime * call)7191 void HGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) {
7192   ASSERT(call->arguments()->length() == 1);
7193   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
7194   HValue* value = Pop();
7195   HIsUndetectableAndBranch* result =
7196       new(zone()) HIsUndetectableAndBranch(value);
7197   return ast_context()->ReturnControl(result, call->id());
7198 }
7199 
7200 
GenerateIsStringWrapperSafeForDefaultValueOf(CallRuntime * call)7201 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf(
7202     CallRuntime* call) {
7203   return Bailout(
7204       "inlined runtime function: IsStringWrapperSafeForDefaultValueOf");
7205 }
7206 
7207 
7208 // Support for construct call checks.
GenerateIsConstructCall(CallRuntime * call)7209 void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) {
7210   ASSERT(call->arguments()->length() == 0);
7211   if (function_state()->outer() != NULL) {
7212     // We are generating graph for inlined function.
7213     HValue* value = function_state()->is_construct()
7214         ? graph()->GetConstantTrue()
7215         : graph()->GetConstantFalse();
7216     return ast_context()->ReturnValue(value);
7217   } else {
7218     return ast_context()->ReturnControl(new(zone()) HIsConstructCallAndBranch,
7219                                         call->id());
7220   }
7221 }
7222 
7223 
7224 // Support for arguments.length and arguments[?].
GenerateArgumentsLength(CallRuntime * call)7225 void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) {
7226   // Our implementation of arguments (based on this stack frame or an
7227   // adapter below it) does not work for inlined functions.  This runtime
7228   // function is blacklisted by AstNode::IsInlineable.
7229   ASSERT(function_state()->outer() == NULL);
7230   ASSERT(call->arguments()->length() == 0);
7231   HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
7232   HArgumentsLength* result = new(zone()) HArgumentsLength(elements);
7233   return ast_context()->ReturnInstruction(result, call->id());
7234 }
7235 
7236 
GenerateArguments(CallRuntime * call)7237 void HGraphBuilder::GenerateArguments(CallRuntime* call) {
7238   // Our implementation of arguments (based on this stack frame or an
7239   // adapter below it) does not work for inlined functions.  This runtime
7240   // function is blacklisted by AstNode::IsInlineable.
7241   ASSERT(function_state()->outer() == NULL);
7242   ASSERT(call->arguments()->length() == 1);
7243   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
7244   HValue* index = Pop();
7245   HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
7246   HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements));
7247   HAccessArgumentsAt* result =
7248       new(zone()) HAccessArgumentsAt(elements, length, index);
7249   return ast_context()->ReturnInstruction(result, call->id());
7250 }
7251 
7252 
7253 // Support for accessing the class and value fields of an object.
GenerateClassOf(CallRuntime * call)7254 void HGraphBuilder::GenerateClassOf(CallRuntime* call) {
7255   // The special form detected by IsClassOfTest is detected before we get here
7256   // and does not cause a bailout.
7257   return Bailout("inlined runtime function: ClassOf");
7258 }
7259 
7260 
GenerateValueOf(CallRuntime * call)7261 void HGraphBuilder::GenerateValueOf(CallRuntime* call) {
7262   ASSERT(call->arguments()->length() == 1);
7263   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
7264   HValue* value = Pop();
7265   HValueOf* result = new(zone()) HValueOf(value);
7266   return ast_context()->ReturnInstruction(result, call->id());
7267 }
7268 
7269 
GenerateDateField(CallRuntime * call)7270 void HGraphBuilder::GenerateDateField(CallRuntime* call) {
7271   ASSERT(call->arguments()->length() == 2);
7272   ASSERT_NE(NULL, call->arguments()->at(1)->AsLiteral());
7273   Smi* index = Smi::cast(*(call->arguments()->at(1)->AsLiteral()->handle()));
7274   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
7275   HValue* date = Pop();
7276   HDateField* result = new(zone()) HDateField(date, index);
7277   return ast_context()->ReturnInstruction(result, call->id());
7278 }
7279 
7280 
GenerateSetValueOf(CallRuntime * call)7281 void HGraphBuilder::GenerateSetValueOf(CallRuntime* call) {
7282   ASSERT(call->arguments()->length() == 2);
7283   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
7284   CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
7285   HValue* value = Pop();
7286   HValue* object = Pop();
7287   // Check if object is a not a smi.
7288   HIsSmiAndBranch* smicheck = new(zone()) HIsSmiAndBranch(object);
7289   HBasicBlock* if_smi = graph()->CreateBasicBlock();
7290   HBasicBlock* if_heap_object = graph()->CreateBasicBlock();
7291   HBasicBlock* join = graph()->CreateBasicBlock();
7292   smicheck->SetSuccessorAt(0, if_smi);
7293   smicheck->SetSuccessorAt(1, if_heap_object);
7294   current_block()->Finish(smicheck);
7295   if_smi->Goto(join);
7296 
7297   // Check if object is a JSValue.
7298   set_current_block(if_heap_object);
7299   HHasInstanceTypeAndBranch* typecheck =
7300       new(zone()) HHasInstanceTypeAndBranch(object, JS_VALUE_TYPE);
7301   HBasicBlock* if_js_value = graph()->CreateBasicBlock();
7302   HBasicBlock* not_js_value = graph()->CreateBasicBlock();
7303   typecheck->SetSuccessorAt(0, if_js_value);
7304   typecheck->SetSuccessorAt(1, not_js_value);
7305   current_block()->Finish(typecheck);
7306   not_js_value->Goto(join);
7307 
7308   // Create in-object property store to kValueOffset.
7309   set_current_block(if_js_value);
7310   Handle<String> name = isolate()->factory()->undefined_symbol();
7311   AddInstruction(new HStoreNamedField(object,
7312                                       name,
7313                                       value,
7314                                       true,  // in-object store.
7315                                       JSValue::kValueOffset));
7316   if_js_value->Goto(join);
7317   join->SetJoinId(call->id());
7318   set_current_block(join);
7319   return ast_context()->ReturnValue(value);
7320 }
7321 
7322 
7323 // Fast support for charCodeAt(n).
GenerateStringCharCodeAt(CallRuntime * call)7324 void HGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) {
7325   ASSERT(call->arguments()->length() == 2);
7326   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
7327   CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
7328   HValue* index = Pop();
7329   HValue* string = Pop();
7330   HValue* context = environment()->LookupContext();
7331   HStringCharCodeAt* result = BuildStringCharCodeAt(context, string, index);
7332   return ast_context()->ReturnInstruction(result, call->id());
7333 }
7334 
7335 
7336 // Fast support for string.charAt(n) and string[n].
GenerateStringCharFromCode(CallRuntime * call)7337 void HGraphBuilder::GenerateStringCharFromCode(CallRuntime* call) {
7338   ASSERT(call->arguments()->length() == 1);
7339   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
7340   HValue* char_code = Pop();
7341   HValue* context = environment()->LookupContext();
7342   HStringCharFromCode* result =
7343       new(zone()) HStringCharFromCode(context, char_code);
7344   return ast_context()->ReturnInstruction(result, call->id());
7345 }
7346 
7347 
7348 // Fast support for string.charAt(n) and string[n].
GenerateStringCharAt(CallRuntime * call)7349 void HGraphBuilder::GenerateStringCharAt(CallRuntime* call) {
7350   ASSERT(call->arguments()->length() == 2);
7351   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
7352   CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
7353   HValue* index = Pop();
7354   HValue* string = Pop();
7355   HValue* context = environment()->LookupContext();
7356   HStringCharCodeAt* char_code = BuildStringCharCodeAt(context, string, index);
7357   AddInstruction(char_code);
7358   HStringCharFromCode* result =
7359       new(zone()) HStringCharFromCode(context, char_code);
7360   return ast_context()->ReturnInstruction(result, call->id());
7361 }
7362 
7363 
7364 // Fast support for object equality testing.
GenerateObjectEquals(CallRuntime * call)7365 void HGraphBuilder::GenerateObjectEquals(CallRuntime* call) {
7366   ASSERT(call->arguments()->length() == 2);
7367   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
7368   CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
7369   HValue* right = Pop();
7370   HValue* left = Pop();
7371   HCompareObjectEqAndBranch* result =
7372       new(zone()) HCompareObjectEqAndBranch(left, right);
7373   return ast_context()->ReturnControl(result, call->id());
7374 }
7375 
7376 
GenerateLog(CallRuntime * call)7377 void HGraphBuilder::GenerateLog(CallRuntime* call) {
7378   // %_Log is ignored in optimized code.
7379   return ast_context()->ReturnValue(graph()->GetConstantUndefined());
7380 }
7381 
7382 
7383 // Fast support for Math.random().
GenerateRandomHeapNumber(CallRuntime * call)7384 void HGraphBuilder::GenerateRandomHeapNumber(CallRuntime* call) {
7385   HValue* context = environment()->LookupContext();
7386   HGlobalObject* global_object = new(zone()) HGlobalObject(context);
7387   AddInstruction(global_object);
7388   HRandom* result = new(zone()) HRandom(global_object);
7389   return ast_context()->ReturnInstruction(result, call->id());
7390 }
7391 
7392 
7393 // Fast support for StringAdd.
GenerateStringAdd(CallRuntime * call)7394 void HGraphBuilder::GenerateStringAdd(CallRuntime* call) {
7395   ASSERT_EQ(2, call->arguments()->length());
7396   CHECK_ALIVE(VisitArgumentList(call->arguments()));
7397   HValue* context = environment()->LookupContext();
7398   HCallStub* result = new(zone()) HCallStub(context, CodeStub::StringAdd, 2);
7399   Drop(2);
7400   return ast_context()->ReturnInstruction(result, call->id());
7401 }
7402 
7403 
7404 // Fast support for SubString.
GenerateSubString(CallRuntime * call)7405 void HGraphBuilder::GenerateSubString(CallRuntime* call) {
7406   ASSERT_EQ(3, call->arguments()->length());
7407   CHECK_ALIVE(VisitArgumentList(call->arguments()));
7408   HValue* context = environment()->LookupContext();
7409   HCallStub* result = new(zone()) HCallStub(context, CodeStub::SubString, 3);
7410   Drop(3);
7411   return ast_context()->ReturnInstruction(result, call->id());
7412 }
7413 
7414 
7415 // Fast support for StringCompare.
GenerateStringCompare(CallRuntime * call)7416 void HGraphBuilder::GenerateStringCompare(CallRuntime* call) {
7417   ASSERT_EQ(2, call->arguments()->length());
7418   CHECK_ALIVE(VisitArgumentList(call->arguments()));
7419   HValue* context = environment()->LookupContext();
7420   HCallStub* result =
7421       new(zone()) HCallStub(context, CodeStub::StringCompare, 2);
7422   Drop(2);
7423   return ast_context()->ReturnInstruction(result, call->id());
7424 }
7425 
7426 
7427 // Support for direct calls from JavaScript to native RegExp code.
GenerateRegExpExec(CallRuntime * call)7428 void HGraphBuilder::GenerateRegExpExec(CallRuntime* call) {
7429   ASSERT_EQ(4, call->arguments()->length());
7430   CHECK_ALIVE(VisitArgumentList(call->arguments()));
7431   HValue* context = environment()->LookupContext();
7432   HCallStub* result = new(zone()) HCallStub(context, CodeStub::RegExpExec, 4);
7433   Drop(4);
7434   return ast_context()->ReturnInstruction(result, call->id());
7435 }
7436 
7437 
7438 // Construct a RegExp exec result with two in-object properties.
GenerateRegExpConstructResult(CallRuntime * call)7439 void HGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) {
7440   ASSERT_EQ(3, call->arguments()->length());
7441   CHECK_ALIVE(VisitArgumentList(call->arguments()));
7442   HValue* context = environment()->LookupContext();
7443   HCallStub* result =
7444       new(zone()) HCallStub(context, CodeStub::RegExpConstructResult, 3);
7445   Drop(3);
7446   return ast_context()->ReturnInstruction(result, call->id());
7447 }
7448 
7449 
7450 // Support for fast native caches.
GenerateGetFromCache(CallRuntime * call)7451 void HGraphBuilder::GenerateGetFromCache(CallRuntime* call) {
7452   return Bailout("inlined runtime function: GetFromCache");
7453 }
7454 
7455 
7456 // Fast support for number to string.
GenerateNumberToString(CallRuntime * call)7457 void HGraphBuilder::GenerateNumberToString(CallRuntime* call) {
7458   ASSERT_EQ(1, call->arguments()->length());
7459   CHECK_ALIVE(VisitArgumentList(call->arguments()));
7460   HValue* context = environment()->LookupContext();
7461   HCallStub* result =
7462       new(zone()) HCallStub(context, CodeStub::NumberToString, 1);
7463   Drop(1);
7464   return ast_context()->ReturnInstruction(result, call->id());
7465 }
7466 
7467 
7468 // Fast call for custom callbacks.
GenerateCallFunction(CallRuntime * call)7469 void HGraphBuilder::GenerateCallFunction(CallRuntime* call) {
7470   // 1 ~ The function to call is not itself an argument to the call.
7471   int arg_count = call->arguments()->length() - 1;
7472   ASSERT(arg_count >= 1);  // There's always at least a receiver.
7473 
7474   for (int i = 0; i < arg_count; ++i) {
7475     CHECK_ALIVE(VisitArgument(call->arguments()->at(i)));
7476   }
7477   CHECK_ALIVE(VisitForValue(call->arguments()->last()));
7478 
7479   HValue* function = Pop();
7480   HValue* context = environment()->LookupContext();
7481 
7482   // Branch for function proxies, or other non-functions.
7483   HHasInstanceTypeAndBranch* typecheck =
7484       new(zone()) HHasInstanceTypeAndBranch(function, JS_FUNCTION_TYPE);
7485   HBasicBlock* if_jsfunction = graph()->CreateBasicBlock();
7486   HBasicBlock* if_nonfunction = graph()->CreateBasicBlock();
7487   HBasicBlock* join = graph()->CreateBasicBlock();
7488   typecheck->SetSuccessorAt(0, if_jsfunction);
7489   typecheck->SetSuccessorAt(1, if_nonfunction);
7490   current_block()->Finish(typecheck);
7491 
7492   set_current_block(if_jsfunction);
7493   HInstruction* invoke_result = AddInstruction(
7494       new(zone()) HInvokeFunction(context, function, arg_count));
7495   Drop(arg_count);
7496   Push(invoke_result);
7497   if_jsfunction->Goto(join);
7498 
7499   set_current_block(if_nonfunction);
7500   HInstruction* call_result = AddInstruction(
7501       new(zone()) HCallFunction(context, function, arg_count));
7502   Drop(arg_count);
7503   Push(call_result);
7504   if_nonfunction->Goto(join);
7505 
7506   set_current_block(join);
7507   join->SetJoinId(call->id());
7508   return ast_context()->ReturnValue(Pop());
7509 }
7510 
7511 
7512 // Fast call to math functions.
GenerateMathPow(CallRuntime * call)7513 void HGraphBuilder::GenerateMathPow(CallRuntime* call) {
7514   ASSERT_EQ(2, call->arguments()->length());
7515   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
7516   CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
7517   HValue* right = Pop();
7518   HValue* left = Pop();
7519   HPower* result = new(zone()) HPower(left, right);
7520   return ast_context()->ReturnInstruction(result, call->id());
7521 }
7522 
7523 
GenerateMathSin(CallRuntime * call)7524 void HGraphBuilder::GenerateMathSin(CallRuntime* call) {
7525   ASSERT_EQ(1, call->arguments()->length());
7526   CHECK_ALIVE(VisitArgumentList(call->arguments()));
7527   HValue* context = environment()->LookupContext();
7528   HCallStub* result =
7529       new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
7530   result->set_transcendental_type(TranscendentalCache::SIN);
7531   Drop(1);
7532   return ast_context()->ReturnInstruction(result, call->id());
7533 }
7534 
7535 
GenerateMathCos(CallRuntime * call)7536 void HGraphBuilder::GenerateMathCos(CallRuntime* call) {
7537   ASSERT_EQ(1, call->arguments()->length());
7538   CHECK_ALIVE(VisitArgumentList(call->arguments()));
7539   HValue* context = environment()->LookupContext();
7540   HCallStub* result =
7541       new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
7542   result->set_transcendental_type(TranscendentalCache::COS);
7543   Drop(1);
7544   return ast_context()->ReturnInstruction(result, call->id());
7545 }
7546 
7547 
GenerateMathTan(CallRuntime * call)7548 void HGraphBuilder::GenerateMathTan(CallRuntime* call) {
7549   ASSERT_EQ(1, call->arguments()->length());
7550   CHECK_ALIVE(VisitArgumentList(call->arguments()));
7551   HValue* context = environment()->LookupContext();
7552   HCallStub* result =
7553       new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
7554   result->set_transcendental_type(TranscendentalCache::TAN);
7555   Drop(1);
7556   return ast_context()->ReturnInstruction(result, call->id());
7557 }
7558 
7559 
GenerateMathLog(CallRuntime * call)7560 void HGraphBuilder::GenerateMathLog(CallRuntime* call) {
7561   ASSERT_EQ(1, call->arguments()->length());
7562   CHECK_ALIVE(VisitArgumentList(call->arguments()));
7563   HValue* context = environment()->LookupContext();
7564   HCallStub* result =
7565       new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
7566   result->set_transcendental_type(TranscendentalCache::LOG);
7567   Drop(1);
7568   return ast_context()->ReturnInstruction(result, call->id());
7569 }
7570 
7571 
GenerateMathSqrt(CallRuntime * call)7572 void HGraphBuilder::GenerateMathSqrt(CallRuntime* call) {
7573   return Bailout("inlined runtime function: MathSqrt");
7574 }
7575 
7576 
7577 // Check whether two RegExps are equivalent
GenerateIsRegExpEquivalent(CallRuntime * call)7578 void HGraphBuilder::GenerateIsRegExpEquivalent(CallRuntime* call) {
7579   return Bailout("inlined runtime function: IsRegExpEquivalent");
7580 }
7581 
7582 
GenerateGetCachedArrayIndex(CallRuntime * call)7583 void HGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) {
7584   ASSERT(call->arguments()->length() == 1);
7585   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
7586   HValue* value = Pop();
7587   HGetCachedArrayIndex* result = new(zone()) HGetCachedArrayIndex(value);
7588   return ast_context()->ReturnInstruction(result, call->id());
7589 }
7590 
7591 
GenerateFastAsciiArrayJoin(CallRuntime * call)7592 void HGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) {
7593   return Bailout("inlined runtime function: FastAsciiArrayJoin");
7594 }
7595 
7596 
7597 #undef CHECK_BAILOUT
7598 #undef CHECK_ALIVE
7599 
7600 
HEnvironment(HEnvironment * outer,Scope * scope,Handle<JSFunction> closure)7601 HEnvironment::HEnvironment(HEnvironment* outer,
7602                            Scope* scope,
7603                            Handle<JSFunction> closure)
7604     : closure_(closure),
7605       values_(0),
7606       assigned_variables_(4),
7607       frame_type_(JS_FUNCTION),
7608       parameter_count_(0),
7609       specials_count_(1),
7610       local_count_(0),
7611       outer_(outer),
7612       pop_count_(0),
7613       push_count_(0),
7614       ast_id_(AstNode::kNoNumber) {
7615   Initialize(scope->num_parameters() + 1, scope->num_stack_slots(), 0);
7616 }
7617 
7618 
HEnvironment(const HEnvironment * other)7619 HEnvironment::HEnvironment(const HEnvironment* other)
7620     : values_(0),
7621       assigned_variables_(0),
7622       frame_type_(JS_FUNCTION),
7623       parameter_count_(0),
7624       specials_count_(1),
7625       local_count_(0),
7626       outer_(NULL),
7627       pop_count_(0),
7628       push_count_(0),
7629       ast_id_(other->ast_id()) {
7630   Initialize(other);
7631 }
7632 
7633 
HEnvironment(HEnvironment * outer,Handle<JSFunction> closure,FrameType frame_type,int arguments)7634 HEnvironment::HEnvironment(HEnvironment* outer,
7635                            Handle<JSFunction> closure,
7636                            FrameType frame_type,
7637                            int arguments)
7638     : closure_(closure),
7639       values_(arguments),
7640       assigned_variables_(0),
7641       frame_type_(frame_type),
7642       parameter_count_(arguments),
7643       local_count_(0),
7644       outer_(outer),
7645       pop_count_(0),
7646       push_count_(0),
7647       ast_id_(AstNode::kNoNumber) {
7648 }
7649 
7650 
Initialize(int parameter_count,int local_count,int stack_height)7651 void HEnvironment::Initialize(int parameter_count,
7652                               int local_count,
7653                               int stack_height) {
7654   parameter_count_ = parameter_count;
7655   local_count_ = local_count;
7656 
7657   // Avoid reallocating the temporaries' backing store on the first Push.
7658   int total = parameter_count + specials_count_ + local_count + stack_height;
7659   values_.Initialize(total + 4);
7660   for (int i = 0; i < total; ++i) values_.Add(NULL);
7661 }
7662 
7663 
Initialize(const HEnvironment * other)7664 void HEnvironment::Initialize(const HEnvironment* other) {
7665   closure_ = other->closure();
7666   values_.AddAll(other->values_);
7667   assigned_variables_.AddAll(other->assigned_variables_);
7668   frame_type_ = other->frame_type_;
7669   parameter_count_ = other->parameter_count_;
7670   local_count_ = other->local_count_;
7671   if (other->outer_ != NULL) outer_ = other->outer_->Copy();  // Deep copy.
7672   pop_count_ = other->pop_count_;
7673   push_count_ = other->push_count_;
7674   ast_id_ = other->ast_id_;
7675 }
7676 
7677 
AddIncomingEdge(HBasicBlock * block,HEnvironment * other)7678 void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) {
7679   ASSERT(!block->IsLoopHeader());
7680   ASSERT(values_.length() == other->values_.length());
7681 
7682   int length = values_.length();
7683   for (int i = 0; i < length; ++i) {
7684     HValue* value = values_[i];
7685     if (value != NULL && value->IsPhi() && value->block() == block) {
7686       // There is already a phi for the i'th value.
7687       HPhi* phi = HPhi::cast(value);
7688       // Assert index is correct and that we haven't missed an incoming edge.
7689       ASSERT(phi->merged_index() == i);
7690       ASSERT(phi->OperandCount() == block->predecessors()->length());
7691       phi->AddInput(other->values_[i]);
7692     } else if (values_[i] != other->values_[i]) {
7693       // There is a fresh value on the incoming edge, a phi is needed.
7694       ASSERT(values_[i] != NULL && other->values_[i] != NULL);
7695       HPhi* phi = new(block->zone()) HPhi(i);
7696       HValue* old_value = values_[i];
7697       for (int j = 0; j < block->predecessors()->length(); j++) {
7698         phi->AddInput(old_value);
7699       }
7700       phi->AddInput(other->values_[i]);
7701       this->values_[i] = phi;
7702       block->AddPhi(phi);
7703     }
7704   }
7705 }
7706 
7707 
Bind(int index,HValue * value)7708 void HEnvironment::Bind(int index, HValue* value) {
7709   ASSERT(value != NULL);
7710   if (!assigned_variables_.Contains(index)) {
7711     assigned_variables_.Add(index);
7712   }
7713   values_[index] = value;
7714 }
7715 
7716 
HasExpressionAt(int index) const7717 bool HEnvironment::HasExpressionAt(int index) const {
7718   return index >= parameter_count_ + specials_count_ + local_count_;
7719 }
7720 
7721 
ExpressionStackIsEmpty() const7722 bool HEnvironment::ExpressionStackIsEmpty() const {
7723   ASSERT(length() >= first_expression_index());
7724   return length() == first_expression_index();
7725 }
7726 
7727 
SetExpressionStackAt(int index_from_top,HValue * value)7728 void HEnvironment::SetExpressionStackAt(int index_from_top, HValue* value) {
7729   int count = index_from_top + 1;
7730   int index = values_.length() - count;
7731   ASSERT(HasExpressionAt(index));
7732   // The push count must include at least the element in question or else
7733   // the new value will not be included in this environment's history.
7734   if (push_count_ < count) {
7735     // This is the same effect as popping then re-pushing 'count' elements.
7736     pop_count_ += (count - push_count_);
7737     push_count_ = count;
7738   }
7739   values_[index] = value;
7740 }
7741 
7742 
Drop(int count)7743 void HEnvironment::Drop(int count) {
7744   for (int i = 0; i < count; ++i) {
7745     Pop();
7746   }
7747 }
7748 
7749 
Copy() const7750 HEnvironment* HEnvironment::Copy() const {
7751   return new(closure()->GetIsolate()->zone()) HEnvironment(this);
7752 }
7753 
7754 
CopyWithoutHistory() const7755 HEnvironment* HEnvironment::CopyWithoutHistory() const {
7756   HEnvironment* result = Copy();
7757   result->ClearHistory();
7758   return result;
7759 }
7760 
7761 
CopyAsLoopHeader(HBasicBlock * loop_header) const7762 HEnvironment* HEnvironment::CopyAsLoopHeader(HBasicBlock* loop_header) const {
7763   HEnvironment* new_env = Copy();
7764   for (int i = 0; i < values_.length(); ++i) {
7765     HPhi* phi = new(loop_header->zone()) HPhi(i);
7766     phi->AddInput(values_[i]);
7767     new_env->values_[i] = phi;
7768     loop_header->AddPhi(phi);
7769   }
7770   new_env->ClearHistory();
7771   return new_env;
7772 }
7773 
7774 
CreateStubEnvironment(HEnvironment * outer,Handle<JSFunction> target,FrameType frame_type,int arguments) const7775 HEnvironment* HEnvironment::CreateStubEnvironment(HEnvironment* outer,
7776                                                   Handle<JSFunction> target,
7777                                                   FrameType frame_type,
7778                                                   int arguments) const {
7779   HEnvironment* new_env = new(closure()->GetIsolate()->zone())
7780       HEnvironment(outer, target, frame_type, arguments + 1);
7781   for (int i = 0; i <= arguments; ++i) {  // Include receiver.
7782     new_env->Push(ExpressionStackAt(arguments - i));
7783   }
7784   new_env->ClearHistory();
7785   return new_env;
7786 }
7787 
7788 
CopyForInlining(Handle<JSFunction> target,int arguments,FunctionLiteral * function,HConstant * undefined,CallKind call_kind,bool is_construct) const7789 HEnvironment* HEnvironment::CopyForInlining(
7790     Handle<JSFunction> target,
7791     int arguments,
7792     FunctionLiteral* function,
7793     HConstant* undefined,
7794     CallKind call_kind,
7795     bool is_construct) const {
7796   ASSERT(frame_type() == JS_FUNCTION);
7797 
7798   Zone* zone = closure()->GetIsolate()->zone();
7799 
7800   // Outer environment is a copy of this one without the arguments.
7801   int arity = function->scope()->num_parameters();
7802 
7803   HEnvironment* outer = Copy();
7804   outer->Drop(arguments + 1);  // Including receiver.
7805   outer->ClearHistory();
7806 
7807   if (is_construct) {
7808     // Create artificial constructor stub environment.  The receiver should
7809     // actually be the constructor function, but we pass the newly allocated
7810     // object instead, DoComputeConstructStubFrame() relies on that.
7811     outer = CreateStubEnvironment(outer, target, JS_CONSTRUCT, arguments);
7812   }
7813 
7814   if (arity != arguments) {
7815     // Create artificial arguments adaptation environment.
7816     outer = CreateStubEnvironment(outer, target, ARGUMENTS_ADAPTOR, arguments);
7817   }
7818 
7819   HEnvironment* inner =
7820       new(zone) HEnvironment(outer, function->scope(), target);
7821   // Get the argument values from the original environment.
7822   for (int i = 0; i <= arity; ++i) {  // Include receiver.
7823     HValue* push = (i <= arguments) ?
7824         ExpressionStackAt(arguments - i) : undefined;
7825     inner->SetValueAt(i, push);
7826   }
7827   // If the function we are inlining is a strict mode function or a
7828   // builtin function, pass undefined as the receiver for function
7829   // calls (instead of the global receiver).
7830   if ((target->shared()->native() || !function->is_classic_mode()) &&
7831       call_kind == CALL_AS_FUNCTION && !is_construct) {
7832     inner->SetValueAt(0, undefined);
7833   }
7834   inner->SetValueAt(arity + 1, LookupContext());
7835   for (int i = arity + 2; i < inner->length(); ++i) {
7836     inner->SetValueAt(i, undefined);
7837   }
7838 
7839   inner->set_ast_id(AstNode::kFunctionEntryId);
7840   return inner;
7841 }
7842 
7843 
PrintTo(StringStream * stream)7844 void HEnvironment::PrintTo(StringStream* stream) {
7845   for (int i = 0; i < length(); i++) {
7846     if (i == 0) stream->Add("parameters\n");
7847     if (i == parameter_count()) stream->Add("specials\n");
7848     if (i == parameter_count() + specials_count()) stream->Add("locals\n");
7849     if (i == parameter_count() + specials_count() + local_count()) {
7850       stream->Add("expressions\n");
7851     }
7852     HValue* val = values_.at(i);
7853     stream->Add("%d: ", i);
7854     if (val != NULL) {
7855       val->PrintNameTo(stream);
7856     } else {
7857       stream->Add("NULL");
7858     }
7859     stream->Add("\n");
7860   }
7861   PrintF("\n");
7862 }
7863 
7864 
PrintToStd()7865 void HEnvironment::PrintToStd() {
7866   HeapStringAllocator string_allocator;
7867   StringStream trace(&string_allocator);
7868   PrintTo(&trace);
7869   PrintF("%s", *trace.ToCString());
7870 }
7871 
7872 
TraceCompilation(FunctionLiteral * function)7873 void HTracer::TraceCompilation(FunctionLiteral* function) {
7874   Tag tag(this, "compilation");
7875   Handle<String> name = function->debug_name();
7876   PrintStringProperty("name", *name->ToCString());
7877   PrintStringProperty("method", *name->ToCString());
7878   PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis()));
7879 }
7880 
7881 
TraceLithium(const char * name,LChunk * chunk)7882 void HTracer::TraceLithium(const char* name, LChunk* chunk) {
7883   Trace(name, chunk->graph(), chunk);
7884 }
7885 
7886 
TraceHydrogen(const char * name,HGraph * graph)7887 void HTracer::TraceHydrogen(const char* name, HGraph* graph) {
7888   Trace(name, graph, NULL);
7889 }
7890 
7891 
Trace(const char * name,HGraph * graph,LChunk * chunk)7892 void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) {
7893   Tag tag(this, "cfg");
7894   PrintStringProperty("name", name);
7895   const ZoneList<HBasicBlock*>* blocks = graph->blocks();
7896   for (int i = 0; i < blocks->length(); i++) {
7897     HBasicBlock* current = blocks->at(i);
7898     Tag block_tag(this, "block");
7899     PrintBlockProperty("name", current->block_id());
7900     PrintIntProperty("from_bci", -1);
7901     PrintIntProperty("to_bci", -1);
7902 
7903     if (!current->predecessors()->is_empty()) {
7904       PrintIndent();
7905       trace_.Add("predecessors");
7906       for (int j = 0; j < current->predecessors()->length(); ++j) {
7907         trace_.Add(" \"B%d\"", current->predecessors()->at(j)->block_id());
7908       }
7909       trace_.Add("\n");
7910     } else {
7911       PrintEmptyProperty("predecessors");
7912     }
7913 
7914     if (current->end()->SuccessorCount() == 0) {
7915       PrintEmptyProperty("successors");
7916     } else  {
7917       PrintIndent();
7918       trace_.Add("successors");
7919       for (HSuccessorIterator it(current->end()); !it.Done(); it.Advance()) {
7920         trace_.Add(" \"B%d\"", it.Current()->block_id());
7921       }
7922       trace_.Add("\n");
7923     }
7924 
7925     PrintEmptyProperty("xhandlers");
7926     const char* flags = current->IsLoopSuccessorDominator()
7927         ? "dom-loop-succ"
7928         : "";
7929     PrintStringProperty("flags", flags);
7930 
7931     if (current->dominator() != NULL) {
7932       PrintBlockProperty("dominator", current->dominator()->block_id());
7933     }
7934 
7935     PrintIntProperty("loop_depth", current->LoopNestingDepth());
7936 
7937     if (chunk != NULL) {
7938       int first_index = current->first_instruction_index();
7939       int last_index = current->last_instruction_index();
7940       PrintIntProperty(
7941           "first_lir_id",
7942           LifetimePosition::FromInstructionIndex(first_index).Value());
7943       PrintIntProperty(
7944           "last_lir_id",
7945           LifetimePosition::FromInstructionIndex(last_index).Value());
7946     }
7947 
7948     {
7949       Tag states_tag(this, "states");
7950       Tag locals_tag(this, "locals");
7951       int total = current->phis()->length();
7952       PrintIntProperty("size", current->phis()->length());
7953       PrintStringProperty("method", "None");
7954       for (int j = 0; j < total; ++j) {
7955         HPhi* phi = current->phis()->at(j);
7956         PrintIndent();
7957         trace_.Add("%d ", phi->merged_index());
7958         phi->PrintNameTo(&trace_);
7959         trace_.Add(" ");
7960         phi->PrintTo(&trace_);
7961         trace_.Add("\n");
7962       }
7963     }
7964 
7965     {
7966       Tag HIR_tag(this, "HIR");
7967       HInstruction* instruction = current->first();
7968       while (instruction != NULL) {
7969         int bci = 0;
7970         int uses = instruction->UseCount();
7971         PrintIndent();
7972         trace_.Add("%d %d ", bci, uses);
7973         instruction->PrintNameTo(&trace_);
7974         trace_.Add(" ");
7975         instruction->PrintTo(&trace_);
7976         trace_.Add(" <|@\n");
7977         instruction = instruction->next();
7978       }
7979     }
7980 
7981 
7982     if (chunk != NULL) {
7983       Tag LIR_tag(this, "LIR");
7984       int first_index = current->first_instruction_index();
7985       int last_index = current->last_instruction_index();
7986       if (first_index != -1 && last_index != -1) {
7987         const ZoneList<LInstruction*>* instructions = chunk->instructions();
7988         for (int i = first_index; i <= last_index; ++i) {
7989           LInstruction* linstr = instructions->at(i);
7990           if (linstr != NULL) {
7991             PrintIndent();
7992             trace_.Add("%d ",
7993                        LifetimePosition::FromInstructionIndex(i).Value());
7994             linstr->PrintTo(&trace_);
7995             trace_.Add(" <|@\n");
7996           }
7997         }
7998       }
7999     }
8000   }
8001 }
8002 
8003 
TraceLiveRanges(const char * name,LAllocator * allocator)8004 void HTracer::TraceLiveRanges(const char* name, LAllocator* allocator) {
8005   Tag tag(this, "intervals");
8006   PrintStringProperty("name", name);
8007 
8008   const Vector<LiveRange*>* fixed_d = allocator->fixed_double_live_ranges();
8009   for (int i = 0; i < fixed_d->length(); ++i) {
8010     TraceLiveRange(fixed_d->at(i), "fixed");
8011   }
8012 
8013   const Vector<LiveRange*>* fixed = allocator->fixed_live_ranges();
8014   for (int i = 0; i < fixed->length(); ++i) {
8015     TraceLiveRange(fixed->at(i), "fixed");
8016   }
8017 
8018   const ZoneList<LiveRange*>* live_ranges = allocator->live_ranges();
8019   for (int i = 0; i < live_ranges->length(); ++i) {
8020     TraceLiveRange(live_ranges->at(i), "object");
8021   }
8022 }
8023 
8024 
TraceLiveRange(LiveRange * range,const char * type)8025 void HTracer::TraceLiveRange(LiveRange* range, const char* type) {
8026   if (range != NULL && !range->IsEmpty()) {
8027     PrintIndent();
8028     trace_.Add("%d %s", range->id(), type);
8029     if (range->HasRegisterAssigned()) {
8030       LOperand* op = range->CreateAssignedOperand(ZONE);
8031       int assigned_reg = op->index();
8032       if (op->IsDoubleRegister()) {
8033         trace_.Add(" \"%s\"",
8034                    DoubleRegister::AllocationIndexToString(assigned_reg));
8035       } else {
8036         ASSERT(op->IsRegister());
8037         trace_.Add(" \"%s\"", Register::AllocationIndexToString(assigned_reg));
8038       }
8039     } else if (range->IsSpilled()) {
8040       LOperand* op = range->TopLevel()->GetSpillOperand();
8041       if (op->IsDoubleStackSlot()) {
8042         trace_.Add(" \"double_stack:%d\"", op->index());
8043       } else {
8044         ASSERT(op->IsStackSlot());
8045         trace_.Add(" \"stack:%d\"", op->index());
8046       }
8047     }
8048     int parent_index = -1;
8049     if (range->IsChild()) {
8050       parent_index = range->parent()->id();
8051     } else {
8052       parent_index = range->id();
8053     }
8054     LOperand* op = range->FirstHint();
8055     int hint_index = -1;
8056     if (op != NULL && op->IsUnallocated()) {
8057       hint_index = LUnallocated::cast(op)->virtual_register();
8058     }
8059     trace_.Add(" %d %d", parent_index, hint_index);
8060     UseInterval* cur_interval = range->first_interval();
8061     while (cur_interval != NULL && range->Covers(cur_interval->start())) {
8062       trace_.Add(" [%d, %d[",
8063                  cur_interval->start().Value(),
8064                  cur_interval->end().Value());
8065       cur_interval = cur_interval->next();
8066     }
8067 
8068     UsePosition* current_pos = range->first_pos();
8069     while (current_pos != NULL) {
8070       if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) {
8071         trace_.Add(" %d M", current_pos->pos().Value());
8072       }
8073       current_pos = current_pos->next();
8074     }
8075 
8076     trace_.Add(" \"\"\n");
8077   }
8078 }
8079 
8080 
FlushToFile()8081 void HTracer::FlushToFile() {
8082   AppendChars(filename_, *trace_.ToCString(), trace_.length(), false);
8083   trace_.Reset();
8084 }
8085 
8086 
Initialize(CompilationInfo * info)8087 void HStatistics::Initialize(CompilationInfo* info) {
8088   source_size_ += info->shared_info()->SourceSize();
8089 }
8090 
8091 
Print()8092 void HStatistics::Print() {
8093   PrintF("Timing results:\n");
8094   int64_t sum = 0;
8095   for (int i = 0; i < timing_.length(); ++i) {
8096     sum += timing_[i];
8097   }
8098 
8099   for (int i = 0; i < names_.length(); ++i) {
8100     PrintF("%30s", names_[i]);
8101     double ms = static_cast<double>(timing_[i]) / 1000;
8102     double percent = static_cast<double>(timing_[i]) * 100 / sum;
8103     PrintF(" - %7.3f ms / %4.1f %% ", ms, percent);
8104 
8105     unsigned size = sizes_[i];
8106     double size_percent = static_cast<double>(size) * 100 / total_size_;
8107     PrintF(" %8u bytes / %4.1f %%\n", size, size_percent);
8108   }
8109   double source_size_in_kb = static_cast<double>(source_size_) / 1024;
8110   double normalized_time =  source_size_in_kb > 0
8111       ? (static_cast<double>(sum) / 1000) / source_size_in_kb
8112       : 0;
8113   double normalized_bytes = source_size_in_kb > 0
8114       ? total_size_ / source_size_in_kb
8115       : 0;
8116   PrintF("%30s - %7.3f ms           %7.3f bytes\n", "Sum",
8117          normalized_time, normalized_bytes);
8118   PrintF("---------------------------------------------------------------\n");
8119   PrintF("%30s - %7.3f ms (%.1f times slower than full code gen)\n",
8120          "Total",
8121          static_cast<double>(total_) / 1000,
8122          static_cast<double>(total_) / full_code_gen_);
8123 }
8124 
8125 
SaveTiming(const char * name,int64_t ticks,unsigned size)8126 void HStatistics::SaveTiming(const char* name, int64_t ticks, unsigned size) {
8127   if (name == HPhase::kFullCodeGen) {
8128     full_code_gen_ += ticks;
8129   } else if (name == HPhase::kTotal) {
8130     total_ += ticks;
8131   } else {
8132     total_size_ += size;
8133     for (int i = 0; i < names_.length(); ++i) {
8134       if (names_[i] == name) {
8135         timing_[i] += ticks;
8136         sizes_[i] += size;
8137         return;
8138       }
8139     }
8140     names_.Add(name);
8141     timing_.Add(ticks);
8142     sizes_.Add(size);
8143   }
8144 }
8145 
8146 
8147 const char* const HPhase::kFullCodeGen = "Full code generator";
8148 const char* const HPhase::kTotal = "Total";
8149 
8150 
Begin(const char * name,HGraph * graph,LChunk * chunk,LAllocator * allocator)8151 void HPhase::Begin(const char* name,
8152                    HGraph* graph,
8153                    LChunk* chunk,
8154                    LAllocator* allocator) {
8155   name_ = name;
8156   graph_ = graph;
8157   chunk_ = chunk;
8158   allocator_ = allocator;
8159   if (allocator != NULL && chunk_ == NULL) {
8160     chunk_ = allocator->chunk();
8161   }
8162   if (FLAG_hydrogen_stats) start_ = OS::Ticks();
8163   start_allocation_size_ = Zone::allocation_size_;
8164 }
8165 
8166 
End() const8167 void HPhase::End() const {
8168   if (FLAG_hydrogen_stats) {
8169     int64_t end = OS::Ticks();
8170     unsigned size = Zone::allocation_size_ - start_allocation_size_;
8171     HStatistics::Instance()->SaveTiming(name_, end - start_, size);
8172   }
8173 
8174   // Produce trace output if flag is set so that the first letter of the
8175   // phase name matches the command line parameter FLAG_trace_phase.
8176   if (FLAG_trace_hydrogen &&
8177       OS::StrChr(const_cast<char*>(FLAG_trace_phase), name_[0]) != NULL) {
8178     if (graph_ != NULL) HTracer::Instance()->TraceHydrogen(name_, graph_);
8179     if (chunk_ != NULL) HTracer::Instance()->TraceLithium(name_, chunk_);
8180     if (allocator_ != NULL) {
8181       HTracer::Instance()->TraceLiveRanges(name_, allocator_);
8182     }
8183   }
8184 
8185 #ifdef DEBUG
8186   if (graph_ != NULL) graph_->Verify(false);  // No full verify.
8187   if (allocator_ != NULL) allocator_->Verify();
8188 #endif
8189 }
8190 
8191 } }  // namespace v8::internal
8192