1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
10 #include "src/accessors.h"
11 #include "src/allocation.h"
13 #include "src/bailout-reason.h"
14 #include "src/compiler.h"
15 #include "src/hydrogen-instructions.h"
16 #include "src/scopes.h"
22 // Forward declarations.
27 class HLoopInformation;
35 class HBasicBlock FINAL : public ZoneObject {
37 explicit HBasicBlock(HGraph* graph);
41 int block_id() const { return block_id_; }
42 void set_block_id(int id) { block_id_ = id; }
43 HGraph* graph() const { return graph_; }
44 Isolate* isolate() const;
45 const ZoneList<HPhi*>* phis() const { return &phis_; }
46 HInstruction* first() const { return first_; }
47 HInstruction* last() const { return last_; }
48 void set_last(HInstruction* instr) { last_ = instr; }
49 HControlInstruction* end() const { return end_; }
50 HLoopInformation* loop_information() const { return loop_information_; }
51 HLoopInformation* current_loop() const {
52 return IsLoopHeader() ? loop_information()
53 : (parent_loop_header() != NULL
54 ? parent_loop_header()->loop_information() : NULL);
56 const ZoneList<HBasicBlock*>* predecessors() const { return &predecessors_; }
57 bool HasPredecessor() const { return predecessors_.length() > 0; }
58 const ZoneList<HBasicBlock*>* dominated_blocks() const {
59 return &dominated_blocks_;
61 const ZoneList<int>* deleted_phis() const {
62 return &deleted_phis_;
64 void RecordDeletedPhi(int merge_index) {
65 deleted_phis_.Add(merge_index, zone());
67 HBasicBlock* dominator() const { return dominator_; }
68 HEnvironment* last_environment() const { return last_environment_; }
69 int argument_count() const { return argument_count_; }
70 void set_argument_count(int count) { argument_count_ = count; }
71 int first_instruction_index() const { return first_instruction_index_; }
72 void set_first_instruction_index(int index) {
73 first_instruction_index_ = index;
75 int last_instruction_index() const { return last_instruction_index_; }
76 void set_last_instruction_index(int index) {
77 last_instruction_index_ = index;
79 bool is_osr_entry() { return is_osr_entry_; }
80 void set_osr_entry() { is_osr_entry_ = true; }
82 void AttachLoopInformation();
83 void DetachLoopInformation();
84 bool IsLoopHeader() const { return loop_information() != NULL; }
85 bool IsStartBlock() const { return block_id() == 0; }
86 void PostProcessLoopHeader(IterationStatement* stmt);
88 bool IsFinished() const { return end_ != NULL; }
89 void AddPhi(HPhi* phi);
90 void RemovePhi(HPhi* phi);
91 void AddInstruction(HInstruction* instr, SourcePosition position);
92 bool Dominates(HBasicBlock* other) const;
93 bool EqualToOrDominates(HBasicBlock* other) const;
94 int LoopNestingDepth() const;
96 void SetInitialEnvironment(HEnvironment* env);
97 void ClearEnvironment() {
99 DCHECK(end()->SuccessorCount() == 0);
100 last_environment_ = NULL;
102 bool HasEnvironment() const { return last_environment_ != NULL; }
103 void UpdateEnvironment(HEnvironment* env);
104 HBasicBlock* parent_loop_header() const { return parent_loop_header_; }
106 void set_parent_loop_header(HBasicBlock* block) {
107 DCHECK(parent_loop_header_ == NULL);
108 parent_loop_header_ = block;
111 bool HasParentLoopHeader() const { return parent_loop_header_ != NULL; }
113 void SetJoinId(BailoutId ast_id);
115 int PredecessorIndexOf(HBasicBlock* predecessor) const;
116 HPhi* AddNewPhi(int merged_index);
117 HSimulate* AddNewSimulate(BailoutId ast_id, SourcePosition position,
118 RemovableSimulate removable = FIXED_SIMULATE) {
119 HSimulate* instr = CreateSimulate(ast_id, removable);
120 AddInstruction(instr, position);
123 void AssignCommonDominator(HBasicBlock* other);
124 void AssignLoopSuccessorDominators();
126 // If a target block is tagged as an inline function return, all
127 // predecessors should contain the inlined exit sequence:
130 // Simulate (caller's environment)
131 // Goto (target block)
132 bool IsInlineReturnTarget() const { return is_inline_return_target_; }
133 void MarkAsInlineReturnTarget(HBasicBlock* inlined_entry_block) {
134 is_inline_return_target_ = true;
135 inlined_entry_block_ = inlined_entry_block;
137 HBasicBlock* inlined_entry_block() { return inlined_entry_block_; }
139 bool IsDeoptimizing() const {
140 return end() != NULL && end()->IsDeoptimize();
143 void MarkUnreachable();
144 bool IsUnreachable() const { return !is_reachable_; }
145 bool IsReachable() const { return is_reachable_; }
147 bool IsLoopSuccessorDominator() const {
148 return dominates_loop_successors_;
150 void MarkAsLoopSuccessorDominator() {
151 dominates_loop_successors_ = true;
154 bool IsOrdered() const { return is_ordered_; }
155 void MarkAsOrdered() { is_ordered_ = true; }
157 void MarkSuccEdgeUnreachable(int succ);
159 inline Zone* zone() const;
166 friend class HGraphBuilder;
168 HSimulate* CreateSimulate(BailoutId ast_id, RemovableSimulate removable);
169 void Finish(HControlInstruction* last, SourcePosition position);
170 void FinishExit(HControlInstruction* instruction, SourcePosition position);
171 void Goto(HBasicBlock* block, SourcePosition position,
172 FunctionState* state = NULL, bool add_simulate = true);
173 void GotoNoSimulate(HBasicBlock* block, SourcePosition position) {
174 Goto(block, position, NULL, false);
177 // Add the inlined function exit sequence, adding an HLeaveInlined
178 // instruction and updating the bailout environment.
179 void AddLeaveInlined(HValue* return_value, FunctionState* state,
180 SourcePosition position);
183 void RegisterPredecessor(HBasicBlock* pred);
184 void AddDominatedBlock(HBasicBlock* block);
188 ZoneList<HPhi*> phis_;
189 HInstruction* first_;
191 HControlInstruction* end_;
192 HLoopInformation* loop_information_;
193 ZoneList<HBasicBlock*> predecessors_;
194 HBasicBlock* dominator_;
195 ZoneList<HBasicBlock*> dominated_blocks_;
196 HEnvironment* last_environment_;
197 // Outgoing parameter count at block exit, set during lithium translation.
199 // Instruction indices into the lithium code stream.
200 int first_instruction_index_;
201 int last_instruction_index_;
202 ZoneList<int> deleted_phis_;
203 HBasicBlock* parent_loop_header_;
204 // For blocks marked as inline return target: the block with HEnterInlined.
205 HBasicBlock* inlined_entry_block_;
206 bool is_inline_return_target_ : 1;
207 bool is_reachable_ : 1;
208 bool dominates_loop_successors_ : 1;
209 bool is_osr_entry_ : 1;
210 bool is_ordered_ : 1;
214 std::ostream& operator<<(std::ostream& os, const HBasicBlock& b);
217 class HPredecessorIterator FINAL BASE_EMBEDDED {
219 explicit HPredecessorIterator(HBasicBlock* block)
220 : predecessor_list_(block->predecessors()), current_(0) { }
222 bool Done() { return current_ >= predecessor_list_->length(); }
223 HBasicBlock* Current() { return predecessor_list_->at(current_); }
224 void Advance() { current_++; }
227 const ZoneList<HBasicBlock*>* predecessor_list_;
232 class HInstructionIterator FINAL BASE_EMBEDDED {
234 explicit HInstructionIterator(HBasicBlock* block)
235 : instr_(block->first()) {
236 next_ = Done() ? NULL : instr_->next();
239 inline bool Done() const { return instr_ == NULL; }
240 inline HInstruction* Current() { return instr_; }
241 inline void Advance() {
243 next_ = Done() ? NULL : instr_->next();
247 HInstruction* instr_;
252 class HLoopInformation FINAL : public ZoneObject {
254 HLoopInformation(HBasicBlock* loop_header, Zone* zone)
255 : back_edges_(4, zone),
256 loop_header_(loop_header),
259 blocks_.Add(loop_header, zone);
261 ~HLoopInformation() {}
263 const ZoneList<HBasicBlock*>* back_edges() const { return &back_edges_; }
264 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
265 HBasicBlock* loop_header() const { return loop_header_; }
266 HBasicBlock* GetLastBackEdge() const;
267 void RegisterBackEdge(HBasicBlock* block);
269 HStackCheck* stack_check() const { return stack_check_; }
270 void set_stack_check(HStackCheck* stack_check) {
271 stack_check_ = stack_check;
274 bool IsNestedInThisLoop(HLoopInformation* other) {
275 while (other != NULL) {
279 other = other->parent_loop();
283 HLoopInformation* parent_loop() {
284 HBasicBlock* parent_header = loop_header()->parent_loop_header();
285 return parent_header != NULL ? parent_header->loop_information() : NULL;
289 void AddBlock(HBasicBlock* block);
291 ZoneList<HBasicBlock*> back_edges_;
292 HBasicBlock* loop_header_;
293 ZoneList<HBasicBlock*> blocks_;
294 HStackCheck* stack_check_;
298 class BoundsCheckTable;
299 class InductionVariableBlocksTable;
300 class HGraph FINAL : public ZoneObject {
302 explicit HGraph(CompilationInfo* info);
304 Isolate* isolate() const { return isolate_; }
305 Zone* zone() const { return zone_; }
306 CompilationInfo* info() const { return info_; }
308 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
309 const ZoneList<HPhi*>* phi_list() const { return phi_list_; }
310 HBasicBlock* entry_block() const { return entry_block_; }
311 HEnvironment* start_environment() const { return start_environment_; }
313 void FinalizeUniqueness();
315 void AssignDominators();
316 void RestoreActualValues();
318 // Returns false if there are phi-uses of the arguments-object
319 // which are not supported by the optimizing compiler.
320 bool CheckArgumentsPhiUses();
322 // Returns false if there are phi-uses of an uninitialized const
323 // which are not supported by the optimizing compiler.
324 bool CheckConstPhiUses();
328 HConstant* GetConstantUndefined();
329 HConstant* GetConstant0();
330 HConstant* GetConstant1();
331 HConstant* GetConstantMinus1();
332 HConstant* GetConstantTrue();
333 HConstant* GetConstantFalse();
334 HConstant* GetConstantHole();
335 HConstant* GetConstantNull();
336 HConstant* GetInvalidContext();
338 bool IsConstantUndefined(HConstant* constant);
339 bool IsConstant0(HConstant* constant);
340 bool IsConstant1(HConstant* constant);
341 bool IsConstantMinus1(HConstant* constant);
342 bool IsConstantTrue(HConstant* constant);
343 bool IsConstantFalse(HConstant* constant);
344 bool IsConstantHole(HConstant* constant);
345 bool IsConstantNull(HConstant* constant);
346 bool IsStandardConstant(HConstant* constant);
348 HBasicBlock* CreateBasicBlock();
349 HArgumentsObject* GetArgumentsObject() const {
350 return arguments_object_.get();
353 void SetArgumentsObject(HArgumentsObject* object) {
354 arguments_object_.set(object);
357 int GetMaximumValueID() const { return values_.length(); }
358 int GetNextBlockID() { return next_block_id_++; }
359 int GetNextValueID(HValue* value) {
360 DCHECK(!disallow_adding_new_values_);
361 values_.Add(value, zone());
362 return values_.length() - 1;
364 HValue* LookupValue(int id) const {
365 if (id >= 0 && id < values_.length()) return values_[id];
368 void DisallowAddingNewValues() {
369 disallow_adding_new_values_ = true;
372 bool Optimize(BailoutReason* bailout_reason);
375 void Verify(bool do_full_verify) const;
382 void set_osr(HOsrBuilder* osr) {
390 int update_type_change_checksum(int delta) {
391 type_change_checksum_ += delta;
392 return type_change_checksum_;
395 void update_maximum_environment_size(int environment_size) {
396 if (environment_size > maximum_environment_size_) {
397 maximum_environment_size_ = environment_size;
400 int maximum_environment_size() { return maximum_environment_size_; }
402 bool use_optimistic_licm() {
403 return use_optimistic_licm_;
406 void set_use_optimistic_licm(bool value) {
407 use_optimistic_licm_ = value;
410 void MarkRecursive() {
411 is_recursive_ = true;
414 bool is_recursive() const {
415 return is_recursive_;
418 void MarkDependsOnEmptyArrayProtoElements() {
419 // Add map dependency if not already added.
420 if (depends_on_empty_array_proto_elements_) return;
421 Map::AddDependentCompilationInfo(
422 handle(isolate()->initial_object_prototype()->map()),
423 DependentCode::kElementsCantBeAddedGroup, info());
424 Map::AddDependentCompilationInfo(
425 handle(isolate()->initial_array_prototype()->map()),
426 DependentCode::kElementsCantBeAddedGroup, info());
427 depends_on_empty_array_proto_elements_ = true;
430 bool depends_on_empty_array_proto_elements() {
431 return depends_on_empty_array_proto_elements_;
434 bool has_uint32_instructions() {
435 DCHECK(uint32_instructions_ == NULL || !uint32_instructions_->is_empty());
436 return uint32_instructions_ != NULL;
439 ZoneList<HInstruction*>* uint32_instructions() {
440 DCHECK(uint32_instructions_ == NULL || !uint32_instructions_->is_empty());
441 return uint32_instructions_;
444 void RecordUint32Instruction(HInstruction* instr) {
445 DCHECK(uint32_instructions_ == NULL || !uint32_instructions_->is_empty());
446 if (uint32_instructions_ == NULL) {
447 uint32_instructions_ = new(zone()) ZoneList<HInstruction*>(4, zone());
449 uint32_instructions_->Add(instr, zone());
452 void IncrementInNoSideEffectsScope() { no_side_effects_scope_count_++; }
453 void DecrementInNoSideEffectsScope() { no_side_effects_scope_count_--; }
454 bool IsInsideNoSideEffectsScope() { return no_side_effects_scope_count_ > 0; }
456 // If we are tracking source positions then this function assigns a unique
457 // identifier to each inlining and dumps function source if it was inlined
458 // for the first time during the current optimization.
459 int TraceInlinedFunction(Handle<SharedFunctionInfo> shared,
460 SourcePosition position);
462 // Converts given SourcePosition to the absolute offset from the start of
463 // the corresponding script.
464 int SourcePositionToScriptPosition(SourcePosition position);
467 HConstant* ReinsertConstantIfNecessary(HConstant* constant);
468 HConstant* GetConstant(SetOncePointer<HConstant>* pointer,
469 int32_t integer_value);
471 template<class Phase>
479 HBasicBlock* entry_block_;
480 HEnvironment* start_environment_;
481 ZoneList<HBasicBlock*> blocks_;
482 ZoneList<HValue*> values_;
483 ZoneList<HPhi*>* phi_list_;
484 ZoneList<HInstruction*>* uint32_instructions_;
485 SetOncePointer<HConstant> constant_undefined_;
486 SetOncePointer<HConstant> constant_0_;
487 SetOncePointer<HConstant> constant_1_;
488 SetOncePointer<HConstant> constant_minus1_;
489 SetOncePointer<HConstant> constant_true_;
490 SetOncePointer<HConstant> constant_false_;
491 SetOncePointer<HConstant> constant_the_hole_;
492 SetOncePointer<HConstant> constant_null_;
493 SetOncePointer<HConstant> constant_invalid_context_;
494 SetOncePointer<HArgumentsObject> arguments_object_;
498 CompilationInfo* info_;
502 bool use_optimistic_licm_;
503 bool depends_on_empty_array_proto_elements_;
504 int type_change_checksum_;
505 int maximum_environment_size_;
506 int no_side_effects_scope_count_;
507 bool disallow_adding_new_values_;
509 DISALLOW_COPY_AND_ASSIGN(HGraph);
513 Zone* HBasicBlock::zone() const { return graph_->zone(); }
516 // Type of stack frame an environment might refer to.
527 class HEnvironment FINAL : public ZoneObject {
529 HEnvironment(HEnvironment* outer,
531 Handle<JSFunction> closure,
534 HEnvironment(Zone* zone, int parameter_count);
536 HEnvironment* arguments_environment() {
537 return outer()->frame_type() == ARGUMENTS_ADAPTOR ? outer() : this;
541 Handle<JSFunction> closure() const { return closure_; }
542 const ZoneList<HValue*>* values() const { return &values_; }
543 const GrowableBitVector* assigned_variables() const {
544 return &assigned_variables_;
546 FrameType frame_type() const { return frame_type_; }
547 int parameter_count() const { return parameter_count_; }
548 int specials_count() const { return specials_count_; }
549 int local_count() const { return local_count_; }
550 HEnvironment* outer() const { return outer_; }
551 int pop_count() const { return pop_count_; }
552 int push_count() const { return push_count_; }
554 BailoutId ast_id() const { return ast_id_; }
555 void set_ast_id(BailoutId id) { ast_id_ = id; }
557 HEnterInlined* entry() const { return entry_; }
558 void set_entry(HEnterInlined* entry) { entry_ = entry; }
560 int length() const { return values_.length(); }
562 int first_expression_index() const {
563 return parameter_count() + specials_count() + local_count();
566 int first_local_index() const {
567 return parameter_count() + specials_count();
570 void Bind(Variable* variable, HValue* value) {
571 Bind(IndexFor(variable), value);
574 void Bind(int index, HValue* value);
576 void BindContext(HValue* value) {
577 Bind(parameter_count(), value);
580 HValue* Lookup(Variable* variable) const {
581 return Lookup(IndexFor(variable));
584 HValue* Lookup(int index) const {
585 HValue* result = values_[index];
586 DCHECK(result != NULL);
590 HValue* context() const {
591 // Return first special.
592 return Lookup(parameter_count());
595 void Push(HValue* value) {
596 DCHECK(value != NULL);
598 values_.Add(value, zone());
602 DCHECK(!ExpressionStackIsEmpty());
603 if (push_count_ > 0) {
608 return values_.RemoveLast();
611 void Drop(int count);
613 HValue* Top() const { return ExpressionStackAt(0); }
615 bool ExpressionStackIsEmpty() const;
617 HValue* ExpressionStackAt(int index_from_top) const {
618 int index = length() - index_from_top - 1;
619 DCHECK(HasExpressionAt(index));
620 return values_[index];
623 void SetExpressionStackAt(int index_from_top, HValue* value);
624 HValue* RemoveExpressionStackAt(int index_from_top);
626 HEnvironment* Copy() const;
627 HEnvironment* CopyWithoutHistory() const;
628 HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const;
630 // Create an "inlined version" of this environment, where the original
631 // environment is the outer environment but the top expression stack
632 // elements are moved to an inner environment as parameters.
633 HEnvironment* CopyForInlining(Handle<JSFunction> target,
635 FunctionLiteral* function,
636 HConstant* undefined,
637 InliningKind inlining_kind) const;
639 HEnvironment* DiscardInlined(bool drop_extra) {
640 HEnvironment* outer = outer_;
641 while (outer->frame_type() != JS_FUNCTION) outer = outer->outer_;
642 if (drop_extra) outer->Drop(1);
646 void AddIncomingEdge(HBasicBlock* block, HEnvironment* other);
648 void ClearHistory() {
651 assigned_variables_.Clear();
654 void SetValueAt(int index, HValue* value) {
655 DCHECK(index < length());
656 values_[index] = value;
659 // Map a variable to an environment index. Parameter indices are shifted
660 // by 1 (receiver is parameter index -1 but environment index 0).
661 // Stack-allocated local indices are shifted by the number of parameters.
662 int IndexFor(Variable* variable) const {
663 DCHECK(variable->IsStackAllocated());
664 int shift = variable->IsParameter()
666 : parameter_count_ + specials_count_;
667 return variable->index() + shift;
670 bool is_local_index(int i) const {
671 return i >= first_local_index() && i < first_expression_index();
674 bool is_parameter_index(int i) const {
675 return i >= 0 && i < parameter_count();
678 bool is_special_index(int i) const {
679 return i >= parameter_count() && i < parameter_count() + specials_count();
682 Zone* zone() const { return zone_; }
685 HEnvironment(const HEnvironment* other, Zone* zone);
687 HEnvironment(HEnvironment* outer,
688 Handle<JSFunction> closure,
689 FrameType frame_type,
693 // Create an artificial stub environment (e.g. for argument adaptor or
694 // constructor stub).
695 HEnvironment* CreateStubEnvironment(HEnvironment* outer,
696 Handle<JSFunction> target,
697 FrameType frame_type,
698 int arguments) const;
700 // True if index is included in the expression stack part of the environment.
701 bool HasExpressionAt(int index) const;
703 void Initialize(int parameter_count, int local_count, int stack_height);
704 void Initialize(const HEnvironment* other);
706 Handle<JSFunction> closure_;
707 // Value array [parameters] [specials] [locals] [temporaries].
708 ZoneList<HValue*> values_;
709 GrowableBitVector assigned_variables_;
710 FrameType frame_type_;
711 int parameter_count_;
714 HEnvironment* outer_;
715 HEnterInlined* entry_;
723 std::ostream& operator<<(std::ostream& os, const HEnvironment& env);
726 class HOptimizedGraphBuilder;
728 enum ArgumentsAllowedFlag {
729 ARGUMENTS_NOT_ALLOWED,
735 class HIfContinuation;
737 // This class is not BASE_EMBEDDED because our inlining implementation uses
741 bool IsEffect() const { return kind_ == Expression::kEffect; }
742 bool IsValue() const { return kind_ == Expression::kValue; }
743 bool IsTest() const { return kind_ == Expression::kTest; }
745 // 'Fill' this context with a hydrogen value. The value is assumed to
746 // have already been inserted in the instruction stream (or not need to
747 // be, e.g., HPhi). Call this function in tail position in the Visit
748 // functions for expressions.
749 virtual void ReturnValue(HValue* value) = 0;
751 // Add a hydrogen instruction to the instruction stream (recording an
752 // environment simulation if necessary) and then fill this context with
753 // the instruction as value.
754 virtual void ReturnInstruction(HInstruction* instr, BailoutId ast_id) = 0;
756 // Finishes the current basic block and materialize a boolean for
757 // value context, nothing for effect, generate a branch for test context.
758 // Call this function in tail position in the Visit functions for
760 virtual void ReturnControl(HControlInstruction* instr, BailoutId ast_id) = 0;
762 // Finishes the current basic block and materialize a boolean for
763 // value context, nothing for effect, generate a branch for test context.
764 // Call this function in tail position in the Visit functions for
765 // expressions that use an IfBuilder.
766 virtual void ReturnContinuation(HIfContinuation* continuation,
767 BailoutId ast_id) = 0;
769 void set_for_typeof(bool for_typeof) { for_typeof_ = for_typeof; }
770 bool is_for_typeof() { return for_typeof_; }
773 AstContext(HOptimizedGraphBuilder* owner, Expression::Context kind);
774 virtual ~AstContext();
776 HOptimizedGraphBuilder* owner() const { return owner_; }
778 inline Zone* zone() const;
780 // We want to be able to assert, in a context-specific way, that the stack
781 // height makes sense when the context is filled.
783 int original_length_;
787 HOptimizedGraphBuilder* owner_;
788 Expression::Context kind_;
794 class EffectContext FINAL : public AstContext {
796 explicit EffectContext(HOptimizedGraphBuilder* owner)
797 : AstContext(owner, Expression::kEffect) {
799 virtual ~EffectContext();
801 void ReturnValue(HValue* value) OVERRIDE;
802 virtual void ReturnInstruction(HInstruction* instr,
803 BailoutId ast_id) OVERRIDE;
804 virtual void ReturnControl(HControlInstruction* instr,
805 BailoutId ast_id) OVERRIDE;
806 virtual void ReturnContinuation(HIfContinuation* continuation,
807 BailoutId ast_id) OVERRIDE;
811 class ValueContext FINAL : public AstContext {
813 ValueContext(HOptimizedGraphBuilder* owner, ArgumentsAllowedFlag flag)
814 : AstContext(owner, Expression::kValue), flag_(flag) {
816 virtual ~ValueContext();
818 void ReturnValue(HValue* value) OVERRIDE;
819 virtual void ReturnInstruction(HInstruction* instr,
820 BailoutId ast_id) OVERRIDE;
821 virtual void ReturnControl(HControlInstruction* instr,
822 BailoutId ast_id) OVERRIDE;
823 virtual void ReturnContinuation(HIfContinuation* continuation,
824 BailoutId ast_id) OVERRIDE;
826 bool arguments_allowed() { return flag_ == ARGUMENTS_ALLOWED; }
829 ArgumentsAllowedFlag flag_;
833 class TestContext FINAL : public AstContext {
835 TestContext(HOptimizedGraphBuilder* owner,
836 Expression* condition,
837 HBasicBlock* if_true,
838 HBasicBlock* if_false)
839 : AstContext(owner, Expression::kTest),
840 condition_(condition),
842 if_false_(if_false) {
845 void ReturnValue(HValue* value) OVERRIDE;
846 virtual void ReturnInstruction(HInstruction* instr,
847 BailoutId ast_id) OVERRIDE;
848 virtual void ReturnControl(HControlInstruction* instr,
849 BailoutId ast_id) OVERRIDE;
850 virtual void ReturnContinuation(HIfContinuation* continuation,
851 BailoutId ast_id) OVERRIDE;
853 static TestContext* cast(AstContext* context) {
854 DCHECK(context->IsTest());
855 return reinterpret_cast<TestContext*>(context);
858 Expression* condition() const { return condition_; }
859 HBasicBlock* if_true() const { return if_true_; }
860 HBasicBlock* if_false() const { return if_false_; }
863 // Build the shared core part of the translation unpacking a value into
865 void BuildBranch(HValue* value);
867 Expression* condition_;
868 HBasicBlock* if_true_;
869 HBasicBlock* if_false_;
873 class FunctionState FINAL {
875 FunctionState(HOptimizedGraphBuilder* owner,
876 CompilationInfo* info,
877 InliningKind inlining_kind,
881 CompilationInfo* compilation_info() { return compilation_info_; }
882 AstContext* call_context() { return call_context_; }
883 InliningKind inlining_kind() const { return inlining_kind_; }
884 HBasicBlock* function_return() { return function_return_; }
885 TestContext* test_context() { return test_context_; }
886 void ClearInlinedTestContext() {
887 delete test_context_;
888 test_context_ = NULL;
891 FunctionState* outer() { return outer_; }
893 HEnterInlined* entry() { return entry_; }
894 void set_entry(HEnterInlined* entry) { entry_ = entry; }
896 HArgumentsObject* arguments_object() { return arguments_object_; }
897 void set_arguments_object(HArgumentsObject* arguments_object) {
898 arguments_object_ = arguments_object;
901 HArgumentsElements* arguments_elements() { return arguments_elements_; }
902 void set_arguments_elements(HArgumentsElements* arguments_elements) {
903 arguments_elements_ = arguments_elements;
906 bool arguments_pushed() { return arguments_elements() != NULL; }
908 int inlining_id() const { return inlining_id_; }
911 HOptimizedGraphBuilder* owner_;
913 CompilationInfo* compilation_info_;
915 // During function inlining, expression context of the call being
916 // inlined. NULL when not inlining.
917 AstContext* call_context_;
919 // The kind of call which is currently being inlined.
920 InliningKind inlining_kind_;
922 // When inlining in an effect or value context, this is the return block.
923 // It is NULL otherwise. When inlining in a test context, there are a
924 // pair of return blocks in the context. When not inlining, there is no
925 // local return point.
926 HBasicBlock* function_return_;
928 // When inlining a call in a test context, a context containing a pair of
929 // return blocks. NULL in all other cases.
930 TestContext* test_context_;
932 // When inlining HEnterInlined instruction corresponding to the function
934 HEnterInlined* entry_;
936 HArgumentsObject* arguments_object_;
937 HArgumentsElements* arguments_elements_;
940 SourcePosition outer_source_position_;
942 FunctionState* outer_;
946 class HIfContinuation FINAL {
949 : continuation_captured_(false),
951 false_branch_(NULL) {}
952 HIfContinuation(HBasicBlock* true_branch,
953 HBasicBlock* false_branch)
954 : continuation_captured_(true), true_branch_(true_branch),
955 false_branch_(false_branch) {}
956 ~HIfContinuation() { DCHECK(!continuation_captured_); }
958 void Capture(HBasicBlock* true_branch,
959 HBasicBlock* false_branch) {
960 DCHECK(!continuation_captured_);
961 true_branch_ = true_branch;
962 false_branch_ = false_branch;
963 continuation_captured_ = true;
966 void Continue(HBasicBlock** true_branch,
967 HBasicBlock** false_branch) {
968 DCHECK(continuation_captured_);
969 *true_branch = true_branch_;
970 *false_branch = false_branch_;
971 continuation_captured_ = false;
974 bool IsTrueReachable() { return true_branch_ != NULL; }
975 bool IsFalseReachable() { return false_branch_ != NULL; }
976 bool TrueAndFalseReachable() {
977 return IsTrueReachable() || IsFalseReachable();
980 HBasicBlock* true_branch() const { return true_branch_; }
981 HBasicBlock* false_branch() const { return false_branch_; }
984 bool continuation_captured_;
985 HBasicBlock* true_branch_;
986 HBasicBlock* false_branch_;
990 class HAllocationMode FINAL BASE_EMBEDDED {
992 explicit HAllocationMode(Handle<AllocationSite> feedback_site)
993 : current_site_(NULL), feedback_site_(feedback_site),
994 pretenure_flag_(NOT_TENURED) {}
995 explicit HAllocationMode(HValue* current_site)
996 : current_site_(current_site), pretenure_flag_(NOT_TENURED) {}
997 explicit HAllocationMode(PretenureFlag pretenure_flag)
998 : current_site_(NULL), pretenure_flag_(pretenure_flag) {}
1000 : current_site_(NULL), pretenure_flag_(NOT_TENURED) {}
1002 HValue* current_site() const { return current_site_; }
1003 Handle<AllocationSite> feedback_site() const { return feedback_site_; }
1005 bool CreateAllocationMementos() const WARN_UNUSED_RESULT {
1006 return current_site() != NULL;
1009 PretenureFlag GetPretenureMode() const WARN_UNUSED_RESULT {
1010 if (!feedback_site().is_null()) return feedback_site()->GetPretenureMode();
1011 return pretenure_flag_;
1015 HValue* current_site_;
1016 Handle<AllocationSite> feedback_site_;
1017 PretenureFlag pretenure_flag_;
1021 class HGraphBuilder {
1023 explicit HGraphBuilder(CompilationInfo* info)
1026 current_block_(NULL),
1027 scope_(info->scope()),
1028 position_(SourcePosition::Unknown()),
1029 start_position_(0) {}
1030 virtual ~HGraphBuilder() {}
1032 Scope* scope() const { return scope_; }
1033 void set_scope(Scope* scope) { scope_ = scope; }
1035 HBasicBlock* current_block() const { return current_block_; }
1036 void set_current_block(HBasicBlock* block) { current_block_ = block; }
1037 HEnvironment* environment() const {
1038 return current_block()->last_environment();
1040 Zone* zone() const { return info_->zone(); }
1041 HGraph* graph() const { return graph_; }
1042 Isolate* isolate() const { return graph_->isolate(); }
1043 CompilationInfo* top_info() { return info_; }
1045 HGraph* CreateGraph();
1047 // Bailout environment manipulation.
1048 void Push(HValue* value) { environment()->Push(value); }
1049 HValue* Pop() { return environment()->Pop(); }
1051 virtual HValue* context() = 0;
1053 // Adding instructions.
1054 HInstruction* AddInstruction(HInstruction* instr);
1055 void FinishCurrentBlock(HControlInstruction* last);
1056 void FinishExitCurrentBlock(HControlInstruction* instruction);
1058 void Goto(HBasicBlock* from,
1059 HBasicBlock* target,
1060 FunctionState* state = NULL,
1061 bool add_simulate = true) {
1062 from->Goto(target, source_position(), state, add_simulate);
1064 void Goto(HBasicBlock* target,
1065 FunctionState* state = NULL,
1066 bool add_simulate = true) {
1067 Goto(current_block(), target, state, add_simulate);
1069 void GotoNoSimulate(HBasicBlock* from, HBasicBlock* target) {
1070 Goto(from, target, NULL, false);
1072 void GotoNoSimulate(HBasicBlock* target) {
1073 Goto(target, NULL, false);
1075 void AddLeaveInlined(HBasicBlock* block,
1076 HValue* return_value,
1077 FunctionState* state) {
1078 block->AddLeaveInlined(return_value, state, source_position());
1080 void AddLeaveInlined(HValue* return_value, FunctionState* state) {
1081 return AddLeaveInlined(current_block(), return_value, state);
1085 HInstruction* NewUncasted() {
1086 return I::New(isolate(), zone(), context());
1091 return I::New(isolate(), zone(), context());
1095 HInstruction* AddUncasted() { return AddInstruction(NewUncasted<I>());}
1098 I* Add() { return AddInstructionTyped(New<I>());}
1100 template<class I, class P1>
1101 HInstruction* NewUncasted(P1 p1) {
1102 return I::New(isolate(), zone(), context(), p1);
1105 template <class I, class P1>
1107 return I::New(isolate(), zone(), context(), p1);
1110 template<class I, class P1>
1111 HInstruction* AddUncasted(P1 p1) {
1112 HInstruction* result = AddInstruction(NewUncasted<I>(p1));
1113 // Specializations must have their parameters properly casted
1114 // to avoid landing here.
1115 DCHECK(!result->IsReturn() && !result->IsSimulate() &&
1116 !result->IsDeoptimize());
1120 template<class I, class P1>
1122 I* result = AddInstructionTyped(New<I>(p1));
1123 // Specializations must have their parameters properly casted
1124 // to avoid landing here.
1125 DCHECK(!result->IsReturn() && !result->IsSimulate() &&
1126 !result->IsDeoptimize());
1130 template<class I, class P1, class P2>
1131 HInstruction* NewUncasted(P1 p1, P2 p2) {
1132 return I::New(isolate(), zone(), context(), p1, p2);
1135 template<class I, class P1, class P2>
1136 I* New(P1 p1, P2 p2) {
1137 return I::New(isolate(), zone(), context(), p1, p2);
1140 template<class I, class P1, class P2>
1141 HInstruction* AddUncasted(P1 p1, P2 p2) {
1142 HInstruction* result = AddInstruction(NewUncasted<I>(p1, p2));
1143 // Specializations must have their parameters properly casted
1144 // to avoid landing here.
1145 DCHECK(!result->IsSimulate());
1149 template<class I, class P1, class P2>
1150 I* Add(P1 p1, P2 p2) {
1151 I* result = AddInstructionTyped(New<I>(p1, p2));
1152 // Specializations must have their parameters properly casted
1153 // to avoid landing here.
1154 DCHECK(!result->IsSimulate());
1158 template<class I, class P1, class P2, class P3>
1159 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3) {
1160 return I::New(isolate(), zone(), context(), p1, p2, p3);
1163 template<class I, class P1, class P2, class P3>
1164 I* New(P1 p1, P2 p2, P3 p3) {
1165 return I::New(isolate(), zone(), context(), p1, p2, p3);
1168 template<class I, class P1, class P2, class P3>
1169 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3) {
1170 return AddInstruction(NewUncasted<I>(p1, p2, p3));
1173 template<class I, class P1, class P2, class P3>
1174 I* Add(P1 p1, P2 p2, P3 p3) {
1175 return AddInstructionTyped(New<I>(p1, p2, p3));
1178 template<class I, class P1, class P2, class P3, class P4>
1179 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4) {
1180 return I::New(isolate(), zone(), context(), p1, p2, p3, p4);
1183 template<class I, class P1, class P2, class P3, class P4>
1184 I* New(P1 p1, P2 p2, P3 p3, P4 p4) {
1185 return I::New(isolate(), zone(), context(), p1, p2, p3, p4);
1188 template<class I, class P1, class P2, class P3, class P4>
1189 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4) {
1190 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4));
1193 template<class I, class P1, class P2, class P3, class P4>
1194 I* Add(P1 p1, P2 p2, P3 p3, P4 p4) {
1195 return AddInstructionTyped(New<I>(p1, p2, p3, p4));
1198 template<class I, class P1, class P2, class P3, class P4, class P5>
1199 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
1200 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5);
1203 template<class I, class P1, class P2, class P3, class P4, class P5>
1204 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
1205 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5);
1208 template<class I, class P1, class P2, class P3, class P4, class P5>
1209 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
1210 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5));
1213 template<class I, class P1, class P2, class P3, class P4, class P5>
1214 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
1215 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5));
1218 template<class I, class P1, class P2, class P3, class P4, class P5, class P6>
1219 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {
1220 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6);
1223 template<class I, class P1, class P2, class P3, class P4, class P5, class P6>
1224 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {
1225 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6);
1228 template<class I, class P1, class P2, class P3, class P4, class P5, class P6>
1229 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {
1230 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6));
1233 template<class I, class P1, class P2, class P3, class P4, class P5, class P6>
1234 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {
1235 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5, p6));
1238 template<class I, class P1, class P2, class P3, class P4,
1239 class P5, class P6, class P7>
1240 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
1241 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6, p7);
1244 template<class I, class P1, class P2, class P3, class P4,
1245 class P5, class P6, class P7>
1246 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
1247 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6, p7);
1250 template<class I, class P1, class P2, class P3,
1251 class P4, class P5, class P6, class P7>
1252 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
1253 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6, p7));
1256 template<class I, class P1, class P2, class P3,
1257 class P4, class P5, class P6, class P7>
1258 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
1259 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5, p6, p7));
1262 template<class I, class P1, class P2, class P3, class P4,
1263 class P5, class P6, class P7, class P8>
1264 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4,
1265 P5 p5, P6 p6, P7 p7, P8 p8) {
1266 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6, p7, p8);
1269 template<class I, class P1, class P2, class P3, class P4,
1270 class P5, class P6, class P7, class P8>
1271 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) {
1272 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6, p7, p8);
1275 template<class I, class P1, class P2, class P3, class P4,
1276 class P5, class P6, class P7, class P8>
1277 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4,
1278 P5 p5, P6 p6, P7 p7, P8 p8) {
1279 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6, p7, p8));
1282 template<class I, class P1, class P2, class P3, class P4,
1283 class P5, class P6, class P7, class P8>
1284 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) {
1285 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5, p6, p7, p8));
1288 void AddSimulate(BailoutId id, RemovableSimulate removable = FIXED_SIMULATE);
1290 // When initializing arrays, we'll unfold the loop if the number of elements
1291 // is known at compile time and is <= kElementLoopUnrollThreshold.
1292 static const int kElementLoopUnrollThreshold = 8;
1295 virtual bool BuildGraph() = 0;
1297 HBasicBlock* CreateBasicBlock(HEnvironment* env);
1298 HBasicBlock* CreateLoopHeaderBlock();
1300 template <class BitFieldClass>
1301 HValue* BuildDecodeField(HValue* encoded_field) {
1302 HValue* mask_value = Add<HConstant>(static_cast<int>(BitFieldClass::kMask));
1303 HValue* masked_field =
1304 AddUncasted<HBitwise>(Token::BIT_AND, encoded_field, mask_value);
1305 return AddUncasted<HShr>(masked_field,
1306 Add<HConstant>(static_cast<int>(BitFieldClass::kShift)));
1309 HValue* BuildGetElementsKind(HValue* object);
1311 HValue* BuildCheckHeapObject(HValue* object);
1312 HValue* BuildCheckString(HValue* string);
1313 HValue* BuildWrapReceiver(HValue* object, HValue* function);
1315 // Building common constructs
1316 HValue* BuildCheckForCapacityGrow(HValue* object,
1322 PropertyAccessType access_type);
1324 HValue* BuildCopyElementsOnWrite(HValue* object,
1329 void BuildTransitionElementsKind(HValue* object,
1331 ElementsKind from_kind,
1332 ElementsKind to_kind,
1335 HValue* BuildNumberToString(HValue* object, Type* type);
1337 void BuildJSObjectCheck(HValue* receiver,
1338 int bit_field_mask);
1340 // Checks a key value that's being used for a keyed element access context. If
1341 // the key is a index, i.e. a smi or a number in a unique string with a cached
1342 // numeric value, the "true" of the continuation is joined. Otherwise,
1343 // if the key is a name or a unique string, the "false" of the continuation is
1344 // joined. Otherwise, a deoptimization is triggered. In both paths of the
1345 // continuation, the key is pushed on the top of the environment.
1346 void BuildKeyedIndexCheck(HValue* key,
1347 HIfContinuation* join_continuation);
1349 // Checks the properties of an object if they are in dictionary case, in which
1350 // case "true" of continuation is taken, otherwise the "false"
1351 void BuildTestForDictionaryProperties(HValue* object,
1352 HIfContinuation* continuation);
1354 void BuildNonGlobalObjectCheck(HValue* receiver);
1356 HValue* BuildKeyedLookupCacheHash(HValue* object,
1359 HValue* BuildUncheckedDictionaryElementLoad(HValue* receiver,
1364 HValue* BuildRegExpConstructResult(HValue* length,
1368 // Allocates a new object according with the given allocation properties.
1369 HAllocate* BuildAllocate(HValue* object_size,
1371 InstanceType instance_type,
1372 HAllocationMode allocation_mode);
1373 // Computes the sum of two string lengths, taking care of overflow handling.
1374 HValue* BuildAddStringLengths(HValue* left_length, HValue* right_length);
1375 // Creates a cons string using the two input strings.
1376 HValue* BuildCreateConsString(HValue* length,
1379 HAllocationMode allocation_mode);
1380 // Copies characters from one sequential string to another.
1381 void BuildCopySeqStringChars(HValue* src,
1383 String::Encoding src_encoding,
1386 String::Encoding dst_encoding,
1389 // Align an object size to object alignment boundary
1390 HValue* BuildObjectSizeAlignment(HValue* unaligned_size, int header_size);
1392 // Both operands are non-empty strings.
1393 HValue* BuildUncheckedStringAdd(HValue* left,
1395 HAllocationMode allocation_mode);
1396 // Add two strings using allocation mode, validating type feedback.
1397 HValue* BuildStringAdd(HValue* left,
1399 HAllocationMode allocation_mode);
1401 HInstruction* BuildUncheckedMonomorphicElementAccess(
1402 HValue* checked_object,
1406 ElementsKind elements_kind,
1407 PropertyAccessType access_type,
1408 LoadKeyedHoleMode load_mode,
1409 KeyedAccessStoreMode store_mode);
1411 HInstruction* AddElementAccess(
1413 HValue* checked_key,
1416 ElementsKind elements_kind,
1417 PropertyAccessType access_type,
1418 LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE);
1420 HInstruction* AddLoadStringInstanceType(HValue* string);
1421 HInstruction* AddLoadStringLength(HValue* string);
1422 HStoreNamedField* AddStoreMapConstant(HValue* object, Handle<Map> map) {
1423 return Add<HStoreNamedField>(object, HObjectAccess::ForMap(),
1424 Add<HConstant>(map));
1426 HLoadNamedField* AddLoadMap(HValue* object,
1427 HValue* dependency = NULL);
1428 HLoadNamedField* AddLoadElements(HValue* object,
1429 HValue* dependency = NULL);
1431 bool MatchRotateRight(HValue* left,
1434 HValue** shift_amount);
1436 HValue* BuildBinaryOperation(Token::Value op,
1442 Maybe<int> fixed_right_arg,
1443 HAllocationMode allocation_mode);
1445 HLoadNamedField* AddLoadFixedArrayLength(HValue *object,
1446 HValue *dependency = NULL);
1448 HLoadNamedField* AddLoadArrayLength(HValue *object,
1450 HValue *dependency = NULL);
1452 HValue* AddLoadJSBuiltin(Builtins::JavaScript builtin);
1454 HValue* EnforceNumberType(HValue* number, Type* expected);
1455 HValue* TruncateToNumber(HValue* value, Type** expected);
1457 void FinishExitWithHardDeoptimization(Deoptimizer::DeoptReason reason);
1459 void AddIncrementCounter(StatsCounter* counter);
1461 class IfBuilder FINAL {
1463 // If using this constructor, Initialize() must be called explicitly!
1466 explicit IfBuilder(HGraphBuilder* builder);
1467 IfBuilder(HGraphBuilder* builder,
1468 HIfContinuation* continuation);
1471 if (!finished_) End();
1474 void Initialize(HGraphBuilder* builder);
1476 template<class Condition>
1477 Condition* If(HValue *p) {
1478 Condition* compare = builder()->New<Condition>(p);
1479 AddCompare(compare);
1483 template<class Condition, class P2>
1484 Condition* If(HValue* p1, P2 p2) {
1485 Condition* compare = builder()->New<Condition>(p1, p2);
1486 AddCompare(compare);
1490 template<class Condition, class P2, class P3>
1491 Condition* If(HValue* p1, P2 p2, P3 p3) {
1492 Condition* compare = builder()->New<Condition>(p1, p2, p3);
1493 AddCompare(compare);
1497 template<class Condition>
1498 Condition* IfNot(HValue* p) {
1499 Condition* compare = If<Condition>(p);
1504 template<class Condition, class P2>
1505 Condition* IfNot(HValue* p1, P2 p2) {
1506 Condition* compare = If<Condition>(p1, p2);
1511 template<class Condition, class P2, class P3>
1512 Condition* IfNot(HValue* p1, P2 p2, P3 p3) {
1513 Condition* compare = If<Condition>(p1, p2, p3);
1518 template<class Condition>
1519 Condition* OrIf(HValue *p) {
1521 return If<Condition>(p);
1524 template<class Condition, class P2>
1525 Condition* OrIf(HValue* p1, P2 p2) {
1527 return If<Condition>(p1, p2);
1530 template<class Condition, class P2, class P3>
1531 Condition* OrIf(HValue* p1, P2 p2, P3 p3) {
1533 return If<Condition>(p1, p2, p3);
1536 template<class Condition>
1537 Condition* AndIf(HValue *p) {
1539 return If<Condition>(p);
1542 template<class Condition, class P2>
1543 Condition* AndIf(HValue* p1, P2 p2) {
1545 return If<Condition>(p1, p2);
1548 template<class Condition, class P2, class P3>
1549 Condition* AndIf(HValue* p1, P2 p2, P3 p3) {
1551 return If<Condition>(p1, p2, p3);
1557 // Captures the current state of this IfBuilder in the specified
1558 // continuation and ends this IfBuilder.
1559 void CaptureContinuation(HIfContinuation* continuation);
1561 // Joins the specified continuation from this IfBuilder and ends this
1562 // IfBuilder. This appends a Goto instruction from the true branch of
1563 // this IfBuilder to the true branch of the continuation unless the
1564 // true branch of this IfBuilder is already finished. And vice versa
1565 // for the false branch.
1567 // The basic idea is as follows: You have several nested IfBuilder's
1568 // that you want to join based on two possible outcomes (i.e. success
1569 // and failure, or whatever). You can do this easily using this method
1570 // now, for example:
1572 // HIfContinuation cont(graph()->CreateBasicBlock(),
1573 // graph()->CreateBasicBlock());
1575 // IfBuilder if_whatever(this);
1576 // if_whatever.If<Condition>(arg);
1577 // if_whatever.Then();
1579 // if_whatever.Else();
1581 // if_whatever.JoinContinuation(&cont);
1583 // IfBuilder if_something(this);
1584 // if_something.If<Condition>(arg1, arg2);
1585 // if_something.Then();
1587 // if_something.Else();
1589 // if_something.JoinContinuation(&cont);
1591 // IfBuilder if_finally(this, &cont);
1592 // if_finally.Then();
1593 // // continues after then code of if_whatever or if_something.
1595 // if_finally.Else();
1596 // // continues after else code of if_whatever or if_something.
1598 // if_finally.End();
1599 void JoinContinuation(HIfContinuation* continuation);
1605 void Deopt(Deoptimizer::DeoptReason reason);
1606 void ThenDeopt(Deoptimizer::DeoptReason reason) {
1610 void ElseDeopt(Deoptimizer::DeoptReason reason) {
1615 void Return(HValue* value);
1618 void InitializeDontCreateBlocks(HGraphBuilder* builder);
1620 HControlInstruction* AddCompare(HControlInstruction* compare);
1622 HGraphBuilder* builder() const {
1623 DCHECK(builder_ != NULL); // Have you called "Initialize"?
1627 void AddMergeAtJoinBlock(bool deopt);
1630 void Finish(HBasicBlock** then_continuation,
1631 HBasicBlock** else_continuation);
1633 class MergeAtJoinBlock : public ZoneObject {
1635 MergeAtJoinBlock(HBasicBlock* block,
1637 MergeAtJoinBlock* next)
1641 HBasicBlock* block_;
1643 MergeAtJoinBlock* next_;
1646 HGraphBuilder* builder_;
1650 bool did_else_if_ : 1;
1654 bool needs_compare_ : 1;
1655 bool pending_merge_block_ : 1;
1656 HBasicBlock* first_true_block_;
1657 HBasicBlock* first_false_block_;
1658 HBasicBlock* split_edge_merge_block_;
1659 MergeAtJoinBlock* merge_at_join_blocks_;
1660 int normal_merge_at_join_block_count_;
1661 int deopt_merge_at_join_block_count_;
1664 class LoopBuilder FINAL {
1674 explicit LoopBuilder(HGraphBuilder* builder); // while (true) {...}
1675 LoopBuilder(HGraphBuilder* builder,
1677 Direction direction);
1678 LoopBuilder(HGraphBuilder* builder,
1680 Direction direction,
1681 HValue* increment_amount);
1689 HValue* terminating,
1690 Token::Value token);
1692 void BeginBody(int drop_count);
1699 void Initialize(HGraphBuilder* builder, HValue* context,
1700 Direction direction, HValue* increment_amount);
1701 Zone* zone() { return builder_->zone(); }
1703 HGraphBuilder* builder_;
1705 HValue* increment_amount_;
1706 HInstruction* increment_;
1708 HBasicBlock* header_block_;
1709 HBasicBlock* body_block_;
1710 HBasicBlock* exit_block_;
1711 HBasicBlock* exit_trampoline_block_;
1712 Direction direction_;
1716 HValue* BuildNewElementsCapacity(HValue* old_capacity);
1718 class JSArrayBuilder FINAL {
1720 JSArrayBuilder(HGraphBuilder* builder,
1722 HValue* allocation_site_payload,
1723 HValue* constructor_function,
1724 AllocationSiteOverrideMode override_mode);
1726 JSArrayBuilder(HGraphBuilder* builder,
1728 HValue* constructor_function = NULL);
1731 DONT_FILL_WITH_HOLE,
1735 ElementsKind kind() { return kind_; }
1736 HAllocate* elements_location() { return elements_location_; }
1738 HAllocate* AllocateEmptyArray();
1739 HAllocate* AllocateArray(HValue* capacity,
1740 HValue* length_field,
1741 FillMode fill_mode = FILL_WITH_HOLE);
1742 // Use these allocators when capacity could be unknown at compile time
1743 // but its limit is known. For constant |capacity| the value of
1744 // |capacity_upper_bound| is ignored and the actual |capacity|
1745 // value is used as an upper bound.
1746 HAllocate* AllocateArray(HValue* capacity,
1747 int capacity_upper_bound,
1748 HValue* length_field,
1749 FillMode fill_mode = FILL_WITH_HOLE);
1750 HAllocate* AllocateArray(HValue* capacity,
1751 HConstant* capacity_upper_bound,
1752 HValue* length_field,
1753 FillMode fill_mode = FILL_WITH_HOLE);
1754 HValue* GetElementsLocation() { return elements_location_; }
1755 HValue* EmitMapCode();
1758 Zone* zone() const { return builder_->zone(); }
1759 int elements_size() const {
1760 return IsFastDoubleElementsKind(kind_) ? kDoubleSize : kPointerSize;
1762 HGraphBuilder* builder() { return builder_; }
1763 HGraph* graph() { return builder_->graph(); }
1764 int initial_capacity() {
1765 STATIC_ASSERT(JSArray::kPreallocatedArrayElements > 0);
1766 return JSArray::kPreallocatedArrayElements;
1769 HValue* EmitInternalMapCode();
1771 HGraphBuilder* builder_;
1773 AllocationSiteMode mode_;
1774 HValue* allocation_site_payload_;
1775 HValue* constructor_function_;
1776 HAllocate* elements_location_;
1779 HValue* BuildAllocateArrayFromLength(JSArrayBuilder* array_builder,
1780 HValue* length_argument);
1781 HValue* BuildCalculateElementsSize(ElementsKind kind,
1783 HAllocate* AllocateJSArrayObject(AllocationSiteMode mode);
1784 HConstant* EstablishElementsAllocationSize(ElementsKind kind, int capacity);
1786 HAllocate* BuildAllocateElements(ElementsKind kind, HValue* size_in_bytes);
1788 void BuildInitializeElementsHeader(HValue* elements,
1792 // Build allocation and header initialization code for respective successor
1793 // of FixedArrayBase.
1794 HValue* BuildAllocateAndInitializeArray(ElementsKind kind, HValue* capacity);
1796 // |array| must have been allocated with enough room for
1797 // 1) the JSArray and 2) an AllocationMemento if mode requires it.
1798 // If the |elements| value provided is NULL then the array elements storage
1799 // is initialized with empty array.
1800 void BuildJSArrayHeader(HValue* array,
1803 AllocationSiteMode mode,
1804 ElementsKind elements_kind,
1805 HValue* allocation_site_payload,
1806 HValue* length_field);
1808 HValue* BuildGrowElementsCapacity(HValue* object,
1811 ElementsKind new_kind,
1813 HValue* new_capacity);
1815 void BuildFillElementsWithValue(HValue* elements,
1816 ElementsKind elements_kind,
1821 void BuildFillElementsWithHole(HValue* elements,
1822 ElementsKind elements_kind,
1826 void BuildCopyProperties(HValue* from_properties, HValue* to_properties,
1827 HValue* length, HValue* capacity);
1829 void BuildCopyElements(HValue* from_elements,
1830 ElementsKind from_elements_kind,
1831 HValue* to_elements,
1832 ElementsKind to_elements_kind,
1836 HValue* BuildCloneShallowArrayCow(HValue* boilerplate,
1837 HValue* allocation_site,
1838 AllocationSiteMode mode,
1841 HValue* BuildCloneShallowArrayEmpty(HValue* boilerplate,
1842 HValue* allocation_site,
1843 AllocationSiteMode mode);
1845 HValue* BuildCloneShallowArrayNonEmpty(HValue* boilerplate,
1846 HValue* allocation_site,
1847 AllocationSiteMode mode,
1850 HValue* BuildElementIndexHash(HValue* index);
1852 enum MapEmbedding { kEmbedMapsDirectly, kEmbedMapsViaWeakCells };
1854 void BuildCompareNil(HValue* value, Type* type, HIfContinuation* continuation,
1855 MapEmbedding map_embedding = kEmbedMapsDirectly);
1857 void BuildCreateAllocationMemento(HValue* previous_object,
1858 HValue* previous_object_size,
1861 HInstruction* BuildConstantMapCheck(Handle<JSObject> constant);
1862 HInstruction* BuildCheckPrototypeMaps(Handle<JSObject> prototype,
1863 Handle<JSObject> holder);
1865 HInstruction* BuildGetNativeContext(HValue* closure);
1866 HInstruction* BuildGetNativeContext();
1867 HInstruction* BuildGetScriptContext(int context_index);
1868 HInstruction* BuildGetArrayFunction();
1871 void SetSourcePosition(int position) {
1872 DCHECK(position != RelocInfo::kNoPosition);
1873 position_.set_position(position - start_position_);
1876 void EnterInlinedSource(int start_position, int id) {
1877 if (FLAG_hydrogen_track_positions) {
1878 start_position_ = start_position;
1879 position_.set_inlining_id(id);
1883 // Convert the given absolute offset from the start of the script to
1884 // the SourcePosition assuming that this position corresponds to the
1885 // same function as current position_.
1886 SourcePosition ScriptPositionToSourcePosition(int position) {
1887 SourcePosition pos = position_;
1888 pos.set_position(position - start_position_);
1892 SourcePosition source_position() { return position_; }
1893 void set_source_position(SourcePosition position) { position_ = position; }
1895 template <typename ViewClass>
1896 void BuildArrayBufferViewInitialization(HValue* obj,
1898 HValue* byte_offset,
1899 HValue* byte_length);
1905 I* AddInstructionTyped(I* instr) {
1906 return I::cast(AddInstruction(instr));
1909 CompilationInfo* info_;
1911 HBasicBlock* current_block_;
1913 SourcePosition position_;
1914 int start_position_;
1919 inline HDeoptimize* HGraphBuilder::Add<HDeoptimize>(
1920 Deoptimizer::DeoptReason reason, Deoptimizer::BailoutType type) {
1921 if (type == Deoptimizer::SOFT) {
1922 isolate()->counters()->soft_deopts_requested()->Increment();
1923 if (FLAG_always_opt) return NULL;
1925 if (current_block()->IsDeoptimizing()) return NULL;
1926 HBasicBlock* after_deopt_block = CreateBasicBlock(
1927 current_block()->last_environment());
1928 HDeoptimize* instr = New<HDeoptimize>(reason, type, after_deopt_block);
1929 if (type == Deoptimizer::SOFT) {
1930 isolate()->counters()->soft_deopts_inserted()->Increment();
1932 FinishCurrentBlock(instr);
1933 set_current_block(after_deopt_block);
1939 inline HInstruction* HGraphBuilder::AddUncasted<HDeoptimize>(
1940 Deoptimizer::DeoptReason reason, Deoptimizer::BailoutType type) {
1941 return Add<HDeoptimize>(reason, type);
1946 inline HSimulate* HGraphBuilder::Add<HSimulate>(
1948 RemovableSimulate removable) {
1949 HSimulate* instr = current_block()->CreateSimulate(id, removable);
1950 AddInstruction(instr);
1956 inline HSimulate* HGraphBuilder::Add<HSimulate>(
1958 return Add<HSimulate>(id, FIXED_SIMULATE);
1963 inline HInstruction* HGraphBuilder::AddUncasted<HSimulate>(BailoutId id) {
1964 return Add<HSimulate>(id, FIXED_SIMULATE);
1969 inline HReturn* HGraphBuilder::Add<HReturn>(HValue* value) {
1970 int num_parameters = graph()->info()->num_parameters();
1971 HValue* params = AddUncasted<HConstant>(num_parameters);
1972 HReturn* return_instruction = New<HReturn>(value, params);
1973 FinishExitCurrentBlock(return_instruction);
1974 return return_instruction;
1979 inline HReturn* HGraphBuilder::Add<HReturn>(HConstant* value) {
1980 return Add<HReturn>(static_cast<HValue*>(value));
1984 inline HInstruction* HGraphBuilder::AddUncasted<HReturn>(HValue* value) {
1985 return Add<HReturn>(value);
1990 inline HInstruction* HGraphBuilder::AddUncasted<HReturn>(HConstant* value) {
1991 return Add<HReturn>(value);
1996 inline HCallRuntime* HGraphBuilder::Add<HCallRuntime>(
1997 Handle<String> name,
1998 const Runtime::Function* c_function,
1999 int argument_count) {
2000 HCallRuntime* instr = New<HCallRuntime>(name, c_function, argument_count);
2001 if (graph()->info()->IsStub()) {
2002 // When compiling code stubs, we don't want to save all double registers
2003 // upon entry to the stub, but instead have the call runtime instruction
2004 // save the double registers only on-demand (in the fallback case).
2005 instr->set_save_doubles(kSaveFPRegs);
2007 AddInstruction(instr);
2013 inline HInstruction* HGraphBuilder::AddUncasted<HCallRuntime>(
2014 Handle<String> name,
2015 const Runtime::Function* c_function,
2016 int argument_count) {
2017 return Add<HCallRuntime>(name, c_function, argument_count);
2022 inline HContext* HGraphBuilder::New<HContext>() {
2023 return HContext::New(zone());
2028 inline HInstruction* HGraphBuilder::NewUncasted<HContext>() {
2029 return New<HContext>();
2032 class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
2034 // A class encapsulating (lazily-allocated) break and continue blocks for
2035 // a breakable statement. Separated from BreakAndContinueScope so that it
2036 // can have a separate lifetime.
2037 class BreakAndContinueInfo FINAL BASE_EMBEDDED {
2039 explicit BreakAndContinueInfo(BreakableStatement* target,
2044 continue_block_(NULL),
2046 drop_extra_(drop_extra) {
2049 BreakableStatement* target() { return target_; }
2050 HBasicBlock* break_block() { return break_block_; }
2051 void set_break_block(HBasicBlock* block) { break_block_ = block; }
2052 HBasicBlock* continue_block() { return continue_block_; }
2053 void set_continue_block(HBasicBlock* block) { continue_block_ = block; }
2054 Scope* scope() { return scope_; }
2055 int drop_extra() { return drop_extra_; }
2058 BreakableStatement* target_;
2059 HBasicBlock* break_block_;
2060 HBasicBlock* continue_block_;
2065 // A helper class to maintain a stack of current BreakAndContinueInfo
2066 // structures mirroring BreakableStatement nesting.
2067 class BreakAndContinueScope FINAL BASE_EMBEDDED {
2069 BreakAndContinueScope(BreakAndContinueInfo* info,
2070 HOptimizedGraphBuilder* owner)
2071 : info_(info), owner_(owner), next_(owner->break_scope()) {
2072 owner->set_break_scope(this);
2075 ~BreakAndContinueScope() { owner_->set_break_scope(next_); }
2077 BreakAndContinueInfo* info() { return info_; }
2078 HOptimizedGraphBuilder* owner() { return owner_; }
2079 BreakAndContinueScope* next() { return next_; }
2081 // Search the break stack for a break or continue target.
2082 enum BreakType { BREAK, CONTINUE };
2083 HBasicBlock* Get(BreakableStatement* stmt, BreakType type,
2084 Scope** scope, int* drop_extra);
2087 BreakAndContinueInfo* info_;
2088 HOptimizedGraphBuilder* owner_;
2089 BreakAndContinueScope* next_;
2092 explicit HOptimizedGraphBuilder(CompilationInfo* info);
2094 bool BuildGraph() OVERRIDE;
2096 // Simple accessors.
2097 BreakAndContinueScope* break_scope() const { return break_scope_; }
2098 void set_break_scope(BreakAndContinueScope* head) { break_scope_ = head; }
2100 HValue* context() OVERRIDE { return environment()->context(); }
2102 HOsrBuilder* osr() const { return osr_; }
2104 void Bailout(BailoutReason reason);
2106 HBasicBlock* CreateJoin(HBasicBlock* first,
2107 HBasicBlock* second,
2110 FunctionState* function_state() const { return function_state_; }
2112 void VisitDeclarations(ZoneList<Declaration*>* declarations) OVERRIDE;
2114 void* operator new(size_t size, Zone* zone) { return zone->New(size); }
2115 void operator delete(void* pointer, Zone* zone) { }
2116 void operator delete(void* pointer) { }
2118 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
2121 // Type of a member function that generates inline code for a native function.
2122 typedef void (HOptimizedGraphBuilder::*InlineFunctionGenerator)
2123 (CallRuntime* call);
2125 // Forward declarations for inner scope classes.
2126 class SubgraphScope;
2128 static const InlineFunctionGenerator kInlineFunctionGenerators[];
2130 static const int kMaxCallPolymorphism = 4;
2131 static const int kMaxLoadPolymorphism = 4;
2132 static const int kMaxStorePolymorphism = 4;
2134 // Even in the 'unlimited' case we have to have some limit in order not to
2135 // overflow the stack.
2136 static const int kUnlimitedMaxInlinedSourceSize = 100000;
2137 static const int kUnlimitedMaxInlinedNodes = 10000;
2138 static const int kUnlimitedMaxInlinedNodesCumulative = 10000;
2140 // Maximum depth and total number of elements and properties for literal
2141 // graphs to be considered for fast deep-copying.
2142 static const int kMaxFastLiteralDepth = 3;
2143 static const int kMaxFastLiteralProperties = 8;
2145 // Simple accessors.
2146 void set_function_state(FunctionState* state) { function_state_ = state; }
2148 AstContext* ast_context() const { return ast_context_; }
2149 void set_ast_context(AstContext* context) { ast_context_ = context; }
2151 // Accessors forwarded to the function state.
2152 CompilationInfo* current_info() const {
2153 return function_state()->compilation_info();
2155 AstContext* call_context() const {
2156 return function_state()->call_context();
2158 HBasicBlock* function_return() const {
2159 return function_state()->function_return();
2161 TestContext* inlined_test_context() const {
2162 return function_state()->test_context();
2164 void ClearInlinedTestContext() {
2165 function_state()->ClearInlinedTestContext();
2167 LanguageMode function_language_mode() {
2168 return function_state()->compilation_info()->language_mode();
2171 // Generators for inline runtime functions.
2172 #define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \
2173 void Generate##Name(CallRuntime* call);
2175 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
2176 INLINE_OPTIMIZED_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
2177 #undef INLINE_FUNCTION_GENERATOR_DECLARATION
2179 void VisitDelete(UnaryOperation* expr);
2180 void VisitVoid(UnaryOperation* expr);
2181 void VisitTypeof(UnaryOperation* expr);
2182 void VisitNot(UnaryOperation* expr);
2184 void VisitComma(BinaryOperation* expr);
2185 void VisitLogicalExpression(BinaryOperation* expr);
2186 void VisitArithmeticExpression(BinaryOperation* expr);
2188 void VisitLoopBody(IterationStatement* stmt,
2189 HBasicBlock* loop_entry);
2191 // Create a back edge in the flow graph. body_exit is the predecessor
2192 // block and loop_entry is the successor block. loop_successor is the
2193 // block where control flow exits the loop normally (e.g., via failure of
2194 // the condition) and break_block is the block where control flow breaks
2195 // from the loop. All blocks except loop_entry can be NULL. The return
2196 // value is the new successor block which is the join of loop_successor
2197 // and break_block, or NULL.
2198 HBasicBlock* CreateLoop(IterationStatement* statement,
2199 HBasicBlock* loop_entry,
2200 HBasicBlock* body_exit,
2201 HBasicBlock* loop_successor,
2202 HBasicBlock* break_block);
2204 // Build a loop entry
2205 HBasicBlock* BuildLoopEntry();
2207 // Builds a loop entry respectful of OSR requirements
2208 HBasicBlock* BuildLoopEntry(IterationStatement* statement);
2210 HBasicBlock* JoinContinue(IterationStatement* statement,
2211 HBasicBlock* exit_block,
2212 HBasicBlock* continue_block);
2214 HValue* Top() const { return environment()->Top(); }
2215 void Drop(int n) { environment()->Drop(n); }
2216 void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); }
2217 bool IsEligibleForEnvironmentLivenessAnalysis(Variable* var,
2220 HEnvironment* env) {
2221 if (!FLAG_analyze_environment_liveness) return false;
2222 // |this| and |arguments| are always live; zapping parameters isn't
2223 // safe because function.arguments can inspect them at any time.
2224 return !var->is_this() &&
2225 !var->is_arguments() &&
2226 !value->IsArgumentsObject() &&
2227 env->is_local_index(index);
2229 void BindIfLive(Variable* var, HValue* value) {
2230 HEnvironment* env = environment();
2231 int index = env->IndexFor(var);
2232 env->Bind(index, value);
2233 if (IsEligibleForEnvironmentLivenessAnalysis(var, index, value, env)) {
2234 HEnvironmentMarker* bind =
2235 Add<HEnvironmentMarker>(HEnvironmentMarker::BIND, index);
2238 bind->set_closure(env->closure());
2242 HValue* LookupAndMakeLive(Variable* var) {
2243 HEnvironment* env = environment();
2244 int index = env->IndexFor(var);
2245 HValue* value = env->Lookup(index);
2246 if (IsEligibleForEnvironmentLivenessAnalysis(var, index, value, env)) {
2247 HEnvironmentMarker* lookup =
2248 Add<HEnvironmentMarker>(HEnvironmentMarker::LOOKUP, index);
2251 lookup->set_closure(env->closure());
2257 // The value of the arguments object is allowed in some but not most value
2258 // contexts. (It's allowed in all effect contexts and disallowed in all
2260 void VisitForValue(Expression* expr,
2261 ArgumentsAllowedFlag flag = ARGUMENTS_NOT_ALLOWED);
2262 void VisitForTypeOf(Expression* expr);
2263 void VisitForEffect(Expression* expr);
2264 void VisitForControl(Expression* expr,
2265 HBasicBlock* true_block,
2266 HBasicBlock* false_block);
2268 // Visit a list of expressions from left to right, each in a value context.
2269 void VisitExpressions(ZoneList<Expression*>* exprs) OVERRIDE;
2270 void VisitExpressions(ZoneList<Expression*>* exprs,
2271 ArgumentsAllowedFlag flag);
2273 // Remove the arguments from the bailout environment and emit instructions
2274 // to push them as outgoing parameters.
2275 template <class Instruction> HInstruction* PreProcessCall(Instruction* call);
2276 void PushArgumentsFromEnvironment(int count);
2278 void SetUpScope(Scope* scope);
2279 void VisitStatements(ZoneList<Statement*>* statements) OVERRIDE;
2281 #define DECLARE_VISIT(type) virtual void Visit##type(type* node) OVERRIDE;
2282 AST_NODE_LIST(DECLARE_VISIT)
2283 #undef DECLARE_VISIT
2286 // Helpers for flow graph construction.
2287 enum GlobalPropertyAccess {
2291 GlobalPropertyAccess LookupGlobalProperty(Variable* var, LookupIterator* it,
2292 PropertyAccessType access_type);
2294 void EnsureArgumentsArePushedForAccess();
2295 bool TryArgumentsAccess(Property* expr);
2297 // Shared code for .call and .apply optimizations.
2298 void HandleIndirectCall(Call* expr, HValue* function, int arguments_count);
2299 // Try to optimize indirect calls such as fun.apply(receiver, arguments)
2300 // or fun.call(...).
2301 bool TryIndirectCall(Call* expr);
2302 void BuildFunctionApply(Call* expr);
2303 void BuildFunctionCall(Call* expr);
2305 bool TryHandleArrayCall(Call* expr, HValue* function);
2306 bool TryHandleArrayCallNew(CallNew* expr, HValue* function);
2307 void BuildArrayCall(Expression* expr, int arguments_count, HValue* function,
2308 Handle<AllocationSite> cell);
2310 enum ArrayIndexOfMode { kFirstIndexOf, kLastIndexOf };
2311 HValue* BuildArrayIndexOf(HValue* receiver,
2312 HValue* search_element,
2314 ArrayIndexOfMode mode);
2316 HValue* ImplicitReceiverFor(HValue* function,
2317 Handle<JSFunction> target);
2319 int InliningAstSize(Handle<JSFunction> target);
2320 bool TryInline(Handle<JSFunction> target, int arguments_count,
2321 HValue* implicit_return_value, BailoutId ast_id,
2322 BailoutId return_id, InliningKind inlining_kind,
2323 SourcePosition position);
2325 bool TryInlineCall(Call* expr);
2326 bool TryInlineConstruct(CallNew* expr, HValue* implicit_return_value);
2327 bool TryInlineGetter(Handle<JSFunction> getter,
2328 Handle<Map> receiver_map,
2330 BailoutId return_id);
2331 bool TryInlineSetter(Handle<JSFunction> setter,
2332 Handle<Map> receiver_map,
2334 BailoutId assignment_id,
2335 HValue* implicit_return_value);
2336 bool TryInlineIndirectCall(Handle<JSFunction> function, Call* expr,
2337 int arguments_count);
2338 bool TryInlineBuiltinMethodCall(Call* expr, Handle<JSFunction> function,
2339 Handle<Map> receiver_map,
2340 int args_count_no_receiver);
2341 bool TryInlineBuiltinFunctionCall(Call* expr);
2348 bool TryInlineApiMethodCall(Call* expr,
2350 SmallMapList* receiver_types);
2351 bool TryInlineApiFunctionCall(Call* expr, HValue* receiver);
2352 bool TryInlineApiGetter(Handle<JSFunction> function,
2353 Handle<Map> receiver_map,
2355 bool TryInlineApiSetter(Handle<JSFunction> function,
2356 Handle<Map> receiver_map,
2358 bool TryInlineApiCall(Handle<JSFunction> function,
2360 SmallMapList* receiver_maps,
2363 ApiCallType call_type);
2364 static bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map);
2365 static bool CanInlineArrayResizeOperation(Handle<Map> receiver_map);
2367 // If --trace-inlining, print a line of the inlining trace. Inlining
2368 // succeeded if the reason string is NULL and failed if there is a
2369 // non-NULL reason string.
2370 void TraceInline(Handle<JSFunction> target,
2371 Handle<JSFunction> caller,
2372 const char* failure_reason);
2374 void HandleGlobalVariableAssignment(Variable* var,
2378 void HandlePropertyAssignment(Assignment* expr);
2379 void HandleCompoundAssignment(Assignment* expr);
2380 void HandlePolymorphicNamedFieldAccess(PropertyAccessType access_type,
2383 BailoutId return_id,
2386 SmallMapList* types,
2387 Handle<String> name);
2389 HValue* BuildAllocateExternalElements(
2390 ExternalArrayType array_type,
2391 bool is_zero_byte_offset,
2392 HValue* buffer, HValue* byte_offset, HValue* length);
2393 HValue* BuildAllocateFixedTypedArray(
2394 ExternalArrayType array_type, size_t element_size,
2395 ElementsKind fixed_elements_kind,
2396 HValue* byte_length, HValue* length);
2398 // TODO(adamk): Move all OrderedHashTable functions to their own class.
2399 HValue* BuildOrderedHashTableHashToBucket(HValue* hash, HValue* num_buckets);
2400 template <typename CollectionType>
2401 HValue* BuildOrderedHashTableHashToEntry(HValue* table, HValue* hash,
2402 HValue* num_buckets);
2403 template <typename CollectionType>
2404 HValue* BuildOrderedHashTableEntryToIndex(HValue* entry, HValue* num_buckets);
2405 template <typename CollectionType>
2406 HValue* BuildOrderedHashTableFindEntry(HValue* table, HValue* key,
2408 template <typename CollectionType>
2409 HValue* BuildOrderedHashTableAddEntry(HValue* table, HValue* key,
2411 HIfContinuation* join_continuation);
2412 template <typename CollectionType>
2413 HValue* BuildAllocateOrderedHashTable();
2414 template <typename CollectionType>
2415 void BuildOrderedHashTableClear(HValue* receiver);
2416 template <typename CollectionType>
2417 void BuildJSCollectionDelete(CallRuntime* call,
2418 const Runtime::Function* c_function);
2419 template <typename CollectionType>
2420 void BuildJSCollectionHas(CallRuntime* call,
2421 const Runtime::Function* c_function);
2422 HValue* BuildStringHashLoadIfIsStringAndHashComputed(
2423 HValue* object, HIfContinuation* continuation);
2425 Handle<JSFunction> array_function() {
2426 return handle(isolate()->native_context()->array_function());
2429 bool IsCallArrayInlineable(int argument_count, Handle<AllocationSite> site);
2430 void BuildInlinedCallArray(Expression* expression, int argument_count,
2431 Handle<AllocationSite> site);
2433 class LookupResult FINAL BASE_EMBEDDED {
2436 : lookup_type_(NOT_FOUND),
2437 details_(NONE, DATA, Representation::None()) {}
2439 void LookupDescriptor(Map* map, Name* name) {
2440 DescriptorArray* descriptors = map->instance_descriptors();
2441 int number = descriptors->SearchWithCache(name, map);
2442 if (number == DescriptorArray::kNotFound) return NotFound();
2443 lookup_type_ = DESCRIPTOR_TYPE;
2444 details_ = descriptors->GetDetails(number);
2448 void LookupTransition(Map* map, Name* name, PropertyAttributes attributes) {
2449 int transition_index = map->SearchTransition(kData, name, attributes);
2450 if (transition_index == TransitionArray::kNotFound) return NotFound();
2451 lookup_type_ = TRANSITION_TYPE;
2452 transition_ = handle(map->GetTransition(transition_index));
2453 number_ = transition_->LastAdded();
2454 details_ = transition_->instance_descriptors()->GetDetails(number_);
2458 lookup_type_ = NOT_FOUND;
2459 details_ = PropertyDetails(NONE, DATA, 0);
2462 Representation representation() const {
2464 return details_.representation();
2467 // Property callbacks does not include transitions to callbacks.
2468 bool IsAccessorConstant() const {
2469 return !IsTransition() && details_.type() == ACCESSOR_CONSTANT;
2472 bool IsReadOnly() const {
2474 return details_.IsReadOnly();
2477 bool IsData() const {
2478 return lookup_type_ == DESCRIPTOR_TYPE && details_.type() == DATA;
2481 bool IsDataConstant() const {
2482 return lookup_type_ == DESCRIPTOR_TYPE &&
2483 details_.type() == DATA_CONSTANT;
2486 bool IsConfigurable() const { return details_.IsConfigurable(); }
2487 bool IsFound() const { return lookup_type_ != NOT_FOUND; }
2488 bool IsTransition() const { return lookup_type_ == TRANSITION_TYPE; }
2490 // Is the result is a property excluding transitions and the null
2492 bool IsProperty() const { return IsFound() && !IsTransition(); }
2494 Handle<Map> GetTransitionTarget() const {
2495 DCHECK(IsTransition());
2499 bool IsTransitionToData() const {
2500 return IsTransition() && details_.type() == DATA;
2503 int GetLocalFieldIndexFromMap(Map* map) const {
2504 return GetFieldIndexFromMap(map) - map->inobject_properties();
2507 Object* GetConstantFromMap(Map* map) const {
2508 DCHECK(details_.type() == DATA_CONSTANT);
2509 return GetValueFromMap(map);
2512 Object* GetValueFromMap(Map* map) const {
2513 DCHECK(lookup_type_ == DESCRIPTOR_TYPE ||
2514 lookup_type_ == TRANSITION_TYPE);
2515 DCHECK(number_ < map->NumberOfOwnDescriptors());
2516 return map->instance_descriptors()->GetValue(number_);
2519 int GetFieldIndexFromMap(Map* map) const {
2520 DCHECK(lookup_type_ == DESCRIPTOR_TYPE ||
2521 lookup_type_ == TRANSITION_TYPE);
2522 DCHECK(number_ < map->NumberOfOwnDescriptors());
2523 return map->instance_descriptors()->GetFieldIndex(number_);
2526 HeapType* GetFieldTypeFromMap(Map* map) const {
2527 DCHECK_NE(NOT_FOUND, lookup_type_);
2528 DCHECK(number_ < map->NumberOfOwnDescriptors());
2529 return map->instance_descriptors()->GetFieldType(number_);
2532 Map* GetFieldOwnerFromMap(Map* map) const {
2533 DCHECK(lookup_type_ == DESCRIPTOR_TYPE ||
2534 lookup_type_ == TRANSITION_TYPE);
2535 DCHECK(number_ < map->NumberOfOwnDescriptors());
2536 return map->FindFieldOwner(number_);
2540 // Where did we find the result;
2541 enum { NOT_FOUND, DESCRIPTOR_TYPE, TRANSITION_TYPE } lookup_type_;
2543 Handle<Map> transition_;
2545 PropertyDetails details_;
2548 class PropertyAccessInfo {
2550 PropertyAccessInfo(HOptimizedGraphBuilder* builder,
2551 PropertyAccessType access_type, Handle<Map> map,
2552 Handle<String> name)
2553 : builder_(builder),
2554 access_type_(access_type),
2557 field_type_(HType::Tagged()),
2558 access_(HObjectAccess::ForMap()) {}
2560 // Checkes whether this PropertyAccessInfo can be handled as a monomorphic
2561 // load named. It additionally fills in the fields necessary to generate the
2563 bool CanAccessMonomorphic();
2565 // Checks whether all types behave uniform when loading name. If all maps
2566 // behave the same, a single monomorphic load instruction can be emitted,
2567 // guarded by a single map-checks instruction that whether the receiver is
2568 // an instance of any of the types.
2569 // This method skips the first type in types, assuming that this
2570 // PropertyAccessInfo is built for types->first().
2571 bool CanAccessAsMonomorphic(SmallMapList* types);
2573 bool NeedsWrappingFor(Handle<JSFunction> target) const;
2576 Handle<String> name() const { return name_; }
2578 bool IsJSObjectFieldAccessor() {
2579 int offset; // unused
2580 return Accessors::IsJSObjectFieldAccessor(map_, name_, &offset);
2583 bool GetJSObjectFieldAccess(HObjectAccess* access) {
2585 if (Accessors::IsJSObjectFieldAccessor(map_, name_, &offset)) {
2586 if (IsStringType()) {
2587 DCHECK(String::Equals(isolate()->factory()->length_string(), name_));
2588 *access = HObjectAccess::ForStringLength();
2589 } else if (IsArrayType()) {
2590 DCHECK(String::Equals(isolate()->factory()->length_string(), name_));
2591 *access = HObjectAccess::ForArrayLength(map_->elements_kind());
2593 *access = HObjectAccess::ForMapAndOffset(map_, offset);
2600 bool has_holder() { return !holder_.is_null(); }
2601 bool IsLoad() const { return access_type_ == LOAD; }
2603 Isolate* isolate() const { return builder_->isolate(); }
2604 Handle<JSObject> holder() { return holder_; }
2605 Handle<JSFunction> accessor() { return accessor_; }
2606 Handle<Object> constant() { return constant_; }
2607 Handle<Map> transition() { return lookup_.GetTransitionTarget(); }
2608 SmallMapList* field_maps() { return &field_maps_; }
2609 HType field_type() const { return field_type_; }
2610 HObjectAccess access() { return access_; }
2612 bool IsFound() const { return lookup_.IsFound(); }
2613 bool IsProperty() const { return lookup_.IsProperty(); }
2614 bool IsData() const { return lookup_.IsData(); }
2615 bool IsDataConstant() const { return lookup_.IsDataConstant(); }
2616 bool IsAccessorConstant() const { return lookup_.IsAccessorConstant(); }
2617 bool IsTransition() const { return lookup_.IsTransition(); }
2619 bool IsConfigurable() const { return lookup_.IsConfigurable(); }
2620 bool IsReadOnly() const { return lookup_.IsReadOnly(); }
2622 bool IsStringType() { return map_->instance_type() < FIRST_NONSTRING_TYPE; }
2623 bool IsNumberType() { return map_->instance_type() == HEAP_NUMBER_TYPE; }
2624 bool IsValueWrapped() { return IsStringType() || IsNumberType(); }
2625 bool IsArrayType() { return map_->instance_type() == JS_ARRAY_TYPE; }
2628 Handle<Object> GetAccessorsFromMap(Handle<Map> map) const {
2629 return handle(lookup_.GetValueFromMap(*map), isolate());
2631 Handle<Object> GetConstantFromMap(Handle<Map> map) const {
2632 return handle(lookup_.GetConstantFromMap(*map), isolate());
2634 Handle<HeapType> GetFieldTypeFromMap(Handle<Map> map) const {
2635 return handle(lookup_.GetFieldTypeFromMap(*map), isolate());
2637 Handle<Map> GetFieldOwnerFromMap(Handle<Map> map) const {
2638 return handle(lookup_.GetFieldOwnerFromMap(*map));
2640 int GetLocalFieldIndexFromMap(Handle<Map> map) const {
2641 return lookup_.GetLocalFieldIndexFromMap(*map);
2643 Representation representation() const { return lookup_.representation(); }
2645 Zone* zone() { return builder_->zone(); }
2646 CompilationInfo* top_info() { return builder_->top_info(); }
2647 CompilationInfo* current_info() { return builder_->current_info(); }
2649 bool LoadResult(Handle<Map> map);
2650 void LoadFieldMaps(Handle<Map> map);
2651 bool LookupDescriptor();
2652 bool LookupInPrototypes();
2653 bool IsCompatible(PropertyAccessInfo* other);
2655 void GeneralizeRepresentation(Representation r) {
2656 access_ = access_.WithRepresentation(
2657 access_.representation().generalize(r));
2660 LookupResult lookup_;
2661 HOptimizedGraphBuilder* builder_;
2662 PropertyAccessType access_type_;
2664 Handle<String> name_;
2665 Handle<JSObject> holder_;
2666 Handle<JSFunction> accessor_;
2667 Handle<JSObject> api_holder_;
2668 Handle<Object> constant_;
2669 SmallMapList field_maps_;
2671 HObjectAccess access_;
2674 HInstruction* BuildMonomorphicAccess(PropertyAccessInfo* info,
2676 HValue* checked_object,
2679 BailoutId return_id,
2680 bool can_inline_accessor = true);
2682 HInstruction* BuildNamedAccess(PropertyAccessType access,
2684 BailoutId reutrn_id,
2687 Handle<String> name,
2689 bool is_uninitialized = false);
2691 void HandlePolymorphicCallNamed(Call* expr,
2693 SmallMapList* types,
2694 Handle<String> name);
2695 void HandleLiteralCompareTypeof(CompareOperation* expr,
2696 Expression* sub_expr,
2697 Handle<String> check);
2698 void HandleLiteralCompareNil(CompareOperation* expr,
2699 Expression* sub_expr,
2702 enum PushBeforeSimulateBehavior {
2703 PUSH_BEFORE_SIMULATE,
2704 NO_PUSH_BEFORE_SIMULATE
2707 HControlInstruction* BuildCompareInstruction(
2708 Token::Value op, HValue* left, HValue* right, Type* left_type,
2709 Type* right_type, Type* combined_type, SourcePosition left_position,
2710 SourcePosition right_position, PushBeforeSimulateBehavior push_sim_result,
2711 BailoutId bailout_id);
2713 HInstruction* BuildStringCharCodeAt(HValue* string,
2716 HValue* BuildBinaryOperation(
2717 BinaryOperation* expr,
2720 PushBeforeSimulateBehavior push_sim_result);
2721 HInstruction* BuildIncrement(bool returns_original_input,
2722 CountOperation* expr);
2723 HInstruction* BuildKeyedGeneric(PropertyAccessType access_type,
2729 HInstruction* TryBuildConsolidatedElementLoad(HValue* object,
2732 SmallMapList* maps);
2734 LoadKeyedHoleMode BuildKeyedHoleMode(Handle<Map> map);
2736 HInstruction* BuildMonomorphicElementAccess(HValue* object,
2741 PropertyAccessType access_type,
2742 KeyedAccessStoreMode store_mode);
2744 HValue* HandlePolymorphicElementAccess(Expression* expr,
2749 PropertyAccessType access_type,
2750 KeyedAccessStoreMode store_mode,
2751 bool* has_side_effects);
2753 HValue* HandleKeyedElementAccess(HValue* obj, HValue* key, HValue* val,
2754 Expression* expr, BailoutId ast_id,
2755 BailoutId return_id,
2756 PropertyAccessType access_type,
2757 bool* has_side_effects);
2759 HInstruction* BuildNamedGeneric(PropertyAccessType access,
2762 Handle<String> name,
2764 bool is_uninitialized = false);
2766 HCheckMaps* AddCheckMap(HValue* object, Handle<Map> map);
2768 void BuildLoad(Property* property,
2770 void PushLoad(Property* property,
2774 void BuildStoreForEffect(Expression* expression,
2777 BailoutId return_id,
2782 void BuildStore(Expression* expression,
2785 BailoutId return_id,
2786 bool is_uninitialized = false);
2788 HInstruction* BuildLoadNamedField(PropertyAccessInfo* info,
2789 HValue* checked_object);
2790 HInstruction* BuildStoreNamedField(PropertyAccessInfo* info,
2791 HValue* checked_object,
2794 HValue* BuildContextChainWalk(Variable* var);
2796 HInstruction* BuildThisFunction();
2798 HInstruction* BuildFastLiteral(Handle<JSObject> boilerplate_object,
2799 AllocationSiteUsageContext* site_context);
2801 void BuildEmitObjectHeader(Handle<JSObject> boilerplate_object,
2802 HInstruction* object);
2804 void BuildInitElementsInObjectHeader(Handle<JSObject> boilerplate_object,
2805 HInstruction* object,
2806 HInstruction* object_elements);
2808 void BuildEmitInObjectProperties(Handle<JSObject> boilerplate_object,
2809 HInstruction* object,
2810 AllocationSiteUsageContext* site_context,
2811 PretenureFlag pretenure_flag);
2813 void BuildEmitElements(Handle<JSObject> boilerplate_object,
2814 Handle<FixedArrayBase> elements,
2815 HValue* object_elements,
2816 AllocationSiteUsageContext* site_context);
2818 void BuildEmitFixedDoubleArray(Handle<FixedArrayBase> elements,
2820 HValue* object_elements);
2822 void BuildEmitFixedArray(Handle<FixedArrayBase> elements,
2824 HValue* object_elements,
2825 AllocationSiteUsageContext* site_context);
2827 void AddCheckPrototypeMaps(Handle<JSObject> holder,
2828 Handle<Map> receiver_map);
2830 HInstruction* NewPlainFunctionCall(HValue* fun,
2832 bool pass_argument_count);
2834 HInstruction* NewArgumentAdaptorCall(HValue* fun, HValue* context,
2836 HValue* expected_param_count);
2838 HInstruction* BuildCallConstantFunction(Handle<JSFunction> target,
2839 int argument_count);
2841 bool CanBeFunctionApplyArguments(Call* expr);
2843 // The translation state of the currently-being-translated function.
2844 FunctionState* function_state_;
2846 // The base of the function state stack.
2847 FunctionState initial_function_state_;
2849 // Expression context of the currently visited subexpression. NULL when
2850 // visiting statements.
2851 AstContext* ast_context_;
2853 // A stack of breakable statements entered.
2854 BreakAndContinueScope* break_scope_;
2857 ZoneList<Handle<Object> > globals_;
2859 bool inline_bailout_;
2863 friend class FunctionState; // Pushes and pops the state stack.
2864 friend class AstContext; // Pushes and pops the AST context stack.
2865 friend class KeyedLoadFastElementStub;
2866 friend class HOsrBuilder;
2868 DISALLOW_COPY_AND_ASSIGN(HOptimizedGraphBuilder);
2872 Zone* AstContext::zone() const { return owner_->zone(); }
2875 class HStatistics FINAL: public Malloced {
2884 void Initialize(CompilationInfo* info);
2886 void SaveTiming(const char* name, base::TimeDelta time, size_t size);
2888 void IncrementFullCodeGen(base::TimeDelta full_code_gen) {
2889 full_code_gen_ += full_code_gen;
2892 void IncrementCreateGraph(base::TimeDelta delta) { create_graph_ += delta; }
2894 void IncrementOptimizeGraph(base::TimeDelta delta) {
2895 optimize_graph_ += delta;
2898 void IncrementGenerateCode(base::TimeDelta delta) { generate_code_ += delta; }
2900 void IncrementSubtotals(base::TimeDelta create_graph,
2901 base::TimeDelta optimize_graph,
2902 base::TimeDelta generate_code) {
2903 IncrementCreateGraph(create_graph);
2904 IncrementOptimizeGraph(optimize_graph);
2905 IncrementGenerateCode(generate_code);
2909 List<base::TimeDelta> times_;
2910 List<const char*> names_;
2911 List<size_t> sizes_;
2912 base::TimeDelta create_graph_;
2913 base::TimeDelta optimize_graph_;
2914 base::TimeDelta generate_code_;
2916 base::TimeDelta full_code_gen_;
2917 double source_size_;
2921 class HPhase : public CompilationPhase {
2923 HPhase(const char* name, HGraph* graph)
2924 : CompilationPhase(name, graph->info()),
2929 HGraph* graph() const { return graph_; }
2934 DISALLOW_COPY_AND_ASSIGN(HPhase);
2938 class HTracer FINAL : public Malloced {
2940 explicit HTracer(int isolate_id)
2941 : trace_(&string_allocator_), indent_(0) {
2942 if (FLAG_trace_hydrogen_file == NULL) {
2944 "hydrogen-%d-%d.cfg",
2945 base::OS::GetCurrentProcessId(),
2948 StrNCpy(filename_, FLAG_trace_hydrogen_file, filename_.length());
2950 WriteChars(filename_.start(), "", 0, false);
2953 void TraceCompilation(CompilationInfo* info);
2954 void TraceHydrogen(const char* name, HGraph* graph);
2955 void TraceLithium(const char* name, LChunk* chunk);
2956 void TraceLiveRanges(const char* name, LAllocator* allocator);
2959 class Tag FINAL BASE_EMBEDDED {
2961 Tag(HTracer* tracer, const char* name) {
2964 tracer->PrintIndent();
2965 tracer->trace_.Add("begin_%s\n", name);
2971 tracer_->PrintIndent();
2972 tracer_->trace_.Add("end_%s\n", name_);
2973 DCHECK(tracer_->indent_ >= 0);
2974 tracer_->FlushToFile();
2982 void TraceLiveRange(LiveRange* range, const char* type, Zone* zone);
2983 void Trace(const char* name, HGraph* graph, LChunk* chunk);
2986 void PrintEmptyProperty(const char* name) {
2988 trace_.Add("%s\n", name);
2991 void PrintStringProperty(const char* name, const char* value) {
2993 trace_.Add("%s \"%s\"\n", name, value);
2996 void PrintLongProperty(const char* name, int64_t value) {
2998 trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000));
3001 void PrintBlockProperty(const char* name, int block_id) {
3003 trace_.Add("%s \"B%d\"\n", name, block_id);
3006 void PrintIntProperty(const char* name, int value) {
3008 trace_.Add("%s %d\n", name, value);
3011 void PrintIndent() {
3012 for (int i = 0; i < indent_; i++) {
3017 EmbeddedVector<char, 64> filename_;
3018 HeapStringAllocator string_allocator_;
3019 StringStream trace_;
3024 class NoObservableSideEffectsScope FINAL {
3026 explicit NoObservableSideEffectsScope(HGraphBuilder* builder) :
3028 builder_->graph()->IncrementInNoSideEffectsScope();
3030 ~NoObservableSideEffectsScope() {
3031 builder_->graph()->DecrementInNoSideEffectsScope();
3035 HGraphBuilder* builder_;
3039 } } // namespace v8::internal
3041 #endif // V8_HYDROGEN_H_