| 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_
|
|
|