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/compiler.h"
14 #include "src/hydrogen-instructions.h"
15 #include "src/scopes.h"
21 // Forward declarations.
26 class HLoopInformation;
34 class HBasicBlock V8_FINAL : public ZoneObject {
36 explicit HBasicBlock(HGraph* graph);
40 int block_id() const { return block_id_; }
41 void set_block_id(int id) { block_id_ = id; }
42 HGraph* graph() const { return graph_; }
43 Isolate* isolate() const;
44 const ZoneList<HPhi*>* phis() const { return &phis_; }
45 HInstruction* first() const { return first_; }
46 HInstruction* last() const { return last_; }
47 void set_last(HInstruction* instr) { last_ = instr; }
48 HControlInstruction* end() const { return end_; }
49 HLoopInformation* loop_information() const { return loop_information_; }
50 HLoopInformation* current_loop() const {
51 return IsLoopHeader() ? loop_information()
52 : (parent_loop_header() != NULL
53 ? parent_loop_header()->loop_information() : NULL);
55 const ZoneList<HBasicBlock*>* predecessors() const { return &predecessors_; }
56 bool HasPredecessor() const { return predecessors_.length() > 0; }
57 const ZoneList<HBasicBlock*>* dominated_blocks() const {
58 return &dominated_blocks_;
60 const ZoneList<int>* deleted_phis() const {
61 return &deleted_phis_;
63 void RecordDeletedPhi(int merge_index) {
64 deleted_phis_.Add(merge_index, zone());
66 HBasicBlock* dominator() const { return dominator_; }
67 HEnvironment* last_environment() const { return last_environment_; }
68 int argument_count() const { return argument_count_; }
69 void set_argument_count(int count) { argument_count_ = count; }
70 int first_instruction_index() const { return first_instruction_index_; }
71 void set_first_instruction_index(int index) {
72 first_instruction_index_ = index;
74 int last_instruction_index() const { return last_instruction_index_; }
75 void set_last_instruction_index(int index) {
76 last_instruction_index_ = index;
78 bool is_osr_entry() { return is_osr_entry_; }
79 void set_osr_entry() { is_osr_entry_ = true; }
81 void AttachLoopInformation();
82 void DetachLoopInformation();
83 bool IsLoopHeader() const { return loop_information() != NULL; }
84 bool IsStartBlock() const { return block_id() == 0; }
85 void PostProcessLoopHeader(IterationStatement* stmt);
87 bool IsFinished() const { return end_ != NULL; }
88 void AddPhi(HPhi* phi);
89 void RemovePhi(HPhi* phi);
90 void AddInstruction(HInstruction* instr, HSourcePosition position);
91 bool Dominates(HBasicBlock* other) const;
92 bool EqualToOrDominates(HBasicBlock* other) const;
93 int LoopNestingDepth() const;
95 void SetInitialEnvironment(HEnvironment* env);
96 void ClearEnvironment() {
98 DCHECK(end()->SuccessorCount() == 0);
99 last_environment_ = NULL;
101 bool HasEnvironment() const { return last_environment_ != NULL; }
102 void UpdateEnvironment(HEnvironment* env);
103 HBasicBlock* parent_loop_header() const { return parent_loop_header_; }
105 void set_parent_loop_header(HBasicBlock* block) {
106 DCHECK(parent_loop_header_ == NULL);
107 parent_loop_header_ = block;
110 bool HasParentLoopHeader() const { return parent_loop_header_ != NULL; }
112 void SetJoinId(BailoutId ast_id);
114 int PredecessorIndexOf(HBasicBlock* predecessor) const;
115 HPhi* AddNewPhi(int merged_index);
116 HSimulate* AddNewSimulate(BailoutId ast_id,
117 HSourcePosition 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, HSourcePosition position);
170 void FinishExit(HControlInstruction* instruction, HSourcePosition position);
171 void Goto(HBasicBlock* block,
172 HSourcePosition position,
173 FunctionState* state = NULL,
174 bool add_simulate = true);
175 void GotoNoSimulate(HBasicBlock* block, HSourcePosition position) {
176 Goto(block, position, NULL, false);
179 // Add the inlined function exit sequence, adding an HLeaveInlined
180 // instruction and updating the bailout environment.
181 void AddLeaveInlined(HValue* return_value,
182 FunctionState* state,
183 HSourcePosition position);
186 void RegisterPredecessor(HBasicBlock* pred);
187 void AddDominatedBlock(HBasicBlock* block);
191 ZoneList<HPhi*> phis_;
192 HInstruction* first_;
194 HControlInstruction* end_;
195 HLoopInformation* loop_information_;
196 ZoneList<HBasicBlock*> predecessors_;
197 HBasicBlock* dominator_;
198 ZoneList<HBasicBlock*> dominated_blocks_;
199 HEnvironment* last_environment_;
200 // Outgoing parameter count at block exit, set during lithium translation.
202 // Instruction indices into the lithium code stream.
203 int first_instruction_index_;
204 int last_instruction_index_;
205 ZoneList<int> deleted_phis_;
206 HBasicBlock* parent_loop_header_;
207 // For blocks marked as inline return target: the block with HEnterInlined.
208 HBasicBlock* inlined_entry_block_;
209 bool is_inline_return_target_ : 1;
210 bool is_reachable_ : 1;
211 bool dominates_loop_successors_ : 1;
212 bool is_osr_entry_ : 1;
213 bool is_ordered_ : 1;
217 OStream& operator<<(OStream& os, const HBasicBlock& b);
220 class HPredecessorIterator V8_FINAL BASE_EMBEDDED {
222 explicit HPredecessorIterator(HBasicBlock* block)
223 : predecessor_list_(block->predecessors()), current_(0) { }
225 bool Done() { return current_ >= predecessor_list_->length(); }
226 HBasicBlock* Current() { return predecessor_list_->at(current_); }
227 void Advance() { current_++; }
230 const ZoneList<HBasicBlock*>* predecessor_list_;
235 class HInstructionIterator V8_FINAL BASE_EMBEDDED {
237 explicit HInstructionIterator(HBasicBlock* block)
238 : instr_(block->first()) {
239 next_ = Done() ? NULL : instr_->next();
242 inline bool Done() const { return instr_ == NULL; }
243 inline HInstruction* Current() { return instr_; }
244 inline void Advance() {
246 next_ = Done() ? NULL : instr_->next();
250 HInstruction* instr_;
255 class HLoopInformation V8_FINAL : public ZoneObject {
257 HLoopInformation(HBasicBlock* loop_header, Zone* zone)
258 : back_edges_(4, zone),
259 loop_header_(loop_header),
262 blocks_.Add(loop_header, zone);
264 ~HLoopInformation() {}
266 const ZoneList<HBasicBlock*>* back_edges() const { return &back_edges_; }
267 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
268 HBasicBlock* loop_header() const { return loop_header_; }
269 HBasicBlock* GetLastBackEdge() const;
270 void RegisterBackEdge(HBasicBlock* block);
272 HStackCheck* stack_check() const { return stack_check_; }
273 void set_stack_check(HStackCheck* stack_check) {
274 stack_check_ = stack_check;
277 bool IsNestedInThisLoop(HLoopInformation* other) {
278 while (other != NULL) {
282 other = other->parent_loop();
286 HLoopInformation* parent_loop() {
287 HBasicBlock* parent_header = loop_header()->parent_loop_header();
288 return parent_header != NULL ? parent_header->loop_information() : NULL;
292 void AddBlock(HBasicBlock* block);
294 ZoneList<HBasicBlock*> back_edges_;
295 HBasicBlock* loop_header_;
296 ZoneList<HBasicBlock*> blocks_;
297 HStackCheck* stack_check_;
301 class BoundsCheckTable;
302 class InductionVariableBlocksTable;
303 class HGraph V8_FINAL : public ZoneObject {
305 explicit HGraph(CompilationInfo* info);
307 Isolate* isolate() const { return isolate_; }
308 Zone* zone() const { return zone_; }
309 CompilationInfo* info() const { return info_; }
311 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
312 const ZoneList<HPhi*>* phi_list() const { return phi_list_; }
313 HBasicBlock* entry_block() const { return entry_block_; }
314 HEnvironment* start_environment() const { return start_environment_; }
316 void FinalizeUniqueness();
317 bool ProcessArgumentsObject();
319 void AssignDominators();
320 void RestoreActualValues();
322 // Returns false if there are phi-uses of the arguments-object
323 // which are not supported by the optimizing compiler.
324 bool CheckArgumentsPhiUses();
326 // Returns false if there are phi-uses of an uninitialized const
327 // which are not supported by the optimizing compiler.
328 bool CheckConstPhiUses();
332 HConstant* GetConstantUndefined();
333 HConstant* GetConstant0();
334 HConstant* GetConstant1();
335 HConstant* GetConstantMinus1();
336 HConstant* GetConstantTrue();
337 HConstant* GetConstantFalse();
338 HConstant* GetConstantHole();
339 HConstant* GetConstantNull();
340 HConstant* GetInvalidContext();
342 bool IsConstantUndefined(HConstant* constant);
343 bool IsConstant0(HConstant* constant);
344 bool IsConstant1(HConstant* constant);
345 bool IsConstantMinus1(HConstant* constant);
346 bool IsConstantTrue(HConstant* constant);
347 bool IsConstantFalse(HConstant* constant);
348 bool IsConstantHole(HConstant* constant);
349 bool IsConstantNull(HConstant* constant);
350 bool IsStandardConstant(HConstant* constant);
352 HBasicBlock* CreateBasicBlock();
353 HArgumentsObject* GetArgumentsObject() const {
354 return arguments_object_.get();
357 void SetArgumentsObject(HArgumentsObject* object) {
358 arguments_object_.set(object);
361 int GetMaximumValueID() const { return values_.length(); }
362 int GetNextBlockID() { return next_block_id_++; }
363 int GetNextValueID(HValue* value) {
364 DCHECK(!disallow_adding_new_values_);
365 values_.Add(value, zone());
366 return values_.length() - 1;
368 HValue* LookupValue(int id) const {
369 if (id >= 0 && id < values_.length()) return values_[id];
372 void DisallowAddingNewValues() {
373 disallow_adding_new_values_ = true;
376 bool Optimize(BailoutReason* bailout_reason);
379 void Verify(bool do_full_verify) const;
386 void set_osr(HOsrBuilder* osr) {
394 int update_type_change_checksum(int delta) {
395 type_change_checksum_ += delta;
396 return type_change_checksum_;
399 void update_maximum_environment_size(int environment_size) {
400 if (environment_size > maximum_environment_size_) {
401 maximum_environment_size_ = environment_size;
404 int maximum_environment_size() { return maximum_environment_size_; }
406 bool use_optimistic_licm() {
407 return use_optimistic_licm_;
410 void set_use_optimistic_licm(bool value) {
411 use_optimistic_licm_ = value;
414 void MarkRecursive() {
415 is_recursive_ = true;
418 bool is_recursive() const {
419 return is_recursive_;
422 void MarkDependsOnEmptyArrayProtoElements() {
423 // Add map dependency if not already added.
424 if (depends_on_empty_array_proto_elements_) return;
425 Map::AddDependentCompilationInfo(
426 handle(isolate()->initial_object_prototype()->map()),
427 DependentCode::kElementsCantBeAddedGroup, info());
428 Map::AddDependentCompilationInfo(
429 handle(isolate()->initial_array_prototype()->map()),
430 DependentCode::kElementsCantBeAddedGroup, info());
431 depends_on_empty_array_proto_elements_ = true;
434 bool depends_on_empty_array_proto_elements() {
435 return depends_on_empty_array_proto_elements_;
438 bool has_uint32_instructions() {
439 DCHECK(uint32_instructions_ == NULL || !uint32_instructions_->is_empty());
440 return uint32_instructions_ != NULL;
443 ZoneList<HInstruction*>* uint32_instructions() {
444 DCHECK(uint32_instructions_ == NULL || !uint32_instructions_->is_empty());
445 return uint32_instructions_;
448 void RecordUint32Instruction(HInstruction* instr) {
449 DCHECK(uint32_instructions_ == NULL || !uint32_instructions_->is_empty());
450 if (uint32_instructions_ == NULL) {
451 uint32_instructions_ = new(zone()) ZoneList<HInstruction*>(4, zone());
453 uint32_instructions_->Add(instr, zone());
456 void IncrementInNoSideEffectsScope() { no_side_effects_scope_count_++; }
457 void DecrementInNoSideEffectsScope() { no_side_effects_scope_count_--; }
458 bool IsInsideNoSideEffectsScope() { return no_side_effects_scope_count_ > 0; }
460 // If we are tracking source positions then this function assigns a unique
461 // identifier to each inlining and dumps function source if it was inlined
462 // for the first time during the current optimization.
463 int TraceInlinedFunction(Handle<SharedFunctionInfo> shared,
464 HSourcePosition position);
466 // Converts given HSourcePosition to the absolute offset from the start of
467 // the corresponding script.
468 int SourcePositionToScriptPosition(HSourcePosition position);
471 HConstant* ReinsertConstantIfNecessary(HConstant* constant);
472 HConstant* GetConstant(SetOncePointer<HConstant>* pointer,
473 int32_t integer_value);
475 template<class Phase>
481 void EliminateRedundantBoundsChecksUsingInductionVariables();
485 HBasicBlock* entry_block_;
486 HEnvironment* start_environment_;
487 ZoneList<HBasicBlock*> blocks_;
488 ZoneList<HValue*> values_;
489 ZoneList<HPhi*>* phi_list_;
490 ZoneList<HInstruction*>* uint32_instructions_;
491 SetOncePointer<HConstant> constant_undefined_;
492 SetOncePointer<HConstant> constant_0_;
493 SetOncePointer<HConstant> constant_1_;
494 SetOncePointer<HConstant> constant_minus1_;
495 SetOncePointer<HConstant> constant_true_;
496 SetOncePointer<HConstant> constant_false_;
497 SetOncePointer<HConstant> constant_the_hole_;
498 SetOncePointer<HConstant> constant_null_;
499 SetOncePointer<HConstant> constant_invalid_context_;
500 SetOncePointer<HArgumentsObject> arguments_object_;
504 CompilationInfo* info_;
508 bool use_optimistic_licm_;
509 bool depends_on_empty_array_proto_elements_;
510 int type_change_checksum_;
511 int maximum_environment_size_;
512 int no_side_effects_scope_count_;
513 bool disallow_adding_new_values_;
515 class InlinedFunctionInfo {
517 explicit InlinedFunctionInfo(Handle<SharedFunctionInfo> shared)
518 : shared_(shared), start_position_(shared->start_position()) {
521 Handle<SharedFunctionInfo> shared() const { return shared_; }
522 int start_position() const { return start_position_; }
525 Handle<SharedFunctionInfo> shared_;
530 ZoneList<InlinedFunctionInfo> inlined_functions_;
532 DISALLOW_COPY_AND_ASSIGN(HGraph);
536 Zone* HBasicBlock::zone() const { return graph_->zone(); }
539 // Type of stack frame an environment might refer to.
550 class HEnvironment V8_FINAL : public ZoneObject {
552 HEnvironment(HEnvironment* outer,
554 Handle<JSFunction> closure,
557 HEnvironment(Zone* zone, int parameter_count);
559 HEnvironment* arguments_environment() {
560 return outer()->frame_type() == ARGUMENTS_ADAPTOR ? outer() : this;
564 Handle<JSFunction> closure() const { return closure_; }
565 const ZoneList<HValue*>* values() const { return &values_; }
566 const GrowableBitVector* assigned_variables() const {
567 return &assigned_variables_;
569 FrameType frame_type() const { return frame_type_; }
570 int parameter_count() const { return parameter_count_; }
571 int specials_count() const { return specials_count_; }
572 int local_count() const { return local_count_; }
573 HEnvironment* outer() const { return outer_; }
574 int pop_count() const { return pop_count_; }
575 int push_count() const { return push_count_; }
577 BailoutId ast_id() const { return ast_id_; }
578 void set_ast_id(BailoutId id) { ast_id_ = id; }
580 HEnterInlined* entry() const { return entry_; }
581 void set_entry(HEnterInlined* entry) { entry_ = entry; }
583 int length() const { return values_.length(); }
585 int first_expression_index() const {
586 return parameter_count() + specials_count() + local_count();
589 int first_local_index() const {
590 return parameter_count() + specials_count();
593 void Bind(Variable* variable, HValue* value) {
594 Bind(IndexFor(variable), value);
597 void Bind(int index, HValue* value);
599 void BindContext(HValue* value) {
600 Bind(parameter_count(), value);
603 HValue* Lookup(Variable* variable) const {
604 return Lookup(IndexFor(variable));
607 HValue* Lookup(int index) const {
608 HValue* result = values_[index];
609 DCHECK(result != NULL);
613 HValue* context() const {
614 // Return first special.
615 return Lookup(parameter_count());
618 void Push(HValue* value) {
619 DCHECK(value != NULL);
621 values_.Add(value, zone());
625 DCHECK(!ExpressionStackIsEmpty());
626 if (push_count_ > 0) {
631 return values_.RemoveLast();
634 void Drop(int count);
636 HValue* Top() const { return ExpressionStackAt(0); }
638 bool ExpressionStackIsEmpty() const;
640 HValue* ExpressionStackAt(int index_from_top) const {
641 int index = length() - index_from_top - 1;
642 DCHECK(HasExpressionAt(index));
643 return values_[index];
646 void SetExpressionStackAt(int index_from_top, HValue* value);
648 HEnvironment* Copy() const;
649 HEnvironment* CopyWithoutHistory() const;
650 HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const;
652 // Create an "inlined version" of this environment, where the original
653 // environment is the outer environment but the top expression stack
654 // elements are moved to an inner environment as parameters.
655 HEnvironment* CopyForInlining(Handle<JSFunction> target,
657 FunctionLiteral* function,
658 HConstant* undefined,
659 InliningKind inlining_kind) const;
661 HEnvironment* DiscardInlined(bool drop_extra) {
662 HEnvironment* outer = outer_;
663 while (outer->frame_type() != JS_FUNCTION) outer = outer->outer_;
664 if (drop_extra) outer->Drop(1);
668 void AddIncomingEdge(HBasicBlock* block, HEnvironment* other);
670 void ClearHistory() {
673 assigned_variables_.Clear();
676 void SetValueAt(int index, HValue* value) {
677 DCHECK(index < length());
678 values_[index] = value;
681 // Map a variable to an environment index. Parameter indices are shifted
682 // by 1 (receiver is parameter index -1 but environment index 0).
683 // Stack-allocated local indices are shifted by the number of parameters.
684 int IndexFor(Variable* variable) const {
685 DCHECK(variable->IsStackAllocated());
686 int shift = variable->IsParameter()
688 : parameter_count_ + specials_count_;
689 return variable->index() + shift;
692 bool is_local_index(int i) const {
693 return i >= first_local_index() && i < first_expression_index();
696 bool is_parameter_index(int i) const {
697 return i >= 0 && i < parameter_count();
700 bool is_special_index(int i) const {
701 return i >= parameter_count() && i < parameter_count() + specials_count();
704 Zone* zone() const { return zone_; }
707 HEnvironment(const HEnvironment* other, Zone* zone);
709 HEnvironment(HEnvironment* outer,
710 Handle<JSFunction> closure,
711 FrameType frame_type,
715 // Create an artificial stub environment (e.g. for argument adaptor or
716 // constructor stub).
717 HEnvironment* CreateStubEnvironment(HEnvironment* outer,
718 Handle<JSFunction> target,
719 FrameType frame_type,
720 int arguments) const;
722 // True if index is included in the expression stack part of the environment.
723 bool HasExpressionAt(int index) const;
725 void Initialize(int parameter_count, int local_count, int stack_height);
726 void Initialize(const HEnvironment* other);
728 Handle<JSFunction> closure_;
729 // Value array [parameters] [specials] [locals] [temporaries].
730 ZoneList<HValue*> values_;
731 GrowableBitVector assigned_variables_;
732 FrameType frame_type_;
733 int parameter_count_;
736 HEnvironment* outer_;
737 HEnterInlined* entry_;
745 OStream& operator<<(OStream& os, const HEnvironment& env);
748 class HOptimizedGraphBuilder;
750 enum ArgumentsAllowedFlag {
751 ARGUMENTS_NOT_ALLOWED,
756 class HIfContinuation;
758 // This class is not BASE_EMBEDDED because our inlining implementation uses
762 bool IsEffect() const { return kind_ == Expression::kEffect; }
763 bool IsValue() const { return kind_ == Expression::kValue; }
764 bool IsTest() const { return kind_ == Expression::kTest; }
766 // 'Fill' this context with a hydrogen value. The value is assumed to
767 // have already been inserted in the instruction stream (or not need to
768 // be, e.g., HPhi). Call this function in tail position in the Visit
769 // functions for expressions.
770 virtual void ReturnValue(HValue* value) = 0;
772 // Add a hydrogen instruction to the instruction stream (recording an
773 // environment simulation if necessary) and then fill this context with
774 // the instruction as value.
775 virtual void ReturnInstruction(HInstruction* instr, BailoutId ast_id) = 0;
777 // Finishes the current basic block and materialize a boolean for
778 // value context, nothing for effect, generate a branch for test context.
779 // Call this function in tail position in the Visit functions for
781 virtual void ReturnControl(HControlInstruction* instr, BailoutId ast_id) = 0;
783 // Finishes the current basic block and materialize a boolean for
784 // value context, nothing for effect, generate a branch for test context.
785 // Call this function in tail position in the Visit functions for
786 // expressions that use an IfBuilder.
787 virtual void ReturnContinuation(HIfContinuation* continuation,
788 BailoutId ast_id) = 0;
790 void set_for_typeof(bool for_typeof) { for_typeof_ = for_typeof; }
791 bool is_for_typeof() { return for_typeof_; }
794 AstContext(HOptimizedGraphBuilder* owner, Expression::Context kind);
795 virtual ~AstContext();
797 HOptimizedGraphBuilder* owner() const { return owner_; }
799 inline Zone* zone() const;
801 // We want to be able to assert, in a context-specific way, that the stack
802 // height makes sense when the context is filled.
804 int original_length_;
808 HOptimizedGraphBuilder* owner_;
809 Expression::Context kind_;
815 class EffectContext V8_FINAL : public AstContext {
817 explicit EffectContext(HOptimizedGraphBuilder* owner)
818 : AstContext(owner, Expression::kEffect) {
820 virtual ~EffectContext();
822 virtual void ReturnValue(HValue* value) V8_OVERRIDE;
823 virtual void ReturnInstruction(HInstruction* instr,
824 BailoutId ast_id) V8_OVERRIDE;
825 virtual void ReturnControl(HControlInstruction* instr,
826 BailoutId ast_id) V8_OVERRIDE;
827 virtual void ReturnContinuation(HIfContinuation* continuation,
828 BailoutId ast_id) V8_OVERRIDE;
832 class ValueContext V8_FINAL : public AstContext {
834 ValueContext(HOptimizedGraphBuilder* owner, ArgumentsAllowedFlag flag)
835 : AstContext(owner, Expression::kValue), flag_(flag) {
837 virtual ~ValueContext();
839 virtual void ReturnValue(HValue* value) V8_OVERRIDE;
840 virtual void ReturnInstruction(HInstruction* instr,
841 BailoutId ast_id) V8_OVERRIDE;
842 virtual void ReturnControl(HControlInstruction* instr,
843 BailoutId ast_id) V8_OVERRIDE;
844 virtual void ReturnContinuation(HIfContinuation* continuation,
845 BailoutId ast_id) V8_OVERRIDE;
847 bool arguments_allowed() { return flag_ == ARGUMENTS_ALLOWED; }
850 ArgumentsAllowedFlag flag_;
854 class TestContext V8_FINAL : public AstContext {
856 TestContext(HOptimizedGraphBuilder* owner,
857 Expression* condition,
858 HBasicBlock* if_true,
859 HBasicBlock* if_false)
860 : AstContext(owner, Expression::kTest),
861 condition_(condition),
863 if_false_(if_false) {
866 virtual void ReturnValue(HValue* value) V8_OVERRIDE;
867 virtual void ReturnInstruction(HInstruction* instr,
868 BailoutId ast_id) V8_OVERRIDE;
869 virtual void ReturnControl(HControlInstruction* instr,
870 BailoutId ast_id) V8_OVERRIDE;
871 virtual void ReturnContinuation(HIfContinuation* continuation,
872 BailoutId ast_id) V8_OVERRIDE;
874 static TestContext* cast(AstContext* context) {
875 DCHECK(context->IsTest());
876 return reinterpret_cast<TestContext*>(context);
879 Expression* condition() const { return condition_; }
880 HBasicBlock* if_true() const { return if_true_; }
881 HBasicBlock* if_false() const { return if_false_; }
884 // Build the shared core part of the translation unpacking a value into
886 void BuildBranch(HValue* value);
888 Expression* condition_;
889 HBasicBlock* if_true_;
890 HBasicBlock* if_false_;
894 class FunctionState V8_FINAL {
896 FunctionState(HOptimizedGraphBuilder* owner,
897 CompilationInfo* info,
898 InliningKind inlining_kind,
902 CompilationInfo* compilation_info() { return compilation_info_; }
903 AstContext* call_context() { return call_context_; }
904 InliningKind inlining_kind() const { return inlining_kind_; }
905 HBasicBlock* function_return() { return function_return_; }
906 TestContext* test_context() { return test_context_; }
907 void ClearInlinedTestContext() {
908 delete test_context_;
909 test_context_ = NULL;
912 FunctionState* outer() { return outer_; }
914 HEnterInlined* entry() { return entry_; }
915 void set_entry(HEnterInlined* entry) { entry_ = entry; }
917 HArgumentsObject* arguments_object() { return arguments_object_; }
918 void set_arguments_object(HArgumentsObject* arguments_object) {
919 arguments_object_ = arguments_object;
922 HArgumentsElements* arguments_elements() { return arguments_elements_; }
923 void set_arguments_elements(HArgumentsElements* arguments_elements) {
924 arguments_elements_ = arguments_elements;
927 bool arguments_pushed() { return arguments_elements() != NULL; }
929 int inlining_id() const { return inlining_id_; }
932 HOptimizedGraphBuilder* owner_;
934 CompilationInfo* compilation_info_;
936 // During function inlining, expression context of the call being
937 // inlined. NULL when not inlining.
938 AstContext* call_context_;
940 // The kind of call which is currently being inlined.
941 InliningKind inlining_kind_;
943 // When inlining in an effect or value context, this is the return block.
944 // It is NULL otherwise. When inlining in a test context, there are a
945 // pair of return blocks in the context. When not inlining, there is no
946 // local return point.
947 HBasicBlock* function_return_;
949 // When inlining a call in a test context, a context containing a pair of
950 // return blocks. NULL in all other cases.
951 TestContext* test_context_;
953 // When inlining HEnterInlined instruction corresponding to the function
955 HEnterInlined* entry_;
957 HArgumentsObject* arguments_object_;
958 HArgumentsElements* arguments_elements_;
961 HSourcePosition outer_source_position_;
963 FunctionState* outer_;
967 class HIfContinuation V8_FINAL {
970 : continuation_captured_(false),
972 false_branch_(NULL) {}
973 HIfContinuation(HBasicBlock* true_branch,
974 HBasicBlock* false_branch)
975 : continuation_captured_(true), true_branch_(true_branch),
976 false_branch_(false_branch) {}
977 ~HIfContinuation() { DCHECK(!continuation_captured_); }
979 void Capture(HBasicBlock* true_branch,
980 HBasicBlock* false_branch) {
981 DCHECK(!continuation_captured_);
982 true_branch_ = true_branch;
983 false_branch_ = false_branch;
984 continuation_captured_ = true;
987 void Continue(HBasicBlock** true_branch,
988 HBasicBlock** false_branch) {
989 DCHECK(continuation_captured_);
990 *true_branch = true_branch_;
991 *false_branch = false_branch_;
992 continuation_captured_ = false;
995 bool IsTrueReachable() { return true_branch_ != NULL; }
996 bool IsFalseReachable() { return false_branch_ != NULL; }
997 bool TrueAndFalseReachable() {
998 return IsTrueReachable() || IsFalseReachable();
1001 HBasicBlock* true_branch() const { return true_branch_; }
1002 HBasicBlock* false_branch() const { return false_branch_; }
1005 bool continuation_captured_;
1006 HBasicBlock* true_branch_;
1007 HBasicBlock* false_branch_;
1011 class HAllocationMode V8_FINAL BASE_EMBEDDED {
1013 explicit HAllocationMode(Handle<AllocationSite> feedback_site)
1014 : current_site_(NULL), feedback_site_(feedback_site),
1015 pretenure_flag_(NOT_TENURED) {}
1016 explicit HAllocationMode(HValue* current_site)
1017 : current_site_(current_site), pretenure_flag_(NOT_TENURED) {}
1018 explicit HAllocationMode(PretenureFlag pretenure_flag)
1019 : current_site_(NULL), pretenure_flag_(pretenure_flag) {}
1021 : current_site_(NULL), pretenure_flag_(NOT_TENURED) {}
1023 HValue* current_site() const { return current_site_; }
1024 Handle<AllocationSite> feedback_site() const { return feedback_site_; }
1026 bool CreateAllocationMementos() const V8_WARN_UNUSED_RESULT {
1027 return current_site() != NULL;
1030 PretenureFlag GetPretenureMode() const V8_WARN_UNUSED_RESULT {
1031 if (!feedback_site().is_null()) return feedback_site()->GetPretenureMode();
1032 return pretenure_flag_;
1036 HValue* current_site_;
1037 Handle<AllocationSite> feedback_site_;
1038 PretenureFlag pretenure_flag_;
1042 class HGraphBuilder {
1044 explicit HGraphBuilder(CompilationInfo* info)
1047 current_block_(NULL),
1048 scope_(info->scope()),
1049 position_(HSourcePosition::Unknown()),
1050 start_position_(0) {}
1051 virtual ~HGraphBuilder() {}
1053 Scope* scope() const { return scope_; }
1054 void set_scope(Scope* scope) { scope_ = scope; }
1056 HBasicBlock* current_block() const { return current_block_; }
1057 void set_current_block(HBasicBlock* block) { current_block_ = block; }
1058 HEnvironment* environment() const {
1059 return current_block()->last_environment();
1061 Zone* zone() const { return info_->zone(); }
1062 HGraph* graph() const { return graph_; }
1063 Isolate* isolate() const { return graph_->isolate(); }
1064 CompilationInfo* top_info() { return info_; }
1066 HGraph* CreateGraph();
1068 // Bailout environment manipulation.
1069 void Push(HValue* value) { environment()->Push(value); }
1070 HValue* Pop() { return environment()->Pop(); }
1072 virtual HValue* context() = 0;
1074 // Adding instructions.
1075 HInstruction* AddInstruction(HInstruction* instr);
1076 void FinishCurrentBlock(HControlInstruction* last);
1077 void FinishExitCurrentBlock(HControlInstruction* instruction);
1079 void Goto(HBasicBlock* from,
1080 HBasicBlock* target,
1081 FunctionState* state = NULL,
1082 bool add_simulate = true) {
1083 from->Goto(target, source_position(), state, add_simulate);
1085 void Goto(HBasicBlock* target,
1086 FunctionState* state = NULL,
1087 bool add_simulate = true) {
1088 Goto(current_block(), target, state, add_simulate);
1090 void GotoNoSimulate(HBasicBlock* from, HBasicBlock* target) {
1091 Goto(from, target, NULL, false);
1093 void GotoNoSimulate(HBasicBlock* target) {
1094 Goto(target, NULL, false);
1096 void AddLeaveInlined(HBasicBlock* block,
1097 HValue* return_value,
1098 FunctionState* state) {
1099 block->AddLeaveInlined(return_value, state, source_position());
1101 void AddLeaveInlined(HValue* return_value, FunctionState* state) {
1102 return AddLeaveInlined(current_block(), return_value, state);
1106 HInstruction* NewUncasted() { return I::New(zone(), context()); }
1109 I* New() { return I::New(zone(), context()); }
1112 HInstruction* AddUncasted() { return AddInstruction(NewUncasted<I>());}
1115 I* Add() { return AddInstructionTyped(New<I>());}
1117 template<class I, class P1>
1118 HInstruction* NewUncasted(P1 p1) {
1119 return I::New(zone(), context(), p1);
1122 template<class I, class P1>
1123 I* New(P1 p1) { return I::New(zone(), context(), p1); }
1125 template<class I, class P1>
1126 HInstruction* AddUncasted(P1 p1) {
1127 HInstruction* result = AddInstruction(NewUncasted<I>(p1));
1128 // Specializations must have their parameters properly casted
1129 // to avoid landing here.
1130 DCHECK(!result->IsReturn() && !result->IsSimulate() &&
1131 !result->IsDeoptimize());
1135 template<class I, class P1>
1137 I* result = AddInstructionTyped(New<I>(p1));
1138 // Specializations must have their parameters properly casted
1139 // to avoid landing here.
1140 DCHECK(!result->IsReturn() && !result->IsSimulate() &&
1141 !result->IsDeoptimize());
1145 template<class I, class P1, class P2>
1146 HInstruction* NewUncasted(P1 p1, P2 p2) {
1147 return I::New(zone(), context(), p1, p2);
1150 template<class I, class P1, class P2>
1151 I* New(P1 p1, P2 p2) {
1152 return I::New(zone(), context(), p1, p2);
1155 template<class I, class P1, class P2>
1156 HInstruction* AddUncasted(P1 p1, P2 p2) {
1157 HInstruction* result = AddInstruction(NewUncasted<I>(p1, p2));
1158 // Specializations must have their parameters properly casted
1159 // to avoid landing here.
1160 DCHECK(!result->IsSimulate());
1164 template<class I, class P1, class P2>
1165 I* Add(P1 p1, P2 p2) {
1166 I* result = AddInstructionTyped(New<I>(p1, p2));
1167 // Specializations must have their parameters properly casted
1168 // to avoid landing here.
1169 DCHECK(!result->IsSimulate());
1173 template<class I, class P1, class P2, class P3>
1174 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3) {
1175 return I::New(zone(), context(), p1, p2, p3);
1178 template<class I, class P1, class P2, class P3>
1179 I* New(P1 p1, P2 p2, P3 p3) {
1180 return I::New(zone(), context(), p1, p2, p3);
1183 template<class I, class P1, class P2, class P3>
1184 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3) {
1185 return AddInstruction(NewUncasted<I>(p1, p2, p3));
1188 template<class I, class P1, class P2, class P3>
1189 I* Add(P1 p1, P2 p2, P3 p3) {
1190 return AddInstructionTyped(New<I>(p1, p2, p3));
1193 template<class I, class P1, class P2, class P3, class P4>
1194 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4) {
1195 return I::New(zone(), context(), p1, p2, p3, p4);
1198 template<class I, class P1, class P2, class P3, class P4>
1199 I* New(P1 p1, P2 p2, P3 p3, P4 p4) {
1200 return I::New(zone(), context(), p1, p2, p3, p4);
1203 template<class I, class P1, class P2, class P3, class P4>
1204 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4) {
1205 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4));
1208 template<class I, class P1, class P2, class P3, class P4>
1209 I* Add(P1 p1, P2 p2, P3 p3, P4 p4) {
1210 return AddInstructionTyped(New<I>(p1, p2, p3, p4));
1213 template<class I, class P1, class P2, class P3, class P4, class P5>
1214 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
1215 return I::New(zone(), context(), p1, p2, p3, p4, p5);
1218 template<class I, class P1, class P2, class P3, class P4, class P5>
1219 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
1220 return I::New(zone(), context(), p1, p2, p3, p4, p5);
1223 template<class I, class P1, class P2, class P3, class P4, class P5>
1224 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
1225 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5));
1228 template<class I, class P1, class P2, class P3, class P4, class P5>
1229 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
1230 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5));
1233 template<class I, class P1, class P2, class P3, class P4, class P5, class P6>
1234 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {
1235 return I::New(zone(), context(), p1, p2, p3, p4, p5, p6);
1238 template<class I, class P1, class P2, class P3, class P4, class P5, class P6>
1239 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {
1240 return I::New(zone(), context(), p1, p2, p3, p4, p5, p6);
1243 template<class I, class P1, class P2, class P3, class P4, class P5, class P6>
1244 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {
1245 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6));
1248 template<class I, class P1, class P2, class P3, class P4, class P5, class P6>
1249 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {
1250 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5, p6));
1253 template<class I, class P1, class P2, class P3, class P4,
1254 class P5, class P6, class P7>
1255 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
1256 return I::New(zone(), context(), p1, p2, p3, p4, p5, p6, p7);
1259 template<class I, class P1, class P2, class P3, class P4,
1260 class P5, class P6, class P7>
1261 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
1262 return I::New(zone(), context(), p1, p2, p3, p4, p5, p6, p7);
1265 template<class I, class P1, class P2, class P3,
1266 class P4, class P5, class P6, class P7>
1267 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
1268 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6, p7));
1271 template<class I, class P1, class P2, class P3,
1272 class P4, class P5, class P6, class P7>
1273 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
1274 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5, p6, p7));
1277 template<class I, class P1, class P2, class P3, class P4,
1278 class P5, class P6, class P7, class P8>
1279 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4,
1280 P5 p5, P6 p6, P7 p7, P8 p8) {
1281 return I::New(zone(), context(), p1, p2, p3, p4, p5, p6, p7, p8);
1284 template<class I, class P1, class P2, class P3, class P4,
1285 class P5, class P6, class P7, class P8>
1286 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) {
1287 return I::New(zone(), context(), p1, p2, p3, p4, p5, p6, p7, p8);
1290 template<class I, class P1, class P2, class P3, class P4,
1291 class P5, class P6, class P7, class P8>
1292 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4,
1293 P5 p5, P6 p6, P7 p7, P8 p8) {
1294 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6, p7, p8));
1297 template<class I, class P1, class P2, class P3, class P4,
1298 class P5, class P6, class P7, class P8>
1299 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) {
1300 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5, p6, p7, p8));
1303 void AddSimulate(BailoutId id, RemovableSimulate removable = FIXED_SIMULATE);
1305 // When initializing arrays, we'll unfold the loop if the number of elements
1306 // is known at compile time and is <= kElementLoopUnrollThreshold.
1307 static const int kElementLoopUnrollThreshold = 8;
1310 virtual bool BuildGraph() = 0;
1312 HBasicBlock* CreateBasicBlock(HEnvironment* env);
1313 HBasicBlock* CreateLoopHeaderBlock();
1315 template <class BitFieldClass>
1316 HValue* BuildDecodeField(HValue* encoded_field) {
1317 HValue* mask_value = Add<HConstant>(static_cast<int>(BitFieldClass::kMask));
1318 HValue* masked_field =
1319 AddUncasted<HBitwise>(Token::BIT_AND, encoded_field, mask_value);
1320 return AddUncasted<HShr>(masked_field,
1321 Add<HConstant>(static_cast<int>(BitFieldClass::kShift)));
1324 HValue* BuildGetElementsKind(HValue* object);
1326 HValue* BuildCheckHeapObject(HValue* object);
1327 HValue* BuildCheckString(HValue* string);
1328 HValue* BuildWrapReceiver(HValue* object, HValue* function);
1330 // Building common constructs
1331 HValue* BuildCheckForCapacityGrow(HValue* object,
1337 PropertyAccessType access_type);
1339 HValue* BuildCopyElementsOnWrite(HValue* object,
1344 void BuildTransitionElementsKind(HValue* object,
1346 ElementsKind from_kind,
1347 ElementsKind to_kind,
1350 HValue* BuildNumberToString(HValue* object, Type* type);
1352 void BuildJSObjectCheck(HValue* receiver,
1353 int bit_field_mask);
1355 // Checks a key value that's being used for a keyed element access context. If
1356 // the key is a index, i.e. a smi or a number in a unique string with a cached
1357 // numeric value, the "true" of the continuation is joined. Otherwise,
1358 // if the key is a name or a unique string, the "false" of the continuation is
1359 // joined. Otherwise, a deoptimization is triggered. In both paths of the
1360 // continuation, the key is pushed on the top of the environment.
1361 void BuildKeyedIndexCheck(HValue* key,
1362 HIfContinuation* join_continuation);
1364 // Checks the properties of an object if they are in dictionary case, in which
1365 // case "true" of continuation is taken, otherwise the "false"
1366 void BuildTestForDictionaryProperties(HValue* object,
1367 HIfContinuation* continuation);
1369 void BuildNonGlobalObjectCheck(HValue* receiver);
1371 HValue* BuildKeyedLookupCacheHash(HValue* object,
1374 HValue* BuildUncheckedDictionaryElementLoad(HValue* receiver,
1379 HValue* BuildRegExpConstructResult(HValue* length,
1383 // Allocates a new object according with the given allocation properties.
1384 HAllocate* BuildAllocate(HValue* object_size,
1386 InstanceType instance_type,
1387 HAllocationMode allocation_mode);
1388 // Computes the sum of two string lengths, taking care of overflow handling.
1389 HValue* BuildAddStringLengths(HValue* left_length, HValue* right_length);
1390 // Creates a cons string using the two input strings.
1391 HValue* BuildCreateConsString(HValue* length,
1394 HAllocationMode allocation_mode);
1395 // Copies characters from one sequential string to another.
1396 void BuildCopySeqStringChars(HValue* src,
1398 String::Encoding src_encoding,
1401 String::Encoding dst_encoding,
1404 // Align an object size to object alignment boundary
1405 HValue* BuildObjectSizeAlignment(HValue* unaligned_size, int header_size);
1407 // Both operands are non-empty strings.
1408 HValue* BuildUncheckedStringAdd(HValue* left,
1410 HAllocationMode allocation_mode);
1411 // Add two strings using allocation mode, validating type feedback.
1412 HValue* BuildStringAdd(HValue* left,
1414 HAllocationMode allocation_mode);
1416 HInstruction* BuildUncheckedMonomorphicElementAccess(
1417 HValue* checked_object,
1421 ElementsKind elements_kind,
1422 PropertyAccessType access_type,
1423 LoadKeyedHoleMode load_mode,
1424 KeyedAccessStoreMode store_mode);
1426 HInstruction* AddElementAccess(
1428 HValue* checked_key,
1431 ElementsKind elements_kind,
1432 PropertyAccessType access_type,
1433 LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE);
1435 HInstruction* AddLoadStringInstanceType(HValue* string);
1436 HInstruction* AddLoadStringLength(HValue* string);
1437 HStoreNamedField* AddStoreMapConstant(HValue* object, Handle<Map> map) {
1438 return Add<HStoreNamedField>(object, HObjectAccess::ForMap(),
1439 Add<HConstant>(map));
1441 HLoadNamedField* AddLoadMap(HValue* object,
1442 HValue* dependency = NULL);
1443 HLoadNamedField* AddLoadElements(HValue* object,
1444 HValue* dependency = NULL);
1446 bool MatchRotateRight(HValue* left,
1449 HValue** shift_amount);
1451 HValue* BuildBinaryOperation(Token::Value op,
1457 Maybe<int> fixed_right_arg,
1458 HAllocationMode allocation_mode);
1460 HLoadNamedField* AddLoadFixedArrayLength(HValue *object,
1461 HValue *dependency = NULL);
1463 HLoadNamedField* AddLoadArrayLength(HValue *object,
1465 HValue *dependency = NULL);
1467 HValue* AddLoadJSBuiltin(Builtins::JavaScript builtin);
1469 HValue* EnforceNumberType(HValue* number, Type* expected);
1470 HValue* TruncateToNumber(HValue* value, Type** expected);
1472 void FinishExitWithHardDeoptimization(const char* reason);
1474 void AddIncrementCounter(StatsCounter* counter);
1476 class IfBuilder V8_FINAL {
1478 // If using this constructor, Initialize() must be called explicitly!
1481 explicit IfBuilder(HGraphBuilder* builder);
1482 IfBuilder(HGraphBuilder* builder,
1483 HIfContinuation* continuation);
1486 if (!finished_) End();
1489 void Initialize(HGraphBuilder* builder);
1491 template<class Condition>
1492 Condition* If(HValue *p) {
1493 Condition* compare = builder()->New<Condition>(p);
1494 AddCompare(compare);
1498 template<class Condition, class P2>
1499 Condition* If(HValue* p1, P2 p2) {
1500 Condition* compare = builder()->New<Condition>(p1, p2);
1501 AddCompare(compare);
1505 template<class Condition, class P2, class P3>
1506 Condition* If(HValue* p1, P2 p2, P3 p3) {
1507 Condition* compare = builder()->New<Condition>(p1, p2, p3);
1508 AddCompare(compare);
1512 template<class Condition>
1513 Condition* IfNot(HValue* p) {
1514 Condition* compare = If<Condition>(p);
1519 template<class Condition, class P2>
1520 Condition* IfNot(HValue* p1, P2 p2) {
1521 Condition* compare = If<Condition>(p1, p2);
1526 template<class Condition, class P2, class P3>
1527 Condition* IfNot(HValue* p1, P2 p2, P3 p3) {
1528 Condition* compare = If<Condition>(p1, p2, p3);
1533 template<class Condition>
1534 Condition* OrIf(HValue *p) {
1536 return If<Condition>(p);
1539 template<class Condition, class P2>
1540 Condition* OrIf(HValue* p1, P2 p2) {
1542 return If<Condition>(p1, p2);
1545 template<class Condition, class P2, class P3>
1546 Condition* OrIf(HValue* p1, P2 p2, P3 p3) {
1548 return If<Condition>(p1, p2, p3);
1551 template<class Condition>
1552 Condition* AndIf(HValue *p) {
1554 return If<Condition>(p);
1557 template<class Condition, class P2>
1558 Condition* AndIf(HValue* p1, P2 p2) {
1560 return If<Condition>(p1, p2);
1563 template<class Condition, class P2, class P3>
1564 Condition* AndIf(HValue* p1, P2 p2, P3 p3) {
1566 return If<Condition>(p1, p2, p3);
1572 // Captures the current state of this IfBuilder in the specified
1573 // continuation and ends this IfBuilder.
1574 void CaptureContinuation(HIfContinuation* continuation);
1576 // Joins the specified continuation from this IfBuilder and ends this
1577 // IfBuilder. This appends a Goto instruction from the true branch of
1578 // this IfBuilder to the true branch of the continuation unless the
1579 // true branch of this IfBuilder is already finished. And vice versa
1580 // for the false branch.
1582 // The basic idea is as follows: You have several nested IfBuilder's
1583 // that you want to join based on two possible outcomes (i.e. success
1584 // and failure, or whatever). You can do this easily using this method
1585 // now, for example:
1587 // HIfContinuation cont(graph()->CreateBasicBlock(),
1588 // graph()->CreateBasicBlock());
1590 // IfBuilder if_whatever(this);
1591 // if_whatever.If<Condition>(arg);
1592 // if_whatever.Then();
1594 // if_whatever.Else();
1596 // if_whatever.JoinContinuation(&cont);
1598 // IfBuilder if_something(this);
1599 // if_something.If<Condition>(arg1, arg2);
1600 // if_something.Then();
1602 // if_something.Else();
1604 // if_something.JoinContinuation(&cont);
1606 // IfBuilder if_finally(this, &cont);
1607 // if_finally.Then();
1608 // // continues after then code of if_whatever or if_something.
1610 // if_finally.Else();
1611 // // continues after else code of if_whatever or if_something.
1613 // if_finally.End();
1614 void JoinContinuation(HIfContinuation* continuation);
1620 void Deopt(const char* reason);
1621 void ThenDeopt(const char* reason) {
1625 void ElseDeopt(const char* reason) {
1630 void Return(HValue* value);
1633 void InitializeDontCreateBlocks(HGraphBuilder* builder);
1635 HControlInstruction* AddCompare(HControlInstruction* compare);
1637 HGraphBuilder* builder() const {
1638 DCHECK(builder_ != NULL); // Have you called "Initialize"?
1642 void AddMergeAtJoinBlock(bool deopt);
1645 void Finish(HBasicBlock** then_continuation,
1646 HBasicBlock** else_continuation);
1648 class MergeAtJoinBlock : public ZoneObject {
1650 MergeAtJoinBlock(HBasicBlock* block,
1652 MergeAtJoinBlock* next)
1656 HBasicBlock* block_;
1658 MergeAtJoinBlock* next_;
1661 HGraphBuilder* builder_;
1665 bool did_else_if_ : 1;
1669 bool needs_compare_ : 1;
1670 bool pending_merge_block_ : 1;
1671 HBasicBlock* first_true_block_;
1672 HBasicBlock* first_false_block_;
1673 HBasicBlock* split_edge_merge_block_;
1674 MergeAtJoinBlock* merge_at_join_blocks_;
1675 int normal_merge_at_join_block_count_;
1676 int deopt_merge_at_join_block_count_;
1679 class LoopBuilder V8_FINAL {
1689 explicit LoopBuilder(HGraphBuilder* builder); // while (true) {...}
1690 LoopBuilder(HGraphBuilder* builder,
1692 Direction direction);
1693 LoopBuilder(HGraphBuilder* builder,
1695 Direction direction,
1696 HValue* increment_amount);
1704 HValue* terminating,
1705 Token::Value token);
1707 void BeginBody(int drop_count);
1714 void Initialize(HGraphBuilder* builder, HValue* context,
1715 Direction direction, HValue* increment_amount);
1716 Zone* zone() { return builder_->zone(); }
1718 HGraphBuilder* builder_;
1720 HValue* increment_amount_;
1721 HInstruction* increment_;
1723 HBasicBlock* header_block_;
1724 HBasicBlock* body_block_;
1725 HBasicBlock* exit_block_;
1726 HBasicBlock* exit_trampoline_block_;
1727 Direction direction_;
1731 template <class A, class P1>
1732 void DeoptimizeIf(P1 p1, char* const reason) {
1733 IfBuilder builder(this);
1735 builder.ThenDeopt(reason);
1738 template <class A, class P1, class P2>
1739 void DeoptimizeIf(P1 p1, P2 p2, const char* reason) {
1740 IfBuilder builder(this);
1741 builder.If<A>(p1, p2);
1742 builder.ThenDeopt(reason);
1745 template <class A, class P1, class P2, class P3>
1746 void DeoptimizeIf(P1 p1, P2 p2, P3 p3, const char* reason) {
1747 IfBuilder builder(this);
1748 builder.If<A>(p1, p2, p3);
1749 builder.ThenDeopt(reason);
1752 HValue* BuildNewElementsCapacity(HValue* old_capacity);
1754 class JSArrayBuilder V8_FINAL {
1756 JSArrayBuilder(HGraphBuilder* builder,
1758 HValue* allocation_site_payload,
1759 HValue* constructor_function,
1760 AllocationSiteOverrideMode override_mode);
1762 JSArrayBuilder(HGraphBuilder* builder,
1764 HValue* constructor_function = NULL);
1767 DONT_FILL_WITH_HOLE,
1771 ElementsKind kind() { return kind_; }
1772 HAllocate* elements_location() { return elements_location_; }
1774 HAllocate* AllocateEmptyArray();
1775 HAllocate* AllocateArray(HValue* capacity,
1776 HValue* length_field,
1777 FillMode fill_mode = FILL_WITH_HOLE);
1778 // Use these allocators when capacity could be unknown at compile time
1779 // but its limit is known. For constant |capacity| the value of
1780 // |capacity_upper_bound| is ignored and the actual |capacity|
1781 // value is used as an upper bound.
1782 HAllocate* AllocateArray(HValue* capacity,
1783 int capacity_upper_bound,
1784 HValue* length_field,
1785 FillMode fill_mode = FILL_WITH_HOLE);
1786 HAllocate* AllocateArray(HValue* capacity,
1787 HConstant* capacity_upper_bound,
1788 HValue* length_field,
1789 FillMode fill_mode = FILL_WITH_HOLE);
1790 HValue* GetElementsLocation() { return elements_location_; }
1791 HValue* EmitMapCode();
1794 Zone* zone() const { return builder_->zone(); }
1795 int elements_size() const {
1796 return IsFastDoubleElementsKind(kind_) ? kDoubleSize : kPointerSize;
1798 HGraphBuilder* builder() { return builder_; }
1799 HGraph* graph() { return builder_->graph(); }
1800 int initial_capacity() {
1801 STATIC_ASSERT(JSArray::kPreallocatedArrayElements > 0);
1802 return JSArray::kPreallocatedArrayElements;
1805 HValue* EmitInternalMapCode();
1807 HGraphBuilder* builder_;
1809 AllocationSiteMode mode_;
1810 HValue* allocation_site_payload_;
1811 HValue* constructor_function_;
1812 HAllocate* elements_location_;
1815 HValue* BuildAllocateArrayFromLength(JSArrayBuilder* array_builder,
1816 HValue* length_argument);
1817 HValue* BuildCalculateElementsSize(ElementsKind kind,
1819 HAllocate* AllocateJSArrayObject(AllocationSiteMode mode);
1820 HConstant* EstablishElementsAllocationSize(ElementsKind kind, int capacity);
1822 HAllocate* BuildAllocateElements(ElementsKind kind, HValue* size_in_bytes);
1824 void BuildInitializeElementsHeader(HValue* elements,
1828 HValue* BuildAllocateElementsAndInitializeElementsHeader(ElementsKind kind,
1831 // |array| must have been allocated with enough room for
1832 // 1) the JSArray and 2) an AllocationMemento if mode requires it.
1833 // If the |elements| value provided is NULL then the array elements storage
1834 // is initialized with empty array.
1835 void BuildJSArrayHeader(HValue* array,
1838 AllocationSiteMode mode,
1839 ElementsKind elements_kind,
1840 HValue* allocation_site_payload,
1841 HValue* length_field);
1843 HValue* BuildGrowElementsCapacity(HValue* object,
1846 ElementsKind new_kind,
1848 HValue* new_capacity);
1850 void BuildFillElementsWithValue(HValue* elements,
1851 ElementsKind elements_kind,
1856 void BuildFillElementsWithHole(HValue* elements,
1857 ElementsKind elements_kind,
1861 void BuildCopyElements(HValue* from_elements,
1862 ElementsKind from_elements_kind,
1863 HValue* to_elements,
1864 ElementsKind to_elements_kind,
1868 HValue* BuildCloneShallowArrayCow(HValue* boilerplate,
1869 HValue* allocation_site,
1870 AllocationSiteMode mode,
1873 HValue* BuildCloneShallowArrayEmpty(HValue* boilerplate,
1874 HValue* allocation_site,
1875 AllocationSiteMode mode);
1877 HValue* BuildCloneShallowArrayNonEmpty(HValue* boilerplate,
1878 HValue* allocation_site,
1879 AllocationSiteMode mode,
1882 HValue* BuildElementIndexHash(HValue* index);
1884 void BuildCompareNil(
1887 HIfContinuation* continuation);
1889 void BuildCreateAllocationMemento(HValue* previous_object,
1890 HValue* previous_object_size,
1893 HInstruction* BuildConstantMapCheck(Handle<JSObject> constant);
1894 HInstruction* BuildCheckPrototypeMaps(Handle<JSObject> prototype,
1895 Handle<JSObject> holder);
1897 HInstruction* BuildGetNativeContext(HValue* closure);
1898 HInstruction* BuildGetNativeContext();
1899 HInstruction* BuildGetArrayFunction();
1902 void SetSourcePosition(int position) {
1903 DCHECK(position != RelocInfo::kNoPosition);
1904 position_.set_position(position - start_position_);
1907 void EnterInlinedSource(int start_position, int id) {
1908 if (FLAG_hydrogen_track_positions) {
1909 start_position_ = start_position;
1910 position_.set_inlining_id(id);
1914 // Convert the given absolute offset from the start of the script to
1915 // the HSourcePosition assuming that this position corresponds to the
1916 // same function as current position_.
1917 HSourcePosition ScriptPositionToSourcePosition(int position) {
1918 HSourcePosition pos = position_;
1919 pos.set_position(position - start_position_);
1923 HSourcePosition source_position() { return position_; }
1924 void set_source_position(HSourcePosition position) {
1925 position_ = position;
1928 template <typename ViewClass>
1929 void BuildArrayBufferViewInitialization(HValue* obj,
1931 HValue* byte_offset,
1932 HValue* byte_length);
1938 I* AddInstructionTyped(I* instr) {
1939 return I::cast(AddInstruction(instr));
1942 CompilationInfo* info_;
1944 HBasicBlock* current_block_;
1946 HSourcePosition position_;
1947 int start_position_;
1952 inline HDeoptimize* HGraphBuilder::Add<HDeoptimize>(
1953 const char* reason, Deoptimizer::BailoutType type) {
1954 if (type == Deoptimizer::SOFT) {
1955 isolate()->counters()->soft_deopts_requested()->Increment();
1956 if (FLAG_always_opt) return NULL;
1958 if (current_block()->IsDeoptimizing()) return NULL;
1959 HBasicBlock* after_deopt_block = CreateBasicBlock(
1960 current_block()->last_environment());
1961 HDeoptimize* instr = New<HDeoptimize>(reason, type, after_deopt_block);
1962 if (type == Deoptimizer::SOFT) {
1963 isolate()->counters()->soft_deopts_inserted()->Increment();
1965 FinishCurrentBlock(instr);
1966 set_current_block(after_deopt_block);
1972 inline HInstruction* HGraphBuilder::AddUncasted<HDeoptimize>(
1973 const char* reason, Deoptimizer::BailoutType type) {
1974 return Add<HDeoptimize>(reason, type);
1979 inline HSimulate* HGraphBuilder::Add<HSimulate>(
1981 RemovableSimulate removable) {
1982 HSimulate* instr = current_block()->CreateSimulate(id, removable);
1983 AddInstruction(instr);
1989 inline HSimulate* HGraphBuilder::Add<HSimulate>(
1991 return Add<HSimulate>(id, FIXED_SIMULATE);
1996 inline HInstruction* HGraphBuilder::AddUncasted<HSimulate>(BailoutId id) {
1997 return Add<HSimulate>(id, FIXED_SIMULATE);
2002 inline HReturn* HGraphBuilder::Add<HReturn>(HValue* value) {
2003 int num_parameters = graph()->info()->num_parameters();
2004 HValue* params = AddUncasted<HConstant>(num_parameters);
2005 HReturn* return_instruction = New<HReturn>(value, params);
2006 FinishExitCurrentBlock(return_instruction);
2007 return return_instruction;
2012 inline HReturn* HGraphBuilder::Add<HReturn>(HConstant* value) {
2013 return Add<HReturn>(static_cast<HValue*>(value));
2017 inline HInstruction* HGraphBuilder::AddUncasted<HReturn>(HValue* value) {
2018 return Add<HReturn>(value);
2023 inline HInstruction* HGraphBuilder::AddUncasted<HReturn>(HConstant* value) {
2024 return Add<HReturn>(value);
2029 inline HCallRuntime* HGraphBuilder::Add<HCallRuntime>(
2030 Handle<String> name,
2031 const Runtime::Function* c_function,
2032 int argument_count) {
2033 HCallRuntime* instr = New<HCallRuntime>(name, c_function, argument_count);
2034 if (graph()->info()->IsStub()) {
2035 // When compiling code stubs, we don't want to save all double registers
2036 // upon entry to the stub, but instead have the call runtime instruction
2037 // save the double registers only on-demand (in the fallback case).
2038 instr->set_save_doubles(kSaveFPRegs);
2040 AddInstruction(instr);
2046 inline HInstruction* HGraphBuilder::AddUncasted<HCallRuntime>(
2047 Handle<String> name,
2048 const Runtime::Function* c_function,
2049 int argument_count) {
2050 return Add<HCallRuntime>(name, c_function, argument_count);
2055 inline HContext* HGraphBuilder::New<HContext>() {
2056 return HContext::New(zone());
2061 inline HInstruction* HGraphBuilder::NewUncasted<HContext>() {
2062 return New<HContext>();
2065 class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
2067 // A class encapsulating (lazily-allocated) break and continue blocks for
2068 // a breakable statement. Separated from BreakAndContinueScope so that it
2069 // can have a separate lifetime.
2070 class BreakAndContinueInfo V8_FINAL BASE_EMBEDDED {
2072 explicit BreakAndContinueInfo(BreakableStatement* target,
2077 continue_block_(NULL),
2079 drop_extra_(drop_extra) {
2082 BreakableStatement* target() { return target_; }
2083 HBasicBlock* break_block() { return break_block_; }
2084 void set_break_block(HBasicBlock* block) { break_block_ = block; }
2085 HBasicBlock* continue_block() { return continue_block_; }
2086 void set_continue_block(HBasicBlock* block) { continue_block_ = block; }
2087 Scope* scope() { return scope_; }
2088 int drop_extra() { return drop_extra_; }
2091 BreakableStatement* target_;
2092 HBasicBlock* break_block_;
2093 HBasicBlock* continue_block_;
2098 // A helper class to maintain a stack of current BreakAndContinueInfo
2099 // structures mirroring BreakableStatement nesting.
2100 class BreakAndContinueScope V8_FINAL BASE_EMBEDDED {
2102 BreakAndContinueScope(BreakAndContinueInfo* info,
2103 HOptimizedGraphBuilder* owner)
2104 : info_(info), owner_(owner), next_(owner->break_scope()) {
2105 owner->set_break_scope(this);
2108 ~BreakAndContinueScope() { owner_->set_break_scope(next_); }
2110 BreakAndContinueInfo* info() { return info_; }
2111 HOptimizedGraphBuilder* owner() { return owner_; }
2112 BreakAndContinueScope* next() { return next_; }
2114 // Search the break stack for a break or continue target.
2115 enum BreakType { BREAK, CONTINUE };
2116 HBasicBlock* Get(BreakableStatement* stmt, BreakType type,
2117 Scope** scope, int* drop_extra);
2120 BreakAndContinueInfo* info_;
2121 HOptimizedGraphBuilder* owner_;
2122 BreakAndContinueScope* next_;
2125 explicit HOptimizedGraphBuilder(CompilationInfo* info);
2127 virtual bool BuildGraph() V8_OVERRIDE;
2129 // Simple accessors.
2130 BreakAndContinueScope* break_scope() const { return break_scope_; }
2131 void set_break_scope(BreakAndContinueScope* head) { break_scope_ = head; }
2133 bool inline_bailout() { return inline_bailout_; }
2135 HValue* context() { return environment()->context(); }
2137 HOsrBuilder* osr() const { return osr_; }
2139 void Bailout(BailoutReason reason);
2141 HBasicBlock* CreateJoin(HBasicBlock* first,
2142 HBasicBlock* second,
2145 FunctionState* function_state() const { return function_state_; }
2147 void VisitDeclarations(ZoneList<Declaration*>* declarations);
2149 void* operator new(size_t size, Zone* zone) {
2150 return zone->New(static_cast<int>(size));
2152 void operator delete(void* pointer, Zone* zone) { }
2153 void operator delete(void* pointer) { }
2155 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
2158 // Type of a member function that generates inline code for a native function.
2159 typedef void (HOptimizedGraphBuilder::*InlineFunctionGenerator)
2160 (CallRuntime* call);
2162 // Forward declarations for inner scope classes.
2163 class SubgraphScope;
2165 static const InlineFunctionGenerator kInlineFunctionGenerators[];
2167 static const int kMaxCallPolymorphism = 4;
2168 static const int kMaxLoadPolymorphism = 4;
2169 static const int kMaxStorePolymorphism = 4;
2171 // Even in the 'unlimited' case we have to have some limit in order not to
2172 // overflow the stack.
2173 static const int kUnlimitedMaxInlinedSourceSize = 100000;
2174 static const int kUnlimitedMaxInlinedNodes = 10000;
2175 static const int kUnlimitedMaxInlinedNodesCumulative = 10000;
2177 // Maximum depth and total number of elements and properties for literal
2178 // graphs to be considered for fast deep-copying.
2179 static const int kMaxFastLiteralDepth = 3;
2180 static const int kMaxFastLiteralProperties = 8;
2182 // Simple accessors.
2183 void set_function_state(FunctionState* state) { function_state_ = state; }
2185 AstContext* ast_context() const { return ast_context_; }
2186 void set_ast_context(AstContext* context) { ast_context_ = context; }
2188 // Accessors forwarded to the function state.
2189 CompilationInfo* current_info() const {
2190 return function_state()->compilation_info();
2192 AstContext* call_context() const {
2193 return function_state()->call_context();
2195 HBasicBlock* function_return() const {
2196 return function_state()->function_return();
2198 TestContext* inlined_test_context() const {
2199 return function_state()->test_context();
2201 void ClearInlinedTestContext() {
2202 function_state()->ClearInlinedTestContext();
2204 StrictMode function_strict_mode() {
2205 return function_state()->compilation_info()->strict_mode();
2208 // Generators for inline runtime functions.
2209 #define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \
2210 void Generate##Name(CallRuntime* call);
2212 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
2213 INLINE_OPTIMIZED_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
2214 #undef INLINE_FUNCTION_GENERATOR_DECLARATION
2216 void VisitDelete(UnaryOperation* expr);
2217 void VisitVoid(UnaryOperation* expr);
2218 void VisitTypeof(UnaryOperation* expr);
2219 void VisitNot(UnaryOperation* expr);
2221 void VisitComma(BinaryOperation* expr);
2222 void VisitLogicalExpression(BinaryOperation* expr);
2223 void VisitArithmeticExpression(BinaryOperation* expr);
2225 bool PreProcessOsrEntry(IterationStatement* statement);
2226 void VisitLoopBody(IterationStatement* stmt,
2227 HBasicBlock* loop_entry);
2229 // Create a back edge in the flow graph. body_exit is the predecessor
2230 // block and loop_entry is the successor block. loop_successor is the
2231 // block where control flow exits the loop normally (e.g., via failure of
2232 // the condition) and break_block is the block where control flow breaks
2233 // from the loop. All blocks except loop_entry can be NULL. The return
2234 // value is the new successor block which is the join of loop_successor
2235 // and break_block, or NULL.
2236 HBasicBlock* CreateLoop(IterationStatement* statement,
2237 HBasicBlock* loop_entry,
2238 HBasicBlock* body_exit,
2239 HBasicBlock* loop_successor,
2240 HBasicBlock* break_block);
2242 // Build a loop entry
2243 HBasicBlock* BuildLoopEntry();
2245 // Builds a loop entry respectful of OSR requirements
2246 HBasicBlock* BuildLoopEntry(IterationStatement* statement);
2248 HBasicBlock* JoinContinue(IterationStatement* statement,
2249 HBasicBlock* exit_block,
2250 HBasicBlock* continue_block);
2252 HValue* Top() const { return environment()->Top(); }
2253 void Drop(int n) { environment()->Drop(n); }
2254 void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); }
2255 bool IsEligibleForEnvironmentLivenessAnalysis(Variable* var,
2258 HEnvironment* env) {
2259 if (!FLAG_analyze_environment_liveness) return false;
2260 // |this| and |arguments| are always live; zapping parameters isn't
2261 // safe because function.arguments can inspect them at any time.
2262 return !var->is_this() &&
2263 !var->is_arguments() &&
2264 !value->IsArgumentsObject() &&
2265 env->is_local_index(index);
2267 void BindIfLive(Variable* var, HValue* value) {
2268 HEnvironment* env = environment();
2269 int index = env->IndexFor(var);
2270 env->Bind(index, value);
2271 if (IsEligibleForEnvironmentLivenessAnalysis(var, index, value, env)) {
2272 HEnvironmentMarker* bind =
2273 Add<HEnvironmentMarker>(HEnvironmentMarker::BIND, index);
2276 bind->set_closure(env->closure());
2281 HValue* LookupAndMakeLive(Variable* var) {
2282 HEnvironment* env = environment();
2283 int index = env->IndexFor(var);
2284 HValue* value = env->Lookup(index);
2285 if (IsEligibleForEnvironmentLivenessAnalysis(var, index, value, env)) {
2286 HEnvironmentMarker* lookup =
2287 Add<HEnvironmentMarker>(HEnvironmentMarker::LOOKUP, index);
2290 lookup->set_closure(env->closure());
2296 // The value of the arguments object is allowed in some but not most value
2297 // contexts. (It's allowed in all effect contexts and disallowed in all
2299 void VisitForValue(Expression* expr,
2300 ArgumentsAllowedFlag flag = ARGUMENTS_NOT_ALLOWED);
2301 void VisitForTypeOf(Expression* expr);
2302 void VisitForEffect(Expression* expr);
2303 void VisitForControl(Expression* expr,
2304 HBasicBlock* true_block,
2305 HBasicBlock* false_block);
2307 // Visit a list of expressions from left to right, each in a value context.
2308 void VisitExpressions(ZoneList<Expression*>* exprs);
2310 // Remove the arguments from the bailout environment and emit instructions
2311 // to push them as outgoing parameters.
2312 template <class Instruction> HInstruction* PreProcessCall(Instruction* call);
2313 void PushArgumentsFromEnvironment(int count);
2315 void SetUpScope(Scope* scope);
2316 virtual void VisitStatements(ZoneList<Statement*>* statements) V8_OVERRIDE;
2318 #define DECLARE_VISIT(type) virtual void Visit##type(type* node) V8_OVERRIDE;
2319 AST_NODE_LIST(DECLARE_VISIT)
2320 #undef DECLARE_VISIT
2322 Type* ToType(Handle<Map> map) { return IC::MapToType<Type>(map, zone()); }
2325 // Helpers for flow graph construction.
2326 enum GlobalPropertyAccess {
2330 GlobalPropertyAccess LookupGlobalProperty(Variable* var,
2331 LookupResult* lookup,
2332 PropertyAccessType access_type);
2334 void EnsureArgumentsArePushedForAccess();
2335 bool TryArgumentsAccess(Property* expr);
2337 // Try to optimize fun.apply(receiver, arguments) pattern.
2338 bool TryCallApply(Call* expr);
2340 bool TryHandleArrayCall(Call* expr, HValue* function);
2341 bool TryHandleArrayCallNew(CallNew* expr, HValue* function);
2342 void BuildArrayCall(Expression* expr, int arguments_count, HValue* function,
2343 Handle<AllocationSite> cell);
2345 enum ArrayIndexOfMode { kFirstIndexOf, kLastIndexOf };
2346 HValue* BuildArrayIndexOf(HValue* receiver,
2347 HValue* search_element,
2349 ArrayIndexOfMode mode);
2351 HValue* ImplicitReceiverFor(HValue* function,
2352 Handle<JSFunction> target);
2354 int InliningAstSize(Handle<JSFunction> target);
2355 bool TryInline(Handle<JSFunction> target,
2356 int arguments_count,
2357 HValue* implicit_return_value,
2359 BailoutId return_id,
2360 InliningKind inlining_kind,
2361 HSourcePosition position);
2363 bool TryInlineCall(Call* expr);
2364 bool TryInlineConstruct(CallNew* expr, HValue* implicit_return_value);
2365 bool TryInlineGetter(Handle<JSFunction> getter,
2366 Handle<Map> receiver_map,
2368 BailoutId return_id);
2369 bool TryInlineSetter(Handle<JSFunction> setter,
2370 Handle<Map> receiver_map,
2372 BailoutId assignment_id,
2373 HValue* implicit_return_value);
2374 bool TryInlineApply(Handle<JSFunction> function,
2376 int arguments_count);
2377 bool TryInlineBuiltinMethodCall(Call* expr,
2379 Handle<Map> receiver_map);
2380 bool TryInlineBuiltinFunctionCall(Call* expr);
2387 bool TryInlineApiMethodCall(Call* expr,
2389 SmallMapList* receiver_types);
2390 bool TryInlineApiFunctionCall(Call* expr, HValue* receiver);
2391 bool TryInlineApiGetter(Handle<JSFunction> function,
2392 Handle<Map> receiver_map,
2394 bool TryInlineApiSetter(Handle<JSFunction> function,
2395 Handle<Map> receiver_map,
2397 bool TryInlineApiCall(Handle<JSFunction> function,
2399 SmallMapList* receiver_maps,
2402 ApiCallType call_type);
2404 // If --trace-inlining, print a line of the inlining trace. Inlining
2405 // succeeded if the reason string is NULL and failed if there is a
2406 // non-NULL reason string.
2407 void TraceInline(Handle<JSFunction> target,
2408 Handle<JSFunction> caller,
2409 const char* failure_reason);
2411 void HandleGlobalVariableAssignment(Variable* var,
2415 void HandlePropertyAssignment(Assignment* expr);
2416 void HandleCompoundAssignment(Assignment* expr);
2417 void HandlePolymorphicNamedFieldAccess(PropertyAccessType access_type,
2420 BailoutId return_id,
2423 SmallMapList* types,
2424 Handle<String> name);
2426 HValue* BuildAllocateExternalElements(
2427 ExternalArrayType array_type,
2428 bool is_zero_byte_offset,
2429 HValue* buffer, HValue* byte_offset, HValue* length);
2430 HValue* BuildAllocateFixedTypedArray(
2431 ExternalArrayType array_type, size_t element_size,
2432 ElementsKind fixed_elements_kind,
2433 HValue* byte_length, HValue* length);
2435 Handle<JSFunction> array_function() {
2436 return handle(isolate()->native_context()->array_function());
2439 bool IsCallArrayInlineable(int argument_count, Handle<AllocationSite> site);
2440 void BuildInlinedCallArray(Expression* expression, int argument_count,
2441 Handle<AllocationSite> site);
2443 class PropertyAccessInfo {
2445 PropertyAccessInfo(HOptimizedGraphBuilder* builder,
2446 PropertyAccessType access_type,
2448 Handle<String> name)
2449 : lookup_(builder->isolate()),
2451 access_type_(access_type),
2454 field_type_(HType::Tagged()),
2455 access_(HObjectAccess::ForMap()) { }
2457 // Checkes whether this PropertyAccessInfo can be handled as a monomorphic
2458 // load named. It additionally fills in the fields necessary to generate the
2460 bool CanAccessMonomorphic();
2462 // Checks whether all types behave uniform when loading name. If all maps
2463 // behave the same, a single monomorphic load instruction can be emitted,
2464 // guarded by a single map-checks instruction that whether the receiver is
2465 // an instance of any of the types.
2466 // This method skips the first type in types, assuming that this
2467 // PropertyAccessInfo is built for types->first().
2468 bool CanAccessAsMonomorphic(SmallMapList* types);
2471 Type* type() const { return type_; }
2472 Handle<String> name() const { return name_; }
2474 bool IsJSObjectFieldAccessor() {
2475 int offset; // unused
2476 return Accessors::IsJSObjectFieldAccessor<Type>(type_, name_, &offset);
2479 bool GetJSObjectFieldAccess(HObjectAccess* access) {
2481 if (Accessors::IsJSObjectFieldAccessor<Type>(type_, name_, &offset)) {
2482 if (type_->Is(Type::String())) {
2483 DCHECK(String::Equals(isolate()->factory()->length_string(), name_));
2484 *access = HObjectAccess::ForStringLength();
2485 } else if (type_->Is(Type::Array())) {
2486 DCHECK(String::Equals(isolate()->factory()->length_string(), name_));
2487 *access = HObjectAccess::ForArrayLength(map()->elements_kind());
2489 *access = HObjectAccess::ForMapAndOffset(map(), offset);
2496 bool has_holder() { return !holder_.is_null(); }
2497 bool IsLoad() const { return access_type_ == LOAD; }
2499 LookupResult* lookup() { return &lookup_; }
2500 Handle<JSObject> holder() { return holder_; }
2501 Handle<JSFunction> accessor() { return accessor_; }
2502 Handle<Object> constant() { return constant_; }
2503 Handle<Map> transition() { return handle(lookup_.GetTransitionTarget()); }
2504 SmallMapList* field_maps() { return &field_maps_; }
2505 HType field_type() const { return field_type_; }
2506 HObjectAccess access() { return access_; }
2509 Type* ToType(Handle<Map> map) { return builder_->ToType(map); }
2510 Zone* zone() { return builder_->zone(); }
2511 Isolate* isolate() { return lookup_.isolate(); }
2512 CompilationInfo* top_info() { return builder_->top_info(); }
2513 CompilationInfo* current_info() { return builder_->current_info(); }
2515 bool LoadResult(Handle<Map> map);
2516 void LoadFieldMaps(Handle<Map> map);
2517 bool LookupDescriptor();
2518 bool LookupInPrototypes();
2519 bool IsCompatible(PropertyAccessInfo* other);
2521 void GeneralizeRepresentation(Representation r) {
2522 access_ = access_.WithRepresentation(
2523 access_.representation().generalize(r));
2526 LookupResult lookup_;
2527 HOptimizedGraphBuilder* builder_;
2528 PropertyAccessType access_type_;
2530 Handle<String> name_;
2531 Handle<JSObject> holder_;
2532 Handle<JSFunction> accessor_;
2533 Handle<JSObject> api_holder_;
2534 Handle<Object> constant_;
2535 SmallMapList field_maps_;
2537 HObjectAccess access_;
2540 HInstruction* BuildMonomorphicAccess(PropertyAccessInfo* info,
2542 HValue* checked_object,
2545 BailoutId return_id,
2546 bool can_inline_accessor = true);
2548 HInstruction* BuildNamedAccess(PropertyAccessType access,
2550 BailoutId reutrn_id,
2553 Handle<String> name,
2555 bool is_uninitialized = false);
2557 void HandlePolymorphicCallNamed(Call* expr,
2559 SmallMapList* types,
2560 Handle<String> name);
2561 void HandleLiteralCompareTypeof(CompareOperation* expr,
2562 Expression* sub_expr,
2563 Handle<String> check);
2564 void HandleLiteralCompareNil(CompareOperation* expr,
2565 Expression* sub_expr,
2568 enum PushBeforeSimulateBehavior {
2569 PUSH_BEFORE_SIMULATE,
2570 NO_PUSH_BEFORE_SIMULATE
2573 HControlInstruction* BuildCompareInstruction(
2579 Type* combined_type,
2580 HSourcePosition left_position,
2581 HSourcePosition right_position,
2582 PushBeforeSimulateBehavior push_sim_result,
2583 BailoutId bailout_id);
2585 HInstruction* BuildStringCharCodeAt(HValue* string,
2588 HValue* BuildBinaryOperation(
2589 BinaryOperation* expr,
2592 PushBeforeSimulateBehavior push_sim_result);
2593 HInstruction* BuildIncrement(bool returns_original_input,
2594 CountOperation* expr);
2595 HInstruction* BuildKeyedGeneric(PropertyAccessType access_type,
2601 HInstruction* TryBuildConsolidatedElementLoad(HValue* object,
2604 SmallMapList* maps);
2606 LoadKeyedHoleMode BuildKeyedHoleMode(Handle<Map> map);
2608 HInstruction* BuildMonomorphicElementAccess(HValue* object,
2613 PropertyAccessType access_type,
2614 KeyedAccessStoreMode store_mode);
2616 HValue* HandlePolymorphicElementAccess(Expression* expr,
2621 PropertyAccessType access_type,
2622 KeyedAccessStoreMode store_mode,
2623 bool* has_side_effects);
2625 HValue* HandleKeyedElementAccess(HValue* obj,
2629 PropertyAccessType access_type,
2630 bool* has_side_effects);
2632 HInstruction* BuildNamedGeneric(PropertyAccessType access,
2635 Handle<String> name,
2637 bool is_uninitialized = false);
2639 HCheckMaps* AddCheckMap(HValue* object, Handle<Map> map);
2641 void BuildLoad(Property* property,
2643 void PushLoad(Property* property,
2647 void BuildStoreForEffect(Expression* expression,
2650 BailoutId return_id,
2655 void BuildStore(Expression* expression,
2658 BailoutId return_id,
2659 bool is_uninitialized = false);
2661 HInstruction* BuildLoadNamedField(PropertyAccessInfo* info,
2662 HValue* checked_object);
2663 HInstruction* BuildStoreNamedField(PropertyAccessInfo* info,
2664 HValue* checked_object,
2667 HValue* BuildContextChainWalk(Variable* var);
2669 HInstruction* BuildThisFunction();
2671 HInstruction* BuildFastLiteral(Handle<JSObject> boilerplate_object,
2672 AllocationSiteUsageContext* site_context);
2674 void BuildEmitObjectHeader(Handle<JSObject> boilerplate_object,
2675 HInstruction* object);
2677 void BuildInitElementsInObjectHeader(Handle<JSObject> boilerplate_object,
2678 HInstruction* object,
2679 HInstruction* object_elements);
2681 void BuildEmitInObjectProperties(Handle<JSObject> boilerplate_object,
2682 HInstruction* object,
2683 AllocationSiteUsageContext* site_context,
2684 PretenureFlag pretenure_flag);
2686 void BuildEmitElements(Handle<JSObject> boilerplate_object,
2687 Handle<FixedArrayBase> elements,
2688 HValue* object_elements,
2689 AllocationSiteUsageContext* site_context);
2691 void BuildEmitFixedDoubleArray(Handle<FixedArrayBase> elements,
2693 HValue* object_elements);
2695 void BuildEmitFixedArray(Handle<FixedArrayBase> elements,
2697 HValue* object_elements,
2698 AllocationSiteUsageContext* site_context);
2700 void AddCheckPrototypeMaps(Handle<JSObject> holder,
2701 Handle<Map> receiver_map);
2703 HInstruction* NewPlainFunctionCall(HValue* fun,
2705 bool pass_argument_count);
2707 HInstruction* NewArgumentAdaptorCall(HValue* fun, HValue* context,
2709 HValue* expected_param_count);
2711 HInstruction* BuildCallConstantFunction(Handle<JSFunction> target,
2712 int argument_count);
2714 // The translation state of the currently-being-translated function.
2715 FunctionState* function_state_;
2717 // The base of the function state stack.
2718 FunctionState initial_function_state_;
2720 // Expression context of the currently visited subexpression. NULL when
2721 // visiting statements.
2722 AstContext* ast_context_;
2724 // A stack of breakable statements entered.
2725 BreakAndContinueScope* break_scope_;
2728 ZoneList<Handle<Object> > globals_;
2730 bool inline_bailout_;
2734 friend class FunctionState; // Pushes and pops the state stack.
2735 friend class AstContext; // Pushes and pops the AST context stack.
2736 friend class KeyedLoadFastElementStub;
2737 friend class HOsrBuilder;
2739 DISALLOW_COPY_AND_ASSIGN(HOptimizedGraphBuilder);
2743 Zone* AstContext::zone() const { return owner_->zone(); }
2746 class HStatistics V8_FINAL: public Malloced {
2755 void Initialize(CompilationInfo* info);
2756 void Print(const char* stats_name);
2757 void SaveTiming(const char* name, base::TimeDelta time, unsigned size);
2759 void IncrementFullCodeGen(base::TimeDelta full_code_gen) {
2760 full_code_gen_ += full_code_gen;
2763 void IncrementCreateGraph(base::TimeDelta delta) { create_graph_ += delta; }
2765 void IncrementOptimizeGraph(base::TimeDelta delta) {
2766 optimize_graph_ += delta;
2769 void IncrementGenerateCode(base::TimeDelta delta) { generate_code_ += delta; }
2771 void IncrementSubtotals(base::TimeDelta create_graph,
2772 base::TimeDelta optimize_graph,
2773 base::TimeDelta generate_code) {
2774 IncrementCreateGraph(create_graph);
2775 IncrementOptimizeGraph(optimize_graph);
2776 IncrementGenerateCode(generate_code);
2780 List<base::TimeDelta> times_;
2781 List<const char*> names_;
2782 List<unsigned> sizes_;
2783 base::TimeDelta create_graph_;
2784 base::TimeDelta optimize_graph_;
2785 base::TimeDelta generate_code_;
2786 unsigned total_size_;
2787 base::TimeDelta full_code_gen_;
2788 double source_size_;
2792 class HPhase : public CompilationPhase {
2794 HPhase(const char* name, HGraph* graph)
2795 : CompilationPhase(name, graph->info()),
2800 HGraph* graph() const { return graph_; }
2805 DISALLOW_COPY_AND_ASSIGN(HPhase);
2809 class HTracer V8_FINAL : public Malloced {
2811 explicit HTracer(int isolate_id)
2812 : trace_(&string_allocator_), indent_(0) {
2813 if (FLAG_trace_hydrogen_file == NULL) {
2815 "hydrogen-%d-%d.cfg",
2816 base::OS::GetCurrentProcessId(),
2819 StrNCpy(filename_, FLAG_trace_hydrogen_file, filename_.length());
2821 WriteChars(filename_.start(), "", 0, false);
2824 void TraceCompilation(CompilationInfo* info);
2825 void TraceHydrogen(const char* name, HGraph* graph);
2826 void TraceLithium(const char* name, LChunk* chunk);
2827 void TraceLiveRanges(const char* name, LAllocator* allocator);
2830 class Tag V8_FINAL BASE_EMBEDDED {
2832 Tag(HTracer* tracer, const char* name) {
2835 tracer->PrintIndent();
2836 tracer->trace_.Add("begin_%s\n", name);
2842 tracer_->PrintIndent();
2843 tracer_->trace_.Add("end_%s\n", name_);
2844 DCHECK(tracer_->indent_ >= 0);
2845 tracer_->FlushToFile();
2853 void TraceLiveRange(LiveRange* range, const char* type, Zone* zone);
2854 void Trace(const char* name, HGraph* graph, LChunk* chunk);
2857 void PrintEmptyProperty(const char* name) {
2859 trace_.Add("%s\n", name);
2862 void PrintStringProperty(const char* name, const char* value) {
2864 trace_.Add("%s \"%s\"\n", name, value);
2867 void PrintLongProperty(const char* name, int64_t value) {
2869 trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000));
2872 void PrintBlockProperty(const char* name, int block_id) {
2874 trace_.Add("%s \"B%d\"\n", name, block_id);
2877 void PrintIntProperty(const char* name, int value) {
2879 trace_.Add("%s %d\n", name, value);
2882 void PrintIndent() {
2883 for (int i = 0; i < indent_; i++) {
2888 EmbeddedVector<char, 64> filename_;
2889 HeapStringAllocator string_allocator_;
2890 StringStream trace_;
2895 class NoObservableSideEffectsScope V8_FINAL {
2897 explicit NoObservableSideEffectsScope(HGraphBuilder* builder) :
2899 builder_->graph()->IncrementInNoSideEffectsScope();
2901 ~NoObservableSideEffectsScope() {
2902 builder_->graph()->DecrementInNoSideEffectsScope();
2906 HGraphBuilder* builder_;
2910 } } // namespace v8::internal
2912 #endif // V8_HYDROGEN_H_