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;
7802 if (receiver_map->is_observed()) return false;
7803 ASSERT(receiver_map->is_extensible());
7805 Drop(expr->arguments()->length());
7807 HValue* reduced_length;
7808 HValue* receiver = Pop();
7810 HValue* checked_object = AddCheckMap(receiver, receiver_map);
7811 HValue* length = Add<HLoadNamedField>(
7812 checked_object, static_cast<HValue*>(NULL),
7813 HObjectAccess::ForArrayLength(elements_kind));
7815 Drop(1); // Function.
7817 { NoObservableSideEffectsScope scope(this);
7818 IfBuilder length_checker(this);
7820 HValue* bounds_check = length_checker.If<HCompareNumericAndBranch>(
7821 length, graph()->GetConstant0(), Token::EQ);
7822 length_checker.Then();
7824 if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined());
7826 length_checker.Else();
7827 HValue* elements = AddLoadElements(checked_object);
7828 // Ensure that we aren't popping from a copy-on-write array.
7829 if (IsFastSmiOrObjectElementsKind(elements_kind)) {
7830 elements = BuildCopyElementsOnWrite(checked_object, elements,
7831 elements_kind, length);
7833 reduced_length = AddUncasted<HSub>(length, graph()->GetConstant1());
7834 result = AddElementAccess(elements, reduced_length, NULL,
7835 bounds_check, elements_kind, LOAD);
7836 Factory* factory = isolate()->factory();
7837 double nan_double = FixedDoubleArray::hole_nan_as_double();
7838 HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind)
7839 ? Add<HConstant>(factory->the_hole_value())
7840 : Add<HConstant>(nan_double);
7841 if (IsFastSmiOrObjectElementsKind(elements_kind)) {
7842 elements_kind = FAST_HOLEY_ELEMENTS;
7845 elements, reduced_length, hole, bounds_check, elements_kind, STORE);
7846 Add<HStoreNamedField>(
7847 checked_object, HObjectAccess::ForArrayLength(elements_kind),
7848 reduced_length, STORE_TO_INITIALIZED_ENTRY);
7850 if (!ast_context()->IsEffect()) Push(result);
7852 length_checker.End();
7854 result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top();
7855 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
7856 if (!ast_context()->IsEffect()) Drop(1);
7858 ast_context()->ReturnValue(result);
7862 if (receiver_map.is_null()) return false;
7863 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false;
7864 ElementsKind elements_kind = receiver_map->elements_kind();
7865 if (!IsFastElementsKind(elements_kind)) return false;
7866 if (receiver_map->is_observed()) return false;
7867 ASSERT(receiver_map->is_extensible());
7869 HValue* op_vals[] = {
7872 environment()->ExpressionStackAt(expr->arguments()->length())
7875 const int argc = expr->arguments()->length();
7876 // Includes receiver.
7877 PushArgumentsFromEnvironment(argc + 1);
7879 CallInterfaceDescriptor* descriptor =
7880 isolate()->call_descriptor(Isolate::CallHandler);
7882 ArrayPushStub stub(receiver_map->elements_kind(), argc);
7883 Handle<Code> code = stub.GetCode(isolate());
7884 HConstant* code_value = Add<HConstant>(code);
7886 ASSERT((sizeof(op_vals) / kPointerSize) ==
7887 descriptor->environment_length());
7889 HInstruction* call = New<HCallWithDescriptor>(
7890 code_value, argc + 1, descriptor,
7891 Vector<HValue*>(op_vals, descriptor->environment_length()));
7892 Drop(1); // Drop function.
7893 ast_context()->ReturnInstruction(call, expr->id());
7896 #define SIMD_NULLARY_OPERATION_CASE_ITEM(p1, p2, name, p4) \
7898 SIMD_NULLARY_OPERATIONS(SIMD_NULLARY_OPERATION_CASE_ITEM)
7899 #undef SIMD_NULLARY_OPERATION_CASE_ITEM
7900 if (CPU::SupportsSIMD128InCrankshaft() && argument_count == 1) {
7901 Drop(2); // Receiver and function.
7902 HInstruction* op = NewUncasted<HNullarySIMDOperation>(id);
7903 ast_context()->ReturnInstruction(op, expr->id());
7907 #define SIMD_UNARY_OPERATION_CASE_ITEM(p1, p2, name, p4, p5) \
7909 SIMD_UNARY_OPERATIONS(SIMD_UNARY_OPERATION_CASE_ITEM)
7910 #undef SIMD_UNARY_OPERATION_CASE_ITEM
7911 if (CPU::SupportsSIMD128InCrankshaft() && argument_count == 2) {
7912 HValue* argument = Pop();
7913 Drop(2); // Receiver and function.
7914 HInstruction* op = NewUncasted<HUnarySIMDOperation>(argument, id);
7915 ast_context()->ReturnInstruction(op, expr->id());
7919 #define SIMD_BINARY_OPERATION_CASE_ITEM(p1, p2, name, p4, p5, p6) \
7921 SIMD_BINARY_OPERATIONS(SIMD_BINARY_OPERATION_CASE_ITEM)
7922 #undef SIMD_BINARY_OPERATION_CASE_ITEM
7923 if (CPU::SupportsSIMD128InCrankshaft() && argument_count == 3) {
7924 HValue* right = Pop();
7925 HValue* left = Pop();
7926 Drop(2); // Receiver and function.
7927 HInstruction* op = NewUncasted<HBinarySIMDOperation>(left, right, id);
7928 ast_context()->ReturnInstruction(op, expr->id());
7932 #define SIMD_TERNARY_OPERATION_CASE_ITEM(p1, p2, name, p4, p5, p6, p7) \
7934 SIMD_TERNARY_OPERATIONS(SIMD_TERNARY_OPERATION_CASE_ITEM)
7935 #undef SIMD_TERNARY_OPERATION_CASE_ITEM
7936 if (CPU::SupportsSIMD128InCrankshaft() && argument_count == 4) {
7937 HValue* right = Pop();
7938 HValue* left = Pop();
7939 HValue* value = Pop();
7940 Drop(2); // Receiver and function.
7942 NewUncasted<HTernarySIMDOperation>(value, left, right, id);
7943 ast_context()->ReturnInstruction(op, expr->id());
7947 #define SIMD_QUARTERNARY_OPERATION_CASE_ITEM(p1, p2, name, p4, p5, p6, p7, p8) \
7949 SIMD_QUARTERNARY_OPERATIONS(SIMD_QUARTERNARY_OPERATION_CASE_ITEM)
7950 #undef SIMD_QUARTERNARY_OPERATION_CASE_ITEM
7951 if (CPU::SupportsSIMD128InCrankshaft() && argument_count == 5) {
7956 Drop(2); // Receiver and function.
7957 HValue* context = environment()->context();
7959 HQuarternarySIMDOperation::New(zone(), context, x, y, z, w, id);
7960 ast_context()->ReturnInstruction(op, expr->id());
7964 case kFloat32x4ArrayGetAt:
7965 case kInt32x4ArrayGetAt:
7966 if (CPU::SupportsSIMD128InCrankshaft() && argument_count == 2) {
7967 HValue* key = Pop();
7968 HValue* typed32x4_array = Pop();
7969 ASSERT(typed32x4_array == receiver);
7970 Drop(1); // Drop function.
7971 HInstruction* instr = BuildUncheckedMonomorphicElementAccess(
7972 typed32x4_array, key, NULL,
7973 receiver_map->instance_type() == JS_ARRAY_TYPE,
7974 receiver_map->elements_kind(),
7976 NEVER_RETURN_HOLE, // load_mode.
7978 ast_context()->ReturnValue(instr);
7982 case kFloat32x4ArraySetAt:
7983 case kInt32x4ArraySetAt:
7984 if (CPU::SupportsSIMD128InCrankshaft() && argument_count == 3) {
7985 HValue* value = Pop();
7986 HValue* key = Pop();
7987 HValue* typed32x4_array = Pop();
7988 ASSERT(typed32x4_array == receiver);
7989 Drop(1); // Drop function.
7990 // TODO(haitao): add STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS.
7991 KeyedAccessStoreMode store_mode = STANDARD_STORE;
7992 BuildUncheckedMonomorphicElementAccess(
7993 typed32x4_array, key, value,
7994 receiver_map->instance_type() == JS_ARRAY_TYPE,
7995 receiver_map->elements_kind(),
7997 NEVER_RETURN_HOLE, // load_mode.
8000 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
8001 ast_context()->ReturnValue(Pop());
8006 // Not yet supported for inlining.
8013 bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr,
8015 Handle<JSFunction> function = expr->target();
8016 int argc = expr->arguments()->length();
8017 SmallMapList receiver_maps;
8018 return TryInlineApiCall(function,
8027 bool HOptimizedGraphBuilder::TryInlineApiMethodCall(
8030 SmallMapList* receiver_maps) {
8031 Handle<JSFunction> function = expr->target();
8032 int argc = expr->arguments()->length();
8033 return TryInlineApiCall(function,
8042 bool HOptimizedGraphBuilder::TryInlineApiGetter(Handle<JSFunction> function,
8043 Handle<Map> receiver_map,
8045 SmallMapList receiver_maps(1, zone());
8046 receiver_maps.Add(receiver_map, zone());
8047 return TryInlineApiCall(function,
8048 NULL, // Receiver is on expression stack.
8056 bool HOptimizedGraphBuilder::TryInlineApiSetter(Handle<JSFunction> function,
8057 Handle<Map> receiver_map,
8059 SmallMapList receiver_maps(1, zone());
8060 receiver_maps.Add(receiver_map, zone());
8061 return TryInlineApiCall(function,
8062 NULL, // Receiver is on expression stack.
8070 bool HOptimizedGraphBuilder::TryInlineApiCall(Handle<JSFunction> function,
8072 SmallMapList* receiver_maps,
8075 ApiCallType call_type) {
8076 CallOptimization optimization(function);
8077 if (!optimization.is_simple_api_call()) return false;
8078 Handle<Map> holder_map;
8079 if (call_type == kCallApiFunction) {
8080 // Cannot embed a direct reference to the global proxy map
8081 // as it maybe dropped on deserialization.
8082 CHECK(!Serializer::enabled());
8083 ASSERT_EQ(0, receiver_maps->length());
8084 receiver_maps->Add(handle(
8085 function->context()->global_object()->global_receiver()->map()),
8088 CallOptimization::HolderLookup holder_lookup =
8089 CallOptimization::kHolderNotFound;
8090 Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType(
8091 receiver_maps->first(), &holder_lookup);
8092 if (holder_lookup == CallOptimization::kHolderNotFound) return false;
8094 if (FLAG_trace_inlining) {
8095 PrintF("Inlining api function ");
8096 function->ShortPrint();
8100 bool drop_extra = false;
8101 bool is_store = false;
8102 switch (call_type) {
8103 case kCallApiFunction:
8104 case kCallApiMethod:
8105 // Need to check that none of the receiver maps could have changed.
8106 Add<HCheckMaps>(receiver, receiver_maps);
8107 // Need to ensure the chain between receiver and api_holder is intact.
8108 if (holder_lookup == CallOptimization::kHolderFound) {
8109 AddCheckPrototypeMaps(api_holder, receiver_maps->first());
8111 ASSERT_EQ(holder_lookup, CallOptimization::kHolderIsReceiver);
8113 // Includes receiver.
8114 PushArgumentsFromEnvironment(argc + 1);
8115 // Drop function after call.
8118 case kCallApiGetter:
8119 // Receiver and prototype chain cannot have changed.
8121 ASSERT_EQ(NULL, receiver);
8122 // Receiver is on expression stack.
8124 Add<HPushArgument>(receiver);
8126 case kCallApiSetter:
8129 // Receiver and prototype chain cannot have changed.
8131 ASSERT_EQ(NULL, receiver);
8132 // Receiver and value are on expression stack.
8133 HValue* value = Pop();
8135 Add<HPushArgument>(receiver);
8136 Add<HPushArgument>(value);
8141 HValue* holder = NULL;
8142 switch (holder_lookup) {
8143 case CallOptimization::kHolderFound:
8144 holder = Add<HConstant>(api_holder);
8146 case CallOptimization::kHolderIsReceiver:
8149 case CallOptimization::kHolderNotFound:
8153 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
8154 Handle<Object> call_data_obj(api_call_info->data(), isolate());
8155 bool call_data_is_undefined = call_data_obj->IsUndefined();
8156 HValue* call_data = Add<HConstant>(call_data_obj);
8157 ApiFunction fun(v8::ToCData<Address>(api_call_info->callback()));
8158 ExternalReference ref = ExternalReference(&fun,
8159 ExternalReference::DIRECT_API_CALL,
8161 HValue* api_function_address = Add<HConstant>(ExternalReference(ref));
8163 HValue* op_vals[] = {
8164 Add<HConstant>(function),
8167 api_function_address,
8171 CallInterfaceDescriptor* descriptor =
8172 isolate()->call_descriptor(Isolate::ApiFunctionCall);
8174 CallApiFunctionStub stub(is_store, call_data_is_undefined, argc);
8175 Handle<Code> code = stub.GetCode(isolate());
8176 HConstant* code_value = Add<HConstant>(code);
8178 ASSERT((sizeof(op_vals) / kPointerSize) ==
8179 descriptor->environment_length());
8181 HInstruction* call = New<HCallWithDescriptor>(
8182 code_value, argc + 1, descriptor,
8183 Vector<HValue*>(op_vals, descriptor->environment_length()));
8185 if (drop_extra) Drop(1); // Drop function.
8186 ast_context()->ReturnInstruction(call, ast_id);
8191 bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
8192 ASSERT(expr->expression()->IsProperty());
8194 if (!expr->IsMonomorphic()) {
8197 Handle<Map> function_map = expr->GetReceiverTypes()->first();
8198 if (function_map->instance_type() != JS_FUNCTION_TYPE ||
8199 !expr->target()->shared()->HasBuiltinFunctionId() ||
8200 expr->target()->shared()->builtin_function_id() != kFunctionApply) {
8204 if (current_info()->scope()->arguments() == NULL) return false;
8206 ZoneList<Expression*>* args = expr->arguments();
8207 if (args->length() != 2) return false;
8209 VariableProxy* arg_two = args->at(1)->AsVariableProxy();
8210 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
8211 HValue* arg_two_value = LookupAndMakeLive(arg_two->var());
8212 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
8214 // Found pattern f.apply(receiver, arguments).
8215 CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true);
8216 HValue* receiver = Pop(); // receiver
8217 HValue* function = Pop(); // f
8220 if (function_state()->outer() == NULL) {
8221 HInstruction* elements = Add<HArgumentsElements>(false);
8222 HInstruction* length = Add<HArgumentsLength>(elements);
8223 HValue* wrapped_receiver = BuildWrapReceiver(receiver, function);
8224 HInstruction* result = New<HApplyArguments>(function,
8228 ast_context()->ReturnInstruction(result, expr->id());
8231 // We are inside inlined function and we know exactly what is inside
8232 // arguments object. But we need to be able to materialize at deopt.
8233 ASSERT_EQ(environment()->arguments_environment()->parameter_count(),
8234 function_state()->entry()->arguments_object()->arguments_count());
8235 HArgumentsObject* args = function_state()->entry()->arguments_object();
8236 const ZoneList<HValue*>* arguments_values = args->arguments_values();
8237 int arguments_count = arguments_values->length();
8239 Push(BuildWrapReceiver(receiver, function));
8240 for (int i = 1; i < arguments_count; i++) {
8241 Push(arguments_values->at(i));
8244 Handle<JSFunction> known_function;
8245 if (function->IsConstant() &&
8246 HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
8247 known_function = Handle<JSFunction>::cast(
8248 HConstant::cast(function)->handle(isolate()));
8249 int args_count = arguments_count - 1; // Excluding receiver.
8250 if (TryInlineApply(known_function, expr, args_count)) return true;
8253 PushArgumentsFromEnvironment(arguments_count);
8254 HInvokeFunction* call = New<HInvokeFunction>(
8255 function, known_function, arguments_count);
8256 Drop(1); // Function.
8257 ast_context()->ReturnInstruction(call, expr->id());
8263 HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function,
8264 Handle<JSFunction> target) {
8265 SharedFunctionInfo* shared = target->shared();
8266 if (shared->strict_mode() == SLOPPY && !shared->native()) {
8267 // Cannot embed a direct reference to the global proxy
8268 // as is it dropped on deserialization.
8269 CHECK(!Serializer::enabled());
8270 Handle<JSObject> global_receiver(
8271 target->context()->global_object()->global_receiver());
8272 return Add<HConstant>(global_receiver);
8274 return graph()->GetConstantUndefined();
8278 void HOptimizedGraphBuilder::VisitCall(Call* expr) {
8279 ASSERT(!HasStackOverflow());
8280 ASSERT(current_block() != NULL);
8281 ASSERT(current_block()->HasPredecessor());
8282 Expression* callee = expr->expression();
8283 int argument_count = expr->arguments()->length() + 1; // Plus receiver.
8284 HInstruction* call = NULL;
8286 Property* prop = callee->AsProperty();
8288 CHECK_ALIVE(VisitForValue(prop->obj()));
8289 HValue* receiver = Top();
8291 SmallMapList* types;
8292 ComputeReceiverTypes(expr, receiver, &types, zone());
8294 if (prop->key()->IsPropertyName() && types->length() > 0) {
8295 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
8296 PropertyAccessInfo info(this, LOAD, ToType(types->first()), name);
8297 if (!info.CanAccessAsMonomorphic(types)) {
8298 HandlePolymorphicCallNamed(expr, receiver, types, name);
8304 if (!prop->key()->IsPropertyName()) {
8305 CHECK_ALIVE(VisitForValue(prop->key()));
8309 CHECK_ALIVE(PushLoad(prop, receiver, key));
8310 HValue* function = Pop();
8312 if (FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
8314 // Push the function under the receiver.
8315 environment()->SetExpressionStackAt(0, function);
8319 if (function->IsConstant() &&
8320 HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
8321 Handle<JSFunction> known_function = Handle<JSFunction>::cast(
8322 HConstant::cast(function)->handle(isolate()));
8323 expr->set_target(known_function);
8325 if (TryCallApply(expr)) return;
8326 CHECK_ALIVE(VisitExpressions(expr->arguments()));
8328 Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>();
8329 if (TryInlineBuiltinMethodCall(expr, receiver, map)) {
8330 if (FLAG_trace_inlining) {
8331 PrintF("Inlining builtin ");
8332 known_function->ShortPrint();
8337 if (TryInlineApiMethodCall(expr, receiver, types)) return;
8339 // Wrap the receiver if necessary.
8340 if (NeedsWrappingFor(ToType(types->first()), known_function)) {
8341 // Since HWrapReceiver currently cannot actually wrap numbers and
8342 // strings, use the regular CallFunctionStub for method calls to wrap
8344 // TODO(verwaest): Support creation of value wrappers directly in
8346 call = New<HCallFunction>(
8347 function, argument_count, WRAP_AND_CALL);
8348 } else if (TryInlineCall(expr)) {
8351 call = BuildCallConstantFunction(known_function, argument_count);
8355 CHECK_ALIVE(VisitExpressions(expr->arguments()));
8356 CallFunctionFlags flags = receiver->type().IsJSObject()
8357 ? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD;
8358 call = New<HCallFunction>(function, argument_count, flags);
8360 PushArgumentsFromEnvironment(argument_count);
8363 VariableProxy* proxy = expr->expression()->AsVariableProxy();
8364 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) {
8365 return Bailout(kPossibleDirectCallToEval);
8368 // The function is on the stack in the unoptimized code during
8369 // evaluation of the arguments.
8370 CHECK_ALIVE(VisitForValue(expr->expression()));
8371 HValue* function = Top();
8372 bool global_call = proxy != NULL && proxy->var()->IsUnallocated();
8374 Variable* var = proxy->var();
8375 bool known_global_function = false;
8376 // If there is a global property cell for the name at compile time and
8377 // access check is not enabled we assume that the function will not change
8378 // and generate optimized code for calling the function.
8379 LookupResult lookup(isolate());
8380 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, LOAD);
8381 if (type == kUseCell &&
8382 !current_info()->global_object()->IsAccessCheckNeeded()) {
8383 Handle<GlobalObject> global(current_info()->global_object());
8384 known_global_function = expr->ComputeGlobalTarget(global, &lookup);
8386 if (known_global_function) {
8387 Add<HCheckValue>(function, expr->target());
8389 // Placeholder for the receiver.
8390 Push(graph()->GetConstantUndefined());
8391 CHECK_ALIVE(VisitExpressions(expr->arguments()));
8393 // Patch the global object on the stack by the expected receiver.
8394 HValue* receiver = ImplicitReceiverFor(function, expr->target());
8395 const int receiver_index = argument_count - 1;
8396 environment()->SetExpressionStackAt(receiver_index, receiver);
8398 if (TryInlineBuiltinFunctionCall(expr)) {
8399 if (FLAG_trace_inlining) {
8400 PrintF("Inlining builtin ");
8401 expr->target()->ShortPrint();
8406 if (TryInlineApiFunctionCall(expr, receiver)) return;
8407 if (TryInlineCall(expr)) return;
8409 PushArgumentsFromEnvironment(argument_count);
8410 call = BuildCallConstantFunction(expr->target(), argument_count);
8412 Push(graph()->GetConstantUndefined());
8413 CHECK_ALIVE(VisitExpressions(expr->arguments()));
8414 PushArgumentsFromEnvironment(argument_count);
8415 call = New<HCallFunction>(function, argument_count);
8418 } else if (expr->IsMonomorphic()) {
8419 Add<HCheckValue>(function, expr->target());
8421 Push(graph()->GetConstantUndefined());
8422 CHECK_ALIVE(VisitExpressions(expr->arguments()));
8424 HValue* receiver = ImplicitReceiverFor(function, expr->target());
8425 const int receiver_index = argument_count - 1;
8426 environment()->SetExpressionStackAt(receiver_index, receiver);
8428 if (TryInlineBuiltinFunctionCall(expr)) {
8429 if (FLAG_trace_inlining) {
8430 PrintF("Inlining builtin ");
8431 expr->target()->ShortPrint();
8436 if (TryInlineApiFunctionCall(expr, receiver)) return;
8438 if (TryInlineCall(expr)) return;
8440 call = PreProcessCall(New<HInvokeFunction>(
8441 function, expr->target(), argument_count));
8444 Push(graph()->GetConstantUndefined());
8445 CHECK_ALIVE(VisitExpressions(expr->arguments()));
8446 PushArgumentsFromEnvironment(argument_count);
8447 call = New<HCallFunction>(function, argument_count);
8451 Drop(1); // Drop the function.
8452 return ast_context()->ReturnInstruction(call, expr->id());
8456 void HOptimizedGraphBuilder::BuildInlinedCallNewArray(CallNew* expr) {
8457 NoObservableSideEffectsScope no_effects(this);
8459 int argument_count = expr->arguments()->length();
8460 // We should at least have the constructor on the expression stack.
8461 HValue* constructor = environment()->ExpressionStackAt(argument_count);
8463 ElementsKind kind = expr->elements_kind();
8464 Handle<AllocationSite> site = expr->allocation_site();
8465 ASSERT(!site.is_null());
8467 // Register on the site for deoptimization if the transition feedback changes.
8468 AllocationSite::AddDependentCompilationInfo(
8469 site, AllocationSite::TRANSITIONS, top_info());
8470 HInstruction* site_instruction = Add<HConstant>(site);
8472 // In the single constant argument case, we may have to adjust elements kind
8473 // to avoid creating a packed non-empty array.
8474 if (argument_count == 1 && !IsHoleyElementsKind(kind)) {
8475 HValue* argument = environment()->Top();
8476 if (argument->IsConstant()) {
8477 HConstant* constant_argument = HConstant::cast(argument);
8478 ASSERT(constant_argument->HasSmiValue());
8479 int constant_array_size = constant_argument->Integer32Value();
8480 if (constant_array_size != 0) {
8481 kind = GetHoleyElementsKind(kind);
8487 JSArrayBuilder array_builder(this,
8491 DISABLE_ALLOCATION_SITES);
8493 if (argument_count == 0) {
8494 new_object = array_builder.AllocateEmptyArray();
8495 } else if (argument_count == 1) {
8496 HValue* argument = environment()->Top();
8497 new_object = BuildAllocateArrayFromLength(&array_builder, argument);
8499 HValue* length = Add<HConstant>(argument_count);
8500 // Smi arrays need to initialize array elements with the hole because
8501 // bailout could occur if the arguments don't fit in a smi.
8503 // TODO(mvstanton): If all the arguments are constants in smi range, then
8504 // we could set fill_with_hole to false and save a few instructions.
8505 JSArrayBuilder::FillMode fill_mode = IsFastSmiElementsKind(kind)
8506 ? JSArrayBuilder::FILL_WITH_HOLE
8507 : JSArrayBuilder::DONT_FILL_WITH_HOLE;
8508 new_object = array_builder.AllocateArray(length, length, fill_mode);
8509 HValue* elements = array_builder.GetElementsLocation();
8510 for (int i = 0; i < argument_count; i++) {
8511 HValue* value = environment()->ExpressionStackAt(argument_count - i - 1);
8512 HValue* constant_i = Add<HConstant>(i);
8513 Add<HStoreKeyed>(elements, constant_i, value, kind);
8517 Drop(argument_count + 1); // drop constructor and args.
8518 ast_context()->ReturnValue(new_object);
8522 // Checks whether allocation using the given constructor can be inlined.
8523 static bool IsAllocationInlineable(Handle<JSFunction> constructor) {
8524 return constructor->has_initial_map() &&
8525 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE &&
8526 constructor->initial_map()->instance_size() < HAllocate::kMaxInlineSize &&
8527 constructor->initial_map()->InitialPropertiesLength() == 0;
8531 bool HOptimizedGraphBuilder::IsCallNewArrayInlineable(CallNew* expr) {
8532 Handle<JSFunction> caller = current_info()->closure();
8533 Handle<JSFunction> target(isolate()->native_context()->array_function(),
8535 int argument_count = expr->arguments()->length();
8536 // We should have the function plus array arguments on the environment stack.
8537 ASSERT(environment()->length() >= (argument_count + 1));
8538 Handle<AllocationSite> site = expr->allocation_site();
8539 ASSERT(!site.is_null());
8541 bool inline_ok = false;
8542 if (site->CanInlineCall()) {
8543 // We also want to avoid inlining in certain 1 argument scenarios.
8544 if (argument_count == 1) {
8545 HValue* argument = Top();
8546 if (argument->IsConstant()) {
8547 // Do not inline if the constant length argument is not a smi or
8548 // outside the valid range for a fast array.
8549 HConstant* constant_argument = HConstant::cast(argument);
8550 if (constant_argument->HasSmiValue()) {
8551 int value = constant_argument->Integer32Value();
8552 inline_ok = value >= 0 &&
8553 value < JSObject::kInitialMaxFastElementArray;
8555 TraceInline(target, caller,
8556 "Length outside of valid array range");
8566 TraceInline(target, caller, "AllocationSite requested no inlining.");
8570 TraceInline(target, caller, NULL);
8576 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
8577 ASSERT(!HasStackOverflow());
8578 ASSERT(current_block() != NULL);
8579 ASSERT(current_block()->HasPredecessor());
8580 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
8581 int argument_count = expr->arguments()->length() + 1; // Plus constructor.
8582 Factory* factory = isolate()->factory();
8584 // The constructor function is on the stack in the unoptimized code
8585 // during evaluation of the arguments.
8586 CHECK_ALIVE(VisitForValue(expr->expression()));
8587 HValue* function = Top();
8588 CHECK_ALIVE(VisitExpressions(expr->arguments()));
8590 if (FLAG_inline_construct &&
8591 expr->IsMonomorphic() &&
8592 IsAllocationInlineable(expr->target())) {
8593 Handle<JSFunction> constructor = expr->target();
8594 HValue* check = Add<HCheckValue>(function, constructor);
8596 // Force completion of inobject slack tracking before generating
8597 // allocation code to finalize instance size.
8598 if (constructor->shared()->IsInobjectSlackTrackingInProgress()) {
8599 constructor->shared()->CompleteInobjectSlackTracking();
8602 // Calculate instance size from initial map of constructor.
8603 ASSERT(constructor->has_initial_map());
8604 Handle<Map> initial_map(constructor->initial_map());
8605 int instance_size = initial_map->instance_size();
8606 ASSERT(initial_map->InitialPropertiesLength() == 0);
8608 // Allocate an instance of the implicit receiver object.
8609 HValue* size_in_bytes = Add<HConstant>(instance_size);
8610 HAllocationMode allocation_mode;
8611 if (FLAG_pretenuring_call_new) {
8612 if (FLAG_allocation_site_pretenuring) {
8613 // Try to use pretenuring feedback.
8614 Handle<AllocationSite> allocation_site = expr->allocation_site();
8615 allocation_mode = HAllocationMode(allocation_site);
8616 // Take a dependency on allocation site.
8617 AllocationSite::AddDependentCompilationInfo(allocation_site,
8618 AllocationSite::TENURING,
8621 allocation_mode = HAllocationMode(
8622 isolate()->heap()->GetPretenureMode());
8626 HAllocate* receiver =
8627 BuildAllocate(size_in_bytes, HType::JSObject(), JS_OBJECT_TYPE,
8629 receiver->set_known_initial_map(initial_map);
8631 // Load the initial map from the constructor.
8632 HValue* constructor_value = Add<HConstant>(constructor);
8633 HValue* initial_map_value =
8634 Add<HLoadNamedField>(constructor_value, static_cast<HValue*>(NULL),
8635 HObjectAccess::ForMapAndOffset(
8636 handle(constructor->map()),
8637 JSFunction::kPrototypeOrInitialMapOffset));
8639 // Initialize map and fields of the newly allocated object.
8640 { NoObservableSideEffectsScope no_effects(this);
8641 ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE);
8642 Add<HStoreNamedField>(receiver,
8643 HObjectAccess::ForMapAndOffset(initial_map, JSObject::kMapOffset),
8645 HValue* empty_fixed_array = Add<HConstant>(factory->empty_fixed_array());
8646 Add<HStoreNamedField>(receiver,
8647 HObjectAccess::ForMapAndOffset(initial_map,
8648 JSObject::kPropertiesOffset),
8650 Add<HStoreNamedField>(receiver,
8651 HObjectAccess::ForMapAndOffset(initial_map,
8652 JSObject::kElementsOffset),
8654 if (initial_map->inobject_properties() != 0) {
8655 HConstant* undefined = graph()->GetConstantUndefined();
8656 for (int i = 0; i < initial_map->inobject_properties(); i++) {
8657 int property_offset = initial_map->GetInObjectPropertyOffset(i);
8658 Add<HStoreNamedField>(receiver,
8659 HObjectAccess::ForMapAndOffset(initial_map, property_offset),
8665 // Replace the constructor function with a newly allocated receiver using
8666 // the index of the receiver from the top of the expression stack.
8667 const int receiver_index = argument_count - 1;
8668 ASSERT(environment()->ExpressionStackAt(receiver_index) == function);
8669 environment()->SetExpressionStackAt(receiver_index, receiver);
8671 if (TryInlineConstruct(expr, receiver)) return;
8673 // TODO(mstarzinger): For now we remove the previous HAllocate and all
8674 // corresponding instructions and instead add HPushArgument for the
8675 // arguments in case inlining failed. What we actually should do is for
8676 // inlining to try to build a subgraph without mutating the parent graph.
8677 HInstruction* instr = current_block()->last();
8678 while (instr != initial_map_value) {
8679 HInstruction* prev_instr = instr->previous();
8680 instr->DeleteAndReplaceWith(NULL);
8683 initial_map_value->DeleteAndReplaceWith(NULL);
8684 receiver->DeleteAndReplaceWith(NULL);
8685 check->DeleteAndReplaceWith(NULL);
8686 environment()->SetExpressionStackAt(receiver_index, function);
8687 HInstruction* call =
8688 PreProcessCall(New<HCallNew>(function, argument_count));
8689 return ast_context()->ReturnInstruction(call, expr->id());
8691 // The constructor function is both an operand to the instruction and an
8692 // argument to the construct call.
8693 Handle<JSFunction> array_function(
8694 isolate()->native_context()->array_function(), isolate());
8695 bool use_call_new_array = expr->target().is_identical_to(array_function);
8696 if (use_call_new_array && IsCallNewArrayInlineable(expr)) {
8697 // Verify we are still calling the array function for our native context.
8698 Add<HCheckValue>(function, array_function);
8699 BuildInlinedCallNewArray(expr);
8704 if (use_call_new_array) {
8705 Add<HCheckValue>(function, array_function);
8706 call = New<HCallNewArray>(function, argument_count,
8707 expr->elements_kind());
8709 call = New<HCallNew>(function, argument_count);
8711 PreProcessCall(call);
8712 return ast_context()->ReturnInstruction(call, expr->id());
8717 // Support for generating inlined runtime functions.
8719 // Lookup table for generators for runtime calls that are generated inline.
8720 // Elements of the table are member pointers to functions of
8721 // HOptimizedGraphBuilder.
8722 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \
8723 &HOptimizedGraphBuilder::Generate##Name,
8725 const HOptimizedGraphBuilder::InlineFunctionGenerator
8726 HOptimizedGraphBuilder::kInlineFunctionGenerators[] = {
8727 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
8728 INLINE_OPTIMIZED_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
8730 #undef INLINE_FUNCTION_GENERATOR_ADDRESS
8733 template <class ViewClass>
8734 void HGraphBuilder::BuildArrayBufferViewInitialization(
8737 HValue* byte_offset,
8738 HValue* byte_length) {
8740 for (int offset = ViewClass::kSize;
8741 offset < ViewClass::kSizeWithInternalFields;
8742 offset += kPointerSize) {
8743 Add<HStoreNamedField>(obj,
8744 HObjectAccess::ForObservableJSObjectOffset(offset),
8745 graph()->GetConstant0());
8748 Add<HStoreNamedField>(
8750 HObjectAccess::ForJSArrayBufferViewByteOffset(),
8752 Add<HStoreNamedField>(
8754 HObjectAccess::ForJSArrayBufferViewByteLength(),
8757 if (buffer != NULL) {
8758 Add<HStoreNamedField>(
8760 HObjectAccess::ForJSArrayBufferViewBuffer(), buffer);
8761 HObjectAccess weak_first_view_access =
8762 HObjectAccess::ForJSArrayBufferWeakFirstView();
8763 Add<HStoreNamedField>(obj,
8764 HObjectAccess::ForJSArrayBufferViewWeakNext(),
8765 Add<HLoadNamedField>(buffer,
8766 static_cast<HValue*>(NULL),
8767 weak_first_view_access));
8768 Add<HStoreNamedField>(buffer, weak_first_view_access, obj);
8770 Add<HStoreNamedField>(
8772 HObjectAccess::ForJSArrayBufferViewBuffer(),
8773 Add<HConstant>(static_cast<int32_t>(0)));
8774 Add<HStoreNamedField>(obj,
8775 HObjectAccess::ForJSArrayBufferViewWeakNext(),
8776 graph()->GetConstantUndefined());
8781 void HOptimizedGraphBuilder::GenerateDataViewInitialize(
8782 CallRuntime* expr) {
8783 ZoneList<Expression*>* arguments = expr->arguments();
8785 NoObservableSideEffectsScope scope(this);
8786 ASSERT(arguments->length()== 4);
8787 CHECK_ALIVE(VisitForValue(arguments->at(0)));
8788 HValue* obj = Pop();
8790 CHECK_ALIVE(VisitForValue(arguments->at(1)));
8791 HValue* buffer = Pop();
8793 CHECK_ALIVE(VisitForValue(arguments->at(2)));
8794 HValue* byte_offset = Pop();
8796 CHECK_ALIVE(VisitForValue(arguments->at(3)));
8797 HValue* byte_length = Pop();
8799 BuildArrayBufferViewInitialization<JSDataView>(
8800 obj, buffer, byte_offset, byte_length);
8804 static Handle<Map> TypedArrayMap(Isolate* isolate,
8805 ExternalArrayType array_type,
8806 ElementsKind target_kind) {
8807 Handle<Context> native_context = isolate->native_context();
8808 Handle<JSFunction> fun;
8809 switch (array_type) {
8810 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
8811 case kExternal##Type##Array: \
8812 fun = Handle<JSFunction>(native_context->type##_array_fun()); \
8815 TYPED_ARRAYS(TYPED_ARRAY_CASE)
8816 #undef TYPED_ARRAY_CASE
8818 Handle<Map> map(fun->initial_map());
8819 return Map::AsElementsKind(map, target_kind);
8823 HValue* HOptimizedGraphBuilder::BuildAllocateExternalElements(
8824 ExternalArrayType array_type,
8825 bool is_zero_byte_offset,
8826 HValue* buffer, HValue* byte_offset, HValue* length) {
8827 Handle<Map> external_array_map(
8828 isolate()->heap()->MapForExternalArrayType(array_type));
8831 Add<HConstant>(ExternalArray::kAlignedSize),
8834 external_array_map->instance_type());
8836 AddStoreMapConstant(elements, external_array_map);
8838 HValue* backing_store = Add<HLoadNamedField>(
8839 buffer, static_cast<HValue*>(NULL),
8840 HObjectAccess::ForJSArrayBufferBackingStore());
8842 HValue* typed_array_start;
8843 if (is_zero_byte_offset) {
8844 typed_array_start = backing_store;
8846 HInstruction* external_pointer =
8847 AddUncasted<HAdd>(backing_store, byte_offset);
8848 // Arguments are checked prior to call to TypedArrayInitialize,
8849 // including byte_offset.
8850 external_pointer->ClearFlag(HValue::kCanOverflow);
8851 typed_array_start = external_pointer;
8855 Add<HStoreNamedField>(elements,
8856 HObjectAccess::ForExternalArrayExternalPointer(),
8859 Add<HStoreNamedField>(elements,
8860 HObjectAccess::ForFixedArrayLength(), length);
8865 HValue* HOptimizedGraphBuilder::BuildAllocateFixedTypedArray(
8866 ExternalArrayType array_type, size_t element_size,
8867 ElementsKind fixed_elements_kind,
8868 HValue* byte_length, HValue* length) {
8870 (FixedTypedArrayBase::kHeaderSize & kObjectAlignmentMask) == 0);
8873 // if fixed array's elements are not aligned to object's alignment,
8874 // we need to align the whole array to object alignment.
8875 if (element_size % kObjectAlignment != 0) {
8876 total_size = BuildObjectSizeAlignment(
8877 byte_length, FixedTypedArrayBase::kHeaderSize);
8879 total_size = AddUncasted<HAdd>(byte_length,
8880 Add<HConstant>(FixedTypedArrayBase::kHeaderSize));
8881 total_size->ClearFlag(HValue::kCanOverflow);
8884 Handle<Map> fixed_typed_array_map(
8885 isolate()->heap()->MapForFixedTypedArray(array_type));
8887 Add<HAllocate>(total_size, HType::Tagged(),
8889 fixed_typed_array_map->instance_type());
8890 AddStoreMapConstant(elements, fixed_typed_array_map);
8892 Add<HStoreNamedField>(elements,
8893 HObjectAccess::ForFixedArrayLength(),
8896 HValue* filler = Add<HConstant>(static_cast<int32_t>(0));
8897 if (IsFixedFloat32x4ElementsKind(fixed_elements_kind)) {
8898 if (CPU::SupportsSIMD128InCrankshaft()) {
8899 filler = AddUncasted<HNullarySIMDOperation>(kFloat32x4Zero);
8901 HValue* size = Add<HConstant>(Float32x4::kSize);
8902 filler = Add<HAllocate>(size, HType::Tagged(), NOT_TENURED,
8903 Float32x4::kInstanceType);
8904 AddStoreMapConstant(filler, isolate()->factory()->float32x4_map());
8905 HValue* zero = Add<HConstant>(static_cast<double>(0.0));
8906 Add<HStoreNamedField>(filler, HObjectAccess::ForSIMD128XYLanes(), zero);
8907 Add<HStoreNamedField>(filler, HObjectAccess::ForSIMD128ZWLanes(), zero);
8909 } else if (IsFixedInt32x4ElementsKind(fixed_elements_kind)) {
8910 if (CPU::SupportsSIMD128InCrankshaft()) {
8911 filler = AddUncasted<HNullarySIMDOperation>(kInt32x4Zero);
8913 HValue* size = Add<HConstant>(Int32x4::kSize);
8914 filler = Add<HAllocate>(size, HType::Tagged(), NOT_TENURED,
8915 Int32x4::kInstanceType);
8916 AddStoreMapConstant(filler, isolate()->factory()->int32x4_map());
8917 HValue* zero = Add<HConstant>(static_cast<double>(0.0));
8918 Add<HStoreNamedField>(filler, HObjectAccess::ForSIMD128XYLanes(), zero);
8919 Add<HStoreNamedField>(filler, HObjectAccess::ForSIMD128ZWLanes(), zero);
8924 LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement);
8926 HValue* key = builder.BeginBody(
8927 Add<HConstant>(static_cast<int32_t>(0)),
8929 Add<HStoreKeyed>(elements, key, filler, fixed_elements_kind);
8933 Add<HStoreNamedField>(
8934 elements, HObjectAccess::ForFixedArrayLength(), length);
8939 void HOptimizedGraphBuilder::GenerateTypedArrayInitialize(
8940 CallRuntime* expr) {
8941 ZoneList<Expression*>* arguments = expr->arguments();
8943 NoObservableSideEffectsScope scope(this);
8944 static const int kObjectArg = 0;
8945 static const int kArrayIdArg = 1;
8946 static const int kBufferArg = 2;
8947 static const int kByteOffsetArg = 3;
8948 static const int kByteLengthArg = 4;
8949 static const int kArgsLength = 5;
8950 ASSERT(arguments->length() == kArgsLength);
8953 CHECK_ALIVE(VisitForValue(arguments->at(kObjectArg)));
8954 HValue* obj = Pop();
8956 ASSERT(arguments->at(kArrayIdArg)->node_type() == AstNode::kLiteral);
8957 Handle<Object> value =
8958 static_cast<Literal*>(arguments->at(kArrayIdArg))->value();
8959 ASSERT(value->IsSmi());
8960 int array_id = Smi::cast(*value)->value();
8963 if (!arguments->at(kBufferArg)->IsNullLiteral()) {
8964 CHECK_ALIVE(VisitForValue(arguments->at(kBufferArg)));
8970 HValue* byte_offset;
8971 bool is_zero_byte_offset;
8973 if (arguments->at(kByteOffsetArg)->node_type() == AstNode::kLiteral
8974 && Smi::FromInt(0) ==
8975 *static_cast<Literal*>(arguments->at(kByteOffsetArg))->value()) {
8976 byte_offset = Add<HConstant>(static_cast<int32_t>(0));
8977 is_zero_byte_offset = true;
8979 CHECK_ALIVE(VisitForValue(arguments->at(kByteOffsetArg)));
8980 byte_offset = Pop();
8981 is_zero_byte_offset = false;
8982 ASSERT(buffer != NULL);
8985 CHECK_ALIVE(VisitForValue(arguments->at(kByteLengthArg)));
8986 HValue* byte_length = Pop();
8988 IfBuilder byte_offset_smi(this);
8990 if (!is_zero_byte_offset) {
8991 byte_offset_smi.If<HIsSmiAndBranch>(byte_offset);
8992 byte_offset_smi.Then();
8995 ExternalArrayType array_type =
8996 kExternalInt8Array; // Bogus initialization.
8997 size_t element_size = 1; // Bogus initialization.
8998 ElementsKind external_elements_kind = // Bogus initialization.
8999 EXTERNAL_INT8_ELEMENTS;
9000 ElementsKind fixed_elements_kind = // Bogus initialization.
9002 Runtime::ArrayIdToTypeAndSize(array_id,
9004 &external_elements_kind,
9005 &fixed_elements_kind,
9009 { // byte_offset is Smi.
9010 BuildArrayBufferViewInitialization<JSTypedArray>(
9011 obj, buffer, byte_offset, byte_length);
9014 HInstruction* length = AddUncasted<HDiv>(byte_length,
9015 Add<HConstant>(static_cast<int32_t>(element_size)));
9017 Add<HStoreNamedField>(obj,
9018 HObjectAccess::ForJSTypedArrayLength(),
9022 if (buffer != NULL) {
9023 elements = BuildAllocateExternalElements(
9024 array_type, is_zero_byte_offset, buffer, byte_offset, length);
9025 Handle<Map> obj_map = TypedArrayMap(
9026 isolate(), array_type, external_elements_kind);
9027 AddStoreMapConstant(obj, obj_map);
9029 ASSERT(is_zero_byte_offset);
9030 elements = BuildAllocateFixedTypedArray(
9031 array_type, element_size, fixed_elements_kind,
9032 byte_length, length);
9034 Add<HStoreNamedField>(
9035 obj, HObjectAccess::ForElementsPointer(), elements);
9038 if (!is_zero_byte_offset) {
9039 byte_offset_smi.Else();
9040 { // byte_offset is not Smi.
9042 CHECK_ALIVE(VisitForValue(arguments->at(kArrayIdArg)));
9046 PushArgumentsFromEnvironment(kArgsLength);
9047 Add<HCallRuntime>(expr->name(), expr->function(), kArgsLength);
9050 byte_offset_smi.End();
9054 void HOptimizedGraphBuilder::GenerateMaxSmi(CallRuntime* expr) {
9055 ASSERT(expr->arguments()->length() == 0);
9056 HConstant* max_smi = New<HConstant>(static_cast<int32_t>(Smi::kMaxValue));
9057 return ast_context()->ReturnInstruction(max_smi, expr->id());
9061 void HOptimizedGraphBuilder::GenerateTypedArrayMaxSizeInHeap(
9062 CallRuntime* expr) {
9063 ASSERT(expr->arguments()->length() == 0);
9064 HConstant* result = New<HConstant>(static_cast<int32_t>(
9065 FLAG_typed_array_max_size_in_heap));
9066 return ast_context()->ReturnInstruction(result, expr->id());
9070 void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
9071 ASSERT(!HasStackOverflow());
9072 ASSERT(current_block() != NULL);
9073 ASSERT(current_block()->HasPredecessor());
9074 if (expr->is_jsruntime()) {
9075 return Bailout(kCallToAJavaScriptRuntimeFunction);
9078 const Runtime::Function* function = expr->function();
9079 ASSERT(function != NULL);
9081 if (function->intrinsic_type == Runtime::INLINE ||
9082 function->intrinsic_type == Runtime::INLINE_OPTIMIZED) {
9083 ASSERT(expr->name()->length() > 0);
9084 ASSERT(expr->name()->Get(0) == '_');
9085 // Call to an inline function.
9086 int lookup_index = static_cast<int>(function->function_id) -
9087 static_cast<int>(Runtime::kFirstInlineFunction);
9088 ASSERT(lookup_index >= 0);
9089 ASSERT(static_cast<size_t>(lookup_index) <
9090 ARRAY_SIZE(kInlineFunctionGenerators));
9091 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index];
9093 // Call the inline code generator using the pointer-to-member.
9094 (this->*generator)(expr);
9096 ASSERT(function->intrinsic_type == Runtime::RUNTIME);
9097 Handle<String> name = expr->name();
9098 int argument_count = expr->arguments()->length();
9099 CHECK_ALIVE(VisitExpressions(expr->arguments()));
9100 PushArgumentsFromEnvironment(argument_count);
9101 HCallRuntime* call = New<HCallRuntime>(name, function,
9103 return ast_context()->ReturnInstruction(call, expr->id());
9108 void HOptimizedGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
9109 ASSERT(!HasStackOverflow());
9110 ASSERT(current_block() != NULL);
9111 ASSERT(current_block()->HasPredecessor());
9112 switch (expr->op()) {
9113 case Token::DELETE: return VisitDelete(expr);
9114 case Token::VOID: return VisitVoid(expr);
9115 case Token::TYPEOF: return VisitTypeof(expr);
9116 case Token::NOT: return VisitNot(expr);
9117 default: UNREACHABLE();
9122 void HOptimizedGraphBuilder::VisitDelete(UnaryOperation* expr) {
9123 Property* prop = expr->expression()->AsProperty();
9124 VariableProxy* proxy = expr->expression()->AsVariableProxy();
9126 CHECK_ALIVE(VisitForValue(prop->obj()));
9127 CHECK_ALIVE(VisitForValue(prop->key()));
9128 HValue* key = Pop();
9129 HValue* obj = Pop();
9130 HValue* function = AddLoadJSBuiltin(Builtins::DELETE);
9131 Add<HPushArgument>(obj);
9132 Add<HPushArgument>(key);
9133 Add<HPushArgument>(Add<HConstant>(function_strict_mode()));
9134 // TODO(olivf) InvokeFunction produces a check for the parameter count,
9135 // even though we are certain to pass the correct number of arguments here.
9136 HInstruction* instr = New<HInvokeFunction>(function, 3);
9137 return ast_context()->ReturnInstruction(instr, expr->id());
9138 } else if (proxy != NULL) {
9139 Variable* var = proxy->var();
9140 if (var->IsUnallocated()) {
9141 Bailout(kDeleteWithGlobalVariable);
9142 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
9143 // Result of deleting non-global variables is false. 'this' is not
9144 // really a variable, though we implement it as one. The
9145 // subexpression does not have side effects.
9146 HValue* value = var->is_this()
9147 ? graph()->GetConstantTrue()
9148 : graph()->GetConstantFalse();
9149 return ast_context()->ReturnValue(value);
9151 Bailout(kDeleteWithNonGlobalVariable);
9154 // Result of deleting non-property, non-variable reference is true.
9155 // Evaluate the subexpression for side effects.
9156 CHECK_ALIVE(VisitForEffect(expr->expression()));
9157 return ast_context()->ReturnValue(graph()->GetConstantTrue());
9162 void HOptimizedGraphBuilder::VisitVoid(UnaryOperation* expr) {
9163 CHECK_ALIVE(VisitForEffect(expr->expression()));
9164 return ast_context()->ReturnValue(graph()->GetConstantUndefined());
9168 void HOptimizedGraphBuilder::VisitTypeof(UnaryOperation* expr) {
9169 CHECK_ALIVE(VisitForTypeOf(expr->expression()));
9170 HValue* value = Pop();
9171 HInstruction* instr = New<HTypeof>(value);
9172 return ast_context()->ReturnInstruction(instr, expr->id());
9176 void HOptimizedGraphBuilder::VisitNot(UnaryOperation* expr) {
9177 if (ast_context()->IsTest()) {
9178 TestContext* context = TestContext::cast(ast_context());
9179 VisitForControl(expr->expression(),
9180 context->if_false(),
9181 context->if_true());
9185 if (ast_context()->IsEffect()) {
9186 VisitForEffect(expr->expression());
9190 ASSERT(ast_context()->IsValue());
9191 HBasicBlock* materialize_false = graph()->CreateBasicBlock();
9192 HBasicBlock* materialize_true = graph()->CreateBasicBlock();
9193 CHECK_BAILOUT(VisitForControl(expr->expression(),
9197 if (materialize_false->HasPredecessor()) {
9198 materialize_false->SetJoinId(expr->MaterializeFalseId());
9199 set_current_block(materialize_false);
9200 Push(graph()->GetConstantFalse());
9202 materialize_false = NULL;
9205 if (materialize_true->HasPredecessor()) {
9206 materialize_true->SetJoinId(expr->MaterializeTrueId());
9207 set_current_block(materialize_true);
9208 Push(graph()->GetConstantTrue());
9210 materialize_true = NULL;
9214 CreateJoin(materialize_false, materialize_true, expr->id());
9215 set_current_block(join);
9216 if (join != NULL) return ast_context()->ReturnValue(Pop());
9220 HInstruction* HOptimizedGraphBuilder::BuildIncrement(
9221 bool returns_original_input,
9222 CountOperation* expr) {
9223 // The input to the count operation is on top of the expression stack.
9224 Representation rep = Representation::FromType(expr->type());
9225 if (rep.IsNone() || rep.IsTagged()) {
9226 rep = Representation::Smi();
9229 if (returns_original_input) {
9230 // We need an explicit HValue representing ToNumber(input). The
9231 // actual HChange instruction we need is (sometimes) added in a later
9232 // phase, so it is not available now to be used as an input to HAdd and
9233 // as the return value.
9234 HInstruction* number_input = AddUncasted<HForceRepresentation>(Pop(), rep);
9235 if (!rep.IsDouble()) {
9236 number_input->SetFlag(HInstruction::kFlexibleRepresentation);
9237 number_input->SetFlag(HInstruction::kCannotBeTagged);
9242 // The addition has no side effects, so we do not need
9243 // to simulate the expression stack after this instruction.
9244 // Any later failures deopt to the load of the input or earlier.
9245 HConstant* delta = (expr->op() == Token::INC)
9246 ? graph()->GetConstant1()
9247 : graph()->GetConstantMinus1();
9248 HInstruction* instr = AddUncasted<HAdd>(Top(), delta);
9249 if (instr->IsAdd()) {
9250 HAdd* add = HAdd::cast(instr);
9251 add->set_observed_input_representation(1, rep);
9252 add->set_observed_input_representation(2, Representation::Smi());
9254 instr->SetFlag(HInstruction::kCannotBeTagged);
9255 instr->ClearAllSideEffects();
9260 void HOptimizedGraphBuilder::BuildStoreForEffect(Expression* expr,
9263 BailoutId return_id,
9267 EffectContext for_effect(this);
9269 if (key != NULL) Push(key);
9271 BuildStore(expr, prop, ast_id, return_id);
9275 void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
9276 ASSERT(!HasStackOverflow());
9277 ASSERT(current_block() != NULL);
9278 ASSERT(current_block()->HasPredecessor());
9279 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
9280 Expression* target = expr->expression();
9281 VariableProxy* proxy = target->AsVariableProxy();
9282 Property* prop = target->AsProperty();
9283 if (proxy == NULL && prop == NULL) {
9284 return Bailout(kInvalidLhsInCountOperation);
9287 // Match the full code generator stack by simulating an extra stack
9288 // element for postfix operations in a non-effect context. The return
9289 // value is ToNumber(input).
9290 bool returns_original_input =
9291 expr->is_postfix() && !ast_context()->IsEffect();
9292 HValue* input = NULL; // ToNumber(original_input).
9293 HValue* after = NULL; // The result after incrementing or decrementing.
9295 if (proxy != NULL) {
9296 Variable* var = proxy->var();
9297 if (var->mode() == CONST_LEGACY) {
9298 return Bailout(kUnsupportedCountOperationWithConst);
9300 // Argument of the count operation is a variable, not a property.
9301 ASSERT(prop == NULL);
9302 CHECK_ALIVE(VisitForValue(target));
9304 after = BuildIncrement(returns_original_input, expr);
9305 input = returns_original_input ? Top() : Pop();
9308 switch (var->location()) {
9309 case Variable::UNALLOCATED:
9310 HandleGlobalVariableAssignment(var,
9312 expr->AssignmentId());
9315 case Variable::PARAMETER:
9316 case Variable::LOCAL:
9317 BindIfLive(var, after);
9320 case Variable::CONTEXT: {
9321 // Bail out if we try to mutate a parameter value in a function
9322 // using the arguments object. We do not (yet) correctly handle the
9323 // arguments property of the function.
9324 if (current_info()->scope()->arguments() != NULL) {
9325 // Parameters will rewrite to context slots. We have no direct
9326 // way to detect that the variable is a parameter so we use a
9327 // linear search of the parameter list.
9328 int count = current_info()->scope()->num_parameters();
9329 for (int i = 0; i < count; ++i) {
9330 if (var == current_info()->scope()->parameter(i)) {
9331 return Bailout(kAssignmentToParameterInArgumentsObject);
9336 HValue* context = BuildContextChainWalk(var);
9337 HStoreContextSlot::Mode mode = IsLexicalVariableMode(var->mode())
9338 ? HStoreContextSlot::kCheckDeoptimize : HStoreContextSlot::kNoCheck;
9339 HStoreContextSlot* instr = Add<HStoreContextSlot>(context, var->index(),
9341 if (instr->HasObservableSideEffects()) {
9342 Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE);
9347 case Variable::LOOKUP:
9348 return Bailout(kLookupVariableInCountOperation);
9351 Drop(returns_original_input ? 2 : 1);
9352 return ast_context()->ReturnValue(expr->is_postfix() ? input : after);
9355 // Argument of the count operation is a property.
9356 ASSERT(prop != NULL);
9357 if (returns_original_input) Push(graph()->GetConstantUndefined());
9359 CHECK_ALIVE(VisitForValue(prop->obj()));
9360 HValue* object = Top();
9363 if ((!prop->IsFunctionPrototype() && !prop->key()->IsPropertyName()) ||
9364 prop->IsStringAccess()) {
9365 CHECK_ALIVE(VisitForValue(prop->key()));
9369 CHECK_ALIVE(PushLoad(prop, object, key));
9371 after = BuildIncrement(returns_original_input, expr);
9373 if (returns_original_input) {
9375 // Drop object and key to push it again in the effect context below.
9376 Drop(key == NULL ? 1 : 2);
9377 environment()->SetExpressionStackAt(0, input);
9378 CHECK_ALIVE(BuildStoreForEffect(
9379 expr, prop, expr->id(), expr->AssignmentId(), object, key, after));
9380 return ast_context()->ReturnValue(Pop());
9383 environment()->SetExpressionStackAt(0, after);
9384 return BuildStore(expr, prop, expr->id(), expr->AssignmentId());
9388 HInstruction* HOptimizedGraphBuilder::BuildStringCharCodeAt(
9391 if (string->IsConstant() && index->IsConstant()) {
9392 HConstant* c_string = HConstant::cast(string);
9393 HConstant* c_index = HConstant::cast(index);
9394 if (c_string->HasStringValue() && c_index->HasNumberValue()) {
9395 int32_t i = c_index->NumberValueAsInteger32();
9396 Handle<String> s = c_string->StringValue();
9397 if (i < 0 || i >= s->length()) {
9398 return New<HConstant>(OS::nan_value());
9400 return New<HConstant>(s->Get(i));
9403 string = BuildCheckString(string);
9404 index = Add<HBoundsCheck>(index, AddLoadStringLength(string));
9405 return New<HStringCharCodeAt>(string, index);
9409 // Checks if the given shift amounts have following forms:
9410 // (N1) and (N2) with N1 + N2 = 32; (sa) and (32 - sa).
9411 static bool ShiftAmountsAllowReplaceByRotate(HValue* sa,
9412 HValue* const32_minus_sa) {
9413 if (sa->IsConstant() && const32_minus_sa->IsConstant()) {
9414 const HConstant* c1 = HConstant::cast(sa);
9415 const HConstant* c2 = HConstant::cast(const32_minus_sa);
9416 return c1->HasInteger32Value() && c2->HasInteger32Value() &&
9417 (c1->Integer32Value() + c2->Integer32Value() == 32);
9419 if (!const32_minus_sa->IsSub()) return false;
9420 HSub* sub = HSub::cast(const32_minus_sa);
9421 return sub->left()->EqualsInteger32Constant(32) && sub->right() == sa;
9425 // Checks if the left and the right are shift instructions with the oposite
9426 // directions that can be replaced by one rotate right instruction or not.
9427 // Returns the operand and the shift amount for the rotate instruction in the
9429 bool HGraphBuilder::MatchRotateRight(HValue* left,
9432 HValue** shift_amount) {
9435 if (left->IsShl() && right->IsShr()) {
9436 shl = HShl::cast(left);
9437 shr = HShr::cast(right);
9438 } else if (left->IsShr() && right->IsShl()) {
9439 shl = HShl::cast(right);
9440 shr = HShr::cast(left);
9444 if (shl->left() != shr->left()) return false;
9446 if (!ShiftAmountsAllowReplaceByRotate(shl->right(), shr->right()) &&
9447 !ShiftAmountsAllowReplaceByRotate(shr->right(), shl->right())) {
9450 *operand= shr->left();
9451 *shift_amount = shr->right();
9456 bool CanBeZero(HValue* right) {
9457 if (right->IsConstant()) {
9458 HConstant* right_const = HConstant::cast(right);
9459 if (right_const->HasInteger32Value() &&
9460 (right_const->Integer32Value() & 0x1f) != 0) {
9468 HValue* HGraphBuilder::EnforceNumberType(HValue* number,
9470 if (expected->Is(Type::SignedSmall())) {
9471 return AddUncasted<HForceRepresentation>(number, Representation::Smi());
9473 if (expected->Is(Type::Signed32())) {
9474 return AddUncasted<HForceRepresentation>(number,
9475 Representation::Integer32());
9481 HValue* HGraphBuilder::TruncateToNumber(HValue* value, Type** expected) {
9482 if (value->IsConstant()) {
9483 HConstant* constant = HConstant::cast(value);
9484 Maybe<HConstant*> number = constant->CopyToTruncatedNumber(zone());
9485 if (number.has_value) {
9486 *expected = Type::Number(zone());
9487 return AddInstruction(number.value);
9491 // We put temporary values on the stack, which don't correspond to anything
9492 // in baseline code. Since nothing is observable we avoid recording those
9493 // pushes with a NoObservableSideEffectsScope.
9494 NoObservableSideEffectsScope no_effects(this);
9496 Type* expected_type = *expected;
9498 // Separate the number type from the rest.
9499 Type* expected_obj =
9500 Type::Intersect(expected_type, Type::NonNumber(zone()), zone());
9501 Type* expected_number =
9502 Type::Intersect(expected_type, Type::Number(zone()), zone());
9504 // We expect to get a number.
9505 // (We need to check first, since Type::None->Is(Type::Any()) == true.
9506 if (expected_obj->Is(Type::None())) {
9507 ASSERT(!expected_number->Is(Type::None(zone())));
9511 if (expected_obj->Is(Type::Undefined(zone()))) {
9512 // This is already done by HChange.
9513 *expected = Type::Union(expected_number, Type::Float(zone()), zone());
9521 HValue* HOptimizedGraphBuilder::BuildBinaryOperation(
9522 BinaryOperation* expr,
9525 PushBeforeSimulateBehavior push_sim_result) {
9526 Type* left_type = expr->left()->bounds().lower;
9527 Type* right_type = expr->right()->bounds().lower;
9528 Type* result_type = expr->bounds().lower;
9529 Maybe<int> fixed_right_arg = expr->fixed_right_arg();
9530 Handle<AllocationSite> allocation_site = expr->allocation_site();
9532 PretenureFlag pretenure_flag = !FLAG_allocation_site_pretenuring ?
9533 isolate()->heap()->GetPretenureMode() : NOT_TENURED;
9535 HAllocationMode allocation_mode =
9536 FLAG_allocation_site_pretenuring
9537 ? (allocation_site.is_null()
9538 ? HAllocationMode(NOT_TENURED)
9539 : HAllocationMode(allocation_site))
9540 : HAllocationMode(pretenure_flag);
9542 HValue* result = HGraphBuilder::BuildBinaryOperation(
9543 expr->op(), left, right, left_type, right_type, result_type,
9544 fixed_right_arg, allocation_mode);
9545 // Add a simulate after instructions with observable side effects, and
9546 // after phis, which are the result of BuildBinaryOperation when we
9547 // inlined some complex subgraph.
9548 if (result->HasObservableSideEffects() || result->IsPhi()) {
9549 if (push_sim_result == PUSH_BEFORE_SIMULATE) {
9551 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
9554 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
9561 HValue* HGraphBuilder::BuildBinaryOperation(
9568 Maybe<int> fixed_right_arg,
9569 HAllocationMode allocation_mode) {
9571 Representation left_rep = Representation::FromType(left_type);
9572 Representation right_rep = Representation::FromType(right_type);
9574 bool maybe_string_add = op == Token::ADD &&
9575 (left_type->Maybe(Type::String()) ||
9576 right_type->Maybe(Type::String()));
9578 if (left_type->Is(Type::None())) {
9579 Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation",
9581 // TODO(rossberg): we should be able to get rid of non-continuous
9583 left_type = Type::Any(zone());
9585 if (!maybe_string_add) left = TruncateToNumber(left, &left_type);
9586 left_rep = Representation::FromType(left_type);
9589 if (right_type->Is(Type::None())) {
9590 Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation",
9592 right_type = Type::Any(zone());
9594 if (!maybe_string_add) right = TruncateToNumber(right, &right_type);
9595 right_rep = Representation::FromType(right_type);
9598 // Special case for string addition here.
9599 if (op == Token::ADD &&
9600 (left_type->Is(Type::String()) || right_type->Is(Type::String()))) {
9601 // Validate type feedback for left argument.
9602 if (left_type->Is(Type::String())) {
9603 left = BuildCheckString(left);
9606 // Validate type feedback for right argument.
9607 if (right_type->Is(Type::String())) {
9608 right = BuildCheckString(right);
9611 // Convert left argument as necessary.
9612 if (left_type->Is(Type::Number())) {
9613 ASSERT(right_type->Is(Type::String()));
9614 left = BuildNumberToString(left, left_type);
9615 } else if (!left_type->Is(Type::String())) {
9616 ASSERT(right_type->Is(Type::String()));
9617 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_RIGHT);
9618 Add<HPushArgument>(left);
9619 Add<HPushArgument>(right);
9620 return AddUncasted<HInvokeFunction>(function, 2);
9623 // Convert right argument as necessary.
9624 if (right_type->Is(Type::Number())) {
9625 ASSERT(left_type->Is(Type::String()));
9626 right = BuildNumberToString(right, right_type);
9627 } else if (!right_type->Is(Type::String())) {
9628 ASSERT(left_type->Is(Type::String()));
9629 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_LEFT);
9630 Add<HPushArgument>(left);
9631 Add<HPushArgument>(right);
9632 return AddUncasted<HInvokeFunction>(function, 2);
9635 // Fast path for empty constant strings.
9636 if (left->IsConstant() &&
9637 HConstant::cast(left)->HasStringValue() &&
9638 HConstant::cast(left)->StringValue()->length() == 0) {
9641 if (right->IsConstant() &&
9642 HConstant::cast(right)->HasStringValue() &&
9643 HConstant::cast(right)->StringValue()->length() == 0) {
9647 // Register the dependent code with the allocation site.
9648 if (!allocation_mode.feedback_site().is_null()) {
9649 ASSERT(!graph()->info()->IsStub());
9650 Handle<AllocationSite> site(allocation_mode.feedback_site());
9651 AllocationSite::AddDependentCompilationInfo(
9652 site, AllocationSite::TENURING, top_info());
9655 // Inline the string addition into the stub when creating allocation
9656 // mementos to gather allocation site feedback, or if we can statically
9657 // infer that we're going to create a cons string.
9658 if ((graph()->info()->IsStub() &&
9659 allocation_mode.CreateAllocationMementos()) ||
9660 (left->IsConstant() &&
9661 HConstant::cast(left)->HasStringValue() &&
9662 HConstant::cast(left)->StringValue()->length() + 1 >=
9663 ConsString::kMinLength) ||
9664 (right->IsConstant() &&
9665 HConstant::cast(right)->HasStringValue() &&
9666 HConstant::cast(right)->StringValue()->length() + 1 >=
9667 ConsString::kMinLength)) {
9668 return BuildStringAdd(left, right, allocation_mode);
9671 // Fallback to using the string add stub.
9672 return AddUncasted<HStringAdd>(
9673 left, right, allocation_mode.GetPretenureMode(),
9674 STRING_ADD_CHECK_NONE, allocation_mode.feedback_site());
9677 if (graph()->info()->IsStub()) {
9678 left = EnforceNumberType(left, left_type);
9679 right = EnforceNumberType(right, right_type);
9682 Representation result_rep = Representation::FromType(result_type);
9684 bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) ||
9685 (right_rep.IsTagged() && !right_rep.IsSmi());
9687 HInstruction* instr = NULL;
9688 // Only the stub is allowed to call into the runtime, since otherwise we would
9689 // inline several instructions (including the two pushes) for every tagged
9690 // operation in optimized code, which is more expensive, than a stub call.
9691 if (graph()->info()->IsStub() && is_non_primitive) {
9692 HValue* function = AddLoadJSBuiltin(BinaryOpIC::TokenToJSBuiltin(op));
9693 Add<HPushArgument>(left);
9694 Add<HPushArgument>(right);
9695 instr = AddUncasted<HInvokeFunction>(function, 2);
9699 instr = AddUncasted<HAdd>(left, right);
9702 instr = AddUncasted<HSub>(left, right);
9705 instr = AddUncasted<HMul>(left, right);
9708 if (fixed_right_arg.has_value &&
9709 !right->EqualsInteger32Constant(fixed_right_arg.value)) {
9710 HConstant* fixed_right = Add<HConstant>(
9711 static_cast<int>(fixed_right_arg.value));
9712 IfBuilder if_same(this);
9713 if_same.If<HCompareNumericAndBranch>(right, fixed_right, Token::EQ);
9715 if_same.ElseDeopt("Unexpected RHS of binary operation");
9716 right = fixed_right;
9718 instr = AddUncasted<HMod>(left, right);
9722 instr = AddUncasted<HDiv>(left, right);
9724 case Token::BIT_XOR:
9725 case Token::BIT_AND:
9726 instr = AddUncasted<HBitwise>(op, left, right);
9728 case Token::BIT_OR: {
9729 HValue* operand, *shift_amount;
9730 if (left_type->Is(Type::Signed32()) &&
9731 right_type->Is(Type::Signed32()) &&
9732 MatchRotateRight(left, right, &operand, &shift_amount)) {
9733 instr = AddUncasted<HRor>(operand, shift_amount);
9735 instr = AddUncasted<HBitwise>(op, left, right);
9740 instr = AddUncasted<HSar>(left, right);
9743 instr = AddUncasted<HShr>(left, right);
9744 if (FLAG_opt_safe_uint32_operations && instr->IsShr() &&
9746 graph()->RecordUint32Instruction(instr);
9750 instr = AddUncasted<HShl>(left, right);
9757 if (instr->IsBinaryOperation()) {
9758 HBinaryOperation* binop = HBinaryOperation::cast(instr);
9759 binop->set_observed_input_representation(1, left_rep);
9760 binop->set_observed_input_representation(2, right_rep);
9761 binop->initialize_output_representation(result_rep);
9762 if (graph()->info()->IsStub()) {
9763 // Stub should not call into stub.
9764 instr->SetFlag(HValue::kCannotBeTagged);
9765 // And should truncate on HForceRepresentation already.
9766 if (left->IsForceRepresentation()) {
9767 left->CopyFlag(HValue::kTruncatingToSmi, instr);
9768 left->CopyFlag(HValue::kTruncatingToInt32, instr);
9770 if (right->IsForceRepresentation()) {
9771 right->CopyFlag(HValue::kTruncatingToSmi, instr);
9772 right->CopyFlag(HValue::kTruncatingToInt32, instr);
9780 // Check for the form (%_ClassOf(foo) === 'BarClass').
9781 static bool IsClassOfTest(CompareOperation* expr) {
9782 if (expr->op() != Token::EQ_STRICT) return false;
9783 CallRuntime* call = expr->left()->AsCallRuntime();
9784 if (call == NULL) return false;
9785 Literal* literal = expr->right()->AsLiteral();
9786 if (literal == NULL) return false;
9787 if (!literal->value()->IsString()) return false;
9788 if (!call->name()->IsOneByteEqualTo(STATIC_ASCII_VECTOR("_ClassOf"))) {
9791 ASSERT(call->arguments()->length() == 1);
9796 void HOptimizedGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
9797 ASSERT(!HasStackOverflow());
9798 ASSERT(current_block() != NULL);
9799 ASSERT(current_block()->HasPredecessor());
9800 switch (expr->op()) {
9802 return VisitComma(expr);
9805 return VisitLogicalExpression(expr);
9807 return VisitArithmeticExpression(expr);
9812 void HOptimizedGraphBuilder::VisitComma(BinaryOperation* expr) {
9813 CHECK_ALIVE(VisitForEffect(expr->left()));
9814 // Visit the right subexpression in the same AST context as the entire
9816 Visit(expr->right());
9820 void HOptimizedGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
9821 bool is_logical_and = expr->op() == Token::AND;
9822 if (ast_context()->IsTest()) {
9823 TestContext* context = TestContext::cast(ast_context());
9824 // Translate left subexpression.
9825 HBasicBlock* eval_right = graph()->CreateBasicBlock();
9826 if (is_logical_and) {
9827 CHECK_BAILOUT(VisitForControl(expr->left(),
9829 context->if_false()));
9831 CHECK_BAILOUT(VisitForControl(expr->left(),
9836 // Translate right subexpression by visiting it in the same AST
9837 // context as the entire expression.
9838 if (eval_right->HasPredecessor()) {
9839 eval_right->SetJoinId(expr->RightId());
9840 set_current_block(eval_right);
9841 Visit(expr->right());
9844 } else if (ast_context()->IsValue()) {
9845 CHECK_ALIVE(VisitForValue(expr->left()));
9846 ASSERT(current_block() != NULL);
9847 HValue* left_value = Top();
9849 // Short-circuit left values that always evaluate to the same boolean value.
9850 if (expr->left()->ToBooleanIsTrue() || expr->left()->ToBooleanIsFalse()) {
9851 // l (evals true) && r -> r
9852 // l (evals true) || r -> l
9853 // l (evals false) && r -> l
9854 // l (evals false) || r -> r
9855 if (is_logical_and == expr->left()->ToBooleanIsTrue()) {
9857 CHECK_ALIVE(VisitForValue(expr->right()));
9859 return ast_context()->ReturnValue(Pop());
9862 // We need an extra block to maintain edge-split form.
9863 HBasicBlock* empty_block = graph()->CreateBasicBlock();
9864 HBasicBlock* eval_right = graph()->CreateBasicBlock();
9865 ToBooleanStub::Types expected(expr->left()->to_boolean_types());
9866 HBranch* test = is_logical_and
9867 ? New<HBranch>(left_value, expected, eval_right, empty_block)
9868 : New<HBranch>(left_value, expected, empty_block, eval_right);
9869 FinishCurrentBlock(test);
9871 set_current_block(eval_right);
9872 Drop(1); // Value of the left subexpression.
9873 CHECK_BAILOUT(VisitForValue(expr->right()));
9875 HBasicBlock* join_block =
9876 CreateJoin(empty_block, current_block(), expr->id());
9877 set_current_block(join_block);
9878 return ast_context()->ReturnValue(Pop());
9881 ASSERT(ast_context()->IsEffect());
9882 // In an effect context, we don't need the value of the left subexpression,
9883 // only its control flow and side effects. We need an extra block to
9884 // maintain edge-split form.
9885 HBasicBlock* empty_block = graph()->CreateBasicBlock();
9886 HBasicBlock* right_block = graph()->CreateBasicBlock();
9887 if (is_logical_and) {
9888 CHECK_BAILOUT(VisitForControl(expr->left(), right_block, empty_block));
9890 CHECK_BAILOUT(VisitForControl(expr->left(), empty_block, right_block));
9893 // TODO(kmillikin): Find a way to fix this. It's ugly that there are
9894 // actually two empty blocks (one here and one inserted by
9895 // TestContext::BuildBranch, and that they both have an HSimulate though the
9896 // second one is not a merge node, and that we really have no good AST ID to
9897 // put on that first HSimulate.
9899 if (empty_block->HasPredecessor()) {
9900 empty_block->SetJoinId(expr->id());
9905 if (right_block->HasPredecessor()) {
9906 right_block->SetJoinId(expr->RightId());
9907 set_current_block(right_block);
9908 CHECK_BAILOUT(VisitForEffect(expr->right()));
9909 right_block = current_block();
9914 HBasicBlock* join_block =
9915 CreateJoin(empty_block, right_block, expr->id());
9916 set_current_block(join_block);
9917 // We did not materialize any value in the predecessor environments,
9918 // so there is no need to handle it here.
9923 void HOptimizedGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) {
9924 CHECK_ALIVE(VisitForValue(expr->left()));
9925 CHECK_ALIVE(VisitForValue(expr->right()));
9926 SetSourcePosition(expr->position());
9927 HValue* right = Pop();
9928 HValue* left = Pop();
9930 BuildBinaryOperation(expr, left, right,
9931 ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE
9932 : PUSH_BEFORE_SIMULATE);
9933 if (FLAG_hydrogen_track_positions && result->IsBinaryOperation()) {
9934 HBinaryOperation::cast(result)->SetOperandPositions(
9936 ScriptPositionToSourcePosition(expr->left()->position()),
9937 ScriptPositionToSourcePosition(expr->right()->position()));
9939 return ast_context()->ReturnValue(result);
9943 void HOptimizedGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr,
9944 Expression* sub_expr,
9945 Handle<String> check) {
9946 CHECK_ALIVE(VisitForTypeOf(sub_expr));
9947 SetSourcePosition(expr->position());
9948 HValue* value = Pop();
9949 HTypeofIsAndBranch* instr = New<HTypeofIsAndBranch>(value, check);
9950 return ast_context()->ReturnControl(instr, expr->id());
9954 static bool IsLiteralCompareBool(Isolate* isolate,
9958 return op == Token::EQ_STRICT &&
9959 ((left->IsConstant() &&
9960 HConstant::cast(left)->handle(isolate)->IsBoolean()) ||
9961 (right->IsConstant() &&
9962 HConstant::cast(right)->handle(isolate)->IsBoolean()));
9966 void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
9967 ASSERT(!HasStackOverflow());
9968 ASSERT(current_block() != NULL);
9969 ASSERT(current_block()->HasPredecessor());
9971 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
9973 // Check for a few fast cases. The AST visiting behavior must be in sync
9974 // with the full codegen: We don't push both left and right values onto
9975 // the expression stack when one side is a special-case literal.
9976 Expression* sub_expr = NULL;
9977 Handle<String> check;
9978 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) {
9979 return HandleLiteralCompareTypeof(expr, sub_expr, check);
9981 if (expr->IsLiteralCompareUndefined(&sub_expr, isolate())) {
9982 return HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue);
9984 if (expr->IsLiteralCompareNull(&sub_expr)) {
9985 return HandleLiteralCompareNil(expr, sub_expr, kNullValue);
9988 if (IsClassOfTest(expr)) {
9989 CallRuntime* call = expr->left()->AsCallRuntime();
9990 ASSERT(call->arguments()->length() == 1);
9991 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
9992 HValue* value = Pop();
9993 Literal* literal = expr->right()->AsLiteral();
9994 Handle<String> rhs = Handle<String>::cast(literal->value());
9995 HClassOfTestAndBranch* instr = New<HClassOfTestAndBranch>(value, rhs);
9996 return ast_context()->ReturnControl(instr, expr->id());
9999 Type* left_type = expr->left()->bounds().lower;
10000 Type* right_type = expr->right()->bounds().lower;
10001 Type* combined_type = expr->combined_type();
10003 CHECK_ALIVE(VisitForValue(expr->left()));
10004 CHECK_ALIVE(VisitForValue(expr->right()));
10006 if (FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
10008 HValue* right = Pop();
10009 HValue* left = Pop();
10010 Token::Value op = expr->op();
10012 if (IsLiteralCompareBool(isolate(), left, op, right)) {
10013 HCompareObjectEqAndBranch* result =
10014 New<HCompareObjectEqAndBranch>(left, right);
10015 return ast_context()->ReturnControl(result, expr->id());
10018 if (op == Token::INSTANCEOF) {
10019 // Check to see if the rhs of the instanceof is a global function not
10020 // residing in new space. If it is we assume that the function will stay the
10022 Handle<JSFunction> target = Handle<JSFunction>::null();
10023 VariableProxy* proxy = expr->right()->AsVariableProxy();
10024 bool global_function = (proxy != NULL) && proxy->var()->IsUnallocated();
10025 if (global_function &&
10026 current_info()->has_global_object() &&
10027 !current_info()->global_object()->IsAccessCheckNeeded()) {
10028 Handle<String> name = proxy->name();
10029 Handle<GlobalObject> global(current_info()->global_object());
10030 LookupResult lookup(isolate());
10031 global->Lookup(*name, &lookup);
10032 if (lookup.IsNormal() && lookup.GetValue()->IsJSFunction()) {
10033 Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue()));
10034 // If the function is in new space we assume it's more likely to
10035 // change and thus prefer the general IC code.
10036 if (!isolate()->heap()->InNewSpace(*candidate)) {
10037 target = candidate;
10042 // If the target is not null we have found a known global function that is
10043 // assumed to stay the same for this instanceof.
10044 if (target.is_null()) {
10045 HInstanceOf* result = New<HInstanceOf>(left, right);
10046 return ast_context()->ReturnInstruction(result, expr->id());
10048 Add<HCheckValue>(right, target);
10049 HInstanceOfKnownGlobal* result =
10050 New<HInstanceOfKnownGlobal>(left, target);
10051 return ast_context()->ReturnInstruction(result, expr->id());
10054 // Code below assumes that we don't fall through.
10056 } else if (op == Token::IN) {
10057 HValue* function = AddLoadJSBuiltin(Builtins::IN);
10058 Add<HPushArgument>(left);
10059 Add<HPushArgument>(right);
10060 // TODO(olivf) InvokeFunction produces a check for the parameter count,
10061 // even though we are certain to pass the correct number of arguments here.
10062 HInstruction* result = New<HInvokeFunction>(function, 2);
10063 return ast_context()->ReturnInstruction(result, expr->id());
10066 PushBeforeSimulateBehavior push_behavior =
10067 ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE
10068 : PUSH_BEFORE_SIMULATE;
10069 HControlInstruction* compare = BuildCompareInstruction(
10070 op, left, right, left_type, right_type, combined_type,
10071 ScriptPositionToSourcePosition(expr->left()->position()),
10072 ScriptPositionToSourcePosition(expr->right()->position()),
10073 push_behavior, expr->id());
10074 if (compare == NULL) return; // Bailed out.
10075 return ast_context()->ReturnControl(compare, expr->id());
10079 HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction(
10085 Type* combined_type,
10086 HSourcePosition left_position,
10087 HSourcePosition right_position,
10088 PushBeforeSimulateBehavior push_sim_result,
10089 BailoutId bailout_id) {
10090 // Cases handled below depend on collected type feedback. They should
10091 // soft deoptimize when there is no type feedback.
10092 if (combined_type->Is(Type::None())) {
10093 Add<HDeoptimize>("Insufficient type feedback for combined type "
10094 "of binary operation",
10095 Deoptimizer::SOFT);
10096 combined_type = left_type = right_type = Type::Any(zone());
10099 Representation left_rep = Representation::FromType(left_type);
10100 Representation right_rep = Representation::FromType(right_type);
10101 Representation combined_rep = Representation::FromType(combined_type);
10103 if (combined_type->Is(Type::Receiver())) {
10104 if (Token::IsEqualityOp(op)) {
10105 // Can we get away with map check and not instance type check?
10106 HValue* operand_to_check =
10107 left->block()->block_id() < right->block()->block_id() ? left : right;
10108 if (combined_type->IsClass()) {
10109 Handle<Map> map = combined_type->AsClass();
10110 AddCheckMap(operand_to_check, map);
10111 HCompareObjectEqAndBranch* result =
10112 New<HCompareObjectEqAndBranch>(left, right);
10113 if (FLAG_hydrogen_track_positions) {
10114 result->set_operand_position(zone(), 0, left_position);
10115 result->set_operand_position(zone(), 1, right_position);
10119 BuildCheckHeapObject(operand_to_check);
10120 Add<HCheckInstanceType>(operand_to_check,
10121 HCheckInstanceType::IS_SPEC_OBJECT);
10122 HCompareObjectEqAndBranch* result =
10123 New<HCompareObjectEqAndBranch>(left, right);
10127 Bailout(kUnsupportedNonPrimitiveCompare);
10130 } else if (combined_type->Is(Type::InternalizedString()) &&
10131 Token::IsEqualityOp(op)) {
10132 BuildCheckHeapObject(left);
10133 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_INTERNALIZED_STRING);
10134 BuildCheckHeapObject(right);
10135 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_INTERNALIZED_STRING);
10136 HCompareObjectEqAndBranch* result =
10137 New<HCompareObjectEqAndBranch>(left, right);
10139 } else if (combined_type->Is(Type::String())) {
10140 BuildCheckHeapObject(left);
10141 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_STRING);
10142 BuildCheckHeapObject(right);
10143 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_STRING);
10144 HStringCompareAndBranch* result =
10145 New<HStringCompareAndBranch>(left, right, op);
10148 if (combined_rep.IsTagged() || combined_rep.IsNone()) {
10149 HCompareGeneric* result = Add<HCompareGeneric>(left, right, op);
10150 result->set_observed_input_representation(1, left_rep);
10151 result->set_observed_input_representation(2, right_rep);
10152 if (result->HasObservableSideEffects()) {
10153 if (push_sim_result == PUSH_BEFORE_SIMULATE) {
10155 AddSimulate(bailout_id, REMOVABLE_SIMULATE);
10158 AddSimulate(bailout_id, REMOVABLE_SIMULATE);
10161 // TODO(jkummerow): Can we make this more efficient?
10162 HBranch* branch = New<HBranch>(result);
10165 HCompareNumericAndBranch* result =
10166 New<HCompareNumericAndBranch>(left, right, op);
10167 result->set_observed_input_representation(left_rep, right_rep);
10168 if (FLAG_hydrogen_track_positions) {
10169 result->SetOperandPositions(zone(), left_position, right_position);
10177 void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
10178 Expression* sub_expr,
10180 ASSERT(!HasStackOverflow());
10181 ASSERT(current_block() != NULL);
10182 ASSERT(current_block()->HasPredecessor());
10183 ASSERT(expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT);
10184 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
10185 CHECK_ALIVE(VisitForValue(sub_expr));
10186 HValue* value = Pop();
10187 if (expr->op() == Token::EQ_STRICT) {
10188 HConstant* nil_constant = nil == kNullValue
10189 ? graph()->GetConstantNull()
10190 : graph()->GetConstantUndefined();
10191 HCompareObjectEqAndBranch* instr =
10192 New<HCompareObjectEqAndBranch>(value, nil_constant);
10193 return ast_context()->ReturnControl(instr, expr->id());
10195 ASSERT_EQ(Token::EQ, expr->op());
10196 Type* type = expr->combined_type()->Is(Type::None())
10197 ? Type::Any(zone()) : expr->combined_type();
10198 HIfContinuation continuation;
10199 BuildCompareNil(value, type, &continuation);
10200 return ast_context()->ReturnContinuation(&continuation, expr->id());
10205 HInstruction* HOptimizedGraphBuilder::BuildThisFunction() {
10206 // If we share optimized code between different closures, the
10207 // this-function is not a constant, except inside an inlined body.
10208 if (function_state()->outer() != NULL) {
10209 return New<HConstant>(
10210 function_state()->compilation_info()->closure());
10212 return New<HThisFunction>();
10217 HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
10218 Handle<JSObject> boilerplate_object,
10219 AllocationSiteUsageContext* site_context) {
10220 NoObservableSideEffectsScope no_effects(this);
10221 InstanceType instance_type = boilerplate_object->map()->instance_type();
10222 ASSERT(instance_type == JS_ARRAY_TYPE || instance_type == JS_OBJECT_TYPE);
10224 HType type = instance_type == JS_ARRAY_TYPE
10225 ? HType::JSArray() : HType::JSObject();
10226 HValue* object_size_constant = Add<HConstant>(
10227 boilerplate_object->map()->instance_size());
10229 PretenureFlag pretenure_flag = isolate()->heap()->GetPretenureMode();
10230 if (FLAG_allocation_site_pretenuring) {
10231 pretenure_flag = site_context->current()->GetPretenureMode();
10232 Handle<AllocationSite> site(site_context->current());
10233 AllocationSite::AddDependentCompilationInfo(
10234 site, AllocationSite::TENURING, top_info());
10237 HInstruction* object = Add<HAllocate>(object_size_constant, type,
10238 pretenure_flag, instance_type, site_context->current());
10240 // If allocation folding reaches Page::kMaxRegularHeapObjectSize the
10241 // elements array may not get folded into the object. Hence, we set the
10242 // elements pointer to empty fixed array and let store elimination remove
10243 // this store in the folding case.
10244 HConstant* empty_fixed_array = Add<HConstant>(
10245 isolate()->factory()->empty_fixed_array());
10246 Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
10247 empty_fixed_array, INITIALIZING_STORE);
10249 BuildEmitObjectHeader(boilerplate_object, object);
10251 Handle<FixedArrayBase> elements(boilerplate_object->elements());
10252 int elements_size = (elements->length() > 0 &&
10253 elements->map() != isolate()->heap()->fixed_cow_array_map()) ?
10254 elements->Size() : 0;
10256 if (pretenure_flag == TENURED &&
10257 elements->map() == isolate()->heap()->fixed_cow_array_map() &&
10258 isolate()->heap()->InNewSpace(*elements)) {
10259 // If we would like to pretenure a fixed cow array, we must ensure that the
10260 // array is already in old space, otherwise we'll create too many old-to-
10261 // new-space pointers (overflowing the store buffer).
10262 elements = Handle<FixedArrayBase>(
10263 isolate()->factory()->CopyAndTenureFixedCOWArray(
10264 Handle<FixedArray>::cast(elements)));
10265 boilerplate_object->set_elements(*elements);
10268 HInstruction* object_elements = NULL;
10269 if (elements_size > 0) {
10270 HValue* object_elements_size = Add<HConstant>(elements_size);
10271 if (boilerplate_object->HasFastDoubleElements()) {
10272 object_elements = Add<HAllocate>(object_elements_size, HType::Tagged(),
10273 pretenure_flag, FIXED_DOUBLE_ARRAY_TYPE, site_context->current());
10275 object_elements = Add<HAllocate>(object_elements_size, HType::Tagged(),
10276 pretenure_flag, FIXED_ARRAY_TYPE, site_context->current());
10279 BuildInitElementsInObjectHeader(boilerplate_object, object, object_elements);
10281 // Copy object elements if non-COW.
10282 if (object_elements != NULL) {
10283 BuildEmitElements(boilerplate_object, elements, object_elements,
10287 // Copy in-object properties.
10288 if (boilerplate_object->map()->NumberOfFields() != 0) {
10289 BuildEmitInObjectProperties(boilerplate_object, object, site_context,
10296 void HOptimizedGraphBuilder::BuildEmitObjectHeader(
10297 Handle<JSObject> boilerplate_object,
10298 HInstruction* object) {
10299 ASSERT(boilerplate_object->properties()->length() == 0);
10301 Handle<Map> boilerplate_object_map(boilerplate_object->map());
10302 AddStoreMapConstant(object, boilerplate_object_map);
10304 Handle<Object> properties_field =
10305 Handle<Object>(boilerplate_object->properties(), isolate());
10306 ASSERT(*properties_field == isolate()->heap()->empty_fixed_array());
10307 HInstruction* properties = Add<HConstant>(properties_field);
10308 HObjectAccess access = HObjectAccess::ForPropertiesPointer();
10309 Add<HStoreNamedField>(object, access, properties);
10311 if (boilerplate_object->IsJSArray()) {
10312 Handle<JSArray> boilerplate_array =
10313 Handle<JSArray>::cast(boilerplate_object);
10314 Handle<Object> length_field =
10315 Handle<Object>(boilerplate_array->length(), isolate());
10316 HInstruction* length = Add<HConstant>(length_field);
10318 ASSERT(boilerplate_array->length()->IsSmi());
10319 Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(
10320 boilerplate_array->GetElementsKind()), length);
10325 void HOptimizedGraphBuilder::BuildInitElementsInObjectHeader(
10326 Handle<JSObject> boilerplate_object,
10327 HInstruction* object,
10328 HInstruction* object_elements) {
10329 ASSERT(boilerplate_object->properties()->length() == 0);
10330 if (object_elements == NULL) {
10331 Handle<Object> elements_field =
10332 Handle<Object>(boilerplate_object->elements(), isolate());
10333 object_elements = Add<HConstant>(elements_field);
10335 Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(),
10340 void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
10341 Handle<JSObject> boilerplate_object,
10342 HInstruction* object,
10343 AllocationSiteUsageContext* site_context,
10344 PretenureFlag pretenure_flag) {
10345 Handle<Map> boilerplate_map(boilerplate_object->map());
10346 Handle<DescriptorArray> descriptors(boilerplate_map->instance_descriptors());
10347 int limit = boilerplate_map->NumberOfOwnDescriptors();
10349 int copied_fields = 0;
10350 for (int i = 0; i < limit; i++) {
10351 PropertyDetails details = descriptors->GetDetails(i);
10352 if (details.type() != FIELD) continue;
10354 int index = descriptors->GetFieldIndex(i);
10355 int property_offset = boilerplate_object->GetInObjectPropertyOffset(index);
10356 Handle<Name> name(descriptors->GetKey(i));
10357 Handle<Object> value =
10358 Handle<Object>(boilerplate_object->InObjectPropertyAt(index),
10361 // The access for the store depends on the type of the boilerplate.
10362 HObjectAccess access = boilerplate_object->IsJSArray() ?
10363 HObjectAccess::ForJSArrayOffset(property_offset) :
10364 HObjectAccess::ForMapAndOffset(boilerplate_map, property_offset);
10366 if (value->IsJSObject()) {
10367 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
10368 Handle<AllocationSite> current_site = site_context->EnterNewScope();
10369 HInstruction* result =
10370 BuildFastLiteral(value_object, site_context);
10371 site_context->ExitScope(current_site, value_object);
10372 Add<HStoreNamedField>(object, access, result);
10374 Representation representation = details.representation();
10375 HInstruction* value_instruction;
10377 if (representation.IsDouble()) {
10378 // Allocate a HeapNumber box and store the value into it.
10379 HValue* heap_number_constant = Add<HConstant>(HeapNumber::kSize);
10380 // This heap number alloc does not have a corresponding
10381 // AllocationSite. That is okay because
10382 // 1) it's a child object of another object with a valid allocation site
10383 // 2) we can just use the mode of the parent object for pretenuring
10384 HInstruction* double_box =
10385 Add<HAllocate>(heap_number_constant, HType::HeapNumber(),
10386 pretenure_flag, HEAP_NUMBER_TYPE);
10387 AddStoreMapConstant(double_box,
10388 isolate()->factory()->heap_number_map());
10389 Add<HStoreNamedField>(double_box, HObjectAccess::ForHeapNumberValue(),
10390 Add<HConstant>(value));
10391 value_instruction = double_box;
10392 } else if (representation.IsSmi()) {
10393 value_instruction = value->IsUninitialized()
10394 ? graph()->GetConstant0()
10395 : Add<HConstant>(value);
10396 // Ensure that value is stored as smi.
10397 access = access.WithRepresentation(representation);
10399 value_instruction = Add<HConstant>(value);
10402 Add<HStoreNamedField>(object, access, value_instruction);
10406 int inobject_properties = boilerplate_object->map()->inobject_properties();
10407 HInstruction* value_instruction =
10408 Add<HConstant>(isolate()->factory()->one_pointer_filler_map());
10409 for (int i = copied_fields; i < inobject_properties; i++) {
10410 ASSERT(boilerplate_object->IsJSObject());
10411 int property_offset = boilerplate_object->GetInObjectPropertyOffset(i);
10412 HObjectAccess access =
10413 HObjectAccess::ForMapAndOffset(boilerplate_map, property_offset);
10414 Add<HStoreNamedField>(object, access, value_instruction);
10419 void HOptimizedGraphBuilder::BuildEmitElements(
10420 Handle<JSObject> boilerplate_object,
10421 Handle<FixedArrayBase> elements,
10422 HValue* object_elements,
10423 AllocationSiteUsageContext* site_context) {
10424 ElementsKind kind = boilerplate_object->map()->elements_kind();
10425 int elements_length = elements->length();
10426 HValue* object_elements_length = Add<HConstant>(elements_length);
10427 BuildInitializeElementsHeader(object_elements, kind, object_elements_length);
10429 // Copy elements backing store content.
10430 if (elements->IsFixedDoubleArray()) {
10431 BuildEmitFixedDoubleArray(elements, kind, object_elements);
10432 } else if (elements->IsFixedArray()) {
10433 BuildEmitFixedArray(elements, kind, object_elements,
10441 void HOptimizedGraphBuilder::BuildEmitFixedDoubleArray(
10442 Handle<FixedArrayBase> elements,
10444 HValue* object_elements) {
10445 HInstruction* boilerplate_elements = Add<HConstant>(elements);
10446 int elements_length = elements->length();
10447 for (int i = 0; i < elements_length; i++) {
10448 HValue* key_constant = Add<HConstant>(i);
10449 HInstruction* value_instruction =
10450 Add<HLoadKeyed>(boilerplate_elements, key_constant,
10451 static_cast<HValue*>(NULL), kind,
10452 ALLOW_RETURN_HOLE);
10453 HInstruction* store = Add<HStoreKeyed>(object_elements, key_constant,
10454 value_instruction, kind);
10455 store->SetFlag(HValue::kAllowUndefinedAsNaN);
10460 void HOptimizedGraphBuilder::BuildEmitFixedArray(
10461 Handle<FixedArrayBase> elements,
10463 HValue* object_elements,
10464 AllocationSiteUsageContext* site_context) {
10465 HInstruction* boilerplate_elements = Add<HConstant>(elements);
10466 int elements_length = elements->length();
10467 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
10468 for (int i = 0; i < elements_length; i++) {
10469 Handle<Object> value(fast_elements->get(i), isolate());
10470 HValue* key_constant = Add<HConstant>(i);
10471 if (value->IsJSObject()) {
10472 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
10473 Handle<AllocationSite> current_site = site_context->EnterNewScope();
10474 HInstruction* result =
10475 BuildFastLiteral(value_object, site_context);
10476 site_context->ExitScope(current_site, value_object);
10477 Add<HStoreKeyed>(object_elements, key_constant, result, kind);
10479 HInstruction* value_instruction =
10480 Add<HLoadKeyed>(boilerplate_elements, key_constant,
10481 static_cast<HValue*>(NULL), kind,
10482 ALLOW_RETURN_HOLE);
10483 Add<HStoreKeyed>(object_elements, key_constant, value_instruction, kind);
10489 void HOptimizedGraphBuilder::VisitThisFunction(ThisFunction* expr) {
10490 ASSERT(!HasStackOverflow());
10491 ASSERT(current_block() != NULL);
10492 ASSERT(current_block()->HasPredecessor());
10493 HInstruction* instr = BuildThisFunction();
10494 return ast_context()->ReturnInstruction(instr, expr->id());
10498 void HOptimizedGraphBuilder::VisitDeclarations(
10499 ZoneList<Declaration*>* declarations) {
10500 ASSERT(globals_.is_empty());
10501 AstVisitor::VisitDeclarations(declarations);
10502 if (!globals_.is_empty()) {
10503 Handle<FixedArray> array =
10504 isolate()->factory()->NewFixedArray(globals_.length(), TENURED);
10505 for (int i = 0; i < globals_.length(); ++i) array->set(i, *globals_.at(i));
10506 int flags = DeclareGlobalsEvalFlag::encode(current_info()->is_eval()) |
10507 DeclareGlobalsNativeFlag::encode(current_info()->is_native()) |
10508 DeclareGlobalsStrictMode::encode(current_info()->strict_mode());
10509 Add<HDeclareGlobals>(array, flags);
10515 void HOptimizedGraphBuilder::VisitVariableDeclaration(
10516 VariableDeclaration* declaration) {
10517 VariableProxy* proxy = declaration->proxy();
10518 VariableMode mode = declaration->mode();
10519 Variable* variable = proxy->var();
10520 bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY;
10521 switch (variable->location()) {
10522 case Variable::UNALLOCATED:
10523 globals_.Add(variable->name(), zone());
10524 globals_.Add(variable->binding_needs_init()
10525 ? isolate()->factory()->the_hole_value()
10526 : isolate()->factory()->undefined_value(), zone());
10528 case Variable::PARAMETER:
10529 case Variable::LOCAL:
10531 HValue* value = graph()->GetConstantHole();
10532 environment()->Bind(variable, value);
10535 case Variable::CONTEXT:
10537 HValue* value = graph()->GetConstantHole();
10538 HValue* context = environment()->context();
10539 HStoreContextSlot* store = Add<HStoreContextSlot>(
10540 context, variable->index(), HStoreContextSlot::kNoCheck, value);
10541 if (store->HasObservableSideEffects()) {
10542 Add<HSimulate>(proxy->id(), REMOVABLE_SIMULATE);
10546 case Variable::LOOKUP:
10547 return Bailout(kUnsupportedLookupSlotInDeclaration);
10552 void HOptimizedGraphBuilder::VisitFunctionDeclaration(
10553 FunctionDeclaration* declaration) {
10554 VariableProxy* proxy = declaration->proxy();
10555 Variable* variable = proxy->var();
10556 switch (variable->location()) {
10557 case Variable::UNALLOCATED: {
10558 globals_.Add(variable->name(), zone());
10559 Handle<SharedFunctionInfo> function = Compiler::BuildFunctionInfo(
10560 declaration->fun(), current_info()->script());
10561 // Check for stack-overflow exception.
10562 if (function.is_null()) return SetStackOverflow();
10563 globals_.Add(function, zone());
10566 case Variable::PARAMETER:
10567 case Variable::LOCAL: {
10568 CHECK_ALIVE(VisitForValue(declaration->fun()));
10569 HValue* value = Pop();
10570 BindIfLive(variable, value);
10573 case Variable::CONTEXT: {
10574 CHECK_ALIVE(VisitForValue(declaration->fun()));
10575 HValue* value = Pop();
10576 HValue* context = environment()->context();
10577 HStoreContextSlot* store = Add<HStoreContextSlot>(
10578 context, variable->index(), HStoreContextSlot::kNoCheck, value);
10579 if (store->HasObservableSideEffects()) {
10580 Add<HSimulate>(proxy->id(), REMOVABLE_SIMULATE);
10584 case Variable::LOOKUP:
10585 return Bailout(kUnsupportedLookupSlotInDeclaration);
10590 void HOptimizedGraphBuilder::VisitModuleDeclaration(
10591 ModuleDeclaration* declaration) {
10596 void HOptimizedGraphBuilder::VisitImportDeclaration(
10597 ImportDeclaration* declaration) {
10602 void HOptimizedGraphBuilder::VisitExportDeclaration(
10603 ExportDeclaration* declaration) {
10608 void HOptimizedGraphBuilder::VisitModuleLiteral(ModuleLiteral* module) {
10613 void HOptimizedGraphBuilder::VisitModuleVariable(ModuleVariable* module) {
10618 void HOptimizedGraphBuilder::VisitModulePath(ModulePath* module) {
10623 void HOptimizedGraphBuilder::VisitModuleUrl(ModuleUrl* module) {
10628 void HOptimizedGraphBuilder::VisitModuleStatement(ModuleStatement* stmt) {
10633 // Generators for inline runtime functions.
10634 // Support for types.
10635 void HOptimizedGraphBuilder::GenerateIsSmi(CallRuntime* call) {
10636 ASSERT(call->arguments()->length() == 1);
10637 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10638 HValue* value = Pop();
10639 HIsSmiAndBranch* result = New<HIsSmiAndBranch>(value);
10640 return ast_context()->ReturnControl(result, call->id());
10644 void HOptimizedGraphBuilder::GenerateIsSpecObject(CallRuntime* call) {
10645 ASSERT(call->arguments()->length() == 1);
10646 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10647 HValue* value = Pop();
10648 HHasInstanceTypeAndBranch* result =
10649 New<HHasInstanceTypeAndBranch>(value,
10650 FIRST_SPEC_OBJECT_TYPE,
10651 LAST_SPEC_OBJECT_TYPE);
10652 return ast_context()->ReturnControl(result, call->id());
10656 void HOptimizedGraphBuilder::GenerateIsFunction(CallRuntime* call) {
10657 ASSERT(call->arguments()->length() == 1);
10658 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10659 HValue* value = Pop();
10660 HHasInstanceTypeAndBranch* result =
10661 New<HHasInstanceTypeAndBranch>(value, JS_FUNCTION_TYPE);
10662 return ast_context()->ReturnControl(result, call->id());
10666 void HOptimizedGraphBuilder::GenerateIsMinusZero(CallRuntime* call) {
10667 ASSERT(call->arguments()->length() == 1);
10668 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10669 HValue* value = Pop();
10670 HCompareMinusZeroAndBranch* result = New<HCompareMinusZeroAndBranch>(value);
10671 return ast_context()->ReturnControl(result, call->id());
10675 void HOptimizedGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) {
10676 ASSERT(call->arguments()->length() == 1);
10677 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10678 HValue* value = Pop();
10679 HHasCachedArrayIndexAndBranch* result =
10680 New<HHasCachedArrayIndexAndBranch>(value);
10681 return ast_context()->ReturnControl(result, call->id());
10685 void HOptimizedGraphBuilder::GenerateIsArray(CallRuntime* call) {
10686 ASSERT(call->arguments()->length() == 1);
10687 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10688 HValue* value = Pop();
10689 HHasInstanceTypeAndBranch* result =
10690 New<HHasInstanceTypeAndBranch>(value, JS_ARRAY_TYPE);
10691 return ast_context()->ReturnControl(result, call->id());
10695 void HOptimizedGraphBuilder::GenerateIsRegExp(CallRuntime* call) {
10696 ASSERT(call->arguments()->length() == 1);
10697 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10698 HValue* value = Pop();
10699 HHasInstanceTypeAndBranch* result =
10700 New<HHasInstanceTypeAndBranch>(value, JS_REGEXP_TYPE);
10701 return ast_context()->ReturnControl(result, call->id());
10705 void HOptimizedGraphBuilder::GenerateIsObject(CallRuntime* call) {
10706 ASSERT(call->arguments()->length() == 1);
10707 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10708 HValue* value = Pop();
10709 HIsObjectAndBranch* result = New<HIsObjectAndBranch>(value);
10710 return ast_context()->ReturnControl(result, call->id());
10714 void HOptimizedGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) {
10715 return Bailout(kInlinedRuntimeFunctionIsNonNegativeSmi);
10719 void HOptimizedGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) {
10720 ASSERT(call->arguments()->length() == 1);
10721 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10722 HValue* value = Pop();
10723 HIsUndetectableAndBranch* result = New<HIsUndetectableAndBranch>(value);
10724 return ast_context()->ReturnControl(result, call->id());
10728 void HOptimizedGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf(
10729 CallRuntime* call) {
10730 return Bailout(kInlinedRuntimeFunctionIsStringWrapperSafeForDefaultValueOf);
10734 // Support for construct call checks.
10735 void HOptimizedGraphBuilder::GenerateIsConstructCall(CallRuntime* call) {
10736 ASSERT(call->arguments()->length() == 0);
10737 if (function_state()->outer() != NULL) {
10738 // We are generating graph for inlined function.
10739 HValue* value = function_state()->inlining_kind() == CONSTRUCT_CALL_RETURN
10740 ? graph()->GetConstantTrue()
10741 : graph()->GetConstantFalse();
10742 return ast_context()->ReturnValue(value);
10744 return ast_context()->ReturnControl(New<HIsConstructCallAndBranch>(),
10750 // Support for arguments.length and arguments[?].
10751 void HOptimizedGraphBuilder::GenerateArgumentsLength(CallRuntime* call) {
10752 // Our implementation of arguments (based on this stack frame or an
10753 // adapter below it) does not work for inlined functions. This runtime
10754 // function is blacklisted by AstNode::IsInlineable.
10755 ASSERT(function_state()->outer() == NULL);
10756 ASSERT(call->arguments()->length() == 0);
10757 HInstruction* elements = Add<HArgumentsElements>(false);
10758 HArgumentsLength* result = New<HArgumentsLength>(elements);
10759 return ast_context()->ReturnInstruction(result, call->id());
10763 void HOptimizedGraphBuilder::GenerateArguments(CallRuntime* call) {
10764 // Our implementation of arguments (based on this stack frame or an
10765 // adapter below it) does not work for inlined functions. This runtime
10766 // function is blacklisted by AstNode::IsInlineable.
10767 ASSERT(function_state()->outer() == NULL);
10768 ASSERT(call->arguments()->length() == 1);
10769 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10770 HValue* index = Pop();
10771 HInstruction* elements = Add<HArgumentsElements>(false);
10772 HInstruction* length = Add<HArgumentsLength>(elements);
10773 HInstruction* checked_index = Add<HBoundsCheck>(index, length);
10774 HAccessArgumentsAt* result = New<HAccessArgumentsAt>(
10775 elements, length, checked_index);
10776 return ast_context()->ReturnInstruction(result, call->id());
10780 // Support for accessing the class and value fields of an object.
10781 void HOptimizedGraphBuilder::GenerateClassOf(CallRuntime* call) {
10782 // The special form detected by IsClassOfTest is detected before we get here
10783 // and does not cause a bailout.
10784 return Bailout(kInlinedRuntimeFunctionClassOf);
10788 void HOptimizedGraphBuilder::GenerateValueOf(CallRuntime* call) {
10789 ASSERT(call->arguments()->length() == 1);
10790 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10791 HValue* object = Pop();
10793 IfBuilder if_objectisvalue(this);
10794 HValue* objectisvalue = if_objectisvalue.If<HHasInstanceTypeAndBranch>(
10795 object, JS_VALUE_TYPE);
10796 if_objectisvalue.Then();
10798 // Return the actual value.
10799 Push(Add<HLoadNamedField>(
10800 object, objectisvalue,
10801 HObjectAccess::ForObservableJSObjectOffset(
10802 JSValue::kValueOffset)));
10803 Add<HSimulate>(call->id(), FIXED_SIMULATE);
10805 if_objectisvalue.Else();
10807 // If the object is not a value return the object.
10809 Add<HSimulate>(call->id(), FIXED_SIMULATE);
10811 if_objectisvalue.End();
10812 return ast_context()->ReturnValue(Pop());
10816 void HOptimizedGraphBuilder::GenerateDateField(CallRuntime* call) {
10817 ASSERT(call->arguments()->length() == 2);
10818 ASSERT_NE(NULL, call->arguments()->at(1)->AsLiteral());
10819 Smi* index = Smi::cast(*(call->arguments()->at(1)->AsLiteral()->value()));
10820 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10821 HValue* date = Pop();
10822 HDateField* result = New<HDateField>(date, index);
10823 return ast_context()->ReturnInstruction(result, call->id());
10827 void HOptimizedGraphBuilder::GenerateOneByteSeqStringSetChar(
10828 CallRuntime* call) {
10829 ASSERT(call->arguments()->length() == 3);
10830 // We need to follow the evaluation order of full codegen.
10831 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
10832 CHECK_ALIVE(VisitForValue(call->arguments()->at(2)));
10833 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10834 HValue* string = Pop();
10835 HValue* value = Pop();
10836 HValue* index = Pop();
10837 Add<HSeqStringSetChar>(String::ONE_BYTE_ENCODING, string,
10839 Add<HSimulate>(call->id(), FIXED_SIMULATE);
10840 return ast_context()->ReturnValue(graph()->GetConstantUndefined());
10844 void HOptimizedGraphBuilder::GenerateTwoByteSeqStringSetChar(
10845 CallRuntime* call) {
10846 ASSERT(call->arguments()->length() == 3);
10847 // We need to follow the evaluation order of full codegen.
10848 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
10849 CHECK_ALIVE(VisitForValue(call->arguments()->at(2)));
10850 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10851 HValue* string = Pop();
10852 HValue* value = Pop();
10853 HValue* index = Pop();
10854 Add<HSeqStringSetChar>(String::TWO_BYTE_ENCODING, string,
10856 Add<HSimulate>(call->id(), FIXED_SIMULATE);
10857 return ast_context()->ReturnValue(graph()->GetConstantUndefined());
10861 void HOptimizedGraphBuilder::GenerateSetValueOf(CallRuntime* call) {
10862 ASSERT(call->arguments()->length() == 2);
10863 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10864 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
10865 HValue* value = Pop();
10866 HValue* object = Pop();
10868 // Check if object is a JSValue.
10869 IfBuilder if_objectisvalue(this);
10870 if_objectisvalue.If<HHasInstanceTypeAndBranch>(object, JS_VALUE_TYPE);
10871 if_objectisvalue.Then();
10873 // Create in-object property store to kValueOffset.
10874 Add<HStoreNamedField>(object,
10875 HObjectAccess::ForObservableJSObjectOffset(JSValue::kValueOffset),
10877 if (!ast_context()->IsEffect()) {
10880 Add<HSimulate>(call->id(), FIXED_SIMULATE);
10882 if_objectisvalue.Else();
10884 // Nothing to do in this case.
10885 if (!ast_context()->IsEffect()) {
10888 Add<HSimulate>(call->id(), FIXED_SIMULATE);
10890 if_objectisvalue.End();
10891 if (!ast_context()->IsEffect()) {
10894 return ast_context()->ReturnValue(value);
10898 // Fast support for charCodeAt(n).
10899 void HOptimizedGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) {
10900 ASSERT(call->arguments()->length() == 2);
10901 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10902 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
10903 HValue* index = Pop();
10904 HValue* string = Pop();
10905 HInstruction* result = BuildStringCharCodeAt(string, index);
10906 return ast_context()->ReturnInstruction(result, call->id());
10910 // Fast support for string.charAt(n) and string[n].
10911 void HOptimizedGraphBuilder::GenerateStringCharFromCode(CallRuntime* call) {
10912 ASSERT(call->arguments()->length() == 1);
10913 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10914 HValue* char_code = Pop();
10915 HInstruction* result = NewUncasted<HStringCharFromCode>(char_code);
10916 return ast_context()->ReturnInstruction(result, call->id());
10920 // Fast support for string.charAt(n) and string[n].
10921 void HOptimizedGraphBuilder::GenerateStringCharAt(CallRuntime* call) {
10922 ASSERT(call->arguments()->length() == 2);
10923 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10924 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
10925 HValue* index = Pop();
10926 HValue* string = Pop();
10927 HInstruction* char_code = BuildStringCharCodeAt(string, index);
10928 AddInstruction(char_code);
10929 HInstruction* result = NewUncasted<HStringCharFromCode>(char_code);
10930 return ast_context()->ReturnInstruction(result, call->id());
10934 // Fast support for object equality testing.
10935 void HOptimizedGraphBuilder::GenerateObjectEquals(CallRuntime* call) {
10936 ASSERT(call->arguments()->length() == 2);
10937 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10938 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
10939 HValue* right = Pop();
10940 HValue* left = Pop();
10941 HCompareObjectEqAndBranch* result =
10942 New<HCompareObjectEqAndBranch>(left, right);
10943 return ast_context()->ReturnControl(result, call->id());
10947 void HOptimizedGraphBuilder::GenerateLog(CallRuntime* call) {
10948 // %_Log is ignored in optimized code.
10949 return ast_context()->ReturnValue(graph()->GetConstantUndefined());
10953 // Fast support for StringAdd.
10954 void HOptimizedGraphBuilder::GenerateStringAdd(CallRuntime* call) {
10955 ASSERT_EQ(2, call->arguments()->length());
10956 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10957 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
10958 HValue* right = Pop();
10959 HValue* left = Pop();
10960 HInstruction* result = NewUncasted<HStringAdd>(left, right);
10961 return ast_context()->ReturnInstruction(result, call->id());
10965 // Fast support for SubString.
10966 void HOptimizedGraphBuilder::GenerateSubString(CallRuntime* call) {
10967 ASSERT_EQ(3, call->arguments()->length());
10968 CHECK_ALIVE(VisitExpressions(call->arguments()));
10969 PushArgumentsFromEnvironment(call->arguments()->length());
10970 HCallStub* result = New<HCallStub>(CodeStub::SubString, 3);
10971 return ast_context()->ReturnInstruction(result, call->id());
10975 // Fast support for StringCompare.
10976 void HOptimizedGraphBuilder::GenerateStringCompare(CallRuntime* call) {
10977 ASSERT_EQ(2, call->arguments()->length());
10978 CHECK_ALIVE(VisitExpressions(call->arguments()));
10979 PushArgumentsFromEnvironment(call->arguments()->length());
10980 HCallStub* result = New<HCallStub>(CodeStub::StringCompare, 2);
10981 return ast_context()->ReturnInstruction(result, call->id());
10985 // Support for direct calls from JavaScript to native RegExp code.
10986 void HOptimizedGraphBuilder::GenerateRegExpExec(CallRuntime* call) {
10987 ASSERT_EQ(4, call->arguments()->length());
10988 CHECK_ALIVE(VisitExpressions(call->arguments()));
10989 PushArgumentsFromEnvironment(call->arguments()->length());
10990 HCallStub* result = New<HCallStub>(CodeStub::RegExpExec, 4);
10991 return ast_context()->ReturnInstruction(result, call->id());
10995 void HOptimizedGraphBuilder::GenerateDoubleLo(CallRuntime* call) {
10996 ASSERT_EQ(1, call->arguments()->length());
10997 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
10998 HValue* value = Pop();
10999 HInstruction* result = NewUncasted<HDoubleBits>(value, HDoubleBits::LOW);
11000 return ast_context()->ReturnInstruction(result, call->id());
11004 void HOptimizedGraphBuilder::GenerateDoubleHi(CallRuntime* call) {
11005 ASSERT_EQ(1, call->arguments()->length());
11006 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11007 HValue* value = Pop();
11008 HInstruction* result = NewUncasted<HDoubleBits>(value, HDoubleBits::HIGH);
11009 return ast_context()->ReturnInstruction(result, call->id());
11013 void HOptimizedGraphBuilder::GenerateConstructDouble(CallRuntime* call) {
11014 ASSERT_EQ(2, call->arguments()->length());
11015 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11016 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
11017 HValue* lo = Pop();
11018 HValue* hi = Pop();
11019 HInstruction* result = NewUncasted<HConstructDouble>(hi, lo);
11020 return ast_context()->ReturnInstruction(result, call->id());
11024 // Construct a RegExp exec result with two in-object properties.
11025 void HOptimizedGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) {
11026 ASSERT_EQ(3, call->arguments()->length());
11027 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11028 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
11029 CHECK_ALIVE(VisitForValue(call->arguments()->at(2)));
11030 HValue* input = Pop();
11031 HValue* index = Pop();
11032 HValue* length = Pop();
11033 HValue* result = BuildRegExpConstructResult(length, index, input);
11034 return ast_context()->ReturnValue(result);
11038 // Support for fast native caches.
11039 void HOptimizedGraphBuilder::GenerateGetFromCache(CallRuntime* call) {
11040 return Bailout(kInlinedRuntimeFunctionGetFromCache);
11044 // Fast support for number to string.
11045 void HOptimizedGraphBuilder::GenerateNumberToString(CallRuntime* call) {
11046 ASSERT_EQ(1, call->arguments()->length());
11047 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11048 HValue* number = Pop();
11049 HValue* result = BuildNumberToString(number, Type::Any(zone()));
11050 return ast_context()->ReturnValue(result);
11054 // Fast call for custom callbacks.
11055 void HOptimizedGraphBuilder::GenerateCallFunction(CallRuntime* call) {
11056 // 1 ~ The function to call is not itself an argument to the call.
11057 int arg_count = call->arguments()->length() - 1;
11058 ASSERT(arg_count >= 1); // There's always at least a receiver.
11060 CHECK_ALIVE(VisitExpressions(call->arguments()));
11061 // The function is the last argument
11062 HValue* function = Pop();
11063 // Push the arguments to the stack
11064 PushArgumentsFromEnvironment(arg_count);
11066 IfBuilder if_is_jsfunction(this);
11067 if_is_jsfunction.If<HHasInstanceTypeAndBranch>(function, JS_FUNCTION_TYPE);
11069 if_is_jsfunction.Then();
11071 HInstruction* invoke_result =
11072 Add<HInvokeFunction>(function, arg_count);
11073 if (!ast_context()->IsEffect()) {
11074 Push(invoke_result);
11076 Add<HSimulate>(call->id(), FIXED_SIMULATE);
11079 if_is_jsfunction.Else();
11081 HInstruction* call_result =
11082 Add<HCallFunction>(function, arg_count);
11083 if (!ast_context()->IsEffect()) {
11086 Add<HSimulate>(call->id(), FIXED_SIMULATE);
11088 if_is_jsfunction.End();
11090 if (ast_context()->IsEffect()) {
11091 // EffectContext::ReturnValue ignores the value, so we can just pass
11092 // 'undefined' (as we do not have the call result anymore).
11093 return ast_context()->ReturnValue(graph()->GetConstantUndefined());
11095 return ast_context()->ReturnValue(Pop());
11100 // Fast call to math functions.
11101 void HOptimizedGraphBuilder::GenerateMathPow(CallRuntime* call) {
11102 ASSERT_EQ(2, call->arguments()->length());
11103 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11104 CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
11105 HValue* right = Pop();
11106 HValue* left = Pop();
11107 HInstruction* result = NewUncasted<HPower>(left, right);
11108 return ast_context()->ReturnInstruction(result, call->id());
11112 void HOptimizedGraphBuilder::GenerateMathLog(CallRuntime* call) {
11113 ASSERT(call->arguments()->length() == 1);
11114 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11115 HValue* value = Pop();
11116 HInstruction* result = NewUncasted<HUnaryMathOperation>(value, kMathLog);
11117 return ast_context()->ReturnInstruction(result, call->id());
11121 void HOptimizedGraphBuilder::GenerateMathSqrt(CallRuntime* call) {
11122 ASSERT(call->arguments()->length() == 1);
11123 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11124 HValue* value = Pop();
11125 HInstruction* result = NewUncasted<HUnaryMathOperation>(value, kMathSqrt);
11126 return ast_context()->ReturnInstruction(result, call->id());
11130 void HOptimizedGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) {
11131 ASSERT(call->arguments()->length() == 1);
11132 CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
11133 HValue* value = Pop();
11134 HGetCachedArrayIndex* result = New<HGetCachedArrayIndex>(value);
11135 return ast_context()->ReturnInstruction(result, call->id());
11139 void HOptimizedGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) {
11140 return Bailout(kInlinedRuntimeFunctionFastAsciiArrayJoin);
11144 // Support for generators.
11145 void HOptimizedGraphBuilder::GenerateGeneratorNext(CallRuntime* call) {
11146 return Bailout(kInlinedRuntimeFunctionGeneratorNext);
11150 void HOptimizedGraphBuilder::GenerateGeneratorThrow(CallRuntime* call) {
11151 return Bailout(kInlinedRuntimeFunctionGeneratorThrow);
11155 void HOptimizedGraphBuilder::GenerateDebugBreakInOptimizedCode(
11156 CallRuntime* call) {
11157 Add<HDebugBreak>();
11158 return ast_context()->ReturnValue(graph()->GetConstant0());
11162 #undef CHECK_BAILOUT
11166 HEnvironment::HEnvironment(HEnvironment* outer,
11168 Handle<JSFunction> closure,
11170 : closure_(closure),
11172 frame_type_(JS_FUNCTION),
11173 parameter_count_(0),
11174 specials_count_(1),
11180 ast_id_(BailoutId::None()),
11182 Initialize(scope->num_parameters() + 1, scope->num_stack_slots(), 0);
11186 HEnvironment::HEnvironment(Zone* zone, int parameter_count)
11187 : values_(0, zone),
11189 parameter_count_(parameter_count),
11190 specials_count_(1),
11196 ast_id_(BailoutId::None()),
11198 Initialize(parameter_count, 0, 0);
11202 HEnvironment::HEnvironment(const HEnvironment* other, Zone* zone)
11203 : values_(0, zone),
11204 frame_type_(JS_FUNCTION),
11205 parameter_count_(0),
11206 specials_count_(0),
11212 ast_id_(other->ast_id()),
11218 HEnvironment::HEnvironment(HEnvironment* outer,
11219 Handle<JSFunction> closure,
11220 FrameType frame_type,
11223 : closure_(closure),
11224 values_(arguments, zone),
11225 frame_type_(frame_type),
11226 parameter_count_(arguments),
11227 specials_count_(0),
11233 ast_id_(BailoutId::None()),
11238 void HEnvironment::Initialize(int parameter_count,
11240 int stack_height) {
11241 parameter_count_ = parameter_count;
11242 local_count_ = local_count;
11244 // Avoid reallocating the temporaries' backing store on the first Push.
11245 int total = parameter_count + specials_count_ + local_count + stack_height;
11246 values_.Initialize(total + 4, zone());
11247 for (int i = 0; i < total; ++i) values_.Add(NULL, zone());
11251 void HEnvironment::Initialize(const HEnvironment* other) {
11252 closure_ = other->closure();
11253 values_.AddAll(other->values_, zone());
11254 assigned_variables_.Union(other->assigned_variables_, zone());
11255 frame_type_ = other->frame_type_;
11256 parameter_count_ = other->parameter_count_;
11257 local_count_ = other->local_count_;
11258 if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy.
11259 entry_ = other->entry_;
11260 pop_count_ = other->pop_count_;
11261 push_count_ = other->push_count_;
11262 specials_count_ = other->specials_count_;
11263 ast_id_ = other->ast_id_;
11267 void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) {
11268 ASSERT(!block->IsLoopHeader());
11269 ASSERT(values_.length() == other->values_.length());
11271 int length = values_.length();
11272 for (int i = 0; i < length; ++i) {
11273 HValue* value = values_[i];
11274 if (value != NULL && value->IsPhi() && value->block() == block) {
11275 // There is already a phi for the i'th value.
11276 HPhi* phi = HPhi::cast(value);
11277 // Assert index is correct and that we haven't missed an incoming edge.
11278 ASSERT(phi->merged_index() == i || !phi->HasMergedIndex());
11279 ASSERT(phi->OperandCount() == block->predecessors()->length());
11280 phi->AddInput(other->values_[i]);
11281 } else if (values_[i] != other->values_[i]) {
11282 // There is a fresh value on the incoming edge, a phi is needed.
11283 ASSERT(values_[i] != NULL && other->values_[i] != NULL);
11284 HPhi* phi = block->AddNewPhi(i);
11285 HValue* old_value = values_[i];
11286 for (int j = 0; j < block->predecessors()->length(); j++) {
11287 phi->AddInput(old_value);
11289 phi->AddInput(other->values_[i]);
11290 this->values_[i] = phi;
11296 void HEnvironment::Bind(int index, HValue* value) {
11297 ASSERT(value != NULL);
11298 assigned_variables_.Add(index, zone());
11299 values_[index] = value;
11303 bool HEnvironment::HasExpressionAt(int index) const {
11304 return index >= parameter_count_ + specials_count_ + local_count_;
11308 bool HEnvironment::ExpressionStackIsEmpty() const {
11309 ASSERT(length() >= first_expression_index());
11310 return length() == first_expression_index();
11314 void HEnvironment::SetExpressionStackAt(int index_from_top, HValue* value) {
11315 int count = index_from_top + 1;
11316 int index = values_.length() - count;
11317 ASSERT(HasExpressionAt(index));
11318 // The push count must include at least the element in question or else
11319 // the new value will not be included in this environment's history.
11320 if (push_count_ < count) {
11321 // This is the same effect as popping then re-pushing 'count' elements.
11322 pop_count_ += (count - push_count_);
11323 push_count_ = count;
11325 values_[index] = value;
11329 void HEnvironment::Drop(int count) {
11330 for (int i = 0; i < count; ++i) {
11336 HEnvironment* HEnvironment::Copy() const {
11337 return new(zone()) HEnvironment(this, zone());
11341 HEnvironment* HEnvironment::CopyWithoutHistory() const {
11342 HEnvironment* result = Copy();
11343 result->ClearHistory();
11348 HEnvironment* HEnvironment::CopyAsLoopHeader(HBasicBlock* loop_header) const {
11349 HEnvironment* new_env = Copy();
11350 for (int i = 0; i < values_.length(); ++i) {
11351 HPhi* phi = loop_header->AddNewPhi(i);
11352 phi->AddInput(values_[i]);
11353 new_env->values_[i] = phi;
11355 new_env->ClearHistory();
11360 HEnvironment* HEnvironment::CreateStubEnvironment(HEnvironment* outer,
11361 Handle<JSFunction> target,
11362 FrameType frame_type,
11363 int arguments) const {
11364 HEnvironment* new_env =
11365 new(zone()) HEnvironment(outer, target, frame_type,
11366 arguments + 1, zone());
11367 for (int i = 0; i <= arguments; ++i) { // Include receiver.
11368 new_env->Push(ExpressionStackAt(arguments - i));
11370 new_env->ClearHistory();
11375 HEnvironment* HEnvironment::CopyForInlining(
11376 Handle<JSFunction> target,
11378 FunctionLiteral* function,
11379 HConstant* undefined,
11380 InliningKind inlining_kind) const {
11381 ASSERT(frame_type() == JS_FUNCTION);
11383 // Outer environment is a copy of this one without the arguments.
11384 int arity = function->scope()->num_parameters();
11386 HEnvironment* outer = Copy();
11387 outer->Drop(arguments + 1); // Including receiver.
11388 outer->ClearHistory();
11390 if (inlining_kind == CONSTRUCT_CALL_RETURN) {
11391 // Create artificial constructor stub environment. The receiver should
11392 // actually be the constructor function, but we pass the newly allocated
11393 // object instead, DoComputeConstructStubFrame() relies on that.
11394 outer = CreateStubEnvironment(outer, target, JS_CONSTRUCT, arguments);
11395 } else if (inlining_kind == GETTER_CALL_RETURN) {
11396 // We need an additional StackFrame::INTERNAL frame for restoring the
11397 // correct context.
11398 outer = CreateStubEnvironment(outer, target, JS_GETTER, arguments);
11399 } else if (inlining_kind == SETTER_CALL_RETURN) {
11400 // We need an additional StackFrame::INTERNAL frame for temporarily saving
11401 // the argument of the setter, see StoreStubCompiler::CompileStoreViaSetter.
11402 outer = CreateStubEnvironment(outer, target, JS_SETTER, arguments);
11405 if (arity != arguments) {
11406 // Create artificial arguments adaptation environment.
11407 outer = CreateStubEnvironment(outer, target, ARGUMENTS_ADAPTOR, arguments);
11410 HEnvironment* inner =
11411 new(zone()) HEnvironment(outer, function->scope(), target, zone());
11412 // Get the argument values from the original environment.
11413 for (int i = 0; i <= arity; ++i) { // Include receiver.
11414 HValue* push = (i <= arguments) ?
11415 ExpressionStackAt(arguments - i) : undefined;
11416 inner->SetValueAt(i, push);
11418 inner->SetValueAt(arity + 1, context());
11419 for (int i = arity + 2; i < inner->length(); ++i) {
11420 inner->SetValueAt(i, undefined);
11423 inner->set_ast_id(BailoutId::FunctionEntry());
11428 void HEnvironment::PrintTo(StringStream* stream) {
11429 for (int i = 0; i < length(); i++) {
11430 if (i == 0) stream->Add("parameters\n");
11431 if (i == parameter_count()) stream->Add("specials\n");
11432 if (i == parameter_count() + specials_count()) stream->Add("locals\n");
11433 if (i == parameter_count() + specials_count() + local_count()) {
11434 stream->Add("expressions\n");
11436 HValue* val = values_.at(i);
11437 stream->Add("%d: ", i);
11439 val->PrintNameTo(stream);
11441 stream->Add("NULL");
11449 void HEnvironment::PrintToStd() {
11450 HeapStringAllocator string_allocator;
11451 StringStream trace(&string_allocator);
11453 PrintF("%s", trace.ToCString().get());
11457 void HTracer::TraceCompilation(CompilationInfo* info) {
11458 Tag tag(this, "compilation");
11459 if (info->IsOptimizing()) {
11460 Handle<String> name = info->function()->debug_name();
11461 PrintStringProperty("name", name->ToCString().get());
11463 trace_.Add("method \"%s:%d\"\n",
11464 name->ToCString().get(),
11465 info->optimization_id());
11467 CodeStub::Major major_key = info->code_stub()->MajorKey();
11468 PrintStringProperty("name", CodeStub::MajorName(major_key, false));
11469 PrintStringProperty("method", "stub");
11471 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis()));
11475 void HTracer::TraceLithium(const char* name, LChunk* chunk) {
11476 ASSERT(!chunk->isolate()->concurrent_recompilation_enabled());
11477 AllowHandleDereference allow_deref;
11478 AllowDeferredHandleDereference allow_deferred_deref;
11479 Trace(name, chunk->graph(), chunk);
11483 void HTracer::TraceHydrogen(const char* name, HGraph* graph) {
11484 ASSERT(!graph->isolate()->concurrent_recompilation_enabled());
11485 AllowHandleDereference allow_deref;
11486 AllowDeferredHandleDereference allow_deferred_deref;
11487 Trace(name, graph, NULL);
11491 void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) {
11492 Tag tag(this, "cfg");
11493 PrintStringProperty("name", name);
11494 const ZoneList<HBasicBlock*>* blocks = graph->blocks();
11495 for (int i = 0; i < blocks->length(); i++) {
11496 HBasicBlock* current = blocks->at(i);
11497 Tag block_tag(this, "block");
11498 PrintBlockProperty("name", current->block_id());
11499 PrintIntProperty("from_bci", -1);
11500 PrintIntProperty("to_bci", -1);
11502 if (!current->predecessors()->is_empty()) {
11504 trace_.Add("predecessors");
11505 for (int j = 0; j < current->predecessors()->length(); ++j) {
11506 trace_.Add(" \"B%d\"", current->predecessors()->at(j)->block_id());
11510 PrintEmptyProperty("predecessors");
11513 if (current->end()->SuccessorCount() == 0) {
11514 PrintEmptyProperty("successors");
11517 trace_.Add("successors");
11518 for (HSuccessorIterator it(current->end()); !it.Done(); it.Advance()) {
11519 trace_.Add(" \"B%d\"", it.Current()->block_id());
11524 PrintEmptyProperty("xhandlers");
11528 trace_.Add("flags");
11529 if (current->IsLoopSuccessorDominator()) {
11530 trace_.Add(" \"dom-loop-succ\"");
11532 if (current->IsUnreachable()) {
11533 trace_.Add(" \"dead\"");
11535 if (current->is_osr_entry()) {
11536 trace_.Add(" \"osr\"");
11541 if (current->dominator() != NULL) {
11542 PrintBlockProperty("dominator", current->dominator()->block_id());
11545 PrintIntProperty("loop_depth", current->LoopNestingDepth());
11547 if (chunk != NULL) {
11548 int first_index = current->first_instruction_index();
11549 int last_index = current->last_instruction_index();
11552 LifetimePosition::FromInstructionIndex(first_index).Value());
11555 LifetimePosition::FromInstructionIndex(last_index).Value());
11559 Tag states_tag(this, "states");
11560 Tag locals_tag(this, "locals");
11561 int total = current->phis()->length();
11562 PrintIntProperty("size", current->phis()->length());
11563 PrintStringProperty("method", "None");
11564 for (int j = 0; j < total; ++j) {
11565 HPhi* phi = current->phis()->at(j);
11567 trace_.Add("%d ", phi->merged_index());
11568 phi->PrintNameTo(&trace_);
11570 phi->PrintTo(&trace_);
11576 Tag HIR_tag(this, "HIR");
11577 for (HInstructionIterator it(current); !it.Done(); it.Advance()) {
11578 HInstruction* instruction = it.Current();
11579 int uses = instruction->UseCount();
11581 trace_.Add("0 %d ", uses);
11582 instruction->PrintNameTo(&trace_);
11584 instruction->PrintTo(&trace_);
11585 if (FLAG_hydrogen_track_positions &&
11586 instruction->has_position() &&
11587 instruction->position().raw() != 0) {
11588 const HSourcePosition pos = instruction->position();
11589 trace_.Add(" pos:");
11590 if (pos.inlining_id() != 0) {
11591 trace_.Add("%d_", pos.inlining_id());
11593 trace_.Add("%d", pos.position());
11595 trace_.Add(" <|@\n");
11600 if (chunk != NULL) {
11601 Tag LIR_tag(this, "LIR");
11602 int first_index = current->first_instruction_index();
11603 int last_index = current->last_instruction_index();
11604 if (first_index != -1 && last_index != -1) {
11605 const ZoneList<LInstruction*>* instructions = chunk->instructions();
11606 for (int i = first_index; i <= last_index; ++i) {
11607 LInstruction* linstr = instructions->at(i);
11608 if (linstr != NULL) {
11611 LifetimePosition::FromInstructionIndex(i).Value());
11612 linstr->PrintTo(&trace_);
11613 trace_.Add(" [hir:");
11614 linstr->hydrogen_value()->PrintNameTo(&trace_);
11616 trace_.Add(" <|@\n");
11625 void HTracer::TraceLiveRanges(const char* name, LAllocator* allocator) {
11626 Tag tag(this, "intervals");
11627 PrintStringProperty("name", name);
11629 const Vector<LiveRange*>* fixed_d = allocator->fixed_double_live_ranges();
11630 for (int i = 0; i < fixed_d->length(); ++i) {
11631 TraceLiveRange(fixed_d->at(i), "fixed", allocator->zone());
11634 const Vector<LiveRange*>* fixed = allocator->fixed_live_ranges();
11635 for (int i = 0; i < fixed->length(); ++i) {
11636 TraceLiveRange(fixed->at(i), "fixed", allocator->zone());
11639 const ZoneList<LiveRange*>* live_ranges = allocator->live_ranges();
11640 for (int i = 0; i < live_ranges->length(); ++i) {
11641 TraceLiveRange(live_ranges->at(i), "object", allocator->zone());
11646 void HTracer::TraceLiveRange(LiveRange* range, const char* type,
11648 if (range != NULL && !range->IsEmpty()) {
11650 trace_.Add("%d %s", range->id(), type);
11651 if (range->HasRegisterAssigned()) {
11652 LOperand* op = range->CreateAssignedOperand(zone);
11653 int assigned_reg = op->index();
11654 if (op->IsDoubleRegister()) {
11655 trace_.Add(" \"%s\"",
11656 DoubleRegister::AllocationIndexToString(assigned_reg));
11657 } else if (op->IsFloat32x4Register()) {
11658 trace_.Add(" \"%s\"",
11659 SIMD128Register::AllocationIndexToString(assigned_reg));
11660 } else if (op->IsInt32x4Register()) {
11661 trace_.Add(" \"%s\"",
11662 SIMD128Register::AllocationIndexToString(assigned_reg));
11664 ASSERT(op->IsRegister());
11665 trace_.Add(" \"%s\"", Register::AllocationIndexToString(assigned_reg));
11667 } else if (range->IsSpilled()) {
11668 LOperand* op = range->TopLevel()->GetSpillOperand();
11669 if (op->IsDoubleStackSlot()) {
11670 trace_.Add(" \"double_stack:%d\"", op->index());
11671 } else if (op->IsFloat32x4StackSlot()) {
11672 trace_.Add(" \"float32x4_stack:%d\"", op->index());
11673 } else if (op->IsInt32x4StackSlot()) {
11674 trace_.Add(" \"int32x4_stack:%d\"", op->index());
11676 ASSERT(op->IsStackSlot());
11677 trace_.Add(" \"stack:%d\"", op->index());
11680 int parent_index = -1;
11681 if (range->IsChild()) {
11682 parent_index = range->parent()->id();
11684 parent_index = range->id();
11686 LOperand* op = range->FirstHint();
11687 int hint_index = -1;
11688 if (op != NULL && op->IsUnallocated()) {
11689 hint_index = LUnallocated::cast(op)->virtual_register();
11691 trace_.Add(" %d %d", parent_index, hint_index);
11692 UseInterval* cur_interval = range->first_interval();
11693 while (cur_interval != NULL && range->Covers(cur_interval->start())) {
11694 trace_.Add(" [%d, %d[",
11695 cur_interval->start().Value(),
11696 cur_interval->end().Value());
11697 cur_interval = cur_interval->next();
11700 UsePosition* current_pos = range->first_pos();
11701 while (current_pos != NULL) {
11702 if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) {
11703 trace_.Add(" %d M", current_pos->pos().Value());
11705 current_pos = current_pos->next();
11708 trace_.Add(" \"\"\n");
11713 void HTracer::FlushToFile() {
11714 AppendChars(filename_.start(), trace_.ToCString().get(), trace_.length(),
11720 void HStatistics::Initialize(CompilationInfo* info) {
11721 if (info->shared_info().is_null()) return;
11722 source_size_ += info->shared_info()->SourceSize();
11726 void HStatistics::Print() {
11727 PrintF("Timing results:\n");
11729 for (int i = 0; i < times_.length(); ++i) {
11733 for (int i = 0; i < names_.length(); ++i) {
11734 PrintF("%32s", names_[i]);
11735 double ms = times_[i].InMillisecondsF();
11736 double percent = times_[i].PercentOf(sum);
11737 PrintF(" %8.3f ms / %4.1f %% ", ms, percent);
11739 unsigned size = sizes_[i];
11740 double size_percent = static_cast<double>(size) * 100 / total_size_;
11741 PrintF(" %9u bytes / %4.1f %%\n", size, size_percent);
11744 PrintF("----------------------------------------"
11745 "---------------------------------------\n");
11746 TimeDelta total = create_graph_ + optimize_graph_ + generate_code_;
11747 PrintF("%32s %8.3f ms / %4.1f %% \n",
11749 create_graph_.InMillisecondsF(),
11750 create_graph_.PercentOf(total));
11751 PrintF("%32s %8.3f ms / %4.1f %% \n",
11753 optimize_graph_.InMillisecondsF(),
11754 optimize_graph_.PercentOf(total));
11755 PrintF("%32s %8.3f ms / %4.1f %% \n",
11756 "Generate and install code",
11757 generate_code_.InMillisecondsF(),
11758 generate_code_.PercentOf(total));
11759 PrintF("----------------------------------------"
11760 "---------------------------------------\n");
11761 PrintF("%32s %8.3f ms (%.1f times slower than full code gen)\n",
11763 total.InMillisecondsF(),
11764 total.TimesOf(full_code_gen_));
11766 double source_size_in_kb = static_cast<double>(source_size_) / 1024;
11767 double normalized_time = source_size_in_kb > 0
11768 ? total.InMillisecondsF() / source_size_in_kb
11770 double normalized_size_in_kb = source_size_in_kb > 0
11771 ? total_size_ / 1024 / source_size_in_kb
11773 PrintF("%32s %8.3f ms %7.3f kB allocated\n",
11774 "Average per kB source",
11775 normalized_time, normalized_size_in_kb);
11779 void HStatistics::SaveTiming(const char* name, TimeDelta time, unsigned size) {
11780 total_size_ += size;
11781 for (int i = 0; i < names_.length(); ++i) {
11782 if (strcmp(names_[i], name) == 0) {
11794 HPhase::~HPhase() {
11795 if (ShouldProduceTraceOutput()) {
11796 isolate()->GetHTracer()->TraceHydrogen(name(), graph_);
11800 graph_->Verify(false); // No full verify.
11804 } } // namespace v8::internal