Index: src/hydrogen.h |
diff --git a/src/hydrogen.h b/src/hydrogen.h |
deleted file mode 100644 |
index 4d0d2b6715f5c9c574a9c6c0a89f0567517e3125..0000000000000000000000000000000000000000 |
--- a/src/hydrogen.h |
+++ /dev/null |
@@ -1,3081 +0,0 @@ |
-// Copyright 2012 the V8 project authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#ifndef V8_HYDROGEN_H_ |
-#define V8_HYDROGEN_H_ |
- |
-#include "src/accessors.h" |
-#include "src/allocation.h" |
-#include "src/ast.h" |
-#include "src/bailout-reason.h" |
-#include "src/compiler.h" |
-#include "src/hydrogen-instructions.h" |
-#include "src/scopes.h" |
-#include "src/zone.h" |
- |
-namespace v8 { |
-namespace internal { |
- |
-// Forward declarations. |
-class BitVector; |
-class FunctionState; |
-class HEnvironment; |
-class HGraph; |
-class HLoopInformation; |
-class HOsrBuilder; |
-class HTracer; |
-class LAllocator; |
-class LChunk; |
-class LiveRange; |
- |
- |
-class HBasicBlock final : public ZoneObject { |
- public: |
- explicit HBasicBlock(HGraph* graph); |
- ~HBasicBlock() { } |
- |
- // Simple accessors. |
- int block_id() const { return block_id_; } |
- void set_block_id(int id) { block_id_ = id; } |
- HGraph* graph() const { return graph_; } |
- Isolate* isolate() const; |
- const ZoneList<HPhi*>* phis() const { return &phis_; } |
- HInstruction* first() const { return first_; } |
- HInstruction* last() const { return last_; } |
- void set_last(HInstruction* instr) { last_ = instr; } |
- HControlInstruction* end() const { return end_; } |
- HLoopInformation* loop_information() const { return loop_information_; } |
- HLoopInformation* current_loop() const { |
- return IsLoopHeader() ? loop_information() |
- : (parent_loop_header() != NULL |
- ? parent_loop_header()->loop_information() : NULL); |
- } |
- const ZoneList<HBasicBlock*>* predecessors() const { return &predecessors_; } |
- bool HasPredecessor() const { return predecessors_.length() > 0; } |
- const ZoneList<HBasicBlock*>* dominated_blocks() const { |
- return &dominated_blocks_; |
- } |
- const ZoneList<int>* deleted_phis() const { |
- return &deleted_phis_; |
- } |
- void RecordDeletedPhi(int merge_index) { |
- deleted_phis_.Add(merge_index, zone()); |
- } |
- HBasicBlock* dominator() const { return dominator_; } |
- HEnvironment* last_environment() const { return last_environment_; } |
- int argument_count() const { return argument_count_; } |
- void set_argument_count(int count) { argument_count_ = count; } |
- int first_instruction_index() const { return first_instruction_index_; } |
- void set_first_instruction_index(int index) { |
- first_instruction_index_ = index; |
- } |
- int last_instruction_index() const { return last_instruction_index_; } |
- void set_last_instruction_index(int index) { |
- last_instruction_index_ = index; |
- } |
- bool is_osr_entry() { return is_osr_entry_; } |
- void set_osr_entry() { is_osr_entry_ = true; } |
- |
- void AttachLoopInformation(); |
- void DetachLoopInformation(); |
- bool IsLoopHeader() const { return loop_information() != NULL; } |
- bool IsStartBlock() const { return block_id() == 0; } |
- void PostProcessLoopHeader(IterationStatement* stmt); |
- |
- bool IsFinished() const { return end_ != NULL; } |
- void AddPhi(HPhi* phi); |
- void RemovePhi(HPhi* phi); |
- void AddInstruction(HInstruction* instr, SourcePosition position); |
- bool Dominates(HBasicBlock* other) const; |
- bool EqualToOrDominates(HBasicBlock* other) const; |
- int LoopNestingDepth() const; |
- |
- void SetInitialEnvironment(HEnvironment* env); |
- void ClearEnvironment() { |
- DCHECK(IsFinished()); |
- DCHECK(end()->SuccessorCount() == 0); |
- last_environment_ = NULL; |
- } |
- bool HasEnvironment() const { return last_environment_ != NULL; } |
- void UpdateEnvironment(HEnvironment* env); |
- HBasicBlock* parent_loop_header() const { return parent_loop_header_; } |
- |
- void set_parent_loop_header(HBasicBlock* block) { |
- DCHECK(parent_loop_header_ == NULL); |
- parent_loop_header_ = block; |
- } |
- |
- bool HasParentLoopHeader() const { return parent_loop_header_ != NULL; } |
- |
- void SetJoinId(BailoutId ast_id); |
- |
- int PredecessorIndexOf(HBasicBlock* predecessor) const; |
- HPhi* AddNewPhi(int merged_index); |
- HSimulate* AddNewSimulate(BailoutId ast_id, SourcePosition position, |
- RemovableSimulate removable = FIXED_SIMULATE) { |
- HSimulate* instr = CreateSimulate(ast_id, removable); |
- AddInstruction(instr, position); |
- return instr; |
- } |
- void AssignCommonDominator(HBasicBlock* other); |
- void AssignLoopSuccessorDominators(); |
- |
- // If a target block is tagged as an inline function return, all |
- // predecessors should contain the inlined exit sequence: |
- // |
- // LeaveInlined |
- // Simulate (caller's environment) |
- // Goto (target block) |
- bool IsInlineReturnTarget() const { return is_inline_return_target_; } |
- void MarkAsInlineReturnTarget(HBasicBlock* inlined_entry_block) { |
- is_inline_return_target_ = true; |
- inlined_entry_block_ = inlined_entry_block; |
- } |
- HBasicBlock* inlined_entry_block() { return inlined_entry_block_; } |
- |
- bool IsDeoptimizing() const { |
- return end() != NULL && end()->IsDeoptimize(); |
- } |
- |
- void MarkUnreachable(); |
- bool IsUnreachable() const { return !is_reachable_; } |
- bool IsReachable() const { return is_reachable_; } |
- |
- bool IsLoopSuccessorDominator() const { |
- return dominates_loop_successors_; |
- } |
- void MarkAsLoopSuccessorDominator() { |
- dominates_loop_successors_ = true; |
- } |
- |
- bool IsOrdered() const { return is_ordered_; } |
- void MarkAsOrdered() { is_ordered_ = true; } |
- |
- void MarkSuccEdgeUnreachable(int succ); |
- |
- inline Zone* zone() const; |
- |
-#ifdef DEBUG |
- void Verify(); |
-#endif |
- |
- protected: |
- friend class HGraphBuilder; |
- |
- HSimulate* CreateSimulate(BailoutId ast_id, RemovableSimulate removable); |
- void Finish(HControlInstruction* last, SourcePosition position); |
- void FinishExit(HControlInstruction* instruction, SourcePosition position); |
- void Goto(HBasicBlock* block, SourcePosition position, |
- FunctionState* state = NULL, bool add_simulate = true); |
- void GotoNoSimulate(HBasicBlock* block, SourcePosition position) { |
- Goto(block, position, NULL, false); |
- } |
- |
- // Add the inlined function exit sequence, adding an HLeaveInlined |
- // instruction and updating the bailout environment. |
- void AddLeaveInlined(HValue* return_value, FunctionState* state, |
- SourcePosition position); |
- |
- private: |
- void RegisterPredecessor(HBasicBlock* pred); |
- void AddDominatedBlock(HBasicBlock* block); |
- |
- int block_id_; |
- HGraph* graph_; |
- ZoneList<HPhi*> phis_; |
- HInstruction* first_; |
- HInstruction* last_; |
- HControlInstruction* end_; |
- HLoopInformation* loop_information_; |
- ZoneList<HBasicBlock*> predecessors_; |
- HBasicBlock* dominator_; |
- ZoneList<HBasicBlock*> dominated_blocks_; |
- HEnvironment* last_environment_; |
- // Outgoing parameter count at block exit, set during lithium translation. |
- int argument_count_; |
- // Instruction indices into the lithium code stream. |
- int first_instruction_index_; |
- int last_instruction_index_; |
- ZoneList<int> deleted_phis_; |
- HBasicBlock* parent_loop_header_; |
- // For blocks marked as inline return target: the block with HEnterInlined. |
- HBasicBlock* inlined_entry_block_; |
- bool is_inline_return_target_ : 1; |
- bool is_reachable_ : 1; |
- bool dominates_loop_successors_ : 1; |
- bool is_osr_entry_ : 1; |
- bool is_ordered_ : 1; |
-}; |
- |
- |
-std::ostream& operator<<(std::ostream& os, const HBasicBlock& b); |
- |
- |
-class HPredecessorIterator final BASE_EMBEDDED { |
- public: |
- explicit HPredecessorIterator(HBasicBlock* block) |
- : predecessor_list_(block->predecessors()), current_(0) { } |
- |
- bool Done() { return current_ >= predecessor_list_->length(); } |
- HBasicBlock* Current() { return predecessor_list_->at(current_); } |
- void Advance() { current_++; } |
- |
- private: |
- const ZoneList<HBasicBlock*>* predecessor_list_; |
- int current_; |
-}; |
- |
- |
-class HInstructionIterator final BASE_EMBEDDED { |
- public: |
- explicit HInstructionIterator(HBasicBlock* block) |
- : instr_(block->first()) { |
- next_ = Done() ? NULL : instr_->next(); |
- } |
- |
- inline bool Done() const { return instr_ == NULL; } |
- inline HInstruction* Current() { return instr_; } |
- inline void Advance() { |
- instr_ = next_; |
- next_ = Done() ? NULL : instr_->next(); |
- } |
- |
- private: |
- HInstruction* instr_; |
- HInstruction* next_; |
-}; |
- |
- |
-class HLoopInformation final : public ZoneObject { |
- public: |
- HLoopInformation(HBasicBlock* loop_header, Zone* zone) |
- : back_edges_(4, zone), |
- loop_header_(loop_header), |
- blocks_(8, zone), |
- stack_check_(NULL) { |
- blocks_.Add(loop_header, zone); |
- } |
- ~HLoopInformation() {} |
- |
- const ZoneList<HBasicBlock*>* back_edges() const { return &back_edges_; } |
- const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; } |
- HBasicBlock* loop_header() const { return loop_header_; } |
- HBasicBlock* GetLastBackEdge() const; |
- void RegisterBackEdge(HBasicBlock* block); |
- |
- HStackCheck* stack_check() const { return stack_check_; } |
- void set_stack_check(HStackCheck* stack_check) { |
- stack_check_ = stack_check; |
- } |
- |
- bool IsNestedInThisLoop(HLoopInformation* other) { |
- while (other != NULL) { |
- if (other == this) { |
- return true; |
- } |
- other = other->parent_loop(); |
- } |
- return false; |
- } |
- HLoopInformation* parent_loop() { |
- HBasicBlock* parent_header = loop_header()->parent_loop_header(); |
- return parent_header != NULL ? parent_header->loop_information() : NULL; |
- } |
- |
- private: |
- void AddBlock(HBasicBlock* block); |
- |
- ZoneList<HBasicBlock*> back_edges_; |
- HBasicBlock* loop_header_; |
- ZoneList<HBasicBlock*> blocks_; |
- HStackCheck* stack_check_; |
-}; |
- |
- |
-class BoundsCheckTable; |
-class InductionVariableBlocksTable; |
-class HGraph final : public ZoneObject { |
- public: |
- explicit HGraph(CompilationInfo* info); |
- |
- Isolate* isolate() const { return isolate_; } |
- Zone* zone() const { return zone_; } |
- CompilationInfo* info() const { return info_; } |
- |
- const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; } |
- const ZoneList<HPhi*>* phi_list() const { return phi_list_; } |
- HBasicBlock* entry_block() const { return entry_block_; } |
- HEnvironment* start_environment() const { return start_environment_; } |
- |
- void FinalizeUniqueness(); |
- void OrderBlocks(); |
- void AssignDominators(); |
- void RestoreActualValues(); |
- |
- // Returns false if there are phi-uses of the arguments-object |
- // which are not supported by the optimizing compiler. |
- bool CheckArgumentsPhiUses(); |
- |
- // Returns false if there are phi-uses of an uninitialized const |
- // which are not supported by the optimizing compiler. |
- bool CheckConstPhiUses(); |
- |
- void CollectPhis(); |
- |
- HConstant* GetConstantUndefined(); |
- HConstant* GetConstant0(); |
- HConstant* GetConstant1(); |
- HConstant* GetConstantMinus1(); |
- HConstant* GetConstantTrue(); |
- HConstant* GetConstantFalse(); |
- HConstant* GetConstantBool(bool value); |
- HConstant* GetConstantHole(); |
- HConstant* GetConstantNull(); |
- HConstant* GetInvalidContext(); |
- |
- bool IsConstantUndefined(HConstant* constant); |
- bool IsConstant0(HConstant* constant); |
- bool IsConstant1(HConstant* constant); |
- bool IsConstantMinus1(HConstant* constant); |
- bool IsConstantTrue(HConstant* constant); |
- bool IsConstantFalse(HConstant* constant); |
- bool IsConstantHole(HConstant* constant); |
- bool IsConstantNull(HConstant* constant); |
- bool IsStandardConstant(HConstant* constant); |
- |
- HBasicBlock* CreateBasicBlock(); |
- HArgumentsObject* GetArgumentsObject() const { |
- return arguments_object_.get(); |
- } |
- |
- void SetArgumentsObject(HArgumentsObject* object) { |
- arguments_object_.set(object); |
- } |
- |
- int GetMaximumValueID() const { return values_.length(); } |
- int GetNextBlockID() { return next_block_id_++; } |
- int GetNextValueID(HValue* value) { |
- DCHECK(!disallow_adding_new_values_); |
- values_.Add(value, zone()); |
- return values_.length() - 1; |
- } |
- HValue* LookupValue(int id) const { |
- if (id >= 0 && id < values_.length()) return values_[id]; |
- return NULL; |
- } |
- void DisallowAddingNewValues() { |
- disallow_adding_new_values_ = true; |
- } |
- |
- bool Optimize(BailoutReason* bailout_reason); |
- |
-#ifdef DEBUG |
- void Verify(bool do_full_verify) const; |
-#endif |
- |
- bool has_osr() { |
- return osr_ != NULL; |
- } |
- |
- void set_osr(HOsrBuilder* osr) { |
- osr_ = osr; |
- } |
- |
- HOsrBuilder* osr() { |
- return osr_; |
- } |
- |
- int update_type_change_checksum(int delta) { |
- type_change_checksum_ += delta; |
- return type_change_checksum_; |
- } |
- |
- void update_maximum_environment_size(int environment_size) { |
- if (environment_size > maximum_environment_size_) { |
- maximum_environment_size_ = environment_size; |
- } |
- } |
- int maximum_environment_size() { return maximum_environment_size_; } |
- |
- bool use_optimistic_licm() { |
- return use_optimistic_licm_; |
- } |
- |
- void set_use_optimistic_licm(bool value) { |
- use_optimistic_licm_ = value; |
- } |
- |
- void MarkRecursive() { is_recursive_ = true; } |
- bool is_recursive() const { return is_recursive_; } |
- |
- void MarkDependsOnEmptyArrayProtoElements() { |
- // Add map dependency if not already added. |
- if (depends_on_empty_array_proto_elements_) return; |
- info()->dependencies()->AssumePropertyCell( |
- isolate()->factory()->array_protector()); |
- depends_on_empty_array_proto_elements_ = true; |
- } |
- |
- bool depends_on_empty_array_proto_elements() { |
- return depends_on_empty_array_proto_elements_; |
- } |
- |
- bool has_uint32_instructions() { |
- DCHECK(uint32_instructions_ == NULL || !uint32_instructions_->is_empty()); |
- return uint32_instructions_ != NULL; |
- } |
- |
- ZoneList<HInstruction*>* uint32_instructions() { |
- DCHECK(uint32_instructions_ == NULL || !uint32_instructions_->is_empty()); |
- return uint32_instructions_; |
- } |
- |
- void RecordUint32Instruction(HInstruction* instr) { |
- DCHECK(uint32_instructions_ == NULL || !uint32_instructions_->is_empty()); |
- if (uint32_instructions_ == NULL) { |
- uint32_instructions_ = new(zone()) ZoneList<HInstruction*>(4, zone()); |
- } |
- uint32_instructions_->Add(instr, zone()); |
- } |
- |
- void IncrementInNoSideEffectsScope() { no_side_effects_scope_count_++; } |
- void DecrementInNoSideEffectsScope() { no_side_effects_scope_count_--; } |
- bool IsInsideNoSideEffectsScope() { return no_side_effects_scope_count_ > 0; } |
- |
- // If we are tracking source positions then this function assigns a unique |
- // identifier to each inlining and dumps function source if it was inlined |
- // for the first time during the current optimization. |
- int TraceInlinedFunction(Handle<SharedFunctionInfo> shared, |
- SourcePosition position); |
- |
- // Converts given SourcePosition to the absolute offset from the start of |
- // the corresponding script. |
- int SourcePositionToScriptPosition(SourcePosition position); |
- |
- private: |
- HConstant* ReinsertConstantIfNecessary(HConstant* constant); |
- HConstant* GetConstant(SetOncePointer<HConstant>* pointer, |
- int32_t integer_value); |
- |
- template<class Phase> |
- void Run() { |
- Phase phase(this); |
- phase.Run(); |
- } |
- |
- Isolate* isolate_; |
- int next_block_id_; |
- HBasicBlock* entry_block_; |
- HEnvironment* start_environment_; |
- ZoneList<HBasicBlock*> blocks_; |
- ZoneList<HValue*> values_; |
- ZoneList<HPhi*>* phi_list_; |
- ZoneList<HInstruction*>* uint32_instructions_; |
- SetOncePointer<HConstant> constant_undefined_; |
- SetOncePointer<HConstant> constant_0_; |
- SetOncePointer<HConstant> constant_1_; |
- SetOncePointer<HConstant> constant_minus1_; |
- SetOncePointer<HConstant> constant_true_; |
- SetOncePointer<HConstant> constant_false_; |
- SetOncePointer<HConstant> constant_the_hole_; |
- SetOncePointer<HConstant> constant_null_; |
- SetOncePointer<HConstant> constant_invalid_context_; |
- SetOncePointer<HArgumentsObject> arguments_object_; |
- |
- HOsrBuilder* osr_; |
- |
- CompilationInfo* info_; |
- Zone* zone_; |
- |
- bool is_recursive_; |
- bool use_optimistic_licm_; |
- bool depends_on_empty_array_proto_elements_; |
- int type_change_checksum_; |
- int maximum_environment_size_; |
- int no_side_effects_scope_count_; |
- bool disallow_adding_new_values_; |
- |
- DISALLOW_COPY_AND_ASSIGN(HGraph); |
-}; |
- |
- |
-Zone* HBasicBlock::zone() const { return graph_->zone(); } |
- |
- |
-// Type of stack frame an environment might refer to. |
-enum FrameType { |
- JS_FUNCTION, |
- JS_CONSTRUCT, |
- JS_GETTER, |
- JS_SETTER, |
- ARGUMENTS_ADAPTOR, |
- STUB |
-}; |
- |
- |
-class HEnvironment final : public ZoneObject { |
- public: |
- HEnvironment(HEnvironment* outer, |
- Scope* scope, |
- Handle<JSFunction> closure, |
- Zone* zone); |
- |
- HEnvironment(Zone* zone, int parameter_count); |
- |
- HEnvironment* arguments_environment() { |
- return outer()->frame_type() == ARGUMENTS_ADAPTOR ? outer() : this; |
- } |
- |
- // Simple accessors. |
- Handle<JSFunction> closure() const { return closure_; } |
- const ZoneList<HValue*>* values() const { return &values_; } |
- const GrowableBitVector* assigned_variables() const { |
- return &assigned_variables_; |
- } |
- FrameType frame_type() const { return frame_type_; } |
- int parameter_count() const { return parameter_count_; } |
- int specials_count() const { return specials_count_; } |
- int local_count() const { return local_count_; } |
- HEnvironment* outer() const { return outer_; } |
- int pop_count() const { return pop_count_; } |
- int push_count() const { return push_count_; } |
- |
- BailoutId ast_id() const { return ast_id_; } |
- void set_ast_id(BailoutId id) { ast_id_ = id; } |
- |
- HEnterInlined* entry() const { return entry_; } |
- void set_entry(HEnterInlined* entry) { entry_ = entry; } |
- |
- int length() const { return values_.length(); } |
- |
- int first_expression_index() const { |
- return parameter_count() + specials_count() + local_count(); |
- } |
- |
- int first_local_index() const { |
- return parameter_count() + specials_count(); |
- } |
- |
- void Bind(Variable* variable, HValue* value) { |
- Bind(IndexFor(variable), value); |
- } |
- |
- void Bind(int index, HValue* value); |
- |
- void BindContext(HValue* value) { |
- Bind(parameter_count(), value); |
- } |
- |
- HValue* Lookup(Variable* variable) const { |
- return Lookup(IndexFor(variable)); |
- } |
- |
- HValue* Lookup(int index) const { |
- HValue* result = values_[index]; |
- DCHECK(result != NULL); |
- return result; |
- } |
- |
- HValue* context() const { |
- // Return first special. |
- return Lookup(parameter_count()); |
- } |
- |
- void Push(HValue* value) { |
- DCHECK(value != NULL); |
- ++push_count_; |
- values_.Add(value, zone()); |
- } |
- |
- HValue* Pop() { |
- DCHECK(!ExpressionStackIsEmpty()); |
- if (push_count_ > 0) { |
- --push_count_; |
- } else { |
- ++pop_count_; |
- } |
- return values_.RemoveLast(); |
- } |
- |
- void Drop(int count); |
- |
- HValue* Top() const { return ExpressionStackAt(0); } |
- |
- bool ExpressionStackIsEmpty() const; |
- |
- HValue* ExpressionStackAt(int index_from_top) const { |
- int index = length() - index_from_top - 1; |
- DCHECK(HasExpressionAt(index)); |
- return values_[index]; |
- } |
- |
- void SetExpressionStackAt(int index_from_top, HValue* value); |
- HValue* RemoveExpressionStackAt(int index_from_top); |
- |
- void Print() const; |
- |
- HEnvironment* Copy() const; |
- HEnvironment* CopyWithoutHistory() const; |
- HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const; |
- |
- // Create an "inlined version" of this environment, where the original |
- // environment is the outer environment but the top expression stack |
- // elements are moved to an inner environment as parameters. |
- HEnvironment* CopyForInlining(Handle<JSFunction> target, |
- int arguments, |
- FunctionLiteral* function, |
- HConstant* undefined, |
- InliningKind inlining_kind) const; |
- |
- HEnvironment* DiscardInlined(bool drop_extra) { |
- HEnvironment* outer = outer_; |
- while (outer->frame_type() != JS_FUNCTION) outer = outer->outer_; |
- if (drop_extra) outer->Drop(1); |
- return outer; |
- } |
- |
- void AddIncomingEdge(HBasicBlock* block, HEnvironment* other); |
- |
- void ClearHistory() { |
- pop_count_ = 0; |
- push_count_ = 0; |
- assigned_variables_.Clear(); |
- } |
- |
- void SetValueAt(int index, HValue* value) { |
- DCHECK(index < length()); |
- values_[index] = value; |
- } |
- |
- // Map a variable to an environment index. Parameter indices are shifted |
- // by 1 (receiver is parameter index -1 but environment index 0). |
- // Stack-allocated local indices are shifted by the number of parameters. |
- int IndexFor(Variable* variable) const { |
- DCHECK(variable->IsStackAllocated()); |
- int shift = variable->IsParameter() |
- ? 1 |
- : parameter_count_ + specials_count_; |
- return variable->index() + shift; |
- } |
- |
- bool is_local_index(int i) const { |
- return i >= first_local_index() && i < first_expression_index(); |
- } |
- |
- bool is_parameter_index(int i) const { |
- return i >= 0 && i < parameter_count(); |
- } |
- |
- bool is_special_index(int i) const { |
- return i >= parameter_count() && i < parameter_count() + specials_count(); |
- } |
- |
- Zone* zone() const { return zone_; } |
- |
- private: |
- HEnvironment(const HEnvironment* other, Zone* zone); |
- |
- HEnvironment(HEnvironment* outer, |
- Handle<JSFunction> closure, |
- FrameType frame_type, |
- int arguments, |
- Zone* zone); |
- |
- // Create an artificial stub environment (e.g. for argument adaptor or |
- // constructor stub). |
- HEnvironment* CreateStubEnvironment(HEnvironment* outer, |
- Handle<JSFunction> target, |
- FrameType frame_type, |
- int arguments) const; |
- |
- // True if index is included in the expression stack part of the environment. |
- bool HasExpressionAt(int index) const; |
- |
- void Initialize(int parameter_count, int local_count, int stack_height); |
- void Initialize(const HEnvironment* other); |
- |
- Handle<JSFunction> closure_; |
- // Value array [parameters] [specials] [locals] [temporaries]. |
- ZoneList<HValue*> values_; |
- GrowableBitVector assigned_variables_; |
- FrameType frame_type_; |
- int parameter_count_; |
- int specials_count_; |
- int local_count_; |
- HEnvironment* outer_; |
- HEnterInlined* entry_; |
- int pop_count_; |
- int push_count_; |
- BailoutId ast_id_; |
- Zone* zone_; |
-}; |
- |
- |
-std::ostream& operator<<(std::ostream& os, const HEnvironment& env); |
- |
- |
-class HOptimizedGraphBuilder; |
- |
-enum ArgumentsAllowedFlag { |
- ARGUMENTS_NOT_ALLOWED, |
- ARGUMENTS_ALLOWED, |
- ARGUMENTS_FAKED |
-}; |
- |
- |
-class HIfContinuation; |
- |
-// This class is not BASE_EMBEDDED because our inlining implementation uses |
-// new and delete. |
-class AstContext { |
- public: |
- bool IsEffect() const { return kind_ == Expression::kEffect; } |
- bool IsValue() const { return kind_ == Expression::kValue; } |
- bool IsTest() const { return kind_ == Expression::kTest; } |
- |
- // 'Fill' this context with a hydrogen value. The value is assumed to |
- // have already been inserted in the instruction stream (or not need to |
- // be, e.g., HPhi). Call this function in tail position in the Visit |
- // functions for expressions. |
- virtual void ReturnValue(HValue* value) = 0; |
- |
- // Add a hydrogen instruction to the instruction stream (recording an |
- // environment simulation if necessary) and then fill this context with |
- // the instruction as value. |
- virtual void ReturnInstruction(HInstruction* instr, BailoutId ast_id) = 0; |
- |
- // Finishes the current basic block and materialize a boolean for |
- // value context, nothing for effect, generate a branch for test context. |
- // Call this function in tail position in the Visit functions for |
- // expressions. |
- virtual void ReturnControl(HControlInstruction* instr, BailoutId ast_id) = 0; |
- |
- // Finishes the current basic block and materialize a boolean for |
- // value context, nothing for effect, generate a branch for test context. |
- // Call this function in tail position in the Visit functions for |
- // expressions that use an IfBuilder. |
- virtual void ReturnContinuation(HIfContinuation* continuation, |
- BailoutId ast_id) = 0; |
- |
- void set_typeof_mode(TypeofMode typeof_mode) { typeof_mode_ = typeof_mode; } |
- TypeofMode typeof_mode() { return typeof_mode_; } |
- |
- protected: |
- AstContext(HOptimizedGraphBuilder* owner, Expression::Context kind); |
- virtual ~AstContext(); |
- |
- HOptimizedGraphBuilder* owner() const { return owner_; } |
- |
- inline Zone* zone() const; |
- |
- // We want to be able to assert, in a context-specific way, that the stack |
- // height makes sense when the context is filled. |
-#ifdef DEBUG |
- int original_length_; |
-#endif |
- |
- private: |
- HOptimizedGraphBuilder* owner_; |
- Expression::Context kind_; |
- AstContext* outer_; |
- TypeofMode typeof_mode_; |
-}; |
- |
- |
-class EffectContext final : public AstContext { |
- public: |
- explicit EffectContext(HOptimizedGraphBuilder* owner) |
- : AstContext(owner, Expression::kEffect) { |
- } |
- virtual ~EffectContext(); |
- |
- void ReturnValue(HValue* value) override; |
- virtual void ReturnInstruction(HInstruction* instr, |
- BailoutId ast_id) override; |
- virtual void ReturnControl(HControlInstruction* instr, |
- BailoutId ast_id) override; |
- virtual void ReturnContinuation(HIfContinuation* continuation, |
- BailoutId ast_id) override; |
-}; |
- |
- |
-class ValueContext final : public AstContext { |
- public: |
- ValueContext(HOptimizedGraphBuilder* owner, ArgumentsAllowedFlag flag) |
- : AstContext(owner, Expression::kValue), flag_(flag) { |
- } |
- virtual ~ValueContext(); |
- |
- void ReturnValue(HValue* value) override; |
- virtual void ReturnInstruction(HInstruction* instr, |
- BailoutId ast_id) override; |
- virtual void ReturnControl(HControlInstruction* instr, |
- BailoutId ast_id) override; |
- virtual void ReturnContinuation(HIfContinuation* continuation, |
- BailoutId ast_id) override; |
- |
- bool arguments_allowed() { return flag_ == ARGUMENTS_ALLOWED; } |
- |
- private: |
- ArgumentsAllowedFlag flag_; |
-}; |
- |
- |
-class TestContext final : public AstContext { |
- public: |
- TestContext(HOptimizedGraphBuilder* owner, |
- Expression* condition, |
- HBasicBlock* if_true, |
- HBasicBlock* if_false) |
- : AstContext(owner, Expression::kTest), |
- condition_(condition), |
- if_true_(if_true), |
- if_false_(if_false) { |
- } |
- |
- void ReturnValue(HValue* value) override; |
- virtual void ReturnInstruction(HInstruction* instr, |
- BailoutId ast_id) override; |
- virtual void ReturnControl(HControlInstruction* instr, |
- BailoutId ast_id) override; |
- virtual void ReturnContinuation(HIfContinuation* continuation, |
- BailoutId ast_id) override; |
- |
- static TestContext* cast(AstContext* context) { |
- DCHECK(context->IsTest()); |
- return reinterpret_cast<TestContext*>(context); |
- } |
- |
- Expression* condition() const { return condition_; } |
- HBasicBlock* if_true() const { return if_true_; } |
- HBasicBlock* if_false() const { return if_false_; } |
- |
- private: |
- // Build the shared core part of the translation unpacking a value into |
- // control flow. |
- void BuildBranch(HValue* value); |
- |
- Expression* condition_; |
- HBasicBlock* if_true_; |
- HBasicBlock* if_false_; |
-}; |
- |
- |
-class FunctionState final { |
- public: |
- FunctionState(HOptimizedGraphBuilder* owner, |
- CompilationInfo* info, |
- InliningKind inlining_kind, |
- int inlining_id); |
- ~FunctionState(); |
- |
- CompilationInfo* compilation_info() { return compilation_info_; } |
- AstContext* call_context() { return call_context_; } |
- InliningKind inlining_kind() const { return inlining_kind_; } |
- HBasicBlock* function_return() { return function_return_; } |
- TestContext* test_context() { return test_context_; } |
- void ClearInlinedTestContext() { |
- delete test_context_; |
- test_context_ = NULL; |
- } |
- |
- FunctionState* outer() { return outer_; } |
- |
- HEnterInlined* entry() { return entry_; } |
- void set_entry(HEnterInlined* entry) { entry_ = entry; } |
- |
- HArgumentsObject* arguments_object() { return arguments_object_; } |
- void set_arguments_object(HArgumentsObject* arguments_object) { |
- arguments_object_ = arguments_object; |
- } |
- |
- HArgumentsElements* arguments_elements() { return arguments_elements_; } |
- void set_arguments_elements(HArgumentsElements* arguments_elements) { |
- arguments_elements_ = arguments_elements; |
- } |
- |
- bool arguments_pushed() { return arguments_elements() != NULL; } |
- |
- int inlining_id() const { return inlining_id_; } |
- |
- private: |
- HOptimizedGraphBuilder* owner_; |
- |
- CompilationInfo* compilation_info_; |
- |
- // During function inlining, expression context of the call being |
- // inlined. NULL when not inlining. |
- AstContext* call_context_; |
- |
- // The kind of call which is currently being inlined. |
- InliningKind inlining_kind_; |
- |
- // When inlining in an effect or value context, this is the return block. |
- // It is NULL otherwise. When inlining in a test context, there are a |
- // pair of return blocks in the context. When not inlining, there is no |
- // local return point. |
- HBasicBlock* function_return_; |
- |
- // When inlining a call in a test context, a context containing a pair of |
- // return blocks. NULL in all other cases. |
- TestContext* test_context_; |
- |
- // When inlining HEnterInlined instruction corresponding to the function |
- // entry. |
- HEnterInlined* entry_; |
- |
- HArgumentsObject* arguments_object_; |
- HArgumentsElements* arguments_elements_; |
- |
- int inlining_id_; |
- SourcePosition outer_source_position_; |
- |
- FunctionState* outer_; |
-}; |
- |
- |
-class HIfContinuation final { |
- public: |
- HIfContinuation() |
- : continuation_captured_(false), |
- true_branch_(NULL), |
- false_branch_(NULL) {} |
- HIfContinuation(HBasicBlock* true_branch, |
- HBasicBlock* false_branch) |
- : continuation_captured_(true), true_branch_(true_branch), |
- false_branch_(false_branch) {} |
- ~HIfContinuation() { DCHECK(!continuation_captured_); } |
- |
- void Capture(HBasicBlock* true_branch, |
- HBasicBlock* false_branch) { |
- DCHECK(!continuation_captured_); |
- true_branch_ = true_branch; |
- false_branch_ = false_branch; |
- continuation_captured_ = true; |
- } |
- |
- void Continue(HBasicBlock** true_branch, |
- HBasicBlock** false_branch) { |
- DCHECK(continuation_captured_); |
- *true_branch = true_branch_; |
- *false_branch = false_branch_; |
- continuation_captured_ = false; |
- } |
- |
- bool IsTrueReachable() { return true_branch_ != NULL; } |
- bool IsFalseReachable() { return false_branch_ != NULL; } |
- bool TrueAndFalseReachable() { |
- return IsTrueReachable() || IsFalseReachable(); |
- } |
- |
- HBasicBlock* true_branch() const { return true_branch_; } |
- HBasicBlock* false_branch() const { return false_branch_; } |
- |
- private: |
- bool continuation_captured_; |
- HBasicBlock* true_branch_; |
- HBasicBlock* false_branch_; |
-}; |
- |
- |
-class HAllocationMode final BASE_EMBEDDED { |
- public: |
- explicit HAllocationMode(Handle<AllocationSite> feedback_site) |
- : current_site_(NULL), feedback_site_(feedback_site), |
- pretenure_flag_(NOT_TENURED) {} |
- explicit HAllocationMode(HValue* current_site) |
- : current_site_(current_site), pretenure_flag_(NOT_TENURED) {} |
- explicit HAllocationMode(PretenureFlag pretenure_flag) |
- : current_site_(NULL), pretenure_flag_(pretenure_flag) {} |
- HAllocationMode() |
- : current_site_(NULL), pretenure_flag_(NOT_TENURED) {} |
- |
- HValue* current_site() const { return current_site_; } |
- Handle<AllocationSite> feedback_site() const { return feedback_site_; } |
- |
- bool CreateAllocationMementos() const WARN_UNUSED_RESULT { |
- return current_site() != NULL; |
- } |
- |
- PretenureFlag GetPretenureMode() const WARN_UNUSED_RESULT { |
- if (!feedback_site().is_null()) return feedback_site()->GetPretenureMode(); |
- return pretenure_flag_; |
- } |
- |
- private: |
- HValue* current_site_; |
- Handle<AllocationSite> feedback_site_; |
- PretenureFlag pretenure_flag_; |
-}; |
- |
- |
-class HGraphBuilder { |
- public: |
- explicit HGraphBuilder(CompilationInfo* info) |
- : info_(info), |
- graph_(NULL), |
- current_block_(NULL), |
- scope_(info->scope()), |
- position_(SourcePosition::Unknown()), |
- start_position_(0) {} |
- virtual ~HGraphBuilder() {} |
- |
- Scope* scope() const { return scope_; } |
- void set_scope(Scope* scope) { scope_ = scope; } |
- |
- HBasicBlock* current_block() const { return current_block_; } |
- void set_current_block(HBasicBlock* block) { current_block_ = block; } |
- HEnvironment* environment() const { |
- return current_block()->last_environment(); |
- } |
- Zone* zone() const { return info_->zone(); } |
- HGraph* graph() const { return graph_; } |
- Isolate* isolate() const { return graph_->isolate(); } |
- CompilationInfo* top_info() { return info_; } |
- |
- HGraph* CreateGraph(); |
- |
- // Bailout environment manipulation. |
- void Push(HValue* value) { environment()->Push(value); } |
- HValue* Pop() { return environment()->Pop(); } |
- |
- virtual HValue* context() = 0; |
- |
- // Adding instructions. |
- HInstruction* AddInstruction(HInstruction* instr); |
- void FinishCurrentBlock(HControlInstruction* last); |
- void FinishExitCurrentBlock(HControlInstruction* instruction); |
- |
- void Goto(HBasicBlock* from, |
- HBasicBlock* target, |
- FunctionState* state = NULL, |
- bool add_simulate = true) { |
- from->Goto(target, source_position(), state, add_simulate); |
- } |
- void Goto(HBasicBlock* target, |
- FunctionState* state = NULL, |
- bool add_simulate = true) { |
- Goto(current_block(), target, state, add_simulate); |
- } |
- void GotoNoSimulate(HBasicBlock* from, HBasicBlock* target) { |
- Goto(from, target, NULL, false); |
- } |
- void GotoNoSimulate(HBasicBlock* target) { |
- Goto(target, NULL, false); |
- } |
- void AddLeaveInlined(HBasicBlock* block, |
- HValue* return_value, |
- FunctionState* state) { |
- block->AddLeaveInlined(return_value, state, source_position()); |
- } |
- void AddLeaveInlined(HValue* return_value, FunctionState* state) { |
- return AddLeaveInlined(current_block(), return_value, state); |
- } |
- |
- template <class I> |
- HInstruction* NewUncasted() { |
- return I::New(isolate(), zone(), context()); |
- } |
- |
- template <class I> |
- I* New() { |
- return I::New(isolate(), zone(), context()); |
- } |
- |
- template<class I> |
- HInstruction* AddUncasted() { return AddInstruction(NewUncasted<I>());} |
- |
- template<class I> |
- I* Add() { return AddInstructionTyped(New<I>());} |
- |
- template<class I, class P1> |
- HInstruction* NewUncasted(P1 p1) { |
- return I::New(isolate(), zone(), context(), p1); |
- } |
- |
- template <class I, class P1> |
- I* New(P1 p1) { |
- return I::New(isolate(), zone(), context(), p1); |
- } |
- |
- template<class I, class P1> |
- HInstruction* AddUncasted(P1 p1) { |
- HInstruction* result = AddInstruction(NewUncasted<I>(p1)); |
- // Specializations must have their parameters properly casted |
- // to avoid landing here. |
- DCHECK(!result->IsReturn() && !result->IsSimulate() && |
- !result->IsDeoptimize()); |
- return result; |
- } |
- |
- template<class I, class P1> |
- I* Add(P1 p1) { |
- I* result = AddInstructionTyped(New<I>(p1)); |
- // Specializations must have their parameters properly casted |
- // to avoid landing here. |
- DCHECK(!result->IsReturn() && !result->IsSimulate() && |
- !result->IsDeoptimize()); |
- return result; |
- } |
- |
- template<class I, class P1, class P2> |
- HInstruction* NewUncasted(P1 p1, P2 p2) { |
- return I::New(isolate(), zone(), context(), p1, p2); |
- } |
- |
- template<class I, class P1, class P2> |
- I* New(P1 p1, P2 p2) { |
- return I::New(isolate(), zone(), context(), p1, p2); |
- } |
- |
- template<class I, class P1, class P2> |
- HInstruction* AddUncasted(P1 p1, P2 p2) { |
- HInstruction* result = AddInstruction(NewUncasted<I>(p1, p2)); |
- // Specializations must have their parameters properly casted |
- // to avoid landing here. |
- DCHECK(!result->IsSimulate()); |
- return result; |
- } |
- |
- template<class I, class P1, class P2> |
- I* Add(P1 p1, P2 p2) { |
- I* result = AddInstructionTyped(New<I>(p1, p2)); |
- // Specializations must have their parameters properly casted |
- // to avoid landing here. |
- DCHECK(!result->IsSimulate()); |
- return result; |
- } |
- |
- template<class I, class P1, class P2, class P3> |
- HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3) { |
- return I::New(isolate(), zone(), context(), p1, p2, p3); |
- } |
- |
- template<class I, class P1, class P2, class P3> |
- I* New(P1 p1, P2 p2, P3 p3) { |
- return I::New(isolate(), zone(), context(), p1, p2, p3); |
- } |
- |
- template<class I, class P1, class P2, class P3> |
- HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3) { |
- return AddInstruction(NewUncasted<I>(p1, p2, p3)); |
- } |
- |
- template<class I, class P1, class P2, class P3> |
- I* Add(P1 p1, P2 p2, P3 p3) { |
- return AddInstructionTyped(New<I>(p1, p2, p3)); |
- } |
- |
- template<class I, class P1, class P2, class P3, class P4> |
- HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4) { |
- return I::New(isolate(), zone(), context(), p1, p2, p3, p4); |
- } |
- |
- template<class I, class P1, class P2, class P3, class P4> |
- I* New(P1 p1, P2 p2, P3 p3, P4 p4) { |
- return I::New(isolate(), zone(), context(), p1, p2, p3, p4); |
- } |
- |
- template<class I, class P1, class P2, class P3, class P4> |
- HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4) { |
- return AddInstruction(NewUncasted<I>(p1, p2, p3, p4)); |
- } |
- |
- template<class I, class P1, class P2, class P3, class P4> |
- I* Add(P1 p1, P2 p2, P3 p3, P4 p4) { |
- return AddInstructionTyped(New<I>(p1, p2, p3, p4)); |
- } |
- |
- template<class I, class P1, class P2, class P3, class P4, class P5> |
- HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { |
- return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5); |
- } |
- |
- template<class I, class P1, class P2, class P3, class P4, class P5> |
- I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { |
- return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5); |
- } |
- |
- template<class I, class P1, class P2, class P3, class P4, class P5> |
- HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { |
- return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5)); |
- } |
- |
- template<class I, class P1, class P2, class P3, class P4, class P5> |
- I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { |
- return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5)); |
- } |
- |
- template<class I, class P1, class P2, class P3, class P4, class P5, class P6> |
- HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) { |
- return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6); |
- } |
- |
- template<class I, class P1, class P2, class P3, class P4, class P5, class P6> |
- I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) { |
- return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6); |
- } |
- |
- template<class I, class P1, class P2, class P3, class P4, class P5, class P6> |
- HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) { |
- return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6)); |
- } |
- |
- template<class I, class P1, class P2, class P3, class P4, class P5, class P6> |
- I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) { |
- return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5, p6)); |
- } |
- |
- template<class I, class P1, class P2, class P3, class P4, |
- class P5, class P6, class P7> |
- HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) { |
- return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6, p7); |
- } |
- |
- template<class I, class P1, class P2, class P3, class P4, |
- class P5, class P6, class P7> |
- I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) { |
- return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6, p7); |
- } |
- |
- template<class I, class P1, class P2, class P3, |
- class P4, class P5, class P6, class P7> |
- HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) { |
- return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6, p7)); |
- } |
- |
- template<class I, class P1, class P2, class P3, |
- class P4, class P5, class P6, class P7> |
- I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) { |
- return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5, p6, p7)); |
- } |
- |
- template<class I, class P1, class P2, class P3, class P4, |
- class P5, class P6, class P7, class P8> |
- HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, |
- P5 p5, P6 p6, P7 p7, P8 p8) { |
- return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6, p7, p8); |
- } |
- |
- template<class I, class P1, class P2, class P3, class P4, |
- class P5, class P6, class P7, class P8> |
- I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) { |
- return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6, p7, p8); |
- } |
- |
- template<class I, class P1, class P2, class P3, class P4, |
- class P5, class P6, class P7, class P8> |
- HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, |
- P5 p5, P6 p6, P7 p7, P8 p8) { |
- return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6, p7, p8)); |
- } |
- |
- template<class I, class P1, class P2, class P3, class P4, |
- class P5, class P6, class P7, class P8> |
- I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) { |
- return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5, p6, p7, p8)); |
- } |
- |
- void AddSimulate(BailoutId id, RemovableSimulate removable = FIXED_SIMULATE); |
- |
- // When initializing arrays, we'll unfold the loop if the number of elements |
- // is known at compile time and is <= kElementLoopUnrollThreshold. |
- static const int kElementLoopUnrollThreshold = 8; |
- |
- protected: |
- virtual bool BuildGraph() = 0; |
- |
- HBasicBlock* CreateBasicBlock(HEnvironment* env); |
- HBasicBlock* CreateLoopHeaderBlock(); |
- |
- template <class BitFieldClass> |
- HValue* BuildDecodeField(HValue* encoded_field) { |
- HValue* mask_value = Add<HConstant>(static_cast<int>(BitFieldClass::kMask)); |
- HValue* masked_field = |
- AddUncasted<HBitwise>(Token::BIT_AND, encoded_field, mask_value); |
- return AddUncasted<HShr>(masked_field, |
- Add<HConstant>(static_cast<int>(BitFieldClass::kShift))); |
- } |
- |
- HValue* BuildGetElementsKind(HValue* object); |
- |
- HValue* BuildCheckHeapObject(HValue* object); |
- HValue* BuildCheckString(HValue* string); |
- HValue* BuildWrapReceiver(HValue* object, HValue* function); |
- |
- // Building common constructs |
- HValue* BuildCheckForCapacityGrow(HValue* object, |
- HValue* elements, |
- ElementsKind kind, |
- HValue* length, |
- HValue* key, |
- bool is_js_array, |
- PropertyAccessType access_type); |
- |
- HValue* BuildCheckAndGrowElementsCapacity(HValue* object, HValue* elements, |
- ElementsKind kind, HValue* length, |
- HValue* capacity, HValue* key); |
- |
- HValue* BuildCopyElementsOnWrite(HValue* object, |
- HValue* elements, |
- ElementsKind kind, |
- HValue* length); |
- |
- void BuildTransitionElementsKind(HValue* object, |
- HValue* map, |
- ElementsKind from_kind, |
- ElementsKind to_kind, |
- bool is_jsarray); |
- |
- HValue* BuildNumberToString(HValue* object, Type* type); |
- HValue* BuildToObject(HValue* receiver); |
- |
- void BuildJSObjectCheck(HValue* receiver, |
- int bit_field_mask); |
- |
- // Checks a key value that's being used for a keyed element access context. If |
- // the key is a index, i.e. a smi or a number in a unique string with a cached |
- // numeric value, the "true" of the continuation is joined. Otherwise, |
- // if the key is a name or a unique string, the "false" of the continuation is |
- // joined. Otherwise, a deoptimization is triggered. In both paths of the |
- // continuation, the key is pushed on the top of the environment. |
- void BuildKeyedIndexCheck(HValue* key, |
- HIfContinuation* join_continuation); |
- |
- // Checks the properties of an object if they are in dictionary case, in which |
- // case "true" of continuation is taken, otherwise the "false" |
- void BuildTestForDictionaryProperties(HValue* object, |
- HIfContinuation* continuation); |
- |
- void BuildNonGlobalObjectCheck(HValue* receiver); |
- |
- HValue* BuildKeyedLookupCacheHash(HValue* object, |
- HValue* key); |
- |
- HValue* BuildUncheckedDictionaryElementLoad(HValue* receiver, |
- HValue* elements, HValue* key, |
- HValue* hash, |
- LanguageMode language_mode); |
- |
- // ES6 section 7.4.7 CreateIterResultObject ( value, done ) |
- HValue* BuildCreateIterResultObject(HValue* value, HValue* done); |
- |
- HValue* BuildRegExpConstructResult(HValue* length, |
- HValue* index, |
- HValue* input); |
- |
- // Allocates a new object according with the given allocation properties. |
- HAllocate* BuildAllocate(HValue* object_size, |
- HType type, |
- InstanceType instance_type, |
- HAllocationMode allocation_mode); |
- // Computes the sum of two string lengths, taking care of overflow handling. |
- HValue* BuildAddStringLengths(HValue* left_length, HValue* right_length); |
- // Creates a cons string using the two input strings. |
- HValue* BuildCreateConsString(HValue* length, |
- HValue* left, |
- HValue* right, |
- HAllocationMode allocation_mode); |
- // Copies characters from one sequential string to another. |
- void BuildCopySeqStringChars(HValue* src, |
- HValue* src_offset, |
- String::Encoding src_encoding, |
- HValue* dst, |
- HValue* dst_offset, |
- String::Encoding dst_encoding, |
- HValue* length); |
- |
- // Align an object size to object alignment boundary |
- HValue* BuildObjectSizeAlignment(HValue* unaligned_size, int header_size); |
- |
- // Both operands are non-empty strings. |
- HValue* BuildUncheckedStringAdd(HValue* left, |
- HValue* right, |
- HAllocationMode allocation_mode); |
- // Add two strings using allocation mode, validating type feedback. |
- HValue* BuildStringAdd(HValue* left, |
- HValue* right, |
- HAllocationMode allocation_mode); |
- |
- HInstruction* BuildUncheckedMonomorphicElementAccess( |
- HValue* checked_object, |
- HValue* key, |
- HValue* val, |
- bool is_js_array, |
- ElementsKind elements_kind, |
- PropertyAccessType access_type, |
- LoadKeyedHoleMode load_mode, |
- KeyedAccessStoreMode store_mode); |
- |
- HInstruction* AddElementAccess( |
- HValue* elements, |
- HValue* checked_key, |
- HValue* val, |
- HValue* dependency, |
- ElementsKind elements_kind, |
- PropertyAccessType access_type, |
- LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE); |
- |
- HInstruction* AddLoadStringInstanceType(HValue* string); |
- HInstruction* AddLoadStringLength(HValue* string); |
- HInstruction* BuildLoadStringLength(HValue* string); |
- HStoreNamedField* AddStoreMapConstant(HValue* object, Handle<Map> map) { |
- return Add<HStoreNamedField>(object, HObjectAccess::ForMap(), |
- Add<HConstant>(map)); |
- } |
- HLoadNamedField* AddLoadMap(HValue* object, |
- HValue* dependency = NULL); |
- HLoadNamedField* AddLoadElements(HValue* object, |
- HValue* dependency = NULL); |
- |
- bool MatchRotateRight(HValue* left, |
- HValue* right, |
- HValue** operand, |
- HValue** shift_amount); |
- |
- HValue* BuildBinaryOperation(Token::Value op, HValue* left, HValue* right, |
- Type* left_type, Type* right_type, |
- Type* result_type, Maybe<int> fixed_right_arg, |
- HAllocationMode allocation_mode, |
- Strength strength, |
- BailoutId opt_id = BailoutId::None()); |
- |
- HLoadNamedField* AddLoadFixedArrayLength(HValue *object, |
- HValue *dependency = NULL); |
- |
- HLoadNamedField* AddLoadArrayLength(HValue *object, |
- ElementsKind kind, |
- HValue *dependency = NULL); |
- |
- HValue* AddLoadJSBuiltin(int context_index); |
- |
- HValue* EnforceNumberType(HValue* number, Type* expected); |
- HValue* TruncateToNumber(HValue* value, Type** expected); |
- |
- void FinishExitWithHardDeoptimization(Deoptimizer::DeoptReason reason); |
- |
- void AddIncrementCounter(StatsCounter* counter); |
- |
- class IfBuilder final { |
- public: |
- // If using this constructor, Initialize() must be called explicitly! |
- IfBuilder(); |
- |
- explicit IfBuilder(HGraphBuilder* builder); |
- IfBuilder(HGraphBuilder* builder, |
- HIfContinuation* continuation); |
- |
- ~IfBuilder() { |
- if (!finished_) End(); |
- } |
- |
- void Initialize(HGraphBuilder* builder); |
- |
- template<class Condition> |
- Condition* If(HValue *p) { |
- Condition* compare = builder()->New<Condition>(p); |
- AddCompare(compare); |
- return compare; |
- } |
- |
- template<class Condition, class P2> |
- Condition* If(HValue* p1, P2 p2) { |
- Condition* compare = builder()->New<Condition>(p1, p2); |
- AddCompare(compare); |
- return compare; |
- } |
- |
- template<class Condition, class P2, class P3> |
- Condition* If(HValue* p1, P2 p2, P3 p3) { |
- Condition* compare = builder()->New<Condition>(p1, p2, p3); |
- AddCompare(compare); |
- return compare; |
- } |
- |
- template<class Condition> |
- Condition* IfNot(HValue* p) { |
- Condition* compare = If<Condition>(p); |
- compare->Not(); |
- return compare; |
- } |
- |
- template<class Condition, class P2> |
- Condition* IfNot(HValue* p1, P2 p2) { |
- Condition* compare = If<Condition>(p1, p2); |
- compare->Not(); |
- return compare; |
- } |
- |
- template<class Condition, class P2, class P3> |
- Condition* IfNot(HValue* p1, P2 p2, P3 p3) { |
- Condition* compare = If<Condition>(p1, p2, p3); |
- compare->Not(); |
- return compare; |
- } |
- |
- template<class Condition> |
- Condition* OrIf(HValue *p) { |
- Or(); |
- return If<Condition>(p); |
- } |
- |
- template<class Condition, class P2> |
- Condition* OrIf(HValue* p1, P2 p2) { |
- Or(); |
- return If<Condition>(p1, p2); |
- } |
- |
- template<class Condition, class P2, class P3> |
- Condition* OrIf(HValue* p1, P2 p2, P3 p3) { |
- Or(); |
- return If<Condition>(p1, p2, p3); |
- } |
- |
- template<class Condition> |
- Condition* AndIf(HValue *p) { |
- And(); |
- return If<Condition>(p); |
- } |
- |
- template<class Condition, class P2> |
- Condition* AndIf(HValue* p1, P2 p2) { |
- And(); |
- return If<Condition>(p1, p2); |
- } |
- |
- template<class Condition, class P2, class P3> |
- Condition* AndIf(HValue* p1, P2 p2, P3 p3) { |
- And(); |
- return If<Condition>(p1, p2, p3); |
- } |
- |
- void Or(); |
- void And(); |
- |
- // Captures the current state of this IfBuilder in the specified |
- // continuation and ends this IfBuilder. |
- void CaptureContinuation(HIfContinuation* continuation); |
- |
- // Joins the specified continuation from this IfBuilder and ends this |
- // IfBuilder. This appends a Goto instruction from the true branch of |
- // this IfBuilder to the true branch of the continuation unless the |
- // true branch of this IfBuilder is already finished. And vice versa |
- // for the false branch. |
- // |
- // The basic idea is as follows: You have several nested IfBuilder's |
- // that you want to join based on two possible outcomes (i.e. success |
- // and failure, or whatever). You can do this easily using this method |
- // now, for example: |
- // |
- // HIfContinuation cont(graph()->CreateBasicBlock(), |
- // graph()->CreateBasicBlock()); |
- // ... |
- // IfBuilder if_whatever(this); |
- // if_whatever.If<Condition>(arg); |
- // if_whatever.Then(); |
- // ... |
- // if_whatever.Else(); |
- // ... |
- // if_whatever.JoinContinuation(&cont); |
- // ... |
- // IfBuilder if_something(this); |
- // if_something.If<Condition>(arg1, arg2); |
- // if_something.Then(); |
- // ... |
- // if_something.Else(); |
- // ... |
- // if_something.JoinContinuation(&cont); |
- // ... |
- // IfBuilder if_finally(this, &cont); |
- // if_finally.Then(); |
- // // continues after then code of if_whatever or if_something. |
- // ... |
- // if_finally.Else(); |
- // // continues after else code of if_whatever or if_something. |
- // ... |
- // if_finally.End(); |
- void JoinContinuation(HIfContinuation* continuation); |
- |
- void Then(); |
- void Else(); |
- void End(); |
- void EndUnreachable(); |
- |
- void Deopt(Deoptimizer::DeoptReason reason); |
- void ThenDeopt(Deoptimizer::DeoptReason reason) { |
- Then(); |
- Deopt(reason); |
- } |
- void ElseDeopt(Deoptimizer::DeoptReason reason) { |
- Else(); |
- Deopt(reason); |
- } |
- |
- void Return(HValue* value); |
- |
- private: |
- void InitializeDontCreateBlocks(HGraphBuilder* builder); |
- |
- HControlInstruction* AddCompare(HControlInstruction* compare); |
- |
- HGraphBuilder* builder() const { |
- DCHECK(builder_ != NULL); // Have you called "Initialize"? |
- return builder_; |
- } |
- |
- void AddMergeAtJoinBlock(bool deopt); |
- |
- void Finish(); |
- void Finish(HBasicBlock** then_continuation, |
- HBasicBlock** else_continuation); |
- |
- class MergeAtJoinBlock : public ZoneObject { |
- public: |
- MergeAtJoinBlock(HBasicBlock* block, |
- bool deopt, |
- MergeAtJoinBlock* next) |
- : block_(block), |
- deopt_(deopt), |
- next_(next) {} |
- HBasicBlock* block_; |
- bool deopt_; |
- MergeAtJoinBlock* next_; |
- }; |
- |
- HGraphBuilder* builder_; |
- bool finished_ : 1; |
- bool did_then_ : 1; |
- bool did_else_ : 1; |
- bool did_else_if_ : 1; |
- bool did_and_ : 1; |
- bool did_or_ : 1; |
- bool captured_ : 1; |
- bool needs_compare_ : 1; |
- bool pending_merge_block_ : 1; |
- HBasicBlock* first_true_block_; |
- HBasicBlock* first_false_block_; |
- HBasicBlock* split_edge_merge_block_; |
- MergeAtJoinBlock* merge_at_join_blocks_; |
- int normal_merge_at_join_block_count_; |
- int deopt_merge_at_join_block_count_; |
- }; |
- |
- class LoopBuilder final { |
- public: |
- enum Direction { |
- kPreIncrement, |
- kPostIncrement, |
- kPreDecrement, |
- kPostDecrement, |
- kWhileTrue |
- }; |
- |
- explicit LoopBuilder(HGraphBuilder* builder); // while (true) {...} |
- LoopBuilder(HGraphBuilder* builder, |
- HValue* context, |
- Direction direction); |
- LoopBuilder(HGraphBuilder* builder, |
- HValue* context, |
- Direction direction, |
- HValue* increment_amount); |
- |
- ~LoopBuilder() { |
- DCHECK(finished_); |
- } |
- |
- HValue* BeginBody( |
- HValue* initial, |
- HValue* terminating, |
- Token::Value token); |
- |
- void BeginBody(int drop_count); |
- |
- void Break(); |
- |
- void EndBody(); |
- |
- private: |
- void Initialize(HGraphBuilder* builder, HValue* context, |
- Direction direction, HValue* increment_amount); |
- Zone* zone() { return builder_->zone(); } |
- |
- HGraphBuilder* builder_; |
- HValue* context_; |
- HValue* increment_amount_; |
- HInstruction* increment_; |
- HPhi* phi_; |
- HBasicBlock* header_block_; |
- HBasicBlock* body_block_; |
- HBasicBlock* exit_block_; |
- HBasicBlock* exit_trampoline_block_; |
- Direction direction_; |
- bool finished_; |
- }; |
- |
- HValue* BuildNewElementsCapacity(HValue* old_capacity); |
- |
- class JSArrayBuilder final { |
- public: |
- JSArrayBuilder(HGraphBuilder* builder, |
- ElementsKind kind, |
- HValue* allocation_site_payload, |
- HValue* constructor_function, |
- AllocationSiteOverrideMode override_mode); |
- |
- JSArrayBuilder(HGraphBuilder* builder, |
- ElementsKind kind, |
- HValue* constructor_function = NULL); |
- |
- enum FillMode { |
- DONT_FILL_WITH_HOLE, |
- FILL_WITH_HOLE |
- }; |
- |
- ElementsKind kind() { return kind_; } |
- HAllocate* elements_location() { return elements_location_; } |
- |
- HAllocate* AllocateEmptyArray(); |
- HAllocate* AllocateArray(HValue* capacity, |
- HValue* length_field, |
- FillMode fill_mode = FILL_WITH_HOLE); |
- // Use these allocators when capacity could be unknown at compile time |
- // but its limit is known. For constant |capacity| the value of |
- // |capacity_upper_bound| is ignored and the actual |capacity| |
- // value is used as an upper bound. |
- HAllocate* AllocateArray(HValue* capacity, |
- int capacity_upper_bound, |
- HValue* length_field, |
- FillMode fill_mode = FILL_WITH_HOLE); |
- HAllocate* AllocateArray(HValue* capacity, |
- HConstant* capacity_upper_bound, |
- HValue* length_field, |
- FillMode fill_mode = FILL_WITH_HOLE); |
- HValue* GetElementsLocation() { return elements_location_; } |
- HValue* EmitMapCode(); |
- |
- private: |
- Zone* zone() const { return builder_->zone(); } |
- int elements_size() const { |
- return IsFastDoubleElementsKind(kind_) ? kDoubleSize : kPointerSize; |
- } |
- HGraphBuilder* builder() { return builder_; } |
- HGraph* graph() { return builder_->graph(); } |
- int initial_capacity() { |
- STATIC_ASSERT(JSArray::kPreallocatedArrayElements > 0); |
- return JSArray::kPreallocatedArrayElements; |
- } |
- |
- HValue* EmitInternalMapCode(); |
- |
- HGraphBuilder* builder_; |
- ElementsKind kind_; |
- AllocationSiteMode mode_; |
- HValue* allocation_site_payload_; |
- HValue* constructor_function_; |
- HAllocate* elements_location_; |
- }; |
- |
- HValue* BuildAllocateArrayFromLength(JSArrayBuilder* array_builder, |
- HValue* length_argument); |
- HValue* BuildCalculateElementsSize(ElementsKind kind, |
- HValue* capacity); |
- HAllocate* AllocateJSArrayObject(AllocationSiteMode mode); |
- HConstant* EstablishElementsAllocationSize(ElementsKind kind, int capacity); |
- |
- HAllocate* BuildAllocateElements(ElementsKind kind, HValue* size_in_bytes); |
- |
- void BuildInitializeElementsHeader(HValue* elements, |
- ElementsKind kind, |
- HValue* capacity); |
- |
- // Build allocation and header initialization code for respective successor |
- // of FixedArrayBase. |
- HValue* BuildAllocateAndInitializeArray(ElementsKind kind, HValue* capacity); |
- |
- // |array| must have been allocated with enough room for |
- // 1) the JSArray and 2) an AllocationMemento if mode requires it. |
- // If the |elements| value provided is NULL then the array elements storage |
- // is initialized with empty array. |
- void BuildJSArrayHeader(HValue* array, |
- HValue* array_map, |
- HValue* elements, |
- AllocationSiteMode mode, |
- ElementsKind elements_kind, |
- HValue* allocation_site_payload, |
- HValue* length_field); |
- |
- HValue* BuildGrowElementsCapacity(HValue* object, |
- HValue* elements, |
- ElementsKind kind, |
- ElementsKind new_kind, |
- HValue* length, |
- HValue* new_capacity); |
- |
- void BuildFillElementsWithValue(HValue* elements, |
- ElementsKind elements_kind, |
- HValue* from, |
- HValue* to, |
- HValue* value); |
- |
- void BuildFillElementsWithHole(HValue* elements, |
- ElementsKind elements_kind, |
- HValue* from, |
- HValue* to); |
- |
- void BuildCopyProperties(HValue* from_properties, HValue* to_properties, |
- HValue* length, HValue* capacity); |
- |
- void BuildCopyElements(HValue* from_elements, |
- ElementsKind from_elements_kind, |
- HValue* to_elements, |
- ElementsKind to_elements_kind, |
- HValue* length, |
- HValue* capacity); |
- |
- HValue* BuildCloneShallowArrayCow(HValue* boilerplate, |
- HValue* allocation_site, |
- AllocationSiteMode mode, |
- ElementsKind kind); |
- |
- HValue* BuildCloneShallowArrayEmpty(HValue* boilerplate, |
- HValue* allocation_site, |
- AllocationSiteMode mode); |
- |
- HValue* BuildCloneShallowArrayNonEmpty(HValue* boilerplate, |
- HValue* allocation_site, |
- AllocationSiteMode mode, |
- ElementsKind kind); |
- |
- HValue* BuildElementIndexHash(HValue* index); |
- |
- enum MapEmbedding { kEmbedMapsDirectly, kEmbedMapsViaWeakCells }; |
- |
- void BuildCompareNil(HValue* value, Type* type, HIfContinuation* continuation, |
- MapEmbedding map_embedding = kEmbedMapsDirectly); |
- |
- void BuildCreateAllocationMemento(HValue* previous_object, |
- HValue* previous_object_size, |
- HValue* payload); |
- |
- HInstruction* BuildConstantMapCheck(Handle<JSObject> constant); |
- HInstruction* BuildCheckPrototypeMaps(Handle<JSObject> prototype, |
- Handle<JSObject> holder); |
- |
- HInstruction* BuildGetNativeContext(HValue* closure); |
- HInstruction* BuildGetNativeContext(); |
- HInstruction* BuildGetScriptContext(int context_index); |
- // Builds a loop version if |depth| is specified or unrolls the loop to |
- // |depth_value| iterations otherwise. |
- HValue* BuildGetParentContext(HValue* depth, int depth_value); |
- |
- HInstruction* BuildGetArrayFunction(); |
- HValue* BuildArrayBufferViewFieldAccessor(HValue* object, |
- HValue* checked_object, |
- FieldIndex index); |
- |
- |
- protected: |
- void SetSourcePosition(int position) { |
- if (position != RelocInfo::kNoPosition) { |
- position_.set_position(position - start_position_); |
- } |
- // Otherwise position remains unknown. |
- } |
- |
- void EnterInlinedSource(int start_position, int id) { |
- if (top_info()->is_tracking_positions()) { |
- start_position_ = start_position; |
- position_.set_inlining_id(id); |
- } |
- } |
- |
- // Convert the given absolute offset from the start of the script to |
- // the SourcePosition assuming that this position corresponds to the |
- // same function as current position_. |
- SourcePosition ScriptPositionToSourcePosition(int position) { |
- if (position == RelocInfo::kNoPosition) { |
- return SourcePosition::Unknown(); |
- } |
- SourcePosition pos = position_; |
- pos.set_position(position - start_position_); |
- return pos; |
- } |
- |
- SourcePosition source_position() { return position_; } |
- void set_source_position(SourcePosition position) { position_ = position; } |
- |
- HValue* BuildAllocateEmptyArrayBuffer(HValue* byte_length); |
- template <typename ViewClass> |
- void BuildArrayBufferViewInitialization(HValue* obj, |
- HValue* buffer, |
- HValue* byte_offset, |
- HValue* byte_length); |
- |
- private: |
- HGraphBuilder(); |
- |
- template <class I> |
- I* AddInstructionTyped(I* instr) { |
- return I::cast(AddInstruction(instr)); |
- } |
- |
- CompilationInfo* info_; |
- HGraph* graph_; |
- HBasicBlock* current_block_; |
- Scope* scope_; |
- SourcePosition position_; |
- int start_position_; |
-}; |
- |
- |
-template <> |
-inline HDeoptimize* HGraphBuilder::Add<HDeoptimize>( |
- Deoptimizer::DeoptReason reason, Deoptimizer::BailoutType type) { |
- if (type == Deoptimizer::SOFT) { |
- isolate()->counters()->soft_deopts_requested()->Increment(); |
- if (FLAG_always_opt) return NULL; |
- } |
- if (current_block()->IsDeoptimizing()) return NULL; |
- HBasicBlock* after_deopt_block = CreateBasicBlock( |
- current_block()->last_environment()); |
- HDeoptimize* instr = New<HDeoptimize>(reason, type, after_deopt_block); |
- if (type == Deoptimizer::SOFT) { |
- isolate()->counters()->soft_deopts_inserted()->Increment(); |
- } |
- FinishCurrentBlock(instr); |
- set_current_block(after_deopt_block); |
- return instr; |
-} |
- |
- |
-template <> |
-inline HInstruction* HGraphBuilder::AddUncasted<HDeoptimize>( |
- Deoptimizer::DeoptReason reason, Deoptimizer::BailoutType type) { |
- return Add<HDeoptimize>(reason, type); |
-} |
- |
- |
-template<> |
-inline HSimulate* HGraphBuilder::Add<HSimulate>( |
- BailoutId id, |
- RemovableSimulate removable) { |
- HSimulate* instr = current_block()->CreateSimulate(id, removable); |
- AddInstruction(instr); |
- return instr; |
-} |
- |
- |
-template<> |
-inline HSimulate* HGraphBuilder::Add<HSimulate>( |
- BailoutId id) { |
- return Add<HSimulate>(id, FIXED_SIMULATE); |
-} |
- |
- |
-template<> |
-inline HInstruction* HGraphBuilder::AddUncasted<HSimulate>(BailoutId id) { |
- return Add<HSimulate>(id, FIXED_SIMULATE); |
-} |
- |
- |
-template<> |
-inline HReturn* HGraphBuilder::Add<HReturn>(HValue* value) { |
- int num_parameters = graph()->info()->num_parameters(); |
- HValue* params = AddUncasted<HConstant>(num_parameters); |
- HReturn* return_instruction = New<HReturn>(value, params); |
- FinishExitCurrentBlock(return_instruction); |
- return return_instruction; |
-} |
- |
- |
-template<> |
-inline HReturn* HGraphBuilder::Add<HReturn>(HConstant* value) { |
- return Add<HReturn>(static_cast<HValue*>(value)); |
-} |
- |
-template<> |
-inline HInstruction* HGraphBuilder::AddUncasted<HReturn>(HValue* value) { |
- return Add<HReturn>(value); |
-} |
- |
- |
-template<> |
-inline HInstruction* HGraphBuilder::AddUncasted<HReturn>(HConstant* value) { |
- return Add<HReturn>(value); |
-} |
- |
- |
-template<> |
-inline HCallRuntime* HGraphBuilder::Add<HCallRuntime>( |
- const Runtime::Function* c_function, |
- int argument_count) { |
- HCallRuntime* instr = New<HCallRuntime>(c_function, argument_count); |
- if (graph()->info()->IsStub()) { |
- // When compiling code stubs, we don't want to save all double registers |
- // upon entry to the stub, but instead have the call runtime instruction |
- // save the double registers only on-demand (in the fallback case). |
- instr->set_save_doubles(kSaveFPRegs); |
- } |
- AddInstruction(instr); |
- return instr; |
-} |
- |
- |
-template<> |
-inline HInstruction* HGraphBuilder::AddUncasted<HCallRuntime>( |
- Handle<String> name, |
- const Runtime::Function* c_function, |
- int argument_count) { |
- return Add<HCallRuntime>(c_function, argument_count); |
-} |
- |
- |
-template <> |
-inline HParameter* HGraphBuilder::New<HParameter>(unsigned index) { |
- return HParameter::New(isolate(), zone(), nullptr, index); |
-} |
- |
- |
-template <> |
-inline HParameter* HGraphBuilder::New<HParameter>( |
- unsigned index, HParameter::ParameterKind kind) { |
- return HParameter::New(isolate(), zone(), nullptr, index, kind); |
-} |
- |
- |
-template <> |
-inline HParameter* HGraphBuilder::New<HParameter>( |
- unsigned index, HParameter::ParameterKind kind, Representation r) { |
- return HParameter::New(isolate(), zone(), nullptr, index, kind, r); |
-} |
- |
- |
-template <> |
-inline HPrologue* HGraphBuilder::New<HPrologue>() { |
- return HPrologue::New(zone()); |
-} |
- |
- |
-template <> |
-inline HContext* HGraphBuilder::New<HContext>() { |
- return HContext::New(zone()); |
-} |
- |
- |
-class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { |
- public: |
- // A class encapsulating (lazily-allocated) break and continue blocks for |
- // a breakable statement. Separated from BreakAndContinueScope so that it |
- // can have a separate lifetime. |
- class BreakAndContinueInfo final BASE_EMBEDDED { |
- public: |
- explicit BreakAndContinueInfo(BreakableStatement* target, |
- Scope* scope, |
- int drop_extra = 0) |
- : target_(target), |
- break_block_(NULL), |
- continue_block_(NULL), |
- scope_(scope), |
- drop_extra_(drop_extra) { |
- } |
- |
- BreakableStatement* target() { return target_; } |
- HBasicBlock* break_block() { return break_block_; } |
- void set_break_block(HBasicBlock* block) { break_block_ = block; } |
- HBasicBlock* continue_block() { return continue_block_; } |
- void set_continue_block(HBasicBlock* block) { continue_block_ = block; } |
- Scope* scope() { return scope_; } |
- int drop_extra() { return drop_extra_; } |
- |
- private: |
- BreakableStatement* target_; |
- HBasicBlock* break_block_; |
- HBasicBlock* continue_block_; |
- Scope* scope_; |
- int drop_extra_; |
- }; |
- |
- // A helper class to maintain a stack of current BreakAndContinueInfo |
- // structures mirroring BreakableStatement nesting. |
- class BreakAndContinueScope final BASE_EMBEDDED { |
- public: |
- BreakAndContinueScope(BreakAndContinueInfo* info, |
- HOptimizedGraphBuilder* owner) |
- : info_(info), owner_(owner), next_(owner->break_scope()) { |
- owner->set_break_scope(this); |
- } |
- |
- ~BreakAndContinueScope() { owner_->set_break_scope(next_); } |
- |
- BreakAndContinueInfo* info() { return info_; } |
- HOptimizedGraphBuilder* owner() { return owner_; } |
- BreakAndContinueScope* next() { return next_; } |
- |
- // Search the break stack for a break or continue target. |
- enum BreakType { BREAK, CONTINUE }; |
- HBasicBlock* Get(BreakableStatement* stmt, BreakType type, |
- Scope** scope, int* drop_extra); |
- |
- private: |
- BreakAndContinueInfo* info_; |
- HOptimizedGraphBuilder* owner_; |
- BreakAndContinueScope* next_; |
- }; |
- |
- explicit HOptimizedGraphBuilder(CompilationInfo* info); |
- |
- bool BuildGraph() override; |
- |
- // Simple accessors. |
- BreakAndContinueScope* break_scope() const { return break_scope_; } |
- void set_break_scope(BreakAndContinueScope* head) { break_scope_ = head; } |
- |
- HValue* context() override { return environment()->context(); } |
- |
- HOsrBuilder* osr() const { return osr_; } |
- |
- void Bailout(BailoutReason reason); |
- |
- HBasicBlock* CreateJoin(HBasicBlock* first, |
- HBasicBlock* second, |
- BailoutId join_id); |
- |
- FunctionState* function_state() const { return function_state_; } |
- |
- void VisitDeclarations(ZoneList<Declaration*>* declarations) override; |
- |
- void* operator new(size_t size, Zone* zone) { return zone->New(size); } |
- void operator delete(void* pointer, Zone* zone) { } |
- void operator delete(void* pointer) { } |
- |
- DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); |
- |
- protected: |
- // Forward declarations for inner scope classes. |
- class SubgraphScope; |
- |
- static const int kMaxCallPolymorphism = 4; |
- static const int kMaxLoadPolymorphism = 4; |
- static const int kMaxStorePolymorphism = 4; |
- |
- // Even in the 'unlimited' case we have to have some limit in order not to |
- // overflow the stack. |
- static const int kUnlimitedMaxInlinedSourceSize = 100000; |
- static const int kUnlimitedMaxInlinedNodes = 10000; |
- static const int kUnlimitedMaxInlinedNodesCumulative = 10000; |
- |
- // Maximum depth and total number of elements and properties for literal |
- // graphs to be considered for fast deep-copying. |
- static const int kMaxFastLiteralDepth = 3; |
- static const int kMaxFastLiteralProperties = 8; |
- |
- // Simple accessors. |
- void set_function_state(FunctionState* state) { function_state_ = state; } |
- |
- AstContext* ast_context() const { return ast_context_; } |
- void set_ast_context(AstContext* context) { ast_context_ = context; } |
- |
- // Accessors forwarded to the function state. |
- CompilationInfo* current_info() const { |
- return function_state()->compilation_info(); |
- } |
- AstContext* call_context() const { |
- return function_state()->call_context(); |
- } |
- HBasicBlock* function_return() const { |
- return function_state()->function_return(); |
- } |
- TestContext* inlined_test_context() const { |
- return function_state()->test_context(); |
- } |
- Handle<SharedFunctionInfo> current_shared_info() const { |
- return current_info()->shared_info(); |
- } |
- TypeFeedbackVector* current_feedback_vector() const { |
- return current_shared_info()->feedback_vector(); |
- } |
- void ClearInlinedTestContext() { |
- function_state()->ClearInlinedTestContext(); |
- } |
- LanguageMode function_language_mode() { |
- return function_state()->compilation_info()->language_mode(); |
- } |
- |
-#define FOR_EACH_HYDROGEN_INTRINSIC(F) \ |
- F(IsSmi) \ |
- F(IsArray) \ |
- F(IsTypedArray) \ |
- F(IsRegExp) \ |
- F(IsJSProxy) \ |
- F(IsConstructCall) \ |
- F(Call) \ |
- F(CallFunction) \ |
- F(ArgumentsLength) \ |
- F(Arguments) \ |
- F(ValueOf) \ |
- F(SetValueOf) \ |
- F(IsDate) \ |
- F(DateField) \ |
- F(ThrowNotDateError) \ |
- F(StringCharFromCode) \ |
- F(StringCharAt) \ |
- F(OneByteSeqStringSetChar) \ |
- F(TwoByteSeqStringSetChar) \ |
- F(ObjectEquals) \ |
- F(ToInteger) \ |
- F(ToObject) \ |
- F(ToString) \ |
- F(ToLength) \ |
- F(ToNumber) \ |
- F(IsFunction) \ |
- F(IsSpecObject) \ |
- F(MathPow) \ |
- F(IsMinusZero) \ |
- F(HasCachedArrayIndex) \ |
- F(GetCachedArrayIndex) \ |
- F(FastOneByteArrayJoin) \ |
- F(DebugBreakInOptimizedCode) \ |
- F(StringCharCodeAt) \ |
- F(StringAdd) \ |
- F(SubString) \ |
- F(RegExpExec) \ |
- F(RegExpConstructResult) \ |
- F(NumberToString) \ |
- F(DebugIsActive) \ |
- F(Likely) \ |
- F(Unlikely) \ |
- F(HasInPrototypeChain) \ |
- /* Typed Arrays */ \ |
- F(TypedArrayInitialize) \ |
- F(DataViewInitialize) \ |
- F(MaxSmi) \ |
- F(TypedArrayMaxSizeInHeap) \ |
- F(ArrayBufferViewGetByteLength) \ |
- F(ArrayBufferViewGetByteOffset) \ |
- F(TypedArrayGetLength) \ |
- /* ArrayBuffer */ \ |
- F(ArrayBufferGetByteLength) \ |
- /* Maths */ \ |
- F(ConstructDouble) \ |
- F(DoubleHi) \ |
- F(DoubleLo) \ |
- F(MathClz32) \ |
- F(MathFloor) \ |
- F(MathSqrt) \ |
- F(MathLogRT) \ |
- /* ES6 Collections */ \ |
- F(MapClear) \ |
- F(MapInitialize) \ |
- F(SetClear) \ |
- F(SetInitialize) \ |
- F(FixedArrayGet) \ |
- F(FixedArraySet) \ |
- F(JSCollectionGetTable) \ |
- F(StringGetRawHashField) \ |
- F(TheHole) \ |
- /* ES6 Iterators */ \ |
- F(CreateIterResultObject) \ |
- /* Arrays */ \ |
- F(HasFastPackedElements) \ |
- /* Strings */ \ |
- F(StringGetLength) \ |
- /* JSValue */ \ |
- F(JSValueGetValue) |
- |
-#define GENERATOR_DECLARATION(Name) void Generate##Name(CallRuntime* call); |
- FOR_EACH_HYDROGEN_INTRINSIC(GENERATOR_DECLARATION) |
-#undef GENERATOR_DECLARATION |
- |
- void VisitDelete(UnaryOperation* expr); |
- void VisitVoid(UnaryOperation* expr); |
- void VisitTypeof(UnaryOperation* expr); |
- void VisitNot(UnaryOperation* expr); |
- |
- void VisitComma(BinaryOperation* expr); |
- void VisitLogicalExpression(BinaryOperation* expr); |
- void VisitArithmeticExpression(BinaryOperation* expr); |
- |
- void VisitLoopBody(IterationStatement* stmt, |
- HBasicBlock* loop_entry); |
- |
- void BuildForInBody(ForInStatement* stmt, Variable* each_var, |
- HValue* enumerable); |
- |
- // Create a back edge in the flow graph. body_exit is the predecessor |
- // block and loop_entry is the successor block. loop_successor is the |
- // block where control flow exits the loop normally (e.g., via failure of |
- // the condition) and break_block is the block where control flow breaks |
- // from the loop. All blocks except loop_entry can be NULL. The return |
- // value is the new successor block which is the join of loop_successor |
- // and break_block, or NULL. |
- HBasicBlock* CreateLoop(IterationStatement* statement, |
- HBasicBlock* loop_entry, |
- HBasicBlock* body_exit, |
- HBasicBlock* loop_successor, |
- HBasicBlock* break_block); |
- |
- // Build a loop entry |
- HBasicBlock* BuildLoopEntry(); |
- |
- // Builds a loop entry respectful of OSR requirements |
- HBasicBlock* BuildLoopEntry(IterationStatement* statement); |
- |
- HBasicBlock* JoinContinue(IterationStatement* statement, |
- HBasicBlock* exit_block, |
- HBasicBlock* continue_block); |
- |
- HValue* Top() const { return environment()->Top(); } |
- void Drop(int n) { environment()->Drop(n); } |
- void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); } |
- bool IsEligibleForEnvironmentLivenessAnalysis(Variable* var, |
- int index, |
- HValue* value, |
- HEnvironment* env) { |
- if (!FLAG_analyze_environment_liveness) return false; |
- // |this| and |arguments| are always live; zapping parameters isn't |
- // safe because function.arguments can inspect them at any time. |
- return !var->is_this() && |
- !var->is_arguments() && |
- !value->IsArgumentsObject() && |
- env->is_local_index(index); |
- } |
- void BindIfLive(Variable* var, HValue* value) { |
- HEnvironment* env = environment(); |
- int index = env->IndexFor(var); |
- env->Bind(index, value); |
- if (IsEligibleForEnvironmentLivenessAnalysis(var, index, value, env)) { |
- HEnvironmentMarker* bind = |
- Add<HEnvironmentMarker>(HEnvironmentMarker::BIND, index); |
- USE(bind); |
-#ifdef DEBUG |
- bind->set_closure(env->closure()); |
-#endif |
- } |
- } |
- HValue* LookupAndMakeLive(Variable* var) { |
- HEnvironment* env = environment(); |
- int index = env->IndexFor(var); |
- HValue* value = env->Lookup(index); |
- if (IsEligibleForEnvironmentLivenessAnalysis(var, index, value, env)) { |
- HEnvironmentMarker* lookup = |
- Add<HEnvironmentMarker>(HEnvironmentMarker::LOOKUP, index); |
- USE(lookup); |
-#ifdef DEBUG |
- lookup->set_closure(env->closure()); |
-#endif |
- } |
- return value; |
- } |
- |
- // The value of the arguments object is allowed in some but not most value |
- // contexts. (It's allowed in all effect contexts and disallowed in all |
- // test contexts.) |
- void VisitForValue(Expression* expr, |
- ArgumentsAllowedFlag flag = ARGUMENTS_NOT_ALLOWED); |
- void VisitForTypeOf(Expression* expr); |
- void VisitForEffect(Expression* expr); |
- void VisitForControl(Expression* expr, |
- HBasicBlock* true_block, |
- HBasicBlock* false_block); |
- |
- // Visit a list of expressions from left to right, each in a value context. |
- void VisitExpressions(ZoneList<Expression*>* exprs) override; |
- void VisitExpressions(ZoneList<Expression*>* exprs, |
- ArgumentsAllowedFlag flag); |
- |
- // Remove the arguments from the bailout environment and emit instructions |
- // to push them as outgoing parameters. |
- template <class Instruction> HInstruction* PreProcessCall(Instruction* call); |
- void PushArgumentsFromEnvironment(int count); |
- |
- void SetUpScope(Scope* scope); |
- void VisitStatements(ZoneList<Statement*>* statements) override; |
- |
-#define DECLARE_VISIT(type) virtual void Visit##type(type* node) override; |
- AST_NODE_LIST(DECLARE_VISIT) |
-#undef DECLARE_VISIT |
- |
- private: |
- // Helpers for flow graph construction. |
- enum GlobalPropertyAccess { |
- kUseCell, |
- kUseGeneric |
- }; |
- GlobalPropertyAccess LookupGlobalProperty(Variable* var, LookupIterator* it, |
- PropertyAccessType access_type); |
- |
- void EnsureArgumentsArePushedForAccess(); |
- bool TryArgumentsAccess(Property* expr); |
- |
- // Shared code for .call and .apply optimizations. |
- void HandleIndirectCall(Call* expr, HValue* function, int arguments_count); |
- // Try to optimize indirect calls such as fun.apply(receiver, arguments) |
- // or fun.call(...). |
- bool TryIndirectCall(Call* expr); |
- void BuildFunctionApply(Call* expr); |
- void BuildFunctionCall(Call* expr); |
- |
- bool TryHandleArrayCall(Call* expr, HValue* function); |
- bool TryHandleArrayCallNew(CallNew* expr, HValue* function); |
- void BuildArrayCall(Expression* expr, int arguments_count, HValue* function, |
- Handle<AllocationSite> cell); |
- |
- enum ArrayIndexOfMode { kFirstIndexOf, kLastIndexOf }; |
- HValue* BuildArrayIndexOf(HValue* receiver, |
- HValue* search_element, |
- ElementsKind kind, |
- ArrayIndexOfMode mode); |
- |
- HValue* ImplicitReceiverFor(HValue* function, |
- Handle<JSFunction> target); |
- |
- int InliningAstSize(Handle<JSFunction> target); |
- bool TryInline(Handle<JSFunction> target, int arguments_count, |
- HValue* implicit_return_value, BailoutId ast_id, |
- BailoutId return_id, InliningKind inlining_kind); |
- |
- bool TryInlineCall(Call* expr); |
- bool TryInlineConstruct(CallNew* expr, HValue* implicit_return_value); |
- bool TryInlineGetter(Handle<JSFunction> getter, |
- Handle<Map> receiver_map, |
- BailoutId ast_id, |
- BailoutId return_id); |
- bool TryInlineSetter(Handle<JSFunction> setter, |
- Handle<Map> receiver_map, |
- BailoutId id, |
- BailoutId assignment_id, |
- HValue* implicit_return_value); |
- bool TryInlineIndirectCall(Handle<JSFunction> function, Call* expr, |
- int arguments_count); |
- bool TryInlineBuiltinMethodCall(Call* expr, Handle<JSFunction> function, |
- Handle<Map> receiver_map, |
- int args_count_no_receiver); |
- bool TryInlineBuiltinFunctionCall(Call* expr); |
- enum ApiCallType { |
- kCallApiFunction, |
- kCallApiMethod, |
- kCallApiGetter, |
- kCallApiSetter |
- }; |
- bool TryInlineApiMethodCall(Call* expr, |
- HValue* receiver, |
- SmallMapList* receiver_types); |
- bool TryInlineApiFunctionCall(Call* expr, HValue* receiver); |
- bool TryInlineApiGetter(Handle<JSFunction> function, |
- Handle<Map> receiver_map, |
- BailoutId ast_id); |
- bool TryInlineApiSetter(Handle<JSFunction> function, |
- Handle<Map> receiver_map, |
- BailoutId ast_id); |
- bool TryInlineApiCall(Handle<JSFunction> function, |
- HValue* receiver, |
- SmallMapList* receiver_maps, |
- int argc, |
- BailoutId ast_id, |
- ApiCallType call_type); |
- static bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map); |
- static bool CanInlineArrayResizeOperation(Handle<Map> receiver_map); |
- |
- // If --trace-inlining, print a line of the inlining trace. Inlining |
- // succeeded if the reason string is NULL and failed if there is a |
- // non-NULL reason string. |
- void TraceInline(Handle<JSFunction> target, |
- Handle<JSFunction> caller, |
- const char* failure_reason); |
- |
- void HandleGlobalVariableAssignment(Variable* var, HValue* value, |
- FeedbackVectorSlot slot, |
- BailoutId ast_id); |
- |
- void HandlePropertyAssignment(Assignment* expr); |
- void HandleCompoundAssignment(Assignment* expr); |
- void HandlePolymorphicNamedFieldAccess( |
- PropertyAccessType access_type, Expression* expr, FeedbackVectorSlot slot, |
- BailoutId ast_id, BailoutId return_id, HValue* object, HValue* value, |
- SmallMapList* types, Handle<String> name); |
- |
- HValue* BuildAllocateExternalElements( |
- ExternalArrayType array_type, |
- bool is_zero_byte_offset, |
- HValue* buffer, HValue* byte_offset, HValue* length); |
- HValue* BuildAllocateFixedTypedArray(ExternalArrayType array_type, |
- size_t element_size, |
- ElementsKind fixed_elements_kind, |
- HValue* byte_length, HValue* length, |
- bool initialize); |
- |
- // TODO(adamk): Move all OrderedHashTable functions to their own class. |
- HValue* BuildOrderedHashTableHashToBucket(HValue* hash, HValue* num_buckets); |
- template <typename CollectionType> |
- HValue* BuildOrderedHashTableHashToEntry(HValue* table, HValue* hash, |
- HValue* num_buckets); |
- template <typename CollectionType> |
- HValue* BuildOrderedHashTableEntryToIndex(HValue* entry, HValue* num_buckets); |
- template <typename CollectionType> |
- HValue* BuildOrderedHashTableFindEntry(HValue* table, HValue* key, |
- HValue* hash); |
- template <typename CollectionType> |
- HValue* BuildOrderedHashTableAddEntry(HValue* table, HValue* key, |
- HValue* hash, |
- HIfContinuation* join_continuation); |
- template <typename CollectionType> |
- HValue* BuildAllocateOrderedHashTable(); |
- template <typename CollectionType> |
- void BuildOrderedHashTableClear(HValue* receiver); |
- template <typename CollectionType> |
- void BuildJSCollectionDelete(CallRuntime* call, |
- const Runtime::Function* c_function); |
- template <typename CollectionType> |
- void BuildJSCollectionHas(CallRuntime* call, |
- const Runtime::Function* c_function); |
- HValue* BuildStringHashLoadIfIsStringAndHashComputed( |
- HValue* object, HIfContinuation* continuation); |
- |
- Handle<JSFunction> array_function() { |
- return handle(isolate()->native_context()->array_function()); |
- } |
- |
- bool IsCallArrayInlineable(int argument_count, Handle<AllocationSite> site); |
- void BuildInlinedCallArray(Expression* expression, int argument_count, |
- Handle<AllocationSite> site); |
- |
- void BuildInitializeInobjectProperties(HValue* receiver, |
- Handle<Map> initial_map); |
- |
- class PropertyAccessInfo { |
- public: |
- PropertyAccessInfo(HOptimizedGraphBuilder* builder, |
- PropertyAccessType access_type, Handle<Map> map, |
- Handle<Name> name) |
- : builder_(builder), |
- access_type_(access_type), |
- map_(map), |
- name_(name), |
- field_type_(HType::Tagged()), |
- access_(HObjectAccess::ForMap()), |
- lookup_type_(NOT_FOUND), |
- details_(NONE, DATA, Representation::None()) {} |
- |
- // Checkes whether this PropertyAccessInfo can be handled as a monomorphic |
- // load named. It additionally fills in the fields necessary to generate the |
- // lookup code. |
- bool CanAccessMonomorphic(); |
- |
- // Checks whether all types behave uniform when loading name. If all maps |
- // behave the same, a single monomorphic load instruction can be emitted, |
- // guarded by a single map-checks instruction that whether the receiver is |
- // an instance of any of the types. |
- // This method skips the first type in types, assuming that this |
- // PropertyAccessInfo is built for types->first(). |
- bool CanAccessAsMonomorphic(SmallMapList* types); |
- |
- bool NeedsWrappingFor(Handle<JSFunction> target) const; |
- |
- Handle<Map> map(); |
- Handle<Name> name() const { return name_; } |
- |
- bool IsJSObjectFieldAccessor() { |
- int offset; // unused |
- return Accessors::IsJSObjectFieldAccessor(map_, name_, &offset); |
- } |
- |
- bool GetJSObjectFieldAccess(HObjectAccess* access) { |
- int offset; |
- if (Accessors::IsJSObjectFieldAccessor(map_, name_, &offset)) { |
- if (IsStringType()) { |
- DCHECK(Name::Equals(isolate()->factory()->length_string(), name_)); |
- *access = HObjectAccess::ForStringLength(); |
- } else if (IsArrayType()) { |
- DCHECK(Name::Equals(isolate()->factory()->length_string(), name_)); |
- *access = HObjectAccess::ForArrayLength(map_->elements_kind()); |
- } else { |
- *access = HObjectAccess::ForMapAndOffset(map_, offset); |
- } |
- return true; |
- } |
- return false; |
- } |
- |
- bool IsJSArrayBufferViewFieldAccessor() { |
- int offset; // unused |
- return Accessors::IsJSArrayBufferViewFieldAccessor(map_, name_, &offset); |
- } |
- |
- bool GetJSArrayBufferViewFieldAccess(HObjectAccess* access) { |
- int offset; |
- if (Accessors::IsJSArrayBufferViewFieldAccessor(map_, name_, &offset)) { |
- *access = HObjectAccess::ForMapAndOffset(map_, offset); |
- return true; |
- } |
- return false; |
- } |
- |
- bool has_holder() { return !holder_.is_null(); } |
- bool IsLoad() const { return access_type_ == LOAD; } |
- |
- Isolate* isolate() const { return builder_->isolate(); } |
- Handle<JSObject> holder() { return holder_; } |
- Handle<JSFunction> accessor() { return accessor_; } |
- Handle<Object> constant() { return constant_; } |
- Handle<Map> transition() { return transition_; } |
- SmallMapList* field_maps() { return &field_maps_; } |
- HType field_type() const { return field_type_; } |
- HObjectAccess access() { return access_; } |
- |
- bool IsFound() const { return lookup_type_ != NOT_FOUND; } |
- bool IsProperty() const { return IsFound() && !IsTransition(); } |
- bool IsTransition() const { return lookup_type_ == TRANSITION_TYPE; } |
- bool IsData() const { |
- return lookup_type_ == DESCRIPTOR_TYPE && details_.type() == DATA; |
- } |
- bool IsDataConstant() const { |
- return lookup_type_ == DESCRIPTOR_TYPE && |
- details_.type() == DATA_CONSTANT; |
- } |
- bool IsAccessorConstant() const { |
- return !IsTransition() && details_.type() == ACCESSOR_CONSTANT; |
- } |
- bool IsConfigurable() const { return details_.IsConfigurable(); } |
- bool IsReadOnly() const { return details_.IsReadOnly(); } |
- |
- bool IsStringType() { return map_->instance_type() < FIRST_NONSTRING_TYPE; } |
- bool IsNumberType() { return map_->instance_type() == HEAP_NUMBER_TYPE; } |
- bool IsValueWrapped() { return IsStringType() || IsNumberType(); } |
- bool IsArrayType() { return map_->instance_type() == JS_ARRAY_TYPE; } |
- |
- private: |
- Handle<Object> GetConstantFromMap(Handle<Map> map) const { |
- DCHECK_EQ(DESCRIPTOR_TYPE, lookup_type_); |
- DCHECK(number_ < map->NumberOfOwnDescriptors()); |
- return handle(map->instance_descriptors()->GetValue(number_), isolate()); |
- } |
- Handle<Object> GetAccessorsFromMap(Handle<Map> map) const { |
- return GetConstantFromMap(map); |
- } |
- Handle<HeapType> GetFieldTypeFromMap(Handle<Map> map) const { |
- DCHECK(IsFound()); |
- DCHECK(number_ < map->NumberOfOwnDescriptors()); |
- return handle(map->instance_descriptors()->GetFieldType(number_), |
- isolate()); |
- } |
- Handle<Map> GetFieldOwnerFromMap(Handle<Map> map) const { |
- DCHECK(IsFound()); |
- DCHECK(number_ < map->NumberOfOwnDescriptors()); |
- return handle(map->FindFieldOwner(number_)); |
- } |
- int GetLocalFieldIndexFromMap(Handle<Map> map) const { |
- DCHECK(lookup_type_ == DESCRIPTOR_TYPE || |
- lookup_type_ == TRANSITION_TYPE); |
- DCHECK(number_ < map->NumberOfOwnDescriptors()); |
- int field_index = map->instance_descriptors()->GetFieldIndex(number_); |
- return field_index - map->GetInObjectProperties(); |
- } |
- |
- void LookupDescriptor(Map* map, Name* name) { |
- DescriptorArray* descriptors = map->instance_descriptors(); |
- int number = descriptors->SearchWithCache(name, map); |
- if (number == DescriptorArray::kNotFound) return NotFound(); |
- lookup_type_ = DESCRIPTOR_TYPE; |
- details_ = descriptors->GetDetails(number); |
- number_ = number; |
- } |
- void LookupTransition(Map* map, Name* name, PropertyAttributes attributes) { |
- Map* target = |
- TransitionArray::SearchTransition(map, kData, name, attributes); |
- if (target == NULL) return NotFound(); |
- lookup_type_ = TRANSITION_TYPE; |
- transition_ = handle(target); |
- number_ = transition_->LastAdded(); |
- details_ = transition_->instance_descriptors()->GetDetails(number_); |
- } |
- void NotFound() { |
- lookup_type_ = NOT_FOUND; |
- details_ = PropertyDetails::Empty(); |
- } |
- Representation representation() const { |
- DCHECK(IsFound()); |
- return details_.representation(); |
- } |
- bool IsTransitionToData() const { |
- return IsTransition() && details_.type() == DATA; |
- } |
- |
- Zone* zone() { return builder_->zone(); } |
- CompilationInfo* top_info() { return builder_->top_info(); } |
- CompilationInfo* current_info() { return builder_->current_info(); } |
- |
- bool LoadResult(Handle<Map> map); |
- bool LoadFieldMaps(Handle<Map> map); |
- bool LookupDescriptor(); |
- bool LookupInPrototypes(); |
- bool IsIntegerIndexedExotic(); |
- bool IsCompatible(PropertyAccessInfo* other); |
- |
- void GeneralizeRepresentation(Representation r) { |
- access_ = access_.WithRepresentation( |
- access_.representation().generalize(r)); |
- } |
- |
- HOptimizedGraphBuilder* builder_; |
- PropertyAccessType access_type_; |
- Handle<Map> map_; |
- Handle<Name> name_; |
- Handle<JSObject> holder_; |
- Handle<JSFunction> accessor_; |
- Handle<JSObject> api_holder_; |
- Handle<Object> constant_; |
- SmallMapList field_maps_; |
- HType field_type_; |
- HObjectAccess access_; |
- |
- enum { NOT_FOUND, DESCRIPTOR_TYPE, TRANSITION_TYPE } lookup_type_; |
- Handle<Map> transition_; |
- int number_; |
- PropertyDetails details_; |
- }; |
- |
- HValue* BuildMonomorphicAccess(PropertyAccessInfo* info, HValue* object, |
- HValue* checked_object, HValue* value, |
- BailoutId ast_id, BailoutId return_id, |
- bool can_inline_accessor = true); |
- |
- HValue* BuildNamedAccess(PropertyAccessType access, BailoutId ast_id, |
- BailoutId reutrn_id, Expression* expr, |
- FeedbackVectorSlot slot, HValue* object, |
- Handle<String> name, HValue* value, |
- bool is_uninitialized = false); |
- |
- void HandlePolymorphicCallNamed(Call* expr, |
- HValue* receiver, |
- SmallMapList* types, |
- Handle<String> name); |
- void HandleLiteralCompareTypeof(CompareOperation* expr, |
- Expression* sub_expr, |
- Handle<String> check); |
- void HandleLiteralCompareNil(CompareOperation* expr, |
- Expression* sub_expr, |
- NilValue nil); |
- |
- enum PushBeforeSimulateBehavior { |
- PUSH_BEFORE_SIMULATE, |
- NO_PUSH_BEFORE_SIMULATE |
- }; |
- |
- HControlInstruction* BuildCompareInstruction( |
- Token::Value op, HValue* left, HValue* right, Type* left_type, |
- Type* right_type, Type* combined_type, SourcePosition left_position, |
- SourcePosition right_position, PushBeforeSimulateBehavior push_sim_result, |
- BailoutId bailout_id); |
- |
- HInstruction* BuildStringCharCodeAt(HValue* string, |
- HValue* index); |
- |
- HValue* BuildBinaryOperation( |
- BinaryOperation* expr, |
- HValue* left, |
- HValue* right, |
- PushBeforeSimulateBehavior push_sim_result); |
- HInstruction* BuildIncrement(bool returns_original_input, |
- CountOperation* expr); |
- HInstruction* BuildKeyedGeneric(PropertyAccessType access_type, |
- Expression* expr, FeedbackVectorSlot slot, |
- HValue* object, HValue* key, HValue* value); |
- |
- HInstruction* TryBuildConsolidatedElementLoad(HValue* object, |
- HValue* key, |
- HValue* val, |
- SmallMapList* maps); |
- |
- LoadKeyedHoleMode BuildKeyedHoleMode(Handle<Map> map); |
- |
- HInstruction* BuildMonomorphicElementAccess(HValue* object, |
- HValue* key, |
- HValue* val, |
- HValue* dependency, |
- Handle<Map> map, |
- PropertyAccessType access_type, |
- KeyedAccessStoreMode store_mode); |
- |
- HValue* HandlePolymorphicElementAccess( |
- Expression* expr, FeedbackVectorSlot slot, HValue* object, HValue* key, |
- HValue* val, SmallMapList* maps, PropertyAccessType access_type, |
- KeyedAccessStoreMode store_mode, bool* has_side_effects); |
- |
- HValue* HandleKeyedElementAccess(HValue* obj, HValue* key, HValue* val, |
- Expression* expr, FeedbackVectorSlot slot, |
- BailoutId ast_id, BailoutId return_id, |
- PropertyAccessType access_type, |
- bool* has_side_effects); |
- |
- HInstruction* BuildNamedGeneric(PropertyAccessType access, Expression* expr, |
- FeedbackVectorSlot slot, HValue* object, |
- Handle<Name> name, HValue* value, |
- bool is_uninitialized = false); |
- |
- HCheckMaps* AddCheckMap(HValue* object, Handle<Map> map); |
- |
- void BuildLoad(Property* property, |
- BailoutId ast_id); |
- void PushLoad(Property* property, |
- HValue* object, |
- HValue* key); |
- |
- void BuildStoreForEffect(Expression* expression, Property* prop, |
- FeedbackVectorSlot slot, BailoutId ast_id, |
- BailoutId return_id, HValue* object, HValue* key, |
- HValue* value); |
- |
- void BuildStore(Expression* expression, Property* prop, |
- FeedbackVectorSlot slot, BailoutId ast_id, |
- BailoutId return_id, bool is_uninitialized = false); |
- |
- HInstruction* BuildLoadNamedField(PropertyAccessInfo* info, |
- HValue* checked_object); |
- HInstruction* BuildStoreNamedField(PropertyAccessInfo* info, |
- HValue* checked_object, |
- HValue* value); |
- |
- HValue* BuildContextChainWalk(Variable* var); |
- |
- HInstruction* BuildThisFunction(); |
- |
- HInstruction* BuildFastLiteral(Handle<JSObject> boilerplate_object, |
- AllocationSiteUsageContext* site_context); |
- |
- void BuildEmitObjectHeader(Handle<JSObject> boilerplate_object, |
- HInstruction* object); |
- |
- void BuildEmitInObjectProperties(Handle<JSObject> boilerplate_object, |
- HInstruction* object, |
- AllocationSiteUsageContext* site_context, |
- PretenureFlag pretenure_flag); |
- |
- void BuildEmitElements(Handle<JSObject> boilerplate_object, |
- Handle<FixedArrayBase> elements, |
- HValue* object_elements, |
- AllocationSiteUsageContext* site_context); |
- |
- void BuildEmitFixedDoubleArray(Handle<FixedArrayBase> elements, |
- ElementsKind kind, |
- HValue* object_elements); |
- |
- void BuildEmitFixedArray(Handle<FixedArrayBase> elements, |
- ElementsKind kind, |
- HValue* object_elements, |
- AllocationSiteUsageContext* site_context); |
- |
- void AddCheckPrototypeMaps(Handle<JSObject> holder, |
- Handle<Map> receiver_map); |
- |
- HInstruction* NewPlainFunctionCall(HValue* fun, int argument_count); |
- |
- HInstruction* NewArgumentAdaptorCall(HValue* fun, HValue* context, |
- int argument_count, |
- HValue* expected_param_count); |
- |
- HInstruction* BuildCallConstantFunction(Handle<JSFunction> target, |
- int argument_count); |
- |
- bool CanBeFunctionApplyArguments(Call* expr); |
- |
- // The translation state of the currently-being-translated function. |
- FunctionState* function_state_; |
- |
- // The base of the function state stack. |
- FunctionState initial_function_state_; |
- |
- // Expression context of the currently visited subexpression. NULL when |
- // visiting statements. |
- AstContext* ast_context_; |
- |
- // A stack of breakable statements entered. |
- BreakAndContinueScope* break_scope_; |
- |
- int inlined_count_; |
- ZoneList<Handle<Object> > globals_; |
- |
- bool inline_bailout_; |
- |
- HOsrBuilder* osr_; |
- |
- friend class FunctionState; // Pushes and pops the state stack. |
- friend class AstContext; // Pushes and pops the AST context stack. |
- friend class KeyedLoadFastElementStub; |
- friend class HOsrBuilder; |
- |
- DISALLOW_COPY_AND_ASSIGN(HOptimizedGraphBuilder); |
-}; |
- |
- |
-Zone* AstContext::zone() const { return owner_->zone(); } |
- |
- |
-class HStatistics final : public Malloced { |
- public: |
- HStatistics() |
- : times_(5), |
- names_(5), |
- sizes_(5), |
- total_size_(0), |
- source_size_(0) { } |
- |
- void Initialize(CompilationInfo* info); |
- void Print(); |
- void SaveTiming(const char* name, base::TimeDelta time, size_t size); |
- |
- void IncrementFullCodeGen(base::TimeDelta full_code_gen) { |
- full_code_gen_ += full_code_gen; |
- } |
- |
- void IncrementCreateGraph(base::TimeDelta delta) { create_graph_ += delta; } |
- |
- void IncrementOptimizeGraph(base::TimeDelta delta) { |
- optimize_graph_ += delta; |
- } |
- |
- void IncrementGenerateCode(base::TimeDelta delta) { generate_code_ += delta; } |
- |
- void IncrementSubtotals(base::TimeDelta create_graph, |
- base::TimeDelta optimize_graph, |
- base::TimeDelta generate_code) { |
- IncrementCreateGraph(create_graph); |
- IncrementOptimizeGraph(optimize_graph); |
- IncrementGenerateCode(generate_code); |
- } |
- |
- private: |
- List<base::TimeDelta> times_; |
- List<const char*> names_; |
- List<size_t> sizes_; |
- base::TimeDelta create_graph_; |
- base::TimeDelta optimize_graph_; |
- base::TimeDelta generate_code_; |
- size_t total_size_; |
- base::TimeDelta full_code_gen_; |
- double source_size_; |
-}; |
- |
- |
-class HPhase : public CompilationPhase { |
- public: |
- HPhase(const char* name, HGraph* graph) |
- : CompilationPhase(name, graph->info()), |
- graph_(graph) { } |
- ~HPhase(); |
- |
- protected: |
- HGraph* graph() const { return graph_; } |
- |
- private: |
- HGraph* graph_; |
- |
- DISALLOW_COPY_AND_ASSIGN(HPhase); |
-}; |
- |
- |
-class HTracer final : public Malloced { |
- public: |
- explicit HTracer(int isolate_id) |
- : trace_(&string_allocator_), indent_(0) { |
- if (FLAG_trace_hydrogen_file == NULL) { |
- SNPrintF(filename_, |
- "hydrogen-%d-%d.cfg", |
- base::OS::GetCurrentProcessId(), |
- isolate_id); |
- } else { |
- StrNCpy(filename_, FLAG_trace_hydrogen_file, filename_.length()); |
- } |
- WriteChars(filename_.start(), "", 0, false); |
- } |
- |
- void TraceCompilation(CompilationInfo* info); |
- void TraceHydrogen(const char* name, HGraph* graph); |
- void TraceLithium(const char* name, LChunk* chunk); |
- void TraceLiveRanges(const char* name, LAllocator* allocator); |
- |
- private: |
- class Tag final BASE_EMBEDDED { |
- public: |
- Tag(HTracer* tracer, const char* name) { |
- name_ = name; |
- tracer_ = tracer; |
- tracer->PrintIndent(); |
- tracer->trace_.Add("begin_%s\n", name); |
- tracer->indent_++; |
- } |
- |
- ~Tag() { |
- tracer_->indent_--; |
- tracer_->PrintIndent(); |
- tracer_->trace_.Add("end_%s\n", name_); |
- DCHECK(tracer_->indent_ >= 0); |
- tracer_->FlushToFile(); |
- } |
- |
- private: |
- HTracer* tracer_; |
- const char* name_; |
- }; |
- |
- void TraceLiveRange(LiveRange* range, const char* type, Zone* zone); |
- void Trace(const char* name, HGraph* graph, LChunk* chunk); |
- void FlushToFile(); |
- |
- void PrintEmptyProperty(const char* name) { |
- PrintIndent(); |
- trace_.Add("%s\n", name); |
- } |
- |
- void PrintStringProperty(const char* name, const char* value) { |
- PrintIndent(); |
- trace_.Add("%s \"%s\"\n", name, value); |
- } |
- |
- void PrintLongProperty(const char* name, int64_t value) { |
- PrintIndent(); |
- trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000)); |
- } |
- |
- void PrintBlockProperty(const char* name, int block_id) { |
- PrintIndent(); |
- trace_.Add("%s \"B%d\"\n", name, block_id); |
- } |
- |
- void PrintIntProperty(const char* name, int value) { |
- PrintIndent(); |
- trace_.Add("%s %d\n", name, value); |
- } |
- |
- void PrintIndent() { |
- for (int i = 0; i < indent_; i++) { |
- trace_.Add(" "); |
- } |
- } |
- |
- EmbeddedVector<char, 64> filename_; |
- HeapStringAllocator string_allocator_; |
- StringStream trace_; |
- int indent_; |
-}; |
- |
- |
-class NoObservableSideEffectsScope final { |
- public: |
- explicit NoObservableSideEffectsScope(HGraphBuilder* builder) : |
- builder_(builder) { |
- builder_->graph()->IncrementInNoSideEffectsScope(); |
- } |
- ~NoObservableSideEffectsScope() { |
- builder_->graph()->DecrementInNoSideEffectsScope(); |
- } |
- |
- private: |
- HGraphBuilder* builder_; |
-}; |
- |
- |
-} // namespace internal |
-} // namespace v8 |
- |
-#endif // V8_HYDROGEN_H_ |