Line data Source code
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 0 : class HOptimizedGraphBuilderWithPositions : public HOptimizedGraphBuilder {
75 : public:
76 119 : explicit HOptimizedGraphBuilderWithPositions(CompilationInfo* info)
77 119 : : HOptimizedGraphBuilder(info, true) {
78 238 : SetSourcePosition(info->shared_info()->start_position());
79 119 : }
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 6360 : 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 2834 : 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 100 : DECLARATION_NODE_LIST(DEF_VISIT)
116 : #undef DEF_VISIT
117 : };
118 :
119 265576 : HCompilationJob::Status HCompilationJob::PrepareJobImpl() {
120 3648443 : if (!isolate()->use_crankshaft() ||
121 794768 : 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 529075 : bool should_recompile = !info()->shared_info()->has_deoptimization_support();
132 264537 : if (should_recompile || FLAG_hydrogen_stats) {
133 : base::ElapsedTimer timer;
134 217357 : if (FLAG_hydrogen_stats) {
135 : timer.Start();
136 : }
137 217357 : if (!Compiler::EnsureDeoptimizationSupport(info())) {
138 : return FAILED;
139 : }
140 216949 : if (FLAG_hydrogen_stats) {
141 0 : isolate()->GetHStatistics()->IncrementFullCodeGen(timer.Elapsed());
142 : }
143 : }
144 : DCHECK(info()->shared_info()->has_deoptimization_support());
145 :
146 : // Check the whitelist for Crankshaft.
147 792388 : if (!info()->shared_info()->PassesFilter(FLAG_hydrogen_filter)) {
148 97 : return AbortOptimization(kHydrogenFilter);
149 : }
150 :
151 266466 : Scope* scope = info()->scope();
152 264033 : if (LUnallocated::TooManyParameters(scope->num_parameters())) {
153 : // Crankshaft would require too many Lithium operands.
154 3 : return AbortOptimization(kTooManyParameters);
155 : }
156 :
157 266462 : if (info()->is_osr() &&
158 : LUnallocated::TooManyParametersOrStackSlots(scope->num_parameters(),
159 2433 : scope->num_stack_slots())) {
160 : // Crankshaft would require too many Lithium operands.
161 0 : return AbortOptimization(kTooManyParametersLocals);
162 : }
163 :
164 528059 : if (IsGeneratorFunction(info()->shared_info()->kind())) {
165 : // Crankshaft does not support generators.
166 0 : return AbortOptimization(kGenerator);
167 : }
168 :
169 264030 : if (FLAG_trace_hydrogen) {
170 0 : 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 528060 : if (info()->shared_info()->optimization_disabled()) {
176 : return AbortOptimization(
177 1194 : info()->shared_info()->disable_optimization_reason());
178 : }
179 :
180 : HOptimizedGraphBuilder* graph_builder =
181 263429 : (FLAG_hydrogen_track_positions || isolate()->is_profiling() ||
182 : FLAG_trace_ic)
183 238 : ? new (info()->zone()) HOptimizedGraphBuilderWithPositions(info())
184 790180 : : 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 1053728 : .Run();
191 :
192 263433 : graph_ = graph_builder->CreateGraph();
193 :
194 263433 : if (isolate()->has_pending_exception()) {
195 : return FAILED;
196 : }
197 :
198 263432 : if (graph_ == NULL) return FAILED;
199 :
200 259782 : if (info()->dependencies()->HasAborted()) {
201 : // Dependency has changed during graph creation. Let's try again later.
202 0 : return RetryOptimization(kBailedOutDueToDependencyChange);
203 : }
204 :
205 : return SUCCEEDED;
206 : }
207 :
208 259760 : HCompilationJob::Status HCompilationJob::ExecuteJobImpl() {
209 : DCHECK(graph_ != NULL);
210 259760 : BailoutReason bailout_reason = kNoReason;
211 :
212 259760 : if (graph_->Optimize(&bailout_reason)) {
213 259713 : chunk_ = LChunk::NewChunk(graph_);
214 259714 : if (chunk_ != NULL) return SUCCEEDED;
215 46 : } else if (bailout_reason != kNoReason) {
216 46 : info()->AbortOptimization(bailout_reason);
217 : }
218 :
219 : return FAILED;
220 : }
221 :
222 255333 : 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 255333 : Handle<Code> optimized_code = chunk_->Codegen();
232 255333 : if (optimized_code.is_null()) {
233 255333 : if (info()->bailout_reason() == kNoReason) {
234 33 : return AbortOptimization(kCodeGenerationFailed);
235 : }
236 : return FAILED;
237 : }
238 255300 : RegisterWeakObjectsInOptimizedCode(optimized_code);
239 : info()->SetCode(optimized_code);
240 : }
241 : // Add to the weak list of optimized code objects.
242 510600 : info()->context()->native_context()->AddOptimizedCode(*info()->code());
243 255300 : return SUCCEEDED;
244 : }
245 :
246 23021437 : 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 23021437 : is_ordered_(false) { }
269 :
270 :
271 178417 : Isolate* HBasicBlock::isolate() const {
272 178417 : return graph_->isolate();
273 : }
274 :
275 :
276 1971674 : void HBasicBlock::MarkUnreachable() {
277 1974674 : is_reachable_ = false;
278 1971674 : }
279 :
280 :
281 61068 : void HBasicBlock::AttachLoopInformation() {
282 : DCHECK(!IsLoopHeader());
283 61068 : loop_information_ = new(zone()) HLoopInformation(this, zone());
284 61068 : }
285 :
286 :
287 0 : void HBasicBlock::DetachLoopInformation() {
288 : DCHECK(IsLoopHeader());
289 758 : loop_information_ = NULL;
290 0 : }
291 :
292 :
293 694560 : void HBasicBlock::AddPhi(HPhi* phi) {
294 : DCHECK(!IsStartBlock());
295 : phis_.Add(phi, zone());
296 694560 : phi->SetBlock(this);
297 694560 : }
298 :
299 :
300 378285 : void HBasicBlock::RemovePhi(HPhi* phi) {
301 : DCHECK(phi->block() == this);
302 : DCHECK(phis_.Contains(phi));
303 378285 : phi->Kill();
304 378285 : phis_.RemoveElement(phi);
305 378285 : phi->SetBlock(NULL);
306 378285 : }
307 :
308 :
309 29461534 : void HBasicBlock::AddInstruction(HInstruction* instr, SourcePosition position) {
310 : DCHECK(!IsStartBlock() || !IsFinished());
311 : DCHECK(!instr->IsLinked());
312 : DCHECK(!IsFinished());
313 :
314 24859077 : if (position.IsKnown()) {
315 : instr->set_position(position);
316 : }
317 24859077 : if (first_ == NULL) {
318 : DCHECK(last_environment() != NULL);
319 : DCHECK(!last_environment()->ast_id().IsNone());
320 4602458 : HBlockEntry* entry = new(zone()) HBlockEntry();
321 : entry->InitializeAsFirst(this);
322 4602461 : if (position.IsKnown()) {
323 : entry->set_position(position);
324 : } else {
325 : DCHECK(!FLAG_hydrogen_track_positions ||
326 : !graph()->info()->IsOptimizing() || instr->IsAbnormalExit());
327 : }
328 4602461 : first_ = last_ = entry;
329 : }
330 24859081 : instr->InsertAfter(last_);
331 24859065 : }
332 :
333 :
334 678608 : HPhi* HBasicBlock::AddNewPhi(int merged_index) {
335 678608 : if (graph()->IsInsideNoSideEffectsScope()) {
336 : merged_index = HPhi::kInvalidMergedIndex;
337 : }
338 678608 : HPhi* phi = new(zone()) HPhi(merged_index, zone());
339 678608 : AddPhi(phi);
340 678608 : return phi;
341 : }
342 :
343 :
344 4955043 : HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id,
345 14865130 : RemovableSimulate removable) {
346 : DCHECK(HasEnvironment());
347 4955043 : 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 9910086 : 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 7834492 : for (int i = 0; i < push_count; ++i) {
364 : instr->AddPushedValue(environment->ExpressionStackAt(i));
365 : }
366 10870537 : for (GrowableBitVector::Iterator it(environment->assigned_variables(),
367 4955044 : zone());
368 : !it.Done();
369 : it.Advance()) {
370 : int index = it.Current();
371 : instr->AddAssignedValue(index, environment->Lookup(index));
372 : }
373 : environment->ClearHistory();
374 4955046 : return instr;
375 : }
376 :
377 :
378 4598903 : void HBasicBlock::Finish(HControlInstruction* end, SourcePosition position) {
379 : DCHECK(!IsFinished());
380 4598903 : AddInstruction(end, position);
381 4598903 : end_ = end;
382 9825297 : for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
383 5226394 : it.Current()->RegisterPredecessor(this);
384 : }
385 4598903 : }
386 :
387 :
388 2983096 : void HBasicBlock::Goto(HBasicBlock* block, SourcePosition position,
389 6216680 : FunctionState* state, bool add_simulate) {
390 4653698 : bool drop_extra = state != NULL &&
391 : state->inlining_kind() == NORMAL_RETURN;
392 :
393 2983096 : if (block->IsInlineReturnTarget()) {
394 : HEnvironment* env = last_environment();
395 520993 : int argument_count = env->arguments_environment()->parameter_count();
396 : AddInstruction(new(zone())
397 : HLeaveInlined(state->entry(), argument_count),
398 520993 : position);
399 1041986 : UpdateEnvironment(last_environment()->DiscardInlined(drop_extra));
400 : }
401 :
402 2983096 : if (add_simulate) AddNewSimulate(BailoutId::None(), position);
403 : HGoto* instr = new(zone()) HGoto(block);
404 2983095 : Finish(instr, position);
405 2983095 : }
406 :
407 :
408 80016 : void HBasicBlock::AddLeaveInlined(HValue* return_value, FunctionState* state,
409 200040 : SourcePosition position) {
410 : HBasicBlock* target = state->function_return();
411 40008 : bool drop_extra = state->inlining_kind() == NORMAL_RETURN;
412 :
413 : DCHECK(target->IsInlineReturnTarget());
414 : DCHECK(return_value != NULL);
415 : HEnvironment* env = last_environment();
416 40008 : int argument_count = env->arguments_environment()->parameter_count();
417 : AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count),
418 40008 : position);
419 80016 : UpdateEnvironment(last_environment()->DiscardInlined(drop_extra));
420 : last_environment()->Push(return_value);
421 40008 : AddNewSimulate(BailoutId::None(), position);
422 : HGoto* instr = new(zone()) HGoto(target);
423 40008 : Finish(instr, position);
424 40008 : }
425 :
426 :
427 0 : void HBasicBlock::SetInitialEnvironment(HEnvironment* env) {
428 : DCHECK(!HasEnvironment());
429 : DCHECK(first() == NULL);
430 : UpdateEnvironment(env);
431 0 : }
432 :
433 :
434 15591853 : void HBasicBlock::UpdateEnvironment(HEnvironment* env) {
435 10432202 : last_environment_ = env;
436 : graph()->update_maximum_environment_size(env->first_expression_index());
437 5159651 : }
438 :
439 :
440 25915 : void HBasicBlock::SetJoinId(BailoutId ast_id) {
441 1819799 : int length = predecessors_.length();
442 : DCHECK(length > 0);
443 2522179 : for (int i = 0; i < length; i++) {
444 4992528 : HBasicBlock* predecessor = predecessors_[i];
445 : DCHECK(predecessor->end()->IsGoto());
446 2496264 : 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 25915 : }
455 :
456 :
457 364358 : bool HBasicBlock::Dominates(HBasicBlock* other) const {
458 4982570 : HBasicBlock* current = other->dominator();
459 5688725 : while (current != NULL) {
460 5334225 : if (current == this) return true;
461 : current = current->dominator();
462 : }
463 : return false;
464 : }
465 :
466 :
467 30064 : bool HBasicBlock::EqualToOrDominates(HBasicBlock* other) const {
468 30064 : if (this == other) return true;
469 22561 : return Dominates(other);
470 : }
471 :
472 :
473 0 : int HBasicBlock::LoopNestingDepth() const {
474 0 : const HBasicBlock* current = this;
475 0 : int result = (current->IsLoopHeader()) ? 1 : 0;
476 0 : while (current->parent_loop_header() != NULL) {
477 : current = current->parent_loop_header();
478 0 : result++;
479 : }
480 0 : return result;
481 : }
482 :
483 :
484 89606 : void HBasicBlock::PostProcessLoopHeader(IterationStatement* stmt) {
485 : DCHECK(IsLoopHeader());
486 :
487 : SetJoinId(stmt->EntryId());
488 45182 : if (predecessors()->length() == 1) {
489 : // This is a degenerated loop.
490 : DetachLoopInformation();
491 45182 : 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 44424 : for (int i = 1; i < predecessors()->length(); ++i) {
497 88848 : loop_information()->RegisterBackEdge(predecessors()->at(i));
498 : }
499 : }
500 :
501 :
502 3000 : void HBasicBlock::MarkSuccEdgeUnreachable(int succ) {
503 : DCHECK(IsFinished());
504 3000 : HBasicBlock* succ_block = end()->SuccessorAt(succ);
505 :
506 : DCHECK(succ_block->predecessors()->length() == 1);
507 : succ_block->MarkUnreachable();
508 3000 : }
509 :
510 :
511 18824968 : void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) {
512 5226397 : 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 4114947 : HEnvironment* incoming_env = pred->last_environment();
518 909200 : if (IsLoopHeader()) {
519 : DCHECK_EQ(phis()->length(), incoming_env->length());
520 924564 : for (int i = 0; i < phis_.length(); ++i) {
521 1356861 : phis_[i]->AddInput(incoming_env->values()->at(i));
522 : }
523 : } else {
524 849230 : last_environment()->AddIncomingEdge(this, pred->last_environment());
525 : }
526 7522944 : } else if (!HasEnvironment() && !IsFinished()) {
527 : DCHECK(!IsLoopHeader());
528 3205747 : SetInitialEnvironment(pred->last_environment()->Copy());
529 : }
530 :
531 : predecessors_.Add(pred, zone());
532 5226391 : }
533 :
534 :
535 9843774 : 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 15044168 : while (index < dominated_blocks_.length() &&
541 2600197 : dominated_blocks_[index]->block_id() < block->block_id()) {
542 2600197 : ++index;
543 : }
544 : dominated_blocks_.InsertAt(index, block, zone());
545 4921886 : }
546 :
547 :
548 5864020 : void HBasicBlock::AssignCommonDominator(HBasicBlock* other) {
549 5042293 : if (dominator_ == NULL) {
550 4220566 : dominator_ = other;
551 4220566 : other->AddDominatedBlock(this);
552 821727 : } else if (other->dominator() != NULL) {
553 6454651 : HBasicBlock* first = dominator_;
554 7826006 : HBasicBlock* second = other;
555 :
556 5581946 : while (first != second) {
557 4760219 : 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 821727 : if (dominator_ != first) {
566 : DCHECK(dominator_->dominated_blocks_.Contains(this));
567 701326 : dominator_->dominated_blocks_.RemoveElement(this);
568 701326 : dominator_ = first;
569 701326 : first->AddDominatedBlock(this);
570 : }
571 : }
572 5042291 : }
573 :
574 :
575 119754 : 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 2343576 : HBasicBlock* last = loop_information()->GetLastBackEdge();
586 : int outstanding_successors = 1; // one edge from the pre-header
587 : // Header always dominates everything.
588 : MarkAsLoopSuccessorDominator();
589 2179786 : for (int j = block_id(); j <= last->block_id(); ++j) {
590 6730697 : HBasicBlock* dominator_candidate = graph_->blocks()->at(j);
591 2317951 : for (HPredecessorIterator it(dominator_candidate); !it.Done();
592 : it.Advance()) {
593 1287935 : HBasicBlock* predecessor = it.Current();
594 : // Don't count back edges.
595 1287935 : if (predecessor->block_id() < dominator_candidate->block_id()) {
596 1218920 : 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 2308743 : if (outstanding_successors == 0 &&
611 1030016 : (parent_loop_header == this && !dominator_candidate->IsLoopHeader())) {
612 : dominator_candidate->MarkAsLoopSuccessorDominator();
613 : }
614 : HControlInstruction* end = dominator_candidate->end();
615 2352714 : for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
616 1322698 : HBasicBlock* successor = it.Current();
617 : // Only count successors that remain inside the loop and don't loop back
618 : // to a loop header.
619 2576381 : 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 1159043 : outstanding_successors++;
625 : }
626 : }
627 : }
628 59877 : }
629 :
630 :
631 5572481 : int HBasicBlock::PredecessorIndexOf(HBasicBlock* predecessor) const {
632 20877016 : for (int i = 0; i < predecessors_.length(); ++i) {
633 31315524 : if (predecessors_[i] == predecessor) return i;
634 : }
635 0 : UNREACHABLE();
636 : return -1;
637 : }
638 :
639 :
640 : #ifdef DEBUG
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 :
656 59970 : void HLoopInformation::RegisterBackEdge(HBasicBlock* block) {
657 59970 : this->back_edges_.Add(block, block->zone());
658 59970 : AddBlock(block);
659 59970 : }
660 :
661 :
662 374479 : HBasicBlock* HLoopInformation::GetLastBackEdge() const {
663 : int max_id = -1;
664 : HBasicBlock* result = NULL;
665 1677547 : for (int i = 0; i < back_edges_.length(); ++i) {
666 1737424 : HBasicBlock* cur = back_edges_[i];
667 434356 : if (cur->block_id() > max_id) {
668 : max_id = cur->block_id();
669 : result = cur;
670 : }
671 : }
672 374479 : return result;
673 : }
674 :
675 :
676 1094300 : void HLoopInformation::AddBlock(HBasicBlock* block) {
677 1966889 : if (block == loop_header()) return;
678 1049777 : if (block->parent_loop_header() == loop_header()) return;
679 872589 : 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 1891146 : for (int i = 0; i < block->predecessors()->length(); ++i) {
685 1034330 : 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:
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 :
711 : int visited_count() const { return visited_count_; }
712 : const BitVector* reachable() const { return &reachable_; }
713 :
714 : private:
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 :
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 :
740 : 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 :
824 562332 : HConstant* HGraph::GetConstant(SetOncePointer<HConstant>* pointer,
825 651268 : int32_t value) {
826 562332 : if (!pointer->is_set()) {
827 : // Can't pass GetInvalidContext() to HConstant::New, because that will
828 : // recursively call GetConstant
829 325634 : HConstant* constant = HConstant::New(isolate(), zone(), NULL, value);
830 325634 : constant->InsertAfter(entry_block()->first());
831 : pointer->set(constant);
832 325634 : return constant;
833 : }
834 236699 : return ReinsertConstantIfNecessary(pointer->get());
835 : }
836 :
837 :
838 8 : HConstant* HGraph::ReinsertConstantIfNecessary(HConstant* constant) {
839 5335887 : if (!constant->IsLinked()) {
840 : // The constant was removed from the graph. Reinsert.
841 : constant->ClearFlag(HValue::kIsDead);
842 8 : constant->InsertAfter(entry_block()->first());
843 : }
844 0 : return constant;
845 : }
846 :
847 :
848 34152 : HConstant* HGraph::GetConstant0() {
849 449675 : return GetConstant(&constant_0_, 0);
850 : }
851 :
852 :
853 312 : HConstant* HGraph::GetConstant1() {
854 94501 : return GetConstant(&constant_1_, 1);
855 : }
856 :
857 :
858 0 : HConstant* HGraph::GetConstantMinus1() {
859 16963 : return GetConstant(&constant_minus1_, -1);
860 : }
861 :
862 :
863 2 : HConstant* HGraph::GetConstantBool(bool value) {
864 2 : 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 :
882 3973725 : DEFINE_GET_CONSTANT(Undefined, undefined, undefined_value, undefined,
883 : HType::Undefined(), false, true)
884 207681 : DEFINE_GET_CONSTANT(True, true, true_value, boolean, HType::Boolean(), true,
885 : false)
886 188058 : DEFINE_GET_CONSTANT(False, false, false_value, boolean, HType::Boolean(), false,
887 : false)
888 11161206 : DEFINE_GET_CONSTANT(Hole, the_hole, the_hole_value, the_hole, HType::None(),
889 : false, false)
890 29433 : DEFINE_GET_CONSTANT(Null, null, null_value, null, HType::Null(), false, true)
891 1605693 : 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 347292 : DEFINE_IS_CONSTANT(Undefined, undefined)
901 340064 : DEFINE_IS_CONSTANT(0, 0)
902 335231 : DEFINE_IS_CONSTANT(1, 1)
903 331402 : DEFINE_IS_CONSTANT(Minus1, minus1)
904 331000 : DEFINE_IS_CONSTANT(True, true)
905 310649 : DEFINE_IS_CONSTANT(False, false)
906 309718 : DEFINE_IS_CONSTANT(Hole, the_hole)
907 307304 : DEFINE_IS_CONSTANT(Null, null)
908 :
909 : #undef DEFINE_IS_CONSTANT
910 :
911 :
912 1194 : HConstant* HGraph::GetInvalidContext() {
913 1194 : return GetConstant(&constant_invalid_context_, 0xFFFFC0C7);
914 : }
915 :
916 :
917 347292 : bool HGraph::IsStandardConstant(HConstant* constant) {
918 347292 : if (IsConstantUndefined(constant)) return true;
919 340064 : if (IsConstant0(constant)) return true;
920 335231 : if (IsConstant1(constant)) return true;
921 331402 : if (IsConstantMinus1(constant)) return true;
922 331000 : if (IsConstantTrue(constant)) return true;
923 310649 : if (IsConstantFalse(constant)) return true;
924 309718 : if (IsConstantHole(constant)) return true;
925 307304 : if (IsConstantNull(constant)) return true;
926 307184 : return false;
927 : }
928 :
929 :
930 0 : HGraphBuilder::IfBuilder::IfBuilder() : builder_(NULL), needs_compare_(true) {}
931 :
932 :
933 14110 : HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder)
934 102983 : : needs_compare_(true) {
935 102983 : Initialize(builder);
936 14110 : }
937 :
938 :
939 0 : HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder,
940 : HIfContinuation* continuation)
941 5174 : : needs_compare_(false), first_true_block_(NULL), first_false_block_(NULL) {
942 : InitializeDontCreateBlocks(builder);
943 : continuation->Continue(&first_true_block_, &first_false_block_);
944 0 : }
945 :
946 :
947 0 : void HGraphBuilder::IfBuilder::InitializeDontCreateBlocks(
948 : HGraphBuilder* builder) {
949 108157 : builder_ = builder;
950 108157 : finished_ = false;
951 108157 : did_then_ = false;
952 108157 : did_else_ = false;
953 108157 : did_else_if_ = false;
954 108157 : did_and_ = false;
955 108157 : did_or_ = false;
956 108157 : captured_ = false;
957 108157 : pending_merge_block_ = false;
958 108157 : split_edge_merge_block_ = NULL;
959 108157 : merge_at_join_blocks_ = NULL;
960 108157 : normal_merge_at_join_block_count_ = 0;
961 108157 : deopt_merge_at_join_block_count_ = 0;
962 0 : }
963 :
964 :
965 102983 : void HGraphBuilder::IfBuilder::Initialize(HGraphBuilder* builder) {
966 : InitializeDontCreateBlocks(builder);
967 : HEnvironment* env = builder->environment();
968 102983 : first_true_block_ = builder->CreateBasicBlock(env->Copy());
969 102983 : first_false_block_ = builder->CreateBasicBlock(env->Copy());
970 102983 : }
971 :
972 :
973 127968 : HControlInstruction* HGraphBuilder::IfBuilder::AddCompare(
974 177938 : HControlInstruction* compare) {
975 : DCHECK(did_then_ == did_else_);
976 127968 : if (did_else_) {
977 : // Handle if-then-elseif
978 0 : did_else_if_ = true;
979 0 : did_else_ = false;
980 0 : did_then_ = false;
981 0 : did_and_ = false;
982 0 : did_or_ = false;
983 0 : pending_merge_block_ = false;
984 0 : split_edge_merge_block_ = NULL;
985 : HEnvironment* env = builder()->environment();
986 0 : first_true_block_ = builder()->CreateBasicBlock(env->Copy());
987 0 : first_false_block_ = builder()->CreateBasicBlock(env->Copy());
988 : }
989 127968 : if (split_edge_merge_block_ != NULL) {
990 24985 : HEnvironment* env = first_false_block_->last_environment();
991 49970 : HBasicBlock* split_edge = builder()->CreateBasicBlock(env->Copy());
992 24985 : if (did_or_) {
993 16818 : compare->SetSuccessorAt(0, split_edge);
994 16818 : compare->SetSuccessorAt(1, first_false_block_);
995 : } else {
996 8167 : compare->SetSuccessorAt(0, first_true_block_);
997 8167 : compare->SetSuccessorAt(1, split_edge);
998 : }
999 24985 : builder()->GotoNoSimulate(split_edge, split_edge_merge_block_);
1000 : } else {
1001 102983 : compare->SetSuccessorAt(0, first_true_block_);
1002 102983 : compare->SetSuccessorAt(1, first_false_block_);
1003 : }
1004 127968 : builder()->FinishCurrentBlock(compare);
1005 127968 : needs_compare_ = false;
1006 127968 : return compare;
1007 : }
1008 :
1009 :
1010 84070 : void HGraphBuilder::IfBuilder::Or() {
1011 : DCHECK(!needs_compare_);
1012 : DCHECK(!did_and_);
1013 16818 : did_or_ = true;
1014 16818 : HEnvironment* env = first_false_block_->last_environment();
1015 16818 : if (split_edge_merge_block_ == NULL) {
1016 33616 : split_edge_merge_block_ = builder()->CreateBasicBlock(env->Copy());
1017 16808 : builder()->GotoNoSimulate(first_true_block_, split_edge_merge_block_);
1018 16808 : first_true_block_ = split_edge_merge_block_;
1019 : }
1020 16818 : builder()->set_current_block(first_false_block_);
1021 33636 : first_false_block_ = builder()->CreateBasicBlock(env->Copy());
1022 16818 : }
1023 :
1024 :
1025 40835 : void HGraphBuilder::IfBuilder::And() {
1026 : DCHECK(!needs_compare_);
1027 : DCHECK(!did_or_);
1028 8167 : did_and_ = true;
1029 8167 : HEnvironment* env = first_false_block_->last_environment();
1030 8167 : if (split_edge_merge_block_ == NULL) {
1031 16334 : split_edge_merge_block_ = builder()->CreateBasicBlock(env->Copy());
1032 8167 : builder()->GotoNoSimulate(first_false_block_, split_edge_merge_block_);
1033 8167 : first_false_block_ = split_edge_merge_block_;
1034 : }
1035 8167 : builder()->set_current_block(first_true_block_);
1036 16334 : first_true_block_ = builder()->CreateBasicBlock(env->Copy());
1037 8167 : }
1038 :
1039 :
1040 843 : void HGraphBuilder::IfBuilder::CaptureContinuation(
1041 843 : HIfContinuation* continuation) {
1042 : DCHECK(!did_else_if_);
1043 : DCHECK(!finished_);
1044 : DCHECK(!captured_);
1045 :
1046 843 : HBasicBlock* true_block = NULL;
1047 843 : HBasicBlock* false_block = NULL;
1048 843 : Finish(&true_block, &false_block);
1049 : DCHECK(true_block != NULL);
1050 : DCHECK(false_block != NULL);
1051 843 : continuation->Capture(true_block, false_block);
1052 843 : captured_ = true;
1053 : builder()->set_current_block(NULL);
1054 843 : End();
1055 843 : }
1056 :
1057 :
1058 30216 : void HGraphBuilder::IfBuilder::JoinContinuation(HIfContinuation* continuation) {
1059 : DCHECK(!did_else_if_);
1060 : DCHECK(!finished_);
1061 : DCHECK(!captured_);
1062 12516 : HBasicBlock* true_block = NULL;
1063 12516 : HBasicBlock* false_block = NULL;
1064 12516 : Finish(&true_block, &false_block);
1065 12516 : merge_at_join_blocks_ = NULL;
1066 12516 : if (true_block != NULL && !true_block->IsFinished()) {
1067 : DCHECK(continuation->IsTrueReachable());
1068 : builder()->GotoNoSimulate(true_block, continuation->true_branch());
1069 : }
1070 12516 : if (false_block != NULL && !false_block->IsFinished()) {
1071 : DCHECK(continuation->IsFalseReachable());
1072 : builder()->GotoNoSimulate(false_block, continuation->false_branch());
1073 : }
1074 12516 : captured_ = true;
1075 12516 : End();
1076 12516 : }
1077 :
1078 :
1079 216314 : void HGraphBuilder::IfBuilder::Then() {
1080 : DCHECK(!captured_);
1081 : DCHECK(!finished_);
1082 108157 : did_then_ = true;
1083 108157 : 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 0 : HConstant* constant_false = builder()->graph()->GetConstantFalse();
1089 : ToBooleanHints boolean_type = ToBooleanHint::kBoolean;
1090 : HBranch* branch = builder()->New<HBranch>(
1091 0 : constant_false, boolean_type, first_true_block_, first_false_block_);
1092 0 : builder()->FinishCurrentBlock(branch);
1093 : }
1094 108157 : builder()->set_current_block(first_true_block_);
1095 108157 : pending_merge_block_ = true;
1096 108157 : }
1097 :
1098 :
1099 122212 : void HGraphBuilder::IfBuilder::Else() {
1100 : DCHECK(did_then_);
1101 : DCHECK(!captured_);
1102 : DCHECK(!finished_);
1103 108157 : AddMergeAtJoinBlock(false);
1104 108157 : builder()->set_current_block(first_false_block_);
1105 108157 : pending_merge_block_ = true;
1106 108157 : did_else_ = true;
1107 14055 : }
1108 :
1109 6964 : void HGraphBuilder::IfBuilder::Deopt(DeoptimizeReason reason) {
1110 : DCHECK(did_then_);
1111 6964 : builder()->Add<HDeoptimize>(reason, Deoptimizer::EAGER);
1112 6964 : AddMergeAtJoinBlock(true);
1113 6964 : }
1114 :
1115 :
1116 41157 : void HGraphBuilder::IfBuilder::Return(HValue* value) {
1117 13719 : HValue* parameter_count = builder()->graph()->GetConstantMinus1();
1118 : builder()->FinishExitCurrentBlock(
1119 27438 : builder()->New<HReturn>(value, parameter_count));
1120 13719 : AddMergeAtJoinBlock(false);
1121 13719 : }
1122 :
1123 :
1124 683185 : void HGraphBuilder::IfBuilder::AddMergeAtJoinBlock(bool deopt) {
1125 501114 : if (!pending_merge_block_) return;
1126 216314 : HBasicBlock* block = builder()->current_block();
1127 : DCHECK(block == NULL || !block->IsFinished());
1128 216314 : MergeAtJoinBlock* record = new (builder()->zone())
1129 216314 : MergeAtJoinBlock(block, deopt, merge_at_join_blocks_);
1130 216314 : merge_at_join_blocks_ = record;
1131 216314 : if (block != NULL) {
1132 : DCHECK(block->end() == NULL);
1133 194923 : if (deopt) {
1134 6964 : normal_merge_at_join_block_count_++;
1135 : } else {
1136 187959 : deopt_merge_at_join_block_count_++;
1137 : }
1138 : }
1139 : builder()->set_current_block(NULL);
1140 216314 : pending_merge_block_ = false;
1141 : }
1142 :
1143 :
1144 108157 : void HGraphBuilder::IfBuilder::Finish() {
1145 : DCHECK(!finished_);
1146 108157 : if (!did_then_) {
1147 853 : Then();
1148 : }
1149 108157 : AddMergeAtJoinBlock(false);
1150 108157 : if (!did_else_) {
1151 : Else();
1152 13560 : AddMergeAtJoinBlock(false);
1153 : }
1154 108157 : finished_ = true;
1155 108157 : }
1156 :
1157 :
1158 13359 : void HGraphBuilder::IfBuilder::Finish(HBasicBlock** then_continuation,
1159 : HBasicBlock** else_continuation) {
1160 13359 : Finish();
1161 :
1162 13359 : MergeAtJoinBlock* else_record = merge_at_join_blocks_;
1163 13359 : if (else_continuation != NULL) {
1164 13359 : *else_continuation = else_record->block_;
1165 : }
1166 13359 : MergeAtJoinBlock* then_record = else_record->next_;
1167 13359 : if (then_continuation != NULL) {
1168 13359 : *then_continuation = then_record->block_;
1169 : }
1170 : DCHECK(then_record->next_ == NULL);
1171 13359 : }
1172 :
1173 :
1174 0 : void HGraphBuilder::IfBuilder::EndUnreachable() {
1175 0 : if (captured_) return;
1176 0 : Finish();
1177 : builder()->set_current_block(nullptr);
1178 : }
1179 :
1180 :
1181 445172 : void HGraphBuilder::IfBuilder::End() {
1182 108157 : if (captured_) return;
1183 94798 : Finish();
1184 :
1185 94798 : int total_merged_blocks = normal_merge_at_join_block_count_ +
1186 94798 : deopt_merge_at_join_block_count_;
1187 : DCHECK(total_merged_blocks >= 1);
1188 : HBasicBlock* merge_block =
1189 175537 : 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 94798 : MergeAtJoinBlock* current = merge_at_join_blocks_;
1194 351074 : while (current != NULL) {
1195 175537 : 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 173366 : if (total_merged_blocks == 1) {
1200 : builder()->set_current_block(current->block_);
1201 : return;
1202 : }
1203 : builder()->GotoNoSimulate(current->block_, merge_block);
1204 : }
1205 161478 : current = current->next_;
1206 : }
1207 :
1208 : // Merge deopt blocks, padding when necessary.
1209 80739 : current = merge_at_join_blocks_;
1210 322956 : while (current != NULL) {
1211 161478 : if (current->deopt_ && current->block_ != NULL) {
1212 : current->block_->FinishExit(
1213 4342 : HAbnormalExit::New(builder()->isolate(), builder()->zone(), NULL),
1214 2171 : SourcePosition::Unknown());
1215 : }
1216 161478 : current = current->next_;
1217 : }
1218 : builder()->set_current_block(merge_block);
1219 : }
1220 :
1221 :
1222 0 : HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder) {
1223 : Initialize(builder, NULL, kWhileTrue, NULL);
1224 0 : }
1225 :
1226 :
1227 15546 : HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, HValue* context,
1228 : LoopBuilder::Direction direction) {
1229 : Initialize(builder, context, direction, builder->graph()->GetConstant1());
1230 15546 : }
1231 :
1232 :
1233 0 : HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, HValue* context,
1234 : LoopBuilder::Direction direction,
1235 : HValue* increment_amount) {
1236 : Initialize(builder, context, direction, increment_amount);
1237 0 : increment_amount_ = increment_amount;
1238 0 : }
1239 :
1240 :
1241 0 : void HGraphBuilder::LoopBuilder::Initialize(HGraphBuilder* builder,
1242 : HValue* context,
1243 : Direction direction,
1244 : HValue* increment_amount) {
1245 15546 : builder_ = builder;
1246 15546 : context_ = context;
1247 15546 : direction_ = direction;
1248 15546 : increment_amount_ = increment_amount;
1249 :
1250 15546 : finished_ = false;
1251 15546 : header_block_ = builder->CreateLoopHeaderBlock();
1252 15546 : body_block_ = NULL;
1253 15546 : exit_block_ = NULL;
1254 15546 : exit_trampoline_block_ = NULL;
1255 0 : }
1256 :
1257 :
1258 15546 : HValue* HGraphBuilder::LoopBuilder::BeginBody(
1259 : HValue* initial,
1260 : HValue* terminating,
1261 82 : Token::Value token) {
1262 : DCHECK(direction_ != kWhileTrue);
1263 15628 : HEnvironment* env = builder_->environment();
1264 15546 : phi_ = header_block_->AddNewPhi(env->values()->length());
1265 15546 : phi_->AddInput(initial);
1266 : env->Push(initial);
1267 15546 : builder_->GotoNoSimulate(header_block_);
1268 :
1269 15546 : HEnvironment* body_env = env->Copy();
1270 15546 : HEnvironment* exit_env = env->Copy();
1271 : // Remove the phi from the expression stack
1272 15546 : body_env->Pop();
1273 15546 : exit_env->Pop();
1274 15546 : body_block_ = builder_->CreateBasicBlock(body_env);
1275 15546 : exit_block_ = builder_->CreateBasicBlock(exit_env);
1276 :
1277 15546 : builder_->set_current_block(header_block_);
1278 15546 : env->Pop();
1279 : builder_->FinishCurrentBlock(builder_->New<HCompareNumericAndBranch>(
1280 15546 : phi_, terminating, token, body_block_, exit_block_));
1281 :
1282 15546 : builder_->set_current_block(body_block_);
1283 15546 : if (direction_ == kPreIncrement || direction_ == kPreDecrement) {
1284 82 : Isolate* isolate = builder_->isolate();
1285 : HValue* one = builder_->graph()->GetConstant1();
1286 82 : if (direction_ == kPreIncrement) {
1287 0 : increment_ = HAdd::New(isolate, zone(), context_, phi_, one);
1288 : } else {
1289 164 : increment_ = HSub::New(isolate, zone(), context_, phi_, one);
1290 : }
1291 82 : increment_->ClearFlag(HValue::kCanOverflow);
1292 82 : builder_->AddInstruction(increment_);
1293 82 : return increment_;
1294 : } else {
1295 15464 : return phi_;
1296 : }
1297 : }
1298 :
1299 :
1300 0 : void HGraphBuilder::LoopBuilder::BeginBody(int drop_count) {
1301 : DCHECK(direction_ == kWhileTrue);
1302 0 : HEnvironment* env = builder_->environment();
1303 0 : builder_->GotoNoSimulate(header_block_);
1304 0 : builder_->set_current_block(header_block_);
1305 : env->Drop(drop_count);
1306 0 : }
1307 :
1308 :
1309 340 : void HGraphBuilder::LoopBuilder::Break() {
1310 340 : if (exit_trampoline_block_ == NULL) {
1311 : // Its the first time we saw a break.
1312 340 : if (direction_ == kWhileTrue) {
1313 0 : HEnvironment* env = builder_->environment()->Copy();
1314 0 : exit_trampoline_block_ = builder_->CreateBasicBlock(env);
1315 : } else {
1316 340 : HEnvironment* env = exit_block_->last_environment()->Copy();
1317 340 : exit_trampoline_block_ = builder_->CreateBasicBlock(env);
1318 340 : builder_->GotoNoSimulate(exit_block_, exit_trampoline_block_);
1319 : }
1320 : }
1321 :
1322 340 : builder_->GotoNoSimulate(exit_trampoline_block_);
1323 340 : builder_->set_current_block(NULL);
1324 340 : }
1325 :
1326 :
1327 15546 : void HGraphBuilder::LoopBuilder::EndBody() {
1328 : DCHECK(!finished_);
1329 :
1330 15546 : if (direction_ == kPostIncrement || direction_ == kPostDecrement) {
1331 31010 : Isolate* isolate = builder_->isolate();
1332 15464 : if (direction_ == kPostIncrement) {
1333 : increment_ =
1334 29276 : HAdd::New(isolate, zone(), context_, phi_, increment_amount_);
1335 : } else {
1336 : increment_ =
1337 1652 : HSub::New(isolate, zone(), context_, phi_, increment_amount_);
1338 : }
1339 15464 : increment_->ClearFlag(HValue::kCanOverflow);
1340 15464 : builder_->AddInstruction(increment_);
1341 : }
1342 :
1343 15546 : if (direction_ != kWhileTrue) {
1344 : // Push the new increment value on the expression stack to merge into
1345 : // the phi.
1346 15546 : builder_->environment()->Push(increment_);
1347 : }
1348 15546 : HBasicBlock* last_block = builder_->current_block();
1349 31092 : builder_->GotoNoSimulate(last_block, header_block_);
1350 31092 : header_block_->loop_information()->RegisterBackEdge(last_block);
1351 :
1352 15546 : if (exit_trampoline_block_ != NULL) {
1353 340 : builder_->set_current_block(exit_trampoline_block_);
1354 : } else {
1355 15206 : builder_->set_current_block(exit_block_);
1356 : }
1357 15546 : finished_ = true;
1358 15546 : }
1359 :
1360 :
1361 1144013 : HGraph* HGraphBuilder::CreateGraph() {
1362 : DCHECK(!FLAG_minimal);
1363 573831 : graph_ = new (zone()) HGraph(info_, descriptor_);
1364 286916 : if (FLAG_hydrogen_stats) isolate()->GetHStatistics()->Initialize(info_);
1365 286916 : CompilationPhase phase("H_Block building", info_);
1366 286916 : set_current_block(graph()->entry_block());
1367 286916 : if (!BuildGraph()) return NULL;
1368 283265 : graph()->FinalizeUniqueness();
1369 283265 : return graph_;
1370 : }
1371 :
1372 :
1373 33732890 : HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
1374 : DCHECK(current_block() != NULL);
1375 : DCHECK(!FLAG_hydrogen_track_positions || position_.IsKnown() ||
1376 : !info_->IsOptimizing());
1377 16866447 : current_block()->AddInstruction(instr, source_position());
1378 16866443 : if (graph()->IsInsideNoSideEffectsScope()) {
1379 : instr->SetFlag(HValue::kHasNoObservableSideEffects);
1380 : }
1381 16866443 : return instr;
1382 : }
1383 :
1384 :
1385 1218975 : void HGraphBuilder::FinishCurrentBlock(HControlInstruction* last) {
1386 : DCHECK(!FLAG_hydrogen_track_positions || !info_->IsOptimizing() ||
1387 : position_.IsKnown());
1388 1218975 : current_block()->Finish(last, source_position());
1389 3633442 : if (last->IsReturn() || last->IsAbnormalExit()) {
1390 : set_current_block(NULL);
1391 : }
1392 1218975 : }
1393 :
1394 :
1395 354654 : void HGraphBuilder::FinishExitCurrentBlock(HControlInstruction* instruction) {
1396 : DCHECK(!FLAG_hydrogen_track_positions || !info_->IsOptimizing() ||
1397 : position_.IsKnown());
1398 : current_block()->FinishExit(instruction, source_position());
1399 722263 : if (instruction->IsReturn() || instruction->IsAbnormalExit()) {
1400 : set_current_block(NULL);
1401 : }
1402 354654 : }
1403 :
1404 :
1405 54904 : void HGraphBuilder::AddIncrementCounter(StatsCounter* counter) {
1406 54904 : if (FLAG_native_code_counters && counter->Enabled()) {
1407 0 : HValue* reference = Add<HConstant>(ExternalReference(counter));
1408 : HValue* old_value =
1409 0 : Add<HLoadNamedField>(reference, nullptr, HObjectAccess::ForCounter());
1410 0 : 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 0 : new_value, STORE_TO_INITIALIZED_ENTRY);
1414 : }
1415 54904 : }
1416 :
1417 :
1418 0 : void HGraphBuilder::AddSimulate(BailoutId id,
1419 335797 : RemovableSimulate removable) {
1420 : DCHECK(current_block() != NULL);
1421 : DCHECK(!graph()->IsInsideNoSideEffectsScope());
1422 335797 : current_block()->AddNewSimulate(id, source_position(), removable);
1423 0 : }
1424 :
1425 :
1426 1050384 : HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) {
1427 1050384 : HBasicBlock* b = graph()->CreateBasicBlock();
1428 : b->SetInitialEnvironment(env);
1429 1050383 : return b;
1430 : }
1431 :
1432 :
1433 61068 : HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() {
1434 61068 : HBasicBlock* header = graph()->CreateBasicBlock();
1435 61068 : HEnvironment* entry_env = environment()->CopyAsLoopHeader(header);
1436 : header->SetInitialEnvironment(entry_env);
1437 61068 : header->AttachLoopInformation();
1438 61068 : return header;
1439 : }
1440 :
1441 :
1442 10 : HValue* HGraphBuilder::BuildGetElementsKind(HValue* object) {
1443 10 : HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap());
1444 :
1445 : HValue* bit_field2 =
1446 10 : Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField2());
1447 10 : return BuildDecodeField<Map::ElementsKindBits>(bit_field2);
1448 : }
1449 :
1450 :
1451 1078 : HValue* HGraphBuilder::BuildEnumLength(HValue* map) {
1452 : NoObservableSideEffectsScope scope(this);
1453 : HValue* bit_field3 =
1454 1078 : Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField3());
1455 2156 : return BuildDecodeField<Map::EnumLengthBits>(bit_field3);
1456 : }
1457 :
1458 :
1459 0 : HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) {
1460 310748 : if (obj->type().IsHeapObject()) return obj;
1461 180870 : return Add<HCheckHeapObject>(obj);
1462 : }
1463 :
1464 8229 : void HGraphBuilder::FinishExitWithHardDeoptimization(DeoptimizeReason reason) {
1465 8229 : Add<HDeoptimize>(reason, Deoptimizer::EAGER);
1466 8229 : FinishExitCurrentBlock(New<HAbnormalExit>());
1467 8229 : }
1468 :
1469 :
1470 82211 : HValue* HGraphBuilder::BuildCheckString(HValue* string) {
1471 82211 : if (!string->type().IsString()) {
1472 : DCHECK(!string->IsConstant() ||
1473 : !HConstant::cast(string)->HasStringValue());
1474 : BuildCheckHeapObject(string);
1475 31586 : return Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING);
1476 : }
1477 : return string;
1478 : }
1479 :
1480 6215 : HValue* HGraphBuilder::BuildWrapReceiver(HValue* object, HValue* checked) {
1481 5493 : if (object->type().IsJSObject()) return object;
1482 5166 : HValue* function = checked->ActualValue();
1483 15498 : if (function->IsConstant() &&
1484 5888 : HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
1485 : Handle<JSFunction> f = Handle<JSFunction>::cast(
1486 361 : HConstant::cast(function)->handle(isolate()));
1487 : SharedFunctionInfo* shared = f->shared();
1488 615 : if (is_strict(shared->language_mode()) || shared->native()) return object;
1489 : }
1490 4925 : return Add<HWrapReceiver>(object, checked);
1491 : }
1492 :
1493 :
1494 0 : HValue* HGraphBuilder::BuildCheckAndGrowElementsCapacity(
1495 : HValue* object, HValue* elements, ElementsKind kind, HValue* length,
1496 : HValue* capacity, HValue* key) {
1497 0 : HValue* max_gap = Add<HConstant>(static_cast<int32_t>(JSObject::kMaxGap));
1498 0 : HValue* max_capacity = AddUncasted<HAdd>(capacity, max_gap);
1499 0 : Add<HBoundsCheck>(key, max_capacity);
1500 :
1501 0 : HValue* new_capacity = BuildNewElementsCapacity(key);
1502 : HValue* new_elements = BuildGrowElementsCapacity(object, elements, kind, kind,
1503 0 : length, new_capacity);
1504 0 : return new_elements;
1505 : }
1506 :
1507 :
1508 2593 : HValue* HGraphBuilder::BuildCheckForCapacityGrow(
1509 : HValue* object,
1510 : HValue* elements,
1511 : ElementsKind kind,
1512 : HValue* length,
1513 : HValue* key,
1514 : bool is_js_array,
1515 3056 : PropertyAccessType access_type) {
1516 : IfBuilder length_checker(this);
1517 :
1518 2593 : Token::Value token = IsHoleyElementsKind(kind) ? Token::GTE : Token::EQ;
1519 2593 : length_checker.If<HCompareNumericAndBranch>(key, length, token);
1520 :
1521 2593 : length_checker.Then();
1522 :
1523 : HValue* current_capacity = AddLoadFixedArrayLength(elements);
1524 :
1525 2593 : if (top_info()->IsStub()) {
1526 : IfBuilder capacity_checker(this);
1527 : capacity_checker.If<HCompareNumericAndBranch>(key, current_capacity,
1528 0 : Token::GTE);
1529 0 : capacity_checker.Then();
1530 : HValue* new_elements = BuildCheckAndGrowElementsCapacity(
1531 0 : object, elements, kind, length, current_capacity, key);
1532 : environment()->Push(new_elements);
1533 : capacity_checker.Else();
1534 : environment()->Push(elements);
1535 0 : capacity_checker.End();
1536 : } else {
1537 : HValue* result = Add<HMaybeGrowElements>(
1538 2593 : object, elements, key, current_capacity, is_js_array, kind);
1539 : environment()->Push(result);
1540 : }
1541 :
1542 2593 : if (is_js_array) {
1543 5170 : HValue* new_length = AddUncasted<HAdd>(key, graph_->GetConstant1());
1544 : new_length->ClearFlag(HValue::kCanOverflow);
1545 :
1546 : Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(kind),
1547 2585 : new_length);
1548 : }
1549 :
1550 2593 : 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 463 : kind);
1556 : }
1557 :
1558 : length_checker.Else();
1559 2593 : Add<HBoundsCheck>(key, length);
1560 :
1561 : environment()->Push(elements);
1562 2593 : length_checker.End();
1563 :
1564 5186 : return environment()->Pop();
1565 : }
1566 :
1567 :
1568 237 : HValue* HGraphBuilder::BuildCopyElementsOnWrite(HValue* object,
1569 : HValue* elements,
1570 : ElementsKind kind,
1571 237 : HValue* length) {
1572 : Factory* factory = isolate()->factory();
1573 :
1574 : IfBuilder cow_checker(this);
1575 :
1576 237 : cow_checker.If<HCompareMap>(elements, factory->fixed_cow_array_map());
1577 237 : cow_checker.Then();
1578 :
1579 : HValue* capacity = AddLoadFixedArrayLength(elements);
1580 :
1581 : HValue* new_elements = BuildGrowElementsCapacity(object, elements, kind,
1582 237 : kind, length, capacity);
1583 :
1584 : environment()->Push(new_elements);
1585 :
1586 : cow_checker.Else();
1587 :
1588 : environment()->Push(elements);
1589 :
1590 237 : cow_checker.End();
1591 :
1592 474 : return environment()->Pop();
1593 : }
1594 :
1595 0 : HValue* HGraphBuilder::BuildElementIndexHash(HValue* index) {
1596 0 : int32_t seed_value = static_cast<uint32_t>(isolate()->heap()->HashSeed());
1597 0 : HValue* seed = Add<HConstant>(seed_value);
1598 0 : HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, index, seed);
1599 :
1600 : // hash = ~hash + (hash << 15);
1601 0 : HValue* shifted_hash = AddUncasted<HShl>(hash, Add<HConstant>(15));
1602 : HValue* not_hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash,
1603 0 : graph()->GetConstantMinus1());
1604 0 : hash = AddUncasted<HAdd>(shifted_hash, not_hash);
1605 :
1606 : // hash = hash ^ (hash >> 12);
1607 0 : shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(12));
1608 0 : hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
1609 :
1610 : // hash = hash + (hash << 2);
1611 0 : shifted_hash = AddUncasted<HShl>(hash, Add<HConstant>(2));
1612 0 : hash = AddUncasted<HAdd>(hash, shifted_hash);
1613 :
1614 : // hash = hash ^ (hash >> 4);
1615 0 : shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(4));
1616 0 : hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
1617 :
1618 : // hash = hash * 2057;
1619 0 : hash = AddUncasted<HMul>(hash, Add<HConstant>(2057));
1620 : hash->ClearFlag(HValue::kCanOverflow);
1621 :
1622 : // hash = hash ^ (hash >> 16);
1623 0 : shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(16));
1624 0 : return AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
1625 : }
1626 :
1627 0 : HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver,
1628 : HValue* elements,
1629 : HValue* key,
1630 0 : HValue* hash) {
1631 : HValue* capacity =
1632 : Add<HLoadKeyed>(elements, Add<HConstant>(NameDictionary::kCapacityIndex),
1633 0 : nullptr, nullptr, FAST_ELEMENTS);
1634 :
1635 0 : 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 0 : Push(entry);
1642 0 : Push(count);
1643 :
1644 : HIfContinuation return_or_loop_continuation(graph()->CreateBasicBlock(),
1645 0 : graph()->CreateBasicBlock());
1646 : HIfContinuation found_key_match_continuation(graph()->CreateBasicBlock(),
1647 0 : graph()->CreateBasicBlock());
1648 : LoopBuilder probe_loop(this);
1649 0 : 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 0 : entry = AddUncasted<HBitwise>(Token::BIT_AND, entry, mask);
1655 : int entry_size = SeededNumberDictionary::kEntrySize;
1656 0 : 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 0 : AddUncasted<HAdd>(base_index, Add<HConstant>(start_offset));
1661 : key_index->ClearFlag(HValue::kCanOverflow);
1662 :
1663 : HValue* candidate_key =
1664 0 : Add<HLoadKeyed>(elements, key_index, nullptr, nullptr, FAST_ELEMENTS);
1665 : IfBuilder if_undefined(this);
1666 : if_undefined.If<HCompareObjectEqAndBranch>(candidate_key,
1667 0 : graph()->GetConstantUndefined());
1668 0 : if_undefined.Then();
1669 : {
1670 : // element == undefined means "not found". Call the runtime.
1671 : // TODO(jkummerow): walk the prototype chain instead.
1672 0 : Add<HPushArguments>(receiver, key);
1673 : Push(Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kKeyedGetProperty),
1674 0 : 2));
1675 : }
1676 : if_undefined.Else();
1677 : {
1678 : IfBuilder if_match(this);
1679 0 : if_match.If<HCompareObjectEqAndBranch>(candidate_key, key);
1680 0 : 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 0 : if_update_with_internalized.And();
1688 : HValue* map = AddLoadMap(candidate_key, smi_check);
1689 : HValue* instance_type =
1690 0 : Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapInstanceType());
1691 : HValue* not_internalized_bit = AddUncasted<HBitwise>(
1692 : Token::BIT_AND, instance_type,
1693 0 : Add<HConstant>(static_cast<int>(kIsNotInternalizedMask)));
1694 : if_update_with_internalized.If<HCompareNumericAndBranch>(
1695 0 : not_internalized_bit, graph()->GetConstant0(), Token::NE);
1696 0 : if_update_with_internalized.And();
1697 : if_update_with_internalized.IfNot<HCompareObjectEqAndBranch>(
1698 0 : candidate_key, graph()->GetConstantHole());
1699 : if_update_with_internalized.AndIf<HStringCompareAndBranch>(candidate_key,
1700 : key, Token::EQ);
1701 0 : 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 0 : Add<HStoreKeyed>(elements, key_index, key, nullptr, FAST_ELEMENTS);
1705 : if_update_with_internalized.Else();
1706 :
1707 0 : if_update_with_internalized.JoinContinuation(&found_key_match_continuation);
1708 0 : if_match.JoinContinuation(&found_key_match_continuation);
1709 :
1710 : IfBuilder found_key_match(this, &found_key_match_continuation);
1711 0 : 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 0 : 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 0 : FAST_ELEMENTS);
1719 : int details_mask = PropertyDetails::KindField::kMask;
1720 : details = AddUncasted<HBitwise>(Token::BIT_AND, details,
1721 0 : Add<HConstant>(details_mask));
1722 : IfBuilder details_compare(this);
1723 : details_compare.If<HCompareNumericAndBranch>(details, New<HConstant>(kData),
1724 0 : Token::EQ);
1725 0 : details_compare.Then();
1726 : HValue* result_index =
1727 0 : 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 0 : FAST_ELEMENTS));
1731 : details_compare.Else();
1732 0 : Add<HPushArguments>(receiver, key);
1733 : Push(Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kKeyedGetProperty),
1734 0 : 2));
1735 0 : details_compare.End();
1736 :
1737 : found_key_match.Else();
1738 0 : found_key_match.JoinContinuation(&return_or_loop_continuation);
1739 : }
1740 0 : if_undefined.JoinContinuation(&return_or_loop_continuation);
1741 :
1742 : IfBuilder return_or_loop(this, &return_or_loop_continuation);
1743 0 : return_or_loop.Then();
1744 0 : probe_loop.Break();
1745 :
1746 : return_or_loop.Else();
1747 0 : entry = AddUncasted<HAdd>(entry, count);
1748 : entry->ClearFlag(HValue::kCanOverflow);
1749 0 : count = AddUncasted<HAdd>(count, graph()->GetConstant1());
1750 : count->ClearFlag(HValue::kCanOverflow);
1751 0 : Push(entry);
1752 0 : Push(count);
1753 :
1754 0 : probe_loop.EndBody();
1755 :
1756 0 : return_or_loop.End();
1757 :
1758 0 : return Pop();
1759 : }
1760 :
1761 9 : 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 9 : NOT_TENURED, JS_OBJECT_TYPE, graph()->GetConstant0());
1769 :
1770 : // Initialize the JSIteratorResult object.
1771 9 : HValue* native_context = BuildGetNativeContext();
1772 : HValue* map = Add<HLoadNamedField>(
1773 : native_context, nullptr,
1774 9 : HObjectAccess::ForContextSlot(Context::ITERATOR_RESULT_MAP_INDEX));
1775 9 : Add<HStoreNamedField>(result, HObjectAccess::ForMap(), map);
1776 9 : HValue* empty_fixed_array = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex);
1777 : Add<HStoreNamedField>(result, HObjectAccess::ForPropertiesPointer(),
1778 9 : empty_fixed_array);
1779 : Add<HStoreNamedField>(result, HObjectAccess::ForElementsPointer(),
1780 9 : empty_fixed_array);
1781 : Add<HStoreNamedField>(result, HObjectAccess::ForObservableJSObjectOffset(
1782 : JSIteratorResult::kValueOffset),
1783 9 : value);
1784 : Add<HStoreNamedField>(result, HObjectAccess::ForObservableJSObjectOffset(
1785 : JSIteratorResult::kDoneOffset),
1786 9 : done);
1787 : STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
1788 9 : return result;
1789 : }
1790 :
1791 :
1792 41182 : HValue* HGraphBuilder::BuildNumberToString(HValue* object, AstType* type) {
1793 : NoObservableSideEffectsScope scope(this);
1794 :
1795 : // Convert constant numbers at compile time.
1796 5631 : if (object->IsConstant() && HConstant::cast(object)->HasNumberValue()) {
1797 409 : Handle<Object> number = HConstant::cast(object)->handle(isolate());
1798 409 : Handle<String> result = isolate()->factory()->NumberToString(number);
1799 409 : return Add<HConstant>(result);
1800 : }
1801 :
1802 : // Create a joinable continuation.
1803 : HIfContinuation found(graph()->CreateBasicBlock(),
1804 9586 : graph()->CreateBasicBlock());
1805 :
1806 : // Load the number string cache.
1807 : HValue* number_string_cache =
1808 4793 : 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 4793 : mask = AddUncasted<HSar>(mask, graph()->GetConstant1());
1815 4793 : mask = AddUncasted<HSub>(mask, graph()->GetConstant1());
1816 :
1817 : // Check whether object is a smi.
1818 : IfBuilder if_objectissmi(this);
1819 4793 : if_objectissmi.If<HIsSmiAndBranch>(object);
1820 4793 : if_objectissmi.Then();
1821 : {
1822 : // Compute hash for smi similar to smi_get_hash().
1823 4793 : HValue* hash = AddUncasted<HBitwise>(Token::BIT_AND, object, mask);
1824 :
1825 : // Load the key.
1826 4793 : HValue* key_index = AddUncasted<HShl>(hash, graph()->GetConstant1());
1827 : HValue* key = Add<HLoadKeyed>(number_string_cache, key_index, nullptr,
1828 4793 : nullptr, FAST_ELEMENTS, ALLOW_RETURN_HOLE);
1829 :
1830 : // Check if object == key.
1831 : IfBuilder if_objectiskey(this);
1832 4793 : if_objectiskey.If<HCompareObjectEqAndBranch>(object, key);
1833 4793 : if_objectiskey.Then();
1834 : {
1835 : // Make the key_index available.
1836 4793 : Push(key_index);
1837 : }
1838 4793 : if_objectiskey.JoinContinuation(&found);
1839 : }
1840 : if_objectissmi.Else();
1841 : {
1842 4793 : if (type->Is(AstType::SignedSmall())) {
1843 4256 : 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 537 : object, isolate()->factory()->heap_number_map());
1849 537 : if_objectisnumber.Then();
1850 : {
1851 : // Compute hash for heap number similar to double_get_hash().
1852 : HValue* low = Add<HLoadNamedField>(
1853 : object, objectisnumber,
1854 537 : HObjectAccess::ForHeapNumberValueLowestBits());
1855 : HValue* high = Add<HLoadNamedField>(
1856 : object, objectisnumber,
1857 537 : HObjectAccess::ForHeapNumberValueHighestBits());
1858 537 : HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, low, high);
1859 537 : hash = AddUncasted<HBitwise>(Token::BIT_AND, hash, mask);
1860 :
1861 : // Load the key.
1862 537 : HValue* key_index = AddUncasted<HShl>(hash, graph()->GetConstant1());
1863 : HValue* key =
1864 : Add<HLoadKeyed>(number_string_cache, key_index, nullptr, nullptr,
1865 537 : 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 537 : if_keyisnotsmi.Then();
1871 : {
1872 : IfBuilder if_keyisheapnumber(this);
1873 : if_keyisheapnumber.If<HCompareMap>(
1874 537 : key, isolate()->factory()->heap_number_map());
1875 537 : 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 537 : HObjectAccess::ForHeapNumberValue()),
1882 : Add<HLoadNamedField>(object, objectisnumber,
1883 : HObjectAccess::ForHeapNumberValue()),
1884 1074 : Token::EQ);
1885 537 : if_keyeqobject.Then();
1886 : {
1887 : // Make the key_index available.
1888 537 : Push(key_index);
1889 : }
1890 537 : if_keyeqobject.JoinContinuation(&found);
1891 : }
1892 537 : if_keyisheapnumber.JoinContinuation(&found);
1893 : }
1894 537 : if_keyisnotsmi.JoinContinuation(&found);
1895 : }
1896 : if_objectisnumber.Else();
1897 : {
1898 537 : if (type->Is(AstType::Number())) {
1899 537 : if_objectisnumber.Deopt(DeoptimizeReason::kExpectedHeapNumber);
1900 : }
1901 : }
1902 537 : if_objectisnumber.JoinContinuation(&found);
1903 : }
1904 : }
1905 4793 : if_objectissmi.JoinContinuation(&found);
1906 :
1907 : // Check for cache hit.
1908 : IfBuilder if_found(this, &found);
1909 4793 : if_found.Then();
1910 : {
1911 : // Count number to string operation in native code.
1912 4793 : AddIncrementCounter(isolate()->counters()->number_to_string_native());
1913 :
1914 : // Load the value in case of cache hit.
1915 : HValue* key_index = Pop();
1916 4793 : HValue* value_index = AddUncasted<HAdd>(key_index, graph()->GetConstant1());
1917 : Push(Add<HLoadKeyed>(number_string_cache, value_index, nullptr, nullptr,
1918 4793 : FAST_ELEMENTS, ALLOW_RETURN_HOLE));
1919 : }
1920 : if_found.Else();
1921 : {
1922 : // Cache miss, fallback to runtime.
1923 4793 : Add<HPushArguments>(object);
1924 : Push(Add<HCallRuntime>(
1925 : Runtime::FunctionForId(Runtime::kNumberToStringSkipCache),
1926 4793 : 1));
1927 : }
1928 4793 : if_found.End();
1929 :
1930 : return Pop();
1931 : }
1932 :
1933 17879 : HValue* HGraphBuilder::BuildToNumber(HValue* input) {
1934 27890 : if (input->type().IsTaggedNumber() ||
1935 18244 : input->representation().IsSpecialization()) {
1936 : return input;
1937 : }
1938 8233 : Callable callable = CodeFactory::ToNumber(isolate());
1939 8233 : HValue* stub = Add<HConstant>(callable.code());
1940 8233 : HValue* values[] = {input};
1941 : HCallWithDescriptor* instr = Add<HCallWithDescriptor>(
1942 8233 : stub, 0, callable.descriptor(), ArrayVector(values));
1943 : instr->set_type(HType::TaggedNumber());
1944 : return instr;
1945 : }
1946 :
1947 :
1948 762 : HValue* HGraphBuilder::BuildToObject(HValue* receiver) {
1949 : NoObservableSideEffectsScope scope(this);
1950 :
1951 : // Create a joinable continuation.
1952 : HIfContinuation wrap(graph()->CreateBasicBlock(),
1953 762 : 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 381 : receiver_is_smi.If<HIsSmiAndBranch>(receiver);
1961 381 : receiver_is_smi.Then();
1962 : {
1963 : // Use global Number function.
1964 381 : 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 381 : Add<HLoadNamedField>(receiver, nullptr, HObjectAccess::ForMap());
1971 : HValue* receiver_instance_type = Add<HLoadNamedField>(
1972 381 : 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 381 : Token::LT);
1979 381 : 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 381 : 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 381 : Add<HConstant>(Map::kNoConstructorFunctionIndex), Token::EQ);
1992 : constructor_function_index_is_invalid.ThenDeopt(
1993 : DeoptimizeReason::kUndefinedOrNullInToObject);
1994 381 : constructor_function_index_is_invalid.End();
1995 :
1996 : // Use the global constructor function.
1997 381 : Push(constructor_function_index);
1998 : }
1999 381 : receiver_is_not_spec_object.JoinContinuation(&wrap);
2000 : }
2001 381 : receiver_is_smi.JoinContinuation(&wrap);
2002 :
2003 : // Wrap the receiver if necessary.
2004 : IfBuilder if_wrap(this, &wrap);
2005 381 : if_wrap.Then();
2006 : {
2007 : // Grab the constructor function index.
2008 : HValue* constructor_index = Pop();
2009 :
2010 : // Load native context.
2011 381 : HValue* native_context = BuildGetNativeContext();
2012 :
2013 : // Determine the initial map for the global constructor.
2014 : HValue* constructor = Add<HLoadKeyed>(native_context, constructor_index,
2015 381 : nullptr, nullptr, FAST_ELEMENTS);
2016 : HValue* constructor_initial_map = Add<HLoadNamedField>(
2017 381 : constructor, nullptr, HObjectAccess::ForPrototypeOrInitialMap());
2018 : // Allocate and initialize a JSValue wrapper.
2019 : HValue* value =
2020 381 : BuildAllocate(Add<HConstant>(JSValue::kSize), HType::JSObject(),
2021 381 : JS_VALUE_TYPE, HAllocationMode());
2022 : Add<HStoreNamedField>(value, HObjectAccess::ForMap(),
2023 381 : constructor_initial_map);
2024 381 : HValue* empty_fixed_array = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex);
2025 : Add<HStoreNamedField>(value, HObjectAccess::ForPropertiesPointer(),
2026 381 : empty_fixed_array);
2027 : Add<HStoreNamedField>(value, HObjectAccess::ForElementsPointer(),
2028 381 : empty_fixed_array);
2029 : Add<HStoreNamedField>(value, HObjectAccess::ForObservableJSObjectOffset(
2030 : JSValue::kValueOffset),
2031 381 : receiver);
2032 381 : Push(value);
2033 : }
2034 : if_wrap.Else();
2035 381 : { Push(receiver); }
2036 381 : if_wrap.End();
2037 381 : return Pop();
2038 : }
2039 :
2040 :
2041 23917 : HAllocate* HGraphBuilder::BuildAllocate(
2042 : HValue* object_size,
2043 : HType type,
2044 : InstanceType instance_type,
2045 23917 : HAllocationMode allocation_mode) {
2046 : // Compute the effective allocation size.
2047 : HValue* size = object_size;
2048 23917 : if (allocation_mode.CreateAllocationMementos()) {
2049 7136 : 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 23917 : graph()->GetConstant0(), allocation_mode.feedback_site());
2057 :
2058 : // Setup the allocation memento.
2059 23917 : if (allocation_mode.CreateAllocationMementos()) {
2060 : BuildCreateAllocationMemento(
2061 7136 : object, object_size, allocation_mode.current_site());
2062 : }
2063 :
2064 23917 : return object;
2065 : }
2066 :
2067 :
2068 15417 : HValue* HGraphBuilder::BuildAddStringLengths(HValue* left_length,
2069 39099 : HValue* right_length) {
2070 : // Compute the combined string length and check against max string length.
2071 15417 : HValue* length = AddUncasted<HAdd>(left_length, right_length);
2072 : // Check that length <= kMaxLength <=> length < MaxLength + 1.
2073 15417 : HValue* max_length = Add<HConstant>(String::kMaxLength + 1);
2074 27266 : 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 3584 : if_invalid.If<HCompareNumericAndBranch>(length, max_length, Token::GT);
2079 3584 : if_invalid.Then();
2080 : {
2081 : Add<HCallRuntime>(
2082 3584 : Runtime::FunctionForId(Runtime::kThrowInvalidStringLength), 0);
2083 : }
2084 3584 : if_invalid.End();
2085 : } else {
2086 11833 : graph()->MarkDependsOnStringLengthOverflow();
2087 11833 : Add<HBoundsCheck>(length, max_length);
2088 : }
2089 15417 : return length;
2090 : }
2091 :
2092 :
2093 15417 : HValue* HGraphBuilder::BuildCreateConsString(
2094 : HValue* length,
2095 : HValue* left,
2096 : HValue* right,
2097 61668 : HAllocationMode allocation_mode) {
2098 : // Determine the string instance types.
2099 15417 : HInstruction* left_instance_type = AddLoadStringInstanceType(left);
2100 15417 : 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 15417 : HAllocate* result = BuildAllocate(Add<HConstant>(ConsString::kSize),
2109 : HType::String(), CONS_STRING_TYPE,
2110 15417 : allocation_mode);
2111 :
2112 : // Compute intersection and difference of instance types.
2113 : HValue* anded_instance_types = AddUncasted<HBitwise>(
2114 15417 : Token::BIT_AND, left_instance_type, right_instance_type);
2115 : HValue* xored_instance_types = AddUncasted<HBitwise>(
2116 15417 : 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 15417 : kStringEncodingMask | kOneByteDataHintMask))),
2135 15417 : graph()->GetConstant0(), Token::NE);
2136 15417 : 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 15417 : kOneByteStringTag | kOneByteDataHintTag))),
2145 : Add<HConstant>(static_cast<int32_t>(
2146 30834 : kOneByteStringTag | kOneByteDataHintTag)), Token::EQ);
2147 15417 : 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 15417 : 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 15417 : Add<HConstant>(isolate()->factory()->cons_string_map()));
2160 : }
2161 15417 : if_onebyte.End();
2162 :
2163 : // Initialize the cons string fields.
2164 : Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(),
2165 15417 : Add<HConstant>(String::kEmptyHashField));
2166 15417 : Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length);
2167 15417 : Add<HStoreNamedField>(result, HObjectAccess::ForConsStringFirst(), left);
2168 15417 : Add<HStoreNamedField>(result, HObjectAccess::ForConsStringSecond(), right);
2169 :
2170 : // Count the native string addition.
2171 15417 : AddIncrementCounter(isolate()->counters()->string_add_native());
2172 :
2173 15417 : return result;
2174 : }
2175 :
2176 :
2177 14272 : 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 14272 : HValue* length) {
2184 : DCHECK(dst_encoding != String::ONE_BYTE_ENCODING ||
2185 : src_encoding == String::ONE_BYTE_ENCODING);
2186 14272 : LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement);
2187 14272 : HValue* index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT);
2188 : {
2189 14272 : HValue* src_index = AddUncasted<HAdd>(src_offset, index);
2190 : HValue* value =
2191 14272 : AddUncasted<HSeqStringGetChar>(src_encoding, src, src_index);
2192 14272 : HValue* dst_index = AddUncasted<HAdd>(dst_offset, index);
2193 14272 : Add<HSeqStringSetChar>(dst_encoding, dst, dst_index, value);
2194 : }
2195 14272 : loop.EndBody();
2196 14272 : }
2197 :
2198 :
2199 3568 : 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 3568 : header_size + kObjectAlignmentMask)));
2205 : size->ClearFlag(HValue::kCanOverflow);
2206 : return AddUncasted<HBitwise>(
2207 : Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>(
2208 3568 : ~kObjectAlignmentMask)));
2209 : }
2210 :
2211 :
2212 15417 : HValue* HGraphBuilder::BuildUncheckedStringAdd(
2213 : HValue* left,
2214 : HValue* right,
2215 46384 : HAllocationMode allocation_mode) {
2216 : // Determine the string lengths.
2217 15417 : HValue* left_length = AddLoadStringLength(left);
2218 15417 : HValue* right_length = AddLoadStringLength(right);
2219 :
2220 : // Compute the combined string length.
2221 15417 : HValue* length = BuildAddStringLengths(left_length, right_length);
2222 :
2223 : // Do some manual constant folding here.
2224 15417 : if (left_length->IsConstant()) {
2225 1946 : HConstant* c_left_length = HConstant::cast(left_length);
2226 : DCHECK_NE(0, c_left_length->Integer32Value());
2227 1946 : if (c_left_length->Integer32Value() + 1 >= ConsString::kMinLength) {
2228 : // The right string contains at least one character.
2229 1946 : return BuildCreateConsString(length, left, right, allocation_mode);
2230 : }
2231 13471 : } else if (right_length->IsConstant()) {
2232 9903 : HConstant* c_right_length = HConstant::cast(right_length);
2233 : DCHECK_NE(0, c_right_length->Integer32Value());
2234 9903 : if (c_right_length->Integer32Value() + 1 >= ConsString::kMinLength) {
2235 : // The left string contains at least one character.
2236 9903 : 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 3568 : length, Add<HConstant>(ConsString::kMinLength), Token::GTE);
2244 3568 : if_createcons.And();
2245 : if_createcons.If<HCompareNumericAndBranch>(
2246 3568 : length, Add<HConstant>(ConsString::kMaxLength), Token::LTE);
2247 3568 : if_createcons.Then();
2248 : {
2249 : // Create a cons string.
2250 3568 : Push(BuildCreateConsString(length, left, right, allocation_mode));
2251 : }
2252 : if_createcons.Else();
2253 : {
2254 : // Determine the string instance types.
2255 3568 : HValue* left_instance_type = AddLoadStringInstanceType(left);
2256 3568 : HValue* right_instance_type = AddLoadStringInstanceType(right);
2257 :
2258 : // Compute union and difference of instance types.
2259 : HValue* ored_instance_types = AddUncasted<HBitwise>(
2260 3568 : Token::BIT_OR, left_instance_type, right_instance_type);
2261 : HValue* xored_instance_types = AddUncasted<HBitwise>(
2262 3568 : 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 3568 : Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))),
2271 3568 : graph()->GetConstant0(), Token::EQ);
2272 3568 : if_sameencodingandsequential.And();
2273 : STATIC_ASSERT(kSeqStringTag == 0);
2274 : if_sameencodingandsequential.If<HCompareNumericAndBranch>(
2275 : AddUncasted<HBitwise>(
2276 : Token::BIT_AND, ored_instance_types,
2277 3568 : Add<HConstant>(static_cast<int32_t>(kStringRepresentationMask))),
2278 3568 : graph()->GetConstant0(), Token::EQ);
2279 3568 : if_sameencodingandsequential.Then();
2280 : {
2281 : HConstant* string_map =
2282 3568 : Add<HConstant>(isolate()->factory()->string_map());
2283 : HConstant* one_byte_string_map =
2284 3568 : 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 3568 : Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))),
2293 3568 : graph()->GetConstant0(), Token::NE);
2294 3568 : if_onebyte.Then();
2295 : {
2296 : // Allocate sequential one-byte string object.
2297 3568 : Push(length);
2298 3568 : Push(one_byte_string_map);
2299 : }
2300 : if_onebyte.Else();
2301 : {
2302 : // Allocate sequential two-byte string object.
2303 3568 : HValue* size = AddUncasted<HShl>(length, graph()->GetConstant1());
2304 : size->ClearFlag(HValue::kCanOverflow);
2305 : size->SetFlag(HValue::kUint32);
2306 3568 : Push(size);
2307 3568 : Push(string_map);
2308 : }
2309 3568 : 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 3568 : HValue* size = BuildObjectSizeAlignment(Pop(), SeqString::kHeaderSize);
2316 :
2317 : IfBuilder if_size(this);
2318 : if_size.If<HCompareNumericAndBranch>(
2319 3568 : size, Add<HConstant>(kMaxRegularHeapObjectSize), Token::LT);
2320 3568 : 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 3568 : BuildAllocate(size, HType::String(), STRING_TYPE, allocation_mode);
2326 3568 : Add<HStoreNamedField>(result, HObjectAccess::ForMap(), map);
2327 :
2328 : // Initialize the string fields.
2329 : Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(),
2330 3568 : Add<HConstant>(String::kEmptyHashField));
2331 3568 : Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length);
2332 :
2333 : // Copy characters to the result string.
2334 : IfBuilder if_twobyte(this);
2335 3568 : if_twobyte.If<HCompareObjectEqAndBranch>(map, string_map);
2336 3568 : if_twobyte.Then();
2337 : {
2338 : // Copy characters from the left string.
2339 : BuildCopySeqStringChars(
2340 : left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, result,
2341 3568 : 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 3568 : 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 3568 : 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 3568 : left_length, String::ONE_BYTE_ENCODING, right_length);
2359 : }
2360 3568 : if_twobyte.End();
2361 :
2362 : // Count the native string addition.
2363 3568 : AddIncrementCounter(isolate()->counters()->string_add_native());
2364 :
2365 : // Return the sequential string.
2366 3568 : 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 3568 : Add<HPushArguments>(left, right);
2373 3568 : Push(Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kStringAdd), 2));
2374 : }
2375 3568 : if_size.End();
2376 : }
2377 : if_sameencodingandsequential.Else();
2378 : {
2379 : // Fallback to the runtime to add the two strings.
2380 3568 : Add<HPushArguments>(left, right);
2381 3568 : Push(Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kStringAdd), 2));
2382 : }
2383 3568 : if_sameencodingandsequential.End();
2384 : }
2385 3568 : if_createcons.End();
2386 :
2387 : return Pop();
2388 : }
2389 :
2390 :
2391 15417 : HValue* HGraphBuilder::BuildStringAdd(
2392 : HValue* left,
2393 : HValue* right,
2394 61668 : HAllocationMode allocation_mode) {
2395 : NoObservableSideEffectsScope no_effects(this);
2396 :
2397 : // Determine string lengths.
2398 15417 : HValue* left_length = AddLoadStringLength(left);
2399 15417 : HValue* right_length = AddLoadStringLength(right);
2400 :
2401 : // Check if left string is empty.
2402 : IfBuilder if_leftempty(this);
2403 : if_leftempty.If<HCompareNumericAndBranch>(
2404 15417 : left_length, graph()->GetConstant0(), Token::EQ);
2405 15417 : if_leftempty.Then();
2406 : {
2407 : // Count the native string addition.
2408 15417 : AddIncrementCounter(isolate()->counters()->string_add_native());
2409 :
2410 : // Just return the right string.
2411 15417 : 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 15417 : right_length, graph()->GetConstant0(), Token::EQ);
2419 15417 : if_rightempty.Then();
2420 : {
2421 : // Count the native string addition.
2422 15417 : AddIncrementCounter(isolate()->counters()->string_add_native());
2423 :
2424 : // Just return the left string.
2425 15417 : Push(left);
2426 : }
2427 : if_rightempty.Else();
2428 : {
2429 : // Add the two non-empty strings.
2430 15417 : Push(BuildUncheckedStringAdd(left, right, allocation_mode));
2431 : }
2432 15417 : if_rightempty.End();
2433 : }
2434 15417 : if_leftempty.End();
2435 :
2436 15417 : return Pop();
2437 : }
2438 :
2439 :
2440 27712 : 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 9381 : 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 49657 : if ((elements_kind == FAST_HOLEY_ELEMENTS) ||
2459 21945 : (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 27712 : 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 5891 : elements, isolate()->factory()->fixed_array_map());
2470 : check_cow_map->ClearDependsOnFlag(kElementsKind);
2471 : }
2472 : HInstruction* length = NULL;
2473 27712 : if (is_js_array) {
2474 : length = Add<HLoadNamedField>(
2475 : checked_object->ActualValue(), checked_object,
2476 22991 : HObjectAccess::ForArrayLength(elements_kind));
2477 : } else {
2478 : length = AddLoadFixedArrayLength(elements);
2479 : }
2480 : length->set_type(HType::Smi());
2481 : HValue* checked_key = NULL;
2482 27712 : if (IsFixedTypedArrayElementsKind(elements_kind)) {
2483 3894 : checked_object = Add<HCheckArrayBufferNotNeutered>(checked_object);
2484 :
2485 : HValue* external_pointer = Add<HLoadNamedField>(
2486 : elements, nullptr,
2487 3894 : HObjectAccess::ForFixedTypedArrayBaseExternalPointer());
2488 : HValue* base_pointer = Add<HLoadNamedField>(
2489 3894 : elements, nullptr, HObjectAccess::ForFixedTypedArrayBaseBasePointer());
2490 : HValue* backing_store = AddUncasted<HAdd>(external_pointer, base_pointer,
2491 3894 : AddOfExternalAndTagged);
2492 :
2493 3894 : if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
2494 : NoObservableSideEffectsScope no_effects(this);
2495 : IfBuilder length_checker(this);
2496 40 : length_checker.If<HCompareNumericAndBranch>(key, length, Token::LT);
2497 40 : length_checker.Then();
2498 : IfBuilder negative_checker(this);
2499 : HValue* bounds_check = negative_checker.If<HCompareNumericAndBranch>(
2500 40 : key, graph()->GetConstant0(), Token::GTE);
2501 40 : negative_checker.Then();
2502 : HInstruction* result = AddElementAccess(
2503 : backing_store, key, val, bounds_check, checked_object->ActualValue(),
2504 40 : elements_kind, access_type);
2505 40 : negative_checker.ElseDeopt(DeoptimizeReason::kNegativeKeyEncountered);
2506 40 : negative_checker.End();
2507 40 : length_checker.End();
2508 : return result;
2509 : } else {
2510 : DCHECK(store_mode == STANDARD_STORE);
2511 3854 : checked_key = Add<HBoundsCheck>(key, length);
2512 : return AddElementAccess(backing_store, checked_key, val, checked_object,
2513 : checked_object->ActualValue(), elements_kind,
2514 3854 : 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 26011 : if (access_type == STORE && IsFastSmiElementsKind(elements_kind) &&
2525 : !val->type().IsSmi()) {
2526 1309 : val = AddUncasted<HForceRepresentation>(val, Representation::Smi());
2527 : }
2528 :
2529 23818 : if (IsGrowStoreMode(store_mode)) {
2530 : NoObservableSideEffectsScope no_effects(this);
2531 : Representation representation = HStoreKeyed::RequiredValueRepresentation(
2532 2593 : elements_kind, STORE_TO_INITIALIZED_ENTRY);
2533 2593 : val = AddUncasted<HForceRepresentation>(val, representation);
2534 : elements = BuildCheckForCapacityGrow(checked_object, elements,
2535 : elements_kind, length, key,
2536 2593 : is_js_array, access_type);
2537 : checked_key = key;
2538 : } else {
2539 21225 : checked_key = Add<HBoundsCheck>(key, length);
2540 :
2541 21225 : if (access_type == STORE && (fast_elements || fast_smi_only_elements)) {
2542 3566 : if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) {
2543 : NoObservableSideEffectsScope no_effects(this);
2544 : elements = BuildCopyElementsOnWrite(checked_object, elements,
2545 116 : elements_kind, length);
2546 : } else {
2547 : HCheckMaps* check_cow_map = Add<HCheckMaps>(
2548 3450 : 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 23818 : elements_kind, access_type, load_mode);
2555 : }
2556 :
2557 :
2558 534 : HValue* HGraphBuilder::BuildCalculateElementsSize(ElementsKind kind,
2559 1068 : HValue* capacity) {
2560 : int elements_size = IsFastDoubleElementsKind(kind)
2561 : ? kDoubleSize
2562 : : kPointerSize;
2563 :
2564 534 : HConstant* elements_size_value = Add<HConstant>(elements_size);
2565 : HInstruction* mul =
2566 534 : HMul::NewImul(isolate(), zone(), context(), capacity->ActualValue(),
2567 1602 : elements_size_value);
2568 534 : AddInstruction(mul);
2569 : mul->ClearFlag(HValue::kCanOverflow);
2570 :
2571 : STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize);
2572 :
2573 534 : HConstant* header_size = Add<HConstant>(FixedArray::kHeaderSize);
2574 534 : HValue* total_size = AddUncasted<HAdd>(mul, header_size);
2575 : total_size->ClearFlag(HValue::kCanOverflow);
2576 534 : return total_size;
2577 : }
2578 :
2579 :
2580 484 : HAllocate* HGraphBuilder::AllocateJSArrayObject(AllocationSiteMode mode) {
2581 : int base_size = JSArray::kSize;
2582 242 : if (mode == TRACK_ALLOCATION_SITE) {
2583 : base_size += AllocationMemento::kSize;
2584 : }
2585 242 : HConstant* size_in_bytes = Add<HConstant>(base_size);
2586 : return Add<HAllocate>(size_in_bytes, HType::JSArray(), NOT_TENURED,
2587 242 : JS_OBJECT_TYPE, graph()->GetConstant0());
2588 : }
2589 :
2590 :
2591 0 : HConstant* HGraphBuilder::EstablishElementsAllocationSize(
2592 : ElementsKind kind,
2593 : int capacity) {
2594 : int base_size = IsFastDoubleElementsKind(kind)
2595 : ? FixedDoubleArray::SizeFor(capacity)
2596 0 : : FixedArray::SizeFor(capacity);
2597 :
2598 0 : return Add<HConstant>(base_size);
2599 : }
2600 :
2601 :
2602 534 : HAllocate* HGraphBuilder::BuildAllocateElements(ElementsKind kind,
2603 534 : HValue* size_in_bytes) {
2604 : InstanceType instance_type = IsFastDoubleElementsKind(kind)
2605 : ? FIXED_DOUBLE_ARRAY_TYPE
2606 534 : : FIXED_ARRAY_TYPE;
2607 :
2608 : return Add<HAllocate>(size_in_bytes, HType::HeapObject(), NOT_TENURED,
2609 534 : instance_type, graph()->GetConstant0());
2610 : }
2611 :
2612 :
2613 2361 : void HGraphBuilder::BuildInitializeElementsHeader(HValue* elements,
2614 : ElementsKind kind,
2615 2361 : HValue* capacity) {
2616 : Factory* factory = isolate()->factory();
2617 : Handle<Map> map = IsFastDoubleElementsKind(kind)
2618 : ? factory->fixed_double_array_map()
2619 4722 : : factory->fixed_array_map();
2620 :
2621 2361 : Add<HStoreNamedField>(elements, HObjectAccess::ForMap(), Add<HConstant>(map));
2622 : Add<HStoreNamedField>(elements, HObjectAccess::ForFixedArrayLength(),
2623 2361 : capacity);
2624 2361 : }
2625 :
2626 :
2627 292 : 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 292 : capacity = AddUncasted<HForceRepresentation>(capacity, Representation::Smi());
2632 292 : HValue* size_in_bytes = BuildCalculateElementsSize(kind, capacity);
2633 292 : HValue* new_array = BuildAllocateElements(kind, size_in_bytes);
2634 292 : BuildInitializeElementsHeader(new_array, kind, capacity);
2635 292 : return new_array;
2636 : }
2637 :
2638 :
2639 242 : 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 242 : Add<HStoreNamedField>(array, HObjectAccess::ForMap(), array_map);
2647 :
2648 242 : HValue* empty_fixed_array = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex);
2649 :
2650 : Add<HStoreNamedField>(
2651 242 : array, HObjectAccess::ForPropertiesPointer(), empty_fixed_array);
2652 :
2653 : Add<HStoreNamedField>(array, HObjectAccess::ForElementsPointer(),
2654 242 : elements != nullptr ? elements : empty_fixed_array);
2655 :
2656 : Add<HStoreNamedField>(
2657 242 : array, HObjectAccess::ForArrayLength(elements_kind), length_field);
2658 :
2659 242 : if (mode == TRACK_ALLOCATION_SITE) {
2660 : BuildCreateAllocationMemento(
2661 0 : array, Add<HConstant>(JSArray::kSize), allocation_site_payload);
2662 : }
2663 242 : }
2664 :
2665 :
2666 28070 : HInstruction* HGraphBuilder::AddElementAccess(
2667 : HValue* elements, HValue* checked_key, HValue* val, HValue* dependency,
2668 : HValue* backing_store_owner, ElementsKind elements_kind,
2669 276 : PropertyAccessType access_type, LoadKeyedHoleMode load_mode) {
2670 28070 : if (access_type == STORE) {
2671 : DCHECK(val != NULL);
2672 8510 : if (elements_kind == UINT8_CLAMPED_ELEMENTS) {
2673 335 : val = Add<HClampToUint8>(val);
2674 : }
2675 : return Add<HStoreKeyed>(elements, checked_key, val, backing_store_owner,
2676 8510 : 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 19560 : elements_kind, load_mode);
2684 19560 : if (elements_kind == UINT32_ELEMENTS) {
2685 276 : graph()->RecordUint32Instruction(load);
2686 : }
2687 19560 : return load;
2688 : }
2689 :
2690 :
2691 0 : HLoadNamedField* HGraphBuilder::AddLoadMap(HValue* object,
2692 : HValue* dependency) {
2693 133 : return Add<HLoadNamedField>(object, dependency, HObjectAccess::ForMap());
2694 : }
2695 :
2696 :
2697 55 : HLoadNamedField* HGraphBuilder::AddLoadElements(HValue* object,
2698 : HValue* dependency) {
2699 : return Add<HLoadNamedField>(
2700 44673 : object, dependency, HObjectAccess::ForElementsPointer());
2701 : }
2702 :
2703 :
2704 55 : HLoadNamedField* HGraphBuilder::AddLoadFixedArrayLength(
2705 : HValue* array,
2706 : HValue* dependency) {
2707 : return Add<HLoadNamedField>(
2708 12927 : array, dependency, HObjectAccess::ForFixedArrayLength());
2709 : }
2710 :
2711 :
2712 170 : HLoadNamedField* HGraphBuilder::AddLoadArrayLength(HValue* array,
2713 : ElementsKind kind,
2714 : HValue* dependency) {
2715 : return Add<HLoadNamedField>(
2716 170 : array, dependency, HObjectAccess::ForArrayLength(kind));
2717 : }
2718 :
2719 :
2720 0 : HValue* HGraphBuilder::BuildNewElementsCapacity(HValue* old_capacity) {
2721 : HValue* half_old_capacity = AddUncasted<HShr>(old_capacity,
2722 0 : graph_->GetConstant1());
2723 :
2724 0 : HValue* new_capacity = AddUncasted<HAdd>(half_old_capacity, old_capacity);
2725 : new_capacity->ClearFlag(HValue::kCanOverflow);
2726 :
2727 0 : HValue* min_growth = Add<HConstant>(16);
2728 :
2729 0 : new_capacity = AddUncasted<HAdd>(new_capacity, min_growth);
2730 : new_capacity->ClearFlag(HValue::kCanOverflow);
2731 :
2732 0 : return new_capacity;
2733 : }
2734 :
2735 :
2736 292 : 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 292 : ElementsKindToShiftSize(new_kind)));
2746 :
2747 : HValue* new_elements =
2748 292 : BuildAllocateAndInitializeArray(new_kind, new_capacity);
2749 :
2750 : BuildCopyElements(elements, kind, new_elements,
2751 292 : new_kind, length, new_capacity);
2752 :
2753 : Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
2754 292 : new_elements);
2755 :
2756 292 : return new_elements;
2757 : }
2758 :
2759 :
2760 534 : void HGraphBuilder::BuildFillElementsWithValue(HValue* elements,
2761 : ElementsKind elements_kind,
2762 : HValue* from,
2763 : HValue* to,
2764 534 : HValue* value) {
2765 534 : 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 534 : if (from->IsInteger32Constant() && to->IsInteger32Constant()) {
2774 0 : int constant_from = from->GetInteger32Constant();
2775 0 : int constant_to = to->GetInteger32Constant();
2776 :
2777 0 : if (constant_from == 0 && constant_to <= kElementLoopUnrollThreshold) {
2778 : initial_capacity = constant_to;
2779 : }
2780 : }
2781 :
2782 534 : if (initial_capacity >= 0) {
2783 0 : for (int i = 0; i < initial_capacity; i++) {
2784 0 : HInstruction* key = Add<HConstant>(i);
2785 0 : 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 534 : LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement);
2793 :
2794 534 : HValue* key = builder.BeginBody(to, from, Token::GT);
2795 :
2796 534 : HValue* adjusted_key = AddUncasted<HSub>(key, graph()->GetConstant1());
2797 : adjusted_key->ClearFlag(HValue::kCanOverflow);
2798 :
2799 534 : Add<HStoreKeyed>(elements, adjusted_key, value, nullptr, elements_kind);
2800 :
2801 534 : builder.EndBody();
2802 : }
2803 534 : }
2804 :
2805 :
2806 534 : void HGraphBuilder::BuildFillElementsWithHole(HValue* elements,
2807 : ElementsKind elements_kind,
2808 : HValue* from,
2809 456 : 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 990 : : 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 534 : if (IsFastSmiOrObjectElementsKind(elements_kind)) {
2820 : elements_kind = FAST_HOLEY_ELEMENTS;
2821 : }
2822 :
2823 534 : BuildFillElementsWithValue(elements, elements_kind, from, to, hole);
2824 534 : }
2825 :
2826 :
2827 0 : void HGraphBuilder::BuildCopyProperties(HValue* from_properties,
2828 : HValue* to_properties, HValue* length,
2829 0 : HValue* capacity) {
2830 : ElementsKind kind = FAST_ELEMENTS;
2831 :
2832 : BuildFillElementsWithValue(to_properties, kind, length, capacity,
2833 0 : graph()->GetConstantUndefined());
2834 :
2835 0 : LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement);
2836 :
2837 0 : HValue* key = builder.BeginBody(length, graph()->GetConstant0(), Token::GT);
2838 :
2839 0 : key = AddUncasted<HSub>(key, graph()->GetConstant1());
2840 : key->ClearFlag(HValue::kCanOverflow);
2841 :
2842 : HValue* element =
2843 0 : Add<HLoadKeyed>(from_properties, key, nullptr, nullptr, kind);
2844 :
2845 0 : Add<HStoreKeyed>(to_properties, key, element, nullptr, kind);
2846 :
2847 0 : builder.EndBody();
2848 0 : }
2849 :
2850 :
2851 292 : void HGraphBuilder::BuildCopyElements(HValue* from_elements,
2852 : ElementsKind from_elements_kind,
2853 : HValue* to_elements,
2854 : ElementsKind to_elements_kind,
2855 : HValue* length,
2856 902 : HValue* capacity) {
2857 : int constant_capacity = -1;
2858 584 : if (capacity != NULL &&
2859 292 : capacity->IsConstant() &&
2860 0 : HConstant::cast(capacity)->HasInteger32Value()) {
2861 0 : int constant_candidate = HConstant::cast(capacity)->Integer32Value();
2862 0 : if (constant_candidate <= kElementLoopUnrollThreshold) {
2863 : constant_capacity = constant_candidate;
2864 : }
2865 : }
2866 :
2867 : bool pre_fill_with_holes =
2868 309 : IsFastDoubleElementsKind(from_elements_kind) &&
2869 : IsFastObjectElementsKind(to_elements_kind);
2870 292 : 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 17 : graph()->GetConstant0(), NULL);
2876 : }
2877 :
2878 292 : if (constant_capacity != -1) {
2879 : // Unroll the loop for small elements kinds.
2880 0 : for (int i = 0; i < constant_capacity; i++) {
2881 0 : HValue* key_constant = Add<HConstant>(i);
2882 : HInstruction* value = Add<HLoadKeyed>(
2883 0 : from_elements, key_constant, nullptr, nullptr, from_elements_kind);
2884 : Add<HStoreKeyed>(to_elements, key_constant, value, nullptr,
2885 0 : to_elements_kind);
2886 : }
2887 : } else {
2888 584 : if (!pre_fill_with_holes &&
2889 275 : (capacity == NULL || !length->Equals(capacity))) {
2890 : BuildFillElementsWithHole(to_elements, to_elements_kind,
2891 275 : length, NULL);
2892 : }
2893 :
2894 292 : LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement);
2895 :
2896 : HValue* key = builder.BeginBody(length, graph()->GetConstant0(),
2897 292 : Token::GT);
2898 :
2899 292 : key = AddUncasted<HSub>(key, graph()->GetConstant1());
2900 : key->ClearFlag(HValue::kCanOverflow);
2901 :
2902 : HValue* element = Add<HLoadKeyed>(from_elements, key, nullptr, nullptr,
2903 292 : from_elements_kind, ALLOW_RETURN_HOLE);
2904 :
2905 107 : ElementsKind kind = (IsHoleyElementsKind(from_elements_kind) &&
2906 : IsFastSmiElementsKind(to_elements_kind))
2907 523 : ? FAST_HOLEY_ELEMENTS : to_elements_kind;
2908 :
2909 292 : if (IsHoleyElementsKind(from_elements_kind) &&
2910 : from_elements_kind != to_elements_kind) {
2911 : IfBuilder if_hole(this);
2912 33 : if_hole.If<HCompareHoleAndBranch>(element);
2913 33 : if_hole.Then();
2914 : HConstant* hole_constant = IsFastDoubleElementsKind(to_elements_kind)
2915 : ? Add<HConstant>(HConstant::kHoleNaN)
2916 42 : : graph()->GetConstantHole();
2917 33 : Add<HStoreKeyed>(to_elements, key, hole_constant, nullptr, kind);
2918 : if_hole.Else();
2919 : HStoreKeyed* store =
2920 33 : Add<HStoreKeyed>(to_elements, key, element, nullptr, kind);
2921 : store->SetFlag(HValue::kTruncatingToNumber);
2922 33 : if_hole.End();
2923 : } else {
2924 : HStoreKeyed* store =
2925 259 : Add<HStoreKeyed>(to_elements, key, element, nullptr, kind);
2926 : store->SetFlag(HValue::kTruncatingToNumber);
2927 : }
2928 :
2929 292 : builder.EndBody();
2930 : }
2931 :
2932 292 : Counters* counters = isolate()->counters();
2933 292 : AddIncrementCounter(counters->inlined_copied_elements());
2934 292 : }
2935 :
2936 7136 : void HGraphBuilder::BuildCreateAllocationMemento(
2937 : HValue* previous_object,
2938 : HValue* previous_object_size,
2939 14272 : HValue* allocation_site) {
2940 : DCHECK(allocation_site != NULL);
2941 : HInnerAllocatedObject* allocation_memento = Add<HInnerAllocatedObject>(
2942 7136 : previous_object, previous_object_size, HType::HeapObject());
2943 : AddStoreMapConstant(
2944 7136 : allocation_memento, isolate()->factory()->allocation_memento_map());
2945 : Add<HStoreNamedField>(
2946 : allocation_memento,
2947 : HObjectAccess::ForAllocationMementoSite(),
2948 7136 : allocation_site);
2949 7136 : if (FLAG_allocation_site_pretenuring) {
2950 : HValue* memento_create_count =
2951 : Add<HLoadNamedField>(allocation_site, nullptr,
2952 : HObjectAccess::ForAllocationSiteOffset(
2953 7136 : AllocationSite::kPretenureCreateCountOffset));
2954 : memento_create_count = AddUncasted<HAdd>(
2955 7136 : 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 7136 : AllocationSite::kPretenureCreateCountOffset), memento_create_count);
2962 : }
2963 7136 : }
2964 :
2965 :
2966 11523 : HInstruction* HGraphBuilder::BuildGetNativeContext() {
2967 : return Add<HLoadNamedField>(
2968 11523 : context(), nullptr,
2969 23046 : HObjectAccess::ForContextSlot(Context::NATIVE_CONTEXT_INDEX));
2970 : }
2971 :
2972 :
2973 0 : HInstruction* HGraphBuilder::BuildGetNativeContext(HValue* closure) {
2974 : // Get the global object, then the native context
2975 : HInstruction* context = Add<HLoadNamedField>(
2976 0 : closure, nullptr, HObjectAccess::ForFunctionContextPointer());
2977 : return Add<HLoadNamedField>(
2978 : context, nullptr,
2979 0 : HObjectAccess::ForContextSlot(Context::NATIVE_CONTEXT_INDEX));
2980 : }
2981 :
2982 :
2983 0 : HValue* HGraphBuilder::BuildGetParentContext(HValue* depth, int depth_value) {
2984 0 : HValue* script_context = context();
2985 0 : if (depth != NULL) {
2986 : HValue* zero = graph()->GetConstant0();
2987 :
2988 0 : Push(script_context);
2989 0 : Push(depth);
2990 :
2991 : LoopBuilder loop(this);
2992 0 : 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 0 : HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
3000 0 : depth = AddUncasted<HSub>(depth, graph()->GetConstant1());
3001 : depth->ClearFlag(HValue::kCanOverflow);
3002 :
3003 : IfBuilder if_break(this);
3004 0 : if_break.If<HCompareNumericAndBranch, HValue*>(depth, zero, Token::EQ);
3005 0 : if_break.Then();
3006 : {
3007 0 : Push(script_context); // The result.
3008 0 : loop.Break();
3009 : }
3010 : if_break.Else();
3011 : {
3012 0 : Push(script_context);
3013 0 : Push(depth);
3014 : }
3015 0 : loop.EndBody();
3016 0 : if_break.End();
3017 :
3018 : script_context = Pop();
3019 0 : } else if (depth_value > 0) {
3020 : // Unroll the above loop.
3021 0 : for (int i = 0; i < depth_value; i++) {
3022 : script_context = Add<HLoadNamedField>(
3023 : script_context, nullptr,
3024 0 : HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
3025 : }
3026 : }
3027 0 : return script_context;
3028 : }
3029 :
3030 :
3031 0 : HInstruction* HGraphBuilder::BuildGetArrayFunction() {
3032 0 : HInstruction* native_context = BuildGetNativeContext();
3033 : HInstruction* index =
3034 0 : Add<HConstant>(static_cast<int32_t>(Context::ARRAY_FUNCTION_INDEX));
3035 : return Add<HLoadKeyed>(native_context, index, nullptr, nullptr,
3036 0 : FAST_ELEMENTS);
3037 : }
3038 :
3039 :
3040 143 : HValue* HGraphBuilder::BuildArrayBufferViewFieldAccessor(HValue* object,
3041 : HValue* checked_object,
3042 286 : FieldIndex index) {
3043 : NoObservableSideEffectsScope scope(this);
3044 : HObjectAccess access = HObjectAccess::ForObservableJSObjectOffset(
3045 143 : index.offset(), Representation::Tagged());
3046 : HInstruction* buffer = Add<HLoadNamedField>(
3047 143 : object, checked_object, HObjectAccess::ForJSArrayBufferViewBuffer());
3048 143 : HInstruction* field = Add<HLoadNamedField>(object, checked_object, access);
3049 :
3050 : HInstruction* flags = Add<HLoadNamedField>(
3051 143 : buffer, nullptr, HObjectAccess::ForJSArrayBufferBitField());
3052 : HValue* was_neutered_mask =
3053 143 : Add<HConstant>(1 << JSArrayBuffer::WasNeutered::kShift);
3054 : HValue* was_neutered_test =
3055 143 : AddUncasted<HBitwise>(Token::BIT_AND, flags, was_neutered_mask);
3056 :
3057 : IfBuilder if_was_neutered(this);
3058 : if_was_neutered.If<HCompareNumericAndBranch>(
3059 143 : was_neutered_test, graph()->GetConstant0(), Token::NE);
3060 143 : if_was_neutered.Then();
3061 143 : Push(graph()->GetConstant0());
3062 : if_was_neutered.Else();
3063 143 : Push(field);
3064 143 : if_was_neutered.End();
3065 :
3066 143 : return Pop();
3067 : }
3068 :
3069 0 : HValue* HGraphBuilder::AddLoadJSBuiltin(int context_index) {
3070 0 : HValue* native_context = BuildGetNativeContext();
3071 0 : HObjectAccess function_access = HObjectAccess::ForContextSlot(context_index);
3072 0 : return Add<HLoadNamedField>(native_context, nullptr, function_access);
3073 : }
3074 :
3075 1317163 : 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 790297 : 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 263433 : function_state_ = &initial_function_state_;
3091 : InitializeAstVisitor(info->isolate());
3092 263433 : }
3093 :
3094 :
3095 466297 : HBasicBlock* HOptimizedGraphBuilder::CreateJoin(HBasicBlock* first,
3096 : HBasicBlock* second,
3097 : BailoutId join_id) {
3098 466297 : if (first == NULL) {
3099 : return second;
3100 188603 : } else if (second == NULL) {
3101 : return first;
3102 : } else {
3103 187790 : 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 :
3111 45231 : HBasicBlock* HOptimizedGraphBuilder::JoinContinue(IterationStatement* statement,
3112 : BailoutId continue_id,
3113 : HBasicBlock* exit_block,
3114 : HBasicBlock* continue_block) {
3115 45231 : if (continue_block != NULL) {
3116 681 : 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 :
3124 45182 : HBasicBlock* HOptimizedGraphBuilder::CreateLoop(IterationStatement* statement,
3125 : HBasicBlock* loop_entry,
3126 : HBasicBlock* body_exit,
3127 : HBasicBlock* loop_successor,
3128 : HBasicBlock* break_block) {
3129 45182 : if (body_exit != NULL) Goto(body_exit, loop_entry);
3130 45182 : loop_entry->PostProcessLoopHeader(statement);
3131 45182 : if (break_block != NULL) {
3132 1879 : 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.
3141 45522 : HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry() {
3142 45522 : HBasicBlock* loop_entry = CreateLoopHeaderBlock();
3143 : Goto(loop_entry);
3144 : set_current_block(loop_entry);
3145 45522 : return loop_entry;
3146 : }
3147 :
3148 :
3149 45522 : HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry(
3150 50386 : IterationStatement* statement) {
3151 : HBasicBlock* loop_entry;
3152 :
3153 45522 : if (osr()->HasOsrEntryAt(statement)) {
3154 2432 : loop_entry = osr()->BuildOsrLoopEntry(statement);
3155 2432 : if (function_state()->IsInsideDoExpressionScope()) {
3156 : Bailout(kDoExpressionUnmodelable);
3157 : }
3158 : } else {
3159 43090 : loop_entry = BuildLoopEntry();
3160 : }
3161 45522 : return loop_entry;
3162 : }
3163 :
3164 :
3165 0 : void HBasicBlock::FinishExit(HControlInstruction* instruction,
3166 : SourcePosition position) {
3167 356825 : Finish(instruction, position);
3168 : ClearEnvironment();
3169 0 : }
3170 :
3171 :
3172 0 : std::ostream& operator<<(std::ostream& os, const HBasicBlock& b) {
3173 0 : return os << "B" << b.block_id();
3174 : }
3175 :
3176 1434577 : 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 1434577 : disallow_adding_new_values_(false) {
3196 286916 : if (info->IsStub()) {
3197 : // For stubs, explicitly add the context to the environment.
3198 : start_environment_ =
3199 46966 : new (zone_) HEnvironment(zone_, descriptor.GetParameterCount() + 1);
3200 : } else {
3201 : start_environment_ =
3202 526866 : new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_);
3203 : }
3204 286916 : start_environment_->set_ast_id(BailoutId::FunctionContext());
3205 286916 : entry_block_ = CreateBasicBlock();
3206 286916 : entry_block_->SetInitialEnvironment(start_environment_);
3207 286916 : }
3208 :
3209 :
3210 9208576 : HBasicBlock* HGraph::CreateBasicBlock() {
3211 4604288 : HBasicBlock* result = new(zone()) HBasicBlock(this);
3212 : blocks_.Add(result, zone());
3213 4604290 : return result;
3214 : }
3215 :
3216 :
3217 283265 : void HGraph::FinalizeUniqueness() {
3218 : DisallowHeapAllocation no_gc;
3219 4787240 : for (int i = 0; i < blocks()->length(); ++i) {
3220 38569944 : for (HInstructionIterator it(blocks()->at(i)); !it.Done(); it.Advance()) {
3221 29561994 : it.Current()->FinalizeUniqueness();
3222 : }
3223 : }
3224 283265 : }
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).
3275 : PostorderProcessor* parent() {return father_; }
3276 : // Forward link (towards the stack top).
3277 : PostorderProcessor* child() {return child_; }
3278 : HBasicBlock* block() { return block_; }
3279 : HLoopInformation* loop() { return loop_; }
3280 : HBasicBlock* loop_header() { return loop_header_; }
3281 :
3282 283242 : static PostorderProcessor* CreateEntryProcessor(Zone* zone,
3283 : HBasicBlock* block) {
3284 : PostorderProcessor* result = new(zone) PostorderProcessor(NULL);
3285 283242 : return result->SetupSuccessors(zone, block, NULL);
3286 : }
3287 :
3288 7763339 : PostorderProcessor* PerformStep(Zone* zone,
3289 : ZoneList<HBasicBlock*>* order) {
3290 : PostorderProcessor* next =
3291 7763339 : PerformNonBacktrackingStep(zone, order);
3292 7763356 : if (next != NULL) {
3293 : return next;
3294 : } else {
3295 2600646 : return Backtrack(zone, order);
3296 : }
3297 : }
3298 :
3299 : private:
3300 : explicit PostorderProcessor(PostorderProcessor* father)
3301 1946757 : : 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.
3313 6724219 : PostorderProcessor* SetupSuccessors(Zone* zone,
3314 5747630 : HBasicBlock* block,
3315 : HBasicBlock* loop_header) {
3316 19136151 : if (block == NULL || block->IsOrdered() ||
3317 : block->parent_loop_header() != loop_header) {
3318 2220436 : kind_ = NONE;
3319 2220436 : block_ = NULL;
3320 2220436 : loop_ = NULL;
3321 2220436 : loop_header_ = NULL;
3322 2220436 : return this;
3323 : } else {
3324 4503783 : block_ = block;
3325 4503783 : loop_ = NULL;
3326 : block->MarkAsOrdered();
3327 :
3328 4503783 : if (block->IsLoopHeader()) {
3329 59877 : kind_ = SUCCESSORS_OF_LOOP_HEADER;
3330 59877 : loop_header_ = block;
3331 : InitializeSuccessors();
3332 59877 : PostorderProcessor* result = Push(zone);
3333 : return result->SetupLoopMembers(zone, block, block->loop_information(),
3334 59877 : loop_header);
3335 : } else {
3336 : DCHECK(block->IsFinished());
3337 4443906 : kind_ = SUCCESSORS;
3338 4443906 : loop_header_ = loop_header;
3339 : InitializeSuccessors();
3340 4443906 : return this;
3341 : }
3342 : }
3343 : }
3344 :
3345 : PostorderProcessor* SetupLoopMembers(Zone* zone,
3346 : HBasicBlock* block,
3347 : HLoopInformation* loop,
3348 : HBasicBlock* loop_header) {
3349 69015 : kind_ = LOOP_MEMBERS;
3350 59877 : block_ = block;
3351 69015 : loop_ = loop;
3352 59877 : loop_header_ = loop_header;
3353 : InitializeLoopMembers();
3354 : return this;
3355 : }
3356 :
3357 : PostorderProcessor* SetupSuccessorsOfLoopMember(
3358 : HBasicBlock* block,
3359 : HLoopInformation* loop,
3360 : HBasicBlock* loop_header) {
3361 1039153 : kind_ = SUCCESSORS_OF_LOOP_MEMBER;
3362 1039153 : block_ = block;
3363 1039153 : loop_ = loop;
3364 1039153 : loop_header_ = loop_header;
3365 : InitializeSuccessors();
3366 : return this;
3367 : }
3368 :
3369 : // This method "allocates" a new stack frame.
3370 7539963 : PostorderProcessor* Push(Zone* zone) {
3371 7539963 : if (child_ == NULL) {
3372 1663515 : child_ = new(zone) PostorderProcessor(this);
3373 : }
3374 7539960 : return child_;
3375 : }
3376 :
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 4503799 : order->Add(block_, zone);
3385 : }
3386 :
3387 : // This method is the basic block to walk up the stack.
3388 7832405 : PostorderProcessor* Pop(Zone* zone,
3389 1039153 : ZoneList<HBasicBlock*>* order) {
3390 7832405 : switch (kind_) {
3391 : case SUCCESSORS:
3392 : case SUCCESSORS_OF_LOOP_HEADER:
3393 : ClosePostorder(order, zone);
3394 4503799 : return father_;
3395 : case LOOP_MEMBERS:
3396 69015 : return father_;
3397 : case SUCCESSORS_OF_LOOP_MEMBER:
3398 1039153 : 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 9138 : block()->loop_information(), loop_header_);
3403 : } else {
3404 1030015 : return father_;
3405 : }
3406 : case NONE:
3407 2220438 : return father_;
3408 : }
3409 0 : UNREACHABLE();
3410 : return NULL;
3411 : }
3412 :
3413 : // Walks up the stack.
3414 2600645 : PostorderProcessor* Backtrack(Zone* zone,
3415 : ZoneList<HBasicBlock*>* order) {
3416 2600645 : PostorderProcessor* parent = Pop(zone, order);
3417 10433035 : while (parent != NULL) {
3418 : PostorderProcessor* next =
3419 7549147 : parent->PerformNonBacktrackingStep(zone, order);
3420 7549140 : if (next != NULL) {
3421 : return next;
3422 : } else {
3423 5231755 : parent = parent->Pop(zone, order);
3424 : }
3425 : }
3426 : return NULL;
3427 : }
3428 :
3429 15312404 : PostorderProcessor* PerformNonBacktrackingStep(
3430 : Zone* zone,
3431 111600 : ZoneList<HBasicBlock*>* order) {
3432 : HBasicBlock* next_block;
3433 15312404 : switch (kind_) {
3434 : case SUCCESSORS:
3435 9434403 : next_block = AdvanceSuccessors();
3436 9434387 : if (next_block != NULL) {
3437 4990534 : PostorderProcessor* result = Push(zone);
3438 4990529 : return result->SetupSuccessors(zone, next_block, loop_header_);
3439 : }
3440 : break;
3441 : case SUCCESSORS_OF_LOOP_HEADER:
3442 171477 : next_block = AdvanceSuccessors();
3443 171477 : if (next_block != NULL) {
3444 111600 : PostorderProcessor* result = Push(zone);
3445 111600 : return result->SetupSuccessors(zone, next_block, block());
3446 : }
3447 : break;
3448 : case LOOP_MEMBERS:
3449 : next_block = AdvanceLoopMembers();
3450 1108168 : if (next_block != NULL) {
3451 1039153 : PostorderProcessor* result = Push(zone);
3452 : return result->SetupSuccessorsOfLoopMember(next_block,
3453 2078306 : loop_, loop_header_);
3454 : }
3455 : break;
3456 : case SUCCESSORS_OF_LOOP_MEMBER:
3457 2377987 : next_block = AdvanceSuccessors();
3458 2377985 : if (next_block != NULL) {
3459 1338832 : PostorderProcessor* result = Push(zone);
3460 1338832 : 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.
3470 : void InitializeSuccessors() {
3471 5542936 : loop_index = 0;
3472 5542936 : loop_length = 0;
3473 5542936 : successor_iterator = HSuccessorIterator(block_->end());
3474 : }
3475 :
3476 11983837 : HBasicBlock* AdvanceSuccessors() {
3477 23967662 : if (!successor_iterator.Done()) {
3478 : HBasicBlock* result = successor_iterator.Current();
3479 : successor_iterator.Advance();
3480 6440949 : return result;
3481 : }
3482 : return NULL;
3483 : }
3484 :
3485 : // The following two methods implement a "foreach b in loop members" cycle.
3486 : void InitializeLoopMembers() {
3487 69015 : loop_index = 0;
3488 69015 : loop_length = loop_->blocks()->length();
3489 : }
3490 :
3491 : HBasicBlock* AdvanceLoopMembers() {
3492 1108168 : if (loop_index < loop_length) {
3493 2078306 : HBasicBlock* result = loop_->blocks()->at(loop_index);
3494 1039153 : 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 :
3513 8329825 : void HGraph::OrderBlocks() {
3514 283243 : 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 7936708 : PostorderProcessor::CreateEntryProcessor(zone(), blocks_[0]);
3525 : blocks_.Rewind(0);
3526 8046583 : while (postorder) {
3527 15526680 : 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 2645570 : for (int i = 0, j = blocks_.length(); --j >= i; ++i) {
3539 2362327 : HBasicBlock* bi = blocks_[i];
3540 2362327 : HBasicBlock* bj = blocks_[j];
3541 : bi->set_block_id(j);
3542 : bj->set_block_id(i);
3543 2362327 : blocks_[i] = bj;
3544 2362327 : blocks_[j] = bi;
3545 283243 : }
3546 283243 : }
3547 :
3548 :
3549 283242 : void HGraph::AssignDominators() {
3550 : HPhase phase("H_Assign dominators", this);
3551 9574098 : for (int i = 0; i < blocks_.length(); ++i) {
3552 18777075 : HBasicBlock* block = blocks_[i];
3553 4503806 : 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 59876 : block->AssignCommonDominator(block->predecessors()->first());
3557 59877 : block->AssignLoopSuccessorDominators();
3558 : } else {
3559 9426338 : for (int j = blocks_[i]->predecessors()->length() - 1; j >= 0; --j) {
3560 9964828 : blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j));
3561 : }
3562 : }
3563 283243 : }
3564 283242 : }
3565 :
3566 :
3567 283200 : bool HGraph::CheckArgumentsPhiUses() {
3568 5076532 : int block_count = blocks_.length();
3569 4776810 : for (int i = 0; i < block_count; ++i) {
3570 5093051 : for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
3571 299722 : HPhi* phi = blocks_[i]->phis()->at(j);
3572 : // We don't support phi uses of arguments for now.
3573 599444 : if (phi->CheckFlag(HValue::kIsArguments)) return false;
3574 : }
3575 : }
3576 : return true;
3577 : }
3578 :
3579 :
3580 283242 : bool HGraph::CheckConstPhiUses() {
3581 5441366 : int block_count = blocks_.length();
3582 4778746 : for (int i = 0; i < block_count; ++i) {
3583 5820703 : for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
3584 662620 : HPhi* phi = blocks_[i]->phis()->at(j);
3585 : // Check for the hole value (from an uninitialized const).
3586 3995610 : for (int k = 0; k < phi->OperandCount(); k++) {
3587 1335226 : if (phi->OperandAt(k) == GetConstantHole()) return false;
3588 : }
3589 : }
3590 : }
3591 : return true;
3592 : }
3593 :
3594 :
3595 882024 : void HGraph::CollectPhis() {
3596 5092415 : int block_count = blocks_.length();
3597 283197 : phi_list_ = new(zone()) ZoneList<HPhi*>(block_count, zone());
3598 4776785 : for (int i = 0; i < block_count; ++i) {
3599 5124848 : for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
3600 315630 : HPhi* phi = blocks_[i]->phis()->at(j);
3601 315630 : phi_list_->Add(phi, zone());
3602 : }
3603 : }
3604 283197 : }
3605 :
3606 :
3607 : // Implementation of utility class to encapsulate the translation state for
3608 : // a (possibly inlined) function.
3609 976003 : 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 741736 : outer_(owner->function_state()) {
3626 370868 : if (outer_ != NULL) {
3627 : // State for an inline function.
3628 107436 : if (owner->ast_context()->IsTest()) {
3629 585740 : HBasicBlock* if_true = owner->graph()->CreateBasicBlock();
3630 19395 : HBasicBlock* if_false = owner->graph()->CreateBasicBlock();
3631 : if_true->MarkAsInlineReturnTarget(owner->current_block());
3632 : if_false->MarkAsInlineReturnTarget(owner->current_block());
3633 19395 : 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 38790 : test_context_ = new TestContext(owner, cond, if_true, if_false);
3638 : } else {
3639 88041 : function_return_ = owner->graph()->CreateBasicBlock();
3640 : function_return()->MarkAsInlineReturnTarget(owner->current_block());
3641 : }
3642 : // Set this after possibly allocating a new TestContext above.
3643 107436 : call_context_ = owner->ast_context();
3644 : }
3645 :
3646 : // Push on the state stack.
3647 : owner->set_function_state(this);
3648 :
3649 370868 : if (owner->is_tracking_positions()) {
3650 122 : outer_source_position_ = owner->source_position();
3651 : owner->EnterInlinedSource(inlining_id);
3652 244 : owner->SetSourcePosition(info->shared_info()->start_position());
3653 : }
3654 370868 : }
3655 :
3656 :
3657 107436 : FunctionState::~FunctionState() {
3658 107436 : delete test_context_;
3659 107439 : owner_->set_function_state(outer_);
3660 :
3661 107436 : if (owner_->is_tracking_positions()) {
3662 : owner_->set_source_position(outer_source_position_);
3663 3 : owner_->EnterInlinedSource(outer_->inlining_id());
3664 : }
3665 107436 : }
3666 :
3667 :
3668 : // Implementation of utility classes to represent an expression's context in
3669 : // the AST.
3670 7313663 : AstContext::AstContext(HOptimizedGraphBuilder* owner, Expression::Context kind)
3671 : : owner_(owner),
3672 : kind_(kind),
3673 : outer_(owner->ast_context()),
3674 14627326 : 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 0 : }
3681 :
3682 :
3683 7313660 : AstContext::~AstContext() {
3684 7313660 : owner_->set_ast_context(outer_); // Pop.
3685 0 : }
3686 :
3687 :
3688 923364 : 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 0 : }
3694 :
3695 :
3696 5359098 : 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 0 : }
3702 :
3703 :
3704 656862 : void EffectContext::ReturnValue(HValue* value) {
3705 : // The value is simply ignored.
3706 656862 : }
3707 :
3708 :
3709 2629657 : 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 2629657 : if (value->CheckFlag(HValue::kIsArguments)) {
3713 1802 : if (flag_ == ARGUMENTS_FAKED) {
3714 2629928 : value = owner()->graph()->GetConstantUndefined();
3715 1774 : } else if (!arguments_allowed()) {
3716 : owner()->Bailout(kBadValueContextForArgumentsValue);
3717 : }
3718 : }
3719 2629657 : owner()->Push(value);
3720 2629658 : }
3721 :
3722 :
3723 22610 : void TestContext::ReturnValue(HValue* value) {
3724 22772 : BuildBranch(value);
3725 22610 : }
3726 :
3727 :
3728 193692 : void EffectContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
3729 : DCHECK(!instr->IsControlInstruction());
3730 336769 : owner()->AddInstruction(instr);
3731 193692 : if (instr->HasObservableSideEffects()) {
3732 143077 : owner()->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
3733 : }
3734 193692 : }
3735 :
3736 :
3737 108 : void EffectContext::ReturnControl(HControlInstruction* instr,
3738 : BailoutId ast_id) {
3739 : DCHECK(!instr->HasObservableSideEffects());
3740 432 : HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock();
3741 108 : HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock();
3742 108 : instr->SetSuccessorAt(0, empty_true);
3743 108 : instr->SetSuccessorAt(1, empty_false);
3744 108 : owner()->FinishCurrentBlock(instr);
3745 108 : HBasicBlock* join = owner()->CreateJoin(empty_true, empty_false, ast_id);
3746 : owner()->set_current_block(join);
3747 108 : }
3748 :
3749 :
3750 0 : 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 0 : if (!continuation->IsTrueReachable()) {
3756 0 : owner()->set_current_block(false_branch);
3757 0 : } else if (!continuation->IsFalseReachable()) {
3758 : owner()->set_current_block(true_branch);
3759 : } else {
3760 0 : HBasicBlock* join = owner()->CreateJoin(true_branch, false_branch, ast_id);
3761 : owner()->set_current_block(join);
3762 : }
3763 0 : }
3764 :
3765 :
3766 2698665 : void ValueContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
3767 : DCHECK(!instr->IsControlInstruction());
3768 5048166 : if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) {
3769 8868226 : return owner()->Bailout(kBadValueContextForArgumentsObjectValue);
3770 : }
3771 2698665 : owner()->AddInstruction(instr);
3772 2698665 : owner()->Push(instr);
3773 2698665 : if (instr->HasObservableSideEffects()) {
3774 772231 : owner()->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
3775 : }
3776 : }
3777 :
3778 :
3779 16748 : void ValueContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) {
3780 : DCHECK(!instr->HasObservableSideEffects());
3781 32297 : if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) {
3782 200976 : return owner()->Bailout(kBadValueContextForArgumentsObjectValue);
3783 : }
3784 16748 : HBasicBlock* materialize_false = owner()->graph()->CreateBasicBlock();
3785 16748 : HBasicBlock* materialize_true = owner()->graph()->CreateBasicBlock();
3786 16748 : instr->SetSuccessorAt(0, materialize_true);
3787 16748 : instr->SetSuccessorAt(1, materialize_false);
3788 16748 : owner()->FinishCurrentBlock(instr);
3789 : owner()->set_current_block(materialize_true);
3790 33496 : owner()->Push(owner()->graph()->GetConstantTrue());
3791 : owner()->set_current_block(materialize_false);
3792 33496 : owner()->Push(owner()->graph()->GetConstantFalse());
3793 : HBasicBlock* join =
3794 16748 : owner()->CreateJoin(materialize_true, materialize_false, ast_id);
3795 : owner()->set_current_block(join);
3796 : }
3797 :
3798 :
3799 0 : 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 0 : if (continuation->IsTrueReachable()) {
3805 0 : owner()->set_current_block(materialize_true);
3806 0 : owner()->Push(owner()->graph()->GetConstantTrue());
3807 : owner()->set_current_block(materialize_true);
3808 : }
3809 0 : if (continuation->IsFalseReachable()) {
3810 : owner()->set_current_block(materialize_false);
3811 0 : owner()->Push(owner()->graph()->GetConstantFalse());
3812 : owner()->set_current_block(materialize_false);
3813 : }
3814 0 : if (continuation->TrueAndFalseReachable()) {
3815 : HBasicBlock* join =
3816 0 : owner()->CreateJoin(materialize_true, materialize_false, ast_id);
3817 : owner()->set_current_block(join);
3818 : }
3819 0 : }
3820 :
3821 :
3822 273278 : void TestContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
3823 : DCHECK(!instr->IsControlInstruction());
3824 273278 : HOptimizedGraphBuilder* builder = owner();
3825 273278 : 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 273278 : if (instr->HasObservableSideEffects()) {
3829 107802 : builder->Push(instr);
3830 107802 : builder->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
3831 : builder->Pop();
3832 : }
3833 273278 : BuildBranch(instr);
3834 273278 : }
3835 :
3836 :
3837 2350521 : void TestContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) {
3838 : DCHECK(!instr->HasObservableSideEffects());
3839 3917535 : HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock();
3840 783507 : HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock();
3841 783507 : instr->SetSuccessorAt(0, empty_true);
3842 783507 : instr->SetSuccessorAt(1, empty_false);
3843 783507 : owner()->FinishCurrentBlock(instr);
3844 783507 : owner()->Goto(empty_true, if_true(), owner()->function_state());
3845 783507 : owner()->Goto(empty_false, if_false(), owner()->function_state());
3846 : owner()->set_current_block(NULL);
3847 783507 : }
3848 :
3849 :
3850 1706 : void TestContext::ReturnContinuation(HIfContinuation* continuation,
3851 1706 : BailoutId ast_id) {
3852 : HBasicBlock* true_branch = NULL;
3853 : HBasicBlock* false_branch = NULL;
3854 : continuation->Continue(&true_branch, &false_branch);
3855 853 : if (continuation->IsTrueReachable()) {
3856 2559 : owner()->Goto(true_branch, if_true(), owner()->function_state());
3857 : }
3858 853 : if (continuation->IsFalseReachable()) {
3859 853 : owner()->Goto(false_branch, if_false(), owner()->function_state());
3860 : }
3861 : owner()->set_current_block(NULL);
3862 853 : }
3863 :
3864 :
3865 888150 : 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 296050 : HOptimizedGraphBuilder* builder = owner();
3871 592100 : if (value != NULL && value->CheckFlag(HValue::kIsArguments)) {
3872 : builder->Bailout(kArgumentsObjectValueInATestContext);
3873 : }
3874 296050 : ToBooleanHints expected(condition()->to_boolean_types());
3875 296050 : ReturnControl(owner()->New<HBranch>(value, expected), BailoutId::None());
3876 296050 : }
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 :
3901 0 : void HOptimizedGraphBuilder::Bailout(BailoutReason reason) {
3902 : current_info()->AbortOptimization(reason);
3903 : SetStackOverflow();
3904 0 : }
3905 :
3906 :
3907 922453 : void HOptimizedGraphBuilder::VisitForEffect(Expression* expr) {
3908 : EffectContext for_effect(this);
3909 922453 : Visit(expr);
3910 922453 : }
3911 :
3912 :
3913 5044787 : void HOptimizedGraphBuilder::VisitForValue(Expression* expr,
3914 : ArgumentsAllowedFlag flag) {
3915 : ValueContext for_value(this, flag);
3916 5044787 : Visit(expr);
3917 5044784 : }
3918 :
3919 :
3920 106415 : void HOptimizedGraphBuilder::VisitForTypeOf(Expression* expr) {
3921 : ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED);
3922 : for_value.set_typeof_mode(INSIDE_TYPEOF);
3923 106415 : Visit(expr);
3924 106415 : }
3925 :
3926 :
3927 1011803 : void HOptimizedGraphBuilder::VisitForControl(Expression* expr,
3928 : HBasicBlock* true_block,
3929 : HBasicBlock* false_block) {
3930 : TestContext for_control(this, expr, true_block, false_block);
3931 1011803 : Visit(expr);
3932 1011803 : }
3933 :
3934 :
3935 621214 : void HOptimizedGraphBuilder::VisitExpressions(
3936 993658 : ZoneList<Expression*>* exprs) {
3937 3229494 : for (int i = 0; i < exprs->length(); ++i) {
3938 4223277 : CHECK_ALIVE(VisitForValue(exprs->at(i)));
3939 : }
3940 : }
3941 :
3942 :
3943 114573 : void HOptimizedGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs,
3944 105859 : ArgumentsAllowedFlag flag) {
3945 440830 : for (int i = 0; i < exprs->length(); ++i) {
3946 546706 : CHECK_ALIVE(VisitForValue(exprs->at(i), flag));
3947 : }
3948 : }
3949 :
3950 :
3951 786648 : bool HOptimizedGraphBuilder::BuildGraph() {
3952 526865 : if (IsDerivedConstructor(current_info()->literal()->kind())) {
3953 : Bailout(kSuperReference);
3954 0 : return false;
3955 : }
3956 :
3957 263432 : DeclarationScope* scope = current_info()->scope();
3958 263432 : 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 1086859 : HEnvironment* initial_env = environment()->CopyWithoutHistory();
3976 263433 : HBasicBlock* body_entry = CreateBasicBlock(initial_env);
3977 : Goto(body_entry);
3978 : body_entry->SetJoinId(BailoutId::FunctionEntry());
3979 : set_current_block(body_entry);
3980 :
3981 263433 : VisitDeclarations(scope->declarations());
3982 : Add<HSimulate>(BailoutId::Declarations());
3983 :
3984 263433 : Add<HStackCheck>(HStackCheck::kFunctionEntry);
3985 :
3986 263433 : VisitStatements(current_info()->literal()->body());
3987 263433 : if (HasStackOverflow()) return false;
3988 :
3989 259782 : if (current_block() != NULL) {
3990 44081 : 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 519564 : 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 259782 : !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 519564 : current_info()->IsStub() ||
4011 779346 : current_info()->shared_info()->deopt_count() + 1 < FLAG_max_deopt_count);
4012 :
4013 : // Perform any necessary OSR-specific cleanups or changes to the graph.
4014 259782 : osr()->FinishGraph();
4015 :
4016 259782 : return true;
4017 : }
4018 :
4019 :
4020 845946 : bool HGraph::Optimize(BailoutReason* bailout_reason) {
4021 283243 : OrderBlocks();
4022 283243 : 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 562749 : if (FLAG_analyze_environment_liveness && maximum_environment_size() != 0) {
4036 279506 : Run<HEnvironmentLivenessAnalysisPhase>();
4037 : }
4038 :
4039 283243 : if (!CheckConstPhiUses()) {
4040 43 : *bailout_reason = kUnsupportedPhiUseOfConstVariable;
4041 43 : return false;
4042 : }
4043 283199 : Run<HRedundantPhiEliminationPhase>();
4044 283200 : if (!CheckArgumentsPhiUses()) {
4045 3 : *bailout_reason = kUnsupportedPhiUseOfArguments;
4046 3 : return false;
4047 : }
4048 :
4049 : // Find and mark unreachable code to simplify optimizations, especially gvn,
4050 : // where unreachable code could unnecessarily defeat LICM.
4051 283197 : Run<HMarkUnreachableBlocksPhase>();
4052 :
4053 283197 : if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>();
4054 283196 : if (FLAG_use_escape_analysis) Run<HEscapeAnalysisPhase>();
4055 :
4056 283197 : if (FLAG_load_elimination) Run<HLoadEliminationPhase>();
4057 :
4058 283197 : CollectPhis();
4059 :
4060 283197 : if (has_osr()) osr()->FinishOsrValues();
4061 :
4062 283197 : 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 283197 : Run<HMergeRemovableSimulatesPhase>();
4068 :
4069 283196 : Run<HRepresentationChangesPhase>();
4070 :
4071 283197 : 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 283197 : Run<HUint32AnalysisPhase>();
4077 :
4078 283197 : if (FLAG_use_canonicalizing) Run<HCanonicalizePhase>();
4079 :
4080 283197 : if (FLAG_use_gvn) Run<HGlobalValueNumberingPhase>();
4081 :
4082 283197 : if (FLAG_check_elimination) Run<HCheckEliminationPhase>();
4083 :
4084 283197 : if (FLAG_store_elimination) Run<HStoreEliminationPhase>();
4085 :
4086 283197 : Run<HRangeAnalysisPhase>();
4087 :
4088 : // Eliminate redundant stack checks on backwards branches.
4089 283197 : Run<HStackCheckEliminationPhase>();
4090 :
4091 283197 : if (FLAG_array_bounds_checks_elimination) Run<HBoundsCheckEliminationPhase>();
4092 283196 : if (FLAG_array_index_dehoisting) Run<HDehoistIndexComputationsPhase>();
4093 283195 : if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>();
4094 :
4095 283195 : RestoreActualValues();
4096 :
4097 : // Find unreachable code a second time, GVN and other optimizations may have
4098 : // made blocks unreachable that were previously reachable.
4099 283197 : Run<HMarkUnreachableBlocksPhase>();
4100 :
4101 283197 : return true;
4102 : }
4103 :
4104 :
4105 283192 : void HGraph::RestoreActualValues() {
4106 : HPhase phase("H_Restore actual values", this);
4107 :
4108 4776647 : for (int block_index = 0; block_index < blocks()->length(); block_index++) {
4109 4493450 : 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 29624382 : for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
4119 : HInstruction* instruction = it.Current();
4120 25130936 : if (instruction->ActualValue() == instruction) continue;
4121 317881 : 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 6573 : instruction->DeleteAndReplaceWith(instruction->ActualValue());
4126 : } else {
4127 : DCHECK(instruction->IsInformativeDefinition());
4128 311308 : if (instruction->IsPurelyInformativeDefinition()) {
4129 0 : instruction->DeleteAndReplaceWith(instruction->RedefinedOperand());
4130 : } else {
4131 311312 : instruction->ReplaceAllUsesWith(instruction->ActualValue());
4132 : }
4133 : }
4134 : }
4135 283197 : }
4136 283197 : }
4137 :
4138 :
4139 595778 : void HOptimizedGraphBuilder::PushArgumentsFromEnvironment(int count) {
4140 2598183 : ZoneList<HValue*> arguments(count, zone());
4141 2002405 : for (int i = 0; i < count; ++i) {
4142 : arguments.Add(Pop(), zone());
4143 : }
4144 :
4145 595778 : HPushArguments* push_args = New<HPushArguments>();
4146 2598182 : while (!arguments.is_empty()) {
4147 1406627 : push_args->AddInput(arguments.RemoveLast());
4148 : }
4149 595777 : AddInstruction(push_args);
4150 595777 : }
4151 :
4152 :
4153 : template <class Instruction>
4154 373 : HInstruction* HOptimizedGraphBuilder::PreProcessCall(Instruction* call) {
4155 373 : PushArgumentsFromEnvironment(call->argument_count());
4156 373 : return call;
4157 : }
4158 :
4159 790299 : void HOptimizedGraphBuilder::SetUpScope(DeclarationScope* scope) {
4160 1380272 : HEnvironment* prolog_env = environment();
4161 263433 : int parameter_count = environment()->parameter_count();
4162 263433 : ZoneList<HValue*> parameters(parameter_count, zone());
4163 690138 : for (int i = 0; i < parameter_count; ++i) {
4164 426705 : HInstruction* parameter = Add<HParameter>(static_cast<unsigned>(i));
4165 : parameters.Add(parameter, zone());
4166 : environment()->Bind(i, parameter);
4167 : }
4168 :
4169 263433 : HConstant* undefined_constant = graph()->GetConstantUndefined();
4170 : // Initialize specials and locals to undefined.
4171 1199638 : for (int i = parameter_count + 1; i < environment()->length(); ++i) {
4172 : environment()->Bind(i, undefined_constant);
4173 : }
4174 263433 : Add<HPrologue>();
4175 :
4176 263433 : HEnvironment* initial_env = environment()->CopyWithoutHistory();
4177 263433 : 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 263431 : prolog_env->BindContext(undefined_constant);
4183 :
4184 : // First special is HContext.
4185 263432 : HInstruction* context = Add<HContext>();
4186 263432 : 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 263432 : HArgumentsObject* arguments_object = New<HArgumentsObject>(parameter_count);
4192 690134 : for (int i = 0; i < parameter_count; ++i) {
4193 426701 : HValue* parameter = parameters.at(i);
4194 426701 : arguments_object->AddArgument(parameter, zone());
4195 : }
4196 :
4197 263433 : AddInstruction(arguments_object);
4198 :
4199 : // Handle the arguments and arguments shadow variables specially (they do
4200 : // not have declarations).
4201 263433 : if (scope->arguments() != NULL) {
4202 854 : environment()->Bind(scope->arguments(), arguments_object);
4203 : }
4204 :
4205 263433 : if (scope->rest_parameter() != nullptr) {
4206 : return Bailout(kRestParameter);
4207 : }
4208 :
4209 526866 : if (scope->this_function_var() != nullptr ||
4210 : scope->new_target_var() != nullptr) {
4211 : return Bailout(kSuperReference);
4212 : }
4213 :
4214 : // Trace the call.
4215 263433 : if (FLAG_trace && top_info()->IsOptimizing()) {
4216 0 : Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kTraceEnter), 0);
4217 : }
4218 : }
4219 :
4220 :
4221 3144400 : void HOptimizedGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) {
4222 5496208 : for (int i = 0; i < statements->length(); i++) {
4223 4807138 : Statement* stmt = statements->at(i);
4224 5203434 : CHECK_ALIVE(Visit(stmt));
4225 1665872 : if (stmt->IsJump()) break;
4226 : }
4227 : }
4228 :
4229 :
4230 2056845 : void HOptimizedGraphBuilder::VisitBlock(Block* stmt) {
4231 : DCHECK(!HasStackOverflow());
4232 : DCHECK(current_block() != NULL);
4233 : DCHECK(current_block()->HasPredecessor());
4234 :
4235 694460 : Scope* outer_scope = scope();
4236 : Scope* scope = stmt->scope();
4237 : BreakAndContinueInfo break_info(stmt, outer_scope);
4238 :
4239 : { BreakAndContinueScope push(&break_info, this);
4240 685615 : if (scope != NULL) {
4241 8478 : if (scope->NeedsContext()) {
4242 : // Load the function object.
4243 892 : DeclarationScope* declaration_scope = scope->GetDeclarationScope();
4244 : HInstruction* function;
4245 : HValue* outer_context = environment()->context();
4246 892 : if (declaration_scope->is_script_scope() ||
4247 : declaration_scope->is_eval_scope()) {
4248 : function = new (zone())
4249 : HLoadContextSlot(outer_context, Context::CLOSURE_INDEX,
4250 727 : HLoadContextSlot::kNoCheck);
4251 : } else {
4252 165 : function = New<HThisFunction>();
4253 : }
4254 892 : AddInstruction(function);
4255 : // Allocate a block context and store it to the stack frame.
4256 892 : HValue* scope_info = Add<HConstant>(scope->scope_info());
4257 892 : Add<HPushArguments>(scope_info, function);
4258 : HInstruction* inner_context = Add<HCallRuntime>(
4259 892 : Runtime::FunctionForId(Runtime::kPushBlockContext), 2);
4260 : inner_context->SetFlag(HValue::kHasNoObservableSideEffects);
4261 : set_scope(scope);
4262 892 : environment()->BindContext(inner_context);
4263 : }
4264 8478 : VisitDeclarations(scope->declarations());
4265 : AddSimulate(stmt->DeclsId(), REMOVABLE_SIMULATE);
4266 : }
4267 2056845 : CHECK_BAILOUT(VisitStatements(stmt->statements()));
4268 : }
4269 : set_scope(outer_scope);
4270 698955 : if (scope != NULL && current_block() != NULL &&
4271 7252 : scope->ContextLocalCount() > 0) {
4272 : HValue* inner_context = environment()->context();
4273 : HValue* outer_context = Add<HLoadNamedField>(
4274 : inner_context, nullptr,
4275 869 : HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
4276 :
4277 869 : environment()->BindContext(outer_context);
4278 : }
4279 683654 : HBasicBlock* break_block = break_info.break_block();
4280 683654 : if (break_block != NULL) {
4281 69 : if (current_block() != NULL) Goto(break_block);
4282 : break_block->SetJoinId(stmt->ExitId());
4283 : set_current_block(break_block);
4284 : }
4285 : }
4286 :
4287 :
4288 911753 : void HOptimizedGraphBuilder::VisitExpressionStatement(
4289 912070 : ExpressionStatement* stmt) {
4290 : DCHECK(!HasStackOverflow());
4291 : DCHECK(current_block() != NULL);
4292 : DCHECK(current_block()->HasPredecessor());
4293 912070 : VisitForEffect(stmt->expression());
4294 911753 : }
4295 :
4296 :
4297 389599 : void HOptimizedGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
4298 : DCHECK(!HasStackOverflow());
4299 : DCHECK(current_block() != NULL);
4300 : DCHECK(current_block()->HasPredecessor());
4301 389599 : }
4302 :
4303 :
4304 371 : void HOptimizedGraphBuilder::VisitSloppyBlockFunctionStatement(
4305 371 : SloppyBlockFunctionStatement* stmt) {
4306 371 : Visit(stmt->statement());
4307 371 : }
4308 :
4309 :
4310 3311637 : void HOptimizedGraphBuilder::VisitIfStatement(IfStatement* stmt) {
4311 : DCHECK(!HasStackOverflow());
4312 : DCHECK(current_block() != NULL);
4313 : DCHECK(current_block()->HasPredecessor());
4314 414256 : if (stmt->condition()->ToBooleanIsTrue()) {
4315 1655145 : Add<HSimulate>(stmt->ThenId());
4316 33 : Visit(stmt->then_statement());
4317 414223 : } else if (stmt->condition()->ToBooleanIsFalse()) {
4318 427 : Add<HSimulate>(stmt->ElseId());
4319 427 : Visit(stmt->else_statement());
4320 : } else {
4321 413796 : HBasicBlock* cond_true = graph()->CreateBasicBlock();
4322 413796 : HBasicBlock* cond_false = graph()->CreateBasicBlock();
4323 827592 : 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 413793 : CHECK(cond_true->HasPredecessor());
4332 413793 : CHECK(cond_false->HasPredecessor());
4333 :
4334 : cond_true->SetJoinId(stmt->ThenId());
4335 : set_current_block(cond_true);
4336 827586 : 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 827520 : CHECK_BAILOUT(Visit(stmt->else_statement()));
4342 : cond_false = current_block();
4343 :
4344 413760 : HBasicBlock* join = CreateJoin(cond_true, cond_false, stmt->IfId());
4345 : set_current_block(join);
4346 : }
4347 : }
4348 :
4349 :
4350 8143 : HBasicBlock* HOptimizedGraphBuilder::BreakAndContinueScope::Get(
4351 : BreakableStatement* stmt,
4352 : BreakType type,
4353 : Scope** scope,
4354 : int* drop_extra) {
4355 8143 : *drop_extra = 0;
4356 65928 : BreakAndContinueScope* current = this;
4357 41413 : while (current != NULL && current->info()->target() != stmt) {
4358 8492 : *drop_extra += current->info()->drop_extra();
4359 : current = current->next();
4360 : }
4361 : DCHECK(current != NULL); // Always found (unless stack is malformed).
4362 8143 : *scope = current->info()->scope();
4363 :
4364 8143 : if (type == BREAK) {
4365 7601 : *drop_extra += current->info()->drop_extra();
4366 : }
4367 :
4368 : HBasicBlock* block = NULL;
4369 8143 : switch (type) {
4370 : case BREAK:
4371 7601 : block = current->info()->break_block();
4372 7601 : if (block == NULL) {
4373 3762 : block = current->owner()->graph()->CreateBasicBlock();
4374 : current->info()->set_break_block(block);
4375 : }
4376 : break;
4377 :
4378 : case CONTINUE:
4379 542 : block = current->info()->continue_block();
4380 542 : if (block == NULL) {
4381 449 : block = current->owner()->graph()->CreateBasicBlock();
4382 : current->info()->set_continue_block(block);
4383 : }
4384 : break;
4385 : }
4386 :
4387 8143 : return block;
4388 : }
4389 :
4390 :
4391 544 : void HOptimizedGraphBuilder::VisitContinueStatement(
4392 1086 : ContinueStatement* stmt) {
4393 : DCHECK(!HasStackOverflow());
4394 : DCHECK(current_block() != NULL);
4395 : DCHECK(current_block()->HasPredecessor());
4396 :
4397 544 : if (function_state()->IsInsideDoExpressionScope()) {
4398 546 : return Bailout(kDoExpressionUnmodelable);
4399 : }
4400 :
4401 542 : Scope* outer_scope = NULL;
4402 542 : Scope* inner_scope = scope();
4403 542 : int drop_extra = 0;
4404 : HBasicBlock* continue_block = break_scope()->Get(
4405 : stmt->target(), BreakAndContinueScope::CONTINUE,
4406 542 : &outer_scope, &drop_extra);
4407 : HValue* context = environment()->context();
4408 542 : Drop(drop_extra);
4409 542 : int context_pop_count = inner_scope->ContextChainLength(outer_scope);
4410 542 : if (context_pop_count > 0) {
4411 0 : while (context_pop_count-- > 0) {
4412 : HInstruction* context_instruction = Add<HLoadNamedField>(
4413 : context, nullptr,
4414 0 : HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
4415 : context = context_instruction;
4416 : }
4417 0 : environment()->BindContext(context);
4418 : }
4419 :
4420 : Goto(continue_block);
4421 : set_current_block(NULL);
4422 : }
4423 :
4424 :
4425 15206 : void HOptimizedGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
4426 : DCHECK(!HasStackOverflow());
4427 : DCHECK(current_block() != NULL);
4428 : DCHECK(current_block()->HasPredecessor());
4429 :
4430 7605 : if (function_state()->IsInsideDoExpressionScope()) {
4431 7609 : return Bailout(kDoExpressionUnmodelable);
4432 : }
4433 :
4434 7601 : Scope* outer_scope = NULL;
4435 7601 : Scope* inner_scope = scope();
4436 7601 : int drop_extra = 0;
4437 : HBasicBlock* break_block = break_scope()->Get(
4438 : stmt->target(), BreakAndContinueScope::BREAK,
4439 7601 : &outer_scope, &drop_extra);
4440 : HValue* context = environment()->context();
4441 7601 : Drop(drop_extra);
4442 7601 : int context_pop_count = inner_scope->ContextChainLength(outer_scope);
4443 7601 : if (context_pop_count > 0) {
4444 804 : while (context_pop_count-- > 0) {
4445 : HInstruction* context_instruction = Add<HLoadNamedField>(
4446 : context, nullptr,
4447 402 : HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
4448 : context = context_instruction;
4449 : }
4450 402 : environment()->BindContext(context);
4451 : }
4452 : Goto(break_block);
4453 : set_current_block(NULL);
4454 : }
4455 :
4456 :
4457 1421756 : void HOptimizedGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
4458 : DCHECK(!HasStackOverflow());
4459 : DCHECK(current_block() != NULL);
4460 : DCHECK(current_block()->HasPredecessor());
4461 263374 : FunctionState* state = function_state();
4462 263374 : AstContext* context = call_context();
4463 547435 : if (context == NULL) {
4464 : // Not an inlined return, so an actual one.
4465 611285 : CHECK_ALIVE(VisitForValue(stmt->expression()));
4466 283899 : HValue* result = environment()->Pop();
4467 283899 : Add<HReturn>(result);
4468 263374 : } 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 207 : if (context->IsTest()) {
4473 33 : CHECK_ALIVE(VisitForEffect(stmt->expression()));
4474 22 : context->ReturnValue(graph()->GetConstantTrue());
4475 196 : } else if (context->IsEffect()) {
4476 66 : CHECK_ALIVE(VisitForEffect(stmt->expression()));
4477 : Goto(function_return(), state);
4478 : } else {
4479 : DCHECK(context->IsValue());
4480 522 : 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 174 : LAST_JS_RECEIVER_TYPE);
4487 174 : HBasicBlock* if_spec_object = graph()->CreateBasicBlock();
4488 174 : HBasicBlock* not_spec_object = graph()->CreateBasicBlock();
4489 174 : typecheck->SetSuccessorAt(0, if_spec_object);
4490 174 : typecheck->SetSuccessorAt(1, not_spec_object);
4491 174 : FinishCurrentBlock(typecheck);
4492 : AddLeaveInlined(if_spec_object, return_value, state);
4493 : AddLeaveInlined(not_spec_object, receiver, state);
4494 : }
4495 263167 : } 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 156 : CHECK_ALIVE(VisitForEffect(stmt->expression()));
4499 52 : if (context->IsTest()) {
4500 : HValue* rhs = environment()->arguments_environment()->Lookup(1);
4501 8 : context->ReturnValue(rhs);
4502 44 : } 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 263115 : if (context->IsTest()) {
4513 220549 : TestContext* test = TestContext::cast(context);
4514 220549 : VisitForControl(stmt->expression(), test->if_true(), test->if_false());
4515 42566 : } 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 18936 : CHECK_ALIVE(VisitForValue(stmt->expression()));
4521 : Pop();
4522 : Goto(function_return(), state);
4523 : } else {
4524 : DCHECK(context->IsValue());
4525 108741 : CHECK_ALIVE(VisitForValue(stmt->expression()));
4526 : AddLeaveInlined(Pop(), state);
4527 : }
4528 : }
4529 : set_current_block(NULL);
4530 : }
4531 :
4532 :
4533 0 : void HOptimizedGraphBuilder::VisitWithStatement(WithStatement* stmt) {
4534 : DCHECK(!HasStackOverflow());
4535 : DCHECK(current_block() != NULL);
4536 : DCHECK(current_block()->HasPredecessor());
4537 0 : return Bailout(kWithStatement);
4538 : }
4539 :
4540 :
4541 103420 : 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 4573 : int clause_count = clauses->length();
4548 165318 : ZoneList<HBasicBlock*> body_blocks(clause_count, zone());
4549 :
4550 13719 : CHECK_ALIVE(VisitForValue(stmt->tag()));
4551 4573 : Add<HSimulate>(stmt->EntryId());
4552 : HValue* tag_value = Top();
4553 4573 : 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 34085 : for (int i = 0; i < clause_count; ++i) {
4558 57636 : CaseClause* clause = clauses->at(i);
4559 29514 : 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 56248 : CHECK_BAILOUT(VisitForValue(clause->label()));
4567 28122 : if (current_block() == NULL) return Bailout(kUnsupportedSwitchStatement);
4568 : HValue* label_value = Pop();
4569 :
4570 28122 : 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 28122 : ScriptPositionToSourcePosition(clause->label()->position()),
4577 84366 : PUSH_BEFORE_SIMULATE, clause->id());
4578 :
4579 28122 : HBasicBlock* next_test_block = graph()->CreateBasicBlock();
4580 28122 : HBasicBlock* body_block = graph()->CreateBasicBlock();
4581 : body_blocks.Add(body_block, zone());
4582 28122 : compare->SetSuccessorAt(0, body_block);
4583 28122 : compare->SetSuccessorAt(1, next_test_block);
4584 28122 : 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 33150 : for (int i = 0; i < clause_count; ++i) {
4604 57764 : 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 28882 : if (clause->is_default()) {
4610 1388 : if (last_block == NULL) continue;
4611 : normal_block = last_block;
4612 : last_block = NULL; // Cleared to indicate we've handled it.
4613 : } else {
4614 54988 : normal_block = body_blocks[i];
4615 : }
4616 :
4617 28882 : if (fall_through_block == NULL) {
4618 : set_current_block(normal_block);
4619 : } else {
4620 : HBasicBlock* join = CreateJoin(fall_through_block,
4621 : normal_block,
4622 7049 : clause->EntryId());
4623 : set_current_block(join);
4624 : }
4625 :
4626 57764 : 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 4268 : HBasicBlock* break_block = break_info.break_block();
4634 4268 : if (break_block == NULL) {
4635 : set_current_block(CreateJoin(fall_through_block,
4636 : last_block,
4637 2757 : stmt->ExitId()));
4638 : } else {
4639 1511 : if (fall_through_block != NULL) Goto(fall_through_block, break_block);
4640 1511 : if (last_block != NULL) Goto(last_block, break_block);
4641 : break_block->SetJoinId(stmt->ExitId());
4642 : set_current_block(break_block);
4643 : }
4644 : }
4645 :
4646 90916 : void HOptimizedGraphBuilder::VisitLoopBody(IterationStatement* stmt,
4647 : BailoutId stack_check_id,
4648 45458 : HBasicBlock* loop_entry) {
4649 45458 : Add<HSimulate>(stack_check_id);
4650 : HStackCheck* stack_check =
4651 45458 : HStackCheck::cast(Add<HStackCheck>(HStackCheck::kBackwardsBranch));
4652 : DCHECK(loop_entry->IsLoopHeader());
4653 : loop_entry->loop_information()->set_stack_check(stack_check);
4654 45458 : CHECK_BAILOUT(Visit(stmt->body()));
4655 : }
4656 :
4657 :
4658 2896 : void HOptimizedGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
4659 : DCHECK(!HasStackOverflow());
4660 : DCHECK(current_block() != NULL);
4661 : DCHECK(current_block()->HasPredecessor());
4662 : DCHECK(current_block() != NULL);
4663 720 : HBasicBlock* loop_entry = BuildLoopEntry(stmt);
4664 :
4665 2378 : BreakAndContinueInfo break_info(stmt, scope());
4666 : {
4667 : BreakAndContinueScope push(&break_info, this);
4668 1244 : CHECK_BAILOUT(VisitLoopBody(stmt, stmt->StackCheckId(), loop_entry));
4669 : }
4670 : HBasicBlock* body_exit = JoinContinue(
4671 1244 : stmt, stmt->ContinueId(), current_block(), break_info.continue_block());
4672 : HBasicBlock* loop_successor = NULL;
4673 622 : if (body_exit != NULL) {
4674 : set_current_block(body_exit);
4675 616 : loop_successor = graph()->CreateBasicBlock();
4676 616 : if (stmt->cond()->ToBooleanIsFalse()) {
4677 98 : 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 518 : body_exit = graph()->CreateBasicBlock();
4684 1036 : CHECK_BAILOUT(VisitForControl(stmt->cond(), body_exit, loop_successor));
4685 : }
4686 1134 : if (body_exit != NULL && body_exit->HasPredecessor()) {
4687 : body_exit->SetJoinId(stmt->BackEdgeId());
4688 : } else {
4689 : body_exit = NULL;
4690 : }
4691 616 : 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 622 : break_info.break_block());
4702 : set_current_block(loop_exit);
4703 : }
4704 :
4705 :
4706 16876 : void HOptimizedGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
4707 : DCHECK(!HasStackOverflow());
4708 : DCHECK(current_block() != NULL);
4709 : DCHECK(current_block()->HasPredecessor());
4710 : DCHECK(current_block() != NULL);
4711 4219 : HBasicBlock* loop_entry = BuildLoopEntry(stmt);
4712 :
4713 : // If the condition is constant true, do not generate a branch.
4714 : HBasicBlock* loop_successor = NULL;
4715 16873 : HBasicBlock* body_entry = graph()->CreateBasicBlock();
4716 4219 : loop_successor = graph()->CreateBasicBlock();
4717 8441 : CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor));
4718 4219 : if (body_entry->HasPredecessor()) {
4719 : body_entry->SetJoinId(stmt->BodyId());
4720 : set_current_block(body_entry);
4721 : }
4722 4219 : 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 4219 : if (current_block() != NULL) {
4730 : BreakAndContinueScope push(&break_info, this);
4731 8438 : CHECK_BAILOUT(VisitLoopBody(stmt, stmt->StackCheckId(), loop_entry));
4732 : }
4733 : HBasicBlock* body_exit = JoinContinue(
4734 8432 : 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 4216 : break_info.break_block());
4740 : set_current_block(loop_exit);
4741 : }
4742 :
4743 :
4744 308905 : void HOptimizedGraphBuilder::VisitForStatement(ForStatement* stmt) {
4745 : DCHECK(!HasStackOverflow());
4746 : DCHECK(current_block() != NULL);
4747 : DCHECK(current_block()->HasPredecessor());
4748 39603 : if (stmt->init() != NULL) {
4749 310864 : CHECK_ALIVE(Visit(stmt->init()));
4750 : }
4751 : DCHECK(current_block() != NULL);
4752 39603 : HBasicBlock* loop_entry = BuildLoopEntry(stmt);
4753 :
4754 39603 : HBasicBlock* loop_successor = graph()->CreateBasicBlock();
4755 39603 : HBasicBlock* body_entry = graph()->CreateBasicBlock();
4756 39603 : if (stmt->cond() != NULL) {
4757 77316 : CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor));
4758 38594 : if (body_entry->HasPredecessor()) {
4759 : body_entry->SetJoinId(stmt->BodyId());
4760 : set_current_block(body_entry);
4761 : }
4762 38594 : 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 945 : HControlInstruction* branch = New<HBranch>(graph()->GetConstantTrue());
4771 945 : branch->SetSuccessorAt(0, body_entry);
4772 945 : branch->SetSuccessorAt(1, loop_successor);
4773 945 : FinishCurrentBlock(branch);
4774 : set_current_block(body_entry);
4775 : }
4776 :
4777 : BreakAndContinueInfo break_info(stmt, scope());
4778 39539 : if (current_block() != NULL) {
4779 : BreakAndContinueScope push(&break_info, this);
4780 79078 : CHECK_BAILOUT(VisitLoopBody(stmt, stmt->StackCheckId(), loop_entry));
4781 : }
4782 : HBasicBlock* body_exit = JoinContinue(
4783 78688 : stmt, stmt->ContinueId(), current_block(), break_info.continue_block());
4784 :
4785 39344 : if (stmt->next() != NULL && body_exit != NULL) {
4786 : set_current_block(body_exit);
4787 74856 : 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 39295 : break_info.break_block());
4796 : set_current_block(loop_exit);
4797 : }
4798 :
4799 :
4800 4391 : void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
4801 : DCHECK(!HasStackOverflow());
4802 : DCHECK(current_block() != NULL);
4803 : DCHECK(current_block()->HasPredecessor());
4804 :
4805 2229 : if (!stmt->each()->IsVariableProxy() ||
4806 2222 : !stmt->each()->AsVariableProxy()->var()->IsStackLocal()) {
4807 40 : return Bailout(kForInStatementWithNonLocalEachVariable);
4808 : }
4809 :
4810 2162 : Variable* each_var = stmt->each()->AsVariableProxy()->var();
4811 :
4812 4318 : CHECK_ALIVE(VisitForValue(stmt->enumerable()));
4813 : HValue* enumerable = Top(); // Leave enumerable at the top.
4814 :
4815 1078 : IfBuilder if_undefined_or_null(this);
4816 : if_undefined_or_null.If<HCompareObjectEqAndBranch>(
4817 1078 : enumerable, graph()->GetConstantUndefined());
4818 1078 : if_undefined_or_null.Or();
4819 : if_undefined_or_null.If<HCompareObjectEqAndBranch>(
4820 1078 : enumerable, graph()->GetConstantNull());
4821 : if_undefined_or_null.ThenDeopt(DeoptimizeReason::kUndefinedOrNullInForIn);
4822 1078 : if_undefined_or_null.End();
4823 1078 : BuildForInBody(stmt, each_var, enumerable);
4824 : }
4825 :
4826 :
4827 2156 : void HOptimizedGraphBuilder::BuildForInBody(ForInStatement* stmt,
4828 : Variable* each_var,
4829 1078 : HValue* enumerable) {
4830 11625 : Handle<Map> meta_map = isolate()->factory()->meta_map();
4831 1078 : bool fast = stmt->for_in_type() == ForInStatement::FAST_FOR_IN;
4832 1078 : BuildCheckHeapObject(enumerable);
4833 1078 : Add<HCheckInstanceType>(enumerable, HCheckInstanceType::IS_JS_RECEIVER);
4834 : Add<HSimulate>(stmt->ToObjectId());
4835 1078 : if (fast) {
4836 842 : HForInPrepareMap* map = Add<HForInPrepareMap>(enumerable);
4837 842 : Push(map);
4838 : Add<HSimulate>(stmt->EnumId());
4839 : Drop(1);
4840 842 : Add<HCheckMaps>(map, meta_map);
4841 :
4842 : HForInCacheArray* array = Add<HForInCacheArray>(
4843 842 : enumerable, map, DescriptorArray::kEnumCacheBridgeCacheIndex);
4844 842 : HValue* enum_length = BuildEnumLength(map);
4845 :
4846 : HForInCacheArray* index_cache = Add<HForInCacheArray>(
4847 842 : enumerable, map, DescriptorArray::kEnumCacheBridgeIndicesCacheIndex);
4848 : array->set_index_cache(index_cache);
4849 :
4850 842 : Push(map);
4851 842 : Push(array);
4852 842 : Push(enum_length);
4853 : Add<HSimulate>(stmt->PrepareId());
4854 : } else {
4855 : Runtime::FunctionId function_id = Runtime::kForInEnumerate;
4856 236 : Add<HPushArguments>(enumerable);
4857 : HCallRuntime* array =
4858 236 : Add<HCallRuntime>(Runtime::FunctionForId(function_id), 1);
4859 236 : Push(array);
4860 : Add<HSimulate>(stmt->EnumId());
4861 : Drop(1);
4862 :
4863 : IfBuilder if_fast(this);
4864 236 : if_fast.If<HCompareMap>(array, meta_map);
4865 236 : if_fast.Then();
4866 : {
4867 : HValue* cache_map = array;
4868 : HForInCacheArray* cache = Add<HForInCacheArray>(
4869 236 : enumerable, cache_map, DescriptorArray::kEnumCacheBridgeCacheIndex);
4870 236 : HValue* enum_length = BuildEnumLength(cache_map);
4871 236 : Push(cache_map);
4872 236 : Push(cache);
4873 236 : Push(enum_length);
4874 236 : Add<HSimulate>(stmt->PrepareId(), FIXED_SIMULATE);
4875 : }
4876 : if_fast.Else();
4877 : {
4878 236 : Push(graph()->GetConstant1());
4879 236 : Push(array);
4880 236 : Push(AddLoadFixedArrayLength(array));
4881 236 : Add<HSimulate>(stmt->PrepareId(), FIXED_SIMULATE);
4882 : }
4883 : }
4884 :
4885 1078 : Push(graph()->GetConstant0());
4886 :
4887 1078 : 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 1078 : New<HCompareNumericAndBranch>(index, limit, Token::LT);
4901 : compare_index->set_observed_input_representation(
4902 : Representation::Smi(), Representation::Smi());
4903 :
4904 1078 : HBasicBlock* loop_body = graph()->CreateBasicBlock();
4905 1078 : HBasicBlock* loop_successor = graph()->CreateBasicBlock();
4906 :
4907 1078 : compare_index->SetSuccessorAt(0, loop_body);
4908 1078 : compare_index->SetSuccessorAt(1, loop_successor);
4909 1078 : 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 1078 : HValue* key = Add<HLoadKeyed>(array, index, index, nullptr, FAST_ELEMENTS);
4918 :
4919 : HBasicBlock* continue_block = nullptr;
4920 1078 : if (fast) {
4921 : // Check if expected map still matches that of the enumerable.
4922 842 : 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 236 : 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 236 : HBasicBlock* if_fast = graph()->CreateBasicBlock();
4933 236 : HBasicBlock* if_slow = graph()->CreateBasicBlock();
4934 236 : HBasicBlock* if_slow_pass = graph()->CreateBasicBlock();
4935 236 : HBasicBlock* if_slow_skip = graph()->CreateBasicBlock();
4936 236 : HBasicBlock* if_join = graph()->CreateBasicBlock();
4937 :
4938 : // Check if expected map still matches that of the enumerable.
4939 : HValue* enumerable_map =
4940 236 : Add<HLoadNamedField>(enumerable, nullptr, HObjectAccess::ForMap());
4941 : FinishCurrentBlock(
4942 236 : 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 236 : Push(key);
4947 : Goto(if_join);
4948 : }
4949 : set_current_block(if_slow);
4950 : {
4951 236 : Callable callable = CodeFactory::ForInFilter(isolate());
4952 236 : HValue* values[] = {key, enumerable};
4953 236 : HConstant* stub_value = Add<HConstant>(callable.code());
4954 : Push(Add<HCallWithDescriptor>(stub_value, 0, callable.descriptor(),
4955 236 : ArrayVector(values)));
4956 : Add<HSimulate>(stmt->FilterId());
4957 : FinishCurrentBlock(New<HCompareObjectEqAndBranch>(
4958 472 : 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 3234 : CHECK_BAILOUT(VisitLoopBody(stmt, stmt->StackCheckId(), loop_entry));
4981 : }
4982 :
4983 : HBasicBlock* body_exit = JoinContinue(
4984 2098 : stmt, stmt->IncrementId(), current_block(), break_info.continue_block());
4985 :
4986 1049 : if (body_exit != NULL) {
4987 : set_current_block(body_exit);
4988 :
4989 : HValue* current_index = Pop();
4990 : HValue* increment =
4991 992 : AddUncasted<HAdd>(current_index, graph()->GetConstant1());
4992 : increment->ClearFlag(HValue::kCanOverflow);
4993 992 : 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 1049 : break_info.break_block());
5002 :
5003 : set_current_block(loop_exit);
5004 : }
5005 :
5006 :
5007 0 : void HOptimizedGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) {
5008 : DCHECK(!HasStackOverflow());
5009 : DCHECK(current_block() != NULL);
5010 : DCHECK(current_block()->HasPredecessor());
5011 0 : return Bailout(kForOfStatement);
5012 : }
5013 :
5014 :
5015 0 : void HOptimizedGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
5016 : DCHECK(!HasStackOverflow());
5017 : DCHECK(current_block() != NULL);
5018 : DCHECK(current_block()->HasPredecessor());
5019 0 : return Bailout(kTryCatchStatement);
5020 : }
5021 :
5022 :
5023 0 : void HOptimizedGraphBuilder::VisitTryFinallyStatement(
5024 : TryFinallyStatement* stmt) {
5025 : DCHECK(!HasStackOverflow());
5026 : DCHECK(current_block() != NULL);
5027 : DCHECK(current_block()->HasPredecessor());
5028 0 : return Bailout(kTryFinallyStatement);
5029 : }
5030 :
5031 :
5032 0 : void HOptimizedGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
5033 : DCHECK(!HasStackOverflow());
5034 : DCHECK(current_block() != NULL);
5035 : DCHECK(current_block()->HasPredecessor());
5036 0 : return Bailout(kDebuggerStatement);
5037 : }
5038 :
5039 :
5040 0 : void HOptimizedGraphBuilder::VisitCaseClause(CaseClause* clause) {
5041 0 : UNREACHABLE();
5042 : }
5043 :
5044 :
5045 424473 : 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 409471 : expr, current_info()->script(), top_info());
5051 : // We also have a stack overflow if the recursive compilation did.
5052 104243 : 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 104243 : HConstant* shared_info_value = Add<HConstant>(shared_info);
5056 : HInstruction* instr;
5057 : Handle<FeedbackVector> vector(current_feedback_vector(), isolate());
5058 104243 : HValue* vector_value = Add<HConstant>(vector);
5059 : int index = FeedbackVector::GetIndex(expr->LiteralFeedbackSlot());
5060 104243 : HValue* index_value = Add<HConstant>(index);
5061 104243 : if (!expr->pretenure()) {
5062 96742 : Callable callable = CodeFactory::FastNewClosure(isolate());
5063 96742 : HValue* values[] = {shared_info_value, vector_value, index_value};
5064 96742 : HConstant* stub_value = Add<HConstant>(callable.code());
5065 : instr = New<HCallWithDescriptor>(stub_value, 0, callable.descriptor(),
5066 96742 : ArrayVector(values));
5067 : } else {
5068 7501 : Add<HPushArguments>(shared_info_value);
5069 7501 : Add<HPushArguments>(vector_value);
5070 7501 : Add<HPushArguments>(index_value);
5071 : Runtime::FunctionId function_id =
5072 7501 : expr->pretenure() ? Runtime::kNewClosure_Tenured : Runtime::kNewClosure;
5073 7501 : instr = New<HCallRuntime>(Runtime::FunctionForId(function_id), 3);
5074 : }
5075 208486 : return ast_context()->ReturnInstruction(instr, expr->id());
5076 : }
5077 :
5078 :
5079 0 : void HOptimizedGraphBuilder::VisitClassLiteral(ClassLiteral* lit) {
5080 : DCHECK(!HasStackOverflow());
5081 : DCHECK(current_block() != NULL);
5082 : DCHECK(current_block()->HasPredecessor());
5083 0 : return Bailout(kClassLiteral);
5084 : }
5085 :
5086 :
5087 0 : void HOptimizedGraphBuilder::VisitNativeFunctionLiteral(
5088 : NativeFunctionLiteral* expr) {
5089 : DCHECK(!HasStackOverflow());
5090 : DCHECK(current_block() != NULL);
5091 : DCHECK(current_block()->HasPredecessor());
5092 0 : return Bailout(kNativeFunctionLiteral);
5093 : }
5094 :
5095 :
5096 204 : void HOptimizedGraphBuilder::VisitDoExpression(DoExpression* expr) {
5097 : DoExpressionScope scope(this);
5098 : DCHECK(!HasStackOverflow());
5099 : DCHECK(current_block() != NULL);
5100 : DCHECK(current_block()->HasPredecessor());
5101 248 : CHECK_ALIVE(VisitBlock(expr->block()));
5102 18 : Visit(expr->result());
5103 : }
5104 :
5105 :
5106 93616 : void HOptimizedGraphBuilder::VisitConditional(Conditional* expr) {
5107 : DCHECK(!HasStackOverflow());
5108 : DCHECK(current_block() != NULL);
5109 : DCHECK(current_block()->HasPredecessor());
5110 28105 : HBasicBlock* cond_true = graph()->CreateBasicBlock();
5111 9373 : HBasicBlock* cond_false = graph()->CreateBasicBlock();
5112 18746 : 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 9373 : if (cond_true->HasPredecessor()) {
5117 : cond_true->SetJoinId(expr->ThenId());
5118 : set_current_block(cond_true);
5119 18746 : CHECK_BAILOUT(Visit(expr->then_expression()));
5120 : cond_true = current_block();
5121 : } else {
5122 : cond_true = NULL;
5123 : }
5124 :
5125 9366 : if (cond_false->HasPredecessor()) {
5126 : cond_false->SetJoinId(expr->ElseId());
5127 : set_current_block(cond_false);
5128 18732 : CHECK_BAILOUT(Visit(expr->else_expression()));
5129 : cond_false = current_block();
5130 : } else {
5131 : cond_false = NULL;
5132 : }
5133 :
5134 9366 : if (!ast_context()->IsTest()) {
5135 9350 : HBasicBlock* join = CreateJoin(cond_true, cond_false, expr->id());
5136 : set_current_block(join);
5137 18700 : if (join != NULL && !ast_context()->IsEffect()) {
5138 18606 : return ast_context()->ReturnValue(Pop());
5139 : }
5140 : }
5141 : }
5142 :
5143 0 : bool HOptimizedGraphBuilder::CanInlineGlobalPropertyAccess(
5144 : Variable* var, LookupIterator* it, PropertyAccessType access_type) {
5145 365671 : if (var->is_this()) return false;
5146 365671 : return CanInlineGlobalPropertyAccess(it, access_type);
5147 : }
5148 :
5149 365872 : bool HOptimizedGraphBuilder::CanInlineGlobalPropertyAccess(
5150 365872 : LookupIterator* it, PropertyAccessType access_type) {
5151 365872 : if (!current_info()->has_global_object()) {
5152 : return false;
5153 : }
5154 :
5155 365872 : 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 310284 : if (access_type == STORE && it->IsReadOnly()) return false;
5164 300120 : if (!it->GetHolder<JSObject>()->IsJSGlobalObject()) return false;
5165 300120 : return true;
5166 : case LookupIterator::JSPROXY:
5167 : case LookupIterator::TRANSITION:
5168 0 : UNREACHABLE();
5169 : }
5170 0 : UNREACHABLE();
5171 : return false;
5172 : }
5173 :
5174 :
5175 856650 : HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) {
5176 : DCHECK(var->IsContextSlot());
5177 428325 : HValue* context = environment()->context();
5178 428325 : int length = scope()->ContextChainLength(var->scope());
5179 859703 : while (length-- > 0) {
5180 : context = Add<HLoadNamedField>(
5181 : context, nullptr,
5182 3053 : HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
5183 : }
5184 428325 : return context;
5185 : }
5186 :
5187 290056 : void HOptimizedGraphBuilder::InlineGlobalPropertyLoad(LookupIterator* it,
5188 290056 : BailoutId ast_id) {
5189 290056 : Handle<PropertyCell> cell = it->GetPropertyCell();
5190 566539 : top_info()->dependencies()->AssumePropertyCell(cell);
5191 : auto cell_type = it->property_details().cell_type();
5192 290056 : if (cell_type == PropertyCellType::kConstant ||
5193 : cell_type == PropertyCellType::kUndefined) {
5194 : Handle<Object> constant_object(cell->value(), isolate());
5195 274177 : if (constant_object->IsConsString()) {
5196 102 : constant_object = String::Flatten(Handle<String>::cast(constant_object));
5197 : }
5198 274177 : HConstant* constant = New<HConstant>(constant_object);
5199 274177 : return ast_context()->ReturnInstruction(constant, ast_id);
5200 : } else {
5201 15879 : auto access = HObjectAccess::ForPropertyCellValue();
5202 : UniqueSet<Map>* field_maps = nullptr;
5203 15879 : if (cell_type == PropertyCellType::kConstantType) {
5204 8829 : switch (cell->GetConstantType()) {
5205 : case PropertyCellConstantType::kSmi:
5206 6458 : access = access.WithRepresentation(Representation::Smi());
5207 6458 : 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 2371 : access = access.WithRepresentation(Representation::HeapObject());
5214 : Handle<Map> map(HeapObject::cast(cell->value())->map());
5215 2371 : if (map->is_stable()) {
5216 : field_maps = new (zone())
5217 : UniqueSet<Map>(Unique<Map>::CreateImmovable(map), zone());
5218 : }
5219 : break;
5220 : }
5221 : }
5222 : }
5223 15879 : HConstant* cell_constant = Add<HConstant>(cell);
5224 : HLoadNamedField* instr;
5225 15879 : if (field_maps == nullptr) {
5226 13573 : instr = New<HLoadNamedField>(cell_constant, nullptr, access);
5227 : } else {
5228 : instr = New<HLoadNamedField>(cell_constant, nullptr, access, field_maps,
5229 2306 : HType::HeapObject());
5230 : }
5231 : instr->ClearDependsOnFlag(kInobjectFields);
5232 : instr->SetDependsOnFlag(kGlobalVars);
5233 15879 : return ast_context()->ReturnInstruction(instr, ast_id);
5234 : }
5235 : }
5236 :
5237 5423096 : void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
5238 : DCHECK(!HasStackOverflow());
5239 : DCHECK(current_block() != NULL);
5240 : DCHECK(current_block()->HasPredecessor());
5241 4715043 : Variable* variable = expr->var();
5242 2829281 : switch (variable->location()) {
5243 : case VariableLocation::UNALLOCATED: {
5244 361398 : 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 3310913 : isolate()->factory()->GlobalConstantFor(variable->name());
5252 361398 : if (!constant_value.is_null()) {
5253 11367 : HConstant* instr = New<HConstant>(constant_value);
5254 22734 : return ast_context()->ReturnInstruction(instr, expr->id());
5255 : }
5256 :
5257 350031 : 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 350031 : if (ScriptContextTable::Lookup(script_contexts, variable->name(),
5265 : &lookup)) {
5266 : Handle<Context> script_context = ScriptContextTable::GetContext(
5267 5544 : script_contexts, lookup.context_index);
5268 : Handle<Object> current_value =
5269 11088 : 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 5544 : if (current_value->IsTheHole(isolate())) {
5274 : return Bailout(kReferenceToUninitializedVariable);
5275 : }
5276 : HInstruction* result = New<HLoadNamedField>(
5277 : Add<HConstant>(script_context), nullptr,
5278 5542 : HObjectAccess::ForContextSlot(lookup.slot_index));
5279 11084 : return ast_context()->ReturnInstruction(result, expr->id());
5280 : }
5281 : }
5282 :
5283 344487 : LookupIterator it(global, variable->name(), LookupIterator::OWN);
5284 344487 : it.TryLookupCachedProperty();
5285 344487 : if (CanInlineGlobalPropertyAccess(variable, &it, LOAD)) {
5286 289913 : InlineGlobalPropertyLoad(&it, expr->id());
5287 289913 : return;
5288 : } else {
5289 : Handle<FeedbackVector> vector(current_feedback_vector(), isolate());
5290 : FeedbackSlot slot = expr->VariableFeedbackSlot();
5291 : DCHECK(vector->IsLoadGlobalIC(slot));
5292 :
5293 54574 : HValue* vector_value = Add<HConstant>(vector);
5294 54574 : HValue* slot_value = Add<HConstant>(vector->GetIndex(slot));
5295 : Callable callable = CodeFactory::LoadGlobalICInOptimizedCode(
5296 109148 : isolate(), ast_context()->typeof_mode());
5297 54574 : HValue* stub = Add<HConstant>(callable.code());
5298 54574 : HValue* name = Add<HConstant>(variable->name());
5299 54574 : HValue* values[] = {name, slot_value, vector_value};
5300 : HCallWithDescriptor* instr = New<HCallWithDescriptor>(
5301 : Code::LOAD_GLOBAL_IC, stub, 0, callable.descriptor(),
5302 54574 : ArrayVector(values));
5303 109148 : return ast_context()->ReturnInstruction(instr, expr->id());
5304 : }
5305 : }
5306 :
5307 : case VariableLocation::PARAMETER:
5308 : case VariableLocation::LOCAL: {
5309 2080247 : HValue* value = LookupAndMakeLive(variable);
5310 2080245 : if (value == graph()->GetConstantHole()) {
5311 : DCHECK(IsDeclaredVariableMode(variable->mode()) &&
5312 : variable->mode() != VAR);
5313 : return Bailout(kReferenceToUninitializedVariable);
5314 : }
5315 2080122 : return ast_context()->ReturnValue(value);
5316 : }
5317 :
5318 : case VariableLocation::CONTEXT: {
5319 387636 : HValue* context = BuildContextChainWalk(variable);
5320 : HLoadContextSlot::Mode mode;
5321 387636 : switch (variable->mode()) {
5322 : case LET:
5323 : case CONST:
5324 : mode = HLoadContextSlot::kCheckDeoptimize;
5325 : break;
5326 : default:
5327 : mode = HLoadContextSlot::kNoCheck;
5328 373898 : break;
5329 : }
5330 : HLoadContextSlot* instr =
5331 387636 : new(zone()) HLoadContextSlot(context, variable->index(), mode);
5332 775272 : return ast_context()->ReturnInstruction(instr, expr->id());
5333 : }
5334 :
5335 : case VariableLocation::LOOKUP:
5336 : return Bailout(kReferenceToAVariableWhichRequiresDynamicLookup);
5337 :
5338 : case VariableLocation::MODULE:
5339 0 : UNREACHABLE();
5340 : }
5341 : }
5342 :
5343 :
5344 2300514 : void HOptimizedGraphBuilder::VisitLiteral(Literal* expr) {
5345 : DCHECK(!HasStackOverflow());
5346 : DCHECK(current_block() != NULL);
5347 : DCHECK(current_block()->HasPredecessor());
5348 1150257 : HConstant* instr = New<HConstant>(expr->value());
5349 2300514 : return ast_context()->ReturnInstruction(instr, expr->id());
5350 : }
5351 :
5352 :
5353 34696 : void HOptimizedGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
5354 : DCHECK(!HasStackOverflow());
5355 : DCHECK(current_block() != NULL);
5356 : DCHECK(current_block()->HasPredecessor());
5357 17348 : Callable callable = CodeFactory::FastCloneRegExp(isolate());
5358 : int index = FeedbackVector::GetIndex(expr->literal_slot());
5359 17348 : HValue* values[] = {AddThisFunction(), Add<HConstant>(index),
5360 8674 : Add<HConstant>(expr->pattern()),
5361 34696 : Add<HConstant>(expr->flags())};
5362 8674 : HConstant* stub_value = Add<HConstant>(callable.code());
5363 : HInstruction* instr = New<HCallWithDescriptor>(
5364 8674 : stub_value, 0, callable.descriptor(), ArrayVector(values));
5365 17348 : return ast_context()->ReturnInstruction(instr, expr->id());
5366 : }
5367 :
5368 :
5369 770944 : static bool CanInlinePropertyAccess(Handle<Map> map) {
5370 770944 : if (map->instance_type() == HEAP_NUMBER_TYPE) return true;
5371 767964 : if (map->instance_type() < FIRST_NONSTRING_TYPE) return true;
5372 1432690 : return map->IsJSObjectMap() && !map->is_dictionary_map() &&
5373 1436147 : !map->has_named_interceptor() &&
5374 : // TODO(verwaest): Whitelist contexts to which we have access.
5375 722513 : !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.
5382 7333 : static bool IsFastLiteral(Handle<JSObject> boilerplate,
5383 : int max_depth,
5384 : int* max_properties) {
5385 7357 : if (boilerplate->map()->is_deprecated() &&
5386 24 : !JSObject::TryMigrateInstance(boilerplate)) {
5387 : return false;
5388 : }
5389 :
5390 : DCHECK(max_depth >= 0 && *max_properties >= 0);
5391 7333 : if (max_depth == 0) return false;
5392 :
5393 : Isolate* isolate = boilerplate->GetIsolate();
5394 : Handle<FixedArrayBase> elements(boilerplate->elements());
5395 9929 : if (elements->length() > 0 &&
5396 2596 : elements->map() != isolate->heap()->fixed_cow_array_map()) {
5397 1834 : if (boilerplate->HasFastSmiOrObjectElements()) {
5398 : Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
5399 : int length = elements->length();
5400 8230 : for (int i = 0; i < length; i++) {
5401 6834 : if ((*max_properties)-- == 0) return false;
5402 : Handle<Object> value(fast_elements->get(i), isolate);
5403 6834 : if (value->IsJSObject()) {
5404 313 : Handle<JSObject> value_object = Handle<JSObject>::cast(value);
5405 313 : if (!IsFastLiteral(value_object,
5406 : max_depth - 1,
5407 313 : max_properties)) {
5408 0 : return false;
5409 : }
5410 : }
5411 : }
5412 438 : } else if (boilerplate->HasFastDoubleElements()) {
5413 436 : if (elements->Size() > kMaxRegularHeapObjectSize) return false;
5414 : } else {
5415 : return false;
5416 : }
5417 : }
5418 :
5419 : Handle<FixedArray> properties(boilerplate->properties());
5420 7326 : 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 18169 : for (int i = 0; i < limit; i++) {
5427 10843 : PropertyDetails details = descriptors->GetDetails(i);
5428 14307 : if (details.location() != kField) continue;
5429 : DCHECK_EQ(kData, details.kind());
5430 7458 : if ((*max_properties)-- == 0) return false;
5431 7458 : FieldIndex field_index = FieldIndex::ForDescriptor(boilerplate->map(), i);
5432 7458 : if (boilerplate->IsUnboxedDoubleField(field_index)) continue;
5433 : Handle<Object> value(boilerplate->RawFastPropertyAt(field_index),
5434 7379 : isolate);
5435 7379 : if (value->IsJSObject()) {
5436 349 : Handle<JSObject> value_object = Handle<JSObject>::cast(value);
5437 349 : if (!IsFastLiteral(value_object,
5438 : max_depth - 1,
5439 349 : max_properties)) {
5440 0 : return false;
5441 : }
5442 : }
5443 : }
5444 : }
5445 : return true;
5446 : }
5447 :
5448 :
5449 176078 : void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
5450 : DCHECK(!HasStackOverflow());
5451 : DCHECK(current_block() != NULL);
5452 : DCHECK(current_block()->HasPredecessor());
5453 :
5454 22922 : 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 22922 : int max_properties = kMaxFastLiteralProperties;
5459 : Handle<Object> literals_cell(
5460 96578 : closure->feedback_vector()->Get(expr->literal_slot()), isolate());
5461 : Handle<AllocationSite> site;
5462 : Handle<JSObject> boilerplate;
5463 22922 : 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 26471 : if (!boilerplate.is_null() &&
5471 3549 : IsFastLiteral(boilerplate, kMaxFastLiteralDepth, &max_properties)) {
5472 : AllocationSiteUsageContext site_context(isolate(), site, false);
5473 3547 : site_context.EnterNewScope();
5474 3547 : literal = BuildFastLiteral(boilerplate, &site_context);
5475 : site_context.ExitScope(site, boilerplate);
5476 : } else {
5477 19375 : NoObservableSideEffectsScope no_effects(this);
5478 : Handle<BoilerplateDescription> constant_properties =
5479 19375 : expr->GetOrBuildConstantProperties(isolate());
5480 : int literal_index = FeedbackVector::GetIndex(expr->literal_slot());
5481 19375 : int flags = expr->ComputeFlags(true);
5482 :
5483 : Add<HPushArguments>(AddThisFunction(), Add<HConstant>(literal_index),
5484 : Add<HConstant>(constant_properties),
5485 19375 : Add<HConstant>(flags));
5486 :
5487 : Runtime::FunctionId function_id = Runtime::kCreateObjectLiteral;
5488 19375 : 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 22922 : Push(literal);
5494 174268 : for (int i = 0; i < expr->properties()->length(); i++) {
5495 90217 : ObjectLiteral::Property* property = expr->properties()->at(i);
5496 140544 : if (property->is_computed_name()) return Bailout(kComputedPropertyName);
5497 64767 : if (property->IsCompileTimeValue()) continue;
5498 :
5499 25450 : Literal* key = property->key()->AsLiteral();
5500 : Expression* value = property->value();
5501 :
5502 25450 : 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 24940 : if (key->IsStringLiteral()) {
5510 : DCHECK(key->IsPropertyName());
5511 24913 : if (property->emit_store()) {
5512 74682 : 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 24876 : FeedbackSlot slot = property->GetSlot();
5519 24876 : if (map.is_null()) {
5520 : // If we don't know the monomorphic type, do a generic store.
5521 56226 : CHECK_ALIVE(store = BuildNamedGeneric(STORE, NULL, slot, literal,
5522 : name, value));
5523 : } else {
5524 6134 : PropertyAccessInfo info(this, STORE, map, name);
5525 6134 : if (info.CanAccessMonomorphic()) {
5526 6134 : HValue* checked_literal = Add<HCheckMaps>(literal, map);
5527 : DCHECK(!info.IsAccessorConstant());
5528 : info.MarkAsInitializingStore();
5529 : store = BuildMonomorphicAccess(
5530 : &info, literal, checked_literal, value,
5531 6134 : BailoutId::None(), BailoutId::None());
5532 : DCHECK_NOT_NULL(store);
5533 : } else {
5534 0 : CHECK_ALIVE(store = BuildNamedGeneric(STORE, NULL, slot,
5535 : literal, name, value));
5536 : }
5537 : }
5538 24876 : if (store->IsInstruction()) {
5539 24876 : AddInstruction(HInstruction::cast(store));
5540 : }
5541 : DCHECK(store->HasObservableSideEffects());
5542 24876 : Add<HSimulate>(key->id(), REMOVABLE_SIMULATE);
5543 :
5544 : // Add [[HomeObject]] to function literals.
5545 24876 : if (FunctionLiteral::NeedsHomeObject(property->value())) {
5546 : Handle<Symbol> sym = isolate()->factory()->home_object_symbol();
5547 : HInstruction* store_home = BuildNamedGeneric(
5548 1 : STORE, NULL, property->GetSlot(1), value, sym, literal);
5549 1 : AddInstruction(store_home);
5550 : DCHECK(store_home->HasObservableSideEffects());
5551 1 : Add<HSimulate>(property->value()->id(), REMOVABLE_SIMULATE);
5552 : }
5553 : } else {
5554 57 : 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 0 : default: UNREACHABLE();
5564 : }
5565 : }
5566 :
5567 44734 : return ast_context()->ReturnValue(Pop());
5568 : }
5569 :
5570 :
5571 50726 : 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 17229 : int length = subexprs->length();
5577 : HInstruction* literal;
5578 :
5579 : Handle<AllocationSite> site;
5580 : Handle<FeedbackVector> vector(environment()->closure()->feedback_vector(),
5581 74199 : isolate());
5582 : Handle<Object> literals_cell(vector->Get(expr->literal_slot()), isolate());
5583 : Handle<JSObject> boilerplate_object;
5584 17229 : 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 17229 : int max_properties = kMaxFastLiteralProperties;
5593 20351 : if (!boilerplate_object.is_null() &&
5594 : IsFastLiteral(boilerplate_object, kMaxFastLiteralDepth,
5595 3122 : &max_properties)) {
5596 : DCHECK(site->SitePointsToLiteral());
5597 : AllocationSiteUsageContext site_context(isolate(), site, false);
5598 3117 : site_context.EnterNewScope();
5599 3117 : literal = BuildFastLiteral(boilerplate_object, &site_context);
5600 : site_context.ExitScope(site, boilerplate_object);
5601 : } else {
5602 14112 : NoObservableSideEffectsScope no_effects(this);
5603 : Handle<ConstantElementsPair> constants =
5604 14112 : 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 14112 : Add<HConstant>(constants), Add<HConstant>(flags));
5610 :
5611 : Runtime::FunctionId function_id = Runtime::kCreateArrayLiteral;
5612 14112 : literal = Add<HCallRuntime>(Runtime::FunctionForId(function_id), 4);
5613 :
5614 : // Register to deopt if the boilerplate ElementsKind changes.
5615 14112 : if (!site.is_null()) {
5616 5 : 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 17229 : Push(literal);
5623 :
5624 : HInstruction* elements = NULL;
5625 :
5626 965494 : for (int i = 0; i < length; i++) {
5627 948274 : 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 948274 : if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
5633 :
5634 48822 : CHECK_ALIVE(VisitForValue(subexpr));
5635 : HValue* value = Pop();
5636 : if (!Smi::IsValid(i)) return Bailout(kNonSmiKeyInArrayLiteral);
5637 :
5638 : elements = AddLoadElements(literal);
5639 :
5640 16268 : HValue* key = Add<HConstant>(i);
5641 :
5642 16268 : if (!boilerplate_object.is_null()) {
5643 : ElementsKind boilerplate_elements_kind =
5644 : boilerplate_object->GetElementsKind();
5645 3463 : 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 3463 : boilerplate_elements_kind);
5654 : break;
5655 : }
5656 : default:
5657 0 : UNREACHABLE();
5658 : break;
5659 : }
5660 : } else {
5661 : HInstruction* instr = BuildKeyedGeneric(
5662 12805 : STORE, expr, expr->LiteralFeedbackSlot(), literal, key, value);
5663 12805 : AddInstruction(instr);
5664 : }
5665 :
5666 : Add<HSimulate>(expr->GetIdForElement(i));
5667 : }
5668 :
5669 34440 : return ast_context()->ReturnValue(Pop());
5670 : }
5671 :
5672 :
5673 7416 : HCheckMaps* HOptimizedGraphBuilder::AddCheckMap(HValue* object,
5674 : Handle<Map> map) {
5675 7416 : BuildCheckHeapObject(object);
5676 7416 : return Add<HCheckMaps>(object, map);
5677 : }
5678 :
5679 :
5680 52412 : HInstruction* HOptimizedGraphBuilder::BuildLoadNamedField(
5681 : PropertyAccessInfo* info,
5682 : HValue* checked_object) {
5683 : // Check if this is a load of an immutable or constant property.
5684 104824 : if (checked_object->ActualValue()->IsConstant()) {
5685 : Handle<Object> object(
5686 39965 : HConstant::cast(checked_object->ActualValue())->handle(isolate()));
5687 :
5688 11662 : if (object->IsJSObject()) {
5689 : LookupIterator it(object, info->name(),
5690 11662 : LookupIterator::OWN_SKIP_INTERCEPTOR);
5691 11662 : if (it.IsFound()) {
5692 : bool is_reaonly_non_configurable =
5693 12405 : it.IsReadOnly() && !it.IsConfigurable();
5694 11656 : if (is_reaonly_non_configurable ||
5695 : (FLAG_track_constant_fields && info->IsDataConstantField())) {
5696 747 : Handle<Object> value = JSReceiver::GetDataProperty(&it);
5697 747 : if (!is_reaonly_non_configurable) {
5698 : DCHECK(!it.is_dictionary_holder());
5699 : // Add dependency on the map that introduced the field.
5700 0 : Handle<Map> field_owner_map = it.GetFieldOwnerMap();
5701 0 : top_info()->dependencies()->AssumeFieldOwner(field_owner_map);
5702 : }
5703 747 : return New<HConstant>(value);
5704 : }
5705 : }
5706 : }
5707 : }
5708 :
5709 51665 : HObjectAccess access = info->access();
5710 52105 : 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 17 : access.WithRepresentation(Representation::Tagged()));
5716 : // Load the double value from it.
5717 17 : access = HObjectAccess::ForHeapNumberValue();
5718 : }
5719 :
5720 : SmallMapList* map_list = info->field_maps();
5721 51665 : if (map_list->length() == 0) {
5722 43347 : return New<HLoadNamedField>(checked_object, checked_object, access);
5723 : }
5724 :
5725 : UniqueSet<Map>* maps = new(zone()) UniqueSet<Map>(map_list->length(), zone());
5726 33282 : for (int i = 0; i < map_list->length(); ++i) {
5727 8323 : maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone());
5728 : }
5729 : return New<HLoadNamedField>(
5730 8318 : checked_object, checked_object, access, maps, info->field_type());
5731 : }
5732 :
5733 42546 : 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 21285 : 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 21551 : if (field_access.representation().IsDouble() &&
5746 : (!FLAG_unbox_double_fields || !field_access.IsInobject())) {
5747 : HObjectAccess heap_number_access =
5748 24 : field_access.WithRepresentation(Representation::Tagged());
5749 24 : if (transition_to_field) {
5750 : // The store requires a mutable HeapNumber to be allocated.
5751 0 : NoObservableSideEffectsScope no_side_effects(this);
5752 0 : 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 0 : MUTABLE_HEAP_NUMBER_TYPE, graph()->GetConstant0());
5758 : AddStoreMapConstant(
5759 0 : heap_number, isolate()->factory()->mutable_heap_number_map());
5760 : Add<HStoreNamedField>(heap_number, HObjectAccess::ForHeapNumberValue(),
5761 0 : value);
5762 : instr = New<HStoreNamedField>(checked_object->ActualValue(),
5763 : heap_number_access,
5764 0 : heap_number);
5765 : } else {
5766 : // Already holds a HeapNumber; load the box and write its value field.
5767 : HInstruction* heap_number =
5768 24 : 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 24 : 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 21261 : if (field_access.representation().IsHeapObject()) {
5808 12725 : BuildCheckHeapObject(value);
5809 : }
5810 :
5811 21261 : if (!info->field_maps()->is_empty()) {
5812 : DCHECK(field_access.representation().IsHeapObject());
5813 2170 : 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 21261 : value, info->StoreMode());
5819 : }
5820 : }
5821 :
5822 21285 : if (transition_to_field) {
5823 10955 : Handle<Map> transition(info->transition());
5824 : DCHECK(!transition->is_deprecated());
5825 10955 : instr->SetTransition(Add<HConstant>(transition));
5826 : }
5827 : return instr;
5828 : }
5829 :
5830 : Handle<FieldType>
5831 106642 : HOptimizedGraphBuilder::PropertyAccessInfo::GetFieldTypeFromMap(
5832 106642 : Handle<Map> map) const {
5833 : DCHECK(IsFound());
5834 : DCHECK(number_ < map->NumberOfOwnDescriptors());
5835 319926 : return handle(map->instance_descriptors()->GetFieldType(number_), isolate());
5836 : }
5837 :
5838 10804 : bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatible(
5839 20819 : PropertyAccessInfo* info) {
5840 10804 : 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 10756 : if (IsNumberType()) return false;
5846 :
5847 : // Values are only compatible for monomorphic load if they all behave the same
5848 : // regarding value wrappers.
5849 10756 : if (IsValueWrapped() != info->IsValueWrapped()) return false;
5850 :
5851 10745 : if (!LookupDescriptor()) return false;
5852 :
5853 10684 : if (!IsFound()) {
5854 11194 : return (!info->IsFound() || info->has_holder()) &&
5855 9609 : map()->prototype() == info->map()->prototype();
5856 : }
5857 :
5858 : // Mismatch if the other access info found the property in the prototype
5859 : // chain.
5860 6407 : if (info->has_holder()) return false;
5861 :
5862 5881 : if (IsAccessorConstant()) {
5863 86 : return accessor_.is_identical_to(info->accessor_) &&
5864 81 : api_holder_.is_identical_to(info->api_holder_);
5865 : }
5866 :
5867 5800 : if (IsDataConstant()) {
5868 30 : return constant_.is_identical_to(info->constant_);
5869 : }
5870 :
5871 : DCHECK(IsData());
5872 5770 : if (!info->IsData()) return false;
5873 :
5874 5769 : Representation r = access_.representation();
5875 5769 : if (IsLoad()) {
5876 16342 : if (!info->access_.representation().IsCompatibleForLoad(r)) return false;
5877 : } else {
5878 475 : if (!info->access_.representation().IsCompatibleForStore(r)) return false;
5879 : }
5880 5754 : if (info->access_.offset() != access_.offset()) return false;
5881 3204 : if (info->access_.IsInobject() != access_.IsInobject()) return false;
5882 3204 : if (IsLoad()) {
5883 3162 : if (field_maps_.is_empty()) {
5884 : info->field_maps_.Clear();
5885 94 : } else if (!info->field_maps_.is_empty()) {
5886 267 : for (int i = 0; i < field_maps_.length(); ++i) {
5887 89 : 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 42 : if (field_maps_.length() != info->field_maps_.length()) return false;
5895 42 : for (int i = 0; i < field_maps_.length(); ++i) {
5896 0 : if (!field_maps_.at(i).is_identical_to(info->field_maps_.at(i))) {
5897 : return false;
5898 : }
5899 : }
5900 : }
5901 3204 : info->GeneralizeRepresentation(r);
5902 3204 : info->field_type_ = info->field_type_.Combine(field_type_);
5903 3204 : return true;
5904 : }
5905 :
5906 :
5907 315241 : bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() {
5908 315241 : if (!map_->IsJSObjectMap()) return true;
5909 294564 : LookupDescriptor(*map_, *name_);
5910 294564 : return LoadResult(map_);
5911 : }
5912 :
5913 :
5914 467913 : bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) {
5915 424559 : if (!IsLoad() && IsProperty() && IsReadOnly()) {
5916 : return false;
5917 : }
5918 :
5919 372638 : if (IsData()) {
5920 : // Construct the object field access.
5921 91509 : int index = GetLocalFieldIndexFromMap(map);
5922 91509 : access_ = HObjectAccess::ForField(map, index, representation(), name_);
5923 :
5924 : // Load field map for heap objects.
5925 91509 : return LoadFieldMaps(map);
5926 281129 : } else if (IsAccessorConstant()) {
5927 : Handle<Object> accessors = GetAccessorsFromMap(map);
5928 12225 : if (!accessors->IsAccessorPair()) return false;
5929 : Object* raw_accessor =
5930 : IsLoad() ? Handle<AccessorPair>::cast(accessors)->getter()
5931 3718 : : Handle<AccessorPair>::cast(accessors)->setter();
5932 3836 : if (!raw_accessor->IsJSFunction() &&
5933 : !raw_accessor->IsFunctionTemplateInfo())
5934 : return false;
5935 : Handle<Object> accessor = handle(HeapObject::cast(raw_accessor));
5936 3619 : CallOptimization call_optimization(accessor);
5937 3619 : if (call_optimization.is_simple_api_call()) {
5938 : CallOptimization::HolderLookup holder_lookup;
5939 : api_holder_ =
5940 51 : call_optimization.LookupHolderOfExpectedType(map_, &holder_lookup);
5941 : }
5942 3619 : accessor_ = accessor;
5943 273207 : } else if (IsDataConstant()) {
5944 192781 : constant_ = GetConstantFromMap(map);
5945 : }
5946 :
5947 : return true;
5948 : }
5949 :
5950 :
5951 106642 : bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadFieldMaps(
5952 142492 : Handle<Map> map) {
5953 : // Clear any previously collected field maps/type.
5954 : field_maps_.Clear();
5955 106642 : field_type_ = HType::Tagged();
5956 :
5957 : // Figure out the field type from the accessor map.
5958 106642 : Handle<FieldType> field_type = GetFieldTypeFromMap(map);
5959 :
5960 : // Collect the (stable) maps from the field type.
5961 106642 : if (field_type->IsClass()) {
5962 : DCHECK(access_.representation().IsHeapObject());
5963 13136 : Handle<Map> field_map = field_type->AsClass();
5964 13136 : if (field_map->is_stable()) {
5965 : field_maps_.Add(field_map, zone());
5966 : }
5967 : }
5968 :
5969 106642 : if (field_maps_.is_empty()) {
5970 : // Store is not safe if the field map was cleared.
5971 123697 : return IsLoad() || !field_type->IsNone();
5972 : }
5973 :
5974 : // Determine field HType from field type.
5975 11950 : field_type_ = HType::FromFieldType(field_type, zone());
5976 : DCHECK(field_type_.IsHeapObject());
5977 :
5978 : // Add dependency on the map that introduced the field.
5979 23900 : top_info()->dependencies()->AssumeFieldOwner(GetFieldOwnerFromMap(map));
5980 11950 : return true;
5981 : }
5982 :
5983 :
5984 224480 : bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
5985 96799 : Handle<Map> map = this->map();
5986 96799 : if (name_->IsPrivate()) {
5987 : NotFound();
5988 108 : return !map->has_hidden_prototype();
5989 : }
5990 :
5991 146250 : while (map->prototype()->IsJSObject()) {
5992 128477 : holder_ = handle(JSObject::cast(map->prototype()));
5993 128477 : if (holder_->map()->is_deprecated()) {
5994 0 : JSObject::TryMigrateInstance(holder_);
5995 : }
5996 : map = Handle<Map>(holder_->map());
5997 128477 : if (!CanInlinePropertyAccess(map)) {
5998 : NotFound();
5999 796 : return false;
6000 : }
6001 127681 : LookupDescriptor(*map, *name_);
6002 127681 : if (IsFound()) return LoadResult(map);
6003 : }
6004 :
6005 : NotFound();
6006 17773 : return !map->prototype()->IsJSReceiver();
6007 : }
6008 :
6009 :
6010 97659 : bool HOptimizedGraphBuilder::PropertyAccessInfo::IsIntegerIndexedExotic() {
6011 : InstanceType instance_type = map_->instance_type();
6012 98494 : return instance_type == JS_TYPED_ARRAY_TYPE && name_->IsString() &&
6013 97659 : IsSpecialIndex(isolate()->unicode_cache(), String::cast(*name_));
6014 : }
6015 :
6016 :
6017 987075 : bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() {
6018 335489 : if (!CanInlinePropertyAccess(map_)) return false;
6019 346873 : if (IsJSObjectFieldAccessor()) return IsLoad();
6020 376766 : if (map_->IsJSFunctionMap() && map_->is_constructor() &&
6021 338274 : !map_->has_non_instance_prototype() &&
6022 : name_.is_identical_to(isolate()->factory()->prototype_string())) {
6023 6119 : return IsLoad();
6024 : }
6025 304496 : if (!LookupDescriptor()) return false;
6026 517407 : if (IsFound()) return IsLoad() || !IsReadOnly();
6027 96826 : if (IsIntegerIndexedExotic()) return false;
6028 96799 : if (!LookupInPrototypes()) return false;
6029 95877 : if (IsLoad()) return true;
6030 :
6031 16976 : if (IsAccessorConstant()) return true;
6032 16838 : LookupTransition(*map_, *name_, NONE);
6033 33350 : 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 15133 : map_->GetInObjectProperties();
6039 : PropertyDetails details =
6040 15133 : transition()->instance_descriptors()->GetDetails(descriptor);
6041 15133 : Representation representation = details.representation();
6042 15133 : access_ = HObjectAccess::ForField(map_, index, representation, name_);
6043 :
6044 : // Load field map for heap objects.
6045 15133 : return LoadFieldMaps(transition());
6046 : }
6047 : return false;
6048 : }
6049 :
6050 :
6051 286581 : bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessAsMonomorphic(
6052 264825 : SmallMapList* maps) {
6053 : DCHECK(map_.is_identical_to(maps->first()));
6054 286581 : if (!CanAccessMonomorphic()) return false;
6055 : STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism);
6056 282127 : if (maps->length() > kMaxLoadPolymorphism) return false;
6057 282127 : HObjectAccess access = HObjectAccess::ForMap(); // bogus default
6058 282127 : if (GetJSObjectFieldAccess(&access)) {
6059 19806 : for (int i = 1; i < maps->length(); ++i) {
6060 1858 : PropertyAccessInfo test_info(builder_, access_type_, maps->at(i), name_);
6061 3705 : HObjectAccess test_access = HObjectAccess::ForMap(); // bogus default
6062 2086 : if (!test_info.GetJSObjectFieldAccess(&test_access)) return false;
6063 3694 : 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 265581 : if (IsNumberType()) return false;
6072 :
6073 : // Multiple maps cannot transition to the same target map.
6074 : DCHECK(!IsLoad() || !IsTransition());
6075 273760 : if (IsTransition() && maps->length() > 1) return false;
6076 :
6077 274675 : for (int i = 1; i < maps->length(); ++i) {
6078 10804 : PropertyAccessInfo test_info(builder_, access_type_, maps->at(i), name_);
6079 10804 : if (!test_info.IsCompatible(this)) return false;
6080 : }
6081 :
6082 : return true;
6083 : }
6084 :
6085 :
6086 183001 : Handle<Map> HOptimizedGraphBuilder::PropertyAccessInfo::map() {
6087 : Handle<JSFunction> ctor;
6088 183001 : if (Map::GetConstructorFunction(
6089 : map_, handle(current_info()->closure()->context()->native_context()))
6090 366002 : .ToHandle(&ctor)) {
6091 : return handle(ctor->initial_map());
6092 : }
6093 152186 : return map_;
6094 : }
6095 :
6096 :
6097 : static bool NeedsWrapping(Handle<Map> map, Handle<JSFunction> target) {
6098 8983 : return !map->IsJSObjectMap() &&
6099 70520 : is_sloppy(target->shared()->language_mode()) &&
6100 : !target->shared()->native();
6101 : }
6102 :
6103 :
6104 4862 : bool HOptimizedGraphBuilder::PropertyAccessInfo::NeedsWrappingFor(
6105 : Handle<JSFunction> target) const {
6106 4862 : return NeedsWrapping(map_, target);
6107 : }
6108 :
6109 :
6110 198991 : HValue* HOptimizedGraphBuilder::BuildMonomorphicAccess(
6111 342011 : PropertyAccessInfo* info, HValue* object, HValue* checked_object,
6112 : HValue* value, BailoutId ast_id, BailoutId return_id,
6113 1118 : bool can_inline_accessor) {
6114 198991 : HObjectAccess access = HObjectAccess::ForMap(); // bogus default
6115 198991 : if (info->GetJSObjectFieldAccess(&access)) {
6116 : DCHECK(info->IsLoad());
6117 22451 : return New<HLoadNamedField>(object, checked_object, access);
6118 : }
6119 :
6120 188051 : if (info->name().is_identical_to(isolate()->factory()->prototype_string()) &&
6121 194136 : info->map()->IsJSFunctionMap() && info->map()->is_constructor()) {
6122 : DCHECK(!info->map()->has_non_instance_prototype());
6123 6085 : return New<HLoadFunctionPrototype>(checked_object);
6124 : }
6125 :
6126 : HValue* checked_holder = checked_object;
6127 175881 : if (info->has_holder()) {
6128 97326 : Handle<JSObject> prototype(JSObject::cast(info->map()->prototype()));
6129 48663 : checked_holder = BuildCheckPrototypeMaps(prototype, info->holder());
6130 : }
6131 :
6132 175881 : if (!info->IsFound()) {
6133 : DCHECK(info->IsLoad());
6134 2107 : return graph()->GetConstantUndefined();
6135 : }
6136 :
6137 173774 : if (info->IsData()) {
6138 62738 : if (info->IsLoad()) {
6139 52408 : return BuildLoadNamedField(info, checked_holder);
6140 : } else {
6141 10330 : return BuildStoreNamedField(info, checked_object, value);
6142 : }
6143 : }
6144 :
6145 111036 : if (info->IsTransition()) {
6146 : DCHECK(!info->IsLoad());
6147 10955 : return BuildStoreNamedField(info, checked_object, value);
6148 : }
6149 :
6150 100081 : if (info->IsAccessorConstant()) {
6151 : MaybeHandle<Name> maybe_name =
6152 : FunctionTemplateInfo::TryGetCachedPropertyName(isolate(),
6153 3319 : info->accessor());
6154 3319 : if (!maybe_name.is_null()) {
6155 4 : Handle<Name> name = maybe_name.ToHandleChecked();
6156 4 : PropertyAccessInfo cache_info(this, LOAD, info->map(), name);
6157 : // Load new target.
6158 4 : if (cache_info.CanAccessMonomorphic()) {
6159 4 : return BuildLoadNamedField(&cache_info, checked_object);
6160 : }
6161 : }
6162 :
6163 3315 : Push(checked_object);
6164 : int argument_count = 1;
6165 3315 : if (!info->IsLoad()) {
6166 : argument_count = 2;
6167 246 : Push(value);
6168 : }
6169 :
6170 6615 : if (info->accessor()->IsJSFunction() &&
6171 3300 : info->NeedsWrappingFor(Handle<JSFunction>::cast(info->accessor()))) {
6172 0 : HValue* function = Add<HConstant>(info->accessor());
6173 0 : PushArgumentsFromEnvironment(argument_count);
6174 : return NewCallFunction(function, argument_count, TailCallMode::kDisallow,
6175 : ConvertReceiverMode::kNotNullOrUndefined,
6176 0 : TailCallMode::kDisallow);
6177 3315 : } else if (FLAG_inline_accessors && can_inline_accessor) {
6178 : bool success = info->IsLoad()
6179 3069 : ? TryInlineGetter(info->accessor(), info->map(), ast_id, return_id)
6180 : : TryInlineSetter(
6181 6384 : info->accessor(), info->map(), ast_id, return_id, value);
6182 4433 : if (success || HasStackOverflow()) return NULL;
6183 : }
6184 :
6185 1118 : PushArgumentsFromEnvironment(argument_count);
6186 1118 : if (!info->accessor()->IsJSFunction()) {
6187 : Bailout(kInliningBailedOut);
6188 0 : return nullptr;
6189 : }
6190 : return NewCallConstantFunction(Handle<JSFunction>::cast(info->accessor()),
6191 : argument_count, TailCallMode::kDisallow,
6192 1118 : TailCallMode::kDisallow);
6193 : }
6194 :
6195 : DCHECK(info->IsDataConstant());
6196 96762 : if (info->IsLoad()) {
6197 96748 : return New<HConstant>(info->constant());
6198 : } else {
6199 14 : return New<HCheckValue>(value, Handle<JSFunction>::cast(info->constant()));
6200 : }
6201 : }
6202 :
6203 10166 : void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess(
6204 : PropertyAccessType access_type, Expression* expr, FeedbackSlot slot,
6205 : BailoutId ast_id, BailoutId return_id, HValue* object, HValue* value,
6206 29291 : 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 58820 : for (i = 0; i < maps->length() && count < kMaxLoadPolymorphism; ++i) {
6217 19286 : PropertyAccessInfo info(this, access_type, maps->at(i), name);
6218 19286 : if (info.IsStringType()) {
6219 35 : if (handled_string) continue;
6220 : handled_string = true;
6221 : }
6222 19286 : if (info.CanAccessMonomorphic()) {
6223 14897 : count++;
6224 14897 : if (info.IsNumberType()) {
6225 : handle_smi = true;
6226 42 : break;
6227 : }
6228 : }
6229 : }
6230 :
6231 10166 : 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 48654 : for (i = 0; i < maps->length() && count < kMaxLoadPolymorphism; ++i) {
6241 19244 : PropertyAccessInfo info(this, access_type, maps->at(i), name);
6242 19244 : if (info.IsStringType()) {
6243 4424 : if (handled_string) continue;
6244 : handled_string = true;
6245 : }
6246 19244 : if (!info.CanAccessMonomorphic()) continue;
6247 :
6248 14855 : if (count == 0) {
6249 50757 : join = graph()->CreateBasicBlock();
6250 6192 : if (handle_smi) {
6251 0 : HBasicBlock* empty_smi_block = graph()->CreateBasicBlock();
6252 0 : HBasicBlock* not_smi_block = graph()->CreateBasicBlock();
6253 0 : number_block = graph()->CreateBasicBlock();
6254 : smi_check = New<HIsSmiAndBranch>(
6255 0 : object, empty_smi_block, not_smi_block);
6256 0 : FinishCurrentBlock(smi_check);
6257 : GotoNoSimulate(empty_smi_block, number_block);
6258 : set_current_block(not_smi_block);
6259 : } else {
6260 6192 : BuildCheckHeapObject(object);
6261 : }
6262 : }
6263 14855 : ++count;
6264 14855 : HBasicBlock* if_true = graph()->CreateBasicBlock();
6265 14855 : HBasicBlock* if_false = graph()->CreateBasicBlock();
6266 : HUnaryControlInstruction* compare;
6267 :
6268 : HValue* dependency;
6269 14855 : if (info.IsNumberType()) {
6270 0 : Handle<Map> heap_number_map = isolate()->factory()->heap_number_map();
6271 0 : compare = New<HCompareMap>(object, heap_number_map, if_true, if_false);
6272 : dependency = smi_check;
6273 14855 : } else if (info.IsStringType()) {
6274 22 : compare = New<HIsStringAndBranch>(object, if_true, if_false);
6275 : dependency = compare;
6276 : } else {
6277 14833 : compare = New<HCompareMap>(object, info.map(), if_true, if_false);
6278 : dependency = compare;
6279 : }
6280 14855 : FinishCurrentBlock(compare);
6281 :
6282 14855 : 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 14855 : return_id, FLAG_polymorphic_inlining);
6292 :
6293 : HValue* result = NULL;
6294 14855 : switch (access_type) {
6295 : case LOAD:
6296 : result = access;
6297 9465 : break;
6298 : case STORE:
6299 : result = value;
6300 5390 : break;
6301 : }
6302 :
6303 14855 : if (access == NULL) {
6304 127 : if (HasStackOverflow()) return;
6305 : } else {
6306 14728 : if (access->IsInstruction()) {
6307 : HInstruction* instr = HInstruction::cast(access);
6308 14728 : if (!instr->IsLinked()) AddInstruction(instr);
6309 : }
6310 14728 : if (!ast_context()->IsEffect()) Push(result);
6311 : }
6312 :
6313 14855 : 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 10166 : if (count == maps->length() && FLAG_deoptimize_uncommon_cases) {
6321 : FinishExitWithHardDeoptimization(
6322 5891 : DeoptimizeReason::kUnknownMapInPolymorphicAccess);
6323 : } else {
6324 : HInstruction* instr =
6325 4275 : BuildNamedGeneric(access_type, expr, slot, object, name, value);
6326 4275 : AddInstruction(instr);
6327 4275 : if (!ast_context()->IsEffect()) Push(access_type == LOAD ? instr : value);
6328 :
6329 4275 : if (join != NULL) {
6330 : Goto(join);
6331 : } else {
6332 3974 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6333 7057 : if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
6334 : return;
6335 : }
6336 : }
6337 :
6338 : DCHECK(join != NULL);
6339 6192 : if (join->HasPredecessor()) {
6340 : join->SetJoinId(ast_id);
6341 : set_current_block(join);
6342 10449 : if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
6343 : } else {
6344 : set_current_block(NULL);
6345 : }
6346 : }
6347 :
6348 800964 : static bool ComputeReceiverTypes(Expression* expr, HValue* receiver,
6349 : SmallMapList** t,
6350 : HOptimizedGraphBuilder* builder) {
6351 865894 : Zone* zone = builder->zone();
6352 800964 : SmallMapList* maps = expr->GetReceiverTypes();
6353 800964 : *t = maps;
6354 800964 : bool monomorphic = expr->IsMonomorphic();
6355 800964 : if (maps != nullptr && receiver->HasMonomorphicJSObjectType()) {
6356 168886 : if (maps->length() > 0) {
6357 207972 : Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap();
6358 103986 : maps->FilterForPossibleTransitions(root_map);
6359 103986 : 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 64900 : Handle<Map> candidate_map = receiver->GetMonomorphicJSObjectMap();
6365 89802 : for (HInstruction* current = builder->current_block()->last();
6366 : current != nullptr; current = current->previous()) {
6367 171826 : if (current->IsBlockEntry()) break;
6368 84427 : 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 7208 : if (!current->IsStoreNamedField()) break;
6372 : HStoreNamedField* map_change = HStoreNamedField::cast(current);
6373 30 : if (!map_change->value()->IsConstant()) break;
6374 : HConstant* map_constant = HConstant::cast(map_change->value());
6375 30 : if (!map_constant->representation().IsTagged()) break;
6376 30 : Handle<Object> map = map_constant->handle(builder->isolate());
6377 30 : if (!map.is_identical_to(candidate_map)) break;
6378 : }
6379 77238 : 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 52336 : break;
6386 : }
6387 : }
6388 : }
6389 : }
6390 1097138 : return monomorphic && CanInlinePropertyAccess(maps->first());
6391 : }
6392 :
6393 :
6394 178002 : static bool AreStringTypes(SmallMapList* maps) {
6395 384396 : for (int i = 0; i < maps->length(); i++) {
6396 178425 : if (maps->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false;
6397 : }
6398 : return true;
6399 : }
6400 :
6401 130739 : void HOptimizedGraphBuilder::BuildStore(Expression* expr, Property* prop,
6402 : FeedbackSlot slot, BailoutId ast_id,
6403 : BailoutId return_id,
6404 210271 : bool is_uninitialized) {
6405 73202 : if (!prop->key()->IsPropertyName()) {
6406 : // Keyed store.
6407 : HValue* value = Pop();
6408 : HValue* key = Pop();
6409 : HValue* object = Pop();
6410 15665 : bool has_side_effects = false;
6411 : HValue* result =
6412 : HandleKeyedElementAccess(object, key, value, expr, slot, ast_id,
6413 15665 : return_id, STORE, &has_side_effects);
6414 15665 : if (has_side_effects) {
6415 15556 : if (!ast_context()->IsEffect()) Push(value);
6416 15556 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6417 15556 : if (!ast_context()->IsEffect()) Drop(1);
6418 : }
6419 15665 : if (result == NULL) return;
6420 15596 : return ast_context()->ReturnValue(value);
6421 : }
6422 :
6423 : // Named store.
6424 : HValue* value = Pop();
6425 : HValue* object = Pop();
6426 :
6427 115074 : 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 115074 : object, name, value, is_uninitialized);
6433 57537 : if (access == NULL) return;
6434 :
6435 54521 : if (!ast_context()->IsEffect()) Push(value);
6436 54521 : if (access->IsInstruction()) AddInstruction(HInstruction::cast(access));
6437 54521 : if (access->HasObservableSideEffects()) {
6438 54507 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6439 : }
6440 54521 : if (!ast_context()->IsEffect()) Drop(1);
6441 54521 : return ast_context()->ReturnValue(value);
6442 : }
6443 :
6444 :
6445 371772 : void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
6446 229192 : Property* prop = expr->target()->AsProperty();
6447 : DCHECK(prop != NULL);
6448 229162 : CHECK_ALIVE(VisitForValue(prop->obj()));
6449 71307 : if (!prop->key()->IsPropertyName()) {
6450 45611 : CHECK_ALIVE(VisitForValue(prop->key()));
6451 : }
6452 213887 : CHECK_ALIVE(VisitForValue(expr->value()));
6453 : BuildStore(expr, prop, expr->AssignmentSlot(), expr->id(),
6454 142562 : expr->AssignmentId(), expr->IsUninitialized());
6455 : }
6456 :
6457 10064 : HInstruction* HOptimizedGraphBuilder::InlineGlobalPropertyStore(
6458 : LookupIterator* it, HValue* value, BailoutId ast_id) {
6459 10064 : Handle<PropertyCell> cell = it->GetPropertyCell();
6460 14086 : top_info()->dependencies()->AssumePropertyCell(cell);
6461 : auto cell_type = it->property_details().cell_type();
6462 10064 : if (cell_type == PropertyCellType::kConstant ||
6463 : cell_type == PropertyCellType::kUndefined) {
6464 : Handle<Object> constant(cell->value(), isolate());
6465 2464 : if (value->IsConstant()) {
6466 : HConstant* c_value = HConstant::cast(value);
6467 2332 : if (!constant.is_identical_to(c_value->handle(isolate()))) {
6468 : Add<HDeoptimize>(DeoptimizeReason::kConstantGlobalVariableAssignment,
6469 921 : Deoptimizer::EAGER);
6470 : }
6471 : } else {
6472 1298 : HValue* c_constant = Add<HConstant>(constant);
6473 : IfBuilder builder(this);
6474 1298 : if (constant->IsNumber()) {
6475 779 : builder.If<HCompareNumericAndBranch>(value, c_constant, Token::EQ);
6476 : } else {
6477 519 : builder.If<HCompareObjectEqAndBranch>(value, c_constant);
6478 : }
6479 1298 : builder.Then();
6480 : builder.Else();
6481 : Add<HDeoptimize>(DeoptimizeReason::kConstantGlobalVariableAssignment,
6482 1298 : Deoptimizer::EAGER);
6483 1298 : builder.End();
6484 : }
6485 : }
6486 10064 : HConstant* cell_constant = Add<HConstant>(cell);
6487 10064 : auto access = HObjectAccess::ForPropertyCellValue();
6488 10064 : if (cell_type == PropertyCellType::kConstantType) {
6489 4182 : switch (cell->GetConstantType()) {
6490 : case PropertyCellConstantType::kSmi:
6491 3790 : access = access.WithRepresentation(Representation::Smi());
6492 3790 : 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 392 : if (!cell_value_map->is_stable()) {
6501 : Bailout(kUnstableConstantTypeHeapObject);
6502 : return nullptr;
6503 : }
6504 392 : top_info()->dependencies()->AssumeMapStable(cell_value_map);
6505 : // Now check that the new {value} is a HeapObject with the same map
6506 392 : Add<HCheckHeapObject>(value);
6507 392 : value = Add<HCheckMaps>(value, cell_value_map);
6508 392 : access = access.WithRepresentation(Representation::HeapObject());
6509 : break;
6510 : }
6511 : }
6512 : }
6513 10064 : HInstruction* instr = New<HStoreNamedField>(cell_constant, access, value);
6514 : instr->ClearChangesFlag(kInobjectFields);
6515 : instr->SetChangesFlag(kGlobalVars);
6516 10064 : 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.
6522 74721 : void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(Variable* var,
6523 : HValue* value,
6524 : FeedbackSlot slot,
6525 : BailoutId ast_id) {
6526 21202 : 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 21202 : if (ScriptContextTable::Lookup(script_contexts, var->name(), &lookup)) {
6534 18 : if (lookup.mode == CONST) {
6535 : return Bailout(kNonInitializerAssignmentToConst);
6536 : }
6537 : Handle<Context> script_context =
6538 16 : ScriptContextTable::GetContext(script_contexts, lookup.context_index);
6539 :
6540 : Handle<Object> current_value =
6541 22314 : 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 16 : if (current_value->IsTheHole(isolate())) {
6546 : return Bailout(kReferenceToUninitializedVariable);
6547 : }
6548 :
6549 : HStoreNamedField* instr = Add<HStoreNamedField>(
6550 : Add<HConstant>(script_context),
6551 15 : HObjectAccess::ForContextSlot(lookup.slot_index), value);
6552 : USE(instr);
6553 : DCHECK(instr->HasObservableSideEffects());
6554 15 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6555 15 : return;
6556 : }
6557 : }
6558 :
6559 21184 : LookupIterator it(global, var->name(), LookupIterator::OWN);
6560 21184 : if (CanInlineGlobalPropertyAccess(var, &it, STORE)) {
6561 10051 : HInstruction* instr = InlineGlobalPropertyStore(&it, value, ast_id);
6562 10051 : if (!instr) return;
6563 10051 : AddInstruction(instr);
6564 10051 : if (instr->HasObservableSideEffects()) {
6565 10051 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6566 : }
6567 : } else {
6568 : HValue* global_object = Add<HLoadNamedField>(
6569 : BuildGetNativeContext(), nullptr,
6570 11133 : HObjectAccess::ForContextSlot(Context::EXTENSION_INDEX));
6571 : Handle<FeedbackVector> vector =
6572 11133 : handle(current_feedback_vector(), isolate());
6573 11133 : HValue* name = Add<HConstant>(var->name());
6574 11133 : HValue* vector_value = Add<HConstant>(vector);
6575 11133 : HValue* slot_value = Add<HConstant>(vector->GetIndex(slot));
6576 : DCHECK(vector->IsStoreGlobalIC(slot));
6577 : DCHECK_EQ(vector->GetLanguageMode(slot), function_language_mode());
6578 : Callable callable = CodeFactory::StoreGlobalICInOptimizedCode(
6579 11133 : isolate(), function_language_mode());
6580 11133 : HValue* stub = Add<HConstant>(callable.code());
6581 11133 : HValue* values[] = {global_object, name, value, slot_value, vector_value};
6582 : HCallWithDescriptor* instr =
6583 : Add<HCallWithDescriptor>(Code::STORE_GLOBAL_IC, stub, 0,
6584 11133 : callable.descriptor(), ArrayVector(values));
6585 : USE(instr);
6586 : DCHECK(instr->HasObservableSideEffects());
6587 11133 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6588 : }
6589 : }
6590 :
6591 :
6592 110388 : void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
6593 : Expression* target = expr->target();
6594 54677 : VariableProxy* proxy = target->AsVariableProxy();
6595 993 : Property* prop = target->AsProperty();
6596 : DCHECK(proxy == NULL || prop == NULL);
6597 :
6598 : // We have a second position recorded in the FullCodeGenerator to have
6599 : // type feedback for the binary operation.
6600 : BinaryOperation* operation = expr->binary_operation();
6601 :
6602 27504 : if (proxy != NULL) {
6603 55115 : Variable* var = proxy->var();
6604 27173 : if (var->mode() == LET) {
6605 : return Bailout(kUnsupportedLetCompoundAssignment);
6606 : }
6607 :
6608 55339 : CHECK_ALIVE(VisitForValue(operation));
6609 :
6610 27035 : switch (var->location()) {
6611 : case VariableLocation::UNALLOCATED:
6612 : HandleGlobalVariableAssignment(var, Top(), expr->AssignmentSlot(),
6613 1900 : expr->AssignmentId());
6614 1900 : break;
6615 :
6616 : case VariableLocation::PARAMETER:
6617 : case VariableLocation::LOCAL:
6618 24404 : if (var->mode() == CONST) {
6619 : return Bailout(kNonInitializerAssignmentToConst);
6620 : }
6621 24354 : BindIfLive(var, Top());
6622 24354 : break;
6623 :
6624 : case VariableLocation::CONTEXT: {
6625 : // Bail out if we try to mutate a parameter value in a function
6626 : // using the arguments object. We do not (yet) correctly handle the
6627 : // arguments property of the function.
6628 731 : if (current_info()->scope()->arguments() != NULL) {
6629 : // Parameters will be allocated to context slots. We have no
6630 : // direct way to detect that the variable is a parameter so we do
6631 : // a linear search of the parameter variables.
6632 2 : int count = current_info()->scope()->num_parameters();
6633 4 : for (int i = 0; i < count; ++i) {
6634 4 : if (var == current_info()->scope()->parameter(i)) {
6635 : Bailout(kAssignmentToParameterFunctionUsesArgumentsObject);
6636 : }
6637 : }
6638 : }
6639 :
6640 : HStoreContextSlot::Mode mode;
6641 :
6642 731 : switch (var->mode()) {
6643 : case LET:
6644 : mode = HStoreContextSlot::kCheckDeoptimize;
6645 : break;
6646 : case CONST:
6647 555 : if (var->throw_on_const_assignment(function_language_mode())) {
6648 : return Bailout(kNonInitializerAssignmentToConst);
6649 : } else {
6650 12 : return ast_context()->ReturnValue(Pop());
6651 : }
6652 : default:
6653 : mode = HStoreContextSlot::kNoCheck;
6654 : }
6655 :
6656 176 : HValue* context = BuildContextChainWalk(var);
6657 : HStoreContextSlot* instr = Add<HStoreContextSlot>(
6658 176 : context, var->index(), mode, Top());
6659 176 : if (instr->HasObservableSideEffects()) {
6660 176 : Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
6661 : }
6662 : break;
6663 : }
6664 :
6665 : case VariableLocation::LOOKUP:
6666 : return Bailout(kCompoundAssignmentToLookupSlot);
6667 :
6668 : case VariableLocation::MODULE:
6669 0 : UNREACHABLE();
6670 : }
6671 52860 : return ast_context()->ReturnValue(Pop());
6672 :
6673 331 : } else if (prop != NULL) {
6674 993 : CHECK_ALIVE(VisitForValue(prop->obj()));
6675 : HValue* object = Top();
6676 : HValue* key = NULL;
6677 430 : if (!prop->key()->IsPropertyName() || prop->IsStringAccess()) {
6678 696 : CHECK_ALIVE(VisitForValue(prop->key()));
6679 : key = Top();
6680 : }
6681 :
6682 993 : CHECK_ALIVE(PushLoad(prop, object, key));
6683 :
6684 993 : CHECK_ALIVE(VisitForValue(expr->value()));
6685 : HValue* right = Pop();
6686 : HValue* left = Pop();
6687 :
6688 331 : Push(BuildBinaryOperation(operation, left, right, PUSH_BEFORE_SIMULATE));
6689 :
6690 : BuildStore(expr, prop, expr->AssignmentSlot(), expr->id(),
6691 662 : expr->AssignmentId(), expr->IsUninitialized());
6692 : } else {
6693 : return Bailout(kInvalidLhsInCompoundAssignment);
6694 : }
6695 : }
6696 :
6697 :
6698 2880048 : void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) {
6699 : DCHECK(!HasStackOverflow());
6700 : DCHECK(current_block() != NULL);
6701 : DCHECK(current_block()->HasPredecessor());
6702 :
6703 1157814 : VariableProxy* proxy = expr->target()->AsVariableProxy();
6704 628329 : Property* prop = expr->target()->AsProperty();
6705 : DCHECK(proxy == NULL || prop == NULL);
6706 :
6707 628329 : if (expr->is_compound()) {
6708 27504 : HandleCompoundAssignment(expr);
6709 27504 : return;
6710 : }
6711 :
6712 600825 : if (prop != NULL) {
6713 71340 : HandlePropertyAssignment(expr);
6714 529485 : } else if (proxy != NULL) {
6715 575966 : Variable* var = proxy->var();
6716 :
6717 529485 : if (var->mode() == CONST) {
6718 66799 : if (expr->op() != Token::INIT) {
6719 626 : if (var->throw_on_const_assignment(function_language_mode())) {
6720 : return Bailout(kNonInitializerAssignmentToConst);
6721 : } else {
6722 526653 : CHECK_ALIVE(VisitForValue(expr->value()));
6723 6 : return ast_context()->ReturnValue(Pop());
6724 : }
6725 : }
6726 : }
6727 :
6728 : // Handle the assignment.
6729 528859 : switch (var->location()) {
6730 : case VariableLocation::UNALLOCATED:
6731 46437 : CHECK_ALIVE(VisitForValue(expr->value()));
6732 : HandleGlobalVariableAssignment(var, Top(), expr->AssignmentSlot(),
6733 15475 : expr->AssignmentId());
6734 30950 : return ast_context()->ReturnValue(Pop());
6735 :
6736 : case VariableLocation::PARAMETER:
6737 : case VariableLocation::LOCAL: {
6738 : // Perform an initialization check for let declared variables
6739 : // or parameters.
6740 473749 : if (var->mode() == LET && expr->op() == Token::ASSIGN) {
6741 : HValue* env_value = environment()->Lookup(var);
6742 481 : if (env_value == graph()->GetConstantHole()) {
6743 : return Bailout(kAssignmentToLetVariableBeforeInitialization);
6744 : }
6745 : }
6746 : // We do not allow the arguments object to occur in a context where it
6747 : // may escape, but assignments to stack-allocated locals are
6748 : // permitted.
6749 1418628 : CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED));
6750 : HValue* value = Pop();
6751 471148 : BindIfLive(var, value);
6752 471148 : return ast_context()->ReturnValue(value);
6753 : }
6754 :
6755 : case VariableLocation::CONTEXT: {
6756 : // Bail out if we try to mutate a parameter value in a function using
6757 : // the arguments object. We do not (yet) correctly handle the
6758 : // arguments property of the function.
6759 39629 : if (current_info()->scope()->arguments() != NULL) {
6760 : // Parameters will rewrite to context slots. We have no direct way
6761 : // to detect that the variable is a parameter.
6762 17 : int count = current_info()->scope()->num_parameters();
6763 34 : for (int i = 0; i < count; ++i) {
6764 44 : if (var == current_info()->scope()->parameter(i)) {
6765 : return Bailout(kAssignmentToParameterInArgumentsObject);
6766 : }
6767 : }
6768 : }
6769 :
6770 118785 : CHECK_ALIVE(VisitForValue(expr->value()));
6771 : HStoreContextSlot::Mode mode;
6772 39537 : if (expr->op() == Token::ASSIGN) {
6773 6944 : switch (var->mode()) {
6774 : case LET:
6775 : mode = HStoreContextSlot::kCheckDeoptimize;
6776 : break;
6777 : case CONST:
6778 : // If we reached this point, the only possibility
6779 : // is a sloppy assignment to a function name.
6780 : DCHECK(function_language_mode() == SLOPPY &&
6781 : !var->throw_on_const_assignment(SLOPPY));
6782 0 : return ast_context()->ReturnValue(Pop());
6783 : default:
6784 : mode = HStoreContextSlot::kNoCheck;
6785 : }
6786 : } else {
6787 : DCHECK_EQ(Token::INIT, expr->op());
6788 : mode = HStoreContextSlot::kNoCheck;
6789 : }
6790 :
6791 39537 : HValue* context = BuildContextChainWalk(var);
6792 : HStoreContextSlot* instr = Add<HStoreContextSlot>(
6793 39537 : context, var->index(), mode, Top());
6794 39537 : if (instr->HasObservableSideEffects()) {
6795 39537 : Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
6796 : }
6797 79074 : return ast_context()->ReturnValue(Pop());
6798 : }
6799 :
6800 : case VariableLocation::LOOKUP:
6801 : return Bailout(kAssignmentToLOOKUPVariable);
6802 :
6803 : case VariableLocation::MODULE:
6804 0 : UNREACHABLE();
6805 : }
6806 : } else {
6807 : return Bailout(kInvalidLeftHandSideInAssignment);
6808 : }
6809 : }
6810 :
6811 0 : void HOptimizedGraphBuilder::VisitSuspend(Suspend* expr) {
6812 : // Generators are not optimized, so we should never get here.
6813 0 : UNREACHABLE();
6814 : }
6815 :
6816 :
6817 21266 : void HOptimizedGraphBuilder::VisitThrow(Throw* expr) {
6818 : DCHECK(!HasStackOverflow());
6819 : DCHECK(current_block() != NULL);
6820 : DCHECK(current_block()->HasPredecessor());
6821 7124 : if (!ast_context()->IsEffect()) {
6822 : // The parser turns invalid left-hand sides in assignments into throw
6823 : // statements, which may not be in effect contexts. We might still try
6824 : // to optimize such functions; bail out now if we do.
6825 : return Bailout(kInvalidLeftHandSideInAssignment);
6826 : }
6827 21213 : CHECK_ALIVE(VisitForValue(expr->exception()));
6828 :
6829 7071 : HValue* value = environment()->Pop();
6830 7071 : if (!is_tracking_positions()) SetSourcePosition(expr->position());
6831 7071 : Add<HPushArguments>(value);
6832 7071 : Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kThrow), 1);
6833 : Add<HSimulate>(expr->id());
6834 :
6835 : // If the throw definitely exits the function, we can finish with a dummy
6836 : // control flow at this point. This is not the case if the throw is inside
6837 : // an inlined function which may be replaced.
6838 7071 : if (call_context() == NULL) {
6839 4726 : FinishExitCurrentBlock(New<HAbnormalExit>());
6840 : }
6841 : }
6842 :
6843 :
6844 37970 : HInstruction* HGraphBuilder::AddLoadStringInstanceType(HValue* string) {
6845 37970 : if (string->IsConstant()) {
6846 : HConstant* c_string = HConstant::cast(string);
6847 11849 : if (c_string->HasStringValue()) {
6848 11849 : return Add<HConstant>(c_string->StringValue()->map()->instance_type());
6849 : }
6850 : }
6851 : return Add<HLoadNamedField>(
6852 : Add<HLoadNamedField>(string, nullptr, HObjectAccess::ForMap()), nullptr,
6853 26121 : HObjectAccess::ForMapInstanceType());
6854 : }
6855 :
6856 :
6857 62041 : HInstruction* HGraphBuilder::AddLoadStringLength(HValue* string) {
6858 62041 : return AddInstruction(BuildLoadStringLength(string));
6859 : }
6860 :
6861 :
6862 62041 : HInstruction* HGraphBuilder::BuildLoadStringLength(HValue* string) {
6863 62041 : if (string->IsConstant()) {
6864 : HConstant* c_string = HConstant::cast(string);
6865 23745 : if (c_string->HasStringValue()) {
6866 23745 : return New<HConstant>(c_string->StringValue()->length());
6867 : }
6868 : }
6869 : return New<HLoadNamedField>(string, nullptr,
6870 38296 : HObjectAccess::ForStringLength());
6871 : }
6872 :
6873 321543 : HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric(
6874 : PropertyAccessType access_type, Expression* expr, FeedbackSlot slot,
6875 : HValue* object, Handle<Name> name, HValue* value, bool is_uninitialized) {
6876 321543 : if (is_uninitialized) {
6877 : Add<HDeoptimize>(
6878 : DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess,
6879 505560 : Deoptimizer::SOFT);
6880 : }
6881 : Handle<FeedbackVector> vector(current_feedback_vector(), isolate());
6882 :
6883 321543 : HValue* key = Add<HConstant>(name);
6884 321543 : HValue* vector_value = Add<HConstant>(vector);
6885 321543 : HValue* slot_value = Add<HConstant>(vector->GetIndex(slot));
6886 :
6887 321543 : if (access_type == LOAD) {
6888 256790 : HValue* values[] = {object, key, slot_value, vector_value};
6889 513579 : if (!expr->AsProperty()->key()->IsPropertyName()) {
6890 : DCHECK(vector->IsKeyedLoadIC(slot));
6891 : // It's possible that a keyed load of a constant string was converted
6892 : // to a named load. Here, at the last minute, we need to make sure to
6893 : // use a generic Keyed Load if we are using the type vector, because
6894 : // it has to share information with full code.
6895 126 : Callable callable = CodeFactory::KeyedLoadICInOptimizedCode(isolate());
6896 126 : HValue* stub = Add<HConstant>(callable.code());
6897 : HCallWithDescriptor* result =
6898 : New<HCallWithDescriptor>(Code::KEYED_LOAD_IC, stub, 0,
6899 126 : callable.descriptor(), ArrayVector(values));
6900 : return result;
6901 : }
6902 : DCHECK(vector->IsLoadIC(slot));
6903 256664 : Callable callable = CodeFactory::LoadICInOptimizedCode(isolate());
6904 256663 : HValue* stub = Add<HConstant>(callable.code());
6905 : HCallWithDescriptor* result = New<HCallWithDescriptor>(
6906 256664 : Code::LOAD_IC, stub, 0, callable.descriptor(), ArrayVector(values));
6907 : return result;
6908 :
6909 : } else {
6910 64753 : HValue* values[] = {object, key, value, slot_value, vector_value};
6911 64753 : if (vector->IsKeyedStoreIC(slot)) {
6912 : // It's possible that a keyed store of a constant string was converted
6913 : // to a named store. Here, at the last minute, we need to make sure to
6914 : // use a generic Keyed Store if we are using the type vector, because
6915 : // it has to share information with full code.
6916 : DCHECK_EQ(vector->GetLanguageMode(slot), function_language_mode());
6917 : Callable callable = CodeFactory::KeyedStoreICInOptimizedCode(
6918 171 : isolate(), function_language_mode());
6919 171 : HValue* stub = Add<HConstant>(callable.code());
6920 : HCallWithDescriptor* result =
6921 : New<HCallWithDescriptor>(Code::KEYED_STORE_IC, stub, 0,
6922 171 : callable.descriptor(), ArrayVector(values));
6923 : return result;
6924 : }
6925 : HCallWithDescriptor* result;
6926 64582 : if (vector->IsStoreOwnIC(slot)) {
6927 18742 : Callable callable = CodeFactory::StoreOwnICInOptimizedCode(isolate());
6928 18742 : HValue* stub = Add<HConstant>(callable.code());
6929 : result = New<HCallWithDescriptor>(
6930 18742 : Code::STORE_IC, stub, 0, callable.descriptor(), ArrayVector(values));
6931 : } else {
6932 : DCHECK(vector->IsStoreIC(slot));
6933 : DCHECK_EQ(vector->GetLanguageMode(slot), function_language_mode());
6934 : Callable callable = CodeFactory::StoreICInOptimizedCode(
6935 45840 : isolate(), function_language_mode());
6936 45840 : HValue* stub = Add<HConstant>(callable.code());
6937 : result = New<HCallWithDescriptor>(
6938 45840 : Code::STORE_IC, stub, 0, callable.descriptor(), ArrayVector(values));
6939 : }
6940 64582 : return result;
6941 : }
6942 : }
6943 :
6944 95519 : HInstruction* HOptimizedGraphBuilder::BuildKeyedGeneric(
6945 : PropertyAccessType access_type, Expression* expr, FeedbackSlot slot,
6946 : HValue* object, HValue* key, HValue* value) {
6947 191038 : Handle<FeedbackVector> vector(current_feedback_vector(), isolate());
6948 95519 : HValue* vector_value = Add<HConstant>(vector);
6949 95519 : HValue* slot_value = Add<HConstant>(vector->GetIndex(slot));
6950 :
6951 95519 : if (access_type == LOAD) {
6952 72441 : HValue* values[] = {object, key, slot_value, vector_value};
6953 :
6954 72441 : Callable callable = CodeFactory::KeyedLoadICInOptimizedCode(isolate());
6955 72441 : HValue* stub = Add<HConstant>(callable.code());
6956 : HCallWithDescriptor* result =
6957 : New<HCallWithDescriptor>(Code::KEYED_LOAD_IC, stub, 0,
6958 72441 : callable.descriptor(), ArrayVector(values));
6959 : return result;
6960 : } else {
6961 23078 : HValue* values[] = {object, key, value, slot_value, vector_value};
6962 :
6963 : Callable callable = CodeFactory::KeyedStoreICInOptimizedCode(
6964 23078 : isolate(), function_language_mode());
6965 23078 : HValue* stub = Add<HConstant>(callable.code());
6966 : HCallWithDescriptor* result =
6967 : New<HCallWithDescriptor>(Code::KEYED_STORE_IC, stub, 0,
6968 23078 : callable.descriptor(), ArrayVector(values));
6969 : return result;
6970 : }
6971 : }
6972 :
6973 :
6974 24602 : LoadKeyedHoleMode HOptimizedGraphBuilder::BuildKeyedHoleMode(Handle<Map> map) {
6975 : // Loads from a "stock" fast holey double arrays can elide the hole check.
6976 : // Loads from a "stock" fast holey array can convert the hole to undefined
6977 : // with impunity.
6978 : LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE;
6979 : bool holey_double_elements =
6980 88651 : *map == isolate()->get_initial_js_array_map(FAST_HOLEY_DOUBLE_ELEMENTS);
6981 : bool holey_elements =
6982 24602 : *map == isolate()->get_initial_js_array_map(FAST_HOLEY_ELEMENTS);
6983 28362 : if ((holey_double_elements || holey_elements) &&
6984 3760 : isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
6985 : load_mode =
6986 3695 : holey_double_elements ? ALLOW_RETURN_HOLE : CONVERT_HOLE_TO_UNDEFINED;
6987 :
6988 : Handle<JSObject> prototype(JSObject::cast(map->prototype()), isolate());
6989 3695 : Handle<JSObject> object_prototype = isolate()->initial_object_prototype();
6990 3695 : BuildCheckPrototypeMaps(prototype, object_prototype);
6991 3695 : graph()->MarkDependsOnEmptyArrayProtoElements();
6992 : }
6993 24602 : return load_mode;
6994 : }
6995 :
6996 :
6997 21913 : HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess(
6998 : HValue* object,
6999 : HValue* key,
7000 : HValue* val,
7001 : HValue* dependency,
7002 : Handle<Map> map,
7003 : PropertyAccessType access_type,
7004 : KeyedAccessStoreMode store_mode) {
7005 21913 : HCheckMaps* checked_object = Add<HCheckMaps>(object, map, dependency);
7006 :
7007 26064 : if (access_type == STORE && map->prototype()->IsJSObject()) {
7008 : // monomorphic stores need a prototype chain check because shape
7009 : // changes could allow callbacks on elements in the chain that
7010 : // aren't compatible with monomorphic keyed stores.
7011 4056 : PrototypeIterator iter(map);
7012 : JSObject* holder = NULL;
7013 17676 : while (!iter.IsAtEnd()) {
7014 : // JSProxies can't occur here because we wouldn't have installed a
7015 : // non-generic IC if there were any.
7016 : holder = *PrototypeIterator::GetCurrent<JSObject>(iter);
7017 9564 : iter.Advance();
7018 : }
7019 : DCHECK(holder && holder->IsJSObject());
7020 :
7021 : BuildCheckPrototypeMaps(handle(JSObject::cast(map->prototype())),
7022 4056 : Handle<JSObject>(holder));
7023 : }
7024 :
7025 21913 : LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map);
7026 : return BuildUncheckedMonomorphicElementAccess(
7027 : checked_object, key, val,
7028 : map->instance_type() == JS_ARRAY_TYPE,
7029 : map->elements_kind(), access_type,
7030 21913 : load_mode, store_mode);
7031 : }
7032 :
7033 :
7034 32532 : static bool CanInlineElementAccess(Handle<Map> map) {
7035 32181 : return map->IsJSObjectMap() &&
7036 36217 : (map->has_fast_elements() || map->has_fixed_typed_array_elements()) &&
7037 64444 : !map->has_indexed_interceptor() && !map->is_access_check_needed();
7038 : }
7039 :
7040 :
7041 1827 : HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad(
7042 : HValue* object,
7043 : HValue* key,
7044 : HValue* val,
7045 : SmallMapList* maps) {
7046 : // For polymorphic loads of similar elements kinds (i.e. all tagged or all
7047 : // double), always use the "worst case" code without a transition. This is
7048 : // much faster than transitioning the elements to the worst case, trading a
7049 : // HTransitionElements for a HCheckMaps, and avoiding mutation of the array.
7050 : bool has_double_maps = false;
7051 : bool has_smi_or_object_maps = false;
7052 : bool has_js_array_access = false;
7053 : bool has_non_js_array_access = false;
7054 : bool has_seen_holey_elements = false;
7055 : Handle<Map> most_general_consolidated_map;
7056 10120 : for (int i = 0; i < maps->length(); ++i) {
7057 : Handle<Map> map = maps->at(i);
7058 3819 : if (!CanInlineElementAccess(map)) return NULL;
7059 : // Don't allow mixing of JSArrays with JSObjects.
7060 3686 : if (map->instance_type() == JS_ARRAY_TYPE) {
7061 3526 : if (has_non_js_array_access) return NULL;
7062 : has_js_array_access = true;
7063 160 : } else if (has_js_array_access) {
7064 : return NULL;
7065 : } else {
7066 : has_non_js_array_access = true;
7067 : }
7068 : // Don't allow mixed, incompatible elements kinds.
7069 3567 : if (map->has_fast_double_elements()) {
7070 374 : if (has_smi_or_object_maps) return NULL;
7071 : has_double_maps = true;
7072 3193 : } else if (map->has_fast_smi_or_object_elements()) {
7073 3167 : if (has_double_maps) return NULL;
7074 : has_smi_or_object_maps = true;
7075 : } else {
7076 : return NULL;
7077 : }
7078 : // Remember if we've ever seen holey elements.
7079 3233 : if (IsHoleyElementsKind(map->elements_kind())) {
7080 : has_seen_holey_elements = true;
7081 : }
7082 : // Remember the most general elements kind, the code for its load will
7083 : // properly handle all of the more specific cases.
7084 4787 : if ((i == 0) || IsMoreGeneralElementsKindTransition(
7085 : most_general_consolidated_map->elements_kind(),
7086 1554 : map->elements_kind())) {
7087 : most_general_consolidated_map = map;
7088 : }
7089 : }
7090 1241 : if (!has_double_maps && !has_smi_or_object_maps) return NULL;
7091 :
7092 3282 : HCheckMaps* checked_object = Add<HCheckMaps>(object, maps);
7093 : // FAST_ELEMENTS is considered more general than FAST_HOLEY_SMI_ELEMENTS.
7094 : // If we've seen both, the consolidated load must use FAST_HOLEY_ELEMENTS.
7095 : ElementsKind consolidated_elements_kind = has_seen_holey_elements
7096 : ? GetHoleyElementsKind(most_general_consolidated_map->elements_kind())
7097 1241 : : most_general_consolidated_map->elements_kind();
7098 : LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE;
7099 1241 : if (has_seen_holey_elements) {
7100 : // Make sure that all of the maps we are handling have the initial array
7101 : // prototype.
7102 : bool saw_non_array_prototype = false;
7103 1961 : for (int i = 0; i < maps->length(); ++i) {
7104 : Handle<Map> map = maps->at(i);
7105 2670 : if (map->prototype() != *isolate()->initial_array_prototype()) {
7106 : // We can't guarantee that loading the hole is safe. The prototype may
7107 : // have an element at this position.
7108 : saw_non_array_prototype = true;
7109 : break;
7110 : }
7111 : }
7112 :
7113 1105 : if (!saw_non_array_prototype) {
7114 : Handle<Map> holey_map = handle(
7115 198 : isolate()->get_initial_js_array_map(consolidated_elements_kind));
7116 198 : load_mode = BuildKeyedHoleMode(holey_map);
7117 198 : if (load_mode != NEVER_RETURN_HOLE) {
7118 1006 : for (int i = 0; i < maps->length(); ++i) {
7119 : Handle<Map> map = maps->at(i);
7120 : // The prototype check was already done for the holey map in
7121 : // BuildKeyedHoleMode.
7122 408 : if (!map.is_identical_to(holey_map)) {
7123 : Handle<JSObject> prototype(JSObject::cast(map->prototype()),
7124 : isolate());
7125 : Handle<JSObject> object_prototype =
7126 254 : isolate()->initial_object_prototype();
7127 254 : BuildCheckPrototypeMaps(prototype, object_prototype);
7128 : }
7129 : }
7130 : }
7131 : }
7132 : }
7133 : HInstruction* instr = BuildUncheckedMonomorphicElementAccess(
7134 : checked_object, key, val,
7135 : most_general_consolidated_map->instance_type() == JS_ARRAY_TYPE,
7136 1241 : consolidated_elements_kind, LOAD, load_mode, STANDARD_STORE);
7137 1241 : return instr;
7138 : }
7139 :
7140 3110 : HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
7141 : Expression* expr, FeedbackSlot slot, HValue* object, HValue* key,
7142 : HValue* val, SmallMapList* maps, PropertyAccessType access_type,
7143 : KeyedAccessStoreMode store_mode, bool* has_side_effects) {
7144 3110 : *has_side_effects = false;
7145 9473 : BuildCheckHeapObject(object);
7146 :
7147 3110 : if (access_type == LOAD) {
7148 : HInstruction* consolidated_load =
7149 1827 : TryBuildConsolidatedElementLoad(object, key, val, maps);
7150 1827 : if (consolidated_load != NULL) {
7151 1241 : *has_side_effects |= consolidated_load->HasObservableSideEffects();
7152 1241 : return consolidated_load;
7153 : }
7154 : }
7155 :
7156 : // Elements_kind transition support.
7157 : MapHandleList transition_target(maps->length());
7158 : // Collect possible transition targets.
7159 : MapHandleList possible_transitioned_maps(maps->length());
7160 11722 : for (int i = 0; i < maps->length(); ++i) {
7161 4000 : Handle<Map> map = maps->at(i);
7162 : // Loads from strings or loads with a mix of string and non-string maps
7163 : // shouldn't be handled polymorphically.
7164 : DCHECK(access_type != LOAD || !map->IsStringMap());
7165 : ElementsKind elements_kind = map->elements_kind();
7166 7783 : if (CanInlineElementAccess(map) && IsFastElementsKind(elements_kind) &&
7167 : elements_kind != GetInitialFastElementsKind()) {
7168 2634 : possible_transitioned_maps.Add(map);
7169 : }
7170 4000 : if (IsSloppyArgumentsElementsKind(elements_kind)) {
7171 : HInstruction* result =
7172 8 : BuildKeyedGeneric(access_type, expr, slot, object, key, val);
7173 8 : *has_side_effects = result->HasObservableSideEffects();
7174 8 : return AddInstruction(result);
7175 : }
7176 : }
7177 : // Get transition target for each map (NULL == no transition).
7178 9833 : for (int i = 0; i < maps->length(); ++i) {
7179 : Handle<Map> map = maps->at(i);
7180 : Map* transitioned_map =
7181 3986 : map->FindElementsKindTransitionedMap(&possible_transitioned_maps);
7182 3986 : if (transitioned_map != nullptr) {
7183 : DCHECK(!map->is_stable());
7184 808 : transition_target.Add(handle(transitioned_map));
7185 : } else {
7186 3178 : transition_target.Add(Handle<Map>());
7187 : }
7188 : }
7189 :
7190 : MapHandleList untransitionable_maps(maps->length());
7191 : HTransitionElementsKind* transition = NULL;
7192 11694 : for (int i = 0; i < maps->length(); ++i) {
7193 3986 : Handle<Map> map = maps->at(i);
7194 : DCHECK(map->IsMap());
7195 3986 : if (!transition_target.at(i).is_null()) {
7196 : DCHECK(Map::IsValidElementsTransition(
7197 : map->elements_kind(),
7198 : transition_target.at(i)->elements_kind()));
7199 : transition = Add<HTransitionElementsKind>(object, map,
7200 808 : transition_target.at(i));
7201 : } else {
7202 3178 : untransitionable_maps.Add(map);
7203 : }
7204 : }
7205 :
7206 : // If only one map is left after transitioning, handle this case
7207 : // monomorphically.
7208 : DCHECK(untransitionable_maps.length() >= 1);
7209 1861 : if (untransitionable_maps.length() == 1) {
7210 618 : Handle<Map> untransitionable_map = untransitionable_maps[0];
7211 : HInstruction* instr = NULL;
7212 618 : if (!CanInlineElementAccess(untransitionable_map)) {
7213 : instr = AddInstruction(
7214 134 : BuildKeyedGeneric(access_type, expr, slot, object, key, val));
7215 : } else {
7216 : instr = BuildMonomorphicElementAccess(
7217 : object, key, val, transition, untransitionable_map, access_type,
7218 484 : store_mode);
7219 : }
7220 618 : *has_side_effects |= instr->HasObservableSideEffects();
7221 618 : return access_type == STORE ? val : instr;
7222 : }
7223 :
7224 1243 : HBasicBlock* join = graph()->CreateBasicBlock();
7225 :
7226 3803 : for (int i = 0; i < untransitionable_maps.length(); ++i) {
7227 5120 : Handle<Map> map = untransitionable_maps[i];
7228 : ElementsKind elements_kind = map->elements_kind();
7229 2560 : HBasicBlock* this_map = graph()->CreateBasicBlock();
7230 2560 : HBasicBlock* other_map = graph()->CreateBasicBlock();
7231 : HCompareMap* mapcompare =
7232 2560 : New<HCompareMap>(object, map, this_map, other_map);
7233 2560 : FinishCurrentBlock(mapcompare);
7234 :
7235 : set_current_block(this_map);
7236 : HInstruction* access = NULL;
7237 2560 : if (!CanInlineElementAccess(map)) {
7238 : access = AddInstruction(
7239 69 : BuildKeyedGeneric(access_type, expr, slot, object, key, val));
7240 : } else {
7241 : DCHECK(IsFastElementsKind(elements_kind) ||
7242 : IsFixedTypedArrayElementsKind(elements_kind));
7243 2491 : LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map);
7244 : // Happily, mapcompare is a checked object.
7245 : access = BuildUncheckedMonomorphicElementAccess(
7246 : mapcompare, key, val,
7247 : map->instance_type() == JS_ARRAY_TYPE,
7248 : elements_kind, access_type,
7249 : load_mode,
7250 2491 : store_mode);
7251 : }
7252 2560 : *has_side_effects |= access->HasObservableSideEffects();
7253 : // The caller will use has_side_effects and add a correct Simulate.
7254 : access->SetFlag(HValue::kHasNoObservableSideEffects);
7255 2560 : if (access_type == LOAD) {
7256 364 : Push(access);
7257 : }
7258 : NoObservableSideEffectsScope scope(this);
7259 : GotoNoSimulate(join);
7260 : set_current_block(other_map);
7261 : }
7262 :
7263 : // Ensure that we visited at least one map above that goes to join. This is
7264 : // necessary because FinishExitWithHardDeoptimization does an AbnormalExit
7265 : // rather than joining the join block. If this becomes an issue, insert a
7266 : // generic access in the case length() == 0.
7267 : DCHECK(join->predecessors()->length() > 0);
7268 : // Deopt if none of the cases matched.
7269 : NoObservableSideEffectsScope scope(this);
7270 : FinishExitWithHardDeoptimization(
7271 1243 : DeoptimizeReason::kUnknownMapInPolymorphicElementAccess);
7272 : set_current_block(join);
7273 1243 : return access_type == STORE ? val : Pop();
7274 : }
7275 :
7276 107851 : HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
7277 : HValue* obj, HValue* key, HValue* val, Expression* expr, FeedbackSlot slot,
7278 : BailoutId ast_id, BailoutId return_id, PropertyAccessType access_type,
7279 : bool* has_side_effects) {
7280 : // A keyed name access with type feedback may contain the name.
7281 122577 : Handle<FeedbackVector> vector = handle(current_feedback_vector(), isolate());
7282 : HValue* expected_key = key;
7283 215702 : if (!key->ActualValue()->IsConstant()) {
7284 : Name* name = nullptr;
7285 93552 : if (access_type == LOAD) {
7286 : KeyedLoadICNexus nexus(vector, slot);
7287 81014 : name = nexus.FindFirstName();
7288 : } else {
7289 : KeyedStoreICNexus nexus(vector, slot);
7290 12538 : name = nexus.FindFirstName();
7291 : }
7292 93552 : if (name != nullptr) {
7293 : Handle<Name> handle_name(name);
7294 426 : expected_key = Add<HConstant>(handle_name);
7295 : // We need a check against the key.
7296 : bool in_new_space = isolate()->heap()->InNewSpace(*handle_name);
7297 426 : Unique<Name> unique_name = Unique<Name>::CreateUninitialized(handle_name);
7298 426 : Add<HCheckValue>(key, unique_name, in_new_space);
7299 : }
7300 : }
7301 215702 : if (expected_key->ActualValue()->IsConstant()) {
7302 : Handle<Object> constant =
7303 14725 : HConstant::cast(expected_key->ActualValue())->handle(isolate());
7304 : uint32_t array_index;
7305 15287 : if ((constant->IsString() &&
7306 29481 : !Handle<String>::cast(constant)->AsArrayIndex(&array_index)) ||
7307 : constant->IsSymbol()) {
7308 809 : if (!constant->IsUniqueName()) {
7309 : constant = isolate()->factory()->InternalizeString(
7310 1 : Handle<String>::cast(constant));
7311 : }
7312 : HValue* access =
7313 : BuildNamedAccess(access_type, ast_id, return_id, expr, slot, obj,
7314 809 : Handle<Name>::cast(constant), val, false);
7315 2207 : if (access == NULL || access->IsPhi() ||
7316 : HInstruction::cast(access)->IsLinked()) {
7317 259 : *has_side_effects = false;
7318 : } else {
7319 : HInstruction* instr = HInstruction::cast(access);
7320 550 : AddInstruction(instr);
7321 550 : *has_side_effects = instr->HasObservableSideEffects();
7322 : }
7323 809 : return access;
7324 : }
7325 : }
7326 :
7327 : DCHECK(!expr->IsPropertyName());
7328 : HInstruction* instr = NULL;
7329 :
7330 : SmallMapList* maps;
7331 107042 : bool monomorphic = ComputeReceiverTypes(expr, obj, &maps, this);
7332 :
7333 : bool force_generic = false;
7334 107042 : if (expr->GetKeyType() == PROPERTY) {
7335 : // Non-Generic accesses assume that elements are being accessed, and will
7336 : // deopt for non-index keys, which the IC knows will occur.
7337 : // TODO(jkummerow): Consider adding proper support for property accesses.
7338 : force_generic = true;
7339 : monomorphic = false;
7340 207396 : } else if (access_type == STORE &&
7341 22344 : (monomorphic || (maps != NULL && !maps->is_empty()))) {
7342 : // Stores can't be mono/polymorphic if their prototype chain has dictionary
7343 : // elements. However a receiver map that has dictionary elements itself
7344 : // should be left to normal mono/poly behavior (the other maps may benefit
7345 : // from highly optimized stores).
7346 18531 : for (int i = 0; i < maps->length(); i++) {
7347 : Handle<Map> current_map = maps->at(i);
7348 6637 : if (current_map->DictionaryElementsInPrototypeChainOnly()) {
7349 : force_generic = true;
7350 : monomorphic = false;
7351 : break;
7352 : }
7353 : }
7354 267791 : } else if (access_type == LOAD && !monomorphic &&
7355 141962 : (maps != NULL && !maps->is_empty())) {
7356 : // Polymorphic loads have to go generic if any of the maps are strings.
7357 : // If some, but not all of the maps are strings, we should go generic
7358 : // because polymorphic access wants to key on ElementsKind and isn't
7359 : // compatible with strings.
7360 9616 : for (int i = 0; i < maps->length(); i++) {
7361 : Handle<Map> current_map = maps->at(i);
7362 3897 : if (current_map->IsStringMap()) {
7363 : force_generic = true;
7364 : break;
7365 : }
7366 : }
7367 : }
7368 :
7369 107042 : if (monomorphic) {
7370 43070 : Handle<Map> map = maps->first();
7371 21535 : if (!CanInlineElementAccess(map)) {
7372 : instr = AddInstruction(
7373 106 : BuildKeyedGeneric(access_type, expr, slot, obj, key, val));
7374 : } else {
7375 21429 : BuildCheckHeapObject(obj);
7376 : instr = BuildMonomorphicElementAccess(
7377 21429 : obj, key, val, NULL, map, access_type, expr->GetStoreMode());
7378 : }
7379 167647 : } else if (!force_generic && (maps != NULL && !maps->is_empty())) {
7380 : return HandlePolymorphicElementAccess(expr, slot, obj, key, val, maps,
7381 : access_type, expr->GetStoreMode(),
7382 3110 : has_side_effects);
7383 : } else {
7384 82397 : if (access_type == STORE) {
7385 20225 : if (expr->IsAssignment() &&
7386 20102 : expr->AsAssignment()->HasNoTypeInformation()) {
7387 : Add<HDeoptimize>(
7388 : DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess,
7389 9450 : Deoptimizer::SOFT);
7390 : }
7391 : } else {
7392 144446 : if (expr->AsProperty()->HasNoTypeInformation()) {
7393 : Add<HDeoptimize>(
7394 : DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess,
7395 67193 : Deoptimizer::SOFT);
7396 : }
7397 : }
7398 : instr = AddInstruction(
7399 82397 : BuildKeyedGeneric(access_type, expr, slot, obj, key, val));
7400 : }
7401 103932 : *has_side_effects = instr->HasObservableSideEffects();
7402 103932 : return instr;
7403 : }
7404 :
7405 :
7406 571 : void HOptimizedGraphBuilder::EnsureArgumentsArePushedForAccess() {
7407 : // Outermost function already has arguments on the stack.
7408 340 : if (function_state()->outer() == NULL) return;
7409 :
7410 340 : if (function_state()->arguments_pushed()) return;
7411 :
7412 : // Push arguments when entering inlined function.
7413 462 : HEnterInlined* entry = function_state()->entry();
7414 : entry->set_arguments_pushed();
7415 :
7416 : HArgumentsObject* arguments = entry->arguments_object();
7417 : const ZoneList<HValue*>* arguments_values = arguments->arguments_values();
7418 :
7419 : HInstruction* insert_after = entry;
7420 1958 : for (int i = 0; i < arguments_values->length(); i++) {
7421 1727 : HValue* argument = arguments_values->at(i);
7422 748 : HInstruction* push_argument = New<HPushArguments>(argument);
7423 748 : push_argument->InsertAfter(insert_after);
7424 : insert_after = push_argument;
7425 : }
7426 :
7427 231 : HArgumentsElements* arguments_elements = New<HArgumentsElements>(true);
7428 : arguments_elements->ClearFlag(HValue::kUseGVN);
7429 231 : arguments_elements->InsertAfter(insert_after);
7430 : function_state()->set_arguments_elements(arguments_elements);
7431 : }
7432 :
7433 751 : bool HOptimizedGraphBuilder::IsAnyParameterContextAllocated() {
7434 751 : int count = current_info()->scope()->num_parameters();
7435 2121 : for (int i = 0; i < count; ++i) {
7436 4221 : if (current_info()->scope()->parameter(i)->location() ==
7437 : VariableLocation::CONTEXT) {
7438 : return true;
7439 : }
7440 : }
7441 : return false;
7442 : }
7443 :
7444 323331 : bool HOptimizedGraphBuilder::TryArgumentsAccess(Property* expr) {
7445 596320 : VariableProxy* proxy = expr->obj()->AsVariableProxy();
7446 313753 : if (proxy == NULL) return false;
7447 282567 : if (!proxy->var()->IsStackAllocated()) return false;
7448 448625 : if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) {
7449 : return false;
7450 : }
7451 :
7452 : HInstruction* result = NULL;
7453 1462 : if (expr->key()->IsPropertyName()) {
7454 1408 : Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
7455 704 : if (!String::Equals(name, isolate()->factory()->length_string())) {
7456 7 : return false;
7457 : }
7458 :
7459 : // Make sure we visit the arguments object so that the liveness analysis
7460 : // still records the access.
7461 2091 : CHECK_ALIVE_OR_RETURN(VisitForValue(expr->obj(), ARGUMENTS_ALLOWED), true);
7462 : Drop(1);
7463 :
7464 697 : if (function_state()->outer() == NULL) {
7465 447 : HInstruction* elements = Add<HArgumentsElements>(false);
7466 447 : result = New<HArgumentsLength>(elements);
7467 : } else {
7468 : // Number of arguments without receiver.
7469 : int argument_count = environment()->
7470 250 : arguments_environment()->parameter_count() - 1;
7471 250 : result = New<HConstant>(argument_count);
7472 : }
7473 : } else {
7474 : // We need to take into account the KEYED_LOAD_IC feedback to guard the
7475 : // HBoundsCheck instructions below.
7476 1059 : if (!expr->IsMonomorphic() && !expr->IsUninitialized()) return false;
7477 751 : if (IsAnyParameterContextAllocated()) return false;
7478 2142 : CHECK_ALIVE_OR_RETURN(VisitForValue(expr->obj(), ARGUMENTS_ALLOWED), true);
7479 2142 : CHECK_ALIVE_OR_RETURN(VisitForValue(expr->key()), true);
7480 : HValue* key = Pop();
7481 : Drop(1); // Arguments object.
7482 714 : if (function_state()->outer() == NULL) {
7483 374 : HInstruction* elements = Add<HArgumentsElements>(false);
7484 374 : HInstruction* length = Add<HArgumentsLength>(elements);
7485 374 : HInstruction* checked_key = Add<HBoundsCheck>(key, length);
7486 374 : result = New<HAccessArgumentsAt>(elements, length, checked_key);
7487 : } else {
7488 340 : EnsureArgumentsArePushedForAccess();
7489 :
7490 : // Number of arguments without receiver.
7491 340 : HInstruction* elements = function_state()->arguments_elements();
7492 : int argument_count = environment()->
7493 340 : arguments_environment()->parameter_count() - 1;
7494 340 : HInstruction* length = Add<HConstant>(argument_count);
7495 340 : HInstruction* checked_key = Add<HBoundsCheck>(key, length);
7496 340 : result = New<HAccessArgumentsAt>(elements, length, checked_key);
7497 : }
7498 : }
7499 2822 : ast_context()->ReturnInstruction(result, expr->id());
7500 1411 : return true;
7501 : }
7502 :
7503 486255 : HValue* HOptimizedGraphBuilder::BuildNamedAccess(
7504 : PropertyAccessType access, BailoutId ast_id, BailoutId return_id,
7505 : Expression* expr, FeedbackSlot slot, HValue* object, Handle<Name> name,
7506 : HValue* value, bool is_uninitialized) {
7507 : SmallMapList* maps;
7508 486255 : ComputeReceiverTypes(expr, object, &maps, this);
7509 : DCHECK(maps != NULL);
7510 :
7511 : // Check for special case: Access via a single map to the global proxy
7512 : // can also be handled monomorphically.
7513 972510 : if (maps->length() > 0) {
7514 : Handle<Object> map_constructor =
7515 376648 : handle(maps->first()->GetConstructor(), isolate());
7516 188324 : if (map_constructor->IsJSFunction()) {
7517 : Handle<Context> map_context =
7518 : handle(Handle<JSFunction>::cast(map_constructor)->context());
7519 153202 : Handle<Context> current_context(current_info()->context());
7520 : bool is_same_context_global_proxy_access =
7521 295748 : maps->length() == 1 && // >1 map => fallback to polymorphic
7522 153520 : maps->first()->IsJSGlobalProxyMap() &&
7523 : (*map_context == *current_context);
7524 153202 : if (is_same_context_global_proxy_access) {
7525 201 : Handle<JSGlobalObject> global_object(current_info()->global_object());
7526 201 : LookupIterator it(global_object, name, LookupIterator::OWN);
7527 201 : if (CanInlineGlobalPropertyAccess(&it, access)) {
7528 156 : BuildCheckHeapObject(object);
7529 156 : Add<HCheckMaps>(object, maps);
7530 156 : if (access == LOAD) {
7531 143 : InlineGlobalPropertyLoad(&it, expr->id());
7532 143 : return nullptr;
7533 : } else {
7534 13 : return InlineGlobalPropertyStore(&it, value, expr->id());
7535 : }
7536 : }
7537 : }
7538 : }
7539 :
7540 376336 : PropertyAccessInfo info(this, access, maps->first(), name);
7541 188168 : if (!info.CanAccessAsMonomorphic(maps)) {
7542 : HandlePolymorphicNamedFieldAccess(access, expr, slot, ast_id, return_id,
7543 10166 : object, value, maps, name);
7544 10166 : return NULL;
7545 : }
7546 :
7547 : HValue* checked_object;
7548 : // AstType::Number() is only supported by polymorphic load/call handling.
7549 : DCHECK(!info.IsNumberType());
7550 178002 : BuildCheckHeapObject(object);
7551 178002 : if (AreStringTypes(maps)) {
7552 : checked_object =
7553 13773 : Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING);
7554 : } else {
7555 164229 : checked_object = Add<HCheckMaps>(object, maps);
7556 : }
7557 : return BuildMonomorphicAccess(
7558 178002 : &info, object, checked_object, value, ast_id, return_id);
7559 : }
7560 :
7561 : return BuildNamedGeneric(access, expr, slot, object, name, value,
7562 297931 : is_uninitialized);
7563 : }
7564 :
7565 :
7566 207899 : void HOptimizedGraphBuilder::PushLoad(Property* expr,
7567 : HValue* object,
7568 : HValue* key) {
7569 : ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED);
7570 207899 : Push(object);
7571 207899 : if (key != NULL) Push(key);
7572 207899 : BuildLoad(expr, expr->LoadId());
7573 207899 : }
7574 :
7575 :
7576 1468180 : void HOptimizedGraphBuilder::BuildLoad(Property* expr,
7577 583449 : BailoutId ast_id) {
7578 : HInstruction* instr = NULL;
7579 520272 : if (expr->IsStringAccess() && expr->GetKeyType() == ELEMENT) {
7580 : HValue* index = Pop();
7581 : HValue* string = Pop();
7582 81 : HInstruction* char_code = BuildStringCharCodeAt(string, index);
7583 81 : AddInstruction(char_code);
7584 162 : if (char_code->IsConstant()) {
7585 21 : HConstant* c_code = HConstant::cast(char_code);
7586 42 : if (c_code->HasNumberValue() && std::isnan(c_code->DoubleValue())) {
7587 11 : Add<HDeoptimize>(DeoptimizeReason::kOutOfBounds, Deoptimizer::EAGER);
7588 : }
7589 : }
7590 81 : instr = NewUncasted<HStringCharFromCode>(char_code);
7591 :
7592 520095 : } else if (expr->key()->IsPropertyName()) {
7593 427909 : Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
7594 : HValue* object = Pop();
7595 :
7596 : HValue* value = BuildNamedAccess(LOAD, ast_id, expr->LoadId(), expr,
7597 : expr->PropertyFeedbackSlot(), object, name,
7598 855818 : NULL, expr->IsUninitialized());
7599 427909 : if (value == NULL) return;
7600 418656 : if (value->IsPhi()) return ast_context()->ReturnValue(value);
7601 : instr = HInstruction::cast(value);
7602 419560 : if (instr->IsLinked()) return ast_context()->ReturnValue(instr);
7603 :
7604 : } else {
7605 : HValue* key = Pop();
7606 : HValue* obj = Pop();
7607 :
7608 92186 : bool has_side_effects = false;
7609 : HValue* load = HandleKeyedElementAccess(
7610 : obj, key, NULL, expr, expr->PropertyFeedbackSlot(), ast_id,
7611 92186 : expr->LoadId(), LOAD, &has_side_effects);
7612 92186 : if (has_side_effects) {
7613 72567 : if (ast_context()->IsEffect()) {
7614 28 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
7615 : } else {
7616 72539 : Push(load);
7617 72539 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
7618 : Drop(1);
7619 : }
7620 : }
7621 92186 : if (load == NULL) return;
7622 92145 : return ast_context()->ReturnValue(load);
7623 : }
7624 417833 : return ast_context()->ReturnInstruction(instr, ast_id);
7625 : }
7626 :
7627 :
7628 1654363 : void HOptimizedGraphBuilder::VisitProperty(Property* expr) {
7629 : DCHECK(!HasStackOverflow());
7630 : DCHECK(current_block() != NULL);
7631 : DCHECK(current_block()->HasPredecessor());
7632 :
7633 313753 : if (TryArgumentsAccess(expr)) return;
7634 :
7635 716056 : CHECK_ALIVE(VisitForValue(expr->obj()));
7636 533182 : if (!expr->key()->IsPropertyName() || expr->IsStringAccess()) {
7637 274116 : CHECK_ALIVE(VisitForValue(expr->key()));
7638 : }
7639 :
7640 312277 : BuildLoad(expr, expr->id());
7641 : }
7642 :
7643 94743 : HInstruction* HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant,
7644 216 : bool ensure_no_elements) {
7645 : HCheckMaps* check = Add<HCheckMaps>(
7646 94743 : Add<HConstant>(constant), handle(constant->map()));
7647 : check->ClearDependsOnFlag(kElementsKind);
7648 94743 : if (ensure_no_elements) {
7649 : // TODO(ishell): remove this once we support NO_ELEMENTS elements kind.
7650 : HValue* elements = AddLoadElements(check, nullptr);
7651 : HValue* empty_elements =
7652 216 : Add<HConstant>(isolate()->factory()->empty_fixed_array());
7653 : IfBuilder if_empty(this);
7654 : if_empty.IfNot<HCompareObjectEqAndBranch>(elements, empty_elements);
7655 : if_empty.ThenDeopt(DeoptimizeReason::kWrongMap);
7656 216 : if_empty.End();
7657 : }
7658 94743 : return check;
7659 : }
7660 :
7661 61069 : HInstruction* HGraphBuilder::BuildCheckPrototypeMaps(Handle<JSObject> prototype,
7662 : Handle<JSObject> holder,
7663 61069 : bool ensure_no_elements) {
7664 61069 : PrototypeIterator iter(isolate(), prototype, kStartAtReceiver);
7665 245350 : while (holder.is_null() ||
7666 : !PrototypeIterator::GetCurrent(iter).is_identical_to(holder)) {
7667 : BuildConstantMapCheck(PrototypeIterator::GetCurrent<JSObject>(iter),
7668 36195 : ensure_no_elements);
7669 36195 : iter.Advance();
7670 36195 : if (iter.IsAtEnd()) {
7671 : return NULL;
7672 : }
7673 : }
7674 58548 : return BuildConstantMapCheck(holder);
7675 : }
7676 :
7677 :
7678 1565 : void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder,
7679 : Handle<Map> receiver_map) {
7680 1565 : if (!holder.is_null()) {
7681 : Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype()));
7682 1557 : BuildCheckPrototypeMaps(prototype, holder);
7683 : }
7684 1565 : }
7685 :
7686 133 : void HOptimizedGraphBuilder::BuildEnsureCallable(HValue* object) {
7687 133 : NoObservableSideEffectsScope scope(this);
7688 : const Runtime::Function* throw_called_non_callable =
7689 133 : Runtime::FunctionForId(Runtime::kThrowCalledNonCallable);
7690 :
7691 : IfBuilder is_not_function(this);
7692 133 : HValue* smi_check = is_not_function.If<HIsSmiAndBranch>(object);
7693 133 : is_not_function.Or();
7694 : HValue* map = AddLoadMap(object, smi_check);
7695 : HValue* bit_field =
7696 133 : Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField());
7697 : HValue* bit_field_masked = AddUncasted<HBitwise>(
7698 133 : Token::BIT_AND, bit_field, Add<HConstant>(1 << Map::kIsCallable));
7699 : is_not_function.IfNot<HCompareNumericAndBranch>(
7700 133 : bit_field_masked, Add<HConstant>(1 << Map::kIsCallable), Token::EQ);
7701 133 : is_not_function.Then();
7702 : {
7703 133 : Add<HPushArguments>(object);
7704 133 : Add<HCallRuntime>(throw_called_non_callable, 1);
7705 : }
7706 133 : is_not_function.End();
7707 133 : }
7708 :
7709 118037 : HInstruction* HOptimizedGraphBuilder::NewCallFunction(
7710 : HValue* function, int argument_count, TailCallMode syntactic_tail_call_mode,
7711 : ConvertReceiverMode convert_mode, TailCallMode tail_call_mode) {
7712 118037 : if (syntactic_tail_call_mode == TailCallMode::kAllow) {
7713 89 : BuildEnsureCallable(function);
7714 : } else {
7715 : DCHECK_EQ(TailCallMode::kDisallow, tail_call_mode);
7716 : }
7717 236074 : HValue* arity = Add<HConstant>(argument_count - 1);
7718 :
7719 118037 : HValue* op_vals[] = {function, arity};
7720 :
7721 : Callable callable =
7722 118037 : CodeFactory::Call(isolate(), convert_mode, tail_call_mode);
7723 118037 : HConstant* stub = Add<HConstant>(callable.code());
7724 :
7725 : return New<HCallWithDescriptor>(stub, argument_count, callable.descriptor(),
7726 : ArrayVector(op_vals),
7727 118037 : syntactic_tail_call_mode);
7728 : }
7729 :
7730 243641 : HInstruction* HOptimizedGraphBuilder::NewCallFunctionViaIC(
7731 : HValue* function, int argument_count, TailCallMode syntactic_tail_call_mode,
7732 : ConvertReceiverMode convert_mode, TailCallMode tail_call_mode,
7733 : FeedbackSlot slot) {
7734 243641 : if (syntactic_tail_call_mode == TailCallMode::kAllow) {
7735 44 : BuildEnsureCallable(function);
7736 : } else {
7737 : DCHECK_EQ(TailCallMode::kDisallow, tail_call_mode);
7738 : }
7739 243641 : int arity = argument_count - 1;
7740 487282 : Handle<FeedbackVector> vector(current_feedback_vector(), isolate());
7741 243641 : HValue* arity_val = Add<HConstant>(arity);
7742 243641 : HValue* index_val = Add<HConstant>(vector->GetIndex(slot));
7743 243641 : HValue* vector_val = Add<HConstant>(vector);
7744 :
7745 243641 : HValue* op_vals[] = {function, arity_val, index_val, vector_val};
7746 : Callable callable =
7747 243641 : CodeFactory::CallIC(isolate(), convert_mode, tail_call_mode);
7748 243641 : HConstant* stub = Add<HConstant>(callable.code());
7749 :
7750 : return New<HCallWithDescriptor>(stub, argument_count, callable.descriptor(),
7751 : ArrayVector(op_vals),
7752 243641 : syntactic_tail_call_mode);
7753 : }
7754 :
7755 140084 : HInstruction* HOptimizedGraphBuilder::NewCallConstantFunction(
7756 : Handle<JSFunction> function, int argument_count,
7757 : TailCallMode syntactic_tail_call_mode, TailCallMode tail_call_mode) {
7758 140084 : HValue* target = Add<HConstant>(function);
7759 : return New<HInvokeFunction>(target, function, argument_count,
7760 140084 : syntactic_tail_call_mode, tail_call_mode);
7761 : }
7762 :
7763 :
7764 : class FunctionSorter {
7765 : public:
7766 : explicit FunctionSorter(int index = 0, int ticks = 0, int size = 0)
7767 6756 : : index_(index), ticks_(ticks), size_(size) {}
7768 :
7769 : int index() const { return index_; }
7770 : int ticks() const { return ticks_; }
7771 : int size() const { return size_; }
7772 :
7773 : private:
7774 : int index_;
7775 : int ticks_;
7776 : int size_;
7777 : };
7778 :
7779 :
7780 1648 : inline bool operator<(const FunctionSorter& lhs, const FunctionSorter& rhs) {
7781 849 : int diff = lhs.ticks() - rhs.ticks();
7782 849 : if (diff != 0) return diff > 0;
7783 799 : return lhs.size() < rhs.size();
7784 : }
7785 :
7786 :
7787 6128 : void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
7788 : HValue* receiver,
7789 : SmallMapList* maps,
7790 7127 : Handle<String> name) {
7791 1689 : int argument_count = expr->arguments()->length() + 1; // Includes receiver.
7792 8445 : FunctionSorter order[kMaxCallPolymorphism];
7793 :
7794 : bool handle_smi = false;
7795 : bool handled_string = false;
7796 : int ordered_functions = 0;
7797 :
7798 : TailCallMode syntactic_tail_call_mode = expr->tail_call_mode();
7799 : TailCallMode tail_call_mode =
7800 1689 : function_state()->ComputeTailCallMode(syntactic_tail_call_mode);
7801 :
7802 : int i;
7803 7896 : for (i = 0; i < maps->length() && ordered_functions < kMaxCallPolymorphism;
7804 : ++i) {
7805 2259 : PropertyAccessInfo info(this, LOAD, maps->at(i), name);
7806 5598 : if (info.CanAccessMonomorphic() && info.IsDataConstant() &&
7807 : info.constant()->IsJSFunction()) {
7808 1562 : if (info.IsStringType()) {
7809 1 : if (handled_string) continue;
7810 : handled_string = true;
7811 : }
7812 : Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant());
7813 1562 : if (info.IsNumberType()) {
7814 : handle_smi = true;
7815 : }
7816 : expr->set_target(target);
7817 : order[ordered_functions++] = FunctionSorter(
7818 3124 : i, target->shared()->profiler_ticks(), InliningAstSize(target));
7819 : }
7820 : }
7821 :
7822 1689 : std::sort(order, order + ordered_functions);
7823 :
7824 1689 : if (i < maps->length()) {
7825 : maps->Clear();
7826 : ordered_functions = -1;
7827 : }
7828 :
7829 : HBasicBlock* number_block = NULL;
7830 : HBasicBlock* join = NULL;
7831 : handled_string = false;
7832 : int count = 0;
7833 :
7834 3251 : for (int fn = 0; fn < ordered_functions; ++fn) {
7835 1562 : int i = order[fn].index();
7836 1562 : PropertyAccessInfo info(this, LOAD, maps->at(i), name);
7837 1562 : if (info.IsStringType()) {
7838 1 : if (handled_string) continue;
7839 : handled_string = true;
7840 : }
7841 : // Reloads the target.
7842 1562 : info.CanAccessMonomorphic();
7843 : Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant());
7844 :
7845 : expr->set_target(target);
7846 1562 : if (count == 0) {
7847 : // Only needed once.
7848 10788 : join = graph()->CreateBasicBlock();
7849 1126 : if (handle_smi) {
7850 705 : HBasicBlock* empty_smi_block = graph()->CreateBasicBlock();
7851 705 : HBasicBlock* not_smi_block = graph()->CreateBasicBlock();
7852 705 : number_block = graph()->CreateBasicBlock();
7853 : FinishCurrentBlock(New<HIsSmiAndBranch>(
7854 705 : receiver, empty_smi_block, not_smi_block));
7855 : GotoNoSimulate(empty_smi_block, number_block);
7856 : set_current_block(not_smi_block);
7857 : } else {
7858 421 : BuildCheckHeapObject(receiver);
7859 : }
7860 : }
7861 1562 : ++count;
7862 1562 : HBasicBlock* if_true = graph()->CreateBasicBlock();
7863 1562 : HBasicBlock* if_false = graph()->CreateBasicBlock();
7864 : HUnaryControlInstruction* compare;
7865 :
7866 1562 : Handle<Map> map = info.map();
7867 1562 : if (info.IsNumberType()) {
7868 705 : Handle<Map> heap_number_map = isolate()->factory()->heap_number_map();
7869 705 : compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false);
7870 857 : } else if (info.IsStringType()) {
7871 1 : compare = New<HIsStringAndBranch>(receiver, if_true, if_false);
7872 : } else {
7873 856 : compare = New<HCompareMap>(receiver, map, if_true, if_false);
7874 : }
7875 1562 : FinishCurrentBlock(compare);
7876 :
7877 1562 : if (info.IsNumberType()) {
7878 : GotoNoSimulate(if_true, number_block);
7879 : if_true = number_block;
7880 : }
7881 :
7882 : set_current_block(if_true);
7883 :
7884 1562 : AddCheckPrototypeMaps(info.holder(), map);
7885 :
7886 1562 : HValue* function = Add<HConstant>(expr->target());
7887 : environment()->SetExpressionStackAt(0, function);
7888 1562 : Push(receiver);
7889 4686 : CHECK_ALIVE(VisitExpressions(expr->arguments()));
7890 1562 : bool needs_wrapping = info.NeedsWrappingFor(target);
7891 1562 : bool try_inline = FLAG_polymorphic_inlining && !needs_wrapping;
7892 1562 : if (FLAG_trace_inlining && try_inline) {
7893 : Handle<JSFunction> caller = current_info()->closure();
7894 : std::unique_ptr<char[]> caller_name =
7895 0 : caller->shared()->DebugName()->ToCString();
7896 : PrintF("Trying to inline the polymorphic call to %s from %s\n",
7897 : name->ToCString().get(),
7898 0 : caller_name.get());
7899 : }
7900 1562 : if (try_inline && TryInlineCall(expr)) {
7901 : // Trying to inline will signal that we should bailout from the
7902 : // entire compilation by setting stack overflow on the visitor.
7903 82 : if (HasStackOverflow()) return;
7904 : } else {
7905 : // Since HWrapReceiver currently cannot actually wrap numbers and strings,
7906 : // use the regular call builtin for method calls to wrap the receiver.
7907 : // TODO(verwaest): Support creation of value wrappers directly in
7908 : // HWrapReceiver.
7909 : HInstruction* call =
7910 : needs_wrapping
7911 : ? NewCallFunction(
7912 : function, argument_count, syntactic_tail_call_mode,
7913 : ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode)
7914 : : NewCallConstantFunction(target, argument_count,
7915 : syntactic_tail_call_mode,
7916 1480 : tail_call_mode);
7917 1480 : PushArgumentsFromEnvironment(argument_count);
7918 1480 : AddInstruction(call);
7919 : Drop(1); // Drop the function.
7920 1480 : if (!ast_context()->IsEffect()) Push(call);
7921 : }
7922 :
7923 1562 : if (current_block() != NULL) Goto(join);
7924 : set_current_block(if_false);
7925 : }
7926 :
7927 : // Finish up. Unconditionally deoptimize if we've handled all the maps we
7928 : // know about and do not want to handle ones we've never seen. Otherwise
7929 : // use a generic IC.
7930 1689 : if (ordered_functions == maps->length() && FLAG_deoptimize_uncommon_cases) {
7931 : FinishExitWithHardDeoptimization(
7932 1095 : DeoptimizeReason::kUnknownMapInPolymorphicCall);
7933 : } else {
7934 594 : Property* prop = expr->expression()->AsProperty();
7935 : HInstruction* function =
7936 : BuildNamedGeneric(LOAD, prop, prop->PropertyFeedbackSlot(), receiver,
7937 1188 : name, NULL, prop->IsUninitialized());
7938 594 : AddInstruction(function);
7939 594 : Push(function);
7940 : AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE);
7941 :
7942 : environment()->SetExpressionStackAt(1, function);
7943 : environment()->SetExpressionStackAt(0, receiver);
7944 1782 : CHECK_ALIVE(VisitExpressions(expr->arguments()));
7945 :
7946 : HInstruction* call = NewCallFunction(
7947 : function, argument_count, syntactic_tail_call_mode,
7948 594 : ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode);
7949 :
7950 594 : PushArgumentsFromEnvironment(argument_count);
7951 :
7952 : Drop(1); // Function.
7953 :
7954 594 : if (join != NULL) {
7955 31 : AddInstruction(call);
7956 31 : if (!ast_context()->IsEffect()) Push(call);
7957 : Goto(join);
7958 : } else {
7959 1126 : return ast_context()->ReturnInstruction(call, expr->id());
7960 : }
7961 : }
7962 :
7963 : // We assume that control flow is always live after an expression. So
7964 : // even without predecessors to the join block, we set it as the exit
7965 : // block and continue by adding instructions there.
7966 : DCHECK(join != NULL);
7967 1126 : if (join->HasPredecessor()) {
7968 : set_current_block(join);
7969 : join->SetJoinId(expr->id());
7970 1982 : if (!ast_context()->IsEffect()) return ast_context()->ReturnValue(Pop());
7971 : } else {
7972 : set_current_block(NULL);
7973 : }
7974 : }
7975 :
7976 145828 : void HOptimizedGraphBuilder::TraceInline(Handle<JSFunction> target,
7977 : Handle<JSFunction> caller,
7978 : const char* reason,
7979 : TailCallMode tail_call_mode) {
7980 145828 : if (FLAG_trace_inlining) {
7981 : std::unique_ptr<char[]> target_name =
7982 0 : target->shared()->DebugName()->ToCString();
7983 : std::unique_ptr<char[]> caller_name =
7984 0 : caller->shared()->DebugName()->ToCString();
7985 0 : if (reason == NULL) {
7986 : const char* call_mode =
7987 0 : tail_call_mode == TailCallMode::kAllow ? "tail called" : "called";
7988 : PrintF("Inlined %s %s from %s.\n", target_name.get(), call_mode,
7989 0 : caller_name.get());
7990 : } else {
7991 : PrintF("Did not inline %s called from %s (%s).\n",
7992 0 : target_name.get(), caller_name.get(), reason);
7993 : }
7994 : }
7995 145828 : }
7996 :
7997 :
7998 : static const int kNotInlinable = 1000000000;
7999 :
8000 :
8001 248447 : int HOptimizedGraphBuilder::InliningAstSize(Handle<JSFunction> target) {
8002 248447 : if (!FLAG_use_inlining) return kNotInlinable;
8003 :
8004 : // Precondition: call is monomorphic and we have found a target with the
8005 : // appropriate arity.
8006 245188 : Handle<JSFunction> caller = current_info()->closure();
8007 : Handle<SharedFunctionInfo> target_shared(target->shared());
8008 :
8009 : // Always inline functions that force inlining.
8010 245188 : if (target_shared->force_inline()) {
8011 : return 0;
8012 : }
8013 242799 : if (!target->shared()->IsUserJavaScript()) {
8014 : return kNotInlinable;
8015 : }
8016 :
8017 142916 : if (target_shared->IsApiFunction()) {
8018 0 : TraceInline(target, caller, "target is api function");
8019 0 : return kNotInlinable;
8020 : }
8021 :
8022 : // Do a quick check on source code length to avoid parsing large
8023 : // inlining candidates.
8024 285832 : if (target_shared->SourceSize() >
8025 142916 : Min(FLAG_max_inlined_source_size, kUnlimitedMaxInlinedSourceSize)) {
8026 7595 : TraceInline(target, caller, "target text too big");
8027 7595 : return kNotInlinable;
8028 : }
8029 :
8030 : // Target must be inlineable.
8031 : BailoutReason noopt_reason = target_shared->disable_optimization_reason();
8032 135321 : if (!target_shared->IsInlineable() && noopt_reason != kHydrogenFilter) {
8033 808 : TraceInline(target, caller, "target not inlineable");
8034 808 : return kNotInlinable;
8035 : }
8036 134513 : if (noopt_reason != kNoReason && noopt_reason != kHydrogenFilter) {
8037 0 : TraceInline(target, caller, "target contains unsupported syntax [early]");
8038 0 : return kNotInlinable;
8039 : }
8040 :
8041 : int nodes_added = target_shared->ast_node_count();
8042 134513 : return nodes_added;
8043 : }
8044 :
8045 246938 : bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target,
8046 : int arguments_count,
8047 : HValue* implicit_return_value,
8048 : BailoutId ast_id, BailoutId return_id,
8049 : InliningKind inlining_kind,
8050 675063 : TailCallMode syntactic_tail_call_mode) {
8051 246938 : if (target->context()->native_context() !=
8052 1670778 : top_info()->closure()->context()->native_context()) {
8053 : return false;
8054 : }
8055 246885 : int nodes_added = InliningAstSize(target);
8056 246885 : if (nodes_added == kNotInlinable) return false;
8057 :
8058 136810 : Handle<JSFunction> caller = current_info()->closure();
8059 273620 : if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) {
8060 7 : TraceInline(target, caller, "target AST is too large [early]");
8061 7 : return false;
8062 : }
8063 :
8064 : // Don't inline deeper than the maximum number of inlining levels.
8065 305860 : HEnvironment* env = environment();
8066 : int current_level = 1;
8067 442663 : while (env->outer() != NULL) {
8068 171231 : if (current_level == FLAG_max_inlining_levels) {
8069 2174 : TraceInline(target, caller, "inline depth limit reached");
8070 2174 : return false;
8071 : }
8072 169057 : if (env->outer()->frame_type() == JS_FUNCTION) {
8073 129382 : current_level++;
8074 : }
8075 : env = env->outer();
8076 : }
8077 :
8078 : // Don't inline recursive functions.
8079 471624 : for (FunctionState* state = function_state();
8080 : state != NULL;
8081 : state = state->outer()) {
8082 239339 : if (*state->compilation_info()->closure() == *target) {
8083 7054 : TraceInline(target, caller, "target is recursive");
8084 7054 : return false;
8085 : }
8086 : }
8087 :
8088 : // We don't want to add more than a certain number of nodes from inlining.
8089 : // Always inline small methods (<= 10 nodes).
8090 255150 : if (inlined_count_ > Min(FLAG_max_inlined_nodes_cumulative,
8091 127575 : kUnlimitedMaxInlinedNodesCumulative)) {
8092 4963 : TraceInline(target, caller, "cumulative AST node limit reached");
8093 4963 : return false;
8094 : }
8095 :
8096 : // Parse and allocate variables.
8097 : // Use the same AstValueFactory for creating strings in the sub-compilation
8098 : // step, but don't transfer ownership to target_info.
8099 : Handle<SharedFunctionInfo> target_shared(target->shared());
8100 367836 : ParseInfo parse_info(target_shared, top_info()->parse_info()->zone_shared());
8101 : parse_info.set_ast_value_factory(
8102 122612 : top_info()->parse_info()->ast_value_factory());
8103 : parse_info.set_ast_value_factory_owned(false);
8104 :
8105 : CompilationInfo target_info(parse_info.zone(), &parse_info,
8106 245224 : target->GetIsolate(), target);
8107 :
8108 243596 : if (inlining_kind != CONSTRUCT_CALL_RETURN &&
8109 : IsClassConstructor(target_shared->kind())) {
8110 0 : TraceInline(target, caller, "target is classConstructor");
8111 0 : return false;
8112 : }
8113 :
8114 122612 : if (target_shared->HasDebugInfo()) {
8115 29 : TraceInline(target, caller, "target is being debugged");
8116 29 : return false;
8117 : }
8118 122583 : if (!Compiler::ParseAndAnalyze(&target_info)) {
8119 1 : if (target_info.isolate()->has_pending_exception()) {
8120 : // Parse or scope error, never optimize this function.
8121 : SetStackOverflow();
8122 1 : target_shared->DisableOptimization(kParseScopeError);
8123 : }
8124 1 : TraceInline(target, caller, "parse failure");
8125 1 : return false;
8126 : }
8127 122582 : if (target_shared->must_use_ignition_turbo()) {
8128 11835 : TraceInline(target, caller, "ParseAndAnalyze found incompatibility");
8129 11835 : return false;
8130 : }
8131 :
8132 221494 : if (target_info.scope()->NeedsContext()) {
8133 3270 : TraceInline(target, caller, "target has context-allocated variables");
8134 3270 : return false;
8135 : }
8136 :
8137 214954 : if (target_info.scope()->rest_parameter() != nullptr) {
8138 0 : TraceInline(target, caller, "target uses rest parameters");
8139 0 : return false;
8140 : }
8141 :
8142 537262 : FunctionLiteral* function = target_info.literal();
8143 :
8144 : // The following conditions must be checked again after re-parsing, because
8145 : // earlier the information might not have been complete due to lazy parsing.
8146 : nodes_added = function->ast_node_count();
8147 214954 : if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) {
8148 0 : TraceInline(target, caller, "target AST is too large [late]");
8149 0 : return false;
8150 : }
8151 107477 : if (function->dont_optimize()) {
8152 0 : TraceInline(target, caller, "target contains unsupported syntax [late]");
8153 0 : return false;
8154 : }
8155 :
8156 : // If the function uses the arguments object check that inlining of functions
8157 : // with arguments object is enabled and the arguments-variable is
8158 : // stack allocated.
8159 107477 : if (function->scope()->arguments() != NULL) {
8160 380 : if (!FLAG_inline_arguments) {
8161 0 : TraceInline(target, caller, "target uses arguments object");
8162 0 : return false;
8163 : }
8164 : }
8165 :
8166 : // Unsupported variable references present.
8167 214954 : if (function->scope()->this_function_var() != nullptr ||
8168 107477 : function->scope()->new_target_var() != nullptr) {
8169 0 : TraceInline(target, caller, "target uses new target or this function");
8170 0 : return false;
8171 : }
8172 :
8173 : // All declarations must be inlineable.
8174 107477 : Declaration::List* decls = target_info.scope()->declarations();
8175 396304 : for (Declaration* decl : *decls) {
8176 181384 : if (decl->IsFunctionDeclaration() ||
8177 90675 : !decl->proxy()->var()->IsStackAllocated()) {
8178 34 : TraceInline(target, caller, "target has non-trivial declaration");
8179 : return false;
8180 : }
8181 : }
8182 :
8183 : // Generate the deoptimization data for the unoptimized version of
8184 : // the target function if we don't already have it.
8185 107443 : if (!Compiler::EnsureDeoptimizationSupport(&target_info)) {
8186 7 : TraceInline(target, caller, "could not generate deoptimization info");
8187 7 : return false;
8188 : }
8189 :
8190 : // Remember that we inlined this function. This needs to be called right
8191 : // after the EnsureDeoptimizationSupport call so that the code flusher
8192 : // does not remove the code with the deoptimization support.
8193 : int inlining_id = top_info()->AddInlinedFunction(target_info.shared_info(),
8194 214872 : source_position());
8195 :
8196 : // ----------------------------------------------------------------
8197 : // After this point, we've made a decision to inline this function (so
8198 : // TryInline should always return true).
8199 :
8200 : // If target was lazily compiled, it's literals array may not yet be set up.
8201 107436 : JSFunction::EnsureLiterals(target);
8202 :
8203 : // Type-check the inlined function.
8204 : DCHECK(target_shared->has_deoptimization_support());
8205 : AstTyper(target_info.isolate(), target_info.zone(), target_info.closure(),
8206 : target_info.scope(), target_info.osr_ast_id(), target_info.literal(),
8207 : &bounds_)
8208 107436 : .Run();
8209 :
8210 : // Save the pending call context. Set up new one for the inlined function.
8211 : // The function state is new-allocated because we need to delete it
8212 : // in two different places.
8213 : FunctionState* target_state = new FunctionState(
8214 : this, &target_info, inlining_kind, inlining_id,
8215 214872 : function_state()->ComputeTailCallMode(syntactic_tail_call_mode));
8216 :
8217 107436 : HConstant* undefined = graph()->GetConstantUndefined();
8218 :
8219 : HEnvironment* inner_env = environment()->CopyForInlining(
8220 : target, arguments_count, function, undefined,
8221 214872 : function_state()->inlining_kind(), syntactic_tail_call_mode);
8222 :
8223 107436 : HConstant* context = Add<HConstant>(Handle<Context>(target->context()));
8224 107436 : inner_env->BindContext(context);
8225 :
8226 : // Create a dematerialized arguments object for the function, also copy the
8227 : // current arguments values to use them for materialization.
8228 107436 : HEnvironment* arguments_env = inner_env->arguments_environment();
8229 : int parameter_count = arguments_env->parameter_count();
8230 107436 : HArgumentsObject* arguments_object = Add<HArgumentsObject>(parameter_count);
8231 407129 : for (int i = 0; i < parameter_count; i++) {
8232 299693 : arguments_object->AddArgument(arguments_env->Lookup(i), zone());
8233 : }
8234 :
8235 : // If the function uses arguments object then bind bind one.
8236 107436 : if (function->scope()->arguments() != NULL) {
8237 : DCHECK(function->scope()->arguments()->IsStackAllocated());
8238 380 : inner_env->Bind(function->scope()->arguments(), arguments_object);
8239 : }
8240 :
8241 : // Capture the state before invoking the inlined function for deopt in the
8242 : // inlined function. This simulate has no bailout-id since it's not directly
8243 : // reachable for deopt, and is only used to capture the state. If the simulate
8244 : // becomes reachable by merging, the ast id of the simulate merged into it is
8245 : // adopted.
8246 : Add<HSimulate>(BailoutId::None());
8247 :
8248 : current_block()->UpdateEnvironment(inner_env);
8249 : Scope* saved_scope = scope();
8250 107436 : set_scope(target_info.scope());
8251 : HEnterInlined* enter_inlined = Add<HEnterInlined>(
8252 : return_id, target, context, arguments_count, function,
8253 : function_state()->inlining_kind(), function->scope()->arguments(),
8254 214872 : arguments_object, syntactic_tail_call_mode);
8255 107436 : if (is_tracking_positions()) {
8256 : enter_inlined->set_inlining_id(inlining_id);
8257 : }
8258 :
8259 : function_state()->set_entry(enter_inlined);
8260 :
8261 107436 : VisitDeclarations(target_info.scope()->declarations());
8262 107436 : VisitStatements(function->body());
8263 : set_scope(saved_scope);
8264 107436 : if (HasStackOverflow()) {
8265 : // Bail out if the inline function did, as we cannot residualize a call
8266 : // instead, but do not disable optimization for the outer function.
8267 36 : TraceInline(target, caller, "inline graph construction failed");
8268 36 : target_shared->DisableOptimization(kInliningBailedOut);
8269 : current_info()->RetryOptimization(kInliningBailedOut);
8270 36 : delete target_state;
8271 : return true;
8272 : }
8273 :
8274 : // Update inlined nodes count.
8275 107400 : inlined_count_ += nodes_added;
8276 :
8277 : Handle<Code> unoptimized_code(target_shared->code());
8278 : DCHECK(unoptimized_code->kind() == Code::FUNCTION);
8279 : Handle<TypeFeedbackInfo> type_info(
8280 : TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info()));
8281 : graph()->update_type_change_checksum(type_info->own_type_change_checksum());
8282 :
8283 107400 : TraceInline(target, caller, NULL, syntactic_tail_call_mode);
8284 :
8285 107400 : if (current_block() != NULL) {
8286 60303 : FunctionState* state = function_state();
8287 60303 : if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) {
8288 : // Falling off the end of an inlined construct call. In a test context the
8289 : // return value will always evaluate to true, in a value context the
8290 : // return value is the newly allocated receiver.
8291 842 : if (call_context()->IsTest()) {
8292 12 : inlined_test_context()->ReturnValue(graph()->GetConstantTrue());
8293 830 : } else if (call_context()->IsEffect()) {
8294 : Goto(function_return(), state);
8295 : } else {
8296 : DCHECK(call_context()->IsValue());
8297 : AddLeaveInlined(implicit_return_value, state);
8298 : }
8299 59461 : } else if (state->inlining_kind() == SETTER_CALL_RETURN) {
8300 : // Falling off the end of an inlined setter call. The returned value is
8301 : // never used, the value of an assignment is always the value of the RHS
8302 : // of the assignment.
8303 145 : if (call_context()->IsTest()) {
8304 : inlined_test_context()->ReturnValue(implicit_return_value);
8305 131 : } else if (call_context()->IsEffect()) {
8306 : Goto(function_return(), state);
8307 : } else {
8308 : DCHECK(call_context()->IsValue());
8309 : AddLeaveInlined(implicit_return_value, state);
8310 : }
8311 : } else {
8312 : // Falling off the end of a normal inlined function. This basically means
8313 : // returning undefined.
8314 59316 : if (call_context()->IsTest()) {
8315 136 : inlined_test_context()->ReturnValue(graph()->GetConstantFalse());
8316 59180 : } else if (call_context()->IsEffect()) {
8317 : Goto(function_return(), state);
8318 : } else {
8319 : DCHECK(call_context()->IsValue());
8320 : AddLeaveInlined(undefined, state);
8321 : }
8322 : }
8323 : }
8324 :
8325 : // Fix up the function exits.
8326 107400 : if (inlined_test_context() != NULL) {
8327 19395 : HBasicBlock* if_true = inlined_test_context()->if_true();
8328 19395 : HBasicBlock* if_false = inlined_test_context()->if_false();
8329 :
8330 19395 : HEnterInlined* entry = function_state()->entry();
8331 :
8332 : // Pop the return test context from the expression context stack.
8333 : DCHECK(ast_context() == inlined_test_context());
8334 : ClearInlinedTestContext();
8335 19395 : delete target_state;
8336 :
8337 : // Forward to the real test context.
8338 19395 : if (if_true->HasPredecessor()) {
8339 19395 : entry->RegisterReturnTarget(if_true, zone());
8340 : if_true->SetJoinId(ast_id);
8341 19395 : HBasicBlock* true_target = TestContext::cast(ast_context())->if_true();
8342 : Goto(if_true, true_target, function_state());
8343 : }
8344 19395 : if (if_false->HasPredecessor()) {
8345 19395 : entry->RegisterReturnTarget(if_false, zone());
8346 : if_false->SetJoinId(ast_id);
8347 19395 : HBasicBlock* false_target = TestContext::cast(ast_context())->if_false();
8348 : Goto(if_false, false_target, function_state());
8349 : }
8350 : set_current_block(NULL);
8351 19395 : return true;
8352 :
8353 88005 : } else if (function_return()->HasPredecessor()) {
8354 88005 : function_state()->entry()->RegisterReturnTarget(function_return(), zone());
8355 : function_return()->SetJoinId(ast_id);
8356 : set_current_block(function_return());
8357 : } else {
8358 : set_current_block(NULL);
8359 : }
8360 88005 : delete target_state;
8361 122612 : return true;
8362 : }
8363 :
8364 :
8365 477784 : bool HOptimizedGraphBuilder::TryInlineCall(Call* expr) {
8366 : return TryInline(expr->target(), expr->arguments()->length(), NULL,
8367 : expr->id(), expr->ReturnId(), NORMAL_RETURN,
8368 238892 : expr->tail_call_mode());
8369 : }
8370 :
8371 :
8372 9102 : bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr,
8373 : HValue* implicit_return_value) {
8374 : return TryInline(expr->target(), expr->arguments()->length(),
8375 : implicit_return_value, expr->id(), expr->ReturnId(),
8376 4551 : CONSTRUCT_CALL_RETURN, TailCallMode::kDisallow);
8377 : }
8378 :
8379 3069 : bool HOptimizedGraphBuilder::TryInlineGetter(Handle<Object> getter,
8380 : Handle<Map> receiver_map,
8381 : BailoutId ast_id,
8382 : BailoutId return_id) {
8383 3069 : if (TryInlineApiGetter(getter, receiver_map, ast_id)) return true;
8384 3034 : if (getter->IsJSFunction()) {
8385 3034 : Handle<JSFunction> getter_function = Handle<JSFunction>::cast(getter);
8386 5924 : return TryInlineBuiltinGetterCall(getter_function, receiver_map, ast_id) ||
8387 : TryInline(getter_function, 0, NULL, ast_id, return_id,
8388 2890 : GETTER_CALL_RETURN, TailCallMode::kDisallow);
8389 : }
8390 : return false;
8391 : }
8392 :
8393 246 : bool HOptimizedGraphBuilder::TryInlineSetter(Handle<Object> setter,
8394 : Handle<Map> receiver_map,
8395 : BailoutId id,
8396 : BailoutId assignment_id,
8397 : HValue* implicit_return_value) {
8398 246 : if (TryInlineApiSetter(setter, receiver_map, id)) return true;
8399 468 : return setter->IsJSFunction() &&
8400 : TryInline(Handle<JSFunction>::cast(setter), 1, implicit_return_value,
8401 : id, assignment_id, SETTER_CALL_RETURN,
8402 468 : TailCallMode::kDisallow);
8403 : }
8404 :
8405 :
8406 371 : bool HOptimizedGraphBuilder::TryInlineIndirectCall(Handle<JSFunction> function,
8407 371 : Call* expr,
8408 : int arguments_count) {
8409 : return TryInline(function, arguments_count, NULL, expr->id(),
8410 371 : expr->ReturnId(), NORMAL_RETURN, expr->tail_call_mode());
8411 : }
8412 :
8413 :
8414 215284 : bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) {
8415 197968 : if (!expr->target()->shared()->HasBuiltinFunctionId()) return false;
8416 : BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
8417 : // We intentionally ignore expr->tail_call_mode() here because builtins
8418 : // we inline here do not observe if they were tail called or not.
8419 48988 : switch (id) {
8420 : case kMathCos:
8421 : case kMathExp:
8422 : case kMathRound:
8423 : case kMathFround:
8424 : case kMathFloor:
8425 : case kMathAbs:
8426 : case kMathSin:
8427 : case kMathSqrt:
8428 : case kMathLog:
8429 : case kMathClz32:
8430 8624 : if (expr->arguments()->length() == 1) {
8431 68 : HValue* argument = Pop();
8432 : Drop(2); // Receiver and function.
8433 8624 : HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id);
8434 17248 : ast_context()->ReturnInstruction(op, expr->id());
8435 8624 : return true;
8436 : }
8437 : break;
8438 : case kMathImul:
8439 34 : if (expr->arguments()->length() == 2) {
8440 : HValue* right = Pop();
8441 : HValue* left = Pop();
8442 : Drop(2); // Receiver and function.
8443 : HInstruction* op =
8444 68 : HMul::NewImul(isolate(), zone(), context(), left, right);
8445 68 : ast_context()->ReturnInstruction(op, expr->id());
8446 34 : return true;
8447 : }
8448 : break;
8449 : default:
8450 : // Not supported for inlining yet.
8451 : break;
8452 : }
8453 : return false;
8454 : }
8455 :
8456 :
8457 : // static
8458 2548 : bool HOptimizedGraphBuilder::IsReadOnlyLengthDescriptor(
8459 : Handle<Map> jsarray_map) {
8460 : DCHECK(!jsarray_map->is_dictionary_map());
8461 : Isolate* isolate = jsarray_map->GetIsolate();
8462 : Handle<Name> length_string = isolate->factory()->length_string();
8463 : DescriptorArray* descriptors = jsarray_map->instance_descriptors();
8464 : int number =
8465 : descriptors->SearchWithCache(isolate, *length_string, *jsarray_map);
8466 : DCHECK_NE(DescriptorArray::kNotFound, number);
8467 5096 : return descriptors->GetDetails(number).IsReadOnly();
8468 : }
8469 :
8470 :
8471 : // static
8472 2695 : bool HOptimizedGraphBuilder::CanInlineArrayResizeOperation(
8473 : Handle<Map> receiver_map) {
8474 5202 : return !receiver_map.is_null() && receiver_map->prototype()->IsJSObject() &&
8475 2592 : receiver_map->instance_type() == JS_ARRAY_TYPE &&
8476 2559 : IsFastElementsKind(receiver_map->elements_kind()) &&
8477 5106 : !receiver_map->is_dictionary_map() && receiver_map->is_extensible() &&
8478 5254 : (!receiver_map->is_prototype_map() || receiver_map->is_stable()) &&
8479 5243 : !IsReadOnlyLengthDescriptor(receiver_map);
8480 : }
8481 :
8482 3034 : bool HOptimizedGraphBuilder::TryInlineBuiltinGetterCall(
8483 144 : Handle<JSFunction> function, Handle<Map> receiver_map, BailoutId ast_id) {
8484 3034 : if (!function->shared()->HasBuiltinFunctionId()) return false;
8485 : BuiltinFunctionId id = function->shared()->builtin_function_id();
8486 :
8487 : // Try to inline getter calls like DataView.prototype.byteLength/byteOffset
8488 : // as operations in the calling function.
8489 170 : switch (id) {
8490 : case kDataViewBuffer: {
8491 0 : if (!receiver_map->IsJSDataViewMap()) return false;
8492 : HObjectAccess access = HObjectAccess::ForMapAndOffset(
8493 0 : receiver_map, JSDataView::kBufferOffset);
8494 : HValue* object = Pop(); // receiver
8495 0 : HInstruction* result = New<HLoadNamedField>(object, object, access);
8496 0 : ast_context()->ReturnInstruction(result, ast_id);
8497 0 : return true;
8498 : }
8499 : case kDataViewByteLength:
8500 : case kDataViewByteOffset: {
8501 12 : if (!receiver_map->IsJSDataViewMap()) return false;
8502 : int offset = (id == kDataViewByteLength) ? JSDataView::kByteLengthOffset
8503 12 : : JSDataView::kByteOffsetOffset;
8504 : HObjectAccess access =
8505 12 : HObjectAccess::ForMapAndOffset(receiver_map, offset);
8506 : HValue* object = Pop(); // receiver
8507 12 : HValue* checked_object = Add<HCheckArrayBufferNotNeutered>(object);
8508 : HInstruction* result =
8509 12 : New<HLoadNamedField>(object, checked_object, access);
8510 12 : ast_context()->ReturnInstruction(result, ast_id);
8511 12 : return true;
8512 : }
8513 : case kTypedArrayByteLength:
8514 : case kTypedArrayByteOffset:
8515 : case kTypedArrayLength: {
8516 132 : if (!receiver_map->IsJSTypedArrayMap()) return false;
8517 : int offset = (id == kTypedArrayLength)
8518 : ? JSTypedArray::kLengthOffset
8519 : : (id == kTypedArrayByteLength)
8520 : ? JSTypedArray::kByteLengthOffset
8521 132 : : JSTypedArray::kByteOffsetOffset;
8522 : HObjectAccess access =
8523 132 : HObjectAccess::ForMapAndOffset(receiver_map, offset);
8524 : HValue* object = Pop(); // receiver
8525 132 : HValue* checked_object = Add<HCheckArrayBufferNotNeutered>(object);
8526 : HInstruction* result =
8527 132 : New<HLoadNamedField>(object, checked_object, access);
8528 132 : ast_context()->ReturnInstruction(result, ast_id);
8529 132 : return true;
8530 : }
8531 : default:
8532 : return false;
8533 : }
8534 : }
8535 :
8536 : // static
8537 123 : bool HOptimizedGraphBuilder::NoElementsInPrototypeChain(
8538 : Handle<Map> receiver_map) {
8539 : // TODO(ishell): remove this once we support NO_ELEMENTS elements kind.
8540 123 : PrototypeIterator iter(receiver_map);
8541 : Handle<Object> empty_fixed_array =
8542 123 : iter.isolate()->factory()->empty_fixed_array();
8543 : while (true) {
8544 : Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter);
8545 231 : if (current->elements() != *empty_fixed_array) return false;
8546 216 : iter.Advance();
8547 216 : if (iter.IsAtEnd()) {
8548 : return true;
8549 : }
8550 : }
8551 : }
8552 :
8553 86284 : bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
8554 : Handle<JSFunction> function, Handle<Map> receiver_map, BailoutId ast_id,
8555 32202 : int args_count_no_receiver) {
8556 86284 : if (!function->shared()->HasBuiltinFunctionId()) return false;
8557 : BuiltinFunctionId id = function->shared()->builtin_function_id();
8558 48814 : int argument_count = args_count_no_receiver + 1; // Plus receiver.
8559 :
8560 48814 : if (receiver_map.is_null()) {
8561 6199 : HValue* receiver = environment()->ExpressionStackAt(args_count_no_receiver);
8562 1224 : if (receiver->IsConstant() &&
8563 554 : HConstant::cast(receiver)->handle(isolate())->IsHeapObject()) {
8564 : receiver_map =
8565 : handle(Handle<HeapObject>::cast(
8566 73 : HConstant::cast(receiver)->handle(isolate()))->map());
8567 : }
8568 : }
8569 : // Try to inline calls like Math.* as operations in the calling function.
8570 48814 : switch (id) {
8571 : case kObjectHasOwnProperty: {
8572 : // It's not safe to look through the phi for elements if we're compiling
8573 : // for osr.
8574 34 : if (top_info()->is_osr()) return false;
8575 19 : if (argument_count != 2) return false;
8576 : HValue* key = Top();
8577 19 : if (!key->IsLoadKeyed()) return false;
8578 : HValue* elements = HLoadKeyed::cast(key)->elements();
8579 3 : if (!elements->IsPhi() || elements->OperandCount() != 1) return false;
8580 0 : if (!elements->OperandAt(0)->IsForInCacheArray()) return false;
8581 0 : HForInCacheArray* cache = HForInCacheArray::cast(elements->OperandAt(0));
8582 : HValue* receiver = environment()->ExpressionStackAt(1);
8583 0 : if (!receiver->IsPhi() || receiver->OperandCount() != 1) return false;
8584 0 : if (cache->enumerable() != receiver->OperandAt(0)) return false;
8585 : Drop(3); // key, receiver, function
8586 0 : Add<HCheckMapValue>(receiver, cache->map());
8587 0 : ast_context()->ReturnValue(graph()->GetConstantTrue());
8588 0 : return true;
8589 : }
8590 : case kStringCharCodeAt:
8591 : case kStringCharAt:
8592 353 : if (argument_count == 2) {
8593 : HValue* index = Pop();
8594 : HValue* string = Pop();
8595 : Drop(1); // Function.
8596 : HInstruction* char_code =
8597 347 : BuildStringCharCodeAt(string, index);
8598 347 : if (id == kStringCharCodeAt) {
8599 213 : ast_context()->ReturnInstruction(char_code, ast_id);
8600 213 : return true;
8601 : }
8602 134 : AddInstruction(char_code);
8603 134 : HInstruction* result = NewUncasted<HStringCharFromCode>(char_code);
8604 134 : ast_context()->ReturnInstruction(result, ast_id);
8605 134 : return true;
8606 : }
8607 : break;
8608 : case kStringFromCharCode:
8609 319 : if (argument_count == 2) {
8610 : HValue* argument = Pop();
8611 : Drop(2); // Receiver and function.
8612 : argument = AddUncasted<HForceRepresentation>(
8613 294 : argument, Representation::Integer32());
8614 : argument->SetFlag(HValue::kTruncatingToInt32);
8615 294 : HInstruction* result = NewUncasted<HStringCharFromCode>(argument);
8616 294 : ast_context()->ReturnInstruction(result, ast_id);
8617 294 : return true;
8618 : }
8619 : break;
8620 : case kMathCos:
8621 : case kMathExp:
8622 : case kMathRound:
8623 : case kMathFround:
8624 : case kMathFloor:
8625 : case kMathAbs:
8626 : case kMathSin:
8627 : case kMathSqrt:
8628 : case kMathLog:
8629 : case kMathClz32:
8630 20580 : if (argument_count == 2) {
8631 : HValue* argument = Pop();
8632 : Drop(2); // Receiver and function.
8633 20573 : HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id);
8634 20573 : ast_context()->ReturnInstruction(op, ast_id);
8635 20573 : return true;
8636 : }
8637 : break;
8638 : case kMathPow:
8639 1140 : if (argument_count == 3) {
8640 : HValue* right = Pop();
8641 : HValue* left = Pop();
8642 : Drop(2); // Receiver and function.
8643 : HInstruction* result = NULL;
8644 : // Use sqrt() if exponent is 0.5 or -0.5.
8645 2036 : if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) {
8646 876 : double exponent = HConstant::cast(right)->DoubleValue();
8647 876 : if (exponent == 0.5) {
8648 49 : result = NewUncasted<HUnaryMathOperation>(left, kMathPowHalf);
8649 827 : } else if (exponent == -0.5) {
8650 : HValue* one = graph()->GetConstant1();
8651 : HInstruction* sqrt = AddUncasted<HUnaryMathOperation>(
8652 46 : left, kMathPowHalf);
8653 : // MathPowHalf doesn't have side effects so there's no need for
8654 : // an environment simulation here.
8655 : DCHECK(!sqrt->HasObservableSideEffects());
8656 46 : result = NewUncasted<HDiv>(one, sqrt);
8657 781 : } else if (exponent == 2.0) {
8658 43 : result = NewUncasted<HMul>(left, left);
8659 : }
8660 : }
8661 :
8662 1129 : if (result == NULL) {
8663 991 : result = NewUncasted<HPower>(left, right);
8664 : }
8665 1129 : ast_context()->ReturnInstruction(result, ast_id);
8666 1129 : return true;
8667 : }
8668 : break;
8669 : case kMathMax:
8670 : case kMathMin:
8671 1800 : if (argument_count == 3) {
8672 : HValue* right = Pop();
8673 : HValue* left = Pop();
8674 : Drop(2); // Receiver and function.
8675 : HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin
8676 1750 : : HMathMinMax::kMathMax;
8677 1750 : HInstruction* result = NewUncasted<HMathMinMax>(left, right, op);
8678 1750 : ast_context()->ReturnInstruction(result, ast_id);
8679 1750 : return true;
8680 : }
8681 : break;
8682 : case kMathImul:
8683 30 : if (argument_count == 3) {
8684 : HValue* right = Pop();
8685 : HValue* left = Pop();
8686 : Drop(2); // Receiver and function.
8687 : HInstruction* result =
8688 60 : HMul::NewImul(isolate(), zone(), context(), left, right);
8689 30 : ast_context()->ReturnInstruction(result, ast_id);
8690 30 : return true;
8691 : }
8692 : break;
8693 : case kArrayPop: {
8694 185 : if (!CanInlineArrayResizeOperation(receiver_map)) return false;
8695 : ElementsKind elements_kind = receiver_map->elements_kind();
8696 :
8697 : Drop(args_count_no_receiver);
8698 : HValue* result;
8699 : HValue* reduced_length;
8700 : HValue* receiver = Pop();
8701 :
8702 144 : HValue* checked_object = AddCheckMap(receiver, receiver_map);
8703 : HValue* length =
8704 : Add<HLoadNamedField>(checked_object, nullptr,
8705 144 : HObjectAccess::ForArrayLength(elements_kind));
8706 :
8707 : Drop(1); // Function.
8708 :
8709 : { NoObservableSideEffectsScope scope(this);
8710 : IfBuilder length_checker(this);
8711 :
8712 : HValue* bounds_check = length_checker.If<HCompareNumericAndBranch>(
8713 144 : length, graph()->GetConstant0(), Token::EQ);
8714 144 : length_checker.Then();
8715 :
8716 282 : if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined());
8717 :
8718 : length_checker.Else();
8719 : HValue* elements = AddLoadElements(checked_object);
8720 : // Ensure that we aren't popping from a copy-on-write array.
8721 144 : if (IsFastSmiOrObjectElementsKind(elements_kind)) {
8722 : elements = BuildCopyElementsOnWrite(checked_object, elements,
8723 121 : elements_kind, length);
8724 : }
8725 144 : reduced_length = AddUncasted<HSub>(length, graph()->GetConstant1());
8726 : result = AddElementAccess(elements, reduced_length, nullptr,
8727 144 : bounds_check, nullptr, elements_kind, LOAD);
8728 : HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind)
8729 : ? graph()->GetConstantHole()
8730 265 : : Add<HConstant>(HConstant::kHoleNaN);
8731 144 : if (IsFastSmiOrObjectElementsKind(elements_kind)) {
8732 : elements_kind = FAST_HOLEY_ELEMENTS;
8733 : }
8734 : AddElementAccess(elements, reduced_length, hole, bounds_check, nullptr,
8735 144 : elements_kind, STORE);
8736 : Add<HStoreNamedField>(
8737 : checked_object, HObjectAccess::ForArrayLength(elements_kind),
8738 144 : reduced_length, STORE_TO_INITIALIZED_ENTRY);
8739 :
8740 144 : if (!ast_context()->IsEffect()) Push(result);
8741 :
8742 144 : length_checker.End();
8743 : }
8744 144 : result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top();
8745 144 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
8746 144 : if (!ast_context()->IsEffect()) Drop(1);
8747 :
8748 144 : ast_context()->ReturnValue(result);
8749 144 : return true;
8750 : }
8751 : case kArrayPush: {
8752 2362 : if (!CanInlineArrayResizeOperation(receiver_map)) return false;
8753 : ElementsKind elements_kind = receiver_map->elements_kind();
8754 :
8755 : // If there may be elements accessors in the prototype chain, the fast
8756 : // inlined version can't be used.
8757 2248 : if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false;
8758 : // If there currently can be no elements accessors on the prototype chain,
8759 : // it doesn't mean that there won't be any later. Install a full prototype
8760 : // chain check to trap element accessors being installed on the prototype
8761 : // chain, which would cause elements to go to dictionary mode and result
8762 : // in a map change.
8763 : Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype()));
8764 2243 : BuildCheckPrototypeMaps(prototype, Handle<JSObject>());
8765 :
8766 : // Protect against adding elements to the Array prototype, which needs to
8767 : // route through appropriate bottlenecks.
8768 4473 : if (isolate()->IsFastArrayConstructorPrototypeChainIntact() &&
8769 : !prototype->IsJSArray()) {
8770 : return false;
8771 : }
8772 :
8773 : const int argc = args_count_no_receiver;
8774 2072 : if (argc != 1) return false;
8775 :
8776 : HValue* value_to_push = Pop();
8777 : HValue* array = Pop();
8778 : Drop(1); // Drop function.
8779 :
8780 : HInstruction* new_size = NULL;
8781 : HValue* length = NULL;
8782 :
8783 : {
8784 : NoObservableSideEffectsScope scope(this);
8785 :
8786 : length = Add<HLoadNamedField>(
8787 2067 : array, nullptr, HObjectAccess::ForArrayLength(elements_kind));
8788 :
8789 2067 : new_size = AddUncasted<HAdd>(length, graph()->GetConstant1());
8790 :
8791 2067 : bool is_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
8792 2067 : HValue* checked_array = Add<HCheckMaps>(array, receiver_map);
8793 : BuildUncheckedMonomorphicElementAccess(
8794 : checked_array, length, value_to_push, is_array, elements_kind,
8795 2067 : STORE, NEVER_RETURN_HOLE, STORE_AND_GROW_NO_TRANSITION);
8796 :
8797 2067 : if (!ast_context()->IsEffect()) Push(new_size);
8798 2067 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
8799 2067 : if (!ast_context()->IsEffect()) Drop(1);
8800 : }
8801 :
8802 2067 : ast_context()->ReturnValue(new_size);
8803 2067 : return true;
8804 : }
8805 : case kArrayShift: {
8806 148 : if (!CanInlineArrayResizeOperation(receiver_map)) return false;
8807 123 : if (!NoElementsInPrototypeChain(receiver_map)) return false;
8808 : ElementsKind kind = receiver_map->elements_kind();
8809 :
8810 : // If there may be elements accessors in the prototype chain, the fast
8811 : // inlined version can't be used.
8812 108 : if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false;
8813 :
8814 : // If there currently can be no elements accessors on the prototype chain,
8815 : // it doesn't mean that there won't be any later. Install a full prototype
8816 : // chain check to trap element accessors being installed on the prototype
8817 : // chain, which would cause elements to go to dictionary mode and result
8818 : // in a map change.
8819 : BuildCheckPrototypeMaps(
8820 : handle(JSObject::cast(receiver_map->prototype()), isolate()),
8821 108 : Handle<JSObject>::null(), true);
8822 :
8823 : // Threshold for fast inlined Array.shift().
8824 108 : HConstant* inline_threshold = Add<HConstant>(static_cast<int32_t>(16));
8825 :
8826 : Drop(args_count_no_receiver);
8827 : HValue* result;
8828 : HValue* receiver = Pop();
8829 108 : HValue* checked_object = AddCheckMap(receiver, receiver_map);
8830 : HValue* length = Add<HLoadNamedField>(
8831 108 : receiver, checked_object, HObjectAccess::ForArrayLength(kind));
8832 :
8833 : Drop(1); // Function.
8834 : {
8835 : NoObservableSideEffectsScope scope(this);
8836 :
8837 : IfBuilder if_lengthiszero(this);
8838 : HValue* lengthiszero = if_lengthiszero.If<HCompareNumericAndBranch>(
8839 108 : length, graph()->GetConstant0(), Token::EQ);
8840 108 : if_lengthiszero.Then();
8841 : {
8842 178 : if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined());
8843 : }
8844 : if_lengthiszero.Else();
8845 : {
8846 : HValue* elements = AddLoadElements(receiver);
8847 :
8848 : // Check if we can use the fast inlined Array.shift().
8849 : IfBuilder if_inline(this);
8850 : if_inline.If<HCompareNumericAndBranch>(
8851 108 : length, inline_threshold, Token::LTE);
8852 108 : if (IsFastSmiOrObjectElementsKind(kind)) {
8853 : // We cannot handle copy-on-write backing stores here.
8854 : if_inline.AndIf<HCompareMap>(
8855 : elements, isolate()->factory()->fixed_array_map());
8856 : }
8857 108 : if_inline.Then();
8858 : {
8859 : // Remember the result.
8860 108 : if (!ast_context()->IsEffect()) {
8861 : Push(AddElementAccess(elements, graph()->GetConstant0(), nullptr,
8862 70 : lengthiszero, nullptr, kind, LOAD));
8863 : }
8864 :
8865 : // Compute the new length.
8866 : HValue* new_length = AddUncasted<HSub>(
8867 108 : length, graph()->GetConstant1());
8868 : new_length->ClearFlag(HValue::kCanOverflow);
8869 :
8870 : // Copy the remaining elements.
8871 108 : LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement);
8872 : {
8873 : HValue* new_key = loop.BeginBody(
8874 108 : graph()->GetConstant0(), new_length, Token::LT);
8875 108 : HValue* key = AddUncasted<HAdd>(new_key, graph()->GetConstant1());
8876 : key->ClearFlag(HValue::kCanOverflow);
8877 : ElementsKind copy_kind =
8878 108 : kind == FAST_HOLEY_SMI_ELEMENTS ? FAST_HOLEY_ELEMENTS : kind;
8879 : HValue* element =
8880 : AddUncasted<HLoadKeyed>(elements, key, lengthiszero, nullptr,
8881 108 : copy_kind, ALLOW_RETURN_HOLE);
8882 : HStoreKeyed* store = Add<HStoreKeyed>(elements, new_key, element,
8883 108 : nullptr, copy_kind);
8884 : store->SetFlag(HValue::kTruncatingToNumber);
8885 : }
8886 108 : loop.EndBody();
8887 :
8888 : // Put a hole at the end.
8889 : HValue* hole = IsFastSmiOrObjectElementsKind(kind)
8890 : ? graph()->GetConstantHole()
8891 211 : : Add<HConstant>(HConstant::kHoleNaN);
8892 108 : if (IsFastSmiOrObjectElementsKind(kind)) kind = FAST_HOLEY_ELEMENTS;
8893 : Add<HStoreKeyed>(elements, new_length, hole, nullptr, kind,
8894 108 : INITIALIZING_STORE);
8895 :
8896 : // Remember new length.
8897 : Add<HStoreNamedField>(
8898 : receiver, HObjectAccess::ForArrayLength(kind),
8899 108 : new_length, STORE_TO_INITIALIZED_ENTRY);
8900 : }
8901 : if_inline.Else();
8902 : {
8903 108 : Add<HPushArguments>(receiver);
8904 : result = AddInstruction(NewCallConstantFunction(
8905 108 : function, 1, TailCallMode::kDisallow, TailCallMode::kDisallow));
8906 108 : if (!ast_context()->IsEffect()) Push(result);
8907 : }
8908 108 : if_inline.End();
8909 : }
8910 108 : if_lengthiszero.End();
8911 : }
8912 108 : result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top();
8913 108 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
8914 108 : if (!ast_context()->IsEffect()) Drop(1);
8915 108 : ast_context()->ReturnValue(result);
8916 108 : return true;
8917 : }
8918 : case kArrayIndexOf:
8919 : case kArrayLastIndexOf: {
8920 191 : if (receiver_map.is_null()) return false;
8921 191 : if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false;
8922 191 : if (!receiver_map->prototype()->IsJSObject()) return false;
8923 : ElementsKind kind = receiver_map->elements_kind();
8924 185 : if (!IsFastElementsKind(kind)) return false;
8925 185 : if (argument_count != 2) return false;
8926 170 : if (!receiver_map->is_extensible()) return false;
8927 :
8928 : // If there may be elements accessors in the prototype chain, the fast
8929 : // inlined version can't be used.
8930 170 : if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false;
8931 :
8932 : // If there currently can be no elements accessors on the prototype chain,
8933 : // it doesn't mean that there won't be any later. Install a full prototype
8934 : // chain check to trap element accessors being installed on the prototype
8935 : // chain, which would cause elements to go to dictionary mode and result
8936 : // in a map change.
8937 : BuildCheckPrototypeMaps(
8938 : handle(JSObject::cast(receiver_map->prototype()), isolate()),
8939 170 : Handle<JSObject>::null());
8940 :
8941 : HValue* search_element = Pop();
8942 : HValue* receiver = Pop();
8943 : Drop(1); // Drop function.
8944 :
8945 : ArrayIndexOfMode mode = (id == kArrayIndexOf)
8946 170 : ? kFirstIndexOf : kLastIndexOf;
8947 170 : HValue* index = BuildArrayIndexOf(receiver, search_element, kind, mode);
8948 :
8949 170 : if (!ast_context()->IsEffect()) Push(index);
8950 170 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
8951 170 : if (!ast_context()->IsEffect()) Drop(1);
8952 170 : ast_context()->ReturnValue(index);
8953 170 : return true;
8954 : }
8955 : default:
8956 : // Not yet supported for inlining.
8957 : break;
8958 : }
8959 : return false;
8960 : }
8961 :
8962 :
8963 567930 : bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr,
8964 : HValue* receiver) {
8965 189310 : if (V8_UNLIKELY(FLAG_runtime_stats)) return false;
8966 : Handle<JSFunction> function = expr->target();
8967 189310 : int argc = expr->arguments()->length();
8968 : SmallMapList receiver_maps;
8969 : return TryInlineApiCall(function, receiver, &receiver_maps, argc, expr->id(),
8970 189310 : kCallApiFunction, expr->tail_call_mode());
8971 : }
8972 :
8973 :
8974 59301 : bool HOptimizedGraphBuilder::TryInlineApiMethodCall(
8975 118602 : Call* expr,
8976 : HValue* receiver,
8977 : SmallMapList* receiver_maps) {
8978 59301 : if (V8_UNLIKELY(FLAG_runtime_stats)) return false;
8979 : Handle<JSFunction> function = expr->target();
8980 59301 : int argc = expr->arguments()->length();
8981 : return TryInlineApiCall(function, receiver, receiver_maps, argc, expr->id(),
8982 59301 : kCallApiMethod, expr->tail_call_mode());
8983 : }
8984 :
8985 3069 : bool HOptimizedGraphBuilder::TryInlineApiGetter(Handle<Object> function,
8986 : Handle<Map> receiver_map,
8987 : BailoutId ast_id) {
8988 3069 : if (V8_UNLIKELY(FLAG_runtime_stats)) return false;
8989 6138 : SmallMapList receiver_maps(1, zone());
8990 : receiver_maps.Add(receiver_map, zone());
8991 : return TryInlineApiCall(function,
8992 : NULL, // Receiver is on expression stack.
8993 : &receiver_maps, 0, ast_id, kCallApiGetter,
8994 3069 : TailCallMode::kDisallow);
8995 : }
8996 :
8997 246 : bool HOptimizedGraphBuilder::TryInlineApiSetter(Handle<Object> function,
8998 : Handle<Map> receiver_map,
8999 : BailoutId ast_id) {
9000 492 : SmallMapList receiver_maps(1, zone());
9001 : receiver_maps.Add(receiver_map, zone());
9002 : return TryInlineApiCall(function,
9003 : NULL, // Receiver is on expression stack.
9004 : &receiver_maps, 1, ast_id, kCallApiSetter,
9005 246 : TailCallMode::kDisallow);
9006 : }
9007 :
9008 251926 : bool HOptimizedGraphBuilder::TryInlineApiCall(
9009 : Handle<Object> function, HValue* receiver, SmallMapList* receiver_maps,
9010 : int argc, BailoutId ast_id, ApiCallType call_type,
9011 11220 : TailCallMode syntactic_tail_call_mode) {
9012 251926 : if (V8_UNLIKELY(FLAG_runtime_stats)) return false;
9013 503837 : if (function->IsJSFunction() &&
9014 : Handle<JSFunction>::cast(function)->context()->native_context() !=
9015 302693 : top_info()->closure()->context()->native_context()) {
9016 : return false;
9017 : }
9018 251875 : if (argc > CallApiCallbackStub::kArgMax) {
9019 : return false;
9020 : }
9021 :
9022 251848 : CallOptimization optimization(function);
9023 251848 : if (!optimization.is_simple_api_call()) return false;
9024 : Handle<Map> holder_map;
9025 16547 : for (int i = 0; i < receiver_maps->length(); ++i) {
9026 : auto map = receiver_maps->at(i);
9027 : // Don't inline calls to receivers requiring accesschecks.
9028 2662 : if (map->is_access_check_needed()) return false;
9029 : }
9030 11223 : if (call_type == kCallApiFunction) {
9031 : // Cannot embed a direct reference to the global proxy map
9032 : // as it maybe dropped on deserialization.
9033 8561 : CHECK(!isolate()->serializer_enabled());
9034 : DCHECK(function->IsJSFunction());
9035 : DCHECK_EQ(0, receiver_maps->length());
9036 : receiver_maps->Add(
9037 : handle(Handle<JSFunction>::cast(function)->global_proxy()->map()),
9038 : zone());
9039 : }
9040 : CallOptimization::HolderLookup holder_lookup =
9041 11223 : CallOptimization::kHolderNotFound;
9042 : Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType(
9043 11223 : receiver_maps->first(), &holder_lookup);
9044 11223 : if (holder_lookup == CallOptimization::kHolderNotFound) return false;
9045 :
9046 11220 : if (FLAG_trace_inlining) {
9047 0 : PrintF("Inlining api function ");
9048 0 : function->ShortPrint();
9049 0 : PrintF("\n");
9050 : }
9051 :
9052 : bool is_function = false;
9053 : bool is_store = false;
9054 11220 : switch (call_type) {
9055 : case kCallApiFunction:
9056 : case kCallApiMethod:
9057 : // Need to check that none of the receiver maps could have changed.
9058 11173 : Add<HCheckMaps>(receiver, receiver_maps);
9059 : // Need to ensure the chain between receiver and api_holder is intact.
9060 11173 : if (holder_lookup == CallOptimization::kHolderFound) {
9061 3 : AddCheckPrototypeMaps(api_holder, receiver_maps->first());
9062 : } else {
9063 : DCHECK_EQ(holder_lookup, CallOptimization::kHolderIsReceiver);
9064 : }
9065 : // Includes receiver.
9066 11173 : PushArgumentsFromEnvironment(argc + 1);
9067 : is_function = true;
9068 11173 : break;
9069 : case kCallApiGetter:
9070 : // Receiver and prototype chain cannot have changed.
9071 : DCHECK_EQ(0, argc);
9072 : DCHECK_NULL(receiver);
9073 : // Receiver is on expression stack.
9074 : receiver = Pop();
9075 35 : Add<HPushArguments>(receiver);
9076 35 : break;
9077 : case kCallApiSetter:
9078 : {
9079 : is_store = true;
9080 : // Receiver and prototype chain cannot have changed.
9081 : DCHECK_EQ(1, argc);
9082 : DCHECK_NULL(receiver);
9083 : // Receiver and value are on expression stack.
9084 : HValue* value = Pop();
9085 : receiver = Pop();
9086 12 : Add<HPushArguments>(receiver, value);
9087 12 : break;
9088 : }
9089 : }
9090 :
9091 : HValue* holder = NULL;
9092 11220 : switch (holder_lookup) {
9093 : case CallOptimization::kHolderFound:
9094 3 : holder = Add<HConstant>(api_holder);
9095 3 : break;
9096 : case CallOptimization::kHolderIsReceiver:
9097 : holder = receiver;
9098 11217 : break;
9099 : case CallOptimization::kHolderNotFound:
9100 0 : UNREACHABLE();
9101 : break;
9102 : }
9103 : Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
9104 : Handle<Object> call_data_obj(api_call_info->data(), isolate());
9105 11220 : HValue* call_data = Add<HConstant>(call_data_obj);
9106 : ApiFunction fun(v8::ToCData<Address>(api_call_info->callback()));
9107 : ExternalReference ref = ExternalReference(&fun,
9108 : ExternalReference::DIRECT_API_CALL,
9109 11220 : isolate());
9110 11220 : HValue* api_function_address = Add<HConstant>(ExternalReference(ref));
9111 :
9112 11220 : HValue* op_vals[] = {Add<HConstant>(function), call_data, holder,
9113 11220 : api_function_address};
9114 :
9115 : HInstruction* call = nullptr;
9116 11220 : CHECK(argc <= CallApiCallbackStub::kArgMax);
9117 11220 : if (!is_function) {
9118 : CallApiCallbackStub stub(isolate(), is_store,
9119 47 : !optimization.is_constant_call());
9120 47 : Handle<Code> code = stub.GetCode();
9121 47 : HConstant* code_value = Add<HConstant>(code);
9122 : call = New<HCallWithDescriptor>(
9123 : code_value, argc + 1, stub.GetCallInterfaceDescriptor(),
9124 47 : Vector<HValue*>(op_vals, arraysize(op_vals)), syntactic_tail_call_mode);
9125 : } else {
9126 : CallApiCallbackStub stub(isolate(), argc, false);
9127 11173 : Handle<Code> code = stub.GetCode();
9128 11173 : HConstant* code_value = Add<HConstant>(code);
9129 : call = New<HCallWithDescriptor>(
9130 : code_value, argc + 1, stub.GetCallInterfaceDescriptor(),
9131 11173 : Vector<HValue*>(op_vals, arraysize(op_vals)), syntactic_tail_call_mode);
9132 : Drop(1); // Drop function.
9133 : }
9134 :
9135 11220 : ast_context()->ReturnInstruction(call, ast_id);
9136 11220 : return true;
9137 : }
9138 :
9139 :
9140 10579 : void HOptimizedGraphBuilder::HandleIndirectCall(Call* expr, HValue* function,
9141 10444 : int arguments_count) {
9142 : Handle<JSFunction> known_function;
9143 5357 : int args_count_no_receiver = arguments_count - 1;
9144 16071 : if (function->IsConstant() &&
9145 6941 : HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
9146 : known_function =
9147 396 : Handle<JSFunction>::cast(HConstant::cast(function)->handle(isolate()));
9148 792 : if (TryInlineBuiltinMethodCall(known_function, Handle<Map>(), expr->id(),
9149 396 : args_count_no_receiver)) {
9150 25 : if (FLAG_trace_inlining) {
9151 0 : PrintF("Inlining builtin ");
9152 0 : known_function->ShortPrint();
9153 0 : PrintF("\n");
9154 : }
9155 : return;
9156 : }
9157 :
9158 371 : if (TryInlineIndirectCall(known_function, expr, args_count_no_receiver)) {
9159 : return;
9160 : }
9161 : }
9162 :
9163 : TailCallMode syntactic_tail_call_mode = expr->tail_call_mode();
9164 : TailCallMode tail_call_mode =
9165 5222 : function_state()->ComputeTailCallMode(syntactic_tail_call_mode);
9166 :
9167 5222 : PushArgumentsFromEnvironment(arguments_count);
9168 : HInvokeFunction* call =
9169 : New<HInvokeFunction>(function, known_function, arguments_count,
9170 5222 : syntactic_tail_call_mode, tail_call_mode);
9171 : Drop(1); // Function
9172 10444 : ast_context()->ReturnInstruction(call, expr->id());
9173 : }
9174 :
9175 :
9176 96690 : bool HOptimizedGraphBuilder::TryIndirectCall(Call* expr) {
9177 : DCHECK(expr->expression()->IsProperty());
9178 :
9179 91405 : if (!expr->IsMonomorphic()) {
9180 : return false;
9181 : }
9182 90407 : Handle<Map> function_map = expr->GetReceiverTypes()->first();
9183 104294 : if (function_map->instance_type() != JS_FUNCTION_TYPE ||
9184 : !expr->target()->shared()->HasBuiltinFunctionId()) {
9185 : return false;
9186 : }
9187 :
9188 6730 : switch (expr->target()->shared()->builtin_function_id()) {
9189 : case kFunctionCall: {
9190 5285 : if (expr->arguments()->length() == 0) return false;
9191 5264 : BuildFunctionCall(expr);
9192 5264 : return true;
9193 : }
9194 : case kFunctionApply: {
9195 : // For .apply, only the pattern f.apply(receiver, arguments)
9196 : // is supported.
9197 325 : if (!CanBeFunctionApplyArguments(expr)) return false;
9198 :
9199 231 : BuildFunctionApply(expr);
9200 231 : return true;
9201 : }
9202 : default: { return false; }
9203 : }
9204 : UNREACHABLE();
9205 : }
9206 :
9207 :
9208 : // f.apply(...)
9209 965 : void HOptimizedGraphBuilder::BuildFunctionApply(Call* expr) {
9210 : ZoneList<Expression*>* args = expr->arguments();
9211 462 : CHECK_ALIVE(VisitForValue(args->at(0)));
9212 : HValue* receiver = Pop(); // receiver
9213 : HValue* function = Pop(); // f
9214 : Drop(1); // apply
9215 :
9216 : // Make sure the arguments object is live.
9217 462 : VariableProxy* arg_two = args->at(1)->AsVariableProxy();
9218 231 : LookupAndMakeLive(arg_two->var());
9219 :
9220 462 : Handle<Map> function_map = expr->GetReceiverTypes()->first();
9221 231 : HValue* checked_function = AddCheckMap(function, function_map);
9222 :
9223 231 : if (function_state()->outer() == NULL) {
9224 : TailCallMode syntactic_tail_call_mode = expr->tail_call_mode();
9225 : TailCallMode tail_call_mode =
9226 136 : function_state()->ComputeTailCallMode(syntactic_tail_call_mode);
9227 :
9228 136 : HInstruction* elements = Add<HArgumentsElements>(false);
9229 136 : HInstruction* length = Add<HArgumentsLength>(elements);
9230 136 : HValue* wrapped_receiver = BuildWrapReceiver(receiver, checked_function);
9231 : HInstruction* result = New<HApplyArguments>(
9232 136 : function, wrapped_receiver, length, elements, tail_call_mode);
9233 272 : ast_context()->ReturnInstruction(result, expr->id());
9234 : } else {
9235 : // We are inside inlined function and we know exactly what is inside
9236 : // arguments object. But we need to be able to materialize at deopt.
9237 : DCHECK_EQ(environment()->arguments_environment()->parameter_count(),
9238 : function_state()->entry()->arguments_object()->arguments_count());
9239 95 : HArgumentsObject* args = function_state()->entry()->arguments_object();
9240 : const ZoneList<HValue*>* arguments_values = args->arguments_values();
9241 95 : int arguments_count = arguments_values->length();
9242 95 : Push(function);
9243 95 : Push(BuildWrapReceiver(receiver, checked_function));
9244 245 : for (int i = 1; i < arguments_count; i++) {
9245 150 : Push(arguments_values->at(i));
9246 : }
9247 95 : HandleIndirectCall(expr, function, arguments_count);
9248 : }
9249 : }
9250 :
9251 :
9252 : // f.call(...)
9253 21054 : void HOptimizedGraphBuilder::BuildFunctionCall(Call* expr) {
9254 : HValue* function = Top(); // f
9255 10528 : Handle<Map> function_map = expr->GetReceiverTypes()->first();
9256 5264 : HValue* checked_function = AddCheckMap(function, function_map);
9257 :
9258 : // f and call are on the stack in the unoptimized code
9259 : // during evaluation of the arguments.
9260 10530 : CHECK_ALIVE(VisitExpressions(expr->arguments()));
9261 :
9262 5262 : int args_length = expr->arguments()->length();
9263 5262 : int receiver_index = args_length - 1;
9264 : // Patch the receiver.
9265 : HValue* receiver = BuildWrapReceiver(
9266 5262 : environment()->ExpressionStackAt(receiver_index), checked_function);
9267 : environment()->SetExpressionStackAt(receiver_index, receiver);
9268 :
9269 : // Call must not be on the stack from now on.
9270 5262 : int call_index = args_length + 1;
9271 5262 : environment()->RemoveExpressionStackAt(call_index);
9272 :
9273 5262 : HandleIndirectCall(expr, function, args_length);
9274 : }
9275 :
9276 :
9277 202205 : HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function,
9278 : Handle<JSFunction> target) {
9279 : SharedFunctionInfo* shared = target->shared();
9280 396700 : if (is_sloppy(shared->language_mode()) && !shared->native()) {
9281 : // Cannot embed a direct reference to the global proxy
9282 : // as is it dropped on deserialization.
9283 341525 : CHECK(!isolate()->serializer_enabled());
9284 139320 : Handle<JSObject> global_proxy(target->context()->global_proxy());
9285 139320 : return Add<HConstant>(global_proxy);
9286 : }
9287 62885 : return graph()->GetConstantUndefined();
9288 : }
9289 :
9290 :
9291 170 : HValue* HOptimizedGraphBuilder::BuildArrayIndexOf(HValue* receiver,
9292 : HValue* search_element,
9293 : ElementsKind kind,
9294 : ArrayIndexOfMode mode) {
9295 : DCHECK(IsFastElementsKind(kind));
9296 :
9297 680 : NoObservableSideEffectsScope no_effects(this);
9298 :
9299 : HValue* elements = AddLoadElements(receiver);
9300 170 : HValue* length = AddLoadArrayLength(receiver, kind);
9301 :
9302 : HValue* initial;
9303 : HValue* terminating;
9304 : Token::Value token;
9305 : LoopBuilder::Direction direction;
9306 170 : if (mode == kFirstIndexOf) {
9307 : initial = graph()->GetConstant0();
9308 : terminating = length;
9309 : token = Token::LT;
9310 : direction = LoopBuilder::kPostIncrement;
9311 : } else {
9312 : DCHECK_EQ(kLastIndexOf, mode);
9313 : initial = length;
9314 : terminating = graph()->GetConstant0();
9315 : token = Token::GT;
9316 : direction = LoopBuilder::kPreDecrement;
9317 : }
9318 :
9319 170 : Push(graph()->GetConstantMinus1());
9320 170 : if (IsFastDoubleElementsKind(kind) || IsFastSmiElementsKind(kind)) {
9321 : // Make sure that we can actually compare numbers correctly below, see
9322 : // https://code.google.com/p/chromium/issues/detail?id=407946 for details.
9323 : search_element = AddUncasted<HForceRepresentation>(
9324 : search_element, IsFastSmiElementsKind(kind) ? Representation::Smi()
9325 85 : : Representation::Double());
9326 :
9327 85 : LoopBuilder loop(this, context(), direction);
9328 : {
9329 85 : HValue* index = loop.BeginBody(initial, terminating, token);
9330 : HValue* element = AddUncasted<HLoadKeyed>(
9331 85 : elements, index, nullptr, nullptr, kind, ALLOW_RETURN_HOLE);
9332 : IfBuilder if_issame(this);
9333 : if_issame.If<HCompareNumericAndBranch>(element, search_element,
9334 85 : Token::EQ_STRICT);
9335 85 : if_issame.Then();
9336 : {
9337 : Drop(1);
9338 85 : Push(index);
9339 85 : loop.Break();
9340 : }
9341 85 : if_issame.End();
9342 : }
9343 85 : loop.EndBody();
9344 : } else {
9345 : IfBuilder if_isstring(this);
9346 85 : if_isstring.If<HIsStringAndBranch>(search_element);
9347 85 : if_isstring.Then();
9348 : {
9349 85 : LoopBuilder loop(this, context(), direction);
9350 : {
9351 85 : HValue* index = loop.BeginBody(initial, terminating, token);
9352 : HValue* element = AddUncasted<HLoadKeyed>(
9353 85 : elements, index, nullptr, nullptr, kind, ALLOW_RETURN_HOLE);
9354 : IfBuilder if_issame(this);
9355 85 : if_issame.If<HIsStringAndBranch>(element);
9356 : if_issame.AndIf<HStringCompareAndBranch>(
9357 : element, search_element, Token::EQ_STRICT);
9358 85 : if_issame.Then();
9359 : {
9360 : Drop(1);
9361 85 : Push(index);
9362 85 : loop.Break();
9363 : }
9364 85 : if_issame.End();
9365 : }
9366 85 : loop.EndBody();
9367 : }
9368 : if_isstring.Else();
9369 : {
9370 : IfBuilder if_isnumber(this);
9371 85 : if_isnumber.If<HIsSmiAndBranch>(search_element);
9372 : if_isnumber.OrIf<HCompareMap>(
9373 : search_element, isolate()->factory()->heap_number_map());
9374 85 : if_isnumber.Then();
9375 : {
9376 : HValue* search_number =
9377 : AddUncasted<HForceRepresentation>(search_element,
9378 85 : Representation::Double());
9379 85 : LoopBuilder loop(this, context(), direction);
9380 : {
9381 85 : HValue* index = loop.BeginBody(initial, terminating, token);
9382 : HValue* element = AddUncasted<HLoadKeyed>(
9383 85 : elements, index, nullptr, nullptr, kind, ALLOW_RETURN_HOLE);
9384 :
9385 : IfBuilder if_element_isnumber(this);
9386 85 : if_element_isnumber.If<HIsSmiAndBranch>(element);
9387 : if_element_isnumber.OrIf<HCompareMap>(
9388 : element, isolate()->factory()->heap_number_map());
9389 85 : if_element_isnumber.Then();
9390 : {
9391 : HValue* number =
9392 : AddUncasted<HForceRepresentation>(element,
9393 85 : Representation::Double());
9394 : IfBuilder if_issame(this);
9395 : if_issame.If<HCompareNumericAndBranch>(
9396 85 : number, search_number, Token::EQ_STRICT);
9397 85 : if_issame.Then();
9398 : {
9399 : Drop(1);
9400 85 : Push(index);
9401 85 : loop.Break();
9402 : }
9403 85 : if_issame.End();
9404 : }
9405 85 : if_element_isnumber.End();
9406 : }
9407 85 : loop.EndBody();
9408 : }
9409 : if_isnumber.Else();
9410 : {
9411 85 : LoopBuilder loop(this, context(), direction);
9412 : {
9413 85 : HValue* index = loop.BeginBody(initial, terminating, token);
9414 : HValue* element = AddUncasted<HLoadKeyed>(
9415 85 : elements, index, nullptr, nullptr, kind, ALLOW_RETURN_HOLE);
9416 : IfBuilder if_issame(this);
9417 : if_issame.If<HCompareObjectEqAndBranch>(
9418 85 : element, search_element);
9419 85 : if_issame.Then();
9420 : {
9421 : Drop(1);
9422 85 : Push(index);
9423 85 : loop.Break();
9424 : }
9425 85 : if_issame.End();
9426 : }
9427 85 : loop.EndBody();
9428 : }
9429 85 : if_isnumber.End();
9430 : }
9431 85 : if_isstring.End();
9432 : }
9433 :
9434 170 : return Pop();
9435 : }
9436 :
9437 : template <class T>
9438 209261 : bool HOptimizedGraphBuilder::TryHandleArrayCall(T* expr, HValue* function) {
9439 416546 : if (!array_function().is_identical_to(expr->target())) {
9440 : return false;
9441 : }
9442 :
9443 : Handle<AllocationSite> site = expr->allocation_site();
9444 2881 : if (site.is_null()) return false;
9445 :
9446 615 : Add<HCheckValue>(function, array_function());
9447 :
9448 615 : int arguments_count = expr->arguments()->length();
9449 615 : if (TryInlineArrayCall(expr, arguments_count, site)) return true;
9450 :
9451 : HInstruction* call = PreProcessCall(New<HCallNewArray>(
9452 373 : function, arguments_count + 1, site->GetElementsKind(), site));
9453 373 : if (expr->IsCall()) Drop(1);
9454 746 : ast_context()->ReturnInstruction(call, expr->id());
9455 :
9456 373 : return true;
9457 : }
9458 :
9459 :
9460 114898 : bool HOptimizedGraphBuilder::CanBeFunctionApplyArguments(Call* expr) {
9461 : ZoneList<Expression*>* args = expr->arguments();
9462 114898 : if (args->length() != 2) return false;
9463 16767 : VariableProxy* arg_two = args->at(1)->AsVariableProxy();
9464 14300 : if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
9465 2467 : HValue* arg_two_value = environment()->Lookup(arg_two->var());
9466 2467 : if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
9467 : DCHECK_NOT_NULL(current_info()->scope()->arguments());
9468 264 : return true;
9469 : }
9470 :
9471 :
9472 6473234 : void HOptimizedGraphBuilder::VisitCall(Call* expr) {
9473 : DCHECK(!HasStackOverflow());
9474 : DCHECK(current_block() != NULL);
9475 : DCHECK(current_block()->HasPredecessor());
9476 3107847 : if (!is_tracking_positions()) SetSourcePosition(expr->position());
9477 : Expression* callee = expr->expression();
9478 652215 : int argument_count = expr->arguments()->length() + 1; // Plus receiver.
9479 : HInstruction* call = NULL;
9480 :
9481 : TailCallMode syntactic_tail_call_mode = expr->tail_call_mode();
9482 : TailCallMode tail_call_mode =
9483 652215 : function_state()->ComputeTailCallMode(syntactic_tail_call_mode);
9484 :
9485 1372376 : Property* prop = callee->AsProperty();
9486 652214 : if (prop != NULL) {
9487 665735 : CHECK_ALIVE(VisitForValue(prop->obj()));
9488 : HValue* receiver = Top();
9489 :
9490 : SmallMapList* maps;
9491 207667 : ComputeReceiverTypes(expr, receiver, &maps, this);
9492 :
9493 414911 : if (prop->key()->IsPropertyName() && maps->length() > 0) {
9494 98413 : Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
9495 196826 : PropertyAccessInfo info(this, LOAD, maps->first(), name);
9496 98413 : if (!info.CanAccessAsMonomorphic(maps)) {
9497 1689 : HandlePolymorphicCallNamed(expr, receiver, maps, name);
9498 1689 : return;
9499 : }
9500 : }
9501 : HValue* key = NULL;
9502 205978 : if (!prop->key()->IsPropertyName()) {
9503 1269 : CHECK_ALIVE(VisitForValue(prop->key()));
9504 : key = Pop();
9505 : }
9506 :
9507 617934 : CHECK_ALIVE(PushLoad(prop, receiver, key));
9508 : HValue* function = Pop();
9509 :
9510 617934 : if (function->IsConstant() &&
9511 388890 : HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
9512 : // Push the function under the receiver.
9513 : environment()->SetExpressionStackAt(0, function);
9514 91405 : Push(receiver);
9515 :
9516 : Handle<JSFunction> known_function = Handle<JSFunction>::cast(
9517 91405 : HConstant::cast(function)->handle(isolate()));
9518 : expr->set_target(known_function);
9519 :
9520 132394 : if (TryIndirectCall(expr)) return;
9521 257708 : CHECK_ALIVE(VisitExpressions(expr->arguments()));
9522 :
9523 256666 : Handle<Map> map = maps->length() == 1 ? maps->first() : Handle<Map>();
9524 85888 : if (TryInlineBuiltinMethodCall(known_function, map, expr->id(),
9525 85888 : expr->arguments()->length())) {
9526 26587 : if (FLAG_trace_inlining) {
9527 0 : PrintF("Inlining builtin ");
9528 0 : known_function->ShortPrint();
9529 0 : PrintF("\n");
9530 : }
9531 : return;
9532 : }
9533 59301 : if (TryInlineApiMethodCall(expr, receiver, maps)) return;
9534 :
9535 : // Wrap the receiver if necessary.
9536 113372 : if (NeedsWrapping(maps->first(), known_function)) {
9537 : // Since HWrapReceiver currently cannot actually wrap numbers and
9538 : // strings, use the regular call builtin for method calls to wrap
9539 : // the receiver.
9540 : // TODO(verwaest): Support creation of value wrappers directly in
9541 : // HWrapReceiver.
9542 : call = NewCallFunction(
9543 : function, argument_count, syntactic_tail_call_mode,
9544 9 : ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode);
9545 56677 : } else if (TryInlineCall(expr)) {
9546 : return;
9547 : } else {
9548 : call =
9549 : NewCallConstantFunction(known_function, argument_count,
9550 50407 : syntactic_tail_call_mode, tail_call_mode);
9551 : }
9552 :
9553 : } else {
9554 : ArgumentsAllowedFlag arguments_flag = ARGUMENTS_NOT_ALLOWED;
9555 114606 : if (CanBeFunctionApplyArguments(expr) && expr->is_uninitialized()) {
9556 : // We have to use EAGER deoptimization here because Deoptimizer::SOFT
9557 : // gets ignored by the always-opt flag, which leads to incorrect code.
9558 : Add<HDeoptimize>(
9559 : DeoptimizeReason::kInsufficientTypeFeedbackForCallWithArguments,
9560 26 : Deoptimizer::EAGER);
9561 : arguments_flag = ARGUMENTS_FAKED;
9562 : }
9563 :
9564 : // Push the function under the receiver.
9565 : environment()->SetExpressionStackAt(0, function);
9566 114573 : Push(receiver);
9567 :
9568 343702 : CHECK_ALIVE(VisitExpressions(expr->arguments(), arguments_flag));
9569 : call = NewCallFunction(function, argument_count, syntactic_tail_call_mode,
9570 : ConvertReceiverMode::kNotNullOrUndefined,
9571 114556 : tail_call_mode);
9572 : }
9573 164972 : PushArgumentsFromEnvironment(argument_count);
9574 :
9575 : } else {
9576 444534 : if (expr->is_possibly_eval()) {
9577 : return Bailout(kPossibleDirectCallToEval);
9578 : }
9579 :
9580 : // The function is on the stack in the unoptimized code during
9581 : // evaluation of the arguments.
9582 1333604 : CHECK_ALIVE(VisitForValue(expr->expression()));
9583 : HValue* function = Top();
9584 1333605 : if (function->IsConstant() &&
9585 769285 : HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
9586 162337 : Handle<Object> constant = HConstant::cast(function)->handle(isolate());
9587 : Handle<JSFunction> target = Handle<JSFunction>::cast(constant);
9588 : expr->SetKnownGlobalTarget(target);
9589 : }
9590 :
9591 : // Placeholder for the receiver.
9592 444535 : Push(graph()->GetConstantUndefined());
9593 1333547 : CHECK_ALIVE(VisitExpressions(expr->arguments()));
9594 :
9595 642450 : if (expr->IsMonomorphic() &&
9596 : !IsClassConstructor(expr->target()->shared()->kind())) {
9597 197968 : Add<HCheckValue>(function, expr->target());
9598 :
9599 : // Patch the global object on the stack by the expected receiver.
9600 197968 : HValue* receiver = ImplicitReceiverFor(function, expr->target());
9601 : const int receiver_index = argument_count - 1;
9602 : environment()->SetExpressionStackAt(receiver_index, receiver);
9603 :
9604 197968 : if (TryInlineBuiltinFunctionCall(expr)) {
9605 8658 : if (FLAG_trace_inlining) {
9606 0 : PrintF("Inlining builtin ");
9607 0 : expr->target()->ShortPrint();
9608 0 : PrintF("\n");
9609 : }
9610 : return;
9611 : }
9612 189310 : if (TryInlineApiFunctionCall(expr, receiver)) return;
9613 180752 : if (TryHandleArrayCall(expr, function)) return;
9614 180663 : if (TryInlineCall(expr)) return;
9615 :
9616 82744 : PushArgumentsFromEnvironment(argument_count);
9617 : call = NewCallConstantFunction(expr->target(), argument_count,
9618 82744 : syntactic_tail_call_mode, tail_call_mode);
9619 : } else {
9620 246509 : PushArgumentsFromEnvironment(argument_count);
9621 246508 : if (expr->is_uninitialized()) {
9622 : // We've never seen this call before, so let's have Crankshaft learn
9623 : // through the type vector.
9624 : call = NewCallFunctionViaIC(function, argument_count,
9625 : syntactic_tail_call_mode,
9626 : ConvertReceiverMode::kNullOrUndefined,
9627 243640 : tail_call_mode, expr->CallFeedbackICSlot());
9628 : } else {
9629 : call = NewCallFunction(
9630 : function, argument_count, syntactic_tail_call_mode,
9631 2868 : ConvertReceiverMode::kNullOrUndefined, tail_call_mode);
9632 : }
9633 : }
9634 : }
9635 :
9636 : Drop(1); // Drop the function.
9637 988450 : return ast_context()->ReturnInstruction(call, expr->id());
9638 : }
9639 :
9640 615 : bool HOptimizedGraphBuilder::TryInlineArrayCall(Expression* expression,
9641 : int argument_count,
9642 242 : Handle<AllocationSite> site) {
9643 615 : Handle<JSFunction> caller = current_info()->closure();
9644 615 : Handle<JSFunction> target = array_function();
9645 :
9646 615 : if (!site->CanInlineCall()) {
9647 103 : TraceInline(target, caller, "AllocationSite requested no inlining.");
9648 103 : return false;
9649 : }
9650 :
9651 512 : if (argument_count > 1) {
9652 38 : TraceInline(target, caller, "Too many arguments to inline.");
9653 38 : return false;
9654 : }
9655 :
9656 : int array_length = 0;
9657 : // Do not inline if the constant length argument is not a smi or outside the
9658 : // valid range for unrolled loop initialization.
9659 474 : if (argument_count == 1) {
9660 : HValue* argument = Top();
9661 376 : if (!argument->IsConstant()) {
9662 : TraceInline(target, caller,
9663 138 : "Dont inline [new] Array(n) where n isn't constant.");
9664 138 : return false;
9665 : }
9666 :
9667 476 : HConstant* constant_argument = HConstant::cast(argument);
9668 238 : if (!constant_argument->HasSmiValue()) {
9669 : TraceInline(target, caller,
9670 0 : "Constant length outside of valid inlining range.");
9671 0 : return false;
9672 : }
9673 : array_length = constant_argument->Integer32Value();
9674 238 : if (array_length < 0 || array_length > kElementLoopUnrollThreshold) {
9675 : TraceInline(target, caller,
9676 94 : "Constant length outside of valid inlining range.");
9677 94 : return false;
9678 : }
9679 : }
9680 :
9681 242 : TraceInline(target, caller, NULL);
9682 :
9683 1093 : NoObservableSideEffectsScope no_effects(this);
9684 :
9685 : // Register on the site for deoptimization if the transition feedback changes.
9686 242 : top_info()->dependencies()->AssumeTransitionStable(site);
9687 :
9688 : // Build the array.
9689 : ElementsKind kind = site->GetElementsKind();
9690 : HValue* capacity;
9691 : HValue* length;
9692 242 : if (array_length == 0) {
9693 : STATIC_ASSERT(0 < JSArray::kPreallocatedArrayElements);
9694 : const int initial_capacity = JSArray::kPreallocatedArrayElements;
9695 125 : capacity = Add<HConstant>(initial_capacity);
9696 : length = graph()->GetConstant0();
9697 : } else {
9698 : length = Top();
9699 : capacity = length;
9700 : kind = GetHoleyElementsKind(kind);
9701 : }
9702 :
9703 : // These HForceRepresentations are because we store these as fields in the
9704 : // objects we construct, and an int32-to-smi HChange could deopt. Accept
9705 : // the deopt possibility now, before allocation occurs.
9706 242 : length = AddUncasted<HForceRepresentation>(length, Representation::Smi());
9707 242 : capacity = AddUncasted<HForceRepresentation>(capacity, Representation::Smi());
9708 :
9709 : // Generate size calculation code here in order to make it dominate
9710 : // the JSArray allocation.
9711 242 : HValue* elements_size = BuildCalculateElementsSize(kind, capacity);
9712 :
9713 : // Bail out for large objects.
9714 242 : HValue* max_size = Add<HConstant>(kMaxRegularHeapObjectSize);
9715 242 : Add<HBoundsCheck>(elements_size, max_size);
9716 :
9717 : // Allocate (dealing with failure appropriately).
9718 : AllocationSiteMode mode = DONT_TRACK_ALLOCATION_SITE;
9719 242 : HAllocate* new_object = AllocateJSArrayObject(mode);
9720 :
9721 : // Fill in the fields: map, properties, length.
9722 242 : Handle<Map> map_constant(isolate()->get_initial_js_array_map(kind));
9723 242 : HValue* map = Add<HConstant>(map_constant);
9724 :
9725 : BuildJSArrayHeader(new_object, map,
9726 : nullptr, // set elements to empty fixed array
9727 242 : mode, kind, nullptr, length);
9728 :
9729 : // Allocate and initialize the elements.
9730 242 : HAllocate* elements = BuildAllocateElements(kind, elements_size);
9731 242 : BuildInitializeElementsHeader(elements, kind, capacity);
9732 242 : BuildFillElementsWithHole(elements, kind, graph()->GetConstant0(), capacity);
9733 :
9734 : // Set the elements.
9735 : Add<HStoreNamedField>(new_object, HObjectAccess::ForElementsPointer(),
9736 242 : elements);
9737 :
9738 242 : int args_to_drop = argument_count + (expression->IsCall() ? 2 : 1);
9739 : Drop(args_to_drop);
9740 242 : ast_context()->ReturnValue(new_object);
9741 : return true;
9742 : }
9743 :
9744 :
9745 : // Checks whether allocation using the given constructor can be inlined.
9746 15273 : static bool IsAllocationInlineable(Handle<JSFunction> constructor) {
9747 29086 : return constructor->has_initial_map() &&
9748 13778 : !IsDerivedConstructor(constructor->shared()->kind()) &&
9749 13342 : !constructor->initial_map()->is_dictionary_map() &&
9750 19829 : constructor->initial_map()->instance_type() == JS_OBJECT_TYPE &&
9751 : constructor->initial_map()->instance_size() <
9752 15273 : HAllocate::kMaxInlineSize;
9753 : }
9754 :
9755 255001 : void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
9756 : DCHECK(!HasStackOverflow());
9757 : DCHECK(current_block() != NULL);
9758 : DCHECK(current_block()->HasPredecessor());
9759 187906 : if (!is_tracking_positions()) SetSourcePosition(expr->position());
9760 32072 : int argument_count = expr->arguments()->length() + 1; // Plus constructor.
9761 : Factory* factory = isolate()->factory();
9762 :
9763 : // The constructor function is on the stack in the unoptimized code
9764 : // during evaluation of the arguments.
9765 96216 : CHECK_ALIVE(VisitForValue(expr->expression()));
9766 : HValue* function = Top();
9767 96216 : CHECK_ALIVE(VisitExpressions(expr->arguments()));
9768 :
9769 96216 : if (function->IsConstant() &&
9770 56654 : HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
9771 12279 : Handle<Object> constant = HConstant::cast(function)->handle(isolate());
9772 : expr->SetKnownGlobalTarget(Handle<JSFunction>::cast(constant));
9773 : }
9774 :
9775 64144 : if (FLAG_inline_construct &&
9776 47345 : expr->IsMonomorphic() &&
9777 15273 : IsAllocationInlineable(expr->target())) {
9778 : Handle<JSFunction> constructor = expr->target();
9779 : DCHECK(
9780 : constructor->shared()->construct_stub() ==
9781 : isolate()->builtins()->builtin(Builtins::kJSConstructStubGeneric) ||
9782 : constructor->shared()->construct_stub() ==
9783 : isolate()->builtins()->builtin(Builtins::kJSConstructStubApi) ||
9784 : constructor->shared()->construct_stub() ==
9785 : isolate()->builtins()->builtin(
9786 : Builtins::kJSBuiltinsConstructStubForBase));
9787 4551 : HValue* check = Add<HCheckValue>(function, constructor);
9788 :
9789 : // Force completion of inobject slack tracking before generating
9790 : // allocation code to finalize instance size.
9791 4551 : constructor->CompleteInobjectSlackTrackingIfActive();
9792 :
9793 : // Calculate instance size from initial map of constructor.
9794 : DCHECK(constructor->has_initial_map());
9795 : Handle<Map> initial_map(constructor->initial_map());
9796 : int instance_size = initial_map->instance_size();
9797 :
9798 : // Allocate an instance of the implicit receiver object.
9799 4551 : HValue* size_in_bytes = Add<HConstant>(instance_size);
9800 : HAllocationMode allocation_mode;
9801 : HAllocate* receiver = BuildAllocate(
9802 4551 : size_in_bytes, HType::JSObject(), JS_OBJECT_TYPE, allocation_mode);
9803 : receiver->set_known_initial_map(initial_map);
9804 :
9805 : // Initialize map and fields of the newly allocated object.
9806 : { NoObservableSideEffectsScope no_effects(this);
9807 : DCHECK(initial_map->instance_type() == JS_OBJECT_TYPE);
9808 : Add<HStoreNamedField>(receiver,
9809 : HObjectAccess::ForMapAndOffset(initial_map, JSObject::kMapOffset),
9810 4551 : Add<HConstant>(initial_map));
9811 4551 : HValue* empty_fixed_array = Add<HConstant>(factory->empty_fixed_array());
9812 : Add<HStoreNamedField>(receiver,
9813 : HObjectAccess::ForMapAndOffset(initial_map,
9814 : JSObject::kPropertiesOffset),
9815 4551 : empty_fixed_array);
9816 : Add<HStoreNamedField>(receiver,
9817 : HObjectAccess::ForMapAndOffset(initial_map,
9818 : JSObject::kElementsOffset),
9819 4551 : empty_fixed_array);
9820 4551 : BuildInitializeInobjectProperties(receiver, initial_map);
9821 : }
9822 :
9823 : // Replace the constructor function with a newly allocated receiver using
9824 : // the index of the receiver from the top of the expression stack.
9825 : const int receiver_index = argument_count - 1;
9826 : DCHECK(environment()->ExpressionStackAt(receiver_index) == function);
9827 : environment()->SetExpressionStackAt(receiver_index, receiver);
9828 :
9829 4551 : if (TryInlineConstruct(expr, receiver)) {
9830 : // Inlining worked, add a dependency on the initial map to make sure that
9831 : // this code is deoptimized whenever the initial map of the constructor
9832 : // changes.
9833 1049 : top_info()->dependencies()->AssumeInitialMapCantChange(initial_map);
9834 1049 : return;
9835 : }
9836 :
9837 : // TODO(mstarzinger): For now we remove the previous HAllocate and all
9838 : // corresponding instructions and instead add HPushArguments for the
9839 : // arguments in case inlining failed. What we actually should do is for
9840 : // inlining to try to build a subgraph without mutating the parent graph.
9841 3502 : HInstruction* instr = current_block()->last();
9842 37373 : do {
9843 : HInstruction* prev_instr = instr->previous();
9844 37373 : instr->DeleteAndReplaceWith(NULL);
9845 : instr = prev_instr;
9846 : } while (instr != check);
9847 : environment()->SetExpressionStackAt(receiver_index, function);
9848 : } else {
9849 : // The constructor function is both an operand to the instruction and an
9850 : // argument to the construct call.
9851 27521 : if (TryHandleArrayCall(expr, function)) return;
9852 : }
9853 :
9854 30497 : HValue* arity = Add<HConstant>(argument_count - 1);
9855 30497 : HValue* op_vals[] = {function, function, arity};
9856 30497 : Callable callable = CodeFactory::Construct(isolate());
9857 30497 : HConstant* stub = Add<HConstant>(callable.code());
9858 30497 : PushArgumentsFromEnvironment(argument_count);
9859 : HInstruction* construct = New<HCallWithDescriptor>(
9860 30497 : stub, argument_count, callable.descriptor(), ArrayVector(op_vals));
9861 60994 : return ast_context()->ReturnInstruction(construct, expr->id());
9862 : }
9863 :
9864 :
9865 11877 : void HOptimizedGraphBuilder::BuildInitializeInobjectProperties(
9866 : HValue* receiver, Handle<Map> initial_map) {
9867 11877 : if (initial_map->GetInObjectProperties() != 0) {
9868 8033 : HConstant* undefined = graph()->GetConstantUndefined();
9869 67784 : for (int i = 0; i < initial_map->GetInObjectProperties(); i++) {
9870 25859 : int property_offset = initial_map->GetInObjectPropertyOffset(i);
9871 : Add<HStoreNamedField>(receiver, HObjectAccess::ForMapAndOffset(
9872 : initial_map, property_offset),
9873 25859 : undefined);
9874 : }
9875 : }
9876 11877 : }
9877 :
9878 32 : void HOptimizedGraphBuilder::GenerateMaxSmi(CallRuntime* expr) {
9879 : DCHECK(expr->arguments()->length() == 0);
9880 16 : HConstant* max_smi = New<HConstant>(static_cast<int32_t>(Smi::kMaxValue));
9881 32 : return ast_context()->ReturnInstruction(max_smi, expr->id());
9882 : }
9883 :
9884 :
9885 0 : void HOptimizedGraphBuilder::GenerateTypedArrayMaxSizeInHeap(
9886 0 : CallRuntime* expr) {
9887 : DCHECK(expr->arguments()->length() == 0);
9888 : HConstant* result = New<HConstant>(static_cast<int32_t>(
9889 0 : FLAG_typed_array_max_size_in_heap));
9890 0 : return ast_context()->ReturnInstruction(result, expr->id());
9891 : }
9892 :
9893 :
9894 0 : void HOptimizedGraphBuilder::GenerateArrayBufferGetByteLength(
9895 0 : CallRuntime* expr) {
9896 : DCHECK(expr->arguments()->length() == 1);
9897 0 : CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
9898 : HValue* buffer = Pop();
9899 : HInstruction* result = New<HLoadNamedField>(
9900 0 : buffer, nullptr, HObjectAccess::ForJSArrayBufferByteLength());
9901 0 : return ast_context()->ReturnInstruction(result, expr->id());
9902 : }
9903 :
9904 :
9905 9 : void HOptimizedGraphBuilder::GenerateArrayBufferViewGetByteLength(
9906 27 : CallRuntime* expr) {
9907 18 : NoObservableSideEffectsScope scope(this);
9908 : DCHECK(expr->arguments()->length() == 1);
9909 27 : CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
9910 : HValue* view = Pop();
9911 :
9912 : return ast_context()->ReturnValue(BuildArrayBufferViewFieldAccessor(
9913 : view, nullptr,
9914 9 : FieldIndex::ForInObjectOffset(JSArrayBufferView::kByteLengthOffset)));
9915 : }
9916 :
9917 :
9918 35 : void HOptimizedGraphBuilder::GenerateArrayBufferViewGetByteOffset(
9919 105 : CallRuntime* expr) {
9920 70 : NoObservableSideEffectsScope scope(this);
9921 : DCHECK(expr->arguments()->length() == 1);
9922 105 : CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
9923 : HValue* view = Pop();
9924 :
9925 : return ast_context()->ReturnValue(BuildArrayBufferViewFieldAccessor(
9926 : view, nullptr,
9927 35 : FieldIndex::ForInObjectOffset(JSArrayBufferView::kByteOffsetOffset)));
9928 : }
9929 :
9930 44 : void HOptimizedGraphBuilder::GenerateArrayBufferViewWasNeutered(
9931 132 : CallRuntime* expr) {
9932 88 : NoObservableSideEffectsScope scope(this);
9933 : DCHECK_EQ(expr->arguments()->length(), 1);
9934 132 : CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
9935 : HValue* view = Pop();
9936 :
9937 : HInstruction* buffer = Add<HLoadNamedField>(
9938 44 : view, nullptr, HObjectAccess::ForJSArrayBufferViewBuffer());
9939 : HInstruction* flags = Add<HLoadNamedField>(
9940 44 : buffer, nullptr, HObjectAccess::ForJSArrayBufferBitField());
9941 : HValue* was_neutered_mask =
9942 44 : Add<HConstant>(1 << JSArrayBuffer::WasNeutered::kShift);
9943 : HValue* was_neutered =
9944 44 : AddUncasted<HBitwise>(Token::BIT_AND, flags, was_neutered_mask);
9945 44 : return ast_context()->ReturnValue(was_neutered);
9946 : }
9947 :
9948 99 : void HOptimizedGraphBuilder::GenerateTypedArrayGetLength(
9949 297 : CallRuntime* expr) {
9950 198 : NoObservableSideEffectsScope scope(this);
9951 : DCHECK(expr->arguments()->length() == 1);
9952 297 : CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
9953 : HValue* view = Pop();
9954 :
9955 : return ast_context()->ReturnValue(BuildArrayBufferViewFieldAccessor(
9956 : view, nullptr,
9957 99 : FieldIndex::ForInObjectOffset(JSTypedArray::kLengthOffset)));
9958 : }
9959 :
9960 :
9961 212669 : void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
9962 : DCHECK(!HasStackOverflow());
9963 : DCHECK(current_block() != NULL);
9964 : DCHECK(current_block()->HasPredecessor());
9965 72674 : if (expr->is_jsruntime()) {
9966 : // Crankshaft always specializes to the native context, so we can just grab
9967 : // the constant function from the current native context and embed that into
9968 : // the code object.
9969 : Handle<JSFunction> known_function(
9970 : JSFunction::cast(
9971 4237 : current_info()->native_context()->get(expr->context_index())),
9972 49461 : isolate());
9973 :
9974 : // The callee and the receiver both have to be pushed onto the operand stack
9975 : // before arguments are being evaluated.
9976 4237 : HConstant* function = Add<HConstant>(known_function);
9977 4237 : HValue* receiver = ImplicitReceiverFor(function, known_function);
9978 4237 : Push(function);
9979 4237 : Push(receiver);
9980 :
9981 4237 : int argument_count = expr->arguments()->length() + 1; // Count receiver.
9982 12711 : CHECK_ALIVE(VisitExpressions(expr->arguments()));
9983 4237 : PushArgumentsFromEnvironment(argument_count);
9984 : HInstruction* call = NewCallConstantFunction(known_function, argument_count,
9985 : TailCallMode::kDisallow,
9986 4237 : TailCallMode::kDisallow);
9987 : Drop(1); // Function
9988 8474 : return ast_context()->ReturnInstruction(call, expr->id());
9989 : }
9990 :
9991 : const Runtime::Function* function = expr->function();
9992 : DCHECK(function != NULL);
9993 68437 : switch (function->function_id) {
9994 : #define CALL_INTRINSIC_GENERATOR(Name) \
9995 : case Runtime::kInline##Name: \
9996 : return Generate##Name(expr);
9997 :
9998 1624 : FOR_EACH_HYDROGEN_INTRINSIC(CALL_INTRINSIC_GENERATOR)
9999 : #undef CALL_INTRINSIC_GENERATOR
10000 : default: {
10001 41030 : int argument_count = expr->arguments()->length();
10002 123047 : CHECK_ALIVE(VisitExpressions(expr->arguments()));
10003 40987 : PushArgumentsFromEnvironment(argument_count);
10004 40987 : HCallRuntime* call = New<HCallRuntime>(function, argument_count);
10005 81974 : return ast_context()->ReturnInstruction(call, expr->id());
10006 : }
10007 : }
10008 : }
10009 :
10010 :
10011 259309 : void HOptimizedGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
10012 : DCHECK(!HasStackOverflow());
10013 : DCHECK(current_block() != NULL);
10014 : DCHECK(current_block()->HasPredecessor());
10015 259309 : switch (expr->op()) {
10016 1248 : case Token::DELETE: return VisitDelete(expr);
10017 4151 : case Token::VOID: return VisitVoid(expr);
10018 40230 : case Token::TYPEOF: return VisitTypeof(expr);
10019 213680 : case Token::NOT: return VisitNot(expr);
10020 0 : default: UNREACHABLE();
10021 : }
10022 : }
10023 :
10024 :
10025 6083 : void HOptimizedGraphBuilder::VisitDelete(UnaryOperation* expr) {
10026 3560 : Property* prop = expr->expression()->AsProperty();
10027 1287 : VariableProxy* proxy = expr->expression()->AsVariableProxy();
10028 1248 : if (prop != NULL) {
10029 3576 : CHECK_ALIVE(VisitForValue(prop->obj()));
10030 3426 : CHECK_ALIVE(VisitForValue(prop->key()));
10031 : HValue* key = Pop();
10032 : HValue* obj = Pop();
10033 : HValue* language_mode = Add<HConstant>(
10034 1142 : static_cast<int32_t>(function_language_mode()), Representation::Smi());
10035 1142 : Add<HPushArguments>(obj, key, language_mode);
10036 : HInstruction* instr =
10037 1142 : New<HCallRuntime>(Runtime::FunctionForId(Runtime::kDeleteProperty), 3);
10038 2284 : return ast_context()->ReturnInstruction(instr, expr->id());
10039 78 : } else if (proxy != NULL) {
10040 : Variable* var = proxy->var();
10041 39 : if (var->IsUnallocated()) {
10042 : Bailout(kDeleteWithGlobalVariable);
10043 16 : } else if (var->IsStackAllocated() || var->IsContextSlot()) {
10044 : // Result of deleting non-global variables is false. 'this' is not really
10045 : // a variable, though we implement it as one. The subexpression does not
10046 : // have side effects.
10047 : HValue* value = var->is_this() ? graph()->GetConstantTrue()
10048 32 : : graph()->GetConstantFalse();
10049 16 : return ast_context()->ReturnValue(value);
10050 : } else {
10051 : Bailout(kDeleteWithNonGlobalVariable);
10052 : }
10053 : } else {
10054 : // Result of deleting non-property, non-variable reference is true.
10055 : // Evaluate the subexpression for side effects.
10056 117 : CHECK_ALIVE(VisitForEffect(expr->expression()));
10057 78 : return ast_context()->ReturnValue(graph()->GetConstantTrue());
10058 : }
10059 : }
10060 :
10061 :
10062 12453 : void HOptimizedGraphBuilder::VisitVoid(UnaryOperation* expr) {
10063 12453 : CHECK_ALIVE(VisitForEffect(expr->expression()));
10064 8302 : return ast_context()->ReturnValue(graph()->GetConstantUndefined());
10065 : }
10066 :
10067 :
10068 120689 : void HOptimizedGraphBuilder::VisitTypeof(UnaryOperation* expr) {
10069 80460 : CHECK_ALIVE(VisitForTypeOf(expr->expression()));
10070 : HValue* value = Pop();
10071 40229 : HInstruction* instr = New<HTypeof>(value);
10072 80458 : return ast_context()->ReturnInstruction(instr, expr->id());
10073 : }
10074 :
10075 :
10076 438308 : void HOptimizedGraphBuilder::VisitNot(UnaryOperation* expr) {
10077 213680 : if (ast_context()->IsTest()) {
10078 208184 : TestContext* context = TestContext::cast(ast_context());
10079 : VisitForControl(expr->expression(),
10080 : context->if_false(),
10081 208184 : context->if_true());
10082 208184 : return;
10083 : }
10084 :
10085 5496 : if (ast_context()->IsEffect()) {
10086 21 : VisitForEffect(expr->expression());
10087 21 : return;
10088 : }
10089 :
10090 : DCHECK(ast_context()->IsValue());
10091 16421 : HBasicBlock* materialize_false = graph()->CreateBasicBlock();
10092 5475 : HBasicBlock* materialize_true = graph()->CreateBasicBlock();
10093 10950 : CHECK_BAILOUT(VisitForControl(expr->expression(),
10094 : materialize_false,
10095 : materialize_true));
10096 :
10097 5473 : if (materialize_false->HasPredecessor()) {
10098 : materialize_false->SetJoinId(expr->MaterializeFalseId());
10099 : set_current_block(materialize_false);
10100 5473 : Push(graph()->GetConstantFalse());
10101 : } else {
10102 : materialize_false = NULL;
10103 : }
10104 :
10105 5473 : if (materialize_true->HasPredecessor()) {
10106 : materialize_true->SetJoinId(expr->MaterializeTrueId());
10107 : set_current_block(materialize_true);
10108 5473 : Push(graph()->GetConstantTrue());
10109 : } else {
10110 : materialize_true = NULL;
10111 : }
10112 :
10113 : HBasicBlock* join =
10114 5473 : CreateJoin(materialize_false, materialize_true, expr->id());
10115 : set_current_block(join);
10116 16419 : if (join != NULL) return ast_context()->ReturnValue(Pop());
10117 : }
10118 :
10119 2541928 : static Representation RepresentationFor(AstType* type) {
10120 : DisallowHeapAllocation no_allocation;
10121 2541928 : if (type->Is(AstType::None())) return Representation::None();
10122 2427222 : if (type->Is(AstType::SignedSmall())) return Representation::Smi();
10123 1473001 : if (type->Is(AstType::Signed32())) return Representation::Integer32();
10124 1473001 : if (type->Is(AstType::Number())) return Representation::Double();
10125 : return Representation::Tagged();
10126 : }
10127 :
10128 88220 : HInstruction* HOptimizedGraphBuilder::BuildIncrement(CountOperation* expr) {
10129 : // The input to the count operation is on top of the expression stack.
10130 44110 : Representation rep = RepresentationFor(expr->type());
10131 44110 : if (rep.IsNone() || rep.IsTagged()) {
10132 : rep = Representation::Smi();
10133 : }
10134 :
10135 : // We need an explicit HValue representing ToNumber(input). The
10136 : // actual HChange instruction we need is (sometimes) added in a later
10137 : // phase, so it is not available now to be used as an input to HAdd and
10138 : // as the return value.
10139 88220 : HInstruction* number_input = AddUncasted<HForceRepresentation>(Pop(), rep);
10140 44110 : if (!rep.IsDouble()) {
10141 : number_input->SetFlag(HInstruction::kFlexibleRepresentation);
10142 : number_input->SetFlag(HInstruction::kCannotBeTagged);
10143 : }
10144 44110 : Push(number_input);
10145 :
10146 : // The addition has no side effects, so we do not need
10147 : // to simulate the expression stack after this instruction.
10148 : // Any later failures deopt to the load of the input or earlier.
10149 : HConstant* delta = (expr->op() == Token::INC)
10150 : ? graph()->GetConstant1()
10151 44110 : : graph()->GetConstantMinus1();
10152 44110 : HInstruction* instr = AddUncasted<HAdd>(Top(), delta);
10153 88220 : if (instr->IsAdd()) {
10154 : HAdd* add = HAdd::cast(instr);
10155 : add->set_observed_input_representation(1, rep);
10156 : add->set_observed_input_representation(2, Representation::Smi());
10157 : }
10158 : instr->ClearAllSideEffects();
10159 : instr->SetFlag(HInstruction::kCannotBeTagged);
10160 44110 : return instr;
10161 : }
10162 :
10163 911 : void HOptimizedGraphBuilder::BuildStoreForEffect(
10164 : Expression* expr, Property* prop, FeedbackSlot slot, BailoutId ast_id,
10165 : BailoutId return_id, HValue* object, HValue* key, HValue* value) {
10166 : EffectContext for_effect(this);
10167 911 : Push(object);
10168 911 : if (key != NULL) Push(key);
10169 911 : Push(value);
10170 911 : BuildStore(expr, prop, slot, ast_id, return_id);
10171 911 : }
10172 :
10173 :
10174 218684 : void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
10175 : DCHECK(!HasStackOverflow());
10176 : DCHECK(current_block() != NULL);
10177 : DCHECK(current_block()->HasPredecessor());
10178 93164 : if (!is_tracking_positions()) SetSourcePosition(expr->position());
10179 : Expression* target = expr->expression();
10180 89204 : VariableProxy* proxy = target->AsVariableProxy();
10181 4776 : Property* prop = target->AsProperty();
10182 45398 : if (proxy == NULL && prop == NULL) {
10183 : return Bailout(kInvalidLhsInCountOperation);
10184 : }
10185 :
10186 : // Match the full code generator stack by simulating an extra stack
10187 : // element for postfix operations in a non-effect context. The return
10188 : // value is ToNumber(input).
10189 : bool returns_original_input =
10190 82952 : expr->is_postfix() && !ast_context()->IsEffect();
10191 : HValue* input = NULL; // ToNumber(original_input).
10192 : HValue* after = NULL; // The result after incrementing or decrementing.
10193 :
10194 45398 : if (proxy != NULL) {
10195 88278 : Variable* var = proxy->var();
10196 43806 : if (var->mode() == CONST) {
10197 : return Bailout(kNonInitializerAssignmentToConst);
10198 : }
10199 : // Argument of the count operation is a variable, not a property.
10200 : DCHECK(prop == NULL);
10201 127656 : CHECK_ALIVE(VisitForValue(target));
10202 :
10203 42520 : after = BuildIncrement(expr);
10204 42520 : input = returns_original_input ? Top() : Pop();
10205 42520 : Push(after);
10206 :
10207 42520 : switch (var->location()) {
10208 : case VariableLocation::UNALLOCATED:
10209 : HandleGlobalVariableAssignment(var, after, expr->CountSlot(),
10210 3827 : expr->AssignmentId());
10211 3827 : break;
10212 :
10213 : case VariableLocation::PARAMETER:
10214 : case VariableLocation::LOCAL:
10215 37717 : BindIfLive(var, after);
10216 37717 : break;
10217 :
10218 : case VariableLocation::CONTEXT: {
10219 976 : HValue* context = BuildContextChainWalk(var);
10220 : HStoreContextSlot::Mode mode = IsLexicalVariableMode(var->mode())
10221 976 : ? HStoreContextSlot::kCheckDeoptimize : HStoreContextSlot::kNoCheck;
10222 : HStoreContextSlot* instr = Add<HStoreContextSlot>(context, var->index(),
10223 976 : mode, after);
10224 976 : if (instr->HasObservableSideEffects()) {
10225 976 : Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
10226 : }
10227 : break;
10228 : }
10229 :
10230 : case VariableLocation::LOOKUP:
10231 : return Bailout(kLookupVariableInCountOperation);
10232 :
10233 : case VariableLocation::MODULE:
10234 0 : UNREACHABLE();
10235 : }
10236 :
10237 42520 : Drop(returns_original_input ? 2 : 1);
10238 85040 : return ast_context()->ReturnValue(expr->is_postfix() ? input : after);
10239 : }
10240 :
10241 : // Argument of the count operation is a property.
10242 : DCHECK(prop != NULL);
10243 2505 : if (returns_original_input) Push(graph()->GetConstantUndefined());
10244 :
10245 4776 : CHECK_ALIVE(VisitForValue(prop->obj()));
10246 : HValue* object = Top();
10247 :
10248 : HValue* key = NULL;
10249 2942 : if (!prop->key()->IsPropertyName() || prop->IsStringAccess()) {
10250 724 : CHECK_ALIVE(VisitForValue(prop->key()));
10251 : key = Top();
10252 : }
10253 :
10254 4770 : CHECK_ALIVE(PushLoad(prop, object, key));
10255 :
10256 1590 : after = BuildIncrement(expr);
10257 :
10258 1590 : if (returns_original_input) {
10259 : input = Pop();
10260 : // Drop object and key to push it again in the effect context below.
10261 911 : Drop(key == NULL ? 1 : 2);
10262 : environment()->SetExpressionStackAt(0, input);
10263 2733 : CHECK_ALIVE(BuildStoreForEffect(expr, prop, expr->CountSlot(), expr->id(),
10264 : expr->AssignmentId(), object, key, after));
10265 1822 : return ast_context()->ReturnValue(Pop());
10266 : }
10267 :
10268 : environment()->SetExpressionStackAt(0, after);
10269 : return BuildStore(expr, prop, expr->CountSlot(), expr->id(),
10270 679 : expr->AssignmentId());
10271 : }
10272 :
10273 :
10274 548 : HInstruction* HOptimizedGraphBuilder::BuildStringCharCodeAt(
10275 : HValue* string,
10276 : HValue* index) {
10277 770 : if (string->IsConstant() && index->IsConstant()) {
10278 : HConstant* c_string = HConstant::cast(string);
10279 175 : HConstant* c_index = HConstant::cast(index);
10280 386 : if (c_string->HasStringValue() && c_index->HasNumberValue()) {
10281 : int32_t i = c_index->NumberValueAsInteger32();
10282 : Handle<String> s = c_string->StringValue();
10283 339 : if (i < 0 || i >= s->length()) {
10284 44 : return New<HConstant>(std::numeric_limits<double>::quiet_NaN());
10285 : }
10286 131 : return New<HConstant>(s->Get(i));
10287 : }
10288 : }
10289 373 : string = BuildCheckString(string);
10290 373 : index = Add<HBoundsCheck>(index, AddLoadStringLength(string));
10291 373 : return New<HStringCharCodeAt>(string, index);
10292 : }
10293 :
10294 :
10295 : // Checks if the given shift amounts have following forms:
10296 : // (N1) and (N2) with N1 + N2 = 32; (sa) and (32 - sa).
10297 579 : static bool ShiftAmountsAllowReplaceByRotate(HValue* sa,
10298 : HValue* const32_minus_sa) {
10299 1056 : if (sa->IsConstant() && const32_minus_sa->IsConstant()) {
10300 96 : const HConstant* c1 = HConstant::cast(sa);
10301 96 : const HConstant* c2 = HConstant::cast(const32_minus_sa);
10302 144 : return c1->HasInteger32Value() && c2->HasInteger32Value() &&
10303 96 : (c1->Integer32Value() + c2->Integer32Value() == 32);
10304 : }
10305 531 : if (!const32_minus_sa->IsSub()) return false;
10306 : HSub* sub = HSub::cast(const32_minus_sa);
10307 1008 : return sub->left()->EqualsInteger32Constant(32) && sub->right() == sa;
10308 : }
10309 :
10310 :
10311 : // Checks if the left and the right are shift instructions with the oposite
10312 : // directions that can be replaced by one rotate right instruction or not.
10313 : // Returns the operand and the shift amount for the rotate instruction in the
10314 : // former case.
10315 18281 : bool HGraphBuilder::MatchRotateRight(HValue* left,
10316 : HValue* right,
10317 : HValue** operand,
10318 : HValue** shift_amount) {
10319 : HShl* shl;
10320 : HShr* shr;
10321 20778 : if (left->IsShl() && right->IsShr()) {
10322 : shl = HShl::cast(left);
10323 : shr = HShr::cast(right);
10324 17956 : } else if (left->IsShr() && right->IsShl()) {
10325 : shl = HShl::cast(right);
10326 : shr = HShr::cast(left);
10327 : } else {
10328 : return false;
10329 : }
10330 570 : if (shl->left() != shr->left()) return false;
10331 :
10332 579 : if (!ShiftAmountsAllowReplaceByRotate(shl->right(), shr->right()) &&
10333 24 : !ShiftAmountsAllowReplaceByRotate(shr->right(), shl->right())) {
10334 : return false;
10335 : }
10336 549 : *operand = shr->left();
10337 549 : *shift_amount = shr->right();
10338 549 : return true;
10339 : }
10340 :
10341 :
10342 8340 : bool CanBeZero(HValue* right) {
10343 8340 : if (right->IsConstant()) {
10344 12634 : HConstant* right_const = HConstant::cast(right);
10345 12634 : if (right_const->HasInteger32Value() &&
10346 6142 : (right_const->Integer32Value() & 0x1f) != 0) {
10347 : return false;
10348 : }
10349 : }
10350 3443 : return true;
10351 : }
10352 :
10353 16816 : HValue* HGraphBuilder::EnforceNumberType(HValue* number, AstType* expected) {
10354 16816 : if (expected->Is(AstType::SignedSmall())) {
10355 11753 : return AddUncasted<HForceRepresentation>(number, Representation::Smi());
10356 : }
10357 5063 : if (expected->Is(AstType::Signed32())) {
10358 : return AddUncasted<HForceRepresentation>(number,
10359 0 : Representation::Integer32());
10360 : }
10361 : return number;
10362 : }
10363 :
10364 2574159 : HValue* HGraphBuilder::TruncateToNumber(HValue* value, AstType** expected) {
10365 670160 : if (value->IsConstant()) {
10366 : HConstant* constant = HConstant::cast(value);
10367 : Maybe<HConstant*> number =
10368 268986 : constant->CopyToTruncatedNumber(isolate(), zone());
10369 268986 : if (number.IsJust()) {
10370 7135 : *expected = AstType::Number();
10371 7135 : return AddInstruction(number.FromJust());
10372 : }
10373 : }
10374 :
10375 : // We put temporary values on the stack, which don't correspond to anything
10376 : // in baseline code. Since nothing is observable we avoid recording those
10377 : // pushes with a NoObservableSideEffectsScope.
10378 : NoObservableSideEffectsScope no_effects(this);
10379 :
10380 663025 : AstType* expected_type = *expected;
10381 :
10382 : // Separate the number type from the rest.
10383 : AstType* expected_obj =
10384 663025 : AstType::Intersect(expected_type, AstType::NonNumber(), zone());
10385 : AstType* expected_number =
10386 663025 : AstType::Intersect(expected_type, AstType::Number(), zone());
10387 :
10388 : // We expect to get a number.
10389 : // (We need to check first, since AstType::None->Is(AstType::Any()) == true.
10390 663025 : if (expected_obj->Is(AstType::None())) {
10391 : DCHECK(!expected_number->Is(AstType::None()));
10392 : return value;
10393 : }
10394 :
10395 663025 : if (expected_obj->Is(AstType::Undefined())) {
10396 : // This is already done by HChange.
10397 39977 : *expected = AstType::Union(expected_number, AstType::Number(), zone());
10398 39977 : return value;
10399 : }
10400 :
10401 : return value;
10402 : }
10403 :
10404 :
10405 385432 : HValue* HOptimizedGraphBuilder::BuildBinaryOperation(
10406 1156296 : BinaryOperation* expr,
10407 : HValue* left,
10408 : HValue* right,
10409 : PushBeforeSimulateBehavior push_sim_result) {
10410 385432 : AstType* left_type = bounds_.get(expr->left()).lower;
10411 385432 : AstType* right_type = bounds_.get(expr->right()).lower;
10412 385432 : AstType* result_type = bounds_.get(expr).lower;
10413 385432 : Maybe<int> fixed_right_arg = expr->fixed_right_arg();
10414 : Handle<AllocationSite> allocation_site = expr->allocation_site();
10415 :
10416 : HAllocationMode allocation_mode;
10417 385432 : if (FLAG_allocation_site_pretenuring && !allocation_site.is_null()) {
10418 21914 : allocation_mode = HAllocationMode(allocation_site);
10419 : }
10420 : HValue* result = HGraphBuilder::BuildBinaryOperation(
10421 : expr->op(), left, right, left_type, right_type, result_type,
10422 385432 : fixed_right_arg, allocation_mode, expr->id());
10423 : // Add a simulate after instructions with observable side effects, and
10424 : // after phis, which are the result of BuildBinaryOperation when we
10425 : // inlined some complex subgraph.
10426 425962 : if (result->HasObservableSideEffects() || result->IsPhi()) {
10427 356851 : if (push_sim_result == PUSH_BEFORE_SIMULATE) {
10428 356546 : Push(result);
10429 356546 : Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
10430 : Drop(1);
10431 : } else {
10432 305 : Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
10433 : }
10434 : }
10435 385432 : return result;
10436 : }
10437 :
10438 395422 : HValue* HGraphBuilder::BuildBinaryOperation(
10439 : Token::Value op, HValue* left, HValue* right, AstType* left_type,
10440 : AstType* right_type, AstType* result_type, Maybe<int> fixed_right_arg,
10441 1087137 : HAllocationMode allocation_mode, BailoutId opt_id) {
10442 : bool maybe_string_add = false;
10443 395422 : if (op == Token::ADD) {
10444 : // If we are adding constant string with something for which we don't have
10445 : // a feedback yet, assume that it's also going to be a string and don't
10446 : // generate deopt instructions.
10447 241824 : if (!left_type->IsInhabited() && right->IsConstant() &&
10448 : HConstant::cast(right)->HasStringValue()) {
10449 10128 : left_type = AstType::String();
10450 : }
10451 :
10452 226510 : if (!right_type->IsInhabited() && left->IsConstant() &&
10453 : HConstant::cast(left)->HasStringValue()) {
10454 5693 : right_type = AstType::String();
10455 : }
10456 :
10457 364059 : maybe_string_add = (left_type->Maybe(AstType::String()) ||
10458 319528 : left_type->Maybe(AstType::Receiver()) ||
10459 522932 : right_type->Maybe(AstType::String()) ||
10460 158907 : right_type->Maybe(AstType::Receiver()));
10461 : }
10462 :
10463 395422 : Representation left_rep = RepresentationFor(left_type);
10464 395422 : Representation right_rep = RepresentationFor(right_type);
10465 :
10466 395422 : if (!left_type->IsInhabited()) {
10467 : Add<HDeoptimize>(
10468 : DeoptimizeReason::kInsufficientTypeFeedbackForLHSOfBinaryOperation,
10469 31154 : Deoptimizer::SOFT);
10470 31154 : left_type = AstType::Any();
10471 31154 : left_rep = RepresentationFor(left_type);
10472 31154 : maybe_string_add = op == Token::ADD;
10473 : }
10474 :
10475 395422 : if (!right_type->IsInhabited()) {
10476 : Add<HDeoptimize>(
10477 : DeoptimizeReason::kInsufficientTypeFeedbackForRHSOfBinaryOperation,
10478 39134 : Deoptimizer::SOFT);
10479 39134 : right_type = AstType::Any();
10480 39134 : right_rep = RepresentationFor(right_type);
10481 39134 : maybe_string_add = op == Token::ADD;
10482 : }
10483 :
10484 395422 : if (!maybe_string_add) {
10485 335080 : left = TruncateToNumber(left, &left_type);
10486 335080 : right = TruncateToNumber(right, &right_type);
10487 : }
10488 :
10489 : // Special case for string addition here.
10490 995122 : if (op == Token::ADD &&
10491 525676 : (left_type->Is(AstType::String()) || right_type->Is(AstType::String()))) {
10492 : // Validate type feedback for left argument.
10493 88410 : if (left_type->Is(AstType::String())) {
10494 43579 : left = BuildCheckString(left);
10495 : }
10496 :
10497 : // Validate type feedback for right argument.
10498 88410 : if (right_type->Is(AstType::String())) {
10499 38259 : right = BuildCheckString(right);
10500 : }
10501 :
10502 : // Convert left argument as necessary.
10503 88410 : if (left_type->Is(AstType::Number())) {
10504 : DCHECK(right_type->Is(AstType::String()));
10505 422 : left = BuildNumberToString(left, left_type);
10506 87566 : } else if (!left_type->Is(AstType::String())) {
10507 : DCHECK(right_type->Is(AstType::String()));
10508 : return AddUncasted<HStringAdd>(
10509 : left, right, allocation_mode.GetPretenureMode(),
10510 204 : STRING_ADD_CONVERT_LEFT, allocation_mode.feedback_site());
10511 : }
10512 :
10513 : // Convert right argument as necessary.
10514 88002 : if (right_type->Is(AstType::Number())) {
10515 : DCHECK(left_type->Is(AstType::String()));
10516 4780 : right = BuildNumberToString(right, right_type);
10517 78442 : } else if (!right_type->Is(AstType::String())) {
10518 : DCHECK(left_type->Is(AstType::String()));
10519 : return AddUncasted<HStringAdd>(
10520 : left, right, allocation_mode.GetPretenureMode(),
10521 1166 : STRING_ADD_CONVERT_RIGHT, allocation_mode.feedback_site());
10522 : }
10523 :
10524 : // Fast paths for empty constant strings.
10525 : Handle<String> left_string =
10526 10769 : left->IsConstant() && HConstant::cast(left)->HasStringValue()
10527 : ? HConstant::cast(left)->StringValue()
10528 53604 : : Handle<String>();
10529 : Handle<String> right_string =
10530 26984 : right->IsConstant() && HConstant::cast(right)->HasStringValue()
10531 : ? HConstant::cast(right)->StringValue()
10532 69819 : : Handle<String>();
10533 53604 : if (!left_string.is_null() && left_string->length() == 0) return right;
10534 69114 : if (!right_string.is_null() && right_string->length() == 0) return left;
10535 40928 : if (!left_string.is_null() && !right_string.is_null()) {
10536 : return AddUncasted<HStringAdd>(
10537 : left, right, allocation_mode.GetPretenureMode(),
10538 1533 : STRING_ADD_CHECK_NONE, allocation_mode.feedback_site());
10539 : }
10540 :
10541 : // Register the dependent code with the allocation site.
10542 39395 : if (!allocation_mode.feedback_site().is_null()) {
10543 : DCHECK(!graph()->info()->IsStub());
10544 : Handle<AllocationSite> site(allocation_mode.feedback_site());
10545 20317 : top_info()->dependencies()->AssumeTenuringDecision(site);
10546 : }
10547 :
10548 : // Inline the string addition into the stub when creating allocation
10549 : // mementos to gather allocation site feedback, or if we can statically
10550 : // infer that we're going to create a cons string.
10551 82590 : if ((graph()->info()->IsStub() &&
10552 35827 : allocation_mode.CreateAllocationMementos()) ||
10553 8696 : (left->IsConstant() &&
10554 8696 : HConstant::cast(left)->HasStringValue() &&
10555 : HConstant::cast(left)->StringValue()->length() + 1 >=
10556 73276 : ConsString::kMinLength) ||
10557 23917 : (right->IsConstant() &&
10558 23917 : HConstant::cast(right)->HasStringValue() &&
10559 : HConstant::cast(right)->StringValue()->length() + 1 >=
10560 : ConsString::kMinLength)) {
10561 15417 : return BuildStringAdd(left, right, allocation_mode);
10562 : }
10563 :
10564 : // Fallback to using the string add stub.
10565 : return AddUncasted<HStringAdd>(
10566 : left, right, allocation_mode.GetPretenureMode(), STRING_ADD_CHECK_NONE,
10567 23978 : allocation_mode.feedback_site());
10568 : }
10569 :
10570 : // Special case for +x here.
10571 351217 : if (op == Token::MUL) {
10572 36329 : if (left->EqualsInteger32Constant(1)) {
10573 50 : return BuildToNumber(right);
10574 : }
10575 36279 : if (right->EqualsInteger32Constant(1)) {
10576 9512 : return BuildToNumber(left);
10577 : }
10578 : }
10579 :
10580 341655 : if (graph()->info()->IsStub()) {
10581 5867 : left = EnforceNumberType(left, left_type);
10582 5867 : right = EnforceNumberType(right, right_type);
10583 : }
10584 :
10585 341655 : Representation result_rep = RepresentationFor(result_type);
10586 :
10587 341655 : bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) ||
10588 31116 : (right_rep.IsTagged() && !right_rep.IsSmi());
10589 :
10590 : HInstruction* instr = NULL;
10591 : // Only the stub is allowed to call into the runtime, since otherwise we would
10592 : // inline several instructions (including the two pushes) for every tagged
10593 : // operation in optimized code, which is more expensive, than a stub call.
10594 341655 : if (graph()->info()->IsStub() && is_non_primitive) {
10595 785 : HValue* values[] = {left, right};
10596 : #define GET_STUB(Name) \
10597 : do { \
10598 : Callable callable = CodeFactory::Name(isolate()); \
10599 : HValue* stub = Add<HConstant>(callable.code()); \
10600 : instr = AddUncasted<HCallWithDescriptor>(stub, 0, callable.descriptor(), \
10601 : ArrayVector(values)); \
10602 : } while (false)
10603 :
10604 785 : switch (op) {
10605 : default:
10606 0 : UNREACHABLE();
10607 : case Token::ADD:
10608 586 : GET_STUB(Add);
10609 293 : break;
10610 : case Token::SUB:
10611 154 : GET_STUB(Subtract);
10612 77 : break;
10613 : case Token::MUL:
10614 242 : GET_STUB(Multiply);
10615 121 : break;
10616 : case Token::DIV:
10617 58 : GET_STUB(Divide);
10618 29 : break;
10619 : case Token::MOD:
10620 52 : GET_STUB(Modulus);
10621 26 : break;
10622 : case Token::BIT_OR:
10623 136 : GET_STUB(BitwiseOr);
10624 68 : break;
10625 : case Token::BIT_AND:
10626 48 : GET_STUB(BitwiseAnd);
10627 24 : break;
10628 : case Token::BIT_XOR:
10629 72 : GET_STUB(BitwiseXor);
10630 36 : break;
10631 : case Token::SAR:
10632 62 : GET_STUB(ShiftRight);
10633 31 : break;
10634 : case Token::SHR:
10635 116 : GET_STUB(ShiftRightLogical);
10636 58 : break;
10637 : case Token::SHL:
10638 44 : GET_STUB(ShiftLeft);
10639 22 : break;
10640 : }
10641 : #undef GET_STUB
10642 : } else {
10643 340870 : switch (op) {
10644 : case Token::ADD:
10645 159780 : instr = AddUncasted<HAdd>(left, right);
10646 159780 : break;
10647 : case Token::SUB:
10648 19655 : instr = AddUncasted<HSub>(left, right);
10649 19655 : break;
10650 : case Token::MUL:
10651 26646 : instr = AddUncasted<HMul>(left, right);
10652 26646 : break;
10653 : case Token::MOD: {
10654 6308 : if (fixed_right_arg.IsJust() &&
10655 711 : !right->EqualsInteger32Constant(fixed_right_arg.FromJust())) {
10656 : HConstant* fixed_right =
10657 456 : Add<HConstant>(static_cast<int>(fixed_right_arg.FromJust()));
10658 : IfBuilder if_same(this);
10659 456 : if_same.If<HCompareNumericAndBranch>(right, fixed_right, Token::EQ);
10660 456 : if_same.Then();
10661 456 : if_same.ElseDeopt(DeoptimizeReason::kUnexpectedRHSOfBinaryOperation);
10662 : right = fixed_right;
10663 : }
10664 5597 : instr = AddUncasted<HMod>(left, right);
10665 5597 : break;
10666 : }
10667 : case Token::DIV:
10668 52162 : instr = AddUncasted<HDiv>(left, right);
10669 52162 : break;
10670 : case Token::BIT_XOR:
10671 : case Token::BIT_AND:
10672 22828 : instr = AddUncasted<HBitwise>(op, left, right);
10673 22828 : break;
10674 : case Token::BIT_OR: {
10675 : HValue *operand, *shift_amount;
10676 73791 : if (left_type->Is(AstType::Signed32()) &&
10677 45846 : right_type->Is(AstType::Signed32()) &&
10678 18281 : MatchRotateRight(left, right, &operand, &shift_amount)) {
10679 549 : instr = AddUncasted<HRor>(operand, shift_amount);
10680 : } else {
10681 27016 : instr = AddUncasted<HBitwise>(op, left, right);
10682 : }
10683 : break;
10684 : }
10685 : case Token::SAR:
10686 10416 : instr = AddUncasted<HSar>(left, right);
10687 10416 : break;
10688 : case Token::SHR:
10689 8340 : instr = AddUncasted<HShr>(left, right);
10690 16680 : if (instr->IsShr() && CanBeZero(right)) {
10691 3443 : graph()->RecordUint32Instruction(instr);
10692 : }
10693 : break;
10694 : case Token::SHL:
10695 7881 : instr = AddUncasted<HShl>(left, right);
10696 7881 : break;
10697 : default:
10698 0 : UNREACHABLE();
10699 : }
10700 : }
10701 :
10702 341655 : if (instr->IsBinaryOperation()) {
10703 : HBinaryOperation* binop = HBinaryOperation::cast(instr);
10704 : binop->set_observed_input_representation(1, left_rep);
10705 : binop->set_observed_input_representation(2, right_rep);
10706 340672 : binop->initialize_output_representation(result_rep);
10707 340672 : if (graph()->info()->IsStub()) {
10708 : // Stub should not call into stub.
10709 : instr->SetFlag(HValue::kCannotBeTagged);
10710 : // And should truncate on HForceRepresentation already.
10711 5082 : if (left->IsForceRepresentation()) {
10712 : left->CopyFlag(HValue::kTruncatingToSmi, instr);
10713 : left->CopyFlag(HValue::kTruncatingToInt32, instr);
10714 : }
10715 5082 : if (right->IsForceRepresentation()) {
10716 : right->CopyFlag(HValue::kTruncatingToSmi, instr);
10717 : right->CopyFlag(HValue::kTruncatingToInt32, instr);
10718 : }
10719 : }
10720 : }
10721 341655 : return instr;
10722 : }
10723 :
10724 : // Check for the form (%_ClassOf(foo) === 'BarClass').
10725 744285 : static bool IsClassOfTest(CompareOperation* expr) {
10726 419597 : if (expr->op() != Token::EQ_STRICT) return false;
10727 324602 : CallRuntime* call = expr->left()->AsCallRuntime();
10728 316908 : if (call == NULL) return false;
10729 15560 : Literal* literal = expr->right()->AsLiteral();
10730 7780 : if (literal == NULL) return false;
10731 7780 : if (!literal->value()->IsString()) return false;
10732 7694 : if (call->is_jsruntime()) return false;
10733 7688 : if (call->function()->function_id != Runtime::kInlineClassOf) return false;
10734 : DCHECK_EQ(call->arguments()->length(), 1);
10735 7688 : return true;
10736 : }
10737 :
10738 514229 : void HOptimizedGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
10739 : DCHECK(!HasStackOverflow());
10740 : DCHECK(current_block() != NULL);
10741 : DCHECK(current_block()->HasPredecessor());
10742 514229 : switch (expr->op()) {
10743 : case Token::COMMA:
10744 6032 : return VisitComma(expr);
10745 : case Token::OR:
10746 : case Token::AND:
10747 122210 : return VisitLogicalExpression(expr);
10748 : default:
10749 385987 : return VisitArithmeticExpression(expr);
10750 : }
10751 : }
10752 :
10753 :
10754 18087 : void HOptimizedGraphBuilder::VisitComma(BinaryOperation* expr) {
10755 18096 : CHECK_ALIVE(VisitForEffect(expr->left()));
10756 : // Visit the right subexpression in the same AST context as the entire
10757 : // expression.
10758 6023 : Visit(expr->right());
10759 : }
10760 :
10761 :
10762 666741 : void HOptimizedGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
10763 122210 : bool is_logical_and = expr->op() == Token::AND;
10764 122210 : if (ast_context()->IsTest()) {
10765 110995 : TestContext* context = TestContext::cast(ast_context());
10766 : // Translate left subexpression.
10767 155423 : HBasicBlock* eval_right = graph()->CreateBasicBlock();
10768 110995 : if (is_logical_and) {
10769 90162 : CHECK_BAILOUT(VisitForControl(expr->left(),
10770 : eval_right,
10771 : context->if_false()));
10772 : } else {
10773 131828 : CHECK_BAILOUT(VisitForControl(expr->left(),
10774 : context->if_true(),
10775 : eval_right));
10776 : }
10777 :
10778 : // Translate right subexpression by visiting it in the same AST
10779 : // context as the entire expression.
10780 110995 : CHECK(eval_right->HasPredecessor());
10781 : eval_right->SetJoinId(expr->RightId());
10782 : set_current_block(eval_right);
10783 110995 : Visit(expr->right());
10784 11215 : } else if (ast_context()->IsValue()) {
10785 33537 : CHECK_ALIVE(VisitForValue(expr->left()));
10786 : DCHECK(current_block() != NULL);
10787 : HValue* left_value = Top();
10788 :
10789 : // Short-circuit left values that always evaluate to the same boolean value.
10790 22264 : if (expr->left()->ToBooleanIsTrue() || expr->left()->ToBooleanIsFalse()) {
10791 : // l (evals true) && r -> r
10792 : // l (evals true) || r -> l
10793 : // l (evals false) && r -> l
10794 : // l (evals false) || r -> r
10795 161 : if (is_logical_and == expr->left()->ToBooleanIsTrue()) {
10796 : Drop(1);
10797 267 : CHECK_ALIVE(VisitForValue(expr->right()));
10798 : }
10799 322 : return ast_context()->ReturnValue(Pop());
10800 : }
10801 :
10802 : // We need an extra block to maintain edge-split form.
10803 11018 : HBasicBlock* empty_block = graph()->CreateBasicBlock();
10804 11018 : HBasicBlock* eval_right = graph()->CreateBasicBlock();
10805 11018 : ToBooleanHints expected(expr->left()->to_boolean_types());
10806 : HBranch* test = is_logical_and
10807 6267 : ? New<HBranch>(left_value, expected, eval_right, empty_block)
10808 17285 : : New<HBranch>(left_value, expected, empty_block, eval_right);
10809 11018 : FinishCurrentBlock(test);
10810 :
10811 : set_current_block(eval_right);
10812 : Drop(1); // Value of the left subexpression.
10813 22036 : CHECK_BAILOUT(VisitForValue(expr->right()));
10814 :
10815 : HBasicBlock* join_block =
10816 11016 : CreateJoin(empty_block, current_block(), expr->id());
10817 : set_current_block(join_block);
10818 22032 : return ast_context()->ReturnValue(Pop());
10819 :
10820 : } else {
10821 : DCHECK(ast_context()->IsEffect());
10822 : // In an effect context, we don't need the value of the left subexpression,
10823 : // only its control flow and side effects. We need an extra block to
10824 : // maintain edge-split form.
10825 36 : HBasicBlock* empty_block = graph()->CreateBasicBlock();
10826 36 : HBasicBlock* right_block = graph()->CreateBasicBlock();
10827 36 : if (is_logical_and) {
10828 60 : CHECK_BAILOUT(VisitForControl(expr->left(), right_block, empty_block));
10829 : } else {
10830 12 : CHECK_BAILOUT(VisitForControl(expr->left(), empty_block, right_block));
10831 : }
10832 :
10833 : // TODO(kmillikin): Find a way to fix this. It's ugly that there are
10834 : // actually two empty blocks (one here and one inserted by
10835 : // TestContext::BuildBranch, and that they both have an HSimulate though the
10836 : // second one is not a merge node, and that we really have no good AST ID to
10837 : // put on that first HSimulate.
10838 :
10839 : // Technically, we should be able to handle the case when one side of
10840 : // the test is not connected, but this can trip up liveness analysis
10841 : // if we did not fully connect the test context based on some optimistic
10842 : // assumption. If such an assumption was violated, we would end up with
10843 : // an environment with optimized-out values. So we should always
10844 : // conservatively connect the test context.
10845 :
10846 36 : CHECK(right_block->HasPredecessor());
10847 36 : CHECK(empty_block->HasPredecessor());
10848 :
10849 : empty_block->SetJoinId(expr->id());
10850 :
10851 : right_block->SetJoinId(expr->RightId());
10852 : set_current_block(right_block);
10853 72 : CHECK_BAILOUT(VisitForEffect(expr->right()));
10854 : right_block = current_block();
10855 :
10856 : HBasicBlock* join_block =
10857 36 : CreateJoin(empty_block, right_block, expr->id());
10858 : set_current_block(join_block);
10859 : // We did not materialize any value in the predecessor environments,
10860 : // so there is no need to handle it here.
10861 : }
10862 : }
10863 :
10864 :
10865 2312434 : void HOptimizedGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) {
10866 1157075 : CHECK_ALIVE(VisitForValue(expr->left()));
10867 1155359 : CHECK_ALIVE(VisitForValue(expr->right()));
10868 385101 : SetSourcePosition(expr->position());
10869 : HValue* right = Pop();
10870 : HValue* left = Pop();
10871 : HValue* result =
10872 : BuildBinaryOperation(expr, left, right,
10873 385101 : ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE
10874 385101 : : PUSH_BEFORE_SIMULATE);
10875 385101 : return ast_context()->ReturnValue(result);
10876 : }
10877 :
10878 :
10879 66185 : void HOptimizedGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr,
10880 : Expression* sub_expr,
10881 132370 : Handle<String> check) {
10882 132370 : CHECK_ALIVE(VisitForTypeOf(sub_expr));
10883 66185 : SetSourcePosition(expr->position());
10884 : HValue* value = Pop();
10885 66185 : HTypeofIsAndBranch* instr = New<HTypeofIsAndBranch>(value, check);
10886 132370 : return ast_context()->ReturnControl(instr, expr->id());
10887 : }
10888 :
10889 : namespace {
10890 :
10891 411904 : bool IsLiteralCompareStrict(Isolate* isolate, HValue* left, Token::Value op,
10892 : HValue* right) {
10893 721121 : return op == Token::EQ_STRICT &&
10894 7349 : ((left->IsConstant() &&
10895 430135 : !HConstant::cast(left)->handle(isolate)->IsNumber() &&
10896 723371 : !HConstant::cast(left)->handle(isolate)->IsString()) ||
10897 171993 : (right->IsConstant() &&
10898 722599 : !HConstant::cast(right)->handle(isolate)->IsNumber() &&
10899 1367065 : !HConstant::cast(right)->handle(isolate)->IsString()));
10900 : }
10901 :
10902 : } // namespace
10903 :
10904 5040022 : void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
10905 : DCHECK(!HasStackOverflow());
10906 : DCHECK(current_block() != NULL);
10907 : DCHECK(current_block()->HasPredecessor());
10908 :
10909 1752475 : if (!is_tracking_positions()) SetSourcePosition(expr->position());
10910 :
10911 : // Check for a few fast cases. The AST visiting behavior must be in sync
10912 : // with the full codegen: We don't push both left and right values onto
10913 : // the expression stack when one side is a special-case literal.
10914 503361 : Expression* sub_expr = NULL;
10915 : Literal* literal;
10916 503361 : if (expr->IsLiteralCompareTypeof(&sub_expr, &literal)) {
10917 : return HandleLiteralCompareTypeof(expr, sub_expr,
10918 132370 : Handle<String>::cast(literal->value()));
10919 : }
10920 437176 : if (expr->IsLiteralCompareUndefined(&sub_expr)) {
10921 12051 : return HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue);
10922 : }
10923 425125 : if (expr->IsLiteralCompareNull(&sub_expr)) {
10924 5528 : return HandleLiteralCompareNil(expr, sub_expr, kNullValue);
10925 : }
10926 :
10927 419597 : if (IsClassOfTest(expr)) {
10928 15376 : CallRuntime* call = expr->left()->AsCallRuntime();
10929 : DCHECK(call->arguments()->length() == 1);
10930 23064 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10931 : HValue* value = Pop();
10932 15376 : Literal* literal = expr->right()->AsLiteral();
10933 7688 : Handle<String> rhs = Handle<String>::cast(literal->value());
10934 7688 : HClassOfTestAndBranch* instr = New<HClassOfTestAndBranch>(value, rhs);
10935 15376 : return ast_context()->ReturnControl(instr, expr->id());
10936 : }
10937 :
10938 411909 : AstType* left_type = bounds_.get(expr->left()).lower;
10939 411909 : AstType* right_type = bounds_.get(expr->right()).lower;
10940 : AstType* combined_type = expr->combined_type();
10941 :
10942 1235723 : CHECK_ALIVE(VisitForValue(expr->left()));
10943 1235714 : CHECK_ALIVE(VisitForValue(expr->right()));
10944 :
10945 : HValue* right = Pop();
10946 : HValue* left = Pop();
10947 : Token::Value op = expr->op();
10948 :
10949 411904 : if (IsLiteralCompareStrict(isolate(), left, op, right)) {
10950 : HCompareObjectEqAndBranch* result =
10951 5616 : New<HCompareObjectEqAndBranch>(left, right);
10952 11232 : return ast_context()->ReturnControl(result, expr->id());
10953 : }
10954 :
10955 406288 : if (op == Token::INSTANCEOF) {
10956 : // Check to see if the rhs of the instanceof is a known function.
10957 4617 : if (right->IsConstant() &&
10958 2463 : HConstant::cast(right)->handle(isolate())->IsJSFunction()) {
10959 : Handle<JSFunction> function =
10960 430 : Handle<JSFunction>::cast(HConstant::cast(right)->handle(isolate()));
10961 : // Make sure that the {function} already has a meaningful initial map
10962 : // (i.e. we constructed at least one instance using the constructor
10963 : // {function}), and has an instance as .prototype.
10964 826 : if (function->has_initial_map() &&
10965 : !function->map()->has_non_instance_prototype()) {
10966 : // Lookup @@hasInstance on the {function}.
10967 : Handle<Map> function_map(function->map(), isolate());
10968 : PropertyAccessInfo has_instance(
10969 : this, LOAD, function_map,
10970 395 : isolate()->factory()->has_instance_symbol());
10971 : // Check if we are using the Function.prototype[@@hasInstance].
10972 1190 : if (has_instance.CanAccessMonomorphic() &&
10973 724 : has_instance.IsDataConstant() &&
10974 : has_instance.constant().is_identical_to(
10975 1053 : isolate()->function_has_instance())) {
10976 : // Add appropriate receiver map check and prototype chain
10977 : // checks to guard the @@hasInstance lookup chain.
10978 323 : AddCheckMap(right, function_map);
10979 323 : if (has_instance.has_holder()) {
10980 : Handle<JSObject> prototype(
10981 646 : JSObject::cast(has_instance.map()->prototype()), isolate());
10982 323 : BuildCheckPrototypeMaps(prototype, has_instance.holder());
10983 : }
10984 : // Perform the prototype chain walk.
10985 : Handle<Map> initial_map(function->initial_map(), isolate());
10986 323 : top_info()->dependencies()->AssumeInitialMapCantChange(initial_map);
10987 : HInstruction* prototype =
10988 323 : Add<HConstant>(handle(initial_map->prototype(), isolate()));
10989 : HHasInPrototypeChainAndBranch* result =
10990 323 : New<HHasInPrototypeChainAndBranch>(left, prototype);
10991 646 : return ast_context()->ReturnControl(result, expr->id());
10992 : }
10993 : }
10994 : }
10995 :
10996 1216 : Callable callable = CodeFactory::InstanceOf(isolate());
10997 1216 : HValue* stub = Add<HConstant>(callable.code());
10998 1216 : HValue* values[] = {left, right};
10999 : HCallWithDescriptor* result = New<HCallWithDescriptor>(
11000 1216 : stub, 0, callable.descriptor(), ArrayVector(values));
11001 : result->set_type(HType::Boolean());
11002 2432 : return ast_context()->ReturnInstruction(result, expr->id());
11003 :
11004 404749 : } else if (op == Token::IN) {
11005 1194 : Callable callable = CodeFactory::HasProperty(isolate());
11006 1194 : HValue* stub = Add<HConstant>(callable.code());
11007 1194 : HValue* values[] = {left, right};
11008 : HInstruction* result =
11009 : New<HCallWithDescriptor>(stub, 0, callable.descriptor(),
11010 1194 : Vector<HValue*>(values, arraysize(values)));
11011 2388 : return ast_context()->ReturnInstruction(result, expr->id());
11012 : }
11013 :
11014 : PushBeforeSimulateBehavior push_behavior =
11015 403555 : ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE
11016 403555 : : PUSH_BEFORE_SIMULATE;
11017 : HControlInstruction* compare = BuildCompareInstruction(
11018 : op, left, right, left_type, right_type, combined_type,
11019 : ScriptPositionToSourcePosition(expr->left()->position()),
11020 : ScriptPositionToSourcePosition(expr->right()->position()),
11021 1210665 : push_behavior, expr->id());
11022 403555 : if (compare == NULL) return; // Bailed out.
11023 807090 : return ast_context()->ReturnControl(compare, expr->id());
11024 : }
11025 :
11026 431677 : HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction(
11027 1018 : Token::Value op, HValue* left, HValue* right, AstType* left_type,
11028 : AstType* right_type, AstType* combined_type, SourcePosition left_position,
11029 : SourcePosition right_position, PushBeforeSimulateBehavior push_sim_result,
11030 : BailoutId bailout_id) {
11031 : // Cases handled below depend on collected type feedback. They should
11032 : // soft deoptimize when there is no type feedback.
11033 431677 : if (!combined_type->IsInhabited()) {
11034 : Add<HDeoptimize>(
11035 : DeoptimizeReason::
11036 : kInsufficientTypeFeedbackForCombinedTypeOfBinaryOperation,
11037 294867 : Deoptimizer::SOFT);
11038 : combined_type = left_type = right_type = AstType::Any();
11039 : }
11040 :
11041 431677 : Representation left_rep = RepresentationFor(left_type);
11042 431677 : Representation right_rep = RepresentationFor(right_type);
11043 431677 : Representation combined_rep = RepresentationFor(combined_type);
11044 :
11045 431677 : if (combined_type->Is(AstType::Receiver())) {
11046 639 : if (Token::IsEqualityOp(op)) {
11047 : // HCompareObjectEqAndBranch can only deal with object, so
11048 : // exclude numbers.
11049 642 : if ((left->IsConstant() &&
11050 1246 : HConstant::cast(left)->HasNumberValue()) ||
11051 9 : (right->IsConstant() &&
11052 : HConstant::cast(right)->HasNumberValue())) {
11053 : Add<HDeoptimize>(
11054 : DeoptimizeReason::kTypeMismatchBetweenFeedbackAndConstant,
11055 9 : Deoptimizer::SOFT);
11056 : // The caller expects a branch instruction, so make it happy.
11057 9 : return New<HBranch>(graph()->GetConstantTrue());
11058 : }
11059 618 : if (op == Token::EQ) {
11060 : // For abstract equality we need to check both sides are receivers.
11061 109 : if (combined_type->IsClass()) {
11062 18 : Handle<Map> map = combined_type->AsClass()->Map();
11063 18 : AddCheckMap(left, map);
11064 18 : AddCheckMap(right, map);
11065 : } else {
11066 91 : BuildCheckHeapObject(left);
11067 91 : Add<HCheckInstanceType>(left, HCheckInstanceType::IS_JS_RECEIVER);
11068 : BuildCheckHeapObject(right);
11069 91 : Add<HCheckInstanceType>(right, HCheckInstanceType::IS_JS_RECEIVER);
11070 : }
11071 : } else {
11072 : // For strict equality we only need to check one side.
11073 : HValue* operand_to_check =
11074 1018 : left->block()->block_id() < right->block()->block_id() ? left
11075 509 : : right;
11076 509 : if (combined_type->IsClass()) {
11077 32 : Handle<Map> map = combined_type->AsClass()->Map();
11078 32 : AddCheckMap(operand_to_check, map);
11079 : } else {
11080 477 : BuildCheckHeapObject(operand_to_check);
11081 : Add<HCheckInstanceType>(operand_to_check,
11082 477 : HCheckInstanceType::IS_JS_RECEIVER);
11083 : }
11084 : }
11085 : HCompareObjectEqAndBranch* result =
11086 618 : New<HCompareObjectEqAndBranch>(left, right);
11087 618 : return result;
11088 : } else {
11089 12 : if (combined_type->IsClass()) {
11090 : // TODO(bmeurer): This is an optimized version of an x < y, x > y,
11091 : // x <= y or x >= y, where both x and y are spec objects with the
11092 : // same map. The CompareIC collects this map for us. So if we know
11093 : // that there's no @@toPrimitive on the map (including the prototype
11094 : // chain), and both valueOf and toString are the default initial
11095 : // implementations (on the %ObjectPrototype%), then we can reduce
11096 : // the comparison to map checks on x and y, because the comparison
11097 : // will turn into a comparison of "[object CLASS]" to itself (the
11098 : // default outcome of toString, since valueOf returns a spec object).
11099 : // This is pretty much adhoc, so in TurboFan we could do a lot better
11100 : // and inline the interesting parts of ToPrimitive (actually we could
11101 : // even do that in Crankshaft but we don't want to waste too much
11102 : // time on this now).
11103 : DCHECK(Token::IsOrderedRelationalCompareOp(op));
11104 : Handle<Map> map = combined_type->AsClass()->Map();
11105 : PropertyAccessInfo value_of(this, LOAD, map,
11106 12 : isolate()->factory()->valueOf_string());
11107 : PropertyAccessInfo to_primitive(
11108 12 : this, LOAD, map, isolate()->factory()->to_primitive_symbol());
11109 : PropertyAccessInfo to_string(this, LOAD, map,
11110 12 : isolate()->factory()->toString_string());
11111 : PropertyAccessInfo to_string_tag(
11112 12 : this, LOAD, map, isolate()->factory()->to_string_tag_symbol());
11113 40 : if (to_primitive.CanAccessMonomorphic() && !to_primitive.IsFound() &&
11114 8 : to_string_tag.CanAccessMonomorphic() &&
11115 4 : (!to_string_tag.IsFound() || to_string_tag.IsData() ||
11116 4 : to_string_tag.IsDataConstant()) &&
11117 12 : value_of.CanAccessMonomorphic() && value_of.IsDataConstant() &&
11118 24 : value_of.constant().is_identical_to(isolate()->object_value_of()) &&
11119 22 : to_string.CanAccessMonomorphic() && to_string.IsDataConstant() &&
11120 : to_string.constant().is_identical_to(
11121 14 : isolate()->object_to_string())) {
11122 : // We depend on the prototype chain to stay the same, because we
11123 : // also need to deoptimize when someone installs @@toPrimitive
11124 : // or @@toStringTag somewhere in the prototype chain.
11125 : Handle<Object> prototype(map->prototype(), isolate());
11126 2 : if (prototype->IsJSObject()) {
11127 : BuildCheckPrototypeMaps(Handle<JSObject>::cast(prototype),
11128 0 : Handle<JSObject>::null());
11129 : }
11130 2 : AddCheckMap(left, map);
11131 2 : AddCheckMap(right, map);
11132 : // The caller expects a branch instruction, so make it happy.
11133 : return New<HBranch>(
11134 4 : graph()->GetConstantBool(op == Token::LTE || op == Token::GTE));
11135 : }
11136 : }
11137 : Bailout(kUnsupportedNonPrimitiveCompare);
11138 10 : return NULL;
11139 : }
11140 439897 : } else if (combined_type->Is(AstType::InternalizedString()) &&
11141 : Token::IsEqualityOp(op)) {
11142 : // If we have a constant argument, it should be consistent with the type
11143 : // feedback (otherwise we fail assertions in HCompareObjectEqAndBranch).
11144 9099 : if ((left->IsConstant() &&
11145 17716 : !HConstant::cast(left)->HasInternalizedStringValue()) ||
11146 4007 : (right->IsConstant() &&
11147 4007 : !HConstant::cast(right)->HasInternalizedStringValue())) {
11148 : Add<HDeoptimize>(
11149 : DeoptimizeReason::kTypeMismatchBetweenFeedbackAndConstant,
11150 2 : Deoptimizer::SOFT);
11151 : // The caller expects a branch instruction, so make it happy.
11152 2 : return New<HBranch>(graph()->GetConstantTrue());
11153 : }
11154 8857 : BuildCheckHeapObject(left);
11155 8857 : Add<HCheckInstanceType>(left, HCheckInstanceType::IS_INTERNALIZED_STRING);
11156 : BuildCheckHeapObject(right);
11157 8857 : Add<HCheckInstanceType>(right, HCheckInstanceType::IS_INTERNALIZED_STRING);
11158 : HCompareObjectEqAndBranch* result =
11159 8857 : New<HCompareObjectEqAndBranch>(left, right);
11160 8857 : return result;
11161 422179 : } else if (combined_type->Is(AstType::String())) {
11162 15130 : BuildCheckHeapObject(left);
11163 15130 : Add<HCheckInstanceType>(left, HCheckInstanceType::IS_STRING);
11164 : BuildCheckHeapObject(right);
11165 15130 : Add<HCheckInstanceType>(right, HCheckInstanceType::IS_STRING);
11166 : HStringCompareAndBranch* result =
11167 15130 : New<HStringCompareAndBranch>(left, right, op);
11168 15130 : return result;
11169 407049 : } else if (combined_type->Is(AstType::Boolean())) {
11170 637 : AddCheckMap(left, isolate()->factory()->boolean_map());
11171 637 : AddCheckMap(right, isolate()->factory()->boolean_map());
11172 637 : if (Token::IsEqualityOp(op)) {
11173 : HCompareObjectEqAndBranch* result =
11174 603 : New<HCompareObjectEqAndBranch>(left, right);
11175 603 : return result;
11176 : }
11177 : left = Add<HLoadNamedField>(
11178 : left, nullptr,
11179 34 : HObjectAccess::ForOddballToNumber(Representation::Smi()));
11180 : right = Add<HLoadNamedField>(
11181 : right, nullptr,
11182 34 : HObjectAccess::ForOddballToNumber(Representation::Smi()));
11183 : HCompareNumericAndBranch* result =
11184 34 : New<HCompareNumericAndBranch>(left, right, op);
11185 34 : return result;
11186 : } else {
11187 406412 : if (op == Token::EQ) {
11188 20948 : if (left->IsConstant() &&
11189 19477 : HConstant::cast(left)->GetInstanceType() == ODDBALL_TYPE &&
11190 : HConstant::cast(left)->IsUndetectable()) {
11191 0 : return New<HIsUndetectableAndBranch>(right);
11192 : }
11193 :
11194 32204 : if (right->IsConstant() &&
11195 19490 : HConstant::cast(right)->GetInstanceType() == ODDBALL_TYPE &&
11196 : HConstant::cast(right)->IsUndetectable()) {
11197 1 : return New<HIsUndetectableAndBranch>(left);
11198 : }
11199 : }
11200 :
11201 406411 : if (combined_rep.IsTagged() || combined_rep.IsNone()) {
11202 326725 : HCompareGeneric* result = Add<HCompareGeneric>(left, right, op);
11203 : result->set_observed_input_representation(1, left_rep);
11204 : result->set_observed_input_representation(2, right_rep);
11205 326725 : if (result->HasObservableSideEffects()) {
11206 326725 : if (push_sim_result == PUSH_BEFORE_SIMULATE) {
11207 326645 : Push(result);
11208 : AddSimulate(bailout_id, REMOVABLE_SIMULATE);
11209 : Drop(1);
11210 : } else {
11211 : AddSimulate(bailout_id, REMOVABLE_SIMULATE);
11212 : }
11213 : }
11214 : // TODO(jkummerow): Can we make this more efficient?
11215 326725 : HBranch* branch = New<HBranch>(result);
11216 326725 : return branch;
11217 : } else {
11218 : HCompareNumericAndBranch* result =
11219 79686 : New<HCompareNumericAndBranch>(left, right, op);
11220 : result->set_observed_input_representation(left_rep, right_rep);
11221 79686 : return result;
11222 : }
11223 : }
11224 : }
11225 :
11226 :
11227 35158 : void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
11228 : Expression* sub_expr,
11229 35158 : NilValue nil) {
11230 : DCHECK(!HasStackOverflow());
11231 : DCHECK(current_block() != NULL);
11232 : DCHECK(current_block()->HasPredecessor());
11233 : DCHECK(expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT);
11234 51256 : if (!is_tracking_positions()) SetSourcePosition(expr->position());
11235 52737 : CHECK_ALIVE(VisitForValue(sub_expr));
11236 : HValue* value = Pop();
11237 : HControlInstruction* instr;
11238 17579 : if (expr->op() == Token::EQ_STRICT) {
11239 : HConstant* nil_constant = nil == kNullValue
11240 : ? graph()->GetConstantNull()
11241 32196 : : graph()->GetConstantUndefined();
11242 16098 : instr = New<HCompareObjectEqAndBranch>(value, nil_constant);
11243 : } else {
11244 : DCHECK_EQ(Token::EQ, expr->op());
11245 1481 : instr = New<HIsUndetectableAndBranch>(value);
11246 : }
11247 35158 : return ast_context()->ReturnControl(instr, expr->id());
11248 : }
11249 :
11250 :
11251 0 : void HOptimizedGraphBuilder::VisitSpread(Spread* expr) { UNREACHABLE(); }
11252 :
11253 :
11254 0 : void HOptimizedGraphBuilder::VisitEmptyParentheses(EmptyParentheses* expr) {
11255 0 : UNREACHABLE();
11256 : }
11257 :
11258 0 : void HOptimizedGraphBuilder::VisitGetIterator(GetIterator* expr) {
11259 0 : UNREACHABLE();
11260 : }
11261 :
11262 0 : void HOptimizedGraphBuilder::VisitImportCallExpression(
11263 : ImportCallExpression* expr) {
11264 0 : UNREACHABLE();
11265 : }
11266 :
11267 42161 : HValue* HOptimizedGraphBuilder::AddThisFunction() {
11268 42161 : return AddInstruction(BuildThisFunction());
11269 : }
11270 :
11271 :
11272 92876 : HInstruction* HOptimizedGraphBuilder::BuildThisFunction() {
11273 : // If we share optimized code between different closures, the
11274 : // this-function is not a constant, except inside an inlined body.
11275 92876 : if (function_state()->outer() != NULL) {
11276 : return New<HConstant>(
11277 48562 : function_state()->compilation_info()->closure());
11278 : } else {
11279 44314 : return New<HThisFunction>();
11280 : }
11281 : }
11282 :
11283 :
11284 7326 : HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
11285 : Handle<JSObject> boilerplate_object,
11286 : AllocationSiteUsageContext* site_context) {
11287 60566 : NoObservableSideEffectsScope no_effects(this);
11288 : Handle<Map> initial_map(boilerplate_object->map());
11289 : InstanceType instance_type = initial_map->instance_type();
11290 : DCHECK(instance_type == JS_ARRAY_TYPE || instance_type == JS_OBJECT_TYPE);
11291 :
11292 : HType type = instance_type == JS_ARRAY_TYPE
11293 7326 : ? HType::JSArray() : HType::JSObject();
11294 7326 : HValue* object_size_constant = Add<HConstant>(initial_map->instance_size());
11295 :
11296 : PretenureFlag pretenure_flag = NOT_TENURED;
11297 : Handle<AllocationSite> top_site(*site_context->top(), isolate());
11298 7326 : if (FLAG_allocation_site_pretenuring) {
11299 7326 : pretenure_flag = top_site->GetPretenureMode();
11300 : }
11301 :
11302 : Handle<AllocationSite> current_site(*site_context->current(), isolate());
11303 7326 : if (*top_site == *current_site) {
11304 : // We install a dependency for pretenuring only on the outermost literal.
11305 6664 : top_info()->dependencies()->AssumeTenuringDecision(top_site);
11306 : }
11307 7326 : top_info()->dependencies()->AssumeTransitionStable(current_site);
11308 :
11309 : HInstruction* object =
11310 : Add<HAllocate>(object_size_constant, type, pretenure_flag, instance_type,
11311 7326 : graph()->GetConstant0(), top_site);
11312 :
11313 : // If allocation folding reaches kMaxRegularHeapObjectSize the
11314 : // elements array may not get folded into the object. Hence, we set the
11315 : // elements pointer to empty fixed array and let store elimination remove
11316 : // this store in the folding case.
11317 : HConstant* empty_fixed_array = Add<HConstant>(
11318 7326 : isolate()->factory()->empty_fixed_array());
11319 : Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
11320 7326 : empty_fixed_array);
11321 :
11322 7326 : BuildEmitObjectHeader(boilerplate_object, object);
11323 :
11324 : // Similarly to the elements pointer, there is no guarantee that all
11325 : // property allocations can get folded, so pre-initialize all in-object
11326 : // properties to a safe value.
11327 7326 : BuildInitializeInobjectProperties(object, initial_map);
11328 :
11329 : // Copy in-object properties.
11330 11577 : if (initial_map->NumberOfFields() != 0 ||
11331 : initial_map->unused_property_fields() > 0) {
11332 : BuildEmitInObjectProperties(boilerplate_object, object, site_context,
11333 3941 : pretenure_flag);
11334 : }
11335 :
11336 : // Copy elements.
11337 : Handle<FixedArrayBase> elements(boilerplate_object->elements());
11338 2589 : int elements_size = (elements->length() > 0 &&
11339 2589 : elements->map() != isolate()->heap()->fixed_cow_array_map()) ?
11340 9153 : elements->Size() : 0;
11341 :
11342 7357 : if (pretenure_flag == TENURED &&
11343 7357 : elements->map() == isolate()->heap()->fixed_cow_array_map() &&
11344 : isolate()->heap()->InNewSpace(*elements)) {
11345 : // If we would like to pretenure a fixed cow array, we must ensure that the
11346 : // array is already in old space, otherwise we'll create too many old-to-
11347 : // new-space pointers (overflowing the store buffer).
11348 : elements = Handle<FixedArrayBase>(
11349 : isolate()->factory()->CopyAndTenureFixedCOWArray(
11350 0 : Handle<FixedArray>::cast(elements)));
11351 0 : boilerplate_object->set_elements(*elements);
11352 : }
11353 :
11354 : HInstruction* object_elements = NULL;
11355 7326 : if (elements_size > 0) {
11356 1827 : HValue* object_elements_size = Add<HConstant>(elements_size);
11357 1827 : InstanceType instance_type = boilerplate_object->HasFastDoubleElements()
11358 1827 : ? FIXED_DOUBLE_ARRAY_TYPE : FIXED_ARRAY_TYPE;
11359 : object_elements = Add<HAllocate>(object_elements_size, HType::HeapObject(),
11360 : pretenure_flag, instance_type,
11361 1827 : graph()->GetConstant0(), top_site);
11362 : BuildEmitElements(boilerplate_object, elements, object_elements,
11363 1827 : site_context);
11364 : Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
11365 1827 : object_elements);
11366 : } else {
11367 : Handle<Object> elements_field =
11368 : Handle<Object>(boilerplate_object->elements(), isolate());
11369 5499 : HInstruction* object_elements_cow = Add<HConstant>(elements_field);
11370 : Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
11371 5499 : object_elements_cow);
11372 : }
11373 :
11374 7326 : return object;
11375 : }
11376 :
11377 :
11378 7326 : void HOptimizedGraphBuilder::BuildEmitObjectHeader(
11379 : Handle<JSObject> boilerplate_object,
11380 : HInstruction* object) {
11381 : DCHECK(boilerplate_object->properties()->length() == 0);
11382 :
11383 : Handle<Map> boilerplate_object_map(boilerplate_object->map());
11384 10711 : AddStoreMapConstant(object, boilerplate_object_map);
11385 :
11386 : Handle<Object> properties_field =
11387 : Handle<Object>(boilerplate_object->properties(), isolate());
11388 : DCHECK(*properties_field == isolate()->heap()->empty_fixed_array());
11389 7326 : HInstruction* properties = Add<HConstant>(properties_field);
11390 7326 : HObjectAccess access = HObjectAccess::ForPropertiesPointer();
11391 7326 : Add<HStoreNamedField>(object, access, properties);
11392 :
11393 7326 : if (boilerplate_object->IsJSArray()) {
11394 : Handle<JSArray> boilerplate_array =
11395 : Handle<JSArray>::cast(boilerplate_object);
11396 : Handle<Object> length_field =
11397 : Handle<Object>(boilerplate_array->length(), isolate());
11398 3385 : HInstruction* length = Add<HConstant>(length_field);
11399 :
11400 : DCHECK(boilerplate_array->length()->IsSmi());
11401 : Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(
11402 3385 : boilerplate_array->GetElementsKind()), length);
11403 : }
11404 7326 : }
11405 :
11406 :
11407 3941 : void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
11408 : Handle<JSObject> boilerplate_object,
11409 : HInstruction* object,
11410 : AllocationSiteUsageContext* site_context,
11411 : PretenureFlag pretenure_flag) {
11412 : Handle<Map> boilerplate_map(boilerplate_object->map());
11413 : Handle<DescriptorArray> descriptors(boilerplate_map->instance_descriptors());
11414 : int limit = boilerplate_map->NumberOfOwnDescriptors();
11415 :
11416 : int copied_fields = 0;
11417 11399 : for (int i = 0; i < limit; i++) {
11418 7458 : PropertyDetails details = descriptors->GetDetails(i);
11419 7537 : if (details.location() != kField) continue;
11420 : DCHECK_EQ(kData, details.kind());
11421 7458 : copied_fields++;
11422 7458 : FieldIndex field_index = FieldIndex::ForDescriptor(*boilerplate_map, i);
11423 :
11424 :
11425 : int property_offset = field_index.offset();
11426 : Handle<Name> name(descriptors->GetKey(i));
11427 :
11428 : // The access for the store depends on the type of the boilerplate.
11429 : HObjectAccess access = boilerplate_object->IsJSArray() ?
11430 : HObjectAccess::ForJSArrayOffset(property_offset) :
11431 7458 : HObjectAccess::ForMapAndOffset(boilerplate_map, property_offset);
11432 :
11433 7458 : if (boilerplate_object->IsUnboxedDoubleField(field_index)) {
11434 79 : CHECK(!boilerplate_object->IsJSArray());
11435 : double value = boilerplate_object->RawFastDoublePropertyAt(field_index);
11436 79 : access = access.WithRepresentation(Representation::Double());
11437 9496 : Add<HStoreNamedField>(object, access, Add<HConstant>(value));
11438 79 : continue;
11439 : }
11440 : Handle<Object> value(boilerplate_object->RawFastPropertyAt(field_index),
11441 7379 : isolate());
11442 :
11443 7379 : if (value->IsJSObject()) {
11444 349 : Handle<JSObject> value_object = Handle<JSObject>::cast(value);
11445 349 : Handle<AllocationSite> current_site = site_context->EnterNewScope();
11446 : HInstruction* result =
11447 349 : BuildFastLiteral(value_object, site_context);
11448 : site_context->ExitScope(current_site, value_object);
11449 349 : Add<HStoreNamedField>(object, access, result);
11450 : } else {
11451 : Representation representation = details.representation();
11452 : HInstruction* value_instruction;
11453 :
11454 7030 : if (representation.IsDouble()) {
11455 : // Allocate a HeapNumber box and store the value into it.
11456 0 : HValue* heap_number_constant = Add<HConstant>(HeapNumber::kSize);
11457 : HInstruction* double_box = Add<HAllocate>(
11458 : heap_number_constant, HType::HeapObject(), pretenure_flag,
11459 0 : MUTABLE_HEAP_NUMBER_TYPE, graph()->GetConstant0());
11460 : AddStoreMapConstant(double_box,
11461 0 : isolate()->factory()->mutable_heap_number_map());
11462 : // Unwrap the mutable heap number from the boilerplate.
11463 : HValue* double_value =
11464 0 : Add<HConstant>(Handle<HeapNumber>::cast(value)->value());
11465 : Add<HStoreNamedField>(
11466 0 : double_box, HObjectAccess::ForHeapNumberValue(), double_value);
11467 : value_instruction = double_box;
11468 7030 : } else if (representation.IsSmi()) {
11469 : value_instruction = value->IsUninitialized(isolate())
11470 : ? graph()->GetConstant0()
11471 3167 : : Add<HConstant>(value);
11472 : // Ensure that value is stored as smi.
11473 2881 : access = access.WithRepresentation(representation);
11474 : } else {
11475 4149 : value_instruction = Add<HConstant>(value);
11476 : }
11477 :
11478 7030 : Add<HStoreNamedField>(object, access, value_instruction);
11479 : }
11480 : }
11481 :
11482 : int inobject_properties = boilerplate_object->map()->GetInObjectProperties();
11483 : HInstruction* value_instruction =
11484 3941 : Add<HConstant>(isolate()->factory()->one_pointer_filler_map());
11485 7416 : for (int i = copied_fields; i < inobject_properties; i++) {
11486 : DCHECK(boilerplate_object->IsJSObject());
11487 3475 : int property_offset = boilerplate_object->GetInObjectPropertyOffset(i);
11488 : HObjectAccess access =
11489 3475 : HObjectAccess::ForMapAndOffset(boilerplate_map, property_offset);
11490 3475 : Add<HStoreNamedField>(object, access, value_instruction);
11491 : }
11492 3941 : }
11493 :
11494 :
11495 1827 : void HOptimizedGraphBuilder::BuildEmitElements(
11496 : Handle<JSObject> boilerplate_object,
11497 : Handle<FixedArrayBase> elements,
11498 : HValue* object_elements,
11499 : AllocationSiteUsageContext* site_context) {
11500 : ElementsKind kind = boilerplate_object->map()->elements_kind();
11501 : int elements_length = elements->length();
11502 1827 : HValue* object_elements_length = Add<HConstant>(elements_length);
11503 1827 : BuildInitializeElementsHeader(object_elements, kind, object_elements_length);
11504 :
11505 : // Copy elements backing store content.
11506 1827 : if (elements->IsFixedDoubleArray()) {
11507 431 : BuildEmitFixedDoubleArray(elements, kind, object_elements);
11508 1396 : } else if (elements->IsFixedArray()) {
11509 : BuildEmitFixedArray(elements, kind, object_elements,
11510 1396 : site_context);
11511 : } else {
11512 0 : UNREACHABLE();
11513 : }
11514 1827 : }
11515 :
11516 :
11517 431 : void HOptimizedGraphBuilder::BuildEmitFixedDoubleArray(
11518 : Handle<FixedArrayBase> elements,
11519 : ElementsKind kind,
11520 : HValue* object_elements) {
11521 431 : HInstruction* boilerplate_elements = Add<HConstant>(elements);
11522 : int elements_length = elements->length();
11523 6237 : for (int i = 0; i < elements_length; i++) {
11524 5806 : HValue* key_constant = Add<HConstant>(i);
11525 : HInstruction* value_instruction =
11526 : Add<HLoadKeyed>(boilerplate_elements, key_constant, nullptr, nullptr,
11527 5806 : kind, ALLOW_RETURN_HOLE);
11528 : HInstruction* store = Add<HStoreKeyed>(object_elements, key_constant,
11529 5806 : value_instruction, nullptr, kind);
11530 : store->SetFlag(HValue::kTruncatingToNumber);
11531 : }
11532 431 : }
11533 :
11534 :
11535 1396 : void HOptimizedGraphBuilder::BuildEmitFixedArray(
11536 : Handle<FixedArrayBase> elements,
11537 : ElementsKind kind,
11538 : HValue* object_elements,
11539 : AllocationSiteUsageContext* site_context) {
11540 8230 : HInstruction* boilerplate_elements = Add<HConstant>(elements);
11541 : int elements_length = elements->length();
11542 : Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
11543 8230 : for (int i = 0; i < elements_length; i++) {
11544 : Handle<Object> value(fast_elements->get(i), isolate());
11545 6834 : HValue* key_constant = Add<HConstant>(i);
11546 6834 : if (value->IsJSObject()) {
11547 313 : Handle<JSObject> value_object = Handle<JSObject>::cast(value);
11548 313 : Handle<AllocationSite> current_site = site_context->EnterNewScope();
11549 : HInstruction* result =
11550 313 : BuildFastLiteral(value_object, site_context);
11551 : site_context->ExitScope(current_site, value_object);
11552 313 : Add<HStoreKeyed>(object_elements, key_constant, result, nullptr, kind);
11553 : } else {
11554 : ElementsKind copy_kind =
11555 6521 : kind == FAST_HOLEY_SMI_ELEMENTS ? FAST_HOLEY_ELEMENTS : kind;
11556 : HInstruction* value_instruction =
11557 : Add<HLoadKeyed>(boilerplate_elements, key_constant, nullptr, nullptr,
11558 6521 : copy_kind, ALLOW_RETURN_HOLE);
11559 : Add<HStoreKeyed>(object_elements, key_constant, value_instruction,
11560 6521 : nullptr, copy_kind);
11561 : }
11562 : }
11563 1396 : }
11564 :
11565 :
11566 101430 : void HOptimizedGraphBuilder::VisitThisFunction(ThisFunction* expr) {
11567 : DCHECK(!HasStackOverflow());
11568 : DCHECK(current_block() != NULL);
11569 : DCHECK(current_block()->HasPredecessor());
11570 50715 : HInstruction* instr = BuildThisFunction();
11571 101430 : return ast_context()->ReturnInstruction(instr, expr->id());
11572 : }
11573 :
11574 :
11575 0 : void HOptimizedGraphBuilder::VisitSuperPropertyReference(
11576 : SuperPropertyReference* expr) {
11577 : DCHECK(!HasStackOverflow());
11578 : DCHECK(current_block() != NULL);
11579 : DCHECK(current_block()->HasPredecessor());
11580 0 : return Bailout(kSuperReference);
11581 : }
11582 :
11583 :
11584 0 : void HOptimizedGraphBuilder::VisitSuperCallReference(SuperCallReference* expr) {
11585 : DCHECK(!HasStackOverflow());
11586 : DCHECK(current_block() != NULL);
11587 : DCHECK(current_block()->HasPredecessor());
11588 0 : return Bailout(kSuperReference);
11589 : }
11590 :
11591 379346 : void HOptimizedGraphBuilder::VisitDeclarations(
11592 : Declaration::List* declarations) {
11593 : DCHECK(globals_.is_empty());
11594 : AstVisitor<HOptimizedGraphBuilder>::VisitDeclarations(declarations);
11595 933418 : if (!globals_.is_empty()) {
11596 : Handle<FixedArray> array =
11597 37272 : isolate()->factory()->NewFixedArray(globals_.length(), TENURED);
11598 1108144 : for (int i = 0; i < globals_.length(); ++i) array->set(i, *globals_.at(i));
11599 12424 : int flags = current_info()->GetDeclareGlobalsFlags();
11600 : Handle<FeedbackVector> vector(current_feedback_vector(), isolate());
11601 12424 : Add<HDeclareGlobals>(array, flags, vector);
11602 : globals_.Rewind(0);
11603 : }
11604 379346 : }
11605 :
11606 :
11607 436396 : void HOptimizedGraphBuilder::VisitVariableDeclaration(
11608 : VariableDeclaration* declaration) {
11609 436396 : VariableProxy* proxy = declaration->proxy();
11610 571972 : Variable* variable = proxy->var();
11611 436396 : switch (variable->location()) {
11612 : case VariableLocation::UNALLOCATED: {
11613 : DCHECK(!variable->binding_needs_init());
11614 808146 : globals_.Add(variable->name(), zone());
11615 : FeedbackSlot slot = proxy->VariableFeedbackSlot();
11616 : DCHECK(!slot.IsInvalid());
11617 108099 : globals_.Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
11618 108099 : globals_.Add(isolate()->factory()->undefined_value(), zone());
11619 108099 : globals_.Add(isolate()->factory()->undefined_value(), zone());
11620 : return;
11621 : }
11622 : case VariableLocation::PARAMETER:
11623 : case VariableLocation::LOCAL:
11624 293155 : if (variable->binding_needs_init()) {
11625 23976 : HValue* value = graph()->GetConstantHole();
11626 23976 : environment()->Bind(variable, value);
11627 : }
11628 : break;
11629 : case VariableLocation::CONTEXT:
11630 35142 : if (variable->binding_needs_init()) {
11631 27477 : HValue* value = graph()->GetConstantHole();
11632 : HValue* context = environment()->context();
11633 : HStoreContextSlot* store = Add<HStoreContextSlot>(
11634 27477 : context, variable->index(), HStoreContextSlot::kNoCheck, value);
11635 27477 : if (store->HasObservableSideEffects()) {
11636 27477 : Add<HSimulate>(proxy->id(), REMOVABLE_SIMULATE);
11637 : }
11638 : }
11639 : break;
11640 : case VariableLocation::LOOKUP:
11641 : return Bailout(kUnsupportedLookupSlotInDeclaration);
11642 : case VariableLocation::MODULE:
11643 0 : UNREACHABLE();
11644 : }
11645 : }
11646 :
11647 :
11648 34388 : void HOptimizedGraphBuilder::VisitFunctionDeclaration(
11649 68776 : FunctionDeclaration* declaration) {
11650 34388 : VariableProxy* proxy = declaration->proxy();
11651 64367 : Variable* variable = proxy->var();
11652 34388 : switch (variable->location()) {
11653 : case VariableLocation::UNALLOCATED: {
11654 198266 : globals_.Add(variable->name(), zone());
11655 : FeedbackSlot slot = proxy->VariableFeedbackSlot();
11656 : DCHECK(!slot.IsInvalid());
11657 27313 : globals_.Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
11658 :
11659 : // We need the slot where the literals array lives, too.
11660 : slot = declaration->fun()->LiteralFeedbackSlot();
11661 : DCHECK(!slot.IsInvalid());
11662 27313 : globals_.Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
11663 :
11664 : Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo(
11665 54626 : declaration->fun(), current_info()->script(), top_info());
11666 : // Check for stack-overflow exception.
11667 27313 : if (function.is_null()) return SetStackOverflow();
11668 27313 : globals_.Add(function, zone());
11669 27313 : return;
11670 : }
11671 : case VariableLocation::PARAMETER:
11672 : case VariableLocation::LOCAL: {
11673 13227 : CHECK_ALIVE(VisitForValue(declaration->fun()));
11674 : HValue* value = Pop();
11675 4409 : BindIfLive(variable, value);
11676 4409 : break;
11677 : }
11678 : case VariableLocation::CONTEXT: {
11679 7998 : CHECK_ALIVE(VisitForValue(declaration->fun()));
11680 : HValue* value = Pop();
11681 : HValue* context = environment()->context();
11682 : HStoreContextSlot* store = Add<HStoreContextSlot>(
11683 2666 : context, variable->index(), HStoreContextSlot::kNoCheck, value);
11684 2666 : if (store->HasObservableSideEffects()) {
11685 2666 : Add<HSimulate>(proxy->id(), REMOVABLE_SIMULATE);
11686 : }
11687 : break;
11688 : }
11689 : case VariableLocation::LOOKUP:
11690 : return Bailout(kUnsupportedLookupSlotInDeclaration);
11691 : case VariableLocation::MODULE:
11692 0 : UNREACHABLE();
11693 : }
11694 : }
11695 :
11696 :
11697 8 : void HOptimizedGraphBuilder::VisitRewritableExpression(
11698 8 : RewritableExpression* node) {
11699 8 : CHECK_ALIVE(Visit(node->expression()));
11700 : }
11701 :
11702 :
11703 : // Generators for inline runtime functions.
11704 : // Support for types.
11705 4872 : void HOptimizedGraphBuilder::GenerateIsSmi(CallRuntime* call) {
11706 : DCHECK(call->arguments()->length() == 1);
11707 3248 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11708 : HValue* value = Pop();
11709 1624 : HIsSmiAndBranch* result = New<HIsSmiAndBranch>(value);
11710 3248 : return ast_context()->ReturnControl(result, call->id());
11711 : }
11712 :
11713 :
11714 2757 : void HOptimizedGraphBuilder::GenerateIsJSReceiver(CallRuntime* call) {
11715 : DCHECK(call->arguments()->length() == 1);
11716 1838 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11717 : HValue* value = Pop();
11718 : HHasInstanceTypeAndBranch* result =
11719 : New<HHasInstanceTypeAndBranch>(value,
11720 : FIRST_JS_RECEIVER_TYPE,
11721 919 : LAST_JS_RECEIVER_TYPE);
11722 1838 : return ast_context()->ReturnControl(result, call->id());
11723 : }
11724 :
11725 2346 : void HOptimizedGraphBuilder::GenerateIsArray(CallRuntime* call) {
11726 : DCHECK(call->arguments()->length() == 1);
11727 1564 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11728 : HValue* value = Pop();
11729 : HHasInstanceTypeAndBranch* result =
11730 782 : New<HHasInstanceTypeAndBranch>(value, JS_ARRAY_TYPE);
11731 1564 : return ast_context()->ReturnControl(result, call->id());
11732 : }
11733 :
11734 :
11735 156 : void HOptimizedGraphBuilder::GenerateIsTypedArray(CallRuntime* call) {
11736 : DCHECK(call->arguments()->length() == 1);
11737 104 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11738 : HValue* value = Pop();
11739 : HHasInstanceTypeAndBranch* result =
11740 52 : New<HHasInstanceTypeAndBranch>(value, JS_TYPED_ARRAY_TYPE);
11741 104 : return ast_context()->ReturnControl(result, call->id());
11742 : }
11743 :
11744 :
11745 933 : void HOptimizedGraphBuilder::GenerateToInteger(CallRuntime* call) {
11746 : DCHECK_EQ(1, call->arguments()->length());
11747 933 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11748 : HValue* input = Pop();
11749 311 : if (input->type().IsSmi()) {
11750 0 : return ast_context()->ReturnValue(input);
11751 : } else {
11752 311 : Callable callable = CodeFactory::ToInteger(isolate());
11753 311 : HValue* stub = Add<HConstant>(callable.code());
11754 311 : HValue* values[] = {input};
11755 : HInstruction* result = New<HCallWithDescriptor>(
11756 311 : stub, 0, callable.descriptor(), ArrayVector(values));
11757 622 : return ast_context()->ReturnInstruction(result, call->id());
11758 : }
11759 : }
11760 :
11761 :
11762 1143 : void HOptimizedGraphBuilder::GenerateToObject(CallRuntime* call) {
11763 : DCHECK_EQ(1, call->arguments()->length());
11764 762 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11765 : HValue* value = Pop();
11766 381 : HValue* result = BuildToObject(value);
11767 381 : return ast_context()->ReturnValue(result);
11768 : }
11769 :
11770 :
11771 6411 : void HOptimizedGraphBuilder::GenerateToString(CallRuntime* call) {
11772 : DCHECK_EQ(1, call->arguments()->length());
11773 6358 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11774 : HValue* input = Pop();
11775 2137 : if (input->type().IsString()) {
11776 53 : return ast_context()->ReturnValue(input);
11777 : } else {
11778 2084 : Callable callable = CodeFactory::ToString(isolate());
11779 2084 : HValue* stub = Add<HConstant>(callable.code());
11780 2084 : HValue* values[] = {input};
11781 : HInstruction* result = New<HCallWithDescriptor>(
11782 2084 : stub, 0, callable.descriptor(), ArrayVector(values));
11783 4168 : return ast_context()->ReturnInstruction(result, call->id());
11784 : }
11785 : }
11786 :
11787 :
11788 1032 : void HOptimizedGraphBuilder::GenerateToLength(CallRuntime* call) {
11789 : DCHECK_EQ(1, call->arguments()->length());
11790 688 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11791 344 : Callable callable = CodeFactory::ToLength(isolate());
11792 : HValue* input = Pop();
11793 344 : HValue* stub = Add<HConstant>(callable.code());
11794 344 : HValue* values[] = {input};
11795 : HInstruction* result = New<HCallWithDescriptor>(
11796 344 : stub, 0, callable.descriptor(), ArrayVector(values));
11797 688 : return ast_context()->ReturnInstruction(result, call->id());
11798 : }
11799 :
11800 :
11801 420 : void HOptimizedGraphBuilder::GenerateToNumber(CallRuntime* call) {
11802 : DCHECK_EQ(1, call->arguments()->length());
11803 168 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11804 84 : Callable callable = CodeFactory::ToNumber(isolate());
11805 : HValue* input = Pop();
11806 84 : HValue* result = BuildToNumber(input);
11807 84 : if (result->HasObservableSideEffects()) {
11808 84 : if (!ast_context()->IsEffect()) Push(result);
11809 84 : Add<HSimulate>(call->id(), REMOVABLE_SIMULATE);
11810 84 : if (!ast_context()->IsEffect()) result = Pop();
11811 : }
11812 84 : return ast_context()->ReturnValue(result);
11813 : }
11814 :
11815 :
11816 2529 : void HOptimizedGraphBuilder::GenerateIsJSProxy(CallRuntime* call) {
11817 : DCHECK(call->arguments()->length() == 1);
11818 1686 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11819 : HValue* value = Pop();
11820 : HIfContinuation continuation;
11821 843 : IfBuilder if_proxy(this);
11822 :
11823 : HValue* smicheck = if_proxy.IfNot<HIsSmiAndBranch>(value);
11824 843 : if_proxy.And();
11825 843 : HValue* map = Add<HLoadNamedField>(value, smicheck, HObjectAccess::ForMap());
11826 : HValue* instance_type =
11827 843 : Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapInstanceType());
11828 : if_proxy.If<HCompareNumericAndBranch>(
11829 843 : instance_type, Add<HConstant>(JS_PROXY_TYPE), Token::EQ);
11830 :
11831 843 : if_proxy.CaptureContinuation(&continuation);
11832 1686 : return ast_context()->ReturnContinuation(&continuation, call->id());
11833 : }
11834 :
11835 :
11836 30 : void HOptimizedGraphBuilder::GenerateHasFastPackedElements(CallRuntime* call) {
11837 : DCHECK(call->arguments()->length() == 1);
11838 40 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11839 : HValue* object = Pop();
11840 : HIfContinuation continuation(graph()->CreateBasicBlock(),
11841 20 : graph()->CreateBasicBlock());
11842 10 : IfBuilder if_not_smi(this);
11843 : if_not_smi.IfNot<HIsSmiAndBranch>(object);
11844 10 : if_not_smi.Then();
11845 : {
11846 : NoObservableSideEffectsScope no_effects(this);
11847 :
11848 : IfBuilder if_fast_packed(this);
11849 10 : HValue* elements_kind = BuildGetElementsKind(object);
11850 : if_fast_packed.If<HCompareNumericAndBranch>(
11851 10 : elements_kind, Add<HConstant>(FAST_SMI_ELEMENTS), Token::EQ);
11852 10 : if_fast_packed.Or();
11853 : if_fast_packed.If<HCompareNumericAndBranch>(
11854 10 : elements_kind, Add<HConstant>(FAST_ELEMENTS), Token::EQ);
11855 10 : if_fast_packed.Or();
11856 : if_fast_packed.If<HCompareNumericAndBranch>(
11857 10 : elements_kind, Add<HConstant>(FAST_DOUBLE_ELEMENTS), Token::EQ);
11858 10 : if_fast_packed.JoinContinuation(&continuation);
11859 : }
11860 10 : if_not_smi.JoinContinuation(&continuation);
11861 20 : return ast_context()->ReturnContinuation(&continuation, call->id());
11862 : }
11863 :
11864 :
11865 : // Fast support for charCodeAt(n).
11866 600 : void HOptimizedGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) {
11867 : DCHECK(call->arguments()->length() == 2);
11868 360 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11869 360 : CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
11870 : HValue* index = Pop();
11871 : HValue* string = Pop();
11872 120 : HInstruction* result = BuildStringCharCodeAt(string, index);
11873 240 : return ast_context()->ReturnInstruction(result, call->id());
11874 : }
11875 :
11876 :
11877 : // Fast support for SubString.
11878 414 : void HOptimizedGraphBuilder::GenerateSubString(CallRuntime* call) {
11879 : DCHECK_EQ(3, call->arguments()->length());
11880 276 : CHECK_ALIVE(VisitExpressions(call->arguments()));
11881 138 : Callable callable = CodeFactory::SubString(isolate());
11882 138 : HValue* stub = Add<HConstant>(callable.code());
11883 : HValue* to = Pop();
11884 : HValue* from = Pop();
11885 : HValue* string = Pop();
11886 138 : HValue* values[] = {string, from, to};
11887 : HInstruction* result = New<HCallWithDescriptor>(
11888 138 : stub, 0, callable.descriptor(), ArrayVector(values));
11889 : result->set_type(HType::String());
11890 276 : return ast_context()->ReturnInstruction(result, call->id());
11891 : }
11892 :
11893 :
11894 : // Fast support for calls.
11895 35232 : void HOptimizedGraphBuilder::GenerateCall(CallRuntime* call) {
11896 : DCHECK_LE(2, call->arguments()->length());
11897 17616 : CHECK_ALIVE(VisitExpressions(call->arguments()));
11898 5872 : CallTrampolineDescriptor descriptor(isolate());
11899 5872 : PushArgumentsFromEnvironment(call->arguments()->length() - 1);
11900 5872 : HValue* trampoline = Add<HConstant>(isolate()->builtins()->Call());
11901 : HValue* target = Pop();
11902 11744 : HValue* values[] = {target, Add<HConstant>(call->arguments()->length() - 2)};
11903 : HInstruction* result =
11904 5872 : New<HCallWithDescriptor>(trampoline, call->arguments()->length() - 1,
11905 11744 : descriptor, ArrayVector(values));
11906 11744 : return ast_context()->ReturnInstruction(result, call->id());
11907 : }
11908 :
11909 :
11910 39540 : void HOptimizedGraphBuilder::GenerateFixedArrayGet(CallRuntime* call) {
11911 : DCHECK(call->arguments()->length() == 2);
11912 23724 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11913 23724 : CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
11914 : HValue* index = Pop();
11915 : HValue* object = Pop();
11916 : HInstruction* result = New<HLoadKeyed>(
11917 7908 : object, index, nullptr, nullptr, FAST_HOLEY_ELEMENTS, ALLOW_RETURN_HOLE);
11918 15816 : return ast_context()->ReturnInstruction(result, call->id());
11919 : }
11920 :
11921 :
11922 20153 : void HOptimizedGraphBuilder::GenerateFixedArraySet(CallRuntime* call) {
11923 : DCHECK(call->arguments()->length() == 3);
11924 14395 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11925 8637 : CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
11926 8637 : CHECK_ALIVE(VisitForValue(call->arguments()->at(2)));
11927 : HValue* value = Pop();
11928 : HValue* index = Pop();
11929 : HValue* object = Pop();
11930 2879 : NoObservableSideEffectsScope no_effects(this);
11931 2879 : Add<HStoreKeyed>(object, index, value, nullptr, FAST_HOLEY_ELEMENTS);
11932 5758 : return ast_context()->ReturnValue(graph()->GetConstantUndefined());
11933 : }
11934 :
11935 :
11936 419 : void HOptimizedGraphBuilder::GenerateTheHole(CallRuntime* call) {
11937 : DCHECK(call->arguments()->length() == 0);
11938 419 : return ast_context()->ReturnValue(graph()->GetConstantHole());
11939 : }
11940 :
11941 :
11942 45 : void HOptimizedGraphBuilder::GenerateCreateIterResultObject(CallRuntime* call) {
11943 : DCHECK_EQ(2, call->arguments()->length());
11944 27 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11945 27 : CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
11946 : HValue* done = Pop();
11947 : HValue* value = Pop();
11948 9 : HValue* result = BuildCreateIterResultObject(value, done);
11949 9 : return ast_context()->ReturnValue(result);
11950 : }
11951 :
11952 :
11953 4638 : void HOptimizedGraphBuilder::GenerateJSCollectionGetTable(CallRuntime* call) {
11954 : DCHECK(call->arguments()->length() == 1);
11955 3092 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11956 : HValue* receiver = Pop();
11957 : HInstruction* result = New<HLoadNamedField>(
11958 1546 : receiver, nullptr, HObjectAccess::ForJSCollectionTable());
11959 3092 : return ast_context()->ReturnInstruction(result, call->id());
11960 : }
11961 :
11962 :
11963 2469 : void HOptimizedGraphBuilder::GenerateStringGetRawHashField(CallRuntime* call) {
11964 : DCHECK(call->arguments()->length() == 1);
11965 1646 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11966 : HValue* object = Pop();
11967 : HInstruction* result = New<HLoadNamedField>(
11968 823 : object, nullptr, HObjectAccess::ForStringHashField());
11969 1646 : return ast_context()->ReturnInstruction(result, call->id());
11970 : }
11971 :
11972 :
11973 : template <typename CollectionType>
11974 3 : HValue* HOptimizedGraphBuilder::BuildAllocateOrderedHashTable() {
11975 : static const int kCapacity = CollectionType::kMinCapacity;
11976 : static const int kBucketCount = kCapacity / CollectionType::kLoadFactor;
11977 : static const int kFixedArrayLength = CollectionType::kHashTableStartIndex +
11978 : kBucketCount +
11979 : (kCapacity * CollectionType::kEntrySize);
11980 : static const int kSizeInBytes =
11981 : FixedArray::kHeaderSize + (kFixedArrayLength * kPointerSize);
11982 :
11983 : // Allocate the table and add the proper map.
11984 : HValue* table =
11985 : Add<HAllocate>(Add<HConstant>(kSizeInBytes), HType::HeapObject(),
11986 15 : NOT_TENURED, FIXED_ARRAY_TYPE, graph()->GetConstant0());
11987 3 : AddStoreMapConstant(table, isolate()->factory()->ordered_hash_table_map());
11988 :
11989 : // Initialize the FixedArray...
11990 3 : HValue* length = Add<HConstant>(kFixedArrayLength);
11991 3 : Add<HStoreNamedField>(table, HObjectAccess::ForFixedArrayLength(), length);
11992 :
11993 : // ...and the OrderedHashTable fields.
11994 3 : Add<HStoreNamedField>(
11995 : table,
11996 : HObjectAccess::ForOrderedHashTableNumberOfBuckets<CollectionType>(),
11997 : Add<HConstant>(kBucketCount));
11998 3 : Add<HStoreNamedField>(
11999 : table,
12000 : HObjectAccess::ForOrderedHashTableNumberOfElements<CollectionType>(),
12001 : graph()->GetConstant0());
12002 3 : Add<HStoreNamedField>(
12003 : table, HObjectAccess::ForOrderedHashTableNumberOfDeletedElements<
12004 : CollectionType>(),
12005 : graph()->GetConstant0());
12006 :
12007 : // Fill the buckets with kNotFound.
12008 3 : HValue* not_found = Add<HConstant>(CollectionType::kNotFound);
12009 9 : for (int i = 0; i < kBucketCount; ++i) {
12010 6 : Add<HStoreNamedField>(
12011 : table, HObjectAccess::ForOrderedHashTableBucket<CollectionType>(i),
12012 : not_found);
12013 : }
12014 :
12015 : // Fill the data table with undefined.
12016 3 : HValue* undefined = graph()->GetConstantUndefined();
12017 31 : for (int i = 0; i < (kCapacity * CollectionType::kEntrySize); ++i) {
12018 28 : Add<HStoreNamedField>(table,
12019 : HObjectAccess::ForOrderedHashTableDataTableIndex<
12020 : CollectionType, kBucketCount>(i),
12021 : undefined);
12022 : }
12023 :
12024 3 : return table;
12025 : }
12026 :
12027 :
12028 0 : void HOptimizedGraphBuilder::GenerateSetInitialize(CallRuntime* call) {
12029 : DCHECK(call->arguments()->length() == 1);
12030 0 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12031 : HValue* receiver = Pop();
12032 :
12033 0 : NoObservableSideEffectsScope no_effects(this);
12034 0 : HValue* table = BuildAllocateOrderedHashTable<OrderedHashSet>();
12035 0 : Add<HStoreNamedField>(receiver, HObjectAccess::ForJSCollectionTable(), table);
12036 0 : return ast_context()->ReturnValue(receiver);
12037 : }
12038 :
12039 :
12040 0 : void HOptimizedGraphBuilder::GenerateMapInitialize(CallRuntime* call) {
12041 : DCHECK(call->arguments()->length() == 1);
12042 0 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12043 : HValue* receiver = Pop();
12044 :
12045 0 : NoObservableSideEffectsScope no_effects(this);
12046 0 : HValue* table = BuildAllocateOrderedHashTable<OrderedHashMap>();
12047 0 : Add<HStoreNamedField>(receiver, HObjectAccess::ForJSCollectionTable(), table);
12048 0 : return ast_context()->ReturnValue(receiver);
12049 : }
12050 :
12051 :
12052 : template <typename CollectionType>
12053 3 : void HOptimizedGraphBuilder::BuildOrderedHashTableClear(HValue* receiver) {
12054 : HValue* old_table = Add<HLoadNamedField>(
12055 3 : receiver, nullptr, HObjectAccess::ForJSCollectionTable());
12056 3 : HValue* new_table = BuildAllocateOrderedHashTable<CollectionType>();
12057 3 : Add<HStoreNamedField>(
12058 : old_table, HObjectAccess::ForOrderedHashTableNextTable<CollectionType>(),
12059 : new_table);
12060 3 : Add<HStoreNamedField>(
12061 : old_table, HObjectAccess::ForOrderedHashTableNumberOfDeletedElements<
12062 : CollectionType>(),
12063 : Add<HConstant>(CollectionType::kClearedTableSentinel));
12064 3 : Add<HStoreNamedField>(receiver, HObjectAccess::ForJSCollectionTable(),
12065 3 : new_table);
12066 3 : }
12067 :
12068 :
12069 6 : void HOptimizedGraphBuilder::GenerateSetClear(CallRuntime* call) {
12070 : DCHECK(call->arguments()->length() == 1);
12071 6 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12072 : HValue* receiver = Pop();
12073 :
12074 2 : NoObservableSideEffectsScope no_effects(this);
12075 2 : BuildOrderedHashTableClear<OrderedHashSet>(receiver);
12076 4 : return ast_context()->ReturnValue(graph()->GetConstantUndefined());
12077 : }
12078 :
12079 :
12080 3 : void HOptimizedGraphBuilder::GenerateMapClear(CallRuntime* call) {
12081 : DCHECK(call->arguments()->length() == 1);
12082 3 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12083 : HValue* receiver = Pop();
12084 :
12085 1 : NoObservableSideEffectsScope no_effects(this);
12086 1 : BuildOrderedHashTableClear<OrderedHashMap>(receiver);
12087 2 : return ast_context()->ReturnValue(graph()->GetConstantUndefined());
12088 : }
12089 :
12090 0 : void HOptimizedGraphBuilder::GenerateDebugBreakInOptimizedCode(
12091 0 : CallRuntime* call) {
12092 0 : Add<HDebugBreak>();
12093 0 : return ast_context()->ReturnValue(graph()->GetConstant0());
12094 : }
12095 :
12096 :
12097 0 : void HOptimizedGraphBuilder::GenerateDebugIsActive(CallRuntime* call) {
12098 : DCHECK(call->arguments()->length() == 0);
12099 : HValue* ref =
12100 0 : Add<HConstant>(ExternalReference::debug_is_active_address(isolate()));
12101 : HValue* value =
12102 0 : Add<HLoadNamedField>(ref, nullptr, HObjectAccess::ForExternalUInteger8());
12103 0 : return ast_context()->ReturnValue(value);
12104 : }
12105 :
12106 : #undef CHECK_BAILOUT
12107 : #undef CHECK_ALIVE
12108 :
12109 :
12110 477600 : HEnvironment::HEnvironment(HEnvironment* outer,
12111 : Scope* scope,
12112 : Handle<JSFunction> closure,
12113 : Zone* zone)
12114 : : closure_(closure),
12115 : values_(0, zone),
12116 : frame_type_(JS_FUNCTION),
12117 : parameter_count_(0),
12118 : specials_count_(1),
12119 : local_count_(0),
12120 : outer_(outer),
12121 : entry_(NULL),
12122 : pop_count_(0),
12123 : push_count_(0),
12124 : ast_id_(BailoutId::None()),
12125 955199 : zone_(zone) {
12126 477599 : DeclarationScope* declaration_scope = scope->GetDeclarationScope();
12127 : Initialize(declaration_scope->num_parameters() + 1,
12128 955198 : declaration_scope->num_stack_slots(), 0);
12129 477598 : }
12130 :
12131 :
12132 23483 : HEnvironment::HEnvironment(Zone* zone, int parameter_count)
12133 : : values_(0, zone),
12134 : frame_type_(STUB),
12135 : parameter_count_(parameter_count),
12136 : specials_count_(1),
12137 : local_count_(0),
12138 : outer_(NULL),
12139 : entry_(NULL),
12140 : pop_count_(0),
12141 : push_count_(0),
12142 : ast_id_(BailoutId::None()),
12143 46966 : zone_(zone) {
12144 23483 : Initialize(parameter_count, 0, 0);
12145 23483 : }
12146 :
12147 :
12148 13882160 : HEnvironment::HEnvironment(const HEnvironment* other, Zone* zone)
12149 : : values_(0, zone),
12150 : frame_type_(JS_FUNCTION),
12151 : parameter_count_(0),
12152 : specials_count_(0),
12153 : local_count_(0),
12154 : outer_(NULL),
12155 : entry_(NULL),
12156 : pop_count_(0),
12157 : push_count_(0),
12158 : ast_id_(other->ast_id()),
12159 27764159 : zone_(zone) {
12160 13881999 : Initialize(other);
12161 13882355 : }
12162 :
12163 :
12164 0 : HEnvironment::HEnvironment(HEnvironment* outer,
12165 : Handle<JSFunction> closure,
12166 : FrameType frame_type,
12167 : int arguments,
12168 : Zone* zone)
12169 : : closure_(closure),
12170 : values_(arguments, zone),
12171 : frame_type_(frame_type),
12172 : parameter_count_(arguments),
12173 : specials_count_(0),
12174 : local_count_(0),
12175 : outer_(outer),
12176 : entry_(NULL),
12177 : pop_count_(0),
12178 : push_count_(0),
12179 : ast_id_(BailoutId::None()),
12180 152140 : zone_(zone) {
12181 0 : }
12182 :
12183 :
12184 501082 : void HEnvironment::Initialize(int parameter_count,
12185 : int local_count,
12186 2765208 : int stack_height) {
12187 501082 : parameter_count_ = parameter_count;
12188 501082 : local_count_ = local_count;
12189 :
12190 : // Avoid reallocating the temporaries' backing store on the first Push.
12191 501082 : int total = parameter_count + specials_count_ + local_count + stack_height;
12192 501082 : values_.Initialize(total + 4, zone());
12193 2765207 : for (int i = 0; i < total; ++i) values_.Add(NULL, zone());
12194 501081 : }
12195 :
12196 :
12197 41646534 : void HEnvironment::Initialize(const HEnvironment* other) {
12198 13882200 : closure_ = other->closure();
12199 : values_.AddAll(other->values_, zone());
12200 13882134 : assigned_variables_.Union(other->assigned_variables_, zone());
12201 13882276 : frame_type_ = other->frame_type_;
12202 13882276 : parameter_count_ = other->parameter_count_;
12203 13882276 : local_count_ = other->local_count_;
12204 13882276 : if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy.
12205 13882287 : entry_ = other->entry_;
12206 13882287 : pop_count_ = other->pop_count_;
12207 13882287 : push_count_ = other->push_count_;
12208 13882287 : specials_count_ = other->specials_count_;
12209 13882287 : ast_id_ = other->ast_id_;
12210 13882287 : }
12211 :
12212 :
12213 849230 : void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) {
12214 : DCHECK(!block->IsLoopHeader());
12215 : DCHECK(values_.length() == other->values_.length());
12216 :
12217 13022968 : int length = values_.length();
12218 6705071 : for (int i = 0; i < length; ++i) {
12219 6807744 : HValue* value = values_[i];
12220 12663585 : if (value != NULL && value->IsPhi() && value->block() == block) {
12221 : // There is already a phi for the i'th value.
12222 : HPhi* phi = HPhi::cast(value);
12223 : // Assert index is correct and that we haven't missed an incoming edge.
12224 : DCHECK(phi->merged_index() == i || !phi->HasMergedIndex());
12225 : DCHECK(phi->OperandCount() == block->predecessors()->length());
12226 6108973 : phi->AddInput(other->values_[i]);
12227 11682210 : } else if (values_[i] != other->values_[i]) {
12228 : // There is a fresh value on the incoming edge, a phi is needed.
12229 : DCHECK(values_[i] != NULL && other->values_[i] != NULL);
12230 238396 : HPhi* phi = block->AddNewPhi(i);
12231 238396 : HValue* old_value = values_[i];
12232 477534 : for (int j = 0; j < block->predecessors()->length(); j++) {
12233 239138 : phi->AddInput(old_value);
12234 : }
12235 238396 : phi->AddInput(other->values_[i]);
12236 238396 : this->values_[i] = phi;
12237 : }
12238 : }
12239 849230 : }
12240 :
12241 :
12242 3422921 : void HEnvironment::Bind(int index, HValue* value) {
12243 : DCHECK(value != NULL);
12244 3422921 : assigned_variables_.Add(index, zone());
12245 6845862 : values_[index] = value;
12246 1459461 : }
12247 :
12248 :
12249 0 : bool HEnvironment::HasExpressionAt(int index) const {
12250 0 : return index >= parameter_count_ + specials_count_ + local_count_;
12251 : }
12252 :
12253 :
12254 0 : bool HEnvironment::ExpressionStackIsEmpty() const {
12255 : DCHECK(length() >= first_expression_index());
12256 0 : return length() == first_expression_index();
12257 : }
12258 :
12259 :
12260 0 : void HEnvironment::SetExpressionStackAt(int index_from_top, HValue* value) {
12261 0 : int count = index_from_top + 1;
12262 843202 : int index = values_.length() - count;
12263 : DCHECK(HasExpressionAt(index));
12264 : // The push count must include at least the element in question or else
12265 : // the new value will not be included in this environment's history.
12266 421601 : if (push_count_ < count) {
12267 : // This is the same effect as popping then re-pushing 'count' elements.
12268 168186 : pop_count_ += (count - push_count_);
12269 168186 : push_count_ = count;
12270 : }
12271 421601 : values_[index] = value;
12272 0 : }
12273 :
12274 :
12275 5262 : HValue* HEnvironment::RemoveExpressionStackAt(int index_from_top) {
12276 5262 : int count = index_from_top + 1;
12277 5262 : int index = values_.length() - count;
12278 : DCHECK(HasExpressionAt(index));
12279 : // Simulate popping 'count' elements and then
12280 : // pushing 'count - 1' elements back.
12281 10524 : pop_count_ += Max(count - push_count_, 0);
12282 10524 : push_count_ = Max(push_count_ - count, 0) + (count - 1);
12283 5262 : return values_.Remove(index);
12284 : }
12285 :
12286 :
12287 4726149 : void HEnvironment::Drop(int count) {
12288 10177432 : for (int i = 0; i < count; ++i) {
12289 5451284 : Pop();
12290 : }
12291 4726148 : }
12292 :
12293 :
12294 0 : void HEnvironment::Print() const {
12295 0 : OFStream os(stdout);
12296 0 : os << *this << "\n";
12297 0 : }
12298 :
12299 :
12300 13882165 : HEnvironment* HEnvironment::Copy() const {
12301 13882149 : return new(zone()) HEnvironment(this, zone());
12302 : }
12303 :
12304 :
12305 526865 : HEnvironment* HEnvironment::CopyWithoutHistory() const {
12306 526865 : HEnvironment* result = Copy();
12307 : result->ClearHistory();
12308 526866 : return result;
12309 : }
12310 :
12311 :
12312 61068 : HEnvironment* HEnvironment::CopyAsLoopHeader(HBasicBlock* loop_header) const {
12313 61068 : HEnvironment* new_env = Copy();
12314 971468 : for (int i = 0; i < values_.length(); ++i) {
12315 424666 : HPhi* phi = loop_header->AddNewPhi(i);
12316 1335066 : phi->AddInput(values_[i]);
12317 849332 : new_env->values_[i] = phi;
12318 : }
12319 : new_env->ClearHistory();
12320 61068 : return new_env;
12321 : }
12322 :
12323 :
12324 76070 : HEnvironment* HEnvironment::CreateStubEnvironment(HEnvironment* outer,
12325 : Handle<JSFunction> target,
12326 : FrameType frame_type,
12327 76070 : int arguments) const {
12328 : HEnvironment* new_env =
12329 : new(zone()) HEnvironment(outer, target, frame_type,
12330 152140 : arguments + 1, zone());
12331 280424 : for (int i = 0; i <= arguments; ++i) { // Include receiver.
12332 204354 : new_env->Push(ExpressionStackAt(arguments - i));
12333 : }
12334 : new_env->ClearHistory();
12335 76070 : return new_env;
12336 : }
12337 :
12338 0 : void HEnvironment::MarkAsTailCaller() {
12339 : DCHECK_EQ(JS_FUNCTION, frame_type());
12340 336 : frame_type_ = TAIL_CALLER_FUNCTION;
12341 0 : }
12342 :
12343 181 : void HEnvironment::ClearTailCallerMark() {
12344 : DCHECK_EQ(TAIL_CALLER_FUNCTION, frame_type());
12345 372 : frame_type_ = JS_FUNCTION;
12346 181 : }
12347 :
12348 214167 : HEnvironment* HEnvironment::CopyForInlining(
12349 428334 : Handle<JSFunction> target, int arguments, FunctionLiteral* function,
12350 : HConstant* undefined, InliningKind inlining_kind,
12351 214167 : TailCallMode syntactic_tail_call_mode) const {
12352 : DCHECK_EQ(JS_FUNCTION, frame_type());
12353 :
12354 : // Outer environment is a copy of this one without the arguments.
12355 : int arity = function->scope()->num_parameters();
12356 :
12357 214167 : HEnvironment* outer = Copy();
12358 : outer->Drop(arguments + 1); // Including receiver.
12359 : outer->ClearHistory();
12360 :
12361 214167 : if (syntactic_tail_call_mode == TailCallMode::kAllow) {
12362 : DCHECK_EQ(NORMAL_RETURN, inlining_kind);
12363 : outer->MarkAsTailCaller();
12364 : }
12365 :
12366 214167 : if (inlining_kind == CONSTRUCT_CALL_RETURN) {
12367 : // Create artificial constructor stub environment. The receiver should
12368 : // actually be the constructor function, but we pass the newly allocated
12369 : // object instead, DoComputeConstructStubFrame() relies on that.
12370 2098 : outer = CreateStubEnvironment(outer, target, JS_CONSTRUCT, arguments);
12371 212069 : } else if (inlining_kind == GETTER_CALL_RETURN) {
12372 : // We need an additional StackFrame::INTERNAL frame for restoring the
12373 : // correct context.
12374 3617 : outer = CreateStubEnvironment(outer, target, JS_GETTER, arguments);
12375 208452 : } else if (inlining_kind == SETTER_CALL_RETURN) {
12376 : // We need an additional StackFrame::INTERNAL frame for temporarily saving
12377 : // the argument of the setter, see StoreStubCompiler::CompileStoreViaSetter.
12378 394 : outer = CreateStubEnvironment(outer, target, JS_SETTER, arguments);
12379 : }
12380 :
12381 214167 : if (arity != arguments) {
12382 : // Create artificial arguments adaptation environment.
12383 69961 : outer = CreateStubEnvironment(outer, target, ARGUMENTS_ADAPTOR, arguments);
12384 : }
12385 :
12386 : HEnvironment* inner =
12387 428334 : new(zone()) HEnvironment(outer, function->scope(), target, zone());
12388 : // Get the argument values from the original environment.
12389 879922 : for (int i = 0; i <= arity; ++i) { // Include receiver.
12390 : HValue* push = (i <= arguments) ?
12391 665757 : ExpressionStackAt(arguments - i) : undefined;
12392 : inner->SetValueAt(i, push);
12393 : }
12394 214165 : inner->SetValueAt(arity + 1, context());
12395 975554 : for (int i = arity + 2; i < inner->length(); ++i) {
12396 : inner->SetValueAt(i, undefined);
12397 : }
12398 :
12399 : inner->set_ast_id(BailoutId::FunctionEntry());
12400 214165 : return inner;
12401 : }
12402 :
12403 :
12404 0 : std::ostream& operator<<(std::ostream& os, const HEnvironment& env) {
12405 0 : for (int i = 0; i < env.length(); i++) {
12406 0 : if (i == 0) os << "parameters\n";
12407 0 : if (i == env.parameter_count()) os << "specials\n";
12408 0 : if (i == env.parameter_count() + env.specials_count()) os << "locals\n";
12409 0 : if (i == env.parameter_count() + env.specials_count() + env.local_count()) {
12410 0 : os << "expressions\n";
12411 : }
12412 0 : HValue* val = env.values()->at(i);
12413 0 : os << i << ": ";
12414 0 : if (val != NULL) {
12415 : os << val;
12416 : } else {
12417 0 : os << "NULL";
12418 : }
12419 0 : os << "\n";
12420 : }
12421 0 : return os << "\n";
12422 : }
12423 :
12424 :
12425 0 : void HTracer::TraceCompilation(CompilationInfo* info) {
12426 0 : Tag tag(this, "compilation");
12427 : std::string name;
12428 0 : if (info->parse_info()) {
12429 0 : Object* source_name = info->script()->name();
12430 0 : if (source_name->IsString()) {
12431 : String* str = String::cast(source_name);
12432 0 : if (str->length() > 0) {
12433 0 : name.append(str->ToCString().get());
12434 0 : name.append(":");
12435 : }
12436 : }
12437 : }
12438 0 : std::unique_ptr<char[]> method_name = info->GetDebugName();
12439 0 : name.append(method_name.get());
12440 0 : if (info->IsOptimizing()) {
12441 0 : PrintStringProperty("name", name.c_str());
12442 : PrintIndent();
12443 : trace_.Add("method \"%s:%d\"\n", method_name.get(),
12444 0 : info->optimization_id());
12445 : } else {
12446 0 : PrintStringProperty("name", name.c_str());
12447 0 : PrintStringProperty("method", "stub");
12448 : }
12449 : PrintLongProperty("date",
12450 0 : static_cast<int64_t>(base::OS::TimeCurrentMillis()));
12451 0 : }
12452 :
12453 :
12454 0 : void HTracer::TraceLithium(const char* name, LChunk* chunk) {
12455 : DCHECK(!chunk->isolate()->concurrent_recompilation_enabled());
12456 : AllowHandleDereference allow_deref;
12457 : AllowDeferredHandleDereference allow_deferred_deref;
12458 0 : Trace(name, chunk->graph(), chunk);
12459 0 : }
12460 :
12461 :
12462 0 : void HTracer::TraceHydrogen(const char* name, HGraph* graph) {
12463 : DCHECK(!graph->isolate()->concurrent_recompilation_enabled());
12464 : AllowHandleDereference allow_deref;
12465 : AllowDeferredHandleDereference allow_deferred_deref;
12466 0 : Trace(name, graph, NULL);
12467 0 : }
12468 :
12469 :
12470 0 : void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) {
12471 0 : Tag tag(this, "cfg");
12472 0 : PrintStringProperty("name", name);
12473 : const ZoneList<HBasicBlock*>* blocks = graph->blocks();
12474 0 : for (int i = 0; i < blocks->length(); i++) {
12475 0 : HBasicBlock* current = blocks->at(i);
12476 0 : Tag block_tag(this, "block");
12477 0 : PrintBlockProperty("name", current->block_id());
12478 0 : PrintIntProperty("from_bci", -1);
12479 0 : PrintIntProperty("to_bci", -1);
12480 :
12481 0 : if (!current->predecessors()->is_empty()) {
12482 : PrintIndent();
12483 0 : trace_.Add("predecessors");
12484 0 : for (int j = 0; j < current->predecessors()->length(); ++j) {
12485 0 : trace_.Add(" \"B%d\"", current->predecessors()->at(j)->block_id());
12486 : }
12487 0 : trace_.Add("\n");
12488 : } else {
12489 0 : PrintEmptyProperty("predecessors");
12490 : }
12491 :
12492 0 : if (current->end()->SuccessorCount() == 0) {
12493 0 : PrintEmptyProperty("successors");
12494 : } else {
12495 : PrintIndent();
12496 0 : trace_.Add("successors");
12497 0 : for (HSuccessorIterator it(current->end()); !it.Done(); it.Advance()) {
12498 0 : trace_.Add(" \"B%d\"", it.Current()->block_id());
12499 : }
12500 0 : trace_.Add("\n");
12501 : }
12502 :
12503 0 : PrintEmptyProperty("xhandlers");
12504 :
12505 : {
12506 : PrintIndent();
12507 0 : trace_.Add("flags");
12508 0 : if (current->IsLoopSuccessorDominator()) {
12509 0 : trace_.Add(" \"dom-loop-succ\"");
12510 : }
12511 0 : if (current->IsUnreachable()) {
12512 0 : trace_.Add(" \"dead\"");
12513 : }
12514 0 : if (current->is_osr_entry()) {
12515 0 : trace_.Add(" \"osr\"");
12516 : }
12517 0 : trace_.Add("\n");
12518 : }
12519 :
12520 0 : if (current->dominator() != NULL) {
12521 0 : PrintBlockProperty("dominator", current->dominator()->block_id());
12522 : }
12523 :
12524 0 : PrintIntProperty("loop_depth", current->LoopNestingDepth());
12525 :
12526 0 : if (chunk != NULL) {
12527 : int first_index = current->first_instruction_index();
12528 : int last_index = current->last_instruction_index();
12529 : PrintIntProperty(
12530 : "first_lir_id",
12531 0 : LifetimePosition::FromInstructionIndex(first_index).Value());
12532 : PrintIntProperty(
12533 : "last_lir_id",
12534 0 : LifetimePosition::FromInstructionIndex(last_index).Value());
12535 : }
12536 :
12537 : {
12538 0 : Tag states_tag(this, "states");
12539 0 : Tag locals_tag(this, "locals");
12540 0 : int total = current->phis()->length();
12541 0 : PrintIntProperty("size", current->phis()->length());
12542 0 : PrintStringProperty("method", "None");
12543 0 : for (int j = 0; j < total; ++j) {
12544 0 : HPhi* phi = current->phis()->at(j);
12545 : PrintIndent();
12546 0 : std::ostringstream os;
12547 0 : os << phi->merged_index() << " " << NameOf(phi) << " " << *phi << "\n";
12548 0 : trace_.Add(os.str().c_str());
12549 0 : }
12550 : }
12551 :
12552 : {
12553 0 : Tag HIR_tag(this, "HIR");
12554 0 : for (HInstructionIterator it(current); !it.Done(); it.Advance()) {
12555 : HInstruction* instruction = it.Current();
12556 0 : int uses = instruction->UseCount();
12557 : PrintIndent();
12558 0 : std::ostringstream os;
12559 0 : os << "0 " << uses << " " << NameOf(instruction) << " " << *instruction;
12560 0 : if (instruction->has_position()) {
12561 0 : const SourcePosition pos = instruction->position();
12562 0 : os << " pos:";
12563 0 : if (pos.isInlined()) os << "inlining(" << pos.InliningId() << "),";
12564 0 : os << pos.ScriptOffset();
12565 : }
12566 0 : os << " <|@\n";
12567 0 : trace_.Add(os.str().c_str());
12568 0 : }
12569 : }
12570 :
12571 :
12572 0 : if (chunk != NULL) {
12573 0 : Tag LIR_tag(this, "LIR");
12574 : int first_index = current->first_instruction_index();
12575 : int last_index = current->last_instruction_index();
12576 0 : if (first_index != -1 && last_index != -1) {
12577 : const ZoneList<LInstruction*>* instructions = chunk->instructions();
12578 0 : for (int i = first_index; i <= last_index; ++i) {
12579 0 : LInstruction* linstr = instructions->at(i);
12580 0 : if (linstr != NULL) {
12581 : PrintIndent();
12582 : trace_.Add("%d ",
12583 0 : LifetimePosition::FromInstructionIndex(i).Value());
12584 0 : linstr->PrintTo(&trace_);
12585 0 : std::ostringstream os;
12586 0 : os << " [hir:" << NameOf(linstr->hydrogen_value()) << "] <|@\n";
12587 0 : trace_.Add(os.str().c_str());
12588 : }
12589 : }
12590 0 : }
12591 : }
12592 0 : }
12593 0 : }
12594 :
12595 :
12596 0 : void HTracer::TraceLiveRanges(const char* name, LAllocator* allocator) {
12597 0 : Tag tag(this, "intervals");
12598 0 : PrintStringProperty("name", name);
12599 :
12600 0 : const Vector<LiveRange*>* fixed_d = allocator->fixed_double_live_ranges();
12601 0 : for (int i = 0; i < fixed_d->length(); ++i) {
12602 0 : TraceLiveRange(fixed_d->at(i), "fixed", allocator->zone());
12603 : }
12604 :
12605 0 : const Vector<LiveRange*>* fixed = allocator->fixed_live_ranges();
12606 0 : for (int i = 0; i < fixed->length(); ++i) {
12607 0 : TraceLiveRange(fixed->at(i), "fixed", allocator->zone());
12608 : }
12609 :
12610 : const ZoneList<LiveRange*>* live_ranges = allocator->live_ranges();
12611 0 : for (int i = 0; i < live_ranges->length(); ++i) {
12612 0 : TraceLiveRange(live_ranges->at(i), "object", allocator->zone());
12613 0 : }
12614 0 : }
12615 :
12616 :
12617 0 : void HTracer::TraceLiveRange(LiveRange* range, const char* type,
12618 : Zone* zone) {
12619 0 : if (range != NULL && !range->IsEmpty()) {
12620 : PrintIndent();
12621 0 : trace_.Add("%d %s", range->id(), type);
12622 0 : if (range->HasRegisterAssigned()) {
12623 0 : LOperand* op = range->CreateAssignedOperand(zone);
12624 : int assigned_reg = op->index();
12625 0 : if (op->IsDoubleRegister()) {
12626 : trace_.Add(" \"%s\"",
12627 0 : GetRegConfig()->GetDoubleRegisterName(assigned_reg));
12628 : } else {
12629 : DCHECK(op->IsRegister());
12630 : trace_.Add(" \"%s\"",
12631 0 : GetRegConfig()->GetGeneralRegisterName(assigned_reg));
12632 : }
12633 0 : } else if (range->IsSpilled()) {
12634 0 : LOperand* op = range->TopLevel()->GetSpillOperand();
12635 0 : if (op->IsDoubleStackSlot()) {
12636 0 : trace_.Add(" \"double_stack:%d\"", op->index());
12637 : } else {
12638 : DCHECK(op->IsStackSlot());
12639 0 : trace_.Add(" \"stack:%d\"", op->index());
12640 : }
12641 : }
12642 : int parent_index = -1;
12643 0 : if (range->IsChild()) {
12644 0 : parent_index = range->parent()->id();
12645 : } else {
12646 : parent_index = range->id();
12647 : }
12648 0 : LOperand* op = range->FirstHint();
12649 : int hint_index = -1;
12650 0 : if (op != NULL && op->IsUnallocated()) {
12651 : hint_index = LUnallocated::cast(op)->virtual_register();
12652 : }
12653 0 : trace_.Add(" %d %d", parent_index, hint_index);
12654 0 : UseInterval* cur_interval = range->first_interval();
12655 0 : while (cur_interval != NULL && range->Covers(cur_interval->start())) {
12656 : trace_.Add(" [%d, %d[",
12657 : cur_interval->start().Value(),
12658 0 : cur_interval->end().Value());
12659 : cur_interval = cur_interval->next();
12660 : }
12661 :
12662 0 : UsePosition* current_pos = range->first_pos();
12663 0 : while (current_pos != NULL) {
12664 0 : if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) {
12665 0 : trace_.Add(" %d M", current_pos->pos().Value());
12666 : }
12667 : current_pos = current_pos->next();
12668 : }
12669 :
12670 0 : trace_.Add(" \"\"\n");
12671 : }
12672 0 : }
12673 :
12674 :
12675 0 : void HTracer::FlushToFile() {
12676 0 : AppendChars(filename_.start(), trace_.ToCString().get(), trace_.length(),
12677 0 : false);
12678 : trace_.Reset();
12679 0 : }
12680 :
12681 :
12682 0 : void HStatistics::Initialize(CompilationInfo* info) {
12683 0 : if (!info->has_shared_info()) return;
12684 0 : source_size_ += info->shared_info()->SourceSize();
12685 : }
12686 :
12687 :
12688 0 : void HStatistics::Print() {
12689 : PrintF(
12690 : "\n"
12691 : "----------------------------------------"
12692 : "----------------------------------------\n"
12693 : "--- Hydrogen timing results:\n"
12694 : "----------------------------------------"
12695 0 : "----------------------------------------\n");
12696 : base::TimeDelta sum;
12697 0 : for (int i = 0; i < times_.length(); ++i) {
12698 0 : sum += times_[i];
12699 : }
12700 :
12701 0 : for (int i = 0; i < names_.length(); ++i) {
12702 0 : PrintF("%33s", names_[i]);
12703 0 : double ms = times_[i].InMillisecondsF();
12704 : double percent = times_[i].PercentOf(sum);
12705 0 : PrintF(" %8.3f ms / %4.1f %% ", ms, percent);
12706 :
12707 0 : size_t size = sizes_[i];
12708 0 : double size_percent = static_cast<double>(size) * 100 / total_size_;
12709 0 : PrintF(" %9zu bytes / %4.1f %%\n", size, size_percent);
12710 : }
12711 :
12712 : PrintF(
12713 : "----------------------------------------"
12714 0 : "----------------------------------------\n");
12715 0 : base::TimeDelta total = create_graph_ + optimize_graph_ + generate_code_;
12716 : PrintF("%33s %8.3f ms / %4.1f %% \n", "Create graph",
12717 0 : create_graph_.InMillisecondsF(), create_graph_.PercentOf(total));
12718 : PrintF("%33s %8.3f ms / %4.1f %% \n", "Optimize graph",
12719 0 : optimize_graph_.InMillisecondsF(), optimize_graph_.PercentOf(total));
12720 : PrintF("%33s %8.3f ms / %4.1f %% \n", "Generate and install code",
12721 0 : generate_code_.InMillisecondsF(), generate_code_.PercentOf(total));
12722 : PrintF(
12723 : "----------------------------------------"
12724 0 : "----------------------------------------\n");
12725 : PrintF("%33s %8.3f ms %9zu bytes\n", "Total",
12726 0 : total.InMillisecondsF(), total_size_);
12727 : PrintF("%33s (%.1f times slower than full code gen)\n", "",
12728 0 : total.TimesOf(full_code_gen_));
12729 :
12730 0 : double source_size_in_kb = static_cast<double>(source_size_) / 1024;
12731 : double normalized_time = source_size_in_kb > 0
12732 0 : ? total.InMillisecondsF() / source_size_in_kb
12733 0 : : 0;
12734 : double normalized_size_in_kb =
12735 : source_size_in_kb > 0
12736 0 : ? static_cast<double>(total_size_) / 1024 / source_size_in_kb
12737 0 : : 0;
12738 : PrintF("%33s %8.3f ms %7.3f kB allocated\n",
12739 0 : "Average per kB source", normalized_time, normalized_size_in_kb);
12740 0 : }
12741 :
12742 :
12743 0 : void HStatistics::SaveTiming(const char* name, base::TimeDelta time,
12744 : size_t size) {
12745 0 : total_size_ += size;
12746 0 : for (int i = 0; i < names_.length(); ++i) {
12747 0 : if (strcmp(names_[i], name) == 0) {
12748 0 : times_[i] += time;
12749 0 : sizes_[i] += size;
12750 0 : return;
12751 : }
12752 : }
12753 0 : names_.Add(name);
12754 0 : times_.Add(time);
12755 0 : sizes_.Add(size);
12756 : }
12757 :
12758 :
12759 11887319 : HPhase::~HPhase() {
12760 5943661 : if (ShouldProduceTraceOutput()) {
12761 0 : isolate()->GetHTracer()->TraceHydrogen(name(), graph_);
12762 : }
12763 :
12764 : #ifdef DEBUG
12765 : graph_->Verify(false); // No full verify.
12766 : #endif
12767 5943656 : }
12768 :
12769 : } // namespace internal
12770 : } // namespace v8
|