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