• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/crankshaft/hydrogen.h"
6 
7 #include <memory>
8 #include <sstream>
9 
10 #include "src/allocation-site-scopes.h"
11 #include "src/ast/ast-numbering.h"
12 #include "src/ast/compile-time-value.h"
13 #include "src/ast/scopes.h"
14 #include "src/code-factory.h"
15 #include "src/crankshaft/hydrogen-bce.h"
16 #include "src/crankshaft/hydrogen-canonicalize.h"
17 #include "src/crankshaft/hydrogen-check-elimination.h"
18 #include "src/crankshaft/hydrogen-dce.h"
19 #include "src/crankshaft/hydrogen-dehoist.h"
20 #include "src/crankshaft/hydrogen-environment-liveness.h"
21 #include "src/crankshaft/hydrogen-escape-analysis.h"
22 #include "src/crankshaft/hydrogen-gvn.h"
23 #include "src/crankshaft/hydrogen-infer-representation.h"
24 #include "src/crankshaft/hydrogen-infer-types.h"
25 #include "src/crankshaft/hydrogen-load-elimination.h"
26 #include "src/crankshaft/hydrogen-mark-unreachable.h"
27 #include "src/crankshaft/hydrogen-osr.h"
28 #include "src/crankshaft/hydrogen-range-analysis.h"
29 #include "src/crankshaft/hydrogen-redundant-phi.h"
30 #include "src/crankshaft/hydrogen-removable-simulates.h"
31 #include "src/crankshaft/hydrogen-representation-changes.h"
32 #include "src/crankshaft/hydrogen-sce.h"
33 #include "src/crankshaft/hydrogen-store-elimination.h"
34 #include "src/crankshaft/hydrogen-uint32-analysis.h"
35 #include "src/crankshaft/lithium-allocator.h"
36 #include "src/crankshaft/typing.h"
37 #include "src/field-type.h"
38 #include "src/full-codegen/full-codegen.h"
39 #include "src/globals.h"
40 #include "src/ic/call-optimization.h"
41 #include "src/ic/ic.h"
42 // GetRootConstructor
43 #include "src/ic/ic-inl.h"
44 #include "src/isolate-inl.h"
45 #include "src/runtime/runtime.h"
46 
47 #if V8_TARGET_ARCH_IA32
48 #include "src/crankshaft/ia32/lithium-codegen-ia32.h"  // NOLINT
49 #elif V8_TARGET_ARCH_X64
50 #include "src/crankshaft/x64/lithium-codegen-x64.h"  // NOLINT
51 #elif V8_TARGET_ARCH_ARM64
52 #include "src/crankshaft/arm64/lithium-codegen-arm64.h"  // NOLINT
53 #elif V8_TARGET_ARCH_ARM
54 #include "src/crankshaft/arm/lithium-codegen-arm.h"  // NOLINT
55 #elif V8_TARGET_ARCH_PPC
56 #include "src/crankshaft/ppc/lithium-codegen-ppc.h"  // NOLINT
57 #elif V8_TARGET_ARCH_MIPS
58 #include "src/crankshaft/mips/lithium-codegen-mips.h"  // NOLINT
59 #elif V8_TARGET_ARCH_MIPS64
60 #include "src/crankshaft/mips64/lithium-codegen-mips64.h"  // NOLINT
61 #elif V8_TARGET_ARCH_S390
62 #include "src/crankshaft/s390/lithium-codegen-s390.h"  // NOLINT
63 #elif V8_TARGET_ARCH_X87
64 #include "src/crankshaft/x87/lithium-codegen-x87.h"  // NOLINT
65 #else
66 #error Unsupported target architecture.
67 #endif
68 
69 namespace v8 {
70 namespace internal {
71 
72 const auto GetRegConfig = RegisterConfiguration::Crankshaft;
73 
74 class HOptimizedGraphBuilderWithPositions : public HOptimizedGraphBuilder {
75  public:
HOptimizedGraphBuilderWithPositions(CompilationInfo * info)76   explicit HOptimizedGraphBuilderWithPositions(CompilationInfo* info)
77       : HOptimizedGraphBuilder(info, true) {
78     SetSourcePosition(info->shared_info()->start_position());
79   }
80 
81 #define DEF_VISIT(type)                                      \
82   void Visit##type(type* node) override {                    \
83     SourcePosition old_position = SourcePosition::Unknown(); \
84     if (node->position() != kNoSourcePosition) {             \
85       old_position = source_position();                      \
86       SetSourcePosition(node->position());                   \
87     }                                                        \
88     HOptimizedGraphBuilder::Visit##type(node);               \
89     if (old_position.IsKnown()) {                            \
90       set_source_position(old_position);                     \
91     }                                                        \
92   }
93   EXPRESSION_NODE_LIST(DEF_VISIT)
94 #undef DEF_VISIT
95 
96 #define DEF_VISIT(type)                                      \
97   void Visit##type(type* node) override {                    \
98     SourcePosition old_position = SourcePosition::Unknown(); \
99     if (node->position() != kNoSourcePosition) {             \
100       old_position = source_position();                      \
101       SetSourcePosition(node->position());                   \
102     }                                                        \
103     HOptimizedGraphBuilder::Visit##type(node);               \
104     if (old_position.IsKnown()) {                            \
105       set_source_position(old_position);                     \
106     }                                                        \
107   }
108   STATEMENT_NODE_LIST(DEF_VISIT)
109 #undef DEF_VISIT
110 
111 #define DEF_VISIT(type)                        \
112   void Visit##type(type* node) override {      \
113     HOptimizedGraphBuilder::Visit##type(node); \
114   }
115   DECLARATION_NODE_LIST(DEF_VISIT)
116 #undef DEF_VISIT
117 };
118 
PrepareJobImpl()119 HCompilationJob::Status HCompilationJob::PrepareJobImpl() {
120   if (!isolate()->use_crankshaft() ||
121       info()->shared_info()->must_use_ignition_turbo()) {
122     // Crankshaft is entirely disabled.
123     return FAILED;
124   }
125 
126   // Optimization requires a version of fullcode with deoptimization support.
127   // Recompile the unoptimized version of the code if the current version
128   // doesn't have deoptimization support already.
129   // Otherwise, if we are gathering compilation time and space statistics
130   // for hydrogen, gather baseline statistics for a fullcode compilation.
131   bool should_recompile = !info()->shared_info()->has_deoptimization_support();
132   if (should_recompile || FLAG_hydrogen_stats) {
133     base::ElapsedTimer timer;
134     if (FLAG_hydrogen_stats) {
135       timer.Start();
136     }
137     if (!Compiler::EnsureDeoptimizationSupport(info())) {
138       return FAILED;
139     }
140     if (FLAG_hydrogen_stats) {
141       isolate()->GetHStatistics()->IncrementFullCodeGen(timer.Elapsed());
142     }
143   }
144   DCHECK(info()->shared_info()->has_deoptimization_support());
145 
146   // Check the whitelist for Crankshaft.
147   if (!info()->shared_info()->PassesFilter(FLAG_hydrogen_filter)) {
148     return AbortOptimization(kHydrogenFilter);
149   }
150 
151   Scope* scope = info()->scope();
152   if (LUnallocated::TooManyParameters(scope->num_parameters())) {
153     // Crankshaft would require too many Lithium operands.
154     return AbortOptimization(kTooManyParameters);
155   }
156 
157   if (info()->is_osr() &&
158       LUnallocated::TooManyParametersOrStackSlots(scope->num_parameters(),
159                                                   scope->num_stack_slots())) {
160     // Crankshaft would require too many Lithium operands.
161     return AbortOptimization(kTooManyParametersLocals);
162   }
163 
164   if (IsGeneratorFunction(info()->shared_info()->kind())) {
165     // Crankshaft does not support generators.
166     return AbortOptimization(kGenerator);
167   }
168 
169   if (FLAG_trace_hydrogen) {
170     isolate()->GetHTracer()->TraceCompilation(info());
171   }
172 
173   // Optimization could have been disabled by the parser. Note that this check
174   // is only needed because the Hydrogen graph builder is missing some bailouts.
175   if (info()->shared_info()->optimization_disabled()) {
176     return AbortOptimization(
177         info()->shared_info()->disable_optimization_reason());
178   }
179 
180   HOptimizedGraphBuilder* graph_builder =
181       (FLAG_hydrogen_track_positions || isolate()->is_profiling() ||
182        FLAG_trace_ic)
183           ? new (info()->zone()) HOptimizedGraphBuilderWithPositions(info())
184           : new (info()->zone()) HOptimizedGraphBuilder(info(), false);
185 
186   // Type-check the function.
187   AstTyper(info()->isolate(), info()->zone(), info()->closure(),
188            info()->scope(), info()->osr_ast_id(), info()->literal(),
189            graph_builder->bounds())
190       .Run();
191 
192   graph_ = graph_builder->CreateGraph();
193 
194   if (isolate()->has_pending_exception()) {
195     return FAILED;
196   }
197 
198   if (graph_ == NULL) return FAILED;
199 
200   if (info()->dependencies()->HasAborted()) {
201     // Dependency has changed during graph creation. Let's try again later.
202     return RetryOptimization(kBailedOutDueToDependencyChange);
203   }
204 
205   return SUCCEEDED;
206 }
207 
ExecuteJobImpl()208 HCompilationJob::Status HCompilationJob::ExecuteJobImpl() {
209   DCHECK(graph_ != NULL);
210   BailoutReason bailout_reason = kNoReason;
211 
212   if (graph_->Optimize(&bailout_reason)) {
213     chunk_ = LChunk::NewChunk(graph_);
214     if (chunk_ != NULL) return SUCCEEDED;
215   } else if (bailout_reason != kNoReason) {
216     info()->AbortOptimization(bailout_reason);
217   }
218 
219   return FAILED;
220 }
221 
FinalizeJobImpl()222 HCompilationJob::Status HCompilationJob::FinalizeJobImpl() {
223   DCHECK(chunk_ != NULL);
224   DCHECK(graph_ != NULL);
225   {
226     // Deferred handles reference objects that were accessible during
227     // graph creation.  To make sure that we don't encounter inconsistencies
228     // between graph creation and code generation, we disallow accessing
229     // objects through deferred handles during the latter, with exceptions.
230     DisallowDeferredHandleDereference no_deferred_handle_deref;
231     Handle<Code> optimized_code = chunk_->Codegen();
232     if (optimized_code.is_null()) {
233       if (info()->bailout_reason() == kNoReason) {
234         return AbortOptimization(kCodeGenerationFailed);
235       }
236       return FAILED;
237     }
238     RegisterWeakObjectsInOptimizedCode(optimized_code);
239     info()->SetCode(optimized_code);
240   }
241   // Add to the weak list of optimized code objects.
242   info()->context()->native_context()->AddOptimizedCode(*info()->code());
243   return SUCCEEDED;
244 }
245 
HBasicBlock(HGraph * graph)246 HBasicBlock::HBasicBlock(HGraph* graph)
247     : block_id_(graph->GetNextBlockID()),
248       graph_(graph),
249       phis_(4, graph->zone()),
250       first_(NULL),
251       last_(NULL),
252       end_(NULL),
253       loop_information_(NULL),
254       predecessors_(2, graph->zone()),
255       dominator_(NULL),
256       dominated_blocks_(4, graph->zone()),
257       last_environment_(NULL),
258       argument_count_(-1),
259       first_instruction_index_(-1),
260       last_instruction_index_(-1),
261       deleted_phis_(4, graph->zone()),
262       parent_loop_header_(NULL),
263       inlined_entry_block_(NULL),
264       is_inline_return_target_(false),
265       is_reachable_(true),
266       dominates_loop_successors_(false),
267       is_osr_entry_(false),
268       is_ordered_(false) { }
269 
270 
isolate() const271 Isolate* HBasicBlock::isolate() const {
272   return graph_->isolate();
273 }
274 
275 
MarkUnreachable()276 void HBasicBlock::MarkUnreachable() {
277   is_reachable_ = false;
278 }
279 
280 
AttachLoopInformation()281 void HBasicBlock::AttachLoopInformation() {
282   DCHECK(!IsLoopHeader());
283   loop_information_ = new(zone()) HLoopInformation(this, zone());
284 }
285 
286 
DetachLoopInformation()287 void HBasicBlock::DetachLoopInformation() {
288   DCHECK(IsLoopHeader());
289   loop_information_ = NULL;
290 }
291 
292 
AddPhi(HPhi * phi)293 void HBasicBlock::AddPhi(HPhi* phi) {
294   DCHECK(!IsStartBlock());
295   phis_.Add(phi, zone());
296   phi->SetBlock(this);
297 }
298 
299 
RemovePhi(HPhi * phi)300 void HBasicBlock::RemovePhi(HPhi* phi) {
301   DCHECK(phi->block() == this);
302   DCHECK(phis_.Contains(phi));
303   phi->Kill();
304   phis_.RemoveElement(phi);
305   phi->SetBlock(NULL);
306 }
307 
308 
AddInstruction(HInstruction * instr,SourcePosition position)309 void HBasicBlock::AddInstruction(HInstruction* instr, SourcePosition position) {
310   DCHECK(!IsStartBlock() || !IsFinished());
311   DCHECK(!instr->IsLinked());
312   DCHECK(!IsFinished());
313 
314   if (position.IsKnown()) {
315     instr->set_position(position);
316   }
317   if (first_ == NULL) {
318     DCHECK(last_environment() != NULL);
319     DCHECK(!last_environment()->ast_id().IsNone());
320     HBlockEntry* entry = new(zone()) HBlockEntry();
321     entry->InitializeAsFirst(this);
322     if (position.IsKnown()) {
323       entry->set_position(position);
324     } else {
325       DCHECK(!FLAG_hydrogen_track_positions ||
326              !graph()->info()->IsOptimizing() || instr->IsAbnormalExit());
327     }
328     first_ = last_ = entry;
329   }
330   instr->InsertAfter(last_);
331 }
332 
333 
AddNewPhi(int merged_index)334 HPhi* HBasicBlock::AddNewPhi(int merged_index) {
335   if (graph()->IsInsideNoSideEffectsScope()) {
336     merged_index = HPhi::kInvalidMergedIndex;
337   }
338   HPhi* phi = new(zone()) HPhi(merged_index, zone());
339   AddPhi(phi);
340   return phi;
341 }
342 
343 
CreateSimulate(BailoutId ast_id,RemovableSimulate removable)344 HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id,
345                                        RemovableSimulate removable) {
346   DCHECK(HasEnvironment());
347   HEnvironment* environment = last_environment();
348   DCHECK(ast_id.IsNone() ||
349          ast_id == BailoutId::StubEntry() ||
350          environment->closure()->shared()->VerifyBailoutId(ast_id));
351 
352   int push_count = environment->push_count();
353   int pop_count = environment->pop_count();
354 
355   HSimulate* instr =
356       new(zone()) HSimulate(ast_id, pop_count, zone(), removable);
357 #ifdef DEBUG
358   instr->set_closure(environment->closure());
359 #endif
360   // Order of pushed values: newest (top of stack) first. This allows
361   // HSimulate::MergeWith() to easily append additional pushed values
362   // that are older (from further down the stack).
363   for (int i = 0; i < push_count; ++i) {
364     instr->AddPushedValue(environment->ExpressionStackAt(i));
365   }
366   for (GrowableBitVector::Iterator it(environment->assigned_variables(),
367                                       zone());
368        !it.Done();
369        it.Advance()) {
370     int index = it.Current();
371     instr->AddAssignedValue(index, environment->Lookup(index));
372   }
373   environment->ClearHistory();
374   return instr;
375 }
376 
377 
Finish(HControlInstruction * end,SourcePosition position)378 void HBasicBlock::Finish(HControlInstruction* end, SourcePosition position) {
379   DCHECK(!IsFinished());
380   AddInstruction(end, position);
381   end_ = end;
382   for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
383     it.Current()->RegisterPredecessor(this);
384   }
385 }
386 
387 
Goto(HBasicBlock * block,SourcePosition position,FunctionState * state,bool add_simulate)388 void HBasicBlock::Goto(HBasicBlock* block, SourcePosition position,
389                        FunctionState* state, bool add_simulate) {
390   bool drop_extra = state != NULL &&
391       state->inlining_kind() == NORMAL_RETURN;
392 
393   if (block->IsInlineReturnTarget()) {
394     HEnvironment* env = last_environment();
395     int argument_count = env->arguments_environment()->parameter_count();
396     AddInstruction(new(zone())
397                    HLeaveInlined(state->entry(), argument_count),
398                    position);
399     UpdateEnvironment(last_environment()->DiscardInlined(drop_extra));
400   }
401 
402   if (add_simulate) AddNewSimulate(BailoutId::None(), position);
403   HGoto* instr = new(zone()) HGoto(block);
404   Finish(instr, position);
405 }
406 
407 
AddLeaveInlined(HValue * return_value,FunctionState * state,SourcePosition position)408 void HBasicBlock::AddLeaveInlined(HValue* return_value, FunctionState* state,
409                                   SourcePosition position) {
410   HBasicBlock* target = state->function_return();
411   bool drop_extra = state->inlining_kind() == NORMAL_RETURN;
412 
413   DCHECK(target->IsInlineReturnTarget());
414   DCHECK(return_value != NULL);
415   HEnvironment* env = last_environment();
416   int argument_count = env->arguments_environment()->parameter_count();
417   AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count),
418                  position);
419   UpdateEnvironment(last_environment()->DiscardInlined(drop_extra));
420   last_environment()->Push(return_value);
421   AddNewSimulate(BailoutId::None(), position);
422   HGoto* instr = new(zone()) HGoto(target);
423   Finish(instr, position);
424 }
425 
426 
SetInitialEnvironment(HEnvironment * env)427 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) {
428   DCHECK(!HasEnvironment());
429   DCHECK(first() == NULL);
430   UpdateEnvironment(env);
431 }
432 
433 
UpdateEnvironment(HEnvironment * env)434 void HBasicBlock::UpdateEnvironment(HEnvironment* env) {
435   last_environment_ = env;
436   graph()->update_maximum_environment_size(env->first_expression_index());
437 }
438 
439 
SetJoinId(BailoutId ast_id)440 void HBasicBlock::SetJoinId(BailoutId ast_id) {
441   int length = predecessors_.length();
442   DCHECK(length > 0);
443   for (int i = 0; i < length; i++) {
444     HBasicBlock* predecessor = predecessors_[i];
445     DCHECK(predecessor->end()->IsGoto());
446     HSimulate* simulate = HSimulate::cast(predecessor->end()->previous());
447     DCHECK(i != 0 ||
448            (predecessor->last_environment()->closure().is_null() ||
449             predecessor->last_environment()->closure()->shared()
450               ->VerifyBailoutId(ast_id)));
451     simulate->set_ast_id(ast_id);
452     predecessor->last_environment()->set_ast_id(ast_id);
453   }
454 }
455 
456 
Dominates(HBasicBlock * other) const457 bool HBasicBlock::Dominates(HBasicBlock* other) const {
458   HBasicBlock* current = other->dominator();
459   while (current != NULL) {
460     if (current == this) return true;
461     current = current->dominator();
462   }
463   return false;
464 }
465 
466 
EqualToOrDominates(HBasicBlock * other) const467 bool HBasicBlock::EqualToOrDominates(HBasicBlock* other) const {
468   if (this == other) return true;
469   return Dominates(other);
470 }
471 
472 
LoopNestingDepth() const473 int HBasicBlock::LoopNestingDepth() const {
474   const HBasicBlock* current = this;
475   int result  = (current->IsLoopHeader()) ? 1 : 0;
476   while (current->parent_loop_header() != NULL) {
477     current = current->parent_loop_header();
478     result++;
479   }
480   return result;
481 }
482 
483 
PostProcessLoopHeader(IterationStatement * stmt)484 void HBasicBlock::PostProcessLoopHeader(IterationStatement* stmt) {
485   DCHECK(IsLoopHeader());
486 
487   SetJoinId(stmt->EntryId());
488   if (predecessors()->length() == 1) {
489     // This is a degenerated loop.
490     DetachLoopInformation();
491     return;
492   }
493 
494   // Only the first entry into the loop is from outside the loop. All other
495   // entries must be back edges.
496   for (int i = 1; i < predecessors()->length(); ++i) {
497     loop_information()->RegisterBackEdge(predecessors()->at(i));
498   }
499 }
500 
501 
MarkSuccEdgeUnreachable(int succ)502 void HBasicBlock::MarkSuccEdgeUnreachable(int succ) {
503   DCHECK(IsFinished());
504   HBasicBlock* succ_block = end()->SuccessorAt(succ);
505 
506   DCHECK(succ_block->predecessors()->length() == 1);
507   succ_block->MarkUnreachable();
508 }
509 
510 
RegisterPredecessor(HBasicBlock * pred)511 void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) {
512   if (HasPredecessor()) {
513     // Only loop header blocks can have a predecessor added after
514     // instructions have been added to the block (they have phis for all
515     // values in the environment, these phis may be eliminated later).
516     DCHECK(IsLoopHeader() || first_ == NULL);
517     HEnvironment* incoming_env = pred->last_environment();
518     if (IsLoopHeader()) {
519       DCHECK_EQ(phis()->length(), incoming_env->length());
520       for (int i = 0; i < phis_.length(); ++i) {
521         phis_[i]->AddInput(incoming_env->values()->at(i));
522       }
523     } else {
524       last_environment()->AddIncomingEdge(this, pred->last_environment());
525     }
526   } else if (!HasEnvironment() && !IsFinished()) {
527     DCHECK(!IsLoopHeader());
528     SetInitialEnvironment(pred->last_environment()->Copy());
529   }
530 
531   predecessors_.Add(pred, zone());
532 }
533 
534 
AddDominatedBlock(HBasicBlock * block)535 void HBasicBlock::AddDominatedBlock(HBasicBlock* block) {
536   DCHECK(!dominated_blocks_.Contains(block));
537   // Keep the list of dominated blocks sorted such that if there is two
538   // succeeding block in this list, the predecessor is before the successor.
539   int index = 0;
540   while (index < dominated_blocks_.length() &&
541          dominated_blocks_[index]->block_id() < block->block_id()) {
542     ++index;
543   }
544   dominated_blocks_.InsertAt(index, block, zone());
545 }
546 
547 
AssignCommonDominator(HBasicBlock * other)548 void HBasicBlock::AssignCommonDominator(HBasicBlock* other) {
549   if (dominator_ == NULL) {
550     dominator_ = other;
551     other->AddDominatedBlock(this);
552   } else if (other->dominator() != NULL) {
553     HBasicBlock* first = dominator_;
554     HBasicBlock* second = other;
555 
556     while (first != second) {
557       if (first->block_id() > second->block_id()) {
558         first = first->dominator();
559       } else {
560         second = second->dominator();
561       }
562       DCHECK(first != NULL && second != NULL);
563     }
564 
565     if (dominator_ != first) {
566       DCHECK(dominator_->dominated_blocks_.Contains(this));
567       dominator_->dominated_blocks_.RemoveElement(this);
568       dominator_ = first;
569       first->AddDominatedBlock(this);
570     }
571   }
572 }
573 
574 
AssignLoopSuccessorDominators()575 void HBasicBlock::AssignLoopSuccessorDominators() {
576   // Mark blocks that dominate all subsequent reachable blocks inside their
577   // loop. Exploit the fact that blocks are sorted in reverse post order. When
578   // the loop is visited in increasing block id order, if the number of
579   // non-loop-exiting successor edges at the dominator_candidate block doesn't
580   // exceed the number of previously encountered predecessor edges, there is no
581   // path from the loop header to any block with higher id that doesn't go
582   // through the dominator_candidate block. In this case, the
583   // dominator_candidate block is guaranteed to dominate all blocks reachable
584   // from it with higher ids.
585   HBasicBlock* last = loop_information()->GetLastBackEdge();
586   int outstanding_successors = 1;  // one edge from the pre-header
587   // Header always dominates everything.
588   MarkAsLoopSuccessorDominator();
589   for (int j = block_id(); j <= last->block_id(); ++j) {
590     HBasicBlock* dominator_candidate = graph_->blocks()->at(j);
591     for (HPredecessorIterator it(dominator_candidate); !it.Done();
592          it.Advance()) {
593       HBasicBlock* predecessor = it.Current();
594       // Don't count back edges.
595       if (predecessor->block_id() < dominator_candidate->block_id()) {
596         outstanding_successors--;
597       }
598     }
599 
600     // If more successors than predecessors have been seen in the loop up to
601     // now, it's not possible to guarantee that the current block dominates
602     // all of the blocks with higher IDs. In this case, assume conservatively
603     // that those paths through loop that don't go through the current block
604     // contain all of the loop's dependencies. Also be careful to record
605     // dominator information about the current loop that's being processed,
606     // and not nested loops, which will be processed when
607     // AssignLoopSuccessorDominators gets called on their header.
608     DCHECK(outstanding_successors >= 0);
609     HBasicBlock* parent_loop_header = dominator_candidate->parent_loop_header();
610     if (outstanding_successors == 0 &&
611         (parent_loop_header == this && !dominator_candidate->IsLoopHeader())) {
612       dominator_candidate->MarkAsLoopSuccessorDominator();
613     }
614     HControlInstruction* end = dominator_candidate->end();
615     for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
616       HBasicBlock* successor = it.Current();
617       // Only count successors that remain inside the loop and don't loop back
618       // to a loop header.
619       if (successor->block_id() > dominator_candidate->block_id() &&
620           successor->block_id() <= last->block_id()) {
621         // Backwards edges must land on loop headers.
622         DCHECK(successor->block_id() > dominator_candidate->block_id() ||
623                successor->IsLoopHeader());
624         outstanding_successors++;
625       }
626     }
627   }
628 }
629 
630 
PredecessorIndexOf(HBasicBlock * predecessor) const631 int HBasicBlock::PredecessorIndexOf(HBasicBlock* predecessor) const {
632   for (int i = 0; i < predecessors_.length(); ++i) {
633     if (predecessors_[i] == predecessor) return i;
634   }
635   UNREACHABLE();
636   return -1;
637 }
638 
639 
640 #ifdef DEBUG
Verify()641 void HBasicBlock::Verify() {
642   // Check that every block is finished.
643   DCHECK(IsFinished());
644   DCHECK(block_id() >= 0);
645 
646   // Check that the incoming edges are in edge split form.
647   if (predecessors_.length() > 1) {
648     for (int i = 0; i < predecessors_.length(); ++i) {
649       DCHECK(predecessors_[i]->end()->SecondSuccessor() == NULL);
650     }
651   }
652 }
653 #endif
654 
655 
RegisterBackEdge(HBasicBlock * block)656 void HLoopInformation::RegisterBackEdge(HBasicBlock* block) {
657   this->back_edges_.Add(block, block->zone());
658   AddBlock(block);
659 }
660 
661 
GetLastBackEdge() const662 HBasicBlock* HLoopInformation::GetLastBackEdge() const {
663   int max_id = -1;
664   HBasicBlock* result = NULL;
665   for (int i = 0; i < back_edges_.length(); ++i) {
666     HBasicBlock* cur = back_edges_[i];
667     if (cur->block_id() > max_id) {
668       max_id = cur->block_id();
669       result = cur;
670     }
671   }
672   return result;
673 }
674 
675 
AddBlock(HBasicBlock * block)676 void HLoopInformation::AddBlock(HBasicBlock* block) {
677   if (block == loop_header()) return;
678   if (block->parent_loop_header() == loop_header()) return;
679   if (block->parent_loop_header() != NULL) {
680     AddBlock(block->parent_loop_header());
681   } else {
682     block->set_parent_loop_header(loop_header());
683     blocks_.Add(block, block->zone());
684     for (int i = 0; i < block->predecessors()->length(); ++i) {
685       AddBlock(block->predecessors()->at(i));
686     }
687   }
688 }
689 
690 
691 #ifdef DEBUG
692 
693 // Checks reachability of the blocks in this graph and stores a bit in
694 // the BitVector "reachable()" for every block that can be reached
695 // from the start block of the graph. If "dont_visit" is non-null, the given
696 // block is treated as if it would not be part of the graph. "visited_count()"
697 // returns the number of reachable blocks.
698 class ReachabilityAnalyzer BASE_EMBEDDED {
699  public:
ReachabilityAnalyzer(HBasicBlock * entry_block,int block_count,HBasicBlock * dont_visit)700   ReachabilityAnalyzer(HBasicBlock* entry_block,
701                        int block_count,
702                        HBasicBlock* dont_visit)
703       : visited_count_(0),
704         stack_(16, entry_block->zone()),
705         reachable_(block_count, entry_block->zone()),
706         dont_visit_(dont_visit) {
707     PushBlock(entry_block);
708     Analyze();
709   }
710 
visited_count() const711   int visited_count() const { return visited_count_; }
reachable() const712   const BitVector* reachable() const { return &reachable_; }
713 
714  private:
PushBlock(HBasicBlock * block)715   void PushBlock(HBasicBlock* block) {
716     if (block != NULL && block != dont_visit_ &&
717         !reachable_.Contains(block->block_id())) {
718       reachable_.Add(block->block_id());
719       stack_.Add(block, block->zone());
720       visited_count_++;
721     }
722   }
723 
Analyze()724   void Analyze() {
725     while (!stack_.is_empty()) {
726       HControlInstruction* end = stack_.RemoveLast()->end();
727       for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
728         PushBlock(it.Current());
729       }
730     }
731   }
732 
733   int visited_count_;
734   ZoneList<HBasicBlock*> stack_;
735   BitVector reachable_;
736   HBasicBlock* dont_visit_;
737 };
738 
739 
Verify(bool do_full_verify) const740 void HGraph::Verify(bool do_full_verify) const {
741   Heap::RelocationLock relocation_lock(isolate()->heap());
742   AllowHandleDereference allow_deref;
743   AllowDeferredHandleDereference allow_deferred_deref;
744   for (int i = 0; i < blocks_.length(); i++) {
745     HBasicBlock* block = blocks_.at(i);
746 
747     block->Verify();
748 
749     // Check that every block contains at least one node and that only the last
750     // node is a control instruction.
751     HInstruction* current = block->first();
752     DCHECK(current != NULL && current->IsBlockEntry());
753     while (current != NULL) {
754       DCHECK((current->next() == NULL) == current->IsControlInstruction());
755       DCHECK(current->block() == block);
756       current->Verify();
757       current = current->next();
758     }
759 
760     // Check that successors are correctly set.
761     HBasicBlock* first = block->end()->FirstSuccessor();
762     HBasicBlock* second = block->end()->SecondSuccessor();
763     DCHECK(second == NULL || first != NULL);
764 
765     // Check that the predecessor array is correct.
766     if (first != NULL) {
767       DCHECK(first->predecessors()->Contains(block));
768       if (second != NULL) {
769         DCHECK(second->predecessors()->Contains(block));
770       }
771     }
772 
773     // Check that phis have correct arguments.
774     for (int j = 0; j < block->phis()->length(); j++) {
775       HPhi* phi = block->phis()->at(j);
776       phi->Verify();
777     }
778 
779     // Check that all join blocks have predecessors that end with an
780     // unconditional goto and agree on their environment node id.
781     if (block->predecessors()->length() >= 2) {
782       BailoutId id =
783           block->predecessors()->first()->last_environment()->ast_id();
784       for (int k = 0; k < block->predecessors()->length(); k++) {
785         HBasicBlock* predecessor = block->predecessors()->at(k);
786         DCHECK(predecessor->end()->IsGoto() ||
787                predecessor->end()->IsDeoptimize());
788         DCHECK(predecessor->last_environment()->ast_id() == id);
789       }
790     }
791   }
792 
793   // Check special property of first block to have no predecessors.
794   DCHECK(blocks_.at(0)->predecessors()->is_empty());
795 
796   if (do_full_verify) {
797     // Check that the graph is fully connected.
798     ReachabilityAnalyzer analyzer(entry_block_, blocks_.length(), NULL);
799     DCHECK(analyzer.visited_count() == blocks_.length());
800 
801     // Check that entry block dominator is NULL.
802     DCHECK(entry_block_->dominator() == NULL);
803 
804     // Check dominators.
805     for (int i = 0; i < blocks_.length(); ++i) {
806       HBasicBlock* block = blocks_.at(i);
807       if (block->dominator() == NULL) {
808         // Only start block may have no dominator assigned to.
809         DCHECK(i == 0);
810       } else {
811         // Assert that block is unreachable if dominator must not be visited.
812         ReachabilityAnalyzer dominator_analyzer(entry_block_,
813                                                 blocks_.length(),
814                                                 block->dominator());
815         DCHECK(!dominator_analyzer.reachable()->Contains(block->block_id()));
816       }
817     }
818   }
819 }
820 
821 #endif
822 
823 
GetConstant(SetOncePointer<HConstant> * pointer,int32_t value)824 HConstant* HGraph::GetConstant(SetOncePointer<HConstant>* pointer,
825                                int32_t value) {
826   if (!pointer->is_set()) {
827     // Can't pass GetInvalidContext() to HConstant::New, because that will
828     // recursively call GetConstant
829     HConstant* constant = HConstant::New(isolate(), zone(), NULL, value);
830     constant->InsertAfter(entry_block()->first());
831     pointer->set(constant);
832     return constant;
833   }
834   return ReinsertConstantIfNecessary(pointer->get());
835 }
836 
837 
ReinsertConstantIfNecessary(HConstant * constant)838 HConstant* HGraph::ReinsertConstantIfNecessary(HConstant* constant) {
839   if (!constant->IsLinked()) {
840     // The constant was removed from the graph. Reinsert.
841     constant->ClearFlag(HValue::kIsDead);
842     constant->InsertAfter(entry_block()->first());
843   }
844   return constant;
845 }
846 
847 
GetConstant0()848 HConstant* HGraph::GetConstant0() {
849   return GetConstant(&constant_0_, 0);
850 }
851 
852 
GetConstant1()853 HConstant* HGraph::GetConstant1() {
854   return GetConstant(&constant_1_, 1);
855 }
856 
857 
GetConstantMinus1()858 HConstant* HGraph::GetConstantMinus1() {
859   return GetConstant(&constant_minus1_, -1);
860 }
861 
862 
GetConstantBool(bool value)863 HConstant* HGraph::GetConstantBool(bool value) {
864   return value ? GetConstantTrue() : GetConstantFalse();
865 }
866 
867 #define DEFINE_GET_CONSTANT(Name, name, constant, type, htype, boolean_value, \
868                             undetectable)                                     \
869   HConstant* HGraph::GetConstant##Name() {                                    \
870     if (!constant_##name##_.is_set()) {                                       \
871       HConstant* constant = new (zone()) HConstant(                           \
872           Unique<Object>::CreateImmovable(isolate()->factory()->constant()),  \
873           Unique<Map>::CreateImmovable(isolate()->factory()->type##_map()),   \
874           false, Representation::Tagged(), htype, true, boolean_value,        \
875           undetectable, ODDBALL_TYPE);                                        \
876       constant->InsertAfter(entry_block()->first());                          \
877       constant_##name##_.set(constant);                                       \
878     }                                                                         \
879     return ReinsertConstantIfNecessary(constant_##name##_.get());             \
880   }
881 
DEFINE_GET_CONSTANT(Undefined,undefined,undefined_value,undefined,HType::Undefined (),false,true)882 DEFINE_GET_CONSTANT(Undefined, undefined, undefined_value, undefined,
883                     HType::Undefined(), false, true)
884 DEFINE_GET_CONSTANT(True, true, true_value, boolean, HType::Boolean(), true,
885                     false)
886 DEFINE_GET_CONSTANT(False, false, false_value, boolean, HType::Boolean(), false,
887                     false)
888 DEFINE_GET_CONSTANT(Hole, the_hole, the_hole_value, the_hole, HType::None(),
889                     false, false)
890 DEFINE_GET_CONSTANT(Null, null, null_value, null, HType::Null(), false, true)
891 DEFINE_GET_CONSTANT(OptimizedOut, optimized_out, optimized_out, optimized_out,
892                     HType::None(), false, false)
893 
894 #undef DEFINE_GET_CONSTANT
895 
896 #define DEFINE_IS_CONSTANT(Name, name)                                         \
897 bool HGraph::IsConstant##Name(HConstant* constant) {                           \
898   return constant_##name##_.is_set() && constant == constant_##name##_.get();  \
899 }
900 DEFINE_IS_CONSTANT(Undefined, undefined)
901 DEFINE_IS_CONSTANT(0, 0)
902 DEFINE_IS_CONSTANT(1, 1)
903 DEFINE_IS_CONSTANT(Minus1, minus1)
904 DEFINE_IS_CONSTANT(True, true)
905 DEFINE_IS_CONSTANT(False, false)
906 DEFINE_IS_CONSTANT(Hole, the_hole)
907 DEFINE_IS_CONSTANT(Null, null)
908 
909 #undef DEFINE_IS_CONSTANT
910 
911 
912 HConstant* HGraph::GetInvalidContext() {
913   return GetConstant(&constant_invalid_context_, 0xFFFFC0C7);
914 }
915 
916 
IsStandardConstant(HConstant * constant)917 bool HGraph::IsStandardConstant(HConstant* constant) {
918   if (IsConstantUndefined(constant)) return true;
919   if (IsConstant0(constant)) return true;
920   if (IsConstant1(constant)) return true;
921   if (IsConstantMinus1(constant)) return true;
922   if (IsConstantTrue(constant)) return true;
923   if (IsConstantFalse(constant)) return true;
924   if (IsConstantHole(constant)) return true;
925   if (IsConstantNull(constant)) return true;
926   return false;
927 }
928 
929 
IfBuilder()930 HGraphBuilder::IfBuilder::IfBuilder() : builder_(NULL), needs_compare_(true) {}
931 
932 
IfBuilder(HGraphBuilder * builder)933 HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder)
934     : needs_compare_(true) {
935   Initialize(builder);
936 }
937 
938 
IfBuilder(HGraphBuilder * builder,HIfContinuation * continuation)939 HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder,
940                                     HIfContinuation* continuation)
941     : needs_compare_(false), first_true_block_(NULL), first_false_block_(NULL) {
942   InitializeDontCreateBlocks(builder);
943   continuation->Continue(&first_true_block_, &first_false_block_);
944 }
945 
946 
InitializeDontCreateBlocks(HGraphBuilder * builder)947 void HGraphBuilder::IfBuilder::InitializeDontCreateBlocks(
948     HGraphBuilder* builder) {
949   builder_ = builder;
950   finished_ = false;
951   did_then_ = false;
952   did_else_ = false;
953   did_else_if_ = false;
954   did_and_ = false;
955   did_or_ = false;
956   captured_ = false;
957   pending_merge_block_ = false;
958   split_edge_merge_block_ = NULL;
959   merge_at_join_blocks_ = NULL;
960   normal_merge_at_join_block_count_ = 0;
961   deopt_merge_at_join_block_count_ = 0;
962 }
963 
964 
Initialize(HGraphBuilder * builder)965 void HGraphBuilder::IfBuilder::Initialize(HGraphBuilder* builder) {
966   InitializeDontCreateBlocks(builder);
967   HEnvironment* env = builder->environment();
968   first_true_block_ = builder->CreateBasicBlock(env->Copy());
969   first_false_block_ = builder->CreateBasicBlock(env->Copy());
970 }
971 
972 
AddCompare(HControlInstruction * compare)973 HControlInstruction* HGraphBuilder::IfBuilder::AddCompare(
974     HControlInstruction* compare) {
975   DCHECK(did_then_ == did_else_);
976   if (did_else_) {
977     // Handle if-then-elseif
978     did_else_if_ = true;
979     did_else_ = false;
980     did_then_ = false;
981     did_and_ = false;
982     did_or_ = false;
983     pending_merge_block_ = false;
984     split_edge_merge_block_ = NULL;
985     HEnvironment* env = builder()->environment();
986     first_true_block_ = builder()->CreateBasicBlock(env->Copy());
987     first_false_block_ = builder()->CreateBasicBlock(env->Copy());
988   }
989   if (split_edge_merge_block_ != NULL) {
990     HEnvironment* env = first_false_block_->last_environment();
991     HBasicBlock* split_edge = builder()->CreateBasicBlock(env->Copy());
992     if (did_or_) {
993       compare->SetSuccessorAt(0, split_edge);
994       compare->SetSuccessorAt(1, first_false_block_);
995     } else {
996       compare->SetSuccessorAt(0, first_true_block_);
997       compare->SetSuccessorAt(1, split_edge);
998     }
999     builder()->GotoNoSimulate(split_edge, split_edge_merge_block_);
1000   } else {
1001     compare->SetSuccessorAt(0, first_true_block_);
1002     compare->SetSuccessorAt(1, first_false_block_);
1003   }
1004   builder()->FinishCurrentBlock(compare);
1005   needs_compare_ = false;
1006   return compare;
1007 }
1008 
1009 
Or()1010 void HGraphBuilder::IfBuilder::Or() {
1011   DCHECK(!needs_compare_);
1012   DCHECK(!did_and_);
1013   did_or_ = true;
1014   HEnvironment* env = first_false_block_->last_environment();
1015   if (split_edge_merge_block_ == NULL) {
1016     split_edge_merge_block_ = builder()->CreateBasicBlock(env->Copy());
1017     builder()->GotoNoSimulate(first_true_block_, split_edge_merge_block_);
1018     first_true_block_ = split_edge_merge_block_;
1019   }
1020   builder()->set_current_block(first_false_block_);
1021   first_false_block_ = builder()->CreateBasicBlock(env->Copy());
1022 }
1023 
1024 
And()1025 void HGraphBuilder::IfBuilder::And() {
1026   DCHECK(!needs_compare_);
1027   DCHECK(!did_or_);
1028   did_and_ = true;
1029   HEnvironment* env = first_false_block_->last_environment();
1030   if (split_edge_merge_block_ == NULL) {
1031     split_edge_merge_block_ = builder()->CreateBasicBlock(env->Copy());
1032     builder()->GotoNoSimulate(first_false_block_, split_edge_merge_block_);
1033     first_false_block_ = split_edge_merge_block_;
1034   }
1035   builder()->set_current_block(first_true_block_);
1036   first_true_block_ = builder()->CreateBasicBlock(env->Copy());
1037 }
1038 
1039 
CaptureContinuation(HIfContinuation * continuation)1040 void HGraphBuilder::IfBuilder::CaptureContinuation(
1041     HIfContinuation* continuation) {
1042   DCHECK(!did_else_if_);
1043   DCHECK(!finished_);
1044   DCHECK(!captured_);
1045 
1046   HBasicBlock* true_block = NULL;
1047   HBasicBlock* false_block = NULL;
1048   Finish(&true_block, &false_block);
1049   DCHECK(true_block != NULL);
1050   DCHECK(false_block != NULL);
1051   continuation->Capture(true_block, false_block);
1052   captured_ = true;
1053   builder()->set_current_block(NULL);
1054   End();
1055 }
1056 
1057 
JoinContinuation(HIfContinuation * continuation)1058 void HGraphBuilder::IfBuilder::JoinContinuation(HIfContinuation* continuation) {
1059   DCHECK(!did_else_if_);
1060   DCHECK(!finished_);
1061   DCHECK(!captured_);
1062   HBasicBlock* true_block = NULL;
1063   HBasicBlock* false_block = NULL;
1064   Finish(&true_block, &false_block);
1065   merge_at_join_blocks_ = NULL;
1066   if (true_block != NULL && !true_block->IsFinished()) {
1067     DCHECK(continuation->IsTrueReachable());
1068     builder()->GotoNoSimulate(true_block, continuation->true_branch());
1069   }
1070   if (false_block != NULL && !false_block->IsFinished()) {
1071     DCHECK(continuation->IsFalseReachable());
1072     builder()->GotoNoSimulate(false_block, continuation->false_branch());
1073   }
1074   captured_ = true;
1075   End();
1076 }
1077 
1078 
Then()1079 void HGraphBuilder::IfBuilder::Then() {
1080   DCHECK(!captured_);
1081   DCHECK(!finished_);
1082   did_then_ = true;
1083   if (needs_compare_) {
1084     // Handle if's without any expressions, they jump directly to the "else"
1085     // branch. However, we must pretend that the "then" branch is reachable,
1086     // so that the graph builder visits it and sees any live range extending
1087     // constructs within it.
1088     HConstant* constant_false = builder()->graph()->GetConstantFalse();
1089     ToBooleanHints boolean_type = ToBooleanHint::kBoolean;
1090     HBranch* branch = builder()->New<HBranch>(
1091         constant_false, boolean_type, first_true_block_, first_false_block_);
1092     builder()->FinishCurrentBlock(branch);
1093   }
1094   builder()->set_current_block(first_true_block_);
1095   pending_merge_block_ = true;
1096 }
1097 
1098 
Else()1099 void HGraphBuilder::IfBuilder::Else() {
1100   DCHECK(did_then_);
1101   DCHECK(!captured_);
1102   DCHECK(!finished_);
1103   AddMergeAtJoinBlock(false);
1104   builder()->set_current_block(first_false_block_);
1105   pending_merge_block_ = true;
1106   did_else_ = true;
1107 }
1108 
Deopt(DeoptimizeReason reason)1109 void HGraphBuilder::IfBuilder::Deopt(DeoptimizeReason reason) {
1110   DCHECK(did_then_);
1111   builder()->Add<HDeoptimize>(reason, Deoptimizer::EAGER);
1112   AddMergeAtJoinBlock(true);
1113 }
1114 
1115 
Return(HValue * value)1116 void HGraphBuilder::IfBuilder::Return(HValue* value) {
1117   HValue* parameter_count = builder()->graph()->GetConstantMinus1();
1118   builder()->FinishExitCurrentBlock(
1119       builder()->New<HReturn>(value, parameter_count));
1120   AddMergeAtJoinBlock(false);
1121 }
1122 
1123 
AddMergeAtJoinBlock(bool deopt)1124 void HGraphBuilder::IfBuilder::AddMergeAtJoinBlock(bool deopt) {
1125   if (!pending_merge_block_) return;
1126   HBasicBlock* block = builder()->current_block();
1127   DCHECK(block == NULL || !block->IsFinished());
1128   MergeAtJoinBlock* record = new (builder()->zone())
1129       MergeAtJoinBlock(block, deopt, merge_at_join_blocks_);
1130   merge_at_join_blocks_ = record;
1131   if (block != NULL) {
1132     DCHECK(block->end() == NULL);
1133     if (deopt) {
1134       normal_merge_at_join_block_count_++;
1135     } else {
1136       deopt_merge_at_join_block_count_++;
1137     }
1138   }
1139   builder()->set_current_block(NULL);
1140   pending_merge_block_ = false;
1141 }
1142 
1143 
Finish()1144 void HGraphBuilder::IfBuilder::Finish() {
1145   DCHECK(!finished_);
1146   if (!did_then_) {
1147     Then();
1148   }
1149   AddMergeAtJoinBlock(false);
1150   if (!did_else_) {
1151     Else();
1152     AddMergeAtJoinBlock(false);
1153   }
1154   finished_ = true;
1155 }
1156 
1157 
Finish(HBasicBlock ** then_continuation,HBasicBlock ** else_continuation)1158 void HGraphBuilder::IfBuilder::Finish(HBasicBlock** then_continuation,
1159                                       HBasicBlock** else_continuation) {
1160   Finish();
1161 
1162   MergeAtJoinBlock* else_record = merge_at_join_blocks_;
1163   if (else_continuation != NULL) {
1164     *else_continuation = else_record->block_;
1165   }
1166   MergeAtJoinBlock* then_record = else_record->next_;
1167   if (then_continuation != NULL) {
1168     *then_continuation = then_record->block_;
1169   }
1170   DCHECK(then_record->next_ == NULL);
1171 }
1172 
1173 
EndUnreachable()1174 void HGraphBuilder::IfBuilder::EndUnreachable() {
1175   if (captured_) return;
1176   Finish();
1177   builder()->set_current_block(nullptr);
1178 }
1179 
1180 
End()1181 void HGraphBuilder::IfBuilder::End() {
1182   if (captured_) return;
1183   Finish();
1184 
1185   int total_merged_blocks = normal_merge_at_join_block_count_ +
1186     deopt_merge_at_join_block_count_;
1187   DCHECK(total_merged_blocks >= 1);
1188   HBasicBlock* merge_block =
1189       total_merged_blocks == 1 ? NULL : builder()->graph()->CreateBasicBlock();
1190 
1191   // Merge non-deopt blocks first to ensure environment has right size for
1192   // padding.
1193   MergeAtJoinBlock* current = merge_at_join_blocks_;
1194   while (current != NULL) {
1195     if (!current->deopt_ && current->block_ != NULL) {
1196       // If there is only one block that makes it through to the end of the
1197       // if, then just set it as the current block and continue rather then
1198       // creating an unnecessary merge block.
1199       if (total_merged_blocks == 1) {
1200         builder()->set_current_block(current->block_);
1201         return;
1202       }
1203       builder()->GotoNoSimulate(current->block_, merge_block);
1204     }
1205     current = current->next_;
1206   }
1207 
1208   // Merge deopt blocks, padding when necessary.
1209   current = merge_at_join_blocks_;
1210   while (current != NULL) {
1211     if (current->deopt_ && current->block_ != NULL) {
1212       current->block_->FinishExit(
1213           HAbnormalExit::New(builder()->isolate(), builder()->zone(), NULL),
1214           SourcePosition::Unknown());
1215     }
1216     current = current->next_;
1217   }
1218   builder()->set_current_block(merge_block);
1219 }
1220 
1221 
LoopBuilder(HGraphBuilder * builder)1222 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder) {
1223   Initialize(builder, NULL, kWhileTrue, NULL);
1224 }
1225 
1226 
LoopBuilder(HGraphBuilder * builder,HValue * context,LoopBuilder::Direction direction)1227 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, HValue* context,
1228                                         LoopBuilder::Direction direction) {
1229   Initialize(builder, context, direction, builder->graph()->GetConstant1());
1230 }
1231 
1232 
LoopBuilder(HGraphBuilder * builder,HValue * context,LoopBuilder::Direction direction,HValue * increment_amount)1233 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, HValue* context,
1234                                         LoopBuilder::Direction direction,
1235                                         HValue* increment_amount) {
1236   Initialize(builder, context, direction, increment_amount);
1237   increment_amount_ = increment_amount;
1238 }
1239 
1240 
Initialize(HGraphBuilder * builder,HValue * context,Direction direction,HValue * increment_amount)1241 void HGraphBuilder::LoopBuilder::Initialize(HGraphBuilder* builder,
1242                                             HValue* context,
1243                                             Direction direction,
1244                                             HValue* increment_amount) {
1245   builder_ = builder;
1246   context_ = context;
1247   direction_ = direction;
1248   increment_amount_ = increment_amount;
1249 
1250   finished_ = false;
1251   header_block_ = builder->CreateLoopHeaderBlock();
1252   body_block_ = NULL;
1253   exit_block_ = NULL;
1254   exit_trampoline_block_ = NULL;
1255 }
1256 
1257 
BeginBody(HValue * initial,HValue * terminating,Token::Value token)1258 HValue* HGraphBuilder::LoopBuilder::BeginBody(
1259     HValue* initial,
1260     HValue* terminating,
1261     Token::Value token) {
1262   DCHECK(direction_ != kWhileTrue);
1263   HEnvironment* env = builder_->environment();
1264   phi_ = header_block_->AddNewPhi(env->values()->length());
1265   phi_->AddInput(initial);
1266   env->Push(initial);
1267   builder_->GotoNoSimulate(header_block_);
1268 
1269   HEnvironment* body_env = env->Copy();
1270   HEnvironment* exit_env = env->Copy();
1271   // Remove the phi from the expression stack
1272   body_env->Pop();
1273   exit_env->Pop();
1274   body_block_ = builder_->CreateBasicBlock(body_env);
1275   exit_block_ = builder_->CreateBasicBlock(exit_env);
1276 
1277   builder_->set_current_block(header_block_);
1278   env->Pop();
1279   builder_->FinishCurrentBlock(builder_->New<HCompareNumericAndBranch>(
1280           phi_, terminating, token, body_block_, exit_block_));
1281 
1282   builder_->set_current_block(body_block_);
1283   if (direction_ == kPreIncrement || direction_ == kPreDecrement) {
1284     Isolate* isolate = builder_->isolate();
1285     HValue* one = builder_->graph()->GetConstant1();
1286     if (direction_ == kPreIncrement) {
1287       increment_ = HAdd::New(isolate, zone(), context_, phi_, one);
1288     } else {
1289       increment_ = HSub::New(isolate, zone(), context_, phi_, one);
1290     }
1291     increment_->ClearFlag(HValue::kCanOverflow);
1292     builder_->AddInstruction(increment_);
1293     return increment_;
1294   } else {
1295     return phi_;
1296   }
1297 }
1298 
1299 
BeginBody(int drop_count)1300 void HGraphBuilder::LoopBuilder::BeginBody(int drop_count) {
1301   DCHECK(direction_ == kWhileTrue);
1302   HEnvironment* env = builder_->environment();
1303   builder_->GotoNoSimulate(header_block_);
1304   builder_->set_current_block(header_block_);
1305   env->Drop(drop_count);
1306 }
1307 
1308 
Break()1309 void HGraphBuilder::LoopBuilder::Break() {
1310   if (exit_trampoline_block_ == NULL) {
1311     // Its the first time we saw a break.
1312     if (direction_ == kWhileTrue) {
1313       HEnvironment* env = builder_->environment()->Copy();
1314       exit_trampoline_block_ = builder_->CreateBasicBlock(env);
1315     } else {
1316       HEnvironment* env = exit_block_->last_environment()->Copy();
1317       exit_trampoline_block_ = builder_->CreateBasicBlock(env);
1318       builder_->GotoNoSimulate(exit_block_, exit_trampoline_block_);
1319     }
1320   }
1321 
1322   builder_->GotoNoSimulate(exit_trampoline_block_);
1323   builder_->set_current_block(NULL);
1324 }
1325 
1326 
EndBody()1327 void HGraphBuilder::LoopBuilder::EndBody() {
1328   DCHECK(!finished_);
1329 
1330   if (direction_ == kPostIncrement || direction_ == kPostDecrement) {
1331     Isolate* isolate = builder_->isolate();
1332     if (direction_ == kPostIncrement) {
1333       increment_ =
1334           HAdd::New(isolate, zone(), context_, phi_, increment_amount_);
1335     } else {
1336       increment_ =
1337           HSub::New(isolate, zone(), context_, phi_, increment_amount_);
1338     }
1339     increment_->ClearFlag(HValue::kCanOverflow);
1340     builder_->AddInstruction(increment_);
1341   }
1342 
1343   if (direction_ != kWhileTrue) {
1344     // Push the new increment value on the expression stack to merge into
1345     // the phi.
1346     builder_->environment()->Push(increment_);
1347   }
1348   HBasicBlock* last_block = builder_->current_block();
1349   builder_->GotoNoSimulate(last_block, header_block_);
1350   header_block_->loop_information()->RegisterBackEdge(last_block);
1351 
1352   if (exit_trampoline_block_ != NULL) {
1353     builder_->set_current_block(exit_trampoline_block_);
1354   } else {
1355     builder_->set_current_block(exit_block_);
1356   }
1357   finished_ = true;
1358 }
1359 
1360 
CreateGraph()1361 HGraph* HGraphBuilder::CreateGraph() {
1362   DCHECK(!FLAG_minimal);
1363   graph_ = new (zone()) HGraph(info_, descriptor_);
1364   if (FLAG_hydrogen_stats) isolate()->GetHStatistics()->Initialize(info_);
1365   CompilationPhase phase("H_Block building", info_);
1366   set_current_block(graph()->entry_block());
1367   if (!BuildGraph()) return NULL;
1368   graph()->FinalizeUniqueness();
1369   return graph_;
1370 }
1371 
1372 
AddInstruction(HInstruction * instr)1373 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
1374   DCHECK(current_block() != NULL);
1375   DCHECK(!FLAG_hydrogen_track_positions || position_.IsKnown() ||
1376          !info_->IsOptimizing());
1377   current_block()->AddInstruction(instr, source_position());
1378   if (graph()->IsInsideNoSideEffectsScope()) {
1379     instr->SetFlag(HValue::kHasNoObservableSideEffects);
1380   }
1381   return instr;
1382 }
1383 
1384 
FinishCurrentBlock(HControlInstruction * last)1385 void HGraphBuilder::FinishCurrentBlock(HControlInstruction* last) {
1386   DCHECK(!FLAG_hydrogen_track_positions || !info_->IsOptimizing() ||
1387          position_.IsKnown());
1388   current_block()->Finish(last, source_position());
1389   if (last->IsReturn() || last->IsAbnormalExit()) {
1390     set_current_block(NULL);
1391   }
1392 }
1393 
1394 
FinishExitCurrentBlock(HControlInstruction * instruction)1395 void HGraphBuilder::FinishExitCurrentBlock(HControlInstruction* instruction) {
1396   DCHECK(!FLAG_hydrogen_track_positions || !info_->IsOptimizing() ||
1397          position_.IsKnown());
1398   current_block()->FinishExit(instruction, source_position());
1399   if (instruction->IsReturn() || instruction->IsAbnormalExit()) {
1400     set_current_block(NULL);
1401   }
1402 }
1403 
1404 
AddIncrementCounter(StatsCounter * counter)1405 void HGraphBuilder::AddIncrementCounter(StatsCounter* counter) {
1406   if (FLAG_native_code_counters && counter->Enabled()) {
1407     HValue* reference = Add<HConstant>(ExternalReference(counter));
1408     HValue* old_value =
1409         Add<HLoadNamedField>(reference, nullptr, HObjectAccess::ForCounter());
1410     HValue* new_value = AddUncasted<HAdd>(old_value, graph()->GetConstant1());
1411     new_value->ClearFlag(HValue::kCanOverflow);  // Ignore counter overflow
1412     Add<HStoreNamedField>(reference, HObjectAccess::ForCounter(),
1413                           new_value, STORE_TO_INITIALIZED_ENTRY);
1414   }
1415 }
1416 
1417 
AddSimulate(BailoutId id,RemovableSimulate removable)1418 void HGraphBuilder::AddSimulate(BailoutId id,
1419                                 RemovableSimulate removable) {
1420   DCHECK(current_block() != NULL);
1421   DCHECK(!graph()->IsInsideNoSideEffectsScope());
1422   current_block()->AddNewSimulate(id, source_position(), removable);
1423 }
1424 
1425 
CreateBasicBlock(HEnvironment * env)1426 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) {
1427   HBasicBlock* b = graph()->CreateBasicBlock();
1428   b->SetInitialEnvironment(env);
1429   return b;
1430 }
1431 
1432 
CreateLoopHeaderBlock()1433 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() {
1434   HBasicBlock* header = graph()->CreateBasicBlock();
1435   HEnvironment* entry_env = environment()->CopyAsLoopHeader(header);
1436   header->SetInitialEnvironment(entry_env);
1437   header->AttachLoopInformation();
1438   return header;
1439 }
1440 
1441 
BuildGetElementsKind(HValue * object)1442 HValue* HGraphBuilder::BuildGetElementsKind(HValue* object) {
1443   HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap());
1444 
1445   HValue* bit_field2 =
1446       Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField2());
1447   return BuildDecodeField<Map::ElementsKindBits>(bit_field2);
1448 }
1449 
1450 
BuildEnumLength(HValue * map)1451 HValue* HGraphBuilder::BuildEnumLength(HValue* map) {
1452   NoObservableSideEffectsScope scope(this);
1453   HValue* bit_field3 =
1454       Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField3());
1455   return BuildDecodeField<Map::EnumLengthBits>(bit_field3);
1456 }
1457 
1458 
BuildCheckHeapObject(HValue * obj)1459 HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) {
1460   if (obj->type().IsHeapObject()) return obj;
1461   return Add<HCheckHeapObject>(obj);
1462 }
1463 
FinishExitWithHardDeoptimization(DeoptimizeReason reason)1464 void HGraphBuilder::FinishExitWithHardDeoptimization(DeoptimizeReason reason) {
1465   Add<HDeoptimize>(reason, Deoptimizer::EAGER);
1466   FinishExitCurrentBlock(New<HAbnormalExit>());
1467 }
1468 
1469 
BuildCheckString(HValue * string)1470 HValue* HGraphBuilder::BuildCheckString(HValue* string) {
1471   if (!string->type().IsString()) {
1472     DCHECK(!string->IsConstant() ||
1473            !HConstant::cast(string)->HasStringValue());
1474     BuildCheckHeapObject(string);
1475     return Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING);
1476   }
1477   return string;
1478 }
1479 
BuildWrapReceiver(HValue * object,HValue * checked)1480 HValue* HGraphBuilder::BuildWrapReceiver(HValue* object, HValue* checked) {
1481   if (object->type().IsJSObject()) return object;
1482   HValue* function = checked->ActualValue();
1483   if (function->IsConstant() &&
1484       HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
1485     Handle<JSFunction> f = Handle<JSFunction>::cast(
1486         HConstant::cast(function)->handle(isolate()));
1487     SharedFunctionInfo* shared = f->shared();
1488     if (is_strict(shared->language_mode()) || shared->native()) return object;
1489   }
1490   return Add<HWrapReceiver>(object, checked);
1491 }
1492 
1493 
BuildCheckAndGrowElementsCapacity(HValue * object,HValue * elements,ElementsKind kind,HValue * length,HValue * capacity,HValue * key)1494 HValue* HGraphBuilder::BuildCheckAndGrowElementsCapacity(
1495     HValue* object, HValue* elements, ElementsKind kind, HValue* length,
1496     HValue* capacity, HValue* key) {
1497   HValue* max_gap = Add<HConstant>(static_cast<int32_t>(JSObject::kMaxGap));
1498   HValue* max_capacity = AddUncasted<HAdd>(capacity, max_gap);
1499   Add<HBoundsCheck>(key, max_capacity);
1500 
1501   HValue* new_capacity = BuildNewElementsCapacity(key);
1502   HValue* new_elements = BuildGrowElementsCapacity(object, elements, kind, kind,
1503                                                    length, new_capacity);
1504   return new_elements;
1505 }
1506 
1507 
BuildCheckForCapacityGrow(HValue * object,HValue * elements,ElementsKind kind,HValue * length,HValue * key,bool is_js_array,PropertyAccessType access_type)1508 HValue* HGraphBuilder::BuildCheckForCapacityGrow(
1509     HValue* object,
1510     HValue* elements,
1511     ElementsKind kind,
1512     HValue* length,
1513     HValue* key,
1514     bool is_js_array,
1515     PropertyAccessType access_type) {
1516   IfBuilder length_checker(this);
1517 
1518   Token::Value token = IsHoleyElementsKind(kind) ? Token::GTE : Token::EQ;
1519   length_checker.If<HCompareNumericAndBranch>(key, length, token);
1520 
1521   length_checker.Then();
1522 
1523   HValue* current_capacity = AddLoadFixedArrayLength(elements);
1524 
1525   if (top_info()->IsStub()) {
1526     IfBuilder capacity_checker(this);
1527     capacity_checker.If<HCompareNumericAndBranch>(key, current_capacity,
1528                                                   Token::GTE);
1529     capacity_checker.Then();
1530     HValue* new_elements = BuildCheckAndGrowElementsCapacity(
1531         object, elements, kind, length, current_capacity, key);
1532     environment()->Push(new_elements);
1533     capacity_checker.Else();
1534     environment()->Push(elements);
1535     capacity_checker.End();
1536   } else {
1537     HValue* result = Add<HMaybeGrowElements>(
1538         object, elements, key, current_capacity, is_js_array, kind);
1539     environment()->Push(result);
1540   }
1541 
1542   if (is_js_array) {
1543     HValue* new_length = AddUncasted<HAdd>(key, graph_->GetConstant1());
1544     new_length->ClearFlag(HValue::kCanOverflow);
1545 
1546     Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(kind),
1547                           new_length);
1548   }
1549 
1550   if (access_type == STORE && kind == FAST_SMI_ELEMENTS) {
1551     HValue* checked_elements = environment()->Top();
1552 
1553     // Write zero to ensure that the new element is initialized with some smi.
1554     Add<HStoreKeyed>(checked_elements, key, graph()->GetConstant0(), nullptr,
1555                      kind);
1556   }
1557 
1558   length_checker.Else();
1559   Add<HBoundsCheck>(key, length);
1560 
1561   environment()->Push(elements);
1562   length_checker.End();
1563 
1564   return environment()->Pop();
1565 }
1566 
1567 
BuildCopyElementsOnWrite(HValue * object,HValue * elements,ElementsKind kind,HValue * length)1568 HValue* HGraphBuilder::BuildCopyElementsOnWrite(HValue* object,
1569                                                 HValue* elements,
1570                                                 ElementsKind kind,
1571                                                 HValue* length) {
1572   Factory* factory = isolate()->factory();
1573 
1574   IfBuilder cow_checker(this);
1575 
1576   cow_checker.If<HCompareMap>(elements, factory->fixed_cow_array_map());
1577   cow_checker.Then();
1578 
1579   HValue* capacity = AddLoadFixedArrayLength(elements);
1580 
1581   HValue* new_elements = BuildGrowElementsCapacity(object, elements, kind,
1582                                                    kind, length, capacity);
1583 
1584   environment()->Push(new_elements);
1585 
1586   cow_checker.Else();
1587 
1588   environment()->Push(elements);
1589 
1590   cow_checker.End();
1591 
1592   return environment()->Pop();
1593 }
1594 
BuildElementIndexHash(HValue * index)1595 HValue* HGraphBuilder::BuildElementIndexHash(HValue* index) {
1596   int32_t seed_value = static_cast<uint32_t>(isolate()->heap()->HashSeed());
1597   HValue* seed = Add<HConstant>(seed_value);
1598   HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, index, seed);
1599 
1600   // hash = ~hash + (hash << 15);
1601   HValue* shifted_hash = AddUncasted<HShl>(hash, Add<HConstant>(15));
1602   HValue* not_hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash,
1603                                            graph()->GetConstantMinus1());
1604   hash = AddUncasted<HAdd>(shifted_hash, not_hash);
1605 
1606   // hash = hash ^ (hash >> 12);
1607   shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(12));
1608   hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
1609 
1610   // hash = hash + (hash << 2);
1611   shifted_hash = AddUncasted<HShl>(hash, Add<HConstant>(2));
1612   hash = AddUncasted<HAdd>(hash, shifted_hash);
1613 
1614   // hash = hash ^ (hash >> 4);
1615   shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(4));
1616   hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
1617 
1618   // hash = hash * 2057;
1619   hash = AddUncasted<HMul>(hash, Add<HConstant>(2057));
1620   hash->ClearFlag(HValue::kCanOverflow);
1621 
1622   // hash = hash ^ (hash >> 16);
1623   shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(16));
1624   return AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
1625 }
1626 
BuildUncheckedDictionaryElementLoad(HValue * receiver,HValue * elements,HValue * key,HValue * hash)1627 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver,
1628                                                            HValue* elements,
1629                                                            HValue* key,
1630                                                            HValue* hash) {
1631   HValue* capacity =
1632       Add<HLoadKeyed>(elements, Add<HConstant>(NameDictionary::kCapacityIndex),
1633                       nullptr, nullptr, FAST_ELEMENTS);
1634 
1635   HValue* mask = AddUncasted<HSub>(capacity, graph()->GetConstant1());
1636   mask->ChangeRepresentation(Representation::Integer32());
1637   mask->ClearFlag(HValue::kCanOverflow);
1638 
1639   HValue* entry = hash;
1640   HValue* count = graph()->GetConstant1();
1641   Push(entry);
1642   Push(count);
1643 
1644   HIfContinuation return_or_loop_continuation(graph()->CreateBasicBlock(),
1645                                               graph()->CreateBasicBlock());
1646   HIfContinuation found_key_match_continuation(graph()->CreateBasicBlock(),
1647                                                graph()->CreateBasicBlock());
1648   LoopBuilder probe_loop(this);
1649   probe_loop.BeginBody(2);  // Drop entry, count from last environment to
1650                             // appease live range building without simulates.
1651 
1652   count = Pop();
1653   entry = Pop();
1654   entry = AddUncasted<HBitwise>(Token::BIT_AND, entry, mask);
1655   int entry_size = SeededNumberDictionary::kEntrySize;
1656   HValue* base_index = AddUncasted<HMul>(entry, Add<HConstant>(entry_size));
1657   base_index->ClearFlag(HValue::kCanOverflow);
1658   int start_offset = SeededNumberDictionary::kElementsStartIndex;
1659   HValue* key_index =
1660       AddUncasted<HAdd>(base_index, Add<HConstant>(start_offset));
1661   key_index->ClearFlag(HValue::kCanOverflow);
1662 
1663   HValue* candidate_key =
1664       Add<HLoadKeyed>(elements, key_index, nullptr, nullptr, FAST_ELEMENTS);
1665   IfBuilder if_undefined(this);
1666   if_undefined.If<HCompareObjectEqAndBranch>(candidate_key,
1667                                              graph()->GetConstantUndefined());
1668   if_undefined.Then();
1669   {
1670     // element == undefined means "not found". Call the runtime.
1671     // TODO(jkummerow): walk the prototype chain instead.
1672     Add<HPushArguments>(receiver, key);
1673     Push(Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kKeyedGetProperty),
1674                            2));
1675   }
1676   if_undefined.Else();
1677   {
1678     IfBuilder if_match(this);
1679     if_match.If<HCompareObjectEqAndBranch>(candidate_key, key);
1680     if_match.Then();
1681     if_match.Else();
1682 
1683     // Update non-internalized string in the dictionary with internalized key?
1684     IfBuilder if_update_with_internalized(this);
1685     HValue* smi_check =
1686         if_update_with_internalized.IfNot<HIsSmiAndBranch>(candidate_key);
1687     if_update_with_internalized.And();
1688     HValue* map = AddLoadMap(candidate_key, smi_check);
1689     HValue* instance_type =
1690         Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapInstanceType());
1691     HValue* not_internalized_bit = AddUncasted<HBitwise>(
1692         Token::BIT_AND, instance_type,
1693         Add<HConstant>(static_cast<int>(kIsNotInternalizedMask)));
1694     if_update_with_internalized.If<HCompareNumericAndBranch>(
1695         not_internalized_bit, graph()->GetConstant0(), Token::NE);
1696     if_update_with_internalized.And();
1697     if_update_with_internalized.IfNot<HCompareObjectEqAndBranch>(
1698         candidate_key, graph()->GetConstantHole());
1699     if_update_with_internalized.AndIf<HStringCompareAndBranch>(candidate_key,
1700                                                                key, Token::EQ);
1701     if_update_with_internalized.Then();
1702     // Replace a key that is a non-internalized string by the equivalent
1703     // internalized string for faster further lookups.
1704     Add<HStoreKeyed>(elements, key_index, key, nullptr, FAST_ELEMENTS);
1705     if_update_with_internalized.Else();
1706 
1707     if_update_with_internalized.JoinContinuation(&found_key_match_continuation);
1708     if_match.JoinContinuation(&found_key_match_continuation);
1709 
1710     IfBuilder found_key_match(this, &found_key_match_continuation);
1711     found_key_match.Then();
1712     // Key at current probe matches. Relevant bits in the |details| field must
1713     // be zero, otherwise the dictionary element requires special handling.
1714     HValue* details_index =
1715         AddUncasted<HAdd>(base_index, Add<HConstant>(start_offset + 2));
1716     details_index->ClearFlag(HValue::kCanOverflow);
1717     HValue* details = Add<HLoadKeyed>(elements, details_index, nullptr, nullptr,
1718                                       FAST_ELEMENTS);
1719     int details_mask = PropertyDetails::KindField::kMask;
1720     details = AddUncasted<HBitwise>(Token::BIT_AND, details,
1721                                     Add<HConstant>(details_mask));
1722     IfBuilder details_compare(this);
1723     details_compare.If<HCompareNumericAndBranch>(details, New<HConstant>(kData),
1724                                                  Token::EQ);
1725     details_compare.Then();
1726     HValue* result_index =
1727         AddUncasted<HAdd>(base_index, Add<HConstant>(start_offset + 1));
1728     result_index->ClearFlag(HValue::kCanOverflow);
1729     Push(Add<HLoadKeyed>(elements, result_index, nullptr, nullptr,
1730                          FAST_ELEMENTS));
1731     details_compare.Else();
1732     Add<HPushArguments>(receiver, key);
1733     Push(Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kKeyedGetProperty),
1734                            2));
1735     details_compare.End();
1736 
1737     found_key_match.Else();
1738     found_key_match.JoinContinuation(&return_or_loop_continuation);
1739   }
1740   if_undefined.JoinContinuation(&return_or_loop_continuation);
1741 
1742   IfBuilder return_or_loop(this, &return_or_loop_continuation);
1743   return_or_loop.Then();
1744   probe_loop.Break();
1745 
1746   return_or_loop.Else();
1747   entry = AddUncasted<HAdd>(entry, count);
1748   entry->ClearFlag(HValue::kCanOverflow);
1749   count = AddUncasted<HAdd>(count, graph()->GetConstant1());
1750   count->ClearFlag(HValue::kCanOverflow);
1751   Push(entry);
1752   Push(count);
1753 
1754   probe_loop.EndBody();
1755 
1756   return_or_loop.End();
1757 
1758   return Pop();
1759 }
1760 
BuildCreateIterResultObject(HValue * value,HValue * done)1761 HValue* HGraphBuilder::BuildCreateIterResultObject(HValue* value,
1762                                                    HValue* done) {
1763   NoObservableSideEffectsScope scope(this);
1764 
1765   // Allocate the JSIteratorResult object.
1766   HValue* result =
1767       Add<HAllocate>(Add<HConstant>(JSIteratorResult::kSize), HType::JSObject(),
1768                      NOT_TENURED, JS_OBJECT_TYPE, graph()->GetConstant0());
1769 
1770   // Initialize the JSIteratorResult object.
1771   HValue* native_context = BuildGetNativeContext();
1772   HValue* map = Add<HLoadNamedField>(
1773       native_context, nullptr,
1774       HObjectAccess::ForContextSlot(Context::ITERATOR_RESULT_MAP_INDEX));
1775   Add<HStoreNamedField>(result, HObjectAccess::ForMap(), map);
1776   HValue* empty_fixed_array = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex);
1777   Add<HStoreNamedField>(result, HObjectAccess::ForPropertiesPointer(),
1778                         empty_fixed_array);
1779   Add<HStoreNamedField>(result, HObjectAccess::ForElementsPointer(),
1780                         empty_fixed_array);
1781   Add<HStoreNamedField>(result, HObjectAccess::ForObservableJSObjectOffset(
1782                                     JSIteratorResult::kValueOffset),
1783                         value);
1784   Add<HStoreNamedField>(result, HObjectAccess::ForObservableJSObjectOffset(
1785                                     JSIteratorResult::kDoneOffset),
1786                         done);
1787   STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
1788   return result;
1789 }
1790 
1791 
BuildNumberToString(HValue * object,AstType * type)1792 HValue* HGraphBuilder::BuildNumberToString(HValue* object, AstType* type) {
1793   NoObservableSideEffectsScope scope(this);
1794 
1795   // Convert constant numbers at compile time.
1796   if (object->IsConstant() && HConstant::cast(object)->HasNumberValue()) {
1797     Handle<Object> number = HConstant::cast(object)->handle(isolate());
1798     Handle<String> result = isolate()->factory()->NumberToString(number);
1799     return Add<HConstant>(result);
1800   }
1801 
1802   // Create a joinable continuation.
1803   HIfContinuation found(graph()->CreateBasicBlock(),
1804                         graph()->CreateBasicBlock());
1805 
1806   // Load the number string cache.
1807   HValue* number_string_cache =
1808       Add<HLoadRoot>(Heap::kNumberStringCacheRootIndex);
1809 
1810   // Make the hash mask from the length of the number string cache. It
1811   // contains two elements (number and string) for each cache entry.
1812   HValue* mask = AddLoadFixedArrayLength(number_string_cache);
1813   mask->set_type(HType::Smi());
1814   mask = AddUncasted<HSar>(mask, graph()->GetConstant1());
1815   mask = AddUncasted<HSub>(mask, graph()->GetConstant1());
1816 
1817   // Check whether object is a smi.
1818   IfBuilder if_objectissmi(this);
1819   if_objectissmi.If<HIsSmiAndBranch>(object);
1820   if_objectissmi.Then();
1821   {
1822     // Compute hash for smi similar to smi_get_hash().
1823     HValue* hash = AddUncasted<HBitwise>(Token::BIT_AND, object, mask);
1824 
1825     // Load the key.
1826     HValue* key_index = AddUncasted<HShl>(hash, graph()->GetConstant1());
1827     HValue* key = Add<HLoadKeyed>(number_string_cache, key_index, nullptr,
1828                                   nullptr, FAST_ELEMENTS, ALLOW_RETURN_HOLE);
1829 
1830     // Check if object == key.
1831     IfBuilder if_objectiskey(this);
1832     if_objectiskey.If<HCompareObjectEqAndBranch>(object, key);
1833     if_objectiskey.Then();
1834     {
1835       // Make the key_index available.
1836       Push(key_index);
1837     }
1838     if_objectiskey.JoinContinuation(&found);
1839   }
1840   if_objectissmi.Else();
1841   {
1842     if (type->Is(AstType::SignedSmall())) {
1843       if_objectissmi.Deopt(DeoptimizeReason::kExpectedSmi);
1844     } else {
1845       // Check if the object is a heap number.
1846       IfBuilder if_objectisnumber(this);
1847       HValue* objectisnumber = if_objectisnumber.If<HCompareMap>(
1848           object, isolate()->factory()->heap_number_map());
1849       if_objectisnumber.Then();
1850       {
1851         // Compute hash for heap number similar to double_get_hash().
1852         HValue* low = Add<HLoadNamedField>(
1853             object, objectisnumber,
1854             HObjectAccess::ForHeapNumberValueLowestBits());
1855         HValue* high = Add<HLoadNamedField>(
1856             object, objectisnumber,
1857             HObjectAccess::ForHeapNumberValueHighestBits());
1858         HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, low, high);
1859         hash = AddUncasted<HBitwise>(Token::BIT_AND, hash, mask);
1860 
1861         // Load the key.
1862         HValue* key_index = AddUncasted<HShl>(hash, graph()->GetConstant1());
1863         HValue* key =
1864             Add<HLoadKeyed>(number_string_cache, key_index, nullptr, nullptr,
1865                             FAST_ELEMENTS, ALLOW_RETURN_HOLE);
1866 
1867         // Check if the key is a heap number and compare it with the object.
1868         IfBuilder if_keyisnotsmi(this);
1869         HValue* keyisnotsmi = if_keyisnotsmi.IfNot<HIsSmiAndBranch>(key);
1870         if_keyisnotsmi.Then();
1871         {
1872           IfBuilder if_keyisheapnumber(this);
1873           if_keyisheapnumber.If<HCompareMap>(
1874               key, isolate()->factory()->heap_number_map());
1875           if_keyisheapnumber.Then();
1876           {
1877             // Check if values of key and object match.
1878             IfBuilder if_keyeqobject(this);
1879             if_keyeqobject.If<HCompareNumericAndBranch>(
1880                 Add<HLoadNamedField>(key, keyisnotsmi,
1881                                      HObjectAccess::ForHeapNumberValue()),
1882                 Add<HLoadNamedField>(object, objectisnumber,
1883                                      HObjectAccess::ForHeapNumberValue()),
1884                 Token::EQ);
1885             if_keyeqobject.Then();
1886             {
1887               // Make the key_index available.
1888               Push(key_index);
1889             }
1890             if_keyeqobject.JoinContinuation(&found);
1891           }
1892           if_keyisheapnumber.JoinContinuation(&found);
1893         }
1894         if_keyisnotsmi.JoinContinuation(&found);
1895       }
1896       if_objectisnumber.Else();
1897       {
1898         if (type->Is(AstType::Number())) {
1899           if_objectisnumber.Deopt(DeoptimizeReason::kExpectedHeapNumber);
1900         }
1901       }
1902       if_objectisnumber.JoinContinuation(&found);
1903     }
1904   }
1905   if_objectissmi.JoinContinuation(&found);
1906 
1907   // Check for cache hit.
1908   IfBuilder if_found(this, &found);
1909   if_found.Then();
1910   {
1911     // Count number to string operation in native code.
1912     AddIncrementCounter(isolate()->counters()->number_to_string_native());
1913 
1914     // Load the value in case of cache hit.
1915     HValue* key_index = Pop();
1916     HValue* value_index = AddUncasted<HAdd>(key_index, graph()->GetConstant1());
1917     Push(Add<HLoadKeyed>(number_string_cache, value_index, nullptr, nullptr,
1918                          FAST_ELEMENTS, ALLOW_RETURN_HOLE));
1919   }
1920   if_found.Else();
1921   {
1922     // Cache miss, fallback to runtime.
1923     Add<HPushArguments>(object);
1924     Push(Add<HCallRuntime>(
1925             Runtime::FunctionForId(Runtime::kNumberToStringSkipCache),
1926             1));
1927   }
1928   if_found.End();
1929 
1930   return Pop();
1931 }
1932 
BuildToNumber(HValue * input)1933 HValue* HGraphBuilder::BuildToNumber(HValue* input) {
1934   if (input->type().IsTaggedNumber() ||
1935       input->representation().IsSpecialization()) {
1936     return input;
1937   }
1938   Callable callable = CodeFactory::ToNumber(isolate());
1939   HValue* stub = Add<HConstant>(callable.code());
1940   HValue* values[] = {input};
1941   HCallWithDescriptor* instr = Add<HCallWithDescriptor>(
1942       stub, 0, callable.descriptor(), ArrayVector(values));
1943   instr->set_type(HType::TaggedNumber());
1944   return instr;
1945 }
1946 
1947 
BuildToObject(HValue * receiver)1948 HValue* HGraphBuilder::BuildToObject(HValue* receiver) {
1949   NoObservableSideEffectsScope scope(this);
1950 
1951   // Create a joinable continuation.
1952   HIfContinuation wrap(graph()->CreateBasicBlock(),
1953                        graph()->CreateBasicBlock());
1954 
1955   // Determine the proper global constructor function required to wrap
1956   // {receiver} into a JSValue, unless {receiver} is already a {JSReceiver}, in
1957   // which case we just return it.  Deopts to Runtime::kToObject if {receiver}
1958   // is undefined or null.
1959   IfBuilder receiver_is_smi(this);
1960   receiver_is_smi.If<HIsSmiAndBranch>(receiver);
1961   receiver_is_smi.Then();
1962   {
1963     // Use global Number function.
1964     Push(Add<HConstant>(Context::NUMBER_FUNCTION_INDEX));
1965   }
1966   receiver_is_smi.Else();
1967   {
1968     // Determine {receiver} map and instance type.
1969     HValue* receiver_map =
1970         Add<HLoadNamedField>(receiver, nullptr, HObjectAccess::ForMap());
1971     HValue* receiver_instance_type = Add<HLoadNamedField>(
1972         receiver_map, nullptr, HObjectAccess::ForMapInstanceType());
1973 
1974     // First check whether {receiver} is already a spec object (fast case).
1975     IfBuilder receiver_is_not_spec_object(this);
1976     receiver_is_not_spec_object.If<HCompareNumericAndBranch>(
1977         receiver_instance_type, Add<HConstant>(FIRST_JS_RECEIVER_TYPE),
1978         Token::LT);
1979     receiver_is_not_spec_object.Then();
1980     {
1981       // Load the constructor function index from the {receiver} map.
1982       HValue* constructor_function_index = Add<HLoadNamedField>(
1983           receiver_map, nullptr,
1984           HObjectAccess::ForMapInObjectPropertiesOrConstructorFunctionIndex());
1985 
1986       // Check if {receiver} has a constructor (null and undefined have no
1987       // constructors, so we deoptimize to the runtime to throw an exception).
1988       IfBuilder constructor_function_index_is_invalid(this);
1989       constructor_function_index_is_invalid.If<HCompareNumericAndBranch>(
1990           constructor_function_index,
1991           Add<HConstant>(Map::kNoConstructorFunctionIndex), Token::EQ);
1992       constructor_function_index_is_invalid.ThenDeopt(
1993           DeoptimizeReason::kUndefinedOrNullInToObject);
1994       constructor_function_index_is_invalid.End();
1995 
1996       // Use the global constructor function.
1997       Push(constructor_function_index);
1998     }
1999     receiver_is_not_spec_object.JoinContinuation(&wrap);
2000   }
2001   receiver_is_smi.JoinContinuation(&wrap);
2002 
2003   // Wrap the receiver if necessary.
2004   IfBuilder if_wrap(this, &wrap);
2005   if_wrap.Then();
2006   {
2007     // Grab the constructor function index.
2008     HValue* constructor_index = Pop();
2009 
2010     // Load native context.
2011     HValue* native_context = BuildGetNativeContext();
2012 
2013     // Determine the initial map for the global constructor.
2014     HValue* constructor = Add<HLoadKeyed>(native_context, constructor_index,
2015                                           nullptr, nullptr, FAST_ELEMENTS);
2016     HValue* constructor_initial_map = Add<HLoadNamedField>(
2017         constructor, nullptr, HObjectAccess::ForPrototypeOrInitialMap());
2018     // Allocate and initialize a JSValue wrapper.
2019     HValue* value =
2020         BuildAllocate(Add<HConstant>(JSValue::kSize), HType::JSObject(),
2021                       JS_VALUE_TYPE, HAllocationMode());
2022     Add<HStoreNamedField>(value, HObjectAccess::ForMap(),
2023                           constructor_initial_map);
2024     HValue* empty_fixed_array = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex);
2025     Add<HStoreNamedField>(value, HObjectAccess::ForPropertiesPointer(),
2026                           empty_fixed_array);
2027     Add<HStoreNamedField>(value, HObjectAccess::ForElementsPointer(),
2028                           empty_fixed_array);
2029     Add<HStoreNamedField>(value, HObjectAccess::ForObservableJSObjectOffset(
2030                                      JSValue::kValueOffset),
2031                           receiver);
2032     Push(value);
2033   }
2034   if_wrap.Else();
2035   { Push(receiver); }
2036   if_wrap.End();
2037   return Pop();
2038 }
2039 
2040 
BuildAllocate(HValue * object_size,HType type,InstanceType instance_type,HAllocationMode allocation_mode)2041 HAllocate* HGraphBuilder::BuildAllocate(
2042     HValue* object_size,
2043     HType type,
2044     InstanceType instance_type,
2045     HAllocationMode allocation_mode) {
2046   // Compute the effective allocation size.
2047   HValue* size = object_size;
2048   if (allocation_mode.CreateAllocationMementos()) {
2049     size = AddUncasted<HAdd>(size, Add<HConstant>(AllocationMemento::kSize));
2050     size->ClearFlag(HValue::kCanOverflow);
2051   }
2052 
2053   // Perform the actual allocation.
2054   HAllocate* object = Add<HAllocate>(
2055       size, type, allocation_mode.GetPretenureMode(), instance_type,
2056       graph()->GetConstant0(), allocation_mode.feedback_site());
2057 
2058   // Setup the allocation memento.
2059   if (allocation_mode.CreateAllocationMementos()) {
2060     BuildCreateAllocationMemento(
2061         object, object_size, allocation_mode.current_site());
2062   }
2063 
2064   return object;
2065 }
2066 
2067 
BuildAddStringLengths(HValue * left_length,HValue * right_length)2068 HValue* HGraphBuilder::BuildAddStringLengths(HValue* left_length,
2069                                              HValue* right_length) {
2070   // Compute the combined string length and check against max string length.
2071   HValue* length = AddUncasted<HAdd>(left_length, right_length);
2072   // Check that length <= kMaxLength <=> length < MaxLength + 1.
2073   HValue* max_length = Add<HConstant>(String::kMaxLength + 1);
2074   if (top_info()->IsStub() || !isolate()->IsStringLengthOverflowIntact()) {
2075     // This is a mitigation for crbug.com/627934; the real fix
2076     // will be to migrate the StringAddStub to TurboFan one day.
2077     IfBuilder if_invalid(this);
2078     if_invalid.If<HCompareNumericAndBranch>(length, max_length, Token::GT);
2079     if_invalid.Then();
2080     {
2081       Add<HCallRuntime>(
2082           Runtime::FunctionForId(Runtime::kThrowInvalidStringLength), 0);
2083     }
2084     if_invalid.End();
2085   } else {
2086     graph()->MarkDependsOnStringLengthOverflow();
2087     Add<HBoundsCheck>(length, max_length);
2088   }
2089   return length;
2090 }
2091 
2092 
BuildCreateConsString(HValue * length,HValue * left,HValue * right,HAllocationMode allocation_mode)2093 HValue* HGraphBuilder::BuildCreateConsString(
2094     HValue* length,
2095     HValue* left,
2096     HValue* right,
2097     HAllocationMode allocation_mode) {
2098   // Determine the string instance types.
2099   HInstruction* left_instance_type = AddLoadStringInstanceType(left);
2100   HInstruction* right_instance_type = AddLoadStringInstanceType(right);
2101 
2102   // Allocate the cons string object. HAllocate does not care whether we
2103   // pass CONS_STRING_TYPE or CONS_ONE_BYTE_STRING_TYPE here, so we just use
2104   // CONS_STRING_TYPE here. Below we decide whether the cons string is
2105   // one-byte or two-byte and set the appropriate map.
2106   DCHECK(HAllocate::CompatibleInstanceTypes(CONS_STRING_TYPE,
2107                                             CONS_ONE_BYTE_STRING_TYPE));
2108   HAllocate* result = BuildAllocate(Add<HConstant>(ConsString::kSize),
2109                                     HType::String(), CONS_STRING_TYPE,
2110                                     allocation_mode);
2111 
2112   // Compute intersection and difference of instance types.
2113   HValue* anded_instance_types = AddUncasted<HBitwise>(
2114       Token::BIT_AND, left_instance_type, right_instance_type);
2115   HValue* xored_instance_types = AddUncasted<HBitwise>(
2116       Token::BIT_XOR, left_instance_type, right_instance_type);
2117 
2118   // We create a one-byte cons string if
2119   // 1. both strings are one-byte, or
2120   // 2. at least one of the strings is two-byte, but happens to contain only
2121   //    one-byte characters.
2122   // To do this, we check
2123   // 1. if both strings are one-byte, or if the one-byte data hint is set in
2124   //    both strings, or
2125   // 2. if one of the strings has the one-byte data hint set and the other
2126   //    string is one-byte.
2127   IfBuilder if_onebyte(this);
2128   STATIC_ASSERT(kOneByteStringTag != 0);
2129   STATIC_ASSERT(kOneByteDataHintMask != 0);
2130   if_onebyte.If<HCompareNumericAndBranch>(
2131       AddUncasted<HBitwise>(
2132           Token::BIT_AND, anded_instance_types,
2133           Add<HConstant>(static_cast<int32_t>(
2134                   kStringEncodingMask | kOneByteDataHintMask))),
2135       graph()->GetConstant0(), Token::NE);
2136   if_onebyte.Or();
2137   STATIC_ASSERT(kOneByteStringTag != 0 &&
2138                 kOneByteDataHintTag != 0 &&
2139                 kOneByteDataHintTag != kOneByteStringTag);
2140   if_onebyte.If<HCompareNumericAndBranch>(
2141       AddUncasted<HBitwise>(
2142           Token::BIT_AND, xored_instance_types,
2143           Add<HConstant>(static_cast<int32_t>(
2144                   kOneByteStringTag | kOneByteDataHintTag))),
2145       Add<HConstant>(static_cast<int32_t>(
2146               kOneByteStringTag | kOneByteDataHintTag)), Token::EQ);
2147   if_onebyte.Then();
2148   {
2149     // We can safely skip the write barrier for storing the map here.
2150     Add<HStoreNamedField>(
2151         result, HObjectAccess::ForMap(),
2152         Add<HConstant>(isolate()->factory()->cons_one_byte_string_map()));
2153   }
2154   if_onebyte.Else();
2155   {
2156     // We can safely skip the write barrier for storing the map here.
2157     Add<HStoreNamedField>(
2158         result, HObjectAccess::ForMap(),
2159         Add<HConstant>(isolate()->factory()->cons_string_map()));
2160   }
2161   if_onebyte.End();
2162 
2163   // Initialize the cons string fields.
2164   Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(),
2165                         Add<HConstant>(String::kEmptyHashField));
2166   Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length);
2167   Add<HStoreNamedField>(result, HObjectAccess::ForConsStringFirst(), left);
2168   Add<HStoreNamedField>(result, HObjectAccess::ForConsStringSecond(), right);
2169 
2170   // Count the native string addition.
2171   AddIncrementCounter(isolate()->counters()->string_add_native());
2172 
2173   return result;
2174 }
2175 
2176 
BuildCopySeqStringChars(HValue * src,HValue * src_offset,String::Encoding src_encoding,HValue * dst,HValue * dst_offset,String::Encoding dst_encoding,HValue * length)2177 void HGraphBuilder::BuildCopySeqStringChars(HValue* src,
2178                                             HValue* src_offset,
2179                                             String::Encoding src_encoding,
2180                                             HValue* dst,
2181                                             HValue* dst_offset,
2182                                             String::Encoding dst_encoding,
2183                                             HValue* length) {
2184   DCHECK(dst_encoding != String::ONE_BYTE_ENCODING ||
2185          src_encoding == String::ONE_BYTE_ENCODING);
2186   LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement);
2187   HValue* index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT);
2188   {
2189     HValue* src_index = AddUncasted<HAdd>(src_offset, index);
2190     HValue* value =
2191         AddUncasted<HSeqStringGetChar>(src_encoding, src, src_index);
2192     HValue* dst_index = AddUncasted<HAdd>(dst_offset, index);
2193     Add<HSeqStringSetChar>(dst_encoding, dst, dst_index, value);
2194   }
2195   loop.EndBody();
2196 }
2197 
2198 
BuildObjectSizeAlignment(HValue * unaligned_size,int header_size)2199 HValue* HGraphBuilder::BuildObjectSizeAlignment(
2200     HValue* unaligned_size, int header_size) {
2201   DCHECK((header_size & kObjectAlignmentMask) == 0);
2202   HValue* size = AddUncasted<HAdd>(
2203       unaligned_size, Add<HConstant>(static_cast<int32_t>(
2204           header_size + kObjectAlignmentMask)));
2205   size->ClearFlag(HValue::kCanOverflow);
2206   return AddUncasted<HBitwise>(
2207       Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>(
2208           ~kObjectAlignmentMask)));
2209 }
2210 
2211 
BuildUncheckedStringAdd(HValue * left,HValue * right,HAllocationMode allocation_mode)2212 HValue* HGraphBuilder::BuildUncheckedStringAdd(
2213     HValue* left,
2214     HValue* right,
2215     HAllocationMode allocation_mode) {
2216   // Determine the string lengths.
2217   HValue* left_length = AddLoadStringLength(left);
2218   HValue* right_length = AddLoadStringLength(right);
2219 
2220   // Compute the combined string length.
2221   HValue* length = BuildAddStringLengths(left_length, right_length);
2222 
2223   // Do some manual constant folding here.
2224   if (left_length->IsConstant()) {
2225     HConstant* c_left_length = HConstant::cast(left_length);
2226     DCHECK_NE(0, c_left_length->Integer32Value());
2227     if (c_left_length->Integer32Value() + 1 >= ConsString::kMinLength) {
2228       // The right string contains at least one character.
2229       return BuildCreateConsString(length, left, right, allocation_mode);
2230     }
2231   } else if (right_length->IsConstant()) {
2232     HConstant* c_right_length = HConstant::cast(right_length);
2233     DCHECK_NE(0, c_right_length->Integer32Value());
2234     if (c_right_length->Integer32Value() + 1 >= ConsString::kMinLength) {
2235       // The left string contains at least one character.
2236       return BuildCreateConsString(length, left, right, allocation_mode);
2237     }
2238   }
2239 
2240   // Check if we should create a cons string.
2241   IfBuilder if_createcons(this);
2242   if_createcons.If<HCompareNumericAndBranch>(
2243       length, Add<HConstant>(ConsString::kMinLength), Token::GTE);
2244   if_createcons.And();
2245   if_createcons.If<HCompareNumericAndBranch>(
2246       length, Add<HConstant>(ConsString::kMaxLength), Token::LTE);
2247   if_createcons.Then();
2248   {
2249     // Create a cons string.
2250     Push(BuildCreateConsString(length, left, right, allocation_mode));
2251   }
2252   if_createcons.Else();
2253   {
2254     // Determine the string instance types.
2255     HValue* left_instance_type = AddLoadStringInstanceType(left);
2256     HValue* right_instance_type = AddLoadStringInstanceType(right);
2257 
2258     // Compute union and difference of instance types.
2259     HValue* ored_instance_types = AddUncasted<HBitwise>(
2260         Token::BIT_OR, left_instance_type, right_instance_type);
2261     HValue* xored_instance_types = AddUncasted<HBitwise>(
2262         Token::BIT_XOR, left_instance_type, right_instance_type);
2263 
2264     // Check if both strings have the same encoding and both are
2265     // sequential.
2266     IfBuilder if_sameencodingandsequential(this);
2267     if_sameencodingandsequential.If<HCompareNumericAndBranch>(
2268         AddUncasted<HBitwise>(
2269             Token::BIT_AND, xored_instance_types,
2270             Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))),
2271         graph()->GetConstant0(), Token::EQ);
2272     if_sameencodingandsequential.And();
2273     STATIC_ASSERT(kSeqStringTag == 0);
2274     if_sameencodingandsequential.If<HCompareNumericAndBranch>(
2275         AddUncasted<HBitwise>(
2276             Token::BIT_AND, ored_instance_types,
2277             Add<HConstant>(static_cast<int32_t>(kStringRepresentationMask))),
2278         graph()->GetConstant0(), Token::EQ);
2279     if_sameencodingandsequential.Then();
2280     {
2281       HConstant* string_map =
2282           Add<HConstant>(isolate()->factory()->string_map());
2283       HConstant* one_byte_string_map =
2284           Add<HConstant>(isolate()->factory()->one_byte_string_map());
2285 
2286       // Determine map and size depending on whether result is one-byte string.
2287       IfBuilder if_onebyte(this);
2288       STATIC_ASSERT(kOneByteStringTag != 0);
2289       if_onebyte.If<HCompareNumericAndBranch>(
2290           AddUncasted<HBitwise>(
2291               Token::BIT_AND, ored_instance_types,
2292               Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))),
2293           graph()->GetConstant0(), Token::NE);
2294       if_onebyte.Then();
2295       {
2296         // Allocate sequential one-byte string object.
2297         Push(length);
2298         Push(one_byte_string_map);
2299       }
2300       if_onebyte.Else();
2301       {
2302         // Allocate sequential two-byte string object.
2303         HValue* size = AddUncasted<HShl>(length, graph()->GetConstant1());
2304         size->ClearFlag(HValue::kCanOverflow);
2305         size->SetFlag(HValue::kUint32);
2306         Push(size);
2307         Push(string_map);
2308       }
2309       if_onebyte.End();
2310       HValue* map = Pop();
2311 
2312       // Calculate the number of bytes needed for the characters in the
2313       // string while observing object alignment.
2314       STATIC_ASSERT((SeqString::kHeaderSize & kObjectAlignmentMask) == 0);
2315       HValue* size = BuildObjectSizeAlignment(Pop(), SeqString::kHeaderSize);
2316 
2317       IfBuilder if_size(this);
2318       if_size.If<HCompareNumericAndBranch>(
2319           size, Add<HConstant>(kMaxRegularHeapObjectSize), Token::LT);
2320       if_size.Then();
2321       {
2322         // Allocate the string object. HAllocate does not care whether we pass
2323         // STRING_TYPE or ONE_BYTE_STRING_TYPE here, so we just use STRING_TYPE.
2324         HAllocate* result =
2325             BuildAllocate(size, HType::String(), STRING_TYPE, allocation_mode);
2326         Add<HStoreNamedField>(result, HObjectAccess::ForMap(), map);
2327 
2328         // Initialize the string fields.
2329         Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(),
2330                               Add<HConstant>(String::kEmptyHashField));
2331         Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length);
2332 
2333         // Copy characters to the result string.
2334         IfBuilder if_twobyte(this);
2335         if_twobyte.If<HCompareObjectEqAndBranch>(map, string_map);
2336         if_twobyte.Then();
2337         {
2338           // Copy characters from the left string.
2339           BuildCopySeqStringChars(
2340               left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, result,
2341               graph()->GetConstant0(), String::TWO_BYTE_ENCODING, left_length);
2342 
2343           // Copy characters from the right string.
2344           BuildCopySeqStringChars(
2345               right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, result,
2346               left_length, String::TWO_BYTE_ENCODING, right_length);
2347         }
2348         if_twobyte.Else();
2349         {
2350           // Copy characters from the left string.
2351           BuildCopySeqStringChars(
2352               left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, result,
2353               graph()->GetConstant0(), String::ONE_BYTE_ENCODING, left_length);
2354 
2355           // Copy characters from the right string.
2356           BuildCopySeqStringChars(
2357               right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, result,
2358               left_length, String::ONE_BYTE_ENCODING, right_length);
2359         }
2360         if_twobyte.End();
2361 
2362         // Count the native string addition.
2363         AddIncrementCounter(isolate()->counters()->string_add_native());
2364 
2365         // Return the sequential string.
2366         Push(result);
2367       }
2368       if_size.Else();
2369       {
2370         // Fallback to the runtime to add the two strings. The string has to be
2371         // allocated in LO space.
2372         Add<HPushArguments>(left, right);
2373         Push(Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kStringAdd), 2));
2374       }
2375       if_size.End();
2376     }
2377     if_sameencodingandsequential.Else();
2378     {
2379       // Fallback to the runtime to add the two strings.
2380       Add<HPushArguments>(left, right);
2381       Push(Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kStringAdd), 2));
2382     }
2383     if_sameencodingandsequential.End();
2384   }
2385   if_createcons.End();
2386 
2387   return Pop();
2388 }
2389 
2390 
BuildStringAdd(HValue * left,HValue * right,HAllocationMode allocation_mode)2391 HValue* HGraphBuilder::BuildStringAdd(
2392     HValue* left,
2393     HValue* right,
2394     HAllocationMode allocation_mode) {
2395   NoObservableSideEffectsScope no_effects(this);
2396 
2397   // Determine string lengths.
2398   HValue* left_length = AddLoadStringLength(left);
2399   HValue* right_length = AddLoadStringLength(right);
2400 
2401   // Check if left string is empty.
2402   IfBuilder if_leftempty(this);
2403   if_leftempty.If<HCompareNumericAndBranch>(
2404       left_length, graph()->GetConstant0(), Token::EQ);
2405   if_leftempty.Then();
2406   {
2407     // Count the native string addition.
2408     AddIncrementCounter(isolate()->counters()->string_add_native());
2409 
2410     // Just return the right string.
2411     Push(right);
2412   }
2413   if_leftempty.Else();
2414   {
2415     // Check if right string is empty.
2416     IfBuilder if_rightempty(this);
2417     if_rightempty.If<HCompareNumericAndBranch>(
2418         right_length, graph()->GetConstant0(), Token::EQ);
2419     if_rightempty.Then();
2420     {
2421       // Count the native string addition.
2422       AddIncrementCounter(isolate()->counters()->string_add_native());
2423 
2424       // Just return the left string.
2425       Push(left);
2426     }
2427     if_rightempty.Else();
2428     {
2429       // Add the two non-empty strings.
2430       Push(BuildUncheckedStringAdd(left, right, allocation_mode));
2431     }
2432     if_rightempty.End();
2433   }
2434   if_leftempty.End();
2435 
2436   return Pop();
2437 }
2438 
2439 
BuildUncheckedMonomorphicElementAccess(HValue * checked_object,HValue * key,HValue * val,bool is_js_array,ElementsKind elements_kind,PropertyAccessType access_type,LoadKeyedHoleMode load_mode,KeyedAccessStoreMode store_mode)2440 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
2441     HValue* checked_object,
2442     HValue* key,
2443     HValue* val,
2444     bool is_js_array,
2445     ElementsKind elements_kind,
2446     PropertyAccessType access_type,
2447     LoadKeyedHoleMode load_mode,
2448     KeyedAccessStoreMode store_mode) {
2449   DCHECK(top_info()->IsStub() || checked_object->IsCompareMap() ||
2450          checked_object->IsCheckMaps());
2451   DCHECK(!IsFixedTypedArrayElementsKind(elements_kind) || !is_js_array);
2452   // No GVNFlag is necessary for ElementsKind if there is an explicit dependency
2453   // on a HElementsTransition instruction. The flag can also be removed if the
2454   // map to check has FAST_HOLEY_ELEMENTS, since there can be no further
2455   // ElementsKind transitions. Finally, the dependency can be removed for stores
2456   // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the
2457   // generated store code.
2458   if ((elements_kind == FAST_HOLEY_ELEMENTS) ||
2459       (elements_kind == FAST_ELEMENTS && access_type == STORE)) {
2460     checked_object->ClearDependsOnFlag(kElementsKind);
2461   }
2462 
2463   bool fast_smi_only_elements = IsFastSmiElementsKind(elements_kind);
2464   bool fast_elements = IsFastObjectElementsKind(elements_kind);
2465   HValue* elements = AddLoadElements(checked_object);
2466   if (access_type == STORE && (fast_elements || fast_smi_only_elements) &&
2467       store_mode != STORE_NO_TRANSITION_HANDLE_COW) {
2468     HCheckMaps* check_cow_map = Add<HCheckMaps>(
2469         elements, isolate()->factory()->fixed_array_map());
2470     check_cow_map->ClearDependsOnFlag(kElementsKind);
2471   }
2472   HInstruction* length = NULL;
2473   if (is_js_array) {
2474     length = Add<HLoadNamedField>(
2475         checked_object->ActualValue(), checked_object,
2476         HObjectAccess::ForArrayLength(elements_kind));
2477   } else {
2478     length = AddLoadFixedArrayLength(elements);
2479   }
2480   length->set_type(HType::Smi());
2481   HValue* checked_key = NULL;
2482   if (IsFixedTypedArrayElementsKind(elements_kind)) {
2483     checked_object = Add<HCheckArrayBufferNotNeutered>(checked_object);
2484 
2485     HValue* external_pointer = Add<HLoadNamedField>(
2486         elements, nullptr,
2487         HObjectAccess::ForFixedTypedArrayBaseExternalPointer());
2488     HValue* base_pointer = Add<HLoadNamedField>(
2489         elements, nullptr, HObjectAccess::ForFixedTypedArrayBaseBasePointer());
2490     HValue* backing_store = AddUncasted<HAdd>(external_pointer, base_pointer,
2491                                               AddOfExternalAndTagged);
2492 
2493     if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
2494       NoObservableSideEffectsScope no_effects(this);
2495       IfBuilder length_checker(this);
2496       length_checker.If<HCompareNumericAndBranch>(key, length, Token::LT);
2497       length_checker.Then();
2498       IfBuilder negative_checker(this);
2499       HValue* bounds_check = negative_checker.If<HCompareNumericAndBranch>(
2500           key, graph()->GetConstant0(), Token::GTE);
2501       negative_checker.Then();
2502       HInstruction* result = AddElementAccess(
2503           backing_store, key, val, bounds_check, checked_object->ActualValue(),
2504           elements_kind, access_type);
2505       negative_checker.ElseDeopt(DeoptimizeReason::kNegativeKeyEncountered);
2506       negative_checker.End();
2507       length_checker.End();
2508       return result;
2509     } else {
2510       DCHECK(store_mode == STANDARD_STORE);
2511       checked_key = Add<HBoundsCheck>(key, length);
2512       return AddElementAccess(backing_store, checked_key, val, checked_object,
2513                               checked_object->ActualValue(), elements_kind,
2514                               access_type);
2515     }
2516   }
2517   DCHECK(fast_smi_only_elements ||
2518          fast_elements ||
2519          IsFastDoubleElementsKind(elements_kind));
2520 
2521   // In case val is stored into a fast smi array, assure that the value is a smi
2522   // before manipulating the backing store. Otherwise the actual store may
2523   // deopt, leaving the backing store in an invalid state.
2524   if (access_type == STORE && IsFastSmiElementsKind(elements_kind) &&
2525       !val->type().IsSmi()) {
2526     val = AddUncasted<HForceRepresentation>(val, Representation::Smi());
2527   }
2528 
2529   if (IsGrowStoreMode(store_mode)) {
2530     NoObservableSideEffectsScope no_effects(this);
2531     Representation representation = HStoreKeyed::RequiredValueRepresentation(
2532         elements_kind, STORE_TO_INITIALIZED_ENTRY);
2533     val = AddUncasted<HForceRepresentation>(val, representation);
2534     elements = BuildCheckForCapacityGrow(checked_object, elements,
2535                                          elements_kind, length, key,
2536                                          is_js_array, access_type);
2537     checked_key = key;
2538   } else {
2539     checked_key = Add<HBoundsCheck>(key, length);
2540 
2541     if (access_type == STORE && (fast_elements || fast_smi_only_elements)) {
2542       if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) {
2543         NoObservableSideEffectsScope no_effects(this);
2544         elements = BuildCopyElementsOnWrite(checked_object, elements,
2545                                             elements_kind, length);
2546       } else {
2547         HCheckMaps* check_cow_map = Add<HCheckMaps>(
2548             elements, isolate()->factory()->fixed_array_map());
2549         check_cow_map->ClearDependsOnFlag(kElementsKind);
2550       }
2551     }
2552   }
2553   return AddElementAccess(elements, checked_key, val, checked_object, nullptr,
2554                           elements_kind, access_type, load_mode);
2555 }
2556 
2557 
BuildCalculateElementsSize(ElementsKind kind,HValue * capacity)2558 HValue* HGraphBuilder::BuildCalculateElementsSize(ElementsKind kind,
2559                                                   HValue* capacity) {
2560   int elements_size = IsFastDoubleElementsKind(kind)
2561       ? kDoubleSize
2562       : kPointerSize;
2563 
2564   HConstant* elements_size_value = Add<HConstant>(elements_size);
2565   HInstruction* mul =
2566       HMul::NewImul(isolate(), zone(), context(), capacity->ActualValue(),
2567                     elements_size_value);
2568   AddInstruction(mul);
2569   mul->ClearFlag(HValue::kCanOverflow);
2570 
2571   STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize);
2572 
2573   HConstant* header_size = Add<HConstant>(FixedArray::kHeaderSize);
2574   HValue* total_size = AddUncasted<HAdd>(mul, header_size);
2575   total_size->ClearFlag(HValue::kCanOverflow);
2576   return total_size;
2577 }
2578 
2579 
AllocateJSArrayObject(AllocationSiteMode mode)2580 HAllocate* HGraphBuilder::AllocateJSArrayObject(AllocationSiteMode mode) {
2581   int base_size = JSArray::kSize;
2582   if (mode == TRACK_ALLOCATION_SITE) {
2583     base_size += AllocationMemento::kSize;
2584   }
2585   HConstant* size_in_bytes = Add<HConstant>(base_size);
2586   return Add<HAllocate>(size_in_bytes, HType::JSArray(), NOT_TENURED,
2587                         JS_OBJECT_TYPE, graph()->GetConstant0());
2588 }
2589 
2590 
EstablishElementsAllocationSize(ElementsKind kind,int capacity)2591 HConstant* HGraphBuilder::EstablishElementsAllocationSize(
2592     ElementsKind kind,
2593     int capacity) {
2594   int base_size = IsFastDoubleElementsKind(kind)
2595       ? FixedDoubleArray::SizeFor(capacity)
2596       : FixedArray::SizeFor(capacity);
2597 
2598   return Add<HConstant>(base_size);
2599 }
2600 
2601 
BuildAllocateElements(ElementsKind kind,HValue * size_in_bytes)2602 HAllocate* HGraphBuilder::BuildAllocateElements(ElementsKind kind,
2603                                                 HValue* size_in_bytes) {
2604   InstanceType instance_type = IsFastDoubleElementsKind(kind)
2605       ? FIXED_DOUBLE_ARRAY_TYPE
2606       : FIXED_ARRAY_TYPE;
2607 
2608   return Add<HAllocate>(size_in_bytes, HType::HeapObject(), NOT_TENURED,
2609                         instance_type, graph()->GetConstant0());
2610 }
2611 
2612 
BuildInitializeElementsHeader(HValue * elements,ElementsKind kind,HValue * capacity)2613 void HGraphBuilder::BuildInitializeElementsHeader(HValue* elements,
2614                                                   ElementsKind kind,
2615                                                   HValue* capacity) {
2616   Factory* factory = isolate()->factory();
2617   Handle<Map> map = IsFastDoubleElementsKind(kind)
2618       ? factory->fixed_double_array_map()
2619       : factory->fixed_array_map();
2620 
2621   Add<HStoreNamedField>(elements, HObjectAccess::ForMap(), Add<HConstant>(map));
2622   Add<HStoreNamedField>(elements, HObjectAccess::ForFixedArrayLength(),
2623                         capacity);
2624 }
2625 
2626 
BuildAllocateAndInitializeArray(ElementsKind kind,HValue * capacity)2627 HValue* HGraphBuilder::BuildAllocateAndInitializeArray(ElementsKind kind,
2628                                                        HValue* capacity) {
2629   // The HForceRepresentation is to prevent possible deopt on int-smi
2630   // conversion after allocation but before the new object fields are set.
2631   capacity = AddUncasted<HForceRepresentation>(capacity, Representation::Smi());
2632   HValue* size_in_bytes = BuildCalculateElementsSize(kind, capacity);
2633   HValue* new_array = BuildAllocateElements(kind, size_in_bytes);
2634   BuildInitializeElementsHeader(new_array, kind, capacity);
2635   return new_array;
2636 }
2637 
2638 
BuildJSArrayHeader(HValue * array,HValue * array_map,HValue * elements,AllocationSiteMode mode,ElementsKind elements_kind,HValue * allocation_site_payload,HValue * length_field)2639 void HGraphBuilder::BuildJSArrayHeader(HValue* array,
2640                                        HValue* array_map,
2641                                        HValue* elements,
2642                                        AllocationSiteMode mode,
2643                                        ElementsKind elements_kind,
2644                                        HValue* allocation_site_payload,
2645                                        HValue* length_field) {
2646   Add<HStoreNamedField>(array, HObjectAccess::ForMap(), array_map);
2647 
2648   HValue* empty_fixed_array = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex);
2649 
2650   Add<HStoreNamedField>(
2651       array, HObjectAccess::ForPropertiesPointer(), empty_fixed_array);
2652 
2653   Add<HStoreNamedField>(array, HObjectAccess::ForElementsPointer(),
2654                         elements != nullptr ? elements : empty_fixed_array);
2655 
2656   Add<HStoreNamedField>(
2657       array, HObjectAccess::ForArrayLength(elements_kind), length_field);
2658 
2659   if (mode == TRACK_ALLOCATION_SITE) {
2660     BuildCreateAllocationMemento(
2661         array, Add<HConstant>(JSArray::kSize), allocation_site_payload);
2662   }
2663 }
2664 
2665 
AddElementAccess(HValue * elements,HValue * checked_key,HValue * val,HValue * dependency,HValue * backing_store_owner,ElementsKind elements_kind,PropertyAccessType access_type,LoadKeyedHoleMode load_mode)2666 HInstruction* HGraphBuilder::AddElementAccess(
2667     HValue* elements, HValue* checked_key, HValue* val, HValue* dependency,
2668     HValue* backing_store_owner, ElementsKind elements_kind,
2669     PropertyAccessType access_type, LoadKeyedHoleMode load_mode) {
2670   if (access_type == STORE) {
2671     DCHECK(val != NULL);
2672     if (elements_kind == UINT8_CLAMPED_ELEMENTS) {
2673       val = Add<HClampToUint8>(val);
2674     }
2675     return Add<HStoreKeyed>(elements, checked_key, val, backing_store_owner,
2676                             elements_kind, STORE_TO_INITIALIZED_ENTRY);
2677   }
2678 
2679   DCHECK(access_type == LOAD);
2680   DCHECK(val == NULL);
2681   HLoadKeyed* load =
2682       Add<HLoadKeyed>(elements, checked_key, dependency, backing_store_owner,
2683                       elements_kind, load_mode);
2684   if (elements_kind == UINT32_ELEMENTS) {
2685     graph()->RecordUint32Instruction(load);
2686   }
2687   return load;
2688 }
2689 
2690 
AddLoadMap(HValue * object,HValue * dependency)2691 HLoadNamedField* HGraphBuilder::AddLoadMap(HValue* object,
2692                                            HValue* dependency) {
2693   return Add<HLoadNamedField>(object, dependency, HObjectAccess::ForMap());
2694 }
2695 
2696 
AddLoadElements(HValue * object,HValue * dependency)2697 HLoadNamedField* HGraphBuilder::AddLoadElements(HValue* object,
2698                                                 HValue* dependency) {
2699   return Add<HLoadNamedField>(
2700       object, dependency, HObjectAccess::ForElementsPointer());
2701 }
2702 
2703 
AddLoadFixedArrayLength(HValue * array,HValue * dependency)2704 HLoadNamedField* HGraphBuilder::AddLoadFixedArrayLength(
2705     HValue* array,
2706     HValue* dependency) {
2707   return Add<HLoadNamedField>(
2708       array, dependency, HObjectAccess::ForFixedArrayLength());
2709 }
2710 
2711 
AddLoadArrayLength(HValue * array,ElementsKind kind,HValue * dependency)2712 HLoadNamedField* HGraphBuilder::AddLoadArrayLength(HValue* array,
2713                                                    ElementsKind kind,
2714                                                    HValue* dependency) {
2715   return Add<HLoadNamedField>(
2716       array, dependency, HObjectAccess::ForArrayLength(kind));
2717 }
2718 
2719 
BuildNewElementsCapacity(HValue * old_capacity)2720 HValue* HGraphBuilder::BuildNewElementsCapacity(HValue* old_capacity) {
2721   HValue* half_old_capacity = AddUncasted<HShr>(old_capacity,
2722                                                 graph_->GetConstant1());
2723 
2724   HValue* new_capacity = AddUncasted<HAdd>(half_old_capacity, old_capacity);
2725   new_capacity->ClearFlag(HValue::kCanOverflow);
2726 
2727   HValue* min_growth = Add<HConstant>(16);
2728 
2729   new_capacity = AddUncasted<HAdd>(new_capacity, min_growth);
2730   new_capacity->ClearFlag(HValue::kCanOverflow);
2731 
2732   return new_capacity;
2733 }
2734 
2735 
BuildGrowElementsCapacity(HValue * object,HValue * elements,ElementsKind kind,ElementsKind new_kind,HValue * length,HValue * new_capacity)2736 HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object,
2737                                                  HValue* elements,
2738                                                  ElementsKind kind,
2739                                                  ElementsKind new_kind,
2740                                                  HValue* length,
2741                                                  HValue* new_capacity) {
2742   Add<HBoundsCheck>(
2743       new_capacity,
2744       Add<HConstant>((kMaxRegularHeapObjectSize - FixedArray::kHeaderSize) >>
2745                      ElementsKindToShiftSize(new_kind)));
2746 
2747   HValue* new_elements =
2748       BuildAllocateAndInitializeArray(new_kind, new_capacity);
2749 
2750   BuildCopyElements(elements, kind, new_elements,
2751                     new_kind, length, new_capacity);
2752 
2753   Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
2754                         new_elements);
2755 
2756   return new_elements;
2757 }
2758 
2759 
BuildFillElementsWithValue(HValue * elements,ElementsKind elements_kind,HValue * from,HValue * to,HValue * value)2760 void HGraphBuilder::BuildFillElementsWithValue(HValue* elements,
2761                                                ElementsKind elements_kind,
2762                                                HValue* from,
2763                                                HValue* to,
2764                                                HValue* value) {
2765   if (to == NULL) {
2766     to = AddLoadFixedArrayLength(elements);
2767   }
2768 
2769   // Special loop unfolding case
2770   STATIC_ASSERT(JSArray::kPreallocatedArrayElements <=
2771                 kElementLoopUnrollThreshold);
2772   int initial_capacity = -1;
2773   if (from->IsInteger32Constant() && to->IsInteger32Constant()) {
2774     int constant_from = from->GetInteger32Constant();
2775     int constant_to = to->GetInteger32Constant();
2776 
2777     if (constant_from == 0 && constant_to <= kElementLoopUnrollThreshold) {
2778       initial_capacity = constant_to;
2779     }
2780   }
2781 
2782   if (initial_capacity >= 0) {
2783     for (int i = 0; i < initial_capacity; i++) {
2784       HInstruction* key = Add<HConstant>(i);
2785       Add<HStoreKeyed>(elements, key, value, nullptr, elements_kind);
2786     }
2787   } else {
2788     // Carefully loop backwards so that the "from" remains live through the loop
2789     // rather than the to. This often corresponds to keeping length live rather
2790     // then capacity, which helps register allocation, since length is used more
2791     // other than capacity after filling with holes.
2792     LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement);
2793 
2794     HValue* key = builder.BeginBody(to, from, Token::GT);
2795 
2796     HValue* adjusted_key = AddUncasted<HSub>(key, graph()->GetConstant1());
2797     adjusted_key->ClearFlag(HValue::kCanOverflow);
2798 
2799     Add<HStoreKeyed>(elements, adjusted_key, value, nullptr, elements_kind);
2800 
2801     builder.EndBody();
2802   }
2803 }
2804 
2805 
BuildFillElementsWithHole(HValue * elements,ElementsKind elements_kind,HValue * from,HValue * to)2806 void HGraphBuilder::BuildFillElementsWithHole(HValue* elements,
2807                                               ElementsKind elements_kind,
2808                                               HValue* from,
2809                                               HValue* to) {
2810   // Fast elements kinds need to be initialized in case statements below cause a
2811   // garbage collection.
2812 
2813   HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind)
2814                      ? graph()->GetConstantHole()
2815                      : Add<HConstant>(HConstant::kHoleNaN);
2816 
2817   // Since we're about to store a hole value, the store instruction below must
2818   // assume an elements kind that supports heap object values.
2819   if (IsFastSmiOrObjectElementsKind(elements_kind)) {
2820     elements_kind = FAST_HOLEY_ELEMENTS;
2821   }
2822 
2823   BuildFillElementsWithValue(elements, elements_kind, from, to, hole);
2824 }
2825 
2826 
BuildCopyProperties(HValue * from_properties,HValue * to_properties,HValue * length,HValue * capacity)2827 void HGraphBuilder::BuildCopyProperties(HValue* from_properties,
2828                                         HValue* to_properties, HValue* length,
2829                                         HValue* capacity) {
2830   ElementsKind kind = FAST_ELEMENTS;
2831 
2832   BuildFillElementsWithValue(to_properties, kind, length, capacity,
2833                              graph()->GetConstantUndefined());
2834 
2835   LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement);
2836 
2837   HValue* key = builder.BeginBody(length, graph()->GetConstant0(), Token::GT);
2838 
2839   key = AddUncasted<HSub>(key, graph()->GetConstant1());
2840   key->ClearFlag(HValue::kCanOverflow);
2841 
2842   HValue* element =
2843       Add<HLoadKeyed>(from_properties, key, nullptr, nullptr, kind);
2844 
2845   Add<HStoreKeyed>(to_properties, key, element, nullptr, kind);
2846 
2847   builder.EndBody();
2848 }
2849 
2850 
BuildCopyElements(HValue * from_elements,ElementsKind from_elements_kind,HValue * to_elements,ElementsKind to_elements_kind,HValue * length,HValue * capacity)2851 void HGraphBuilder::BuildCopyElements(HValue* from_elements,
2852                                       ElementsKind from_elements_kind,
2853                                       HValue* to_elements,
2854                                       ElementsKind to_elements_kind,
2855                                       HValue* length,
2856                                       HValue* capacity) {
2857   int constant_capacity = -1;
2858   if (capacity != NULL &&
2859       capacity->IsConstant() &&
2860       HConstant::cast(capacity)->HasInteger32Value()) {
2861     int constant_candidate = HConstant::cast(capacity)->Integer32Value();
2862     if (constant_candidate <= kElementLoopUnrollThreshold) {
2863       constant_capacity = constant_candidate;
2864     }
2865   }
2866 
2867   bool pre_fill_with_holes =
2868     IsFastDoubleElementsKind(from_elements_kind) &&
2869     IsFastObjectElementsKind(to_elements_kind);
2870   if (pre_fill_with_holes) {
2871     // If the copy might trigger a GC, make sure that the FixedArray is
2872     // pre-initialized with holes to make sure that it's always in a
2873     // consistent state.
2874     BuildFillElementsWithHole(to_elements, to_elements_kind,
2875                               graph()->GetConstant0(), NULL);
2876   }
2877 
2878   if (constant_capacity != -1) {
2879     // Unroll the loop for small elements kinds.
2880     for (int i = 0; i < constant_capacity; i++) {
2881       HValue* key_constant = Add<HConstant>(i);
2882       HInstruction* value = Add<HLoadKeyed>(
2883           from_elements, key_constant, nullptr, nullptr, from_elements_kind);
2884       Add<HStoreKeyed>(to_elements, key_constant, value, nullptr,
2885                        to_elements_kind);
2886     }
2887   } else {
2888     if (!pre_fill_with_holes &&
2889         (capacity == NULL || !length->Equals(capacity))) {
2890       BuildFillElementsWithHole(to_elements, to_elements_kind,
2891                                 length, NULL);
2892     }
2893 
2894     LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement);
2895 
2896     HValue* key = builder.BeginBody(length, graph()->GetConstant0(),
2897                                     Token::GT);
2898 
2899     key = AddUncasted<HSub>(key, graph()->GetConstant1());
2900     key->ClearFlag(HValue::kCanOverflow);
2901 
2902     HValue* element = Add<HLoadKeyed>(from_elements, key, nullptr, nullptr,
2903                                       from_elements_kind, ALLOW_RETURN_HOLE);
2904 
2905     ElementsKind kind = (IsHoleyElementsKind(from_elements_kind) &&
2906                          IsFastSmiElementsKind(to_elements_kind))
2907       ? FAST_HOLEY_ELEMENTS : to_elements_kind;
2908 
2909     if (IsHoleyElementsKind(from_elements_kind) &&
2910         from_elements_kind != to_elements_kind) {
2911       IfBuilder if_hole(this);
2912       if_hole.If<HCompareHoleAndBranch>(element);
2913       if_hole.Then();
2914       HConstant* hole_constant = IsFastDoubleElementsKind(to_elements_kind)
2915                                      ? Add<HConstant>(HConstant::kHoleNaN)
2916                                      : graph()->GetConstantHole();
2917       Add<HStoreKeyed>(to_elements, key, hole_constant, nullptr, kind);
2918       if_hole.Else();
2919       HStoreKeyed* store =
2920           Add<HStoreKeyed>(to_elements, key, element, nullptr, kind);
2921       store->SetFlag(HValue::kTruncatingToNumber);
2922       if_hole.End();
2923     } else {
2924       HStoreKeyed* store =
2925           Add<HStoreKeyed>(to_elements, key, element, nullptr, kind);
2926       store->SetFlag(HValue::kTruncatingToNumber);
2927     }
2928 
2929     builder.EndBody();
2930   }
2931 
2932   Counters* counters = isolate()->counters();
2933   AddIncrementCounter(counters->inlined_copied_elements());
2934 }
2935 
BuildCreateAllocationMemento(HValue * previous_object,HValue * previous_object_size,HValue * allocation_site)2936 void HGraphBuilder::BuildCreateAllocationMemento(
2937     HValue* previous_object,
2938     HValue* previous_object_size,
2939     HValue* allocation_site) {
2940   DCHECK(allocation_site != NULL);
2941   HInnerAllocatedObject* allocation_memento = Add<HInnerAllocatedObject>(
2942       previous_object, previous_object_size, HType::HeapObject());
2943   AddStoreMapConstant(
2944       allocation_memento, isolate()->factory()->allocation_memento_map());
2945   Add<HStoreNamedField>(
2946       allocation_memento,
2947       HObjectAccess::ForAllocationMementoSite(),
2948       allocation_site);
2949   if (FLAG_allocation_site_pretenuring) {
2950     HValue* memento_create_count =
2951         Add<HLoadNamedField>(allocation_site, nullptr,
2952                              HObjectAccess::ForAllocationSiteOffset(
2953                                  AllocationSite::kPretenureCreateCountOffset));
2954     memento_create_count = AddUncasted<HAdd>(
2955         memento_create_count, graph()->GetConstant1());
2956     // This smi value is reset to zero after every gc, overflow isn't a problem
2957     // since the counter is bounded by the new space size.
2958     memento_create_count->ClearFlag(HValue::kCanOverflow);
2959     Add<HStoreNamedField>(
2960         allocation_site, HObjectAccess::ForAllocationSiteOffset(
2961             AllocationSite::kPretenureCreateCountOffset), memento_create_count);
2962   }
2963 }
2964 
2965 
BuildGetNativeContext()2966 HInstruction* HGraphBuilder::BuildGetNativeContext() {
2967   return Add<HLoadNamedField>(
2968       context(), nullptr,
2969       HObjectAccess::ForContextSlot(Context::NATIVE_CONTEXT_INDEX));
2970 }
2971 
2972 
BuildGetNativeContext(HValue * closure)2973 HInstruction* HGraphBuilder::BuildGetNativeContext(HValue* closure) {
2974   // Get the global object, then the native context
2975   HInstruction* context = Add<HLoadNamedField>(
2976       closure, nullptr, HObjectAccess::ForFunctionContextPointer());
2977   return Add<HLoadNamedField>(
2978       context, nullptr,
2979       HObjectAccess::ForContextSlot(Context::NATIVE_CONTEXT_INDEX));
2980 }
2981 
2982 
BuildGetParentContext(HValue * depth,int depth_value)2983 HValue* HGraphBuilder::BuildGetParentContext(HValue* depth, int depth_value) {
2984   HValue* script_context = context();
2985   if (depth != NULL) {
2986     HValue* zero = graph()->GetConstant0();
2987 
2988     Push(script_context);
2989     Push(depth);
2990 
2991     LoopBuilder loop(this);
2992     loop.BeginBody(2);  // Drop script_context and depth from last environment
2993                         // to appease live range building without simulates.
2994     depth = Pop();
2995     script_context = Pop();
2996 
2997     script_context = Add<HLoadNamedField>(
2998         script_context, nullptr,
2999         HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
3000     depth = AddUncasted<HSub>(depth, graph()->GetConstant1());
3001     depth->ClearFlag(HValue::kCanOverflow);
3002 
3003     IfBuilder if_break(this);
3004     if_break.If<HCompareNumericAndBranch, HValue*>(depth, zero, Token::EQ);
3005     if_break.Then();
3006     {
3007       Push(script_context);  // The result.
3008       loop.Break();
3009     }
3010     if_break.Else();
3011     {
3012       Push(script_context);
3013       Push(depth);
3014     }
3015     loop.EndBody();
3016     if_break.End();
3017 
3018     script_context = Pop();
3019   } else if (depth_value > 0) {
3020     // Unroll the above loop.
3021     for (int i = 0; i < depth_value; i++) {
3022       script_context = Add<HLoadNamedField>(
3023           script_context, nullptr,
3024           HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
3025     }
3026   }
3027   return script_context;
3028 }
3029 
3030 
BuildGetArrayFunction()3031 HInstruction* HGraphBuilder::BuildGetArrayFunction() {
3032   HInstruction* native_context = BuildGetNativeContext();
3033   HInstruction* index =
3034       Add<HConstant>(static_cast<int32_t>(Context::ARRAY_FUNCTION_INDEX));
3035   return Add<HLoadKeyed>(native_context, index, nullptr, nullptr,
3036                          FAST_ELEMENTS);
3037 }
3038 
3039 
BuildArrayBufferViewFieldAccessor(HValue * object,HValue * checked_object,FieldIndex index)3040 HValue* HGraphBuilder::BuildArrayBufferViewFieldAccessor(HValue* object,
3041                                                          HValue* checked_object,
3042                                                          FieldIndex index) {
3043   NoObservableSideEffectsScope scope(this);
3044   HObjectAccess access = HObjectAccess::ForObservableJSObjectOffset(
3045       index.offset(), Representation::Tagged());
3046   HInstruction* buffer = Add<HLoadNamedField>(
3047       object, checked_object, HObjectAccess::ForJSArrayBufferViewBuffer());
3048   HInstruction* field = Add<HLoadNamedField>(object, checked_object, access);
3049 
3050   HInstruction* flags = Add<HLoadNamedField>(
3051       buffer, nullptr, HObjectAccess::ForJSArrayBufferBitField());
3052   HValue* was_neutered_mask =
3053       Add<HConstant>(1 << JSArrayBuffer::WasNeutered::kShift);
3054   HValue* was_neutered_test =
3055       AddUncasted<HBitwise>(Token::BIT_AND, flags, was_neutered_mask);
3056 
3057   IfBuilder if_was_neutered(this);
3058   if_was_neutered.If<HCompareNumericAndBranch>(
3059       was_neutered_test, graph()->GetConstant0(), Token::NE);
3060   if_was_neutered.Then();
3061   Push(graph()->GetConstant0());
3062   if_was_neutered.Else();
3063   Push(field);
3064   if_was_neutered.End();
3065 
3066   return Pop();
3067 }
3068 
AddLoadJSBuiltin(int context_index)3069 HValue* HGraphBuilder::AddLoadJSBuiltin(int context_index) {
3070   HValue* native_context = BuildGetNativeContext();
3071   HObjectAccess function_access = HObjectAccess::ForContextSlot(context_index);
3072   return Add<HLoadNamedField>(native_context, nullptr, function_access);
3073 }
3074 
HOptimizedGraphBuilder(CompilationInfo * info,bool track_positions)3075 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info,
3076                                                bool track_positions)
3077     : HGraphBuilder(info, CallInterfaceDescriptor(), track_positions),
3078       function_state_(NULL),
3079       initial_function_state_(this, info, NORMAL_RETURN, -1,
3080                               TailCallMode::kAllow),
3081       ast_context_(NULL),
3082       break_scope_(NULL),
3083       inlined_count_(0),
3084       globals_(10, info->zone()),
3085       osr_(new (info->zone()) HOsrBuilder(this)),
3086       bounds_(info->zone()) {
3087   // This is not initialized in the initializer list because the
3088   // constructor for the initial state relies on function_state_ == NULL
3089   // to know it's the initial state.
3090   function_state_ = &initial_function_state_;
3091   InitializeAstVisitor(info->isolate());
3092 }
3093 
3094 
CreateJoin(HBasicBlock * first,HBasicBlock * second,BailoutId join_id)3095 HBasicBlock* HOptimizedGraphBuilder::CreateJoin(HBasicBlock* first,
3096                                                 HBasicBlock* second,
3097                                                 BailoutId join_id) {
3098   if (first == NULL) {
3099     return second;
3100   } else if (second == NULL) {
3101     return first;
3102   } else {
3103     HBasicBlock* join_block = graph()->CreateBasicBlock();
3104     Goto(first, join_block);
3105     Goto(second, join_block);
3106     join_block->SetJoinId(join_id);
3107     return join_block;
3108   }
3109 }
3110 
JoinContinue(IterationStatement * statement,BailoutId continue_id,HBasicBlock * exit_block,HBasicBlock * continue_block)3111 HBasicBlock* HOptimizedGraphBuilder::JoinContinue(IterationStatement* statement,
3112                                                   BailoutId continue_id,
3113                                                   HBasicBlock* exit_block,
3114                                                   HBasicBlock* continue_block) {
3115   if (continue_block != NULL) {
3116     if (exit_block != NULL) Goto(exit_block, continue_block);
3117     continue_block->SetJoinId(continue_id);
3118     return continue_block;
3119   }
3120   return exit_block;
3121 }
3122 
3123 
CreateLoop(IterationStatement * statement,HBasicBlock * loop_entry,HBasicBlock * body_exit,HBasicBlock * loop_successor,HBasicBlock * break_block)3124 HBasicBlock* HOptimizedGraphBuilder::CreateLoop(IterationStatement* statement,
3125                                                 HBasicBlock* loop_entry,
3126                                                 HBasicBlock* body_exit,
3127                                                 HBasicBlock* loop_successor,
3128                                                 HBasicBlock* break_block) {
3129   if (body_exit != NULL) Goto(body_exit, loop_entry);
3130   loop_entry->PostProcessLoopHeader(statement);
3131   if (break_block != NULL) {
3132     if (loop_successor != NULL) Goto(loop_successor, break_block);
3133     break_block->SetJoinId(statement->ExitId());
3134     return break_block;
3135   }
3136   return loop_successor;
3137 }
3138 
3139 
3140 // Build a new loop header block and set it as the current block.
BuildLoopEntry()3141 HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry() {
3142   HBasicBlock* loop_entry = CreateLoopHeaderBlock();
3143   Goto(loop_entry);
3144   set_current_block(loop_entry);
3145   return loop_entry;
3146 }
3147 
3148 
BuildLoopEntry(IterationStatement * statement)3149 HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry(
3150     IterationStatement* statement) {
3151   HBasicBlock* loop_entry;
3152 
3153   if (osr()->HasOsrEntryAt(statement)) {
3154     loop_entry = osr()->BuildOsrLoopEntry(statement);
3155     if (function_state()->IsInsideDoExpressionScope()) {
3156       Bailout(kDoExpressionUnmodelable);
3157     }
3158   } else {
3159     loop_entry = BuildLoopEntry();
3160   }
3161   return loop_entry;
3162 }
3163 
3164 
FinishExit(HControlInstruction * instruction,SourcePosition position)3165 void HBasicBlock::FinishExit(HControlInstruction* instruction,
3166                              SourcePosition position) {
3167   Finish(instruction, position);
3168   ClearEnvironment();
3169 }
3170 
3171 
operator <<(std::ostream & os,const HBasicBlock & b)3172 std::ostream& operator<<(std::ostream& os, const HBasicBlock& b) {
3173   return os << "B" << b.block_id();
3174 }
3175 
HGraph(CompilationInfo * info,CallInterfaceDescriptor descriptor)3176 HGraph::HGraph(CompilationInfo* info, CallInterfaceDescriptor descriptor)
3177     : isolate_(info->isolate()),
3178       next_block_id_(0),
3179       entry_block_(NULL),
3180       blocks_(8, info->zone()),
3181       values_(16, info->zone()),
3182       phi_list_(NULL),
3183       uint32_instructions_(NULL),
3184       osr_(NULL),
3185       info_(info),
3186       descriptor_(descriptor),
3187       zone_(info->zone()),
3188       allow_code_motion_(false),
3189       use_optimistic_licm_(false),
3190       depends_on_empty_array_proto_elements_(false),
3191       depends_on_string_length_overflow_(false),
3192       type_change_checksum_(0),
3193       maximum_environment_size_(0),
3194       no_side_effects_scope_count_(0),
3195       disallow_adding_new_values_(false) {
3196   if (info->IsStub()) {
3197     // For stubs, explicitly add the context to the environment.
3198     start_environment_ =
3199         new (zone_) HEnvironment(zone_, descriptor.GetParameterCount() + 1);
3200   } else {
3201     start_environment_ =
3202         new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_);
3203   }
3204   start_environment_->set_ast_id(BailoutId::FunctionContext());
3205   entry_block_ = CreateBasicBlock();
3206   entry_block_->SetInitialEnvironment(start_environment_);
3207 }
3208 
3209 
CreateBasicBlock()3210 HBasicBlock* HGraph::CreateBasicBlock() {
3211   HBasicBlock* result = new(zone()) HBasicBlock(this);
3212   blocks_.Add(result, zone());
3213   return result;
3214 }
3215 
3216 
FinalizeUniqueness()3217 void HGraph::FinalizeUniqueness() {
3218   DisallowHeapAllocation no_gc;
3219   for (int i = 0; i < blocks()->length(); ++i) {
3220     for (HInstructionIterator it(blocks()->at(i)); !it.Done(); it.Advance()) {
3221       it.Current()->FinalizeUniqueness();
3222     }
3223   }
3224 }
3225 
3226 
3227 // Block ordering was implemented with two mutually recursive methods,
3228 // HGraph::Postorder and HGraph::PostorderLoopBlocks.
3229 // The recursion could lead to stack overflow so the algorithm has been
3230 // implemented iteratively.
3231 // At a high level the algorithm looks like this:
3232 //
3233 // Postorder(block, loop_header) : {
3234 //   if (block has already been visited or is of another loop) return;
3235 //   mark block as visited;
3236 //   if (block is a loop header) {
3237 //     VisitLoopMembers(block, loop_header);
3238 //     VisitSuccessorsOfLoopHeader(block);
3239 //   } else {
3240 //     VisitSuccessors(block)
3241 //   }
3242 //   put block in result list;
3243 // }
3244 //
3245 // VisitLoopMembers(block, outer_loop_header) {
3246 //   foreach (block b in block loop members) {
3247 //     VisitSuccessorsOfLoopMember(b, outer_loop_header);
3248 //     if (b is loop header) VisitLoopMembers(b);
3249 //   }
3250 // }
3251 //
3252 // VisitSuccessorsOfLoopMember(block, outer_loop_header) {
3253 //   foreach (block b in block successors) Postorder(b, outer_loop_header)
3254 // }
3255 //
3256 // VisitSuccessorsOfLoopHeader(block) {
3257 //   foreach (block b in block successors) Postorder(b, block)
3258 // }
3259 //
3260 // VisitSuccessors(block, loop_header) {
3261 //   foreach (block b in block successors) Postorder(b, loop_header)
3262 // }
3263 //
3264 // The ordering is started calling Postorder(entry, NULL).
3265 //
3266 // Each instance of PostorderProcessor represents the "stack frame" of the
3267 // recursion, and particularly keeps the state of the loop (iteration) of the
3268 // "Visit..." function it represents.
3269 // To recycle memory we keep all the frames in a double linked list but
3270 // this means that we cannot use constructors to initialize the frames.
3271 //
3272 class PostorderProcessor : public ZoneObject {
3273  public:
3274   // Back link (towards the stack bottom).
parent()3275   PostorderProcessor* parent() {return father_; }
3276   // Forward link (towards the stack top).
child()3277   PostorderProcessor* child() {return child_; }
block()3278   HBasicBlock* block() { return block_; }
loop()3279   HLoopInformation* loop() { return loop_; }
loop_header()3280   HBasicBlock* loop_header() { return loop_header_; }
3281 
CreateEntryProcessor(Zone * zone,HBasicBlock * block)3282   static PostorderProcessor* CreateEntryProcessor(Zone* zone,
3283                                                   HBasicBlock* block) {
3284     PostorderProcessor* result = new(zone) PostorderProcessor(NULL);
3285     return result->SetupSuccessors(zone, block, NULL);
3286   }
3287 
PerformStep(Zone * zone,ZoneList<HBasicBlock * > * order)3288   PostorderProcessor* PerformStep(Zone* zone,
3289                                   ZoneList<HBasicBlock*>* order) {
3290     PostorderProcessor* next =
3291         PerformNonBacktrackingStep(zone, order);
3292     if (next != NULL) {
3293       return next;
3294     } else {
3295       return Backtrack(zone, order);
3296     }
3297   }
3298 
3299  private:
PostorderProcessor(PostorderProcessor * father)3300   explicit PostorderProcessor(PostorderProcessor* father)
3301       : father_(father), child_(NULL), successor_iterator(NULL) { }
3302 
3303   // Each enum value states the cycle whose state is kept by this instance.
3304   enum LoopKind {
3305     NONE,
3306     SUCCESSORS,
3307     SUCCESSORS_OF_LOOP_HEADER,
3308     LOOP_MEMBERS,
3309     SUCCESSORS_OF_LOOP_MEMBER
3310   };
3311 
3312   // Each "Setup..." method is like a constructor for a cycle state.
SetupSuccessors(Zone * zone,HBasicBlock * block,HBasicBlock * loop_header)3313   PostorderProcessor* SetupSuccessors(Zone* zone,
3314                                       HBasicBlock* block,
3315                                       HBasicBlock* loop_header) {
3316     if (block == NULL || block->IsOrdered() ||
3317         block->parent_loop_header() != loop_header) {
3318       kind_ = NONE;
3319       block_ = NULL;
3320       loop_ = NULL;
3321       loop_header_ = NULL;
3322       return this;
3323     } else {
3324       block_ = block;
3325       loop_ = NULL;
3326       block->MarkAsOrdered();
3327 
3328       if (block->IsLoopHeader()) {
3329         kind_ = SUCCESSORS_OF_LOOP_HEADER;
3330         loop_header_ = block;
3331         InitializeSuccessors();
3332         PostorderProcessor* result = Push(zone);
3333         return result->SetupLoopMembers(zone, block, block->loop_information(),
3334                                         loop_header);
3335       } else {
3336         DCHECK(block->IsFinished());
3337         kind_ = SUCCESSORS;
3338         loop_header_ = loop_header;
3339         InitializeSuccessors();
3340         return this;
3341       }
3342     }
3343   }
3344 
SetupLoopMembers(Zone * zone,HBasicBlock * block,HLoopInformation * loop,HBasicBlock * loop_header)3345   PostorderProcessor* SetupLoopMembers(Zone* zone,
3346                                        HBasicBlock* block,
3347                                        HLoopInformation* loop,
3348                                        HBasicBlock* loop_header) {
3349     kind_ = LOOP_MEMBERS;
3350     block_ = block;
3351     loop_ = loop;
3352     loop_header_ = loop_header;
3353     InitializeLoopMembers();
3354     return this;
3355   }
3356 
SetupSuccessorsOfLoopMember(HBasicBlock * block,HLoopInformation * loop,HBasicBlock * loop_header)3357   PostorderProcessor* SetupSuccessorsOfLoopMember(
3358       HBasicBlock* block,
3359       HLoopInformation* loop,
3360       HBasicBlock* loop_header) {
3361     kind_ = SUCCESSORS_OF_LOOP_MEMBER;
3362     block_ = block;
3363     loop_ = loop;
3364     loop_header_ = loop_header;
3365     InitializeSuccessors();
3366     return this;
3367   }
3368 
3369   // This method "allocates" a new stack frame.
Push(Zone * zone)3370   PostorderProcessor* Push(Zone* zone) {
3371     if (child_ == NULL) {
3372       child_ = new(zone) PostorderProcessor(this);
3373     }
3374     return child_;
3375   }
3376 
ClosePostorder(ZoneList<HBasicBlock * > * order,Zone * zone)3377   void ClosePostorder(ZoneList<HBasicBlock*>* order, Zone* zone) {
3378     DCHECK(block_->end()->FirstSuccessor() == NULL ||
3379            order->Contains(block_->end()->FirstSuccessor()) ||
3380            block_->end()->FirstSuccessor()->IsLoopHeader());
3381     DCHECK(block_->end()->SecondSuccessor() == NULL ||
3382            order->Contains(block_->end()->SecondSuccessor()) ||
3383            block_->end()->SecondSuccessor()->IsLoopHeader());
3384     order->Add(block_, zone);
3385   }
3386 
3387   // This method is the basic block to walk up the stack.
Pop(Zone * zone,ZoneList<HBasicBlock * > * order)3388   PostorderProcessor* Pop(Zone* zone,
3389                           ZoneList<HBasicBlock*>* order) {
3390     switch (kind_) {
3391       case SUCCESSORS:
3392       case SUCCESSORS_OF_LOOP_HEADER:
3393         ClosePostorder(order, zone);
3394         return father_;
3395       case LOOP_MEMBERS:
3396         return father_;
3397       case SUCCESSORS_OF_LOOP_MEMBER:
3398         if (block()->IsLoopHeader() && block() != loop_->loop_header()) {
3399           // In this case we need to perform a LOOP_MEMBERS cycle so we
3400           // initialize it and return this instead of father.
3401           return SetupLoopMembers(zone, block(),
3402                                   block()->loop_information(), loop_header_);
3403         } else {
3404           return father_;
3405         }
3406       case NONE:
3407         return father_;
3408     }
3409     UNREACHABLE();
3410     return NULL;
3411   }
3412 
3413   // Walks up the stack.
Backtrack(Zone * zone,ZoneList<HBasicBlock * > * order)3414   PostorderProcessor* Backtrack(Zone* zone,
3415                                 ZoneList<HBasicBlock*>* order) {
3416     PostorderProcessor* parent = Pop(zone, order);
3417     while (parent != NULL) {
3418       PostorderProcessor* next =
3419           parent->PerformNonBacktrackingStep(zone, order);
3420       if (next != NULL) {
3421         return next;
3422       } else {
3423         parent = parent->Pop(zone, order);
3424       }
3425     }
3426     return NULL;
3427   }
3428 
PerformNonBacktrackingStep(Zone * zone,ZoneList<HBasicBlock * > * order)3429   PostorderProcessor* PerformNonBacktrackingStep(
3430       Zone* zone,
3431       ZoneList<HBasicBlock*>* order) {
3432     HBasicBlock* next_block;
3433     switch (kind_) {
3434       case SUCCESSORS:
3435         next_block = AdvanceSuccessors();
3436         if (next_block != NULL) {
3437           PostorderProcessor* result = Push(zone);
3438           return result->SetupSuccessors(zone, next_block, loop_header_);
3439         }
3440         break;
3441       case SUCCESSORS_OF_LOOP_HEADER:
3442         next_block = AdvanceSuccessors();
3443         if (next_block != NULL) {
3444           PostorderProcessor* result = Push(zone);
3445           return result->SetupSuccessors(zone, next_block, block());
3446         }
3447         break;
3448       case LOOP_MEMBERS:
3449         next_block = AdvanceLoopMembers();
3450         if (next_block != NULL) {
3451           PostorderProcessor* result = Push(zone);
3452           return result->SetupSuccessorsOfLoopMember(next_block,
3453                                                      loop_, loop_header_);
3454         }
3455         break;
3456       case SUCCESSORS_OF_LOOP_MEMBER:
3457         next_block = AdvanceSuccessors();
3458         if (next_block != NULL) {
3459           PostorderProcessor* result = Push(zone);
3460           return result->SetupSuccessors(zone, next_block, loop_header_);
3461         }
3462         break;
3463       case NONE:
3464         return NULL;
3465     }
3466     return NULL;
3467   }
3468 
3469   // The following two methods implement a "foreach b in successors" cycle.
InitializeSuccessors()3470   void InitializeSuccessors() {
3471     loop_index = 0;
3472     loop_length = 0;
3473     successor_iterator = HSuccessorIterator(block_->end());
3474   }
3475 
AdvanceSuccessors()3476   HBasicBlock* AdvanceSuccessors() {
3477     if (!successor_iterator.Done()) {
3478       HBasicBlock* result = successor_iterator.Current();
3479       successor_iterator.Advance();
3480       return result;
3481     }
3482     return NULL;
3483   }
3484 
3485   // The following two methods implement a "foreach b in loop members" cycle.
InitializeLoopMembers()3486   void InitializeLoopMembers() {
3487     loop_index = 0;
3488     loop_length = loop_->blocks()->length();
3489   }
3490 
AdvanceLoopMembers()3491   HBasicBlock* AdvanceLoopMembers() {
3492     if (loop_index < loop_length) {
3493       HBasicBlock* result = loop_->blocks()->at(loop_index);
3494       loop_index++;
3495       return result;
3496     } else {
3497       return NULL;
3498     }
3499   }
3500 
3501   LoopKind kind_;
3502   PostorderProcessor* father_;
3503   PostorderProcessor* child_;
3504   HLoopInformation* loop_;
3505   HBasicBlock* block_;
3506   HBasicBlock* loop_header_;
3507   int loop_index;
3508   int loop_length;
3509   HSuccessorIterator successor_iterator;
3510 };
3511 
3512 
OrderBlocks()3513 void HGraph::OrderBlocks() {
3514   CompilationPhase phase("H_Block ordering", info());
3515 
3516 #ifdef DEBUG
3517   // Initially the blocks must not be ordered.
3518   for (int i = 0; i < blocks_.length(); ++i) {
3519     DCHECK(!blocks_[i]->IsOrdered());
3520   }
3521 #endif
3522 
3523   PostorderProcessor* postorder =
3524       PostorderProcessor::CreateEntryProcessor(zone(), blocks_[0]);
3525   blocks_.Rewind(0);
3526   while (postorder) {
3527     postorder = postorder->PerformStep(zone(), &blocks_);
3528   }
3529 
3530 #ifdef DEBUG
3531   // Now all blocks must be marked as ordered.
3532   for (int i = 0; i < blocks_.length(); ++i) {
3533     DCHECK(blocks_[i]->IsOrdered());
3534   }
3535 #endif
3536 
3537   // Reverse block list and assign block IDs.
3538   for (int i = 0, j = blocks_.length(); --j >= i; ++i) {
3539     HBasicBlock* bi = blocks_[i];
3540     HBasicBlock* bj = blocks_[j];
3541     bi->set_block_id(j);
3542     bj->set_block_id(i);
3543     blocks_[i] = bj;
3544     blocks_[j] = bi;
3545   }
3546 }
3547 
3548 
AssignDominators()3549 void HGraph::AssignDominators() {
3550   HPhase phase("H_Assign dominators", this);
3551   for (int i = 0; i < blocks_.length(); ++i) {
3552     HBasicBlock* block = blocks_[i];
3553     if (block->IsLoopHeader()) {
3554       // Only the first predecessor of a loop header is from outside the loop.
3555       // All others are back edges, and thus cannot dominate the loop header.
3556       block->AssignCommonDominator(block->predecessors()->first());
3557       block->AssignLoopSuccessorDominators();
3558     } else {
3559       for (int j = blocks_[i]->predecessors()->length() - 1; j >= 0; --j) {
3560         blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j));
3561       }
3562     }
3563   }
3564 }
3565 
3566 
CheckArgumentsPhiUses()3567 bool HGraph::CheckArgumentsPhiUses() {
3568   int block_count = blocks_.length();
3569   for (int i = 0; i < block_count; ++i) {
3570     for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
3571       HPhi* phi = blocks_[i]->phis()->at(j);
3572       // We don't support phi uses of arguments for now.
3573       if (phi->CheckFlag(HValue::kIsArguments)) return false;
3574     }
3575   }
3576   return true;
3577 }
3578 
3579 
CheckConstPhiUses()3580 bool HGraph::CheckConstPhiUses() {
3581   int block_count = blocks_.length();
3582   for (int i = 0; i < block_count; ++i) {
3583     for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
3584       HPhi* phi = blocks_[i]->phis()->at(j);
3585       // Check for the hole value (from an uninitialized const).
3586       for (int k = 0; k < phi->OperandCount(); k++) {
3587         if (phi->OperandAt(k) == GetConstantHole()) return false;
3588       }
3589     }
3590   }
3591   return true;
3592 }
3593 
3594 
CollectPhis()3595 void HGraph::CollectPhis() {
3596   int block_count = blocks_.length();
3597   phi_list_ = new(zone()) ZoneList<HPhi*>(block_count, zone());
3598   for (int i = 0; i < block_count; ++i) {
3599     for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
3600       HPhi* phi = blocks_[i]->phis()->at(j);
3601       phi_list_->Add(phi, zone());
3602     }
3603   }
3604 }
3605 
3606 
3607 // Implementation of utility class to encapsulate the translation state for
3608 // a (possibly inlined) function.
FunctionState(HOptimizedGraphBuilder * owner,CompilationInfo * info,InliningKind inlining_kind,int inlining_id,TailCallMode tail_call_mode)3609 FunctionState::FunctionState(HOptimizedGraphBuilder* owner,
3610                              CompilationInfo* info, InliningKind inlining_kind,
3611                              int inlining_id, TailCallMode tail_call_mode)
3612     : owner_(owner),
3613       compilation_info_(info),
3614       call_context_(NULL),
3615       inlining_kind_(inlining_kind),
3616       tail_call_mode_(tail_call_mode),
3617       function_return_(NULL),
3618       test_context_(NULL),
3619       entry_(NULL),
3620       arguments_object_(NULL),
3621       arguments_elements_(NULL),
3622       inlining_id_(inlining_id),
3623       outer_source_position_(SourcePosition::Unknown()),
3624       do_expression_scope_count_(0),
3625       outer_(owner->function_state()) {
3626   if (outer_ != NULL) {
3627     // State for an inline function.
3628     if (owner->ast_context()->IsTest()) {
3629       HBasicBlock* if_true = owner->graph()->CreateBasicBlock();
3630       HBasicBlock* if_false = owner->graph()->CreateBasicBlock();
3631       if_true->MarkAsInlineReturnTarget(owner->current_block());
3632       if_false->MarkAsInlineReturnTarget(owner->current_block());
3633       TestContext* outer_test_context = TestContext::cast(owner->ast_context());
3634       Expression* cond = outer_test_context->condition();
3635       // The AstContext constructor pushed on the context stack.  This newed
3636       // instance is the reason that AstContext can't be BASE_EMBEDDED.
3637       test_context_ = new TestContext(owner, cond, if_true, if_false);
3638     } else {
3639       function_return_ = owner->graph()->CreateBasicBlock();
3640       function_return()->MarkAsInlineReturnTarget(owner->current_block());
3641     }
3642     // Set this after possibly allocating a new TestContext above.
3643     call_context_ = owner->ast_context();
3644   }
3645 
3646   // Push on the state stack.
3647   owner->set_function_state(this);
3648 
3649   if (owner->is_tracking_positions()) {
3650     outer_source_position_ = owner->source_position();
3651     owner->EnterInlinedSource(inlining_id);
3652     owner->SetSourcePosition(info->shared_info()->start_position());
3653   }
3654 }
3655 
3656 
~FunctionState()3657 FunctionState::~FunctionState() {
3658   delete test_context_;
3659   owner_->set_function_state(outer_);
3660 
3661   if (owner_->is_tracking_positions()) {
3662     owner_->set_source_position(outer_source_position_);
3663     owner_->EnterInlinedSource(outer_->inlining_id());
3664   }
3665 }
3666 
3667 
3668 // Implementation of utility classes to represent an expression's context in
3669 // the AST.
AstContext(HOptimizedGraphBuilder * owner,Expression::Context kind)3670 AstContext::AstContext(HOptimizedGraphBuilder* owner, Expression::Context kind)
3671     : owner_(owner),
3672       kind_(kind),
3673       outer_(owner->ast_context()),
3674       typeof_mode_(NOT_INSIDE_TYPEOF) {
3675   owner->set_ast_context(this);  // Push.
3676 #ifdef DEBUG
3677   DCHECK_EQ(JS_FUNCTION, owner->environment()->frame_type());
3678   original_length_ = owner->environment()->length();
3679 #endif
3680 }
3681 
3682 
~AstContext()3683 AstContext::~AstContext() {
3684   owner_->set_ast_context(outer_);  // Pop.
3685 }
3686 
3687 
~EffectContext()3688 EffectContext::~EffectContext() {
3689   DCHECK(owner()->HasStackOverflow() || owner()->current_block() == NULL ||
3690          (owner()->environment()->length() == original_length_ &&
3691           (owner()->environment()->frame_type() == JS_FUNCTION ||
3692            owner()->environment()->frame_type() == TAIL_CALLER_FUNCTION)));
3693 }
3694 
3695 
~ValueContext()3696 ValueContext::~ValueContext() {
3697   DCHECK(owner()->HasStackOverflow() || owner()->current_block() == NULL ||
3698          (owner()->environment()->length() == original_length_ + 1 &&
3699           (owner()->environment()->frame_type() == JS_FUNCTION ||
3700            owner()->environment()->frame_type() == TAIL_CALLER_FUNCTION)));
3701 }
3702 
3703 
ReturnValue(HValue * value)3704 void EffectContext::ReturnValue(HValue* value) {
3705   // The value is simply ignored.
3706 }
3707 
3708 
ReturnValue(HValue * value)3709 void ValueContext::ReturnValue(HValue* value) {
3710   // The value is tracked in the bailout environment, and communicated
3711   // through the environment as the result of the expression.
3712   if (value->CheckFlag(HValue::kIsArguments)) {
3713     if (flag_ == ARGUMENTS_FAKED) {
3714       value = owner()->graph()->GetConstantUndefined();
3715     } else if (!arguments_allowed()) {
3716       owner()->Bailout(kBadValueContextForArgumentsValue);
3717     }
3718   }
3719   owner()->Push(value);
3720 }
3721 
3722 
ReturnValue(HValue * value)3723 void TestContext::ReturnValue(HValue* value) {
3724   BuildBranch(value);
3725 }
3726 
3727 
ReturnInstruction(HInstruction * instr,BailoutId ast_id)3728 void EffectContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
3729   DCHECK(!instr->IsControlInstruction());
3730   owner()->AddInstruction(instr);
3731   if (instr->HasObservableSideEffects()) {
3732     owner()->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
3733   }
3734 }
3735 
3736 
ReturnControl(HControlInstruction * instr,BailoutId ast_id)3737 void EffectContext::ReturnControl(HControlInstruction* instr,
3738                                   BailoutId ast_id) {
3739   DCHECK(!instr->HasObservableSideEffects());
3740   HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock();
3741   HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock();
3742   instr->SetSuccessorAt(0, empty_true);
3743   instr->SetSuccessorAt(1, empty_false);
3744   owner()->FinishCurrentBlock(instr);
3745   HBasicBlock* join = owner()->CreateJoin(empty_true, empty_false, ast_id);
3746   owner()->set_current_block(join);
3747 }
3748 
3749 
ReturnContinuation(HIfContinuation * continuation,BailoutId ast_id)3750 void EffectContext::ReturnContinuation(HIfContinuation* continuation,
3751                                        BailoutId ast_id) {
3752   HBasicBlock* true_branch = NULL;
3753   HBasicBlock* false_branch = NULL;
3754   continuation->Continue(&true_branch, &false_branch);
3755   if (!continuation->IsTrueReachable()) {
3756     owner()->set_current_block(false_branch);
3757   } else if (!continuation->IsFalseReachable()) {
3758     owner()->set_current_block(true_branch);
3759   } else {
3760     HBasicBlock* join = owner()->CreateJoin(true_branch, false_branch, ast_id);
3761     owner()->set_current_block(join);
3762   }
3763 }
3764 
3765 
ReturnInstruction(HInstruction * instr,BailoutId ast_id)3766 void ValueContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
3767   DCHECK(!instr->IsControlInstruction());
3768   if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) {
3769     return owner()->Bailout(kBadValueContextForArgumentsObjectValue);
3770   }
3771   owner()->AddInstruction(instr);
3772   owner()->Push(instr);
3773   if (instr->HasObservableSideEffects()) {
3774     owner()->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
3775   }
3776 }
3777 
3778 
ReturnControl(HControlInstruction * instr,BailoutId ast_id)3779 void ValueContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) {
3780   DCHECK(!instr->HasObservableSideEffects());
3781   if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) {
3782     return owner()->Bailout(kBadValueContextForArgumentsObjectValue);
3783   }
3784   HBasicBlock* materialize_false = owner()->graph()->CreateBasicBlock();
3785   HBasicBlock* materialize_true = owner()->graph()->CreateBasicBlock();
3786   instr->SetSuccessorAt(0, materialize_true);
3787   instr->SetSuccessorAt(1, materialize_false);
3788   owner()->FinishCurrentBlock(instr);
3789   owner()->set_current_block(materialize_true);
3790   owner()->Push(owner()->graph()->GetConstantTrue());
3791   owner()->set_current_block(materialize_false);
3792   owner()->Push(owner()->graph()->GetConstantFalse());
3793   HBasicBlock* join =
3794     owner()->CreateJoin(materialize_true, materialize_false, ast_id);
3795   owner()->set_current_block(join);
3796 }
3797 
3798 
ReturnContinuation(HIfContinuation * continuation,BailoutId ast_id)3799 void ValueContext::ReturnContinuation(HIfContinuation* continuation,
3800                                       BailoutId ast_id) {
3801   HBasicBlock* materialize_true = NULL;
3802   HBasicBlock* materialize_false = NULL;
3803   continuation->Continue(&materialize_true, &materialize_false);
3804   if (continuation->IsTrueReachable()) {
3805     owner()->set_current_block(materialize_true);
3806     owner()->Push(owner()->graph()->GetConstantTrue());
3807     owner()->set_current_block(materialize_true);
3808   }
3809   if (continuation->IsFalseReachable()) {
3810     owner()->set_current_block(materialize_false);
3811     owner()->Push(owner()->graph()->GetConstantFalse());
3812     owner()->set_current_block(materialize_false);
3813   }
3814   if (continuation->TrueAndFalseReachable()) {
3815     HBasicBlock* join =
3816         owner()->CreateJoin(materialize_true, materialize_false, ast_id);
3817     owner()->set_current_block(join);
3818   }
3819 }
3820 
3821 
ReturnInstruction(HInstruction * instr,BailoutId ast_id)3822 void TestContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
3823   DCHECK(!instr->IsControlInstruction());
3824   HOptimizedGraphBuilder* builder = owner();
3825   builder->AddInstruction(instr);
3826   // We expect a simulate after every expression with side effects, though
3827   // this one isn't actually needed (and wouldn't work if it were targeted).
3828   if (instr->HasObservableSideEffects()) {
3829     builder->Push(instr);
3830     builder->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
3831     builder->Pop();
3832   }
3833   BuildBranch(instr);
3834 }
3835 
3836 
ReturnControl(HControlInstruction * instr,BailoutId ast_id)3837 void TestContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) {
3838   DCHECK(!instr->HasObservableSideEffects());
3839   HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock();
3840   HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock();
3841   instr->SetSuccessorAt(0, empty_true);
3842   instr->SetSuccessorAt(1, empty_false);
3843   owner()->FinishCurrentBlock(instr);
3844   owner()->Goto(empty_true, if_true(), owner()->function_state());
3845   owner()->Goto(empty_false, if_false(), owner()->function_state());
3846   owner()->set_current_block(NULL);
3847 }
3848 
3849 
ReturnContinuation(HIfContinuation * continuation,BailoutId ast_id)3850 void TestContext::ReturnContinuation(HIfContinuation* continuation,
3851                                      BailoutId ast_id) {
3852   HBasicBlock* true_branch = NULL;
3853   HBasicBlock* false_branch = NULL;
3854   continuation->Continue(&true_branch, &false_branch);
3855   if (continuation->IsTrueReachable()) {
3856     owner()->Goto(true_branch, if_true(), owner()->function_state());
3857   }
3858   if (continuation->IsFalseReachable()) {
3859     owner()->Goto(false_branch, if_false(), owner()->function_state());
3860   }
3861   owner()->set_current_block(NULL);
3862 }
3863 
3864 
BuildBranch(HValue * value)3865 void TestContext::BuildBranch(HValue* value) {
3866   // We expect the graph to be in edge-split form: there is no edge that
3867   // connects a branch node to a join node.  We conservatively ensure that
3868   // property by always adding an empty block on the outgoing edges of this
3869   // branch.
3870   HOptimizedGraphBuilder* builder = owner();
3871   if (value != NULL && value->CheckFlag(HValue::kIsArguments)) {
3872     builder->Bailout(kArgumentsObjectValueInATestContext);
3873   }
3874   ToBooleanHints expected(condition()->to_boolean_types());
3875   ReturnControl(owner()->New<HBranch>(value, expected), BailoutId::None());
3876 }
3877 
3878 
3879 // HOptimizedGraphBuilder infrastructure for bailing out and checking bailouts.
3880 #define CHECK_BAILOUT(call)                     \
3881   do {                                          \
3882     call;                                       \
3883     if (HasStackOverflow()) return;             \
3884   } while (false)
3885 
3886 
3887 #define CHECK_ALIVE(call)                                       \
3888   do {                                                          \
3889     call;                                                       \
3890     if (HasStackOverflow() || current_block() == NULL) return;  \
3891   } while (false)
3892 
3893 
3894 #define CHECK_ALIVE_OR_RETURN(call, value)                            \
3895   do {                                                                \
3896     call;                                                             \
3897     if (HasStackOverflow() || current_block() == NULL) return value;  \
3898   } while (false)
3899 
3900 
Bailout(BailoutReason reason)3901 void HOptimizedGraphBuilder::Bailout(BailoutReason reason) {
3902   current_info()->AbortOptimization(reason);
3903   SetStackOverflow();
3904 }
3905 
3906 
VisitForEffect(Expression * expr)3907 void HOptimizedGraphBuilder::VisitForEffect(Expression* expr) {
3908   EffectContext for_effect(this);
3909   Visit(expr);
3910 }
3911 
3912 
VisitForValue(Expression * expr,ArgumentsAllowedFlag flag)3913 void HOptimizedGraphBuilder::VisitForValue(Expression* expr,
3914                                            ArgumentsAllowedFlag flag) {
3915   ValueContext for_value(this, flag);
3916   Visit(expr);
3917 }
3918 
3919 
VisitForTypeOf(Expression * expr)3920 void HOptimizedGraphBuilder::VisitForTypeOf(Expression* expr) {
3921   ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED);
3922   for_value.set_typeof_mode(INSIDE_TYPEOF);
3923   Visit(expr);
3924 }
3925 
3926 
VisitForControl(Expression * expr,HBasicBlock * true_block,HBasicBlock * false_block)3927 void HOptimizedGraphBuilder::VisitForControl(Expression* expr,
3928                                              HBasicBlock* true_block,
3929                                              HBasicBlock* false_block) {
3930   TestContext for_control(this, expr, true_block, false_block);
3931   Visit(expr);
3932 }
3933 
3934 
VisitExpressions(ZoneList<Expression * > * exprs)3935 void HOptimizedGraphBuilder::VisitExpressions(
3936     ZoneList<Expression*>* exprs) {
3937   for (int i = 0; i < exprs->length(); ++i) {
3938     CHECK_ALIVE(VisitForValue(exprs->at(i)));
3939   }
3940 }
3941 
3942 
VisitExpressions(ZoneList<Expression * > * exprs,ArgumentsAllowedFlag flag)3943 void HOptimizedGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs,
3944                                               ArgumentsAllowedFlag flag) {
3945   for (int i = 0; i < exprs->length(); ++i) {
3946     CHECK_ALIVE(VisitForValue(exprs->at(i), flag));
3947   }
3948 }
3949 
3950 
BuildGraph()3951 bool HOptimizedGraphBuilder::BuildGraph() {
3952   if (IsDerivedConstructor(current_info()->literal()->kind())) {
3953     Bailout(kSuperReference);
3954     return false;
3955   }
3956 
3957   DeclarationScope* scope = current_info()->scope();
3958   SetUpScope(scope);
3959 
3960   // Add an edge to the body entry.  This is warty: the graph's start
3961   // environment will be used by the Lithium translation as the initial
3962   // environment on graph entry, but it has now been mutated by the
3963   // Hydrogen translation of the instructions in the start block.  This
3964   // environment uses values which have not been defined yet.  These
3965   // Hydrogen instructions will then be replayed by the Lithium
3966   // translation, so they cannot have an environment effect.  The edge to
3967   // the body's entry block (along with some special logic for the start
3968   // block in HInstruction::InsertAfter) seals the start block from
3969   // getting unwanted instructions inserted.
3970   //
3971   // TODO(kmillikin): Fix this.  Stop mutating the initial environment.
3972   // Make the Hydrogen instructions in the initial block into Hydrogen
3973   // values (but not instructions), present in the initial environment and
3974   // not replayed by the Lithium translation.
3975   HEnvironment* initial_env = environment()->CopyWithoutHistory();
3976   HBasicBlock* body_entry = CreateBasicBlock(initial_env);
3977   Goto(body_entry);
3978   body_entry->SetJoinId(BailoutId::FunctionEntry());
3979   set_current_block(body_entry);
3980 
3981   VisitDeclarations(scope->declarations());
3982   Add<HSimulate>(BailoutId::Declarations());
3983 
3984   Add<HStackCheck>(HStackCheck::kFunctionEntry);
3985 
3986   VisitStatements(current_info()->literal()->body());
3987   if (HasStackOverflow()) return false;
3988 
3989   if (current_block() != NULL) {
3990     Add<HReturn>(graph()->GetConstantUndefined());
3991     set_current_block(NULL);
3992   }
3993 
3994   // If the checksum of the number of type info changes is the same as the
3995   // last time this function was compiled, then this recompile is likely not
3996   // due to missing/inadequate type feedback, but rather too aggressive
3997   // optimization. Disable optimistic LICM in that case.
3998   Handle<Code> unoptimized_code(current_info()->shared_info()->code());
3999   DCHECK(unoptimized_code->kind() == Code::FUNCTION);
4000   Handle<TypeFeedbackInfo> type_info(
4001       TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info()));
4002   int checksum = type_info->own_type_change_checksum();
4003   int composite_checksum = graph()->update_type_change_checksum(checksum);
4004   graph()->set_use_optimistic_licm(
4005       !type_info->matches_inlined_type_change_checksum(composite_checksum));
4006   type_info->set_inlined_type_change_checksum(composite_checksum);
4007 
4008   // Set this predicate early to avoid handle deref during graph optimization.
4009   graph()->set_allow_code_motion(
4010       current_info()->IsStub() ||
4011       current_info()->shared_info()->opt_count() + 1 < FLAG_max_opt_count);
4012 
4013   // Perform any necessary OSR-specific cleanups or changes to the graph.
4014   osr()->FinishGraph();
4015 
4016   return true;
4017 }
4018 
4019 
Optimize(BailoutReason * bailout_reason)4020 bool HGraph::Optimize(BailoutReason* bailout_reason) {
4021   OrderBlocks();
4022   AssignDominators();
4023 
4024   // We need to create a HConstant "zero" now so that GVN will fold every
4025   // zero-valued constant in the graph together.
4026   // The constant is needed to make idef-based bounds check work: the pass
4027   // evaluates relations with "zero" and that zero cannot be created after GVN.
4028   GetConstant0();
4029 
4030 #ifdef DEBUG
4031   // Do a full verify after building the graph and computing dominators.
4032   Verify(true);
4033 #endif
4034 
4035   if (FLAG_analyze_environment_liveness && maximum_environment_size() != 0) {
4036     Run<HEnvironmentLivenessAnalysisPhase>();
4037   }
4038 
4039   if (!CheckConstPhiUses()) {
4040     *bailout_reason = kUnsupportedPhiUseOfConstVariable;
4041     return false;
4042   }
4043   Run<HRedundantPhiEliminationPhase>();
4044   if (!CheckArgumentsPhiUses()) {
4045     *bailout_reason = kUnsupportedPhiUseOfArguments;
4046     return false;
4047   }
4048 
4049   // Find and mark unreachable code to simplify optimizations, especially gvn,
4050   // where unreachable code could unnecessarily defeat LICM.
4051   Run<HMarkUnreachableBlocksPhase>();
4052 
4053   if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>();
4054   if (FLAG_use_escape_analysis) Run<HEscapeAnalysisPhase>();
4055 
4056   if (FLAG_load_elimination) Run<HLoadEliminationPhase>();
4057 
4058   CollectPhis();
4059 
4060   if (has_osr()) osr()->FinishOsrValues();
4061 
4062   Run<HInferRepresentationPhase>();
4063 
4064   // Remove HSimulate instructions that have turned out not to be needed
4065   // after all by folding them into the following HSimulate.
4066   // This must happen after inferring representations.
4067   Run<HMergeRemovableSimulatesPhase>();
4068 
4069   Run<HRepresentationChangesPhase>();
4070 
4071   Run<HInferTypesPhase>();
4072 
4073   // Must be performed before canonicalization to ensure that Canonicalize
4074   // will not remove semantically meaningful ToInt32 operations e.g. BIT_OR with
4075   // zero.
4076   Run<HUint32AnalysisPhase>();
4077 
4078   if (FLAG_use_canonicalizing) Run<HCanonicalizePhase>();
4079 
4080   if (FLAG_use_gvn) Run<HGlobalValueNumberingPhase>();
4081 
4082   if (FLAG_check_elimination) Run<HCheckEliminationPhase>();
4083 
4084   if (FLAG_store_elimination) Run<HStoreEliminationPhase>();
4085 
4086   Run<HRangeAnalysisPhase>();
4087 
4088   // Eliminate redundant stack checks on backwards branches.
4089   Run<HStackCheckEliminationPhase>();
4090 
4091   if (FLAG_array_bounds_checks_elimination) Run<HBoundsCheckEliminationPhase>();
4092   if (FLAG_array_index_dehoisting) Run<HDehoistIndexComputationsPhase>();
4093   if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>();
4094 
4095   RestoreActualValues();
4096 
4097   // Find unreachable code a second time, GVN and other optimizations may have
4098   // made blocks unreachable that were previously reachable.
4099   Run<HMarkUnreachableBlocksPhase>();
4100 
4101   return true;
4102 }
4103 
4104 
RestoreActualValues()4105 void HGraph::RestoreActualValues() {
4106   HPhase phase("H_Restore actual values", this);
4107 
4108   for (int block_index = 0; block_index < blocks()->length(); block_index++) {
4109     HBasicBlock* block = blocks()->at(block_index);
4110 
4111 #ifdef DEBUG
4112     for (int i = 0; i < block->phis()->length(); i++) {
4113       HPhi* phi = block->phis()->at(i);
4114       DCHECK(phi->ActualValue() == phi);
4115     }
4116 #endif
4117 
4118     for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
4119       HInstruction* instruction = it.Current();
4120       if (instruction->ActualValue() == instruction) continue;
4121       if (instruction->CheckFlag(HValue::kIsDead)) {
4122         // The instruction was marked as deleted but left in the graph
4123         // as a control flow dependency point for subsequent
4124         // instructions.
4125         instruction->DeleteAndReplaceWith(instruction->ActualValue());
4126       } else {
4127         DCHECK(instruction->IsInformativeDefinition());
4128         if (instruction->IsPurelyInformativeDefinition()) {
4129           instruction->DeleteAndReplaceWith(instruction->RedefinedOperand());
4130         } else {
4131           instruction->ReplaceAllUsesWith(instruction->ActualValue());
4132         }
4133       }
4134     }
4135   }
4136 }
4137 
4138 
PushArgumentsFromEnvironment(int count)4139 void HOptimizedGraphBuilder::PushArgumentsFromEnvironment(int count) {
4140   ZoneList<HValue*> arguments(count, zone());
4141   for (int i = 0; i < count; ++i) {
4142     arguments.Add(Pop(), zone());
4143   }
4144 
4145   HPushArguments* push_args = New<HPushArguments>();
4146   while (!arguments.is_empty()) {
4147     push_args->AddInput(arguments.RemoveLast());
4148   }
4149   AddInstruction(push_args);
4150 }
4151 
4152 
4153 template <class Instruction>
PreProcessCall(Instruction * call)4154 HInstruction* HOptimizedGraphBuilder::PreProcessCall(Instruction* call) {
4155   PushArgumentsFromEnvironment(call->argument_count());
4156   return call;
4157 }
4158 
SetUpScope(DeclarationScope * scope)4159 void HOptimizedGraphBuilder::SetUpScope(DeclarationScope* scope) {
4160   HEnvironment* prolog_env = environment();
4161   int parameter_count = environment()->parameter_count();
4162   ZoneList<HValue*> parameters(parameter_count, zone());
4163   for (int i = 0; i < parameter_count; ++i) {
4164     HInstruction* parameter = Add<HParameter>(static_cast<unsigned>(i));
4165     parameters.Add(parameter, zone());
4166     environment()->Bind(i, parameter);
4167   }
4168 
4169   HConstant* undefined_constant = graph()->GetConstantUndefined();
4170   // Initialize specials and locals to undefined.
4171   for (int i = parameter_count + 1; i < environment()->length(); ++i) {
4172     environment()->Bind(i, undefined_constant);
4173   }
4174   Add<HPrologue>();
4175 
4176   HEnvironment* initial_env = environment()->CopyWithoutHistory();
4177   HBasicBlock* body_entry = CreateBasicBlock(initial_env);
4178   GotoNoSimulate(body_entry);
4179   set_current_block(body_entry);
4180 
4181   // Initialize context of prolog environment to undefined.
4182   prolog_env->BindContext(undefined_constant);
4183 
4184   // First special is HContext.
4185   HInstruction* context = Add<HContext>();
4186   environment()->BindContext(context);
4187 
4188   // Create an arguments object containing the initial parameters.  Set the
4189   // initial values of parameters including "this" having parameter index 0.
4190   DCHECK_EQ(scope->num_parameters() + 1, parameter_count);
4191   HArgumentsObject* arguments_object = New<HArgumentsObject>(parameter_count);
4192   for (int i = 0; i < parameter_count; ++i) {
4193     HValue* parameter = parameters.at(i);
4194     arguments_object->AddArgument(parameter, zone());
4195   }
4196 
4197   AddInstruction(arguments_object);
4198 
4199   // Handle the arguments and arguments shadow variables specially (they do
4200   // not have declarations).
4201   if (scope->arguments() != NULL) {
4202     environment()->Bind(scope->arguments(), arguments_object);
4203   }
4204 
4205   if (scope->rest_parameter() != nullptr) {
4206     return Bailout(kRestParameter);
4207   }
4208 
4209   if (scope->this_function_var() != nullptr ||
4210       scope->new_target_var() != nullptr) {
4211     return Bailout(kSuperReference);
4212   }
4213 
4214   // Trace the call.
4215   if (FLAG_trace && top_info()->IsOptimizing()) {
4216     Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kTraceEnter), 0);
4217   }
4218 }
4219 
4220 
VisitStatements(ZoneList<Statement * > * statements)4221 void HOptimizedGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) {
4222   for (int i = 0; i < statements->length(); i++) {
4223     Statement* stmt = statements->at(i);
4224     CHECK_ALIVE(Visit(stmt));
4225     if (stmt->IsJump()) break;
4226   }
4227 }
4228 
4229 
VisitBlock(Block * stmt)4230 void HOptimizedGraphBuilder::VisitBlock(Block* stmt) {
4231   DCHECK(!HasStackOverflow());
4232   DCHECK(current_block() != NULL);
4233   DCHECK(current_block()->HasPredecessor());
4234 
4235   Scope* outer_scope = scope();
4236   Scope* scope = stmt->scope();
4237   BreakAndContinueInfo break_info(stmt, outer_scope);
4238 
4239   { BreakAndContinueScope push(&break_info, this);
4240     if (scope != NULL) {
4241       if (scope->NeedsContext()) {
4242         // Load the function object.
4243         DeclarationScope* declaration_scope = scope->GetDeclarationScope();
4244         HInstruction* function;
4245         HValue* outer_context = environment()->context();
4246         if (declaration_scope->is_script_scope() ||
4247             declaration_scope->is_eval_scope()) {
4248           function = new (zone())
4249               HLoadContextSlot(outer_context, Context::CLOSURE_INDEX,
4250                                HLoadContextSlot::kNoCheck);
4251         } else {
4252           function = New<HThisFunction>();
4253         }
4254         AddInstruction(function);
4255         // Allocate a block context and store it to the stack frame.
4256         HValue* scope_info = Add<HConstant>(scope->scope_info());
4257         Add<HPushArguments>(scope_info, function);
4258         HInstruction* inner_context = Add<HCallRuntime>(
4259             Runtime::FunctionForId(Runtime::kPushBlockContext), 2);
4260         inner_context->SetFlag(HValue::kHasNoObservableSideEffects);
4261         set_scope(scope);
4262         environment()->BindContext(inner_context);
4263       }
4264       VisitDeclarations(scope->declarations());
4265       AddSimulate(stmt->DeclsId(), REMOVABLE_SIMULATE);
4266     }
4267     CHECK_BAILOUT(VisitStatements(stmt->statements()));
4268   }
4269   set_scope(outer_scope);
4270   if (scope != NULL && current_block() != NULL &&
4271       scope->ContextLocalCount() > 0) {
4272     HValue* inner_context = environment()->context();
4273     HValue* outer_context = Add<HLoadNamedField>(
4274         inner_context, nullptr,
4275         HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
4276 
4277     environment()->BindContext(outer_context);
4278   }
4279   HBasicBlock* break_block = break_info.break_block();
4280   if (break_block != NULL) {
4281     if (current_block() != NULL) Goto(break_block);
4282     break_block->SetJoinId(stmt->ExitId());
4283     set_current_block(break_block);
4284   }
4285 }
4286 
4287 
VisitExpressionStatement(ExpressionStatement * stmt)4288 void HOptimizedGraphBuilder::VisitExpressionStatement(
4289     ExpressionStatement* stmt) {
4290   DCHECK(!HasStackOverflow());
4291   DCHECK(current_block() != NULL);
4292   DCHECK(current_block()->HasPredecessor());
4293   VisitForEffect(stmt->expression());
4294 }
4295 
4296 
VisitEmptyStatement(EmptyStatement * stmt)4297 void HOptimizedGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
4298   DCHECK(!HasStackOverflow());
4299   DCHECK(current_block() != NULL);
4300   DCHECK(current_block()->HasPredecessor());
4301 }
4302 
4303 
VisitSloppyBlockFunctionStatement(SloppyBlockFunctionStatement * stmt)4304 void HOptimizedGraphBuilder::VisitSloppyBlockFunctionStatement(
4305     SloppyBlockFunctionStatement* stmt) {
4306   Visit(stmt->statement());
4307 }
4308 
4309 
VisitIfStatement(IfStatement * stmt)4310 void HOptimizedGraphBuilder::VisitIfStatement(IfStatement* stmt) {
4311   DCHECK(!HasStackOverflow());
4312   DCHECK(current_block() != NULL);
4313   DCHECK(current_block()->HasPredecessor());
4314   if (stmt->condition()->ToBooleanIsTrue()) {
4315     Add<HSimulate>(stmt->ThenId());
4316     Visit(stmt->then_statement());
4317   } else if (stmt->condition()->ToBooleanIsFalse()) {
4318     Add<HSimulate>(stmt->ElseId());
4319     Visit(stmt->else_statement());
4320   } else {
4321     HBasicBlock* cond_true = graph()->CreateBasicBlock();
4322     HBasicBlock* cond_false = graph()->CreateBasicBlock();
4323     CHECK_BAILOUT(VisitForControl(stmt->condition(), cond_true, cond_false));
4324 
4325     // Technically, we should be able to handle the case when one side of
4326     // the test is not connected, but this can trip up liveness analysis
4327     // if we did not fully connect the test context based on some optimistic
4328     // assumption. If such an assumption was violated, we would end up with
4329     // an environment with optimized-out values. So we should always
4330     // conservatively connect the test context.
4331     CHECK(cond_true->HasPredecessor());
4332     CHECK(cond_false->HasPredecessor());
4333 
4334     cond_true->SetJoinId(stmt->ThenId());
4335     set_current_block(cond_true);
4336     CHECK_BAILOUT(Visit(stmt->then_statement()));
4337     cond_true = current_block();
4338 
4339     cond_false->SetJoinId(stmt->ElseId());
4340     set_current_block(cond_false);
4341     CHECK_BAILOUT(Visit(stmt->else_statement()));
4342     cond_false = current_block();
4343 
4344     HBasicBlock* join = CreateJoin(cond_true, cond_false, stmt->IfId());
4345     set_current_block(join);
4346   }
4347 }
4348 
4349 
Get(BreakableStatement * stmt,BreakType type,Scope ** scope,int * drop_extra)4350 HBasicBlock* HOptimizedGraphBuilder::BreakAndContinueScope::Get(
4351     BreakableStatement* stmt,
4352     BreakType type,
4353     Scope** scope,
4354     int* drop_extra) {
4355   *drop_extra = 0;
4356   BreakAndContinueScope* current = this;
4357   while (current != NULL && current->info()->target() != stmt) {
4358     *drop_extra += current->info()->drop_extra();
4359     current = current->next();
4360   }
4361   DCHECK(current != NULL);  // Always found (unless stack is malformed).
4362   *scope = current->info()->scope();
4363 
4364   if (type == BREAK) {
4365     *drop_extra += current->info()->drop_extra();
4366   }
4367 
4368   HBasicBlock* block = NULL;
4369   switch (type) {
4370     case BREAK:
4371       block = current->info()->break_block();
4372       if (block == NULL) {
4373         block = current->owner()->graph()->CreateBasicBlock();
4374         current->info()->set_break_block(block);
4375       }
4376       break;
4377 
4378     case CONTINUE:
4379       block = current->info()->continue_block();
4380       if (block == NULL) {
4381         block = current->owner()->graph()->CreateBasicBlock();
4382         current->info()->set_continue_block(block);
4383       }
4384       break;
4385   }
4386 
4387   return block;
4388 }
4389 
4390 
VisitContinueStatement(ContinueStatement * stmt)4391 void HOptimizedGraphBuilder::VisitContinueStatement(
4392     ContinueStatement* stmt) {
4393   DCHECK(!HasStackOverflow());
4394   DCHECK(current_block() != NULL);
4395   DCHECK(current_block()->HasPredecessor());
4396 
4397   if (function_state()->IsInsideDoExpressionScope()) {
4398     return Bailout(kDoExpressionUnmodelable);
4399   }
4400 
4401   Scope* outer_scope = NULL;
4402   Scope* inner_scope = scope();
4403   int drop_extra = 0;
4404   HBasicBlock* continue_block = break_scope()->Get(
4405       stmt->target(), BreakAndContinueScope::CONTINUE,
4406       &outer_scope, &drop_extra);
4407   HValue* context = environment()->context();
4408   Drop(drop_extra);
4409   int context_pop_count = inner_scope->ContextChainLength(outer_scope);
4410   if (context_pop_count > 0) {
4411     while (context_pop_count-- > 0) {
4412       HInstruction* context_instruction = Add<HLoadNamedField>(
4413           context, nullptr,
4414           HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
4415       context = context_instruction;
4416     }
4417     environment()->BindContext(context);
4418   }
4419 
4420   Goto(continue_block);
4421   set_current_block(NULL);
4422 }
4423 
4424 
VisitBreakStatement(BreakStatement * stmt)4425 void HOptimizedGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
4426   DCHECK(!HasStackOverflow());
4427   DCHECK(current_block() != NULL);
4428   DCHECK(current_block()->HasPredecessor());
4429 
4430   if (function_state()->IsInsideDoExpressionScope()) {
4431     return Bailout(kDoExpressionUnmodelable);
4432   }
4433 
4434   Scope* outer_scope = NULL;
4435   Scope* inner_scope = scope();
4436   int drop_extra = 0;
4437   HBasicBlock* break_block = break_scope()->Get(
4438       stmt->target(), BreakAndContinueScope::BREAK,
4439       &outer_scope, &drop_extra);
4440   HValue* context = environment()->context();
4441   Drop(drop_extra);
4442   int context_pop_count = inner_scope->ContextChainLength(outer_scope);
4443   if (context_pop_count > 0) {
4444     while (context_pop_count-- > 0) {
4445       HInstruction* context_instruction = Add<HLoadNamedField>(
4446           context, nullptr,
4447           HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
4448       context = context_instruction;
4449     }
4450     environment()->BindContext(context);
4451   }
4452   Goto(break_block);
4453   set_current_block(NULL);
4454 }
4455 
4456 
VisitReturnStatement(ReturnStatement * stmt)4457 void HOptimizedGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
4458   DCHECK(!HasStackOverflow());
4459   DCHECK(current_block() != NULL);
4460   DCHECK(current_block()->HasPredecessor());
4461   FunctionState* state = function_state();
4462   AstContext* context = call_context();
4463   if (context == NULL) {
4464     // Not an inlined return, so an actual one.
4465     CHECK_ALIVE(VisitForValue(stmt->expression()));
4466     HValue* result = environment()->Pop();
4467     Add<HReturn>(result);
4468   } else if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) {
4469     // Return from an inlined construct call. In a test context the return value
4470     // will always evaluate to true, in a value context the return value needs
4471     // to be a JSObject.
4472     if (context->IsTest()) {
4473       CHECK_ALIVE(VisitForEffect(stmt->expression()));
4474       context->ReturnValue(graph()->GetConstantTrue());
4475     } else if (context->IsEffect()) {
4476       CHECK_ALIVE(VisitForEffect(stmt->expression()));
4477       Goto(function_return(), state);
4478     } else {
4479       DCHECK(context->IsValue());
4480       CHECK_ALIVE(VisitForValue(stmt->expression()));
4481       HValue* return_value = Pop();
4482       HValue* receiver = environment()->arguments_environment()->Lookup(0);
4483       HHasInstanceTypeAndBranch* typecheck =
4484           New<HHasInstanceTypeAndBranch>(return_value,
4485                                          FIRST_JS_RECEIVER_TYPE,
4486                                          LAST_JS_RECEIVER_TYPE);
4487       HBasicBlock* if_spec_object = graph()->CreateBasicBlock();
4488       HBasicBlock* not_spec_object = graph()->CreateBasicBlock();
4489       typecheck->SetSuccessorAt(0, if_spec_object);
4490       typecheck->SetSuccessorAt(1, not_spec_object);
4491       FinishCurrentBlock(typecheck);
4492       AddLeaveInlined(if_spec_object, return_value, state);
4493       AddLeaveInlined(not_spec_object, receiver, state);
4494     }
4495   } else if (state->inlining_kind() == SETTER_CALL_RETURN) {
4496     // Return from an inlined setter call. The returned value is never used, the
4497     // value of an assignment is always the value of the RHS of the assignment.
4498     CHECK_ALIVE(VisitForEffect(stmt->expression()));
4499     if (context->IsTest()) {
4500       HValue* rhs = environment()->arguments_environment()->Lookup(1);
4501       context->ReturnValue(rhs);
4502     } else if (context->IsEffect()) {
4503       Goto(function_return(), state);
4504     } else {
4505       DCHECK(context->IsValue());
4506       HValue* rhs = environment()->arguments_environment()->Lookup(1);
4507       AddLeaveInlined(rhs, state);
4508     }
4509   } else {
4510     // Return from a normal inlined function. Visit the subexpression in the
4511     // expression context of the call.
4512     if (context->IsTest()) {
4513       TestContext* test = TestContext::cast(context);
4514       VisitForControl(stmt->expression(), test->if_true(), test->if_false());
4515     } else if (context->IsEffect()) {
4516       // Visit in value context and ignore the result. This is needed to keep
4517       // environment in sync with full-codegen since some visitors (e.g.
4518       // VisitCountOperation) use the operand stack differently depending on
4519       // context.
4520       CHECK_ALIVE(VisitForValue(stmt->expression()));
4521       Pop();
4522       Goto(function_return(), state);
4523     } else {
4524       DCHECK(context->IsValue());
4525       CHECK_ALIVE(VisitForValue(stmt->expression()));
4526       AddLeaveInlined(Pop(), state);
4527     }
4528   }
4529   set_current_block(NULL);
4530 }
4531 
4532 
VisitWithStatement(WithStatement * stmt)4533 void HOptimizedGraphBuilder::VisitWithStatement(WithStatement* stmt) {
4534   DCHECK(!HasStackOverflow());
4535   DCHECK(current_block() != NULL);
4536   DCHECK(current_block()->HasPredecessor());
4537   return Bailout(kWithStatement);
4538 }
4539 
4540 
VisitSwitchStatement(SwitchStatement * stmt)4541 void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
4542   DCHECK(!HasStackOverflow());
4543   DCHECK(current_block() != NULL);
4544   DCHECK(current_block()->HasPredecessor());
4545 
4546   ZoneList<CaseClause*>* clauses = stmt->cases();
4547   int clause_count = clauses->length();
4548   ZoneList<HBasicBlock*> body_blocks(clause_count, zone());
4549 
4550   CHECK_ALIVE(VisitForValue(stmt->tag()));
4551   Add<HSimulate>(stmt->EntryId());
4552   HValue* tag_value = Top();
4553   AstType* tag_type = bounds_.get(stmt->tag()).lower;
4554 
4555   // 1. Build all the tests, with dangling true branches
4556   BailoutId default_id = BailoutId::None();
4557   for (int i = 0; i < clause_count; ++i) {
4558     CaseClause* clause = clauses->at(i);
4559     if (clause->is_default()) {
4560       body_blocks.Add(NULL, zone());
4561       if (default_id.IsNone()) default_id = clause->EntryId();
4562       continue;
4563     }
4564 
4565     // Generate a compare and branch.
4566     CHECK_BAILOUT(VisitForValue(clause->label()));
4567     if (current_block() == NULL) return Bailout(kUnsupportedSwitchStatement);
4568     HValue* label_value = Pop();
4569 
4570     AstType* label_type = bounds_.get(clause->label()).lower;
4571     AstType* combined_type = clause->compare_type();
4572     HControlInstruction* compare = BuildCompareInstruction(
4573         Token::EQ_STRICT, tag_value, label_value, tag_type, label_type,
4574         combined_type,
4575         ScriptPositionToSourcePosition(stmt->tag()->position()),
4576         ScriptPositionToSourcePosition(clause->label()->position()),
4577         PUSH_BEFORE_SIMULATE, clause->id());
4578 
4579     HBasicBlock* next_test_block = graph()->CreateBasicBlock();
4580     HBasicBlock* body_block = graph()->CreateBasicBlock();
4581     body_blocks.Add(body_block, zone());
4582     compare->SetSuccessorAt(0, body_block);
4583     compare->SetSuccessorAt(1, next_test_block);
4584     FinishCurrentBlock(compare);
4585 
4586     set_current_block(body_block);
4587     Drop(1);  // tag_value
4588 
4589     set_current_block(next_test_block);
4590   }
4591 
4592   // Save the current block to use for the default or to join with the
4593   // exit.
4594   HBasicBlock* last_block = current_block();
4595   Drop(1);  // tag_value
4596 
4597   // 2. Loop over the clauses and the linked list of tests in lockstep,
4598   // translating the clause bodies.
4599   HBasicBlock* fall_through_block = NULL;
4600 
4601   BreakAndContinueInfo break_info(stmt, scope());
4602   { BreakAndContinueScope push(&break_info, this);
4603     for (int i = 0; i < clause_count; ++i) {
4604       CaseClause* clause = clauses->at(i);
4605 
4606       // Identify the block where normal (non-fall-through) control flow
4607       // goes to.
4608       HBasicBlock* normal_block = NULL;
4609       if (clause->is_default()) {
4610         if (last_block == NULL) continue;
4611         normal_block = last_block;
4612         last_block = NULL;  // Cleared to indicate we've handled it.
4613       } else {
4614         normal_block = body_blocks[i];
4615       }
4616 
4617       if (fall_through_block == NULL) {
4618         set_current_block(normal_block);
4619       } else {
4620         HBasicBlock* join = CreateJoin(fall_through_block,
4621                                        normal_block,
4622                                        clause->EntryId());
4623         set_current_block(join);
4624       }
4625 
4626       CHECK_BAILOUT(VisitStatements(clause->statements()));
4627       fall_through_block = current_block();
4628     }
4629   }
4630 
4631   // Create an up-to-3-way join.  Use the break block if it exists since
4632   // it's already a join block.
4633   HBasicBlock* break_block = break_info.break_block();
4634   if (break_block == NULL) {
4635     set_current_block(CreateJoin(fall_through_block,
4636                                  last_block,
4637                                  stmt->ExitId()));
4638   } else {
4639     if (fall_through_block != NULL) Goto(fall_through_block, break_block);
4640     if (last_block != NULL) Goto(last_block, break_block);
4641     break_block->SetJoinId(stmt->ExitId());
4642     set_current_block(break_block);
4643   }
4644 }
4645 
VisitLoopBody(IterationStatement * stmt,BailoutId stack_check_id,HBasicBlock * loop_entry)4646 void HOptimizedGraphBuilder::VisitLoopBody(IterationStatement* stmt,
4647                                            BailoutId stack_check_id,
4648                                            HBasicBlock* loop_entry) {
4649   Add<HSimulate>(stack_check_id);
4650   HStackCheck* stack_check =
4651       HStackCheck::cast(Add<HStackCheck>(HStackCheck::kBackwardsBranch));
4652   DCHECK(loop_entry->IsLoopHeader());
4653   loop_entry->loop_information()->set_stack_check(stack_check);
4654   CHECK_BAILOUT(Visit(stmt->body()));
4655 }
4656 
4657 
VisitDoWhileStatement(DoWhileStatement * stmt)4658 void HOptimizedGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
4659   DCHECK(!HasStackOverflow());
4660   DCHECK(current_block() != NULL);
4661   DCHECK(current_block()->HasPredecessor());
4662   DCHECK(current_block() != NULL);
4663   HBasicBlock* loop_entry = BuildLoopEntry(stmt);
4664 
4665   BreakAndContinueInfo break_info(stmt, scope());
4666   {
4667     BreakAndContinueScope push(&break_info, this);
4668     CHECK_BAILOUT(VisitLoopBody(stmt, stmt->StackCheckId(), loop_entry));
4669   }
4670   HBasicBlock* body_exit = JoinContinue(
4671       stmt, stmt->ContinueId(), current_block(), break_info.continue_block());
4672   HBasicBlock* loop_successor = NULL;
4673   if (body_exit != NULL) {
4674     set_current_block(body_exit);
4675     loop_successor = graph()->CreateBasicBlock();
4676     if (stmt->cond()->ToBooleanIsFalse()) {
4677       loop_entry->loop_information()->stack_check()->Eliminate();
4678       Goto(loop_successor);
4679       body_exit = NULL;
4680     } else {
4681       // The block for a true condition, the actual predecessor block of the
4682       // back edge.
4683       body_exit = graph()->CreateBasicBlock();
4684       CHECK_BAILOUT(VisitForControl(stmt->cond(), body_exit, loop_successor));
4685     }
4686     if (body_exit != NULL && body_exit->HasPredecessor()) {
4687       body_exit->SetJoinId(stmt->BackEdgeId());
4688     } else {
4689       body_exit = NULL;
4690     }
4691     if (loop_successor->HasPredecessor()) {
4692       loop_successor->SetJoinId(stmt->ExitId());
4693     } else {
4694       loop_successor = NULL;
4695     }
4696   }
4697   HBasicBlock* loop_exit = CreateLoop(stmt,
4698                                       loop_entry,
4699                                       body_exit,
4700                                       loop_successor,
4701                                       break_info.break_block());
4702   set_current_block(loop_exit);
4703 }
4704 
4705 
VisitWhileStatement(WhileStatement * stmt)4706 void HOptimizedGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
4707   DCHECK(!HasStackOverflow());
4708   DCHECK(current_block() != NULL);
4709   DCHECK(current_block()->HasPredecessor());
4710   DCHECK(current_block() != NULL);
4711   HBasicBlock* loop_entry = BuildLoopEntry(stmt);
4712 
4713   // If the condition is constant true, do not generate a branch.
4714   HBasicBlock* loop_successor = NULL;
4715   HBasicBlock* body_entry = graph()->CreateBasicBlock();
4716   loop_successor = graph()->CreateBasicBlock();
4717   CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor));
4718   if (body_entry->HasPredecessor()) {
4719     body_entry->SetJoinId(stmt->BodyId());
4720     set_current_block(body_entry);
4721   }
4722   if (loop_successor->HasPredecessor()) {
4723     loop_successor->SetJoinId(stmt->ExitId());
4724   } else {
4725     loop_successor = NULL;
4726   }
4727 
4728   BreakAndContinueInfo break_info(stmt, scope());
4729   if (current_block() != NULL) {
4730     BreakAndContinueScope push(&break_info, this);
4731     CHECK_BAILOUT(VisitLoopBody(stmt, stmt->StackCheckId(), loop_entry));
4732   }
4733   HBasicBlock* body_exit = JoinContinue(
4734       stmt, stmt->ContinueId(), current_block(), break_info.continue_block());
4735   HBasicBlock* loop_exit = CreateLoop(stmt,
4736                                       loop_entry,
4737                                       body_exit,
4738                                       loop_successor,
4739                                       break_info.break_block());
4740   set_current_block(loop_exit);
4741 }
4742 
4743 
VisitForStatement(ForStatement * stmt)4744 void HOptimizedGraphBuilder::VisitForStatement(ForStatement* stmt) {
4745   DCHECK(!HasStackOverflow());
4746   DCHECK(current_block() != NULL);
4747   DCHECK(current_block()->HasPredecessor());
4748   if (stmt->init() != NULL) {
4749     CHECK_ALIVE(Visit(stmt->init()));
4750   }
4751   DCHECK(current_block() != NULL);
4752   HBasicBlock* loop_entry = BuildLoopEntry(stmt);
4753 
4754   HBasicBlock* loop_successor = graph()->CreateBasicBlock();
4755   HBasicBlock* body_entry = graph()->CreateBasicBlock();
4756   if (stmt->cond() != NULL) {
4757     CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor));
4758     if (body_entry->HasPredecessor()) {
4759       body_entry->SetJoinId(stmt->BodyId());
4760       set_current_block(body_entry);
4761     }
4762     if (loop_successor->HasPredecessor()) {
4763       loop_successor->SetJoinId(stmt->ExitId());
4764     } else {
4765       loop_successor = NULL;
4766     }
4767   } else {
4768     // Create dummy control flow so that variable liveness analysis
4769     // produces teh correct result.
4770     HControlInstruction* branch = New<HBranch>(graph()->GetConstantTrue());
4771     branch->SetSuccessorAt(0, body_entry);
4772     branch->SetSuccessorAt(1, loop_successor);
4773     FinishCurrentBlock(branch);
4774     set_current_block(body_entry);
4775   }
4776 
4777   BreakAndContinueInfo break_info(stmt, scope());
4778   if (current_block() != NULL) {
4779     BreakAndContinueScope push(&break_info, this);
4780     CHECK_BAILOUT(VisitLoopBody(stmt, stmt->StackCheckId(), loop_entry));
4781   }
4782   HBasicBlock* body_exit = JoinContinue(
4783       stmt, stmt->ContinueId(), current_block(), break_info.continue_block());
4784 
4785   if (stmt->next() != NULL && body_exit != NULL) {
4786     set_current_block(body_exit);
4787     CHECK_BAILOUT(Visit(stmt->next()));
4788     body_exit = current_block();
4789   }
4790 
4791   HBasicBlock* loop_exit = CreateLoop(stmt,
4792                                       loop_entry,
4793                                       body_exit,
4794                                       loop_successor,
4795                                       break_info.break_block());
4796   set_current_block(loop_exit);
4797 }
4798 
4799 
VisitForInStatement(ForInStatement * stmt)4800 void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
4801   DCHECK(!HasStackOverflow());
4802   DCHECK(current_block() != NULL);
4803   DCHECK(current_block()->HasPredecessor());
4804 
4805   if (!stmt->each()->IsVariableProxy() ||
4806       !stmt->each()->AsVariableProxy()->var()->IsStackLocal()) {
4807     return Bailout(kForInStatementWithNonLocalEachVariable);
4808   }
4809 
4810   Variable* each_var = stmt->each()->AsVariableProxy()->var();
4811 
4812   CHECK_ALIVE(VisitForValue(stmt->enumerable()));
4813   HValue* enumerable = Top();  // Leave enumerable at the top.
4814 
4815   IfBuilder if_undefined_or_null(this);
4816   if_undefined_or_null.If<HCompareObjectEqAndBranch>(
4817       enumerable, graph()->GetConstantUndefined());
4818   if_undefined_or_null.Or();
4819   if_undefined_or_null.If<HCompareObjectEqAndBranch>(
4820       enumerable, graph()->GetConstantNull());
4821   if_undefined_or_null.ThenDeopt(DeoptimizeReason::kUndefinedOrNullInForIn);
4822   if_undefined_or_null.End();
4823   BuildForInBody(stmt, each_var, enumerable);
4824 }
4825 
4826 
BuildForInBody(ForInStatement * stmt,Variable * each_var,HValue * enumerable)4827 void HOptimizedGraphBuilder::BuildForInBody(ForInStatement* stmt,
4828                                             Variable* each_var,
4829                                             HValue* enumerable) {
4830   Handle<Map> meta_map = isolate()->factory()->meta_map();
4831   bool fast = stmt->for_in_type() == ForInStatement::FAST_FOR_IN;
4832   BuildCheckHeapObject(enumerable);
4833   Add<HCheckInstanceType>(enumerable, HCheckInstanceType::IS_JS_RECEIVER);
4834   Add<HSimulate>(stmt->ToObjectId());
4835   if (fast) {
4836     HForInPrepareMap* map = Add<HForInPrepareMap>(enumerable);
4837     Push(map);
4838     Add<HSimulate>(stmt->EnumId());
4839     Drop(1);
4840     Add<HCheckMaps>(map, meta_map);
4841 
4842     HForInCacheArray* array = Add<HForInCacheArray>(
4843         enumerable, map, DescriptorArray::kEnumCacheBridgeCacheIndex);
4844     HValue* enum_length = BuildEnumLength(map);
4845 
4846     HForInCacheArray* index_cache = Add<HForInCacheArray>(
4847         enumerable, map, DescriptorArray::kEnumCacheBridgeIndicesCacheIndex);
4848     array->set_index_cache(index_cache);
4849 
4850     Push(map);
4851     Push(array);
4852     Push(enum_length);
4853     Add<HSimulate>(stmt->PrepareId());
4854   } else {
4855     Runtime::FunctionId function_id = Runtime::kForInEnumerate;
4856     Add<HPushArguments>(enumerable);
4857     HCallRuntime* array =
4858         Add<HCallRuntime>(Runtime::FunctionForId(function_id), 1);
4859     Push(array);
4860     Add<HSimulate>(stmt->EnumId());
4861     Drop(1);
4862 
4863     IfBuilder if_fast(this);
4864     if_fast.If<HCompareMap>(array, meta_map);
4865     if_fast.Then();
4866     {
4867       HValue* cache_map = array;
4868       HForInCacheArray* cache = Add<HForInCacheArray>(
4869           enumerable, cache_map, DescriptorArray::kEnumCacheBridgeCacheIndex);
4870       HValue* enum_length = BuildEnumLength(cache_map);
4871       Push(cache_map);
4872       Push(cache);
4873       Push(enum_length);
4874       Add<HSimulate>(stmt->PrepareId(), FIXED_SIMULATE);
4875     }
4876     if_fast.Else();
4877     {
4878       Push(graph()->GetConstant1());
4879       Push(array);
4880       Push(AddLoadFixedArrayLength(array));
4881       Add<HSimulate>(stmt->PrepareId(), FIXED_SIMULATE);
4882     }
4883   }
4884 
4885   Push(graph()->GetConstant0());
4886 
4887   HBasicBlock* loop_entry = BuildLoopEntry(stmt);
4888 
4889   // Reload the values to ensure we have up-to-date values inside of the loop.
4890   // This is relevant especially for OSR where the values don't come from the
4891   // computation above, but from the OSR entry block.
4892   HValue* index = environment()->ExpressionStackAt(0);
4893   HValue* limit = environment()->ExpressionStackAt(1);
4894   HValue* array = environment()->ExpressionStackAt(2);
4895   HValue* type = environment()->ExpressionStackAt(3);
4896   enumerable = environment()->ExpressionStackAt(4);
4897 
4898   // Check that we still have more keys.
4899   HCompareNumericAndBranch* compare_index =
4900       New<HCompareNumericAndBranch>(index, limit, Token::LT);
4901   compare_index->set_observed_input_representation(
4902       Representation::Smi(), Representation::Smi());
4903 
4904   HBasicBlock* loop_body = graph()->CreateBasicBlock();
4905   HBasicBlock* loop_successor = graph()->CreateBasicBlock();
4906 
4907   compare_index->SetSuccessorAt(0, loop_body);
4908   compare_index->SetSuccessorAt(1, loop_successor);
4909   FinishCurrentBlock(compare_index);
4910 
4911   set_current_block(loop_successor);
4912   Drop(5);
4913 
4914   set_current_block(loop_body);
4915 
4916   // Compute the next enumerated value.
4917   HValue* key = Add<HLoadKeyed>(array, index, index, nullptr, FAST_ELEMENTS);
4918 
4919   HBasicBlock* continue_block = nullptr;
4920   if (fast) {
4921     // Check if expected map still matches that of the enumerable.
4922     Add<HCheckMapValue>(enumerable, type);
4923     Add<HSimulate>(stmt->FilterId());
4924   } else {
4925     // We need the continue block here to be able to skip over invalidated keys.
4926     continue_block = graph()->CreateBasicBlock();
4927 
4928     // We cannot use the IfBuilder here, since we need to be able to jump
4929     // over the loop body in case of undefined result from %ForInFilter,
4930     // and the poor soul that is the IfBuilder get's really confused about
4931     // such "advanced control flow requirements".
4932     HBasicBlock* if_fast = graph()->CreateBasicBlock();
4933     HBasicBlock* if_slow = graph()->CreateBasicBlock();
4934     HBasicBlock* if_slow_pass = graph()->CreateBasicBlock();
4935     HBasicBlock* if_slow_skip = graph()->CreateBasicBlock();
4936     HBasicBlock* if_join = graph()->CreateBasicBlock();
4937 
4938     // Check if expected map still matches that of the enumerable.
4939     HValue* enumerable_map =
4940         Add<HLoadNamedField>(enumerable, nullptr, HObjectAccess::ForMap());
4941     FinishCurrentBlock(
4942         New<HCompareObjectEqAndBranch>(enumerable_map, type, if_fast, if_slow));
4943     set_current_block(if_fast);
4944     {
4945       // The enum cache for enumerable is still valid, no need to check key.
4946       Push(key);
4947       Goto(if_join);
4948     }
4949     set_current_block(if_slow);
4950     {
4951       Callable callable = CodeFactory::ForInFilter(isolate());
4952       HValue* values[] = {key, enumerable};
4953       HConstant* stub_value = Add<HConstant>(callable.code());
4954       Push(Add<HCallWithDescriptor>(stub_value, 0, callable.descriptor(),
4955                                     ArrayVector(values)));
4956       Add<HSimulate>(stmt->FilterId());
4957       FinishCurrentBlock(New<HCompareObjectEqAndBranch>(
4958           Top(), graph()->GetConstantUndefined(), if_slow_skip, if_slow_pass));
4959     }
4960     set_current_block(if_slow_pass);
4961     { Goto(if_join); }
4962     set_current_block(if_slow_skip);
4963     {
4964       // The key is no longer valid for enumerable, skip it.
4965       Drop(1);
4966       Goto(continue_block);
4967     }
4968     if_join->SetJoinId(stmt->FilterId());
4969     set_current_block(if_join);
4970     key = Pop();
4971   }
4972 
4973   Bind(each_var, key);
4974   Add<HSimulate>(stmt->AssignmentId());
4975 
4976   BreakAndContinueInfo break_info(stmt, scope(), 5);
4977   break_info.set_continue_block(continue_block);
4978   {
4979     BreakAndContinueScope push(&break_info, this);
4980     CHECK_BAILOUT(VisitLoopBody(stmt, stmt->StackCheckId(), loop_entry));
4981   }
4982 
4983   HBasicBlock* body_exit = JoinContinue(
4984       stmt, stmt->IncrementId(), current_block(), break_info.continue_block());
4985 
4986   if (body_exit != NULL) {
4987     set_current_block(body_exit);
4988 
4989     HValue* current_index = Pop();
4990     HValue* increment =
4991         AddUncasted<HAdd>(current_index, graph()->GetConstant1());
4992     increment->ClearFlag(HValue::kCanOverflow);
4993     Push(increment);
4994     body_exit = current_block();
4995   }
4996 
4997   HBasicBlock* loop_exit = CreateLoop(stmt,
4998                                       loop_entry,
4999                                       body_exit,
5000                                       loop_successor,
5001                                       break_info.break_block());
5002 
5003   set_current_block(loop_exit);
5004 }
5005 
5006 
VisitForOfStatement(ForOfStatement * stmt)5007 void HOptimizedGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) {
5008   DCHECK(!HasStackOverflow());
5009   DCHECK(current_block() != NULL);
5010   DCHECK(current_block()->HasPredecessor());
5011   return Bailout(kForOfStatement);
5012 }
5013 
5014 
VisitTryCatchStatement(TryCatchStatement * stmt)5015 void HOptimizedGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
5016   DCHECK(!HasStackOverflow());
5017   DCHECK(current_block() != NULL);
5018   DCHECK(current_block()->HasPredecessor());
5019   return Bailout(kTryCatchStatement);
5020 }
5021 
5022 
VisitTryFinallyStatement(TryFinallyStatement * stmt)5023 void HOptimizedGraphBuilder::VisitTryFinallyStatement(
5024     TryFinallyStatement* stmt) {
5025   DCHECK(!HasStackOverflow());
5026   DCHECK(current_block() != NULL);
5027   DCHECK(current_block()->HasPredecessor());
5028   return Bailout(kTryFinallyStatement);
5029 }
5030 
5031 
VisitDebuggerStatement(DebuggerStatement * stmt)5032 void HOptimizedGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
5033   DCHECK(!HasStackOverflow());
5034   DCHECK(current_block() != NULL);
5035   DCHECK(current_block()->HasPredecessor());
5036   return Bailout(kDebuggerStatement);
5037 }
5038 
5039 
VisitCaseClause(CaseClause * clause)5040 void HOptimizedGraphBuilder::VisitCaseClause(CaseClause* clause) {
5041   UNREACHABLE();
5042 }
5043 
5044 
VisitFunctionLiteral(FunctionLiteral * expr)5045 void HOptimizedGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
5046   DCHECK(!HasStackOverflow());
5047   DCHECK(current_block() != NULL);
5048   DCHECK(current_block()->HasPredecessor());
5049   Handle<SharedFunctionInfo> shared_info = Compiler::GetSharedFunctionInfo(
5050       expr, current_info()->script(), top_info());
5051   // We also have a stack overflow if the recursive compilation did.
5052   if (HasStackOverflow()) return;
5053   // Use the fast case closure allocation code that allocates in new
5054   // space for nested functions that don't need pretenuring.
5055   HConstant* shared_info_value = Add<HConstant>(shared_info);
5056   HInstruction* instr;
5057   Handle<FeedbackVector> vector(current_feedback_vector(), isolate());
5058   HValue* vector_value = Add<HConstant>(vector);
5059   int index = FeedbackVector::GetIndex(expr->LiteralFeedbackSlot());
5060   HValue* index_value = Add<HConstant>(index);
5061   if (!expr->pretenure()) {
5062     Callable callable = CodeFactory::FastNewClosure(isolate());
5063     HValue* values[] = {shared_info_value, vector_value, index_value};
5064     HConstant* stub_value = Add<HConstant>(callable.code());
5065     instr = New<HCallWithDescriptor>(stub_value, 0, callable.descriptor(),
5066                                      ArrayVector(values));
5067   } else {
5068     Add<HPushArguments>(shared_info_value);
5069     Add<HPushArguments>(vector_value);
5070     Add<HPushArguments>(index_value);
5071     Runtime::FunctionId function_id =
5072         expr->pretenure() ? Runtime::kNewClosure_Tenured : Runtime::kNewClosure;
5073     instr = New<HCallRuntime>(Runtime::FunctionForId(function_id), 3);
5074   }
5075   return ast_context()->ReturnInstruction(instr, expr->id());
5076 }
5077 
5078 
VisitClassLiteral(ClassLiteral * lit)5079 void HOptimizedGraphBuilder::VisitClassLiteral(ClassLiteral* lit) {
5080   DCHECK(!HasStackOverflow());
5081   DCHECK(current_block() != NULL);
5082   DCHECK(current_block()->HasPredecessor());
5083   return Bailout(kClassLiteral);
5084 }
5085 
5086 
VisitNativeFunctionLiteral(NativeFunctionLiteral * expr)5087 void HOptimizedGraphBuilder::VisitNativeFunctionLiteral(
5088     NativeFunctionLiteral* expr) {
5089   DCHECK(!HasStackOverflow());
5090   DCHECK(current_block() != NULL);
5091   DCHECK(current_block()->HasPredecessor());
5092   return Bailout(kNativeFunctionLiteral);
5093 }
5094 
5095 
VisitDoExpression(DoExpression * expr)5096 void HOptimizedGraphBuilder::VisitDoExpression(DoExpression* expr) {
5097   DoExpressionScope scope(this);
5098   DCHECK(!HasStackOverflow());
5099   DCHECK(current_block() != NULL);
5100   DCHECK(current_block()->HasPredecessor());
5101   CHECK_ALIVE(VisitBlock(expr->block()));
5102   Visit(expr->result());
5103 }
5104 
5105 
VisitConditional(Conditional * expr)5106 void HOptimizedGraphBuilder::VisitConditional(Conditional* expr) {
5107   DCHECK(!HasStackOverflow());
5108   DCHECK(current_block() != NULL);
5109   DCHECK(current_block()->HasPredecessor());
5110   HBasicBlock* cond_true = graph()->CreateBasicBlock();
5111   HBasicBlock* cond_false = graph()->CreateBasicBlock();
5112   CHECK_BAILOUT(VisitForControl(expr->condition(), cond_true, cond_false));
5113 
5114   // Visit the true and false subexpressions in the same AST context as the
5115   // whole expression.
5116   if (cond_true->HasPredecessor()) {
5117     cond_true->SetJoinId(expr->ThenId());
5118     set_current_block(cond_true);
5119     CHECK_BAILOUT(Visit(expr->then_expression()));
5120     cond_true = current_block();
5121   } else {
5122     cond_true = NULL;
5123   }
5124 
5125   if (cond_false->HasPredecessor()) {
5126     cond_false->SetJoinId(expr->ElseId());
5127     set_current_block(cond_false);
5128     CHECK_BAILOUT(Visit(expr->else_expression()));
5129     cond_false = current_block();
5130   } else {
5131     cond_false = NULL;
5132   }
5133 
5134   if (!ast_context()->IsTest()) {
5135     HBasicBlock* join = CreateJoin(cond_true, cond_false, expr->id());
5136     set_current_block(join);
5137     if (join != NULL && !ast_context()->IsEffect()) {
5138       return ast_context()->ReturnValue(Pop());
5139     }
5140   }
5141 }
5142 
CanInlineGlobalPropertyAccess(Variable * var,LookupIterator * it,PropertyAccessType access_type)5143 bool HOptimizedGraphBuilder::CanInlineGlobalPropertyAccess(
5144     Variable* var, LookupIterator* it, PropertyAccessType access_type) {
5145   if (var->is_this()) return false;
5146   return CanInlineGlobalPropertyAccess(it, access_type);
5147 }
5148 
CanInlineGlobalPropertyAccess(LookupIterator * it,PropertyAccessType access_type)5149 bool HOptimizedGraphBuilder::CanInlineGlobalPropertyAccess(
5150     LookupIterator* it, PropertyAccessType access_type) {
5151   if (!current_info()->has_global_object()) {
5152     return false;
5153   }
5154 
5155   switch (it->state()) {
5156     case LookupIterator::ACCESSOR:
5157     case LookupIterator::ACCESS_CHECK:
5158     case LookupIterator::INTERCEPTOR:
5159     case LookupIterator::INTEGER_INDEXED_EXOTIC:
5160     case LookupIterator::NOT_FOUND:
5161       return false;
5162     case LookupIterator::DATA:
5163       if (access_type == STORE && it->IsReadOnly()) return false;
5164       if (!it->GetHolder<JSObject>()->IsJSGlobalObject()) return false;
5165       return true;
5166     case LookupIterator::JSPROXY:
5167     case LookupIterator::TRANSITION:
5168       UNREACHABLE();
5169   }
5170   UNREACHABLE();
5171   return false;
5172 }
5173 
5174 
BuildContextChainWalk(Variable * var)5175 HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) {
5176   DCHECK(var->IsContextSlot());
5177   HValue* context = environment()->context();
5178   int length = scope()->ContextChainLength(var->scope());
5179   while (length-- > 0) {
5180     context = Add<HLoadNamedField>(
5181         context, nullptr,
5182         HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
5183   }
5184   return context;
5185 }
5186 
InlineGlobalPropertyLoad(LookupIterator * it,BailoutId ast_id)5187 void HOptimizedGraphBuilder::InlineGlobalPropertyLoad(LookupIterator* it,
5188                                                       BailoutId ast_id) {
5189   Handle<PropertyCell> cell = it->GetPropertyCell();
5190   top_info()->dependencies()->AssumePropertyCell(cell);
5191   auto cell_type = it->property_details().cell_type();
5192   if (cell_type == PropertyCellType::kConstant ||
5193       cell_type == PropertyCellType::kUndefined) {
5194     Handle<Object> constant_object(cell->value(), isolate());
5195     if (constant_object->IsConsString()) {
5196       constant_object = String::Flatten(Handle<String>::cast(constant_object));
5197     }
5198     HConstant* constant = New<HConstant>(constant_object);
5199     return ast_context()->ReturnInstruction(constant, ast_id);
5200   } else {
5201     auto access = HObjectAccess::ForPropertyCellValue();
5202     UniqueSet<Map>* field_maps = nullptr;
5203     if (cell_type == PropertyCellType::kConstantType) {
5204       switch (cell->GetConstantType()) {
5205         case PropertyCellConstantType::kSmi:
5206           access = access.WithRepresentation(Representation::Smi());
5207           break;
5208         case PropertyCellConstantType::kStableMap: {
5209           // Check that the map really is stable. The heap object could
5210           // have mutated without the cell updating state. In that case,
5211           // make no promises about the loaded value except that it's a
5212           // heap object.
5213           access = access.WithRepresentation(Representation::HeapObject());
5214           Handle<Map> map(HeapObject::cast(cell->value())->map());
5215           if (map->is_stable()) {
5216             field_maps = new (zone())
5217                 UniqueSet<Map>(Unique<Map>::CreateImmovable(map), zone());
5218           }
5219           break;
5220         }
5221       }
5222     }
5223     HConstant* cell_constant = Add<HConstant>(cell);
5224     HLoadNamedField* instr;
5225     if (field_maps == nullptr) {
5226       instr = New<HLoadNamedField>(cell_constant, nullptr, access);
5227     } else {
5228       instr = New<HLoadNamedField>(cell_constant, nullptr, access, field_maps,
5229                                    HType::HeapObject());
5230     }
5231     instr->ClearDependsOnFlag(kInobjectFields);
5232     instr->SetDependsOnFlag(kGlobalVars);
5233     return ast_context()->ReturnInstruction(instr, ast_id);
5234   }
5235 }
5236 
VisitVariableProxy(VariableProxy * expr)5237 void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
5238   DCHECK(!HasStackOverflow());
5239   DCHECK(current_block() != NULL);
5240   DCHECK(current_block()->HasPredecessor());
5241   Variable* variable = expr->var();
5242   switch (variable->location()) {
5243     case VariableLocation::UNALLOCATED: {
5244       if (IsLexicalVariableMode(variable->mode())) {
5245         // TODO(rossberg): should this be an DCHECK?
5246         return Bailout(kReferenceToGlobalLexicalVariable);
5247       }
5248       // Handle known global constants like 'undefined' specially to avoid a
5249       // load from a global cell for them.
5250       Handle<Object> constant_value =
5251           isolate()->factory()->GlobalConstantFor(variable->name());
5252       if (!constant_value.is_null()) {
5253         HConstant* instr = New<HConstant>(constant_value);
5254         return ast_context()->ReturnInstruction(instr, expr->id());
5255       }
5256 
5257       Handle<JSGlobalObject> global(current_info()->global_object());
5258 
5259       // Lookup in script contexts.
5260       {
5261         Handle<ScriptContextTable> script_contexts(
5262             global->native_context()->script_context_table());
5263         ScriptContextTable::LookupResult lookup;
5264         if (ScriptContextTable::Lookup(script_contexts, variable->name(),
5265                                        &lookup)) {
5266           Handle<Context> script_context = ScriptContextTable::GetContext(
5267               script_contexts, lookup.context_index);
5268           Handle<Object> current_value =
5269               FixedArray::get(*script_context, lookup.slot_index, isolate());
5270 
5271           // If the values is not the hole, it will stay initialized,
5272           // so no need to generate a check.
5273           if (current_value->IsTheHole(isolate())) {
5274             return Bailout(kReferenceToUninitializedVariable);
5275           }
5276           HInstruction* result = New<HLoadNamedField>(
5277               Add<HConstant>(script_context), nullptr,
5278               HObjectAccess::ForContextSlot(lookup.slot_index));
5279           return ast_context()->ReturnInstruction(result, expr->id());
5280         }
5281       }
5282 
5283       LookupIterator it(global, variable->name(), LookupIterator::OWN);
5284       it.TryLookupCachedProperty();
5285       if (CanInlineGlobalPropertyAccess(variable, &it, LOAD)) {
5286         InlineGlobalPropertyLoad(&it, expr->id());
5287         return;
5288       } else {
5289         Handle<FeedbackVector> vector(current_feedback_vector(), isolate());
5290         FeedbackSlot slot = expr->VariableFeedbackSlot();
5291         DCHECK(vector->IsLoadGlobalIC(slot));
5292 
5293         HValue* vector_value = Add<HConstant>(vector);
5294         HValue* slot_value = Add<HConstant>(vector->GetIndex(slot));
5295         Callable callable = CodeFactory::LoadGlobalICInOptimizedCode(
5296             isolate(), ast_context()->typeof_mode());
5297         HValue* stub = Add<HConstant>(callable.code());
5298         HValue* name = Add<HConstant>(variable->name());
5299         HValue* values[] = {name, slot_value, vector_value};
5300         HCallWithDescriptor* instr = New<HCallWithDescriptor>(
5301             Code::LOAD_GLOBAL_IC, stub, 0, callable.descriptor(),
5302             ArrayVector(values));
5303         return ast_context()->ReturnInstruction(instr, expr->id());
5304       }
5305     }
5306 
5307     case VariableLocation::PARAMETER:
5308     case VariableLocation::LOCAL: {
5309       HValue* value = LookupAndMakeLive(variable);
5310       if (value == graph()->GetConstantHole()) {
5311         DCHECK(IsDeclaredVariableMode(variable->mode()) &&
5312                variable->mode() != VAR);
5313         return Bailout(kReferenceToUninitializedVariable);
5314       }
5315       return ast_context()->ReturnValue(value);
5316     }
5317 
5318     case VariableLocation::CONTEXT: {
5319       HValue* context = BuildContextChainWalk(variable);
5320       HLoadContextSlot::Mode mode;
5321       switch (variable->mode()) {
5322         case LET:
5323         case CONST:
5324           mode = HLoadContextSlot::kCheckDeoptimize;
5325           break;
5326         default:
5327           mode = HLoadContextSlot::kNoCheck;
5328           break;
5329       }
5330       HLoadContextSlot* instr =
5331           new(zone()) HLoadContextSlot(context, variable->index(), mode);
5332       return ast_context()->ReturnInstruction(instr, expr->id());
5333     }
5334 
5335     case VariableLocation::LOOKUP:
5336       return Bailout(kReferenceToAVariableWhichRequiresDynamicLookup);
5337 
5338     case VariableLocation::MODULE:
5339       UNREACHABLE();
5340   }
5341 }
5342 
5343 
VisitLiteral(Literal * expr)5344 void HOptimizedGraphBuilder::VisitLiteral(Literal* expr) {
5345   DCHECK(!HasStackOverflow());
5346   DCHECK(current_block() != NULL);
5347   DCHECK(current_block()->HasPredecessor());
5348   HConstant* instr = New<HConstant>(expr->value());
5349   return ast_context()->ReturnInstruction(instr, expr->id());
5350 }
5351 
5352 
VisitRegExpLiteral(RegExpLiteral * expr)5353 void HOptimizedGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
5354   DCHECK(!HasStackOverflow());
5355   DCHECK(current_block() != NULL);
5356   DCHECK(current_block()->HasPredecessor());
5357   Callable callable = CodeFactory::FastCloneRegExp(isolate());
5358   int index = FeedbackVector::GetIndex(expr->literal_slot());
5359   HValue* values[] = {AddThisFunction(), Add<HConstant>(index),
5360                       Add<HConstant>(expr->pattern()),
5361                       Add<HConstant>(expr->flags())};
5362   HConstant* stub_value = Add<HConstant>(callable.code());
5363   HInstruction* instr = New<HCallWithDescriptor>(
5364       stub_value, 0, callable.descriptor(), ArrayVector(values));
5365   return ast_context()->ReturnInstruction(instr, expr->id());
5366 }
5367 
5368 
CanInlinePropertyAccess(Handle<Map> map)5369 static bool CanInlinePropertyAccess(Handle<Map> map) {
5370   if (map->instance_type() == HEAP_NUMBER_TYPE) return true;
5371   if (map->instance_type() < FIRST_NONSTRING_TYPE) return true;
5372   return map->IsJSObjectMap() && !map->is_dictionary_map() &&
5373          !map->has_named_interceptor() &&
5374          // TODO(verwaest): Whitelist contexts to which we have access.
5375          !map->is_access_check_needed();
5376 }
5377 
5378 
5379 // Determines whether the given array or object literal boilerplate satisfies
5380 // all limits to be considered for fast deep-copying and computes the total
5381 // size of all objects that are part of the graph.
IsFastLiteral(Handle<JSObject> boilerplate,int max_depth,int * max_properties)5382 static bool IsFastLiteral(Handle<JSObject> boilerplate,
5383                           int max_depth,
5384                           int* max_properties) {
5385   if (boilerplate->map()->is_deprecated() &&
5386       !JSObject::TryMigrateInstance(boilerplate)) {
5387     return false;
5388   }
5389 
5390   DCHECK(max_depth >= 0 && *max_properties >= 0);
5391   if (max_depth == 0) return false;
5392 
5393   Isolate* isolate = boilerplate->GetIsolate();
5394   Handle<FixedArrayBase> elements(boilerplate->elements());
5395   if (elements->length() > 0 &&
5396       elements->map() != isolate->heap()->fixed_cow_array_map()) {
5397     if (boilerplate->HasFastSmiOrObjectElements()) {
5398       Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
5399       int length = elements->length();
5400       for (int i = 0; i < length; i++) {
5401         if ((*max_properties)-- == 0) return false;
5402         Handle<Object> value(fast_elements->get(i), isolate);
5403         if (value->IsJSObject()) {
5404           Handle<JSObject> value_object = Handle<JSObject>::cast(value);
5405           if (!IsFastLiteral(value_object,
5406                              max_depth - 1,
5407                              max_properties)) {
5408             return false;
5409           }
5410         }
5411       }
5412     } else if (boilerplate->HasFastDoubleElements()) {
5413       if (elements->Size() > kMaxRegularHeapObjectSize) return false;
5414     } else {
5415       return false;
5416     }
5417   }
5418 
5419   Handle<FixedArray> properties(boilerplate->properties());
5420   if (properties->length() > 0) {
5421     return false;
5422   } else {
5423     Handle<DescriptorArray> descriptors(
5424         boilerplate->map()->instance_descriptors());
5425     int limit = boilerplate->map()->NumberOfOwnDescriptors();
5426     for (int i = 0; i < limit; i++) {
5427       PropertyDetails details = descriptors->GetDetails(i);
5428       if (details.location() != kField) continue;
5429       DCHECK_EQ(kData, details.kind());
5430       if ((*max_properties)-- == 0) return false;
5431       FieldIndex field_index = FieldIndex::ForDescriptor(boilerplate->map(), i);
5432       if (boilerplate->IsUnboxedDoubleField(field_index)) continue;
5433       Handle<Object> value(boilerplate->RawFastPropertyAt(field_index),
5434                            isolate);
5435       if (value->IsJSObject()) {
5436         Handle<JSObject> value_object = Handle<JSObject>::cast(value);
5437         if (!IsFastLiteral(value_object,
5438                            max_depth - 1,
5439                            max_properties)) {
5440           return false;
5441         }
5442       }
5443     }
5444   }
5445   return true;
5446 }
5447 
5448 
VisitObjectLiteral(ObjectLiteral * expr)5449 void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
5450   DCHECK(!HasStackOverflow());
5451   DCHECK(current_block() != NULL);
5452   DCHECK(current_block()->HasPredecessor());
5453 
5454   Handle<JSFunction> closure = function_state()->compilation_info()->closure();
5455   HInstruction* literal;
5456 
5457   // Check whether to use fast or slow deep-copying for boilerplate.
5458   int max_properties = kMaxFastLiteralProperties;
5459   Handle<Object> literals_cell(
5460       closure->feedback_vector()->Get(expr->literal_slot()), isolate());
5461   Handle<AllocationSite> site;
5462   Handle<JSObject> boilerplate;
5463   if (!literals_cell->IsUndefined(isolate())) {
5464     // Retrieve the boilerplate
5465     site = Handle<AllocationSite>::cast(literals_cell);
5466     boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()),
5467                                    isolate());
5468   }
5469 
5470   if (!boilerplate.is_null() &&
5471       IsFastLiteral(boilerplate, kMaxFastLiteralDepth, &max_properties)) {
5472     AllocationSiteUsageContext site_context(isolate(), site, false);
5473     site_context.EnterNewScope();
5474     literal = BuildFastLiteral(boilerplate, &site_context);
5475     site_context.ExitScope(site, boilerplate);
5476   } else {
5477     NoObservableSideEffectsScope no_effects(this);
5478     Handle<BoilerplateDescription> constant_properties =
5479         expr->GetOrBuildConstantProperties(isolate());
5480     int literal_index = FeedbackVector::GetIndex(expr->literal_slot());
5481     int flags = expr->ComputeFlags(true);
5482 
5483     Add<HPushArguments>(AddThisFunction(), Add<HConstant>(literal_index),
5484                         Add<HConstant>(constant_properties),
5485                         Add<HConstant>(flags));
5486 
5487     Runtime::FunctionId function_id = Runtime::kCreateObjectLiteral;
5488     literal = Add<HCallRuntime>(Runtime::FunctionForId(function_id), 4);
5489   }
5490 
5491   // The object is expected in the bailout environment during computation
5492   // of the property values and is the value of the entire expression.
5493   Push(literal);
5494   for (int i = 0; i < expr->properties()->length(); i++) {
5495     ObjectLiteral::Property* property = expr->properties()->at(i);
5496     if (property->is_computed_name()) return Bailout(kComputedPropertyName);
5497     if (property->IsCompileTimeValue()) continue;
5498 
5499     Literal* key = property->key()->AsLiteral();
5500     Expression* value = property->value();
5501 
5502     switch (property->kind()) {
5503       case ObjectLiteral::Property::MATERIALIZED_LITERAL:
5504         DCHECK(!CompileTimeValue::IsCompileTimeValue(value));
5505         // Fall through.
5506       case ObjectLiteral::Property::COMPUTED:
5507         // It is safe to use [[Put]] here because the boilerplate already
5508         // contains computed properties with an uninitialized value.
5509         if (key->IsStringLiteral()) {
5510           DCHECK(key->IsPropertyName());
5511           if (property->emit_store()) {
5512             CHECK_ALIVE(VisitForValue(value));
5513             HValue* value = Pop();
5514 
5515             Handle<Map> map = property->GetReceiverType();
5516             Handle<String> name = key->AsPropertyName();
5517             HValue* store;
5518             FeedbackSlot slot = property->GetSlot();
5519             if (map.is_null()) {
5520               // If we don't know the monomorphic type, do a generic store.
5521               CHECK_ALIVE(store = BuildNamedGeneric(STORE, NULL, slot, literal,
5522                                                     name, value));
5523             } else {
5524               PropertyAccessInfo info(this, STORE, map, name);
5525               if (info.CanAccessMonomorphic()) {
5526                 HValue* checked_literal = Add<HCheckMaps>(literal, map);
5527                 DCHECK(!info.IsAccessorConstant());
5528                 info.MarkAsInitializingStore();
5529                 store = BuildMonomorphicAccess(
5530                     &info, literal, checked_literal, value,
5531                     BailoutId::None(), BailoutId::None());
5532                 DCHECK_NOT_NULL(store);
5533               } else {
5534                 CHECK_ALIVE(store = BuildNamedGeneric(STORE, NULL, slot,
5535                                                       literal, name, value));
5536               }
5537             }
5538             if (store->IsInstruction()) {
5539               AddInstruction(HInstruction::cast(store));
5540             }
5541             DCHECK(store->HasObservableSideEffects());
5542             Add<HSimulate>(key->id(), REMOVABLE_SIMULATE);
5543 
5544             // Add [[HomeObject]] to function literals.
5545             if (FunctionLiteral::NeedsHomeObject(property->value())) {
5546               Handle<Symbol> sym = isolate()->factory()->home_object_symbol();
5547               HInstruction* store_home = BuildNamedGeneric(
5548                   STORE, NULL, property->GetSlot(1), value, sym, literal);
5549               AddInstruction(store_home);
5550               DCHECK(store_home->HasObservableSideEffects());
5551               Add<HSimulate>(property->value()->id(), REMOVABLE_SIMULATE);
5552             }
5553           } else {
5554             CHECK_ALIVE(VisitForEffect(value));
5555           }
5556           break;
5557         }
5558         // Fall through.
5559       case ObjectLiteral::Property::PROTOTYPE:
5560       case ObjectLiteral::Property::SETTER:
5561       case ObjectLiteral::Property::GETTER:
5562         return Bailout(kObjectLiteralWithComplexProperty);
5563       default: UNREACHABLE();
5564     }
5565   }
5566 
5567   return ast_context()->ReturnValue(Pop());
5568 }
5569 
5570 
VisitArrayLiteral(ArrayLiteral * expr)5571 void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
5572   DCHECK(!HasStackOverflow());
5573   DCHECK(current_block() != NULL);
5574   DCHECK(current_block()->HasPredecessor());
5575   ZoneList<Expression*>* subexprs = expr->values();
5576   int length = subexprs->length();
5577   HInstruction* literal;
5578 
5579   Handle<AllocationSite> site;
5580   Handle<FeedbackVector> vector(environment()->closure()->feedback_vector(),
5581                                 isolate());
5582   Handle<Object> literals_cell(vector->Get(expr->literal_slot()), isolate());
5583   Handle<JSObject> boilerplate_object;
5584   if (!literals_cell->IsUndefined(isolate())) {
5585     DCHECK(literals_cell->IsAllocationSite());
5586     site = Handle<AllocationSite>::cast(literals_cell);
5587     boilerplate_object = Handle<JSObject>(
5588         JSObject::cast(site->transition_info()), isolate());
5589   }
5590 
5591   // Check whether to use fast or slow deep-copying for boilerplate.
5592   int max_properties = kMaxFastLiteralProperties;
5593   if (!boilerplate_object.is_null() &&
5594       IsFastLiteral(boilerplate_object, kMaxFastLiteralDepth,
5595                     &max_properties)) {
5596     DCHECK(site->SitePointsToLiteral());
5597     AllocationSiteUsageContext site_context(isolate(), site, false);
5598     site_context.EnterNewScope();
5599     literal = BuildFastLiteral(boilerplate_object, &site_context);
5600     site_context.ExitScope(site, boilerplate_object);
5601   } else {
5602     NoObservableSideEffectsScope no_effects(this);
5603     Handle<ConstantElementsPair> constants =
5604         expr->GetOrBuildConstantElements(isolate());
5605     int literal_index = FeedbackVector::GetIndex(expr->literal_slot());
5606     int flags = expr->ComputeFlags(true);
5607 
5608     Add<HPushArguments>(AddThisFunction(), Add<HConstant>(literal_index),
5609                         Add<HConstant>(constants), Add<HConstant>(flags));
5610 
5611     Runtime::FunctionId function_id = Runtime::kCreateArrayLiteral;
5612     literal = Add<HCallRuntime>(Runtime::FunctionForId(function_id), 4);
5613 
5614     // Register to deopt if the boilerplate ElementsKind changes.
5615     if (!site.is_null()) {
5616       top_info()->dependencies()->AssumeTransitionStable(site);
5617     }
5618   }
5619 
5620   // The array is expected in the bailout environment during computation
5621   // of the property values and is the value of the entire expression.
5622   Push(literal);
5623 
5624   HInstruction* elements = NULL;
5625 
5626   for (int i = 0; i < length; i++) {
5627     Expression* subexpr = subexprs->at(i);
5628     DCHECK(!subexpr->IsSpread());
5629 
5630     // If the subexpression is a literal or a simple materialized literal it
5631     // is already set in the cloned array.
5632     if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
5633 
5634     CHECK_ALIVE(VisitForValue(subexpr));
5635     HValue* value = Pop();
5636     if (!Smi::IsValid(i)) return Bailout(kNonSmiKeyInArrayLiteral);
5637 
5638     elements = AddLoadElements(literal);
5639 
5640     HValue* key = Add<HConstant>(i);
5641 
5642     if (!boilerplate_object.is_null()) {
5643       ElementsKind boilerplate_elements_kind =
5644           boilerplate_object->GetElementsKind();
5645       switch (boilerplate_elements_kind) {
5646         case FAST_SMI_ELEMENTS:
5647         case FAST_HOLEY_SMI_ELEMENTS:
5648         case FAST_ELEMENTS:
5649         case FAST_HOLEY_ELEMENTS:
5650         case FAST_DOUBLE_ELEMENTS:
5651         case FAST_HOLEY_DOUBLE_ELEMENTS: {
5652           Add<HStoreKeyed>(elements, key, value, nullptr,
5653                            boilerplate_elements_kind);
5654           break;
5655         }
5656         default:
5657           UNREACHABLE();
5658           break;
5659       }
5660     } else {
5661       HInstruction* instr = BuildKeyedGeneric(
5662           STORE, expr, expr->LiteralFeedbackSlot(), literal, key, value);
5663       AddInstruction(instr);
5664     }
5665 
5666     Add<HSimulate>(expr->GetIdForElement(i));
5667   }
5668 
5669   return ast_context()->ReturnValue(Pop());
5670 }
5671 
5672 
AddCheckMap(HValue * object,Handle<Map> map)5673 HCheckMaps* HOptimizedGraphBuilder::AddCheckMap(HValue* object,
5674                                                 Handle<Map> map) {
5675   BuildCheckHeapObject(object);
5676   return Add<HCheckMaps>(object, map);
5677 }
5678 
5679 
BuildLoadNamedField(PropertyAccessInfo * info,HValue * checked_object)5680 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedField(
5681     PropertyAccessInfo* info,
5682     HValue* checked_object) {
5683   // Check if this is a load of an immutable or constant property.
5684   if (checked_object->ActualValue()->IsConstant()) {
5685     Handle<Object> object(
5686         HConstant::cast(checked_object->ActualValue())->handle(isolate()));
5687 
5688     if (object->IsJSObject()) {
5689       LookupIterator it(object, info->name(),
5690                         LookupIterator::OWN_SKIP_INTERCEPTOR);
5691       if (it.IsFound()) {
5692         bool is_reaonly_non_configurable =
5693             it.IsReadOnly() && !it.IsConfigurable();
5694         if (is_reaonly_non_configurable ||
5695             (FLAG_track_constant_fields && info->IsDataConstantField())) {
5696           Handle<Object> value = JSReceiver::GetDataProperty(&it);
5697           if (!is_reaonly_non_configurable) {
5698             DCHECK(!it.is_dictionary_holder());
5699             // Add dependency on the map that introduced the field.
5700             Handle<Map> field_owner_map = it.GetFieldOwnerMap();
5701             top_info()->dependencies()->AssumeFieldOwner(field_owner_map);
5702           }
5703           return New<HConstant>(value);
5704         }
5705       }
5706     }
5707   }
5708 
5709   HObjectAccess access = info->access();
5710   if (access.representation().IsDouble() &&
5711       (!FLAG_unbox_double_fields || !access.IsInobject())) {
5712     // Load the heap number.
5713     checked_object = Add<HLoadNamedField>(
5714         checked_object, nullptr,
5715         access.WithRepresentation(Representation::Tagged()));
5716     // Load the double value from it.
5717     access = HObjectAccess::ForHeapNumberValue();
5718   }
5719 
5720   SmallMapList* map_list = info->field_maps();
5721   if (map_list->length() == 0) {
5722     return New<HLoadNamedField>(checked_object, checked_object, access);
5723   }
5724 
5725   UniqueSet<Map>* maps = new(zone()) UniqueSet<Map>(map_list->length(), zone());
5726   for (int i = 0; i < map_list->length(); ++i) {
5727     maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone());
5728   }
5729   return New<HLoadNamedField>(
5730       checked_object, checked_object, access, maps, info->field_type());
5731 }
5732 
BuildStoreNamedField(PropertyAccessInfo * info,HValue * checked_object,HValue * value)5733 HValue* HOptimizedGraphBuilder::BuildStoreNamedField(PropertyAccessInfo* info,
5734                                                      HValue* checked_object,
5735                                                      HValue* value) {
5736   bool transition_to_field = info->IsTransition();
5737   // TODO(verwaest): Move this logic into PropertyAccessInfo.
5738   HObjectAccess field_access = info->access();
5739 
5740   bool store_to_constant_field = FLAG_track_constant_fields &&
5741                                  info->StoreMode() != INITIALIZING_STORE &&
5742                                  info->IsDataConstantField();
5743 
5744   HStoreNamedField *instr;
5745   if (field_access.representation().IsDouble() &&
5746       (!FLAG_unbox_double_fields || !field_access.IsInobject())) {
5747     HObjectAccess heap_number_access =
5748         field_access.WithRepresentation(Representation::Tagged());
5749     if (transition_to_field) {
5750       // The store requires a mutable HeapNumber to be allocated.
5751       NoObservableSideEffectsScope no_side_effects(this);
5752       HInstruction* heap_number_size = Add<HConstant>(HeapNumber::kSize);
5753 
5754       // TODO(hpayer): Allocation site pretenuring support.
5755       HInstruction* heap_number =
5756           Add<HAllocate>(heap_number_size, HType::HeapObject(), NOT_TENURED,
5757                          MUTABLE_HEAP_NUMBER_TYPE, graph()->GetConstant0());
5758       AddStoreMapConstant(
5759           heap_number, isolate()->factory()->mutable_heap_number_map());
5760       Add<HStoreNamedField>(heap_number, HObjectAccess::ForHeapNumberValue(),
5761                             value);
5762       instr = New<HStoreNamedField>(checked_object->ActualValue(),
5763                                     heap_number_access,
5764                                     heap_number);
5765     } else {
5766       // Already holds a HeapNumber; load the box and write its value field.
5767       HInstruction* heap_number =
5768           Add<HLoadNamedField>(checked_object, nullptr, heap_number_access);
5769 
5770       if (store_to_constant_field) {
5771         // If the field is constant check that the value we are going to store
5772         // matches current value.
5773         HInstruction* current_value = Add<HLoadNamedField>(
5774             heap_number, nullptr, HObjectAccess::ForHeapNumberValue());
5775         IfBuilder value_checker(this);
5776         value_checker.IfNot<HCompareNumericAndBranch>(current_value, value,
5777                                                       Token::EQ);
5778         value_checker.ThenDeopt(DeoptimizeReason::kValueMismatch);
5779         value_checker.End();
5780         return nullptr;
5781 
5782       } else {
5783         instr = New<HStoreNamedField>(heap_number,
5784                                       HObjectAccess::ForHeapNumberValue(),
5785                                       value, STORE_TO_INITIALIZED_ENTRY);
5786       }
5787     }
5788   } else {
5789     if (store_to_constant_field) {
5790       // If the field is constant check that the value we are going to store
5791       // matches current value.
5792       HInstruction* current_value = Add<HLoadNamedField>(
5793           checked_object->ActualValue(), checked_object, field_access);
5794 
5795       IfBuilder value_checker(this);
5796       if (field_access.representation().IsDouble()) {
5797         value_checker.IfNot<HCompareNumericAndBranch>(current_value, value,
5798                                                       Token::EQ);
5799       } else {
5800         value_checker.IfNot<HCompareObjectEqAndBranch>(current_value, value);
5801       }
5802       value_checker.ThenDeopt(DeoptimizeReason::kValueMismatch);
5803       value_checker.End();
5804       return nullptr;
5805 
5806     } else {
5807       if (field_access.representation().IsHeapObject()) {
5808         BuildCheckHeapObject(value);
5809       }
5810 
5811       if (!info->field_maps()->is_empty()) {
5812         DCHECK(field_access.representation().IsHeapObject());
5813         value = Add<HCheckMaps>(value, info->field_maps());
5814       }
5815 
5816       // This is a normal store.
5817       instr = New<HStoreNamedField>(checked_object->ActualValue(), field_access,
5818                                     value, info->StoreMode());
5819     }
5820   }
5821 
5822   if (transition_to_field) {
5823     Handle<Map> transition(info->transition());
5824     DCHECK(!transition->is_deprecated());
5825     instr->SetTransition(Add<HConstant>(transition));
5826   }
5827   return instr;
5828 }
5829 
5830 Handle<FieldType>
GetFieldTypeFromMap(Handle<Map> map) const5831 HOptimizedGraphBuilder::PropertyAccessInfo::GetFieldTypeFromMap(
5832     Handle<Map> map) const {
5833   DCHECK(IsFound());
5834   DCHECK(number_ < map->NumberOfOwnDescriptors());
5835   return handle(map->instance_descriptors()->GetFieldType(number_), isolate());
5836 }
5837 
IsCompatible(PropertyAccessInfo * info)5838 bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatible(
5839     PropertyAccessInfo* info) {
5840   if (!CanInlinePropertyAccess(map_)) return false;
5841 
5842   // Currently only handle AstType::Number as a polymorphic case.
5843   // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber
5844   // instruction.
5845   if (IsNumberType()) return false;
5846 
5847   // Values are only compatible for monomorphic load if they all behave the same
5848   // regarding value wrappers.
5849   if (IsValueWrapped() != info->IsValueWrapped()) return false;
5850 
5851   if (!LookupDescriptor()) return false;
5852 
5853   if (!IsFound()) {
5854     return (!info->IsFound() || info->has_holder()) &&
5855            map()->prototype() == info->map()->prototype();
5856   }
5857 
5858   // Mismatch if the other access info found the property in the prototype
5859   // chain.
5860   if (info->has_holder()) return false;
5861 
5862   if (IsAccessorConstant()) {
5863     return accessor_.is_identical_to(info->accessor_) &&
5864         api_holder_.is_identical_to(info->api_holder_);
5865   }
5866 
5867   if (IsDataConstant()) {
5868     return constant_.is_identical_to(info->constant_);
5869   }
5870 
5871   DCHECK(IsData());
5872   if (!info->IsData()) return false;
5873 
5874   Representation r = access_.representation();
5875   if (IsLoad()) {
5876     if (!info->access_.representation().IsCompatibleForLoad(r)) return false;
5877   } else {
5878     if (!info->access_.representation().IsCompatibleForStore(r)) return false;
5879   }
5880   if (info->access_.offset() != access_.offset()) return false;
5881   if (info->access_.IsInobject() != access_.IsInobject()) return false;
5882   if (IsLoad()) {
5883     if (field_maps_.is_empty()) {
5884       info->field_maps_.Clear();
5885     } else if (!info->field_maps_.is_empty()) {
5886       for (int i = 0; i < field_maps_.length(); ++i) {
5887         info->field_maps_.AddMapIfMissing(field_maps_.at(i), info->zone());
5888       }
5889       info->field_maps_.Sort();
5890     }
5891   } else {
5892     // We can only merge stores that agree on their field maps. The comparison
5893     // below is safe, since we keep the field maps sorted.
5894     if (field_maps_.length() != info->field_maps_.length()) return false;
5895     for (int i = 0; i < field_maps_.length(); ++i) {
5896       if (!field_maps_.at(i).is_identical_to(info->field_maps_.at(i))) {
5897         return false;
5898       }
5899     }
5900   }
5901   info->GeneralizeRepresentation(r);
5902   info->field_type_ = info->field_type_.Combine(field_type_);
5903   return true;
5904 }
5905 
5906 
LookupDescriptor()5907 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() {
5908   if (!map_->IsJSObjectMap()) return true;
5909   LookupDescriptor(*map_, *name_);
5910   return LoadResult(map_);
5911 }
5912 
5913 
LoadResult(Handle<Map> map)5914 bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) {
5915   if (!IsLoad() && IsProperty() && IsReadOnly()) {
5916     return false;
5917   }
5918 
5919   if (IsData()) {
5920     // Construct the object field access.
5921     int index = GetLocalFieldIndexFromMap(map);
5922     access_ = HObjectAccess::ForField(map, index, representation(), name_);
5923 
5924     // Load field map for heap objects.
5925     return LoadFieldMaps(map);
5926   } else if (IsAccessorConstant()) {
5927     Handle<Object> accessors = GetAccessorsFromMap(map);
5928     if (!accessors->IsAccessorPair()) return false;
5929     Object* raw_accessor =
5930         IsLoad() ? Handle<AccessorPair>::cast(accessors)->getter()
5931                  : Handle<AccessorPair>::cast(accessors)->setter();
5932     if (!raw_accessor->IsJSFunction() &&
5933         !raw_accessor->IsFunctionTemplateInfo())
5934       return false;
5935     Handle<Object> accessor = handle(HeapObject::cast(raw_accessor));
5936     CallOptimization call_optimization(accessor);
5937     if (call_optimization.is_simple_api_call()) {
5938       CallOptimization::HolderLookup holder_lookup;
5939       api_holder_ =
5940           call_optimization.LookupHolderOfExpectedType(map_, &holder_lookup);
5941     }
5942     accessor_ = accessor;
5943   } else if (IsDataConstant()) {
5944     constant_ = GetConstantFromMap(map);
5945   }
5946 
5947   return true;
5948 }
5949 
5950 
LoadFieldMaps(Handle<Map> map)5951 bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadFieldMaps(
5952     Handle<Map> map) {
5953   // Clear any previously collected field maps/type.
5954   field_maps_.Clear();
5955   field_type_ = HType::Tagged();
5956 
5957   // Figure out the field type from the accessor map.
5958   Handle<FieldType> field_type = GetFieldTypeFromMap(map);
5959 
5960   // Collect the (stable) maps from the field type.
5961   if (field_type->IsClass()) {
5962     DCHECK(access_.representation().IsHeapObject());
5963     Handle<Map> field_map = field_type->AsClass();
5964     if (field_map->is_stable()) {
5965       field_maps_.Add(field_map, zone());
5966     }
5967   }
5968 
5969   if (field_maps_.is_empty()) {
5970     // Store is not safe if the field map was cleared.
5971     return IsLoad() || !field_type->IsNone();
5972   }
5973 
5974   // Determine field HType from field type.
5975   field_type_ = HType::FromFieldType(field_type, zone());
5976   DCHECK(field_type_.IsHeapObject());
5977 
5978   // Add dependency on the map that introduced the field.
5979   top_info()->dependencies()->AssumeFieldOwner(GetFieldOwnerFromMap(map));
5980   return true;
5981 }
5982 
5983 
LookupInPrototypes()5984 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
5985   Handle<Map> map = this->map();
5986   if (name_->IsPrivate()) {
5987     NotFound();
5988     return !map->has_hidden_prototype();
5989   }
5990 
5991   while (map->prototype()->IsJSObject()) {
5992     holder_ = handle(JSObject::cast(map->prototype()));
5993     if (holder_->map()->is_deprecated()) {
5994       JSObject::TryMigrateInstance(holder_);
5995     }
5996     map = Handle<Map>(holder_->map());
5997     if (!CanInlinePropertyAccess(map)) {
5998       NotFound();
5999       return false;
6000     }
6001     LookupDescriptor(*map, *name_);
6002     if (IsFound()) return LoadResult(map);
6003   }
6004 
6005   NotFound();
6006   return !map->prototype()->IsJSReceiver();
6007 }
6008 
6009 
IsIntegerIndexedExotic()6010 bool HOptimizedGraphBuilder::PropertyAccessInfo::IsIntegerIndexedExotic() {
6011   InstanceType instance_type = map_->instance_type();
6012   return instance_type == JS_TYPED_ARRAY_TYPE && name_->IsString() &&
6013          IsSpecialIndex(isolate()->unicode_cache(), String::cast(*name_));
6014 }
6015 
6016 
CanAccessMonomorphic()6017 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() {
6018   if (!CanInlinePropertyAccess(map_)) return false;
6019   if (IsJSObjectFieldAccessor()) return IsLoad();
6020   if (map_->IsJSFunctionMap() && map_->is_constructor() &&
6021       !map_->has_non_instance_prototype() &&
6022       name_.is_identical_to(isolate()->factory()->prototype_string())) {
6023     return IsLoad();
6024   }
6025   if (!LookupDescriptor()) return false;
6026   if (IsFound()) return IsLoad() || !IsReadOnly();
6027   if (IsIntegerIndexedExotic()) return false;
6028   if (!LookupInPrototypes()) return false;
6029   if (IsLoad()) return true;
6030 
6031   if (IsAccessorConstant()) return true;
6032   LookupTransition(*map_, *name_, NONE);
6033   if (IsTransitionToData() && map_->unused_property_fields() > 0) {
6034     // Construct the object field access.
6035     int descriptor = transition()->LastAdded();
6036     int index =
6037         transition()->instance_descriptors()->GetFieldIndex(descriptor) -
6038         map_->GetInObjectProperties();
6039     PropertyDetails details =
6040         transition()->instance_descriptors()->GetDetails(descriptor);
6041     Representation representation = details.representation();
6042     access_ = HObjectAccess::ForField(map_, index, representation, name_);
6043 
6044     // Load field map for heap objects.
6045     return LoadFieldMaps(transition());
6046   }
6047   return false;
6048 }
6049 
6050 
CanAccessAsMonomorphic(SmallMapList * maps)6051 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessAsMonomorphic(
6052     SmallMapList* maps) {
6053   DCHECK(map_.is_identical_to(maps->first()));
6054   if (!CanAccessMonomorphic()) return false;
6055   STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism);
6056   if (maps->length() > kMaxLoadPolymorphism) return false;
6057   HObjectAccess access = HObjectAccess::ForMap();  // bogus default
6058   if (GetJSObjectFieldAccess(&access)) {
6059     for (int i = 1; i < maps->length(); ++i) {
6060       PropertyAccessInfo test_info(builder_, access_type_, maps->at(i), name_);
6061       HObjectAccess test_access = HObjectAccess::ForMap();  // bogus default
6062       if (!test_info.GetJSObjectFieldAccess(&test_access)) return false;
6063       if (!access.Equals(test_access)) return false;
6064     }
6065     return true;
6066   }
6067 
6068   // Currently only handle numbers as a polymorphic case.
6069   // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber
6070   // instruction.
6071   if (IsNumberType()) return false;
6072 
6073   // Multiple maps cannot transition to the same target map.
6074   DCHECK(!IsLoad() || !IsTransition());
6075   if (IsTransition() && maps->length() > 1) return false;
6076 
6077   for (int i = 1; i < maps->length(); ++i) {
6078     PropertyAccessInfo test_info(builder_, access_type_, maps->at(i), name_);
6079     if (!test_info.IsCompatible(this)) return false;
6080   }
6081 
6082   return true;
6083 }
6084 
6085 
map()6086 Handle<Map> HOptimizedGraphBuilder::PropertyAccessInfo::map() {
6087   Handle<JSFunction> ctor;
6088   if (Map::GetConstructorFunction(
6089           map_, handle(current_info()->closure()->context()->native_context()))
6090           .ToHandle(&ctor)) {
6091     return handle(ctor->initial_map());
6092   }
6093   return map_;
6094 }
6095 
6096 
NeedsWrapping(Handle<Map> map,Handle<JSFunction> target)6097 static bool NeedsWrapping(Handle<Map> map, Handle<JSFunction> target) {
6098   return !map->IsJSObjectMap() &&
6099          is_sloppy(target->shared()->language_mode()) &&
6100          !target->shared()->native();
6101 }
6102 
6103 
NeedsWrappingFor(Handle<JSFunction> target) const6104 bool HOptimizedGraphBuilder::PropertyAccessInfo::NeedsWrappingFor(
6105     Handle<JSFunction> target) const {
6106   return NeedsWrapping(map_, target);
6107 }
6108 
6109 
BuildMonomorphicAccess(PropertyAccessInfo * info,HValue * object,HValue * checked_object,HValue * value,BailoutId ast_id,BailoutId return_id,bool can_inline_accessor)6110 HValue* HOptimizedGraphBuilder::BuildMonomorphicAccess(
6111     PropertyAccessInfo* info, HValue* object, HValue* checked_object,
6112     HValue* value, BailoutId ast_id, BailoutId return_id,
6113     bool can_inline_accessor) {
6114   HObjectAccess access = HObjectAccess::ForMap();  // bogus default
6115   if (info->GetJSObjectFieldAccess(&access)) {
6116     DCHECK(info->IsLoad());
6117     return New<HLoadNamedField>(object, checked_object, access);
6118   }
6119 
6120   if (info->name().is_identical_to(isolate()->factory()->prototype_string()) &&
6121       info->map()->IsJSFunctionMap() && info->map()->is_constructor()) {
6122     DCHECK(!info->map()->has_non_instance_prototype());
6123     return New<HLoadFunctionPrototype>(checked_object);
6124   }
6125 
6126   HValue* checked_holder = checked_object;
6127   if (info->has_holder()) {
6128     Handle<JSObject> prototype(JSObject::cast(info->map()->prototype()));
6129     checked_holder = BuildCheckPrototypeMaps(prototype, info->holder());
6130   }
6131 
6132   if (!info->IsFound()) {
6133     DCHECK(info->IsLoad());
6134     return graph()->GetConstantUndefined();
6135   }
6136 
6137   if (info->IsData()) {
6138     if (info->IsLoad()) {
6139       return BuildLoadNamedField(info, checked_holder);
6140     } else {
6141       return BuildStoreNamedField(info, checked_object, value);
6142     }
6143   }
6144 
6145   if (info->IsTransition()) {
6146     DCHECK(!info->IsLoad());
6147     return BuildStoreNamedField(info, checked_object, value);
6148   }
6149 
6150   if (info->IsAccessorConstant()) {
6151     MaybeHandle<Name> maybe_name =
6152         FunctionTemplateInfo::TryGetCachedPropertyName(isolate(),
6153                                                        info->accessor());
6154     if (!maybe_name.is_null()) {
6155       Handle<Name> name = maybe_name.ToHandleChecked();
6156       PropertyAccessInfo cache_info(this, LOAD, info->map(), name);
6157       // Load new target.
6158       if (cache_info.CanAccessMonomorphic()) {
6159         return BuildLoadNamedField(&cache_info, checked_object);
6160       }
6161     }
6162 
6163     Push(checked_object);
6164     int argument_count = 1;
6165     if (!info->IsLoad()) {
6166       argument_count = 2;
6167       Push(value);
6168     }
6169 
6170     if (info->accessor()->IsJSFunction() &&
6171         info->NeedsWrappingFor(Handle<JSFunction>::cast(info->accessor()))) {
6172       HValue* function = Add<HConstant>(info->accessor());
6173       PushArgumentsFromEnvironment(argument_count);
6174       return NewCallFunction(function, argument_count, TailCallMode::kDisallow,
6175                              ConvertReceiverMode::kNotNullOrUndefined,
6176                              TailCallMode::kDisallow);
6177     } else if (FLAG_inline_accessors && can_inline_accessor) {
6178       bool success = info->IsLoad()
6179           ? TryInlineGetter(info->accessor(), info->map(), ast_id, return_id)
6180           : TryInlineSetter(
6181               info->accessor(), info->map(), ast_id, return_id, value);
6182       if (success || HasStackOverflow()) return NULL;
6183     }
6184 
6185     PushArgumentsFromEnvironment(argument_count);
6186     if (!info->accessor()->IsJSFunction()) {
6187       Bailout(kInliningBailedOut);
6188       return nullptr;
6189     }
6190     return NewCallConstantFunction(Handle<JSFunction>::cast(info->accessor()),
6191                                    argument_count, TailCallMode::kDisallow,
6192                                    TailCallMode::kDisallow);
6193   }
6194 
6195   DCHECK(info->IsDataConstant());
6196   if (info->IsLoad()) {
6197     return New<HConstant>(info->constant());
6198   } else {
6199     return New<HCheckValue>(value, Handle<JSFunction>::cast(info->constant()));
6200   }
6201 }
6202 
HandlePolymorphicNamedFieldAccess(PropertyAccessType access_type,Expression * expr,FeedbackSlot slot,BailoutId ast_id,BailoutId return_id,HValue * object,HValue * value,SmallMapList * maps,Handle<Name> name)6203 void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess(
6204     PropertyAccessType access_type, Expression* expr, FeedbackSlot slot,
6205     BailoutId ast_id, BailoutId return_id, HValue* object, HValue* value,
6206     SmallMapList* maps, Handle<Name> name) {
6207   // Something did not match; must use a polymorphic load.
6208   int count = 0;
6209   HBasicBlock* join = NULL;
6210   HBasicBlock* number_block = NULL;
6211   bool handled_string = false;
6212 
6213   bool handle_smi = false;
6214   STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism);
6215   int i;
6216   for (i = 0; i < maps->length() && count < kMaxLoadPolymorphism; ++i) {
6217     PropertyAccessInfo info(this, access_type, maps->at(i), name);
6218     if (info.IsStringType()) {
6219       if (handled_string) continue;
6220       handled_string = true;
6221     }
6222     if (info.CanAccessMonomorphic()) {
6223       count++;
6224       if (info.IsNumberType()) {
6225         handle_smi = true;
6226         break;
6227       }
6228     }
6229   }
6230 
6231   if (i < maps->length()) {
6232     count = -1;
6233     maps->Clear();
6234   } else {
6235     count = 0;
6236   }
6237   HControlInstruction* smi_check = NULL;
6238   handled_string = false;
6239 
6240   for (i = 0; i < maps->length() && count < kMaxLoadPolymorphism; ++i) {
6241     PropertyAccessInfo info(this, access_type, maps->at(i), name);
6242     if (info.IsStringType()) {
6243       if (handled_string) continue;
6244       handled_string = true;
6245     }
6246     if (!info.CanAccessMonomorphic()) continue;
6247 
6248     if (count == 0) {
6249       join = graph()->CreateBasicBlock();
6250       if (handle_smi) {
6251         HBasicBlock* empty_smi_block = graph()->CreateBasicBlock();
6252         HBasicBlock* not_smi_block = graph()->CreateBasicBlock();
6253         number_block = graph()->CreateBasicBlock();
6254         smi_check = New<HIsSmiAndBranch>(
6255             object, empty_smi_block, not_smi_block);
6256         FinishCurrentBlock(smi_check);
6257         GotoNoSimulate(empty_smi_block, number_block);
6258         set_current_block(not_smi_block);
6259       } else {
6260         BuildCheckHeapObject(object);
6261       }
6262     }
6263     ++count;
6264     HBasicBlock* if_true = graph()->CreateBasicBlock();
6265     HBasicBlock* if_false = graph()->CreateBasicBlock();
6266     HUnaryControlInstruction* compare;
6267 
6268     HValue* dependency;
6269     if (info.IsNumberType()) {
6270       Handle<Map> heap_number_map = isolate()->factory()->heap_number_map();
6271       compare = New<HCompareMap>(object, heap_number_map, if_true, if_false);
6272       dependency = smi_check;
6273     } else if (info.IsStringType()) {
6274       compare = New<HIsStringAndBranch>(object, if_true, if_false);
6275       dependency = compare;
6276     } else {
6277       compare = New<HCompareMap>(object, info.map(), if_true, if_false);
6278       dependency = compare;
6279     }
6280     FinishCurrentBlock(compare);
6281 
6282     if (info.IsNumberType()) {
6283       GotoNoSimulate(if_true, number_block);
6284       if_true = number_block;
6285     }
6286 
6287     set_current_block(if_true);
6288 
6289     HValue* access =
6290         BuildMonomorphicAccess(&info, object, dependency, value, ast_id,
6291                                return_id, FLAG_polymorphic_inlining);
6292 
6293     HValue* result = NULL;
6294     switch (access_type) {
6295       case LOAD:
6296         result = access;
6297         break;
6298       case STORE:
6299         result = value;
6300         break;
6301     }
6302 
6303     if (access == NULL) {
6304       if (HasStackOverflow()) return;
6305     } else {
6306       if (access->IsInstruction()) {
6307         HInstruction* instr = HInstruction::cast(access);
6308         if (!instr->IsLinked()) AddInstruction(instr);
6309       }
6310       if (!ast_context()->IsEffect()) Push(result);
6311     }
6312 
6313     if (current_block() != NULL) Goto(join);
6314     set_current_block(if_false);
6315   }
6316 
6317   // Finish up.  Unconditionally deoptimize if we've handled all the maps we
6318   // know about and do not want to handle ones we've never seen.  Otherwise
6319   // use a generic IC.
6320   if (count == maps->length() && FLAG_deoptimize_uncommon_cases) {
6321     FinishExitWithHardDeoptimization(
6322         DeoptimizeReason::kUnknownMapInPolymorphicAccess);
6323   } else {
6324     HInstruction* instr =
6325         BuildNamedGeneric(access_type, expr, slot, object, name, value);
6326     AddInstruction(instr);
6327     if (!ast_context()->IsEffect()) Push(access_type == LOAD ? instr : value);
6328 
6329     if (join != NULL) {
6330       Goto(join);
6331     } else {
6332       Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6333       if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
6334       return;
6335     }
6336   }
6337 
6338   DCHECK(join != NULL);
6339   if (join->HasPredecessor()) {
6340     join->SetJoinId(ast_id);
6341     set_current_block(join);
6342     if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
6343   } else {
6344     set_current_block(NULL);
6345   }
6346 }
6347 
ComputeReceiverTypes(Expression * expr,HValue * receiver,SmallMapList ** t,HOptimizedGraphBuilder * builder)6348 static bool ComputeReceiverTypes(Expression* expr, HValue* receiver,
6349                                  SmallMapList** t,
6350                                  HOptimizedGraphBuilder* builder) {
6351   Zone* zone = builder->zone();
6352   SmallMapList* maps = expr->GetReceiverTypes();
6353   *t = maps;
6354   bool monomorphic = expr->IsMonomorphic();
6355   if (maps != nullptr && receiver->HasMonomorphicJSObjectType()) {
6356     if (maps->length() > 0) {
6357       Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap();
6358       maps->FilterForPossibleTransitions(root_map);
6359       monomorphic = maps->length() == 1;
6360     } else {
6361       // No type feedback, see if we can infer the type. This is safely
6362       // possible if the receiver had a known map at some point, and no
6363       // map-changing stores have happened to it since.
6364       Handle<Map> candidate_map = receiver->GetMonomorphicJSObjectMap();
6365       for (HInstruction* current = builder->current_block()->last();
6366            current != nullptr; current = current->previous()) {
6367         if (current->IsBlockEntry()) break;
6368         if (current->CheckChangesFlag(kMaps)) {
6369           // Only allow map changes that store the candidate map. We don't
6370           // need to care which object the map is being written into.
6371           if (!current->IsStoreNamedField()) break;
6372           HStoreNamedField* map_change = HStoreNamedField::cast(current);
6373           if (!map_change->value()->IsConstant()) break;
6374           HConstant* map_constant = HConstant::cast(map_change->value());
6375           if (!map_constant->representation().IsTagged()) break;
6376           Handle<Object> map = map_constant->handle(builder->isolate());
6377           if (!map.is_identical_to(candidate_map)) break;
6378         }
6379         if (current == receiver) {
6380           // We made it all the way back to the receiver without encountering
6381           // a map change! So we can assume that the receiver still has the
6382           // candidate_map we know about.
6383           maps->Add(candidate_map, zone);
6384           monomorphic = true;
6385           break;
6386         }
6387       }
6388     }
6389   }
6390   return monomorphic && CanInlinePropertyAccess(maps->first());
6391 }
6392 
6393 
AreStringTypes(SmallMapList * maps)6394 static bool AreStringTypes(SmallMapList* maps) {
6395   for (int i = 0; i < maps->length(); i++) {
6396     if (maps->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false;
6397   }
6398   return true;
6399 }
6400 
BuildStore(Expression * expr,Property * prop,FeedbackSlot slot,BailoutId ast_id,BailoutId return_id,bool is_uninitialized)6401 void HOptimizedGraphBuilder::BuildStore(Expression* expr, Property* prop,
6402                                         FeedbackSlot slot, BailoutId ast_id,
6403                                         BailoutId return_id,
6404                                         bool is_uninitialized) {
6405   if (!prop->key()->IsPropertyName()) {
6406     // Keyed store.
6407     HValue* value = Pop();
6408     HValue* key = Pop();
6409     HValue* object = Pop();
6410     bool has_side_effects = false;
6411     HValue* result =
6412         HandleKeyedElementAccess(object, key, value, expr, slot, ast_id,
6413                                  return_id, STORE, &has_side_effects);
6414     if (has_side_effects) {
6415       if (!ast_context()->IsEffect()) Push(value);
6416       Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6417       if (!ast_context()->IsEffect()) Drop(1);
6418     }
6419     if (result == NULL) return;
6420     return ast_context()->ReturnValue(value);
6421   }
6422 
6423   // Named store.
6424   HValue* value = Pop();
6425   HValue* object = Pop();
6426 
6427   Literal* key = prop->key()->AsLiteral();
6428   Handle<String> name = Handle<String>::cast(key->value());
6429   DCHECK(!name.is_null());
6430 
6431   HValue* access = BuildNamedAccess(STORE, ast_id, return_id, expr, slot,
6432                                     object, name, value, is_uninitialized);
6433   if (access == NULL) return;
6434 
6435   if (!ast_context()->IsEffect()) Push(value);
6436   if (access->IsInstruction()) AddInstruction(HInstruction::cast(access));
6437   if (access->HasObservableSideEffects()) {
6438     Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6439   }
6440   if (!ast_context()->IsEffect()) Drop(1);
6441   return ast_context()->ReturnValue(value);
6442 }
6443 
6444 
HandlePropertyAssignment(Assignment * expr)6445 void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
6446   Property* prop = expr->target()->AsProperty();
6447   DCHECK(prop != NULL);
6448   CHECK_ALIVE(VisitForValue(prop->obj()));
6449   if (!prop->key()->IsPropertyName()) {
6450     CHECK_ALIVE(VisitForValue(prop->key()));
6451   }
6452   CHECK_ALIVE(VisitForValue(expr->value()));
6453   BuildStore(expr, prop, expr->AssignmentSlot(), expr->id(),
6454              expr->AssignmentId(), expr->IsUninitialized());
6455 }
6456 
InlineGlobalPropertyStore(LookupIterator * it,HValue * value,BailoutId ast_id)6457 HInstruction* HOptimizedGraphBuilder::InlineGlobalPropertyStore(
6458     LookupIterator* it, HValue* value, BailoutId ast_id) {
6459   Handle<PropertyCell> cell = it->GetPropertyCell();
6460   top_info()->dependencies()->AssumePropertyCell(cell);
6461   auto cell_type = it->property_details().cell_type();
6462   if (cell_type == PropertyCellType::kConstant ||
6463       cell_type == PropertyCellType::kUndefined) {
6464     Handle<Object> constant(cell->value(), isolate());
6465     if (value->IsConstant()) {
6466       HConstant* c_value = HConstant::cast(value);
6467       if (!constant.is_identical_to(c_value->handle(isolate()))) {
6468         Add<HDeoptimize>(DeoptimizeReason::kConstantGlobalVariableAssignment,
6469                          Deoptimizer::EAGER);
6470       }
6471     } else {
6472       HValue* c_constant = Add<HConstant>(constant);
6473       IfBuilder builder(this);
6474       if (constant->IsNumber()) {
6475         builder.If<HCompareNumericAndBranch>(value, c_constant, Token::EQ);
6476       } else {
6477         builder.If<HCompareObjectEqAndBranch>(value, c_constant);
6478       }
6479       builder.Then();
6480       builder.Else();
6481       Add<HDeoptimize>(DeoptimizeReason::kConstantGlobalVariableAssignment,
6482                        Deoptimizer::EAGER);
6483       builder.End();
6484     }
6485   }
6486   HConstant* cell_constant = Add<HConstant>(cell);
6487   auto access = HObjectAccess::ForPropertyCellValue();
6488   if (cell_type == PropertyCellType::kConstantType) {
6489     switch (cell->GetConstantType()) {
6490       case PropertyCellConstantType::kSmi:
6491         access = access.WithRepresentation(Representation::Smi());
6492         break;
6493       case PropertyCellConstantType::kStableMap: {
6494         // First check that the previous value of the {cell} still has the
6495         // map that we are about to check the new {value} for. If not, then
6496         // the stable map assumption was invalidated and we cannot continue
6497         // with the optimized code.
6498         Handle<HeapObject> cell_value(HeapObject::cast(cell->value()));
6499         Handle<Map> cell_value_map(cell_value->map());
6500         if (!cell_value_map->is_stable()) {
6501           Bailout(kUnstableConstantTypeHeapObject);
6502           return nullptr;
6503         }
6504         top_info()->dependencies()->AssumeMapStable(cell_value_map);
6505         // Now check that the new {value} is a HeapObject with the same map
6506         Add<HCheckHeapObject>(value);
6507         value = Add<HCheckMaps>(value, cell_value_map);
6508         access = access.WithRepresentation(Representation::HeapObject());
6509         break;
6510       }
6511     }
6512   }
6513   HInstruction* instr = New<HStoreNamedField>(cell_constant, access, value);
6514   instr->ClearChangesFlag(kInobjectFields);
6515   instr->SetChangesFlag(kGlobalVars);
6516   return instr;
6517 }
6518 
6519 // Because not every expression has a position and there is not common
6520 // superclass of Assignment and CountOperation, we cannot just pass the
6521 // owning expression instead of position and ast_id separately.
HandleGlobalVariableAssignment(Variable * var,HValue * value,FeedbackSlot slot,BailoutId ast_id)6522 void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(Variable* var,
6523                                                             HValue* value,
6524                                                             FeedbackSlot slot,
6525                                                             BailoutId ast_id) {
6526   Handle<JSGlobalObject> global(current_info()->global_object());
6527 
6528   // Lookup in script contexts.
6529   {
6530     Handle<ScriptContextTable> script_contexts(
6531         global->native_context()->script_context_table());
6532     ScriptContextTable::LookupResult lookup;
6533     if (ScriptContextTable::Lookup(script_contexts, var->name(), &lookup)) {
6534       if (lookup.mode == CONST) {
6535         return Bailout(kNonInitializerAssignmentToConst);
6536       }
6537       Handle<Context> script_context =
6538           ScriptContextTable::GetContext(script_contexts, lookup.context_index);
6539 
6540       Handle<Object> current_value =
6541           FixedArray::get(*script_context, lookup.slot_index, isolate());
6542 
6543       // If the values is not the hole, it will stay initialized,
6544       // so no need to generate a check.
6545       if (current_value->IsTheHole(isolate())) {
6546         return Bailout(kReferenceToUninitializedVariable);
6547       }
6548 
6549       HStoreNamedField* instr = Add<HStoreNamedField>(
6550           Add<HConstant>(script_context),
6551           HObjectAccess::ForContextSlot(lookup.slot_index), value);
6552       USE(instr);
6553       DCHECK(instr->HasObservableSideEffects());
6554       Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6555       return;
6556     }
6557   }
6558 
6559   LookupIterator it(global, var->name(), LookupIterator::OWN);
6560   if (CanInlineGlobalPropertyAccess(var, &it, STORE)) {
6561     HInstruction* instr = InlineGlobalPropertyStore(&it, value, ast_id);
6562     if (!instr) return;
6563     AddInstruction(instr);
6564     if (instr->HasObservableSideEffects()) {
6565       Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6566     }
6567   } else {
6568     HValue* global_object = Add<HLoadNamedField>(
6569         BuildGetNativeContext(), nullptr,
6570         HObjectAccess::ForContextSlot(Context::EXTENSION_INDEX));
6571     Handle<FeedbackVector> vector =
6572         handle(current_feedback_vector(), isolate());
6573     HValue* name = Add<HConstant>(var->name());
6574     HValue* vector_value = Add<HConstant>(vector);
6575     HValue* slot_value = Add<HConstant>(vector->GetIndex(slot));
6576     DCHECK_EQ(vector->GetLanguageMode(slot), function_language_mode());
6577     Callable callable = CodeFactory::StoreICInOptimizedCode(
6578         isolate(), function_language_mode());
6579     HValue* stub = Add<HConstant>(callable.code());
6580     HValue* values[] = {global_object, name, value, slot_value, vector_value};
6581     HCallWithDescriptor* instr = Add<HCallWithDescriptor>(
6582         Code::STORE_IC, stub, 0, callable.descriptor(), ArrayVector(values));
6583     USE(instr);
6584     DCHECK(instr->HasObservableSideEffects());
6585     Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6586   }
6587 }
6588 
6589 
HandleCompoundAssignment(Assignment * expr)6590 void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
6591   Expression* target = expr->target();
6592   VariableProxy* proxy = target->AsVariableProxy();
6593   Property* prop = target->AsProperty();
6594   DCHECK(proxy == NULL || prop == NULL);
6595 
6596   // We have a second position recorded in the FullCodeGenerator to have
6597   // type feedback for the binary operation.
6598   BinaryOperation* operation = expr->binary_operation();
6599 
6600   if (proxy != NULL) {
6601     Variable* var = proxy->var();
6602     if (var->mode() == LET)  {
6603       return Bailout(kUnsupportedLetCompoundAssignment);
6604     }
6605 
6606     CHECK_ALIVE(VisitForValue(operation));
6607 
6608     switch (var->location()) {
6609       case VariableLocation::UNALLOCATED:
6610         HandleGlobalVariableAssignment(var, Top(), expr->AssignmentSlot(),
6611                                        expr->AssignmentId());
6612         break;
6613 
6614       case VariableLocation::PARAMETER:
6615       case VariableLocation::LOCAL:
6616         if (var->mode() == CONST) {
6617           return Bailout(kNonInitializerAssignmentToConst);
6618         }
6619         BindIfLive(var, Top());
6620         break;
6621 
6622       case VariableLocation::CONTEXT: {
6623         // Bail out if we try to mutate a parameter value in a function
6624         // using the arguments object.  We do not (yet) correctly handle the
6625         // arguments property of the function.
6626         if (current_info()->scope()->arguments() != NULL) {
6627           // Parameters will be allocated to context slots.  We have no
6628           // direct way to detect that the variable is a parameter so we do
6629           // a linear search of the parameter variables.
6630           int count = current_info()->scope()->num_parameters();
6631           for (int i = 0; i < count; ++i) {
6632             if (var == current_info()->scope()->parameter(i)) {
6633               Bailout(kAssignmentToParameterFunctionUsesArgumentsObject);
6634             }
6635           }
6636         }
6637 
6638         HStoreContextSlot::Mode mode;
6639 
6640         switch (var->mode()) {
6641           case LET:
6642             mode = HStoreContextSlot::kCheckDeoptimize;
6643             break;
6644           case CONST:
6645             if (var->throw_on_const_assignment(function_language_mode())) {
6646               return Bailout(kNonInitializerAssignmentToConst);
6647             } else {
6648               return ast_context()->ReturnValue(Pop());
6649             }
6650           default:
6651             mode = HStoreContextSlot::kNoCheck;
6652         }
6653 
6654         HValue* context = BuildContextChainWalk(var);
6655         HStoreContextSlot* instr = Add<HStoreContextSlot>(
6656             context, var->index(), mode, Top());
6657         if (instr->HasObservableSideEffects()) {
6658           Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
6659         }
6660         break;
6661       }
6662 
6663       case VariableLocation::LOOKUP:
6664         return Bailout(kCompoundAssignmentToLookupSlot);
6665 
6666       case VariableLocation::MODULE:
6667         UNREACHABLE();
6668     }
6669     return ast_context()->ReturnValue(Pop());
6670 
6671   } else if (prop != NULL) {
6672     CHECK_ALIVE(VisitForValue(prop->obj()));
6673     HValue* object = Top();
6674     HValue* key = NULL;
6675     if (!prop->key()->IsPropertyName() || prop->IsStringAccess()) {
6676       CHECK_ALIVE(VisitForValue(prop->key()));
6677       key = Top();
6678     }
6679 
6680     CHECK_ALIVE(PushLoad(prop, object, key));
6681 
6682     CHECK_ALIVE(VisitForValue(expr->value()));
6683     HValue* right = Pop();
6684     HValue* left = Pop();
6685 
6686     Push(BuildBinaryOperation(operation, left, right, PUSH_BEFORE_SIMULATE));
6687 
6688     BuildStore(expr, prop, expr->AssignmentSlot(), expr->id(),
6689                expr->AssignmentId(), expr->IsUninitialized());
6690   } else {
6691     return Bailout(kInvalidLhsInCompoundAssignment);
6692   }
6693 }
6694 
6695 
VisitAssignment(Assignment * expr)6696 void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) {
6697   DCHECK(!HasStackOverflow());
6698   DCHECK(current_block() != NULL);
6699   DCHECK(current_block()->HasPredecessor());
6700 
6701   VariableProxy* proxy = expr->target()->AsVariableProxy();
6702   Property* prop = expr->target()->AsProperty();
6703   DCHECK(proxy == NULL || prop == NULL);
6704 
6705   if (expr->is_compound()) {
6706     HandleCompoundAssignment(expr);
6707     return;
6708   }
6709 
6710   if (prop != NULL) {
6711     HandlePropertyAssignment(expr);
6712   } else if (proxy != NULL) {
6713     Variable* var = proxy->var();
6714 
6715     if (var->mode() == CONST) {
6716       if (expr->op() != Token::INIT) {
6717         if (var->throw_on_const_assignment(function_language_mode())) {
6718           return Bailout(kNonInitializerAssignmentToConst);
6719         } else {
6720           CHECK_ALIVE(VisitForValue(expr->value()));
6721           return ast_context()->ReturnValue(Pop());
6722         }
6723       }
6724     }
6725 
6726     // Handle the assignment.
6727     switch (var->location()) {
6728       case VariableLocation::UNALLOCATED:
6729         CHECK_ALIVE(VisitForValue(expr->value()));
6730         HandleGlobalVariableAssignment(var, Top(), expr->AssignmentSlot(),
6731                                        expr->AssignmentId());
6732         return ast_context()->ReturnValue(Pop());
6733 
6734       case VariableLocation::PARAMETER:
6735       case VariableLocation::LOCAL: {
6736         // Perform an initialization check for let declared variables
6737         // or parameters.
6738         if (var->mode() == LET && expr->op() == Token::ASSIGN) {
6739           HValue* env_value = environment()->Lookup(var);
6740           if (env_value == graph()->GetConstantHole()) {
6741             return Bailout(kAssignmentToLetVariableBeforeInitialization);
6742           }
6743         }
6744         // We do not allow the arguments object to occur in a context where it
6745         // may escape, but assignments to stack-allocated locals are
6746         // permitted.
6747         CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED));
6748         HValue* value = Pop();
6749         BindIfLive(var, value);
6750         return ast_context()->ReturnValue(value);
6751       }
6752 
6753       case VariableLocation::CONTEXT: {
6754         // Bail out if we try to mutate a parameter value in a function using
6755         // the arguments object.  We do not (yet) correctly handle the
6756         // arguments property of the function.
6757         if (current_info()->scope()->arguments() != NULL) {
6758           // Parameters will rewrite to context slots.  We have no direct way
6759           // to detect that the variable is a parameter.
6760           int count = current_info()->scope()->num_parameters();
6761           for (int i = 0; i < count; ++i) {
6762             if (var == current_info()->scope()->parameter(i)) {
6763               return Bailout(kAssignmentToParameterInArgumentsObject);
6764             }
6765           }
6766         }
6767 
6768         CHECK_ALIVE(VisitForValue(expr->value()));
6769         HStoreContextSlot::Mode mode;
6770         if (expr->op() == Token::ASSIGN) {
6771           switch (var->mode()) {
6772             case LET:
6773               mode = HStoreContextSlot::kCheckDeoptimize;
6774               break;
6775             case CONST:
6776               // If we reached this point, the only possibility
6777               // is a sloppy assignment to a function name.
6778               DCHECK(function_language_mode() == SLOPPY &&
6779                      !var->throw_on_const_assignment(SLOPPY));
6780               return ast_context()->ReturnValue(Pop());
6781             default:
6782               mode = HStoreContextSlot::kNoCheck;
6783           }
6784         } else {
6785           DCHECK_EQ(Token::INIT, expr->op());
6786           mode = HStoreContextSlot::kNoCheck;
6787         }
6788 
6789         HValue* context = BuildContextChainWalk(var);
6790         HStoreContextSlot* instr = Add<HStoreContextSlot>(
6791             context, var->index(), mode, Top());
6792         if (instr->HasObservableSideEffects()) {
6793           Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
6794         }
6795         return ast_context()->ReturnValue(Pop());
6796       }
6797 
6798       case VariableLocation::LOOKUP:
6799         return Bailout(kAssignmentToLOOKUPVariable);
6800 
6801       case VariableLocation::MODULE:
6802         UNREACHABLE();
6803     }
6804   } else {
6805     return Bailout(kInvalidLeftHandSideInAssignment);
6806   }
6807 }
6808 
6809 
VisitYield(Yield * expr)6810 void HOptimizedGraphBuilder::VisitYield(Yield* expr) {
6811   // Generators are not optimized, so we should never get here.
6812   UNREACHABLE();
6813 }
6814 
6815 
VisitThrow(Throw * expr)6816 void HOptimizedGraphBuilder::VisitThrow(Throw* expr) {
6817   DCHECK(!HasStackOverflow());
6818   DCHECK(current_block() != NULL);
6819   DCHECK(current_block()->HasPredecessor());
6820   if (!ast_context()->IsEffect()) {
6821     // The parser turns invalid left-hand sides in assignments into throw
6822     // statements, which may not be in effect contexts. We might still try
6823     // to optimize such functions; bail out now if we do.
6824     return Bailout(kInvalidLeftHandSideInAssignment);
6825   }
6826   CHECK_ALIVE(VisitForValue(expr->exception()));
6827 
6828   HValue* value = environment()->Pop();
6829   if (!is_tracking_positions()) SetSourcePosition(expr->position());
6830   Add<HPushArguments>(value);
6831   Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kThrow), 1);
6832   Add<HSimulate>(expr->id());
6833 
6834   // If the throw definitely exits the function, we can finish with a dummy
6835   // control flow at this point.  This is not the case if the throw is inside
6836   // an inlined function which may be replaced.
6837   if (call_context() == NULL) {
6838     FinishExitCurrentBlock(New<HAbnormalExit>());
6839   }
6840 }
6841 
6842 
AddLoadStringInstanceType(HValue * string)6843 HInstruction* HGraphBuilder::AddLoadStringInstanceType(HValue* string) {
6844   if (string->IsConstant()) {
6845     HConstant* c_string = HConstant::cast(string);
6846     if (c_string->HasStringValue()) {
6847       return Add<HConstant>(c_string->StringValue()->map()->instance_type());
6848     }
6849   }
6850   return Add<HLoadNamedField>(
6851       Add<HLoadNamedField>(string, nullptr, HObjectAccess::ForMap()), nullptr,
6852       HObjectAccess::ForMapInstanceType());
6853 }
6854 
6855 
AddLoadStringLength(HValue * string)6856 HInstruction* HGraphBuilder::AddLoadStringLength(HValue* string) {
6857   return AddInstruction(BuildLoadStringLength(string));
6858 }
6859 
6860 
BuildLoadStringLength(HValue * string)6861 HInstruction* HGraphBuilder::BuildLoadStringLength(HValue* string) {
6862   if (string->IsConstant()) {
6863     HConstant* c_string = HConstant::cast(string);
6864     if (c_string->HasStringValue()) {
6865       return New<HConstant>(c_string->StringValue()->length());
6866     }
6867   }
6868   return New<HLoadNamedField>(string, nullptr,
6869                               HObjectAccess::ForStringLength());
6870 }
6871 
BuildNamedGeneric(PropertyAccessType access_type,Expression * expr,FeedbackSlot slot,HValue * object,Handle<Name> name,HValue * value,bool is_uninitialized)6872 HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric(
6873     PropertyAccessType access_type, Expression* expr, FeedbackSlot slot,
6874     HValue* object, Handle<Name> name, HValue* value, bool is_uninitialized) {
6875   if (is_uninitialized) {
6876     Add<HDeoptimize>(
6877         DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess,
6878         Deoptimizer::SOFT);
6879   }
6880   Handle<FeedbackVector> vector(current_feedback_vector(), isolate());
6881 
6882   HValue* key = Add<HConstant>(name);
6883   HValue* vector_value = Add<HConstant>(vector);
6884   HValue* slot_value = Add<HConstant>(vector->GetIndex(slot));
6885 
6886   if (access_type == LOAD) {
6887     HValue* values[] = {object, key, slot_value, vector_value};
6888     if (!expr->AsProperty()->key()->IsPropertyName()) {
6889       DCHECK(vector->IsKeyedLoadIC(slot));
6890       // It's possible that a keyed load of a constant string was converted
6891       // to a named load. Here, at the last minute, we need to make sure to
6892       // use a generic Keyed Load if we are using the type vector, because
6893       // it has to share information with full code.
6894       Callable callable = CodeFactory::KeyedLoadICInOptimizedCode(isolate());
6895       HValue* stub = Add<HConstant>(callable.code());
6896       HCallWithDescriptor* result =
6897           New<HCallWithDescriptor>(Code::KEYED_LOAD_IC, stub, 0,
6898                                    callable.descriptor(), ArrayVector(values));
6899       return result;
6900     }
6901     DCHECK(vector->IsLoadIC(slot));
6902     Callable callable = CodeFactory::LoadICInOptimizedCode(isolate());
6903     HValue* stub = Add<HConstant>(callable.code());
6904     HCallWithDescriptor* result = New<HCallWithDescriptor>(
6905         Code::LOAD_IC, stub, 0, callable.descriptor(), ArrayVector(values));
6906     return result;
6907 
6908   } else {
6909     HValue* values[] = {object, key, value, slot_value, vector_value};
6910     if (vector->IsKeyedStoreIC(slot)) {
6911       // It's possible that a keyed store of a constant string was converted
6912       // to a named store. Here, at the last minute, we need to make sure to
6913       // use a generic Keyed Store if we are using the type vector, because
6914       // it has to share information with full code.
6915       DCHECK_EQ(vector->GetLanguageMode(slot), function_language_mode());
6916       Callable callable = CodeFactory::KeyedStoreICInOptimizedCode(
6917           isolate(), function_language_mode());
6918       HValue* stub = Add<HConstant>(callable.code());
6919       HCallWithDescriptor* result =
6920           New<HCallWithDescriptor>(Code::KEYED_STORE_IC, stub, 0,
6921                                    callable.descriptor(), ArrayVector(values));
6922       return result;
6923     }
6924     HCallWithDescriptor* result;
6925     if (vector->IsStoreOwnIC(slot)) {
6926       Callable callable = CodeFactory::StoreOwnICInOptimizedCode(isolate());
6927       HValue* stub = Add<HConstant>(callable.code());
6928       result = New<HCallWithDescriptor>(
6929           Code::STORE_IC, stub, 0, callable.descriptor(), ArrayVector(values));
6930     } else {
6931       DCHECK(vector->IsStoreIC(slot));
6932       DCHECK_EQ(vector->GetLanguageMode(slot), function_language_mode());
6933       Callable callable = CodeFactory::StoreICInOptimizedCode(
6934           isolate(), function_language_mode());
6935       HValue* stub = Add<HConstant>(callable.code());
6936       result = New<HCallWithDescriptor>(
6937           Code::STORE_IC, stub, 0, callable.descriptor(), ArrayVector(values));
6938     }
6939     return result;
6940   }
6941 }
6942 
BuildKeyedGeneric(PropertyAccessType access_type,Expression * expr,FeedbackSlot slot,HValue * object,HValue * key,HValue * value)6943 HInstruction* HOptimizedGraphBuilder::BuildKeyedGeneric(
6944     PropertyAccessType access_type, Expression* expr, FeedbackSlot slot,
6945     HValue* object, HValue* key, HValue* value) {
6946   Handle<FeedbackVector> vector(current_feedback_vector(), isolate());
6947   HValue* vector_value = Add<HConstant>(vector);
6948   HValue* slot_value = Add<HConstant>(vector->GetIndex(slot));
6949 
6950   if (access_type == LOAD) {
6951     HValue* values[] = {object, key, slot_value, vector_value};
6952 
6953     Callable callable = CodeFactory::KeyedLoadICInOptimizedCode(isolate());
6954     HValue* stub = Add<HConstant>(callable.code());
6955     HCallWithDescriptor* result =
6956         New<HCallWithDescriptor>(Code::KEYED_LOAD_IC, stub, 0,
6957                                  callable.descriptor(), ArrayVector(values));
6958     return result;
6959   } else {
6960     HValue* values[] = {object, key, value, slot_value, vector_value};
6961 
6962     Callable callable = CodeFactory::KeyedStoreICInOptimizedCode(
6963         isolate(), function_language_mode());
6964     HValue* stub = Add<HConstant>(callable.code());
6965     HCallWithDescriptor* result =
6966         New<HCallWithDescriptor>(Code::KEYED_STORE_IC, stub, 0,
6967                                  callable.descriptor(), ArrayVector(values));
6968     return result;
6969   }
6970 }
6971 
6972 
BuildKeyedHoleMode(Handle<Map> map)6973 LoadKeyedHoleMode HOptimizedGraphBuilder::BuildKeyedHoleMode(Handle<Map> map) {
6974   // Loads from a "stock" fast holey double arrays can elide the hole check.
6975   // Loads from a "stock" fast holey array can convert the hole to undefined
6976   // with impunity.
6977   LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE;
6978   bool holey_double_elements =
6979       *map == isolate()->get_initial_js_array_map(FAST_HOLEY_DOUBLE_ELEMENTS);
6980   bool holey_elements =
6981       *map == isolate()->get_initial_js_array_map(FAST_HOLEY_ELEMENTS);
6982   if ((holey_double_elements || holey_elements) &&
6983       isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
6984     load_mode =
6985         holey_double_elements ? ALLOW_RETURN_HOLE : CONVERT_HOLE_TO_UNDEFINED;
6986 
6987     Handle<JSObject> prototype(JSObject::cast(map->prototype()), isolate());
6988     Handle<JSObject> object_prototype = isolate()->initial_object_prototype();
6989     BuildCheckPrototypeMaps(prototype, object_prototype);
6990     graph()->MarkDependsOnEmptyArrayProtoElements();
6991   }
6992   return load_mode;
6993 }
6994 
6995 
BuildMonomorphicElementAccess(HValue * object,HValue * key,HValue * val,HValue * dependency,Handle<Map> map,PropertyAccessType access_type,KeyedAccessStoreMode store_mode)6996 HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess(
6997     HValue* object,
6998     HValue* key,
6999     HValue* val,
7000     HValue* dependency,
7001     Handle<Map> map,
7002     PropertyAccessType access_type,
7003     KeyedAccessStoreMode store_mode) {
7004   HCheckMaps* checked_object = Add<HCheckMaps>(object, map, dependency);
7005 
7006   if (access_type == STORE && map->prototype()->IsJSObject()) {
7007     // monomorphic stores need a prototype chain check because shape
7008     // changes could allow callbacks on elements in the chain that
7009     // aren't compatible with monomorphic keyed stores.
7010     PrototypeIterator iter(map);
7011     JSObject* holder = NULL;
7012     while (!iter.IsAtEnd()) {
7013       // JSProxies can't occur here because we wouldn't have installed a
7014       // non-generic IC if there were any.
7015       holder = *PrototypeIterator::GetCurrent<JSObject>(iter);
7016       iter.Advance();
7017     }
7018     DCHECK(holder && holder->IsJSObject());
7019 
7020     BuildCheckPrototypeMaps(handle(JSObject::cast(map->prototype())),
7021                             Handle<JSObject>(holder));
7022   }
7023 
7024   LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map);
7025   return BuildUncheckedMonomorphicElementAccess(
7026       checked_object, key, val,
7027       map->instance_type() == JS_ARRAY_TYPE,
7028       map->elements_kind(), access_type,
7029       load_mode, store_mode);
7030 }
7031 
7032 
CanInlineElementAccess(Handle<Map> map)7033 static bool CanInlineElementAccess(Handle<Map> map) {
7034   return map->IsJSObjectMap() &&
7035          (map->has_fast_elements() || map->has_fixed_typed_array_elements()) &&
7036          !map->has_indexed_interceptor() && !map->is_access_check_needed();
7037 }
7038 
7039 
TryBuildConsolidatedElementLoad(HValue * object,HValue * key,HValue * val,SmallMapList * maps)7040 HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad(
7041     HValue* object,
7042     HValue* key,
7043     HValue* val,
7044     SmallMapList* maps) {
7045   // For polymorphic loads of similar elements kinds (i.e. all tagged or all
7046   // double), always use the "worst case" code without a transition.  This is
7047   // much faster than transitioning the elements to the worst case, trading a
7048   // HTransitionElements for a HCheckMaps, and avoiding mutation of the array.
7049   bool has_double_maps = false;
7050   bool has_smi_or_object_maps = false;
7051   bool has_js_array_access = false;
7052   bool has_non_js_array_access = false;
7053   bool has_seen_holey_elements = false;
7054   Handle<Map> most_general_consolidated_map;
7055   for (int i = 0; i < maps->length(); ++i) {
7056     Handle<Map> map = maps->at(i);
7057     if (!CanInlineElementAccess(map)) return NULL;
7058     // Don't allow mixing of JSArrays with JSObjects.
7059     if (map->instance_type() == JS_ARRAY_TYPE) {
7060       if (has_non_js_array_access) return NULL;
7061       has_js_array_access = true;
7062     } else if (has_js_array_access) {
7063       return NULL;
7064     } else {
7065       has_non_js_array_access = true;
7066     }
7067     // Don't allow mixed, incompatible elements kinds.
7068     if (map->has_fast_double_elements()) {
7069       if (has_smi_or_object_maps) return NULL;
7070       has_double_maps = true;
7071     } else if (map->has_fast_smi_or_object_elements()) {
7072       if (has_double_maps) return NULL;
7073       has_smi_or_object_maps = true;
7074     } else {
7075       return NULL;
7076     }
7077     // Remember if we've ever seen holey elements.
7078     if (IsHoleyElementsKind(map->elements_kind())) {
7079       has_seen_holey_elements = true;
7080     }
7081     // Remember the most general elements kind, the code for its load will
7082     // properly handle all of the more specific cases.
7083     if ((i == 0) || IsMoreGeneralElementsKindTransition(
7084             most_general_consolidated_map->elements_kind(),
7085             map->elements_kind())) {
7086       most_general_consolidated_map = map;
7087     }
7088   }
7089   if (!has_double_maps && !has_smi_or_object_maps) return NULL;
7090 
7091   HCheckMaps* checked_object = Add<HCheckMaps>(object, maps);
7092   // FAST_ELEMENTS is considered more general than FAST_HOLEY_SMI_ELEMENTS.
7093   // If we've seen both, the consolidated load must use FAST_HOLEY_ELEMENTS.
7094   ElementsKind consolidated_elements_kind = has_seen_holey_elements
7095       ? GetHoleyElementsKind(most_general_consolidated_map->elements_kind())
7096       : most_general_consolidated_map->elements_kind();
7097   LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE;
7098   if (has_seen_holey_elements) {
7099     // Make sure that all of the maps we are handling have the initial array
7100     // prototype.
7101     bool saw_non_array_prototype = false;
7102     for (int i = 0; i < maps->length(); ++i) {
7103       Handle<Map> map = maps->at(i);
7104       if (map->prototype() != *isolate()->initial_array_prototype()) {
7105         // We can't guarantee that loading the hole is safe. The prototype may
7106         // have an element at this position.
7107         saw_non_array_prototype = true;
7108         break;
7109       }
7110     }
7111 
7112     if (!saw_non_array_prototype) {
7113       Handle<Map> holey_map = handle(
7114           isolate()->get_initial_js_array_map(consolidated_elements_kind));
7115       load_mode = BuildKeyedHoleMode(holey_map);
7116       if (load_mode != NEVER_RETURN_HOLE) {
7117         for (int i = 0; i < maps->length(); ++i) {
7118           Handle<Map> map = maps->at(i);
7119           // The prototype check was already done for the holey map in
7120           // BuildKeyedHoleMode.
7121           if (!map.is_identical_to(holey_map)) {
7122             Handle<JSObject> prototype(JSObject::cast(map->prototype()),
7123                                        isolate());
7124             Handle<JSObject> object_prototype =
7125                 isolate()->initial_object_prototype();
7126             BuildCheckPrototypeMaps(prototype, object_prototype);
7127           }
7128         }
7129       }
7130     }
7131   }
7132   HInstruction* instr = BuildUncheckedMonomorphicElementAccess(
7133       checked_object, key, val,
7134       most_general_consolidated_map->instance_type() == JS_ARRAY_TYPE,
7135       consolidated_elements_kind, LOAD, load_mode, STANDARD_STORE);
7136   return instr;
7137 }
7138 
HandlePolymorphicElementAccess(Expression * expr,FeedbackSlot slot,HValue * object,HValue * key,HValue * val,SmallMapList * maps,PropertyAccessType access_type,KeyedAccessStoreMode store_mode,bool * has_side_effects)7139 HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
7140     Expression* expr, FeedbackSlot slot, HValue* object, HValue* key,
7141     HValue* val, SmallMapList* maps, PropertyAccessType access_type,
7142     KeyedAccessStoreMode store_mode, bool* has_side_effects) {
7143   *has_side_effects = false;
7144   BuildCheckHeapObject(object);
7145 
7146   if (access_type == LOAD) {
7147     HInstruction* consolidated_load =
7148         TryBuildConsolidatedElementLoad(object, key, val, maps);
7149     if (consolidated_load != NULL) {
7150       *has_side_effects |= consolidated_load->HasObservableSideEffects();
7151       return consolidated_load;
7152     }
7153   }
7154 
7155   // Elements_kind transition support.
7156   MapHandleList transition_target(maps->length());
7157   // Collect possible transition targets.
7158   MapHandleList possible_transitioned_maps(maps->length());
7159   for (int i = 0; i < maps->length(); ++i) {
7160     Handle<Map> map = maps->at(i);
7161     // Loads from strings or loads with a mix of string and non-string maps
7162     // shouldn't be handled polymorphically.
7163     DCHECK(access_type != LOAD || !map->IsStringMap());
7164     ElementsKind elements_kind = map->elements_kind();
7165     if (CanInlineElementAccess(map) && IsFastElementsKind(elements_kind) &&
7166         elements_kind != GetInitialFastElementsKind()) {
7167       possible_transitioned_maps.Add(map);
7168     }
7169     if (IsSloppyArgumentsElements(elements_kind)) {
7170       HInstruction* result =
7171           BuildKeyedGeneric(access_type, expr, slot, object, key, val);
7172       *has_side_effects = result->HasObservableSideEffects();
7173       return AddInstruction(result);
7174     }
7175   }
7176   // Get transition target for each map (NULL == no transition).
7177   for (int i = 0; i < maps->length(); ++i) {
7178     Handle<Map> map = maps->at(i);
7179     Map* transitioned_map = map->is_stable() ?
7180         nullptr :
7181         map->FindElementsKindTransitionedMap(&possible_transitioned_maps);
7182     if (transitioned_map != nullptr) {
7183       transition_target.Add(handle(transitioned_map));
7184     } else {
7185       transition_target.Add(Handle<Map>());
7186     }
7187   }
7188 
7189   MapHandleList untransitionable_maps(maps->length());
7190   HTransitionElementsKind* transition = NULL;
7191   for (int i = 0; i < maps->length(); ++i) {
7192     Handle<Map> map = maps->at(i);
7193     DCHECK(map->IsMap());
7194     if (!transition_target.at(i).is_null()) {
7195       DCHECK(Map::IsValidElementsTransition(
7196           map->elements_kind(),
7197           transition_target.at(i)->elements_kind()));
7198       transition = Add<HTransitionElementsKind>(object, map,
7199                                                 transition_target.at(i));
7200     } else {
7201       untransitionable_maps.Add(map);
7202     }
7203   }
7204 
7205   // If only one map is left after transitioning, handle this case
7206   // monomorphically.
7207   DCHECK(untransitionable_maps.length() >= 1);
7208   if (untransitionable_maps.length() == 1) {
7209     Handle<Map> untransitionable_map = untransitionable_maps[0];
7210     HInstruction* instr = NULL;
7211     if (!CanInlineElementAccess(untransitionable_map)) {
7212       instr = AddInstruction(
7213           BuildKeyedGeneric(access_type, expr, slot, object, key, val));
7214     } else {
7215       instr = BuildMonomorphicElementAccess(
7216           object, key, val, transition, untransitionable_map, access_type,
7217           store_mode);
7218     }
7219     *has_side_effects |= instr->HasObservableSideEffects();
7220     return access_type == STORE ? val : instr;
7221   }
7222 
7223   HBasicBlock* join = graph()->CreateBasicBlock();
7224 
7225   for (int i = 0; i < untransitionable_maps.length(); ++i) {
7226     Handle<Map> map = untransitionable_maps[i];
7227     ElementsKind elements_kind = map->elements_kind();
7228     HBasicBlock* this_map = graph()->CreateBasicBlock();
7229     HBasicBlock* other_map = graph()->CreateBasicBlock();
7230     HCompareMap* mapcompare =
7231         New<HCompareMap>(object, map, this_map, other_map);
7232     FinishCurrentBlock(mapcompare);
7233 
7234     set_current_block(this_map);
7235     HInstruction* access = NULL;
7236     if (!CanInlineElementAccess(map)) {
7237       access = AddInstruction(
7238           BuildKeyedGeneric(access_type, expr, slot, object, key, val));
7239     } else {
7240       DCHECK(IsFastElementsKind(elements_kind) ||
7241              IsFixedTypedArrayElementsKind(elements_kind));
7242       LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map);
7243       // Happily, mapcompare is a checked object.
7244       access = BuildUncheckedMonomorphicElementAccess(
7245           mapcompare, key, val,
7246           map->instance_type() == JS_ARRAY_TYPE,
7247           elements_kind, access_type,
7248           load_mode,
7249           store_mode);
7250     }
7251     *has_side_effects |= access->HasObservableSideEffects();
7252     // The caller will use has_side_effects and add a correct Simulate.
7253     access->SetFlag(HValue::kHasNoObservableSideEffects);
7254     if (access_type == LOAD) {
7255       Push(access);
7256     }
7257     NoObservableSideEffectsScope scope(this);
7258     GotoNoSimulate(join);
7259     set_current_block(other_map);
7260   }
7261 
7262   // Ensure that we visited at least one map above that goes to join. This is
7263   // necessary because FinishExitWithHardDeoptimization does an AbnormalExit
7264   // rather than joining the join block. If this becomes an issue, insert a
7265   // generic access in the case length() == 0.
7266   DCHECK(join->predecessors()->length() > 0);
7267   // Deopt if none of the cases matched.
7268   NoObservableSideEffectsScope scope(this);
7269   FinishExitWithHardDeoptimization(
7270       DeoptimizeReason::kUnknownMapInPolymorphicElementAccess);
7271   set_current_block(join);
7272   return access_type == STORE ? val : Pop();
7273 }
7274 
HandleKeyedElementAccess(HValue * obj,HValue * key,HValue * val,Expression * expr,FeedbackSlot slot,BailoutId ast_id,BailoutId return_id,PropertyAccessType access_type,bool * has_side_effects)7275 HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
7276     HValue* obj, HValue* key, HValue* val, Expression* expr, FeedbackSlot slot,
7277     BailoutId ast_id, BailoutId return_id, PropertyAccessType access_type,
7278     bool* has_side_effects) {
7279   // A keyed name access with type feedback may contain the name.
7280   Handle<FeedbackVector> vector = handle(current_feedback_vector(), isolate());
7281   HValue* expected_key = key;
7282   if (!key->ActualValue()->IsConstant()) {
7283     Name* name = nullptr;
7284     if (access_type == LOAD) {
7285       KeyedLoadICNexus nexus(vector, slot);
7286       name = nexus.FindFirstName();
7287     } else {
7288       KeyedStoreICNexus nexus(vector, slot);
7289       name = nexus.FindFirstName();
7290     }
7291     if (name != nullptr) {
7292       Handle<Name> handle_name(name);
7293       expected_key = Add<HConstant>(handle_name);
7294       // We need a check against the key.
7295       bool in_new_space = isolate()->heap()->InNewSpace(*handle_name);
7296       Unique<Name> unique_name = Unique<Name>::CreateUninitialized(handle_name);
7297       Add<HCheckValue>(key, unique_name, in_new_space);
7298     }
7299   }
7300   if (expected_key->ActualValue()->IsConstant()) {
7301     Handle<Object> constant =
7302         HConstant::cast(expected_key->ActualValue())->handle(isolate());
7303     uint32_t array_index;
7304     if ((constant->IsString() &&
7305          !Handle<String>::cast(constant)->AsArrayIndex(&array_index)) ||
7306         constant->IsSymbol()) {
7307       if (!constant->IsUniqueName()) {
7308         constant = isolate()->factory()->InternalizeString(
7309             Handle<String>::cast(constant));
7310       }
7311       HValue* access =
7312           BuildNamedAccess(access_type, ast_id, return_id, expr, slot, obj,
7313                            Handle<Name>::cast(constant), val, false);
7314       if (access == NULL || access->IsPhi() ||
7315           HInstruction::cast(access)->IsLinked()) {
7316         *has_side_effects = false;
7317       } else {
7318         HInstruction* instr = HInstruction::cast(access);
7319         AddInstruction(instr);
7320         *has_side_effects = instr->HasObservableSideEffects();
7321       }
7322       return access;
7323     }
7324   }
7325 
7326   DCHECK(!expr->IsPropertyName());
7327   HInstruction* instr = NULL;
7328 
7329   SmallMapList* maps;
7330   bool monomorphic = ComputeReceiverTypes(expr, obj, &maps, this);
7331 
7332   bool force_generic = false;
7333   if (expr->GetKeyType() == PROPERTY) {
7334     // Non-Generic accesses assume that elements are being accessed, and will
7335     // deopt for non-index keys, which the IC knows will occur.
7336     // TODO(jkummerow): Consider adding proper support for property accesses.
7337     force_generic = true;
7338     monomorphic = false;
7339   } else if (access_type == STORE &&
7340              (monomorphic || (maps != NULL && !maps->is_empty()))) {
7341     // Stores can't be mono/polymorphic if their prototype chain has dictionary
7342     // elements. However a receiver map that has dictionary elements itself
7343     // should be left to normal mono/poly behavior (the other maps may benefit
7344     // from highly optimized stores).
7345     for (int i = 0; i < maps->length(); i++) {
7346       Handle<Map> current_map = maps->at(i);
7347       if (current_map->DictionaryElementsInPrototypeChainOnly()) {
7348         force_generic = true;
7349         monomorphic = false;
7350         break;
7351       }
7352     }
7353   } else if (access_type == LOAD && !monomorphic &&
7354              (maps != NULL && !maps->is_empty())) {
7355     // Polymorphic loads have to go generic if any of the maps are strings.
7356     // If some, but not all of the maps are strings, we should go generic
7357     // because polymorphic access wants to key on ElementsKind and isn't
7358     // compatible with strings.
7359     for (int i = 0; i < maps->length(); i++) {
7360       Handle<Map> current_map = maps->at(i);
7361       if (current_map->IsStringMap()) {
7362         force_generic = true;
7363         break;
7364       }
7365     }
7366   }
7367 
7368   if (monomorphic) {
7369     Handle<Map> map = maps->first();
7370     if (!CanInlineElementAccess(map)) {
7371       instr = AddInstruction(
7372           BuildKeyedGeneric(access_type, expr, slot, obj, key, val));
7373     } else {
7374       BuildCheckHeapObject(obj);
7375       instr = BuildMonomorphicElementAccess(
7376           obj, key, val, NULL, map, access_type, expr->GetStoreMode());
7377     }
7378   } else if (!force_generic && (maps != NULL && !maps->is_empty())) {
7379     return HandlePolymorphicElementAccess(expr, slot, obj, key, val, maps,
7380                                           access_type, expr->GetStoreMode(),
7381                                           has_side_effects);
7382   } else {
7383     if (access_type == STORE) {
7384       if (expr->IsAssignment() &&
7385           expr->AsAssignment()->HasNoTypeInformation()) {
7386         Add<HDeoptimize>(
7387             DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess,
7388             Deoptimizer::SOFT);
7389       }
7390     } else {
7391       if (expr->AsProperty()->HasNoTypeInformation()) {
7392         Add<HDeoptimize>(
7393             DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess,
7394             Deoptimizer::SOFT);
7395       }
7396     }
7397     instr = AddInstruction(
7398         BuildKeyedGeneric(access_type, expr, slot, obj, key, val));
7399   }
7400   *has_side_effects = instr->HasObservableSideEffects();
7401   return instr;
7402 }
7403 
7404 
EnsureArgumentsArePushedForAccess()7405 void HOptimizedGraphBuilder::EnsureArgumentsArePushedForAccess() {
7406   // Outermost function already has arguments on the stack.
7407   if (function_state()->outer() == NULL) return;
7408 
7409   if (function_state()->arguments_pushed()) return;
7410 
7411   // Push arguments when entering inlined function.
7412   HEnterInlined* entry = function_state()->entry();
7413   entry->set_arguments_pushed();
7414 
7415   HArgumentsObject* arguments = entry->arguments_object();
7416   const ZoneList<HValue*>* arguments_values = arguments->arguments_values();
7417 
7418   HInstruction* insert_after = entry;
7419   for (int i = 0; i < arguments_values->length(); i++) {
7420     HValue* argument = arguments_values->at(i);
7421     HInstruction* push_argument = New<HPushArguments>(argument);
7422     push_argument->InsertAfter(insert_after);
7423     insert_after = push_argument;
7424   }
7425 
7426   HArgumentsElements* arguments_elements = New<HArgumentsElements>(true);
7427   arguments_elements->ClearFlag(HValue::kUseGVN);
7428   arguments_elements->InsertAfter(insert_after);
7429   function_state()->set_arguments_elements(arguments_elements);
7430 }
7431 
IsAnyParameterContextAllocated()7432 bool HOptimizedGraphBuilder::IsAnyParameterContextAllocated() {
7433   int count = current_info()->scope()->num_parameters();
7434   for (int i = 0; i < count; ++i) {
7435     if (current_info()->scope()->parameter(i)->location() ==
7436         VariableLocation::CONTEXT) {
7437       return true;
7438     }
7439   }
7440   return false;
7441 }
7442 
TryArgumentsAccess(Property * expr)7443 bool HOptimizedGraphBuilder::TryArgumentsAccess(Property* expr) {
7444   VariableProxy* proxy = expr->obj()->AsVariableProxy();
7445   if (proxy == NULL) return false;
7446   if (!proxy->var()->IsStackAllocated()) return false;
7447   if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) {
7448     return false;
7449   }
7450 
7451   HInstruction* result = NULL;
7452   if (expr->key()->IsPropertyName()) {
7453     Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
7454     if (!String::Equals(name, isolate()->factory()->length_string())) {
7455       return false;
7456     }
7457 
7458     // Make sure we visit the arguments object so that the liveness analysis
7459     // still records the access.
7460     CHECK_ALIVE_OR_RETURN(VisitForValue(expr->obj(), ARGUMENTS_ALLOWED), true);
7461     Drop(1);
7462 
7463     if (function_state()->outer() == NULL) {
7464       HInstruction* elements = Add<HArgumentsElements>(false);
7465       result = New<HArgumentsLength>(elements);
7466     } else {
7467       // Number of arguments without receiver.
7468       int argument_count = environment()->
7469           arguments_environment()->parameter_count() - 1;
7470       result = New<HConstant>(argument_count);
7471     }
7472   } else {
7473     // We need to take into account the KEYED_LOAD_IC feedback to guard the
7474     // HBoundsCheck instructions below.
7475     if (!expr->IsMonomorphic() && !expr->IsUninitialized()) return false;
7476     if (IsAnyParameterContextAllocated()) return false;
7477     CHECK_ALIVE_OR_RETURN(VisitForValue(expr->obj(), ARGUMENTS_ALLOWED), true);
7478     CHECK_ALIVE_OR_RETURN(VisitForValue(expr->key()), true);
7479     HValue* key = Pop();
7480     Drop(1);  // Arguments object.
7481     if (function_state()->outer() == NULL) {
7482       HInstruction* elements = Add<HArgumentsElements>(false);
7483       HInstruction* length = Add<HArgumentsLength>(elements);
7484       HInstruction* checked_key = Add<HBoundsCheck>(key, length);
7485       result = New<HAccessArgumentsAt>(elements, length, checked_key);
7486     } else {
7487       EnsureArgumentsArePushedForAccess();
7488 
7489       // Number of arguments without receiver.
7490       HInstruction* elements = function_state()->arguments_elements();
7491       int argument_count = environment()->
7492           arguments_environment()->parameter_count() - 1;
7493       HInstruction* length = Add<HConstant>(argument_count);
7494       HInstruction* checked_key = Add<HBoundsCheck>(key, length);
7495       result = New<HAccessArgumentsAt>(elements, length, checked_key);
7496     }
7497   }
7498   ast_context()->ReturnInstruction(result, expr->id());
7499   return true;
7500 }
7501 
BuildNamedAccess(PropertyAccessType access,BailoutId ast_id,BailoutId return_id,Expression * expr,FeedbackSlot slot,HValue * object,Handle<Name> name,HValue * value,bool is_uninitialized)7502 HValue* HOptimizedGraphBuilder::BuildNamedAccess(
7503     PropertyAccessType access, BailoutId ast_id, BailoutId return_id,
7504     Expression* expr, FeedbackSlot slot, HValue* object, Handle<Name> name,
7505     HValue* value, bool is_uninitialized) {
7506   SmallMapList* maps;
7507   ComputeReceiverTypes(expr, object, &maps, this);
7508   DCHECK(maps != NULL);
7509 
7510   // Check for special case: Access via a single map to the global proxy
7511   // can also be handled monomorphically.
7512   if (maps->length() > 0) {
7513     Handle<Object> map_constructor =
7514         handle(maps->first()->GetConstructor(), isolate());
7515     if (map_constructor->IsJSFunction()) {
7516       Handle<Context> map_context =
7517           handle(Handle<JSFunction>::cast(map_constructor)->context());
7518       Handle<Context> current_context(current_info()->context());
7519       bool is_same_context_global_proxy_access =
7520           maps->length() == 1 &&  // >1 map => fallback to polymorphic
7521           maps->first()->IsJSGlobalProxyMap() &&
7522           (*map_context == *current_context);
7523       if (is_same_context_global_proxy_access) {
7524         Handle<JSGlobalObject> global_object(current_info()->global_object());
7525         LookupIterator it(global_object, name, LookupIterator::OWN);
7526         if (CanInlineGlobalPropertyAccess(&it, access)) {
7527           BuildCheckHeapObject(object);
7528           Add<HCheckMaps>(object, maps);
7529           if (access == LOAD) {
7530             InlineGlobalPropertyLoad(&it, expr->id());
7531             return nullptr;
7532           } else {
7533             return InlineGlobalPropertyStore(&it, value, expr->id());
7534           }
7535         }
7536       }
7537     }
7538 
7539     PropertyAccessInfo info(this, access, maps->first(), name);
7540     if (!info.CanAccessAsMonomorphic(maps)) {
7541       HandlePolymorphicNamedFieldAccess(access, expr, slot, ast_id, return_id,
7542                                         object, value, maps, name);
7543       return NULL;
7544     }
7545 
7546     HValue* checked_object;
7547     // AstType::Number() is only supported by polymorphic load/call handling.
7548     DCHECK(!info.IsNumberType());
7549     BuildCheckHeapObject(object);
7550     if (AreStringTypes(maps)) {
7551       checked_object =
7552           Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING);
7553     } else {
7554       checked_object = Add<HCheckMaps>(object, maps);
7555     }
7556     return BuildMonomorphicAccess(
7557         &info, object, checked_object, value, ast_id, return_id);
7558   }
7559 
7560   return BuildNamedGeneric(access, expr, slot, object, name, value,
7561                            is_uninitialized);
7562 }
7563 
7564 
PushLoad(Property * expr,HValue * object,HValue * key)7565 void HOptimizedGraphBuilder::PushLoad(Property* expr,
7566                                       HValue* object,
7567                                       HValue* key) {
7568   ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED);
7569   Push(object);
7570   if (key != NULL) Push(key);
7571   BuildLoad(expr, expr->LoadId());
7572 }
7573 
7574 
BuildLoad(Property * expr,BailoutId ast_id)7575 void HOptimizedGraphBuilder::BuildLoad(Property* expr,
7576                                        BailoutId ast_id) {
7577   HInstruction* instr = NULL;
7578   if (expr->IsStringAccess() && expr->GetKeyType() == ELEMENT) {
7579     HValue* index = Pop();
7580     HValue* string = Pop();
7581     HInstruction* char_code = BuildStringCharCodeAt(string, index);
7582     AddInstruction(char_code);
7583     if (char_code->IsConstant()) {
7584       HConstant* c_code = HConstant::cast(char_code);
7585       if (c_code->HasNumberValue() && std::isnan(c_code->DoubleValue())) {
7586         Add<HDeoptimize>(DeoptimizeReason::kOutOfBounds, Deoptimizer::EAGER);
7587       }
7588     }
7589     instr = NewUncasted<HStringCharFromCode>(char_code);
7590 
7591   } else if (expr->key()->IsPropertyName()) {
7592     Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
7593     HValue* object = Pop();
7594 
7595     HValue* value = BuildNamedAccess(LOAD, ast_id, expr->LoadId(), expr,
7596                                      expr->PropertyFeedbackSlot(), object, name,
7597                                      NULL, expr->IsUninitialized());
7598     if (value == NULL) return;
7599     if (value->IsPhi()) return ast_context()->ReturnValue(value);
7600     instr = HInstruction::cast(value);
7601     if (instr->IsLinked()) return ast_context()->ReturnValue(instr);
7602 
7603   } else {
7604     HValue* key = Pop();
7605     HValue* obj = Pop();
7606 
7607     bool has_side_effects = false;
7608     HValue* load = HandleKeyedElementAccess(
7609         obj, key, NULL, expr, expr->PropertyFeedbackSlot(), ast_id,
7610         expr->LoadId(), LOAD, &has_side_effects);
7611     if (has_side_effects) {
7612       if (ast_context()->IsEffect()) {
7613         Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
7614       } else {
7615         Push(load);
7616         Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
7617         Drop(1);
7618       }
7619     }
7620     if (load == NULL) return;
7621     return ast_context()->ReturnValue(load);
7622   }
7623   return ast_context()->ReturnInstruction(instr, ast_id);
7624 }
7625 
7626 
VisitProperty(Property * expr)7627 void HOptimizedGraphBuilder::VisitProperty(Property* expr) {
7628   DCHECK(!HasStackOverflow());
7629   DCHECK(current_block() != NULL);
7630   DCHECK(current_block()->HasPredecessor());
7631 
7632   if (TryArgumentsAccess(expr)) return;
7633 
7634   CHECK_ALIVE(VisitForValue(expr->obj()));
7635   if (!expr->key()->IsPropertyName() || expr->IsStringAccess()) {
7636     CHECK_ALIVE(VisitForValue(expr->key()));
7637   }
7638 
7639   BuildLoad(expr, expr->id());
7640 }
7641 
BuildConstantMapCheck(Handle<JSObject> constant,bool ensure_no_elements)7642 HInstruction* HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant,
7643                                                    bool ensure_no_elements) {
7644   HCheckMaps* check = Add<HCheckMaps>(
7645       Add<HConstant>(constant), handle(constant->map()));
7646   check->ClearDependsOnFlag(kElementsKind);
7647   if (ensure_no_elements) {
7648     // TODO(ishell): remove this once we support NO_ELEMENTS elements kind.
7649     HValue* elements = AddLoadElements(check, nullptr);
7650     HValue* empty_elements =
7651         Add<HConstant>(isolate()->factory()->empty_fixed_array());
7652     IfBuilder if_empty(this);
7653     if_empty.IfNot<HCompareObjectEqAndBranch>(elements, empty_elements);
7654     if_empty.ThenDeopt(DeoptimizeReason::kWrongMap);
7655     if_empty.End();
7656   }
7657   return check;
7658 }
7659 
BuildCheckPrototypeMaps(Handle<JSObject> prototype,Handle<JSObject> holder,bool ensure_no_elements)7660 HInstruction* HGraphBuilder::BuildCheckPrototypeMaps(Handle<JSObject> prototype,
7661                                                      Handle<JSObject> holder,
7662                                                      bool ensure_no_elements) {
7663   PrototypeIterator iter(isolate(), prototype, kStartAtReceiver);
7664   while (holder.is_null() ||
7665          !PrototypeIterator::GetCurrent(iter).is_identical_to(holder)) {
7666     BuildConstantMapCheck(PrototypeIterator::GetCurrent<JSObject>(iter),
7667                           ensure_no_elements);
7668     iter.Advance();
7669     if (iter.IsAtEnd()) {
7670       return NULL;
7671     }
7672   }
7673   return BuildConstantMapCheck(holder);
7674 }
7675 
7676 
AddCheckPrototypeMaps(Handle<JSObject> holder,Handle<Map> receiver_map)7677 void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder,
7678                                                    Handle<Map> receiver_map) {
7679   if (!holder.is_null()) {
7680     Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype()));
7681     BuildCheckPrototypeMaps(prototype, holder);
7682   }
7683 }
7684 
BuildEnsureCallable(HValue * object)7685 void HOptimizedGraphBuilder::BuildEnsureCallable(HValue* object) {
7686   NoObservableSideEffectsScope scope(this);
7687   const Runtime::Function* throw_called_non_callable =
7688       Runtime::FunctionForId(Runtime::kThrowCalledNonCallable);
7689 
7690   IfBuilder is_not_function(this);
7691   HValue* smi_check = is_not_function.If<HIsSmiAndBranch>(object);
7692   is_not_function.Or();
7693   HValue* map = AddLoadMap(object, smi_check);
7694   HValue* bit_field =
7695       Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField());
7696   HValue* bit_field_masked = AddUncasted<HBitwise>(
7697       Token::BIT_AND, bit_field, Add<HConstant>(1 << Map::kIsCallable));
7698   is_not_function.IfNot<HCompareNumericAndBranch>(
7699       bit_field_masked, Add<HConstant>(1 << Map::kIsCallable), Token::EQ);
7700   is_not_function.Then();
7701   {
7702     Add<HPushArguments>(object);
7703     Add<HCallRuntime>(throw_called_non_callable, 1);
7704   }
7705   is_not_function.End();
7706 }
7707 
NewCallFunction(HValue * function,int argument_count,TailCallMode syntactic_tail_call_mode,ConvertReceiverMode convert_mode,TailCallMode tail_call_mode)7708 HInstruction* HOptimizedGraphBuilder::NewCallFunction(
7709     HValue* function, int argument_count, TailCallMode syntactic_tail_call_mode,
7710     ConvertReceiverMode convert_mode, TailCallMode tail_call_mode) {
7711   if (syntactic_tail_call_mode == TailCallMode::kAllow) {
7712     BuildEnsureCallable(function);
7713   } else {
7714     DCHECK_EQ(TailCallMode::kDisallow, tail_call_mode);
7715   }
7716   HValue* arity = Add<HConstant>(argument_count - 1);
7717 
7718   HValue* op_vals[] = {function, arity};
7719 
7720   Callable callable =
7721       CodeFactory::Call(isolate(), convert_mode, tail_call_mode);
7722   HConstant* stub = Add<HConstant>(callable.code());
7723 
7724   return New<HCallWithDescriptor>(stub, argument_count, callable.descriptor(),
7725                                   ArrayVector(op_vals),
7726                                   syntactic_tail_call_mode);
7727 }
7728 
NewCallFunctionViaIC(HValue * function,int argument_count,TailCallMode syntactic_tail_call_mode,ConvertReceiverMode convert_mode,TailCallMode tail_call_mode,FeedbackSlot slot)7729 HInstruction* HOptimizedGraphBuilder::NewCallFunctionViaIC(
7730     HValue* function, int argument_count, TailCallMode syntactic_tail_call_mode,
7731     ConvertReceiverMode convert_mode, TailCallMode tail_call_mode,
7732     FeedbackSlot slot) {
7733   if (syntactic_tail_call_mode == TailCallMode::kAllow) {
7734     BuildEnsureCallable(function);
7735   } else {
7736     DCHECK_EQ(TailCallMode::kDisallow, tail_call_mode);
7737   }
7738   int arity = argument_count - 1;
7739   Handle<FeedbackVector> vector(current_feedback_vector(), isolate());
7740   HValue* arity_val = Add<HConstant>(arity);
7741   HValue* index_val = Add<HConstant>(vector->GetIndex(slot));
7742   HValue* vector_val = Add<HConstant>(vector);
7743 
7744   HValue* op_vals[] = {function, arity_val, index_val, vector_val};
7745   Callable callable =
7746       CodeFactory::CallIC(isolate(), convert_mode, tail_call_mode);
7747   HConstant* stub = Add<HConstant>(callable.code());
7748 
7749   return New<HCallWithDescriptor>(stub, argument_count, callable.descriptor(),
7750                                   ArrayVector(op_vals),
7751                                   syntactic_tail_call_mode);
7752 }
7753 
NewCallConstantFunction(Handle<JSFunction> function,int argument_count,TailCallMode syntactic_tail_call_mode,TailCallMode tail_call_mode)7754 HInstruction* HOptimizedGraphBuilder::NewCallConstantFunction(
7755     Handle<JSFunction> function, int argument_count,
7756     TailCallMode syntactic_tail_call_mode, TailCallMode tail_call_mode) {
7757   HValue* target = Add<HConstant>(function);
7758   return New<HInvokeFunction>(target, function, argument_count,
7759                               syntactic_tail_call_mode, tail_call_mode);
7760 }
7761 
7762 
7763 class FunctionSorter {
7764  public:
FunctionSorter(int index=0,int ticks=0,int size=0)7765   explicit FunctionSorter(int index = 0, int ticks = 0, int size = 0)
7766       : index_(index), ticks_(ticks), size_(size) {}
7767 
index() const7768   int index() const { return index_; }
ticks() const7769   int ticks() const { return ticks_; }
size() const7770   int size() const { return size_; }
7771 
7772  private:
7773   int index_;
7774   int ticks_;
7775   int size_;
7776 };
7777 
7778 
operator <(const FunctionSorter & lhs,const FunctionSorter & rhs)7779 inline bool operator<(const FunctionSorter& lhs, const FunctionSorter& rhs) {
7780   int diff = lhs.ticks() - rhs.ticks();
7781   if (diff != 0) return diff > 0;
7782   return lhs.size() < rhs.size();
7783 }
7784 
7785 
HandlePolymorphicCallNamed(Call * expr,HValue * receiver,SmallMapList * maps,Handle<String> name)7786 void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
7787                                                         HValue* receiver,
7788                                                         SmallMapList* maps,
7789                                                         Handle<String> name) {
7790   int argument_count = expr->arguments()->length() + 1;  // Includes receiver.
7791   FunctionSorter order[kMaxCallPolymorphism];
7792 
7793   bool handle_smi = false;
7794   bool handled_string = false;
7795   int ordered_functions = 0;
7796 
7797   TailCallMode syntactic_tail_call_mode = expr->tail_call_mode();
7798   TailCallMode tail_call_mode =
7799       function_state()->ComputeTailCallMode(syntactic_tail_call_mode);
7800 
7801   int i;
7802   for (i = 0; i < maps->length() && ordered_functions < kMaxCallPolymorphism;
7803        ++i) {
7804     PropertyAccessInfo info(this, LOAD, maps->at(i), name);
7805     if (info.CanAccessMonomorphic() && info.IsDataConstant() &&
7806         info.constant()->IsJSFunction()) {
7807       if (info.IsStringType()) {
7808         if (handled_string) continue;
7809         handled_string = true;
7810       }
7811       Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant());
7812       if (info.IsNumberType()) {
7813         handle_smi = true;
7814       }
7815       expr->set_target(target);
7816       order[ordered_functions++] = FunctionSorter(
7817           i, target->shared()->profiler_ticks(), InliningAstSize(target));
7818     }
7819   }
7820 
7821   std::sort(order, order + ordered_functions);
7822 
7823   if (i < maps->length()) {
7824     maps->Clear();
7825     ordered_functions = -1;
7826   }
7827 
7828   HBasicBlock* number_block = NULL;
7829   HBasicBlock* join = NULL;
7830   handled_string = false;
7831   int count = 0;
7832 
7833   for (int fn = 0; fn < ordered_functions; ++fn) {
7834     int i = order[fn].index();
7835     PropertyAccessInfo info(this, LOAD, maps->at(i), name);
7836     if (info.IsStringType()) {
7837       if (handled_string) continue;
7838       handled_string = true;
7839     }
7840     // Reloads the target.
7841     info.CanAccessMonomorphic();
7842     Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant());
7843 
7844     expr->set_target(target);
7845     if (count == 0) {
7846       // Only needed once.
7847       join = graph()->CreateBasicBlock();
7848       if (handle_smi) {
7849         HBasicBlock* empty_smi_block = graph()->CreateBasicBlock();
7850         HBasicBlock* not_smi_block = graph()->CreateBasicBlock();
7851         number_block = graph()->CreateBasicBlock();
7852         FinishCurrentBlock(New<HIsSmiAndBranch>(
7853                 receiver, empty_smi_block, not_smi_block));
7854         GotoNoSimulate(empty_smi_block, number_block);
7855         set_current_block(not_smi_block);
7856       } else {
7857         BuildCheckHeapObject(receiver);
7858       }
7859     }
7860     ++count;
7861     HBasicBlock* if_true = graph()->CreateBasicBlock();
7862     HBasicBlock* if_false = graph()->CreateBasicBlock();
7863     HUnaryControlInstruction* compare;
7864 
7865     Handle<Map> map = info.map();
7866     if (info.IsNumberType()) {
7867       Handle<Map> heap_number_map = isolate()->factory()->heap_number_map();
7868       compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false);
7869     } else if (info.IsStringType()) {
7870       compare = New<HIsStringAndBranch>(receiver, if_true, if_false);
7871     } else {
7872       compare = New<HCompareMap>(receiver, map, if_true, if_false);
7873     }
7874     FinishCurrentBlock(compare);
7875 
7876     if (info.IsNumberType()) {
7877       GotoNoSimulate(if_true, number_block);
7878       if_true = number_block;
7879     }
7880 
7881     set_current_block(if_true);
7882 
7883     AddCheckPrototypeMaps(info.holder(), map);
7884 
7885     HValue* function = Add<HConstant>(expr->target());
7886     environment()->SetExpressionStackAt(0, function);
7887     Push(receiver);
7888     CHECK_ALIVE(VisitExpressions(expr->arguments()));
7889     bool needs_wrapping = info.NeedsWrappingFor(target);
7890     bool try_inline = FLAG_polymorphic_inlining && !needs_wrapping;
7891     if (FLAG_trace_inlining && try_inline) {
7892       Handle<JSFunction> caller = current_info()->closure();
7893       std::unique_ptr<char[]> caller_name =
7894           caller->shared()->DebugName()->ToCString();
7895       PrintF("Trying to inline the polymorphic call to %s from %s\n",
7896              name->ToCString().get(),
7897              caller_name.get());
7898     }
7899     if (try_inline && TryInlineCall(expr)) {
7900       // Trying to inline will signal that we should bailout from the
7901       // entire compilation by setting stack overflow on the visitor.
7902       if (HasStackOverflow()) return;
7903     } else {
7904       // Since HWrapReceiver currently cannot actually wrap numbers and strings,
7905       // use the regular call builtin for method calls to wrap the receiver.
7906       // TODO(verwaest): Support creation of value wrappers directly in
7907       // HWrapReceiver.
7908       HInstruction* call =
7909           needs_wrapping
7910               ? NewCallFunction(
7911                     function, argument_count, syntactic_tail_call_mode,
7912                     ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode)
7913               : NewCallConstantFunction(target, argument_count,
7914                                         syntactic_tail_call_mode,
7915                                         tail_call_mode);
7916       PushArgumentsFromEnvironment(argument_count);
7917       AddInstruction(call);
7918       Drop(1);  // Drop the function.
7919       if (!ast_context()->IsEffect()) Push(call);
7920     }
7921 
7922     if (current_block() != NULL) Goto(join);
7923     set_current_block(if_false);
7924   }
7925 
7926   // Finish up.  Unconditionally deoptimize if we've handled all the maps we
7927   // know about and do not want to handle ones we've never seen.  Otherwise
7928   // use a generic IC.
7929   if (ordered_functions == maps->length() && FLAG_deoptimize_uncommon_cases) {
7930     FinishExitWithHardDeoptimization(
7931         DeoptimizeReason::kUnknownMapInPolymorphicCall);
7932   } else {
7933     Property* prop = expr->expression()->AsProperty();
7934     HInstruction* function =
7935         BuildNamedGeneric(LOAD, prop, prop->PropertyFeedbackSlot(), receiver,
7936                           name, NULL, prop->IsUninitialized());
7937     AddInstruction(function);
7938     Push(function);
7939     AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE);
7940 
7941     environment()->SetExpressionStackAt(1, function);
7942     environment()->SetExpressionStackAt(0, receiver);
7943     CHECK_ALIVE(VisitExpressions(expr->arguments()));
7944 
7945     HInstruction* call = NewCallFunction(
7946         function, argument_count, syntactic_tail_call_mode,
7947         ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode);
7948 
7949     PushArgumentsFromEnvironment(argument_count);
7950 
7951     Drop(1);  // Function.
7952 
7953     if (join != NULL) {
7954       AddInstruction(call);
7955       if (!ast_context()->IsEffect()) Push(call);
7956       Goto(join);
7957     } else {
7958       return ast_context()->ReturnInstruction(call, expr->id());
7959     }
7960   }
7961 
7962   // We assume that control flow is always live after an expression.  So
7963   // even without predecessors to the join block, we set it as the exit
7964   // block and continue by adding instructions there.
7965   DCHECK(join != NULL);
7966   if (join->HasPredecessor()) {
7967     set_current_block(join);
7968     join->SetJoinId(expr->id());
7969     if (!ast_context()->IsEffect()) return ast_context()->ReturnValue(Pop());
7970   } else {
7971     set_current_block(NULL);
7972   }
7973 }
7974 
TraceInline(Handle<JSFunction> target,Handle<JSFunction> caller,const char * reason,TailCallMode tail_call_mode)7975 void HOptimizedGraphBuilder::TraceInline(Handle<JSFunction> target,
7976                                          Handle<JSFunction> caller,
7977                                          const char* reason,
7978                                          TailCallMode tail_call_mode) {
7979   if (FLAG_trace_inlining) {
7980     std::unique_ptr<char[]> target_name =
7981         target->shared()->DebugName()->ToCString();
7982     std::unique_ptr<char[]> caller_name =
7983         caller->shared()->DebugName()->ToCString();
7984     if (reason == NULL) {
7985       const char* call_mode =
7986           tail_call_mode == TailCallMode::kAllow ? "tail called" : "called";
7987       PrintF("Inlined %s %s from %s.\n", target_name.get(), call_mode,
7988              caller_name.get());
7989     } else {
7990       PrintF("Did not inline %s called from %s (%s).\n",
7991              target_name.get(), caller_name.get(), reason);
7992     }
7993   }
7994 }
7995 
7996 
7997 static const int kNotInlinable = 1000000000;
7998 
7999 
InliningAstSize(Handle<JSFunction> target)8000 int HOptimizedGraphBuilder::InliningAstSize(Handle<JSFunction> target) {
8001   if (!FLAG_use_inlining) return kNotInlinable;
8002 
8003   // Precondition: call is monomorphic and we have found a target with the
8004   // appropriate arity.
8005   Handle<JSFunction> caller = current_info()->closure();
8006   Handle<SharedFunctionInfo> target_shared(target->shared());
8007 
8008   // Always inline functions that force inlining.
8009   if (target_shared->force_inline()) {
8010     return 0;
8011   }
8012   if (!target->shared()->IsUserJavaScript()) {
8013     return kNotInlinable;
8014   }
8015 
8016   if (target_shared->IsApiFunction()) {
8017     TraceInline(target, caller, "target is api function");
8018     return kNotInlinable;
8019   }
8020 
8021   // Do a quick check on source code length to avoid parsing large
8022   // inlining candidates.
8023   if (target_shared->SourceSize() >
8024       Min(FLAG_max_inlined_source_size, kUnlimitedMaxInlinedSourceSize)) {
8025     TraceInline(target, caller, "target text too big");
8026     return kNotInlinable;
8027   }
8028 
8029   // Target must be inlineable.
8030   BailoutReason noopt_reason = target_shared->disable_optimization_reason();
8031   if (!target_shared->IsInlineable() && noopt_reason != kHydrogenFilter) {
8032     TraceInline(target, caller, "target not inlineable");
8033     return kNotInlinable;
8034   }
8035   if (noopt_reason != kNoReason && noopt_reason != kHydrogenFilter) {
8036     TraceInline(target, caller, "target contains unsupported syntax [early]");
8037     return kNotInlinable;
8038   }
8039 
8040   int nodes_added = target_shared->ast_node_count();
8041   return nodes_added;
8042 }
8043 
TryInline(Handle<JSFunction> target,int arguments_count,HValue * implicit_return_value,BailoutId ast_id,BailoutId return_id,InliningKind inlining_kind,TailCallMode syntactic_tail_call_mode)8044 bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target,
8045                                        int arguments_count,
8046                                        HValue* implicit_return_value,
8047                                        BailoutId ast_id, BailoutId return_id,
8048                                        InliningKind inlining_kind,
8049                                        TailCallMode syntactic_tail_call_mode) {
8050   if (target->context()->native_context() !=
8051       top_info()->closure()->context()->native_context()) {
8052     return false;
8053   }
8054   int nodes_added = InliningAstSize(target);
8055   if (nodes_added == kNotInlinable) return false;
8056 
8057   Handle<JSFunction> caller = current_info()->closure();
8058   if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) {
8059     TraceInline(target, caller, "target AST is too large [early]");
8060     return false;
8061   }
8062 
8063   // Don't inline deeper than the maximum number of inlining levels.
8064   HEnvironment* env = environment();
8065   int current_level = 1;
8066   while (env->outer() != NULL) {
8067     if (current_level == FLAG_max_inlining_levels) {
8068       TraceInline(target, caller, "inline depth limit reached");
8069       return false;
8070     }
8071     if (env->outer()->frame_type() == JS_FUNCTION) {
8072       current_level++;
8073     }
8074     env = env->outer();
8075   }
8076 
8077   // Don't inline recursive functions.
8078   for (FunctionState* state = function_state();
8079        state != NULL;
8080        state = state->outer()) {
8081     if (*state->compilation_info()->closure() == *target) {
8082       TraceInline(target, caller, "target is recursive");
8083       return false;
8084     }
8085   }
8086 
8087   // We don't want to add more than a certain number of nodes from inlining.
8088   // Always inline small methods (<= 10 nodes).
8089   if (inlined_count_ > Min(FLAG_max_inlined_nodes_cumulative,
8090                            kUnlimitedMaxInlinedNodesCumulative)) {
8091     TraceInline(target, caller, "cumulative AST node limit reached");
8092     return false;
8093   }
8094 
8095   // Parse and allocate variables.
8096   // Use the same AstValueFactory for creating strings in the sub-compilation
8097   // step, but don't transfer ownership to target_info.
8098   Handle<SharedFunctionInfo> target_shared(target->shared());
8099   ParseInfo parse_info(target_shared, top_info()->parse_info()->zone_shared());
8100   parse_info.set_ast_value_factory(
8101       top_info()->parse_info()->ast_value_factory());
8102   parse_info.set_ast_value_factory_owned(false);
8103 
8104   CompilationInfo target_info(parse_info.zone(), &parse_info, target);
8105 
8106   if (inlining_kind != CONSTRUCT_CALL_RETURN &&
8107       IsClassConstructor(target_shared->kind())) {
8108     TraceInline(target, caller, "target is classConstructor");
8109     return false;
8110   }
8111 
8112   if (target_shared->HasDebugInfo()) {
8113     TraceInline(target, caller, "target is being debugged");
8114     return false;
8115   }
8116   if (!Compiler::ParseAndAnalyze(target_info.parse_info())) {
8117     if (target_info.isolate()->has_pending_exception()) {
8118       // Parse or scope error, never optimize this function.
8119       SetStackOverflow();
8120       target_shared->DisableOptimization(kParseScopeError);
8121     }
8122     TraceInline(target, caller, "parse failure");
8123     return false;
8124   }
8125   if (target_shared->must_use_ignition_turbo()) {
8126     TraceInline(target, caller, "ParseAndAnalyze found incompatibility");
8127     return false;
8128   }
8129 
8130   if (target_info.scope()->NeedsContext()) {
8131     TraceInline(target, caller, "target has context-allocated variables");
8132     return false;
8133   }
8134 
8135   if (target_info.scope()->rest_parameter() != nullptr) {
8136     TraceInline(target, caller, "target uses rest parameters");
8137     return false;
8138   }
8139 
8140   FunctionLiteral* function = target_info.literal();
8141 
8142   // The following conditions must be checked again after re-parsing, because
8143   // earlier the information might not have been complete due to lazy parsing.
8144   nodes_added = function->ast_node_count();
8145   if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) {
8146     TraceInline(target, caller, "target AST is too large [late]");
8147     return false;
8148   }
8149   if (function->dont_optimize()) {
8150     TraceInline(target, caller, "target contains unsupported syntax [late]");
8151     return false;
8152   }
8153 
8154   // If the function uses the arguments object check that inlining of functions
8155   // with arguments object is enabled and the arguments-variable is
8156   // stack allocated.
8157   if (function->scope()->arguments() != NULL) {
8158     if (!FLAG_inline_arguments) {
8159       TraceInline(target, caller, "target uses arguments object");
8160       return false;
8161     }
8162   }
8163 
8164   // Unsupported variable references present.
8165   if (function->scope()->this_function_var() != nullptr ||
8166       function->scope()->new_target_var() != nullptr) {
8167     TraceInline(target, caller, "target uses new target or this function");
8168     return false;
8169   }
8170 
8171   // All declarations must be inlineable.
8172   Declaration::List* decls = target_info.scope()->declarations();
8173   for (Declaration* decl : *decls) {
8174     if (decl->IsFunctionDeclaration() ||
8175         !decl->proxy()->var()->IsStackAllocated()) {
8176       TraceInline(target, caller, "target has non-trivial declaration");
8177       return false;
8178     }
8179   }
8180 
8181   // Generate the deoptimization data for the unoptimized version of
8182   // the target function if we don't already have it.
8183   if (!Compiler::EnsureDeoptimizationSupport(&target_info)) {
8184     TraceInline(target, caller, "could not generate deoptimization info");
8185     return false;
8186   }
8187 
8188   // Remember that we inlined this function. This needs to be called right
8189   // after the EnsureDeoptimizationSupport call so that the code flusher
8190   // does not remove the code with the deoptimization support.
8191   int inlining_id = top_info()->AddInlinedFunction(target_info.shared_info(),
8192                                                    source_position());
8193 
8194   // ----------------------------------------------------------------
8195   // After this point, we've made a decision to inline this function (so
8196   // TryInline should always return true).
8197 
8198   // If target was lazily compiled, it's literals array may not yet be set up.
8199   JSFunction::EnsureLiterals(target);
8200 
8201   // Type-check the inlined function.
8202   DCHECK(target_shared->has_deoptimization_support());
8203   AstTyper(target_info.isolate(), target_info.zone(), target_info.closure(),
8204            target_info.scope(), target_info.osr_ast_id(), target_info.literal(),
8205            &bounds_)
8206       .Run();
8207 
8208   // Save the pending call context. Set up new one for the inlined function.
8209   // The function state is new-allocated because we need to delete it
8210   // in two different places.
8211   FunctionState* target_state = new FunctionState(
8212       this, &target_info, inlining_kind, inlining_id,
8213       function_state()->ComputeTailCallMode(syntactic_tail_call_mode));
8214 
8215   HConstant* undefined = graph()->GetConstantUndefined();
8216 
8217   HEnvironment* inner_env = environment()->CopyForInlining(
8218       target, arguments_count, function, undefined,
8219       function_state()->inlining_kind(), syntactic_tail_call_mode);
8220 
8221   HConstant* context = Add<HConstant>(Handle<Context>(target->context()));
8222   inner_env->BindContext(context);
8223 
8224   // Create a dematerialized arguments object for the function, also copy the
8225   // current arguments values to use them for materialization.
8226   HEnvironment* arguments_env = inner_env->arguments_environment();
8227   int parameter_count = arguments_env->parameter_count();
8228   HArgumentsObject* arguments_object = Add<HArgumentsObject>(parameter_count);
8229   for (int i = 0; i < parameter_count; i++) {
8230     arguments_object->AddArgument(arguments_env->Lookup(i), zone());
8231   }
8232 
8233   // If the function uses arguments object then bind bind one.
8234   if (function->scope()->arguments() != NULL) {
8235     DCHECK(function->scope()->arguments()->IsStackAllocated());
8236     inner_env->Bind(function->scope()->arguments(), arguments_object);
8237   }
8238 
8239   // Capture the state before invoking the inlined function for deopt in the
8240   // inlined function. This simulate has no bailout-id since it's not directly
8241   // reachable for deopt, and is only used to capture the state. If the simulate
8242   // becomes reachable by merging, the ast id of the simulate merged into it is
8243   // adopted.
8244   Add<HSimulate>(BailoutId::None());
8245 
8246   current_block()->UpdateEnvironment(inner_env);
8247   Scope* saved_scope = scope();
8248   set_scope(target_info.scope());
8249   HEnterInlined* enter_inlined = Add<HEnterInlined>(
8250       return_id, target, context, arguments_count, function,
8251       function_state()->inlining_kind(), function->scope()->arguments(),
8252       arguments_object, syntactic_tail_call_mode);
8253   if (is_tracking_positions()) {
8254     enter_inlined->set_inlining_id(inlining_id);
8255   }
8256 
8257   function_state()->set_entry(enter_inlined);
8258 
8259   VisitDeclarations(target_info.scope()->declarations());
8260   VisitStatements(function->body());
8261   set_scope(saved_scope);
8262   if (HasStackOverflow()) {
8263     // Bail out if the inline function did, as we cannot residualize a call
8264     // instead, but do not disable optimization for the outer function.
8265     TraceInline(target, caller, "inline graph construction failed");
8266     target_shared->DisableOptimization(kInliningBailedOut);
8267     current_info()->RetryOptimization(kInliningBailedOut);
8268     delete target_state;
8269     return true;
8270   }
8271 
8272   // Update inlined nodes count.
8273   inlined_count_ += nodes_added;
8274 
8275   Handle<Code> unoptimized_code(target_shared->code());
8276   DCHECK(unoptimized_code->kind() == Code::FUNCTION);
8277   Handle<TypeFeedbackInfo> type_info(
8278       TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info()));
8279   graph()->update_type_change_checksum(type_info->own_type_change_checksum());
8280 
8281   TraceInline(target, caller, NULL, syntactic_tail_call_mode);
8282 
8283   if (current_block() != NULL) {
8284     FunctionState* state = function_state();
8285     if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) {
8286       // Falling off the end of an inlined construct call. In a test context the
8287       // return value will always evaluate to true, in a value context the
8288       // return value is the newly allocated receiver.
8289       if (call_context()->IsTest()) {
8290         inlined_test_context()->ReturnValue(graph()->GetConstantTrue());
8291       } else if (call_context()->IsEffect()) {
8292         Goto(function_return(), state);
8293       } else {
8294         DCHECK(call_context()->IsValue());
8295         AddLeaveInlined(implicit_return_value, state);
8296       }
8297     } else if (state->inlining_kind() == SETTER_CALL_RETURN) {
8298       // Falling off the end of an inlined setter call. The returned value is
8299       // never used, the value of an assignment is always the value of the RHS
8300       // of the assignment.
8301       if (call_context()->IsTest()) {
8302         inlined_test_context()->ReturnValue(implicit_return_value);
8303       } else if (call_context()->IsEffect()) {
8304         Goto(function_return(), state);
8305       } else {
8306         DCHECK(call_context()->IsValue());
8307         AddLeaveInlined(implicit_return_value, state);
8308       }
8309     } else {
8310       // Falling off the end of a normal inlined function. This basically means
8311       // returning undefined.
8312       if (call_context()->IsTest()) {
8313         inlined_test_context()->ReturnValue(graph()->GetConstantFalse());
8314       } else if (call_context()->IsEffect()) {
8315         Goto(function_return(), state);
8316       } else {
8317         DCHECK(call_context()->IsValue());
8318         AddLeaveInlined(undefined, state);
8319       }
8320     }
8321   }
8322 
8323   // Fix up the function exits.
8324   if (inlined_test_context() != NULL) {
8325     HBasicBlock* if_true = inlined_test_context()->if_true();
8326     HBasicBlock* if_false = inlined_test_context()->if_false();
8327 
8328     HEnterInlined* entry = function_state()->entry();
8329 
8330     // Pop the return test context from the expression context stack.
8331     DCHECK(ast_context() == inlined_test_context());
8332     ClearInlinedTestContext();
8333     delete target_state;
8334 
8335     // Forward to the real test context.
8336     if (if_true->HasPredecessor()) {
8337       entry->RegisterReturnTarget(if_true, zone());
8338       if_true->SetJoinId(ast_id);
8339       HBasicBlock* true_target = TestContext::cast(ast_context())->if_true();
8340       Goto(if_true, true_target, function_state());
8341     }
8342     if (if_false->HasPredecessor()) {
8343       entry->RegisterReturnTarget(if_false, zone());
8344       if_false->SetJoinId(ast_id);
8345       HBasicBlock* false_target = TestContext::cast(ast_context())->if_false();
8346       Goto(if_false, false_target, function_state());
8347     }
8348     set_current_block(NULL);
8349     return true;
8350 
8351   } else if (function_return()->HasPredecessor()) {
8352     function_state()->entry()->RegisterReturnTarget(function_return(), zone());
8353     function_return()->SetJoinId(ast_id);
8354     set_current_block(function_return());
8355   } else {
8356     set_current_block(NULL);
8357   }
8358   delete target_state;
8359   return true;
8360 }
8361 
8362 
TryInlineCall(Call * expr)8363 bool HOptimizedGraphBuilder::TryInlineCall(Call* expr) {
8364   return TryInline(expr->target(), expr->arguments()->length(), NULL,
8365                    expr->id(), expr->ReturnId(), NORMAL_RETURN,
8366                    expr->tail_call_mode());
8367 }
8368 
8369 
TryInlineConstruct(CallNew * expr,HValue * implicit_return_value)8370 bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr,
8371                                                 HValue* implicit_return_value) {
8372   return TryInline(expr->target(), expr->arguments()->length(),
8373                    implicit_return_value, expr->id(), expr->ReturnId(),
8374                    CONSTRUCT_CALL_RETURN, TailCallMode::kDisallow);
8375 }
8376 
TryInlineGetter(Handle<Object> getter,Handle<Map> receiver_map,BailoutId ast_id,BailoutId return_id)8377 bool HOptimizedGraphBuilder::TryInlineGetter(Handle<Object> getter,
8378                                              Handle<Map> receiver_map,
8379                                              BailoutId ast_id,
8380                                              BailoutId return_id) {
8381   if (TryInlineApiGetter(getter, receiver_map, ast_id)) return true;
8382   if (getter->IsJSFunction()) {
8383     Handle<JSFunction> getter_function = Handle<JSFunction>::cast(getter);
8384     return TryInlineBuiltinGetterCall(getter_function, receiver_map, ast_id) ||
8385            TryInline(getter_function, 0, NULL, ast_id, return_id,
8386                      GETTER_CALL_RETURN, TailCallMode::kDisallow);
8387   }
8388   return false;
8389 }
8390 
TryInlineSetter(Handle<Object> setter,Handle<Map> receiver_map,BailoutId id,BailoutId assignment_id,HValue * implicit_return_value)8391 bool HOptimizedGraphBuilder::TryInlineSetter(Handle<Object> setter,
8392                                              Handle<Map> receiver_map,
8393                                              BailoutId id,
8394                                              BailoutId assignment_id,
8395                                              HValue* implicit_return_value) {
8396   if (TryInlineApiSetter(setter, receiver_map, id)) return true;
8397   return setter->IsJSFunction() &&
8398          TryInline(Handle<JSFunction>::cast(setter), 1, implicit_return_value,
8399                    id, assignment_id, SETTER_CALL_RETURN,
8400                    TailCallMode::kDisallow);
8401 }
8402 
8403 
TryInlineIndirectCall(Handle<JSFunction> function,Call * expr,int arguments_count)8404 bool HOptimizedGraphBuilder::TryInlineIndirectCall(Handle<JSFunction> function,
8405                                                    Call* expr,
8406                                                    int arguments_count) {
8407   return TryInline(function, arguments_count, NULL, expr->id(),
8408                    expr->ReturnId(), NORMAL_RETURN, expr->tail_call_mode());
8409 }
8410 
8411 
TryInlineBuiltinFunctionCall(Call * expr)8412 bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) {
8413   if (!expr->target()->shared()->HasBuiltinFunctionId()) return false;
8414   BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
8415   // We intentionally ignore expr->tail_call_mode() here because builtins
8416   // we inline here do not observe if they were tail called or not.
8417   switch (id) {
8418     case kMathCos:
8419     case kMathExp:
8420     case kMathRound:
8421     case kMathFround:
8422     case kMathFloor:
8423     case kMathAbs:
8424     case kMathSin:
8425     case kMathSqrt:
8426     case kMathLog:
8427     case kMathClz32:
8428       if (expr->arguments()->length() == 1) {
8429         HValue* argument = Pop();
8430         Drop(2);  // Receiver and function.
8431         HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id);
8432         ast_context()->ReturnInstruction(op, expr->id());
8433         return true;
8434       }
8435       break;
8436     case kMathImul:
8437       if (expr->arguments()->length() == 2) {
8438         HValue* right = Pop();
8439         HValue* left = Pop();
8440         Drop(2);  // Receiver and function.
8441         HInstruction* op =
8442             HMul::NewImul(isolate(), zone(), context(), left, right);
8443         ast_context()->ReturnInstruction(op, expr->id());
8444         return true;
8445       }
8446       break;
8447     default:
8448       // Not supported for inlining yet.
8449       break;
8450   }
8451   return false;
8452 }
8453 
8454 
8455 // static
IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map)8456 bool HOptimizedGraphBuilder::IsReadOnlyLengthDescriptor(
8457     Handle<Map> jsarray_map) {
8458   DCHECK(!jsarray_map->is_dictionary_map());
8459   Isolate* isolate = jsarray_map->GetIsolate();
8460   Handle<Name> length_string = isolate->factory()->length_string();
8461   DescriptorArray* descriptors = jsarray_map->instance_descriptors();
8462   int number =
8463       descriptors->SearchWithCache(isolate, *length_string, *jsarray_map);
8464   DCHECK_NE(DescriptorArray::kNotFound, number);
8465   return descriptors->GetDetails(number).IsReadOnly();
8466 }
8467 
8468 
8469 // static
CanInlineArrayResizeOperation(Handle<Map> receiver_map)8470 bool HOptimizedGraphBuilder::CanInlineArrayResizeOperation(
8471     Handle<Map> receiver_map) {
8472   return !receiver_map.is_null() && receiver_map->prototype()->IsJSObject() &&
8473          receiver_map->instance_type() == JS_ARRAY_TYPE &&
8474          IsFastElementsKind(receiver_map->elements_kind()) &&
8475          !receiver_map->is_dictionary_map() && receiver_map->is_extensible() &&
8476          (!receiver_map->is_prototype_map() || receiver_map->is_stable()) &&
8477          !IsReadOnlyLengthDescriptor(receiver_map);
8478 }
8479 
TryInlineBuiltinGetterCall(Handle<JSFunction> function,Handle<Map> receiver_map,BailoutId ast_id)8480 bool HOptimizedGraphBuilder::TryInlineBuiltinGetterCall(
8481     Handle<JSFunction> function, Handle<Map> receiver_map, BailoutId ast_id) {
8482   if (!function->shared()->HasBuiltinFunctionId()) return false;
8483   BuiltinFunctionId id = function->shared()->builtin_function_id();
8484 
8485   // Try to inline getter calls like DataView.prototype.byteLength/byteOffset
8486   // as operations in the calling function.
8487   switch (id) {
8488     case kDataViewBuffer: {
8489       if (!receiver_map->IsJSDataViewMap()) return false;
8490       HObjectAccess access = HObjectAccess::ForMapAndOffset(
8491           receiver_map, JSDataView::kBufferOffset);
8492       HValue* object = Pop();  // receiver
8493       HInstruction* result = New<HLoadNamedField>(object, object, access);
8494       ast_context()->ReturnInstruction(result, ast_id);
8495       return true;
8496     }
8497     case kDataViewByteLength:
8498     case kDataViewByteOffset: {
8499       if (!receiver_map->IsJSDataViewMap()) return false;
8500       int offset = (id == kDataViewByteLength) ? JSDataView::kByteLengthOffset
8501                                                : JSDataView::kByteOffsetOffset;
8502       HObjectAccess access =
8503           HObjectAccess::ForMapAndOffset(receiver_map, offset);
8504       HValue* object = Pop();  // receiver
8505       HValue* checked_object = Add<HCheckArrayBufferNotNeutered>(object);
8506       HInstruction* result =
8507           New<HLoadNamedField>(object, checked_object, access);
8508       ast_context()->ReturnInstruction(result, ast_id);
8509       return true;
8510     }
8511     case kTypedArrayByteLength:
8512     case kTypedArrayByteOffset:
8513     case kTypedArrayLength: {
8514       if (!receiver_map->IsJSTypedArrayMap()) return false;
8515       int offset = (id == kTypedArrayLength)
8516                        ? JSTypedArray::kLengthOffset
8517                        : (id == kTypedArrayByteLength)
8518                              ? JSTypedArray::kByteLengthOffset
8519                              : JSTypedArray::kByteOffsetOffset;
8520       HObjectAccess access =
8521           HObjectAccess::ForMapAndOffset(receiver_map, offset);
8522       HValue* object = Pop();  // receiver
8523       HValue* checked_object = Add<HCheckArrayBufferNotNeutered>(object);
8524       HInstruction* result =
8525           New<HLoadNamedField>(object, checked_object, access);
8526       ast_context()->ReturnInstruction(result, ast_id);
8527       return true;
8528     }
8529     default:
8530       return false;
8531   }
8532 }
8533 
8534 // static
NoElementsInPrototypeChain(Handle<Map> receiver_map)8535 bool HOptimizedGraphBuilder::NoElementsInPrototypeChain(
8536     Handle<Map> receiver_map) {
8537   // TODO(ishell): remove this once we support NO_ELEMENTS elements kind.
8538   PrototypeIterator iter(receiver_map);
8539   Handle<Object> empty_fixed_array =
8540       iter.isolate()->factory()->empty_fixed_array();
8541   while (true) {
8542     Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter);
8543     if (current->elements() != *empty_fixed_array) return false;
8544     iter.Advance();
8545     if (iter.IsAtEnd()) {
8546       return true;
8547     }
8548   }
8549 }
8550 
TryInlineBuiltinMethodCall(Handle<JSFunction> function,Handle<Map> receiver_map,BailoutId ast_id,int args_count_no_receiver)8551 bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
8552     Handle<JSFunction> function, Handle<Map> receiver_map, BailoutId ast_id,
8553     int args_count_no_receiver) {
8554   if (!function->shared()->HasBuiltinFunctionId()) return false;
8555   BuiltinFunctionId id = function->shared()->builtin_function_id();
8556   int argument_count = args_count_no_receiver + 1;  // Plus receiver.
8557 
8558   if (receiver_map.is_null()) {
8559     HValue* receiver = environment()->ExpressionStackAt(args_count_no_receiver);
8560     if (receiver->IsConstant() &&
8561         HConstant::cast(receiver)->handle(isolate())->IsHeapObject()) {
8562       receiver_map =
8563           handle(Handle<HeapObject>::cast(
8564                      HConstant::cast(receiver)->handle(isolate()))->map());
8565     }
8566   }
8567   // Try to inline calls like Math.* as operations in the calling function.
8568   switch (id) {
8569     case kObjectHasOwnProperty: {
8570       // It's not safe to look through the phi for elements if we're compiling
8571       // for osr.
8572       if (top_info()->is_osr()) return false;
8573       if (argument_count != 2) return false;
8574       HValue* key = Top();
8575       if (!key->IsLoadKeyed()) return false;
8576       HValue* elements = HLoadKeyed::cast(key)->elements();
8577       if (!elements->IsPhi() || elements->OperandCount() != 1) return false;
8578       if (!elements->OperandAt(0)->IsForInCacheArray()) return false;
8579       HForInCacheArray* cache = HForInCacheArray::cast(elements->OperandAt(0));
8580       HValue* receiver = environment()->ExpressionStackAt(1);
8581       if (!receiver->IsPhi() || receiver->OperandCount() != 1) return false;
8582       if (cache->enumerable() != receiver->OperandAt(0)) return false;
8583       Drop(3);  // key, receiver, function
8584       Add<HCheckMapValue>(receiver, cache->map());
8585       ast_context()->ReturnValue(graph()->GetConstantTrue());
8586       return true;
8587     }
8588     case kStringCharCodeAt:
8589     case kStringCharAt:
8590       if (argument_count == 2) {
8591         HValue* index = Pop();
8592         HValue* string = Pop();
8593         Drop(1);  // Function.
8594         HInstruction* char_code =
8595             BuildStringCharCodeAt(string, index);
8596         if (id == kStringCharCodeAt) {
8597           ast_context()->ReturnInstruction(char_code, ast_id);
8598           return true;
8599         }
8600         AddInstruction(char_code);
8601         HInstruction* result = NewUncasted<HStringCharFromCode>(char_code);
8602         ast_context()->ReturnInstruction(result, ast_id);
8603         return true;
8604       }
8605       break;
8606     case kStringFromCharCode:
8607       if (argument_count == 2) {
8608         HValue* argument = Pop();
8609         Drop(2);  // Receiver and function.
8610         argument = AddUncasted<HForceRepresentation>(
8611             argument, Representation::Integer32());
8612         argument->SetFlag(HValue::kTruncatingToInt32);
8613         HInstruction* result = NewUncasted<HStringCharFromCode>(argument);
8614         ast_context()->ReturnInstruction(result, ast_id);
8615         return true;
8616       }
8617       break;
8618     case kMathCos:
8619     case kMathExp:
8620     case kMathRound:
8621     case kMathFround:
8622     case kMathFloor:
8623     case kMathAbs:
8624     case kMathSin:
8625     case kMathSqrt:
8626     case kMathLog:
8627     case kMathClz32:
8628       if (argument_count == 2) {
8629         HValue* argument = Pop();
8630         Drop(2);  // Receiver and function.
8631         HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id);
8632         ast_context()->ReturnInstruction(op, ast_id);
8633         return true;
8634       }
8635       break;
8636     case kMathPow:
8637       if (argument_count == 3) {
8638         HValue* right = Pop();
8639         HValue* left = Pop();
8640         Drop(2);  // Receiver and function.
8641         HInstruction* result = NULL;
8642         // Use sqrt() if exponent is 0.5 or -0.5.
8643         if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) {
8644           double exponent = HConstant::cast(right)->DoubleValue();
8645           if (exponent == 0.5) {
8646             result = NewUncasted<HUnaryMathOperation>(left, kMathPowHalf);
8647           } else if (exponent == -0.5) {
8648             HValue* one = graph()->GetConstant1();
8649             HInstruction* sqrt = AddUncasted<HUnaryMathOperation>(
8650                 left, kMathPowHalf);
8651             // MathPowHalf doesn't have side effects so there's no need for
8652             // an environment simulation here.
8653             DCHECK(!sqrt->HasObservableSideEffects());
8654             result = NewUncasted<HDiv>(one, sqrt);
8655           } else if (exponent == 2.0) {
8656             result = NewUncasted<HMul>(left, left);
8657           }
8658         }
8659 
8660         if (result == NULL) {
8661           result = NewUncasted<HPower>(left, right);
8662         }
8663         ast_context()->ReturnInstruction(result, ast_id);
8664         return true;
8665       }
8666       break;
8667     case kMathMax:
8668     case kMathMin:
8669       if (argument_count == 3) {
8670         HValue* right = Pop();
8671         HValue* left = Pop();
8672         Drop(2);  // Receiver and function.
8673         HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin
8674                                                      : HMathMinMax::kMathMax;
8675         HInstruction* result = NewUncasted<HMathMinMax>(left, right, op);
8676         ast_context()->ReturnInstruction(result, ast_id);
8677         return true;
8678       }
8679       break;
8680     case kMathImul:
8681       if (argument_count == 3) {
8682         HValue* right = Pop();
8683         HValue* left = Pop();
8684         Drop(2);  // Receiver and function.
8685         HInstruction* result =
8686             HMul::NewImul(isolate(), zone(), context(), left, right);
8687         ast_context()->ReturnInstruction(result, ast_id);
8688         return true;
8689       }
8690       break;
8691     case kArrayPop: {
8692       if (!CanInlineArrayResizeOperation(receiver_map)) return false;
8693       ElementsKind elements_kind = receiver_map->elements_kind();
8694 
8695       Drop(args_count_no_receiver);
8696       HValue* result;
8697       HValue* reduced_length;
8698       HValue* receiver = Pop();
8699 
8700       HValue* checked_object = AddCheckMap(receiver, receiver_map);
8701       HValue* length =
8702           Add<HLoadNamedField>(checked_object, nullptr,
8703                                HObjectAccess::ForArrayLength(elements_kind));
8704 
8705       Drop(1);  // Function.
8706 
8707       { NoObservableSideEffectsScope scope(this);
8708         IfBuilder length_checker(this);
8709 
8710         HValue* bounds_check = length_checker.If<HCompareNumericAndBranch>(
8711             length, graph()->GetConstant0(), Token::EQ);
8712         length_checker.Then();
8713 
8714         if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined());
8715 
8716         length_checker.Else();
8717         HValue* elements = AddLoadElements(checked_object);
8718         // Ensure that we aren't popping from a copy-on-write array.
8719         if (IsFastSmiOrObjectElementsKind(elements_kind)) {
8720           elements = BuildCopyElementsOnWrite(checked_object, elements,
8721                                               elements_kind, length);
8722         }
8723         reduced_length = AddUncasted<HSub>(length, graph()->GetConstant1());
8724         result = AddElementAccess(elements, reduced_length, nullptr,
8725                                   bounds_check, nullptr, elements_kind, LOAD);
8726         HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind)
8727                            ? graph()->GetConstantHole()
8728                            : Add<HConstant>(HConstant::kHoleNaN);
8729         if (IsFastSmiOrObjectElementsKind(elements_kind)) {
8730           elements_kind = FAST_HOLEY_ELEMENTS;
8731         }
8732         AddElementAccess(elements, reduced_length, hole, bounds_check, nullptr,
8733                          elements_kind, STORE);
8734         Add<HStoreNamedField>(
8735             checked_object, HObjectAccess::ForArrayLength(elements_kind),
8736             reduced_length, STORE_TO_INITIALIZED_ENTRY);
8737 
8738         if (!ast_context()->IsEffect()) Push(result);
8739 
8740         length_checker.End();
8741       }
8742       result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top();
8743       Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
8744       if (!ast_context()->IsEffect()) Drop(1);
8745 
8746       ast_context()->ReturnValue(result);
8747       return true;
8748     }
8749     case kArrayPush: {
8750       if (!CanInlineArrayResizeOperation(receiver_map)) return false;
8751       ElementsKind elements_kind = receiver_map->elements_kind();
8752 
8753       // If there may be elements accessors in the prototype chain, the fast
8754       // inlined version can't be used.
8755       if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false;
8756       // If there currently can be no elements accessors on the prototype chain,
8757       // it doesn't mean that there won't be any later. Install a full prototype
8758       // chain check to trap element accessors being installed on the prototype
8759       // chain, which would cause elements to go to dictionary mode and result
8760       // in a map change.
8761       Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype()));
8762       BuildCheckPrototypeMaps(prototype, Handle<JSObject>());
8763 
8764       // Protect against adding elements to the Array prototype, which needs to
8765       // route through appropriate bottlenecks.
8766       if (isolate()->IsFastArrayConstructorPrototypeChainIntact() &&
8767           !prototype->IsJSArray()) {
8768         return false;
8769       }
8770 
8771       const int argc = args_count_no_receiver;
8772       if (argc != 1) return false;
8773 
8774       HValue* value_to_push = Pop();
8775       HValue* array = Pop();
8776       Drop(1);  // Drop function.
8777 
8778       HInstruction* new_size = NULL;
8779       HValue* length = NULL;
8780 
8781       {
8782         NoObservableSideEffectsScope scope(this);
8783 
8784         length = Add<HLoadNamedField>(
8785             array, nullptr, HObjectAccess::ForArrayLength(elements_kind));
8786 
8787         new_size = AddUncasted<HAdd>(length, graph()->GetConstant1());
8788 
8789         bool is_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
8790         HValue* checked_array = Add<HCheckMaps>(array, receiver_map);
8791         BuildUncheckedMonomorphicElementAccess(
8792             checked_array, length, value_to_push, is_array, elements_kind,
8793             STORE, NEVER_RETURN_HOLE, STORE_AND_GROW_NO_TRANSITION);
8794 
8795         if (!ast_context()->IsEffect()) Push(new_size);
8796         Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
8797         if (!ast_context()->IsEffect()) Drop(1);
8798       }
8799 
8800       ast_context()->ReturnValue(new_size);
8801       return true;
8802     }
8803     case kArrayShift: {
8804       if (!CanInlineArrayResizeOperation(receiver_map)) return false;
8805       if (!NoElementsInPrototypeChain(receiver_map)) return false;
8806       ElementsKind kind = receiver_map->elements_kind();
8807 
8808       // If there may be elements accessors in the prototype chain, the fast
8809       // inlined version can't be used.
8810       if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false;
8811 
8812       // If there currently can be no elements accessors on the prototype chain,
8813       // it doesn't mean that there won't be any later. Install a full prototype
8814       // chain check to trap element accessors being installed on the prototype
8815       // chain, which would cause elements to go to dictionary mode and result
8816       // in a map change.
8817       BuildCheckPrototypeMaps(
8818           handle(JSObject::cast(receiver_map->prototype()), isolate()),
8819           Handle<JSObject>::null(), true);
8820 
8821       // Threshold for fast inlined Array.shift().
8822       HConstant* inline_threshold = Add<HConstant>(static_cast<int32_t>(16));
8823 
8824       Drop(args_count_no_receiver);
8825       HValue* result;
8826       HValue* receiver = Pop();
8827       HValue* checked_object = AddCheckMap(receiver, receiver_map);
8828       HValue* length = Add<HLoadNamedField>(
8829           receiver, checked_object, HObjectAccess::ForArrayLength(kind));
8830 
8831       Drop(1);  // Function.
8832       {
8833         NoObservableSideEffectsScope scope(this);
8834 
8835         IfBuilder if_lengthiszero(this);
8836         HValue* lengthiszero = if_lengthiszero.If<HCompareNumericAndBranch>(
8837             length, graph()->GetConstant0(), Token::EQ);
8838         if_lengthiszero.Then();
8839         {
8840           if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined());
8841         }
8842         if_lengthiszero.Else();
8843         {
8844           HValue* elements = AddLoadElements(receiver);
8845 
8846           // Check if we can use the fast inlined Array.shift().
8847           IfBuilder if_inline(this);
8848           if_inline.If<HCompareNumericAndBranch>(
8849               length, inline_threshold, Token::LTE);
8850           if (IsFastSmiOrObjectElementsKind(kind)) {
8851             // We cannot handle copy-on-write backing stores here.
8852             if_inline.AndIf<HCompareMap>(
8853                 elements, isolate()->factory()->fixed_array_map());
8854           }
8855           if_inline.Then();
8856           {
8857             // Remember the result.
8858             if (!ast_context()->IsEffect()) {
8859               Push(AddElementAccess(elements, graph()->GetConstant0(), nullptr,
8860                                     lengthiszero, nullptr, kind, LOAD));
8861             }
8862 
8863             // Compute the new length.
8864             HValue* new_length = AddUncasted<HSub>(
8865                 length, graph()->GetConstant1());
8866             new_length->ClearFlag(HValue::kCanOverflow);
8867 
8868             // Copy the remaining elements.
8869             LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement);
8870             {
8871               HValue* new_key = loop.BeginBody(
8872                   graph()->GetConstant0(), new_length, Token::LT);
8873               HValue* key = AddUncasted<HAdd>(new_key, graph()->GetConstant1());
8874               key->ClearFlag(HValue::kCanOverflow);
8875               ElementsKind copy_kind =
8876                   kind == FAST_HOLEY_SMI_ELEMENTS ? FAST_HOLEY_ELEMENTS : kind;
8877               HValue* element =
8878                   AddUncasted<HLoadKeyed>(elements, key, lengthiszero, nullptr,
8879                                           copy_kind, ALLOW_RETURN_HOLE);
8880               HStoreKeyed* store = Add<HStoreKeyed>(elements, new_key, element,
8881                                                     nullptr, copy_kind);
8882               store->SetFlag(HValue::kTruncatingToNumber);
8883             }
8884             loop.EndBody();
8885 
8886             // Put a hole at the end.
8887             HValue* hole = IsFastSmiOrObjectElementsKind(kind)
8888                                ? graph()->GetConstantHole()
8889                                : Add<HConstant>(HConstant::kHoleNaN);
8890             if (IsFastSmiOrObjectElementsKind(kind)) kind = FAST_HOLEY_ELEMENTS;
8891             Add<HStoreKeyed>(elements, new_length, hole, nullptr, kind,
8892                              INITIALIZING_STORE);
8893 
8894             // Remember new length.
8895             Add<HStoreNamedField>(
8896                 receiver, HObjectAccess::ForArrayLength(kind),
8897                 new_length, STORE_TO_INITIALIZED_ENTRY);
8898           }
8899           if_inline.Else();
8900           {
8901             Add<HPushArguments>(receiver);
8902             result = AddInstruction(NewCallConstantFunction(
8903                 function, 1, TailCallMode::kDisallow, TailCallMode::kDisallow));
8904             if (!ast_context()->IsEffect()) Push(result);
8905           }
8906           if_inline.End();
8907         }
8908         if_lengthiszero.End();
8909       }
8910       result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top();
8911       Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
8912       if (!ast_context()->IsEffect()) Drop(1);
8913       ast_context()->ReturnValue(result);
8914       return true;
8915     }
8916     case kArrayIndexOf:
8917     case kArrayLastIndexOf: {
8918       if (receiver_map.is_null()) return false;
8919       if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false;
8920       if (!receiver_map->prototype()->IsJSObject()) return false;
8921       ElementsKind kind = receiver_map->elements_kind();
8922       if (!IsFastElementsKind(kind)) return false;
8923       if (argument_count != 2) return false;
8924       if (!receiver_map->is_extensible()) return false;
8925 
8926       // If there may be elements accessors in the prototype chain, the fast
8927       // inlined version can't be used.
8928       if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false;
8929 
8930       // If there currently can be no elements accessors on the prototype chain,
8931       // it doesn't mean that there won't be any later. Install a full prototype
8932       // chain check to trap element accessors being installed on the prototype
8933       // chain, which would cause elements to go to dictionary mode and result
8934       // in a map change.
8935       BuildCheckPrototypeMaps(
8936           handle(JSObject::cast(receiver_map->prototype()), isolate()),
8937           Handle<JSObject>::null());
8938 
8939       HValue* search_element = Pop();
8940       HValue* receiver = Pop();
8941       Drop(1);  // Drop function.
8942 
8943       ArrayIndexOfMode mode = (id == kArrayIndexOf)
8944           ? kFirstIndexOf : kLastIndexOf;
8945       HValue* index = BuildArrayIndexOf(receiver, search_element, kind, mode);
8946 
8947       if (!ast_context()->IsEffect()) Push(index);
8948       Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
8949       if (!ast_context()->IsEffect()) Drop(1);
8950       ast_context()->ReturnValue(index);
8951       return true;
8952     }
8953     default:
8954       // Not yet supported for inlining.
8955       break;
8956   }
8957   return false;
8958 }
8959 
8960 
TryInlineApiFunctionCall(Call * expr,HValue * receiver)8961 bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr,
8962                                                       HValue* receiver) {
8963   if (V8_UNLIKELY(FLAG_runtime_stats)) return false;
8964   Handle<JSFunction> function = expr->target();
8965   int argc = expr->arguments()->length();
8966   SmallMapList receiver_maps;
8967   return TryInlineApiCall(function, receiver, &receiver_maps, argc, expr->id(),
8968                           kCallApiFunction, expr->tail_call_mode());
8969 }
8970 
8971 
TryInlineApiMethodCall(Call * expr,HValue * receiver,SmallMapList * receiver_maps)8972 bool HOptimizedGraphBuilder::TryInlineApiMethodCall(
8973     Call* expr,
8974     HValue* receiver,
8975     SmallMapList* receiver_maps) {
8976   if (V8_UNLIKELY(FLAG_runtime_stats)) return false;
8977   Handle<JSFunction> function = expr->target();
8978   int argc = expr->arguments()->length();
8979   return TryInlineApiCall(function, receiver, receiver_maps, argc, expr->id(),
8980                           kCallApiMethod, expr->tail_call_mode());
8981 }
8982 
TryInlineApiGetter(Handle<Object> function,Handle<Map> receiver_map,BailoutId ast_id)8983 bool HOptimizedGraphBuilder::TryInlineApiGetter(Handle<Object> function,
8984                                                 Handle<Map> receiver_map,
8985                                                 BailoutId ast_id) {
8986   if (V8_UNLIKELY(FLAG_runtime_stats)) return false;
8987   SmallMapList receiver_maps(1, zone());
8988   receiver_maps.Add(receiver_map, zone());
8989   return TryInlineApiCall(function,
8990                           NULL,  // Receiver is on expression stack.
8991                           &receiver_maps, 0, ast_id, kCallApiGetter,
8992                           TailCallMode::kDisallow);
8993 }
8994 
TryInlineApiSetter(Handle<Object> function,Handle<Map> receiver_map,BailoutId ast_id)8995 bool HOptimizedGraphBuilder::TryInlineApiSetter(Handle<Object> function,
8996                                                 Handle<Map> receiver_map,
8997                                                 BailoutId ast_id) {
8998   SmallMapList receiver_maps(1, zone());
8999   receiver_maps.Add(receiver_map, zone());
9000   return TryInlineApiCall(function,
9001                           NULL,  // Receiver is on expression stack.
9002                           &receiver_maps, 1, ast_id, kCallApiSetter,
9003                           TailCallMode::kDisallow);
9004 }
9005 
TryInlineApiCall(Handle<Object> function,HValue * receiver,SmallMapList * receiver_maps,int argc,BailoutId ast_id,ApiCallType call_type,TailCallMode syntactic_tail_call_mode)9006 bool HOptimizedGraphBuilder::TryInlineApiCall(
9007     Handle<Object> function, HValue* receiver, SmallMapList* receiver_maps,
9008     int argc, BailoutId ast_id, ApiCallType call_type,
9009     TailCallMode syntactic_tail_call_mode) {
9010   if (V8_UNLIKELY(FLAG_runtime_stats)) return false;
9011   if (function->IsJSFunction() &&
9012       Handle<JSFunction>::cast(function)->context()->native_context() !=
9013           top_info()->closure()->context()->native_context()) {
9014     return false;
9015   }
9016   if (argc > CallApiCallbackStub::kArgMax) {
9017     return false;
9018   }
9019 
9020   CallOptimization optimization(function);
9021   if (!optimization.is_simple_api_call()) return false;
9022   Handle<Map> holder_map;
9023   for (int i = 0; i < receiver_maps->length(); ++i) {
9024     auto map = receiver_maps->at(i);
9025     // Don't inline calls to receivers requiring accesschecks.
9026     if (map->is_access_check_needed()) return false;
9027   }
9028   if (call_type == kCallApiFunction) {
9029     // Cannot embed a direct reference to the global proxy map
9030     // as it maybe dropped on deserialization.
9031     CHECK(!isolate()->serializer_enabled());
9032     DCHECK(function->IsJSFunction());
9033     DCHECK_EQ(0, receiver_maps->length());
9034     receiver_maps->Add(
9035         handle(Handle<JSFunction>::cast(function)->global_proxy()->map()),
9036         zone());
9037   }
9038   CallOptimization::HolderLookup holder_lookup =
9039       CallOptimization::kHolderNotFound;
9040   Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType(
9041       receiver_maps->first(), &holder_lookup);
9042   if (holder_lookup == CallOptimization::kHolderNotFound) return false;
9043 
9044   if (FLAG_trace_inlining) {
9045     PrintF("Inlining api function ");
9046     function->ShortPrint();
9047     PrintF("\n");
9048   }
9049 
9050   bool is_function = false;
9051   bool is_store = false;
9052   switch (call_type) {
9053     case kCallApiFunction:
9054     case kCallApiMethod:
9055       // Need to check that none of the receiver maps could have changed.
9056       Add<HCheckMaps>(receiver, receiver_maps);
9057       // Need to ensure the chain between receiver and api_holder is intact.
9058       if (holder_lookup == CallOptimization::kHolderFound) {
9059         AddCheckPrototypeMaps(api_holder, receiver_maps->first());
9060       } else {
9061         DCHECK_EQ(holder_lookup, CallOptimization::kHolderIsReceiver);
9062       }
9063       // Includes receiver.
9064       PushArgumentsFromEnvironment(argc + 1);
9065       is_function = true;
9066       break;
9067     case kCallApiGetter:
9068       // Receiver and prototype chain cannot have changed.
9069       DCHECK_EQ(0, argc);
9070       DCHECK_NULL(receiver);
9071       // Receiver is on expression stack.
9072       receiver = Pop();
9073       Add<HPushArguments>(receiver);
9074       break;
9075     case kCallApiSetter:
9076       {
9077         is_store = true;
9078         // Receiver and prototype chain cannot have changed.
9079         DCHECK_EQ(1, argc);
9080         DCHECK_NULL(receiver);
9081         // Receiver and value are on expression stack.
9082         HValue* value = Pop();
9083         receiver = Pop();
9084         Add<HPushArguments>(receiver, value);
9085         break;
9086      }
9087   }
9088 
9089   HValue* holder = NULL;
9090   switch (holder_lookup) {
9091     case CallOptimization::kHolderFound:
9092       holder = Add<HConstant>(api_holder);
9093       break;
9094     case CallOptimization::kHolderIsReceiver:
9095       holder = receiver;
9096       break;
9097     case CallOptimization::kHolderNotFound:
9098       UNREACHABLE();
9099       break;
9100   }
9101   Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
9102   Handle<Object> call_data_obj(api_call_info->data(), isolate());
9103   bool call_data_undefined = call_data_obj->IsUndefined(isolate());
9104   HValue* call_data = Add<HConstant>(call_data_obj);
9105   ApiFunction fun(v8::ToCData<Address>(api_call_info->callback()));
9106   ExternalReference ref = ExternalReference(&fun,
9107                                             ExternalReference::DIRECT_API_CALL,
9108                                             isolate());
9109   HValue* api_function_address = Add<HConstant>(ExternalReference(ref));
9110 
9111   HValue* op_vals[] = {Add<HConstant>(function), call_data, holder,
9112                        api_function_address};
9113 
9114   HInstruction* call = nullptr;
9115   CHECK(argc <= CallApiCallbackStub::kArgMax);
9116   if (!is_function) {
9117     CallApiCallbackStub stub(isolate(), is_store, call_data_undefined,
9118                              !optimization.is_constant_call());
9119     Handle<Code> code = stub.GetCode();
9120     HConstant* code_value = Add<HConstant>(code);
9121     call = New<HCallWithDescriptor>(
9122         code_value, argc + 1, stub.GetCallInterfaceDescriptor(),
9123         Vector<HValue*>(op_vals, arraysize(op_vals)), syntactic_tail_call_mode);
9124   } else {
9125     CallApiCallbackStub stub(isolate(), argc, call_data_undefined, false);
9126     Handle<Code> code = stub.GetCode();
9127     HConstant* code_value = Add<HConstant>(code);
9128     call = New<HCallWithDescriptor>(
9129         code_value, argc + 1, stub.GetCallInterfaceDescriptor(),
9130         Vector<HValue*>(op_vals, arraysize(op_vals)), syntactic_tail_call_mode);
9131     Drop(1);  // Drop function.
9132   }
9133 
9134   ast_context()->ReturnInstruction(call, ast_id);
9135   return true;
9136 }
9137 
9138 
HandleIndirectCall(Call * expr,HValue * function,int arguments_count)9139 void HOptimizedGraphBuilder::HandleIndirectCall(Call* expr, HValue* function,
9140                                                 int arguments_count) {
9141   Handle<JSFunction> known_function;
9142   int args_count_no_receiver = arguments_count - 1;
9143   if (function->IsConstant() &&
9144       HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
9145     known_function =
9146         Handle<JSFunction>::cast(HConstant::cast(function)->handle(isolate()));
9147     if (TryInlineBuiltinMethodCall(known_function, Handle<Map>(), expr->id(),
9148                                    args_count_no_receiver)) {
9149       if (FLAG_trace_inlining) {
9150         PrintF("Inlining builtin ");
9151         known_function->ShortPrint();
9152         PrintF("\n");
9153       }
9154       return;
9155     }
9156 
9157     if (TryInlineIndirectCall(known_function, expr, args_count_no_receiver)) {
9158       return;
9159     }
9160   }
9161 
9162   TailCallMode syntactic_tail_call_mode = expr->tail_call_mode();
9163   TailCallMode tail_call_mode =
9164       function_state()->ComputeTailCallMode(syntactic_tail_call_mode);
9165 
9166   PushArgumentsFromEnvironment(arguments_count);
9167   HInvokeFunction* call =
9168       New<HInvokeFunction>(function, known_function, arguments_count,
9169                            syntactic_tail_call_mode, tail_call_mode);
9170   Drop(1);  // Function
9171   ast_context()->ReturnInstruction(call, expr->id());
9172 }
9173 
9174 
TryIndirectCall(Call * expr)9175 bool HOptimizedGraphBuilder::TryIndirectCall(Call* expr) {
9176   DCHECK(expr->expression()->IsProperty());
9177 
9178   if (!expr->IsMonomorphic()) {
9179     return false;
9180   }
9181   Handle<Map> function_map = expr->GetReceiverTypes()->first();
9182   if (function_map->instance_type() != JS_FUNCTION_TYPE ||
9183       !expr->target()->shared()->HasBuiltinFunctionId()) {
9184     return false;
9185   }
9186 
9187   switch (expr->target()->shared()->builtin_function_id()) {
9188     case kFunctionCall: {
9189       if (expr->arguments()->length() == 0) return false;
9190       BuildFunctionCall(expr);
9191       return true;
9192     }
9193     case kFunctionApply: {
9194       // For .apply, only the pattern f.apply(receiver, arguments)
9195       // is supported.
9196       if (!CanBeFunctionApplyArguments(expr)) return false;
9197 
9198       BuildFunctionApply(expr);
9199       return true;
9200     }
9201     default: { return false; }
9202   }
9203   UNREACHABLE();
9204 }
9205 
9206 
9207 // f.apply(...)
BuildFunctionApply(Call * expr)9208 void HOptimizedGraphBuilder::BuildFunctionApply(Call* expr) {
9209   ZoneList<Expression*>* args = expr->arguments();
9210   CHECK_ALIVE(VisitForValue(args->at(0)));
9211   HValue* receiver = Pop();  // receiver
9212   HValue* function = Pop();  // f
9213   Drop(1);  // apply
9214 
9215   // Make sure the arguments object is live.
9216   VariableProxy* arg_two = args->at(1)->AsVariableProxy();
9217   LookupAndMakeLive(arg_two->var());
9218 
9219   Handle<Map> function_map = expr->GetReceiverTypes()->first();
9220   HValue* checked_function = AddCheckMap(function, function_map);
9221 
9222   if (function_state()->outer() == NULL) {
9223     TailCallMode syntactic_tail_call_mode = expr->tail_call_mode();
9224     TailCallMode tail_call_mode =
9225         function_state()->ComputeTailCallMode(syntactic_tail_call_mode);
9226 
9227     HInstruction* elements = Add<HArgumentsElements>(false);
9228     HInstruction* length = Add<HArgumentsLength>(elements);
9229     HValue* wrapped_receiver = BuildWrapReceiver(receiver, checked_function);
9230     HInstruction* result = New<HApplyArguments>(
9231         function, wrapped_receiver, length, elements, tail_call_mode);
9232     ast_context()->ReturnInstruction(result, expr->id());
9233   } else {
9234     // We are inside inlined function and we know exactly what is inside
9235     // arguments object. But we need to be able to materialize at deopt.
9236     DCHECK_EQ(environment()->arguments_environment()->parameter_count(),
9237               function_state()->entry()->arguments_object()->arguments_count());
9238     HArgumentsObject* args = function_state()->entry()->arguments_object();
9239     const ZoneList<HValue*>* arguments_values = args->arguments_values();
9240     int arguments_count = arguments_values->length();
9241     Push(function);
9242     Push(BuildWrapReceiver(receiver, checked_function));
9243     for (int i = 1; i < arguments_count; i++) {
9244       Push(arguments_values->at(i));
9245     }
9246     HandleIndirectCall(expr, function, arguments_count);
9247   }
9248 }
9249 
9250 
9251 // f.call(...)
BuildFunctionCall(Call * expr)9252 void HOptimizedGraphBuilder::BuildFunctionCall(Call* expr) {
9253   HValue* function = Top();  // f
9254   Handle<Map> function_map = expr->GetReceiverTypes()->first();
9255   HValue* checked_function = AddCheckMap(function, function_map);
9256 
9257   // f and call are on the stack in the unoptimized code
9258   // during evaluation of the arguments.
9259   CHECK_ALIVE(VisitExpressions(expr->arguments()));
9260 
9261   int args_length = expr->arguments()->length();
9262   int receiver_index = args_length - 1;
9263   // Patch the receiver.
9264   HValue* receiver = BuildWrapReceiver(
9265       environment()->ExpressionStackAt(receiver_index), checked_function);
9266   environment()->SetExpressionStackAt(receiver_index, receiver);
9267 
9268   // Call must not be on the stack from now on.
9269   int call_index = args_length + 1;
9270   environment()->RemoveExpressionStackAt(call_index);
9271 
9272   HandleIndirectCall(expr, function, args_length);
9273 }
9274 
9275 
ImplicitReceiverFor(HValue * function,Handle<JSFunction> target)9276 HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function,
9277                                                     Handle<JSFunction> target) {
9278   SharedFunctionInfo* shared = target->shared();
9279   if (is_sloppy(shared->language_mode()) && !shared->native()) {
9280     // Cannot embed a direct reference to the global proxy
9281     // as is it dropped on deserialization.
9282     CHECK(!isolate()->serializer_enabled());
9283     Handle<JSObject> global_proxy(target->context()->global_proxy());
9284     return Add<HConstant>(global_proxy);
9285   }
9286   return graph()->GetConstantUndefined();
9287 }
9288 
9289 
BuildArrayIndexOf(HValue * receiver,HValue * search_element,ElementsKind kind,ArrayIndexOfMode mode)9290 HValue* HOptimizedGraphBuilder::BuildArrayIndexOf(HValue* receiver,
9291                                                   HValue* search_element,
9292                                                   ElementsKind kind,
9293                                                   ArrayIndexOfMode mode) {
9294   DCHECK(IsFastElementsKind(kind));
9295 
9296   NoObservableSideEffectsScope no_effects(this);
9297 
9298   HValue* elements = AddLoadElements(receiver);
9299   HValue* length = AddLoadArrayLength(receiver, kind);
9300 
9301   HValue* initial;
9302   HValue* terminating;
9303   Token::Value token;
9304   LoopBuilder::Direction direction;
9305   if (mode == kFirstIndexOf) {
9306     initial = graph()->GetConstant0();
9307     terminating = length;
9308     token = Token::LT;
9309     direction = LoopBuilder::kPostIncrement;
9310   } else {
9311     DCHECK_EQ(kLastIndexOf, mode);
9312     initial = length;
9313     terminating = graph()->GetConstant0();
9314     token = Token::GT;
9315     direction = LoopBuilder::kPreDecrement;
9316   }
9317 
9318   Push(graph()->GetConstantMinus1());
9319   if (IsFastDoubleElementsKind(kind) || IsFastSmiElementsKind(kind)) {
9320     // Make sure that we can actually compare numbers correctly below, see
9321     // https://code.google.com/p/chromium/issues/detail?id=407946 for details.
9322     search_element = AddUncasted<HForceRepresentation>(
9323         search_element, IsFastSmiElementsKind(kind) ? Representation::Smi()
9324                                                     : Representation::Double());
9325 
9326     LoopBuilder loop(this, context(), direction);
9327     {
9328       HValue* index = loop.BeginBody(initial, terminating, token);
9329       HValue* element = AddUncasted<HLoadKeyed>(
9330           elements, index, nullptr, nullptr, kind, ALLOW_RETURN_HOLE);
9331       IfBuilder if_issame(this);
9332       if_issame.If<HCompareNumericAndBranch>(element, search_element,
9333                                              Token::EQ_STRICT);
9334       if_issame.Then();
9335       {
9336         Drop(1);
9337         Push(index);
9338         loop.Break();
9339       }
9340       if_issame.End();
9341     }
9342     loop.EndBody();
9343   } else {
9344     IfBuilder if_isstring(this);
9345     if_isstring.If<HIsStringAndBranch>(search_element);
9346     if_isstring.Then();
9347     {
9348       LoopBuilder loop(this, context(), direction);
9349       {
9350         HValue* index = loop.BeginBody(initial, terminating, token);
9351         HValue* element = AddUncasted<HLoadKeyed>(
9352             elements, index, nullptr, nullptr, kind, ALLOW_RETURN_HOLE);
9353         IfBuilder if_issame(this);
9354         if_issame.If<HIsStringAndBranch>(element);
9355         if_issame.AndIf<HStringCompareAndBranch>(
9356             element, search_element, Token::EQ_STRICT);
9357         if_issame.Then();
9358         {
9359           Drop(1);
9360           Push(index);
9361           loop.Break();
9362         }
9363         if_issame.End();
9364       }
9365       loop.EndBody();
9366     }
9367     if_isstring.Else();
9368     {
9369       IfBuilder if_isnumber(this);
9370       if_isnumber.If<HIsSmiAndBranch>(search_element);
9371       if_isnumber.OrIf<HCompareMap>(
9372           search_element, isolate()->factory()->heap_number_map());
9373       if_isnumber.Then();
9374       {
9375         HValue* search_number =
9376             AddUncasted<HForceRepresentation>(search_element,
9377                                               Representation::Double());
9378         LoopBuilder loop(this, context(), direction);
9379         {
9380           HValue* index = loop.BeginBody(initial, terminating, token);
9381           HValue* element = AddUncasted<HLoadKeyed>(
9382               elements, index, nullptr, nullptr, kind, ALLOW_RETURN_HOLE);
9383 
9384           IfBuilder if_element_isnumber(this);
9385           if_element_isnumber.If<HIsSmiAndBranch>(element);
9386           if_element_isnumber.OrIf<HCompareMap>(
9387               element, isolate()->factory()->heap_number_map());
9388           if_element_isnumber.Then();
9389           {
9390             HValue* number =
9391                 AddUncasted<HForceRepresentation>(element,
9392                                                   Representation::Double());
9393             IfBuilder if_issame(this);
9394             if_issame.If<HCompareNumericAndBranch>(
9395                 number, search_number, Token::EQ_STRICT);
9396             if_issame.Then();
9397             {
9398               Drop(1);
9399               Push(index);
9400               loop.Break();
9401             }
9402             if_issame.End();
9403           }
9404           if_element_isnumber.End();
9405         }
9406         loop.EndBody();
9407       }
9408       if_isnumber.Else();
9409       {
9410         LoopBuilder loop(this, context(), direction);
9411         {
9412           HValue* index = loop.BeginBody(initial, terminating, token);
9413           HValue* element = AddUncasted<HLoadKeyed>(
9414               elements, index, nullptr, nullptr, kind, ALLOW_RETURN_HOLE);
9415           IfBuilder if_issame(this);
9416           if_issame.If<HCompareObjectEqAndBranch>(
9417               element, search_element);
9418           if_issame.Then();
9419           {
9420             Drop(1);
9421             Push(index);
9422             loop.Break();
9423           }
9424           if_issame.End();
9425         }
9426         loop.EndBody();
9427       }
9428       if_isnumber.End();
9429     }
9430     if_isstring.End();
9431   }
9432 
9433   return Pop();
9434 }
9435 
9436 template <class T>
TryHandleArrayCall(T * expr,HValue * function)9437 bool HOptimizedGraphBuilder::TryHandleArrayCall(T* expr, HValue* function) {
9438   if (!array_function().is_identical_to(expr->target())) {
9439     return false;
9440   }
9441 
9442   Handle<AllocationSite> site = expr->allocation_site();
9443   if (site.is_null()) return false;
9444 
9445   Add<HCheckValue>(function, array_function());
9446 
9447   int arguments_count = expr->arguments()->length();
9448   if (TryInlineArrayCall(expr, arguments_count, site)) return true;
9449 
9450   HInstruction* call = PreProcessCall(New<HCallNewArray>(
9451       function, arguments_count + 1, site->GetElementsKind(), site));
9452   if (expr->IsCall()) Drop(1);
9453   ast_context()->ReturnInstruction(call, expr->id());
9454 
9455   return true;
9456 }
9457 
9458 
CanBeFunctionApplyArguments(Call * expr)9459 bool HOptimizedGraphBuilder::CanBeFunctionApplyArguments(Call* expr) {
9460   ZoneList<Expression*>* args = expr->arguments();
9461   if (args->length() != 2) return false;
9462   VariableProxy* arg_two = args->at(1)->AsVariableProxy();
9463   if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
9464   HValue* arg_two_value = environment()->Lookup(arg_two->var());
9465   if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
9466   DCHECK_NOT_NULL(current_info()->scope()->arguments());
9467   return true;
9468 }
9469 
9470 
VisitCall(Call * expr)9471 void HOptimizedGraphBuilder::VisitCall(Call* expr) {
9472   DCHECK(!HasStackOverflow());
9473   DCHECK(current_block() != NULL);
9474   DCHECK(current_block()->HasPredecessor());
9475   if (!is_tracking_positions()) SetSourcePosition(expr->position());
9476   Expression* callee = expr->expression();
9477   int argument_count = expr->arguments()->length() + 1;  // Plus receiver.
9478   HInstruction* call = NULL;
9479 
9480   TailCallMode syntactic_tail_call_mode = expr->tail_call_mode();
9481   TailCallMode tail_call_mode =
9482       function_state()->ComputeTailCallMode(syntactic_tail_call_mode);
9483 
9484   Property* prop = callee->AsProperty();
9485   if (prop != NULL) {
9486     CHECK_ALIVE(VisitForValue(prop->obj()));
9487     HValue* receiver = Top();
9488 
9489     SmallMapList* maps;
9490     ComputeReceiverTypes(expr, receiver, &maps, this);
9491 
9492     if (prop->key()->IsPropertyName() && maps->length() > 0) {
9493       Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
9494       PropertyAccessInfo info(this, LOAD, maps->first(), name);
9495       if (!info.CanAccessAsMonomorphic(maps)) {
9496         HandlePolymorphicCallNamed(expr, receiver, maps, name);
9497         return;
9498       }
9499     }
9500     HValue* key = NULL;
9501     if (!prop->key()->IsPropertyName()) {
9502       CHECK_ALIVE(VisitForValue(prop->key()));
9503       key = Pop();
9504     }
9505 
9506     CHECK_ALIVE(PushLoad(prop, receiver, key));
9507     HValue* function = Pop();
9508 
9509     if (function->IsConstant() &&
9510         HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
9511       // Push the function under the receiver.
9512       environment()->SetExpressionStackAt(0, function);
9513       Push(receiver);
9514 
9515       Handle<JSFunction> known_function = Handle<JSFunction>::cast(
9516           HConstant::cast(function)->handle(isolate()));
9517       expr->set_target(known_function);
9518 
9519       if (TryIndirectCall(expr)) return;
9520       CHECK_ALIVE(VisitExpressions(expr->arguments()));
9521 
9522       Handle<Map> map = maps->length() == 1 ? maps->first() : Handle<Map>();
9523       if (TryInlineBuiltinMethodCall(known_function, map, expr->id(),
9524                                      expr->arguments()->length())) {
9525         if (FLAG_trace_inlining) {
9526           PrintF("Inlining builtin ");
9527           known_function->ShortPrint();
9528           PrintF("\n");
9529         }
9530         return;
9531       }
9532       if (TryInlineApiMethodCall(expr, receiver, maps)) return;
9533 
9534       // Wrap the receiver if necessary.
9535       if (NeedsWrapping(maps->first(), known_function)) {
9536         // Since HWrapReceiver currently cannot actually wrap numbers and
9537         // strings, use the regular call builtin for method calls to wrap
9538         // the receiver.
9539         // TODO(verwaest): Support creation of value wrappers directly in
9540         // HWrapReceiver.
9541         call = NewCallFunction(
9542             function, argument_count, syntactic_tail_call_mode,
9543             ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode);
9544       } else if (TryInlineCall(expr)) {
9545         return;
9546       } else {
9547         call =
9548             NewCallConstantFunction(known_function, argument_count,
9549                                     syntactic_tail_call_mode, tail_call_mode);
9550       }
9551 
9552     } else {
9553       ArgumentsAllowedFlag arguments_flag = ARGUMENTS_NOT_ALLOWED;
9554       if (CanBeFunctionApplyArguments(expr) && expr->is_uninitialized()) {
9555         // We have to use EAGER deoptimization here because Deoptimizer::SOFT
9556         // gets ignored by the always-opt flag, which leads to incorrect code.
9557         Add<HDeoptimize>(
9558             DeoptimizeReason::kInsufficientTypeFeedbackForCallWithArguments,
9559             Deoptimizer::EAGER);
9560         arguments_flag = ARGUMENTS_FAKED;
9561       }
9562 
9563       // Push the function under the receiver.
9564       environment()->SetExpressionStackAt(0, function);
9565       Push(receiver);
9566 
9567       CHECK_ALIVE(VisitExpressions(expr->arguments(), arguments_flag));
9568       call = NewCallFunction(function, argument_count, syntactic_tail_call_mode,
9569                              ConvertReceiverMode::kNotNullOrUndefined,
9570                              tail_call_mode);
9571     }
9572     PushArgumentsFromEnvironment(argument_count);
9573 
9574   } else {
9575     if (expr->is_possibly_eval()) {
9576       return Bailout(kPossibleDirectCallToEval);
9577     }
9578 
9579     // The function is on the stack in the unoptimized code during
9580     // evaluation of the arguments.
9581     CHECK_ALIVE(VisitForValue(expr->expression()));
9582     HValue* function = Top();
9583     if (function->IsConstant() &&
9584         HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
9585       Handle<Object> constant = HConstant::cast(function)->handle(isolate());
9586       Handle<JSFunction> target = Handle<JSFunction>::cast(constant);
9587       expr->SetKnownGlobalTarget(target);
9588     }
9589 
9590     // Placeholder for the receiver.
9591     Push(graph()->GetConstantUndefined());
9592     CHECK_ALIVE(VisitExpressions(expr->arguments()));
9593 
9594     if (expr->IsMonomorphic() &&
9595         !IsClassConstructor(expr->target()->shared()->kind())) {
9596       Add<HCheckValue>(function, expr->target());
9597 
9598       // Patch the global object on the stack by the expected receiver.
9599       HValue* receiver = ImplicitReceiverFor(function, expr->target());
9600       const int receiver_index = argument_count - 1;
9601       environment()->SetExpressionStackAt(receiver_index, receiver);
9602 
9603       if (TryInlineBuiltinFunctionCall(expr)) {
9604         if (FLAG_trace_inlining) {
9605           PrintF("Inlining builtin ");
9606           expr->target()->ShortPrint();
9607           PrintF("\n");
9608         }
9609         return;
9610       }
9611       if (TryInlineApiFunctionCall(expr, receiver)) return;
9612       if (TryHandleArrayCall(expr, function)) return;
9613       if (TryInlineCall(expr)) return;
9614 
9615       PushArgumentsFromEnvironment(argument_count);
9616       call = NewCallConstantFunction(expr->target(), argument_count,
9617                                      syntactic_tail_call_mode, tail_call_mode);
9618     } else {
9619       PushArgumentsFromEnvironment(argument_count);
9620       if (expr->is_uninitialized()) {
9621         // We've never seen this call before, so let's have Crankshaft learn
9622         // through the type vector.
9623         call = NewCallFunctionViaIC(function, argument_count,
9624                                     syntactic_tail_call_mode,
9625                                     ConvertReceiverMode::kNullOrUndefined,
9626                                     tail_call_mode, expr->CallFeedbackICSlot());
9627       } else {
9628         call = NewCallFunction(
9629             function, argument_count, syntactic_tail_call_mode,
9630             ConvertReceiverMode::kNullOrUndefined, tail_call_mode);
9631       }
9632     }
9633   }
9634 
9635   Drop(1);  // Drop the function.
9636   return ast_context()->ReturnInstruction(call, expr->id());
9637 }
9638 
TryInlineArrayCall(Expression * expression,int argument_count,Handle<AllocationSite> site)9639 bool HOptimizedGraphBuilder::TryInlineArrayCall(Expression* expression,
9640                                                 int argument_count,
9641                                                 Handle<AllocationSite> site) {
9642   Handle<JSFunction> caller = current_info()->closure();
9643   Handle<JSFunction> target = array_function();
9644 
9645   if (!site->CanInlineCall()) {
9646     TraceInline(target, caller, "AllocationSite requested no inlining.");
9647     return false;
9648   }
9649 
9650   if (argument_count > 1) {
9651     TraceInline(target, caller, "Too many arguments to inline.");
9652     return false;
9653   }
9654 
9655   int array_length = 0;
9656   // Do not inline if the constant length argument is not a smi or outside the
9657   // valid range for unrolled loop initialization.
9658   if (argument_count == 1) {
9659     HValue* argument = Top();
9660     if (!argument->IsConstant()) {
9661       TraceInline(target, caller,
9662                   "Dont inline [new] Array(n) where n isn't constant.");
9663       return false;
9664     }
9665 
9666     HConstant* constant_argument = HConstant::cast(argument);
9667     if (!constant_argument->HasSmiValue()) {
9668       TraceInline(target, caller,
9669                   "Constant length outside of valid inlining range.");
9670       return false;
9671     }
9672     array_length = constant_argument->Integer32Value();
9673     if (array_length < 0 || array_length > kElementLoopUnrollThreshold) {
9674       TraceInline(target, caller,
9675                   "Constant length outside of valid inlining range.");
9676       return false;
9677     }
9678   }
9679 
9680   TraceInline(target, caller, NULL);
9681 
9682   NoObservableSideEffectsScope no_effects(this);
9683 
9684   // Register on the site for deoptimization if the transition feedback changes.
9685   top_info()->dependencies()->AssumeTransitionStable(site);
9686 
9687   // Build the array.
9688   ElementsKind kind = site->GetElementsKind();
9689   HValue* capacity;
9690   HValue* length;
9691   if (array_length == 0) {
9692     STATIC_ASSERT(0 < JSArray::kPreallocatedArrayElements);
9693     const int initial_capacity = JSArray::kPreallocatedArrayElements;
9694     capacity = Add<HConstant>(initial_capacity);
9695     length = graph()->GetConstant0();
9696   } else {
9697     length = Top();
9698     capacity = length;
9699     kind = GetHoleyElementsKind(kind);
9700   }
9701 
9702   // These HForceRepresentations are because we store these as fields in the
9703   // objects we construct, and an int32-to-smi HChange could deopt. Accept
9704   // the deopt possibility now, before allocation occurs.
9705   length = AddUncasted<HForceRepresentation>(length, Representation::Smi());
9706   capacity = AddUncasted<HForceRepresentation>(capacity, Representation::Smi());
9707 
9708   // Generate size calculation code here in order to make it dominate
9709   // the JSArray allocation.
9710   HValue* elements_size = BuildCalculateElementsSize(kind, capacity);
9711 
9712   // Bail out for large objects.
9713   HValue* max_size = Add<HConstant>(kMaxRegularHeapObjectSize);
9714   Add<HBoundsCheck>(elements_size, max_size);
9715 
9716   // Allocate (dealing with failure appropriately).
9717   AllocationSiteMode mode = DONT_TRACK_ALLOCATION_SITE;
9718   HAllocate* new_object = AllocateJSArrayObject(mode);
9719 
9720   // Fill in the fields: map, properties, length.
9721   Handle<Map> map_constant(isolate()->get_initial_js_array_map(kind));
9722   HValue* map = Add<HConstant>(map_constant);
9723 
9724   BuildJSArrayHeader(new_object, map,
9725                      nullptr,  // set elements to empty fixed array
9726                      mode, kind, nullptr, length);
9727 
9728   // Allocate and initialize the elements.
9729   HAllocate* elements = BuildAllocateElements(kind, elements_size);
9730   BuildInitializeElementsHeader(elements, kind, capacity);
9731   BuildFillElementsWithHole(elements, kind, graph()->GetConstant0(), capacity);
9732 
9733   // Set the elements.
9734   Add<HStoreNamedField>(new_object, HObjectAccess::ForElementsPointer(),
9735                         elements);
9736 
9737   int args_to_drop = argument_count + (expression->IsCall() ? 2 : 1);
9738   Drop(args_to_drop);
9739   ast_context()->ReturnValue(new_object);
9740   return true;
9741 }
9742 
9743 
9744 // Checks whether allocation using the given constructor can be inlined.
IsAllocationInlineable(Handle<JSFunction> constructor)9745 static bool IsAllocationInlineable(Handle<JSFunction> constructor) {
9746   return constructor->has_initial_map() &&
9747          !IsDerivedConstructor(constructor->shared()->kind()) &&
9748          constructor->initial_map()->instance_type() == JS_OBJECT_TYPE &&
9749          constructor->initial_map()->instance_size() <
9750              HAllocate::kMaxInlineSize;
9751 }
9752 
VisitCallNew(CallNew * expr)9753 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
9754   DCHECK(!HasStackOverflow());
9755   DCHECK(current_block() != NULL);
9756   DCHECK(current_block()->HasPredecessor());
9757   if (!is_tracking_positions()) SetSourcePosition(expr->position());
9758   int argument_count = expr->arguments()->length() + 1;  // Plus constructor.
9759   Factory* factory = isolate()->factory();
9760 
9761   // The constructor function is on the stack in the unoptimized code
9762   // during evaluation of the arguments.
9763   CHECK_ALIVE(VisitForValue(expr->expression()));
9764   HValue* function = Top();
9765   CHECK_ALIVE(VisitExpressions(expr->arguments()));
9766 
9767   if (function->IsConstant() &&
9768       HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
9769     Handle<Object> constant = HConstant::cast(function)->handle(isolate());
9770     expr->SetKnownGlobalTarget(Handle<JSFunction>::cast(constant));
9771   }
9772 
9773   if (FLAG_inline_construct &&
9774       expr->IsMonomorphic() &&
9775       IsAllocationInlineable(expr->target())) {
9776     Handle<JSFunction> constructor = expr->target();
9777     DCHECK(
9778         constructor->shared()->construct_stub() ==
9779             isolate()->builtins()->builtin(Builtins::kJSConstructStubGeneric) ||
9780         constructor->shared()->construct_stub() ==
9781             isolate()->builtins()->builtin(Builtins::kJSConstructStubApi));
9782     HValue* check = Add<HCheckValue>(function, constructor);
9783 
9784     // Force completion of inobject slack tracking before generating
9785     // allocation code to finalize instance size.
9786     constructor->CompleteInobjectSlackTrackingIfActive();
9787 
9788     // Calculate instance size from initial map of constructor.
9789     DCHECK(constructor->has_initial_map());
9790     Handle<Map> initial_map(constructor->initial_map());
9791     int instance_size = initial_map->instance_size();
9792 
9793     // Allocate an instance of the implicit receiver object.
9794     HValue* size_in_bytes = Add<HConstant>(instance_size);
9795     HAllocationMode allocation_mode;
9796     HAllocate* receiver = BuildAllocate(
9797         size_in_bytes, HType::JSObject(), JS_OBJECT_TYPE, allocation_mode);
9798     receiver->set_known_initial_map(initial_map);
9799 
9800     // Initialize map and fields of the newly allocated object.
9801     { NoObservableSideEffectsScope no_effects(this);
9802       DCHECK(initial_map->instance_type() == JS_OBJECT_TYPE);
9803       Add<HStoreNamedField>(receiver,
9804           HObjectAccess::ForMapAndOffset(initial_map, JSObject::kMapOffset),
9805           Add<HConstant>(initial_map));
9806       HValue* empty_fixed_array = Add<HConstant>(factory->empty_fixed_array());
9807       Add<HStoreNamedField>(receiver,
9808           HObjectAccess::ForMapAndOffset(initial_map,
9809                                          JSObject::kPropertiesOffset),
9810           empty_fixed_array);
9811       Add<HStoreNamedField>(receiver,
9812           HObjectAccess::ForMapAndOffset(initial_map,
9813                                          JSObject::kElementsOffset),
9814           empty_fixed_array);
9815       BuildInitializeInobjectProperties(receiver, initial_map);
9816     }
9817 
9818     // Replace the constructor function with a newly allocated receiver using
9819     // the index of the receiver from the top of the expression stack.
9820     const int receiver_index = argument_count - 1;
9821     DCHECK(environment()->ExpressionStackAt(receiver_index) == function);
9822     environment()->SetExpressionStackAt(receiver_index, receiver);
9823 
9824     if (TryInlineConstruct(expr, receiver)) {
9825       // Inlining worked, add a dependency on the initial map to make sure that
9826       // this code is deoptimized whenever the initial map of the constructor
9827       // changes.
9828       top_info()->dependencies()->AssumeInitialMapCantChange(initial_map);
9829       return;
9830     }
9831 
9832     // TODO(mstarzinger): For now we remove the previous HAllocate and all
9833     // corresponding instructions and instead add HPushArguments for the
9834     // arguments in case inlining failed.  What we actually should do is for
9835     // inlining to try to build a subgraph without mutating the parent graph.
9836     HInstruction* instr = current_block()->last();
9837     do {
9838       HInstruction* prev_instr = instr->previous();
9839       instr->DeleteAndReplaceWith(NULL);
9840       instr = prev_instr;
9841     } while (instr != check);
9842     environment()->SetExpressionStackAt(receiver_index, function);
9843   } else {
9844     // The constructor function is both an operand to the instruction and an
9845     // argument to the construct call.
9846     if (TryHandleArrayCall(expr, function)) return;
9847   }
9848 
9849   HValue* arity = Add<HConstant>(argument_count - 1);
9850   HValue* op_vals[] = {function, function, arity};
9851   Callable callable = CodeFactory::Construct(isolate());
9852   HConstant* stub = Add<HConstant>(callable.code());
9853   PushArgumentsFromEnvironment(argument_count);
9854   HInstruction* construct = New<HCallWithDescriptor>(
9855       stub, argument_count, callable.descriptor(), ArrayVector(op_vals));
9856   return ast_context()->ReturnInstruction(construct, expr->id());
9857 }
9858 
9859 
BuildInitializeInobjectProperties(HValue * receiver,Handle<Map> initial_map)9860 void HOptimizedGraphBuilder::BuildInitializeInobjectProperties(
9861     HValue* receiver, Handle<Map> initial_map) {
9862   if (initial_map->GetInObjectProperties() != 0) {
9863     HConstant* undefined = graph()->GetConstantUndefined();
9864     for (int i = 0; i < initial_map->GetInObjectProperties(); i++) {
9865       int property_offset = initial_map->GetInObjectPropertyOffset(i);
9866       Add<HStoreNamedField>(receiver, HObjectAccess::ForMapAndOffset(
9867                                           initial_map, property_offset),
9868                             undefined);
9869     }
9870   }
9871 }
9872 
9873 
BuildAllocateEmptyArrayBuffer(HValue * byte_length)9874 HValue* HGraphBuilder::BuildAllocateEmptyArrayBuffer(HValue* byte_length) {
9875   // We HForceRepresentation here to avoid allocations during an *-to-tagged
9876   // HChange that could cause GC while the array buffer object is not fully
9877   // initialized.
9878   HObjectAccess byte_length_access(HObjectAccess::ForJSArrayBufferByteLength());
9879   byte_length = AddUncasted<HForceRepresentation>(
9880       byte_length, byte_length_access.representation());
9881   HAllocate* result =
9882       BuildAllocate(Add<HConstant>(JSArrayBuffer::kSizeWithInternalFields),
9883                     HType::JSObject(), JS_ARRAY_BUFFER_TYPE, HAllocationMode());
9884 
9885   HValue* native_context = BuildGetNativeContext();
9886   Add<HStoreNamedField>(
9887       result, HObjectAccess::ForMap(),
9888       Add<HLoadNamedField>(
9889           native_context, nullptr,
9890           HObjectAccess::ForContextSlot(Context::ARRAY_BUFFER_MAP_INDEX)));
9891 
9892   HConstant* empty_fixed_array =
9893       Add<HConstant>(isolate()->factory()->empty_fixed_array());
9894   Add<HStoreNamedField>(
9895       result, HObjectAccess::ForJSArrayOffset(JSArray::kPropertiesOffset),
9896       empty_fixed_array);
9897   Add<HStoreNamedField>(
9898       result, HObjectAccess::ForJSArrayOffset(JSArray::kElementsOffset),
9899       empty_fixed_array);
9900   Add<HStoreNamedField>(
9901       result, HObjectAccess::ForJSArrayBufferBackingStore().WithRepresentation(
9902                   Representation::Smi()),
9903       graph()->GetConstant0());
9904   Add<HStoreNamedField>(result, byte_length_access, byte_length);
9905   Add<HStoreNamedField>(result, HObjectAccess::ForJSArrayBufferBitFieldSlot(),
9906                         graph()->GetConstant0());
9907   Add<HStoreNamedField>(
9908       result, HObjectAccess::ForJSArrayBufferBitField(),
9909       Add<HConstant>((1 << JSArrayBuffer::IsExternal::kShift) |
9910                      (1 << JSArrayBuffer::IsNeuterable::kShift)));
9911 
9912   for (int field = 0; field < v8::ArrayBuffer::kInternalFieldCount; ++field) {
9913     Add<HStoreNamedField>(
9914         result,
9915         HObjectAccess::ForObservableJSObjectOffset(
9916             JSArrayBuffer::kSize + field * kPointerSize, Representation::Smi()),
9917         graph()->GetConstant0());
9918   }
9919 
9920   return result;
9921 }
9922 
9923 
9924 template <class ViewClass>
BuildArrayBufferViewInitialization(HValue * obj,HValue * buffer,HValue * byte_offset,HValue * byte_length)9925 void HGraphBuilder::BuildArrayBufferViewInitialization(
9926     HValue* obj,
9927     HValue* buffer,
9928     HValue* byte_offset,
9929     HValue* byte_length) {
9930 
9931   for (int offset = ViewClass::kSize;
9932        offset < ViewClass::kSizeWithInternalFields;
9933        offset += kPointerSize) {
9934     Add<HStoreNamedField>(obj,
9935         HObjectAccess::ForObservableJSObjectOffset(offset),
9936         graph()->GetConstant0());
9937   }
9938 
9939   Add<HStoreNamedField>(
9940       obj,
9941       HObjectAccess::ForJSArrayBufferViewByteOffset(),
9942       byte_offset);
9943   Add<HStoreNamedField>(
9944       obj,
9945       HObjectAccess::ForJSArrayBufferViewByteLength(),
9946       byte_length);
9947   Add<HStoreNamedField>(obj, HObjectAccess::ForJSArrayBufferViewBuffer(),
9948                         buffer);
9949 }
9950 
9951 
BuildAllocateExternalElements(ExternalArrayType array_type,bool is_zero_byte_offset,HValue * buffer,HValue * byte_offset,HValue * length)9952 HValue* HOptimizedGraphBuilder::BuildAllocateExternalElements(
9953     ExternalArrayType array_type,
9954     bool is_zero_byte_offset,
9955     HValue* buffer, HValue* byte_offset, HValue* length) {
9956   Handle<Map> external_array_map(
9957       isolate()->heap()->MapForFixedTypedArray(array_type));
9958 
9959   // The HForceRepresentation is to prevent possible deopt on int-smi
9960   // conversion after allocation but before the new object fields are set.
9961   length = AddUncasted<HForceRepresentation>(length, Representation::Smi());
9962   HValue* elements = Add<HAllocate>(
9963       Add<HConstant>(FixedTypedArrayBase::kHeaderSize), HType::HeapObject(),
9964       NOT_TENURED, external_array_map->instance_type(),
9965       graph()->GetConstant0());
9966 
9967   AddStoreMapConstant(elements, external_array_map);
9968   Add<HStoreNamedField>(elements,
9969       HObjectAccess::ForFixedArrayLength(), length);
9970 
9971   HValue* backing_store = Add<HLoadNamedField>(
9972       buffer, nullptr, HObjectAccess::ForJSArrayBufferBackingStore());
9973 
9974   HValue* typed_array_start;
9975   if (is_zero_byte_offset) {
9976     typed_array_start = backing_store;
9977   } else {
9978     HInstruction* external_pointer =
9979         AddUncasted<HAdd>(backing_store, byte_offset);
9980     // Arguments are checked prior to call to TypedArrayInitialize,
9981     // including byte_offset.
9982     external_pointer->ClearFlag(HValue::kCanOverflow);
9983     typed_array_start = external_pointer;
9984   }
9985 
9986   Add<HStoreNamedField>(elements,
9987                         HObjectAccess::ForFixedTypedArrayBaseBasePointer(),
9988                         graph()->GetConstant0());
9989   Add<HStoreNamedField>(elements,
9990                         HObjectAccess::ForFixedTypedArrayBaseExternalPointer(),
9991                         typed_array_start);
9992 
9993   return elements;
9994 }
9995 
9996 
BuildAllocateFixedTypedArray(ExternalArrayType array_type,size_t element_size,ElementsKind fixed_elements_kind,HValue * byte_length,HValue * length,bool initialize)9997 HValue* HOptimizedGraphBuilder::BuildAllocateFixedTypedArray(
9998     ExternalArrayType array_type, size_t element_size,
9999     ElementsKind fixed_elements_kind, HValue* byte_length, HValue* length,
10000     bool initialize) {
10001   STATIC_ASSERT(
10002       (FixedTypedArrayBase::kHeaderSize & kObjectAlignmentMask) == 0);
10003   HValue* total_size;
10004 
10005   // if fixed array's elements are not aligned to object's alignment,
10006   // we need to align the whole array to object alignment.
10007   if (element_size % kObjectAlignment != 0) {
10008     total_size = BuildObjectSizeAlignment(
10009         byte_length, FixedTypedArrayBase::kHeaderSize);
10010   } else {
10011     total_size = AddUncasted<HAdd>(byte_length,
10012         Add<HConstant>(FixedTypedArrayBase::kHeaderSize));
10013     total_size->ClearFlag(HValue::kCanOverflow);
10014   }
10015 
10016   // The HForceRepresentation is to prevent possible deopt on int-smi
10017   // conversion after allocation but before the new object fields are set.
10018   length = AddUncasted<HForceRepresentation>(length, Representation::Smi());
10019   Handle<Map> fixed_typed_array_map(
10020       isolate()->heap()->MapForFixedTypedArray(array_type));
10021   HAllocate* elements = Add<HAllocate>(
10022       total_size, HType::HeapObject(), NOT_TENURED,
10023       fixed_typed_array_map->instance_type(), graph()->GetConstant0());
10024 
10025 #ifndef V8_HOST_ARCH_64_BIT
10026   if (array_type == kExternalFloat64Array) {
10027     elements->MakeDoubleAligned();
10028   }
10029 #endif
10030 
10031   AddStoreMapConstant(elements, fixed_typed_array_map);
10032 
10033   Add<HStoreNamedField>(elements,
10034       HObjectAccess::ForFixedArrayLength(),
10035       length);
10036   Add<HStoreNamedField>(
10037       elements, HObjectAccess::ForFixedTypedArrayBaseBasePointer(), elements);
10038 
10039   Add<HStoreNamedField>(
10040       elements, HObjectAccess::ForFixedTypedArrayBaseExternalPointer(),
10041       Add<HConstant>(ExternalReference::fixed_typed_array_base_data_offset()));
10042 
10043   HValue* filler = Add<HConstant>(static_cast<int32_t>(0));
10044 
10045   if (initialize) {
10046     LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement);
10047 
10048     HValue* backing_store = AddUncasted<HAdd>(
10049         Add<HConstant>(ExternalReference::fixed_typed_array_base_data_offset()),
10050         elements, AddOfExternalAndTagged);
10051 
10052     HValue* key = builder.BeginBody(
10053         Add<HConstant>(static_cast<int32_t>(0)),
10054         length, Token::LT);
10055     Add<HStoreKeyed>(backing_store, key, filler, elements, fixed_elements_kind);
10056 
10057     builder.EndBody();
10058   }
10059   return elements;
10060 }
10061 
10062 
GenerateTypedArrayInitialize(CallRuntime * expr)10063 void HOptimizedGraphBuilder::GenerateTypedArrayInitialize(
10064     CallRuntime* expr) {
10065   ZoneList<Expression*>* arguments = expr->arguments();
10066 
10067   static const int kObjectArg = 0;
10068   static const int kArrayIdArg = 1;
10069   static const int kBufferArg = 2;
10070   static const int kByteOffsetArg = 3;
10071   static const int kByteLengthArg = 4;
10072   static const int kInitializeArg = 5;
10073   static const int kArgsLength = 6;
10074   DCHECK(arguments->length() == kArgsLength);
10075 
10076 
10077   CHECK_ALIVE(VisitForValue(arguments->at(kObjectArg)));
10078   HValue* obj = Pop();
10079 
10080   if (!arguments->at(kArrayIdArg)->IsLiteral()) {
10081     // This should never happen in real use, but can happen when fuzzing.
10082     // Just bail out.
10083     Bailout(kNeedSmiLiteral);
10084     return;
10085   }
10086   Handle<Object> value =
10087       static_cast<Literal*>(arguments->at(kArrayIdArg))->value();
10088   if (!value->IsSmi()) {
10089     // This should never happen in real use, but can happen when fuzzing.
10090     // Just bail out.
10091     Bailout(kNeedSmiLiteral);
10092     return;
10093   }
10094   int array_id = Smi::cast(*value)->value();
10095 
10096   HValue* buffer;
10097   if (!arguments->at(kBufferArg)->IsNullLiteral()) {
10098     CHECK_ALIVE(VisitForValue(arguments->at(kBufferArg)));
10099     buffer = Pop();
10100   } else {
10101     buffer = NULL;
10102   }
10103 
10104   HValue* byte_offset;
10105   bool is_zero_byte_offset;
10106 
10107   if (arguments->at(kByteOffsetArg)->IsLiteral() &&
10108       Smi::kZero ==
10109           *static_cast<Literal*>(arguments->at(kByteOffsetArg))->value()) {
10110     byte_offset = Add<HConstant>(static_cast<int32_t>(0));
10111     is_zero_byte_offset = true;
10112   } else {
10113     CHECK_ALIVE(VisitForValue(arguments->at(kByteOffsetArg)));
10114     byte_offset = Pop();
10115     is_zero_byte_offset = false;
10116     DCHECK(buffer != NULL);
10117   }
10118 
10119   CHECK_ALIVE(VisitForValue(arguments->at(kByteLengthArg)));
10120   HValue* byte_length = Pop();
10121 
10122   CHECK(arguments->at(kInitializeArg)->IsLiteral());
10123   bool initialize = static_cast<Literal*>(arguments->at(kInitializeArg))
10124                         ->value()
10125                         ->BooleanValue();
10126 
10127   NoObservableSideEffectsScope scope(this);
10128   IfBuilder byte_offset_smi(this);
10129 
10130   if (!is_zero_byte_offset) {
10131     byte_offset_smi.If<HIsSmiAndBranch>(byte_offset);
10132     byte_offset_smi.Then();
10133   }
10134 
10135   ExternalArrayType array_type =
10136       kExternalInt8Array;  // Bogus initialization.
10137   size_t element_size = 1;  // Bogus initialization.
10138   ElementsKind fixed_elements_kind =  // Bogus initialization.
10139       INT8_ELEMENTS;
10140   Runtime::ArrayIdToTypeAndSize(array_id,
10141       &array_type,
10142       &fixed_elements_kind,
10143       &element_size);
10144 
10145 
10146   { //  byte_offset is Smi.
10147     HValue* allocated_buffer = buffer;
10148     if (buffer == NULL) {
10149       allocated_buffer = BuildAllocateEmptyArrayBuffer(byte_length);
10150     }
10151     BuildArrayBufferViewInitialization<JSTypedArray>(obj, allocated_buffer,
10152                                                      byte_offset, byte_length);
10153 
10154 
10155     HInstruction* length = AddUncasted<HDiv>(byte_length,
10156         Add<HConstant>(static_cast<int32_t>(element_size)));
10157     // Callers (in typedarray.js) ensure that length <= %_MaxSmi().
10158     length = AddUncasted<HForceRepresentation>(length, Representation::Smi());
10159 
10160     Add<HStoreNamedField>(obj,
10161         HObjectAccess::ForJSTypedArrayLength(),
10162         length);
10163 
10164     HValue* elements;
10165     if (buffer != NULL) {
10166       elements = BuildAllocateExternalElements(
10167           array_type, is_zero_byte_offset, buffer, byte_offset, length);
10168     } else {
10169       DCHECK(is_zero_byte_offset);
10170       elements = BuildAllocateFixedTypedArray(array_type, element_size,
10171                                               fixed_elements_kind, byte_length,
10172                                               length, initialize);
10173     }
10174     Add<HStoreNamedField>(
10175         obj, HObjectAccess::ForElementsPointer(), elements);
10176   }
10177 
10178   if (!is_zero_byte_offset) {
10179     byte_offset_smi.Else();
10180     { //  byte_offset is not Smi.
10181       Push(obj);
10182       CHECK_ALIVE(VisitForValue(arguments->at(kArrayIdArg)));
10183       Push(buffer);
10184       Push(byte_offset);
10185       Push(byte_length);
10186       CHECK_ALIVE(VisitForValue(arguments->at(kInitializeArg)));
10187       PushArgumentsFromEnvironment(kArgsLength);
10188       Add<HCallRuntime>(expr->function(), kArgsLength);
10189     }
10190   }
10191   byte_offset_smi.End();
10192 }
10193 
10194 
GenerateMaxSmi(CallRuntime * expr)10195 void HOptimizedGraphBuilder::GenerateMaxSmi(CallRuntime* expr) {
10196   DCHECK(expr->arguments()->length() == 0);
10197   HConstant* max_smi = New<HConstant>(static_cast<int32_t>(Smi::kMaxValue));
10198   return ast_context()->ReturnInstruction(max_smi, expr->id());
10199 }
10200 
10201 
GenerateTypedArrayMaxSizeInHeap(CallRuntime * expr)10202 void HOptimizedGraphBuilder::GenerateTypedArrayMaxSizeInHeap(
10203     CallRuntime* expr) {
10204   DCHECK(expr->arguments()->length() == 0);
10205   HConstant* result = New<HConstant>(static_cast<int32_t>(
10206         FLAG_typed_array_max_size_in_heap));
10207   return ast_context()->ReturnInstruction(result, expr->id());
10208 }
10209 
10210 
GenerateArrayBufferGetByteLength(CallRuntime * expr)10211 void HOptimizedGraphBuilder::GenerateArrayBufferGetByteLength(
10212     CallRuntime* expr) {
10213   DCHECK(expr->arguments()->length() == 1);
10214   CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
10215   HValue* buffer = Pop();
10216   HInstruction* result = New<HLoadNamedField>(
10217       buffer, nullptr, HObjectAccess::ForJSArrayBufferByteLength());
10218   return ast_context()->ReturnInstruction(result, expr->id());
10219 }
10220 
10221 
GenerateArrayBufferViewGetByteLength(CallRuntime * expr)10222 void HOptimizedGraphBuilder::GenerateArrayBufferViewGetByteLength(
10223     CallRuntime* expr) {
10224   NoObservableSideEffectsScope scope(this);
10225   DCHECK(expr->arguments()->length() == 1);
10226   CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
10227   HValue* view = Pop();
10228 
10229   return ast_context()->ReturnValue(BuildArrayBufferViewFieldAccessor(
10230       view, nullptr,
10231       FieldIndex::ForInObjectOffset(JSArrayBufferView::kByteLengthOffset)));
10232 }
10233 
10234 
GenerateArrayBufferViewGetByteOffset(CallRuntime * expr)10235 void HOptimizedGraphBuilder::GenerateArrayBufferViewGetByteOffset(
10236     CallRuntime* expr) {
10237   NoObservableSideEffectsScope scope(this);
10238   DCHECK(expr->arguments()->length() == 1);
10239   CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
10240   HValue* view = Pop();
10241 
10242   return ast_context()->ReturnValue(BuildArrayBufferViewFieldAccessor(
10243       view, nullptr,
10244       FieldIndex::ForInObjectOffset(JSArrayBufferView::kByteOffsetOffset)));
10245 }
10246 
10247 
GenerateTypedArrayGetLength(CallRuntime * expr)10248 void HOptimizedGraphBuilder::GenerateTypedArrayGetLength(
10249     CallRuntime* expr) {
10250   NoObservableSideEffectsScope scope(this);
10251   DCHECK(expr->arguments()->length() == 1);
10252   CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
10253   HValue* view = Pop();
10254 
10255   return ast_context()->ReturnValue(BuildArrayBufferViewFieldAccessor(
10256       view, nullptr,
10257       FieldIndex::ForInObjectOffset(JSTypedArray::kLengthOffset)));
10258 }
10259 
10260 
VisitCallRuntime(CallRuntime * expr)10261 void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
10262   DCHECK(!HasStackOverflow());
10263   DCHECK(current_block() != NULL);
10264   DCHECK(current_block()->HasPredecessor());
10265   if (expr->is_jsruntime()) {
10266     // Crankshaft always specializes to the native context, so we can just grab
10267     // the constant function from the current native context and embed that into
10268     // the code object.
10269     Handle<JSFunction> known_function(
10270         JSFunction::cast(
10271             current_info()->native_context()->get(expr->context_index())),
10272         isolate());
10273 
10274     // The callee and the receiver both have to be pushed onto the operand stack
10275     // before arguments are being evaluated.
10276     HConstant* function = Add<HConstant>(known_function);
10277     HValue* receiver = ImplicitReceiverFor(function, known_function);
10278     Push(function);
10279     Push(receiver);
10280 
10281     int argument_count = expr->arguments()->length() + 1;  // Count receiver.
10282     CHECK_ALIVE(VisitExpressions(expr->arguments()));
10283     PushArgumentsFromEnvironment(argument_count);
10284     HInstruction* call = NewCallConstantFunction(known_function, argument_count,
10285                                                  TailCallMode::kDisallow,
10286                                                  TailCallMode::kDisallow);
10287     Drop(1);  // Function
10288     return ast_context()->ReturnInstruction(call, expr->id());
10289   }
10290 
10291   const Runtime::Function* function = expr->function();
10292   DCHECK(function != NULL);
10293   switch (function->function_id) {
10294 #define CALL_INTRINSIC_GENERATOR(Name) \
10295   case Runtime::kInline##Name:         \
10296     return Generate##Name(expr);
10297 
10298     FOR_EACH_HYDROGEN_INTRINSIC(CALL_INTRINSIC_GENERATOR)
10299 #undef CALL_INTRINSIC_GENERATOR
10300     default: {
10301       int argument_count = expr->arguments()->length();
10302       CHECK_ALIVE(VisitExpressions(expr->arguments()));
10303       PushArgumentsFromEnvironment(argument_count);
10304       HCallRuntime* call = New<HCallRuntime>(function, argument_count);
10305       return ast_context()->ReturnInstruction(call, expr->id());
10306     }
10307   }
10308 }
10309 
10310 
VisitUnaryOperation(UnaryOperation * expr)10311 void HOptimizedGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
10312   DCHECK(!HasStackOverflow());
10313   DCHECK(current_block() != NULL);
10314   DCHECK(current_block()->HasPredecessor());
10315   switch (expr->op()) {
10316     case Token::DELETE: return VisitDelete(expr);
10317     case Token::VOID: return VisitVoid(expr);
10318     case Token::TYPEOF: return VisitTypeof(expr);
10319     case Token::NOT: return VisitNot(expr);
10320     default: UNREACHABLE();
10321   }
10322 }
10323 
10324 
VisitDelete(UnaryOperation * expr)10325 void HOptimizedGraphBuilder::VisitDelete(UnaryOperation* expr) {
10326   Property* prop = expr->expression()->AsProperty();
10327   VariableProxy* proxy = expr->expression()->AsVariableProxy();
10328   if (prop != NULL) {
10329     CHECK_ALIVE(VisitForValue(prop->obj()));
10330     CHECK_ALIVE(VisitForValue(prop->key()));
10331     HValue* key = Pop();
10332     HValue* obj = Pop();
10333     Add<HPushArguments>(obj, key);
10334     HInstruction* instr = New<HCallRuntime>(
10335         Runtime::FunctionForId(is_strict(function_language_mode())
10336                                    ? Runtime::kDeleteProperty_Strict
10337                                    : Runtime::kDeleteProperty_Sloppy),
10338         2);
10339     return ast_context()->ReturnInstruction(instr, expr->id());
10340   } else if (proxy != NULL) {
10341     Variable* var = proxy->var();
10342     if (var->IsUnallocated()) {
10343       Bailout(kDeleteWithGlobalVariable);
10344     } else if (var->IsStackAllocated() || var->IsContextSlot()) {
10345       // Result of deleting non-global variables is false.  'this' is not really
10346       // a variable, though we implement it as one.  The subexpression does not
10347       // have side effects.
10348       HValue* value = var->is_this() ? graph()->GetConstantTrue()
10349                                      : graph()->GetConstantFalse();
10350       return ast_context()->ReturnValue(value);
10351     } else {
10352       Bailout(kDeleteWithNonGlobalVariable);
10353     }
10354   } else {
10355     // Result of deleting non-property, non-variable reference is true.
10356     // Evaluate the subexpression for side effects.
10357     CHECK_ALIVE(VisitForEffect(expr->expression()));
10358     return ast_context()->ReturnValue(graph()->GetConstantTrue());
10359   }
10360 }
10361 
10362 
VisitVoid(UnaryOperation * expr)10363 void HOptimizedGraphBuilder::VisitVoid(UnaryOperation* expr) {
10364   CHECK_ALIVE(VisitForEffect(expr->expression()));
10365   return ast_context()->ReturnValue(graph()->GetConstantUndefined());
10366 }
10367 
10368 
VisitTypeof(UnaryOperation * expr)10369 void HOptimizedGraphBuilder::VisitTypeof(UnaryOperation* expr) {
10370   CHECK_ALIVE(VisitForTypeOf(expr->expression()));
10371   HValue* value = Pop();
10372   HInstruction* instr = New<HTypeof>(value);
10373   return ast_context()->ReturnInstruction(instr, expr->id());
10374 }
10375 
10376 
VisitNot(UnaryOperation * expr)10377 void HOptimizedGraphBuilder::VisitNot(UnaryOperation* expr) {
10378   if (ast_context()->IsTest()) {
10379     TestContext* context = TestContext::cast(ast_context());
10380     VisitForControl(expr->expression(),
10381                     context->if_false(),
10382                     context->if_true());
10383     return;
10384   }
10385 
10386   if (ast_context()->IsEffect()) {
10387     VisitForEffect(expr->expression());
10388     return;
10389   }
10390 
10391   DCHECK(ast_context()->IsValue());
10392   HBasicBlock* materialize_false = graph()->CreateBasicBlock();
10393   HBasicBlock* materialize_true = graph()->CreateBasicBlock();
10394   CHECK_BAILOUT(VisitForControl(expr->expression(),
10395                                 materialize_false,
10396                                 materialize_true));
10397 
10398   if (materialize_false->HasPredecessor()) {
10399     materialize_false->SetJoinId(expr->MaterializeFalseId());
10400     set_current_block(materialize_false);
10401     Push(graph()->GetConstantFalse());
10402   } else {
10403     materialize_false = NULL;
10404   }
10405 
10406   if (materialize_true->HasPredecessor()) {
10407     materialize_true->SetJoinId(expr->MaterializeTrueId());
10408     set_current_block(materialize_true);
10409     Push(graph()->GetConstantTrue());
10410   } else {
10411     materialize_true = NULL;
10412   }
10413 
10414   HBasicBlock* join =
10415     CreateJoin(materialize_false, materialize_true, expr->id());
10416   set_current_block(join);
10417   if (join != NULL) return ast_context()->ReturnValue(Pop());
10418 }
10419 
RepresentationFor(AstType * type)10420 static Representation RepresentationFor(AstType* type) {
10421   DisallowHeapAllocation no_allocation;
10422   if (type->Is(AstType::None())) return Representation::None();
10423   if (type->Is(AstType::SignedSmall())) return Representation::Smi();
10424   if (type->Is(AstType::Signed32())) return Representation::Integer32();
10425   if (type->Is(AstType::Number())) return Representation::Double();
10426   return Representation::Tagged();
10427 }
10428 
BuildIncrement(CountOperation * expr)10429 HInstruction* HOptimizedGraphBuilder::BuildIncrement(CountOperation* expr) {
10430   // The input to the count operation is on top of the expression stack.
10431   Representation rep = RepresentationFor(expr->type());
10432   if (rep.IsNone() || rep.IsTagged()) {
10433     rep = Representation::Smi();
10434   }
10435 
10436   // We need an explicit HValue representing ToNumber(input).  The
10437   // actual HChange instruction we need is (sometimes) added in a later
10438   // phase, so it is not available now to be used as an input to HAdd and
10439   // as the return value.
10440   HInstruction* number_input = AddUncasted<HForceRepresentation>(Pop(), rep);
10441   if (!rep.IsDouble()) {
10442     number_input->SetFlag(HInstruction::kFlexibleRepresentation);
10443     number_input->SetFlag(HInstruction::kCannotBeTagged);
10444   }
10445   Push(number_input);
10446 
10447   // The addition has no side effects, so we do not need
10448   // to simulate the expression stack after this instruction.
10449   // Any later failures deopt to the load of the input or earlier.
10450   HConstant* delta = (expr->op() == Token::INC)
10451       ? graph()->GetConstant1()
10452       : graph()->GetConstantMinus1();
10453   HInstruction* instr = AddUncasted<HAdd>(Top(), delta);
10454   if (instr->IsAdd()) {
10455     HAdd* add = HAdd::cast(instr);
10456     add->set_observed_input_representation(1, rep);
10457     add->set_observed_input_representation(2, Representation::Smi());
10458   }
10459   instr->ClearAllSideEffects();
10460   instr->SetFlag(HInstruction::kCannotBeTagged);
10461   return instr;
10462 }
10463 
BuildStoreForEffect(Expression * expr,Property * prop,FeedbackSlot slot,BailoutId ast_id,BailoutId return_id,HValue * object,HValue * key,HValue * value)10464 void HOptimizedGraphBuilder::BuildStoreForEffect(
10465     Expression* expr, Property* prop, FeedbackSlot slot, BailoutId ast_id,
10466     BailoutId return_id, HValue* object, HValue* key, HValue* value) {
10467   EffectContext for_effect(this);
10468   Push(object);
10469   if (key != NULL) Push(key);
10470   Push(value);
10471   BuildStore(expr, prop, slot, ast_id, return_id);
10472 }
10473 
10474 
VisitCountOperation(CountOperation * expr)10475 void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
10476   DCHECK(!HasStackOverflow());
10477   DCHECK(current_block() != NULL);
10478   DCHECK(current_block()->HasPredecessor());
10479   if (!is_tracking_positions()) SetSourcePosition(expr->position());
10480   Expression* target = expr->expression();
10481   VariableProxy* proxy = target->AsVariableProxy();
10482   Property* prop = target->AsProperty();
10483   if (proxy == NULL && prop == NULL) {
10484     return Bailout(kInvalidLhsInCountOperation);
10485   }
10486 
10487   // Match the full code generator stack by simulating an extra stack
10488   // element for postfix operations in a non-effect context.  The return
10489   // value is ToNumber(input).
10490   bool returns_original_input =
10491       expr->is_postfix() && !ast_context()->IsEffect();
10492   HValue* input = NULL;  // ToNumber(original_input).
10493   HValue* after = NULL;  // The result after incrementing or decrementing.
10494 
10495   if (proxy != NULL) {
10496     Variable* var = proxy->var();
10497     if (var->mode() == CONST) {
10498       return Bailout(kNonInitializerAssignmentToConst);
10499     }
10500     // Argument of the count operation is a variable, not a property.
10501     DCHECK(prop == NULL);
10502     CHECK_ALIVE(VisitForValue(target));
10503 
10504     after = BuildIncrement(expr);
10505     input = returns_original_input ? Top() : Pop();
10506     Push(after);
10507 
10508     switch (var->location()) {
10509       case VariableLocation::UNALLOCATED:
10510         HandleGlobalVariableAssignment(var, after, expr->CountSlot(),
10511                                        expr->AssignmentId());
10512         break;
10513 
10514       case VariableLocation::PARAMETER:
10515       case VariableLocation::LOCAL:
10516         BindIfLive(var, after);
10517         break;
10518 
10519       case VariableLocation::CONTEXT: {
10520         HValue* context = BuildContextChainWalk(var);
10521         HStoreContextSlot::Mode mode = IsLexicalVariableMode(var->mode())
10522             ? HStoreContextSlot::kCheckDeoptimize : HStoreContextSlot::kNoCheck;
10523         HStoreContextSlot* instr = Add<HStoreContextSlot>(context, var->index(),
10524                                                           mode, after);
10525         if (instr->HasObservableSideEffects()) {
10526           Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
10527         }
10528         break;
10529       }
10530 
10531       case VariableLocation::LOOKUP:
10532         return Bailout(kLookupVariableInCountOperation);
10533 
10534       case VariableLocation::MODULE:
10535         UNREACHABLE();
10536     }
10537 
10538     Drop(returns_original_input ? 2 : 1);
10539     return ast_context()->ReturnValue(expr->is_postfix() ? input : after);
10540   }
10541 
10542   // Argument of the count operation is a property.
10543   DCHECK(prop != NULL);
10544   if (returns_original_input) Push(graph()->GetConstantUndefined());
10545 
10546   CHECK_ALIVE(VisitForValue(prop->obj()));
10547   HValue* object = Top();
10548 
10549   HValue* key = NULL;
10550   if (!prop->key()->IsPropertyName() || prop->IsStringAccess()) {
10551     CHECK_ALIVE(VisitForValue(prop->key()));
10552     key = Top();
10553   }
10554 
10555   CHECK_ALIVE(PushLoad(prop, object, key));
10556 
10557   after = BuildIncrement(expr);
10558 
10559   if (returns_original_input) {
10560     input = Pop();
10561     // Drop object and key to push it again in the effect context below.
10562     Drop(key == NULL ? 1 : 2);
10563     environment()->SetExpressionStackAt(0, input);
10564     CHECK_ALIVE(BuildStoreForEffect(expr, prop, expr->CountSlot(), expr->id(),
10565                                     expr->AssignmentId(), object, key, after));
10566     return ast_context()->ReturnValue(Pop());
10567   }
10568 
10569   environment()->SetExpressionStackAt(0, after);
10570   return BuildStore(expr, prop, expr->CountSlot(), expr->id(),
10571                     expr->AssignmentId());
10572 }
10573 
10574 
BuildStringCharCodeAt(HValue * string,HValue * index)10575 HInstruction* HOptimizedGraphBuilder::BuildStringCharCodeAt(
10576     HValue* string,
10577     HValue* index) {
10578   if (string->IsConstant() && index->IsConstant()) {
10579     HConstant* c_string = HConstant::cast(string);
10580     HConstant* c_index = HConstant::cast(index);
10581     if (c_string->HasStringValue() && c_index->HasNumberValue()) {
10582       int32_t i = c_index->NumberValueAsInteger32();
10583       Handle<String> s = c_string->StringValue();
10584       if (i < 0 || i >= s->length()) {
10585         return New<HConstant>(std::numeric_limits<double>::quiet_NaN());
10586       }
10587       return New<HConstant>(s->Get(i));
10588     }
10589   }
10590   string = BuildCheckString(string);
10591   index = Add<HBoundsCheck>(index, AddLoadStringLength(string));
10592   return New<HStringCharCodeAt>(string, index);
10593 }
10594 
10595 
10596 // Checks if the given shift amounts have following forms:
10597 // (N1) and (N2) with N1 + N2 = 32; (sa) and (32 - sa).
ShiftAmountsAllowReplaceByRotate(HValue * sa,HValue * const32_minus_sa)10598 static bool ShiftAmountsAllowReplaceByRotate(HValue* sa,
10599                                              HValue* const32_minus_sa) {
10600   if (sa->IsConstant() && const32_minus_sa->IsConstant()) {
10601     const HConstant* c1 = HConstant::cast(sa);
10602     const HConstant* c2 = HConstant::cast(const32_minus_sa);
10603     return c1->HasInteger32Value() && c2->HasInteger32Value() &&
10604         (c1->Integer32Value() + c2->Integer32Value() == 32);
10605   }
10606   if (!const32_minus_sa->IsSub()) return false;
10607   HSub* sub = HSub::cast(const32_minus_sa);
10608   return sub->left()->EqualsInteger32Constant(32) && sub->right() == sa;
10609 }
10610 
10611 
10612 // Checks if the left and the right are shift instructions with the oposite
10613 // directions that can be replaced by one rotate right instruction or not.
10614 // Returns the operand and the shift amount for the rotate instruction in the
10615 // former case.
MatchRotateRight(HValue * left,HValue * right,HValue ** operand,HValue ** shift_amount)10616 bool HGraphBuilder::MatchRotateRight(HValue* left,
10617                                      HValue* right,
10618                                      HValue** operand,
10619                                      HValue** shift_amount) {
10620   HShl* shl;
10621   HShr* shr;
10622   if (left->IsShl() && right->IsShr()) {
10623     shl = HShl::cast(left);
10624     shr = HShr::cast(right);
10625   } else if (left->IsShr() && right->IsShl()) {
10626     shl = HShl::cast(right);
10627     shr = HShr::cast(left);
10628   } else {
10629     return false;
10630   }
10631   if (shl->left() != shr->left()) return false;
10632 
10633   if (!ShiftAmountsAllowReplaceByRotate(shl->right(), shr->right()) &&
10634       !ShiftAmountsAllowReplaceByRotate(shr->right(), shl->right())) {
10635     return false;
10636   }
10637   *operand = shr->left();
10638   *shift_amount = shr->right();
10639   return true;
10640 }
10641 
10642 
CanBeZero(HValue * right)10643 bool CanBeZero(HValue* right) {
10644   if (right->IsConstant()) {
10645     HConstant* right_const = HConstant::cast(right);
10646     if (right_const->HasInteger32Value() &&
10647        (right_const->Integer32Value() & 0x1f) != 0) {
10648       return false;
10649     }
10650   }
10651   return true;
10652 }
10653 
EnforceNumberType(HValue * number,AstType * expected)10654 HValue* HGraphBuilder::EnforceNumberType(HValue* number, AstType* expected) {
10655   if (expected->Is(AstType::SignedSmall())) {
10656     return AddUncasted<HForceRepresentation>(number, Representation::Smi());
10657   }
10658   if (expected->Is(AstType::Signed32())) {
10659     return AddUncasted<HForceRepresentation>(number,
10660                                              Representation::Integer32());
10661   }
10662   return number;
10663 }
10664 
TruncateToNumber(HValue * value,AstType ** expected)10665 HValue* HGraphBuilder::TruncateToNumber(HValue* value, AstType** expected) {
10666   if (value->IsConstant()) {
10667     HConstant* constant = HConstant::cast(value);
10668     Maybe<HConstant*> number =
10669         constant->CopyToTruncatedNumber(isolate(), zone());
10670     if (number.IsJust()) {
10671       *expected = AstType::Number();
10672       return AddInstruction(number.FromJust());
10673     }
10674   }
10675 
10676   // We put temporary values on the stack, which don't correspond to anything
10677   // in baseline code. Since nothing is observable we avoid recording those
10678   // pushes with a NoObservableSideEffectsScope.
10679   NoObservableSideEffectsScope no_effects(this);
10680 
10681   AstType* expected_type = *expected;
10682 
10683   // Separate the number type from the rest.
10684   AstType* expected_obj =
10685       AstType::Intersect(expected_type, AstType::NonNumber(), zone());
10686   AstType* expected_number =
10687       AstType::Intersect(expected_type, AstType::Number(), zone());
10688 
10689   // We expect to get a number.
10690   // (We need to check first, since AstType::None->Is(AstType::Any()) == true.
10691   if (expected_obj->Is(AstType::None())) {
10692     DCHECK(!expected_number->Is(AstType::None()));
10693     return value;
10694   }
10695 
10696   if (expected_obj->Is(AstType::Undefined())) {
10697     // This is already done by HChange.
10698     *expected = AstType::Union(expected_number, AstType::Number(), zone());
10699     return value;
10700   }
10701 
10702   return value;
10703 }
10704 
10705 
BuildBinaryOperation(BinaryOperation * expr,HValue * left,HValue * right,PushBeforeSimulateBehavior push_sim_result)10706 HValue* HOptimizedGraphBuilder::BuildBinaryOperation(
10707     BinaryOperation* expr,
10708     HValue* left,
10709     HValue* right,
10710     PushBeforeSimulateBehavior push_sim_result) {
10711   AstType* left_type = bounds_.get(expr->left()).lower;
10712   AstType* right_type = bounds_.get(expr->right()).lower;
10713   AstType* result_type = bounds_.get(expr).lower;
10714   Maybe<int> fixed_right_arg = expr->fixed_right_arg();
10715   Handle<AllocationSite> allocation_site = expr->allocation_site();
10716 
10717   HAllocationMode allocation_mode;
10718   if (FLAG_allocation_site_pretenuring && !allocation_site.is_null()) {
10719     allocation_mode = HAllocationMode(allocation_site);
10720   }
10721   HValue* result = HGraphBuilder::BuildBinaryOperation(
10722       expr->op(), left, right, left_type, right_type, result_type,
10723       fixed_right_arg, allocation_mode, expr->id());
10724   // Add a simulate after instructions with observable side effects, and
10725   // after phis, which are the result of BuildBinaryOperation when we
10726   // inlined some complex subgraph.
10727   if (result->HasObservableSideEffects() || result->IsPhi()) {
10728     if (push_sim_result == PUSH_BEFORE_SIMULATE) {
10729       Push(result);
10730       Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
10731       Drop(1);
10732     } else {
10733       Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
10734     }
10735   }
10736   return result;
10737 }
10738 
BuildBinaryOperation(Token::Value op,HValue * left,HValue * right,AstType * left_type,AstType * right_type,AstType * result_type,Maybe<int> fixed_right_arg,HAllocationMode allocation_mode,BailoutId opt_id)10739 HValue* HGraphBuilder::BuildBinaryOperation(
10740     Token::Value op, HValue* left, HValue* right, AstType* left_type,
10741     AstType* right_type, AstType* result_type, Maybe<int> fixed_right_arg,
10742     HAllocationMode allocation_mode, BailoutId opt_id) {
10743   bool maybe_string_add = false;
10744   if (op == Token::ADD) {
10745     // If we are adding constant string with something for which we don't have
10746     // a feedback yet, assume that it's also going to be a string and don't
10747     // generate deopt instructions.
10748     if (!left_type->IsInhabited() && right->IsConstant() &&
10749         HConstant::cast(right)->HasStringValue()) {
10750       left_type = AstType::String();
10751     }
10752 
10753     if (!right_type->IsInhabited() && left->IsConstant() &&
10754         HConstant::cast(left)->HasStringValue()) {
10755       right_type = AstType::String();
10756     }
10757 
10758     maybe_string_add = (left_type->Maybe(AstType::String()) ||
10759                         left_type->Maybe(AstType::Receiver()) ||
10760                         right_type->Maybe(AstType::String()) ||
10761                         right_type->Maybe(AstType::Receiver()));
10762   }
10763 
10764   Representation left_rep = RepresentationFor(left_type);
10765   Representation right_rep = RepresentationFor(right_type);
10766 
10767   if (!left_type->IsInhabited()) {
10768     Add<HDeoptimize>(
10769         DeoptimizeReason::kInsufficientTypeFeedbackForLHSOfBinaryOperation,
10770         Deoptimizer::SOFT);
10771     left_type = AstType::Any();
10772     left_rep = RepresentationFor(left_type);
10773     maybe_string_add = op == Token::ADD;
10774   }
10775 
10776   if (!right_type->IsInhabited()) {
10777     Add<HDeoptimize>(
10778         DeoptimizeReason::kInsufficientTypeFeedbackForRHSOfBinaryOperation,
10779         Deoptimizer::SOFT);
10780     right_type = AstType::Any();
10781     right_rep = RepresentationFor(right_type);
10782     maybe_string_add = op == Token::ADD;
10783   }
10784 
10785   if (!maybe_string_add) {
10786     left = TruncateToNumber(left, &left_type);
10787     right = TruncateToNumber(right, &right_type);
10788   }
10789 
10790   // Special case for string addition here.
10791   if (op == Token::ADD &&
10792       (left_type->Is(AstType::String()) || right_type->Is(AstType::String()))) {
10793     // Validate type feedback for left argument.
10794     if (left_type->Is(AstType::String())) {
10795       left = BuildCheckString(left);
10796     }
10797 
10798     // Validate type feedback for right argument.
10799     if (right_type->Is(AstType::String())) {
10800       right = BuildCheckString(right);
10801     }
10802 
10803     // Convert left argument as necessary.
10804     if (left_type->Is(AstType::Number())) {
10805       DCHECK(right_type->Is(AstType::String()));
10806       left = BuildNumberToString(left, left_type);
10807     } else if (!left_type->Is(AstType::String())) {
10808       DCHECK(right_type->Is(AstType::String()));
10809       return AddUncasted<HStringAdd>(
10810           left, right, allocation_mode.GetPretenureMode(),
10811           STRING_ADD_CONVERT_LEFT, allocation_mode.feedback_site());
10812     }
10813 
10814     // Convert right argument as necessary.
10815     if (right_type->Is(AstType::Number())) {
10816       DCHECK(left_type->Is(AstType::String()));
10817       right = BuildNumberToString(right, right_type);
10818     } else if (!right_type->Is(AstType::String())) {
10819       DCHECK(left_type->Is(AstType::String()));
10820       return AddUncasted<HStringAdd>(
10821           left, right, allocation_mode.GetPretenureMode(),
10822           STRING_ADD_CONVERT_RIGHT, allocation_mode.feedback_site());
10823     }
10824 
10825     // Fast paths for empty constant strings.
10826     Handle<String> left_string =
10827         left->IsConstant() && HConstant::cast(left)->HasStringValue()
10828             ? HConstant::cast(left)->StringValue()
10829             : Handle<String>();
10830     Handle<String> right_string =
10831         right->IsConstant() && HConstant::cast(right)->HasStringValue()
10832             ? HConstant::cast(right)->StringValue()
10833             : Handle<String>();
10834     if (!left_string.is_null() && left_string->length() == 0) return right;
10835     if (!right_string.is_null() && right_string->length() == 0) return left;
10836     if (!left_string.is_null() && !right_string.is_null()) {
10837       return AddUncasted<HStringAdd>(
10838           left, right, allocation_mode.GetPretenureMode(),
10839           STRING_ADD_CHECK_NONE, allocation_mode.feedback_site());
10840     }
10841 
10842     // Register the dependent code with the allocation site.
10843     if (!allocation_mode.feedback_site().is_null()) {
10844       DCHECK(!graph()->info()->IsStub());
10845       Handle<AllocationSite> site(allocation_mode.feedback_site());
10846       top_info()->dependencies()->AssumeTenuringDecision(site);
10847     }
10848 
10849     // Inline the string addition into the stub when creating allocation
10850     // mementos to gather allocation site feedback, or if we can statically
10851     // infer that we're going to create a cons string.
10852     if ((graph()->info()->IsStub() &&
10853          allocation_mode.CreateAllocationMementos()) ||
10854         (left->IsConstant() &&
10855          HConstant::cast(left)->HasStringValue() &&
10856          HConstant::cast(left)->StringValue()->length() + 1 >=
10857            ConsString::kMinLength) ||
10858         (right->IsConstant() &&
10859          HConstant::cast(right)->HasStringValue() &&
10860          HConstant::cast(right)->StringValue()->length() + 1 >=
10861            ConsString::kMinLength)) {
10862       return BuildStringAdd(left, right, allocation_mode);
10863     }
10864 
10865     // Fallback to using the string add stub.
10866     return AddUncasted<HStringAdd>(
10867         left, right, allocation_mode.GetPretenureMode(), STRING_ADD_CHECK_NONE,
10868         allocation_mode.feedback_site());
10869   }
10870 
10871   // Special case for +x here.
10872   if (op == Token::MUL) {
10873     if (left->EqualsInteger32Constant(1)) {
10874       return BuildToNumber(right);
10875     }
10876     if (right->EqualsInteger32Constant(1)) {
10877       return BuildToNumber(left);
10878     }
10879   }
10880 
10881   if (graph()->info()->IsStub()) {
10882     left = EnforceNumberType(left, left_type);
10883     right = EnforceNumberType(right, right_type);
10884   }
10885 
10886   Representation result_rep = RepresentationFor(result_type);
10887 
10888   bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) ||
10889                           (right_rep.IsTagged() && !right_rep.IsSmi());
10890 
10891   HInstruction* instr = NULL;
10892   // Only the stub is allowed to call into the runtime, since otherwise we would
10893   // inline several instructions (including the two pushes) for every tagged
10894   // operation in optimized code, which is more expensive, than a stub call.
10895   if (graph()->info()->IsStub() && is_non_primitive) {
10896     HValue* values[] = {left, right};
10897 #define GET_STUB(Name)                                                       \
10898   do {                                                                       \
10899     Callable callable = CodeFactory::Name(isolate());                        \
10900     HValue* stub = Add<HConstant>(callable.code());                          \
10901     instr = AddUncasted<HCallWithDescriptor>(stub, 0, callable.descriptor(), \
10902                                              ArrayVector(values));           \
10903   } while (false)
10904 
10905     switch (op) {
10906       default:
10907         UNREACHABLE();
10908       case Token::ADD:
10909         GET_STUB(Add);
10910         break;
10911       case Token::SUB:
10912         GET_STUB(Subtract);
10913         break;
10914       case Token::MUL:
10915         GET_STUB(Multiply);
10916         break;
10917       case Token::DIV:
10918         GET_STUB(Divide);
10919         break;
10920       case Token::MOD:
10921         GET_STUB(Modulus);
10922         break;
10923       case Token::BIT_OR:
10924         GET_STUB(BitwiseOr);
10925         break;
10926       case Token::BIT_AND:
10927         GET_STUB(BitwiseAnd);
10928         break;
10929       case Token::BIT_XOR:
10930         GET_STUB(BitwiseXor);
10931         break;
10932       case Token::SAR:
10933         GET_STUB(ShiftRight);
10934         break;
10935       case Token::SHR:
10936         GET_STUB(ShiftRightLogical);
10937         break;
10938       case Token::SHL:
10939         GET_STUB(ShiftLeft);
10940         break;
10941     }
10942 #undef GET_STUB
10943   } else {
10944     switch (op) {
10945       case Token::ADD:
10946         instr = AddUncasted<HAdd>(left, right);
10947         break;
10948       case Token::SUB:
10949         instr = AddUncasted<HSub>(left, right);
10950         break;
10951       case Token::MUL:
10952         instr = AddUncasted<HMul>(left, right);
10953         break;
10954       case Token::MOD: {
10955         if (fixed_right_arg.IsJust() &&
10956             !right->EqualsInteger32Constant(fixed_right_arg.FromJust())) {
10957           HConstant* fixed_right =
10958               Add<HConstant>(static_cast<int>(fixed_right_arg.FromJust()));
10959           IfBuilder if_same(this);
10960           if_same.If<HCompareNumericAndBranch>(right, fixed_right, Token::EQ);
10961           if_same.Then();
10962           if_same.ElseDeopt(DeoptimizeReason::kUnexpectedRHSOfBinaryOperation);
10963           right = fixed_right;
10964         }
10965         instr = AddUncasted<HMod>(left, right);
10966         break;
10967       }
10968       case Token::DIV:
10969         instr = AddUncasted<HDiv>(left, right);
10970         break;
10971       case Token::BIT_XOR:
10972       case Token::BIT_AND:
10973         instr = AddUncasted<HBitwise>(op, left, right);
10974         break;
10975       case Token::BIT_OR: {
10976         HValue *operand, *shift_amount;
10977         if (left_type->Is(AstType::Signed32()) &&
10978             right_type->Is(AstType::Signed32()) &&
10979             MatchRotateRight(left, right, &operand, &shift_amount)) {
10980           instr = AddUncasted<HRor>(operand, shift_amount);
10981         } else {
10982           instr = AddUncasted<HBitwise>(op, left, right);
10983         }
10984         break;
10985       }
10986       case Token::SAR:
10987         instr = AddUncasted<HSar>(left, right);
10988         break;
10989       case Token::SHR:
10990         instr = AddUncasted<HShr>(left, right);
10991         if (instr->IsShr() && CanBeZero(right)) {
10992           graph()->RecordUint32Instruction(instr);
10993         }
10994         break;
10995       case Token::SHL:
10996         instr = AddUncasted<HShl>(left, right);
10997         break;
10998       default:
10999         UNREACHABLE();
11000     }
11001   }
11002 
11003   if (instr->IsBinaryOperation()) {
11004     HBinaryOperation* binop = HBinaryOperation::cast(instr);
11005     binop->set_observed_input_representation(1, left_rep);
11006     binop->set_observed_input_representation(2, right_rep);
11007     binop->initialize_output_representation(result_rep);
11008     if (graph()->info()->IsStub()) {
11009       // Stub should not call into stub.
11010       instr->SetFlag(HValue::kCannotBeTagged);
11011       // And should truncate on HForceRepresentation already.
11012       if (left->IsForceRepresentation()) {
11013         left->CopyFlag(HValue::kTruncatingToSmi, instr);
11014         left->CopyFlag(HValue::kTruncatingToInt32, instr);
11015       }
11016       if (right->IsForceRepresentation()) {
11017         right->CopyFlag(HValue::kTruncatingToSmi, instr);
11018         right->CopyFlag(HValue::kTruncatingToInt32, instr);
11019       }
11020     }
11021   }
11022   return instr;
11023 }
11024 
11025 
11026 // Check for the form (%_ClassOf(foo) === 'BarClass').
IsClassOfTest(CompareOperation * expr)11027 static bool IsClassOfTest(CompareOperation* expr) {
11028   if (expr->op() != Token::EQ_STRICT) return false;
11029   CallRuntime* call = expr->left()->AsCallRuntime();
11030   if (call == NULL) return false;
11031   Literal* literal = expr->right()->AsLiteral();
11032   if (literal == NULL) return false;
11033   if (!literal->value()->IsString()) return false;
11034   if (call->is_jsruntime()) return false;
11035   if (call->function()->function_id != Runtime::kInlineClassOf) return false;
11036   DCHECK_EQ(call->arguments()->length(), 1);
11037   return true;
11038 }
11039 
VisitBinaryOperation(BinaryOperation * expr)11040 void HOptimizedGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
11041   DCHECK(!HasStackOverflow());
11042   DCHECK(current_block() != NULL);
11043   DCHECK(current_block()->HasPredecessor());
11044   switch (expr->op()) {
11045     case Token::COMMA:
11046       return VisitComma(expr);
11047     case Token::OR:
11048     case Token::AND:
11049       return VisitLogicalExpression(expr);
11050     default:
11051       return VisitArithmeticExpression(expr);
11052   }
11053 }
11054 
11055 
VisitComma(BinaryOperation * expr)11056 void HOptimizedGraphBuilder::VisitComma(BinaryOperation* expr) {
11057   CHECK_ALIVE(VisitForEffect(expr->left()));
11058   // Visit the right subexpression in the same AST context as the entire
11059   // expression.
11060   Visit(expr->right());
11061 }
11062 
11063 
VisitLogicalExpression(BinaryOperation * expr)11064 void HOptimizedGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
11065   bool is_logical_and = expr->op() == Token::AND;
11066   if (ast_context()->IsTest()) {
11067     TestContext* context = TestContext::cast(ast_context());
11068     // Translate left subexpression.
11069     HBasicBlock* eval_right = graph()->CreateBasicBlock();
11070     if (is_logical_and) {
11071       CHECK_BAILOUT(VisitForControl(expr->left(),
11072                                     eval_right,
11073                                     context->if_false()));
11074     } else {
11075       CHECK_BAILOUT(VisitForControl(expr->left(),
11076                                     context->if_true(),
11077                                     eval_right));
11078     }
11079 
11080     // Translate right subexpression by visiting it in the same AST
11081     // context as the entire expression.
11082     CHECK(eval_right->HasPredecessor());
11083     eval_right->SetJoinId(expr->RightId());
11084     set_current_block(eval_right);
11085     Visit(expr->right());
11086   } else if (ast_context()->IsValue()) {
11087     CHECK_ALIVE(VisitForValue(expr->left()));
11088     DCHECK(current_block() != NULL);
11089     HValue* left_value = Top();
11090 
11091     // Short-circuit left values that always evaluate to the same boolean value.
11092     if (expr->left()->ToBooleanIsTrue() || expr->left()->ToBooleanIsFalse()) {
11093       // l (evals true)  && r -> r
11094       // l (evals true)  || r -> l
11095       // l (evals false) && r -> l
11096       // l (evals false) || r -> r
11097       if (is_logical_and == expr->left()->ToBooleanIsTrue()) {
11098         Drop(1);
11099         CHECK_ALIVE(VisitForValue(expr->right()));
11100       }
11101       return ast_context()->ReturnValue(Pop());
11102     }
11103 
11104     // We need an extra block to maintain edge-split form.
11105     HBasicBlock* empty_block = graph()->CreateBasicBlock();
11106     HBasicBlock* eval_right = graph()->CreateBasicBlock();
11107     ToBooleanHints expected(expr->left()->to_boolean_types());
11108     HBranch* test = is_logical_and
11109         ? New<HBranch>(left_value, expected, eval_right, empty_block)
11110         : New<HBranch>(left_value, expected, empty_block, eval_right);
11111     FinishCurrentBlock(test);
11112 
11113     set_current_block(eval_right);
11114     Drop(1);  // Value of the left subexpression.
11115     CHECK_BAILOUT(VisitForValue(expr->right()));
11116 
11117     HBasicBlock* join_block =
11118       CreateJoin(empty_block, current_block(), expr->id());
11119     set_current_block(join_block);
11120     return ast_context()->ReturnValue(Pop());
11121 
11122   } else {
11123     DCHECK(ast_context()->IsEffect());
11124     // In an effect context, we don't need the value of the left subexpression,
11125     // only its control flow and side effects.  We need an extra block to
11126     // maintain edge-split form.
11127     HBasicBlock* empty_block = graph()->CreateBasicBlock();
11128     HBasicBlock* right_block = graph()->CreateBasicBlock();
11129     if (is_logical_and) {
11130       CHECK_BAILOUT(VisitForControl(expr->left(), right_block, empty_block));
11131     } else {
11132       CHECK_BAILOUT(VisitForControl(expr->left(), empty_block, right_block));
11133     }
11134 
11135     // TODO(kmillikin): Find a way to fix this.  It's ugly that there are
11136     // actually two empty blocks (one here and one inserted by
11137     // TestContext::BuildBranch, and that they both have an HSimulate though the
11138     // second one is not a merge node, and that we really have no good AST ID to
11139     // put on that first HSimulate.
11140 
11141     // Technically, we should be able to handle the case when one side of
11142     // the test is not connected, but this can trip up liveness analysis
11143     // if we did not fully connect the test context based on some optimistic
11144     // assumption. If such an assumption was violated, we would end up with
11145     // an environment with optimized-out values. So we should always
11146     // conservatively connect the test context.
11147 
11148     CHECK(right_block->HasPredecessor());
11149     CHECK(empty_block->HasPredecessor());
11150 
11151     empty_block->SetJoinId(expr->id());
11152 
11153     right_block->SetJoinId(expr->RightId());
11154     set_current_block(right_block);
11155     CHECK_BAILOUT(VisitForEffect(expr->right()));
11156     right_block = current_block();
11157 
11158     HBasicBlock* join_block =
11159       CreateJoin(empty_block, right_block, expr->id());
11160     set_current_block(join_block);
11161     // We did not materialize any value in the predecessor environments,
11162     // so there is no need to handle it here.
11163   }
11164 }
11165 
11166 
VisitArithmeticExpression(BinaryOperation * expr)11167 void HOptimizedGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) {
11168   CHECK_ALIVE(VisitForValue(expr->left()));
11169   CHECK_ALIVE(VisitForValue(expr->right()));
11170   SetSourcePosition(expr->position());
11171   HValue* right = Pop();
11172   HValue* left = Pop();
11173   HValue* result =
11174       BuildBinaryOperation(expr, left, right,
11175           ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE
11176                                     : PUSH_BEFORE_SIMULATE);
11177   return ast_context()->ReturnValue(result);
11178 }
11179 
11180 
HandleLiteralCompareTypeof(CompareOperation * expr,Expression * sub_expr,Handle<String> check)11181 void HOptimizedGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr,
11182                                                         Expression* sub_expr,
11183                                                         Handle<String> check) {
11184   CHECK_ALIVE(VisitForTypeOf(sub_expr));
11185   SetSourcePosition(expr->position());
11186   HValue* value = Pop();
11187   HTypeofIsAndBranch* instr = New<HTypeofIsAndBranch>(value, check);
11188   return ast_context()->ReturnControl(instr, expr->id());
11189 }
11190 
11191 namespace {
11192 
IsLiteralCompareStrict(Isolate * isolate,HValue * left,Token::Value op,HValue * right)11193 bool IsLiteralCompareStrict(Isolate* isolate, HValue* left, Token::Value op,
11194                             HValue* right) {
11195   return op == Token::EQ_STRICT &&
11196          ((left->IsConstant() &&
11197            !HConstant::cast(left)->handle(isolate)->IsNumber() &&
11198            !HConstant::cast(left)->handle(isolate)->IsString()) ||
11199           (right->IsConstant() &&
11200            !HConstant::cast(right)->handle(isolate)->IsNumber() &&
11201            !HConstant::cast(right)->handle(isolate)->IsString()));
11202 }
11203 
11204 }  // namespace
11205 
VisitCompareOperation(CompareOperation * expr)11206 void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
11207   DCHECK(!HasStackOverflow());
11208   DCHECK(current_block() != NULL);
11209   DCHECK(current_block()->HasPredecessor());
11210 
11211   if (!is_tracking_positions()) SetSourcePosition(expr->position());
11212 
11213   // Check for a few fast cases. The AST visiting behavior must be in sync
11214   // with the full codegen: We don't push both left and right values onto
11215   // the expression stack when one side is a special-case literal.
11216   Expression* sub_expr = NULL;
11217   Handle<String> check;
11218   if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) {
11219     return HandleLiteralCompareTypeof(expr, sub_expr, check);
11220   }
11221   if (expr->IsLiteralCompareUndefined(&sub_expr)) {
11222     return HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue);
11223   }
11224   if (expr->IsLiteralCompareNull(&sub_expr)) {
11225     return HandleLiteralCompareNil(expr, sub_expr, kNullValue);
11226   }
11227 
11228   if (IsClassOfTest(expr)) {
11229     CallRuntime* call = expr->left()->AsCallRuntime();
11230     DCHECK(call->arguments()->length() == 1);
11231     CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11232     HValue* value = Pop();
11233     Literal* literal = expr->right()->AsLiteral();
11234     Handle<String> rhs = Handle<String>::cast(literal->value());
11235     HClassOfTestAndBranch* instr = New<HClassOfTestAndBranch>(value, rhs);
11236     return ast_context()->ReturnControl(instr, expr->id());
11237   }
11238 
11239   AstType* left_type = bounds_.get(expr->left()).lower;
11240   AstType* right_type = bounds_.get(expr->right()).lower;
11241   AstType* combined_type = expr->combined_type();
11242 
11243   CHECK_ALIVE(VisitForValue(expr->left()));
11244   CHECK_ALIVE(VisitForValue(expr->right()));
11245 
11246   HValue* right = Pop();
11247   HValue* left = Pop();
11248   Token::Value op = expr->op();
11249 
11250   if (IsLiteralCompareStrict(isolate(), left, op, right)) {
11251     HCompareObjectEqAndBranch* result =
11252         New<HCompareObjectEqAndBranch>(left, right);
11253     return ast_context()->ReturnControl(result, expr->id());
11254   }
11255 
11256   if (op == Token::INSTANCEOF) {
11257     // Check to see if the rhs of the instanceof is a known function.
11258     if (right->IsConstant() &&
11259         HConstant::cast(right)->handle(isolate())->IsJSFunction()) {
11260       Handle<JSFunction> function =
11261           Handle<JSFunction>::cast(HConstant::cast(right)->handle(isolate()));
11262       // Make sure that the {function} already has a meaningful initial map
11263       // (i.e. we constructed at least one instance using the constructor
11264       // {function}), and has an instance as .prototype.
11265       if (function->has_initial_map() &&
11266           !function->map()->has_non_instance_prototype()) {
11267         // Lookup @@hasInstance on the {function}.
11268         Handle<Map> function_map(function->map(), isolate());
11269         PropertyAccessInfo has_instance(
11270             this, LOAD, function_map,
11271             isolate()->factory()->has_instance_symbol());
11272         // Check if we are using the Function.prototype[@@hasInstance].
11273         if (has_instance.CanAccessMonomorphic() &&
11274             has_instance.IsDataConstant() &&
11275             has_instance.constant().is_identical_to(
11276                 isolate()->function_has_instance())) {
11277           // Add appropriate receiver map check and prototype chain
11278           // checks to guard the @@hasInstance lookup chain.
11279           AddCheckMap(right, function_map);
11280           if (has_instance.has_holder()) {
11281             Handle<JSObject> prototype(
11282                 JSObject::cast(has_instance.map()->prototype()), isolate());
11283             BuildCheckPrototypeMaps(prototype, has_instance.holder());
11284           }
11285           // Perform the prototype chain walk.
11286           Handle<Map> initial_map(function->initial_map(), isolate());
11287           top_info()->dependencies()->AssumeInitialMapCantChange(initial_map);
11288           HInstruction* prototype =
11289               Add<HConstant>(handle(initial_map->prototype(), isolate()));
11290           HHasInPrototypeChainAndBranch* result =
11291               New<HHasInPrototypeChainAndBranch>(left, prototype);
11292           return ast_context()->ReturnControl(result, expr->id());
11293         }
11294       }
11295     }
11296 
11297     Callable callable = CodeFactory::InstanceOf(isolate());
11298     HValue* stub = Add<HConstant>(callable.code());
11299     HValue* values[] = {left, right};
11300     HCallWithDescriptor* result = New<HCallWithDescriptor>(
11301         stub, 0, callable.descriptor(), ArrayVector(values));
11302     result->set_type(HType::Boolean());
11303     return ast_context()->ReturnInstruction(result, expr->id());
11304 
11305   } else if (op == Token::IN) {
11306     Callable callable = CodeFactory::HasProperty(isolate());
11307     HValue* stub = Add<HConstant>(callable.code());
11308     HValue* values[] = {left, right};
11309     HInstruction* result =
11310         New<HCallWithDescriptor>(stub, 0, callable.descriptor(),
11311                                  Vector<HValue*>(values, arraysize(values)));
11312     return ast_context()->ReturnInstruction(result, expr->id());
11313   }
11314 
11315   PushBeforeSimulateBehavior push_behavior =
11316     ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE
11317                               : PUSH_BEFORE_SIMULATE;
11318   HControlInstruction* compare = BuildCompareInstruction(
11319       op, left, right, left_type, right_type, combined_type,
11320       ScriptPositionToSourcePosition(expr->left()->position()),
11321       ScriptPositionToSourcePosition(expr->right()->position()),
11322       push_behavior, expr->id());
11323   if (compare == NULL) return;  // Bailed out.
11324   return ast_context()->ReturnControl(compare, expr->id());
11325 }
11326 
BuildCompareInstruction(Token::Value op,HValue * left,HValue * right,AstType * left_type,AstType * right_type,AstType * combined_type,SourcePosition left_position,SourcePosition right_position,PushBeforeSimulateBehavior push_sim_result,BailoutId bailout_id)11327 HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction(
11328     Token::Value op, HValue* left, HValue* right, AstType* left_type,
11329     AstType* right_type, AstType* combined_type, SourcePosition left_position,
11330     SourcePosition right_position, PushBeforeSimulateBehavior push_sim_result,
11331     BailoutId bailout_id) {
11332   // Cases handled below depend on collected type feedback. They should
11333   // soft deoptimize when there is no type feedback.
11334   if (!combined_type->IsInhabited()) {
11335     Add<HDeoptimize>(
11336         DeoptimizeReason::
11337             kInsufficientTypeFeedbackForCombinedTypeOfBinaryOperation,
11338         Deoptimizer::SOFT);
11339     combined_type = left_type = right_type = AstType::Any();
11340   }
11341 
11342   Representation left_rep = RepresentationFor(left_type);
11343   Representation right_rep = RepresentationFor(right_type);
11344   Representation combined_rep = RepresentationFor(combined_type);
11345 
11346   if (combined_type->Is(AstType::Receiver())) {
11347     if (Token::IsEqualityOp(op)) {
11348       // HCompareObjectEqAndBranch can only deal with object, so
11349       // exclude numbers.
11350       if ((left->IsConstant() &&
11351            HConstant::cast(left)->HasNumberValue()) ||
11352           (right->IsConstant() &&
11353            HConstant::cast(right)->HasNumberValue())) {
11354         Add<HDeoptimize>(
11355             DeoptimizeReason::kTypeMismatchBetweenFeedbackAndConstant,
11356             Deoptimizer::SOFT);
11357         // The caller expects a branch instruction, so make it happy.
11358         return New<HBranch>(graph()->GetConstantTrue());
11359       }
11360       if (op == Token::EQ) {
11361         // For abstract equality we need to check both sides are receivers.
11362         if (combined_type->IsClass()) {
11363           Handle<Map> map = combined_type->AsClass()->Map();
11364           AddCheckMap(left, map);
11365           AddCheckMap(right, map);
11366         } else {
11367           BuildCheckHeapObject(left);
11368           Add<HCheckInstanceType>(left, HCheckInstanceType::IS_JS_RECEIVER);
11369           BuildCheckHeapObject(right);
11370           Add<HCheckInstanceType>(right, HCheckInstanceType::IS_JS_RECEIVER);
11371         }
11372       } else {
11373         // For strict equality we only need to check one side.
11374         HValue* operand_to_check =
11375             left->block()->block_id() < right->block()->block_id() ? left
11376                                                                    : right;
11377         if (combined_type->IsClass()) {
11378           Handle<Map> map = combined_type->AsClass()->Map();
11379           AddCheckMap(operand_to_check, map);
11380         } else {
11381           BuildCheckHeapObject(operand_to_check);
11382           Add<HCheckInstanceType>(operand_to_check,
11383                                   HCheckInstanceType::IS_JS_RECEIVER);
11384         }
11385       }
11386       HCompareObjectEqAndBranch* result =
11387           New<HCompareObjectEqAndBranch>(left, right);
11388       return result;
11389     } else {
11390       if (combined_type->IsClass()) {
11391         // TODO(bmeurer): This is an optimized version of an x < y, x > y,
11392         // x <= y or x >= y, where both x and y are spec objects with the
11393         // same map. The CompareIC collects this map for us. So if we know
11394         // that there's no @@toPrimitive on the map (including the prototype
11395         // chain), and both valueOf and toString are the default initial
11396         // implementations (on the %ObjectPrototype%), then we can reduce
11397         // the comparison to map checks on x and y, because the comparison
11398         // will turn into a comparison of "[object CLASS]" to itself (the
11399         // default outcome of toString, since valueOf returns a spec object).
11400         // This is pretty much adhoc, so in TurboFan we could do a lot better
11401         // and inline the interesting parts of ToPrimitive (actually we could
11402         // even do that in Crankshaft but we don't want to waste too much
11403         // time on this now).
11404         DCHECK(Token::IsOrderedRelationalCompareOp(op));
11405         Handle<Map> map = combined_type->AsClass()->Map();
11406         PropertyAccessInfo value_of(this, LOAD, map,
11407                                     isolate()->factory()->valueOf_string());
11408         PropertyAccessInfo to_primitive(
11409             this, LOAD, map, isolate()->factory()->to_primitive_symbol());
11410         PropertyAccessInfo to_string(this, LOAD, map,
11411                                      isolate()->factory()->toString_string());
11412         PropertyAccessInfo to_string_tag(
11413             this, LOAD, map, isolate()->factory()->to_string_tag_symbol());
11414         if (to_primitive.CanAccessMonomorphic() && !to_primitive.IsFound() &&
11415             to_string_tag.CanAccessMonomorphic() &&
11416             (!to_string_tag.IsFound() || to_string_tag.IsData() ||
11417              to_string_tag.IsDataConstant()) &&
11418             value_of.CanAccessMonomorphic() && value_of.IsDataConstant() &&
11419             value_of.constant().is_identical_to(isolate()->object_value_of()) &&
11420             to_string.CanAccessMonomorphic() && to_string.IsDataConstant() &&
11421             to_string.constant().is_identical_to(
11422                 isolate()->object_to_string())) {
11423           // We depend on the prototype chain to stay the same, because we
11424           // also need to deoptimize when someone installs @@toPrimitive
11425           // or @@toStringTag somewhere in the prototype chain.
11426           Handle<Object> prototype(map->prototype(), isolate());
11427           if (prototype->IsJSObject()) {
11428             BuildCheckPrototypeMaps(Handle<JSObject>::cast(prototype),
11429                                     Handle<JSObject>::null());
11430           }
11431           AddCheckMap(left, map);
11432           AddCheckMap(right, map);
11433           // The caller expects a branch instruction, so make it happy.
11434           return New<HBranch>(
11435               graph()->GetConstantBool(op == Token::LTE || op == Token::GTE));
11436         }
11437       }
11438       Bailout(kUnsupportedNonPrimitiveCompare);
11439       return NULL;
11440     }
11441   } else if (combined_type->Is(AstType::InternalizedString()) &&
11442              Token::IsEqualityOp(op)) {
11443     // If we have a constant argument, it should be consistent with the type
11444     // feedback (otherwise we fail assertions in HCompareObjectEqAndBranch).
11445     if ((left->IsConstant() &&
11446          !HConstant::cast(left)->HasInternalizedStringValue()) ||
11447         (right->IsConstant() &&
11448          !HConstant::cast(right)->HasInternalizedStringValue())) {
11449       Add<HDeoptimize>(
11450           DeoptimizeReason::kTypeMismatchBetweenFeedbackAndConstant,
11451           Deoptimizer::SOFT);
11452       // The caller expects a branch instruction, so make it happy.
11453       return New<HBranch>(graph()->GetConstantTrue());
11454     }
11455     BuildCheckHeapObject(left);
11456     Add<HCheckInstanceType>(left, HCheckInstanceType::IS_INTERNALIZED_STRING);
11457     BuildCheckHeapObject(right);
11458     Add<HCheckInstanceType>(right, HCheckInstanceType::IS_INTERNALIZED_STRING);
11459     HCompareObjectEqAndBranch* result =
11460         New<HCompareObjectEqAndBranch>(left, right);
11461     return result;
11462   } else if (combined_type->Is(AstType::String())) {
11463     BuildCheckHeapObject(left);
11464     Add<HCheckInstanceType>(left, HCheckInstanceType::IS_STRING);
11465     BuildCheckHeapObject(right);
11466     Add<HCheckInstanceType>(right, HCheckInstanceType::IS_STRING);
11467     HStringCompareAndBranch* result =
11468         New<HStringCompareAndBranch>(left, right, op);
11469     return result;
11470   } else if (combined_type->Is(AstType::Boolean())) {
11471     AddCheckMap(left, isolate()->factory()->boolean_map());
11472     AddCheckMap(right, isolate()->factory()->boolean_map());
11473     if (Token::IsEqualityOp(op)) {
11474       HCompareObjectEqAndBranch* result =
11475           New<HCompareObjectEqAndBranch>(left, right);
11476       return result;
11477     }
11478     left = Add<HLoadNamedField>(
11479         left, nullptr,
11480         HObjectAccess::ForOddballToNumber(Representation::Smi()));
11481     right = Add<HLoadNamedField>(
11482         right, nullptr,
11483         HObjectAccess::ForOddballToNumber(Representation::Smi()));
11484     HCompareNumericAndBranch* result =
11485         New<HCompareNumericAndBranch>(left, right, op);
11486     return result;
11487   } else {
11488     if (op == Token::EQ) {
11489       if (left->IsConstant() &&
11490           HConstant::cast(left)->GetInstanceType() == ODDBALL_TYPE &&
11491           HConstant::cast(left)->IsUndetectable()) {
11492         return New<HIsUndetectableAndBranch>(right);
11493       }
11494 
11495       if (right->IsConstant() &&
11496           HConstant::cast(right)->GetInstanceType() == ODDBALL_TYPE &&
11497           HConstant::cast(right)->IsUndetectable()) {
11498         return New<HIsUndetectableAndBranch>(left);
11499       }
11500     }
11501 
11502     if (combined_rep.IsTagged() || combined_rep.IsNone()) {
11503       HCompareGeneric* result = Add<HCompareGeneric>(left, right, op);
11504       result->set_observed_input_representation(1, left_rep);
11505       result->set_observed_input_representation(2, right_rep);
11506       if (result->HasObservableSideEffects()) {
11507         if (push_sim_result == PUSH_BEFORE_SIMULATE) {
11508           Push(result);
11509           AddSimulate(bailout_id, REMOVABLE_SIMULATE);
11510           Drop(1);
11511         } else {
11512           AddSimulate(bailout_id, REMOVABLE_SIMULATE);
11513         }
11514       }
11515       // TODO(jkummerow): Can we make this more efficient?
11516       HBranch* branch = New<HBranch>(result);
11517       return branch;
11518     } else {
11519       HCompareNumericAndBranch* result =
11520           New<HCompareNumericAndBranch>(left, right, op);
11521       result->set_observed_input_representation(left_rep, right_rep);
11522       return result;
11523     }
11524   }
11525 }
11526 
11527 
HandleLiteralCompareNil(CompareOperation * expr,Expression * sub_expr,NilValue nil)11528 void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
11529                                                      Expression* sub_expr,
11530                                                      NilValue nil) {
11531   DCHECK(!HasStackOverflow());
11532   DCHECK(current_block() != NULL);
11533   DCHECK(current_block()->HasPredecessor());
11534   DCHECK(expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT);
11535   if (!is_tracking_positions()) SetSourcePosition(expr->position());
11536   CHECK_ALIVE(VisitForValue(sub_expr));
11537   HValue* value = Pop();
11538   HControlInstruction* instr;
11539   if (expr->op() == Token::EQ_STRICT) {
11540     HConstant* nil_constant = nil == kNullValue
11541         ? graph()->GetConstantNull()
11542         : graph()->GetConstantUndefined();
11543     instr = New<HCompareObjectEqAndBranch>(value, nil_constant);
11544   } else {
11545     DCHECK_EQ(Token::EQ, expr->op());
11546     instr = New<HIsUndetectableAndBranch>(value);
11547   }
11548   return ast_context()->ReturnControl(instr, expr->id());
11549 }
11550 
11551 
VisitSpread(Spread * expr)11552 void HOptimizedGraphBuilder::VisitSpread(Spread* expr) { UNREACHABLE(); }
11553 
11554 
VisitEmptyParentheses(EmptyParentheses * expr)11555 void HOptimizedGraphBuilder::VisitEmptyParentheses(EmptyParentheses* expr) {
11556   UNREACHABLE();
11557 }
11558 
VisitGetIterator(GetIterator * expr)11559 void HOptimizedGraphBuilder::VisitGetIterator(GetIterator* expr) {
11560   UNREACHABLE();
11561 }
11562 
AddThisFunction()11563 HValue* HOptimizedGraphBuilder::AddThisFunction() {
11564   return AddInstruction(BuildThisFunction());
11565 }
11566 
11567 
BuildThisFunction()11568 HInstruction* HOptimizedGraphBuilder::BuildThisFunction() {
11569   // If we share optimized code between different closures, the
11570   // this-function is not a constant, except inside an inlined body.
11571   if (function_state()->outer() != NULL) {
11572       return New<HConstant>(
11573           function_state()->compilation_info()->closure());
11574   } else {
11575       return New<HThisFunction>();
11576   }
11577 }
11578 
11579 
BuildFastLiteral(Handle<JSObject> boilerplate_object,AllocationSiteUsageContext * site_context)11580 HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
11581     Handle<JSObject> boilerplate_object,
11582     AllocationSiteUsageContext* site_context) {
11583   NoObservableSideEffectsScope no_effects(this);
11584   Handle<Map> initial_map(boilerplate_object->map());
11585   InstanceType instance_type = initial_map->instance_type();
11586   DCHECK(instance_type == JS_ARRAY_TYPE || instance_type == JS_OBJECT_TYPE);
11587 
11588   HType type = instance_type == JS_ARRAY_TYPE
11589       ? HType::JSArray() : HType::JSObject();
11590   HValue* object_size_constant = Add<HConstant>(initial_map->instance_size());
11591 
11592   PretenureFlag pretenure_flag = NOT_TENURED;
11593   Handle<AllocationSite> top_site(*site_context->top(), isolate());
11594   if (FLAG_allocation_site_pretenuring) {
11595     pretenure_flag = top_site->GetPretenureMode();
11596   }
11597 
11598   Handle<AllocationSite> current_site(*site_context->current(), isolate());
11599   if (*top_site == *current_site) {
11600     // We install a dependency for pretenuring only on the outermost literal.
11601     top_info()->dependencies()->AssumeTenuringDecision(top_site);
11602   }
11603   top_info()->dependencies()->AssumeTransitionStable(current_site);
11604 
11605   HInstruction* object =
11606       Add<HAllocate>(object_size_constant, type, pretenure_flag, instance_type,
11607                      graph()->GetConstant0(), top_site);
11608 
11609   // If allocation folding reaches kMaxRegularHeapObjectSize the
11610   // elements array may not get folded into the object. Hence, we set the
11611   // elements pointer to empty fixed array and let store elimination remove
11612   // this store in the folding case.
11613   HConstant* empty_fixed_array = Add<HConstant>(
11614       isolate()->factory()->empty_fixed_array());
11615   Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
11616       empty_fixed_array);
11617 
11618   BuildEmitObjectHeader(boilerplate_object, object);
11619 
11620   // Similarly to the elements pointer, there is no guarantee that all
11621   // property allocations can get folded, so pre-initialize all in-object
11622   // properties to a safe value.
11623   BuildInitializeInobjectProperties(object, initial_map);
11624 
11625   Handle<FixedArrayBase> elements(boilerplate_object->elements());
11626   int elements_size = (elements->length() > 0 &&
11627       elements->map() != isolate()->heap()->fixed_cow_array_map()) ?
11628           elements->Size() : 0;
11629 
11630   if (pretenure_flag == TENURED &&
11631       elements->map() == isolate()->heap()->fixed_cow_array_map() &&
11632       isolate()->heap()->InNewSpace(*elements)) {
11633     // If we would like to pretenure a fixed cow array, we must ensure that the
11634     // array is already in old space, otherwise we'll create too many old-to-
11635     // new-space pointers (overflowing the store buffer).
11636     elements = Handle<FixedArrayBase>(
11637         isolate()->factory()->CopyAndTenureFixedCOWArray(
11638             Handle<FixedArray>::cast(elements)));
11639     boilerplate_object->set_elements(*elements);
11640   }
11641 
11642   HInstruction* object_elements = NULL;
11643   if (elements_size > 0) {
11644     HValue* object_elements_size = Add<HConstant>(elements_size);
11645     InstanceType instance_type = boilerplate_object->HasFastDoubleElements()
11646         ? FIXED_DOUBLE_ARRAY_TYPE : FIXED_ARRAY_TYPE;
11647     object_elements = Add<HAllocate>(object_elements_size, HType::HeapObject(),
11648                                      pretenure_flag, instance_type,
11649                                      graph()->GetConstant0(), top_site);
11650     BuildEmitElements(boilerplate_object, elements, object_elements,
11651                       site_context);
11652     Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
11653                           object_elements);
11654   } else {
11655     Handle<Object> elements_field =
11656         Handle<Object>(boilerplate_object->elements(), isolate());
11657     HInstruction* object_elements_cow = Add<HConstant>(elements_field);
11658     Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
11659                           object_elements_cow);
11660   }
11661 
11662   // Copy in-object properties.
11663   if (initial_map->NumberOfFields() != 0 ||
11664       initial_map->unused_property_fields() > 0) {
11665     BuildEmitInObjectProperties(boilerplate_object, object, site_context,
11666                                 pretenure_flag);
11667   }
11668   return object;
11669 }
11670 
11671 
BuildEmitObjectHeader(Handle<JSObject> boilerplate_object,HInstruction * object)11672 void HOptimizedGraphBuilder::BuildEmitObjectHeader(
11673     Handle<JSObject> boilerplate_object,
11674     HInstruction* object) {
11675   DCHECK(boilerplate_object->properties()->length() == 0);
11676 
11677   Handle<Map> boilerplate_object_map(boilerplate_object->map());
11678   AddStoreMapConstant(object, boilerplate_object_map);
11679 
11680   Handle<Object> properties_field =
11681       Handle<Object>(boilerplate_object->properties(), isolate());
11682   DCHECK(*properties_field == isolate()->heap()->empty_fixed_array());
11683   HInstruction* properties = Add<HConstant>(properties_field);
11684   HObjectAccess access = HObjectAccess::ForPropertiesPointer();
11685   Add<HStoreNamedField>(object, access, properties);
11686 
11687   if (boilerplate_object->IsJSArray()) {
11688     Handle<JSArray> boilerplate_array =
11689         Handle<JSArray>::cast(boilerplate_object);
11690     Handle<Object> length_field =
11691         Handle<Object>(boilerplate_array->length(), isolate());
11692     HInstruction* length = Add<HConstant>(length_field);
11693 
11694     DCHECK(boilerplate_array->length()->IsSmi());
11695     Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(
11696         boilerplate_array->GetElementsKind()), length);
11697   }
11698 }
11699 
11700 
BuildEmitInObjectProperties(Handle<JSObject> boilerplate_object,HInstruction * object,AllocationSiteUsageContext * site_context,PretenureFlag pretenure_flag)11701 void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
11702     Handle<JSObject> boilerplate_object,
11703     HInstruction* object,
11704     AllocationSiteUsageContext* site_context,
11705     PretenureFlag pretenure_flag) {
11706   Handle<Map> boilerplate_map(boilerplate_object->map());
11707   Handle<DescriptorArray> descriptors(boilerplate_map->instance_descriptors());
11708   int limit = boilerplate_map->NumberOfOwnDescriptors();
11709 
11710   int copied_fields = 0;
11711   for (int i = 0; i < limit; i++) {
11712     PropertyDetails details = descriptors->GetDetails(i);
11713     if (details.location() != kField) continue;
11714     DCHECK_EQ(kData, details.kind());
11715     copied_fields++;
11716     FieldIndex field_index = FieldIndex::ForDescriptor(*boilerplate_map, i);
11717 
11718 
11719     int property_offset = field_index.offset();
11720     Handle<Name> name(descriptors->GetKey(i));
11721 
11722     // The access for the store depends on the type of the boilerplate.
11723     HObjectAccess access = boilerplate_object->IsJSArray() ?
11724         HObjectAccess::ForJSArrayOffset(property_offset) :
11725         HObjectAccess::ForMapAndOffset(boilerplate_map, property_offset);
11726 
11727     if (boilerplate_object->IsUnboxedDoubleField(field_index)) {
11728       CHECK(!boilerplate_object->IsJSArray());
11729       double value = boilerplate_object->RawFastDoublePropertyAt(field_index);
11730       access = access.WithRepresentation(Representation::Double());
11731       Add<HStoreNamedField>(object, access, Add<HConstant>(value));
11732       continue;
11733     }
11734     Handle<Object> value(boilerplate_object->RawFastPropertyAt(field_index),
11735                          isolate());
11736 
11737     if (value->IsJSObject()) {
11738       Handle<JSObject> value_object = Handle<JSObject>::cast(value);
11739       Handle<AllocationSite> current_site = site_context->EnterNewScope();
11740       HInstruction* result =
11741           BuildFastLiteral(value_object, site_context);
11742       site_context->ExitScope(current_site, value_object);
11743       Add<HStoreNamedField>(object, access, result);
11744     } else {
11745       Representation representation = details.representation();
11746       HInstruction* value_instruction;
11747 
11748       if (representation.IsDouble()) {
11749         // Allocate a HeapNumber box and store the value into it.
11750         HValue* heap_number_constant = Add<HConstant>(HeapNumber::kSize);
11751         HInstruction* double_box = Add<HAllocate>(
11752             heap_number_constant, HType::HeapObject(), pretenure_flag,
11753             MUTABLE_HEAP_NUMBER_TYPE, graph()->GetConstant0());
11754         AddStoreMapConstant(double_box,
11755             isolate()->factory()->mutable_heap_number_map());
11756         // Unwrap the mutable heap number from the boilerplate.
11757         HValue* double_value =
11758             Add<HConstant>(Handle<HeapNumber>::cast(value)->value());
11759         Add<HStoreNamedField>(
11760             double_box, HObjectAccess::ForHeapNumberValue(), double_value);
11761         value_instruction = double_box;
11762       } else if (representation.IsSmi()) {
11763         value_instruction = value->IsUninitialized(isolate())
11764                                 ? graph()->GetConstant0()
11765                                 : Add<HConstant>(value);
11766         // Ensure that value is stored as smi.
11767         access = access.WithRepresentation(representation);
11768       } else {
11769         value_instruction = Add<HConstant>(value);
11770       }
11771 
11772       Add<HStoreNamedField>(object, access, value_instruction);
11773     }
11774   }
11775 
11776   int inobject_properties = boilerplate_object->map()->GetInObjectProperties();
11777   HInstruction* value_instruction =
11778       Add<HConstant>(isolate()->factory()->one_pointer_filler_map());
11779   for (int i = copied_fields; i < inobject_properties; i++) {
11780     DCHECK(boilerplate_object->IsJSObject());
11781     int property_offset = boilerplate_object->GetInObjectPropertyOffset(i);
11782     HObjectAccess access =
11783         HObjectAccess::ForMapAndOffset(boilerplate_map, property_offset);
11784     Add<HStoreNamedField>(object, access, value_instruction);
11785   }
11786 }
11787 
11788 
BuildEmitElements(Handle<JSObject> boilerplate_object,Handle<FixedArrayBase> elements,HValue * object_elements,AllocationSiteUsageContext * site_context)11789 void HOptimizedGraphBuilder::BuildEmitElements(
11790     Handle<JSObject> boilerplate_object,
11791     Handle<FixedArrayBase> elements,
11792     HValue* object_elements,
11793     AllocationSiteUsageContext* site_context) {
11794   ElementsKind kind = boilerplate_object->map()->elements_kind();
11795   int elements_length = elements->length();
11796   HValue* object_elements_length = Add<HConstant>(elements_length);
11797   BuildInitializeElementsHeader(object_elements, kind, object_elements_length);
11798 
11799   // Copy elements backing store content.
11800   if (elements->IsFixedDoubleArray()) {
11801     BuildEmitFixedDoubleArray(elements, kind, object_elements);
11802   } else if (elements->IsFixedArray()) {
11803     BuildEmitFixedArray(elements, kind, object_elements,
11804                         site_context);
11805   } else {
11806     UNREACHABLE();
11807   }
11808 }
11809 
11810 
BuildEmitFixedDoubleArray(Handle<FixedArrayBase> elements,ElementsKind kind,HValue * object_elements)11811 void HOptimizedGraphBuilder::BuildEmitFixedDoubleArray(
11812     Handle<FixedArrayBase> elements,
11813     ElementsKind kind,
11814     HValue* object_elements) {
11815   HInstruction* boilerplate_elements = Add<HConstant>(elements);
11816   int elements_length = elements->length();
11817   for (int i = 0; i < elements_length; i++) {
11818     HValue* key_constant = Add<HConstant>(i);
11819     HInstruction* value_instruction =
11820         Add<HLoadKeyed>(boilerplate_elements, key_constant, nullptr, nullptr,
11821                         kind, ALLOW_RETURN_HOLE);
11822     HInstruction* store = Add<HStoreKeyed>(object_elements, key_constant,
11823                                            value_instruction, nullptr, kind);
11824     store->SetFlag(HValue::kTruncatingToNumber);
11825   }
11826 }
11827 
11828 
BuildEmitFixedArray(Handle<FixedArrayBase> elements,ElementsKind kind,HValue * object_elements,AllocationSiteUsageContext * site_context)11829 void HOptimizedGraphBuilder::BuildEmitFixedArray(
11830     Handle<FixedArrayBase> elements,
11831     ElementsKind kind,
11832     HValue* object_elements,
11833     AllocationSiteUsageContext* site_context) {
11834   HInstruction* boilerplate_elements = Add<HConstant>(elements);
11835   int elements_length = elements->length();
11836   Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
11837   for (int i = 0; i < elements_length; i++) {
11838     Handle<Object> value(fast_elements->get(i), isolate());
11839     HValue* key_constant = Add<HConstant>(i);
11840     if (value->IsJSObject()) {
11841       Handle<JSObject> value_object = Handle<JSObject>::cast(value);
11842       Handle<AllocationSite> current_site = site_context->EnterNewScope();
11843       HInstruction* result =
11844           BuildFastLiteral(value_object, site_context);
11845       site_context->ExitScope(current_site, value_object);
11846       Add<HStoreKeyed>(object_elements, key_constant, result, nullptr, kind);
11847     } else {
11848       ElementsKind copy_kind =
11849           kind == FAST_HOLEY_SMI_ELEMENTS ? FAST_HOLEY_ELEMENTS : kind;
11850       HInstruction* value_instruction =
11851           Add<HLoadKeyed>(boilerplate_elements, key_constant, nullptr, nullptr,
11852                           copy_kind, ALLOW_RETURN_HOLE);
11853       Add<HStoreKeyed>(object_elements, key_constant, value_instruction,
11854                        nullptr, copy_kind);
11855     }
11856   }
11857 }
11858 
11859 
VisitThisFunction(ThisFunction * expr)11860 void HOptimizedGraphBuilder::VisitThisFunction(ThisFunction* expr) {
11861   DCHECK(!HasStackOverflow());
11862   DCHECK(current_block() != NULL);
11863   DCHECK(current_block()->HasPredecessor());
11864   HInstruction* instr = BuildThisFunction();
11865   return ast_context()->ReturnInstruction(instr, expr->id());
11866 }
11867 
11868 
VisitSuperPropertyReference(SuperPropertyReference * expr)11869 void HOptimizedGraphBuilder::VisitSuperPropertyReference(
11870     SuperPropertyReference* expr) {
11871   DCHECK(!HasStackOverflow());
11872   DCHECK(current_block() != NULL);
11873   DCHECK(current_block()->HasPredecessor());
11874   return Bailout(kSuperReference);
11875 }
11876 
11877 
VisitSuperCallReference(SuperCallReference * expr)11878 void HOptimizedGraphBuilder::VisitSuperCallReference(SuperCallReference* expr) {
11879   DCHECK(!HasStackOverflow());
11880   DCHECK(current_block() != NULL);
11881   DCHECK(current_block()->HasPredecessor());
11882   return Bailout(kSuperReference);
11883 }
11884 
VisitDeclarations(Declaration::List * declarations)11885 void HOptimizedGraphBuilder::VisitDeclarations(
11886     Declaration::List* declarations) {
11887   DCHECK(globals_.is_empty());
11888   AstVisitor<HOptimizedGraphBuilder>::VisitDeclarations(declarations);
11889   if (!globals_.is_empty()) {
11890     Handle<FixedArray> array =
11891        isolate()->factory()->NewFixedArray(globals_.length(), TENURED);
11892     for (int i = 0; i < globals_.length(); ++i) array->set(i, *globals_.at(i));
11893     int flags = current_info()->GetDeclareGlobalsFlags();
11894     Handle<FeedbackVector> vector(current_feedback_vector(), isolate());
11895     Add<HDeclareGlobals>(array, flags, vector);
11896     globals_.Rewind(0);
11897   }
11898 }
11899 
11900 
VisitVariableDeclaration(VariableDeclaration * declaration)11901 void HOptimizedGraphBuilder::VisitVariableDeclaration(
11902     VariableDeclaration* declaration) {
11903   VariableProxy* proxy = declaration->proxy();
11904   Variable* variable = proxy->var();
11905   switch (variable->location()) {
11906     case VariableLocation::UNALLOCATED: {
11907       DCHECK(!variable->binding_needs_init());
11908       globals_.Add(variable->name(), zone());
11909       FeedbackSlot slot = proxy->VariableFeedbackSlot();
11910       DCHECK(!slot.IsInvalid());
11911       globals_.Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
11912       globals_.Add(isolate()->factory()->undefined_value(), zone());
11913       globals_.Add(isolate()->factory()->undefined_value(), zone());
11914       return;
11915     }
11916     case VariableLocation::PARAMETER:
11917     case VariableLocation::LOCAL:
11918       if (variable->binding_needs_init()) {
11919         HValue* value = graph()->GetConstantHole();
11920         environment()->Bind(variable, value);
11921       }
11922       break;
11923     case VariableLocation::CONTEXT:
11924       if (variable->binding_needs_init()) {
11925         HValue* value = graph()->GetConstantHole();
11926         HValue* context = environment()->context();
11927         HStoreContextSlot* store = Add<HStoreContextSlot>(
11928             context, variable->index(), HStoreContextSlot::kNoCheck, value);
11929         if (store->HasObservableSideEffects()) {
11930           Add<HSimulate>(proxy->id(), REMOVABLE_SIMULATE);
11931         }
11932       }
11933       break;
11934     case VariableLocation::LOOKUP:
11935       return Bailout(kUnsupportedLookupSlotInDeclaration);
11936     case VariableLocation::MODULE:
11937       UNREACHABLE();
11938   }
11939 }
11940 
11941 
VisitFunctionDeclaration(FunctionDeclaration * declaration)11942 void HOptimizedGraphBuilder::VisitFunctionDeclaration(
11943     FunctionDeclaration* declaration) {
11944   VariableProxy* proxy = declaration->proxy();
11945   Variable* variable = proxy->var();
11946   switch (variable->location()) {
11947     case VariableLocation::UNALLOCATED: {
11948       globals_.Add(variable->name(), zone());
11949       FeedbackSlot slot = proxy->VariableFeedbackSlot();
11950       DCHECK(!slot.IsInvalid());
11951       globals_.Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
11952 
11953       // We need the slot where the literals array lives, too.
11954       slot = declaration->fun()->LiteralFeedbackSlot();
11955       DCHECK(!slot.IsInvalid());
11956       globals_.Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
11957 
11958       Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo(
11959           declaration->fun(), current_info()->script(), top_info());
11960       // Check for stack-overflow exception.
11961       if (function.is_null()) return SetStackOverflow();
11962       globals_.Add(function, zone());
11963       return;
11964     }
11965     case VariableLocation::PARAMETER:
11966     case VariableLocation::LOCAL: {
11967       CHECK_ALIVE(VisitForValue(declaration->fun()));
11968       HValue* value = Pop();
11969       BindIfLive(variable, value);
11970       break;
11971     }
11972     case VariableLocation::CONTEXT: {
11973       CHECK_ALIVE(VisitForValue(declaration->fun()));
11974       HValue* value = Pop();
11975       HValue* context = environment()->context();
11976       HStoreContextSlot* store = Add<HStoreContextSlot>(
11977           context, variable->index(), HStoreContextSlot::kNoCheck, value);
11978       if (store->HasObservableSideEffects()) {
11979         Add<HSimulate>(proxy->id(), REMOVABLE_SIMULATE);
11980       }
11981       break;
11982     }
11983     case VariableLocation::LOOKUP:
11984       return Bailout(kUnsupportedLookupSlotInDeclaration);
11985     case VariableLocation::MODULE:
11986       UNREACHABLE();
11987   }
11988 }
11989 
11990 
VisitRewritableExpression(RewritableExpression * node)11991 void HOptimizedGraphBuilder::VisitRewritableExpression(
11992     RewritableExpression* node) {
11993   CHECK_ALIVE(Visit(node->expression()));
11994 }
11995 
11996 
11997 // Generators for inline runtime functions.
11998 // Support for types.
GenerateIsSmi(CallRuntime * call)11999 void HOptimizedGraphBuilder::GenerateIsSmi(CallRuntime* call) {
12000   DCHECK(call->arguments()->length() == 1);
12001   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12002   HValue* value = Pop();
12003   HIsSmiAndBranch* result = New<HIsSmiAndBranch>(value);
12004   return ast_context()->ReturnControl(result, call->id());
12005 }
12006 
12007 
GenerateIsJSReceiver(CallRuntime * call)12008 void HOptimizedGraphBuilder::GenerateIsJSReceiver(CallRuntime* call) {
12009   DCHECK(call->arguments()->length() == 1);
12010   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12011   HValue* value = Pop();
12012   HHasInstanceTypeAndBranch* result =
12013       New<HHasInstanceTypeAndBranch>(value,
12014                                      FIRST_JS_RECEIVER_TYPE,
12015                                      LAST_JS_RECEIVER_TYPE);
12016   return ast_context()->ReturnControl(result, call->id());
12017 }
12018 
GenerateIsArray(CallRuntime * call)12019 void HOptimizedGraphBuilder::GenerateIsArray(CallRuntime* call) {
12020   DCHECK(call->arguments()->length() == 1);
12021   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12022   HValue* value = Pop();
12023   HHasInstanceTypeAndBranch* result =
12024       New<HHasInstanceTypeAndBranch>(value, JS_ARRAY_TYPE);
12025   return ast_context()->ReturnControl(result, call->id());
12026 }
12027 
12028 
GenerateIsTypedArray(CallRuntime * call)12029 void HOptimizedGraphBuilder::GenerateIsTypedArray(CallRuntime* call) {
12030   DCHECK(call->arguments()->length() == 1);
12031   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12032   HValue* value = Pop();
12033   HHasInstanceTypeAndBranch* result =
12034       New<HHasInstanceTypeAndBranch>(value, JS_TYPED_ARRAY_TYPE);
12035   return ast_context()->ReturnControl(result, call->id());
12036 }
12037 
12038 
GenerateToInteger(CallRuntime * call)12039 void HOptimizedGraphBuilder::GenerateToInteger(CallRuntime* call) {
12040   DCHECK_EQ(1, call->arguments()->length());
12041   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12042   HValue* input = Pop();
12043   if (input->type().IsSmi()) {
12044     return ast_context()->ReturnValue(input);
12045   } else {
12046     Callable callable = CodeFactory::ToInteger(isolate());
12047     HValue* stub = Add<HConstant>(callable.code());
12048     HValue* values[] = {input};
12049     HInstruction* result = New<HCallWithDescriptor>(
12050         stub, 0, callable.descriptor(), ArrayVector(values));
12051     return ast_context()->ReturnInstruction(result, call->id());
12052   }
12053 }
12054 
12055 
GenerateToObject(CallRuntime * call)12056 void HOptimizedGraphBuilder::GenerateToObject(CallRuntime* call) {
12057   DCHECK_EQ(1, call->arguments()->length());
12058   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12059   HValue* value = Pop();
12060   HValue* result = BuildToObject(value);
12061   return ast_context()->ReturnValue(result);
12062 }
12063 
12064 
GenerateToString(CallRuntime * call)12065 void HOptimizedGraphBuilder::GenerateToString(CallRuntime* call) {
12066   DCHECK_EQ(1, call->arguments()->length());
12067   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12068   HValue* input = Pop();
12069   if (input->type().IsString()) {
12070     return ast_context()->ReturnValue(input);
12071   } else {
12072     Callable callable = CodeFactory::ToString(isolate());
12073     HValue* stub = Add<HConstant>(callable.code());
12074     HValue* values[] = {input};
12075     HInstruction* result = New<HCallWithDescriptor>(
12076         stub, 0, callable.descriptor(), ArrayVector(values));
12077     return ast_context()->ReturnInstruction(result, call->id());
12078   }
12079 }
12080 
12081 
GenerateToLength(CallRuntime * call)12082 void HOptimizedGraphBuilder::GenerateToLength(CallRuntime* call) {
12083   DCHECK_EQ(1, call->arguments()->length());
12084   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12085   Callable callable = CodeFactory::ToLength(isolate());
12086   HValue* input = Pop();
12087   HValue* stub = Add<HConstant>(callable.code());
12088   HValue* values[] = {input};
12089   HInstruction* result = New<HCallWithDescriptor>(
12090       stub, 0, callable.descriptor(), ArrayVector(values));
12091   return ast_context()->ReturnInstruction(result, call->id());
12092 }
12093 
12094 
GenerateToNumber(CallRuntime * call)12095 void HOptimizedGraphBuilder::GenerateToNumber(CallRuntime* call) {
12096   DCHECK_EQ(1, call->arguments()->length());
12097   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12098   Callable callable = CodeFactory::ToNumber(isolate());
12099   HValue* input = Pop();
12100   HValue* result = BuildToNumber(input);
12101   if (result->HasObservableSideEffects()) {
12102     if (!ast_context()->IsEffect()) Push(result);
12103     Add<HSimulate>(call->id(), REMOVABLE_SIMULATE);
12104     if (!ast_context()->IsEffect()) result = Pop();
12105   }
12106   return ast_context()->ReturnValue(result);
12107 }
12108 
12109 
GenerateIsJSProxy(CallRuntime * call)12110 void HOptimizedGraphBuilder::GenerateIsJSProxy(CallRuntime* call) {
12111   DCHECK(call->arguments()->length() == 1);
12112   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12113   HValue* value = Pop();
12114   HIfContinuation continuation;
12115   IfBuilder if_proxy(this);
12116 
12117   HValue* smicheck = if_proxy.IfNot<HIsSmiAndBranch>(value);
12118   if_proxy.And();
12119   HValue* map = Add<HLoadNamedField>(value, smicheck, HObjectAccess::ForMap());
12120   HValue* instance_type =
12121       Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapInstanceType());
12122   if_proxy.If<HCompareNumericAndBranch>(
12123       instance_type, Add<HConstant>(JS_PROXY_TYPE), Token::EQ);
12124 
12125   if_proxy.CaptureContinuation(&continuation);
12126   return ast_context()->ReturnContinuation(&continuation, call->id());
12127 }
12128 
12129 
GenerateHasFastPackedElements(CallRuntime * call)12130 void HOptimizedGraphBuilder::GenerateHasFastPackedElements(CallRuntime* call) {
12131   DCHECK(call->arguments()->length() == 1);
12132   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12133   HValue* object = Pop();
12134   HIfContinuation continuation(graph()->CreateBasicBlock(),
12135                                graph()->CreateBasicBlock());
12136   IfBuilder if_not_smi(this);
12137   if_not_smi.IfNot<HIsSmiAndBranch>(object);
12138   if_not_smi.Then();
12139   {
12140     NoObservableSideEffectsScope no_effects(this);
12141 
12142     IfBuilder if_fast_packed(this);
12143     HValue* elements_kind = BuildGetElementsKind(object);
12144     if_fast_packed.If<HCompareNumericAndBranch>(
12145         elements_kind, Add<HConstant>(FAST_SMI_ELEMENTS), Token::EQ);
12146     if_fast_packed.Or();
12147     if_fast_packed.If<HCompareNumericAndBranch>(
12148         elements_kind, Add<HConstant>(FAST_ELEMENTS), Token::EQ);
12149     if_fast_packed.Or();
12150     if_fast_packed.If<HCompareNumericAndBranch>(
12151         elements_kind, Add<HConstant>(FAST_DOUBLE_ELEMENTS), Token::EQ);
12152     if_fast_packed.JoinContinuation(&continuation);
12153   }
12154   if_not_smi.JoinContinuation(&continuation);
12155   return ast_context()->ReturnContinuation(&continuation, call->id());
12156 }
12157 
12158 
12159 // Fast support for charCodeAt(n).
GenerateStringCharCodeAt(CallRuntime * call)12160 void HOptimizedGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) {
12161   DCHECK(call->arguments()->length() == 2);
12162   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12163   CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
12164   HValue* index = Pop();
12165   HValue* string = Pop();
12166   HInstruction* result = BuildStringCharCodeAt(string, index);
12167   return ast_context()->ReturnInstruction(result, call->id());
12168 }
12169 
12170 
12171 // Fast support for SubString.
GenerateSubString(CallRuntime * call)12172 void HOptimizedGraphBuilder::GenerateSubString(CallRuntime* call) {
12173   DCHECK_EQ(3, call->arguments()->length());
12174   CHECK_ALIVE(VisitExpressions(call->arguments()));
12175   Callable callable = CodeFactory::SubString(isolate());
12176   HValue* stub = Add<HConstant>(callable.code());
12177   HValue* to = Pop();
12178   HValue* from = Pop();
12179   HValue* string = Pop();
12180   HValue* values[] = {string, from, to};
12181   HInstruction* result = New<HCallWithDescriptor>(
12182       stub, 0, callable.descriptor(), ArrayVector(values));
12183   result->set_type(HType::String());
12184   return ast_context()->ReturnInstruction(result, call->id());
12185 }
12186 
12187 
12188 // Fast support for calls.
GenerateCall(CallRuntime * call)12189 void HOptimizedGraphBuilder::GenerateCall(CallRuntime* call) {
12190   DCHECK_LE(2, call->arguments()->length());
12191   CHECK_ALIVE(VisitExpressions(call->arguments()));
12192   CallTrampolineDescriptor descriptor(isolate());
12193   PushArgumentsFromEnvironment(call->arguments()->length() - 1);
12194   HValue* trampoline = Add<HConstant>(isolate()->builtins()->Call());
12195   HValue* target = Pop();
12196   HValue* values[] = {target, Add<HConstant>(call->arguments()->length() - 2)};
12197   HInstruction* result =
12198       New<HCallWithDescriptor>(trampoline, call->arguments()->length() - 1,
12199                                descriptor, ArrayVector(values));
12200   return ast_context()->ReturnInstruction(result, call->id());
12201 }
12202 
12203 
GenerateFixedArrayGet(CallRuntime * call)12204 void HOptimizedGraphBuilder::GenerateFixedArrayGet(CallRuntime* call) {
12205   DCHECK(call->arguments()->length() == 2);
12206   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12207   CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
12208   HValue* index = Pop();
12209   HValue* object = Pop();
12210   HInstruction* result = New<HLoadKeyed>(
12211       object, index, nullptr, nullptr, FAST_HOLEY_ELEMENTS, ALLOW_RETURN_HOLE);
12212   return ast_context()->ReturnInstruction(result, call->id());
12213 }
12214 
12215 
GenerateFixedArraySet(CallRuntime * call)12216 void HOptimizedGraphBuilder::GenerateFixedArraySet(CallRuntime* call) {
12217   DCHECK(call->arguments()->length() == 3);
12218   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12219   CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
12220   CHECK_ALIVE(VisitForValue(call->arguments()->at(2)));
12221   HValue* value = Pop();
12222   HValue* index = Pop();
12223   HValue* object = Pop();
12224   NoObservableSideEffectsScope no_effects(this);
12225   Add<HStoreKeyed>(object, index, value, nullptr, FAST_HOLEY_ELEMENTS);
12226   return ast_context()->ReturnValue(graph()->GetConstantUndefined());
12227 }
12228 
12229 
GenerateTheHole(CallRuntime * call)12230 void HOptimizedGraphBuilder::GenerateTheHole(CallRuntime* call) {
12231   DCHECK(call->arguments()->length() == 0);
12232   return ast_context()->ReturnValue(graph()->GetConstantHole());
12233 }
12234 
12235 
GenerateCreateIterResultObject(CallRuntime * call)12236 void HOptimizedGraphBuilder::GenerateCreateIterResultObject(CallRuntime* call) {
12237   DCHECK_EQ(2, call->arguments()->length());
12238   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12239   CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
12240   HValue* done = Pop();
12241   HValue* value = Pop();
12242   HValue* result = BuildCreateIterResultObject(value, done);
12243   return ast_context()->ReturnValue(result);
12244 }
12245 
12246 
GenerateJSCollectionGetTable(CallRuntime * call)12247 void HOptimizedGraphBuilder::GenerateJSCollectionGetTable(CallRuntime* call) {
12248   DCHECK(call->arguments()->length() == 1);
12249   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12250   HValue* receiver = Pop();
12251   HInstruction* result = New<HLoadNamedField>(
12252       receiver, nullptr, HObjectAccess::ForJSCollectionTable());
12253   return ast_context()->ReturnInstruction(result, call->id());
12254 }
12255 
12256 
GenerateStringGetRawHashField(CallRuntime * call)12257 void HOptimizedGraphBuilder::GenerateStringGetRawHashField(CallRuntime* call) {
12258   DCHECK(call->arguments()->length() == 1);
12259   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12260   HValue* object = Pop();
12261   HInstruction* result = New<HLoadNamedField>(
12262       object, nullptr, HObjectAccess::ForStringHashField());
12263   return ast_context()->ReturnInstruction(result, call->id());
12264 }
12265 
12266 
12267 template <typename CollectionType>
BuildAllocateOrderedHashTable()12268 HValue* HOptimizedGraphBuilder::BuildAllocateOrderedHashTable() {
12269   static const int kCapacity = CollectionType::kMinCapacity;
12270   static const int kBucketCount = kCapacity / CollectionType::kLoadFactor;
12271   static const int kFixedArrayLength = CollectionType::kHashTableStartIndex +
12272                                        kBucketCount +
12273                                        (kCapacity * CollectionType::kEntrySize);
12274   static const int kSizeInBytes =
12275       FixedArray::kHeaderSize + (kFixedArrayLength * kPointerSize);
12276 
12277   // Allocate the table and add the proper map.
12278   HValue* table =
12279       Add<HAllocate>(Add<HConstant>(kSizeInBytes), HType::HeapObject(),
12280                      NOT_TENURED, FIXED_ARRAY_TYPE, graph()->GetConstant0());
12281   AddStoreMapConstant(table, isolate()->factory()->ordered_hash_table_map());
12282 
12283   // Initialize the FixedArray...
12284   HValue* length = Add<HConstant>(kFixedArrayLength);
12285   Add<HStoreNamedField>(table, HObjectAccess::ForFixedArrayLength(), length);
12286 
12287   // ...and the OrderedHashTable fields.
12288   Add<HStoreNamedField>(
12289       table,
12290       HObjectAccess::ForOrderedHashTableNumberOfBuckets<CollectionType>(),
12291       Add<HConstant>(kBucketCount));
12292   Add<HStoreNamedField>(
12293       table,
12294       HObjectAccess::ForOrderedHashTableNumberOfElements<CollectionType>(),
12295       graph()->GetConstant0());
12296   Add<HStoreNamedField>(
12297       table, HObjectAccess::ForOrderedHashTableNumberOfDeletedElements<
12298                  CollectionType>(),
12299       graph()->GetConstant0());
12300 
12301   // Fill the buckets with kNotFound.
12302   HValue* not_found = Add<HConstant>(CollectionType::kNotFound);
12303   for (int i = 0; i < kBucketCount; ++i) {
12304     Add<HStoreNamedField>(
12305         table, HObjectAccess::ForOrderedHashTableBucket<CollectionType>(i),
12306         not_found);
12307   }
12308 
12309   // Fill the data table with undefined.
12310   HValue* undefined = graph()->GetConstantUndefined();
12311   for (int i = 0; i < (kCapacity * CollectionType::kEntrySize); ++i) {
12312     Add<HStoreNamedField>(table,
12313                           HObjectAccess::ForOrderedHashTableDataTableIndex<
12314                               CollectionType, kBucketCount>(i),
12315                           undefined);
12316   }
12317 
12318   return table;
12319 }
12320 
12321 
GenerateSetInitialize(CallRuntime * call)12322 void HOptimizedGraphBuilder::GenerateSetInitialize(CallRuntime* call) {
12323   DCHECK(call->arguments()->length() == 1);
12324   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12325   HValue* receiver = Pop();
12326 
12327   NoObservableSideEffectsScope no_effects(this);
12328   HValue* table = BuildAllocateOrderedHashTable<OrderedHashSet>();
12329   Add<HStoreNamedField>(receiver, HObjectAccess::ForJSCollectionTable(), table);
12330   return ast_context()->ReturnValue(receiver);
12331 }
12332 
12333 
GenerateMapInitialize(CallRuntime * call)12334 void HOptimizedGraphBuilder::GenerateMapInitialize(CallRuntime* call) {
12335   DCHECK(call->arguments()->length() == 1);
12336   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12337   HValue* receiver = Pop();
12338 
12339   NoObservableSideEffectsScope no_effects(this);
12340   HValue* table = BuildAllocateOrderedHashTable<OrderedHashMap>();
12341   Add<HStoreNamedField>(receiver, HObjectAccess::ForJSCollectionTable(), table);
12342   return ast_context()->ReturnValue(receiver);
12343 }
12344 
12345 
12346 template <typename CollectionType>
BuildOrderedHashTableClear(HValue * receiver)12347 void HOptimizedGraphBuilder::BuildOrderedHashTableClear(HValue* receiver) {
12348   HValue* old_table = Add<HLoadNamedField>(
12349       receiver, nullptr, HObjectAccess::ForJSCollectionTable());
12350   HValue* new_table = BuildAllocateOrderedHashTable<CollectionType>();
12351   Add<HStoreNamedField>(
12352       old_table, HObjectAccess::ForOrderedHashTableNextTable<CollectionType>(),
12353       new_table);
12354   Add<HStoreNamedField>(
12355       old_table, HObjectAccess::ForOrderedHashTableNumberOfDeletedElements<
12356                      CollectionType>(),
12357       Add<HConstant>(CollectionType::kClearedTableSentinel));
12358   Add<HStoreNamedField>(receiver, HObjectAccess::ForJSCollectionTable(),
12359                         new_table);
12360 }
12361 
12362 
GenerateSetClear(CallRuntime * call)12363 void HOptimizedGraphBuilder::GenerateSetClear(CallRuntime* call) {
12364   DCHECK(call->arguments()->length() == 1);
12365   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12366   HValue* receiver = Pop();
12367 
12368   NoObservableSideEffectsScope no_effects(this);
12369   BuildOrderedHashTableClear<OrderedHashSet>(receiver);
12370   return ast_context()->ReturnValue(graph()->GetConstantUndefined());
12371 }
12372 
12373 
GenerateMapClear(CallRuntime * call)12374 void HOptimizedGraphBuilder::GenerateMapClear(CallRuntime* call) {
12375   DCHECK(call->arguments()->length() == 1);
12376   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12377   HValue* receiver = Pop();
12378 
12379   NoObservableSideEffectsScope no_effects(this);
12380   BuildOrderedHashTableClear<OrderedHashMap>(receiver);
12381   return ast_context()->ReturnValue(graph()->GetConstantUndefined());
12382 }
12383 
GenerateDebugBreakInOptimizedCode(CallRuntime * call)12384 void HOptimizedGraphBuilder::GenerateDebugBreakInOptimizedCode(
12385     CallRuntime* call) {
12386   Add<HDebugBreak>();
12387   return ast_context()->ReturnValue(graph()->GetConstant0());
12388 }
12389 
12390 
GenerateDebugIsActive(CallRuntime * call)12391 void HOptimizedGraphBuilder::GenerateDebugIsActive(CallRuntime* call) {
12392   DCHECK(call->arguments()->length() == 0);
12393   HValue* ref =
12394       Add<HConstant>(ExternalReference::debug_is_active_address(isolate()));
12395   HValue* value =
12396       Add<HLoadNamedField>(ref, nullptr, HObjectAccess::ForExternalUInteger8());
12397   return ast_context()->ReturnValue(value);
12398 }
12399 
12400 #undef CHECK_BAILOUT
12401 #undef CHECK_ALIVE
12402 
12403 
HEnvironment(HEnvironment * outer,Scope * scope,Handle<JSFunction> closure,Zone * zone)12404 HEnvironment::HEnvironment(HEnvironment* outer,
12405                            Scope* scope,
12406                            Handle<JSFunction> closure,
12407                            Zone* zone)
12408     : closure_(closure),
12409       values_(0, zone),
12410       frame_type_(JS_FUNCTION),
12411       parameter_count_(0),
12412       specials_count_(1),
12413       local_count_(0),
12414       outer_(outer),
12415       entry_(NULL),
12416       pop_count_(0),
12417       push_count_(0),
12418       ast_id_(BailoutId::None()),
12419       zone_(zone) {
12420   DeclarationScope* declaration_scope = scope->GetDeclarationScope();
12421   Initialize(declaration_scope->num_parameters() + 1,
12422              declaration_scope->num_stack_slots(), 0);
12423 }
12424 
12425 
HEnvironment(Zone * zone,int parameter_count)12426 HEnvironment::HEnvironment(Zone* zone, int parameter_count)
12427     : values_(0, zone),
12428       frame_type_(STUB),
12429       parameter_count_(parameter_count),
12430       specials_count_(1),
12431       local_count_(0),
12432       outer_(NULL),
12433       entry_(NULL),
12434       pop_count_(0),
12435       push_count_(0),
12436       ast_id_(BailoutId::None()),
12437       zone_(zone) {
12438   Initialize(parameter_count, 0, 0);
12439 }
12440 
12441 
HEnvironment(const HEnvironment * other,Zone * zone)12442 HEnvironment::HEnvironment(const HEnvironment* other, Zone* zone)
12443     : values_(0, zone),
12444       frame_type_(JS_FUNCTION),
12445       parameter_count_(0),
12446       specials_count_(0),
12447       local_count_(0),
12448       outer_(NULL),
12449       entry_(NULL),
12450       pop_count_(0),
12451       push_count_(0),
12452       ast_id_(other->ast_id()),
12453       zone_(zone) {
12454   Initialize(other);
12455 }
12456 
12457 
HEnvironment(HEnvironment * outer,Handle<JSFunction> closure,FrameType frame_type,int arguments,Zone * zone)12458 HEnvironment::HEnvironment(HEnvironment* outer,
12459                            Handle<JSFunction> closure,
12460                            FrameType frame_type,
12461                            int arguments,
12462                            Zone* zone)
12463     : closure_(closure),
12464       values_(arguments, zone),
12465       frame_type_(frame_type),
12466       parameter_count_(arguments),
12467       specials_count_(0),
12468       local_count_(0),
12469       outer_(outer),
12470       entry_(NULL),
12471       pop_count_(0),
12472       push_count_(0),
12473       ast_id_(BailoutId::None()),
12474       zone_(zone) {
12475 }
12476 
12477 
Initialize(int parameter_count,int local_count,int stack_height)12478 void HEnvironment::Initialize(int parameter_count,
12479                               int local_count,
12480                               int stack_height) {
12481   parameter_count_ = parameter_count;
12482   local_count_ = local_count;
12483 
12484   // Avoid reallocating the temporaries' backing store on the first Push.
12485   int total = parameter_count + specials_count_ + local_count + stack_height;
12486   values_.Initialize(total + 4, zone());
12487   for (int i = 0; i < total; ++i) values_.Add(NULL, zone());
12488 }
12489 
12490 
Initialize(const HEnvironment * other)12491 void HEnvironment::Initialize(const HEnvironment* other) {
12492   closure_ = other->closure();
12493   values_.AddAll(other->values_, zone());
12494   assigned_variables_.Union(other->assigned_variables_, zone());
12495   frame_type_ = other->frame_type_;
12496   parameter_count_ = other->parameter_count_;
12497   local_count_ = other->local_count_;
12498   if (other->outer_ != NULL) outer_ = other->outer_->Copy();  // Deep copy.
12499   entry_ = other->entry_;
12500   pop_count_ = other->pop_count_;
12501   push_count_ = other->push_count_;
12502   specials_count_ = other->specials_count_;
12503   ast_id_ = other->ast_id_;
12504 }
12505 
12506 
AddIncomingEdge(HBasicBlock * block,HEnvironment * other)12507 void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) {
12508   DCHECK(!block->IsLoopHeader());
12509   DCHECK(values_.length() == other->values_.length());
12510 
12511   int length = values_.length();
12512   for (int i = 0; i < length; ++i) {
12513     HValue* value = values_[i];
12514     if (value != NULL && value->IsPhi() && value->block() == block) {
12515       // There is already a phi for the i'th value.
12516       HPhi* phi = HPhi::cast(value);
12517       // Assert index is correct and that we haven't missed an incoming edge.
12518       DCHECK(phi->merged_index() == i || !phi->HasMergedIndex());
12519       DCHECK(phi->OperandCount() == block->predecessors()->length());
12520       phi->AddInput(other->values_[i]);
12521     } else if (values_[i] != other->values_[i]) {
12522       // There is a fresh value on the incoming edge, a phi is needed.
12523       DCHECK(values_[i] != NULL && other->values_[i] != NULL);
12524       HPhi* phi = block->AddNewPhi(i);
12525       HValue* old_value = values_[i];
12526       for (int j = 0; j < block->predecessors()->length(); j++) {
12527         phi->AddInput(old_value);
12528       }
12529       phi->AddInput(other->values_[i]);
12530       this->values_[i] = phi;
12531     }
12532   }
12533 }
12534 
12535 
Bind(int index,HValue * value)12536 void HEnvironment::Bind(int index, HValue* value) {
12537   DCHECK(value != NULL);
12538   assigned_variables_.Add(index, zone());
12539   values_[index] = value;
12540 }
12541 
12542 
HasExpressionAt(int index) const12543 bool HEnvironment::HasExpressionAt(int index) const {
12544   return index >= parameter_count_ + specials_count_ + local_count_;
12545 }
12546 
12547 
ExpressionStackIsEmpty() const12548 bool HEnvironment::ExpressionStackIsEmpty() const {
12549   DCHECK(length() >= first_expression_index());
12550   return length() == first_expression_index();
12551 }
12552 
12553 
SetExpressionStackAt(int index_from_top,HValue * value)12554 void HEnvironment::SetExpressionStackAt(int index_from_top, HValue* value) {
12555   int count = index_from_top + 1;
12556   int index = values_.length() - count;
12557   DCHECK(HasExpressionAt(index));
12558   // The push count must include at least the element in question or else
12559   // the new value will not be included in this environment's history.
12560   if (push_count_ < count) {
12561     // This is the same effect as popping then re-pushing 'count' elements.
12562     pop_count_ += (count - push_count_);
12563     push_count_ = count;
12564   }
12565   values_[index] = value;
12566 }
12567 
12568 
RemoveExpressionStackAt(int index_from_top)12569 HValue* HEnvironment::RemoveExpressionStackAt(int index_from_top) {
12570   int count = index_from_top + 1;
12571   int index = values_.length() - count;
12572   DCHECK(HasExpressionAt(index));
12573   // Simulate popping 'count' elements and then
12574   // pushing 'count - 1' elements back.
12575   pop_count_ += Max(count - push_count_, 0);
12576   push_count_ = Max(push_count_ - count, 0) + (count - 1);
12577   return values_.Remove(index);
12578 }
12579 
12580 
Drop(int count)12581 void HEnvironment::Drop(int count) {
12582   for (int i = 0; i < count; ++i) {
12583     Pop();
12584   }
12585 }
12586 
12587 
Print() const12588 void HEnvironment::Print() const {
12589   OFStream os(stdout);
12590   os << *this << "\n";
12591 }
12592 
12593 
Copy() const12594 HEnvironment* HEnvironment::Copy() const {
12595   return new(zone()) HEnvironment(this, zone());
12596 }
12597 
12598 
CopyWithoutHistory() const12599 HEnvironment* HEnvironment::CopyWithoutHistory() const {
12600   HEnvironment* result = Copy();
12601   result->ClearHistory();
12602   return result;
12603 }
12604 
12605 
CopyAsLoopHeader(HBasicBlock * loop_header) const12606 HEnvironment* HEnvironment::CopyAsLoopHeader(HBasicBlock* loop_header) const {
12607   HEnvironment* new_env = Copy();
12608   for (int i = 0; i < values_.length(); ++i) {
12609     HPhi* phi = loop_header->AddNewPhi(i);
12610     phi->AddInput(values_[i]);
12611     new_env->values_[i] = phi;
12612   }
12613   new_env->ClearHistory();
12614   return new_env;
12615 }
12616 
12617 
CreateStubEnvironment(HEnvironment * outer,Handle<JSFunction> target,FrameType frame_type,int arguments) const12618 HEnvironment* HEnvironment::CreateStubEnvironment(HEnvironment* outer,
12619                                                   Handle<JSFunction> target,
12620                                                   FrameType frame_type,
12621                                                   int arguments) const {
12622   HEnvironment* new_env =
12623       new(zone()) HEnvironment(outer, target, frame_type,
12624                                arguments + 1, zone());
12625   for (int i = 0; i <= arguments; ++i) {  // Include receiver.
12626     new_env->Push(ExpressionStackAt(arguments - i));
12627   }
12628   new_env->ClearHistory();
12629   return new_env;
12630 }
12631 
MarkAsTailCaller()12632 void HEnvironment::MarkAsTailCaller() {
12633   DCHECK_EQ(JS_FUNCTION, frame_type());
12634   frame_type_ = TAIL_CALLER_FUNCTION;
12635 }
12636 
ClearTailCallerMark()12637 void HEnvironment::ClearTailCallerMark() {
12638   DCHECK_EQ(TAIL_CALLER_FUNCTION, frame_type());
12639   frame_type_ = JS_FUNCTION;
12640 }
12641 
CopyForInlining(Handle<JSFunction> target,int arguments,FunctionLiteral * function,HConstant * undefined,InliningKind inlining_kind,TailCallMode syntactic_tail_call_mode) const12642 HEnvironment* HEnvironment::CopyForInlining(
12643     Handle<JSFunction> target, int arguments, FunctionLiteral* function,
12644     HConstant* undefined, InliningKind inlining_kind,
12645     TailCallMode syntactic_tail_call_mode) const {
12646   DCHECK_EQ(JS_FUNCTION, frame_type());
12647 
12648   // Outer environment is a copy of this one without the arguments.
12649   int arity = function->scope()->num_parameters();
12650 
12651   HEnvironment* outer = Copy();
12652   outer->Drop(arguments + 1);  // Including receiver.
12653   outer->ClearHistory();
12654 
12655   if (syntactic_tail_call_mode == TailCallMode::kAllow) {
12656     DCHECK_EQ(NORMAL_RETURN, inlining_kind);
12657     outer->MarkAsTailCaller();
12658   }
12659 
12660   if (inlining_kind == CONSTRUCT_CALL_RETURN) {
12661     // Create artificial constructor stub environment.  The receiver should
12662     // actually be the constructor function, but we pass the newly allocated
12663     // object instead, DoComputeConstructStubFrame() relies on that.
12664     outer = CreateStubEnvironment(outer, target, JS_CONSTRUCT, arguments);
12665   } else if (inlining_kind == GETTER_CALL_RETURN) {
12666     // We need an additional StackFrame::INTERNAL frame for restoring the
12667     // correct context.
12668     outer = CreateStubEnvironment(outer, target, JS_GETTER, arguments);
12669   } else if (inlining_kind == SETTER_CALL_RETURN) {
12670     // We need an additional StackFrame::INTERNAL frame for temporarily saving
12671     // the argument of the setter, see StoreStubCompiler::CompileStoreViaSetter.
12672     outer = CreateStubEnvironment(outer, target, JS_SETTER, arguments);
12673   }
12674 
12675   if (arity != arguments) {
12676     // Create artificial arguments adaptation environment.
12677     outer = CreateStubEnvironment(outer, target, ARGUMENTS_ADAPTOR, arguments);
12678   }
12679 
12680   HEnvironment* inner =
12681       new(zone()) HEnvironment(outer, function->scope(), target, zone());
12682   // Get the argument values from the original environment.
12683   for (int i = 0; i <= arity; ++i) {  // Include receiver.
12684     HValue* push = (i <= arguments) ?
12685         ExpressionStackAt(arguments - i) : undefined;
12686     inner->SetValueAt(i, push);
12687   }
12688   inner->SetValueAt(arity + 1, context());
12689   for (int i = arity + 2; i < inner->length(); ++i) {
12690     inner->SetValueAt(i, undefined);
12691   }
12692 
12693   inner->set_ast_id(BailoutId::FunctionEntry());
12694   return inner;
12695 }
12696 
12697 
operator <<(std::ostream & os,const HEnvironment & env)12698 std::ostream& operator<<(std::ostream& os, const HEnvironment& env) {
12699   for (int i = 0; i < env.length(); i++) {
12700     if (i == 0) os << "parameters\n";
12701     if (i == env.parameter_count()) os << "specials\n";
12702     if (i == env.parameter_count() + env.specials_count()) os << "locals\n";
12703     if (i == env.parameter_count() + env.specials_count() + env.local_count()) {
12704       os << "expressions\n";
12705     }
12706     HValue* val = env.values()->at(i);
12707     os << i << ": ";
12708     if (val != NULL) {
12709       os << val;
12710     } else {
12711       os << "NULL";
12712     }
12713     os << "\n";
12714   }
12715   return os << "\n";
12716 }
12717 
12718 
TraceCompilation(CompilationInfo * info)12719 void HTracer::TraceCompilation(CompilationInfo* info) {
12720   Tag tag(this, "compilation");
12721   std::string name;
12722   if (info->parse_info()) {
12723     Object* source_name = info->script()->name();
12724     if (source_name->IsString()) {
12725       String* str = String::cast(source_name);
12726       if (str->length() > 0) {
12727         name.append(str->ToCString().get());
12728         name.append(":");
12729       }
12730     }
12731   }
12732   std::unique_ptr<char[]> method_name = info->GetDebugName();
12733   name.append(method_name.get());
12734   if (info->IsOptimizing()) {
12735     PrintStringProperty("name", name.c_str());
12736     PrintIndent();
12737     trace_.Add("method \"%s:%d\"\n", method_name.get(),
12738                info->optimization_id());
12739   } else {
12740     PrintStringProperty("name", name.c_str());
12741     PrintStringProperty("method", "stub");
12742   }
12743   PrintLongProperty("date",
12744                     static_cast<int64_t>(base::OS::TimeCurrentMillis()));
12745 }
12746 
12747 
TraceLithium(const char * name,LChunk * chunk)12748 void HTracer::TraceLithium(const char* name, LChunk* chunk) {
12749   DCHECK(!chunk->isolate()->concurrent_recompilation_enabled());
12750   AllowHandleDereference allow_deref;
12751   AllowDeferredHandleDereference allow_deferred_deref;
12752   Trace(name, chunk->graph(), chunk);
12753 }
12754 
12755 
TraceHydrogen(const char * name,HGraph * graph)12756 void HTracer::TraceHydrogen(const char* name, HGraph* graph) {
12757   DCHECK(!graph->isolate()->concurrent_recompilation_enabled());
12758   AllowHandleDereference allow_deref;
12759   AllowDeferredHandleDereference allow_deferred_deref;
12760   Trace(name, graph, NULL);
12761 }
12762 
12763 
Trace(const char * name,HGraph * graph,LChunk * chunk)12764 void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) {
12765   Tag tag(this, "cfg");
12766   PrintStringProperty("name", name);
12767   const ZoneList<HBasicBlock*>* blocks = graph->blocks();
12768   for (int i = 0; i < blocks->length(); i++) {
12769     HBasicBlock* current = blocks->at(i);
12770     Tag block_tag(this, "block");
12771     PrintBlockProperty("name", current->block_id());
12772     PrintIntProperty("from_bci", -1);
12773     PrintIntProperty("to_bci", -1);
12774 
12775     if (!current->predecessors()->is_empty()) {
12776       PrintIndent();
12777       trace_.Add("predecessors");
12778       for (int j = 0; j < current->predecessors()->length(); ++j) {
12779         trace_.Add(" \"B%d\"", current->predecessors()->at(j)->block_id());
12780       }
12781       trace_.Add("\n");
12782     } else {
12783       PrintEmptyProperty("predecessors");
12784     }
12785 
12786     if (current->end()->SuccessorCount() == 0) {
12787       PrintEmptyProperty("successors");
12788     } else  {
12789       PrintIndent();
12790       trace_.Add("successors");
12791       for (HSuccessorIterator it(current->end()); !it.Done(); it.Advance()) {
12792         trace_.Add(" \"B%d\"", it.Current()->block_id());
12793       }
12794       trace_.Add("\n");
12795     }
12796 
12797     PrintEmptyProperty("xhandlers");
12798 
12799     {
12800       PrintIndent();
12801       trace_.Add("flags");
12802       if (current->IsLoopSuccessorDominator()) {
12803         trace_.Add(" \"dom-loop-succ\"");
12804       }
12805       if (current->IsUnreachable()) {
12806         trace_.Add(" \"dead\"");
12807       }
12808       if (current->is_osr_entry()) {
12809         trace_.Add(" \"osr\"");
12810       }
12811       trace_.Add("\n");
12812     }
12813 
12814     if (current->dominator() != NULL) {
12815       PrintBlockProperty("dominator", current->dominator()->block_id());
12816     }
12817 
12818     PrintIntProperty("loop_depth", current->LoopNestingDepth());
12819 
12820     if (chunk != NULL) {
12821       int first_index = current->first_instruction_index();
12822       int last_index = current->last_instruction_index();
12823       PrintIntProperty(
12824           "first_lir_id",
12825           LifetimePosition::FromInstructionIndex(first_index).Value());
12826       PrintIntProperty(
12827           "last_lir_id",
12828           LifetimePosition::FromInstructionIndex(last_index).Value());
12829     }
12830 
12831     {
12832       Tag states_tag(this, "states");
12833       Tag locals_tag(this, "locals");
12834       int total = current->phis()->length();
12835       PrintIntProperty("size", current->phis()->length());
12836       PrintStringProperty("method", "None");
12837       for (int j = 0; j < total; ++j) {
12838         HPhi* phi = current->phis()->at(j);
12839         PrintIndent();
12840         std::ostringstream os;
12841         os << phi->merged_index() << " " << NameOf(phi) << " " << *phi << "\n";
12842         trace_.Add(os.str().c_str());
12843       }
12844     }
12845 
12846     {
12847       Tag HIR_tag(this, "HIR");
12848       for (HInstructionIterator it(current); !it.Done(); it.Advance()) {
12849         HInstruction* instruction = it.Current();
12850         int uses = instruction->UseCount();
12851         PrintIndent();
12852         std::ostringstream os;
12853         os << "0 " << uses << " " << NameOf(instruction) << " " << *instruction;
12854         if (instruction->has_position()) {
12855           const SourcePosition pos = instruction->position();
12856           os << " pos:";
12857           if (pos.isInlined()) os << "inlining(" << pos.InliningId() << "),";
12858           os << pos.ScriptOffset();
12859         }
12860         os << " <|@\n";
12861         trace_.Add(os.str().c_str());
12862       }
12863     }
12864 
12865 
12866     if (chunk != NULL) {
12867       Tag LIR_tag(this, "LIR");
12868       int first_index = current->first_instruction_index();
12869       int last_index = current->last_instruction_index();
12870       if (first_index != -1 && last_index != -1) {
12871         const ZoneList<LInstruction*>* instructions = chunk->instructions();
12872         for (int i = first_index; i <= last_index; ++i) {
12873           LInstruction* linstr = instructions->at(i);
12874           if (linstr != NULL) {
12875             PrintIndent();
12876             trace_.Add("%d ",
12877                        LifetimePosition::FromInstructionIndex(i).Value());
12878             linstr->PrintTo(&trace_);
12879             std::ostringstream os;
12880             os << " [hir:" << NameOf(linstr->hydrogen_value()) << "] <|@\n";
12881             trace_.Add(os.str().c_str());
12882           }
12883         }
12884       }
12885     }
12886   }
12887 }
12888 
12889 
TraceLiveRanges(const char * name,LAllocator * allocator)12890 void HTracer::TraceLiveRanges(const char* name, LAllocator* allocator) {
12891   Tag tag(this, "intervals");
12892   PrintStringProperty("name", name);
12893 
12894   const Vector<LiveRange*>* fixed_d = allocator->fixed_double_live_ranges();
12895   for (int i = 0; i < fixed_d->length(); ++i) {
12896     TraceLiveRange(fixed_d->at(i), "fixed", allocator->zone());
12897   }
12898 
12899   const Vector<LiveRange*>* fixed = allocator->fixed_live_ranges();
12900   for (int i = 0; i < fixed->length(); ++i) {
12901     TraceLiveRange(fixed->at(i), "fixed", allocator->zone());
12902   }
12903 
12904   const ZoneList<LiveRange*>* live_ranges = allocator->live_ranges();
12905   for (int i = 0; i < live_ranges->length(); ++i) {
12906     TraceLiveRange(live_ranges->at(i), "object", allocator->zone());
12907   }
12908 }
12909 
12910 
TraceLiveRange(LiveRange * range,const char * type,Zone * zone)12911 void HTracer::TraceLiveRange(LiveRange* range, const char* type,
12912                              Zone* zone) {
12913   if (range != NULL && !range->IsEmpty()) {
12914     PrintIndent();
12915     trace_.Add("%d %s", range->id(), type);
12916     if (range->HasRegisterAssigned()) {
12917       LOperand* op = range->CreateAssignedOperand(zone);
12918       int assigned_reg = op->index();
12919       if (op->IsDoubleRegister()) {
12920         trace_.Add(" \"%s\"",
12921                    GetRegConfig()->GetDoubleRegisterName(assigned_reg));
12922       } else {
12923         DCHECK(op->IsRegister());
12924         trace_.Add(" \"%s\"",
12925                    GetRegConfig()->GetGeneralRegisterName(assigned_reg));
12926       }
12927     } else if (range->IsSpilled()) {
12928       LOperand* op = range->TopLevel()->GetSpillOperand();
12929       if (op->IsDoubleStackSlot()) {
12930         trace_.Add(" \"double_stack:%d\"", op->index());
12931       } else {
12932         DCHECK(op->IsStackSlot());
12933         trace_.Add(" \"stack:%d\"", op->index());
12934       }
12935     }
12936     int parent_index = -1;
12937     if (range->IsChild()) {
12938       parent_index = range->parent()->id();
12939     } else {
12940       parent_index = range->id();
12941     }
12942     LOperand* op = range->FirstHint();
12943     int hint_index = -1;
12944     if (op != NULL && op->IsUnallocated()) {
12945       hint_index = LUnallocated::cast(op)->virtual_register();
12946     }
12947     trace_.Add(" %d %d", parent_index, hint_index);
12948     UseInterval* cur_interval = range->first_interval();
12949     while (cur_interval != NULL && range->Covers(cur_interval->start())) {
12950       trace_.Add(" [%d, %d[",
12951                  cur_interval->start().Value(),
12952                  cur_interval->end().Value());
12953       cur_interval = cur_interval->next();
12954     }
12955 
12956     UsePosition* current_pos = range->first_pos();
12957     while (current_pos != NULL) {
12958       if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) {
12959         trace_.Add(" %d M", current_pos->pos().Value());
12960       }
12961       current_pos = current_pos->next();
12962     }
12963 
12964     trace_.Add(" \"\"\n");
12965   }
12966 }
12967 
12968 
FlushToFile()12969 void HTracer::FlushToFile() {
12970   AppendChars(filename_.start(), trace_.ToCString().get(), trace_.length(),
12971               false);
12972   trace_.Reset();
12973 }
12974 
12975 
Initialize(CompilationInfo * info)12976 void HStatistics::Initialize(CompilationInfo* info) {
12977   if (!info->has_shared_info()) return;
12978   source_size_ += info->shared_info()->SourceSize();
12979 }
12980 
12981 
Print()12982 void HStatistics::Print() {
12983   PrintF(
12984       "\n"
12985       "----------------------------------------"
12986       "----------------------------------------\n"
12987       "--- Hydrogen timing results:\n"
12988       "----------------------------------------"
12989       "----------------------------------------\n");
12990   base::TimeDelta sum;
12991   for (int i = 0; i < times_.length(); ++i) {
12992     sum += times_[i];
12993   }
12994 
12995   for (int i = 0; i < names_.length(); ++i) {
12996     PrintF("%33s", names_[i]);
12997     double ms = times_[i].InMillisecondsF();
12998     double percent = times_[i].PercentOf(sum);
12999     PrintF(" %8.3f ms / %4.1f %% ", ms, percent);
13000 
13001     size_t size = sizes_[i];
13002     double size_percent = static_cast<double>(size) * 100 / total_size_;
13003     PrintF(" %9zu bytes / %4.1f %%\n", size, size_percent);
13004   }
13005 
13006   PrintF(
13007       "----------------------------------------"
13008       "----------------------------------------\n");
13009   base::TimeDelta total = create_graph_ + optimize_graph_ + generate_code_;
13010   PrintF("%33s %8.3f ms / %4.1f %% \n", "Create graph",
13011          create_graph_.InMillisecondsF(), create_graph_.PercentOf(total));
13012   PrintF("%33s %8.3f ms / %4.1f %% \n", "Optimize graph",
13013          optimize_graph_.InMillisecondsF(), optimize_graph_.PercentOf(total));
13014   PrintF("%33s %8.3f ms / %4.1f %% \n", "Generate and install code",
13015          generate_code_.InMillisecondsF(), generate_code_.PercentOf(total));
13016   PrintF(
13017       "----------------------------------------"
13018       "----------------------------------------\n");
13019   PrintF("%33s %8.3f ms           %9zu bytes\n", "Total",
13020          total.InMillisecondsF(), total_size_);
13021   PrintF("%33s     (%.1f times slower than full code gen)\n", "",
13022          total.TimesOf(full_code_gen_));
13023 
13024   double source_size_in_kb = static_cast<double>(source_size_) / 1024;
13025   double normalized_time =  source_size_in_kb > 0
13026       ? total.InMillisecondsF() / source_size_in_kb
13027       : 0;
13028   double normalized_size_in_kb =
13029       source_size_in_kb > 0
13030           ? static_cast<double>(total_size_) / 1024 / source_size_in_kb
13031           : 0;
13032   PrintF("%33s %8.3f ms           %7.3f kB allocated\n",
13033          "Average per kB source", normalized_time, normalized_size_in_kb);
13034 }
13035 
13036 
SaveTiming(const char * name,base::TimeDelta time,size_t size)13037 void HStatistics::SaveTiming(const char* name, base::TimeDelta time,
13038                              size_t size) {
13039   total_size_ += size;
13040   for (int i = 0; i < names_.length(); ++i) {
13041     if (strcmp(names_[i], name) == 0) {
13042       times_[i] += time;
13043       sizes_[i] += size;
13044       return;
13045     }
13046   }
13047   names_.Add(name);
13048   times_.Add(time);
13049   sizes_.Add(size);
13050 }
13051 
13052 
~HPhase()13053 HPhase::~HPhase() {
13054   if (ShouldProduceTraceOutput()) {
13055     isolate()->GetHTracer()->TraceHydrogen(name(), graph_);
13056   }
13057 
13058 #ifdef DEBUG
13059   graph_->Verify(false);  // No full verify.
13060 #endif
13061 }
13062 
13063 }  // namespace internal
13064 }  // namespace v8
13065