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 266057 : HCompilationJob::Status HCompilationJob::PrepareJobImpl() {
120 3654894 : if (!isolate()->use_crankshaft() ||
121 796209 : 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 530036 : bool should_recompile = !info()->shared_info()->has_deoptimization_support();
132 265018 : if (should_recompile || FLAG_hydrogen_stats) {
133 : base::ElapsedTimer timer;
134 217560 : if (FLAG_hydrogen_stats) {
135 : timer.Start();
136 : }
137 217560 : if (!Compiler::EnsureDeoptimizationSupport(info())) {
138 : return FAILED;
139 : }
140 217152 : 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 793830 : if (!info()->shared_info()->PassesFilter(FLAG_hydrogen_filter)) {
148 97 : return AbortOptimization(kHydrogenFilter);
149 : }
150 :
151 266952 : Scope* scope = info()->scope();
152 264513 : if (LUnallocated::TooManyParameters(scope->num_parameters())) {
153 : // Crankshaft would require too many Lithium operands.
154 3 : return AbortOptimization(kTooManyParameters);
155 : }
156 :
157 266949 : if (info()->is_osr() &&
158 : LUnallocated::TooManyParametersOrStackSlots(scope->num_parameters(),
159 2439 : scope->num_stack_slots())) {
160 : // Crankshaft would require too many Lithium operands.
161 0 : return AbortOptimization(kTooManyParametersLocals);
162 : }
163 :
164 529020 : if (IsGeneratorFunction(info()->shared_info()->kind())) {
165 : // Crankshaft does not support generators.
166 0 : return AbortOptimization(kGenerator);
167 : }
168 :
169 264510 : 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 529020 : if (info()->shared_info()->optimization_disabled()) {
176 : return AbortOptimization(
177 1194 : info()->shared_info()->disable_optimization_reason());
178 : }
179 :
180 : HOptimizedGraphBuilder* graph_builder =
181 263909 : (FLAG_hydrogen_track_positions || isolate()->is_profiling() ||
182 : FLAG_trace_ic)
183 238 : ? new (info()->zone()) HOptimizedGraphBuilderWithPositions(info())
184 791620 : : 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 1055652 : .Run();
191 :
192 263913 : graph_ = graph_builder->CreateGraph();
193 :
194 263913 : if (isolate()->has_pending_exception()) {
195 : return FAILED;
196 : }
197 :
198 263911 : if (graph_ == NULL) return FAILED;
199 :
200 260261 : 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 260243 : HCompilationJob::Status HCompilationJob::ExecuteJobImpl() {
209 : DCHECK(graph_ != NULL);
210 260243 : BailoutReason bailout_reason = kNoReason;
211 :
212 260243 : if (graph_->Optimize(&bailout_reason)) {
213 260197 : chunk_ = LChunk::NewChunk(graph_);
214 260197 : if (chunk_ != NULL) return SUCCEEDED;
215 48 : } else if (bailout_reason != kNoReason) {
216 48 : info()->AbortOptimization(bailout_reason);
217 : }
218 :
219 : return FAILED;
220 : }
221 :
222 255552 : 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 255552 : Handle<Code> optimized_code = chunk_->Codegen();
232 255552 : if (optimized_code.is_null()) {
233 255552 : if (info()->bailout_reason() == kNoReason) {
234 37 : return AbortOptimization(kCodeGenerationFailed);
235 : }
236 : return FAILED;
237 : }
238 255515 : RegisterWeakObjectsInOptimizedCode(optimized_code);
239 : info()->SetCode(optimized_code);
240 : }
241 : // Add to the weak list of optimized code objects.
242 511030 : info()->context()->native_context()->AddOptimizedCode(*info()->code());
243 255515 : return SUCCEEDED;
244 : }
245 :
246 23113452 : 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 23113452 : is_ordered_(false) { }
269 :
270 :
271 179632 : Isolate* HBasicBlock::isolate() const {
272 179632 : return graph_->isolate();
273 : }
274 :
275 :
276 1983304 : void HBasicBlock::MarkUnreachable() {
277 1986577 : is_reachable_ = false;
278 1983304 : }
279 :
280 :
281 61252 : void HBasicBlock::AttachLoopInformation() {
282 : DCHECK(!IsLoopHeader());
283 61252 : loop_information_ = new(zone()) HLoopInformation(this, zone());
284 61252 : }
285 :
286 :
287 0 : void HBasicBlock::DetachLoopInformation() {
288 : DCHECK(IsLoopHeader());
289 758 : loop_information_ = NULL;
290 0 : }
291 :
292 :
293 696556 : void HBasicBlock::AddPhi(HPhi* phi) {
294 : DCHECK(!IsStartBlock());
295 : phis_.Add(phi, zone());
296 696556 : phi->SetBlock(this);
297 696556 : }
298 :
299 :
300 379044 : void HBasicBlock::RemovePhi(HPhi* phi) {
301 : DCHECK(phi->block() == this);
302 : DCHECK(phis_.Contains(phi));
303 379044 : phi->Kill();
304 379044 : phis_.RemoveElement(phi);
305 379044 : phi->SetBlock(NULL);
306 379044 : }
307 :
308 :
309 29530172 : void HBasicBlock::AddInstruction(HInstruction* instr, SourcePosition position) {
310 : DCHECK(!IsStartBlock() || !IsFinished());
311 : DCHECK(!instr->IsLinked());
312 : DCHECK(!IsFinished());
313 :
314 24909318 : if (position.IsKnown()) {
315 : instr->set_position(position);
316 : }
317 24909318 : if (first_ == NULL) {
318 : DCHECK(last_environment() != NULL);
319 : DCHECK(!last_environment()->ast_id().IsNone());
320 4620854 : HBlockEntry* entry = new(zone()) HBlockEntry();
321 : entry->InitializeAsFirst(this);
322 4620854 : if (position.IsKnown()) {
323 : entry->set_position(position);
324 : } else {
325 : DCHECK(!FLAG_hydrogen_track_positions ||
326 : !graph()->info()->IsOptimizing() || instr->IsAbnormalExit());
327 : }
328 4620854 : first_ = last_ = entry;
329 : }
330 24909318 : instr->InsertAfter(last_);
331 24909333 : }
332 :
333 :
334 680604 : HPhi* HBasicBlock::AddNewPhi(int merged_index) {
335 680604 : if (graph()->IsInsideNoSideEffectsScope()) {
336 : merged_index = HPhi::kInvalidMergedIndex;
337 : }
338 680604 : HPhi* phi = new(zone()) HPhi(merged_index, zone());
339 680604 : AddPhi(phi);
340 680604 : return phi;
341 : }
342 :
343 :
344 4964890 : HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id,
345 14894669 : RemovableSimulate removable) {
346 : DCHECK(HasEnvironment());
347 4964890 : 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 9929780 : 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 7844132 : for (int i = 0; i < push_count; ++i) {
364 : instr->AddPushedValue(environment->ExpressionStackAt(i));
365 : }
366 10888830 : for (GrowableBitVector::Iterator it(environment->assigned_variables(),
367 4964889 : zone());
368 : !it.Done();
369 : it.Advance()) {
370 : int index = it.Current();
371 : instr->AddAssignedValue(index, environment->Lookup(index));
372 : }
373 : environment->ClearHistory();
374 4964891 : return instr;
375 : }
376 :
377 :
378 4617298 : void HBasicBlock::Finish(HControlInstruction* end, SourcePosition position) {
379 : DCHECK(!IsFinished());
380 4617298 : AddInstruction(end, position);
381 4617299 : end_ = end;
382 9865501 : for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
383 5248205 : it.Current()->RegisterPredecessor(this);
384 : }
385 4617296 : }
386 :
387 :
388 2993677 : void HBasicBlock::Goto(HBasicBlock* block, SourcePosition position,
389 6238865 : FunctionState* state, bool add_simulate) {
390 4670165 : bool drop_extra = state != NULL &&
391 : state->inlining_kind() == NORMAL_RETURN;
392 :
393 2993677 : if (block->IsInlineReturnTarget()) {
394 : HEnvironment* env = last_environment();
395 522900 : int argument_count = env->arguments_environment()->parameter_count();
396 : AddInstruction(new(zone())
397 : HLeaveInlined(state->entry(), argument_count),
398 522900 : position);
399 1045800 : UpdateEnvironment(last_environment()->DiscardInlined(drop_extra));
400 : }
401 :
402 2993677 : if (add_simulate) AddNewSimulate(BailoutId::None(), position);
403 : HGoto* instr = new(zone()) HGoto(block);
404 2993676 : Finish(instr, position);
405 2993676 : }
406 :
407 :
408 79534 : void HBasicBlock::AddLeaveInlined(HValue* return_value, FunctionState* state,
409 198835 : SourcePosition position) {
410 : HBasicBlock* target = state->function_return();
411 39767 : bool drop_extra = state->inlining_kind() == NORMAL_RETURN;
412 :
413 : DCHECK(target->IsInlineReturnTarget());
414 : DCHECK(return_value != NULL);
415 : HEnvironment* env = last_environment();
416 39767 : int argument_count = env->arguments_environment()->parameter_count();
417 : AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count),
418 39767 : position);
419 79534 : UpdateEnvironment(last_environment()->DiscardInlined(drop_extra));
420 : last_environment()->Push(return_value);
421 39767 : AddNewSimulate(BailoutId::None(), position);
422 : HGoto* instr = new(zone()) HGoto(target);
423 39767 : Finish(instr, position);
424 39767 : }
425 :
426 :
427 0 : void HBasicBlock::SetInitialEnvironment(HEnvironment* env) {
428 : DCHECK(!HasEnvironment());
429 : DCHECK(first() == NULL);
430 : UpdateEnvironment(env);
431 0 : }
432 :
433 :
434 15651291 : void HBasicBlock::UpdateEnvironment(HEnvironment* env) {
435 10471935 : last_environment_ = env;
436 : graph()->update_maximum_environment_size(env->first_expression_index());
437 5179356 : }
438 :
439 :
440 25971 : void HBasicBlock::SetJoinId(BailoutId ast_id) {
441 1826768 : int length = predecessors_.length();
442 : DCHECK(length > 0);
443 2531615 : for (int i = 0; i < length; i++) {
444 5011288 : HBasicBlock* predecessor = predecessors_[i];
445 : DCHECK(predecessor->end()->IsGoto());
446 2505644 : 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 25971 : }
455 :
456 :
457 367846 : bool HBasicBlock::Dominates(HBasicBlock* other) const {
458 5005313 : HBasicBlock* current = other->dominator();
459 5718347 : while (current != NULL) {
460 5359825 : if (current == this) return true;
461 : current = current->dominator();
462 : }
463 : return false;
464 : }
465 :
466 :
467 30212 : bool HBasicBlock::EqualToOrDominates(HBasicBlock* other) const {
468 30212 : if (this == other) return true;
469 22658 : 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 89866 : void HBasicBlock::PostProcessLoopHeader(IterationStatement* stmt) {
485 : DCHECK(IsLoopHeader());
486 :
487 : SetJoinId(stmt->EntryId());
488 45312 : if (predecessors()->length() == 1) {
489 : // This is a degenerated loop.
490 : DetachLoopInformation();
491 45312 : 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 44554 : for (int i = 1; i < predecessors()->length(); ++i) {
497 89108 : loop_information()->RegisterBackEdge(predecessors()->at(i));
498 : }
499 : }
500 :
501 :
502 3273 : void HBasicBlock::MarkSuccEdgeUnreachable(int succ) {
503 : DCHECK(IsFinished());
504 3273 : HBasicBlock* succ_block = end()->SuccessorAt(succ);
505 :
506 : DCHECK(succ_block->predecessors()->length() == 1);
507 : succ_block->MarkUnreachable();
508 3273 : }
509 :
510 :
511 18904477 : void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) {
512 5248205 : 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 4133153 : HEnvironment* incoming_env = pred->last_environment();
518 913137 : if (IsLoopHeader()) {
519 : DCHECK_EQ(phis()->length(), incoming_env->length());
520 927038 : for (int i = 0; i < phis_.length(); ++i) {
521 1360480 : phis_[i]->AddInput(incoming_env->values()->at(i));
522 : }
523 : } else {
524 852983 : last_environment()->AddIncomingEdge(this, pred->last_environment());
525 : }
526 7555084 : } else if (!HasEnvironment() && !IsFinished()) {
527 : DCHECK(!IsLoopHeader());
528 3220016 : SetInitialEnvironment(pred->last_environment()->Copy());
529 : }
530 :
531 : predecessors_.Add(pred, zone());
532 5248202 : }
533 :
534 :
535 9885412 : 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 15109294 : while (index < dominated_blocks_.length() &&
541 2611940 : dominated_blocks_[index]->block_id() < block->block_id()) {
542 2611942 : ++index;
543 : }
544 : dominated_blocks_.InsertAt(index, block, zone());
545 4942703 : }
546 :
547 :
548 5889012 : void HBasicBlock::AssignCommonDominator(HBasicBlock* other) {
549 5063602 : if (dominator_ == NULL) {
550 4238192 : dominator_ = other;
551 4238192 : other->AddDominatedBlock(this);
552 825410 : } else if (other->dominator() != NULL) {
553 6484553 : HBasicBlock* first = dominator_;
554 7861792 : HBasicBlock* second = other;
555 :
556 5607525 : while (first != second) {
557 4782115 : 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 825410 : if (dominator_ != first) {
566 : DCHECK(dominator_->dominated_blocks_.Contains(this));
567 704512 : dominator_->dominated_blocks_.RemoveElement(this);
568 704511 : dominator_ = first;
569 704511 : first->AddDominatedBlock(this);
570 : }
571 : }
572 5063602 : }
573 :
574 :
575 120116 : 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 2348488 : HBasicBlock* last = loop_information()->GetLastBackEdge();
586 : int outstanding_successors = 1; // one edge from the pre-header
587 : // Header always dominates everything.
588 : MarkAsLoopSuccessorDominator();
589 2184018 : for (int j = block_id(); j <= last->block_id(); ++j) {
590 6743790 : HBasicBlock* dominator_candidate = graph_->blocks()->at(j);
591 2322274 : for (HPredecessorIterator it(dominator_candidate); !it.Done();
592 : it.Advance()) {
593 1290323 : HBasicBlock* predecessor = it.Current();
594 : // Don't count back edges.
595 1290323 : if (predecessor->block_id() < dominator_candidate->block_id()) {
596 1221139 : 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 2312936 : if (outstanding_successors == 0 &&
611 1031951 : (parent_loop_header == this && !dominator_candidate->IsLoopHeader())) {
612 : dominator_candidate->MarkAsLoopSuccessorDominator();
613 : }
614 : HControlInstruction* end = dominator_candidate->end();
615 2357614 : for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
616 1325663 : HBasicBlock* successor = it.Current();
617 : // Only count successors that remain inside the loop and don't loop back
618 : // to a loop header.
619 2582142 : 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 1161081 : outstanding_successors++;
625 : }
626 : }
627 : }
628 60058 : }
629 :
630 :
631 5595159 : int HBasicBlock::PredecessorIndexOf(HBasicBlock* predecessor) const {
632 20954938 : for (int i = 0; i < predecessors_.length(); ++i) {
633 31432407 : 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 60154 : void HLoopInformation::RegisterBackEdge(HBasicBlock* block) {
657 60154 : this->back_edges_.Add(block, block->zone());
658 60154 : AddBlock(block);
659 60154 : }
660 :
661 :
662 375513 : HBasicBlock* HLoopInformation::GetLastBackEdge() const {
663 : int max_id = -1;
664 : HBasicBlock* result = NULL;
665 1682224 : for (int i = 0; i < back_edges_.length(); ++i) {
666 1742281 : HBasicBlock* cur = back_edges_[i];
667 435570 : if (cur->block_id() > max_id) {
668 : max_id = cur->block_id();
669 : result = cur;
670 : }
671 : }
672 375513 : return result;
673 : }
674 :
675 :
676 1097589 : void HLoopInformation::AddBlock(HBasicBlock* block) {
677 1972813 : if (block == loop_header()) return;
678 1052888 : if (block->parent_loop_header() == loop_header()) return;
679 875224 : 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 1896862 : for (int i = 0; i < block->predecessors()->length(); ++i) {
685 1037435 : 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 563623 : HConstant* HGraph::GetConstant(SetOncePointer<HConstant>* pointer,
825 652566 : int32_t value) {
826 563623 : if (!pointer->is_set()) {
827 : // Can't pass GetInvalidContext() to HConstant::New, because that will
828 : // recursively call GetConstant
829 326283 : HConstant* constant = HConstant::New(isolate(), zone(), NULL, value);
830 326283 : constant->InsertAfter(entry_block()->first());
831 : pointer->set(constant);
832 326283 : return constant;
833 : }
834 237340 : return ReinsertConstantIfNecessary(pointer->get());
835 : }
836 :
837 :
838 8 : HConstant* HGraph::ReinsertConstantIfNecessary(HConstant* constant) {
839 5339285 : 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 34279 : HConstant* HGraph::GetConstant0() {
849 450695 : return GetConstant(&constant_0_, 0);
850 : }
851 :
852 :
853 325 : HConstant* HGraph::GetConstant1() {
854 94733 : return GetConstant(&constant_1_, 1);
855 : }
856 :
857 :
858 0 : HConstant* HGraph::GetConstantMinus1() {
859 17003 : 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 3978426 : DEFINE_GET_CONSTANT(Undefined, undefined, undefined_value, undefined,
883 : HType::Undefined(), false, true)
884 208077 : DEFINE_GET_CONSTANT(True, true, true_value, boolean, HType::Boolean(), true,
885 : false)
886 188400 : DEFINE_GET_CONSTANT(False, false, false_value, boolean, HType::Boolean(), false,
887 : false)
888 11174421 : DEFINE_GET_CONSTANT(Hole, the_hole, the_hole_value, the_hole, HType::None(),
889 : false, false)
890 29496 : DEFINE_GET_CONSTANT(Null, null, null_value, null, HType::Null(), false, true)
891 1598958 : 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 349727 : DEFINE_IS_CONSTANT(Undefined, undefined)
901 342482 : DEFINE_IS_CONSTANT(0, 0)
902 337649 : DEFINE_IS_CONSTANT(1, 1)
903 333810 : DEFINE_IS_CONSTANT(Minus1, minus1)
904 333408 : DEFINE_IS_CONSTANT(True, true)
905 313044 : DEFINE_IS_CONSTANT(False, false)
906 312140 : DEFINE_IS_CONSTANT(Hole, the_hole)
907 309724 : 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 349727 : bool HGraph::IsStandardConstant(HConstant* constant) {
918 349727 : if (IsConstantUndefined(constant)) return true;
919 342482 : if (IsConstant0(constant)) return true;
920 337649 : if (IsConstant1(constant)) return true;
921 333810 : if (IsConstantMinus1(constant)) return true;
922 333408 : if (IsConstantTrue(constant)) return true;
923 313044 : if (IsConstantFalse(constant)) return true;
924 312140 : if (IsConstantHole(constant)) return true;
925 309724 : if (IsConstantNull(constant)) return true;
926 309607 : return false;
927 : }
928 :
929 :
930 0 : HGraphBuilder::IfBuilder::IfBuilder() : builder_(NULL), needs_compare_(true) {}
931 :
932 :
933 14145 : HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder)
934 103187 : : needs_compare_(true) {
935 103187 : Initialize(builder);
936 14145 : }
937 :
938 :
939 0 : HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder,
940 : HIfContinuation* continuation)
941 5178 : : 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 108365 : builder_ = builder;
950 108365 : finished_ = false;
951 108365 : did_then_ = false;
952 108365 : did_else_ = false;
953 108365 : did_else_if_ = false;
954 108365 : did_and_ = false;
955 108365 : did_or_ = false;
956 108365 : captured_ = false;
957 108365 : pending_merge_block_ = false;
958 108365 : split_edge_merge_block_ = NULL;
959 108365 : merge_at_join_blocks_ = NULL;
960 108365 : normal_merge_at_join_block_count_ = 0;
961 108365 : deopt_merge_at_join_block_count_ = 0;
962 0 : }
963 :
964 :
965 103187 : void HGraphBuilder::IfBuilder::Initialize(HGraphBuilder* builder) {
966 : InitializeDontCreateBlocks(builder);
967 : HEnvironment* env = builder->environment();
968 103187 : first_true_block_ = builder->CreateBasicBlock(env->Copy());
969 103187 : first_false_block_ = builder->CreateBasicBlock(env->Copy());
970 103187 : }
971 :
972 :
973 128208 : HControlInstruction* HGraphBuilder::IfBuilder::AddCompare(
974 178250 : HControlInstruction* compare) {
975 : DCHECK(did_then_ == did_else_);
976 128208 : 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 128208 : if (split_edge_merge_block_ != NULL) {
990 25021 : HEnvironment* env = first_false_block_->last_environment();
991 50042 : HBasicBlock* split_edge = builder()->CreateBasicBlock(env->Copy());
992 25021 : if (did_or_) {
993 16839 : compare->SetSuccessorAt(0, split_edge);
994 16839 : compare->SetSuccessorAt(1, first_false_block_);
995 : } else {
996 8182 : compare->SetSuccessorAt(0, first_true_block_);
997 8182 : compare->SetSuccessorAt(1, split_edge);
998 : }
999 25021 : builder()->GotoNoSimulate(split_edge, split_edge_merge_block_);
1000 : } else {
1001 103187 : compare->SetSuccessorAt(0, first_true_block_);
1002 103187 : compare->SetSuccessorAt(1, first_false_block_);
1003 : }
1004 128208 : builder()->FinishCurrentBlock(compare);
1005 128208 : needs_compare_ = false;
1006 128208 : return compare;
1007 : }
1008 :
1009 :
1010 84177 : void HGraphBuilder::IfBuilder::Or() {
1011 : DCHECK(!needs_compare_);
1012 : DCHECK(!did_and_);
1013 16839 : did_or_ = true;
1014 16839 : HEnvironment* env = first_false_block_->last_environment();
1015 16839 : if (split_edge_merge_block_ == NULL) {
1016 33660 : split_edge_merge_block_ = builder()->CreateBasicBlock(env->Copy());
1017 16830 : builder()->GotoNoSimulate(first_true_block_, split_edge_merge_block_);
1018 16830 : first_true_block_ = split_edge_merge_block_;
1019 : }
1020 16839 : builder()->set_current_block(first_false_block_);
1021 33678 : first_false_block_ = builder()->CreateBasicBlock(env->Copy());
1022 16839 : }
1023 :
1024 :
1025 40910 : void HGraphBuilder::IfBuilder::And() {
1026 : DCHECK(!needs_compare_);
1027 : DCHECK(!did_or_);
1028 8182 : did_and_ = true;
1029 8182 : HEnvironment* env = first_false_block_->last_environment();
1030 8182 : if (split_edge_merge_block_ == NULL) {
1031 16364 : split_edge_merge_block_ = builder()->CreateBasicBlock(env->Copy());
1032 8182 : builder()->GotoNoSimulate(first_false_block_, split_edge_merge_block_);
1033 8182 : first_false_block_ = split_edge_merge_block_;
1034 : }
1035 8182 : builder()->set_current_block(first_true_block_);
1036 16364 : first_true_block_ = builder()->CreateBasicBlock(env->Copy());
1037 8182 : }
1038 :
1039 :
1040 838 : void HGraphBuilder::IfBuilder::CaptureContinuation(
1041 838 : HIfContinuation* continuation) {
1042 : DCHECK(!did_else_if_);
1043 : DCHECK(!finished_);
1044 : DCHECK(!captured_);
1045 :
1046 838 : HBasicBlock* true_block = NULL;
1047 838 : HBasicBlock* false_block = NULL;
1048 838 : Finish(&true_block, &false_block);
1049 : DCHECK(true_block != NULL);
1050 : DCHECK(false_block != NULL);
1051 838 : continuation->Capture(true_block, false_block);
1052 838 : captured_ = true;
1053 : builder()->set_current_block(NULL);
1054 838 : End();
1055 838 : }
1056 :
1057 :
1058 30295 : void HGraphBuilder::IfBuilder::JoinContinuation(HIfContinuation* continuation) {
1059 : DCHECK(!did_else_if_);
1060 : DCHECK(!finished_);
1061 : DCHECK(!captured_);
1062 12554 : HBasicBlock* true_block = NULL;
1063 12554 : HBasicBlock* false_block = NULL;
1064 12554 : Finish(&true_block, &false_block);
1065 12554 : merge_at_join_blocks_ = NULL;
1066 12554 : if (true_block != NULL && !true_block->IsFinished()) {
1067 : DCHECK(continuation->IsTrueReachable());
1068 : builder()->GotoNoSimulate(true_block, continuation->true_branch());
1069 : }
1070 12554 : if (false_block != NULL && !false_block->IsFinished()) {
1071 : DCHECK(continuation->IsFalseReachable());
1072 : builder()->GotoNoSimulate(false_block, continuation->false_branch());
1073 : }
1074 12554 : captured_ = true;
1075 12554 : End();
1076 12554 : }
1077 :
1078 :
1079 216730 : void HGraphBuilder::IfBuilder::Then() {
1080 : DCHECK(!captured_);
1081 : DCHECK(!finished_);
1082 108365 : did_then_ = true;
1083 108365 : 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 108365 : builder()->set_current_block(first_true_block_);
1095 108365 : pending_merge_block_ = true;
1096 108365 : }
1097 :
1098 :
1099 122456 : void HGraphBuilder::IfBuilder::Else() {
1100 : DCHECK(did_then_);
1101 : DCHECK(!captured_);
1102 : DCHECK(!finished_);
1103 108365 : AddMergeAtJoinBlock(false);
1104 108365 : builder()->set_current_block(first_false_block_);
1105 108365 : pending_merge_block_ = true;
1106 108365 : did_else_ = true;
1107 14091 : }
1108 :
1109 6954 : void HGraphBuilder::IfBuilder::Deopt(DeoptimizeReason reason) {
1110 : DCHECK(did_then_);
1111 6954 : builder()->Add<HDeoptimize>(reason, Deoptimizer::EAGER);
1112 6954 : AddMergeAtJoinBlock(true);
1113 6954 : }
1114 :
1115 :
1116 41268 : void HGraphBuilder::IfBuilder::Return(HValue* value) {
1117 13756 : HValue* parameter_count = builder()->graph()->GetConstantMinus1();
1118 : builder()->FinishExitCurrentBlock(
1119 27512 : builder()->New<HReturn>(value, parameter_count));
1120 13756 : AddMergeAtJoinBlock(false);
1121 13756 : }
1122 :
1123 :
1124 684469 : void HGraphBuilder::IfBuilder::AddMergeAtJoinBlock(bool deopt) {
1125 502018 : if (!pending_merge_block_) return;
1126 216730 : HBasicBlock* block = builder()->current_block();
1127 : DCHECK(block == NULL || !block->IsFinished());
1128 216730 : MergeAtJoinBlock* record = new (builder()->zone())
1129 216730 : MergeAtJoinBlock(block, deopt, merge_at_join_blocks_);
1130 216730 : merge_at_join_blocks_ = record;
1131 216730 : if (block != NULL) {
1132 : DCHECK(block->end() == NULL);
1133 195267 : if (deopt) {
1134 6954 : normal_merge_at_join_block_count_++;
1135 : } else {
1136 188313 : deopt_merge_at_join_block_count_++;
1137 : }
1138 : }
1139 : builder()->set_current_block(NULL);
1140 216730 : pending_merge_block_ = false;
1141 : }
1142 :
1143 :
1144 108365 : void HGraphBuilder::IfBuilder::Finish() {
1145 : DCHECK(!finished_);
1146 108365 : if (!did_then_) {
1147 847 : Then();
1148 : }
1149 108365 : AddMergeAtJoinBlock(false);
1150 108365 : if (!did_else_) {
1151 : Else();
1152 13569 : AddMergeAtJoinBlock(false);
1153 : }
1154 108365 : finished_ = true;
1155 108365 : }
1156 :
1157 :
1158 13392 : void HGraphBuilder::IfBuilder::Finish(HBasicBlock** then_continuation,
1159 : HBasicBlock** else_continuation) {
1160 13392 : Finish();
1161 :
1162 13392 : MergeAtJoinBlock* else_record = merge_at_join_blocks_;
1163 13392 : if (else_continuation != NULL) {
1164 13392 : *else_continuation = else_record->block_;
1165 : }
1166 13392 : MergeAtJoinBlock* then_record = else_record->next_;
1167 13392 : if (then_continuation != NULL) {
1168 13392 : *then_continuation = then_record->block_;
1169 : }
1170 : DCHECK(then_record->next_ == NULL);
1171 13392 : }
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 445969 : void HGraphBuilder::IfBuilder::End() {
1182 108365 : if (captured_) return;
1183 94973 : Finish();
1184 :
1185 94973 : int total_merged_blocks = normal_merge_at_join_block_count_ +
1186 94973 : deopt_merge_at_join_block_count_;
1187 : DCHECK(total_merged_blocks >= 1);
1188 : HBasicBlock* merge_block =
1189 175850 : 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 94973 : MergeAtJoinBlock* current = merge_at_join_blocks_;
1194 351700 : while (current != NULL) {
1195 175850 : 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 173702 : if (total_merged_blocks == 1) {
1200 : builder()->set_current_block(current->block_);
1201 : return;
1202 : }
1203 : builder()->GotoNoSimulate(current->block_, merge_block);
1204 : }
1205 161754 : current = current->next_;
1206 : }
1207 :
1208 : // Merge deopt blocks, padding when necessary.
1209 80877 : current = merge_at_join_blocks_;
1210 323508 : while (current != NULL) {
1211 161754 : if (current->deopt_ && current->block_ != NULL) {
1212 : current->block_->FinishExit(
1213 4296 : HAbnormalExit::New(builder()->isolate(), builder()->zone(), NULL),
1214 2148 : SourcePosition::Unknown());
1215 : }
1216 161754 : 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 15600 : HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, HValue* context,
1228 : LoopBuilder::Direction direction) {
1229 : Initialize(builder, context, direction, builder->graph()->GetConstant1());
1230 15600 : }
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 15600 : builder_ = builder;
1246 15600 : context_ = context;
1247 15600 : direction_ = direction;
1248 15600 : increment_amount_ = increment_amount;
1249 :
1250 15600 : finished_ = false;
1251 15600 : header_block_ = builder->CreateLoopHeaderBlock();
1252 15600 : body_block_ = NULL;
1253 15600 : exit_block_ = NULL;
1254 15600 : exit_trampoline_block_ = NULL;
1255 0 : }
1256 :
1257 :
1258 15600 : HValue* HGraphBuilder::LoopBuilder::BeginBody(
1259 : HValue* initial,
1260 : HValue* terminating,
1261 82 : Token::Value token) {
1262 : DCHECK(direction_ != kWhileTrue);
1263 15682 : HEnvironment* env = builder_->environment();
1264 15600 : phi_ = header_block_->AddNewPhi(env->values()->length());
1265 15600 : phi_->AddInput(initial);
1266 : env->Push(initial);
1267 15600 : builder_->GotoNoSimulate(header_block_);
1268 :
1269 15600 : HEnvironment* body_env = env->Copy();
1270 15600 : HEnvironment* exit_env = env->Copy();
1271 : // Remove the phi from the expression stack
1272 15600 : body_env->Pop();
1273 15600 : exit_env->Pop();
1274 15600 : body_block_ = builder_->CreateBasicBlock(body_env);
1275 15600 : exit_block_ = builder_->CreateBasicBlock(exit_env);
1276 :
1277 15600 : builder_->set_current_block(header_block_);
1278 15600 : env->Pop();
1279 : builder_->FinishCurrentBlock(builder_->New<HCompareNumericAndBranch>(
1280 15600 : phi_, terminating, token, body_block_, exit_block_));
1281 :
1282 15600 : builder_->set_current_block(body_block_);
1283 15600 : 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 15518 : 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 15600 : void HGraphBuilder::LoopBuilder::EndBody() {
1328 : DCHECK(!finished_);
1329 :
1330 15600 : if (direction_ == kPostIncrement || direction_ == kPostDecrement) {
1331 31118 : Isolate* isolate = builder_->isolate();
1332 15518 : if (direction_ == kPostIncrement) {
1333 : increment_ =
1334 29364 : HAdd::New(isolate, zone(), context_, phi_, increment_amount_);
1335 : } else {
1336 : increment_ =
1337 1672 : HSub::New(isolate, zone(), context_, phi_, increment_amount_);
1338 : }
1339 15518 : increment_->ClearFlag(HValue::kCanOverflow);
1340 15518 : builder_->AddInstruction(increment_);
1341 : }
1342 :
1343 15600 : if (direction_ != kWhileTrue) {
1344 : // Push the new increment value on the expression stack to merge into
1345 : // the phi.
1346 15600 : builder_->environment()->Push(increment_);
1347 : }
1348 15600 : HBasicBlock* last_block = builder_->current_block();
1349 31200 : builder_->GotoNoSimulate(last_block, header_block_);
1350 31200 : header_block_->loop_information()->RegisterBackEdge(last_block);
1351 :
1352 15600 : if (exit_trampoline_block_ != NULL) {
1353 340 : builder_->set_current_block(exit_trampoline_block_);
1354 : } else {
1355 15260 : builder_->set_current_block(exit_block_);
1356 : }
1357 15600 : finished_ = true;
1358 15600 : }
1359 :
1360 :
1361 1146131 : HGraph* HGraphBuilder::CreateGraph() {
1362 : DCHECK(!FLAG_minimal);
1363 574892 : graph_ = new (zone()) HGraph(info_, descriptor_);
1364 287446 : if (FLAG_hydrogen_stats) isolate()->GetHStatistics()->Initialize(info_);
1365 287446 : CompilationPhase phase("H_Block building", info_);
1366 287446 : set_current_block(graph()->entry_block());
1367 287446 : if (!BuildGraph()) return NULL;
1368 283793 : graph()->FinalizeUniqueness();
1369 283794 : return graph_;
1370 : }
1371 :
1372 :
1373 33772247 : HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
1374 : DCHECK(current_block() != NULL);
1375 : DCHECK(!FLAG_hydrogen_track_positions || position_.IsKnown() ||
1376 : !info_->IsOptimizing());
1377 16886122 : current_block()->AddInstruction(instr, source_position());
1378 16886125 : if (graph()->IsInsideNoSideEffectsScope()) {
1379 : instr->SetFlag(HValue::kHasNoObservableSideEffects);
1380 : }
1381 16886125 : return instr;
1382 : }
1383 :
1384 :
1385 1225651 : void HGraphBuilder::FinishCurrentBlock(HControlInstruction* last) {
1386 : DCHECK(!FLAG_hydrogen_track_positions || !info_->IsOptimizing() ||
1387 : position_.IsKnown());
1388 1225651 : current_block()->Finish(last, source_position());
1389 3653420 : if (last->IsReturn() || last->IsAbnormalExit()) {
1390 : set_current_block(NULL);
1391 : }
1392 1225651 : }
1393 :
1394 :
1395 356056 : void HGraphBuilder::FinishExitCurrentBlock(HControlInstruction* instruction) {
1396 : DCHECK(!FLAG_hydrogen_track_positions || !info_->IsOptimizing() ||
1397 : position_.IsKnown());
1398 : current_block()->FinishExit(instruction, source_position());
1399 725762 : if (instruction->IsReturn() || instruction->IsAbnormalExit()) {
1400 : set_current_block(NULL);
1401 : }
1402 356055 : }
1403 :
1404 :
1405 55016 : void HGraphBuilder::AddIncrementCounter(StatsCounter* counter) {
1406 55016 : 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 55016 : }
1416 :
1417 :
1418 0 : void HGraphBuilder::AddSimulate(BailoutId id,
1419 336906 : RemovableSimulate removable) {
1420 : DCHECK(current_block() != NULL);
1421 : DCHECK(!graph()->IsInsideNoSideEffectsScope());
1422 336906 : current_block()->AddNewSimulate(id, source_position(), removable);
1423 0 : }
1424 :
1425 :
1426 1053801 : HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) {
1427 1053801 : HBasicBlock* b = graph()->CreateBasicBlock();
1428 : b->SetInitialEnvironment(env);
1429 1053800 : return b;
1430 : }
1431 :
1432 :
1433 61252 : HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() {
1434 61252 : HBasicBlock* header = graph()->CreateBasicBlock();
1435 61252 : HEnvironment* entry_env = environment()->CopyAsLoopHeader(header);
1436 : header->SetInitialEnvironment(entry_env);
1437 61252 : header->AttachLoopInformation();
1438 61252 : return header;
1439 : }
1440 :
1441 :
1442 9 : HValue* HGraphBuilder::BuildGetElementsKind(HValue* object) {
1443 9 : HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap());
1444 :
1445 : HValue* bit_field2 =
1446 9 : Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField2());
1447 9 : return BuildDecodeField<Map::ElementsKindBits>(bit_field2);
1448 : }
1449 :
1450 :
1451 1072 : HValue* HGraphBuilder::BuildEnumLength(HValue* map) {
1452 : NoObservableSideEffectsScope scope(this);
1453 : HValue* bit_field3 =
1454 1072 : Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField3());
1455 2144 : return BuildDecodeField<Map::EnumLengthBits>(bit_field3);
1456 : }
1457 :
1458 :
1459 0 : HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) {
1460 314200 : if (obj->type().IsHeapObject()) return obj;
1461 183117 : return Add<HCheckHeapObject>(obj);
1462 : }
1463 :
1464 8900 : void HGraphBuilder::FinishExitWithHardDeoptimization(DeoptimizeReason reason) {
1465 8900 : Add<HDeoptimize>(reason, Deoptimizer::EAGER);
1466 8900 : FinishExitCurrentBlock(New<HAbnormalExit>());
1467 8900 : }
1468 :
1469 :
1470 82260 : HValue* HGraphBuilder::BuildCheckString(HValue* string) {
1471 82260 : if (!string->type().IsString()) {
1472 : DCHECK(!string->IsConstant() ||
1473 : !HConstant::cast(string)->HasStringValue());
1474 : BuildCheckHeapObject(string);
1475 31655 : return Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING);
1476 : }
1477 : return string;
1478 : }
1479 :
1480 6244 : HValue* HGraphBuilder::BuildWrapReceiver(HValue* object, HValue* checked) {
1481 5524 : if (object->type().IsJSObject()) return object;
1482 5197 : HValue* function = checked->ActualValue();
1483 15591 : if (function->IsConstant() &&
1484 5917 : HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
1485 : Handle<JSFunction> f = Handle<JSFunction>::cast(
1486 360 : HConstant::cast(function)->handle(isolate()));
1487 : SharedFunctionInfo* shared = f->shared();
1488 613 : if (is_strict(shared->language_mode()) || shared->native()) return object;
1489 : }
1490 4956 : 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 2606 : HValue* HGraphBuilder::BuildCheckForCapacityGrow(
1509 : HValue* object,
1510 : HValue* elements,
1511 : ElementsKind kind,
1512 : HValue* length,
1513 : HValue* key,
1514 : bool is_js_array,
1515 3073 : PropertyAccessType access_type) {
1516 : IfBuilder length_checker(this);
1517 :
1518 2606 : Token::Value token = IsHoleyElementsKind(kind) ? Token::GTE : Token::EQ;
1519 2606 : length_checker.If<HCompareNumericAndBranch>(key, length, token);
1520 :
1521 2606 : length_checker.Then();
1522 :
1523 : HValue* current_capacity = AddLoadFixedArrayLength(elements);
1524 :
1525 2606 : 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 2606 : object, elements, key, current_capacity, is_js_array, kind);
1539 : environment()->Push(result);
1540 : }
1541 :
1542 2606 : if (is_js_array) {
1543 5196 : HValue* new_length = AddUncasted<HAdd>(key, graph_->GetConstant1());
1544 : new_length->ClearFlag(HValue::kCanOverflow);
1545 :
1546 : Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(kind),
1547 2598 : new_length);
1548 : }
1549 :
1550 2606 : 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 467 : kind);
1556 : }
1557 :
1558 : length_checker.Else();
1559 2606 : Add<HBoundsCheck>(key, length);
1560 :
1561 : environment()->Push(elements);
1562 2606 : length_checker.End();
1563 :
1564 5212 : return environment()->Pop();
1565 : }
1566 :
1567 :
1568 238 : HValue* HGraphBuilder::BuildCopyElementsOnWrite(HValue* object,
1569 : HValue* elements,
1570 : ElementsKind kind,
1571 238 : HValue* length) {
1572 : Factory* factory = isolate()->factory();
1573 :
1574 : IfBuilder cow_checker(this);
1575 :
1576 238 : cow_checker.If<HCompareMap>(elements, factory->fixed_cow_array_map());
1577 238 : cow_checker.Then();
1578 :
1579 : HValue* capacity = AddLoadFixedArrayLength(elements);
1580 :
1581 : HValue* new_elements = BuildGrowElementsCapacity(object, elements, kind,
1582 238 : kind, length, capacity);
1583 :
1584 : environment()->Push(new_elements);
1585 :
1586 : cow_checker.Else();
1587 :
1588 : environment()->Push(elements);
1589 :
1590 238 : cow_checker.End();
1591 :
1592 476 : return environment()->Pop();
1593 : }
1594 :
1595 9 : HValue* HGraphBuilder::BuildCreateIterResultObject(HValue* value,
1596 : HValue* done) {
1597 : NoObservableSideEffectsScope scope(this);
1598 :
1599 : // Allocate the JSIteratorResult object.
1600 : HValue* result =
1601 : Add<HAllocate>(Add<HConstant>(JSIteratorResult::kSize), HType::JSObject(),
1602 9 : NOT_TENURED, JS_OBJECT_TYPE, graph()->GetConstant0());
1603 :
1604 : // Initialize the JSIteratorResult object.
1605 9 : HValue* native_context = BuildGetNativeContext();
1606 : HValue* map = Add<HLoadNamedField>(
1607 : native_context, nullptr,
1608 9 : HObjectAccess::ForContextSlot(Context::ITERATOR_RESULT_MAP_INDEX));
1609 9 : Add<HStoreNamedField>(result, HObjectAccess::ForMap(), map);
1610 9 : HValue* empty_fixed_array = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex);
1611 : Add<HStoreNamedField>(result, HObjectAccess::ForPropertiesPointer(),
1612 9 : empty_fixed_array);
1613 : Add<HStoreNamedField>(result, HObjectAccess::ForElementsPointer(),
1614 9 : empty_fixed_array);
1615 : Add<HStoreNamedField>(result, HObjectAccess::ForObservableJSObjectOffset(
1616 : JSIteratorResult::kValueOffset),
1617 9 : value);
1618 : Add<HStoreNamedField>(result, HObjectAccess::ForObservableJSObjectOffset(
1619 : JSIteratorResult::kDoneOffset),
1620 9 : done);
1621 : STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
1622 9 : return result;
1623 : }
1624 :
1625 :
1626 41310 : HValue* HGraphBuilder::BuildNumberToString(HValue* object, AstType* type) {
1627 : NoObservableSideEffectsScope scope(this);
1628 :
1629 : // Convert constant numbers at compile time.
1630 5644 : if (object->IsConstant() && HConstant::cast(object)->HasNumberValue()) {
1631 409 : Handle<Object> number = HConstant::cast(object)->handle(isolate());
1632 409 : Handle<String> result = isolate()->factory()->NumberToString(number);
1633 409 : return Add<HConstant>(result);
1634 : }
1635 :
1636 : // Create a joinable continuation.
1637 : HIfContinuation found(graph()->CreateBasicBlock(),
1638 9612 : graph()->CreateBasicBlock());
1639 :
1640 : // Load the number string cache.
1641 : HValue* number_string_cache =
1642 4806 : Add<HLoadRoot>(Heap::kNumberStringCacheRootIndex);
1643 :
1644 : // Make the hash mask from the length of the number string cache. It
1645 : // contains two elements (number and string) for each cache entry.
1646 : HValue* mask = AddLoadFixedArrayLength(number_string_cache);
1647 : mask->set_type(HType::Smi());
1648 4806 : mask = AddUncasted<HSar>(mask, graph()->GetConstant1());
1649 4806 : mask = AddUncasted<HSub>(mask, graph()->GetConstant1());
1650 :
1651 : // Check whether object is a smi.
1652 : IfBuilder if_objectissmi(this);
1653 4806 : if_objectissmi.If<HIsSmiAndBranch>(object);
1654 4806 : if_objectissmi.Then();
1655 : {
1656 : // Compute hash for smi similar to smi_get_hash().
1657 4806 : HValue* hash = AddUncasted<HBitwise>(Token::BIT_AND, object, mask);
1658 :
1659 : // Load the key.
1660 4806 : HValue* key_index = AddUncasted<HShl>(hash, graph()->GetConstant1());
1661 : HValue* key = Add<HLoadKeyed>(number_string_cache, key_index, nullptr,
1662 4806 : nullptr, FAST_ELEMENTS, ALLOW_RETURN_HOLE);
1663 :
1664 : // Check if object == key.
1665 : IfBuilder if_objectiskey(this);
1666 4806 : if_objectiskey.If<HCompareObjectEqAndBranch>(object, key);
1667 4806 : if_objectiskey.Then();
1668 : {
1669 : // Make the key_index available.
1670 4806 : Push(key_index);
1671 : }
1672 4806 : if_objectiskey.JoinContinuation(&found);
1673 : }
1674 : if_objectissmi.Else();
1675 : {
1676 4806 : if (type->Is(AstType::SignedSmall())) {
1677 4261 : if_objectissmi.Deopt(DeoptimizeReason::kExpectedSmi);
1678 : } else {
1679 : // Check if the object is a heap number.
1680 : IfBuilder if_objectisnumber(this);
1681 : HValue* objectisnumber = if_objectisnumber.If<HCompareMap>(
1682 545 : object, isolate()->factory()->heap_number_map());
1683 545 : if_objectisnumber.Then();
1684 : {
1685 : // Compute hash for heap number similar to double_get_hash().
1686 : HValue* low = Add<HLoadNamedField>(
1687 : object, objectisnumber,
1688 545 : HObjectAccess::ForHeapNumberValueLowestBits());
1689 : HValue* high = Add<HLoadNamedField>(
1690 : object, objectisnumber,
1691 545 : HObjectAccess::ForHeapNumberValueHighestBits());
1692 545 : HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, low, high);
1693 545 : hash = AddUncasted<HBitwise>(Token::BIT_AND, hash, mask);
1694 :
1695 : // Load the key.
1696 545 : HValue* key_index = AddUncasted<HShl>(hash, graph()->GetConstant1());
1697 : HValue* key =
1698 : Add<HLoadKeyed>(number_string_cache, key_index, nullptr, nullptr,
1699 545 : FAST_ELEMENTS, ALLOW_RETURN_HOLE);
1700 :
1701 : // Check if the key is a heap number and compare it with the object.
1702 : IfBuilder if_keyisnotsmi(this);
1703 : HValue* keyisnotsmi = if_keyisnotsmi.IfNot<HIsSmiAndBranch>(key);
1704 545 : if_keyisnotsmi.Then();
1705 : {
1706 : IfBuilder if_keyisheapnumber(this);
1707 : if_keyisheapnumber.If<HCompareMap>(
1708 545 : key, isolate()->factory()->heap_number_map());
1709 545 : if_keyisheapnumber.Then();
1710 : {
1711 : // Check if values of key and object match.
1712 : IfBuilder if_keyeqobject(this);
1713 : if_keyeqobject.If<HCompareNumericAndBranch>(
1714 : Add<HLoadNamedField>(key, keyisnotsmi,
1715 545 : HObjectAccess::ForHeapNumberValue()),
1716 : Add<HLoadNamedField>(object, objectisnumber,
1717 : HObjectAccess::ForHeapNumberValue()),
1718 1090 : Token::EQ);
1719 545 : if_keyeqobject.Then();
1720 : {
1721 : // Make the key_index available.
1722 545 : Push(key_index);
1723 : }
1724 545 : if_keyeqobject.JoinContinuation(&found);
1725 : }
1726 545 : if_keyisheapnumber.JoinContinuation(&found);
1727 : }
1728 545 : if_keyisnotsmi.JoinContinuation(&found);
1729 : }
1730 : if_objectisnumber.Else();
1731 : {
1732 545 : if (type->Is(AstType::Number())) {
1733 545 : if_objectisnumber.Deopt(DeoptimizeReason::kExpectedHeapNumber);
1734 : }
1735 : }
1736 545 : if_objectisnumber.JoinContinuation(&found);
1737 : }
1738 : }
1739 4806 : if_objectissmi.JoinContinuation(&found);
1740 :
1741 : // Check for cache hit.
1742 : IfBuilder if_found(this, &found);
1743 4806 : if_found.Then();
1744 : {
1745 : // Count number to string operation in native code.
1746 4806 : AddIncrementCounter(isolate()->counters()->number_to_string_native());
1747 :
1748 : // Load the value in case of cache hit.
1749 : HValue* key_index = Pop();
1750 4806 : HValue* value_index = AddUncasted<HAdd>(key_index, graph()->GetConstant1());
1751 : Push(Add<HLoadKeyed>(number_string_cache, value_index, nullptr, nullptr,
1752 4806 : FAST_ELEMENTS, ALLOW_RETURN_HOLE));
1753 : }
1754 : if_found.Else();
1755 : {
1756 : // Cache miss, fallback to runtime.
1757 4806 : Add<HPushArguments>(object);
1758 : Push(Add<HCallRuntime>(
1759 : Runtime::FunctionForId(Runtime::kNumberToStringSkipCache),
1760 4806 : 1));
1761 : }
1762 4806 : if_found.End();
1763 :
1764 : return Pop();
1765 : }
1766 :
1767 17891 : HValue* HGraphBuilder::BuildToNumber(HValue* input) {
1768 27910 : if (input->type().IsTaggedNumber() ||
1769 18256 : input->representation().IsSpecialization()) {
1770 : return input;
1771 : }
1772 8237 : Callable callable = CodeFactory::ToNumber(isolate());
1773 8237 : HValue* stub = Add<HConstant>(callable.code());
1774 8237 : HValue* values[] = {input};
1775 : HCallWithDescriptor* instr = Add<HCallWithDescriptor>(
1776 8237 : stub, 0, callable.descriptor(), ArrayVector(values));
1777 : instr->set_type(HType::TaggedNumber());
1778 : return instr;
1779 : }
1780 :
1781 :
1782 744 : HValue* HGraphBuilder::BuildToObject(HValue* receiver) {
1783 : NoObservableSideEffectsScope scope(this);
1784 :
1785 : // Create a joinable continuation.
1786 : HIfContinuation wrap(graph()->CreateBasicBlock(),
1787 744 : graph()->CreateBasicBlock());
1788 :
1789 : // Determine the proper global constructor function required to wrap
1790 : // {receiver} into a JSValue, unless {receiver} is already a {JSReceiver}, in
1791 : // which case we just return it. Deopts to Runtime::kToObject if {receiver}
1792 : // is undefined or null.
1793 : IfBuilder receiver_is_smi(this);
1794 372 : receiver_is_smi.If<HIsSmiAndBranch>(receiver);
1795 372 : receiver_is_smi.Then();
1796 : {
1797 : // Use global Number function.
1798 372 : Push(Add<HConstant>(Context::NUMBER_FUNCTION_INDEX));
1799 : }
1800 : receiver_is_smi.Else();
1801 : {
1802 : // Determine {receiver} map and instance type.
1803 : HValue* receiver_map =
1804 372 : Add<HLoadNamedField>(receiver, nullptr, HObjectAccess::ForMap());
1805 : HValue* receiver_instance_type = Add<HLoadNamedField>(
1806 372 : receiver_map, nullptr, HObjectAccess::ForMapInstanceType());
1807 :
1808 : // First check whether {receiver} is already a spec object (fast case).
1809 : IfBuilder receiver_is_not_spec_object(this);
1810 : receiver_is_not_spec_object.If<HCompareNumericAndBranch>(
1811 : receiver_instance_type, Add<HConstant>(FIRST_JS_RECEIVER_TYPE),
1812 372 : Token::LT);
1813 372 : receiver_is_not_spec_object.Then();
1814 : {
1815 : // Load the constructor function index from the {receiver} map.
1816 : HValue* constructor_function_index = Add<HLoadNamedField>(
1817 : receiver_map, nullptr,
1818 372 : HObjectAccess::ForMapInObjectPropertiesOrConstructorFunctionIndex());
1819 :
1820 : // Check if {receiver} has a constructor (null and undefined have no
1821 : // constructors, so we deoptimize to the runtime to throw an exception).
1822 : IfBuilder constructor_function_index_is_invalid(this);
1823 : constructor_function_index_is_invalid.If<HCompareNumericAndBranch>(
1824 : constructor_function_index,
1825 372 : Add<HConstant>(Map::kNoConstructorFunctionIndex), Token::EQ);
1826 : constructor_function_index_is_invalid.ThenDeopt(
1827 : DeoptimizeReason::kUndefinedOrNullInToObject);
1828 372 : constructor_function_index_is_invalid.End();
1829 :
1830 : // Use the global constructor function.
1831 372 : Push(constructor_function_index);
1832 : }
1833 372 : receiver_is_not_spec_object.JoinContinuation(&wrap);
1834 : }
1835 372 : receiver_is_smi.JoinContinuation(&wrap);
1836 :
1837 : // Wrap the receiver if necessary.
1838 : IfBuilder if_wrap(this, &wrap);
1839 372 : if_wrap.Then();
1840 : {
1841 : // Grab the constructor function index.
1842 : HValue* constructor_index = Pop();
1843 :
1844 : // Load native context.
1845 372 : HValue* native_context = BuildGetNativeContext();
1846 :
1847 : // Determine the initial map for the global constructor.
1848 : HValue* constructor = Add<HLoadKeyed>(native_context, constructor_index,
1849 372 : nullptr, nullptr, FAST_ELEMENTS);
1850 : HValue* constructor_initial_map = Add<HLoadNamedField>(
1851 372 : constructor, nullptr, HObjectAccess::ForPrototypeOrInitialMap());
1852 : // Allocate and initialize a JSValue wrapper.
1853 : HValue* value =
1854 372 : BuildAllocate(Add<HConstant>(JSValue::kSize), HType::JSObject(),
1855 372 : JS_VALUE_TYPE, HAllocationMode());
1856 : Add<HStoreNamedField>(value, HObjectAccess::ForMap(),
1857 372 : constructor_initial_map);
1858 372 : HValue* empty_fixed_array = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex);
1859 : Add<HStoreNamedField>(value, HObjectAccess::ForPropertiesPointer(),
1860 372 : empty_fixed_array);
1861 : Add<HStoreNamedField>(value, HObjectAccess::ForElementsPointer(),
1862 372 : empty_fixed_array);
1863 : Add<HStoreNamedField>(value, HObjectAccess::ForObservableJSObjectOffset(
1864 : JSValue::kValueOffset),
1865 372 : receiver);
1866 372 : Push(value);
1867 : }
1868 : if_wrap.Else();
1869 372 : { Push(receiver); }
1870 372 : if_wrap.End();
1871 372 : return Pop();
1872 : }
1873 :
1874 :
1875 23997 : HAllocate* HGraphBuilder::BuildAllocate(
1876 : HValue* object_size,
1877 : HType type,
1878 : InstanceType instance_type,
1879 23997 : HAllocationMode allocation_mode) {
1880 : // Compute the effective allocation size.
1881 : HValue* size = object_size;
1882 23997 : if (allocation_mode.CreateAllocationMementos()) {
1883 7160 : size = AddUncasted<HAdd>(size, Add<HConstant>(AllocationMemento::kSize));
1884 : size->ClearFlag(HValue::kCanOverflow);
1885 : }
1886 :
1887 : // Perform the actual allocation.
1888 : HAllocate* object = Add<HAllocate>(
1889 : size, type, allocation_mode.GetPretenureMode(), instance_type,
1890 23997 : graph()->GetConstant0(), allocation_mode.feedback_site());
1891 :
1892 : // Setup the allocation memento.
1893 23997 : if (allocation_mode.CreateAllocationMementos()) {
1894 : BuildCreateAllocationMemento(
1895 7160 : object, object_size, allocation_mode.current_site());
1896 : }
1897 :
1898 23997 : return object;
1899 : }
1900 :
1901 :
1902 15446 : HValue* HGraphBuilder::BuildAddStringLengths(HValue* left_length,
1903 39162 : HValue* right_length) {
1904 : // Compute the combined string length and check against max string length.
1905 15446 : HValue* length = AddUncasted<HAdd>(left_length, right_length);
1906 : // Check that length <= kMaxLength <=> length < MaxLength + 1.
1907 15446 : HValue* max_length = Add<HConstant>(String::kMaxLength + 1);
1908 27312 : if (top_info()->IsStub() || !isolate()->IsStringLengthOverflowIntact()) {
1909 : // This is a mitigation for crbug.com/627934; the real fix
1910 : // will be to migrate the StringAddStub to TurboFan one day.
1911 : IfBuilder if_invalid(this);
1912 3596 : if_invalid.If<HCompareNumericAndBranch>(length, max_length, Token::GT);
1913 3596 : if_invalid.Then();
1914 : {
1915 : Add<HCallRuntime>(
1916 3596 : Runtime::FunctionForId(Runtime::kThrowInvalidStringLength), 0);
1917 : }
1918 3596 : if_invalid.End();
1919 : } else {
1920 11850 : graph()->MarkDependsOnStringLengthOverflow();
1921 11850 : Add<HBoundsCheck>(length, max_length);
1922 : }
1923 15446 : return length;
1924 : }
1925 :
1926 :
1927 15446 : HValue* HGraphBuilder::BuildCreateConsString(
1928 : HValue* length,
1929 : HValue* left,
1930 : HValue* right,
1931 61784 : HAllocationMode allocation_mode) {
1932 : // Determine the string instance types.
1933 15446 : HInstruction* left_instance_type = AddLoadStringInstanceType(left);
1934 15446 : HInstruction* right_instance_type = AddLoadStringInstanceType(right);
1935 :
1936 : // Allocate the cons string object. HAllocate does not care whether we
1937 : // pass CONS_STRING_TYPE or CONS_ONE_BYTE_STRING_TYPE here, so we just use
1938 : // CONS_STRING_TYPE here. Below we decide whether the cons string is
1939 : // one-byte or two-byte and set the appropriate map.
1940 : DCHECK(HAllocate::CompatibleInstanceTypes(CONS_STRING_TYPE,
1941 : CONS_ONE_BYTE_STRING_TYPE));
1942 15446 : HAllocate* result = BuildAllocate(Add<HConstant>(ConsString::kSize),
1943 : HType::String(), CONS_STRING_TYPE,
1944 15446 : allocation_mode);
1945 :
1946 : // Compute intersection and difference of instance types.
1947 : HValue* anded_instance_types = AddUncasted<HBitwise>(
1948 15446 : Token::BIT_AND, left_instance_type, right_instance_type);
1949 : HValue* xored_instance_types = AddUncasted<HBitwise>(
1950 15446 : Token::BIT_XOR, left_instance_type, right_instance_type);
1951 :
1952 : // We create a one-byte cons string if
1953 : // 1. both strings are one-byte, or
1954 : // 2. at least one of the strings is two-byte, but happens to contain only
1955 : // one-byte characters.
1956 : // To do this, we check
1957 : // 1. if both strings are one-byte, or if the one-byte data hint is set in
1958 : // both strings, or
1959 : // 2. if one of the strings has the one-byte data hint set and the other
1960 : // string is one-byte.
1961 : IfBuilder if_onebyte(this);
1962 : STATIC_ASSERT(kOneByteStringTag != 0);
1963 : STATIC_ASSERT(kOneByteDataHintMask != 0);
1964 : if_onebyte.If<HCompareNumericAndBranch>(
1965 : AddUncasted<HBitwise>(
1966 : Token::BIT_AND, anded_instance_types,
1967 : Add<HConstant>(static_cast<int32_t>(
1968 15446 : kStringEncodingMask | kOneByteDataHintMask))),
1969 15446 : graph()->GetConstant0(), Token::NE);
1970 15446 : if_onebyte.Or();
1971 : STATIC_ASSERT(kOneByteStringTag != 0 &&
1972 : kOneByteDataHintTag != 0 &&
1973 : kOneByteDataHintTag != kOneByteStringTag);
1974 : if_onebyte.If<HCompareNumericAndBranch>(
1975 : AddUncasted<HBitwise>(
1976 : Token::BIT_AND, xored_instance_types,
1977 : Add<HConstant>(static_cast<int32_t>(
1978 15446 : kOneByteStringTag | kOneByteDataHintTag))),
1979 : Add<HConstant>(static_cast<int32_t>(
1980 30892 : kOneByteStringTag | kOneByteDataHintTag)), Token::EQ);
1981 15446 : if_onebyte.Then();
1982 : {
1983 : // We can safely skip the write barrier for storing the map here.
1984 : Add<HStoreNamedField>(
1985 : result, HObjectAccess::ForMap(),
1986 15446 : Add<HConstant>(isolate()->factory()->cons_one_byte_string_map()));
1987 : }
1988 : if_onebyte.Else();
1989 : {
1990 : // We can safely skip the write barrier for storing the map here.
1991 : Add<HStoreNamedField>(
1992 : result, HObjectAccess::ForMap(),
1993 15446 : Add<HConstant>(isolate()->factory()->cons_string_map()));
1994 : }
1995 15446 : if_onebyte.End();
1996 :
1997 : // Initialize the cons string fields.
1998 : Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(),
1999 15446 : Add<HConstant>(String::kEmptyHashField));
2000 15446 : Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length);
2001 15446 : Add<HStoreNamedField>(result, HObjectAccess::ForConsStringFirst(), left);
2002 15446 : Add<HStoreNamedField>(result, HObjectAccess::ForConsStringSecond(), right);
2003 :
2004 : // Count the native string addition.
2005 15446 : AddIncrementCounter(isolate()->counters()->string_add_native());
2006 :
2007 15446 : return result;
2008 : }
2009 :
2010 :
2011 14320 : void HGraphBuilder::BuildCopySeqStringChars(HValue* src,
2012 : HValue* src_offset,
2013 : String::Encoding src_encoding,
2014 : HValue* dst,
2015 : HValue* dst_offset,
2016 : String::Encoding dst_encoding,
2017 14320 : HValue* length) {
2018 : DCHECK(dst_encoding != String::ONE_BYTE_ENCODING ||
2019 : src_encoding == String::ONE_BYTE_ENCODING);
2020 14320 : LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement);
2021 14320 : HValue* index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT);
2022 : {
2023 14320 : HValue* src_index = AddUncasted<HAdd>(src_offset, index);
2024 : HValue* value =
2025 14320 : AddUncasted<HSeqStringGetChar>(src_encoding, src, src_index);
2026 14320 : HValue* dst_index = AddUncasted<HAdd>(dst_offset, index);
2027 14320 : Add<HSeqStringSetChar>(dst_encoding, dst, dst_index, value);
2028 : }
2029 14320 : loop.EndBody();
2030 14320 : }
2031 :
2032 :
2033 3580 : HValue* HGraphBuilder::BuildObjectSizeAlignment(
2034 : HValue* unaligned_size, int header_size) {
2035 : DCHECK((header_size & kObjectAlignmentMask) == 0);
2036 : HValue* size = AddUncasted<HAdd>(
2037 : unaligned_size, Add<HConstant>(static_cast<int32_t>(
2038 3580 : header_size + kObjectAlignmentMask)));
2039 : size->ClearFlag(HValue::kCanOverflow);
2040 : return AddUncasted<HBitwise>(
2041 : Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>(
2042 3580 : ~kObjectAlignmentMask)));
2043 : }
2044 :
2045 :
2046 15446 : HValue* HGraphBuilder::BuildUncheckedStringAdd(
2047 : HValue* left,
2048 : HValue* right,
2049 46540 : HAllocationMode allocation_mode) {
2050 : // Determine the string lengths.
2051 15446 : HValue* left_length = AddLoadStringLength(left);
2052 15446 : HValue* right_length = AddLoadStringLength(right);
2053 :
2054 : // Compute the combined string length.
2055 15446 : HValue* length = BuildAddStringLengths(left_length, right_length);
2056 :
2057 : // Do some manual constant folding here.
2058 15446 : if (left_length->IsConstant()) {
2059 1965 : HConstant* c_left_length = HConstant::cast(left_length);
2060 : DCHECK_NE(0, c_left_length->Integer32Value());
2061 1965 : if (c_left_length->Integer32Value() + 1 >= ConsString::kMinLength) {
2062 : // The right string contains at least one character.
2063 1965 : return BuildCreateConsString(length, left, right, allocation_mode);
2064 : }
2065 13481 : } else if (right_length->IsConstant()) {
2066 9901 : HConstant* c_right_length = HConstant::cast(right_length);
2067 : DCHECK_NE(0, c_right_length->Integer32Value());
2068 9901 : if (c_right_length->Integer32Value() + 1 >= ConsString::kMinLength) {
2069 : // The left string contains at least one character.
2070 9901 : return BuildCreateConsString(length, left, right, allocation_mode);
2071 : }
2072 : }
2073 :
2074 : // Check if we should create a cons string.
2075 : IfBuilder if_createcons(this);
2076 : if_createcons.If<HCompareNumericAndBranch>(
2077 3580 : length, Add<HConstant>(ConsString::kMinLength), Token::GTE);
2078 3580 : if_createcons.And();
2079 : if_createcons.If<HCompareNumericAndBranch>(
2080 3580 : length, Add<HConstant>(ConsString::kMaxLength), Token::LTE);
2081 3580 : if_createcons.Then();
2082 : {
2083 : // Create a cons string.
2084 3580 : Push(BuildCreateConsString(length, left, right, allocation_mode));
2085 : }
2086 : if_createcons.Else();
2087 : {
2088 : // Determine the string instance types.
2089 3580 : HValue* left_instance_type = AddLoadStringInstanceType(left);
2090 3580 : HValue* right_instance_type = AddLoadStringInstanceType(right);
2091 :
2092 : // Compute union and difference of instance types.
2093 : HValue* ored_instance_types = AddUncasted<HBitwise>(
2094 3580 : Token::BIT_OR, left_instance_type, right_instance_type);
2095 : HValue* xored_instance_types = AddUncasted<HBitwise>(
2096 3580 : Token::BIT_XOR, left_instance_type, right_instance_type);
2097 :
2098 : // Check if both strings have the same encoding and both are
2099 : // sequential.
2100 : IfBuilder if_sameencodingandsequential(this);
2101 : if_sameencodingandsequential.If<HCompareNumericAndBranch>(
2102 : AddUncasted<HBitwise>(
2103 : Token::BIT_AND, xored_instance_types,
2104 3580 : Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))),
2105 3580 : graph()->GetConstant0(), Token::EQ);
2106 3580 : if_sameencodingandsequential.And();
2107 : STATIC_ASSERT(kSeqStringTag == 0);
2108 : if_sameencodingandsequential.If<HCompareNumericAndBranch>(
2109 : AddUncasted<HBitwise>(
2110 : Token::BIT_AND, ored_instance_types,
2111 3580 : Add<HConstant>(static_cast<int32_t>(kStringRepresentationMask))),
2112 3580 : graph()->GetConstant0(), Token::EQ);
2113 3580 : if_sameencodingandsequential.Then();
2114 : {
2115 : HConstant* string_map =
2116 3580 : Add<HConstant>(isolate()->factory()->string_map());
2117 : HConstant* one_byte_string_map =
2118 3580 : Add<HConstant>(isolate()->factory()->one_byte_string_map());
2119 :
2120 : // Determine map and size depending on whether result is one-byte string.
2121 : IfBuilder if_onebyte(this);
2122 : STATIC_ASSERT(kOneByteStringTag != 0);
2123 : if_onebyte.If<HCompareNumericAndBranch>(
2124 : AddUncasted<HBitwise>(
2125 : Token::BIT_AND, ored_instance_types,
2126 3580 : Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))),
2127 3580 : graph()->GetConstant0(), Token::NE);
2128 3580 : if_onebyte.Then();
2129 : {
2130 : // Allocate sequential one-byte string object.
2131 3580 : Push(length);
2132 3580 : Push(one_byte_string_map);
2133 : }
2134 : if_onebyte.Else();
2135 : {
2136 : // Allocate sequential two-byte string object.
2137 3580 : HValue* size = AddUncasted<HShl>(length, graph()->GetConstant1());
2138 : size->ClearFlag(HValue::kCanOverflow);
2139 : size->SetFlag(HValue::kUint32);
2140 3580 : Push(size);
2141 3580 : Push(string_map);
2142 : }
2143 3580 : if_onebyte.End();
2144 : HValue* map = Pop();
2145 :
2146 : // Calculate the number of bytes needed for the characters in the
2147 : // string while observing object alignment.
2148 : STATIC_ASSERT((SeqString::kHeaderSize & kObjectAlignmentMask) == 0);
2149 3580 : HValue* size = BuildObjectSizeAlignment(Pop(), SeqString::kHeaderSize);
2150 :
2151 : IfBuilder if_size(this);
2152 : if_size.If<HCompareNumericAndBranch>(
2153 3580 : size, Add<HConstant>(kMaxRegularHeapObjectSize), Token::LT);
2154 3580 : if_size.Then();
2155 : {
2156 : // Allocate the string object. HAllocate does not care whether we pass
2157 : // STRING_TYPE or ONE_BYTE_STRING_TYPE here, so we just use STRING_TYPE.
2158 : HAllocate* result =
2159 3580 : BuildAllocate(size, HType::String(), STRING_TYPE, allocation_mode);
2160 3580 : Add<HStoreNamedField>(result, HObjectAccess::ForMap(), map);
2161 :
2162 : // Initialize the string fields.
2163 : Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(),
2164 3580 : Add<HConstant>(String::kEmptyHashField));
2165 3580 : Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length);
2166 :
2167 : // Copy characters to the result string.
2168 : IfBuilder if_twobyte(this);
2169 3580 : if_twobyte.If<HCompareObjectEqAndBranch>(map, string_map);
2170 3580 : if_twobyte.Then();
2171 : {
2172 : // Copy characters from the left string.
2173 : BuildCopySeqStringChars(
2174 : left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, result,
2175 3580 : graph()->GetConstant0(), String::TWO_BYTE_ENCODING, left_length);
2176 :
2177 : // Copy characters from the right string.
2178 : BuildCopySeqStringChars(
2179 : right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, result,
2180 3580 : left_length, String::TWO_BYTE_ENCODING, right_length);
2181 : }
2182 : if_twobyte.Else();
2183 : {
2184 : // Copy characters from the left string.
2185 : BuildCopySeqStringChars(
2186 : left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, result,
2187 3580 : graph()->GetConstant0(), String::ONE_BYTE_ENCODING, left_length);
2188 :
2189 : // Copy characters from the right string.
2190 : BuildCopySeqStringChars(
2191 : right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, result,
2192 3580 : left_length, String::ONE_BYTE_ENCODING, right_length);
2193 : }
2194 3580 : if_twobyte.End();
2195 :
2196 : // Count the native string addition.
2197 3580 : AddIncrementCounter(isolate()->counters()->string_add_native());
2198 :
2199 : // Return the sequential string.
2200 3580 : Push(result);
2201 : }
2202 : if_size.Else();
2203 : {
2204 : // Fallback to the runtime to add the two strings. The string has to be
2205 : // allocated in LO space.
2206 3580 : Add<HPushArguments>(left, right);
2207 3580 : Push(Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kStringAdd), 2));
2208 : }
2209 3580 : if_size.End();
2210 : }
2211 : if_sameencodingandsequential.Else();
2212 : {
2213 : // Fallback to the runtime to add the two strings.
2214 3580 : Add<HPushArguments>(left, right);
2215 3580 : Push(Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kStringAdd), 2));
2216 : }
2217 3580 : if_sameencodingandsequential.End();
2218 : }
2219 3580 : if_createcons.End();
2220 :
2221 : return Pop();
2222 : }
2223 :
2224 :
2225 15446 : HValue* HGraphBuilder::BuildStringAdd(
2226 : HValue* left,
2227 : HValue* right,
2228 61784 : HAllocationMode allocation_mode) {
2229 : NoObservableSideEffectsScope no_effects(this);
2230 :
2231 : // Determine string lengths.
2232 15446 : HValue* left_length = AddLoadStringLength(left);
2233 15446 : HValue* right_length = AddLoadStringLength(right);
2234 :
2235 : // Check if left string is empty.
2236 : IfBuilder if_leftempty(this);
2237 : if_leftempty.If<HCompareNumericAndBranch>(
2238 15446 : left_length, graph()->GetConstant0(), Token::EQ);
2239 15446 : if_leftempty.Then();
2240 : {
2241 : // Count the native string addition.
2242 15446 : AddIncrementCounter(isolate()->counters()->string_add_native());
2243 :
2244 : // Just return the right string.
2245 15446 : Push(right);
2246 : }
2247 : if_leftempty.Else();
2248 : {
2249 : // Check if right string is empty.
2250 : IfBuilder if_rightempty(this);
2251 : if_rightempty.If<HCompareNumericAndBranch>(
2252 15446 : right_length, graph()->GetConstant0(), Token::EQ);
2253 15446 : if_rightempty.Then();
2254 : {
2255 : // Count the native string addition.
2256 15446 : AddIncrementCounter(isolate()->counters()->string_add_native());
2257 :
2258 : // Just return the left string.
2259 15446 : Push(left);
2260 : }
2261 : if_rightempty.Else();
2262 : {
2263 : // Add the two non-empty strings.
2264 15446 : Push(BuildUncheckedStringAdd(left, right, allocation_mode));
2265 : }
2266 15446 : if_rightempty.End();
2267 : }
2268 15446 : if_leftempty.End();
2269 :
2270 15446 : return Pop();
2271 : }
2272 :
2273 :
2274 27744 : HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
2275 : HValue* checked_object,
2276 : HValue* key,
2277 : HValue* val,
2278 : bool is_js_array,
2279 : ElementsKind elements_kind,
2280 : PropertyAccessType access_type,
2281 : LoadKeyedHoleMode load_mode,
2282 9272 : KeyedAccessStoreMode store_mode) {
2283 : DCHECK(top_info()->IsStub() || checked_object->IsCompareMap() ||
2284 : checked_object->IsCheckMaps());
2285 : DCHECK(!IsFixedTypedArrayElementsKind(elements_kind) || !is_js_array);
2286 : // No GVNFlag is necessary for ElementsKind if there is an explicit dependency
2287 : // on a HElementsTransition instruction. The flag can also be removed if the
2288 : // map to check has FAST_HOLEY_ELEMENTS, since there can be no further
2289 : // ElementsKind transitions. Finally, the dependency can be removed for stores
2290 : // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the
2291 : // generated store code.
2292 49767 : if ((elements_kind == FAST_HOLEY_ELEMENTS) ||
2293 22023 : (elements_kind == FAST_ELEMENTS && access_type == STORE)) {
2294 : checked_object->ClearDependsOnFlag(kElementsKind);
2295 : }
2296 :
2297 : bool fast_smi_only_elements = IsFastSmiElementsKind(elements_kind);
2298 : bool fast_elements = IsFastObjectElementsKind(elements_kind);
2299 : HValue* elements = AddLoadElements(checked_object);
2300 27744 : if (access_type == STORE && (fast_elements || fast_smi_only_elements) &&
2301 : store_mode != STORE_NO_TRANSITION_HANDLE_COW) {
2302 : HCheckMaps* check_cow_map = Add<HCheckMaps>(
2303 5843 : elements, isolate()->factory()->fixed_array_map());
2304 : check_cow_map->ClearDependsOnFlag(kElementsKind);
2305 : }
2306 : HInstruction* length = NULL;
2307 27744 : if (is_js_array) {
2308 : length = Add<HLoadNamedField>(
2309 : checked_object->ActualValue(), checked_object,
2310 23003 : HObjectAccess::ForArrayLength(elements_kind));
2311 : } else {
2312 : length = AddLoadFixedArrayLength(elements);
2313 : }
2314 : length->set_type(HType::Smi());
2315 : HValue* checked_key = NULL;
2316 27744 : if (IsFixedTypedArrayElementsKind(elements_kind)) {
2317 3897 : checked_object = Add<HCheckArrayBufferNotNeutered>(checked_object);
2318 :
2319 : HValue* external_pointer = Add<HLoadNamedField>(
2320 : elements, nullptr,
2321 3897 : HObjectAccess::ForFixedTypedArrayBaseExternalPointer());
2322 : HValue* base_pointer = Add<HLoadNamedField>(
2323 3897 : elements, nullptr, HObjectAccess::ForFixedTypedArrayBaseBasePointer());
2324 : HValue* backing_store = AddUncasted<HAdd>(external_pointer, base_pointer,
2325 3897 : AddOfExternalAndTagged);
2326 :
2327 3897 : if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
2328 : NoObservableSideEffectsScope no_effects(this);
2329 : IfBuilder length_checker(this);
2330 40 : length_checker.If<HCompareNumericAndBranch>(key, length, Token::LT);
2331 40 : length_checker.Then();
2332 : IfBuilder negative_checker(this);
2333 : HValue* bounds_check = negative_checker.If<HCompareNumericAndBranch>(
2334 40 : key, graph()->GetConstant0(), Token::GTE);
2335 40 : negative_checker.Then();
2336 : HInstruction* result = AddElementAccess(
2337 : backing_store, key, val, bounds_check, checked_object->ActualValue(),
2338 40 : elements_kind, access_type);
2339 40 : negative_checker.ElseDeopt(DeoptimizeReason::kNegativeKeyEncountered);
2340 40 : negative_checker.End();
2341 40 : length_checker.End();
2342 : return result;
2343 : } else {
2344 : DCHECK(store_mode == STANDARD_STORE);
2345 3857 : checked_key = Add<HBoundsCheck>(key, length);
2346 : return AddElementAccess(backing_store, checked_key, val, checked_object,
2347 : checked_object->ActualValue(), elements_kind,
2348 3857 : access_type);
2349 : }
2350 : }
2351 : DCHECK(fast_smi_only_elements ||
2352 : fast_elements ||
2353 : IsFastDoubleElementsKind(elements_kind));
2354 :
2355 : // In case val is stored into a fast smi array, assure that the value is a smi
2356 : // before manipulating the backing store. Otherwise the actual store may
2357 : // deopt, leaving the backing store in an invalid state.
2358 26007 : if (access_type == STORE && IsFastSmiElementsKind(elements_kind) &&
2359 : !val->type().IsSmi()) {
2360 1274 : val = AddUncasted<HForceRepresentation>(val, Representation::Smi());
2361 : }
2362 :
2363 23847 : if (IsGrowStoreMode(store_mode)) {
2364 : NoObservableSideEffectsScope no_effects(this);
2365 : Representation representation = HStoreKeyed::RequiredValueRepresentation(
2366 2606 : elements_kind, STORE_TO_INITIALIZED_ENTRY);
2367 2606 : val = AddUncasted<HForceRepresentation>(val, representation);
2368 : elements = BuildCheckForCapacityGrow(checked_object, elements,
2369 : elements_kind, length, key,
2370 2606 : is_js_array, access_type);
2371 : checked_key = key;
2372 : } else {
2373 21241 : checked_key = Add<HBoundsCheck>(key, length);
2374 :
2375 21241 : if (access_type == STORE && (fast_elements || fast_smi_only_elements)) {
2376 3507 : if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) {
2377 : NoObservableSideEffectsScope no_effects(this);
2378 : elements = BuildCopyElementsOnWrite(checked_object, elements,
2379 118 : elements_kind, length);
2380 : } else {
2381 : HCheckMaps* check_cow_map = Add<HCheckMaps>(
2382 3389 : elements, isolate()->factory()->fixed_array_map());
2383 : check_cow_map->ClearDependsOnFlag(kElementsKind);
2384 : }
2385 : }
2386 : }
2387 : return AddElementAccess(elements, checked_key, val, checked_object, nullptr,
2388 23847 : elements_kind, access_type, load_mode);
2389 : }
2390 :
2391 :
2392 544 : HValue* HGraphBuilder::BuildCalculateElementsSize(ElementsKind kind,
2393 1088 : HValue* capacity) {
2394 : int elements_size = IsFastDoubleElementsKind(kind)
2395 : ? kDoubleSize
2396 : : kPointerSize;
2397 :
2398 544 : HConstant* elements_size_value = Add<HConstant>(elements_size);
2399 : HInstruction* mul =
2400 544 : HMul::NewImul(isolate(), zone(), context(), capacity->ActualValue(),
2401 1632 : elements_size_value);
2402 544 : AddInstruction(mul);
2403 : mul->ClearFlag(HValue::kCanOverflow);
2404 :
2405 : STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize);
2406 :
2407 544 : HConstant* header_size = Add<HConstant>(FixedArray::kHeaderSize);
2408 544 : HValue* total_size = AddUncasted<HAdd>(mul, header_size);
2409 : total_size->ClearFlag(HValue::kCanOverflow);
2410 544 : return total_size;
2411 : }
2412 :
2413 :
2414 504 : HAllocate* HGraphBuilder::AllocateJSArrayObject(AllocationSiteMode mode) {
2415 : int base_size = JSArray::kSize;
2416 252 : if (mode == TRACK_ALLOCATION_SITE) {
2417 : base_size += AllocationMemento::kSize;
2418 : }
2419 252 : HConstant* size_in_bytes = Add<HConstant>(base_size);
2420 : return Add<HAllocate>(size_in_bytes, HType::JSArray(), NOT_TENURED,
2421 252 : JS_OBJECT_TYPE, graph()->GetConstant0());
2422 : }
2423 :
2424 :
2425 0 : HConstant* HGraphBuilder::EstablishElementsAllocationSize(
2426 : ElementsKind kind,
2427 : int capacity) {
2428 : int base_size = IsFastDoubleElementsKind(kind)
2429 : ? FixedDoubleArray::SizeFor(capacity)
2430 0 : : FixedArray::SizeFor(capacity);
2431 :
2432 0 : return Add<HConstant>(base_size);
2433 : }
2434 :
2435 :
2436 544 : HAllocate* HGraphBuilder::BuildAllocateElements(ElementsKind kind,
2437 544 : HValue* size_in_bytes) {
2438 : InstanceType instance_type = IsFastDoubleElementsKind(kind)
2439 : ? FIXED_DOUBLE_ARRAY_TYPE
2440 544 : : FIXED_ARRAY_TYPE;
2441 :
2442 : return Add<HAllocate>(size_in_bytes, HType::HeapObject(), NOT_TENURED,
2443 544 : instance_type, graph()->GetConstant0());
2444 : }
2445 :
2446 :
2447 2365 : void HGraphBuilder::BuildInitializeElementsHeader(HValue* elements,
2448 : ElementsKind kind,
2449 2365 : HValue* capacity) {
2450 : Factory* factory = isolate()->factory();
2451 : Handle<Map> map = IsFastDoubleElementsKind(kind)
2452 : ? factory->fixed_double_array_map()
2453 4730 : : factory->fixed_array_map();
2454 :
2455 2365 : Add<HStoreNamedField>(elements, HObjectAccess::ForMap(), Add<HConstant>(map));
2456 : Add<HStoreNamedField>(elements, HObjectAccess::ForFixedArrayLength(),
2457 2365 : capacity);
2458 2365 : }
2459 :
2460 :
2461 292 : HValue* HGraphBuilder::BuildAllocateAndInitializeArray(ElementsKind kind,
2462 : HValue* capacity) {
2463 : // The HForceRepresentation is to prevent possible deopt on int-smi
2464 : // conversion after allocation but before the new object fields are set.
2465 292 : capacity = AddUncasted<HForceRepresentation>(capacity, Representation::Smi());
2466 292 : HValue* size_in_bytes = BuildCalculateElementsSize(kind, capacity);
2467 292 : HValue* new_array = BuildAllocateElements(kind, size_in_bytes);
2468 292 : BuildInitializeElementsHeader(new_array, kind, capacity);
2469 292 : return new_array;
2470 : }
2471 :
2472 :
2473 252 : void HGraphBuilder::BuildJSArrayHeader(HValue* array,
2474 : HValue* array_map,
2475 : HValue* elements,
2476 : AllocationSiteMode mode,
2477 : ElementsKind elements_kind,
2478 : HValue* allocation_site_payload,
2479 : HValue* length_field) {
2480 252 : Add<HStoreNamedField>(array, HObjectAccess::ForMap(), array_map);
2481 :
2482 252 : HValue* empty_fixed_array = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex);
2483 :
2484 : Add<HStoreNamedField>(
2485 252 : array, HObjectAccess::ForPropertiesPointer(), empty_fixed_array);
2486 :
2487 : Add<HStoreNamedField>(array, HObjectAccess::ForElementsPointer(),
2488 252 : elements != nullptr ? elements : empty_fixed_array);
2489 :
2490 : Add<HStoreNamedField>(
2491 252 : array, HObjectAccess::ForArrayLength(elements_kind), length_field);
2492 :
2493 252 : if (mode == TRACK_ALLOCATION_SITE) {
2494 : BuildCreateAllocationMemento(
2495 0 : array, Add<HConstant>(JSArray::kSize), allocation_site_payload);
2496 : }
2497 252 : }
2498 :
2499 :
2500 28097 : HInstruction* HGraphBuilder::AddElementAccess(
2501 : HValue* elements, HValue* checked_key, HValue* val, HValue* dependency,
2502 : HValue* backing_store_owner, ElementsKind elements_kind,
2503 277 : PropertyAccessType access_type, LoadKeyedHoleMode load_mode) {
2504 28097 : if (access_type == STORE) {
2505 : DCHECK(val != NULL);
2506 8469 : if (elements_kind == UINT8_CLAMPED_ELEMENTS) {
2507 335 : val = Add<HClampToUint8>(val);
2508 : }
2509 : return Add<HStoreKeyed>(elements, checked_key, val, backing_store_owner,
2510 8469 : elements_kind, STORE_TO_INITIALIZED_ENTRY);
2511 : }
2512 :
2513 : DCHECK(access_type == LOAD);
2514 : DCHECK(val == NULL);
2515 : HLoadKeyed* load =
2516 : Add<HLoadKeyed>(elements, checked_key, dependency, backing_store_owner,
2517 19628 : elements_kind, load_mode);
2518 19628 : if (elements_kind == UINT32_ELEMENTS) {
2519 277 : graph()->RecordUint32Instruction(load);
2520 : }
2521 19628 : return load;
2522 : }
2523 :
2524 :
2525 0 : HLoadNamedField* HGraphBuilder::AddLoadMap(HValue* object,
2526 : HValue* dependency) {
2527 133 : return Add<HLoadNamedField>(object, dependency, HObjectAccess::ForMap());
2528 : }
2529 :
2530 :
2531 54 : HLoadNamedField* HGraphBuilder::AddLoadElements(HValue* object,
2532 : HValue* dependency) {
2533 : return Add<HLoadNamedField>(
2534 44676 : object, dependency, HObjectAccess::ForElementsPointer());
2535 : }
2536 :
2537 :
2538 54 : HLoadNamedField* HGraphBuilder::AddLoadFixedArrayLength(
2539 : HValue* array,
2540 : HValue* dependency) {
2541 : return Add<HLoadNamedField>(
2542 12967 : array, dependency, HObjectAccess::ForFixedArrayLength());
2543 : }
2544 :
2545 :
2546 170 : HLoadNamedField* HGraphBuilder::AddLoadArrayLength(HValue* array,
2547 : ElementsKind kind,
2548 : HValue* dependency) {
2549 : return Add<HLoadNamedField>(
2550 170 : array, dependency, HObjectAccess::ForArrayLength(kind));
2551 : }
2552 :
2553 :
2554 0 : HValue* HGraphBuilder::BuildNewElementsCapacity(HValue* old_capacity) {
2555 : HValue* half_old_capacity = AddUncasted<HShr>(old_capacity,
2556 0 : graph_->GetConstant1());
2557 :
2558 0 : HValue* new_capacity = AddUncasted<HAdd>(half_old_capacity, old_capacity);
2559 : new_capacity->ClearFlag(HValue::kCanOverflow);
2560 :
2561 0 : HValue* min_growth = Add<HConstant>(16);
2562 :
2563 0 : new_capacity = AddUncasted<HAdd>(new_capacity, min_growth);
2564 : new_capacity->ClearFlag(HValue::kCanOverflow);
2565 :
2566 0 : return new_capacity;
2567 : }
2568 :
2569 :
2570 292 : HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object,
2571 : HValue* elements,
2572 : ElementsKind kind,
2573 : ElementsKind new_kind,
2574 : HValue* length,
2575 : HValue* new_capacity) {
2576 : Add<HBoundsCheck>(
2577 : new_capacity,
2578 : Add<HConstant>((kMaxRegularHeapObjectSize - FixedArray::kHeaderSize) >>
2579 292 : ElementsKindToShiftSize(new_kind)));
2580 :
2581 : HValue* new_elements =
2582 292 : BuildAllocateAndInitializeArray(new_kind, new_capacity);
2583 :
2584 : BuildCopyElements(elements, kind, new_elements,
2585 292 : new_kind, length, new_capacity);
2586 :
2587 : Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
2588 292 : new_elements);
2589 :
2590 292 : return new_elements;
2591 : }
2592 :
2593 :
2594 544 : void HGraphBuilder::BuildFillElementsWithValue(HValue* elements,
2595 : ElementsKind elements_kind,
2596 : HValue* from,
2597 : HValue* to,
2598 544 : HValue* value) {
2599 544 : if (to == NULL) {
2600 : to = AddLoadFixedArrayLength(elements);
2601 : }
2602 :
2603 : // Special loop unfolding case
2604 : STATIC_ASSERT(JSArray::kPreallocatedArrayElements <=
2605 : kElementLoopUnrollThreshold);
2606 : int initial_capacity = -1;
2607 544 : if (from->IsInteger32Constant() && to->IsInteger32Constant()) {
2608 0 : int constant_from = from->GetInteger32Constant();
2609 0 : int constant_to = to->GetInteger32Constant();
2610 :
2611 0 : if (constant_from == 0 && constant_to <= kElementLoopUnrollThreshold) {
2612 : initial_capacity = constant_to;
2613 : }
2614 : }
2615 :
2616 544 : if (initial_capacity >= 0) {
2617 0 : for (int i = 0; i < initial_capacity; i++) {
2618 0 : HInstruction* key = Add<HConstant>(i);
2619 0 : Add<HStoreKeyed>(elements, key, value, nullptr, elements_kind);
2620 : }
2621 : } else {
2622 : // Carefully loop backwards so that the "from" remains live through the loop
2623 : // rather than the to. This often corresponds to keeping length live rather
2624 : // then capacity, which helps register allocation, since length is used more
2625 : // other than capacity after filling with holes.
2626 544 : LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement);
2627 :
2628 544 : HValue* key = builder.BeginBody(to, from, Token::GT);
2629 :
2630 544 : HValue* adjusted_key = AddUncasted<HSub>(key, graph()->GetConstant1());
2631 : adjusted_key->ClearFlag(HValue::kCanOverflow);
2632 :
2633 544 : Add<HStoreKeyed>(elements, adjusted_key, value, nullptr, elements_kind);
2634 :
2635 544 : builder.EndBody();
2636 : }
2637 544 : }
2638 :
2639 :
2640 544 : void HGraphBuilder::BuildFillElementsWithHole(HValue* elements,
2641 : ElementsKind elements_kind,
2642 : HValue* from,
2643 467 : HValue* to) {
2644 : // Fast elements kinds need to be initialized in case statements below cause a
2645 : // garbage collection.
2646 :
2647 : HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind)
2648 : ? graph()->GetConstantHole()
2649 1011 : : Add<HConstant>(HConstant::kHoleNaN);
2650 :
2651 : // Since we're about to store a hole value, the store instruction below must
2652 : // assume an elements kind that supports heap object values.
2653 544 : if (IsFastSmiOrObjectElementsKind(elements_kind)) {
2654 : elements_kind = FAST_HOLEY_ELEMENTS;
2655 : }
2656 :
2657 544 : BuildFillElementsWithValue(elements, elements_kind, from, to, hole);
2658 544 : }
2659 :
2660 :
2661 0 : void HGraphBuilder::BuildCopyProperties(HValue* from_properties,
2662 : HValue* to_properties, HValue* length,
2663 0 : HValue* capacity) {
2664 : ElementsKind kind = FAST_ELEMENTS;
2665 :
2666 : BuildFillElementsWithValue(to_properties, kind, length, capacity,
2667 0 : graph()->GetConstantUndefined());
2668 :
2669 0 : LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement);
2670 :
2671 0 : HValue* key = builder.BeginBody(length, graph()->GetConstant0(), Token::GT);
2672 :
2673 0 : key = AddUncasted<HSub>(key, graph()->GetConstant1());
2674 : key->ClearFlag(HValue::kCanOverflow);
2675 :
2676 : HValue* element =
2677 0 : Add<HLoadKeyed>(from_properties, key, nullptr, nullptr, kind);
2678 :
2679 0 : Add<HStoreKeyed>(to_properties, key, element, nullptr, kind);
2680 :
2681 0 : builder.EndBody();
2682 0 : }
2683 :
2684 :
2685 292 : void HGraphBuilder::BuildCopyElements(HValue* from_elements,
2686 : ElementsKind from_elements_kind,
2687 : HValue* to_elements,
2688 : ElementsKind to_elements_kind,
2689 : HValue* length,
2690 902 : HValue* capacity) {
2691 : int constant_capacity = -1;
2692 584 : if (capacity != NULL &&
2693 292 : capacity->IsConstant() &&
2694 0 : HConstant::cast(capacity)->HasInteger32Value()) {
2695 0 : int constant_candidate = HConstant::cast(capacity)->Integer32Value();
2696 0 : if (constant_candidate <= kElementLoopUnrollThreshold) {
2697 : constant_capacity = constant_candidate;
2698 : }
2699 : }
2700 :
2701 : bool pre_fill_with_holes =
2702 309 : IsFastDoubleElementsKind(from_elements_kind) &&
2703 : IsFastObjectElementsKind(to_elements_kind);
2704 292 : if (pre_fill_with_holes) {
2705 : // If the copy might trigger a GC, make sure that the FixedArray is
2706 : // pre-initialized with holes to make sure that it's always in a
2707 : // consistent state.
2708 : BuildFillElementsWithHole(to_elements, to_elements_kind,
2709 17 : graph()->GetConstant0(), NULL);
2710 : }
2711 :
2712 292 : if (constant_capacity != -1) {
2713 : // Unroll the loop for small elements kinds.
2714 0 : for (int i = 0; i < constant_capacity; i++) {
2715 0 : HValue* key_constant = Add<HConstant>(i);
2716 : HInstruction* value = Add<HLoadKeyed>(
2717 0 : from_elements, key_constant, nullptr, nullptr, from_elements_kind);
2718 : Add<HStoreKeyed>(to_elements, key_constant, value, nullptr,
2719 0 : to_elements_kind);
2720 : }
2721 : } else {
2722 584 : if (!pre_fill_with_holes &&
2723 275 : (capacity == NULL || !length->Equals(capacity))) {
2724 : BuildFillElementsWithHole(to_elements, to_elements_kind,
2725 275 : length, NULL);
2726 : }
2727 :
2728 292 : LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement);
2729 :
2730 : HValue* key = builder.BeginBody(length, graph()->GetConstant0(),
2731 292 : Token::GT);
2732 :
2733 292 : key = AddUncasted<HSub>(key, graph()->GetConstant1());
2734 : key->ClearFlag(HValue::kCanOverflow);
2735 :
2736 : HValue* element = Add<HLoadKeyed>(from_elements, key, nullptr, nullptr,
2737 292 : from_elements_kind, ALLOW_RETURN_HOLE);
2738 :
2739 108 : ElementsKind kind = (IsHoleyElementsKind(from_elements_kind) &&
2740 : IsFastSmiElementsKind(to_elements_kind))
2741 523 : ? FAST_HOLEY_ELEMENTS : to_elements_kind;
2742 :
2743 292 : if (IsHoleyElementsKind(from_elements_kind) &&
2744 : from_elements_kind != to_elements_kind) {
2745 : IfBuilder if_hole(this);
2746 33 : if_hole.If<HCompareHoleAndBranch>(element);
2747 33 : if_hole.Then();
2748 : HConstant* hole_constant = IsFastDoubleElementsKind(to_elements_kind)
2749 : ? Add<HConstant>(HConstant::kHoleNaN)
2750 42 : : graph()->GetConstantHole();
2751 33 : Add<HStoreKeyed>(to_elements, key, hole_constant, nullptr, kind);
2752 : if_hole.Else();
2753 : HStoreKeyed* store =
2754 33 : Add<HStoreKeyed>(to_elements, key, element, nullptr, kind);
2755 : store->SetFlag(HValue::kTruncatingToNumber);
2756 33 : if_hole.End();
2757 : } else {
2758 : HStoreKeyed* store =
2759 259 : Add<HStoreKeyed>(to_elements, key, element, nullptr, kind);
2760 : store->SetFlag(HValue::kTruncatingToNumber);
2761 : }
2762 :
2763 292 : builder.EndBody();
2764 : }
2765 :
2766 292 : Counters* counters = isolate()->counters();
2767 292 : AddIncrementCounter(counters->inlined_copied_elements());
2768 292 : }
2769 :
2770 7160 : void HGraphBuilder::BuildCreateAllocationMemento(
2771 : HValue* previous_object,
2772 : HValue* previous_object_size,
2773 14320 : HValue* allocation_site) {
2774 : DCHECK(allocation_site != NULL);
2775 : HInnerAllocatedObject* allocation_memento = Add<HInnerAllocatedObject>(
2776 7160 : previous_object, previous_object_size, HType::HeapObject());
2777 : AddStoreMapConstant(
2778 7160 : allocation_memento, isolate()->factory()->allocation_memento_map());
2779 : Add<HStoreNamedField>(
2780 : allocation_memento,
2781 : HObjectAccess::ForAllocationMementoSite(),
2782 7160 : allocation_site);
2783 7160 : if (FLAG_allocation_site_pretenuring) {
2784 : HValue* memento_create_count =
2785 : Add<HLoadNamedField>(allocation_site, nullptr,
2786 : HObjectAccess::ForAllocationSiteOffset(
2787 7160 : AllocationSite::kPretenureCreateCountOffset));
2788 : memento_create_count = AddUncasted<HAdd>(
2789 7160 : memento_create_count, graph()->GetConstant1());
2790 : // This smi value is reset to zero after every gc, overflow isn't a problem
2791 : // since the counter is bounded by the new space size.
2792 : memento_create_count->ClearFlag(HValue::kCanOverflow);
2793 : Add<HStoreNamedField>(
2794 : allocation_site, HObjectAccess::ForAllocationSiteOffset(
2795 7160 : AllocationSite::kPretenureCreateCountOffset), memento_create_count);
2796 : }
2797 7160 : }
2798 :
2799 :
2800 11513 : HInstruction* HGraphBuilder::BuildGetNativeContext() {
2801 : return Add<HLoadNamedField>(
2802 11513 : context(), nullptr,
2803 23026 : HObjectAccess::ForContextSlot(Context::NATIVE_CONTEXT_INDEX));
2804 : }
2805 :
2806 146 : HValue* HGraphBuilder::BuildArrayBufferViewFieldAccessor(HValue* object,
2807 : HValue* checked_object,
2808 292 : FieldIndex index) {
2809 : NoObservableSideEffectsScope scope(this);
2810 : HObjectAccess access = HObjectAccess::ForObservableJSObjectOffset(
2811 146 : index.offset(), Representation::Tagged());
2812 : HInstruction* buffer = Add<HLoadNamedField>(
2813 146 : object, checked_object, HObjectAccess::ForJSArrayBufferViewBuffer());
2814 146 : HInstruction* field = Add<HLoadNamedField>(object, checked_object, access);
2815 :
2816 : HInstruction* flags = Add<HLoadNamedField>(
2817 146 : buffer, nullptr, HObjectAccess::ForJSArrayBufferBitField());
2818 : HValue* was_neutered_mask =
2819 146 : Add<HConstant>(1 << JSArrayBuffer::WasNeutered::kShift);
2820 : HValue* was_neutered_test =
2821 146 : AddUncasted<HBitwise>(Token::BIT_AND, flags, was_neutered_mask);
2822 :
2823 : IfBuilder if_was_neutered(this);
2824 : if_was_neutered.If<HCompareNumericAndBranch>(
2825 146 : was_neutered_test, graph()->GetConstant0(), Token::NE);
2826 146 : if_was_neutered.Then();
2827 146 : Push(graph()->GetConstant0());
2828 : if_was_neutered.Else();
2829 146 : Push(field);
2830 146 : if_was_neutered.End();
2831 :
2832 146 : return Pop();
2833 : }
2834 :
2835 1319565 : HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info,
2836 : bool track_positions)
2837 : : HGraphBuilder(info, CallInterfaceDescriptor(), track_positions),
2838 : function_state_(NULL),
2839 : initial_function_state_(this, info, NORMAL_RETURN, -1,
2840 : TailCallMode::kAllow),
2841 : ast_context_(NULL),
2842 : break_scope_(NULL),
2843 : inlined_count_(0),
2844 : globals_(10, info->zone()),
2845 : osr_(new (info->zone()) HOsrBuilder(this)),
2846 791739 : bounds_(info->zone()) {
2847 : // This is not initialized in the initializer list because the
2848 : // constructor for the initial state relies on function_state_ == NULL
2849 : // to know it's the initial state.
2850 263913 : function_state_ = &initial_function_state_;
2851 : InitializeAstVisitor(info->isolate());
2852 263913 : }
2853 :
2854 :
2855 467857 : HBasicBlock* HOptimizedGraphBuilder::CreateJoin(HBasicBlock* first,
2856 : HBasicBlock* second,
2857 : BailoutId join_id) {
2858 467857 : if (first == NULL) {
2859 : return second;
2860 189186 : } else if (second == NULL) {
2861 : return first;
2862 : } else {
2863 188350 : HBasicBlock* join_block = graph()->CreateBasicBlock();
2864 : Goto(first, join_block);
2865 : Goto(second, join_block);
2866 : join_block->SetJoinId(join_id);
2867 : return join_block;
2868 : }
2869 : }
2870 :
2871 45361 : HBasicBlock* HOptimizedGraphBuilder::JoinContinue(IterationStatement* statement,
2872 : BailoutId continue_id,
2873 : HBasicBlock* exit_block,
2874 : HBasicBlock* continue_block) {
2875 45361 : if (continue_block != NULL) {
2876 676 : if (exit_block != NULL) Goto(exit_block, continue_block);
2877 : continue_block->SetJoinId(continue_id);
2878 : return continue_block;
2879 : }
2880 : return exit_block;
2881 : }
2882 :
2883 :
2884 45312 : HBasicBlock* HOptimizedGraphBuilder::CreateLoop(IterationStatement* statement,
2885 : HBasicBlock* loop_entry,
2886 : HBasicBlock* body_exit,
2887 : HBasicBlock* loop_successor,
2888 : HBasicBlock* break_block) {
2889 45312 : if (body_exit != NULL) Goto(body_exit, loop_entry);
2890 45312 : loop_entry->PostProcessLoopHeader(statement);
2891 45312 : if (break_block != NULL) {
2892 1904 : if (loop_successor != NULL) Goto(loop_successor, break_block);
2893 : break_block->SetJoinId(statement->ExitId());
2894 : return break_block;
2895 : }
2896 : return loop_successor;
2897 : }
2898 :
2899 :
2900 : // Build a new loop header block and set it as the current block.
2901 45652 : HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry() {
2902 45652 : HBasicBlock* loop_entry = CreateLoopHeaderBlock();
2903 : Goto(loop_entry);
2904 : set_current_block(loop_entry);
2905 45652 : return loop_entry;
2906 : }
2907 :
2908 :
2909 45652 : HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry(
2910 50528 : IterationStatement* statement) {
2911 : HBasicBlock* loop_entry;
2912 :
2913 45652 : if (osr()->HasOsrEntryAt(statement)) {
2914 2438 : loop_entry = osr()->BuildOsrLoopEntry(statement);
2915 2438 : if (function_state()->IsInsideDoExpressionScope()) {
2916 : Bailout(kDoExpressionUnmodelable);
2917 : }
2918 : } else {
2919 43214 : loop_entry = BuildLoopEntry();
2920 : }
2921 45652 : return loop_entry;
2922 : }
2923 :
2924 :
2925 0 : void HBasicBlock::FinishExit(HControlInstruction* instruction,
2926 : SourcePosition position) {
2927 358204 : Finish(instruction, position);
2928 : ClearEnvironment();
2929 0 : }
2930 :
2931 :
2932 0 : std::ostream& operator<<(std::ostream& os, const HBasicBlock& b) {
2933 0 : return os << "B" << b.block_id();
2934 : }
2935 :
2936 1437230 : HGraph::HGraph(CompilationInfo* info, CallInterfaceDescriptor descriptor)
2937 : : isolate_(info->isolate()),
2938 : next_block_id_(0),
2939 : entry_block_(NULL),
2940 : blocks_(8, info->zone()),
2941 : values_(16, info->zone()),
2942 : phi_list_(NULL),
2943 : uint32_instructions_(NULL),
2944 : osr_(NULL),
2945 : info_(info),
2946 : descriptor_(descriptor),
2947 : zone_(info->zone()),
2948 : allow_code_motion_(false),
2949 : use_optimistic_licm_(false),
2950 : depends_on_empty_array_proto_elements_(false),
2951 : depends_on_string_length_overflow_(false),
2952 : type_change_checksum_(0),
2953 : maximum_environment_size_(0),
2954 : no_side_effects_scope_count_(0),
2955 1437230 : disallow_adding_new_values_(false) {
2956 287446 : if (info->IsStub()) {
2957 : // For stubs, explicitly add the context to the environment.
2958 : start_environment_ =
2959 47066 : new (zone_) HEnvironment(zone_, descriptor.GetParameterCount() + 1);
2960 : } else {
2961 : start_environment_ =
2962 527826 : new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_);
2963 : }
2964 287446 : start_environment_->set_ast_id(BailoutId::FunctionContext());
2965 287446 : entry_block_ = CreateBasicBlock();
2966 287446 : entry_block_->SetInitialEnvironment(start_environment_);
2967 287446 : }
2968 :
2969 :
2970 9245380 : HBasicBlock* HGraph::CreateBasicBlock() {
2971 4622691 : HBasicBlock* result = new(zone()) HBasicBlock(this);
2972 : blocks_.Add(result, zone());
2973 4622690 : return result;
2974 : }
2975 :
2976 :
2977 283794 : void HGraph::FinalizeUniqueness() {
2978 : DisallowHeapAllocation no_gc;
2979 4805881 : for (int i = 0; i < blocks()->length(); ++i) {
2980 38674578 : for (HInstructionIterator it(blocks()->at(i)); !it.Done(); it.Advance()) {
2981 29630404 : it.Current()->FinalizeUniqueness();
2982 : }
2983 : }
2984 283794 : }
2985 :
2986 :
2987 : // Block ordering was implemented with two mutually recursive methods,
2988 : // HGraph::Postorder and HGraph::PostorderLoopBlocks.
2989 : // The recursion could lead to stack overflow so the algorithm has been
2990 : // implemented iteratively.
2991 : // At a high level the algorithm looks like this:
2992 : //
2993 : // Postorder(block, loop_header) : {
2994 : // if (block has already been visited or is of another loop) return;
2995 : // mark block as visited;
2996 : // if (block is a loop header) {
2997 : // VisitLoopMembers(block, loop_header);
2998 : // VisitSuccessorsOfLoopHeader(block);
2999 : // } else {
3000 : // VisitSuccessors(block)
3001 : // }
3002 : // put block in result list;
3003 : // }
3004 : //
3005 : // VisitLoopMembers(block, outer_loop_header) {
3006 : // foreach (block b in block loop members) {
3007 : // VisitSuccessorsOfLoopMember(b, outer_loop_header);
3008 : // if (b is loop header) VisitLoopMembers(b);
3009 : // }
3010 : // }
3011 : //
3012 : // VisitSuccessorsOfLoopMember(block, outer_loop_header) {
3013 : // foreach (block b in block successors) Postorder(b, outer_loop_header)
3014 : // }
3015 : //
3016 : // VisitSuccessorsOfLoopHeader(block) {
3017 : // foreach (block b in block successors) Postorder(b, block)
3018 : // }
3019 : //
3020 : // VisitSuccessors(block, loop_header) {
3021 : // foreach (block b in block successors) Postorder(b, loop_header)
3022 : // }
3023 : //
3024 : // The ordering is started calling Postorder(entry, NULL).
3025 : //
3026 : // Each instance of PostorderProcessor represents the "stack frame" of the
3027 : // recursion, and particularly keeps the state of the loop (iteration) of the
3028 : // "Visit..." function it represents.
3029 : // To recycle memory we keep all the frames in a double linked list but
3030 : // this means that we cannot use constructors to initialize the frames.
3031 : //
3032 : class PostorderProcessor : public ZoneObject {
3033 : public:
3034 : // Back link (towards the stack bottom).
3035 : PostorderProcessor* parent() {return father_; }
3036 : // Forward link (towards the stack top).
3037 : PostorderProcessor* child() {return child_; }
3038 : HBasicBlock* block() { return block_; }
3039 : HLoopInformation* loop() { return loop_; }
3040 : HBasicBlock* loop_header() { return loop_header_; }
3041 :
3042 283776 : static PostorderProcessor* CreateEntryProcessor(Zone* zone,
3043 : HBasicBlock* block) {
3044 : PostorderProcessor* result = new(zone) PostorderProcessor(NULL);
3045 283776 : return result->SetupSuccessors(zone, block, NULL);
3046 : }
3047 :
3048 7790289 : PostorderProcessor* PerformStep(Zone* zone,
3049 : ZoneList<HBasicBlock*>* order) {
3050 : PostorderProcessor* next =
3051 7790289 : PerformNonBacktrackingStep(zone, order);
3052 7790289 : if (next != NULL) {
3053 : return next;
3054 : } else {
3055 2608903 : return Backtrack(zone, order);
3056 : }
3057 : }
3058 :
3059 : private:
3060 : explicit PostorderProcessor(PostorderProcessor* father)
3061 1951557 : : father_(father), child_(NULL), successor_iterator(NULL) { }
3062 :
3063 : // Each enum value states the cycle whose state is kept by this instance.
3064 : enum LoopKind {
3065 : NONE,
3066 : SUCCESSORS,
3067 : SUCCESSORS_OF_LOOP_HEADER,
3068 : LOOP_MEMBERS,
3069 : SUCCESSORS_OF_LOOP_MEMBER
3070 : };
3071 :
3072 : // Each "Setup..." method is like a constructor for a cycle state.
3073 6749212 : PostorderProcessor* SetupSuccessors(Zone* zone,
3074 5768018 : HBasicBlock* block,
3075 : HBasicBlock* loop_header) {
3076 19206365 : if (block == NULL || block->IsOrdered() ||
3077 : block->parent_loop_header() != loop_header) {
3078 2227254 : kind_ = NONE;
3079 2227254 : block_ = NULL;
3080 2227254 : loop_ = NULL;
3081 2227254 : loop_header_ = NULL;
3082 2227254 : return this;
3083 : } else {
3084 4521958 : block_ = block;
3085 4521958 : loop_ = NULL;
3086 : block->MarkAsOrdered();
3087 :
3088 4521958 : if (block->IsLoopHeader()) {
3089 60058 : kind_ = SUCCESSORS_OF_LOOP_HEADER;
3090 60058 : loop_header_ = block;
3091 : InitializeSuccessors();
3092 60058 : PostorderProcessor* result = Push(zone);
3093 : return result->SetupLoopMembers(zone, block, block->loop_information(),
3094 60058 : loop_header);
3095 : } else {
3096 : DCHECK(block->IsFinished());
3097 4461900 : kind_ = SUCCESSORS;
3098 4461900 : loop_header_ = loop_header;
3099 : InitializeSuccessors();
3100 4461900 : return this;
3101 : }
3102 : }
3103 : }
3104 :
3105 : PostorderProcessor* SetupLoopMembers(Zone* zone,
3106 : HBasicBlock* block,
3107 : HLoopInformation* loop,
3108 : HBasicBlock* loop_header) {
3109 69184 : kind_ = LOOP_MEMBERS;
3110 60058 : block_ = block;
3111 69184 : loop_ = loop;
3112 60058 : loop_header_ = loop_header;
3113 : InitializeLoopMembers();
3114 : return this;
3115 : }
3116 :
3117 : PostorderProcessor* SetupSuccessorsOfLoopMember(
3118 : HBasicBlock* block,
3119 : HLoopInformation* loop,
3120 : HBasicBlock* loop_header) {
3121 1041077 : kind_ = SUCCESSORS_OF_LOOP_MEMBER;
3122 1041077 : block_ = block;
3123 1041077 : loop_ = loop;
3124 1041077 : loop_header_ = loop_header;
3125 : InitializeSuccessors();
3126 : return this;
3127 : }
3128 :
3129 : // This method "allocates" a new stack frame.
3130 7566576 : PostorderProcessor* Push(Zone* zone) {
3131 7566576 : if (child_ == NULL) {
3132 1667781 : child_ = new(zone) PostorderProcessor(this);
3133 : }
3134 7566567 : return child_;
3135 : }
3136 :
3137 : void ClosePostorder(ZoneList<HBasicBlock*>* order, Zone* zone) {
3138 : DCHECK(block_->end()->FirstSuccessor() == NULL ||
3139 : order->Contains(block_->end()->FirstSuccessor()) ||
3140 : block_->end()->FirstSuccessor()->IsLoopHeader());
3141 : DCHECK(block_->end()->SecondSuccessor() == NULL ||
3142 : order->Contains(block_->end()->SecondSuccessor()) ||
3143 : block_->end()->SecondSuccessor()->IsLoopHeader());
3144 4521969 : order->Add(block_, zone);
3145 : }
3146 :
3147 : // This method is the basic block to walk up the stack.
3148 7859484 : PostorderProcessor* Pop(Zone* zone,
3149 1041077 : ZoneList<HBasicBlock*>* order) {
3150 7859484 : switch (kind_) {
3151 : case SUCCESSORS:
3152 : case SUCCESSORS_OF_LOOP_HEADER:
3153 : ClosePostorder(order, zone);
3154 4521968 : return father_;
3155 : case LOOP_MEMBERS:
3156 69184 : return father_;
3157 : case SUCCESSORS_OF_LOOP_MEMBER:
3158 1041077 : if (block()->IsLoopHeader() && block() != loop_->loop_header()) {
3159 : // In this case we need to perform a LOOP_MEMBERS cycle so we
3160 : // initialize it and return this instead of father.
3161 : return SetupLoopMembers(zone, block(),
3162 9126 : block()->loop_information(), loop_header_);
3163 : } else {
3164 1031951 : return father_;
3165 : }
3166 : case NONE:
3167 2227254 : return father_;
3168 : }
3169 0 : UNREACHABLE();
3170 : return NULL;
3171 : }
3172 :
3173 : // Walks up the stack.
3174 2608903 : PostorderProcessor* Backtrack(Zone* zone,
3175 : ZoneList<HBasicBlock*>* order) {
3176 2608903 : PostorderProcessor* parent = Pop(zone, order);
3177 10468383 : while (parent != NULL) {
3178 : PostorderProcessor* next =
3179 7575702 : parent->PerformNonBacktrackingStep(zone, order);
3180 7575701 : if (next != NULL) {
3181 : return next;
3182 : } else {
3183 5250584 : parent = parent->Pop(zone, order);
3184 : }
3185 : }
3186 : return NULL;
3187 : }
3188 :
3189 15365963 : PostorderProcessor* PerformNonBacktrackingStep(
3190 : Zone* zone,
3191 111916 : ZoneList<HBasicBlock*>* order) {
3192 : HBasicBlock* next_block;
3193 15365963 : switch (kind_) {
3194 : case SUCCESSORS:
3195 9473624 : next_block = AdvanceSuccessors();
3196 9473629 : if (next_block != NULL) {
3197 5011743 : PostorderProcessor* result = Push(zone);
3198 5011725 : return result->SetupSuccessors(zone, next_block, loop_header_);
3199 : }
3200 : break;
3201 : case SUCCESSORS_OF_LOOP_HEADER:
3202 171974 : next_block = AdvanceSuccessors();
3203 171974 : if (next_block != NULL) {
3204 111916 : PostorderProcessor* result = Push(zone);
3205 111916 : return result->SetupSuccessors(zone, next_block, block());
3206 : }
3207 : break;
3208 : case LOOP_MEMBERS:
3209 : next_block = AdvanceLoopMembers();
3210 1110261 : if (next_block != NULL) {
3211 1041077 : PostorderProcessor* result = Push(zone);
3212 : return result->SetupSuccessorsOfLoopMember(next_block,
3213 2082154 : loop_, loop_header_);
3214 : }
3215 : break;
3216 : case SUCCESSORS_OF_LOOP_MEMBER:
3217 2382863 : next_block = AdvanceSuccessors();
3218 2382863 : if (next_block != NULL) {
3219 1341786 : PostorderProcessor* result = Push(zone);
3220 1341786 : return result->SetupSuccessors(zone, next_block, loop_header_);
3221 : }
3222 : break;
3223 : case NONE:
3224 : return NULL;
3225 : }
3226 : return NULL;
3227 : }
3228 :
3229 : // The following two methods implement a "foreach b in successors" cycle.
3230 : void InitializeSuccessors() {
3231 5563035 : loop_index = 0;
3232 5563035 : loop_length = 0;
3233 5563035 : successor_iterator = HSuccessorIterator(block_->end());
3234 : }
3235 :
3236 12028460 : HBasicBlock* AdvanceSuccessors() {
3237 24056926 : if (!successor_iterator.Done()) {
3238 : HBasicBlock* result = successor_iterator.Current();
3239 : successor_iterator.Advance();
3240 6465438 : return result;
3241 : }
3242 : return NULL;
3243 : }
3244 :
3245 : // The following two methods implement a "foreach b in loop members" cycle.
3246 : void InitializeLoopMembers() {
3247 69184 : loop_index = 0;
3248 69184 : loop_length = loop_->blocks()->length();
3249 : }
3250 :
3251 : HBasicBlock* AdvanceLoopMembers() {
3252 1110261 : if (loop_index < loop_length) {
3253 2082154 : HBasicBlock* result = loop_->blocks()->at(loop_index);
3254 1041077 : loop_index++;
3255 : return result;
3256 : } else {
3257 : return NULL;
3258 : }
3259 : }
3260 :
3261 : LoopKind kind_;
3262 : PostorderProcessor* father_;
3263 : PostorderProcessor* child_;
3264 : HLoopInformation* loop_;
3265 : HBasicBlock* block_;
3266 : HBasicBlock* loop_header_;
3267 : int loop_index;
3268 : int loop_length;
3269 : HSuccessorIterator successor_iterator;
3270 : };
3271 :
3272 :
3273 8357838 : void HGraph::OrderBlocks() {
3274 283775 : CompilationPhase phase("H_Block ordering", info());
3275 :
3276 : #ifdef DEBUG
3277 : // Initially the blocks must not be ordered.
3278 : for (int i = 0; i < blocks_.length(); ++i) {
3279 : DCHECK(!blocks_[i]->IsOrdered());
3280 : }
3281 : #endif
3282 :
3283 : PostorderProcessor* postorder =
3284 7966154 : PostorderProcessor::CreateEntryProcessor(zone(), blocks_[0]);
3285 : blocks_.Rewind(0);
3286 8074065 : while (postorder) {
3287 15580574 : postorder = postorder->PerformStep(zone(), &blocks_);
3288 : }
3289 :
3290 : #ifdef DEBUG
3291 : // Now all blocks must be marked as ordered.
3292 : for (int i = 0; i < blocks_.length(); ++i) {
3293 : DCHECK(blocks_[i]->IsOrdered());
3294 : }
3295 : #endif
3296 :
3297 : // Reverse block list and assign block IDs.
3298 2655386 : for (int i = 0, j = blocks_.length(); --j >= i; ++i) {
3299 2371608 : HBasicBlock* bi = blocks_[i];
3300 2371608 : HBasicBlock* bj = blocks_[j];
3301 : bi->set_block_id(j);
3302 : bj->set_block_id(i);
3303 2371608 : blocks_[i] = bj;
3304 2371608 : blocks_[j] = bi;
3305 283778 : }
3306 283778 : }
3307 :
3308 :
3309 283777 : void HGraph::AssignDominators() {
3310 : HPhase phase("H_Assign dominators", this);
3311 9611500 : for (int i = 0; i < blocks_.length(); ++i) {
3312 18853240 : HBasicBlock* block = blocks_[i];
3313 4521972 : if (block->IsLoopHeader()) {
3314 : // Only the first predecessor of a loop header is from outside the loop.
3315 : // All others are back edges, and thus cannot dominate the loop header.
3316 60058 : block->AssignCommonDominator(block->predecessors()->first());
3317 60058 : block->AssignLoopSuccessorDominators();
3318 : } else {
3319 9465456 : for (int j = blocks_[i]->predecessors()->length() - 1; j >= 0; --j) {
3320 10007092 : blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j));
3321 : }
3322 : }
3323 283778 : }
3324 283776 : }
3325 :
3326 :
3327 283734 : bool HGraph::CheckArgumentsPhiUses() {
3328 5096410 : int block_count = blocks_.length();
3329 4795484 : for (int i = 0; i < block_count; ++i) {
3330 5113597 : for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
3331 300926 : HPhi* phi = blocks_[i]->phis()->at(j);
3332 : // We don't support phi uses of arguments for now.
3333 601852 : if (phi->CheckFlag(HValue::kIsArguments)) return false;
3334 : }
3335 : }
3336 : return true;
3337 : }
3338 :
3339 :
3340 283777 : bool HGraph::CheckConstPhiUses() {
3341 5462039 : int block_count = blocks_.length();
3342 4797441 : for (int i = 0; i < block_count; ++i) {
3343 5842817 : for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
3344 664598 : HPhi* phi = blocks_[i]->phis()->at(j);
3345 : // Check for the hole value (from an uninitialized const).
3346 4007912 : for (int k = 0; k < phi->OperandCount(); k++) {
3347 1339401 : if (phi->OperandAt(k) == GetConstantHole()) return false;
3348 : }
3349 : }
3350 : }
3351 : return true;
3352 : }
3353 :
3354 :
3355 884286 : void HGraph::CollectPhis() {
3356 5112268 : int block_count = blocks_.length();
3357 283730 : phi_list_ = new(zone()) ZoneList<HPhi*>(block_count, zone());
3358 4795445 : for (int i = 0; i < block_count; ++i) {
3359 5145361 : for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
3360 316826 : HPhi* phi = blocks_[i]->phis()->at(j);
3361 316826 : phi_list_->Add(phi, zone());
3362 : }
3363 : }
3364 283730 : }
3365 :
3366 :
3367 : // Implementation of utility class to encapsulate the translation state for
3368 : // a (possibly inlined) function.
3369 976955 : FunctionState::FunctionState(HOptimizedGraphBuilder* owner,
3370 : CompilationInfo* info, InliningKind inlining_kind,
3371 : int inlining_id, TailCallMode tail_call_mode)
3372 : : owner_(owner),
3373 : compilation_info_(info),
3374 : call_context_(NULL),
3375 : inlining_kind_(inlining_kind),
3376 : tail_call_mode_(tail_call_mode),
3377 : function_return_(NULL),
3378 : test_context_(NULL),
3379 : entry_(NULL),
3380 : arguments_object_(NULL),
3381 : arguments_elements_(NULL),
3382 : inlining_id_(inlining_id),
3383 : outer_source_position_(SourcePosition::Unknown()),
3384 : do_expression_scope_count_(0),
3385 742622 : outer_(owner->function_state()) {
3386 371311 : if (outer_ != NULL) {
3387 : // State for an inline function.
3388 107398 : if (owner->ast_context()->IsTest()) {
3389 586107 : HBasicBlock* if_true = owner->graph()->CreateBasicBlock();
3390 19537 : HBasicBlock* if_false = owner->graph()->CreateBasicBlock();
3391 : if_true->MarkAsInlineReturnTarget(owner->current_block());
3392 : if_false->MarkAsInlineReturnTarget(owner->current_block());
3393 19537 : TestContext* outer_test_context = TestContext::cast(owner->ast_context());
3394 : Expression* cond = outer_test_context->condition();
3395 : // The AstContext constructor pushed on the context stack. This newed
3396 : // instance is the reason that AstContext can't be BASE_EMBEDDED.
3397 39074 : test_context_ = new TestContext(owner, cond, if_true, if_false);
3398 : } else {
3399 87861 : function_return_ = owner->graph()->CreateBasicBlock();
3400 : function_return()->MarkAsInlineReturnTarget(owner->current_block());
3401 : }
3402 : // Set this after possibly allocating a new TestContext above.
3403 107398 : call_context_ = owner->ast_context();
3404 : }
3405 :
3406 : // Push on the state stack.
3407 : owner->set_function_state(this);
3408 :
3409 371311 : if (owner->is_tracking_positions()) {
3410 122 : outer_source_position_ = owner->source_position();
3411 : owner->EnterInlinedSource(inlining_id);
3412 244 : owner->SetSourcePosition(info->shared_info()->start_position());
3413 : }
3414 371311 : }
3415 :
3416 :
3417 107398 : FunctionState::~FunctionState() {
3418 107398 : delete test_context_;
3419 107401 : owner_->set_function_state(outer_);
3420 :
3421 107398 : if (owner_->is_tracking_positions()) {
3422 : owner_->set_source_position(outer_source_position_);
3423 3 : owner_->EnterInlinedSource(outer_->inlining_id());
3424 : }
3425 107398 : }
3426 :
3427 :
3428 : // Implementation of utility classes to represent an expression's context in
3429 : // the AST.
3430 7316144 : AstContext::AstContext(HOptimizedGraphBuilder* owner, Expression::Context kind)
3431 : : owner_(owner),
3432 : kind_(kind),
3433 : outer_(owner->ast_context()),
3434 14632288 : typeof_mode_(NOT_INSIDE_TYPEOF) {
3435 : owner->set_ast_context(this); // Push.
3436 : #ifdef DEBUG
3437 : DCHECK_EQ(JS_FUNCTION, owner->environment()->frame_type());
3438 : original_length_ = owner->environment()->length();
3439 : #endif
3440 0 : }
3441 :
3442 :
3443 7316142 : AstContext::~AstContext() {
3444 7316142 : owner_->set_ast_context(outer_); // Pop.
3445 0 : }
3446 :
3447 :
3448 922161 : EffectContext::~EffectContext() {
3449 : DCHECK(owner()->HasStackOverflow() || owner()->current_block() == NULL ||
3450 : (owner()->environment()->length() == original_length_ &&
3451 : (owner()->environment()->frame_type() == JS_FUNCTION ||
3452 : owner()->environment()->frame_type() == TAIL_CALLER_FUNCTION)));
3453 0 : }
3454 :
3455 :
3456 5358947 : ValueContext::~ValueContext() {
3457 : DCHECK(owner()->HasStackOverflow() || owner()->current_block() == NULL ||
3458 : (owner()->environment()->length() == original_length_ + 1 &&
3459 : (owner()->environment()->frame_type() == JS_FUNCTION ||
3460 : owner()->environment()->frame_type() == TAIL_CALLER_FUNCTION)));
3461 0 : }
3462 :
3463 :
3464 654963 : void EffectContext::ReturnValue(HValue* value) {
3465 : // The value is simply ignored.
3466 654963 : }
3467 :
3468 :
3469 2625719 : void ValueContext::ReturnValue(HValue* value) {
3470 : // The value is tracked in the bailout environment, and communicated
3471 : // through the environment as the result of the expression.
3472 2625719 : if (value->CheckFlag(HValue::kIsArguments)) {
3473 1804 : if (flag_ == ARGUMENTS_FAKED) {
3474 2625991 : value = owner()->graph()->GetConstantUndefined();
3475 1776 : } else if (!arguments_allowed()) {
3476 : owner()->Bailout(kBadValueContextForArgumentsValue);
3477 : }
3478 : }
3479 2625719 : owner()->Push(value);
3480 2625719 : }
3481 :
3482 :
3483 22942 : void TestContext::ReturnValue(HValue* value) {
3484 23104 : BuildBranch(value);
3485 22942 : }
3486 :
3487 :
3488 194046 : void EffectContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
3489 : DCHECK(!instr->IsControlInstruction());
3490 337327 : owner()->AddInstruction(instr);
3491 194046 : if (instr->HasObservableSideEffects()) {
3492 143281 : owner()->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
3493 : }
3494 194046 : }
3495 :
3496 :
3497 106 : void EffectContext::ReturnControl(HControlInstruction* instr,
3498 : BailoutId ast_id) {
3499 : DCHECK(!instr->HasObservableSideEffects());
3500 424 : HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock();
3501 106 : HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock();
3502 106 : instr->SetSuccessorAt(0, empty_true);
3503 106 : instr->SetSuccessorAt(1, empty_false);
3504 106 : owner()->FinishCurrentBlock(instr);
3505 106 : HBasicBlock* join = owner()->CreateJoin(empty_true, empty_false, ast_id);
3506 : owner()->set_current_block(join);
3507 106 : }
3508 :
3509 :
3510 0 : void EffectContext::ReturnContinuation(HIfContinuation* continuation,
3511 : BailoutId ast_id) {
3512 : HBasicBlock* true_branch = NULL;
3513 : HBasicBlock* false_branch = NULL;
3514 : continuation->Continue(&true_branch, &false_branch);
3515 0 : if (!continuation->IsTrueReachable()) {
3516 0 : owner()->set_current_block(false_branch);
3517 0 : } else if (!continuation->IsFalseReachable()) {
3518 : owner()->set_current_block(true_branch);
3519 : } else {
3520 0 : HBasicBlock* join = owner()->CreateJoin(true_branch, false_branch, ast_id);
3521 : owner()->set_current_block(join);
3522 : }
3523 0 : }
3524 :
3525 :
3526 2702762 : void ValueContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
3527 : DCHECK(!instr->IsControlInstruction());
3528 5056443 : if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) {
3529 8882130 : return owner()->Bailout(kBadValueContextForArgumentsObjectValue);
3530 : }
3531 2702762 : owner()->AddInstruction(instr);
3532 2702762 : owner()->Push(instr);
3533 2702761 : if (instr->HasObservableSideEffects()) {
3534 773845 : owner()->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
3535 : }
3536 : }
3537 :
3538 :
3539 16759 : void ValueContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) {
3540 : DCHECK(!instr->HasObservableSideEffects());
3541 32320 : if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) {
3542 201108 : return owner()->Bailout(kBadValueContextForArgumentsObjectValue);
3543 : }
3544 16759 : HBasicBlock* materialize_false = owner()->graph()->CreateBasicBlock();
3545 16759 : HBasicBlock* materialize_true = owner()->graph()->CreateBasicBlock();
3546 16759 : instr->SetSuccessorAt(0, materialize_true);
3547 16759 : instr->SetSuccessorAt(1, materialize_false);
3548 16759 : owner()->FinishCurrentBlock(instr);
3549 : owner()->set_current_block(materialize_true);
3550 33518 : owner()->Push(owner()->graph()->GetConstantTrue());
3551 : owner()->set_current_block(materialize_false);
3552 33518 : owner()->Push(owner()->graph()->GetConstantFalse());
3553 : HBasicBlock* join =
3554 16759 : owner()->CreateJoin(materialize_true, materialize_false, ast_id);
3555 : owner()->set_current_block(join);
3556 : }
3557 :
3558 :
3559 0 : void ValueContext::ReturnContinuation(HIfContinuation* continuation,
3560 : BailoutId ast_id) {
3561 : HBasicBlock* materialize_true = NULL;
3562 : HBasicBlock* materialize_false = NULL;
3563 : continuation->Continue(&materialize_true, &materialize_false);
3564 0 : if (continuation->IsTrueReachable()) {
3565 0 : owner()->set_current_block(materialize_true);
3566 0 : owner()->Push(owner()->graph()->GetConstantTrue());
3567 : owner()->set_current_block(materialize_true);
3568 : }
3569 0 : if (continuation->IsFalseReachable()) {
3570 : owner()->set_current_block(materialize_false);
3571 0 : owner()->Push(owner()->graph()->GetConstantFalse());
3572 : owner()->set_current_block(materialize_false);
3573 : }
3574 0 : if (continuation->TrueAndFalseReachable()) {
3575 : HBasicBlock* join =
3576 0 : owner()->CreateJoin(materialize_true, materialize_false, ast_id);
3577 : owner()->set_current_block(join);
3578 : }
3579 0 : }
3580 :
3581 :
3582 274249 : void TestContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
3583 : DCHECK(!instr->IsControlInstruction());
3584 274249 : HOptimizedGraphBuilder* builder = owner();
3585 274249 : builder->AddInstruction(instr);
3586 : // We expect a simulate after every expression with side effects, though
3587 : // this one isn't actually needed (and wouldn't work if it were targeted).
3588 274249 : if (instr->HasObservableSideEffects()) {
3589 108164 : builder->Push(instr);
3590 108164 : builder->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
3591 : builder->Pop();
3592 : }
3593 274249 : BuildBranch(instr);
3594 274249 : }
3595 :
3596 :
3597 2358771 : void TestContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) {
3598 : DCHECK(!instr->HasObservableSideEffects());
3599 3931285 : HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock();
3600 786257 : HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock();
3601 786257 : instr->SetSuccessorAt(0, empty_true);
3602 786257 : instr->SetSuccessorAt(1, empty_false);
3603 786257 : owner()->FinishCurrentBlock(instr);
3604 786257 : owner()->Goto(empty_true, if_true(), owner()->function_state());
3605 786257 : owner()->Goto(empty_false, if_false(), owner()->function_state());
3606 : owner()->set_current_block(NULL);
3607 786257 : }
3608 :
3609 :
3610 1694 : void TestContext::ReturnContinuation(HIfContinuation* continuation,
3611 1694 : BailoutId ast_id) {
3612 : HBasicBlock* true_branch = NULL;
3613 : HBasicBlock* false_branch = NULL;
3614 : continuation->Continue(&true_branch, &false_branch);
3615 847 : if (continuation->IsTrueReachable()) {
3616 2541 : owner()->Goto(true_branch, if_true(), owner()->function_state());
3617 : }
3618 847 : if (continuation->IsFalseReachable()) {
3619 847 : owner()->Goto(false_branch, if_false(), owner()->function_state());
3620 : }
3621 : owner()->set_current_block(NULL);
3622 847 : }
3623 :
3624 :
3625 892059 : void TestContext::BuildBranch(HValue* value) {
3626 : // We expect the graph to be in edge-split form: there is no edge that
3627 : // connects a branch node to a join node. We conservatively ensure that
3628 : // property by always adding an empty block on the outgoing edges of this
3629 : // branch.
3630 297353 : HOptimizedGraphBuilder* builder = owner();
3631 594706 : if (value != NULL && value->CheckFlag(HValue::kIsArguments)) {
3632 : builder->Bailout(kArgumentsObjectValueInATestContext);
3633 : }
3634 297353 : ToBooleanHints expected(condition()->to_boolean_types());
3635 297353 : ReturnControl(owner()->New<HBranch>(value, expected), BailoutId::None());
3636 297353 : }
3637 :
3638 :
3639 : // HOptimizedGraphBuilder infrastructure for bailing out and checking bailouts.
3640 : #define CHECK_BAILOUT(call) \
3641 : do { \
3642 : call; \
3643 : if (HasStackOverflow()) return; \
3644 : } while (false)
3645 :
3646 :
3647 : #define CHECK_ALIVE(call) \
3648 : do { \
3649 : call; \
3650 : if (HasStackOverflow() || current_block() == NULL) return; \
3651 : } while (false)
3652 :
3653 :
3654 : #define CHECK_ALIVE_OR_RETURN(call, value) \
3655 : do { \
3656 : call; \
3657 : if (HasStackOverflow() || current_block() == NULL) return value; \
3658 : } while (false)
3659 :
3660 :
3661 0 : void HOptimizedGraphBuilder::Bailout(BailoutReason reason) {
3662 : current_info()->AbortOptimization(reason);
3663 : SetStackOverflow();
3664 0 : }
3665 :
3666 :
3667 921251 : void HOptimizedGraphBuilder::VisitForEffect(Expression* expr) {
3668 : EffectContext for_effect(this);
3669 921251 : Visit(expr);
3670 921251 : }
3671 :
3672 :
3673 5043492 : void HOptimizedGraphBuilder::VisitForValue(Expression* expr,
3674 : ArgumentsAllowedFlag flag) {
3675 : ValueContext for_value(this, flag);
3676 5043492 : Visit(expr);
3677 5043490 : }
3678 :
3679 :
3680 106725 : void HOptimizedGraphBuilder::VisitForTypeOf(Expression* expr) {
3681 : ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED);
3682 : for_value.set_typeof_mode(INSIDE_TYPEOF);
3683 106725 : Visit(expr);
3684 106725 : }
3685 :
3686 :
3687 1015497 : void HOptimizedGraphBuilder::VisitForControl(Expression* expr,
3688 : HBasicBlock* true_block,
3689 : HBasicBlock* false_block) {
3690 : TestContext for_control(this, expr, true_block, false_block);
3691 1015497 : Visit(expr);
3692 1015497 : }
3693 :
3694 :
3695 622220 : void HOptimizedGraphBuilder::VisitExpressions(
3696 994727 : ZoneList<Expression*>* exprs) {
3697 3233644 : for (int i = 0; i < exprs->length(); ++i) {
3698 4228496 : CHECK_ALIVE(VisitForValue(exprs->at(i)));
3699 : }
3700 : }
3701 :
3702 :
3703 114937 : void HOptimizedGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs,
3704 106278 : ArgumentsAllowedFlag flag) {
3705 442396 : for (int i = 0; i < exprs->length(); ++i) {
3706 548691 : CHECK_ALIVE(VisitForValue(exprs->at(i), flag));
3707 : }
3708 : }
3709 :
3710 :
3711 788087 : bool HOptimizedGraphBuilder::BuildGraph() {
3712 527826 : if (IsDerivedConstructor(current_info()->literal()->kind())) {
3713 : Bailout(kSuperReference);
3714 0 : return false;
3715 : }
3716 :
3717 263913 : DeclarationScope* scope = current_info()->scope();
3718 263913 : SetUpScope(scope);
3719 :
3720 : // Add an edge to the body entry. This is warty: the graph's start
3721 : // environment will be used by the Lithium translation as the initial
3722 : // environment on graph entry, but it has now been mutated by the
3723 : // Hydrogen translation of the instructions in the start block. This
3724 : // environment uses values which have not been defined yet. These
3725 : // Hydrogen instructions will then be replayed by the Lithium
3726 : // translation, so they cannot have an environment effect. The edge to
3727 : // the body's entry block (along with some special logic for the start
3728 : // block in HInstruction::InsertAfter) seals the start block from
3729 : // getting unwanted instructions inserted.
3730 : //
3731 : // TODO(kmillikin): Fix this. Stop mutating the initial environment.
3732 : // Make the Hydrogen instructions in the initial block into Hydrogen
3733 : // values (but not instructions), present in the initial environment and
3734 : // not replayed by the Lithium translation.
3735 1088896 : HEnvironment* initial_env = environment()->CopyWithoutHistory();
3736 263913 : HBasicBlock* body_entry = CreateBasicBlock(initial_env);
3737 : Goto(body_entry);
3738 : body_entry->SetJoinId(BailoutId::FunctionEntry());
3739 : set_current_block(body_entry);
3740 :
3741 263913 : VisitDeclarations(scope->declarations());
3742 : Add<HSimulate>(BailoutId::Declarations());
3743 :
3744 263913 : Add<HStackCheck>(HStackCheck::kFunctionEntry);
3745 :
3746 263913 : VisitStatements(current_info()->literal()->body());
3747 263913 : if (HasStackOverflow()) return false;
3748 :
3749 260261 : if (current_block() != NULL) {
3750 44200 : Add<HReturn>(graph()->GetConstantUndefined());
3751 : set_current_block(NULL);
3752 : }
3753 :
3754 : // If the checksum of the number of type info changes is the same as the
3755 : // last time this function was compiled, then this recompile is likely not
3756 : // due to missing/inadequate type feedback, but rather too aggressive
3757 : // optimization. Disable optimistic LICM in that case.
3758 520522 : Handle<Code> unoptimized_code(current_info()->shared_info()->code());
3759 : DCHECK(unoptimized_code->kind() == Code::FUNCTION);
3760 : Handle<TypeFeedbackInfo> type_info(
3761 : TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info()));
3762 : int checksum = type_info->own_type_change_checksum();
3763 : int composite_checksum = graph()->update_type_change_checksum(checksum);
3764 : graph()->set_use_optimistic_licm(
3765 260261 : !type_info->matches_inlined_type_change_checksum(composite_checksum));
3766 : type_info->set_inlined_type_change_checksum(composite_checksum);
3767 :
3768 : // Set this predicate early to avoid handle deref during graph optimization.
3769 : graph()->set_allow_code_motion(
3770 520522 : current_info()->IsStub() ||
3771 780783 : current_info()->shared_info()->deopt_count() + 1 < FLAG_max_deopt_count);
3772 :
3773 : // Perform any necessary OSR-specific cleanups or changes to the graph.
3774 260261 : osr()->FinishGraph();
3775 :
3776 260260 : return true;
3777 : }
3778 :
3779 :
3780 847542 : bool HGraph::Optimize(BailoutReason* bailout_reason) {
3781 283776 : OrderBlocks();
3782 283778 : AssignDominators();
3783 :
3784 : // We need to create a HConstant "zero" now so that GVN will fold every
3785 : // zero-valued constant in the graph together.
3786 : // The constant is needed to make idef-based bounds check work: the pass
3787 : // evaluates relations with "zero" and that zero cannot be created after GVN.
3788 : GetConstant0();
3789 :
3790 : #ifdef DEBUG
3791 : // Do a full verify after building the graph and computing dominators.
3792 : Verify(true);
3793 : #endif
3794 :
3795 563813 : if (FLAG_analyze_environment_liveness && maximum_environment_size() != 0) {
3796 280036 : Run<HEnvironmentLivenessAnalysisPhase>();
3797 : }
3798 :
3799 283778 : if (!CheckConstPhiUses()) {
3800 43 : *bailout_reason = kUnsupportedPhiUseOfConstVariable;
3801 43 : return false;
3802 : }
3803 283734 : Run<HRedundantPhiEliminationPhase>();
3804 283734 : if (!CheckArgumentsPhiUses()) {
3805 5 : *bailout_reason = kUnsupportedPhiUseOfArguments;
3806 5 : return false;
3807 : }
3808 :
3809 : // Find and mark unreachable code to simplify optimizations, especially gvn,
3810 : // where unreachable code could unnecessarily defeat LICM.
3811 283729 : Run<HMarkUnreachableBlocksPhase>();
3812 :
3813 283730 : if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>();
3814 283726 : if (FLAG_use_escape_analysis) Run<HEscapeAnalysisPhase>();
3815 :
3816 283730 : if (FLAG_load_elimination) Run<HLoadEliminationPhase>();
3817 :
3818 283730 : CollectPhis();
3819 :
3820 283730 : if (has_osr()) osr()->FinishOsrValues();
3821 :
3822 283730 : Run<HInferRepresentationPhase>();
3823 :
3824 : // Remove HSimulate instructions that have turned out not to be needed
3825 : // after all by folding them into the following HSimulate.
3826 : // This must happen after inferring representations.
3827 283730 : Run<HMergeRemovableSimulatesPhase>();
3828 :
3829 283730 : Run<HRepresentationChangesPhase>();
3830 :
3831 283730 : Run<HInferTypesPhase>();
3832 :
3833 : // Must be performed before canonicalization to ensure that Canonicalize
3834 : // will not remove semantically meaningful ToInt32 operations e.g. BIT_OR with
3835 : // zero.
3836 283730 : Run<HUint32AnalysisPhase>();
3837 :
3838 283730 : if (FLAG_use_canonicalizing) Run<HCanonicalizePhase>();
3839 :
3840 283727 : if (FLAG_use_gvn) Run<HGlobalValueNumberingPhase>();
3841 :
3842 283730 : if (FLAG_check_elimination) Run<HCheckEliminationPhase>();
3843 :
3844 283729 : if (FLAG_store_elimination) Run<HStoreEliminationPhase>();
3845 :
3846 283729 : Run<HRangeAnalysisPhase>();
3847 :
3848 : // Eliminate redundant stack checks on backwards branches.
3849 283730 : Run<HStackCheckEliminationPhase>();
3850 :
3851 283729 : if (FLAG_array_bounds_checks_elimination) Run<HBoundsCheckEliminationPhase>();
3852 283729 : if (FLAG_array_index_dehoisting) Run<HDehoistIndexComputationsPhase>();
3853 283729 : if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>();
3854 :
3855 283729 : RestoreActualValues();
3856 :
3857 : // Find unreachable code a second time, GVN and other optimizations may have
3858 : // made blocks unreachable that were previously reachable.
3859 283730 : Run<HMarkUnreachableBlocksPhase>();
3860 :
3861 283730 : return true;
3862 : }
3863 :
3864 :
3865 283729 : void HGraph::RestoreActualValues() {
3866 : HPhase phase("H_Restore actual values", this);
3867 :
3868 4795412 : for (int block_index = 0; block_index < blocks()->length(); block_index++) {
3869 4511683 : HBasicBlock* block = blocks()->at(block_index);
3870 :
3871 : #ifdef DEBUG
3872 : for (int i = 0; i < block->phis()->length(); i++) {
3873 : HPhi* phi = block->phis()->at(i);
3874 : DCHECK(phi->ActualValue() == phi);
3875 : }
3876 : #endif
3877 :
3878 29715261 : for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
3879 : HInstruction* instruction = it.Current();
3880 25203580 : if (instruction->ActualValue() == instruction) continue;
3881 321017 : if (instruction->CheckFlag(HValue::kIsDead)) {
3882 : // The instruction was marked as deleted but left in the graph
3883 : // as a control flow dependency point for subsequent
3884 : // instructions.
3885 6771 : instruction->DeleteAndReplaceWith(instruction->ActualValue());
3886 : } else {
3887 : DCHECK(instruction->IsInformativeDefinition());
3888 314246 : if (instruction->IsPurelyInformativeDefinition()) {
3889 0 : instruction->DeleteAndReplaceWith(instruction->RedefinedOperand());
3890 : } else {
3891 314246 : instruction->ReplaceAllUsesWith(instruction->ActualValue());
3892 : }
3893 : }
3894 : }
3895 283729 : }
3896 283730 : }
3897 :
3898 :
3899 597064 : void HOptimizedGraphBuilder::PushArgumentsFromEnvironment(int count) {
3900 2603995 : ZoneList<HValue*> arguments(count, zone());
3901 2006931 : for (int i = 0; i < count; ++i) {
3902 : arguments.Add(Pop(), zone());
3903 : }
3904 :
3905 597064 : HPushArguments* push_args = New<HPushArguments>();
3906 2603995 : while (!arguments.is_empty()) {
3907 1409867 : push_args->AddInput(arguments.RemoveLast());
3908 : }
3909 597064 : AddInstruction(push_args);
3910 597064 : }
3911 :
3912 :
3913 : template <class Instruction>
3914 406 : HInstruction* HOptimizedGraphBuilder::PreProcessCall(Instruction* call) {
3915 406 : PushArgumentsFromEnvironment(call->argument_count());
3916 406 : return call;
3917 : }
3918 :
3919 791738 : void HOptimizedGraphBuilder::SetUpScope(DeclarationScope* scope) {
3920 1383407 : HEnvironment* prolog_env = environment();
3921 263913 : int parameter_count = environment()->parameter_count();
3922 263913 : ZoneList<HValue*> parameters(parameter_count, zone());
3923 691704 : for (int i = 0; i < parameter_count; ++i) {
3924 427791 : HInstruction* parameter = Add<HParameter>(static_cast<unsigned>(i));
3925 : parameters.Add(parameter, zone());
3926 : environment()->Bind(i, parameter);
3927 : }
3928 :
3929 263913 : HConstant* undefined_constant = graph()->GetConstantUndefined();
3930 : // Initialize specials and locals to undefined.
3931 1195266 : for (int i = parameter_count + 1; i < environment()->length(); ++i) {
3932 : environment()->Bind(i, undefined_constant);
3933 : }
3934 263913 : Add<HPrologue>();
3935 :
3936 263913 : HEnvironment* initial_env = environment()->CopyWithoutHistory();
3937 263913 : HBasicBlock* body_entry = CreateBasicBlock(initial_env);
3938 : GotoNoSimulate(body_entry);
3939 : set_current_block(body_entry);
3940 :
3941 : // Initialize context of prolog environment to undefined.
3942 263913 : prolog_env->BindContext(undefined_constant);
3943 :
3944 : // First special is HContext.
3945 263912 : HInstruction* context = Add<HContext>();
3946 263913 : environment()->BindContext(context);
3947 :
3948 : // Create an arguments object containing the initial parameters. Set the
3949 : // initial values of parameters including "this" having parameter index 0.
3950 : DCHECK_EQ(scope->num_parameters() + 1, parameter_count);
3951 263913 : HArgumentsObject* arguments_object = New<HArgumentsObject>(parameter_count);
3952 691703 : for (int i = 0; i < parameter_count; ++i) {
3953 427790 : HValue* parameter = parameters.at(i);
3954 427790 : arguments_object->AddArgument(parameter, zone());
3955 : }
3956 :
3957 263913 : AddInstruction(arguments_object);
3958 :
3959 : // Handle the arguments and arguments shadow variables specially (they do
3960 : // not have declarations).
3961 263913 : if (scope->arguments() != NULL) {
3962 856 : environment()->Bind(scope->arguments(), arguments_object);
3963 : }
3964 :
3965 263913 : if (scope->rest_parameter() != nullptr) {
3966 : return Bailout(kRestParameter);
3967 : }
3968 :
3969 527825 : if (scope->this_function_var() != nullptr ||
3970 : scope->new_target_var() != nullptr) {
3971 : return Bailout(kSuperReference);
3972 : }
3973 :
3974 : // Trace the call.
3975 263913 : if (FLAG_trace && top_info()->IsOptimizing()) {
3976 0 : Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kTraceEnter), 0);
3977 : }
3978 : }
3979 :
3980 :
3981 3147487 : void HOptimizedGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) {
3982 5500514 : for (int i = 0; i < statements->length(); i++) {
3983 4810460 : Statement* stmt = statements->at(i);
3984 5207690 : CHECK_ALIVE(Visit(stmt));
3985 1666114 : if (stmt->IsJump()) break;
3986 : }
3987 : }
3988 :
3989 :
3990 2060829 : void HOptimizedGraphBuilder::VisitBlock(Block* stmt) {
3991 : DCHECK(!HasStackOverflow());
3992 : DCHECK(current_block() != NULL);
3993 : DCHECK(current_block()->HasPredecessor());
3994 :
3995 695787 : Scope* outer_scope = scope();
3996 : Scope* scope = stmt->scope();
3997 : BreakAndContinueInfo break_info(stmt, outer_scope);
3998 :
3999 : { BreakAndContinueScope push(&break_info, this);
4000 686943 : if (scope != NULL) {
4001 8477 : if (scope->NeedsContext()) {
4002 : // Load the function object.
4003 889 : DeclarationScope* declaration_scope = scope->GetDeclarationScope();
4004 : HInstruction* function;
4005 : HValue* outer_context = environment()->context();
4006 889 : if (declaration_scope->is_script_scope() ||
4007 : declaration_scope->is_eval_scope()) {
4008 : function = new (zone())
4009 : HLoadContextSlot(outer_context, Context::CLOSURE_INDEX,
4010 727 : HLoadContextSlot::kNoCheck);
4011 : } else {
4012 162 : function = New<HThisFunction>();
4013 : }
4014 889 : AddInstruction(function);
4015 : // Allocate a block context and store it to the stack frame.
4016 889 : HValue* scope_info = Add<HConstant>(scope->scope_info());
4017 889 : Add<HPushArguments>(scope_info, function);
4018 : HInstruction* inner_context = Add<HCallRuntime>(
4019 889 : Runtime::FunctionForId(Runtime::kPushBlockContext), 2);
4020 : inner_context->SetFlag(HValue::kHasNoObservableSideEffects);
4021 : set_scope(scope);
4022 889 : environment()->BindContext(inner_context);
4023 : }
4024 8477 : VisitDeclarations(scope->declarations());
4025 : AddSimulate(stmt->DeclsId(), REMOVABLE_SIMULATE);
4026 : }
4027 2060829 : CHECK_BAILOUT(VisitStatements(stmt->statements()));
4028 : }
4029 : set_scope(outer_scope);
4030 700275 : if (scope != NULL && current_block() != NULL &&
4031 7250 : scope->ContextLocalCount() > 0) {
4032 : HValue* inner_context = environment()->context();
4033 : HValue* outer_context = Add<HLoadNamedField>(
4034 : inner_context, nullptr,
4035 866 : HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
4036 :
4037 866 : environment()->BindContext(outer_context);
4038 : }
4039 684977 : HBasicBlock* break_block = break_info.break_block();
4040 684977 : if (break_block != NULL) {
4041 69 : if (current_block() != NULL) Goto(break_block);
4042 : break_block->SetJoinId(stmt->ExitId());
4043 : set_current_block(break_block);
4044 : }
4045 : }
4046 :
4047 :
4048 910526 : void HOptimizedGraphBuilder::VisitExpressionStatement(
4049 910843 : ExpressionStatement* stmt) {
4050 : DCHECK(!HasStackOverflow());
4051 : DCHECK(current_block() != NULL);
4052 : DCHECK(current_block()->HasPredecessor());
4053 910843 : VisitForEffect(stmt->expression());
4054 910526 : }
4055 :
4056 :
4057 390899 : void HOptimizedGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
4058 : DCHECK(!HasStackOverflow());
4059 : DCHECK(current_block() != NULL);
4060 : DCHECK(current_block()->HasPredecessor());
4061 390899 : }
4062 :
4063 :
4064 371 : void HOptimizedGraphBuilder::VisitSloppyBlockFunctionStatement(
4065 371 : SloppyBlockFunctionStatement* stmt) {
4066 371 : Visit(stmt->statement());
4067 371 : }
4068 :
4069 :
4070 3323128 : void HOptimizedGraphBuilder::VisitIfStatement(IfStatement* stmt) {
4071 : DCHECK(!HasStackOverflow());
4072 : DCHECK(current_block() != NULL);
4073 : DCHECK(current_block()->HasPredecessor());
4074 415692 : if (stmt->condition()->ToBooleanIsTrue()) {
4075 1660891 : Add<HSimulate>(stmt->ThenId());
4076 33 : Visit(stmt->then_statement());
4077 415659 : } else if (stmt->condition()->ToBooleanIsFalse()) {
4078 426 : Add<HSimulate>(stmt->ElseId());
4079 426 : Visit(stmt->else_statement());
4080 : } else {
4081 415233 : HBasicBlock* cond_true = graph()->CreateBasicBlock();
4082 415233 : HBasicBlock* cond_false = graph()->CreateBasicBlock();
4083 830466 : CHECK_BAILOUT(VisitForControl(stmt->condition(), cond_true, cond_false));
4084 :
4085 : // Technically, we should be able to handle the case when one side of
4086 : // the test is not connected, but this can trip up liveness analysis
4087 : // if we did not fully connect the test context based on some optimistic
4088 : // assumption. If such an assumption was violated, we would end up with
4089 : // an environment with optimized-out values. So we should always
4090 : // conservatively connect the test context.
4091 415230 : CHECK(cond_true->HasPredecessor());
4092 415230 : CHECK(cond_false->HasPredecessor());
4093 :
4094 : cond_true->SetJoinId(stmt->ThenId());
4095 : set_current_block(cond_true);
4096 830460 : CHECK_BAILOUT(Visit(stmt->then_statement()));
4097 : cond_true = current_block();
4098 :
4099 : cond_false->SetJoinId(stmt->ElseId());
4100 : set_current_block(cond_false);
4101 830392 : CHECK_BAILOUT(Visit(stmt->else_statement()));
4102 : cond_false = current_block();
4103 :
4104 415196 : HBasicBlock* join = CreateJoin(cond_true, cond_false, stmt->IfId());
4105 : set_current_block(join);
4106 : }
4107 : }
4108 :
4109 :
4110 8280 : HBasicBlock* HOptimizedGraphBuilder::BreakAndContinueScope::Get(
4111 : BreakableStatement* stmt,
4112 : BreakType type,
4113 : Scope** scope,
4114 : int* drop_extra) {
4115 8280 : *drop_extra = 0;
4116 67679 : BreakAndContinueScope* current = this;
4117 42580 : while (current != NULL && current->info()->target() != stmt) {
4118 8870 : *drop_extra += current->info()->drop_extra();
4119 : current = current->next();
4120 : }
4121 : DCHECK(current != NULL); // Always found (unless stack is malformed).
4122 8280 : *scope = current->info()->scope();
4123 :
4124 8280 : if (type == BREAK) {
4125 7737 : *drop_extra += current->info()->drop_extra();
4126 : }
4127 :
4128 : HBasicBlock* block = NULL;
4129 8280 : switch (type) {
4130 : case BREAK:
4131 7737 : block = current->info()->break_block();
4132 7737 : if (block == NULL) {
4133 3796 : block = current->owner()->graph()->CreateBasicBlock();
4134 : current->info()->set_break_block(block);
4135 : }
4136 : break;
4137 :
4138 : case CONTINUE:
4139 543 : block = current->info()->continue_block();
4140 543 : if (block == NULL) {
4141 450 : block = current->owner()->graph()->CreateBasicBlock();
4142 : current->info()->set_continue_block(block);
4143 : }
4144 : break;
4145 : }
4146 :
4147 8280 : return block;
4148 : }
4149 :
4150 :
4151 545 : void HOptimizedGraphBuilder::VisitContinueStatement(
4152 1088 : ContinueStatement* stmt) {
4153 : DCHECK(!HasStackOverflow());
4154 : DCHECK(current_block() != NULL);
4155 : DCHECK(current_block()->HasPredecessor());
4156 :
4157 545 : if (function_state()->IsInsideDoExpressionScope()) {
4158 547 : return Bailout(kDoExpressionUnmodelable);
4159 : }
4160 :
4161 543 : Scope* outer_scope = NULL;
4162 543 : Scope* inner_scope = scope();
4163 543 : int drop_extra = 0;
4164 : HBasicBlock* continue_block = break_scope()->Get(
4165 : stmt->target(), BreakAndContinueScope::CONTINUE,
4166 543 : &outer_scope, &drop_extra);
4167 : HValue* context = environment()->context();
4168 543 : Drop(drop_extra);
4169 543 : int context_pop_count = inner_scope->ContextChainLength(outer_scope);
4170 543 : if (context_pop_count > 0) {
4171 0 : while (context_pop_count-- > 0) {
4172 : HInstruction* context_instruction = Add<HLoadNamedField>(
4173 : context, nullptr,
4174 0 : HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
4175 : context = context_instruction;
4176 : }
4177 0 : environment()->BindContext(context);
4178 : }
4179 :
4180 : Goto(continue_block);
4181 : set_current_block(NULL);
4182 : }
4183 :
4184 :
4185 15478 : void HOptimizedGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
4186 : DCHECK(!HasStackOverflow());
4187 : DCHECK(current_block() != NULL);
4188 : DCHECK(current_block()->HasPredecessor());
4189 :
4190 7741 : if (function_state()->IsInsideDoExpressionScope()) {
4191 7745 : return Bailout(kDoExpressionUnmodelable);
4192 : }
4193 :
4194 7737 : Scope* outer_scope = NULL;
4195 7737 : Scope* inner_scope = scope();
4196 7737 : int drop_extra = 0;
4197 : HBasicBlock* break_block = break_scope()->Get(
4198 : stmt->target(), BreakAndContinueScope::BREAK,
4199 7737 : &outer_scope, &drop_extra);
4200 : HValue* context = environment()->context();
4201 7737 : Drop(drop_extra);
4202 7737 : int context_pop_count = inner_scope->ContextChainLength(outer_scope);
4203 7737 : if (context_pop_count > 0) {
4204 804 : while (context_pop_count-- > 0) {
4205 : HInstruction* context_instruction = Add<HLoadNamedField>(
4206 : context, nullptr,
4207 402 : HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
4208 : context = context_instruction;
4209 : }
4210 402 : environment()->BindContext(context);
4211 : }
4212 : Goto(break_block);
4213 : set_current_block(NULL);
4214 : }
4215 :
4216 :
4217 1424459 : void HOptimizedGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
4218 : DCHECK(!HasStackOverflow());
4219 : DCHECK(current_block() != NULL);
4220 : DCHECK(current_block()->HasPredecessor());
4221 264012 : FunctionState* state = function_state();
4222 264012 : AstContext* context = call_context();
4223 548624 : if (context == NULL) {
4224 : // Not an inlined return, so an actual one.
4225 612161 : CHECK_ALIVE(VisitForValue(stmt->expression()));
4226 284449 : HValue* result = environment()->Pop();
4227 284449 : Add<HReturn>(result);
4228 264012 : } else if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) {
4229 : // Return from an inlined construct call. In a test context the return value
4230 : // will always evaluate to true, in a value context the return value needs
4231 : // to be a JSObject.
4232 207 : if (context->IsTest()) {
4233 33 : CHECK_ALIVE(VisitForEffect(stmt->expression()));
4234 22 : context->ReturnValue(graph()->GetConstantTrue());
4235 196 : } else if (context->IsEffect()) {
4236 66 : CHECK_ALIVE(VisitForEffect(stmt->expression()));
4237 : Goto(function_return(), state);
4238 : } else {
4239 : DCHECK(context->IsValue());
4240 522 : CHECK_ALIVE(VisitForValue(stmt->expression()));
4241 : HValue* return_value = Pop();
4242 : HValue* receiver = environment()->arguments_environment()->Lookup(0);
4243 : HHasInstanceTypeAndBranch* typecheck =
4244 : New<HHasInstanceTypeAndBranch>(return_value,
4245 : FIRST_JS_RECEIVER_TYPE,
4246 174 : LAST_JS_RECEIVER_TYPE);
4247 174 : HBasicBlock* if_spec_object = graph()->CreateBasicBlock();
4248 174 : HBasicBlock* not_spec_object = graph()->CreateBasicBlock();
4249 174 : typecheck->SetSuccessorAt(0, if_spec_object);
4250 174 : typecheck->SetSuccessorAt(1, not_spec_object);
4251 174 : FinishCurrentBlock(typecheck);
4252 : AddLeaveInlined(if_spec_object, return_value, state);
4253 : AddLeaveInlined(not_spec_object, receiver, state);
4254 : }
4255 263805 : } else if (state->inlining_kind() == SETTER_CALL_RETURN) {
4256 : // Return from an inlined setter call. The returned value is never used, the
4257 : // value of an assignment is always the value of the RHS of the assignment.
4258 156 : CHECK_ALIVE(VisitForEffect(stmt->expression()));
4259 52 : if (context->IsTest()) {
4260 : HValue* rhs = environment()->arguments_environment()->Lookup(1);
4261 8 : context->ReturnValue(rhs);
4262 44 : } else if (context->IsEffect()) {
4263 : Goto(function_return(), state);
4264 : } else {
4265 : DCHECK(context->IsValue());
4266 : HValue* rhs = environment()->arguments_environment()->Lookup(1);
4267 : AddLeaveInlined(rhs, state);
4268 : }
4269 : } else {
4270 : // Return from a normal inlined function. Visit the subexpression in the
4271 : // expression context of the call.
4272 263753 : if (context->IsTest()) {
4273 221413 : TestContext* test = TestContext::cast(context);
4274 221413 : VisitForControl(stmt->expression(), test->if_true(), test->if_false());
4275 42340 : } else if (context->IsEffect()) {
4276 : // Visit in value context and ignore the result. This is needed to keep
4277 : // environment in sync with full-codegen since some visitors (e.g.
4278 : // VisitCountOperation) use the operand stack differently depending on
4279 : // context.
4280 19095 : CHECK_ALIVE(VisitForValue(stmt->expression()));
4281 : Pop();
4282 : Goto(function_return(), state);
4283 : } else {
4284 : DCHECK(context->IsValue());
4285 107904 : CHECK_ALIVE(VisitForValue(stmt->expression()));
4286 : AddLeaveInlined(Pop(), state);
4287 : }
4288 : }
4289 : set_current_block(NULL);
4290 : }
4291 :
4292 :
4293 0 : void HOptimizedGraphBuilder::VisitWithStatement(WithStatement* stmt) {
4294 : DCHECK(!HasStackOverflow());
4295 : DCHECK(current_block() != NULL);
4296 : DCHECK(current_block()->HasPredecessor());
4297 0 : return Bailout(kWithStatement);
4298 : }
4299 :
4300 :
4301 104044 : void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
4302 : DCHECK(!HasStackOverflow());
4303 : DCHECK(current_block() != NULL);
4304 : DCHECK(current_block()->HasPredecessor());
4305 :
4306 : ZoneList<CaseClause*>* clauses = stmt->cases();
4307 4615 : int clause_count = clauses->length();
4308 166287 : ZoneList<HBasicBlock*> body_blocks(clause_count, zone());
4309 :
4310 13845 : CHECK_ALIVE(VisitForValue(stmt->tag()));
4311 4615 : Add<HSimulate>(stmt->EntryId());
4312 : HValue* tag_value = Top();
4313 4615 : AstType* tag_type = bounds_.get(stmt->tag()).lower;
4314 :
4315 : // 1. Build all the tests, with dangling true branches
4316 : BailoutId default_id = BailoutId::None();
4317 34278 : for (int i = 0; i < clause_count; ++i) {
4318 57941 : CaseClause* clause = clauses->at(i);
4319 29665 : if (clause->is_default()) {
4320 : body_blocks.Add(NULL, zone());
4321 : if (default_id.IsNone()) default_id = clause->EntryId();
4322 : continue;
4323 : }
4324 :
4325 : // Generate a compare and branch.
4326 56556 : CHECK_BAILOUT(VisitForValue(clause->label()));
4327 28276 : if (current_block() == NULL) return Bailout(kUnsupportedSwitchStatement);
4328 : HValue* label_value = Pop();
4329 :
4330 28276 : AstType* label_type = bounds_.get(clause->label()).lower;
4331 : AstType* combined_type = clause->compare_type();
4332 : HControlInstruction* compare = BuildCompareInstruction(
4333 : Token::EQ_STRICT, tag_value, label_value, tag_type, label_type,
4334 : combined_type,
4335 : ScriptPositionToSourcePosition(stmt->tag()->position()),
4336 28276 : ScriptPositionToSourcePosition(clause->label()->position()),
4337 84828 : PUSH_BEFORE_SIMULATE, clause->id());
4338 :
4339 28276 : HBasicBlock* next_test_block = graph()->CreateBasicBlock();
4340 28276 : HBasicBlock* body_block = graph()->CreateBasicBlock();
4341 : body_blocks.Add(body_block, zone());
4342 28276 : compare->SetSuccessorAt(0, body_block);
4343 28276 : compare->SetSuccessorAt(1, next_test_block);
4344 28276 : FinishCurrentBlock(compare);
4345 :
4346 : set_current_block(body_block);
4347 : Drop(1); // tag_value
4348 :
4349 : set_current_block(next_test_block);
4350 : }
4351 :
4352 : // Save the current block to use for the default or to join with the
4353 : // exit.
4354 : HBasicBlock* last_block = current_block();
4355 : Drop(1); // tag_value
4356 :
4357 : // 2. Loop over the clauses and the linked list of tests in lockstep,
4358 : // translating the clause bodies.
4359 : HBasicBlock* fall_through_block = NULL;
4360 :
4361 : BreakAndContinueInfo break_info(stmt, scope());
4362 : { BreakAndContinueScope push(&break_info, this);
4363 33338 : for (int i = 0; i < clause_count; ++i) {
4364 58060 : CaseClause* clause = clauses->at(i);
4365 :
4366 : // Identify the block where normal (non-fall-through) control flow
4367 : // goes to.
4368 : HBasicBlock* normal_block = NULL;
4369 29030 : if (clause->is_default()) {
4370 1384 : if (last_block == NULL) continue;
4371 : normal_block = last_block;
4372 : last_block = NULL; // Cleared to indicate we've handled it.
4373 : } else {
4374 55292 : normal_block = body_blocks[i];
4375 : }
4376 :
4377 29030 : if (fall_through_block == NULL) {
4378 : set_current_block(normal_block);
4379 : } else {
4380 : HBasicBlock* join = CreateJoin(fall_through_block,
4381 : normal_block,
4382 7035 : clause->EntryId());
4383 : set_current_block(join);
4384 : }
4385 :
4386 58060 : CHECK_BAILOUT(VisitStatements(clause->statements()));
4387 : fall_through_block = current_block();
4388 : }
4389 : }
4390 :
4391 : // Create an up-to-3-way join. Use the break block if it exists since
4392 : // it's already a join block.
4393 4308 : HBasicBlock* break_block = break_info.break_block();
4394 4308 : if (break_block == NULL) {
4395 : set_current_block(CreateJoin(fall_through_block,
4396 : last_block,
4397 2789 : stmt->ExitId()));
4398 : } else {
4399 1519 : if (fall_through_block != NULL) Goto(fall_through_block, break_block);
4400 1519 : if (last_block != NULL) Goto(last_block, break_block);
4401 : break_block->SetJoinId(stmt->ExitId());
4402 : set_current_block(break_block);
4403 : }
4404 : }
4405 :
4406 91176 : void HOptimizedGraphBuilder::VisitLoopBody(IterationStatement* stmt,
4407 : BailoutId stack_check_id,
4408 45588 : HBasicBlock* loop_entry) {
4409 45588 : Add<HSimulate>(stack_check_id);
4410 : HStackCheck* stack_check =
4411 45588 : HStackCheck::cast(Add<HStackCheck>(HStackCheck::kBackwardsBranch));
4412 : DCHECK(loop_entry->IsLoopHeader());
4413 : loop_entry->loop_information()->set_stack_check(stack_check);
4414 45588 : CHECK_BAILOUT(Visit(stmt->body()));
4415 : }
4416 :
4417 :
4418 2886 : void HOptimizedGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
4419 : DCHECK(!HasStackOverflow());
4420 : DCHECK(current_block() != NULL);
4421 : DCHECK(current_block()->HasPredecessor());
4422 : DCHECK(current_block() != NULL);
4423 718 : HBasicBlock* loop_entry = BuildLoopEntry(stmt);
4424 :
4425 2370 : BreakAndContinueInfo break_info(stmt, scope());
4426 : {
4427 : BreakAndContinueScope push(&break_info, this);
4428 1240 : CHECK_BAILOUT(VisitLoopBody(stmt, stmt->StackCheckId(), loop_entry));
4429 : }
4430 : HBasicBlock* body_exit = JoinContinue(
4431 1240 : stmt, stmt->ContinueId(), current_block(), break_info.continue_block());
4432 : HBasicBlock* loop_successor = NULL;
4433 620 : if (body_exit != NULL) {
4434 : set_current_block(body_exit);
4435 614 : loop_successor = graph()->CreateBasicBlock();
4436 614 : if (stmt->cond()->ToBooleanIsFalse()) {
4437 98 : loop_entry->loop_information()->stack_check()->Eliminate();
4438 : Goto(loop_successor);
4439 : body_exit = NULL;
4440 : } else {
4441 : // The block for a true condition, the actual predecessor block of the
4442 : // back edge.
4443 516 : body_exit = graph()->CreateBasicBlock();
4444 1032 : CHECK_BAILOUT(VisitForControl(stmt->cond(), body_exit, loop_successor));
4445 : }
4446 1130 : if (body_exit != NULL && body_exit->HasPredecessor()) {
4447 : body_exit->SetJoinId(stmt->BackEdgeId());
4448 : } else {
4449 : body_exit = NULL;
4450 : }
4451 614 : if (loop_successor->HasPredecessor()) {
4452 : loop_successor->SetJoinId(stmt->ExitId());
4453 : } else {
4454 : loop_successor = NULL;
4455 : }
4456 : }
4457 : HBasicBlock* loop_exit = CreateLoop(stmt,
4458 : loop_entry,
4459 : body_exit,
4460 : loop_successor,
4461 620 : break_info.break_block());
4462 : set_current_block(loop_exit);
4463 : }
4464 :
4465 :
4466 17092 : void HOptimizedGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
4467 : DCHECK(!HasStackOverflow());
4468 : DCHECK(current_block() != NULL);
4469 : DCHECK(current_block()->HasPredecessor());
4470 : DCHECK(current_block() != NULL);
4471 4273 : HBasicBlock* loop_entry = BuildLoopEntry(stmt);
4472 :
4473 : // If the condition is constant true, do not generate a branch.
4474 : HBasicBlock* loop_successor = NULL;
4475 17089 : HBasicBlock* body_entry = graph()->CreateBasicBlock();
4476 4273 : loop_successor = graph()->CreateBasicBlock();
4477 8549 : CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor));
4478 4273 : if (body_entry->HasPredecessor()) {
4479 : body_entry->SetJoinId(stmt->BodyId());
4480 : set_current_block(body_entry);
4481 : }
4482 4273 : if (loop_successor->HasPredecessor()) {
4483 : loop_successor->SetJoinId(stmt->ExitId());
4484 : } else {
4485 : loop_successor = NULL;
4486 : }
4487 :
4488 : BreakAndContinueInfo break_info(stmt, scope());
4489 4273 : if (current_block() != NULL) {
4490 : BreakAndContinueScope push(&break_info, this);
4491 8546 : CHECK_BAILOUT(VisitLoopBody(stmt, stmt->StackCheckId(), loop_entry));
4492 : }
4493 : HBasicBlock* body_exit = JoinContinue(
4494 8540 : stmt, stmt->ContinueId(), current_block(), break_info.continue_block());
4495 : HBasicBlock* loop_exit = CreateLoop(stmt,
4496 : loop_entry,
4497 : body_exit,
4498 : loop_successor,
4499 4270 : break_info.break_block());
4500 : set_current_block(loop_exit);
4501 : }
4502 :
4503 :
4504 309572 : void HOptimizedGraphBuilder::VisitForStatement(ForStatement* stmt) {
4505 : DCHECK(!HasStackOverflow());
4506 : DCHECK(current_block() != NULL);
4507 : DCHECK(current_block()->HasPredecessor());
4508 39687 : if (stmt->init() != NULL) {
4509 311529 : CHECK_ALIVE(Visit(stmt->init()));
4510 : }
4511 : DCHECK(current_block() != NULL);
4512 39687 : HBasicBlock* loop_entry = BuildLoopEntry(stmt);
4513 :
4514 39687 : HBasicBlock* loop_successor = graph()->CreateBasicBlock();
4515 39687 : HBasicBlock* body_entry = graph()->CreateBasicBlock();
4516 39687 : if (stmt->cond() != NULL) {
4517 77484 : CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor));
4518 38678 : if (body_entry->HasPredecessor()) {
4519 : body_entry->SetJoinId(stmt->BodyId());
4520 : set_current_block(body_entry);
4521 : }
4522 38678 : if (loop_successor->HasPredecessor()) {
4523 : loop_successor->SetJoinId(stmt->ExitId());
4524 : } else {
4525 : loop_successor = NULL;
4526 : }
4527 : } else {
4528 : // Create dummy control flow so that variable liveness analysis
4529 : // produces teh correct result.
4530 945 : HControlInstruction* branch = New<HBranch>(graph()->GetConstantTrue());
4531 945 : branch->SetSuccessorAt(0, body_entry);
4532 945 : branch->SetSuccessorAt(1, loop_successor);
4533 945 : FinishCurrentBlock(branch);
4534 : set_current_block(body_entry);
4535 : }
4536 :
4537 : BreakAndContinueInfo break_info(stmt, scope());
4538 39623 : if (current_block() != NULL) {
4539 : BreakAndContinueScope push(&break_info, this);
4540 79246 : CHECK_BAILOUT(VisitLoopBody(stmt, stmt->StackCheckId(), loop_entry));
4541 : }
4542 : HBasicBlock* body_exit = JoinContinue(
4543 78856 : stmt, stmt->ContinueId(), current_block(), break_info.continue_block());
4544 :
4545 39428 : if (stmt->next() != NULL && body_exit != NULL) {
4546 : set_current_block(body_exit);
4547 75022 : CHECK_BAILOUT(Visit(stmt->next()));
4548 : body_exit = current_block();
4549 : }
4550 :
4551 : HBasicBlock* loop_exit = CreateLoop(stmt,
4552 : loop_entry,
4553 : body_exit,
4554 : loop_successor,
4555 39379 : break_info.break_block());
4556 : set_current_block(loop_exit);
4557 : }
4558 :
4559 :
4560 4367 : void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
4561 : DCHECK(!HasStackOverflow());
4562 : DCHECK(current_block() != NULL);
4563 : DCHECK(current_block()->HasPredecessor());
4564 :
4565 2217 : if (!stmt->each()->IsVariableProxy() ||
4566 2210 : !stmt->each()->AsVariableProxy()->var()->IsStackLocal()) {
4567 40 : return Bailout(kForInStatementWithNonLocalEachVariable);
4568 : }
4569 :
4570 2150 : Variable* each_var = stmt->each()->AsVariableProxy()->var();
4571 :
4572 4294 : CHECK_ALIVE(VisitForValue(stmt->enumerable()));
4573 : HValue* enumerable = Top(); // Leave enumerable at the top.
4574 :
4575 1072 : IfBuilder if_undefined_or_null(this);
4576 : if_undefined_or_null.If<HCompareObjectEqAndBranch>(
4577 1072 : enumerable, graph()->GetConstantUndefined());
4578 1072 : if_undefined_or_null.Or();
4579 : if_undefined_or_null.If<HCompareObjectEqAndBranch>(
4580 1072 : enumerable, graph()->GetConstantNull());
4581 : if_undefined_or_null.ThenDeopt(DeoptimizeReason::kUndefinedOrNullInForIn);
4582 1072 : if_undefined_or_null.End();
4583 1072 : BuildForInBody(stmt, each_var, enumerable);
4584 : }
4585 :
4586 :
4587 2144 : void HOptimizedGraphBuilder::BuildForInBody(ForInStatement* stmt,
4588 : Variable* each_var,
4589 1072 : HValue* enumerable) {
4590 11517 : Handle<Map> meta_map = isolate()->factory()->meta_map();
4591 1072 : bool fast = stmt->for_in_type() == ForInStatement::FAST_FOR_IN;
4592 1072 : BuildCheckHeapObject(enumerable);
4593 1072 : Add<HCheckInstanceType>(enumerable, HCheckInstanceType::IS_JS_RECEIVER);
4594 : Add<HSimulate>(stmt->ToObjectId());
4595 1072 : if (fast) {
4596 842 : HForInPrepareMap* map = Add<HForInPrepareMap>(enumerable);
4597 842 : Push(map);
4598 : Add<HSimulate>(stmt->EnumId());
4599 : Drop(1);
4600 842 : Add<HCheckMaps>(map, meta_map);
4601 :
4602 : HForInCacheArray* array = Add<HForInCacheArray>(
4603 842 : enumerable, map, DescriptorArray::kEnumCacheBridgeCacheIndex);
4604 842 : HValue* enum_length = BuildEnumLength(map);
4605 :
4606 : HForInCacheArray* index_cache = Add<HForInCacheArray>(
4607 842 : enumerable, map, DescriptorArray::kEnumCacheBridgeIndicesCacheIndex);
4608 : array->set_index_cache(index_cache);
4609 :
4610 842 : Push(map);
4611 842 : Push(array);
4612 842 : Push(enum_length);
4613 : Add<HSimulate>(stmt->PrepareId());
4614 : } else {
4615 : Runtime::FunctionId function_id = Runtime::kForInEnumerate;
4616 230 : Add<HPushArguments>(enumerable);
4617 : HCallRuntime* array =
4618 230 : Add<HCallRuntime>(Runtime::FunctionForId(function_id), 1);
4619 230 : Push(array);
4620 : Add<HSimulate>(stmt->EnumId());
4621 : Drop(1);
4622 :
4623 : IfBuilder if_fast(this);
4624 230 : if_fast.If<HCompareMap>(array, meta_map);
4625 230 : if_fast.Then();
4626 : {
4627 : HValue* cache_map = array;
4628 : HForInCacheArray* cache = Add<HForInCacheArray>(
4629 230 : enumerable, cache_map, DescriptorArray::kEnumCacheBridgeCacheIndex);
4630 230 : HValue* enum_length = BuildEnumLength(cache_map);
4631 230 : Push(cache_map);
4632 230 : Push(cache);
4633 230 : Push(enum_length);
4634 230 : Add<HSimulate>(stmt->PrepareId(), FIXED_SIMULATE);
4635 : }
4636 : if_fast.Else();
4637 : {
4638 230 : Push(graph()->GetConstant1());
4639 230 : Push(array);
4640 230 : Push(AddLoadFixedArrayLength(array));
4641 230 : Add<HSimulate>(stmt->PrepareId(), FIXED_SIMULATE);
4642 : }
4643 : }
4644 :
4645 1072 : Push(graph()->GetConstant0());
4646 :
4647 1072 : HBasicBlock* loop_entry = BuildLoopEntry(stmt);
4648 :
4649 : // Reload the values to ensure we have up-to-date values inside of the loop.
4650 : // This is relevant especially for OSR where the values don't come from the
4651 : // computation above, but from the OSR entry block.
4652 : HValue* index = environment()->ExpressionStackAt(0);
4653 : HValue* limit = environment()->ExpressionStackAt(1);
4654 : HValue* array = environment()->ExpressionStackAt(2);
4655 : HValue* type = environment()->ExpressionStackAt(3);
4656 : enumerable = environment()->ExpressionStackAt(4);
4657 :
4658 : // Check that we still have more keys.
4659 : HCompareNumericAndBranch* compare_index =
4660 1072 : New<HCompareNumericAndBranch>(index, limit, Token::LT);
4661 : compare_index->set_observed_input_representation(
4662 : Representation::Smi(), Representation::Smi());
4663 :
4664 1072 : HBasicBlock* loop_body = graph()->CreateBasicBlock();
4665 1072 : HBasicBlock* loop_successor = graph()->CreateBasicBlock();
4666 :
4667 1072 : compare_index->SetSuccessorAt(0, loop_body);
4668 1072 : compare_index->SetSuccessorAt(1, loop_successor);
4669 1072 : FinishCurrentBlock(compare_index);
4670 :
4671 : set_current_block(loop_successor);
4672 : Drop(5);
4673 :
4674 : set_current_block(loop_body);
4675 :
4676 : // Compute the next enumerated value.
4677 1072 : HValue* key = Add<HLoadKeyed>(array, index, index, nullptr, FAST_ELEMENTS);
4678 :
4679 : HBasicBlock* continue_block = nullptr;
4680 1072 : if (fast) {
4681 : // Check if expected map still matches that of the enumerable.
4682 842 : Add<HCheckMapValue>(enumerable, type);
4683 : Add<HSimulate>(stmt->FilterId());
4684 : } else {
4685 : // We need the continue block here to be able to skip over invalidated keys.
4686 230 : continue_block = graph()->CreateBasicBlock();
4687 :
4688 : // We cannot use the IfBuilder here, since we need to be able to jump
4689 : // over the loop body in case of undefined result from %ForInFilter,
4690 : // and the poor soul that is the IfBuilder get's really confused about
4691 : // such "advanced control flow requirements".
4692 230 : HBasicBlock* if_fast = graph()->CreateBasicBlock();
4693 230 : HBasicBlock* if_slow = graph()->CreateBasicBlock();
4694 230 : HBasicBlock* if_slow_pass = graph()->CreateBasicBlock();
4695 230 : HBasicBlock* if_slow_skip = graph()->CreateBasicBlock();
4696 230 : HBasicBlock* if_join = graph()->CreateBasicBlock();
4697 :
4698 : // Check if expected map still matches that of the enumerable.
4699 : HValue* enumerable_map =
4700 230 : Add<HLoadNamedField>(enumerable, nullptr, HObjectAccess::ForMap());
4701 : FinishCurrentBlock(
4702 230 : New<HCompareObjectEqAndBranch>(enumerable_map, type, if_fast, if_slow));
4703 : set_current_block(if_fast);
4704 : {
4705 : // The enum cache for enumerable is still valid, no need to check key.
4706 230 : Push(key);
4707 : Goto(if_join);
4708 : }
4709 : set_current_block(if_slow);
4710 : {
4711 230 : Callable callable = CodeFactory::ForInFilter(isolate());
4712 230 : HValue* values[] = {key, enumerable};
4713 230 : HConstant* stub_value = Add<HConstant>(callable.code());
4714 : Push(Add<HCallWithDescriptor>(stub_value, 0, callable.descriptor(),
4715 230 : ArrayVector(values)));
4716 : Add<HSimulate>(stmt->FilterId());
4717 : FinishCurrentBlock(New<HCompareObjectEqAndBranch>(
4718 460 : Top(), graph()->GetConstantUndefined(), if_slow_skip, if_slow_pass));
4719 : }
4720 : set_current_block(if_slow_pass);
4721 : { Goto(if_join); }
4722 : set_current_block(if_slow_skip);
4723 : {
4724 : // The key is no longer valid for enumerable, skip it.
4725 : Drop(1);
4726 : Goto(continue_block);
4727 : }
4728 : if_join->SetJoinId(stmt->FilterId());
4729 : set_current_block(if_join);
4730 : key = Pop();
4731 : }
4732 :
4733 : Bind(each_var, key);
4734 : Add<HSimulate>(stmt->AssignmentId());
4735 :
4736 : BreakAndContinueInfo break_info(stmt, scope(), 5);
4737 : break_info.set_continue_block(continue_block);
4738 : {
4739 : BreakAndContinueScope push(&break_info, this);
4740 3216 : CHECK_BAILOUT(VisitLoopBody(stmt, stmt->StackCheckId(), loop_entry));
4741 : }
4742 :
4743 : HBasicBlock* body_exit = JoinContinue(
4744 2086 : stmt, stmt->IncrementId(), current_block(), break_info.continue_block());
4745 :
4746 1043 : if (body_exit != NULL) {
4747 : set_current_block(body_exit);
4748 :
4749 : HValue* current_index = Pop();
4750 : HValue* increment =
4751 986 : AddUncasted<HAdd>(current_index, graph()->GetConstant1());
4752 : increment->ClearFlag(HValue::kCanOverflow);
4753 986 : Push(increment);
4754 : body_exit = current_block();
4755 : }
4756 :
4757 : HBasicBlock* loop_exit = CreateLoop(stmt,
4758 : loop_entry,
4759 : body_exit,
4760 : loop_successor,
4761 1043 : break_info.break_block());
4762 :
4763 : set_current_block(loop_exit);
4764 : }
4765 :
4766 :
4767 0 : void HOptimizedGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) {
4768 : DCHECK(!HasStackOverflow());
4769 : DCHECK(current_block() != NULL);
4770 : DCHECK(current_block()->HasPredecessor());
4771 0 : return Bailout(kForOfStatement);
4772 : }
4773 :
4774 :
4775 0 : void HOptimizedGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
4776 : DCHECK(!HasStackOverflow());
4777 : DCHECK(current_block() != NULL);
4778 : DCHECK(current_block()->HasPredecessor());
4779 0 : return Bailout(kTryCatchStatement);
4780 : }
4781 :
4782 :
4783 0 : void HOptimizedGraphBuilder::VisitTryFinallyStatement(
4784 : TryFinallyStatement* stmt) {
4785 : DCHECK(!HasStackOverflow());
4786 : DCHECK(current_block() != NULL);
4787 : DCHECK(current_block()->HasPredecessor());
4788 0 : return Bailout(kTryFinallyStatement);
4789 : }
4790 :
4791 :
4792 0 : void HOptimizedGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
4793 : DCHECK(!HasStackOverflow());
4794 : DCHECK(current_block() != NULL);
4795 : DCHECK(current_block()->HasPredecessor());
4796 0 : return Bailout(kDebuggerStatement);
4797 : }
4798 :
4799 :
4800 0 : void HOptimizedGraphBuilder::VisitCaseClause(CaseClause* clause) {
4801 0 : UNREACHABLE();
4802 : }
4803 :
4804 :
4805 424864 : void HOptimizedGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
4806 : DCHECK(!HasStackOverflow());
4807 : DCHECK(current_block() != NULL);
4808 : DCHECK(current_block()->HasPredecessor());
4809 : Handle<SharedFunctionInfo> shared_info = Compiler::GetSharedFunctionInfo(
4810 409808 : expr, current_info()->script(), top_info());
4811 : // We also have a stack overflow if the recursive compilation did.
4812 104334 : if (HasStackOverflow()) return;
4813 : // Use the fast case closure allocation code that allocates in new
4814 : // space for nested functions that don't need pretenuring.
4815 104334 : HConstant* shared_info_value = Add<HConstant>(shared_info);
4816 : HInstruction* instr;
4817 : Handle<FeedbackVector> vector(current_feedback_vector(), isolate());
4818 104334 : HValue* vector_value = Add<HConstant>(vector);
4819 : int index = FeedbackVector::GetIndex(expr->LiteralFeedbackSlot());
4820 104334 : HValue* index_value = Add<HConstant>(index);
4821 104334 : if (!expr->pretenure()) {
4822 96806 : Callable callable = CodeFactory::FastNewClosure(isolate());
4823 96806 : HValue* values[] = {shared_info_value, vector_value, index_value};
4824 96806 : HConstant* stub_value = Add<HConstant>(callable.code());
4825 : instr = New<HCallWithDescriptor>(stub_value, 0, callable.descriptor(),
4826 96806 : ArrayVector(values));
4827 : } else {
4828 7528 : Add<HPushArguments>(shared_info_value);
4829 7528 : Add<HPushArguments>(vector_value);
4830 7528 : Add<HPushArguments>(index_value);
4831 : Runtime::FunctionId function_id =
4832 7528 : expr->pretenure() ? Runtime::kNewClosure_Tenured : Runtime::kNewClosure;
4833 7528 : instr = New<HCallRuntime>(Runtime::FunctionForId(function_id), 3);
4834 : }
4835 208668 : return ast_context()->ReturnInstruction(instr, expr->id());
4836 : }
4837 :
4838 :
4839 0 : void HOptimizedGraphBuilder::VisitClassLiteral(ClassLiteral* lit) {
4840 : DCHECK(!HasStackOverflow());
4841 : DCHECK(current_block() != NULL);
4842 : DCHECK(current_block()->HasPredecessor());
4843 0 : return Bailout(kClassLiteral);
4844 : }
4845 :
4846 :
4847 0 : void HOptimizedGraphBuilder::VisitNativeFunctionLiteral(
4848 : NativeFunctionLiteral* expr) {
4849 : DCHECK(!HasStackOverflow());
4850 : DCHECK(current_block() != NULL);
4851 : DCHECK(current_block()->HasPredecessor());
4852 0 : return Bailout(kNativeFunctionLiteral);
4853 : }
4854 :
4855 :
4856 204 : void HOptimizedGraphBuilder::VisitDoExpression(DoExpression* expr) {
4857 : DoExpressionScope scope(this);
4858 : DCHECK(!HasStackOverflow());
4859 : DCHECK(current_block() != NULL);
4860 : DCHECK(current_block()->HasPredecessor());
4861 248 : CHECK_ALIVE(VisitBlock(expr->block()));
4862 18 : Visit(expr->result());
4863 : }
4864 :
4865 :
4866 94034 : void HOptimizedGraphBuilder::VisitConditional(Conditional* expr) {
4867 : DCHECK(!HasStackOverflow());
4868 : DCHECK(current_block() != NULL);
4869 : DCHECK(current_block()->HasPredecessor());
4870 28231 : HBasicBlock* cond_true = graph()->CreateBasicBlock();
4871 9415 : HBasicBlock* cond_false = graph()->CreateBasicBlock();
4872 18830 : CHECK_BAILOUT(VisitForControl(expr->condition(), cond_true, cond_false));
4873 :
4874 : // Visit the true and false subexpressions in the same AST context as the
4875 : // whole expression.
4876 9415 : if (cond_true->HasPredecessor()) {
4877 : cond_true->SetJoinId(expr->ThenId());
4878 : set_current_block(cond_true);
4879 18830 : CHECK_BAILOUT(Visit(expr->then_expression()));
4880 : cond_true = current_block();
4881 : } else {
4882 : cond_true = NULL;
4883 : }
4884 :
4885 9408 : if (cond_false->HasPredecessor()) {
4886 : cond_false->SetJoinId(expr->ElseId());
4887 : set_current_block(cond_false);
4888 18816 : CHECK_BAILOUT(Visit(expr->else_expression()));
4889 : cond_false = current_block();
4890 : } else {
4891 : cond_false = NULL;
4892 : }
4893 :
4894 9408 : if (!ast_context()->IsTest()) {
4895 9391 : HBasicBlock* join = CreateJoin(cond_true, cond_false, expr->id());
4896 : set_current_block(join);
4897 18782 : if (join != NULL && !ast_context()->IsEffect()) {
4898 18688 : return ast_context()->ReturnValue(Pop());
4899 : }
4900 : }
4901 : }
4902 :
4903 0 : bool HOptimizedGraphBuilder::CanInlineGlobalPropertyAccess(
4904 : Variable* var, LookupIterator* it, PropertyAccessType access_type) {
4905 365803 : if (var->is_this()) return false;
4906 365803 : return CanInlineGlobalPropertyAccess(it, access_type);
4907 : }
4908 :
4909 366002 : bool HOptimizedGraphBuilder::CanInlineGlobalPropertyAccess(
4910 366002 : LookupIterator* it, PropertyAccessType access_type) {
4911 366002 : if (!current_info()->has_global_object()) {
4912 : return false;
4913 : }
4914 :
4915 366002 : switch (it->state()) {
4916 : case LookupIterator::ACCESSOR:
4917 : case LookupIterator::ACCESS_CHECK:
4918 : case LookupIterator::INTERCEPTOR:
4919 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
4920 : case LookupIterator::NOT_FOUND:
4921 : return false;
4922 : case LookupIterator::DATA:
4923 310343 : if (access_type == STORE && it->IsReadOnly()) return false;
4924 300203 : if (!it->GetHolder<JSObject>()->IsJSGlobalObject()) return false;
4925 300203 : return true;
4926 : case LookupIterator::JSPROXY:
4927 : case LookupIterator::TRANSITION:
4928 0 : UNREACHABLE();
4929 : }
4930 0 : UNREACHABLE();
4931 : return false;
4932 : }
4933 :
4934 :
4935 858634 : HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) {
4936 : DCHECK(var->IsContextSlot());
4937 429317 : HValue* context = environment()->context();
4938 429317 : int length = scope()->ContextChainLength(var->scope());
4939 861705 : while (length-- > 0) {
4940 : context = Add<HLoadNamedField>(
4941 : context, nullptr,
4942 3071 : HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
4943 : }
4944 429317 : return context;
4945 : }
4946 :
4947 290161 : void HOptimizedGraphBuilder::InlineGlobalPropertyLoad(LookupIterator* it,
4948 290161 : BailoutId ast_id) {
4949 290161 : Handle<PropertyCell> cell = it->GetPropertyCell();
4950 566782 : top_info()->dependencies()->AssumePropertyCell(cell);
4951 : auto cell_type = it->property_details().cell_type();
4952 290161 : if (cell_type == PropertyCellType::kConstant ||
4953 : cell_type == PropertyCellType::kUndefined) {
4954 : Handle<Object> constant_object(cell->value(), isolate());
4955 274330 : if (constant_object->IsConsString()) {
4956 105 : constant_object = String::Flatten(Handle<String>::cast(constant_object));
4957 : }
4958 274330 : HConstant* constant = New<HConstant>(constant_object);
4959 274330 : return ast_context()->ReturnInstruction(constant, ast_id);
4960 : } else {
4961 15831 : auto access = HObjectAccess::ForPropertyCellValue();
4962 : UniqueSet<Map>* field_maps = nullptr;
4963 15831 : if (cell_type == PropertyCellType::kConstantType) {
4964 8776 : switch (cell->GetConstantType()) {
4965 : case PropertyCellConstantType::kSmi:
4966 6420 : access = access.WithRepresentation(Representation::Smi());
4967 6420 : break;
4968 : case PropertyCellConstantType::kStableMap: {
4969 : // Check that the map really is stable. The heap object could
4970 : // have mutated without the cell updating state. In that case,
4971 : // make no promises about the loaded value except that it's a
4972 : // heap object.
4973 2356 : access = access.WithRepresentation(Representation::HeapObject());
4974 : Handle<Map> map(HeapObject::cast(cell->value())->map());
4975 2356 : if (map->is_stable()) {
4976 : field_maps = new (zone())
4977 : UniqueSet<Map>(Unique<Map>::CreateImmovable(map), zone());
4978 : }
4979 : break;
4980 : }
4981 : }
4982 : }
4983 15831 : HConstant* cell_constant = Add<HConstant>(cell);
4984 : HLoadNamedField* instr;
4985 15831 : if (field_maps == nullptr) {
4986 13540 : instr = New<HLoadNamedField>(cell_constant, nullptr, access);
4987 : } else {
4988 : instr = New<HLoadNamedField>(cell_constant, nullptr, access, field_maps,
4989 2291 : HType::HeapObject());
4990 : }
4991 : instr->ClearDependsOnFlag(kInobjectFields);
4992 : instr->SetDependsOnFlag(kGlobalVars);
4993 15831 : return ast_context()->ReturnInstruction(instr, ast_id);
4994 : }
4995 : }
4996 :
4997 5424760 : void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
4998 : DCHECK(!HasStackOverflow());
4999 : DCHECK(current_block() != NULL);
5000 : DCHECK(current_block()->HasPredecessor());
5001 4718383 : Variable* variable = expr->var();
5002 2830142 : switch (variable->location()) {
5003 : case VariableLocation::UNALLOCATED: {
5004 361577 : if (IsLexicalVariableMode(variable->mode())) {
5005 : // TODO(rossberg): should this be an DCHECK?
5006 : return Bailout(kReferenceToGlobalLexicalVariable);
5007 : }
5008 : // Handle known global constants like 'undefined' specially to avoid a
5009 : // load from a global cell for them.
5010 : Handle<Object> constant_value =
5011 3312031 : isolate()->factory()->GlobalConstantFor(variable->name());
5012 361577 : if (!constant_value.is_null()) {
5013 11401 : HConstant* instr = New<HConstant>(constant_value);
5014 22802 : return ast_context()->ReturnInstruction(instr, expr->id());
5015 : }
5016 :
5017 350176 : Handle<JSGlobalObject> global(current_info()->global_object());
5018 :
5019 : // Lookup in script contexts.
5020 : {
5021 : Handle<ScriptContextTable> script_contexts(
5022 : global->native_context()->script_context_table());
5023 : ScriptContextTable::LookupResult lookup;
5024 350176 : if (ScriptContextTable::Lookup(script_contexts, variable->name(),
5025 : &lookup)) {
5026 : Handle<Context> script_context = ScriptContextTable::GetContext(
5027 5534 : script_contexts, lookup.context_index);
5028 : Handle<Object> current_value =
5029 11068 : FixedArray::get(*script_context, lookup.slot_index, isolate());
5030 :
5031 : // If the values is not the hole, it will stay initialized,
5032 : // so no need to generate a check.
5033 5534 : if (current_value->IsTheHole(isolate())) {
5034 : return Bailout(kReferenceToUninitializedVariable);
5035 : }
5036 : HInstruction* result = New<HLoadNamedField>(
5037 : Add<HConstant>(script_context), nullptr,
5038 5532 : HObjectAccess::ForContextSlot(lookup.slot_index));
5039 11064 : return ast_context()->ReturnInstruction(result, expr->id());
5040 : }
5041 : }
5042 :
5043 344642 : LookupIterator it(global, variable->name(), LookupIterator::OWN);
5044 344642 : it.TryLookupCachedProperty();
5045 344642 : if (CanInlineGlobalPropertyAccess(variable, &it, LOAD)) {
5046 290020 : InlineGlobalPropertyLoad(&it, expr->id());
5047 290020 : return;
5048 : } else {
5049 : Handle<FeedbackVector> vector(current_feedback_vector(), isolate());
5050 : FeedbackSlot slot = expr->VariableFeedbackSlot();
5051 : DCHECK(vector->IsLoadGlobalIC(slot));
5052 :
5053 54622 : HValue* vector_value = Add<HConstant>(vector);
5054 54622 : HValue* slot_value = Add<HConstant>(vector->GetIndex(slot));
5055 : Callable callable = CodeFactory::LoadGlobalICInOptimizedCode(
5056 109244 : isolate(), ast_context()->typeof_mode());
5057 54622 : HValue* stub = Add<HConstant>(callable.code());
5058 54622 : HValue* name = Add<HConstant>(variable->name());
5059 54622 : HValue* values[] = {name, slot_value, vector_value};
5060 : HCallWithDescriptor* instr = New<HCallWithDescriptor>(
5061 : Code::LOAD_GLOBAL_IC, stub, 0, callable.descriptor(),
5062 54622 : ArrayVector(values));
5063 109244 : return ast_context()->ReturnInstruction(instr, expr->id());
5064 : }
5065 : }
5066 :
5067 : case VariableLocation::PARAMETER:
5068 : case VariableLocation::LOCAL: {
5069 2079953 : HValue* value = LookupAndMakeLive(variable);
5070 2079953 : if (value == graph()->GetConstantHole()) {
5071 : DCHECK(IsDeclaredVariableMode(variable->mode()) &&
5072 : variable->mode() != VAR);
5073 : return Bailout(kReferenceToUninitializedVariable);
5074 : }
5075 2079829 : return ast_context()->ReturnValue(value);
5076 : }
5077 :
5078 : case VariableLocation::CONTEXT: {
5079 388612 : HValue* context = BuildContextChainWalk(variable);
5080 : HLoadContextSlot::Mode mode;
5081 388612 : switch (variable->mode()) {
5082 : case LET:
5083 : case CONST:
5084 : mode = HLoadContextSlot::kCheckDeoptimize;
5085 : break;
5086 : default:
5087 : mode = HLoadContextSlot::kNoCheck;
5088 374890 : break;
5089 : }
5090 : HLoadContextSlot* instr =
5091 388612 : new(zone()) HLoadContextSlot(context, variable->index(), mode);
5092 777224 : return ast_context()->ReturnInstruction(instr, expr->id());
5093 : }
5094 :
5095 : case VariableLocation::LOOKUP:
5096 : return Bailout(kReferenceToAVariableWhichRequiresDynamicLookup);
5097 :
5098 : case VariableLocation::MODULE:
5099 0 : UNREACHABLE();
5100 : }
5101 : }
5102 :
5103 :
5104 2301676 : void HOptimizedGraphBuilder::VisitLiteral(Literal* expr) {
5105 : DCHECK(!HasStackOverflow());
5106 : DCHECK(current_block() != NULL);
5107 : DCHECK(current_block()->HasPredecessor());
5108 1150838 : HConstant* instr = New<HConstant>(expr->value());
5109 2301676 : return ast_context()->ReturnInstruction(instr, expr->id());
5110 : }
5111 :
5112 :
5113 34620 : void HOptimizedGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
5114 : DCHECK(!HasStackOverflow());
5115 : DCHECK(current_block() != NULL);
5116 : DCHECK(current_block()->HasPredecessor());
5117 17310 : Callable callable = CodeFactory::FastCloneRegExp(isolate());
5118 : int index = FeedbackVector::GetIndex(expr->literal_slot());
5119 17310 : HValue* values[] = {AddThisFunction(), Add<HConstant>(index),
5120 8655 : Add<HConstant>(expr->pattern()),
5121 34620 : Add<HConstant>(expr->flags())};
5122 8655 : HConstant* stub_value = Add<HConstant>(callable.code());
5123 : HInstruction* instr = New<HCallWithDescriptor>(
5124 8655 : stub_value, 0, callable.descriptor(), ArrayVector(values));
5125 17310 : return ast_context()->ReturnInstruction(instr, expr->id());
5126 : }
5127 :
5128 :
5129 781577 : static bool CanInlinePropertyAccess(Handle<Map> map) {
5130 781577 : if (map->instance_type() == HEAP_NUMBER_TYPE) return true;
5131 778593 : if (map->instance_type() < FIRST_NONSTRING_TYPE) return true;
5132 1453893 : return map->IsJSObjectMap() && !map->is_dictionary_map() &&
5133 1457373 : !map->has_named_interceptor() &&
5134 : // TODO(verwaest): Whitelist contexts to which we have access.
5135 733112 : !map->is_access_check_needed();
5136 : }
5137 :
5138 :
5139 : // Determines whether the given array or object literal boilerplate satisfies
5140 : // all limits to be considered for fast deep-copying and computes the total
5141 : // size of all objects that are part of the graph.
5142 7352 : static bool IsFastLiteral(Handle<JSObject> boilerplate,
5143 : int max_depth,
5144 : int* max_properties) {
5145 7376 : if (boilerplate->map()->is_deprecated() &&
5146 24 : !JSObject::TryMigrateInstance(boilerplate)) {
5147 : return false;
5148 : }
5149 :
5150 : DCHECK(max_depth >= 0 && *max_properties >= 0);
5151 7352 : if (max_depth == 0) return false;
5152 :
5153 : Isolate* isolate = boilerplate->GetIsolate();
5154 : Handle<FixedArrayBase> elements(boilerplate->elements());
5155 9944 : if (elements->length() > 0 &&
5156 2592 : elements->map() != isolate->heap()->fixed_cow_array_map()) {
5157 1828 : if (boilerplate->HasFastSmiOrObjectElements()) {
5158 : Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
5159 : int length = elements->length();
5160 8212 : for (int i = 0; i < length; i++) {
5161 6819 : if ((*max_properties)-- == 0) return false;
5162 : Handle<Object> value(fast_elements->get(i), isolate);
5163 6819 : if (value->IsJSObject()) {
5164 313 : Handle<JSObject> value_object = Handle<JSObject>::cast(value);
5165 313 : if (!IsFastLiteral(value_object,
5166 : max_depth - 1,
5167 313 : max_properties)) {
5168 0 : return false;
5169 : }
5170 : }
5171 : }
5172 435 : } else if (boilerplate->HasFastDoubleElements()) {
5173 433 : if (elements->Size() > kMaxRegularHeapObjectSize) return false;
5174 : } else {
5175 : return false;
5176 : }
5177 : }
5178 :
5179 : Handle<FixedArray> properties(boilerplate->properties());
5180 7345 : if (properties->length() > 0) {
5181 : return false;
5182 : } else {
5183 : Handle<DescriptorArray> descriptors(
5184 : boilerplate->map()->instance_descriptors());
5185 : int limit = boilerplate->map()->NumberOfOwnDescriptors();
5186 18214 : for (int i = 0; i < limit; i++) {
5187 10869 : PropertyDetails details = descriptors->GetDetails(i);
5188 14341 : if (details.location() != kField) continue;
5189 : DCHECK_EQ(kData, details.kind());
5190 7480 : if ((*max_properties)-- == 0) return false;
5191 7480 : FieldIndex field_index = FieldIndex::ForDescriptor(boilerplate->map(), i);
5192 7480 : if (boilerplate->IsUnboxedDoubleField(field_index)) continue;
5193 : Handle<Object> value(boilerplate->RawFastPropertyAt(field_index),
5194 7397 : isolate);
5195 7397 : if (value->IsJSObject()) {
5196 349 : Handle<JSObject> value_object = Handle<JSObject>::cast(value);
5197 349 : if (!IsFastLiteral(value_object,
5198 : max_depth - 1,
5199 349 : max_properties)) {
5200 0 : return false;
5201 : }
5202 : }
5203 : }
5204 : }
5205 : return true;
5206 : }
5207 :
5208 :
5209 176424 : void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
5210 : DCHECK(!HasStackOverflow());
5211 : DCHECK(current_block() != NULL);
5212 : DCHECK(current_block()->HasPredecessor());
5213 :
5214 22976 : Handle<JSFunction> closure = function_state()->compilation_info()->closure();
5215 : HInstruction* literal;
5216 :
5217 : // Check whether to use fast or slow deep-copying for boilerplate.
5218 22976 : int max_properties = kMaxFastLiteralProperties;
5219 : Handle<Object> literals_cell(
5220 96785 : closure->feedback_vector()->Get(expr->literal_slot()), isolate());
5221 : Handle<AllocationSite> site;
5222 : Handle<JSObject> boilerplate;
5223 22976 : if (!literals_cell->IsUndefined(isolate())) {
5224 : // Retrieve the boilerplate
5225 : site = Handle<AllocationSite>::cast(literals_cell);
5226 : boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()),
5227 : isolate());
5228 : }
5229 :
5230 26540 : if (!boilerplate.is_null() &&
5231 3564 : IsFastLiteral(boilerplate, kMaxFastLiteralDepth, &max_properties)) {
5232 : AllocationSiteUsageContext site_context(isolate(), site, false);
5233 3562 : site_context.EnterNewScope();
5234 3562 : literal = BuildFastLiteral(boilerplate, &site_context);
5235 : site_context.ExitScope(site, boilerplate);
5236 : } else {
5237 19414 : NoObservableSideEffectsScope no_effects(this);
5238 : Handle<BoilerplateDescription> constant_properties =
5239 19414 : expr->GetOrBuildConstantProperties(isolate());
5240 : int literal_index = FeedbackVector::GetIndex(expr->literal_slot());
5241 19414 : int flags = expr->ComputeFlags(true);
5242 :
5243 : Add<HPushArguments>(AddThisFunction(), Add<HConstant>(literal_index),
5244 : Add<HConstant>(constant_properties),
5245 19414 : Add<HConstant>(flags));
5246 :
5247 : Runtime::FunctionId function_id = Runtime::kCreateObjectLiteral;
5248 19414 : literal = Add<HCallRuntime>(Runtime::FunctionForId(function_id), 4);
5249 : }
5250 :
5251 : // The object is expected in the bailout environment during computation
5252 : // of the property values and is the value of the entire expression.
5253 22976 : Push(literal);
5254 174604 : for (int i = 0; i < expr->properties()->length(); i++) {
5255 90373 : ObjectLiteral::Property* property = expr->properties()->at(i);
5256 140787 : if (property->is_computed_name()) return Bailout(kComputedPropertyName);
5257 64880 : if (property->IsCompileTimeValue()) continue;
5258 :
5259 25493 : Literal* key = property->key()->AsLiteral();
5260 : Expression* value = property->value();
5261 :
5262 25493 : switch (property->kind()) {
5263 : case ObjectLiteral::Property::MATERIALIZED_LITERAL:
5264 : DCHECK(!CompileTimeValue::IsCompileTimeValue(value));
5265 : // Fall through.
5266 : case ObjectLiteral::Property::COMPUTED:
5267 : // It is safe to use [[Put]] here because the boilerplate already
5268 : // contains computed properties with an uninitialized value.
5269 24982 : if (key->IsStringLiteral()) {
5270 : DCHECK(key->IsPropertyName());
5271 24957 : if (property->emit_store()) {
5272 74814 : CHECK_ALIVE(VisitForValue(value));
5273 : HValue* value = Pop();
5274 :
5275 : Handle<Map> map = property->GetReceiverType();
5276 : Handle<String> name = key->AsPropertyName();
5277 : HValue* store;
5278 24920 : FeedbackSlot slot = property->GetSlot();
5279 24920 : if (map.is_null()) {
5280 : // If we don't know the monomorphic type, do a generic store.
5281 56301 : CHECK_ALIVE(store = BuildNamedGeneric(STORE, NULL, slot, literal,
5282 : name, value));
5283 : } else {
5284 6153 : PropertyAccessInfo info(this, STORE, map, name);
5285 6153 : if (info.CanAccessMonomorphic()) {
5286 6153 : HValue* checked_literal = Add<HCheckMaps>(literal, map);
5287 : DCHECK(!info.IsAccessorConstant());
5288 : info.MarkAsInitializingStore();
5289 : store = BuildMonomorphicAccess(
5290 : &info, literal, checked_literal, value,
5291 6153 : BailoutId::None(), BailoutId::None());
5292 : DCHECK_NOT_NULL(store);
5293 : } else {
5294 0 : CHECK_ALIVE(store = BuildNamedGeneric(STORE, NULL, slot,
5295 : literal, name, value));
5296 : }
5297 : }
5298 24920 : if (store->IsInstruction()) {
5299 24920 : AddInstruction(HInstruction::cast(store));
5300 : }
5301 : DCHECK(store->HasObservableSideEffects());
5302 24920 : Add<HSimulate>(key->id(), REMOVABLE_SIMULATE);
5303 :
5304 : // Add [[HomeObject]] to function literals.
5305 24920 : if (FunctionLiteral::NeedsHomeObject(property->value())) {
5306 : Handle<Symbol> sym = isolate()->factory()->home_object_symbol();
5307 : HInstruction* store_home = BuildNamedGeneric(
5308 1 : STORE, NULL, property->GetSlot(1), value, sym, literal);
5309 1 : AddInstruction(store_home);
5310 : DCHECK(store_home->HasObservableSideEffects());
5311 1 : Add<HSimulate>(property->value()->id(), REMOVABLE_SIMULATE);
5312 : }
5313 : } else {
5314 57 : CHECK_ALIVE(VisitForEffect(value));
5315 : }
5316 : break;
5317 : }
5318 : // Fall through.
5319 : case ObjectLiteral::Property::PROTOTYPE:
5320 : case ObjectLiteral::Property::SETTER:
5321 : case ObjectLiteral::Property::GETTER:
5322 : return Bailout(kObjectLiteralWithComplexProperty);
5323 0 : default: UNREACHABLE();
5324 : }
5325 : }
5326 :
5327 44844 : return ast_context()->ReturnValue(Pop());
5328 : }
5329 :
5330 :
5331 50724 : void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
5332 : DCHECK(!HasStackOverflow());
5333 : DCHECK(current_block() != NULL);
5334 : DCHECK(current_block()->HasPredecessor());
5335 : ZoneList<Expression*>* subexprs = expr->values();
5336 17235 : int length = subexprs->length();
5337 : HInstruction* literal;
5338 :
5339 : Handle<AllocationSite> site;
5340 : Handle<FeedbackVector> vector(environment()->closure()->feedback_vector(),
5341 74211 : isolate());
5342 : Handle<Object> literals_cell(vector->Get(expr->literal_slot()), isolate());
5343 : Handle<JSObject> boilerplate_object;
5344 17235 : if (!literals_cell->IsUndefined(isolate())) {
5345 : DCHECK(literals_cell->IsAllocationSite());
5346 : site = Handle<AllocationSite>::cast(literals_cell);
5347 : boilerplate_object = Handle<JSObject>(
5348 : JSObject::cast(site->transition_info()), isolate());
5349 : }
5350 :
5351 : // Check whether to use fast or slow deep-copying for boilerplate.
5352 17235 : int max_properties = kMaxFastLiteralProperties;
5353 20361 : if (!boilerplate_object.is_null() &&
5354 : IsFastLiteral(boilerplate_object, kMaxFastLiteralDepth,
5355 3126 : &max_properties)) {
5356 : DCHECK(site->SitePointsToLiteral());
5357 : AllocationSiteUsageContext site_context(isolate(), site, false);
5358 3121 : site_context.EnterNewScope();
5359 3121 : literal = BuildFastLiteral(boilerplate_object, &site_context);
5360 : site_context.ExitScope(site, boilerplate_object);
5361 : } else {
5362 14114 : NoObservableSideEffectsScope no_effects(this);
5363 : Handle<ConstantElementsPair> constants =
5364 14114 : expr->GetOrBuildConstantElements(isolate());
5365 : int literal_index = FeedbackVector::GetIndex(expr->literal_slot());
5366 : int flags = expr->ComputeFlags(true);
5367 :
5368 : Add<HPushArguments>(AddThisFunction(), Add<HConstant>(literal_index),
5369 14114 : Add<HConstant>(constants), Add<HConstant>(flags));
5370 :
5371 : Runtime::FunctionId function_id = Runtime::kCreateArrayLiteral;
5372 14114 : literal = Add<HCallRuntime>(Runtime::FunctionForId(function_id), 4);
5373 :
5374 : // Register to deopt if the boilerplate ElementsKind changes.
5375 14114 : if (!site.is_null()) {
5376 5 : top_info()->dependencies()->AssumeTransitionStable(site);
5377 : }
5378 : }
5379 :
5380 : // The array is expected in the bailout environment during computation
5381 : // of the property values and is the value of the entire expression.
5382 17235 : Push(literal);
5383 :
5384 : HInstruction* elements = NULL;
5385 :
5386 964761 : for (int i = 0; i < length; i++) {
5387 947535 : Expression* subexpr = subexprs->at(i);
5388 : DCHECK(!subexpr->IsSpread());
5389 :
5390 : // If the subexpression is a literal or a simple materialized literal it
5391 : // is already set in the cloned array.
5392 947535 : if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
5393 :
5394 48780 : CHECK_ALIVE(VisitForValue(subexpr));
5395 : HValue* value = Pop();
5396 : if (!Smi::IsValid(i)) return Bailout(kNonSmiKeyInArrayLiteral);
5397 :
5398 : elements = AddLoadElements(literal);
5399 :
5400 16254 : HValue* key = Add<HConstant>(i);
5401 :
5402 16254 : if (!boilerplate_object.is_null()) {
5403 : ElementsKind boilerplate_elements_kind =
5404 : boilerplate_object->GetElementsKind();
5405 3453 : switch (boilerplate_elements_kind) {
5406 : case FAST_SMI_ELEMENTS:
5407 : case FAST_HOLEY_SMI_ELEMENTS:
5408 : case FAST_ELEMENTS:
5409 : case FAST_HOLEY_ELEMENTS:
5410 : case FAST_DOUBLE_ELEMENTS:
5411 : case FAST_HOLEY_DOUBLE_ELEMENTS: {
5412 : Add<HStoreKeyed>(elements, key, value, nullptr,
5413 3453 : boilerplate_elements_kind);
5414 : break;
5415 : }
5416 : default:
5417 0 : UNREACHABLE();
5418 : break;
5419 : }
5420 : } else {
5421 : HInstruction* instr = BuildKeyedGeneric(
5422 12801 : STORE, expr, expr->LiteralFeedbackSlot(), literal, key, value);
5423 12801 : AddInstruction(instr);
5424 : }
5425 :
5426 : Add<HSimulate>(expr->GetIdForElement(i));
5427 : }
5428 :
5429 34452 : return ast_context()->ReturnValue(Pop());
5430 : }
5431 :
5432 :
5433 7453 : HCheckMaps* HOptimizedGraphBuilder::AddCheckMap(HValue* object,
5434 : Handle<Map> map) {
5435 7453 : BuildCheckHeapObject(object);
5436 7453 : return Add<HCheckMaps>(object, map);
5437 : }
5438 :
5439 :
5440 54115 : HInstruction* HOptimizedGraphBuilder::BuildLoadNamedField(
5441 : PropertyAccessInfo* info,
5442 : HValue* checked_object) {
5443 : // Check if this is a load of an immutable or constant property.
5444 108230 : if (checked_object->ActualValue()->IsConstant()) {
5445 : Handle<Object> object(
5446 40493 : HConstant::cast(checked_object->ActualValue())->handle(isolate()));
5447 :
5448 11902 : if (object->IsJSObject()) {
5449 : LookupIterator it(object, info->name(),
5450 11902 : LookupIterator::OWN_SKIP_INTERCEPTOR);
5451 11902 : if (it.IsFound()) {
5452 : bool is_reaonly_non_configurable =
5453 12647 : it.IsReadOnly() && !it.IsConfigurable();
5454 11896 : if (is_reaonly_non_configurable ||
5455 : (FLAG_track_constant_fields && info->IsDataConstantField())) {
5456 749 : Handle<Object> value = JSReceiver::GetDataProperty(&it);
5457 749 : if (!is_reaonly_non_configurable) {
5458 : DCHECK(!it.is_dictionary_holder());
5459 : // Add dependency on the map that introduced the field.
5460 0 : Handle<Map> field_owner_map = it.GetFieldOwnerMap();
5461 0 : top_info()->dependencies()->AssumeFieldOwner(field_owner_map);
5462 : }
5463 749 : return New<HConstant>(value);
5464 : }
5465 : }
5466 : }
5467 : }
5468 :
5469 53366 : HObjectAccess access = info->access();
5470 53835 : if (access.representation().IsDouble() &&
5471 : (!FLAG_unbox_double_fields || !access.IsInobject())) {
5472 : // Load the heap number.
5473 : checked_object = Add<HLoadNamedField>(
5474 : checked_object, nullptr,
5475 17 : access.WithRepresentation(Representation::Tagged()));
5476 : // Load the double value from it.
5477 17 : access = HObjectAccess::ForHeapNumberValue();
5478 : }
5479 :
5480 : SmallMapList* map_list = info->field_maps();
5481 53366 : if (map_list->length() == 0) {
5482 45024 : return New<HLoadNamedField>(checked_object, checked_object, access);
5483 : }
5484 :
5485 : UniqueSet<Map>* maps = new(zone()) UniqueSet<Map>(map_list->length(), zone());
5486 33378 : for (int i = 0; i < map_list->length(); ++i) {
5487 8347 : maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone());
5488 : }
5489 : return New<HLoadNamedField>(
5490 8342 : checked_object, checked_object, access, maps, info->field_type());
5491 : }
5492 :
5493 44452 : HValue* HOptimizedGraphBuilder::BuildStoreNamedField(PropertyAccessInfo* info,
5494 : HValue* checked_object,
5495 : HValue* value) {
5496 : bool transition_to_field = info->IsTransition();
5497 : // TODO(verwaest): Move this logic into PropertyAccessInfo.
5498 22238 : HObjectAccess field_access = info->access();
5499 :
5500 : bool store_to_constant_field = FLAG_track_constant_fields &&
5501 : info->StoreMode() != INITIALIZING_STORE &&
5502 : info->IsDataConstantField();
5503 :
5504 : HStoreNamedField *instr;
5505 22511 : if (field_access.representation().IsDouble() &&
5506 : (!FLAG_unbox_double_fields || !field_access.IsInobject())) {
5507 : HObjectAccess heap_number_access =
5508 24 : field_access.WithRepresentation(Representation::Tagged());
5509 24 : if (transition_to_field) {
5510 : // The store requires a mutable HeapNumber to be allocated.
5511 0 : NoObservableSideEffectsScope no_side_effects(this);
5512 0 : HInstruction* heap_number_size = Add<HConstant>(HeapNumber::kSize);
5513 :
5514 : // TODO(hpayer): Allocation site pretenuring support.
5515 : HInstruction* heap_number =
5516 : Add<HAllocate>(heap_number_size, HType::HeapObject(), NOT_TENURED,
5517 0 : MUTABLE_HEAP_NUMBER_TYPE, graph()->GetConstant0());
5518 : AddStoreMapConstant(
5519 0 : heap_number, isolate()->factory()->mutable_heap_number_map());
5520 : Add<HStoreNamedField>(heap_number, HObjectAccess::ForHeapNumberValue(),
5521 0 : value);
5522 : instr = New<HStoreNamedField>(checked_object->ActualValue(),
5523 : heap_number_access,
5524 0 : heap_number);
5525 : } else {
5526 : // Already holds a HeapNumber; load the box and write its value field.
5527 : HInstruction* heap_number =
5528 24 : Add<HLoadNamedField>(checked_object, nullptr, heap_number_access);
5529 :
5530 : if (store_to_constant_field) {
5531 : // If the field is constant check that the value we are going to store
5532 : // matches current value.
5533 : HInstruction* current_value = Add<HLoadNamedField>(
5534 : heap_number, nullptr, HObjectAccess::ForHeapNumberValue());
5535 : IfBuilder value_checker(this);
5536 : value_checker.IfNot<HCompareNumericAndBranch>(current_value, value,
5537 : Token::EQ);
5538 : value_checker.ThenDeopt(DeoptimizeReason::kValueMismatch);
5539 : value_checker.End();
5540 : return nullptr;
5541 :
5542 : } else {
5543 : instr = New<HStoreNamedField>(heap_number,
5544 : HObjectAccess::ForHeapNumberValue(),
5545 24 : value, STORE_TO_INITIALIZED_ENTRY);
5546 : }
5547 : }
5548 : } else {
5549 : if (store_to_constant_field) {
5550 : // If the field is constant check that the value we are going to store
5551 : // matches current value.
5552 : HInstruction* current_value = Add<HLoadNamedField>(
5553 : checked_object->ActualValue(), checked_object, field_access);
5554 :
5555 : IfBuilder value_checker(this);
5556 : if (field_access.representation().IsDouble()) {
5557 : value_checker.IfNot<HCompareNumericAndBranch>(current_value, value,
5558 : Token::EQ);
5559 : } else {
5560 : value_checker.IfNot<HCompareObjectEqAndBranch>(current_value, value);
5561 : }
5562 : value_checker.ThenDeopt(DeoptimizeReason::kValueMismatch);
5563 : value_checker.End();
5564 : return nullptr;
5565 :
5566 : } else {
5567 22214 : if (field_access.representation().IsHeapObject()) {
5568 13606 : BuildCheckHeapObject(value);
5569 : }
5570 :
5571 22214 : if (!info->field_maps()->is_empty()) {
5572 : DCHECK(field_access.representation().IsHeapObject());
5573 2170 : value = Add<HCheckMaps>(value, info->field_maps());
5574 : }
5575 :
5576 : // This is a normal store.
5577 : instr = New<HStoreNamedField>(checked_object->ActualValue(), field_access,
5578 22214 : value, info->StoreMode());
5579 : }
5580 : }
5581 :
5582 22238 : if (transition_to_field) {
5583 11394 : Handle<Map> transition(info->transition());
5584 : DCHECK(!transition->is_deprecated());
5585 11394 : instr->SetTransition(Add<HConstant>(transition));
5586 : }
5587 : return instr;
5588 : }
5589 :
5590 : Handle<FieldType>
5591 112843 : HOptimizedGraphBuilder::PropertyAccessInfo::GetFieldTypeFromMap(
5592 112843 : Handle<Map> map) const {
5593 : DCHECK(IsFound());
5594 : DCHECK(number_ < map->NumberOfOwnDescriptors());
5595 338529 : return handle(map->instance_descriptors()->GetFieldType(number_), isolate());
5596 : }
5597 :
5598 11697 : bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatible(
5599 22601 : PropertyAccessInfo* info) {
5600 11697 : if (!CanInlinePropertyAccess(map_)) return false;
5601 :
5602 : // Currently only handle AstType::Number as a polymorphic case.
5603 : // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber
5604 : // instruction.
5605 11647 : if (IsNumberType()) return false;
5606 :
5607 : // Values are only compatible for monomorphic load if they all behave the same
5608 : // regarding value wrappers.
5609 11647 : if (IsValueWrapped() != info->IsValueWrapped()) return false;
5610 :
5611 11636 : if (!LookupDescriptor()) return false;
5612 :
5613 11575 : if (!IsFound()) {
5614 11739 : return (!info->IsFound() || info->has_holder()) &&
5615 9934 : map()->prototype() == info->map()->prototype();
5616 : }
5617 :
5618 : // Mismatch if the other access info found the property in the prototype
5619 : // chain.
5620 7043 : if (info->has_holder()) return false;
5621 :
5622 6516 : if (IsAccessorConstant()) {
5623 86 : return accessor_.is_identical_to(info->accessor_) &&
5624 81 : api_holder_.is_identical_to(info->api_holder_);
5625 : }
5626 :
5627 6435 : if (IsDataConstant()) {
5628 29 : return constant_.is_identical_to(info->constant_);
5629 : }
5630 :
5631 : DCHECK(IsData());
5632 6406 : if (!info->IsData()) return false;
5633 :
5634 6405 : Representation r = access_.representation();
5635 6405 : if (IsLoad()) {
5636 18082 : if (!info->access_.representation().IsCompatibleForLoad(r)) return false;
5637 : } else {
5638 559 : if (!info->access_.representation().IsCompatibleForStore(r)) return false;
5639 : }
5640 6390 : if (info->access_.offset() != access_.offset()) return false;
5641 3428 : if (info->access_.IsInobject() != access_.IsInobject()) return false;
5642 3428 : if (IsLoad()) {
5643 3386 : if (field_maps_.is_empty()) {
5644 : info->field_maps_.Clear();
5645 94 : } else if (!info->field_maps_.is_empty()) {
5646 267 : for (int i = 0; i < field_maps_.length(); ++i) {
5647 89 : info->field_maps_.AddMapIfMissing(field_maps_.at(i), info->zone());
5648 : }
5649 : info->field_maps_.Sort();
5650 : }
5651 : } else {
5652 : // We can only merge stores that agree on their field maps. The comparison
5653 : // below is safe, since we keep the field maps sorted.
5654 42 : if (field_maps_.length() != info->field_maps_.length()) return false;
5655 42 : for (int i = 0; i < field_maps_.length(); ++i) {
5656 0 : if (!field_maps_.at(i).is_identical_to(info->field_maps_.at(i))) {
5657 : return false;
5658 : }
5659 : }
5660 : }
5661 3428 : info->GeneralizeRepresentation(r);
5662 3428 : info->field_type_ = info->field_type_.Combine(field_type_);
5663 3428 : return true;
5664 : }
5665 :
5666 :
5667 322146 : bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() {
5668 322146 : if (!map_->IsJSObjectMap()) return true;
5669 301507 : LookupDescriptor(*map_, *name_);
5670 301507 : return LoadResult(map_);
5671 : }
5672 :
5673 :
5674 481666 : bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) {
5675 437086 : if (!IsLoad() && IsProperty() && IsReadOnly()) {
5676 : return false;
5677 : }
5678 :
5679 380966 : if (IsData()) {
5680 : // Construct the object field access.
5681 96950 : int index = GetLocalFieldIndexFromMap(map);
5682 96950 : access_ = HObjectAccess::ForField(map, index, representation(), name_);
5683 :
5684 : // Load field map for heap objects.
5685 96950 : return LoadFieldMaps(map);
5686 284016 : } else if (IsAccessorConstant()) {
5687 : Handle<Object> accessors = GetAccessorsFromMap(map);
5688 12143 : if (!accessors->IsAccessorPair()) return false;
5689 : Object* raw_accessor =
5690 : IsLoad() ? Handle<AccessorPair>::cast(accessors)->getter()
5691 3702 : : Handle<AccessorPair>::cast(accessors)->setter();
5692 3820 : if (!raw_accessor->IsJSFunction() &&
5693 : !raw_accessor->IsFunctionTemplateInfo())
5694 : return false;
5695 : Handle<Object> accessor = handle(HeapObject::cast(raw_accessor));
5696 3603 : CallOptimization call_optimization(accessor);
5697 3603 : if (call_optimization.is_simple_api_call()) {
5698 : CallOptimization::HolderLookup holder_lookup;
5699 : api_holder_ =
5700 50 : call_optimization.LookupHolderOfExpectedType(map_, &holder_lookup);
5701 : }
5702 3603 : accessor_ = accessor;
5703 276143 : } else if (IsDataConstant()) {
5704 193730 : constant_ = GetConstantFromMap(map);
5705 : }
5706 :
5707 : return true;
5708 : }
5709 :
5710 :
5711 112843 : bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadFieldMaps(
5712 148783 : Handle<Map> map) {
5713 : // Clear any previously collected field maps/type.
5714 : field_maps_.Clear();
5715 112843 : field_type_ = HType::Tagged();
5716 :
5717 : // Figure out the field type from the accessor map.
5718 112843 : Handle<FieldType> field_type = GetFieldTypeFromMap(map);
5719 :
5720 : // Collect the (stable) maps from the field type.
5721 112843 : if (field_type->IsClass()) {
5722 : DCHECK(access_.representation().IsHeapObject());
5723 13231 : Handle<Map> field_map = field_type->AsClass();
5724 13231 : if (field_map->is_stable()) {
5725 : field_maps_.Add(field_map, zone());
5726 : }
5727 : }
5728 :
5729 112843 : if (field_maps_.is_empty()) {
5730 : // Store is not safe if the field map was cleared.
5731 132299 : return IsLoad() || !field_type->IsNone();
5732 : }
5733 :
5734 : // Determine field HType from field type.
5735 11980 : field_type_ = HType::FromFieldType(field_type, zone());
5736 : DCHECK(field_type_.IsHeapObject());
5737 :
5738 : // Add dependency on the map that introduced the field.
5739 23960 : top_info()->dependencies()->AssumeFieldOwner(GetFieldOwnerFromMap(map));
5740 11980 : return true;
5741 : }
5742 :
5743 :
5744 227990 : bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
5745 98493 : Handle<Map> map = this->map();
5746 98493 : if (name_->IsPrivate()) {
5747 : NotFound();
5748 105 : return !map->has_hidden_prototype();
5749 : }
5750 :
5751 148378 : while (map->prototype()->IsJSObject()) {
5752 130283 : holder_ = handle(JSObject::cast(map->prototype()));
5753 130283 : if (holder_->map()->is_deprecated()) {
5754 0 : JSObject::TryMigrateInstance(holder_);
5755 : }
5756 : map = Handle<Map>(holder_->map());
5757 130283 : if (!CanInlinePropertyAccess(map)) {
5758 : NotFound();
5759 786 : return false;
5760 : }
5761 129497 : LookupDescriptor(*map, *name_);
5762 129497 : if (IsFound()) return LoadResult(map);
5763 : }
5764 :
5765 : NotFound();
5766 18095 : return !map->prototype()->IsJSReceiver();
5767 : }
5768 :
5769 :
5770 99325 : bool HOptimizedGraphBuilder::PropertyAccessInfo::IsIntegerIndexedExotic() {
5771 : InstanceType instance_type = map_->instance_type();
5772 100132 : return instance_type == JS_TYPED_ARRAY_TYPE && name_->IsString() &&
5773 99325 : IsSpecialIndex(isolate()->unicode_cache(), String::cast(*name_));
5774 : }
5775 :
5776 :
5777 1005107 : bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() {
5778 341502 : if (!CanInlinePropertyAccess(map_)) return false;
5779 352937 : if (IsJSObjectFieldAccessor()) return IsLoad();
5780 382612 : if (map_->IsJSFunctionMap() && map_->is_constructor() &&
5781 344175 : !map_->has_non_instance_prototype() &&
5782 : name_.is_identical_to(isolate()->factory()->prototype_string())) {
5783 6119 : return IsLoad();
5784 : }
5785 310510 : if (!LookupDescriptor()) return false;
5786 528899 : if (IsFound()) return IsLoad() || !IsReadOnly();
5787 98520 : if (IsIntegerIndexedExotic()) return false;
5788 98493 : if (!LookupInPrototypes()) return false;
5789 97584 : if (IsLoad()) return true;
5790 :
5791 17761 : if (IsAccessorConstant()) return true;
5792 17623 : LookupTransition(*map_, *name_, NONE);
5793 34923 : if (IsTransitionToData() && map_->unused_property_fields() > 0) {
5794 : // Construct the object field access.
5795 : int descriptor = transition()->LastAdded();
5796 : int index =
5797 : transition()->instance_descriptors()->GetFieldIndex(descriptor) -
5798 15893 : map_->GetInObjectProperties();
5799 : PropertyDetails details =
5800 15893 : transition()->instance_descriptors()->GetDetails(descriptor);
5801 15893 : Representation representation = details.representation();
5802 15893 : access_ = HObjectAccess::ForField(map_, index, representation, name_);
5803 :
5804 : // Load field map for heap objects.
5805 15893 : return LoadFieldMaps(transition());
5806 : }
5807 : return false;
5808 : }
5809 :
5810 :
5811 289283 : bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessAsMonomorphic(
5812 267499 : SmallMapList* maps) {
5813 : DCHECK(map_.is_identical_to(maps->first()));
5814 289283 : if (!CanAccessMonomorphic()) return false;
5815 : STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism);
5816 284846 : if (maps->length() > kMaxLoadPolymorphism) return false;
5817 284846 : HObjectAccess access = HObjectAccess::ForMap(); // bogus default
5818 284846 : if (GetJSObjectFieldAccess(&access)) {
5819 19839 : for (int i = 1; i < maps->length(); ++i) {
5820 1850 : PropertyAccessInfo test_info(builder_, access_type_, maps->at(i), name_);
5821 3689 : HObjectAccess test_access = HObjectAccess::ForMap(); // bogus default
5822 2075 : if (!test_info.GetJSObjectFieldAccess(&test_access)) return false;
5823 3678 : if (!access.Equals(test_access)) return false;
5824 : }
5825 : return true;
5826 : }
5827 :
5828 : // Currently only handle numbers as a polymorphic case.
5829 : // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber
5830 : // instruction.
5831 268257 : if (IsNumberType()) return false;
5832 :
5833 : // Multiple maps cannot transition to the same target map.
5834 : DCHECK(!IsLoad() || !IsTransition());
5835 276718 : if (IsTransition() && maps->length() > 1) return false;
5836 :
5837 277796 : for (int i = 1; i < maps->length(); ++i) {
5838 11697 : PropertyAccessInfo test_info(builder_, access_type_, maps->at(i), name_);
5839 11697 : if (!test_info.IsCompatible(this)) return false;
5840 : }
5841 :
5842 : return true;
5843 : }
5844 :
5845 :
5846 187321 : Handle<Map> HOptimizedGraphBuilder::PropertyAccessInfo::map() {
5847 : Handle<JSFunction> ctor;
5848 187321 : if (Map::GetConstructorFunction(
5849 : map_, handle(current_info()->closure()->context()->native_context()))
5850 374642 : .ToHandle(&ctor)) {
5851 : return handle(ctor->initial_map());
5852 : }
5853 156575 : return map_;
5854 : }
5855 :
5856 :
5857 : static bool NeedsWrapping(Handle<Map> map, Handle<JSFunction> target) {
5858 8979 : return !map->IsJSObjectMap() &&
5859 70762 : is_sloppy(target->shared()->language_mode()) &&
5860 : !target->shared()->native();
5861 : }
5862 :
5863 :
5864 4850 : bool HOptimizedGraphBuilder::PropertyAccessInfo::NeedsWrappingFor(
5865 : Handle<JSFunction> target) const {
5866 4850 : return NeedsWrapping(map_, target);
5867 : }
5868 :
5869 :
5870 202199 : HValue* HOptimizedGraphBuilder::BuildMonomorphicAccess(
5871 347891 : PropertyAccessInfo* info, HValue* object, HValue* checked_object,
5872 : HValue* value, BailoutId ast_id, BailoutId return_id,
5873 1121 : bool can_inline_accessor) {
5874 202199 : HObjectAccess access = HObjectAccess::ForMap(); // bogus default
5875 202199 : if (info->GetJSObjectFieldAccess(&access)) {
5876 : DCHECK(info->IsLoad());
5877 22500 : return New<HLoadNamedField>(object, checked_object, access);
5878 : }
5879 :
5880 191225 : if (info->name().is_identical_to(isolate()->factory()->prototype_string()) &&
5881 197310 : info->map()->IsJSFunctionMap() && info->map()->is_constructor()) {
5882 : DCHECK(!info->map()->has_non_instance_prototype());
5883 6085 : return New<HLoadFunctionPrototype>(checked_object);
5884 : }
5885 :
5886 : HValue* checked_holder = checked_object;
5887 179055 : if (info->has_holder()) {
5888 99140 : Handle<JSObject> prototype(JSObject::cast(info->map()->prototype()));
5889 49570 : checked_holder = BuildCheckPrototypeMaps(prototype, info->holder());
5890 : }
5891 :
5892 179055 : if (!info->IsFound()) {
5893 : DCHECK(info->IsLoad());
5894 2129 : return graph()->GetConstantUndefined();
5895 : }
5896 :
5897 176926 : if (info->IsData()) {
5898 64955 : if (info->IsLoad()) {
5899 54111 : return BuildLoadNamedField(info, checked_holder);
5900 : } else {
5901 10844 : return BuildStoreNamedField(info, checked_object, value);
5902 : }
5903 : }
5904 :
5905 111971 : if (info->IsTransition()) {
5906 : DCHECK(!info->IsLoad());
5907 11394 : return BuildStoreNamedField(info, checked_object, value);
5908 : }
5909 :
5910 100577 : if (info->IsAccessorConstant()) {
5911 : MaybeHandle<Name> maybe_name =
5912 : FunctionTemplateInfo::TryGetCachedPropertyName(isolate(),
5913 3312 : info->accessor());
5914 3312 : if (!maybe_name.is_null()) {
5915 4 : Handle<Name> name = maybe_name.ToHandleChecked();
5916 4 : PropertyAccessInfo cache_info(this, LOAD, info->map(), name);
5917 : // Load new target.
5918 4 : if (cache_info.CanAccessMonomorphic()) {
5919 4 : return BuildLoadNamedField(&cache_info, checked_object);
5920 : }
5921 : }
5922 :
5923 3308 : Push(checked_object);
5924 : int argument_count = 1;
5925 3308 : if (!info->IsLoad()) {
5926 : argument_count = 2;
5927 246 : Push(value);
5928 : }
5929 :
5930 6601 : if (info->accessor()->IsJSFunction() &&
5931 3293 : info->NeedsWrappingFor(Handle<JSFunction>::cast(info->accessor()))) {
5932 0 : HValue* function = Add<HConstant>(info->accessor());
5933 0 : PushArgumentsFromEnvironment(argument_count);
5934 : return NewCallFunction(function, argument_count, TailCallMode::kDisallow,
5935 : ConvertReceiverMode::kNotNullOrUndefined,
5936 0 : TailCallMode::kDisallow);
5937 3308 : } else if (FLAG_inline_accessors && can_inline_accessor) {
5938 : bool success = info->IsLoad()
5939 3062 : ? TryInlineGetter(info->accessor(), info->map(), ast_id, return_id)
5940 : : TryInlineSetter(
5941 6370 : info->accessor(), info->map(), ast_id, return_id, value);
5942 4429 : if (success || HasStackOverflow()) return NULL;
5943 : }
5944 :
5945 1121 : PushArgumentsFromEnvironment(argument_count);
5946 1121 : if (!info->accessor()->IsJSFunction()) {
5947 : Bailout(kInliningBailedOut);
5948 0 : return nullptr;
5949 : }
5950 : return NewCallConstantFunction(Handle<JSFunction>::cast(info->accessor()),
5951 : argument_count, TailCallMode::kDisallow,
5952 1121 : TailCallMode::kDisallow);
5953 : }
5954 :
5955 : DCHECK(info->IsDataConstant());
5956 97265 : if (info->IsLoad()) {
5957 97251 : return New<HConstant>(info->constant());
5958 : } else {
5959 14 : return New<HCheckValue>(value, Handle<JSFunction>::cast(info->constant()));
5960 : }
5961 : }
5962 :
5963 10862 : void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess(
5964 : PropertyAccessType access_type, Expression* expr, FeedbackSlot slot,
5965 : BailoutId ast_id, BailoutId return_id, HValue* object, HValue* value,
5966 31646 : SmallMapList* maps, Handle<Name> name) {
5967 : // Something did not match; must use a polymorphic load.
5968 : int count = 0;
5969 : HBasicBlock* join = NULL;
5970 : HBasicBlock* number_block = NULL;
5971 : bool handled_string = false;
5972 :
5973 : bool handle_smi = false;
5974 : STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism);
5975 : int i;
5976 63514 : for (i = 0; i < maps->length() && count < kMaxLoadPolymorphism; ++i) {
5977 20937 : PropertyAccessInfo info(this, access_type, maps->at(i), name);
5978 20937 : if (info.IsStringType()) {
5979 35 : if (handled_string) continue;
5980 : handled_string = true;
5981 : }
5982 20937 : if (info.CanAccessMonomorphic()) {
5983 16558 : count++;
5984 16558 : if (info.IsNumberType()) {
5985 : handle_smi = true;
5986 42 : break;
5987 : }
5988 : }
5989 : }
5990 :
5991 10862 : if (i < maps->length()) {
5992 : count = -1;
5993 : maps->Clear();
5994 : } else {
5995 : count = 0;
5996 : }
5997 : HControlInstruction* smi_check = NULL;
5998 : handled_string = false;
5999 :
6000 52652 : for (i = 0; i < maps->length() && count < kMaxLoadPolymorphism; ++i) {
6001 20895 : PropertyAccessInfo info(this, access_type, maps->at(i), name);
6002 20895 : if (info.IsStringType()) {
6003 4414 : if (handled_string) continue;
6004 : handled_string = true;
6005 : }
6006 20895 : if (!info.CanAccessMonomorphic()) continue;
6007 :
6008 16516 : if (count == 0) {
6009 56449 : join = graph()->CreateBasicBlock();
6010 6901 : if (handle_smi) {
6011 0 : HBasicBlock* empty_smi_block = graph()->CreateBasicBlock();
6012 0 : HBasicBlock* not_smi_block = graph()->CreateBasicBlock();
6013 0 : number_block = graph()->CreateBasicBlock();
6014 : smi_check = New<HIsSmiAndBranch>(
6015 0 : object, empty_smi_block, not_smi_block);
6016 0 : FinishCurrentBlock(smi_check);
6017 : GotoNoSimulate(empty_smi_block, number_block);
6018 : set_current_block(not_smi_block);
6019 : } else {
6020 6901 : BuildCheckHeapObject(object);
6021 : }
6022 : }
6023 16516 : ++count;
6024 16516 : HBasicBlock* if_true = graph()->CreateBasicBlock();
6025 16516 : HBasicBlock* if_false = graph()->CreateBasicBlock();
6026 : HUnaryControlInstruction* compare;
6027 :
6028 : HValue* dependency;
6029 16516 : if (info.IsNumberType()) {
6030 0 : Handle<Map> heap_number_map = isolate()->factory()->heap_number_map();
6031 0 : compare = New<HCompareMap>(object, heap_number_map, if_true, if_false);
6032 : dependency = smi_check;
6033 16516 : } else if (info.IsStringType()) {
6034 22 : compare = New<HIsStringAndBranch>(object, if_true, if_false);
6035 : dependency = compare;
6036 : } else {
6037 16494 : compare = New<HCompareMap>(object, info.map(), if_true, if_false);
6038 : dependency = compare;
6039 : }
6040 16516 : FinishCurrentBlock(compare);
6041 :
6042 16516 : if (info.IsNumberType()) {
6043 : GotoNoSimulate(if_true, number_block);
6044 : if_true = number_block;
6045 : }
6046 :
6047 : set_current_block(if_true);
6048 :
6049 : HValue* access =
6050 : BuildMonomorphicAccess(&info, object, dependency, value, ast_id,
6051 16516 : return_id, FLAG_polymorphic_inlining);
6052 :
6053 : HValue* result = NULL;
6054 16516 : switch (access_type) {
6055 : case LOAD:
6056 : result = access;
6057 10466 : break;
6058 : case STORE:
6059 : result = value;
6060 6050 : break;
6061 : }
6062 :
6063 16516 : if (access == NULL) {
6064 119 : if (HasStackOverflow()) return;
6065 : } else {
6066 16397 : if (access->IsInstruction()) {
6067 : HInstruction* instr = HInstruction::cast(access);
6068 16397 : if (!instr->IsLinked()) AddInstruction(instr);
6069 : }
6070 16397 : if (!ast_context()->IsEffect()) Push(result);
6071 : }
6072 :
6073 16516 : if (current_block() != NULL) Goto(join);
6074 : set_current_block(if_false);
6075 : }
6076 :
6077 : // Finish up. Unconditionally deoptimize if we've handled all the maps we
6078 : // know about and do not want to handle ones we've never seen. Otherwise
6079 : // use a generic IC.
6080 10862 : if (count == maps->length() && FLAG_deoptimize_uncommon_cases) {
6081 : FinishExitWithHardDeoptimization(
6082 6589 : DeoptimizeReason::kUnknownMapInPolymorphicAccess);
6083 : } else {
6084 : HInstruction* instr =
6085 4273 : BuildNamedGeneric(access_type, expr, slot, object, name, value);
6086 4273 : AddInstruction(instr);
6087 4273 : if (!ast_context()->IsEffect()) Push(access_type == LOAD ? instr : value);
6088 :
6089 4273 : if (join != NULL) {
6090 : Goto(join);
6091 : } else {
6092 3961 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6093 7034 : if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
6094 : return;
6095 : }
6096 : }
6097 :
6098 : DCHECK(join != NULL);
6099 6901 : if (join->HasPredecessor()) {
6100 : join->SetJoinId(ast_id);
6101 : set_current_block(join);
6102 11628 : if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
6103 : } else {
6104 : set_current_block(NULL);
6105 : }
6106 : }
6107 :
6108 805234 : static bool ComputeReceiverTypes(Expression* expr, HValue* receiver,
6109 : SmallMapList** t,
6110 : HOptimizedGraphBuilder* builder) {
6111 870295 : Zone* zone = builder->zone();
6112 805234 : SmallMapList* maps = expr->GetReceiverTypes();
6113 805234 : *t = maps;
6114 805234 : bool monomorphic = expr->IsMonomorphic();
6115 805234 : if (maps != nullptr && receiver->HasMonomorphicJSObjectType()) {
6116 169495 : if (maps->length() > 0) {
6117 208928 : Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap();
6118 104464 : maps->FilterForPossibleTransitions(root_map);
6119 104464 : monomorphic = maps->length() == 1;
6120 : } else {
6121 : // No type feedback, see if we can infer the type. This is safely
6122 : // possible if the receiver had a known map at some point, and no
6123 : // map-changing stores have happened to it since.
6124 65031 : Handle<Map> candidate_map = receiver->GetMonomorphicJSObjectMap();
6125 89968 : for (HInstruction* current = builder->current_block()->last();
6126 : current != nullptr; current = current->previous()) {
6127 172156 : if (current->IsBlockEntry()) break;
6128 84593 : if (current->CheckChangesFlag(kMaps)) {
6129 : // Only allow map changes that store the candidate map. We don't
6130 : // need to care which object the map is being written into.
6131 7241 : if (!current->IsStoreNamedField()) break;
6132 : HStoreNamedField* map_change = HStoreNamedField::cast(current);
6133 30 : if (!map_change->value()->IsConstant()) break;
6134 : HConstant* map_constant = HConstant::cast(map_change->value());
6135 30 : if (!map_constant->representation().IsTagged()) break;
6136 30 : Handle<Object> map = map_constant->handle(builder->isolate());
6137 30 : if (!map.is_identical_to(candidate_map)) break;
6138 : }
6139 77371 : if (current == receiver) {
6140 : // We made it all the way back to the receiver without encountering
6141 : // a map change! So we can assume that the receiver still has the
6142 : // candidate_map we know about.
6143 : maps->Add(candidate_map, zone);
6144 : monomorphic = true;
6145 52434 : break;
6146 : }
6147 : }
6148 : }
6149 : }
6150 1103329 : return monomorphic && CanInlinePropertyAccess(maps->first());
6151 : }
6152 :
6153 :
6154 179530 : static bool AreStringTypes(SmallMapList* maps) {
6155 387468 : for (int i = 0; i < maps->length(); i++) {
6156 179938 : if (maps->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false;
6157 : }
6158 : return true;
6159 : }
6160 :
6161 132248 : void HOptimizedGraphBuilder::BuildStore(Expression* expr, Property* prop,
6162 : FeedbackSlot slot, BailoutId ast_id,
6163 : BailoutId return_id,
6164 211858 : bool is_uninitialized) {
6165 73969 : if (!prop->key()->IsPropertyName()) {
6166 : // Keyed store.
6167 : HValue* value = Pop();
6168 : HValue* key = Pop();
6169 : HValue* object = Pop();
6170 15690 : bool has_side_effects = false;
6171 : HValue* result =
6172 : HandleKeyedElementAccess(object, key, value, expr, slot, ast_id,
6173 15690 : return_id, STORE, &has_side_effects);
6174 15690 : if (has_side_effects) {
6175 15581 : if (!ast_context()->IsEffect()) Push(value);
6176 15581 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6177 15581 : if (!ast_context()->IsEffect()) Drop(1);
6178 : }
6179 15690 : if (result == NULL) return;
6180 15621 : return ast_context()->ReturnValue(value);
6181 : }
6182 :
6183 : // Named store.
6184 : HValue* value = Pop();
6185 : HValue* object = Pop();
6186 :
6187 116558 : Literal* key = prop->key()->AsLiteral();
6188 : Handle<String> name = Handle<String>::cast(key->value());
6189 : DCHECK(!name.is_null());
6190 :
6191 : HValue* access = BuildNamedAccess(STORE, ast_id, return_id, expr, slot,
6192 116558 : object, name, value, is_uninitialized);
6193 58279 : if (access == NULL) return;
6194 :
6195 55025 : if (!ast_context()->IsEffect()) Push(value);
6196 55025 : if (access->IsInstruction()) AddInstruction(HInstruction::cast(access));
6197 55025 : if (access->HasObservableSideEffects()) {
6198 55011 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6199 : }
6200 55025 : if (!ast_context()->IsEffect()) Drop(1);
6201 55025 : return ast_context()->ReturnValue(value);
6202 : }
6203 :
6204 :
6205 375589 : void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
6206 231491 : Property* prop = expr->target()->AsProperty();
6207 : DCHECK(prop != NULL);
6208 231461 : CHECK_ALIVE(VisitForValue(prop->obj()));
6209 72066 : if (!prop->key()->IsPropertyName()) {
6210 45677 : CHECK_ALIVE(VisitForValue(prop->key()));
6211 : }
6212 216164 : CHECK_ALIVE(VisitForValue(expr->value()));
6213 : BuildStore(expr, prop, expr->AssignmentSlot(), expr->id(),
6214 144080 : expr->AssignmentId(), expr->IsUninitialized());
6215 : }
6216 :
6217 10042 : HInstruction* HOptimizedGraphBuilder::InlineGlobalPropertyStore(
6218 : LookupIterator* it, HValue* value, BailoutId ast_id) {
6219 10042 : Handle<PropertyCell> cell = it->GetPropertyCell();
6220 14071 : top_info()->dependencies()->AssumePropertyCell(cell);
6221 : auto cell_type = it->property_details().cell_type();
6222 10042 : if (cell_type == PropertyCellType::kConstant ||
6223 : cell_type == PropertyCellType::kUndefined) {
6224 : Handle<Object> constant(cell->value(), isolate());
6225 2467 : if (value->IsConstant()) {
6226 : HConstant* c_value = HConstant::cast(value);
6227 2340 : if (!constant.is_identical_to(c_value->handle(isolate()))) {
6228 : Add<HDeoptimize>(DeoptimizeReason::kConstantGlobalVariableAssignment,
6229 923 : Deoptimizer::EAGER);
6230 : }
6231 : } else {
6232 1297 : HValue* c_constant = Add<HConstant>(constant);
6233 : IfBuilder builder(this);
6234 1297 : if (constant->IsNumber()) {
6235 776 : builder.If<HCompareNumericAndBranch>(value, c_constant, Token::EQ);
6236 : } else {
6237 521 : builder.If<HCompareObjectEqAndBranch>(value, c_constant);
6238 : }
6239 1297 : builder.Then();
6240 : builder.Else();
6241 : Add<HDeoptimize>(DeoptimizeReason::kConstantGlobalVariableAssignment,
6242 1297 : Deoptimizer::EAGER);
6243 1297 : builder.End();
6244 : }
6245 : }
6246 10042 : HConstant* cell_constant = Add<HConstant>(cell);
6247 10042 : auto access = HObjectAccess::ForPropertyCellValue();
6248 10042 : if (cell_type == PropertyCellType::kConstantType) {
6249 4145 : switch (cell->GetConstantType()) {
6250 : case PropertyCellConstantType::kSmi:
6251 3753 : access = access.WithRepresentation(Representation::Smi());
6252 3753 : break;
6253 : case PropertyCellConstantType::kStableMap: {
6254 : // First check that the previous value of the {cell} still has the
6255 : // map that we are about to check the new {value} for. If not, then
6256 : // the stable map assumption was invalidated and we cannot continue
6257 : // with the optimized code.
6258 : Handle<HeapObject> cell_value(HeapObject::cast(cell->value()));
6259 : Handle<Map> cell_value_map(cell_value->map());
6260 392 : if (!cell_value_map->is_stable()) {
6261 : Bailout(kUnstableConstantTypeHeapObject);
6262 : return nullptr;
6263 : }
6264 392 : top_info()->dependencies()->AssumeMapStable(cell_value_map);
6265 : // Now check that the new {value} is a HeapObject with the same map
6266 392 : Add<HCheckHeapObject>(value);
6267 392 : value = Add<HCheckMaps>(value, cell_value_map);
6268 392 : access = access.WithRepresentation(Representation::HeapObject());
6269 : break;
6270 : }
6271 : }
6272 : }
6273 10042 : HInstruction* instr = New<HStoreNamedField>(cell_constant, access, value);
6274 : instr->ClearChangesFlag(kInobjectFields);
6275 : instr->SetChangesFlag(kGlobalVars);
6276 10042 : return instr;
6277 : }
6278 :
6279 : // Because not every expression has a position and there is not common
6280 : // superclass of Assignment and CountOperation, we cannot just pass the
6281 : // owning expression instead of position and ast_id separately.
6282 74651 : void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(Variable* var,
6283 : HValue* value,
6284 : FeedbackSlot slot,
6285 : BailoutId ast_id) {
6286 21179 : Handle<JSGlobalObject> global(current_info()->global_object());
6287 :
6288 : // Lookup in script contexts.
6289 : {
6290 : Handle<ScriptContextTable> script_contexts(
6291 : global->native_context()->script_context_table());
6292 : ScriptContextTable::LookupResult lookup;
6293 21179 : if (ScriptContextTable::Lookup(script_contexts, var->name(), &lookup)) {
6294 18 : if (lookup.mode == CONST) {
6295 : return Bailout(kNonInitializerAssignmentToConst);
6296 : }
6297 : Handle<Context> script_context =
6298 16 : ScriptContextTable::GetContext(script_contexts, lookup.context_index);
6299 :
6300 : Handle<Object> current_value =
6301 22312 : FixedArray::get(*script_context, lookup.slot_index, isolate());
6302 :
6303 : // If the values is not the hole, it will stay initialized,
6304 : // so no need to generate a check.
6305 16 : if (current_value->IsTheHole(isolate())) {
6306 : return Bailout(kReferenceToUninitializedVariable);
6307 : }
6308 :
6309 : HStoreNamedField* instr = Add<HStoreNamedField>(
6310 : Add<HConstant>(script_context),
6311 15 : HObjectAccess::ForContextSlot(lookup.slot_index), value);
6312 : USE(instr);
6313 : DCHECK(instr->HasObservableSideEffects());
6314 15 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6315 15 : return;
6316 : }
6317 : }
6318 :
6319 21161 : LookupIterator it(global, var->name(), LookupIterator::OWN);
6320 21161 : if (CanInlineGlobalPropertyAccess(var, &it, STORE)) {
6321 10029 : HInstruction* instr = InlineGlobalPropertyStore(&it, value, ast_id);
6322 10029 : if (!instr) return;
6323 10029 : AddInstruction(instr);
6324 10029 : if (instr->HasObservableSideEffects()) {
6325 10029 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6326 : }
6327 : } else {
6328 : HValue* global_object = Add<HLoadNamedField>(
6329 : BuildGetNativeContext(), nullptr,
6330 11132 : HObjectAccess::ForContextSlot(Context::EXTENSION_INDEX));
6331 : Handle<FeedbackVector> vector =
6332 11132 : handle(current_feedback_vector(), isolate());
6333 11132 : HValue* name = Add<HConstant>(var->name());
6334 11132 : HValue* vector_value = Add<HConstant>(vector);
6335 11132 : HValue* slot_value = Add<HConstant>(vector->GetIndex(slot));
6336 : DCHECK(vector->IsStoreGlobalIC(slot));
6337 : DCHECK_EQ(vector->GetLanguageMode(slot), function_language_mode());
6338 : Callable callable = CodeFactory::StoreGlobalICInOptimizedCode(
6339 11132 : isolate(), function_language_mode());
6340 11132 : HValue* stub = Add<HConstant>(callable.code());
6341 11132 : HValue* values[] = {global_object, name, value, slot_value, vector_value};
6342 : HCallWithDescriptor* instr =
6343 : Add<HCallWithDescriptor>(Code::STORE_GLOBAL_IC, stub, 0,
6344 11132 : callable.descriptor(), ArrayVector(values));
6345 : USE(instr);
6346 : DCHECK(instr->HasObservableSideEffects());
6347 11132 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6348 : }
6349 : }
6350 :
6351 :
6352 110515 : void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
6353 : Expression* target = expr->target();
6354 54738 : VariableProxy* proxy = target->AsVariableProxy();
6355 996 : Property* prop = target->AsProperty();
6356 : DCHECK(proxy == NULL || prop == NULL);
6357 :
6358 : // We have a second position recorded in the FullCodeGenerator to have
6359 : // type feedback for the binary operation.
6360 : BinaryOperation* operation = expr->binary_operation();
6361 :
6362 27535 : if (proxy != NULL) {
6363 55173 : Variable* var = proxy->var();
6364 27203 : if (var->mode() == LET) {
6365 : return Bailout(kUnsupportedLetCompoundAssignment);
6366 : }
6367 :
6368 55402 : CHECK_ALIVE(VisitForValue(operation));
6369 :
6370 27065 : switch (var->location()) {
6371 : case VariableLocation::UNALLOCATED:
6372 : HandleGlobalVariableAssignment(var, Top(), expr->AssignmentSlot(),
6373 1909 : expr->AssignmentId());
6374 1909 : break;
6375 :
6376 : case VariableLocation::PARAMETER:
6377 : case VariableLocation::LOCAL:
6378 24426 : if (var->mode() == CONST) {
6379 : return Bailout(kNonInitializerAssignmentToConst);
6380 : }
6381 24376 : BindIfLive(var, Top());
6382 24376 : break;
6383 :
6384 : case VariableLocation::CONTEXT: {
6385 : // Bail out if we try to mutate a parameter value in a function
6386 : // using the arguments object. We do not (yet) correctly handle the
6387 : // arguments property of the function.
6388 730 : if (current_info()->scope()->arguments() != NULL) {
6389 : // Parameters will be allocated to context slots. We have no
6390 : // direct way to detect that the variable is a parameter so we do
6391 : // a linear search of the parameter variables.
6392 2 : int count = current_info()->scope()->num_parameters();
6393 4 : for (int i = 0; i < count; ++i) {
6394 4 : if (var == current_info()->scope()->parameter(i)) {
6395 : Bailout(kAssignmentToParameterFunctionUsesArgumentsObject);
6396 : }
6397 : }
6398 : }
6399 :
6400 : HStoreContextSlot::Mode mode;
6401 :
6402 730 : switch (var->mode()) {
6403 : case LET:
6404 : mode = HStoreContextSlot::kCheckDeoptimize;
6405 : break;
6406 : case CONST:
6407 555 : if (var->throw_on_const_assignment(function_language_mode())) {
6408 : return Bailout(kNonInitializerAssignmentToConst);
6409 : } else {
6410 12 : return ast_context()->ReturnValue(Pop());
6411 : }
6412 : default:
6413 : mode = HStoreContextSlot::kNoCheck;
6414 : }
6415 :
6416 175 : HValue* context = BuildContextChainWalk(var);
6417 : HStoreContextSlot* instr = Add<HStoreContextSlot>(
6418 175 : context, var->index(), mode, Top());
6419 175 : if (instr->HasObservableSideEffects()) {
6420 175 : Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
6421 : }
6422 : break;
6423 : }
6424 :
6425 : case VariableLocation::LOOKUP:
6426 : return Bailout(kCompoundAssignmentToLookupSlot);
6427 :
6428 : case VariableLocation::MODULE:
6429 0 : UNREACHABLE();
6430 : }
6431 52920 : return ast_context()->ReturnValue(Pop());
6432 :
6433 332 : } else if (prop != NULL) {
6434 996 : CHECK_ALIVE(VisitForValue(prop->obj()));
6435 : HValue* object = Top();
6436 : HValue* key = NULL;
6437 432 : if (!prop->key()->IsPropertyName() || prop->IsStringAccess()) {
6438 696 : CHECK_ALIVE(VisitForValue(prop->key()));
6439 : key = Top();
6440 : }
6441 :
6442 996 : CHECK_ALIVE(PushLoad(prop, object, key));
6443 :
6444 996 : CHECK_ALIVE(VisitForValue(expr->value()));
6445 : HValue* right = Pop();
6446 : HValue* left = Pop();
6447 :
6448 332 : Push(BuildBinaryOperation(operation, left, right, PUSH_BEFORE_SIMULATE));
6449 :
6450 : BuildStore(expr, prop, expr->AssignmentSlot(), expr->id(),
6451 664 : expr->AssignmentId(), expr->IsUninitialized());
6452 : } else {
6453 : return Bailout(kInvalidLhsInCompoundAssignment);
6454 : }
6455 : }
6456 :
6457 :
6458 2869411 : void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) {
6459 : DCHECK(!HasStackOverflow());
6460 : DCHECK(current_block() != NULL);
6461 : DCHECK(current_block()->HasPredecessor());
6462 :
6463 1153710 : VariableProxy* proxy = expr->target()->AsVariableProxy();
6464 626672 : Property* prop = expr->target()->AsProperty();
6465 : DCHECK(proxy == NULL || prop == NULL);
6466 :
6467 626672 : if (expr->is_compound()) {
6468 27535 : HandleCompoundAssignment(expr);
6469 27535 : return;
6470 : }
6471 :
6472 599137 : if (prop != NULL) {
6473 72099 : HandlePropertyAssignment(expr);
6474 527038 : } else if (proxy != NULL) {
6475 573553 : Variable* var = proxy->var();
6476 :
6477 527038 : if (var->mode() == CONST) {
6478 66930 : if (expr->op() != Token::INIT) {
6479 626 : if (var->throw_on_const_assignment(function_language_mode())) {
6480 : return Bailout(kNonInitializerAssignmentToConst);
6481 : } else {
6482 524206 : CHECK_ALIVE(VisitForValue(expr->value()));
6483 6 : return ast_context()->ReturnValue(Pop());
6484 : }
6485 : }
6486 : }
6487 :
6488 : // Handle the assignment.
6489 526412 : switch (var->location()) {
6490 : case VariableLocation::UNALLOCATED:
6491 46452 : CHECK_ALIVE(VisitForValue(expr->value()));
6492 : HandleGlobalVariableAssignment(var, Top(), expr->AssignmentSlot(),
6493 15480 : expr->AssignmentId());
6494 30960 : return ast_context()->ReturnValue(Pop());
6495 :
6496 : case VariableLocation::PARAMETER:
6497 : case VariableLocation::LOCAL: {
6498 : // Perform an initialization check for let declared variables
6499 : // or parameters.
6500 471279 : if (var->mode() == LET && expr->op() == Token::ASSIGN) {
6501 : HValue* env_value = environment()->Lookup(var);
6502 482 : if (env_value == graph()->GetConstantHole()) {
6503 : return Bailout(kAssignmentToLetVariableBeforeInitialization);
6504 : }
6505 : }
6506 : // We do not allow the arguments object to occur in a context where it
6507 : // may escape, but assignments to stack-allocated locals are
6508 : // permitted.
6509 1411216 : CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED));
6510 : HValue* value = Pop();
6511 468676 : BindIfLive(var, value);
6512 468676 : return ast_context()->ReturnValue(value);
6513 : }
6514 :
6515 : case VariableLocation::CONTEXT: {
6516 : // Bail out if we try to mutate a parameter value in a function using
6517 : // the arguments object. We do not (yet) correctly handle the
6518 : // arguments property of the function.
6519 39647 : if (current_info()->scope()->arguments() != NULL) {
6520 : // Parameters will rewrite to context slots. We have no direct way
6521 : // to detect that the variable is a parameter.
6522 17 : int count = current_info()->scope()->num_parameters();
6523 34 : for (int i = 0; i < count; ++i) {
6524 44 : if (var == current_info()->scope()->parameter(i)) {
6525 : return Bailout(kAssignmentToParameterInArgumentsObject);
6526 : }
6527 : }
6528 : }
6529 :
6530 118840 : CHECK_ALIVE(VisitForValue(expr->value()));
6531 : HStoreContextSlot::Mode mode;
6532 39556 : if (expr->op() == Token::ASSIGN) {
6533 6959 : switch (var->mode()) {
6534 : case LET:
6535 : mode = HStoreContextSlot::kCheckDeoptimize;
6536 : break;
6537 : case CONST:
6538 : // If we reached this point, the only possibility
6539 : // is a sloppy assignment to a function name.
6540 : DCHECK(function_language_mode() == SLOPPY &&
6541 : !var->throw_on_const_assignment(SLOPPY));
6542 0 : return ast_context()->ReturnValue(Pop());
6543 : default:
6544 : mode = HStoreContextSlot::kNoCheck;
6545 : }
6546 : } else {
6547 : DCHECK_EQ(Token::INIT, expr->op());
6548 : mode = HStoreContextSlot::kNoCheck;
6549 : }
6550 :
6551 39556 : HValue* context = BuildContextChainWalk(var);
6552 : HStoreContextSlot* instr = Add<HStoreContextSlot>(
6553 39556 : context, var->index(), mode, Top());
6554 39556 : if (instr->HasObservableSideEffects()) {
6555 39556 : Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
6556 : }
6557 79112 : return ast_context()->ReturnValue(Pop());
6558 : }
6559 :
6560 : case VariableLocation::LOOKUP:
6561 : return Bailout(kAssignmentToLOOKUPVariable);
6562 :
6563 : case VariableLocation::MODULE:
6564 0 : UNREACHABLE();
6565 : }
6566 : } else {
6567 : return Bailout(kInvalidLeftHandSideInAssignment);
6568 : }
6569 : }
6570 :
6571 0 : void HOptimizedGraphBuilder::VisitSuspend(Suspend* expr) {
6572 : // Generators are not optimized, so we should never get here.
6573 0 : UNREACHABLE();
6574 : }
6575 :
6576 :
6577 21371 : void HOptimizedGraphBuilder::VisitThrow(Throw* expr) {
6578 : DCHECK(!HasStackOverflow());
6579 : DCHECK(current_block() != NULL);
6580 : DCHECK(current_block()->HasPredecessor());
6581 7159 : if (!ast_context()->IsEffect()) {
6582 : // The parser turns invalid left-hand sides in assignments into throw
6583 : // statements, which may not be in effect contexts. We might still try
6584 : // to optimize such functions; bail out now if we do.
6585 : return Bailout(kInvalidLeftHandSideInAssignment);
6586 : }
6587 21318 : CHECK_ALIVE(VisitForValue(expr->exception()));
6588 :
6589 7106 : HValue* value = environment()->Pop();
6590 7106 : if (!is_tracking_positions()) SetSourcePosition(expr->position());
6591 7106 : Add<HPushArguments>(value);
6592 7106 : Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kThrow), 1);
6593 : Add<HSimulate>(expr->id());
6594 :
6595 : // If the throw definitely exits the function, we can finish with a dummy
6596 : // control flow at this point. This is not the case if the throw is inside
6597 : // an inlined function which may be replaced.
6598 7106 : if (call_context() == NULL) {
6599 4751 : FinishExitCurrentBlock(New<HAbnormalExit>());
6600 : }
6601 : }
6602 :
6603 :
6604 38052 : HInstruction* HGraphBuilder::AddLoadStringInstanceType(HValue* string) {
6605 38052 : if (string->IsConstant()) {
6606 : HConstant* c_string = HConstant::cast(string);
6607 11866 : if (c_string->HasStringValue()) {
6608 11866 : return Add<HConstant>(c_string->StringValue()->map()->instance_type());
6609 : }
6610 : }
6611 : return Add<HLoadNamedField>(
6612 : Add<HLoadNamedField>(string, nullptr, HObjectAccess::ForMap()), nullptr,
6613 26186 : HObjectAccess::ForMapInstanceType());
6614 : }
6615 :
6616 :
6617 62161 : HInstruction* HGraphBuilder::AddLoadStringLength(HValue* string) {
6618 62161 : return AddInstruction(BuildLoadStringLength(string));
6619 : }
6620 :
6621 :
6622 62161 : HInstruction* HGraphBuilder::BuildLoadStringLength(HValue* string) {
6623 62161 : if (string->IsConstant()) {
6624 : HConstant* c_string = HConstant::cast(string);
6625 23779 : if (c_string->HasStringValue()) {
6626 23779 : return New<HConstant>(c_string->StringValue()->length());
6627 : }
6628 : }
6629 : return New<HLoadNamedField>(string, nullptr,
6630 38382 : HObjectAccess::ForStringLength());
6631 : }
6632 :
6633 322529 : HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric(
6634 : PropertyAccessType access_type, Expression* expr, FeedbackSlot slot,
6635 : HValue* object, Handle<Name> name, HValue* value, bool is_uninitialized) {
6636 322529 : if (is_uninitialized) {
6637 : Add<HDeoptimize>(
6638 : DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess,
6639 507115 : Deoptimizer::SOFT);
6640 : }
6641 : Handle<FeedbackVector> vector(current_feedback_vector(), isolate());
6642 :
6643 322529 : HValue* key = Add<HConstant>(name);
6644 322529 : HValue* vector_value = Add<HConstant>(vector);
6645 322529 : HValue* slot_value = Add<HConstant>(vector->GetIndex(slot));
6646 :
6647 322529 : if (access_type == LOAD) {
6648 257512 : HValue* values[] = {object, key, slot_value, vector_value};
6649 515024 : if (!expr->AsProperty()->key()->IsPropertyName()) {
6650 : DCHECK(vector->IsKeyedLoadIC(slot));
6651 : // It's possible that a keyed load of a constant string was converted
6652 : // to a named load. Here, at the last minute, we need to make sure to
6653 : // use a generic Keyed Load if we are using the type vector, because
6654 : // it has to share information with full code.
6655 127 : Callable callable = CodeFactory::KeyedLoadICInOptimizedCode(isolate());
6656 127 : HValue* stub = Add<HConstant>(callable.code());
6657 : HCallWithDescriptor* result =
6658 : New<HCallWithDescriptor>(Code::KEYED_LOAD_IC, stub, 0,
6659 127 : callable.descriptor(), ArrayVector(values));
6660 : return result;
6661 : }
6662 : DCHECK(vector->IsLoadIC(slot));
6663 257385 : Callable callable = CodeFactory::LoadICInOptimizedCode(isolate());
6664 257385 : HValue* stub = Add<HConstant>(callable.code());
6665 : HCallWithDescriptor* result = New<HCallWithDescriptor>(
6666 257385 : Code::LOAD_IC, stub, 0, callable.descriptor(), ArrayVector(values));
6667 : return result;
6668 :
6669 : } else {
6670 65017 : HValue* values[] = {object, key, value, slot_value, vector_value};
6671 65017 : if (vector->IsKeyedStoreIC(slot)) {
6672 : // It's possible that a keyed store of a constant string was converted
6673 : // to a named store. Here, at the last minute, we need to make sure to
6674 : // use a generic Keyed Store if we are using the type vector, because
6675 : // it has to share information with full code.
6676 : DCHECK_EQ(vector->GetLanguageMode(slot), function_language_mode());
6677 : Callable callable = CodeFactory::KeyedStoreICInOptimizedCode(
6678 170 : isolate(), function_language_mode());
6679 170 : HValue* stub = Add<HConstant>(callable.code());
6680 : HCallWithDescriptor* result =
6681 : New<HCallWithDescriptor>(Code::KEYED_STORE_IC, stub, 0,
6682 170 : callable.descriptor(), ArrayVector(values));
6683 : return result;
6684 : }
6685 : HCallWithDescriptor* result;
6686 64847 : if (vector->IsStoreOwnIC(slot)) {
6687 18767 : Callable callable = CodeFactory::StoreOwnICInOptimizedCode(isolate());
6688 18767 : HValue* stub = Add<HConstant>(callable.code());
6689 : result = New<HCallWithDescriptor>(
6690 18767 : Code::STORE_IC, stub, 0, callable.descriptor(), ArrayVector(values));
6691 : } else {
6692 : DCHECK(vector->IsStoreIC(slot));
6693 : DCHECK_EQ(vector->GetLanguageMode(slot), function_language_mode());
6694 : Callable callable = CodeFactory::StoreICInOptimizedCode(
6695 46080 : isolate(), function_language_mode());
6696 46080 : HValue* stub = Add<HConstant>(callable.code());
6697 : result = New<HCallWithDescriptor>(
6698 46080 : Code::STORE_IC, stub, 0, callable.descriptor(), ArrayVector(values));
6699 : }
6700 64847 : return result;
6701 : }
6702 : }
6703 :
6704 95734 : HInstruction* HOptimizedGraphBuilder::BuildKeyedGeneric(
6705 : PropertyAccessType access_type, Expression* expr, FeedbackSlot slot,
6706 : HValue* object, HValue* key, HValue* value) {
6707 191468 : Handle<FeedbackVector> vector(current_feedback_vector(), isolate());
6708 95734 : HValue* vector_value = Add<HConstant>(vector);
6709 95734 : HValue* slot_value = Add<HConstant>(vector->GetIndex(slot));
6710 :
6711 95734 : if (access_type == LOAD) {
6712 72619 : HValue* values[] = {object, key, slot_value, vector_value};
6713 :
6714 72619 : Callable callable = CodeFactory::KeyedLoadICInOptimizedCode(isolate());
6715 72619 : HValue* stub = Add<HConstant>(callable.code());
6716 : HCallWithDescriptor* result =
6717 : New<HCallWithDescriptor>(Code::KEYED_LOAD_IC, stub, 0,
6718 72619 : callable.descriptor(), ArrayVector(values));
6719 : return result;
6720 : } else {
6721 23115 : HValue* values[] = {object, key, value, slot_value, vector_value};
6722 :
6723 : Callable callable = CodeFactory::KeyedStoreICInOptimizedCode(
6724 23115 : isolate(), function_language_mode());
6725 23115 : HValue* stub = Add<HConstant>(callable.code());
6726 : HCallWithDescriptor* result =
6727 : New<HCallWithDescriptor>(Code::KEYED_STORE_IC, stub, 0,
6728 23115 : callable.descriptor(), ArrayVector(values));
6729 : return result;
6730 : }
6731 : }
6732 :
6733 :
6734 24663 : LoadKeyedHoleMode HOptimizedGraphBuilder::BuildKeyedHoleMode(Handle<Map> map) {
6735 : // Loads from a "stock" fast holey double arrays can elide the hole check.
6736 : // Loads from a "stock" fast holey array can convert the hole to undefined
6737 : // with impunity.
6738 : LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE;
6739 : bool holey_double_elements =
6740 88895 : *map == isolate()->get_initial_js_array_map(FAST_HOLEY_DOUBLE_ELEMENTS);
6741 : bool holey_elements =
6742 24663 : *map == isolate()->get_initial_js_array_map(FAST_HOLEY_ELEMENTS);
6743 28439 : if ((holey_double_elements || holey_elements) &&
6744 3776 : isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
6745 : load_mode =
6746 3710 : holey_double_elements ? ALLOW_RETURN_HOLE : CONVERT_HOLE_TO_UNDEFINED;
6747 :
6748 : Handle<JSObject> prototype(JSObject::cast(map->prototype()), isolate());
6749 3710 : Handle<JSObject> object_prototype = isolate()->initial_object_prototype();
6750 3710 : BuildCheckPrototypeMaps(prototype, object_prototype);
6751 3710 : graph()->MarkDependsOnEmptyArrayProtoElements();
6752 : }
6753 24663 : return load_mode;
6754 : }
6755 :
6756 :
6757 22019 : HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess(
6758 : HValue* object,
6759 : HValue* key,
6760 : HValue* val,
6761 : HValue* dependency,
6762 : Handle<Map> map,
6763 : PropertyAccessType access_type,
6764 : KeyedAccessStoreMode store_mode) {
6765 22019 : HCheckMaps* checked_object = Add<HCheckMaps>(object, map, dependency);
6766 :
6767 26191 : if (access_type == STORE && map->prototype()->IsJSObject()) {
6768 : // monomorphic stores need a prototype chain check because shape
6769 : // changes could allow callbacks on elements in the chain that
6770 : // aren't compatible with monomorphic keyed stores.
6771 4077 : PrototypeIterator iter(map);
6772 : JSObject* holder = NULL;
6773 17766 : while (!iter.IsAtEnd()) {
6774 : // JSProxies can't occur here because we wouldn't have installed a
6775 : // non-generic IC if there were any.
6776 : holder = *PrototypeIterator::GetCurrent<JSObject>(iter);
6777 9612 : iter.Advance();
6778 : }
6779 : DCHECK(holder && holder->IsJSObject());
6780 :
6781 : BuildCheckPrototypeMaps(handle(JSObject::cast(map->prototype())),
6782 4077 : Handle<JSObject>(holder));
6783 : }
6784 :
6785 22019 : LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map);
6786 : return BuildUncheckedMonomorphicElementAccess(
6787 : checked_object, key, val,
6788 : map->instance_type() == JS_ARRAY_TYPE,
6789 : map->elements_kind(), access_type,
6790 22019 : load_mode, store_mode);
6791 : }
6792 :
6793 :
6794 32486 : static bool CanInlineElementAccess(Handle<Map> map) {
6795 32129 : return map->IsJSObjectMap() &&
6796 36158 : (map->has_fast_elements() || map->has_fixed_typed_array_elements()) &&
6797 64346 : !map->has_indexed_interceptor() && !map->is_access_check_needed();
6798 : }
6799 :
6800 :
6801 1801 : HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad(
6802 : HValue* object,
6803 : HValue* key,
6804 : HValue* val,
6805 : SmallMapList* maps) {
6806 : // For polymorphic loads of similar elements kinds (i.e. all tagged or all
6807 : // double), always use the "worst case" code without a transition. This is
6808 : // much faster than transitioning the elements to the worst case, trading a
6809 : // HTransitionElements for a HCheckMaps, and avoiding mutation of the array.
6810 : bool has_double_maps = false;
6811 : bool has_smi_or_object_maps = false;
6812 : bool has_js_array_access = false;
6813 : bool has_non_js_array_access = false;
6814 : bool has_seen_holey_elements = false;
6815 : Handle<Map> most_general_consolidated_map;
6816 9940 : for (int i = 0; i < maps->length(); ++i) {
6817 : Handle<Map> map = maps->at(i);
6818 3767 : if (!CanInlineElementAccess(map)) return NULL;
6819 : // Don't allow mixing of JSArrays with JSObjects.
6820 3632 : if (map->instance_type() == JS_ARRAY_TYPE) {
6821 3459 : if (has_non_js_array_access) return NULL;
6822 : has_js_array_access = true;
6823 173 : } else if (has_js_array_access) {
6824 : return NULL;
6825 : } else {
6826 : has_non_js_array_access = true;
6827 : }
6828 : // Don't allow mixed, incompatible elements kinds.
6829 3498 : if (map->has_fast_double_elements()) {
6830 371 : if (has_smi_or_object_maps) return NULL;
6831 : has_double_maps = true;
6832 3127 : } else if (map->has_fast_smi_or_object_elements()) {
6833 3103 : if (has_double_maps) return NULL;
6834 : has_smi_or_object_maps = true;
6835 : } else {
6836 : return NULL;
6837 : }
6838 : // Remember if we've ever seen holey elements.
6839 3169 : if (IsHoleyElementsKind(map->elements_kind())) {
6840 : has_seen_holey_elements = true;
6841 : }
6842 : // Remember the most general elements kind, the code for its load will
6843 : // properly handle all of the more specific cases.
6844 4685 : if ((i == 0) || IsMoreGeneralElementsKindTransition(
6845 : most_general_consolidated_map->elements_kind(),
6846 1516 : map->elements_kind())) {
6847 : most_general_consolidated_map = map;
6848 : }
6849 : }
6850 1203 : if (!has_double_maps && !has_smi_or_object_maps) return NULL;
6851 :
6852 3227 : HCheckMaps* checked_object = Add<HCheckMaps>(object, maps);
6853 : // FAST_ELEMENTS is considered more general than FAST_HOLEY_SMI_ELEMENTS.
6854 : // If we've seen both, the consolidated load must use FAST_HOLEY_ELEMENTS.
6855 : ElementsKind consolidated_elements_kind = has_seen_holey_elements
6856 : ? GetHoleyElementsKind(most_general_consolidated_map->elements_kind())
6857 1203 : : most_general_consolidated_map->elements_kind();
6858 : LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE;
6859 1203 : if (has_seen_holey_elements) {
6860 : // Make sure that all of the maps we are handling have the initial array
6861 : // prototype.
6862 : bool saw_non_array_prototype = false;
6863 1946 : for (int i = 0; i < maps->length(); ++i) {
6864 : Handle<Map> map = maps->at(i);
6865 2610 : if (map->prototype() != *isolate()->initial_array_prototype()) {
6866 : // We can't guarantee that loading the hole is safe. The prototype may
6867 : // have an element at this position.
6868 : saw_non_array_prototype = true;
6869 : break;
6870 : }
6871 : }
6872 :
6873 1070 : if (!saw_non_array_prototype) {
6874 : Handle<Map> holey_map = handle(
6875 203 : isolate()->get_initial_js_array_map(consolidated_elements_kind));
6876 203 : load_mode = BuildKeyedHoleMode(holey_map);
6877 203 : if (load_mode != NEVER_RETURN_HOLE) {
6878 1024 : for (int i = 0; i < maps->length(); ++i) {
6879 : Handle<Map> map = maps->at(i);
6880 : // The prototype check was already done for the holey map in
6881 : // BuildKeyedHoleMode.
6882 415 : if (!map.is_identical_to(holey_map)) {
6883 : Handle<JSObject> prototype(JSObject::cast(map->prototype()),
6884 : isolate());
6885 : Handle<JSObject> object_prototype =
6886 258 : isolate()->initial_object_prototype();
6887 258 : BuildCheckPrototypeMaps(prototype, object_prototype);
6888 : }
6889 : }
6890 : }
6891 : }
6892 : }
6893 : HInstruction* instr = BuildUncheckedMonomorphicElementAccess(
6894 : checked_object, key, val,
6895 : most_general_consolidated_map->instance_type() == JS_ARRAY_TYPE,
6896 1203 : consolidated_elements_kind, LOAD, load_mode, STANDARD_STORE);
6897 1203 : return instr;
6898 : }
6899 :
6900 3047 : HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
6901 : Expression* expr, FeedbackSlot slot, HValue* object, HValue* key,
6902 : HValue* val, SmallMapList* maps, PropertyAccessType access_type,
6903 : KeyedAccessStoreMode store_mode, bool* has_side_effects) {
6904 3047 : *has_side_effects = false;
6905 9285 : BuildCheckHeapObject(object);
6906 :
6907 3047 : if (access_type == LOAD) {
6908 : HInstruction* consolidated_load =
6909 1801 : TryBuildConsolidatedElementLoad(object, key, val, maps);
6910 1801 : if (consolidated_load != NULL) {
6911 1203 : *has_side_effects |= consolidated_load->HasObservableSideEffects();
6912 1203 : return consolidated_load;
6913 : }
6914 : }
6915 :
6916 : // Elements_kind transition support.
6917 : MapHandleList transition_target(maps->length());
6918 : // Collect possible transition targets.
6919 : MapHandleList possible_transitioned_maps(maps->length());
6920 11568 : for (int i = 0; i < maps->length(); ++i) {
6921 3948 : Handle<Map> map = maps->at(i);
6922 : // Loads from strings or loads with a mix of string and non-string maps
6923 : // shouldn't be handled polymorphically.
6924 : DCHECK(access_type != LOAD || !map->IsStringMap());
6925 : ElementsKind elements_kind = map->elements_kind();
6926 7677 : if (CanInlineElementAccess(map) && IsFastElementsKind(elements_kind) &&
6927 : elements_kind != GetInitialFastElementsKind()) {
6928 2610 : possible_transitioned_maps.Add(map);
6929 : }
6930 3948 : if (IsSloppyArgumentsElementsKind(elements_kind)) {
6931 : HInstruction* result =
6932 8 : BuildKeyedGeneric(access_type, expr, slot, object, key, val);
6933 8 : *has_side_effects = result->HasObservableSideEffects();
6934 8 : return AddInstruction(result);
6935 : }
6936 : }
6937 : // Get transition target for each map (NULL == no transition).
6938 9704 : for (int i = 0; i < maps->length(); ++i) {
6939 : Handle<Map> map = maps->at(i);
6940 : Map* transitioned_map =
6941 3934 : map->FindElementsKindTransitionedMap(&possible_transitioned_maps);
6942 3934 : if (transitioned_map != nullptr) {
6943 : DCHECK(!map->is_stable());
6944 806 : transition_target.Add(handle(transitioned_map));
6945 : } else {
6946 3128 : transition_target.Add(Handle<Map>());
6947 : }
6948 : }
6949 :
6950 : MapHandleList untransitionable_maps(maps->length());
6951 : HTransitionElementsKind* transition = NULL;
6952 11540 : for (int i = 0; i < maps->length(); ++i) {
6953 3934 : Handle<Map> map = maps->at(i);
6954 : DCHECK(map->IsMap());
6955 3934 : if (!transition_target.at(i).is_null()) {
6956 : DCHECK(Map::IsValidElementsTransition(
6957 : map->elements_kind(),
6958 : transition_target.at(i)->elements_kind()));
6959 : transition = Add<HTransitionElementsKind>(object, map,
6960 806 : transition_target.at(i));
6961 : } else {
6962 3128 : untransitionable_maps.Add(map);
6963 : }
6964 : }
6965 :
6966 : // If only one map is left after transitioning, handle this case
6967 : // monomorphically.
6968 : DCHECK(untransitionable_maps.length() >= 1);
6969 1836 : if (untransitionable_maps.length() == 1) {
6970 618 : Handle<Map> untransitionable_map = untransitionable_maps[0];
6971 : HInstruction* instr = NULL;
6972 618 : if (!CanInlineElementAccess(untransitionable_map)) {
6973 : instr = AddInstruction(
6974 136 : BuildKeyedGeneric(access_type, expr, slot, object, key, val));
6975 : } else {
6976 : instr = BuildMonomorphicElementAccess(
6977 : object, key, val, transition, untransitionable_map, access_type,
6978 482 : store_mode);
6979 : }
6980 618 : *has_side_effects |= instr->HasObservableSideEffects();
6981 618 : return access_type == STORE ? val : instr;
6982 : }
6983 :
6984 1218 : HBasicBlock* join = graph()->CreateBasicBlock();
6985 :
6986 3728 : for (int i = 0; i < untransitionable_maps.length(); ++i) {
6987 5020 : Handle<Map> map = untransitionable_maps[i];
6988 : ElementsKind elements_kind = map->elements_kind();
6989 2510 : HBasicBlock* this_map = graph()->CreateBasicBlock();
6990 2510 : HBasicBlock* other_map = graph()->CreateBasicBlock();
6991 : HCompareMap* mapcompare =
6992 2510 : New<HCompareMap>(object, map, this_map, other_map);
6993 2510 : FinishCurrentBlock(mapcompare);
6994 :
6995 : set_current_block(this_map);
6996 : HInstruction* access = NULL;
6997 2510 : if (!CanInlineElementAccess(map)) {
6998 : access = AddInstruction(
6999 69 : BuildKeyedGeneric(access_type, expr, slot, object, key, val));
7000 : } else {
7001 : DCHECK(IsFastElementsKind(elements_kind) ||
7002 : IsFixedTypedArrayElementsKind(elements_kind));
7003 2441 : LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map);
7004 : // Happily, mapcompare is a checked object.
7005 : access = BuildUncheckedMonomorphicElementAccess(
7006 : mapcompare, key, val,
7007 : map->instance_type() == JS_ARRAY_TYPE,
7008 : elements_kind, access_type,
7009 : load_mode,
7010 2441 : store_mode);
7011 : }
7012 2510 : *has_side_effects |= access->HasObservableSideEffects();
7013 : // The caller will use has_side_effects and add a correct Simulate.
7014 : access->SetFlag(HValue::kHasNoObservableSideEffects);
7015 2510 : if (access_type == LOAD) {
7016 388 : Push(access);
7017 : }
7018 : NoObservableSideEffectsScope scope(this);
7019 : GotoNoSimulate(join);
7020 : set_current_block(other_map);
7021 : }
7022 :
7023 : // Ensure that we visited at least one map above that goes to join. This is
7024 : // necessary because FinishExitWithHardDeoptimization does an AbnormalExit
7025 : // rather than joining the join block. If this becomes an issue, insert a
7026 : // generic access in the case length() == 0.
7027 : DCHECK(join->predecessors()->length() > 0);
7028 : // Deopt if none of the cases matched.
7029 : NoObservableSideEffectsScope scope(this);
7030 : FinishExitWithHardDeoptimization(
7031 1218 : DeoptimizeReason::kUnknownMapInPolymorphicElementAccess);
7032 : set_current_block(join);
7033 1218 : return access_type == STORE ? val : Pop();
7034 : }
7035 :
7036 108120 : HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
7037 : HValue* obj, HValue* key, HValue* val, Expression* expr, FeedbackSlot slot,
7038 : BailoutId ast_id, BailoutId return_id, PropertyAccessType access_type,
7039 : bool* has_side_effects) {
7040 : // A keyed name access with type feedback may contain the name.
7041 122912 : Handle<FeedbackVector> vector = handle(current_feedback_vector(), isolate());
7042 : HValue* expected_key = key;
7043 216240 : if (!key->ActualValue()->IsConstant()) {
7044 : Name* name = nullptr;
7045 93763 : if (access_type == LOAD) {
7046 : KeyedLoadICNexus nexus(vector, slot);
7047 81206 : name = nexus.FindFirstName();
7048 : } else {
7049 : KeyedStoreICNexus nexus(vector, slot);
7050 12557 : name = nexus.FindFirstName();
7051 : }
7052 93763 : if (name != nullptr) {
7053 : Handle<Name> handle_name(name);
7054 434 : expected_key = Add<HConstant>(handle_name);
7055 : // We need a check against the key.
7056 : bool in_new_space = isolate()->heap()->InNewSpace(*handle_name);
7057 434 : Unique<Name> unique_name = Unique<Name>::CreateUninitialized(handle_name);
7058 434 : Add<HCheckValue>(key, unique_name, in_new_space);
7059 : }
7060 : }
7061 216240 : if (expected_key->ActualValue()->IsConstant()) {
7062 : Handle<Object> constant =
7063 14791 : HConstant::cast(expected_key->ActualValue())->handle(isolate());
7064 : uint32_t array_index;
7065 15360 : if ((constant->IsString() &&
7066 29613 : !Handle<String>::cast(constant)->AsArrayIndex(&array_index)) ||
7067 : constant->IsSymbol()) {
7068 816 : if (!constant->IsUniqueName()) {
7069 : constant = isolate()->factory()->InternalizeString(
7070 1 : Handle<String>::cast(constant));
7071 : }
7072 : HValue* access =
7073 : BuildNamedAccess(access_type, ast_id, return_id, expr, slot, obj,
7074 816 : Handle<Name>::cast(constant), val, false);
7075 2226 : if (access == NULL || access->IsPhi() ||
7076 : HInstruction::cast(access)->IsLinked()) {
7077 261 : *has_side_effects = false;
7078 : } else {
7079 : HInstruction* instr = HInstruction::cast(access);
7080 555 : AddInstruction(instr);
7081 555 : *has_side_effects = instr->HasObservableSideEffects();
7082 : }
7083 816 : return access;
7084 : }
7085 : }
7086 :
7087 : DCHECK(!expr->IsPropertyName());
7088 : HInstruction* instr = NULL;
7089 :
7090 : SmallMapList* maps;
7091 107304 : bool monomorphic = ComputeReceiverTypes(expr, obj, &maps, this);
7092 :
7093 : bool force_generic = false;
7094 107304 : if (expr->GetKeyType() == PROPERTY) {
7095 : // Non-Generic accesses assume that elements are being accessed, and will
7096 : // deopt for non-index keys, which the IC knows will occur.
7097 : // TODO(jkummerow): Consider adding proper support for property accesses.
7098 : force_generic = true;
7099 : monomorphic = false;
7100 207874 : } else if (access_type == STORE &&
7101 22332 : (monomorphic || (maps != NULL && !maps->is_empty()))) {
7102 : // Stores can't be mono/polymorphic if their prototype chain has dictionary
7103 : // elements. However a receiver map that has dictionary elements itself
7104 : // should be left to normal mono/poly behavior (the other maps may benefit
7105 : // from highly optimized stores).
7106 18409 : for (int i = 0; i < maps->length(); i++) {
7107 : Handle<Map> current_map = maps->at(i);
7108 6584 : if (current_map->DictionaryElementsInPrototypeChainOnly()) {
7109 : force_generic = true;
7110 : monomorphic = false;
7111 : break;
7112 : }
7113 : }
7114 268438 : } else if (access_type == LOAD && !monomorphic &&
7115 142236 : (maps != NULL && !maps->is_empty())) {
7116 : // Polymorphic loads have to go generic if any of the maps are strings.
7117 : // If some, but not all of the maps are strings, we should go generic
7118 : // because polymorphic access wants to key on ElementsKind and isn't
7119 : // compatible with strings.
7120 9482 : for (int i = 0; i < maps->length(); i++) {
7121 : Handle<Map> current_map = maps->at(i);
7122 3843 : if (current_map->IsStringMap()) {
7123 : force_generic = true;
7124 : break;
7125 : }
7126 : }
7127 : }
7128 :
7129 107304 : if (monomorphic) {
7130 43286 : Handle<Map> map = maps->first();
7131 21643 : if (!CanInlineElementAccess(map)) {
7132 : instr = AddInstruction(
7133 106 : BuildKeyedGeneric(access_type, expr, slot, obj, key, val));
7134 : } else {
7135 21537 : BuildCheckHeapObject(obj);
7136 : instr = BuildMonomorphicElementAccess(
7137 21537 : obj, key, val, NULL, map, access_type, expr->GetStoreMode());
7138 : }
7139 167932 : } else if (!force_generic && (maps != NULL && !maps->is_empty())) {
7140 : return HandlePolymorphicElementAccess(expr, slot, obj, key, val, maps,
7141 : access_type, expr->GetStoreMode(),
7142 3047 : has_side_effects);
7143 : } else {
7144 82614 : if (access_type == STORE) {
7145 20306 : if (expr->IsAssignment() &&
7146 20182 : expr->AsAssignment()->HasNoTypeInformation()) {
7147 : Add<HDeoptimize>(
7148 : DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess,
7149 9476 : Deoptimizer::SOFT);
7150 : }
7151 : } else {
7152 144798 : if (expr->AsProperty()->HasNoTypeInformation()) {
7153 : Add<HDeoptimize>(
7154 : DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess,
7155 67359 : Deoptimizer::SOFT);
7156 : }
7157 : }
7158 : instr = AddInstruction(
7159 82614 : BuildKeyedGeneric(access_type, expr, slot, obj, key, val));
7160 : }
7161 104257 : *has_side_effects = instr->HasObservableSideEffects();
7162 104257 : return instr;
7163 : }
7164 :
7165 :
7166 573 : void HOptimizedGraphBuilder::EnsureArgumentsArePushedForAccess() {
7167 : // Outermost function already has arguments on the stack.
7168 341 : if (function_state()->outer() == NULL) return;
7169 :
7170 341 : if (function_state()->arguments_pushed()) return;
7171 :
7172 : // Push arguments when entering inlined function.
7173 464 : HEnterInlined* entry = function_state()->entry();
7174 : entry->set_arguments_pushed();
7175 :
7176 : HArgumentsObject* arguments = entry->arguments_object();
7177 : const ZoneList<HValue*>* arguments_values = arguments->arguments_values();
7178 :
7179 : HInstruction* insert_after = entry;
7180 1964 : for (int i = 0; i < arguments_values->length(); i++) {
7181 1732 : HValue* argument = arguments_values->at(i);
7182 750 : HInstruction* push_argument = New<HPushArguments>(argument);
7183 750 : push_argument->InsertAfter(insert_after);
7184 : insert_after = push_argument;
7185 : }
7186 :
7187 232 : HArgumentsElements* arguments_elements = New<HArgumentsElements>(true);
7188 : arguments_elements->ClearFlag(HValue::kUseGVN);
7189 232 : arguments_elements->InsertAfter(insert_after);
7190 : function_state()->set_arguments_elements(arguments_elements);
7191 : }
7192 :
7193 752 : bool HOptimizedGraphBuilder::IsAnyParameterContextAllocated() {
7194 752 : int count = current_info()->scope()->num_parameters();
7195 2122 : for (int i = 0; i < count; ++i) {
7196 4221 : if (current_info()->scope()->parameter(i)->location() ==
7197 : VariableLocation::CONTEXT) {
7198 : return true;
7199 : }
7200 : }
7201 : return false;
7202 : }
7203 :
7204 325191 : bool HOptimizedGraphBuilder::TryArgumentsAccess(Property* expr) {
7205 599827 : VariableProxy* proxy = expr->obj()->AsVariableProxy();
7206 315605 : if (proxy == NULL) return false;
7207 284222 : if (!proxy->var()->IsStackAllocated()) return false;
7208 451535 : if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) {
7209 : return false;
7210 : }
7211 :
7212 : HInstruction* result = NULL;
7213 1463 : if (expr->key()->IsPropertyName()) {
7214 1408 : Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
7215 704 : if (!String::Equals(name, isolate()->factory()->length_string())) {
7216 7 : return false;
7217 : }
7218 :
7219 : // Make sure we visit the arguments object so that the liveness analysis
7220 : // still records the access.
7221 2091 : CHECK_ALIVE_OR_RETURN(VisitForValue(expr->obj(), ARGUMENTS_ALLOWED), true);
7222 : Drop(1);
7223 :
7224 697 : if (function_state()->outer() == NULL) {
7225 446 : HInstruction* elements = Add<HArgumentsElements>(false);
7226 446 : result = New<HArgumentsLength>(elements);
7227 : } else {
7228 : // Number of arguments without receiver.
7229 : int argument_count = environment()->
7230 251 : arguments_environment()->parameter_count() - 1;
7231 251 : result = New<HConstant>(argument_count);
7232 : }
7233 : } else {
7234 : // We need to take into account the KEYED_LOAD_IC feedback to guard the
7235 : // HBoundsCheck instructions below.
7236 1060 : if (!expr->IsMonomorphic() && !expr->IsUninitialized()) return false;
7237 752 : if (IsAnyParameterContextAllocated()) return false;
7238 2145 : CHECK_ALIVE_OR_RETURN(VisitForValue(expr->obj(), ARGUMENTS_ALLOWED), true);
7239 2145 : CHECK_ALIVE_OR_RETURN(VisitForValue(expr->key()), true);
7240 : HValue* key = Pop();
7241 : Drop(1); // Arguments object.
7242 715 : if (function_state()->outer() == NULL) {
7243 374 : HInstruction* elements = Add<HArgumentsElements>(false);
7244 374 : HInstruction* length = Add<HArgumentsLength>(elements);
7245 374 : HInstruction* checked_key = Add<HBoundsCheck>(key, length);
7246 374 : result = New<HAccessArgumentsAt>(elements, length, checked_key);
7247 : } else {
7248 341 : EnsureArgumentsArePushedForAccess();
7249 :
7250 : // Number of arguments without receiver.
7251 341 : HInstruction* elements = function_state()->arguments_elements();
7252 : int argument_count = environment()->
7253 341 : arguments_environment()->parameter_count() - 1;
7254 341 : HInstruction* length = Add<HConstant>(argument_count);
7255 341 : HInstruction* checked_key = Add<HBoundsCheck>(key, length);
7256 341 : result = New<HAccessArgumentsAt>(elements, length, checked_key);
7257 : }
7258 : }
7259 2824 : ast_context()->ReturnInstruction(result, expr->id());
7260 1412 : return true;
7261 : }
7262 :
7263 489441 : HValue* HOptimizedGraphBuilder::BuildNamedAccess(
7264 : PropertyAccessType access, BailoutId ast_id, BailoutId return_id,
7265 : Expression* expr, FeedbackSlot slot, HValue* object, Handle<Name> name,
7266 : HValue* value, bool is_uninitialized) {
7267 : SmallMapList* maps;
7268 489441 : ComputeReceiverTypes(expr, object, &maps, this);
7269 : DCHECK(maps != NULL);
7270 :
7271 : // Check for special case: Access via a single map to the global proxy
7272 : // can also be handled monomorphically.
7273 978882 : if (maps->length() > 0) {
7274 : Handle<Object> map_constructor =
7275 381092 : handle(maps->first()->GetConstructor(), isolate());
7276 190546 : if (map_constructor->IsJSFunction()) {
7277 : Handle<Context> map_context =
7278 : handle(Handle<JSFunction>::cast(map_constructor)->context());
7279 155437 : Handle<Context> current_context(current_info()->context());
7280 : bool is_same_context_global_proxy_access =
7281 299328 : maps->length() == 1 && // >1 map => fallback to polymorphic
7282 155753 : maps->first()->IsJSGlobalProxyMap() &&
7283 : (*map_context == *current_context);
7284 155437 : if (is_same_context_global_proxy_access) {
7285 199 : Handle<JSGlobalObject> global_object(current_info()->global_object());
7286 199 : LookupIterator it(global_object, name, LookupIterator::OWN);
7287 199 : if (CanInlineGlobalPropertyAccess(&it, access)) {
7288 154 : BuildCheckHeapObject(object);
7289 154 : Add<HCheckMaps>(object, maps);
7290 154 : if (access == LOAD) {
7291 141 : InlineGlobalPropertyLoad(&it, expr->id());
7292 141 : return nullptr;
7293 : } else {
7294 13 : return InlineGlobalPropertyStore(&it, value, expr->id());
7295 : }
7296 : }
7297 : }
7298 : }
7299 :
7300 380784 : PropertyAccessInfo info(this, access, maps->first(), name);
7301 190392 : if (!info.CanAccessAsMonomorphic(maps)) {
7302 : HandlePolymorphicNamedFieldAccess(access, expr, slot, ast_id, return_id,
7303 10862 : object, value, maps, name);
7304 10862 : return NULL;
7305 : }
7306 :
7307 : HValue* checked_object;
7308 : // AstType::Number() is only supported by polymorphic load/call handling.
7309 : DCHECK(!info.IsNumberType());
7310 179530 : BuildCheckHeapObject(object);
7311 179530 : if (AreStringTypes(maps)) {
7312 : checked_object =
7313 13796 : Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING);
7314 : } else {
7315 165734 : checked_object = Add<HCheckMaps>(object, maps);
7316 : }
7317 : return BuildMonomorphicAccess(
7318 179530 : &info, object, checked_object, value, ast_id, return_id);
7319 : }
7320 :
7321 : return BuildNamedGeneric(access, expr, slot, object, name, value,
7322 298895 : is_uninitialized);
7323 : }
7324 :
7325 :
7326 208732 : void HOptimizedGraphBuilder::PushLoad(Property* expr,
7327 : HValue* object,
7328 : HValue* key) {
7329 : ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED);
7330 208732 : Push(object);
7331 208732 : if (key != NULL) Push(key);
7332 208732 : BuildLoad(expr, expr->LoadId());
7333 208732 : }
7334 :
7335 :
7336 1475982 : void HOptimizedGraphBuilder::BuildLoad(Property* expr,
7337 585859 : BailoutId ast_id) {
7338 : HInstruction* instr = NULL;
7339 522959 : if (expr->IsStringAccess() && expr->GetKeyType() == ELEMENT) {
7340 : HValue* index = Pop();
7341 : HValue* string = Pop();
7342 84 : HInstruction* char_code = BuildStringCharCodeAt(string, index);
7343 84 : AddInstruction(char_code);
7344 168 : if (char_code->IsConstant()) {
7345 21 : HConstant* c_code = HConstant::cast(char_code);
7346 42 : if (c_code->HasNumberValue() && std::isnan(c_code->DoubleValue())) {
7347 11 : Add<HDeoptimize>(DeoptimizeReason::kOutOfBounds, Deoptimizer::EAGER);
7348 : }
7349 : }
7350 84 : instr = NewUncasted<HStringCharFromCode>(char_code);
7351 :
7352 522776 : } else if (expr->key()->IsPropertyName()) {
7353 430346 : Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
7354 : HValue* object = Pop();
7355 :
7356 : HValue* value = BuildNamedAccess(LOAD, ast_id, expr->LoadId(), expr,
7357 : expr->PropertyFeedbackSlot(), object, name,
7358 860692 : NULL, expr->IsUninitialized());
7359 430346 : if (value == NULL) return;
7360 420640 : if (value->IsPhi()) return ast_context()->ReturnValue(value);
7361 : instr = HInstruction::cast(value);
7362 421558 : if (instr->IsLinked()) return ast_context()->ReturnValue(instr);
7363 :
7364 : } else {
7365 : HValue* key = Pop();
7366 : HValue* obj = Pop();
7367 :
7368 92430 : bool has_side_effects = false;
7369 : HValue* load = HandleKeyedElementAccess(
7370 : obj, key, NULL, expr, expr->PropertyFeedbackSlot(), ast_id,
7371 92430 : expr->LoadId(), LOAD, &has_side_effects);
7372 92430 : if (has_side_effects) {
7373 72747 : if (ast_context()->IsEffect()) {
7374 28 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
7375 : } else {
7376 72719 : Push(load);
7377 72719 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
7378 : Drop(1);
7379 : }
7380 : }
7381 92430 : if (load == NULL) return;
7382 92388 : return ast_context()->ReturnValue(load);
7383 : }
7384 419806 : return ast_context()->ReturnInstruction(instr, ast_id);
7385 : }
7386 :
7387 :
7388 1663862 : void HOptimizedGraphBuilder::VisitProperty(Property* expr) {
7389 : DCHECK(!HasStackOverflow());
7390 : DCHECK(current_block() != NULL);
7391 : DCHECK(current_block()->HasPredecessor());
7392 :
7393 315605 : if (TryArgumentsAccess(expr)) return;
7394 :
7395 720001 : CHECK_ALIVE(VisitForValue(expr->obj()));
7396 536641 : if (!expr->key()->IsPropertyName() || expr->IsStringAccess()) {
7397 274845 : CHECK_ALIVE(VisitForValue(expr->key()));
7398 : }
7399 :
7400 314128 : BuildLoad(expr, expr->id());
7401 : }
7402 :
7403 95866 : HInstruction* HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant,
7404 208 : bool ensure_no_elements) {
7405 : HCheckMaps* check = Add<HCheckMaps>(
7406 95866 : Add<HConstant>(constant), handle(constant->map()));
7407 : check->ClearDependsOnFlag(kElementsKind);
7408 95866 : if (ensure_no_elements) {
7409 : // TODO(ishell): remove this once we support NO_ELEMENTS elements kind.
7410 : HValue* elements = AddLoadElements(check, nullptr);
7411 : HValue* empty_elements =
7412 208 : Add<HConstant>(isolate()->factory()->empty_fixed_array());
7413 : IfBuilder if_empty(this);
7414 : if_empty.IfNot<HCompareObjectEqAndBranch>(elements, empty_elements);
7415 : if_empty.ThenDeopt(DeoptimizeReason::kWrongMap);
7416 208 : if_empty.End();
7417 : }
7418 95866 : return check;
7419 : }
7420 :
7421 62025 : HInstruction* HGraphBuilder::BuildCheckPrototypeMaps(Handle<JSObject> prototype,
7422 : Handle<JSObject> holder,
7423 62025 : bool ensure_no_elements) {
7424 62025 : PrototypeIterator iter(isolate(), prototype, kStartAtReceiver);
7425 248532 : while (holder.is_null() ||
7426 : !PrototypeIterator::GetCurrent(iter).is_identical_to(holder)) {
7427 : BuildConstantMapCheck(PrototypeIterator::GetCurrent<JSObject>(iter),
7428 36372 : ensure_no_elements);
7429 36372 : iter.Advance();
7430 36372 : if (iter.IsAtEnd()) {
7431 : return NULL;
7432 : }
7433 : }
7434 59494 : return BuildConstantMapCheck(holder);
7435 : }
7436 :
7437 :
7438 1560 : void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder,
7439 : Handle<Map> receiver_map) {
7440 1560 : if (!holder.is_null()) {
7441 : Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype()));
7442 1556 : BuildCheckPrototypeMaps(prototype, holder);
7443 : }
7444 1560 : }
7445 :
7446 133 : void HOptimizedGraphBuilder::BuildEnsureCallable(HValue* object) {
7447 133 : NoObservableSideEffectsScope scope(this);
7448 : const Runtime::Function* throw_called_non_callable =
7449 133 : Runtime::FunctionForId(Runtime::kThrowCalledNonCallable);
7450 :
7451 : IfBuilder is_not_function(this);
7452 133 : HValue* smi_check = is_not_function.If<HIsSmiAndBranch>(object);
7453 133 : is_not_function.Or();
7454 : HValue* map = AddLoadMap(object, smi_check);
7455 : HValue* bit_field =
7456 133 : Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField());
7457 : HValue* bit_field_masked = AddUncasted<HBitwise>(
7458 133 : Token::BIT_AND, bit_field, Add<HConstant>(1 << Map::kIsCallable));
7459 : is_not_function.IfNot<HCompareNumericAndBranch>(
7460 133 : bit_field_masked, Add<HConstant>(1 << Map::kIsCallable), Token::EQ);
7461 133 : is_not_function.Then();
7462 : {
7463 133 : Add<HPushArguments>(object);
7464 133 : Add<HCallRuntime>(throw_called_non_callable, 1);
7465 : }
7466 133 : is_not_function.End();
7467 133 : }
7468 :
7469 118361 : HInstruction* HOptimizedGraphBuilder::NewCallFunction(
7470 : HValue* function, int argument_count, TailCallMode syntactic_tail_call_mode,
7471 : ConvertReceiverMode convert_mode, TailCallMode tail_call_mode) {
7472 118361 : if (syntactic_tail_call_mode == TailCallMode::kAllow) {
7473 89 : BuildEnsureCallable(function);
7474 : } else {
7475 : DCHECK_EQ(TailCallMode::kDisallow, tail_call_mode);
7476 : }
7477 236722 : HValue* arity = Add<HConstant>(argument_count - 1);
7478 :
7479 118361 : HValue* op_vals[] = {function, arity};
7480 :
7481 : Callable callable =
7482 118361 : CodeFactory::Call(isolate(), convert_mode, tail_call_mode);
7483 118361 : HConstant* stub = Add<HConstant>(callable.code());
7484 :
7485 : return New<HCallWithDescriptor>(stub, argument_count, callable.descriptor(),
7486 : ArrayVector(op_vals),
7487 118361 : syntactic_tail_call_mode);
7488 : }
7489 :
7490 244174 : HInstruction* HOptimizedGraphBuilder::NewCallFunctionViaIC(
7491 : HValue* function, int argument_count, TailCallMode syntactic_tail_call_mode,
7492 : ConvertReceiverMode convert_mode, TailCallMode tail_call_mode,
7493 : FeedbackSlot slot) {
7494 244174 : if (syntactic_tail_call_mode == TailCallMode::kAllow) {
7495 44 : BuildEnsureCallable(function);
7496 : } else {
7497 : DCHECK_EQ(TailCallMode::kDisallow, tail_call_mode);
7498 : }
7499 244174 : int arity = argument_count - 1;
7500 488348 : Handle<FeedbackVector> vector(current_feedback_vector(), isolate());
7501 244174 : HValue* arity_val = Add<HConstant>(arity);
7502 244174 : HValue* index_val = Add<HConstant>(vector->GetIndex(slot));
7503 244174 : HValue* vector_val = Add<HConstant>(vector);
7504 :
7505 244174 : HValue* op_vals[] = {function, arity_val, index_val, vector_val};
7506 : Callable callable =
7507 244174 : CodeFactory::CallIC(isolate(), convert_mode, tail_call_mode);
7508 244174 : HConstant* stub = Add<HConstant>(callable.code());
7509 :
7510 : return New<HCallWithDescriptor>(stub, argument_count, callable.descriptor(),
7511 : ArrayVector(op_vals),
7512 244174 : syntactic_tail_call_mode);
7513 : }
7514 :
7515 140346 : HInstruction* HOptimizedGraphBuilder::NewCallConstantFunction(
7516 : Handle<JSFunction> function, int argument_count,
7517 : TailCallMode syntactic_tail_call_mode, TailCallMode tail_call_mode) {
7518 140346 : HValue* target = Add<HConstant>(function);
7519 : return New<HInvokeFunction>(target, function, argument_count,
7520 140346 : syntactic_tail_call_mode, tail_call_mode);
7521 : }
7522 :
7523 :
7524 : class FunctionSorter {
7525 : public:
7526 : explicit FunctionSorter(int index = 0, int ticks = 0, int size = 0)
7527 6744 : : index_(index), ticks_(ticks), size_(size) {}
7528 :
7529 : int index() const { return index_; }
7530 : int ticks() const { return ticks_; }
7531 : int size() const { return size_; }
7532 :
7533 : private:
7534 : int index_;
7535 : int ticks_;
7536 : int size_;
7537 : };
7538 :
7539 :
7540 1644 : inline bool operator<(const FunctionSorter& lhs, const FunctionSorter& rhs) {
7541 841 : int diff = lhs.ticks() - rhs.ticks();
7542 841 : if (diff != 0) return diff > 0;
7543 803 : return lhs.size() < rhs.size();
7544 : }
7545 :
7546 :
7547 6115 : void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(Call* expr,
7548 : HValue* receiver,
7549 : SmallMapList* maps,
7550 7111 : Handle<String> name) {
7551 1686 : int argument_count = expr->arguments()->length() + 1; // Includes receiver.
7552 8430 : FunctionSorter order[kMaxCallPolymorphism];
7553 :
7554 : bool handle_smi = false;
7555 : bool handled_string = false;
7556 : int ordered_functions = 0;
7557 :
7558 : TailCallMode syntactic_tail_call_mode = expr->tail_call_mode();
7559 : TailCallMode tail_call_mode =
7560 1686 : function_state()->ComputeTailCallMode(syntactic_tail_call_mode);
7561 :
7562 : int i;
7563 7880 : for (i = 0; i < maps->length() && ordered_functions < kMaxCallPolymorphism;
7564 : ++i) {
7565 2254 : PropertyAccessInfo info(this, LOAD, maps->at(i), name);
7566 5587 : if (info.CanAccessMonomorphic() && info.IsDataConstant() &&
7567 : info.constant()->IsJSFunction()) {
7568 1557 : if (info.IsStringType()) {
7569 1 : if (handled_string) continue;
7570 : handled_string = true;
7571 : }
7572 : Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant());
7573 1557 : if (info.IsNumberType()) {
7574 : handle_smi = true;
7575 : }
7576 : expr->set_target(target);
7577 : order[ordered_functions++] = FunctionSorter(
7578 3114 : i, target->shared()->profiler_ticks(), InliningAstSize(target));
7579 : }
7580 : }
7581 :
7582 1686 : std::sort(order, order + ordered_functions);
7583 :
7584 1686 : if (i < maps->length()) {
7585 : maps->Clear();
7586 : ordered_functions = -1;
7587 : }
7588 :
7589 : HBasicBlock* number_block = NULL;
7590 : HBasicBlock* join = NULL;
7591 : handled_string = false;
7592 : int count = 0;
7593 :
7594 3243 : for (int fn = 0; fn < ordered_functions; ++fn) {
7595 1557 : int i = order[fn].index();
7596 1557 : PropertyAccessInfo info(this, LOAD, maps->at(i), name);
7597 1557 : if (info.IsStringType()) {
7598 1 : if (handled_string) continue;
7599 : handled_string = true;
7600 : }
7601 : // Reloads the target.
7602 1557 : info.CanAccessMonomorphic();
7603 : Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant());
7604 :
7605 : expr->set_target(target);
7606 1557 : if (count == 0) {
7607 : // Only needed once.
7608 10766 : join = graph()->CreateBasicBlock();
7609 1125 : if (handle_smi) {
7610 705 : HBasicBlock* empty_smi_block = graph()->CreateBasicBlock();
7611 705 : HBasicBlock* not_smi_block = graph()->CreateBasicBlock();
7612 705 : number_block = graph()->CreateBasicBlock();
7613 : FinishCurrentBlock(New<HIsSmiAndBranch>(
7614 705 : receiver, empty_smi_block, not_smi_block));
7615 : GotoNoSimulate(empty_smi_block, number_block);
7616 : set_current_block(not_smi_block);
7617 : } else {
7618 420 : BuildCheckHeapObject(receiver);
7619 : }
7620 : }
7621 1557 : ++count;
7622 1557 : HBasicBlock* if_true = graph()->CreateBasicBlock();
7623 1557 : HBasicBlock* if_false = graph()->CreateBasicBlock();
7624 : HUnaryControlInstruction* compare;
7625 :
7626 1557 : Handle<Map> map = info.map();
7627 1557 : if (info.IsNumberType()) {
7628 705 : Handle<Map> heap_number_map = isolate()->factory()->heap_number_map();
7629 705 : compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false);
7630 852 : } else if (info.IsStringType()) {
7631 1 : compare = New<HIsStringAndBranch>(receiver, if_true, if_false);
7632 : } else {
7633 851 : compare = New<HCompareMap>(receiver, map, if_true, if_false);
7634 : }
7635 1557 : FinishCurrentBlock(compare);
7636 :
7637 1557 : if (info.IsNumberType()) {
7638 : GotoNoSimulate(if_true, number_block);
7639 : if_true = number_block;
7640 : }
7641 :
7642 : set_current_block(if_true);
7643 :
7644 1557 : AddCheckPrototypeMaps(info.holder(), map);
7645 :
7646 1557 : HValue* function = Add<HConstant>(expr->target());
7647 : environment()->SetExpressionStackAt(0, function);
7648 1557 : Push(receiver);
7649 4671 : CHECK_ALIVE(VisitExpressions(expr->arguments()));
7650 1557 : bool needs_wrapping = info.NeedsWrappingFor(target);
7651 1557 : bool try_inline = FLAG_polymorphic_inlining && !needs_wrapping;
7652 1557 : if (FLAG_trace_inlining && try_inline) {
7653 : Handle<JSFunction> caller = current_info()->closure();
7654 : std::unique_ptr<char[]> caller_name =
7655 0 : caller->shared()->DebugName()->ToCString();
7656 : PrintF("Trying to inline the polymorphic call to %s from %s\n",
7657 : name->ToCString().get(),
7658 0 : caller_name.get());
7659 : }
7660 1557 : if (try_inline && TryInlineCall(expr)) {
7661 : // Trying to inline will signal that we should bailout from the
7662 : // entire compilation by setting stack overflow on the visitor.
7663 80 : if (HasStackOverflow()) return;
7664 : } else {
7665 : // Since HWrapReceiver currently cannot actually wrap numbers and strings,
7666 : // use the regular call builtin for method calls to wrap the receiver.
7667 : // TODO(verwaest): Support creation of value wrappers directly in
7668 : // HWrapReceiver.
7669 : HInstruction* call =
7670 : needs_wrapping
7671 : ? NewCallFunction(
7672 : function, argument_count, syntactic_tail_call_mode,
7673 : ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode)
7674 : : NewCallConstantFunction(target, argument_count,
7675 : syntactic_tail_call_mode,
7676 1477 : tail_call_mode);
7677 1477 : PushArgumentsFromEnvironment(argument_count);
7678 1477 : AddInstruction(call);
7679 : Drop(1); // Drop the function.
7680 1477 : if (!ast_context()->IsEffect()) Push(call);
7681 : }
7682 :
7683 1557 : if (current_block() != NULL) Goto(join);
7684 : set_current_block(if_false);
7685 : }
7686 :
7687 : // Finish up. Unconditionally deoptimize if we've handled all the maps we
7688 : // know about and do not want to handle ones we've never seen. Otherwise
7689 : // use a generic IC.
7690 1686 : if (ordered_functions == maps->length() && FLAG_deoptimize_uncommon_cases) {
7691 : FinishExitWithHardDeoptimization(
7692 1093 : DeoptimizeReason::kUnknownMapInPolymorphicCall);
7693 : } else {
7694 593 : Property* prop = expr->expression()->AsProperty();
7695 : HInstruction* function =
7696 : BuildNamedGeneric(LOAD, prop, prop->PropertyFeedbackSlot(), receiver,
7697 1186 : name, NULL, prop->IsUninitialized());
7698 593 : AddInstruction(function);
7699 593 : Push(function);
7700 : AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE);
7701 :
7702 : environment()->SetExpressionStackAt(1, function);
7703 : environment()->SetExpressionStackAt(0, receiver);
7704 1779 : CHECK_ALIVE(VisitExpressions(expr->arguments()));
7705 :
7706 : HInstruction* call = NewCallFunction(
7707 : function, argument_count, syntactic_tail_call_mode,
7708 593 : ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode);
7709 :
7710 593 : PushArgumentsFromEnvironment(argument_count);
7711 :
7712 : Drop(1); // Function.
7713 :
7714 593 : if (join != NULL) {
7715 32 : AddInstruction(call);
7716 32 : if (!ast_context()->IsEffect()) Push(call);
7717 : Goto(join);
7718 : } else {
7719 1122 : return ast_context()->ReturnInstruction(call, expr->id());
7720 : }
7721 : }
7722 :
7723 : // We assume that control flow is always live after an expression. So
7724 : // even without predecessors to the join block, we set it as the exit
7725 : // block and continue by adding instructions there.
7726 : DCHECK(join != NULL);
7727 1125 : if (join->HasPredecessor()) {
7728 : set_current_block(join);
7729 : join->SetJoinId(expr->id());
7730 1979 : if (!ast_context()->IsEffect()) return ast_context()->ReturnValue(Pop());
7731 : } else {
7732 : set_current_block(NULL);
7733 : }
7734 : }
7735 :
7736 145926 : void HOptimizedGraphBuilder::TraceInline(Handle<JSFunction> target,
7737 : Handle<JSFunction> caller,
7738 : const char* reason,
7739 : TailCallMode tail_call_mode) {
7740 145926 : if (FLAG_trace_inlining) {
7741 : std::unique_ptr<char[]> target_name =
7742 0 : target->shared()->DebugName()->ToCString();
7743 : std::unique_ptr<char[]> caller_name =
7744 0 : caller->shared()->DebugName()->ToCString();
7745 0 : if (reason == NULL) {
7746 : const char* call_mode =
7747 0 : tail_call_mode == TailCallMode::kAllow ? "tail called" : "called";
7748 : PrintF("Inlined %s %s from %s.\n", target_name.get(), call_mode,
7749 0 : caller_name.get());
7750 : } else {
7751 : PrintF("Did not inline %s called from %s (%s).\n",
7752 0 : target_name.get(), caller_name.get(), reason);
7753 : }
7754 : }
7755 145926 : }
7756 :
7757 :
7758 : static const int kNotInlinable = 1000000000;
7759 :
7760 :
7761 248664 : int HOptimizedGraphBuilder::InliningAstSize(Handle<JSFunction> target) {
7762 248664 : if (!FLAG_use_inlining) return kNotInlinable;
7763 :
7764 : // Precondition: call is monomorphic and we have found a target with the
7765 : // appropriate arity.
7766 245410 : Handle<JSFunction> caller = current_info()->closure();
7767 : Handle<SharedFunctionInfo> target_shared(target->shared());
7768 :
7769 : // Always inline functions that force inlining.
7770 245410 : if (target_shared->force_inline()) {
7771 : return 0;
7772 : }
7773 243054 : if (!target->shared()->IsUserJavaScript()) {
7774 : return kNotInlinable;
7775 : }
7776 :
7777 143002 : if (target_shared->IsApiFunction()) {
7778 0 : TraceInline(target, caller, "target is api function");
7779 0 : return kNotInlinable;
7780 : }
7781 :
7782 : // Do a quick check on source code length to avoid parsing large
7783 : // inlining candidates.
7784 286004 : if (target_shared->SourceSize() >
7785 143002 : Min(FLAG_max_inlined_source_size, kUnlimitedMaxInlinedSourceSize)) {
7786 7650 : TraceInline(target, caller, "target text too big");
7787 7650 : return kNotInlinable;
7788 : }
7789 :
7790 : // Target must be inlineable.
7791 : BailoutReason noopt_reason = target_shared->disable_optimization_reason();
7792 135352 : if (!target_shared->IsInlineable() && noopt_reason != kHydrogenFilter) {
7793 814 : TraceInline(target, caller, "target not inlineable");
7794 814 : return kNotInlinable;
7795 : }
7796 134538 : if (noopt_reason != kNoReason && noopt_reason != kHydrogenFilter) {
7797 0 : TraceInline(target, caller, "target contains unsupported syntax [early]");
7798 0 : return kNotInlinable;
7799 : }
7800 :
7801 : int nodes_added = target_shared->ast_node_count();
7802 134538 : return nodes_added;
7803 : }
7804 :
7805 247160 : bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target,
7806 : int arguments_count,
7807 : HValue* implicit_return_value,
7808 : BailoutId ast_id, BailoutId return_id,
7809 : InliningKind inlining_kind,
7810 675540 : TailCallMode syntactic_tail_call_mode) {
7811 247160 : if (target->context()->native_context() !=
7812 1670103 : top_info()->closure()->context()->native_context()) {
7813 : return false;
7814 : }
7815 247107 : int nodes_added = InliningAstSize(target);
7816 247107 : if (nodes_added == kNotInlinable) return false;
7817 :
7818 136804 : Handle<JSFunction> caller = current_info()->closure();
7819 273608 : if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) {
7820 7 : TraceInline(target, caller, "target AST is too large [early]");
7821 7 : return false;
7822 : }
7823 :
7824 : // Don't inline deeper than the maximum number of inlining levels.
7825 305937 : HEnvironment* env = environment();
7826 : int current_level = 1;
7827 442734 : while (env->outer() != NULL) {
7828 171320 : if (current_level == FLAG_max_inlining_levels) {
7829 2180 : TraceInline(target, caller, "inline depth limit reached");
7830 2180 : return false;
7831 : }
7832 169140 : if (env->outer()->frame_type() == JS_FUNCTION) {
7833 129349 : current_level++;
7834 : }
7835 : env = env->outer();
7836 : }
7837 :
7838 : // Don't inline recursive functions.
7839 471444 : for (FunctionState* state = function_state();
7840 : state != NULL;
7841 : state = state->outer()) {
7842 239230 : if (*state->compilation_info()->closure() == *target) {
7843 7016 : TraceInline(target, caller, "target is recursive");
7844 7016 : return false;
7845 : }
7846 : }
7847 :
7848 : // We don't want to add more than a certain number of nodes from inlining.
7849 : // Always inline small methods (<= 10 nodes).
7850 255202 : if (inlined_count_ > Min(FLAG_max_inlined_nodes_cumulative,
7851 127601 : kUnlimitedMaxInlinedNodesCumulative)) {
7852 5013 : TraceInline(target, caller, "cumulative AST node limit reached");
7853 5013 : return false;
7854 : }
7855 :
7856 : // Parse and allocate variables.
7857 : // Use the same AstValueFactory for creating strings in the sub-compilation
7858 : // step, but don't transfer ownership to target_info.
7859 : Handle<SharedFunctionInfo> target_shared(target->shared());
7860 367764 : ParseInfo parse_info(target_shared, top_info()->parse_info()->zone_shared());
7861 : parse_info.set_ast_value_factory(
7862 122588 : top_info()->parse_info()->ast_value_factory());
7863 : parse_info.set_ast_value_factory_owned(false);
7864 :
7865 : CompilationInfo target_info(parse_info.zone(), &parse_info,
7866 245176 : target->GetIsolate(), target);
7867 :
7868 243502 : if (inlining_kind != CONSTRUCT_CALL_RETURN &&
7869 : IsClassConstructor(target_shared->kind())) {
7870 0 : TraceInline(target, caller, "target is classConstructor");
7871 0 : return false;
7872 : }
7873 :
7874 122588 : if (target_shared->HasDebugInfo()) {
7875 30 : TraceInline(target, caller, "target is being debugged");
7876 30 : return false;
7877 : }
7878 122558 : if (!Compiler::ParseAndAnalyze(&target_info)) {
7879 2 : if (target_info.isolate()->has_pending_exception()) {
7880 : // Parse or scope error, never optimize this function.
7881 : SetStackOverflow();
7882 2 : target_shared->DisableOptimization(kParseScopeError);
7883 : }
7884 2 : TraceInline(target, caller, "parse failure");
7885 2 : return false;
7886 : }
7887 122556 : if (target_shared->must_use_ignition_turbo()) {
7888 11832 : TraceInline(target, caller, "ParseAndAnalyze found incompatibility");
7889 11832 : return false;
7890 : }
7891 :
7892 221448 : if (target_info.scope()->NeedsContext()) {
7893 3285 : TraceInline(target, caller, "target has context-allocated variables");
7894 3285 : return false;
7895 : }
7896 :
7897 214878 : if (target_info.scope()->rest_parameter() != nullptr) {
7898 0 : TraceInline(target, caller, "target uses rest parameters");
7899 0 : return false;
7900 : }
7901 :
7902 537072 : FunctionLiteral* function = target_info.literal();
7903 :
7904 : // The following conditions must be checked again after re-parsing, because
7905 : // earlier the information might not have been complete due to lazy parsing.
7906 : nodes_added = function->ast_node_count();
7907 214878 : if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) {
7908 0 : TraceInline(target, caller, "target AST is too large [late]");
7909 0 : return false;
7910 : }
7911 107439 : if (function->dont_optimize()) {
7912 0 : TraceInline(target, caller, "target contains unsupported syntax [late]");
7913 0 : return false;
7914 : }
7915 :
7916 : // If the function uses the arguments object check that inlining of functions
7917 : // with arguments object is enabled and the arguments-variable is
7918 : // stack allocated.
7919 107439 : if (function->scope()->arguments() != NULL) {
7920 381 : if (!FLAG_inline_arguments) {
7921 0 : TraceInline(target, caller, "target uses arguments object");
7922 0 : return false;
7923 : }
7924 : }
7925 :
7926 : // Unsupported variable references present.
7927 214878 : if (function->scope()->this_function_var() != nullptr ||
7928 107439 : function->scope()->new_target_var() != nullptr) {
7929 0 : TraceInline(target, caller, "target uses new target or this function");
7930 0 : return false;
7931 : }
7932 :
7933 : // All declarations must be inlineable.
7934 107439 : Declaration::List* decls = target_info.scope()->declarations();
7935 396192 : for (Declaration* decl : *decls) {
7936 181348 : if (decl->IsFunctionDeclaration() ||
7937 90657 : !decl->proxy()->var()->IsStackAllocated()) {
7938 34 : TraceInline(target, caller, "target has non-trivial declaration");
7939 : return false;
7940 : }
7941 : }
7942 :
7943 : // Generate the deoptimization data for the unoptimized version of
7944 : // the target function if we don't already have it.
7945 107405 : if (!Compiler::EnsureDeoptimizationSupport(&target_info)) {
7946 7 : TraceInline(target, caller, "could not generate deoptimization info");
7947 7 : return false;
7948 : }
7949 :
7950 : // Remember that we inlined this function. This needs to be called right
7951 : // after the EnsureDeoptimizationSupport call so that the code flusher
7952 : // does not remove the code with the deoptimization support.
7953 : int inlining_id = top_info()->AddInlinedFunction(target_info.shared_info(),
7954 214796 : source_position());
7955 :
7956 : // ----------------------------------------------------------------
7957 : // After this point, we've made a decision to inline this function (so
7958 : // TryInline should always return true).
7959 :
7960 : // If target was lazily compiled, it's literals array may not yet be set up.
7961 107398 : JSFunction::EnsureLiterals(target);
7962 :
7963 : // Type-check the inlined function.
7964 : DCHECK(target_shared->has_deoptimization_support());
7965 : AstTyper(target_info.isolate(), target_info.zone(), target_info.closure(),
7966 : target_info.scope(), target_info.osr_ast_id(), target_info.literal(),
7967 : &bounds_)
7968 107398 : .Run();
7969 :
7970 : // Save the pending call context. Set up new one for the inlined function.
7971 : // The function state is new-allocated because we need to delete it
7972 : // in two different places.
7973 : FunctionState* target_state = new FunctionState(
7974 : this, &target_info, inlining_kind, inlining_id,
7975 214796 : function_state()->ComputeTailCallMode(syntactic_tail_call_mode));
7976 :
7977 107398 : HConstant* undefined = graph()->GetConstantUndefined();
7978 :
7979 : HEnvironment* inner_env = environment()->CopyForInlining(
7980 : target, arguments_count, function, undefined,
7981 214796 : function_state()->inlining_kind(), syntactic_tail_call_mode);
7982 :
7983 107398 : HConstant* context = Add<HConstant>(Handle<Context>(target->context()));
7984 107398 : inner_env->BindContext(context);
7985 :
7986 : // Create a dematerialized arguments object for the function, also copy the
7987 : // current arguments values to use them for materialization.
7988 107398 : HEnvironment* arguments_env = inner_env->arguments_environment();
7989 : int parameter_count = arguments_env->parameter_count();
7990 107398 : HArgumentsObject* arguments_object = Add<HArgumentsObject>(parameter_count);
7991 406407 : for (int i = 0; i < parameter_count; i++) {
7992 299009 : arguments_object->AddArgument(arguments_env->Lookup(i), zone());
7993 : }
7994 :
7995 : // If the function uses arguments object then bind bind one.
7996 107398 : if (function->scope()->arguments() != NULL) {
7997 : DCHECK(function->scope()->arguments()->IsStackAllocated());
7998 381 : inner_env->Bind(function->scope()->arguments(), arguments_object);
7999 : }
8000 :
8001 : // Capture the state before invoking the inlined function for deopt in the
8002 : // inlined function. This simulate has no bailout-id since it's not directly
8003 : // reachable for deopt, and is only used to capture the state. If the simulate
8004 : // becomes reachable by merging, the ast id of the simulate merged into it is
8005 : // adopted.
8006 : Add<HSimulate>(BailoutId::None());
8007 :
8008 : current_block()->UpdateEnvironment(inner_env);
8009 : Scope* saved_scope = scope();
8010 107398 : set_scope(target_info.scope());
8011 : HEnterInlined* enter_inlined = Add<HEnterInlined>(
8012 : return_id, target, context, arguments_count, function,
8013 : function_state()->inlining_kind(), function->scope()->arguments(),
8014 214796 : arguments_object, syntactic_tail_call_mode);
8015 107398 : if (is_tracking_positions()) {
8016 : enter_inlined->set_inlining_id(inlining_id);
8017 : }
8018 :
8019 : function_state()->set_entry(enter_inlined);
8020 :
8021 107398 : VisitDeclarations(target_info.scope()->declarations());
8022 107398 : VisitStatements(function->body());
8023 : set_scope(saved_scope);
8024 107398 : if (HasStackOverflow()) {
8025 : // Bail out if the inline function did, as we cannot residualize a call
8026 : // instead, but do not disable optimization for the outer function.
8027 37 : TraceInline(target, caller, "inline graph construction failed");
8028 37 : target_shared->DisableOptimization(kInliningBailedOut);
8029 : current_info()->RetryOptimization(kInliningBailedOut);
8030 37 : delete target_state;
8031 : return true;
8032 : }
8033 :
8034 : // Update inlined nodes count.
8035 107361 : inlined_count_ += nodes_added;
8036 :
8037 : Handle<Code> unoptimized_code(target_shared->code());
8038 : DCHECK(unoptimized_code->kind() == Code::FUNCTION);
8039 : Handle<TypeFeedbackInfo> type_info(
8040 : TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info()));
8041 : graph()->update_type_change_checksum(type_info->own_type_change_checksum());
8042 :
8043 107361 : TraceInline(target, caller, NULL, syntactic_tail_call_mode);
8044 :
8045 107361 : if (current_block() != NULL) {
8046 60402 : FunctionState* state = function_state();
8047 60402 : if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) {
8048 : // Falling off the end of an inlined construct call. In a test context the
8049 : // return value will always evaluate to true, in a value context the
8050 : // return value is the newly allocated receiver.
8051 888 : if (call_context()->IsTest()) {
8052 12 : inlined_test_context()->ReturnValue(graph()->GetConstantTrue());
8053 876 : } else if (call_context()->IsEffect()) {
8054 : Goto(function_return(), state);
8055 : } else {
8056 : DCHECK(call_context()->IsValue());
8057 : AddLeaveInlined(implicit_return_value, state);
8058 : }
8059 59514 : } else if (state->inlining_kind() == SETTER_CALL_RETURN) {
8060 : // Falling off the end of an inlined setter call. The returned value is
8061 : // never used, the value of an assignment is always the value of the RHS
8062 : // of the assignment.
8063 145 : if (call_context()->IsTest()) {
8064 : inlined_test_context()->ReturnValue(implicit_return_value);
8065 131 : } else if (call_context()->IsEffect()) {
8066 : Goto(function_return(), state);
8067 : } else {
8068 : DCHECK(call_context()->IsValue());
8069 : AddLeaveInlined(implicit_return_value, state);
8070 : }
8071 : } else {
8072 : // Falling off the end of a normal inlined function. This basically means
8073 : // returning undefined.
8074 59369 : if (call_context()->IsTest()) {
8075 136 : inlined_test_context()->ReturnValue(graph()->GetConstantFalse());
8076 59233 : } else if (call_context()->IsEffect()) {
8077 : Goto(function_return(), state);
8078 : } else {
8079 : DCHECK(call_context()->IsValue());
8080 : AddLeaveInlined(undefined, state);
8081 : }
8082 : }
8083 : }
8084 :
8085 : // Fix up the function exits.
8086 107361 : if (inlined_test_context() != NULL) {
8087 19537 : HBasicBlock* if_true = inlined_test_context()->if_true();
8088 19537 : HBasicBlock* if_false = inlined_test_context()->if_false();
8089 :
8090 19537 : HEnterInlined* entry = function_state()->entry();
8091 :
8092 : // Pop the return test context from the expression context stack.
8093 : DCHECK(ast_context() == inlined_test_context());
8094 : ClearInlinedTestContext();
8095 19537 : delete target_state;
8096 :
8097 : // Forward to the real test context.
8098 19537 : if (if_true->HasPredecessor()) {
8099 19537 : entry->RegisterReturnTarget(if_true, zone());
8100 : if_true->SetJoinId(ast_id);
8101 19537 : HBasicBlock* true_target = TestContext::cast(ast_context())->if_true();
8102 : Goto(if_true, true_target, function_state());
8103 : }
8104 19537 : if (if_false->HasPredecessor()) {
8105 19537 : entry->RegisterReturnTarget(if_false, zone());
8106 : if_false->SetJoinId(ast_id);
8107 19537 : HBasicBlock* false_target = TestContext::cast(ast_context())->if_false();
8108 : Goto(if_false, false_target, function_state());
8109 : }
8110 : set_current_block(NULL);
8111 19537 : return true;
8112 :
8113 87824 : } else if (function_return()->HasPredecessor()) {
8114 87824 : function_state()->entry()->RegisterReturnTarget(function_return(), zone());
8115 : function_return()->SetJoinId(ast_id);
8116 : set_current_block(function_return());
8117 : } else {
8118 : set_current_block(NULL);
8119 : }
8120 87824 : delete target_state;
8121 122588 : return true;
8122 : }
8123 :
8124 :
8125 478128 : bool HOptimizedGraphBuilder::TryInlineCall(Call* expr) {
8126 : return TryInline(expr->target(), expr->arguments()->length(), NULL,
8127 : expr->id(), expr->ReturnId(), NORMAL_RETURN,
8128 239064 : expr->tail_call_mode());
8129 : }
8130 :
8131 :
8132 9198 : bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr,
8133 : HValue* implicit_return_value) {
8134 : return TryInline(expr->target(), expr->arguments()->length(),
8135 : implicit_return_value, expr->id(), expr->ReturnId(),
8136 4599 : CONSTRUCT_CALL_RETURN, TailCallMode::kDisallow);
8137 : }
8138 :
8139 3062 : bool HOptimizedGraphBuilder::TryInlineGetter(Handle<Object> getter,
8140 : Handle<Map> receiver_map,
8141 : BailoutId ast_id,
8142 : BailoutId return_id) {
8143 3062 : if (TryInlineApiGetter(getter, receiver_map, ast_id)) return true;
8144 3028 : if (getter->IsJSFunction()) {
8145 3028 : Handle<JSFunction> getter_function = Handle<JSFunction>::cast(getter);
8146 5921 : return TryInlineBuiltinGetterCall(getter_function, receiver_map, ast_id) ||
8147 : TryInline(getter_function, 0, NULL, ast_id, return_id,
8148 2893 : GETTER_CALL_RETURN, TailCallMode::kDisallow);
8149 : }
8150 : return false;
8151 : }
8152 :
8153 246 : bool HOptimizedGraphBuilder::TryInlineSetter(Handle<Object> setter,
8154 : Handle<Map> receiver_map,
8155 : BailoutId id,
8156 : BailoutId assignment_id,
8157 : HValue* implicit_return_value) {
8158 246 : if (TryInlineApiSetter(setter, receiver_map, id)) return true;
8159 468 : return setter->IsJSFunction() &&
8160 : TryInline(Handle<JSFunction>::cast(setter), 1, implicit_return_value,
8161 : id, assignment_id, SETTER_CALL_RETURN,
8162 468 : TailCallMode::kDisallow);
8163 : }
8164 :
8165 :
8166 370 : bool HOptimizedGraphBuilder::TryInlineIndirectCall(Handle<JSFunction> function,
8167 370 : Call* expr,
8168 : int arguments_count) {
8169 : return TryInline(function, arguments_count, NULL, expr->id(),
8170 370 : expr->ReturnId(), NORMAL_RETURN, expr->tail_call_mode());
8171 : }
8172 :
8173 :
8174 215069 : bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) {
8175 197835 : if (!expr->target()->shared()->HasBuiltinFunctionId()) return false;
8176 : BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
8177 : // We intentionally ignore expr->tail_call_mode() here because builtins
8178 : // we inline here do not observe if they were tail called or not.
8179 49101 : switch (id) {
8180 : case kMathCos:
8181 : case kMathExp:
8182 : case kMathRound:
8183 : case kMathFround:
8184 : case kMathFloor:
8185 : case kMathAbs:
8186 : case kMathSin:
8187 : case kMathSqrt:
8188 : case kMathLog:
8189 : case kMathClz32:
8190 8584 : if (expr->arguments()->length() == 1) {
8191 66 : HValue* argument = Pop();
8192 : Drop(2); // Receiver and function.
8193 8584 : HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id);
8194 17168 : ast_context()->ReturnInstruction(op, expr->id());
8195 8584 : return true;
8196 : }
8197 : break;
8198 : case kMathImul:
8199 33 : if (expr->arguments()->length() == 2) {
8200 : HValue* right = Pop();
8201 : HValue* left = Pop();
8202 : Drop(2); // Receiver and function.
8203 : HInstruction* op =
8204 66 : HMul::NewImul(isolate(), zone(), context(), left, right);
8205 66 : ast_context()->ReturnInstruction(op, expr->id());
8206 33 : return true;
8207 : }
8208 : break;
8209 : default:
8210 : // Not supported for inlining yet.
8211 : break;
8212 : }
8213 : return false;
8214 : }
8215 :
8216 :
8217 : // static
8218 2556 : bool HOptimizedGraphBuilder::IsReadOnlyLengthDescriptor(
8219 : Handle<Map> jsarray_map) {
8220 : DCHECK(!jsarray_map->is_dictionary_map());
8221 : Isolate* isolate = jsarray_map->GetIsolate();
8222 : Handle<Name> length_string = isolate->factory()->length_string();
8223 : DescriptorArray* descriptors = jsarray_map->instance_descriptors();
8224 : int number =
8225 : descriptors->SearchWithCache(isolate, *length_string, *jsarray_map);
8226 : DCHECK_NE(DescriptorArray::kNotFound, number);
8227 5112 : return descriptors->GetDetails(number).IsReadOnly();
8228 : }
8229 :
8230 :
8231 : // static
8232 2704 : bool HOptimizedGraphBuilder::CanInlineArrayResizeOperation(
8233 : Handle<Map> receiver_map) {
8234 5218 : return !receiver_map.is_null() && receiver_map->prototype()->IsJSObject() &&
8235 2600 : receiver_map->instance_type() == JS_ARRAY_TYPE &&
8236 2567 : IsFastElementsKind(receiver_map->elements_kind()) &&
8237 5122 : !receiver_map->is_dictionary_map() && receiver_map->is_extensible() &&
8238 5271 : (!receiver_map->is_prototype_map() || receiver_map->is_stable()) &&
8239 5260 : !IsReadOnlyLengthDescriptor(receiver_map);
8240 : }
8241 :
8242 3028 : bool HOptimizedGraphBuilder::TryInlineBuiltinGetterCall(
8243 135 : Handle<JSFunction> function, Handle<Map> receiver_map, BailoutId ast_id) {
8244 3028 : if (!function->shared()->HasBuiltinFunctionId()) return false;
8245 : BuiltinFunctionId id = function->shared()->builtin_function_id();
8246 :
8247 : // Try to inline getter calls like DataView.prototype.byteLength/byteOffset
8248 : // as operations in the calling function.
8249 160 : switch (id) {
8250 : case kDataViewBuffer: {
8251 0 : if (!receiver_map->IsJSDataViewMap()) return false;
8252 : HObjectAccess access = HObjectAccess::ForMapAndOffset(
8253 0 : receiver_map, JSDataView::kBufferOffset);
8254 : HValue* object = Pop(); // receiver
8255 0 : HInstruction* result = New<HLoadNamedField>(object, object, access);
8256 0 : ast_context()->ReturnInstruction(result, ast_id);
8257 0 : return true;
8258 : }
8259 : case kDataViewByteLength:
8260 : case kDataViewByteOffset: {
8261 12 : if (!receiver_map->IsJSDataViewMap()) return false;
8262 : int offset = (id == kDataViewByteLength) ? JSDataView::kByteLengthOffset
8263 12 : : JSDataView::kByteOffsetOffset;
8264 : HObjectAccess access =
8265 12 : HObjectAccess::ForMapAndOffset(receiver_map, offset);
8266 : HValue* object = Pop(); // receiver
8267 12 : HValue* checked_object = Add<HCheckArrayBufferNotNeutered>(object);
8268 : HInstruction* result =
8269 12 : New<HLoadNamedField>(object, checked_object, access);
8270 12 : ast_context()->ReturnInstruction(result, ast_id);
8271 12 : return true;
8272 : }
8273 : case kTypedArrayByteLength:
8274 : case kTypedArrayByteOffset:
8275 : case kTypedArrayLength: {
8276 123 : if (!receiver_map->IsJSTypedArrayMap()) return false;
8277 : int offset = (id == kTypedArrayLength)
8278 : ? JSTypedArray::kLengthOffset
8279 : : (id == kTypedArrayByteLength)
8280 : ? JSTypedArray::kByteLengthOffset
8281 123 : : JSTypedArray::kByteOffsetOffset;
8282 : HObjectAccess access =
8283 123 : HObjectAccess::ForMapAndOffset(receiver_map, offset);
8284 : HValue* object = Pop(); // receiver
8285 123 : HValue* checked_object = Add<HCheckArrayBufferNotNeutered>(object);
8286 : HInstruction* result =
8287 123 : New<HLoadNamedField>(object, checked_object, access);
8288 123 : ast_context()->ReturnInstruction(result, ast_id);
8289 123 : return true;
8290 : }
8291 : default:
8292 : return false;
8293 : }
8294 : }
8295 :
8296 : // static
8297 119 : bool HOptimizedGraphBuilder::NoElementsInPrototypeChain(
8298 : Handle<Map> receiver_map) {
8299 : // TODO(ishell): remove this once we support NO_ELEMENTS elements kind.
8300 119 : PrototypeIterator iter(receiver_map);
8301 : Handle<Object> empty_fixed_array =
8302 119 : iter.isolate()->factory()->empty_fixed_array();
8303 : while (true) {
8304 : Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter);
8305 223 : if (current->elements() != *empty_fixed_array) return false;
8306 208 : iter.Advance();
8307 208 : if (iter.IsAtEnd()) {
8308 : return true;
8309 : }
8310 : }
8311 : }
8312 :
8313 86713 : bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
8314 : Handle<JSFunction> function, Handle<Map> receiver_map, BailoutId ast_id,
8315 32357 : int args_count_no_receiver) {
8316 86713 : if (!function->shared()->HasBuiltinFunctionId()) return false;
8317 : BuiltinFunctionId id = function->shared()->builtin_function_id();
8318 48908 : int argument_count = args_count_no_receiver + 1; // Plus receiver.
8319 :
8320 48908 : if (receiver_map.is_null()) {
8321 6191 : HValue* receiver = environment()->ExpressionStackAt(args_count_no_receiver);
8322 1188 : if (receiver->IsConstant() &&
8323 542 : HConstant::cast(receiver)->handle(isolate())->IsHeapObject()) {
8324 : receiver_map =
8325 : handle(Handle<HeapObject>::cast(
8326 73 : HConstant::cast(receiver)->handle(isolate()))->map());
8327 : }
8328 : }
8329 : // Try to inline calls like Math.* as operations in the calling function.
8330 48908 : switch (id) {
8331 : case kObjectHasOwnProperty: {
8332 : // It's not safe to look through the phi for elements if we're compiling
8333 : // for osr.
8334 34 : if (top_info()->is_osr()) return false;
8335 19 : if (argument_count != 2) return false;
8336 : HValue* key = Top();
8337 19 : if (!key->IsLoadKeyed()) return false;
8338 : HValue* elements = HLoadKeyed::cast(key)->elements();
8339 3 : if (!elements->IsPhi() || elements->OperandCount() != 1) return false;
8340 0 : if (!elements->OperandAt(0)->IsForInCacheArray()) return false;
8341 0 : HForInCacheArray* cache = HForInCacheArray::cast(elements->OperandAt(0));
8342 : HValue* receiver = environment()->ExpressionStackAt(1);
8343 0 : if (!receiver->IsPhi() || receiver->OperandCount() != 1) return false;
8344 0 : if (cache->enumerable() != receiver->OperandAt(0)) return false;
8345 : Drop(3); // key, receiver, function
8346 0 : Add<HCheckMapValue>(receiver, cache->map());
8347 0 : ast_context()->ReturnValue(graph()->GetConstantTrue());
8348 0 : return true;
8349 : }
8350 : case kStringCharCodeAt:
8351 : case kStringCharAt:
8352 354 : if (argument_count == 2) {
8353 : HValue* index = Pop();
8354 : HValue* string = Pop();
8355 : Drop(1); // Function.
8356 : HInstruction* char_code =
8357 348 : BuildStringCharCodeAt(string, index);
8358 348 : if (id == kStringCharCodeAt) {
8359 213 : ast_context()->ReturnInstruction(char_code, ast_id);
8360 213 : return true;
8361 : }
8362 135 : AddInstruction(char_code);
8363 135 : HInstruction* result = NewUncasted<HStringCharFromCode>(char_code);
8364 135 : ast_context()->ReturnInstruction(result, ast_id);
8365 135 : return true;
8366 : }
8367 : break;
8368 : case kStringFromCharCode:
8369 322 : if (argument_count == 2) {
8370 : HValue* argument = Pop();
8371 : Drop(2); // Receiver and function.
8372 : argument = AddUncasted<HForceRepresentation>(
8373 297 : argument, Representation::Integer32());
8374 : argument->SetFlag(HValue::kTruncatingToInt32);
8375 297 : HInstruction* result = NewUncasted<HStringCharFromCode>(argument);
8376 297 : ast_context()->ReturnInstruction(result, ast_id);
8377 297 : return true;
8378 : }
8379 : break;
8380 : case kMathCos:
8381 : case kMathExp:
8382 : case kMathRound:
8383 : case kMathFround:
8384 : case kMathFloor:
8385 : case kMathAbs:
8386 : case kMathSin:
8387 : case kMathSqrt:
8388 : case kMathLog:
8389 : case kMathClz32:
8390 20724 : if (argument_count == 2) {
8391 : HValue* argument = Pop();
8392 : Drop(2); // Receiver and function.
8393 20717 : HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id);
8394 20717 : ast_context()->ReturnInstruction(op, ast_id);
8395 20717 : return true;
8396 : }
8397 : break;
8398 : case kMathPow:
8399 1138 : if (argument_count == 3) {
8400 : HValue* right = Pop();
8401 : HValue* left = Pop();
8402 : Drop(2); // Receiver and function.
8403 : HInstruction* result = NULL;
8404 : // Use sqrt() if exponent is 0.5 or -0.5.
8405 2036 : if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) {
8406 877 : double exponent = HConstant::cast(right)->DoubleValue();
8407 877 : if (exponent == 0.5) {
8408 49 : result = NewUncasted<HUnaryMathOperation>(left, kMathPowHalf);
8409 828 : } else if (exponent == -0.5) {
8410 : HValue* one = graph()->GetConstant1();
8411 : HInstruction* sqrt = AddUncasted<HUnaryMathOperation>(
8412 46 : left, kMathPowHalf);
8413 : // MathPowHalf doesn't have side effects so there's no need for
8414 : // an environment simulation here.
8415 : DCHECK(!sqrt->HasObservableSideEffects());
8416 46 : result = NewUncasted<HDiv>(one, sqrt);
8417 782 : } else if (exponent == 2.0) {
8418 43 : result = NewUncasted<HMul>(left, left);
8419 : }
8420 : }
8421 :
8422 1127 : if (result == NULL) {
8423 989 : result = NewUncasted<HPower>(left, right);
8424 : }
8425 1127 : ast_context()->ReturnInstruction(result, ast_id);
8426 1127 : return true;
8427 : }
8428 : break;
8429 : case kMathMax:
8430 : case kMathMin:
8431 1802 : if (argument_count == 3) {
8432 : HValue* right = Pop();
8433 : HValue* left = Pop();
8434 : Drop(2); // Receiver and function.
8435 : HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin
8436 1751 : : HMathMinMax::kMathMax;
8437 1751 : HInstruction* result = NewUncasted<HMathMinMax>(left, right, op);
8438 1751 : ast_context()->ReturnInstruction(result, ast_id);
8439 1751 : return true;
8440 : }
8441 : break;
8442 : case kMathImul:
8443 30 : if (argument_count == 3) {
8444 : HValue* right = Pop();
8445 : HValue* left = Pop();
8446 : Drop(2); // Receiver and function.
8447 : HInstruction* result =
8448 60 : HMul::NewImul(isolate(), zone(), context(), left, right);
8449 30 : ast_context()->ReturnInstruction(result, ast_id);
8450 30 : return true;
8451 : }
8452 : break;
8453 : case kArrayPop: {
8454 183 : if (!CanInlineArrayResizeOperation(receiver_map)) return false;
8455 : ElementsKind elements_kind = receiver_map->elements_kind();
8456 :
8457 : Drop(args_count_no_receiver);
8458 : HValue* result;
8459 : HValue* reduced_length;
8460 : HValue* receiver = Pop();
8461 :
8462 142 : HValue* checked_object = AddCheckMap(receiver, receiver_map);
8463 : HValue* length =
8464 : Add<HLoadNamedField>(checked_object, nullptr,
8465 142 : HObjectAccess::ForArrayLength(elements_kind));
8466 :
8467 : Drop(1); // Function.
8468 :
8469 : { NoObservableSideEffectsScope scope(this);
8470 : IfBuilder length_checker(this);
8471 :
8472 : HValue* bounds_check = length_checker.If<HCompareNumericAndBranch>(
8473 142 : length, graph()->GetConstant0(), Token::EQ);
8474 142 : length_checker.Then();
8475 :
8476 279 : if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined());
8477 :
8478 : length_checker.Else();
8479 : HValue* elements = AddLoadElements(checked_object);
8480 : // Ensure that we aren't popping from a copy-on-write array.
8481 142 : if (IsFastSmiOrObjectElementsKind(elements_kind)) {
8482 : elements = BuildCopyElementsOnWrite(checked_object, elements,
8483 120 : elements_kind, length);
8484 : }
8485 142 : reduced_length = AddUncasted<HSub>(length, graph()->GetConstant1());
8486 : result = AddElementAccess(elements, reduced_length, nullptr,
8487 142 : bounds_check, nullptr, elements_kind, LOAD);
8488 : HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind)
8489 : ? graph()->GetConstantHole()
8490 262 : : Add<HConstant>(HConstant::kHoleNaN);
8491 142 : if (IsFastSmiOrObjectElementsKind(elements_kind)) {
8492 : elements_kind = FAST_HOLEY_ELEMENTS;
8493 : }
8494 : AddElementAccess(elements, reduced_length, hole, bounds_check, nullptr,
8495 142 : elements_kind, STORE);
8496 : Add<HStoreNamedField>(
8497 : checked_object, HObjectAccess::ForArrayLength(elements_kind),
8498 142 : reduced_length, STORE_TO_INITIALIZED_ENTRY);
8499 :
8500 142 : if (!ast_context()->IsEffect()) Push(result);
8501 :
8502 142 : length_checker.End();
8503 : }
8504 142 : result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top();
8505 142 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
8506 142 : if (!ast_context()->IsEffect()) Drop(1);
8507 :
8508 142 : ast_context()->ReturnValue(result);
8509 142 : return true;
8510 : }
8511 : case kArrayPush: {
8512 2377 : if (!CanInlineArrayResizeOperation(receiver_map)) return false;
8513 : ElementsKind elements_kind = receiver_map->elements_kind();
8514 :
8515 : // If there may be elements accessors in the prototype chain, the fast
8516 : // inlined version can't be used.
8517 2262 : if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false;
8518 : // If there currently can be no elements accessors on the prototype chain,
8519 : // it doesn't mean that there won't be any later. Install a full prototype
8520 : // chain check to trap element accessors being installed on the prototype
8521 : // chain, which would cause elements to go to dictionary mode and result
8522 : // in a map change.
8523 : Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype()));
8524 2257 : BuildCheckPrototypeMaps(prototype, Handle<JSObject>());
8525 :
8526 : // Protect against adding elements to the Array prototype, which needs to
8527 : // route through appropriate bottlenecks.
8528 4501 : if (isolate()->IsFastArrayConstructorPrototypeChainIntact() &&
8529 : !prototype->IsJSArray()) {
8530 : return false;
8531 : }
8532 :
8533 : const int argc = args_count_no_receiver;
8534 2086 : if (argc != 1) return false;
8535 :
8536 : HValue* value_to_push = Pop();
8537 : HValue* array = Pop();
8538 : Drop(1); // Drop function.
8539 :
8540 : HInstruction* new_size = NULL;
8541 : HValue* length = NULL;
8542 :
8543 : {
8544 : NoObservableSideEffectsScope scope(this);
8545 :
8546 : length = Add<HLoadNamedField>(
8547 2081 : array, nullptr, HObjectAccess::ForArrayLength(elements_kind));
8548 :
8549 2081 : new_size = AddUncasted<HAdd>(length, graph()->GetConstant1());
8550 :
8551 2081 : bool is_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
8552 2081 : HValue* checked_array = Add<HCheckMaps>(array, receiver_map);
8553 : BuildUncheckedMonomorphicElementAccess(
8554 : checked_array, length, value_to_push, is_array, elements_kind,
8555 2081 : STORE, NEVER_RETURN_HOLE, STORE_AND_GROW_NO_TRANSITION);
8556 :
8557 2081 : if (!ast_context()->IsEffect()) Push(new_size);
8558 2081 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
8559 2081 : if (!ast_context()->IsEffect()) Drop(1);
8560 : }
8561 :
8562 2081 : ast_context()->ReturnValue(new_size);
8563 2081 : return true;
8564 : }
8565 : case kArrayShift: {
8566 144 : if (!CanInlineArrayResizeOperation(receiver_map)) return false;
8567 119 : if (!NoElementsInPrototypeChain(receiver_map)) return false;
8568 : ElementsKind kind = receiver_map->elements_kind();
8569 :
8570 : // If there may be elements accessors in the prototype chain, the fast
8571 : // inlined version can't be used.
8572 104 : if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false;
8573 :
8574 : // If there currently can be no elements accessors on the prototype chain,
8575 : // it doesn't mean that there won't be any later. Install a full prototype
8576 : // chain check to trap element accessors being installed on the prototype
8577 : // chain, which would cause elements to go to dictionary mode and result
8578 : // in a map change.
8579 : BuildCheckPrototypeMaps(
8580 : handle(JSObject::cast(receiver_map->prototype()), isolate()),
8581 104 : Handle<JSObject>::null(), true);
8582 :
8583 : // Threshold for fast inlined Array.shift().
8584 104 : HConstant* inline_threshold = Add<HConstant>(static_cast<int32_t>(16));
8585 :
8586 : Drop(args_count_no_receiver);
8587 : HValue* result;
8588 : HValue* receiver = Pop();
8589 104 : HValue* checked_object = AddCheckMap(receiver, receiver_map);
8590 : HValue* length = Add<HLoadNamedField>(
8591 104 : receiver, checked_object, HObjectAccess::ForArrayLength(kind));
8592 :
8593 : Drop(1); // Function.
8594 : {
8595 : NoObservableSideEffectsScope scope(this);
8596 :
8597 : IfBuilder if_lengthiszero(this);
8598 : HValue* lengthiszero = if_lengthiszero.If<HCompareNumericAndBranch>(
8599 104 : length, graph()->GetConstant0(), Token::EQ);
8600 104 : if_lengthiszero.Then();
8601 : {
8602 173 : if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined());
8603 : }
8604 : if_lengthiszero.Else();
8605 : {
8606 : HValue* elements = AddLoadElements(receiver);
8607 :
8608 : // Check if we can use the fast inlined Array.shift().
8609 : IfBuilder if_inline(this);
8610 : if_inline.If<HCompareNumericAndBranch>(
8611 104 : length, inline_threshold, Token::LTE);
8612 104 : if (IsFastSmiOrObjectElementsKind(kind)) {
8613 : // We cannot handle copy-on-write backing stores here.
8614 : if_inline.AndIf<HCompareMap>(
8615 : elements, isolate()->factory()->fixed_array_map());
8616 : }
8617 104 : if_inline.Then();
8618 : {
8619 : // Remember the result.
8620 104 : if (!ast_context()->IsEffect()) {
8621 : Push(AddElementAccess(elements, graph()->GetConstant0(), nullptr,
8622 69 : lengthiszero, nullptr, kind, LOAD));
8623 : }
8624 :
8625 : // Compute the new length.
8626 : HValue* new_length = AddUncasted<HSub>(
8627 104 : length, graph()->GetConstant1());
8628 : new_length->ClearFlag(HValue::kCanOverflow);
8629 :
8630 : // Copy the remaining elements.
8631 104 : LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement);
8632 : {
8633 : HValue* new_key = loop.BeginBody(
8634 104 : graph()->GetConstant0(), new_length, Token::LT);
8635 104 : HValue* key = AddUncasted<HAdd>(new_key, graph()->GetConstant1());
8636 : key->ClearFlag(HValue::kCanOverflow);
8637 : ElementsKind copy_kind =
8638 104 : kind == FAST_HOLEY_SMI_ELEMENTS ? FAST_HOLEY_ELEMENTS : kind;
8639 : HValue* element =
8640 : AddUncasted<HLoadKeyed>(elements, key, lengthiszero, nullptr,
8641 104 : copy_kind, ALLOW_RETURN_HOLE);
8642 : HStoreKeyed* store = Add<HStoreKeyed>(elements, new_key, element,
8643 104 : nullptr, copy_kind);
8644 : store->SetFlag(HValue::kTruncatingToNumber);
8645 : }
8646 104 : loop.EndBody();
8647 :
8648 : // Put a hole at the end.
8649 : HValue* hole = IsFastSmiOrObjectElementsKind(kind)
8650 : ? graph()->GetConstantHole()
8651 203 : : Add<HConstant>(HConstant::kHoleNaN);
8652 104 : if (IsFastSmiOrObjectElementsKind(kind)) kind = FAST_HOLEY_ELEMENTS;
8653 : Add<HStoreKeyed>(elements, new_length, hole, nullptr, kind,
8654 104 : INITIALIZING_STORE);
8655 :
8656 : // Remember new length.
8657 : Add<HStoreNamedField>(
8658 : receiver, HObjectAccess::ForArrayLength(kind),
8659 104 : new_length, STORE_TO_INITIALIZED_ENTRY);
8660 : }
8661 : if_inline.Else();
8662 : {
8663 104 : Add<HPushArguments>(receiver);
8664 : result = AddInstruction(NewCallConstantFunction(
8665 104 : function, 1, TailCallMode::kDisallow, TailCallMode::kDisallow));
8666 104 : if (!ast_context()->IsEffect()) Push(result);
8667 : }
8668 104 : if_inline.End();
8669 : }
8670 104 : if_lengthiszero.End();
8671 : }
8672 104 : result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top();
8673 104 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
8674 104 : if (!ast_context()->IsEffect()) Drop(1);
8675 104 : ast_context()->ReturnValue(result);
8676 104 : return true;
8677 : }
8678 : case kArrayIndexOf:
8679 : case kArrayLastIndexOf: {
8680 191 : if (receiver_map.is_null()) return false;
8681 191 : if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false;
8682 191 : if (!receiver_map->prototype()->IsJSObject()) return false;
8683 : ElementsKind kind = receiver_map->elements_kind();
8684 185 : if (!IsFastElementsKind(kind)) return false;
8685 185 : if (argument_count != 2) return false;
8686 170 : if (!receiver_map->is_extensible()) return false;
8687 :
8688 : // If there may be elements accessors in the prototype chain, the fast
8689 : // inlined version can't be used.
8690 170 : if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false;
8691 :
8692 : // If there currently can be no elements accessors on the prototype chain,
8693 : // it doesn't mean that there won't be any later. Install a full prototype
8694 : // chain check to trap element accessors being installed on the prototype
8695 : // chain, which would cause elements to go to dictionary mode and result
8696 : // in a map change.
8697 : BuildCheckPrototypeMaps(
8698 : handle(JSObject::cast(receiver_map->prototype()), isolate()),
8699 170 : Handle<JSObject>::null());
8700 :
8701 : HValue* search_element = Pop();
8702 : HValue* receiver = Pop();
8703 : Drop(1); // Drop function.
8704 :
8705 : ArrayIndexOfMode mode = (id == kArrayIndexOf)
8706 170 : ? kFirstIndexOf : kLastIndexOf;
8707 170 : HValue* index = BuildArrayIndexOf(receiver, search_element, kind, mode);
8708 :
8709 170 : if (!ast_context()->IsEffect()) Push(index);
8710 170 : Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
8711 170 : if (!ast_context()->IsEffect()) Drop(1);
8712 170 : ast_context()->ReturnValue(index);
8713 170 : return true;
8714 : }
8715 : default:
8716 : // Not yet supported for inlining.
8717 : break;
8718 : }
8719 : return false;
8720 : }
8721 :
8722 :
8723 567654 : bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr,
8724 : HValue* receiver) {
8725 189218 : if (V8_UNLIKELY(FLAG_runtime_stats)) return false;
8726 : Handle<JSFunction> function = expr->target();
8727 189218 : int argc = expr->arguments()->length();
8728 : SmallMapList receiver_maps;
8729 : return TryInlineApiCall(function, receiver, &receiver_maps, argc, expr->id(),
8730 189218 : kCallApiFunction, expr->tail_call_mode());
8731 : }
8732 :
8733 :
8734 59576 : bool HOptimizedGraphBuilder::TryInlineApiMethodCall(
8735 119152 : Call* expr,
8736 : HValue* receiver,
8737 : SmallMapList* receiver_maps) {
8738 59576 : if (V8_UNLIKELY(FLAG_runtime_stats)) return false;
8739 : Handle<JSFunction> function = expr->target();
8740 59576 : int argc = expr->arguments()->length();
8741 : return TryInlineApiCall(function, receiver, receiver_maps, argc, expr->id(),
8742 59576 : kCallApiMethod, expr->tail_call_mode());
8743 : }
8744 :
8745 3062 : bool HOptimizedGraphBuilder::TryInlineApiGetter(Handle<Object> function,
8746 : Handle<Map> receiver_map,
8747 : BailoutId ast_id) {
8748 3062 : if (V8_UNLIKELY(FLAG_runtime_stats)) return false;
8749 6124 : SmallMapList receiver_maps(1, zone());
8750 : receiver_maps.Add(receiver_map, zone());
8751 : return TryInlineApiCall(function,
8752 : NULL, // Receiver is on expression stack.
8753 : &receiver_maps, 0, ast_id, kCallApiGetter,
8754 3062 : TailCallMode::kDisallow);
8755 : }
8756 :
8757 246 : bool HOptimizedGraphBuilder::TryInlineApiSetter(Handle<Object> function,
8758 : Handle<Map> receiver_map,
8759 : BailoutId ast_id) {
8760 492 : SmallMapList receiver_maps(1, zone());
8761 : receiver_maps.Add(receiver_map, zone());
8762 : return TryInlineApiCall(function,
8763 : NULL, // Receiver is on expression stack.
8764 : &receiver_maps, 1, ast_id, kCallApiSetter,
8765 246 : TailCallMode::kDisallow);
8766 : }
8767 :
8768 252102 : bool HOptimizedGraphBuilder::TryInlineApiCall(
8769 : Handle<Object> function, HValue* receiver, SmallMapList* receiver_maps,
8770 : int argc, BailoutId ast_id, ApiCallType call_type,
8771 11205 : TailCallMode syntactic_tail_call_mode) {
8772 252102 : if (V8_UNLIKELY(FLAG_runtime_stats)) return false;
8773 504189 : if (function->IsJSFunction() &&
8774 : Handle<JSFunction>::cast(function)->context()->native_context() !=
8775 302762 : top_info()->closure()->context()->native_context()) {
8776 : return false;
8777 : }
8778 252051 : if (argc > CallApiCallbackStub::kArgMax) {
8779 : return false;
8780 : }
8781 :
8782 252024 : CallOptimization optimization(function);
8783 252024 : if (!optimization.is_simple_api_call()) return false;
8784 : Handle<Map> holder_map;
8785 16564 : for (int i = 0; i < receiver_maps->length(); ++i) {
8786 : auto map = receiver_maps->at(i);
8787 : // Don't inline calls to receivers requiring accesschecks.
8788 2678 : if (map->is_access_check_needed()) return false;
8789 : }
8790 11208 : if (call_type == kCallApiFunction) {
8791 : // Cannot embed a direct reference to the global proxy map
8792 : // as it maybe dropped on deserialization.
8793 8530 : CHECK(!isolate()->serializer_enabled());
8794 : DCHECK(function->IsJSFunction());
8795 : DCHECK_EQ(0, receiver_maps->length());
8796 : receiver_maps->Add(
8797 : handle(Handle<JSFunction>::cast(function)->global_proxy()->map()),
8798 : zone());
8799 : }
8800 : CallOptimization::HolderLookup holder_lookup =
8801 11208 : CallOptimization::kHolderNotFound;
8802 : Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType(
8803 11208 : receiver_maps->first(), &holder_lookup);
8804 11208 : if (holder_lookup == CallOptimization::kHolderNotFound) return false;
8805 :
8806 11205 : if (FLAG_trace_inlining) {
8807 0 : PrintF("Inlining api function ");
8808 0 : function->ShortPrint();
8809 0 : PrintF("\n");
8810 : }
8811 :
8812 : bool is_function = false;
8813 : bool is_store = false;
8814 11205 : switch (call_type) {
8815 : case kCallApiFunction:
8816 : case kCallApiMethod:
8817 : // Need to check that none of the receiver maps could have changed.
8818 11159 : Add<HCheckMaps>(receiver, receiver_maps);
8819 : // Need to ensure the chain between receiver and api_holder is intact.
8820 11159 : if (holder_lookup == CallOptimization::kHolderFound) {
8821 3 : AddCheckPrototypeMaps(api_holder, receiver_maps->first());
8822 : } else {
8823 : DCHECK_EQ(holder_lookup, CallOptimization::kHolderIsReceiver);
8824 : }
8825 : // Includes receiver.
8826 11159 : PushArgumentsFromEnvironment(argc + 1);
8827 : is_function = true;
8828 11159 : break;
8829 : case kCallApiGetter:
8830 : // Receiver and prototype chain cannot have changed.
8831 : DCHECK_EQ(0, argc);
8832 : DCHECK_NULL(receiver);
8833 : // Receiver is on expression stack.
8834 : receiver = Pop();
8835 34 : Add<HPushArguments>(receiver);
8836 34 : break;
8837 : case kCallApiSetter:
8838 : {
8839 : is_store = true;
8840 : // Receiver and prototype chain cannot have changed.
8841 : DCHECK_EQ(1, argc);
8842 : DCHECK_NULL(receiver);
8843 : // Receiver and value are on expression stack.
8844 : HValue* value = Pop();
8845 : receiver = Pop();
8846 12 : Add<HPushArguments>(receiver, value);
8847 12 : break;
8848 : }
8849 : }
8850 :
8851 : HValue* holder = NULL;
8852 11205 : switch (holder_lookup) {
8853 : case CallOptimization::kHolderFound:
8854 3 : holder = Add<HConstant>(api_holder);
8855 3 : break;
8856 : case CallOptimization::kHolderIsReceiver:
8857 : holder = receiver;
8858 11202 : break;
8859 : case CallOptimization::kHolderNotFound:
8860 0 : UNREACHABLE();
8861 : break;
8862 : }
8863 : Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
8864 : Handle<Object> call_data_obj(api_call_info->data(), isolate());
8865 11205 : HValue* call_data = Add<HConstant>(call_data_obj);
8866 : ApiFunction fun(v8::ToCData<Address>(api_call_info->callback()));
8867 : ExternalReference ref = ExternalReference(&fun,
8868 : ExternalReference::DIRECT_API_CALL,
8869 11205 : isolate());
8870 11205 : HValue* api_function_address = Add<HConstant>(ExternalReference(ref));
8871 :
8872 11205 : HValue* op_vals[] = {Add<HConstant>(function), call_data, holder,
8873 11205 : api_function_address};
8874 :
8875 : HInstruction* call = nullptr;
8876 11205 : CHECK(argc <= CallApiCallbackStub::kArgMax);
8877 11205 : if (!is_function) {
8878 : CallApiCallbackStub stub(isolate(), is_store,
8879 46 : !optimization.is_constant_call());
8880 46 : Handle<Code> code = stub.GetCode();
8881 46 : HConstant* code_value = Add<HConstant>(code);
8882 : call = New<HCallWithDescriptor>(
8883 : code_value, argc + 1, stub.GetCallInterfaceDescriptor(),
8884 46 : Vector<HValue*>(op_vals, arraysize(op_vals)), syntactic_tail_call_mode);
8885 : } else {
8886 : CallApiCallbackStub stub(isolate(), argc, false);
8887 11159 : Handle<Code> code = stub.GetCode();
8888 11159 : HConstant* code_value = Add<HConstant>(code);
8889 : call = New<HCallWithDescriptor>(
8890 : code_value, argc + 1, stub.GetCallInterfaceDescriptor(),
8891 11159 : Vector<HValue*>(op_vals, arraysize(op_vals)), syntactic_tail_call_mode);
8892 : Drop(1); // Drop function.
8893 : }
8894 :
8895 11205 : ast_context()->ReturnInstruction(call, ast_id);
8896 11205 : return true;
8897 : }
8898 :
8899 :
8900 10642 : void HOptimizedGraphBuilder::HandleIndirectCall(Call* expr, HValue* function,
8901 10508 : int arguments_count) {
8902 : Handle<JSFunction> known_function;
8903 5388 : int args_count_no_receiver = arguments_count - 1;
8904 16164 : if (function->IsConstant() &&
8905 6968 : HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
8906 : known_function =
8907 395 : Handle<JSFunction>::cast(HConstant::cast(function)->handle(isolate()));
8908 790 : if (TryInlineBuiltinMethodCall(known_function, Handle<Map>(), expr->id(),
8909 395 : args_count_no_receiver)) {
8910 25 : if (FLAG_trace_inlining) {
8911 0 : PrintF("Inlining builtin ");
8912 0 : known_function->ShortPrint();
8913 0 : PrintF("\n");
8914 : }
8915 : return;
8916 : }
8917 :
8918 370 : if (TryInlineIndirectCall(known_function, expr, args_count_no_receiver)) {
8919 : return;
8920 : }
8921 : }
8922 :
8923 : TailCallMode syntactic_tail_call_mode = expr->tail_call_mode();
8924 : TailCallMode tail_call_mode =
8925 5254 : function_state()->ComputeTailCallMode(syntactic_tail_call_mode);
8926 :
8927 5254 : PushArgumentsFromEnvironment(arguments_count);
8928 : HInvokeFunction* call =
8929 : New<HInvokeFunction>(function, known_function, arguments_count,
8930 5254 : syntactic_tail_call_mode, tail_call_mode);
8931 : Drop(1); // Function
8932 10508 : ast_context()->ReturnInstruction(call, expr->id());
8933 : }
8934 :
8935 :
8936 97182 : bool HOptimizedGraphBuilder::TryIndirectCall(Call* expr) {
8937 : DCHECK(expr->expression()->IsProperty());
8938 :
8939 91866 : if (!expr->IsMonomorphic()) {
8940 : return false;
8941 : }
8942 90853 : Handle<Map> function_map = expr->GetReceiverTypes()->first();
8943 104702 : if (function_map->instance_type() != JS_FUNCTION_TYPE ||
8944 : !expr->target()->shared()->HasBuiltinFunctionId()) {
8945 : return false;
8946 : }
8947 :
8948 6679 : switch (expr->target()->shared()->builtin_function_id()) {
8949 : case kFunctionCall: {
8950 5316 : if (expr->arguments()->length() == 0) return false;
8951 5295 : BuildFunctionCall(expr);
8952 5295 : return true;
8953 : }
8954 : case kFunctionApply: {
8955 : // For .apply, only the pattern f.apply(receiver, arguments)
8956 : // is supported.
8957 324 : if (!CanBeFunctionApplyArguments(expr)) return false;
8958 :
8959 231 : BuildFunctionApply(expr);
8960 231 : return true;
8961 : }
8962 : default: { return false; }
8963 : }
8964 : UNREACHABLE();
8965 : }
8966 :
8967 :
8968 : // f.apply(...)
8969 965 : void HOptimizedGraphBuilder::BuildFunctionApply(Call* expr) {
8970 : ZoneList<Expression*>* args = expr->arguments();
8971 462 : CHECK_ALIVE(VisitForValue(args->at(0)));
8972 : HValue* receiver = Pop(); // receiver
8973 : HValue* function = Pop(); // f
8974 : Drop(1); // apply
8975 :
8976 : // Make sure the arguments object is live.
8977 462 : VariableProxy* arg_two = args->at(1)->AsVariableProxy();
8978 231 : LookupAndMakeLive(arg_two->var());
8979 :
8980 462 : Handle<Map> function_map = expr->GetReceiverTypes()->first();
8981 231 : HValue* checked_function = AddCheckMap(function, function_map);
8982 :
8983 231 : if (function_state()->outer() == NULL) {
8984 : TailCallMode syntactic_tail_call_mode = expr->tail_call_mode();
8985 : TailCallMode tail_call_mode =
8986 136 : function_state()->ComputeTailCallMode(syntactic_tail_call_mode);
8987 :
8988 136 : HInstruction* elements = Add<HArgumentsElements>(false);
8989 136 : HInstruction* length = Add<HArgumentsLength>(elements);
8990 136 : HValue* wrapped_receiver = BuildWrapReceiver(receiver, checked_function);
8991 : HInstruction* result = New<HApplyArguments>(
8992 136 : function, wrapped_receiver, length, elements, tail_call_mode);
8993 272 : ast_context()->ReturnInstruction(result, expr->id());
8994 : } else {
8995 : // We are inside inlined function and we know exactly what is inside
8996 : // arguments object. But we need to be able to materialize at deopt.
8997 : DCHECK_EQ(environment()->arguments_environment()->parameter_count(),
8998 : function_state()->entry()->arguments_object()->arguments_count());
8999 95 : HArgumentsObject* args = function_state()->entry()->arguments_object();
9000 : const ZoneList<HValue*>* arguments_values = args->arguments_values();
9001 95 : int arguments_count = arguments_values->length();
9002 95 : Push(function);
9003 95 : Push(BuildWrapReceiver(receiver, checked_function));
9004 245 : for (int i = 1; i < arguments_count; i++) {
9005 150 : Push(arguments_values->at(i));
9006 : }
9007 95 : HandleIndirectCall(expr, function, arguments_count);
9008 : }
9009 : }
9010 :
9011 :
9012 : // f.call(...)
9013 21178 : void HOptimizedGraphBuilder::BuildFunctionCall(Call* expr) {
9014 : HValue* function = Top(); // f
9015 10590 : Handle<Map> function_map = expr->GetReceiverTypes()->first();
9016 5295 : HValue* checked_function = AddCheckMap(function, function_map);
9017 :
9018 : // f and call are on the stack in the unoptimized code
9019 : // during evaluation of the arguments.
9020 10592 : CHECK_ALIVE(VisitExpressions(expr->arguments()));
9021 :
9022 5293 : int args_length = expr->arguments()->length();
9023 5293 : int receiver_index = args_length - 1;
9024 : // Patch the receiver.
9025 : HValue* receiver = BuildWrapReceiver(
9026 5293 : environment()->ExpressionStackAt(receiver_index), checked_function);
9027 : environment()->SetExpressionStackAt(receiver_index, receiver);
9028 :
9029 : // Call must not be on the stack from now on.
9030 5293 : int call_index = args_length + 1;
9031 5293 : environment()->RemoveExpressionStackAt(call_index);
9032 :
9033 5293 : HandleIndirectCall(expr, function, args_length);
9034 : }
9035 :
9036 :
9037 202080 : HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function,
9038 : Handle<JSFunction> target) {
9039 : SharedFunctionInfo* shared = target->shared();
9040 396491 : if (is_sloppy(shared->language_mode()) && !shared->native()) {
9041 : // Cannot embed a direct reference to the global proxy
9042 : // as is it dropped on deserialization.
9043 341182 : CHECK(!isolate()->serializer_enabled());
9044 139102 : Handle<JSObject> global_proxy(target->context()->global_proxy());
9045 139102 : return Add<HConstant>(global_proxy);
9046 : }
9047 62978 : return graph()->GetConstantUndefined();
9048 : }
9049 :
9050 :
9051 170 : HValue* HOptimizedGraphBuilder::BuildArrayIndexOf(HValue* receiver,
9052 : HValue* search_element,
9053 : ElementsKind kind,
9054 : ArrayIndexOfMode mode) {
9055 : DCHECK(IsFastElementsKind(kind));
9056 :
9057 680 : NoObservableSideEffectsScope no_effects(this);
9058 :
9059 : HValue* elements = AddLoadElements(receiver);
9060 170 : HValue* length = AddLoadArrayLength(receiver, kind);
9061 :
9062 : HValue* initial;
9063 : HValue* terminating;
9064 : Token::Value token;
9065 : LoopBuilder::Direction direction;
9066 170 : if (mode == kFirstIndexOf) {
9067 : initial = graph()->GetConstant0();
9068 : terminating = length;
9069 : token = Token::LT;
9070 : direction = LoopBuilder::kPostIncrement;
9071 : } else {
9072 : DCHECK_EQ(kLastIndexOf, mode);
9073 : initial = length;
9074 : terminating = graph()->GetConstant0();
9075 : token = Token::GT;
9076 : direction = LoopBuilder::kPreDecrement;
9077 : }
9078 :
9079 170 : Push(graph()->GetConstantMinus1());
9080 170 : if (IsFastDoubleElementsKind(kind) || IsFastSmiElementsKind(kind)) {
9081 : // Make sure that we can actually compare numbers correctly below, see
9082 : // https://code.google.com/p/chromium/issues/detail?id=407946 for details.
9083 : search_element = AddUncasted<HForceRepresentation>(
9084 : search_element, IsFastSmiElementsKind(kind) ? Representation::Smi()
9085 85 : : Representation::Double());
9086 :
9087 85 : LoopBuilder loop(this, context(), direction);
9088 : {
9089 85 : HValue* index = loop.BeginBody(initial, terminating, token);
9090 : HValue* element = AddUncasted<HLoadKeyed>(
9091 85 : elements, index, nullptr, nullptr, kind, ALLOW_RETURN_HOLE);
9092 : IfBuilder if_issame(this);
9093 : if_issame.If<HCompareNumericAndBranch>(element, search_element,
9094 85 : Token::EQ_STRICT);
9095 85 : if_issame.Then();
9096 : {
9097 : Drop(1);
9098 85 : Push(index);
9099 85 : loop.Break();
9100 : }
9101 85 : if_issame.End();
9102 : }
9103 85 : loop.EndBody();
9104 : } else {
9105 : IfBuilder if_isstring(this);
9106 85 : if_isstring.If<HIsStringAndBranch>(search_element);
9107 85 : if_isstring.Then();
9108 : {
9109 85 : LoopBuilder loop(this, context(), direction);
9110 : {
9111 85 : HValue* index = loop.BeginBody(initial, terminating, token);
9112 : HValue* element = AddUncasted<HLoadKeyed>(
9113 85 : elements, index, nullptr, nullptr, kind, ALLOW_RETURN_HOLE);
9114 : IfBuilder if_issame(this);
9115 85 : if_issame.If<HIsStringAndBranch>(element);
9116 : if_issame.AndIf<HStringCompareAndBranch>(
9117 : element, search_element, Token::EQ_STRICT);
9118 85 : if_issame.Then();
9119 : {
9120 : Drop(1);
9121 85 : Push(index);
9122 85 : loop.Break();
9123 : }
9124 85 : if_issame.End();
9125 : }
9126 85 : loop.EndBody();
9127 : }
9128 : if_isstring.Else();
9129 : {
9130 : IfBuilder if_isnumber(this);
9131 85 : if_isnumber.If<HIsSmiAndBranch>(search_element);
9132 : if_isnumber.OrIf<HCompareMap>(
9133 : search_element, isolate()->factory()->heap_number_map());
9134 85 : if_isnumber.Then();
9135 : {
9136 : HValue* search_number =
9137 : AddUncasted<HForceRepresentation>(search_element,
9138 85 : Representation::Double());
9139 85 : LoopBuilder loop(this, context(), direction);
9140 : {
9141 85 : HValue* index = loop.BeginBody(initial, terminating, token);
9142 : HValue* element = AddUncasted<HLoadKeyed>(
9143 85 : elements, index, nullptr, nullptr, kind, ALLOW_RETURN_HOLE);
9144 :
9145 : IfBuilder if_element_isnumber(this);
9146 85 : if_element_isnumber.If<HIsSmiAndBranch>(element);
9147 : if_element_isnumber.OrIf<HCompareMap>(
9148 : element, isolate()->factory()->heap_number_map());
9149 85 : if_element_isnumber.Then();
9150 : {
9151 : HValue* number =
9152 : AddUncasted<HForceRepresentation>(element,
9153 85 : Representation::Double());
9154 : IfBuilder if_issame(this);
9155 : if_issame.If<HCompareNumericAndBranch>(
9156 85 : number, search_number, Token::EQ_STRICT);
9157 85 : if_issame.Then();
9158 : {
9159 : Drop(1);
9160 85 : Push(index);
9161 85 : loop.Break();
9162 : }
9163 85 : if_issame.End();
9164 : }
9165 85 : if_element_isnumber.End();
9166 : }
9167 85 : loop.EndBody();
9168 : }
9169 : if_isnumber.Else();
9170 : {
9171 85 : LoopBuilder loop(this, context(), direction);
9172 : {
9173 85 : HValue* index = loop.BeginBody(initial, terminating, token);
9174 : HValue* element = AddUncasted<HLoadKeyed>(
9175 85 : elements, index, nullptr, nullptr, kind, ALLOW_RETURN_HOLE);
9176 : IfBuilder if_issame(this);
9177 : if_issame.If<HCompareObjectEqAndBranch>(
9178 85 : element, search_element);
9179 85 : if_issame.Then();
9180 : {
9181 : Drop(1);
9182 85 : Push(index);
9183 85 : loop.Break();
9184 : }
9185 85 : if_issame.End();
9186 : }
9187 85 : loop.EndBody();
9188 : }
9189 85 : if_isnumber.End();
9190 : }
9191 85 : if_isstring.End();
9192 : }
9193 :
9194 170 : return Pop();
9195 : }
9196 :
9197 : template <class T>
9198 209363 : bool HOptimizedGraphBuilder::TryHandleArrayCall(T* expr, HValue* function) {
9199 416598 : if (!array_function().is_identical_to(expr->target())) {
9200 : return false;
9201 : }
9202 :
9203 : Handle<AllocationSite> site = expr->allocation_site();
9204 2938 : if (site.is_null()) return false;
9205 :
9206 658 : Add<HCheckValue>(function, array_function());
9207 :
9208 658 : int arguments_count = expr->arguments()->length();
9209 658 : if (TryInlineArrayCall(expr, arguments_count, site)) return true;
9210 :
9211 : HInstruction* call = PreProcessCall(New<HCallNewArray>(
9212 406 : function, arguments_count + 1, site->GetElementsKind(), site));
9213 406 : if (expr->IsCall()) Drop(1);
9214 812 : ast_context()->ReturnInstruction(call, expr->id());
9215 :
9216 406 : return true;
9217 : }
9218 :
9219 :
9220 115261 : bool HOptimizedGraphBuilder::CanBeFunctionApplyArguments(Call* expr) {
9221 : ZoneList<Expression*>* args = expr->arguments();
9222 115261 : if (args->length() != 2) return false;
9223 16769 : VariableProxy* arg_two = args->at(1)->AsVariableProxy();
9224 14299 : if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
9225 2470 : HValue* arg_two_value = environment()->Lookup(arg_two->var());
9226 2470 : if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
9227 : DCHECK_NOT_NULL(current_info()->scope()->arguments());
9228 264 : return true;
9229 : }
9230 :
9231 :
9232 6485050 : void HOptimizedGraphBuilder::VisitCall(Call* expr) {
9233 : DCHECK(!HasStackOverflow());
9234 : DCHECK(current_block() != NULL);
9235 : DCHECK(current_block()->HasPredecessor());
9236 3113056 : if (!is_tracking_positions()) SetSourcePosition(expr->position());
9237 : Expression* callee = expr->expression();
9238 653398 : int argument_count = expr->arguments()->length() + 1; // Plus receiver.
9239 : HInstruction* call = NULL;
9240 :
9241 : TailCallMode syntactic_tail_call_mode = expr->tail_call_mode();
9242 : TailCallMode tail_call_mode =
9243 653398 : function_state()->ComputeTailCallMode(syntactic_tail_call_mode);
9244 :
9245 1376507 : Property* prop = callee->AsProperty();
9246 653398 : if (prop != NULL) {
9247 668576 : CHECK_ALIVE(VisitForValue(prop->obj()));
9248 : HValue* receiver = Top();
9249 :
9250 : SmallMapList* maps;
9251 208489 : ComputeReceiverTypes(expr, receiver, &maps, this);
9252 :
9253 416554 : if (prop->key()->IsPropertyName() && maps->length() > 0) {
9254 98891 : Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
9255 197782 : PropertyAccessInfo info(this, LOAD, maps->first(), name);
9256 98891 : if (!info.CanAccessAsMonomorphic(maps)) {
9257 1686 : HandlePolymorphicCallNamed(expr, receiver, maps, name);
9258 1686 : return;
9259 : }
9260 : }
9261 : HValue* key = NULL;
9262 206803 : if (!prop->key()->IsPropertyName()) {
9263 1272 : CHECK_ALIVE(VisitForValue(prop->key()));
9264 : key = Pop();
9265 : }
9266 :
9267 620409 : CHECK_ALIVE(PushLoad(prop, receiver, key));
9268 : HValue* function = Pop();
9269 :
9270 620409 : if (function->IsConstant() &&
9271 390639 : HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
9272 : // Push the function under the receiver.
9273 : environment()->SetExpressionStackAt(0, function);
9274 91866 : Push(receiver);
9275 :
9276 : Handle<JSFunction> known_function = Handle<JSFunction>::cast(
9277 91866 : HConstant::cast(function)->handle(isolate()));
9278 : expr->set_target(known_function);
9279 :
9280 133233 : if (TryIndirectCall(expr)) return;
9281 258998 : CHECK_ALIVE(VisitExpressions(expr->arguments()));
9282 :
9283 257941 : Handle<Map> map = maps->length() == 1 ? maps->first() : Handle<Map>();
9284 86318 : if (TryInlineBuiltinMethodCall(known_function, map, expr->id(),
9285 86318 : expr->arguments()->length())) {
9286 26742 : if (FLAG_trace_inlining) {
9287 0 : PrintF("Inlining builtin ");
9288 0 : known_function->ShortPrint();
9289 0 : PrintF("\n");
9290 : }
9291 : return;
9292 : }
9293 59576 : if (TryInlineApiMethodCall(expr, receiver, maps)) return;
9294 :
9295 : // Wrap the receiver if necessary.
9296 113888 : if (NeedsWrapping(maps->first(), known_function)) {
9297 : // Since HWrapReceiver currently cannot actually wrap numbers and
9298 : // strings, use the regular call builtin for method calls to wrap
9299 : // the receiver.
9300 : // TODO(verwaest): Support creation of value wrappers directly in
9301 : // HWrapReceiver.
9302 : call = NewCallFunction(
9303 : function, argument_count, syntactic_tail_call_mode,
9304 9 : ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode);
9305 56935 : } else if (TryInlineCall(expr)) {
9306 : return;
9307 : } else {
9308 : call =
9309 : NewCallConstantFunction(known_function, argument_count,
9310 50490 : syntactic_tail_call_mode, tail_call_mode);
9311 : }
9312 :
9313 : } else {
9314 : ArgumentsAllowedFlag arguments_flag = ARGUMENTS_NOT_ALLOWED;
9315 114970 : if (CanBeFunctionApplyArguments(expr) && expr->is_uninitialized()) {
9316 : // We have to use EAGER deoptimization here because Deoptimizer::SOFT
9317 : // gets ignored by the always-opt flag, which leads to incorrect code.
9318 : Add<HDeoptimize>(
9319 : DeoptimizeReason::kInsufficientTypeFeedbackForCallWithArguments,
9320 26 : Deoptimizer::EAGER);
9321 : arguments_flag = ARGUMENTS_FAKED;
9322 : }
9323 :
9324 : // Push the function under the receiver.
9325 : environment()->SetExpressionStackAt(0, function);
9326 114937 : Push(receiver);
9327 :
9328 344794 : CHECK_ALIVE(VisitExpressions(expr->arguments(), arguments_flag));
9329 : call = NewCallFunction(function, argument_count, syntactic_tail_call_mode,
9330 : ConvertReceiverMode::kNotNullOrUndefined,
9331 114920 : tail_call_mode);
9332 : }
9333 165419 : PushArgumentsFromEnvironment(argument_count);
9334 :
9335 : } else {
9336 444896 : if (expr->is_possibly_eval()) {
9337 : return Bailout(kPossibleDirectCallToEval);
9338 : }
9339 :
9340 : // The function is on the stack in the unoptimized code during
9341 : // evaluation of the arguments.
9342 1334688 : CHECK_ALIVE(VisitForValue(expr->expression()));
9343 : HValue* function = Top();
9344 1334688 : if (function->IsConstant() &&
9345 769224 : HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
9346 162126 : Handle<Object> constant = HConstant::cast(function)->handle(isolate());
9347 : Handle<JSFunction> target = Handle<JSFunction>::cast(constant);
9348 : expr->SetKnownGlobalTarget(target);
9349 : }
9350 :
9351 : // Placeholder for the receiver.
9352 444896 : Push(graph()->GetConstantUndefined());
9353 1334630 : CHECK_ALIVE(VisitExpressions(expr->arguments()));
9354 :
9355 642678 : if (expr->IsMonomorphic() &&
9356 : !IsClassConstructor(expr->target()->shared()->kind())) {
9357 197835 : Add<HCheckValue>(function, expr->target());
9358 :
9359 : // Patch the global object on the stack by the expected receiver.
9360 197835 : HValue* receiver = ImplicitReceiverFor(function, expr->target());
9361 : const int receiver_index = argument_count - 1;
9362 : environment()->SetExpressionStackAt(receiver_index, receiver);
9363 :
9364 197835 : if (TryInlineBuiltinFunctionCall(expr)) {
9365 8617 : if (FLAG_trace_inlining) {
9366 0 : PrintF("Inlining builtin ");
9367 0 : expr->target()->ShortPrint();
9368 0 : PrintF("\n");
9369 : }
9370 : return;
9371 : }
9372 189218 : if (TryInlineApiFunctionCall(expr, receiver)) return;
9373 180691 : if (TryHandleArrayCall(expr, function)) return;
9374 180582 : if (TryInlineCall(expr)) return;
9375 :
9376 82919 : PushArgumentsFromEnvironment(argument_count);
9377 : call = NewCallConstantFunction(expr->target(), argument_count,
9378 82919 : syntactic_tail_call_mode, tail_call_mode);
9379 : } else {
9380 247003 : PushArgumentsFromEnvironment(argument_count);
9381 247003 : if (expr->is_uninitialized()) {
9382 : // We've never seen this call before, so let's have Crankshaft learn
9383 : // through the type vector.
9384 : call = NewCallFunctionViaIC(function, argument_count,
9385 : syntactic_tail_call_mode,
9386 : ConvertReceiverMode::kNullOrUndefined,
9387 244174 : tail_call_mode, expr->CallFeedbackICSlot());
9388 : } else {
9389 : call = NewCallFunction(
9390 : function, argument_count, syntactic_tail_call_mode,
9391 2829 : ConvertReceiverMode::kNullOrUndefined, tail_call_mode);
9392 : }
9393 : }
9394 : }
9395 :
9396 : Drop(1); // Drop the function.
9397 990682 : return ast_context()->ReturnInstruction(call, expr->id());
9398 : }
9399 :
9400 658 : bool HOptimizedGraphBuilder::TryInlineArrayCall(Expression* expression,
9401 : int argument_count,
9402 252 : Handle<AllocationSite> site) {
9403 658 : Handle<JSFunction> caller = current_info()->closure();
9404 658 : Handle<JSFunction> target = array_function();
9405 :
9406 658 : if (!site->CanInlineCall()) {
9407 123 : TraceInline(target, caller, "AllocationSite requested no inlining.");
9408 123 : return false;
9409 : }
9410 :
9411 535 : if (argument_count > 1) {
9412 48 : TraceInline(target, caller, "Too many arguments to inline.");
9413 48 : return false;
9414 : }
9415 :
9416 : int array_length = 0;
9417 : // Do not inline if the constant length argument is not a smi or outside the
9418 : // valid range for unrolled loop initialization.
9419 487 : if (argument_count == 1) {
9420 : HValue* argument = Top();
9421 389 : if (!argument->IsConstant()) {
9422 : TraceInline(target, caller,
9423 141 : "Dont inline [new] Array(n) where n isn't constant.");
9424 141 : return false;
9425 : }
9426 :
9427 496 : HConstant* constant_argument = HConstant::cast(argument);
9428 248 : if (!constant_argument->HasSmiValue()) {
9429 : TraceInline(target, caller,
9430 0 : "Constant length outside of valid inlining range.");
9431 0 : return false;
9432 : }
9433 : array_length = constant_argument->Integer32Value();
9434 248 : if (array_length < 0 || array_length > kElementLoopUnrollThreshold) {
9435 : TraceInline(target, caller,
9436 94 : "Constant length outside of valid inlining range.");
9437 94 : return false;
9438 : }
9439 : }
9440 :
9441 252 : TraceInline(target, caller, NULL);
9442 :
9443 1133 : NoObservableSideEffectsScope no_effects(this);
9444 :
9445 : // Register on the site for deoptimization if the transition feedback changes.
9446 252 : top_info()->dependencies()->AssumeTransitionStable(site);
9447 :
9448 : // Build the array.
9449 : ElementsKind kind = site->GetElementsKind();
9450 : HValue* capacity;
9451 : HValue* length;
9452 252 : if (array_length == 0) {
9453 : STATIC_ASSERT(0 < JSArray::kPreallocatedArrayElements);
9454 : const int initial_capacity = JSArray::kPreallocatedArrayElements;
9455 125 : capacity = Add<HConstant>(initial_capacity);
9456 : length = graph()->GetConstant0();
9457 : } else {
9458 : length = Top();
9459 : capacity = length;
9460 : kind = GetHoleyElementsKind(kind);
9461 : }
9462 :
9463 : // These HForceRepresentations are because we store these as fields in the
9464 : // objects we construct, and an int32-to-smi HChange could deopt. Accept
9465 : // the deopt possibility now, before allocation occurs.
9466 252 : length = AddUncasted<HForceRepresentation>(length, Representation::Smi());
9467 252 : capacity = AddUncasted<HForceRepresentation>(capacity, Representation::Smi());
9468 :
9469 : // Generate size calculation code here in order to make it dominate
9470 : // the JSArray allocation.
9471 252 : HValue* elements_size = BuildCalculateElementsSize(kind, capacity);
9472 :
9473 : // Bail out for large objects.
9474 252 : HValue* max_size = Add<HConstant>(kMaxRegularHeapObjectSize);
9475 252 : Add<HBoundsCheck>(elements_size, max_size);
9476 :
9477 : // Allocate (dealing with failure appropriately).
9478 : AllocationSiteMode mode = DONT_TRACK_ALLOCATION_SITE;
9479 252 : HAllocate* new_object = AllocateJSArrayObject(mode);
9480 :
9481 : // Fill in the fields: map, properties, length.
9482 252 : Handle<Map> map_constant(isolate()->get_initial_js_array_map(kind));
9483 252 : HValue* map = Add<HConstant>(map_constant);
9484 :
9485 : BuildJSArrayHeader(new_object, map,
9486 : nullptr, // set elements to empty fixed array
9487 252 : mode, kind, nullptr, length);
9488 :
9489 : // Allocate and initialize the elements.
9490 252 : HAllocate* elements = BuildAllocateElements(kind, elements_size);
9491 252 : BuildInitializeElementsHeader(elements, kind, capacity);
9492 252 : BuildFillElementsWithHole(elements, kind, graph()->GetConstant0(), capacity);
9493 :
9494 : // Set the elements.
9495 : Add<HStoreNamedField>(new_object, HObjectAccess::ForElementsPointer(),
9496 252 : elements);
9497 :
9498 252 : int args_to_drop = argument_count + (expression->IsCall() ? 2 : 1);
9499 : Drop(args_to_drop);
9500 252 : ast_context()->ReturnValue(new_object);
9501 : return true;
9502 : }
9503 :
9504 :
9505 : // Checks whether allocation using the given constructor can be inlined.
9506 15389 : static bool IsAllocationInlineable(Handle<JSFunction> constructor) {
9507 29316 : return constructor->has_initial_map() &&
9508 13892 : !IsDerivedConstructor(constructor->shared()->kind()) &&
9509 13455 : !constructor->initial_map()->is_dictionary_map() &&
9510 19993 : constructor->initial_map()->instance_type() == JS_OBJECT_TYPE &&
9511 : constructor->initial_map()->instance_size() <
9512 15389 : HAllocate::kMaxInlineSize;
9513 : }
9514 :
9515 256012 : void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
9516 : DCHECK(!HasStackOverflow());
9517 : DCHECK(current_block() != NULL);
9518 : DCHECK(current_block()->HasPredecessor());
9519 188708 : if (!is_tracking_positions()) SetSourcePosition(expr->position());
9520 32207 : int argument_count = expr->arguments()->length() + 1; // Plus constructor.
9521 : Factory* factory = isolate()->factory();
9522 :
9523 : // The constructor function is on the stack in the unoptimized code
9524 : // during evaluation of the arguments.
9525 96621 : CHECK_ALIVE(VisitForValue(expr->expression()));
9526 : HValue* function = Top();
9527 96621 : CHECK_ALIVE(VisitExpressions(expr->arguments()));
9528 :
9529 96621 : if (function->IsConstant() &&
9530 56937 : HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
9531 12353 : Handle<Object> constant = HConstant::cast(function)->handle(isolate());
9532 : expr->SetKnownGlobalTarget(Handle<JSFunction>::cast(constant));
9533 : }
9534 :
9535 64414 : if (FLAG_inline_construct &&
9536 47596 : expr->IsMonomorphic() &&
9537 15389 : IsAllocationInlineable(expr->target())) {
9538 : Handle<JSFunction> constructor = expr->target();
9539 : DCHECK(
9540 : constructor->shared()->construct_stub() ==
9541 : isolate()->builtins()->builtin(Builtins::kJSConstructStubGeneric) ||
9542 : constructor->shared()->construct_stub() ==
9543 : isolate()->builtins()->builtin(Builtins::kJSConstructStubApi) ||
9544 : constructor->shared()->construct_stub() ==
9545 : isolate()->builtins()->builtin(
9546 : Builtins::kJSBuiltinsConstructStubForBase));
9547 4599 : HValue* check = Add<HCheckValue>(function, constructor);
9548 :
9549 : // Force completion of inobject slack tracking before generating
9550 : // allocation code to finalize instance size.
9551 4599 : constructor->CompleteInobjectSlackTrackingIfActive();
9552 :
9553 : // Calculate instance size from initial map of constructor.
9554 : DCHECK(constructor->has_initial_map());
9555 : Handle<Map> initial_map(constructor->initial_map());
9556 : int instance_size = initial_map->instance_size();
9557 :
9558 : // Allocate an instance of the implicit receiver object.
9559 4599 : HValue* size_in_bytes = Add<HConstant>(instance_size);
9560 : HAllocationMode allocation_mode;
9561 : HAllocate* receiver = BuildAllocate(
9562 4599 : size_in_bytes, HType::JSObject(), JS_OBJECT_TYPE, allocation_mode);
9563 : receiver->set_known_initial_map(initial_map);
9564 :
9565 : // Initialize map and fields of the newly allocated object.
9566 : { NoObservableSideEffectsScope no_effects(this);
9567 : DCHECK(initial_map->instance_type() == JS_OBJECT_TYPE);
9568 : Add<HStoreNamedField>(receiver,
9569 : HObjectAccess::ForMapAndOffset(initial_map, JSObject::kMapOffset),
9570 4599 : Add<HConstant>(initial_map));
9571 4599 : HValue* empty_fixed_array = Add<HConstant>(factory->empty_fixed_array());
9572 : Add<HStoreNamedField>(receiver,
9573 : HObjectAccess::ForMapAndOffset(initial_map,
9574 : JSObject::kPropertiesOffset),
9575 4599 : empty_fixed_array);
9576 : Add<HStoreNamedField>(receiver,
9577 : HObjectAccess::ForMapAndOffset(initial_map,
9578 : JSObject::kElementsOffset),
9579 4599 : empty_fixed_array);
9580 4599 : BuildInitializeInobjectProperties(receiver, initial_map);
9581 : }
9582 :
9583 : // Replace the constructor function with a newly allocated receiver using
9584 : // the index of the receiver from the top of the expression stack.
9585 : const int receiver_index = argument_count - 1;
9586 : DCHECK(environment()->ExpressionStackAt(receiver_index) == function);
9587 : environment()->SetExpressionStackAt(receiver_index, receiver);
9588 :
9589 4599 : if (TryInlineConstruct(expr, receiver)) {
9590 : // Inlining worked, add a dependency on the initial map to make sure that
9591 : // this code is deoptimized whenever the initial map of the constructor
9592 : // changes.
9593 1095 : top_info()->dependencies()->AssumeInitialMapCantChange(initial_map);
9594 1095 : return;
9595 : }
9596 :
9597 : // TODO(mstarzinger): For now we remove the previous HAllocate and all
9598 : // corresponding instructions and instead add HPushArguments for the
9599 : // arguments in case inlining failed. What we actually should do is for
9600 : // inlining to try to build a subgraph without mutating the parent graph.
9601 3504 : HInstruction* instr = current_block()->last();
9602 37388 : do {
9603 : HInstruction* prev_instr = instr->previous();
9604 37388 : instr->DeleteAndReplaceWith(NULL);
9605 : instr = prev_instr;
9606 : } while (instr != check);
9607 : environment()->SetExpressionStackAt(receiver_index, function);
9608 : } else {
9609 : // The constructor function is both an operand to the instruction and an
9610 : // argument to the construct call.
9611 27608 : if (TryHandleArrayCall(expr, function)) return;
9612 : }
9613 :
9614 30563 : HValue* arity = Add<HConstant>(argument_count - 1);
9615 30563 : HValue* op_vals[] = {function, function, arity};
9616 30563 : Callable callable = CodeFactory::Construct(isolate());
9617 30563 : HConstant* stub = Add<HConstant>(callable.code());
9618 30563 : PushArgumentsFromEnvironment(argument_count);
9619 : HInstruction* construct = New<HCallWithDescriptor>(
9620 30563 : stub, argument_count, callable.descriptor(), ArrayVector(op_vals));
9621 61126 : return ast_context()->ReturnInstruction(construct, expr->id());
9622 : }
9623 :
9624 :
9625 11944 : void HOptimizedGraphBuilder::BuildInitializeInobjectProperties(
9626 : HValue* receiver, Handle<Map> initial_map) {
9627 11944 : if (initial_map->GetInObjectProperties() != 0) {
9628 8096 : HConstant* undefined = graph()->GetConstantUndefined();
9629 68356 : for (int i = 0; i < initial_map->GetInObjectProperties(); i++) {
9630 26082 : int property_offset = initial_map->GetInObjectPropertyOffset(i);
9631 : Add<HStoreNamedField>(receiver, HObjectAccess::ForMapAndOffset(
9632 : initial_map, property_offset),
9633 26082 : undefined);
9634 : }
9635 : }
9636 11944 : }
9637 :
9638 32 : void HOptimizedGraphBuilder::GenerateMaxSmi(CallRuntime* expr) {
9639 : DCHECK(expr->arguments()->length() == 0);
9640 16 : HConstant* max_smi = New<HConstant>(static_cast<int32_t>(Smi::kMaxValue));
9641 32 : return ast_context()->ReturnInstruction(max_smi, expr->id());
9642 : }
9643 :
9644 :
9645 0 : void HOptimizedGraphBuilder::GenerateTypedArrayMaxSizeInHeap(
9646 0 : CallRuntime* expr) {
9647 : DCHECK(expr->arguments()->length() == 0);
9648 : HConstant* result = New<HConstant>(static_cast<int32_t>(
9649 0 : FLAG_typed_array_max_size_in_heap));
9650 0 : return ast_context()->ReturnInstruction(result, expr->id());
9651 : }
9652 :
9653 :
9654 0 : void HOptimizedGraphBuilder::GenerateArrayBufferGetByteLength(
9655 0 : CallRuntime* expr) {
9656 : DCHECK(expr->arguments()->length() == 1);
9657 0 : CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
9658 : HValue* buffer = Pop();
9659 : HInstruction* result = New<HLoadNamedField>(
9660 0 : buffer, nullptr, HObjectAccess::ForJSArrayBufferByteLength());
9661 0 : return ast_context()->ReturnInstruction(result, expr->id());
9662 : }
9663 :
9664 :
9665 9 : void HOptimizedGraphBuilder::GenerateArrayBufferViewGetByteLength(
9666 27 : CallRuntime* expr) {
9667 18 : NoObservableSideEffectsScope scope(this);
9668 : DCHECK(expr->arguments()->length() == 1);
9669 27 : CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
9670 : HValue* view = Pop();
9671 :
9672 : return ast_context()->ReturnValue(BuildArrayBufferViewFieldAccessor(
9673 : view, nullptr,
9674 9 : FieldIndex::ForInObjectOffset(JSArrayBufferView::kByteLengthOffset)));
9675 : }
9676 :
9677 :
9678 36 : void HOptimizedGraphBuilder::GenerateArrayBufferViewGetByteOffset(
9679 108 : CallRuntime* expr) {
9680 72 : NoObservableSideEffectsScope scope(this);
9681 : DCHECK(expr->arguments()->length() == 1);
9682 108 : CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
9683 : HValue* view = Pop();
9684 :
9685 : return ast_context()->ReturnValue(BuildArrayBufferViewFieldAccessor(
9686 : view, nullptr,
9687 36 : FieldIndex::ForInObjectOffset(JSArrayBufferView::kByteOffsetOffset)));
9688 : }
9689 :
9690 43 : void HOptimizedGraphBuilder::GenerateArrayBufferViewWasNeutered(
9691 129 : CallRuntime* expr) {
9692 86 : NoObservableSideEffectsScope scope(this);
9693 : DCHECK_EQ(expr->arguments()->length(), 1);
9694 129 : CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
9695 : HValue* view = Pop();
9696 :
9697 : HInstruction* buffer = Add<HLoadNamedField>(
9698 43 : view, nullptr, HObjectAccess::ForJSArrayBufferViewBuffer());
9699 : HInstruction* flags = Add<HLoadNamedField>(
9700 43 : buffer, nullptr, HObjectAccess::ForJSArrayBufferBitField());
9701 : HValue* was_neutered_mask =
9702 43 : Add<HConstant>(1 << JSArrayBuffer::WasNeutered::kShift);
9703 : HValue* was_neutered =
9704 43 : AddUncasted<HBitwise>(Token::BIT_AND, flags, was_neutered_mask);
9705 43 : return ast_context()->ReturnValue(was_neutered);
9706 : }
9707 :
9708 101 : void HOptimizedGraphBuilder::GenerateTypedArrayGetLength(
9709 303 : CallRuntime* expr) {
9710 202 : NoObservableSideEffectsScope scope(this);
9711 : DCHECK(expr->arguments()->length() == 1);
9712 303 : CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
9713 : HValue* view = Pop();
9714 :
9715 : return ast_context()->ReturnValue(BuildArrayBufferViewFieldAccessor(
9716 : view, nullptr,
9717 101 : FieldIndex::ForInObjectOffset(JSTypedArray::kLengthOffset)));
9718 : }
9719 :
9720 :
9721 212921 : void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
9722 : DCHECK(!HasStackOverflow());
9723 : DCHECK(current_block() != NULL);
9724 : DCHECK(current_block()->HasPredecessor());
9725 72672 : if (expr->is_jsruntime()) {
9726 : // Crankshaft always specializes to the native context, so we can just grab
9727 : // the constant function from the current native context and embed that into
9728 : // the code object.
9729 : Handle<JSFunction> known_function(
9730 : JSFunction::cast(
9731 4245 : current_info()->native_context()->get(expr->context_index())),
9732 49551 : isolate());
9733 :
9734 : // The callee and the receiver both have to be pushed onto the operand stack
9735 : // before arguments are being evaluated.
9736 4245 : HConstant* function = Add<HConstant>(known_function);
9737 4245 : HValue* receiver = ImplicitReceiverFor(function, known_function);
9738 4245 : Push(function);
9739 4245 : Push(receiver);
9740 :
9741 4245 : int argument_count = expr->arguments()->length() + 1; // Count receiver.
9742 12735 : CHECK_ALIVE(VisitExpressions(expr->arguments()));
9743 4245 : PushArgumentsFromEnvironment(argument_count);
9744 : HInstruction* call = NewCallConstantFunction(known_function, argument_count,
9745 : TailCallMode::kDisallow,
9746 4245 : TailCallMode::kDisallow);
9747 : Drop(1); // Function
9748 8490 : return ast_context()->ReturnInstruction(call, expr->id());
9749 : }
9750 :
9751 : const Runtime::Function* function = expr->function();
9752 : DCHECK(function != NULL);
9753 68427 : switch (function->function_id) {
9754 : #define CALL_INTRINSIC_GENERATOR(Name) \
9755 : case Runtime::kInline##Name: \
9756 : return Generate##Name(expr);
9757 :
9758 1622 : FOR_EACH_HYDROGEN_INTRINSIC(CALL_INTRINSIC_GENERATOR)
9759 : #undef CALL_INTRINSIC_GENERATOR
9760 : default: {
9761 41104 : int argument_count = expr->arguments()->length();
9762 123269 : CHECK_ALIVE(VisitExpressions(expr->arguments()));
9763 41061 : PushArgumentsFromEnvironment(argument_count);
9764 41061 : HCallRuntime* call = New<HCallRuntime>(function, argument_count);
9765 82122 : return ast_context()->ReturnInstruction(call, expr->id());
9766 : }
9767 : }
9768 : }
9769 :
9770 :
9771 260304 : void HOptimizedGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
9772 : DCHECK(!HasStackOverflow());
9773 : DCHECK(current_block() != NULL);
9774 : DCHECK(current_block()->HasPredecessor());
9775 260304 : switch (expr->op()) {
9776 1275 : case Token::DELETE: return VisitDelete(expr);
9777 4164 : case Token::VOID: return VisitVoid(expr);
9778 40360 : case Token::TYPEOF: return VisitTypeof(expr);
9779 214505 : case Token::NOT: return VisitNot(expr);
9780 0 : default: UNREACHABLE();
9781 : }
9782 : }
9783 :
9784 :
9785 6218 : void HOptimizedGraphBuilder::VisitDelete(UnaryOperation* expr) {
9786 3633 : Property* prop = expr->expression()->AsProperty();
9787 1314 : VariableProxy* proxy = expr->expression()->AsVariableProxy();
9788 1275 : if (prop != NULL) {
9789 3653 : CHECK_ALIVE(VisitForValue(prop->obj()));
9790 3495 : CHECK_ALIVE(VisitForValue(prop->key()));
9791 : HValue* key = Pop();
9792 : HValue* obj = Pop();
9793 : HValue* language_mode = Add<HConstant>(
9794 1165 : static_cast<int32_t>(function_language_mode()), Representation::Smi());
9795 1165 : Add<HPushArguments>(obj, key, language_mode);
9796 : HInstruction* instr =
9797 1165 : New<HCallRuntime>(Runtime::FunctionForId(Runtime::kDeleteProperty), 3);
9798 2330 : return ast_context()->ReturnInstruction(instr, expr->id());
9799 82 : } else if (proxy != NULL) {
9800 : Variable* var = proxy->var();
9801 39 : if (var->IsUnallocated()) {
9802 : Bailout(kDeleteWithGlobalVariable);
9803 16 : } else if (var->IsStackAllocated() || var->IsContextSlot()) {
9804 : // Result of deleting non-global variables is false. 'this' is not really
9805 : // a variable, though we implement it as one. The subexpression does not
9806 : // have side effects.
9807 : HValue* value = var->is_this() ? graph()->GetConstantTrue()
9808 32 : : graph()->GetConstantFalse();
9809 16 : return ast_context()->ReturnValue(value);
9810 : } else {
9811 : Bailout(kDeleteWithNonGlobalVariable);
9812 : }
9813 : } else {
9814 : // Result of deleting non-property, non-variable reference is true.
9815 : // Evaluate the subexpression for side effects.
9816 129 : CHECK_ALIVE(VisitForEffect(expr->expression()));
9817 86 : return ast_context()->ReturnValue(graph()->GetConstantTrue());
9818 : }
9819 : }
9820 :
9821 :
9822 12492 : void HOptimizedGraphBuilder::VisitVoid(UnaryOperation* expr) {
9823 12492 : CHECK_ALIVE(VisitForEffect(expr->expression()));
9824 8328 : return ast_context()->ReturnValue(graph()->GetConstantUndefined());
9825 : }
9826 :
9827 :
9828 121079 : void HOptimizedGraphBuilder::VisitTypeof(UnaryOperation* expr) {
9829 80720 : CHECK_ALIVE(VisitForTypeOf(expr->expression()));
9830 : HValue* value = Pop();
9831 40359 : HInstruction* instr = New<HTypeof>(value);
9832 80718 : return ast_context()->ReturnInstruction(instr, expr->id());
9833 : }
9834 :
9835 :
9836 439984 : void HOptimizedGraphBuilder::VisitNot(UnaryOperation* expr) {
9837 214505 : if (ast_context()->IsTest()) {
9838 208993 : TestContext* context = TestContext::cast(ast_context());
9839 : VisitForControl(expr->expression(),
9840 : context->if_false(),
9841 208993 : context->if_true());
9842 208993 : return;
9843 : }
9844 :
9845 5512 : if (ast_context()->IsEffect()) {
9846 24 : VisitForEffect(expr->expression());
9847 24 : return;
9848 : }
9849 :
9850 : DCHECK(ast_context()->IsValue());
9851 16460 : HBasicBlock* materialize_false = graph()->CreateBasicBlock();
9852 5488 : HBasicBlock* materialize_true = graph()->CreateBasicBlock();
9853 10976 : CHECK_BAILOUT(VisitForControl(expr->expression(),
9854 : materialize_false,
9855 : materialize_true));
9856 :
9857 5486 : if (materialize_false->HasPredecessor()) {
9858 : materialize_false->SetJoinId(expr->MaterializeFalseId());
9859 : set_current_block(materialize_false);
9860 5486 : Push(graph()->GetConstantFalse());
9861 : } else {
9862 : materialize_false = NULL;
9863 : }
9864 :
9865 5486 : if (materialize_true->HasPredecessor()) {
9866 : materialize_true->SetJoinId(expr->MaterializeTrueId());
9867 : set_current_block(materialize_true);
9868 5486 : Push(graph()->GetConstantTrue());
9869 : } else {
9870 : materialize_true = NULL;
9871 : }
9872 :
9873 : HBasicBlock* join =
9874 5486 : CreateJoin(materialize_false, materialize_true, expr->id());
9875 : set_current_block(join);
9876 16458 : if (join != NULL) return ast_context()->ReturnValue(Pop());
9877 : }
9878 :
9879 2533450 : static Representation RepresentationFor(AstType* type) {
9880 : DisallowHeapAllocation no_allocation;
9881 2533450 : if (type->Is(AstType::None())) return Representation::None();
9882 2418409 : if (type->Is(AstType::SignedSmall())) return Representation::Smi();
9883 1469742 : if (type->Is(AstType::Signed32())) return Representation::Integer32();
9884 1469742 : if (type->Is(AstType::Number())) return Representation::Double();
9885 : return Representation::Tagged();
9886 : }
9887 :
9888 88334 : HInstruction* HOptimizedGraphBuilder::BuildIncrement(CountOperation* expr) {
9889 : // The input to the count operation is on top of the expression stack.
9890 44167 : Representation rep = RepresentationFor(expr->type());
9891 44167 : if (rep.IsNone() || rep.IsTagged()) {
9892 : rep = Representation::Smi();
9893 : }
9894 :
9895 : // We need an explicit HValue representing ToNumber(input). The
9896 : // actual HChange instruction we need is (sometimes) added in a later
9897 : // phase, so it is not available now to be used as an input to HAdd and
9898 : // as the return value.
9899 88334 : HInstruction* number_input = AddUncasted<HForceRepresentation>(Pop(), rep);
9900 44167 : if (!rep.IsDouble()) {
9901 : number_input->SetFlag(HInstruction::kFlexibleRepresentation);
9902 : number_input->SetFlag(HInstruction::kCannotBeTagged);
9903 : }
9904 44167 : Push(number_input);
9905 :
9906 : // The addition has no side effects, so we do not need
9907 : // to simulate the expression stack after this instruction.
9908 : // Any later failures deopt to the load of the input or earlier.
9909 : HConstant* delta = (expr->op() == Token::INC)
9910 : ? graph()->GetConstant1()
9911 44167 : : graph()->GetConstantMinus1();
9912 44167 : HInstruction* instr = AddUncasted<HAdd>(Top(), delta);
9913 88334 : if (instr->IsAdd()) {
9914 : HAdd* add = HAdd::cast(instr);
9915 : add->set_observed_input_representation(1, rep);
9916 : add->set_observed_input_representation(2, Representation::Smi());
9917 : }
9918 : instr->ClearAllSideEffects();
9919 : instr->SetFlag(HInstruction::kCannotBeTagged);
9920 44167 : return instr;
9921 : }
9922 :
9923 910 : void HOptimizedGraphBuilder::BuildStoreForEffect(
9924 : Expression* expr, Property* prop, FeedbackSlot slot, BailoutId ast_id,
9925 : BailoutId return_id, HValue* object, HValue* key, HValue* value) {
9926 : EffectContext for_effect(this);
9927 910 : Push(object);
9928 910 : if (key != NULL) Push(key);
9929 910 : Push(value);
9930 910 : BuildStore(expr, prop, slot, ast_id, return_id);
9931 910 : }
9932 :
9933 :
9934 218949 : void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
9935 : DCHECK(!HasStackOverflow());
9936 : DCHECK(current_block() != NULL);
9937 : DCHECK(current_block()->HasPredecessor());
9938 93286 : if (!is_tracking_positions()) SetSourcePosition(expr->position());
9939 : Expression* target = expr->expression();
9940 89311 : VariableProxy* proxy = target->AsVariableProxy();
9941 4797 : Property* prop = target->AsProperty();
9942 45455 : if (proxy == NULL && prop == NULL) {
9943 : return Bailout(kInvalidLhsInCountOperation);
9944 : }
9945 :
9946 : // Match the full code generator stack by simulating an extra stack
9947 : // element for postfix operations in a non-effect context. The return
9948 : // value is ToNumber(input).
9949 : bool returns_original_input =
9950 83045 : expr->is_postfix() && !ast_context()->IsEffect();
9951 : HValue* input = NULL; // ToNumber(original_input).
9952 : HValue* after = NULL; // The result after incrementing or decrementing.
9953 :
9954 45455 : if (proxy != NULL) {
9955 88374 : Variable* var = proxy->var();
9956 43856 : if (var->mode() == CONST) {
9957 : return Bailout(kNonInitializerAssignmentToConst);
9958 : }
9959 : // Argument of the count operation is a variable, not a property.
9960 : DCHECK(prop == NULL);
9961 127806 : CHECK_ALIVE(VisitForValue(target));
9962 :
9963 42570 : after = BuildIncrement(expr);
9964 42570 : input = returns_original_input ? Top() : Pop();
9965 42570 : Push(after);
9966 :
9967 42570 : switch (var->location()) {
9968 : case VariableLocation::UNALLOCATED:
9969 : HandleGlobalVariableAssignment(var, after, expr->CountSlot(),
9970 3790 : expr->AssignmentId());
9971 3790 : break;
9972 :
9973 : case VariableLocation::PARAMETER:
9974 : case VariableLocation::LOCAL:
9975 37806 : BindIfLive(var, after);
9976 37806 : break;
9977 :
9978 : case VariableLocation::CONTEXT: {
9979 974 : HValue* context = BuildContextChainWalk(var);
9980 : HStoreContextSlot::Mode mode = IsLexicalVariableMode(var->mode())
9981 974 : ? HStoreContextSlot::kCheckDeoptimize : HStoreContextSlot::kNoCheck;
9982 : HStoreContextSlot* instr = Add<HStoreContextSlot>(context, var->index(),
9983 974 : mode, after);
9984 974 : if (instr->HasObservableSideEffects()) {
9985 974 : Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
9986 : }
9987 : break;
9988 : }
9989 :
9990 : case VariableLocation::LOOKUP:
9991 : return Bailout(kLookupVariableInCountOperation);
9992 :
9993 : case VariableLocation::MODULE:
9994 0 : UNREACHABLE();
9995 : }
9996 :
9997 42570 : Drop(returns_original_input ? 2 : 1);
9998 85140 : return ast_context()->ReturnValue(expr->is_postfix() ? input : after);
9999 : }
10000 :
10001 : // Argument of the count operation is a property.
10002 : DCHECK(prop != NULL);
10003 2511 : if (returns_original_input) Push(graph()->GetConstantUndefined());
10004 :
10005 4797 : CHECK_ALIVE(VisitForValue(prop->obj()));
10006 : HValue* object = Top();
10007 :
10008 : HValue* key = NULL;
10009 2953 : if (!prop->key()->IsPropertyName() || prop->IsStringAccess()) {
10010 733 : CHECK_ALIVE(VisitForValue(prop->key()));
10011 : key = Top();
10012 : }
10013 :
10014 4791 : CHECK_ALIVE(PushLoad(prop, object, key));
10015 :
10016 1597 : after = BuildIncrement(expr);
10017 :
10018 1597 : if (returns_original_input) {
10019 : input = Pop();
10020 : // Drop object and key to push it again in the effect context below.
10021 910 : Drop(key == NULL ? 1 : 2);
10022 : environment()->SetExpressionStackAt(0, input);
10023 2730 : CHECK_ALIVE(BuildStoreForEffect(expr, prop, expr->CountSlot(), expr->id(),
10024 : expr->AssignmentId(), object, key, after));
10025 1820 : return ast_context()->ReturnValue(Pop());
10026 : }
10027 :
10028 : environment()->SetExpressionStackAt(0, after);
10029 : return BuildStore(expr, prop, expr->CountSlot(), expr->id(),
10030 687 : expr->AssignmentId());
10031 : }
10032 :
10033 :
10034 552 : HInstruction* HOptimizedGraphBuilder::BuildStringCharCodeAt(
10035 : HValue* string,
10036 : HValue* index) {
10037 774 : if (string->IsConstant() && index->IsConstant()) {
10038 : HConstant* c_string = HConstant::cast(string);
10039 175 : HConstant* c_index = HConstant::cast(index);
10040 386 : if (c_string->HasStringValue() && c_index->HasNumberValue()) {
10041 : int32_t i = c_index->NumberValueAsInteger32();
10042 : Handle<String> s = c_string->StringValue();
10043 339 : if (i < 0 || i >= s->length()) {
10044 44 : return New<HConstant>(std::numeric_limits<double>::quiet_NaN());
10045 : }
10046 131 : return New<HConstant>(s->Get(i));
10047 : }
10048 : }
10049 377 : string = BuildCheckString(string);
10050 377 : index = Add<HBoundsCheck>(index, AddLoadStringLength(string));
10051 377 : return New<HStringCharCodeAt>(string, index);
10052 : }
10053 :
10054 :
10055 : // Checks if the given shift amounts have following forms:
10056 : // (N1) and (N2) with N1 + N2 = 32; (sa) and (32 - sa).
10057 530 : static bool ShiftAmountsAllowReplaceByRotate(HValue* sa,
10058 : HValue* const32_minus_sa) {
10059 958 : if (sa->IsConstant() && const32_minus_sa->IsConstant()) {
10060 96 : const HConstant* c1 = HConstant::cast(sa);
10061 96 : const HConstant* c2 = HConstant::cast(const32_minus_sa);
10062 144 : return c1->HasInteger32Value() && c2->HasInteger32Value() &&
10063 96 : (c1->Integer32Value() + c2->Integer32Value() == 32);
10064 : }
10065 482 : if (!const32_minus_sa->IsSub()) return false;
10066 : HSub* sub = HSub::cast(const32_minus_sa);
10067 910 : return sub->left()->EqualsInteger32Constant(32) && sub->right() == sa;
10068 : }
10069 :
10070 :
10071 : // Checks if the left and the right are shift instructions with the oposite
10072 : // directions that can be replaced by one rotate right instruction or not.
10073 : // Returns the operand and the shift amount for the rotate instruction in the
10074 : // former case.
10075 18214 : bool HGraphBuilder::MatchRotateRight(HValue* left,
10076 : HValue* right,
10077 : HValue** operand,
10078 : HValue** shift_amount) {
10079 : HShl* shl;
10080 : HShr* shr;
10081 20465 : if (left->IsShl() && right->IsShr()) {
10082 : shl = HShl::cast(left);
10083 : shr = HShr::cast(right);
10084 17938 : } else if (left->IsShr() && right->IsShl()) {
10085 : shl = HShl::cast(right);
10086 : shr = HShr::cast(left);
10087 : } else {
10088 : return false;
10089 : }
10090 521 : if (shl->left() != shr->left()) return false;
10091 :
10092 530 : if (!ShiftAmountsAllowReplaceByRotate(shl->right(), shr->right()) &&
10093 24 : !ShiftAmountsAllowReplaceByRotate(shr->right(), shl->right())) {
10094 : return false;
10095 : }
10096 500 : *operand = shr->left();
10097 500 : *shift_amount = shr->right();
10098 500 : return true;
10099 : }
10100 :
10101 :
10102 8278 : bool CanBeZero(HValue* right) {
10103 8278 : if (right->IsConstant()) {
10104 12608 : HConstant* right_const = HConstant::cast(right);
10105 12608 : if (right_const->HasInteger32Value() &&
10106 6129 : (right_const->Integer32Value() & 0x1f) != 0) {
10107 : return false;
10108 : }
10109 : }
10110 3397 : return true;
10111 : }
10112 :
10113 16819 : HValue* HGraphBuilder::EnforceNumberType(HValue* number, AstType* expected) {
10114 16819 : if (expected->Is(AstType::SignedSmall())) {
10115 11753 : return AddUncasted<HForceRepresentation>(number, Representation::Smi());
10116 : }
10117 5066 : if (expected->Is(AstType::Signed32())) {
10118 : return AddUncasted<HForceRepresentation>(number,
10119 0 : Representation::Integer32());
10120 : }
10121 : return number;
10122 : }
10123 :
10124 2538640 : HValue* HGraphBuilder::TruncateToNumber(HValue* value, AstType** expected) {
10125 661502 : if (value->IsConstant()) {
10126 : HConstant* constant = HConstant::cast(value);
10127 : Maybe<HConstant*> number =
10128 265471 : constant->CopyToTruncatedNumber(isolate(), zone());
10129 265471 : if (number.IsJust()) {
10130 7179 : *expected = AstType::Number();
10131 7179 : return AddInstruction(number.FromJust());
10132 : }
10133 : }
10134 :
10135 : // We put temporary values on the stack, which don't correspond to anything
10136 : // in baseline code. Since nothing is observable we avoid recording those
10137 : // pushes with a NoObservableSideEffectsScope.
10138 : NoObservableSideEffectsScope no_effects(this);
10139 :
10140 654323 : AstType* expected_type = *expected;
10141 :
10142 : // Separate the number type from the rest.
10143 : AstType* expected_obj =
10144 654323 : AstType::Intersect(expected_type, AstType::NonNumber(), zone());
10145 : AstType* expected_number =
10146 654323 : AstType::Intersect(expected_type, AstType::Number(), zone());
10147 :
10148 : // We expect to get a number.
10149 : // (We need to check first, since AstType::None->Is(AstType::Any()) == true.
10150 654323 : if (expected_obj->Is(AstType::None())) {
10151 : DCHECK(!expected_number->Is(AstType::None()));
10152 : return value;
10153 : }
10154 :
10155 654323 : if (expected_obj->Is(AstType::Undefined())) {
10156 : // This is already done by HChange.
10157 37550 : *expected = AstType::Union(expected_number, AstType::Number(), zone());
10158 37550 : return value;
10159 : }
10160 :
10161 : return value;
10162 : }
10163 :
10164 :
10165 381164 : HValue* HOptimizedGraphBuilder::BuildBinaryOperation(
10166 1143492 : BinaryOperation* expr,
10167 : HValue* left,
10168 : HValue* right,
10169 : PushBeforeSimulateBehavior push_sim_result) {
10170 381164 : AstType* left_type = bounds_.get(expr->left()).lower;
10171 381164 : AstType* right_type = bounds_.get(expr->right()).lower;
10172 381164 : AstType* result_type = bounds_.get(expr).lower;
10173 381164 : Maybe<int> fixed_right_arg = expr->fixed_right_arg();
10174 : Handle<AllocationSite> allocation_site = expr->allocation_site();
10175 :
10176 : HAllocationMode allocation_mode;
10177 381164 : if (FLAG_allocation_site_pretenuring && !allocation_site.is_null()) {
10178 21913 : allocation_mode = HAllocationMode(allocation_site);
10179 : }
10180 : HValue* result = HGraphBuilder::BuildBinaryOperation(
10181 : expr->op(), left, right, left_type, right_type, result_type,
10182 381164 : fixed_right_arg, allocation_mode, expr->id());
10183 : // Add a simulate after instructions with observable side effects, and
10184 : // after phis, which are the result of BuildBinaryOperation when we
10185 : // inlined some complex subgraph.
10186 421664 : if (result->HasObservableSideEffects() || result->IsPhi()) {
10187 352630 : if (push_sim_result == PUSH_BEFORE_SIMULATE) {
10188 352324 : Push(result);
10189 352324 : Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
10190 : Drop(1);
10191 : } else {
10192 306 : Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
10193 : }
10194 : }
10195 381164 : return result;
10196 : }
10197 :
10198 391168 : HValue* HGraphBuilder::BuildBinaryOperation(
10199 : Token::Value op, HValue* left, HValue* right, AstType* left_type,
10200 : AstType* right_type, AstType* result_type, Maybe<int> fixed_right_arg,
10201 1074282 : HAllocationMode allocation_mode, BailoutId opt_id) {
10202 : bool maybe_string_add = false;
10203 391168 : if (op == Token::ADD) {
10204 : // If we are adding constant string with something for which we don't have
10205 : // a feedback yet, assume that it's also going to be a string and don't
10206 : // generate deopt instructions.
10207 238941 : if (!left_type->IsInhabited() && right->IsConstant() &&
10208 : HConstant::cast(right)->HasStringValue()) {
10209 10119 : left_type = AstType::String();
10210 : }
10211 :
10212 223675 : if (!right_type->IsInhabited() && left->IsConstant() &&
10213 : HConstant::cast(left)->HasStringValue()) {
10214 5714 : right_type = AstType::String();
10215 : }
10216 :
10217 358212 : maybe_string_add = (left_type->Maybe(AstType::String()) ||
10218 313650 : left_type->Maybe(AstType::Receiver()) ||
10219 514145 : right_type->Maybe(AstType::String()) ||
10220 155967 : right_type->Maybe(AstType::Receiver()));
10221 : }
10222 :
10223 391168 : Representation left_rep = RepresentationFor(left_type);
10224 391168 : Representation right_rep = RepresentationFor(right_type);
10225 :
10226 391168 : if (!left_type->IsInhabited()) {
10227 : Add<HDeoptimize>(
10228 : DeoptimizeReason::kInsufficientTypeFeedbackForLHSOfBinaryOperation,
10229 31245 : Deoptimizer::SOFT);
10230 31245 : left_type = AstType::Any();
10231 31245 : left_rep = RepresentationFor(left_type);
10232 31245 : maybe_string_add = op == Token::ADD;
10233 : }
10234 :
10235 391168 : if (!right_type->IsInhabited()) {
10236 : Add<HDeoptimize>(
10237 : DeoptimizeReason::kInsufficientTypeFeedbackForRHSOfBinaryOperation,
10238 39262 : Deoptimizer::SOFT);
10239 39262 : right_type = AstType::Any();
10240 39262 : right_rep = RepresentationFor(right_type);
10241 39262 : maybe_string_add = op == Token::ADD;
10242 : }
10243 :
10244 391168 : if (!maybe_string_add) {
10245 330751 : left = TruncateToNumber(left, &left_type);
10246 330751 : right = TruncateToNumber(right, &right_type);
10247 : }
10248 :
10249 : // Special case for string addition here.
10250 983706 : if (op == Token::ADD &&
10251 516890 : (left_type->Is(AstType::String()) || right_type->Is(AstType::String()))) {
10252 : // Validate type feedback for left argument.
10253 88472 : if (left_type->Is(AstType::String())) {
10254 43610 : left = BuildCheckString(left);
10255 : }
10256 :
10257 : // Validate type feedback for right argument.
10258 88472 : if (right_type->Is(AstType::String())) {
10259 38273 : right = BuildCheckString(right);
10260 : }
10261 :
10262 : // Convert left argument as necessary.
10263 88472 : if (left_type->Is(AstType::Number())) {
10264 : DCHECK(right_type->Is(AstType::String()));
10265 422 : left = BuildNumberToString(left, left_type);
10266 87628 : } else if (!left_type->Is(AstType::String())) {
10267 : DCHECK(right_type->Is(AstType::String()));
10268 : return AddUncasted<HStringAdd>(
10269 : left, right, allocation_mode.GetPretenureMode(),
10270 204 : STRING_ADD_CONVERT_LEFT, allocation_mode.feedback_site());
10271 : }
10272 :
10273 : // Convert right argument as necessary.
10274 88064 : if (right_type->Is(AstType::Number())) {
10275 : DCHECK(left_type->Is(AstType::String()));
10276 4793 : right = BuildNumberToString(right, right_type);
10277 78478 : } else if (!right_type->Is(AstType::String())) {
10278 : DCHECK(left_type->Is(AstType::String()));
10279 : return AddUncasted<HStringAdd>(
10280 : left, right, allocation_mode.GetPretenureMode(),
10281 1170 : STRING_ADD_CONVERT_RIGHT, allocation_mode.feedback_site());
10282 : }
10283 :
10284 : // Fast paths for empty constant strings.
10285 : Handle<String> left_string =
10286 10778 : left->IsConstant() && HConstant::cast(left)->HasStringValue()
10287 : ? HConstant::cast(left)->StringValue()
10288 53640 : : Handle<String>();
10289 : Handle<String> right_string =
10290 26941 : right->IsConstant() && HConstant::cast(right)->HasStringValue()
10291 : ? HConstant::cast(right)->StringValue()
10292 69803 : : Handle<String>();
10293 53640 : if (!left_string.is_null() && left_string->length() == 0) return right;
10294 69084 : if (!right_string.is_null() && right_string->length() == 0) return left;
10295 40939 : if (!left_string.is_null() && !right_string.is_null()) {
10296 : return AddUncasted<HStringAdd>(
10297 : left, right, allocation_mode.GetPretenureMode(),
10298 1497 : STRING_ADD_CHECK_NONE, allocation_mode.feedback_site());
10299 : }
10300 :
10301 : // Register the dependent code with the allocation site.
10302 39442 : if (!allocation_mode.feedback_site().is_null()) {
10303 : DCHECK(!graph()->info()->IsStub());
10304 : Handle<AllocationSite> site(allocation_mode.feedback_site());
10305 20340 : top_info()->dependencies()->AssumeTenuringDecision(site);
10306 : }
10307 :
10308 : // Inline the string addition into the stub when creating allocation
10309 : // mementos to gather allocation site feedback, or if we can statically
10310 : // infer that we're going to create a cons string.
10311 82696 : if ((graph()->info()->IsStub() &&
10312 35862 : allocation_mode.CreateAllocationMementos()) ||
10313 8727 : (left->IsConstant() &&
10314 8727 : HConstant::cast(left)->HasStringValue() &&
10315 : HConstant::cast(left)->StringValue()->length() + 1 >=
10316 73339 : ConsString::kMinLength) ||
10317 23908 : (right->IsConstant() &&
10318 23908 : HConstant::cast(right)->HasStringValue() &&
10319 : HConstant::cast(right)->StringValue()->length() + 1 >=
10320 : ConsString::kMinLength)) {
10321 15446 : return BuildStringAdd(left, right, allocation_mode);
10322 : }
10323 :
10324 : // Fallback to using the string add stub.
10325 : return AddUncasted<HStringAdd>(
10326 : left, right, allocation_mode.GetPretenureMode(), STRING_ADD_CHECK_NONE,
10327 23996 : allocation_mode.feedback_site());
10328 : }
10329 :
10330 : // Special case for +x here.
10331 346932 : if (op == Token::MUL) {
10332 36376 : if (left->EqualsInteger32Constant(1)) {
10333 50 : return BuildToNumber(right);
10334 : }
10335 36326 : if (right->EqualsInteger32Constant(1)) {
10336 9520 : return BuildToNumber(left);
10337 : }
10338 : }
10339 :
10340 337362 : if (graph()->info()->IsStub()) {
10341 5868 : left = EnforceNumberType(left, left_type);
10342 5868 : right = EnforceNumberType(right, right_type);
10343 : }
10344 :
10345 337362 : Representation result_rep = RepresentationFor(result_type);
10346 :
10347 337362 : bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) ||
10348 31233 : (right_rep.IsTagged() && !right_rep.IsSmi());
10349 :
10350 : HInstruction* instr = NULL;
10351 : // Only the stub is allowed to call into the runtime, since otherwise we would
10352 : // inline several instructions (including the two pushes) for every tagged
10353 : // operation in optimized code, which is more expensive, than a stub call.
10354 337362 : if (graph()->info()->IsStub() && is_non_primitive) {
10355 785 : HValue* values[] = {left, right};
10356 : #define GET_STUB(Name) \
10357 : do { \
10358 : Callable callable = CodeFactory::Name(isolate()); \
10359 : HValue* stub = Add<HConstant>(callable.code()); \
10360 : instr = AddUncasted<HCallWithDescriptor>(stub, 0, callable.descriptor(), \
10361 : ArrayVector(values)); \
10362 : } while (false)
10363 :
10364 785 : switch (op) {
10365 : default:
10366 0 : UNREACHABLE();
10367 : case Token::ADD:
10368 586 : GET_STUB(Add);
10369 293 : break;
10370 : case Token::SUB:
10371 154 : GET_STUB(Subtract);
10372 77 : break;
10373 : case Token::MUL:
10374 242 : GET_STUB(Multiply);
10375 121 : break;
10376 : case Token::DIV:
10377 58 : GET_STUB(Divide);
10378 29 : break;
10379 : case Token::MOD:
10380 52 : GET_STUB(Modulus);
10381 26 : break;
10382 : case Token::BIT_OR:
10383 136 : GET_STUB(BitwiseOr);
10384 68 : break;
10385 : case Token::BIT_AND:
10386 48 : GET_STUB(BitwiseAnd);
10387 24 : break;
10388 : case Token::BIT_XOR:
10389 72 : GET_STUB(BitwiseXor);
10390 36 : break;
10391 : case Token::SAR:
10392 62 : GET_STUB(ShiftRight);
10393 31 : break;
10394 : case Token::SHR:
10395 116 : GET_STUB(ShiftRightLogical);
10396 58 : break;
10397 : case Token::SHL:
10398 44 : GET_STUB(ShiftLeft);
10399 22 : break;
10400 : }
10401 : #undef GET_STUB
10402 : } else {
10403 336577 : switch (op) {
10404 : case Token::ADD:
10405 156841 : instr = AddUncasted<HAdd>(left, right);
10406 156841 : break;
10407 : case Token::SUB:
10408 19576 : instr = AddUncasted<HSub>(left, right);
10409 19576 : break;
10410 : case Token::MUL:
10411 26685 : instr = AddUncasted<HMul>(left, right);
10412 26685 : break;
10413 : case Token::MOD: {
10414 6349 : if (fixed_right_arg.IsJust() &&
10415 712 : !right->EqualsInteger32Constant(fixed_right_arg.FromJust())) {
10416 : HConstant* fixed_right =
10417 456 : Add<HConstant>(static_cast<int>(fixed_right_arg.FromJust()));
10418 : IfBuilder if_same(this);
10419 456 : if_same.If<HCompareNumericAndBranch>(right, fixed_right, Token::EQ);
10420 456 : if_same.Then();
10421 456 : if_same.ElseDeopt(DeoptimizeReason::kUnexpectedRHSOfBinaryOperation);
10422 : right = fixed_right;
10423 : }
10424 5637 : instr = AddUncasted<HMod>(left, right);
10425 5637 : break;
10426 : }
10427 : case Token::DIV:
10428 52435 : instr = AddUncasted<HDiv>(left, right);
10429 52435 : break;
10430 : case Token::BIT_XOR:
10431 : case Token::BIT_AND:
10432 22092 : instr = AddUncasted<HBitwise>(op, left, right);
10433 22092 : break;
10434 : case Token::BIT_OR: {
10435 : HValue *operand, *shift_amount;
10436 73736 : if (left_type->Is(AstType::Signed32()) &&
10437 45785 : right_type->Is(AstType::Signed32()) &&
10438 18214 : MatchRotateRight(left, right, &operand, &shift_amount)) {
10439 500 : instr = AddUncasted<HRor>(operand, shift_amount);
10440 : } else {
10441 27071 : instr = AddUncasted<HBitwise>(op, left, right);
10442 : }
10443 : break;
10444 : }
10445 : case Token::SAR:
10446 9831 : instr = AddUncasted<HSar>(left, right);
10447 9831 : break;
10448 : case Token::SHR:
10449 8278 : instr = AddUncasted<HShr>(left, right);
10450 16556 : if (instr->IsShr() && CanBeZero(right)) {
10451 3397 : graph()->RecordUint32Instruction(instr);
10452 : }
10453 : break;
10454 : case Token::SHL:
10455 7631 : instr = AddUncasted<HShl>(left, right);
10456 7631 : break;
10457 : default:
10458 0 : UNREACHABLE();
10459 : }
10460 : }
10461 :
10462 337362 : if (instr->IsBinaryOperation()) {
10463 : HBinaryOperation* binop = HBinaryOperation::cast(instr);
10464 : binop->set_observed_input_representation(1, left_rep);
10465 : binop->set_observed_input_representation(2, right_rep);
10466 336379 : binop->initialize_output_representation(result_rep);
10467 336379 : if (graph()->info()->IsStub()) {
10468 : // Stub should not call into stub.
10469 : instr->SetFlag(HValue::kCannotBeTagged);
10470 : // And should truncate on HForceRepresentation already.
10471 5083 : if (left->IsForceRepresentation()) {
10472 : left->CopyFlag(HValue::kTruncatingToSmi, instr);
10473 : left->CopyFlag(HValue::kTruncatingToInt32, instr);
10474 : }
10475 5083 : if (right->IsForceRepresentation()) {
10476 : right->CopyFlag(HValue::kTruncatingToSmi, instr);
10477 : right->CopyFlag(HValue::kTruncatingToInt32, instr);
10478 : }
10479 : }
10480 : }
10481 337362 : return instr;
10482 : }
10483 :
10484 : // Check for the form (%_ClassOf(foo) === 'BarClass').
10485 746491 : static bool IsClassOfTest(CompareOperation* expr) {
10486 420838 : if (expr->op() != Token::EQ_STRICT) return false;
10487 325567 : CallRuntime* call = expr->left()->AsCallRuntime();
10488 317864 : if (call == NULL) return false;
10489 15578 : Literal* literal = expr->right()->AsLiteral();
10490 7789 : if (literal == NULL) return false;
10491 7789 : if (!literal->value()->IsString()) return false;
10492 7703 : if (call->is_jsruntime()) return false;
10493 7697 : if (call->function()->function_id != Runtime::kInlineClassOf) return false;
10494 : DCHECK_EQ(call->arguments()->length(), 1);
10495 7697 : return true;
10496 : }
10497 :
10498 510401 : void HOptimizedGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
10499 : DCHECK(!HasStackOverflow());
10500 : DCHECK(current_block() != NULL);
10501 : DCHECK(current_block()->HasPredecessor());
10502 510401 : switch (expr->op()) {
10503 : case Token::COMMA:
10504 6037 : return VisitComma(expr);
10505 : case Token::OR:
10506 : case Token::AND:
10507 122646 : return VisitLogicalExpression(expr);
10508 : default:
10509 381718 : return VisitArithmeticExpression(expr);
10510 : }
10511 : }
10512 :
10513 :
10514 18102 : void HOptimizedGraphBuilder::VisitComma(BinaryOperation* expr) {
10515 18111 : CHECK_ALIVE(VisitForEffect(expr->left()));
10516 : // Visit the right subexpression in the same AST context as the entire
10517 : // expression.
10518 6028 : Visit(expr->right());
10519 : }
10520 :
10521 :
10522 669136 : void HOptimizedGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
10523 122646 : bool is_logical_and = expr->op() == Token::AND;
10524 122646 : if (ast_context()->IsTest()) {
10525 111388 : TestContext* context = TestContext::cast(ast_context());
10526 : // Translate left subexpression.
10527 155988 : HBasicBlock* eval_right = graph()->CreateBasicBlock();
10528 111388 : if (is_logical_and) {
10529 90492 : CHECK_BAILOUT(VisitForControl(expr->left(),
10530 : eval_right,
10531 : context->if_false()));
10532 : } else {
10533 132284 : CHECK_BAILOUT(VisitForControl(expr->left(),
10534 : context->if_true(),
10535 : eval_right));
10536 : }
10537 :
10538 : // Translate right subexpression by visiting it in the same AST
10539 : // context as the entire expression.
10540 111388 : CHECK(eval_right->HasPredecessor());
10541 : eval_right->SetJoinId(expr->RightId());
10542 : set_current_block(eval_right);
10543 111388 : Visit(expr->right());
10544 11258 : } else if (ast_context()->IsValue()) {
10545 33666 : CHECK_ALIVE(VisitForValue(expr->left()));
10546 : DCHECK(current_block() != NULL);
10547 : HValue* left_value = Top();
10548 :
10549 : // Short-circuit left values that always evaluate to the same boolean value.
10550 22350 : if (expr->left()->ToBooleanIsTrue() || expr->left()->ToBooleanIsFalse()) {
10551 : // l (evals true) && r -> r
10552 : // l (evals true) || r -> l
10553 : // l (evals false) && r -> l
10554 : // l (evals false) || r -> r
10555 161 : if (is_logical_and == expr->left()->ToBooleanIsTrue()) {
10556 : Drop(1);
10557 267 : CHECK_ALIVE(VisitForValue(expr->right()));
10558 : }
10559 322 : return ast_context()->ReturnValue(Pop());
10560 : }
10561 :
10562 : // We need an extra block to maintain edge-split form.
10563 11061 : HBasicBlock* empty_block = graph()->CreateBasicBlock();
10564 11061 : HBasicBlock* eval_right = graph()->CreateBasicBlock();
10565 11061 : ToBooleanHints expected(expr->left()->to_boolean_types());
10566 : HBranch* test = is_logical_and
10567 6276 : ? New<HBranch>(left_value, expected, eval_right, empty_block)
10568 17337 : : New<HBranch>(left_value, expected, empty_block, eval_right);
10569 11061 : FinishCurrentBlock(test);
10570 :
10571 : set_current_block(eval_right);
10572 : Drop(1); // Value of the left subexpression.
10573 22122 : CHECK_BAILOUT(VisitForValue(expr->right()));
10574 :
10575 : HBasicBlock* join_block =
10576 11059 : CreateJoin(empty_block, current_block(), expr->id());
10577 : set_current_block(join_block);
10578 22118 : return ast_context()->ReturnValue(Pop());
10579 :
10580 : } else {
10581 : DCHECK(ast_context()->IsEffect());
10582 : // In an effect context, we don't need the value of the left subexpression,
10583 : // only its control flow and side effects. We need an extra block to
10584 : // maintain edge-split form.
10585 36 : HBasicBlock* empty_block = graph()->CreateBasicBlock();
10586 36 : HBasicBlock* right_block = graph()->CreateBasicBlock();
10587 36 : if (is_logical_and) {
10588 60 : CHECK_BAILOUT(VisitForControl(expr->left(), right_block, empty_block));
10589 : } else {
10590 12 : CHECK_BAILOUT(VisitForControl(expr->left(), empty_block, right_block));
10591 : }
10592 :
10593 : // TODO(kmillikin): Find a way to fix this. It's ugly that there are
10594 : // actually two empty blocks (one here and one inserted by
10595 : // TestContext::BuildBranch, and that they both have an HSimulate though the
10596 : // second one is not a merge node, and that we really have no good AST ID to
10597 : // put on that first HSimulate.
10598 :
10599 : // Technically, we should be able to handle the case when one side of
10600 : // the test is not connected, but this can trip up liveness analysis
10601 : // if we did not fully connect the test context based on some optimistic
10602 : // assumption. If such an assumption was violated, we would end up with
10603 : // an environment with optimized-out values. So we should always
10604 : // conservatively connect the test context.
10605 :
10606 36 : CHECK(right_block->HasPredecessor());
10607 36 : CHECK(empty_block->HasPredecessor());
10608 :
10609 : empty_block->SetJoinId(expr->id());
10610 :
10611 : right_block->SetJoinId(expr->RightId());
10612 : set_current_block(right_block);
10613 72 : CHECK_BAILOUT(VisitForEffect(expr->right()));
10614 : right_block = current_block();
10615 :
10616 : HBasicBlock* join_block =
10617 36 : CreateJoin(empty_block, right_block, expr->id());
10618 : set_current_block(join_block);
10619 : // We did not materialize any value in the predecessor environments,
10620 : // so there is no need to handle it here.
10621 : }
10622 : }
10623 :
10624 :
10625 2286820 : void HOptimizedGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) {
10626 1144268 : CHECK_ALIVE(VisitForValue(expr->left()));
10627 1142552 : CHECK_ALIVE(VisitForValue(expr->right()));
10628 380832 : SetSourcePosition(expr->position());
10629 : HValue* right = Pop();
10630 : HValue* left = Pop();
10631 : HValue* result =
10632 : BuildBinaryOperation(expr, left, right,
10633 380832 : ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE
10634 380832 : : PUSH_BEFORE_SIMULATE);
10635 380832 : return ast_context()->ReturnValue(result);
10636 : }
10637 :
10638 :
10639 66365 : void HOptimizedGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr,
10640 : Expression* sub_expr,
10641 132730 : Handle<String> check) {
10642 132730 : CHECK_ALIVE(VisitForTypeOf(sub_expr));
10643 66365 : SetSourcePosition(expr->position());
10644 : HValue* value = Pop();
10645 66365 : HTypeofIsAndBranch* instr = New<HTypeofIsAndBranch>(value, check);
10646 132730 : return ast_context()->ReturnControl(instr, expr->id());
10647 : }
10648 :
10649 : namespace {
10650 :
10651 413136 : bool IsLiteralCompareStrict(Isolate* isolate, HValue* left, Token::Value op,
10652 : HValue* right) {
10653 723300 : return op == Token::EQ_STRICT &&
10654 7364 : ((left->IsConstant() &&
10655 431392 : !HConstant::cast(left)->handle(isolate)->IsNumber() &&
10656 725552 : !HConstant::cast(left)->handle(isolate)->IsString()) ||
10657 172599 : (right->IsConstant() &&
10658 724957 : !HConstant::cast(right)->handle(isolate)->IsNumber() &&
10659 1371266 : !HConstant::cast(right)->handle(isolate)->IsString()));
10660 : }
10661 :
10662 : } // namespace
10663 :
10664 5054982 : void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
10665 : DCHECK(!HasStackOverflow());
10666 : DCHECK(current_block() != NULL);
10667 : DCHECK(current_block()->HasPredecessor());
10668 :
10669 1757679 : if (!is_tracking_positions()) SetSourcePosition(expr->position());
10670 :
10671 : // Check for a few fast cases. The AST visiting behavior must be in sync
10672 : // with the full codegen: We don't push both left and right values onto
10673 : // the expression stack when one side is a special-case literal.
10674 504844 : Expression* sub_expr = NULL;
10675 : Literal* literal;
10676 504844 : if (expr->IsLiteralCompareTypeof(&sub_expr, &literal)) {
10677 : return HandleLiteralCompareTypeof(expr, sub_expr,
10678 132730 : Handle<String>::cast(literal->value()));
10679 : }
10680 438479 : if (expr->IsLiteralCompareUndefined(&sub_expr)) {
10681 12086 : return HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue);
10682 : }
10683 426393 : if (expr->IsLiteralCompareNull(&sub_expr)) {
10684 5555 : return HandleLiteralCompareNil(expr, sub_expr, kNullValue);
10685 : }
10686 :
10687 420838 : if (IsClassOfTest(expr)) {
10688 15394 : CallRuntime* call = expr->left()->AsCallRuntime();
10689 : DCHECK(call->arguments()->length() == 1);
10690 23091 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10691 : HValue* value = Pop();
10692 15394 : Literal* literal = expr->right()->AsLiteral();
10693 7697 : Handle<String> rhs = Handle<String>::cast(literal->value());
10694 7697 : HClassOfTestAndBranch* instr = New<HClassOfTestAndBranch>(value, rhs);
10695 15394 : return ast_context()->ReturnControl(instr, expr->id());
10696 : }
10697 :
10698 413141 : AstType* left_type = bounds_.get(expr->left()).lower;
10699 413141 : AstType* right_type = bounds_.get(expr->right()).lower;
10700 : AstType* combined_type = expr->combined_type();
10701 :
10702 1239419 : CHECK_ALIVE(VisitForValue(expr->left()));
10703 1239410 : CHECK_ALIVE(VisitForValue(expr->right()));
10704 :
10705 : HValue* right = Pop();
10706 : HValue* left = Pop();
10707 : Token::Value op = expr->op();
10708 :
10709 413136 : if (IsLiteralCompareStrict(isolate(), left, op, right)) {
10710 : HCompareObjectEqAndBranch* result =
10711 5637 : New<HCompareObjectEqAndBranch>(left, right);
10712 11274 : return ast_context()->ReturnControl(result, expr->id());
10713 : }
10714 :
10715 407499 : if (op == Token::INSTANCEOF) {
10716 : // Check to see if the rhs of the instanceof is a known function.
10717 4623 : if (right->IsConstant() &&
10718 2465 : HConstant::cast(right)->handle(isolate())->IsJSFunction()) {
10719 : Handle<JSFunction> function =
10720 430 : Handle<JSFunction>::cast(HConstant::cast(right)->handle(isolate()));
10721 : // Make sure that the {function} already has a meaningful initial map
10722 : // (i.e. we constructed at least one instance using the constructor
10723 : // {function}), and has an instance as .prototype.
10724 826 : if (function->has_initial_map() &&
10725 : !function->map()->has_non_instance_prototype()) {
10726 : // Lookup @@hasInstance on the {function}.
10727 : Handle<Map> function_map(function->map(), isolate());
10728 : PropertyAccessInfo has_instance(
10729 : this, LOAD, function_map,
10730 395 : isolate()->factory()->has_instance_symbol());
10731 : // Check if we are using the Function.prototype[@@hasInstance].
10732 1190 : if (has_instance.CanAccessMonomorphic() &&
10733 724 : has_instance.IsDataConstant() &&
10734 : has_instance.constant().is_identical_to(
10735 1053 : isolate()->function_has_instance())) {
10736 : // Add appropriate receiver map check and prototype chain
10737 : // checks to guard the @@hasInstance lookup chain.
10738 323 : AddCheckMap(right, function_map);
10739 323 : if (has_instance.has_holder()) {
10740 : Handle<JSObject> prototype(
10741 646 : JSObject::cast(has_instance.map()->prototype()), isolate());
10742 323 : BuildCheckPrototypeMaps(prototype, has_instance.holder());
10743 : }
10744 : // Perform the prototype chain walk.
10745 : Handle<Map> initial_map(function->initial_map(), isolate());
10746 323 : top_info()->dependencies()->AssumeInitialMapCantChange(initial_map);
10747 : HInstruction* prototype =
10748 323 : Add<HConstant>(handle(initial_map->prototype(), isolate()));
10749 : HHasInPrototypeChainAndBranch* result =
10750 323 : New<HHasInPrototypeChainAndBranch>(left, prototype);
10751 646 : return ast_context()->ReturnControl(result, expr->id());
10752 : }
10753 : }
10754 : }
10755 :
10756 1218 : Callable callable = CodeFactory::InstanceOf(isolate());
10757 1218 : HValue* stub = Add<HConstant>(callable.code());
10758 1218 : HValue* values[] = {left, right};
10759 : HCallWithDescriptor* result = New<HCallWithDescriptor>(
10760 1218 : stub, 0, callable.descriptor(), ArrayVector(values));
10761 : result->set_type(HType::Boolean());
10762 2436 : return ast_context()->ReturnInstruction(result, expr->id());
10763 :
10764 405958 : } else if (op == Token::IN) {
10765 1208 : Callable callable = CodeFactory::HasProperty(isolate());
10766 1208 : HValue* stub = Add<HConstant>(callable.code());
10767 1208 : HValue* values[] = {left, right};
10768 : HInstruction* result =
10769 : New<HCallWithDescriptor>(stub, 0, callable.descriptor(),
10770 1208 : Vector<HValue*>(values, arraysize(values)));
10771 2416 : return ast_context()->ReturnInstruction(result, expr->id());
10772 : }
10773 :
10774 : PushBeforeSimulateBehavior push_behavior =
10775 404750 : ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE
10776 404750 : : PUSH_BEFORE_SIMULATE;
10777 : HControlInstruction* compare = BuildCompareInstruction(
10778 : op, left, right, left_type, right_type, combined_type,
10779 : ScriptPositionToSourcePosition(expr->left()->position()),
10780 : ScriptPositionToSourcePosition(expr->right()->position()),
10781 1214250 : push_behavior, expr->id());
10782 404750 : if (compare == NULL) return; // Bailed out.
10783 809480 : return ast_context()->ReturnControl(compare, expr->id());
10784 : }
10785 :
10786 433026 : HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction(
10787 1018 : Token::Value op, HValue* left, HValue* right, AstType* left_type,
10788 : AstType* right_type, AstType* combined_type, SourcePosition left_position,
10789 : SourcePosition right_position, PushBeforeSimulateBehavior push_sim_result,
10790 : BailoutId bailout_id) {
10791 : // Cases handled below depend on collected type feedback. They should
10792 : // soft deoptimize when there is no type feedback.
10793 433026 : if (!combined_type->IsInhabited()) {
10794 : Add<HDeoptimize>(
10795 : DeoptimizeReason::
10796 : kInsufficientTypeFeedbackForCombinedTypeOfBinaryOperation,
10797 295719 : Deoptimizer::SOFT);
10798 : combined_type = left_type = right_type = AstType::Any();
10799 : }
10800 :
10801 433026 : Representation left_rep = RepresentationFor(left_type);
10802 433026 : Representation right_rep = RepresentationFor(right_type);
10803 433026 : Representation combined_rep = RepresentationFor(combined_type);
10804 :
10805 433026 : if (combined_type->Is(AstType::Receiver())) {
10806 641 : if (Token::IsEqualityOp(op)) {
10807 : // HCompareObjectEqAndBranch can only deal with object, so
10808 : // exclude numbers.
10809 644 : if ((left->IsConstant() &&
10810 1250 : HConstant::cast(left)->HasNumberValue()) ||
10811 11 : (right->IsConstant() &&
10812 : HConstant::cast(right)->HasNumberValue())) {
10813 : Add<HDeoptimize>(
10814 : DeoptimizeReason::kTypeMismatchBetweenFeedbackAndConstant,
10815 9 : Deoptimizer::SOFT);
10816 : // The caller expects a branch instruction, so make it happy.
10817 9 : return New<HBranch>(graph()->GetConstantTrue());
10818 : }
10819 620 : if (op == Token::EQ) {
10820 : // For abstract equality we need to check both sides are receivers.
10821 111 : if (combined_type->IsClass()) {
10822 18 : Handle<Map> map = combined_type->AsClass()->Map();
10823 18 : AddCheckMap(left, map);
10824 18 : AddCheckMap(right, map);
10825 : } else {
10826 93 : BuildCheckHeapObject(left);
10827 93 : Add<HCheckInstanceType>(left, HCheckInstanceType::IS_JS_RECEIVER);
10828 : BuildCheckHeapObject(right);
10829 93 : Add<HCheckInstanceType>(right, HCheckInstanceType::IS_JS_RECEIVER);
10830 : }
10831 : } else {
10832 : // For strict equality we only need to check one side.
10833 : HValue* operand_to_check =
10834 1018 : left->block()->block_id() < right->block()->block_id() ? left
10835 509 : : right;
10836 509 : if (combined_type->IsClass()) {
10837 32 : Handle<Map> map = combined_type->AsClass()->Map();
10838 32 : AddCheckMap(operand_to_check, map);
10839 : } else {
10840 477 : BuildCheckHeapObject(operand_to_check);
10841 : Add<HCheckInstanceType>(operand_to_check,
10842 477 : HCheckInstanceType::IS_JS_RECEIVER);
10843 : }
10844 : }
10845 : HCompareObjectEqAndBranch* result =
10846 620 : New<HCompareObjectEqAndBranch>(left, right);
10847 620 : return result;
10848 : } else {
10849 12 : if (combined_type->IsClass()) {
10850 : // TODO(bmeurer): This is an optimized version of an x < y, x > y,
10851 : // x <= y or x >= y, where both x and y are spec objects with the
10852 : // same map. The CompareIC collects this map for us. So if we know
10853 : // that there's no @@toPrimitive on the map (including the prototype
10854 : // chain), and both valueOf and toString are the default initial
10855 : // implementations (on the %ObjectPrototype%), then we can reduce
10856 : // the comparison to map checks on x and y, because the comparison
10857 : // will turn into a comparison of "[object CLASS]" to itself (the
10858 : // default outcome of toString, since valueOf returns a spec object).
10859 : // This is pretty much adhoc, so in TurboFan we could do a lot better
10860 : // and inline the interesting parts of ToPrimitive (actually we could
10861 : // even do that in Crankshaft but we don't want to waste too much
10862 : // time on this now).
10863 : DCHECK(Token::IsOrderedRelationalCompareOp(op));
10864 : Handle<Map> map = combined_type->AsClass()->Map();
10865 : PropertyAccessInfo value_of(this, LOAD, map,
10866 12 : isolate()->factory()->valueOf_string());
10867 : PropertyAccessInfo to_primitive(
10868 12 : this, LOAD, map, isolate()->factory()->to_primitive_symbol());
10869 : PropertyAccessInfo to_string(this, LOAD, map,
10870 12 : isolate()->factory()->toString_string());
10871 : PropertyAccessInfo to_string_tag(
10872 12 : this, LOAD, map, isolate()->factory()->to_string_tag_symbol());
10873 40 : if (to_primitive.CanAccessMonomorphic() && !to_primitive.IsFound() &&
10874 8 : to_string_tag.CanAccessMonomorphic() &&
10875 4 : (!to_string_tag.IsFound() || to_string_tag.IsData() ||
10876 4 : to_string_tag.IsDataConstant()) &&
10877 12 : value_of.CanAccessMonomorphic() && value_of.IsDataConstant() &&
10878 24 : value_of.constant().is_identical_to(isolate()->object_value_of()) &&
10879 22 : to_string.CanAccessMonomorphic() && to_string.IsDataConstant() &&
10880 : to_string.constant().is_identical_to(
10881 14 : isolate()->object_to_string())) {
10882 : // We depend on the prototype chain to stay the same, because we
10883 : // also need to deoptimize when someone installs @@toPrimitive
10884 : // or @@toStringTag somewhere in the prototype chain.
10885 : Handle<Object> prototype(map->prototype(), isolate());
10886 2 : if (prototype->IsJSObject()) {
10887 : BuildCheckPrototypeMaps(Handle<JSObject>::cast(prototype),
10888 0 : Handle<JSObject>::null());
10889 : }
10890 2 : AddCheckMap(left, map);
10891 2 : AddCheckMap(right, map);
10892 : // The caller expects a branch instruction, so make it happy.
10893 : return New<HBranch>(
10894 4 : graph()->GetConstantBool(op == Token::LTE || op == Token::GTE));
10895 : }
10896 : }
10897 : Bailout(kUnsupportedNonPrimitiveCompare);
10898 10 : return NULL;
10899 : }
10900 441259 : } else if (combined_type->Is(AstType::InternalizedString()) &&
10901 : Token::IsEqualityOp(op)) {
10902 : // If we have a constant argument, it should be consistent with the type
10903 : // feedback (otherwise we fail assertions in HCompareObjectEqAndBranch).
10904 9117 : if ((left->IsConstant() &&
10905 17746 : !HConstant::cast(left)->HasInternalizedStringValue()) ||
10906 4036 : (right->IsConstant() &&
10907 4036 : !HConstant::cast(right)->HasInternalizedStringValue())) {
10908 : Add<HDeoptimize>(
10909 : DeoptimizeReason::kTypeMismatchBetweenFeedbackAndConstant,
10910 2 : Deoptimizer::SOFT);
10911 : // The caller expects a branch instruction, so make it happy.
10912 2 : return New<HBranch>(graph()->GetConstantTrue());
10913 : }
10914 8872 : BuildCheckHeapObject(left);
10915 8872 : Add<HCheckInstanceType>(left, HCheckInstanceType::IS_INTERNALIZED_STRING);
10916 : BuildCheckHeapObject(right);
10917 8872 : Add<HCheckInstanceType>(right, HCheckInstanceType::IS_INTERNALIZED_STRING);
10918 : HCompareObjectEqAndBranch* result =
10919 8872 : New<HCompareObjectEqAndBranch>(left, right);
10920 8872 : return result;
10921 423511 : } else if (combined_type->Is(AstType::String())) {
10922 15209 : BuildCheckHeapObject(left);
10923 15209 : Add<HCheckInstanceType>(left, HCheckInstanceType::IS_STRING);
10924 : BuildCheckHeapObject(right);
10925 15209 : Add<HCheckInstanceType>(right, HCheckInstanceType::IS_STRING);
10926 : HStringCompareAndBranch* result =
10927 15209 : New<HStringCompareAndBranch>(left, right, op);
10928 15209 : return result;
10929 408302 : } else if (combined_type->Is(AstType::Boolean())) {
10930 643 : AddCheckMap(left, isolate()->factory()->boolean_map());
10931 643 : AddCheckMap(right, isolate()->factory()->boolean_map());
10932 643 : if (Token::IsEqualityOp(op)) {
10933 : HCompareObjectEqAndBranch* result =
10934 609 : New<HCompareObjectEqAndBranch>(left, right);
10935 609 : return result;
10936 : }
10937 : left = Add<HLoadNamedField>(
10938 : left, nullptr,
10939 34 : HObjectAccess::ForOddballToNumber(Representation::Smi()));
10940 : right = Add<HLoadNamedField>(
10941 : right, nullptr,
10942 34 : HObjectAccess::ForOddballToNumber(Representation::Smi()));
10943 : HCompareNumericAndBranch* result =
10944 34 : New<HCompareNumericAndBranch>(left, right, op);
10945 34 : return result;
10946 : } else {
10947 407659 : if (op == Token::EQ) {
10948 21006 : if (left->IsConstant() &&
10949 19532 : HConstant::cast(left)->GetInstanceType() == ODDBALL_TYPE &&
10950 : HConstant::cast(left)->IsUndetectable()) {
10951 0 : return New<HIsUndetectableAndBranch>(right);
10952 : }
10953 :
10954 32303 : if (right->IsConstant() &&
10955 19545 : HConstant::cast(right)->GetInstanceType() == ODDBALL_TYPE &&
10956 : HConstant::cast(right)->IsUndetectable()) {
10957 1 : return New<HIsUndetectableAndBranch>(left);
10958 : }
10959 : }
10960 :
10961 407658 : if (combined_rep.IsTagged() || combined_rep.IsNone()) {
10962 327836 : HCompareGeneric* result = Add<HCompareGeneric>(left, right, op);
10963 : result->set_observed_input_representation(1, left_rep);
10964 : result->set_observed_input_representation(2, right_rep);
10965 327836 : if (result->HasObservableSideEffects()) {
10966 327836 : if (push_sim_result == PUSH_BEFORE_SIMULATE) {
10967 327758 : Push(result);
10968 : AddSimulate(bailout_id, REMOVABLE_SIMULATE);
10969 : Drop(1);
10970 : } else {
10971 : AddSimulate(bailout_id, REMOVABLE_SIMULATE);
10972 : }
10973 : }
10974 : // TODO(jkummerow): Can we make this more efficient?
10975 327836 : HBranch* branch = New<HBranch>(result);
10976 327836 : return branch;
10977 : } else {
10978 : HCompareNumericAndBranch* result =
10979 79822 : New<HCompareNumericAndBranch>(left, right, op);
10980 : result->set_observed_input_representation(left_rep, right_rep);
10981 79822 : return result;
10982 : }
10983 : }
10984 : }
10985 :
10986 :
10987 35282 : void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
10988 : Expression* sub_expr,
10989 35282 : NilValue nil) {
10990 : DCHECK(!HasStackOverflow());
10991 : DCHECK(current_block() != NULL);
10992 : DCHECK(current_block()->HasPredecessor());
10993 : DCHECK(expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT);
10994 51436 : if (!is_tracking_positions()) SetSourcePosition(expr->position());
10995 52923 : CHECK_ALIVE(VisitForValue(sub_expr));
10996 : HValue* value = Pop();
10997 : HControlInstruction* instr;
10998 17641 : if (expr->op() == Token::EQ_STRICT) {
10999 : HConstant* nil_constant = nil == kNullValue
11000 : ? graph()->GetConstantNull()
11001 32308 : : graph()->GetConstantUndefined();
11002 16154 : instr = New<HCompareObjectEqAndBranch>(value, nil_constant);
11003 : } else {
11004 : DCHECK_EQ(Token::EQ, expr->op());
11005 1487 : instr = New<HIsUndetectableAndBranch>(value);
11006 : }
11007 35282 : return ast_context()->ReturnControl(instr, expr->id());
11008 : }
11009 :
11010 :
11011 0 : void HOptimizedGraphBuilder::VisitSpread(Spread* expr) { UNREACHABLE(); }
11012 :
11013 :
11014 0 : void HOptimizedGraphBuilder::VisitEmptyParentheses(EmptyParentheses* expr) {
11015 0 : UNREACHABLE();
11016 : }
11017 :
11018 0 : void HOptimizedGraphBuilder::VisitGetIterator(GetIterator* expr) {
11019 0 : UNREACHABLE();
11020 : }
11021 :
11022 0 : void HOptimizedGraphBuilder::VisitImportCallExpression(
11023 : ImportCallExpression* expr) {
11024 0 : UNREACHABLE();
11025 : }
11026 :
11027 42183 : HValue* HOptimizedGraphBuilder::AddThisFunction() {
11028 42183 : return AddInstruction(BuildThisFunction());
11029 : }
11030 :
11031 :
11032 93016 : HInstruction* HOptimizedGraphBuilder::BuildThisFunction() {
11033 : // If we share optimized code between different closures, the
11034 : // this-function is not a constant, except inside an inlined body.
11035 93016 : if (function_state()->outer() != NULL) {
11036 : return New<HConstant>(
11037 48642 : function_state()->compilation_info()->closure());
11038 : } else {
11039 44374 : return New<HThisFunction>();
11040 : }
11041 : }
11042 :
11043 :
11044 7345 : HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
11045 : Handle<JSObject> boilerplate_object,
11046 : AllocationSiteUsageContext* site_context) {
11047 60714 : NoObservableSideEffectsScope no_effects(this);
11048 : Handle<Map> initial_map(boilerplate_object->map());
11049 : InstanceType instance_type = initial_map->instance_type();
11050 : DCHECK(instance_type == JS_ARRAY_TYPE || instance_type == JS_OBJECT_TYPE);
11051 :
11052 : HType type = instance_type == JS_ARRAY_TYPE
11053 7345 : ? HType::JSArray() : HType::JSObject();
11054 7345 : HValue* object_size_constant = Add<HConstant>(initial_map->instance_size());
11055 :
11056 : PretenureFlag pretenure_flag = NOT_TENURED;
11057 : Handle<AllocationSite> top_site(*site_context->top(), isolate());
11058 7345 : if (FLAG_allocation_site_pretenuring) {
11059 7345 : pretenure_flag = top_site->GetPretenureMode();
11060 : }
11061 :
11062 : Handle<AllocationSite> current_site(*site_context->current(), isolate());
11063 7345 : if (*top_site == *current_site) {
11064 : // We install a dependency for pretenuring only on the outermost literal.
11065 6683 : top_info()->dependencies()->AssumeTenuringDecision(top_site);
11066 : }
11067 7345 : top_info()->dependencies()->AssumeTransitionStable(current_site);
11068 :
11069 : HInstruction* object =
11070 : Add<HAllocate>(object_size_constant, type, pretenure_flag, instance_type,
11071 7345 : graph()->GetConstant0(), top_site);
11072 :
11073 : // If allocation folding reaches kMaxRegularHeapObjectSize the
11074 : // elements array may not get folded into the object. Hence, we set the
11075 : // elements pointer to empty fixed array and let store elimination remove
11076 : // this store in the folding case.
11077 : HConstant* empty_fixed_array = Add<HConstant>(
11078 7345 : isolate()->factory()->empty_fixed_array());
11079 : Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
11080 7345 : empty_fixed_array);
11081 :
11082 7345 : BuildEmitObjectHeader(boilerplate_object, object);
11083 :
11084 : // Similarly to the elements pointer, there is no guarantee that all
11085 : // property allocations can get folded, so pre-initialize all in-object
11086 : // properties to a safe value.
11087 7345 : BuildInitializeInobjectProperties(object, initial_map);
11088 :
11089 : // Copy in-object properties.
11090 11604 : if (initial_map->NumberOfFields() != 0 ||
11091 : initial_map->unused_property_fields() > 0) {
11092 : BuildEmitInObjectProperties(boilerplate_object, object, site_context,
11093 3956 : pretenure_flag);
11094 : }
11095 :
11096 : // Copy elements.
11097 : Handle<FixedArrayBase> elements(boilerplate_object->elements());
11098 2585 : int elements_size = (elements->length() > 0 &&
11099 2585 : elements->map() != isolate()->heap()->fixed_cow_array_map()) ?
11100 9166 : elements->Size() : 0;
11101 :
11102 7376 : if (pretenure_flag == TENURED &&
11103 7376 : elements->map() == isolate()->heap()->fixed_cow_array_map() &&
11104 : isolate()->heap()->InNewSpace(*elements)) {
11105 : // If we would like to pretenure a fixed cow array, we must ensure that the
11106 : // array is already in old space, otherwise we'll create too many old-to-
11107 : // new-space pointers (overflowing the store buffer).
11108 : elements = Handle<FixedArrayBase>(
11109 : isolate()->factory()->CopyAndTenureFixedCOWArray(
11110 0 : Handle<FixedArray>::cast(elements)));
11111 0 : boilerplate_object->set_elements(*elements);
11112 : }
11113 :
11114 : HInstruction* object_elements = NULL;
11115 7345 : if (elements_size > 0) {
11116 1821 : HValue* object_elements_size = Add<HConstant>(elements_size);
11117 1821 : InstanceType instance_type = boilerplate_object->HasFastDoubleElements()
11118 1821 : ? FIXED_DOUBLE_ARRAY_TYPE : FIXED_ARRAY_TYPE;
11119 : object_elements = Add<HAllocate>(object_elements_size, HType::HeapObject(),
11120 : pretenure_flag, instance_type,
11121 1821 : graph()->GetConstant0(), top_site);
11122 : BuildEmitElements(boilerplate_object, elements, object_elements,
11123 1821 : site_context);
11124 : Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
11125 1821 : object_elements);
11126 : } else {
11127 : Handle<Object> elements_field =
11128 : Handle<Object>(boilerplate_object->elements(), isolate());
11129 5524 : HInstruction* object_elements_cow = Add<HConstant>(elements_field);
11130 : Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
11131 5524 : object_elements_cow);
11132 : }
11133 :
11134 7345 : return object;
11135 : }
11136 :
11137 :
11138 7345 : void HOptimizedGraphBuilder::BuildEmitObjectHeader(
11139 : Handle<JSObject> boilerplate_object,
11140 : HInstruction* object) {
11141 : DCHECK(boilerplate_object->properties()->length() == 0);
11142 :
11143 : Handle<Map> boilerplate_object_map(boilerplate_object->map());
11144 10734 : AddStoreMapConstant(object, boilerplate_object_map);
11145 :
11146 : Handle<Object> properties_field =
11147 : Handle<Object>(boilerplate_object->properties(), isolate());
11148 : DCHECK(*properties_field == isolate()->heap()->empty_fixed_array());
11149 7345 : HInstruction* properties = Add<HConstant>(properties_field);
11150 7345 : HObjectAccess access = HObjectAccess::ForPropertiesPointer();
11151 7345 : Add<HStoreNamedField>(object, access, properties);
11152 :
11153 7345 : if (boilerplate_object->IsJSArray()) {
11154 : Handle<JSArray> boilerplate_array =
11155 : Handle<JSArray>::cast(boilerplate_object);
11156 : Handle<Object> length_field =
11157 : Handle<Object>(boilerplate_array->length(), isolate());
11158 3389 : HInstruction* length = Add<HConstant>(length_field);
11159 :
11160 : DCHECK(boilerplate_array->length()->IsSmi());
11161 : Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(
11162 3389 : boilerplate_array->GetElementsKind()), length);
11163 : }
11164 7345 : }
11165 :
11166 :
11167 3956 : void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
11168 : Handle<JSObject> boilerplate_object,
11169 : HInstruction* object,
11170 : AllocationSiteUsageContext* site_context,
11171 : PretenureFlag pretenure_flag) {
11172 : Handle<Map> boilerplate_map(boilerplate_object->map());
11173 : Handle<DescriptorArray> descriptors(boilerplate_map->instance_descriptors());
11174 : int limit = boilerplate_map->NumberOfOwnDescriptors();
11175 :
11176 : int copied_fields = 0;
11177 11436 : for (int i = 0; i < limit; i++) {
11178 7480 : PropertyDetails details = descriptors->GetDetails(i);
11179 7563 : if (details.location() != kField) continue;
11180 : DCHECK_EQ(kData, details.kind());
11181 7480 : copied_fields++;
11182 7480 : FieldIndex field_index = FieldIndex::ForDescriptor(*boilerplate_map, i);
11183 :
11184 :
11185 : int property_offset = field_index.offset();
11186 : Handle<Name> name(descriptors->GetKey(i));
11187 :
11188 : // The access for the store depends on the type of the boilerplate.
11189 : HObjectAccess access = boilerplate_object->IsJSArray() ?
11190 : HObjectAccess::ForJSArrayOffset(property_offset) :
11191 7480 : HObjectAccess::ForMapAndOffset(boilerplate_map, property_offset);
11192 :
11193 7480 : if (boilerplate_object->IsUnboxedDoubleField(field_index)) {
11194 83 : CHECK(!boilerplate_object->IsJSArray());
11195 : double value = boilerplate_object->RawFastDoublePropertyAt(field_index);
11196 83 : access = access.WithRepresentation(Representation::Double());
11197 9522 : Add<HStoreNamedField>(object, access, Add<HConstant>(value));
11198 83 : continue;
11199 : }
11200 : Handle<Object> value(boilerplate_object->RawFastPropertyAt(field_index),
11201 7397 : isolate());
11202 :
11203 7397 : if (value->IsJSObject()) {
11204 349 : Handle<JSObject> value_object = Handle<JSObject>::cast(value);
11205 349 : Handle<AllocationSite> current_site = site_context->EnterNewScope();
11206 : HInstruction* result =
11207 349 : BuildFastLiteral(value_object, site_context);
11208 : site_context->ExitScope(current_site, value_object);
11209 349 : Add<HStoreNamedField>(object, access, result);
11210 : } else {
11211 : Representation representation = details.representation();
11212 : HInstruction* value_instruction;
11213 :
11214 7048 : if (representation.IsDouble()) {
11215 : // Allocate a HeapNumber box and store the value into it.
11216 0 : HValue* heap_number_constant = Add<HConstant>(HeapNumber::kSize);
11217 : HInstruction* double_box = Add<HAllocate>(
11218 : heap_number_constant, HType::HeapObject(), pretenure_flag,
11219 0 : MUTABLE_HEAP_NUMBER_TYPE, graph()->GetConstant0());
11220 : AddStoreMapConstant(double_box,
11221 0 : isolate()->factory()->mutable_heap_number_map());
11222 : // Unwrap the mutable heap number from the boilerplate.
11223 : HValue* double_value =
11224 0 : Add<HConstant>(Handle<HeapNumber>::cast(value)->value());
11225 : Add<HStoreNamedField>(
11226 0 : double_box, HObjectAccess::ForHeapNumberValue(), double_value);
11227 : value_instruction = double_box;
11228 7048 : } else if (representation.IsSmi()) {
11229 : value_instruction = value->IsUninitialized(isolate())
11230 : ? graph()->GetConstant0()
11231 3175 : : Add<HConstant>(value);
11232 : // Ensure that value is stored as smi.
11233 2886 : access = access.WithRepresentation(representation);
11234 : } else {
11235 4162 : value_instruction = Add<HConstant>(value);
11236 : }
11237 :
11238 7048 : Add<HStoreNamedField>(object, access, value_instruction);
11239 : }
11240 : }
11241 :
11242 : int inobject_properties = boilerplate_object->map()->GetInObjectProperties();
11243 : HInstruction* value_instruction =
11244 3956 : Add<HConstant>(isolate()->factory()->one_pointer_filler_map());
11245 7447 : for (int i = copied_fields; i < inobject_properties; i++) {
11246 : DCHECK(boilerplate_object->IsJSObject());
11247 3491 : int property_offset = boilerplate_object->GetInObjectPropertyOffset(i);
11248 : HObjectAccess access =
11249 3491 : HObjectAccess::ForMapAndOffset(boilerplate_map, property_offset);
11250 3491 : Add<HStoreNamedField>(object, access, value_instruction);
11251 : }
11252 3956 : }
11253 :
11254 :
11255 1821 : void HOptimizedGraphBuilder::BuildEmitElements(
11256 : Handle<JSObject> boilerplate_object,
11257 : Handle<FixedArrayBase> elements,
11258 : HValue* object_elements,
11259 : AllocationSiteUsageContext* site_context) {
11260 : ElementsKind kind = boilerplate_object->map()->elements_kind();
11261 : int elements_length = elements->length();
11262 1821 : HValue* object_elements_length = Add<HConstant>(elements_length);
11263 1821 : BuildInitializeElementsHeader(object_elements, kind, object_elements_length);
11264 :
11265 : // Copy elements backing store content.
11266 1821 : if (elements->IsFixedDoubleArray()) {
11267 428 : BuildEmitFixedDoubleArray(elements, kind, object_elements);
11268 1393 : } else if (elements->IsFixedArray()) {
11269 : BuildEmitFixedArray(elements, kind, object_elements,
11270 1393 : site_context);
11271 : } else {
11272 0 : UNREACHABLE();
11273 : }
11274 1821 : }
11275 :
11276 :
11277 428 : void HOptimizedGraphBuilder::BuildEmitFixedDoubleArray(
11278 : Handle<FixedArrayBase> elements,
11279 : ElementsKind kind,
11280 : HValue* object_elements) {
11281 428 : HInstruction* boilerplate_elements = Add<HConstant>(elements);
11282 : int elements_length = elements->length();
11283 5529 : for (int i = 0; i < elements_length; i++) {
11284 5101 : HValue* key_constant = Add<HConstant>(i);
11285 : HInstruction* value_instruction =
11286 : Add<HLoadKeyed>(boilerplate_elements, key_constant, nullptr, nullptr,
11287 5101 : kind, ALLOW_RETURN_HOLE);
11288 : HInstruction* store = Add<HStoreKeyed>(object_elements, key_constant,
11289 5101 : value_instruction, nullptr, kind);
11290 : store->SetFlag(HValue::kTruncatingToNumber);
11291 : }
11292 428 : }
11293 :
11294 :
11295 1393 : void HOptimizedGraphBuilder::BuildEmitFixedArray(
11296 : Handle<FixedArrayBase> elements,
11297 : ElementsKind kind,
11298 : HValue* object_elements,
11299 : AllocationSiteUsageContext* site_context) {
11300 8212 : HInstruction* boilerplate_elements = Add<HConstant>(elements);
11301 : int elements_length = elements->length();
11302 : Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
11303 8212 : for (int i = 0; i < elements_length; i++) {
11304 : Handle<Object> value(fast_elements->get(i), isolate());
11305 6819 : HValue* key_constant = Add<HConstant>(i);
11306 6819 : if (value->IsJSObject()) {
11307 313 : Handle<JSObject> value_object = Handle<JSObject>::cast(value);
11308 313 : Handle<AllocationSite> current_site = site_context->EnterNewScope();
11309 : HInstruction* result =
11310 313 : BuildFastLiteral(value_object, site_context);
11311 : site_context->ExitScope(current_site, value_object);
11312 313 : Add<HStoreKeyed>(object_elements, key_constant, result, nullptr, kind);
11313 : } else {
11314 : ElementsKind copy_kind =
11315 6506 : kind == FAST_HOLEY_SMI_ELEMENTS ? FAST_HOLEY_ELEMENTS : kind;
11316 : HInstruction* value_instruction =
11317 : Add<HLoadKeyed>(boilerplate_elements, key_constant, nullptr, nullptr,
11318 6506 : copy_kind, ALLOW_RETURN_HOLE);
11319 : Add<HStoreKeyed>(object_elements, key_constant, value_instruction,
11320 6506 : nullptr, copy_kind);
11321 : }
11322 : }
11323 1393 : }
11324 :
11325 :
11326 101666 : void HOptimizedGraphBuilder::VisitThisFunction(ThisFunction* expr) {
11327 : DCHECK(!HasStackOverflow());
11328 : DCHECK(current_block() != NULL);
11329 : DCHECK(current_block()->HasPredecessor());
11330 50833 : HInstruction* instr = BuildThisFunction();
11331 101666 : return ast_context()->ReturnInstruction(instr, expr->id());
11332 : }
11333 :
11334 :
11335 0 : void HOptimizedGraphBuilder::VisitSuperPropertyReference(
11336 : SuperPropertyReference* expr) {
11337 : DCHECK(!HasStackOverflow());
11338 : DCHECK(current_block() != NULL);
11339 : DCHECK(current_block()->HasPredecessor());
11340 0 : return Bailout(kSuperReference);
11341 : }
11342 :
11343 :
11344 0 : void HOptimizedGraphBuilder::VisitSuperCallReference(SuperCallReference* expr) {
11345 : DCHECK(!HasStackOverflow());
11346 : DCHECK(current_block() != NULL);
11347 : DCHECK(current_block()->HasPredecessor());
11348 0 : return Bailout(kSuperReference);
11349 : }
11350 :
11351 379788 : void HOptimizedGraphBuilder::VisitDeclarations(
11352 : Declaration::List* declarations) {
11353 : DCHECK(globals_.is_empty());
11354 : AstVisitor<HOptimizedGraphBuilder>::VisitDeclarations(declarations);
11355 934190 : if (!globals_.is_empty()) {
11356 : Handle<FixedArray> array =
11357 37290 : isolate()->factory()->NewFixedArray(globals_.length(), TENURED);
11358 1108804 : for (int i = 0; i < globals_.length(); ++i) array->set(i, *globals_.at(i));
11359 12430 : int flags = current_info()->GetDeclareGlobalsFlags();
11360 : Handle<FeedbackVector> vector(current_feedback_vector(), isolate());
11361 12430 : Add<HDeclareGlobals>(array, flags, vector);
11362 : globals_.Rewind(0);
11363 : }
11364 379788 : }
11365 :
11366 :
11367 433685 : void HOptimizedGraphBuilder::VisitVariableDeclaration(
11368 : VariableDeclaration* declaration) {
11369 433685 : VariableProxy* proxy = declaration->proxy();
11370 569342 : Variable* variable = proxy->var();
11371 433685 : switch (variable->location()) {
11372 : case VariableLocation::UNALLOCATED: {
11373 : DCHECK(!variable->binding_needs_init());
11374 808768 : globals_.Add(variable->name(), zone());
11375 : FeedbackSlot slot = proxy->VariableFeedbackSlot();
11376 : DCHECK(!slot.IsInvalid());
11377 108185 : globals_.Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
11378 108185 : globals_.Add(isolate()->factory()->undefined_value(), zone());
11379 108185 : globals_.Add(isolate()->factory()->undefined_value(), zone());
11380 : return;
11381 : }
11382 : case VariableLocation::PARAMETER:
11383 : case VariableLocation::LOCAL:
11384 290349 : if (variable->binding_needs_init()) {
11385 24001 : HValue* value = graph()->GetConstantHole();
11386 24001 : environment()->Bind(variable, value);
11387 : }
11388 : break;
11389 : case VariableLocation::CONTEXT:
11390 35151 : if (variable->binding_needs_init()) {
11391 27472 : HValue* value = graph()->GetConstantHole();
11392 : HValue* context = environment()->context();
11393 : HStoreContextSlot* store = Add<HStoreContextSlot>(
11394 27472 : context, variable->index(), HStoreContextSlot::kNoCheck, value);
11395 27472 : if (store->HasObservableSideEffects()) {
11396 27472 : Add<HSimulate>(proxy->id(), REMOVABLE_SIMULATE);
11397 : }
11398 : }
11399 : break;
11400 : case VariableLocation::LOOKUP:
11401 : return Bailout(kUnsupportedLookupSlotInDeclaration);
11402 : case VariableLocation::MODULE:
11403 0 : UNREACHABLE();
11404 : }
11405 : }
11406 :
11407 :
11408 34384 : void HOptimizedGraphBuilder::VisitFunctionDeclaration(
11409 68768 : FunctionDeclaration* declaration) {
11410 34384 : VariableProxy* proxy = declaration->proxy();
11411 64357 : Variable* variable = proxy->var();
11412 34384 : switch (variable->location()) {
11413 : case VariableLocation::UNALLOCATED: {
11414 198232 : globals_.Add(variable->name(), zone());
11415 : FeedbackSlot slot = proxy->VariableFeedbackSlot();
11416 : DCHECK(!slot.IsInvalid());
11417 27308 : globals_.Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
11418 :
11419 : // We need the slot where the literals array lives, too.
11420 : slot = declaration->fun()->LiteralFeedbackSlot();
11421 : DCHECK(!slot.IsInvalid());
11422 27308 : globals_.Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
11423 :
11424 : Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo(
11425 54616 : declaration->fun(), current_info()->script(), top_info());
11426 : // Check for stack-overflow exception.
11427 27308 : if (function.is_null()) return SetStackOverflow();
11428 27308 : globals_.Add(function, zone());
11429 27308 : return;
11430 : }
11431 : case VariableLocation::PARAMETER:
11432 : case VariableLocation::LOCAL: {
11433 13233 : CHECK_ALIVE(VisitForValue(declaration->fun()));
11434 : HValue* value = Pop();
11435 4411 : BindIfLive(variable, value);
11436 4411 : break;
11437 : }
11438 : case VariableLocation::CONTEXT: {
11439 7995 : CHECK_ALIVE(VisitForValue(declaration->fun()));
11440 : HValue* value = Pop();
11441 : HValue* context = environment()->context();
11442 : HStoreContextSlot* store = Add<HStoreContextSlot>(
11443 2665 : context, variable->index(), HStoreContextSlot::kNoCheck, value);
11444 2665 : if (store->HasObservableSideEffects()) {
11445 2665 : Add<HSimulate>(proxy->id(), REMOVABLE_SIMULATE);
11446 : }
11447 : break;
11448 : }
11449 : case VariableLocation::LOOKUP:
11450 : return Bailout(kUnsupportedLookupSlotInDeclaration);
11451 : case VariableLocation::MODULE:
11452 0 : UNREACHABLE();
11453 : }
11454 : }
11455 :
11456 :
11457 8 : void HOptimizedGraphBuilder::VisitRewritableExpression(
11458 8 : RewritableExpression* node) {
11459 8 : CHECK_ALIVE(Visit(node->expression()));
11460 : }
11461 :
11462 :
11463 : // Generators for inline runtime functions.
11464 : // Support for types.
11465 4866 : void HOptimizedGraphBuilder::GenerateIsSmi(CallRuntime* call) {
11466 : DCHECK(call->arguments()->length() == 1);
11467 3244 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11468 : HValue* value = Pop();
11469 1622 : HIsSmiAndBranch* result = New<HIsSmiAndBranch>(value);
11470 3244 : return ast_context()->ReturnControl(result, call->id());
11471 : }
11472 :
11473 :
11474 2748 : void HOptimizedGraphBuilder::GenerateIsJSReceiver(CallRuntime* call) {
11475 : DCHECK(call->arguments()->length() == 1);
11476 1832 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11477 : HValue* value = Pop();
11478 : HHasInstanceTypeAndBranch* result =
11479 : New<HHasInstanceTypeAndBranch>(value,
11480 : FIRST_JS_RECEIVER_TYPE,
11481 916 : LAST_JS_RECEIVER_TYPE);
11482 1832 : return ast_context()->ReturnControl(result, call->id());
11483 : }
11484 :
11485 2328 : void HOptimizedGraphBuilder::GenerateIsArray(CallRuntime* call) {
11486 : DCHECK(call->arguments()->length() == 1);
11487 1552 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11488 : HValue* value = Pop();
11489 : HHasInstanceTypeAndBranch* result =
11490 776 : New<HHasInstanceTypeAndBranch>(value, JS_ARRAY_TYPE);
11491 1552 : return ast_context()->ReturnControl(result, call->id());
11492 : }
11493 :
11494 :
11495 156 : void HOptimizedGraphBuilder::GenerateIsTypedArray(CallRuntime* call) {
11496 : DCHECK(call->arguments()->length() == 1);
11497 104 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11498 : HValue* value = Pop();
11499 : HHasInstanceTypeAndBranch* result =
11500 52 : New<HHasInstanceTypeAndBranch>(value, JS_TYPED_ARRAY_TYPE);
11501 104 : return ast_context()->ReturnControl(result, call->id());
11502 : }
11503 :
11504 :
11505 945 : void HOptimizedGraphBuilder::GenerateToInteger(CallRuntime* call) {
11506 : DCHECK_EQ(1, call->arguments()->length());
11507 945 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11508 : HValue* input = Pop();
11509 315 : if (input->type().IsSmi()) {
11510 0 : return ast_context()->ReturnValue(input);
11511 : } else {
11512 315 : Callable callable = CodeFactory::ToInteger(isolate());
11513 315 : HValue* stub = Add<HConstant>(callable.code());
11514 315 : HValue* values[] = {input};
11515 : HInstruction* result = New<HCallWithDescriptor>(
11516 315 : stub, 0, callable.descriptor(), ArrayVector(values));
11517 630 : return ast_context()->ReturnInstruction(result, call->id());
11518 : }
11519 : }
11520 :
11521 :
11522 1116 : void HOptimizedGraphBuilder::GenerateToObject(CallRuntime* call) {
11523 : DCHECK_EQ(1, call->arguments()->length());
11524 744 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11525 : HValue* value = Pop();
11526 372 : HValue* result = BuildToObject(value);
11527 372 : return ast_context()->ReturnValue(result);
11528 : }
11529 :
11530 :
11531 6408 : void HOptimizedGraphBuilder::GenerateToString(CallRuntime* call) {
11532 : DCHECK_EQ(1, call->arguments()->length());
11533 6355 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11534 : HValue* input = Pop();
11535 2136 : if (input->type().IsString()) {
11536 53 : return ast_context()->ReturnValue(input);
11537 : } else {
11538 2083 : Callable callable = CodeFactory::ToString(isolate());
11539 2083 : HValue* stub = Add<HConstant>(callable.code());
11540 2083 : HValue* values[] = {input};
11541 : HInstruction* result = New<HCallWithDescriptor>(
11542 2083 : stub, 0, callable.descriptor(), ArrayVector(values));
11543 4166 : return ast_context()->ReturnInstruction(result, call->id());
11544 : }
11545 : }
11546 :
11547 :
11548 1023 : void HOptimizedGraphBuilder::GenerateToLength(CallRuntime* call) {
11549 : DCHECK_EQ(1, call->arguments()->length());
11550 682 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11551 341 : Callable callable = CodeFactory::ToLength(isolate());
11552 : HValue* input = Pop();
11553 341 : HValue* stub = Add<HConstant>(callable.code());
11554 341 : HValue* values[] = {input};
11555 : HInstruction* result = New<HCallWithDescriptor>(
11556 341 : stub, 0, callable.descriptor(), ArrayVector(values));
11557 682 : return ast_context()->ReturnInstruction(result, call->id());
11558 : }
11559 :
11560 :
11561 420 : void HOptimizedGraphBuilder::GenerateToNumber(CallRuntime* call) {
11562 : DCHECK_EQ(1, call->arguments()->length());
11563 168 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11564 84 : Callable callable = CodeFactory::ToNumber(isolate());
11565 : HValue* input = Pop();
11566 84 : HValue* result = BuildToNumber(input);
11567 84 : if (result->HasObservableSideEffects()) {
11568 84 : if (!ast_context()->IsEffect()) Push(result);
11569 84 : Add<HSimulate>(call->id(), REMOVABLE_SIMULATE);
11570 84 : if (!ast_context()->IsEffect()) result = Pop();
11571 : }
11572 84 : return ast_context()->ReturnValue(result);
11573 : }
11574 :
11575 :
11576 2514 : void HOptimizedGraphBuilder::GenerateIsJSProxy(CallRuntime* call) {
11577 : DCHECK(call->arguments()->length() == 1);
11578 1676 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11579 : HValue* value = Pop();
11580 : HIfContinuation continuation;
11581 838 : IfBuilder if_proxy(this);
11582 :
11583 : HValue* smicheck = if_proxy.IfNot<HIsSmiAndBranch>(value);
11584 838 : if_proxy.And();
11585 838 : HValue* map = Add<HLoadNamedField>(value, smicheck, HObjectAccess::ForMap());
11586 : HValue* instance_type =
11587 838 : Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapInstanceType());
11588 : if_proxy.If<HCompareNumericAndBranch>(
11589 838 : instance_type, Add<HConstant>(JS_PROXY_TYPE), Token::EQ);
11590 :
11591 838 : if_proxy.CaptureContinuation(&continuation);
11592 1676 : return ast_context()->ReturnContinuation(&continuation, call->id());
11593 : }
11594 :
11595 :
11596 27 : void HOptimizedGraphBuilder::GenerateHasFastPackedElements(CallRuntime* call) {
11597 : DCHECK(call->arguments()->length() == 1);
11598 36 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11599 : HValue* object = Pop();
11600 : HIfContinuation continuation(graph()->CreateBasicBlock(),
11601 18 : graph()->CreateBasicBlock());
11602 9 : IfBuilder if_not_smi(this);
11603 : if_not_smi.IfNot<HIsSmiAndBranch>(object);
11604 9 : if_not_smi.Then();
11605 : {
11606 : NoObservableSideEffectsScope no_effects(this);
11607 :
11608 : IfBuilder if_fast_packed(this);
11609 9 : HValue* elements_kind = BuildGetElementsKind(object);
11610 : if_fast_packed.If<HCompareNumericAndBranch>(
11611 9 : elements_kind, Add<HConstant>(FAST_SMI_ELEMENTS), Token::EQ);
11612 9 : if_fast_packed.Or();
11613 : if_fast_packed.If<HCompareNumericAndBranch>(
11614 9 : elements_kind, Add<HConstant>(FAST_ELEMENTS), Token::EQ);
11615 9 : if_fast_packed.Or();
11616 : if_fast_packed.If<HCompareNumericAndBranch>(
11617 9 : elements_kind, Add<HConstant>(FAST_DOUBLE_ELEMENTS), Token::EQ);
11618 9 : if_fast_packed.JoinContinuation(&continuation);
11619 : }
11620 9 : if_not_smi.JoinContinuation(&continuation);
11621 18 : return ast_context()->ReturnContinuation(&continuation, call->id());
11622 : }
11623 :
11624 :
11625 : // Fast support for charCodeAt(n).
11626 600 : void HOptimizedGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) {
11627 : DCHECK(call->arguments()->length() == 2);
11628 360 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11629 360 : CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
11630 : HValue* index = Pop();
11631 : HValue* string = Pop();
11632 120 : HInstruction* result = BuildStringCharCodeAt(string, index);
11633 240 : return ast_context()->ReturnInstruction(result, call->id());
11634 : }
11635 :
11636 :
11637 : // Fast support for SubString.
11638 417 : void HOptimizedGraphBuilder::GenerateSubString(CallRuntime* call) {
11639 : DCHECK_EQ(3, call->arguments()->length());
11640 278 : CHECK_ALIVE(VisitExpressions(call->arguments()));
11641 139 : Callable callable = CodeFactory::SubString(isolate());
11642 139 : HValue* stub = Add<HConstant>(callable.code());
11643 : HValue* to = Pop();
11644 : HValue* from = Pop();
11645 : HValue* string = Pop();
11646 139 : HValue* values[] = {string, from, to};
11647 : HInstruction* result = New<HCallWithDescriptor>(
11648 139 : stub, 0, callable.descriptor(), ArrayVector(values));
11649 : result->set_type(HType::String());
11650 278 : return ast_context()->ReturnInstruction(result, call->id());
11651 : }
11652 :
11653 :
11654 : // Fast support for calls.
11655 35064 : void HOptimizedGraphBuilder::GenerateCall(CallRuntime* call) {
11656 : DCHECK_LE(2, call->arguments()->length());
11657 17532 : CHECK_ALIVE(VisitExpressions(call->arguments()));
11658 5844 : CallTrampolineDescriptor descriptor(isolate());
11659 5844 : PushArgumentsFromEnvironment(call->arguments()->length() - 1);
11660 5844 : HValue* trampoline = Add<HConstant>(isolate()->builtins()->Call());
11661 : HValue* target = Pop();
11662 11688 : HValue* values[] = {target, Add<HConstant>(call->arguments()->length() - 2)};
11663 : HInstruction* result =
11664 5844 : New<HCallWithDescriptor>(trampoline, call->arguments()->length() - 1,
11665 11688 : descriptor, ArrayVector(values));
11666 11688 : return ast_context()->ReturnInstruction(result, call->id());
11667 : }
11668 :
11669 :
11670 39425 : void HOptimizedGraphBuilder::GenerateFixedArrayGet(CallRuntime* call) {
11671 : DCHECK(call->arguments()->length() == 2);
11672 23655 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11673 23655 : CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
11674 : HValue* index = Pop();
11675 : HValue* object = Pop();
11676 : HInstruction* result = New<HLoadKeyed>(
11677 7885 : object, index, nullptr, nullptr, FAST_HOLEY_ELEMENTS, ALLOW_RETURN_HOLE);
11678 15770 : return ast_context()->ReturnInstruction(result, call->id());
11679 : }
11680 :
11681 :
11682 20104 : void HOptimizedGraphBuilder::GenerateFixedArraySet(CallRuntime* call) {
11683 : DCHECK(call->arguments()->length() == 3);
11684 14360 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11685 8616 : CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
11686 8616 : CHECK_ALIVE(VisitForValue(call->arguments()->at(2)));
11687 : HValue* value = Pop();
11688 : HValue* index = Pop();
11689 : HValue* object = Pop();
11690 2872 : NoObservableSideEffectsScope no_effects(this);
11691 2872 : Add<HStoreKeyed>(object, index, value, nullptr, FAST_HOLEY_ELEMENTS);
11692 5744 : return ast_context()->ReturnValue(graph()->GetConstantUndefined());
11693 : }
11694 :
11695 :
11696 420 : void HOptimizedGraphBuilder::GenerateTheHole(CallRuntime* call) {
11697 : DCHECK(call->arguments()->length() == 0);
11698 420 : return ast_context()->ReturnValue(graph()->GetConstantHole());
11699 : }
11700 :
11701 :
11702 45 : void HOptimizedGraphBuilder::GenerateCreateIterResultObject(CallRuntime* call) {
11703 : DCHECK_EQ(2, call->arguments()->length());
11704 27 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11705 27 : CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
11706 : HValue* done = Pop();
11707 : HValue* value = Pop();
11708 9 : HValue* result = BuildCreateIterResultObject(value, done);
11709 9 : return ast_context()->ReturnValue(result);
11710 : }
11711 :
11712 :
11713 4641 : void HOptimizedGraphBuilder::GenerateJSCollectionGetTable(CallRuntime* call) {
11714 : DCHECK(call->arguments()->length() == 1);
11715 3094 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11716 : HValue* receiver = Pop();
11717 : HInstruction* result = New<HLoadNamedField>(
11718 1547 : receiver, nullptr, HObjectAccess::ForJSCollectionTable());
11719 3094 : return ast_context()->ReturnInstruction(result, call->id());
11720 : }
11721 :
11722 :
11723 2454 : void HOptimizedGraphBuilder::GenerateStringGetRawHashField(CallRuntime* call) {
11724 : DCHECK(call->arguments()->length() == 1);
11725 1636 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11726 : HValue* object = Pop();
11727 : HInstruction* result = New<HLoadNamedField>(
11728 818 : object, nullptr, HObjectAccess::ForStringHashField());
11729 1636 : return ast_context()->ReturnInstruction(result, call->id());
11730 : }
11731 :
11732 :
11733 : template <typename CollectionType>
11734 3 : HValue* HOptimizedGraphBuilder::BuildAllocateOrderedHashTable() {
11735 : static const int kCapacity = CollectionType::kMinCapacity;
11736 : static const int kBucketCount = kCapacity / CollectionType::kLoadFactor;
11737 : static const int kFixedArrayLength = CollectionType::kHashTableStartIndex +
11738 : kBucketCount +
11739 : (kCapacity * CollectionType::kEntrySize);
11740 : static const int kSizeInBytes =
11741 : FixedArray::kHeaderSize + (kFixedArrayLength * kPointerSize);
11742 :
11743 : // Allocate the table and add the proper map.
11744 : HValue* table =
11745 : Add<HAllocate>(Add<HConstant>(kSizeInBytes), HType::HeapObject(),
11746 15 : NOT_TENURED, FIXED_ARRAY_TYPE, graph()->GetConstant0());
11747 3 : AddStoreMapConstant(table, isolate()->factory()->ordered_hash_table_map());
11748 :
11749 : // Initialize the FixedArray...
11750 3 : HValue* length = Add<HConstant>(kFixedArrayLength);
11751 3 : Add<HStoreNamedField>(table, HObjectAccess::ForFixedArrayLength(), length);
11752 :
11753 : // ...and the OrderedHashTable fields.
11754 3 : Add<HStoreNamedField>(
11755 : table,
11756 : HObjectAccess::ForOrderedHashTableNumberOfBuckets<CollectionType>(),
11757 : Add<HConstant>(kBucketCount));
11758 3 : Add<HStoreNamedField>(
11759 : table,
11760 : HObjectAccess::ForOrderedHashTableNumberOfElements<CollectionType>(),
11761 : graph()->GetConstant0());
11762 3 : Add<HStoreNamedField>(
11763 : table, HObjectAccess::ForOrderedHashTableNumberOfDeletedElements<
11764 : CollectionType>(),
11765 : graph()->GetConstant0());
11766 :
11767 : // Fill the buckets with kNotFound.
11768 3 : HValue* not_found = Add<HConstant>(CollectionType::kNotFound);
11769 9 : for (int i = 0; i < kBucketCount; ++i) {
11770 6 : Add<HStoreNamedField>(
11771 : table, HObjectAccess::ForOrderedHashTableBucket<CollectionType>(i),
11772 : not_found);
11773 : }
11774 :
11775 : // Fill the data table with undefined.
11776 3 : HValue* undefined = graph()->GetConstantUndefined();
11777 31 : for (int i = 0; i < (kCapacity * CollectionType::kEntrySize); ++i) {
11778 28 : Add<HStoreNamedField>(table,
11779 : HObjectAccess::ForOrderedHashTableDataTableIndex<
11780 : CollectionType, kBucketCount>(i),
11781 : undefined);
11782 : }
11783 :
11784 3 : return table;
11785 : }
11786 :
11787 :
11788 0 : void HOptimizedGraphBuilder::GenerateSetInitialize(CallRuntime* call) {
11789 : DCHECK(call->arguments()->length() == 1);
11790 0 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11791 : HValue* receiver = Pop();
11792 :
11793 0 : NoObservableSideEffectsScope no_effects(this);
11794 0 : HValue* table = BuildAllocateOrderedHashTable<OrderedHashSet>();
11795 0 : Add<HStoreNamedField>(receiver, HObjectAccess::ForJSCollectionTable(), table);
11796 0 : return ast_context()->ReturnValue(receiver);
11797 : }
11798 :
11799 :
11800 0 : void HOptimizedGraphBuilder::GenerateMapInitialize(CallRuntime* call) {
11801 : DCHECK(call->arguments()->length() == 1);
11802 0 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11803 : HValue* receiver = Pop();
11804 :
11805 0 : NoObservableSideEffectsScope no_effects(this);
11806 0 : HValue* table = BuildAllocateOrderedHashTable<OrderedHashMap>();
11807 0 : Add<HStoreNamedField>(receiver, HObjectAccess::ForJSCollectionTable(), table);
11808 0 : return ast_context()->ReturnValue(receiver);
11809 : }
11810 :
11811 :
11812 : template <typename CollectionType>
11813 3 : void HOptimizedGraphBuilder::BuildOrderedHashTableClear(HValue* receiver) {
11814 : HValue* old_table = Add<HLoadNamedField>(
11815 3 : receiver, nullptr, HObjectAccess::ForJSCollectionTable());
11816 3 : HValue* new_table = BuildAllocateOrderedHashTable<CollectionType>();
11817 3 : Add<HStoreNamedField>(
11818 : old_table, HObjectAccess::ForOrderedHashTableNextTable<CollectionType>(),
11819 : new_table);
11820 3 : Add<HStoreNamedField>(
11821 : old_table, HObjectAccess::ForOrderedHashTableNumberOfDeletedElements<
11822 : CollectionType>(),
11823 : Add<HConstant>(CollectionType::kClearedTableSentinel));
11824 3 : Add<HStoreNamedField>(receiver, HObjectAccess::ForJSCollectionTable(),
11825 3 : new_table);
11826 3 : }
11827 :
11828 :
11829 6 : void HOptimizedGraphBuilder::GenerateSetClear(CallRuntime* call) {
11830 : DCHECK(call->arguments()->length() == 1);
11831 6 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11832 : HValue* receiver = Pop();
11833 :
11834 2 : NoObservableSideEffectsScope no_effects(this);
11835 2 : BuildOrderedHashTableClear<OrderedHashSet>(receiver);
11836 4 : return ast_context()->ReturnValue(graph()->GetConstantUndefined());
11837 : }
11838 :
11839 :
11840 3 : void HOptimizedGraphBuilder::GenerateMapClear(CallRuntime* call) {
11841 : DCHECK(call->arguments()->length() == 1);
11842 3 : CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11843 : HValue* receiver = Pop();
11844 :
11845 1 : NoObservableSideEffectsScope no_effects(this);
11846 1 : BuildOrderedHashTableClear<OrderedHashMap>(receiver);
11847 2 : return ast_context()->ReturnValue(graph()->GetConstantUndefined());
11848 : }
11849 :
11850 0 : void HOptimizedGraphBuilder::GenerateDebugBreakInOptimizedCode(
11851 0 : CallRuntime* call) {
11852 0 : Add<HDebugBreak>();
11853 0 : return ast_context()->ReturnValue(graph()->GetConstant0());
11854 : }
11855 :
11856 :
11857 0 : void HOptimizedGraphBuilder::GenerateDebugIsActive(CallRuntime* call) {
11858 : DCHECK(call->arguments()->length() == 0);
11859 : HValue* ref =
11860 0 : Add<HConstant>(ExternalReference::debug_is_active_address(isolate()));
11861 : HValue* value =
11862 0 : Add<HLoadNamedField>(ref, nullptr, HObjectAccess::ForExternalUInteger8());
11863 0 : return ast_context()->ReturnValue(value);
11864 : }
11865 :
11866 : #undef CHECK_BAILOUT
11867 : #undef CHECK_ALIVE
11868 :
11869 :
11870 478002 : HEnvironment::HEnvironment(HEnvironment* outer,
11871 : Scope* scope,
11872 : Handle<JSFunction> closure,
11873 : Zone* zone)
11874 : : closure_(closure),
11875 : values_(0, zone),
11876 : frame_type_(JS_FUNCTION),
11877 : parameter_count_(0),
11878 : specials_count_(1),
11879 : local_count_(0),
11880 : outer_(outer),
11881 : entry_(NULL),
11882 : pop_count_(0),
11883 : push_count_(0),
11884 : ast_id_(BailoutId::None()),
11885 956004 : zone_(zone) {
11886 478002 : DeclarationScope* declaration_scope = scope->GetDeclarationScope();
11887 : Initialize(declaration_scope->num_parameters() + 1,
11888 956004 : declaration_scope->num_stack_slots(), 0);
11889 478002 : }
11890 :
11891 :
11892 23533 : HEnvironment::HEnvironment(Zone* zone, int parameter_count)
11893 : : values_(0, zone),
11894 : frame_type_(STUB),
11895 : parameter_count_(parameter_count),
11896 : specials_count_(1),
11897 : local_count_(0),
11898 : outer_(NULL),
11899 : entry_(NULL),
11900 : pop_count_(0),
11901 : push_count_(0),
11902 : ast_id_(BailoutId::None()),
11903 47066 : zone_(zone) {
11904 23533 : Initialize(parameter_count, 0, 0);
11905 23533 : }
11906 :
11907 :
11908 13939000 : HEnvironment::HEnvironment(const HEnvironment* other, Zone* zone)
11909 : : values_(0, zone),
11910 : frame_type_(JS_FUNCTION),
11911 : parameter_count_(0),
11912 : specials_count_(0),
11913 : local_count_(0),
11914 : outer_(NULL),
11915 : entry_(NULL),
11916 : pop_count_(0),
11917 : push_count_(0),
11918 : ast_id_(other->ast_id()),
11919 27877684 : zone_(zone) {
11920 13938684 : Initialize(other);
11921 13939472 : }
11922 :
11923 :
11924 0 : HEnvironment::HEnvironment(HEnvironment* outer,
11925 : Handle<JSFunction> closure,
11926 : FrameType frame_type,
11927 : int arguments,
11928 : Zone* zone)
11929 : : closure_(closure),
11930 : values_(arguments, zone),
11931 : frame_type_(frame_type),
11932 : parameter_count_(arguments),
11933 : specials_count_(0),
11934 : local_count_(0),
11935 : outer_(outer),
11936 : entry_(NULL),
11937 : pop_count_(0),
11938 : push_count_(0),
11939 : ast_id_(BailoutId::None()),
11940 152612 : zone_(zone) {
11941 0 : }
11942 :
11943 :
11944 501535 : void HEnvironment::Initialize(int parameter_count,
11945 : int local_count,
11946 2763503 : int stack_height) {
11947 501535 : parameter_count_ = parameter_count;
11948 501535 : local_count_ = local_count;
11949 :
11950 : // Avoid reallocating the temporaries' backing store on the first Push.
11951 501535 : int total = parameter_count + specials_count_ + local_count + stack_height;
11952 501535 : values_.Initialize(total + 4, zone());
11953 2763503 : for (int i = 0; i < total; ++i) values_.Add(NULL, zone());
11954 501535 : }
11955 :
11956 :
11957 41817158 : void HEnvironment::Initialize(const HEnvironment* other) {
11958 13939086 : closure_ = other->closure();
11959 : values_.AddAll(other->values_, zone());
11960 13938986 : assigned_variables_.Union(other->assigned_variables_, zone());
11961 13939158 : frame_type_ = other->frame_type_;
11962 13939158 : parameter_count_ = other->parameter_count_;
11963 13939158 : local_count_ = other->local_count_;
11964 13939158 : if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy.
11965 13939263 : entry_ = other->entry_;
11966 13939263 : pop_count_ = other->pop_count_;
11967 13939263 : push_count_ = other->push_count_;
11968 13939263 : specials_count_ = other->specials_count_;
11969 13939263 : ast_id_ = other->ast_id_;
11970 13939263 : }
11971 :
11972 :
11973 852983 : void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) {
11974 : DCHECK(!block->IsLoopHeader());
11975 : DCHECK(values_.length() == other->values_.length());
11976 :
11977 13080993 : int length = values_.length();
11978 6735226 : for (int i = 0; i < length; ++i) {
11979 6841880 : HValue* value = values_[i];
11980 12724123 : if (value != NULL && value->IsPhi() && value->block() == block) {
11981 : // There is already a phi for the i'th value.
11982 : HPhi* phi = HPhi::cast(value);
11983 : // Assert index is correct and that we haven't missed an incoming edge.
11984 : DCHECK(phi->merged_index() == i || !phi->HasMergedIndex());
11985 : DCHECK(phi->OperandCount() == block->predecessors()->length());
11986 6136460 : phi->AddInput(other->values_[i]);
11987 11734546 : } else if (values_[i] != other->values_[i]) {
11988 : // There is a fresh value on the incoming edge, a phi is needed.
11989 : DCHECK(values_[i] != NULL && other->values_[i] != NULL);
11990 239247 : HPhi* phi = block->AddNewPhi(i);
11991 239247 : HValue* old_value = values_[i];
11992 479231 : for (int j = 0; j < block->predecessors()->length(); j++) {
11993 239984 : phi->AddInput(old_value);
11994 : }
11995 239247 : phi->AddInput(other->values_[i]);
11996 239247 : this->values_[i] = phi;
11997 : }
11998 : }
11999 852983 : }
12000 :
12001 :
12002 3423234 : void HEnvironment::Bind(int index, HValue* value) {
12003 : DCHECK(value != NULL);
12004 3423234 : assigned_variables_.Add(index, zone());
12005 6846464 : values_[index] = value;
12006 1462762 : }
12007 :
12008 :
12009 0 : bool HEnvironment::HasExpressionAt(int index) const {
12010 0 : return index >= parameter_count_ + specials_count_ + local_count_;
12011 : }
12012 :
12013 :
12014 0 : bool HEnvironment::ExpressionStackIsEmpty() const {
12015 : DCHECK(length() >= first_expression_index());
12016 0 : return length() == first_expression_index();
12017 : }
12018 :
12019 :
12020 0 : void HEnvironment::SetExpressionStackAt(int index_from_top, HValue* value) {
12021 0 : int count = index_from_top + 1;
12022 844748 : int index = values_.length() - count;
12023 : DCHECK(HasExpressionAt(index));
12024 : // The push count must include at least the element in question or else
12025 : // the new value will not be included in this environment's history.
12026 422374 : if (push_count_ < count) {
12027 : // This is the same effect as popping then re-pushing 'count' elements.
12028 168340 : pop_count_ += (count - push_count_);
12029 168340 : push_count_ = count;
12030 : }
12031 422374 : values_[index] = value;
12032 0 : }
12033 :
12034 :
12035 5293 : HValue* HEnvironment::RemoveExpressionStackAt(int index_from_top) {
12036 5293 : int count = index_from_top + 1;
12037 5293 : int index = values_.length() - count;
12038 : DCHECK(HasExpressionAt(index));
12039 : // Simulate popping 'count' elements and then
12040 : // pushing 'count - 1' elements back.
12041 10586 : pop_count_ += Max(count - push_count_, 0);
12042 10586 : push_count_ = Max(push_count_ - count, 0) + (count - 1);
12043 5293 : return values_.Remove(index);
12044 : }
12045 :
12046 :
12047 4740099 : void HEnvironment::Drop(int count) {
12048 10197941 : for (int i = 0; i < count; ++i) {
12049 5457840 : Pop();
12050 : }
12051 4740101 : }
12052 :
12053 :
12054 0 : void HEnvironment::Print() const {
12055 0 : OFStream os(stdout);
12056 0 : os << *this << "\n";
12057 0 : }
12058 :
12059 :
12060 13938933 : HEnvironment* HEnvironment::Copy() const {
12061 13938976 : return new(zone()) HEnvironment(this, zone());
12062 : }
12063 :
12064 :
12065 527826 : HEnvironment* HEnvironment::CopyWithoutHistory() const {
12066 527826 : HEnvironment* result = Copy();
12067 : result->ClearHistory();
12068 527826 : return result;
12069 : }
12070 :
12071 :
12072 61252 : HEnvironment* HEnvironment::CopyAsLoopHeader(HBasicBlock* loop_header) const {
12073 61252 : HEnvironment* new_env = Copy();
12074 974018 : for (int i = 0; i < values_.length(); ++i) {
12075 425757 : HPhi* phi = loop_header->AddNewPhi(i);
12076 1338523 : phi->AddInput(values_[i]);
12077 851514 : new_env->values_[i] = phi;
12078 : }
12079 : new_env->ClearHistory();
12080 61252 : return new_env;
12081 : }
12082 :
12083 :
12084 76306 : HEnvironment* HEnvironment::CreateStubEnvironment(HEnvironment* outer,
12085 : Handle<JSFunction> target,
12086 : FrameType frame_type,
12087 76306 : int arguments) const {
12088 : HEnvironment* new_env =
12089 : new(zone()) HEnvironment(outer, target, frame_type,
12090 152612 : arguments + 1, zone());
12091 281316 : for (int i = 0; i <= arguments; ++i) { // Include receiver.
12092 205010 : new_env->Push(ExpressionStackAt(arguments - i));
12093 : }
12094 : new_env->ClearHistory();
12095 76306 : return new_env;
12096 : }
12097 :
12098 0 : void HEnvironment::MarkAsTailCaller() {
12099 : DCHECK_EQ(JS_FUNCTION, frame_type());
12100 334 : frame_type_ = TAIL_CALLER_FUNCTION;
12101 0 : }
12102 :
12103 179 : void HEnvironment::ClearTailCallerMark() {
12104 : DCHECK_EQ(TAIL_CALLER_FUNCTION, frame_type());
12105 368 : frame_type_ = JS_FUNCTION;
12106 179 : }
12107 :
12108 214089 : HEnvironment* HEnvironment::CopyForInlining(
12109 428178 : Handle<JSFunction> target, int arguments, FunctionLiteral* function,
12110 : HConstant* undefined, InliningKind inlining_kind,
12111 214089 : TailCallMode syntactic_tail_call_mode) const {
12112 : DCHECK_EQ(JS_FUNCTION, frame_type());
12113 :
12114 : // Outer environment is a copy of this one without the arguments.
12115 : int arity = function->scope()->num_parameters();
12116 :
12117 214089 : HEnvironment* outer = Copy();
12118 : outer->Drop(arguments + 1); // Including receiver.
12119 : outer->ClearHistory();
12120 :
12121 214089 : if (syntactic_tail_call_mode == TailCallMode::kAllow) {
12122 : DCHECK_EQ(NORMAL_RETURN, inlining_kind);
12123 : outer->MarkAsTailCaller();
12124 : }
12125 :
12126 214089 : if (inlining_kind == CONSTRUCT_CALL_RETURN) {
12127 : // Create artificial constructor stub environment. The receiver should
12128 : // actually be the constructor function, but we pass the newly allocated
12129 : // object instead, DoComputeConstructStubFrame() relies on that.
12130 2190 : outer = CreateStubEnvironment(outer, target, JS_CONSTRUCT, arguments);
12131 211899 : } else if (inlining_kind == GETTER_CALL_RETURN) {
12132 : // We need an additional StackFrame::INTERNAL frame for restoring the
12133 : // correct context.
12134 3617 : outer = CreateStubEnvironment(outer, target, JS_GETTER, arguments);
12135 208282 : } else if (inlining_kind == SETTER_CALL_RETURN) {
12136 : // We need an additional StackFrame::INTERNAL frame for temporarily saving
12137 : // the argument of the setter, see StoreStubCompiler::CompileStoreViaSetter.
12138 394 : outer = CreateStubEnvironment(outer, target, JS_SETTER, arguments);
12139 : }
12140 :
12141 214089 : if (arity != arguments) {
12142 : // Create artificial arguments adaptation environment.
12143 70105 : outer = CreateStubEnvironment(outer, target, ARGUMENTS_ADAPTOR, arguments);
12144 : }
12145 :
12146 : HEnvironment* inner =
12147 428178 : new(zone()) HEnvironment(outer, function->scope(), target, zone());
12148 : // Get the argument values from the original environment.
12149 878588 : for (int i = 0; i <= arity; ++i) { // Include receiver.
12150 : HValue* push = (i <= arguments) ?
12151 664499 : ExpressionStackAt(arguments - i) : undefined;
12152 : inner->SetValueAt(i, push);
12153 : }
12154 214089 : inner->SetValueAt(arity + 1, context());
12155 975604 : for (int i = arity + 2; i < inner->length(); ++i) {
12156 : inner->SetValueAt(i, undefined);
12157 : }
12158 :
12159 : inner->set_ast_id(BailoutId::FunctionEntry());
12160 214089 : return inner;
12161 : }
12162 :
12163 :
12164 0 : std::ostream& operator<<(std::ostream& os, const HEnvironment& env) {
12165 0 : for (int i = 0; i < env.length(); i++) {
12166 0 : if (i == 0) os << "parameters\n";
12167 0 : if (i == env.parameter_count()) os << "specials\n";
12168 0 : if (i == env.parameter_count() + env.specials_count()) os << "locals\n";
12169 0 : if (i == env.parameter_count() + env.specials_count() + env.local_count()) {
12170 0 : os << "expressions\n";
12171 : }
12172 0 : HValue* val = env.values()->at(i);
12173 0 : os << i << ": ";
12174 0 : if (val != NULL) {
12175 : os << val;
12176 : } else {
12177 0 : os << "NULL";
12178 : }
12179 0 : os << "\n";
12180 : }
12181 0 : return os << "\n";
12182 : }
12183 :
12184 :
12185 0 : void HTracer::TraceCompilation(CompilationInfo* info) {
12186 0 : Tag tag(this, "compilation");
12187 : std::string name;
12188 0 : if (info->parse_info()) {
12189 0 : Object* source_name = info->script()->name();
12190 0 : if (source_name->IsString()) {
12191 : String* str = String::cast(source_name);
12192 0 : if (str->length() > 0) {
12193 0 : name.append(str->ToCString().get());
12194 0 : name.append(":");
12195 : }
12196 : }
12197 : }
12198 0 : std::unique_ptr<char[]> method_name = info->GetDebugName();
12199 0 : name.append(method_name.get());
12200 0 : if (info->IsOptimizing()) {
12201 0 : PrintStringProperty("name", name.c_str());
12202 : PrintIndent();
12203 : trace_.Add("method \"%s:%d\"\n", method_name.get(),
12204 0 : info->optimization_id());
12205 : } else {
12206 0 : PrintStringProperty("name", name.c_str());
12207 0 : PrintStringProperty("method", "stub");
12208 : }
12209 : PrintLongProperty("date",
12210 0 : static_cast<int64_t>(base::OS::TimeCurrentMillis()));
12211 0 : }
12212 :
12213 :
12214 0 : void HTracer::TraceLithium(const char* name, LChunk* chunk) {
12215 : DCHECK(!chunk->isolate()->concurrent_recompilation_enabled());
12216 : AllowHandleDereference allow_deref;
12217 : AllowDeferredHandleDereference allow_deferred_deref;
12218 0 : Trace(name, chunk->graph(), chunk);
12219 0 : }
12220 :
12221 :
12222 0 : void HTracer::TraceHydrogen(const char* name, HGraph* graph) {
12223 : DCHECK(!graph->isolate()->concurrent_recompilation_enabled());
12224 : AllowHandleDereference allow_deref;
12225 : AllowDeferredHandleDereference allow_deferred_deref;
12226 0 : Trace(name, graph, NULL);
12227 0 : }
12228 :
12229 :
12230 0 : void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) {
12231 0 : Tag tag(this, "cfg");
12232 0 : PrintStringProperty("name", name);
12233 : const ZoneList<HBasicBlock*>* blocks = graph->blocks();
12234 0 : for (int i = 0; i < blocks->length(); i++) {
12235 0 : HBasicBlock* current = blocks->at(i);
12236 0 : Tag block_tag(this, "block");
12237 0 : PrintBlockProperty("name", current->block_id());
12238 0 : PrintIntProperty("from_bci", -1);
12239 0 : PrintIntProperty("to_bci", -1);
12240 :
12241 0 : if (!current->predecessors()->is_empty()) {
12242 : PrintIndent();
12243 0 : trace_.Add("predecessors");
12244 0 : for (int j = 0; j < current->predecessors()->length(); ++j) {
12245 0 : trace_.Add(" \"B%d\"", current->predecessors()->at(j)->block_id());
12246 : }
12247 0 : trace_.Add("\n");
12248 : } else {
12249 0 : PrintEmptyProperty("predecessors");
12250 : }
12251 :
12252 0 : if (current->end()->SuccessorCount() == 0) {
12253 0 : PrintEmptyProperty("successors");
12254 : } else {
12255 : PrintIndent();
12256 0 : trace_.Add("successors");
12257 0 : for (HSuccessorIterator it(current->end()); !it.Done(); it.Advance()) {
12258 0 : trace_.Add(" \"B%d\"", it.Current()->block_id());
12259 : }
12260 0 : trace_.Add("\n");
12261 : }
12262 :
12263 0 : PrintEmptyProperty("xhandlers");
12264 :
12265 : {
12266 : PrintIndent();
12267 0 : trace_.Add("flags");
12268 0 : if (current->IsLoopSuccessorDominator()) {
12269 0 : trace_.Add(" \"dom-loop-succ\"");
12270 : }
12271 0 : if (current->IsUnreachable()) {
12272 0 : trace_.Add(" \"dead\"");
12273 : }
12274 0 : if (current->is_osr_entry()) {
12275 0 : trace_.Add(" \"osr\"");
12276 : }
12277 0 : trace_.Add("\n");
12278 : }
12279 :
12280 0 : if (current->dominator() != NULL) {
12281 0 : PrintBlockProperty("dominator", current->dominator()->block_id());
12282 : }
12283 :
12284 0 : PrintIntProperty("loop_depth", current->LoopNestingDepth());
12285 :
12286 0 : if (chunk != NULL) {
12287 : int first_index = current->first_instruction_index();
12288 : int last_index = current->last_instruction_index();
12289 : PrintIntProperty(
12290 : "first_lir_id",
12291 0 : LifetimePosition::FromInstructionIndex(first_index).Value());
12292 : PrintIntProperty(
12293 : "last_lir_id",
12294 0 : LifetimePosition::FromInstructionIndex(last_index).Value());
12295 : }
12296 :
12297 : {
12298 0 : Tag states_tag(this, "states");
12299 0 : Tag locals_tag(this, "locals");
12300 0 : int total = current->phis()->length();
12301 0 : PrintIntProperty("size", current->phis()->length());
12302 0 : PrintStringProperty("method", "None");
12303 0 : for (int j = 0; j < total; ++j) {
12304 0 : HPhi* phi = current->phis()->at(j);
12305 : PrintIndent();
12306 0 : std::ostringstream os;
12307 0 : os << phi->merged_index() << " " << NameOf(phi) << " " << *phi << "\n";
12308 0 : trace_.Add(os.str().c_str());
12309 0 : }
12310 : }
12311 :
12312 : {
12313 0 : Tag HIR_tag(this, "HIR");
12314 0 : for (HInstructionIterator it(current); !it.Done(); it.Advance()) {
12315 : HInstruction* instruction = it.Current();
12316 0 : int uses = instruction->UseCount();
12317 : PrintIndent();
12318 0 : std::ostringstream os;
12319 0 : os << "0 " << uses << " " << NameOf(instruction) << " " << *instruction;
12320 0 : if (instruction->has_position()) {
12321 0 : const SourcePosition pos = instruction->position();
12322 0 : os << " pos:";
12323 0 : if (pos.isInlined()) os << "inlining(" << pos.InliningId() << "),";
12324 0 : os << pos.ScriptOffset();
12325 : }
12326 0 : os << " <|@\n";
12327 0 : trace_.Add(os.str().c_str());
12328 0 : }
12329 : }
12330 :
12331 :
12332 0 : if (chunk != NULL) {
12333 0 : Tag LIR_tag(this, "LIR");
12334 : int first_index = current->first_instruction_index();
12335 : int last_index = current->last_instruction_index();
12336 0 : if (first_index != -1 && last_index != -1) {
12337 : const ZoneList<LInstruction*>* instructions = chunk->instructions();
12338 0 : for (int i = first_index; i <= last_index; ++i) {
12339 0 : LInstruction* linstr = instructions->at(i);
12340 0 : if (linstr != NULL) {
12341 : PrintIndent();
12342 : trace_.Add("%d ",
12343 0 : LifetimePosition::FromInstructionIndex(i).Value());
12344 0 : linstr->PrintTo(&trace_);
12345 0 : std::ostringstream os;
12346 0 : os << " [hir:" << NameOf(linstr->hydrogen_value()) << "] <|@\n";
12347 0 : trace_.Add(os.str().c_str());
12348 : }
12349 : }
12350 0 : }
12351 : }
12352 0 : }
12353 0 : }
12354 :
12355 :
12356 0 : void HTracer::TraceLiveRanges(const char* name, LAllocator* allocator) {
12357 0 : Tag tag(this, "intervals");
12358 0 : PrintStringProperty("name", name);
12359 :
12360 0 : const Vector<LiveRange*>* fixed_d = allocator->fixed_double_live_ranges();
12361 0 : for (int i = 0; i < fixed_d->length(); ++i) {
12362 0 : TraceLiveRange(fixed_d->at(i), "fixed", allocator->zone());
12363 : }
12364 :
12365 0 : const Vector<LiveRange*>* fixed = allocator->fixed_live_ranges();
12366 0 : for (int i = 0; i < fixed->length(); ++i) {
12367 0 : TraceLiveRange(fixed->at(i), "fixed", allocator->zone());
12368 : }
12369 :
12370 : const ZoneList<LiveRange*>* live_ranges = allocator->live_ranges();
12371 0 : for (int i = 0; i < live_ranges->length(); ++i) {
12372 0 : TraceLiveRange(live_ranges->at(i), "object", allocator->zone());
12373 0 : }
12374 0 : }
12375 :
12376 :
12377 0 : void HTracer::TraceLiveRange(LiveRange* range, const char* type,
12378 : Zone* zone) {
12379 0 : if (range != NULL && !range->IsEmpty()) {
12380 : PrintIndent();
12381 0 : trace_.Add("%d %s", range->id(), type);
12382 0 : if (range->HasRegisterAssigned()) {
12383 0 : LOperand* op = range->CreateAssignedOperand(zone);
12384 : int assigned_reg = op->index();
12385 0 : if (op->IsDoubleRegister()) {
12386 : trace_.Add(" \"%s\"",
12387 0 : GetRegConfig()->GetDoubleRegisterName(assigned_reg));
12388 : } else {
12389 : DCHECK(op->IsRegister());
12390 : trace_.Add(" \"%s\"",
12391 0 : GetRegConfig()->GetGeneralRegisterName(assigned_reg));
12392 : }
12393 0 : } else if (range->IsSpilled()) {
12394 0 : LOperand* op = range->TopLevel()->GetSpillOperand();
12395 0 : if (op->IsDoubleStackSlot()) {
12396 0 : trace_.Add(" \"double_stack:%d\"", op->index());
12397 : } else {
12398 : DCHECK(op->IsStackSlot());
12399 0 : trace_.Add(" \"stack:%d\"", op->index());
12400 : }
12401 : }
12402 : int parent_index = -1;
12403 0 : if (range->IsChild()) {
12404 0 : parent_index = range->parent()->id();
12405 : } else {
12406 : parent_index = range->id();
12407 : }
12408 0 : LOperand* op = range->FirstHint();
12409 : int hint_index = -1;
12410 0 : if (op != NULL && op->IsUnallocated()) {
12411 : hint_index = LUnallocated::cast(op)->virtual_register();
12412 : }
12413 0 : trace_.Add(" %d %d", parent_index, hint_index);
12414 0 : UseInterval* cur_interval = range->first_interval();
12415 0 : while (cur_interval != NULL && range->Covers(cur_interval->start())) {
12416 : trace_.Add(" [%d, %d[",
12417 : cur_interval->start().Value(),
12418 0 : cur_interval->end().Value());
12419 : cur_interval = cur_interval->next();
12420 : }
12421 :
12422 0 : UsePosition* current_pos = range->first_pos();
12423 0 : while (current_pos != NULL) {
12424 0 : if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) {
12425 0 : trace_.Add(" %d M", current_pos->pos().Value());
12426 : }
12427 : current_pos = current_pos->next();
12428 : }
12429 :
12430 0 : trace_.Add(" \"\"\n");
12431 : }
12432 0 : }
12433 :
12434 :
12435 0 : void HTracer::FlushToFile() {
12436 0 : AppendChars(filename_.start(), trace_.ToCString().get(), trace_.length(),
12437 0 : false);
12438 : trace_.Reset();
12439 0 : }
12440 :
12441 :
12442 0 : void HStatistics::Initialize(CompilationInfo* info) {
12443 0 : if (!info->has_shared_info()) return;
12444 0 : source_size_ += info->shared_info()->SourceSize();
12445 : }
12446 :
12447 :
12448 0 : void HStatistics::Print() {
12449 : PrintF(
12450 : "\n"
12451 : "----------------------------------------"
12452 : "----------------------------------------\n"
12453 : "--- Hydrogen timing results:\n"
12454 : "----------------------------------------"
12455 0 : "----------------------------------------\n");
12456 : base::TimeDelta sum;
12457 0 : for (int i = 0; i < times_.length(); ++i) {
12458 0 : sum += times_[i];
12459 : }
12460 :
12461 0 : for (int i = 0; i < names_.length(); ++i) {
12462 0 : PrintF("%33s", names_[i]);
12463 0 : double ms = times_[i].InMillisecondsF();
12464 : double percent = times_[i].PercentOf(sum);
12465 0 : PrintF(" %8.3f ms / %4.1f %% ", ms, percent);
12466 :
12467 0 : size_t size = sizes_[i];
12468 0 : double size_percent = static_cast<double>(size) * 100 / total_size_;
12469 0 : PrintF(" %9zu bytes / %4.1f %%\n", size, size_percent);
12470 : }
12471 :
12472 : PrintF(
12473 : "----------------------------------------"
12474 0 : "----------------------------------------\n");
12475 0 : base::TimeDelta total = create_graph_ + optimize_graph_ + generate_code_;
12476 : PrintF("%33s %8.3f ms / %4.1f %% \n", "Create graph",
12477 0 : create_graph_.InMillisecondsF(), create_graph_.PercentOf(total));
12478 : PrintF("%33s %8.3f ms / %4.1f %% \n", "Optimize graph",
12479 0 : optimize_graph_.InMillisecondsF(), optimize_graph_.PercentOf(total));
12480 : PrintF("%33s %8.3f ms / %4.1f %% \n", "Generate and install code",
12481 0 : generate_code_.InMillisecondsF(), generate_code_.PercentOf(total));
12482 : PrintF(
12483 : "----------------------------------------"
12484 0 : "----------------------------------------\n");
12485 : PrintF("%33s %8.3f ms %9zu bytes\n", "Total",
12486 0 : total.InMillisecondsF(), total_size_);
12487 : PrintF("%33s (%.1f times slower than full code gen)\n", "",
12488 0 : total.TimesOf(full_code_gen_));
12489 :
12490 0 : double source_size_in_kb = static_cast<double>(source_size_) / 1024;
12491 : double normalized_time = source_size_in_kb > 0
12492 0 : ? total.InMillisecondsF() / source_size_in_kb
12493 0 : : 0;
12494 : double normalized_size_in_kb =
12495 : source_size_in_kb > 0
12496 0 : ? static_cast<double>(total_size_) / 1024 / source_size_in_kb
12497 0 : : 0;
12498 : PrintF("%33s %8.3f ms %7.3f kB allocated\n",
12499 0 : "Average per kB source", normalized_time, normalized_size_in_kb);
12500 0 : }
12501 :
12502 :
12503 0 : void HStatistics::SaveTiming(const char* name, base::TimeDelta time,
12504 : size_t size) {
12505 0 : total_size_ += size;
12506 0 : for (int i = 0; i < names_.length(); ++i) {
12507 0 : if (strcmp(names_[i], name) == 0) {
12508 0 : times_[i] += time;
12509 0 : sizes_[i] += size;
12510 0 : return;
12511 : }
12512 : }
12513 0 : names_.Add(name);
12514 0 : times_.Add(time);
12515 0 : sizes_.Add(size);
12516 : }
12517 :
12518 :
12519 11909755 : HPhase::~HPhase() {
12520 5954876 : if (ShouldProduceTraceOutput()) {
12521 0 : isolate()->GetHTracer()->TraceHydrogen(name(), graph_);
12522 : }
12523 :
12524 : #ifdef DEBUG
12525 : graph_->Verify(false); // No full verify.
12526 : #endif
12527 5954869 : }
12528 :
12529 : } // namespace internal
12530 : } // namespace v8
|