1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #ifndef V8_HYDROGEN_H_
29 #define V8_HYDROGEN_H_
33 #include "accessors.h"
34 #include "allocation.h"
37 #include "hydrogen-instructions.h"
44 // Forward declarations.
49 class HLoopInformation;
57 class HBasicBlock V8_FINAL : public ZoneObject {
59 explicit HBasicBlock(HGraph* graph);
63 int block_id() const { return block_id_; }
64 void set_block_id(int id) { block_id_ = id; }
65 HGraph* graph() const { return graph_; }
66 Isolate* isolate() const;
67 const ZoneList<HPhi*>* phis() const { return &phis_; }
68 HInstruction* first() const { return first_; }
69 HInstruction* last() const { return last_; }
70 void set_last(HInstruction* instr) { last_ = instr; }
71 HControlInstruction* end() const { return end_; }
72 HLoopInformation* loop_information() const { return loop_information_; }
73 HLoopInformation* current_loop() const {
74 return IsLoopHeader() ? loop_information()
75 : (parent_loop_header() != NULL
76 ? parent_loop_header()->loop_information() : NULL);
78 const ZoneList<HBasicBlock*>* predecessors() const { return &predecessors_; }
79 bool HasPredecessor() const { return predecessors_.length() > 0; }
80 const ZoneList<HBasicBlock*>* dominated_blocks() const {
81 return &dominated_blocks_;
83 const ZoneList<int>* deleted_phis() const {
84 return &deleted_phis_;
86 void RecordDeletedPhi(int merge_index) {
87 deleted_phis_.Add(merge_index, zone());
89 HBasicBlock* dominator() const { return dominator_; }
90 HEnvironment* last_environment() const { return last_environment_; }
91 int argument_count() const { return argument_count_; }
92 void set_argument_count(int count) { argument_count_ = count; }
93 int first_instruction_index() const { return first_instruction_index_; }
94 void set_first_instruction_index(int index) {
95 first_instruction_index_ = index;
97 int last_instruction_index() const { return last_instruction_index_; }
98 void set_last_instruction_index(int index) {
99 last_instruction_index_ = index;
101 bool is_osr_entry() { return is_osr_entry_; }
102 void set_osr_entry() { is_osr_entry_ = true; }
104 void AttachLoopInformation();
105 void DetachLoopInformation();
106 bool IsLoopHeader() const { return loop_information() != NULL; }
107 bool IsStartBlock() const { return block_id() == 0; }
108 void PostProcessLoopHeader(IterationStatement* stmt);
110 bool IsFinished() const { return end_ != NULL; }
111 void AddPhi(HPhi* phi);
112 void RemovePhi(HPhi* phi);
113 void AddInstruction(HInstruction* instr, int position);
114 bool Dominates(HBasicBlock* other) const;
115 bool EqualToOrDominates(HBasicBlock* other) const;
116 int LoopNestingDepth() const;
118 void SetInitialEnvironment(HEnvironment* env);
119 void ClearEnvironment() {
120 ASSERT(IsFinished());
121 ASSERT(end()->SuccessorCount() == 0);
122 last_environment_ = NULL;
124 bool HasEnvironment() const { return last_environment_ != NULL; }
125 void UpdateEnvironment(HEnvironment* env);
126 HBasicBlock* parent_loop_header() const { return parent_loop_header_; }
128 void set_parent_loop_header(HBasicBlock* block) {
129 ASSERT(parent_loop_header_ == NULL);
130 parent_loop_header_ = block;
133 bool HasParentLoopHeader() const { return parent_loop_header_ != NULL; }
135 void SetJoinId(BailoutId ast_id);
137 int PredecessorIndexOf(HBasicBlock* predecessor) const;
138 HPhi* AddNewPhi(int merged_index);
139 HSimulate* AddNewSimulate(BailoutId ast_id,
141 RemovableSimulate removable = FIXED_SIMULATE) {
142 HSimulate* instr = CreateSimulate(ast_id, removable);
143 AddInstruction(instr, position);
146 void AssignCommonDominator(HBasicBlock* other);
147 void AssignLoopSuccessorDominators();
149 // If a target block is tagged as an inline function return, all
150 // predecessors should contain the inlined exit sequence:
153 // Simulate (caller's environment)
154 // Goto (target block)
155 bool IsInlineReturnTarget() const { return is_inline_return_target_; }
156 void MarkAsInlineReturnTarget(HBasicBlock* inlined_entry_block) {
157 is_inline_return_target_ = true;
158 inlined_entry_block_ = inlined_entry_block;
160 HBasicBlock* inlined_entry_block() { return inlined_entry_block_; }
162 bool IsDeoptimizing() const {
163 return end() != NULL && end()->IsDeoptimize();
166 void MarkUnreachable();
167 bool IsUnreachable() const { return !is_reachable_; }
168 bool IsReachable() const { return is_reachable_; }
170 bool IsLoopSuccessorDominator() const {
171 return dominates_loop_successors_;
173 void MarkAsLoopSuccessorDominator() {
174 dominates_loop_successors_ = true;
177 inline Zone* zone() const;
184 friend class HGraphBuilder;
186 HSimulate* CreateSimulate(BailoutId ast_id, RemovableSimulate removable);
187 void Finish(HControlInstruction* last, int position);
188 void FinishExit(HControlInstruction* instruction, int position);
189 void Goto(HBasicBlock* block,
191 FunctionState* state = NULL,
192 bool add_simulate = true);
193 void GotoNoSimulate(HBasicBlock* block, int position) {
194 Goto(block, position, NULL, false);
197 // Add the inlined function exit sequence, adding an HLeaveInlined
198 // instruction and updating the bailout environment.
199 void AddLeaveInlined(HValue* return_value,
200 FunctionState* state,
204 void RegisterPredecessor(HBasicBlock* pred);
205 void AddDominatedBlock(HBasicBlock* block);
209 ZoneList<HPhi*> phis_;
210 HInstruction* first_;
212 HControlInstruction* end_;
213 HLoopInformation* loop_information_;
214 ZoneList<HBasicBlock*> predecessors_;
215 HBasicBlock* dominator_;
216 ZoneList<HBasicBlock*> dominated_blocks_;
217 HEnvironment* last_environment_;
218 // Outgoing parameter count at block exit, set during lithium translation.
220 // Instruction indices into the lithium code stream.
221 int first_instruction_index_;
222 int last_instruction_index_;
223 ZoneList<int> deleted_phis_;
224 HBasicBlock* parent_loop_header_;
225 // For blocks marked as inline return target: the block with HEnterInlined.
226 HBasicBlock* inlined_entry_block_;
227 bool is_inline_return_target_ : 1;
228 bool is_reachable_ : 1;
229 bool dominates_loop_successors_ : 1;
230 bool is_osr_entry_ : 1;
234 class HPredecessorIterator V8_FINAL BASE_EMBEDDED {
236 explicit HPredecessorIterator(HBasicBlock* block)
237 : predecessor_list_(block->predecessors()), current_(0) { }
239 bool Done() { return current_ >= predecessor_list_->length(); }
240 HBasicBlock* Current() { return predecessor_list_->at(current_); }
241 void Advance() { current_++; }
244 const ZoneList<HBasicBlock*>* predecessor_list_;
249 class HInstructionIterator V8_FINAL BASE_EMBEDDED {
251 explicit HInstructionIterator(HBasicBlock* block)
252 : instr_(block->first()) {
253 next_ = Done() ? NULL : instr_->next();
256 inline bool Done() const { return instr_ == NULL; }
257 inline HInstruction* Current() { return instr_; }
258 inline void Advance() {
260 next_ = Done() ? NULL : instr_->next();
264 HInstruction* instr_;
269 class HLoopInformation V8_FINAL : public ZoneObject {
271 HLoopInformation(HBasicBlock* loop_header, Zone* zone)
272 : back_edges_(4, zone),
273 loop_header_(loop_header),
276 blocks_.Add(loop_header, zone);
278 ~HLoopInformation() {}
280 const ZoneList<HBasicBlock*>* back_edges() const { return &back_edges_; }
281 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
282 HBasicBlock* loop_header() const { return loop_header_; }
283 HBasicBlock* GetLastBackEdge() const;
284 void RegisterBackEdge(HBasicBlock* block);
286 HStackCheck* stack_check() const { return stack_check_; }
287 void set_stack_check(HStackCheck* stack_check) {
288 stack_check_ = stack_check;
291 bool IsNestedInThisLoop(HLoopInformation* other) {
292 while (other != NULL) {
296 other = other->parent_loop();
300 HLoopInformation* parent_loop() {
301 HBasicBlock* parent_header = loop_header()->parent_loop_header();
302 return parent_header != NULL ? parent_header->loop_information() : NULL;
306 void AddBlock(HBasicBlock* block);
308 ZoneList<HBasicBlock*> back_edges_;
309 HBasicBlock* loop_header_;
310 ZoneList<HBasicBlock*> blocks_;
311 HStackCheck* stack_check_;
315 class BoundsCheckTable;
316 class InductionVariableBlocksTable;
317 class HGraph V8_FINAL : public ZoneObject {
319 explicit HGraph(CompilationInfo* info);
321 Isolate* isolate() const { return isolate_; }
322 Zone* zone() const { return zone_; }
323 CompilationInfo* info() const { return info_; }
325 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; }
326 const ZoneList<HPhi*>* phi_list() const { return phi_list_; }
327 HBasicBlock* entry_block() const { return entry_block_; }
328 HEnvironment* start_environment() const { return start_environment_; }
330 void FinalizeUniqueness();
331 bool ProcessArgumentsObject();
333 void AssignDominators();
334 void RestoreActualValues();
336 // Returns false if there are phi-uses of the arguments-object
337 // which are not supported by the optimizing compiler.
338 bool CheckArgumentsPhiUses();
340 // Returns false if there are phi-uses of an uninitialized const
341 // which are not supported by the optimizing compiler.
342 bool CheckConstPhiUses();
346 HConstant* GetConstantUndefined();
347 HConstant* GetConstant0();
348 HConstant* GetConstant1();
349 HConstant* GetConstantMinus1();
350 HConstant* GetConstantTrue();
351 HConstant* GetConstantFalse();
352 HConstant* GetConstantHole();
353 HConstant* GetConstantNull();
354 HConstant* GetInvalidContext();
356 bool IsConstantUndefined(HConstant* constant);
357 bool IsConstant0(HConstant* constant);
358 bool IsConstant1(HConstant* constant);
359 bool IsConstantMinus1(HConstant* constant);
360 bool IsConstantTrue(HConstant* constant);
361 bool IsConstantFalse(HConstant* constant);
362 bool IsConstantHole(HConstant* constant);
363 bool IsConstantNull(HConstant* constant);
364 bool IsStandardConstant(HConstant* constant);
366 HBasicBlock* CreateBasicBlock();
367 HArgumentsObject* GetArgumentsObject() const {
368 return arguments_object_.get();
371 void SetArgumentsObject(HArgumentsObject* object) {
372 arguments_object_.set(object);
375 int GetMaximumValueID() const { return values_.length(); }
376 int GetNextBlockID() { return next_block_id_++; }
377 int GetNextValueID(HValue* value) {
378 ASSERT(!disallow_adding_new_values_);
379 values_.Add(value, zone());
380 return values_.length() - 1;
382 HValue* LookupValue(int id) const {
383 if (id >= 0 && id < values_.length()) return values_[id];
386 void DisallowAddingNewValues() {
387 disallow_adding_new_values_ = true;
390 bool Optimize(BailoutReason* bailout_reason);
393 void Verify(bool do_full_verify) const;
400 void set_osr(HOsrBuilder* osr) {
408 int update_type_change_checksum(int delta) {
409 type_change_checksum_ += delta;
410 return type_change_checksum_;
413 void update_maximum_environment_size(int environment_size) {
414 if (environment_size > maximum_environment_size_) {
415 maximum_environment_size_ = environment_size;
418 int maximum_environment_size() { return maximum_environment_size_; }
420 bool use_optimistic_licm() {
421 return use_optimistic_licm_;
424 void set_use_optimistic_licm(bool value) {
425 use_optimistic_licm_ = value;
428 void MarkRecursive() {
429 is_recursive_ = true;
432 bool is_recursive() const {
433 return is_recursive_;
436 void MarkDependsOnEmptyArrayProtoElements() {
437 // Add map dependency if not already added.
438 if (depends_on_empty_array_proto_elements_) return;
439 isolate()->initial_object_prototype()->map()->AddDependentCompilationInfo(
440 DependentCode::kElementsCantBeAddedGroup, info());
441 isolate()->initial_array_prototype()->map()->AddDependentCompilationInfo(
442 DependentCode::kElementsCantBeAddedGroup, info());
443 depends_on_empty_array_proto_elements_ = true;
446 bool depends_on_empty_array_proto_elements() {
447 return depends_on_empty_array_proto_elements_;
450 bool has_uint32_instructions() {
451 ASSERT(uint32_instructions_ == NULL || !uint32_instructions_->is_empty());
452 return uint32_instructions_ != NULL;
455 ZoneList<HInstruction*>* uint32_instructions() {
456 ASSERT(uint32_instructions_ == NULL || !uint32_instructions_->is_empty());
457 return uint32_instructions_;
460 void RecordUint32Instruction(HInstruction* instr) {
461 ASSERT(uint32_instructions_ == NULL || !uint32_instructions_->is_empty());
462 if (uint32_instructions_ == NULL) {
463 uint32_instructions_ = new(zone()) ZoneList<HInstruction*>(4, zone());
465 uint32_instructions_->Add(instr, zone());
468 void IncrementInNoSideEffectsScope() { no_side_effects_scope_count_++; }
469 void DecrementInNoSideEffectsScope() { no_side_effects_scope_count_--; }
470 bool IsInsideNoSideEffectsScope() { return no_side_effects_scope_count_ > 0; }
473 HConstant* ReinsertConstantIfNecessary(HConstant* constant);
474 HConstant* GetConstant(SetOncePointer<HConstant>* pointer,
475 int32_t integer_value);
477 template<class Phase>
483 void EliminateRedundantBoundsChecksUsingInductionVariables();
487 HBasicBlock* entry_block_;
488 HEnvironment* start_environment_;
489 ZoneList<HBasicBlock*> blocks_;
490 ZoneList<HValue*> values_;
491 ZoneList<HPhi*>* phi_list_;
492 ZoneList<HInstruction*>* uint32_instructions_;
493 SetOncePointer<HConstant> constant_undefined_;
494 SetOncePointer<HConstant> constant_0_;
495 SetOncePointer<HConstant> constant_1_;
496 SetOncePointer<HConstant> constant_minus1_;
497 SetOncePointer<HConstant> constant_true_;
498 SetOncePointer<HConstant> constant_false_;
499 SetOncePointer<HConstant> constant_the_hole_;
500 SetOncePointer<HConstant> constant_null_;
501 SetOncePointer<HConstant> constant_invalid_context_;
502 SetOncePointer<HArgumentsObject> arguments_object_;
506 CompilationInfo* info_;
510 bool use_optimistic_licm_;
511 bool depends_on_empty_array_proto_elements_;
512 int type_change_checksum_;
513 int maximum_environment_size_;
514 int no_side_effects_scope_count_;
515 bool disallow_adding_new_values_;
517 DISALLOW_COPY_AND_ASSIGN(HGraph);
521 Zone* HBasicBlock::zone() const { return graph_->zone(); }
524 // Type of stack frame an environment might refer to.
535 class HEnvironment V8_FINAL : public ZoneObject {
537 HEnvironment(HEnvironment* outer,
539 Handle<JSFunction> closure,
542 HEnvironment(Zone* zone, int parameter_count);
544 HEnvironment* arguments_environment() {
545 return outer()->frame_type() == ARGUMENTS_ADAPTOR ? outer() : this;
549 Handle<JSFunction> closure() const { return closure_; }
550 const ZoneList<HValue*>* values() const { return &values_; }
551 const GrowableBitVector* assigned_variables() const {
552 return &assigned_variables_;
554 FrameType frame_type() const { return frame_type_; }
555 int parameter_count() const { return parameter_count_; }
556 int specials_count() const { return specials_count_; }
557 int local_count() const { return local_count_; }
558 HEnvironment* outer() const { return outer_; }
559 int pop_count() const { return pop_count_; }
560 int push_count() const { return push_count_; }
562 BailoutId ast_id() const { return ast_id_; }
563 void set_ast_id(BailoutId id) { ast_id_ = id; }
565 HEnterInlined* entry() const { return entry_; }
566 void set_entry(HEnterInlined* entry) { entry_ = entry; }
568 int length() const { return values_.length(); }
570 int first_expression_index() const {
571 return parameter_count() + specials_count() + local_count();
574 int first_local_index() const {
575 return parameter_count() + specials_count();
578 void Bind(Variable* variable, HValue* value) {
579 Bind(IndexFor(variable), value);
582 void Bind(int index, HValue* value);
584 void BindContext(HValue* value) {
585 Bind(parameter_count(), value);
588 HValue* Lookup(Variable* variable) const {
589 return Lookup(IndexFor(variable));
592 HValue* Lookup(int index) const {
593 HValue* result = values_[index];
594 ASSERT(result != NULL);
598 HValue* context() const {
599 // Return first special.
600 return Lookup(parameter_count());
603 void Push(HValue* value) {
604 ASSERT(value != NULL);
606 values_.Add(value, zone());
610 ASSERT(!ExpressionStackIsEmpty());
611 if (push_count_ > 0) {
616 return values_.RemoveLast();
619 void Drop(int count);
621 HValue* Top() const { return ExpressionStackAt(0); }
623 bool ExpressionStackIsEmpty() const;
625 HValue* ExpressionStackAt(int index_from_top) const {
626 int index = length() - index_from_top - 1;
627 ASSERT(HasExpressionAt(index));
628 return values_[index];
631 void SetExpressionStackAt(int index_from_top, HValue* value);
633 HEnvironment* Copy() const;
634 HEnvironment* CopyWithoutHistory() const;
635 HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const;
637 // Create an "inlined version" of this environment, where the original
638 // environment is the outer environment but the top expression stack
639 // elements are moved to an inner environment as parameters.
640 HEnvironment* CopyForInlining(Handle<JSFunction> target,
642 FunctionLiteral* function,
643 HConstant* undefined,
644 InliningKind inlining_kind) const;
646 HEnvironment* DiscardInlined(bool drop_extra) {
647 HEnvironment* outer = outer_;
648 while (outer->frame_type() != JS_FUNCTION) outer = outer->outer_;
649 if (drop_extra) outer->Drop(1);
653 void AddIncomingEdge(HBasicBlock* block, HEnvironment* other);
655 void ClearHistory() {
658 assigned_variables_.Clear();
661 void SetValueAt(int index, HValue* value) {
662 ASSERT(index < length());
663 values_[index] = value;
666 // Map a variable to an environment index. Parameter indices are shifted
667 // by 1 (receiver is parameter index -1 but environment index 0).
668 // Stack-allocated local indices are shifted by the number of parameters.
669 int IndexFor(Variable* variable) const {
670 ASSERT(variable->IsStackAllocated());
671 int shift = variable->IsParameter()
673 : parameter_count_ + specials_count_;
674 return variable->index() + shift;
677 bool is_local_index(int i) const {
678 return i >= first_local_index() && i < first_expression_index();
681 bool is_parameter_index(int i) const {
682 return i >= 0 && i < parameter_count();
685 bool is_special_index(int i) const {
686 return i >= parameter_count() && i < parameter_count() + specials_count();
689 void PrintTo(StringStream* stream);
692 Zone* zone() const { return zone_; }
695 HEnvironment(const HEnvironment* other, Zone* zone);
697 HEnvironment(HEnvironment* outer,
698 Handle<JSFunction> closure,
699 FrameType frame_type,
703 // Create an artificial stub environment (e.g. for argument adaptor or
704 // constructor stub).
705 HEnvironment* CreateStubEnvironment(HEnvironment* outer,
706 Handle<JSFunction> target,
707 FrameType frame_type,
708 int arguments) const;
710 // True if index is included in the expression stack part of the environment.
711 bool HasExpressionAt(int index) const;
713 void Initialize(int parameter_count, int local_count, int stack_height);
714 void Initialize(const HEnvironment* other);
716 Handle<JSFunction> closure_;
717 // Value array [parameters] [specials] [locals] [temporaries].
718 ZoneList<HValue*> values_;
719 GrowableBitVector assigned_variables_;
720 FrameType frame_type_;
721 int parameter_count_;
724 HEnvironment* outer_;
725 HEnterInlined* entry_;
733 class HOptimizedGraphBuilder;
735 enum ArgumentsAllowedFlag {
736 ARGUMENTS_NOT_ALLOWED,
741 class HIfContinuation;
743 // This class is not BASE_EMBEDDED because our inlining implementation uses
747 bool IsEffect() const { return kind_ == Expression::kEffect; }
748 bool IsValue() const { return kind_ == Expression::kValue; }
749 bool IsTest() const { return kind_ == Expression::kTest; }
751 // 'Fill' this context with a hydrogen value. The value is assumed to
752 // have already been inserted in the instruction stream (or not need to
753 // be, e.g., HPhi). Call this function in tail position in the Visit
754 // functions for expressions.
755 virtual void ReturnValue(HValue* value) = 0;
757 // Add a hydrogen instruction to the instruction stream (recording an
758 // environment simulation if necessary) and then fill this context with
759 // the instruction as value.
760 virtual void ReturnInstruction(HInstruction* 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
766 virtual void ReturnControl(HControlInstruction* instr, BailoutId ast_id) = 0;
768 // Finishes the current basic block and materialize a boolean for
769 // value context, nothing for effect, generate a branch for test context.
770 // Call this function in tail position in the Visit functions for
771 // expressions that use an IfBuilder.
772 virtual void ReturnContinuation(HIfContinuation* continuation,
773 BailoutId ast_id) = 0;
775 void set_for_typeof(bool for_typeof) { for_typeof_ = for_typeof; }
776 bool is_for_typeof() { return for_typeof_; }
779 AstContext(HOptimizedGraphBuilder* owner, Expression::Context kind);
780 virtual ~AstContext();
782 HOptimizedGraphBuilder* owner() const { return owner_; }
784 inline Zone* zone() const;
786 // We want to be able to assert, in a context-specific way, that the stack
787 // height makes sense when the context is filled.
789 int original_length_;
793 HOptimizedGraphBuilder* owner_;
794 Expression::Context kind_;
800 class EffectContext V8_FINAL : public AstContext {
802 explicit EffectContext(HOptimizedGraphBuilder* owner)
803 : AstContext(owner, Expression::kEffect) {
805 virtual ~EffectContext();
807 virtual void ReturnValue(HValue* value) V8_OVERRIDE;
808 virtual void ReturnInstruction(HInstruction* instr,
809 BailoutId ast_id) V8_OVERRIDE;
810 virtual void ReturnControl(HControlInstruction* instr,
811 BailoutId ast_id) V8_OVERRIDE;
812 virtual void ReturnContinuation(HIfContinuation* continuation,
813 BailoutId ast_id) V8_OVERRIDE;
817 class ValueContext V8_FINAL : public AstContext {
819 ValueContext(HOptimizedGraphBuilder* owner, ArgumentsAllowedFlag flag)
820 : AstContext(owner, Expression::kValue), flag_(flag) {
822 virtual ~ValueContext();
824 virtual void ReturnValue(HValue* value) V8_OVERRIDE;
825 virtual void ReturnInstruction(HInstruction* instr,
826 BailoutId ast_id) V8_OVERRIDE;
827 virtual void ReturnControl(HControlInstruction* instr,
828 BailoutId ast_id) V8_OVERRIDE;
829 virtual void ReturnContinuation(HIfContinuation* continuation,
830 BailoutId ast_id) V8_OVERRIDE;
832 bool arguments_allowed() { return flag_ == ARGUMENTS_ALLOWED; }
835 ArgumentsAllowedFlag flag_;
839 class TestContext V8_FINAL : public AstContext {
841 TestContext(HOptimizedGraphBuilder* owner,
842 Expression* condition,
843 HBasicBlock* if_true,
844 HBasicBlock* if_false)
845 : AstContext(owner, Expression::kTest),
846 condition_(condition),
848 if_false_(if_false) {
851 virtual void ReturnValue(HValue* value) V8_OVERRIDE;
852 virtual void ReturnInstruction(HInstruction* instr,
853 BailoutId ast_id) V8_OVERRIDE;
854 virtual void ReturnControl(HControlInstruction* instr,
855 BailoutId ast_id) V8_OVERRIDE;
856 virtual void ReturnContinuation(HIfContinuation* continuation,
857 BailoutId ast_id) V8_OVERRIDE;
859 static TestContext* cast(AstContext* context) {
860 ASSERT(context->IsTest());
861 return reinterpret_cast<TestContext*>(context);
864 Expression* condition() const { return condition_; }
865 HBasicBlock* if_true() const { return if_true_; }
866 HBasicBlock* if_false() const { return if_false_; }
869 // Build the shared core part of the translation unpacking a value into
871 void BuildBranch(HValue* value);
873 Expression* condition_;
874 HBasicBlock* if_true_;
875 HBasicBlock* if_false_;
879 class FunctionState V8_FINAL {
881 FunctionState(HOptimizedGraphBuilder* owner,
882 CompilationInfo* info,
883 InliningKind inlining_kind);
886 CompilationInfo* compilation_info() { return compilation_info_; }
887 AstContext* call_context() { return call_context_; }
888 InliningKind inlining_kind() const { return inlining_kind_; }
889 HBasicBlock* function_return() { return function_return_; }
890 TestContext* test_context() { return test_context_; }
891 void ClearInlinedTestContext() {
892 delete test_context_;
893 test_context_ = NULL;
896 FunctionState* outer() { return outer_; }
898 HEnterInlined* entry() { return entry_; }
899 void set_entry(HEnterInlined* entry) { entry_ = entry; }
901 HArgumentsObject* arguments_object() { return arguments_object_; }
902 void set_arguments_object(HArgumentsObject* arguments_object) {
903 arguments_object_ = arguments_object;
906 HArgumentsElements* arguments_elements() { return arguments_elements_; }
907 void set_arguments_elements(HArgumentsElements* arguments_elements) {
908 arguments_elements_ = arguments_elements;
911 bool arguments_pushed() { return arguments_elements() != NULL; }
914 HOptimizedGraphBuilder* owner_;
916 CompilationInfo* compilation_info_;
918 // During function inlining, expression context of the call being
919 // inlined. NULL when not inlining.
920 AstContext* call_context_;
922 // The kind of call which is currently being inlined.
923 InliningKind inlining_kind_;
925 // When inlining in an effect or value context, this is the return block.
926 // It is NULL otherwise. When inlining in a test context, there are a
927 // pair of return blocks in the context. When not inlining, there is no
928 // local return point.
929 HBasicBlock* function_return_;
931 // When inlining a call in a test context, a context containing a pair of
932 // return blocks. NULL in all other cases.
933 TestContext* test_context_;
935 // When inlining HEnterInlined instruction corresponding to the function
937 HEnterInlined* entry_;
939 HArgumentsObject* arguments_object_;
940 HArgumentsElements* arguments_elements_;
942 FunctionState* outer_;
946 class HIfContinuation V8_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() { ASSERT(!continuation_captured_); }
958 void Capture(HBasicBlock* true_branch,
959 HBasicBlock* false_branch) {
960 ASSERT(!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 ASSERT(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 V8_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 HValue* current_site() const { return current_site_; }
1001 Handle<AllocationSite> feedback_site() const { return feedback_site_; }
1003 bool CreateAllocationMementos() const V8_WARN_UNUSED_RESULT {
1004 return current_site() != NULL;
1007 PretenureFlag GetPretenureMode() const V8_WARN_UNUSED_RESULT {
1008 if (!feedback_site().is_null()) return feedback_site()->GetPretenureMode();
1009 return pretenure_flag_;
1013 HValue* current_site_;
1014 Handle<AllocationSite> feedback_site_;
1015 PretenureFlag pretenure_flag_;
1019 class HGraphBuilder {
1021 explicit HGraphBuilder(CompilationInfo* info)
1024 current_block_(NULL),
1025 position_(RelocInfo::kNoPosition) {}
1026 virtual ~HGraphBuilder() {}
1028 HBasicBlock* current_block() const { return current_block_; }
1029 void set_current_block(HBasicBlock* block) { current_block_ = block; }
1030 HEnvironment* environment() const {
1031 return current_block()->last_environment();
1033 Zone* zone() const { return info_->zone(); }
1034 HGraph* graph() const { return graph_; }
1035 Isolate* isolate() const { return graph_->isolate(); }
1036 CompilationInfo* top_info() { return info_; }
1038 HGraph* CreateGraph();
1040 // Bailout environment manipulation.
1041 void Push(HValue* value) { environment()->Push(value); }
1042 HValue* Pop() { return environment()->Pop(); }
1044 virtual HValue* context() = 0;
1046 // Adding instructions.
1047 HInstruction* AddInstruction(HInstruction* instr);
1048 void FinishCurrentBlock(HControlInstruction* last);
1049 void FinishExitCurrentBlock(HControlInstruction* instruction);
1051 void Goto(HBasicBlock* from,
1052 HBasicBlock* target,
1053 FunctionState* state = NULL,
1054 bool add_simulate = true) {
1055 from->Goto(target, position_, state, add_simulate);
1057 void Goto(HBasicBlock* target,
1058 FunctionState* state = NULL,
1059 bool add_simulate = true) {
1060 Goto(current_block(), target, state, add_simulate);
1062 void GotoNoSimulate(HBasicBlock* from, HBasicBlock* target) {
1063 Goto(from, target, NULL, false);
1065 void GotoNoSimulate(HBasicBlock* target) {
1066 Goto(target, NULL, false);
1068 void AddLeaveInlined(HBasicBlock* block,
1069 HValue* return_value,
1070 FunctionState* state) {
1071 block->AddLeaveInlined(return_value, state, position_);
1073 void AddLeaveInlined(HValue* return_value, FunctionState* state) {
1074 return AddLeaveInlined(current_block(), return_value, state);
1078 HInstruction* NewUncasted() { return I::New(zone(), context()); }
1081 I* New() { return I::New(zone(), context()); }
1084 HInstruction* AddUncasted() { return AddInstruction(NewUncasted<I>());}
1087 I* Add() { return AddInstructionTyped(New<I>());}
1089 template<class I, class P1>
1090 HInstruction* NewUncasted(P1 p1) {
1091 return I::New(zone(), context(), p1);
1094 template<class I, class P1>
1095 I* New(P1 p1) { return I::New(zone(), context(), p1); }
1097 template<class I, class P1>
1098 HInstruction* AddUncasted(P1 p1) {
1099 HInstruction* result = AddInstruction(NewUncasted<I>(p1));
1100 // Specializations must have their parameters properly casted
1101 // to avoid landing here.
1102 ASSERT(!result->IsReturn() && !result->IsSimulate() &&
1103 !result->IsDeoptimize());
1107 template<class I, class P1>
1109 I* result = AddInstructionTyped(New<I>(p1));
1110 // Specializations must have their parameters properly casted
1111 // to avoid landing here.
1112 ASSERT(!result->IsReturn() && !result->IsSimulate() &&
1113 !result->IsDeoptimize());
1117 template<class I, class P1, class P2>
1118 HInstruction* NewUncasted(P1 p1, P2 p2) {
1119 return I::New(zone(), context(), p1, p2);
1122 template<class I, class P1, class P2>
1123 I* New(P1 p1, P2 p2) {
1124 return I::New(zone(), context(), p1, p2);
1127 template<class I, class P1, class P2>
1128 HInstruction* AddUncasted(P1 p1, P2 p2) {
1129 HInstruction* result = AddInstruction(NewUncasted<I>(p1, p2));
1130 // Specializations must have their parameters properly casted
1131 // to avoid landing here.
1132 ASSERT(!result->IsSimulate());
1136 template<class I, class P1, class P2>
1137 I* Add(P1 p1, P2 p2) {
1138 I* result = AddInstructionTyped(New<I>(p1, p2));
1139 // Specializations must have their parameters properly casted
1140 // to avoid landing here.
1141 ASSERT(!result->IsSimulate());
1145 template<class I, class P1, class P2, class P3>
1146 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3) {
1147 return I::New(zone(), context(), p1, p2, p3);
1150 template<class I, class P1, class P2, class P3>
1151 I* New(P1 p1, P2 p2, P3 p3) {
1152 return I::New(zone(), context(), p1, p2, p3);
1155 template<class I, class P1, class P2, class P3>
1156 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3) {
1157 return AddInstruction(NewUncasted<I>(p1, p2, p3));
1160 template<class I, class P1, class P2, class P3>
1161 I* Add(P1 p1, P2 p2, P3 p3) {
1162 return AddInstructionTyped(New<I>(p1, p2, p3));
1165 template<class I, class P1, class P2, class P3, class P4>
1166 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4) {
1167 return I::New(zone(), context(), p1, p2, p3, p4);
1170 template<class I, class P1, class P2, class P3, class P4>
1171 I* New(P1 p1, P2 p2, P3 p3, P4 p4) {
1172 return I::New(zone(), context(), p1, p2, p3, p4);
1175 template<class I, class P1, class P2, class P3, class P4>
1176 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4) {
1177 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4));
1180 template<class I, class P1, class P2, class P3, class P4>
1181 I* Add(P1 p1, P2 p2, P3 p3, P4 p4) {
1182 return AddInstructionTyped(New<I>(p1, p2, p3, p4));
1185 template<class I, class P1, class P2, class P3, class P4, class P5>
1186 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
1187 return I::New(zone(), context(), p1, p2, p3, p4, p5);
1190 template<class I, class P1, class P2, class P3, class P4, class P5>
1191 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
1192 return I::New(zone(), context(), p1, p2, p3, p4, p5);
1195 template<class I, class P1, class P2, class P3, class P4, class P5>
1196 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
1197 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5));
1200 template<class I, class P1, class P2, class P3, class P4, class P5>
1201 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
1202 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5));
1205 template<class I, class P1, class P2, class P3, class P4, class P5, class P6>
1206 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {
1207 return I::New(zone(), context(), p1, p2, p3, p4, p5, p6);
1210 template<class I, class P1, class P2, class P3, class P4, class P5, class P6>
1211 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {
1212 return I::New(zone(), context(), p1, p2, p3, p4, p5, p6);
1215 template<class I, class P1, class P2, class P3, class P4, class P5, class P6>
1216 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {
1217 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6));
1220 template<class I, class P1, class P2, class P3, class P4, class P5, class P6>
1221 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {
1222 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5, p6));
1225 template<class I, class P1, class P2, class P3, class P4,
1226 class P5, class P6, class P7>
1227 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
1228 return I::New(zone(), context(), p1, p2, p3, p4, p5, p6, p7);
1231 template<class I, class P1, class P2, class P3, class P4,
1232 class P5, class P6, class P7>
1233 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
1234 return I::New(zone(), context(), p1, p2, p3, p4, p5, p6, p7);
1237 template<class I, class P1, class P2, class P3,
1238 class P4, class P5, class P6, class P7>
1239 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
1240 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6, p7));
1243 template<class I, class P1, class P2, class P3,
1244 class P4, class P5, class P6, class P7>
1245 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {
1246 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5, p6, p7));
1249 template<class I, class P1, class P2, class P3, class P4,
1250 class P5, class P6, class P7, class P8>
1251 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4,
1252 P5 p5, P6 p6, P7 p7, P8 p8) {
1253 return I::New(zone(), context(), p1, p2, p3, p4, p5, p6, p7, p8);
1256 template<class I, class P1, class P2, class P3, class P4,
1257 class P5, class P6, class P7, class P8>
1258 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) {
1259 return I::New(zone(), context(), p1, p2, p3, p4, p5, p6, p7, p8);
1262 template<class I, class P1, class P2, class P3, class P4,
1263 class P5, class P6, class P7, class P8>
1264 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4,
1265 P5 p5, P6 p6, P7 p7, P8 p8) {
1266 return AddInstruction(NewUncasted<I>(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* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) {
1272 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5, p6, p7, p8));
1275 void AddSimulate(BailoutId id, RemovableSimulate removable = FIXED_SIMULATE);
1277 int position() const { return position_; }
1280 virtual bool BuildGraph() = 0;
1282 HBasicBlock* CreateBasicBlock(HEnvironment* env);
1283 HBasicBlock* CreateLoopHeaderBlock();
1285 HValue* BuildCheckHeapObject(HValue* object);
1286 HValue* BuildCheckMap(HValue* obj, Handle<Map> map);
1287 HValue* BuildCheckString(HValue* string);
1288 HValue* BuildWrapReceiver(HValue* object, HValue* function);
1290 // Building common constructs
1291 HValue* BuildCheckForCapacityGrow(HValue* object,
1299 HValue* BuildCopyElementsOnWrite(HValue* object,
1304 void BuildTransitionElementsKind(HValue* object,
1306 ElementsKind from_kind,
1307 ElementsKind to_kind,
1310 HValue* BuildNumberToString(HValue* object, Type* type);
1312 HValue* BuildUncheckedDictionaryElementLoad(HValue* receiver,
1315 HValue* BuildRegExpConstructResult(HValue* length,
1319 // Allocates a new object according with the given allocation properties.
1320 HAllocate* BuildAllocate(HValue* object_size,
1322 InstanceType instance_type,
1323 HAllocationMode allocation_mode);
1324 // Computes the sum of two string lengths, taking care of overflow handling.
1325 HValue* BuildAddStringLengths(HValue* left_length, HValue* right_length);
1326 // Creates a cons string using the two input strings.
1327 HValue* BuildCreateConsString(HValue* length,
1330 HAllocationMode allocation_mode);
1331 // Copies characters from one sequential string to another.
1332 void BuildCopySeqStringChars(HValue* src,
1334 String::Encoding src_encoding,
1337 String::Encoding dst_encoding,
1339 // Both operands are non-empty strings.
1340 HValue* BuildUncheckedStringAdd(HValue* left,
1342 HAllocationMode allocation_mode);
1343 // Add two strings using allocation mode, validating type feedback.
1344 HValue* BuildStringAdd(HValue* left,
1346 HAllocationMode allocation_mode);
1348 HInstruction* BuildUncheckedMonomorphicElementAccess(
1349 HValue* checked_object,
1353 ElementsKind elements_kind,
1355 LoadKeyedHoleMode load_mode,
1356 KeyedAccessStoreMode store_mode);
1358 HInstruction* AddElementAccess(
1360 HValue* checked_key,
1363 ElementsKind elements_kind,
1365 LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE);
1367 HLoadNamedField* BuildLoadNamedField(HValue* object, HObjectAccess access);
1368 HInstruction* AddLoadNamedField(HValue* object, HObjectAccess access);
1369 HInstruction* AddLoadStringInstanceType(HValue* string);
1370 HInstruction* AddLoadStringLength(HValue* string);
1371 HStoreNamedField* AddStoreMapNoWriteBarrier(HValue* object, HValue* map) {
1372 HStoreNamedField* store_map = Add<HStoreNamedField>(
1373 object, HObjectAccess::ForMap(), map);
1374 store_map->SkipWriteBarrier();
1377 HStoreNamedField* AddStoreMapConstant(HValue* object, Handle<Map> map);
1378 HStoreNamedField* AddStoreMapConstantNoWriteBarrier(HValue* object,
1380 HStoreNamedField* store_map = AddStoreMapConstant(object, map);
1381 store_map->SkipWriteBarrier();
1384 HLoadNamedField* AddLoadElements(HValue* object);
1386 bool MatchRotateRight(HValue* left,
1389 HValue** shift_amount);
1391 HValue* BuildBinaryOperation(Token::Value op,
1397 Maybe<int> fixed_right_arg,
1398 HAllocationMode allocation_mode);
1400 HLoadNamedField* AddLoadFixedArrayLength(HValue *object);
1402 HValue* AddLoadJSBuiltin(Builtins::JavaScript builtin);
1404 HValue* EnforceNumberType(HValue* number, Type* expected);
1405 HValue* TruncateToNumber(HValue* value, Type** expected);
1407 void FinishExitWithHardDeoptimization(const char* reason,
1408 HBasicBlock* continuation);
1410 void AddIncrementCounter(StatsCounter* counter);
1412 class IfBuilder V8_FINAL {
1414 explicit IfBuilder(HGraphBuilder* builder);
1415 IfBuilder(HGraphBuilder* builder,
1416 HIfContinuation* continuation);
1419 if (!finished_) End();
1422 template<class Condition>
1423 Condition* If(HValue *p) {
1424 Condition* compare = builder()->New<Condition>(p);
1425 AddCompare(compare);
1429 template<class Condition, class P2>
1430 Condition* If(HValue* p1, P2 p2) {
1431 Condition* compare = builder()->New<Condition>(p1, p2);
1432 AddCompare(compare);
1436 template<class Condition, class P2, class P3>
1437 Condition* If(HValue* p1, P2 p2, P3 p3) {
1438 Condition* compare = builder()->New<Condition>(p1, p2, p3);
1439 AddCompare(compare);
1443 template<class Condition>
1444 Condition* IfNot(HValue* p) {
1445 Condition* compare = If<Condition>(p);
1450 template<class Condition, class P2>
1451 Condition* IfNot(HValue* p1, P2 p2) {
1452 Condition* compare = If<Condition>(p1, p2);
1457 template<class Condition, class P2, class P3>
1458 Condition* IfNot(HValue* p1, P2 p2, P3 p3) {
1459 Condition* compare = If<Condition>(p1, p2, p3);
1464 template<class Condition>
1465 Condition* OrIf(HValue *p) {
1467 return If<Condition>(p);
1470 template<class Condition, class P2>
1471 Condition* OrIf(HValue* p1, P2 p2) {
1473 return If<Condition>(p1, p2);
1476 template<class Condition, class P2, class P3>
1477 Condition* OrIf(HValue* p1, P2 p2, P3 p3) {
1479 return If<Condition>(p1, p2, p3);
1482 template<class Condition>
1483 Condition* AndIf(HValue *p) {
1485 return If<Condition>(p);
1488 template<class Condition, class P2>
1489 Condition* AndIf(HValue* p1, P2 p2) {
1491 return If<Condition>(p1, p2);
1494 template<class Condition, class P2, class P3>
1495 Condition* AndIf(HValue* p1, P2 p2, P3 p3) {
1497 return If<Condition>(p1, p2, p3);
1503 // Captures the current state of this IfBuilder in the specified
1504 // continuation and ends this IfBuilder.
1505 void CaptureContinuation(HIfContinuation* continuation);
1507 // Joins the specified continuation from this IfBuilder and ends this
1508 // IfBuilder. This appends a Goto instruction from the true branch of
1509 // this IfBuilder to the true branch of the continuation unless the
1510 // true branch of this IfBuilder is already finished. And vice versa
1511 // for the false branch.
1513 // The basic idea is as follows: You have several nested IfBuilder's
1514 // that you want to join based on two possible outcomes (i.e. success
1515 // and failure, or whatever). You can do this easily using this method
1516 // now, for example:
1518 // HIfContinuation cont(graph()->CreateBasicBlock(),
1519 // graph()->CreateBasicBlock());
1521 // IfBuilder if_whatever(this);
1522 // if_whatever.If<Condition>(arg);
1523 // if_whatever.Then();
1525 // if_whatever.Else();
1527 // if_whatever.JoinContinuation(&cont);
1529 // IfBuilder if_something(this);
1530 // if_something.If<Condition>(arg1, arg2);
1531 // if_something.Then();
1533 // if_something.Else();
1535 // if_something.JoinContinuation(&cont);
1537 // IfBuilder if_finally(this, &cont);
1538 // if_finally.Then();
1539 // // continues after then code of if_whatever or if_something.
1541 // if_finally.Else();
1542 // // continues after else code of if_whatever or if_something.
1544 // if_finally.End();
1545 void JoinContinuation(HIfContinuation* continuation);
1551 void Deopt(const char* reason);
1552 void ThenDeopt(const char* reason) {
1556 void ElseDeopt(const char* reason) {
1561 void Return(HValue* value);
1564 HControlInstruction* AddCompare(HControlInstruction* compare);
1566 HGraphBuilder* builder() const { return builder_; }
1568 void AddMergeAtJoinBlock(bool deopt);
1571 void Finish(HBasicBlock** then_continuation,
1572 HBasicBlock** else_continuation);
1574 class MergeAtJoinBlock : public ZoneObject {
1576 MergeAtJoinBlock(HBasicBlock* block,
1578 MergeAtJoinBlock* next)
1582 HBasicBlock* block_;
1584 MergeAtJoinBlock* next_;
1587 HGraphBuilder* builder_;
1591 bool did_else_if_ : 1;
1595 bool needs_compare_ : 1;
1596 bool pending_merge_block_ : 1;
1597 HBasicBlock* first_true_block_;
1598 HBasicBlock* first_false_block_;
1599 HBasicBlock* split_edge_merge_block_;
1600 MergeAtJoinBlock* merge_at_join_blocks_;
1601 int normal_merge_at_join_block_count_;
1602 int deopt_merge_at_join_block_count_;
1605 class LoopBuilder V8_FINAL {
1614 LoopBuilder(HGraphBuilder* builder,
1616 Direction direction);
1617 LoopBuilder(HGraphBuilder* builder,
1619 Direction direction,
1620 HValue* increment_amount);
1628 HValue* terminating,
1629 Token::Value token);
1636 Zone* zone() { return builder_->zone(); }
1638 HGraphBuilder* builder_;
1640 HValue* increment_amount_;
1641 HInstruction* increment_;
1643 HBasicBlock* header_block_;
1644 HBasicBlock* body_block_;
1645 HBasicBlock* exit_block_;
1646 HBasicBlock* exit_trampoline_block_;
1647 Direction direction_;
1651 HValue* BuildNewElementsCapacity(HValue* old_capacity);
1653 void BuildNewSpaceArrayCheck(HValue* length,
1656 class JSArrayBuilder V8_FINAL {
1658 JSArrayBuilder(HGraphBuilder* builder,
1660 HValue* allocation_site_payload,
1661 HValue* constructor_function,
1662 AllocationSiteOverrideMode override_mode);
1664 JSArrayBuilder(HGraphBuilder* builder,
1666 HValue* constructor_function = NULL);
1669 DONT_FILL_WITH_HOLE,
1673 ElementsKind kind() { return kind_; }
1675 HValue* AllocateEmptyArray();
1676 HValue* AllocateArray(HValue* capacity, HValue* length_field,
1677 FillMode fill_mode = FILL_WITH_HOLE);
1678 HValue* GetElementsLocation() { return elements_location_; }
1679 HValue* EmitMapCode();
1682 Zone* zone() const { return builder_->zone(); }
1683 int elements_size() const {
1684 return IsFastDoubleElementsKind(kind_) ? kDoubleSize : kPointerSize;
1686 HGraphBuilder* builder() { return builder_; }
1687 HGraph* graph() { return builder_->graph(); }
1688 int initial_capacity() {
1689 STATIC_ASSERT(JSArray::kPreallocatedArrayElements > 0);
1690 return JSArray::kPreallocatedArrayElements;
1693 HValue* EmitInternalMapCode();
1694 HValue* EstablishEmptyArrayAllocationSize();
1695 HValue* EstablishAllocationSize(HValue* length_node);
1696 HValue* AllocateArray(HValue* size_in_bytes, HValue* capacity,
1697 HValue* length_field,
1698 FillMode fill_mode = FILL_WITH_HOLE);
1700 HGraphBuilder* builder_;
1702 AllocationSiteMode mode_;
1703 HValue* allocation_site_payload_;
1704 HValue* constructor_function_;
1705 HInnerAllocatedObject* elements_location_;
1708 HValue* BuildAllocateArrayFromLength(JSArrayBuilder* array_builder,
1709 HValue* length_argument);
1711 HValue* BuildAllocateElements(ElementsKind kind,
1714 void BuildInitializeElementsHeader(HValue* elements,
1718 HValue* BuildAllocateElementsAndInitializeElementsHeader(ElementsKind kind,
1721 // array must have been allocated with enough room for
1722 // 1) the JSArray, 2) a AllocationMemento if mode requires it,
1723 // 3) a FixedArray or FixedDoubleArray.
1724 // A pointer to the Fixed(Double)Array is returned.
1725 HInnerAllocatedObject* BuildJSArrayHeader(HValue* array,
1727 AllocationSiteMode mode,
1728 ElementsKind elements_kind,
1729 HValue* allocation_site_payload,
1730 HValue* length_field);
1732 HValue* BuildGrowElementsCapacity(HValue* object,
1735 ElementsKind new_kind,
1737 HValue* new_capacity);
1739 void BuildFillElementsWithHole(HValue* elements,
1740 ElementsKind elements_kind,
1744 void BuildCopyElements(HValue* from_elements,
1745 ElementsKind from_elements_kind,
1746 HValue* to_elements,
1747 ElementsKind to_elements_kind,
1751 HValue* BuildCloneShallowArray(HValue* boilerplate,
1752 HValue* allocation_site,
1753 AllocationSiteMode mode,
1757 HValue* BuildElementIndexHash(HValue* index);
1759 void BuildCompareNil(
1762 HIfContinuation* continuation);
1764 void BuildCreateAllocationMemento(HValue* previous_object,
1765 HValue* previous_object_size,
1768 HInstruction* BuildConstantMapCheck(Handle<JSObject> constant,
1769 CompilationInfo* info);
1770 HInstruction* BuildCheckPrototypeMaps(Handle<JSObject> prototype,
1771 Handle<JSObject> holder);
1773 HInstruction* BuildGetNativeContext(HValue* closure);
1774 HInstruction* BuildGetNativeContext();
1775 HInstruction* BuildGetArrayFunction();
1778 void SetSourcePosition(int position) {
1779 ASSERT(position != RelocInfo::kNoPosition);
1780 position_ = position;
1783 template <typename ViewClass>
1784 void BuildArrayBufferViewInitialization(HValue* obj,
1786 HValue* byte_offset,
1787 HValue* byte_length);
1792 HValue* BuildUncheckedDictionaryElementLoadHelper(
1799 void PadEnvironmentForContinuation(HBasicBlock* from,
1800 HBasicBlock* continuation);
1803 I* AddInstructionTyped(I* instr) {
1804 return I::cast(AddInstruction(instr));
1807 CompilationInfo* info_;
1809 HBasicBlock* current_block_;
1815 inline HDeoptimize* HGraphBuilder::Add<HDeoptimize>(
1816 const char* reason, Deoptimizer::BailoutType type) {
1817 if (type == Deoptimizer::SOFT) {
1818 isolate()->counters()->soft_deopts_requested()->Increment();
1819 if (FLAG_always_opt) return NULL;
1821 if (current_block()->IsDeoptimizing()) return NULL;
1822 HBasicBlock* after_deopt_block = CreateBasicBlock(
1823 current_block()->last_environment());
1824 HDeoptimize* instr = New<HDeoptimize>(reason, type, after_deopt_block);
1825 if (type == Deoptimizer::SOFT) {
1826 isolate()->counters()->soft_deopts_inserted()->Increment();
1828 FinishCurrentBlock(instr);
1829 set_current_block(after_deopt_block);
1835 inline HInstruction* HGraphBuilder::AddUncasted<HDeoptimize>(
1836 const char* reason, Deoptimizer::BailoutType type) {
1837 return Add<HDeoptimize>(reason, type);
1842 inline HSimulate* HGraphBuilder::Add<HSimulate>(
1844 RemovableSimulate removable) {
1845 HSimulate* instr = current_block()->CreateSimulate(id, removable);
1846 AddInstruction(instr);
1852 inline HSimulate* HGraphBuilder::Add<HSimulate>(
1854 return Add<HSimulate>(id, FIXED_SIMULATE);
1859 inline HInstruction* HGraphBuilder::AddUncasted<HSimulate>(BailoutId id) {
1860 return Add<HSimulate>(id, FIXED_SIMULATE);
1865 inline HReturn* HGraphBuilder::Add<HReturn>(HValue* value) {
1866 int num_parameters = graph()->info()->num_parameters();
1867 HValue* params = AddUncasted<HConstant>(num_parameters);
1868 HReturn* return_instruction = New<HReturn>(value, params);
1869 FinishExitCurrentBlock(return_instruction);
1870 return return_instruction;
1875 inline HReturn* HGraphBuilder::Add<HReturn>(HConstant* value) {
1876 return Add<HReturn>(static_cast<HValue*>(value));
1880 inline HInstruction* HGraphBuilder::AddUncasted<HReturn>(HValue* value) {
1881 return Add<HReturn>(value);
1886 inline HInstruction* HGraphBuilder::AddUncasted<HReturn>(HConstant* value) {
1887 return Add<HReturn>(value);
1892 inline HCallRuntime* HGraphBuilder::Add<HCallRuntime>(
1893 Handle<String> name,
1894 const Runtime::Function* c_function,
1895 int argument_count) {
1896 HCallRuntime* instr = New<HCallRuntime>(name, c_function, argument_count);
1897 if (graph()->info()->IsStub()) {
1898 // When compiling code stubs, we don't want to save all double registers
1899 // upon entry to the stub, but instead have the call runtime instruction
1900 // save the double registers only on-demand (in the fallback case).
1901 instr->set_save_doubles(kSaveFPRegs);
1903 AddInstruction(instr);
1909 inline HInstruction* HGraphBuilder::AddUncasted<HCallRuntime>(
1910 Handle<String> name,
1911 const Runtime::Function* c_function,
1912 int argument_count) {
1913 return Add<HCallRuntime>(name, c_function, argument_count);
1918 inline HContext* HGraphBuilder::New<HContext>() {
1919 return HContext::New(zone());
1924 inline HInstruction* HGraphBuilder::NewUncasted<HContext>() {
1925 return New<HContext>();
1928 class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
1930 // A class encapsulating (lazily-allocated) break and continue blocks for
1931 // a breakable statement. Separated from BreakAndContinueScope so that it
1932 // can have a separate lifetime.
1933 class BreakAndContinueInfo V8_FINAL BASE_EMBEDDED {
1935 explicit BreakAndContinueInfo(BreakableStatement* target,
1939 continue_block_(NULL),
1940 drop_extra_(drop_extra) {
1943 BreakableStatement* target() { return target_; }
1944 HBasicBlock* break_block() { return break_block_; }
1945 void set_break_block(HBasicBlock* block) { break_block_ = block; }
1946 HBasicBlock* continue_block() { return continue_block_; }
1947 void set_continue_block(HBasicBlock* block) { continue_block_ = block; }
1948 int drop_extra() { return drop_extra_; }
1951 BreakableStatement* target_;
1952 HBasicBlock* break_block_;
1953 HBasicBlock* continue_block_;
1957 // A helper class to maintain a stack of current BreakAndContinueInfo
1958 // structures mirroring BreakableStatement nesting.
1959 class BreakAndContinueScope V8_FINAL BASE_EMBEDDED {
1961 BreakAndContinueScope(BreakAndContinueInfo* info,
1962 HOptimizedGraphBuilder* owner)
1963 : info_(info), owner_(owner), next_(owner->break_scope()) {
1964 owner->set_break_scope(this);
1967 ~BreakAndContinueScope() { owner_->set_break_scope(next_); }
1969 BreakAndContinueInfo* info() { return info_; }
1970 HOptimizedGraphBuilder* owner() { return owner_; }
1971 BreakAndContinueScope* next() { return next_; }
1973 // Search the break stack for a break or continue target.
1974 enum BreakType { BREAK, CONTINUE };
1975 HBasicBlock* Get(BreakableStatement* stmt, BreakType type, int* drop_extra);
1978 BreakAndContinueInfo* info_;
1979 HOptimizedGraphBuilder* owner_;
1980 BreakAndContinueScope* next_;
1983 explicit HOptimizedGraphBuilder(CompilationInfo* info);
1985 virtual bool BuildGraph() V8_OVERRIDE;
1987 // Simple accessors.
1988 BreakAndContinueScope* break_scope() const { return break_scope_; }
1989 void set_break_scope(BreakAndContinueScope* head) { break_scope_ = head; }
1991 bool inline_bailout() { return inline_bailout_; }
1993 HValue* context() { return environment()->context(); }
1995 HOsrBuilder* osr() const { return osr_; }
1997 void Bailout(BailoutReason reason);
1999 HBasicBlock* CreateJoin(HBasicBlock* first,
2000 HBasicBlock* second,
2003 FunctionState* function_state() const { return function_state_; }
2005 void VisitDeclarations(ZoneList<Declaration*>* declarations);
2007 void* operator new(size_t size, Zone* zone) {
2008 return zone->New(static_cast<int>(size));
2010 void operator delete(void* pointer, Zone* zone) { }
2011 void operator delete(void* pointer) { }
2013 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
2016 // Type of a member function that generates inline code for a native function.
2017 typedef void (HOptimizedGraphBuilder::*InlineFunctionGenerator)
2018 (CallRuntime* call);
2020 // Forward declarations for inner scope classes.
2021 class SubgraphScope;
2023 static const InlineFunctionGenerator kInlineFunctionGenerators[];
2025 static const int kMaxCallPolymorphism = 4;
2026 static const int kMaxLoadPolymorphism = 4;
2027 static const int kMaxStorePolymorphism = 4;
2029 // Even in the 'unlimited' case we have to have some limit in order not to
2030 // overflow the stack.
2031 static const int kUnlimitedMaxInlinedSourceSize = 100000;
2032 static const int kUnlimitedMaxInlinedNodes = 10000;
2033 static const int kUnlimitedMaxInlinedNodesCumulative = 10000;
2035 // Maximum depth and total number of elements and properties for literal
2036 // graphs to be considered for fast deep-copying.
2037 static const int kMaxFastLiteralDepth = 3;
2038 static const int kMaxFastLiteralProperties = 8;
2040 // Simple accessors.
2041 void set_function_state(FunctionState* state) { function_state_ = state; }
2043 AstContext* ast_context() const { return ast_context_; }
2044 void set_ast_context(AstContext* context) { ast_context_ = context; }
2046 // Accessors forwarded to the function state.
2047 CompilationInfo* current_info() const {
2048 return function_state()->compilation_info();
2050 AstContext* call_context() const {
2051 return function_state()->call_context();
2053 HBasicBlock* function_return() const {
2054 return function_state()->function_return();
2056 TestContext* inlined_test_context() const {
2057 return function_state()->test_context();
2059 void ClearInlinedTestContext() {
2060 function_state()->ClearInlinedTestContext();
2062 StrictModeFlag function_strict_mode_flag() {
2063 return function_state()->compilation_info()->is_classic_mode()
2064 ? kNonStrictMode : kStrictMode;
2067 // Generators for inline runtime functions.
2068 #define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \
2069 void Generate##Name(CallRuntime* call);
2071 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
2072 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
2073 #undef INLINE_FUNCTION_GENERATOR_DECLARATION
2075 void VisitDelete(UnaryOperation* expr);
2076 void VisitVoid(UnaryOperation* expr);
2077 void VisitTypeof(UnaryOperation* expr);
2078 void VisitNot(UnaryOperation* expr);
2080 void VisitComma(BinaryOperation* expr);
2081 void VisitLogicalExpression(BinaryOperation* expr);
2082 void VisitArithmeticExpression(BinaryOperation* expr);
2084 bool PreProcessOsrEntry(IterationStatement* statement);
2085 void VisitLoopBody(IterationStatement* stmt,
2086 HBasicBlock* loop_entry,
2087 BreakAndContinueInfo* break_info);
2089 // Create a back edge in the flow graph. body_exit is the predecessor
2090 // block and loop_entry is the successor block. loop_successor is the
2091 // block where control flow exits the loop normally (e.g., via failure of
2092 // the condition) and break_block is the block where control flow breaks
2093 // from the loop. All blocks except loop_entry can be NULL. The return
2094 // value is the new successor block which is the join of loop_successor
2095 // and break_block, or NULL.
2096 HBasicBlock* CreateLoop(IterationStatement* statement,
2097 HBasicBlock* loop_entry,
2098 HBasicBlock* body_exit,
2099 HBasicBlock* loop_successor,
2100 HBasicBlock* break_block);
2102 // Build a loop entry
2103 HBasicBlock* BuildLoopEntry();
2105 // Builds a loop entry respectful of OSR requirements
2106 HBasicBlock* BuildLoopEntry(IterationStatement* statement);
2108 HBasicBlock* JoinContinue(IterationStatement* statement,
2109 HBasicBlock* exit_block,
2110 HBasicBlock* continue_block);
2112 HValue* Top() const { return environment()->Top(); }
2113 void Drop(int n) { environment()->Drop(n); }
2114 void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); }
2115 bool IsEligibleForEnvironmentLivenessAnalysis(Variable* var,
2118 HEnvironment* env) {
2119 if (!FLAG_analyze_environment_liveness) return false;
2120 // |this| and |arguments| are always live; zapping parameters isn't
2121 // safe because function.arguments can inspect them at any time.
2122 return !var->is_this() &&
2123 !var->is_arguments() &&
2124 !value->IsArgumentsObject() &&
2125 env->is_local_index(index);
2127 void BindIfLive(Variable* var, HValue* value) {
2128 HEnvironment* env = environment();
2129 int index = env->IndexFor(var);
2130 env->Bind(index, value);
2131 if (IsEligibleForEnvironmentLivenessAnalysis(var, index, value, env)) {
2132 HEnvironmentMarker* bind =
2133 Add<HEnvironmentMarker>(HEnvironmentMarker::BIND, index);
2136 bind->set_closure(env->closure());
2141 HValue* LookupAndMakeLive(Variable* var) {
2142 HEnvironment* env = environment();
2143 int index = env->IndexFor(var);
2144 HValue* value = env->Lookup(index);
2145 if (IsEligibleForEnvironmentLivenessAnalysis(var, index, value, env)) {
2146 HEnvironmentMarker* lookup =
2147 Add<HEnvironmentMarker>(HEnvironmentMarker::LOOKUP, index);
2150 lookup->set_closure(env->closure());
2156 // The value of the arguments object is allowed in some but not most value
2157 // contexts. (It's allowed in all effect contexts and disallowed in all
2159 void VisitForValue(Expression* expr,
2160 ArgumentsAllowedFlag flag = ARGUMENTS_NOT_ALLOWED);
2161 void VisitForTypeOf(Expression* expr);
2162 void VisitForEffect(Expression* expr);
2163 void VisitForControl(Expression* expr,
2164 HBasicBlock* true_block,
2165 HBasicBlock* false_block);
2167 // Visit an argument subexpression and emit a push to the outgoing arguments.
2168 void VisitArgument(Expression* expr);
2170 void VisitArgumentList(ZoneList<Expression*>* arguments);
2172 // Visit a list of expressions from left to right, each in a value context.
2173 void VisitExpressions(ZoneList<Expression*>* exprs);
2175 // Remove the arguments from the bailout environment and emit instructions
2176 // to push them as outgoing parameters.
2177 template <class Instruction> HInstruction* PreProcessCall(Instruction* call);
2178 void PushArgumentsFromEnvironment(int count);
2180 void SetUpScope(Scope* scope);
2181 virtual void VisitStatements(ZoneList<Statement*>* statements) V8_OVERRIDE;
2183 #define DECLARE_VISIT(type) virtual void Visit##type(type* node) V8_OVERRIDE;
2184 AST_NODE_LIST(DECLARE_VISIT)
2185 #undef DECLARE_VISIT
2187 Type* ToType(Handle<Map> map) { return IC::MapToType<Type>(map, zone()); }
2190 enum PropertyAccessType { LOAD, STORE };
2192 // Helpers for flow graph construction.
2193 enum GlobalPropertyAccess {
2197 GlobalPropertyAccess LookupGlobalProperty(Variable* var,
2198 LookupResult* lookup,
2201 void EnsureArgumentsArePushedForAccess();
2202 bool TryArgumentsAccess(Property* expr);
2204 // Try to optimize fun.apply(receiver, arguments) pattern.
2205 bool TryCallApply(Call* expr);
2207 HValue* ImplicitReceiverFor(HValue* function,
2208 Handle<JSFunction> target);
2210 int InliningAstSize(Handle<JSFunction> target);
2211 bool TryInline(Handle<JSFunction> target,
2212 int arguments_count,
2213 HValue* implicit_return_value,
2215 BailoutId return_id,
2216 InliningKind inlining_kind);
2218 bool TryInlineCall(Call* expr);
2219 bool TryInlineConstruct(CallNew* expr, HValue* implicit_return_value);
2220 bool TryInlineGetter(Handle<JSFunction> getter,
2221 Handle<Map> receiver_map,
2223 BailoutId return_id);
2224 bool TryInlineSetter(Handle<JSFunction> setter,
2225 Handle<Map> receiver_map,
2227 BailoutId assignment_id,
2228 HValue* implicit_return_value);
2229 bool TryInlineApply(Handle<JSFunction> function,
2231 int arguments_count);
2232 bool TryInlineBuiltinMethodCall(Call* expr,
2234 Handle<Map> receiver_map);
2235 bool TryInlineBuiltinFunctionCall(Call* expr);
2242 bool TryInlineApiMethodCall(Call* expr,
2244 SmallMapList* receiver_types);
2245 bool TryInlineApiFunctionCall(Call* expr, HValue* receiver);
2246 bool TryInlineApiGetter(Handle<JSFunction> function,
2247 Handle<Map> receiver_map,
2249 bool TryInlineApiSetter(Handle<JSFunction> function,
2250 Handle<Map> receiver_map,
2252 bool TryInlineApiCall(Handle<JSFunction> function,
2254 SmallMapList* receiver_maps,
2257 ApiCallType call_type);
2259 // If --trace-inlining, print a line of the inlining trace. Inlining
2260 // succeeded if the reason string is NULL and failed if there is a
2261 // non-NULL reason string.
2262 void TraceInline(Handle<JSFunction> target,
2263 Handle<JSFunction> caller,
2264 const char* failure_reason);
2266 void HandleGlobalVariableAssignment(Variable* var,
2270 void HandlePropertyAssignment(Assignment* expr);
2271 void HandleCompoundAssignment(Assignment* expr);
2272 void HandlePolymorphicNamedFieldAccess(PropertyAccessType access_type,
2274 BailoutId return_id,
2277 SmallMapList* types,
2278 Handle<String> name);
2280 void VisitTypedArrayInitialize(CallRuntime* expr);
2282 bool IsCallNewArrayInlineable(CallNew* expr);
2283 void BuildInlinedCallNewArray(CallNew* expr);
2285 void VisitDataViewInitialize(CallRuntime* expr);
2287 class PropertyAccessInfo {
2289 PropertyAccessInfo(HOptimizedGraphBuilder* builder,
2290 PropertyAccessType access_type,
2292 Handle<String> name)
2293 : lookup_(builder->isolate()),
2295 access_type_(access_type),
2298 access_(HObjectAccess::ForMap()) { }
2300 // Checkes whether this PropertyAccessInfo can be handled as a monomorphic
2301 // load named. It additionally fills in the fields necessary to generate the
2303 bool CanAccessMonomorphic();
2305 // Checks whether all types behave uniform when loading name. If all maps
2306 // behave the same, a single monomorphic load instruction can be emitted,
2307 // guarded by a single map-checks instruction that whether the receiver is
2308 // an instance of any of the types.
2309 // This method skips the first type in types, assuming that this
2310 // PropertyAccessInfo is built for types->first().
2311 bool CanAccessAsMonomorphic(SmallMapList* types);
2314 if (type_->Is(Type::Number())) {
2315 Context* context = current_info()->closure()->context();
2316 context = context->native_context();
2317 return handle(context->number_function()->initial_map());
2318 } else if (type_->Is(Type::Float32x4())) {
2319 Context* context = current_info()->closure()->context();
2320 context = context->native_context();
2321 return handle(context->float32x4_function()->initial_map());
2322 } else if (type_->Is(Type::Int32x4())) {
2323 Context* context = current_info()->closure()->context();
2324 context = context->native_context();
2325 return handle(context->int32x4_function()->initial_map());
2326 } else if (type_->Is(Type::Boolean())) {
2327 Context* context = current_info()->closure()->context();
2328 context = context->native_context();
2329 return handle(context->boolean_function()->initial_map());
2330 } else if (type_->Is(Type::String())) {
2331 Context* context = current_info()->closure()->context();
2332 context = context->native_context();
2333 return handle(context->string_function()->initial_map());
2335 return type_->AsClass();
2338 Type* type() const { return type_; }
2339 Handle<String> name() const { return name_; }
2341 bool IsJSObjectFieldAccessor() {
2342 int offset; // unused
2343 return Accessors::IsJSObjectFieldAccessor<Type>(type_, name_, &offset);
2346 bool GetJSObjectFieldAccess(HObjectAccess* access) {
2348 if (Accessors::IsJSObjectFieldAccessor<Type>(type_, name_, &offset)) {
2349 if (type_->Is(Type::String())) {
2350 ASSERT(name_->Equals(isolate()->heap()->length_string()));
2351 *access = HObjectAccess::ForStringLength();
2352 } else if (type_->Is(Type::Array())) {
2353 ASSERT(name_->Equals(isolate()->heap()->length_string()));
2354 *access = HObjectAccess::ForArrayLength(map()->elements_kind());
2356 *access = HObjectAccess::ForMapAndOffset(map(), offset);
2363 bool has_holder() { return !holder_.is_null(); }
2364 bool IsLoad() const { return access_type_ == LOAD; }
2366 LookupResult* lookup() { return &lookup_; }
2367 Handle<String> name() { return name_; }
2368 Handle<JSObject> holder() { return holder_; }
2369 Handle<JSFunction> accessor() { return accessor_; }
2370 Handle<Object> constant() { return constant_; }
2371 Handle<Map> transition() { return handle(lookup_.GetTransitionTarget()); }
2372 HObjectAccess access() { return access_; }
2375 Type* ToType(Handle<Map> map) { return builder_->ToType(map); }
2376 Isolate* isolate() { return lookup_.isolate(); }
2377 CompilationInfo* current_info() { return builder_->current_info(); }
2379 bool IsSIMD128PropertyCallback() {
2380 return (((type_->Is(Type::Float32x4()) || type_->Is(Type::Int32x4())) &&
2381 (name_->Equals(isolate()->heap()->signMask()) ||
2382 name_->Equals(isolate()->heap()->x()) ||
2383 name_->Equals(isolate()->heap()->y()) ||
2384 name_->Equals(isolate()->heap()->z()) ||
2385 name_->Equals(isolate()->heap()->w()))) ||
2386 (type_->Is(Type::Int32x4()) &&
2387 (name_->Equals(isolate()->heap()->flagX()) ||
2388 name_->Equals(isolate()->heap()->flagY()) ||
2389 name_->Equals(isolate()->heap()->flagZ()) ||
2390 name_->Equals(isolate()->heap()->flagW()))));
2393 bool LoadResult(Handle<Map> map);
2394 bool LookupDescriptor();
2395 bool LookupInPrototypes();
2396 bool IsCompatible(PropertyAccessInfo* other);
2398 void GeneralizeRepresentation(Representation r) {
2399 access_ = access_.WithRepresentation(
2400 access_.representation().generalize(r));
2403 LookupResult lookup_;
2404 HOptimizedGraphBuilder* builder_;
2405 PropertyAccessType access_type_;
2407 Handle<String> name_;
2408 Handle<JSObject> holder_;
2409 Handle<JSFunction> accessor_;
2410 Handle<JSObject> api_holder_;
2411 Handle<Object> constant_;
2412 HObjectAccess access_;
2415 HInstruction* BuildMonomorphicAccess(PropertyAccessInfo* info,
2417 HValue* checked_object,
2420 BailoutId return_id,
2421 bool can_inline_accessor = true);
2423 HInstruction* BuildNamedAccess(PropertyAccessType access,
2425 BailoutId reutrn_id,
2428 Handle<String> name,
2430 bool is_uninitialized = false);
2432 void HandlePolymorphicCallNamed(Call* expr,
2434 SmallMapList* types,
2435 Handle<String> name);
2436 void HandleLiteralCompareTypeof(CompareOperation* expr,
2437 Expression* sub_expr,
2438 Handle<String> check);
2439 void HandleLiteralCompareNil(CompareOperation* expr,
2440 Expression* sub_expr,
2442 HControlInstruction* BuildCompareInstruction(Token::Value op,
2447 Type* combined_type,
2450 BailoutId bailout_id);
2452 HInstruction* BuildStringCharCodeAt(HValue* string,
2455 enum PushBeforeSimulateBehavior {
2456 PUSH_BEFORE_SIMULATE,
2457 NO_PUSH_BEFORE_SIMULATE
2459 HValue* BuildBinaryOperation(
2460 BinaryOperation* expr,
2463 PushBeforeSimulateBehavior push_sim_result);
2464 HInstruction* BuildIncrement(bool returns_original_input,
2465 CountOperation* expr);
2466 HInstruction* BuildLoadKeyedGeneric(HValue* object,
2469 HInstruction* TryBuildConsolidatedElementLoad(HValue* object,
2472 SmallMapList* maps);
2474 LoadKeyedHoleMode BuildKeyedHoleMode(Handle<Map> map);
2476 HInstruction* BuildMonomorphicElementAccess(HValue* object,
2482 KeyedAccessStoreMode store_mode);
2484 HValue* HandlePolymorphicElementAccess(HValue* object,
2489 KeyedAccessStoreMode store_mode,
2490 bool* has_side_effects);
2492 HValue* HandleKeyedElementAccess(HValue* obj,
2497 bool* has_side_effects);
2499 HInstruction* BuildLoadNamedGeneric(HValue* object,
2500 Handle<String> name,
2501 bool is_uninitialized = false);
2503 HCheckMaps* AddCheckMap(HValue* object, Handle<Map> map);
2505 void BuildLoad(Property* property,
2507 void PushLoad(Property* property,
2511 void BuildStoreForEffect(Expression* expression,
2514 BailoutId return_id,
2519 void BuildStore(Expression* expression,
2522 BailoutId return_id,
2523 bool is_uninitialized = false);
2525 HInstruction* BuildStoreNamedField(PropertyAccessInfo* info,
2526 HValue* checked_object,
2528 HInstruction* BuildStoreNamedGeneric(HValue* object,
2529 Handle<String> name,
2531 bool is_uninitialized = false);
2532 HInstruction* BuildStoreKeyedGeneric(HValue* object,
2536 HValue* BuildContextChainWalk(Variable* var);
2538 HInstruction* BuildThisFunction();
2540 HInstruction* BuildFastLiteral(Handle<JSObject> boilerplate_object,
2541 AllocationSiteUsageContext* site_context);
2543 void BuildEmitObjectHeader(Handle<JSObject> boilerplate_object,
2544 HInstruction* object);
2546 void BuildInitElementsInObjectHeader(Handle<JSObject> boilerplate_object,
2547 HInstruction* object,
2548 HInstruction* object_elements);
2550 void BuildEmitInObjectProperties(Handle<JSObject> boilerplate_object,
2551 HInstruction* object,
2552 AllocationSiteUsageContext* site_context,
2553 PretenureFlag pretenure_flag);
2555 void BuildEmitElements(Handle<JSObject> boilerplate_object,
2556 Handle<FixedArrayBase> elements,
2557 HValue* object_elements,
2558 AllocationSiteUsageContext* site_context);
2560 void BuildEmitFixedDoubleArray(Handle<FixedArrayBase> elements,
2562 HValue* object_elements);
2564 void BuildEmitFixedArray(Handle<FixedArrayBase> elements,
2566 HValue* object_elements,
2567 AllocationSiteUsageContext* site_context);
2569 void AddCheckPrototypeMaps(Handle<JSObject> holder,
2570 Handle<Map> receiver_map);
2572 HInstruction* NewPlainFunctionCall(HValue* fun,
2574 bool pass_argument_count);
2576 HInstruction* NewArgumentAdaptorCall(HValue* fun, HValue* context,
2578 HValue* expected_param_count);
2580 HInstruction* BuildCallConstantFunction(Handle<JSFunction> target,
2581 int argument_count);
2583 // The translation state of the currently-being-translated function.
2584 FunctionState* function_state_;
2586 // The base of the function state stack.
2587 FunctionState initial_function_state_;
2589 // Expression context of the currently visited subexpression. NULL when
2590 // visiting statements.
2591 AstContext* ast_context_;
2593 // A stack of breakable statements entered.
2594 BreakAndContinueScope* break_scope_;
2597 ZoneList<Handle<Object> > globals_;
2599 bool inline_bailout_;
2603 friend class FunctionState; // Pushes and pops the state stack.
2604 friend class AstContext; // Pushes and pops the AST context stack.
2605 friend class KeyedLoadFastElementStub;
2606 friend class HOsrBuilder;
2608 DISALLOW_COPY_AND_ASSIGN(HOptimizedGraphBuilder);
2612 Zone* AstContext::zone() const { return owner_->zone(); }
2615 class HStatistics V8_FINAL: public Malloced {
2624 void Initialize(CompilationInfo* info);
2626 void SaveTiming(const char* name, TimeDelta time, unsigned size);
2628 void IncrementFullCodeGen(TimeDelta full_code_gen) {
2629 full_code_gen_ += full_code_gen;
2632 void IncrementSubtotals(TimeDelta create_graph,
2633 TimeDelta optimize_graph,
2634 TimeDelta generate_code) {
2635 create_graph_ += create_graph;
2636 optimize_graph_ += optimize_graph;
2637 generate_code_ += generate_code;
2641 List<TimeDelta> times_;
2642 List<const char*> names_;
2643 List<unsigned> sizes_;
2644 TimeDelta create_graph_;
2645 TimeDelta optimize_graph_;
2646 TimeDelta generate_code_;
2647 unsigned total_size_;
2648 TimeDelta full_code_gen_;
2649 double source_size_;
2653 class HPhase : public CompilationPhase {
2655 HPhase(const char* name, HGraph* graph)
2656 : CompilationPhase(name, graph->info()),
2661 HGraph* graph() const { return graph_; }
2666 DISALLOW_COPY_AND_ASSIGN(HPhase);
2670 class HTracer V8_FINAL : public Malloced {
2672 explicit HTracer(int isolate_id)
2673 : trace_(&string_allocator_), indent_(0) {
2674 if (FLAG_trace_hydrogen_file == NULL) {
2675 OS::SNPrintF(filename_,
2676 "hydrogen-%d-%d.cfg",
2677 OS::GetCurrentProcessId(),
2680 OS::StrNCpy(filename_, FLAG_trace_hydrogen_file, filename_.length());
2682 WriteChars(filename_.start(), "", 0, false);
2685 void TraceCompilation(CompilationInfo* info);
2686 void TraceHydrogen(const char* name, HGraph* graph);
2687 void TraceLithium(const char* name, LChunk* chunk);
2688 void TraceLiveRanges(const char* name, LAllocator* allocator);
2691 class Tag V8_FINAL BASE_EMBEDDED {
2693 Tag(HTracer* tracer, const char* name) {
2696 tracer->PrintIndent();
2697 tracer->trace_.Add("begin_%s\n", name);
2703 tracer_->PrintIndent();
2704 tracer_->trace_.Add("end_%s\n", name_);
2705 ASSERT(tracer_->indent_ >= 0);
2706 tracer_->FlushToFile();
2714 void TraceLiveRange(LiveRange* range, const char* type, Zone* zone);
2715 void Trace(const char* name, HGraph* graph, LChunk* chunk);
2718 void PrintEmptyProperty(const char* name) {
2720 trace_.Add("%s\n", name);
2723 void PrintStringProperty(const char* name, const char* value) {
2725 trace_.Add("%s \"%s\"\n", name, value);
2728 void PrintLongProperty(const char* name, int64_t value) {
2730 trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000));
2733 void PrintBlockProperty(const char* name, int block_id) {
2735 trace_.Add("%s \"B%d\"\n", name, block_id);
2738 void PrintIntProperty(const char* name, int value) {
2740 trace_.Add("%s %d\n", name, value);
2743 void PrintIndent() {
2744 for (int i = 0; i < indent_; i++) {
2749 EmbeddedVector<char, 64> filename_;
2750 HeapStringAllocator string_allocator_;
2751 StringStream trace_;
2756 class NoObservableSideEffectsScope V8_FINAL {
2758 explicit NoObservableSideEffectsScope(HGraphBuilder* builder) :
2760 builder_->graph()->IncrementInNoSideEffectsScope();
2762 ~NoObservableSideEffectsScope() {
2763 builder_->graph()->DecrementInNoSideEffectsScope();
2767 HGraphBuilder* builder_;
2771 } } // namespace v8::internal
2773 #endif // V8_HYDROGEN_H_