1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include "allocation-site-scopes.h"
35 #include "full-codegen.h"
37 #include "hydrogen-bce.h"
38 #include "hydrogen-bch.h"
39 #include "hydrogen-canonicalize.h"
40 #include "hydrogen-check-elimination.h"
41 #include "hydrogen-dce.h"
42 #include "hydrogen-dehoist.h"
43 #include "hydrogen-environment-liveness.h"
44 #include "hydrogen-escape-analysis.h"
45 #include "hydrogen-infer-representation.h"
46 #include "hydrogen-infer-types.h"
47 #include "hydrogen-load-elimination.h"
48 #include "hydrogen-gvn.h"
49 #include "hydrogen-mark-deoptimize.h"
50 #include "hydrogen-mark-unreachable.h"
51 #include "hydrogen-osr.h"
52 #include "hydrogen-range-analysis.h"
53 #include "hydrogen-redundant-phi.h"
54 #include "hydrogen-removable-simulates.h"
55 #include "hydrogen-representation-changes.h"
56 #include "hydrogen-sce.h"
57 #include "hydrogen-store-elimination.h"
58 #include "hydrogen-uint32-analysis.h"
59 #include "lithium-allocator.h"
62 #include "scopeinfo.h"
64 #include "stub-cache.h"
67 #if V8_TARGET_ARCH_IA32
68 #include "ia32/lithium-codegen-ia32.h"
69 #elif V8_TARGET_ARCH_X64
70 #include "x64/lithium-codegen-x64.h"
71 #elif V8_TARGET_ARCH_ARM64
72 #include "arm64/lithium-codegen-arm64.h"
73 #elif V8_TARGET_ARCH_ARM
74 #include "arm/lithium-codegen-arm.h"
75 #elif V8_TARGET_ARCH_MIPS
76 #include "mips/lithium-codegen-mips.h"
78 #error Unsupported target architecture.
84 HBasicBlock::HBasicBlock(HGraph* graph)
85 : block_id_(graph->GetNextBlockID()),
87 phis_(4, graph->zone()),
91 loop_information_(NULL),
92 predecessors_(2, graph->zone()),
94 dominated_blocks_(4, graph->zone()),
95 last_environment_(NULL),
97 first_instruction_index_(-1),
98 last_instruction_index_(-1),
99 deleted_phis_(4, graph->zone()),
100 parent_loop_header_(NULL),
101 inlined_entry_block_(NULL),
102 is_inline_return_target_(false),
104 dominates_loop_successors_(false),
105 is_osr_entry_(false) { }
108 Isolate* HBasicBlock::isolate() const {
109 return graph_->isolate();
113 void HBasicBlock::MarkUnreachable() {
114 is_reachable_ = false;
118 void HBasicBlock::AttachLoopInformation() {
119 ASSERT(!IsLoopHeader());
120 loop_information_ = new(zone()) HLoopInformation(this, zone());
124 void HBasicBlock::DetachLoopInformation() {
125 ASSERT(IsLoopHeader());
126 loop_information_ = NULL;
130 void HBasicBlock::AddPhi(HPhi* phi) {
131 ASSERT(!IsStartBlock());
132 phis_.Add(phi, zone());
137 void HBasicBlock::RemovePhi(HPhi* phi) {
138 ASSERT(phi->block() == this);
139 ASSERT(phis_.Contains(phi));
141 phis_.RemoveElement(phi);
146 void HBasicBlock::AddInstruction(HInstruction* instr,
147 HSourcePosition position) {
148 ASSERT(!IsStartBlock() || !IsFinished());
149 ASSERT(!instr->IsLinked());
150 ASSERT(!IsFinished());
152 if (!position.IsUnknown()) {
153 instr->set_position(position);
155 if (first_ == NULL) {
156 ASSERT(last_environment() != NULL);
157 ASSERT(!last_environment()->ast_id().IsNone());
158 HBlockEntry* entry = new(zone()) HBlockEntry();
159 entry->InitializeAsFirst(this);
160 if (!position.IsUnknown()) {
161 entry->set_position(position);
163 ASSERT(!FLAG_hydrogen_track_positions ||
164 !graph()->info()->IsOptimizing());
166 first_ = last_ = entry;
168 instr->InsertAfter(last_);
172 HPhi* HBasicBlock::AddNewPhi(int merged_index) {
173 if (graph()->IsInsideNoSideEffectsScope()) {
174 merged_index = HPhi::kInvalidMergedIndex;
176 HPhi* phi = new(zone()) HPhi(merged_index, zone());
182 HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id,
183 RemovableSimulate removable) {
184 ASSERT(HasEnvironment());
185 HEnvironment* environment = last_environment();
186 ASSERT(ast_id.IsNone() ||
187 ast_id == BailoutId::StubEntry() ||
188 environment->closure()->shared()->VerifyBailoutId(ast_id));
190 int push_count = environment->push_count();
191 int pop_count = environment->pop_count();
194 new(zone()) HSimulate(ast_id, pop_count, zone(), removable);
196 instr->set_closure(environment->closure());
198 // Order of pushed values: newest (top of stack) first. This allows
199 // HSimulate::MergeWith() to easily append additional pushed values
200 // that are older (from further down the stack).
201 for (int i = 0; i < push_count; ++i) {
202 instr->AddPushedValue(environment->ExpressionStackAt(i));
204 for (GrowableBitVector::Iterator it(environment->assigned_variables(),
208 int index = it.Current();
209 instr->AddAssignedValue(index, environment->Lookup(index));
211 environment->ClearHistory();
216 void HBasicBlock::Finish(HControlInstruction* end, HSourcePosition position) {
217 ASSERT(!IsFinished());
218 AddInstruction(end, position);
220 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
221 it.Current()->RegisterPredecessor(this);
226 void HBasicBlock::Goto(HBasicBlock* block,
227 HSourcePosition position,
228 FunctionState* state,
230 bool drop_extra = state != NULL &&
231 state->inlining_kind() == NORMAL_RETURN;
233 if (block->IsInlineReturnTarget()) {
234 HEnvironment* env = last_environment();
235 int argument_count = env->arguments_environment()->parameter_count();
236 AddInstruction(new(zone())
237 HLeaveInlined(state->entry(), argument_count),
239 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra));
242 if (add_simulate) AddNewSimulate(BailoutId::None(), position);
243 HGoto* instr = new(zone()) HGoto(block);
244 Finish(instr, position);
248 void HBasicBlock::AddLeaveInlined(HValue* return_value,
249 FunctionState* state,
250 HSourcePosition position) {
251 HBasicBlock* target = state->function_return();
252 bool drop_extra = state->inlining_kind() == NORMAL_RETURN;
254 ASSERT(target->IsInlineReturnTarget());
255 ASSERT(return_value != NULL);
256 HEnvironment* env = last_environment();
257 int argument_count = env->arguments_environment()->parameter_count();
258 AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count),
260 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra));
261 last_environment()->Push(return_value);
262 AddNewSimulate(BailoutId::None(), position);
263 HGoto* instr = new(zone()) HGoto(target);
264 Finish(instr, position);
268 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) {
269 ASSERT(!HasEnvironment());
270 ASSERT(first() == NULL);
271 UpdateEnvironment(env);
275 void HBasicBlock::UpdateEnvironment(HEnvironment* env) {
276 last_environment_ = env;
277 graph()->update_maximum_environment_size(env->first_expression_index());
281 void HBasicBlock::SetJoinId(BailoutId ast_id) {
282 int length = predecessors_.length();
284 for (int i = 0; i < length; i++) {
285 HBasicBlock* predecessor = predecessors_[i];
286 ASSERT(predecessor->end()->IsGoto());
287 HSimulate* simulate = HSimulate::cast(predecessor->end()->previous());
289 (predecessor->last_environment()->closure().is_null() ||
290 predecessor->last_environment()->closure()->shared()
291 ->VerifyBailoutId(ast_id)));
292 simulate->set_ast_id(ast_id);
293 predecessor->last_environment()->set_ast_id(ast_id);
298 bool HBasicBlock::Dominates(HBasicBlock* other) const {
299 HBasicBlock* current = other->dominator();
300 while (current != NULL) {
301 if (current == this) return true;
302 current = current->dominator();
308 bool HBasicBlock::EqualToOrDominates(HBasicBlock* other) const {
309 if (this == other) return true;
310 return Dominates(other);
314 int HBasicBlock::LoopNestingDepth() const {
315 const HBasicBlock* current = this;
316 int result = (current->IsLoopHeader()) ? 1 : 0;
317 while (current->parent_loop_header() != NULL) {
318 current = current->parent_loop_header();
325 void HBasicBlock::PostProcessLoopHeader(IterationStatement* stmt) {
326 ASSERT(IsLoopHeader());
328 SetJoinId(stmt->EntryId());
329 if (predecessors()->length() == 1) {
330 // This is a degenerated loop.
331 DetachLoopInformation();
335 // Only the first entry into the loop is from outside the loop. All other
336 // entries must be back edges.
337 for (int i = 1; i < predecessors()->length(); ++i) {
338 loop_information()->RegisterBackEdge(predecessors()->at(i));
343 void HBasicBlock::MarkSuccEdgeUnreachable(int succ) {
344 ASSERT(IsFinished());
345 HBasicBlock* succ_block = end()->SuccessorAt(succ);
347 ASSERT(succ_block->predecessors()->length() == 1);
348 succ_block->MarkUnreachable();
352 void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) {
353 if (HasPredecessor()) {
354 // Only loop header blocks can have a predecessor added after
355 // instructions have been added to the block (they have phis for all
356 // values in the environment, these phis may be eliminated later).
357 ASSERT(IsLoopHeader() || first_ == NULL);
358 HEnvironment* incoming_env = pred->last_environment();
359 if (IsLoopHeader()) {
360 ASSERT(phis()->length() == incoming_env->length());
361 for (int i = 0; i < phis_.length(); ++i) {
362 phis_[i]->AddInput(incoming_env->values()->at(i));
365 last_environment()->AddIncomingEdge(this, pred->last_environment());
367 } else if (!HasEnvironment() && !IsFinished()) {
368 ASSERT(!IsLoopHeader());
369 SetInitialEnvironment(pred->last_environment()->Copy());
372 predecessors_.Add(pred, zone());
376 void HBasicBlock::AddDominatedBlock(HBasicBlock* block) {
377 ASSERT(!dominated_blocks_.Contains(block));
378 // Keep the list of dominated blocks sorted such that if there is two
379 // succeeding block in this list, the predecessor is before the successor.
381 while (index < dominated_blocks_.length() &&
382 dominated_blocks_[index]->block_id() < block->block_id()) {
385 dominated_blocks_.InsertAt(index, block, zone());
389 void HBasicBlock::AssignCommonDominator(HBasicBlock* other) {
390 if (dominator_ == NULL) {
392 other->AddDominatedBlock(this);
393 } else if (other->dominator() != NULL) {
394 HBasicBlock* first = dominator_;
395 HBasicBlock* second = other;
397 while (first != second) {
398 if (first->block_id() > second->block_id()) {
399 first = first->dominator();
401 second = second->dominator();
403 ASSERT(first != NULL && second != NULL);
406 if (dominator_ != first) {
407 ASSERT(dominator_->dominated_blocks_.Contains(this));
408 dominator_->dominated_blocks_.RemoveElement(this);
410 first->AddDominatedBlock(this);
416 void HBasicBlock::AssignLoopSuccessorDominators() {
417 // Mark blocks that dominate all subsequent reachable blocks inside their
418 // loop. Exploit the fact that blocks are sorted in reverse post order. When
419 // the loop is visited in increasing block id order, if the number of
420 // non-loop-exiting successor edges at the dominator_candidate block doesn't
421 // exceed the number of previously encountered predecessor edges, there is no
422 // path from the loop header to any block with higher id that doesn't go
423 // through the dominator_candidate block. In this case, the
424 // dominator_candidate block is guaranteed to dominate all blocks reachable
425 // from it with higher ids.
426 HBasicBlock* last = loop_information()->GetLastBackEdge();
427 int outstanding_successors = 1; // one edge from the pre-header
428 // Header always dominates everything.
429 MarkAsLoopSuccessorDominator();
430 for (int j = block_id(); j <= last->block_id(); ++j) {
431 HBasicBlock* dominator_candidate = graph_->blocks()->at(j);
432 for (HPredecessorIterator it(dominator_candidate); !it.Done();
434 HBasicBlock* predecessor = it.Current();
435 // Don't count back edges.
436 if (predecessor->block_id() < dominator_candidate->block_id()) {
437 outstanding_successors--;
441 // If more successors than predecessors have been seen in the loop up to
442 // now, it's not possible to guarantee that the current block dominates
443 // all of the blocks with higher IDs. In this case, assume conservatively
444 // that those paths through loop that don't go through the current block
445 // contain all of the loop's dependencies. Also be careful to record
446 // dominator information about the current loop that's being processed,
447 // and not nested loops, which will be processed when
448 // AssignLoopSuccessorDominators gets called on their header.
449 ASSERT(outstanding_successors >= 0);
450 HBasicBlock* parent_loop_header = dominator_candidate->parent_loop_header();
451 if (outstanding_successors == 0 &&
452 (parent_loop_header == this && !dominator_candidate->IsLoopHeader())) {
453 dominator_candidate->MarkAsLoopSuccessorDominator();
455 HControlInstruction* end = dominator_candidate->end();
456 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
457 HBasicBlock* successor = it.Current();
458 // Only count successors that remain inside the loop and don't loop back
460 if (successor->block_id() > dominator_candidate->block_id() &&
461 successor->block_id() <= last->block_id()) {
462 // Backwards edges must land on loop headers.
463 ASSERT(successor->block_id() > dominator_candidate->block_id() ||
464 successor->IsLoopHeader());
465 outstanding_successors++;
472 int HBasicBlock::PredecessorIndexOf(HBasicBlock* predecessor) const {
473 for (int i = 0; i < predecessors_.length(); ++i) {
474 if (predecessors_[i] == predecessor) return i;
482 void HBasicBlock::Verify() {
483 // Check that every block is finished.
484 ASSERT(IsFinished());
485 ASSERT(block_id() >= 0);
487 // Check that the incoming edges are in edge split form.
488 if (predecessors_.length() > 1) {
489 for (int i = 0; i < predecessors_.length(); ++i) {
490 ASSERT(predecessors_[i]->end()->SecondSuccessor() == NULL);
497 void HLoopInformation::RegisterBackEdge(HBasicBlock* block) {
498 this->back_edges_.Add(block, block->zone());
503 HBasicBlock* HLoopInformation::GetLastBackEdge() const {
505 HBasicBlock* result = NULL;
506 for (int i = 0; i < back_edges_.length(); ++i) {
507 HBasicBlock* cur = back_edges_[i];
508 if (cur->block_id() > max_id) {
509 max_id = cur->block_id();
517 void HLoopInformation::AddBlock(HBasicBlock* block) {
518 if (block == loop_header()) return;
519 if (block->parent_loop_header() == loop_header()) return;
520 if (block->parent_loop_header() != NULL) {
521 AddBlock(block->parent_loop_header());
523 block->set_parent_loop_header(loop_header());
524 blocks_.Add(block, block->zone());
525 for (int i = 0; i < block->predecessors()->length(); ++i) {
526 AddBlock(block->predecessors()->at(i));
534 // Checks reachability of the blocks in this graph and stores a bit in
535 // the BitVector "reachable()" for every block that can be reached
536 // from the start block of the graph. If "dont_visit" is non-null, the given
537 // block is treated as if it would not be part of the graph. "visited_count()"
538 // returns the number of reachable blocks.
539 class ReachabilityAnalyzer BASE_EMBEDDED {
541 ReachabilityAnalyzer(HBasicBlock* entry_block,
543 HBasicBlock* dont_visit)
545 stack_(16, entry_block->zone()),
546 reachable_(block_count, entry_block->zone()),
547 dont_visit_(dont_visit) {
548 PushBlock(entry_block);
552 int visited_count() const { return visited_count_; }
553 const BitVector* reachable() const { return &reachable_; }
556 void PushBlock(HBasicBlock* block) {
557 if (block != NULL && block != dont_visit_ &&
558 !reachable_.Contains(block->block_id())) {
559 reachable_.Add(block->block_id());
560 stack_.Add(block, block->zone());
566 while (!stack_.is_empty()) {
567 HControlInstruction* end = stack_.RemoveLast()->end();
568 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
569 PushBlock(it.Current());
575 ZoneList<HBasicBlock*> stack_;
576 BitVector reachable_;
577 HBasicBlock* dont_visit_;
581 void HGraph::Verify(bool do_full_verify) const {
582 Heap::RelocationLock relocation_lock(isolate()->heap());
583 AllowHandleDereference allow_deref;
584 AllowDeferredHandleDereference allow_deferred_deref;
585 for (int i = 0; i < blocks_.length(); i++) {
586 HBasicBlock* block = blocks_.at(i);
590 // Check that every block contains at least one node and that only the last
591 // node is a control instruction.
592 HInstruction* current = block->first();
593 ASSERT(current != NULL && current->IsBlockEntry());
594 while (current != NULL) {
595 ASSERT((current->next() == NULL) == current->IsControlInstruction());
596 ASSERT(current->block() == block);
598 current = current->next();
601 // Check that successors are correctly set.
602 HBasicBlock* first = block->end()->FirstSuccessor();
603 HBasicBlock* second = block->end()->SecondSuccessor();
604 ASSERT(second == NULL || first != NULL);
606 // Check that the predecessor array is correct.
608 ASSERT(first->predecessors()->Contains(block));
609 if (second != NULL) {
610 ASSERT(second->predecessors()->Contains(block));
614 // Check that phis have correct arguments.
615 for (int j = 0; j < block->phis()->length(); j++) {
616 HPhi* phi = block->phis()->at(j);
620 // Check that all join blocks have predecessors that end with an
621 // unconditional goto and agree on their environment node id.
622 if (block->predecessors()->length() >= 2) {
624 block->predecessors()->first()->last_environment()->ast_id();
625 for (int k = 0; k < block->predecessors()->length(); k++) {
626 HBasicBlock* predecessor = block->predecessors()->at(k);
627 ASSERT(predecessor->end()->IsGoto() ||
628 predecessor->end()->IsDeoptimize());
629 ASSERT(predecessor->last_environment()->ast_id() == id);
634 // Check special property of first block to have no predecessors.
635 ASSERT(blocks_.at(0)->predecessors()->is_empty());
637 if (do_full_verify) {
638 // Check that the graph is fully connected.
639 ReachabilityAnalyzer analyzer(entry_block_, blocks_.length(), NULL);
640 ASSERT(analyzer.visited_count() == blocks_.length());
642 // Check that entry block dominator is NULL.
643 ASSERT(entry_block_->dominator() == NULL);
646 for (int i = 0; i < blocks_.length(); ++i) {
647 HBasicBlock* block = blocks_.at(i);
648 if (block->dominator() == NULL) {
649 // Only start block may have no dominator assigned to.
652 // Assert that block is unreachable if dominator must not be visited.
653 ReachabilityAnalyzer dominator_analyzer(entry_block_,
656 ASSERT(!dominator_analyzer.reachable()->Contains(block->block_id()));
665 HConstant* HGraph::GetConstant(SetOncePointer<HConstant>* pointer,
667 if (!pointer->is_set()) {
668 // Can't pass GetInvalidContext() to HConstant::New, because that will
669 // recursively call GetConstant
670 HConstant* constant = HConstant::New(zone(), NULL, value);
671 constant->InsertAfter(entry_block()->first());
672 pointer->set(constant);
675 return ReinsertConstantIfNecessary(pointer->get());
679 HConstant* HGraph::ReinsertConstantIfNecessary(HConstant* constant) {
680 if (!constant->IsLinked()) {
681 // The constant was removed from the graph. Reinsert.
682 constant->ClearFlag(HValue::kIsDead);
683 constant->InsertAfter(entry_block()->first());
689 HConstant* HGraph::GetConstant0() {
690 return GetConstant(&constant_0_, 0);
694 HConstant* HGraph::GetConstant1() {
695 return GetConstant(&constant_1_, 1);
699 HConstant* HGraph::GetConstantMinus1() {
700 return GetConstant(&constant_minus1_, -1);
704 #define DEFINE_GET_CONSTANT(Name, name, htype, boolean_value) \
705 HConstant* HGraph::GetConstant##Name() { \
706 if (!constant_##name##_.is_set()) { \
707 HConstant* constant = new(zone()) HConstant( \
708 Unique<Object>::CreateImmovable(isolate()->factory()->name##_value()), \
709 Representation::Tagged(), \
715 constant->InsertAfter(entry_block()->first()); \
716 constant_##name##_.set(constant); \
718 return ReinsertConstantIfNecessary(constant_##name##_.get()); \
722 DEFINE_GET_CONSTANT(Undefined, undefined, HType::Tagged(), false)
723 DEFINE_GET_CONSTANT(True, true, HType::Boolean(), true)
724 DEFINE_GET_CONSTANT(False, false, HType::Boolean(), false)
725 DEFINE_GET_CONSTANT(Hole, the_hole, HType::Tagged(), false)
726 DEFINE_GET_CONSTANT(Null, null, HType::Tagged(), false)
729 #undef DEFINE_GET_CONSTANT
731 #define DEFINE_IS_CONSTANT(Name, name) \
732 bool HGraph::IsConstant##Name(HConstant* constant) { \
733 return constant_##name##_.is_set() && constant == constant_##name##_.get(); \
735 DEFINE_IS_CONSTANT(Undefined, undefined)
736 DEFINE_IS_CONSTANT(0, 0)
737 DEFINE_IS_CONSTANT(1, 1)
738 DEFINE_IS_CONSTANT(Minus1, minus1)
739 DEFINE_IS_CONSTANT(True, true)
740 DEFINE_IS_CONSTANT(False, false)
741 DEFINE_IS_CONSTANT(Hole, the_hole)
742 DEFINE_IS_CONSTANT(Null, null)
744 #undef DEFINE_IS_CONSTANT
747 HConstant* HGraph::GetInvalidContext() {
748 return GetConstant(&constant_invalid_context_, 0xFFFFC0C7);
752 bool HGraph::IsStandardConstant(HConstant* constant) {
753 if (IsConstantUndefined(constant)) return true;
754 if (IsConstant0(constant)) return true;
755 if (IsConstant1(constant)) return true;
756 if (IsConstantMinus1(constant)) return true;
757 if (IsConstantTrue(constant)) return true;
758 if (IsConstantFalse(constant)) return true;
759 if (IsConstantHole(constant)) return true;
760 if (IsConstantNull(constant)) return true;
765 HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder)
774 needs_compare_(true),
775 pending_merge_block_(false),
776 split_edge_merge_block_(NULL),
777 merge_at_join_blocks_(NULL),
778 normal_merge_at_join_block_count_(0),
779 deopt_merge_at_join_block_count_(0) {
780 HEnvironment* env = builder->environment();
781 first_true_block_ = builder->CreateBasicBlock(env->Copy());
782 first_false_block_ = builder->CreateBasicBlock(env->Copy());
786 HGraphBuilder::IfBuilder::IfBuilder(
787 HGraphBuilder* builder,
788 HIfContinuation* continuation)
797 needs_compare_(false),
798 pending_merge_block_(false),
799 first_true_block_(NULL),
800 first_false_block_(NULL),
801 split_edge_merge_block_(NULL),
802 merge_at_join_blocks_(NULL),
803 normal_merge_at_join_block_count_(0),
804 deopt_merge_at_join_block_count_(0) {
805 continuation->Continue(&first_true_block_,
806 &first_false_block_);
810 HControlInstruction* HGraphBuilder::IfBuilder::AddCompare(
811 HControlInstruction* compare) {
812 ASSERT(did_then_ == did_else_);
814 // Handle if-then-elseif
820 pending_merge_block_ = false;
821 split_edge_merge_block_ = NULL;
822 HEnvironment* env = builder_->environment();
823 first_true_block_ = builder_->CreateBasicBlock(env->Copy());
824 first_false_block_ = builder_->CreateBasicBlock(env->Copy());
826 if (split_edge_merge_block_ != NULL) {
827 HEnvironment* env = first_false_block_->last_environment();
828 HBasicBlock* split_edge =
829 builder_->CreateBasicBlock(env->Copy());
831 compare->SetSuccessorAt(0, split_edge);
832 compare->SetSuccessorAt(1, first_false_block_);
834 compare->SetSuccessorAt(0, first_true_block_);
835 compare->SetSuccessorAt(1, split_edge);
837 builder_->GotoNoSimulate(split_edge, split_edge_merge_block_);
839 compare->SetSuccessorAt(0, first_true_block_);
840 compare->SetSuccessorAt(1, first_false_block_);
842 builder_->FinishCurrentBlock(compare);
843 needs_compare_ = false;
848 void HGraphBuilder::IfBuilder::Or() {
849 ASSERT(!needs_compare_);
852 HEnvironment* env = first_false_block_->last_environment();
853 if (split_edge_merge_block_ == NULL) {
854 split_edge_merge_block_ =
855 builder_->CreateBasicBlock(env->Copy());
856 builder_->GotoNoSimulate(first_true_block_, split_edge_merge_block_);
857 first_true_block_ = split_edge_merge_block_;
859 builder_->set_current_block(first_false_block_);
860 first_false_block_ = builder_->CreateBasicBlock(env->Copy());
864 void HGraphBuilder::IfBuilder::And() {
865 ASSERT(!needs_compare_);
868 HEnvironment* env = first_false_block_->last_environment();
869 if (split_edge_merge_block_ == NULL) {
870 split_edge_merge_block_ = builder_->CreateBasicBlock(env->Copy());
871 builder_->GotoNoSimulate(first_false_block_, split_edge_merge_block_);
872 first_false_block_ = split_edge_merge_block_;
874 builder_->set_current_block(first_true_block_);
875 first_true_block_ = builder_->CreateBasicBlock(env->Copy());
879 void HGraphBuilder::IfBuilder::CaptureContinuation(
880 HIfContinuation* continuation) {
881 ASSERT(!did_else_if_);
885 HBasicBlock* true_block = NULL;
886 HBasicBlock* false_block = NULL;
887 Finish(&true_block, &false_block);
888 ASSERT(true_block != NULL);
889 ASSERT(false_block != NULL);
890 continuation->Capture(true_block, false_block);
892 builder_->set_current_block(NULL);
897 void HGraphBuilder::IfBuilder::JoinContinuation(HIfContinuation* continuation) {
898 ASSERT(!did_else_if_);
901 HBasicBlock* true_block = NULL;
902 HBasicBlock* false_block = NULL;
903 Finish(&true_block, &false_block);
904 merge_at_join_blocks_ = NULL;
905 if (true_block != NULL && !true_block->IsFinished()) {
906 ASSERT(continuation->IsTrueReachable());
907 builder_->GotoNoSimulate(true_block, continuation->true_branch());
909 if (false_block != NULL && !false_block->IsFinished()) {
910 ASSERT(continuation->IsFalseReachable());
911 builder_->GotoNoSimulate(false_block, continuation->false_branch());
918 void HGraphBuilder::IfBuilder::Then() {
922 if (needs_compare_) {
923 // Handle if's without any expressions, they jump directly to the "else"
924 // branch. However, we must pretend that the "then" branch is reachable,
925 // so that the graph builder visits it and sees any live range extending
926 // constructs within it.
927 HConstant* constant_false = builder_->graph()->GetConstantFalse();
928 ToBooleanStub::Types boolean_type = ToBooleanStub::Types();
929 boolean_type.Add(ToBooleanStub::BOOLEAN);
930 HBranch* branch = builder()->New<HBranch>(
931 constant_false, boolean_type, first_true_block_, first_false_block_);
932 builder_->FinishCurrentBlock(branch);
934 builder_->set_current_block(first_true_block_);
935 pending_merge_block_ = true;
939 void HGraphBuilder::IfBuilder::Else() {
943 AddMergeAtJoinBlock(false);
944 builder_->set_current_block(first_false_block_);
945 pending_merge_block_ = true;
950 void HGraphBuilder::IfBuilder::Deopt(const char* reason) {
952 builder_->Add<HDeoptimize>(reason, Deoptimizer::EAGER);
953 AddMergeAtJoinBlock(true);
957 void HGraphBuilder::IfBuilder::Return(HValue* value) {
958 HValue* parameter_count = builder_->graph()->GetConstantMinus1();
959 builder_->FinishExitCurrentBlock(
960 builder_->New<HReturn>(value, parameter_count));
961 AddMergeAtJoinBlock(false);
965 void HGraphBuilder::IfBuilder::AddMergeAtJoinBlock(bool deopt) {
966 if (!pending_merge_block_) return;
967 HBasicBlock* block = builder_->current_block();
968 ASSERT(block == NULL || !block->IsFinished());
969 MergeAtJoinBlock* record =
970 new(builder_->zone()) MergeAtJoinBlock(block, deopt,
971 merge_at_join_blocks_);
972 merge_at_join_blocks_ = record;
974 ASSERT(block->end() == NULL);
976 normal_merge_at_join_block_count_++;
978 deopt_merge_at_join_block_count_++;
981 builder_->set_current_block(NULL);
982 pending_merge_block_ = false;
986 void HGraphBuilder::IfBuilder::Finish() {
991 AddMergeAtJoinBlock(false);
994 AddMergeAtJoinBlock(false);
1000 void HGraphBuilder::IfBuilder::Finish(HBasicBlock** then_continuation,
1001 HBasicBlock** else_continuation) {
1004 MergeAtJoinBlock* else_record = merge_at_join_blocks_;
1005 if (else_continuation != NULL) {
1006 *else_continuation = else_record->block_;
1008 MergeAtJoinBlock* then_record = else_record->next_;
1009 if (then_continuation != NULL) {
1010 *then_continuation = then_record->block_;
1012 ASSERT(then_record->next_ == NULL);
1016 void HGraphBuilder::IfBuilder::End() {
1017 if (captured_) return;
1020 int total_merged_blocks = normal_merge_at_join_block_count_ +
1021 deopt_merge_at_join_block_count_;
1022 ASSERT(total_merged_blocks >= 1);
1023 HBasicBlock* merge_block = total_merged_blocks == 1
1024 ? NULL : builder_->graph()->CreateBasicBlock();
1026 // Merge non-deopt blocks first to ensure environment has right size for
1028 MergeAtJoinBlock* current = merge_at_join_blocks_;
1029 while (current != NULL) {
1030 if (!current->deopt_ && current->block_ != NULL) {
1031 // If there is only one block that makes it through to the end of the
1032 // if, then just set it as the current block and continue rather then
1033 // creating an unnecessary merge block.
1034 if (total_merged_blocks == 1) {
1035 builder_->set_current_block(current->block_);
1038 builder_->GotoNoSimulate(current->block_, merge_block);
1040 current = current->next_;
1043 // Merge deopt blocks, padding when necessary.
1044 current = merge_at_join_blocks_;
1045 while (current != NULL) {
1046 if (current->deopt_ && current->block_ != NULL) {
1047 current->block_->FinishExit(
1048 HAbnormalExit::New(builder_->zone(), NULL),
1049 HSourcePosition::Unknown());
1051 current = current->next_;
1053 builder_->set_current_block(merge_block);
1057 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder,
1059 LoopBuilder::Direction direction)
1060 : builder_(builder),
1062 direction_(direction),
1064 header_block_ = builder->CreateLoopHeaderBlock();
1067 exit_trampoline_block_ = NULL;
1068 increment_amount_ = builder_->graph()->GetConstant1();
1072 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder,
1074 LoopBuilder::Direction direction,
1075 HValue* increment_amount)
1076 : builder_(builder),
1078 direction_(direction),
1080 header_block_ = builder->CreateLoopHeaderBlock();
1083 exit_trampoline_block_ = NULL;
1084 increment_amount_ = increment_amount;
1088 HValue* HGraphBuilder::LoopBuilder::BeginBody(
1090 HValue* terminating,
1091 Token::Value token) {
1092 HEnvironment* env = builder_->environment();
1093 phi_ = header_block_->AddNewPhi(env->values()->length());
1094 phi_->AddInput(initial);
1096 builder_->GotoNoSimulate(header_block_);
1098 HEnvironment* body_env = env->Copy();
1099 HEnvironment* exit_env = env->Copy();
1100 // Remove the phi from the expression stack
1103 body_block_ = builder_->CreateBasicBlock(body_env);
1104 exit_block_ = builder_->CreateBasicBlock(exit_env);
1106 builder_->set_current_block(header_block_);
1108 builder_->FinishCurrentBlock(builder_->New<HCompareNumericAndBranch>(
1109 phi_, terminating, token, body_block_, exit_block_));
1111 builder_->set_current_block(body_block_);
1112 if (direction_ == kPreIncrement || direction_ == kPreDecrement) {
1113 HValue* one = builder_->graph()->GetConstant1();
1114 if (direction_ == kPreIncrement) {
1115 increment_ = HAdd::New(zone(), context_, phi_, one);
1117 increment_ = HSub::New(zone(), context_, phi_, one);
1119 increment_->ClearFlag(HValue::kCanOverflow);
1120 builder_->AddInstruction(increment_);
1128 void HGraphBuilder::LoopBuilder::Break() {
1129 if (exit_trampoline_block_ == NULL) {
1130 // Its the first time we saw a break.
1131 HEnvironment* env = exit_block_->last_environment()->Copy();
1132 exit_trampoline_block_ = builder_->CreateBasicBlock(env);
1133 builder_->GotoNoSimulate(exit_block_, exit_trampoline_block_);
1136 builder_->GotoNoSimulate(exit_trampoline_block_);
1137 builder_->set_current_block(NULL);
1141 void HGraphBuilder::LoopBuilder::EndBody() {
1144 if (direction_ == kPostIncrement || direction_ == kPostDecrement) {
1145 if (direction_ == kPostIncrement) {
1146 increment_ = HAdd::New(zone(), context_, phi_, increment_amount_);
1148 increment_ = HSub::New(zone(), context_, phi_, increment_amount_);
1150 increment_->ClearFlag(HValue::kCanOverflow);
1151 builder_->AddInstruction(increment_);
1154 // Push the new increment value on the expression stack to merge into the phi.
1155 builder_->environment()->Push(increment_);
1156 HBasicBlock* last_block = builder_->current_block();
1157 builder_->GotoNoSimulate(last_block, header_block_);
1158 header_block_->loop_information()->RegisterBackEdge(last_block);
1160 if (exit_trampoline_block_ != NULL) {
1161 builder_->set_current_block(exit_trampoline_block_);
1163 builder_->set_current_block(exit_block_);
1169 HGraph* HGraphBuilder::CreateGraph() {
1170 graph_ = new(zone()) HGraph(info_);
1171 if (FLAG_hydrogen_stats) isolate()->GetHStatistics()->Initialize(info_);
1172 CompilationPhase phase("H_Block building", info_);
1173 set_current_block(graph()->entry_block());
1174 if (!BuildGraph()) return NULL;
1175 graph()->FinalizeUniqueness();
1180 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
1181 ASSERT(current_block() != NULL);
1182 ASSERT(!FLAG_hydrogen_track_positions ||
1183 !position_.IsUnknown() ||
1184 !info_->IsOptimizing());
1185 current_block()->AddInstruction(instr, source_position());
1186 if (graph()->IsInsideNoSideEffectsScope()) {
1187 instr->SetFlag(HValue::kHasNoObservableSideEffects);
1193 void HGraphBuilder::FinishCurrentBlock(HControlInstruction* last) {
1194 ASSERT(!FLAG_hydrogen_track_positions ||
1195 !info_->IsOptimizing() ||
1196 !position_.IsUnknown());
1197 current_block()->Finish(last, source_position());
1198 if (last->IsReturn() || last->IsAbnormalExit()) {
1199 set_current_block(NULL);
1204 void HGraphBuilder::FinishExitCurrentBlock(HControlInstruction* instruction) {
1205 ASSERT(!FLAG_hydrogen_track_positions || !info_->IsOptimizing() ||
1206 !position_.IsUnknown());
1207 current_block()->FinishExit(instruction, source_position());
1208 if (instruction->IsReturn() || instruction->IsAbnormalExit()) {
1209 set_current_block(NULL);
1214 void HGraphBuilder::AddIncrementCounter(StatsCounter* counter) {
1215 if (FLAG_native_code_counters && counter->Enabled()) {
1216 HValue* reference = Add<HConstant>(ExternalReference(counter));
1217 HValue* old_value = Add<HLoadNamedField>(
1218 reference, static_cast<HValue*>(NULL), HObjectAccess::ForCounter());
1219 HValue* new_value = AddUncasted<HAdd>(old_value, graph()->GetConstant1());
1220 new_value->ClearFlag(HValue::kCanOverflow); // Ignore counter overflow
1221 Add<HStoreNamedField>(reference, HObjectAccess::ForCounter(),
1222 new_value, STORE_TO_INITIALIZED_ENTRY);
1227 void HGraphBuilder::AddSimulate(BailoutId id,
1228 RemovableSimulate removable) {
1229 ASSERT(current_block() != NULL);
1230 ASSERT(!graph()->IsInsideNoSideEffectsScope());
1231 current_block()->AddNewSimulate(id, source_position(), removable);
1235 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) {
1236 HBasicBlock* b = graph()->CreateBasicBlock();
1237 b->SetInitialEnvironment(env);
1242 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() {
1243 HBasicBlock* header = graph()->CreateBasicBlock();
1244 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header);
1245 header->SetInitialEnvironment(entry_env);
1246 header->AttachLoopInformation();
1251 HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) {
1252 if (obj->type().IsHeapObject()) return obj;
1253 return Add<HCheckHeapObject>(obj);
1257 void HGraphBuilder::FinishExitWithHardDeoptimization(const char* reason) {
1258 Add<HDeoptimize>(reason, Deoptimizer::EAGER);
1259 FinishExitCurrentBlock(New<HAbnormalExit>());
1263 HValue* HGraphBuilder::BuildCheckMap(HValue* obj, Handle<Map> map) {
1264 return Add<HCheckMaps>(obj, map, top_info());
1268 HValue* HGraphBuilder::BuildCheckString(HValue* string) {
1269 if (!string->type().IsString()) {
1270 ASSERT(!string->IsConstant() ||
1271 !HConstant::cast(string)->HasStringValue());
1272 BuildCheckHeapObject(string);
1273 return Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING);
1279 HValue* HGraphBuilder::BuildWrapReceiver(HValue* object, HValue* function) {
1280 if (object->type().IsJSObject()) return object;
1281 if (function->IsConstant() &&
1282 HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
1283 Handle<JSFunction> f = Handle<JSFunction>::cast(
1284 HConstant::cast(function)->handle(isolate()));
1285 SharedFunctionInfo* shared = f->shared();
1286 if (shared->strict_mode() == STRICT || shared->native()) return object;
1288 return Add<HWrapReceiver>(object, function);
1292 HValue* HGraphBuilder::BuildCheckForCapacityGrow(
1299 PropertyAccessType access_type) {
1300 IfBuilder length_checker(this);
1302 Token::Value token = IsHoleyElementsKind(kind) ? Token::GTE : Token::EQ;
1303 length_checker.If<HCompareNumericAndBranch>(key, length, token);
1305 length_checker.Then();
1307 HValue* current_capacity = AddLoadFixedArrayLength(elements);
1309 IfBuilder capacity_checker(this);
1311 capacity_checker.If<HCompareNumericAndBranch>(key, current_capacity,
1313 capacity_checker.Then();
1315 HValue* max_gap = Add<HConstant>(static_cast<int32_t>(JSObject::kMaxGap));
1316 HValue* max_capacity = AddUncasted<HAdd>(current_capacity, max_gap);
1317 IfBuilder key_checker(this);
1318 key_checker.If<HCompareNumericAndBranch>(key, max_capacity, Token::LT);
1320 key_checker.ElseDeopt("Key out of capacity range");
1323 HValue* new_capacity = BuildNewElementsCapacity(key);
1324 HValue* new_elements = BuildGrowElementsCapacity(object, elements,
1328 environment()->Push(new_elements);
1329 capacity_checker.Else();
1331 environment()->Push(elements);
1332 capacity_checker.End();
1335 HValue* new_length = AddUncasted<HAdd>(key, graph_->GetConstant1());
1336 new_length->ClearFlag(HValue::kCanOverflow);
1338 Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(kind),
1342 if (access_type == STORE && kind == FAST_SMI_ELEMENTS) {
1343 HValue* checked_elements = environment()->Top();
1345 // Write zero to ensure that the new element is initialized with some smi.
1346 Add<HStoreKeyed>(checked_elements, key, graph()->GetConstant0(), kind);
1349 length_checker.Else();
1350 Add<HBoundsCheck>(key, length);
1352 environment()->Push(elements);
1353 length_checker.End();
1355 return environment()->Pop();
1359 HValue* HGraphBuilder::BuildCopyElementsOnWrite(HValue* object,
1363 Factory* factory = isolate()->factory();
1365 IfBuilder cow_checker(this);
1367 cow_checker.If<HCompareMap>(elements, factory->fixed_cow_array_map());
1370 HValue* capacity = AddLoadFixedArrayLength(elements);
1372 HValue* new_elements = BuildGrowElementsCapacity(object, elements, kind,
1373 kind, length, capacity);
1375 environment()->Push(new_elements);
1379 environment()->Push(elements);
1383 return environment()->Pop();
1387 void HGraphBuilder::BuildTransitionElementsKind(HValue* object,
1389 ElementsKind from_kind,
1390 ElementsKind to_kind,
1392 ASSERT(!IsFastHoleyElementsKind(from_kind) ||
1393 IsFastHoleyElementsKind(to_kind));
1395 if (AllocationSite::GetMode(from_kind, to_kind) == TRACK_ALLOCATION_SITE) {
1396 Add<HTrapAllocationMemento>(object);
1399 if (!IsSimpleMapChangeTransition(from_kind, to_kind)) {
1400 HInstruction* elements = AddLoadElements(object);
1402 HInstruction* empty_fixed_array = Add<HConstant>(
1403 isolate()->factory()->empty_fixed_array());
1405 IfBuilder if_builder(this);
1407 if_builder.IfNot<HCompareObjectEqAndBranch>(elements, empty_fixed_array);
1411 HInstruction* elements_length = AddLoadFixedArrayLength(elements);
1413 HInstruction* array_length = is_jsarray
1414 ? Add<HLoadNamedField>(object, static_cast<HValue*>(NULL),
1415 HObjectAccess::ForArrayLength(from_kind))
1418 BuildGrowElementsCapacity(object, elements, from_kind, to_kind,
1419 array_length, elements_length);
1424 Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map);
1428 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoadHelper(
1433 int current_probe) {
1434 if (current_probe == kNumberDictionaryProbes) {
1438 int32_t offset = SeededNumberDictionary::GetProbeOffset(current_probe);
1439 HValue* raw_index = (current_probe == 0)
1441 : AddUncasted<HAdd>(hash, Add<HConstant>(offset));
1442 raw_index = AddUncasted<HBitwise>(Token::BIT_AND, raw_index, mask);
1443 int32_t entry_size = SeededNumberDictionary::kEntrySize;
1444 raw_index = AddUncasted<HMul>(raw_index, Add<HConstant>(entry_size));
1445 raw_index->ClearFlag(HValue::kCanOverflow);
1447 int32_t base_offset = SeededNumberDictionary::kElementsStartIndex;
1448 HValue* key_index = AddUncasted<HAdd>(raw_index, Add<HConstant>(base_offset));
1449 key_index->ClearFlag(HValue::kCanOverflow);
1451 HValue* candidate_key = Add<HLoadKeyed>(elements, key_index,
1452 static_cast<HValue*>(NULL),
1455 IfBuilder key_compare(this);
1456 key_compare.IfNot<HCompareObjectEqAndBranch>(key, candidate_key);
1459 // Key at the current probe doesn't match, try at the next probe.
1460 HValue* result = BuildUncheckedDictionaryElementLoadHelper(
1461 elements, key, hash, mask, current_probe + 1);
1462 if (result == NULL) {
1463 key_compare.Deopt("probes exhausted in keyed load dictionary lookup");
1464 result = graph()->GetConstantUndefined();
1471 // Key at current probe matches. Details must be zero, otherwise the
1472 // dictionary element requires special handling.
1473 HValue* details_index = AddUncasted<HAdd>(
1474 raw_index, Add<HConstant>(base_offset + 2));
1475 details_index->ClearFlag(HValue::kCanOverflow);
1477 HValue* details = Add<HLoadKeyed>(elements, details_index,
1478 static_cast<HValue*>(NULL),
1480 IfBuilder details_compare(this);
1481 details_compare.If<HCompareNumericAndBranch>(details,
1482 graph()->GetConstant0(),
1484 details_compare.ThenDeopt("keyed load dictionary element not fast case");
1486 details_compare.Else();
1488 // Key matches and details are zero --> fast case. Load and return the
1490 HValue* result_index = AddUncasted<HAdd>(
1491 raw_index, Add<HConstant>(base_offset + 1));
1492 result_index->ClearFlag(HValue::kCanOverflow);
1494 Push(Add<HLoadKeyed>(elements, result_index,
1495 static_cast<HValue*>(NULL),
1498 details_compare.End();
1506 HValue* HGraphBuilder::BuildElementIndexHash(HValue* index) {
1507 int32_t seed_value = static_cast<uint32_t>(isolate()->heap()->HashSeed());
1508 HValue* seed = Add<HConstant>(seed_value);
1509 HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, index, seed);
1511 // hash = ~hash + (hash << 15);
1512 HValue* shifted_hash = AddUncasted<HShl>(hash, Add<HConstant>(15));
1513 HValue* not_hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash,
1514 graph()->GetConstantMinus1());
1515 hash = AddUncasted<HAdd>(shifted_hash, not_hash);
1517 // hash = hash ^ (hash >> 12);
1518 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(12));
1519 hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
1521 // hash = hash + (hash << 2);
1522 shifted_hash = AddUncasted<HShl>(hash, Add<HConstant>(2));
1523 hash = AddUncasted<HAdd>(hash, shifted_hash);
1525 // hash = hash ^ (hash >> 4);
1526 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(4));
1527 hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
1529 // hash = hash * 2057;
1530 hash = AddUncasted<HMul>(hash, Add<HConstant>(2057));
1531 hash->ClearFlag(HValue::kCanOverflow);
1533 // hash = hash ^ (hash >> 16);
1534 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(16));
1535 return AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
1539 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver,
1541 HValue* elements = AddLoadElements(receiver);
1543 HValue* hash = BuildElementIndexHash(key);
1545 HValue* capacity = Add<HLoadKeyed>(
1547 Add<HConstant>(NameDictionary::kCapacityIndex),
1548 static_cast<HValue*>(NULL),
1551 HValue* mask = AddUncasted<HSub>(capacity, graph()->GetConstant1());
1552 mask->ChangeRepresentation(Representation::Integer32());
1553 mask->ClearFlag(HValue::kCanOverflow);
1555 return BuildUncheckedDictionaryElementLoadHelper(elements, key,
1560 HValue* HGraphBuilder::BuildRegExpConstructResult(HValue* length,
1563 NoObservableSideEffectsScope scope(this);
1565 // Compute the size of the RegExpResult followed by FixedArray with length.
1566 HValue* size = length;
1567 size = AddUncasted<HShl>(size, Add<HConstant>(kPointerSizeLog2));
1568 size = AddUncasted<HAdd>(size, Add<HConstant>(static_cast<int32_t>(
1569 JSRegExpResult::kSize + FixedArray::kHeaderSize)));
1571 // Make sure size does not exceeds max regular heap object size.
1572 Add<HBoundsCheck>(size, Add<HConstant>(Page::kMaxRegularHeapObjectSize));
1574 // Allocate the JSRegExpResult and the FixedArray in one step.
1575 HValue* result = Add<HAllocate>(
1576 size, HType::JSArray(), NOT_TENURED, JS_ARRAY_TYPE);
1578 // Determine the elements FixedArray.
1579 HValue* elements = Add<HInnerAllocatedObject>(
1580 result, Add<HConstant>(JSRegExpResult::kSize));
1582 // Initialize the JSRegExpResult header.
1583 HValue* global_object = Add<HLoadNamedField>(
1584 context(), static_cast<HValue*>(NULL),
1585 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
1586 HValue* native_context = Add<HLoadNamedField>(
1587 global_object, static_cast<HValue*>(NULL),
1588 HObjectAccess::ForGlobalObjectNativeContext());
1589 AddStoreMapNoWriteBarrier(result, Add<HLoadNamedField>(
1590 native_context, static_cast<HValue*>(NULL),
1591 HObjectAccess::ForContextSlot(Context::REGEXP_RESULT_MAP_INDEX)));
1592 Add<HStoreNamedField>(
1593 result, HObjectAccess::ForJSArrayOffset(JSArray::kPropertiesOffset),
1594 Add<HConstant>(isolate()->factory()->empty_fixed_array()));
1595 Add<HStoreNamedField>(
1596 result, HObjectAccess::ForJSArrayOffset(JSArray::kElementsOffset),
1598 Add<HStoreNamedField>(
1599 result, HObjectAccess::ForJSArrayOffset(JSArray::kLengthOffset), length);
1601 // Initialize the additional fields.
1602 Add<HStoreNamedField>(
1603 result, HObjectAccess::ForJSArrayOffset(JSRegExpResult::kIndexOffset),
1605 Add<HStoreNamedField>(
1606 result, HObjectAccess::ForJSArrayOffset(JSRegExpResult::kInputOffset),
1609 // Initialize the elements header.
1610 AddStoreMapConstantNoWriteBarrier(elements,
1611 isolate()->factory()->fixed_array_map());
1612 Add<HStoreNamedField>(elements, HObjectAccess::ForFixedArrayLength(), length);
1614 // Initialize the elements contents with undefined.
1615 LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement);
1616 index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT);
1618 Add<HStoreKeyed>(elements, index, graph()->GetConstantUndefined(),
1627 HValue* HGraphBuilder::BuildNumberToString(HValue* object, Type* type) {
1628 NoObservableSideEffectsScope scope(this);
1630 // Convert constant numbers at compile time.
1631 if (object->IsConstant() && HConstant::cast(object)->HasNumberValue()) {
1632 Handle<Object> number = HConstant::cast(object)->handle(isolate());
1633 Handle<String> result = isolate()->factory()->NumberToString(number);
1634 return Add<HConstant>(result);
1637 // Create a joinable continuation.
1638 HIfContinuation found(graph()->CreateBasicBlock(),
1639 graph()->CreateBasicBlock());
1641 // Load the number string cache.
1642 HValue* number_string_cache =
1643 Add<HLoadRoot>(Heap::kNumberStringCacheRootIndex);
1645 // Make the hash mask from the length of the number string cache. It
1646 // contains two elements (number and string) for each cache entry.
1647 HValue* mask = AddLoadFixedArrayLength(number_string_cache);
1648 mask->set_type(HType::Smi());
1649 mask = AddUncasted<HSar>(mask, graph()->GetConstant1());
1650 mask = AddUncasted<HSub>(mask, graph()->GetConstant1());
1652 // Check whether object is a smi.
1653 IfBuilder if_objectissmi(this);
1654 if_objectissmi.If<HIsSmiAndBranch>(object);
1655 if_objectissmi.Then();
1657 // Compute hash for smi similar to smi_get_hash().
1658 HValue* hash = AddUncasted<HBitwise>(Token::BIT_AND, object, mask);
1661 HValue* key_index = AddUncasted<HShl>(hash, graph()->GetConstant1());
1662 HValue* key = Add<HLoadKeyed>(number_string_cache, key_index,
1663 static_cast<HValue*>(NULL),
1664 FAST_ELEMENTS, ALLOW_RETURN_HOLE);
1666 // Check if object == key.
1667 IfBuilder if_objectiskey(this);
1668 if_objectiskey.If<HCompareObjectEqAndBranch>(object, key);
1669 if_objectiskey.Then();
1671 // Make the key_index available.
1674 if_objectiskey.JoinContinuation(&found);
1676 if_objectissmi.Else();
1678 if (type->Is(Type::SignedSmall())) {
1679 if_objectissmi.Deopt("Expected smi");
1681 // Check if the object is a heap number.
1682 IfBuilder if_objectisnumber(this);
1683 HValue* objectisnumber = if_objectisnumber.If<HCompareMap>(
1684 object, isolate()->factory()->heap_number_map());
1685 if_objectisnumber.Then();
1687 // Compute hash for heap number similar to double_get_hash().
1688 HValue* low = Add<HLoadNamedField>(
1689 object, objectisnumber,
1690 HObjectAccess::ForHeapNumberValueLowestBits());
1691 HValue* high = Add<HLoadNamedField>(
1692 object, objectisnumber,
1693 HObjectAccess::ForHeapNumberValueHighestBits());
1694 HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, low, high);
1695 hash = AddUncasted<HBitwise>(Token::BIT_AND, hash, mask);
1698 HValue* key_index = AddUncasted<HShl>(hash, graph()->GetConstant1());
1699 HValue* key = Add<HLoadKeyed>(number_string_cache, key_index,
1700 static_cast<HValue*>(NULL),
1701 FAST_ELEMENTS, ALLOW_RETURN_HOLE);
1703 // Check if key is a heap number (the number string cache contains only
1704 // SMIs and heap number, so it is sufficient to do a SMI check here).
1705 IfBuilder if_keyisnotsmi(this);
1706 HValue* keyisnotsmi = if_keyisnotsmi.IfNot<HIsSmiAndBranch>(key);
1707 if_keyisnotsmi.Then();
1709 // Check if values of key and object match.
1710 IfBuilder if_keyeqobject(this);
1711 if_keyeqobject.If<HCompareNumericAndBranch>(
1712 Add<HLoadNamedField>(key, keyisnotsmi,
1713 HObjectAccess::ForHeapNumberValue()),
1714 Add<HLoadNamedField>(object, objectisnumber,
1715 HObjectAccess::ForHeapNumberValue()),
1717 if_keyeqobject.Then();
1719 // Make the key_index available.
1722 if_keyeqobject.JoinContinuation(&found);
1724 if_keyisnotsmi.JoinContinuation(&found);
1726 if_objectisnumber.Else();
1728 if (type->Is(Type::Number())) {
1729 if_objectisnumber.Deopt("Expected heap number");
1732 if_objectisnumber.JoinContinuation(&found);
1735 if_objectissmi.JoinContinuation(&found);
1737 // Check for cache hit.
1738 IfBuilder if_found(this, &found);
1741 // Count number to string operation in native code.
1742 AddIncrementCounter(isolate()->counters()->number_to_string_native());
1744 // Load the value in case of cache hit.
1745 HValue* key_index = Pop();
1746 HValue* value_index = AddUncasted<HAdd>(key_index, graph()->GetConstant1());
1747 Push(Add<HLoadKeyed>(number_string_cache, value_index,
1748 static_cast<HValue*>(NULL),
1749 FAST_ELEMENTS, ALLOW_RETURN_HOLE));
1753 // Cache miss, fallback to runtime.
1754 Add<HPushArgument>(object);
1755 Push(Add<HCallRuntime>(
1756 isolate()->factory()->empty_string(),
1757 Runtime::FunctionForId(Runtime::kHiddenNumberToStringSkipCache),
1766 HAllocate* HGraphBuilder::BuildAllocate(
1767 HValue* object_size,
1769 InstanceType instance_type,
1770 HAllocationMode allocation_mode) {
1771 // Compute the effective allocation size.
1772 HValue* size = object_size;
1773 if (allocation_mode.CreateAllocationMementos()) {
1774 size = AddUncasted<HAdd>(size, Add<HConstant>(AllocationMemento::kSize));
1775 size->ClearFlag(HValue::kCanOverflow);
1778 // Perform the actual allocation.
1779 HAllocate* object = Add<HAllocate>(
1780 size, type, allocation_mode.GetPretenureMode(),
1781 instance_type, allocation_mode.feedback_site());
1783 // Setup the allocation memento.
1784 if (allocation_mode.CreateAllocationMementos()) {
1785 BuildCreateAllocationMemento(
1786 object, object_size, allocation_mode.current_site());
1793 HValue* HGraphBuilder::BuildAddStringLengths(HValue* left_length,
1794 HValue* right_length) {
1795 // Compute the combined string length and check against max string length.
1796 HValue* length = AddUncasted<HAdd>(left_length, right_length);
1797 HValue* max_length = Add<HConstant>(String::kMaxLength);
1798 Add<HBoundsCheck>(length, max_length);
1803 HValue* HGraphBuilder::BuildCreateConsString(
1807 HAllocationMode allocation_mode) {
1808 // Determine the string instance types.
1809 HInstruction* left_instance_type = AddLoadStringInstanceType(left);
1810 HInstruction* right_instance_type = AddLoadStringInstanceType(right);
1812 // Allocate the cons string object. HAllocate does not care whether we
1813 // pass CONS_STRING_TYPE or CONS_ASCII_STRING_TYPE here, so we just use
1814 // CONS_STRING_TYPE here. Below we decide whether the cons string is
1815 // one-byte or two-byte and set the appropriate map.
1816 ASSERT(HAllocate::CompatibleInstanceTypes(CONS_STRING_TYPE,
1817 CONS_ASCII_STRING_TYPE));
1818 HAllocate* result = BuildAllocate(Add<HConstant>(ConsString::kSize),
1819 HType::String(), CONS_STRING_TYPE,
1822 // Compute intersection and difference of instance types.
1823 HValue* anded_instance_types = AddUncasted<HBitwise>(
1824 Token::BIT_AND, left_instance_type, right_instance_type);
1825 HValue* xored_instance_types = AddUncasted<HBitwise>(
1826 Token::BIT_XOR, left_instance_type, right_instance_type);
1828 // We create a one-byte cons string if
1829 // 1. both strings are one-byte, or
1830 // 2. at least one of the strings is two-byte, but happens to contain only
1831 // one-byte characters.
1832 // To do this, we check
1833 // 1. if both strings are one-byte, or if the one-byte data hint is set in
1835 // 2. if one of the strings has the one-byte data hint set and the other
1836 // string is one-byte.
1837 IfBuilder if_onebyte(this);
1838 STATIC_ASSERT(kOneByteStringTag != 0);
1839 STATIC_ASSERT(kOneByteDataHintMask != 0);
1840 if_onebyte.If<HCompareNumericAndBranch>(
1841 AddUncasted<HBitwise>(
1842 Token::BIT_AND, anded_instance_types,
1843 Add<HConstant>(static_cast<int32_t>(
1844 kStringEncodingMask | kOneByteDataHintMask))),
1845 graph()->GetConstant0(), Token::NE);
1847 STATIC_ASSERT(kOneByteStringTag != 0 &&
1848 kOneByteDataHintTag != 0 &&
1849 kOneByteDataHintTag != kOneByteStringTag);
1850 if_onebyte.If<HCompareNumericAndBranch>(
1851 AddUncasted<HBitwise>(
1852 Token::BIT_AND, xored_instance_types,
1853 Add<HConstant>(static_cast<int32_t>(
1854 kOneByteStringTag | kOneByteDataHintTag))),
1855 Add<HConstant>(static_cast<int32_t>(
1856 kOneByteStringTag | kOneByteDataHintTag)), Token::EQ);
1859 // We can safely skip the write barrier for storing the map here.
1860 Handle<Map> map = isolate()->factory()->cons_ascii_string_map();
1861 AddStoreMapConstantNoWriteBarrier(result, map);
1865 // We can safely skip the write barrier for storing the map here.
1866 Handle<Map> map = isolate()->factory()->cons_string_map();
1867 AddStoreMapConstantNoWriteBarrier(result, map);
1871 // Initialize the cons string fields.
1872 Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(),
1873 Add<HConstant>(String::kEmptyHashField));
1874 Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length);
1875 Add<HStoreNamedField>(result, HObjectAccess::ForConsStringFirst(), left);
1876 Add<HStoreNamedField>(result, HObjectAccess::ForConsStringSecond(), right);
1878 // Count the native string addition.
1879 AddIncrementCounter(isolate()->counters()->string_add_native());
1885 void HGraphBuilder::BuildCopySeqStringChars(HValue* src,
1887 String::Encoding src_encoding,
1890 String::Encoding dst_encoding,
1892 ASSERT(dst_encoding != String::ONE_BYTE_ENCODING ||
1893 src_encoding == String::ONE_BYTE_ENCODING);
1894 LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement);
1895 HValue* index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT);
1897 HValue* src_index = AddUncasted<HAdd>(src_offset, index);
1899 AddUncasted<HSeqStringGetChar>(src_encoding, src, src_index);
1900 HValue* dst_index = AddUncasted<HAdd>(dst_offset, index);
1901 Add<HSeqStringSetChar>(dst_encoding, dst, dst_index, value);
1907 HValue* HGraphBuilder::BuildObjectSizeAlignment(
1908 HValue* unaligned_size, int header_size) {
1909 ASSERT((header_size & kObjectAlignmentMask) == 0);
1910 HValue* size = AddUncasted<HAdd>(
1911 unaligned_size, Add<HConstant>(static_cast<int32_t>(
1912 header_size + kObjectAlignmentMask)));
1913 size->ClearFlag(HValue::kCanOverflow);
1914 return AddUncasted<HBitwise>(
1915 Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>(
1916 ~kObjectAlignmentMask)));
1920 HValue* HGraphBuilder::BuildUncheckedStringAdd(
1923 HAllocationMode allocation_mode) {
1924 // Determine the string lengths.
1925 HValue* left_length = AddLoadStringLength(left);
1926 HValue* right_length = AddLoadStringLength(right);
1928 // Compute the combined string length.
1929 HValue* length = BuildAddStringLengths(left_length, right_length);
1931 // Do some manual constant folding here.
1932 if (left_length->IsConstant()) {
1933 HConstant* c_left_length = HConstant::cast(left_length);
1934 ASSERT_NE(0, c_left_length->Integer32Value());
1935 if (c_left_length->Integer32Value() + 1 >= ConsString::kMinLength) {
1936 // The right string contains at least one character.
1937 return BuildCreateConsString(length, left, right, allocation_mode);
1939 } else if (right_length->IsConstant()) {
1940 HConstant* c_right_length = HConstant::cast(right_length);
1941 ASSERT_NE(0, c_right_length->Integer32Value());
1942 if (c_right_length->Integer32Value() + 1 >= ConsString::kMinLength) {
1943 // The left string contains at least one character.
1944 return BuildCreateConsString(length, left, right, allocation_mode);
1948 // Check if we should create a cons string.
1949 IfBuilder if_createcons(this);
1950 if_createcons.If<HCompareNumericAndBranch>(
1951 length, Add<HConstant>(ConsString::kMinLength), Token::GTE);
1952 if_createcons.Then();
1954 // Create a cons string.
1955 Push(BuildCreateConsString(length, left, right, allocation_mode));
1957 if_createcons.Else();
1959 // Determine the string instance types.
1960 HValue* left_instance_type = AddLoadStringInstanceType(left);
1961 HValue* right_instance_type = AddLoadStringInstanceType(right);
1963 // Compute union and difference of instance types.
1964 HValue* ored_instance_types = AddUncasted<HBitwise>(
1965 Token::BIT_OR, left_instance_type, right_instance_type);
1966 HValue* xored_instance_types = AddUncasted<HBitwise>(
1967 Token::BIT_XOR, left_instance_type, right_instance_type);
1969 // Check if both strings have the same encoding and both are
1971 IfBuilder if_sameencodingandsequential(this);
1972 if_sameencodingandsequential.If<HCompareNumericAndBranch>(
1973 AddUncasted<HBitwise>(
1974 Token::BIT_AND, xored_instance_types,
1975 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))),
1976 graph()->GetConstant0(), Token::EQ);
1977 if_sameencodingandsequential.And();
1978 STATIC_ASSERT(kSeqStringTag == 0);
1979 if_sameencodingandsequential.If<HCompareNumericAndBranch>(
1980 AddUncasted<HBitwise>(
1981 Token::BIT_AND, ored_instance_types,
1982 Add<HConstant>(static_cast<int32_t>(kStringRepresentationMask))),
1983 graph()->GetConstant0(), Token::EQ);
1984 if_sameencodingandsequential.Then();
1986 HConstant* string_map =
1987 Add<HConstant>(isolate()->factory()->string_map());
1988 HConstant* ascii_string_map =
1989 Add<HConstant>(isolate()->factory()->ascii_string_map());
1991 // Determine map and size depending on whether result is one-byte string.
1992 IfBuilder if_onebyte(this);
1993 STATIC_ASSERT(kOneByteStringTag != 0);
1994 if_onebyte.If<HCompareNumericAndBranch>(
1995 AddUncasted<HBitwise>(
1996 Token::BIT_AND, ored_instance_types,
1997 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))),
1998 graph()->GetConstant0(), Token::NE);
2001 // Allocate sequential one-byte string object.
2003 Push(ascii_string_map);
2007 // Allocate sequential two-byte string object.
2008 HValue* size = AddUncasted<HShl>(length, graph()->GetConstant1());
2009 size->ClearFlag(HValue::kCanOverflow);
2010 size->SetFlag(HValue::kUint32);
2015 HValue* map = Pop();
2017 // Calculate the number of bytes needed for the characters in the
2018 // string while observing object alignment.
2019 STATIC_ASSERT((SeqString::kHeaderSize & kObjectAlignmentMask) == 0);
2020 HValue* size = BuildObjectSizeAlignment(Pop(), SeqString::kHeaderSize);
2022 // Allocate the string object. HAllocate does not care whether we pass
2023 // STRING_TYPE or ASCII_STRING_TYPE here, so we just use STRING_TYPE here.
2024 HAllocate* result = BuildAllocate(
2025 size, HType::String(), STRING_TYPE, allocation_mode);
2027 // We can safely skip the write barrier for storing map here.
2028 AddStoreMapNoWriteBarrier(result, map);
2030 // Initialize the string fields.
2031 Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(),
2032 Add<HConstant>(String::kEmptyHashField));
2033 Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length);
2035 // Copy characters to the result string.
2036 IfBuilder if_twobyte(this);
2037 if_twobyte.If<HCompareObjectEqAndBranch>(map, string_map);
2040 // Copy characters from the left string.
2041 BuildCopySeqStringChars(
2042 left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
2043 result, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
2046 // Copy characters from the right string.
2047 BuildCopySeqStringChars(
2048 right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
2049 result, left_length, String::TWO_BYTE_ENCODING,
2054 // Copy characters from the left string.
2055 BuildCopySeqStringChars(
2056 left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
2057 result, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
2060 // Copy characters from the right string.
2061 BuildCopySeqStringChars(
2062 right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
2063 result, left_length, String::ONE_BYTE_ENCODING,
2068 // Count the native string addition.
2069 AddIncrementCounter(isolate()->counters()->string_add_native());
2071 // Return the sequential string.
2074 if_sameencodingandsequential.Else();
2076 // Fallback to the runtime to add the two strings.
2077 Add<HPushArgument>(left);
2078 Add<HPushArgument>(right);
2079 Push(Add<HCallRuntime>(
2080 isolate()->factory()->empty_string(),
2081 Runtime::FunctionForId(Runtime::kHiddenStringAdd),
2084 if_sameencodingandsequential.End();
2086 if_createcons.End();
2092 HValue* HGraphBuilder::BuildStringAdd(
2095 HAllocationMode allocation_mode) {
2096 NoObservableSideEffectsScope no_effects(this);
2098 // Determine string lengths.
2099 HValue* left_length = AddLoadStringLength(left);
2100 HValue* right_length = AddLoadStringLength(right);
2102 // Check if left string is empty.
2103 IfBuilder if_leftempty(this);
2104 if_leftempty.If<HCompareNumericAndBranch>(
2105 left_length, graph()->GetConstant0(), Token::EQ);
2106 if_leftempty.Then();
2108 // Count the native string addition.
2109 AddIncrementCounter(isolate()->counters()->string_add_native());
2111 // Just return the right string.
2114 if_leftempty.Else();
2116 // Check if right string is empty.
2117 IfBuilder if_rightempty(this);
2118 if_rightempty.If<HCompareNumericAndBranch>(
2119 right_length, graph()->GetConstant0(), Token::EQ);
2120 if_rightempty.Then();
2122 // Count the native string addition.
2123 AddIncrementCounter(isolate()->counters()->string_add_native());
2125 // Just return the left string.
2128 if_rightempty.Else();
2130 // Add the two non-empty strings.
2131 Push(BuildUncheckedStringAdd(left, right, allocation_mode));
2133 if_rightempty.End();
2141 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
2142 HValue* checked_object,
2146 ElementsKind elements_kind,
2147 PropertyAccessType access_type,
2148 LoadKeyedHoleMode load_mode,
2149 KeyedAccessStoreMode store_mode) {
2150 ASSERT((!IsExternalArrayElementsKind(elements_kind) &&
2151 !IsFixedTypedArrayElementsKind(elements_kind)) ||
2153 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency
2154 // on a HElementsTransition instruction. The flag can also be removed if the
2155 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further
2156 // ElementsKind transitions. Finally, the dependency can be removed for stores
2157 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the
2158 // generated store code.
2159 if ((elements_kind == FAST_HOLEY_ELEMENTS) ||
2160 (elements_kind == FAST_ELEMENTS && access_type == STORE)) {
2161 checked_object->ClearDependsOnFlag(kElementsKind);
2164 bool fast_smi_only_elements = IsFastSmiElementsKind(elements_kind);
2165 bool fast_elements = IsFastObjectElementsKind(elements_kind);
2166 HValue* elements = AddLoadElements(checked_object);
2167 if (access_type == STORE && (fast_elements || fast_smi_only_elements) &&
2168 store_mode != STORE_NO_TRANSITION_HANDLE_COW) {
2169 HCheckMaps* check_cow_map = Add<HCheckMaps>(
2170 elements, isolate()->factory()->fixed_array_map(), top_info());
2171 check_cow_map->ClearDependsOnFlag(kElementsKind);
2173 HInstruction* length = NULL;
2175 length = Add<HLoadNamedField>(
2176 checked_object, static_cast<HValue*>(NULL),
2177 HObjectAccess::ForArrayLength(elements_kind));
2179 length = AddLoadFixedArrayLength(elements);
2181 length->set_type(HType::Smi());
2182 HValue* checked_key = NULL;
2183 if (IsExternalArrayElementsKind(elements_kind) ||
2184 IsFixedTypedArrayElementsKind(elements_kind)) {
2185 HValue* backing_store;
2186 if (IsExternalArrayElementsKind(elements_kind)) {
2187 backing_store = Add<HLoadNamedField>(
2188 elements, static_cast<HValue*>(NULL),
2189 HObjectAccess::ForExternalArrayExternalPointer());
2191 backing_store = elements;
2193 if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
2194 NoObservableSideEffectsScope no_effects(this);
2195 IfBuilder length_checker(this);
2196 length_checker.If<HCompareNumericAndBranch>(key, length, Token::LT);
2197 length_checker.Then();
2198 IfBuilder negative_checker(this);
2199 HValue* bounds_check = negative_checker.If<HCompareNumericAndBranch>(
2200 key, graph()->GetConstant0(), Token::GTE);
2201 negative_checker.Then();
2202 HInstruction* result = AddElementAccess(
2203 backing_store, key, val, bounds_check, elements_kind, access_type);
2204 negative_checker.ElseDeopt("Negative key encountered");
2205 negative_checker.End();
2206 length_checker.End();
2209 ASSERT(store_mode == STANDARD_STORE);
2210 checked_key = Add<HBoundsCheck>(key, length);
2211 return AddElementAccess(
2212 backing_store, checked_key, val,
2213 checked_object, elements_kind, access_type);
2216 ASSERT(fast_smi_only_elements ||
2218 IsFastDoubleElementsKind(elements_kind));
2220 // In case val is stored into a fast smi array, assure that the value is a smi
2221 // before manipulating the backing store. Otherwise the actual store may
2222 // deopt, leaving the backing store in an invalid state.
2223 if (access_type == STORE && IsFastSmiElementsKind(elements_kind) &&
2224 !val->type().IsSmi()) {
2225 val = AddUncasted<HForceRepresentation>(val, Representation::Smi());
2228 if (IsGrowStoreMode(store_mode)) {
2229 NoObservableSideEffectsScope no_effects(this);
2230 elements = BuildCheckForCapacityGrow(checked_object, elements,
2231 elements_kind, length, key,
2232 is_js_array, access_type);
2235 checked_key = Add<HBoundsCheck>(key, length);
2237 if (access_type == STORE && (fast_elements || fast_smi_only_elements)) {
2238 if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) {
2239 NoObservableSideEffectsScope no_effects(this);
2240 elements = BuildCopyElementsOnWrite(checked_object, elements,
2241 elements_kind, length);
2243 HCheckMaps* check_cow_map = Add<HCheckMaps>(
2244 elements, isolate()->factory()->fixed_array_map(), top_info());
2245 check_cow_map->ClearDependsOnFlag(kElementsKind);
2249 return AddElementAccess(elements, checked_key, val, checked_object,
2250 elements_kind, access_type, load_mode);
2255 HValue* HGraphBuilder::BuildAllocateArrayFromLength(
2256 JSArrayBuilder* array_builder,
2257 HValue* length_argument) {
2258 if (length_argument->IsConstant() &&
2259 HConstant::cast(length_argument)->HasSmiValue()) {
2260 int array_length = HConstant::cast(length_argument)->Integer32Value();
2261 HValue* new_object = array_length == 0
2262 ? array_builder->AllocateEmptyArray()
2263 : array_builder->AllocateArray(length_argument, length_argument);
2267 HValue* constant_zero = graph()->GetConstant0();
2268 HConstant* max_alloc_length =
2269 Add<HConstant>(JSObject::kInitialMaxFastElementArray);
2270 HInstruction* checked_length = Add<HBoundsCheck>(length_argument,
2272 IfBuilder if_builder(this);
2273 if_builder.If<HCompareNumericAndBranch>(checked_length, constant_zero,
2276 const int initial_capacity = JSArray::kPreallocatedArrayElements;
2277 HConstant* initial_capacity_node = Add<HConstant>(initial_capacity);
2278 Push(initial_capacity_node); // capacity
2279 Push(constant_zero); // length
2281 if (!(top_info()->IsStub()) &&
2282 IsFastPackedElementsKind(array_builder->kind())) {
2283 // We'll come back later with better (holey) feedback.
2284 if_builder.Deopt("Holey array despite packed elements_kind feedback");
2286 Push(checked_length); // capacity
2287 Push(checked_length); // length
2291 // Figure out total size
2292 HValue* length = Pop();
2293 HValue* capacity = Pop();
2294 return array_builder->AllocateArray(capacity, length);
2297 HValue* HGraphBuilder::BuildAllocateElements(ElementsKind kind,
2300 InstanceType instance_type;
2302 if (IsFastDoubleElementsKind(kind)) {
2303 elements_size = kDoubleSize;
2304 instance_type = FIXED_DOUBLE_ARRAY_TYPE;
2306 elements_size = kPointerSize;
2307 instance_type = FIXED_ARRAY_TYPE;
2310 HConstant* elements_size_value = Add<HConstant>(elements_size);
2311 HValue* mul = AddUncasted<HMul>(capacity, elements_size_value);
2312 mul->ClearFlag(HValue::kCanOverflow);
2314 HConstant* header_size = Add<HConstant>(FixedArray::kHeaderSize);
2315 HValue* total_size = AddUncasted<HAdd>(mul, header_size);
2316 total_size->ClearFlag(HValue::kCanOverflow);
2318 PretenureFlag pretenure_flag = !FLAG_allocation_site_pretenuring ?
2319 isolate()->heap()->GetPretenureMode() : NOT_TENURED;
2321 return Add<HAllocate>(total_size, HType::Tagged(), pretenure_flag,
2326 void HGraphBuilder::BuildInitializeElementsHeader(HValue* elements,
2329 Factory* factory = isolate()->factory();
2330 Handle<Map> map = IsFastDoubleElementsKind(kind)
2331 ? factory->fixed_double_array_map()
2332 : factory->fixed_array_map();
2334 AddStoreMapConstant(elements, map);
2335 Add<HStoreNamedField>(elements, HObjectAccess::ForFixedArrayLength(),
2340 HValue* HGraphBuilder::BuildAllocateElementsAndInitializeElementsHeader(
2343 // The HForceRepresentation is to prevent possible deopt on int-smi
2344 // conversion after allocation but before the new object fields are set.
2345 capacity = AddUncasted<HForceRepresentation>(capacity, Representation::Smi());
2346 HValue* new_elements = BuildAllocateElements(kind, capacity);
2347 BuildInitializeElementsHeader(new_elements, kind, capacity);
2348 return new_elements;
2352 HInnerAllocatedObject* HGraphBuilder::BuildJSArrayHeader(HValue* array,
2354 AllocationSiteMode mode,
2355 ElementsKind elements_kind,
2356 HValue* allocation_site_payload,
2357 HValue* length_field) {
2359 Add<HStoreNamedField>(array, HObjectAccess::ForMap(), array_map);
2361 HConstant* empty_fixed_array =
2362 Add<HConstant>(isolate()->factory()->empty_fixed_array());
2364 HObjectAccess access = HObjectAccess::ForPropertiesPointer();
2365 Add<HStoreNamedField>(array, access, empty_fixed_array);
2366 Add<HStoreNamedField>(array, HObjectAccess::ForArrayLength(elements_kind),
2369 if (mode == TRACK_ALLOCATION_SITE) {
2370 BuildCreateAllocationMemento(
2371 array, Add<HConstant>(JSArray::kSize), allocation_site_payload);
2374 int elements_location = JSArray::kSize;
2375 if (mode == TRACK_ALLOCATION_SITE) {
2376 elements_location += AllocationMemento::kSize;
2379 HInnerAllocatedObject* elements = Add<HInnerAllocatedObject>(
2380 array, Add<HConstant>(elements_location));
2381 Add<HStoreNamedField>(array, HObjectAccess::ForElementsPointer(), elements);
2386 HInstruction* HGraphBuilder::AddElementAccess(
2388 HValue* checked_key,
2391 ElementsKind elements_kind,
2392 PropertyAccessType access_type,
2393 LoadKeyedHoleMode load_mode) {
2394 if (access_type == STORE) {
2395 ASSERT(val != NULL);
2396 if (elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS ||
2397 elements_kind == UINT8_CLAMPED_ELEMENTS) {
2398 val = Add<HClampToUint8>(val);
2400 return Add<HStoreKeyed>(elements, checked_key, val, elements_kind,
2401 elements_kind == FAST_SMI_ELEMENTS
2402 ? STORE_TO_INITIALIZED_ENTRY
2403 : INITIALIZING_STORE);
2406 ASSERT(access_type == LOAD);
2407 ASSERT(val == NULL);
2408 HLoadKeyed* load = Add<HLoadKeyed>(
2409 elements, checked_key, dependency, elements_kind, load_mode);
2410 if (FLAG_opt_safe_uint32_operations &&
2411 (elements_kind == EXTERNAL_UINT32_ELEMENTS ||
2412 elements_kind == UINT32_ELEMENTS)) {
2413 graph()->RecordUint32Instruction(load);
2419 HLoadNamedField* HGraphBuilder::AddLoadElements(HValue* object) {
2420 return Add<HLoadNamedField>(
2421 object, static_cast<HValue*>(NULL), HObjectAccess::ForElementsPointer());
2425 HLoadNamedField* HGraphBuilder::AddLoadFixedArrayLength(HValue* object) {
2426 return Add<HLoadNamedField>(
2427 object, static_cast<HValue*>(NULL), HObjectAccess::ForFixedArrayLength());
2431 HValue* HGraphBuilder::BuildNewElementsCapacity(HValue* old_capacity) {
2432 HValue* half_old_capacity = AddUncasted<HShr>(old_capacity,
2433 graph_->GetConstant1());
2435 HValue* new_capacity = AddUncasted<HAdd>(half_old_capacity, old_capacity);
2436 new_capacity->ClearFlag(HValue::kCanOverflow);
2438 HValue* min_growth = Add<HConstant>(16);
2440 new_capacity = AddUncasted<HAdd>(new_capacity, min_growth);
2441 new_capacity->ClearFlag(HValue::kCanOverflow);
2443 return new_capacity;
2447 void HGraphBuilder::BuildNewSpaceArrayCheck(HValue* length, ElementsKind kind) {
2448 int element_size = IsFastDoubleElementsKind(kind) ? kDoubleSize
2450 int max_size = Page::kMaxRegularHeapObjectSize / element_size;
2451 max_size -= JSArray::kSize / element_size;
2452 HConstant* max_size_constant = Add<HConstant>(max_size);
2453 Add<HBoundsCheck>(length, max_size_constant);
2457 HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object,
2460 ElementsKind new_kind,
2462 HValue* new_capacity) {
2463 BuildNewSpaceArrayCheck(new_capacity, new_kind);
2465 HValue* new_elements = BuildAllocateElementsAndInitializeElementsHeader(
2466 new_kind, new_capacity);
2468 BuildCopyElements(elements, kind,
2469 new_elements, new_kind,
2470 length, new_capacity);
2472 Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
2475 return new_elements;
2479 void HGraphBuilder::BuildFillElementsWithHole(HValue* elements,
2480 ElementsKind elements_kind,
2483 // Fast elements kinds need to be initialized in case statements below cause
2484 // a garbage collection.
2485 Factory* factory = isolate()->factory();
2487 double nan_double = FixedDoubleArray::hole_nan_as_double();
2488 HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind)
2489 ? Add<HConstant>(factory->the_hole_value())
2490 : Add<HConstant>(nan_double);
2492 // Special loop unfolding case
2493 static const int kLoopUnfoldLimit = 8;
2494 STATIC_ASSERT(JSArray::kPreallocatedArrayElements <= kLoopUnfoldLimit);
2495 int initial_capacity = -1;
2496 if (from->IsInteger32Constant() && to->IsInteger32Constant()) {
2497 int constant_from = from->GetInteger32Constant();
2498 int constant_to = to->GetInteger32Constant();
2500 if (constant_from == 0 && constant_to <= kLoopUnfoldLimit) {
2501 initial_capacity = constant_to;
2505 // Since we're about to store a hole value, the store instruction below must
2506 // assume an elements kind that supports heap object values.
2507 if (IsFastSmiOrObjectElementsKind(elements_kind)) {
2508 elements_kind = FAST_HOLEY_ELEMENTS;
2511 if (initial_capacity >= 0) {
2512 for (int i = 0; i < initial_capacity; i++) {
2513 HInstruction* key = Add<HConstant>(i);
2514 Add<HStoreKeyed>(elements, key, hole, elements_kind);
2517 LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement);
2519 HValue* key = builder.BeginBody(from, to, Token::LT);
2521 Add<HStoreKeyed>(elements, key, hole, elements_kind);
2528 void HGraphBuilder::BuildCopyElements(HValue* from_elements,
2529 ElementsKind from_elements_kind,
2530 HValue* to_elements,
2531 ElementsKind to_elements_kind,
2534 bool pre_fill_with_holes =
2535 IsFastDoubleElementsKind(from_elements_kind) &&
2536 IsFastObjectElementsKind(to_elements_kind);
2538 if (pre_fill_with_holes) {
2539 // If the copy might trigger a GC, make sure that the FixedArray is
2540 // pre-initialized with holes to make sure that it's always in a consistent
2542 BuildFillElementsWithHole(to_elements, to_elements_kind,
2543 graph()->GetConstant0(), capacity);
2546 LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement);
2548 HValue* key = builder.BeginBody(graph()->GetConstant0(), length, Token::LT);
2550 HValue* element = Add<HLoadKeyed>(from_elements, key,
2551 static_cast<HValue*>(NULL),
2555 ElementsKind kind = (IsHoleyElementsKind(from_elements_kind) &&
2556 IsFastSmiElementsKind(to_elements_kind))
2557 ? FAST_HOLEY_ELEMENTS : to_elements_kind;
2559 if (IsHoleyElementsKind(from_elements_kind) &&
2560 from_elements_kind != to_elements_kind) {
2561 IfBuilder if_hole(this);
2562 if_hole.If<HCompareHoleAndBranch>(element);
2564 HConstant* hole_constant = IsFastDoubleElementsKind(to_elements_kind)
2565 ? Add<HConstant>(FixedDoubleArray::hole_nan_as_double())
2566 : graph()->GetConstantHole();
2567 Add<HStoreKeyed>(to_elements, key, hole_constant, kind);
2569 HStoreKeyed* store = Add<HStoreKeyed>(to_elements, key, element, kind);
2570 store->SetFlag(HValue::kAllowUndefinedAsNaN);
2573 HStoreKeyed* store = Add<HStoreKeyed>(to_elements, key, element, kind);
2574 store->SetFlag(HValue::kAllowUndefinedAsNaN);
2579 if (!pre_fill_with_holes && length != capacity) {
2580 // Fill unused capacity with the hole.
2581 BuildFillElementsWithHole(to_elements, to_elements_kind,
2587 HValue* HGraphBuilder::BuildCloneShallowArray(HValue* boilerplate,
2588 HValue* allocation_site,
2589 AllocationSiteMode mode,
2592 NoObservableSideEffectsScope no_effects(this);
2594 // All sizes here are multiples of kPointerSize.
2595 int size = JSArray::kSize;
2596 if (mode == TRACK_ALLOCATION_SITE) {
2597 size += AllocationMemento::kSize;
2600 HValue* size_in_bytes = Add<HConstant>(size);
2601 HInstruction* object = Add<HAllocate>(size_in_bytes,
2606 // Copy the JS array part.
2607 for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
2608 if ((i != JSArray::kElementsOffset) || (length == 0)) {
2609 HObjectAccess access = HObjectAccess::ForJSArrayOffset(i);
2610 Add<HStoreNamedField>(
2611 object, access, Add<HLoadNamedField>(
2612 boilerplate, static_cast<HValue*>(NULL), access));
2616 // Create an allocation site info if requested.
2617 if (mode == TRACK_ALLOCATION_SITE) {
2618 BuildCreateAllocationMemento(
2619 object, Add<HConstant>(JSArray::kSize), allocation_site);
2623 HValue* boilerplate_elements = AddLoadElements(boilerplate);
2624 HValue* object_elements;
2625 if (IsFastDoubleElementsKind(kind)) {
2626 HValue* elems_size = Add<HConstant>(FixedDoubleArray::SizeFor(length));
2627 object_elements = Add<HAllocate>(elems_size, HType::Tagged(),
2628 NOT_TENURED, FIXED_DOUBLE_ARRAY_TYPE);
2630 HValue* elems_size = Add<HConstant>(FixedArray::SizeFor(length));
2631 object_elements = Add<HAllocate>(elems_size, HType::Tagged(),
2632 NOT_TENURED, FIXED_ARRAY_TYPE);
2634 Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
2637 // Copy the elements array header.
2638 for (int i = 0; i < FixedArrayBase::kHeaderSize; i += kPointerSize) {
2639 HObjectAccess access = HObjectAccess::ForFixedArrayHeader(i);
2640 Add<HStoreNamedField>(
2641 object_elements, access, Add<HLoadNamedField>(
2642 boilerplate_elements, static_cast<HValue*>(NULL), access));
2645 // Copy the elements array contents.
2646 // TODO(mstarzinger): Teach HGraphBuilder::BuildCopyElements to unfold
2647 // copying loops with constant length up to a given boundary and use this
2648 // helper here instead.
2649 for (int i = 0; i < length; i++) {
2650 HValue* key_constant = Add<HConstant>(i);
2651 HInstruction* value = Add<HLoadKeyed>(boilerplate_elements, key_constant,
2652 static_cast<HValue*>(NULL), kind);
2653 Add<HStoreKeyed>(object_elements, key_constant, value, kind);
2661 void HGraphBuilder::BuildCompareNil(
2664 HIfContinuation* continuation) {
2665 IfBuilder if_nil(this);
2666 bool some_case_handled = false;
2667 bool some_case_missing = false;
2669 if (type->Maybe(Type::Null())) {
2670 if (some_case_handled) if_nil.Or();
2671 if_nil.If<HCompareObjectEqAndBranch>(value, graph()->GetConstantNull());
2672 some_case_handled = true;
2674 some_case_missing = true;
2677 if (type->Maybe(Type::Undefined())) {
2678 if (some_case_handled) if_nil.Or();
2679 if_nil.If<HCompareObjectEqAndBranch>(value,
2680 graph()->GetConstantUndefined());
2681 some_case_handled = true;
2683 some_case_missing = true;
2686 if (type->Maybe(Type::Undetectable())) {
2687 if (some_case_handled) if_nil.Or();
2688 if_nil.If<HIsUndetectableAndBranch>(value);
2689 some_case_handled = true;
2691 some_case_missing = true;
2694 if (some_case_missing) {
2697 if (type->NumClasses() == 1) {
2698 BuildCheckHeapObject(value);
2699 // For ICs, the map checked below is a sentinel map that gets replaced by
2700 // the monomorphic map when the code is used as a template to generate a
2701 // new IC. For optimized functions, there is no sentinel map, the map
2702 // emitted below is the actual monomorphic map.
2703 BuildCheckMap(value, type->Classes().Current());
2705 if_nil.Deopt("Too many undetectable types");
2709 if_nil.CaptureContinuation(continuation);
2713 void HGraphBuilder::BuildCreateAllocationMemento(
2714 HValue* previous_object,
2715 HValue* previous_object_size,
2716 HValue* allocation_site) {
2717 ASSERT(allocation_site != NULL);
2718 HInnerAllocatedObject* allocation_memento = Add<HInnerAllocatedObject>(
2719 previous_object, previous_object_size);
2720 AddStoreMapConstant(
2721 allocation_memento, isolate()->factory()->allocation_memento_map());
2722 Add<HStoreNamedField>(
2724 HObjectAccess::ForAllocationMementoSite(),
2726 if (FLAG_allocation_site_pretenuring) {
2727 HValue* memento_create_count = Add<HLoadNamedField>(
2728 allocation_site, static_cast<HValue*>(NULL),
2729 HObjectAccess::ForAllocationSiteOffset(
2730 AllocationSite::kPretenureCreateCountOffset));
2731 memento_create_count = AddUncasted<HAdd>(
2732 memento_create_count, graph()->GetConstant1());
2733 // This smi value is reset to zero after every gc, overflow isn't a problem
2734 // since the counter is bounded by the new space size.
2735 memento_create_count->ClearFlag(HValue::kCanOverflow);
2736 HStoreNamedField* store = Add<HStoreNamedField>(
2737 allocation_site, HObjectAccess::ForAllocationSiteOffset(
2738 AllocationSite::kPretenureCreateCountOffset), memento_create_count);
2739 // No write barrier needed to store a smi.
2740 store->SkipWriteBarrier();
2745 HInstruction* HGraphBuilder::BuildGetNativeContext(HValue* closure) {
2746 // Get the global context, then the native context
2747 HInstruction* context =
2748 Add<HLoadNamedField>(closure, static_cast<HValue*>(NULL),
2749 HObjectAccess::ForFunctionContextPointer());
2750 HInstruction* global_object = Add<HLoadNamedField>(
2751 context, static_cast<HValue*>(NULL),
2752 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
2753 HObjectAccess access = HObjectAccess::ForObservableJSObjectOffset(
2754 GlobalObject::kNativeContextOffset);
2755 return Add<HLoadNamedField>(
2756 global_object, static_cast<HValue*>(NULL), access);
2760 HInstruction* HGraphBuilder::BuildGetNativeContext() {
2761 // Get the global context, then the native context
2762 HValue* global_object = Add<HLoadNamedField>(
2763 context(), static_cast<HValue*>(NULL),
2764 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
2765 return Add<HLoadNamedField>(
2766 global_object, static_cast<HValue*>(NULL),
2767 HObjectAccess::ForObservableJSObjectOffset(
2768 GlobalObject::kNativeContextOffset));
2772 HInstruction* HGraphBuilder::BuildGetArrayFunction() {
2773 HInstruction* native_context = BuildGetNativeContext();
2774 HInstruction* index =
2775 Add<HConstant>(static_cast<int32_t>(Context::ARRAY_FUNCTION_INDEX));
2776 return Add<HLoadKeyed>(
2777 native_context, index, static_cast<HValue*>(NULL), FAST_ELEMENTS);
2781 HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder,
2783 HValue* allocation_site_payload,
2784 HValue* constructor_function,
2785 AllocationSiteOverrideMode override_mode) :
2788 allocation_site_payload_(allocation_site_payload),
2789 constructor_function_(constructor_function) {
2790 ASSERT(!allocation_site_payload->IsConstant() ||
2791 HConstant::cast(allocation_site_payload)->handle(
2792 builder_->isolate())->IsAllocationSite());
2793 mode_ = override_mode == DISABLE_ALLOCATION_SITES
2794 ? DONT_TRACK_ALLOCATION_SITE
2795 : AllocationSite::GetMode(kind);
2799 HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder,
2801 HValue* constructor_function) :
2804 mode_(DONT_TRACK_ALLOCATION_SITE),
2805 allocation_site_payload_(NULL),
2806 constructor_function_(constructor_function) {
2810 HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode() {
2811 if (!builder()->top_info()->IsStub()) {
2812 // A constant map is fine.
2813 Handle<Map> map(builder()->isolate()->get_initial_js_array_map(kind_),
2814 builder()->isolate());
2815 return builder()->Add<HConstant>(map);
2818 if (constructor_function_ != NULL && kind_ == GetInitialFastElementsKind()) {
2819 // No need for a context lookup if the kind_ matches the initial
2820 // map, because we can just load the map in that case.
2821 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap();
2822 return builder()->Add<HLoadNamedField>(
2823 constructor_function_, static_cast<HValue*>(NULL), access);
2826 // TODO(mvstanton): we should always have a constructor function if we
2827 // are creating a stub.
2828 HInstruction* native_context = constructor_function_ != NULL
2829 ? builder()->BuildGetNativeContext(constructor_function_)
2830 : builder()->BuildGetNativeContext();
2832 HInstruction* index = builder()->Add<HConstant>(
2833 static_cast<int32_t>(Context::JS_ARRAY_MAPS_INDEX));
2835 HInstruction* map_array = builder()->Add<HLoadKeyed>(
2836 native_context, index, static_cast<HValue*>(NULL), FAST_ELEMENTS);
2838 HInstruction* kind_index = builder()->Add<HConstant>(kind_);
2840 return builder()->Add<HLoadKeyed>(
2841 map_array, kind_index, static_cast<HValue*>(NULL), FAST_ELEMENTS);
2845 HValue* HGraphBuilder::JSArrayBuilder::EmitInternalMapCode() {
2846 // Find the map near the constructor function
2847 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap();
2848 return builder()->Add<HLoadNamedField>(
2849 constructor_function_, static_cast<HValue*>(NULL), access);
2853 HValue* HGraphBuilder::JSArrayBuilder::EstablishAllocationSize(
2854 HValue* length_node) {
2855 ASSERT(length_node != NULL);
2857 int base_size = JSArray::kSize;
2858 if (mode_ == TRACK_ALLOCATION_SITE) {
2859 base_size += AllocationMemento::kSize;
2862 STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize);
2863 base_size += FixedArray::kHeaderSize;
2865 HInstruction* elements_size_value =
2866 builder()->Add<HConstant>(elements_size());
2867 HInstruction* mul = HMul::NewImul(builder()->zone(), builder()->context(),
2868 length_node, elements_size_value);
2869 builder()->AddInstruction(mul);
2870 HInstruction* base = builder()->Add<HConstant>(base_size);
2871 HInstruction* total_size = HAdd::New(builder()->zone(), builder()->context(),
2873 total_size->ClearFlag(HValue::kCanOverflow);
2874 builder()->AddInstruction(total_size);
2879 HValue* HGraphBuilder::JSArrayBuilder::EstablishEmptyArrayAllocationSize() {
2880 int base_size = JSArray::kSize;
2881 if (mode_ == TRACK_ALLOCATION_SITE) {
2882 base_size += AllocationMemento::kSize;
2885 base_size += IsFastDoubleElementsKind(kind_)
2886 ? FixedDoubleArray::SizeFor(initial_capacity())
2887 : FixedArray::SizeFor(initial_capacity());
2889 return builder()->Add<HConstant>(base_size);
2893 HValue* HGraphBuilder::JSArrayBuilder::AllocateEmptyArray() {
2894 HValue* size_in_bytes = EstablishEmptyArrayAllocationSize();
2895 HConstant* capacity = builder()->Add<HConstant>(initial_capacity());
2896 return AllocateArray(size_in_bytes,
2898 builder()->graph()->GetConstant0());
2902 HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* capacity,
2903 HValue* length_field,
2904 FillMode fill_mode) {
2905 HValue* size_in_bytes = EstablishAllocationSize(capacity);
2906 return AllocateArray(size_in_bytes, capacity, length_field, fill_mode);
2910 HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes,
2912 HValue* length_field,
2913 FillMode fill_mode) {
2914 // These HForceRepresentations are because we store these as fields in the
2915 // objects we construct, and an int32-to-smi HChange could deopt. Accept
2916 // the deopt possibility now, before allocation occurs.
2918 builder()->AddUncasted<HForceRepresentation>(capacity,
2919 Representation::Smi());
2921 builder()->AddUncasted<HForceRepresentation>(length_field,
2922 Representation::Smi());
2923 // Allocate (dealing with failure appropriately)
2924 HAllocate* new_object = builder()->Add<HAllocate>(size_in_bytes,
2925 HType::JSArray(), NOT_TENURED, JS_ARRAY_TYPE);
2927 // Folded array allocation should be aligned if it has fast double elements.
2928 if (IsFastDoubleElementsKind(kind_)) {
2929 new_object->MakeDoubleAligned();
2932 // Fill in the fields: map, properties, length
2934 if (allocation_site_payload_ == NULL) {
2935 map = EmitInternalMapCode();
2937 map = EmitMapCode();
2939 elements_location_ = builder()->BuildJSArrayHeader(new_object,
2943 allocation_site_payload_,
2946 // Initialize the elements
2947 builder()->BuildInitializeElementsHeader(elements_location_, kind_, capacity);
2949 if (fill_mode == FILL_WITH_HOLE) {
2950 builder()->BuildFillElementsWithHole(elements_location_, kind_,
2951 graph()->GetConstant0(), capacity);
2958 HStoreNamedField* HGraphBuilder::AddStoreMapConstant(HValue *object,
2960 return Add<HStoreNamedField>(object, HObjectAccess::ForMap(),
2961 Add<HConstant>(map));
2965 HValue* HGraphBuilder::AddLoadJSBuiltin(Builtins::JavaScript builtin) {
2966 HValue* global_object = Add<HLoadNamedField>(
2967 context(), static_cast<HValue*>(NULL),
2968 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
2969 HObjectAccess access = HObjectAccess::ForObservableJSObjectOffset(
2970 GlobalObject::kBuiltinsOffset);
2971 HValue* builtins = Add<HLoadNamedField>(
2972 global_object, static_cast<HValue*>(NULL), access);
2973 HObjectAccess function_access = HObjectAccess::ForObservableJSObjectOffset(
2974 JSBuiltinsObject::OffsetOfFunctionWithId(builtin));
2975 return Add<HLoadNamedField>(
2976 builtins, static_cast<HValue*>(NULL), function_access);
2980 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info)
2981 : HGraphBuilder(info),
2982 function_state_(NULL),
2983 initial_function_state_(this, info, NORMAL_RETURN, 0),
2987 globals_(10, info->zone()),
2988 inline_bailout_(false),
2989 osr_(new(info->zone()) HOsrBuilder(this)) {
2990 // This is not initialized in the initializer list because the
2991 // constructor for the initial state relies on function_state_ == NULL
2992 // to know it's the initial state.
2993 function_state_= &initial_function_state_;
2994 InitializeAstVisitor(info->zone());
2995 if (FLAG_hydrogen_track_positions) {
2996 SetSourcePosition(info->shared_info()->start_position());
3001 HBasicBlock* HOptimizedGraphBuilder::CreateJoin(HBasicBlock* first,
3002 HBasicBlock* second,
3003 BailoutId join_id) {
3004 if (first == NULL) {
3006 } else if (second == NULL) {
3009 HBasicBlock* join_block = graph()->CreateBasicBlock();
3010 Goto(first, join_block);
3011 Goto(second, join_block);
3012 join_block->SetJoinId(join_id);
3018 HBasicBlock* HOptimizedGraphBuilder::JoinContinue(IterationStatement* statement,
3019 HBasicBlock* exit_block,
3020 HBasicBlock* continue_block) {
3021 if (continue_block != NULL) {
3022 if (exit_block != NULL) Goto(exit_block, continue_block);
3023 continue_block->SetJoinId(statement->ContinueId());
3024 return continue_block;
3030 HBasicBlock* HOptimizedGraphBuilder::CreateLoop(IterationStatement* statement,
3031 HBasicBlock* loop_entry,
3032 HBasicBlock* body_exit,
3033 HBasicBlock* loop_successor,
3034 HBasicBlock* break_block) {
3035 if (body_exit != NULL) Goto(body_exit, loop_entry);
3036 loop_entry->PostProcessLoopHeader(statement);
3037 if (break_block != NULL) {
3038 if (loop_successor != NULL) Goto(loop_successor, break_block);
3039 break_block->SetJoinId(statement->ExitId());
3042 return loop_successor;
3046 // Build a new loop header block and set it as the current block.
3047 HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry() {
3048 HBasicBlock* loop_entry = CreateLoopHeaderBlock();
3050 set_current_block(loop_entry);
3055 HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry(
3056 IterationStatement* statement) {
3057 HBasicBlock* loop_entry = osr()->HasOsrEntryAt(statement)
3058 ? osr()->BuildOsrLoopEntry(statement)
3064 void HBasicBlock::FinishExit(HControlInstruction* instruction,
3065 HSourcePosition position) {
3066 Finish(instruction, position);
3071 HGraph::HGraph(CompilationInfo* info)
3072 : isolate_(info->isolate()),
3075 blocks_(8, info->zone()),
3076 values_(16, info->zone()),
3078 uint32_instructions_(NULL),
3081 zone_(info->zone()),
3082 is_recursive_(false),
3083 use_optimistic_licm_(false),
3084 depends_on_empty_array_proto_elements_(false),
3085 type_change_checksum_(0),
3086 maximum_environment_size_(0),
3087 no_side_effects_scope_count_(0),
3088 disallow_adding_new_values_(false),
3090 inlined_functions_(5, info->zone()) {
3091 if (info->IsStub()) {
3092 HydrogenCodeStub* stub = info->code_stub();
3093 CodeStubInterfaceDescriptor* descriptor =
3094 stub->GetInterfaceDescriptor(isolate_);
3095 start_environment_ =
3096 new(zone_) HEnvironment(zone_, descriptor->environment_length());
3098 TraceInlinedFunction(info->shared_info(), HSourcePosition::Unknown());
3099 start_environment_ =
3100 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_);
3102 start_environment_->set_ast_id(BailoutId::FunctionEntry());
3103 entry_block_ = CreateBasicBlock();
3104 entry_block_->SetInitialEnvironment(start_environment_);
3108 HBasicBlock* HGraph::CreateBasicBlock() {
3109 HBasicBlock* result = new(zone()) HBasicBlock(this);
3110 blocks_.Add(result, zone());
3115 void HGraph::FinalizeUniqueness() {
3116 DisallowHeapAllocation no_gc;
3117 ASSERT(!OptimizingCompilerThread::IsOptimizerThread(isolate()));
3118 for (int i = 0; i < blocks()->length(); ++i) {
3119 for (HInstructionIterator it(blocks()->at(i)); !it.Done(); it.Advance()) {
3120 it.Current()->FinalizeUniqueness();
3126 int HGraph::TraceInlinedFunction(
3127 Handle<SharedFunctionInfo> shared,
3128 HSourcePosition position) {
3129 if (!FLAG_hydrogen_track_positions) {
3134 for (; id < inlined_functions_.length(); id++) {
3135 if (inlined_functions_[id].shared().is_identical_to(shared)) {
3140 if (id == inlined_functions_.length()) {
3141 inlined_functions_.Add(InlinedFunctionInfo(shared), zone());
3143 if (!shared->script()->IsUndefined()) {
3144 Handle<Script> script(Script::cast(shared->script()));
3145 if (!script->source()->IsUndefined()) {
3146 CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer());
3147 PrintF(tracing_scope.file(),
3148 "--- FUNCTION SOURCE (%s) id{%d,%d} ---\n",
3149 shared->DebugName()->ToCString().get(),
3150 info()->optimization_id(),
3154 ConsStringIteratorOp op;
3155 StringCharacterStream stream(String::cast(script->source()),
3157 shared->start_position());
3158 // fun->end_position() points to the last character in the stream. We
3159 // need to compensate by adding one to calculate the length.
3161 shared->end_position() - shared->start_position() + 1;
3162 for (int i = 0; i < source_len; i++) {
3163 if (stream.HasMore()) {
3164 PrintF(tracing_scope.file(), "%c", stream.GetNext());
3169 PrintF(tracing_scope.file(), "\n--- END ---\n");
3174 int inline_id = next_inline_id_++;
3176 if (inline_id != 0) {
3177 CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer());
3178 PrintF(tracing_scope.file(), "INLINE (%s) id{%d,%d} AS %d AT ",
3179 shared->DebugName()->ToCString().get(),
3180 info()->optimization_id(),
3183 position.PrintTo(tracing_scope.file());
3184 PrintF(tracing_scope.file(), "\n");
3191 int HGraph::SourcePositionToScriptPosition(HSourcePosition pos) {
3192 if (!FLAG_hydrogen_track_positions || pos.IsUnknown()) {
3196 return inlined_functions_[pos.inlining_id()].start_position() +
3201 // Block ordering was implemented with two mutually recursive methods,
3202 // HGraph::Postorder and HGraph::PostorderLoopBlocks.
3203 // The recursion could lead to stack overflow so the algorithm has been
3204 // implemented iteratively.
3205 // At a high level the algorithm looks like this:
3207 // Postorder(block, loop_header) : {
3208 // if (block has already been visited or is of another loop) return;
3209 // mark block as visited;
3210 // if (block is a loop header) {
3211 // VisitLoopMembers(block, loop_header);
3212 // VisitSuccessorsOfLoopHeader(block);
3214 // VisitSuccessors(block)
3216 // put block in result list;
3219 // VisitLoopMembers(block, outer_loop_header) {
3220 // foreach (block b in block loop members) {
3221 // VisitSuccessorsOfLoopMember(b, outer_loop_header);
3222 // if (b is loop header) VisitLoopMembers(b);
3226 // VisitSuccessorsOfLoopMember(block, outer_loop_header) {
3227 // foreach (block b in block successors) Postorder(b, outer_loop_header)
3230 // VisitSuccessorsOfLoopHeader(block) {
3231 // foreach (block b in block successors) Postorder(b, block)
3234 // VisitSuccessors(block, loop_header) {
3235 // foreach (block b in block successors) Postorder(b, loop_header)
3238 // The ordering is started calling Postorder(entry, NULL).
3240 // Each instance of PostorderProcessor represents the "stack frame" of the
3241 // recursion, and particularly keeps the state of the loop (iteration) of the
3242 // "Visit..." function it represents.
3243 // To recycle memory we keep all the frames in a double linked list but
3244 // this means that we cannot use constructors to initialize the frames.
3246 class PostorderProcessor : public ZoneObject {
3248 // Back link (towards the stack bottom).
3249 PostorderProcessor* parent() {return father_; }
3250 // Forward link (towards the stack top).
3251 PostorderProcessor* child() {return child_; }
3252 HBasicBlock* block() { return block_; }
3253 HLoopInformation* loop() { return loop_; }
3254 HBasicBlock* loop_header() { return loop_header_; }
3256 static PostorderProcessor* CreateEntryProcessor(Zone* zone,
3258 BitVector* visited) {
3259 PostorderProcessor* result = new(zone) PostorderProcessor(NULL);
3260 return result->SetupSuccessors(zone, block, NULL, visited);
3263 PostorderProcessor* PerformStep(Zone* zone,
3265 ZoneList<HBasicBlock*>* order) {
3266 PostorderProcessor* next =
3267 PerformNonBacktrackingStep(zone, visited, order);
3271 return Backtrack(zone, visited, order);
3276 explicit PostorderProcessor(PostorderProcessor* father)
3277 : father_(father), child_(NULL), successor_iterator(NULL) { }
3279 // Each enum value states the cycle whose state is kept by this instance.
3283 SUCCESSORS_OF_LOOP_HEADER,
3285 SUCCESSORS_OF_LOOP_MEMBER
3288 // Each "Setup..." method is like a constructor for a cycle state.
3289 PostorderProcessor* SetupSuccessors(Zone* zone,
3291 HBasicBlock* loop_header,
3292 BitVector* visited) {
3293 if (block == NULL || visited->Contains(block->block_id()) ||
3294 block->parent_loop_header() != loop_header) {
3298 loop_header_ = NULL;
3303 visited->Add(block->block_id());
3305 if (block->IsLoopHeader()) {
3306 kind_ = SUCCESSORS_OF_LOOP_HEADER;
3307 loop_header_ = block;
3308 InitializeSuccessors();
3309 PostorderProcessor* result = Push(zone);
3310 return result->SetupLoopMembers(zone, block, block->loop_information(),
3313 ASSERT(block->IsFinished());
3315 loop_header_ = loop_header;
3316 InitializeSuccessors();
3322 PostorderProcessor* SetupLoopMembers(Zone* zone,
3324 HLoopInformation* loop,
3325 HBasicBlock* loop_header) {
3326 kind_ = LOOP_MEMBERS;
3329 loop_header_ = loop_header;
3330 InitializeLoopMembers();
3334 PostorderProcessor* SetupSuccessorsOfLoopMember(
3336 HLoopInformation* loop,
3337 HBasicBlock* loop_header) {
3338 kind_ = SUCCESSORS_OF_LOOP_MEMBER;
3341 loop_header_ = loop_header;
3342 InitializeSuccessors();
3346 // This method "allocates" a new stack frame.
3347 PostorderProcessor* Push(Zone* zone) {
3348 if (child_ == NULL) {
3349 child_ = new(zone) PostorderProcessor(this);
3354 void ClosePostorder(ZoneList<HBasicBlock*>* order, Zone* zone) {
3355 ASSERT(block_->end()->FirstSuccessor() == NULL ||
3356 order->Contains(block_->end()->FirstSuccessor()) ||
3357 block_->end()->FirstSuccessor()->IsLoopHeader());
3358 ASSERT(block_->end()->SecondSuccessor() == NULL ||
3359 order->Contains(block_->end()->SecondSuccessor()) ||
3360 block_->end()->SecondSuccessor()->IsLoopHeader());
3361 order->Add(block_, zone);
3364 // This method is the basic block to walk up the stack.
3365 PostorderProcessor* Pop(Zone* zone,
3367 ZoneList<HBasicBlock*>* order) {
3370 case SUCCESSORS_OF_LOOP_HEADER:
3371 ClosePostorder(order, zone);
3375 case SUCCESSORS_OF_LOOP_MEMBER:
3376 if (block()->IsLoopHeader() && block() != loop_->loop_header()) {
3377 // In this case we need to perform a LOOP_MEMBERS cycle so we
3378 // initialize it and return this instead of father.
3379 return SetupLoopMembers(zone, block(),
3380 block()->loop_information(), loop_header_);
3391 // Walks up the stack.
3392 PostorderProcessor* Backtrack(Zone* zone,
3394 ZoneList<HBasicBlock*>* order) {
3395 PostorderProcessor* parent = Pop(zone, visited, order);
3396 while (parent != NULL) {
3397 PostorderProcessor* next =
3398 parent->PerformNonBacktrackingStep(zone, visited, order);
3402 parent = parent->Pop(zone, visited, order);
3408 PostorderProcessor* PerformNonBacktrackingStep(
3411 ZoneList<HBasicBlock*>* order) {
3412 HBasicBlock* next_block;
3415 next_block = AdvanceSuccessors();
3416 if (next_block != NULL) {
3417 PostorderProcessor* result = Push(zone);
3418 return result->SetupSuccessors(zone, next_block,
3419 loop_header_, visited);
3422 case SUCCESSORS_OF_LOOP_HEADER:
3423 next_block = AdvanceSuccessors();
3424 if (next_block != NULL) {
3425 PostorderProcessor* result = Push(zone);
3426 return result->SetupSuccessors(zone, next_block,
3431 next_block = AdvanceLoopMembers();
3432 if (next_block != NULL) {
3433 PostorderProcessor* result = Push(zone);
3434 return result->SetupSuccessorsOfLoopMember(next_block,
3435 loop_, loop_header_);
3438 case SUCCESSORS_OF_LOOP_MEMBER:
3439 next_block = AdvanceSuccessors();
3440 if (next_block != NULL) {
3441 PostorderProcessor* result = Push(zone);
3442 return result->SetupSuccessors(zone, next_block,
3443 loop_header_, visited);
3452 // The following two methods implement a "foreach b in successors" cycle.
3453 void InitializeSuccessors() {
3456 successor_iterator = HSuccessorIterator(block_->end());
3459 HBasicBlock* AdvanceSuccessors() {
3460 if (!successor_iterator.Done()) {
3461 HBasicBlock* result = successor_iterator.Current();
3462 successor_iterator.Advance();
3468 // The following two methods implement a "foreach b in loop members" cycle.
3469 void InitializeLoopMembers() {
3471 loop_length = loop_->blocks()->length();
3474 HBasicBlock* AdvanceLoopMembers() {
3475 if (loop_index < loop_length) {
3476 HBasicBlock* result = loop_->blocks()->at(loop_index);
3485 PostorderProcessor* father_;
3486 PostorderProcessor* child_;
3487 HLoopInformation* loop_;
3488 HBasicBlock* block_;
3489 HBasicBlock* loop_header_;
3492 HSuccessorIterator successor_iterator;
3496 void HGraph::OrderBlocks() {
3497 CompilationPhase phase("H_Block ordering", info());
3498 BitVector visited(blocks_.length(), zone());
3500 ZoneList<HBasicBlock*> reverse_result(8, zone());
3501 HBasicBlock* start = blocks_[0];
3502 PostorderProcessor* postorder =
3503 PostorderProcessor::CreateEntryProcessor(zone(), start, &visited);
3504 while (postorder != NULL) {
3505 postorder = postorder->PerformStep(zone(), &visited, &reverse_result);
3509 for (int i = reverse_result.length() - 1; i >= 0; --i) {
3510 HBasicBlock* b = reverse_result[i];
3511 blocks_.Add(b, zone());
3512 b->set_block_id(index++);
3517 void HGraph::AssignDominators() {
3518 HPhase phase("H_Assign dominators", this);
3519 for (int i = 0; i < blocks_.length(); ++i) {
3520 HBasicBlock* block = blocks_[i];
3521 if (block->IsLoopHeader()) {
3522 // Only the first predecessor of a loop header is from outside the loop.
3523 // All others are back edges, and thus cannot dominate the loop header.
3524 block->AssignCommonDominator(block->predecessors()->first());
3525 block->AssignLoopSuccessorDominators();
3527 for (int j = blocks_[i]->predecessors()->length() - 1; j >= 0; --j) {
3528 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j));
3535 bool HGraph::CheckArgumentsPhiUses() {
3536 int block_count = blocks_.length();
3537 for (int i = 0; i < block_count; ++i) {
3538 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
3539 HPhi* phi = blocks_[i]->phis()->at(j);
3540 // We don't support phi uses of arguments for now.
3541 if (phi->CheckFlag(HValue::kIsArguments)) return false;
3548 bool HGraph::CheckConstPhiUses() {
3549 int block_count = blocks_.length();
3550 for (int i = 0; i < block_count; ++i) {
3551 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
3552 HPhi* phi = blocks_[i]->phis()->at(j);
3553 // Check for the hole value (from an uninitialized const).
3554 for (int k = 0; k < phi->OperandCount(); k++) {
3555 if (phi->OperandAt(k) == GetConstantHole()) return false;
3563 void HGraph::CollectPhis() {
3564 int block_count = blocks_.length();
3565 phi_list_ = new(zone()) ZoneList<HPhi*>(block_count, zone());
3566 for (int i = 0; i < block_count; ++i) {
3567 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
3568 HPhi* phi = blocks_[i]->phis()->at(j);
3569 phi_list_->Add(phi, zone());
3575 // Implementation of utility class to encapsulate the translation state for
3576 // a (possibly inlined) function.
3577 FunctionState::FunctionState(HOptimizedGraphBuilder* owner,
3578 CompilationInfo* info,
3579 InliningKind inlining_kind,
3582 compilation_info_(info),
3583 call_context_(NULL),
3584 inlining_kind_(inlining_kind),
3585 function_return_(NULL),
3586 test_context_(NULL),
3588 arguments_object_(NULL),
3589 arguments_elements_(NULL),
3590 inlining_id_(inlining_id),
3591 outer_source_position_(HSourcePosition::Unknown()),
3592 outer_(owner->function_state()) {
3593 if (outer_ != NULL) {
3594 // State for an inline function.
3595 if (owner->ast_context()->IsTest()) {
3596 HBasicBlock* if_true = owner->graph()->CreateBasicBlock();
3597 HBasicBlock* if_false = owner->graph()->CreateBasicBlock();
3598 if_true->MarkAsInlineReturnTarget(owner->current_block());
3599 if_false->MarkAsInlineReturnTarget(owner->current_block());
3600 TestContext* outer_test_context = TestContext::cast(owner->ast_context());
3601 Expression* cond = outer_test_context->condition();
3602 // The AstContext constructor pushed on the context stack. This newed
3603 // instance is the reason that AstContext can't be BASE_EMBEDDED.
3604 test_context_ = new TestContext(owner, cond, if_true, if_false);
3606 function_return_ = owner->graph()->CreateBasicBlock();
3607 function_return()->MarkAsInlineReturnTarget(owner->current_block());
3609 // Set this after possibly allocating a new TestContext above.
3610 call_context_ = owner->ast_context();
3613 // Push on the state stack.
3614 owner->set_function_state(this);
3616 if (FLAG_hydrogen_track_positions) {
3617 outer_source_position_ = owner->source_position();
3618 owner->EnterInlinedSource(
3619 info->shared_info()->start_position(),
3621 owner->SetSourcePosition(info->shared_info()->start_position());
3626 FunctionState::~FunctionState() {
3627 delete test_context_;
3628 owner_->set_function_state(outer_);
3630 if (FLAG_hydrogen_track_positions) {
3631 owner_->set_source_position(outer_source_position_);
3632 owner_->EnterInlinedSource(
3633 outer_->compilation_info()->shared_info()->start_position(),
3634 outer_->inlining_id());
3639 // Implementation of utility classes to represent an expression's context in
3641 AstContext::AstContext(HOptimizedGraphBuilder* owner, Expression::Context kind)
3644 outer_(owner->ast_context()),
3645 for_typeof_(false) {
3646 owner->set_ast_context(this); // Push.
3648 ASSERT(owner->environment()->frame_type() == JS_FUNCTION);
3649 original_length_ = owner->environment()->length();
3654 AstContext::~AstContext() {
3655 owner_->set_ast_context(outer_); // Pop.
3659 EffectContext::~EffectContext() {
3660 ASSERT(owner()->HasStackOverflow() ||
3661 owner()->current_block() == NULL ||
3662 (owner()->environment()->length() == original_length_ &&
3663 owner()->environment()->frame_type() == JS_FUNCTION));
3667 ValueContext::~ValueContext() {
3668 ASSERT(owner()->HasStackOverflow() ||
3669 owner()->current_block() == NULL ||
3670 (owner()->environment()->length() == original_length_ + 1 &&
3671 owner()->environment()->frame_type() == JS_FUNCTION));
3675 void EffectContext::ReturnValue(HValue* value) {
3676 // The value is simply ignored.
3680 void ValueContext::ReturnValue(HValue* value) {
3681 // The value is tracked in the bailout environment, and communicated
3682 // through the environment as the result of the expression.
3683 if (!arguments_allowed() && value->CheckFlag(HValue::kIsArguments)) {
3684 owner()->Bailout(kBadValueContextForArgumentsValue);
3686 owner()->Push(value);
3690 void TestContext::ReturnValue(HValue* value) {
3695 void EffectContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
3696 ASSERT(!instr->IsControlInstruction());
3697 owner()->AddInstruction(instr);
3698 if (instr->HasObservableSideEffects()) {
3699 owner()->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
3704 void EffectContext::ReturnControl(HControlInstruction* instr,
3706 ASSERT(!instr->HasObservableSideEffects());
3707 HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock();
3708 HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock();
3709 instr->SetSuccessorAt(0, empty_true);
3710 instr->SetSuccessorAt(1, empty_false);
3711 owner()->FinishCurrentBlock(instr);
3712 HBasicBlock* join = owner()->CreateJoin(empty_true, empty_false, ast_id);
3713 owner()->set_current_block(join);
3717 void EffectContext::ReturnContinuation(HIfContinuation* continuation,
3719 HBasicBlock* true_branch = NULL;
3720 HBasicBlock* false_branch = NULL;
3721 continuation->Continue(&true_branch, &false_branch);
3722 if (!continuation->IsTrueReachable()) {
3723 owner()->set_current_block(false_branch);
3724 } else if (!continuation->IsFalseReachable()) {
3725 owner()->set_current_block(true_branch);
3727 HBasicBlock* join = owner()->CreateJoin(true_branch, false_branch, ast_id);
3728 owner()->set_current_block(join);
3733 void ValueContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
3734 ASSERT(!instr->IsControlInstruction());
3735 if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) {
3736 return owner()->Bailout(kBadValueContextForArgumentsObjectValue);
3738 owner()->AddInstruction(instr);
3739 owner()->Push(instr);
3740 if (instr->HasObservableSideEffects()) {
3741 owner()->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
3746 void ValueContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) {
3747 ASSERT(!instr->HasObservableSideEffects());
3748 if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) {
3749 return owner()->Bailout(kBadValueContextForArgumentsObjectValue);
3751 HBasicBlock* materialize_false = owner()->graph()->CreateBasicBlock();
3752 HBasicBlock* materialize_true = owner()->graph()->CreateBasicBlock();
3753 instr->SetSuccessorAt(0, materialize_true);
3754 instr->SetSuccessorAt(1, materialize_false);
3755 owner()->FinishCurrentBlock(instr);
3756 owner()->set_current_block(materialize_true);
3757 owner()->Push(owner()->graph()->GetConstantTrue());
3758 owner()->set_current_block(materialize_false);
3759 owner()->Push(owner()->graph()->GetConstantFalse());
3761 owner()->CreateJoin(materialize_true, materialize_false, ast_id);
3762 owner()->set_current_block(join);
3766 void ValueContext::ReturnContinuation(HIfContinuation* continuation,
3768 HBasicBlock* materialize_true = NULL;
3769 HBasicBlock* materialize_false = NULL;
3770 continuation->Continue(&materialize_true, &materialize_false);
3771 if (continuation->IsTrueReachable()) {
3772 owner()->set_current_block(materialize_true);
3773 owner()->Push(owner()->graph()->GetConstantTrue());
3774 owner()->set_current_block(materialize_true);
3776 if (continuation->IsFalseReachable()) {
3777 owner()->set_current_block(materialize_false);
3778 owner()->Push(owner()->graph()->GetConstantFalse());
3779 owner()->set_current_block(materialize_false);
3781 if (continuation->TrueAndFalseReachable()) {
3783 owner()->CreateJoin(materialize_true, materialize_false, ast_id);
3784 owner()->set_current_block(join);
3789 void TestContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
3790 ASSERT(!instr->IsControlInstruction());
3791 HOptimizedGraphBuilder* builder = owner();
3792 builder->AddInstruction(instr);
3793 // We expect a simulate after every expression with side effects, though
3794 // this one isn't actually needed (and wouldn't work if it were targeted).
3795 if (instr->HasObservableSideEffects()) {
3796 builder->Push(instr);
3797 builder->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
3804 void TestContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) {
3805 ASSERT(!instr->HasObservableSideEffects());
3806 HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock();
3807 HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock();
3808 instr->SetSuccessorAt(0, empty_true);
3809 instr->SetSuccessorAt(1, empty_false);
3810 owner()->FinishCurrentBlock(instr);
3811 owner()->Goto(empty_true, if_true(), owner()->function_state());
3812 owner()->Goto(empty_false, if_false(), owner()->function_state());
3813 owner()->set_current_block(NULL);
3817 void TestContext::ReturnContinuation(HIfContinuation* continuation,
3819 HBasicBlock* true_branch = NULL;
3820 HBasicBlock* false_branch = NULL;
3821 continuation->Continue(&true_branch, &false_branch);
3822 if (continuation->IsTrueReachable()) {
3823 owner()->Goto(true_branch, if_true(), owner()->function_state());
3825 if (continuation->IsFalseReachable()) {
3826 owner()->Goto(false_branch, if_false(), owner()->function_state());
3828 owner()->set_current_block(NULL);
3832 void TestContext::BuildBranch(HValue* value) {
3833 // We expect the graph to be in edge-split form: there is no edge that
3834 // connects a branch node to a join node. We conservatively ensure that
3835 // property by always adding an empty block on the outgoing edges of this
3837 HOptimizedGraphBuilder* builder = owner();
3838 if (value != NULL && value->CheckFlag(HValue::kIsArguments)) {
3839 builder->Bailout(kArgumentsObjectValueInATestContext);
3841 ToBooleanStub::Types expected(condition()->to_boolean_types());
3842 ReturnControl(owner()->New<HBranch>(value, expected), BailoutId::None());
3846 // HOptimizedGraphBuilder infrastructure for bailing out and checking bailouts.
3847 #define CHECK_BAILOUT(call) \
3850 if (HasStackOverflow()) return; \
3854 #define CHECK_ALIVE(call) \
3857 if (HasStackOverflow() || current_block() == NULL) return; \
3861 #define CHECK_ALIVE_OR_RETURN(call, value) \
3864 if (HasStackOverflow() || current_block() == NULL) return value; \
3868 void HOptimizedGraphBuilder::Bailout(BailoutReason reason) {
3869 current_info()->set_bailout_reason(reason);
3874 void HOptimizedGraphBuilder::VisitForEffect(Expression* expr) {
3875 EffectContext for_effect(this);
3880 void HOptimizedGraphBuilder::VisitForValue(Expression* expr,
3881 ArgumentsAllowedFlag flag) {
3882 ValueContext for_value(this, flag);
3887 void HOptimizedGraphBuilder::VisitForTypeOf(Expression* expr) {
3888 ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED);
3889 for_value.set_for_typeof(true);
3894 void HOptimizedGraphBuilder::VisitForControl(Expression* expr,
3895 HBasicBlock* true_block,
3896 HBasicBlock* false_block) {
3897 TestContext for_test(this, expr, true_block, false_block);
3902 void HOptimizedGraphBuilder::VisitExpressions(
3903 ZoneList<Expression*>* exprs) {
3904 for (int i = 0; i < exprs->length(); ++i) {
3905 CHECK_ALIVE(VisitForValue(exprs->at(i)));
3910 bool HOptimizedGraphBuilder::BuildGraph() {
3911 if (current_info()->function()->is_generator()) {
3912 Bailout(kFunctionIsAGenerator);
3915 Scope* scope = current_info()->scope();
3916 if (scope->HasIllegalRedeclaration()) {
3917 Bailout(kFunctionWithIllegalRedeclaration);
3920 if (scope->calls_eval()) {
3921 Bailout(kFunctionCallsEval);
3926 // Add an edge to the body entry. This is warty: the graph's start
3927 // environment will be used by the Lithium translation as the initial
3928 // environment on graph entry, but it has now been mutated by the
3929 // Hydrogen translation of the instructions in the start block. This
3930 // environment uses values which have not been defined yet. These
3931 // Hydrogen instructions will then be replayed by the Lithium
3932 // translation, so they cannot have an environment effect. The edge to
3933 // the body's entry block (along with some special logic for the start
3934 // block in HInstruction::InsertAfter) seals the start block from
3935 // getting unwanted instructions inserted.
3937 // TODO(kmillikin): Fix this. Stop mutating the initial environment.
3938 // Make the Hydrogen instructions in the initial block into Hydrogen
3939 // values (but not instructions), present in the initial environment and
3940 // not replayed by the Lithium translation.
3941 HEnvironment* initial_env = environment()->CopyWithoutHistory();
3942 HBasicBlock* body_entry = CreateBasicBlock(initial_env);
3944 body_entry->SetJoinId(BailoutId::FunctionEntry());
3945 set_current_block(body_entry);
3947 // Handle implicit declaration of the function name in named function
3948 // expressions before other declarations.
3949 if (scope->is_function_scope() && scope->function() != NULL) {
3950 VisitVariableDeclaration(scope->function());
3952 VisitDeclarations(scope->declarations());
3953 Add<HSimulate>(BailoutId::Declarations());
3955 Add<HStackCheck>(HStackCheck::kFunctionEntry);
3957 VisitStatements(current_info()->function()->body());
3958 if (HasStackOverflow()) return false;
3960 if (current_block() != NULL) {
3961 Add<HReturn>(graph()->GetConstantUndefined());
3962 set_current_block(NULL);
3965 // If the checksum of the number of type info changes is the same as the
3966 // last time this function was compiled, then this recompile is likely not
3967 // due to missing/inadequate type feedback, but rather too aggressive
3968 // optimization. Disable optimistic LICM in that case.
3969 Handle<Code> unoptimized_code(current_info()->shared_info()->code());
3970 ASSERT(unoptimized_code->kind() == Code::FUNCTION);
3971 Handle<TypeFeedbackInfo> type_info(
3972 TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info()));
3973 int checksum = type_info->own_type_change_checksum();
3974 int composite_checksum = graph()->update_type_change_checksum(checksum);
3975 graph()->set_use_optimistic_licm(
3976 !type_info->matches_inlined_type_change_checksum(composite_checksum));
3977 type_info->set_inlined_type_change_checksum(composite_checksum);
3979 // Perform any necessary OSR-specific cleanups or changes to the graph.
3980 osr()->FinishGraph();
3986 bool HGraph::Optimize(BailoutReason* bailout_reason) {
3990 // We need to create a HConstant "zero" now so that GVN will fold every
3991 // zero-valued constant in the graph together.
3992 // The constant is needed to make idef-based bounds check work: the pass
3993 // evaluates relations with "zero" and that zero cannot be created after GVN.
3997 // Do a full verify after building the graph and computing dominators.
4001 if (FLAG_analyze_environment_liveness && maximum_environment_size() != 0) {
4002 Run<HEnvironmentLivenessAnalysisPhase>();
4005 if (!CheckConstPhiUses()) {
4006 *bailout_reason = kUnsupportedPhiUseOfConstVariable;
4009 Run<HRedundantPhiEliminationPhase>();
4010 if (!CheckArgumentsPhiUses()) {
4011 *bailout_reason = kUnsupportedPhiUseOfArguments;
4015 // Find and mark unreachable code to simplify optimizations, especially gvn,
4016 // where unreachable code could unnecessarily defeat LICM.
4017 Run<HMarkUnreachableBlocksPhase>();
4019 if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>();
4020 if (FLAG_use_escape_analysis) Run<HEscapeAnalysisPhase>();
4022 if (FLAG_load_elimination) Run<HLoadEliminationPhase>();
4026 if (has_osr()) osr()->FinishOsrValues();
4028 Run<HInferRepresentationPhase>();
4030 // Remove HSimulate instructions that have turned out not to be needed
4031 // after all by folding them into the following HSimulate.
4032 // This must happen after inferring representations.
4033 Run<HMergeRemovableSimulatesPhase>();
4035 Run<HMarkDeoptimizeOnUndefinedPhase>();
4036 Run<HRepresentationChangesPhase>();
4038 Run<HInferTypesPhase>();
4040 // Must be performed before canonicalization to ensure that Canonicalize
4041 // will not remove semantically meaningful ToInt32 operations e.g. BIT_OR with
4043 if (FLAG_opt_safe_uint32_operations) Run<HUint32AnalysisPhase>();
4045 if (FLAG_use_canonicalizing) Run<HCanonicalizePhase>();
4047 if (FLAG_use_gvn) Run<HGlobalValueNumberingPhase>();
4049 if (FLAG_check_elimination) Run<HCheckEliminationPhase>();
4051 if (FLAG_store_elimination) Run<HStoreEliminationPhase>();
4053 Run<HRangeAnalysisPhase>();
4055 Run<HComputeChangeUndefinedToNaN>();
4057 // Eliminate redundant stack checks on backwards branches.
4058 Run<HStackCheckEliminationPhase>();
4060 if (FLAG_array_bounds_checks_elimination) Run<HBoundsCheckEliminationPhase>();
4061 if (FLAG_array_bounds_checks_hoisting) Run<HBoundsCheckHoistingPhase>();
4062 if (FLAG_array_index_dehoisting) Run<HDehoistIndexComputationsPhase>();
4063 if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>();
4065 RestoreActualValues();
4067 // Find unreachable code a second time, GVN and other optimizations may have
4068 // made blocks unreachable that were previously reachable.
4069 Run<HMarkUnreachableBlocksPhase>();
4075 void HGraph::RestoreActualValues() {
4076 HPhase phase("H_Restore actual values", this);
4078 for (int block_index = 0; block_index < blocks()->length(); block_index++) {
4079 HBasicBlock* block = blocks()->at(block_index);
4082 for (int i = 0; i < block->phis()->length(); i++) {
4083 HPhi* phi = block->phis()->at(i);
4084 ASSERT(phi->ActualValue() == phi);
4088 for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
4089 HInstruction* instruction = it.Current();
4090 if (instruction->ActualValue() == instruction) continue;
4091 if (instruction->CheckFlag(HValue::kIsDead)) {
4092 // The instruction was marked as deleted but left in the graph
4093 // as a control flow dependency point for subsequent
4095 instruction->DeleteAndReplaceWith(instruction->ActualValue());
4097 ASSERT(instruction->IsInformativeDefinition());
4098 if (instruction->IsPurelyInformativeDefinition()) {
4099 instruction->DeleteAndReplaceWith(instruction->RedefinedOperand());
4101 instruction->ReplaceAllUsesWith(instruction->ActualValue());
4109 void HOptimizedGraphBuilder::PushArgumentsFromEnvironment(int count) {
4110 ZoneList<HValue*> arguments(count, zone());
4111 for (int i = 0; i < count; ++i) {
4112 arguments.Add(Pop(), zone());
4115 while (!arguments.is_empty()) {
4116 Add<HPushArgument>(arguments.RemoveLast());
4121 template <class Instruction>
4122 HInstruction* HOptimizedGraphBuilder::PreProcessCall(Instruction* call) {
4123 PushArgumentsFromEnvironment(call->argument_count());
4128 void HOptimizedGraphBuilder::SetUpScope(Scope* scope) {
4129 // First special is HContext.
4130 HInstruction* context = Add<HContext>();
4131 environment()->BindContext(context);
4133 // Create an arguments object containing the initial parameters. Set the
4134 // initial values of parameters including "this" having parameter index 0.
4135 ASSERT_EQ(scope->num_parameters() + 1, environment()->parameter_count());
4136 HArgumentsObject* arguments_object =
4137 New<HArgumentsObject>(environment()->parameter_count());
4138 for (int i = 0; i < environment()->parameter_count(); ++i) {
4139 HInstruction* parameter = Add<HParameter>(i);
4140 arguments_object->AddArgument(parameter, zone());
4141 environment()->Bind(i, parameter);
4143 AddInstruction(arguments_object);
4144 graph()->SetArgumentsObject(arguments_object);
4146 HConstant* undefined_constant = graph()->GetConstantUndefined();
4147 // Initialize specials and locals to undefined.
4148 for (int i = environment()->parameter_count() + 1;
4149 i < environment()->length();
4151 environment()->Bind(i, undefined_constant);
4154 // Handle the arguments and arguments shadow variables specially (they do
4155 // not have declarations).
4156 if (scope->arguments() != NULL) {
4157 if (!scope->arguments()->IsStackAllocated()) {
4158 return Bailout(kContextAllocatedArguments);
4161 environment()->Bind(scope->arguments(),
4162 graph()->GetArgumentsObject());
4167 void HOptimizedGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) {
4168 for (int i = 0; i < statements->length(); i++) {
4169 Statement* stmt = statements->at(i);
4170 CHECK_ALIVE(Visit(stmt));
4171 if (stmt->IsJump()) break;
4176 void HOptimizedGraphBuilder::VisitBlock(Block* stmt) {
4177 ASSERT(!HasStackOverflow());
4178 ASSERT(current_block() != NULL);
4179 ASSERT(current_block()->HasPredecessor());
4180 if (stmt->scope() != NULL) {
4181 return Bailout(kScopedBlock);
4183 BreakAndContinueInfo break_info(stmt);
4184 { BreakAndContinueScope push(&break_info, this);
4185 CHECK_BAILOUT(VisitStatements(stmt->statements()));
4187 HBasicBlock* break_block = break_info.break_block();
4188 if (break_block != NULL) {
4189 if (current_block() != NULL) Goto(break_block);
4190 break_block->SetJoinId(stmt->ExitId());
4191 set_current_block(break_block);
4196 void HOptimizedGraphBuilder::VisitExpressionStatement(
4197 ExpressionStatement* stmt) {
4198 ASSERT(!HasStackOverflow());
4199 ASSERT(current_block() != NULL);
4200 ASSERT(current_block()->HasPredecessor());
4201 VisitForEffect(stmt->expression());
4205 void HOptimizedGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
4206 ASSERT(!HasStackOverflow());
4207 ASSERT(current_block() != NULL);
4208 ASSERT(current_block()->HasPredecessor());
4212 void HOptimizedGraphBuilder::VisitIfStatement(IfStatement* stmt) {
4213 ASSERT(!HasStackOverflow());
4214 ASSERT(current_block() != NULL);
4215 ASSERT(current_block()->HasPredecessor());
4216 if (stmt->condition()->ToBooleanIsTrue()) {
4217 Add<HSimulate>(stmt->ThenId());
4218 Visit(stmt->then_statement());
4219 } else if (stmt->condition()->ToBooleanIsFalse()) {
4220 Add<HSimulate>(stmt->ElseId());
4221 Visit(stmt->else_statement());
4223 HBasicBlock* cond_true = graph()->CreateBasicBlock();
4224 HBasicBlock* cond_false = graph()->CreateBasicBlock();
4225 CHECK_BAILOUT(VisitForControl(stmt->condition(), cond_true, cond_false));
4227 if (cond_true->HasPredecessor()) {
4228 cond_true->SetJoinId(stmt->ThenId());
4229 set_current_block(cond_true);
4230 CHECK_BAILOUT(Visit(stmt->then_statement()));
4231 cond_true = current_block();
4236 if (cond_false->HasPredecessor()) {
4237 cond_false->SetJoinId(stmt->ElseId());
4238 set_current_block(cond_false);
4239 CHECK_BAILOUT(Visit(stmt->else_statement()));
4240 cond_false = current_block();
4245 HBasicBlock* join = CreateJoin(cond_true, cond_false, stmt->IfId());
4246 set_current_block(join);
4251 HBasicBlock* HOptimizedGraphBuilder::BreakAndContinueScope::Get(
4252 BreakableStatement* stmt,
4256 BreakAndContinueScope* current = this;
4257 while (current != NULL && current->info()->target() != stmt) {
4258 *drop_extra += current->info()->drop_extra();
4259 current = current->next();
4261 ASSERT(current != NULL); // Always found (unless stack is malformed).
4263 if (type == BREAK) {
4264 *drop_extra += current->info()->drop_extra();
4267 HBasicBlock* block = NULL;
4270 block = current->info()->break_block();
4271 if (block == NULL) {
4272 block = current->owner()->graph()->CreateBasicBlock();
4273 current->info()->set_break_block(block);
4278 block = current->info()->continue_block();
4279 if (block == NULL) {
4280 block = current->owner()->graph()->CreateBasicBlock();
4281 current->info()->set_continue_block(block);
4290 void HOptimizedGraphBuilder::VisitContinueStatement(
4291 ContinueStatement* stmt) {
4292 ASSERT(!HasStackOverflow());
4293 ASSERT(current_block() != NULL);
4294 ASSERT(current_block()->HasPredecessor());
4296 HBasicBlock* continue_block = break_scope()->Get(
4297 stmt->target(), BreakAndContinueScope::CONTINUE, &drop_extra);
4299 Goto(continue_block);
4300 set_current_block(NULL);
4304 void HOptimizedGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
4305 ASSERT(!HasStackOverflow());
4306 ASSERT(current_block() != NULL);
4307 ASSERT(current_block()->HasPredecessor());
4309 HBasicBlock* break_block = break_scope()->Get(
4310 stmt->target(), BreakAndContinueScope::BREAK, &drop_extra);
4313 set_current_block(NULL);
4317 void HOptimizedGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
4318 ASSERT(!HasStackOverflow());
4319 ASSERT(current_block() != NULL);
4320 ASSERT(current_block()->HasPredecessor());
4321 FunctionState* state = function_state();
4322 AstContext* context = call_context();
4323 if (context == NULL) {
4324 // Not an inlined return, so an actual one.
4325 CHECK_ALIVE(VisitForValue(stmt->expression()));
4326 HValue* result = environment()->Pop();
4327 Add<HReturn>(result);
4328 } else if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) {
4329 // Return from an inlined construct call. In a test context the return value
4330 // will always evaluate to true, in a value context the return value needs
4331 // to be a JSObject.
4332 if (context->IsTest()) {
4333 TestContext* test = TestContext::cast(context);
4334 CHECK_ALIVE(VisitForEffect(stmt->expression()));
4335 Goto(test->if_true(), state);
4336 } else if (context->IsEffect()) {
4337 CHECK_ALIVE(VisitForEffect(stmt->expression()));
4338 Goto(function_return(), state);
4340 ASSERT(context->IsValue());
4341 CHECK_ALIVE(VisitForValue(stmt->expression()));
4342 HValue* return_value = Pop();
4343 HValue* receiver = environment()->arguments_environment()->Lookup(0);
4344 HHasInstanceTypeAndBranch* typecheck =
4345 New<HHasInstanceTypeAndBranch>(return_value,
4346 FIRST_SPEC_OBJECT_TYPE,
4347 LAST_SPEC_OBJECT_TYPE);
4348 HBasicBlock* if_spec_object = graph()->CreateBasicBlock();
4349 HBasicBlock* not_spec_object = graph()->CreateBasicBlock();
4350 typecheck->SetSuccessorAt(0, if_spec_object);
4351 typecheck->SetSuccessorAt(1, not_spec_object);
4352 FinishCurrentBlock(typecheck);
4353 AddLeaveInlined(if_spec_object, return_value, state);
4354 AddLeaveInlined(not_spec_object, receiver, state);
4356 } else if (state->inlining_kind() == SETTER_CALL_RETURN) {
4357 // Return from an inlined setter call. The returned value is never used, the
4358 // value of an assignment is always the value of the RHS of the assignment.
4359 CHECK_ALIVE(VisitForEffect(stmt->expression()));
4360 if (context->IsTest()) {
4361 HValue* rhs = environment()->arguments_environment()->Lookup(1);
4362 context->ReturnValue(rhs);
4363 } else if (context->IsEffect()) {
4364 Goto(function_return(), state);
4366 ASSERT(context->IsValue());
4367 HValue* rhs = environment()->arguments_environment()->Lookup(1);
4368 AddLeaveInlined(rhs, state);
4371 // Return from a normal inlined function. Visit the subexpression in the
4372 // expression context of the call.
4373 if (context->IsTest()) {
4374 TestContext* test = TestContext::cast(context);
4375 VisitForControl(stmt->expression(), test->if_true(), test->if_false());
4376 } else if (context->IsEffect()) {
4377 // Visit in value context and ignore the result. This is needed to keep
4378 // environment in sync with full-codegen since some visitors (e.g.
4379 // VisitCountOperation) use the operand stack differently depending on
4381 CHECK_ALIVE(VisitForValue(stmt->expression()));
4383 Goto(function_return(), state);
4385 ASSERT(context->IsValue());
4386 CHECK_ALIVE(VisitForValue(stmt->expression()));
4387 AddLeaveInlined(Pop(), state);
4390 set_current_block(NULL);
4394 void HOptimizedGraphBuilder::VisitWithStatement(WithStatement* stmt) {
4395 ASSERT(!HasStackOverflow());
4396 ASSERT(current_block() != NULL);
4397 ASSERT(current_block()->HasPredecessor());
4398 return Bailout(kWithStatement);
4402 void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
4403 ASSERT(!HasStackOverflow());
4404 ASSERT(current_block() != NULL);
4405 ASSERT(current_block()->HasPredecessor());
4407 // We only optimize switch statements with a bounded number of clauses.
4408 const int kCaseClauseLimit = 128;
4409 ZoneList<CaseClause*>* clauses = stmt->cases();
4410 int clause_count = clauses->length();
4411 ZoneList<HBasicBlock*> body_blocks(clause_count, zone());
4412 if (clause_count > kCaseClauseLimit) {
4413 return Bailout(kSwitchStatementTooManyClauses);
4416 CHECK_ALIVE(VisitForValue(stmt->tag()));
4417 Add<HSimulate>(stmt->EntryId());
4418 HValue* tag_value = Top();
4419 Type* tag_type = stmt->tag()->bounds().lower;
4421 // 1. Build all the tests, with dangling true branches
4422 BailoutId default_id = BailoutId::None();
4423 for (int i = 0; i < clause_count; ++i) {
4424 CaseClause* clause = clauses->at(i);
4425 if (clause->is_default()) {
4426 body_blocks.Add(NULL, zone());
4427 if (default_id.IsNone()) default_id = clause->EntryId();
4431 // Generate a compare and branch.
4432 CHECK_ALIVE(VisitForValue(clause->label()));
4433 HValue* label_value = Pop();
4435 Type* label_type = clause->label()->bounds().lower;
4436 Type* combined_type = clause->compare_type();
4437 HControlInstruction* compare = BuildCompareInstruction(
4438 Token::EQ_STRICT, tag_value, label_value, tag_type, label_type,
4440 ScriptPositionToSourcePosition(stmt->tag()->position()),
4441 ScriptPositionToSourcePosition(clause->label()->position()),
4442 PUSH_BEFORE_SIMULATE, clause->id());
4444 HBasicBlock* next_test_block = graph()->CreateBasicBlock();
4445 HBasicBlock* body_block = graph()->CreateBasicBlock();
4446 body_blocks.Add(body_block, zone());
4447 compare->SetSuccessorAt(0, body_block);
4448 compare->SetSuccessorAt(1, next_test_block);
4449 FinishCurrentBlock(compare);
4451 set_current_block(body_block);
4452 Drop(1); // tag_value
4454 set_current_block(next_test_block);
4457 // Save the current block to use for the default or to join with the
4459 HBasicBlock* last_block = current_block();
4460 Drop(1); // tag_value
4462 // 2. Loop over the clauses and the linked list of tests in lockstep,
4463 // translating the clause bodies.
4464 HBasicBlock* fall_through_block = NULL;
4466 BreakAndContinueInfo break_info(stmt);
4467 { BreakAndContinueScope push(&break_info, this);
4468 for (int i = 0; i < clause_count; ++i) {
4469 CaseClause* clause = clauses->at(i);
4471 // Identify the block where normal (non-fall-through) control flow
4473 HBasicBlock* normal_block = NULL;
4474 if (clause->is_default()) {
4475 if (last_block == NULL) continue;
4476 normal_block = last_block;
4477 last_block = NULL; // Cleared to indicate we've handled it.
4479 normal_block = body_blocks[i];
4482 if (fall_through_block == NULL) {
4483 set_current_block(normal_block);
4485 HBasicBlock* join = CreateJoin(fall_through_block,
4488 set_current_block(join);
4491 CHECK_BAILOUT(VisitStatements(clause->statements()));
4492 fall_through_block = current_block();
4496 // Create an up-to-3-way join. Use the break block if it exists since
4497 // it's already a join block.
4498 HBasicBlock* break_block = break_info.break_block();
4499 if (break_block == NULL) {
4500 set_current_block(CreateJoin(fall_through_block,
4504 if (fall_through_block != NULL) Goto(fall_through_block, break_block);
4505 if (last_block != NULL) Goto(last_block, break_block);
4506 break_block->SetJoinId(stmt->ExitId());
4507 set_current_block(break_block);
4512 void HOptimizedGraphBuilder::VisitLoopBody(IterationStatement* stmt,
4513 HBasicBlock* loop_entry,
4514 BreakAndContinueInfo* break_info) {
4515 BreakAndContinueScope push(break_info, this);
4516 Add<HSimulate>(stmt->StackCheckId());
4517 HStackCheck* stack_check =
4518 HStackCheck::cast(Add<HStackCheck>(HStackCheck::kBackwardsBranch));
4519 ASSERT(loop_entry->IsLoopHeader());
4520 loop_entry->loop_information()->set_stack_check(stack_check);
4521 CHECK_BAILOUT(Visit(stmt->body()));
4525 void HOptimizedGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
4526 ASSERT(!HasStackOverflow());
4527 ASSERT(current_block() != NULL);
4528 ASSERT(current_block()->HasPredecessor());
4529 ASSERT(current_block() != NULL);
4530 HBasicBlock* loop_entry = BuildLoopEntry(stmt);
4532 BreakAndContinueInfo break_info(stmt);
4533 CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
4534 HBasicBlock* body_exit =
4535 JoinContinue(stmt, current_block(), break_info.continue_block());
4536 HBasicBlock* loop_successor = NULL;
4537 if (body_exit != NULL && !stmt->cond()->ToBooleanIsTrue()) {
4538 set_current_block(body_exit);
4539 loop_successor = graph()->CreateBasicBlock();
4540 if (stmt->cond()->ToBooleanIsFalse()) {
4541 Goto(loop_successor);
4544 // The block for a true condition, the actual predecessor block of the
4546 body_exit = graph()->CreateBasicBlock();
4547 CHECK_BAILOUT(VisitForControl(stmt->cond(), body_exit, loop_successor));
4549 if (body_exit != NULL && body_exit->HasPredecessor()) {
4550 body_exit->SetJoinId(stmt->BackEdgeId());
4554 if (loop_successor->HasPredecessor()) {
4555 loop_successor->SetJoinId(stmt->ExitId());
4557 loop_successor = NULL;
4560 HBasicBlock* loop_exit = CreateLoop(stmt,
4564 break_info.break_block());
4565 set_current_block(loop_exit);
4569 void HOptimizedGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
4570 ASSERT(!HasStackOverflow());
4571 ASSERT(current_block() != NULL);
4572 ASSERT(current_block()->HasPredecessor());
4573 ASSERT(current_block() != NULL);
4574 HBasicBlock* loop_entry = BuildLoopEntry(stmt);
4576 // If the condition is constant true, do not generate a branch.
4577 HBasicBlock* loop_successor = NULL;
4578 if (!stmt->cond()->ToBooleanIsTrue()) {
4579 HBasicBlock* body_entry = graph()->CreateBasicBlock();
4580 loop_successor = graph()->CreateBasicBlock();
4581 CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor));
4582 if (body_entry->HasPredecessor()) {
4583 body_entry->SetJoinId(stmt->BodyId());
4584 set_current_block(body_entry);
4586 if (loop_successor->HasPredecessor()) {
4587 loop_successor->SetJoinId(stmt->ExitId());
4589 loop_successor = NULL;
4593 BreakAndContinueInfo break_info(stmt);
4594 if (current_block() != NULL) {
4595 CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
4597 HBasicBlock* body_exit =
4598 JoinContinue(stmt, current_block(), break_info.continue_block());
4599 HBasicBlock* loop_exit = CreateLoop(stmt,
4603 break_info.break_block());
4604 set_current_block(loop_exit);
4608 void HOptimizedGraphBuilder::VisitForStatement(ForStatement* stmt) {
4609 ASSERT(!HasStackOverflow());
4610 ASSERT(current_block() != NULL);
4611 ASSERT(current_block()->HasPredecessor());
4612 if (stmt->init() != NULL) {
4613 CHECK_ALIVE(Visit(stmt->init()));
4615 ASSERT(current_block() != NULL);
4616 HBasicBlock* loop_entry = BuildLoopEntry(stmt);
4618 HBasicBlock* loop_successor = NULL;
4619 if (stmt->cond() != NULL) {
4620 HBasicBlock* body_entry = graph()->CreateBasicBlock();
4621 loop_successor = graph()->CreateBasicBlock();
4622 CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor));
4623 if (body_entry->HasPredecessor()) {
4624 body_entry->SetJoinId(stmt->BodyId());
4625 set_current_block(body_entry);
4627 if (loop_successor->HasPredecessor()) {
4628 loop_successor->SetJoinId(stmt->ExitId());
4630 loop_successor = NULL;
4634 BreakAndContinueInfo break_info(stmt);
4635 if (current_block() != NULL) {
4636 CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
4638 HBasicBlock* body_exit =
4639 JoinContinue(stmt, current_block(), break_info.continue_block());
4641 if (stmt->next() != NULL && body_exit != NULL) {
4642 set_current_block(body_exit);
4643 CHECK_BAILOUT(Visit(stmt->next()));
4644 body_exit = current_block();
4647 HBasicBlock* loop_exit = CreateLoop(stmt,
4651 break_info.break_block());
4652 set_current_block(loop_exit);
4656 void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
4657 ASSERT(!HasStackOverflow());
4658 ASSERT(current_block() != NULL);
4659 ASSERT(current_block()->HasPredecessor());
4661 if (!FLAG_optimize_for_in) {
4662 return Bailout(kForInStatementOptimizationIsDisabled);
4665 if (stmt->for_in_type() != ForInStatement::FAST_FOR_IN) {
4666 return Bailout(kForInStatementIsNotFastCase);
4669 if (!stmt->each()->IsVariableProxy() ||
4670 !stmt->each()->AsVariableProxy()->var()->IsStackLocal()) {
4671 return Bailout(kForInStatementWithNonLocalEachVariable);
4674 Variable* each_var = stmt->each()->AsVariableProxy()->var();
4676 CHECK_ALIVE(VisitForValue(stmt->enumerable()));
4677 HValue* enumerable = Top(); // Leave enumerable at the top.
4679 HInstruction* map = Add<HForInPrepareMap>(enumerable);
4680 Add<HSimulate>(stmt->PrepareId());
4682 HInstruction* array = Add<HForInCacheArray>(
4683 enumerable, map, DescriptorArray::kEnumCacheBridgeCacheIndex);
4685 HInstruction* enum_length = Add<HMapEnumLength>(map);
4687 HInstruction* start_index = Add<HConstant>(0);
4694 HInstruction* index_cache = Add<HForInCacheArray>(
4695 enumerable, map, DescriptorArray::kEnumCacheBridgeIndicesCacheIndex);
4696 HForInCacheArray::cast(array)->set_index_cache(
4697 HForInCacheArray::cast(index_cache));
4699 HBasicBlock* loop_entry = BuildLoopEntry(stmt);
4701 HValue* index = environment()->ExpressionStackAt(0);
4702 HValue* limit = environment()->ExpressionStackAt(1);
4704 // Check that we still have more keys.
4705 HCompareNumericAndBranch* compare_index =
4706 New<HCompareNumericAndBranch>(index, limit, Token::LT);
4707 compare_index->set_observed_input_representation(
4708 Representation::Smi(), Representation::Smi());
4710 HBasicBlock* loop_body = graph()->CreateBasicBlock();
4711 HBasicBlock* loop_successor = graph()->CreateBasicBlock();
4713 compare_index->SetSuccessorAt(0, loop_body);
4714 compare_index->SetSuccessorAt(1, loop_successor);
4715 FinishCurrentBlock(compare_index);
4717 set_current_block(loop_successor);
4720 set_current_block(loop_body);
4722 HValue* key = Add<HLoadKeyed>(
4723 environment()->ExpressionStackAt(2), // Enum cache.
4724 environment()->ExpressionStackAt(0), // Iteration index.
4725 environment()->ExpressionStackAt(0),
4728 // Check if the expected map still matches that of the enumerable.
4729 // If not just deoptimize.
4730 Add<HCheckMapValue>(environment()->ExpressionStackAt(4),
4731 environment()->ExpressionStackAt(3));
4733 Bind(each_var, key);
4735 BreakAndContinueInfo break_info(stmt, 5);
4736 CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
4738 HBasicBlock* body_exit =
4739 JoinContinue(stmt, current_block(), break_info.continue_block());
4741 if (body_exit != NULL) {
4742 set_current_block(body_exit);
4744 HValue* current_index = Pop();
4745 Push(AddUncasted<HAdd>(current_index, graph()->GetConstant1()));
4746 body_exit = current_block();
4749 HBasicBlock* loop_exit = CreateLoop(stmt,
4753 break_info.break_block());
4755 set_current_block(loop_exit);
4759 void HOptimizedGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) {
4760 ASSERT(!HasStackOverflow());
4761 ASSERT(current_block() != NULL);
4762 ASSERT(current_block()->HasPredecessor());
4763 return Bailout(kForOfStatement);
4767 void HOptimizedGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
4768 ASSERT(!HasStackOverflow());
4769 ASSERT(current_block() != NULL);
4770 ASSERT(current_block()->HasPredecessor());
4771 return Bailout(kTryCatchStatement);
4775 void HOptimizedGraphBuilder::VisitTryFinallyStatement(
4776 TryFinallyStatement* stmt) {
4777 ASSERT(!HasStackOverflow());
4778 ASSERT(current_block() != NULL);
4779 ASSERT(current_block()->HasPredecessor());
4780 return Bailout(kTryFinallyStatement);
4784 void HOptimizedGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
4785 ASSERT(!HasStackOverflow());
4786 ASSERT(current_block() != NULL);
4787 ASSERT(current_block()->HasPredecessor());
4788 return Bailout(kDebuggerStatement);
4792 void HOptimizedGraphBuilder::VisitCaseClause(CaseClause* clause) {
4797 void HOptimizedGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
4798 ASSERT(!HasStackOverflow());
4799 ASSERT(current_block() != NULL);
4800 ASSERT(current_block()->HasPredecessor());
4801 Handle<SharedFunctionInfo> shared_info = expr->shared_info();
4802 if (shared_info.is_null()) {
4803 shared_info = Compiler::BuildFunctionInfo(expr, current_info()->script());
4805 // We also have a stack overflow if the recursive compilation did.
4806 if (HasStackOverflow()) return;
4807 HFunctionLiteral* instr =
4808 New<HFunctionLiteral>(shared_info, expr->pretenure());
4809 return ast_context()->ReturnInstruction(instr, expr->id());
4813 void HOptimizedGraphBuilder::VisitNativeFunctionLiteral(
4814 NativeFunctionLiteral* expr) {
4815 ASSERT(!HasStackOverflow());
4816 ASSERT(current_block() != NULL);
4817 ASSERT(current_block()->HasPredecessor());
4818 return Bailout(kNativeFunctionLiteral);
4822 void HOptimizedGraphBuilder::VisitConditional(Conditional* expr) {
4823 ASSERT(!HasStackOverflow());
4824 ASSERT(current_block() != NULL);
4825 ASSERT(current_block()->HasPredecessor());
4826 HBasicBlock* cond_true = graph()->CreateBasicBlock();
4827 HBasicBlock* cond_false = graph()->CreateBasicBlock();
4828 CHECK_BAILOUT(VisitForControl(expr->condition(), cond_true, cond_false));
4830 // Visit the true and false subexpressions in the same AST context as the
4831 // whole expression.
4832 if (cond_true->HasPredecessor()) {
4833 cond_true->SetJoinId(expr->ThenId());
4834 set_current_block(cond_true);
4835 CHECK_BAILOUT(Visit(expr->then_expression()));
4836 cond_true = current_block();
4841 if (cond_false->HasPredecessor()) {
4842 cond_false->SetJoinId(expr->ElseId());
4843 set_current_block(cond_false);
4844 CHECK_BAILOUT(Visit(expr->else_expression()));
4845 cond_false = current_block();
4850 if (!ast_context()->IsTest()) {
4851 HBasicBlock* join = CreateJoin(cond_true, cond_false, expr->id());
4852 set_current_block(join);
4853 if (join != NULL && !ast_context()->IsEffect()) {
4854 return ast_context()->ReturnValue(Pop());
4860 HOptimizedGraphBuilder::GlobalPropertyAccess
4861 HOptimizedGraphBuilder::LookupGlobalProperty(
4862 Variable* var, LookupResult* lookup, PropertyAccessType access_type) {
4863 if (var->is_this() || !current_info()->has_global_object()) {
4866 Handle<GlobalObject> global(current_info()->global_object());
4867 global->Lookup(*var->name(), lookup);
4868 if (!lookup->IsNormal() ||
4869 (access_type == STORE && lookup->IsReadOnly()) ||
4870 lookup->holder() != *global) {
4878 HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) {
4879 ASSERT(var->IsContextSlot());
4880 HValue* context = environment()->context();
4881 int length = current_info()->scope()->ContextChainLength(var->scope());
4882 while (length-- > 0) {
4883 context = Add<HLoadNamedField>(
4884 context, static_cast<HValue*>(NULL),
4885 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
4891 void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
4892 if (expr->is_this()) {
4893 current_info()->set_this_has_uses(true);
4896 ASSERT(!HasStackOverflow());
4897 ASSERT(current_block() != NULL);
4898 ASSERT(current_block()->HasPredecessor());
4899 Variable* variable = expr->var();
4900 switch (variable->location()) {
4901 case Variable::UNALLOCATED: {
4902 if (IsLexicalVariableMode(variable->mode())) {
4903 // TODO(rossberg): should this be an ASSERT?
4904 return Bailout(kReferenceToGlobalLexicalVariable);
4906 // Handle known global constants like 'undefined' specially to avoid a
4907 // load from a global cell for them.
4908 Handle<Object> constant_value =
4909 isolate()->factory()->GlobalConstantFor(variable->name());
4910 if (!constant_value.is_null()) {
4911 HConstant* instr = New<HConstant>(constant_value);
4912 return ast_context()->ReturnInstruction(instr, expr->id());
4915 LookupResult lookup(isolate());
4916 GlobalPropertyAccess type = LookupGlobalProperty(variable, &lookup, LOAD);
4918 if (type == kUseCell &&
4919 current_info()->global_object()->IsAccessCheckNeeded()) {
4923 if (type == kUseCell) {
4924 Handle<GlobalObject> global(current_info()->global_object());
4925 Handle<PropertyCell> cell(global->GetPropertyCell(&lookup));
4926 if (cell->type()->IsConstant()) {
4927 cell->AddDependentCompilationInfo(top_info());
4928 Handle<Object> constant_object = cell->type()->AsConstant();
4929 if (constant_object->IsConsString()) {
4931 FlattenGetString(Handle<String>::cast(constant_object));
4933 HConstant* constant = New<HConstant>(constant_object);
4934 return ast_context()->ReturnInstruction(constant, expr->id());
4936 HLoadGlobalCell* instr =
4937 New<HLoadGlobalCell>(cell, lookup.GetPropertyDetails());
4938 return ast_context()->ReturnInstruction(instr, expr->id());
4941 HValue* global_object = Add<HLoadNamedField>(
4942 context(), static_cast<HValue*>(NULL),
4943 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
4944 HLoadGlobalGeneric* instr =
4945 New<HLoadGlobalGeneric>(global_object,
4947 ast_context()->is_for_typeof());
4948 return ast_context()->ReturnInstruction(instr, expr->id());
4952 case Variable::PARAMETER:
4953 case Variable::LOCAL: {
4954 HValue* value = LookupAndMakeLive(variable);
4955 if (value == graph()->GetConstantHole()) {
4956 ASSERT(IsDeclaredVariableMode(variable->mode()) &&
4957 variable->mode() != VAR);
4958 return Bailout(kReferenceToUninitializedVariable);
4960 return ast_context()->ReturnValue(value);
4963 case Variable::CONTEXT: {
4964 HValue* context = BuildContextChainWalk(variable);
4965 HLoadContextSlot* instr = new(zone()) HLoadContextSlot(context, variable);
4966 return ast_context()->ReturnInstruction(instr, expr->id());
4969 case Variable::LOOKUP:
4970 return Bailout(kReferenceToAVariableWhichRequiresDynamicLookup);
4975 void HOptimizedGraphBuilder::VisitLiteral(Literal* expr) {
4976 ASSERT(!HasStackOverflow());
4977 ASSERT(current_block() != NULL);
4978 ASSERT(current_block()->HasPredecessor());
4979 HConstant* instr = New<HConstant>(expr->value());
4980 return ast_context()->ReturnInstruction(instr, expr->id());
4984 void HOptimizedGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
4985 ASSERT(!HasStackOverflow());
4986 ASSERT(current_block() != NULL);
4987 ASSERT(current_block()->HasPredecessor());
4988 Handle<JSFunction> closure = function_state()->compilation_info()->closure();
4989 Handle<FixedArray> literals(closure->literals());
4990 HRegExpLiteral* instr = New<HRegExpLiteral>(literals,
4993 expr->literal_index());
4994 return ast_context()->ReturnInstruction(instr, expr->id());
4998 static bool CanInlinePropertyAccess(Type* type) {
4999 if (type->Is(Type::NumberOrString())) return true;
5000 if (!type->IsClass()) return false;
5001 Handle<Map> map = type->AsClass();
5002 return map->IsJSObjectMap() &&
5003 !map->is_dictionary_map() &&
5004 !map->has_named_interceptor();
5008 // Determines whether the given array or object literal boilerplate satisfies
5009 // all limits to be considered for fast deep-copying and computes the total
5010 // size of all objects that are part of the graph.
5011 static bool IsFastLiteral(Handle<JSObject> boilerplate,
5013 int* max_properties) {
5014 if (boilerplate->map()->is_deprecated()) {
5015 Handle<Object> result = JSObject::TryMigrateInstance(boilerplate);
5016 if (result.is_null()) return false;
5019 ASSERT(max_depth >= 0 && *max_properties >= 0);
5020 if (max_depth == 0) return false;
5022 Isolate* isolate = boilerplate->GetIsolate();
5023 Handle<FixedArrayBase> elements(boilerplate->elements());
5024 if (elements->length() > 0 &&
5025 elements->map() != isolate->heap()->fixed_cow_array_map()) {
5026 if (boilerplate->HasFastObjectElements()) {
5027 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
5028 int length = elements->length();
5029 for (int i = 0; i < length; i++) {
5030 if ((*max_properties)-- == 0) return false;
5031 Handle<Object> value(fast_elements->get(i), isolate);
5032 if (value->IsJSObject()) {
5033 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
5034 if (!IsFastLiteral(value_object,
5041 } else if (!boilerplate->HasFastDoubleElements()) {
5046 Handle<FixedArray> properties(boilerplate->properties());
5047 if (properties->length() > 0) {
5050 Handle<DescriptorArray> descriptors(
5051 boilerplate->map()->instance_descriptors());
5052 int limit = boilerplate->map()->NumberOfOwnDescriptors();
5053 for (int i = 0; i < limit; i++) {
5054 PropertyDetails details = descriptors->GetDetails(i);
5055 if (details.type() != FIELD) continue;
5056 int index = descriptors->GetFieldIndex(i);
5057 if ((*max_properties)-- == 0) return false;
5058 Handle<Object> value(boilerplate->InObjectPropertyAt(index), isolate);
5059 if (value->IsJSObject()) {
5060 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
5061 if (!IsFastLiteral(value_object,
5073 void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
5074 ASSERT(!HasStackOverflow());
5075 ASSERT(current_block() != NULL);
5076 ASSERT(current_block()->HasPredecessor());
5077 expr->BuildConstantProperties(isolate());
5078 Handle<JSFunction> closure = function_state()->compilation_info()->closure();
5079 HInstruction* literal;
5081 // Check whether to use fast or slow deep-copying for boilerplate.
5082 int max_properties = kMaxFastLiteralProperties;
5083 Handle<Object> literals_cell(closure->literals()->get(expr->literal_index()),
5085 Handle<AllocationSite> site;
5086 Handle<JSObject> boilerplate;
5087 if (!literals_cell->IsUndefined()) {
5088 // Retrieve the boilerplate
5089 site = Handle<AllocationSite>::cast(literals_cell);
5090 boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()),
5094 if (!boilerplate.is_null() &&
5095 IsFastLiteral(boilerplate, kMaxFastLiteralDepth, &max_properties)) {
5096 AllocationSiteUsageContext usage_context(isolate(), site, false);
5097 usage_context.EnterNewScope();
5098 literal = BuildFastLiteral(boilerplate, &usage_context);
5099 usage_context.ExitScope(site, boilerplate);
5101 NoObservableSideEffectsScope no_effects(this);
5102 Handle<FixedArray> closure_literals(closure->literals(), isolate());
5103 Handle<FixedArray> constant_properties = expr->constant_properties();
5104 int literal_index = expr->literal_index();
5105 int flags = expr->fast_elements()
5106 ? ObjectLiteral::kFastElements : ObjectLiteral::kNoFlags;
5107 flags |= expr->has_function()
5108 ? ObjectLiteral::kHasFunction : ObjectLiteral::kNoFlags;
5110 Add<HPushArgument>(Add<HConstant>(closure_literals));
5111 Add<HPushArgument>(Add<HConstant>(literal_index));
5112 Add<HPushArgument>(Add<HConstant>(constant_properties));
5113 Add<HPushArgument>(Add<HConstant>(flags));
5115 // TODO(mvstanton): Add a flag to turn off creation of any
5116 // AllocationMementos for this call: we are in crankshaft and should have
5117 // learned enough about transition behavior to stop emitting mementos.
5118 Runtime::FunctionId function_id = Runtime::kHiddenCreateObjectLiteral;
5119 literal = Add<HCallRuntime>(isolate()->factory()->empty_string(),
5120 Runtime::FunctionForId(function_id),
5124 // The object is expected in the bailout environment during computation
5125 // of the property values and is the value of the entire expression.
5128 expr->CalculateEmitStore(zone());
5130 for (int i = 0; i < expr->properties()->length(); i++) {
5131 ObjectLiteral::Property* property = expr->properties()->at(i);
5132 if (property->IsCompileTimeValue()) continue;
5134 Literal* key = property->key();
5135 Expression* value = property->value();
5137 switch (property->kind()) {
5138 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
5139 ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
5141 case ObjectLiteral::Property::COMPUTED:
5142 if (key->value()->IsInternalizedString()) {
5143 if (property->emit_store()) {
5144 CHECK_ALIVE(VisitForValue(value));
5145 HValue* value = Pop();
5146 Handle<Map> map = property->GetReceiverType();
5147 Handle<String> name = property->key()->AsPropertyName();
5148 HInstruction* store;
5149 if (map.is_null()) {
5150 // If we don't know the monomorphic type, do a generic store.
5151 CHECK_ALIVE(store = BuildNamedGeneric(
5152 STORE, literal, name, value));
5154 PropertyAccessInfo info(this, STORE, ToType(map), name);
5155 if (info.CanAccessMonomorphic()) {
5156 HValue* checked_literal = BuildCheckMap(literal, map);
5157 ASSERT(!info.lookup()->IsPropertyCallbacks());
5158 store = BuildMonomorphicAccess(
5159 &info, literal, checked_literal, value,
5160 BailoutId::None(), BailoutId::None());
5162 CHECK_ALIVE(store = BuildNamedGeneric(
5163 STORE, literal, name, value));
5166 AddInstruction(store);
5167 if (store->HasObservableSideEffects()) {
5168 Add<HSimulate>(key->id(), REMOVABLE_SIMULATE);
5171 CHECK_ALIVE(VisitForEffect(value));
5176 case ObjectLiteral::Property::PROTOTYPE:
5177 case ObjectLiteral::Property::SETTER:
5178 case ObjectLiteral::Property::GETTER:
5179 return Bailout(kObjectLiteralWithComplexProperty);
5180 default: UNREACHABLE();
5184 if (expr->has_function()) {
5185 // Return the result of the transformation to fast properties
5186 // instead of the original since this operation changes the map
5187 // of the object. This makes sure that the original object won't
5188 // be used by other optimized code before it is transformed
5189 // (e.g. because of code motion).
5190 HToFastProperties* result = Add<HToFastProperties>(Pop());
5191 return ast_context()->ReturnValue(result);
5193 return ast_context()->ReturnValue(Pop());
5198 void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
5199 ASSERT(!HasStackOverflow());
5200 ASSERT(current_block() != NULL);
5201 ASSERT(current_block()->HasPredecessor());
5202 expr->BuildConstantElements(isolate());
5203 ZoneList<Expression*>* subexprs = expr->values();
5204 int length = subexprs->length();
5205 HInstruction* literal;
5207 Handle<AllocationSite> site;
5208 Handle<FixedArray> literals(environment()->closure()->literals(), isolate());
5209 bool uninitialized = false;
5210 Handle<Object> literals_cell(literals->get(expr->literal_index()),
5212 Handle<JSObject> boilerplate_object;
5213 if (literals_cell->IsUndefined()) {
5214 uninitialized = true;
5215 Handle<Object> raw_boilerplate = Runtime::CreateArrayLiteralBoilerplate(
5216 isolate(), literals, expr->constant_elements());
5217 if (raw_boilerplate.is_null()) {
5218 return Bailout(kArrayBoilerplateCreationFailed);
5221 boilerplate_object = Handle<JSObject>::cast(raw_boilerplate);
5222 AllocationSiteCreationContext creation_context(isolate());
5223 site = creation_context.EnterNewScope();
5224 if (JSObject::DeepWalk(boilerplate_object, &creation_context).is_null()) {
5225 return Bailout(kArrayBoilerplateCreationFailed);
5227 creation_context.ExitScope(site, boilerplate_object);
5228 literals->set(expr->literal_index(), *site);
5230 if (boilerplate_object->elements()->map() ==
5231 isolate()->heap()->fixed_cow_array_map()) {
5232 isolate()->counters()->cow_arrays_created_runtime()->Increment();
5235 ASSERT(literals_cell->IsAllocationSite());
5236 site = Handle<AllocationSite>::cast(literals_cell);
5237 boilerplate_object = Handle<JSObject>(
5238 JSObject::cast(site->transition_info()), isolate());
5241 ASSERT(!boilerplate_object.is_null());
5242 ASSERT(site->SitePointsToLiteral());
5244 ElementsKind boilerplate_elements_kind =
5245 boilerplate_object->GetElementsKind();
5247 // Check whether to use fast or slow deep-copying for boilerplate.
5248 int max_properties = kMaxFastLiteralProperties;
5249 if (IsFastLiteral(boilerplate_object,
5250 kMaxFastLiteralDepth,
5252 AllocationSiteUsageContext usage_context(isolate(), site, false);
5253 usage_context.EnterNewScope();
5254 literal = BuildFastLiteral(boilerplate_object, &usage_context);
5255 usage_context.ExitScope(site, boilerplate_object);
5257 NoObservableSideEffectsScope no_effects(this);
5258 // Boilerplate already exists and constant elements are never accessed,
5259 // pass an empty fixed array to the runtime function instead.
5260 Handle<FixedArray> constants = isolate()->factory()->empty_fixed_array();
5261 int literal_index = expr->literal_index();
5262 int flags = expr->depth() == 1
5263 ? ArrayLiteral::kShallowElements
5264 : ArrayLiteral::kNoFlags;
5265 flags |= ArrayLiteral::kDisableMementos;
5267 Add<HPushArgument>(Add<HConstant>(literals));
5268 Add<HPushArgument>(Add<HConstant>(literal_index));
5269 Add<HPushArgument>(Add<HConstant>(constants));
5270 Add<HPushArgument>(Add<HConstant>(flags));
5272 // TODO(mvstanton): Consider a flag to turn off creation of any
5273 // AllocationMementos for this call: we are in crankshaft and should have
5274 // learned enough about transition behavior to stop emitting mementos.
5275 Runtime::FunctionId function_id = Runtime::kHiddenCreateArrayLiteral;
5276 literal = Add<HCallRuntime>(isolate()->factory()->empty_string(),
5277 Runtime::FunctionForId(function_id),
5280 // De-opt if elements kind changed from boilerplate_elements_kind.
5281 Handle<Map> map = Handle<Map>(boilerplate_object->map(), isolate());
5282 literal = Add<HCheckMaps>(literal, map, top_info());
5285 // The array is expected in the bailout environment during computation
5286 // of the property values and is the value of the entire expression.
5288 // The literal index is on the stack, too.
5289 Push(Add<HConstant>(expr->literal_index()));
5291 HInstruction* elements = NULL;
5293 for (int i = 0; i < length; i++) {
5294 Expression* subexpr = subexprs->at(i);
5295 // If the subexpression is a literal or a simple materialized literal it
5296 // is already set in the cloned array.
5297 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
5299 CHECK_ALIVE(VisitForValue(subexpr));
5300 HValue* value = Pop();
5301 if (!Smi::IsValid(i)) return Bailout(kNonSmiKeyInArrayLiteral);
5303 elements = AddLoadElements(literal);
5305 HValue* key = Add<HConstant>(i);
5307 switch (boilerplate_elements_kind) {
5308 case FAST_SMI_ELEMENTS:
5309 case FAST_HOLEY_SMI_ELEMENTS:
5311 case FAST_HOLEY_ELEMENTS:
5312 case FAST_DOUBLE_ELEMENTS:
5313 case FAST_HOLEY_DOUBLE_ELEMENTS: {
5314 HStoreKeyed* instr = Add<HStoreKeyed>(elements, key, value,
5315 boilerplate_elements_kind);
5316 instr->SetUninitialized(uninitialized);
5324 Add<HSimulate>(expr->GetIdForElement(i));
5327 Drop(1); // array literal index
5328 return ast_context()->ReturnValue(Pop());
5332 HCheckMaps* HOptimizedGraphBuilder::AddCheckMap(HValue* object,
5334 BuildCheckHeapObject(object);
5335 return Add<HCheckMaps>(object, map, top_info());
5339 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedField(
5340 PropertyAccessInfo* info,
5341 HValue* checked_object) {
5342 HObjectAccess access = info->access();
5343 if (access.representation().IsDouble()) {
5344 // Load the heap number.
5345 checked_object = Add<HLoadNamedField>(
5346 checked_object, static_cast<HValue*>(NULL),
5347 access.WithRepresentation(Representation::Tagged()));
5348 checked_object->set_type(HType::HeapNumber());
5349 // Load the double value from it.
5350 access = HObjectAccess::ForHeapNumberValue();
5352 return New<HLoadNamedField>(
5353 checked_object, static_cast<HValue*>(NULL), access);
5357 HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField(
5358 PropertyAccessInfo* info,
5359 HValue* checked_object,
5361 bool transition_to_field = info->lookup()->IsTransition();
5362 // TODO(verwaest): Move this logic into PropertyAccessInfo.
5363 HObjectAccess field_access = HObjectAccess::ForField(
5364 info->map(), info->lookup(), info->name());
5366 HStoreNamedField *instr;
5367 if (field_access.representation().IsDouble()) {
5368 HObjectAccess heap_number_access =
5369 field_access.WithRepresentation(Representation::Tagged());
5370 if (transition_to_field) {
5371 // The store requires a mutable HeapNumber to be allocated.
5372 NoObservableSideEffectsScope no_side_effects(this);
5373 HInstruction* heap_number_size = Add<HConstant>(HeapNumber::kSize);
5375 PretenureFlag pretenure_flag = !FLAG_allocation_site_pretenuring ?
5376 isolate()->heap()->GetPretenureMode() : NOT_TENURED;
5378 HInstruction* heap_number = Add<HAllocate>(heap_number_size,
5379 HType::HeapNumber(),
5382 AddStoreMapConstant(heap_number, isolate()->factory()->heap_number_map());
5383 Add<HStoreNamedField>(heap_number, HObjectAccess::ForHeapNumberValue(),
5385 instr = New<HStoreNamedField>(checked_object->ActualValue(),
5389 // Already holds a HeapNumber; load the box and write its value field.
5390 HInstruction* heap_number = Add<HLoadNamedField>(
5391 checked_object, static_cast<HValue*>(NULL), heap_number_access);
5392 heap_number->set_type(HType::HeapNumber());
5393 instr = New<HStoreNamedField>(heap_number,
5394 HObjectAccess::ForHeapNumberValue(),
5395 value, STORE_TO_INITIALIZED_ENTRY);
5398 // This is a normal store.
5399 instr = New<HStoreNamedField>(
5400 checked_object->ActualValue(), field_access, value,
5401 transition_to_field ? INITIALIZING_STORE : STORE_TO_INITIALIZED_ENTRY);
5404 if (transition_to_field) {
5405 HConstant* transition_constant = Add<HConstant>(info->transition());
5406 instr->SetTransition(transition_constant, top_info());
5407 instr->SetChangesFlag(kMaps);
5413 bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatible(
5414 PropertyAccessInfo* info) {
5415 if (!CanInlinePropertyAccess(type_)) return false;
5417 // Currently only handle Type::Number as a polymorphic case.
5418 // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber
5420 if (type_->Is(Type::Number())) return false;
5422 // Values are only compatible for monomorphic load if they all behave the same
5423 // regarding value wrappers.
5424 if (type_->Is(Type::NumberOrString())) {
5425 if (!info->type_->Is(Type::NumberOrString())) return false;
5427 if (info->type_->Is(Type::NumberOrString())) return false;
5430 if (!LookupDescriptor()) return false;
5432 if (!lookup_.IsFound()) {
5433 return (!info->lookup_.IsFound() || info->has_holder()) &&
5434 map()->prototype() == info->map()->prototype();
5437 // Mismatch if the other access info found the property in the prototype
5439 if (info->has_holder()) return false;
5441 if (lookup_.IsPropertyCallbacks()) {
5442 return accessor_.is_identical_to(info->accessor_) &&
5443 api_holder_.is_identical_to(info->api_holder_);
5446 if (lookup_.IsConstant()) {
5447 return constant_.is_identical_to(info->constant_);
5450 ASSERT(lookup_.IsField());
5451 if (!info->lookup_.IsField()) return false;
5453 Representation r = access_.representation();
5455 if (!info->access_.representation().IsCompatibleForLoad(r)) return false;
5457 if (!info->access_.representation().IsCompatibleForStore(r)) return false;
5459 if (info->access_.offset() != access_.offset()) return false;
5460 if (info->access_.IsInobject() != access_.IsInobject()) return false;
5461 info->GeneralizeRepresentation(r);
5466 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() {
5467 if (!type_->IsClass()) return true;
5468 map()->LookupDescriptor(NULL, *name_, &lookup_);
5469 return LoadResult(map());
5473 bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) {
5474 if (!IsLoad() && lookup_.IsProperty() &&
5475 (lookup_.IsReadOnly() || !lookup_.IsCacheable())) {
5479 if (lookup_.IsField()) {
5480 access_ = HObjectAccess::ForField(map, &lookup_, name_);
5481 } else if (lookup_.IsPropertyCallbacks()) {
5482 Handle<Object> callback(lookup_.GetValueFromMap(*map), isolate());
5483 if (!callback->IsAccessorPair()) return false;
5484 Object* raw_accessor = IsLoad()
5485 ? Handle<AccessorPair>::cast(callback)->getter()
5486 : Handle<AccessorPair>::cast(callback)->setter();
5487 if (!raw_accessor->IsJSFunction()) return false;
5488 Handle<JSFunction> accessor = handle(JSFunction::cast(raw_accessor));
5489 if (accessor->shared()->IsApiFunction()) {
5490 CallOptimization call_optimization(accessor);
5491 if (!call_optimization.is_simple_api_call()) return false;
5492 CallOptimization::HolderLookup holder_lookup;
5493 api_holder_ = call_optimization.LookupHolderOfExpectedType(
5494 map, &holder_lookup);
5495 switch (holder_lookup) {
5496 case CallOptimization::kHolderNotFound:
5498 case CallOptimization::kHolderIsReceiver:
5499 case CallOptimization::kHolderFound:
5503 accessor_ = accessor;
5504 } else if (lookup_.IsConstant()) {
5505 constant_ = handle(lookup_.GetConstantFromMap(*map), isolate());
5512 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
5513 Handle<Map> map = this->map();
5515 while (map->prototype()->IsJSObject()) {
5516 holder_ = handle(JSObject::cast(map->prototype()));
5517 if (holder_->map()->is_deprecated()) {
5518 JSObject::TryMigrateInstance(holder_);
5520 map = Handle<Map>(holder_->map());
5521 if (!CanInlinePropertyAccess(ToType(map))) {
5525 map->LookupDescriptor(*holder_, *name_, &lookup_);
5526 if (lookup_.IsFound()) return LoadResult(map);
5533 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() {
5534 if (IsSIMD128PropertyCallback() && CPU::SupportsSIMD128InCrankshaft()) {
5537 if (!CanInlinePropertyAccess(type_)) return false;
5538 if (IsJSObjectFieldAccessor()) return IsLoad();
5539 if (!LookupDescriptor()) return false;
5540 if (lookup_.IsFound()) {
5541 if (IsLoad()) return true;
5542 return !lookup_.IsReadOnly() && lookup_.IsCacheable();
5544 if (!LookupInPrototypes()) return false;
5545 if (IsLoad()) return true;
5547 if (lookup_.IsPropertyCallbacks()) return true;
5548 Handle<Map> map = this->map();
5549 map->LookupTransition(NULL, *name_, &lookup_);
5550 if (lookup_.IsTransitionToField() && map->unused_property_fields() > 0) {
5557 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessAsMonomorphic(
5558 SmallMapList* types) {
5559 ASSERT(type_->Is(ToType(types->first())));
5560 if (!CanAccessMonomorphic()) return false;
5561 STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism);
5562 if (types->length() > kMaxLoadPolymorphism) return false;
5564 if (IsSIMD128PropertyCallback() && CPU::SupportsSIMD128InCrankshaft()) {
5565 for (int i = 1; i < types->length(); ++i) {
5566 if (types->at(i)->instance_type() == types->first()->instance_type()) {
5573 HObjectAccess access = HObjectAccess::ForMap(); // bogus default
5574 if (GetJSObjectFieldAccess(&access)) {
5575 for (int i = 1; i < types->length(); ++i) {
5576 PropertyAccessInfo test_info(
5577 builder_, access_type_, ToType(types->at(i)), name_);
5578 HObjectAccess test_access = HObjectAccess::ForMap(); // bogus default
5579 if (!test_info.GetJSObjectFieldAccess(&test_access)) return false;
5580 if (!access.Equals(test_access)) return false;
5585 // Currently only handle Type::Number as a polymorphic case.
5586 // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber
5588 if (type_->Is(Type::Number())) return false;
5590 // Multiple maps cannot transition to the same target map.
5591 ASSERT(!IsLoad() || !lookup_.IsTransition());
5592 if (lookup_.IsTransition() && types->length() > 1) return false;
5594 for (int i = 1; i < types->length(); ++i) {
5595 PropertyAccessInfo test_info(
5596 builder_, access_type_, ToType(types->at(i)), name_);
5597 if (!test_info.IsCompatible(this)) return false;
5604 static bool NeedsWrappingFor(Type* type, Handle<JSFunction> target) {
5605 return type->Is(Type::NumberOrString()) &&
5606 target->shared()->strict_mode() == SLOPPY &&
5607 !target->shared()->native();
5611 static bool IsSIMDProperty(Handle<String> name, uint8_t* mask) {
5612 SmartArrayPointer<char> cstring = name->ToCString();
5616 switch (cstring[i]) {
5628 *mask |= (shift << 2*i);
5636 HInstruction* HOptimizedGraphBuilder::BuildMonomorphicAccess(
5637 PropertyAccessInfo* info,
5639 HValue* checked_object,
5642 BailoutId return_id,
5643 bool can_inline_accessor) {
5645 HObjectAccess access = HObjectAccess::ForMap(); // bogus default
5646 if (info->GetJSObjectFieldAccess(&access)) {
5647 ASSERT(info->IsLoad());
5648 return New<HLoadNamedField>(object, checked_object, access);
5651 HValue* checked_holder = checked_object;
5652 if (info->has_holder()) {
5653 Handle<JSObject> prototype(JSObject::cast(info->map()->prototype()));
5654 checked_holder = BuildCheckPrototypeMaps(prototype, info->holder());
5657 if (!info->lookup()->IsFound()) {
5658 ASSERT(info->IsLoad());
5659 return graph()->GetConstantUndefined();
5662 if (info->lookup()->IsField()) {
5663 if (info->IsLoad()) {
5664 if (info->map()->constructor()->IsJSFunction()) {
5665 JSFunction* constructor = JSFunction::cast(info->map()->constructor());
5666 String* class_name =
5667 String::cast(constructor->shared()->instance_class_name());
5669 if (class_name->Equals(isolate()->heap()->simd()) &&
5670 IsSIMDProperty(info->name(), &mask) &&
5671 CPU::SupportsSIMD128InCrankshaft()) {
5672 return New<HConstant>(mask);
5675 return BuildLoadNamedField(info, checked_holder);
5677 return BuildStoreNamedField(info, checked_object, value);
5681 if (info->lookup()->IsTransition()) {
5682 ASSERT(!info->IsLoad());
5683 return BuildStoreNamedField(info, checked_object, value);
5686 if (info->lookup()->IsPropertyCallbacks()) {
5687 Push(checked_object);
5688 int argument_count = 1;
5689 if (!info->IsLoad()) {
5694 if (NeedsWrappingFor(info->type(), info->accessor())) {
5695 HValue* function = Add<HConstant>(info->accessor());
5696 PushArgumentsFromEnvironment(argument_count);
5697 return New<HCallFunction>(function, argument_count, WRAP_AND_CALL);
5698 } else if (FLAG_inline_accessors && can_inline_accessor) {
5699 bool success = info->IsLoad()
5700 ? TryInlineGetter(info->accessor(), info->map(), ast_id, return_id)
5702 info->accessor(), info->map(), ast_id, return_id, value);
5703 if (success) return NULL;
5706 PushArgumentsFromEnvironment(argument_count);
5707 return BuildCallConstantFunction(info->accessor(), argument_count);
5710 ASSERT(info->lookup()->IsConstant());
5711 if (info->IsLoad()) {
5712 return New<HConstant>(info->constant());
5714 return New<HCheckValue>(value, Handle<JSFunction>::cast(info->constant()));
5719 void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess(
5720 PropertyAccessType access_type,
5722 BailoutId return_id,
5725 SmallMapList* types,
5726 Handle<String> name) {
5727 // Something did not match; must use a polymorphic load.
5729 HBasicBlock* join = NULL;
5730 HBasicBlock* number_block = NULL;
5731 bool handled_string = false;
5733 bool handle_smi = false;
5734 STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism);
5735 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
5736 PropertyAccessInfo info(this, access_type, ToType(types->at(i)), name);
5737 if (info.type()->Is(Type::String())) {
5738 if (handled_string) continue;
5739 handled_string = true;
5741 if (info.CanAccessMonomorphic()) {
5743 if (info.type()->Is(Type::Number())) {
5751 HControlInstruction* smi_check = NULL;
5752 handled_string = false;
5754 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
5755 PropertyAccessInfo info(this, access_type, ToType(types->at(i)), name);
5756 if (info.type()->Is(Type::String())) {
5757 if (handled_string) continue;
5758 handled_string = true;
5760 if (!info.CanAccessMonomorphic()) continue;
5763 join = graph()->CreateBasicBlock();
5765 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock();
5766 HBasicBlock* not_smi_block = graph()->CreateBasicBlock();
5767 number_block = graph()->CreateBasicBlock();
5768 smi_check = New<HIsSmiAndBranch>(
5769 object, empty_smi_block, not_smi_block);
5770 FinishCurrentBlock(smi_check);
5771 GotoNoSimulate(empty_smi_block, number_block);
5772 set_current_block(not_smi_block);
5774 BuildCheckHeapObject(object);
5778 HBasicBlock* if_true = graph()->CreateBasicBlock();
5779 HBasicBlock* if_false = graph()->CreateBasicBlock();
5780 HUnaryControlInstruction* compare;
5783 if (info.type()->Is(Type::Number())) {
5784 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map();
5785 compare = New<HCompareMap>(object, heap_number_map, if_true, if_false);
5786 dependency = smi_check;
5787 } else if (info.type()->Is(Type::String())) {
5788 compare = New<HIsStringAndBranch>(object, if_true, if_false);
5789 dependency = compare;
5791 compare = New<HCompareMap>(object, info.map(), if_true, if_false);
5792 dependency = compare;
5794 FinishCurrentBlock(compare);
5796 if (info.type()->Is(Type::Number())) {
5797 GotoNoSimulate(if_true, number_block);
5798 if_true = number_block;
5801 set_current_block(if_true);
5803 HInstruction* access = BuildMonomorphicAccess(
5804 &info, object, dependency, value, ast_id,
5805 return_id, FLAG_polymorphic_inlining);
5807 HValue* result = NULL;
5808 switch (access_type) {
5817 if (access == NULL) {
5818 if (HasStackOverflow()) return;
5820 if (!access->IsLinked()) AddInstruction(access);
5821 if (!ast_context()->IsEffect()) Push(result);
5824 if (current_block() != NULL) Goto(join);
5825 set_current_block(if_false);
5828 // Finish up. Unconditionally deoptimize if we've handled all the maps we
5829 // know about and do not want to handle ones we've never seen. Otherwise
5830 // use a generic IC.
5831 if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
5832 FinishExitWithHardDeoptimization("Uknown map in polymorphic access");
5834 HInstruction* instr = BuildNamedGeneric(access_type, object, name, value);
5835 AddInstruction(instr);
5836 if (!ast_context()->IsEffect()) Push(access_type == LOAD ? instr : value);
5841 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
5842 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
5847 ASSERT(join != NULL);
5848 if (join->HasPredecessor()) {
5849 join->SetJoinId(ast_id);
5850 set_current_block(join);
5851 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
5853 set_current_block(NULL);
5858 static bool ComputeReceiverTypes(Expression* expr,
5862 SmallMapList* types = expr->GetReceiverTypes();
5864 bool monomorphic = expr->IsMonomorphic();
5865 if (types != NULL && receiver->HasMonomorphicJSObjectType()) {
5866 Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap();
5867 types->FilterForPossibleTransitions(root_map);
5868 monomorphic = types->length() == 1;
5870 return monomorphic && CanInlinePropertyAccess(
5871 IC::MapToType<Type>(types->first(), zone));
5875 static bool AreStringTypes(SmallMapList* types) {
5876 for (int i = 0; i < types->length(); i++) {
5877 if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false;
5883 static bool AreInt32x4Types(SmallMapList* types) {
5884 if (types == NULL || types->length() == 0) return false;
5885 for (int i = 0; i < types->length(); i++) {
5886 if (types->at(i)->instance_type() != INT32x4_TYPE) return false;
5892 static bool AreFloat32x4Types(SmallMapList* types) {
5893 if (types == NULL || types->length() == 0) return false;
5894 for (int i = 0; i < types->length(); i++) {
5895 if (types->at(i)->instance_type() != FLOAT32x4_TYPE) return false;
5901 static BuiltinFunctionId NameToId(Isolate* isolate, Handle<String> name,
5902 InstanceType type) {
5903 BuiltinFunctionId id;
5904 if (name->Equals(isolate->heap()->signMask())) {
5905 id = type == FLOAT32x4_TYPE ? kFloat32x4GetSignMask : kInt32x4GetSignMask;
5906 } else if (name->Equals(isolate->heap()->x())) {
5907 id = type == FLOAT32x4_TYPE ? kFloat32x4GetX : kInt32x4GetX;
5908 } else if (name->Equals(isolate->heap()->y())) {
5909 id = type == FLOAT32x4_TYPE ? kFloat32x4GetY : kInt32x4GetY;
5910 } else if (name->Equals(isolate->heap()->z())) {
5911 id = type == FLOAT32x4_TYPE ? kFloat32x4GetZ : kInt32x4GetZ;
5912 } else if (name->Equals(isolate->heap()->w())) {
5913 id = type == FLOAT32x4_TYPE ? kFloat32x4GetW : kInt32x4GetW;
5914 } else if (name->Equals(isolate->heap()->flagX())) {
5915 ASSERT(type == INT32x4_TYPE);
5916 id = kInt32x4GetFlagX;
5917 } else if (name->Equals(isolate->heap()->flagY())) {
5918 ASSERT(type == INT32x4_TYPE);
5919 id = kInt32x4GetFlagY;
5920 } else if (name->Equals(isolate->heap()->flagZ())) {
5921 ASSERT(type == INT32x4_TYPE);
5922 id = kInt32x4GetFlagZ;
5923 } else if (name->Equals(isolate->heap()->flagW())) {
5924 ASSERT(type == INT32x4_TYPE);
5925 id = kInt32x4GetFlagW;
5928 id = kSIMD128Unreachable;
5935 void HOptimizedGraphBuilder::BuildStore(Expression* expr,
5938 BailoutId return_id,
5939 bool is_uninitialized) {
5940 if (!prop->key()->IsPropertyName()) {
5942 HValue* value = environment()->ExpressionStackAt(0);
5943 HValue* key = environment()->ExpressionStackAt(1);
5944 HValue* object = environment()->ExpressionStackAt(2);
5945 bool has_side_effects = false;
5946 HandleKeyedElementAccess(object, key, value, expr,
5947 STORE, &has_side_effects);
5950 Add<HSimulate>(return_id, REMOVABLE_SIMULATE);
5951 return ast_context()->ReturnValue(Pop());
5955 HValue* value = Pop();
5956 HValue* object = Pop();
5958 Literal* key = prop->key()->AsLiteral();
5959 Handle<String> name = Handle<String>::cast(key->value());
5960 ASSERT(!name.is_null());
5962 HInstruction* instr = BuildNamedAccess(STORE, ast_id, return_id, expr,
5963 object, name, value, is_uninitialized);
5964 if (instr == NULL) return;
5966 if (!ast_context()->IsEffect()) Push(value);
5967 AddInstruction(instr);
5968 if (instr->HasObservableSideEffects()) {
5969 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
5971 if (!ast_context()->IsEffect()) Drop(1);
5972 return ast_context()->ReturnValue(value);
5976 void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
5977 Property* prop = expr->target()->AsProperty();
5978 ASSERT(prop != NULL);
5979 CHECK_ALIVE(VisitForValue(prop->obj()));
5980 if (!prop->key()->IsPropertyName()) {
5981 CHECK_ALIVE(VisitForValue(prop->key()));
5983 CHECK_ALIVE(VisitForValue(expr->value()));
5984 BuildStore(expr, prop, expr->id(),
5985 expr->AssignmentId(), expr->IsUninitialized());
5989 // Because not every expression has a position and there is not common
5990 // superclass of Assignment and CountOperation, we cannot just pass the
5991 // owning expression instead of position and ast_id separately.
5992 void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
5996 LookupResult lookup(isolate());
5997 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, STORE);
5998 if (type == kUseCell) {
5999 Handle<GlobalObject> global(current_info()->global_object());
6000 Handle<PropertyCell> cell(global->GetPropertyCell(&lookup));
6001 if (cell->type()->IsConstant()) {
6002 Handle<Object> constant = cell->type()->AsConstant();
6003 if (value->IsConstant()) {
6004 HConstant* c_value = HConstant::cast(value);
6005 if (!constant.is_identical_to(c_value->handle(isolate()))) {
6006 Add<HDeoptimize>("Constant global variable assignment",
6007 Deoptimizer::EAGER);
6010 HValue* c_constant = Add<HConstant>(constant);
6011 IfBuilder builder(this);
6012 if (constant->IsNumber()) {
6013 builder.If<HCompareNumericAndBranch>(value, c_constant, Token::EQ);
6015 builder.If<HCompareObjectEqAndBranch>(value, c_constant);
6019 Add<HDeoptimize>("Constant global variable assignment",
6020 Deoptimizer::EAGER);
6024 HInstruction* instr =
6025 Add<HStoreGlobalCell>(value, cell, lookup.GetPropertyDetails());
6026 if (instr->HasObservableSideEffects()) {
6027 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6030 HValue* global_object = Add<HLoadNamedField>(
6031 context(), static_cast<HValue*>(NULL),
6032 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
6033 HStoreNamedGeneric* instr =
6034 Add<HStoreNamedGeneric>(global_object, var->name(),
6035 value, function_strict_mode());
6037 ASSERT(instr->HasObservableSideEffects());
6038 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6043 void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
6044 Expression* target = expr->target();
6045 VariableProxy* proxy = target->AsVariableProxy();
6046 Property* prop = target->AsProperty();
6047 ASSERT(proxy == NULL || prop == NULL);
6049 // We have a second position recorded in the FullCodeGenerator to have
6050 // type feedback for the binary operation.
6051 BinaryOperation* operation = expr->binary_operation();
6053 if (proxy != NULL) {
6054 Variable* var = proxy->var();
6055 if (var->mode() == LET) {
6056 return Bailout(kUnsupportedLetCompoundAssignment);
6059 CHECK_ALIVE(VisitForValue(operation));
6061 switch (var->location()) {
6062 case Variable::UNALLOCATED:
6063 HandleGlobalVariableAssignment(var,
6065 expr->AssignmentId());
6068 case Variable::PARAMETER:
6069 case Variable::LOCAL:
6070 if (var->mode() == CONST_LEGACY) {
6071 return Bailout(kUnsupportedConstCompoundAssignment);
6073 BindIfLive(var, Top());
6076 case Variable::CONTEXT: {
6077 // Bail out if we try to mutate a parameter value in a function
6078 // using the arguments object. We do not (yet) correctly handle the
6079 // arguments property of the function.
6080 if (current_info()->scope()->arguments() != NULL) {
6081 // Parameters will be allocated to context slots. We have no
6082 // direct way to detect that the variable is a parameter so we do
6083 // a linear search of the parameter variables.
6084 int count = current_info()->scope()->num_parameters();
6085 for (int i = 0; i < count; ++i) {
6086 if (var == current_info()->scope()->parameter(i)) {
6087 Bailout(kAssignmentToParameterFunctionUsesArgumentsObject);
6092 HStoreContextSlot::Mode mode;
6094 switch (var->mode()) {
6096 mode = HStoreContextSlot::kCheckDeoptimize;
6099 // This case is checked statically so no need to
6100 // perform checks here
6103 return ast_context()->ReturnValue(Pop());
6105 mode = HStoreContextSlot::kNoCheck;
6108 HValue* context = BuildContextChainWalk(var);
6109 HStoreContextSlot* instr = Add<HStoreContextSlot>(
6110 context, var->index(), mode, Top());
6111 if (instr->HasObservableSideEffects()) {
6112 Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
6117 case Variable::LOOKUP:
6118 return Bailout(kCompoundAssignmentToLookupSlot);
6120 return ast_context()->ReturnValue(Pop());
6122 } else if (prop != NULL) {
6123 CHECK_ALIVE(VisitForValue(prop->obj()));
6124 HValue* object = Top();
6126 if ((!prop->IsFunctionPrototype() && !prop->key()->IsPropertyName()) ||
6127 prop->IsStringAccess()) {
6128 CHECK_ALIVE(VisitForValue(prop->key()));
6132 CHECK_ALIVE(PushLoad(prop, object, key));
6134 CHECK_ALIVE(VisitForValue(expr->value()));
6135 HValue* right = Pop();
6136 HValue* left = Pop();
6138 Push(BuildBinaryOperation(operation, left, right, PUSH_BEFORE_SIMULATE));
6140 BuildStore(expr, prop, expr->id(),
6141 expr->AssignmentId(), expr->IsUninitialized());
6143 return Bailout(kInvalidLhsInCompoundAssignment);
6148 void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) {
6149 ASSERT(!HasStackOverflow());
6150 ASSERT(current_block() != NULL);
6151 ASSERT(current_block()->HasPredecessor());
6152 VariableProxy* proxy = expr->target()->AsVariableProxy();
6153 Property* prop = expr->target()->AsProperty();
6154 ASSERT(proxy == NULL || prop == NULL);
6156 if (expr->is_compound()) {
6157 HandleCompoundAssignment(expr);
6162 HandlePropertyAssignment(expr);
6163 } else if (proxy != NULL) {
6164 Variable* var = proxy->var();
6166 if (var->mode() == CONST) {
6167 if (expr->op() != Token::INIT_CONST) {
6168 return Bailout(kNonInitializerAssignmentToConst);
6170 } else if (var->mode() == CONST_LEGACY) {
6171 if (expr->op() != Token::INIT_CONST_LEGACY) {
6172 CHECK_ALIVE(VisitForValue(expr->value()));
6173 return ast_context()->ReturnValue(Pop());
6176 if (var->IsStackAllocated()) {
6177 // We insert a use of the old value to detect unsupported uses of const
6178 // variables (e.g. initialization inside a loop).
6179 HValue* old_value = environment()->Lookup(var);
6180 Add<HUseConst>(old_value);
6184 if (proxy->IsArguments()) return Bailout(kAssignmentToArguments);
6186 // Handle the assignment.
6187 switch (var->location()) {
6188 case Variable::UNALLOCATED:
6189 CHECK_ALIVE(VisitForValue(expr->value()));
6190 HandleGlobalVariableAssignment(var,
6192 expr->AssignmentId());
6193 return ast_context()->ReturnValue(Pop());
6195 case Variable::PARAMETER:
6196 case Variable::LOCAL: {
6197 // Perform an initialization check for let declared variables
6199 if (var->mode() == LET && expr->op() == Token::ASSIGN) {
6200 HValue* env_value = environment()->Lookup(var);
6201 if (env_value == graph()->GetConstantHole()) {
6202 return Bailout(kAssignmentToLetVariableBeforeInitialization);
6205 // We do not allow the arguments object to occur in a context where it
6206 // may escape, but assignments to stack-allocated locals are
6208 CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED));
6209 HValue* value = Pop();
6210 BindIfLive(var, value);
6211 return ast_context()->ReturnValue(value);
6214 case Variable::CONTEXT: {
6215 // Bail out if we try to mutate a parameter value in a function using
6216 // the arguments object. We do not (yet) correctly handle the
6217 // arguments property of the function.
6218 if (current_info()->scope()->arguments() != NULL) {
6219 // Parameters will rewrite to context slots. We have no direct way
6220 // to detect that the variable is a parameter.
6221 int count = current_info()->scope()->num_parameters();
6222 for (int i = 0; i < count; ++i) {
6223 if (var == current_info()->scope()->parameter(i)) {
6224 return Bailout(kAssignmentToParameterInArgumentsObject);
6229 CHECK_ALIVE(VisitForValue(expr->value()));
6230 HStoreContextSlot::Mode mode;
6231 if (expr->op() == Token::ASSIGN) {
6232 switch (var->mode()) {
6234 mode = HStoreContextSlot::kCheckDeoptimize;
6237 // This case is checked statically so no need to
6238 // perform checks here
6241 return ast_context()->ReturnValue(Pop());
6243 mode = HStoreContextSlot::kNoCheck;
6245 } else if (expr->op() == Token::INIT_VAR ||
6246 expr->op() == Token::INIT_LET ||
6247 expr->op() == Token::INIT_CONST) {
6248 mode = HStoreContextSlot::kNoCheck;
6250 ASSERT(expr->op() == Token::INIT_CONST_LEGACY);
6252 mode = HStoreContextSlot::kCheckIgnoreAssignment;
6255 HValue* context = BuildContextChainWalk(var);
6256 HStoreContextSlot* instr = Add<HStoreContextSlot>(
6257 context, var->index(), mode, Top());
6258 if (instr->HasObservableSideEffects()) {
6259 Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
6261 return ast_context()->ReturnValue(Pop());
6264 case Variable::LOOKUP:
6265 return Bailout(kAssignmentToLOOKUPVariable);
6268 return Bailout(kInvalidLeftHandSideInAssignment);
6273 void HOptimizedGraphBuilder::VisitYield(Yield* expr) {
6274 // Generators are not optimized, so we should never get here.
6279 void HOptimizedGraphBuilder::VisitThrow(Throw* expr) {
6280 ASSERT(!HasStackOverflow());
6281 ASSERT(current_block() != NULL);
6282 ASSERT(current_block()->HasPredecessor());
6283 // We don't optimize functions with invalid left-hand sides in
6284 // assignments, count operations, or for-in. Consequently throw can
6285 // currently only occur in an effect context.
6286 ASSERT(ast_context()->IsEffect());
6287 CHECK_ALIVE(VisitForValue(expr->exception()));
6289 HValue* value = environment()->Pop();
6290 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
6291 Add<HPushArgument>(value);
6292 Add<HCallRuntime>(isolate()->factory()->empty_string(),
6293 Runtime::FunctionForId(Runtime::kHiddenThrow), 1);
6294 Add<HSimulate>(expr->id());
6296 // If the throw definitely exits the function, we can finish with a dummy
6297 // control flow at this point. This is not the case if the throw is inside
6298 // an inlined function which may be replaced.
6299 if (call_context() == NULL) {
6300 FinishExitCurrentBlock(New<HAbnormalExit>());
6305 HInstruction* HGraphBuilder::AddLoadStringInstanceType(HValue* string) {
6306 if (string->IsConstant()) {
6307 HConstant* c_string = HConstant::cast(string);
6308 if (c_string->HasStringValue()) {
6309 return Add<HConstant>(c_string->StringValue()->map()->instance_type());
6312 return Add<HLoadNamedField>(
6313 Add<HLoadNamedField>(string, static_cast<HValue*>(NULL),
6314 HObjectAccess::ForMap()),
6315 static_cast<HValue*>(NULL), HObjectAccess::ForMapInstanceType());
6319 HInstruction* HGraphBuilder::AddLoadStringLength(HValue* string) {
6320 if (string->IsConstant()) {
6321 HConstant* c_string = HConstant::cast(string);
6322 if (c_string->HasStringValue()) {
6323 return Add<HConstant>(c_string->StringValue()->length());
6326 return Add<HLoadNamedField>(string, static_cast<HValue*>(NULL),
6327 HObjectAccess::ForStringLength());
6331 HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric(
6332 PropertyAccessType access_type,
6334 Handle<String> name,
6336 bool is_uninitialized) {
6337 if (is_uninitialized) {
6338 Add<HDeoptimize>("Insufficient type feedback for generic named access",
6341 if (access_type == LOAD) {
6342 return New<HLoadNamedGeneric>(object, name);
6344 return New<HStoreNamedGeneric>(object, name, value, function_strict_mode());
6350 HInstruction* HOptimizedGraphBuilder::BuildKeyedGeneric(
6351 PropertyAccessType access_type,
6355 if (access_type == LOAD) {
6356 return New<HLoadKeyedGeneric>(object, key);
6358 return New<HStoreKeyedGeneric>(object, key, value, function_strict_mode());
6363 LoadKeyedHoleMode HOptimizedGraphBuilder::BuildKeyedHoleMode(Handle<Map> map) {
6364 // Loads from a "stock" fast holey double arrays can elide the hole check.
6365 LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE;
6366 if (*map == isolate()->get_initial_js_array_map(FAST_HOLEY_DOUBLE_ELEMENTS) &&
6367 isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
6368 Handle<JSObject> prototype(JSObject::cast(map->prototype()), isolate());
6369 Handle<JSObject> object_prototype = isolate()->initial_object_prototype();
6370 BuildCheckPrototypeMaps(prototype, object_prototype);
6371 load_mode = ALLOW_RETURN_HOLE;
6372 graph()->MarkDependsOnEmptyArrayProtoElements();
6379 HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess(
6385 PropertyAccessType access_type,
6386 KeyedAccessStoreMode store_mode) {
6387 HCheckMaps* checked_object = Add<HCheckMaps>(object, map, top_info(),
6390 checked_object->ClearDependsOnFlag(kElementsKind);
6393 if (access_type == STORE && map->prototype()->IsJSObject()) {
6394 // monomorphic stores need a prototype chain check because shape
6395 // changes could allow callbacks on elements in the chain that
6396 // aren't compatible with monomorphic keyed stores.
6397 Handle<JSObject> prototype(JSObject::cast(map->prototype()));
6398 Object* holder = map->prototype();
6399 while (holder->GetPrototype(isolate())->IsJSObject()) {
6400 holder = holder->GetPrototype(isolate());
6402 ASSERT(holder->GetPrototype(isolate())->IsNull());
6404 BuildCheckPrototypeMaps(prototype,
6405 Handle<JSObject>(JSObject::cast(holder)));
6408 LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map);
6409 return BuildUncheckedMonomorphicElementAccess(
6410 checked_object, key, val,
6411 map->instance_type() == JS_ARRAY_TYPE,
6412 map->elements_kind(), access_type,
6413 load_mode, store_mode);
6417 HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad(
6421 SmallMapList* maps) {
6422 // For polymorphic loads of similar elements kinds (i.e. all tagged or all
6423 // double), always use the "worst case" code without a transition. This is
6424 // much faster than transitioning the elements to the worst case, trading a
6425 // HTransitionElements for a HCheckMaps, and avoiding mutation of the array.
6426 bool has_double_maps = false;
6427 bool has_smi_or_object_maps = false;
6428 bool has_js_array_access = false;
6429 bool has_non_js_array_access = false;
6430 bool has_seen_holey_elements = false;
6431 Handle<Map> most_general_consolidated_map;
6432 for (int i = 0; i < maps->length(); ++i) {
6433 Handle<Map> map = maps->at(i);
6434 if (!map->IsJSObjectMap()) return NULL;
6435 // Don't allow mixing of JSArrays with JSObjects.
6436 if (map->instance_type() == JS_ARRAY_TYPE) {
6437 if (has_non_js_array_access) return NULL;
6438 has_js_array_access = true;
6439 } else if (has_js_array_access) {
6442 has_non_js_array_access = true;
6444 // Don't allow mixed, incompatible elements kinds.
6445 if (map->has_fast_double_elements()) {
6446 if (has_smi_or_object_maps) return NULL;
6447 has_double_maps = true;
6448 } else if (map->has_fast_smi_or_object_elements()) {
6449 if (has_double_maps) return NULL;
6450 has_smi_or_object_maps = true;
6454 // Remember if we've ever seen holey elements.
6455 if (IsHoleyElementsKind(map->elements_kind())) {
6456 has_seen_holey_elements = true;
6458 // Remember the most general elements kind, the code for its load will
6459 // properly handle all of the more specific cases.
6460 if ((i == 0) || IsMoreGeneralElementsKindTransition(
6461 most_general_consolidated_map->elements_kind(),
6462 map->elements_kind())) {
6463 most_general_consolidated_map = map;
6466 if (!has_double_maps && !has_smi_or_object_maps) return NULL;
6468 HCheckMaps* checked_object = Add<HCheckMaps>(object, maps);
6469 // FAST_ELEMENTS is considered more general than FAST_HOLEY_SMI_ELEMENTS.
6470 // If we've seen both, the consolidated load must use FAST_HOLEY_ELEMENTS.
6471 ElementsKind consolidated_elements_kind = has_seen_holey_elements
6472 ? GetHoleyElementsKind(most_general_consolidated_map->elements_kind())
6473 : most_general_consolidated_map->elements_kind();
6474 HInstruction* instr = BuildUncheckedMonomorphicElementAccess(
6475 checked_object, key, val,
6476 most_general_consolidated_map->instance_type() == JS_ARRAY_TYPE,
6477 consolidated_elements_kind,
6478 LOAD, NEVER_RETURN_HOLE, STANDARD_STORE);
6483 HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
6488 PropertyAccessType access_type,
6489 KeyedAccessStoreMode store_mode,
6490 bool* has_side_effects) {
6491 *has_side_effects = false;
6492 BuildCheckHeapObject(object);
6494 if (access_type == LOAD) {
6495 HInstruction* consolidated_load =
6496 TryBuildConsolidatedElementLoad(object, key, val, maps);
6497 if (consolidated_load != NULL) {
6498 *has_side_effects |= consolidated_load->HasObservableSideEffects();
6499 return consolidated_load;
6503 // Elements_kind transition support.
6504 MapHandleList transition_target(maps->length());
6505 // Collect possible transition targets.
6506 MapHandleList possible_transitioned_maps(maps->length());
6507 for (int i = 0; i < maps->length(); ++i) {
6508 Handle<Map> map = maps->at(i);
6509 ElementsKind elements_kind = map->elements_kind();
6510 if (IsFastElementsKind(elements_kind) &&
6511 elements_kind != GetInitialFastElementsKind()) {
6512 possible_transitioned_maps.Add(map);
6514 if (elements_kind == SLOPPY_ARGUMENTS_ELEMENTS) {
6515 HInstruction* result = BuildKeyedGeneric(access_type, object, key, val);
6516 *has_side_effects = result->HasObservableSideEffects();
6517 return AddInstruction(result);
6520 // Get transition target for each map (NULL == no transition).
6521 for (int i = 0; i < maps->length(); ++i) {
6522 Handle<Map> map = maps->at(i);
6523 Handle<Map> transitioned_map =
6524 map->FindTransitionedMap(&possible_transitioned_maps);
6525 transition_target.Add(transitioned_map);
6528 MapHandleList untransitionable_maps(maps->length());
6529 HTransitionElementsKind* transition = NULL;
6530 for (int i = 0; i < maps->length(); ++i) {
6531 Handle<Map> map = maps->at(i);
6532 ASSERT(map->IsMap());
6533 if (!transition_target.at(i).is_null()) {
6534 ASSERT(Map::IsValidElementsTransition(
6535 map->elements_kind(),
6536 transition_target.at(i)->elements_kind()));
6537 transition = Add<HTransitionElementsKind>(object, map,
6538 transition_target.at(i));
6540 untransitionable_maps.Add(map);
6544 // If only one map is left after transitioning, handle this case
6546 ASSERT(untransitionable_maps.length() >= 1);
6547 if (untransitionable_maps.length() == 1) {
6548 Handle<Map> untransitionable_map = untransitionable_maps[0];
6549 HInstruction* instr = NULL;
6550 if (untransitionable_map->has_slow_elements_kind() ||
6551 !untransitionable_map->IsJSObjectMap()) {
6552 instr = AddInstruction(BuildKeyedGeneric(access_type, object, key, val));
6554 instr = BuildMonomorphicElementAccess(
6555 object, key, val, transition, untransitionable_map, access_type,
6558 *has_side_effects |= instr->HasObservableSideEffects();
6559 return access_type == STORE ? NULL : instr;
6562 HBasicBlock* join = graph()->CreateBasicBlock();
6564 for (int i = 0; i < untransitionable_maps.length(); ++i) {
6565 Handle<Map> map = untransitionable_maps[i];
6566 if (!map->IsJSObjectMap()) continue;
6567 ElementsKind elements_kind = map->elements_kind();
6568 HBasicBlock* this_map = graph()->CreateBasicBlock();
6569 HBasicBlock* other_map = graph()->CreateBasicBlock();
6570 HCompareMap* mapcompare =
6571 New<HCompareMap>(object, map, this_map, other_map);
6572 FinishCurrentBlock(mapcompare);
6574 set_current_block(this_map);
6575 HInstruction* access = NULL;
6576 if (IsDictionaryElementsKind(elements_kind)) {
6577 access = AddInstruction(BuildKeyedGeneric(access_type, object, key, val));
6579 ASSERT(IsFastElementsKind(elements_kind) ||
6580 IsExternalArrayElementsKind(elements_kind) ||
6581 IsFixedTypedArrayElementsKind(elements_kind));
6582 LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map);
6583 // Happily, mapcompare is a checked object.
6584 access = BuildUncheckedMonomorphicElementAccess(
6585 mapcompare, key, val,
6586 map->instance_type() == JS_ARRAY_TYPE,
6587 elements_kind, access_type,
6591 *has_side_effects |= access->HasObservableSideEffects();
6592 // The caller will use has_side_effects and add a correct Simulate.
6593 access->SetFlag(HValue::kHasNoObservableSideEffects);
6594 if (access_type == LOAD) {
6597 NoObservableSideEffectsScope scope(this);
6598 GotoNoSimulate(join);
6599 set_current_block(other_map);
6602 // Ensure that we visited at least one map above that goes to join. This is
6603 // necessary because FinishExitWithHardDeoptimization does an AbnormalExit
6604 // rather than joining the join block. If this becomes an issue, insert a
6605 // generic access in the case length() == 0.
6606 ASSERT(join->predecessors()->length() > 0);
6607 // Deopt if none of the cases matched.
6608 NoObservableSideEffectsScope scope(this);
6609 FinishExitWithHardDeoptimization("Unknown map in polymorphic element access");
6610 set_current_block(join);
6611 return access_type == STORE ? NULL : Pop();
6615 HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
6620 PropertyAccessType access_type,
6621 bool* has_side_effects) {
6622 ASSERT(!expr->IsPropertyName());
6623 HInstruction* instr = NULL;
6625 SmallMapList* types;
6626 bool monomorphic = ComputeReceiverTypes(expr, obj, &types, zone());
6628 bool force_generic = false;
6629 if (access_type == STORE &&
6630 (monomorphic || (types != NULL && !types->is_empty()))) {
6631 // Stores can't be mono/polymorphic if their prototype chain has dictionary
6632 // elements. However a receiver map that has dictionary elements itself
6633 // should be left to normal mono/poly behavior (the other maps may benefit
6634 // from highly optimized stores).
6635 for (int i = 0; i < types->length(); i++) {
6636 Handle<Map> current_map = types->at(i);
6637 if (current_map->DictionaryElementsInPrototypeChainOnly()) {
6638 force_generic = true;
6639 monomorphic = false;
6646 Handle<Map> map = types->first();
6647 if (map->has_slow_elements_kind() || !map->IsJSObjectMap()) {
6648 instr = AddInstruction(BuildKeyedGeneric(access_type, obj, key, val));
6650 BuildCheckHeapObject(obj);
6651 instr = BuildMonomorphicElementAccess(
6652 obj, key, val, NULL, map, access_type, expr->GetStoreMode());
6654 } else if (!force_generic && (types != NULL && !types->is_empty())) {
6655 return HandlePolymorphicElementAccess(
6656 obj, key, val, types, access_type,
6657 expr->GetStoreMode(), has_side_effects);
6659 if (access_type == STORE) {
6660 if (expr->IsAssignment() &&
6661 expr->AsAssignment()->HasNoTypeInformation()) {
6662 Add<HDeoptimize>("Insufficient type feedback for keyed store",
6666 if (expr->AsProperty()->HasNoTypeInformation()) {
6667 Add<HDeoptimize>("Insufficient type feedback for keyed load",
6671 instr = AddInstruction(BuildKeyedGeneric(access_type, obj, key, val));
6673 *has_side_effects = instr->HasObservableSideEffects();
6678 void HOptimizedGraphBuilder::EnsureArgumentsArePushedForAccess() {
6679 // Outermost function already has arguments on the stack.
6680 if (function_state()->outer() == NULL) return;
6682 if (function_state()->arguments_pushed()) return;
6684 // Push arguments when entering inlined function.
6685 HEnterInlined* entry = function_state()->entry();
6686 entry->set_arguments_pushed();
6688 HArgumentsObject* arguments = entry->arguments_object();
6689 const ZoneList<HValue*>* arguments_values = arguments->arguments_values();
6691 HInstruction* insert_after = entry;
6692 for (int i = 0; i < arguments_values->length(); i++) {
6693 HValue* argument = arguments_values->at(i);
6694 HInstruction* push_argument = New<HPushArgument>(argument);
6695 push_argument->InsertAfter(insert_after);
6696 insert_after = push_argument;
6699 HArgumentsElements* arguments_elements = New<HArgumentsElements>(true);
6700 arguments_elements->ClearFlag(HValue::kUseGVN);
6701 arguments_elements->InsertAfter(insert_after);
6702 function_state()->set_arguments_elements(arguments_elements);
6706 bool HOptimizedGraphBuilder::TryArgumentsAccess(Property* expr) {
6707 VariableProxy* proxy = expr->obj()->AsVariableProxy();
6708 if (proxy == NULL) return false;
6709 if (!proxy->var()->IsStackAllocated()) return false;
6710 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) {
6714 HInstruction* result = NULL;
6715 if (expr->key()->IsPropertyName()) {
6716 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
6717 if (!name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("length"))) return false;
6719 if (function_state()->outer() == NULL) {
6720 HInstruction* elements = Add<HArgumentsElements>(false);
6721 result = New<HArgumentsLength>(elements);
6723 // Number of arguments without receiver.
6724 int argument_count = environment()->
6725 arguments_environment()->parameter_count() - 1;
6726 result = New<HConstant>(argument_count);
6729 Push(graph()->GetArgumentsObject());
6730 CHECK_ALIVE_OR_RETURN(VisitForValue(expr->key()), true);
6731 HValue* key = Pop();
6732 Drop(1); // Arguments object.
6733 if (function_state()->outer() == NULL) {
6734 HInstruction* elements = Add<HArgumentsElements>(false);
6735 HInstruction* length = Add<HArgumentsLength>(elements);
6736 HInstruction* checked_key = Add<HBoundsCheck>(key, length);
6737 result = New<HAccessArgumentsAt>(elements, length, checked_key);
6739 EnsureArgumentsArePushedForAccess();
6741 // Number of arguments without receiver.
6742 HInstruction* elements = function_state()->arguments_elements();
6743 int argument_count = environment()->
6744 arguments_environment()->parameter_count() - 1;
6745 HInstruction* length = Add<HConstant>(argument_count);
6746 HInstruction* checked_key = Add<HBoundsCheck>(key, length);
6747 result = New<HAccessArgumentsAt>(elements, length, checked_key);
6750 ast_context()->ReturnInstruction(result, expr->id());
6755 HInstruction* HOptimizedGraphBuilder::BuildNamedAccess(
6756 PropertyAccessType access,
6758 BailoutId return_id,
6761 Handle<String> name,
6763 bool is_uninitialized) {
6764 SmallMapList* types;
6765 ComputeReceiverTypes(expr, object, &types, zone());
6766 ASSERT(types != NULL);
6768 if (types->length() > 0) {
6769 PropertyAccessInfo info(this, access, ToType(types->first()), name);
6770 if (!info.CanAccessAsMonomorphic(types)) {
6771 HandlePolymorphicNamedFieldAccess(
6772 access, ast_id, return_id, object, value, types, name);
6776 HValue* checked_object;
6777 // Type::Number() is only supported by polymorphic load/call handling.
6778 ASSERT(!info.type()->Is(Type::Number()));
6779 BuildCheckHeapObject(object);
6781 if (AreStringTypes(types)) {
6783 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING);
6784 } else if (AreFloat32x4Types(types) && CPU::SupportsSIMD128InCrankshaft()) {
6785 Handle<JSFunction> function(
6786 isolate()->native_context()->float32x4_function());
6787 HInstruction* constant_function = Add<HConstant>(function);
6788 HObjectAccess map_access = HObjectAccess::ForPrototypeOrInitialMap();
6789 HInstruction* map = Add<HLoadNamedField>(
6790 constant_function, static_cast<HValue*>(NULL), map_access);
6791 HObjectAccess prototype_access = HObjectAccess::ForMapPrototype();
6792 HInstruction* prototype = Add<HLoadNamedField>(
6793 map, static_cast<HValue*>(NULL), prototype_access);
6794 Handle<Map> initial_function_prototype_map(
6795 isolate()->native_context()->float32x4_function_prototype_map());
6796 BuildCheckMap(prototype, initial_function_prototype_map);
6797 BuiltinFunctionId id = NameToId(isolate(), name, FLOAT32x4_TYPE);
6798 return NewUncasted<HUnarySIMDOperation>(object, id);
6799 } else if (AreInt32x4Types(types) && CPU::SupportsSIMD128InCrankshaft()) {
6800 Handle<JSFunction> function(
6801 isolate()->native_context()->int32x4_function());
6802 HInstruction* constant_function = Add<HConstant>(function);
6803 HObjectAccess map_access = HObjectAccess::ForPrototypeOrInitialMap();
6804 HInstruction* map = Add<HLoadNamedField>(
6805 constant_function, static_cast<HValue*>(NULL), map_access);
6806 HObjectAccess prototype_access = HObjectAccess::ForMapPrototype();
6807 HInstruction* prototype = Add<HLoadNamedField>(
6808 map, static_cast<HValue*>(NULL), prototype_access);
6809 Handle<Map> initial_function_prototype_map(
6810 isolate()->native_context()->int32x4_function_prototype_map());
6811 BuildCheckMap(prototype, initial_function_prototype_map);
6812 BuiltinFunctionId id = NameToId(isolate(), name, INT32x4_TYPE);
6813 return NewUncasted<HUnarySIMDOperation>(object, id);
6815 checked_object = Add<HCheckMaps>(object, types);
6817 return BuildMonomorphicAccess(
6818 &info, object, checked_object, value, ast_id, return_id);
6821 return BuildNamedGeneric(access, object, name, value, is_uninitialized);
6825 void HOptimizedGraphBuilder::PushLoad(Property* expr,
6828 ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED);
6830 if (key != NULL) Push(key);
6831 BuildLoad(expr, expr->LoadId());
6835 void HOptimizedGraphBuilder::BuildLoad(Property* expr,
6837 HInstruction* instr = NULL;
6838 if (expr->IsStringAccess()) {
6839 HValue* index = Pop();
6840 HValue* string = Pop();
6841 HInstruction* char_code = BuildStringCharCodeAt(string, index);
6842 AddInstruction(char_code);
6843 instr = NewUncasted<HStringCharFromCode>(char_code);
6845 } else if (expr->IsFunctionPrototype()) {
6846 HValue* function = Pop();
6847 BuildCheckHeapObject(function);
6848 instr = New<HLoadFunctionPrototype>(function);
6850 } else if (expr->key()->IsPropertyName()) {
6851 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
6852 HValue* object = Pop();
6854 instr = BuildNamedAccess(LOAD, ast_id, expr->LoadId(), expr,
6855 object, name, NULL, expr->IsUninitialized());
6856 if (instr == NULL) return;
6857 if (instr->IsLinked()) return ast_context()->ReturnValue(instr);
6860 HValue* key = Pop();
6861 HValue* obj = Pop();
6863 bool has_side_effects = false;
6864 HValue* load = HandleKeyedElementAccess(
6865 obj, key, NULL, expr, LOAD, &has_side_effects);
6866 if (has_side_effects) {
6867 if (ast_context()->IsEffect()) {
6868 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6871 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
6875 return ast_context()->ReturnValue(load);
6877 return ast_context()->ReturnInstruction(instr, ast_id);
6881 void HOptimizedGraphBuilder::VisitProperty(Property* expr) {
6882 ASSERT(!HasStackOverflow());
6883 ASSERT(current_block() != NULL);
6884 ASSERT(current_block()->HasPredecessor());
6886 if (TryArgumentsAccess(expr)) return;
6888 CHECK_ALIVE(VisitForValue(expr->obj()));
6889 if ((!expr->IsFunctionPrototype() && !expr->key()->IsPropertyName()) ||
6890 expr->IsStringAccess()) {
6891 CHECK_ALIVE(VisitForValue(expr->key()));
6894 BuildLoad(expr, expr->id());
6898 HInstruction* HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant,
6899 CompilationInfo* info) {
6900 HConstant* constant_value = New<HConstant>(constant);
6902 if (constant->map()->CanOmitMapChecks()) {
6903 constant->map()->AddDependentCompilationInfo(
6904 DependentCode::kPrototypeCheckGroup, info);
6905 return constant_value;
6908 AddInstruction(constant_value);
6910 Add<HCheckMaps>(constant_value, handle(constant->map()), info);
6911 check->ClearDependsOnFlag(kElementsKind);
6916 HInstruction* HGraphBuilder::BuildCheckPrototypeMaps(Handle<JSObject> prototype,
6917 Handle<JSObject> holder) {
6918 while (!prototype.is_identical_to(holder)) {
6919 BuildConstantMapCheck(prototype, top_info());
6920 prototype = handle(JSObject::cast(prototype->GetPrototype()));
6923 HInstruction* checked_object = BuildConstantMapCheck(prototype, top_info());
6924 if (!checked_object->IsLinked()) AddInstruction(checked_object);
6925 return checked_object;
6929 void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder,
6930 Handle<Map> receiver_map) {
6931 if (!holder.is_null()) {
6932 Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype()));
6933 BuildCheckPrototypeMaps(prototype, holder);
6938 HInstruction* HOptimizedGraphBuilder::NewPlainFunctionCall(
6939 HValue* fun, int argument_count, bool pass_argument_count) {
6940 return New<HCallJSFunction>(
6941 fun, argument_count, pass_argument_count);
6945 HInstruction* HOptimizedGraphBuilder::NewArgumentAdaptorCall(
6946 HValue* fun, HValue* context,
6947 int argument_count, HValue* expected_param_count) {
6948 CallInterfaceDescriptor* descriptor =
6949 isolate()->call_descriptor(Isolate::ArgumentAdaptorCall);
6951 HValue* arity = Add<HConstant>(argument_count - 1);
6953 HValue* op_vals[] = { fun, context, arity, expected_param_count };
6955 Handle<Code> adaptor =
6956 isolate()->builtins()->ArgumentsAdaptorTrampoline();
6957 HConstant* adaptor_value = Add<HConstant>(adaptor);
6959 return New<HCallWithDescriptor>(
6960 adaptor_value, argument_count, descriptor,
6961 Vector<HValue*>(op_vals, descriptor->environment_length()));
6965 HInstruction* HOptimizedGraphBuilder::BuildCallConstantFunction(
6966 Handle<JSFunction> jsfun, int argument_count) {
6967 HValue* target = Add<HConstant>(jsfun);
6968 // For constant functions, we try to avoid calling the
6969 // argument adaptor and instead call the function directly
6970 int formal_parameter_count = jsfun->shared()->formal_parameter_count();
6971 bool dont_adapt_arguments =
6972 (formal_parameter_count ==
6973 SharedFunctionInfo::kDontAdaptArgumentsSentinel);
6974 int arity = argument_count - 1;
6975 bool can_invoke_directly =
6976 dont_adapt_arguments || formal_parameter_count == arity;
6977 if (can_invoke_directly) {
6978 if (jsfun.is_identical_to(current_info()->closure())) {
6979 graph()->MarkRecursive();
6981 return NewPlainFunctionCall(target, argument_count, dont_adapt_arguments);
6983 HValue* param_count_value = Add<HConstant>(formal_parameter_count);
6984 HValue* context = Add<HLoadNamedField>(
6985 target, static_cast<HValue*>(NULL),
6986 HObjectAccess::ForFunctionContextPointer());
6987 return NewArgumentAdaptorCall(target, context,
6988 argument_count, param_count_value);
6995 void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
6998 SmallMapList* types,
6999 Handle<String> name) {
7000 int argument_count = expr->arguments()->length() + 1; // Includes receiver.
7001 int order[kMaxCallPolymorphism];
7003 bool handle_smi = false;
7004 bool handled_string = false;
7005 int ordered_functions = 0;
7008 i < types->length() && ordered_functions < kMaxCallPolymorphism;
7010 PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name);
7011 if (info.CanAccessMonomorphic() &&
7012 info.lookup()->IsConstant() &&
7013 info.constant()->IsJSFunction()) {
7014 if (info.type()->Is(Type::String())) {
7015 if (handled_string) continue;
7016 handled_string = true;
7018 Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant());
7019 if (info.type()->Is(Type::Number())) {
7022 expr->set_target(target);
7023 order[ordered_functions++] = i;
7027 HBasicBlock* number_block = NULL;
7028 HBasicBlock* join = NULL;
7029 handled_string = false;
7032 for (int fn = 0; fn < ordered_functions; ++fn) {
7034 PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name);
7035 if (info.type()->Is(Type::String())) {
7036 if (handled_string) continue;
7037 handled_string = true;
7039 // Reloads the target.
7040 info.CanAccessMonomorphic();
7041 Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant());
7043 expr->set_target(target);
7045 // Only needed once.
7046 join = graph()->CreateBasicBlock();
7048 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock();
7049 HBasicBlock* not_smi_block = graph()->CreateBasicBlock();
7050 number_block = graph()->CreateBasicBlock();
7051 FinishCurrentBlock(New<HIsSmiAndBranch>(
7052 receiver, empty_smi_block, not_smi_block));
7053 GotoNoSimulate(empty_smi_block, number_block);
7054 set_current_block(not_smi_block);
7056 BuildCheckHeapObject(receiver);
7060 HBasicBlock* if_true = graph()->CreateBasicBlock();
7061 HBasicBlock* if_false = graph()->CreateBasicBlock();
7062 HUnaryControlInstruction* compare;
7064 Handle<Map> map = info.map();
7065 if (info.type()->Is(Type::Number())) {
7066 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map();
7067 compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false);
7068 } else if (info.type()->Is(Type::String())) {
7069 compare = New<HIsStringAndBranch>(receiver, if_true, if_false);
7071 compare = New<HCompareMap>(receiver, map, if_true, if_false);
7073 FinishCurrentBlock(compare);
7075 if (info.type()->Is(Type::Number())) {
7076 GotoNoSimulate(if_true, number_block);
7077 if_true = number_block;
7080 set_current_block(if_true);
7082 AddCheckPrototypeMaps(info.holder(), map);
7084 HValue* function = Add<HConstant>(expr->target());
7085 environment()->SetExpressionStackAt(0, function);
7087 CHECK_ALIVE(VisitExpressions(expr->arguments()));
7088 bool needs_wrapping = NeedsWrappingFor(info.type(), target);
7089 bool try_inline = FLAG_polymorphic_inlining && !needs_wrapping;
7090 if (FLAG_trace_inlining && try_inline) {
7091 Handle<JSFunction> caller = current_info()->closure();
7092 SmartArrayPointer<char> caller_name =
7093 caller->shared()->DebugName()->ToCString();
7094 PrintF("Trying to inline the polymorphic call to %s from %s\n",
7095 name->ToCString().get(),
7098 if (try_inline && TryInlineCall(expr)) {
7099 // Trying to inline will signal that we should bailout from the
7100 // entire compilation by setting stack overflow on the visitor.
7101 if (HasStackOverflow()) return;
7103 // Since HWrapReceiver currently cannot actually wrap numbers and strings,
7104 // use the regular CallFunctionStub for method calls to wrap the receiver.
7105 // TODO(verwaest): Support creation of value wrappers directly in
7107 HInstruction* call = needs_wrapping
7108 ? NewUncasted<HCallFunction>(
7109 function, argument_count, WRAP_AND_CALL)
7110 : BuildCallConstantFunction(target, argument_count);
7111 PushArgumentsFromEnvironment(argument_count);
7112 AddInstruction(call);
7113 Drop(1); // Drop the function.
7114 if (!ast_context()->IsEffect()) Push(call);
7117 if (current_block() != NULL) Goto(join);
7118 set_current_block(if_false);
7121 // Finish up. Unconditionally deoptimize if we've handled all the maps we
7122 // know about and do not want to handle ones we've never seen. Otherwise
7123 // use a generic IC.
7124 if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) {
7125 FinishExitWithHardDeoptimization("Unknown map in polymorphic call");
7127 Property* prop = expr->expression()->AsProperty();
7128 HInstruction* function = BuildNamedGeneric(
7129 LOAD, receiver, name, NULL, prop->IsUninitialized());
7130 AddInstruction(function);
7132 AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE);
7134 environment()->SetExpressionStackAt(1, function);
7135 environment()->SetExpressionStackAt(0, receiver);
7136 CHECK_ALIVE(VisitExpressions(expr->arguments()));
7138 CallFunctionFlags flags = receiver->type().IsJSObject()
7139 ? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD;
7140 HInstruction* call = New<HCallFunction>(
7141 function, argument_count, flags);
7143 PushArgumentsFromEnvironment(argument_count);
7145 Drop(1); // Function.
7148 AddInstruction(call);
7149 if (!ast_context()->IsEffect()) Push(call);
7152 return ast_context()->ReturnInstruction(call, expr->id());
7156 // We assume that control flow is always live after an expression. So
7157 // even without predecessors to the join block, we set it as the exit
7158 // block and continue by adding instructions there.
7159 ASSERT(join != NULL);
7160 if (join->HasPredecessor()) {
7161 set_current_block(join);
7162 join->SetJoinId(expr->id());
7163 if (!ast_context()->IsEffect()) return ast_context()->ReturnValue(Pop());
7165 set_current_block(NULL);
7170 void HOptimizedGraphBuilder::TraceInline(Handle<JSFunction> target,
7171 Handle<JSFunction> caller,
7172 const char* reason) {
7173 if (FLAG_trace_inlining) {
7174 SmartArrayPointer<char> target_name =
7175 target->shared()->DebugName()->ToCString();
7176 SmartArrayPointer<char> caller_name =
7177 caller->shared()->DebugName()->ToCString();
7178 if (reason == NULL) {
7179 PrintF("Inlined %s called from %s.\n", target_name.get(),
7182 PrintF("Did not inline %s called from %s (%s).\n",
7183 target_name.get(), caller_name.get(), reason);
7189 static const int kNotInlinable = 1000000000;
7192 int HOptimizedGraphBuilder::InliningAstSize(Handle<JSFunction> target) {
7193 if (!FLAG_use_inlining) return kNotInlinable;
7195 // Precondition: call is monomorphic and we have found a target with the
7196 // appropriate arity.
7197 Handle<JSFunction> caller = current_info()->closure();
7198 Handle<SharedFunctionInfo> target_shared(target->shared());
7200 // Always inline builtins marked for inlining.
7201 if (target->IsBuiltin()) {
7202 return target_shared->inline_builtin() ? 0 : kNotInlinable;
7205 // Do a quick check on source code length to avoid parsing large
7206 // inlining candidates.
7207 if (target_shared->SourceSize() >
7208 Min(FLAG_max_inlined_source_size, kUnlimitedMaxInlinedSourceSize)) {
7209 TraceInline(target, caller, "target text too big");
7210 return kNotInlinable;
7213 // Target must be inlineable.
7214 if (!target_shared->IsInlineable()) {
7215 TraceInline(target, caller, "target not inlineable");
7216 return kNotInlinable;
7218 if (target_shared->dont_inline() || target_shared->dont_optimize()) {
7219 TraceInline(target, caller, "target contains unsupported syntax [early]");
7220 return kNotInlinable;
7223 int nodes_added = target_shared->ast_node_count();
7228 bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target,
7229 int arguments_count,
7230 HValue* implicit_return_value,
7232 BailoutId return_id,
7233 InliningKind inlining_kind,
7234 HSourcePosition position) {
7235 int nodes_added = InliningAstSize(target);
7236 if (nodes_added == kNotInlinable) return false;
7238 Handle<JSFunction> caller = current_info()->closure();
7240 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) {
7241 TraceInline(target, caller, "target AST is too large [early]");
7245 // Don't inline deeper than the maximum number of inlining levels.
7246 HEnvironment* env = environment();
7247 int current_level = 1;
7248 while (env->outer() != NULL) {
7249 if (current_level == FLAG_max_inlining_levels) {
7250 TraceInline(target, caller, "inline depth limit reached");
7253 if (env->outer()->frame_type() == JS_FUNCTION) {
7259 // Don't inline recursive functions.
7260 for (FunctionState* state = function_state();
7262 state = state->outer()) {
7263 if (*state->compilation_info()->closure() == *target) {
7264 TraceInline(target, caller, "target is recursive");
7269 // We don't want to add more than a certain number of nodes from inlining.
7270 if (inlined_count_ > Min(FLAG_max_inlined_nodes_cumulative,
7271 kUnlimitedMaxInlinedNodesCumulative)) {
7272 TraceInline(target, caller, "cumulative AST node limit reached");
7276 // Parse and allocate variables.
7277 CompilationInfo target_info(target, zone());
7278 Handle<SharedFunctionInfo> target_shared(target->shared());
7279 if (!Parser::Parse(&target_info) || !Scope::Analyze(&target_info)) {
7280 if (target_info.isolate()->has_pending_exception()) {
7281 // Parse or scope error, never optimize this function.
7283 target_shared->DisableOptimization(kParseScopeError);
7285 TraceInline(target, caller, "parse failure");
7289 if (target_info.scope()->num_heap_slots() > 0) {
7290 TraceInline(target, caller, "target has context-allocated variables");
7293 FunctionLiteral* function = target_info.function();
7295 // The following conditions must be checked again after re-parsing, because
7296 // earlier the information might not have been complete due to lazy parsing.
7297 nodes_added = function->ast_node_count();
7298 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) {
7299 TraceInline(target, caller, "target AST is too large [late]");
7302 AstProperties::Flags* flags(function->flags());
7303 if (flags->Contains(kDontInline) || function->dont_optimize()) {
7304 TraceInline(target, caller, "target contains unsupported syntax [late]");
7308 // If the function uses the arguments object check that inlining of functions
7309 // with arguments object is enabled and the arguments-variable is
7311 if (function->scope()->arguments() != NULL) {
7312 if (!FLAG_inline_arguments) {
7313 TraceInline(target, caller, "target uses arguments object");
7317 if (!function->scope()->arguments()->IsStackAllocated()) {
7320 "target uses non-stackallocated arguments object");
7325 // All declarations must be inlineable.
7326 ZoneList<Declaration*>* decls = target_info.scope()->declarations();
7327 int decl_count = decls->length();
7328 for (int i = 0; i < decl_count; ++i) {
7329 if (!decls->at(i)->IsInlineable()) {
7330 TraceInline(target, caller, "target has non-trivial declaration");
7335 // Generate the deoptimization data for the unoptimized version of
7336 // the target function if we don't already have it.
7337 if (!target_shared->has_deoptimization_support()) {
7338 // Note that we compile here using the same AST that we will use for
7339 // generating the optimized inline code.
7340 target_info.EnableDeoptimizationSupport();
7341 if (!FullCodeGenerator::MakeCode(&target_info)) {
7342 TraceInline(target, caller, "could not generate deoptimization info");
7345 if (target_shared->scope_info() == ScopeInfo::Empty(isolate())) {
7346 // The scope info might not have been set if a lazily compiled
7347 // function is inlined before being called for the first time.
7348 Handle<ScopeInfo> target_scope_info =
7349 ScopeInfo::Create(target_info.scope(), zone());
7350 target_shared->set_scope_info(*target_scope_info);
7352 target_shared->EnableDeoptimizationSupport(*target_info.code());
7353 Compiler::RecordFunctionCompilation(Logger::FUNCTION_TAG,
7358 // ----------------------------------------------------------------
7359 // After this point, we've made a decision to inline this function (so
7360 // TryInline should always return true).
7362 // Type-check the inlined function.
7363 ASSERT(target_shared->has_deoptimization_support());
7364 AstTyper::Run(&target_info);
7366 int function_id = graph()->TraceInlinedFunction(target_shared, position);
7368 // Save the pending call context. Set up new one for the inlined function.
7369 // The function state is new-allocated because we need to delete it
7370 // in two different places.
7371 FunctionState* target_state = new FunctionState(
7372 this, &target_info, inlining_kind, function_id);
7374 HConstant* undefined = graph()->GetConstantUndefined();
7376 HEnvironment* inner_env =
7377 environment()->CopyForInlining(target,
7381 function_state()->inlining_kind());
7383 HConstant* context = Add<HConstant>(Handle<Context>(target->context()));
7384 inner_env->BindContext(context);
7386 Add<HSimulate>(return_id);
7387 current_block()->UpdateEnvironment(inner_env);
7388 HArgumentsObject* arguments_object = NULL;
7390 // If the function uses arguments object create and bind one, also copy
7391 // current arguments values to use them for materialization.
7392 if (function->scope()->arguments() != NULL) {
7393 ASSERT(function->scope()->arguments()->IsStackAllocated());
7394 HEnvironment* arguments_env = inner_env->arguments_environment();
7395 int arguments_count = arguments_env->parameter_count();
7396 arguments_object = Add<HArgumentsObject>(arguments_count);
7397 inner_env->Bind(function->scope()->arguments(), arguments_object);
7398 for (int i = 0; i < arguments_count; i++) {
7399 arguments_object->AddArgument(arguments_env->Lookup(i), zone());
7403 HEnterInlined* enter_inlined =
7404 Add<HEnterInlined>(target, arguments_count, function,
7405 function_state()->inlining_kind(),
7406 function->scope()->arguments(),
7408 function_state()->set_entry(enter_inlined);
7410 VisitDeclarations(target_info.scope()->declarations());
7411 VisitStatements(function->body());
7412 if (HasStackOverflow()) {
7413 // Bail out if the inline function did, as we cannot residualize a call
7415 TraceInline(target, caller, "inline graph construction failed");
7416 target_shared->DisableOptimization(kInliningBailedOut);
7417 inline_bailout_ = true;
7418 delete target_state;
7422 // Update inlined nodes count.
7423 inlined_count_ += nodes_added;
7425 Handle<Code> unoptimized_code(target_shared->code());
7426 ASSERT(unoptimized_code->kind() == Code::FUNCTION);
7427 Handle<TypeFeedbackInfo> type_info(
7428 TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info()));
7429 graph()->update_type_change_checksum(type_info->own_type_change_checksum());
7431 TraceInline(target, caller, NULL);
7433 if (current_block() != NULL) {
7434 FunctionState* state = function_state();
7435 if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) {
7436 // Falling off the end of an inlined construct call. In a test context the
7437 // return value will always evaluate to true, in a value context the
7438 // return value is the newly allocated receiver.
7439 if (call_context()->IsTest()) {
7440 Goto(inlined_test_context()->if_true(), state);
7441 } else if (call_context()->IsEffect()) {
7442 Goto(function_return(), state);
7444 ASSERT(call_context()->IsValue());
7445 AddLeaveInlined(implicit_return_value, state);
7447 } else if (state->inlining_kind() == SETTER_CALL_RETURN) {
7448 // Falling off the end of an inlined setter call. The returned value is
7449 // never used, the value of an assignment is always the value of the RHS
7450 // of the assignment.
7451 if (call_context()->IsTest()) {
7452 inlined_test_context()->ReturnValue(implicit_return_value);
7453 } else if (call_context()->IsEffect()) {
7454 Goto(function_return(), state);
7456 ASSERT(call_context()->IsValue());
7457 AddLeaveInlined(implicit_return_value, state);
7460 // Falling off the end of a normal inlined function. This basically means
7461 // returning undefined.
7462 if (call_context()->IsTest()) {
7463 Goto(inlined_test_context()->if_false(), state);
7464 } else if (call_context()->IsEffect()) {
7465 Goto(function_return(), state);
7467 ASSERT(call_context()->IsValue());
7468 AddLeaveInlined(undefined, state);
7473 // Fix up the function exits.
7474 if (inlined_test_context() != NULL) {
7475 HBasicBlock* if_true = inlined_test_context()->if_true();
7476 HBasicBlock* if_false = inlined_test_context()->if_false();
7478 HEnterInlined* entry = function_state()->entry();
7480 // Pop the return test context from the expression context stack.
7481 ASSERT(ast_context() == inlined_test_context());
7482 ClearInlinedTestContext();
7483 delete target_state;
7485 // Forward to the real test context.
7486 if (if_true->HasPredecessor()) {
7487 entry->RegisterReturnTarget(if_true, zone());
7488 if_true->SetJoinId(ast_id);
7489 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true();
7490 Goto(if_true, true_target, function_state());
7492 if (if_false->HasPredecessor()) {
7493 entry->RegisterReturnTarget(if_false, zone());
7494 if_false->SetJoinId(ast_id);
7495 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false();
7496 Goto(if_false, false_target, function_state());
7498 set_current_block(NULL);
7501 } else if (function_return()->HasPredecessor()) {
7502 function_state()->entry()->RegisterReturnTarget(function_return(), zone());
7503 function_return()->SetJoinId(ast_id);
7504 set_current_block(function_return());
7506 set_current_block(NULL);
7508 delete target_state;
7513 bool HOptimizedGraphBuilder::TryInlineCall(Call* expr) {
7514 return TryInline(expr->target(),
7515 expr->arguments()->length(),
7520 ScriptPositionToSourcePosition(expr->position()));
7524 bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr,
7525 HValue* implicit_return_value) {
7526 return TryInline(expr->target(),
7527 expr->arguments()->length(),
7528 implicit_return_value,
7531 CONSTRUCT_CALL_RETURN,
7532 ScriptPositionToSourcePosition(expr->position()));
7536 bool HOptimizedGraphBuilder::TryInlineGetter(Handle<JSFunction> getter,
7537 Handle<Map> receiver_map,
7539 BailoutId return_id) {
7540 if (TryInlineApiGetter(getter, receiver_map, ast_id)) return true;
7541 return TryInline(getter,
7551 bool HOptimizedGraphBuilder::TryInlineSetter(Handle<JSFunction> setter,
7552 Handle<Map> receiver_map,
7554 BailoutId assignment_id,
7555 HValue* implicit_return_value) {
7556 if (TryInlineApiSetter(setter, receiver_map, id)) return true;
7557 return TryInline(setter,
7559 implicit_return_value,
7566 bool HOptimizedGraphBuilder::TryInlineApply(Handle<JSFunction> function,
7568 int arguments_count) {
7569 return TryInline(function,
7575 ScriptPositionToSourcePosition(expr->position()));
7579 bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) {
7580 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false;
7581 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
7584 if (!FLAG_fast_math) break;
7585 // Fall through if FLAG_fast_math.
7592 if (expr->arguments()->length() == 1) {
7593 HValue* argument = Pop();
7594 Drop(2); // Receiver and function.
7595 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id);
7596 ast_context()->ReturnInstruction(op, expr->id());
7601 if (expr->arguments()->length() == 2) {
7602 HValue* right = Pop();
7603 HValue* left = Pop();
7604 Drop(2); // Receiver and function.
7605 HInstruction* op = HMul::NewImul(zone(), context(), left, right);
7606 ast_context()->ReturnInstruction(op, expr->id());
7610 #define SIMD_NULLARY_OPERATION_CASE_ITEM(p1, p2, name, p4) \
7612 SIMD_NULLARY_OPERATIONS(SIMD_NULLARY_OPERATION_CASE_ITEM)
7613 #undef SIMD_NULLARY_OPERATION_CASE_ITEM
7614 if (CPU::SupportsSIMD128InCrankshaft() &&
7615 expr->arguments()->length() == 0) {
7616 Drop(2); // Receiver and function.
7617 HInstruction* op = NewUncasted<HNullarySIMDOperation>(id);
7618 ast_context()->ReturnInstruction(op, expr->id());
7622 #define SIMD_UNARY_OPERATION_CASE_ITEM(p1, p2, name, p4, p5) \
7624 SIMD_UNARY_OPERATIONS(SIMD_UNARY_OPERATION_CASE_ITEM)
7625 #undef SIMD_UNARY_OPERATION_CASE_ITEM
7626 if (CPU::SupportsSIMD128InCrankshaft() &&
7627 expr->arguments()->length() == 1) {
7628 HValue* argument = Pop();
7629 Drop(2); // Receiver and function.
7630 HInstruction* op = NewUncasted<HUnarySIMDOperation>(argument, id);
7631 ast_context()->ReturnInstruction(op, expr->id());
7635 #define SIMD_BINARY_OPERATION_CASE_ITEM(p1, p2, name, p4, p5, p6) \
7637 SIMD_BINARY_OPERATIONS(SIMD_BINARY_OPERATION_CASE_ITEM)
7638 #undef SIMD_BINARY_OPERATION_CASE_ITEM
7639 if (CPU::SupportsSIMD128InCrankshaft() &&
7640 expr->arguments()->length() == 2) {
7641 HValue* right = Pop();
7642 HValue* left = Pop();
7643 Drop(2); // Receiver and function.
7644 HInstruction* op = NewUncasted<HBinarySIMDOperation>(left, right, id);
7645 ast_context()->ReturnInstruction(op, expr->id());
7649 #define SIMD_TERNARY_OPERATION_CASE_ITEM(p1, p2, name, p4, p5, p6, p7) \
7651 SIMD_TERNARY_OPERATIONS(SIMD_TERNARY_OPERATION_CASE_ITEM)
7652 #undef SIMD_TERNARY_OPERATION_CASE_ITEM
7653 if (CPU::SupportsSIMD128InCrankshaft() &&
7654 expr->arguments()->length() == 3) {
7655 HValue* right = Pop();
7656 HValue* left = Pop();
7657 HValue* value = Pop();
7658 Drop(2); // Receiver and function.
7660 NewUncasted<HTernarySIMDOperation>(value, left, right, id);
7661 ast_context()->ReturnInstruction(op, expr->id());
7665 #define SIMD_QUARTERNARY_OPERATION_CASE_ITEM(p1, p2, name, p4, p5, p6, p7, p8) \
7667 SIMD_QUARTERNARY_OPERATIONS(SIMD_QUARTERNARY_OPERATION_CASE_ITEM)
7668 #undef SIMD_QUARTERNARY_OPERATION_CASE_ITEM
7669 if (CPU::SupportsSIMD128InCrankshaft() &&
7670 expr->arguments()->length() == 4) {
7675 Drop(2); // Receiver and function.
7677 NewUncasted<HQuarternarySIMDOperation>(x, y, z, w, id);
7678 ast_context()->ReturnInstruction(op, expr->id());
7683 // Not supported for inlining yet.
7690 bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
7693 Handle<Map> receiver_map) {
7694 // Try to inline calls like Math.* as operations in the calling function.
7695 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false;
7696 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
7697 int argument_count = expr->arguments()->length() + 1; // Plus receiver.
7699 case kStringCharCodeAt:
7701 if (argument_count == 2) {
7702 HValue* index = Pop();
7703 HValue* string = Pop();
7704 Drop(1); // Function.
7705 HInstruction* char_code =
7706 BuildStringCharCodeAt(string, index);
7707 if (id == kStringCharCodeAt) {
7708 ast_context()->ReturnInstruction(char_code, expr->id());
7711 AddInstruction(char_code);
7712 HInstruction* result = NewUncasted<HStringCharFromCode>(char_code);
7713 ast_context()->ReturnInstruction(result, expr->id());
7717 case kStringFromCharCode:
7718 if (argument_count == 2) {
7719 HValue* argument = Pop();
7720 Drop(2); // Receiver and function.
7721 HInstruction* result = NewUncasted<HStringCharFromCode>(argument);
7722 ast_context()->ReturnInstruction(result, expr->id());
7727 if (!FLAG_fast_math) break;
7728 // Fall through if FLAG_fast_math.
7735 if (argument_count == 2) {
7736 HValue* argument = Pop();
7737 Drop(2); // Receiver and function.
7738 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id);
7739 ast_context()->ReturnInstruction(op, expr->id());
7744 if (argument_count == 3) {
7745 HValue* right = Pop();
7746 HValue* left = Pop();
7747 Drop(2); // Receiver and function.
7748 HInstruction* result = NULL;
7749 // Use sqrt() if exponent is 0.5 or -0.5.
7750 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) {
7751 double exponent = HConstant::cast(right)->DoubleValue();
7752 if (exponent == 0.5) {
7753 result = NewUncasted<HUnaryMathOperation>(left, kMathPowHalf);
7754 } else if (exponent == -0.5) {
7755 HValue* one = graph()->GetConstant1();
7756 HInstruction* sqrt = AddUncasted<HUnaryMathOperation>(
7757 left, kMathPowHalf);
7758 // MathPowHalf doesn't have side effects so there's no need for
7759 // an environment simulation here.
7760 ASSERT(!sqrt->HasObservableSideEffects());
7761 result = NewUncasted<HDiv>(one, sqrt);
7762 } else if (exponent == 2.0) {
7763 result = NewUncasted<HMul>(left, left);
7767 if (result == NULL) {
7768 result = NewUncasted<HPower>(left, right);
7770 ast_context()->ReturnInstruction(result, expr->id());
7776 if (argument_count == 3) {
7777 HValue* right = Pop();
7778 HValue* left = Pop();
7779 Drop(2); // Receiver and function.
7780 HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin
7781 : HMathMinMax::kMathMax;
7782 HInstruction* result = NewUncasted<HMathMinMax>(left, right, op);
7783 ast_context()->ReturnInstruction(result, expr->id());
7788 if (argument_count == 3) {
7789 HValue* right = Pop();
7790 HValue* left = Pop();
7791 Drop(2); // Receiver and function.
7792 HInstruction* result = HMul::NewImul(zone(), context(), left, right);
7793 ast_context()->ReturnInstruction(result, expr->id());
7798 if (receiver_map.is_null()) return false;
7799 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false;
7800 ElementsKind elements_kind = receiver_map->elements_kind();
7801 if (!IsFastElementsKind(elements_kind)) return false;
7803 Drop(expr->arguments()->length());
7805 HValue* reduced_length;
7806 HValue* receiver = Pop();
7808 HValue* checked_object = AddCheckMap(receiver, receiver_map);
7809 HValue* length = Add<HLoadNamedField>(
7810 checked_object, static_cast<HValue*>(NULL),
7811 HObjectAccess::ForArrayLength(elements_kind));
7813 Drop(1); // Function.
7815 { NoObservableSideEffectsScope scope(this);
7816 IfBuilder length_checker(this);
7818 HValue* bounds_check = length_checker.If<HCompareNumericAndBranch>(
7819 length, graph()->GetConstant0(), Token::EQ);
7820 length_checker.Then();
7822 if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined());
7824 length_checker.Else();
7825 HValue* elements = AddLoadElements(checked_object);
7826 // Ensure that we aren't popping from a copy-on-write array.
7827 if (IsFastSmiOrObjectElementsKind(elements_kind)) {
7828 elements = BuildCopyElementsOnWrite(checked_object, elements,
7829 elements_kind, length);
7831 reduced_length = AddUncasted<HSub>(length, graph()->GetConstant1());
7832 result = AddElementAccess(elements, reduced_length, NULL,
7833 bounds_check, elements_kind, LOAD);
7834 Factory* factory = isolate()->factory();
7835 double nan_double = FixedDoubleArray::hole_nan_as_double();
7836 HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind)
7837 ? Add<HConstant>(factory->the_hole_value())
7838 : Add<HConstant>(nan_double);
7839 if (IsFastSmiOrObjectElementsKind(elements_kind)) {
7840 elements_kind = FAST_HOLEY_ELEMENTS;
7843 elements, reduced_length, hole, bounds_check, elements_kind, STORE);
7844 Add<HStoreNamedField>(
7845 checked_object, HObjectAccess::ForArrayLength(elements_kind),
7846 reduced_length, STORE_TO_INITIALIZED_ENTRY);
7848 if (!ast_context()->IsEffect()) Push(result);
7850 length_checker.End();
7852 result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top();
7853 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
7854 if (!ast_context()->IsEffect()) Drop(1);
7856 ast_context()->ReturnValue(result);
7860 if (receiver_map.is_null()) return false;
7861 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false;
7862 ElementsKind elements_kind = receiver_map->elements_kind();
7863 if (!IsFastElementsKind(elements_kind)) return false;
7865 HValue* op_vals[] = {
7868 environment()->ExpressionStackAt(expr->arguments()->length())
7871 const int argc = expr->arguments()->length();
7872 // Includes receiver.
7873 PushArgumentsFromEnvironment(argc + 1);
7875 CallInterfaceDescriptor* descriptor =
7876 isolate()->call_descriptor(Isolate::CallHandler);
7878 ArrayPushStub stub(receiver_map->elements_kind(), argc);
7879 Handle<Code> code = stub.GetCode(isolate());
7880 HConstant* code_value = Add<HConstant>(code);
7882 ASSERT((sizeof(op_vals) / kPointerSize) ==
7883 descriptor->environment_length());
7885 HInstruction* call = New<HCallWithDescriptor>(
7886 code_value, argc + 1, descriptor,
7887 Vector<HValue*>(op_vals, descriptor->environment_length()));
7888 Drop(1); // Drop function.
7889 ast_context()->ReturnInstruction(call, expr->id());
7892 #define SIMD_NULLARY_OPERATION_CASE_ITEM(p1, p2, name, p4) \
7894 SIMD_NULLARY_OPERATIONS(SIMD_NULLARY_OPERATION_CASE_ITEM)
7895 #undef SIMD_NULLARY_OPERATION_CASE_ITEM
7896 if (CPU::SupportsSIMD128InCrankshaft() && argument_count == 1) {
7897 Drop(2); // Receiver and function.
7898 HInstruction* op = NewUncasted<HNullarySIMDOperation>(id);
7899 ast_context()->ReturnInstruction(op, expr->id());
7903 #define SIMD_UNARY_OPERATION_CASE_ITEM(p1, p2, name, p4, p5) \
7905 SIMD_UNARY_OPERATIONS(SIMD_UNARY_OPERATION_CASE_ITEM)
7906 #undef SIMD_UNARY_OPERATION_CASE_ITEM
7907 if (CPU::SupportsSIMD128InCrankshaft() && argument_count == 2) {
7908 HValue* argument = Pop();
7909 Drop(2); // Receiver and function.
7910 HInstruction* op = NewUncasted<HUnarySIMDOperation>(argument, id);
7911 ast_context()->ReturnInstruction(op, expr->id());
7915 #define SIMD_BINARY_OPERATION_CASE_ITEM(p1, p2, name, p4, p5, p6) \
7917 SIMD_BINARY_OPERATIONS(SIMD_BINARY_OPERATION_CASE_ITEM)
7918 #undef SIMD_BINARY_OPERATION_CASE_ITEM
7919 if (CPU::SupportsSIMD128InCrankshaft() && argument_count == 3) {
7920 HValue* right = Pop();
7921 HValue* left = Pop();
7922 Drop(2); // Receiver and function.
7923 HInstruction* op = NewUncasted<HBinarySIMDOperation>(left, right, id);
7924 ast_context()->ReturnInstruction(op, expr->id());
7928 #define SIMD_TERNARY_OPERATION_CASE_ITEM(p1, p2, name, p4, p5, p6, p7) \
7930 SIMD_TERNARY_OPERATIONS(SIMD_TERNARY_OPERATION_CASE_ITEM)
7931 #undef SIMD_TERNARY_OPERATION_CASE_ITEM
7932 if (CPU::SupportsSIMD128InCrankshaft() && argument_count == 4) {
7933 HValue* right = Pop();
7934 HValue* left = Pop();
7935 HValue* value = Pop();
7936 Drop(2); // Receiver and function.
7938 NewUncasted<HTernarySIMDOperation>(value, left, right, id);
7939 ast_context()->ReturnInstruction(op, expr->id());
7943 #define SIMD_QUARTERNARY_OPERATION_CASE_ITEM(p1, p2, name, p4, p5, p6, p7, p8) \
7945 SIMD_QUARTERNARY_OPERATIONS(SIMD_QUARTERNARY_OPERATION_CASE_ITEM)
7946 #undef SIMD_QUARTERNARY_OPERATION_CASE_ITEM
7947 if (CPU::SupportsSIMD128InCrankshaft() && argument_count == 5) {
7952 Drop(2); // Receiver and function.
7953 HValue* context = environment()->context();
7955 HQuarternarySIMDOperation::New(zone(), context, x, y, z, w, id);
7956 ast_context()->ReturnInstruction(op, expr->id());
7960 case kFloat32x4ArrayGetAt:
7961 case kInt32x4ArrayGetAt:
7962 if (CPU::SupportsSIMD128InCrankshaft() && argument_count == 2) {
7963 HValue* key = Pop();
7964 HValue* typed32x4_array = Pop();
7965 ASSERT(typed32x4_array == receiver);
7966 Drop(1); // Drop function.
7967 HInstruction* instr = BuildUncheckedMonomorphicElementAccess(
7968 typed32x4_array, key, NULL,
7969 receiver_map->instance_type() == JS_ARRAY_TYPE,
7970 receiver_map->elements_kind(),
7972 NEVER_RETURN_HOLE, // load_mode.
7974 ast_context()->ReturnValue(instr);
7978 case kFloat32x4ArraySetAt:
7979 case kInt32x4ArraySetAt:
7980 if (CPU::SupportsSIMD128InCrankshaft() && argument_count == 3) {
7981 HValue* value = Pop();
7982 HValue* key = Pop();
7983 HValue* typed32x4_array = Pop();
7984 ASSERT(typed32x4_array == receiver);
7985 Drop(1); // Drop function.
7986 // TODO(haitao): add STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS.
7987 KeyedAccessStoreMode store_mode = STANDARD_STORE;
7988 BuildUncheckedMonomorphicElementAccess(
7989 typed32x4_array, key, value,
7990 receiver_map->instance_type() == JS_ARRAY_TYPE,
7991 receiver_map->elements_kind(),
7993 NEVER_RETURN_HOLE, // load_mode.
7996 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
7997 ast_context()->ReturnValue(Pop());
8002 // Not yet supported for inlining.
8009 bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr,
8011 Handle<JSFunction> function = expr->target();
8012 int argc = expr->arguments()->length();
8013 SmallMapList receiver_maps;
8014 return TryInlineApiCall(function,
8023 bool HOptimizedGraphBuilder::TryInlineApiMethodCall(
8026 SmallMapList* receiver_maps) {
8027 Handle<JSFunction> function = expr->target();
8028 int argc = expr->arguments()->length();
8029 return TryInlineApiCall(function,
8038 bool HOptimizedGraphBuilder::TryInlineApiGetter(Handle<JSFunction> function,
8039 Handle<Map> receiver_map,
8041 SmallMapList receiver_maps(1, zone());
8042 receiver_maps.Add(receiver_map, zone());
8043 return TryInlineApiCall(function,
8044 NULL, // Receiver is on expression stack.
8052 bool HOptimizedGraphBuilder::TryInlineApiSetter(Handle<JSFunction> function,
8053 Handle<Map> receiver_map,
8055 SmallMapList receiver_maps(1, zone());
8056 receiver_maps.Add(receiver_map, zone());
8057 return TryInlineApiCall(function,
8058 NULL, // Receiver is on expression stack.
8066 bool HOptimizedGraphBuilder::TryInlineApiCall(Handle<JSFunction> function,
8068 SmallMapList* receiver_maps,
8071 ApiCallType call_type) {
8072 CallOptimization optimization(function);
8073 if (!optimization.is_simple_api_call()) return false;
8074 Handle<Map> holder_map;
8075 if (call_type == kCallApiFunction) {
8076 // Cannot embed a direct reference to the global proxy map
8077 // as it maybe dropped on deserialization.
8078 CHECK(!Serializer::enabled());
8079 ASSERT_EQ(0, receiver_maps->length());
8080 receiver_maps->Add(handle(
8081 function->context()->global_object()->global_receiver()->map()),
8084 CallOptimization::HolderLookup holder_lookup =
8085 CallOptimization::kHolderNotFound;
8086 Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType(
8087 receiver_maps->first(), &holder_lookup);
8088 if (holder_lookup == CallOptimization::kHolderNotFound) return false;
8090 if (FLAG_trace_inlining) {
8091 PrintF("Inlining api function ");
8092 function->ShortPrint();
8096 bool drop_extra = false;
8097 bool is_store = false;
8098 switch (call_type) {
8099 case kCallApiFunction:
8100 case kCallApiMethod:
8101 // Need to check that none of the receiver maps could have changed.
8102 Add<HCheckMaps>(receiver, receiver_maps);
8103 // Need to ensure the chain between receiver and api_holder is intact.
8104 if (holder_lookup == CallOptimization::kHolderFound) {
8105 AddCheckPrototypeMaps(api_holder, receiver_maps->first());
8107 ASSERT_EQ(holder_lookup, CallOptimization::kHolderIsReceiver);
8109 // Includes receiver.
8110 PushArgumentsFromEnvironment(argc + 1);
8111 // Drop function after call.
8114 case kCallApiGetter:
8115 // Receiver and prototype chain cannot have changed.
8117 ASSERT_EQ(NULL, receiver);
8118 // Receiver is on expression stack.
8120 Add<HPushArgument>(receiver);
8122 case kCallApiSetter:
8125 // Receiver and prototype chain cannot have changed.
8127 ASSERT_EQ(NULL, receiver);
8128 // Receiver and value are on expression stack.
8129 HValue* value = Pop();
8131 Add<HPushArgument>(receiver);
8132 Add<HPushArgument>(value);
8137 HValue* holder = NULL;
8138 switch (holder_lookup) {
8139 case CallOptimization::kHolderFound:
8140 holder = Add<HConstant>(api_holder);
8142 case CallOptimization::kHolderIsReceiver:
8145 case CallOptimization::kHolderNotFound:
8149 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
8150 Handle<Object> call_data_obj(api_call_info->data(), isolate());
8151 bool call_data_is_undefined = call_data_obj->IsUndefined();
8152 HValue* call_data = Add<HConstant>(call_data_obj);
8153 ApiFunction fun(v8::ToCData<Address>(api_call_info->callback()));
8154 ExternalReference ref = ExternalReference(&fun,
8155 ExternalReference::DIRECT_API_CALL,
8157 HValue* api_function_address = Add<HConstant>(ExternalReference(ref));
8159 HValue* op_vals[] = {
8160 Add<HConstant>(function),
8163 api_function_address,
8167 CallInterfaceDescriptor* descriptor =
8168 isolate()->call_descriptor(Isolate::ApiFunctionCall);
8170 CallApiFunctionStub stub(is_store, call_data_is_undefined, argc);
8171 Handle<Code> code = stub.GetCode(isolate());
8172 HConstant* code_value = Add<HConstant>(code);
8174 ASSERT((sizeof(op_vals) / kPointerSize) ==
8175 descriptor->environment_length());
8177 HInstruction* call = New<HCallWithDescriptor>(
8178 code_value, argc + 1, descriptor,
8179 Vector<HValue*>(op_vals, descriptor->environment_length()));
8181 if (drop_extra) Drop(1); // Drop function.
8182 ast_context()->ReturnInstruction(call, ast_id);
8187 bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
8188 ASSERT(expr->expression()->IsProperty());
8190 if (!expr->IsMonomorphic()) {
8193 Handle<Map> function_map = expr->GetReceiverTypes()->first();
8194 if (function_map->instance_type() != JS_FUNCTION_TYPE ||
8195 !expr->target()->shared()->HasBuiltinFunctionId() ||
8196 expr->target()->shared()->builtin_function_id() != kFunctionApply) {
8200 if (current_info()->scope()->arguments() == NULL) return false;
8202 ZoneList<Expression*>* args = expr->arguments();
8203 if (args->length() != 2) return false;
8205 VariableProxy* arg_two = args->at(1)->AsVariableProxy();
8206 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
8207 HValue* arg_two_value = LookupAndMakeLive(arg_two->var());
8208 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
8210 // Found pattern f.apply(receiver, arguments).
8211 CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true);
8212 HValue* receiver = Pop(); // receiver
8213 HValue* function = Pop(); // f
8216 if (function_state()->outer() == NULL) {
8217 HInstruction* elements = Add<HArgumentsElements>(false);
8218 HInstruction* length = Add<HArgumentsLength>(elements);
8219 HValue* wrapped_receiver = BuildWrapReceiver(receiver, function);
8220 HInstruction* result = New<HApplyArguments>(function,
8224 ast_context()->ReturnInstruction(result, expr->id());
8227 // We are inside inlined function and we know exactly what is inside
8228 // arguments object. But we need to be able to materialize at deopt.
8229 ASSERT_EQ(environment()->arguments_environment()->parameter_count(),
8230 function_state()->entry()->arguments_object()->arguments_count());
8231 HArgumentsObject* args = function_state()->entry()->arguments_object();
8232 const ZoneList<HValue*>* arguments_values = args->arguments_values();
8233 int arguments_count = arguments_values->length();
8235 Push(BuildWrapReceiver(receiver, function));
8236 for (int i = 1; i < arguments_count; i++) {
8237 Push(arguments_values->at(i));
8240 Handle<JSFunction> known_function;
8241 if (function->IsConstant() &&
8242 HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
8243 known_function = Handle<JSFunction>::cast(
8244 HConstant::cast(function)->handle(isolate()));
8245 int args_count = arguments_count - 1; // Excluding receiver.
8246 if (TryInlineApply(known_function, expr, args_count)) return true;
8249 PushArgumentsFromEnvironment(arguments_count);
8250 HInvokeFunction* call = New<HInvokeFunction>(
8251 function, known_function, arguments_count);
8252 Drop(1); // Function.
8253 ast_context()->ReturnInstruction(call, expr->id());
8259 HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function,
8260 Handle<JSFunction> target) {
8261 SharedFunctionInfo* shared = target->shared();
8262 if (shared->strict_mode() == SLOPPY && !shared->native()) {
8263 // Cannot embed a direct reference to the global proxy
8264 // as is it dropped on deserialization.
8265 CHECK(!Serializer::enabled());
8266 Handle<JSObject> global_receiver(
8267 target->context()->global_object()->global_receiver());
8268 return Add<HConstant>(global_receiver);
8270 return graph()->GetConstantUndefined();
8274 void HOptimizedGraphBuilder::VisitCall(Call* expr) {
8275 ASSERT(!HasStackOverflow());
8276 ASSERT(current_block() != NULL);
8277 ASSERT(current_block()->HasPredecessor());
8278 Expression* callee = expr->expression();
8279 int argument_count = expr->arguments()->length() + 1; // Plus receiver.
8280 HInstruction* call = NULL;
8282 Property* prop = callee->AsProperty();
8284 CHECK_ALIVE(VisitForValue(prop->obj()));
8285 HValue* receiver = Top();
8287 SmallMapList* types;
8288 ComputeReceiverTypes(expr, receiver, &types, zone());
8290 if (prop->key()->IsPropertyName() && types->length() > 0) {
8291 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
8292 PropertyAccessInfo info(this, LOAD, ToType(types->first()), name);
8293 if (!info.CanAccessAsMonomorphic(types)) {
8294 HandlePolymorphicCallNamed(expr, receiver, types, name);
8300 if (!prop->key()->IsPropertyName()) {
8301 CHECK_ALIVE(VisitForValue(prop->key()));
8305 CHECK_ALIVE(PushLoad(prop, receiver, key));
8306 HValue* function = Pop();
8308 if (FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
8310 // Push the function under the receiver.
8311 environment()->SetExpressionStackAt(0, function);
8315 if (function->IsConstant() &&
8316 HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
8317 Handle<JSFunction> known_function = Handle<JSFunction>::cast(
8318 HConstant::cast(function)->handle(isolate()));
8319 expr->set_target(known_function);
8321 if (TryCallApply(expr)) return;
8322 CHECK_ALIVE(VisitExpressions(expr->arguments()));
8324 Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>();
8325 if (TryInlineBuiltinMethodCall(expr, receiver, map)) {
8326 if (FLAG_trace_inlining) {
8327 PrintF("Inlining builtin ");
8328 known_function->ShortPrint();
8333 if (TryInlineApiMethodCall(expr, receiver, types)) return;
8335 // Wrap the receiver if necessary.
8336 if (NeedsWrappingFor(ToType(types->first()), known_function)) {
8337 // Since HWrapReceiver currently cannot actually wrap numbers and
8338 // strings, use the regular CallFunctionStub for method calls to wrap
8340 // TODO(verwaest): Support creation of value wrappers directly in
8342 call = New<HCallFunction>(
8343 function, argument_count, WRAP_AND_CALL);
8344 } else if (TryInlineCall(expr)) {
8347 call = BuildCallConstantFunction(known_function, argument_count);
8351 CHECK_ALIVE(VisitExpressions(expr->arguments()));
8352 CallFunctionFlags flags = receiver->type().IsJSObject()
8353 ? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD;
8354 call = New<HCallFunction>(function, argument_count, flags);
8356 PushArgumentsFromEnvironment(argument_count);
8359 VariableProxy* proxy = expr->expression()->AsVariableProxy();
8360 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) {
8361 return Bailout(kPossibleDirectCallToEval);
8364 // The function is on the stack in the unoptimized code during
8365 // evaluation of the arguments.
8366 CHECK_ALIVE(VisitForValue(expr->expression()));
8367 HValue* function = Top();
8368 bool global_call = proxy != NULL && proxy->var()->IsUnallocated();
8370 Variable* var = proxy->var();
8371 bool known_global_function = false;
8372 // If there is a global property cell for the name at compile time and
8373 // access check is not enabled we assume that the function will not change
8374 // and generate optimized code for calling the function.
8375 LookupResult lookup(isolate());
8376 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, LOAD);
8377 if (type == kUseCell &&
8378 !current_info()->global_object()->IsAccessCheckNeeded()) {
8379 Handle<GlobalObject> global(current_info()->global_object());
8380 known_global_function = expr->ComputeGlobalTarget(global, &lookup);
8382 if (known_global_function) {
8383 Add<HCheckValue>(function, expr->target());
8385 // Placeholder for the receiver.
8386 Push(graph()->GetConstantUndefined());
8387 CHECK_ALIVE(VisitExpressions(expr->arguments()));
8389 // Patch the global object on the stack by the expected receiver.
8390 HValue* receiver = ImplicitReceiverFor(function, expr->target());
8391 const int receiver_index = argument_count - 1;
8392 environment()->SetExpressionStackAt(receiver_index, receiver);
8394 if (TryInlineBuiltinFunctionCall(expr)) {
8395 if (FLAG_trace_inlining) {
8396 PrintF("Inlining builtin ");
8397 expr->target()->ShortPrint();
8402 if (TryInlineApiFunctionCall(expr, receiver)) return;
8403 if (TryInlineCall(expr)) return;
8405 PushArgumentsFromEnvironment(argument_count);
8406 call = BuildCallConstantFunction(expr->target(), argument_count);
8408 Push(graph()->GetConstantUndefined());
8409 CHECK_ALIVE(VisitExpressions(expr->arguments()));
8410 PushArgumentsFromEnvironment(argument_count);
8411 call = New<HCallFunction>(function, argument_count);
8414 } else if (expr->IsMonomorphic()) {
8415 Add<HCheckValue>(function, expr->target());
8417 Push(graph()->GetConstantUndefined());
8418 CHECK_ALIVE(VisitExpressions(expr->arguments()));
8420 HValue* receiver = ImplicitReceiverFor(function, expr->target());
8421 const int receiver_index = argument_count - 1;
8422 environment()->SetExpressionStackAt(receiver_index, receiver);
8424 if (TryInlineBuiltinFunctionCall(expr)) {
8425 if (FLAG_trace_inlining) {
8426 PrintF("Inlining builtin ");
8427 expr->target()->ShortPrint();
8432 if (TryInlineApiFunctionCall(expr, receiver)) return;
8434 if (TryInlineCall(expr)) return;
8436 call = PreProcessCall(New<HInvokeFunction>(
8437 function, expr->target(), argument_count));
8440 Push(graph()->GetConstantUndefined());
8441 CHECK_ALIVE(VisitExpressions(expr->arguments()));
8442 PushArgumentsFromEnvironment(argument_count);
8443 call = New<HCallFunction>(function, argument_count);
8447 Drop(1); // Drop the function.
8448 return ast_context()->ReturnInstruction(call, expr->id());
8452 void HOptimizedGraphBuilder::BuildInlinedCallNewArray(CallNew* expr) {
8453 NoObservableSideEffectsScope no_effects(this);
8455 int argument_count = expr->arguments()->length();
8456 // We should at least have the constructor on the expression stack.
8457 HValue* constructor = environment()->ExpressionStackAt(argument_count);
8459 ElementsKind kind = expr->elements_kind();
8460 Handle<AllocationSite> site = expr->allocation_site();
8461 ASSERT(!site.is_null());
8463 // Register on the site for deoptimization if the transition feedback changes.
8464 AllocationSite::AddDependentCompilationInfo(
8465 site, AllocationSite::TRANSITIONS, top_info());
8466 HInstruction* site_instruction = Add<HConstant>(site);
8468 // In the single constant argument case, we may have to adjust elements kind
8469 // to avoid creating a packed non-empty array.
8470 if (argument_count == 1 && !IsHoleyElementsKind(kind)) {
8471 HValue* argument = environment()->Top();
8472 if (argument->IsConstant()) {
8473 HConstant* constant_argument = HConstant::cast(argument);
8474 ASSERT(constant_argument->HasSmiValue());
8475 int constant_array_size = constant_argument->Integer32Value();
8476 if (constant_array_size != 0) {
8477 kind = GetHoleyElementsKind(kind);
8483 JSArrayBuilder array_builder(this,
8487 DISABLE_ALLOCATION_SITES);
8489 if (argument_count == 0) {
8490 new_object = array_builder.AllocateEmptyArray();
8491 } else if (argument_count == 1) {
8492 HValue* argument = environment()->Top();
8493 new_object = BuildAllocateArrayFromLength(&array_builder, argument);
8495 HValue* length = Add<HConstant>(argument_count);
8496 // Smi arrays need to initialize array elements with the hole because
8497 // bailout could occur if the arguments don't fit in a smi.
8499 // TODO(mvstanton): If all the arguments are constants in smi range, then
8500 // we could set fill_with_hole to false and save a few instructions.
8501 JSArrayBuilder::FillMode fill_mode = IsFastSmiElementsKind(kind)
8502 ? JSArrayBuilder::FILL_WITH_HOLE
8503 : JSArrayBuilder::DONT_FILL_WITH_HOLE;
8504 new_object = array_builder.AllocateArray(length, length, fill_mode);
8505 HValue* elements = array_builder.GetElementsLocation();
8506 for (int i = 0; i < argument_count; i++) {
8507 HValue* value = environment()->ExpressionStackAt(argument_count - i - 1);
8508 HValue* constant_i = Add<HConstant>(i);
8509 Add<HStoreKeyed>(elements, constant_i, value, kind);
8513 Drop(argument_count + 1); // drop constructor and args.
8514 ast_context()->ReturnValue(new_object);
8518 // Checks whether allocation using the given constructor can be inlined.
8519 static bool IsAllocationInlineable(Handle<JSFunction> constructor) {
8520 return constructor->has_initial_map() &&
8521 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE &&
8522 constructor->initial_map()->instance_size() < HAllocate::kMaxInlineSize &&
8523 constructor->initial_map()->InitialPropertiesLength() == 0;
8527 bool HOptimizedGraphBuilder::IsCallNewArrayInlineable(CallNew* expr) {
8528 Handle<JSFunction> caller = current_info()->closure();
8529 Handle<JSFunction> target(isolate()->native_context()->array_function(),
8531 int argument_count = expr->arguments()->length();
8532 // We should have the function plus array arguments on the environment stack.
8533 ASSERT(environment()->length() >= (argument_count + 1));
8534 Handle<AllocationSite> site = expr->allocation_site();
8535 ASSERT(!site.is_null());
8537 bool inline_ok = false;
8538 if (site->CanInlineCall()) {
8539 // We also want to avoid inlining in certain 1 argument scenarios.
8540 if (argument_count == 1) {
8541 HValue* argument = Top();
8542 if (argument->IsConstant()) {
8543 // Do not inline if the constant length argument is not a smi or
8544 // outside the valid range for a fast array.
8545 HConstant* constant_argument = HConstant::cast(argument);
8546 if (constant_argument->HasSmiValue()) {
8547 int value = constant_argument->Integer32Value();
8548 inline_ok = value >= 0 &&
8549 value < JSObject::kInitialMaxFastElementArray;
8551 TraceInline(target, caller,
8552 "Length outside of valid array range");
8562 TraceInline(target, caller, "AllocationSite requested no inlining.");
8566 TraceInline(target, caller, NULL);
8572 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
8573 ASSERT(!HasStackOverflow());
8574 ASSERT(current_block() != NULL);
8575 ASSERT(current_block()->HasPredecessor());
8576 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
8577 int argument_count = expr->arguments()->length() + 1; // Plus constructor.
8578 Factory* factory = isolate()->factory();
8580 // The constructor function is on the stack in the unoptimized code
8581 // during evaluation of the arguments.
8582 CHECK_ALIVE(VisitForValue(expr->expression()));
8583 HValue* function = Top();
8584 CHECK_ALIVE(VisitExpressions(expr->arguments()));
8586 if (FLAG_inline_construct &&
8587 expr->IsMonomorphic() &&
8588 IsAllocationInlineable(expr->target())) {
8589 Handle<JSFunction> constructor = expr->target();
8590 HValue* check = Add<HCheckValue>(function, constructor);
8592 // Force completion of inobject slack tracking before generating
8593 // allocation code to finalize instance size.
8594 if (constructor->shared()->IsInobjectSlackTrackingInProgress()) {
8595 constructor->shared()->CompleteInobjectSlackTracking();
8598 // Calculate instance size from initial map of constructor.
8599 ASSERT(constructor->has_initial_map());
8600 Handle<Map> initial_map(constructor->initial_map());
8601 int instance_size = initial_map->instance_size();
8602 ASSERT(initial_map->InitialPropertiesLength() == 0);
8604 // Allocate an instance of the implicit receiver object.
8605 HValue* size_in_bytes = Add<HConstant>(instance_size);
8606 HAllocationMode allocation_mode;
8607 if (FLAG_pretenuring_call_new) {
8608 if (FLAG_allocation_site_pretenuring) {
8609 // Try to use pretenuring feedback.
8610 Handle<AllocationSite> allocation_site = expr->allocation_site();
8611 allocation_mode = HAllocationMode(allocation_site);
8612 // Take a dependency on allocation site.
8613 AllocationSite::AddDependentCompilationInfo(allocation_site,
8614 AllocationSite::TENURING,
8617 allocation_mode = HAllocationMode(
8618 isolate()->heap()->GetPretenureMode());
8622 HAllocate* receiver =
8623 BuildAllocate(size_in_bytes, HType::JSObject(), JS_OBJECT_TYPE,
8625 receiver->set_known_initial_map(initial_map);
8627 // Load the initial map from the constructor.
8628 HValue* constructor_value = Add<HConstant>(constructor);
8629 HValue* initial_map_value =
8630 Add<HLoadNamedField>(constructor_value, static_cast<HValue*>(NULL),
8631 HObjectAccess::ForMapAndOffset(
8632 handle(constructor->map()),
8633 JSFunction::kPrototypeOrInitialMapOffset));
8635 // Initialize map and fields of the newly allocated object.
8636 { NoObservableSideEffectsScope no_effects(this);
8637 ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE);
8638 Add<HStoreNamedField>(receiver,
8639 HObjectAccess::ForMapAndOffset(initial_map, JSObject::kMapOffset),
8641 HValue* empty_fixed_array = Add<HConstant>(factory->empty_fixed_array());
8642 Add<HStoreNamedField>(receiver,
8643 HObjectAccess::ForMapAndOffset(initial_map,
8644 JSObject::kPropertiesOffset),
8646 Add<HStoreNamedField>(receiver,
8647 HObjectAccess::ForMapAndOffset(initial_map,
8648 JSObject::kElementsOffset),
8650 if (initial_map->inobject_properties() != 0) {
8651 HConstant* undefined = graph()->GetConstantUndefined();
8652 for (int i = 0; i < initial_map->inobject_properties(); i++) {
8653 int property_offset = initial_map->GetInObjectPropertyOffset(i);
8654 Add<HStoreNamedField>(receiver,
8655 HObjectAccess::ForMapAndOffset(initial_map, property_offset),
8661 // Replace the constructor function with a newly allocated receiver using
8662 // the index of the receiver from the top of the expression stack.
8663 const int receiver_index = argument_count - 1;
8664 ASSERT(environment()->ExpressionStackAt(receiver_index) == function);
8665 environment()->SetExpressionStackAt(receiver_index, receiver);
8667 if (TryInlineConstruct(expr, receiver)) return;
8669 // TODO(mstarzinger): For now we remove the previous HAllocate and all
8670 // corresponding instructions and instead add HPushArgument for the
8671 // arguments in case inlining failed. What we actually should do is for
8672 // inlining to try to build a subgraph without mutating the parent graph.
8673 HInstruction* instr = current_block()->last();
8674 while (instr != initial_map_value) {
8675 HInstruction* prev_instr = instr->previous();
8676 instr->DeleteAndReplaceWith(NULL);
8679 initial_map_value->DeleteAndReplaceWith(NULL);
8680 receiver->DeleteAndReplaceWith(NULL);
8681 check->DeleteAndReplaceWith(NULL);
8682 environment()->SetExpressionStackAt(receiver_index, function);
8683 HInstruction* call =
8684 PreProcessCall(New<HCallNew>(function, argument_count));
8685 return ast_context()->ReturnInstruction(call, expr->id());
8687 // The constructor function is both an operand to the instruction and an
8688 // argument to the construct call.
8689 Handle<JSFunction> array_function(
8690 isolate()->native_context()->array_function(), isolate());
8691 bool use_call_new_array = expr->target().is_identical_to(array_function);
8692 if (use_call_new_array && IsCallNewArrayInlineable(expr)) {
8693 // Verify we are still calling the array function for our native context.
8694 Add<HCheckValue>(function, array_function);
8695 BuildInlinedCallNewArray(expr);
8700 if (use_call_new_array) {
8701 Add<HCheckValue>(function, array_function);
8702 call = New<HCallNewArray>(function, argument_count,
8703 expr->elements_kind());
8705 call = New<HCallNew>(function, argument_count);
8707 PreProcessCall(call);
8708 return ast_context()->ReturnInstruction(call, expr->id());
8713 // Support for generating inlined runtime functions.
8715 // Lookup table for generators for runtime calls that are generated inline.
8716 // Elements of the table are member pointers to functions of
8717 // HOptimizedGraphBuilder.
8718 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \
8719 &HOptimizedGraphBuilder::Generate##Name,
8721 const HOptimizedGraphBuilder::InlineFunctionGenerator
8722 HOptimizedGraphBuilder::kInlineFunctionGenerators[] = {
8723 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
8724 INLINE_OPTIMIZED_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
8726 #undef INLINE_FUNCTION_GENERATOR_ADDRESS
8729 template <class ViewClass>
8730 void HGraphBuilder::BuildArrayBufferViewInitialization(
8733 HValue* byte_offset,
8734 HValue* byte_length) {
8736 for (int offset = ViewClass::kSize;
8737 offset < ViewClass::kSizeWithInternalFields;
8738 offset += kPointerSize) {
8739 Add<HStoreNamedField>(obj,
8740 HObjectAccess::ForObservableJSObjectOffset(offset),
8741 graph()->GetConstant0());
8744 Add<HStoreNamedField>(
8746 HObjectAccess::ForJSArrayBufferViewByteOffset(),
8748 Add<HStoreNamedField>(
8750 HObjectAccess::ForJSArrayBufferViewByteLength(),
8753 if (buffer != NULL) {
8754 Add<HStoreNamedField>(
8756 HObjectAccess::ForJSArrayBufferViewBuffer(), buffer);
8757 HObjectAccess weak_first_view_access =
8758 HObjectAccess::ForJSArrayBufferWeakFirstView();
8759 Add<HStoreNamedField>(obj,
8760 HObjectAccess::ForJSArrayBufferViewWeakNext(),
8761 Add<HLoadNamedField>(buffer,
8762 static_cast<HValue*>(NULL),
8763 weak_first_view_access));
8764 Add<HStoreNamedField>(buffer, weak_first_view_access, obj);
8766 Add<HStoreNamedField>(
8768 HObjectAccess::ForJSArrayBufferViewBuffer(),
8769 Add<HConstant>(static_cast<int32_t>(0)));
8770 Add<HStoreNamedField>(obj,
8771 HObjectAccess::ForJSArrayBufferViewWeakNext(),
8772 graph()->GetConstantUndefined());
8777 void HOptimizedGraphBuilder::GenerateDataViewInitialize(
8778 CallRuntime* expr) {
8779 ZoneList<Expression*>* arguments = expr->arguments();
8781 NoObservableSideEffectsScope scope(this);
8782 ASSERT(arguments->length()== 4);
8783 CHECK_ALIVE(VisitForValue(arguments->at(0)));
8784 HValue* obj = Pop();
8786 CHECK_ALIVE(VisitForValue(arguments->at(1)));
8787 HValue* buffer = Pop();
8789 CHECK_ALIVE(VisitForValue(arguments->at(2)));
8790 HValue* byte_offset = Pop();
8792 CHECK_ALIVE(VisitForValue(arguments->at(3)));
8793 HValue* byte_length = Pop();
8795 BuildArrayBufferViewInitialization<JSDataView>(
8796 obj, buffer, byte_offset, byte_length);
8800 static Handle<Map> TypedArrayMap(Isolate* isolate,
8801 ExternalArrayType array_type,
8802 ElementsKind target_kind) {
8803 Handle<Context> native_context = isolate->native_context();
8804 Handle<JSFunction> fun;
8805 switch (array_type) {
8806 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
8807 case kExternal##Type##Array: \
8808 fun = Handle<JSFunction>(native_context->type##_array_fun()); \
8811 TYPED_ARRAYS(TYPED_ARRAY_CASE)
8812 #undef TYPED_ARRAY_CASE
8814 Handle<Map> map(fun->initial_map());
8815 return Map::AsElementsKind(map, target_kind);
8819 HValue* HOptimizedGraphBuilder::BuildAllocateExternalElements(
8820 ExternalArrayType array_type,
8821 bool is_zero_byte_offset,
8822 HValue* buffer, HValue* byte_offset, HValue* length) {
8823 Handle<Map> external_array_map(
8824 isolate()->heap()->MapForExternalArrayType(array_type));
8827 Add<HConstant>(ExternalArray::kAlignedSize),
8830 external_array_map->instance_type());
8832 AddStoreMapConstant(elements, external_array_map);
8834 HValue* backing_store = Add<HLoadNamedField>(
8835 buffer, static_cast<HValue*>(NULL),
8836 HObjectAccess::ForJSArrayBufferBackingStore());
8838 HValue* typed_array_start;
8839 if (is_zero_byte_offset) {
8840 typed_array_start = backing_store;
8842 HInstruction* external_pointer =
8843 AddUncasted<HAdd>(backing_store, byte_offset);
8844 // Arguments are checked prior to call to TypedArrayInitialize,
8845 // including byte_offset.
8846 external_pointer->ClearFlag(HValue::kCanOverflow);
8847 typed_array_start = external_pointer;
8851 Add<HStoreNamedField>(elements,
8852 HObjectAccess::ForExternalArrayExternalPointer(),
8855 Add<HStoreNamedField>(elements,
8856 HObjectAccess::ForFixedArrayLength(), length);
8861 HValue* HOptimizedGraphBuilder::BuildAllocateFixedTypedArray(
8862 ExternalArrayType array_type, size_t element_size,
8863 ElementsKind fixed_elements_kind,
8864 HValue* byte_length, HValue* length) {
8866 (FixedTypedArrayBase::kHeaderSize & kObjectAlignmentMask) == 0);
8869 // if fixed array's elements are not aligned to object's alignment,
8870 // we need to align the whole array to object alignment.
8871 if (element_size % kObjectAlignment != 0) {
8872 total_size = BuildObjectSizeAlignment(
8873 byte_length, FixedTypedArrayBase::kHeaderSize);
8875 total_size = AddUncasted<HAdd>(byte_length,
8876 Add<HConstant>(FixedTypedArrayBase::kHeaderSize));
8877 total_size->ClearFlag(HValue::kCanOverflow);
8880 Handle<Map> fixed_typed_array_map(
8881 isolate()->heap()->MapForFixedTypedArray(array_type));
8883 Add<HAllocate>(total_size, HType::Tagged(),
8885 fixed_typed_array_map->instance_type());
8886 AddStoreMapConstant(elements, fixed_typed_array_map);
8888 Add<HStoreNamedField>(elements,
8889 HObjectAccess::ForFixedArrayLength(),
8892 HValue* filler = Add<HConstant>(static_cast<int32_t>(0));
8893 if (IsFixedFloat32x4ElementsKind(fixed_elements_kind)) {
8894 if (CPU::SupportsSIMD128InCrankshaft()) {
8895 filler = AddUncasted<HNullarySIMDOperation>(kFloat32x4Zero);
8897 HValue* size = Add<HConstant>(Float32x4::kSize);
8898 filler = Add<HAllocate>(size, HType::Tagged(), NOT_TENURED,
8899 Float32x4::kInstanceType);
8900 AddStoreMapConstant(filler, isolate()->factory()->float32x4_map());
8901 HValue* zero = Add<HConstant>(static_cast<double>(0.0));
8902 Add<HStoreNamedField>(filler, HObjectAccess::ForSIMD128XYLanes(), zero);
8903 Add<HStoreNamedField>(filler, HObjectAccess::ForSIMD128ZWLanes(), zero);
8905 } else if (IsFixedInt32x4ElementsKind(fixed_elements_kind)) {
8906 if (CPU::SupportsSIMD128InCrankshaft()) {
8907 filler = AddUncasted<HNullarySIMDOperation>(kInt32x4Zero);
8909 HValue* size = Add<HConstant>(Int32x4::kSize);
8910 filler = Add<HAllocate>(size, HType::Tagged(), NOT_TENURED,
8911 Int32x4::kInstanceType);
8912 AddStoreMapConstant(filler, isolate()->factory()->int32x4_map());
8913 HValue* zero = Add<HConstant>(static_cast<double>(0.0));
8914 Add<HStoreNamedField>(filler, HObjectAccess::ForSIMD128XYLanes(), zero);
8915 Add<HStoreNamedField>(filler, HObjectAccess::ForSIMD128ZWLanes(), zero);
8920 LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement);
8922 HValue* key = builder.BeginBody(
8923 Add<HConstant>(static_cast<int32_t>(0)),
8925 Add<HStoreKeyed>(elements, key, filler, fixed_elements_kind);
8929 Add<HStoreNamedField>(
8930 elements, HObjectAccess::ForFixedArrayLength(), length);
8935 void HOptimizedGraphBuilder::GenerateTypedArrayInitialize(
8936 CallRuntime* expr) {
8937 ZoneList<Expression*>* arguments = expr->arguments();
8939 NoObservableSideEffectsScope scope(this);
8940 static const int kObjectArg = 0;
8941 static const int kArrayIdArg = 1;
8942 static const int kBufferArg = 2;
8943 static const int kByteOffsetArg = 3;
8944 static const int kByteLengthArg = 4;
8945 static const int kArgsLength = 5;
8946 ASSERT(arguments->length() == kArgsLength);
8949 CHECK_ALIVE(VisitForValue(arguments->at(kObjectArg)));
8950 HValue* obj = Pop();
8952 ASSERT(arguments->at(kArrayIdArg)->node_type() == AstNode::kLiteral);
8953 Handle<Object> value =
8954 static_cast<Literal*>(arguments->at(kArrayIdArg))->value();
8955 ASSERT(value->IsSmi());
8956 int array_id = Smi::cast(*value)->value();
8959 if (!arguments->at(kBufferArg)->IsNullLiteral()) {
8960 CHECK_ALIVE(VisitForValue(arguments->at(kBufferArg)));
8966 HValue* byte_offset;
8967 bool is_zero_byte_offset;
8969 if (arguments->at(kByteOffsetArg)->node_type() == AstNode::kLiteral
8970 && Smi::FromInt(0) ==
8971 *static_cast<Literal*>(arguments->at(kByteOffsetArg))->value()) {
8972 byte_offset = Add<HConstant>(static_cast<int32_t>(0));
8973 is_zero_byte_offset = true;
8975 CHECK_ALIVE(VisitForValue(arguments->at(kByteOffsetArg)));
8976 byte_offset = Pop();
8977 is_zero_byte_offset = false;
8978 ASSERT(buffer != NULL);
8981 CHECK_ALIVE(VisitForValue(arguments->at(kByteLengthArg)));
8982 HValue* byte_length = Pop();
8984 IfBuilder byte_offset_smi(this);
8986 if (!is_zero_byte_offset) {
8987 byte_offset_smi.If<HIsSmiAndBranch>(byte_offset);
8988 byte_offset_smi.Then();
8991 ExternalArrayType array_type =
8992 kExternalInt8Array; // Bogus initialization.
8993 size_t element_size = 1; // Bogus initialization.
8994 ElementsKind external_elements_kind = // Bogus initialization.
8995 EXTERNAL_INT8_ELEMENTS;
8996 ElementsKind fixed_elements_kind = // Bogus initialization.
8998 Runtime::ArrayIdToTypeAndSize(array_id,
9000 &external_elements_kind,
9001 &fixed_elements_kind,
9005 { // byte_offset is Smi.
9006 BuildArrayBufferViewInitialization<JSTypedArray>(
9007 obj, buffer, byte_offset, byte_length);
9010 HInstruction* length = AddUncasted<HDiv>(byte_length,
9011 Add<HConstant>(static_cast<int32_t>(element_size)));
9013 Add<HStoreNamedField>(obj,
9014 HObjectAccess::ForJSTypedArrayLength(),
9018 if (buffer != NULL) {
9019 elements = BuildAllocateExternalElements(
9020 array_type, is_zero_byte_offset, buffer, byte_offset, length);
9021 Handle<Map> obj_map = TypedArrayMap(
9022 isolate(), array_type, external_elements_kind);
9023 AddStoreMapConstant(obj, obj_map);
9025 ASSERT(is_zero_byte_offset);
9026 elements = BuildAllocateFixedTypedArray(
9027 array_type, element_size, fixed_elements_kind,
9028 byte_length, length);
9030 Add<HStoreNamedField>(
9031 obj, HObjectAccess::ForElementsPointer(), elements);
9034 if (!is_zero_byte_offset) {
9035 byte_offset_smi.Else();
9036 { // byte_offset is not Smi.
9038 CHECK_ALIVE(VisitForValue(arguments->at(kArrayIdArg)));
9042 PushArgumentsFromEnvironment(kArgsLength);
9043 Add<HCallRuntime>(expr->name(), expr->function(), kArgsLength);
9046 byte_offset_smi.End();
9050 void HOptimizedGraphBuilder::GenerateMaxSmi(CallRuntime* expr) {
9051 ASSERT(expr->arguments()->length() == 0);
9052 HConstant* max_smi = New<HConstant>(static_cast<int32_t>(Smi::kMaxValue));
9053 return ast_context()->ReturnInstruction(max_smi, expr->id());
9057 void HOptimizedGraphBuilder::GenerateTypedArrayMaxSizeInHeap(
9058 CallRuntime* expr) {
9059 ASSERT(expr->arguments()->length() == 0);
9060 HConstant* result = New<HConstant>(static_cast<int32_t>(
9061 FLAG_typed_array_max_size_in_heap));
9062 return ast_context()->ReturnInstruction(result, expr->id());
9066 void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
9067 ASSERT(!HasStackOverflow());
9068 ASSERT(current_block() != NULL);
9069 ASSERT(current_block()->HasPredecessor());
9070 if (expr->is_jsruntime()) {
9071 return Bailout(kCallToAJavaScriptRuntimeFunction);
9074 const Runtime::Function* function = expr->function();
9075 ASSERT(function != NULL);
9077 if (function->intrinsic_type == Runtime::INLINE ||
9078 function->intrinsic_type == Runtime::INLINE_OPTIMIZED) {
9079 ASSERT(expr->name()->length() > 0);
9080 ASSERT(expr->name()->Get(0) == '_');
9081 // Call to an inline function.
9082 int lookup_index = static_cast<int>(function->function_id) -
9083 static_cast<int>(Runtime::kFirstInlineFunction);
9084 ASSERT(lookup_index >= 0);
9085 ASSERT(static_cast<size_t>(lookup_index) <
9086 ARRAY_SIZE(kInlineFunctionGenerators));
9087 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index];
9089 // Call the inline code generator using the pointer-to-member.
9090 (this->*generator)(expr);
9092 ASSERT(function->intrinsic_type == Runtime::RUNTIME);
9093 Handle<String> name = expr->name();
9094 int argument_count = expr->arguments()->length();
9095 CHECK_ALIVE(VisitExpressions(expr->arguments()));
9096 PushArgumentsFromEnvironment(argument_count);
9097 HCallRuntime* call = New<HCallRuntime>(name, function,
9099 return ast_context()->ReturnInstruction(call, expr->id());
9104 void HOptimizedGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
9105 ASSERT(!HasStackOverflow());
9106 ASSERT(current_block() != NULL);
9107 ASSERT(current_block()->HasPredecessor());
9108 switch (expr->op()) {
9109 case Token::DELETE: return VisitDelete(expr);
9110 case Token::VOID: return VisitVoid(expr);
9111 case Token::TYPEOF: return VisitTypeof(expr);
9112 case Token::NOT: return VisitNot(expr);
9113 default: UNREACHABLE();
9118 void HOptimizedGraphBuilder::VisitDelete(UnaryOperation* expr) {
9119 Property* prop = expr->expression()->AsProperty();
9120 VariableProxy* proxy = expr->expression()->AsVariableProxy();
9122 CHECK_ALIVE(VisitForValue(prop->obj()));
9123 CHECK_ALIVE(VisitForValue(prop->key()));
9124 HValue* key = Pop();
9125 HValue* obj = Pop();
9126 HValue* function = AddLoadJSBuiltin(Builtins::DELETE);
9127 Add<HPushArgument>(obj);
9128 Add<HPushArgument>(key);
9129 Add<HPushArgument>(Add<HConstant>(function_strict_mode()));
9130 // TODO(olivf) InvokeFunction produces a check for the parameter count,
9131 // even though we are certain to pass the correct number of arguments here.
9132 HInstruction* instr = New<HInvokeFunction>(function, 3);
9133 return ast_context()->ReturnInstruction(instr, expr->id());
9134 } else if (proxy != NULL) {
9135 Variable* var = proxy->var();
9136 if (var->IsUnallocated()) {
9137 Bailout(kDeleteWithGlobalVariable);
9138 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
9139 // Result of deleting non-global variables is false. 'this' is not
9140 // really a variable, though we implement it as one. The
9141 // subexpression does not have side effects.
9142 HValue* value = var->is_this()
9143 ? graph()->GetConstantTrue()
9144 : graph()->GetConstantFalse();
9145 return ast_context()->ReturnValue(value);
9147 Bailout(kDeleteWithNonGlobalVariable);
9150 // Result of deleting non-property, non-variable reference is true.
9151 // Evaluate the subexpression for side effects.
9152 CHECK_ALIVE(VisitForEffect(expr->expression()));
9153 return ast_context()->ReturnValue(graph()->GetConstantTrue());
9158 void HOptimizedGraphBuilder::VisitVoid(UnaryOperation* expr) {
9159 CHECK_ALIVE(VisitForEffect(expr->expression()));
9160 return ast_context()->ReturnValue(graph()->GetConstantUndefined());
9164 void HOptimizedGraphBuilder::VisitTypeof(UnaryOperation* expr) {
9165 CHECK_ALIVE(VisitForTypeOf(expr->expression()));
9166 HValue* value = Pop();
9167 HInstruction* instr = New<HTypeof>(value);
9168 return ast_context()->ReturnInstruction(instr, expr->id());
9172 void HOptimizedGraphBuilder::VisitNot(UnaryOperation* expr) {
9173 if (ast_context()->IsTest()) {
9174 TestContext* context = TestContext::cast(ast_context());
9175 VisitForControl(expr->expression(),
9176 context->if_false(),
9177 context->if_true());
9181 if (ast_context()->IsEffect()) {
9182 VisitForEffect(expr->expression());
9186 ASSERT(ast_context()->IsValue());
9187 HBasicBlock* materialize_false = graph()->CreateBasicBlock();
9188 HBasicBlock* materialize_true = graph()->CreateBasicBlock();
9189 CHECK_BAILOUT(VisitForControl(expr->expression(),
9193 if (materialize_false->HasPredecessor()) {
9194 materialize_false->SetJoinId(expr->MaterializeFalseId());
9195 set_current_block(materialize_false);
9196 Push(graph()->GetConstantFalse());
9198 materialize_false = NULL;
9201 if (materialize_true->HasPredecessor()) {
9202 materialize_true->SetJoinId(expr->MaterializeTrueId());
9203 set_current_block(materialize_true);
9204 Push(graph()->GetConstantTrue());
9206 materialize_true = NULL;
9210 CreateJoin(materialize_false, materialize_true, expr->id());
9211 set_current_block(join);
9212 if (join != NULL) return ast_context()->ReturnValue(Pop());
9216 HInstruction* HOptimizedGraphBuilder::BuildIncrement(
9217 bool returns_original_input,
9218 CountOperation* expr) {
9219 // The input to the count operation is on top of the expression stack.
9220 Representation rep = Representation::FromType(expr->type());
9221 if (rep.IsNone() || rep.IsTagged()) {
9222 rep = Representation::Smi();
9225 if (returns_original_input) {
9226 // We need an explicit HValue representing ToNumber(input). The
9227 // actual HChange instruction we need is (sometimes) added in a later
9228 // phase, so it is not available now to be used as an input to HAdd and
9229 // as the return value.
9230 HInstruction* number_input = AddUncasted<HForceRepresentation>(Pop(), rep);
9231 if (!rep.IsDouble()) {
9232 number_input->SetFlag(HInstruction::kFlexibleRepresentation);
9233 number_input->SetFlag(HInstruction::kCannotBeTagged);
9238 // The addition has no side effects, so we do not need
9239 // to simulate the expression stack after this instruction.
9240 // Any later failures deopt to the load of the input or earlier.
9241 HConstant* delta = (expr->op() == Token::INC)
9242 ? graph()->GetConstant1()
9243 : graph()->GetConstantMinus1();
9244 HInstruction* instr = AddUncasted<HAdd>(Top(), delta);
9245 if (instr->IsAdd()) {
9246 HAdd* add = HAdd::cast(instr);
9247 add->set_observed_input_representation(1, rep);
9248 add->set_observed_input_representation(2, Representation::Smi());
9250 instr->SetFlag(HInstruction::kCannotBeTagged);
9251 instr->ClearAllSideEffects();
9256 void HOptimizedGraphBuilder::BuildStoreForEffect(Expression* expr,
9259 BailoutId return_id,
9263 EffectContext for_effect(this);
9265 if (key != NULL) Push(key);
9267 BuildStore(expr, prop, ast_id, return_id);
9271 void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
9272 ASSERT(!HasStackOverflow());
9273 ASSERT(current_block() != NULL);
9274 ASSERT(current_block()->HasPredecessor());
9275 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
9276 Expression* target = expr->expression();
9277 VariableProxy* proxy = target->AsVariableProxy();
9278 Property* prop = target->AsProperty();
9279 if (proxy == NULL && prop == NULL) {
9280 return Bailout(kInvalidLhsInCountOperation);
9283 // Match the full code generator stack by simulating an extra stack
9284 // element for postfix operations in a non-effect context. The return
9285 // value is ToNumber(input).
9286 bool returns_original_input =
9287 expr->is_postfix() && !ast_context()->IsEffect();
9288 HValue* input = NULL; // ToNumber(original_input).
9289 HValue* after = NULL; // The result after incrementing or decrementing.
9291 if (proxy != NULL) {
9292 Variable* var = proxy->var();
9293 if (var->mode() == CONST_LEGACY) {
9294 return Bailout(kUnsupportedCountOperationWithConst);
9296 // Argument of the count operation is a variable, not a property.
9297 ASSERT(prop == NULL);
9298 CHECK_ALIVE(VisitForValue(target));
9300 after = BuildIncrement(returns_original_input, expr);
9301 input = returns_original_input ? Top() : Pop();
9304 switch (var->location()) {
9305 case Variable::UNALLOCATED:
9306 HandleGlobalVariableAssignment(var,
9308 expr->AssignmentId());
9311 case Variable::PARAMETER:
9312 case Variable::LOCAL:
9313 BindIfLive(var, after);
9316 case Variable::CONTEXT: {
9317 // Bail out if we try to mutate a parameter value in a function
9318 // using the arguments object. We do not (yet) correctly handle the
9319 // arguments property of the function.
9320 if (current_info()->scope()->arguments() != NULL) {
9321 // Parameters will rewrite to context slots. We have no direct
9322 // way to detect that the variable is a parameter so we use a
9323 // linear search of the parameter list.
9324 int count = current_info()->scope()->num_parameters();
9325 for (int i = 0; i < count; ++i) {
9326 if (var == current_info()->scope()->parameter(i)) {
9327 return Bailout(kAssignmentToParameterInArgumentsObject);
9332 HValue* context = BuildContextChainWalk(var);
9333 HStoreContextSlot::Mode mode = IsLexicalVariableMode(var->mode())
9334 ? HStoreContextSlot::kCheckDeoptimize : HStoreContextSlot::kNoCheck;
9335 HStoreContextSlot* instr = Add<HStoreContextSlot>(context, var->index(),
9337 if (instr->HasObservableSideEffects()) {
9338 Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
9343 case Variable::LOOKUP:
9344 return Bailout(kLookupVariableInCountOperation);
9347 Drop(returns_original_input ? 2 : 1);
9348 return ast_context()->ReturnValue(expr->is_postfix() ? input : after);
9351 // Argument of the count operation is a property.
9352 ASSERT(prop != NULL);
9353 if (returns_original_input) Push(graph()->GetConstantUndefined());
9355 CHECK_ALIVE(VisitForValue(prop->obj()));
9356 HValue* object = Top();
9359 if ((!prop->IsFunctionPrototype() && !prop->key()->IsPropertyName()) ||
9360 prop->IsStringAccess()) {
9361 CHECK_ALIVE(VisitForValue(prop->key()));
9365 CHECK_ALIVE(PushLoad(prop, object, key));
9367 after = BuildIncrement(returns_original_input, expr);
9369 if (returns_original_input) {
9371 // Drop object and key to push it again in the effect context below.
9372 Drop(key == NULL ? 1 : 2);
9373 environment()->SetExpressionStackAt(0, input);
9374 CHECK_ALIVE(BuildStoreForEffect(
9375 expr, prop, expr->id(), expr->AssignmentId(), object, key, after));
9376 return ast_context()->ReturnValue(Pop());
9379 environment()->SetExpressionStackAt(0, after);
9380 return BuildStore(expr, prop, expr->id(), expr->AssignmentId());
9384 HInstruction* HOptimizedGraphBuilder::BuildStringCharCodeAt(
9387 if (string->IsConstant() && index->IsConstant()) {
9388 HConstant* c_string = HConstant::cast(string);
9389 HConstant* c_index = HConstant::cast(index);
9390 if (c_string->HasStringValue() && c_index->HasNumberValue()) {
9391 int32_t i = c_index->NumberValueAsInteger32();
9392 Handle<String> s = c_string->StringValue();
9393 if (i < 0 || i >= s->length()) {
9394 return New<HConstant>(OS::nan_value());
9396 return New<HConstant>(s->Get(i));
9399 string = BuildCheckString(string);
9400 index = Add<HBoundsCheck>(index, AddLoadStringLength(string));
9401 return New<HStringCharCodeAt>(string, index);
9405 // Checks if the given shift amounts have following forms:
9406 // (N1) and (N2) with N1 + N2 = 32; (sa) and (32 - sa).
9407 static bool ShiftAmountsAllowReplaceByRotate(HValue* sa,
9408 HValue* const32_minus_sa) {
9409 if (sa->IsConstant() && const32_minus_sa->IsConstant()) {
9410 const HConstant* c1 = HConstant::cast(sa);
9411 const HConstant* c2 = HConstant::cast(const32_minus_sa);
9412 return c1->HasInteger32Value() && c2->HasInteger32Value() &&
9413 (c1->Integer32Value() + c2->Integer32Value() == 32);
9415 if (!const32_minus_sa->IsSub()) return false;
9416 HSub* sub = HSub::cast(const32_minus_sa);
9417 return sub->left()->EqualsInteger32Constant(32) && sub->right() == sa;
9421 // Checks if the left and the right are shift instructions with the oposite
9422 // directions that can be replaced by one rotate right instruction or not.
9423 // Returns the operand and the shift amount for the rotate instruction in the
9425 bool HGraphBuilder::MatchRotateRight(HValue* left,
9428 HValue** shift_amount) {
9431 if (left->IsShl() && right->IsShr()) {
9432 shl = HShl::cast(left);
9433 shr = HShr::cast(right);
9434 } else if (left->IsShr() && right->IsShl()) {
9435 shl = HShl::cast(right);
9436 shr = HShr::cast(left);
9440 if (shl->left() != shr->left()) return false;
9442 if (!ShiftAmountsAllowReplaceByRotate(shl->right(), shr->right()) &&
9443 !ShiftAmountsAllowReplaceByRotate(shr->right(), shl->right())) {
9446 *operand= shr->left();
9447 *shift_amount = shr->right();
9452 bool CanBeZero(HValue* right) {
9453 if (right->IsConstant()) {
9454 HConstant* right_const = HConstant::cast(right);
9455 if (right_const->HasInteger32Value() &&
9456 (right_const->Integer32Value() & 0x1f) != 0) {
9464 HValue* HGraphBuilder::EnforceNumberType(HValue* number,
9466 if (expected->Is(Type::SignedSmall())) {
9467 return AddUncasted<HForceRepresentation>(number, Representation::Smi());
9469 if (expected->Is(Type::Signed32())) {
9470 return AddUncasted<HForceRepresentation>(number,
9471 Representation::Integer32());
9477 HValue* HGraphBuilder::TruncateToNumber(HValue* value, Type** expected) {
9478 if (value->IsConstant()) {
9479 HConstant* constant = HConstant::cast(value);
9480 Maybe<HConstant*> number = constant->CopyToTruncatedNumber(zone());
9481 if (number.has_value) {
9482 *expected = Type::Number(zone());
9483 return AddInstruction(number.value);
9487 // We put temporary values on the stack, which don't correspond to anything
9488 // in baseline code. Since nothing is observable we avoid recording those
9489 // pushes with a NoObservableSideEffectsScope.
9490 NoObservableSideEffectsScope no_effects(this);
9492 Type* expected_type = *expected;
9494 // Separate the number type from the rest.
9495 Type* expected_obj =
9496 Type::Intersect(expected_type, Type::NonNumber(zone()), zone());
9497 Type* expected_number =
9498 Type::Intersect(expected_type, Type::Number(zone()), zone());
9500 // We expect to get a number.
9501 // (We need to check first, since Type::None->Is(Type::Any()) == true.
9502 if (expected_obj->Is(Type::None())) {
9503 ASSERT(!expected_number->Is(Type::None(zone())));
9507 if (expected_obj->Is(Type::Undefined(zone()))) {
9508 // This is already done by HChange.
9509 *expected = Type::Union(expected_number, Type::Float(zone()), zone());
9517 HValue* HOptimizedGraphBuilder::BuildBinaryOperation(
9518 BinaryOperation* expr,
9521 PushBeforeSimulateBehavior push_sim_result) {
9522 Type* left_type = expr->left()->bounds().lower;
9523 Type* right_type = expr->right()->bounds().lower;
9524 Type* result_type = expr->bounds().lower;
9525 Maybe<int> fixed_right_arg = expr->fixed_right_arg();
9526 Handle<AllocationSite> allocation_site = expr->allocation_site();
9528 PretenureFlag pretenure_flag = !FLAG_allocation_site_pretenuring ?
9529 isolate()->heap()->GetPretenureMode() : NOT_TENURED;
9531 HAllocationMode allocation_mode =
9532 FLAG_allocation_site_pretenuring
9533 ? (allocation_site.is_null()
9534 ? HAllocationMode(NOT_TENURED)
9535 : HAllocationMode(allocation_site))
9536 : HAllocationMode(pretenure_flag);
9538 HValue* result = HGraphBuilder::BuildBinaryOperation(
9539 expr->op(), left, right, left_type, right_type, result_type,
9540 fixed_right_arg, allocation_mode);
9541 // Add a simulate after instructions with observable side effects, and
9542 // after phis, which are the result of BuildBinaryOperation when we
9543 // inlined some complex subgraph.
9544 if (result->HasObservableSideEffects() || result->IsPhi()) {
9545 if (push_sim_result == PUSH_BEFORE_SIMULATE) {
9547 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
9550 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
9557 HValue* HGraphBuilder::BuildBinaryOperation(
9564 Maybe<int> fixed_right_arg,
9565 HAllocationMode allocation_mode) {
9567 Representation left_rep = Representation::FromType(left_type);
9568 Representation right_rep = Representation::FromType(right_type);
9570 bool maybe_string_add = op == Token::ADD &&
9571 (left_type->Maybe(Type::String()) ||
9572 right_type->Maybe(Type::String()));
9574 if (left_type->Is(Type::None())) {
9575 Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation",
9577 // TODO(rossberg): we should be able to get rid of non-continuous
9579 left_type = Type::Any(zone());
9581 if (!maybe_string_add) left = TruncateToNumber(left, &left_type);
9582 left_rep = Representation::FromType(left_type);
9585 if (right_type->Is(Type::None())) {
9586 Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation",
9588 right_type = Type::Any(zone());
9590 if (!maybe_string_add) right = TruncateToNumber(right, &right_type);
9591 right_rep = Representation::FromType(right_type);
9594 // Special case for string addition here.
9595 if (op == Token::ADD &&
9596 (left_type->Is(Type::String()) || right_type->Is(Type::String()))) {
9597 // Validate type feedback for left argument.
9598 if (left_type->Is(Type::String())) {
9599 left = BuildCheckString(left);
9602 // Validate type feedback for right argument.
9603 if (right_type->Is(Type::String())) {
9604 right = BuildCheckString(right);
9607 // Convert left argument as necessary.
9608 if (left_type->Is(Type::Number())) {
9609 ASSERT(right_type->Is(Type::String()));
9610 left = BuildNumberToString(left, left_type);
9611 } else if (!left_type->Is(Type::String())) {
9612 ASSERT(right_type->Is(Type::String()));
9613 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_RIGHT);
9614 Add<HPushArgument>(left);
9615 Add<HPushArgument>(right);
9616 return AddUncasted<HInvokeFunction>(function, 2);
9619 // Convert right argument as necessary.
9620 if (right_type->Is(Type::Number())) {
9621 ASSERT(left_type->Is(Type::String()));
9622 right = BuildNumberToString(right, right_type);
9623 } else if (!right_type->Is(Type::String())) {
9624 ASSERT(left_type->Is(Type::String()));
9625 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_LEFT);
9626 Add<HPushArgument>(left);
9627 Add<HPushArgument>(right);
9628 return AddUncasted<HInvokeFunction>(function, 2);
9631 // Fast path for empty constant strings.
9632 if (left->IsConstant() &&
9633 HConstant::cast(left)->HasStringValue() &&
9634 HConstant::cast(left)->StringValue()->length() == 0) {
9637 if (right->IsConstant() &&
9638 HConstant::cast(right)->HasStringValue() &&
9639 HConstant::cast(right)->StringValue()->length() == 0) {
9643 // Register the dependent code with the allocation site.
9644 if (!allocation_mode.feedback_site().is_null()) {
9645 ASSERT(!graph()->info()->IsStub());
9646 Handle<AllocationSite> site(allocation_mode.feedback_site());
9647 AllocationSite::AddDependentCompilationInfo(
9648 site, AllocationSite::TENURING, top_info());
9651 // Inline the string addition into the stub when creating allocation
9652 // mementos to gather allocation site feedback, or if we can statically
9653 // infer that we're going to create a cons string.
9654 if ((graph()->info()->IsStub() &&
9655 allocation_mode.CreateAllocationMementos()) ||
9656 (left->IsConstant() &&
9657 HConstant::cast(left)->HasStringValue() &&
9658 HConstant::cast(left)->StringValue()->length() + 1 >=
9659 ConsString::kMinLength) ||
9660 (right->IsConstant() &&
9661 HConstant::cast(right)->HasStringValue() &&
9662 HConstant::cast(right)->StringValue()->length() + 1 >=
9663 ConsString::kMinLength)) {
9664 return BuildStringAdd(left, right, allocation_mode);
9667 // Fallback to using the string add stub.
9668 return AddUncasted<HStringAdd>(
9669 left, right, allocation_mode.GetPretenureMode(),
9670 STRING_ADD_CHECK_NONE, allocation_mode.feedback_site());
9673 if (graph()->info()->IsStub()) {
9674 left = EnforceNumberType(left, left_type);
9675 right = EnforceNumberType(right, right_type);
9678 Representation result_rep = Representation::FromType(result_type);
9680 bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) ||
9681 (right_rep.IsTagged() && !right_rep.IsSmi());
9683 HInstruction* instr = NULL;
9684 // Only the stub is allowed to call into the runtime, since otherwise we would
9685 // inline several instructions (including the two pushes) for every tagged
9686 // operation in optimized code, which is more expensive, than a stub call.
9687 if (graph()->info()->IsStub() && is_non_primitive) {
9688 HValue* function = AddLoadJSBuiltin(BinaryOpIC::TokenToJSBuiltin(op));
9689 Add<HPushArgument>(left);
9690 Add<HPushArgument>(right);
9691 instr = AddUncasted<HInvokeFunction>(function, 2);
9695 instr = AddUncasted<HAdd>(left, right);
9698 instr = AddUncasted<HSub>(left, right);
9701 instr = AddUncasted<HMul>(left, right);
9704 if (fixed_right_arg.has_value &&
9705 !right->EqualsInteger32Constant(fixed_right_arg.value)) {
9706 HConstant* fixed_right = Add<HConstant>(
9707 static_cast<int>(fixed_right_arg.value));
9708 IfBuilder if_same(this);
9709 if_same.If<HCompareNumericAndBranch>(right, fixed_right, Token::EQ);
9711 if_same.ElseDeopt("Unexpected RHS of binary operation");
9712 right = fixed_right;
9714 instr = AddUncasted<HMod>(left, right);
9718 instr = AddUncasted<HDiv>(left, right);
9720 case Token::BIT_XOR:
9721 case Token::BIT_AND:
9722 instr = AddUncasted<HBitwise>(op, left, right);
9724 case Token::BIT_OR: {
9725 HValue* operand, *shift_amount;
9726 if (left_type->Is(Type::Signed32()) &&
9727 right_type->Is(Type::Signed32()) &&
9728 MatchRotateRight(left, right, &operand, &shift_amount)) {
9729 instr = AddUncasted<HRor>(operand, shift_amount);
9731 instr = AddUncasted<HBitwise>(op, left, right);
9736 instr = AddUncasted<HSar>(left, right);
9739 instr = AddUncasted<HShr>(left, right);
9740 if (FLAG_opt_safe_uint32_operations && instr->IsShr() &&
9742 graph()->RecordUint32Instruction(instr);
9746 instr = AddUncasted<HShl>(left, right);
9753 if (instr->IsBinaryOperation()) {
9754 HBinaryOperation* binop = HBinaryOperation::cast(instr);
9755 binop->set_observed_input_representation(1, left_rep);
9756 binop->set_observed_input_representation(2, right_rep);
9757 binop->initialize_output_representation(result_rep);
9758 if (graph()->info()->IsStub()) {
9759 // Stub should not call into stub.
9760 instr->SetFlag(HValue::kCannotBeTagged);
9761 // And should truncate on HForceRepresentation already.
9762 if (left->IsForceRepresentation()) {
9763 left->CopyFlag(HValue::kTruncatingToSmi, instr);
9764 left->CopyFlag(HValue::kTruncatingToInt32, instr);
9766 if (right->IsForceRepresentation()) {
9767 right->CopyFlag(HValue::kTruncatingToSmi, instr);
9768 right->CopyFlag(HValue::kTruncatingToInt32, instr);
9776 // Check for the form (%_ClassOf(foo) === 'BarClass').
9777 static bool IsClassOfTest(CompareOperation* expr) {
9778 if (expr->op() != Token::EQ_STRICT) return false;
9779 CallRuntime* call = expr->left()->AsCallRuntime();
9780 if (call == NULL) return false;
9781 Literal* literal = expr->right()->AsLiteral();
9782 if (literal == NULL) return false;
9783 if (!literal->value()->IsString()) return false;
9784 if (!call->name()->IsOneByteEqualTo(STATIC_ASCII_VECTOR("_ClassOf"))) {
9787 ASSERT(call->arguments()->length() == 1);
9792 void HOptimizedGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
9793 ASSERT(!HasStackOverflow());
9794 ASSERT(current_block() != NULL);
9795 ASSERT(current_block()->HasPredecessor());
9796 switch (expr->op()) {
9798 return VisitComma(expr);
9801 return VisitLogicalExpression(expr);
9803 return VisitArithmeticExpression(expr);
9808 void HOptimizedGraphBuilder::VisitComma(BinaryOperation* expr) {
9809 CHECK_ALIVE(VisitForEffect(expr->left()));
9810 // Visit the right subexpression in the same AST context as the entire
9812 Visit(expr->right());
9816 void HOptimizedGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
9817 bool is_logical_and = expr->op() == Token::AND;
9818 if (ast_context()->IsTest()) {
9819 TestContext* context = TestContext::cast(ast_context());
9820 // Translate left subexpression.
9821 HBasicBlock* eval_right = graph()->CreateBasicBlock();
9822 if (is_logical_and) {
9823 CHECK_BAILOUT(VisitForControl(expr->left(),
9825 context->if_false()));
9827 CHECK_BAILOUT(VisitForControl(expr->left(),
9832 // Translate right subexpression by visiting it in the same AST
9833 // context as the entire expression.
9834 if (eval_right->HasPredecessor()) {
9835 eval_right->SetJoinId(expr->RightId());
9836 set_current_block(eval_right);
9837 Visit(expr->right());
9840 } else if (ast_context()->IsValue()) {
9841 CHECK_ALIVE(VisitForValue(expr->left()));
9842 ASSERT(current_block() != NULL);
9843 HValue* left_value = Top();
9845 // Short-circuit left values that always evaluate to the same boolean value.
9846 if (expr->left()->ToBooleanIsTrue() || expr->left()->ToBooleanIsFalse()) {
9847 // l (evals true) && r -> r
9848 // l (evals true) || r -> l
9849 // l (evals false) && r -> l
9850 // l (evals false) || r -> r
9851 if (is_logical_and == expr->left()->ToBooleanIsTrue()) {
9853 CHECK_ALIVE(VisitForValue(expr->right()));
9855 return ast_context()->ReturnValue(Pop());
9858 // We need an extra block to maintain edge-split form.
9859 HBasicBlock* empty_block = graph()->CreateBasicBlock();
9860 HBasicBlock* eval_right = graph()->CreateBasicBlock();
9861 ToBooleanStub::Types expected(expr->left()->to_boolean_types());
9862 HBranch* test = is_logical_and
9863 ? New<HBranch>(left_value, expected, eval_right, empty_block)
9864 : New<HBranch>(left_value, expected, empty_block, eval_right);
9865 FinishCurrentBlock(test);
9867 set_current_block(eval_right);
9868 Drop(1); // Value of the left subexpression.
9869 CHECK_BAILOUT(VisitForValue(expr->right()));
9871 HBasicBlock* join_block =
9872 CreateJoin(empty_block, current_block(), expr->id());
9873 set_current_block(join_block);
9874 return ast_context()->ReturnValue(Pop());
9877 ASSERT(ast_context()->IsEffect());
9878 // In an effect context, we don't need the value of the left subexpression,
9879 // only its control flow and side effects. We need an extra block to
9880 // maintain edge-split form.
9881 HBasicBlock* empty_block = graph()->CreateBasicBlock();
9882 HBasicBlock* right_block = graph()->CreateBasicBlock();
9883 if (is_logical_and) {
9884 CHECK_BAILOUT(VisitForControl(expr->left(), right_block, empty_block));
9886 CHECK_BAILOUT(VisitForControl(expr->left(), empty_block, right_block));
9889 // TODO(kmillikin): Find a way to fix this. It's ugly that there are
9890 // actually two empty blocks (one here and one inserted by
9891 // TestContext::BuildBranch, and that they both have an HSimulate though the
9892 // second one is not a merge node, and that we really have no good AST ID to
9893 // put on that first HSimulate.
9895 if (empty_block->HasPredecessor()) {
9896 empty_block->SetJoinId(expr->id());
9901 if (right_block->HasPredecessor()) {
9902 right_block->SetJoinId(expr->RightId());
9903 set_current_block(right_block);
9904 CHECK_BAILOUT(VisitForEffect(expr->right()));
9905 right_block = current_block();
9910 HBasicBlock* join_block =
9911 CreateJoin(empty_block, right_block, expr->id());
9912 set_current_block(join_block);
9913 // We did not materialize any value in the predecessor environments,
9914 // so there is no need to handle it here.
9919 void HOptimizedGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) {
9920 CHECK_ALIVE(VisitForValue(expr->left()));
9921 CHECK_ALIVE(VisitForValue(expr->right()));
9922 SetSourcePosition(expr->position());
9923 HValue* right = Pop();
9924 HValue* left = Pop();
9926 BuildBinaryOperation(expr, left, right,
9927 ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE
9928 : PUSH_BEFORE_SIMULATE);
9929 if (FLAG_hydrogen_track_positions && result->IsBinaryOperation()) {
9930 HBinaryOperation::cast(result)->SetOperandPositions(
9932 ScriptPositionToSourcePosition(expr->left()->position()),
9933 ScriptPositionToSourcePosition(expr->right()->position()));
9935 return ast_context()->ReturnValue(result);
9939 void HOptimizedGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr,
9940 Expression* sub_expr,
9941 Handle<String> check) {
9942 CHECK_ALIVE(VisitForTypeOf(sub_expr));
9943 SetSourcePosition(expr->position());
9944 HValue* value = Pop();
9945 HTypeofIsAndBranch* instr = New<HTypeofIsAndBranch>(value, check);
9946 return ast_context()->ReturnControl(instr, expr->id());
9950 static bool IsLiteralCompareBool(Isolate* isolate,
9954 return op == Token::EQ_STRICT &&
9955 ((left->IsConstant() &&
9956 HConstant::cast(left)->handle(isolate)->IsBoolean()) ||
9957 (right->IsConstant() &&
9958 HConstant::cast(right)->handle(isolate)->IsBoolean()));
9962 void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
9963 ASSERT(!HasStackOverflow());
9964 ASSERT(current_block() != NULL);
9965 ASSERT(current_block()->HasPredecessor());
9967 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
9969 // Check for a few fast cases. The AST visiting behavior must be in sync
9970 // with the full codegen: We don't push both left and right values onto
9971 // the expression stack when one side is a special-case literal.
9972 Expression* sub_expr = NULL;
9973 Handle<String> check;
9974 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) {
9975 return HandleLiteralCompareTypeof(expr, sub_expr, check);
9977 if (expr->IsLiteralCompareUndefined(&sub_expr, isolate())) {
9978 return HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue);
9980 if (expr->IsLiteralCompareNull(&sub_expr)) {
9981 return HandleLiteralCompareNil(expr, sub_expr, kNullValue);
9984 if (IsClassOfTest(expr)) {
9985 CallRuntime* call = expr->left()->AsCallRuntime();
9986 ASSERT(call->arguments()->length() == 1);
9987 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
9988 HValue* value = Pop();
9989 Literal* literal = expr->right()->AsLiteral();
9990 Handle<String> rhs = Handle<String>::cast(literal->value());
9991 HClassOfTestAndBranch* instr = New<HClassOfTestAndBranch>(value, rhs);
9992 return ast_context()->ReturnControl(instr, expr->id());
9995 Type* left_type = expr->left()->bounds().lower;
9996 Type* right_type = expr->right()->bounds().lower;
9997 Type* combined_type = expr->combined_type();
9999 CHECK_ALIVE(VisitForValue(expr->left()));
10000 CHECK_ALIVE(VisitForValue(expr->right()));
10002 if (FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
10004 HValue* right = Pop();
10005 HValue* left = Pop();
10006 Token::Value op = expr->op();
10008 if (IsLiteralCompareBool(isolate(), left, op, right)) {
10009 HCompareObjectEqAndBranch* result =
10010 New<HCompareObjectEqAndBranch>(left, right);
10011 return ast_context()->ReturnControl(result, expr->id());
10014 if (op == Token::INSTANCEOF) {
10015 // Check to see if the rhs of the instanceof is a global function not
10016 // residing in new space. If it is we assume that the function will stay the
10018 Handle<JSFunction> target = Handle<JSFunction>::null();
10019 VariableProxy* proxy = expr->right()->AsVariableProxy();
10020 bool global_function = (proxy != NULL) && proxy->var()->IsUnallocated();
10021 if (global_function &&
10022 current_info()->has_global_object() &&
10023 !current_info()->global_object()->IsAccessCheckNeeded()) {
10024 Handle<String> name = proxy->name();
10025 Handle<GlobalObject> global(current_info()->global_object());
10026 LookupResult lookup(isolate());
10027 global->Lookup(*name, &lookup);
10028 if (lookup.IsNormal() && lookup.GetValue()->IsJSFunction()) {
10029 Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue()));
10030 // If the function is in new space we assume it's more likely to
10031 // change and thus prefer the general IC code.
10032 if (!isolate()->heap()->InNewSpace(*candidate)) {
10033 target = candidate;
10038 // If the target is not null we have found a known global function that is
10039 // assumed to stay the same for this instanceof.
10040 if (target.is_null()) {
10041 HInstanceOf* result = New<HInstanceOf>(left, right);
10042 return ast_context()->ReturnInstruction(result, expr->id());
10044 Add<HCheckValue>(right, target);
10045 HInstanceOfKnownGlobal* result =
10046 New<HInstanceOfKnownGlobal>(left, target);
10047 return ast_context()->ReturnInstruction(result, expr->id());
10050 // Code below assumes that we don't fall through.
10052 } else if (op == Token::IN) {
10053 HValue* function = AddLoadJSBuiltin(Builtins::IN);
10054 Add<HPushArgument>(left);
10055 Add<HPushArgument>(right);
10056 // TODO(olivf) InvokeFunction produces a check for the parameter count,
10057 // even though we are certain to pass the correct number of arguments here.
10058 HInstruction* result = New<HInvokeFunction>(function, 2);
10059 return ast_context()->ReturnInstruction(result, expr->id());
10062 PushBeforeSimulateBehavior push_behavior =
10063 ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE
10064 : PUSH_BEFORE_SIMULATE;
10065 HControlInstruction* compare = BuildCompareInstruction(
10066 op, left, right, left_type, right_type, combined_type,
10067 ScriptPositionToSourcePosition(expr->left()->position()),
10068 ScriptPositionToSourcePosition(expr->right()->position()),
10069 push_behavior, expr->id());
10070 if (compare == NULL) return; // Bailed out.
10071 return ast_context()->ReturnControl(compare, expr->id());
10075 HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction(
10081 Type* combined_type,
10082 HSourcePosition left_position,
10083 HSourcePosition right_position,
10084 PushBeforeSimulateBehavior push_sim_result,
10085 BailoutId bailout_id) {
10086 // Cases handled below depend on collected type feedback. They should
10087 // soft deoptimize when there is no type feedback.
10088 if (combined_type->Is(Type::None())) {
10089 Add<HDeoptimize>("Insufficient type feedback for combined type "
10090 "of binary operation",
10091 Deoptimizer::SOFT);
10092 combined_type = left_type = right_type = Type::Any(zone());
10095 Representation left_rep = Representation::FromType(left_type);
10096 Representation right_rep = Representation::FromType(right_type);
10097 Representation combined_rep = Representation::FromType(combined_type);
10099 if (combined_type->Is(Type::Receiver())) {
10100 if (Token::IsEqualityOp(op)) {
10101 // Can we get away with map check and not instance type check?
10102 HValue* operand_to_check =
10103 left->block()->block_id() < right->block()->block_id() ? left : right;
10104 if (combined_type->IsClass()) {
10105 Handle<Map> map = combined_type->AsClass();
10106 AddCheckMap(operand_to_check, map);
10107 HCompareObjectEqAndBranch* result =
10108 New<HCompareObjectEqAndBranch>(left, right);
10109 if (FLAG_hydrogen_track_positions) {
10110 result->set_operand_position(zone(), 0, left_position);
10111 result->set_operand_position(zone(), 1, right_position);
10115 BuildCheckHeapObject(operand_to_check);
10116 Add<HCheckInstanceType>(operand_to_check,
10117 HCheckInstanceType::IS_SPEC_OBJECT);
10118 HCompareObjectEqAndBranch* result =
10119 New<HCompareObjectEqAndBranch>(left, right);
10123 Bailout(kUnsupportedNonPrimitiveCompare);
10126 } else if (combined_type->Is(Type::InternalizedString()) &&
10127 Token::IsEqualityOp(op)) {
10128 BuildCheckHeapObject(left);
10129 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_INTERNALIZED_STRING);
10130 BuildCheckHeapObject(right);
10131 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_INTERNALIZED_STRING);
10132 HCompareObjectEqAndBranch* result =
10133 New<HCompareObjectEqAndBranch>(left, right);
10135 } else if (combined_type->Is(Type::String())) {
10136 BuildCheckHeapObject(left);
10137 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_STRING);
10138 BuildCheckHeapObject(right);
10139 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_STRING);
10140 HStringCompareAndBranch* result =
10141 New<HStringCompareAndBranch>(left, right, op);
10144 if (combined_rep.IsTagged() || combined_rep.IsNone()) {
10145 HCompareGeneric* result = Add<HCompareGeneric>(left, right, op);
10146 result->set_observed_input_representation(1, left_rep);
10147 result->set_observed_input_representation(2, right_rep);
10148 if (result->HasObservableSideEffects()) {
10149 if (push_sim_result == PUSH_BEFORE_SIMULATE) {
10151 AddSimulate(bailout_id, REMOVABLE_SIMULATE);
10154 AddSimulate(bailout_id, REMOVABLE_SIMULATE);
10157 // TODO(jkummerow): Can we make this more efficient?
10158 HBranch* branch = New<HBranch>(result);
10161 HCompareNumericAndBranch* result =
10162 New<HCompareNumericAndBranch>(left, right, op);
10163 result->set_observed_input_representation(left_rep, right_rep);
10164 if (FLAG_hydrogen_track_positions) {
10165 result->SetOperandPositions(zone(), left_position, right_position);
10173 void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
10174 Expression* sub_expr,
10176 ASSERT(!HasStackOverflow());
10177 ASSERT(current_block() != NULL);
10178 ASSERT(current_block()->HasPredecessor());
10179 ASSERT(expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT);
10180 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
10181 CHECK_ALIVE(VisitForValue(sub_expr));
10182 HValue* value = Pop();
10183 if (expr->op() == Token::EQ_STRICT) {
10184 HConstant* nil_constant = nil == kNullValue
10185 ? graph()->GetConstantNull()
10186 : graph()->GetConstantUndefined();
10187 HCompareObjectEqAndBranch* instr =
10188 New<HCompareObjectEqAndBranch>(value, nil_constant);
10189 return ast_context()->ReturnControl(instr, expr->id());
10191 ASSERT_EQ(Token::EQ, expr->op());
10192 Type* type = expr->combined_type()->Is(Type::None())
10193 ? Type::Any(zone()) : expr->combined_type();
10194 HIfContinuation continuation;
10195 BuildCompareNil(value, type, &continuation);
10196 return ast_context()->ReturnContinuation(&continuation, expr->id());
10201 HInstruction* HOptimizedGraphBuilder::BuildThisFunction() {
10202 // If we share optimized code between different closures, the
10203 // this-function is not a constant, except inside an inlined body.
10204 if (function_state()->outer() != NULL) {
10205 return New<HConstant>(
10206 function_state()->compilation_info()->closure());
10208 return New<HThisFunction>();
10213 HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
10214 Handle<JSObject> boilerplate_object,
10215 AllocationSiteUsageContext* site_context) {
10216 NoObservableSideEffectsScope no_effects(this);
10217 InstanceType instance_type = boilerplate_object->map()->instance_type();
10218 ASSERT(instance_type == JS_ARRAY_TYPE || instance_type == JS_OBJECT_TYPE);
10220 HType type = instance_type == JS_ARRAY_TYPE
10221 ? HType::JSArray() : HType::JSObject();
10222 HValue* object_size_constant = Add<HConstant>(
10223 boilerplate_object->map()->instance_size());
10225 PretenureFlag pretenure_flag = isolate()->heap()->GetPretenureMode();
10226 if (FLAG_allocation_site_pretenuring) {
10227 pretenure_flag = site_context->current()->GetPretenureMode();
10228 Handle<AllocationSite> site(site_context->current());
10229 AllocationSite::AddDependentCompilationInfo(
10230 site, AllocationSite::TENURING, top_info());
10233 HInstruction* object = Add<HAllocate>(object_size_constant, type,
10234 pretenure_flag, instance_type, site_context->current());
10236 // If allocation folding reaches Page::kMaxRegularHeapObjectSize the
10237 // elements array may not get folded into the object. Hence, we set the
10238 // elements pointer to empty fixed array and let store elimination remove
10239 // this store in the folding case.
10240 HConstant* empty_fixed_array = Add<HConstant>(
10241 isolate()->factory()->empty_fixed_array());
10242 Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
10243 empty_fixed_array, INITIALIZING_STORE);
10245 BuildEmitObjectHeader(boilerplate_object, object);
10247 Handle<FixedArrayBase> elements(boilerplate_object->elements());
10248 int elements_size = (elements->length() > 0 &&
10249 elements->map() != isolate()->heap()->fixed_cow_array_map()) ?
10250 elements->Size() : 0;
10252 if (pretenure_flag == TENURED &&
10253 elements->map() == isolate()->heap()->fixed_cow_array_map() &&
10254 isolate()->heap()->InNewSpace(*elements)) {
10255 // If we would like to pretenure a fixed cow array, we must ensure that the
10256 // array is already in old space, otherwise we'll create too many old-to-
10257 // new-space pointers (overflowing the store buffer).
10258 elements = Handle<FixedArrayBase>(
10259 isolate()->factory()->CopyAndTenureFixedCOWArray(
10260 Handle<FixedArray>::cast(elements)));
10261 boilerplate_object->set_elements(*elements);
10264 HInstruction* object_elements = NULL;
10265 if (elements_size > 0) {
10266 HValue* object_elements_size = Add<HConstant>(elements_size);
10267 if (boilerplate_object->HasFastDoubleElements()) {
10268 object_elements = Add<HAllocate>(object_elements_size, HType::Tagged(),
10269 pretenure_flag, FIXED_DOUBLE_ARRAY_TYPE, site_context->current());
10271 object_elements = Add<HAllocate>(object_elements_size, HType::Tagged(),
10272 pretenure_flag, FIXED_ARRAY_TYPE, site_context->current());
10275 BuildInitElementsInObjectHeader(boilerplate_object, object, object_elements);
10277 // Copy object elements if non-COW.
10278 if (object_elements != NULL) {
10279 BuildEmitElements(boilerplate_object, elements, object_elements,
10283 // Copy in-object properties.
10284 if (boilerplate_object->map()->NumberOfFields() != 0) {
10285 BuildEmitInObjectProperties(boilerplate_object, object, site_context,
10292 void HOptimizedGraphBuilder::BuildEmitObjectHeader(
10293 Handle<JSObject> boilerplate_object,
10294 HInstruction* object) {
10295 ASSERT(boilerplate_object->properties()->length() == 0);
10297 Handle<Map> boilerplate_object_map(boilerplate_object->map());
10298 AddStoreMapConstant(object, boilerplate_object_map);
10300 Handle<Object> properties_field =
10301 Handle<Object>(boilerplate_object->properties(), isolate());
10302 ASSERT(*properties_field == isolate()->heap()->empty_fixed_array());
10303 HInstruction* properties = Add<HConstant>(properties_field);
10304 HObjectAccess access = HObjectAccess::ForPropertiesPointer();
10305 Add<HStoreNamedField>(object, access, properties);
10307 if (boilerplate_object->IsJSArray()) {
10308 Handle<JSArray> boilerplate_array =
10309 Handle<JSArray>::cast(boilerplate_object);
10310 Handle<Object> length_field =
10311 Handle<Object>(boilerplate_array->length(), isolate());
10312 HInstruction* length = Add<HConstant>(length_field);
10314 ASSERT(boilerplate_array->length()->IsSmi());
10315 Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(
10316 boilerplate_array->GetElementsKind()), length);
10321 void HOptimizedGraphBuilder::BuildInitElementsInObjectHeader(
10322 Handle<JSObject> boilerplate_object,
10323 HInstruction* object,
10324 HInstruction* object_elements) {
10325 ASSERT(boilerplate_object->properties()->length() == 0);
10326 if (object_elements == NULL) {
10327 Handle<Object> elements_field =
10328 Handle<Object>(boilerplate_object->elements(), isolate());
10329 object_elements = Add<HConstant>(elements_field);
10331 Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
10336 void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
10337 Handle<JSObject> boilerplate_object,
10338 HInstruction* object,
10339 AllocationSiteUsageContext* site_context,
10340 PretenureFlag pretenure_flag) {
10341 Handle<Map> boilerplate_map(boilerplate_object->map());
10342 Handle<DescriptorArray> descriptors(boilerplate_map->instance_descriptors());
10343 int limit = boilerplate_map->NumberOfOwnDescriptors();
10345 int copied_fields = 0;
10346 for (int i = 0; i < limit; i++) {
10347 PropertyDetails details = descriptors->GetDetails(i);
10348 if (details.type() != FIELD) continue;
10350 int index = descriptors->GetFieldIndex(i);
10351 int property_offset = boilerplate_object->GetInObjectPropertyOffset(index);
10352 Handle<Name> name(descriptors->GetKey(i));
10353 Handle<Object> value =
10354 Handle<Object>(boilerplate_object->InObjectPropertyAt(index),
10357 // The access for the store depends on the type of the boilerplate.
10358 HObjectAccess access = boilerplate_object->IsJSArray() ?
10359 HObjectAccess::ForJSArrayOffset(property_offset) :
10360 HObjectAccess::ForMapAndOffset(boilerplate_map, property_offset);
10362 if (value->IsJSObject()) {
10363 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
10364 Handle<AllocationSite> current_site = site_context->EnterNewScope();
10365 HInstruction* result =
10366 BuildFastLiteral(value_object, site_context);
10367 site_context->ExitScope(current_site, value_object);
10368 Add<HStoreNamedField>(object, access, result);
10370 Representation representation = details.representation();
10371 HInstruction* value_instruction;
10373 if (representation.IsDouble()) {
10374 // Allocate a HeapNumber box and store the value into it.
10375 HValue* heap_number_constant = Add<HConstant>(HeapNumber::kSize);
10376 // This heap number alloc does not have a corresponding
10377 // AllocationSite. That is okay because
10378 // 1) it's a child object of another object with a valid allocation site
10379 // 2) we can just use the mode of the parent object for pretenuring
10380 HInstruction* double_box =
10381 Add<HAllocate>(heap_number_constant, HType::HeapNumber(),
10382 pretenure_flag, HEAP_NUMBER_TYPE);
10383 AddStoreMapConstant(double_box,
10384 isolate()->factory()->heap_number_map());
10385 Add<HStoreNamedField>(double_box, HObjectAccess::ForHeapNumberValue(),
10386 Add<HConstant>(value));
10387 value_instruction = double_box;
10388 } else if (representation.IsSmi()) {
10389 value_instruction = value->IsUninitialized()
10390 ? graph()->GetConstant0()
10391 : Add<HConstant>(value);
10392 // Ensure that value is stored as smi.
10393 access = access.WithRepresentation(representation);
10395 value_instruction = Add<HConstant>(value);
10398 Add<HStoreNamedField>(object, access, value_instruction);
10402 int inobject_properties = boilerplate_object->map()->inobject_properties();
10403 HInstruction* value_instruction =
10404 Add<HConstant>(isolate()->factory()->one_pointer_filler_map());
10405 for (int i = copied_fields; i < inobject_properties; i++) {
10406 ASSERT(boilerplate_object->IsJSObject());
10407 int property_offset = boilerplate_object->GetInObjectPropertyOffset(i);
10408 HObjectAccess access =
10409 HObjectAccess::ForMapAndOffset(boilerplate_map, property_offset);
10410 Add<HStoreNamedField>(object, access, value_instruction);
10415 void HOptimizedGraphBuilder::BuildEmitElements(
10416 Handle<JSObject> boilerplate_object,
10417 Handle<FixedArrayBase> elements,
10418 HValue* object_elements,
10419 AllocationSiteUsageContext* site_context) {
10420 ElementsKind kind = boilerplate_object->map()->elements_kind();
10421 int elements_length = elements->length();
10422 HValue* object_elements_length = Add<HConstant>(elements_length);
10423 BuildInitializeElementsHeader(object_elements, kind, object_elements_length);
10425 // Copy elements backing store content.
10426 if (elements->IsFixedDoubleArray()) {
10427 BuildEmitFixedDoubleArray(elements, kind, object_elements);
10428 } else if (elements->IsFixedArray()) {
10429 BuildEmitFixedArray(elements, kind, object_elements,
10437 void HOptimizedGraphBuilder::BuildEmitFixedDoubleArray(
10438 Handle<FixedArrayBase> elements,
10440 HValue* object_elements) {
10441 HInstruction* boilerplate_elements = Add<HConstant>(elements);
10442 int elements_length = elements->length();
10443 for (int i = 0; i < elements_length; i++) {
10444 HValue* key_constant = Add<HConstant>(i);
10445 HInstruction* value_instruction =
10446 Add<HLoadKeyed>(boilerplate_elements, key_constant,
10447 static_cast<HValue*>(NULL), kind,
10448 ALLOW_RETURN_HOLE);
10449 HInstruction* store = Add<HStoreKeyed>(object_elements, key_constant,
10450 value_instruction, kind);
10451 store->SetFlag(HValue::kAllowUndefinedAsNaN);
10456 void HOptimizedGraphBuilder::BuildEmitFixedArray(
10457 Handle<FixedArrayBase> elements,
10459 HValue* object_elements,
10460 AllocationSiteUsageContext* site_context) {
10461 HInstruction* boilerplate_elements = Add<HConstant>(elements);
10462 int elements_length = elements->length();
10463 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
10464 for (int i = 0; i < elements_length; i++) {
10465 Handle<Object> value(fast_elements->get(i), isolate());
10466 HValue* key_constant = Add<HConstant>(i);
10467 if (value->IsJSObject()) {
10468 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
10469 Handle<AllocationSite> current_site = site_context->EnterNewScope();
10470 HInstruction* result =
10471 BuildFastLiteral(value_object, site_context);
10472 site_context->ExitScope(current_site, value_object);
10473 Add<HStoreKeyed>(object_elements, key_constant, result, kind);
10475 HInstruction* value_instruction =
10476 Add<HLoadKeyed>(boilerplate_elements, key_constant,
10477 static_cast<HValue*>(NULL), kind,
10478 ALLOW_RETURN_HOLE);
10479 Add<HStoreKeyed>(object_elements, key_constant, value_instruction, kind);
10485 void HOptimizedGraphBuilder::VisitThisFunction(ThisFunction* expr) {
10486 ASSERT(!HasStackOverflow());
10487 ASSERT(current_block() != NULL);
10488 ASSERT(current_block()->HasPredecessor());
10489 HInstruction* instr = BuildThisFunction();
10490 return ast_context()->ReturnInstruction(instr, expr->id());
10494 void HOptimizedGraphBuilder::VisitDeclarations(
10495 ZoneList<Declaration*>* declarations) {
10496 ASSERT(globals_.is_empty());
10497 AstVisitor::VisitDeclarations(declarations);
10498 if (!globals_.is_empty()) {
10499 Handle<FixedArray> array =
10500 isolate()->factory()->NewFixedArray(globals_.length(), TENURED);
10501 for (int i = 0; i < globals_.length(); ++i) array->set(i, *globals_.at(i));
10502 int flags = DeclareGlobalsEvalFlag::encode(current_info()->is_eval()) |
10503 DeclareGlobalsNativeFlag::encode(current_info()->is_native()) |
10504 DeclareGlobalsStrictMode::encode(current_info()->strict_mode());
10505 Add<HDeclareGlobals>(array, flags);
10511 void HOptimizedGraphBuilder::VisitVariableDeclaration(
10512 VariableDeclaration* declaration) {
10513 VariableProxy* proxy = declaration->proxy();
10514 VariableMode mode = declaration->mode();
10515 Variable* variable = proxy->var();
10516 bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY;
10517 switch (variable->location()) {
10518 case Variable::UNALLOCATED:
10519 globals_.Add(variable->name(), zone());
10520 globals_.Add(variable->binding_needs_init()
10521 ? isolate()->factory()->the_hole_value()
10522 : isolate()->factory()->undefined_value(), zone());
10524 case Variable::PARAMETER:
10525 case Variable::LOCAL:
10527 HValue* value = graph()->GetConstantHole();
10528 environment()->Bind(variable, value);
10531 case Variable::CONTEXT:
10533 HValue* value = graph()->GetConstantHole();
10534 HValue* context = environment()->context();
10535 HStoreContextSlot* store = Add<HStoreContextSlot>(
10536 context, variable->index(), HStoreContextSlot::kNoCheck, value);
10537 if (store->HasObservableSideEffects()) {
10538 Add<HSimulate>(proxy->id(), REMOVABLE_SIMULATE);
10542 case Variable::LOOKUP:
10543 return Bailout(kUnsupportedLookupSlotInDeclaration);
10548 void HOptimizedGraphBuilder::VisitFunctionDeclaration(
10549 FunctionDeclaration* declaration) {
10550 VariableProxy* proxy = declaration->proxy();
10551 Variable* variable = proxy->var();
10552 switch (variable->location()) {
10553 case Variable::UNALLOCATED: {
10554 globals_.Add(variable->name(), zone());
10555 Handle<SharedFunctionInfo> function = Compiler::BuildFunctionInfo(
10556 declaration->fun(), current_info()->script());
10557 // Check for stack-overflow exception.
10558 if (function.is_null()) return SetStackOverflow();
10559 globals_.Add(function, zone());
10562 case Variable::PARAMETER:
10563 case Variable::LOCAL: {
10564 CHECK_ALIVE(VisitForValue(declaration->fun()));
10565 HValue* value = Pop();
10566 BindIfLive(variable, value);
10569 case Variable::CONTEXT: {
10570 CHECK_ALIVE(VisitForValue(declaration->fun()));
10571 HValue* value = Pop();
10572 HValue* context = environment()->context();
10573 HStoreContextSlot* store = Add<HStoreContextSlot>(
10574 context, variable->index(), HStoreContextSlot::kNoCheck, value);
10575 if (store->HasObservableSideEffects()) {
10576 Add<HSimulate>(proxy->id(), REMOVABLE_SIMULATE);
10580 case Variable::LOOKUP:
10581 return Bailout(kUnsupportedLookupSlotInDeclaration);
10586 void HOptimizedGraphBuilder::VisitModuleDeclaration(
10587 ModuleDeclaration* declaration) {
10592 void HOptimizedGraphBuilder::VisitImportDeclaration(
10593 ImportDeclaration* declaration) {
10598 void HOptimizedGraphBuilder::VisitExportDeclaration(
10599 ExportDeclaration* declaration) {
10604 void HOptimizedGraphBuilder::VisitModuleLiteral(ModuleLiteral* module) {
10609 void HOptimizedGraphBuilder::VisitModuleVariable(ModuleVariable* module) {
10614 void HOptimizedGraphBuilder::VisitModulePath(ModulePath* module) {
10619 void HOptimizedGraphBuilder::VisitModuleUrl(ModuleUrl* module) {
10624 void HOptimizedGraphBuilder::VisitModuleStatement(ModuleStatement* stmt) {
10629 // Generators for inline runtime functions.
10630 // Support for types.
10631 void HOptimizedGraphBuilder::GenerateIsSmi(CallRuntime* call) {
10632 ASSERT(call->arguments()->length() == 1);
10633 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10634 HValue* value = Pop();
10635 HIsSmiAndBranch* result = New<HIsSmiAndBranch>(value);
10636 return ast_context()->ReturnControl(result, call->id());
10640 void HOptimizedGraphBuilder::GenerateIsSpecObject(CallRuntime* call) {
10641 ASSERT(call->arguments()->length() == 1);
10642 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10643 HValue* value = Pop();
10644 HHasInstanceTypeAndBranch* result =
10645 New<HHasInstanceTypeAndBranch>(value,
10646 FIRST_SPEC_OBJECT_TYPE,
10647 LAST_SPEC_OBJECT_TYPE);
10648 return ast_context()->ReturnControl(result, call->id());
10652 void HOptimizedGraphBuilder::GenerateIsFunction(CallRuntime* call) {
10653 ASSERT(call->arguments()->length() == 1);
10654 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10655 HValue* value = Pop();
10656 HHasInstanceTypeAndBranch* result =
10657 New<HHasInstanceTypeAndBranch>(value, JS_FUNCTION_TYPE);
10658 return ast_context()->ReturnControl(result, call->id());
10662 void HOptimizedGraphBuilder::GenerateIsMinusZero(CallRuntime* call) {
10663 ASSERT(call->arguments()->length() == 1);
10664 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10665 HValue* value = Pop();
10666 HCompareMinusZeroAndBranch* result = New<HCompareMinusZeroAndBranch>(value);
10667 return ast_context()->ReturnControl(result, call->id());
10671 void HOptimizedGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) {
10672 ASSERT(call->arguments()->length() == 1);
10673 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10674 HValue* value = Pop();
10675 HHasCachedArrayIndexAndBranch* result =
10676 New<HHasCachedArrayIndexAndBranch>(value);
10677 return ast_context()->ReturnControl(result, call->id());
10681 void HOptimizedGraphBuilder::GenerateIsArray(CallRuntime* call) {
10682 ASSERT(call->arguments()->length() == 1);
10683 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10684 HValue* value = Pop();
10685 HHasInstanceTypeAndBranch* result =
10686 New<HHasInstanceTypeAndBranch>(value, JS_ARRAY_TYPE);
10687 return ast_context()->ReturnControl(result, call->id());
10691 void HOptimizedGraphBuilder::GenerateIsRegExp(CallRuntime* call) {
10692 ASSERT(call->arguments()->length() == 1);
10693 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10694 HValue* value = Pop();
10695 HHasInstanceTypeAndBranch* result =
10696 New<HHasInstanceTypeAndBranch>(value, JS_REGEXP_TYPE);
10697 return ast_context()->ReturnControl(result, call->id());
10701 void HOptimizedGraphBuilder::GenerateIsObject(CallRuntime* call) {
10702 ASSERT(call->arguments()->length() == 1);
10703 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10704 HValue* value = Pop();
10705 HIsObjectAndBranch* result = New<HIsObjectAndBranch>(value);
10706 return ast_context()->ReturnControl(result, call->id());
10710 void HOptimizedGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) {
10711 return Bailout(kInlinedRuntimeFunctionIsNonNegativeSmi);
10715 void HOptimizedGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) {
10716 ASSERT(call->arguments()->length() == 1);
10717 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10718 HValue* value = Pop();
10719 HIsUndetectableAndBranch* result = New<HIsUndetectableAndBranch>(value);
10720 return ast_context()->ReturnControl(result, call->id());
10724 void HOptimizedGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf(
10725 CallRuntime* call) {
10726 return Bailout(kInlinedRuntimeFunctionIsStringWrapperSafeForDefaultValueOf);
10730 // Support for construct call checks.
10731 void HOptimizedGraphBuilder::GenerateIsConstructCall(CallRuntime* call) {
10732 ASSERT(call->arguments()->length() == 0);
10733 if (function_state()->outer() != NULL) {
10734 // We are generating graph for inlined function.
10735 HValue* value = function_state()->inlining_kind() == CONSTRUCT_CALL_RETURN
10736 ? graph()->GetConstantTrue()
10737 : graph()->GetConstantFalse();
10738 return ast_context()->ReturnValue(value);
10740 return ast_context()->ReturnControl(New<HIsConstructCallAndBranch>(),
10746 // Support for arguments.length and arguments[?].
10747 void HOptimizedGraphBuilder::GenerateArgumentsLength(CallRuntime* call) {
10748 // Our implementation of arguments (based on this stack frame or an
10749 // adapter below it) does not work for inlined functions. This runtime
10750 // function is blacklisted by AstNode::IsInlineable.
10751 ASSERT(function_state()->outer() == NULL);
10752 ASSERT(call->arguments()->length() == 0);
10753 HInstruction* elements = Add<HArgumentsElements>(false);
10754 HArgumentsLength* result = New<HArgumentsLength>(elements);
10755 return ast_context()->ReturnInstruction(result, call->id());
10759 void HOptimizedGraphBuilder::GenerateArguments(CallRuntime* call) {
10760 // Our implementation of arguments (based on this stack frame or an
10761 // adapter below it) does not work for inlined functions. This runtime
10762 // function is blacklisted by AstNode::IsInlineable.
10763 ASSERT(function_state()->outer() == NULL);
10764 ASSERT(call->arguments()->length() == 1);
10765 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10766 HValue* index = Pop();
10767 HInstruction* elements = Add<HArgumentsElements>(false);
10768 HInstruction* length = Add<HArgumentsLength>(elements);
10769 HInstruction* checked_index = Add<HBoundsCheck>(index, length);
10770 HAccessArgumentsAt* result = New<HAccessArgumentsAt>(
10771 elements, length, checked_index);
10772 return ast_context()->ReturnInstruction(result, call->id());
10776 // Support for accessing the class and value fields of an object.
10777 void HOptimizedGraphBuilder::GenerateClassOf(CallRuntime* call) {
10778 // The special form detected by IsClassOfTest is detected before we get here
10779 // and does not cause a bailout.
10780 return Bailout(kInlinedRuntimeFunctionClassOf);
10784 void HOptimizedGraphBuilder::GenerateValueOf(CallRuntime* call) {
10785 ASSERT(call->arguments()->length() == 1);
10786 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10787 HValue* object = Pop();
10789 IfBuilder if_objectisvalue(this);
10790 HValue* objectisvalue = if_objectisvalue.If<HHasInstanceTypeAndBranch>(
10791 object, JS_VALUE_TYPE);
10792 if_objectisvalue.Then();
10794 // Return the actual value.
10795 Push(Add<HLoadNamedField>(
10796 object, objectisvalue,
10797 HObjectAccess::ForObservableJSObjectOffset(
10798 JSValue::kValueOffset)));
10799 Add<HSimulate>(call->id(), FIXED_SIMULATE);
10801 if_objectisvalue.Else();
10803 // If the object is not a value return the object.
10805 Add<HSimulate>(call->id(), FIXED_SIMULATE);
10807 if_objectisvalue.End();
10808 return ast_context()->ReturnValue(Pop());
10812 void HOptimizedGraphBuilder::GenerateDateField(CallRuntime* call) {
10813 ASSERT(call->arguments()->length() == 2);
10814 ASSERT_NE(NULL, call->arguments()->at(1)->AsLiteral());
10815 Smi* index = Smi::cast(*(call->arguments()->at(1)->AsLiteral()->value()));
10816 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10817 HValue* date = Pop();
10818 HDateField* result = New<HDateField>(date, index);
10819 return ast_context()->ReturnInstruction(result, call->id());
10823 void HOptimizedGraphBuilder::GenerateOneByteSeqStringSetChar(
10824 CallRuntime* call) {
10825 ASSERT(call->arguments()->length() == 3);
10826 // We need to follow the evaluation order of full codegen.
10827 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
10828 CHECK_ALIVE(VisitForValue(call->arguments()->at(2)));
10829 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10830 HValue* string = Pop();
10831 HValue* value = Pop();
10832 HValue* index = Pop();
10833 Add<HSeqStringSetChar>(String::ONE_BYTE_ENCODING, string,
10835 Add<HSimulate>(call->id(), FIXED_SIMULATE);
10836 return ast_context()->ReturnValue(graph()->GetConstantUndefined());
10840 void HOptimizedGraphBuilder::GenerateTwoByteSeqStringSetChar(
10841 CallRuntime* call) {
10842 ASSERT(call->arguments()->length() == 3);
10843 // We need to follow the evaluation order of full codegen.
10844 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
10845 CHECK_ALIVE(VisitForValue(call->arguments()->at(2)));
10846 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10847 HValue* string = Pop();
10848 HValue* value = Pop();
10849 HValue* index = Pop();
10850 Add<HSeqStringSetChar>(String::TWO_BYTE_ENCODING, string,
10852 Add<HSimulate>(call->id(), FIXED_SIMULATE);
10853 return ast_context()->ReturnValue(graph()->GetConstantUndefined());
10857 void HOptimizedGraphBuilder::GenerateSetValueOf(CallRuntime* call) {
10858 ASSERT(call->arguments()->length() == 2);
10859 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10860 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
10861 HValue* value = Pop();
10862 HValue* object = Pop();
10864 // Check if object is a JSValue.
10865 IfBuilder if_objectisvalue(this);
10866 if_objectisvalue.If<HHasInstanceTypeAndBranch>(object, JS_VALUE_TYPE);
10867 if_objectisvalue.Then();
10869 // Create in-object property store to kValueOffset.
10870 Add<HStoreNamedField>(object,
10871 HObjectAccess::ForObservableJSObjectOffset(JSValue::kValueOffset),
10873 if (!ast_context()->IsEffect()) {
10876 Add<HSimulate>(call->id(), FIXED_SIMULATE);
10878 if_objectisvalue.Else();
10880 // Nothing to do in this case.
10881 if (!ast_context()->IsEffect()) {
10884 Add<HSimulate>(call->id(), FIXED_SIMULATE);
10886 if_objectisvalue.End();
10887 if (!ast_context()->IsEffect()) {
10890 return ast_context()->ReturnValue(value);
10894 // Fast support for charCodeAt(n).
10895 void HOptimizedGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) {
10896 ASSERT(call->arguments()->length() == 2);
10897 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10898 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
10899 HValue* index = Pop();
10900 HValue* string = Pop();
10901 HInstruction* result = BuildStringCharCodeAt(string, index);
10902 return ast_context()->ReturnInstruction(result, call->id());
10906 // Fast support for string.charAt(n) and string[n].
10907 void HOptimizedGraphBuilder::GenerateStringCharFromCode(CallRuntime* call) {
10908 ASSERT(call->arguments()->length() == 1);
10909 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10910 HValue* char_code = Pop();
10911 HInstruction* result = NewUncasted<HStringCharFromCode>(char_code);
10912 return ast_context()->ReturnInstruction(result, call->id());
10916 // Fast support for string.charAt(n) and string[n].
10917 void HOptimizedGraphBuilder::GenerateStringCharAt(CallRuntime* call) {
10918 ASSERT(call->arguments()->length() == 2);
10919 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10920 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
10921 HValue* index = Pop();
10922 HValue* string = Pop();
10923 HInstruction* char_code = BuildStringCharCodeAt(string, index);
10924 AddInstruction(char_code);
10925 HInstruction* result = NewUncasted<HStringCharFromCode>(char_code);
10926 return ast_context()->ReturnInstruction(result, call->id());
10930 // Fast support for object equality testing.
10931 void HOptimizedGraphBuilder::GenerateObjectEquals(CallRuntime* call) {
10932 ASSERT(call->arguments()->length() == 2);
10933 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10934 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
10935 HValue* right = Pop();
10936 HValue* left = Pop();
10937 HCompareObjectEqAndBranch* result =
10938 New<HCompareObjectEqAndBranch>(left, right);
10939 return ast_context()->ReturnControl(result, call->id());
10943 void HOptimizedGraphBuilder::GenerateLog(CallRuntime* call) {
10944 // %_Log is ignored in optimized code.
10945 return ast_context()->ReturnValue(graph()->GetConstantUndefined());
10949 // Fast support for StringAdd.
10950 void HOptimizedGraphBuilder::GenerateStringAdd(CallRuntime* call) {
10951 ASSERT_EQ(2, call->arguments()->length());
10952 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10953 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
10954 HValue* right = Pop();
10955 HValue* left = Pop();
10956 HInstruction* result = NewUncasted<HStringAdd>(left, right);
10957 return ast_context()->ReturnInstruction(result, call->id());
10961 // Fast support for SubString.
10962 void HOptimizedGraphBuilder::GenerateSubString(CallRuntime* call) {
10963 ASSERT_EQ(3, call->arguments()->length());
10964 CHECK_ALIVE(VisitExpressions(call->arguments()));
10965 PushArgumentsFromEnvironment(call->arguments()->length());
10966 HCallStub* result = New<HCallStub>(CodeStub::SubString, 3);
10967 return ast_context()->ReturnInstruction(result, call->id());
10971 // Fast support for StringCompare.
10972 void HOptimizedGraphBuilder::GenerateStringCompare(CallRuntime* call) {
10973 ASSERT_EQ(2, call->arguments()->length());
10974 CHECK_ALIVE(VisitExpressions(call->arguments()));
10975 PushArgumentsFromEnvironment(call->arguments()->length());
10976 HCallStub* result = New<HCallStub>(CodeStub::StringCompare, 2);
10977 return ast_context()->ReturnInstruction(result, call->id());
10981 // Support for direct calls from JavaScript to native RegExp code.
10982 void HOptimizedGraphBuilder::GenerateRegExpExec(CallRuntime* call) {
10983 ASSERT_EQ(4, call->arguments()->length());
10984 CHECK_ALIVE(VisitExpressions(call->arguments()));
10985 PushArgumentsFromEnvironment(call->arguments()->length());
10986 HCallStub* result = New<HCallStub>(CodeStub::RegExpExec, 4);
10987 return ast_context()->ReturnInstruction(result, call->id());
10991 void HOptimizedGraphBuilder::GenerateDoubleLo(CallRuntime* call) {
10992 ASSERT_EQ(1, call->arguments()->length());
10993 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10994 HValue* value = Pop();
10995 HInstruction* result = NewUncasted<HDoubleBits>(value, HDoubleBits::LOW);
10996 return ast_context()->ReturnInstruction(result, call->id());
11000 void HOptimizedGraphBuilder::GenerateDoubleHi(CallRuntime* call) {
11001 ASSERT_EQ(1, call->arguments()->length());
11002 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11003 HValue* value = Pop();
11004 HInstruction* result = NewUncasted<HDoubleBits>(value, HDoubleBits::HIGH);
11005 return ast_context()->ReturnInstruction(result, call->id());
11009 void HOptimizedGraphBuilder::GenerateConstructDouble(CallRuntime* call) {
11010 ASSERT_EQ(2, call->arguments()->length());
11011 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11012 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
11013 HValue* lo = Pop();
11014 HValue* hi = Pop();
11015 HInstruction* result = NewUncasted<HConstructDouble>(hi, lo);
11016 return ast_context()->ReturnInstruction(result, call->id());
11020 // Construct a RegExp exec result with two in-object properties.
11021 void HOptimizedGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) {
11022 ASSERT_EQ(3, call->arguments()->length());
11023 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11024 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
11025 CHECK_ALIVE(VisitForValue(call->arguments()->at(2)));
11026 HValue* input = Pop();
11027 HValue* index = Pop();
11028 HValue* length = Pop();
11029 HValue* result = BuildRegExpConstructResult(length, index, input);
11030 return ast_context()->ReturnValue(result);
11034 // Support for fast native caches.
11035 void HOptimizedGraphBuilder::GenerateGetFromCache(CallRuntime* call) {
11036 return Bailout(kInlinedRuntimeFunctionGetFromCache);
11040 // Fast support for number to string.
11041 void HOptimizedGraphBuilder::GenerateNumberToString(CallRuntime* call) {
11042 ASSERT_EQ(1, call->arguments()->length());
11043 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11044 HValue* number = Pop();
11045 HValue* result = BuildNumberToString(number, Type::Any(zone()));
11046 return ast_context()->ReturnValue(result);
11050 // Fast call for custom callbacks.
11051 void HOptimizedGraphBuilder::GenerateCallFunction(CallRuntime* call) {
11052 // 1 ~ The function to call is not itself an argument to the call.
11053 int arg_count = call->arguments()->length() - 1;
11054 ASSERT(arg_count >= 1); // There's always at least a receiver.
11056 CHECK_ALIVE(VisitExpressions(call->arguments()));
11057 // The function is the last argument
11058 HValue* function = Pop();
11059 // Push the arguments to the stack
11060 PushArgumentsFromEnvironment(arg_count);
11062 IfBuilder if_is_jsfunction(this);
11063 if_is_jsfunction.If<HHasInstanceTypeAndBranch>(function, JS_FUNCTION_TYPE);
11065 if_is_jsfunction.Then();
11067 HInstruction* invoke_result =
11068 Add<HInvokeFunction>(function, arg_count);
11069 if (!ast_context()->IsEffect()) {
11070 Push(invoke_result);
11072 Add<HSimulate>(call->id(), FIXED_SIMULATE);
11075 if_is_jsfunction.Else();
11077 HInstruction* call_result =
11078 Add<HCallFunction>(function, arg_count);
11079 if (!ast_context()->IsEffect()) {
11082 Add<HSimulate>(call->id(), FIXED_SIMULATE);
11084 if_is_jsfunction.End();
11086 if (ast_context()->IsEffect()) {
11087 // EffectContext::ReturnValue ignores the value, so we can just pass
11088 // 'undefined' (as we do not have the call result anymore).
11089 return ast_context()->ReturnValue(graph()->GetConstantUndefined());
11091 return ast_context()->ReturnValue(Pop());
11096 // Fast call to math functions.
11097 void HOptimizedGraphBuilder::GenerateMathPow(CallRuntime* call) {
11098 ASSERT_EQ(2, call->arguments()->length());
11099 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11100 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
11101 HValue* right = Pop();
11102 HValue* left = Pop();
11103 HInstruction* result = NewUncasted<HPower>(left, right);
11104 return ast_context()->ReturnInstruction(result, call->id());
11108 void HOptimizedGraphBuilder::GenerateMathLog(CallRuntime* call) {
11109 ASSERT(call->arguments()->length() == 1);
11110 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11111 HValue* value = Pop();
11112 HInstruction* result = NewUncasted<HUnaryMathOperation>(value, kMathLog);
11113 return ast_context()->ReturnInstruction(result, call->id());
11117 void HOptimizedGraphBuilder::GenerateMathSqrt(CallRuntime* call) {
11118 ASSERT(call->arguments()->length() == 1);
11119 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11120 HValue* value = Pop();
11121 HInstruction* result = NewUncasted<HUnaryMathOperation>(value, kMathSqrt);
11122 return ast_context()->ReturnInstruction(result, call->id());
11126 void HOptimizedGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) {
11127 ASSERT(call->arguments()->length() == 1);
11128 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11129 HValue* value = Pop();
11130 HGetCachedArrayIndex* result = New<HGetCachedArrayIndex>(value);
11131 return ast_context()->ReturnInstruction(result, call->id());
11135 void HOptimizedGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) {
11136 return Bailout(kInlinedRuntimeFunctionFastAsciiArrayJoin);
11140 // Support for generators.
11141 void HOptimizedGraphBuilder::GenerateGeneratorNext(CallRuntime* call) {
11142 return Bailout(kInlinedRuntimeFunctionGeneratorNext);
11146 void HOptimizedGraphBuilder::GenerateGeneratorThrow(CallRuntime* call) {
11147 return Bailout(kInlinedRuntimeFunctionGeneratorThrow);
11151 void HOptimizedGraphBuilder::GenerateDebugBreakInOptimizedCode(
11152 CallRuntime* call) {
11153 Add<HDebugBreak>();
11154 return ast_context()->ReturnValue(graph()->GetConstant0());
11158 #undef CHECK_BAILOUT
11162 HEnvironment::HEnvironment(HEnvironment* outer,
11164 Handle<JSFunction> closure,
11166 : closure_(closure),
11168 frame_type_(JS_FUNCTION),
11169 parameter_count_(0),
11170 specials_count_(1),
11176 ast_id_(BailoutId::None()),
11178 Initialize(scope->num_parameters() + 1, scope->num_stack_slots(), 0);
11182 HEnvironment::HEnvironment(Zone* zone, int parameter_count)
11183 : values_(0, zone),
11185 parameter_count_(parameter_count),
11186 specials_count_(1),
11192 ast_id_(BailoutId::None()),
11194 Initialize(parameter_count, 0, 0);
11198 HEnvironment::HEnvironment(const HEnvironment* other, Zone* zone)
11199 : values_(0, zone),
11200 frame_type_(JS_FUNCTION),
11201 parameter_count_(0),
11202 specials_count_(0),
11208 ast_id_(other->ast_id()),
11214 HEnvironment::HEnvironment(HEnvironment* outer,
11215 Handle<JSFunction> closure,
11216 FrameType frame_type,
11219 : closure_(closure),
11220 values_(arguments, zone),
11221 frame_type_(frame_type),
11222 parameter_count_(arguments),
11223 specials_count_(0),
11229 ast_id_(BailoutId::None()),
11234 void HEnvironment::Initialize(int parameter_count,
11236 int stack_height) {
11237 parameter_count_ = parameter_count;
11238 local_count_ = local_count;
11240 // Avoid reallocating the temporaries' backing store on the first Push.
11241 int total = parameter_count + specials_count_ + local_count + stack_height;
11242 values_.Initialize(total + 4, zone());
11243 for (int i = 0; i < total; ++i) values_.Add(NULL, zone());
11247 void HEnvironment::Initialize(const HEnvironment* other) {
11248 closure_ = other->closure();
11249 values_.AddAll(other->values_, zone());
11250 assigned_variables_.Union(other->assigned_variables_, zone());
11251 frame_type_ = other->frame_type_;
11252 parameter_count_ = other->parameter_count_;
11253 local_count_ = other->local_count_;
11254 if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy.
11255 entry_ = other->entry_;
11256 pop_count_ = other->pop_count_;
11257 push_count_ = other->push_count_;
11258 specials_count_ = other->specials_count_;
11259 ast_id_ = other->ast_id_;
11263 void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) {
11264 ASSERT(!block->IsLoopHeader());
11265 ASSERT(values_.length() == other->values_.length());
11267 int length = values_.length();
11268 for (int i = 0; i < length; ++i) {
11269 HValue* value = values_[i];
11270 if (value != NULL && value->IsPhi() && value->block() == block) {
11271 // There is already a phi for the i'th value.
11272 HPhi* phi = HPhi::cast(value);
11273 // Assert index is correct and that we haven't missed an incoming edge.
11274 ASSERT(phi->merged_index() == i || !phi->HasMergedIndex());
11275 ASSERT(phi->OperandCount() == block->predecessors()->length());
11276 phi->AddInput(other->values_[i]);
11277 } else if (values_[i] != other->values_[i]) {
11278 // There is a fresh value on the incoming edge, a phi is needed.
11279 ASSERT(values_[i] != NULL && other->values_[i] != NULL);
11280 HPhi* phi = block->AddNewPhi(i);
11281 HValue* old_value = values_[i];
11282 for (int j = 0; j < block->predecessors()->length(); j++) {
11283 phi->AddInput(old_value);
11285 phi->AddInput(other->values_[i]);
11286 this->values_[i] = phi;
11292 void HEnvironment::Bind(int index, HValue* value) {
11293 ASSERT(value != NULL);
11294 assigned_variables_.Add(index, zone());
11295 values_[index] = value;
11299 bool HEnvironment::HasExpressionAt(int index) const {
11300 return index >= parameter_count_ + specials_count_ + local_count_;
11304 bool HEnvironment::ExpressionStackIsEmpty() const {
11305 ASSERT(length() >= first_expression_index());
11306 return length() == first_expression_index();
11310 void HEnvironment::SetExpressionStackAt(int index_from_top, HValue* value) {
11311 int count = index_from_top + 1;
11312 int index = values_.length() - count;
11313 ASSERT(HasExpressionAt(index));
11314 // The push count must include at least the element in question or else
11315 // the new value will not be included in this environment's history.
11316 if (push_count_ < count) {
11317 // This is the same effect as popping then re-pushing 'count' elements.
11318 pop_count_ += (count - push_count_);
11319 push_count_ = count;
11321 values_[index] = value;
11325 void HEnvironment::Drop(int count) {
11326 for (int i = 0; i < count; ++i) {
11332 HEnvironment* HEnvironment::Copy() const {
11333 return new(zone()) HEnvironment(this, zone());
11337 HEnvironment* HEnvironment::CopyWithoutHistory() const {
11338 HEnvironment* result = Copy();
11339 result->ClearHistory();
11344 HEnvironment* HEnvironment::CopyAsLoopHeader(HBasicBlock* loop_header) const {
11345 HEnvironment* new_env = Copy();
11346 for (int i = 0; i < values_.length(); ++i) {
11347 HPhi* phi = loop_header->AddNewPhi(i);
11348 phi->AddInput(values_[i]);
11349 new_env->values_[i] = phi;
11351 new_env->ClearHistory();
11356 HEnvironment* HEnvironment::CreateStubEnvironment(HEnvironment* outer,
11357 Handle<JSFunction> target,
11358 FrameType frame_type,
11359 int arguments) const {
11360 HEnvironment* new_env =
11361 new(zone()) HEnvironment(outer, target, frame_type,
11362 arguments + 1, zone());
11363 for (int i = 0; i <= arguments; ++i) { // Include receiver.
11364 new_env->Push(ExpressionStackAt(arguments - i));
11366 new_env->ClearHistory();
11371 HEnvironment* HEnvironment::CopyForInlining(
11372 Handle<JSFunction> target,
11374 FunctionLiteral* function,
11375 HConstant* undefined,
11376 InliningKind inlining_kind) const {
11377 ASSERT(frame_type() == JS_FUNCTION);
11379 // Outer environment is a copy of this one without the arguments.
11380 int arity = function->scope()->num_parameters();
11382 HEnvironment* outer = Copy();
11383 outer->Drop(arguments + 1); // Including receiver.
11384 outer->ClearHistory();
11386 if (inlining_kind == CONSTRUCT_CALL_RETURN) {
11387 // Create artificial constructor stub environment. The receiver should
11388 // actually be the constructor function, but we pass the newly allocated
11389 // object instead, DoComputeConstructStubFrame() relies on that.
11390 outer = CreateStubEnvironment(outer, target, JS_CONSTRUCT, arguments);
11391 } else if (inlining_kind == GETTER_CALL_RETURN) {
11392 // We need an additional StackFrame::INTERNAL frame for restoring the
11393 // correct context.
11394 outer = CreateStubEnvironment(outer, target, JS_GETTER, arguments);
11395 } else if (inlining_kind == SETTER_CALL_RETURN) {
11396 // We need an additional StackFrame::INTERNAL frame for temporarily saving
11397 // the argument of the setter, see StoreStubCompiler::CompileStoreViaSetter.
11398 outer = CreateStubEnvironment(outer, target, JS_SETTER, arguments);
11401 if (arity != arguments) {
11402 // Create artificial arguments adaptation environment.
11403 outer = CreateStubEnvironment(outer, target, ARGUMENTS_ADAPTOR, arguments);
11406 HEnvironment* inner =
11407 new(zone()) HEnvironment(outer, function->scope(), target, zone());
11408 // Get the argument values from the original environment.
11409 for (int i = 0; i <= arity; ++i) { // Include receiver.
11410 HValue* push = (i <= arguments) ?
11411 ExpressionStackAt(arguments - i) : undefined;
11412 inner->SetValueAt(i, push);
11414 inner->SetValueAt(arity + 1, context());
11415 for (int i = arity + 2; i < inner->length(); ++i) {
11416 inner->SetValueAt(i, undefined);
11419 inner->set_ast_id(BailoutId::FunctionEntry());
11424 void HEnvironment::PrintTo(StringStream* stream) {
11425 for (int i = 0; i < length(); i++) {
11426 if (i == 0) stream->Add("parameters\n");
11427 if (i == parameter_count()) stream->Add("specials\n");
11428 if (i == parameter_count() + specials_count()) stream->Add("locals\n");
11429 if (i == parameter_count() + specials_count() + local_count()) {
11430 stream->Add("expressions\n");
11432 HValue* val = values_.at(i);
11433 stream->Add("%d: ", i);
11435 val->PrintNameTo(stream);
11437 stream->Add("NULL");
11445 void HEnvironment::PrintToStd() {
11446 HeapStringAllocator string_allocator;
11447 StringStream trace(&string_allocator);
11449 PrintF("%s", trace.ToCString().get());
11453 void HTracer::TraceCompilation(CompilationInfo* info) {
11454 Tag tag(this, "compilation");
11455 if (info->IsOptimizing()) {
11456 Handle<String> name = info->function()->debug_name();
11457 PrintStringProperty("name", name->ToCString().get());
11459 trace_.Add("method \"%s:%d\"\n",
11460 name->ToCString().get(),
11461 info->optimization_id());
11463 CodeStub::Major major_key = info->code_stub()->MajorKey();
11464 PrintStringProperty("name", CodeStub::MajorName(major_key, false));
11465 PrintStringProperty("method", "stub");
11467 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis()));
11471 void HTracer::TraceLithium(const char* name, LChunk* chunk) {
11472 ASSERT(!chunk->isolate()->concurrent_recompilation_enabled());
11473 AllowHandleDereference allow_deref;
11474 AllowDeferredHandleDereference allow_deferred_deref;
11475 Trace(name, chunk->graph(), chunk);
11479 void HTracer::TraceHydrogen(const char* name, HGraph* graph) {
11480 ASSERT(!graph->isolate()->concurrent_recompilation_enabled());
11481 AllowHandleDereference allow_deref;
11482 AllowDeferredHandleDereference allow_deferred_deref;
11483 Trace(name, graph, NULL);
11487 void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) {
11488 Tag tag(this, "cfg");
11489 PrintStringProperty("name", name);
11490 const ZoneList<HBasicBlock*>* blocks = graph->blocks();
11491 for (int i = 0; i < blocks->length(); i++) {
11492 HBasicBlock* current = blocks->at(i);
11493 Tag block_tag(this, "block");
11494 PrintBlockProperty("name", current->block_id());
11495 PrintIntProperty("from_bci", -1);
11496 PrintIntProperty("to_bci", -1);
11498 if (!current->predecessors()->is_empty()) {
11500 trace_.Add("predecessors");
11501 for (int j = 0; j < current->predecessors()->length(); ++j) {
11502 trace_.Add(" \"B%d\"", current->predecessors()->at(j)->block_id());
11506 PrintEmptyProperty("predecessors");
11509 if (current->end()->SuccessorCount() == 0) {
11510 PrintEmptyProperty("successors");
11513 trace_.Add("successors");
11514 for (HSuccessorIterator it(current->end()); !it.Done(); it.Advance()) {
11515 trace_.Add(" \"B%d\"", it.Current()->block_id());
11520 PrintEmptyProperty("xhandlers");
11524 trace_.Add("flags");
11525 if (current->IsLoopSuccessorDominator()) {
11526 trace_.Add(" \"dom-loop-succ\"");
11528 if (current->IsUnreachable()) {
11529 trace_.Add(" \"dead\"");
11531 if (current->is_osr_entry()) {
11532 trace_.Add(" \"osr\"");
11537 if (current->dominator() != NULL) {
11538 PrintBlockProperty("dominator", current->dominator()->block_id());
11541 PrintIntProperty("loop_depth", current->LoopNestingDepth());
11543 if (chunk != NULL) {
11544 int first_index = current->first_instruction_index();
11545 int last_index = current->last_instruction_index();
11548 LifetimePosition::FromInstructionIndex(first_index).Value());
11551 LifetimePosition::FromInstructionIndex(last_index).Value());
11555 Tag states_tag(this, "states");
11556 Tag locals_tag(this, "locals");
11557 int total = current->phis()->length();
11558 PrintIntProperty("size", current->phis()->length());
11559 PrintStringProperty("method", "None");
11560 for (int j = 0; j < total; ++j) {
11561 HPhi* phi = current->phis()->at(j);
11563 trace_.Add("%d ", phi->merged_index());
11564 phi->PrintNameTo(&trace_);
11566 phi->PrintTo(&trace_);
11572 Tag HIR_tag(this, "HIR");
11573 for (HInstructionIterator it(current); !it.Done(); it.Advance()) {
11574 HInstruction* instruction = it.Current();
11575 int uses = instruction->UseCount();
11577 trace_.Add("0 %d ", uses);
11578 instruction->PrintNameTo(&trace_);
11580 instruction->PrintTo(&trace_);
11581 if (FLAG_hydrogen_track_positions &&
11582 instruction->has_position() &&
11583 instruction->position().raw() != 0) {
11584 const HSourcePosition pos = instruction->position();
11585 trace_.Add(" pos:");
11586 if (pos.inlining_id() != 0) {
11587 trace_.Add("%d_", pos.inlining_id());
11589 trace_.Add("%d", pos.position());
11591 trace_.Add(" <|@\n");
11596 if (chunk != NULL) {
11597 Tag LIR_tag(this, "LIR");
11598 int first_index = current->first_instruction_index();
11599 int last_index = current->last_instruction_index();
11600 if (first_index != -1 && last_index != -1) {
11601 const ZoneList<LInstruction*>* instructions = chunk->instructions();
11602 for (int i = first_index; i <= last_index; ++i) {
11603 LInstruction* linstr = instructions->at(i);
11604 if (linstr != NULL) {
11607 LifetimePosition::FromInstructionIndex(i).Value());
11608 linstr->PrintTo(&trace_);
11609 trace_.Add(" [hir:");
11610 linstr->hydrogen_value()->PrintNameTo(&trace_);
11612 trace_.Add(" <|@\n");
11621 void HTracer::TraceLiveRanges(const char* name, LAllocator* allocator) {
11622 Tag tag(this, "intervals");
11623 PrintStringProperty("name", name);
11625 const Vector<LiveRange*>* fixed_d = allocator->fixed_double_live_ranges();
11626 for (int i = 0; i < fixed_d->length(); ++i) {
11627 TraceLiveRange(fixed_d->at(i), "fixed", allocator->zone());
11630 const Vector<LiveRange*>* fixed = allocator->fixed_live_ranges();
11631 for (int i = 0; i < fixed->length(); ++i) {
11632 TraceLiveRange(fixed->at(i), "fixed", allocator->zone());
11635 const ZoneList<LiveRange*>* live_ranges = allocator->live_ranges();
11636 for (int i = 0; i < live_ranges->length(); ++i) {
11637 TraceLiveRange(live_ranges->at(i), "object", allocator->zone());
11642 void HTracer::TraceLiveRange(LiveRange* range, const char* type,
11644 if (range != NULL && !range->IsEmpty()) {
11646 trace_.Add("%d %s", range->id(), type);
11647 if (range->HasRegisterAssigned()) {
11648 LOperand* op = range->CreateAssignedOperand(zone);
11649 int assigned_reg = op->index();
11650 if (op->IsDoubleRegister()) {
11651 trace_.Add(" \"%s\"",
11652 DoubleRegister::AllocationIndexToString(assigned_reg));
11653 } else if (op->IsFloat32x4Register()) {
11654 trace_.Add(" \"%s\"",
11655 SIMD128Register::AllocationIndexToString(assigned_reg));
11656 } else if (op->IsInt32x4Register()) {
11657 trace_.Add(" \"%s\"",
11658 SIMD128Register::AllocationIndexToString(assigned_reg));
11660 ASSERT(op->IsRegister());
11661 trace_.Add(" \"%s\"", Register::AllocationIndexToString(assigned_reg));
11663 } else if (range->IsSpilled()) {
11664 LOperand* op = range->TopLevel()->GetSpillOperand();
11665 if (op->IsDoubleStackSlot()) {
11666 trace_.Add(" \"double_stack:%d\"", op->index());
11667 } else if (op->IsFloat32x4StackSlot()) {
11668 trace_.Add(" \"float32x4_stack:%d\"", op->index());
11669 } else if (op->IsInt32x4StackSlot()) {
11670 trace_.Add(" \"int32x4_stack:%d\"", op->index());
11672 ASSERT(op->IsStackSlot());
11673 trace_.Add(" \"stack:%d\"", op->index());
11676 int parent_index = -1;
11677 if (range->IsChild()) {
11678 parent_index = range->parent()->id();
11680 parent_index = range->id();
11682 LOperand* op = range->FirstHint();
11683 int hint_index = -1;
11684 if (op != NULL && op->IsUnallocated()) {
11685 hint_index = LUnallocated::cast(op)->virtual_register();
11687 trace_.Add(" %d %d", parent_index, hint_index);
11688 UseInterval* cur_interval = range->first_interval();
11689 while (cur_interval != NULL && range->Covers(cur_interval->start())) {
11690 trace_.Add(" [%d, %d[",
11691 cur_interval->start().Value(),
11692 cur_interval->end().Value());
11693 cur_interval = cur_interval->next();
11696 UsePosition* current_pos = range->first_pos();
11697 while (current_pos != NULL) {
11698 if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) {
11699 trace_.Add(" %d M", current_pos->pos().Value());
11701 current_pos = current_pos->next();
11704 trace_.Add(" \"\"\n");
11709 void HTracer::FlushToFile() {
11710 AppendChars(filename_.start(), trace_.ToCString().get(), trace_.length(),
11716 void HStatistics::Initialize(CompilationInfo* info) {
11717 if (info->shared_info().is_null()) return;
11718 source_size_ += info->shared_info()->SourceSize();
11722 void HStatistics::Print() {
11723 PrintF("Timing results:\n");
11725 for (int i = 0; i < times_.length(); ++i) {
11729 for (int i = 0; i < names_.length(); ++i) {
11730 PrintF("%32s", names_[i]);
11731 double ms = times_[i].InMillisecondsF();
11732 double percent = times_[i].PercentOf(sum);
11733 PrintF(" %8.3f ms / %4.1f %% ", ms, percent);
11735 unsigned size = sizes_[i];
11736 double size_percent = static_cast<double>(size) * 100 / total_size_;
11737 PrintF(" %9u bytes / %4.1f %%\n", size, size_percent);
11740 PrintF("----------------------------------------"
11741 "---------------------------------------\n");
11742 TimeDelta total = create_graph_ + optimize_graph_ + generate_code_;
11743 PrintF("%32s %8.3f ms / %4.1f %% \n",
11745 create_graph_.InMillisecondsF(),
11746 create_graph_.PercentOf(total));
11747 PrintF("%32s %8.3f ms / %4.1f %% \n",
11749 optimize_graph_.InMillisecondsF(),
11750 optimize_graph_.PercentOf(total));
11751 PrintF("%32s %8.3f ms / %4.1f %% \n",
11752 "Generate and install code",
11753 generate_code_.InMillisecondsF(),
11754 generate_code_.PercentOf(total));
11755 PrintF("----------------------------------------"
11756 "---------------------------------------\n");
11757 PrintF("%32s %8.3f ms (%.1f times slower than full code gen)\n",
11759 total.InMillisecondsF(),
11760 total.TimesOf(full_code_gen_));
11762 double source_size_in_kb = static_cast<double>(source_size_) / 1024;
11763 double normalized_time = source_size_in_kb > 0
11764 ? total.InMillisecondsF() / source_size_in_kb
11766 double normalized_size_in_kb = source_size_in_kb > 0
11767 ? total_size_ / 1024 / source_size_in_kb
11769 PrintF("%32s %8.3f ms %7.3f kB allocated\n",
11770 "Average per kB source",
11771 normalized_time, normalized_size_in_kb);
11775 void HStatistics::SaveTiming(const char* name, TimeDelta time, unsigned size) {
11776 total_size_ += size;
11777 for (int i = 0; i < names_.length(); ++i) {
11778 if (strcmp(names_[i], name) == 0) {
11790 HPhase::~HPhase() {
11791 if (ShouldProduceTraceOutput()) {
11792 isolate()->GetHTracer()->TraceHydrogen(name(), graph_);
11796 graph_->Verify(false); // No full verify.
11800 } } // namespace v8::internal