blob: a6843115bb27104727e5a926999433b295e0be01 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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.
Ben Murdochb0fe1622011-05-05 13:52:32 +01004
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#include "src/hydrogen.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +01006
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007#include <sstream>
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008
9#include "src/v8.h"
10
11#include "src/allocation-site-scopes.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012#include "src/ast-numbering.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013#include "src/full-codegen.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014#include "src/hydrogen-bce.h"
15#include "src/hydrogen-bch.h"
16#include "src/hydrogen-canonicalize.h"
17#include "src/hydrogen-check-elimination.h"
18#include "src/hydrogen-dce.h"
19#include "src/hydrogen-dehoist.h"
20#include "src/hydrogen-environment-liveness.h"
21#include "src/hydrogen-escape-analysis.h"
22#include "src/hydrogen-gvn.h"
23#include "src/hydrogen-infer-representation.h"
24#include "src/hydrogen-infer-types.h"
25#include "src/hydrogen-load-elimination.h"
26#include "src/hydrogen-mark-deoptimize.h"
27#include "src/hydrogen-mark-unreachable.h"
28#include "src/hydrogen-osr.h"
29#include "src/hydrogen-range-analysis.h"
30#include "src/hydrogen-redundant-phi.h"
31#include "src/hydrogen-removable-simulates.h"
32#include "src/hydrogen-representation-changes.h"
33#include "src/hydrogen-sce.h"
34#include "src/hydrogen-store-elimination.h"
35#include "src/hydrogen-uint32-analysis.h"
36#include "src/ic/call-optimization.h"
37#include "src/ic/ic.h"
38// GetRootConstructor
39#include "src/ic/ic-inl.h"
40#include "src/lithium-allocator.h"
41#include "src/parser.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040042#include "src/runtime/runtime.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000043#include "src/scopeinfo.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000044#include "src/typing.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010045
46#if V8_TARGET_ARCH_IA32
Ben Murdochb8a8cc12014-11-26 15:28:44 +000047#include "src/ia32/lithium-codegen-ia32.h" // NOLINT
Ben Murdochb0fe1622011-05-05 13:52:32 +010048#elif V8_TARGET_ARCH_X64
Ben Murdochb8a8cc12014-11-26 15:28:44 +000049#include "src/x64/lithium-codegen-x64.h" // NOLINT
50#elif V8_TARGET_ARCH_ARM64
51#include "src/arm64/lithium-codegen-arm64.h" // NOLINT
Ben Murdochb0fe1622011-05-05 13:52:32 +010052#elif V8_TARGET_ARCH_ARM
Ben Murdochb8a8cc12014-11-26 15:28:44 +000053#include "src/arm/lithium-codegen-arm.h" // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +010054#elif V8_TARGET_ARCH_MIPS
Ben Murdochb8a8cc12014-11-26 15:28:44 +000055#include "src/mips/lithium-codegen-mips.h" // NOLINT
56#elif V8_TARGET_ARCH_MIPS64
57#include "src/mips64/lithium-codegen-mips64.h" // NOLINT
58#elif V8_TARGET_ARCH_X87
59#include "src/x87/lithium-codegen-x87.h" // NOLINT
Ben Murdochb0fe1622011-05-05 13:52:32 +010060#else
61#error Unsupported target architecture.
62#endif
63
64namespace v8 {
65namespace internal {
66
67HBasicBlock::HBasicBlock(HGraph* graph)
68 : block_id_(graph->GetNextBlockID()),
69 graph_(graph),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000070 phis_(4, graph->zone()),
Ben Murdochb0fe1622011-05-05 13:52:32 +010071 first_(NULL),
72 last_(NULL),
73 end_(NULL),
74 loop_information_(NULL),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000075 predecessors_(2, graph->zone()),
Ben Murdochb0fe1622011-05-05 13:52:32 +010076 dominator_(NULL),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000077 dominated_blocks_(4, graph->zone()),
Ben Murdochb0fe1622011-05-05 13:52:32 +010078 last_environment_(NULL),
79 argument_count_(-1),
80 first_instruction_index_(-1),
81 last_instruction_index_(-1),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000082 deleted_phis_(4, graph->zone()),
Steve Block1e0659c2011-05-24 12:43:12 +010083 parent_loop_header_(NULL),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000084 inlined_entry_block_(NULL),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000085 is_inline_return_target_(false),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000086 is_reachable_(true),
87 dominates_loop_successors_(false),
88 is_osr_entry_(false),
89 is_ordered_(false) { }
90
91
92Isolate* HBasicBlock::isolate() const {
93 return graph_->isolate();
94}
95
96
97void HBasicBlock::MarkUnreachable() {
98 is_reachable_ = false;
99}
Ben Murdochb0fe1622011-05-05 13:52:32 +0100100
101
102void HBasicBlock::AttachLoopInformation() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000103 DCHECK(!IsLoopHeader());
104 loop_information_ = new(zone()) HLoopInformation(this, zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100105}
106
107
108void HBasicBlock::DetachLoopInformation() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000109 DCHECK(IsLoopHeader());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100110 loop_information_ = NULL;
111}
112
113
114void HBasicBlock::AddPhi(HPhi* phi) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000115 DCHECK(!IsStartBlock());
116 phis_.Add(phi, zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100117 phi->SetBlock(this);
118}
119
120
121void HBasicBlock::RemovePhi(HPhi* phi) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000122 DCHECK(phi->block() == this);
123 DCHECK(phis_.Contains(phi));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100124 phi->Kill();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100125 phis_.RemoveElement(phi);
126 phi->SetBlock(NULL);
127}
128
129
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000130void HBasicBlock::AddInstruction(HInstruction* instr,
131 HSourcePosition position) {
132 DCHECK(!IsStartBlock() || !IsFinished());
133 DCHECK(!instr->IsLinked());
134 DCHECK(!IsFinished());
135
136 if (!position.IsUnknown()) {
137 instr->set_position(position);
138 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100139 if (first_ == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000140 DCHECK(last_environment() != NULL);
141 DCHECK(!last_environment()->ast_id().IsNone());
Ben Murdoch8b112d22011-06-08 16:22:53 +0100142 HBlockEntry* entry = new(zone()) HBlockEntry();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100143 entry->InitializeAsFirst(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000144 if (!position.IsUnknown()) {
145 entry->set_position(position);
146 } else {
147 DCHECK(!FLAG_hydrogen_track_positions ||
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400148 !graph()->info()->IsOptimizing() || instr->IsAbnormalExit());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000149 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100150 first_ = last_ = entry;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100151 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100152 instr->InsertAfter(last_);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100153}
154
155
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000156HPhi* HBasicBlock::AddNewPhi(int merged_index) {
157 if (graph()->IsInsideNoSideEffectsScope()) {
158 merged_index = HPhi::kInvalidMergedIndex;
Steve Block44f0eee2011-05-26 01:26:41 +0100159 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000160 HPhi* phi = new(zone()) HPhi(merged_index, zone());
161 AddPhi(phi);
162 return phi;
Steve Block44f0eee2011-05-26 01:26:41 +0100163}
164
165
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000166HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id,
167 RemovableSimulate removable) {
168 DCHECK(HasEnvironment());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100169 HEnvironment* environment = last_environment();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000170 DCHECK(ast_id.IsNone() ||
171 ast_id == BailoutId::StubEntry() ||
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000172 environment->closure()->shared()->VerifyBailoutId(ast_id));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100173
174 int push_count = environment->push_count();
175 int pop_count = environment->pop_count();
176
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000177 HSimulate* instr =
178 new(zone()) HSimulate(ast_id, pop_count, zone(), removable);
179#ifdef DEBUG
180 instr->set_closure(environment->closure());
181#endif
182 // Order of pushed values: newest (top of stack) first. This allows
183 // HSimulate::MergeWith() to easily append additional pushed values
184 // that are older (from further down the stack).
185 for (int i = 0; i < push_count; ++i) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100186 instr->AddPushedValue(environment->ExpressionStackAt(i));
187 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000188 for (GrowableBitVector::Iterator it(environment->assigned_variables(),
189 zone());
190 !it.Done();
191 it.Advance()) {
192 int index = it.Current();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100193 instr->AddAssignedValue(index, environment->Lookup(index));
194 }
195 environment->ClearHistory();
196 return instr;
197}
198
199
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000200void HBasicBlock::Finish(HControlInstruction* end, HSourcePosition position) {
201 DCHECK(!IsFinished());
202 AddInstruction(end, position);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100203 end_ = end;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000204 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
205 it.Current()->RegisterPredecessor(this);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100206 }
207}
208
209
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000210void HBasicBlock::Goto(HBasicBlock* block,
211 HSourcePosition position,
212 FunctionState* state,
213 bool add_simulate) {
214 bool drop_extra = state != NULL &&
215 state->inlining_kind() == NORMAL_RETURN;
216
Steve Block44f0eee2011-05-26 01:26:41 +0100217 if (block->IsInlineReturnTarget()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000218 HEnvironment* env = last_environment();
219 int argument_count = env->arguments_environment()->parameter_count();
220 AddInstruction(new(zone())
221 HLeaveInlined(state->entry(), argument_count),
222 position);
223 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra));
Steve Block44f0eee2011-05-26 01:26:41 +0100224 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000225
226 if (add_simulate) AddNewSimulate(BailoutId::None(), position);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100227 HGoto* instr = new(zone()) HGoto(block);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000228 Finish(instr, position);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100229}
230
231
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100232void HBasicBlock::AddLeaveInlined(HValue* return_value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000233 FunctionState* state,
234 HSourcePosition position) {
235 HBasicBlock* target = state->function_return();
236 bool drop_extra = state->inlining_kind() == NORMAL_RETURN;
237
238 DCHECK(target->IsInlineReturnTarget());
239 DCHECK(return_value != NULL);
240 HEnvironment* env = last_environment();
241 int argument_count = env->arguments_environment()->parameter_count();
242 AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count),
243 position);
244 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra));
Steve Block44f0eee2011-05-26 01:26:41 +0100245 last_environment()->Push(return_value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000246 AddNewSimulate(BailoutId::None(), position);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100247 HGoto* instr = new(zone()) HGoto(target);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000248 Finish(instr, position);
Steve Block44f0eee2011-05-26 01:26:41 +0100249}
250
251
Ben Murdochb0fe1622011-05-05 13:52:32 +0100252void HBasicBlock::SetInitialEnvironment(HEnvironment* env) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000253 DCHECK(!HasEnvironment());
254 DCHECK(first() == NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100255 UpdateEnvironment(env);
256}
257
258
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000259void HBasicBlock::UpdateEnvironment(HEnvironment* env) {
260 last_environment_ = env;
261 graph()->update_maximum_environment_size(env->first_expression_index());
262}
263
264
265void HBasicBlock::SetJoinId(BailoutId ast_id) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100266 int length = predecessors_.length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000267 DCHECK(length > 0);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100268 for (int i = 0; i < length; i++) {
269 HBasicBlock* predecessor = predecessors_[i];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000270 DCHECK(predecessor->end()->IsGoto());
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100271 HSimulate* simulate = HSimulate::cast(predecessor->end()->previous());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000272 DCHECK(i != 0 ||
273 (predecessor->last_environment()->closure().is_null() ||
274 predecessor->last_environment()->closure()->shared()
275 ->VerifyBailoutId(ast_id)));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000276 simulate->set_ast_id(ast_id);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000277 predecessor->last_environment()->set_ast_id(ast_id);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100278 }
279}
280
281
282bool HBasicBlock::Dominates(HBasicBlock* other) const {
283 HBasicBlock* current = other->dominator();
284 while (current != NULL) {
285 if (current == this) return true;
286 current = current->dominator();
287 }
288 return false;
289}
290
291
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000292bool HBasicBlock::EqualToOrDominates(HBasicBlock* other) const {
293 if (this == other) return true;
294 return Dominates(other);
295}
296
297
Ben Murdoch589d6972011-11-30 16:04:58 +0000298int HBasicBlock::LoopNestingDepth() const {
299 const HBasicBlock* current = this;
300 int result = (current->IsLoopHeader()) ? 1 : 0;
301 while (current->parent_loop_header() != NULL) {
302 current = current->parent_loop_header();
303 result++;
304 }
305 return result;
306}
307
308
Ben Murdochb0fe1622011-05-05 13:52:32 +0100309void HBasicBlock::PostProcessLoopHeader(IterationStatement* stmt) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000310 DCHECK(IsLoopHeader());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100311
312 SetJoinId(stmt->EntryId());
313 if (predecessors()->length() == 1) {
314 // This is a degenerated loop.
315 DetachLoopInformation();
316 return;
317 }
318
319 // Only the first entry into the loop is from outside the loop. All other
320 // entries must be back edges.
321 for (int i = 1; i < predecessors()->length(); ++i) {
322 loop_information()->RegisterBackEdge(predecessors()->at(i));
323 }
324}
325
326
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000327void HBasicBlock::MarkSuccEdgeUnreachable(int succ) {
328 DCHECK(IsFinished());
329 HBasicBlock* succ_block = end()->SuccessorAt(succ);
330
331 DCHECK(succ_block->predecessors()->length() == 1);
332 succ_block->MarkUnreachable();
333}
334
335
Ben Murdochb0fe1622011-05-05 13:52:32 +0100336void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000337 if (HasPredecessor()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100338 // Only loop header blocks can have a predecessor added after
339 // instructions have been added to the block (they have phis for all
340 // values in the environment, these phis may be eliminated later).
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000341 DCHECK(IsLoopHeader() || first_ == NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100342 HEnvironment* incoming_env = pred->last_environment();
343 if (IsLoopHeader()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000344 DCHECK(phis()->length() == incoming_env->length());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100345 for (int i = 0; i < phis_.length(); ++i) {
346 phis_[i]->AddInput(incoming_env->values()->at(i));
347 }
348 } else {
349 last_environment()->AddIncomingEdge(this, pred->last_environment());
350 }
351 } else if (!HasEnvironment() && !IsFinished()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000352 DCHECK(!IsLoopHeader());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100353 SetInitialEnvironment(pred->last_environment()->Copy());
354 }
355
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000356 predecessors_.Add(pred, zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100357}
358
359
360void HBasicBlock::AddDominatedBlock(HBasicBlock* block) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000361 DCHECK(!dominated_blocks_.Contains(block));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100362 // Keep the list of dominated blocks sorted such that if there is two
363 // succeeding block in this list, the predecessor is before the successor.
364 int index = 0;
365 while (index < dominated_blocks_.length() &&
366 dominated_blocks_[index]->block_id() < block->block_id()) {
367 ++index;
368 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000369 dominated_blocks_.InsertAt(index, block, zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100370}
371
372
373void HBasicBlock::AssignCommonDominator(HBasicBlock* other) {
374 if (dominator_ == NULL) {
375 dominator_ = other;
376 other->AddDominatedBlock(this);
377 } else if (other->dominator() != NULL) {
378 HBasicBlock* first = dominator_;
379 HBasicBlock* second = other;
380
381 while (first != second) {
382 if (first->block_id() > second->block_id()) {
383 first = first->dominator();
384 } else {
385 second = second->dominator();
386 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000387 DCHECK(first != NULL && second != NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100388 }
389
390 if (dominator_ != first) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000391 DCHECK(dominator_->dominated_blocks_.Contains(this));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100392 dominator_->dominated_blocks_.RemoveElement(this);
393 dominator_ = first;
394 first->AddDominatedBlock(this);
395 }
396 }
397}
398
399
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100400void HBasicBlock::AssignLoopSuccessorDominators() {
401 // Mark blocks that dominate all subsequent reachable blocks inside their
402 // loop. Exploit the fact that blocks are sorted in reverse post order. When
403 // the loop is visited in increasing block id order, if the number of
404 // non-loop-exiting successor edges at the dominator_candidate block doesn't
405 // exceed the number of previously encountered predecessor edges, there is no
406 // path from the loop header to any block with higher id that doesn't go
407 // through the dominator_candidate block. In this case, the
408 // dominator_candidate block is guaranteed to dominate all blocks reachable
409 // from it with higher ids.
410 HBasicBlock* last = loop_information()->GetLastBackEdge();
411 int outstanding_successors = 1; // one edge from the pre-header
412 // Header always dominates everything.
413 MarkAsLoopSuccessorDominator();
414 for (int j = block_id(); j <= last->block_id(); ++j) {
415 HBasicBlock* dominator_candidate = graph_->blocks()->at(j);
416 for (HPredecessorIterator it(dominator_candidate); !it.Done();
417 it.Advance()) {
418 HBasicBlock* predecessor = it.Current();
419 // Don't count back edges.
420 if (predecessor->block_id() < dominator_candidate->block_id()) {
421 outstanding_successors--;
422 }
423 }
424
425 // If more successors than predecessors have been seen in the loop up to
426 // now, it's not possible to guarantee that the current block dominates
427 // all of the blocks with higher IDs. In this case, assume conservatively
428 // that those paths through loop that don't go through the current block
429 // contain all of the loop's dependencies. Also be careful to record
430 // dominator information about the current loop that's being processed,
431 // and not nested loops, which will be processed when
432 // AssignLoopSuccessorDominators gets called on their header.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000433 DCHECK(outstanding_successors >= 0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100434 HBasicBlock* parent_loop_header = dominator_candidate->parent_loop_header();
435 if (outstanding_successors == 0 &&
436 (parent_loop_header == this && !dominator_candidate->IsLoopHeader())) {
437 dominator_candidate->MarkAsLoopSuccessorDominator();
438 }
439 HControlInstruction* end = dominator_candidate->end();
440 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
441 HBasicBlock* successor = it.Current();
442 // Only count successors that remain inside the loop and don't loop back
443 // to a loop header.
444 if (successor->block_id() > dominator_candidate->block_id() &&
445 successor->block_id() <= last->block_id()) {
446 // Backwards edges must land on loop headers.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000447 DCHECK(successor->block_id() > dominator_candidate->block_id() ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100448 successor->IsLoopHeader());
449 outstanding_successors++;
450 }
451 }
452 }
453}
454
455
Ben Murdochb0fe1622011-05-05 13:52:32 +0100456int HBasicBlock::PredecessorIndexOf(HBasicBlock* predecessor) const {
457 for (int i = 0; i < predecessors_.length(); ++i) {
458 if (predecessors_[i] == predecessor) return i;
459 }
460 UNREACHABLE();
461 return -1;
462}
463
464
465#ifdef DEBUG
466void HBasicBlock::Verify() {
467 // Check that every block is finished.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000468 DCHECK(IsFinished());
469 DCHECK(block_id() >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +0100470
471 // Check that the incoming edges are in edge split form.
472 if (predecessors_.length() > 1) {
473 for (int i = 0; i < predecessors_.length(); ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000474 DCHECK(predecessors_[i]->end()->SecondSuccessor() == NULL);
Steve Block44f0eee2011-05-26 01:26:41 +0100475 }
476 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100477}
478#endif
479
480
481void HLoopInformation::RegisterBackEdge(HBasicBlock* block) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000482 this->back_edges_.Add(block, block->zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100483 AddBlock(block);
484}
485
486
487HBasicBlock* HLoopInformation::GetLastBackEdge() const {
488 int max_id = -1;
489 HBasicBlock* result = NULL;
490 for (int i = 0; i < back_edges_.length(); ++i) {
491 HBasicBlock* cur = back_edges_[i];
492 if (cur->block_id() > max_id) {
493 max_id = cur->block_id();
494 result = cur;
495 }
496 }
497 return result;
498}
499
500
501void HLoopInformation::AddBlock(HBasicBlock* block) {
502 if (block == loop_header()) return;
503 if (block->parent_loop_header() == loop_header()) return;
504 if (block->parent_loop_header() != NULL) {
505 AddBlock(block->parent_loop_header());
506 } else {
507 block->set_parent_loop_header(loop_header());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000508 blocks_.Add(block, block->zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100509 for (int i = 0; i < block->predecessors()->length(); ++i) {
510 AddBlock(block->predecessors()->at(i));
511 }
512 }
513}
514
515
516#ifdef DEBUG
517
518// Checks reachability of the blocks in this graph and stores a bit in
519// the BitVector "reachable()" for every block that can be reached
520// from the start block of the graph. If "dont_visit" is non-null, the given
521// block is treated as if it would not be part of the graph. "visited_count()"
522// returns the number of reachable blocks.
523class ReachabilityAnalyzer BASE_EMBEDDED {
524 public:
525 ReachabilityAnalyzer(HBasicBlock* entry_block,
526 int block_count,
527 HBasicBlock* dont_visit)
528 : visited_count_(0),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000529 stack_(16, entry_block->zone()),
530 reachable_(block_count, entry_block->zone()),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100531 dont_visit_(dont_visit) {
532 PushBlock(entry_block);
533 Analyze();
534 }
535
536 int visited_count() const { return visited_count_; }
537 const BitVector* reachable() const { return &reachable_; }
538
539 private:
540 void PushBlock(HBasicBlock* block) {
541 if (block != NULL && block != dont_visit_ &&
542 !reachable_.Contains(block->block_id())) {
543 reachable_.Add(block->block_id());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000544 stack_.Add(block, block->zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100545 visited_count_++;
546 }
547 }
548
549 void Analyze() {
550 while (!stack_.is_empty()) {
551 HControlInstruction* end = stack_.RemoveLast()->end();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000552 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
553 PushBlock(it.Current());
554 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100555 }
556 }
557
558 int visited_count_;
559 ZoneList<HBasicBlock*> stack_;
560 BitVector reachable_;
561 HBasicBlock* dont_visit_;
562};
563
564
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100565void HGraph::Verify(bool do_full_verify) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000566 Heap::RelocationLock relocation_lock(isolate()->heap());
567 AllowHandleDereference allow_deref;
568 AllowDeferredHandleDereference allow_deferred_deref;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100569 for (int i = 0; i < blocks_.length(); i++) {
570 HBasicBlock* block = blocks_.at(i);
571
572 block->Verify();
573
574 // Check that every block contains at least one node and that only the last
575 // node is a control instruction.
576 HInstruction* current = block->first();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000577 DCHECK(current != NULL && current->IsBlockEntry());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100578 while (current != NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000579 DCHECK((current->next() == NULL) == current->IsControlInstruction());
580 DCHECK(current->block() == block);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100581 current->Verify();
582 current = current->next();
583 }
584
585 // Check that successors are correctly set.
586 HBasicBlock* first = block->end()->FirstSuccessor();
587 HBasicBlock* second = block->end()->SecondSuccessor();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000588 DCHECK(second == NULL || first != NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100589
590 // Check that the predecessor array is correct.
591 if (first != NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000592 DCHECK(first->predecessors()->Contains(block));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100593 if (second != NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000594 DCHECK(second->predecessors()->Contains(block));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100595 }
596 }
597
598 // Check that phis have correct arguments.
599 for (int j = 0; j < block->phis()->length(); j++) {
600 HPhi* phi = block->phis()->at(j);
601 phi->Verify();
602 }
603
604 // Check that all join blocks have predecessors that end with an
605 // unconditional goto and agree on their environment node id.
606 if (block->predecessors()->length() >= 2) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000607 BailoutId id =
608 block->predecessors()->first()->last_environment()->ast_id();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100609 for (int k = 0; k < block->predecessors()->length(); k++) {
610 HBasicBlock* predecessor = block->predecessors()->at(k);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000611 DCHECK(predecessor->end()->IsGoto() ||
612 predecessor->end()->IsDeoptimize());
613 DCHECK(predecessor->last_environment()->ast_id() == id);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100614 }
615 }
616 }
617
618 // Check special property of first block to have no predecessors.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000619 DCHECK(blocks_.at(0)->predecessors()->is_empty());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100620
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100621 if (do_full_verify) {
622 // Check that the graph is fully connected.
623 ReachabilityAnalyzer analyzer(entry_block_, blocks_.length(), NULL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000624 DCHECK(analyzer.visited_count() == blocks_.length());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100625
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100626 // Check that entry block dominator is NULL.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000627 DCHECK(entry_block_->dominator() == NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100628
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100629 // Check dominators.
630 for (int i = 0; i < blocks_.length(); ++i) {
631 HBasicBlock* block = blocks_.at(i);
632 if (block->dominator() == NULL) {
633 // Only start block may have no dominator assigned to.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000634 DCHECK(i == 0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100635 } else {
636 // Assert that block is unreachable if dominator must not be visited.
637 ReachabilityAnalyzer dominator_analyzer(entry_block_,
638 blocks_.length(),
639 block->dominator());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000640 DCHECK(!dominator_analyzer.reachable()->Contains(block->block_id()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100641 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100642 }
643 }
644}
645
646#endif
647
648
649HConstant* HGraph::GetConstant(SetOncePointer<HConstant>* pointer,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000650 int32_t value) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100651 if (!pointer->is_set()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000652 // Can't pass GetInvalidContext() to HConstant::New, because that will
653 // recursively call GetConstant
654 HConstant* constant = HConstant::New(zone(), NULL, value);
655 constant->InsertAfter(entry_block()->first());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100656 pointer->set(constant);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000657 return constant;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100658 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000659 return ReinsertConstantIfNecessary(pointer->get());
660}
661
662
663HConstant* HGraph::ReinsertConstantIfNecessary(HConstant* constant) {
664 if (!constant->IsLinked()) {
665 // The constant was removed from the graph. Reinsert.
666 constant->ClearFlag(HValue::kIsDead);
667 constant->InsertAfter(entry_block()->first());
668 }
669 return constant;
670}
671
672
673HConstant* HGraph::GetConstant0() {
674 return GetConstant(&constant_0_, 0);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100675}
676
677
678HConstant* HGraph::GetConstant1() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000679 return GetConstant(&constant_1_, 1);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100680}
681
682
683HConstant* HGraph::GetConstantMinus1() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000684 return GetConstant(&constant_minus1_, -1);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100685}
686
687
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000688#define DEFINE_GET_CONSTANT(Name, name, type, htype, boolean_value) \
689HConstant* HGraph::GetConstant##Name() { \
690 if (!constant_##name##_.is_set()) { \
691 HConstant* constant = new(zone()) HConstant( \
692 Unique<Object>::CreateImmovable(isolate()->factory()->name##_value()), \
693 Unique<Map>::CreateImmovable(isolate()->factory()->type##_map()), \
694 false, \
695 Representation::Tagged(), \
696 htype, \
697 true, \
698 boolean_value, \
699 false, \
700 ODDBALL_TYPE); \
701 constant->InsertAfter(entry_block()->first()); \
702 constant_##name##_.set(constant); \
703 } \
704 return ReinsertConstantIfNecessary(constant_##name##_.get()); \
Ben Murdochb0fe1622011-05-05 13:52:32 +0100705}
706
707
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000708DEFINE_GET_CONSTANT(Undefined, undefined, undefined, HType::Undefined(), false)
709DEFINE_GET_CONSTANT(True, true, boolean, HType::Boolean(), true)
710DEFINE_GET_CONSTANT(False, false, boolean, HType::Boolean(), false)
711DEFINE_GET_CONSTANT(Hole, the_hole, the_hole, HType::None(), false)
712DEFINE_GET_CONSTANT(Null, null, null, HType::Null(), false)
713
714
715#undef DEFINE_GET_CONSTANT
716
717#define DEFINE_IS_CONSTANT(Name, name) \
718bool HGraph::IsConstant##Name(HConstant* constant) { \
719 return constant_##name##_.is_set() && constant == constant_##name##_.get(); \
720}
721DEFINE_IS_CONSTANT(Undefined, undefined)
722DEFINE_IS_CONSTANT(0, 0)
723DEFINE_IS_CONSTANT(1, 1)
724DEFINE_IS_CONSTANT(Minus1, minus1)
725DEFINE_IS_CONSTANT(True, true)
726DEFINE_IS_CONSTANT(False, false)
727DEFINE_IS_CONSTANT(Hole, the_hole)
728DEFINE_IS_CONSTANT(Null, null)
729
730#undef DEFINE_IS_CONSTANT
731
732
733HConstant* HGraph::GetInvalidContext() {
734 return GetConstant(&constant_invalid_context_, 0xFFFFC0C7);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100735}
736
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000737
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000738bool HGraph::IsStandardConstant(HConstant* constant) {
739 if (IsConstantUndefined(constant)) return true;
740 if (IsConstant0(constant)) return true;
741 if (IsConstant1(constant)) return true;
742 if (IsConstantMinus1(constant)) return true;
743 if (IsConstantTrue(constant)) return true;
744 if (IsConstantFalse(constant)) return true;
745 if (IsConstantHole(constant)) return true;
746 if (IsConstantNull(constant)) return true;
747 return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000748}
749
750
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000751HGraphBuilder::IfBuilder::IfBuilder() : builder_(NULL), needs_compare_(true) {}
752
753
754HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder)
755 : needs_compare_(true) {
756 Initialize(builder);
757}
758
759
760HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder,
761 HIfContinuation* continuation)
762 : needs_compare_(false), first_true_block_(NULL), first_false_block_(NULL) {
763 InitializeDontCreateBlocks(builder);
764 continuation->Continue(&first_true_block_, &first_false_block_);
765}
766
767
768void HGraphBuilder::IfBuilder::InitializeDontCreateBlocks(
769 HGraphBuilder* builder) {
770 builder_ = builder;
771 finished_ = false;
772 did_then_ = false;
773 did_else_ = false;
774 did_else_if_ = false;
775 did_and_ = false;
776 did_or_ = false;
777 captured_ = false;
778 pending_merge_block_ = false;
779 split_edge_merge_block_ = NULL;
780 merge_at_join_blocks_ = NULL;
781 normal_merge_at_join_block_count_ = 0;
782 deopt_merge_at_join_block_count_ = 0;
783}
784
785
786void HGraphBuilder::IfBuilder::Initialize(HGraphBuilder* builder) {
787 InitializeDontCreateBlocks(builder);
788 HEnvironment* env = builder->environment();
789 first_true_block_ = builder->CreateBasicBlock(env->Copy());
790 first_false_block_ = builder->CreateBasicBlock(env->Copy());
791}
792
793
794HControlInstruction* HGraphBuilder::IfBuilder::AddCompare(
795 HControlInstruction* compare) {
796 DCHECK(did_then_ == did_else_);
797 if (did_else_) {
798 // Handle if-then-elseif
799 did_else_if_ = true;
800 did_else_ = false;
801 did_then_ = false;
802 did_and_ = false;
803 did_or_ = false;
804 pending_merge_block_ = false;
805 split_edge_merge_block_ = NULL;
806 HEnvironment* env = builder()->environment();
807 first_true_block_ = builder()->CreateBasicBlock(env->Copy());
808 first_false_block_ = builder()->CreateBasicBlock(env->Copy());
809 }
810 if (split_edge_merge_block_ != NULL) {
811 HEnvironment* env = first_false_block_->last_environment();
812 HBasicBlock* split_edge = builder()->CreateBasicBlock(env->Copy());
813 if (did_or_) {
814 compare->SetSuccessorAt(0, split_edge);
815 compare->SetSuccessorAt(1, first_false_block_);
816 } else {
817 compare->SetSuccessorAt(0, first_true_block_);
818 compare->SetSuccessorAt(1, split_edge);
819 }
820 builder()->GotoNoSimulate(split_edge, split_edge_merge_block_);
821 } else {
822 compare->SetSuccessorAt(0, first_true_block_);
823 compare->SetSuccessorAt(1, first_false_block_);
824 }
825 builder()->FinishCurrentBlock(compare);
826 needs_compare_ = false;
827 return compare;
828}
829
830
831void HGraphBuilder::IfBuilder::Or() {
832 DCHECK(!needs_compare_);
833 DCHECK(!did_and_);
834 did_or_ = true;
835 HEnvironment* env = first_false_block_->last_environment();
836 if (split_edge_merge_block_ == NULL) {
837 split_edge_merge_block_ = builder()->CreateBasicBlock(env->Copy());
838 builder()->GotoNoSimulate(first_true_block_, split_edge_merge_block_);
839 first_true_block_ = split_edge_merge_block_;
840 }
841 builder()->set_current_block(first_false_block_);
842 first_false_block_ = builder()->CreateBasicBlock(env->Copy());
843}
844
845
846void HGraphBuilder::IfBuilder::And() {
847 DCHECK(!needs_compare_);
848 DCHECK(!did_or_);
849 did_and_ = true;
850 HEnvironment* env = first_false_block_->last_environment();
851 if (split_edge_merge_block_ == NULL) {
852 split_edge_merge_block_ = builder()->CreateBasicBlock(env->Copy());
853 builder()->GotoNoSimulate(first_false_block_, split_edge_merge_block_);
854 first_false_block_ = split_edge_merge_block_;
855 }
856 builder()->set_current_block(first_true_block_);
857 first_true_block_ = builder()->CreateBasicBlock(env->Copy());
858}
859
860
861void HGraphBuilder::IfBuilder::CaptureContinuation(
862 HIfContinuation* continuation) {
863 DCHECK(!did_else_if_);
864 DCHECK(!finished_);
865 DCHECK(!captured_);
866
867 HBasicBlock* true_block = NULL;
868 HBasicBlock* false_block = NULL;
869 Finish(&true_block, &false_block);
870 DCHECK(true_block != NULL);
871 DCHECK(false_block != NULL);
872 continuation->Capture(true_block, false_block);
873 captured_ = true;
874 builder()->set_current_block(NULL);
875 End();
876}
877
878
879void HGraphBuilder::IfBuilder::JoinContinuation(HIfContinuation* continuation) {
880 DCHECK(!did_else_if_);
881 DCHECK(!finished_);
882 DCHECK(!captured_);
883 HBasicBlock* true_block = NULL;
884 HBasicBlock* false_block = NULL;
885 Finish(&true_block, &false_block);
886 merge_at_join_blocks_ = NULL;
887 if (true_block != NULL && !true_block->IsFinished()) {
888 DCHECK(continuation->IsTrueReachable());
889 builder()->GotoNoSimulate(true_block, continuation->true_branch());
890 }
891 if (false_block != NULL && !false_block->IsFinished()) {
892 DCHECK(continuation->IsFalseReachable());
893 builder()->GotoNoSimulate(false_block, continuation->false_branch());
894 }
895 captured_ = true;
896 End();
897}
898
899
900void HGraphBuilder::IfBuilder::Then() {
901 DCHECK(!captured_);
902 DCHECK(!finished_);
903 did_then_ = true;
904 if (needs_compare_) {
905 // Handle if's without any expressions, they jump directly to the "else"
906 // branch. However, we must pretend that the "then" branch is reachable,
907 // so that the graph builder visits it and sees any live range extending
908 // constructs within it.
909 HConstant* constant_false = builder()->graph()->GetConstantFalse();
910 ToBooleanStub::Types boolean_type = ToBooleanStub::Types();
911 boolean_type.Add(ToBooleanStub::BOOLEAN);
912 HBranch* branch = builder()->New<HBranch>(
913 constant_false, boolean_type, first_true_block_, first_false_block_);
914 builder()->FinishCurrentBlock(branch);
915 }
916 builder()->set_current_block(first_true_block_);
917 pending_merge_block_ = true;
918}
919
920
921void HGraphBuilder::IfBuilder::Else() {
922 DCHECK(did_then_);
923 DCHECK(!captured_);
924 DCHECK(!finished_);
925 AddMergeAtJoinBlock(false);
926 builder()->set_current_block(first_false_block_);
927 pending_merge_block_ = true;
928 did_else_ = true;
929}
930
931
932void HGraphBuilder::IfBuilder::Deopt(const char* reason) {
933 DCHECK(did_then_);
934 builder()->Add<HDeoptimize>(reason, Deoptimizer::EAGER);
935 AddMergeAtJoinBlock(true);
936}
937
938
939void HGraphBuilder::IfBuilder::Return(HValue* value) {
940 HValue* parameter_count = builder()->graph()->GetConstantMinus1();
941 builder()->FinishExitCurrentBlock(
942 builder()->New<HReturn>(value, parameter_count));
943 AddMergeAtJoinBlock(false);
944}
945
946
947void HGraphBuilder::IfBuilder::AddMergeAtJoinBlock(bool deopt) {
948 if (!pending_merge_block_) return;
949 HBasicBlock* block = builder()->current_block();
950 DCHECK(block == NULL || !block->IsFinished());
951 MergeAtJoinBlock* record = new (builder()->zone())
952 MergeAtJoinBlock(block, deopt, merge_at_join_blocks_);
953 merge_at_join_blocks_ = record;
954 if (block != NULL) {
955 DCHECK(block->end() == NULL);
956 if (deopt) {
957 normal_merge_at_join_block_count_++;
958 } else {
959 deopt_merge_at_join_block_count_++;
960 }
961 }
962 builder()->set_current_block(NULL);
963 pending_merge_block_ = false;
964}
965
966
967void HGraphBuilder::IfBuilder::Finish() {
968 DCHECK(!finished_);
969 if (!did_then_) {
970 Then();
971 }
972 AddMergeAtJoinBlock(false);
973 if (!did_else_) {
974 Else();
975 AddMergeAtJoinBlock(false);
976 }
977 finished_ = true;
978}
979
980
981void HGraphBuilder::IfBuilder::Finish(HBasicBlock** then_continuation,
982 HBasicBlock** else_continuation) {
983 Finish();
984
985 MergeAtJoinBlock* else_record = merge_at_join_blocks_;
986 if (else_continuation != NULL) {
987 *else_continuation = else_record->block_;
988 }
989 MergeAtJoinBlock* then_record = else_record->next_;
990 if (then_continuation != NULL) {
991 *then_continuation = then_record->block_;
992 }
993 DCHECK(then_record->next_ == NULL);
994}
995
996
997void HGraphBuilder::IfBuilder::End() {
998 if (captured_) return;
999 Finish();
1000
1001 int total_merged_blocks = normal_merge_at_join_block_count_ +
1002 deopt_merge_at_join_block_count_;
1003 DCHECK(total_merged_blocks >= 1);
1004 HBasicBlock* merge_block =
1005 total_merged_blocks == 1 ? NULL : builder()->graph()->CreateBasicBlock();
1006
1007 // Merge non-deopt blocks first to ensure environment has right size for
1008 // padding.
1009 MergeAtJoinBlock* current = merge_at_join_blocks_;
1010 while (current != NULL) {
1011 if (!current->deopt_ && current->block_ != NULL) {
1012 // If there is only one block that makes it through to the end of the
1013 // if, then just set it as the current block and continue rather then
1014 // creating an unnecessary merge block.
1015 if (total_merged_blocks == 1) {
1016 builder()->set_current_block(current->block_);
1017 return;
1018 }
1019 builder()->GotoNoSimulate(current->block_, merge_block);
1020 }
1021 current = current->next_;
1022 }
1023
1024 // Merge deopt blocks, padding when necessary.
1025 current = merge_at_join_blocks_;
1026 while (current != NULL) {
1027 if (current->deopt_ && current->block_ != NULL) {
1028 current->block_->FinishExit(HAbnormalExit::New(builder()->zone(), NULL),
1029 HSourcePosition::Unknown());
1030 }
1031 current = current->next_;
1032 }
1033 builder()->set_current_block(merge_block);
1034}
1035
1036
1037HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder) {
1038 Initialize(builder, NULL, kWhileTrue, NULL);
1039}
1040
1041
1042HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, HValue* context,
1043 LoopBuilder::Direction direction) {
1044 Initialize(builder, context, direction, builder->graph()->GetConstant1());
1045}
1046
1047
1048HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, HValue* context,
1049 LoopBuilder::Direction direction,
1050 HValue* increment_amount) {
1051 Initialize(builder, context, direction, increment_amount);
1052 increment_amount_ = increment_amount;
1053}
1054
1055
1056void HGraphBuilder::LoopBuilder::Initialize(HGraphBuilder* builder,
1057 HValue* context,
1058 Direction direction,
1059 HValue* increment_amount) {
1060 builder_ = builder;
1061 context_ = context;
1062 direction_ = direction;
1063 increment_amount_ = increment_amount;
1064
1065 finished_ = false;
1066 header_block_ = builder->CreateLoopHeaderBlock();
1067 body_block_ = NULL;
1068 exit_block_ = NULL;
1069 exit_trampoline_block_ = NULL;
1070}
1071
1072
1073HValue* HGraphBuilder::LoopBuilder::BeginBody(
1074 HValue* initial,
1075 HValue* terminating,
1076 Token::Value token) {
1077 DCHECK(direction_ != kWhileTrue);
1078 HEnvironment* env = builder_->environment();
1079 phi_ = header_block_->AddNewPhi(env->values()->length());
1080 phi_->AddInput(initial);
1081 env->Push(initial);
1082 builder_->GotoNoSimulate(header_block_);
1083
1084 HEnvironment* body_env = env->Copy();
1085 HEnvironment* exit_env = env->Copy();
1086 // Remove the phi from the expression stack
1087 body_env->Pop();
1088 exit_env->Pop();
1089 body_block_ = builder_->CreateBasicBlock(body_env);
1090 exit_block_ = builder_->CreateBasicBlock(exit_env);
1091
1092 builder_->set_current_block(header_block_);
1093 env->Pop();
1094 builder_->FinishCurrentBlock(builder_->New<HCompareNumericAndBranch>(
1095 phi_, terminating, token, body_block_, exit_block_));
1096
1097 builder_->set_current_block(body_block_);
1098 if (direction_ == kPreIncrement || direction_ == kPreDecrement) {
1099 HValue* one = builder_->graph()->GetConstant1();
1100 if (direction_ == kPreIncrement) {
1101 increment_ = HAdd::New(zone(), context_, phi_, one);
1102 } else {
1103 increment_ = HSub::New(zone(), context_, phi_, one);
1104 }
1105 increment_->ClearFlag(HValue::kCanOverflow);
1106 builder_->AddInstruction(increment_);
1107 return increment_;
1108 } else {
1109 return phi_;
1110 }
1111}
1112
1113
1114void HGraphBuilder::LoopBuilder::BeginBody(int drop_count) {
1115 DCHECK(direction_ == kWhileTrue);
1116 HEnvironment* env = builder_->environment();
1117 builder_->GotoNoSimulate(header_block_);
1118 builder_->set_current_block(header_block_);
1119 env->Drop(drop_count);
1120}
1121
1122
1123void HGraphBuilder::LoopBuilder::Break() {
1124 if (exit_trampoline_block_ == NULL) {
1125 // Its the first time we saw a break.
1126 if (direction_ == kWhileTrue) {
1127 HEnvironment* env = builder_->environment()->Copy();
1128 exit_trampoline_block_ = builder_->CreateBasicBlock(env);
1129 } else {
1130 HEnvironment* env = exit_block_->last_environment()->Copy();
1131 exit_trampoline_block_ = builder_->CreateBasicBlock(env);
1132 builder_->GotoNoSimulate(exit_block_, exit_trampoline_block_);
1133 }
1134 }
1135
1136 builder_->GotoNoSimulate(exit_trampoline_block_);
1137 builder_->set_current_block(NULL);
1138}
1139
1140
1141void HGraphBuilder::LoopBuilder::EndBody() {
1142 DCHECK(!finished_);
1143
1144 if (direction_ == kPostIncrement || direction_ == kPostDecrement) {
1145 if (direction_ == kPostIncrement) {
1146 increment_ = HAdd::New(zone(), context_, phi_, increment_amount_);
1147 } else {
1148 increment_ = HSub::New(zone(), context_, phi_, increment_amount_);
1149 }
1150 increment_->ClearFlag(HValue::kCanOverflow);
1151 builder_->AddInstruction(increment_);
1152 }
1153
1154 if (direction_ != kWhileTrue) {
1155 // Push the new increment value on the expression stack to merge into
1156 // the phi.
1157 builder_->environment()->Push(increment_);
1158 }
1159 HBasicBlock* last_block = builder_->current_block();
1160 builder_->GotoNoSimulate(last_block, header_block_);
1161 header_block_->loop_information()->RegisterBackEdge(last_block);
1162
1163 if (exit_trampoline_block_ != NULL) {
1164 builder_->set_current_block(exit_trampoline_block_);
1165 } else {
1166 builder_->set_current_block(exit_block_);
1167 }
1168 finished_ = true;
1169}
1170
1171
1172HGraph* HGraphBuilder::CreateGraph() {
1173 graph_ = new(zone()) HGraph(info_);
1174 if (FLAG_hydrogen_stats) isolate()->GetHStatistics()->Initialize(info_);
1175 CompilationPhase phase("H_Block building", info_);
1176 set_current_block(graph()->entry_block());
1177 if (!BuildGraph()) return NULL;
1178 graph()->FinalizeUniqueness();
1179 return graph_;
1180}
1181
1182
1183HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
1184 DCHECK(current_block() != NULL);
1185 DCHECK(!FLAG_hydrogen_track_positions ||
1186 !position_.IsUnknown() ||
1187 !info_->IsOptimizing());
1188 current_block()->AddInstruction(instr, source_position());
1189 if (graph()->IsInsideNoSideEffectsScope()) {
1190 instr->SetFlag(HValue::kHasNoObservableSideEffects);
1191 }
1192 return instr;
1193}
1194
1195
1196void HGraphBuilder::FinishCurrentBlock(HControlInstruction* last) {
1197 DCHECK(!FLAG_hydrogen_track_positions ||
1198 !info_->IsOptimizing() ||
1199 !position_.IsUnknown());
1200 current_block()->Finish(last, source_position());
1201 if (last->IsReturn() || last->IsAbnormalExit()) {
1202 set_current_block(NULL);
1203 }
1204}
1205
1206
1207void HGraphBuilder::FinishExitCurrentBlock(HControlInstruction* instruction) {
1208 DCHECK(!FLAG_hydrogen_track_positions || !info_->IsOptimizing() ||
1209 !position_.IsUnknown());
1210 current_block()->FinishExit(instruction, source_position());
1211 if (instruction->IsReturn() || instruction->IsAbnormalExit()) {
1212 set_current_block(NULL);
1213 }
1214}
1215
1216
1217void HGraphBuilder::AddIncrementCounter(StatsCounter* counter) {
1218 if (FLAG_native_code_counters && counter->Enabled()) {
1219 HValue* reference = Add<HConstant>(ExternalReference(counter));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001220 HValue* old_value =
1221 Add<HLoadNamedField>(reference, nullptr, HObjectAccess::ForCounter());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001222 HValue* new_value = AddUncasted<HAdd>(old_value, graph()->GetConstant1());
1223 new_value->ClearFlag(HValue::kCanOverflow); // Ignore counter overflow
1224 Add<HStoreNamedField>(reference, HObjectAccess::ForCounter(),
1225 new_value, STORE_TO_INITIALIZED_ENTRY);
1226 }
1227}
1228
1229
1230void HGraphBuilder::AddSimulate(BailoutId id,
1231 RemovableSimulate removable) {
1232 DCHECK(current_block() != NULL);
1233 DCHECK(!graph()->IsInsideNoSideEffectsScope());
1234 current_block()->AddNewSimulate(id, source_position(), removable);
1235}
1236
1237
1238HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) {
1239 HBasicBlock* b = graph()->CreateBasicBlock();
1240 b->SetInitialEnvironment(env);
1241 return b;
1242}
1243
1244
1245HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() {
1246 HBasicBlock* header = graph()->CreateBasicBlock();
1247 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header);
1248 header->SetInitialEnvironment(entry_env);
1249 header->AttachLoopInformation();
1250 return header;
1251}
1252
1253
1254HValue* HGraphBuilder::BuildGetElementsKind(HValue* object) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001255 HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001256
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001257 HValue* bit_field2 =
1258 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField2());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001259 return BuildDecodeField<Map::ElementsKindBits>(bit_field2);
1260}
1261
1262
1263HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) {
1264 if (obj->type().IsHeapObject()) return obj;
1265 return Add<HCheckHeapObject>(obj);
1266}
1267
1268
1269void HGraphBuilder::FinishExitWithHardDeoptimization(const char* reason) {
1270 Add<HDeoptimize>(reason, Deoptimizer::EAGER);
1271 FinishExitCurrentBlock(New<HAbnormalExit>());
1272}
1273
1274
1275HValue* HGraphBuilder::BuildCheckString(HValue* string) {
1276 if (!string->type().IsString()) {
1277 DCHECK(!string->IsConstant() ||
1278 !HConstant::cast(string)->HasStringValue());
1279 BuildCheckHeapObject(string);
1280 return Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING);
1281 }
1282 return string;
1283}
1284
1285
1286HValue* HGraphBuilder::BuildWrapReceiver(HValue* object, HValue* function) {
1287 if (object->type().IsJSObject()) return object;
1288 if (function->IsConstant() &&
1289 HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
1290 Handle<JSFunction> f = Handle<JSFunction>::cast(
1291 HConstant::cast(function)->handle(isolate()));
1292 SharedFunctionInfo* shared = f->shared();
1293 if (shared->strict_mode() == STRICT || shared->native()) return object;
1294 }
1295 return Add<HWrapReceiver>(object, function);
1296}
1297
1298
1299HValue* HGraphBuilder::BuildCheckForCapacityGrow(
1300 HValue* object,
1301 HValue* elements,
1302 ElementsKind kind,
1303 HValue* length,
1304 HValue* key,
1305 bool is_js_array,
1306 PropertyAccessType access_type) {
1307 IfBuilder length_checker(this);
1308
1309 Token::Value token = IsHoleyElementsKind(kind) ? Token::GTE : Token::EQ;
1310 length_checker.If<HCompareNumericAndBranch>(key, length, token);
1311
1312 length_checker.Then();
1313
1314 HValue* current_capacity = AddLoadFixedArrayLength(elements);
1315
1316 IfBuilder capacity_checker(this);
1317
1318 capacity_checker.If<HCompareNumericAndBranch>(key, current_capacity,
1319 Token::GTE);
1320 capacity_checker.Then();
1321
1322 HValue* max_gap = Add<HConstant>(static_cast<int32_t>(JSObject::kMaxGap));
1323 HValue* max_capacity = AddUncasted<HAdd>(current_capacity, max_gap);
1324
1325 Add<HBoundsCheck>(key, max_capacity);
1326
1327 HValue* new_capacity = BuildNewElementsCapacity(key);
1328 HValue* new_elements = BuildGrowElementsCapacity(object, elements,
1329 kind, kind, length,
1330 new_capacity);
1331
1332 environment()->Push(new_elements);
1333 capacity_checker.Else();
1334
1335 environment()->Push(elements);
1336 capacity_checker.End();
1337
1338 if (is_js_array) {
1339 HValue* new_length = AddUncasted<HAdd>(key, graph_->GetConstant1());
1340 new_length->ClearFlag(HValue::kCanOverflow);
1341
1342 Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(kind),
1343 new_length);
1344 }
1345
1346 if (access_type == STORE && kind == FAST_SMI_ELEMENTS) {
1347 HValue* checked_elements = environment()->Top();
1348
1349 // Write zero to ensure that the new element is initialized with some smi.
1350 Add<HStoreKeyed>(checked_elements, key, graph()->GetConstant0(), kind);
1351 }
1352
1353 length_checker.Else();
1354 Add<HBoundsCheck>(key, length);
1355
1356 environment()->Push(elements);
1357 length_checker.End();
1358
1359 return environment()->Pop();
1360}
1361
1362
1363HValue* HGraphBuilder::BuildCopyElementsOnWrite(HValue* object,
1364 HValue* elements,
1365 ElementsKind kind,
1366 HValue* length) {
1367 Factory* factory = isolate()->factory();
1368
1369 IfBuilder cow_checker(this);
1370
1371 cow_checker.If<HCompareMap>(elements, factory->fixed_cow_array_map());
1372 cow_checker.Then();
1373
1374 HValue* capacity = AddLoadFixedArrayLength(elements);
1375
1376 HValue* new_elements = BuildGrowElementsCapacity(object, elements, kind,
1377 kind, length, capacity);
1378
1379 environment()->Push(new_elements);
1380
1381 cow_checker.Else();
1382
1383 environment()->Push(elements);
1384
1385 cow_checker.End();
1386
1387 return environment()->Pop();
1388}
1389
1390
1391void HGraphBuilder::BuildTransitionElementsKind(HValue* object,
1392 HValue* map,
1393 ElementsKind from_kind,
1394 ElementsKind to_kind,
1395 bool is_jsarray) {
1396 DCHECK(!IsFastHoleyElementsKind(from_kind) ||
1397 IsFastHoleyElementsKind(to_kind));
1398
1399 if (AllocationSite::GetMode(from_kind, to_kind) == TRACK_ALLOCATION_SITE) {
1400 Add<HTrapAllocationMemento>(object);
1401 }
1402
1403 if (!IsSimpleMapChangeTransition(from_kind, to_kind)) {
1404 HInstruction* elements = AddLoadElements(object);
1405
1406 HInstruction* empty_fixed_array = Add<HConstant>(
1407 isolate()->factory()->empty_fixed_array());
1408
1409 IfBuilder if_builder(this);
1410
1411 if_builder.IfNot<HCompareObjectEqAndBranch>(elements, empty_fixed_array);
1412
1413 if_builder.Then();
1414
1415 HInstruction* elements_length = AddLoadFixedArrayLength(elements);
1416
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001417 HInstruction* array_length =
1418 is_jsarray
1419 ? Add<HLoadNamedField>(object, nullptr,
1420 HObjectAccess::ForArrayLength(from_kind))
1421 : elements_length;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001422
1423 BuildGrowElementsCapacity(object, elements, from_kind, to_kind,
1424 array_length, elements_length);
1425
1426 if_builder.End();
1427 }
1428
1429 Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map);
1430}
1431
1432
1433void HGraphBuilder::BuildJSObjectCheck(HValue* receiver,
1434 int bit_field_mask) {
1435 // Check that the object isn't a smi.
1436 Add<HCheckHeapObject>(receiver);
1437
1438 // Get the map of the receiver.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001439 HValue* map =
1440 Add<HLoadNamedField>(receiver, nullptr, HObjectAccess::ForMap());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001441
1442 // Check the instance type and if an access check is needed, this can be
1443 // done with a single load, since both bytes are adjacent in the map.
1444 HObjectAccess access(HObjectAccess::ForMapInstanceTypeAndBitField());
1445 HValue* instance_type_and_bit_field =
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001446 Add<HLoadNamedField>(map, nullptr, access);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001447
1448 HValue* mask = Add<HConstant>(0x00FF | (bit_field_mask << 8));
1449 HValue* and_result = AddUncasted<HBitwise>(Token::BIT_AND,
1450 instance_type_and_bit_field,
1451 mask);
1452 HValue* sub_result = AddUncasted<HSub>(and_result,
1453 Add<HConstant>(JS_OBJECT_TYPE));
1454 Add<HBoundsCheck>(sub_result,
1455 Add<HConstant>(LAST_JS_OBJECT_TYPE + 1 - JS_OBJECT_TYPE));
1456}
1457
1458
1459void HGraphBuilder::BuildKeyedIndexCheck(HValue* key,
1460 HIfContinuation* join_continuation) {
1461 // The sometimes unintuitively backward ordering of the ifs below is
1462 // convoluted, but necessary. All of the paths must guarantee that the
1463 // if-true of the continuation returns a smi element index and the if-false of
1464 // the continuation returns either a symbol or a unique string key. All other
1465 // object types cause a deopt to fall back to the runtime.
1466
1467 IfBuilder key_smi_if(this);
1468 key_smi_if.If<HIsSmiAndBranch>(key);
1469 key_smi_if.Then();
1470 {
1471 Push(key); // Nothing to do, just continue to true of continuation.
1472 }
1473 key_smi_if.Else();
1474 {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001475 HValue* map = Add<HLoadNamedField>(key, nullptr, HObjectAccess::ForMap());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001476 HValue* instance_type =
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001477 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapInstanceType());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001478
1479 // Non-unique string, check for a string with a hash code that is actually
1480 // an index.
1481 STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE);
1482 IfBuilder not_string_or_name_if(this);
1483 not_string_or_name_if.If<HCompareNumericAndBranch>(
1484 instance_type,
1485 Add<HConstant>(LAST_UNIQUE_NAME_TYPE),
1486 Token::GT);
1487
1488 not_string_or_name_if.Then();
1489 {
1490 // Non-smi, non-Name, non-String: Try to convert to smi in case of
1491 // HeapNumber.
1492 // TODO(danno): This could call some variant of ToString
1493 Push(AddUncasted<HForceRepresentation>(key, Representation::Smi()));
1494 }
1495 not_string_or_name_if.Else();
1496 {
1497 // String or Name: check explicitly for Name, they can short-circuit
1498 // directly to unique non-index key path.
1499 IfBuilder not_symbol_if(this);
1500 not_symbol_if.If<HCompareNumericAndBranch>(
1501 instance_type,
1502 Add<HConstant>(SYMBOL_TYPE),
1503 Token::NE);
1504
1505 not_symbol_if.Then();
1506 {
1507 // String: check whether the String is a String of an index. If it is,
1508 // extract the index value from the hash.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001509 HValue* hash = Add<HLoadNamedField>(key, nullptr,
1510 HObjectAccess::ForNameHashField());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001511 HValue* not_index_mask = Add<HConstant>(static_cast<int>(
1512 String::kContainsCachedArrayIndexMask));
1513
1514 HValue* not_index_test = AddUncasted<HBitwise>(
1515 Token::BIT_AND, hash, not_index_mask);
1516
1517 IfBuilder string_index_if(this);
1518 string_index_if.If<HCompareNumericAndBranch>(not_index_test,
1519 graph()->GetConstant0(),
1520 Token::EQ);
1521 string_index_if.Then();
1522 {
1523 // String with index in hash: extract string and merge to index path.
1524 Push(BuildDecodeField<String::ArrayIndexValueBits>(hash));
1525 }
1526 string_index_if.Else();
1527 {
1528 // Key is a non-index String, check for uniqueness/internalization.
1529 // If it's not internalized yet, internalize it now.
1530 HValue* not_internalized_bit = AddUncasted<HBitwise>(
1531 Token::BIT_AND,
1532 instance_type,
1533 Add<HConstant>(static_cast<int>(kIsNotInternalizedMask)));
1534
1535 IfBuilder internalized(this);
1536 internalized.If<HCompareNumericAndBranch>(not_internalized_bit,
1537 graph()->GetConstant0(),
1538 Token::EQ);
1539 internalized.Then();
1540 Push(key);
1541
1542 internalized.Else();
1543 Add<HPushArguments>(key);
1544 HValue* intern_key = Add<HCallRuntime>(
1545 isolate()->factory()->empty_string(),
1546 Runtime::FunctionForId(Runtime::kInternalizeString), 1);
1547 Push(intern_key);
1548
1549 internalized.End();
1550 // Key guaranteed to be a unique string
1551 }
1552 string_index_if.JoinContinuation(join_continuation);
1553 }
1554 not_symbol_if.Else();
1555 {
1556 Push(key); // Key is symbol
1557 }
1558 not_symbol_if.JoinContinuation(join_continuation);
1559 }
1560 not_string_or_name_if.JoinContinuation(join_continuation);
1561 }
1562 key_smi_if.JoinContinuation(join_continuation);
1563}
1564
1565
1566void HGraphBuilder::BuildNonGlobalObjectCheck(HValue* receiver) {
1567 // Get the the instance type of the receiver, and make sure that it is
1568 // not one of the global object types.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001569 HValue* map =
1570 Add<HLoadNamedField>(receiver, nullptr, HObjectAccess::ForMap());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001571 HValue* instance_type =
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001572 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapInstanceType());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001573 STATIC_ASSERT(JS_BUILTINS_OBJECT_TYPE == JS_GLOBAL_OBJECT_TYPE + 1);
1574 HValue* min_global_type = Add<HConstant>(JS_GLOBAL_OBJECT_TYPE);
1575 HValue* max_global_type = Add<HConstant>(JS_BUILTINS_OBJECT_TYPE);
1576
1577 IfBuilder if_global_object(this);
1578 if_global_object.If<HCompareNumericAndBranch>(instance_type,
1579 max_global_type,
1580 Token::LTE);
1581 if_global_object.And();
1582 if_global_object.If<HCompareNumericAndBranch>(instance_type,
1583 min_global_type,
1584 Token::GTE);
1585 if_global_object.ThenDeopt("receiver was a global object");
1586 if_global_object.End();
1587}
1588
1589
1590void HGraphBuilder::BuildTestForDictionaryProperties(
1591 HValue* object,
1592 HIfContinuation* continuation) {
1593 HValue* properties = Add<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001594 object, nullptr, HObjectAccess::ForPropertiesPointer());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001595 HValue* properties_map =
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001596 Add<HLoadNamedField>(properties, nullptr, HObjectAccess::ForMap());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001597 HValue* hash_map = Add<HLoadRoot>(Heap::kHashTableMapRootIndex);
1598 IfBuilder builder(this);
1599 builder.If<HCompareObjectEqAndBranch>(properties_map, hash_map);
1600 builder.CaptureContinuation(continuation);
1601}
1602
1603
1604HValue* HGraphBuilder::BuildKeyedLookupCacheHash(HValue* object,
1605 HValue* key) {
1606 // Load the map of the receiver, compute the keyed lookup cache hash
1607 // based on 32 bits of the map pointer and the string hash.
1608 HValue* object_map =
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001609 Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMapAsInteger32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001610 HValue* shifted_map = AddUncasted<HShr>(
1611 object_map, Add<HConstant>(KeyedLookupCache::kMapHashShift));
1612 HValue* string_hash =
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001613 Add<HLoadNamedField>(key, nullptr, HObjectAccess::ForStringHashField());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001614 HValue* shifted_hash = AddUncasted<HShr>(
1615 string_hash, Add<HConstant>(String::kHashShift));
1616 HValue* xor_result = AddUncasted<HBitwise>(Token::BIT_XOR, shifted_map,
1617 shifted_hash);
1618 int mask = (KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask);
1619 return AddUncasted<HBitwise>(Token::BIT_AND, xor_result,
1620 Add<HConstant>(mask));
1621}
1622
1623
1624HValue* HGraphBuilder::BuildElementIndexHash(HValue* index) {
1625 int32_t seed_value = static_cast<uint32_t>(isolate()->heap()->HashSeed());
1626 HValue* seed = Add<HConstant>(seed_value);
1627 HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, index, seed);
1628
1629 // hash = ~hash + (hash << 15);
1630 HValue* shifted_hash = AddUncasted<HShl>(hash, Add<HConstant>(15));
1631 HValue* not_hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash,
1632 graph()->GetConstantMinus1());
1633 hash = AddUncasted<HAdd>(shifted_hash, not_hash);
1634
1635 // hash = hash ^ (hash >> 12);
1636 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(12));
1637 hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
1638
1639 // hash = hash + (hash << 2);
1640 shifted_hash = AddUncasted<HShl>(hash, Add<HConstant>(2));
1641 hash = AddUncasted<HAdd>(hash, shifted_hash);
1642
1643 // hash = hash ^ (hash >> 4);
1644 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(4));
1645 hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
1646
1647 // hash = hash * 2057;
1648 hash = AddUncasted<HMul>(hash, Add<HConstant>(2057));
1649 hash->ClearFlag(HValue::kCanOverflow);
1650
1651 // hash = hash ^ (hash >> 16);
1652 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(16));
1653 return AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
1654}
1655
1656
1657HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver,
1658 HValue* elements,
1659 HValue* key,
1660 HValue* hash) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001661 HValue* capacity =
1662 Add<HLoadKeyed>(elements, Add<HConstant>(NameDictionary::kCapacityIndex),
1663 nullptr, FAST_ELEMENTS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001664
1665 HValue* mask = AddUncasted<HSub>(capacity, graph()->GetConstant1());
1666 mask->ChangeRepresentation(Representation::Integer32());
1667 mask->ClearFlag(HValue::kCanOverflow);
1668
1669 HValue* entry = hash;
1670 HValue* count = graph()->GetConstant1();
1671 Push(entry);
1672 Push(count);
1673
1674 HIfContinuation return_or_loop_continuation(graph()->CreateBasicBlock(),
1675 graph()->CreateBasicBlock());
1676 HIfContinuation found_key_match_continuation(graph()->CreateBasicBlock(),
1677 graph()->CreateBasicBlock());
1678 LoopBuilder probe_loop(this);
1679 probe_loop.BeginBody(2); // Drop entry, count from last environment to
1680 // appease live range building without simulates.
1681
1682 count = Pop();
1683 entry = Pop();
1684 entry = AddUncasted<HBitwise>(Token::BIT_AND, entry, mask);
1685 int entry_size = SeededNumberDictionary::kEntrySize;
1686 HValue* base_index = AddUncasted<HMul>(entry, Add<HConstant>(entry_size));
1687 base_index->ClearFlag(HValue::kCanOverflow);
1688 int start_offset = SeededNumberDictionary::kElementsStartIndex;
1689 HValue* key_index =
1690 AddUncasted<HAdd>(base_index, Add<HConstant>(start_offset));
1691 key_index->ClearFlag(HValue::kCanOverflow);
1692
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001693 HValue* candidate_key =
1694 Add<HLoadKeyed>(elements, key_index, nullptr, FAST_ELEMENTS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001695 IfBuilder if_undefined(this);
1696 if_undefined.If<HCompareObjectEqAndBranch>(candidate_key,
1697 graph()->GetConstantUndefined());
1698 if_undefined.Then();
1699 {
1700 // element == undefined means "not found". Call the runtime.
1701 // TODO(jkummerow): walk the prototype chain instead.
1702 Add<HPushArguments>(receiver, key);
1703 Push(Add<HCallRuntime>(isolate()->factory()->empty_string(),
1704 Runtime::FunctionForId(Runtime::kKeyedGetProperty),
1705 2));
1706 }
1707 if_undefined.Else();
1708 {
1709 IfBuilder if_match(this);
1710 if_match.If<HCompareObjectEqAndBranch>(candidate_key, key);
1711 if_match.Then();
1712 if_match.Else();
1713
1714 // Update non-internalized string in the dictionary with internalized key?
1715 IfBuilder if_update_with_internalized(this);
1716 HValue* smi_check =
1717 if_update_with_internalized.IfNot<HIsSmiAndBranch>(candidate_key);
1718 if_update_with_internalized.And();
1719 HValue* map = AddLoadMap(candidate_key, smi_check);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001720 HValue* instance_type =
1721 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapInstanceType());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001722 HValue* not_internalized_bit = AddUncasted<HBitwise>(
1723 Token::BIT_AND, instance_type,
1724 Add<HConstant>(static_cast<int>(kIsNotInternalizedMask)));
1725 if_update_with_internalized.If<HCompareNumericAndBranch>(
1726 not_internalized_bit, graph()->GetConstant0(), Token::NE);
1727 if_update_with_internalized.And();
1728 if_update_with_internalized.IfNot<HCompareObjectEqAndBranch>(
1729 candidate_key, graph()->GetConstantHole());
1730 if_update_with_internalized.AndIf<HStringCompareAndBranch>(candidate_key,
1731 key, Token::EQ);
1732 if_update_with_internalized.Then();
1733 // Replace a key that is a non-internalized string by the equivalent
1734 // internalized string for faster further lookups.
1735 Add<HStoreKeyed>(elements, key_index, key, FAST_ELEMENTS);
1736 if_update_with_internalized.Else();
1737
1738 if_update_with_internalized.JoinContinuation(&found_key_match_continuation);
1739 if_match.JoinContinuation(&found_key_match_continuation);
1740
1741 IfBuilder found_key_match(this, &found_key_match_continuation);
1742 found_key_match.Then();
1743 // Key at current probe matches. Relevant bits in the |details| field must
1744 // be zero, otherwise the dictionary element requires special handling.
1745 HValue* details_index =
1746 AddUncasted<HAdd>(base_index, Add<HConstant>(start_offset + 2));
1747 details_index->ClearFlag(HValue::kCanOverflow);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001748 HValue* details =
1749 Add<HLoadKeyed>(elements, details_index, nullptr, FAST_ELEMENTS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001750 int details_mask = PropertyDetails::TypeField::kMask |
1751 PropertyDetails::DeletedField::kMask;
1752 details = AddUncasted<HBitwise>(Token::BIT_AND, details,
1753 Add<HConstant>(details_mask));
1754 IfBuilder details_compare(this);
1755 details_compare.If<HCompareNumericAndBranch>(
1756 details, graph()->GetConstant0(), Token::EQ);
1757 details_compare.Then();
1758 HValue* result_index =
1759 AddUncasted<HAdd>(base_index, Add<HConstant>(start_offset + 1));
1760 result_index->ClearFlag(HValue::kCanOverflow);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001761 Push(Add<HLoadKeyed>(elements, result_index, nullptr, FAST_ELEMENTS));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001762 details_compare.Else();
1763 Add<HPushArguments>(receiver, key);
1764 Push(Add<HCallRuntime>(isolate()->factory()->empty_string(),
1765 Runtime::FunctionForId(Runtime::kKeyedGetProperty),
1766 2));
1767 details_compare.End();
1768
1769 found_key_match.Else();
1770 found_key_match.JoinContinuation(&return_or_loop_continuation);
1771 }
1772 if_undefined.JoinContinuation(&return_or_loop_continuation);
1773
1774 IfBuilder return_or_loop(this, &return_or_loop_continuation);
1775 return_or_loop.Then();
1776 probe_loop.Break();
1777
1778 return_or_loop.Else();
1779 entry = AddUncasted<HAdd>(entry, count);
1780 entry->ClearFlag(HValue::kCanOverflow);
1781 count = AddUncasted<HAdd>(count, graph()->GetConstant1());
1782 count->ClearFlag(HValue::kCanOverflow);
1783 Push(entry);
1784 Push(count);
1785
1786 probe_loop.EndBody();
1787
1788 return_or_loop.End();
1789
1790 return Pop();
1791}
1792
1793
1794HValue* HGraphBuilder::BuildRegExpConstructResult(HValue* length,
1795 HValue* index,
1796 HValue* input) {
1797 NoObservableSideEffectsScope scope(this);
1798 HConstant* max_length = Add<HConstant>(JSObject::kInitialMaxFastElementArray);
1799 Add<HBoundsCheck>(length, max_length);
1800
1801 // Generate size calculation code here in order to make it dominate
1802 // the JSRegExpResult allocation.
1803 ElementsKind elements_kind = FAST_ELEMENTS;
1804 HValue* size = BuildCalculateElementsSize(elements_kind, length);
1805
1806 // Allocate the JSRegExpResult and the FixedArray in one step.
1807 HValue* result = Add<HAllocate>(
1808 Add<HConstant>(JSRegExpResult::kSize), HType::JSArray(),
1809 NOT_TENURED, JS_ARRAY_TYPE);
1810
1811 // Initialize the JSRegExpResult header.
1812 HValue* global_object = Add<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001813 context(), nullptr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001814 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
1815 HValue* native_context = Add<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001816 global_object, nullptr, HObjectAccess::ForGlobalObjectNativeContext());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001817 Add<HStoreNamedField>(
1818 result, HObjectAccess::ForMap(),
1819 Add<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001820 native_context, nullptr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001821 HObjectAccess::ForContextSlot(Context::REGEXP_RESULT_MAP_INDEX)));
1822 HConstant* empty_fixed_array =
1823 Add<HConstant>(isolate()->factory()->empty_fixed_array());
1824 Add<HStoreNamedField>(
1825 result, HObjectAccess::ForJSArrayOffset(JSArray::kPropertiesOffset),
1826 empty_fixed_array);
1827 Add<HStoreNamedField>(
1828 result, HObjectAccess::ForJSArrayOffset(JSArray::kElementsOffset),
1829 empty_fixed_array);
1830 Add<HStoreNamedField>(
1831 result, HObjectAccess::ForJSArrayOffset(JSArray::kLengthOffset), length);
1832
1833 // Initialize the additional fields.
1834 Add<HStoreNamedField>(
1835 result, HObjectAccess::ForJSArrayOffset(JSRegExpResult::kIndexOffset),
1836 index);
1837 Add<HStoreNamedField>(
1838 result, HObjectAccess::ForJSArrayOffset(JSRegExpResult::kInputOffset),
1839 input);
1840
1841 // Allocate and initialize the elements header.
1842 HAllocate* elements = BuildAllocateElements(elements_kind, size);
1843 BuildInitializeElementsHeader(elements, elements_kind, length);
1844
1845 if (!elements->has_size_upper_bound()) {
1846 HConstant* size_in_bytes_upper_bound = EstablishElementsAllocationSize(
1847 elements_kind, max_length->Integer32Value());
1848 elements->set_size_upper_bound(size_in_bytes_upper_bound);
1849 }
1850
1851 Add<HStoreNamedField>(
1852 result, HObjectAccess::ForJSArrayOffset(JSArray::kElementsOffset),
1853 elements);
1854
1855 // Initialize the elements contents with undefined.
1856 BuildFillElementsWithValue(
1857 elements, elements_kind, graph()->GetConstant0(), length,
1858 graph()->GetConstantUndefined());
1859
1860 return result;
1861}
1862
1863
1864HValue* HGraphBuilder::BuildNumberToString(HValue* object, Type* type) {
1865 NoObservableSideEffectsScope scope(this);
1866
1867 // Convert constant numbers at compile time.
1868 if (object->IsConstant() && HConstant::cast(object)->HasNumberValue()) {
1869 Handle<Object> number = HConstant::cast(object)->handle(isolate());
1870 Handle<String> result = isolate()->factory()->NumberToString(number);
1871 return Add<HConstant>(result);
1872 }
1873
1874 // Create a joinable continuation.
1875 HIfContinuation found(graph()->CreateBasicBlock(),
1876 graph()->CreateBasicBlock());
1877
1878 // Load the number string cache.
1879 HValue* number_string_cache =
1880 Add<HLoadRoot>(Heap::kNumberStringCacheRootIndex);
1881
1882 // Make the hash mask from the length of the number string cache. It
1883 // contains two elements (number and string) for each cache entry.
1884 HValue* mask = AddLoadFixedArrayLength(number_string_cache);
1885 mask->set_type(HType::Smi());
1886 mask = AddUncasted<HSar>(mask, graph()->GetConstant1());
1887 mask = AddUncasted<HSub>(mask, graph()->GetConstant1());
1888
1889 // Check whether object is a smi.
1890 IfBuilder if_objectissmi(this);
1891 if_objectissmi.If<HIsSmiAndBranch>(object);
1892 if_objectissmi.Then();
1893 {
1894 // Compute hash for smi similar to smi_get_hash().
1895 HValue* hash = AddUncasted<HBitwise>(Token::BIT_AND, object, mask);
1896
1897 // Load the key.
1898 HValue* key_index = AddUncasted<HShl>(hash, graph()->GetConstant1());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001899 HValue* key = Add<HLoadKeyed>(number_string_cache, key_index, nullptr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001900 FAST_ELEMENTS, ALLOW_RETURN_HOLE);
1901
1902 // Check if object == key.
1903 IfBuilder if_objectiskey(this);
1904 if_objectiskey.If<HCompareObjectEqAndBranch>(object, key);
1905 if_objectiskey.Then();
1906 {
1907 // Make the key_index available.
1908 Push(key_index);
1909 }
1910 if_objectiskey.JoinContinuation(&found);
1911 }
1912 if_objectissmi.Else();
1913 {
1914 if (type->Is(Type::SignedSmall())) {
1915 if_objectissmi.Deopt("Expected smi");
1916 } else {
1917 // Check if the object is a heap number.
1918 IfBuilder if_objectisnumber(this);
1919 HValue* objectisnumber = if_objectisnumber.If<HCompareMap>(
1920 object, isolate()->factory()->heap_number_map());
1921 if_objectisnumber.Then();
1922 {
1923 // Compute hash for heap number similar to double_get_hash().
1924 HValue* low = Add<HLoadNamedField>(
1925 object, objectisnumber,
1926 HObjectAccess::ForHeapNumberValueLowestBits());
1927 HValue* high = Add<HLoadNamedField>(
1928 object, objectisnumber,
1929 HObjectAccess::ForHeapNumberValueHighestBits());
1930 HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, low, high);
1931 hash = AddUncasted<HBitwise>(Token::BIT_AND, hash, mask);
1932
1933 // Load the key.
1934 HValue* key_index = AddUncasted<HShl>(hash, graph()->GetConstant1());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001935 HValue* key = Add<HLoadKeyed>(number_string_cache, key_index, nullptr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001936 FAST_ELEMENTS, ALLOW_RETURN_HOLE);
1937
1938 // Check if the key is a heap number and compare it with the object.
1939 IfBuilder if_keyisnotsmi(this);
1940 HValue* keyisnotsmi = if_keyisnotsmi.IfNot<HIsSmiAndBranch>(key);
1941 if_keyisnotsmi.Then();
1942 {
1943 IfBuilder if_keyisheapnumber(this);
1944 if_keyisheapnumber.If<HCompareMap>(
1945 key, isolate()->factory()->heap_number_map());
1946 if_keyisheapnumber.Then();
1947 {
1948 // Check if values of key and object match.
1949 IfBuilder if_keyeqobject(this);
1950 if_keyeqobject.If<HCompareNumericAndBranch>(
1951 Add<HLoadNamedField>(key, keyisnotsmi,
1952 HObjectAccess::ForHeapNumberValue()),
1953 Add<HLoadNamedField>(object, objectisnumber,
1954 HObjectAccess::ForHeapNumberValue()),
1955 Token::EQ);
1956 if_keyeqobject.Then();
1957 {
1958 // Make the key_index available.
1959 Push(key_index);
1960 }
1961 if_keyeqobject.JoinContinuation(&found);
1962 }
1963 if_keyisheapnumber.JoinContinuation(&found);
1964 }
1965 if_keyisnotsmi.JoinContinuation(&found);
1966 }
1967 if_objectisnumber.Else();
1968 {
1969 if (type->Is(Type::Number())) {
1970 if_objectisnumber.Deopt("Expected heap number");
1971 }
1972 }
1973 if_objectisnumber.JoinContinuation(&found);
1974 }
1975 }
1976 if_objectissmi.JoinContinuation(&found);
1977
1978 // Check for cache hit.
1979 IfBuilder if_found(this, &found);
1980 if_found.Then();
1981 {
1982 // Count number to string operation in native code.
1983 AddIncrementCounter(isolate()->counters()->number_to_string_native());
1984
1985 // Load the value in case of cache hit.
1986 HValue* key_index = Pop();
1987 HValue* value_index = AddUncasted<HAdd>(key_index, graph()->GetConstant1());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001988 Push(Add<HLoadKeyed>(number_string_cache, value_index, nullptr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001989 FAST_ELEMENTS, ALLOW_RETURN_HOLE));
1990 }
1991 if_found.Else();
1992 {
1993 // Cache miss, fallback to runtime.
1994 Add<HPushArguments>(object);
1995 Push(Add<HCallRuntime>(
1996 isolate()->factory()->empty_string(),
1997 Runtime::FunctionForId(Runtime::kNumberToStringSkipCache),
1998 1));
1999 }
2000 if_found.End();
2001
2002 return Pop();
2003}
2004
2005
2006HAllocate* HGraphBuilder::BuildAllocate(
2007 HValue* object_size,
2008 HType type,
2009 InstanceType instance_type,
2010 HAllocationMode allocation_mode) {
2011 // Compute the effective allocation size.
2012 HValue* size = object_size;
2013 if (allocation_mode.CreateAllocationMementos()) {
2014 size = AddUncasted<HAdd>(size, Add<HConstant>(AllocationMemento::kSize));
2015 size->ClearFlag(HValue::kCanOverflow);
2016 }
2017
2018 // Perform the actual allocation.
2019 HAllocate* object = Add<HAllocate>(
2020 size, type, allocation_mode.GetPretenureMode(),
2021 instance_type, allocation_mode.feedback_site());
2022
2023 // Setup the allocation memento.
2024 if (allocation_mode.CreateAllocationMementos()) {
2025 BuildCreateAllocationMemento(
2026 object, object_size, allocation_mode.current_site());
2027 }
2028
2029 return object;
2030}
2031
2032
2033HValue* HGraphBuilder::BuildAddStringLengths(HValue* left_length,
2034 HValue* right_length) {
2035 // Compute the combined string length and check against max string length.
2036 HValue* length = AddUncasted<HAdd>(left_length, right_length);
2037 // Check that length <= kMaxLength <=> length < MaxLength + 1.
2038 HValue* max_length = Add<HConstant>(String::kMaxLength + 1);
2039 Add<HBoundsCheck>(length, max_length);
2040 return length;
2041}
2042
2043
2044HValue* HGraphBuilder::BuildCreateConsString(
2045 HValue* length,
2046 HValue* left,
2047 HValue* right,
2048 HAllocationMode allocation_mode) {
2049 // Determine the string instance types.
2050 HInstruction* left_instance_type = AddLoadStringInstanceType(left);
2051 HInstruction* right_instance_type = AddLoadStringInstanceType(right);
2052
2053 // Allocate the cons string object. HAllocate does not care whether we
2054 // pass CONS_STRING_TYPE or CONS_ONE_BYTE_STRING_TYPE here, so we just use
2055 // CONS_STRING_TYPE here. Below we decide whether the cons string is
2056 // one-byte or two-byte and set the appropriate map.
2057 DCHECK(HAllocate::CompatibleInstanceTypes(CONS_STRING_TYPE,
2058 CONS_ONE_BYTE_STRING_TYPE));
2059 HAllocate* result = BuildAllocate(Add<HConstant>(ConsString::kSize),
2060 HType::String(), CONS_STRING_TYPE,
2061 allocation_mode);
2062
2063 // Compute intersection and difference of instance types.
2064 HValue* anded_instance_types = AddUncasted<HBitwise>(
2065 Token::BIT_AND, left_instance_type, right_instance_type);
2066 HValue* xored_instance_types = AddUncasted<HBitwise>(
2067 Token::BIT_XOR, left_instance_type, right_instance_type);
2068
2069 // We create a one-byte cons string if
2070 // 1. both strings are one-byte, or
2071 // 2. at least one of the strings is two-byte, but happens to contain only
2072 // one-byte characters.
2073 // To do this, we check
2074 // 1. if both strings are one-byte, or if the one-byte data hint is set in
2075 // both strings, or
2076 // 2. if one of the strings has the one-byte data hint set and the other
2077 // string is one-byte.
2078 IfBuilder if_onebyte(this);
2079 STATIC_ASSERT(kOneByteStringTag != 0);
2080 STATIC_ASSERT(kOneByteDataHintMask != 0);
2081 if_onebyte.If<HCompareNumericAndBranch>(
2082 AddUncasted<HBitwise>(
2083 Token::BIT_AND, anded_instance_types,
2084 Add<HConstant>(static_cast<int32_t>(
2085 kStringEncodingMask | kOneByteDataHintMask))),
2086 graph()->GetConstant0(), Token::NE);
2087 if_onebyte.Or();
2088 STATIC_ASSERT(kOneByteStringTag != 0 &&
2089 kOneByteDataHintTag != 0 &&
2090 kOneByteDataHintTag != kOneByteStringTag);
2091 if_onebyte.If<HCompareNumericAndBranch>(
2092 AddUncasted<HBitwise>(
2093 Token::BIT_AND, xored_instance_types,
2094 Add<HConstant>(static_cast<int32_t>(
2095 kOneByteStringTag | kOneByteDataHintTag))),
2096 Add<HConstant>(static_cast<int32_t>(
2097 kOneByteStringTag | kOneByteDataHintTag)), Token::EQ);
2098 if_onebyte.Then();
2099 {
2100 // We can safely skip the write barrier for storing the map here.
2101 Add<HStoreNamedField>(
2102 result, HObjectAccess::ForMap(),
2103 Add<HConstant>(isolate()->factory()->cons_one_byte_string_map()));
2104 }
2105 if_onebyte.Else();
2106 {
2107 // We can safely skip the write barrier for storing the map here.
2108 Add<HStoreNamedField>(
2109 result, HObjectAccess::ForMap(),
2110 Add<HConstant>(isolate()->factory()->cons_string_map()));
2111 }
2112 if_onebyte.End();
2113
2114 // Initialize the cons string fields.
2115 Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(),
2116 Add<HConstant>(String::kEmptyHashField));
2117 Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length);
2118 Add<HStoreNamedField>(result, HObjectAccess::ForConsStringFirst(), left);
2119 Add<HStoreNamedField>(result, HObjectAccess::ForConsStringSecond(), right);
2120
2121 // Count the native string addition.
2122 AddIncrementCounter(isolate()->counters()->string_add_native());
2123
2124 return result;
2125}
2126
2127
2128void HGraphBuilder::BuildCopySeqStringChars(HValue* src,
2129 HValue* src_offset,
2130 String::Encoding src_encoding,
2131 HValue* dst,
2132 HValue* dst_offset,
2133 String::Encoding dst_encoding,
2134 HValue* length) {
2135 DCHECK(dst_encoding != String::ONE_BYTE_ENCODING ||
2136 src_encoding == String::ONE_BYTE_ENCODING);
2137 LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement);
2138 HValue* index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT);
2139 {
2140 HValue* src_index = AddUncasted<HAdd>(src_offset, index);
2141 HValue* value =
2142 AddUncasted<HSeqStringGetChar>(src_encoding, src, src_index);
2143 HValue* dst_index = AddUncasted<HAdd>(dst_offset, index);
2144 Add<HSeqStringSetChar>(dst_encoding, dst, dst_index, value);
2145 }
2146 loop.EndBody();
2147}
2148
2149
2150HValue* HGraphBuilder::BuildObjectSizeAlignment(
2151 HValue* unaligned_size, int header_size) {
2152 DCHECK((header_size & kObjectAlignmentMask) == 0);
2153 HValue* size = AddUncasted<HAdd>(
2154 unaligned_size, Add<HConstant>(static_cast<int32_t>(
2155 header_size + kObjectAlignmentMask)));
2156 size->ClearFlag(HValue::kCanOverflow);
2157 return AddUncasted<HBitwise>(
2158 Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>(
2159 ~kObjectAlignmentMask)));
2160}
2161
2162
2163HValue* HGraphBuilder::BuildUncheckedStringAdd(
2164 HValue* left,
2165 HValue* right,
2166 HAllocationMode allocation_mode) {
2167 // Determine the string lengths.
2168 HValue* left_length = AddLoadStringLength(left);
2169 HValue* right_length = AddLoadStringLength(right);
2170
2171 // Compute the combined string length.
2172 HValue* length = BuildAddStringLengths(left_length, right_length);
2173
2174 // Do some manual constant folding here.
2175 if (left_length->IsConstant()) {
2176 HConstant* c_left_length = HConstant::cast(left_length);
2177 DCHECK_NE(0, c_left_length->Integer32Value());
2178 if (c_left_length->Integer32Value() + 1 >= ConsString::kMinLength) {
2179 // The right string contains at least one character.
2180 return BuildCreateConsString(length, left, right, allocation_mode);
2181 }
2182 } else if (right_length->IsConstant()) {
2183 HConstant* c_right_length = HConstant::cast(right_length);
2184 DCHECK_NE(0, c_right_length->Integer32Value());
2185 if (c_right_length->Integer32Value() + 1 >= ConsString::kMinLength) {
2186 // The left string contains at least one character.
2187 return BuildCreateConsString(length, left, right, allocation_mode);
2188 }
2189 }
2190
2191 // Check if we should create a cons string.
2192 IfBuilder if_createcons(this);
2193 if_createcons.If<HCompareNumericAndBranch>(
2194 length, Add<HConstant>(ConsString::kMinLength), Token::GTE);
2195 if_createcons.Then();
2196 {
2197 // Create a cons string.
2198 Push(BuildCreateConsString(length, left, right, allocation_mode));
2199 }
2200 if_createcons.Else();
2201 {
2202 // Determine the string instance types.
2203 HValue* left_instance_type = AddLoadStringInstanceType(left);
2204 HValue* right_instance_type = AddLoadStringInstanceType(right);
2205
2206 // Compute union and difference of instance types.
2207 HValue* ored_instance_types = AddUncasted<HBitwise>(
2208 Token::BIT_OR, left_instance_type, right_instance_type);
2209 HValue* xored_instance_types = AddUncasted<HBitwise>(
2210 Token::BIT_XOR, left_instance_type, right_instance_type);
2211
2212 // Check if both strings have the same encoding and both are
2213 // sequential.
2214 IfBuilder if_sameencodingandsequential(this);
2215 if_sameencodingandsequential.If<HCompareNumericAndBranch>(
2216 AddUncasted<HBitwise>(
2217 Token::BIT_AND, xored_instance_types,
2218 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))),
2219 graph()->GetConstant0(), Token::EQ);
2220 if_sameencodingandsequential.And();
2221 STATIC_ASSERT(kSeqStringTag == 0);
2222 if_sameencodingandsequential.If<HCompareNumericAndBranch>(
2223 AddUncasted<HBitwise>(
2224 Token::BIT_AND, ored_instance_types,
2225 Add<HConstant>(static_cast<int32_t>(kStringRepresentationMask))),
2226 graph()->GetConstant0(), Token::EQ);
2227 if_sameencodingandsequential.Then();
2228 {
2229 HConstant* string_map =
2230 Add<HConstant>(isolate()->factory()->string_map());
2231 HConstant* one_byte_string_map =
2232 Add<HConstant>(isolate()->factory()->one_byte_string_map());
2233
2234 // Determine map and size depending on whether result is one-byte string.
2235 IfBuilder if_onebyte(this);
2236 STATIC_ASSERT(kOneByteStringTag != 0);
2237 if_onebyte.If<HCompareNumericAndBranch>(
2238 AddUncasted<HBitwise>(
2239 Token::BIT_AND, ored_instance_types,
2240 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))),
2241 graph()->GetConstant0(), Token::NE);
2242 if_onebyte.Then();
2243 {
2244 // Allocate sequential one-byte string object.
2245 Push(length);
2246 Push(one_byte_string_map);
2247 }
2248 if_onebyte.Else();
2249 {
2250 // Allocate sequential two-byte string object.
2251 HValue* size = AddUncasted<HShl>(length, graph()->GetConstant1());
2252 size->ClearFlag(HValue::kCanOverflow);
2253 size->SetFlag(HValue::kUint32);
2254 Push(size);
2255 Push(string_map);
2256 }
2257 if_onebyte.End();
2258 HValue* map = Pop();
2259
2260 // Calculate the number of bytes needed for the characters in the
2261 // string while observing object alignment.
2262 STATIC_ASSERT((SeqString::kHeaderSize & kObjectAlignmentMask) == 0);
2263 HValue* size = BuildObjectSizeAlignment(Pop(), SeqString::kHeaderSize);
2264
2265 // Allocate the string object. HAllocate does not care whether we pass
2266 // STRING_TYPE or ONE_BYTE_STRING_TYPE here, so we just use STRING_TYPE.
2267 HAllocate* result = BuildAllocate(
2268 size, HType::String(), STRING_TYPE, allocation_mode);
2269 Add<HStoreNamedField>(result, HObjectAccess::ForMap(), map);
2270
2271 // Initialize the string fields.
2272 Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(),
2273 Add<HConstant>(String::kEmptyHashField));
2274 Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length);
2275
2276 // Copy characters to the result string.
2277 IfBuilder if_twobyte(this);
2278 if_twobyte.If<HCompareObjectEqAndBranch>(map, string_map);
2279 if_twobyte.Then();
2280 {
2281 // Copy characters from the left string.
2282 BuildCopySeqStringChars(
2283 left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
2284 result, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
2285 left_length);
2286
2287 // Copy characters from the right string.
2288 BuildCopySeqStringChars(
2289 right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
2290 result, left_length, String::TWO_BYTE_ENCODING,
2291 right_length);
2292 }
2293 if_twobyte.Else();
2294 {
2295 // Copy characters from the left string.
2296 BuildCopySeqStringChars(
2297 left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
2298 result, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
2299 left_length);
2300
2301 // Copy characters from the right string.
2302 BuildCopySeqStringChars(
2303 right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
2304 result, left_length, String::ONE_BYTE_ENCODING,
2305 right_length);
2306 }
2307 if_twobyte.End();
2308
2309 // Count the native string addition.
2310 AddIncrementCounter(isolate()->counters()->string_add_native());
2311
2312 // Return the sequential string.
2313 Push(result);
2314 }
2315 if_sameencodingandsequential.Else();
2316 {
2317 // Fallback to the runtime to add the two strings.
2318 Add<HPushArguments>(left, right);
2319 Push(Add<HCallRuntime>(
2320 isolate()->factory()->empty_string(),
2321 Runtime::FunctionForId(Runtime::kStringAdd),
2322 2));
2323 }
2324 if_sameencodingandsequential.End();
2325 }
2326 if_createcons.End();
2327
2328 return Pop();
2329}
2330
2331
2332HValue* HGraphBuilder::BuildStringAdd(
2333 HValue* left,
2334 HValue* right,
2335 HAllocationMode allocation_mode) {
2336 NoObservableSideEffectsScope no_effects(this);
2337
2338 // Determine string lengths.
2339 HValue* left_length = AddLoadStringLength(left);
2340 HValue* right_length = AddLoadStringLength(right);
2341
2342 // Check if left string is empty.
2343 IfBuilder if_leftempty(this);
2344 if_leftempty.If<HCompareNumericAndBranch>(
2345 left_length, graph()->GetConstant0(), Token::EQ);
2346 if_leftempty.Then();
2347 {
2348 // Count the native string addition.
2349 AddIncrementCounter(isolate()->counters()->string_add_native());
2350
2351 // Just return the right string.
2352 Push(right);
2353 }
2354 if_leftempty.Else();
2355 {
2356 // Check if right string is empty.
2357 IfBuilder if_rightempty(this);
2358 if_rightempty.If<HCompareNumericAndBranch>(
2359 right_length, graph()->GetConstant0(), Token::EQ);
2360 if_rightempty.Then();
2361 {
2362 // Count the native string addition.
2363 AddIncrementCounter(isolate()->counters()->string_add_native());
2364
2365 // Just return the left string.
2366 Push(left);
2367 }
2368 if_rightempty.Else();
2369 {
2370 // Add the two non-empty strings.
2371 Push(BuildUncheckedStringAdd(left, right, allocation_mode));
2372 }
2373 if_rightempty.End();
2374 }
2375 if_leftempty.End();
2376
2377 return Pop();
2378}
2379
2380
2381HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
2382 HValue* checked_object,
2383 HValue* key,
2384 HValue* val,
2385 bool is_js_array,
2386 ElementsKind elements_kind,
2387 PropertyAccessType access_type,
2388 LoadKeyedHoleMode load_mode,
2389 KeyedAccessStoreMode store_mode) {
2390 DCHECK((!IsExternalArrayElementsKind(elements_kind) &&
2391 !IsFixedTypedArrayElementsKind(elements_kind)) ||
2392 !is_js_array);
2393 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency
2394 // on a HElementsTransition instruction. The flag can also be removed if the
2395 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further
2396 // ElementsKind transitions. Finally, the dependency can be removed for stores
2397 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the
2398 // generated store code.
2399 if ((elements_kind == FAST_HOLEY_ELEMENTS) ||
2400 (elements_kind == FAST_ELEMENTS && access_type == STORE)) {
2401 checked_object->ClearDependsOnFlag(kElementsKind);
2402 }
2403
2404 bool fast_smi_only_elements = IsFastSmiElementsKind(elements_kind);
2405 bool fast_elements = IsFastObjectElementsKind(elements_kind);
2406 HValue* elements = AddLoadElements(checked_object);
2407 if (access_type == STORE && (fast_elements || fast_smi_only_elements) &&
2408 store_mode != STORE_NO_TRANSITION_HANDLE_COW) {
2409 HCheckMaps* check_cow_map = Add<HCheckMaps>(
2410 elements, isolate()->factory()->fixed_array_map());
2411 check_cow_map->ClearDependsOnFlag(kElementsKind);
2412 }
2413 HInstruction* length = NULL;
2414 if (is_js_array) {
2415 length = Add<HLoadNamedField>(
2416 checked_object->ActualValue(), checked_object,
2417 HObjectAccess::ForArrayLength(elements_kind));
2418 } else {
2419 length = AddLoadFixedArrayLength(elements);
2420 }
2421 length->set_type(HType::Smi());
2422 HValue* checked_key = NULL;
2423 if (IsExternalArrayElementsKind(elements_kind) ||
2424 IsFixedTypedArrayElementsKind(elements_kind)) {
2425 HValue* backing_store;
2426 if (IsExternalArrayElementsKind(elements_kind)) {
2427 backing_store = Add<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002428 elements, nullptr, HObjectAccess::ForExternalArrayExternalPointer());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002429 } else {
2430 backing_store = elements;
2431 }
2432 if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
2433 NoObservableSideEffectsScope no_effects(this);
2434 IfBuilder length_checker(this);
2435 length_checker.If<HCompareNumericAndBranch>(key, length, Token::LT);
2436 length_checker.Then();
2437 IfBuilder negative_checker(this);
2438 HValue* bounds_check = negative_checker.If<HCompareNumericAndBranch>(
2439 key, graph()->GetConstant0(), Token::GTE);
2440 negative_checker.Then();
2441 HInstruction* result = AddElementAccess(
2442 backing_store, key, val, bounds_check, elements_kind, access_type);
2443 negative_checker.ElseDeopt("Negative key encountered");
2444 negative_checker.End();
2445 length_checker.End();
2446 return result;
2447 } else {
2448 DCHECK(store_mode == STANDARD_STORE);
2449 checked_key = Add<HBoundsCheck>(key, length);
2450 return AddElementAccess(
2451 backing_store, checked_key, val,
2452 checked_object, elements_kind, access_type);
2453 }
2454 }
2455 DCHECK(fast_smi_only_elements ||
2456 fast_elements ||
2457 IsFastDoubleElementsKind(elements_kind));
2458
2459 // In case val is stored into a fast smi array, assure that the value is a smi
2460 // before manipulating the backing store. Otherwise the actual store may
2461 // deopt, leaving the backing store in an invalid state.
2462 if (access_type == STORE && IsFastSmiElementsKind(elements_kind) &&
2463 !val->type().IsSmi()) {
2464 val = AddUncasted<HForceRepresentation>(val, Representation::Smi());
2465 }
2466
2467 if (IsGrowStoreMode(store_mode)) {
2468 NoObservableSideEffectsScope no_effects(this);
2469 Representation representation = HStoreKeyed::RequiredValueRepresentation(
2470 elements_kind, STORE_TO_INITIALIZED_ENTRY);
2471 val = AddUncasted<HForceRepresentation>(val, representation);
2472 elements = BuildCheckForCapacityGrow(checked_object, elements,
2473 elements_kind, length, key,
2474 is_js_array, access_type);
2475 checked_key = key;
2476 } else {
2477 checked_key = Add<HBoundsCheck>(key, length);
2478
2479 if (access_type == STORE && (fast_elements || fast_smi_only_elements)) {
2480 if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) {
2481 NoObservableSideEffectsScope no_effects(this);
2482 elements = BuildCopyElementsOnWrite(checked_object, elements,
2483 elements_kind, length);
2484 } else {
2485 HCheckMaps* check_cow_map = Add<HCheckMaps>(
2486 elements, isolate()->factory()->fixed_array_map());
2487 check_cow_map->ClearDependsOnFlag(kElementsKind);
2488 }
2489 }
2490 }
2491 return AddElementAccess(elements, checked_key, val, checked_object,
2492 elements_kind, access_type, load_mode);
2493}
2494
2495
2496HValue* HGraphBuilder::BuildAllocateArrayFromLength(
2497 JSArrayBuilder* array_builder,
2498 HValue* length_argument) {
2499 if (length_argument->IsConstant() &&
2500 HConstant::cast(length_argument)->HasSmiValue()) {
2501 int array_length = HConstant::cast(length_argument)->Integer32Value();
2502 if (array_length == 0) {
2503 return array_builder->AllocateEmptyArray();
2504 } else {
2505 return array_builder->AllocateArray(length_argument,
2506 array_length,
2507 length_argument);
2508 }
2509 }
2510
2511 HValue* constant_zero = graph()->GetConstant0();
2512 HConstant* max_alloc_length =
2513 Add<HConstant>(JSObject::kInitialMaxFastElementArray);
2514 HInstruction* checked_length = Add<HBoundsCheck>(length_argument,
2515 max_alloc_length);
2516 IfBuilder if_builder(this);
2517 if_builder.If<HCompareNumericAndBranch>(checked_length, constant_zero,
2518 Token::EQ);
2519 if_builder.Then();
2520 const int initial_capacity = JSArray::kPreallocatedArrayElements;
2521 HConstant* initial_capacity_node = Add<HConstant>(initial_capacity);
2522 Push(initial_capacity_node); // capacity
2523 Push(constant_zero); // length
2524 if_builder.Else();
2525 if (!(top_info()->IsStub()) &&
2526 IsFastPackedElementsKind(array_builder->kind())) {
2527 // We'll come back later with better (holey) feedback.
2528 if_builder.Deopt("Holey array despite packed elements_kind feedback");
2529 } else {
2530 Push(checked_length); // capacity
2531 Push(checked_length); // length
2532 }
2533 if_builder.End();
2534
2535 // Figure out total size
2536 HValue* length = Pop();
2537 HValue* capacity = Pop();
2538 return array_builder->AllocateArray(capacity, max_alloc_length, length);
2539}
2540
2541
2542HValue* HGraphBuilder::BuildCalculateElementsSize(ElementsKind kind,
2543 HValue* capacity) {
2544 int elements_size = IsFastDoubleElementsKind(kind)
2545 ? kDoubleSize
2546 : kPointerSize;
2547
2548 HConstant* elements_size_value = Add<HConstant>(elements_size);
2549 HInstruction* mul = HMul::NewImul(zone(), context(),
2550 capacity->ActualValue(),
2551 elements_size_value);
2552 AddInstruction(mul);
2553 mul->ClearFlag(HValue::kCanOverflow);
2554
2555 STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize);
2556
2557 HConstant* header_size = Add<HConstant>(FixedArray::kHeaderSize);
2558 HValue* total_size = AddUncasted<HAdd>(mul, header_size);
2559 total_size->ClearFlag(HValue::kCanOverflow);
2560 return total_size;
2561}
2562
2563
2564HAllocate* HGraphBuilder::AllocateJSArrayObject(AllocationSiteMode mode) {
2565 int base_size = JSArray::kSize;
2566 if (mode == TRACK_ALLOCATION_SITE) {
2567 base_size += AllocationMemento::kSize;
2568 }
2569 HConstant* size_in_bytes = Add<HConstant>(base_size);
2570 return Add<HAllocate>(
2571 size_in_bytes, HType::JSArray(), NOT_TENURED, JS_OBJECT_TYPE);
2572}
2573
2574
2575HConstant* HGraphBuilder::EstablishElementsAllocationSize(
2576 ElementsKind kind,
2577 int capacity) {
2578 int base_size = IsFastDoubleElementsKind(kind)
2579 ? FixedDoubleArray::SizeFor(capacity)
2580 : FixedArray::SizeFor(capacity);
2581
2582 return Add<HConstant>(base_size);
2583}
2584
2585
2586HAllocate* HGraphBuilder::BuildAllocateElements(ElementsKind kind,
2587 HValue* size_in_bytes) {
2588 InstanceType instance_type = IsFastDoubleElementsKind(kind)
2589 ? FIXED_DOUBLE_ARRAY_TYPE
2590 : FIXED_ARRAY_TYPE;
2591
2592 return Add<HAllocate>(size_in_bytes, HType::HeapObject(), NOT_TENURED,
2593 instance_type);
2594}
2595
2596
2597void HGraphBuilder::BuildInitializeElementsHeader(HValue* elements,
2598 ElementsKind kind,
2599 HValue* capacity) {
2600 Factory* factory = isolate()->factory();
2601 Handle<Map> map = IsFastDoubleElementsKind(kind)
2602 ? factory->fixed_double_array_map()
2603 : factory->fixed_array_map();
2604
2605 Add<HStoreNamedField>(elements, HObjectAccess::ForMap(), Add<HConstant>(map));
2606 Add<HStoreNamedField>(elements, HObjectAccess::ForFixedArrayLength(),
2607 capacity);
2608}
2609
2610
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002611HValue* HGraphBuilder::BuildAllocateAndInitializeArray(ElementsKind kind,
2612 HValue* capacity) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002613 // The HForceRepresentation is to prevent possible deopt on int-smi
2614 // conversion after allocation but before the new object fields are set.
2615 capacity = AddUncasted<HForceRepresentation>(capacity, Representation::Smi());
2616 HValue* size_in_bytes = BuildCalculateElementsSize(kind, capacity);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002617 HValue* new_array = BuildAllocateElements(kind, size_in_bytes);
2618 BuildInitializeElementsHeader(new_array, kind, capacity);
2619 return new_array;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002620}
2621
2622
2623void HGraphBuilder::BuildJSArrayHeader(HValue* array,
2624 HValue* array_map,
2625 HValue* elements,
2626 AllocationSiteMode mode,
2627 ElementsKind elements_kind,
2628 HValue* allocation_site_payload,
2629 HValue* length_field) {
2630 Add<HStoreNamedField>(array, HObjectAccess::ForMap(), array_map);
2631
2632 HConstant* empty_fixed_array =
2633 Add<HConstant>(isolate()->factory()->empty_fixed_array());
2634
2635 Add<HStoreNamedField>(
2636 array, HObjectAccess::ForPropertiesPointer(), empty_fixed_array);
2637
2638 Add<HStoreNamedField>(
2639 array, HObjectAccess::ForElementsPointer(),
2640 elements != NULL ? elements : empty_fixed_array);
2641
2642 Add<HStoreNamedField>(
2643 array, HObjectAccess::ForArrayLength(elements_kind), length_field);
2644
2645 if (mode == TRACK_ALLOCATION_SITE) {
2646 BuildCreateAllocationMemento(
2647 array, Add<HConstant>(JSArray::kSize), allocation_site_payload);
2648 }
2649}
2650
2651
2652HInstruction* HGraphBuilder::AddElementAccess(
2653 HValue* elements,
2654 HValue* checked_key,
2655 HValue* val,
2656 HValue* dependency,
2657 ElementsKind elements_kind,
2658 PropertyAccessType access_type,
2659 LoadKeyedHoleMode load_mode) {
2660 if (access_type == STORE) {
2661 DCHECK(val != NULL);
2662 if (elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS ||
2663 elements_kind == UINT8_CLAMPED_ELEMENTS) {
2664 val = Add<HClampToUint8>(val);
2665 }
2666 return Add<HStoreKeyed>(elements, checked_key, val, elements_kind,
2667 STORE_TO_INITIALIZED_ENTRY);
2668 }
2669
2670 DCHECK(access_type == LOAD);
2671 DCHECK(val == NULL);
2672 HLoadKeyed* load = Add<HLoadKeyed>(
2673 elements, checked_key, dependency, elements_kind, load_mode);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002674 if (elements_kind == EXTERNAL_UINT32_ELEMENTS ||
2675 elements_kind == UINT32_ELEMENTS) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002676 graph()->RecordUint32Instruction(load);
2677 }
2678 return load;
2679}
2680
2681
2682HLoadNamedField* HGraphBuilder::AddLoadMap(HValue* object,
2683 HValue* dependency) {
2684 return Add<HLoadNamedField>(object, dependency, HObjectAccess::ForMap());
2685}
2686
2687
2688HLoadNamedField* HGraphBuilder::AddLoadElements(HValue* object,
2689 HValue* dependency) {
2690 return Add<HLoadNamedField>(
2691 object, dependency, HObjectAccess::ForElementsPointer());
2692}
2693
2694
2695HLoadNamedField* HGraphBuilder::AddLoadFixedArrayLength(
2696 HValue* array,
2697 HValue* dependency) {
2698 return Add<HLoadNamedField>(
2699 array, dependency, HObjectAccess::ForFixedArrayLength());
2700}
2701
2702
2703HLoadNamedField* HGraphBuilder::AddLoadArrayLength(HValue* array,
2704 ElementsKind kind,
2705 HValue* dependency) {
2706 return Add<HLoadNamedField>(
2707 array, dependency, HObjectAccess::ForArrayLength(kind));
2708}
2709
2710
2711HValue* HGraphBuilder::BuildNewElementsCapacity(HValue* old_capacity) {
2712 HValue* half_old_capacity = AddUncasted<HShr>(old_capacity,
2713 graph_->GetConstant1());
2714
2715 HValue* new_capacity = AddUncasted<HAdd>(half_old_capacity, old_capacity);
2716 new_capacity->ClearFlag(HValue::kCanOverflow);
2717
2718 HValue* min_growth = Add<HConstant>(16);
2719
2720 new_capacity = AddUncasted<HAdd>(new_capacity, min_growth);
2721 new_capacity->ClearFlag(HValue::kCanOverflow);
2722
2723 return new_capacity;
2724}
2725
2726
2727HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object,
2728 HValue* elements,
2729 ElementsKind kind,
2730 ElementsKind new_kind,
2731 HValue* length,
2732 HValue* new_capacity) {
2733 Add<HBoundsCheck>(new_capacity, Add<HConstant>(
2734 (Page::kMaxRegularHeapObjectSize - FixedArray::kHeaderSize) >>
2735 ElementsKindToShiftSize(new_kind)));
2736
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002737 HValue* new_elements =
2738 BuildAllocateAndInitializeArray(new_kind, new_capacity);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002739
2740 BuildCopyElements(elements, kind, new_elements,
2741 new_kind, length, new_capacity);
2742
2743 Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
2744 new_elements);
2745
2746 return new_elements;
2747}
2748
2749
2750void HGraphBuilder::BuildFillElementsWithValue(HValue* elements,
2751 ElementsKind elements_kind,
2752 HValue* from,
2753 HValue* to,
2754 HValue* value) {
2755 if (to == NULL) {
2756 to = AddLoadFixedArrayLength(elements);
2757 }
2758
2759 // Special loop unfolding case
2760 STATIC_ASSERT(JSArray::kPreallocatedArrayElements <=
2761 kElementLoopUnrollThreshold);
2762 int initial_capacity = -1;
2763 if (from->IsInteger32Constant() && to->IsInteger32Constant()) {
2764 int constant_from = from->GetInteger32Constant();
2765 int constant_to = to->GetInteger32Constant();
2766
2767 if (constant_from == 0 && constant_to <= kElementLoopUnrollThreshold) {
2768 initial_capacity = constant_to;
2769 }
2770 }
2771
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002772 if (initial_capacity >= 0) {
2773 for (int i = 0; i < initial_capacity; i++) {
2774 HInstruction* key = Add<HConstant>(i);
2775 Add<HStoreKeyed>(elements, key, value, elements_kind);
2776 }
2777 } else {
2778 // Carefully loop backwards so that the "from" remains live through the loop
2779 // rather than the to. This often corresponds to keeping length live rather
2780 // then capacity, which helps register allocation, since length is used more
2781 // other than capacity after filling with holes.
2782 LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement);
2783
2784 HValue* key = builder.BeginBody(to, from, Token::GT);
2785
2786 HValue* adjusted_key = AddUncasted<HSub>(key, graph()->GetConstant1());
2787 adjusted_key->ClearFlag(HValue::kCanOverflow);
2788
2789 Add<HStoreKeyed>(elements, adjusted_key, value, elements_kind);
2790
2791 builder.EndBody();
2792 }
2793}
2794
2795
2796void HGraphBuilder::BuildFillElementsWithHole(HValue* elements,
2797 ElementsKind elements_kind,
2798 HValue* from,
2799 HValue* to) {
2800 // Fast elements kinds need to be initialized in case statements below cause a
2801 // garbage collection.
2802 Factory* factory = isolate()->factory();
2803
2804 double nan_double = FixedDoubleArray::hole_nan_as_double();
2805 HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind)
2806 ? Add<HConstant>(factory->the_hole_value())
2807 : Add<HConstant>(nan_double);
2808
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002809 // Since we're about to store a hole value, the store instruction below must
2810 // assume an elements kind that supports heap object values.
2811 if (IsFastSmiOrObjectElementsKind(elements_kind)) {
2812 elements_kind = FAST_HOLEY_ELEMENTS;
2813 }
2814
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002815 BuildFillElementsWithValue(elements, elements_kind, from, to, hole);
2816}
2817
2818
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002819void HGraphBuilder::BuildCopyProperties(HValue* from_properties,
2820 HValue* to_properties, HValue* length,
2821 HValue* capacity) {
2822 ElementsKind kind = FAST_ELEMENTS;
2823
2824 BuildFillElementsWithValue(to_properties, kind, length, capacity,
2825 graph()->GetConstantUndefined());
2826
2827 LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement);
2828
2829 HValue* key = builder.BeginBody(length, graph()->GetConstant0(), Token::GT);
2830
2831 key = AddUncasted<HSub>(key, graph()->GetConstant1());
2832 key->ClearFlag(HValue::kCanOverflow);
2833
2834 HValue* element = Add<HLoadKeyed>(from_properties, key, nullptr, kind);
2835
2836 Add<HStoreKeyed>(to_properties, key, element, kind);
2837
2838 builder.EndBody();
2839}
2840
2841
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002842void HGraphBuilder::BuildCopyElements(HValue* from_elements,
2843 ElementsKind from_elements_kind,
2844 HValue* to_elements,
2845 ElementsKind to_elements_kind,
2846 HValue* length,
2847 HValue* capacity) {
2848 int constant_capacity = -1;
2849 if (capacity != NULL &&
2850 capacity->IsConstant() &&
2851 HConstant::cast(capacity)->HasInteger32Value()) {
2852 int constant_candidate = HConstant::cast(capacity)->Integer32Value();
2853 if (constant_candidate <= kElementLoopUnrollThreshold) {
2854 constant_capacity = constant_candidate;
2855 }
2856 }
2857
2858 bool pre_fill_with_holes =
2859 IsFastDoubleElementsKind(from_elements_kind) &&
2860 IsFastObjectElementsKind(to_elements_kind);
2861 if (pre_fill_with_holes) {
2862 // If the copy might trigger a GC, make sure that the FixedArray is
2863 // pre-initialized with holes to make sure that it's always in a
2864 // consistent state.
2865 BuildFillElementsWithHole(to_elements, to_elements_kind,
2866 graph()->GetConstant0(), NULL);
2867 }
2868
2869 if (constant_capacity != -1) {
2870 // Unroll the loop for small elements kinds.
2871 for (int i = 0; i < constant_capacity; i++) {
2872 HValue* key_constant = Add<HConstant>(i);
2873 HInstruction* value = Add<HLoadKeyed>(from_elements, key_constant,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002874 nullptr, from_elements_kind);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002875 Add<HStoreKeyed>(to_elements, key_constant, value, to_elements_kind);
2876 }
2877 } else {
2878 if (!pre_fill_with_holes &&
2879 (capacity == NULL || !length->Equals(capacity))) {
2880 BuildFillElementsWithHole(to_elements, to_elements_kind,
2881 length, NULL);
2882 }
2883
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002884 LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement);
2885
2886 HValue* key = builder.BeginBody(length, graph()->GetConstant0(),
2887 Token::GT);
2888
2889 key = AddUncasted<HSub>(key, graph()->GetConstant1());
2890 key->ClearFlag(HValue::kCanOverflow);
2891
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002892 HValue* element = Add<HLoadKeyed>(from_elements, key, nullptr,
2893 from_elements_kind, ALLOW_RETURN_HOLE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002894
2895 ElementsKind kind = (IsHoleyElementsKind(from_elements_kind) &&
2896 IsFastSmiElementsKind(to_elements_kind))
2897 ? FAST_HOLEY_ELEMENTS : to_elements_kind;
2898
2899 if (IsHoleyElementsKind(from_elements_kind) &&
2900 from_elements_kind != to_elements_kind) {
2901 IfBuilder if_hole(this);
2902 if_hole.If<HCompareHoleAndBranch>(element);
2903 if_hole.Then();
2904 HConstant* hole_constant = IsFastDoubleElementsKind(to_elements_kind)
2905 ? Add<HConstant>(FixedDoubleArray::hole_nan_as_double())
2906 : graph()->GetConstantHole();
2907 Add<HStoreKeyed>(to_elements, key, hole_constant, kind);
2908 if_hole.Else();
2909 HStoreKeyed* store = Add<HStoreKeyed>(to_elements, key, element, kind);
2910 store->SetFlag(HValue::kAllowUndefinedAsNaN);
2911 if_hole.End();
2912 } else {
2913 HStoreKeyed* store = Add<HStoreKeyed>(to_elements, key, element, kind);
2914 store->SetFlag(HValue::kAllowUndefinedAsNaN);
2915 }
2916
2917 builder.EndBody();
2918 }
2919
2920 Counters* counters = isolate()->counters();
2921 AddIncrementCounter(counters->inlined_copied_elements());
2922}
2923
2924
2925HValue* HGraphBuilder::BuildCloneShallowArrayCow(HValue* boilerplate,
2926 HValue* allocation_site,
2927 AllocationSiteMode mode,
2928 ElementsKind kind) {
2929 HAllocate* array = AllocateJSArrayObject(mode);
2930
2931 HValue* map = AddLoadMap(boilerplate);
2932 HValue* elements = AddLoadElements(boilerplate);
2933 HValue* length = AddLoadArrayLength(boilerplate, kind);
2934
2935 BuildJSArrayHeader(array,
2936 map,
2937 elements,
2938 mode,
2939 FAST_ELEMENTS,
2940 allocation_site,
2941 length);
2942 return array;
2943}
2944
2945
2946HValue* HGraphBuilder::BuildCloneShallowArrayEmpty(HValue* boilerplate,
2947 HValue* allocation_site,
2948 AllocationSiteMode mode) {
2949 HAllocate* array = AllocateJSArrayObject(mode);
2950
2951 HValue* map = AddLoadMap(boilerplate);
2952
2953 BuildJSArrayHeader(array,
2954 map,
2955 NULL, // set elements to empty fixed array
2956 mode,
2957 FAST_ELEMENTS,
2958 allocation_site,
2959 graph()->GetConstant0());
2960 return array;
2961}
2962
2963
2964HValue* HGraphBuilder::BuildCloneShallowArrayNonEmpty(HValue* boilerplate,
2965 HValue* allocation_site,
2966 AllocationSiteMode mode,
2967 ElementsKind kind) {
2968 HValue* boilerplate_elements = AddLoadElements(boilerplate);
2969 HValue* capacity = AddLoadFixedArrayLength(boilerplate_elements);
2970
2971 // Generate size calculation code here in order to make it dominate
2972 // the JSArray allocation.
2973 HValue* elements_size = BuildCalculateElementsSize(kind, capacity);
2974
2975 // Create empty JSArray object for now, store elimination should remove
2976 // redundant initialization of elements and length fields and at the same
2977 // time the object will be fully prepared for GC if it happens during
2978 // elements allocation.
2979 HValue* result = BuildCloneShallowArrayEmpty(
2980 boilerplate, allocation_site, mode);
2981
2982 HAllocate* elements = BuildAllocateElements(kind, elements_size);
2983
2984 // This function implicitly relies on the fact that the
2985 // FastCloneShallowArrayStub is called only for literals shorter than
2986 // JSObject::kInitialMaxFastElementArray.
2987 // Can't add HBoundsCheck here because otherwise the stub will eager a frame.
2988 HConstant* size_upper_bound = EstablishElementsAllocationSize(
2989 kind, JSObject::kInitialMaxFastElementArray);
2990 elements->set_size_upper_bound(size_upper_bound);
2991
2992 Add<HStoreNamedField>(result, HObjectAccess::ForElementsPointer(), elements);
2993
2994 // The allocation for the cloned array above causes register pressure on
2995 // machines with low register counts. Force a reload of the boilerplate
2996 // elements here to free up a register for the allocation to avoid unnecessary
2997 // spillage.
2998 boilerplate_elements = AddLoadElements(boilerplate);
2999 boilerplate_elements->SetFlag(HValue::kCantBeReplaced);
3000
3001 // Copy the elements array header.
3002 for (int i = 0; i < FixedArrayBase::kHeaderSize; i += kPointerSize) {
3003 HObjectAccess access = HObjectAccess::ForFixedArrayHeader(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003004 Add<HStoreNamedField>(
3005 elements, access,
3006 Add<HLoadNamedField>(boilerplate_elements, nullptr, access));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003007 }
3008
3009 // And the result of the length
3010 HValue* length = AddLoadArrayLength(boilerplate, kind);
3011 Add<HStoreNamedField>(result, HObjectAccess::ForArrayLength(kind), length);
3012
3013 BuildCopyElements(boilerplate_elements, kind, elements,
3014 kind, length, NULL);
3015 return result;
3016}
3017
3018
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003019void HGraphBuilder::BuildCompareNil(HValue* value, Type* type,
3020 HIfContinuation* continuation,
3021 MapEmbedding map_embedding) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003022 IfBuilder if_nil(this);
3023 bool some_case_handled = false;
3024 bool some_case_missing = false;
3025
3026 if (type->Maybe(Type::Null())) {
3027 if (some_case_handled) if_nil.Or();
3028 if_nil.If<HCompareObjectEqAndBranch>(value, graph()->GetConstantNull());
3029 some_case_handled = true;
3030 } else {
3031 some_case_missing = true;
3032 }
3033
3034 if (type->Maybe(Type::Undefined())) {
3035 if (some_case_handled) if_nil.Or();
3036 if_nil.If<HCompareObjectEqAndBranch>(value,
3037 graph()->GetConstantUndefined());
3038 some_case_handled = true;
3039 } else {
3040 some_case_missing = true;
3041 }
3042
3043 if (type->Maybe(Type::Undetectable())) {
3044 if (some_case_handled) if_nil.Or();
3045 if_nil.If<HIsUndetectableAndBranch>(value);
3046 some_case_handled = true;
3047 } else {
3048 some_case_missing = true;
3049 }
3050
3051 if (some_case_missing) {
3052 if_nil.Then();
3053 if_nil.Else();
3054 if (type->NumClasses() == 1) {
3055 BuildCheckHeapObject(value);
3056 // For ICs, the map checked below is a sentinel map that gets replaced by
3057 // the monomorphic map when the code is used as a template to generate a
3058 // new IC. For optimized functions, there is no sentinel map, the map
3059 // emitted below is the actual monomorphic map.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003060 if (map_embedding == kEmbedMapsViaWeakCells) {
3061 HValue* cell =
3062 Add<HConstant>(Map::WeakCellForMap(type->Classes().Current()));
3063 HValue* expected_map = Add<HLoadNamedField>(
3064 cell, nullptr, HObjectAccess::ForWeakCellValue());
3065 HValue* map =
3066 Add<HLoadNamedField>(value, nullptr, HObjectAccess::ForMap());
3067 IfBuilder map_check(this);
3068 map_check.IfNot<HCompareObjectEqAndBranch>(expected_map, map);
3069 map_check.ThenDeopt("Unknown map");
3070 map_check.End();
3071 } else {
3072 DCHECK(map_embedding == kEmbedMapsDirectly);
3073 Add<HCheckMaps>(value, type->Classes().Current());
3074 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003075 } else {
3076 if_nil.Deopt("Too many undetectable types");
3077 }
3078 }
3079
3080 if_nil.CaptureContinuation(continuation);
3081}
3082
3083
3084void HGraphBuilder::BuildCreateAllocationMemento(
3085 HValue* previous_object,
3086 HValue* previous_object_size,
3087 HValue* allocation_site) {
3088 DCHECK(allocation_site != NULL);
3089 HInnerAllocatedObject* allocation_memento = Add<HInnerAllocatedObject>(
3090 previous_object, previous_object_size, HType::HeapObject());
3091 AddStoreMapConstant(
3092 allocation_memento, isolate()->factory()->allocation_memento_map());
3093 Add<HStoreNamedField>(
3094 allocation_memento,
3095 HObjectAccess::ForAllocationMementoSite(),
3096 allocation_site);
3097 if (FLAG_allocation_site_pretenuring) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003098 HValue* memento_create_count =
3099 Add<HLoadNamedField>(allocation_site, nullptr,
3100 HObjectAccess::ForAllocationSiteOffset(
3101 AllocationSite::kPretenureCreateCountOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003102 memento_create_count = AddUncasted<HAdd>(
3103 memento_create_count, graph()->GetConstant1());
3104 // This smi value is reset to zero after every gc, overflow isn't a problem
3105 // since the counter is bounded by the new space size.
3106 memento_create_count->ClearFlag(HValue::kCanOverflow);
3107 Add<HStoreNamedField>(
3108 allocation_site, HObjectAccess::ForAllocationSiteOffset(
3109 AllocationSite::kPretenureCreateCountOffset), memento_create_count);
3110 }
3111}
3112
3113
3114HInstruction* HGraphBuilder::BuildGetNativeContext(HValue* closure) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003115 // Get the global object, then the native context
3116 HInstruction* context = Add<HLoadNamedField>(
3117 closure, nullptr, HObjectAccess::ForFunctionContextPointer());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003118 HInstruction* global_object = Add<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003119 context, nullptr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003120 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
3121 HObjectAccess access = HObjectAccess::ForObservableJSObjectOffset(
3122 GlobalObject::kNativeContextOffset);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003123 return Add<HLoadNamedField>(global_object, nullptr, access);
3124}
3125
3126
3127HInstruction* HGraphBuilder::BuildGetScriptContext(int context_index) {
3128 HValue* native_context = BuildGetNativeContext();
3129 HValue* script_context_table = Add<HLoadNamedField>(
3130 native_context, nullptr,
3131 HObjectAccess::ForContextSlot(Context::SCRIPT_CONTEXT_TABLE_INDEX));
3132 return Add<HLoadNamedField>(script_context_table, nullptr,
3133 HObjectAccess::ForScriptContext(context_index));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003134}
3135
3136
3137HInstruction* HGraphBuilder::BuildGetNativeContext() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003138 // Get the global object, then the native context
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003139 HValue* global_object = Add<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003140 context(), nullptr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003141 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003142 return Add<HLoadNamedField>(global_object, nullptr,
3143 HObjectAccess::ForObservableJSObjectOffset(
3144 GlobalObject::kNativeContextOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003145}
3146
3147
3148HInstruction* HGraphBuilder::BuildGetArrayFunction() {
3149 HInstruction* native_context = BuildGetNativeContext();
3150 HInstruction* index =
3151 Add<HConstant>(static_cast<int32_t>(Context::ARRAY_FUNCTION_INDEX));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003152 return Add<HLoadKeyed>(native_context, index, nullptr, FAST_ELEMENTS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003153}
3154
3155
3156HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder,
3157 ElementsKind kind,
3158 HValue* allocation_site_payload,
3159 HValue* constructor_function,
3160 AllocationSiteOverrideMode override_mode) :
3161 builder_(builder),
3162 kind_(kind),
3163 allocation_site_payload_(allocation_site_payload),
3164 constructor_function_(constructor_function) {
3165 DCHECK(!allocation_site_payload->IsConstant() ||
3166 HConstant::cast(allocation_site_payload)->handle(
3167 builder_->isolate())->IsAllocationSite());
3168 mode_ = override_mode == DISABLE_ALLOCATION_SITES
3169 ? DONT_TRACK_ALLOCATION_SITE
3170 : AllocationSite::GetMode(kind);
3171}
3172
3173
3174HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder,
3175 ElementsKind kind,
3176 HValue* constructor_function) :
3177 builder_(builder),
3178 kind_(kind),
3179 mode_(DONT_TRACK_ALLOCATION_SITE),
3180 allocation_site_payload_(NULL),
3181 constructor_function_(constructor_function) {
3182}
3183
3184
3185HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode() {
3186 if (!builder()->top_info()->IsStub()) {
3187 // A constant map is fine.
3188 Handle<Map> map(builder()->isolate()->get_initial_js_array_map(kind_),
3189 builder()->isolate());
3190 return builder()->Add<HConstant>(map);
3191 }
3192
3193 if (constructor_function_ != NULL && kind_ == GetInitialFastElementsKind()) {
3194 // No need for a context lookup if the kind_ matches the initial
3195 // map, because we can just load the map in that case.
3196 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003197 return builder()->Add<HLoadNamedField>(constructor_function_, nullptr,
3198 access);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003199 }
3200
3201 // TODO(mvstanton): we should always have a constructor function if we
3202 // are creating a stub.
3203 HInstruction* native_context = constructor_function_ != NULL
3204 ? builder()->BuildGetNativeContext(constructor_function_)
3205 : builder()->BuildGetNativeContext();
3206
3207 HInstruction* index = builder()->Add<HConstant>(
3208 static_cast<int32_t>(Context::JS_ARRAY_MAPS_INDEX));
3209
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003210 HInstruction* map_array =
3211 builder()->Add<HLoadKeyed>(native_context, index, nullptr, FAST_ELEMENTS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003212
3213 HInstruction* kind_index = builder()->Add<HConstant>(kind_);
3214
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003215 return builder()->Add<HLoadKeyed>(map_array, kind_index, nullptr,
3216 FAST_ELEMENTS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003217}
3218
3219
3220HValue* HGraphBuilder::JSArrayBuilder::EmitInternalMapCode() {
3221 // Find the map near the constructor function
3222 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003223 return builder()->Add<HLoadNamedField>(constructor_function_, nullptr,
3224 access);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003225}
3226
3227
3228HAllocate* HGraphBuilder::JSArrayBuilder::AllocateEmptyArray() {
3229 HConstant* capacity = builder()->Add<HConstant>(initial_capacity());
3230 return AllocateArray(capacity,
3231 capacity,
3232 builder()->graph()->GetConstant0());
3233}
3234
3235
3236HAllocate* HGraphBuilder::JSArrayBuilder::AllocateArray(
3237 HValue* capacity,
3238 HConstant* capacity_upper_bound,
3239 HValue* length_field,
3240 FillMode fill_mode) {
3241 return AllocateArray(capacity,
3242 capacity_upper_bound->GetInteger32Constant(),
3243 length_field,
3244 fill_mode);
3245}
3246
3247
3248HAllocate* HGraphBuilder::JSArrayBuilder::AllocateArray(
3249 HValue* capacity,
3250 int capacity_upper_bound,
3251 HValue* length_field,
3252 FillMode fill_mode) {
3253 HConstant* elememts_size_upper_bound = capacity->IsInteger32Constant()
3254 ? HConstant::cast(capacity)
3255 : builder()->EstablishElementsAllocationSize(kind_, capacity_upper_bound);
3256
3257 HAllocate* array = AllocateArray(capacity, length_field, fill_mode);
3258 if (!elements_location_->has_size_upper_bound()) {
3259 elements_location_->set_size_upper_bound(elememts_size_upper_bound);
3260 }
3261 return array;
3262}
3263
3264
3265HAllocate* HGraphBuilder::JSArrayBuilder::AllocateArray(
3266 HValue* capacity,
3267 HValue* length_field,
3268 FillMode fill_mode) {
3269 // These HForceRepresentations are because we store these as fields in the
3270 // objects we construct, and an int32-to-smi HChange could deopt. Accept
3271 // the deopt possibility now, before allocation occurs.
3272 capacity =
3273 builder()->AddUncasted<HForceRepresentation>(capacity,
3274 Representation::Smi());
3275 length_field =
3276 builder()->AddUncasted<HForceRepresentation>(length_field,
3277 Representation::Smi());
3278
3279 // Generate size calculation code here in order to make it dominate
3280 // the JSArray allocation.
3281 HValue* elements_size =
3282 builder()->BuildCalculateElementsSize(kind_, capacity);
3283
3284 // Allocate (dealing with failure appropriately)
3285 HAllocate* array_object = builder()->AllocateJSArrayObject(mode_);
3286
3287 // Fill in the fields: map, properties, length
3288 HValue* map;
3289 if (allocation_site_payload_ == NULL) {
3290 map = EmitInternalMapCode();
3291 } else {
3292 map = EmitMapCode();
3293 }
3294
3295 builder()->BuildJSArrayHeader(array_object,
3296 map,
3297 NULL, // set elements to empty fixed array
3298 mode_,
3299 kind_,
3300 allocation_site_payload_,
3301 length_field);
3302
3303 // Allocate and initialize the elements
3304 elements_location_ = builder()->BuildAllocateElements(kind_, elements_size);
3305
3306 builder()->BuildInitializeElementsHeader(elements_location_, kind_, capacity);
3307
3308 // Set the elements
3309 builder()->Add<HStoreNamedField>(
3310 array_object, HObjectAccess::ForElementsPointer(), elements_location_);
3311
3312 if (fill_mode == FILL_WITH_HOLE) {
3313 builder()->BuildFillElementsWithHole(elements_location_, kind_,
3314 graph()->GetConstant0(), capacity);
3315 }
3316
3317 return array_object;
3318}
3319
3320
3321HValue* HGraphBuilder::AddLoadJSBuiltin(Builtins::JavaScript builtin) {
3322 HValue* global_object = Add<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003323 context(), nullptr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003324 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
3325 HObjectAccess access = HObjectAccess::ForObservableJSObjectOffset(
3326 GlobalObject::kBuiltinsOffset);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003327 HValue* builtins = Add<HLoadNamedField>(global_object, nullptr, access);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003328 HObjectAccess function_access = HObjectAccess::ForObservableJSObjectOffset(
3329 JSBuiltinsObject::OffsetOfFunctionWithId(builtin));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003330 return Add<HLoadNamedField>(builtins, nullptr, function_access);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003331}
3332
3333
3334HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info)
3335 : HGraphBuilder(info),
3336 function_state_(NULL),
3337 initial_function_state_(this, info, NORMAL_RETURN, 0),
Ben Murdoch257744e2011-11-30 15:57:28 +00003338 ast_context_(NULL),
3339 break_scope_(NULL),
Ben Murdoch257744e2011-11-30 15:57:28 +00003340 inlined_count_(0),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003341 globals_(10, info->zone()),
3342 osr_(new(info->zone()) HOsrBuilder(this)) {
Ben Murdoch257744e2011-11-30 15:57:28 +00003343 // This is not initialized in the initializer list because the
3344 // constructor for the initial state relies on function_state_ == NULL
3345 // to know it's the initial state.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003346 function_state_ = &initial_function_state_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003347 InitializeAstVisitor(info->zone());
3348 if (FLAG_hydrogen_track_positions) {
3349 SetSourcePosition(info->shared_info()->start_position());
3350 }
Ben Murdoch257744e2011-11-30 15:57:28 +00003351}
Ben Murdochb0fe1622011-05-05 13:52:32 +01003352
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003353
3354HBasicBlock* HOptimizedGraphBuilder::CreateJoin(HBasicBlock* first,
3355 HBasicBlock* second,
3356 BailoutId join_id) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003357 if (first == NULL) {
3358 return second;
3359 } else if (second == NULL) {
3360 return first;
3361 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003362 HBasicBlock* join_block = graph()->CreateBasicBlock();
3363 Goto(first, join_block);
3364 Goto(second, join_block);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003365 join_block->SetJoinId(join_id);
3366 return join_block;
Ben Murdochb0fe1622011-05-05 13:52:32 +01003367 }
3368}
3369
3370
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003371HBasicBlock* HOptimizedGraphBuilder::JoinContinue(IterationStatement* statement,
3372 HBasicBlock* exit_block,
3373 HBasicBlock* continue_block) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01003374 if (continue_block != NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003375 if (exit_block != NULL) Goto(exit_block, continue_block);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003376 continue_block->SetJoinId(statement->ContinueId());
3377 return continue_block;
Ben Murdochb0fe1622011-05-05 13:52:32 +01003378 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003379 return exit_block;
Ben Murdochb0fe1622011-05-05 13:52:32 +01003380}
3381
3382
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003383HBasicBlock* HOptimizedGraphBuilder::CreateLoop(IterationStatement* statement,
3384 HBasicBlock* loop_entry,
3385 HBasicBlock* body_exit,
3386 HBasicBlock* loop_successor,
3387 HBasicBlock* break_block) {
3388 if (body_exit != NULL) Goto(body_exit, loop_entry);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003389 loop_entry->PostProcessLoopHeader(statement);
3390 if (break_block != NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003391 if (loop_successor != NULL) Goto(loop_successor, break_block);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003392 break_block->SetJoinId(statement->ExitId());
3393 return break_block;
Ben Murdochb0fe1622011-05-05 13:52:32 +01003394 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003395 return loop_successor;
Ben Murdochb0fe1622011-05-05 13:52:32 +01003396}
3397
3398
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003399// Build a new loop header block and set it as the current block.
3400HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry() {
3401 HBasicBlock* loop_entry = CreateLoopHeaderBlock();
3402 Goto(loop_entry);
3403 set_current_block(loop_entry);
3404 return loop_entry;
3405}
3406
3407
3408HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry(
3409 IterationStatement* statement) {
3410 HBasicBlock* loop_entry = osr()->HasOsrEntryAt(statement)
3411 ? osr()->BuildOsrLoopEntry(statement)
3412 : BuildLoopEntry();
3413 return loop_entry;
3414}
3415
3416
3417void HBasicBlock::FinishExit(HControlInstruction* instruction,
3418 HSourcePosition position) {
3419 Finish(instruction, position);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003420 ClearEnvironment();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003421}
3422
3423
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003424std::ostream& operator<<(std::ostream& os, const HBasicBlock& b) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003425 return os << "B" << b.block_id();
3426}
3427
3428
Ben Murdochb0fe1622011-05-05 13:52:32 +01003429HGraph::HGraph(CompilationInfo* info)
Steve Block44f0eee2011-05-26 01:26:41 +01003430 : isolate_(info->isolate()),
Ben Murdochb0fe1622011-05-05 13:52:32 +01003431 next_block_id_(0),
Steve Block44f0eee2011-05-26 01:26:41 +01003432 entry_block_(NULL),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003433 blocks_(8, info->zone()),
3434 values_(16, info->zone()),
3435 phi_list_(NULL),
3436 uint32_instructions_(NULL),
3437 osr_(NULL),
3438 info_(info),
3439 zone_(info->zone()),
3440 is_recursive_(false),
3441 use_optimistic_licm_(false),
3442 depends_on_empty_array_proto_elements_(false),
3443 type_change_checksum_(0),
3444 maximum_environment_size_(0),
3445 no_side_effects_scope_count_(0),
3446 disallow_adding_new_values_(false),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003447 inlined_functions_(FLAG_hydrogen_track_positions ? 5 : 0, info->zone()),
3448 inlining_id_to_function_id_(FLAG_hydrogen_track_positions ? 5 : 0,
3449 info->zone()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003450 if (info->IsStub()) {
3451 CallInterfaceDescriptor descriptor =
3452 info->code_stub()->GetCallInterfaceDescriptor();
3453 start_environment_ = new (zone_)
3454 HEnvironment(zone_, descriptor.GetEnvironmentParameterCount());
3455 } else {
3456 TraceInlinedFunction(info->shared_info(), HSourcePosition::Unknown());
3457 start_environment_ =
3458 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_);
3459 }
3460 start_environment_->set_ast_id(BailoutId::FunctionEntry());
Steve Block44f0eee2011-05-26 01:26:41 +01003461 entry_block_ = CreateBasicBlock();
3462 entry_block_->SetInitialEnvironment(start_environment_);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003463}
3464
3465
Ben Murdochb0fe1622011-05-05 13:52:32 +01003466HBasicBlock* HGraph::CreateBasicBlock() {
Ben Murdoch8b112d22011-06-08 16:22:53 +01003467 HBasicBlock* result = new(zone()) HBasicBlock(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003468 blocks_.Add(result, zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +01003469 return result;
3470}
3471
3472
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003473void HGraph::FinalizeUniqueness() {
3474 DisallowHeapAllocation no_gc;
3475 DCHECK(!OptimizingCompilerThread::IsOptimizerThread(isolate()));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003476 for (int i = 0; i < blocks()->length(); ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003477 for (HInstructionIterator it(blocks()->at(i)); !it.Done(); it.Advance()) {
3478 it.Current()->FinalizeUniqueness();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003479 }
3480 }
3481}
3482
3483
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003484int HGraph::TraceInlinedFunction(
3485 Handle<SharedFunctionInfo> shared,
3486 HSourcePosition position) {
3487 if (!FLAG_hydrogen_track_positions) {
3488 return 0;
3489 }
3490
3491 int id = 0;
3492 for (; id < inlined_functions_.length(); id++) {
3493 if (inlined_functions_[id].shared().is_identical_to(shared)) {
3494 break;
3495 }
3496 }
3497
3498 if (id == inlined_functions_.length()) {
3499 inlined_functions_.Add(InlinedFunctionInfo(shared), zone());
3500
3501 if (!shared->script()->IsUndefined()) {
3502 Handle<Script> script(Script::cast(shared->script()));
3503 if (!script->source()->IsUndefined()) {
3504 CodeTracer::Scope tracing_scopex(isolate()->GetCodeTracer());
3505 OFStream os(tracing_scopex.file());
3506 os << "--- FUNCTION SOURCE (" << shared->DebugName()->ToCString().get()
3507 << ") id{" << info()->optimization_id() << "," << id << "} ---\n";
3508 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003509 StringCharacterStream stream(String::cast(script->source()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003510 shared->start_position());
3511 // fun->end_position() points to the last character in the stream. We
3512 // need to compensate by adding one to calculate the length.
3513 int source_len =
3514 shared->end_position() - shared->start_position() + 1;
3515 for (int i = 0; i < source_len; i++) {
3516 if (stream.HasMore()) {
3517 os << AsReversiblyEscapedUC16(stream.GetNext());
3518 }
3519 }
3520 }
3521
3522 os << "\n--- END ---\n";
3523 }
3524 }
3525 }
3526
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003527 int inline_id = inlining_id_to_function_id_.length();
3528 inlining_id_to_function_id_.Add(id, zone());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003529
3530 if (inline_id != 0) {
3531 CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer());
3532 OFStream os(tracing_scope.file());
3533 os << "INLINE (" << shared->DebugName()->ToCString().get() << ") id{"
3534 << info()->optimization_id() << "," << id << "} AS " << inline_id
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003535 << " AT " << position << std::endl;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003536 }
3537
3538 return inline_id;
3539}
3540
3541
3542int HGraph::SourcePositionToScriptPosition(HSourcePosition pos) {
3543 if (!FLAG_hydrogen_track_positions || pos.IsUnknown()) {
3544 return pos.raw();
3545 }
3546
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003547 const int id = inlining_id_to_function_id_[pos.inlining_id()];
3548 return inlined_functions_[id].start_position() + pos.position();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003549}
3550
3551
3552// Block ordering was implemented with two mutually recursive methods,
3553// HGraph::Postorder and HGraph::PostorderLoopBlocks.
3554// The recursion could lead to stack overflow so the algorithm has been
3555// implemented iteratively.
3556// At a high level the algorithm looks like this:
3557//
3558// Postorder(block, loop_header) : {
3559// if (block has already been visited or is of another loop) return;
3560// mark block as visited;
3561// if (block is a loop header) {
3562// VisitLoopMembers(block, loop_header);
3563// VisitSuccessorsOfLoopHeader(block);
3564// } else {
3565// VisitSuccessors(block)
3566// }
3567// put block in result list;
3568// }
3569//
3570// VisitLoopMembers(block, outer_loop_header) {
3571// foreach (block b in block loop members) {
3572// VisitSuccessorsOfLoopMember(b, outer_loop_header);
3573// if (b is loop header) VisitLoopMembers(b);
3574// }
3575// }
3576//
3577// VisitSuccessorsOfLoopMember(block, outer_loop_header) {
3578// foreach (block b in block successors) Postorder(b, outer_loop_header)
3579// }
3580//
3581// VisitSuccessorsOfLoopHeader(block) {
3582// foreach (block b in block successors) Postorder(b, block)
3583// }
3584//
3585// VisitSuccessors(block, loop_header) {
3586// foreach (block b in block successors) Postorder(b, loop_header)
3587// }
3588//
3589// The ordering is started calling Postorder(entry, NULL).
3590//
3591// Each instance of PostorderProcessor represents the "stack frame" of the
3592// recursion, and particularly keeps the state of the loop (iteration) of the
3593// "Visit..." function it represents.
3594// To recycle memory we keep all the frames in a double linked list but
3595// this means that we cannot use constructors to initialize the frames.
3596//
3597class PostorderProcessor : public ZoneObject {
3598 public:
3599 // Back link (towards the stack bottom).
3600 PostorderProcessor* parent() {return father_; }
3601 // Forward link (towards the stack top).
3602 PostorderProcessor* child() {return child_; }
3603 HBasicBlock* block() { return block_; }
3604 HLoopInformation* loop() { return loop_; }
3605 HBasicBlock* loop_header() { return loop_header_; }
3606
3607 static PostorderProcessor* CreateEntryProcessor(Zone* zone,
3608 HBasicBlock* block) {
3609 PostorderProcessor* result = new(zone) PostorderProcessor(NULL);
3610 return result->SetupSuccessors(zone, block, NULL);
3611 }
3612
3613 PostorderProcessor* PerformStep(Zone* zone,
3614 ZoneList<HBasicBlock*>* order) {
3615 PostorderProcessor* next =
3616 PerformNonBacktrackingStep(zone, order);
3617 if (next != NULL) {
3618 return next;
3619 } else {
3620 return Backtrack(zone, order);
3621 }
3622 }
3623
3624 private:
3625 explicit PostorderProcessor(PostorderProcessor* father)
3626 : father_(father), child_(NULL), successor_iterator(NULL) { }
3627
3628 // Each enum value states the cycle whose state is kept by this instance.
3629 enum LoopKind {
3630 NONE,
3631 SUCCESSORS,
3632 SUCCESSORS_OF_LOOP_HEADER,
3633 LOOP_MEMBERS,
3634 SUCCESSORS_OF_LOOP_MEMBER
3635 };
3636
3637 // Each "Setup..." method is like a constructor for a cycle state.
3638 PostorderProcessor* SetupSuccessors(Zone* zone,
3639 HBasicBlock* block,
3640 HBasicBlock* loop_header) {
3641 if (block == NULL || block->IsOrdered() ||
3642 block->parent_loop_header() != loop_header) {
3643 kind_ = NONE;
3644 block_ = NULL;
3645 loop_ = NULL;
3646 loop_header_ = NULL;
3647 return this;
3648 } else {
3649 block_ = block;
3650 loop_ = NULL;
3651 block->MarkAsOrdered();
3652
3653 if (block->IsLoopHeader()) {
3654 kind_ = SUCCESSORS_OF_LOOP_HEADER;
3655 loop_header_ = block;
3656 InitializeSuccessors();
3657 PostorderProcessor* result = Push(zone);
3658 return result->SetupLoopMembers(zone, block, block->loop_information(),
3659 loop_header);
3660 } else {
3661 DCHECK(block->IsFinished());
3662 kind_ = SUCCESSORS;
3663 loop_header_ = loop_header;
3664 InitializeSuccessors();
3665 return this;
3666 }
3667 }
3668 }
3669
3670 PostorderProcessor* SetupLoopMembers(Zone* zone,
3671 HBasicBlock* block,
3672 HLoopInformation* loop,
3673 HBasicBlock* loop_header) {
3674 kind_ = LOOP_MEMBERS;
3675 block_ = block;
3676 loop_ = loop;
3677 loop_header_ = loop_header;
3678 InitializeLoopMembers();
3679 return this;
3680 }
3681
3682 PostorderProcessor* SetupSuccessorsOfLoopMember(
3683 HBasicBlock* block,
3684 HLoopInformation* loop,
3685 HBasicBlock* loop_header) {
3686 kind_ = SUCCESSORS_OF_LOOP_MEMBER;
3687 block_ = block;
3688 loop_ = loop;
3689 loop_header_ = loop_header;
3690 InitializeSuccessors();
3691 return this;
3692 }
3693
3694 // This method "allocates" a new stack frame.
3695 PostorderProcessor* Push(Zone* zone) {
3696 if (child_ == NULL) {
3697 child_ = new(zone) PostorderProcessor(this);
3698 }
3699 return child_;
3700 }
3701
3702 void ClosePostorder(ZoneList<HBasicBlock*>* order, Zone* zone) {
3703 DCHECK(block_->end()->FirstSuccessor() == NULL ||
3704 order->Contains(block_->end()->FirstSuccessor()) ||
3705 block_->end()->FirstSuccessor()->IsLoopHeader());
3706 DCHECK(block_->end()->SecondSuccessor() == NULL ||
3707 order->Contains(block_->end()->SecondSuccessor()) ||
3708 block_->end()->SecondSuccessor()->IsLoopHeader());
3709 order->Add(block_, zone);
3710 }
3711
3712 // This method is the basic block to walk up the stack.
3713 PostorderProcessor* Pop(Zone* zone,
3714 ZoneList<HBasicBlock*>* order) {
3715 switch (kind_) {
3716 case SUCCESSORS:
3717 case SUCCESSORS_OF_LOOP_HEADER:
3718 ClosePostorder(order, zone);
3719 return father_;
3720 case LOOP_MEMBERS:
3721 return father_;
3722 case SUCCESSORS_OF_LOOP_MEMBER:
3723 if (block()->IsLoopHeader() && block() != loop_->loop_header()) {
3724 // In this case we need to perform a LOOP_MEMBERS cycle so we
3725 // initialize it and return this instead of father.
3726 return SetupLoopMembers(zone, block(),
3727 block()->loop_information(), loop_header_);
3728 } else {
3729 return father_;
3730 }
3731 case NONE:
3732 return father_;
3733 }
3734 UNREACHABLE();
3735 return NULL;
3736 }
3737
3738 // Walks up the stack.
3739 PostorderProcessor* Backtrack(Zone* zone,
3740 ZoneList<HBasicBlock*>* order) {
3741 PostorderProcessor* parent = Pop(zone, order);
3742 while (parent != NULL) {
3743 PostorderProcessor* next =
3744 parent->PerformNonBacktrackingStep(zone, order);
3745 if (next != NULL) {
3746 return next;
3747 } else {
3748 parent = parent->Pop(zone, order);
3749 }
3750 }
3751 return NULL;
3752 }
3753
3754 PostorderProcessor* PerformNonBacktrackingStep(
3755 Zone* zone,
3756 ZoneList<HBasicBlock*>* order) {
3757 HBasicBlock* next_block;
3758 switch (kind_) {
3759 case SUCCESSORS:
3760 next_block = AdvanceSuccessors();
3761 if (next_block != NULL) {
3762 PostorderProcessor* result = Push(zone);
3763 return result->SetupSuccessors(zone, next_block, loop_header_);
3764 }
3765 break;
3766 case SUCCESSORS_OF_LOOP_HEADER:
3767 next_block = AdvanceSuccessors();
3768 if (next_block != NULL) {
3769 PostorderProcessor* result = Push(zone);
3770 return result->SetupSuccessors(zone, next_block, block());
3771 }
3772 break;
3773 case LOOP_MEMBERS:
3774 next_block = AdvanceLoopMembers();
3775 if (next_block != NULL) {
3776 PostorderProcessor* result = Push(zone);
3777 return result->SetupSuccessorsOfLoopMember(next_block,
3778 loop_, loop_header_);
3779 }
3780 break;
3781 case SUCCESSORS_OF_LOOP_MEMBER:
3782 next_block = AdvanceSuccessors();
3783 if (next_block != NULL) {
3784 PostorderProcessor* result = Push(zone);
3785 return result->SetupSuccessors(zone, next_block, loop_header_);
3786 }
3787 break;
3788 case NONE:
3789 return NULL;
3790 }
3791 return NULL;
3792 }
3793
3794 // The following two methods implement a "foreach b in successors" cycle.
3795 void InitializeSuccessors() {
3796 loop_index = 0;
3797 loop_length = 0;
3798 successor_iterator = HSuccessorIterator(block_->end());
3799 }
3800
3801 HBasicBlock* AdvanceSuccessors() {
3802 if (!successor_iterator.Done()) {
3803 HBasicBlock* result = successor_iterator.Current();
3804 successor_iterator.Advance();
3805 return result;
3806 }
3807 return NULL;
3808 }
3809
3810 // The following two methods implement a "foreach b in loop members" cycle.
3811 void InitializeLoopMembers() {
3812 loop_index = 0;
3813 loop_length = loop_->blocks()->length();
3814 }
3815
3816 HBasicBlock* AdvanceLoopMembers() {
3817 if (loop_index < loop_length) {
3818 HBasicBlock* result = loop_->blocks()->at(loop_index);
3819 loop_index++;
3820 return result;
3821 } else {
3822 return NULL;
3823 }
3824 }
3825
3826 LoopKind kind_;
3827 PostorderProcessor* father_;
3828 PostorderProcessor* child_;
3829 HLoopInformation* loop_;
3830 HBasicBlock* block_;
3831 HBasicBlock* loop_header_;
3832 int loop_index;
3833 int loop_length;
3834 HSuccessorIterator successor_iterator;
3835};
3836
3837
Ben Murdochb0fe1622011-05-05 13:52:32 +01003838void HGraph::OrderBlocks() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003839 CompilationPhase phase("H_Block ordering", info());
Ben Murdochb0fe1622011-05-05 13:52:32 +01003840
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003841#ifdef DEBUG
3842 // Initially the blocks must not be ordered.
3843 for (int i = 0; i < blocks_.length(); ++i) {
3844 DCHECK(!blocks_[i]->IsOrdered());
3845 }
3846#endif
Ben Murdochb0fe1622011-05-05 13:52:32 +01003847
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003848 PostorderProcessor* postorder =
3849 PostorderProcessor::CreateEntryProcessor(zone(), blocks_[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01003850 blocks_.Rewind(0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003851 while (postorder) {
3852 postorder = postorder->PerformStep(zone(), &blocks_);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003853 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01003854
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003855#ifdef DEBUG
3856 // Now all blocks must be marked as ordered.
3857 for (int i = 0; i < blocks_.length(); ++i) {
3858 DCHECK(blocks_[i]->IsOrdered());
Ben Murdochb0fe1622011-05-05 13:52:32 +01003859 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003860#endif
Ben Murdochb0fe1622011-05-05 13:52:32 +01003861
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003862 // Reverse block list and assign block IDs.
3863 for (int i = 0, j = blocks_.length(); --j >= i; ++i) {
3864 HBasicBlock* bi = blocks_[i];
3865 HBasicBlock* bj = blocks_[j];
3866 bi->set_block_id(j);
3867 bj->set_block_id(i);
3868 blocks_[i] = bj;
3869 blocks_[j] = bi;
Ben Murdochb0fe1622011-05-05 13:52:32 +01003870 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01003871}
3872
3873
3874void HGraph::AssignDominators() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003875 HPhase phase("H_Assign dominators", this);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003876 for (int i = 0; i < blocks_.length(); ++i) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003877 HBasicBlock* block = blocks_[i];
3878 if (block->IsLoopHeader()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003879 // Only the first predecessor of a loop header is from outside the loop.
3880 // All others are back edges, and thus cannot dominate the loop header.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003881 block->AssignCommonDominator(block->predecessors()->first());
3882 block->AssignLoopSuccessorDominators();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003883 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003884 for (int j = blocks_[i]->predecessors()->length() - 1; j >= 0; --j) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01003885 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j));
3886 }
3887 }
3888 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003889}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003890
Ben Murdochb0fe1622011-05-05 13:52:32 +01003891
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003892bool HGraph::CheckArgumentsPhiUses() {
Ben Murdoch257744e2011-11-30 15:57:28 +00003893 int block_count = blocks_.length();
3894 for (int i = 0; i < block_count; ++i) {
3895 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
3896 HPhi* phi = blocks_[i]->phis()->at(j);
3897 // We don't support phi uses of arguments for now.
3898 if (phi->CheckFlag(HValue::kIsArguments)) return false;
3899 }
3900 }
3901 return true;
3902}
3903
3904
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003905bool HGraph::CheckConstPhiUses() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003906 int block_count = blocks_.length();
3907 for (int i = 0; i < block_count; ++i) {
3908 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
3909 HPhi* phi = blocks_[i]->phis()->at(j);
3910 // Check for the hole value (from an uninitialized const).
3911 for (int k = 0; k < phi->OperandCount(); k++) {
3912 if (phi->OperandAt(k) == GetConstantHole()) return false;
3913 }
3914 }
3915 }
3916 return true;
3917}
3918
3919
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003920void HGraph::CollectPhis() {
3921 int block_count = blocks_.length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003922 phi_list_ = new(zone()) ZoneList<HPhi*>(block_count, zone());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003923 for (int i = 0; i < block_count; ++i) {
3924 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
3925 HPhi* phi = blocks_[i]->phis()->at(j);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003926 phi_list_->Add(phi, zone());
Steve Block1e0659c2011-05-24 12:43:12 +01003927 }
3928 }
3929}
3930
3931
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003932// Implementation of utility class to encapsulate the translation state for
3933// a (possibly inlined) function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003934FunctionState::FunctionState(HOptimizedGraphBuilder* owner,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003935 CompilationInfo* info,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003936 InliningKind inlining_kind,
3937 int inlining_id)
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003938 : owner_(owner),
3939 compilation_info_(info),
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003940 call_context_(NULL),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003941 inlining_kind_(inlining_kind),
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003942 function_return_(NULL),
3943 test_context_(NULL),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003944 entry_(NULL),
3945 arguments_object_(NULL),
3946 arguments_elements_(NULL),
3947 inlining_id_(inlining_id),
3948 outer_source_position_(HSourcePosition::Unknown()),
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003949 outer_(owner->function_state()) {
3950 if (outer_ != NULL) {
3951 // State for an inline function.
3952 if (owner->ast_context()->IsTest()) {
3953 HBasicBlock* if_true = owner->graph()->CreateBasicBlock();
3954 HBasicBlock* if_false = owner->graph()->CreateBasicBlock();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003955 if_true->MarkAsInlineReturnTarget(owner->current_block());
3956 if_false->MarkAsInlineReturnTarget(owner->current_block());
3957 TestContext* outer_test_context = TestContext::cast(owner->ast_context());
3958 Expression* cond = outer_test_context->condition();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003959 // The AstContext constructor pushed on the context stack. This newed
3960 // instance is the reason that AstContext can't be BASE_EMBEDDED.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003961 test_context_ = new TestContext(owner, cond, if_true, if_false);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003962 } else {
3963 function_return_ = owner->graph()->CreateBasicBlock();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003964 function_return()->MarkAsInlineReturnTarget(owner->current_block());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003965 }
3966 // Set this after possibly allocating a new TestContext above.
3967 call_context_ = owner->ast_context();
3968 }
3969
3970 // Push on the state stack.
3971 owner->set_function_state(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003972
3973 if (FLAG_hydrogen_track_positions) {
3974 outer_source_position_ = owner->source_position();
3975 owner->EnterInlinedSource(
3976 info->shared_info()->start_position(),
3977 inlining_id);
3978 owner->SetSourcePosition(info->shared_info()->start_position());
3979 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003980}
3981
3982
3983FunctionState::~FunctionState() {
3984 delete test_context_;
3985 owner_->set_function_state(outer_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003986
3987 if (FLAG_hydrogen_track_positions) {
3988 owner_->set_source_position(outer_source_position_);
3989 owner_->EnterInlinedSource(
3990 outer_->compilation_info()->shared_info()->start_position(),
3991 outer_->inlining_id());
3992 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003993}
3994
3995
Ben Murdochb0fe1622011-05-05 13:52:32 +01003996// Implementation of utility classes to represent an expression's context in
3997// the AST.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003998AstContext::AstContext(HOptimizedGraphBuilder* owner, Expression::Context kind)
Ben Murdoch8b112d22011-06-08 16:22:53 +01003999 : owner_(owner),
4000 kind_(kind),
4001 outer_(owner->ast_context()),
4002 for_typeof_(false) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01004003 owner->set_ast_context(this); // Push.
4004#ifdef DEBUG
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004005 DCHECK(owner->environment()->frame_type() == JS_FUNCTION);
Steve Block9fac8402011-05-12 15:51:54 +01004006 original_length_ = owner->environment()->length();
Ben Murdochb0fe1622011-05-05 13:52:32 +01004007#endif
4008}
4009
4010
4011AstContext::~AstContext() {
4012 owner_->set_ast_context(outer_); // Pop.
4013}
4014
4015
4016EffectContext::~EffectContext() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004017 DCHECK(owner()->HasStackOverflow() ||
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004018 owner()->current_block() == NULL ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004019 (owner()->environment()->length() == original_length_ &&
4020 owner()->environment()->frame_type() == JS_FUNCTION));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004021}
4022
4023
4024ValueContext::~ValueContext() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004025 DCHECK(owner()->HasStackOverflow() ||
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004026 owner()->current_block() == NULL ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004027 (owner()->environment()->length() == original_length_ + 1 &&
4028 owner()->environment()->frame_type() == JS_FUNCTION));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004029}
4030
4031
4032void EffectContext::ReturnValue(HValue* value) {
4033 // The value is simply ignored.
4034}
4035
4036
4037void ValueContext::ReturnValue(HValue* value) {
4038 // The value is tracked in the bailout environment, and communicated
4039 // through the environment as the result of the expression.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004040 if (value->CheckFlag(HValue::kIsArguments)) {
4041 if (flag_ == ARGUMENTS_FAKED) {
4042 value = owner()->graph()->GetConstantUndefined();
4043 } else if (!arguments_allowed()) {
4044 owner()->Bailout(kBadValueContextForArgumentsValue);
4045 }
Ben Murdoch257744e2011-11-30 15:57:28 +00004046 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01004047 owner()->Push(value);
4048}
4049
4050
4051void TestContext::ReturnValue(HValue* value) {
4052 BuildBranch(value);
4053}
4054
4055
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004056void EffectContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
4057 DCHECK(!instr->IsControlInstruction());
Ben Murdochb0fe1622011-05-05 13:52:32 +01004058 owner()->AddInstruction(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004059 if (instr->HasObservableSideEffects()) {
4060 owner()->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
4061 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01004062}
4063
4064
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004065void EffectContext::ReturnControl(HControlInstruction* instr,
4066 BailoutId ast_id) {
4067 DCHECK(!instr->HasObservableSideEffects());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004068 HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock();
4069 HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock();
4070 instr->SetSuccessorAt(0, empty_true);
4071 instr->SetSuccessorAt(1, empty_false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004072 owner()->FinishCurrentBlock(instr);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004073 HBasicBlock* join = owner()->CreateJoin(empty_true, empty_false, ast_id);
4074 owner()->set_current_block(join);
4075}
4076
4077
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004078void EffectContext::ReturnContinuation(HIfContinuation* continuation,
4079 BailoutId ast_id) {
4080 HBasicBlock* true_branch = NULL;
4081 HBasicBlock* false_branch = NULL;
4082 continuation->Continue(&true_branch, &false_branch);
4083 if (!continuation->IsTrueReachable()) {
4084 owner()->set_current_block(false_branch);
4085 } else if (!continuation->IsFalseReachable()) {
4086 owner()->set_current_block(true_branch);
4087 } else {
4088 HBasicBlock* join = owner()->CreateJoin(true_branch, false_branch, ast_id);
4089 owner()->set_current_block(join);
Ben Murdoch257744e2011-11-30 15:57:28 +00004090 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01004091}
4092
4093
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004094void ValueContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
4095 DCHECK(!instr->IsControlInstruction());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004096 if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004097 return owner()->Bailout(kBadValueContextForArgumentsObjectValue);
4098 }
4099 owner()->AddInstruction(instr);
4100 owner()->Push(instr);
4101 if (instr->HasObservableSideEffects()) {
4102 owner()->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
4103 }
4104}
4105
4106
4107void ValueContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) {
4108 DCHECK(!instr->HasObservableSideEffects());
4109 if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) {
4110 return owner()->Bailout(kBadValueContextForArgumentsObjectValue);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004111 }
4112 HBasicBlock* materialize_false = owner()->graph()->CreateBasicBlock();
4113 HBasicBlock* materialize_true = owner()->graph()->CreateBasicBlock();
4114 instr->SetSuccessorAt(0, materialize_true);
4115 instr->SetSuccessorAt(1, materialize_false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004116 owner()->FinishCurrentBlock(instr);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004117 owner()->set_current_block(materialize_true);
4118 owner()->Push(owner()->graph()->GetConstantTrue());
4119 owner()->set_current_block(materialize_false);
4120 owner()->Push(owner()->graph()->GetConstantFalse());
4121 HBasicBlock* join =
4122 owner()->CreateJoin(materialize_true, materialize_false, ast_id);
4123 owner()->set_current_block(join);
4124}
4125
4126
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004127void ValueContext::ReturnContinuation(HIfContinuation* continuation,
4128 BailoutId ast_id) {
4129 HBasicBlock* materialize_true = NULL;
4130 HBasicBlock* materialize_false = NULL;
4131 continuation->Continue(&materialize_true, &materialize_false);
4132 if (continuation->IsTrueReachable()) {
4133 owner()->set_current_block(materialize_true);
4134 owner()->Push(owner()->graph()->GetConstantTrue());
4135 owner()->set_current_block(materialize_true);
4136 }
4137 if (continuation->IsFalseReachable()) {
4138 owner()->set_current_block(materialize_false);
4139 owner()->Push(owner()->graph()->GetConstantFalse());
4140 owner()->set_current_block(materialize_false);
4141 }
4142 if (continuation->TrueAndFalseReachable()) {
4143 HBasicBlock* join =
4144 owner()->CreateJoin(materialize_true, materialize_false, ast_id);
4145 owner()->set_current_block(join);
4146 }
4147}
4148
4149
4150void TestContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
4151 DCHECK(!instr->IsControlInstruction());
4152 HOptimizedGraphBuilder* builder = owner();
Ben Murdochb0fe1622011-05-05 13:52:32 +01004153 builder->AddInstruction(instr);
4154 // We expect a simulate after every expression with side effects, though
4155 // this one isn't actually needed (and wouldn't work if it were targeted).
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004156 if (instr->HasObservableSideEffects()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01004157 builder->Push(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004158 builder->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004159 builder->Pop();
4160 }
4161 BuildBranch(instr);
4162}
4163
4164
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004165void TestContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) {
4166 DCHECK(!instr->HasObservableSideEffects());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004167 HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock();
4168 HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock();
4169 instr->SetSuccessorAt(0, empty_true);
4170 instr->SetSuccessorAt(1, empty_false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004171 owner()->FinishCurrentBlock(instr);
4172 owner()->Goto(empty_true, if_true(), owner()->function_state());
4173 owner()->Goto(empty_false, if_false(), owner()->function_state());
4174 owner()->set_current_block(NULL);
4175}
4176
4177
4178void TestContext::ReturnContinuation(HIfContinuation* continuation,
4179 BailoutId ast_id) {
4180 HBasicBlock* true_branch = NULL;
4181 HBasicBlock* false_branch = NULL;
4182 continuation->Continue(&true_branch, &false_branch);
4183 if (continuation->IsTrueReachable()) {
4184 owner()->Goto(true_branch, if_true(), owner()->function_state());
4185 }
4186 if (continuation->IsFalseReachable()) {
4187 owner()->Goto(false_branch, if_false(), owner()->function_state());
4188 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004189 owner()->set_current_block(NULL);
4190}
4191
4192
Ben Murdochb0fe1622011-05-05 13:52:32 +01004193void TestContext::BuildBranch(HValue* value) {
4194 // We expect the graph to be in edge-split form: there is no edge that
4195 // connects a branch node to a join node. We conservatively ensure that
4196 // property by always adding an empty block on the outgoing edges of this
4197 // branch.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004198 HOptimizedGraphBuilder* builder = owner();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004199 if (value != NULL && value->CheckFlag(HValue::kIsArguments)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004200 builder->Bailout(kArgumentsObjectValueInATestContext);
Ben Murdoch257744e2011-11-30 15:57:28 +00004201 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004202 ToBooleanStub::Types expected(condition()->to_boolean_types());
4203 ReturnControl(owner()->New<HBranch>(value, expected), BailoutId::None());
Ben Murdochb0fe1622011-05-05 13:52:32 +01004204}
4205
4206
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004207// HOptimizedGraphBuilder infrastructure for bailing out and checking bailouts.
Ben Murdoch257744e2011-11-30 15:57:28 +00004208#define CHECK_BAILOUT(call) \
Ben Murdochb0fe1622011-05-05 13:52:32 +01004209 do { \
Ben Murdoch257744e2011-11-30 15:57:28 +00004210 call; \
Ben Murdochb0fe1622011-05-05 13:52:32 +01004211 if (HasStackOverflow()) return; \
4212 } while (false)
4213
4214
Ben Murdoch257744e2011-11-30 15:57:28 +00004215#define CHECK_ALIVE(call) \
Ben Murdochb0fe1622011-05-05 13:52:32 +01004216 do { \
Ben Murdoch257744e2011-11-30 15:57:28 +00004217 call; \
4218 if (HasStackOverflow() || current_block() == NULL) return; \
Ben Murdochb0fe1622011-05-05 13:52:32 +01004219 } while (false)
4220
4221
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004222#define CHECK_ALIVE_OR_RETURN(call, value) \
4223 do { \
4224 call; \
4225 if (HasStackOverflow() || current_block() == NULL) return value; \
4226 } while (false)
4227
4228
4229void HOptimizedGraphBuilder::Bailout(BailoutReason reason) {
4230 current_info()->AbortOptimization(reason);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004231 SetStackOverflow();
4232}
4233
4234
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004235void HOptimizedGraphBuilder::VisitForEffect(Expression* expr) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01004236 EffectContext for_effect(this);
4237 Visit(expr);
4238}
4239
4240
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004241void HOptimizedGraphBuilder::VisitForValue(Expression* expr,
4242 ArgumentsAllowedFlag flag) {
Ben Murdoch257744e2011-11-30 15:57:28 +00004243 ValueContext for_value(this, flag);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004244 Visit(expr);
4245}
4246
4247
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004248void HOptimizedGraphBuilder::VisitForTypeOf(Expression* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +00004249 ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED);
Ben Murdoch8b112d22011-06-08 16:22:53 +01004250 for_value.set_for_typeof(true);
4251 Visit(expr);
4252}
4253
4254
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004255void HOptimizedGraphBuilder::VisitForControl(Expression* expr,
4256 HBasicBlock* true_block,
4257 HBasicBlock* false_block) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004258 TestContext for_test(this, expr, true_block, false_block);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004259 Visit(expr);
4260}
4261
4262
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004263void HOptimizedGraphBuilder::VisitExpressions(
4264 ZoneList<Expression*>* exprs) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004265 for (int i = 0; i < exprs->length(); ++i) {
Ben Murdoch257744e2011-11-30 15:57:28 +00004266 CHECK_ALIVE(VisitForValue(exprs->at(i)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004267 }
4268}
4269
4270
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004271void HOptimizedGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs,
4272 ArgumentsAllowedFlag flag) {
4273 for (int i = 0; i < exprs->length(); ++i) {
4274 CHECK_ALIVE(VisitForValue(exprs->at(i), flag));
4275 }
4276}
4277
4278
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004279bool HOptimizedGraphBuilder::BuildGraph() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004280 Scope* scope = current_info()->scope();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004281 SetUpScope(scope);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004282
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004283 // Add an edge to the body entry. This is warty: the graph's start
4284 // environment will be used by the Lithium translation as the initial
4285 // environment on graph entry, but it has now been mutated by the
4286 // Hydrogen translation of the instructions in the start block. This
4287 // environment uses values which have not been defined yet. These
4288 // Hydrogen instructions will then be replayed by the Lithium
4289 // translation, so they cannot have an environment effect. The edge to
4290 // the body's entry block (along with some special logic for the start
4291 // block in HInstruction::InsertAfter) seals the start block from
4292 // getting unwanted instructions inserted.
4293 //
4294 // TODO(kmillikin): Fix this. Stop mutating the initial environment.
4295 // Make the Hydrogen instructions in the initial block into Hydrogen
4296 // values (but not instructions), present in the initial environment and
4297 // not replayed by the Lithium translation.
4298 HEnvironment* initial_env = environment()->CopyWithoutHistory();
4299 HBasicBlock* body_entry = CreateBasicBlock(initial_env);
4300 Goto(body_entry);
4301 body_entry->SetJoinId(BailoutId::FunctionEntry());
4302 set_current_block(body_entry);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004303
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004304 // Handle implicit declaration of the function name in named function
4305 // expressions before other declarations.
4306 if (scope->is_function_scope() && scope->function() != NULL) {
4307 VisitVariableDeclaration(scope->function());
4308 }
4309 VisitDeclarations(scope->declarations());
4310 Add<HSimulate>(BailoutId::Declarations());
Ben Murdochb0fe1622011-05-05 13:52:32 +01004311
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004312 Add<HStackCheck>(HStackCheck::kFunctionEntry);
Ben Murdoch589d6972011-11-30 16:04:58 +00004313
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004314 VisitStatements(current_info()->function()->body());
4315 if (HasStackOverflow()) return false;
Ben Murdoch589d6972011-11-30 16:04:58 +00004316
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004317 if (current_block() != NULL) {
4318 Add<HReturn>(graph()->GetConstantUndefined());
4319 set_current_block(NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004320 }
4321
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004322 // If the checksum of the number of type info changes is the same as the
4323 // last time this function was compiled, then this recompile is likely not
4324 // due to missing/inadequate type feedback, but rather too aggressive
4325 // optimization. Disable optimistic LICM in that case.
4326 Handle<Code> unoptimized_code(current_info()->shared_info()->code());
4327 DCHECK(unoptimized_code->kind() == Code::FUNCTION);
4328 Handle<TypeFeedbackInfo> type_info(
4329 TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info()));
4330 int checksum = type_info->own_type_change_checksum();
4331 int composite_checksum = graph()->update_type_change_checksum(checksum);
4332 graph()->set_use_optimistic_licm(
4333 !type_info->matches_inlined_type_change_checksum(composite_checksum));
4334 type_info->set_inlined_type_change_checksum(composite_checksum);
4335
4336 // Perform any necessary OSR-specific cleanups or changes to the graph.
4337 osr()->FinishGraph();
4338
4339 return true;
4340}
4341
4342
4343bool HGraph::Optimize(BailoutReason* bailout_reason) {
4344 OrderBlocks();
4345 AssignDominators();
4346
4347 // We need to create a HConstant "zero" now so that GVN will fold every
4348 // zero-valued constant in the graph together.
4349 // The constant is needed to make idef-based bounds check work: the pass
4350 // evaluates relations with "zero" and that zero cannot be created after GVN.
4351 GetConstant0();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004352
4353#ifdef DEBUG
4354 // Do a full verify after building the graph and computing dominators.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004355 Verify(true);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004356#endif
4357
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004358 if (FLAG_analyze_environment_liveness && maximum_environment_size() != 0) {
4359 Run<HEnvironmentLivenessAnalysisPhase>();
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01004360 }
4361
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004362 if (!CheckConstPhiUses()) {
4363 *bailout_reason = kUnsupportedPhiUseOfConstVariable;
4364 return false;
4365 }
4366 Run<HRedundantPhiEliminationPhase>();
4367 if (!CheckArgumentsPhiUses()) {
4368 *bailout_reason = kUnsupportedPhiUseOfArguments;
4369 return false;
Ben Murdochb0fe1622011-05-05 13:52:32 +01004370 }
4371
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004372 // Find and mark unreachable code to simplify optimizations, especially gvn,
4373 // where unreachable code could unnecessarily defeat LICM.
4374 Run<HMarkUnreachableBlocksPhase>();
4375
4376 if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>();
4377 if (FLAG_use_escape_analysis) Run<HEscapeAnalysisPhase>();
4378
4379 if (FLAG_load_elimination) Run<HLoadEliminationPhase>();
4380
4381 CollectPhis();
4382
4383 if (has_osr()) osr()->FinishOsrValues();
4384
4385 Run<HInferRepresentationPhase>();
4386
4387 // Remove HSimulate instructions that have turned out not to be needed
4388 // after all by folding them into the following HSimulate.
4389 // This must happen after inferring representations.
4390 Run<HMergeRemovableSimulatesPhase>();
4391
4392 Run<HMarkDeoptimizeOnUndefinedPhase>();
4393 Run<HRepresentationChangesPhase>();
4394
4395 Run<HInferTypesPhase>();
4396
4397 // Must be performed before canonicalization to ensure that Canonicalize
4398 // will not remove semantically meaningful ToInt32 operations e.g. BIT_OR with
4399 // zero.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004400 Run<HUint32AnalysisPhase>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004401
4402 if (FLAG_use_canonicalizing) Run<HCanonicalizePhase>();
4403
4404 if (FLAG_use_gvn) Run<HGlobalValueNumberingPhase>();
4405
4406 if (FLAG_check_elimination) Run<HCheckEliminationPhase>();
4407
4408 if (FLAG_store_elimination) Run<HStoreEliminationPhase>();
4409
4410 Run<HRangeAnalysisPhase>();
4411
4412 Run<HComputeChangeUndefinedToNaN>();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004413
4414 // Eliminate redundant stack checks on backwards branches.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004415 Run<HStackCheckEliminationPhase>();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004416
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004417 if (FLAG_array_bounds_checks_elimination) Run<HBoundsCheckEliminationPhase>();
4418 if (FLAG_array_bounds_checks_hoisting) Run<HBoundsCheckHoistingPhase>();
4419 if (FLAG_array_index_dehoisting) Run<HDehoistIndexComputationsPhase>();
4420 if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>();
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +01004421
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004422 RestoreActualValues();
4423
4424 // Find unreachable code a second time, GVN and other optimizations may have
4425 // made blocks unreachable that were previously reachable.
4426 Run<HMarkUnreachableBlocksPhase>();
4427
4428 return true;
Ben Murdochb0fe1622011-05-05 13:52:32 +01004429}
4430
4431
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004432void HGraph::RestoreActualValues() {
4433 HPhase phase("H_Restore actual values", this);
4434
4435 for (int block_index = 0; block_index < blocks()->length(); block_index++) {
4436 HBasicBlock* block = blocks()->at(block_index);
4437
4438#ifdef DEBUG
4439 for (int i = 0; i < block->phis()->length(); i++) {
4440 HPhi* phi = block->phis()->at(i);
4441 DCHECK(phi->ActualValue() == phi);
4442 }
4443#endif
4444
4445 for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
4446 HInstruction* instruction = it.Current();
4447 if (instruction->ActualValue() == instruction) continue;
4448 if (instruction->CheckFlag(HValue::kIsDead)) {
4449 // The instruction was marked as deleted but left in the graph
4450 // as a control flow dependency point for subsequent
4451 // instructions.
4452 instruction->DeleteAndReplaceWith(instruction->ActualValue());
4453 } else {
4454 DCHECK(instruction->IsInformativeDefinition());
4455 if (instruction->IsPurelyInformativeDefinition()) {
4456 instruction->DeleteAndReplaceWith(instruction->RedefinedOperand());
4457 } else {
4458 instruction->ReplaceAllUsesWith(instruction->ActualValue());
4459 }
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +01004460 }
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +01004461 }
4462 }
4463}
4464
4465
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004466void HOptimizedGraphBuilder::PushArgumentsFromEnvironment(int count) {
4467 ZoneList<HValue*> arguments(count, zone());
4468 for (int i = 0; i < count; ++i) {
4469 arguments.Add(Pop(), zone());
4470 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01004471
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004472 HPushArguments* push_args = New<HPushArguments>();
4473 while (!arguments.is_empty()) {
4474 push_args->AddInput(arguments.RemoveLast());
4475 }
4476 AddInstruction(push_args);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004477}
4478
4479
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004480template <class Instruction>
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004481HInstruction* HOptimizedGraphBuilder::PreProcessCall(Instruction* call) {
4482 PushArgumentsFromEnvironment(call->argument_count());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004483 return call;
Ben Murdochb0fe1622011-05-05 13:52:32 +01004484}
4485
4486
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004487void HOptimizedGraphBuilder::SetUpScope(Scope* scope) {
Ben Murdoch257744e2011-11-30 15:57:28 +00004488 // First special is HContext.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004489 HInstruction* context = Add<HContext>();
Ben Murdoch257744e2011-11-30 15:57:28 +00004490 environment()->BindContext(context);
4491
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004492 // Create an arguments object containing the initial parameters. Set the
4493 // initial values of parameters including "this" having parameter index 0.
4494 DCHECK_EQ(scope->num_parameters() + 1, environment()->parameter_count());
4495 HArgumentsObject* arguments_object =
4496 New<HArgumentsObject>(environment()->parameter_count());
4497 for (int i = 0; i < environment()->parameter_count(); ++i) {
4498 HInstruction* parameter = Add<HParameter>(i);
4499 arguments_object->AddArgument(parameter, zone());
4500 environment()->Bind(i, parameter);
4501 }
4502 AddInstruction(arguments_object);
4503 graph()->SetArgumentsObject(arguments_object);
4504
4505 HConstant* undefined_constant = graph()->GetConstantUndefined();
Ben Murdoch257744e2011-11-30 15:57:28 +00004506 // Initialize specials and locals to undefined.
4507 for (int i = environment()->parameter_count() + 1;
4508 i < environment()->length();
4509 ++i) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01004510 environment()->Bind(i, undefined_constant);
4511 }
4512
4513 // Handle the arguments and arguments shadow variables specially (they do
4514 // not have declarations).
4515 if (scope->arguments() != NULL) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004516 environment()->Bind(scope->arguments(),
4517 graph()->GetArgumentsObject());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004518 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01004519}
4520
4521
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004522Type* HOptimizedGraphBuilder::ToType(Handle<Map> map) {
4523 return IC::MapToType<Type>(map, zone());
4524}
4525
4526
4527void HOptimizedGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01004528 for (int i = 0; i < statements->length(); i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004529 Statement* stmt = statements->at(i);
4530 CHECK_ALIVE(Visit(stmt));
4531 if (stmt->IsJump()) break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01004532 }
4533}
4534
4535
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004536void HOptimizedGraphBuilder::VisitBlock(Block* stmt) {
4537 DCHECK(!HasStackOverflow());
4538 DCHECK(current_block() != NULL);
4539 DCHECK(current_block()->HasPredecessor());
Ben Murdochb0fe1622011-05-05 13:52:32 +01004540
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004541 Scope* outer_scope = scope();
4542 Scope* scope = stmt->scope();
4543 BreakAndContinueInfo break_info(stmt, outer_scope);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004544
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004545 { BreakAndContinueScope push(&break_info, this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004546 if (scope != NULL) {
4547 // Load the function object.
4548 Scope* declaration_scope = scope->DeclarationScope();
4549 HInstruction* function;
4550 HValue* outer_context = environment()->context();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004551 if (declaration_scope->is_script_scope() ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004552 declaration_scope->is_eval_scope()) {
4553 function = new(zone()) HLoadContextSlot(
4554 outer_context, Context::CLOSURE_INDEX, HLoadContextSlot::kNoCheck);
4555 } else {
4556 function = New<HThisFunction>();
4557 }
4558 AddInstruction(function);
4559 // Allocate a block context and store it to the stack frame.
4560 HInstruction* inner_context = Add<HAllocateBlockContext>(
4561 outer_context, function, scope->GetScopeInfo());
4562 HInstruction* instr = Add<HStoreFrameContext>(inner_context);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004563 set_scope(scope);
4564 environment()->BindContext(inner_context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004565 if (instr->HasObservableSideEffects()) {
4566 AddSimulate(stmt->EntryId(), REMOVABLE_SIMULATE);
4567 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004568 VisitDeclarations(scope->declarations());
4569 AddSimulate(stmt->DeclsId(), REMOVABLE_SIMULATE);
4570 }
Ben Murdoch257744e2011-11-30 15:57:28 +00004571 CHECK_BAILOUT(VisitStatements(stmt->statements()));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004572 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004573 set_scope(outer_scope);
4574 if (scope != NULL && current_block() != NULL) {
4575 HValue* inner_context = environment()->context();
4576 HValue* outer_context = Add<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004577 inner_context, nullptr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004578 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
4579
4580 HInstruction* instr = Add<HStoreFrameContext>(outer_context);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004581 environment()->BindContext(outer_context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004582 if (instr->HasObservableSideEffects()) {
4583 AddSimulate(stmt->ExitId(), REMOVABLE_SIMULATE);
4584 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004585 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004586 HBasicBlock* break_block = break_info.break_block();
4587 if (break_block != NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004588 if (current_block() != NULL) Goto(break_block);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004589 break_block->SetJoinId(stmt->ExitId());
4590 set_current_block(break_block);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004591 }
4592}
4593
4594
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004595void HOptimizedGraphBuilder::VisitExpressionStatement(
4596 ExpressionStatement* stmt) {
4597 DCHECK(!HasStackOverflow());
4598 DCHECK(current_block() != NULL);
4599 DCHECK(current_block()->HasPredecessor());
Ben Murdochb0fe1622011-05-05 13:52:32 +01004600 VisitForEffect(stmt->expression());
4601}
4602
4603
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004604void HOptimizedGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
4605 DCHECK(!HasStackOverflow());
4606 DCHECK(current_block() != NULL);
4607 DCHECK(current_block()->HasPredecessor());
Ben Murdochb0fe1622011-05-05 13:52:32 +01004608}
4609
4610
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004611void HOptimizedGraphBuilder::VisitIfStatement(IfStatement* stmt) {
4612 DCHECK(!HasStackOverflow());
4613 DCHECK(current_block() != NULL);
4614 DCHECK(current_block()->HasPredecessor());
Ben Murdochb0fe1622011-05-05 13:52:32 +01004615 if (stmt->condition()->ToBooleanIsTrue()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004616 Add<HSimulate>(stmt->ThenId());
Ben Murdochb0fe1622011-05-05 13:52:32 +01004617 Visit(stmt->then_statement());
4618 } else if (stmt->condition()->ToBooleanIsFalse()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004619 Add<HSimulate>(stmt->ElseId());
Ben Murdochb0fe1622011-05-05 13:52:32 +01004620 Visit(stmt->else_statement());
4621 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004622 HBasicBlock* cond_true = graph()->CreateBasicBlock();
4623 HBasicBlock* cond_false = graph()->CreateBasicBlock();
Ben Murdoch257744e2011-11-30 15:57:28 +00004624 CHECK_BAILOUT(VisitForControl(stmt->condition(), cond_true, cond_false));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004625
Ben Murdoch257744e2011-11-30 15:57:28 +00004626 if (cond_true->HasPredecessor()) {
4627 cond_true->SetJoinId(stmt->ThenId());
4628 set_current_block(cond_true);
4629 CHECK_BAILOUT(Visit(stmt->then_statement()));
4630 cond_true = current_block();
4631 } else {
4632 cond_true = NULL;
4633 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01004634
Ben Murdoch257744e2011-11-30 15:57:28 +00004635 if (cond_false->HasPredecessor()) {
4636 cond_false->SetJoinId(stmt->ElseId());
4637 set_current_block(cond_false);
4638 CHECK_BAILOUT(Visit(stmt->else_statement()));
4639 cond_false = current_block();
4640 } else {
4641 cond_false = NULL;
4642 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01004643
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004644 HBasicBlock* join = CreateJoin(cond_true, cond_false, stmt->IfId());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004645 set_current_block(join);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004646 }
4647}
4648
4649
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004650HBasicBlock* HOptimizedGraphBuilder::BreakAndContinueScope::Get(
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004651 BreakableStatement* stmt,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004652 BreakType type,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004653 Scope** scope,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004654 int* drop_extra) {
4655 *drop_extra = 0;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004656 BreakAndContinueScope* current = this;
4657 while (current != NULL && current->info()->target() != stmt) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004658 *drop_extra += current->info()->drop_extra();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004659 current = current->next();
4660 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004661 DCHECK(current != NULL); // Always found (unless stack is malformed).
4662 *scope = current->info()->scope();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004663
4664 if (type == BREAK) {
4665 *drop_extra += current->info()->drop_extra();
4666 }
4667
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004668 HBasicBlock* block = NULL;
4669 switch (type) {
4670 case BREAK:
4671 block = current->info()->break_block();
4672 if (block == NULL) {
4673 block = current->owner()->graph()->CreateBasicBlock();
4674 current->info()->set_break_block(block);
4675 }
4676 break;
4677
4678 case CONTINUE:
4679 block = current->info()->continue_block();
4680 if (block == NULL) {
4681 block = current->owner()->graph()->CreateBasicBlock();
4682 current->info()->set_continue_block(block);
4683 }
4684 break;
4685 }
4686
4687 return block;
4688}
4689
4690
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004691void HOptimizedGraphBuilder::VisitContinueStatement(
4692 ContinueStatement* stmt) {
4693 DCHECK(!HasStackOverflow());
4694 DCHECK(current_block() != NULL);
4695 DCHECK(current_block()->HasPredecessor());
4696 Scope* outer_scope = NULL;
4697 Scope* inner_scope = scope();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004698 int drop_extra = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004699 HBasicBlock* continue_block = break_scope()->Get(
4700 stmt->target(), BreakAndContinueScope::CONTINUE,
4701 &outer_scope, &drop_extra);
4702 HValue* context = environment()->context();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004703 Drop(drop_extra);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004704 int context_pop_count = inner_scope->ContextChainLength(outer_scope);
4705 if (context_pop_count > 0) {
4706 while (context_pop_count-- > 0) {
4707 HInstruction* context_instruction = Add<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004708 context, nullptr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004709 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
4710 context = context_instruction;
4711 }
4712 HInstruction* instr = Add<HStoreFrameContext>(context);
4713 if (instr->HasObservableSideEffects()) {
4714 AddSimulate(stmt->target()->EntryId(), REMOVABLE_SIMULATE);
4715 }
4716 environment()->BindContext(context);
4717 }
4718
4719 Goto(continue_block);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004720 set_current_block(NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004721}
4722
4723
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004724void HOptimizedGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
4725 DCHECK(!HasStackOverflow());
4726 DCHECK(current_block() != NULL);
4727 DCHECK(current_block()->HasPredecessor());
4728 Scope* outer_scope = NULL;
4729 Scope* inner_scope = scope();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004730 int drop_extra = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004731 HBasicBlock* break_block = break_scope()->Get(
4732 stmt->target(), BreakAndContinueScope::BREAK,
4733 &outer_scope, &drop_extra);
4734 HValue* context = environment()->context();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004735 Drop(drop_extra);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004736 int context_pop_count = inner_scope->ContextChainLength(outer_scope);
4737 if (context_pop_count > 0) {
4738 while (context_pop_count-- > 0) {
4739 HInstruction* context_instruction = Add<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004740 context, nullptr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004741 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
4742 context = context_instruction;
4743 }
4744 HInstruction* instr = Add<HStoreFrameContext>(context);
4745 if (instr->HasObservableSideEffects()) {
4746 AddSimulate(stmt->target()->ExitId(), REMOVABLE_SIMULATE);
4747 }
4748 environment()->BindContext(context);
4749 }
4750 Goto(break_block);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004751 set_current_block(NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004752}
4753
4754
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004755void HOptimizedGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
4756 DCHECK(!HasStackOverflow());
4757 DCHECK(current_block() != NULL);
4758 DCHECK(current_block()->HasPredecessor());
4759 FunctionState* state = function_state();
Ben Murdochb0fe1622011-05-05 13:52:32 +01004760 AstContext* context = call_context();
4761 if (context == NULL) {
4762 // Not an inlined return, so an actual one.
Ben Murdoch257744e2011-11-30 15:57:28 +00004763 CHECK_ALIVE(VisitForValue(stmt->expression()));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004764 HValue* result = environment()->Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004765 Add<HReturn>(result);
4766 } else if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) {
4767 // Return from an inlined construct call. In a test context the return value
4768 // will always evaluate to true, in a value context the return value needs
4769 // to be a JSObject.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004770 if (context->IsTest()) {
4771 TestContext* test = TestContext::cast(context);
4772 CHECK_ALIVE(VisitForEffect(stmt->expression()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004773 Goto(test->if_true(), state);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004774 } else if (context->IsEffect()) {
4775 CHECK_ALIVE(VisitForEffect(stmt->expression()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004776 Goto(function_return(), state);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004777 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004778 DCHECK(context->IsValue());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004779 CHECK_ALIVE(VisitForValue(stmt->expression()));
4780 HValue* return_value = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004781 HValue* receiver = environment()->arguments_environment()->Lookup(0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004782 HHasInstanceTypeAndBranch* typecheck =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004783 New<HHasInstanceTypeAndBranch>(return_value,
4784 FIRST_SPEC_OBJECT_TYPE,
4785 LAST_SPEC_OBJECT_TYPE);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004786 HBasicBlock* if_spec_object = graph()->CreateBasicBlock();
4787 HBasicBlock* not_spec_object = graph()->CreateBasicBlock();
4788 typecheck->SetSuccessorAt(0, if_spec_object);
4789 typecheck->SetSuccessorAt(1, not_spec_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004790 FinishCurrentBlock(typecheck);
4791 AddLeaveInlined(if_spec_object, return_value, state);
4792 AddLeaveInlined(not_spec_object, receiver, state);
4793 }
4794 } else if (state->inlining_kind() == SETTER_CALL_RETURN) {
4795 // Return from an inlined setter call. The returned value is never used, the
4796 // value of an assignment is always the value of the RHS of the assignment.
4797 CHECK_ALIVE(VisitForEffect(stmt->expression()));
4798 if (context->IsTest()) {
4799 HValue* rhs = environment()->arguments_environment()->Lookup(1);
4800 context->ReturnValue(rhs);
4801 } else if (context->IsEffect()) {
4802 Goto(function_return(), state);
4803 } else {
4804 DCHECK(context->IsValue());
4805 HValue* rhs = environment()->arguments_environment()->Lookup(1);
4806 AddLeaveInlined(rhs, state);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004807 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01004808 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004809 // Return from a normal inlined function. Visit the subexpression in the
Ben Murdochb0fe1622011-05-05 13:52:32 +01004810 // expression context of the call.
4811 if (context->IsTest()) {
4812 TestContext* test = TestContext::cast(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004813 VisitForControl(stmt->expression(), test->if_true(), test->if_false());
Steve Block44f0eee2011-05-26 01:26:41 +01004814 } else if (context->IsEffect()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004815 // Visit in value context and ignore the result. This is needed to keep
4816 // environment in sync with full-codegen since some visitors (e.g.
4817 // VisitCountOperation) use the operand stack differently depending on
4818 // context.
Ben Murdoch257744e2011-11-30 15:57:28 +00004819 CHECK_ALIVE(VisitForValue(stmt->expression()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004820 Pop();
4821 Goto(function_return(), state);
4822 } else {
4823 DCHECK(context->IsValue());
4824 CHECK_ALIVE(VisitForValue(stmt->expression()));
4825 AddLeaveInlined(Pop(), state);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004826 }
4827 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004828 set_current_block(NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004829}
4830
4831
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004832void HOptimizedGraphBuilder::VisitWithStatement(WithStatement* stmt) {
4833 DCHECK(!HasStackOverflow());
4834 DCHECK(current_block() != NULL);
4835 DCHECK(current_block()->HasPredecessor());
4836 return Bailout(kWithStatement);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004837}
4838
4839
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004840void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
4841 DCHECK(!HasStackOverflow());
4842 DCHECK(current_block() != NULL);
4843 DCHECK(current_block()->HasPredecessor());
4844
Ben Murdochb0fe1622011-05-05 13:52:32 +01004845 ZoneList<CaseClause*>* clauses = stmt->cases();
Steve Block44f0eee2011-05-26 01:26:41 +01004846 int clause_count = clauses->length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004847 ZoneList<HBasicBlock*> body_blocks(clause_count, zone());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004848
Ben Murdoch257744e2011-11-30 15:57:28 +00004849 CHECK_ALIVE(VisitForValue(stmt->tag()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004850 Add<HSimulate>(stmt->EntryId());
4851 HValue* tag_value = Top();
4852 Type* tag_type = stmt->tag()->bounds().lower;
Steve Block44f0eee2011-05-26 01:26:41 +01004853
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004854 // 1. Build all the tests, with dangling true branches
4855 BailoutId default_id = BailoutId::None();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004856 for (int i = 0; i < clause_count; ++i) {
4857 CaseClause* clause = clauses->at(i);
4858 if (clause->is_default()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004859 body_blocks.Add(NULL, zone());
4860 if (default_id.IsNone()) default_id = clause->EntryId();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004861 continue;
4862 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01004863
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004864 // Generate a compare and branch.
Ben Murdoch257744e2011-11-30 15:57:28 +00004865 CHECK_ALIVE(VisitForValue(clause->label()));
Steve Block44f0eee2011-05-26 01:26:41 +01004866 HValue* label_value = Pop();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004867
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004868 Type* label_type = clause->label()->bounds().lower;
4869 Type* combined_type = clause->compare_type();
4870 HControlInstruction* compare = BuildCompareInstruction(
4871 Token::EQ_STRICT, tag_value, label_value, tag_type, label_type,
4872 combined_type,
4873 ScriptPositionToSourcePosition(stmt->tag()->position()),
4874 ScriptPositionToSourcePosition(clause->label()->position()),
4875 PUSH_BEFORE_SIMULATE, clause->id());
4876
Ben Murdoch85b71792012-04-11 18:30:58 +01004877 HBasicBlock* next_test_block = graph()->CreateBasicBlock();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004878 HBasicBlock* body_block = graph()->CreateBasicBlock();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004879 body_blocks.Add(body_block, zone());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004880 compare->SetSuccessorAt(0, body_block);
4881 compare->SetSuccessorAt(1, next_test_block);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004882 FinishCurrentBlock(compare);
4883
4884 set_current_block(body_block);
4885 Drop(1); // tag_value
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004886
Steve Block44f0eee2011-05-26 01:26:41 +01004887 set_current_block(next_test_block);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004888 }
4889
Steve Block44f0eee2011-05-26 01:26:41 +01004890 // Save the current block to use for the default or to join with the
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004891 // exit.
Steve Block44f0eee2011-05-26 01:26:41 +01004892 HBasicBlock* last_block = current_block();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004893 Drop(1); // tag_value
Ben Murdochb0fe1622011-05-05 13:52:32 +01004894
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004895 // 2. Loop over the clauses and the linked list of tests in lockstep,
Steve Block44f0eee2011-05-26 01:26:41 +01004896 // translating the clause bodies.
Steve Block44f0eee2011-05-26 01:26:41 +01004897 HBasicBlock* fall_through_block = NULL;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004898
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004899 BreakAndContinueInfo break_info(stmt, scope());
Steve Block44f0eee2011-05-26 01:26:41 +01004900 { BreakAndContinueScope push(&break_info, this);
4901 for (int i = 0; i < clause_count; ++i) {
4902 CaseClause* clause = clauses->at(i);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004903
Steve Block44f0eee2011-05-26 01:26:41 +01004904 // Identify the block where normal (non-fall-through) control flow
4905 // goes to.
4906 HBasicBlock* normal_block = NULL;
Steve Block053d10c2011-06-13 19:13:29 +01004907 if (clause->is_default()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004908 if (last_block == NULL) continue;
4909 normal_block = last_block;
4910 last_block = NULL; // Cleared to indicate we've handled it.
4911 } else {
4912 normal_block = body_blocks[i];
Steve Block44f0eee2011-05-26 01:26:41 +01004913 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01004914
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004915 if (fall_through_block == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +01004916 set_current_block(normal_block);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004917 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01004918 HBasicBlock* join = CreateJoin(fall_through_block,
4919 normal_block,
4920 clause->EntryId());
4921 set_current_block(join);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004922 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01004923
Ben Murdoch257744e2011-11-30 15:57:28 +00004924 CHECK_BAILOUT(VisitStatements(clause->statements()));
Steve Block44f0eee2011-05-26 01:26:41 +01004925 fall_through_block = current_block();
Ben Murdochb0fe1622011-05-05 13:52:32 +01004926 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01004927 }
4928
Steve Block44f0eee2011-05-26 01:26:41 +01004929 // Create an up-to-3-way join. Use the break block if it exists since
4930 // it's already a join block.
4931 HBasicBlock* break_block = break_info.break_block();
4932 if (break_block == NULL) {
4933 set_current_block(CreateJoin(fall_through_block,
4934 last_block,
4935 stmt->ExitId()));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004936 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004937 if (fall_through_block != NULL) Goto(fall_through_block, break_block);
4938 if (last_block != NULL) Goto(last_block, break_block);
Steve Block44f0eee2011-05-26 01:26:41 +01004939 break_block->SetJoinId(stmt->ExitId());
4940 set_current_block(break_block);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004941 }
4942}
4943
Steve Block44f0eee2011-05-26 01:26:41 +01004944
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004945void HOptimizedGraphBuilder::VisitLoopBody(IterationStatement* stmt,
4946 HBasicBlock* loop_entry) {
4947 Add<HSimulate>(stmt->StackCheckId());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004948 HStackCheck* stack_check =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004949 HStackCheck::cast(Add<HStackCheck>(HStackCheck::kBackwardsBranch));
4950 DCHECK(loop_entry->IsLoopHeader());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004951 loop_entry->loop_information()->set_stack_check(stack_check);
4952 CHECK_BAILOUT(Visit(stmt->body()));
4953}
4954
4955
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004956void HOptimizedGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
4957 DCHECK(!HasStackOverflow());
4958 DCHECK(current_block() != NULL);
4959 DCHECK(current_block()->HasPredecessor());
4960 DCHECK(current_block() != NULL);
4961 HBasicBlock* loop_entry = BuildLoopEntry(stmt);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004962
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004963 BreakAndContinueInfo break_info(stmt, scope());
4964 {
4965 BreakAndContinueScope push(&break_info, this);
4966 CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry));
4967 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004968 HBasicBlock* body_exit =
4969 JoinContinue(stmt, current_block(), break_info.continue_block());
4970 HBasicBlock* loop_successor = NULL;
4971 if (body_exit != NULL && !stmt->cond()->ToBooleanIsTrue()) {
4972 set_current_block(body_exit);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004973 loop_successor = graph()->CreateBasicBlock();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004974 if (stmt->cond()->ToBooleanIsFalse()) {
4975 loop_entry->loop_information()->stack_check()->Eliminate();
4976 Goto(loop_successor);
4977 body_exit = NULL;
4978 } else {
4979 // The block for a true condition, the actual predecessor block of the
4980 // back edge.
4981 body_exit = graph()->CreateBasicBlock();
4982 CHECK_BAILOUT(VisitForControl(stmt->cond(), body_exit, loop_successor));
4983 }
4984 if (body_exit != NULL && body_exit->HasPredecessor()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00004985 body_exit->SetJoinId(stmt->BackEdgeId());
4986 } else {
4987 body_exit = NULL;
4988 }
4989 if (loop_successor->HasPredecessor()) {
4990 loop_successor->SetJoinId(stmt->ExitId());
4991 } else {
4992 loop_successor = NULL;
4993 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004994 }
4995 HBasicBlock* loop_exit = CreateLoop(stmt,
4996 loop_entry,
4997 body_exit,
4998 loop_successor,
4999 break_info.break_block());
5000 set_current_block(loop_exit);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005001}
5002
5003
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005004void HOptimizedGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
5005 DCHECK(!HasStackOverflow());
5006 DCHECK(current_block() != NULL);
5007 DCHECK(current_block()->HasPredecessor());
5008 DCHECK(current_block() != NULL);
5009 HBasicBlock* loop_entry = BuildLoopEntry(stmt);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005010
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005011 // If the condition is constant true, do not generate a branch.
5012 HBasicBlock* loop_successor = NULL;
5013 if (!stmt->cond()->ToBooleanIsTrue()) {
5014 HBasicBlock* body_entry = graph()->CreateBasicBlock();
5015 loop_successor = graph()->CreateBasicBlock();
Ben Murdoch257744e2011-11-30 15:57:28 +00005016 CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor));
5017 if (body_entry->HasPredecessor()) {
5018 body_entry->SetJoinId(stmt->BodyId());
5019 set_current_block(body_entry);
5020 }
5021 if (loop_successor->HasPredecessor()) {
5022 loop_successor->SetJoinId(stmt->ExitId());
5023 } else {
5024 loop_successor = NULL;
5025 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01005026 }
5027
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005028 BreakAndContinueInfo break_info(stmt, scope());
Ben Murdoch257744e2011-11-30 15:57:28 +00005029 if (current_block() != NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005030 BreakAndContinueScope push(&break_info, this);
5031 CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005032 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005033 HBasicBlock* body_exit =
5034 JoinContinue(stmt, current_block(), break_info.continue_block());
5035 HBasicBlock* loop_exit = CreateLoop(stmt,
5036 loop_entry,
5037 body_exit,
5038 loop_successor,
5039 break_info.break_block());
5040 set_current_block(loop_exit);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005041}
5042
5043
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005044void HOptimizedGraphBuilder::VisitForStatement(ForStatement* stmt) {
5045 DCHECK(!HasStackOverflow());
5046 DCHECK(current_block() != NULL);
5047 DCHECK(current_block()->HasPredecessor());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005048 if (stmt->init() != NULL) {
Ben Murdoch257744e2011-11-30 15:57:28 +00005049 CHECK_ALIVE(Visit(stmt->init()));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005050 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005051 DCHECK(current_block() != NULL);
5052 HBasicBlock* loop_entry = BuildLoopEntry(stmt);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005053
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005054 HBasicBlock* loop_successor = NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +01005055 if (stmt->cond() != NULL) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005056 HBasicBlock* body_entry = graph()->CreateBasicBlock();
5057 loop_successor = graph()->CreateBasicBlock();
Ben Murdoch257744e2011-11-30 15:57:28 +00005058 CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor));
5059 if (body_entry->HasPredecessor()) {
5060 body_entry->SetJoinId(stmt->BodyId());
5061 set_current_block(body_entry);
5062 }
5063 if (loop_successor->HasPredecessor()) {
5064 loop_successor->SetJoinId(stmt->ExitId());
5065 } else {
5066 loop_successor = NULL;
5067 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01005068 }
5069
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005070 BreakAndContinueInfo break_info(stmt, scope());
Ben Murdoch257744e2011-11-30 15:57:28 +00005071 if (current_block() != NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005072 BreakAndContinueScope push(&break_info, this);
5073 CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005074 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005075 HBasicBlock* body_exit =
5076 JoinContinue(stmt, current_block(), break_info.continue_block());
5077
5078 if (stmt->next() != NULL && body_exit != NULL) {
5079 set_current_block(body_exit);
Ben Murdoch257744e2011-11-30 15:57:28 +00005080 CHECK_BAILOUT(Visit(stmt->next()));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005081 body_exit = current_block();
5082 }
5083
5084 HBasicBlock* loop_exit = CreateLoop(stmt,
5085 loop_entry,
5086 body_exit,
5087 loop_successor,
5088 break_info.break_block());
5089 set_current_block(loop_exit);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005090}
5091
5092
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005093void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
5094 DCHECK(!HasStackOverflow());
5095 DCHECK(current_block() != NULL);
5096 DCHECK(current_block()->HasPredecessor());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005097
5098 if (!FLAG_optimize_for_in) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005099 return Bailout(kForInStatementOptimizationIsDisabled);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005100 }
5101
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005102 if (stmt->for_in_type() != ForInStatement::FAST_FOR_IN) {
5103 return Bailout(kForInStatementIsNotFastCase);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005104 }
5105
5106 if (!stmt->each()->IsVariableProxy() ||
5107 !stmt->each()->AsVariableProxy()->var()->IsStackLocal()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005108 return Bailout(kForInStatementWithNonLocalEachVariable);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005109 }
5110
5111 Variable* each_var = stmt->each()->AsVariableProxy()->var();
5112
5113 CHECK_ALIVE(VisitForValue(stmt->enumerable()));
5114 HValue* enumerable = Top(); // Leave enumerable at the top.
5115
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005116 HInstruction* map = Add<HForInPrepareMap>(enumerable);
5117 Add<HSimulate>(stmt->PrepareId());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005118
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005119 HInstruction* array = Add<HForInCacheArray>(
5120 enumerable, map, DescriptorArray::kEnumCacheBridgeCacheIndex);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005121
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005122 HInstruction* enum_length = Add<HMapEnumLength>(map);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005123
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005124 HInstruction* start_index = Add<HConstant>(0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005125
5126 Push(map);
5127 Push(array);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005128 Push(enum_length);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005129 Push(start_index);
5130
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005131 HInstruction* index_cache = Add<HForInCacheArray>(
5132 enumerable, map, DescriptorArray::kEnumCacheBridgeIndicesCacheIndex);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005133 HForInCacheArray::cast(array)->set_index_cache(
5134 HForInCacheArray::cast(index_cache));
5135
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005136 HBasicBlock* loop_entry = BuildLoopEntry(stmt);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005137
5138 HValue* index = environment()->ExpressionStackAt(0);
5139 HValue* limit = environment()->ExpressionStackAt(1);
5140
5141 // Check that we still have more keys.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005142 HCompareNumericAndBranch* compare_index =
5143 New<HCompareNumericAndBranch>(index, limit, Token::LT);
5144 compare_index->set_observed_input_representation(
5145 Representation::Smi(), Representation::Smi());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005146
5147 HBasicBlock* loop_body = graph()->CreateBasicBlock();
5148 HBasicBlock* loop_successor = graph()->CreateBasicBlock();
5149
5150 compare_index->SetSuccessorAt(0, loop_body);
5151 compare_index->SetSuccessorAt(1, loop_successor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005152 FinishCurrentBlock(compare_index);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005153
5154 set_current_block(loop_successor);
5155 Drop(5);
5156
5157 set_current_block(loop_body);
5158
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005159 HValue* key = Add<HLoadKeyed>(
5160 environment()->ExpressionStackAt(2), // Enum cache.
5161 environment()->ExpressionStackAt(0), // Iteration index.
5162 environment()->ExpressionStackAt(0),
5163 FAST_ELEMENTS);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005164
5165 // Check if the expected map still matches that of the enumerable.
5166 // If not just deoptimize.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005167 Add<HCheckMapValue>(environment()->ExpressionStackAt(4),
5168 environment()->ExpressionStackAt(3));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005169
5170 Bind(each_var, key);
5171
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005172 BreakAndContinueInfo break_info(stmt, scope(), 5);
5173 {
5174 BreakAndContinueScope push(&break_info, this);
5175 CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry));
5176 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005177
5178 HBasicBlock* body_exit =
5179 JoinContinue(stmt, current_block(), break_info.continue_block());
5180
5181 if (body_exit != NULL) {
5182 set_current_block(body_exit);
5183
5184 HValue* current_index = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005185 Push(AddUncasted<HAdd>(current_index, graph()->GetConstant1()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005186 body_exit = current_block();
5187 }
5188
5189 HBasicBlock* loop_exit = CreateLoop(stmt,
5190 loop_entry,
5191 body_exit,
5192 loop_successor,
5193 break_info.break_block());
5194
5195 set_current_block(loop_exit);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005196}
5197
5198
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005199void HOptimizedGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) {
5200 DCHECK(!HasStackOverflow());
5201 DCHECK(current_block() != NULL);
5202 DCHECK(current_block()->HasPredecessor());
5203 return Bailout(kForOfStatement);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005204}
5205
5206
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005207void HOptimizedGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
5208 DCHECK(!HasStackOverflow());
5209 DCHECK(current_block() != NULL);
5210 DCHECK(current_block()->HasPredecessor());
5211 return Bailout(kTryCatchStatement);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005212}
5213
5214
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005215void HOptimizedGraphBuilder::VisitTryFinallyStatement(
5216 TryFinallyStatement* stmt) {
5217 DCHECK(!HasStackOverflow());
5218 DCHECK(current_block() != NULL);
5219 DCHECK(current_block()->HasPredecessor());
5220 return Bailout(kTryFinallyStatement);
Ben Murdoch8b112d22011-06-08 16:22:53 +01005221}
5222
5223
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005224void HOptimizedGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
5225 DCHECK(!HasStackOverflow());
5226 DCHECK(current_block() != NULL);
5227 DCHECK(current_block()->HasPredecessor());
5228 return Bailout(kDebuggerStatement);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005229}
5230
5231
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005232void HOptimizedGraphBuilder::VisitCaseClause(CaseClause* clause) {
5233 UNREACHABLE();
5234}
5235
5236
5237void HOptimizedGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
5238 DCHECK(!HasStackOverflow());
5239 DCHECK(current_block() != NULL);
5240 DCHECK(current_block()->HasPredecessor());
5241 Handle<SharedFunctionInfo> shared_info = expr->shared_info();
Ben Murdoch8b112d22011-06-08 16:22:53 +01005242 if (shared_info.is_null()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005243 shared_info =
5244 Compiler::BuildFunctionInfo(expr, current_info()->script(), top_info());
Ben Murdoch8b112d22011-06-08 16:22:53 +01005245 }
Ben Murdoch257744e2011-11-30 15:57:28 +00005246 // We also have a stack overflow if the recursive compilation did.
5247 if (HasStackOverflow()) return;
Ben Murdochb0fe1622011-05-05 13:52:32 +01005248 HFunctionLiteral* instr =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005249 New<HFunctionLiteral>(shared_info, expr->pretenure());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005250 return ast_context()->ReturnInstruction(instr, expr->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +01005251}
5252
5253
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005254void HOptimizedGraphBuilder::VisitClassLiteral(ClassLiteral* lit) {
5255 DCHECK(!HasStackOverflow());
5256 DCHECK(current_block() != NULL);
5257 DCHECK(current_block()->HasPredecessor());
5258 return Bailout(kClassLiteral);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005259}
5260
5261
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005262void HOptimizedGraphBuilder::VisitNativeFunctionLiteral(
5263 NativeFunctionLiteral* expr) {
5264 DCHECK(!HasStackOverflow());
5265 DCHECK(current_block() != NULL);
5266 DCHECK(current_block()->HasPredecessor());
5267 return Bailout(kNativeFunctionLiteral);
5268}
5269
5270
5271void HOptimizedGraphBuilder::VisitConditional(Conditional* expr) {
5272 DCHECK(!HasStackOverflow());
5273 DCHECK(current_block() != NULL);
5274 DCHECK(current_block()->HasPredecessor());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005275 HBasicBlock* cond_true = graph()->CreateBasicBlock();
5276 HBasicBlock* cond_false = graph()->CreateBasicBlock();
Ben Murdoch257744e2011-11-30 15:57:28 +00005277 CHECK_BAILOUT(VisitForControl(expr->condition(), cond_true, cond_false));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005278
Steve Block44f0eee2011-05-26 01:26:41 +01005279 // Visit the true and false subexpressions in the same AST context as the
5280 // whole expression.
Ben Murdoch257744e2011-11-30 15:57:28 +00005281 if (cond_true->HasPredecessor()) {
5282 cond_true->SetJoinId(expr->ThenId());
5283 set_current_block(cond_true);
5284 CHECK_BAILOUT(Visit(expr->then_expression()));
5285 cond_true = current_block();
5286 } else {
5287 cond_true = NULL;
5288 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01005289
Ben Murdoch257744e2011-11-30 15:57:28 +00005290 if (cond_false->HasPredecessor()) {
5291 cond_false->SetJoinId(expr->ElseId());
5292 set_current_block(cond_false);
5293 CHECK_BAILOUT(Visit(expr->else_expression()));
5294 cond_false = current_block();
5295 } else {
5296 cond_false = NULL;
5297 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01005298
Steve Block44f0eee2011-05-26 01:26:41 +01005299 if (!ast_context()->IsTest()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00005300 HBasicBlock* join = CreateJoin(cond_true, cond_false, expr->id());
Steve Block44f0eee2011-05-26 01:26:41 +01005301 set_current_block(join);
Ben Murdoch257744e2011-11-30 15:57:28 +00005302 if (join != NULL && !ast_context()->IsEffect()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005303 return ast_context()->ReturnValue(Pop());
Ben Murdoch257744e2011-11-30 15:57:28 +00005304 }
Steve Block44f0eee2011-05-26 01:26:41 +01005305 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01005306}
5307
5308
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005309HOptimizedGraphBuilder::GlobalPropertyAccess
5310HOptimizedGraphBuilder::LookupGlobalProperty(Variable* var, LookupIterator* it,
5311 PropertyAccessType access_type) {
5312 if (var->is_this() || !current_info()->has_global_object()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01005313 return kUseGeneric;
Ben Murdochb0fe1622011-05-05 13:52:32 +01005314 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01005315
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005316 switch (it->state()) {
5317 case LookupIterator::ACCESSOR:
5318 case LookupIterator::ACCESS_CHECK:
5319 case LookupIterator::INTERCEPTOR:
5320 case LookupIterator::NOT_FOUND:
5321 return kUseGeneric;
5322 case LookupIterator::DATA:
5323 if (access_type == STORE && it->IsReadOnly()) return kUseGeneric;
5324 return kUseCell;
5325 case LookupIterator::JSPROXY:
5326 case LookupIterator::TRANSITION:
5327 UNREACHABLE();
5328 }
5329 UNREACHABLE();
5330 return kUseGeneric;
Steve Block1e0659c2011-05-24 12:43:12 +01005331}
5332
5333
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005334HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) {
5335 DCHECK(var->IsContextSlot());
5336 HValue* context = environment()->context();
5337 int length = scope()->ContextChainLength(var->scope());
Steve Block1e0659c2011-05-24 12:43:12 +01005338 while (length-- > 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005339 context = Add<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005340 context, nullptr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005341 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
Steve Block1e0659c2011-05-24 12:43:12 +01005342 }
5343 return context;
Ben Murdochb0fe1622011-05-05 13:52:32 +01005344}
5345
5346
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005347void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
5348 if (expr->is_this()) {
5349 current_info()->set_this_has_uses(true);
5350 }
5351
5352 DCHECK(!HasStackOverflow());
5353 DCHECK(current_block() != NULL);
5354 DCHECK(current_block()->HasPredecessor());
Ben Murdoch589d6972011-11-30 16:04:58 +00005355 Variable* variable = expr->var();
Ben Murdoch589d6972011-11-30 16:04:58 +00005356 switch (variable->location()) {
5357 case Variable::UNALLOCATED: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005358 if (IsLexicalVariableMode(variable->mode())) {
5359 // TODO(rossberg): should this be an DCHECK?
5360 return Bailout(kReferenceToGlobalLexicalVariable);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005361 }
5362 // Handle known global constants like 'undefined' specially to avoid a
5363 // load from a global cell for them.
5364 Handle<Object> constant_value =
5365 isolate()->factory()->GlobalConstantFor(variable->name());
5366 if (!constant_value.is_null()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005367 HConstant* instr = New<HConstant>(constant_value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005368 return ast_context()->ReturnInstruction(instr, expr->id());
5369 }
5370
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005371 Handle<GlobalObject> global(current_info()->global_object());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005372
5373 if (FLAG_harmony_scoping) {
5374 Handle<ScriptContextTable> script_contexts(
5375 global->native_context()->script_context_table());
5376 ScriptContextTable::LookupResult lookup;
5377 if (ScriptContextTable::Lookup(script_contexts, variable->name(),
5378 &lookup)) {
5379 Handle<Context> script_context = ScriptContextTable::GetContext(
5380 script_contexts, lookup.context_index);
5381 HInstruction* result = New<HLoadNamedField>(
5382 Add<HConstant>(script_context), nullptr,
5383 HObjectAccess::ForContextSlot(lookup.slot_index));
5384 return ast_context()->ReturnInstruction(result, expr->id());
5385 }
5386 }
5387
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005388 LookupIterator it(global, variable->name(),
5389 LookupIterator::OWN_SKIP_INTERCEPTOR);
5390 GlobalPropertyAccess type = LookupGlobalProperty(variable, &it, LOAD);
Ben Murdoch589d6972011-11-30 16:04:58 +00005391
5392 if (type == kUseCell) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005393 Handle<PropertyCell> cell = it.GetPropertyCell();
5394 if (cell->type()->IsConstant()) {
5395 PropertyCell::AddDependentCompilationInfo(cell, top_info());
5396 Handle<Object> constant_object = cell->type()->AsConstant()->Value();
5397 if (constant_object->IsConsString()) {
5398 constant_object =
5399 String::Flatten(Handle<String>::cast(constant_object));
5400 }
5401 HConstant* constant = New<HConstant>(constant_object);
5402 return ast_context()->ReturnInstruction(constant, expr->id());
5403 } else {
5404 HLoadGlobalCell* instr =
5405 New<HLoadGlobalCell>(cell, it.property_details());
5406 return ast_context()->ReturnInstruction(instr, expr->id());
5407 }
Ben Murdoch589d6972011-11-30 16:04:58 +00005408 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005409 HValue* global_object = Add<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005410 context(), nullptr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005411 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
Ben Murdoch589d6972011-11-30 16:04:58 +00005412 HLoadGlobalGeneric* instr =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005413 New<HLoadGlobalGeneric>(global_object,
5414 variable->name(),
5415 ast_context()->is_for_typeof());
5416 if (FLAG_vector_ics) {
5417 Handle<SharedFunctionInfo> current_shared =
5418 function_state()->compilation_info()->shared_info();
5419 instr->SetVectorAndSlot(
5420 handle(current_shared->feedback_vector(), isolate()),
5421 expr->VariableFeedbackSlot());
5422 }
Ben Murdoch589d6972011-11-30 16:04:58 +00005423 return ast_context()->ReturnInstruction(instr, expr->id());
5424 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01005425 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01005426
Ben Murdoch589d6972011-11-30 16:04:58 +00005427 case Variable::PARAMETER:
5428 case Variable::LOCAL: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005429 HValue* value = LookupAndMakeLive(variable);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005430 if (value == graph()->GetConstantHole()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005431 DCHECK(IsDeclaredVariableMode(variable->mode()) &&
5432 variable->mode() != VAR);
5433 return Bailout(kReferenceToUninitializedVariable);
Ben Murdoch589d6972011-11-30 16:04:58 +00005434 }
5435 return ast_context()->ReturnValue(value);
5436 }
5437
5438 case Variable::CONTEXT: {
Ben Murdoch589d6972011-11-30 16:04:58 +00005439 HValue* context = BuildContextChainWalk(variable);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005440 HLoadContextSlot::Mode mode;
5441 switch (variable->mode()) {
5442 case LET:
5443 case CONST:
5444 mode = HLoadContextSlot::kCheckDeoptimize;
5445 break;
5446 case CONST_LEGACY:
5447 mode = HLoadContextSlot::kCheckReturnUndefined;
5448 break;
5449 default:
5450 mode = HLoadContextSlot::kNoCheck;
5451 break;
5452 }
5453 HLoadContextSlot* instr =
5454 new(zone()) HLoadContextSlot(context, variable->index(), mode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005455 return ast_context()->ReturnInstruction(instr, expr->id());
Ben Murdoch8b112d22011-06-08 16:22:53 +01005456 }
Ben Murdoch589d6972011-11-30 16:04:58 +00005457
5458 case Variable::LOOKUP:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005459 return Bailout(kReferenceToAVariableWhichRequiresDynamicLookup);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005460 }
5461}
5462
5463
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005464void HOptimizedGraphBuilder::VisitLiteral(Literal* expr) {
5465 DCHECK(!HasStackOverflow());
5466 DCHECK(current_block() != NULL);
5467 DCHECK(current_block()->HasPredecessor());
5468 HConstant* instr = New<HConstant>(expr->value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005469 return ast_context()->ReturnInstruction(instr, expr->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +01005470}
5471
5472
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005473void HOptimizedGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
5474 DCHECK(!HasStackOverflow());
5475 DCHECK(current_block() != NULL);
5476 DCHECK(current_block()->HasPredecessor());
5477 Handle<JSFunction> closure = function_state()->compilation_info()->closure();
5478 Handle<FixedArray> literals(closure->literals());
5479 HRegExpLiteral* instr = New<HRegExpLiteral>(literals,
5480 expr->pattern(),
5481 expr->flags(),
5482 expr->literal_index());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005483 return ast_context()->ReturnInstruction(instr, expr->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +01005484}
5485
5486
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005487static bool CanInlinePropertyAccess(Type* type) {
5488 if (type->Is(Type::NumberOrString())) return true;
5489 if (!type->IsClass()) return false;
5490 Handle<Map> map = type->AsClass()->Map();
5491 return map->IsJSObjectMap() &&
5492 !map->is_dictionary_map() &&
5493 !map->has_named_interceptor();
5494}
5495
5496
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005497// Determines whether the given array or object literal boilerplate satisfies
5498// all limits to be considered for fast deep-copying and computes the total
5499// size of all objects that are part of the graph.
5500static bool IsFastLiteral(Handle<JSObject> boilerplate,
5501 int max_depth,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005502 int* max_properties) {
5503 if (boilerplate->map()->is_deprecated() &&
5504 !JSObject::TryMigrateInstance(boilerplate)) {
5505 return false;
5506 }
5507
5508 DCHECK(max_depth >= 0 && *max_properties >= 0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005509 if (max_depth == 0) return false;
5510
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005511 Isolate* isolate = boilerplate->GetIsolate();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005512 Handle<FixedArrayBase> elements(boilerplate->elements());
5513 if (elements->length() > 0 &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005514 elements->map() != isolate->heap()->fixed_cow_array_map()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005515 if (boilerplate->HasFastSmiOrObjectElements()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005516 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005517 int length = elements->length();
5518 for (int i = 0; i < length; i++) {
5519 if ((*max_properties)-- == 0) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005520 Handle<Object> value(fast_elements->get(i), isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005521 if (value->IsJSObject()) {
5522 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
5523 if (!IsFastLiteral(value_object,
5524 max_depth - 1,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005525 max_properties)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005526 return false;
5527 }
5528 }
5529 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005530 } else if (!boilerplate->HasFastDoubleElements()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005531 return false;
5532 }
5533 }
5534
5535 Handle<FixedArray> properties(boilerplate->properties());
5536 if (properties->length() > 0) {
5537 return false;
5538 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005539 Handle<DescriptorArray> descriptors(
5540 boilerplate->map()->instance_descriptors());
5541 int limit = boilerplate->map()->NumberOfOwnDescriptors();
5542 for (int i = 0; i < limit; i++) {
5543 PropertyDetails details = descriptors->GetDetails(i);
5544 if (details.type() != FIELD) continue;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005545 if ((*max_properties)-- == 0) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005546 FieldIndex field_index = FieldIndex::ForDescriptor(boilerplate->map(), i);
5547 if (boilerplate->IsUnboxedDoubleField(field_index)) continue;
5548 Handle<Object> value(boilerplate->RawFastPropertyAt(field_index),
5549 isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005550 if (value->IsJSObject()) {
5551 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
5552 if (!IsFastLiteral(value_object,
5553 max_depth - 1,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005554 max_properties)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005555 return false;
5556 }
5557 }
5558 }
5559 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005560 return true;
5561}
5562
5563
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005564void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
5565 DCHECK(!HasStackOverflow());
5566 DCHECK(current_block() != NULL);
5567 DCHECK(current_block()->HasPredecessor());
5568 expr->BuildConstantProperties(isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005569 Handle<JSFunction> closure = function_state()->compilation_info()->closure();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005570 HInstruction* literal;
5571
5572 // Check whether to use fast or slow deep-copying for boilerplate.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005573 int max_properties = kMaxFastLiteralProperties;
5574 Handle<Object> literals_cell(closure->literals()->get(expr->literal_index()),
5575 isolate());
5576 Handle<AllocationSite> site;
5577 Handle<JSObject> boilerplate;
5578 if (!literals_cell->IsUndefined()) {
5579 // Retrieve the boilerplate
5580 site = Handle<AllocationSite>::cast(literals_cell);
5581 boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()),
5582 isolate());
5583 }
5584
5585 if (!boilerplate.is_null() &&
5586 IsFastLiteral(boilerplate, kMaxFastLiteralDepth, &max_properties)) {
5587 AllocationSiteUsageContext usage_context(isolate(), site, false);
5588 usage_context.EnterNewScope();
5589 literal = BuildFastLiteral(boilerplate, &usage_context);
5590 usage_context.ExitScope(site, boilerplate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005591 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005592 NoObservableSideEffectsScope no_effects(this);
5593 Handle<FixedArray> closure_literals(closure->literals(), isolate());
5594 Handle<FixedArray> constant_properties = expr->constant_properties();
5595 int literal_index = expr->literal_index();
5596 int flags = expr->fast_elements()
5597 ? ObjectLiteral::kFastElements : ObjectLiteral::kNoFlags;
5598 flags |= expr->has_function()
5599 ? ObjectLiteral::kHasFunction : ObjectLiteral::kNoFlags;
5600
5601 Add<HPushArguments>(Add<HConstant>(closure_literals),
5602 Add<HConstant>(literal_index),
5603 Add<HConstant>(constant_properties),
5604 Add<HConstant>(flags));
5605
5606 // TODO(mvstanton): Add a flag to turn off creation of any
5607 // AllocationMementos for this call: we are in crankshaft and should have
5608 // learned enough about transition behavior to stop emitting mementos.
5609 Runtime::FunctionId function_id = Runtime::kCreateObjectLiteral;
5610 literal = Add<HCallRuntime>(isolate()->factory()->empty_string(),
5611 Runtime::FunctionForId(function_id),
5612 4);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005613 }
5614
Ben Murdochb0fe1622011-05-05 13:52:32 +01005615 // The object is expected in the bailout environment during computation
5616 // of the property values and is the value of the entire expression.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005617 Push(literal);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005618
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005619 expr->CalculateEmitStore(zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +01005620
5621 for (int i = 0; i < expr->properties()->length(); i++) {
5622 ObjectLiteral::Property* property = expr->properties()->at(i);
5623 if (property->IsCompileTimeValue()) continue;
5624
5625 Literal* key = property->key();
5626 Expression* value = property->value();
5627
5628 switch (property->kind()) {
5629 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005630 DCHECK(!CompileTimeValue::IsCompileTimeValue(value));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005631 // Fall through.
5632 case ObjectLiteral::Property::COMPUTED:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005633 // It is safe to use [[Put]] here because the boilerplate already
5634 // contains computed properties with an uninitialized value.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005635 if (key->value()->IsInternalizedString()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01005636 if (property->emit_store()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00005637 CHECK_ALIVE(VisitForValue(value));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005638 HValue* value = Pop();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005639
5640 // Add [[HomeObject]] to function literals.
5641 if (FunctionLiteral::NeedsHomeObject(property->value())) {
5642 Handle<Symbol> sym = isolate()->factory()->home_object_symbol();
5643 HInstruction* store_home = BuildKeyedGeneric(
5644 STORE, NULL, value, Add<HConstant>(sym), literal);
5645 AddInstruction(store_home);
5646 DCHECK(store_home->HasObservableSideEffects());
5647 Add<HSimulate>(property->value()->id(), REMOVABLE_SIMULATE);
5648 }
5649
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005650 Handle<Map> map = property->GetReceiverType();
5651 Handle<String> name = property->key()->AsPropertyName();
5652 HInstruction* store;
5653 if (map.is_null()) {
5654 // If we don't know the monomorphic type, do a generic store.
5655 CHECK_ALIVE(store = BuildNamedGeneric(
5656 STORE, NULL, literal, name, value));
5657 } else {
5658 PropertyAccessInfo info(this, STORE, ToType(map), name);
5659 if (info.CanAccessMonomorphic()) {
5660 HValue* checked_literal = Add<HCheckMaps>(literal, map);
5661 DCHECK(!info.IsAccessor());
5662 store = BuildMonomorphicAccess(
5663 &info, literal, checked_literal, value,
5664 BailoutId::None(), BailoutId::None());
5665 } else {
5666 CHECK_ALIVE(store = BuildNamedGeneric(
5667 STORE, NULL, literal, name, value));
5668 }
5669 }
Steve Block1e0659c2011-05-24 12:43:12 +01005670 AddInstruction(store);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005671 DCHECK(store->HasObservableSideEffects());
5672 Add<HSimulate>(key->id(), REMOVABLE_SIMULATE);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005673 } else {
Ben Murdoch257744e2011-11-30 15:57:28 +00005674 CHECK_ALIVE(VisitForEffect(value));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005675 }
5676 break;
5677 }
5678 // Fall through.
5679 case ObjectLiteral::Property::PROTOTYPE:
5680 case ObjectLiteral::Property::SETTER:
5681 case ObjectLiteral::Property::GETTER:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005682 return Bailout(kObjectLiteralWithComplexProperty);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005683 default: UNREACHABLE();
5684 }
5685 }
Steve Block44f0eee2011-05-26 01:26:41 +01005686
5687 if (expr->has_function()) {
5688 // Return the result of the transformation to fast properties
5689 // instead of the original since this operation changes the map
5690 // of the object. This makes sure that the original object won't
5691 // be used by other optimized code before it is transformed
5692 // (e.g. because of code motion).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005693 HToFastProperties* result = Add<HToFastProperties>(Pop());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005694 return ast_context()->ReturnValue(result);
Steve Block44f0eee2011-05-26 01:26:41 +01005695 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005696 return ast_context()->ReturnValue(Pop());
Steve Block44f0eee2011-05-26 01:26:41 +01005697 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01005698}
5699
5700
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005701void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
5702 DCHECK(!HasStackOverflow());
5703 DCHECK(current_block() != NULL);
5704 DCHECK(current_block()->HasPredecessor());
5705 expr->BuildConstantElements(isolate());
Ben Murdochb0fe1622011-05-05 13:52:32 +01005706 ZoneList<Expression*>* subexprs = expr->values();
5707 int length = subexprs->length();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005708 HInstruction* literal;
Ben Murdochb0fe1622011-05-05 13:52:32 +01005709
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005710 Handle<AllocationSite> site;
5711 Handle<FixedArray> literals(environment()->closure()->literals(), isolate());
5712 bool uninitialized = false;
5713 Handle<Object> literals_cell(literals->get(expr->literal_index()),
5714 isolate());
5715 Handle<JSObject> boilerplate_object;
5716 if (literals_cell->IsUndefined()) {
5717 uninitialized = true;
5718 Handle<Object> raw_boilerplate;
5719 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
5720 isolate(), raw_boilerplate,
5721 Runtime::CreateArrayLiteralBoilerplate(
5722 isolate(), literals, expr->constant_elements()),
5723 Bailout(kArrayBoilerplateCreationFailed));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005724
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005725 boilerplate_object = Handle<JSObject>::cast(raw_boilerplate);
5726 AllocationSiteCreationContext creation_context(isolate());
5727 site = creation_context.EnterNewScope();
5728 if (JSObject::DeepWalk(boilerplate_object, &creation_context).is_null()) {
5729 return Bailout(kArrayBoilerplateCreationFailed);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005730 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005731 creation_context.ExitScope(site, boilerplate_object);
5732 literals->set(expr->literal_index(), *site);
5733
5734 if (boilerplate_object->elements()->map() ==
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005735 isolate()->heap()->fixed_cow_array_map()) {
5736 isolate()->counters()->cow_arrays_created_runtime()->Increment();
5737 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005738 } else {
5739 DCHECK(literals_cell->IsAllocationSite());
5740 site = Handle<AllocationSite>::cast(literals_cell);
5741 boilerplate_object = Handle<JSObject>(
5742 JSObject::cast(site->transition_info()), isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005743 }
5744
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005745 DCHECK(!boilerplate_object.is_null());
5746 DCHECK(site->SitePointsToLiteral());
5747
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005748 ElementsKind boilerplate_elements_kind =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005749 boilerplate_object->GetElementsKind();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005750
5751 // Check whether to use fast or slow deep-copying for boilerplate.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005752 int max_properties = kMaxFastLiteralProperties;
5753 if (IsFastLiteral(boilerplate_object,
5754 kMaxFastLiteralDepth,
5755 &max_properties)) {
5756 AllocationSiteUsageContext usage_context(isolate(), site, false);
5757 usage_context.EnterNewScope();
5758 literal = BuildFastLiteral(boilerplate_object, &usage_context);
5759 usage_context.ExitScope(site, boilerplate_object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005760 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005761 NoObservableSideEffectsScope no_effects(this);
5762 // Boilerplate already exists and constant elements are never accessed,
5763 // pass an empty fixed array to the runtime function instead.
5764 Handle<FixedArray> constants = isolate()->factory()->empty_fixed_array();
5765 int literal_index = expr->literal_index();
5766 int flags = expr->depth() == 1
5767 ? ArrayLiteral::kShallowElements
5768 : ArrayLiteral::kNoFlags;
5769 flags |= ArrayLiteral::kDisableMementos;
5770
5771 Add<HPushArguments>(Add<HConstant>(literals),
5772 Add<HConstant>(literal_index),
5773 Add<HConstant>(constants),
5774 Add<HConstant>(flags));
5775
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005776 Runtime::FunctionId function_id = Runtime::kCreateArrayLiteral;
5777 literal = Add<HCallRuntime>(isolate()->factory()->empty_string(),
5778 Runtime::FunctionForId(function_id),
5779 4);
5780
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005781 // Register to deopt if the boilerplate ElementsKind changes.
5782 AllocationSite::RegisterForDeoptOnTransitionChange(site, top_info());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005783 }
5784
Ben Murdochb0fe1622011-05-05 13:52:32 +01005785 // The array is expected in the bailout environment during computation
5786 // of the property values and is the value of the entire expression.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005787 Push(literal);
5788 // The literal index is on the stack, too.
5789 Push(Add<HConstant>(expr->literal_index()));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005790
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005791 HInstruction* elements = NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +01005792
5793 for (int i = 0; i < length; i++) {
5794 Expression* subexpr = subexprs->at(i);
5795 // If the subexpression is a literal or a simple materialized literal it
5796 // is already set in the cloned array.
5797 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
5798
Ben Murdoch257744e2011-11-30 15:57:28 +00005799 CHECK_ALIVE(VisitForValue(subexpr));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005800 HValue* value = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005801 if (!Smi::IsValid(i)) return Bailout(kNonSmiKeyInArrayLiteral);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005802
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005803 elements = AddLoadElements(literal);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005804
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005805 HValue* key = Add<HConstant>(i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005806
5807 switch (boilerplate_elements_kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005808 case FAST_SMI_ELEMENTS:
5809 case FAST_HOLEY_SMI_ELEMENTS:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005810 case FAST_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005811 case FAST_HOLEY_ELEMENTS:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005812 case FAST_DOUBLE_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005813 case FAST_HOLEY_DOUBLE_ELEMENTS: {
5814 HStoreKeyed* instr = Add<HStoreKeyed>(elements, key, value,
5815 boilerplate_elements_kind);
5816 instr->SetUninitialized(uninitialized);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005817 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005818 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005819 default:
5820 UNREACHABLE();
5821 break;
5822 }
5823
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005824 Add<HSimulate>(expr->GetIdForElement(i));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005825 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005826
5827 Drop(1); // array literal index
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005828 return ast_context()->ReturnValue(Pop());
Ben Murdochb0fe1622011-05-05 13:52:32 +01005829}
5830
5831
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005832HCheckMaps* HOptimizedGraphBuilder::AddCheckMap(HValue* object,
5833 Handle<Map> map) {
5834 BuildCheckHeapObject(object);
5835 return Add<HCheckMaps>(object, map);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005836}
5837
5838
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005839HInstruction* HOptimizedGraphBuilder::BuildLoadNamedField(
5840 PropertyAccessInfo* info,
5841 HValue* checked_object) {
5842 // See if this is a load for an immutable property
5843 if (checked_object->ActualValue()->IsConstant()) {
5844 Handle<Object> object(
5845 HConstant::cast(checked_object->ActualValue())->handle(isolate()));
5846
5847 if (object->IsJSObject()) {
5848 LookupIterator it(object, info->name(),
5849 LookupIterator::OWN_SKIP_INTERCEPTOR);
5850 Handle<Object> value = JSObject::GetDataProperty(&it);
5851 if (it.IsFound() && it.IsReadOnly() && !it.IsConfigurable()) {
5852 return New<HConstant>(value);
5853 }
5854 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01005855 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005856
5857 HObjectAccess access = info->access();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005858 if (access.representation().IsDouble() &&
5859 (!FLAG_unbox_double_fields || !access.IsInobject())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005860 // Load the heap number.
5861 checked_object = Add<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005862 checked_object, nullptr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005863 access.WithRepresentation(Representation::Tagged()));
5864 // Load the double value from it.
5865 access = HObjectAccess::ForHeapNumberValue();
5866 }
5867
5868 SmallMapList* map_list = info->field_maps();
5869 if (map_list->length() == 0) {
5870 return New<HLoadNamedField>(checked_object, checked_object, access);
5871 }
5872
5873 UniqueSet<Map>* maps = new(zone()) UniqueSet<Map>(map_list->length(), zone());
5874 for (int i = 0; i < map_list->length(); ++i) {
5875 maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone());
5876 }
5877 return New<HLoadNamedField>(
5878 checked_object, checked_object, access, maps, info->field_type());
Ben Murdochb0fe1622011-05-05 13:52:32 +01005879}
5880
5881
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005882HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField(
5883 PropertyAccessInfo* info,
5884 HValue* checked_object,
5885 HValue* value) {
5886 bool transition_to_field = info->IsTransition();
5887 // TODO(verwaest): Move this logic into PropertyAccessInfo.
5888 HObjectAccess field_access = info->access();
5889
5890 HStoreNamedField *instr;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005891 if (field_access.representation().IsDouble() &&
5892 (!FLAG_unbox_double_fields || !field_access.IsInobject())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005893 HObjectAccess heap_number_access =
5894 field_access.WithRepresentation(Representation::Tagged());
5895 if (transition_to_field) {
5896 // The store requires a mutable HeapNumber to be allocated.
5897 NoObservableSideEffectsScope no_side_effects(this);
5898 HInstruction* heap_number_size = Add<HConstant>(HeapNumber::kSize);
5899
5900 // TODO(hpayer): Allocation site pretenuring support.
5901 HInstruction* heap_number = Add<HAllocate>(heap_number_size,
5902 HType::HeapObject(),
5903 NOT_TENURED,
5904 MUTABLE_HEAP_NUMBER_TYPE);
5905 AddStoreMapConstant(
5906 heap_number, isolate()->factory()->mutable_heap_number_map());
5907 Add<HStoreNamedField>(heap_number, HObjectAccess::ForHeapNumberValue(),
5908 value);
5909 instr = New<HStoreNamedField>(checked_object->ActualValue(),
5910 heap_number_access,
5911 heap_number);
5912 } else {
5913 // Already holds a HeapNumber; load the box and write its value field.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005914 HInstruction* heap_number =
5915 Add<HLoadNamedField>(checked_object, nullptr, heap_number_access);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005916 instr = New<HStoreNamedField>(heap_number,
5917 HObjectAccess::ForHeapNumberValue(),
5918 value, STORE_TO_INITIALIZED_ENTRY);
5919 }
5920 } else {
5921 if (field_access.representation().IsHeapObject()) {
5922 BuildCheckHeapObject(value);
5923 }
5924
5925 if (!info->field_maps()->is_empty()) {
5926 DCHECK(field_access.representation().IsHeapObject());
5927 value = Add<HCheckMaps>(value, info->field_maps());
5928 }
5929
5930 // This is a normal store.
5931 instr = New<HStoreNamedField>(
5932 checked_object->ActualValue(), field_access, value,
5933 transition_to_field ? INITIALIZING_STORE : STORE_TO_INITIALIZED_ENTRY);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005934 }
5935
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005936 if (transition_to_field) {
5937 Handle<Map> transition(info->transition());
5938 DCHECK(!transition->is_deprecated());
5939 instr->SetTransition(Add<HConstant>(transition));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005940 }
5941 return instr;
5942}
5943
5944
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005945bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatible(
5946 PropertyAccessInfo* info) {
5947 if (!CanInlinePropertyAccess(type_)) return false;
5948
5949 // Currently only handle Type::Number as a polymorphic case.
5950 // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber
5951 // instruction.
5952 if (type_->Is(Type::Number())) return false;
5953
5954 // Values are only compatible for monomorphic load if they all behave the same
5955 // regarding value wrappers.
5956 if (type_->Is(Type::NumberOrString())) {
5957 if (!info->type_->Is(Type::NumberOrString())) return false;
5958 } else {
5959 if (info->type_->Is(Type::NumberOrString())) return false;
5960 }
5961
5962 if (!LookupDescriptor()) return false;
5963
5964 if (!IsFound()) {
5965 return (!info->IsFound() || info->has_holder()) &&
5966 map()->prototype() == info->map()->prototype();
5967 }
5968
5969 // Mismatch if the other access info found the property in the prototype
5970 // chain.
5971 if (info->has_holder()) return false;
5972
5973 if (IsAccessor()) {
5974 return accessor_.is_identical_to(info->accessor_) &&
5975 api_holder_.is_identical_to(info->api_holder_);
5976 }
5977
5978 if (IsConstant()) {
5979 return constant_.is_identical_to(info->constant_);
5980 }
5981
5982 DCHECK(IsField());
5983 if (!info->IsField()) return false;
5984
5985 Representation r = access_.representation();
5986 if (IsLoad()) {
5987 if (!info->access_.representation().IsCompatibleForLoad(r)) return false;
5988 } else {
5989 if (!info->access_.representation().IsCompatibleForStore(r)) return false;
5990 }
5991 if (info->access_.offset() != access_.offset()) return false;
5992 if (info->access_.IsInobject() != access_.IsInobject()) return false;
5993 if (IsLoad()) {
5994 if (field_maps_.is_empty()) {
5995 info->field_maps_.Clear();
5996 } else if (!info->field_maps_.is_empty()) {
5997 for (int i = 0; i < field_maps_.length(); ++i) {
5998 info->field_maps_.AddMapIfMissing(field_maps_.at(i), info->zone());
5999 }
6000 info->field_maps_.Sort();
6001 }
6002 } else {
6003 // We can only merge stores that agree on their field maps. The comparison
6004 // below is safe, since we keep the field maps sorted.
6005 if (field_maps_.length() != info->field_maps_.length()) return false;
6006 for (int i = 0; i < field_maps_.length(); ++i) {
6007 if (!field_maps_.at(i).is_identical_to(info->field_maps_.at(i))) {
6008 return false;
6009 }
6010 }
6011 }
6012 info->GeneralizeRepresentation(r);
6013 info->field_type_ = info->field_type_.Combine(field_type_);
6014 return true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006015}
6016
6017
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006018bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() {
6019 if (!type_->IsClass()) return true;
6020 map()->LookupDescriptor(NULL, *name_, &lookup_);
6021 return LoadResult(map());
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01006022}
6023
6024
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006025bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) {
6026 if (!IsLoad() && IsProperty() && IsReadOnly()) {
6027 return false;
6028 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01006029
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006030 if (IsField()) {
6031 // Construct the object field access.
6032 int index = GetLocalFieldIndexFromMap(map);
6033 access_ = HObjectAccess::ForField(map, index, representation(), name_);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006034
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006035 // Load field map for heap objects.
6036 LoadFieldMaps(map);
6037 } else if (IsAccessor()) {
6038 Handle<Object> accessors = GetAccessorsFromMap(map);
6039 if (!accessors->IsAccessorPair()) return false;
6040 Object* raw_accessor =
6041 IsLoad() ? Handle<AccessorPair>::cast(accessors)->getter()
6042 : Handle<AccessorPair>::cast(accessors)->setter();
6043 if (!raw_accessor->IsJSFunction()) return false;
6044 Handle<JSFunction> accessor = handle(JSFunction::cast(raw_accessor));
6045 if (accessor->shared()->IsApiFunction()) {
6046 CallOptimization call_optimization(accessor);
6047 if (call_optimization.is_simple_api_call()) {
6048 CallOptimization::HolderLookup holder_lookup;
6049 Handle<Map> receiver_map = this->map();
6050 api_holder_ = call_optimization.LookupHolderOfExpectedType(
6051 receiver_map, &holder_lookup);
6052 }
6053 }
6054 accessor_ = accessor;
6055 } else if (IsConstant()) {
6056 constant_ = GetConstantFromMap(map);
6057 }
6058
6059 return true;
Ben Murdochb0fe1622011-05-05 13:52:32 +01006060}
6061
6062
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006063void HOptimizedGraphBuilder::PropertyAccessInfo::LoadFieldMaps(
6064 Handle<Map> map) {
6065 // Clear any previously collected field maps/type.
6066 field_maps_.Clear();
6067 field_type_ = HType::Tagged();
6068
6069 // Figure out the field type from the accessor map.
6070 Handle<HeapType> field_type = GetFieldTypeFromMap(map);
6071
6072 // Collect the (stable) maps from the field type.
6073 int num_field_maps = field_type->NumClasses();
6074 if (num_field_maps == 0) return;
6075 DCHECK(access_.representation().IsHeapObject());
6076 field_maps_.Reserve(num_field_maps, zone());
6077 HeapType::Iterator<Map> it = field_type->Classes();
6078 while (!it.Done()) {
6079 Handle<Map> field_map = it.Current();
6080 if (!field_map->is_stable()) {
6081 field_maps_.Clear();
6082 return;
6083 }
6084 field_maps_.Add(field_map, zone());
6085 it.Advance();
6086 }
6087 field_maps_.Sort();
6088 DCHECK_EQ(num_field_maps, field_maps_.length());
6089
6090 // Determine field HType from field HeapType.
6091 field_type_ = HType::FromType<HeapType>(field_type);
6092 DCHECK(field_type_.IsHeapObject());
6093
6094 // Add dependency on the map that introduced the field.
6095 Map::AddDependentCompilationInfo(GetFieldOwnerFromMap(map),
6096 DependentCode::kFieldTypeGroup, top_info());
6097}
6098
6099
6100bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
6101 Handle<Map> map = this->map();
6102
6103 while (map->prototype()->IsJSObject()) {
6104 holder_ = handle(JSObject::cast(map->prototype()));
6105 if (holder_->map()->is_deprecated()) {
6106 JSObject::TryMigrateInstance(holder_);
6107 }
6108 map = Handle<Map>(holder_->map());
6109 if (!CanInlinePropertyAccess(ToType(map))) {
6110 lookup_.NotFound();
6111 return false;
6112 }
6113 map->LookupDescriptor(*holder_, *name_, &lookup_);
6114 if (IsFound()) return LoadResult(map);
6115 }
6116 lookup_.NotFound();
6117 return true;
6118}
6119
6120
6121bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() {
6122 if (!CanInlinePropertyAccess(type_)) return false;
6123 if (IsJSObjectFieldAccessor()) return IsLoad();
6124 if (this->map()->function_with_prototype() &&
6125 !this->map()->has_non_instance_prototype() &&
6126 name_.is_identical_to(isolate()->factory()->prototype_string())) {
6127 return IsLoad();
6128 }
6129 if (!LookupDescriptor()) return false;
6130 if (IsFound()) return IsLoad() || !IsReadOnly();
6131 if (!LookupInPrototypes()) return false;
6132 if (IsLoad()) return true;
6133
6134 if (IsAccessor()) return true;
6135 Handle<Map> map = this->map();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006136 map->LookupTransition(NULL, *name_, NONE, &lookup_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006137 if (lookup_.IsTransitionToField() && map->unused_property_fields() > 0) {
6138 // Construct the object field access.
6139 int descriptor = transition()->LastAdded();
6140 int index =
6141 transition()->instance_descriptors()->GetFieldIndex(descriptor) -
6142 map->inobject_properties();
6143 PropertyDetails details =
6144 transition()->instance_descriptors()->GetDetails(descriptor);
6145 Representation representation = details.representation();
6146 access_ = HObjectAccess::ForField(map, index, representation, name_);
6147
6148 // Load field map for heap objects.
6149 LoadFieldMaps(transition());
6150 return true;
6151 }
6152 return false;
6153}
6154
6155
6156bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessAsMonomorphic(
6157 SmallMapList* types) {
6158 DCHECK(type_->Is(ToType(types->first())));
6159 if (!CanAccessMonomorphic()) return false;
6160 STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism);
6161 if (types->length() > kMaxLoadPolymorphism) return false;
6162
6163 HObjectAccess access = HObjectAccess::ForMap(); // bogus default
6164 if (GetJSObjectFieldAccess(&access)) {
6165 for (int i = 1; i < types->length(); ++i) {
6166 PropertyAccessInfo test_info(
6167 builder_, access_type_, ToType(types->at(i)), name_);
6168 HObjectAccess test_access = HObjectAccess::ForMap(); // bogus default
6169 if (!test_info.GetJSObjectFieldAccess(&test_access)) return false;
6170 if (!access.Equals(test_access)) return false;
6171 }
6172 return true;
6173 }
6174
6175 // Currently only handle Type::Number as a polymorphic case.
6176 // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber
6177 // instruction.
6178 if (type_->Is(Type::Number())) return false;
6179
6180 // Multiple maps cannot transition to the same target map.
6181 DCHECK(!IsLoad() || !IsTransition());
6182 if (IsTransition() && types->length() > 1) return false;
6183
6184 for (int i = 1; i < types->length(); ++i) {
6185 PropertyAccessInfo test_info(
6186 builder_, access_type_, ToType(types->at(i)), name_);
6187 if (!test_info.IsCompatible(this)) return false;
6188 }
6189
6190 return true;
6191}
6192
6193
6194Handle<Map> HOptimizedGraphBuilder::PropertyAccessInfo::map() {
6195 JSFunction* ctor = IC::GetRootConstructor(
6196 type_, current_info()->closure()->context()->native_context());
6197 if (ctor != NULL) return handle(ctor->initial_map());
6198 return type_->AsClass()->Map();
6199}
6200
6201
6202static bool NeedsWrappingFor(Type* type, Handle<JSFunction> target) {
6203 return type->Is(Type::NumberOrString()) &&
6204 target->shared()->strict_mode() == SLOPPY &&
6205 !target->shared()->native();
6206}
6207
6208
6209HInstruction* HOptimizedGraphBuilder::BuildMonomorphicAccess(
6210 PropertyAccessInfo* info,
6211 HValue* object,
6212 HValue* checked_object,
6213 HValue* value,
6214 BailoutId ast_id,
6215 BailoutId return_id,
6216 bool can_inline_accessor) {
6217
6218 HObjectAccess access = HObjectAccess::ForMap(); // bogus default
6219 if (info->GetJSObjectFieldAccess(&access)) {
6220 DCHECK(info->IsLoad());
6221 return New<HLoadNamedField>(object, checked_object, access);
6222 }
6223
6224 if (info->name().is_identical_to(isolate()->factory()->prototype_string()) &&
6225 info->map()->function_with_prototype()) {
6226 DCHECK(!info->map()->has_non_instance_prototype());
6227 return New<HLoadFunctionPrototype>(checked_object);
6228 }
6229
6230 HValue* checked_holder = checked_object;
6231 if (info->has_holder()) {
6232 Handle<JSObject> prototype(JSObject::cast(info->map()->prototype()));
6233 checked_holder = BuildCheckPrototypeMaps(prototype, info->holder());
6234 }
6235
6236 if (!info->IsFound()) {
6237 DCHECK(info->IsLoad());
6238 return graph()->GetConstantUndefined();
6239 }
6240
6241 if (info->IsField()) {
6242 if (info->IsLoad()) {
6243 return BuildLoadNamedField(info, checked_holder);
6244 } else {
6245 return BuildStoreNamedField(info, checked_object, value);
6246 }
6247 }
6248
6249 if (info->IsTransition()) {
6250 DCHECK(!info->IsLoad());
6251 return BuildStoreNamedField(info, checked_object, value);
6252 }
6253
6254 if (info->IsAccessor()) {
6255 Push(checked_object);
6256 int argument_count = 1;
6257 if (!info->IsLoad()) {
6258 argument_count = 2;
6259 Push(value);
6260 }
6261
6262 if (NeedsWrappingFor(info->type(), info->accessor())) {
6263 HValue* function = Add<HConstant>(info->accessor());
6264 PushArgumentsFromEnvironment(argument_count);
6265 return New<HCallFunction>(function, argument_count, WRAP_AND_CALL);
6266 } else if (FLAG_inline_accessors && can_inline_accessor) {
6267 bool success = info->IsLoad()
6268 ? TryInlineGetter(info->accessor(), info->map(), ast_id, return_id)
6269 : TryInlineSetter(
6270 info->accessor(), info->map(), ast_id, return_id, value);
6271 if (success || HasStackOverflow()) return NULL;
6272 }
6273
6274 PushArgumentsFromEnvironment(argument_count);
6275 return BuildCallConstantFunction(info->accessor(), argument_count);
6276 }
6277
6278 DCHECK(info->IsConstant());
6279 if (info->IsLoad()) {
6280 return New<HConstant>(info->constant());
6281 } else {
6282 return New<HCheckValue>(value, Handle<JSFunction>::cast(info->constant()));
6283 }
6284}
6285
6286
6287void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess(
6288 PropertyAccessType access_type,
6289 Expression* expr,
6290 BailoutId ast_id,
6291 BailoutId return_id,
6292 HValue* object,
6293 HValue* value,
6294 SmallMapList* types,
6295 Handle<String> name) {
6296 // Something did not match; must use a polymorphic load.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006297 int count = 0;
6298 HBasicBlock* join = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006299 HBasicBlock* number_block = NULL;
6300 bool handled_string = false;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006301
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006302 bool handle_smi = false;
6303 STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism);
6304 int i;
6305 for (i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
6306 PropertyAccessInfo info(this, access_type, ToType(types->at(i)), name);
6307 if (info.type()->Is(Type::String())) {
6308 if (handled_string) continue;
6309 handled_string = true;
Ben Murdochb0fe1622011-05-05 13:52:32 +01006310 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006311 if (info.CanAccessMonomorphic()) {
6312 count++;
6313 if (info.type()->Is(Type::Number())) {
6314 handle_smi = true;
6315 break;
6316 }
6317 }
6318 }
6319
6320 if (i < types->length()) {
6321 count = -1;
6322 types->Clear();
6323 } else {
6324 count = 0;
6325 }
6326 HControlInstruction* smi_check = NULL;
6327 handled_string = false;
6328
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006329 for (i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006330 PropertyAccessInfo info(this, access_type, ToType(types->at(i)), name);
6331 if (info.type()->Is(Type::String())) {
6332 if (handled_string) continue;
6333 handled_string = true;
6334 }
6335 if (!info.CanAccessMonomorphic()) continue;
6336
6337 if (count == 0) {
6338 join = graph()->CreateBasicBlock();
6339 if (handle_smi) {
6340 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock();
6341 HBasicBlock* not_smi_block = graph()->CreateBasicBlock();
6342 number_block = graph()->CreateBasicBlock();
6343 smi_check = New<HIsSmiAndBranch>(
6344 object, empty_smi_block, not_smi_block);
6345 FinishCurrentBlock(smi_check);
6346 GotoNoSimulate(empty_smi_block, number_block);
6347 set_current_block(not_smi_block);
6348 } else {
6349 BuildCheckHeapObject(object);
6350 }
6351 }
6352 ++count;
6353 HBasicBlock* if_true = graph()->CreateBasicBlock();
6354 HBasicBlock* if_false = graph()->CreateBasicBlock();
6355 HUnaryControlInstruction* compare;
6356
6357 HValue* dependency;
6358 if (info.type()->Is(Type::Number())) {
6359 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map();
6360 compare = New<HCompareMap>(object, heap_number_map, if_true, if_false);
6361 dependency = smi_check;
6362 } else if (info.type()->Is(Type::String())) {
6363 compare = New<HIsStringAndBranch>(object, if_true, if_false);
6364 dependency = compare;
6365 } else {
6366 compare = New<HCompareMap>(object, info.map(), if_true, if_false);
6367 dependency = compare;
6368 }
6369 FinishCurrentBlock(compare);
6370
6371 if (info.type()->Is(Type::Number())) {
6372 GotoNoSimulate(if_true, number_block);
6373 if_true = number_block;
6374 }
6375
6376 set_current_block(if_true);
6377
6378 HInstruction* access = BuildMonomorphicAccess(
6379 &info, object, dependency, value, ast_id,
6380 return_id, FLAG_polymorphic_inlining);
6381
6382 HValue* result = NULL;
6383 switch (access_type) {
6384 case LOAD:
6385 result = access;
6386 break;
6387 case STORE:
6388 result = value;
6389 break;
6390 }
6391
6392 if (access == NULL) {
6393 if (HasStackOverflow()) return;
6394 } else {
6395 if (!access->IsLinked()) AddInstruction(access);
6396 if (!ast_context()->IsEffect()) Push(result);
6397 }
6398
6399 if (current_block() != NULL) Goto(join);
6400 set_current_block(if_false);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006401 }
6402
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006403 // Finish up. Unconditionally deoptimize if we've handled all the maps we
6404 // know about and do not want to handle ones we've never seen. Otherwise
6405 // use a generic IC.
6406 if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006407 FinishExitWithHardDeoptimization("Unknown map in polymorphic access");
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006408 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006409 HInstruction* instr = BuildNamedGeneric(access_type, expr, object, name,
6410 value);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006411 AddInstruction(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006412 if (!ast_context()->IsEffect()) Push(access_type == LOAD ? instr : value);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006413
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006414 if (join != NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006415 Goto(join);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006416 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006417 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6418 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
6419 return;
Steve Block9fac8402011-05-12 15:51:54 +01006420 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01006421 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006422
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006423 DCHECK(join != NULL);
6424 if (join->HasPredecessor()) {
6425 join->SetJoinId(ast_id);
6426 set_current_block(join);
6427 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
6428 } else {
6429 set_current_block(NULL);
6430 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01006431}
6432
6433
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006434static bool ComputeReceiverTypes(Expression* expr,
6435 HValue* receiver,
6436 SmallMapList** t,
6437 Zone* zone) {
6438 SmallMapList* types = expr->GetReceiverTypes();
6439 *t = types;
6440 bool monomorphic = expr->IsMonomorphic();
6441 if (types != NULL && receiver->HasMonomorphicJSObjectType()) {
6442 Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap();
6443 types->FilterForPossibleTransitions(root_map);
6444 monomorphic = types->length() == 1;
6445 }
6446 return monomorphic &&
6447 CanInlinePropertyAccess(IC::MapToType<Type>(types->first(), zone));
6448}
Ben Murdochb0fe1622011-05-05 13:52:32 +01006449
Ben Murdochb0fe1622011-05-05 13:52:32 +01006450
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006451static bool AreStringTypes(SmallMapList* types) {
6452 for (int i = 0; i < types->length(); i++) {
6453 if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false;
6454 }
6455 return true;
6456}
Ben Murdochb0fe1622011-05-05 13:52:32 +01006457
Ben Murdochb0fe1622011-05-05 13:52:32 +01006458
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006459void HOptimizedGraphBuilder::BuildStore(Expression* expr,
6460 Property* prop,
6461 BailoutId ast_id,
6462 BailoutId return_id,
6463 bool is_uninitialized) {
6464 if (!prop->key()->IsPropertyName()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006465 // Keyed store.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006466 HValue* value = Pop();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006467 HValue* key = Pop();
6468 HValue* object = Pop();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006469 bool has_side_effects = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006470 HValue* result = HandleKeyedElementAccess(
6471 object, key, value, expr, ast_id, return_id, STORE, &has_side_effects);
6472 if (has_side_effects) {
6473 if (!ast_context()->IsEffect()) Push(value);
6474 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6475 if (!ast_context()->IsEffect()) Drop(1);
6476 }
6477 if (result == NULL) return;
6478 return ast_context()->ReturnValue(value);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006479 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006480
6481 // Named store.
6482 HValue* value = Pop();
6483 HValue* object = Pop();
6484
6485 Literal* key = prop->key()->AsLiteral();
6486 Handle<String> name = Handle<String>::cast(key->value());
6487 DCHECK(!name.is_null());
6488
6489 HInstruction* instr = BuildNamedAccess(STORE, ast_id, return_id, expr,
6490 object, name, value, is_uninitialized);
6491 if (instr == NULL) return;
6492
6493 if (!ast_context()->IsEffect()) Push(value);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006494 AddInstruction(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006495 if (instr->HasObservableSideEffects()) {
6496 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6497 }
6498 if (!ast_context()->IsEffect()) Drop(1);
6499 return ast_context()->ReturnValue(value);
6500}
6501
6502
6503void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
6504 Property* prop = expr->target()->AsProperty();
6505 DCHECK(prop != NULL);
6506 CHECK_ALIVE(VisitForValue(prop->obj()));
6507 if (!prop->key()->IsPropertyName()) {
6508 CHECK_ALIVE(VisitForValue(prop->key()));
6509 }
6510 CHECK_ALIVE(VisitForValue(expr->value()));
6511 BuildStore(expr, prop, expr->id(),
6512 expr->AssignmentId(), expr->IsUninitialized());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006513}
6514
6515
6516// Because not every expression has a position and there is not common
6517// superclass of Assignment and CountOperation, we cannot just pass the
6518// owning expression instead of position and ast_id separately.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006519void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
6520 Variable* var,
6521 HValue* value,
6522 BailoutId ast_id) {
6523 Handle<GlobalObject> global(current_info()->global_object());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006524
6525 if (FLAG_harmony_scoping) {
6526 Handle<ScriptContextTable> script_contexts(
6527 global->native_context()->script_context_table());
6528 ScriptContextTable::LookupResult lookup;
6529 if (ScriptContextTable::Lookup(script_contexts, var->name(), &lookup)) {
6530 if (lookup.mode == CONST) {
6531 return Bailout(kNonInitializerAssignmentToConst);
6532 }
6533 Handle<Context> script_context =
6534 ScriptContextTable::GetContext(script_contexts, lookup.context_index);
6535 HStoreNamedField* instr = Add<HStoreNamedField>(
6536 Add<HConstant>(script_context),
6537 HObjectAccess::ForContextSlot(lookup.slot_index), value);
6538 USE(instr);
6539 DCHECK(instr->HasObservableSideEffects());
6540 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6541 return;
6542 }
6543 }
6544
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006545 LookupIterator it(global, var->name(), LookupIterator::OWN_SKIP_INTERCEPTOR);
6546 GlobalPropertyAccess type = LookupGlobalProperty(var, &it, STORE);
Ben Murdoch8b112d22011-06-08 16:22:53 +01006547 if (type == kUseCell) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006548 Handle<PropertyCell> cell = it.GetPropertyCell();
6549 if (cell->type()->IsConstant()) {
6550 Handle<Object> constant = cell->type()->AsConstant()->Value();
6551 if (value->IsConstant()) {
6552 HConstant* c_value = HConstant::cast(value);
6553 if (!constant.is_identical_to(c_value->handle(isolate()))) {
6554 Add<HDeoptimize>("Constant global variable assignment",
6555 Deoptimizer::EAGER);
6556 }
6557 } else {
6558 HValue* c_constant = Add<HConstant>(constant);
6559 IfBuilder builder(this);
6560 if (constant->IsNumber()) {
6561 builder.If<HCompareNumericAndBranch>(value, c_constant, Token::EQ);
6562 } else {
6563 builder.If<HCompareObjectEqAndBranch>(value, c_constant);
6564 }
6565 builder.Then();
6566 builder.Else();
6567 Add<HDeoptimize>("Constant global variable assignment",
6568 Deoptimizer::EAGER);
6569 builder.End();
6570 }
6571 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006572 HInstruction* instr =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006573 Add<HStoreGlobalCell>(value, cell, it.property_details());
6574 if (instr->HasObservableSideEffects()) {
6575 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6576 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01006577 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006578 HValue* global_object = Add<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006579 context(), nullptr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006580 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
6581 HStoreNamedGeneric* instr =
6582 Add<HStoreNamedGeneric>(global_object, var->name(),
6583 value, function_strict_mode());
6584 USE(instr);
6585 DCHECK(instr->HasObservableSideEffects());
6586 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
Ben Murdoch8b112d22011-06-08 16:22:53 +01006587 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01006588}
6589
6590
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006591void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006592 Expression* target = expr->target();
6593 VariableProxy* proxy = target->AsVariableProxy();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006594 Property* prop = target->AsProperty();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006595 DCHECK(proxy == NULL || prop == NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006596
6597 // We have a second position recorded in the FullCodeGenerator to have
6598 // type feedback for the binary operation.
6599 BinaryOperation* operation = expr->binary_operation();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006600
Ben Murdoch589d6972011-11-30 16:04:58 +00006601 if (proxy != NULL) {
6602 Variable* var = proxy->var();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006603 if (var->mode() == LET) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006604 return Bailout(kUnsupportedLetCompoundAssignment);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006605 }
6606
Ben Murdoch257744e2011-11-30 15:57:28 +00006607 CHECK_ALIVE(VisitForValue(operation));
Ben Murdochb0fe1622011-05-05 13:52:32 +01006608
Ben Murdoch589d6972011-11-30 16:04:58 +00006609 switch (var->location()) {
6610 case Variable::UNALLOCATED:
6611 HandleGlobalVariableAssignment(var,
6612 Top(),
Ben Murdoch589d6972011-11-30 16:04:58 +00006613 expr->AssignmentId());
6614 break;
6615
6616 case Variable::PARAMETER:
6617 case Variable::LOCAL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006618 if (var->mode() == CONST_LEGACY) {
6619 return Bailout(kUnsupportedConstCompoundAssignment);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006620 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006621 if (var->mode() == CONST) {
6622 return Bailout(kNonInitializerAssignmentToConst);
6623 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006624 BindIfLive(var, Top());
Ben Murdoch589d6972011-11-30 16:04:58 +00006625 break;
6626
6627 case Variable::CONTEXT: {
6628 // Bail out if we try to mutate a parameter value in a function
6629 // using the arguments object. We do not (yet) correctly handle the
6630 // arguments property of the function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006631 if (current_info()->scope()->arguments() != NULL) {
Ben Murdoch589d6972011-11-30 16:04:58 +00006632 // Parameters will be allocated to context slots. We have no
6633 // direct way to detect that the variable is a parameter so we do
6634 // a linear search of the parameter variables.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006635 int count = current_info()->scope()->num_parameters();
Ben Murdoch589d6972011-11-30 16:04:58 +00006636 for (int i = 0; i < count; ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006637 if (var == current_info()->scope()->parameter(i)) {
6638 Bailout(kAssignmentToParameterFunctionUsesArgumentsObject);
Ben Murdoch589d6972011-11-30 16:04:58 +00006639 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006640 }
6641 }
Ben Murdoch589d6972011-11-30 16:04:58 +00006642
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006643 HStoreContextSlot::Mode mode;
6644
6645 switch (var->mode()) {
6646 case LET:
6647 mode = HStoreContextSlot::kCheckDeoptimize;
6648 break;
6649 case CONST:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006650 return Bailout(kNonInitializerAssignmentToConst);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006651 case CONST_LEGACY:
6652 return ast_context()->ReturnValue(Pop());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006653 default:
6654 mode = HStoreContextSlot::kNoCheck;
6655 }
6656
Ben Murdoch589d6972011-11-30 16:04:58 +00006657 HValue* context = BuildContextChainWalk(var);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006658 HStoreContextSlot* instr = Add<HStoreContextSlot>(
6659 context, var->index(), mode, Top());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006660 if (instr->HasObservableSideEffects()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006661 Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006662 }
Ben Murdoch589d6972011-11-30 16:04:58 +00006663 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006664 }
6665
Ben Murdoch589d6972011-11-30 16:04:58 +00006666 case Variable::LOOKUP:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006667 return Bailout(kCompoundAssignmentToLookupSlot);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006668 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006669 return ast_context()->ReturnValue(Pop());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006670
6671 } else if (prop != NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006672 CHECK_ALIVE(VisitForValue(prop->obj()));
6673 HValue* object = Top();
6674 HValue* key = NULL;
6675 if (!prop->key()->IsPropertyName() || prop->IsStringAccess()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00006676 CHECK_ALIVE(VisitForValue(prop->key()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006677 key = Top();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006678 }
6679
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006680 CHECK_ALIVE(PushLoad(prop, object, key));
6681
6682 CHECK_ALIVE(VisitForValue(expr->value()));
6683 HValue* right = Pop();
6684 HValue* left = Pop();
6685
6686 Push(BuildBinaryOperation(operation, left, right, PUSH_BEFORE_SIMULATE));
6687
6688 BuildStore(expr, prop, expr->id(),
6689 expr->AssignmentId(), expr->IsUninitialized());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006690 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006691 return Bailout(kInvalidLhsInCompoundAssignment);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006692 }
6693}
6694
6695
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006696void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) {
6697 DCHECK(!HasStackOverflow());
6698 DCHECK(current_block() != NULL);
6699 DCHECK(current_block()->HasPredecessor());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006700 VariableProxy* proxy = expr->target()->AsVariableProxy();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006701 Property* prop = expr->target()->AsProperty();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006702 DCHECK(proxy == NULL || prop == NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006703
6704 if (expr->is_compound()) {
6705 HandleCompoundAssignment(expr);
6706 return;
6707 }
6708
Ben Murdoch589d6972011-11-30 16:04:58 +00006709 if (prop != NULL) {
6710 HandlePropertyAssignment(expr);
6711 } else if (proxy != NULL) {
6712 Variable* var = proxy->var();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006713
6714 if (var->mode() == CONST) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006715 if (expr->op() != Token::INIT_CONST) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006716 return Bailout(kNonInitializerAssignmentToConst);
6717 }
6718 } else if (var->mode() == CONST_LEGACY) {
6719 if (expr->op() != Token::INIT_CONST_LEGACY) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006720 CHECK_ALIVE(VisitForValue(expr->value()));
6721 return ast_context()->ReturnValue(Pop());
6722 }
6723
6724 if (var->IsStackAllocated()) {
6725 // We insert a use of the old value to detect unsupported uses of const
6726 // variables (e.g. initialization inside a loop).
6727 HValue* old_value = environment()->Lookup(var);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006728 Add<HUseConst>(old_value);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006729 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006730 }
6731
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006732 if (proxy->IsArguments()) return Bailout(kAssignmentToArguments);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006733
6734 // Handle the assignment.
Ben Murdoch589d6972011-11-30 16:04:58 +00006735 switch (var->location()) {
6736 case Variable::UNALLOCATED:
6737 CHECK_ALIVE(VisitForValue(expr->value()));
6738 HandleGlobalVariableAssignment(var,
6739 Top(),
Ben Murdoch589d6972011-11-30 16:04:58 +00006740 expr->AssignmentId());
6741 return ast_context()->ReturnValue(Pop());
Steve Block1e0659c2011-05-24 12:43:12 +01006742
Ben Murdoch589d6972011-11-30 16:04:58 +00006743 case Variable::PARAMETER:
6744 case Variable::LOCAL: {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006745 // Perform an initialization check for let declared variables
6746 // or parameters.
6747 if (var->mode() == LET && expr->op() == Token::ASSIGN) {
6748 HValue* env_value = environment()->Lookup(var);
6749 if (env_value == graph()->GetConstantHole()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006750 return Bailout(kAssignmentToLetVariableBeforeInitialization);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006751 }
6752 }
Ben Murdoch589d6972011-11-30 16:04:58 +00006753 // We do not allow the arguments object to occur in a context where it
6754 // may escape, but assignments to stack-allocated locals are
6755 // permitted.
6756 CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED));
6757 HValue* value = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006758 BindIfLive(var, value);
Ben Murdoch589d6972011-11-30 16:04:58 +00006759 return ast_context()->ReturnValue(value);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006760 }
6761
Ben Murdoch589d6972011-11-30 16:04:58 +00006762 case Variable::CONTEXT: {
Ben Murdoch589d6972011-11-30 16:04:58 +00006763 // Bail out if we try to mutate a parameter value in a function using
6764 // the arguments object. We do not (yet) correctly handle the
6765 // arguments property of the function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006766 if (current_info()->scope()->arguments() != NULL) {
Ben Murdoch589d6972011-11-30 16:04:58 +00006767 // Parameters will rewrite to context slots. We have no direct way
6768 // to detect that the variable is a parameter.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006769 int count = current_info()->scope()->num_parameters();
Ben Murdoch589d6972011-11-30 16:04:58 +00006770 for (int i = 0; i < count; ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006771 if (var == current_info()->scope()->parameter(i)) {
6772 return Bailout(kAssignmentToParameterInArgumentsObject);
Ben Murdoch589d6972011-11-30 16:04:58 +00006773 }
6774 }
6775 }
Steve Block1e0659c2011-05-24 12:43:12 +01006776
Ben Murdoch589d6972011-11-30 16:04:58 +00006777 CHECK_ALIVE(VisitForValue(expr->value()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006778 HStoreContextSlot::Mode mode;
6779 if (expr->op() == Token::ASSIGN) {
6780 switch (var->mode()) {
6781 case LET:
6782 mode = HStoreContextSlot::kCheckDeoptimize;
6783 break;
6784 case CONST:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006785 // This case is checked statically so no need to
6786 // perform checks here
6787 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006788 case CONST_LEGACY:
6789 return ast_context()->ReturnValue(Pop());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006790 default:
6791 mode = HStoreContextSlot::kNoCheck;
6792 }
6793 } else if (expr->op() == Token::INIT_VAR ||
6794 expr->op() == Token::INIT_LET ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006795 expr->op() == Token::INIT_CONST) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006796 mode = HStoreContextSlot::kNoCheck;
6797 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006798 DCHECK(expr->op() == Token::INIT_CONST_LEGACY);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006799
6800 mode = HStoreContextSlot::kCheckIgnoreAssignment;
6801 }
6802
Ben Murdoch589d6972011-11-30 16:04:58 +00006803 HValue* context = BuildContextChainWalk(var);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006804 HStoreContextSlot* instr = Add<HStoreContextSlot>(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006805 context, var->index(), mode, Top());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006806 if (instr->HasObservableSideEffects()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006807 Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006808 }
Ben Murdoch589d6972011-11-30 16:04:58 +00006809 return ast_context()->ReturnValue(Pop());
6810 }
Steve Block1e0659c2011-05-24 12:43:12 +01006811
Ben Murdoch589d6972011-11-30 16:04:58 +00006812 case Variable::LOOKUP:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006813 return Bailout(kAssignmentToLOOKUPVariable);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006814 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01006815 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006816 return Bailout(kInvalidLeftHandSideInAssignment);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006817 }
6818}
6819
6820
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006821void HOptimizedGraphBuilder::VisitYield(Yield* expr) {
6822 // Generators are not optimized, so we should never get here.
6823 UNREACHABLE();
6824}
6825
6826
6827void HOptimizedGraphBuilder::VisitThrow(Throw* expr) {
6828 DCHECK(!HasStackOverflow());
6829 DCHECK(current_block() != NULL);
6830 DCHECK(current_block()->HasPredecessor());
6831 if (!ast_context()->IsEffect()) {
6832 // The parser turns invalid left-hand sides in assignments into throw
6833 // statements, which may not be in effect contexts. We might still try
6834 // to optimize such functions; bail out now if we do.
6835 return Bailout(kInvalidLeftHandSideInAssignment);
6836 }
Ben Murdoch257744e2011-11-30 15:57:28 +00006837 CHECK_ALIVE(VisitForValue(expr->exception()));
Ben Murdochb0fe1622011-05-05 13:52:32 +01006838
6839 HValue* value = environment()->Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006840 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
6841 Add<HPushArguments>(value);
6842 Add<HCallRuntime>(isolate()->factory()->empty_string(),
6843 Runtime::FunctionForId(Runtime::kThrow), 1);
6844 Add<HSimulate>(expr->id());
6845
6846 // If the throw definitely exits the function, we can finish with a dummy
6847 // control flow at this point. This is not the case if the throw is inside
6848 // an inlined function which may be replaced.
6849 if (call_context() == NULL) {
6850 FinishExitCurrentBlock(New<HAbnormalExit>());
6851 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01006852}
6853
6854
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006855HInstruction* HGraphBuilder::AddLoadStringInstanceType(HValue* string) {
6856 if (string->IsConstant()) {
6857 HConstant* c_string = HConstant::cast(string);
6858 if (c_string->HasStringValue()) {
6859 return Add<HConstant>(c_string->StringValue()->map()->instance_type());
6860 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01006861 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006862 return Add<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006863 Add<HLoadNamedField>(string, nullptr, HObjectAccess::ForMap()), nullptr,
6864 HObjectAccess::ForMapInstanceType());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006865}
Ben Murdochb0fe1622011-05-05 13:52:32 +01006866
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006867
6868HInstruction* HGraphBuilder::AddLoadStringLength(HValue* string) {
6869 if (string->IsConstant()) {
6870 HConstant* c_string = HConstant::cast(string);
6871 if (c_string->HasStringValue()) {
6872 return Add<HConstant>(c_string->StringValue()->length());
6873 }
6874 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006875 return Add<HLoadNamedField>(string, nullptr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006876 HObjectAccess::ForStringLength());
6877}
6878
6879
6880HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric(
6881 PropertyAccessType access_type,
6882 Expression* expr,
6883 HValue* object,
6884 Handle<String> name,
6885 HValue* value,
6886 bool is_uninitialized) {
6887 if (is_uninitialized) {
6888 Add<HDeoptimize>("Insufficient type feedback for generic named access",
6889 Deoptimizer::SOFT);
6890 }
6891 if (access_type == LOAD) {
6892 HLoadNamedGeneric* result = New<HLoadNamedGeneric>(object, name);
6893 if (FLAG_vector_ics) {
6894 Handle<SharedFunctionInfo> current_shared =
6895 function_state()->compilation_info()->shared_info();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006896 Handle<TypeFeedbackVector> vector =
6897 handle(current_shared->feedback_vector(), isolate());
6898 FeedbackVectorICSlot slot = expr->AsProperty()->PropertyFeedbackSlot();
6899 result->SetVectorAndSlot(vector, slot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006900 }
6901 return result;
Ben Murdochb0fe1622011-05-05 13:52:32 +01006902 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006903 return New<HStoreNamedGeneric>(object, name, value, function_strict_mode());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006904 }
6905}
6906
6907
Ben Murdochb0fe1622011-05-05 13:52:32 +01006908
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006909HInstruction* HOptimizedGraphBuilder::BuildKeyedGeneric(
6910 PropertyAccessType access_type,
6911 Expression* expr,
6912 HValue* object,
6913 HValue* key,
6914 HValue* value) {
6915 if (access_type == LOAD) {
6916 HLoadKeyedGeneric* result = New<HLoadKeyedGeneric>(object, key);
6917 if (FLAG_vector_ics) {
6918 Handle<SharedFunctionInfo> current_shared =
6919 function_state()->compilation_info()->shared_info();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006920 Handle<TypeFeedbackVector> vector =
6921 handle(current_shared->feedback_vector(), isolate());
6922 FeedbackVectorICSlot slot = expr->AsProperty()->PropertyFeedbackSlot();
6923 result->SetVectorAndSlot(vector, slot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006924 }
6925 return result;
Ben Murdochb0fe1622011-05-05 13:52:32 +01006926 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006927 return New<HStoreKeyedGeneric>(object, key, value, function_strict_mode());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006928 }
6929}
6930
6931
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006932LoadKeyedHoleMode HOptimizedGraphBuilder::BuildKeyedHoleMode(Handle<Map> map) {
6933 // Loads from a "stock" fast holey double arrays can elide the hole check.
6934 LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE;
6935 if (*map == isolate()->get_initial_js_array_map(FAST_HOLEY_DOUBLE_ELEMENTS) &&
6936 isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
6937 Handle<JSObject> prototype(JSObject::cast(map->prototype()), isolate());
6938 Handle<JSObject> object_prototype = isolate()->initial_object_prototype();
6939 BuildCheckPrototypeMaps(prototype, object_prototype);
6940 load_mode = ALLOW_RETURN_HOLE;
6941 graph()->MarkDependsOnEmptyArrayProtoElements();
6942 }
6943
6944 return load_mode;
Ben Murdochb0fe1622011-05-05 13:52:32 +01006945}
6946
6947
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006948HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess(
6949 HValue* object,
6950 HValue* key,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006951 HValue* val,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006952 HValue* dependency,
6953 Handle<Map> map,
6954 PropertyAccessType access_type,
6955 KeyedAccessStoreMode store_mode) {
6956 HCheckMaps* checked_object = Add<HCheckMaps>(object, map, dependency);
6957 if (dependency) {
6958 checked_object->ClearDependsOnFlag(kElementsKind);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006959 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006960
6961 if (access_type == STORE && map->prototype()->IsJSObject()) {
6962 // monomorphic stores need a prototype chain check because shape
6963 // changes could allow callbacks on elements in the chain that
6964 // aren't compatible with monomorphic keyed stores.
6965 PrototypeIterator iter(map);
6966 JSObject* holder = NULL;
6967 while (!iter.IsAtEnd()) {
6968 holder = JSObject::cast(*PrototypeIterator::GetCurrent(iter));
6969 iter.Advance();
6970 }
6971 DCHECK(holder && holder->IsJSObject());
6972
6973 BuildCheckPrototypeMaps(handle(JSObject::cast(map->prototype())),
6974 Handle<JSObject>(holder));
6975 }
6976
6977 LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map);
6978 return BuildUncheckedMonomorphicElementAccess(
6979 checked_object, key, val,
6980 map->instance_type() == JS_ARRAY_TYPE,
6981 map->elements_kind(), access_type,
6982 load_mode, store_mode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006983}
6984
6985
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006986static bool CanInlineElementAccess(Handle<Map> map) {
6987 return map->IsJSObjectMap() && !map->has_slow_elements_kind() &&
6988 !map->has_indexed_interceptor();
6989}
6990
6991
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006992HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad(
6993 HValue* object,
6994 HValue* key,
6995 HValue* val,
6996 SmallMapList* maps) {
6997 // For polymorphic loads of similar elements kinds (i.e. all tagged or all
6998 // double), always use the "worst case" code without a transition. This is
6999 // much faster than transitioning the elements to the worst case, trading a
7000 // HTransitionElements for a HCheckMaps, and avoiding mutation of the array.
7001 bool has_double_maps = false;
7002 bool has_smi_or_object_maps = false;
7003 bool has_js_array_access = false;
7004 bool has_non_js_array_access = false;
7005 bool has_seen_holey_elements = false;
7006 Handle<Map> most_general_consolidated_map;
7007 for (int i = 0; i < maps->length(); ++i) {
7008 Handle<Map> map = maps->at(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007009 if (!CanInlineElementAccess(map)) return NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007010 // Don't allow mixing of JSArrays with JSObjects.
7011 if (map->instance_type() == JS_ARRAY_TYPE) {
7012 if (has_non_js_array_access) return NULL;
7013 has_js_array_access = true;
7014 } else if (has_js_array_access) {
7015 return NULL;
7016 } else {
7017 has_non_js_array_access = true;
7018 }
7019 // Don't allow mixed, incompatible elements kinds.
7020 if (map->has_fast_double_elements()) {
7021 if (has_smi_or_object_maps) return NULL;
7022 has_double_maps = true;
7023 } else if (map->has_fast_smi_or_object_elements()) {
7024 if (has_double_maps) return NULL;
7025 has_smi_or_object_maps = true;
7026 } else {
7027 return NULL;
7028 }
7029 // Remember if we've ever seen holey elements.
7030 if (IsHoleyElementsKind(map->elements_kind())) {
7031 has_seen_holey_elements = true;
7032 }
7033 // Remember the most general elements kind, the code for its load will
7034 // properly handle all of the more specific cases.
7035 if ((i == 0) || IsMoreGeneralElementsKindTransition(
7036 most_general_consolidated_map->elements_kind(),
7037 map->elements_kind())) {
7038 most_general_consolidated_map = map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007039 }
7040 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007041 if (!has_double_maps && !has_smi_or_object_maps) return NULL;
7042
7043 HCheckMaps* checked_object = Add<HCheckMaps>(object, maps);
7044 // FAST_ELEMENTS is considered more general than FAST_HOLEY_SMI_ELEMENTS.
7045 // If we've seen both, the consolidated load must use FAST_HOLEY_ELEMENTS.
7046 ElementsKind consolidated_elements_kind = has_seen_holey_elements
7047 ? GetHoleyElementsKind(most_general_consolidated_map->elements_kind())
7048 : most_general_consolidated_map->elements_kind();
7049 HInstruction* instr = BuildUncheckedMonomorphicElementAccess(
7050 checked_object, key, val,
7051 most_general_consolidated_map->instance_type() == JS_ARRAY_TYPE,
7052 consolidated_elements_kind,
7053 LOAD, NEVER_RETURN_HOLE, STANDARD_STORE);
7054 return instr;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007055}
7056
7057
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007058HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
7059 Expression* expr,
7060 HValue* object,
7061 HValue* key,
7062 HValue* val,
7063 SmallMapList* maps,
7064 PropertyAccessType access_type,
7065 KeyedAccessStoreMode store_mode,
7066 bool* has_side_effects) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007067 *has_side_effects = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007068 BuildCheckHeapObject(object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007069
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007070 if (access_type == LOAD) {
7071 HInstruction* consolidated_load =
7072 TryBuildConsolidatedElementLoad(object, key, val, maps);
7073 if (consolidated_load != NULL) {
7074 *has_side_effects |= consolidated_load->HasObservableSideEffects();
7075 return consolidated_load;
7076 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007077 }
7078
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007079 // Elements_kind transition support.
7080 MapHandleList transition_target(maps->length());
7081 // Collect possible transition targets.
7082 MapHandleList possible_transitioned_maps(maps->length());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007083 for (int i = 0; i < maps->length(); ++i) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007084 Handle<Map> map = maps->at(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007085 // Loads from strings or loads with a mix of string and non-string maps
7086 // shouldn't be handled polymorphically.
7087 DCHECK(access_type != LOAD || !map->IsStringMap());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007088 ElementsKind elements_kind = map->elements_kind();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007089 if (CanInlineElementAccess(map) && IsFastElementsKind(elements_kind) &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007090 elements_kind != GetInitialFastElementsKind()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007091 possible_transitioned_maps.Add(map);
7092 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007093 if (elements_kind == SLOPPY_ARGUMENTS_ELEMENTS) {
7094 HInstruction* result = BuildKeyedGeneric(access_type, expr, object, key,
7095 val);
7096 *has_side_effects = result->HasObservableSideEffects();
7097 return AddInstruction(result);
7098 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007099 }
7100 // Get transition target for each map (NULL == no transition).
7101 for (int i = 0; i < maps->length(); ++i) {
7102 Handle<Map> map = maps->at(i);
7103 Handle<Map> transitioned_map =
7104 map->FindTransitionedMap(&possible_transitioned_maps);
7105 transition_target.Add(transitioned_map);
7106 }
7107
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007108 MapHandleList untransitionable_maps(maps->length());
7109 HTransitionElementsKind* transition = NULL;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007110 for (int i = 0; i < maps->length(); ++i) {
7111 Handle<Map> map = maps->at(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007112 DCHECK(map->IsMap());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007113 if (!transition_target.at(i).is_null()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007114 DCHECK(Map::IsValidElementsTransition(
7115 map->elements_kind(),
7116 transition_target.at(i)->elements_kind()));
7117 transition = Add<HTransitionElementsKind>(object, map,
7118 transition_target.at(i));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007119 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007120 untransitionable_maps.Add(map);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007121 }
7122 }
7123
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007124 // If only one map is left after transitioning, handle this case
7125 // monomorphically.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007126 DCHECK(untransitionable_maps.length() >= 1);
7127 if (untransitionable_maps.length() == 1) {
7128 Handle<Map> untransitionable_map = untransitionable_maps[0];
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007129 HInstruction* instr = NULL;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007130 if (!CanInlineElementAccess(untransitionable_map)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007131 instr = AddInstruction(BuildKeyedGeneric(access_type, expr, object, key,
7132 val));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007133 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007134 instr = BuildMonomorphicElementAccess(
7135 object, key, val, transition, untransitionable_map, access_type,
7136 store_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007137 }
7138 *has_side_effects |= instr->HasObservableSideEffects();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007139 return access_type == STORE ? val : instr;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007140 }
7141
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007142 HBasicBlock* join = graph()->CreateBasicBlock();
7143
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007144 for (int i = 0; i < untransitionable_maps.length(); ++i) {
7145 Handle<Map> map = untransitionable_maps[i];
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007146 ElementsKind elements_kind = map->elements_kind();
7147 HBasicBlock* this_map = graph()->CreateBasicBlock();
7148 HBasicBlock* other_map = graph()->CreateBasicBlock();
7149 HCompareMap* mapcompare =
7150 New<HCompareMap>(object, map, this_map, other_map);
7151 FinishCurrentBlock(mapcompare);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007152
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007153 set_current_block(this_map);
7154 HInstruction* access = NULL;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007155 if (!CanInlineElementAccess(map)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007156 access = AddInstruction(BuildKeyedGeneric(access_type, expr, object, key,
7157 val));
7158 } else {
7159 DCHECK(IsFastElementsKind(elements_kind) ||
7160 IsExternalArrayElementsKind(elements_kind) ||
7161 IsFixedTypedArrayElementsKind(elements_kind));
7162 LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map);
7163 // Happily, mapcompare is a checked object.
7164 access = BuildUncheckedMonomorphicElementAccess(
7165 mapcompare, key, val,
7166 map->instance_type() == JS_ARRAY_TYPE,
7167 elements_kind, access_type,
7168 load_mode,
7169 store_mode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007170 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007171 *has_side_effects |= access->HasObservableSideEffects();
7172 // The caller will use has_side_effects and add a correct Simulate.
7173 access->SetFlag(HValue::kHasNoObservableSideEffects);
7174 if (access_type == LOAD) {
7175 Push(access);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007176 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007177 NoObservableSideEffectsScope scope(this);
7178 GotoNoSimulate(join);
7179 set_current_block(other_map);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007180 }
7181
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007182 // Ensure that we visited at least one map above that goes to join. This is
7183 // necessary because FinishExitWithHardDeoptimization does an AbnormalExit
7184 // rather than joining the join block. If this becomes an issue, insert a
7185 // generic access in the case length() == 0.
7186 DCHECK(join->predecessors()->length() > 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007187 // Deopt if none of the cases matched.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007188 NoObservableSideEffectsScope scope(this);
7189 FinishExitWithHardDeoptimization("Unknown map in polymorphic element access");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007190 set_current_block(join);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007191 return access_type == STORE ? val : Pop();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007192}
7193
7194
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007195HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
7196 HValue* obj, HValue* key, HValue* val, Expression* expr, BailoutId ast_id,
7197 BailoutId return_id, PropertyAccessType access_type,
7198 bool* has_side_effects) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007199 // TODO(mvstanton): This optimization causes trouble for vector-based
7200 // KeyedLoadICs, turn it off for now.
7201 if (!FLAG_vector_ics && key->ActualValue()->IsConstant()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007202 Handle<Object> constant =
7203 HConstant::cast(key->ActualValue())->handle(isolate());
7204 uint32_t array_index;
7205 if (constant->IsString() &&
7206 !Handle<String>::cast(constant)->AsArrayIndex(&array_index)) {
7207 if (!constant->IsUniqueName()) {
7208 constant = isolate()->factory()->InternalizeString(
7209 Handle<String>::cast(constant));
7210 }
7211 HInstruction* instr =
7212 BuildNamedAccess(access_type, ast_id, return_id, expr, obj,
7213 Handle<String>::cast(constant), val, false);
7214 if (instr == NULL || instr->IsLinked()) {
7215 *has_side_effects = false;
7216 } else {
7217 AddInstruction(instr);
7218 *has_side_effects = instr->HasObservableSideEffects();
7219 }
7220 return instr;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007221 }
7222 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007223
7224 DCHECK(!expr->IsPropertyName());
7225 HInstruction* instr = NULL;
7226
7227 SmallMapList* types;
7228 bool monomorphic = ComputeReceiverTypes(expr, obj, &types, zone());
7229
7230 bool force_generic = false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007231 if (expr->GetKeyType() == PROPERTY) {
7232 // Non-Generic accesses assume that elements are being accessed, and will
7233 // deopt for non-index keys, which the IC knows will occur.
7234 // TODO(jkummerow): Consider adding proper support for property accesses.
7235 force_generic = true;
7236 monomorphic = false;
7237 } else if (access_type == STORE &&
7238 (monomorphic || (types != NULL && !types->is_empty()))) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007239 // Stores can't be mono/polymorphic if their prototype chain has dictionary
7240 // elements. However a receiver map that has dictionary elements itself
7241 // should be left to normal mono/poly behavior (the other maps may benefit
7242 // from highly optimized stores).
7243 for (int i = 0; i < types->length(); i++) {
7244 Handle<Map> current_map = types->at(i);
7245 if (current_map->DictionaryElementsInPrototypeChainOnly()) {
7246 force_generic = true;
7247 monomorphic = false;
7248 break;
7249 }
7250 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007251 } else if (access_type == LOAD && !monomorphic &&
7252 (types != NULL && !types->is_empty())) {
7253 // Polymorphic loads have to go generic if any of the maps are strings.
7254 // If some, but not all of the maps are strings, we should go generic
7255 // because polymorphic access wants to key on ElementsKind and isn't
7256 // compatible with strings.
7257 for (int i = 0; i < types->length(); i++) {
7258 Handle<Map> current_map = types->at(i);
7259 if (current_map->IsStringMap()) {
7260 force_generic = true;
7261 break;
7262 }
7263 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007264 }
7265
7266 if (monomorphic) {
7267 Handle<Map> map = types->first();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007268 if (!CanInlineElementAccess(map)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007269 instr = AddInstruction(BuildKeyedGeneric(access_type, expr, obj, key,
7270 val));
7271 } else {
7272 BuildCheckHeapObject(obj);
7273 instr = BuildMonomorphicElementAccess(
7274 obj, key, val, NULL, map, access_type, expr->GetStoreMode());
7275 }
7276 } else if (!force_generic && (types != NULL && !types->is_empty())) {
7277 return HandlePolymorphicElementAccess(
7278 expr, obj, key, val, types, access_type,
7279 expr->GetStoreMode(), has_side_effects);
7280 } else {
7281 if (access_type == STORE) {
7282 if (expr->IsAssignment() &&
7283 expr->AsAssignment()->HasNoTypeInformation()) {
7284 Add<HDeoptimize>("Insufficient type feedback for keyed store",
7285 Deoptimizer::SOFT);
7286 }
7287 } else {
7288 if (expr->AsProperty()->HasNoTypeInformation()) {
7289 Add<HDeoptimize>("Insufficient type feedback for keyed load",
7290 Deoptimizer::SOFT);
7291 }
7292 }
7293 instr = AddInstruction(BuildKeyedGeneric(access_type, expr, obj, key, val));
7294 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007295 *has_side_effects = instr->HasObservableSideEffects();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007296 return instr;
Ben Murdoch8b112d22011-06-08 16:22:53 +01007297}
7298
7299
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007300void HOptimizedGraphBuilder::EnsureArgumentsArePushedForAccess() {
7301 // Outermost function already has arguments on the stack.
7302 if (function_state()->outer() == NULL) return;
7303
7304 if (function_state()->arguments_pushed()) return;
7305
7306 // Push arguments when entering inlined function.
7307 HEnterInlined* entry = function_state()->entry();
7308 entry->set_arguments_pushed();
7309
7310 HArgumentsObject* arguments = entry->arguments_object();
7311 const ZoneList<HValue*>* arguments_values = arguments->arguments_values();
7312
7313 HInstruction* insert_after = entry;
7314 for (int i = 0; i < arguments_values->length(); i++) {
7315 HValue* argument = arguments_values->at(i);
7316 HInstruction* push_argument = New<HPushArguments>(argument);
7317 push_argument->InsertAfter(insert_after);
7318 insert_after = push_argument;
7319 }
7320
7321 HArgumentsElements* arguments_elements = New<HArgumentsElements>(true);
7322 arguments_elements->ClearFlag(HValue::kUseGVN);
7323 arguments_elements->InsertAfter(insert_after);
7324 function_state()->set_arguments_elements(arguments_elements);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007325}
7326
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007327
7328bool HOptimizedGraphBuilder::TryArgumentsAccess(Property* expr) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007329 VariableProxy* proxy = expr->obj()->AsVariableProxy();
7330 if (proxy == NULL) return false;
7331 if (!proxy->var()->IsStackAllocated()) return false;
7332 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) {
7333 return false;
7334 }
7335
7336 HInstruction* result = NULL;
7337 if (expr->key()->IsPropertyName()) {
7338 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007339 if (!String::Equals(name, isolate()->factory()->length_string())) {
7340 return false;
7341 }
7342
7343 if (function_state()->outer() == NULL) {
7344 HInstruction* elements = Add<HArgumentsElements>(false);
7345 result = New<HArgumentsLength>(elements);
7346 } else {
7347 // Number of arguments without receiver.
7348 int argument_count = environment()->
7349 arguments_environment()->parameter_count() - 1;
7350 result = New<HConstant>(argument_count);
7351 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007352 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007353 Push(graph()->GetArgumentsObject());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007354 CHECK_ALIVE_OR_RETURN(VisitForValue(expr->key()), true);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007355 HValue* key = Pop();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007356 Drop(1); // Arguments object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007357 if (function_state()->outer() == NULL) {
7358 HInstruction* elements = Add<HArgumentsElements>(false);
7359 HInstruction* length = Add<HArgumentsLength>(elements);
7360 HInstruction* checked_key = Add<HBoundsCheck>(key, length);
7361 result = New<HAccessArgumentsAt>(elements, length, checked_key);
7362 } else {
7363 EnsureArgumentsArePushedForAccess();
7364
7365 // Number of arguments without receiver.
7366 HInstruction* elements = function_state()->arguments_elements();
7367 int argument_count = environment()->
7368 arguments_environment()->parameter_count() - 1;
7369 HInstruction* length = Add<HConstant>(argument_count);
7370 HInstruction* checked_key = Add<HBoundsCheck>(key, length);
7371 result = New<HAccessArgumentsAt>(elements, length, checked_key);
7372 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007373 }
7374 ast_context()->ReturnInstruction(result, expr->id());
7375 return true;
7376}
7377
7378
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007379HInstruction* HOptimizedGraphBuilder::BuildNamedAccess(
7380 PropertyAccessType access,
7381 BailoutId ast_id,
7382 BailoutId return_id,
7383 Expression* expr,
7384 HValue* object,
7385 Handle<String> name,
7386 HValue* value,
7387 bool is_uninitialized) {
7388 SmallMapList* types;
7389 ComputeReceiverTypes(expr, object, &types, zone());
7390 DCHECK(types != NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007391
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007392 if (types->length() > 0) {
7393 PropertyAccessInfo info(this, access, ToType(types->first()), name);
7394 if (!info.CanAccessAsMonomorphic(types)) {
7395 HandlePolymorphicNamedFieldAccess(
7396 access, expr, ast_id, return_id, object, value, types, name);
7397 return NULL;
7398 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007399
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007400 HValue* checked_object;
7401 // Type::Number() is only supported by polymorphic load/call handling.
7402 DCHECK(!info.type()->Is(Type::Number()));
7403 BuildCheckHeapObject(object);
7404 if (AreStringTypes(types)) {
7405 checked_object =
7406 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING);
7407 } else {
7408 checked_object = Add<HCheckMaps>(object, types);
7409 }
7410 return BuildMonomorphicAccess(
7411 &info, object, checked_object, value, ast_id, return_id);
7412 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007413
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007414 return BuildNamedGeneric(access, expr, object, name, value, is_uninitialized);
7415}
7416
7417
7418void HOptimizedGraphBuilder::PushLoad(Property* expr,
7419 HValue* object,
7420 HValue* key) {
7421 ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED);
7422 Push(object);
7423 if (key != NULL) Push(key);
7424 BuildLoad(expr, expr->LoadId());
7425}
7426
7427
7428void HOptimizedGraphBuilder::BuildLoad(Property* expr,
7429 BailoutId ast_id) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007430 HInstruction* instr = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007431 if (expr->IsStringAccess()) {
Steve Block44f0eee2011-05-26 01:26:41 +01007432 HValue* index = Pop();
7433 HValue* string = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007434 HInstruction* char_code = BuildStringCharCodeAt(string, index);
Steve Block44f0eee2011-05-26 01:26:41 +01007435 AddInstruction(char_code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007436 instr = NewUncasted<HStringCharFromCode>(char_code);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007437
7438 } else if (expr->key()->IsPropertyName()) {
7439 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007440 HValue* object = Pop();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007441
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007442 instr = BuildNamedAccess(LOAD, ast_id, expr->LoadId(), expr,
7443 object, name, NULL, expr->IsUninitialized());
7444 if (instr == NULL) return;
7445 if (instr->IsLinked()) return ast_context()->ReturnValue(instr);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007446
7447 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007448 HValue* key = Pop();
7449 HValue* obj = Pop();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007450
7451 bool has_side_effects = false;
7452 HValue* load = HandleKeyedElementAccess(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007453 obj, key, NULL, expr, ast_id, expr->LoadId(), LOAD, &has_side_effects);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007454 if (has_side_effects) {
7455 if (ast_context()->IsEffect()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007456 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007457 } else {
7458 Push(load);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007459 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007460 Drop(1);
7461 }
7462 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007463 if (load == NULL) return;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007464 return ast_context()->ReturnValue(load);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007465 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007466 return ast_context()->ReturnInstruction(instr, ast_id);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007467}
7468
7469
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007470void HOptimizedGraphBuilder::VisitProperty(Property* expr) {
7471 DCHECK(!HasStackOverflow());
7472 DCHECK(current_block() != NULL);
7473 DCHECK(current_block()->HasPredecessor());
7474
7475 if (TryArgumentsAccess(expr)) return;
7476
7477 CHECK_ALIVE(VisitForValue(expr->obj()));
7478 if (!expr->key()->IsPropertyName() || expr->IsStringAccess()) {
7479 CHECK_ALIVE(VisitForValue(expr->key()));
Ben Murdochb0fe1622011-05-05 13:52:32 +01007480 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007481
7482 BuildLoad(expr, expr->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007483}
7484
7485
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007486HInstruction* HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant) {
7487 HCheckMaps* check = Add<HCheckMaps>(
7488 Add<HConstant>(constant), handle(constant->map()));
7489 check->ClearDependsOnFlag(kElementsKind);
7490 return check;
7491}
Steve Block44f0eee2011-05-26 01:26:41 +01007492
Steve Block44f0eee2011-05-26 01:26:41 +01007493
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007494HInstruction* HGraphBuilder::BuildCheckPrototypeMaps(Handle<JSObject> prototype,
7495 Handle<JSObject> holder) {
7496 PrototypeIterator iter(isolate(), prototype,
7497 PrototypeIterator::START_AT_RECEIVER);
7498 while (holder.is_null() ||
7499 !PrototypeIterator::GetCurrent(iter).is_identical_to(holder)) {
7500 BuildConstantMapCheck(
7501 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)));
7502 iter.Advance();
7503 if (iter.IsAtEnd()) {
7504 return NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +01007505 }
7506 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007507 return BuildConstantMapCheck(
7508 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)));
7509}
7510
7511
7512void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder,
7513 Handle<Map> receiver_map) {
7514 if (!holder.is_null()) {
7515 Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype()));
7516 BuildCheckPrototypeMaps(prototype, holder);
7517 }
7518}
7519
7520
7521HInstruction* HOptimizedGraphBuilder::NewPlainFunctionCall(
7522 HValue* fun, int argument_count, bool pass_argument_count) {
7523 return New<HCallJSFunction>(
7524 fun, argument_count, pass_argument_count);
7525}
7526
7527
7528HInstruction* HOptimizedGraphBuilder::NewArgumentAdaptorCall(
7529 HValue* fun, HValue* context,
7530 int argument_count, HValue* expected_param_count) {
7531 ArgumentAdaptorDescriptor descriptor(isolate());
7532 HValue* arity = Add<HConstant>(argument_count - 1);
7533
7534 HValue* op_vals[] = { context, fun, arity, expected_param_count };
7535
7536 Handle<Code> adaptor =
7537 isolate()->builtins()->ArgumentsAdaptorTrampoline();
7538 HConstant* adaptor_value = Add<HConstant>(adaptor);
7539
7540 return New<HCallWithDescriptor>(
7541 adaptor_value, argument_count, descriptor,
7542 Vector<HValue*>(op_vals, descriptor.GetEnvironmentLength()));
7543}
7544
7545
7546HInstruction* HOptimizedGraphBuilder::BuildCallConstantFunction(
7547 Handle<JSFunction> jsfun, int argument_count) {
7548 HValue* target = Add<HConstant>(jsfun);
7549 // For constant functions, we try to avoid calling the
7550 // argument adaptor and instead call the function directly
7551 int formal_parameter_count = jsfun->shared()->formal_parameter_count();
7552 bool dont_adapt_arguments =
7553 (formal_parameter_count ==
7554 SharedFunctionInfo::kDontAdaptArgumentsSentinel);
7555 int arity = argument_count - 1;
7556 bool can_invoke_directly =
7557 dont_adapt_arguments || formal_parameter_count == arity;
7558 if (can_invoke_directly) {
7559 if (jsfun.is_identical_to(current_info()->closure())) {
7560 graph()->MarkRecursive();
7561 }
7562 return NewPlainFunctionCall(target, argument_count, dont_adapt_arguments);
7563 } else {
7564 HValue* param_count_value = Add<HConstant>(formal_parameter_count);
7565 HValue* context = Add<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007566 target, nullptr, HObjectAccess::ForFunctionContextPointer());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007567 return NewArgumentAdaptorCall(target, context,
7568 argument_count, param_count_value);
7569 }
7570 UNREACHABLE();
7571 return NULL;
7572}
7573
7574
7575class FunctionSorter {
7576 public:
7577 explicit FunctionSorter(int index = 0, int ticks = 0, int size = 0)
7578 : index_(index), ticks_(ticks), size_(size) {}
7579
7580 int index() const { return index_; }
7581 int ticks() const { return ticks_; }
7582 int size() const { return size_; }
7583
7584 private:
7585 int index_;
7586 int ticks_;
7587 int size_;
7588};
7589
7590
7591inline bool operator<(const FunctionSorter& lhs, const FunctionSorter& rhs) {
7592 int diff = lhs.ticks() - rhs.ticks();
7593 if (diff != 0) return diff > 0;
7594 return lhs.size() < rhs.size();
7595}
7596
7597
7598void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
7599 Call* expr,
7600 HValue* receiver,
7601 SmallMapList* types,
7602 Handle<String> name) {
7603 int argument_count = expr->arguments()->length() + 1; // Includes receiver.
7604 FunctionSorter order[kMaxCallPolymorphism];
7605
7606 bool handle_smi = false;
7607 bool handled_string = false;
7608 int ordered_functions = 0;
7609
7610 int i;
7611 for (i = 0; i < types->length() && ordered_functions < kMaxCallPolymorphism;
7612 ++i) {
7613 PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name);
7614 if (info.CanAccessMonomorphic() && info.IsConstant() &&
7615 info.constant()->IsJSFunction()) {
7616 if (info.type()->Is(Type::String())) {
7617 if (handled_string) continue;
7618 handled_string = true;
7619 }
7620 Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant());
7621 if (info.type()->Is(Type::Number())) {
7622 handle_smi = true;
7623 }
7624 expr->set_target(target);
7625 order[ordered_functions++] = FunctionSorter(
7626 i, target->shared()->profiler_ticks(), InliningAstSize(target));
7627 }
7628 }
7629
7630 std::sort(order, order + ordered_functions);
7631
7632 if (i < types->length()) {
7633 types->Clear();
7634 ordered_functions = -1;
7635 }
7636
7637 HBasicBlock* number_block = NULL;
7638 HBasicBlock* join = NULL;
7639 handled_string = false;
7640 int count = 0;
7641
7642 for (int fn = 0; fn < ordered_functions; ++fn) {
7643 int i = order[fn].index();
7644 PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name);
7645 if (info.type()->Is(Type::String())) {
7646 if (handled_string) continue;
7647 handled_string = true;
7648 }
7649 // Reloads the target.
7650 info.CanAccessMonomorphic();
7651 Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant());
7652
7653 expr->set_target(target);
7654 if (count == 0) {
7655 // Only needed once.
7656 join = graph()->CreateBasicBlock();
7657 if (handle_smi) {
7658 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock();
7659 HBasicBlock* not_smi_block = graph()->CreateBasicBlock();
7660 number_block = graph()->CreateBasicBlock();
7661 FinishCurrentBlock(New<HIsSmiAndBranch>(
7662 receiver, empty_smi_block, not_smi_block));
7663 GotoNoSimulate(empty_smi_block, number_block);
7664 set_current_block(not_smi_block);
7665 } else {
7666 BuildCheckHeapObject(receiver);
7667 }
7668 }
7669 ++count;
7670 HBasicBlock* if_true = graph()->CreateBasicBlock();
7671 HBasicBlock* if_false = graph()->CreateBasicBlock();
7672 HUnaryControlInstruction* compare;
7673
7674 Handle<Map> map = info.map();
7675 if (info.type()->Is(Type::Number())) {
7676 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map();
7677 compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false);
7678 } else if (info.type()->Is(Type::String())) {
7679 compare = New<HIsStringAndBranch>(receiver, if_true, if_false);
7680 } else {
7681 compare = New<HCompareMap>(receiver, map, if_true, if_false);
7682 }
7683 FinishCurrentBlock(compare);
7684
7685 if (info.type()->Is(Type::Number())) {
7686 GotoNoSimulate(if_true, number_block);
7687 if_true = number_block;
7688 }
7689
7690 set_current_block(if_true);
7691
7692 AddCheckPrototypeMaps(info.holder(), map);
7693
7694 HValue* function = Add<HConstant>(expr->target());
7695 environment()->SetExpressionStackAt(0, function);
7696 Push(receiver);
7697 CHECK_ALIVE(VisitExpressions(expr->arguments()));
7698 bool needs_wrapping = NeedsWrappingFor(info.type(), target);
7699 bool try_inline = FLAG_polymorphic_inlining && !needs_wrapping;
7700 if (FLAG_trace_inlining && try_inline) {
7701 Handle<JSFunction> caller = current_info()->closure();
7702 SmartArrayPointer<char> caller_name =
7703 caller->shared()->DebugName()->ToCString();
7704 PrintF("Trying to inline the polymorphic call to %s from %s\n",
7705 name->ToCString().get(),
7706 caller_name.get());
7707 }
7708 if (try_inline && TryInlineCall(expr)) {
7709 // Trying to inline will signal that we should bailout from the
7710 // entire compilation by setting stack overflow on the visitor.
7711 if (HasStackOverflow()) return;
7712 } else {
7713 // Since HWrapReceiver currently cannot actually wrap numbers and strings,
7714 // use the regular CallFunctionStub for method calls to wrap the receiver.
7715 // TODO(verwaest): Support creation of value wrappers directly in
7716 // HWrapReceiver.
7717 HInstruction* call = needs_wrapping
7718 ? NewUncasted<HCallFunction>(
7719 function, argument_count, WRAP_AND_CALL)
7720 : BuildCallConstantFunction(target, argument_count);
7721 PushArgumentsFromEnvironment(argument_count);
7722 AddInstruction(call);
7723 Drop(1); // Drop the function.
7724 if (!ast_context()->IsEffect()) Push(call);
7725 }
7726
7727 if (current_block() != NULL) Goto(join);
7728 set_current_block(if_false);
7729 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007730
Steve Block44f0eee2011-05-26 01:26:41 +01007731 // Finish up. Unconditionally deoptimize if we've handled all the maps we
7732 // know about and do not want to handle ones we've never seen. Otherwise
7733 // use a generic IC.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007734 if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) {
7735 FinishExitWithHardDeoptimization("Unknown map in polymorphic call");
Steve Block44f0eee2011-05-26 01:26:41 +01007736 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007737 Property* prop = expr->expression()->AsProperty();
7738 HInstruction* function = BuildNamedGeneric(
7739 LOAD, prop, receiver, name, NULL, prop->IsUninitialized());
7740 AddInstruction(function);
7741 Push(function);
7742 AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE);
7743
7744 environment()->SetExpressionStackAt(1, function);
7745 environment()->SetExpressionStackAt(0, receiver);
7746 CHECK_ALIVE(VisitExpressions(expr->arguments()));
7747
7748 CallFunctionFlags flags = receiver->type().IsJSObject()
7749 ? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD;
7750 HInstruction* call = New<HCallFunction>(
7751 function, argument_count, flags);
7752
7753 PushArgumentsFromEnvironment(argument_count);
7754
7755 Drop(1); // Function.
Ben Murdochb0fe1622011-05-05 13:52:32 +01007756
Steve Block44f0eee2011-05-26 01:26:41 +01007757 if (join != NULL) {
7758 AddInstruction(call);
7759 if (!ast_context()->IsEffect()) Push(call);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007760 Goto(join);
Steve Block44f0eee2011-05-26 01:26:41 +01007761 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007762 return ast_context()->ReturnInstruction(call, expr->id());
Steve Block9fac8402011-05-12 15:51:54 +01007763 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007764 }
Steve Block44f0eee2011-05-26 01:26:41 +01007765
7766 // We assume that control flow is always live after an expression. So
7767 // even without predecessors to the join block, we set it as the exit
7768 // block and continue by adding instructions there.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007769 DCHECK(join != NULL);
Steve Block44f0eee2011-05-26 01:26:41 +01007770 if (join->HasPredecessor()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00007771 set_current_block(join);
Steve Block44f0eee2011-05-26 01:26:41 +01007772 join->SetJoinId(expr->id());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007773 if (!ast_context()->IsEffect()) return ast_context()->ReturnValue(Pop());
Ben Murdoch257744e2011-11-30 15:57:28 +00007774 } else {
7775 set_current_block(NULL);
Steve Block44f0eee2011-05-26 01:26:41 +01007776 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007777}
7778
7779
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007780void HOptimizedGraphBuilder::TraceInline(Handle<JSFunction> target,
7781 Handle<JSFunction> caller,
7782 const char* reason) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007783 if (FLAG_trace_inlining) {
Ben Murdoch589d6972011-11-30 16:04:58 +00007784 SmartArrayPointer<char> target_name =
7785 target->shared()->DebugName()->ToCString();
7786 SmartArrayPointer<char> caller_name =
7787 caller->shared()->DebugName()->ToCString();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007788 if (reason == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007789 PrintF("Inlined %s called from %s.\n", target_name.get(),
7790 caller_name.get());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007791 } else {
7792 PrintF("Did not inline %s called from %s (%s).\n",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007793 target_name.get(), caller_name.get(), reason);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007794 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007795 }
7796}
7797
7798
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007799static const int kNotInlinable = 1000000000;
7800
7801
7802int HOptimizedGraphBuilder::InliningAstSize(Handle<JSFunction> target) {
7803 if (!FLAG_use_inlining) return kNotInlinable;
Ben Murdochb0fe1622011-05-05 13:52:32 +01007804
7805 // Precondition: call is monomorphic and we have found a target with the
7806 // appropriate arity.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007807 Handle<JSFunction> caller = current_info()->closure();
Ben Murdoch257744e2011-11-30 15:57:28 +00007808 Handle<SharedFunctionInfo> target_shared(target->shared());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007809
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007810 // Always inline builtins marked for inlining.
7811 if (target->IsBuiltin()) {
7812 return target_shared->inline_builtin() ? 0 : kNotInlinable;
7813 }
7814
7815 if (target_shared->IsApiFunction()) {
7816 TraceInline(target, caller, "target is api function");
7817 return kNotInlinable;
7818 }
7819
Ben Murdochb0fe1622011-05-05 13:52:32 +01007820 // Do a quick check on source code length to avoid parsing large
7821 // inlining candidates.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007822 if (target_shared->SourceSize() >
7823 Min(FLAG_max_inlined_source_size, kUnlimitedMaxInlinedSourceSize)) {
Ben Murdoch257744e2011-11-30 15:57:28 +00007824 TraceInline(target, caller, "target text too big");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007825 return kNotInlinable;
Ben Murdochb0fe1622011-05-05 13:52:32 +01007826 }
7827
7828 // Target must be inlineable.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007829 if (!target_shared->IsInlineable()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00007830 TraceInline(target, caller, "target not inlineable");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007831 return kNotInlinable;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007832 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007833 if (target_shared->disable_optimization_reason() != kNoReason) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007834 TraceInline(target, caller, "target contains unsupported syntax [early]");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007835 return kNotInlinable;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007836 }
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01007837
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007838 int nodes_added = target_shared->ast_node_count();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007839 return nodes_added;
7840}
7841
7842
7843bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target,
7844 int arguments_count,
7845 HValue* implicit_return_value,
7846 BailoutId ast_id,
7847 BailoutId return_id,
7848 InliningKind inlining_kind,
7849 HSourcePosition position) {
7850 int nodes_added = InliningAstSize(target);
7851 if (nodes_added == kNotInlinable) return false;
7852
7853 Handle<JSFunction> caller = current_info()->closure();
7854
7855 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007856 TraceInline(target, caller, "target AST is too large [early]");
7857 return false;
7858 }
7859
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007860 // Don't inline deeper than the maximum number of inlining levels.
Ben Murdochb0fe1622011-05-05 13:52:32 +01007861 HEnvironment* env = environment();
Ben Murdoch8b112d22011-06-08 16:22:53 +01007862 int current_level = 1;
7863 while (env->outer() != NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007864 if (current_level == FLAG_max_inlining_levels) {
Ben Murdoch257744e2011-11-30 15:57:28 +00007865 TraceInline(target, caller, "inline depth limit reached");
Ben Murdoch8b112d22011-06-08 16:22:53 +01007866 return false;
7867 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007868 if (env->outer()->frame_type() == JS_FUNCTION) {
7869 current_level++;
7870 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01007871 env = env->outer();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007872 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007873
7874 // Don't inline recursive functions.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007875 for (FunctionState* state = function_state();
7876 state != NULL;
7877 state = state->outer()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007878 if (*state->compilation_info()->closure() == *target) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007879 TraceInline(target, caller, "target is recursive");
7880 return false;
7881 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007882 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007883
7884 // We don't want to add more than a certain number of nodes from inlining.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007885 if (inlined_count_ > Min(FLAG_max_inlined_nodes_cumulative,
7886 kUnlimitedMaxInlinedNodesCumulative)) {
Ben Murdoch257744e2011-11-30 15:57:28 +00007887 TraceInline(target, caller, "cumulative AST node limit reached");
Ben Murdochb0fe1622011-05-05 13:52:32 +01007888 return false;
7889 }
7890
Ben Murdochb0fe1622011-05-05 13:52:32 +01007891 // Parse and allocate variables.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007892 CompilationInfo target_info(target, zone());
7893 // Use the same AstValueFactory for creating strings in the sub-compilation
7894 // step, but don't transfer ownership to target_info.
7895 target_info.SetAstValueFactory(top_info()->ast_value_factory(), false);
7896 Handle<SharedFunctionInfo> target_shared(target->shared());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007897 if (!Compiler::ParseAndAnalyze(&target_info)) {
Steve Block44f0eee2011-05-26 01:26:41 +01007898 if (target_info.isolate()->has_pending_exception()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007899 // Parse or scope error, never optimize this function.
Steve Block1e0659c2011-05-24 12:43:12 +01007900 SetStackOverflow();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007901 target_shared->DisableOptimization(kParseScopeError);
Steve Block1e0659c2011-05-24 12:43:12 +01007902 }
Ben Murdoch257744e2011-11-30 15:57:28 +00007903 TraceInline(target, caller, "parse failure");
Ben Murdochb0fe1622011-05-05 13:52:32 +01007904 return false;
7905 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007906
7907 if (target_info.scope()->num_heap_slots() > 0) {
Ben Murdoch257744e2011-11-30 15:57:28 +00007908 TraceInline(target, caller, "target has context-allocated variables");
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007909 return false;
7910 }
7911 FunctionLiteral* function = target_info.function();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007912
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007913 // The following conditions must be checked again after re-parsing, because
7914 // earlier the information might not have been complete due to lazy parsing.
7915 nodes_added = function->ast_node_count();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007916 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007917 TraceInline(target, caller, "target AST is too large [late]");
7918 return false;
7919 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007920 if (function->dont_optimize()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007921 TraceInline(target, caller, "target contains unsupported syntax [late]");
Ben Murdochb0fe1622011-05-05 13:52:32 +01007922 return false;
7923 }
7924
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007925 // If the function uses the arguments object check that inlining of functions
7926 // with arguments object is enabled and the arguments-variable is
7927 // stack allocated.
7928 if (function->scope()->arguments() != NULL) {
7929 if (!FLAG_inline_arguments) {
7930 TraceInline(target, caller, "target uses arguments object");
7931 return false;
7932 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007933 }
7934
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007935 // All declarations must be inlineable.
7936 ZoneList<Declaration*>* decls = target_info.scope()->declarations();
7937 int decl_count = decls->length();
7938 for (int i = 0; i < decl_count; ++i) {
7939 if (!decls->at(i)->IsInlineable()) {
7940 TraceInline(target, caller, "target has non-trivial declaration");
7941 return false;
7942 }
7943 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007944
7945 // Generate the deoptimization data for the unoptimized version of
7946 // the target function if we don't already have it.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007947 if (!Compiler::EnsureDeoptimizationSupport(&target_info)) {
7948 TraceInline(target, caller, "could not generate deoptimization info");
7949 return false;
Ben Murdochb0fe1622011-05-05 13:52:32 +01007950 }
7951
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007952 // ----------------------------------------------------------------
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007953 // After this point, we've made a decision to inline this function (so
7954 // TryInline should always return true).
7955
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007956 // Type-check the inlined function.
7957 DCHECK(target_shared->has_deoptimization_support());
7958 AstTyper::Run(&target_info);
7959
7960 int function_id = graph()->TraceInlinedFunction(target_shared, position);
7961
7962 // Save the pending call context. Set up new one for the inlined function.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007963 // The function state is new-allocated because we need to delete it
7964 // in two different places.
7965 FunctionState* target_state = new FunctionState(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007966 this, &target_info, inlining_kind, function_id);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007967
Steve Block44f0eee2011-05-26 01:26:41 +01007968 HConstant* undefined = graph()->GetConstantUndefined();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007969
Steve Block44f0eee2011-05-26 01:26:41 +01007970 HEnvironment* inner_env =
Ben Murdoch257744e2011-11-30 15:57:28 +00007971 environment()->CopyForInlining(target,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007972 arguments_count,
Ben Murdoch257744e2011-11-30 15:57:28 +00007973 function,
Ben Murdoch257744e2011-11-30 15:57:28 +00007974 undefined,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007975 function_state()->inlining_kind());
7976
7977 HConstant* context = Add<HConstant>(Handle<Context>(target->context()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007978 inner_env->BindContext(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007979
7980 // Create a dematerialized arguments object for the function, also copy the
7981 // current arguments values to use them for materialization.
7982 HEnvironment* arguments_env = inner_env->arguments_environment();
7983 int parameter_count = arguments_env->parameter_count();
7984 HArgumentsObject* arguments_object = Add<HArgumentsObject>(parameter_count);
7985 for (int i = 0; i < parameter_count; i++) {
7986 arguments_object->AddArgument(arguments_env->Lookup(i), zone());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007987 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007988
7989 // If the function uses arguments object then bind bind one.
7990 if (function->scope()->arguments() != NULL) {
7991 DCHECK(function->scope()->arguments()->IsStackAllocated());
7992 inner_env->Bind(function->scope()->arguments(), arguments_object);
7993 }
7994
7995 // Capture the state before invoking the inlined function for deopt in the
7996 // inlined function. This simulate has no bailout-id since it's not directly
7997 // reachable for deopt, and is only used to capture the state. If the simulate
7998 // becomes reachable by merging, the ast id of the simulate merged into it is
7999 // adopted.
8000 Add<HSimulate>(BailoutId::None());
8001
8002 current_block()->UpdateEnvironment(inner_env);
8003 Scope* saved_scope = scope();
8004 set_scope(target_info.scope());
8005 HEnterInlined* enter_inlined =
8006 Add<HEnterInlined>(return_id, target, context, arguments_count, function,
8007 function_state()->inlining_kind(),
8008 function->scope()->arguments(), arguments_object);
8009 function_state()->set_entry(enter_inlined);
8010
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008011 VisitDeclarations(target_info.scope()->declarations());
Steve Block44f0eee2011-05-26 01:26:41 +01008012 VisitStatements(function->body());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008013 set_scope(saved_scope);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008014 if (HasStackOverflow()) {
8015 // Bail out if the inline function did, as we cannot residualize a call
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008016 // instead, but do not disable optimization for the outer function.
Ben Murdoch257744e2011-11-30 15:57:28 +00008017 TraceInline(target, caller, "inline graph construction failed");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008018 target_shared->DisableOptimization(kInliningBailedOut);
8019 current_info()->RetryOptimization(kInliningBailedOut);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008020 delete target_state;
Ben Murdoch257744e2011-11-30 15:57:28 +00008021 return true;
Ben Murdochb0fe1622011-05-05 13:52:32 +01008022 }
8023
8024 // Update inlined nodes count.
8025 inlined_count_ += nodes_added;
8026
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008027 Handle<Code> unoptimized_code(target_shared->code());
8028 DCHECK(unoptimized_code->kind() == Code::FUNCTION);
8029 Handle<TypeFeedbackInfo> type_info(
8030 TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info()));
8031 graph()->update_type_change_checksum(type_info->own_type_change_checksum());
8032
Ben Murdoch257744e2011-11-30 15:57:28 +00008033 TraceInline(target, caller, NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008034
Steve Block44f0eee2011-05-26 01:26:41 +01008035 if (current_block() != NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008036 FunctionState* state = function_state();
8037 if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) {
8038 // Falling off the end of an inlined construct call. In a test context the
8039 // return value will always evaluate to true, in a value context the
8040 // return value is the newly allocated receiver.
8041 if (call_context()->IsTest()) {
8042 Goto(inlined_test_context()->if_true(), state);
8043 } else if (call_context()->IsEffect()) {
8044 Goto(function_return(), state);
8045 } else {
8046 DCHECK(call_context()->IsValue());
8047 AddLeaveInlined(implicit_return_value, state);
8048 }
8049 } else if (state->inlining_kind() == SETTER_CALL_RETURN) {
8050 // Falling off the end of an inlined setter call. The returned value is
8051 // never used, the value of an assignment is always the value of the RHS
8052 // of the assignment.
8053 if (call_context()->IsTest()) {
8054 inlined_test_context()->ReturnValue(implicit_return_value);
8055 } else if (call_context()->IsEffect()) {
8056 Goto(function_return(), state);
8057 } else {
8058 DCHECK(call_context()->IsValue());
8059 AddLeaveInlined(implicit_return_value, state);
8060 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008061 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008062 // Falling off the end of a normal inlined function. This basically means
8063 // returning undefined.
8064 if (call_context()->IsTest()) {
8065 Goto(inlined_test_context()->if_false(), state);
8066 } else if (call_context()->IsEffect()) {
8067 Goto(function_return(), state);
8068 } else {
8069 DCHECK(call_context()->IsValue());
8070 AddLeaveInlined(undefined, state);
8071 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008072 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008073 }
8074
Ben Murdochb0fe1622011-05-05 13:52:32 +01008075 // Fix up the function exits.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008076 if (inlined_test_context() != NULL) {
8077 HBasicBlock* if_true = inlined_test_context()->if_true();
8078 HBasicBlock* if_false = inlined_test_context()->if_false();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008079
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008080 HEnterInlined* entry = function_state()->entry();
8081
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008082 // Pop the return test context from the expression context stack.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008083 DCHECK(ast_context() == inlined_test_context());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008084 ClearInlinedTestContext();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008085 delete target_state;
Ben Murdochb0fe1622011-05-05 13:52:32 +01008086
8087 // Forward to the real test context.
Ben Murdoch257744e2011-11-30 15:57:28 +00008088 if (if_true->HasPredecessor()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008089 entry->RegisterReturnTarget(if_true, zone());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008090 if_true->SetJoinId(ast_id);
Ben Murdoch257744e2011-11-30 15:57:28 +00008091 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008092 Goto(if_true, true_target, function_state());
Ben Murdoch257744e2011-11-30 15:57:28 +00008093 }
8094 if (if_false->HasPredecessor()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008095 entry->RegisterReturnTarget(if_false, zone());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008096 if_false->SetJoinId(ast_id);
Ben Murdoch257744e2011-11-30 15:57:28 +00008097 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008098 Goto(if_false, false_target, function_state());
Ben Murdoch257744e2011-11-30 15:57:28 +00008099 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008100 set_current_block(NULL);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008101 return true;
Ben Murdochb0fe1622011-05-05 13:52:32 +01008102
Ben Murdoch257744e2011-11-30 15:57:28 +00008103 } else if (function_return()->HasPredecessor()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008104 function_state()->entry()->RegisterReturnTarget(function_return(), zone());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008105 function_return()->SetJoinId(ast_id);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008106 set_current_block(function_return());
Ben Murdoch257744e2011-11-30 15:57:28 +00008107 } else {
8108 set_current_block(NULL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008109 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008110 delete target_state;
Ben Murdochb0fe1622011-05-05 13:52:32 +01008111 return true;
8112}
8113
8114
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008115bool HOptimizedGraphBuilder::TryInlineCall(Call* expr) {
8116 return TryInline(expr->target(),
8117 expr->arguments()->length(),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008118 NULL,
8119 expr->id(),
8120 expr->ReturnId(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008121 NORMAL_RETURN,
8122 ScriptPositionToSourcePosition(expr->position()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008123}
8124
8125
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008126bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr,
8127 HValue* implicit_return_value) {
8128 return TryInline(expr->target(),
8129 expr->arguments()->length(),
8130 implicit_return_value,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008131 expr->id(),
8132 expr->ReturnId(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008133 CONSTRUCT_CALL_RETURN,
8134 ScriptPositionToSourcePosition(expr->position()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008135}
8136
8137
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008138bool HOptimizedGraphBuilder::TryInlineGetter(Handle<JSFunction> getter,
8139 Handle<Map> receiver_map,
8140 BailoutId ast_id,
8141 BailoutId return_id) {
8142 if (TryInlineApiGetter(getter, receiver_map, ast_id)) return true;
8143 return TryInline(getter,
8144 0,
8145 NULL,
8146 ast_id,
8147 return_id,
8148 GETTER_CALL_RETURN,
8149 source_position());
8150}
8151
8152
8153bool HOptimizedGraphBuilder::TryInlineSetter(Handle<JSFunction> setter,
8154 Handle<Map> receiver_map,
8155 BailoutId id,
8156 BailoutId assignment_id,
8157 HValue* implicit_return_value) {
8158 if (TryInlineApiSetter(setter, receiver_map, id)) return true;
8159 return TryInline(setter,
8160 1,
8161 implicit_return_value,
8162 id, assignment_id,
8163 SETTER_CALL_RETURN,
8164 source_position());
8165}
8166
8167
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008168bool HOptimizedGraphBuilder::TryInlineIndirectCall(Handle<JSFunction> function,
8169 Call* expr,
8170 int arguments_count) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008171 return TryInline(function,
8172 arguments_count,
8173 NULL,
8174 expr->id(),
8175 expr->ReturnId(),
8176 NORMAL_RETURN,
8177 ScriptPositionToSourcePosition(expr->position()));
8178}
8179
8180
8181bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008182 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false;
8183 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
8184 switch (id) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008185 case kMathExp:
8186 if (!FLAG_fast_math) break;
8187 // Fall through if FLAG_fast_math.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008188 case kMathRound:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008189 case kMathFround:
8190 case kMathFloor:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008191 case kMathAbs:
8192 case kMathSqrt:
8193 case kMathLog:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008194 case kMathClz32:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008195 if (expr->arguments()->length() == 1) {
8196 HValue* argument = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008197 Drop(2); // Receiver and function.
8198 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id);
8199 ast_context()->ReturnInstruction(op, expr->id());
8200 return true;
8201 }
8202 break;
8203 case kMathImul:
8204 if (expr->arguments()->length() == 2) {
8205 HValue* right = Pop();
8206 HValue* left = Pop();
8207 Drop(2); // Receiver and function.
8208 HInstruction* op = HMul::NewImul(zone(), context(), left, right);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008209 ast_context()->ReturnInstruction(op, expr->id());
8210 return true;
8211 }
8212 break;
8213 default:
8214 // Not supported for inlining yet.
8215 break;
8216 }
8217 return false;
8218}
8219
8220
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008221bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008222 Call* expr, Handle<JSFunction> function, Handle<Map> receiver_map,
8223 int args_count_no_receiver) {
8224 if (!function->shared()->HasBuiltinFunctionId()) return false;
8225 BuiltinFunctionId id = function->shared()->builtin_function_id();
8226 int argument_count = args_count_no_receiver + 1; // Plus receiver.
8227
8228 if (receiver_map.is_null()) {
8229 HValue* receiver = environment()->ExpressionStackAt(args_count_no_receiver);
8230 if (receiver->IsConstant() &&
8231 HConstant::cast(receiver)->handle(isolate())->IsHeapObject()) {
8232 receiver_map =
8233 handle(Handle<HeapObject>::cast(
8234 HConstant::cast(receiver)->handle(isolate()))->map());
8235 }
8236 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008237 // Try to inline calls like Math.* as operations in the calling function.
Ben Murdochb0fe1622011-05-05 13:52:32 +01008238 switch (id) {
Steve Block1e0659c2011-05-24 12:43:12 +01008239 case kStringCharCodeAt:
Steve Block44f0eee2011-05-26 01:26:41 +01008240 case kStringCharAt:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008241 if (argument_count == 2) {
Steve Block1e0659c2011-05-24 12:43:12 +01008242 HValue* index = Pop();
8243 HValue* string = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008244 Drop(1); // Function.
8245 HInstruction* char_code =
8246 BuildStringCharCodeAt(string, index);
Steve Block44f0eee2011-05-26 01:26:41 +01008247 if (id == kStringCharCodeAt) {
8248 ast_context()->ReturnInstruction(char_code, expr->id());
8249 return true;
8250 }
8251 AddInstruction(char_code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008252 HInstruction* result = NewUncasted<HStringCharFromCode>(char_code);
Steve Block1e0659c2011-05-24 12:43:12 +01008253 ast_context()->ReturnInstruction(result, expr->id());
8254 return true;
8255 }
8256 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008257 case kStringFromCharCode:
8258 if (argument_count == 2) {
8259 HValue* argument = Pop();
8260 Drop(2); // Receiver and function.
8261 HInstruction* result = NewUncasted<HStringCharFromCode>(argument);
8262 ast_context()->ReturnInstruction(result, expr->id());
8263 return true;
8264 }
8265 break;
8266 case kMathExp:
8267 if (!FLAG_fast_math) break;
8268 // Fall through if FLAG_fast_math.
Ben Murdochb0fe1622011-05-05 13:52:32 +01008269 case kMathRound:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008270 case kMathFround:
Ben Murdochb0fe1622011-05-05 13:52:32 +01008271 case kMathFloor:
8272 case kMathAbs:
8273 case kMathSqrt:
8274 case kMathLog:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008275 case kMathClz32:
8276 if (argument_count == 2) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008277 HValue* argument = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008278 Drop(2); // Receiver and function.
8279 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008280 ast_context()->ReturnInstruction(op, expr->id());
8281 return true;
8282 }
8283 break;
8284 case kMathPow:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008285 if (argument_count == 3) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008286 HValue* right = Pop();
8287 HValue* left = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008288 Drop(2); // Receiver and function.
Ben Murdochb0fe1622011-05-05 13:52:32 +01008289 HInstruction* result = NULL;
8290 // Use sqrt() if exponent is 0.5 or -0.5.
8291 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) {
8292 double exponent = HConstant::cast(right)->DoubleValue();
8293 if (exponent == 0.5) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008294 result = NewUncasted<HUnaryMathOperation>(left, kMathPowHalf);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008295 } else if (exponent == -0.5) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008296 HValue* one = graph()->GetConstant1();
8297 HInstruction* sqrt = AddUncasted<HUnaryMathOperation>(
8298 left, kMathPowHalf);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008299 // MathPowHalf doesn't have side effects so there's no need for
8300 // an environment simulation here.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008301 DCHECK(!sqrt->HasObservableSideEffects());
8302 result = NewUncasted<HDiv>(one, sqrt);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008303 } else if (exponent == 2.0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008304 result = NewUncasted<HMul>(left, left);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008305 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008306 }
8307
Steve Block1e0659c2011-05-24 12:43:12 +01008308 if (result == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008309 result = NewUncasted<HPower>(left, right);
Steve Block1e0659c2011-05-24 12:43:12 +01008310 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008311 ast_context()->ReturnInstruction(result, expr->id());
8312 return true;
8313 }
8314 break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008315 case kMathMax:
8316 case kMathMin:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008317 if (argument_count == 3) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008318 HValue* right = Pop();
8319 HValue* left = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008320 Drop(2); // Receiver and function.
8321 HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin
8322 : HMathMinMax::kMathMax;
8323 HInstruction* result = NewUncasted<HMathMinMax>(left, right, op);
8324 ast_context()->ReturnInstruction(result, expr->id());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008325 return true;
8326 }
8327 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008328 case kMathImul:
8329 if (argument_count == 3) {
8330 HValue* right = Pop();
8331 HValue* left = Pop();
8332 Drop(2); // Receiver and function.
8333 HInstruction* result = HMul::NewImul(zone(), context(), left, right);
8334 ast_context()->ReturnInstruction(result, expr->id());
8335 return true;
8336 }
8337 break;
8338 case kArrayPop: {
8339 if (receiver_map.is_null()) return false;
8340 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false;
8341 ElementsKind elements_kind = receiver_map->elements_kind();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008342 if (JSArray::IsReadOnlyLengthDescriptor(receiver_map)) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008343 if (!IsFastElementsKind(elements_kind)) return false;
8344 if (receiver_map->is_observed()) return false;
8345 if (!receiver_map->is_extensible()) return false;
8346
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008347 Drop(args_count_no_receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008348 HValue* result;
8349 HValue* reduced_length;
8350 HValue* receiver = Pop();
8351
8352 HValue* checked_object = AddCheckMap(receiver, receiver_map);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008353 HValue* length =
8354 Add<HLoadNamedField>(checked_object, nullptr,
8355 HObjectAccess::ForArrayLength(elements_kind));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008356
8357 Drop(1); // Function.
8358
8359 { NoObservableSideEffectsScope scope(this);
8360 IfBuilder length_checker(this);
8361
8362 HValue* bounds_check = length_checker.If<HCompareNumericAndBranch>(
8363 length, graph()->GetConstant0(), Token::EQ);
8364 length_checker.Then();
8365
8366 if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined());
8367
8368 length_checker.Else();
8369 HValue* elements = AddLoadElements(checked_object);
8370 // Ensure that we aren't popping from a copy-on-write array.
8371 if (IsFastSmiOrObjectElementsKind(elements_kind)) {
8372 elements = BuildCopyElementsOnWrite(checked_object, elements,
8373 elements_kind, length);
8374 }
8375 reduced_length = AddUncasted<HSub>(length, graph()->GetConstant1());
8376 result = AddElementAccess(elements, reduced_length, NULL,
8377 bounds_check, elements_kind, LOAD);
8378 Factory* factory = isolate()->factory();
8379 double nan_double = FixedDoubleArray::hole_nan_as_double();
8380 HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind)
8381 ? Add<HConstant>(factory->the_hole_value())
8382 : Add<HConstant>(nan_double);
8383 if (IsFastSmiOrObjectElementsKind(elements_kind)) {
8384 elements_kind = FAST_HOLEY_ELEMENTS;
8385 }
8386 AddElementAccess(
8387 elements, reduced_length, hole, bounds_check, elements_kind, STORE);
8388 Add<HStoreNamedField>(
8389 checked_object, HObjectAccess::ForArrayLength(elements_kind),
8390 reduced_length, STORE_TO_INITIALIZED_ENTRY);
8391
8392 if (!ast_context()->IsEffect()) Push(result);
8393
8394 length_checker.End();
8395 }
8396 result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top();
8397 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
8398 if (!ast_context()->IsEffect()) Drop(1);
8399
8400 ast_context()->ReturnValue(result);
8401 return true;
8402 }
8403 case kArrayPush: {
8404 if (receiver_map.is_null()) return false;
8405 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false;
8406 ElementsKind elements_kind = receiver_map->elements_kind();
8407 if (!IsFastElementsKind(elements_kind)) return false;
8408 if (receiver_map->is_observed()) return false;
8409 if (JSArray::IsReadOnlyLengthDescriptor(receiver_map)) return false;
8410 if (!receiver_map->is_extensible()) return false;
8411
8412 // If there may be elements accessors in the prototype chain, the fast
8413 // inlined version can't be used.
8414 if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false;
8415 // If there currently can be no elements accessors on the prototype chain,
8416 // it doesn't mean that there won't be any later. Install a full prototype
8417 // chain check to trap element accessors being installed on the prototype
8418 // chain, which would cause elements to go to dictionary mode and result
8419 // in a map change.
8420 Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype()));
8421 BuildCheckPrototypeMaps(prototype, Handle<JSObject>());
8422
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008423 const int argc = args_count_no_receiver;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008424 if (argc != 1) return false;
8425
8426 HValue* value_to_push = Pop();
8427 HValue* array = Pop();
8428 Drop(1); // Drop function.
8429
8430 HInstruction* new_size = NULL;
8431 HValue* length = NULL;
8432
8433 {
8434 NoObservableSideEffectsScope scope(this);
8435
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008436 length = Add<HLoadNamedField>(
8437 array, nullptr, HObjectAccess::ForArrayLength(elements_kind));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008438
8439 new_size = AddUncasted<HAdd>(length, graph()->GetConstant1());
8440
8441 bool is_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
8442 BuildUncheckedMonomorphicElementAccess(array, length,
8443 value_to_push, is_array,
8444 elements_kind, STORE,
8445 NEVER_RETURN_HOLE,
8446 STORE_AND_GROW_NO_TRANSITION);
8447
8448 if (!ast_context()->IsEffect()) Push(new_size);
8449 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
8450 if (!ast_context()->IsEffect()) Drop(1);
8451 }
8452
8453 ast_context()->ReturnValue(new_size);
8454 return true;
8455 }
8456 case kArrayShift: {
8457 if (receiver_map.is_null()) return false;
8458 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false;
8459 ElementsKind kind = receiver_map->elements_kind();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008460 if (JSArray::IsReadOnlyLengthDescriptor(receiver_map)) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008461 if (!IsFastElementsKind(kind)) return false;
8462 if (receiver_map->is_observed()) return false;
8463 if (!receiver_map->is_extensible()) return false;
8464
8465 // If there may be elements accessors in the prototype chain, the fast
8466 // inlined version can't be used.
8467 if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false;
8468
8469 // If there currently can be no elements accessors on the prototype chain,
8470 // it doesn't mean that there won't be any later. Install a full prototype
8471 // chain check to trap element accessors being installed on the prototype
8472 // chain, which would cause elements to go to dictionary mode and result
8473 // in a map change.
8474 BuildCheckPrototypeMaps(
8475 handle(JSObject::cast(receiver_map->prototype()), isolate()),
8476 Handle<JSObject>::null());
8477
8478 // Threshold for fast inlined Array.shift().
8479 HConstant* inline_threshold = Add<HConstant>(static_cast<int32_t>(16));
8480
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008481 Drop(args_count_no_receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008482 HValue* receiver = Pop();
8483 HValue* function = Pop();
8484 HValue* result;
8485
8486 {
8487 NoObservableSideEffectsScope scope(this);
8488
8489 HValue* length = Add<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008490 receiver, nullptr, HObjectAccess::ForArrayLength(kind));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008491
8492 IfBuilder if_lengthiszero(this);
8493 HValue* lengthiszero = if_lengthiszero.If<HCompareNumericAndBranch>(
8494 length, graph()->GetConstant0(), Token::EQ);
8495 if_lengthiszero.Then();
8496 {
8497 if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined());
8498 }
8499 if_lengthiszero.Else();
8500 {
8501 HValue* elements = AddLoadElements(receiver);
8502
8503 // Check if we can use the fast inlined Array.shift().
8504 IfBuilder if_inline(this);
8505 if_inline.If<HCompareNumericAndBranch>(
8506 length, inline_threshold, Token::LTE);
8507 if (IsFastSmiOrObjectElementsKind(kind)) {
8508 // We cannot handle copy-on-write backing stores here.
8509 if_inline.AndIf<HCompareMap>(
8510 elements, isolate()->factory()->fixed_array_map());
8511 }
8512 if_inline.Then();
8513 {
8514 // Remember the result.
8515 if (!ast_context()->IsEffect()) {
8516 Push(AddElementAccess(elements, graph()->GetConstant0(), NULL,
8517 lengthiszero, kind, LOAD));
8518 }
8519
8520 // Compute the new length.
8521 HValue* new_length = AddUncasted<HSub>(
8522 length, graph()->GetConstant1());
8523 new_length->ClearFlag(HValue::kCanOverflow);
8524
8525 // Copy the remaining elements.
8526 LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement);
8527 {
8528 HValue* new_key = loop.BeginBody(
8529 graph()->GetConstant0(), new_length, Token::LT);
8530 HValue* key = AddUncasted<HAdd>(new_key, graph()->GetConstant1());
8531 key->ClearFlag(HValue::kCanOverflow);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008532 ElementsKind copy_kind =
8533 kind == FAST_HOLEY_SMI_ELEMENTS ? FAST_HOLEY_ELEMENTS : kind;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008534 HValue* element = AddUncasted<HLoadKeyed>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008535 elements, key, lengthiszero, copy_kind, ALLOW_RETURN_HOLE);
8536 HStoreKeyed* store =
8537 Add<HStoreKeyed>(elements, new_key, element, copy_kind);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008538 store->SetFlag(HValue::kAllowUndefinedAsNaN);
8539 }
8540 loop.EndBody();
8541
8542 // Put a hole at the end.
8543 HValue* hole = IsFastSmiOrObjectElementsKind(kind)
8544 ? Add<HConstant>(isolate()->factory()->the_hole_value())
8545 : Add<HConstant>(FixedDoubleArray::hole_nan_as_double());
8546 if (IsFastSmiOrObjectElementsKind(kind)) kind = FAST_HOLEY_ELEMENTS;
8547 Add<HStoreKeyed>(
8548 elements, new_length, hole, kind, INITIALIZING_STORE);
8549
8550 // Remember new length.
8551 Add<HStoreNamedField>(
8552 receiver, HObjectAccess::ForArrayLength(kind),
8553 new_length, STORE_TO_INITIALIZED_ENTRY);
8554 }
8555 if_inline.Else();
8556 {
8557 Add<HPushArguments>(receiver);
8558 result = Add<HCallJSFunction>(function, 1, true);
8559 if (!ast_context()->IsEffect()) Push(result);
8560 }
8561 if_inline.End();
8562 }
8563 if_lengthiszero.End();
8564 }
8565 result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top();
8566 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
8567 if (!ast_context()->IsEffect()) Drop(1);
8568 ast_context()->ReturnValue(result);
8569 return true;
8570 }
8571 case kArrayIndexOf:
8572 case kArrayLastIndexOf: {
8573 if (receiver_map.is_null()) return false;
8574 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false;
8575 ElementsKind kind = receiver_map->elements_kind();
8576 if (!IsFastElementsKind(kind)) return false;
8577 if (receiver_map->is_observed()) return false;
8578 if (argument_count != 2) return false;
8579 if (!receiver_map->is_extensible()) return false;
8580
8581 // If there may be elements accessors in the prototype chain, the fast
8582 // inlined version can't be used.
8583 if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false;
8584
8585 // If there currently can be no elements accessors on the prototype chain,
8586 // it doesn't mean that there won't be any later. Install a full prototype
8587 // chain check to trap element accessors being installed on the prototype
8588 // chain, which would cause elements to go to dictionary mode and result
8589 // in a map change.
8590 BuildCheckPrototypeMaps(
8591 handle(JSObject::cast(receiver_map->prototype()), isolate()),
8592 Handle<JSObject>::null());
8593
8594 HValue* search_element = Pop();
8595 HValue* receiver = Pop();
8596 Drop(1); // Drop function.
8597
8598 ArrayIndexOfMode mode = (id == kArrayIndexOf)
8599 ? kFirstIndexOf : kLastIndexOf;
8600 HValue* index = BuildArrayIndexOf(receiver, search_element, kind, mode);
8601
8602 if (!ast_context()->IsEffect()) Push(index);
8603 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
8604 if (!ast_context()->IsEffect()) Drop(1);
8605 ast_context()->ReturnValue(index);
8606 return true;
8607 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008608 default:
8609 // Not yet supported for inlining.
8610 break;
8611 }
8612 return false;
8613}
8614
8615
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008616bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr,
8617 HValue* receiver) {
8618 Handle<JSFunction> function = expr->target();
8619 int argc = expr->arguments()->length();
8620 SmallMapList receiver_maps;
8621 return TryInlineApiCall(function,
8622 receiver,
8623 &receiver_maps,
8624 argc,
8625 expr->id(),
8626 kCallApiFunction);
8627}
Ben Murdochb0fe1622011-05-05 13:52:32 +01008628
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008629
8630bool HOptimizedGraphBuilder::TryInlineApiMethodCall(
8631 Call* expr,
8632 HValue* receiver,
8633 SmallMapList* receiver_maps) {
8634 Handle<JSFunction> function = expr->target();
8635 int argc = expr->arguments()->length();
8636 return TryInlineApiCall(function,
8637 receiver,
8638 receiver_maps,
8639 argc,
8640 expr->id(),
8641 kCallApiMethod);
8642}
8643
8644
8645bool HOptimizedGraphBuilder::TryInlineApiGetter(Handle<JSFunction> function,
8646 Handle<Map> receiver_map,
8647 BailoutId ast_id) {
8648 SmallMapList receiver_maps(1, zone());
8649 receiver_maps.Add(receiver_map, zone());
8650 return TryInlineApiCall(function,
8651 NULL, // Receiver is on expression stack.
8652 &receiver_maps,
8653 0,
8654 ast_id,
8655 kCallApiGetter);
8656}
8657
8658
8659bool HOptimizedGraphBuilder::TryInlineApiSetter(Handle<JSFunction> function,
8660 Handle<Map> receiver_map,
8661 BailoutId ast_id) {
8662 SmallMapList receiver_maps(1, zone());
8663 receiver_maps.Add(receiver_map, zone());
8664 return TryInlineApiCall(function,
8665 NULL, // Receiver is on expression stack.
8666 &receiver_maps,
8667 1,
8668 ast_id,
8669 kCallApiSetter);
8670}
8671
8672
8673bool HOptimizedGraphBuilder::TryInlineApiCall(Handle<JSFunction> function,
8674 HValue* receiver,
8675 SmallMapList* receiver_maps,
8676 int argc,
8677 BailoutId ast_id,
8678 ApiCallType call_type) {
8679 CallOptimization optimization(function);
8680 if (!optimization.is_simple_api_call()) return false;
8681 Handle<Map> holder_map;
8682 if (call_type == kCallApiFunction) {
8683 // Cannot embed a direct reference to the global proxy map
8684 // as it maybe dropped on deserialization.
8685 CHECK(!isolate()->serializer_enabled());
8686 DCHECK_EQ(0, receiver_maps->length());
8687 receiver_maps->Add(handle(function->global_proxy()->map()), zone());
8688 }
8689 CallOptimization::HolderLookup holder_lookup =
8690 CallOptimization::kHolderNotFound;
8691 Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType(
8692 receiver_maps->first(), &holder_lookup);
8693 if (holder_lookup == CallOptimization::kHolderNotFound) return false;
8694
8695 if (FLAG_trace_inlining) {
8696 PrintF("Inlining api function ");
8697 function->ShortPrint();
8698 PrintF("\n");
8699 }
8700
8701 bool drop_extra = false;
8702 bool is_store = false;
8703 switch (call_type) {
8704 case kCallApiFunction:
8705 case kCallApiMethod:
8706 // Need to check that none of the receiver maps could have changed.
8707 Add<HCheckMaps>(receiver, receiver_maps);
8708 // Need to ensure the chain between receiver and api_holder is intact.
8709 if (holder_lookup == CallOptimization::kHolderFound) {
8710 AddCheckPrototypeMaps(api_holder, receiver_maps->first());
8711 } else {
8712 DCHECK_EQ(holder_lookup, CallOptimization::kHolderIsReceiver);
8713 }
8714 // Includes receiver.
8715 PushArgumentsFromEnvironment(argc + 1);
8716 // Drop function after call.
8717 drop_extra = true;
8718 break;
8719 case kCallApiGetter:
8720 // Receiver and prototype chain cannot have changed.
8721 DCHECK_EQ(0, argc);
8722 DCHECK_EQ(NULL, receiver);
8723 // Receiver is on expression stack.
8724 receiver = Pop();
8725 Add<HPushArguments>(receiver);
8726 break;
8727 case kCallApiSetter:
8728 {
8729 is_store = true;
8730 // Receiver and prototype chain cannot have changed.
8731 DCHECK_EQ(1, argc);
8732 DCHECK_EQ(NULL, receiver);
8733 // Receiver and value are on expression stack.
8734 HValue* value = Pop();
8735 receiver = Pop();
8736 Add<HPushArguments>(receiver, value);
8737 break;
8738 }
8739 }
8740
8741 HValue* holder = NULL;
8742 switch (holder_lookup) {
8743 case CallOptimization::kHolderFound:
8744 holder = Add<HConstant>(api_holder);
8745 break;
8746 case CallOptimization::kHolderIsReceiver:
8747 holder = receiver;
8748 break;
8749 case CallOptimization::kHolderNotFound:
8750 UNREACHABLE();
8751 break;
8752 }
8753 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
8754 Handle<Object> call_data_obj(api_call_info->data(), isolate());
8755 bool call_data_is_undefined = call_data_obj->IsUndefined();
8756 HValue* call_data = Add<HConstant>(call_data_obj);
8757 ApiFunction fun(v8::ToCData<Address>(api_call_info->callback()));
8758 ExternalReference ref = ExternalReference(&fun,
8759 ExternalReference::DIRECT_API_CALL,
8760 isolate());
8761 HValue* api_function_address = Add<HConstant>(ExternalReference(ref));
8762
8763 HValue* op_vals[] = {
8764 context(),
8765 Add<HConstant>(function),
8766 call_data,
8767 holder,
8768 api_function_address
8769 };
8770
8771 ApiFunctionDescriptor descriptor(isolate());
8772 CallApiFunctionStub stub(isolate(), is_store, call_data_is_undefined, argc);
8773 Handle<Code> code = stub.GetCode();
8774 HConstant* code_value = Add<HConstant>(code);
8775
8776 DCHECK((sizeof(op_vals) / kPointerSize) == descriptor.GetEnvironmentLength());
8777
8778 HInstruction* call = New<HCallWithDescriptor>(
8779 code_value, argc + 1, descriptor,
8780 Vector<HValue*>(op_vals, descriptor.GetEnvironmentLength()));
8781
8782 if (drop_extra) Drop(1); // Drop function.
8783 ast_context()->ReturnInstruction(call, ast_id);
8784 return true;
8785}
8786
8787
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008788void HOptimizedGraphBuilder::HandleIndirectCall(Call* expr, HValue* function,
8789 int arguments_count) {
8790 Handle<JSFunction> known_function;
8791 int args_count_no_receiver = arguments_count - 1;
8792 if (function->IsConstant() &&
8793 HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
8794 HValue* receiver = environment()->ExpressionStackAt(args_count_no_receiver);
8795 Handle<Map> receiver_map;
8796 if (receiver->IsConstant() &&
8797 HConstant::cast(receiver)->handle(isolate())->IsHeapObject()) {
8798 receiver_map =
8799 handle(Handle<HeapObject>::cast(
8800 HConstant::cast(receiver)->handle(isolate()))->map());
8801 }
8802
8803 known_function =
8804 Handle<JSFunction>::cast(HConstant::cast(function)->handle(isolate()));
8805 if (TryInlineBuiltinMethodCall(expr, known_function, receiver_map,
8806 args_count_no_receiver)) {
8807 if (FLAG_trace_inlining) {
8808 PrintF("Inlining builtin ");
8809 known_function->ShortPrint();
8810 PrintF("\n");
8811 }
8812 return;
8813 }
8814
8815 if (TryInlineIndirectCall(known_function, expr, args_count_no_receiver)) {
8816 return;
8817 }
8818 }
8819
8820 PushArgumentsFromEnvironment(arguments_count);
8821 HInvokeFunction* call =
8822 New<HInvokeFunction>(function, known_function, arguments_count);
8823 Drop(1); // Function
8824 ast_context()->ReturnInstruction(call, expr->id());
8825}
8826
8827
8828bool HOptimizedGraphBuilder::TryIndirectCall(Call* expr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008829 DCHECK(expr->expression()->IsProperty());
8830
8831 if (!expr->IsMonomorphic()) {
Ben Murdoch42effa52011-08-19 16:40:31 +01008832 return false;
8833 }
8834 Handle<Map> function_map = expr->GetReceiverTypes()->first();
8835 if (function_map->instance_type() != JS_FUNCTION_TYPE ||
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008836 !expr->target()->shared()->HasBuiltinFunctionId()) {
Ben Murdoch42effa52011-08-19 16:40:31 +01008837 return false;
8838 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008839
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008840 switch (expr->target()->shared()->builtin_function_id()) {
8841 case kFunctionCall: {
8842 if (expr->arguments()->length() == 0) return false;
8843 BuildFunctionCall(expr);
8844 return true;
8845 }
8846 case kFunctionApply: {
8847 // For .apply, only the pattern f.apply(receiver, arguments)
8848 // is supported.
8849 if (current_info()->scope()->arguments() == NULL) return false;
Ben Murdochb0fe1622011-05-05 13:52:32 +01008850
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008851 if (!CanBeFunctionApplyArguments(expr)) return false;
8852
8853 BuildFunctionApply(expr);
8854 return true;
8855 }
8856 default: { return false; }
8857 }
8858 UNREACHABLE();
8859}
8860
8861
8862void HOptimizedGraphBuilder::BuildFunctionApply(Call* expr) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008863 ZoneList<Expression*>* args = expr->arguments();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008864 CHECK_ALIVE(VisitForValue(args->at(0)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008865 HValue* receiver = Pop(); // receiver
8866 HValue* function = Pop(); // f
8867 Drop(1); // apply
Ben Murdoch257744e2011-11-30 15:57:28 +00008868
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008869 Handle<Map> function_map = expr->GetReceiverTypes()->first();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008870 HValue* checked_function = AddCheckMap(function, function_map);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008871
8872 if (function_state()->outer() == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008873 HInstruction* elements = Add<HArgumentsElements>(false);
8874 HInstruction* length = Add<HArgumentsLength>(elements);
8875 HValue* wrapped_receiver = BuildWrapReceiver(receiver, checked_function);
8876 HInstruction* result = New<HApplyArguments>(function,
8877 wrapped_receiver,
8878 length,
8879 elements);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008880 ast_context()->ReturnInstruction(result, expr->id());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008881 } else {
8882 // We are inside inlined function and we know exactly what is inside
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008883 // arguments object. But we need to be able to materialize at deopt.
8884 DCHECK_EQ(environment()->arguments_environment()->parameter_count(),
8885 function_state()->entry()->arguments_object()->arguments_count());
8886 HArgumentsObject* args = function_state()->entry()->arguments_object();
8887 const ZoneList<HValue*>* arguments_values = args->arguments_values();
8888 int arguments_count = arguments_values->length();
8889 Push(function);
8890 Push(BuildWrapReceiver(receiver, checked_function));
8891 for (int i = 1; i < arguments_count; i++) {
8892 Push(arguments_values->at(i));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008893 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008894 HandleIndirectCall(expr, function, arguments_count);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008895 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008896}
8897
8898
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008899// f.call(...)
8900void HOptimizedGraphBuilder::BuildFunctionCall(Call* expr) {
8901 HValue* function = Top(); // f
8902 Handle<Map> function_map = expr->GetReceiverTypes()->first();
8903 HValue* checked_function = AddCheckMap(function, function_map);
8904
8905 // f and call are on the stack in the unoptimized code
8906 // during evaluation of the arguments.
8907 CHECK_ALIVE(VisitExpressions(expr->arguments()));
8908
8909 int args_length = expr->arguments()->length();
8910 int receiver_index = args_length - 1;
8911 // Patch the receiver.
8912 HValue* receiver = BuildWrapReceiver(
8913 environment()->ExpressionStackAt(receiver_index), checked_function);
8914 environment()->SetExpressionStackAt(receiver_index, receiver);
8915
8916 // Call must not be on the stack from now on.
8917 int call_index = args_length + 1;
8918 environment()->RemoveExpressionStackAt(call_index);
8919
8920 HandleIndirectCall(expr, function, args_length);
8921}
8922
8923
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008924HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function,
8925 Handle<JSFunction> target) {
8926 SharedFunctionInfo* shared = target->shared();
8927 if (shared->strict_mode() == SLOPPY && !shared->native()) {
8928 // Cannot embed a direct reference to the global proxy
8929 // as is it dropped on deserialization.
8930 CHECK(!isolate()->serializer_enabled());
8931 Handle<JSObject> global_proxy(target->context()->global_proxy());
8932 return Add<HConstant>(global_proxy);
8933 }
8934 return graph()->GetConstantUndefined();
8935}
8936
8937
8938void HOptimizedGraphBuilder::BuildArrayCall(Expression* expression,
8939 int arguments_count,
8940 HValue* function,
8941 Handle<AllocationSite> site) {
8942 Add<HCheckValue>(function, array_function());
8943
8944 if (IsCallArrayInlineable(arguments_count, site)) {
8945 BuildInlinedCallArray(expression, arguments_count, site);
8946 return;
8947 }
8948
8949 HInstruction* call = PreProcessCall(New<HCallNewArray>(
8950 function, arguments_count + 1, site->GetElementsKind()));
8951 if (expression->IsCall()) {
8952 Drop(1);
8953 }
8954 ast_context()->ReturnInstruction(call, expression->id());
8955}
8956
8957
8958HValue* HOptimizedGraphBuilder::BuildArrayIndexOf(HValue* receiver,
8959 HValue* search_element,
8960 ElementsKind kind,
8961 ArrayIndexOfMode mode) {
8962 DCHECK(IsFastElementsKind(kind));
8963
8964 NoObservableSideEffectsScope no_effects(this);
8965
8966 HValue* elements = AddLoadElements(receiver);
8967 HValue* length = AddLoadArrayLength(receiver, kind);
8968
8969 HValue* initial;
8970 HValue* terminating;
8971 Token::Value token;
8972 LoopBuilder::Direction direction;
8973 if (mode == kFirstIndexOf) {
8974 initial = graph()->GetConstant0();
8975 terminating = length;
8976 token = Token::LT;
8977 direction = LoopBuilder::kPostIncrement;
8978 } else {
8979 DCHECK_EQ(kLastIndexOf, mode);
8980 initial = length;
8981 terminating = graph()->GetConstant0();
8982 token = Token::GT;
8983 direction = LoopBuilder::kPreDecrement;
8984 }
8985
8986 Push(graph()->GetConstantMinus1());
8987 if (IsFastDoubleElementsKind(kind) || IsFastSmiElementsKind(kind)) {
8988 // Make sure that we can actually compare numbers correctly below, see
8989 // https://code.google.com/p/chromium/issues/detail?id=407946 for details.
8990 search_element = AddUncasted<HForceRepresentation>(
8991 search_element, IsFastSmiElementsKind(kind) ? Representation::Smi()
8992 : Representation::Double());
8993
8994 LoopBuilder loop(this, context(), direction);
8995 {
8996 HValue* index = loop.BeginBody(initial, terminating, token);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008997 HValue* element = AddUncasted<HLoadKeyed>(elements, index, nullptr, kind,
8998 ALLOW_RETURN_HOLE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008999 IfBuilder if_issame(this);
9000 if_issame.If<HCompareNumericAndBranch>(element, search_element,
9001 Token::EQ_STRICT);
9002 if_issame.Then();
9003 {
9004 Drop(1);
9005 Push(index);
9006 loop.Break();
9007 }
9008 if_issame.End();
9009 }
9010 loop.EndBody();
9011 } else {
9012 IfBuilder if_isstring(this);
9013 if_isstring.If<HIsStringAndBranch>(search_element);
9014 if_isstring.Then();
9015 {
9016 LoopBuilder loop(this, context(), direction);
9017 {
9018 HValue* index = loop.BeginBody(initial, terminating, token);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009019 HValue* element = AddUncasted<HLoadKeyed>(elements, index, nullptr,
9020 kind, ALLOW_RETURN_HOLE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009021 IfBuilder if_issame(this);
9022 if_issame.If<HIsStringAndBranch>(element);
9023 if_issame.AndIf<HStringCompareAndBranch>(
9024 element, search_element, Token::EQ_STRICT);
9025 if_issame.Then();
9026 {
9027 Drop(1);
9028 Push(index);
9029 loop.Break();
9030 }
9031 if_issame.End();
9032 }
9033 loop.EndBody();
9034 }
9035 if_isstring.Else();
9036 {
9037 IfBuilder if_isnumber(this);
9038 if_isnumber.If<HIsSmiAndBranch>(search_element);
9039 if_isnumber.OrIf<HCompareMap>(
9040 search_element, isolate()->factory()->heap_number_map());
9041 if_isnumber.Then();
9042 {
9043 HValue* search_number =
9044 AddUncasted<HForceRepresentation>(search_element,
9045 Representation::Double());
9046 LoopBuilder loop(this, context(), direction);
9047 {
9048 HValue* index = loop.BeginBody(initial, terminating, token);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009049 HValue* element = AddUncasted<HLoadKeyed>(elements, index, nullptr,
9050 kind, ALLOW_RETURN_HOLE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009051
9052 IfBuilder if_element_isnumber(this);
9053 if_element_isnumber.If<HIsSmiAndBranch>(element);
9054 if_element_isnumber.OrIf<HCompareMap>(
9055 element, isolate()->factory()->heap_number_map());
9056 if_element_isnumber.Then();
9057 {
9058 HValue* number =
9059 AddUncasted<HForceRepresentation>(element,
9060 Representation::Double());
9061 IfBuilder if_issame(this);
9062 if_issame.If<HCompareNumericAndBranch>(
9063 number, search_number, Token::EQ_STRICT);
9064 if_issame.Then();
9065 {
9066 Drop(1);
9067 Push(index);
9068 loop.Break();
9069 }
9070 if_issame.End();
9071 }
9072 if_element_isnumber.End();
9073 }
9074 loop.EndBody();
9075 }
9076 if_isnumber.Else();
9077 {
9078 LoopBuilder loop(this, context(), direction);
9079 {
9080 HValue* index = loop.BeginBody(initial, terminating, token);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009081 HValue* element = AddUncasted<HLoadKeyed>(elements, index, nullptr,
9082 kind, ALLOW_RETURN_HOLE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009083 IfBuilder if_issame(this);
9084 if_issame.If<HCompareObjectEqAndBranch>(
9085 element, search_element);
9086 if_issame.Then();
9087 {
9088 Drop(1);
9089 Push(index);
9090 loop.Break();
9091 }
9092 if_issame.End();
9093 }
9094 loop.EndBody();
9095 }
9096 if_isnumber.End();
9097 }
9098 if_isstring.End();
9099 }
9100
9101 return Pop();
9102}
9103
9104
9105bool HOptimizedGraphBuilder::TryHandleArrayCall(Call* expr, HValue* function) {
9106 if (!array_function().is_identical_to(expr->target())) {
9107 return false;
9108 }
9109
9110 Handle<AllocationSite> site = expr->allocation_site();
9111 if (site.is_null()) return false;
9112
9113 BuildArrayCall(expr,
9114 expr->arguments()->length(),
9115 function,
9116 site);
9117 return true;
9118}
9119
9120
9121bool HOptimizedGraphBuilder::TryHandleArrayCallNew(CallNew* expr,
9122 HValue* function) {
9123 if (!array_function().is_identical_to(expr->target())) {
9124 return false;
9125 }
9126
9127 BuildArrayCall(expr,
9128 expr->arguments()->length(),
9129 function,
9130 expr->allocation_site());
9131 return true;
9132}
9133
9134
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009135bool HOptimizedGraphBuilder::CanBeFunctionApplyArguments(Call* expr) {
9136 ZoneList<Expression*>* args = expr->arguments();
9137 if (args->length() != 2) return false;
9138 VariableProxy* arg_two = args->at(1)->AsVariableProxy();
9139 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
9140 HValue* arg_two_value = LookupAndMakeLive(arg_two->var());
9141 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
9142 return true;
9143}
9144
9145
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009146void HOptimizedGraphBuilder::VisitCall(Call* expr) {
9147 DCHECK(!HasStackOverflow());
9148 DCHECK(current_block() != NULL);
9149 DCHECK(current_block()->HasPredecessor());
Ben Murdochb0fe1622011-05-05 13:52:32 +01009150 Expression* callee = expr->expression();
9151 int argument_count = expr->arguments()->length() + 1; // Plus receiver.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009152 HInstruction* call = NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +01009153
9154 Property* prop = callee->AsProperty();
9155 if (prop != NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009156 CHECK_ALIVE(VisitForValue(prop->obj()));
9157 HValue* receiver = Top();
Ben Murdochb0fe1622011-05-05 13:52:32 +01009158
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009159 SmallMapList* types;
9160 ComputeReceiverTypes(expr, receiver, &types, zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +01009161
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009162 if (prop->key()->IsPropertyName() && types->length() > 0) {
9163 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
9164 PropertyAccessInfo info(this, LOAD, ToType(types->first()), name);
9165 if (!info.CanAccessAsMonomorphic(types)) {
9166 HandlePolymorphicCallNamed(expr, receiver, types, name);
9167 return;
9168 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01009169 }
9170
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009171 HValue* key = NULL;
9172 if (!prop->key()->IsPropertyName()) {
9173 CHECK_ALIVE(VisitForValue(prop->key()));
9174 key = Pop();
9175 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01009176
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009177 CHECK_ALIVE(PushLoad(prop, receiver, key));
9178 HValue* function = Pop();
Ben Murdochb0fe1622011-05-05 13:52:32 +01009179
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009180 if (FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
Ben Murdochb0fe1622011-05-05 13:52:32 +01009181
Ben Murdochb0fe1622011-05-05 13:52:32 +01009182
Ben Murdochb0fe1622011-05-05 13:52:32 +01009183
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009184 if (function->IsConstant() &&
9185 HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009186 // Push the function under the receiver.
9187 environment()->SetExpressionStackAt(0, function);
9188 Push(receiver);
9189
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009190 Handle<JSFunction> known_function = Handle<JSFunction>::cast(
9191 HConstant::cast(function)->handle(isolate()));
9192 expr->set_target(known_function);
9193
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009194 if (TryIndirectCall(expr)) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009195 CHECK_ALIVE(VisitExpressions(expr->arguments()));
9196
9197 Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009198 if (TryInlineBuiltinMethodCall(expr, known_function, map,
9199 expr->arguments()->length())) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009200 if (FLAG_trace_inlining) {
9201 PrintF("Inlining builtin ");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009202 known_function->ShortPrint();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009203 PrintF("\n");
9204 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01009205 return;
Ben Murdochb0fe1622011-05-05 13:52:32 +01009206 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009207 if (TryInlineApiMethodCall(expr, receiver, types)) return;
Ben Murdochb0fe1622011-05-05 13:52:32 +01009208
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009209 // Wrap the receiver if necessary.
9210 if (NeedsWrappingFor(ToType(types->first()), known_function)) {
9211 // Since HWrapReceiver currently cannot actually wrap numbers and
9212 // strings, use the regular CallFunctionStub for method calls to wrap
9213 // the receiver.
9214 // TODO(verwaest): Support creation of value wrappers directly in
9215 // HWrapReceiver.
9216 call = New<HCallFunction>(
9217 function, argument_count, WRAP_AND_CALL);
9218 } else if (TryInlineCall(expr)) {
9219 return;
Steve Block1e0659c2011-05-24 12:43:12 +01009220 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009221 call = BuildCallConstantFunction(known_function, argument_count);
Steve Block1e0659c2011-05-24 12:43:12 +01009222 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01009223
9224 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009225 ArgumentsAllowedFlag arguments_flag = ARGUMENTS_NOT_ALLOWED;
9226 if (CanBeFunctionApplyArguments(expr) && expr->is_uninitialized()) {
9227 // We have to use EAGER deoptimization here because Deoptimizer::SOFT
9228 // gets ignored by the always-opt flag, which leads to incorrect code.
9229 Add<HDeoptimize>("Insufficient type feedback for call with arguments",
9230 Deoptimizer::EAGER);
9231 arguments_flag = ARGUMENTS_FAKED;
9232 }
9233
9234 // Push the function under the receiver.
9235 environment()->SetExpressionStackAt(0, function);
9236 Push(receiver);
9237
9238 CHECK_ALIVE(VisitExpressions(expr->arguments(), arguments_flag));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009239 CallFunctionFlags flags = receiver->type().IsJSObject()
9240 ? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD;
9241 call = New<HCallFunction>(function, argument_count, flags);
Ben Murdochb0fe1622011-05-05 13:52:32 +01009242 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009243 PushArgumentsFromEnvironment(argument_count);
Ben Murdochb0fe1622011-05-05 13:52:32 +01009244
9245 } else {
Ben Murdoch589d6972011-11-30 16:04:58 +00009246 VariableProxy* proxy = expr->expression()->AsVariableProxy();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009247 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) {
9248 return Bailout(kPossibleDirectCallToEval);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009249 }
9250
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009251 // The function is on the stack in the unoptimized code during
9252 // evaluation of the arguments.
9253 CHECK_ALIVE(VisitForValue(expr->expression()));
9254 HValue* function = Top();
9255 if (expr->global_call()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00009256 Variable* var = proxy->var();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009257 bool known_global_function = false;
Ben Murdochb0fe1622011-05-05 13:52:32 +01009258 // If there is a global property cell for the name at compile time and
9259 // access check is not enabled we assume that the function will not change
9260 // and generate optimized code for calling the function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009261 Handle<GlobalObject> global(current_info()->global_object());
9262 LookupIterator it(global, var->name(),
9263 LookupIterator::OWN_SKIP_INTERCEPTOR);
9264 GlobalPropertyAccess type = LookupGlobalProperty(var, &it, LOAD);
9265 if (type == kUseCell) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009266 known_global_function = expr->ComputeGlobalTarget(global, &it);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009267 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01009268 if (known_global_function) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009269 Add<HCheckValue>(function, expr->target());
9270
9271 // Placeholder for the receiver.
9272 Push(graph()->GetConstantUndefined());
Ben Murdoch257744e2011-11-30 15:57:28 +00009273 CHECK_ALIVE(VisitExpressions(expr->arguments()));
Ben Murdochb0fe1622011-05-05 13:52:32 +01009274
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009275 // Patch the global object on the stack by the expected receiver.
9276 HValue* receiver = ImplicitReceiverFor(function, expr->target());
Ben Murdochb0fe1622011-05-05 13:52:32 +01009277 const int receiver_index = argument_count - 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009278 environment()->SetExpressionStackAt(receiver_index, receiver);
Ben Murdochb0fe1622011-05-05 13:52:32 +01009279
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009280 if (TryInlineBuiltinFunctionCall(expr)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009281 if (FLAG_trace_inlining) {
9282 PrintF("Inlining builtin ");
9283 expr->target()->ShortPrint();
9284 PrintF("\n");
9285 }
9286 return;
9287 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009288 if (TryInlineApiFunctionCall(expr, receiver)) return;
9289 if (TryHandleArrayCall(expr, function)) return;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009290 if (TryInlineCall(expr)) return;
Ben Murdochb0fe1622011-05-05 13:52:32 +01009291
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009292 PushArgumentsFromEnvironment(argument_count);
9293 call = BuildCallConstantFunction(expr->target(), argument_count);
9294 } else {
9295 Push(graph()->GetConstantUndefined());
9296 CHECK_ALIVE(VisitExpressions(expr->arguments()));
9297 PushArgumentsFromEnvironment(argument_count);
9298 call = New<HCallFunction>(function, argument_count);
Ben Murdochb0fe1622011-05-05 13:52:32 +01009299 }
9300
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009301 } else if (expr->IsMonomorphic()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009302 Add<HCheckValue>(function, expr->target());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009303
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009304 Push(graph()->GetConstantUndefined());
9305 CHECK_ALIVE(VisitExpressions(expr->arguments()));
9306
9307 HValue* receiver = ImplicitReceiverFor(function, expr->target());
9308 const int receiver_index = argument_count - 1;
9309 environment()->SetExpressionStackAt(receiver_index, receiver);
9310
9311 if (TryInlineBuiltinFunctionCall(expr)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009312 if (FLAG_trace_inlining) {
9313 PrintF("Inlining builtin ");
9314 expr->target()->ShortPrint();
9315 PrintF("\n");
9316 }
9317 return;
9318 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009319 if (TryInlineApiFunctionCall(expr, receiver)) return;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009320
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009321 if (TryInlineCall(expr)) return;
9322
9323 call = PreProcessCall(New<HInvokeFunction>(
9324 function, expr->target(), argument_count));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009325
Ben Murdochb0fe1622011-05-05 13:52:32 +01009326 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009327 Push(graph()->GetConstantUndefined());
9328 CHECK_ALIVE(VisitExpressions(expr->arguments()));
9329 PushArgumentsFromEnvironment(argument_count);
9330 call = New<HCallFunction>(function, argument_count);
Ben Murdochb0fe1622011-05-05 13:52:32 +01009331 }
9332 }
9333
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009334 Drop(1); // Drop the function.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009335 return ast_context()->ReturnInstruction(call, expr->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +01009336}
9337
9338
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009339void HOptimizedGraphBuilder::BuildInlinedCallArray(
9340 Expression* expression,
9341 int argument_count,
9342 Handle<AllocationSite> site) {
9343 DCHECK(!site.is_null());
9344 DCHECK(argument_count >= 0 && argument_count <= 1);
9345 NoObservableSideEffectsScope no_effects(this);
9346
9347 // We should at least have the constructor on the expression stack.
9348 HValue* constructor = environment()->ExpressionStackAt(argument_count);
9349
9350 // Register on the site for deoptimization if the transition feedback changes.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009351 AllocationSite::RegisterForDeoptOnTransitionChange(site, top_info());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009352 ElementsKind kind = site->GetElementsKind();
9353 HInstruction* site_instruction = Add<HConstant>(site);
9354
9355 // In the single constant argument case, we may have to adjust elements kind
9356 // to avoid creating a packed non-empty array.
9357 if (argument_count == 1 && !IsHoleyElementsKind(kind)) {
9358 HValue* argument = environment()->Top();
9359 if (argument->IsConstant()) {
9360 HConstant* constant_argument = HConstant::cast(argument);
9361 DCHECK(constant_argument->HasSmiValue());
9362 int constant_array_size = constant_argument->Integer32Value();
9363 if (constant_array_size != 0) {
9364 kind = GetHoleyElementsKind(kind);
9365 }
9366 }
9367 }
9368
9369 // Build the array.
9370 JSArrayBuilder array_builder(this,
9371 kind,
9372 site_instruction,
9373 constructor,
9374 DISABLE_ALLOCATION_SITES);
9375 HValue* new_object = argument_count == 0
9376 ? array_builder.AllocateEmptyArray()
9377 : BuildAllocateArrayFromLength(&array_builder, Top());
9378
9379 int args_to_drop = argument_count + (expression->IsCall() ? 2 : 1);
9380 Drop(args_to_drop);
9381 ast_context()->ReturnValue(new_object);
9382}
9383
9384
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009385// Checks whether allocation using the given constructor can be inlined.
9386static bool IsAllocationInlineable(Handle<JSFunction> constructor) {
9387 return constructor->has_initial_map() &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009388 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE &&
9389 constructor->initial_map()->instance_size() < HAllocate::kMaxInlineSize &&
9390 constructor->initial_map()->InitialPropertiesLength() == 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009391}
9392
9393
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009394bool HOptimizedGraphBuilder::IsCallArrayInlineable(
9395 int argument_count,
9396 Handle<AllocationSite> site) {
9397 Handle<JSFunction> caller = current_info()->closure();
9398 Handle<JSFunction> target = array_function();
9399 // We should have the function plus array arguments on the environment stack.
9400 DCHECK(environment()->length() >= (argument_count + 1));
9401 DCHECK(!site.is_null());
9402
9403 bool inline_ok = false;
9404 if (site->CanInlineCall()) {
9405 // We also want to avoid inlining in certain 1 argument scenarios.
9406 if (argument_count == 1) {
9407 HValue* argument = Top();
9408 if (argument->IsConstant()) {
9409 // Do not inline if the constant length argument is not a smi or
9410 // outside the valid range for unrolled loop initialization.
9411 HConstant* constant_argument = HConstant::cast(argument);
9412 if (constant_argument->HasSmiValue()) {
9413 int value = constant_argument->Integer32Value();
9414 inline_ok = value >= 0 && value <= kElementLoopUnrollThreshold;
9415 if (!inline_ok) {
9416 TraceInline(target, caller,
9417 "Constant length outside of valid inlining range.");
9418 }
9419 }
9420 } else {
9421 TraceInline(target, caller,
9422 "Dont inline [new] Array(n) where n isn't constant.");
9423 }
9424 } else if (argument_count == 0) {
9425 inline_ok = true;
9426 } else {
9427 TraceInline(target, caller, "Too many arguments to inline.");
9428 }
9429 } else {
9430 TraceInline(target, caller, "AllocationSite requested no inlining.");
9431 }
9432
9433 if (inline_ok) {
9434 TraceInline(target, caller, NULL);
9435 }
9436 return inline_ok;
9437}
9438
9439
9440void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
9441 DCHECK(!HasStackOverflow());
9442 DCHECK(current_block() != NULL);
9443 DCHECK(current_block()->HasPredecessor());
9444 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009445 int argument_count = expr->arguments()->length() + 1; // Plus constructor.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009446 Factory* factory = isolate()->factory();
9447
9448 // The constructor function is on the stack in the unoptimized code
9449 // during evaluation of the arguments.
9450 CHECK_ALIVE(VisitForValue(expr->expression()));
9451 HValue* function = Top();
9452 CHECK_ALIVE(VisitExpressions(expr->arguments()));
Steve Block1e0659c2011-05-24 12:43:12 +01009453
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009454 if (FLAG_inline_construct &&
9455 expr->IsMonomorphic() &&
9456 IsAllocationInlineable(expr->target())) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009457 Handle<JSFunction> constructor = expr->target();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009458 HValue* check = Add<HCheckValue>(function, constructor);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009459
9460 // Force completion of inobject slack tracking before generating
9461 // allocation code to finalize instance size.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009462 if (constructor->IsInobjectSlackTrackingInProgress()) {
9463 constructor->CompleteInobjectSlackTracking();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009464 }
9465
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009466 // Calculate instance size from initial map of constructor.
9467 DCHECK(constructor->has_initial_map());
9468 Handle<Map> initial_map(constructor->initial_map());
9469 int instance_size = initial_map->instance_size();
9470 DCHECK(initial_map->InitialPropertiesLength() == 0);
9471
9472 // Allocate an instance of the implicit receiver object.
9473 HValue* size_in_bytes = Add<HConstant>(instance_size);
9474 HAllocationMode allocation_mode;
9475 if (FLAG_pretenuring_call_new) {
9476 if (FLAG_allocation_site_pretenuring) {
9477 // Try to use pretenuring feedback.
9478 Handle<AllocationSite> allocation_site = expr->allocation_site();
9479 allocation_mode = HAllocationMode(allocation_site);
9480 // Take a dependency on allocation site.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009481 AllocationSite::RegisterForDeoptOnTenureChange(allocation_site,
9482 top_info());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009483 }
9484 }
9485
9486 HAllocate* receiver = BuildAllocate(
9487 size_in_bytes, HType::JSObject(), JS_OBJECT_TYPE, allocation_mode);
9488 receiver->set_known_initial_map(initial_map);
9489
9490 // Initialize map and fields of the newly allocated object.
9491 { NoObservableSideEffectsScope no_effects(this);
9492 DCHECK(initial_map->instance_type() == JS_OBJECT_TYPE);
9493 Add<HStoreNamedField>(receiver,
9494 HObjectAccess::ForMapAndOffset(initial_map, JSObject::kMapOffset),
9495 Add<HConstant>(initial_map));
9496 HValue* empty_fixed_array = Add<HConstant>(factory->empty_fixed_array());
9497 Add<HStoreNamedField>(receiver,
9498 HObjectAccess::ForMapAndOffset(initial_map,
9499 JSObject::kPropertiesOffset),
9500 empty_fixed_array);
9501 Add<HStoreNamedField>(receiver,
9502 HObjectAccess::ForMapAndOffset(initial_map,
9503 JSObject::kElementsOffset),
9504 empty_fixed_array);
9505 if (initial_map->inobject_properties() != 0) {
9506 HConstant* undefined = graph()->GetConstantUndefined();
9507 for (int i = 0; i < initial_map->inobject_properties(); i++) {
9508 int property_offset = initial_map->GetInObjectPropertyOffset(i);
9509 Add<HStoreNamedField>(receiver,
9510 HObjectAccess::ForMapAndOffset(initial_map, property_offset),
9511 undefined);
9512 }
9513 }
9514 }
9515
9516 // Replace the constructor function with a newly allocated receiver using
9517 // the index of the receiver from the top of the expression stack.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009518 const int receiver_index = argument_count - 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009519 DCHECK(environment()->ExpressionStackAt(receiver_index) == function);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009520 environment()->SetExpressionStackAt(receiver_index, receiver);
9521
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009522 if (TryInlineConstruct(expr, receiver)) {
9523 // Inlining worked, add a dependency on the initial map to make sure that
9524 // this code is deoptimized whenever the initial map of the constructor
9525 // changes.
9526 Map::AddDependentCompilationInfo(
9527 initial_map, DependentCode::kInitialMapChangedGroup, top_info());
9528 return;
9529 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009530
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009531 // TODO(mstarzinger): For now we remove the previous HAllocate and all
9532 // corresponding instructions and instead add HPushArguments for the
9533 // arguments in case inlining failed. What we actually should do is for
9534 // inlining to try to build a subgraph without mutating the parent graph.
9535 HInstruction* instr = current_block()->last();
9536 do {
9537 HInstruction* prev_instr = instr->previous();
9538 instr->DeleteAndReplaceWith(NULL);
9539 instr = prev_instr;
9540 } while (instr != check);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009541 environment()->SetExpressionStackAt(receiver_index, function);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009542 HInstruction* call =
9543 PreProcessCall(New<HCallNew>(function, argument_count));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009544 return ast_context()->ReturnInstruction(call, expr->id());
9545 } else {
9546 // The constructor function is both an operand to the instruction and an
9547 // argument to the construct call.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009548 if (TryHandleArrayCallNew(expr, function)) return;
9549
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009550 HInstruction* call =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009551 PreProcessCall(New<HCallNew>(function, argument_count));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009552 return ast_context()->ReturnInstruction(call, expr->id());
9553 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01009554}
9555
9556
9557// Support for generating inlined runtime functions.
9558
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009559// Lookup table for generators for runtime calls that are generated inline.
9560// Elements of the table are member pointers to functions of
9561// HOptimizedGraphBuilder.
Ben Murdochb0fe1622011-05-05 13:52:32 +01009562#define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009563 &HOptimizedGraphBuilder::Generate##Name,
Ben Murdochb0fe1622011-05-05 13:52:32 +01009564
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009565const HOptimizedGraphBuilder::InlineFunctionGenerator
9566 HOptimizedGraphBuilder::kInlineFunctionGenerators[] = {
Ben Murdochb0fe1622011-05-05 13:52:32 +01009567 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009568 INLINE_OPTIMIZED_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
Ben Murdochb0fe1622011-05-05 13:52:32 +01009569};
9570#undef INLINE_FUNCTION_GENERATOR_ADDRESS
9571
9572
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009573template <class ViewClass>
9574void HGraphBuilder::BuildArrayBufferViewInitialization(
9575 HValue* obj,
9576 HValue* buffer,
9577 HValue* byte_offset,
9578 HValue* byte_length) {
9579
9580 for (int offset = ViewClass::kSize;
9581 offset < ViewClass::kSizeWithInternalFields;
9582 offset += kPointerSize) {
9583 Add<HStoreNamedField>(obj,
9584 HObjectAccess::ForObservableJSObjectOffset(offset),
9585 graph()->GetConstant0());
9586 }
9587
9588 Add<HStoreNamedField>(
9589 obj,
9590 HObjectAccess::ForJSArrayBufferViewByteOffset(),
9591 byte_offset);
9592 Add<HStoreNamedField>(
9593 obj,
9594 HObjectAccess::ForJSArrayBufferViewByteLength(),
9595 byte_length);
9596
9597 if (buffer != NULL) {
9598 Add<HStoreNamedField>(
9599 obj,
9600 HObjectAccess::ForJSArrayBufferViewBuffer(), buffer);
9601 HObjectAccess weak_first_view_access =
9602 HObjectAccess::ForJSArrayBufferWeakFirstView();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009603 Add<HStoreNamedField>(
9604 obj, HObjectAccess::ForJSArrayBufferViewWeakNext(),
9605 Add<HLoadNamedField>(buffer, nullptr, weak_first_view_access));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009606 Add<HStoreNamedField>(buffer, weak_first_view_access, obj);
9607 } else {
9608 Add<HStoreNamedField>(
9609 obj,
9610 HObjectAccess::ForJSArrayBufferViewBuffer(),
9611 Add<HConstant>(static_cast<int32_t>(0)));
9612 Add<HStoreNamedField>(obj,
9613 HObjectAccess::ForJSArrayBufferViewWeakNext(),
9614 graph()->GetConstantUndefined());
9615 }
9616}
9617
9618
9619void HOptimizedGraphBuilder::GenerateDataViewInitialize(
9620 CallRuntime* expr) {
9621 ZoneList<Expression*>* arguments = expr->arguments();
9622
9623 DCHECK(arguments->length()== 4);
9624 CHECK_ALIVE(VisitForValue(arguments->at(0)));
9625 HValue* obj = Pop();
9626
9627 CHECK_ALIVE(VisitForValue(arguments->at(1)));
9628 HValue* buffer = Pop();
9629
9630 CHECK_ALIVE(VisitForValue(arguments->at(2)));
9631 HValue* byte_offset = Pop();
9632
9633 CHECK_ALIVE(VisitForValue(arguments->at(3)));
9634 HValue* byte_length = Pop();
9635
9636 {
9637 NoObservableSideEffectsScope scope(this);
9638 BuildArrayBufferViewInitialization<JSDataView>(
9639 obj, buffer, byte_offset, byte_length);
9640 }
9641}
9642
9643
9644static Handle<Map> TypedArrayMap(Isolate* isolate,
9645 ExternalArrayType array_type,
9646 ElementsKind target_kind) {
9647 Handle<Context> native_context = isolate->native_context();
9648 Handle<JSFunction> fun;
9649 switch (array_type) {
9650#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
9651 case kExternal##Type##Array: \
9652 fun = Handle<JSFunction>(native_context->type##_array_fun()); \
9653 break;
9654
9655 TYPED_ARRAYS(TYPED_ARRAY_CASE)
9656#undef TYPED_ARRAY_CASE
9657 }
9658 Handle<Map> map(fun->initial_map());
9659 return Map::AsElementsKind(map, target_kind);
9660}
9661
9662
9663HValue* HOptimizedGraphBuilder::BuildAllocateExternalElements(
9664 ExternalArrayType array_type,
9665 bool is_zero_byte_offset,
9666 HValue* buffer, HValue* byte_offset, HValue* length) {
9667 Handle<Map> external_array_map(
9668 isolate()->heap()->MapForExternalArrayType(array_type));
9669
9670 // The HForceRepresentation is to prevent possible deopt on int-smi
9671 // conversion after allocation but before the new object fields are set.
9672 length = AddUncasted<HForceRepresentation>(length, Representation::Smi());
9673 HValue* elements =
9674 Add<HAllocate>(
9675 Add<HConstant>(ExternalArray::kAlignedSize),
9676 HType::HeapObject(),
9677 NOT_TENURED,
9678 external_array_map->instance_type());
9679
9680 AddStoreMapConstant(elements, external_array_map);
9681 Add<HStoreNamedField>(elements,
9682 HObjectAccess::ForFixedArrayLength(), length);
9683
9684 HValue* backing_store = Add<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009685 buffer, nullptr, HObjectAccess::ForJSArrayBufferBackingStore());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009686
9687 HValue* typed_array_start;
9688 if (is_zero_byte_offset) {
9689 typed_array_start = backing_store;
9690 } else {
9691 HInstruction* external_pointer =
9692 AddUncasted<HAdd>(backing_store, byte_offset);
9693 // Arguments are checked prior to call to TypedArrayInitialize,
9694 // including byte_offset.
9695 external_pointer->ClearFlag(HValue::kCanOverflow);
9696 typed_array_start = external_pointer;
9697 }
9698
9699 Add<HStoreNamedField>(elements,
9700 HObjectAccess::ForExternalArrayExternalPointer(),
9701 typed_array_start);
9702
9703 return elements;
9704}
9705
9706
9707HValue* HOptimizedGraphBuilder::BuildAllocateFixedTypedArray(
9708 ExternalArrayType array_type, size_t element_size,
9709 ElementsKind fixed_elements_kind,
9710 HValue* byte_length, HValue* length) {
9711 STATIC_ASSERT(
9712 (FixedTypedArrayBase::kHeaderSize & kObjectAlignmentMask) == 0);
9713 HValue* total_size;
9714
9715 // if fixed array's elements are not aligned to object's alignment,
9716 // we need to align the whole array to object alignment.
9717 if (element_size % kObjectAlignment != 0) {
9718 total_size = BuildObjectSizeAlignment(
9719 byte_length, FixedTypedArrayBase::kHeaderSize);
9720 } else {
9721 total_size = AddUncasted<HAdd>(byte_length,
9722 Add<HConstant>(FixedTypedArrayBase::kHeaderSize));
9723 total_size->ClearFlag(HValue::kCanOverflow);
9724 }
9725
9726 // The HForceRepresentation is to prevent possible deopt on int-smi
9727 // conversion after allocation but before the new object fields are set.
9728 length = AddUncasted<HForceRepresentation>(length, Representation::Smi());
9729 Handle<Map> fixed_typed_array_map(
9730 isolate()->heap()->MapForFixedTypedArray(array_type));
9731 HValue* elements =
9732 Add<HAllocate>(total_size, HType::HeapObject(),
9733 NOT_TENURED, fixed_typed_array_map->instance_type());
9734 AddStoreMapConstant(elements, fixed_typed_array_map);
9735
9736 Add<HStoreNamedField>(elements,
9737 HObjectAccess::ForFixedArrayLength(),
9738 length);
9739
9740 HValue* filler = Add<HConstant>(static_cast<int32_t>(0));
9741
9742 {
9743 LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement);
9744
9745 HValue* key = builder.BeginBody(
9746 Add<HConstant>(static_cast<int32_t>(0)),
9747 length, Token::LT);
9748 Add<HStoreKeyed>(elements, key, filler, fixed_elements_kind);
9749
9750 builder.EndBody();
9751 }
9752 return elements;
9753}
9754
9755
9756void HOptimizedGraphBuilder::GenerateTypedArrayInitialize(
9757 CallRuntime* expr) {
9758 ZoneList<Expression*>* arguments = expr->arguments();
9759
9760 static const int kObjectArg = 0;
9761 static const int kArrayIdArg = 1;
9762 static const int kBufferArg = 2;
9763 static const int kByteOffsetArg = 3;
9764 static const int kByteLengthArg = 4;
9765 static const int kArgsLength = 5;
9766 DCHECK(arguments->length() == kArgsLength);
9767
9768
9769 CHECK_ALIVE(VisitForValue(arguments->at(kObjectArg)));
9770 HValue* obj = Pop();
9771
9772 if (arguments->at(kArrayIdArg)->IsLiteral()) {
9773 // This should never happen in real use, but can happen when fuzzing.
9774 // Just bail out.
9775 Bailout(kNeedSmiLiteral);
9776 return;
9777 }
9778 Handle<Object> value =
9779 static_cast<Literal*>(arguments->at(kArrayIdArg))->value();
9780 if (!value->IsSmi()) {
9781 // This should never happen in real use, but can happen when fuzzing.
9782 // Just bail out.
9783 Bailout(kNeedSmiLiteral);
9784 return;
9785 }
9786 int array_id = Smi::cast(*value)->value();
9787
9788 HValue* buffer;
9789 if (!arguments->at(kBufferArg)->IsNullLiteral()) {
9790 CHECK_ALIVE(VisitForValue(arguments->at(kBufferArg)));
9791 buffer = Pop();
9792 } else {
9793 buffer = NULL;
9794 }
9795
9796 HValue* byte_offset;
9797 bool is_zero_byte_offset;
9798
9799 if (arguments->at(kByteOffsetArg)->IsLiteral()
9800 && Smi::FromInt(0) ==
9801 *static_cast<Literal*>(arguments->at(kByteOffsetArg))->value()) {
9802 byte_offset = Add<HConstant>(static_cast<int32_t>(0));
9803 is_zero_byte_offset = true;
9804 } else {
9805 CHECK_ALIVE(VisitForValue(arguments->at(kByteOffsetArg)));
9806 byte_offset = Pop();
9807 is_zero_byte_offset = false;
9808 DCHECK(buffer != NULL);
9809 }
9810
9811 CHECK_ALIVE(VisitForValue(arguments->at(kByteLengthArg)));
9812 HValue* byte_length = Pop();
9813
9814 NoObservableSideEffectsScope scope(this);
9815 IfBuilder byte_offset_smi(this);
9816
9817 if (!is_zero_byte_offset) {
9818 byte_offset_smi.If<HIsSmiAndBranch>(byte_offset);
9819 byte_offset_smi.Then();
9820 }
9821
9822 ExternalArrayType array_type =
9823 kExternalInt8Array; // Bogus initialization.
9824 size_t element_size = 1; // Bogus initialization.
9825 ElementsKind external_elements_kind = // Bogus initialization.
9826 EXTERNAL_INT8_ELEMENTS;
9827 ElementsKind fixed_elements_kind = // Bogus initialization.
9828 INT8_ELEMENTS;
9829 Runtime::ArrayIdToTypeAndSize(array_id,
9830 &array_type,
9831 &external_elements_kind,
9832 &fixed_elements_kind,
9833 &element_size);
9834
9835
9836 { // byte_offset is Smi.
9837 BuildArrayBufferViewInitialization<JSTypedArray>(
9838 obj, buffer, byte_offset, byte_length);
9839
9840
9841 HInstruction* length = AddUncasted<HDiv>(byte_length,
9842 Add<HConstant>(static_cast<int32_t>(element_size)));
9843
9844 Add<HStoreNamedField>(obj,
9845 HObjectAccess::ForJSTypedArrayLength(),
9846 length);
9847
9848 HValue* elements;
9849 if (buffer != NULL) {
9850 elements = BuildAllocateExternalElements(
9851 array_type, is_zero_byte_offset, buffer, byte_offset, length);
9852 Handle<Map> obj_map = TypedArrayMap(
9853 isolate(), array_type, external_elements_kind);
9854 AddStoreMapConstant(obj, obj_map);
9855 } else {
9856 DCHECK(is_zero_byte_offset);
9857 elements = BuildAllocateFixedTypedArray(
9858 array_type, element_size, fixed_elements_kind,
9859 byte_length, length);
9860 }
9861 Add<HStoreNamedField>(
9862 obj, HObjectAccess::ForElementsPointer(), elements);
9863 }
9864
9865 if (!is_zero_byte_offset) {
9866 byte_offset_smi.Else();
9867 { // byte_offset is not Smi.
9868 Push(obj);
9869 CHECK_ALIVE(VisitForValue(arguments->at(kArrayIdArg)));
9870 Push(buffer);
9871 Push(byte_offset);
9872 Push(byte_length);
9873 PushArgumentsFromEnvironment(kArgsLength);
9874 Add<HCallRuntime>(expr->name(), expr->function(), kArgsLength);
9875 }
9876 }
9877 byte_offset_smi.End();
9878}
9879
9880
9881void HOptimizedGraphBuilder::GenerateMaxSmi(CallRuntime* expr) {
9882 DCHECK(expr->arguments()->length() == 0);
9883 HConstant* max_smi = New<HConstant>(static_cast<int32_t>(Smi::kMaxValue));
9884 return ast_context()->ReturnInstruction(max_smi, expr->id());
9885}
9886
9887
9888void HOptimizedGraphBuilder::GenerateTypedArrayMaxSizeInHeap(
9889 CallRuntime* expr) {
9890 DCHECK(expr->arguments()->length() == 0);
9891 HConstant* result = New<HConstant>(static_cast<int32_t>(
9892 FLAG_typed_array_max_size_in_heap));
9893 return ast_context()->ReturnInstruction(result, expr->id());
9894}
9895
9896
9897void HOptimizedGraphBuilder::GenerateArrayBufferGetByteLength(
9898 CallRuntime* expr) {
9899 DCHECK(expr->arguments()->length() == 1);
9900 CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
9901 HValue* buffer = Pop();
9902 HInstruction* result = New<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009903 buffer, nullptr, HObjectAccess::ForJSArrayBufferByteLength());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009904 return ast_context()->ReturnInstruction(result, expr->id());
9905}
9906
9907
9908void HOptimizedGraphBuilder::GenerateArrayBufferViewGetByteLength(
9909 CallRuntime* expr) {
9910 DCHECK(expr->arguments()->length() == 1);
9911 CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
9912 HValue* buffer = Pop();
9913 HInstruction* result = New<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009914 buffer, nullptr, HObjectAccess::ForJSArrayBufferViewByteLength());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009915 return ast_context()->ReturnInstruction(result, expr->id());
9916}
9917
9918
9919void HOptimizedGraphBuilder::GenerateArrayBufferViewGetByteOffset(
9920 CallRuntime* expr) {
9921 DCHECK(expr->arguments()->length() == 1);
9922 CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
9923 HValue* buffer = Pop();
9924 HInstruction* result = New<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009925 buffer, nullptr, HObjectAccess::ForJSArrayBufferViewByteOffset());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009926 return ast_context()->ReturnInstruction(result, expr->id());
9927}
9928
9929
9930void HOptimizedGraphBuilder::GenerateTypedArrayGetLength(
9931 CallRuntime* expr) {
9932 DCHECK(expr->arguments()->length() == 1);
9933 CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
9934 HValue* buffer = Pop();
9935 HInstruction* result = New<HLoadNamedField>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009936 buffer, nullptr, HObjectAccess::ForJSTypedArrayLength());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009937 return ast_context()->ReturnInstruction(result, expr->id());
9938}
9939
9940
9941void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
9942 DCHECK(!HasStackOverflow());
9943 DCHECK(current_block() != NULL);
9944 DCHECK(current_block()->HasPredecessor());
Ben Murdochb0fe1622011-05-05 13:52:32 +01009945 if (expr->is_jsruntime()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009946 return Bailout(kCallToAJavaScriptRuntimeFunction);
Ben Murdochb0fe1622011-05-05 13:52:32 +01009947 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009948
Steve Block44f0eee2011-05-26 01:26:41 +01009949 const Runtime::Function* function = expr->function();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009950 DCHECK(function != NULL);
9951
9952 if (function->intrinsic_type == Runtime::INLINE ||
9953 function->intrinsic_type == Runtime::INLINE_OPTIMIZED) {
9954 DCHECK(expr->name()->length() > 0);
9955 DCHECK(expr->name()->Get(0) == '_');
Ben Murdochb0fe1622011-05-05 13:52:32 +01009956 // Call to an inline function.
9957 int lookup_index = static_cast<int>(function->function_id) -
9958 static_cast<int>(Runtime::kFirstInlineFunction);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009959 DCHECK(lookup_index >= 0);
9960 DCHECK(static_cast<size_t>(lookup_index) <
9961 arraysize(kInlineFunctionGenerators));
Ben Murdochb0fe1622011-05-05 13:52:32 +01009962 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index];
9963
9964 // Call the inline code generator using the pointer-to-member.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009965 (this->*generator)(expr);
Ben Murdochb0fe1622011-05-05 13:52:32 +01009966 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009967 DCHECK(function->intrinsic_type == Runtime::RUNTIME);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009968 Handle<String> name = expr->name();
9969 int argument_count = expr->arguments()->length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009970 CHECK_ALIVE(VisitExpressions(expr->arguments()));
9971 PushArgumentsFromEnvironment(argument_count);
9972 HCallRuntime* call = New<HCallRuntime>(name, function,
9973 argument_count);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009974 return ast_context()->ReturnInstruction(call, expr->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +01009975 }
9976}
9977
9978
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009979void HOptimizedGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
9980 DCHECK(!HasStackOverflow());
9981 DCHECK(current_block() != NULL);
9982 DCHECK(current_block()->HasPredecessor());
Ben Murdoch257744e2011-11-30 15:57:28 +00009983 switch (expr->op()) {
9984 case Token::DELETE: return VisitDelete(expr);
9985 case Token::VOID: return VisitVoid(expr);
9986 case Token::TYPEOF: return VisitTypeof(expr);
Ben Murdoch257744e2011-11-30 15:57:28 +00009987 case Token::NOT: return VisitNot(expr);
9988 default: UNREACHABLE();
9989 }
9990}
9991
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009992
9993void HOptimizedGraphBuilder::VisitDelete(UnaryOperation* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +00009994 Property* prop = expr->expression()->AsProperty();
Ben Murdoch589d6972011-11-30 16:04:58 +00009995 VariableProxy* proxy = expr->expression()->AsVariableProxy();
9996 if (prop != NULL) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009997 CHECK_ALIVE(VisitForValue(prop->obj()));
9998 CHECK_ALIVE(VisitForValue(prop->key()));
9999 HValue* key = Pop();
10000 HValue* obj = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010001 HValue* function = AddLoadJSBuiltin(Builtins::DELETE);
10002 Add<HPushArguments>(obj, key, Add<HConstant>(function_strict_mode()));
10003 // TODO(olivf) InvokeFunction produces a check for the parameter count,
10004 // even though we are certain to pass the correct number of arguments here.
10005 HInstruction* instr = New<HInvokeFunction>(function, 3);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010006 return ast_context()->ReturnInstruction(instr, expr->id());
Ben Murdoch589d6972011-11-30 16:04:58 +000010007 } else if (proxy != NULL) {
10008 Variable* var = proxy->var();
10009 if (var->IsUnallocated()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010010 Bailout(kDeleteWithGlobalVariable);
Ben Murdoch589d6972011-11-30 16:04:58 +000010011 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
10012 // Result of deleting non-global variables is false. 'this' is not
10013 // really a variable, though we implement it as one. The
10014 // subexpression does not have side effects.
10015 HValue* value = var->is_this()
10016 ? graph()->GetConstantTrue()
10017 : graph()->GetConstantFalse();
10018 return ast_context()->ReturnValue(value);
10019 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010020 Bailout(kDeleteWithNonGlobalVariable);
Ben Murdoch589d6972011-11-30 16:04:58 +000010021 }
Steve Block44f0eee2011-05-26 01:26:41 +010010022 } else {
Ben Murdoch589d6972011-11-30 16:04:58 +000010023 // Result of deleting non-property, non-variable reference is true.
10024 // Evaluate the subexpression for side effects.
10025 CHECK_ALIVE(VisitForEffect(expr->expression()));
10026 return ast_context()->ReturnValue(graph()->GetConstantTrue());
Ben Murdochb0fe1622011-05-05 13:52:32 +010010027 }
10028}
10029
10030
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010031void HOptimizedGraphBuilder::VisitVoid(UnaryOperation* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +000010032 CHECK_ALIVE(VisitForEffect(expr->expression()));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010033 return ast_context()->ReturnValue(graph()->GetConstantUndefined());
Ben Murdoch257744e2011-11-30 15:57:28 +000010034}
10035
10036
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010037void HOptimizedGraphBuilder::VisitTypeof(UnaryOperation* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +000010038 CHECK_ALIVE(VisitForTypeOf(expr->expression()));
10039 HValue* value = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010040 HInstruction* instr = New<HTypeof>(value);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010041 return ast_context()->ReturnInstruction(instr, expr->id());
Ben Murdoch257744e2011-11-30 15:57:28 +000010042}
10043
10044
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010045void HOptimizedGraphBuilder::VisitNot(UnaryOperation* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +000010046 if (ast_context()->IsTest()) {
10047 TestContext* context = TestContext::cast(ast_context());
10048 VisitForControl(expr->expression(),
10049 context->if_false(),
10050 context->if_true());
10051 return;
10052 }
10053
10054 if (ast_context()->IsEffect()) {
10055 VisitForEffect(expr->expression());
10056 return;
10057 }
10058
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010059 DCHECK(ast_context()->IsValue());
Ben Murdoch257744e2011-11-30 15:57:28 +000010060 HBasicBlock* materialize_false = graph()->CreateBasicBlock();
10061 HBasicBlock* materialize_true = graph()->CreateBasicBlock();
10062 CHECK_BAILOUT(VisitForControl(expr->expression(),
10063 materialize_false,
10064 materialize_true));
10065
10066 if (materialize_false->HasPredecessor()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010067 materialize_false->SetJoinId(expr->MaterializeFalseId());
Ben Murdoch257744e2011-11-30 15:57:28 +000010068 set_current_block(materialize_false);
10069 Push(graph()->GetConstantFalse());
10070 } else {
10071 materialize_false = NULL;
10072 }
10073
10074 if (materialize_true->HasPredecessor()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010075 materialize_true->SetJoinId(expr->MaterializeTrueId());
Ben Murdoch257744e2011-11-30 15:57:28 +000010076 set_current_block(materialize_true);
10077 Push(graph()->GetConstantTrue());
10078 } else {
10079 materialize_true = NULL;
10080 }
10081
10082 HBasicBlock* join =
10083 CreateJoin(materialize_false, materialize_true, expr->id());
10084 set_current_block(join);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010085 if (join != NULL) return ast_context()->ReturnValue(Pop());
Ben Murdoch257744e2011-11-30 15:57:28 +000010086}
10087
10088
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010089HInstruction* HOptimizedGraphBuilder::BuildIncrement(
10090 bool returns_original_input,
10091 CountOperation* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +000010092 // The input to the count operation is on top of the expression stack.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010093 Representation rep = Representation::FromType(expr->type());
10094 if (rep.IsNone() || rep.IsTagged()) {
10095 rep = Representation::Smi();
Ben Murdoch257744e2011-11-30 15:57:28 +000010096 }
10097
10098 if (returns_original_input) {
10099 // We need an explicit HValue representing ToNumber(input). The
10100 // actual HChange instruction we need is (sometimes) added in a later
10101 // phase, so it is not available now to be used as an input to HAdd and
10102 // as the return value.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010103 HInstruction* number_input = AddUncasted<HForceRepresentation>(Pop(), rep);
10104 if (!rep.IsDouble()) {
10105 number_input->SetFlag(HInstruction::kFlexibleRepresentation);
10106 number_input->SetFlag(HInstruction::kCannotBeTagged);
10107 }
Ben Murdoch257744e2011-11-30 15:57:28 +000010108 Push(number_input);
10109 }
10110
10111 // The addition has no side effects, so we do not need
10112 // to simulate the expression stack after this instruction.
10113 // Any later failures deopt to the load of the input or earlier.
10114 HConstant* delta = (expr->op() == Token::INC)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010115 ? graph()->GetConstant1()
10116 : graph()->GetConstantMinus1();
10117 HInstruction* instr = AddUncasted<HAdd>(Top(), delta);
10118 if (instr->IsAdd()) {
10119 HAdd* add = HAdd::cast(instr);
10120 add->set_observed_input_representation(1, rep);
10121 add->set_observed_input_representation(2, Representation::Smi());
10122 }
10123 instr->SetFlag(HInstruction::kCannotBeTagged);
10124 instr->ClearAllSideEffects();
Ben Murdochb0fe1622011-05-05 13:52:32 +010010125 return instr;
10126}
10127
10128
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010129void HOptimizedGraphBuilder::BuildStoreForEffect(Expression* expr,
10130 Property* prop,
10131 BailoutId ast_id,
10132 BailoutId return_id,
10133 HValue* object,
10134 HValue* key,
10135 HValue* value) {
10136 EffectContext for_effect(this);
10137 Push(object);
10138 if (key != NULL) Push(key);
10139 Push(value);
10140 BuildStore(expr, prop, ast_id, return_id);
10141}
10142
10143
10144void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
10145 DCHECK(!HasStackOverflow());
10146 DCHECK(current_block() != NULL);
10147 DCHECK(current_block()->HasPredecessor());
10148 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
Ben Murdoch8b112d22011-06-08 16:22:53 +010010149 Expression* target = expr->expression();
Ben Murdochb0fe1622011-05-05 13:52:32 +010010150 VariableProxy* proxy = target->AsVariableProxy();
Ben Murdochb0fe1622011-05-05 13:52:32 +010010151 Property* prop = target->AsProperty();
Ben Murdoch589d6972011-11-30 16:04:58 +000010152 if (proxy == NULL && prop == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010153 return Bailout(kInvalidLhsInCountOperation);
Ben Murdoch257744e2011-11-30 15:57:28 +000010154 }
10155
10156 // Match the full code generator stack by simulating an extra stack
10157 // element for postfix operations in a non-effect context. The return
10158 // value is ToNumber(input).
10159 bool returns_original_input =
10160 expr->is_postfix() && !ast_context()->IsEffect();
10161 HValue* input = NULL; // ToNumber(original_input).
10162 HValue* after = NULL; // The result after incrementing or decrementing.
Ben Murdochb0fe1622011-05-05 13:52:32 +010010163
Ben Murdoch589d6972011-11-30 16:04:58 +000010164 if (proxy != NULL) {
10165 Variable* var = proxy->var();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010166 if (var->mode() == CONST_LEGACY) {
10167 return Bailout(kUnsupportedCountOperationWithConst);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010168 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010169 if (var->mode() == CONST) {
10170 return Bailout(kNonInitializerAssignmentToConst);
10171 }
Ben Murdoch257744e2011-11-30 15:57:28 +000010172 // Argument of the count operation is a variable, not a property.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010173 DCHECK(prop == NULL);
Ben Murdoch257744e2011-11-30 15:57:28 +000010174 CHECK_ALIVE(VisitForValue(target));
Ben Murdochb0fe1622011-05-05 13:52:32 +010010175
Ben Murdoch257744e2011-11-30 15:57:28 +000010176 after = BuildIncrement(returns_original_input, expr);
10177 input = returns_original_input ? Top() : Pop();
Ben Murdochb0fe1622011-05-05 13:52:32 +010010178 Push(after);
10179
Ben Murdoch589d6972011-11-30 16:04:58 +000010180 switch (var->location()) {
10181 case Variable::UNALLOCATED:
10182 HandleGlobalVariableAssignment(var,
10183 after,
Ben Murdoch589d6972011-11-30 16:04:58 +000010184 expr->AssignmentId());
10185 break;
10186
10187 case Variable::PARAMETER:
10188 case Variable::LOCAL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010189 BindIfLive(var, after);
Ben Murdoch589d6972011-11-30 16:04:58 +000010190 break;
10191
10192 case Variable::CONTEXT: {
10193 // Bail out if we try to mutate a parameter value in a function
10194 // using the arguments object. We do not (yet) correctly handle the
10195 // arguments property of the function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010196 if (current_info()->scope()->arguments() != NULL) {
Ben Murdoch589d6972011-11-30 16:04:58 +000010197 // Parameters will rewrite to context slots. We have no direct
10198 // way to detect that the variable is a parameter so we use a
10199 // linear search of the parameter list.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010200 int count = current_info()->scope()->num_parameters();
Ben Murdoch589d6972011-11-30 16:04:58 +000010201 for (int i = 0; i < count; ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010202 if (var == current_info()->scope()->parameter(i)) {
10203 return Bailout(kAssignmentToParameterInArgumentsObject);
Ben Murdoch589d6972011-11-30 16:04:58 +000010204 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010205 }
10206 }
Ben Murdoch589d6972011-11-30 16:04:58 +000010207
10208 HValue* context = BuildContextChainWalk(var);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010209 HStoreContextSlot::Mode mode = IsLexicalVariableMode(var->mode())
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010210 ? HStoreContextSlot::kCheckDeoptimize : HStoreContextSlot::kNoCheck;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010211 HStoreContextSlot* instr = Add<HStoreContextSlot>(context, var->index(),
10212 mode, after);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010213 if (instr->HasObservableSideEffects()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010214 Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010215 }
Ben Murdoch589d6972011-11-30 16:04:58 +000010216 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010217 }
10218
Ben Murdoch589d6972011-11-30 16:04:58 +000010219 case Variable::LOOKUP:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010220 return Bailout(kLookupVariableInCountOperation);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010221 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010010222
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010223 Drop(returns_original_input ? 2 : 1);
10224 return ast_context()->ReturnValue(expr->is_postfix() ? input : after);
10225 }
10226
10227 // Argument of the count operation is a property.
10228 DCHECK(prop != NULL);
10229 if (returns_original_input) Push(graph()->GetConstantUndefined());
10230
10231 CHECK_ALIVE(VisitForValue(prop->obj()));
10232 HValue* object = Top();
10233
10234 HValue* key = NULL;
10235 if (!prop->key()->IsPropertyName() || prop->IsStringAccess()) {
10236 CHECK_ALIVE(VisitForValue(prop->key()));
10237 key = Top();
10238 }
10239
10240 CHECK_ALIVE(PushLoad(prop, object, key));
10241
10242 after = BuildIncrement(returns_original_input, expr);
10243
10244 if (returns_original_input) {
10245 input = Pop();
10246 // Drop object and key to push it again in the effect context below.
10247 Drop(key == NULL ? 1 : 2);
10248 environment()->SetExpressionStackAt(0, input);
10249 CHECK_ALIVE(BuildStoreForEffect(
10250 expr, prop, expr->id(), expr->AssignmentId(), object, key, after));
10251 return ast_context()->ReturnValue(Pop());
10252 }
10253
10254 environment()->SetExpressionStackAt(0, after);
10255 return BuildStore(expr, prop, expr->id(), expr->AssignmentId());
10256}
10257
10258
10259HInstruction* HOptimizedGraphBuilder::BuildStringCharCodeAt(
10260 HValue* string,
10261 HValue* index) {
10262 if (string->IsConstant() && index->IsConstant()) {
10263 HConstant* c_string = HConstant::cast(string);
10264 HConstant* c_index = HConstant::cast(index);
10265 if (c_string->HasStringValue() && c_index->HasNumberValue()) {
10266 int32_t i = c_index->NumberValueAsInteger32();
10267 Handle<String> s = c_string->StringValue();
10268 if (i < 0 || i >= s->length()) {
10269 return New<HConstant>(base::OS::nan_value());
10270 }
10271 return New<HConstant>(s->Get(i));
10272 }
10273 }
10274 string = BuildCheckString(string);
10275 index = Add<HBoundsCheck>(index, AddLoadStringLength(string));
10276 return New<HStringCharCodeAt>(string, index);
10277}
10278
10279
10280// Checks if the given shift amounts have following forms:
10281// (N1) and (N2) with N1 + N2 = 32; (sa) and (32 - sa).
10282static bool ShiftAmountsAllowReplaceByRotate(HValue* sa,
10283 HValue* const32_minus_sa) {
10284 if (sa->IsConstant() && const32_minus_sa->IsConstant()) {
10285 const HConstant* c1 = HConstant::cast(sa);
10286 const HConstant* c2 = HConstant::cast(const32_minus_sa);
10287 return c1->HasInteger32Value() && c2->HasInteger32Value() &&
10288 (c1->Integer32Value() + c2->Integer32Value() == 32);
10289 }
10290 if (!const32_minus_sa->IsSub()) return false;
10291 HSub* sub = HSub::cast(const32_minus_sa);
10292 return sub->left()->EqualsInteger32Constant(32) && sub->right() == sa;
10293}
10294
10295
10296// Checks if the left and the right are shift instructions with the oposite
10297// directions that can be replaced by one rotate right instruction or not.
10298// Returns the operand and the shift amount for the rotate instruction in the
10299// former case.
10300bool HGraphBuilder::MatchRotateRight(HValue* left,
10301 HValue* right,
10302 HValue** operand,
10303 HValue** shift_amount) {
10304 HShl* shl;
10305 HShr* shr;
10306 if (left->IsShl() && right->IsShr()) {
10307 shl = HShl::cast(left);
10308 shr = HShr::cast(right);
10309 } else if (left->IsShr() && right->IsShl()) {
10310 shl = HShl::cast(right);
10311 shr = HShr::cast(left);
Ben Murdoch257744e2011-11-30 15:57:28 +000010312 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010313 return false;
10314 }
10315 if (shl->left() != shr->left()) return false;
Ben Murdochb0fe1622011-05-05 13:52:32 +010010316
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010317 if (!ShiftAmountsAllowReplaceByRotate(shl->right(), shr->right()) &&
10318 !ShiftAmountsAllowReplaceByRotate(shr->right(), shl->right())) {
10319 return false;
10320 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010321 *operand = shr->left();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010322 *shift_amount = shr->right();
10323 return true;
10324}
Ben Murdochb0fe1622011-05-05 13:52:32 +010010325
Ben Murdochb0fe1622011-05-05 13:52:32 +010010326
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010327bool CanBeZero(HValue* right) {
10328 if (right->IsConstant()) {
10329 HConstant* right_const = HConstant::cast(right);
10330 if (right_const->HasInteger32Value() &&
10331 (right_const->Integer32Value() & 0x1f) != 0) {
10332 return false;
10333 }
10334 }
10335 return true;
10336}
Ben Murdochb0fe1622011-05-05 13:52:32 +010010337
Ben Murdochb0fe1622011-05-05 13:52:32 +010010338
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010339HValue* HGraphBuilder::EnforceNumberType(HValue* number,
10340 Type* expected) {
10341 if (expected->Is(Type::SignedSmall())) {
10342 return AddUncasted<HForceRepresentation>(number, Representation::Smi());
10343 }
10344 if (expected->Is(Type::Signed32())) {
10345 return AddUncasted<HForceRepresentation>(number,
10346 Representation::Integer32());
10347 }
10348 return number;
10349}
Ben Murdochb0fe1622011-05-05 13:52:32 +010010350
Ben Murdochb0fe1622011-05-05 13:52:32 +010010351
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010352HValue* HGraphBuilder::TruncateToNumber(HValue* value, Type** expected) {
10353 if (value->IsConstant()) {
10354 HConstant* constant = HConstant::cast(value);
10355 Maybe<HConstant*> number = constant->CopyToTruncatedNumber(zone());
10356 if (number.has_value) {
10357 *expected = Type::Number(zone());
10358 return AddInstruction(number.value);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010359 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010010360 }
Ben Murdoch257744e2011-11-30 15:57:28 +000010361
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010362 // We put temporary values on the stack, which don't correspond to anything
10363 // in baseline code. Since nothing is observable we avoid recording those
10364 // pushes with a NoObservableSideEffectsScope.
10365 NoObservableSideEffectsScope no_effects(this);
Ben Murdoch257744e2011-11-30 15:57:28 +000010366
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010367 Type* expected_type = *expected;
Ben Murdoch257744e2011-11-30 15:57:28 +000010368
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010369 // Separate the number type from the rest.
10370 Type* expected_obj =
10371 Type::Intersect(expected_type, Type::NonNumber(zone()), zone());
10372 Type* expected_number =
10373 Type::Intersect(expected_type, Type::Number(zone()), zone());
Steve Block1e0659c2011-05-24 12:43:12 +010010374
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010375 // We expect to get a number.
10376 // (We need to check first, since Type::None->Is(Type::Any()) == true.
10377 if (expected_obj->Is(Type::None())) {
10378 DCHECK(!expected_number->Is(Type::None(zone())));
10379 return value;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010380 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010381
10382 if (expected_obj->Is(Type::Undefined(zone()))) {
10383 // This is already done by HChange.
10384 *expected = Type::Union(expected_number, Type::Number(zone()), zone());
10385 return value;
10386 }
10387
10388 return value;
10389}
10390
10391
10392HValue* HOptimizedGraphBuilder::BuildBinaryOperation(
10393 BinaryOperation* expr,
10394 HValue* left,
10395 HValue* right,
10396 PushBeforeSimulateBehavior push_sim_result) {
10397 Type* left_type = expr->left()->bounds().lower;
10398 Type* right_type = expr->right()->bounds().lower;
10399 Type* result_type = expr->bounds().lower;
10400 Maybe<int> fixed_right_arg = expr->fixed_right_arg();
10401 Handle<AllocationSite> allocation_site = expr->allocation_site();
10402
10403 HAllocationMode allocation_mode;
10404 if (FLAG_allocation_site_pretenuring && !allocation_site.is_null()) {
10405 allocation_mode = HAllocationMode(allocation_site);
10406 }
10407
10408 HValue* result = HGraphBuilder::BuildBinaryOperation(
10409 expr->op(), left, right, left_type, right_type, result_type,
10410 fixed_right_arg, allocation_mode);
10411 // Add a simulate after instructions with observable side effects, and
10412 // after phis, which are the result of BuildBinaryOperation when we
10413 // inlined some complex subgraph.
10414 if (result->HasObservableSideEffects() || result->IsPhi()) {
10415 if (push_sim_result == PUSH_BEFORE_SIMULATE) {
10416 Push(result);
10417 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
10418 Drop(1);
10419 } else {
10420 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
10421 }
10422 }
10423 return result;
10424}
10425
10426
10427HValue* HGraphBuilder::BuildBinaryOperation(
10428 Token::Value op,
10429 HValue* left,
10430 HValue* right,
10431 Type* left_type,
10432 Type* right_type,
10433 Type* result_type,
10434 Maybe<int> fixed_right_arg,
10435 HAllocationMode allocation_mode) {
10436
10437 Representation left_rep = Representation::FromType(left_type);
10438 Representation right_rep = Representation::FromType(right_type);
10439
10440 bool maybe_string_add = op == Token::ADD &&
10441 (left_type->Maybe(Type::String()) ||
10442 left_type->Maybe(Type::Receiver()) ||
10443 right_type->Maybe(Type::String()) ||
10444 right_type->Maybe(Type::Receiver()));
10445
10446 if (!left_type->IsInhabited()) {
10447 Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation",
10448 Deoptimizer::SOFT);
10449 // TODO(rossberg): we should be able to get rid of non-continuous
10450 // defaults.
10451 left_type = Type::Any(zone());
10452 } else {
10453 if (!maybe_string_add) left = TruncateToNumber(left, &left_type);
10454 left_rep = Representation::FromType(left_type);
10455 }
10456
10457 if (!right_type->IsInhabited()) {
10458 Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation",
10459 Deoptimizer::SOFT);
10460 right_type = Type::Any(zone());
10461 } else {
10462 if (!maybe_string_add) right = TruncateToNumber(right, &right_type);
10463 right_rep = Representation::FromType(right_type);
10464 }
10465
10466 // Special case for string addition here.
10467 if (op == Token::ADD &&
10468 (left_type->Is(Type::String()) || right_type->Is(Type::String()))) {
10469 // Validate type feedback for left argument.
10470 if (left_type->Is(Type::String())) {
10471 left = BuildCheckString(left);
10472 }
10473
10474 // Validate type feedback for right argument.
10475 if (right_type->Is(Type::String())) {
10476 right = BuildCheckString(right);
10477 }
10478
10479 // Convert left argument as necessary.
10480 if (left_type->Is(Type::Number())) {
10481 DCHECK(right_type->Is(Type::String()));
10482 left = BuildNumberToString(left, left_type);
10483 } else if (!left_type->Is(Type::String())) {
10484 DCHECK(right_type->Is(Type::String()));
10485 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_RIGHT);
10486 Add<HPushArguments>(left, right);
10487 return AddUncasted<HInvokeFunction>(function, 2);
10488 }
10489
10490 // Convert right argument as necessary.
10491 if (right_type->Is(Type::Number())) {
10492 DCHECK(left_type->Is(Type::String()));
10493 right = BuildNumberToString(right, right_type);
10494 } else if (!right_type->Is(Type::String())) {
10495 DCHECK(left_type->Is(Type::String()));
10496 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_LEFT);
10497 Add<HPushArguments>(left, right);
10498 return AddUncasted<HInvokeFunction>(function, 2);
10499 }
10500
10501 // Fast path for empty constant strings.
10502 if (left->IsConstant() &&
10503 HConstant::cast(left)->HasStringValue() &&
10504 HConstant::cast(left)->StringValue()->length() == 0) {
10505 return right;
10506 }
10507 if (right->IsConstant() &&
10508 HConstant::cast(right)->HasStringValue() &&
10509 HConstant::cast(right)->StringValue()->length() == 0) {
10510 return left;
10511 }
10512
10513 // Register the dependent code with the allocation site.
10514 if (!allocation_mode.feedback_site().is_null()) {
10515 DCHECK(!graph()->info()->IsStub());
10516 Handle<AllocationSite> site(allocation_mode.feedback_site());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010517 AllocationSite::RegisterForDeoptOnTenureChange(site, top_info());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010518 }
10519
10520 // Inline the string addition into the stub when creating allocation
10521 // mementos to gather allocation site feedback, or if we can statically
10522 // infer that we're going to create a cons string.
10523 if ((graph()->info()->IsStub() &&
10524 allocation_mode.CreateAllocationMementos()) ||
10525 (left->IsConstant() &&
10526 HConstant::cast(left)->HasStringValue() &&
10527 HConstant::cast(left)->StringValue()->length() + 1 >=
10528 ConsString::kMinLength) ||
10529 (right->IsConstant() &&
10530 HConstant::cast(right)->HasStringValue() &&
10531 HConstant::cast(right)->StringValue()->length() + 1 >=
10532 ConsString::kMinLength)) {
10533 return BuildStringAdd(left, right, allocation_mode);
10534 }
10535
10536 // Fallback to using the string add stub.
10537 return AddUncasted<HStringAdd>(
10538 left, right, allocation_mode.GetPretenureMode(),
10539 STRING_ADD_CHECK_NONE, allocation_mode.feedback_site());
10540 }
10541
10542 if (graph()->info()->IsStub()) {
10543 left = EnforceNumberType(left, left_type);
10544 right = EnforceNumberType(right, right_type);
10545 }
10546
10547 Representation result_rep = Representation::FromType(result_type);
10548
10549 bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) ||
10550 (right_rep.IsTagged() && !right_rep.IsSmi());
10551
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010552 HInstruction* instr = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010553 // Only the stub is allowed to call into the runtime, since otherwise we would
10554 // inline several instructions (including the two pushes) for every tagged
10555 // operation in optimized code, which is more expensive, than a stub call.
10556 if (graph()->info()->IsStub() && is_non_primitive) {
10557 HValue* function = AddLoadJSBuiltin(BinaryOpIC::TokenToJSBuiltin(op));
10558 Add<HPushArguments>(left, right);
10559 instr = AddUncasted<HInvokeFunction>(function, 2);
10560 } else {
10561 switch (op) {
10562 case Token::ADD:
10563 instr = AddUncasted<HAdd>(left, right);
10564 break;
10565 case Token::SUB:
10566 instr = AddUncasted<HSub>(left, right);
10567 break;
10568 case Token::MUL:
10569 instr = AddUncasted<HMul>(left, right);
10570 break;
10571 case Token::MOD: {
10572 if (fixed_right_arg.has_value &&
10573 !right->EqualsInteger32Constant(fixed_right_arg.value)) {
10574 HConstant* fixed_right = Add<HConstant>(
10575 static_cast<int>(fixed_right_arg.value));
10576 IfBuilder if_same(this);
10577 if_same.If<HCompareNumericAndBranch>(right, fixed_right, Token::EQ);
10578 if_same.Then();
10579 if_same.ElseDeopt("Unexpected RHS of binary operation");
10580 right = fixed_right;
10581 }
10582 instr = AddUncasted<HMod>(left, right);
10583 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010584 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010585 case Token::DIV:
10586 instr = AddUncasted<HDiv>(left, right);
10587 break;
10588 case Token::BIT_XOR:
10589 case Token::BIT_AND:
10590 instr = AddUncasted<HBitwise>(op, left, right);
10591 break;
10592 case Token::BIT_OR: {
10593 HValue* operand, *shift_amount;
10594 if (left_type->Is(Type::Signed32()) &&
10595 right_type->Is(Type::Signed32()) &&
10596 MatchRotateRight(left, right, &operand, &shift_amount)) {
10597 instr = AddUncasted<HRor>(operand, shift_amount);
10598 } else {
10599 instr = AddUncasted<HBitwise>(op, left, right);
10600 }
10601 break;
10602 }
10603 case Token::SAR:
10604 instr = AddUncasted<HSar>(left, right);
10605 break;
10606 case Token::SHR:
10607 instr = AddUncasted<HShr>(left, right);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010608 if (instr->IsShr() && CanBeZero(right)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010609 graph()->RecordUint32Instruction(instr);
10610 }
10611 break;
10612 case Token::SHL:
10613 instr = AddUncasted<HShl>(left, right);
10614 break;
10615 default:
10616 UNREACHABLE();
10617 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010618 }
10619
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010620 if (instr->IsBinaryOperation()) {
10621 HBinaryOperation* binop = HBinaryOperation::cast(instr);
10622 binop->set_observed_input_representation(1, left_rep);
10623 binop->set_observed_input_representation(2, right_rep);
10624 binop->initialize_output_representation(result_rep);
10625 if (graph()->info()->IsStub()) {
10626 // Stub should not call into stub.
10627 instr->SetFlag(HValue::kCannotBeTagged);
10628 // And should truncate on HForceRepresentation already.
10629 if (left->IsForceRepresentation()) {
10630 left->CopyFlag(HValue::kTruncatingToSmi, instr);
10631 left->CopyFlag(HValue::kTruncatingToInt32, instr);
10632 }
10633 if (right->IsForceRepresentation()) {
10634 right->CopyFlag(HValue::kTruncatingToSmi, instr);
10635 right->CopyFlag(HValue::kTruncatingToInt32, instr);
10636 }
10637 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010010638 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010010639 return instr;
10640}
10641
10642
10643// Check for the form (%_ClassOf(foo) === 'BarClass').
10644static bool IsClassOfTest(CompareOperation* expr) {
10645 if (expr->op() != Token::EQ_STRICT) return false;
10646 CallRuntime* call = expr->left()->AsCallRuntime();
10647 if (call == NULL) return false;
10648 Literal* literal = expr->right()->AsLiteral();
10649 if (literal == NULL) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010650 if (!literal->value()->IsString()) return false;
10651 if (!call->name()->IsOneByteEqualTo(STATIC_CHAR_VECTOR("_ClassOf"))) {
10652 return false;
10653 }
10654 DCHECK(call->arguments()->length() == 1);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010655 return true;
10656}
10657
10658
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010659void HOptimizedGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
10660 DCHECK(!HasStackOverflow());
10661 DCHECK(current_block() != NULL);
10662 DCHECK(current_block()->HasPredecessor());
Ben Murdoch257744e2011-11-30 15:57:28 +000010663 switch (expr->op()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010664 case Token::COMMA:
10665 return VisitComma(expr);
10666 case Token::OR:
10667 case Token::AND:
10668 return VisitLogicalExpression(expr);
10669 default:
10670 return VisitArithmeticExpression(expr);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010671 }
10672}
10673
10674
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010675void HOptimizedGraphBuilder::VisitComma(BinaryOperation* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +000010676 CHECK_ALIVE(VisitForEffect(expr->left()));
10677 // Visit the right subexpression in the same AST context as the entire
10678 // expression.
10679 Visit(expr->right());
10680}
10681
10682
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010683void HOptimizedGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010684 bool is_logical_and = expr->op() == Token::AND;
Ben Murdoch257744e2011-11-30 15:57:28 +000010685 if (ast_context()->IsTest()) {
10686 TestContext* context = TestContext::cast(ast_context());
10687 // Translate left subexpression.
10688 HBasicBlock* eval_right = graph()->CreateBasicBlock();
10689 if (is_logical_and) {
10690 CHECK_BAILOUT(VisitForControl(expr->left(),
10691 eval_right,
10692 context->if_false()));
10693 } else {
10694 CHECK_BAILOUT(VisitForControl(expr->left(),
10695 context->if_true(),
10696 eval_right));
Ben Murdochb0fe1622011-05-05 13:52:32 +010010697 }
Ben Murdoch257744e2011-11-30 15:57:28 +000010698
10699 // Translate right subexpression by visiting it in the same AST
10700 // context as the entire expression.
10701 if (eval_right->HasPredecessor()) {
10702 eval_right->SetJoinId(expr->RightId());
10703 set_current_block(eval_right);
10704 Visit(expr->right());
10705 }
10706
10707 } else if (ast_context()->IsValue()) {
10708 CHECK_ALIVE(VisitForValue(expr->left()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010709 DCHECK(current_block() != NULL);
10710 HValue* left_value = Top();
10711
10712 // Short-circuit left values that always evaluate to the same boolean value.
10713 if (expr->left()->ToBooleanIsTrue() || expr->left()->ToBooleanIsFalse()) {
10714 // l (evals true) && r -> r
10715 // l (evals true) || r -> l
10716 // l (evals false) && r -> l
10717 // l (evals false) || r -> r
10718 if (is_logical_and == expr->left()->ToBooleanIsTrue()) {
10719 Drop(1);
10720 CHECK_ALIVE(VisitForValue(expr->right()));
10721 }
10722 return ast_context()->ReturnValue(Pop());
10723 }
Ben Murdoch257744e2011-11-30 15:57:28 +000010724
10725 // We need an extra block to maintain edge-split form.
10726 HBasicBlock* empty_block = graph()->CreateBasicBlock();
10727 HBasicBlock* eval_right = graph()->CreateBasicBlock();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010728 ToBooleanStub::Types expected(expr->left()->to_boolean_types());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010729 HBranch* test = is_logical_and
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010730 ? New<HBranch>(left_value, expected, eval_right, empty_block)
10731 : New<HBranch>(left_value, expected, empty_block, eval_right);
10732 FinishCurrentBlock(test);
Ben Murdoch257744e2011-11-30 15:57:28 +000010733
10734 set_current_block(eval_right);
10735 Drop(1); // Value of the left subexpression.
10736 CHECK_BAILOUT(VisitForValue(expr->right()));
10737
10738 HBasicBlock* join_block =
10739 CreateJoin(empty_block, current_block(), expr->id());
10740 set_current_block(join_block);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010741 return ast_context()->ReturnValue(Pop());
Ben Murdoch257744e2011-11-30 15:57:28 +000010742
10743 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010744 DCHECK(ast_context()->IsEffect());
Ben Murdoch257744e2011-11-30 15:57:28 +000010745 // In an effect context, we don't need the value of the left subexpression,
10746 // only its control flow and side effects. We need an extra block to
10747 // maintain edge-split form.
10748 HBasicBlock* empty_block = graph()->CreateBasicBlock();
10749 HBasicBlock* right_block = graph()->CreateBasicBlock();
10750 if (is_logical_and) {
10751 CHECK_BAILOUT(VisitForControl(expr->left(), right_block, empty_block));
10752 } else {
10753 CHECK_BAILOUT(VisitForControl(expr->left(), empty_block, right_block));
10754 }
10755
10756 // TODO(kmillikin): Find a way to fix this. It's ugly that there are
10757 // actually two empty blocks (one here and one inserted by
10758 // TestContext::BuildBranch, and that they both have an HSimulate though the
10759 // second one is not a merge node, and that we really have no good AST ID to
10760 // put on that first HSimulate.
10761
10762 if (empty_block->HasPredecessor()) {
10763 empty_block->SetJoinId(expr->id());
10764 } else {
10765 empty_block = NULL;
10766 }
10767
10768 if (right_block->HasPredecessor()) {
10769 right_block->SetJoinId(expr->RightId());
10770 set_current_block(right_block);
10771 CHECK_BAILOUT(VisitForEffect(expr->right()));
10772 right_block = current_block();
10773 } else {
10774 right_block = NULL;
10775 }
10776
10777 HBasicBlock* join_block =
10778 CreateJoin(empty_block, right_block, expr->id());
10779 set_current_block(join_block);
10780 // We did not materialize any value in the predecessor environments,
10781 // so there is no need to handle it here.
Ben Murdochb0fe1622011-05-05 13:52:32 +010010782 }
10783}
10784
10785
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010786void HOptimizedGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) {
Ben Murdoch257744e2011-11-30 15:57:28 +000010787 CHECK_ALIVE(VisitForValue(expr->left()));
10788 CHECK_ALIVE(VisitForValue(expr->right()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010789 SetSourcePosition(expr->position());
Ben Murdoch257744e2011-11-30 15:57:28 +000010790 HValue* right = Pop();
10791 HValue* left = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010792 HValue* result =
10793 BuildBinaryOperation(expr, left, right,
10794 ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE
10795 : PUSH_BEFORE_SIMULATE);
10796 if (FLAG_hydrogen_track_positions && result->IsBinaryOperation()) {
10797 HBinaryOperation::cast(result)->SetOperandPositions(
10798 zone(),
10799 ScriptPositionToSourcePosition(expr->left()->position()),
10800 ScriptPositionToSourcePosition(expr->right()->position()));
10801 }
10802 return ast_context()->ReturnValue(result);
Ben Murdoch257744e2011-11-30 15:57:28 +000010803}
10804
10805
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010806void HOptimizedGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr,
10807 Expression* sub_expr,
10808 Handle<String> check) {
10809 CHECK_ALIVE(VisitForTypeOf(sub_expr));
10810 SetSourcePosition(expr->position());
10811 HValue* value = Pop();
10812 HTypeofIsAndBranch* instr = New<HTypeofIsAndBranch>(value, check);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010813 return ast_context()->ReturnControl(instr, expr->id());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010814}
10815
10816
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010817static bool IsLiteralCompareBool(Isolate* isolate,
10818 HValue* left,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010819 Token::Value op,
10820 HValue* right) {
10821 return op == Token::EQ_STRICT &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010822 ((left->IsConstant() &&
10823 HConstant::cast(left)->handle(isolate)->IsBoolean()) ||
10824 (right->IsConstant() &&
10825 HConstant::cast(right)->handle(isolate)->IsBoolean()));
Ben Murdochc7cc0282012-03-05 14:35:55 +000010826}
10827
10828
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010829void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
10830 DCHECK(!HasStackOverflow());
10831 DCHECK(current_block() != NULL);
10832 DCHECK(current_block()->HasPredecessor());
10833
10834 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
10835
10836 // Check for a few fast cases. The AST visiting behavior must be in sync
10837 // with the full codegen: We don't push both left and right values onto
10838 // the expression stack when one side is a special-case literal.
10839 Expression* sub_expr = NULL;
10840 Handle<String> check;
10841 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) {
10842 return HandleLiteralCompareTypeof(expr, sub_expr, check);
10843 }
10844 if (expr->IsLiteralCompareUndefined(&sub_expr, isolate())) {
10845 return HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue);
10846 }
10847 if (expr->IsLiteralCompareNull(&sub_expr)) {
10848 return HandleLiteralCompareNil(expr, sub_expr, kNullValue);
10849 }
10850
Ben Murdochb0fe1622011-05-05 13:52:32 +010010851 if (IsClassOfTest(expr)) {
10852 CallRuntime* call = expr->left()->AsCallRuntime();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010853 DCHECK(call->arguments()->length() == 1);
Ben Murdoch257744e2011-11-30 15:57:28 +000010854 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
Ben Murdochb0fe1622011-05-05 13:52:32 +010010855 HValue* value = Pop();
10856 Literal* literal = expr->right()->AsLiteral();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010857 Handle<String> rhs = Handle<String>::cast(literal->value());
10858 HClassOfTestAndBranch* instr = New<HClassOfTestAndBranch>(value, rhs);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010859 return ast_context()->ReturnControl(instr, expr->id());
10860 }
10861
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010862 Type* left_type = expr->left()->bounds().lower;
10863 Type* right_type = expr->right()->bounds().lower;
10864 Type* combined_type = expr->combined_type();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010865
Ben Murdoch257744e2011-11-30 15:57:28 +000010866 CHECK_ALIVE(VisitForValue(expr->left()));
10867 CHECK_ALIVE(VisitForValue(expr->right()));
Ben Murdochb0fe1622011-05-05 13:52:32 +010010868
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010869 if (FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
10870
Ben Murdochb0fe1622011-05-05 13:52:32 +010010871 HValue* right = Pop();
10872 HValue* left = Pop();
10873 Token::Value op = expr->op();
10874
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010875 if (IsLiteralCompareBool(isolate(), left, op, right)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010876 HCompareObjectEqAndBranch* result =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010877 New<HCompareObjectEqAndBranch>(left, right);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010878 return ast_context()->ReturnControl(result, expr->id());
10879 }
10880
Ben Murdochb0fe1622011-05-05 13:52:32 +010010881 if (op == Token::INSTANCEOF) {
Ben Murdoch086aeea2011-05-13 15:57:08 +010010882 // Check to see if the rhs of the instanceof is a global function not
10883 // residing in new space. If it is we assume that the function will stay the
10884 // same.
10885 Handle<JSFunction> target = Handle<JSFunction>::null();
Ben Murdoch589d6972011-11-30 16:04:58 +000010886 VariableProxy* proxy = expr->right()->AsVariableProxy();
10887 bool global_function = (proxy != NULL) && proxy->var()->IsUnallocated();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010888 if (global_function && current_info()->has_global_object()) {
Ben Murdoch589d6972011-11-30 16:04:58 +000010889 Handle<String> name = proxy->name();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010890 Handle<GlobalObject> global(current_info()->global_object());
10891 LookupIterator it(global, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
10892 Handle<Object> value = JSObject::GetDataProperty(&it);
10893 if (it.IsFound() && value->IsJSFunction()) {
10894 Handle<JSFunction> candidate = Handle<JSFunction>::cast(value);
Ben Murdoch086aeea2011-05-13 15:57:08 +010010895 // If the function is in new space we assume it's more likely to
10896 // change and thus prefer the general IC code.
Steve Block44f0eee2011-05-26 01:26:41 +010010897 if (!isolate()->heap()->InNewSpace(*candidate)) {
Ben Murdoch086aeea2011-05-13 15:57:08 +010010898 target = candidate;
10899 }
10900 }
10901 }
10902
10903 // If the target is not null we have found a known global function that is
10904 // assumed to stay the same for this instanceof.
10905 if (target.is_null()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010906 HInstanceOf* result = New<HInstanceOf>(left, right);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010907 return ast_context()->ReturnInstruction(result, expr->id());
Ben Murdoch086aeea2011-05-13 15:57:08 +010010908 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010909 Add<HCheckValue>(right, target);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010910 HInstanceOfKnownGlobal* result =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010911 New<HInstanceOfKnownGlobal>(left, target);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010912 return ast_context()->ReturnInstruction(result, expr->id());
Ben Murdoch086aeea2011-05-13 15:57:08 +010010913 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010914
10915 // Code below assumes that we don't fall through.
10916 UNREACHABLE();
Ben Murdochb0fe1622011-05-05 13:52:32 +010010917 } else if (op == Token::IN) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010918 HValue* function = AddLoadJSBuiltin(Builtins::IN);
10919 Add<HPushArguments>(left, right);
10920 // TODO(olivf) InvokeFunction produces a check for the parameter count,
10921 // even though we are certain to pass the correct number of arguments here.
10922 HInstruction* result = New<HInvokeFunction>(function, 2);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010923 return ast_context()->ReturnInstruction(result, expr->id());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010924 }
10925
10926 PushBeforeSimulateBehavior push_behavior =
10927 ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE
10928 : PUSH_BEFORE_SIMULATE;
10929 HControlInstruction* compare = BuildCompareInstruction(
10930 op, left, right, left_type, right_type, combined_type,
10931 ScriptPositionToSourcePosition(expr->left()->position()),
10932 ScriptPositionToSourcePosition(expr->right()->position()),
10933 push_behavior, expr->id());
10934 if (compare == NULL) return; // Bailed out.
10935 return ast_context()->ReturnControl(compare, expr->id());
10936}
10937
10938
10939HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction(
10940 Token::Value op,
10941 HValue* left,
10942 HValue* right,
10943 Type* left_type,
10944 Type* right_type,
10945 Type* combined_type,
10946 HSourcePosition left_position,
10947 HSourcePosition right_position,
10948 PushBeforeSimulateBehavior push_sim_result,
10949 BailoutId bailout_id) {
10950 // Cases handled below depend on collected type feedback. They should
10951 // soft deoptimize when there is no type feedback.
10952 if (!combined_type->IsInhabited()) {
10953 Add<HDeoptimize>("Insufficient type feedback for combined type "
10954 "of binary operation",
10955 Deoptimizer::SOFT);
10956 combined_type = left_type = right_type = Type::Any(zone());
10957 }
10958
10959 Representation left_rep = Representation::FromType(left_type);
10960 Representation right_rep = Representation::FromType(right_type);
10961 Representation combined_rep = Representation::FromType(combined_type);
10962
10963 if (combined_type->Is(Type::Receiver())) {
10964 if (Token::IsEqualityOp(op)) {
10965 // HCompareObjectEqAndBranch can only deal with object, so
10966 // exclude numbers.
10967 if ((left->IsConstant() &&
10968 HConstant::cast(left)->HasNumberValue()) ||
10969 (right->IsConstant() &&
10970 HConstant::cast(right)->HasNumberValue())) {
10971 Add<HDeoptimize>("Type mismatch between feedback and constant",
10972 Deoptimizer::SOFT);
10973 // The caller expects a branch instruction, so make it happy.
10974 return New<HBranch>(graph()->GetConstantTrue());
Ben Murdochb0fe1622011-05-05 13:52:32 +010010975 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010976 // Can we get away with map check and not instance type check?
10977 HValue* operand_to_check =
10978 left->block()->block_id() < right->block()->block_id() ? left : right;
10979 if (combined_type->IsClass()) {
10980 Handle<Map> map = combined_type->AsClass()->Map();
10981 AddCheckMap(operand_to_check, map);
10982 HCompareObjectEqAndBranch* result =
10983 New<HCompareObjectEqAndBranch>(left, right);
10984 if (FLAG_hydrogen_track_positions) {
10985 result->set_operand_position(zone(), 0, left_position);
10986 result->set_operand_position(zone(), 1, right_position);
10987 }
10988 return result;
10989 } else {
10990 BuildCheckHeapObject(operand_to_check);
10991 Add<HCheckInstanceType>(operand_to_check,
10992 HCheckInstanceType::IS_SPEC_OBJECT);
10993 HCompareObjectEqAndBranch* result =
10994 New<HCompareObjectEqAndBranch>(left, right);
10995 return result;
10996 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010997 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010998 Bailout(kUnsupportedNonPrimitiveCompare);
10999 return NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011000 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011001 } else if (combined_type->Is(Type::InternalizedString()) &&
11002 Token::IsEqualityOp(op)) {
11003 // If we have a constant argument, it should be consistent with the type
11004 // feedback (otherwise we fail assertions in HCompareObjectEqAndBranch).
11005 if ((left->IsConstant() &&
11006 !HConstant::cast(left)->HasInternalizedStringValue()) ||
11007 (right->IsConstant() &&
11008 !HConstant::cast(right)->HasInternalizedStringValue())) {
11009 Add<HDeoptimize>("Type mismatch between feedback and constant",
11010 Deoptimizer::SOFT);
11011 // The caller expects a branch instruction, so make it happy.
11012 return New<HBranch>(graph()->GetConstantTrue());
11013 }
11014 BuildCheckHeapObject(left);
11015 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_INTERNALIZED_STRING);
11016 BuildCheckHeapObject(right);
11017 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_INTERNALIZED_STRING);
11018 HCompareObjectEqAndBranch* result =
11019 New<HCompareObjectEqAndBranch>(left, right);
11020 return result;
11021 } else if (combined_type->Is(Type::String())) {
11022 BuildCheckHeapObject(left);
11023 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_STRING);
11024 BuildCheckHeapObject(right);
11025 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_STRING);
11026 HStringCompareAndBranch* result =
11027 New<HStringCompareAndBranch>(left, right, op);
11028 return result;
11029 } else {
11030 if (combined_rep.IsTagged() || combined_rep.IsNone()) {
11031 HCompareGeneric* result = Add<HCompareGeneric>(left, right, op);
11032 result->set_observed_input_representation(1, left_rep);
11033 result->set_observed_input_representation(2, right_rep);
11034 if (result->HasObservableSideEffects()) {
11035 if (push_sim_result == PUSH_BEFORE_SIMULATE) {
11036 Push(result);
11037 AddSimulate(bailout_id, REMOVABLE_SIMULATE);
11038 Drop(1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011039 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011040 AddSimulate(bailout_id, REMOVABLE_SIMULATE);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011041 }
11042 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011043 // TODO(jkummerow): Can we make this more efficient?
11044 HBranch* branch = New<HBranch>(result);
11045 return branch;
11046 } else {
11047 HCompareNumericAndBranch* result =
11048 New<HCompareNumericAndBranch>(left, right, op);
11049 result->set_observed_input_representation(left_rep, right_rep);
11050 if (FLAG_hydrogen_track_positions) {
11051 result->SetOperandPositions(zone(), left_position, right_position);
11052 }
11053 return result;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011054 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011055 }
Ben Murdoch589d6972011-11-30 16:04:58 +000011056}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011057
Ben Murdoch589d6972011-11-30 16:04:58 +000011058
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011059void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
11060 Expression* sub_expr,
11061 NilValue nil) {
11062 DCHECK(!HasStackOverflow());
11063 DCHECK(current_block() != NULL);
11064 DCHECK(current_block()->HasPredecessor());
11065 DCHECK(expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT);
11066 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
11067 CHECK_ALIVE(VisitForValue(sub_expr));
11068 HValue* value = Pop();
11069 if (expr->op() == Token::EQ_STRICT) {
11070 HConstant* nil_constant = nil == kNullValue
11071 ? graph()->GetConstantNull()
11072 : graph()->GetConstantUndefined();
11073 HCompareObjectEqAndBranch* instr =
11074 New<HCompareObjectEqAndBranch>(value, nil_constant);
11075 return ast_context()->ReturnControl(instr, expr->id());
11076 } else {
11077 DCHECK_EQ(Token::EQ, expr->op());
11078 Type* type = expr->combined_type()->Is(Type::None())
11079 ? Type::Any(zone()) : expr->combined_type();
11080 HIfContinuation continuation;
11081 BuildCompareNil(value, type, &continuation);
11082 return ast_context()->ReturnContinuation(&continuation, expr->id());
11083 }
11084}
11085
11086
11087HInstruction* HOptimizedGraphBuilder::BuildThisFunction() {
11088 // If we share optimized code between different closures, the
11089 // this-function is not a constant, except inside an inlined body.
11090 if (function_state()->outer() != NULL) {
11091 return New<HConstant>(
11092 function_state()->compilation_info()->closure());
11093 } else {
11094 return New<HThisFunction>();
11095 }
11096}
11097
11098
11099HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
11100 Handle<JSObject> boilerplate_object,
11101 AllocationSiteUsageContext* site_context) {
11102 NoObservableSideEffectsScope no_effects(this);
11103 InstanceType instance_type = boilerplate_object->map()->instance_type();
11104 DCHECK(instance_type == JS_ARRAY_TYPE || instance_type == JS_OBJECT_TYPE);
11105
11106 HType type = instance_type == JS_ARRAY_TYPE
11107 ? HType::JSArray() : HType::JSObject();
11108 HValue* object_size_constant = Add<HConstant>(
11109 boilerplate_object->map()->instance_size());
11110
11111 PretenureFlag pretenure_flag = NOT_TENURED;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011112 Handle<AllocationSite> site(site_context->current());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011113 if (FLAG_allocation_site_pretenuring) {
11114 pretenure_flag = site_context->current()->GetPretenureMode();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011115 AllocationSite::RegisterForDeoptOnTenureChange(site, top_info());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011116 }
11117
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011118 AllocationSite::RegisterForDeoptOnTransitionChange(site, top_info());
11119
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011120 HInstruction* object = Add<HAllocate>(object_size_constant, type,
11121 pretenure_flag, instance_type, site_context->current());
11122
11123 // If allocation folding reaches Page::kMaxRegularHeapObjectSize the
11124 // elements array may not get folded into the object. Hence, we set the
11125 // elements pointer to empty fixed array and let store elimination remove
11126 // this store in the folding case.
11127 HConstant* empty_fixed_array = Add<HConstant>(
11128 isolate()->factory()->empty_fixed_array());
11129 Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
11130 empty_fixed_array);
11131
11132 BuildEmitObjectHeader(boilerplate_object, object);
11133
11134 Handle<FixedArrayBase> elements(boilerplate_object->elements());
11135 int elements_size = (elements->length() > 0 &&
11136 elements->map() != isolate()->heap()->fixed_cow_array_map()) ?
11137 elements->Size() : 0;
11138
11139 if (pretenure_flag == TENURED &&
11140 elements->map() == isolate()->heap()->fixed_cow_array_map() &&
11141 isolate()->heap()->InNewSpace(*elements)) {
11142 // If we would like to pretenure a fixed cow array, we must ensure that the
11143 // array is already in old space, otherwise we'll create too many old-to-
11144 // new-space pointers (overflowing the store buffer).
11145 elements = Handle<FixedArrayBase>(
11146 isolate()->factory()->CopyAndTenureFixedCOWArray(
11147 Handle<FixedArray>::cast(elements)));
11148 boilerplate_object->set_elements(*elements);
11149 }
11150
11151 HInstruction* object_elements = NULL;
11152 if (elements_size > 0) {
11153 HValue* object_elements_size = Add<HConstant>(elements_size);
11154 InstanceType instance_type = boilerplate_object->HasFastDoubleElements()
11155 ? FIXED_DOUBLE_ARRAY_TYPE : FIXED_ARRAY_TYPE;
11156 object_elements = Add<HAllocate>(
11157 object_elements_size, HType::HeapObject(),
11158 pretenure_flag, instance_type, site_context->current());
11159 }
11160 BuildInitElementsInObjectHeader(boilerplate_object, object, object_elements);
11161
11162 // Copy object elements if non-COW.
11163 if (object_elements != NULL) {
11164 BuildEmitElements(boilerplate_object, elements, object_elements,
11165 site_context);
11166 }
11167
11168 // Copy in-object properties.
11169 if (boilerplate_object->map()->NumberOfFields() != 0 ||
11170 boilerplate_object->map()->unused_property_fields() > 0) {
11171 BuildEmitInObjectProperties(boilerplate_object, object, site_context,
11172 pretenure_flag);
11173 }
11174 return object;
11175}
11176
11177
11178void HOptimizedGraphBuilder::BuildEmitObjectHeader(
11179 Handle<JSObject> boilerplate_object,
11180 HInstruction* object) {
11181 DCHECK(boilerplate_object->properties()->length() == 0);
11182
11183 Handle<Map> boilerplate_object_map(boilerplate_object->map());
11184 AddStoreMapConstant(object, boilerplate_object_map);
11185
11186 Handle<Object> properties_field =
11187 Handle<Object>(boilerplate_object->properties(), isolate());
11188 DCHECK(*properties_field == isolate()->heap()->empty_fixed_array());
11189 HInstruction* properties = Add<HConstant>(properties_field);
11190 HObjectAccess access = HObjectAccess::ForPropertiesPointer();
11191 Add<HStoreNamedField>(object, access, properties);
11192
11193 if (boilerplate_object->IsJSArray()) {
11194 Handle<JSArray> boilerplate_array =
11195 Handle<JSArray>::cast(boilerplate_object);
11196 Handle<Object> length_field =
11197 Handle<Object>(boilerplate_array->length(), isolate());
11198 HInstruction* length = Add<HConstant>(length_field);
11199
11200 DCHECK(boilerplate_array->length()->IsSmi());
11201 Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(
11202 boilerplate_array->GetElementsKind()), length);
11203 }
11204}
11205
11206
11207void HOptimizedGraphBuilder::BuildInitElementsInObjectHeader(
11208 Handle<JSObject> boilerplate_object,
11209 HInstruction* object,
11210 HInstruction* object_elements) {
11211 DCHECK(boilerplate_object->properties()->length() == 0);
11212 if (object_elements == NULL) {
11213 Handle<Object> elements_field =
11214 Handle<Object>(boilerplate_object->elements(), isolate());
11215 object_elements = Add<HConstant>(elements_field);
11216 }
11217 Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
11218 object_elements);
11219}
11220
11221
11222void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
11223 Handle<JSObject> boilerplate_object,
11224 HInstruction* object,
11225 AllocationSiteUsageContext* site_context,
11226 PretenureFlag pretenure_flag) {
11227 Handle<Map> boilerplate_map(boilerplate_object->map());
11228 Handle<DescriptorArray> descriptors(boilerplate_map->instance_descriptors());
11229 int limit = boilerplate_map->NumberOfOwnDescriptors();
11230
11231 int copied_fields = 0;
11232 for (int i = 0; i < limit; i++) {
11233 PropertyDetails details = descriptors->GetDetails(i);
11234 if (details.type() != FIELD) continue;
11235 copied_fields++;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011236 FieldIndex field_index = FieldIndex::ForDescriptor(*boilerplate_map, i);
11237
11238
11239 int property_offset = field_index.offset();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011240 Handle<Name> name(descriptors->GetKey(i));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011241
11242 // The access for the store depends on the type of the boilerplate.
11243 HObjectAccess access = boilerplate_object->IsJSArray() ?
11244 HObjectAccess::ForJSArrayOffset(property_offset) :
11245 HObjectAccess::ForMapAndOffset(boilerplate_map, property_offset);
11246
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011247 if (boilerplate_object->IsUnboxedDoubleField(field_index)) {
11248 CHECK(!boilerplate_object->IsJSArray());
11249 double value = boilerplate_object->RawFastDoublePropertyAt(field_index);
11250 access = access.WithRepresentation(Representation::Double());
11251 Add<HStoreNamedField>(object, access, Add<HConstant>(value));
11252 continue;
11253 }
11254 Handle<Object> value(boilerplate_object->RawFastPropertyAt(field_index),
11255 isolate());
11256
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011257 if (value->IsJSObject()) {
11258 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
11259 Handle<AllocationSite> current_site = site_context->EnterNewScope();
11260 HInstruction* result =
11261 BuildFastLiteral(value_object, site_context);
11262 site_context->ExitScope(current_site, value_object);
11263 Add<HStoreNamedField>(object, access, result);
11264 } else {
11265 Representation representation = details.representation();
11266 HInstruction* value_instruction;
11267
11268 if (representation.IsDouble()) {
11269 // Allocate a HeapNumber box and store the value into it.
11270 HValue* heap_number_constant = Add<HConstant>(HeapNumber::kSize);
11271 // This heap number alloc does not have a corresponding
11272 // AllocationSite. That is okay because
11273 // 1) it's a child object of another object with a valid allocation site
11274 // 2) we can just use the mode of the parent object for pretenuring
11275 HInstruction* double_box =
11276 Add<HAllocate>(heap_number_constant, HType::HeapObject(),
11277 pretenure_flag, MUTABLE_HEAP_NUMBER_TYPE);
11278 AddStoreMapConstant(double_box,
11279 isolate()->factory()->mutable_heap_number_map());
11280 // Unwrap the mutable heap number from the boilerplate.
11281 HValue* double_value =
11282 Add<HConstant>(Handle<HeapNumber>::cast(value)->value());
11283 Add<HStoreNamedField>(
11284 double_box, HObjectAccess::ForHeapNumberValue(), double_value);
11285 value_instruction = double_box;
11286 } else if (representation.IsSmi()) {
11287 value_instruction = value->IsUninitialized()
11288 ? graph()->GetConstant0()
11289 : Add<HConstant>(value);
11290 // Ensure that value is stored as smi.
11291 access = access.WithRepresentation(representation);
11292 } else {
11293 value_instruction = Add<HConstant>(value);
11294 }
11295
11296 Add<HStoreNamedField>(object, access, value_instruction);
11297 }
11298 }
11299
11300 int inobject_properties = boilerplate_object->map()->inobject_properties();
11301 HInstruction* value_instruction =
11302 Add<HConstant>(isolate()->factory()->one_pointer_filler_map());
11303 for (int i = copied_fields; i < inobject_properties; i++) {
11304 DCHECK(boilerplate_object->IsJSObject());
11305 int property_offset = boilerplate_object->GetInObjectPropertyOffset(i);
11306 HObjectAccess access =
11307 HObjectAccess::ForMapAndOffset(boilerplate_map, property_offset);
11308 Add<HStoreNamedField>(object, access, value_instruction);
11309 }
11310}
11311
11312
11313void HOptimizedGraphBuilder::BuildEmitElements(
11314 Handle<JSObject> boilerplate_object,
11315 Handle<FixedArrayBase> elements,
11316 HValue* object_elements,
11317 AllocationSiteUsageContext* site_context) {
11318 ElementsKind kind = boilerplate_object->map()->elements_kind();
11319 int elements_length = elements->length();
11320 HValue* object_elements_length = Add<HConstant>(elements_length);
11321 BuildInitializeElementsHeader(object_elements, kind, object_elements_length);
11322
11323 // Copy elements backing store content.
11324 if (elements->IsFixedDoubleArray()) {
11325 BuildEmitFixedDoubleArray(elements, kind, object_elements);
11326 } else if (elements->IsFixedArray()) {
11327 BuildEmitFixedArray(elements, kind, object_elements,
11328 site_context);
11329 } else {
11330 UNREACHABLE();
11331 }
11332}
11333
11334
11335void HOptimizedGraphBuilder::BuildEmitFixedDoubleArray(
11336 Handle<FixedArrayBase> elements,
11337 ElementsKind kind,
11338 HValue* object_elements) {
11339 HInstruction* boilerplate_elements = Add<HConstant>(elements);
11340 int elements_length = elements->length();
11341 for (int i = 0; i < elements_length; i++) {
11342 HValue* key_constant = Add<HConstant>(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011343 HInstruction* value_instruction = Add<HLoadKeyed>(
11344 boilerplate_elements, key_constant, nullptr, kind, ALLOW_RETURN_HOLE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011345 HInstruction* store = Add<HStoreKeyed>(object_elements, key_constant,
11346 value_instruction, kind);
11347 store->SetFlag(HValue::kAllowUndefinedAsNaN);
11348 }
11349}
11350
11351
11352void HOptimizedGraphBuilder::BuildEmitFixedArray(
11353 Handle<FixedArrayBase> elements,
11354 ElementsKind kind,
11355 HValue* object_elements,
11356 AllocationSiteUsageContext* site_context) {
11357 HInstruction* boilerplate_elements = Add<HConstant>(elements);
11358 int elements_length = elements->length();
11359 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
11360 for (int i = 0; i < elements_length; i++) {
11361 Handle<Object> value(fast_elements->get(i), isolate());
11362 HValue* key_constant = Add<HConstant>(i);
11363 if (value->IsJSObject()) {
11364 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
11365 Handle<AllocationSite> current_site = site_context->EnterNewScope();
11366 HInstruction* result =
11367 BuildFastLiteral(value_object, site_context);
11368 site_context->ExitScope(current_site, value_object);
11369 Add<HStoreKeyed>(object_elements, key_constant, result, kind);
11370 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011371 ElementsKind copy_kind =
11372 kind == FAST_HOLEY_SMI_ELEMENTS ? FAST_HOLEY_ELEMENTS : kind;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011373 HInstruction* value_instruction =
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011374 Add<HLoadKeyed>(boilerplate_elements, key_constant, nullptr,
11375 copy_kind, ALLOW_RETURN_HOLE);
11376 Add<HStoreKeyed>(object_elements, key_constant, value_instruction,
11377 copy_kind);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011378 }
11379 }
11380}
11381
11382
11383void HOptimizedGraphBuilder::VisitThisFunction(ThisFunction* expr) {
11384 DCHECK(!HasStackOverflow());
11385 DCHECK(current_block() != NULL);
11386 DCHECK(current_block()->HasPredecessor());
11387 HInstruction* instr = BuildThisFunction();
11388 return ast_context()->ReturnInstruction(instr, expr->id());
11389}
11390
11391
11392void HOptimizedGraphBuilder::VisitSuperReference(SuperReference* expr) {
11393 DCHECK(!HasStackOverflow());
11394 DCHECK(current_block() != NULL);
11395 DCHECK(current_block()->HasPredecessor());
11396 return Bailout(kSuperReference);
11397}
11398
11399
11400void HOptimizedGraphBuilder::VisitDeclarations(
11401 ZoneList<Declaration*>* declarations) {
11402 DCHECK(globals_.is_empty());
11403 AstVisitor::VisitDeclarations(declarations);
11404 if (!globals_.is_empty()) {
11405 Handle<FixedArray> array =
11406 isolate()->factory()->NewFixedArray(globals_.length(), TENURED);
11407 for (int i = 0; i < globals_.length(); ++i) array->set(i, *globals_.at(i));
11408 int flags = DeclareGlobalsEvalFlag::encode(current_info()->is_eval()) |
11409 DeclareGlobalsNativeFlag::encode(current_info()->is_native()) |
11410 DeclareGlobalsStrictMode::encode(current_info()->strict_mode());
11411 Add<HDeclareGlobals>(array, flags);
11412 globals_.Rewind(0);
11413 }
11414}
11415
11416
11417void HOptimizedGraphBuilder::VisitVariableDeclaration(
11418 VariableDeclaration* declaration) {
11419 VariableProxy* proxy = declaration->proxy();
11420 VariableMode mode = declaration->mode();
11421 Variable* variable = proxy->var();
11422 bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY;
11423 switch (variable->location()) {
Ben Murdoch589d6972011-11-30 16:04:58 +000011424 case Variable::UNALLOCATED:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011425 globals_.Add(variable->name(), zone());
11426 globals_.Add(variable->binding_needs_init()
11427 ? isolate()->factory()->the_hole_value()
11428 : isolate()->factory()->undefined_value(), zone());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011429 return;
Ben Murdoch589d6972011-11-30 16:04:58 +000011430 case Variable::PARAMETER:
11431 case Variable::LOCAL:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011432 if (hole_init) {
11433 HValue* value = graph()->GetConstantHole();
11434 environment()->Bind(variable, value);
11435 }
11436 break;
Ben Murdoch589d6972011-11-30 16:04:58 +000011437 case Variable::CONTEXT:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011438 if (hole_init) {
11439 HValue* value = graph()->GetConstantHole();
11440 HValue* context = environment()->context();
11441 HStoreContextSlot* store = Add<HStoreContextSlot>(
11442 context, variable->index(), HStoreContextSlot::kNoCheck, value);
11443 if (store->HasObservableSideEffects()) {
11444 Add<HSimulate>(proxy->id(), REMOVABLE_SIMULATE);
Ben Murdoch589d6972011-11-30 16:04:58 +000011445 }
11446 }
11447 break;
11448 case Variable::LOOKUP:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011449 return Bailout(kUnsupportedLookupSlotInDeclaration);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011450 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010011451}
11452
11453
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011454void HOptimizedGraphBuilder::VisitFunctionDeclaration(
11455 FunctionDeclaration* declaration) {
11456 VariableProxy* proxy = declaration->proxy();
11457 Variable* variable = proxy->var();
11458 switch (variable->location()) {
11459 case Variable::UNALLOCATED: {
11460 globals_.Add(variable->name(), zone());
11461 Handle<SharedFunctionInfo> function = Compiler::BuildFunctionInfo(
11462 declaration->fun(), current_info()->script(), top_info());
11463 // Check for stack-overflow exception.
11464 if (function.is_null()) return SetStackOverflow();
11465 globals_.Add(function, zone());
11466 return;
11467 }
11468 case Variable::PARAMETER:
11469 case Variable::LOCAL: {
11470 CHECK_ALIVE(VisitForValue(declaration->fun()));
11471 HValue* value = Pop();
11472 BindIfLive(variable, value);
11473 break;
11474 }
11475 case Variable::CONTEXT: {
11476 CHECK_ALIVE(VisitForValue(declaration->fun()));
11477 HValue* value = Pop();
11478 HValue* context = environment()->context();
11479 HStoreContextSlot* store = Add<HStoreContextSlot>(
11480 context, variable->index(), HStoreContextSlot::kNoCheck, value);
11481 if (store->HasObservableSideEffects()) {
11482 Add<HSimulate>(proxy->id(), REMOVABLE_SIMULATE);
11483 }
11484 break;
11485 }
11486 case Variable::LOOKUP:
11487 return Bailout(kUnsupportedLookupSlotInDeclaration);
11488 }
11489}
11490
11491
11492void HOptimizedGraphBuilder::VisitModuleDeclaration(
11493 ModuleDeclaration* declaration) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011494 UNREACHABLE();
11495}
11496
11497
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011498void HOptimizedGraphBuilder::VisitImportDeclaration(
11499 ImportDeclaration* declaration) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011500 UNREACHABLE();
11501}
11502
11503
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011504void HOptimizedGraphBuilder::VisitExportDeclaration(
11505 ExportDeclaration* declaration) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011506 UNREACHABLE();
11507}
11508
11509
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011510void HOptimizedGraphBuilder::VisitModuleLiteral(ModuleLiteral* module) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011511 UNREACHABLE();
11512}
11513
11514
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011515void HOptimizedGraphBuilder::VisitModuleVariable(ModuleVariable* module) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011516 UNREACHABLE();
11517}
11518
11519
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011520void HOptimizedGraphBuilder::VisitModulePath(ModulePath* module) {
11521 UNREACHABLE();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011522}
11523
11524
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011525void HOptimizedGraphBuilder::VisitModuleUrl(ModuleUrl* module) {
11526 UNREACHABLE();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011527}
11528
11529
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011530void HOptimizedGraphBuilder::VisitModuleStatement(ModuleStatement* stmt) {
11531 UNREACHABLE();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011532}
11533
11534
Ben Murdochb0fe1622011-05-05 13:52:32 +010011535// Generators for inline runtime functions.
11536// Support for types.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011537void HOptimizedGraphBuilder::GenerateIsSmi(CallRuntime* call) {
11538 DCHECK(call->arguments()->length() == 1);
Ben Murdoch257744e2011-11-30 15:57:28 +000011539 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
Ben Murdochb0fe1622011-05-05 13:52:32 +010011540 HValue* value = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011541 HIsSmiAndBranch* result = New<HIsSmiAndBranch>(value);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011542 return ast_context()->ReturnControl(result, call->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +010011543}
11544
11545
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011546void HOptimizedGraphBuilder::GenerateIsSpecObject(CallRuntime* call) {
11547 DCHECK(call->arguments()->length() == 1);
Ben Murdoch257744e2011-11-30 15:57:28 +000011548 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
Ben Murdochb0fe1622011-05-05 13:52:32 +010011549 HValue* value = Pop();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011550 HHasInstanceTypeAndBranch* result =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011551 New<HHasInstanceTypeAndBranch>(value,
11552 FIRST_SPEC_OBJECT_TYPE,
11553 LAST_SPEC_OBJECT_TYPE);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011554 return ast_context()->ReturnControl(result, call->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +010011555}
11556
11557
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011558void HOptimizedGraphBuilder::GenerateIsFunction(CallRuntime* call) {
11559 DCHECK(call->arguments()->length() == 1);
Ben Murdoch257744e2011-11-30 15:57:28 +000011560 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
Ben Murdochb0fe1622011-05-05 13:52:32 +010011561 HValue* value = Pop();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011562 HHasInstanceTypeAndBranch* result =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011563 New<HHasInstanceTypeAndBranch>(value, JS_FUNCTION_TYPE);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011564 return ast_context()->ReturnControl(result, call->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +010011565}
11566
11567
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011568void HOptimizedGraphBuilder::GenerateIsMinusZero(CallRuntime* call) {
11569 DCHECK(call->arguments()->length() == 1);
11570 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11571 HValue* value = Pop();
11572 HCompareMinusZeroAndBranch* result = New<HCompareMinusZeroAndBranch>(value);
11573 return ast_context()->ReturnControl(result, call->id());
11574}
11575
11576
11577void HOptimizedGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) {
11578 DCHECK(call->arguments()->length() == 1);
Ben Murdoch257744e2011-11-30 15:57:28 +000011579 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
Ben Murdochb0fe1622011-05-05 13:52:32 +010011580 HValue* value = Pop();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011581 HHasCachedArrayIndexAndBranch* result =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011582 New<HHasCachedArrayIndexAndBranch>(value);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011583 return ast_context()->ReturnControl(result, call->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +010011584}
11585
11586
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011587void HOptimizedGraphBuilder::GenerateIsArray(CallRuntime* call) {
11588 DCHECK(call->arguments()->length() == 1);
Ben Murdoch257744e2011-11-30 15:57:28 +000011589 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
Ben Murdochb0fe1622011-05-05 13:52:32 +010011590 HValue* value = Pop();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011591 HHasInstanceTypeAndBranch* result =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011592 New<HHasInstanceTypeAndBranch>(value, JS_ARRAY_TYPE);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011593 return ast_context()->ReturnControl(result, call->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +010011594}
11595
11596
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011597void HOptimizedGraphBuilder::GenerateIsRegExp(CallRuntime* call) {
11598 DCHECK(call->arguments()->length() == 1);
Ben Murdoch257744e2011-11-30 15:57:28 +000011599 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
Ben Murdochb0fe1622011-05-05 13:52:32 +010011600 HValue* value = Pop();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011601 HHasInstanceTypeAndBranch* result =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011602 New<HHasInstanceTypeAndBranch>(value, JS_REGEXP_TYPE);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011603 return ast_context()->ReturnControl(result, call->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +010011604}
11605
11606
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011607void HOptimizedGraphBuilder::GenerateIsObject(CallRuntime* call) {
11608 DCHECK(call->arguments()->length() == 1);
Ben Murdoch257744e2011-11-30 15:57:28 +000011609 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
Ben Murdochb0fe1622011-05-05 13:52:32 +010011610 HValue* value = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011611 HIsObjectAndBranch* result = New<HIsObjectAndBranch>(value);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011612 return ast_context()->ReturnControl(result, call->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +010011613}
11614
11615
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011616void HOptimizedGraphBuilder::GenerateIsJSProxy(CallRuntime* call) {
11617 DCHECK(call->arguments()->length() == 1);
11618 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11619 HValue* value = Pop();
11620 HIfContinuation continuation;
11621 IfBuilder if_proxy(this);
11622
11623 HValue* smicheck = if_proxy.IfNot<HIsSmiAndBranch>(value);
11624 if_proxy.And();
11625 HValue* map = Add<HLoadNamedField>(value, smicheck, HObjectAccess::ForMap());
11626 HValue* instance_type =
11627 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapInstanceType());
11628 if_proxy.If<HCompareNumericAndBranch>(
11629 instance_type, Add<HConstant>(FIRST_JS_PROXY_TYPE), Token::GTE);
11630 if_proxy.And();
11631 if_proxy.If<HCompareNumericAndBranch>(
11632 instance_type, Add<HConstant>(LAST_JS_PROXY_TYPE), Token::LTE);
11633
11634 if_proxy.CaptureContinuation(&continuation);
11635 return ast_context()->ReturnContinuation(&continuation, call->id());
11636}
11637
11638
11639void HOptimizedGraphBuilder::GenerateHasFastPackedElements(CallRuntime* call) {
11640 DCHECK(call->arguments()->length() == 1);
11641 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11642 HValue* object = Pop();
11643 HIfContinuation continuation(graph()->CreateBasicBlock(),
11644 graph()->CreateBasicBlock());
11645 IfBuilder if_not_smi(this);
11646 if_not_smi.IfNot<HIsSmiAndBranch>(object);
11647 if_not_smi.Then();
11648 {
11649 NoObservableSideEffectsScope no_effects(this);
11650
11651 IfBuilder if_fast_packed(this);
11652 HValue* elements_kind = BuildGetElementsKind(object);
11653 if_fast_packed.If<HCompareNumericAndBranch>(
11654 elements_kind, Add<HConstant>(FAST_SMI_ELEMENTS), Token::EQ);
11655 if_fast_packed.Or();
11656 if_fast_packed.If<HCompareNumericAndBranch>(
11657 elements_kind, Add<HConstant>(FAST_ELEMENTS), Token::EQ);
11658 if_fast_packed.Or();
11659 if_fast_packed.If<HCompareNumericAndBranch>(
11660 elements_kind, Add<HConstant>(FAST_DOUBLE_ELEMENTS), Token::EQ);
11661 if_fast_packed.JoinContinuation(&continuation);
11662 }
11663 if_not_smi.JoinContinuation(&continuation);
11664 return ast_context()->ReturnContinuation(&continuation, call->id());
11665}
11666
11667
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011668void HOptimizedGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) {
11669 return Bailout(kInlinedRuntimeFunctionIsNonNegativeSmi);
Ben Murdochb0fe1622011-05-05 13:52:32 +010011670}
11671
11672
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011673void HOptimizedGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) {
11674 DCHECK(call->arguments()->length() == 1);
Ben Murdoch257744e2011-11-30 15:57:28 +000011675 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11676 HValue* value = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011677 HIsUndetectableAndBranch* result = New<HIsUndetectableAndBranch>(value);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011678 return ast_context()->ReturnControl(result, call->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +010011679}
11680
11681
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011682void HOptimizedGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf(
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011683 CallRuntime* call) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011684 return Bailout(kInlinedRuntimeFunctionIsStringWrapperSafeForDefaultValueOf);
Ben Murdochb0fe1622011-05-05 13:52:32 +010011685}
11686
11687
Steve Block1e0659c2011-05-24 12:43:12 +010011688// Support for construct call checks.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011689void HOptimizedGraphBuilder::GenerateIsConstructCall(CallRuntime* call) {
11690 DCHECK(call->arguments()->length() == 0);
Ben Murdoch8b112d22011-06-08 16:22:53 +010011691 if (function_state()->outer() != NULL) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011692 // We are generating graph for inlined function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011693 HValue* value = function_state()->inlining_kind() == CONSTRUCT_CALL_RETURN
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011694 ? graph()->GetConstantTrue()
11695 : graph()->GetConstantFalse();
11696 return ast_context()->ReturnValue(value);
Ben Murdoch8b112d22011-06-08 16:22:53 +010011697 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011698 return ast_context()->ReturnControl(New<HIsConstructCallAndBranch>(),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011699 call->id());
Ben Murdoch8b112d22011-06-08 16:22:53 +010011700 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010011701}
11702
11703
11704// Support for arguments.length and arguments[?].
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011705void HOptimizedGraphBuilder::GenerateArgumentsLength(CallRuntime* call) {
11706 DCHECK(call->arguments()->length() == 0);
11707 HInstruction* result = NULL;
11708 if (function_state()->outer() == NULL) {
11709 HInstruction* elements = Add<HArgumentsElements>(false);
11710 result = New<HArgumentsLength>(elements);
11711 } else {
11712 // Number of arguments without receiver.
11713 int argument_count = environment()->
11714 arguments_environment()->parameter_count() - 1;
11715 result = New<HConstant>(argument_count);
11716 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011717 return ast_context()->ReturnInstruction(result, call->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +010011718}
11719
11720
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011721void HOptimizedGraphBuilder::GenerateArguments(CallRuntime* call) {
11722 DCHECK(call->arguments()->length() == 1);
Ben Murdoch257744e2011-11-30 15:57:28 +000011723 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
Ben Murdochb0fe1622011-05-05 13:52:32 +010011724 HValue* index = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011725 HInstruction* result = NULL;
11726 if (function_state()->outer() == NULL) {
11727 HInstruction* elements = Add<HArgumentsElements>(false);
11728 HInstruction* length = Add<HArgumentsLength>(elements);
11729 HInstruction* checked_index = Add<HBoundsCheck>(index, length);
11730 result = New<HAccessArgumentsAt>(elements, length, checked_index);
11731 } else {
11732 EnsureArgumentsArePushedForAccess();
11733
11734 // Number of arguments without receiver.
11735 HInstruction* elements = function_state()->arguments_elements();
11736 int argument_count = environment()->
11737 arguments_environment()->parameter_count() - 1;
11738 HInstruction* length = Add<HConstant>(argument_count);
11739 HInstruction* checked_key = Add<HBoundsCheck>(index, length);
11740 result = New<HAccessArgumentsAt>(elements, length, checked_key);
11741 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011742 return ast_context()->ReturnInstruction(result, call->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +010011743}
11744
11745
11746// Support for accessing the class and value fields of an object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011747void HOptimizedGraphBuilder::GenerateClassOf(CallRuntime* call) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010011748 // The special form detected by IsClassOfTest is detected before we get here
11749 // and does not cause a bailout.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011750 return Bailout(kInlinedRuntimeFunctionClassOf);
Ben Murdochb0fe1622011-05-05 13:52:32 +010011751}
11752
11753
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011754void HOptimizedGraphBuilder::GenerateValueOf(CallRuntime* call) {
11755 DCHECK(call->arguments()->length() == 1);
Ben Murdoch257744e2011-11-30 15:57:28 +000011756 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011757 HValue* object = Pop();
11758
11759 IfBuilder if_objectisvalue(this);
11760 HValue* objectisvalue = if_objectisvalue.If<HHasInstanceTypeAndBranch>(
11761 object, JS_VALUE_TYPE);
11762 if_objectisvalue.Then();
11763 {
11764 // Return the actual value.
11765 Push(Add<HLoadNamedField>(
11766 object, objectisvalue,
11767 HObjectAccess::ForObservableJSObjectOffset(
11768 JSValue::kValueOffset)));
11769 Add<HSimulate>(call->id(), FIXED_SIMULATE);
11770 }
11771 if_objectisvalue.Else();
11772 {
11773 // If the object is not a value return the object.
11774 Push(object);
11775 Add<HSimulate>(call->id(), FIXED_SIMULATE);
11776 }
11777 if_objectisvalue.End();
11778 return ast_context()->ReturnValue(Pop());
Ben Murdochb0fe1622011-05-05 13:52:32 +010011779}
11780
11781
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011782void HOptimizedGraphBuilder::GenerateDateField(CallRuntime* call) {
11783 DCHECK(call->arguments()->length() == 2);
11784 DCHECK_NE(NULL, call->arguments()->at(1)->AsLiteral());
11785 Smi* index = Smi::cast(*(call->arguments()->at(1)->AsLiteral()->value()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011786 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11787 HValue* date = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011788 HDateField* result = New<HDateField>(date, index);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011789 return ast_context()->ReturnInstruction(result, call->id());
11790}
11791
11792
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011793void HOptimizedGraphBuilder::GenerateOneByteSeqStringSetChar(
11794 CallRuntime* call) {
11795 DCHECK(call->arguments()->length() == 3);
11796 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11797 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
11798 CHECK_ALIVE(VisitForValue(call->arguments()->at(2)));
11799 HValue* string = Pop();
11800 HValue* value = Pop();
11801 HValue* index = Pop();
11802 Add<HSeqStringSetChar>(String::ONE_BYTE_ENCODING, string,
11803 index, value);
11804 Add<HSimulate>(call->id(), FIXED_SIMULATE);
11805 return ast_context()->ReturnValue(graph()->GetConstantUndefined());
11806}
11807
11808
11809void HOptimizedGraphBuilder::GenerateTwoByteSeqStringSetChar(
11810 CallRuntime* call) {
11811 DCHECK(call->arguments()->length() == 3);
11812 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11813 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
11814 CHECK_ALIVE(VisitForValue(call->arguments()->at(2)));
11815 HValue* string = Pop();
11816 HValue* value = Pop();
11817 HValue* index = Pop();
11818 Add<HSeqStringSetChar>(String::TWO_BYTE_ENCODING, string,
11819 index, value);
11820 Add<HSimulate>(call->id(), FIXED_SIMULATE);
11821 return ast_context()->ReturnValue(graph()->GetConstantUndefined());
11822}
11823
11824
11825void HOptimizedGraphBuilder::GenerateSetValueOf(CallRuntime* call) {
11826 DCHECK(call->arguments()->length() == 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011827 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11828 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
11829 HValue* value = Pop();
11830 HValue* object = Pop();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011831
11832 // Check if object is a JSValue.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011833 IfBuilder if_objectisvalue(this);
11834 if_objectisvalue.If<HHasInstanceTypeAndBranch>(object, JS_VALUE_TYPE);
11835 if_objectisvalue.Then();
11836 {
11837 // Create in-object property store to kValueOffset.
11838 Add<HStoreNamedField>(object,
11839 HObjectAccess::ForObservableJSObjectOffset(JSValue::kValueOffset),
11840 value);
11841 if (!ast_context()->IsEffect()) {
11842 Push(value);
11843 }
11844 Add<HSimulate>(call->id(), FIXED_SIMULATE);
11845 }
11846 if_objectisvalue.Else();
11847 {
11848 // Nothing to do in this case.
11849 if (!ast_context()->IsEffect()) {
11850 Push(value);
11851 }
11852 Add<HSimulate>(call->id(), FIXED_SIMULATE);
11853 }
11854 if_objectisvalue.End();
11855 if (!ast_context()->IsEffect()) {
11856 Drop(1);
11857 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011858 return ast_context()->ReturnValue(value);
Ben Murdochb0fe1622011-05-05 13:52:32 +010011859}
11860
11861
11862// Fast support for charCodeAt(n).
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011863void HOptimizedGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) {
11864 DCHECK(call->arguments()->length() == 2);
Ben Murdoch257744e2011-11-30 15:57:28 +000011865 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11866 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
Steve Block1e0659c2011-05-24 12:43:12 +010011867 HValue* index = Pop();
11868 HValue* string = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011869 HInstruction* result = BuildStringCharCodeAt(string, index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011870 return ast_context()->ReturnInstruction(result, call->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +010011871}
11872
11873
11874// Fast support for string.charAt(n) and string[n].
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011875void HOptimizedGraphBuilder::GenerateStringCharFromCode(CallRuntime* call) {
11876 DCHECK(call->arguments()->length() == 1);
Ben Murdoch257744e2011-11-30 15:57:28 +000011877 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
Steve Block44f0eee2011-05-26 01:26:41 +010011878 HValue* char_code = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011879 HInstruction* result = NewUncasted<HStringCharFromCode>(char_code);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011880 return ast_context()->ReturnInstruction(result, call->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +010011881}
11882
11883
11884// Fast support for string.charAt(n) and string[n].
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011885void HOptimizedGraphBuilder::GenerateStringCharAt(CallRuntime* call) {
11886 DCHECK(call->arguments()->length() == 2);
Ben Murdoch257744e2011-11-30 15:57:28 +000011887 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11888 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
Steve Block44f0eee2011-05-26 01:26:41 +010011889 HValue* index = Pop();
11890 HValue* string = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011891 HInstruction* char_code = BuildStringCharCodeAt(string, index);
Steve Block44f0eee2011-05-26 01:26:41 +010011892 AddInstruction(char_code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011893 HInstruction* result = NewUncasted<HStringCharFromCode>(char_code);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011894 return ast_context()->ReturnInstruction(result, call->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +010011895}
11896
11897
11898// Fast support for object equality testing.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011899void HOptimizedGraphBuilder::GenerateObjectEquals(CallRuntime* call) {
11900 DCHECK(call->arguments()->length() == 2);
Ben Murdoch257744e2011-11-30 15:57:28 +000011901 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11902 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
Ben Murdochb0fe1622011-05-05 13:52:32 +010011903 HValue* right = Pop();
11904 HValue* left = Pop();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011905 HCompareObjectEqAndBranch* result =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011906 New<HCompareObjectEqAndBranch>(left, right);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011907 return ast_context()->ReturnControl(result, call->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +010011908}
11909
11910
Ben Murdochb0fe1622011-05-05 13:52:32 +010011911// Fast support for StringAdd.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011912void HOptimizedGraphBuilder::GenerateStringAdd(CallRuntime* call) {
11913 DCHECK_EQ(2, call->arguments()->length());
11914 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11915 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
11916 HValue* right = Pop();
11917 HValue* left = Pop();
11918 HInstruction* result = NewUncasted<HStringAdd>(left, right);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011919 return ast_context()->ReturnInstruction(result, call->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +010011920}
11921
11922
11923// Fast support for SubString.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011924void HOptimizedGraphBuilder::GenerateSubString(CallRuntime* call) {
11925 DCHECK_EQ(3, call->arguments()->length());
11926 CHECK_ALIVE(VisitExpressions(call->arguments()));
11927 PushArgumentsFromEnvironment(call->arguments()->length());
11928 HCallStub* result = New<HCallStub>(CodeStub::SubString, 3);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011929 return ast_context()->ReturnInstruction(result, call->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +010011930}
11931
11932
11933// Fast support for StringCompare.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011934void HOptimizedGraphBuilder::GenerateStringCompare(CallRuntime* call) {
11935 DCHECK_EQ(2, call->arguments()->length());
11936 CHECK_ALIVE(VisitExpressions(call->arguments()));
11937 PushArgumentsFromEnvironment(call->arguments()->length());
11938 HCallStub* result = New<HCallStub>(CodeStub::StringCompare, 2);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011939 return ast_context()->ReturnInstruction(result, call->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +010011940}
11941
11942
11943// Support for direct calls from JavaScript to native RegExp code.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011944void HOptimizedGraphBuilder::GenerateRegExpExec(CallRuntime* call) {
11945 DCHECK_EQ(4, call->arguments()->length());
11946 CHECK_ALIVE(VisitExpressions(call->arguments()));
11947 PushArgumentsFromEnvironment(call->arguments()->length());
11948 HCallStub* result = New<HCallStub>(CodeStub::RegExpExec, 4);
11949 return ast_context()->ReturnInstruction(result, call->id());
11950}
11951
11952
11953void HOptimizedGraphBuilder::GenerateDoubleLo(CallRuntime* call) {
11954 DCHECK_EQ(1, call->arguments()->length());
11955 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11956 HValue* value = Pop();
11957 HInstruction* result = NewUncasted<HDoubleBits>(value, HDoubleBits::LOW);
11958 return ast_context()->ReturnInstruction(result, call->id());
11959}
11960
11961
11962void HOptimizedGraphBuilder::GenerateDoubleHi(CallRuntime* call) {
11963 DCHECK_EQ(1, call->arguments()->length());
11964 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11965 HValue* value = Pop();
11966 HInstruction* result = NewUncasted<HDoubleBits>(value, HDoubleBits::HIGH);
11967 return ast_context()->ReturnInstruction(result, call->id());
11968}
11969
11970
11971void HOptimizedGraphBuilder::GenerateConstructDouble(CallRuntime* call) {
11972 DCHECK_EQ(2, call->arguments()->length());
11973 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11974 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
11975 HValue* lo = Pop();
11976 HValue* hi = Pop();
11977 HInstruction* result = NewUncasted<HConstructDouble>(hi, lo);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011978 return ast_context()->ReturnInstruction(result, call->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +010011979}
11980
11981
11982// Construct a RegExp exec result with two in-object properties.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011983void HOptimizedGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) {
11984 DCHECK_EQ(3, call->arguments()->length());
11985 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11986 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
11987 CHECK_ALIVE(VisitForValue(call->arguments()->at(2)));
11988 HValue* input = Pop();
11989 HValue* index = Pop();
11990 HValue* length = Pop();
11991 HValue* result = BuildRegExpConstructResult(length, index, input);
11992 return ast_context()->ReturnValue(result);
Ben Murdochb0fe1622011-05-05 13:52:32 +010011993}
11994
11995
11996// Support for fast native caches.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011997void HOptimizedGraphBuilder::GenerateGetFromCache(CallRuntime* call) {
11998 return Bailout(kInlinedRuntimeFunctionGetFromCache);
Ben Murdochb0fe1622011-05-05 13:52:32 +010011999}
12000
12001
12002// Fast support for number to string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012003void HOptimizedGraphBuilder::GenerateNumberToString(CallRuntime* call) {
12004 DCHECK_EQ(1, call->arguments()->length());
12005 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12006 HValue* number = Pop();
12007 HValue* result = BuildNumberToString(number, Type::Any(zone()));
12008 return ast_context()->ReturnValue(result);
Ben Murdochb0fe1622011-05-05 13:52:32 +010012009}
12010
12011
Ben Murdochb0fe1622011-05-05 13:52:32 +010012012// Fast call for custom callbacks.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012013void HOptimizedGraphBuilder::GenerateCallFunction(CallRuntime* call) {
Ben Murdoch257744e2011-11-30 15:57:28 +000012014 // 1 ~ The function to call is not itself an argument to the call.
12015 int arg_count = call->arguments()->length() - 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012016 DCHECK(arg_count >= 1); // There's always at least a receiver.
Ben Murdoch257744e2011-11-30 15:57:28 +000012017
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012018 CHECK_ALIVE(VisitExpressions(call->arguments()));
12019 // The function is the last argument
Ben Murdoch257744e2011-11-30 15:57:28 +000012020 HValue* function = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012021 // Push the arguments to the stack
12022 PushArgumentsFromEnvironment(arg_count);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012023
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012024 IfBuilder if_is_jsfunction(this);
12025 if_is_jsfunction.If<HHasInstanceTypeAndBranch>(function, JS_FUNCTION_TYPE);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012026
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012027 if_is_jsfunction.Then();
12028 {
12029 HInstruction* invoke_result =
12030 Add<HInvokeFunction>(function, arg_count);
12031 if (!ast_context()->IsEffect()) {
12032 Push(invoke_result);
12033 }
12034 Add<HSimulate>(call->id(), FIXED_SIMULATE);
12035 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012036
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012037 if_is_jsfunction.Else();
12038 {
12039 HInstruction* call_result =
12040 Add<HCallFunction>(function, arg_count);
12041 if (!ast_context()->IsEffect()) {
12042 Push(call_result);
12043 }
12044 Add<HSimulate>(call->id(), FIXED_SIMULATE);
12045 }
12046 if_is_jsfunction.End();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012047
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012048 if (ast_context()->IsEffect()) {
12049 // EffectContext::ReturnValue ignores the value, so we can just pass
12050 // 'undefined' (as we do not have the call result anymore).
12051 return ast_context()->ReturnValue(graph()->GetConstantUndefined());
12052 } else {
12053 return ast_context()->ReturnValue(Pop());
12054 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010012055}
12056
12057
12058// Fast call to math functions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012059void HOptimizedGraphBuilder::GenerateMathPow(CallRuntime* call) {
12060 DCHECK_EQ(2, call->arguments()->length());
Ben Murdoch257744e2011-11-30 15:57:28 +000012061 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12062 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
Ben Murdochb0fe1622011-05-05 13:52:32 +010012063 HValue* right = Pop();
12064 HValue* left = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012065 HInstruction* result = NewUncasted<HPower>(left, right);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012066 return ast_context()->ReturnInstruction(result, call->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +010012067}
12068
12069
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012070void HOptimizedGraphBuilder::GenerateMathLogRT(CallRuntime* call) {
12071 DCHECK(call->arguments()->length() == 1);
Ben Murdoch257744e2011-11-30 15:57:28 +000012072 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012073 HValue* value = Pop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012074 HInstruction* result = NewUncasted<HUnaryMathOperation>(value, kMathLog);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012075 return ast_context()->ReturnInstruction(result, call->id());
Ben Murdochb0fe1622011-05-05 13:52:32 +010012076}
12077
12078
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012079void HOptimizedGraphBuilder::GenerateMathSqrtRT(CallRuntime* call) {
12080 DCHECK(call->arguments()->length() == 1);
12081 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12082 HValue* value = Pop();
12083 HInstruction* result = NewUncasted<HUnaryMathOperation>(value, kMathSqrt);
12084 return ast_context()->ReturnInstruction(result, call->id());
12085}
12086
12087
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012088HValue* HOptimizedGraphBuilder::BuildOrderedHashTableHashToBucket(
12089 HValue* hash, HValue* num_buckets) {
12090 HValue* mask = AddUncasted<HSub>(num_buckets, graph()->GetConstant1());
12091 mask->ChangeRepresentation(Representation::Integer32());
12092 mask->ClearFlag(HValue::kCanOverflow);
12093 return AddUncasted<HBitwise>(Token::BIT_AND, hash, mask);
12094}
12095
12096
12097template <typename CollectionType>
12098HValue* HOptimizedGraphBuilder::BuildOrderedHashTableHashToEntry(
12099 HValue* table, HValue* hash, HValue* num_buckets) {
12100 HValue* bucket = BuildOrderedHashTableHashToBucket(hash, num_buckets);
12101 HValue* entry_index = AddUncasted<HAdd>(
12102 bucket, Add<HConstant>(CollectionType::kHashTableStartIndex));
12103 entry_index->ClearFlag(HValue::kCanOverflow);
12104 HValue* entry = Add<HLoadKeyed>(table, entry_index, nullptr, FAST_ELEMENTS);
12105 entry->set_type(HType::Smi());
12106 return entry;
12107}
12108
12109
12110template <typename CollectionType>
12111HValue* HOptimizedGraphBuilder::BuildOrderedHashTableEntryToIndex(
12112 HValue* entry, HValue* num_buckets) {
12113 HValue* index =
12114 AddUncasted<HMul>(entry, Add<HConstant>(CollectionType::kEntrySize));
12115 index->ClearFlag(HValue::kCanOverflow);
12116 index = AddUncasted<HAdd>(index, num_buckets);
12117 index->ClearFlag(HValue::kCanOverflow);
12118 index = AddUncasted<HAdd>(
12119 index, Add<HConstant>(CollectionType::kHashTableStartIndex));
12120 index->ClearFlag(HValue::kCanOverflow);
12121 return index;
12122}
12123
12124
12125template <typename CollectionType>
12126HValue* HOptimizedGraphBuilder::BuildOrderedHashTableFindEntry(HValue* table,
12127 HValue* key,
12128 HValue* hash) {
12129 HValue* num_buckets = Add<HLoadNamedField>(
12130 table, nullptr,
12131 HObjectAccess::ForOrderedHashTableNumberOfBuckets<CollectionType>());
12132
12133 HValue* entry = BuildOrderedHashTableHashToEntry<CollectionType>(table, hash,
12134 num_buckets);
12135
12136 Push(entry);
12137
12138 LoopBuilder loop(this);
12139 loop.BeginBody(1);
12140
12141 entry = Pop();
12142
12143 {
12144 IfBuilder if_not_found(this);
12145 if_not_found.If<HCompareNumericAndBranch>(
12146 entry, Add<HConstant>(CollectionType::kNotFound), Token::EQ);
12147 if_not_found.Then();
12148 Push(entry);
12149 loop.Break();
12150 }
12151
12152 HValue* key_index =
12153 BuildOrderedHashTableEntryToIndex<CollectionType>(entry, num_buckets);
12154 HValue* candidate_key =
12155 Add<HLoadKeyed>(table, key_index, nullptr, FAST_ELEMENTS);
12156
12157 {
12158 IfBuilder if_keys_equal(this);
12159 if_keys_equal.If<HIsStringAndBranch>(candidate_key);
12160 if_keys_equal.AndIf<HStringCompareAndBranch>(candidate_key, key,
12161 Token::EQ_STRICT);
12162 if_keys_equal.Then();
12163 Push(key_index);
12164 loop.Break();
12165 }
12166
12167 // BuildChainAt
12168 HValue* chain_index = AddUncasted<HAdd>(
12169 key_index, Add<HConstant>(CollectionType::kChainOffset));
12170 chain_index->ClearFlag(HValue::kCanOverflow);
12171 entry = Add<HLoadKeyed>(table, chain_index, nullptr, FAST_ELEMENTS);
12172 entry->set_type(HType::Smi());
12173 Push(entry);
12174
12175 loop.EndBody();
12176
12177 return Pop();
12178}
12179
12180
12181void HOptimizedGraphBuilder::GenerateMapGet(CallRuntime* call) {
12182 DCHECK(call->arguments()->length() == 2);
12183 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12184 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
12185 HValue* key = Pop();
12186 HValue* receiver = Pop();
12187
12188 NoObservableSideEffectsScope no_effects(this);
12189
12190 HIfContinuation continuation;
12191 HValue* hash =
12192 BuildStringHashLoadIfIsStringAndHashComputed(key, &continuation);
12193 {
12194 IfBuilder string_checker(this, &continuation);
12195 string_checker.Then();
12196 {
12197 HValue* table = Add<HLoadNamedField>(
12198 receiver, nullptr, HObjectAccess::ForJSCollectionTable());
12199 HValue* key_index =
12200 BuildOrderedHashTableFindEntry<OrderedHashMap>(table, key, hash);
12201 IfBuilder if_found(this);
12202 if_found.If<HCompareNumericAndBranch>(
12203 key_index, Add<HConstant>(OrderedHashMap::kNotFound), Token::NE);
12204 if_found.Then();
12205 {
12206 HValue* value_index = AddUncasted<HAdd>(
12207 key_index, Add<HConstant>(OrderedHashMap::kValueOffset));
12208 value_index->ClearFlag(HValue::kCanOverflow);
12209 Push(Add<HLoadKeyed>(table, value_index, nullptr, FAST_ELEMENTS));
12210 }
12211 if_found.Else();
12212 Push(graph()->GetConstantUndefined());
12213 if_found.End();
12214 }
12215 string_checker.Else();
12216 {
12217 Add<HPushArguments>(receiver, key);
12218 Push(Add<HCallRuntime>(call->name(),
12219 Runtime::FunctionForId(Runtime::kMapGet), 2));
12220 }
12221 }
12222
12223 return ast_context()->ReturnValue(Pop());
12224}
12225
12226
12227HValue* HOptimizedGraphBuilder::BuildStringHashLoadIfIsStringAndHashComputed(
12228 HValue* object, HIfContinuation* continuation) {
12229 IfBuilder string_checker(this);
12230 string_checker.If<HIsStringAndBranch>(object);
12231 string_checker.And();
12232 HValue* hash = Add<HLoadNamedField>(object, nullptr,
12233 HObjectAccess::ForStringHashField());
12234 HValue* hash_not_computed_mask = Add<HConstant>(String::kHashNotComputedMask);
12235 HValue* hash_computed_test =
12236 AddUncasted<HBitwise>(Token::BIT_AND, hash, hash_not_computed_mask);
12237 string_checker.If<HCompareNumericAndBranch>(
12238 hash_computed_test, graph()->GetConstant0(), Token::EQ);
12239 string_checker.Then();
12240 HValue* shifted_hash =
12241 AddUncasted<HShr>(hash, Add<HConstant>(String::kHashShift));
12242 string_checker.CaptureContinuation(continuation);
12243 return shifted_hash;
12244}
12245
12246
12247template <typename CollectionType>
12248void HOptimizedGraphBuilder::BuildJSCollectionHas(
12249 CallRuntime* call, const Runtime::Function* c_function) {
12250 DCHECK(call->arguments()->length() == 2);
12251 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12252 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
12253 HValue* key = Pop();
12254 HValue* receiver = Pop();
12255
12256 NoObservableSideEffectsScope no_effects(this);
12257
12258 HIfContinuation continuation;
12259 HValue* hash =
12260 BuildStringHashLoadIfIsStringAndHashComputed(key, &continuation);
12261 {
12262 IfBuilder string_checker(this, &continuation);
12263 string_checker.Then();
12264 {
12265 HValue* table = Add<HLoadNamedField>(
12266 receiver, nullptr, HObjectAccess::ForJSCollectionTable());
12267 HValue* key_index =
12268 BuildOrderedHashTableFindEntry<CollectionType>(table, key, hash);
12269 {
12270 IfBuilder if_found(this);
12271 if_found.If<HCompareNumericAndBranch>(
12272 key_index, Add<HConstant>(CollectionType::kNotFound), Token::NE);
12273 if_found.Then();
12274 Push(graph()->GetConstantTrue());
12275 if_found.Else();
12276 Push(graph()->GetConstantFalse());
12277 }
12278 }
12279 string_checker.Else();
12280 {
12281 Add<HPushArguments>(receiver, key);
12282 Push(Add<HCallRuntime>(call->name(), c_function, 2));
12283 }
12284 }
12285
12286 return ast_context()->ReturnValue(Pop());
12287}
12288
12289
12290void HOptimizedGraphBuilder::GenerateMapHas(CallRuntime* call) {
12291 BuildJSCollectionHas<OrderedHashMap>(
12292 call, Runtime::FunctionForId(Runtime::kMapHas));
12293}
12294
12295
12296void HOptimizedGraphBuilder::GenerateSetHas(CallRuntime* call) {
12297 BuildJSCollectionHas<OrderedHashSet>(
12298 call, Runtime::FunctionForId(Runtime::kSetHas));
12299}
12300
12301
12302template <typename CollectionType>
12303HValue* HOptimizedGraphBuilder::BuildOrderedHashTableAddEntry(
12304 HValue* table, HValue* key, HValue* hash,
12305 HIfContinuation* join_continuation) {
12306 HValue* num_buckets = Add<HLoadNamedField>(
12307 table, nullptr,
12308 HObjectAccess::ForOrderedHashTableNumberOfBuckets<CollectionType>());
12309 HValue* capacity = AddUncasted<HMul>(
12310 num_buckets, Add<HConstant>(CollectionType::kLoadFactor));
12311 capacity->ClearFlag(HValue::kCanOverflow);
12312 HValue* num_elements = Add<HLoadNamedField>(
12313 table, nullptr,
12314 HObjectAccess::ForOrderedHashTableNumberOfElements<CollectionType>());
12315 HValue* num_deleted = Add<HLoadNamedField>(
12316 table, nullptr, HObjectAccess::ForOrderedHashTableNumberOfDeletedElements<
12317 CollectionType>());
12318 HValue* used = AddUncasted<HAdd>(num_elements, num_deleted);
12319 used->ClearFlag(HValue::kCanOverflow);
12320 IfBuilder if_space_available(this);
12321 if_space_available.If<HCompareNumericAndBranch>(capacity, used, Token::GT);
12322 if_space_available.Then();
12323 HValue* bucket = BuildOrderedHashTableHashToBucket(hash, num_buckets);
12324 HValue* entry = used;
12325 HValue* key_index =
12326 BuildOrderedHashTableEntryToIndex<CollectionType>(entry, num_buckets);
12327
12328 HValue* bucket_index = AddUncasted<HAdd>(
12329 bucket, Add<HConstant>(CollectionType::kHashTableStartIndex));
12330 bucket_index->ClearFlag(HValue::kCanOverflow);
12331 HValue* chain_entry =
12332 Add<HLoadKeyed>(table, bucket_index, nullptr, FAST_ELEMENTS);
12333 chain_entry->set_type(HType::Smi());
12334
12335 HValue* chain_index = AddUncasted<HAdd>(
12336 key_index, Add<HConstant>(CollectionType::kChainOffset));
12337 chain_index->ClearFlag(HValue::kCanOverflow);
12338
12339 Add<HStoreKeyed>(table, bucket_index, entry, FAST_ELEMENTS);
12340 Add<HStoreKeyed>(table, chain_index, chain_entry, FAST_ELEMENTS);
12341 Add<HStoreKeyed>(table, key_index, key, FAST_ELEMENTS);
12342
12343 HValue* new_num_elements =
12344 AddUncasted<HAdd>(num_elements, graph()->GetConstant1());
12345 new_num_elements->ClearFlag(HValue::kCanOverflow);
12346 Add<HStoreNamedField>(
12347 table,
12348 HObjectAccess::ForOrderedHashTableNumberOfElements<CollectionType>(),
12349 new_num_elements);
12350 if_space_available.JoinContinuation(join_continuation);
12351 return key_index;
12352}
12353
12354
12355void HOptimizedGraphBuilder::GenerateMapSet(CallRuntime* call) {
12356 DCHECK(call->arguments()->length() == 3);
12357 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12358 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
12359 CHECK_ALIVE(VisitForValue(call->arguments()->at(2)));
12360 HValue* value = Pop();
12361 HValue* key = Pop();
12362 HValue* receiver = Pop();
12363
12364 NoObservableSideEffectsScope no_effects(this);
12365
12366 HIfContinuation return_or_call_runtime_continuation(
12367 graph()->CreateBasicBlock(), graph()->CreateBasicBlock());
12368 HIfContinuation got_string_hash;
12369 HValue* hash =
12370 BuildStringHashLoadIfIsStringAndHashComputed(key, &got_string_hash);
12371 IfBuilder string_checker(this, &got_string_hash);
12372 string_checker.Then();
12373 {
12374 HValue* table = Add<HLoadNamedField>(receiver, nullptr,
12375 HObjectAccess::ForJSCollectionTable());
12376 HValue* key_index =
12377 BuildOrderedHashTableFindEntry<OrderedHashMap>(table, key, hash);
12378 {
12379 IfBuilder if_found(this);
12380 if_found.If<HCompareNumericAndBranch>(
12381 key_index, Add<HConstant>(OrderedHashMap::kNotFound), Token::NE);
12382 if_found.Then();
12383 {
12384 HValue* value_index = AddUncasted<HAdd>(
12385 key_index, Add<HConstant>(OrderedHashMap::kValueOffset));
12386 value_index->ClearFlag(HValue::kCanOverflow);
12387 Add<HStoreKeyed>(table, value_index, value, FAST_ELEMENTS);
12388 }
12389 if_found.Else();
12390 {
12391 HIfContinuation did_add(graph()->CreateBasicBlock(),
12392 graph()->CreateBasicBlock());
12393 HValue* key_index = BuildOrderedHashTableAddEntry<OrderedHashMap>(
12394 table, key, hash, &did_add);
12395 IfBuilder if_did_add(this, &did_add);
12396 if_did_add.Then();
12397 {
12398 HValue* value_index = AddUncasted<HAdd>(
12399 key_index, Add<HConstant>(OrderedHashMap::kValueOffset));
12400 value_index->ClearFlag(HValue::kCanOverflow);
12401 Add<HStoreKeyed>(table, value_index, value, FAST_ELEMENTS);
12402 }
12403 if_did_add.JoinContinuation(&return_or_call_runtime_continuation);
12404 }
12405 }
12406 }
12407 string_checker.JoinContinuation(&return_or_call_runtime_continuation);
12408
12409 {
12410 IfBuilder return_or_call_runtime(this,
12411 &return_or_call_runtime_continuation);
12412 return_or_call_runtime.Then();
12413 Push(receiver);
12414 return_or_call_runtime.Else();
12415 Add<HPushArguments>(receiver, key, value);
12416 Push(Add<HCallRuntime>(call->name(),
12417 Runtime::FunctionForId(Runtime::kMapSet), 3));
12418 }
12419
12420 return ast_context()->ReturnValue(Pop());
12421}
12422
12423
12424void HOptimizedGraphBuilder::GenerateSetAdd(CallRuntime* call) {
12425 DCHECK(call->arguments()->length() == 2);
12426 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12427 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
12428 HValue* key = Pop();
12429 HValue* receiver = Pop();
12430
12431 NoObservableSideEffectsScope no_effects(this);
12432
12433 HIfContinuation return_or_call_runtime_continuation(
12434 graph()->CreateBasicBlock(), graph()->CreateBasicBlock());
12435 HIfContinuation got_string_hash;
12436 HValue* hash =
12437 BuildStringHashLoadIfIsStringAndHashComputed(key, &got_string_hash);
12438 IfBuilder string_checker(this, &got_string_hash);
12439 string_checker.Then();
12440 {
12441 HValue* table = Add<HLoadNamedField>(receiver, nullptr,
12442 HObjectAccess::ForJSCollectionTable());
12443 HValue* key_index =
12444 BuildOrderedHashTableFindEntry<OrderedHashSet>(table, key, hash);
12445 {
12446 IfBuilder if_not_found(this);
12447 if_not_found.If<HCompareNumericAndBranch>(
12448 key_index, Add<HConstant>(OrderedHashSet::kNotFound), Token::EQ);
12449 if_not_found.Then();
12450 BuildOrderedHashTableAddEntry<OrderedHashSet>(
12451 table, key, hash, &return_or_call_runtime_continuation);
12452 }
12453 }
12454 string_checker.JoinContinuation(&return_or_call_runtime_continuation);
12455
12456 {
12457 IfBuilder return_or_call_runtime(this,
12458 &return_or_call_runtime_continuation);
12459 return_or_call_runtime.Then();
12460 Push(receiver);
12461 return_or_call_runtime.Else();
12462 Add<HPushArguments>(receiver, key);
12463 Push(Add<HCallRuntime>(call->name(),
12464 Runtime::FunctionForId(Runtime::kSetAdd), 2));
12465 }
12466
12467 return ast_context()->ReturnValue(Pop());
12468}
12469
12470
12471template <typename CollectionType>
12472void HOptimizedGraphBuilder::BuildJSCollectionDelete(
12473 CallRuntime* call, const Runtime::Function* c_function) {
12474 DCHECK(call->arguments()->length() == 2);
12475 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12476 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
12477 HValue* key = Pop();
12478 HValue* receiver = Pop();
12479
12480 NoObservableSideEffectsScope no_effects(this);
12481
12482 HIfContinuation return_or_call_runtime_continuation(
12483 graph()->CreateBasicBlock(), graph()->CreateBasicBlock());
12484 HIfContinuation got_string_hash;
12485 HValue* hash =
12486 BuildStringHashLoadIfIsStringAndHashComputed(key, &got_string_hash);
12487 IfBuilder string_checker(this, &got_string_hash);
12488 string_checker.Then();
12489 {
12490 HValue* table = Add<HLoadNamedField>(receiver, nullptr,
12491 HObjectAccess::ForJSCollectionTable());
12492 HValue* key_index =
12493 BuildOrderedHashTableFindEntry<CollectionType>(table, key, hash);
12494 {
12495 IfBuilder if_found(this);
12496 if_found.If<HCompareNumericAndBranch>(
12497 key_index, Add<HConstant>(CollectionType::kNotFound), Token::NE);
12498 if_found.Then();
12499 {
12500 // If we're removing an element, we might need to shrink.
12501 // If we do need to shrink, we'll be bailing out to the runtime.
12502 HValue* num_elements = Add<HLoadNamedField>(
12503 table, nullptr, HObjectAccess::ForOrderedHashTableNumberOfElements<
12504 CollectionType>());
12505 num_elements = AddUncasted<HSub>(num_elements, graph()->GetConstant1());
12506 num_elements->ClearFlag(HValue::kCanOverflow);
12507
12508 HValue* num_buckets = Add<HLoadNamedField>(
12509 table, nullptr, HObjectAccess::ForOrderedHashTableNumberOfBuckets<
12510 CollectionType>());
12511 // threshold is capacity >> 2; we simplify this to num_buckets >> 1
12512 // since kLoadFactor is 2.
12513 STATIC_ASSERT(CollectionType::kLoadFactor == 2);
12514 HValue* threshold =
12515 AddUncasted<HShr>(num_buckets, graph()->GetConstant1());
12516
12517 IfBuilder if_need_not_shrink(this);
12518 if_need_not_shrink.If<HCompareNumericAndBranch>(num_elements, threshold,
12519 Token::GTE);
12520 if_need_not_shrink.Then();
12521 {
12522 Add<HStoreKeyed>(table, key_index, graph()->GetConstantHole(),
12523 FAST_ELEMENTS);
12524
12525 // For maps, also need to clear the value.
12526 if (CollectionType::kChainOffset > 1) {
12527 HValue* value_index =
12528 AddUncasted<HAdd>(key_index, graph()->GetConstant1());
12529 value_index->ClearFlag(HValue::kCanOverflow);
12530 Add<HStoreKeyed>(table, value_index, graph()->GetConstantHole(),
12531 FAST_ELEMENTS);
12532 }
12533 STATIC_ASSERT(CollectionType::kChainOffset <= 2);
12534
12535 HValue* num_deleted = Add<HLoadNamedField>(
12536 table, nullptr,
12537 HObjectAccess::ForOrderedHashTableNumberOfDeletedElements<
12538 CollectionType>());
12539 num_deleted = AddUncasted<HAdd>(num_deleted, graph()->GetConstant1());
12540 num_deleted->ClearFlag(HValue::kCanOverflow);
12541 Add<HStoreNamedField>(
12542 table, HObjectAccess::ForOrderedHashTableNumberOfElements<
12543 CollectionType>(),
12544 num_elements);
12545 Add<HStoreNamedField>(
12546 table, HObjectAccess::ForOrderedHashTableNumberOfDeletedElements<
12547 CollectionType>(),
12548 num_deleted);
12549 Push(graph()->GetConstantTrue());
12550 }
12551 if_need_not_shrink.JoinContinuation(
12552 &return_or_call_runtime_continuation);
12553 }
12554 if_found.Else();
12555 {
12556 // Not found, so we're done.
12557 Push(graph()->GetConstantFalse());
12558 }
12559 }
12560 }
12561 string_checker.JoinContinuation(&return_or_call_runtime_continuation);
12562
12563 {
12564 IfBuilder return_or_call_runtime(this,
12565 &return_or_call_runtime_continuation);
12566 return_or_call_runtime.Then();
12567 return_or_call_runtime.Else();
12568 Add<HPushArguments>(receiver, key);
12569 Push(Add<HCallRuntime>(call->name(), c_function, 2));
12570 }
12571
12572 return ast_context()->ReturnValue(Pop());
12573}
12574
12575
12576void HOptimizedGraphBuilder::GenerateMapDelete(CallRuntime* call) {
12577 BuildJSCollectionDelete<OrderedHashMap>(
12578 call, Runtime::FunctionForId(Runtime::kMapDelete));
12579}
12580
12581
12582void HOptimizedGraphBuilder::GenerateSetDelete(CallRuntime* call) {
12583 BuildJSCollectionDelete<OrderedHashSet>(
12584 call, Runtime::FunctionForId(Runtime::kSetDelete));
12585}
12586
12587
12588void HOptimizedGraphBuilder::GenerateSetGetSize(CallRuntime* call) {
12589 DCHECK(call->arguments()->length() == 1);
12590 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12591 HValue* receiver = Pop();
12592 HValue* table = Add<HLoadNamedField>(receiver, nullptr,
12593 HObjectAccess::ForJSCollectionTable());
12594 HInstruction* result = New<HLoadNamedField>(
12595 table, nullptr,
12596 HObjectAccess::ForOrderedHashTableNumberOfElements<OrderedHashSet>());
12597 return ast_context()->ReturnInstruction(result, call->id());
12598}
12599
12600
12601void HOptimizedGraphBuilder::GenerateMapGetSize(CallRuntime* call) {
12602 DCHECK(call->arguments()->length() == 1);
12603 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12604 HValue* receiver = Pop();
12605 HValue* table = Add<HLoadNamedField>(receiver, nullptr,
12606 HObjectAccess::ForJSCollectionTable());
12607 HInstruction* result = New<HLoadNamedField>(
12608 table, nullptr,
12609 HObjectAccess::ForOrderedHashTableNumberOfElements<OrderedHashMap>());
12610 return ast_context()->ReturnInstruction(result, call->id());
12611}
12612
12613
12614template <typename CollectionType>
12615HValue* HOptimizedGraphBuilder::BuildAllocateOrderedHashTable() {
12616 static const int kCapacity = CollectionType::kMinCapacity;
12617 static const int kBucketCount = kCapacity / CollectionType::kLoadFactor;
12618 static const int kFixedArrayLength = CollectionType::kHashTableStartIndex +
12619 kBucketCount +
12620 (kCapacity * CollectionType::kEntrySize);
12621 static const int kSizeInBytes =
12622 FixedArray::kHeaderSize + (kFixedArrayLength * kPointerSize);
12623
12624 // Allocate the table and add the proper map.
12625 HValue* table =
12626 Add<HAllocate>(Add<HConstant>(kSizeInBytes), HType::HeapObject(),
12627 NOT_TENURED, FIXED_ARRAY_TYPE);
12628 AddStoreMapConstant(table, isolate()->factory()->ordered_hash_table_map());
12629
12630 // Initialize the FixedArray...
12631 HValue* length = Add<HConstant>(kFixedArrayLength);
12632 Add<HStoreNamedField>(table, HObjectAccess::ForFixedArrayLength(), length);
12633
12634 // ...and the OrderedHashTable fields.
12635 Add<HStoreNamedField>(
12636 table,
12637 HObjectAccess::ForOrderedHashTableNumberOfBuckets<CollectionType>(),
12638 Add<HConstant>(kBucketCount));
12639 Add<HStoreNamedField>(
12640 table,
12641 HObjectAccess::ForOrderedHashTableNumberOfElements<CollectionType>(),
12642 graph()->GetConstant0());
12643 Add<HStoreNamedField>(
12644 table, HObjectAccess::ForOrderedHashTableNumberOfDeletedElements<
12645 CollectionType>(),
12646 graph()->GetConstant0());
12647
12648 // Fill the buckets with kNotFound.
12649 HValue* not_found = Add<HConstant>(CollectionType::kNotFound);
12650 for (int i = 0; i < kBucketCount; ++i) {
12651 Add<HStoreNamedField>(
12652 table, HObjectAccess::ForOrderedHashTableBucket<CollectionType>(i),
12653 not_found);
12654 }
12655
12656 // Fill the data table with undefined.
12657 HValue* undefined = graph()->GetConstantUndefined();
12658 for (int i = 0; i < (kCapacity * CollectionType::kEntrySize); ++i) {
12659 Add<HStoreNamedField>(table,
12660 HObjectAccess::ForOrderedHashTableDataTableIndex<
12661 CollectionType, kBucketCount>(i),
12662 undefined);
12663 }
12664
12665 return table;
12666}
12667
12668
12669void HOptimizedGraphBuilder::GenerateSetInitialize(CallRuntime* call) {
12670 DCHECK(call->arguments()->length() == 1);
12671 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12672 HValue* receiver = Pop();
12673
12674 NoObservableSideEffectsScope no_effects(this);
12675 HValue* table = BuildAllocateOrderedHashTable<OrderedHashSet>();
12676 Add<HStoreNamedField>(receiver, HObjectAccess::ForJSCollectionTable(), table);
12677 return ast_context()->ReturnValue(receiver);
12678}
12679
12680
12681void HOptimizedGraphBuilder::GenerateMapInitialize(CallRuntime* call) {
12682 DCHECK(call->arguments()->length() == 1);
12683 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12684 HValue* receiver = Pop();
12685
12686 NoObservableSideEffectsScope no_effects(this);
12687 HValue* table = BuildAllocateOrderedHashTable<OrderedHashMap>();
12688 Add<HStoreNamedField>(receiver, HObjectAccess::ForJSCollectionTable(), table);
12689 return ast_context()->ReturnValue(receiver);
12690}
12691
12692
12693template <typename CollectionType>
12694void HOptimizedGraphBuilder::BuildOrderedHashTableClear(HValue* receiver) {
12695 HValue* old_table = Add<HLoadNamedField>(
12696 receiver, nullptr, HObjectAccess::ForJSCollectionTable());
12697 HValue* new_table = BuildAllocateOrderedHashTable<CollectionType>();
12698 Add<HStoreNamedField>(
12699 old_table, HObjectAccess::ForOrderedHashTableNextTable<CollectionType>(),
12700 new_table);
12701 Add<HStoreNamedField>(
12702 old_table, HObjectAccess::ForOrderedHashTableNumberOfDeletedElements<
12703 CollectionType>(),
12704 Add<HConstant>(CollectionType::kClearedTableSentinel));
12705 Add<HStoreNamedField>(receiver, HObjectAccess::ForJSCollectionTable(),
12706 new_table);
12707}
12708
12709
12710void HOptimizedGraphBuilder::GenerateSetClear(CallRuntime* call) {
12711 DCHECK(call->arguments()->length() == 1);
12712 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12713 HValue* receiver = Pop();
12714
12715 NoObservableSideEffectsScope no_effects(this);
12716 BuildOrderedHashTableClear<OrderedHashSet>(receiver);
12717 return ast_context()->ReturnValue(graph()->GetConstantUndefined());
12718}
12719
12720
12721void HOptimizedGraphBuilder::GenerateMapClear(CallRuntime* call) {
12722 DCHECK(call->arguments()->length() == 1);
12723 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12724 HValue* receiver = Pop();
12725
12726 NoObservableSideEffectsScope no_effects(this);
12727 BuildOrderedHashTableClear<OrderedHashMap>(receiver);
12728 return ast_context()->ReturnValue(graph()->GetConstantUndefined());
12729}
12730
12731
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012732void HOptimizedGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) {
12733 DCHECK(call->arguments()->length() == 1);
12734 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12735 HValue* value = Pop();
12736 HGetCachedArrayIndex* result = New<HGetCachedArrayIndex>(value);
12737 return ast_context()->ReturnInstruction(result, call->id());
12738}
12739
12740
12741void HOptimizedGraphBuilder::GenerateFastOneByteArrayJoin(CallRuntime* call) {
12742 return Bailout(kInlinedRuntimeFunctionFastOneByteArrayJoin);
12743}
12744
12745
12746// Support for generators.
12747void HOptimizedGraphBuilder::GenerateGeneratorNext(CallRuntime* call) {
12748 return Bailout(kInlinedRuntimeFunctionGeneratorNext);
12749}
12750
12751
12752void HOptimizedGraphBuilder::GenerateGeneratorThrow(CallRuntime* call) {
12753 return Bailout(kInlinedRuntimeFunctionGeneratorThrow);
12754}
12755
12756
12757void HOptimizedGraphBuilder::GenerateDebugBreakInOptimizedCode(
12758 CallRuntime* call) {
12759 Add<HDebugBreak>();
12760 return ast_context()->ReturnValue(graph()->GetConstant0());
12761}
12762
12763
12764void HOptimizedGraphBuilder::GenerateDebugIsActive(CallRuntime* call) {
12765 DCHECK(call->arguments()->length() == 0);
12766 HValue* ref =
12767 Add<HConstant>(ExternalReference::debug_is_active_address(isolate()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012768 HValue* value =
12769 Add<HLoadNamedField>(ref, nullptr, HObjectAccess::ForExternalUInteger8());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012770 return ast_context()->ReturnValue(value);
Ben Murdochb0fe1622011-05-05 13:52:32 +010012771}
12772
12773
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012774void HOptimizedGraphBuilder::GenerateGetPrototype(CallRuntime* call) {
12775 DCHECK(call->arguments()->length() == 1);
12776 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
12777 HValue* object = Pop();
12778
12779 NoObservableSideEffectsScope no_effects(this);
12780
12781 HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap());
12782 HValue* bit_field =
12783 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField());
12784 HValue* is_access_check_needed_mask =
12785 Add<HConstant>(1 << Map::kIsAccessCheckNeeded);
12786 HValue* is_access_check_needed_test = AddUncasted<HBitwise>(
12787 Token::BIT_AND, bit_field, is_access_check_needed_mask);
12788
12789 HValue* proto =
12790 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForPrototype());
12791 HValue* proto_map =
12792 Add<HLoadNamedField>(proto, nullptr, HObjectAccess::ForMap());
12793 HValue* proto_bit_field =
12794 Add<HLoadNamedField>(proto_map, nullptr, HObjectAccess::ForMapBitField());
12795 HValue* is_hidden_prototype_mask =
12796 Add<HConstant>(1 << Map::kIsHiddenPrototype);
12797 HValue* is_hidden_prototype_test = AddUncasted<HBitwise>(
12798 Token::BIT_AND, proto_bit_field, is_hidden_prototype_mask);
12799
12800 {
12801 IfBuilder needs_runtime(this);
12802 needs_runtime.If<HCompareNumericAndBranch>(
12803 is_access_check_needed_test, graph()->GetConstant0(), Token::NE);
12804 needs_runtime.OrIf<HCompareNumericAndBranch>(
12805 is_hidden_prototype_test, graph()->GetConstant0(), Token::NE);
12806
12807 needs_runtime.Then();
12808 {
12809 Add<HPushArguments>(object);
12810 Push(Add<HCallRuntime>(
12811 call->name(), Runtime::FunctionForId(Runtime::kGetPrototype), 1));
12812 }
12813
12814 needs_runtime.Else();
12815 Push(proto);
12816 }
12817 return ast_context()->ReturnValue(Pop());
12818}
12819
12820
Ben Murdochb0fe1622011-05-05 13:52:32 +010012821#undef CHECK_BAILOUT
Ben Murdoch257744e2011-11-30 15:57:28 +000012822#undef CHECK_ALIVE
Ben Murdochb0fe1622011-05-05 13:52:32 +010012823
12824
12825HEnvironment::HEnvironment(HEnvironment* outer,
12826 Scope* scope,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012827 Handle<JSFunction> closure,
12828 Zone* zone)
Ben Murdochb0fe1622011-05-05 13:52:32 +010012829 : closure_(closure),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012830 values_(0, zone),
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012831 frame_type_(JS_FUNCTION),
Ben Murdochb0fe1622011-05-05 13:52:32 +010012832 parameter_count_(0),
Ben Murdoch257744e2011-11-30 15:57:28 +000012833 specials_count_(1),
Ben Murdochb0fe1622011-05-05 13:52:32 +010012834 local_count_(0),
12835 outer_(outer),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012836 entry_(NULL),
Ben Murdochb0fe1622011-05-05 13:52:32 +010012837 pop_count_(0),
12838 push_count_(0),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012839 ast_id_(BailoutId::None()),
12840 zone_(zone) {
12841 Scope* declaration_scope = scope->DeclarationScope();
12842 Initialize(declaration_scope->num_parameters() + 1,
12843 declaration_scope->num_stack_slots(), 0);
Ben Murdochb0fe1622011-05-05 13:52:32 +010012844}
12845
12846
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012847HEnvironment::HEnvironment(Zone* zone, int parameter_count)
12848 : values_(0, zone),
12849 frame_type_(STUB),
12850 parameter_count_(parameter_count),
Ben Murdoch257744e2011-11-30 15:57:28 +000012851 specials_count_(1),
Ben Murdochb0fe1622011-05-05 13:52:32 +010012852 local_count_(0),
12853 outer_(NULL),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012854 entry_(NULL),
Ben Murdochb0fe1622011-05-05 13:52:32 +010012855 pop_count_(0),
12856 push_count_(0),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012857 ast_id_(BailoutId::None()),
12858 zone_(zone) {
12859 Initialize(parameter_count, 0, 0);
12860}
12861
12862
12863HEnvironment::HEnvironment(const HEnvironment* other, Zone* zone)
12864 : values_(0, zone),
12865 frame_type_(JS_FUNCTION),
12866 parameter_count_(0),
12867 specials_count_(0),
12868 local_count_(0),
12869 outer_(NULL),
12870 entry_(NULL),
12871 pop_count_(0),
12872 push_count_(0),
12873 ast_id_(other->ast_id()),
12874 zone_(zone) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010012875 Initialize(other);
12876}
12877
12878
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012879HEnvironment::HEnvironment(HEnvironment* outer,
12880 Handle<JSFunction> closure,
12881 FrameType frame_type,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012882 int arguments,
12883 Zone* zone)
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012884 : closure_(closure),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012885 values_(arguments, zone),
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012886 frame_type_(frame_type),
12887 parameter_count_(arguments),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012888 specials_count_(0),
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012889 local_count_(0),
12890 outer_(outer),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012891 entry_(NULL),
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012892 pop_count_(0),
12893 push_count_(0),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012894 ast_id_(BailoutId::None()),
12895 zone_(zone) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012896}
12897
12898
Ben Murdochb0fe1622011-05-05 13:52:32 +010012899void HEnvironment::Initialize(int parameter_count,
12900 int local_count,
12901 int stack_height) {
12902 parameter_count_ = parameter_count;
12903 local_count_ = local_count;
12904
12905 // Avoid reallocating the temporaries' backing store on the first Push.
Ben Murdoch257744e2011-11-30 15:57:28 +000012906 int total = parameter_count + specials_count_ + local_count + stack_height;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012907 values_.Initialize(total + 4, zone());
12908 for (int i = 0; i < total; ++i) values_.Add(NULL, zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +010012909}
12910
12911
Steve Block9fac8402011-05-12 15:51:54 +010012912void HEnvironment::Initialize(const HEnvironment* other) {
12913 closure_ = other->closure();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012914 values_.AddAll(other->values_, zone());
12915 assigned_variables_.Union(other->assigned_variables_, zone());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012916 frame_type_ = other->frame_type_;
Steve Block9fac8402011-05-12 15:51:54 +010012917 parameter_count_ = other->parameter_count_;
12918 local_count_ = other->local_count_;
12919 if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012920 entry_ = other->entry_;
Steve Block9fac8402011-05-12 15:51:54 +010012921 pop_count_ = other->pop_count_;
12922 push_count_ = other->push_count_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012923 specials_count_ = other->specials_count_;
Steve Block9fac8402011-05-12 15:51:54 +010012924 ast_id_ = other->ast_id_;
12925}
12926
12927
Ben Murdochb0fe1622011-05-05 13:52:32 +010012928void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012929 DCHECK(!block->IsLoopHeader());
12930 DCHECK(values_.length() == other->values_.length());
Ben Murdochb0fe1622011-05-05 13:52:32 +010012931
12932 int length = values_.length();
12933 for (int i = 0; i < length; ++i) {
12934 HValue* value = values_[i];
12935 if (value != NULL && value->IsPhi() && value->block() == block) {
12936 // There is already a phi for the i'th value.
12937 HPhi* phi = HPhi::cast(value);
12938 // Assert index is correct and that we haven't missed an incoming edge.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012939 DCHECK(phi->merged_index() == i || !phi->HasMergedIndex());
12940 DCHECK(phi->OperandCount() == block->predecessors()->length());
Ben Murdochb0fe1622011-05-05 13:52:32 +010012941 phi->AddInput(other->values_[i]);
12942 } else if (values_[i] != other->values_[i]) {
12943 // There is a fresh value on the incoming edge, a phi is needed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012944 DCHECK(values_[i] != NULL && other->values_[i] != NULL);
12945 HPhi* phi = block->AddNewPhi(i);
Ben Murdochb0fe1622011-05-05 13:52:32 +010012946 HValue* old_value = values_[i];
12947 for (int j = 0; j < block->predecessors()->length(); j++) {
12948 phi->AddInput(old_value);
12949 }
12950 phi->AddInput(other->values_[i]);
12951 this->values_[i] = phi;
Ben Murdochb0fe1622011-05-05 13:52:32 +010012952 }
12953 }
12954}
12955
12956
Steve Block9fac8402011-05-12 15:51:54 +010012957void HEnvironment::Bind(int index, HValue* value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012958 DCHECK(value != NULL);
12959 assigned_variables_.Add(index, zone());
Steve Block9fac8402011-05-12 15:51:54 +010012960 values_[index] = value;
Ben Murdochb0fe1622011-05-05 13:52:32 +010012961}
12962
12963
Steve Block9fac8402011-05-12 15:51:54 +010012964bool HEnvironment::HasExpressionAt(int index) const {
Ben Murdoch257744e2011-11-30 15:57:28 +000012965 return index >= parameter_count_ + specials_count_ + local_count_;
Steve Block9fac8402011-05-12 15:51:54 +010012966}
12967
12968
12969bool HEnvironment::ExpressionStackIsEmpty() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012970 DCHECK(length() >= first_expression_index());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012971 return length() == first_expression_index();
Steve Block9fac8402011-05-12 15:51:54 +010012972}
12973
12974
12975void HEnvironment::SetExpressionStackAt(int index_from_top, HValue* value) {
12976 int count = index_from_top + 1;
12977 int index = values_.length() - count;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012978 DCHECK(HasExpressionAt(index));
Steve Block9fac8402011-05-12 15:51:54 +010012979 // The push count must include at least the element in question or else
12980 // the new value will not be included in this environment's history.
12981 if (push_count_ < count) {
12982 // This is the same effect as popping then re-pushing 'count' elements.
12983 pop_count_ += (count - push_count_);
12984 push_count_ = count;
12985 }
12986 values_[index] = value;
12987}
12988
12989
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012990HValue* HEnvironment::RemoveExpressionStackAt(int index_from_top) {
12991 int count = index_from_top + 1;
12992 int index = values_.length() - count;
12993 DCHECK(HasExpressionAt(index));
12994 // Simulate popping 'count' elements and then
12995 // pushing 'count - 1' elements back.
12996 pop_count_ += Max(count - push_count_, 0);
12997 push_count_ = Max(push_count_ - count, 0) + (count - 1);
12998 return values_.Remove(index);
12999}
13000
13001
Steve Block9fac8402011-05-12 15:51:54 +010013002void HEnvironment::Drop(int count) {
13003 for (int i = 0; i < count; ++i) {
13004 Pop();
Ben Murdochb0fe1622011-05-05 13:52:32 +010013005 }
13006}
13007
13008
13009HEnvironment* HEnvironment::Copy() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013010 return new(zone()) HEnvironment(this, zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +010013011}
13012
13013
13014HEnvironment* HEnvironment::CopyWithoutHistory() const {
13015 HEnvironment* result = Copy();
13016 result->ClearHistory();
13017 return result;
13018}
13019
13020
13021HEnvironment* HEnvironment::CopyAsLoopHeader(HBasicBlock* loop_header) const {
13022 HEnvironment* new_env = Copy();
13023 for (int i = 0; i < values_.length(); ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013024 HPhi* phi = loop_header->AddNewPhi(i);
Ben Murdochb0fe1622011-05-05 13:52:32 +010013025 phi->AddInput(values_[i]);
13026 new_env->values_[i] = phi;
Ben Murdochb0fe1622011-05-05 13:52:32 +010013027 }
13028 new_env->ClearHistory();
13029 return new_env;
13030}
13031
13032
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013033HEnvironment* HEnvironment::CreateStubEnvironment(HEnvironment* outer,
13034 Handle<JSFunction> target,
13035 FrameType frame_type,
13036 int arguments) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013037 HEnvironment* new_env =
13038 new(zone()) HEnvironment(outer, target, frame_type,
13039 arguments + 1, zone());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013040 for (int i = 0; i <= arguments; ++i) { // Include receiver.
13041 new_env->Push(ExpressionStackAt(arguments - i));
13042 }
13043 new_env->ClearHistory();
13044 return new_env;
13045}
13046
13047
Ben Murdoch257744e2011-11-30 15:57:28 +000013048HEnvironment* HEnvironment::CopyForInlining(
13049 Handle<JSFunction> target,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013050 int arguments,
Ben Murdoch257744e2011-11-30 15:57:28 +000013051 FunctionLiteral* function,
Ben Murdoch257744e2011-11-30 15:57:28 +000013052 HConstant* undefined,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013053 InliningKind inlining_kind) const {
13054 DCHECK(frame_type() == JS_FUNCTION);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013055
Ben Murdochb0fe1622011-05-05 13:52:32 +010013056 // Outer environment is a copy of this one without the arguments.
13057 int arity = function->scope()->num_parameters();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013058
Ben Murdochb0fe1622011-05-05 13:52:32 +010013059 HEnvironment* outer = Copy();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013060 outer->Drop(arguments + 1); // Including receiver.
Ben Murdochb0fe1622011-05-05 13:52:32 +010013061 outer->ClearHistory();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013062
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013063 if (inlining_kind == CONSTRUCT_CALL_RETURN) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013064 // Create artificial constructor stub environment. The receiver should
13065 // actually be the constructor function, but we pass the newly allocated
13066 // object instead, DoComputeConstructStubFrame() relies on that.
13067 outer = CreateStubEnvironment(outer, target, JS_CONSTRUCT, arguments);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013068 } else if (inlining_kind == GETTER_CALL_RETURN) {
13069 // We need an additional StackFrame::INTERNAL frame for restoring the
13070 // correct context.
13071 outer = CreateStubEnvironment(outer, target, JS_GETTER, arguments);
13072 } else if (inlining_kind == SETTER_CALL_RETURN) {
13073 // We need an additional StackFrame::INTERNAL frame for temporarily saving
13074 // the argument of the setter, see StoreStubCompiler::CompileStoreViaSetter.
13075 outer = CreateStubEnvironment(outer, target, JS_SETTER, arguments);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013076 }
13077
13078 if (arity != arguments) {
13079 // Create artificial arguments adaptation environment.
13080 outer = CreateStubEnvironment(outer, target, ARGUMENTS_ADAPTOR, arguments);
13081 }
13082
Ben Murdoch8b112d22011-06-08 16:22:53 +010013083 HEnvironment* inner =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013084 new(zone()) HEnvironment(outer, function->scope(), target, zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +010013085 // Get the argument values from the original environment.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013086 for (int i = 0; i <= arity; ++i) { // Include receiver.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013087 HValue* push = (i <= arguments) ?
13088 ExpressionStackAt(arguments - i) : undefined;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013089 inner->SetValueAt(i, push);
Ben Murdochb0fe1622011-05-05 13:52:32 +010013090 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013091 inner->SetValueAt(arity + 1, context());
Ben Murdoch257744e2011-11-30 15:57:28 +000013092 for (int i = arity + 2; i < inner->length(); ++i) {
13093 inner->SetValueAt(i, undefined);
Ben Murdochb0fe1622011-05-05 13:52:32 +010013094 }
13095
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013096 inner->set_ast_id(BailoutId::FunctionEntry());
Ben Murdochb0fe1622011-05-05 13:52:32 +010013097 return inner;
13098}
13099
13100
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013101std::ostream& operator<<(std::ostream& os, const HEnvironment& env) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013102 for (int i = 0; i < env.length(); i++) {
13103 if (i == 0) os << "parameters\n";
13104 if (i == env.parameter_count()) os << "specials\n";
13105 if (i == env.parameter_count() + env.specials_count()) os << "locals\n";
13106 if (i == env.parameter_count() + env.specials_count() + env.local_count()) {
13107 os << "expressions\n";
Ben Murdoch257744e2011-11-30 15:57:28 +000013108 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013109 HValue* val = env.values()->at(i);
13110 os << i << ": ";
Ben Murdochb0fe1622011-05-05 13:52:32 +010013111 if (val != NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013112 os << val;
Ben Murdochb0fe1622011-05-05 13:52:32 +010013113 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013114 os << "NULL";
Ben Murdochb0fe1622011-05-05 13:52:32 +010013115 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013116 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010013117 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013118 return os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010013119}
13120
13121
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013122void HTracer::TraceCompilation(CompilationInfo* info) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010013123 Tag tag(this, "compilation");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013124 if (info->IsOptimizing()) {
13125 Handle<String> name = info->function()->debug_name();
13126 PrintStringProperty("name", name->ToCString().get());
13127 PrintIndent();
13128 trace_.Add("method \"%s:%d\"\n",
13129 name->ToCString().get(),
13130 info->optimization_id());
13131 } else {
13132 CodeStub::Major major_key = info->code_stub()->MajorKey();
13133 PrintStringProperty("name", CodeStub::MajorName(major_key, false));
13134 PrintStringProperty("method", "stub");
13135 }
13136 PrintLongProperty("date",
13137 static_cast<int64_t>(base::OS::TimeCurrentMillis()));
Ben Murdochb0fe1622011-05-05 13:52:32 +010013138}
13139
13140
13141void HTracer::TraceLithium(const char* name, LChunk* chunk) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013142 DCHECK(!chunk->isolate()->concurrent_recompilation_enabled());
13143 AllowHandleDereference allow_deref;
13144 AllowDeferredHandleDereference allow_deferred_deref;
Ben Murdochb0fe1622011-05-05 13:52:32 +010013145 Trace(name, chunk->graph(), chunk);
13146}
13147
13148
13149void HTracer::TraceHydrogen(const char* name, HGraph* graph) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013150 DCHECK(!graph->isolate()->concurrent_recompilation_enabled());
13151 AllowHandleDereference allow_deref;
13152 AllowDeferredHandleDereference allow_deferred_deref;
Ben Murdochb0fe1622011-05-05 13:52:32 +010013153 Trace(name, graph, NULL);
13154}
13155
13156
13157void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) {
13158 Tag tag(this, "cfg");
13159 PrintStringProperty("name", name);
13160 const ZoneList<HBasicBlock*>* blocks = graph->blocks();
13161 for (int i = 0; i < blocks->length(); i++) {
13162 HBasicBlock* current = blocks->at(i);
13163 Tag block_tag(this, "block");
13164 PrintBlockProperty("name", current->block_id());
13165 PrintIntProperty("from_bci", -1);
13166 PrintIntProperty("to_bci", -1);
13167
13168 if (!current->predecessors()->is_empty()) {
13169 PrintIndent();
13170 trace_.Add("predecessors");
13171 for (int j = 0; j < current->predecessors()->length(); ++j) {
13172 trace_.Add(" \"B%d\"", current->predecessors()->at(j)->block_id());
13173 }
13174 trace_.Add("\n");
13175 } else {
13176 PrintEmptyProperty("predecessors");
13177 }
13178
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013179 if (current->end()->SuccessorCount() == 0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010013180 PrintEmptyProperty("successors");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013181 } else {
13182 PrintIndent();
13183 trace_.Add("successors");
13184 for (HSuccessorIterator it(current->end()); !it.Done(); it.Advance()) {
13185 trace_.Add(" \"B%d\"", it.Current()->block_id());
13186 }
13187 trace_.Add("\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +010013188 }
13189
13190 PrintEmptyProperty("xhandlers");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013191
13192 {
13193 PrintIndent();
13194 trace_.Add("flags");
13195 if (current->IsLoopSuccessorDominator()) {
13196 trace_.Add(" \"dom-loop-succ\"");
13197 }
13198 if (current->IsUnreachable()) {
13199 trace_.Add(" \"dead\"");
13200 }
13201 if (current->is_osr_entry()) {
13202 trace_.Add(" \"osr\"");
13203 }
13204 trace_.Add("\n");
13205 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010013206
13207 if (current->dominator() != NULL) {
13208 PrintBlockProperty("dominator", current->dominator()->block_id());
13209 }
13210
Ben Murdoch589d6972011-11-30 16:04:58 +000013211 PrintIntProperty("loop_depth", current->LoopNestingDepth());
13212
Ben Murdochb0fe1622011-05-05 13:52:32 +010013213 if (chunk != NULL) {
13214 int first_index = current->first_instruction_index();
13215 int last_index = current->last_instruction_index();
13216 PrintIntProperty(
13217 "first_lir_id",
13218 LifetimePosition::FromInstructionIndex(first_index).Value());
13219 PrintIntProperty(
13220 "last_lir_id",
13221 LifetimePosition::FromInstructionIndex(last_index).Value());
13222 }
13223
13224 {
13225 Tag states_tag(this, "states");
13226 Tag locals_tag(this, "locals");
13227 int total = current->phis()->length();
Ben Murdoch257744e2011-11-30 15:57:28 +000013228 PrintIntProperty("size", current->phis()->length());
13229 PrintStringProperty("method", "None");
Ben Murdochb0fe1622011-05-05 13:52:32 +010013230 for (int j = 0; j < total; ++j) {
13231 HPhi* phi = current->phis()->at(j);
Ben Murdoch257744e2011-11-30 15:57:28 +000013232 PrintIndent();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013233 std::ostringstream os;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013234 os << phi->merged_index() << " " << NameOf(phi) << " " << *phi << "\n";
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013235 trace_.Add(os.str().c_str());
Ben Murdochb0fe1622011-05-05 13:52:32 +010013236 }
13237 }
13238
13239 {
13240 Tag HIR_tag(this, "HIR");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013241 for (HInstructionIterator it(current); !it.Done(); it.Advance()) {
13242 HInstruction* instruction = it.Current();
Ben Murdoch257744e2011-11-30 15:57:28 +000013243 int uses = instruction->UseCount();
13244 PrintIndent();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013245 std::ostringstream os;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013246 os << "0 " << uses << " " << NameOf(instruction) << " " << *instruction;
13247 if (FLAG_hydrogen_track_positions &&
13248 instruction->has_position() &&
13249 instruction->position().raw() != 0) {
13250 const HSourcePosition pos = instruction->position();
13251 os << " pos:";
13252 if (pos.inlining_id() != 0) os << pos.inlining_id() << "_";
13253 os << pos.position();
13254 }
13255 os << " <|@\n";
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013256 trace_.Add(os.str().c_str());
Ben Murdochb0fe1622011-05-05 13:52:32 +010013257 }
13258 }
13259
13260
13261 if (chunk != NULL) {
13262 Tag LIR_tag(this, "LIR");
13263 int first_index = current->first_instruction_index();
13264 int last_index = current->last_instruction_index();
13265 if (first_index != -1 && last_index != -1) {
13266 const ZoneList<LInstruction*>* instructions = chunk->instructions();
13267 for (int i = first_index; i <= last_index; ++i) {
13268 LInstruction* linstr = instructions->at(i);
13269 if (linstr != NULL) {
Ben Murdoch257744e2011-11-30 15:57:28 +000013270 PrintIndent();
Ben Murdochb0fe1622011-05-05 13:52:32 +010013271 trace_.Add("%d ",
13272 LifetimePosition::FromInstructionIndex(i).Value());
13273 linstr->PrintTo(&trace_);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013274 std::ostringstream os;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013275 os << " [hir:" << NameOf(linstr->hydrogen_value()) << "] <|@\n";
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013276 trace_.Add(os.str().c_str());
Ben Murdochb0fe1622011-05-05 13:52:32 +010013277 }
13278 }
13279 }
13280 }
13281 }
13282}
13283
13284
13285void HTracer::TraceLiveRanges(const char* name, LAllocator* allocator) {
13286 Tag tag(this, "intervals");
13287 PrintStringProperty("name", name);
13288
Steve Block44f0eee2011-05-26 01:26:41 +010013289 const Vector<LiveRange*>* fixed_d = allocator->fixed_double_live_ranges();
Ben Murdochb0fe1622011-05-05 13:52:32 +010013290 for (int i = 0; i < fixed_d->length(); ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013291 TraceLiveRange(fixed_d->at(i), "fixed", allocator->zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +010013292 }
13293
Steve Block44f0eee2011-05-26 01:26:41 +010013294 const Vector<LiveRange*>* fixed = allocator->fixed_live_ranges();
Ben Murdochb0fe1622011-05-05 13:52:32 +010013295 for (int i = 0; i < fixed->length(); ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013296 TraceLiveRange(fixed->at(i), "fixed", allocator->zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +010013297 }
13298
13299 const ZoneList<LiveRange*>* live_ranges = allocator->live_ranges();
13300 for (int i = 0; i < live_ranges->length(); ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013301 TraceLiveRange(live_ranges->at(i), "object", allocator->zone());
Ben Murdochb0fe1622011-05-05 13:52:32 +010013302 }
13303}
13304
13305
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013306void HTracer::TraceLiveRange(LiveRange* range, const char* type,
13307 Zone* zone) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010013308 if (range != NULL && !range->IsEmpty()) {
Ben Murdoch257744e2011-11-30 15:57:28 +000013309 PrintIndent();
Ben Murdochb0fe1622011-05-05 13:52:32 +010013310 trace_.Add("%d %s", range->id(), type);
13311 if (range->HasRegisterAssigned()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013312 LOperand* op = range->CreateAssignedOperand(zone);
Ben Murdochb0fe1622011-05-05 13:52:32 +010013313 int assigned_reg = op->index();
13314 if (op->IsDoubleRegister()) {
13315 trace_.Add(" \"%s\"",
13316 DoubleRegister::AllocationIndexToString(assigned_reg));
13317 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013318 DCHECK(op->IsRegister());
Ben Murdochb0fe1622011-05-05 13:52:32 +010013319 trace_.Add(" \"%s\"", Register::AllocationIndexToString(assigned_reg));
13320 }
13321 } else if (range->IsSpilled()) {
13322 LOperand* op = range->TopLevel()->GetSpillOperand();
13323 if (op->IsDoubleStackSlot()) {
13324 trace_.Add(" \"double_stack:%d\"", op->index());
13325 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013326 DCHECK(op->IsStackSlot());
Ben Murdochb0fe1622011-05-05 13:52:32 +010013327 trace_.Add(" \"stack:%d\"", op->index());
13328 }
13329 }
13330 int parent_index = -1;
13331 if (range->IsChild()) {
13332 parent_index = range->parent()->id();
13333 } else {
13334 parent_index = range->id();
13335 }
13336 LOperand* op = range->FirstHint();
13337 int hint_index = -1;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013338 if (op != NULL && op->IsUnallocated()) {
13339 hint_index = LUnallocated::cast(op)->virtual_register();
13340 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010013341 trace_.Add(" %d %d", parent_index, hint_index);
13342 UseInterval* cur_interval = range->first_interval();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013343 while (cur_interval != NULL && range->Covers(cur_interval->start())) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010013344 trace_.Add(" [%d, %d[",
13345 cur_interval->start().Value(),
13346 cur_interval->end().Value());
13347 cur_interval = cur_interval->next();
13348 }
13349
13350 UsePosition* current_pos = range->first_pos();
13351 while (current_pos != NULL) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013352 if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010013353 trace_.Add(" %d M", current_pos->pos().Value());
13354 }
13355 current_pos = current_pos->next();
13356 }
13357
13358 trace_.Add(" \"\"\n");
13359 }
13360}
13361
13362
13363void HTracer::FlushToFile() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013364 AppendChars(filename_.start(), trace_.ToCString().get(), trace_.length(),
13365 false);
Ben Murdochb0fe1622011-05-05 13:52:32 +010013366 trace_.Reset();
13367}
13368
13369
Steve Block44f0eee2011-05-26 01:26:41 +010013370void HStatistics::Initialize(CompilationInfo* info) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013371 if (info->shared_info().is_null()) return;
Steve Block44f0eee2011-05-26 01:26:41 +010013372 source_size_ += info->shared_info()->SourceSize();
13373}
13374
13375
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013376void HStatistics::Print() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013377 PrintF(
13378 "\n"
13379 "----------------------------------------"
13380 "----------------------------------------\n"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013381 "--- Hydrogen timing results:\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013382 "----------------------------------------"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013383 "----------------------------------------\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013384 base::TimeDelta sum;
13385 for (int i = 0; i < times_.length(); ++i) {
13386 sum += times_[i];
Ben Murdochb0fe1622011-05-05 13:52:32 +010013387 }
13388
13389 for (int i = 0; i < names_.length(); ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013390 PrintF("%33s", names_[i]);
13391 double ms = times_[i].InMillisecondsF();
13392 double percent = times_[i].PercentOf(sum);
13393 PrintF(" %8.3f ms / %4.1f %% ", ms, percent);
Ben Murdochb8e0da22011-05-16 14:20:40 +010013394
13395 unsigned size = sizes_[i];
13396 double size_percent = static_cast<double>(size) * 100 / total_size_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013397 PrintF(" %9u bytes / %4.1f %%\n", size, size_percent);
Ben Murdochb0fe1622011-05-05 13:52:32 +010013398 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013399
13400 PrintF(
13401 "----------------------------------------"
13402 "----------------------------------------\n");
13403 base::TimeDelta total = create_graph_ + optimize_graph_ + generate_code_;
13404 PrintF("%33s %8.3f ms / %4.1f %% \n", "Create graph",
13405 create_graph_.InMillisecondsF(), create_graph_.PercentOf(total));
13406 PrintF("%33s %8.3f ms / %4.1f %% \n", "Optimize graph",
13407 optimize_graph_.InMillisecondsF(), optimize_graph_.PercentOf(total));
13408 PrintF("%33s %8.3f ms / %4.1f %% \n", "Generate and install code",
13409 generate_code_.InMillisecondsF(), generate_code_.PercentOf(total));
13410 PrintF(
13411 "----------------------------------------"
13412 "----------------------------------------\n");
13413 PrintF("%33s %8.3f ms %9u bytes\n", "Total",
13414 total.InMillisecondsF(), total_size_);
13415 PrintF("%33s (%.1f times slower than full code gen)\n", "",
13416 total.TimesOf(full_code_gen_));
13417
Steve Block44f0eee2011-05-26 01:26:41 +010013418 double source_size_in_kb = static_cast<double>(source_size_) / 1024;
13419 double normalized_time = source_size_in_kb > 0
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013420 ? total.InMillisecondsF() / source_size_in_kb
Steve Block44f0eee2011-05-26 01:26:41 +010013421 : 0;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013422 double normalized_size_in_kb =
13423 source_size_in_kb > 0
13424 ? static_cast<double>(total_size_) / 1024 / source_size_in_kb
13425 : 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013426 PrintF("%33s %8.3f ms %7.3f kB allocated\n",
13427 "Average per kB source", normalized_time, normalized_size_in_kb);
Ben Murdochb0fe1622011-05-05 13:52:32 +010013428}
13429
13430
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013431void HStatistics::SaveTiming(const char* name, base::TimeDelta time,
13432 unsigned size) {
13433 total_size_ += size;
13434 for (int i = 0; i < names_.length(); ++i) {
13435 if (strcmp(names_[i], name) == 0) {
13436 times_[i] += time;
13437 sizes_[i] += size;
13438 return;
Ben Murdochb0fe1622011-05-05 13:52:32 +010013439 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010013440 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013441 names_.Add(name);
13442 times_.Add(time);
13443 sizes_.Add(size);
Ben Murdochb0fe1622011-05-05 13:52:32 +010013444}
13445
13446
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013447HPhase::~HPhase() {
13448 if (ShouldProduceTraceOutput()) {
13449 isolate()->GetHTracer()->TraceHydrogen(name(), graph_);
Ben Murdochb0fe1622011-05-05 13:52:32 +010013450 }
13451
13452#ifdef DEBUG
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013453 graph_->Verify(false); // No full verify.
Ben Murdochb0fe1622011-05-05 13:52:32 +010013454#endif
13455}
13456
13457} } // namespace v8::internal