| Index: runtime/vm/intermediate_language.h
|
| diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
|
| index 3cb88931a46315cd33e82f6f792ecf05df1915f3..17bec51d74c5c7d32c7c60db8d739427f80f17e6 100644
|
| --- a/runtime/vm/intermediate_language.h
|
| +++ b/runtime/vm/intermediate_language.h
|
| @@ -14,6 +14,20 @@
|
|
|
| namespace dart {
|
|
|
| +class BindInstr;
|
| +class BitVector;
|
| +class BlockEntryInstr;
|
| +class BufferFormatter;
|
| +class ComparisonComp;
|
| +class Computation;
|
| +class Definition;
|
| +class Environment;
|
| +class FlowGraphCompiler;
|
| +class FlowGraphVisitor;
|
| +class Instruction;
|
| +class LocalVariable;
|
| +
|
| +
|
| // TODO(srdjan): Add _ByteArrayBase, get:length.
|
|
|
| #define RECOGNIZED_LIST(V) \
|
| @@ -42,293 +56,316 @@ RECOGNIZED_LIST(DEFINE_ENUM_LIST)
|
| };
|
|
|
|
|
| -class BitVector;
|
| -class FlowGraphAllocator;
|
| -class FlowGraphCompiler;
|
| -class FlowGraphVisitor;
|
| -class Function;
|
| -class LocalVariable;
|
| -
|
| -// M is a two argument macro. It is applied to each concrete instruction's
|
| -// (including the values) typename and classname.
|
| -#define FOR_EACH_COMPUTATION(M) \
|
| - M(AssertAssignable, AssertAssignableComp) \
|
| - M(AssertBoolean, AssertBooleanComp) \
|
| - M(ArgumentDefinitionTest, ArgumentDefinitionTestComp) \
|
| - M(CurrentContext, CurrentContextComp) \
|
| - M(StoreContext, StoreContextComp) \
|
| - M(ClosureCall, ClosureCallComp) \
|
| - M(InstanceCall, InstanceCallComp) \
|
| - M(PolymorphicInstanceCall, PolymorphicInstanceCallComp) \
|
| - M(StaticCall, StaticCallComp) \
|
| - M(LoadLocal, LoadLocalComp) \
|
| - M(StoreLocal, StoreLocalComp) \
|
| - M(StrictCompare, StrictCompareComp) \
|
| - M(EqualityCompare, EqualityCompareComp) \
|
| - M(RelationalOp, RelationalOpComp) \
|
| - M(NativeCall, NativeCallComp) \
|
| - M(LoadIndexed, LoadIndexedComp) \
|
| - M(StoreIndexed, StoreIndexedComp) \
|
| - M(LoadInstanceField, LoadInstanceFieldComp) \
|
| - M(StoreInstanceField, StoreInstanceFieldComp) \
|
| - M(LoadStaticField, LoadStaticFieldComp) \
|
| - M(StoreStaticField, StoreStaticFieldComp) \
|
| - M(BooleanNegate, BooleanNegateComp) \
|
| - M(InstanceOf, InstanceOfComp) \
|
| - M(CreateArray, CreateArrayComp) \
|
| - M(CreateClosure, CreateClosureComp) \
|
| - M(AllocateObject, AllocateObjectComp) \
|
| - M(AllocateObjectWithBoundsCheck, AllocateObjectWithBoundsCheckComp) \
|
| - M(LoadVMField, LoadVMFieldComp) \
|
| - M(StoreVMField, StoreVMFieldComp) \
|
| - M(InstantiateTypeArguments, InstantiateTypeArgumentsComp) \
|
| - M(ExtractConstructorTypeArguments, ExtractConstructorTypeArgumentsComp) \
|
| - M(ExtractConstructorInstantiator, ExtractConstructorInstantiatorComp) \
|
| - M(AllocateContext, AllocateContextComp) \
|
| - M(ChainContext, ChainContextComp) \
|
| - M(CloneContext, CloneContextComp) \
|
| - M(CatchEntry, CatchEntryComp) \
|
| - M(BinarySmiOp, BinarySmiOpComp) \
|
| - M(BinaryMintOp, BinaryMintOpComp) \
|
| - M(BinaryDoubleOp, BinaryDoubleOpComp) \
|
| - M(UnarySmiOp, UnarySmiOpComp) \
|
| - M(NumberNegate, NumberNegateComp) \
|
| - M(CheckStackOverflow, CheckStackOverflowComp) \
|
| - M(DoubleToDouble, DoubleToDoubleComp) \
|
| - M(SmiToDouble, SmiToDoubleComp) \
|
| - M(CheckClass, CheckClassComp) \
|
| - M(CheckSmi, CheckSmiComp) \
|
| - M(Constant, ConstantComp) \
|
| - M(CheckEitherNonSmi, CheckEitherNonSmiComp) \
|
| - M(UnboxedDoubleBinaryOp, UnboxedDoubleBinaryOpComp) \
|
| - M(UnboxDouble, UnboxDoubleComp) \
|
| - M(BoxDouble, BoxDoubleComp) \
|
| - M(CheckArrayBound, CheckArrayBoundComp)
|
| -
|
| +class Value : public ZoneAllocated {
|
| + public:
|
| + explicit Value(Definition* definition)
|
| + : definition_(definition),
|
| + next_use_(NULL),
|
| + instruction_(NULL),
|
| + use_index_(-1) { }
|
|
|
| -#define FORWARD_DECLARATION(ShortName, ClassName) class ClassName;
|
| -FOR_EACH_COMPUTATION(FORWARD_DECLARATION)
|
| -#undef FORWARD_DECLARATION
|
| + Definition* definition() const { return definition_; }
|
| + void set_definition(Definition* definition) { definition_ = definition; }
|
|
|
| -// Forward declarations.
|
| -class BindInstr;
|
| -class BranchInstr;
|
| -class BufferFormatter;
|
| -class ComparisonComp;
|
| -class Definition;
|
| -class Definition;
|
| -class Instruction;
|
| -class PhiInstr;
|
| -class PushArgumentInstr;
|
| -class Value;
|
| + Value* next_use() const { return next_use_; }
|
| + void set_next_use(Value* next) { next_use_ = next; }
|
|
|
| + Instruction* instruction() const { return instruction_; }
|
| + void set_instruction(Instruction* instruction) { instruction_ = instruction; }
|
|
|
| -enum Representation {
|
| - kTagged, kUnboxedDouble
|
| -};
|
| + intptr_t use_index() const { return use_index_; }
|
| + void set_use_index(intptr_t index) { use_index_ = index; }
|
|
|
| + void AddToInputUseList();
|
| + void AddToEnvUseList();
|
|
|
| -class Computation : public ZoneAllocated {
|
| - public:
|
| - Computation()
|
| - : deopt_id_(Isolate::Current()->GetNextDeoptId()), locs_(NULL) { }
|
| + Value* Copy() { return new Value(definition_); }
|
|
|
| - // Unique id used for deoptimization.
|
| - virtual intptr_t deopt_id() const {
|
| - ASSERT(CanDeoptimize());
|
| - return deopt_id_;
|
| - }
|
| + RawAbstractType* CompileType() const;
|
| + intptr_t ResultCid() const;
|
|
|
| - // Visiting support.
|
| - virtual void Accept(FlowGraphVisitor* visitor, BindInstr* instr) = 0;
|
| + void PrintTo(BufferFormatter* f) const;
|
|
|
| - virtual intptr_t InputCount() const = 0;
|
| - virtual Value* InputAt(intptr_t i) const = 0;
|
| - virtual void SetInputAt(intptr_t i, Value* value) = 0;
|
| + const char* DebugName() const { return "Value"; }
|
|
|
| - // Call computations override this function and return the
|
| - // number of pushed arguments.
|
| - virtual intptr_t ArgumentCount() const = 0;
|
| + // Returns true if the value represents a constant.
|
| + bool BindsToConstant() const;
|
|
|
| - // Returns true, if this computation can deoptimize.
|
| - virtual bool CanDeoptimize() const = 0;
|
| + // Returns true if the value represents the constant null.
|
| + bool BindsToConstantNull() const;
|
|
|
| - // Returns a replacement for the instruction that wraps this computation.
|
| - // Returns NULL if instr can be eliminated.
|
| - // By default returns instr (input parameter) which means no change.
|
| - virtual Definition* TryReplace(BindInstr* instr) const;
|
| + // Assert if BindsToConstant() is false, otherwise returns the constant value.
|
| + const Object& BoundConstant() const;
|
|
|
| - // Compares two computations. Returns true, if:
|
| - // 1. They are of the same kind.
|
| - // 2. All input operands match.
|
| - // 3. All other attributes match.
|
| - bool Equals(Computation* other) const;
|
| + // Reminder: The type of the constant null is the bottom type, which is more
|
| + // specific than any type.
|
| + bool CompileTypeIsMoreSpecificThan(const AbstractType& dst_type) const;
|
|
|
| - // Returns a hash code for use with hash maps.
|
| - virtual intptr_t Hashcode() const;
|
| + // Compile time constants, Bool, Smi and Nulls do not need to update
|
| + // the store buffer.
|
| + bool NeedsStoreBuffer() const;
|
|
|
| - // Compare attributes of an computation (except input operands and kind).
|
| - // All computations that participate in CSE have to override this function.
|
| - virtual bool AttributesEqual(Computation* other) const {
|
| - UNREACHABLE();
|
| - return false;
|
| - }
|
| + bool Equals(Value* other) const;
|
|
|
| - // Returns true if the instruction may have side effects.
|
| - // TODO(fschneider): Make this abstract and implement for all computations
|
| - // instead of returning the safe default (true).
|
| - virtual bool HasSideEffect() const { return true; }
|
| + private:
|
| + Definition* definition_;
|
| + Value* next_use_;
|
| + Instruction* instruction_;
|
| + intptr_t use_index_;
|
|
|
| - // Compile time type of the computation, which typically depends on the
|
| - // compile time types (and possibly propagated types) of its inputs.
|
| - virtual RawAbstractType* CompileType() const = 0;
|
| - virtual intptr_t ResultCid() const = 0;
|
| + DISALLOW_COPY_AND_ASSIGN(Value);
|
| +};
|
|
|
| - // Mutate assigned_vars to add the local variable index for all
|
| - // frame-allocated locals assigned to by the computation.
|
| - virtual void RecordAssignedVars(BitVector* assigned_vars,
|
| - intptr_t fixed_parameter_count);
|
|
|
| - virtual const char* DebugName() const = 0;
|
| +enum Representation {
|
| + kTagged, kUnboxedDouble
|
| +};
|
|
|
| - // Printing support. These functions are sometimes overridden for custom
|
| - // formatting. Otherwise, it prints in the format "opcode(op1, op2, op3)".
|
| - virtual void PrintTo(BufferFormatter* f) const;
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - // Returns structure describing location constraints required
|
| - // to emit native code for this computation.
|
| - LocationSummary* locs() {
|
| - if (locs_ == NULL) {
|
| - locs_ = MakeLocationSummary();
|
| - }
|
| - return locs_;
|
| +// An embedded container with N elements of type T. Used (with partial
|
| +// specialization for N=0) because embedded arrays cannot have size 0.
|
| +template<typename T, intptr_t N>
|
| +class EmbeddedArray {
|
| + public:
|
| + EmbeddedArray() {
|
| + for (intptr_t i = 0; i < N; i++) elements_[i] = NULL;
|
| }
|
|
|
| - virtual ComparisonComp* AsComparison() { return NULL; }
|
| -
|
| - // Create a location summary for this computation.
|
| - // TODO(fschneider): Temporarily returns NULL for instructions
|
| - // that are not yet converted to the location based code generation.
|
| - virtual LocationSummary* MakeLocationSummary() const = 0;
|
| -
|
| - // TODO(fschneider): Make EmitNativeCode and locs const.
|
| - virtual void EmitNativeCode(FlowGraphCompiler* compiler) = 0;
|
| + intptr_t length() const { return N; }
|
|
|
| - virtual void EmitBranchCode(FlowGraphCompiler* compiler,
|
| - BranchInstr* branch) {
|
| - UNREACHABLE();
|
| + const T& operator[](intptr_t i) const {
|
| + ASSERT(i < length());
|
| + return elements_[i];
|
| }
|
|
|
| - static LocationSummary* MakeCallSummary();
|
| + T& operator[](intptr_t i) {
|
| + ASSERT(i < length());
|
| + return elements_[i];
|
| + }
|
|
|
| - // Declare an enum value used to define kind-test predicates.
|
| - enum ComputationKind {
|
| -#define DECLARE_COMPUTATION_KIND(ShortName, ClassName) k##ShortName,
|
| + const T& At(intptr_t i) const {
|
| + return (*this)[i];
|
| + }
|
|
|
| - FOR_EACH_COMPUTATION(DECLARE_COMPUTATION_KIND)
|
| + void SetAt(intptr_t i, const T& val) {
|
| + (*this)[i] = val;
|
| + }
|
|
|
| -#undef DECLARE_COMPUTATION_KIND
|
| - };
|
| + private:
|
| + T elements_[N];
|
| +};
|
|
|
| - virtual ComputationKind computation_kind() const = 0;
|
|
|
| - // Returns representation expected for the input operand at the given index.
|
| - virtual Representation RequiredInputRepresentation(intptr_t idx) const {
|
| - return kTagged;
|
| +template<typename T>
|
| +class EmbeddedArray<T, 0> {
|
| + public:
|
| + intptr_t length() const { return 0; }
|
| + const T& operator[](intptr_t i) const {
|
| + UNREACHABLE();
|
| + static T sentinel = 0;
|
| + return sentinel;
|
| }
|
| -
|
| - // Representation of the value produced by this computation.
|
| - virtual Representation representation() const {
|
| - return kTagged;
|
| + T& operator[](intptr_t i) {
|
| + UNREACHABLE();
|
| + static T sentinel = 0;
|
| + return sentinel;
|
| }
|
| +};
|
|
|
| - // Returns deoptimization id that corresponds to the deoptimization target
|
| - // that input operands conversions inserted for this instruction can jump
|
| - // to. Can return kNoDeoptId.
|
| - virtual intptr_t DeoptimizationTarget() const {
|
| - UNREACHABLE();
|
| - return Isolate::kNoDeoptId;
|
| - }
|
|
|
| - // Declare predicate for each computation.
|
| -#define DECLARE_PREDICATE(ShortName, ClassName) \
|
| - inline bool Is##ShortName() const; \
|
| - inline const ClassName* As##ShortName() const; \
|
| - inline ClassName* As##ShortName();
|
| -FOR_EACH_COMPUTATION(DECLARE_PREDICATE)
|
| -#undef DECLARE_PREDICATE
|
| +// Instructions.
|
|
|
| - protected:
|
| - // Fetch deopt id without checking if this computation can deoptimize.
|
| - intptr_t GetDeoptId() const {
|
| - return deopt_id_;
|
| - }
|
| +// M is a single argument macro. It is applied to each concrete instruction
|
| +// type name. The concrete instruction classes are the name with Instr
|
| +// concatenated.
|
| +#define FOR_EACH_INSTRUCTION(M) \
|
| + M(GraphEntry) \
|
| + M(JoinEntry) \
|
| + M(TargetEntry) \
|
| + M(Phi) \
|
| + M(Bind) \
|
| + M(Parameter) \
|
| + M(ParallelMove) \
|
| + M(PushArgument) \
|
| + M(Return) \
|
| + M(Throw) \
|
| + M(ReThrow) \
|
| + M(Goto) \
|
| + M(Branch) \
|
|
|
| - private:
|
| - friend class BranchInstr;
|
|
|
| - intptr_t deopt_id_;
|
| - LocationSummary* locs_;
|
| +#define FORWARD_DECLARATION(type) class type##Instr;
|
| +FOR_EACH_INSTRUCTION(FORWARD_DECLARATION)
|
| +#undef FORWARD_DECLARATION
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(Computation);
|
| -};
|
| +
|
| +// Functions required in all concrete instruction classes.
|
| +#define DECLARE_INSTRUCTION(type) \
|
| + virtual void Accept(FlowGraphVisitor* visitor); \
|
| + virtual bool Is##type() const { return true; } \
|
| + virtual type##Instr* As##type() { return this; } \
|
| + virtual const char* DebugName() const { return #type; } \
|
| + virtual void PrintTo(BufferFormatter* f) const; \
|
| + virtual void PrintToVisualizer(BufferFormatter* f) const;
|
|
|
|
|
| -// An embedded container with N elements of type T. Used (with partial
|
| -// specialization for N=0) because embedded arrays cannot have size 0.
|
| -template<typename T, intptr_t N>
|
| -class EmbeddedArray {
|
| +class Instruction : public ZoneAllocated {
|
| public:
|
| - EmbeddedArray() {
|
| - for (intptr_t i = 0; i < N; i++) elements_[i] = NULL;
|
| + Instruction()
|
| + : lifetime_position_(-1), previous_(NULL), next_(NULL), env_(NULL) { }
|
| +
|
| + virtual bool IsBlockEntry() const { return false; }
|
| + BlockEntryInstr* AsBlockEntry() {
|
| + return IsBlockEntry() ? reinterpret_cast<BlockEntryInstr*>(this) : NULL;
|
| }
|
| + virtual bool IsDefinition() const { return false; }
|
| + virtual Definition* AsDefinition() { return NULL; }
|
| + virtual bool IsControl() const { return false; }
|
|
|
| - intptr_t length() const { return N; }
|
| + virtual intptr_t InputCount() const = 0;
|
| + virtual Value* InputAt(intptr_t i) const = 0;
|
| + virtual void SetInputAt(intptr_t i, Value* value) = 0;
|
|
|
| - const T& operator[](intptr_t i) const {
|
| - ASSERT(i < length());
|
| - return elements_[i];
|
| + // Call instructions override this function and return the
|
| + // number of pushed arguments.
|
| + virtual intptr_t ArgumentCount() const = 0;
|
| +
|
| + // Returns true, if this instruction can deoptimize.
|
| + virtual bool CanDeoptimize() const = 0;
|
| +
|
| + // Visiting support.
|
| + virtual void Accept(FlowGraphVisitor* visitor) = 0;
|
| +
|
| + Instruction* previous() const { return previous_; }
|
| + void set_previous(Instruction* instr) {
|
| + ASSERT(!IsBlockEntry());
|
| + previous_ = instr;
|
| }
|
|
|
| - T& operator[](intptr_t i) {
|
| - ASSERT(i < length());
|
| - return elements_[i];
|
| + Instruction* next() const { return next_; }
|
| + void set_next(Instruction* instr) {
|
| + ASSERT(!IsGraphEntry());
|
| + ASSERT(!IsReturn());
|
| + ASSERT(!IsControl());
|
| + ASSERT(!IsPhi());
|
| + ASSERT(instr == NULL || !instr->IsBlockEntry());
|
| + // TODO(fschneider): Also add Throw and ReThrow to the list of instructions
|
| + // that do not have a successor. Currently, the graph builder will continue
|
| + // to append instruction in case of a Throw inside an expression. This
|
| + // condition should be handled in the graph builder
|
| + next_ = instr;
|
| }
|
|
|
| - const T& At(intptr_t i) const {
|
| - return (*this)[i];
|
| + // Removed this instruction from the graph.
|
| + Instruction* RemoveFromGraph(bool return_previous = true);
|
| +
|
| + // Normal instructions can have 0 (inside a block) or 1 (last instruction in
|
| + // a block) successors. Branch instruction with >1 successors override this
|
| + // function.
|
| + virtual intptr_t SuccessorCount() const;
|
| + virtual BlockEntryInstr* SuccessorAt(intptr_t index) const;
|
| +
|
| + void Goto(JoinEntryInstr* entry);
|
| +
|
| + // Discover basic-block structure by performing a recursive depth first
|
| + // traversal of the instruction graph reachable from this instruction. As
|
| + // a side effect, the block entry instructions in the graph are assigned
|
| + // numbers in both preorder and postorder. The array 'preorder' maps
|
| + // preorder block numbers to the block entry instruction with that number
|
| + // and analogously for the array 'postorder'. The depth first spanning
|
| + // tree is recorded in the array 'parent', which maps preorder block
|
| + // numbers to the preorder number of the block's spanning-tree parent.
|
| + // The array 'assigned_vars' maps preorder block numbers to the set of
|
| + // assigned frame-allocated local variables in the block. As a side
|
| + // effect of this function, the set of basic block predecessors (e.g.,
|
| + // block entry instructions of predecessor blocks) and also the last
|
| + // instruction in the block is recorded in each entry instruction.
|
| + virtual void DiscoverBlocks(
|
| + BlockEntryInstr* current_block,
|
| + GrowableArray<BlockEntryInstr*>* preorder,
|
| + GrowableArray<BlockEntryInstr*>* postorder,
|
| + GrowableArray<intptr_t>* parent,
|
| + GrowableArray<BitVector*>* assigned_vars,
|
| + intptr_t variable_count,
|
| + intptr_t fixed_parameter_count) {
|
| + // Never called for instructions except block entries and branches.
|
| + UNREACHABLE();
|
| }
|
|
|
| - void SetAt(intptr_t i, const T& val) {
|
| - (*this)[i] = val;
|
| + // Mutate assigned_vars to add the local variable index for all
|
| + // frame-allocated locals assigned to by the instruction.
|
| + virtual void RecordAssignedVars(BitVector* assigned_vars,
|
| + intptr_t fixed_parameter_count);
|
| +
|
| + // Printing support.
|
| + virtual void PrintTo(BufferFormatter* f) const = 0;
|
| + virtual void PrintToVisualizer(BufferFormatter* f) const = 0;
|
| +
|
| +#define INSTRUCTION_TYPE_CHECK(type) \
|
| + virtual bool Is##type() const { return false; } \
|
| + virtual type##Instr* As##type() { return NULL; }
|
| +FOR_EACH_INSTRUCTION(INSTRUCTION_TYPE_CHECK)
|
| +#undef INSTRUCTION_TYPE_CHECK
|
| +
|
| + // Returns structure describing location constraints required
|
| + // to emit native code for this instruction.
|
| + virtual LocationSummary* locs() {
|
| + // TODO(vegorov): This should be pure virtual method.
|
| + // However we are temporary using NULL for instructions that
|
| + // were not converted to the location based code generation yet.
|
| + return NULL;
|
| }
|
|
|
| - private:
|
| - T elements_[N];
|
| -};
|
| + virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
|
| + UNIMPLEMENTED();
|
| + }
|
|
|
| + Environment* env() const { return env_; }
|
| + void set_env(Environment* env) { env_ = env; }
|
|
|
| -template<typename T>
|
| -class EmbeddedArray<T, 0> {
|
| - public:
|
| - intptr_t length() const { return 0; }
|
| - const T& operator[](intptr_t i) const {
|
| - UNREACHABLE();
|
| - static T sentinel = 0;
|
| - return sentinel;
|
| + intptr_t lifetime_position() const { return lifetime_position_; }
|
| + void set_lifetime_position(intptr_t pos) {
|
| + lifetime_position_ = pos;
|
| }
|
| - T& operator[](intptr_t i) {
|
| +
|
| + // Returns representation expected for the input operand at the given index.
|
| + virtual Representation RequiredInputRepresentation(intptr_t idx) const {
|
| + return kTagged;
|
| + }
|
| +
|
| + // Representation of the value produced by this computation.
|
| + virtual Representation representation() const {
|
| + return kTagged;
|
| + }
|
| +
|
| + bool WasEliminated() const {
|
| + return next() == NULL;
|
| + }
|
| +
|
| + // Returns deoptimization id that corresponds to the deoptimization target
|
| + // that input operands conversions inserted for this instruction can jump
|
| + // to.
|
| + virtual intptr_t DeoptimizationTarget() const {
|
| UNREACHABLE();
|
| - static T sentinel = 0;
|
| - return sentinel;
|
| + return Isolate::kNoDeoptId;
|
| }
|
| +
|
| + private:
|
| + friend class BindInstr; // Needed for BindInstr::InsertBefore.
|
| +
|
| + intptr_t lifetime_position_; // Position used by register allocator.
|
| + Instruction* previous_;
|
| + Instruction* next_;
|
| + Environment* env_;
|
| + DISALLOW_COPY_AND_ASSIGN(Instruction);
|
| };
|
|
|
|
|
| template<intptr_t N>
|
| -class TemplateComputation : public Computation {
|
| +class TemplateInstruction: public Instruction {
|
| public:
|
| + TemplateInstruction<N>() : locs_(NULL) { }
|
| +
|
| virtual intptr_t InputCount() const { return N; }
|
| virtual Value* InputAt(intptr_t i) const { return inputs_[i]; }
|
| virtual void SetInputAt(intptr_t i, Value* value) {
|
| @@ -336,1158 +373,1238 @@ class TemplateComputation : public Computation {
|
| inputs_[i] = value;
|
| }
|
|
|
| + virtual LocationSummary* locs() {
|
| + if (locs_ == NULL) {
|
| + locs_ = MakeLocationSummary();
|
| + }
|
| + return locs_;
|
| + }
|
| +
|
| + virtual LocationSummary* MakeLocationSummary() const = 0;
|
| +
|
| protected:
|
| EmbeddedArray<Value*, N> inputs_;
|
| +
|
| + private:
|
| + LocationSummary* locs_;
|
| };
|
|
|
|
|
| -class Value : public ZoneAllocated {
|
| +class MoveOperands : public ZoneAllocated {
|
| public:
|
| - explicit Value(Definition* definition)
|
| - : definition_(definition),
|
| - next_use_(NULL),
|
| - instruction_(NULL),
|
| - use_index_(-1) { }
|
| -
|
| - Definition* definition() const { return definition_; }
|
| - void set_definition(Definition* definition) { definition_ = definition; }
|
| + MoveOperands(Location dest, Location src) : dest_(dest), src_(src) { }
|
|
|
| - Value* next_use() const { return next_use_; }
|
| - void set_next_use(Value* next) { next_use_ = next; }
|
| + Location src() const { return src_; }
|
| + Location dest() const { return dest_; }
|
|
|
| - Instruction* instruction() const { return instruction_; }
|
| - void set_instruction(Instruction* instruction) { instruction_ = instruction; }
|
| + Location* src_slot() { return &src_; }
|
| + Location* dest_slot() { return &dest_; }
|
|
|
| - intptr_t use_index() const { return use_index_; }
|
| - void set_use_index(intptr_t index) { use_index_ = index; }
|
| + void set_src(const Location& value) { src_ = value; }
|
| + void set_dest(const Location& value) { dest_ = value; }
|
|
|
| - void AddToInputUseList();
|
| - void AddToEnvUseList();
|
| -
|
| - Value* Copy() { return new Value(definition_); }
|
| -
|
| - RawAbstractType* CompileType() const;
|
| - intptr_t ResultCid() const;
|
| -
|
| - void PrintTo(BufferFormatter* f) const;
|
| -
|
| - const char* DebugName() const { return "Value"; }
|
| -
|
| - // Returns true if the value represents a constant.
|
| - bool BindsToConstant() const;
|
| + // The parallel move resolver marks moves as "in-progress" by clearing the
|
| + // destination (but not the source).
|
| + Location MarkPending() {
|
| + ASSERT(!IsPending());
|
| + Location dest = dest_;
|
| + dest_ = Location::NoLocation();
|
| + return dest;
|
| + }
|
|
|
| - // Returns true if the value represents the constant null.
|
| - bool BindsToConstantNull() const;
|
| + void ClearPending(Location dest) {
|
| + ASSERT(IsPending());
|
| + dest_ = dest;
|
| + }
|
|
|
| - // Assert if BindsToConstant() is false, otherwise returns the constant value.
|
| - const Object& BoundConstant() const;
|
| + bool IsPending() const {
|
| + ASSERT(!src_.IsInvalid() || dest_.IsInvalid());
|
| + return dest_.IsInvalid() && !src_.IsInvalid();
|
| + }
|
|
|
| - // Reminder: The type of the constant null is the bottom type, which is more
|
| - // specific than any type.
|
| - bool CompileTypeIsMoreSpecificThan(const AbstractType& dst_type) const;
|
| + // True if this move a move from the given location.
|
| + bool Blocks(Location loc) const {
|
| + return !IsEliminated() && src_.Equals(loc);
|
| + }
|
|
|
| - // Compile time constants, Bool, Smi and Nulls do not need to update
|
| - // the store buffer.
|
| - bool NeedsStoreBuffer() const;
|
| + // A move is redundant if it's been eliminated, if its source and
|
| + // destination are the same, or if its destination is unneeded.
|
| + bool IsRedundant() const {
|
| + return IsEliminated() || dest_.IsInvalid() || src_.Equals(dest_);
|
| + }
|
|
|
| - bool Equals(Value* other) const;
|
| + // We clear both operands to indicate move that's been eliminated.
|
| + void Eliminate() { src_ = dest_ = Location::NoLocation(); }
|
| + bool IsEliminated() const {
|
| + ASSERT(!src_.IsInvalid() || dest_.IsInvalid());
|
| + return src_.IsInvalid();
|
| + }
|
|
|
| private:
|
| - Definition* definition_;
|
| - Value* next_use_;
|
| - Instruction* instruction_;
|
| - intptr_t use_index_;
|
| + Location dest_;
|
| + Location src_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(Value);
|
| + DISALLOW_COPY_AND_ASSIGN(MoveOperands);
|
| };
|
|
|
|
|
| -// Functions defined in all concrete computation classes.
|
| -#define DECLARE_COMPUTATION(ShortName) \
|
| - virtual void Accept(FlowGraphVisitor* visitor, BindInstr* instr); \
|
| - virtual ComputationKind computation_kind() const { \
|
| - return Computation::k##ShortName; \
|
| - } \
|
| - virtual intptr_t ArgumentCount() const { return 0; } \
|
| - virtual const char* DebugName() const { return #ShortName; } \
|
| - virtual RawAbstractType* CompileType() const; \
|
| - virtual LocationSummary* MakeLocationSummary() const; \
|
| - virtual void EmitNativeCode(FlowGraphCompiler* compiler);
|
| -
|
| +class ParallelMoveInstr : public TemplateInstruction<0> {
|
| + public:
|
| + ParallelMoveInstr() : moves_(4) { }
|
|
|
| -// Function defined in all call computation classes.
|
| -#define DECLARE_CALL_COMPUTATION(ShortName) \
|
| - virtual void Accept(FlowGraphVisitor* visitor, BindInstr* instr); \
|
| - virtual ComputationKind computation_kind() const { \
|
| - return Computation::k##ShortName; \
|
| - } \
|
| - virtual const char* DebugName() const { return #ShortName; } \
|
| - virtual RawAbstractType* CompileType() const; \
|
| - virtual LocationSummary* MakeLocationSummary() const; \
|
| - virtual void EmitNativeCode(FlowGraphCompiler* compiler);
|
| + DECLARE_INSTRUCTION(ParallelMove)
|
|
|
| + virtual intptr_t ArgumentCount() const { return 0; }
|
|
|
| -class ConstantComp : public TemplateComputation<0> {
|
| - public:
|
| - explicit ConstantComp(const Object& value) : value_(value) { }
|
| + virtual bool CanDeoptimize() const { return false; }
|
|
|
| - DECLARE_COMPUTATION(Constant)
|
| + MoveOperands* AddMove(Location dest, Location src) {
|
| + MoveOperands* move = new MoveOperands(dest, src);
|
| + moves_.Add(move);
|
| + return move;
|
| + }
|
|
|
| - const Object& value() const { return value_; }
|
| + MoveOperands* MoveOperandsAt(intptr_t index) const { return moves_[index]; }
|
|
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| + void SetSrcSlotAt(intptr_t index, const Location& loc);
|
| + void SetDestSlotAt(intptr_t index, const Location& loc);
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| + intptr_t NumMoves() const { return moves_.length(); }
|
|
|
| - virtual intptr_t ResultCid() const;
|
| + LocationSummary* MakeLocationSummary() const { return NULL; }
|
|
|
| - virtual bool AttributesEqual(Computation* other) const;
|
| + void EmitNativeCode(FlowGraphCompiler* compiler) { UNREACHABLE(); }
|
|
|
| private:
|
| - const Object& value_;
|
| + GrowableArray<MoveOperands*> moves_; // Elements cannot be null.
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(ConstantComp);
|
| + DISALLOW_COPY_AND_ASSIGN(ParallelMoveInstr);
|
| };
|
|
|
|
|
| -class AssertAssignableComp : public TemplateComputation<3> {
|
| +// Basic block entries are administrative nodes. There is a distinguished
|
| +// graph entry with no predecessor. Joins are the only nodes with multiple
|
| +// predecessors. Targets are all other basic block entries. The types
|
| +// enforce edge-split form---joins are forbidden as the successors of
|
| +// branches.
|
| +class BlockEntryInstr : public Instruction {
|
| public:
|
| - AssertAssignableComp(intptr_t token_pos,
|
| - Value* value,
|
| - Value* instantiator,
|
| - Value* instantiator_type_arguments,
|
| - const AbstractType& dst_type,
|
| - const String& dst_name)
|
| - : token_pos_(token_pos),
|
| - dst_type_(dst_type),
|
| - dst_name_(dst_name),
|
| - is_eliminated_(false) {
|
| - ASSERT(value != NULL);
|
| - ASSERT(instantiator != NULL);
|
| - ASSERT(instantiator_type_arguments != NULL);
|
| - ASSERT(!dst_type.IsNull());
|
| - ASSERT(!dst_name.IsNull());
|
| - inputs_[0] = value;
|
| - inputs_[1] = instantiator;
|
| - inputs_[2] = instantiator_type_arguments;
|
| - }
|
| + virtual bool IsBlockEntry() const { return true; }
|
|
|
| - DECLARE_COMPUTATION(AssertAssignable)
|
| + virtual intptr_t PredecessorCount() const = 0;
|
| + virtual BlockEntryInstr* PredecessorAt(intptr_t index) const = 0;
|
| + virtual void AddPredecessor(BlockEntryInstr* predecessor) = 0;
|
| + virtual void PrepareEntry(FlowGraphCompiler* compiler) = 0;
|
|
|
| - Value* value() const { return inputs_[0]; }
|
| - Value* instantiator() const { return inputs_[1]; }
|
| - Value* instantiator_type_arguments() const { return inputs_[2]; }
|
| + intptr_t preorder_number() const { return preorder_number_; }
|
| + void set_preorder_number(intptr_t number) { preorder_number_ = number; }
|
|
|
| - intptr_t token_pos() const { return token_pos_; }
|
| - const AbstractType& dst_type() const { return dst_type_; }
|
| - const String& dst_name() const { return dst_name_; }
|
| + intptr_t postorder_number() const { return postorder_number_; }
|
| + void set_postorder_number(intptr_t number) { postorder_number_ = number; }
|
|
|
| - bool is_eliminated() const {
|
| - return is_eliminated_;
|
| - }
|
| - void eliminate() {
|
| - ASSERT(!is_eliminated_);
|
| - is_eliminated_ = true;
|
| - }
|
| + intptr_t block_id() const { return block_id_; }
|
| + void set_block_id(intptr_t value) { block_id_ = value; }
|
|
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| + void set_start_pos(intptr_t pos) { start_pos_ = pos; }
|
| + intptr_t start_pos() const { return start_pos_; }
|
| + void set_end_pos(intptr_t pos) { end_pos_ = pos; }
|
| + intptr_t end_pos() const { return end_pos_; }
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kDynamicCid; }
|
| + BlockEntryInstr* dominator() const { return dominator_; }
|
| + void set_dominator(BlockEntryInstr* instr) { dominator_ = instr; }
|
|
|
| - private:
|
| - const intptr_t token_pos_;
|
| - const AbstractType& dst_type_;
|
| - const String& dst_name_;
|
| - bool is_eliminated_;
|
| + const GrowableArray<BlockEntryInstr*>& dominated_blocks() {
|
| + return dominated_blocks_;
|
| + }
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(AssertAssignableComp);
|
| -};
|
| + void AddDominatedBlock(BlockEntryInstr* block) {
|
| + dominated_blocks_.Add(block);
|
| + }
|
|
|
| + Instruction* last_instruction() const { return last_instruction_; }
|
| + void set_last_instruction(Instruction* instr) { last_instruction_ = instr; }
|
|
|
| -class AssertBooleanComp : public TemplateComputation<1> {
|
| - public:
|
| - AssertBooleanComp(intptr_t token_pos,
|
| - Value* value)
|
| - : token_pos_(token_pos),
|
| - is_eliminated_(false) {
|
| - ASSERT(value != NULL);
|
| - inputs_[0] = value;
|
| + ParallelMoveInstr* parallel_move() const {
|
| + return parallel_move_;
|
| }
|
|
|
| - DECLARE_COMPUTATION(AssertBoolean)
|
| -
|
| - intptr_t token_pos() const { return token_pos_; }
|
| - Value* value() const { return inputs_[0]; }
|
| + bool HasParallelMove() const {
|
| + return parallel_move_ != NULL;
|
| + }
|
|
|
| - bool is_eliminated() const {
|
| - return is_eliminated_;
|
| + ParallelMoveInstr* GetParallelMove() {
|
| + if (parallel_move_ == NULL) {
|
| + parallel_move_ = new ParallelMoveInstr();
|
| + }
|
| + return parallel_move_;
|
| }
|
| - void eliminate() {
|
| - ASSERT(!is_eliminated_);
|
| - is_eliminated_ = true;
|
| +
|
| + virtual void DiscoverBlocks(
|
| + BlockEntryInstr* current_block,
|
| + GrowableArray<BlockEntryInstr*>* preorder,
|
| + GrowableArray<BlockEntryInstr*>* postorder,
|
| + GrowableArray<intptr_t>* parent,
|
| + GrowableArray<BitVector*>* assigned_vars,
|
| + intptr_t variable_count,
|
| + intptr_t fixed_parameter_count);
|
| +
|
| + virtual intptr_t InputCount() const { return 0; }
|
| + virtual Value* InputAt(intptr_t i) const {
|
| + UNREACHABLE();
|
| + return NULL;
|
| }
|
| + virtual void SetInputAt(intptr_t i, Value* value) { UNREACHABLE(); }
|
|
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| + virtual intptr_t ArgumentCount() const { return 0; }
|
|
|
| virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kBoolCid; }
|
| -
|
| - private:
|
| - const intptr_t token_pos_;
|
| - bool is_eliminated_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(AssertBooleanComp);
|
| -};
|
| + intptr_t try_index() const { return try_index_; }
|
|
|
| -
|
| -class ArgumentDefinitionTestComp : public TemplateComputation<1> {
|
| - public:
|
| - ArgumentDefinitionTestComp(ArgumentDefinitionTestNode* node,
|
| - Value* saved_arguments_descriptor)
|
| - : ast_node_(*node) {
|
| - ASSERT(saved_arguments_descriptor != NULL);
|
| - inputs_[0] = saved_arguments_descriptor;
|
| - }
|
| -
|
| - DECLARE_COMPUTATION(ArgumentDefinitionTest)
|
| -
|
| - intptr_t token_pos() const { return ast_node_.token_pos(); }
|
| - intptr_t formal_parameter_index() const {
|
| - return ast_node_.formal_parameter_index();
|
| - }
|
| - const String& formal_parameter_name() const {
|
| - return ast_node_.formal_parameter_name();
|
| - }
|
| - Value* saved_arguments_descriptor() const { return inputs_[0]; }
|
| -
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| -
|
| - virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kBoolCid; }
|
| + protected:
|
| + explicit BlockEntryInstr(intptr_t try_index)
|
| + : try_index_(try_index),
|
| + preorder_number_(-1),
|
| + postorder_number_(-1),
|
| + block_id_(-1),
|
| + dominator_(NULL),
|
| + dominated_blocks_(1),
|
| + last_instruction_(NULL),
|
| + parallel_move_(NULL) { }
|
|
|
| private:
|
| - const ArgumentDefinitionTestNode& ast_node_;
|
| + const intptr_t try_index_;
|
| + intptr_t preorder_number_;
|
| + intptr_t postorder_number_;
|
| + // Starting and ending lifetime positions for this block. Used by
|
| + // the linear scan register allocator.
|
| + intptr_t block_id_;
|
| + intptr_t start_pos_;
|
| + intptr_t end_pos_;
|
| + BlockEntryInstr* dominator_; // Immediate dominator, NULL for graph entry.
|
| + // TODO(fschneider): Optimize the case of one child to save space.
|
| + GrowableArray<BlockEntryInstr*> dominated_blocks_;
|
| + Instruction* last_instruction_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(ArgumentDefinitionTestComp);
|
| + // Parallel move that will be used by linear scan register allocator to
|
| + // connect live ranges at the start of the block.
|
| + ParallelMoveInstr* parallel_move_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(BlockEntryInstr);
|
| };
|
|
|
|
|
| -// Denotes the current context, normally held in a register. This is
|
| -// a computation, not a value, because it's mutable.
|
| -class CurrentContextComp : public TemplateComputation<0> {
|
| +class ForwardInstructionIterator : public ValueObject {
|
| public:
|
| - CurrentContextComp() { }
|
| + explicit ForwardInstructionIterator(BlockEntryInstr* block_entry)
|
| + : block_entry_(block_entry), current_(block_entry) {
|
| + ASSERT(block_entry_->last_instruction()->next() == NULL);
|
| + Advance();
|
| + }
|
|
|
| - DECLARE_COMPUTATION(CurrentContext)
|
| + void Advance() {
|
| + ASSERT(!Done());
|
| + current_ = current_->next();
|
| + }
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kDynamicCid; }
|
| + bool Done() const { return current_ == NULL; }
|
| +
|
| + // Removes 'current_' from graph and sets 'current_' to previous instruction.
|
| + void RemoveCurrentFromGraph();
|
| +
|
| + Instruction* Current() const { return current_; }
|
|
|
| private:
|
| - DISALLOW_COPY_AND_ASSIGN(CurrentContextComp);
|
| + BlockEntryInstr* block_entry_;
|
| + Instruction* current_;
|
| };
|
|
|
|
|
| -class StoreContextComp : public TemplateComputation<1> {
|
| +class BackwardInstructionIterator : public ValueObject {
|
| public:
|
| - explicit StoreContextComp(Value* value) {
|
| - ASSERT(value != NULL);
|
| - inputs_[0] = value;
|
| + explicit BackwardInstructionIterator(BlockEntryInstr* block_entry)
|
| + : block_entry_(block_entry), current_(block_entry->last_instruction()) {
|
| + ASSERT(block_entry_->previous() == NULL);
|
| }
|
|
|
| - DECLARE_COMPUTATION(StoreContext);
|
| + void Advance() {
|
| + ASSERT(!Done());
|
| + current_ = current_->previous();
|
| + }
|
|
|
| - Value* value() const { return inputs_[0]; }
|
| + bool Done() const { return current_ == block_entry_; }
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kIllegalCid; }
|
| + Instruction* Current() const { return current_; }
|
|
|
| private:
|
| - DISALLOW_COPY_AND_ASSIGN(StoreContextComp);
|
| + BlockEntryInstr* block_entry_;
|
| + Instruction* current_;
|
| };
|
|
|
|
|
| -class ClosureCallComp : public TemplateComputation<0> {
|
| +class GraphEntryInstr : public BlockEntryInstr {
|
| public:
|
| - ClosureCallComp(ClosureCallNode* node,
|
| - ZoneGrowableArray<PushArgumentInstr*>* arguments)
|
| - : ast_node_(*node),
|
| - arguments_(arguments) { }
|
| -
|
| - DECLARE_CALL_COMPUTATION(ClosureCall)
|
| + explicit GraphEntryInstr(TargetEntryInstr* normal_entry);
|
|
|
| - const Array& argument_names() const { return ast_node_.arguments()->names(); }
|
| - intptr_t token_pos() const { return ast_node_.token_pos(); }
|
| + DECLARE_INSTRUCTION(GraphEntry)
|
|
|
| - virtual intptr_t ArgumentCount() const { return arguments_->length(); }
|
| - PushArgumentInstr* ArgumentAt(intptr_t index) const {
|
| - return (*arguments_)[index];
|
| + virtual intptr_t PredecessorCount() const { return 0; }
|
| + virtual BlockEntryInstr* PredecessorAt(intptr_t index) const {
|
| + UNREACHABLE();
|
| + return NULL;
|
| }
|
| + virtual void AddPredecessor(BlockEntryInstr* predecessor) { UNREACHABLE(); }
|
|
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| -
|
| - virtual bool CanDeoptimize() const { return true; }
|
| - virtual intptr_t ResultCid() const { return kDynamicCid; }
|
| -
|
| - private:
|
| - const ClosureCallNode& ast_node_;
|
| - ZoneGrowableArray<PushArgumentInstr*>* arguments_;
|
| + virtual intptr_t SuccessorCount() const;
|
| + virtual BlockEntryInstr* SuccessorAt(intptr_t index) const;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(ClosureCallComp);
|
| -};
|
| + virtual void DiscoverBlocks(
|
| + BlockEntryInstr* current_block,
|
| + GrowableArray<BlockEntryInstr*>* preorder,
|
| + GrowableArray<BlockEntryInstr*>* postorder,
|
| + GrowableArray<intptr_t>* parent,
|
| + GrowableArray<BitVector*>* assigned_vars,
|
| + intptr_t variable_count,
|
| + intptr_t fixed_parameter_count);
|
|
|
| + void AddCatchEntry(TargetEntryInstr* entry) { catch_entries_.Add(entry); }
|
|
|
| -class InstanceCallComp : public TemplateComputation<0> {
|
| - public:
|
| - InstanceCallComp(intptr_t token_pos,
|
| - const String& function_name,
|
| - Token::Kind token_kind,
|
| - ZoneGrowableArray<PushArgumentInstr*>* arguments,
|
| - const Array& argument_names,
|
| - intptr_t checked_argument_count)
|
| - : ic_data_(Isolate::Current()->GetICDataForDeoptId(deopt_id())),
|
| - token_pos_(token_pos),
|
| - function_name_(function_name),
|
| - token_kind_(token_kind),
|
| - arguments_(arguments),
|
| - argument_names_(argument_names),
|
| - checked_argument_count_(checked_argument_count) {
|
| - ASSERT(function_name.IsZoneHandle());
|
| - ASSERT(!arguments->is_empty());
|
| - ASSERT(argument_names.IsZoneHandle());
|
| - ASSERT(Token::IsBinaryToken(token_kind) ||
|
| - Token::IsUnaryToken(token_kind) ||
|
| - Token::IsIndexOperator(token_kind) ||
|
| - token_kind == Token::kGET ||
|
| - token_kind == Token::kSET ||
|
| - token_kind == Token::kILLEGAL);
|
| - }
|
| + virtual void PrepareEntry(FlowGraphCompiler* compiler);
|
|
|
| - DECLARE_CALL_COMPUTATION(InstanceCall)
|
| + Environment* start_env() const { return start_env_; }
|
| + void set_start_env(Environment* env) { start_env_ = env; }
|
|
|
| - const ICData* ic_data() const { return ic_data_; }
|
| - bool HasICData() const {
|
| - return (ic_data() != NULL) && !ic_data()->IsNull();
|
| - }
|
| + Definition* constant_null() const { return constant_null_; }
|
|
|
| - intptr_t token_pos() const { return token_pos_; }
|
| - const String& function_name() const { return function_name_; }
|
| - Token::Kind token_kind() const { return token_kind_; }
|
| - virtual intptr_t ArgumentCount() const { return arguments_->length(); }
|
| - PushArgumentInstr* ArgumentAt(intptr_t index) const {
|
| - return (*arguments_)[index];
|
| + intptr_t spill_slot_count() const { return spill_slot_count_; }
|
| + void set_spill_slot_count(intptr_t count) {
|
| + ASSERT(count >= 0);
|
| + spill_slot_count_ = count;
|
| }
|
| - const Array& argument_names() const { return argument_names_; }
|
| - intptr_t checked_argument_count() const { return checked_argument_count_; }
|
| -
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - virtual bool CanDeoptimize() const { return true; }
|
| - virtual intptr_t ResultCid() const { return kDynamicCid; }
|
| + TargetEntryInstr* normal_entry() const { return normal_entry_; }
|
|
|
| private:
|
| - const ICData* ic_data_;
|
| - const intptr_t token_pos_;
|
| - const String& function_name_;
|
| - const Token::Kind token_kind_; // Binary op, unary op, kGET or kILLEGAL.
|
| - ZoneGrowableArray<PushArgumentInstr*>* const arguments_;
|
| - const Array& argument_names_;
|
| - const intptr_t checked_argument_count_;
|
| + TargetEntryInstr* normal_entry_;
|
| + GrowableArray<TargetEntryInstr*> catch_entries_;
|
| + Environment* start_env_;
|
| + Definition* constant_null_;
|
| + intptr_t spill_slot_count_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(InstanceCallComp);
|
| + DISALLOW_COPY_AND_ASSIGN(GraphEntryInstr);
|
| };
|
|
|
|
|
| -class PolymorphicInstanceCallComp : public TemplateComputation<0> {
|
| +class JoinEntryInstr : public BlockEntryInstr {
|
| public:
|
| - PolymorphicInstanceCallComp(InstanceCallComp* comp,
|
| - const ICData& ic_data,
|
| - bool with_checks)
|
| - : instance_call_(comp), ic_data_(ic_data), with_checks_(with_checks) {
|
| - ASSERT(instance_call_ != NULL);
|
| - }
|
| -
|
| - InstanceCallComp* instance_call() const { return instance_call_; }
|
| - bool with_checks() const { return with_checks_; }
|
| + explicit JoinEntryInstr(intptr_t try_index)
|
| + : BlockEntryInstr(try_index),
|
| + predecessors_(2), // Two is the assumed to be the common case.
|
| + phis_(NULL),
|
| + phi_count_(0) { }
|
|
|
| - void PrintTo(BufferFormatter* f) const;
|
| + DECLARE_INSTRUCTION(JoinEntry)
|
|
|
| - virtual intptr_t ArgumentCount() const {
|
| - return instance_call()->ArgumentCount();
|
| + virtual intptr_t PredecessorCount() const { return predecessors_.length(); }
|
| + virtual BlockEntryInstr* PredecessorAt(intptr_t index) const {
|
| + return predecessors_[index];
|
| + }
|
| + virtual void AddPredecessor(BlockEntryInstr* predecessor) {
|
| + predecessors_.Add(predecessor);
|
| }
|
|
|
| - DECLARE_CALL_COMPUTATION(PolymorphicInstanceCall)
|
| + // Returns -1 if pred is not in the list.
|
| + intptr_t IndexOfPredecessor(BlockEntryInstr* pred) const;
|
|
|
| - const ICData& ic_data() const { return ic_data_; }
|
| + ZoneGrowableArray<PhiInstr*>* phis() const { return phis_; }
|
|
|
| - virtual bool CanDeoptimize() const { return true; }
|
| - virtual intptr_t ResultCid() const { return kDynamicCid; }
|
| + virtual void PrepareEntry(FlowGraphCompiler* compiler);
|
| +
|
| + void InsertPhi(intptr_t var_index, intptr_t var_count);
|
| + void RemoveDeadPhis();
|
| +
|
| + intptr_t phi_count() const { return phi_count_; }
|
|
|
| private:
|
| - InstanceCallComp* instance_call_;
|
| - const ICData& ic_data_;
|
| - const bool with_checks_;
|
| + GrowableArray<BlockEntryInstr*> predecessors_;
|
| + ZoneGrowableArray<PhiInstr*>* phis_;
|
| + intptr_t phi_count_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(PolymorphicInstanceCallComp);
|
| + DISALLOW_COPY_AND_ASSIGN(JoinEntryInstr);
|
| };
|
|
|
|
|
| -class ComparisonComp : public TemplateComputation<2> {
|
| +class TargetEntryInstr : public BlockEntryInstr {
|
| public:
|
| - ComparisonComp(Token::Kind kind, Value* left, Value* right) : kind_(kind) {
|
| - ASSERT(left != NULL);
|
| - ASSERT(right != NULL);
|
| - inputs_[0] = left;
|
| - inputs_[1] = right;
|
| - }
|
| -
|
| - Value* left() const { return inputs_[0]; }
|
| - Value* right() const { return inputs_[1]; }
|
| + explicit TargetEntryInstr(intptr_t try_index)
|
| + : BlockEntryInstr(try_index),
|
| + predecessor_(NULL),
|
| + catch_try_index_(CatchClauseNode::kInvalidTryIndex) { }
|
|
|
| - virtual ComparisonComp* AsComparison() { return this; }
|
| + // Used for exception catch entries.
|
| + TargetEntryInstr(intptr_t try_index, intptr_t catch_try_index)
|
| + : BlockEntryInstr(try_index),
|
| + predecessor_(NULL),
|
| + catch_try_index_(catch_try_index) { }
|
|
|
| - Token::Kind kind() const { return kind_; }
|
| + DECLARE_INSTRUCTION(TargetEntry)
|
| +
|
| + virtual intptr_t PredecessorCount() const {
|
| + return (predecessor_ == NULL) ? 0 : 1;
|
| + }
|
| + virtual BlockEntryInstr* PredecessorAt(intptr_t index) const {
|
| + ASSERT((index == 0) && (predecessor_ != NULL));
|
| + return predecessor_;
|
| + }
|
| + virtual void AddPredecessor(BlockEntryInstr* predecessor) {
|
| + ASSERT(predecessor_ == NULL);
|
| + predecessor_ = predecessor;
|
| + }
|
| +
|
| + // Returns true if this Block is an entry of a catch handler.
|
| + bool IsCatchEntry() const {
|
| + return catch_try_index_ != CatchClauseNode::kInvalidTryIndex;
|
| + }
|
| +
|
| + // Returns try index for the try block to which this catch handler
|
| + // corresponds.
|
| + intptr_t catch_try_index() const {
|
| + ASSERT(IsCatchEntry());
|
| + return catch_try_index_;
|
| + }
|
| +
|
| + virtual void PrepareEntry(FlowGraphCompiler* compiler);
|
|
|
| private:
|
| - Token::Kind kind_;
|
| + BlockEntryInstr* predecessor_;
|
| + const intptr_t catch_try_index_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(TargetEntryInstr);
|
| };
|
|
|
|
|
| -class StrictCompareComp : public ComparisonComp {
|
| +// Abstract super-class of all instructions that define a value (Bind, Phi).
|
| +class Definition : public Instruction {
|
| public:
|
| - StrictCompareComp(Token::Kind kind, Value* left, Value* right)
|
| - : ComparisonComp(kind, left, right) {
|
| - ASSERT((kind == Token::kEQ_STRICT) || (kind == Token::kNE_STRICT));
|
| + Definition()
|
| + : temp_index_(-1),
|
| + ssa_temp_index_(-1),
|
| + propagated_type_(AbstractType::Handle()),
|
| + propagated_cid_(kIllegalCid),
|
| + input_use_list_(NULL),
|
| + env_use_list_(NULL) { }
|
| +
|
| + virtual bool IsDefinition() const { return true; }
|
| + virtual Definition* AsDefinition() { return this; }
|
| +
|
| + intptr_t temp_index() const { return temp_index_; }
|
| + void set_temp_index(intptr_t index) { temp_index_ = index; }
|
| +
|
| + intptr_t ssa_temp_index() const { return ssa_temp_index_; }
|
| + void set_ssa_temp_index(intptr_t index) {
|
| + ASSERT(index >= 0);
|
| + ssa_temp_index_ = index;
|
| }
|
| + bool HasSSATemp() const { return ssa_temp_index_ >= 0; }
|
|
|
| - DECLARE_COMPUTATION(StrictCompare)
|
| + // Compile time type of the definition, which may be requested before type
|
| + // propagation during graph building.
|
| + virtual RawAbstractType* CompileType() const = 0;
|
|
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| + bool HasPropagatedType() const {
|
| + return !propagated_type_.IsNull();
|
| + }
|
| + RawAbstractType* PropagatedType() const {
|
| + ASSERT(HasPropagatedType());
|
| + return propagated_type_.raw();
|
| + }
|
| + // Returns true if the propagated type has changed.
|
| + bool SetPropagatedType(const AbstractType& propagated_type) {
|
| + if (propagated_type.IsNull()) {
|
| + // Not a typed definition, e.g. access to a VM field.
|
| + return false;
|
| + }
|
| + const bool changed =
|
| + propagated_type_.IsNull() || !propagated_type.Equals(propagated_type_);
|
| + propagated_type_ = propagated_type.raw();
|
| + return changed;
|
| + }
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| + bool has_propagated_cid() const { return propagated_cid_ != kIllegalCid; }
|
| + intptr_t propagated_cid() const { return propagated_cid_; }
|
| + // May compute and set propagated cid.
|
| + virtual intptr_t GetPropagatedCid() = 0;
|
|
|
| - virtual Definition* TryReplace(BindInstr* instr) const;
|
| + // Returns true if the propagated cid has changed.
|
| + bool SetPropagatedCid(intptr_t cid);
|
|
|
| - virtual intptr_t ResultCid() const { return kBoolCid; }
|
| + Value* input_use_list() { return input_use_list_; }
|
| + void set_input_use_list(Value* head) { input_use_list_ = head; }
|
|
|
| - virtual void EmitBranchCode(FlowGraphCompiler* compiler,
|
| - BranchInstr* branch);
|
| + Value* env_use_list() { return env_use_list_; }
|
| + void set_env_use_list(Value* head) { env_use_list_ = head; }
|
| +
|
| + // Replace uses of this definition with uses of other definition or value.
|
| + // Precondition: use lists must be properly calculated.
|
| + // Postcondition: use lists and use values are still valid.
|
| + void ReplaceUsesWith(Definition* other);
|
|
|
| private:
|
| - DISALLOW_COPY_AND_ASSIGN(StrictCompareComp);
|
| + intptr_t temp_index_;
|
| + intptr_t ssa_temp_index_;
|
| + // TODO(regis): GrowableArray<const AbstractType*> propagated_types_;
|
| + // For now:
|
| + AbstractType& propagated_type_;
|
| + intptr_t propagated_cid_;
|
| + Value* input_use_list_;
|
| + Value* env_use_list_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(Definition);
|
| };
|
|
|
|
|
| -class EqualityCompareComp : public ComparisonComp {
|
| +class BindInstr : public Definition {
|
| public:
|
| - EqualityCompareComp(intptr_t token_pos,
|
| - Token::Kind kind,
|
| - Value* left,
|
| - Value* right)
|
| - : ComparisonComp(kind, left, right),
|
| - ic_data_(Isolate::Current()->GetICDataForDeoptId(deopt_id())),
|
| - token_pos_(token_pos),
|
| - receiver_class_id_(kIllegalCid) {
|
| - ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
|
| - }
|
| -
|
| - DECLARE_COMPUTATION(EqualityCompare)
|
| + enum UseKind { kUnused, kUsed };
|
|
|
| - const ICData* ic_data() const { return ic_data_; }
|
| - bool HasICData() const {
|
| - return (ic_data() != NULL) && !ic_data()->IsNull();
|
| + BindInstr(UseKind used, Computation* computation)
|
| + : computation_(computation), is_used_(used != kUnused) {
|
| + ASSERT(computation != NULL);
|
| }
|
|
|
| - intptr_t token_pos() const { return token_pos_; }
|
| + DECLARE_INSTRUCTION(Bind)
|
|
|
| - // Receiver class id is computed from collected ICData.
|
| - void set_receiver_class_id(intptr_t value) { receiver_class_id_ = value; }
|
| - intptr_t receiver_class_id() const { return receiver_class_id_; }
|
| + virtual intptr_t ArgumentCount() const;
|
| + intptr_t InputCount() const;
|
| + Value* InputAt(intptr_t i) const;
|
| + void SetInputAt(intptr_t i, Value* value);
|
| + virtual bool CanDeoptimize() const;
|
|
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| + Computation* computation() const { return computation_; }
|
| + void set_computation(Computation* value) { computation_ = value; }
|
| + bool is_used() const { return is_used_; }
|
|
|
| - virtual bool CanDeoptimize() const {
|
| - return (receiver_class_id() != kDoubleCid);
|
| - }
|
| + virtual RawAbstractType* CompileType() const;
|
| + virtual intptr_t GetPropagatedCid();
|
|
|
| - virtual intptr_t ResultCid() const;
|
| + virtual void RecordAssignedVars(BitVector* assigned_vars,
|
| + intptr_t fixed_parameter_count);
|
|
|
| - virtual void EmitBranchCode(FlowGraphCompiler* compiler,
|
| - BranchInstr* branch);
|
| + intptr_t Hashcode() const;
|
| + bool Equals(BindInstr* other) const;
|
| + virtual LocationSummary* locs();
|
| + virtual void EmitNativeCode(FlowGraphCompiler* compiler);
|
|
|
| - virtual intptr_t DeoptimizationTarget() const {
|
| - return GetDeoptId();
|
| - }
|
| + // Insert this instruction before 'next'.
|
| + void InsertBefore(Instruction* next);
|
|
|
| - virtual Representation RequiredInputRepresentation(intptr_t idx) const {
|
| - ASSERT((idx == 0) || (idx == 1));
|
| - return (receiver_class_id() == kDoubleCid) ? kUnboxedDouble : kTagged;
|
| - }
|
| + // Insert this instruction after 'prev'.
|
| + void InsertAfter(Instruction* prev);
|
| +
|
| + virtual Representation RequiredInputRepresentation(intptr_t i) const;
|
| + virtual Representation representation() const;
|
| + virtual intptr_t DeoptimizationTarget() const;
|
|
|
| private:
|
| - const ICData* ic_data_;
|
| - const intptr_t token_pos_;
|
| - intptr_t receiver_class_id_; // Set by optimizer.
|
| + Computation* computation_;
|
| + const bool is_used_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(EqualityCompareComp);
|
| + DISALLOW_COPY_AND_ASSIGN(BindInstr);
|
| };
|
|
|
|
|
| -class RelationalOpComp : public ComparisonComp {
|
| +class PhiInstr : public Definition {
|
| public:
|
| - RelationalOpComp(intptr_t token_pos,
|
| - Token::Kind kind,
|
| - Value* left,
|
| - Value* right)
|
| - : ComparisonComp(kind, left, right),
|
| - ic_data_(Isolate::Current()->GetICDataForDeoptId(deopt_id())),
|
| - token_pos_(token_pos),
|
| - operands_class_id_(kIllegalCid) {
|
| - ASSERT(Token::IsRelationalOperator(kind));
|
| + explicit PhiInstr(JoinEntryInstr* block, intptr_t num_inputs)
|
| + : block_(block),
|
| + inputs_(num_inputs),
|
| + is_alive_(false),
|
| + representation_(kTagged) {
|
| + for (intptr_t i = 0; i < num_inputs; ++i) {
|
| + inputs_.Add(NULL);
|
| + }
|
| }
|
|
|
| - DECLARE_COMPUTATION(RelationalOp)
|
| + JoinEntryInstr* block() const { return block_; }
|
|
|
| - const ICData* ic_data() const { return ic_data_; }
|
| - bool HasICData() const {
|
| - return (ic_data() != NULL) && !ic_data()->IsNull();
|
| - }
|
| + virtual RawAbstractType* CompileType() const;
|
| + virtual intptr_t GetPropagatedCid() { return propagated_cid(); }
|
|
|
| - intptr_t token_pos() const { return token_pos_; }
|
| + virtual intptr_t ArgumentCount() const { return 0; }
|
|
|
| - // TODO(srdjan): instead of class-id pass an enum that can differentiate
|
| - // between boxed and unboxed doubles and integers.
|
| - void set_operands_class_id(intptr_t value) {
|
| - operands_class_id_ = value;
|
| - }
|
| + intptr_t InputCount() const { return inputs_.length(); }
|
|
|
| - intptr_t operands_class_id() const { return operands_class_id_; }
|
| + Value* InputAt(intptr_t i) const { return inputs_[i]; }
|
|
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| + void SetInputAt(intptr_t i, Value* value) { inputs_[i] = value; }
|
|
|
| - virtual bool CanDeoptimize() const {
|
| - return operands_class_id() != kDoubleCid;
|
| - }
|
| + virtual bool CanDeoptimize() const { return false; }
|
|
|
| - virtual intptr_t ResultCid() const;
|
| + // TODO(regis): This helper will be removed once we support type sets.
|
| + RawAbstractType* LeastSpecificInputType() const;
|
|
|
| - virtual void EmitBranchCode(FlowGraphCompiler* compiler,
|
| - BranchInstr* branch);
|
| + // Phi is alive if it reaches a non-environment use.
|
| + bool is_alive() const { return is_alive_; }
|
| + void mark_alive() { is_alive_ = true; }
|
|
|
| + virtual Representation RequiredInputRepresentation(intptr_t i) const {
|
| + return representation_;
|
| + }
|
|
|
| - virtual intptr_t DeoptimizationTarget() const {
|
| - return GetDeoptId();
|
| + virtual Representation representation() const {
|
| + return representation_;
|
| }
|
|
|
| - virtual Representation RequiredInputRepresentation(intptr_t idx) const {
|
| - ASSERT((idx == 0) || (idx == 1));
|
| - return (operands_class_id() == kDoubleCid) ? kUnboxedDouble : kTagged;
|
| + virtual void set_representation(Representation r) {
|
| + representation_ = r;
|
| }
|
|
|
| + DECLARE_INSTRUCTION(Phi)
|
| +
|
| private:
|
| - const ICData* ic_data_;
|
| - const intptr_t token_pos_;
|
| - intptr_t operands_class_id_; // class id of both operands.
|
| + JoinEntryInstr* block_;
|
| + GrowableArray<Value*> inputs_;
|
| + bool is_alive_;
|
| + Representation representation_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(RelationalOpComp);
|
| + DISALLOW_COPY_AND_ASSIGN(PhiInstr);
|
| };
|
|
|
|
|
| -class StaticCallComp : public TemplateComputation<0> {
|
| +class ParameterInstr : public Definition {
|
| public:
|
| - StaticCallComp(intptr_t token_pos,
|
| - const Function& function,
|
| - const Array& argument_names,
|
| - ZoneGrowableArray<PushArgumentInstr*>* arguments)
|
| - : token_pos_(token_pos),
|
| - function_(function),
|
| - argument_names_(argument_names),
|
| - arguments_(arguments),
|
| - recognized_(MethodRecognizer::kUnknown) {
|
| - ASSERT(function.IsZoneHandle());
|
| - ASSERT(argument_names.IsZoneHandle());
|
| - }
|
| + explicit ParameterInstr(intptr_t index) : index_(index) { }
|
|
|
| - DECLARE_CALL_COMPUTATION(StaticCall)
|
| + DECLARE_INSTRUCTION(Parameter)
|
|
|
| - // Accessors forwarded to the AST node.
|
| - const Function& function() const { return function_; }
|
| - const Array& argument_names() const { return argument_names_; }
|
| - intptr_t token_pos() const { return token_pos_; }
|
| + intptr_t index() const { return index_; }
|
|
|
| - virtual intptr_t ArgumentCount() const { return arguments_->length(); }
|
| - PushArgumentInstr* ArgumentAt(intptr_t index) const {
|
| - return (*arguments_)[index];
|
| - }
|
| + // Compile type of the passed-in parameter.
|
| + virtual RawAbstractType* CompileType() const;
|
| + // No known propagated cid for parameters.
|
| + virtual intptr_t GetPropagatedCid() { return propagated_cid(); }
|
|
|
| - MethodRecognizer::Kind recognized() const { return recognized_; }
|
| - void set_recognized(MethodRecognizer::Kind kind) { recognized_ = kind; }
|
| + virtual intptr_t ArgumentCount() const { return 0; }
|
|
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| + intptr_t InputCount() const { return 0; }
|
| + Value* InputAt(intptr_t i) const {
|
| + UNREACHABLE();
|
| + return NULL;
|
| + }
|
| + void SetInputAt(intptr_t i, Value* value) { UNREACHABLE(); }
|
|
|
| - virtual bool CanDeoptimize() const { return true; }
|
| - virtual intptr_t ResultCid() const { return kDynamicCid; }
|
| + virtual bool CanDeoptimize() const { return false; }
|
|
|
| private:
|
| - const intptr_t token_pos_;
|
| - const Function& function_;
|
| - const Array& argument_names_;
|
| - ZoneGrowableArray<PushArgumentInstr*>* arguments_;
|
| - MethodRecognizer::Kind recognized_;
|
| + const intptr_t index_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(StaticCallComp);
|
| + DISALLOW_COPY_AND_ASSIGN(ParameterInstr);
|
| };
|
|
|
|
|
| -class LoadLocalComp : public TemplateComputation<0> {
|
| +class PushArgumentInstr : public Definition {
|
| public:
|
| - LoadLocalComp(const LocalVariable& local, intptr_t context_level)
|
| - : local_(local),
|
| - context_level_(context_level) { }
|
| + explicit PushArgumentInstr(Value* value) : value_(value), locs_(NULL) {
|
| + ASSERT(value != NULL);
|
| + }
|
|
|
| - DECLARE_COMPUTATION(LoadLocal)
|
| + DECLARE_INSTRUCTION(PushArgument)
|
|
|
| - const LocalVariable& local() const { return local_; }
|
| - intptr_t context_level() const { return context_level_; }
|
| + intptr_t InputCount() const { return 1; }
|
| + Value* InputAt(intptr_t i) const {
|
| + ASSERT(i == 0);
|
| + return value_;
|
| + }
|
| + void SetInputAt(intptr_t i, Value* value) {
|
| + ASSERT(i == 0);
|
| + value_ = value;
|
| + }
|
|
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| + virtual intptr_t ArgumentCount() const { return 0; }
|
| +
|
| + virtual RawAbstractType* CompileType() const;
|
| + virtual intptr_t GetPropagatedCid() { return propagated_cid(); }
|
| +
|
| + Value* value() const { return value_; }
|
| +
|
| + virtual LocationSummary* locs() {
|
| + if (locs_ == NULL) {
|
| + locs_ = MakeLocationSummary();
|
| + }
|
| + return locs_;
|
| + }
|
| +
|
| + LocationSummary* MakeLocationSummary() const;
|
| +
|
| + virtual void EmitNativeCode(FlowGraphCompiler* compiler);
|
|
|
| virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| private:
|
| - const LocalVariable& local_;
|
| - const intptr_t context_level_;
|
| + Value* value_;
|
| + LocationSummary* locs_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(LoadLocalComp);
|
| + DISALLOW_COPY_AND_ASSIGN(PushArgumentInstr);
|
| };
|
|
|
|
|
| -class StoreLocalComp : public TemplateComputation<1> {
|
| +class ReturnInstr : public TemplateInstruction<1> {
|
| public:
|
| - StoreLocalComp(const LocalVariable& local,
|
| - Value* value,
|
| - intptr_t context_level)
|
| - : local_(local),
|
| - context_level_(context_level) {
|
| + ReturnInstr(intptr_t token_pos, Value* value)
|
| + : deopt_id_(Isolate::Current()->GetNextDeoptId()),
|
| + token_pos_(token_pos) {
|
| ASSERT(value != NULL);
|
| inputs_[0] = value;
|
| }
|
|
|
| - DECLARE_COMPUTATION(StoreLocal)
|
| + DECLARE_INSTRUCTION(Return)
|
|
|
| - const LocalVariable& local() const { return local_; }
|
| + virtual intptr_t ArgumentCount() const { return 0; }
|
| +
|
| + intptr_t deopt_id() const { return deopt_id_; }
|
| + intptr_t token_pos() const { return token_pos_; }
|
| Value* value() const { return inputs_[0]; }
|
| - intptr_t context_level() const { return context_level_; }
|
|
|
| - virtual void RecordAssignedVars(BitVector* assigned_vars,
|
| - intptr_t fixed_parameter_count);
|
| + virtual LocationSummary* MakeLocationSummary() const;
|
|
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| + virtual void EmitNativeCode(FlowGraphCompiler* compiler);
|
|
|
| virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| private:
|
| - const LocalVariable& local_;
|
| - const intptr_t context_level_;
|
| + const intptr_t deopt_id_;
|
| + const intptr_t token_pos_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(StoreLocalComp);
|
| + DISALLOW_COPY_AND_ASSIGN(ReturnInstr);
|
| };
|
|
|
|
|
| -class NativeCallComp : public TemplateComputation<0> {
|
| +class ThrowInstr : public TemplateInstruction<0> {
|
| public:
|
| - explicit NativeCallComp(NativeBodyNode* node)
|
| - : ast_node_(*node) {}
|
| -
|
| - DECLARE_COMPUTATION(NativeCall)
|
| -
|
| - intptr_t token_pos() const { return ast_node_.token_pos(); }
|
| -
|
| - const String& native_name() const {
|
| - return ast_node_.native_c_function_name();
|
| - }
|
| + explicit ThrowInstr(intptr_t token_pos) : token_pos_(token_pos) { }
|
|
|
| - NativeFunction native_c_function() const {
|
| - return ast_node_.native_c_function();
|
| - }
|
| + DECLARE_INSTRUCTION(Throw)
|
|
|
| - intptr_t argument_count() const { return ast_node_.argument_count(); }
|
| + virtual intptr_t ArgumentCount() const { return 1; }
|
|
|
| - bool has_optional_parameters() const {
|
| - return ast_node_.has_optional_parameters();
|
| - }
|
| + intptr_t token_pos() const { return token_pos_; }
|
|
|
| - bool is_native_instance_closure() const {
|
| - return ast_node_.is_native_instance_closure();
|
| - }
|
| + virtual LocationSummary* MakeLocationSummary() const;
|
|
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| + virtual void EmitNativeCode(FlowGraphCompiler* compiler);
|
|
|
| virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| private:
|
| - const NativeBodyNode& ast_node_;
|
| + const intptr_t token_pos_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(NativeCallComp);
|
| + DISALLOW_COPY_AND_ASSIGN(ThrowInstr);
|
| };
|
|
|
|
|
| -class LoadInstanceFieldComp : public TemplateComputation<1> {
|
| +class ReThrowInstr : public TemplateInstruction<0> {
|
| public:
|
| - LoadInstanceFieldComp(const Field& field, Value* instance) : field_(field) {
|
| - ASSERT(instance != NULL);
|
| - inputs_[0] = instance;
|
| - }
|
| + explicit ReThrowInstr(intptr_t token_pos) : token_pos_(token_pos) { }
|
|
|
| - DECLARE_COMPUTATION(LoadInstanceField)
|
| + DECLARE_INSTRUCTION(ReThrow)
|
|
|
| - const Field& field() const { return field_; }
|
| - Value* instance() const { return inputs_[0]; }
|
| + virtual intptr_t ArgumentCount() const { return 2; }
|
|
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| + intptr_t token_pos() const { return token_pos_; }
|
| +
|
| + virtual LocationSummary* MakeLocationSummary() const;
|
| +
|
| + virtual void EmitNativeCode(FlowGraphCompiler* compiler);
|
|
|
| virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| private:
|
| - const Field& field_;
|
| + const intptr_t token_pos_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(LoadInstanceFieldComp);
|
| + DISALLOW_COPY_AND_ASSIGN(ReThrowInstr);
|
| };
|
|
|
|
|
| -class StoreInstanceFieldComp : public TemplateComputation<2> {
|
| +class GotoInstr : public TemplateInstruction<0> {
|
| public:
|
| - StoreInstanceFieldComp(const Field& field,
|
| - Value* instance,
|
| - Value* value)
|
| - : field_(field) {
|
| - ASSERT(instance != NULL);
|
| - ASSERT(value != NULL);
|
| - inputs_[0] = instance;
|
| - inputs_[1] = value;
|
| - }
|
| -
|
| - DECLARE_COMPUTATION(StoreInstanceField)
|
| -
|
| - const Field& field() const { return field_; }
|
| -
|
| - Value* instance() const { return inputs_[0]; }
|
| - Value* value() const { return inputs_[1]; }
|
| -
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| + explicit GotoInstr(JoinEntryInstr* entry)
|
| + : successor_(entry),
|
| + parallel_move_(NULL) { }
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kDynamicCid; }
|
| + DECLARE_INSTRUCTION(Goto)
|
|
|
| - private:
|
| - const Field& field_;
|
| + virtual intptr_t ArgumentCount() const { return 0; }
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(StoreInstanceFieldComp);
|
| -};
|
| + JoinEntryInstr* successor() const { return successor_; }
|
| + void set_successor(JoinEntryInstr* successor) { successor_ = successor; }
|
| + virtual intptr_t SuccessorCount() const;
|
| + virtual BlockEntryInstr* SuccessorAt(intptr_t index) const;
|
|
|
| + virtual LocationSummary* MakeLocationSummary() const;
|
|
|
| -class LoadStaticFieldComp : public TemplateComputation<0> {
|
| - public:
|
| - explicit LoadStaticFieldComp(const Field& field) : field_(field) {}
|
| + virtual void EmitNativeCode(FlowGraphCompiler* compiler);
|
|
|
| - DECLARE_COMPUTATION(LoadStaticField);
|
| + virtual bool CanDeoptimize() const { return false; }
|
|
|
| - const Field& field() const { return field_; }
|
| + ParallelMoveInstr* parallel_move() const {
|
| + return parallel_move_;
|
| + }
|
|
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| + bool HasParallelMove() const {
|
| + return parallel_move_ != NULL;
|
| + }
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kDynamicCid; }
|
| + ParallelMoveInstr* GetParallelMove() {
|
| + if (parallel_move_ == NULL) {
|
| + parallel_move_ = new ParallelMoveInstr();
|
| + }
|
| + return parallel_move_;
|
| + }
|
|
|
| private:
|
| - const Field& field_;
|
| + JoinEntryInstr* successor_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(LoadStaticFieldComp);
|
| + // Parallel move that will be used by linear scan register allocator to
|
| + // connect live ranges at the end of the block and resolve phis.
|
| + ParallelMoveInstr* parallel_move_;
|
| };
|
|
|
|
|
| -class StoreStaticFieldComp : public TemplateComputation<1> {
|
| +class ControlInstruction : public Instruction {
|
| public:
|
| - StoreStaticFieldComp(const Field& field, Value* value)
|
| - : field_(field) {
|
| - ASSERT(field.IsZoneHandle());
|
| - ASSERT(value != NULL);
|
| - inputs_[0] = value;
|
| - }
|
| + ControlInstruction() : true_successor_(NULL), false_successor_(NULL) { }
|
|
|
| - DECLARE_COMPUTATION(StoreStaticField);
|
| -
|
| - const Field& field() const { return field_; }
|
| - Value* value() const { return inputs_[0]; }
|
| -
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| -
|
| - virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kDynamicCid; }
|
| -
|
| - private:
|
| - const Field& field_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(StoreStaticFieldComp);
|
| -};
|
| + virtual bool IsControl() const { return true; }
|
|
|
| + TargetEntryInstr* true_successor() const { return true_successor_; }
|
| + TargetEntryInstr* false_successor() const { return false_successor_; }
|
|
|
| -class LoadIndexedComp : public TemplateComputation<2> {
|
| - public:
|
| - LoadIndexedComp(Value* array,
|
| - Value* index,
|
| - intptr_t receiver_type)
|
| - : receiver_type_(receiver_type) {
|
| - ASSERT(array != NULL);
|
| - ASSERT(index != NULL);
|
| - inputs_[0] = array;
|
| - inputs_[1] = index;
|
| - }
|
| + TargetEntryInstr** true_successor_address() { return &true_successor_; }
|
| + TargetEntryInstr** false_successor_address() { return &false_successor_; }
|
|
|
| - DECLARE_COMPUTATION(LoadIndexed)
|
| + virtual intptr_t SuccessorCount() const;
|
| + virtual BlockEntryInstr* SuccessorAt(intptr_t index) const;
|
|
|
| - Value* array() const { return inputs_[0]; }
|
| - Value* index() const { return inputs_[1]; }
|
| + virtual void DiscoverBlocks(
|
| + BlockEntryInstr* current_block,
|
| + GrowableArray<BlockEntryInstr*>* preorder,
|
| + GrowableArray<BlockEntryInstr*>* postorder,
|
| + GrowableArray<intptr_t>* parent,
|
| + GrowableArray<BitVector*>* assigned_vars,
|
| + intptr_t variable_count,
|
| + intptr_t fixed_parameter_count);
|
|
|
| - intptr_t receiver_type() const { return receiver_type_; }
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kDynamicCid; }
|
| + void EmitBranchOnCondition(FlowGraphCompiler* compiler,
|
| + Condition true_condition);
|
|
|
| private:
|
| - intptr_t receiver_type_;
|
| + TargetEntryInstr* true_successor_;
|
| + TargetEntryInstr* false_successor_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(LoadIndexedComp);
|
| + DISALLOW_COPY_AND_ASSIGN(ControlInstruction);
|
| };
|
|
|
|
|
| -class StoreIndexedComp : public TemplateComputation<3> {
|
| +class BranchInstr : public ControlInstruction {
|
| public:
|
| - StoreIndexedComp(Value* array,
|
| - Value* index,
|
| - Value* value,
|
| - intptr_t receiver_type)
|
| - : receiver_type_(receiver_type) {
|
| - ASSERT(array != NULL);
|
| - ASSERT(index != NULL);
|
| - ASSERT(value != NULL);
|
| - inputs_[0] = array;
|
| - inputs_[1] = index;
|
| - inputs_[2] = value;
|
| - }
|
| + explicit BranchInstr(ComparisonComp* computation)
|
| + : computation_(computation), locs_(NULL) { }
|
|
|
| - DECLARE_COMPUTATION(StoreIndexed)
|
| + DECLARE_INSTRUCTION(Branch)
|
|
|
| - Value* array() const { return inputs_[0]; }
|
| - Value* index() const { return inputs_[1]; }
|
| - Value* value() const { return inputs_[2]; }
|
| + virtual intptr_t ArgumentCount() const;
|
| + intptr_t InputCount() const;
|
| + Value* InputAt(intptr_t i) const;
|
| + void SetInputAt(intptr_t i, Value* value);
|
| + virtual bool CanDeoptimize() const;
|
|
|
| - intptr_t receiver_type() const { return receiver_type_; }
|
| + ComparisonComp* computation() const { return computation_; }
|
| + void set_computation(ComparisonComp* value) { computation_ = value; }
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kDynamicCid; }
|
| + virtual void EmitNativeCode(FlowGraphCompiler* compiler);
|
| +
|
| + virtual LocationSummary* locs();
|
| + virtual intptr_t DeoptimizationTarget() const;
|
| + virtual Representation RequiredInputRepresentation(intptr_t i) const;
|
|
|
| private:
|
| - intptr_t receiver_type_;
|
| + ComparisonComp* computation_;
|
| + LocationSummary* locs_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(StoreIndexedComp);
|
| + DISALLOW_COPY_AND_ASSIGN(BranchInstr);
|
| };
|
|
|
|
|
| -// Note overrideable, built-in: value? false : true.
|
| -class BooleanNegateComp : public TemplateComputation<1> {
|
| - public:
|
| - explicit BooleanNegateComp(Value* value) {
|
| - ASSERT(value != NULL);
|
| - inputs_[0] = value;
|
| - }
|
| +#undef DECLARE_INSTRUCTION
|
|
|
| - DECLARE_COMPUTATION(BooleanNegate)
|
|
|
| - Value* value() const { return inputs_[0]; }
|
| +// M is a two argument macro. It is applied to each concrete instruction's
|
| +// (including the values) typename and classname.
|
| +#define FOR_EACH_COMPUTATION(M) \
|
| + M(AssertAssignable, AssertAssignableComp) \
|
| + M(AssertBoolean, AssertBooleanComp) \
|
| + M(ArgumentDefinitionTest, ArgumentDefinitionTestComp) \
|
| + M(CurrentContext, CurrentContextComp) \
|
| + M(StoreContext, StoreContextComp) \
|
| + M(ClosureCall, ClosureCallComp) \
|
| + M(InstanceCall, InstanceCallComp) \
|
| + M(PolymorphicInstanceCall, PolymorphicInstanceCallComp) \
|
| + M(StaticCall, StaticCallComp) \
|
| + M(LoadLocal, LoadLocalComp) \
|
| + M(StoreLocal, StoreLocalComp) \
|
| + M(StrictCompare, StrictCompareComp) \
|
| + M(EqualityCompare, EqualityCompareComp) \
|
| + M(RelationalOp, RelationalOpComp) \
|
| + M(NativeCall, NativeCallComp) \
|
| + M(LoadIndexed, LoadIndexedComp) \
|
| + M(StoreIndexed, StoreIndexedComp) \
|
| + M(LoadInstanceField, LoadInstanceFieldComp) \
|
| + M(StoreInstanceField, StoreInstanceFieldComp) \
|
| + M(LoadStaticField, LoadStaticFieldComp) \
|
| + M(StoreStaticField, StoreStaticFieldComp) \
|
| + M(BooleanNegate, BooleanNegateComp) \
|
| + M(InstanceOf, InstanceOfComp) \
|
| + M(CreateArray, CreateArrayComp) \
|
| + M(CreateClosure, CreateClosureComp) \
|
| + M(AllocateObject, AllocateObjectComp) \
|
| + M(AllocateObjectWithBoundsCheck, AllocateObjectWithBoundsCheckComp) \
|
| + M(LoadVMField, LoadVMFieldComp) \
|
| + M(StoreVMField, StoreVMFieldComp) \
|
| + M(InstantiateTypeArguments, InstantiateTypeArgumentsComp) \
|
| + M(ExtractConstructorTypeArguments, ExtractConstructorTypeArgumentsComp) \
|
| + M(ExtractConstructorInstantiator, ExtractConstructorInstantiatorComp) \
|
| + M(AllocateContext, AllocateContextComp) \
|
| + M(ChainContext, ChainContextComp) \
|
| + M(CloneContext, CloneContextComp) \
|
| + M(CatchEntry, CatchEntryComp) \
|
| + M(BinarySmiOp, BinarySmiOpComp) \
|
| + M(BinaryMintOp, BinaryMintOpComp) \
|
| + M(BinaryDoubleOp, BinaryDoubleOpComp) \
|
| + M(UnarySmiOp, UnarySmiOpComp) \
|
| + M(NumberNegate, NumberNegateComp) \
|
| + M(CheckStackOverflow, CheckStackOverflowComp) \
|
| + M(DoubleToDouble, DoubleToDoubleComp) \
|
| + M(SmiToDouble, SmiToDoubleComp) \
|
| + M(CheckClass, CheckClassComp) \
|
| + M(CheckSmi, CheckSmiComp) \
|
| + M(Constant, ConstantComp) \
|
| + M(CheckEitherNonSmi, CheckEitherNonSmiComp) \
|
| + M(UnboxedDoubleBinaryOp, UnboxedDoubleBinaryOpComp) \
|
| + M(UnboxDouble, UnboxDoubleComp) \
|
| + M(BoxDouble, BoxDoubleComp) \
|
| + M(CheckArrayBound, CheckArrayBoundComp)
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kBoolCid; }
|
|
|
| - private:
|
| - DISALLOW_COPY_AND_ASSIGN(BooleanNegateComp);
|
| -};
|
| +#define FORWARD_DECLARATION(ShortName, ClassName) class ClassName;
|
| +FOR_EACH_COMPUTATION(FORWARD_DECLARATION)
|
| +#undef FORWARD_DECLARATION
|
|
|
|
|
| -class InstanceOfComp : public TemplateComputation<3> {
|
| +class Computation : public ZoneAllocated {
|
| public:
|
| - InstanceOfComp(intptr_t token_pos,
|
| - Value* value,
|
| - Value* instantiator,
|
| - Value* instantiator_type_arguments,
|
| - const AbstractType& type,
|
| - bool negate_result)
|
| - : token_pos_(token_pos),
|
| - type_(type),
|
| - negate_result_(negate_result) {
|
| - ASSERT(value != NULL);
|
| - ASSERT(instantiator != NULL);
|
| - ASSERT(instantiator_type_arguments != NULL);
|
| - ASSERT(!type.IsNull());
|
| - inputs_[0] = value;
|
| - inputs_[1] = instantiator;
|
| - inputs_[2] = instantiator_type_arguments;
|
| - }
|
| + Computation()
|
| + : deopt_id_(Isolate::Current()->GetNextDeoptId()), locs_(NULL) { }
|
|
|
| - DECLARE_COMPUTATION(InstanceOf)
|
| + // Unique id used for deoptimization.
|
| + virtual intptr_t deopt_id() const {
|
| + ASSERT(CanDeoptimize());
|
| + return deopt_id_;
|
| + }
|
|
|
| - Value* value() const { return inputs_[0]; }
|
| - Value* instantiator() const { return inputs_[1]; }
|
| - Value* instantiator_type_arguments() const { return inputs_[2]; }
|
| + // Visiting support.
|
| + virtual void Accept(FlowGraphVisitor* visitor, BindInstr* instr) = 0;
|
|
|
| - bool negate_result() const { return negate_result_; }
|
| - const AbstractType& type() const { return type_; }
|
| - intptr_t token_pos() const { return token_pos_; }
|
| + virtual intptr_t InputCount() const = 0;
|
| + virtual Value* InputAt(intptr_t i) const = 0;
|
| + virtual void SetInputAt(intptr_t i, Value* value) = 0;
|
|
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| + // Call computations override this function and return the
|
| + // number of pushed arguments.
|
| + virtual intptr_t ArgumentCount() const = 0;
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kBoolCid; }
|
| + // Returns true, if this computation can deoptimize.
|
| + virtual bool CanDeoptimize() const = 0;
|
|
|
| - private:
|
| - const intptr_t token_pos_;
|
| - Value* value_;
|
| - Value* instantiator_;
|
| - Value* type_arguments_;
|
| - const AbstractType& type_;
|
| - const bool negate_result_;
|
| + // Returns a replacement for the instruction that wraps this computation.
|
| + // Returns NULL if instr can be eliminated.
|
| + // By default returns instr (input parameter) which means no change.
|
| + virtual Definition* TryReplace(BindInstr* instr) const;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(InstanceOfComp);
|
| -};
|
| + // Compares two computations. Returns true, if:
|
| + // 1. They are of the same kind.
|
| + // 2. All input operands match.
|
| + // 3. All other attributes match.
|
| + bool Equals(Computation* other) const;
|
|
|
| + // Returns a hash code for use with hash maps.
|
| + virtual intptr_t Hashcode() const;
|
|
|
| -class AllocateObjectComp : public TemplateComputation<0> {
|
| - public:
|
| - AllocateObjectComp(ConstructorCallNode* node,
|
| - ZoneGrowableArray<PushArgumentInstr*>* arguments)
|
| - : ast_node_(*node), arguments_(arguments) {
|
| - // Either no arguments or one type-argument and one instantiator.
|
| - ASSERT(arguments->is_empty() || (arguments->length() == 2));
|
| + // Compare attributes of an computation (except input operands and kind).
|
| + // All computations that participate in CSE have to override this function.
|
| + virtual bool AttributesEqual(Computation* other) const {
|
| + UNREACHABLE();
|
| + return false;
|
| }
|
|
|
| - DECLARE_CALL_COMPUTATION(AllocateObject)
|
| + // Returns true if the instruction may have side effects.
|
| + // TODO(fschneider): Make this abstract and implement for all computations
|
| + // instead of returning the safe default (true).
|
| + virtual bool HasSideEffect() const { return true; }
|
|
|
| - virtual intptr_t ArgumentCount() const { return arguments_->length(); }
|
| - PushArgumentInstr* ArgumentAt(intptr_t index) const {
|
| - return (*arguments_)[index];
|
| - }
|
| + // Compile time type of the computation, which typically depends on the
|
| + // compile time types (and possibly propagated types) of its inputs.
|
| + virtual RawAbstractType* CompileType() const = 0;
|
| + virtual intptr_t ResultCid() const = 0;
|
|
|
| - const Function& constructor() const { return ast_node_.constructor(); }
|
| - intptr_t token_pos() const { return ast_node_.token_pos(); }
|
| + // Mutate assigned_vars to add the local variable index for all
|
| + // frame-allocated locals assigned to by the computation.
|
| + virtual void RecordAssignedVars(BitVector* assigned_vars,
|
| + intptr_t fixed_parameter_count);
|
|
|
| + virtual const char* DebugName() const = 0;
|
| +
|
| + // Printing support. These functions are sometimes overridden for custom
|
| + // formatting. Otherwise, it prints in the format "opcode(op1, op2, op3)".
|
| + virtual void PrintTo(BufferFormatter* f) const;
|
| virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kDynamicCid; }
|
| + // Returns structure describing location constraints required
|
| + // to emit native code for this computation.
|
| + LocationSummary* locs() {
|
| + if (locs_ == NULL) {
|
| + locs_ = MakeLocationSummary();
|
| + }
|
| + return locs_;
|
| + }
|
|
|
| - private:
|
| - const ConstructorCallNode& ast_node_;
|
| - ZoneGrowableArray<PushArgumentInstr*>* const arguments_;
|
| + virtual ComparisonComp* AsComparison() { return NULL; }
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(AllocateObjectComp);
|
| -};
|
| + // Create a location summary for this computation.
|
| + // TODO(fschneider): Temporarily returns NULL for instructions
|
| + // that are not yet converted to the location based code generation.
|
| + virtual LocationSummary* MakeLocationSummary() const = 0;
|
|
|
| + // TODO(fschneider): Make EmitNativeCode and locs const.
|
| + virtual void EmitNativeCode(FlowGraphCompiler* compiler) = 0;
|
|
|
| -class AllocateObjectWithBoundsCheckComp : public TemplateComputation<2> {
|
| - public:
|
| - AllocateObjectWithBoundsCheckComp(ConstructorCallNode* node,
|
| - Value* type_arguments,
|
| - Value* instantiator)
|
| - : ast_node_(*node) {
|
| - ASSERT(type_arguments != NULL);
|
| - ASSERT(instantiator != NULL);
|
| - inputs_[0] = type_arguments;
|
| - inputs_[1] = instantiator;
|
| + virtual void EmitBranchCode(FlowGraphCompiler* compiler,
|
| + BranchInstr* branch) {
|
| + UNREACHABLE();
|
| }
|
|
|
| - DECLARE_COMPUTATION(AllocateObjectWithBoundsCheck)
|
| + static LocationSummary* MakeCallSummary();
|
|
|
| - const Function& constructor() const { return ast_node_.constructor(); }
|
| - intptr_t token_pos() const { return ast_node_.token_pos(); }
|
| + // Declare an enum value used to define kind-test predicates.
|
| + enum ComputationKind {
|
| +#define DECLARE_COMPUTATION_KIND(ShortName, ClassName) k##ShortName,
|
|
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| + FOR_EACH_COMPUTATION(DECLARE_COMPUTATION_KIND)
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kDynamicCid; }
|
| +#undef DECLARE_COMPUTATION_KIND
|
| + };
|
| +
|
| + virtual ComputationKind computation_kind() const = 0;
|
| +
|
| + // Returns representation expected for the input operand at the given index.
|
| + virtual Representation RequiredInputRepresentation(intptr_t idx) const {
|
| + return kTagged;
|
| + }
|
| +
|
| + // Representation of the value produced by this computation.
|
| + virtual Representation representation() const {
|
| + return kTagged;
|
| + }
|
| +
|
| + // Returns deoptimization id that corresponds to the deoptimization target
|
| + // that input operands conversions inserted for this instruction can jump
|
| + // to. Can return kNoDeoptId.
|
| + virtual intptr_t DeoptimizationTarget() const {
|
| + UNREACHABLE();
|
| + return Isolate::kNoDeoptId;
|
| + }
|
| +
|
| + // Declare predicate for each computation.
|
| +#define DECLARE_PREDICATE(ShortName, ClassName) \
|
| + inline bool Is##ShortName() const; \
|
| + inline const ClassName* As##ShortName() const; \
|
| + inline ClassName* As##ShortName();
|
| +FOR_EACH_COMPUTATION(DECLARE_PREDICATE)
|
| +#undef DECLARE_PREDICATE
|
| +
|
| + protected:
|
| + // Fetch deopt id without checking if this computation can deoptimize.
|
| + intptr_t GetDeoptId() const {
|
| + return deopt_id_;
|
| + }
|
|
|
| private:
|
| - const ConstructorCallNode& ast_node_;
|
| + friend class BranchInstr;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(AllocateObjectWithBoundsCheckComp);
|
| + intptr_t deopt_id_;
|
| + LocationSummary* locs_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(Computation);
|
| };
|
|
|
|
|
| -class CreateArrayComp : public TemplateComputation<1> {
|
| - public:
|
| - CreateArrayComp(intptr_t token_pos,
|
| - ZoneGrowableArray<PushArgumentInstr*>* arguments,
|
| - const AbstractType& type,
|
| - Value* element_type)
|
| - : token_pos_(token_pos),
|
| - arguments_(arguments),
|
| - type_(type) {
|
| -#if defined(DEBUG)
|
| - for (int i = 0; i < ArgumentCount(); ++i) {
|
| - ASSERT(ArgumentAt(i) != NULL);
|
| - }
|
| - ASSERT(element_type != NULL);
|
| - ASSERT(type_.IsZoneHandle());
|
| - ASSERT(!type_.IsNull());
|
| - ASSERT(type_.IsFinalized());
|
| -#endif
|
| - inputs_[0] = element_type;
|
| - }
|
| +// Inlined functions from class BindInstr that forward to their computation.
|
| +inline intptr_t BindInstr::ArgumentCount() const {
|
| + return computation()->ArgumentCount();
|
| +}
|
|
|
| - DECLARE_CALL_COMPUTATION(CreateArray)
|
|
|
| - virtual intptr_t ArgumentCount() const { return arguments_->length(); }
|
| +inline intptr_t BindInstr::InputCount() const {
|
| + return computation()->InputCount();
|
| +}
|
|
|
| - intptr_t token_pos() const { return token_pos_; }
|
| - PushArgumentInstr* ArgumentAt(intptr_t i) const { return (*arguments_)[i]; }
|
| - const AbstractType& type() const { return type_; }
|
| - Value* element_type() const { return inputs_[0]; }
|
|
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| +inline Value* BindInstr::InputAt(intptr_t i) const {
|
| + return computation()->InputAt(i);
|
| +}
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| - private:
|
| - const intptr_t token_pos_;
|
| - ZoneGrowableArray<PushArgumentInstr*>* const arguments_;
|
| - const AbstractType& type_;
|
| +inline void BindInstr::SetInputAt(intptr_t i, Value* value) {
|
| + computation()->SetInputAt(i, value);
|
| +}
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(CreateArrayComp);
|
| -};
|
| +inline bool BindInstr::CanDeoptimize() const {
|
| + return computation()->CanDeoptimize();
|
| +}
|
|
|
|
|
| -class CreateClosureComp : public TemplateComputation<0> {
|
| - public:
|
| - CreateClosureComp(ClosureNode* node,
|
| - ZoneGrowableArray<PushArgumentInstr*>* arguments)
|
| - : ast_node_(*node),
|
| - arguments_(arguments) { }
|
| +inline intptr_t BindInstr::Hashcode() const {
|
| + return computation()->Hashcode();
|
| +}
|
|
|
| - DECLARE_CALL_COMPUTATION(CreateClosure)
|
|
|
| - intptr_t token_pos() const { return ast_node_.token_pos(); }
|
| - const Function& function() const { return ast_node_.function(); }
|
| +inline bool BindInstr::Equals(BindInstr* other) const {
|
| + return computation()->Equals(other->computation());
|
| +}
|
|
|
| - virtual intptr_t ArgumentCount() const { return arguments_->length(); }
|
| - PushArgumentInstr* ArgumentAt(intptr_t index) const {
|
| - return (*arguments_)[index];
|
| - }
|
|
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| +inline LocationSummary* BindInstr::locs() {
|
| + return computation()->locs();
|
| +}
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| - private:
|
| - const ClosureNode& ast_node_;
|
| - ZoneGrowableArray<PushArgumentInstr*>* arguments_;
|
| +inline Representation BindInstr::RequiredInputRepresentation(intptr_t i) const {
|
| + return computation()->RequiredInputRepresentation(i);
|
| +}
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(CreateClosureComp);
|
| -};
|
| +
|
| +inline Representation BindInstr::representation() const {
|
| + return computation()->representation();
|
| +}
|
|
|
|
|
| -class LoadVMFieldComp : public TemplateComputation<1> {
|
| +inline intptr_t BindInstr::DeoptimizationTarget() const {
|
| + return computation()->DeoptimizationTarget();
|
| +}
|
| +
|
| +
|
| +template<intptr_t N>
|
| +class TemplateComputation : public Computation {
|
| public:
|
| - LoadVMFieldComp(Value* value,
|
| - intptr_t offset_in_bytes,
|
| - const AbstractType& type)
|
| - : offset_in_bytes_(offset_in_bytes),
|
| - type_(type),
|
| - result_cid_(kDynamicCid) {
|
| + virtual intptr_t InputCount() const { return N; }
|
| + virtual Value* InputAt(intptr_t i) const { return inputs_[i]; }
|
| + virtual void SetInputAt(intptr_t i, Value* value) {
|
| ASSERT(value != NULL);
|
| - ASSERT(type.IsZoneHandle()); // May be null if field is not an instance.
|
| - inputs_[0] = value;
|
| + inputs_[i] = value;
|
| }
|
|
|
| - DECLARE_COMPUTATION(LoadVMField)
|
| -
|
| - Value* value() const { return inputs_[0]; }
|
| - intptr_t offset_in_bytes() const { return offset_in_bytes_; }
|
| - const AbstractType& type() const { return type_; }
|
| - void set_result_cid(intptr_t value) { result_cid_ = value; }
|
| + protected:
|
| + EmbeddedArray<Value*, N> inputs_;
|
| +};
|
|
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return result_cid_; }
|
| +// Functions defined in all concrete computation classes.
|
| +#define DECLARE_COMPUTATION(ShortName) \
|
| + virtual void Accept(FlowGraphVisitor* visitor, BindInstr* instr); \
|
| + virtual ComputationKind computation_kind() const { \
|
| + return Computation::k##ShortName; \
|
| + } \
|
| + virtual intptr_t ArgumentCount() const { return 0; } \
|
| + virtual const char* DebugName() const { return #ShortName; } \
|
| + virtual RawAbstractType* CompileType() const; \
|
| + virtual LocationSummary* MakeLocationSummary() const; \
|
| + virtual void EmitNativeCode(FlowGraphCompiler* compiler);
|
|
|
| - private:
|
| - const intptr_t offset_in_bytes_;
|
| - const AbstractType& type_;
|
| - intptr_t result_cid_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(LoadVMFieldComp);
|
| -};
|
| +// Function defined in all call computation classes.
|
| +#define DECLARE_CALL_COMPUTATION(ShortName) \
|
| + virtual void Accept(FlowGraphVisitor* visitor, BindInstr* instr); \
|
| + virtual ComputationKind computation_kind() const { \
|
| + return Computation::k##ShortName; \
|
| + } \
|
| + virtual const char* DebugName() const { return #ShortName; } \
|
| + virtual RawAbstractType* CompileType() const; \
|
| + virtual LocationSummary* MakeLocationSummary() const; \
|
| + virtual void EmitNativeCode(FlowGraphCompiler* compiler);
|
|
|
|
|
| -class StoreVMFieldComp : public TemplateComputation<2> {
|
| +class ConstantComp : public TemplateComputation<0> {
|
| public:
|
| - StoreVMFieldComp(Value* dest,
|
| - intptr_t offset_in_bytes,
|
| - Value* value,
|
| - const AbstractType& type)
|
| - : offset_in_bytes_(offset_in_bytes), type_(type) {
|
| - ASSERT(value != NULL);
|
| - ASSERT(dest != NULL);
|
| - ASSERT(type.IsZoneHandle()); // May be null if field is not an instance.
|
| - inputs_[0] = value;
|
| - inputs_[1] = dest;
|
| - }
|
| + explicit ConstantComp(const Object& value) : value_(value) { }
|
|
|
| - DECLARE_COMPUTATION(StoreVMField)
|
| + DECLARE_COMPUTATION(Constant)
|
|
|
| - Value* value() const { return inputs_[0]; }
|
| - Value* dest() const { return inputs_[1]; }
|
| - intptr_t offset_in_bytes() const { return offset_in_bytes_; }
|
| - const AbstractType& type() const { return type_; }
|
| + const Object& value() const { return value_; }
|
|
|
| virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kDynamicCid; }
|
| +
|
| + virtual intptr_t ResultCid() const;
|
| +
|
| + virtual bool AttributesEqual(Computation* other) const;
|
|
|
| private:
|
| - const intptr_t offset_in_bytes_;
|
| - const AbstractType& type_;
|
| + const Object& value_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(StoreVMFieldComp);
|
| + DISALLOW_COPY_AND_ASSIGN(ConstantComp);
|
| };
|
|
|
|
|
| -class InstantiateTypeArgumentsComp : public TemplateComputation<1> {
|
| +class AssertAssignableComp : public TemplateComputation<3> {
|
| public:
|
| - InstantiateTypeArgumentsComp(intptr_t token_pos,
|
| - const AbstractTypeArguments& type_arguments,
|
| - Value* instantiator)
|
| - : token_pos_(token_pos),
|
| - type_arguments_(type_arguments) {
|
| - ASSERT(type_arguments.IsZoneHandle());
|
| + AssertAssignableComp(intptr_t token_pos,
|
| + Value* value,
|
| + Value* instantiator,
|
| + Value* instantiator_type_arguments,
|
| + const AbstractType& dst_type,
|
| + const String& dst_name)
|
| + : token_pos_(token_pos),
|
| + dst_type_(dst_type),
|
| + dst_name_(dst_name),
|
| + is_eliminated_(false) {
|
| + ASSERT(value != NULL);
|
| ASSERT(instantiator != NULL);
|
| - inputs_[0] = instantiator;
|
| + ASSERT(instantiator_type_arguments != NULL);
|
| + ASSERT(!dst_type.IsNull());
|
| + ASSERT(!dst_name.IsNull());
|
| + inputs_[0] = value;
|
| + inputs_[1] = instantiator;
|
| + inputs_[2] = instantiator_type_arguments;
|
| }
|
|
|
| - DECLARE_COMPUTATION(InstantiateTypeArguments)
|
| + DECLARE_COMPUTATION(AssertAssignable)
|
| +
|
| + Value* value() const { return inputs_[0]; }
|
| + Value* instantiator() const { return inputs_[1]; }
|
| + Value* instantiator_type_arguments() const { return inputs_[2]; }
|
|
|
| - Value* instantiator() const { return inputs_[0]; }
|
| - const AbstractTypeArguments& type_arguments() const {
|
| - return type_arguments_;
|
| - }
|
| intptr_t token_pos() const { return token_pos_; }
|
| + const AbstractType& dst_type() const { return dst_type_; }
|
| + const String& dst_name() const { return dst_name_; }
|
| +
|
| + bool is_eliminated() const {
|
| + return is_eliminated_;
|
| + }
|
| + void eliminate() {
|
| + ASSERT(!is_eliminated_);
|
| + is_eliminated_ = true;
|
| + }
|
|
|
| virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| @@ -1496,1782 +1613,1716 @@ class InstantiateTypeArgumentsComp : public TemplateComputation<1> {
|
|
|
| private:
|
| const intptr_t token_pos_;
|
| - const AbstractTypeArguments& type_arguments_;
|
| + const AbstractType& dst_type_;
|
| + const String& dst_name_;
|
| + bool is_eliminated_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(InstantiateTypeArgumentsComp);
|
| + DISALLOW_COPY_AND_ASSIGN(AssertAssignableComp);
|
| };
|
|
|
|
|
| -class ExtractConstructorTypeArgumentsComp : public TemplateComputation<1> {
|
| +class AssertBooleanComp : public TemplateComputation<1> {
|
| public:
|
| - ExtractConstructorTypeArgumentsComp(
|
| - intptr_t token_pos,
|
| - const AbstractTypeArguments& type_arguments,
|
| - Value* instantiator)
|
| + AssertBooleanComp(intptr_t token_pos,
|
| + Value* value)
|
| : token_pos_(token_pos),
|
| - type_arguments_(type_arguments) {
|
| - ASSERT(instantiator != NULL);
|
| - inputs_[0] = instantiator;
|
| + is_eliminated_(false) {
|
| + ASSERT(value != NULL);
|
| + inputs_[0] = value;
|
| }
|
|
|
| - DECLARE_COMPUTATION(ExtractConstructorTypeArguments)
|
| + DECLARE_COMPUTATION(AssertBoolean)
|
|
|
| - Value* instantiator() const { return inputs_[0]; }
|
| - const AbstractTypeArguments& type_arguments() const {
|
| - return type_arguments_;
|
| - }
|
| intptr_t token_pos() const { return token_pos_; }
|
| + Value* value() const { return inputs_[0]; }
|
| +
|
| + bool is_eliminated() const {
|
| + return is_eliminated_;
|
| + }
|
| + void eliminate() {
|
| + ASSERT(!is_eliminated_);
|
| + is_eliminated_ = true;
|
| + }
|
|
|
| virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kDynamicCid; }
|
| + virtual intptr_t ResultCid() const { return kBoolCid; }
|
|
|
| private:
|
| const intptr_t token_pos_;
|
| - const AbstractTypeArguments& type_arguments_;
|
| + bool is_eliminated_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(ExtractConstructorTypeArgumentsComp);
|
| + DISALLOW_COPY_AND_ASSIGN(AssertBooleanComp);
|
| };
|
|
|
|
|
| -class ExtractConstructorInstantiatorComp : public TemplateComputation<1> {
|
| +class ArgumentDefinitionTestComp : public TemplateComputation<1> {
|
| public:
|
| - ExtractConstructorInstantiatorComp(ConstructorCallNode* ast_node,
|
| - Value* instantiator)
|
| - : ast_node_(*ast_node) {
|
| - ASSERT(instantiator != NULL);
|
| - inputs_[0] = instantiator;
|
| + ArgumentDefinitionTestComp(ArgumentDefinitionTestNode* node,
|
| + Value* saved_arguments_descriptor)
|
| + : ast_node_(*node) {
|
| + ASSERT(saved_arguments_descriptor != NULL);
|
| + inputs_[0] = saved_arguments_descriptor;
|
| }
|
|
|
| - DECLARE_COMPUTATION(ExtractConstructorInstantiator)
|
| + DECLARE_COMPUTATION(ArgumentDefinitionTest)
|
|
|
| - Value* instantiator() const { return inputs_[0]; }
|
| - const AbstractTypeArguments& type_arguments() const {
|
| - return ast_node_.type_arguments();
|
| - }
|
| - const Function& constructor() const { return ast_node_.constructor(); }
|
| intptr_t token_pos() const { return ast_node_.token_pos(); }
|
| + intptr_t formal_parameter_index() const {
|
| + return ast_node_.formal_parameter_index();
|
| + }
|
| + const String& formal_parameter_name() const {
|
| + return ast_node_.formal_parameter_name();
|
| + }
|
| + Value* saved_arguments_descriptor() const { return inputs_[0]; }
|
| +
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kDynamicCid; }
|
| + virtual intptr_t ResultCid() const { return kBoolCid; }
|
|
|
| private:
|
| - const ConstructorCallNode& ast_node_;
|
| + const ArgumentDefinitionTestNode& ast_node_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(ExtractConstructorInstantiatorComp);
|
| + DISALLOW_COPY_AND_ASSIGN(ArgumentDefinitionTestComp);
|
| };
|
|
|
|
|
| -class AllocateContextComp : public TemplateComputation<0> {
|
| +// Denotes the current context, normally held in a register. This is
|
| +// a computation, not a value, because it's mutable.
|
| +class CurrentContextComp : public TemplateComputation<0> {
|
| public:
|
| - AllocateContextComp(intptr_t token_pos,
|
| - intptr_t num_context_variables)
|
| - : token_pos_(token_pos),
|
| - num_context_variables_(num_context_variables) {}
|
| -
|
| - DECLARE_COMPUTATION(AllocateContext);
|
| -
|
| - intptr_t token_pos() const { return token_pos_; }
|
| - intptr_t num_context_variables() const { return num_context_variables_; }
|
| + CurrentContextComp() { }
|
|
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| + DECLARE_COMPUTATION(CurrentContext)
|
|
|
| virtual bool CanDeoptimize() const { return false; }
|
| virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| private:
|
| - const intptr_t token_pos_;
|
| - const intptr_t num_context_variables_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(AllocateContextComp);
|
| + DISALLOW_COPY_AND_ASSIGN(CurrentContextComp);
|
| };
|
|
|
|
|
| -class ChainContextComp : public TemplateComputation<1> {
|
| +class StoreContextComp : public TemplateComputation<1> {
|
| public:
|
| - explicit ChainContextComp(Value* context_value) {
|
| - ASSERT(context_value != NULL);
|
| - inputs_[0] = context_value;
|
| + explicit StoreContextComp(Value* value) {
|
| + ASSERT(value != NULL);
|
| + inputs_[0] = value;
|
| }
|
|
|
| - DECLARE_COMPUTATION(ChainContext)
|
| + DECLARE_COMPUTATION(StoreContext);
|
|
|
| - Value* context_value() const { return inputs_[0]; }
|
| + Value* value() const { return inputs_[0]; }
|
|
|
| virtual bool CanDeoptimize() const { return false; }
|
| virtual intptr_t ResultCid() const { return kIllegalCid; }
|
|
|
| private:
|
| - DISALLOW_COPY_AND_ASSIGN(ChainContextComp);
|
| + DISALLOW_COPY_AND_ASSIGN(StoreContextComp);
|
| };
|
|
|
|
|
| -class CloneContextComp : public TemplateComputation<1> {
|
| +class ClosureCallComp : public TemplateComputation<0> {
|
| public:
|
| - CloneContextComp(intptr_t token_pos,
|
| - Value* context_value)
|
| - : token_pos_(token_pos) {
|
| - ASSERT(context_value != NULL);
|
| - inputs_[0] = context_value;
|
| - }
|
| + ClosureCallComp(ClosureCallNode* node,
|
| + ZoneGrowableArray<PushArgumentInstr*>* arguments)
|
| + : ast_node_(*node),
|
| + arguments_(arguments) { }
|
|
|
| - intptr_t token_pos() const { return token_pos_; }
|
| - Value* context_value() const { return inputs_[0]; }
|
| + DECLARE_CALL_COMPUTATION(ClosureCall)
|
|
|
| - DECLARE_COMPUTATION(CloneContext)
|
| + const Array& argument_names() const { return ast_node_.arguments()->names(); }
|
| + intptr_t token_pos() const { return ast_node_.token_pos(); }
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kIllegalCid; }
|
| + virtual intptr_t ArgumentCount() const { return arguments_->length(); }
|
| + PushArgumentInstr* ArgumentAt(intptr_t index) const {
|
| + return (*arguments_)[index];
|
| + }
|
| +
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| +
|
| + virtual bool CanDeoptimize() const { return true; }
|
| + virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| private:
|
| - const intptr_t token_pos_;
|
| + const ClosureCallNode& ast_node_;
|
| + ZoneGrowableArray<PushArgumentInstr*>* arguments_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(CloneContextComp);
|
| + DISALLOW_COPY_AND_ASSIGN(ClosureCallComp);
|
| };
|
|
|
|
|
| -class CatchEntryComp : public TemplateComputation<0> {
|
| +class InstanceCallComp : public TemplateComputation<0> {
|
| public:
|
| - CatchEntryComp(const LocalVariable& exception_var,
|
| - const LocalVariable& stacktrace_var)
|
| - : exception_var_(exception_var), stacktrace_var_(stacktrace_var) {}
|
| + InstanceCallComp(intptr_t token_pos,
|
| + const String& function_name,
|
| + Token::Kind token_kind,
|
| + ZoneGrowableArray<PushArgumentInstr*>* arguments,
|
| + const Array& argument_names,
|
| + intptr_t checked_argument_count)
|
| + : ic_data_(Isolate::Current()->GetICDataForDeoptId(deopt_id())),
|
| + token_pos_(token_pos),
|
| + function_name_(function_name),
|
| + token_kind_(token_kind),
|
| + arguments_(arguments),
|
| + argument_names_(argument_names),
|
| + checked_argument_count_(checked_argument_count) {
|
| + ASSERT(function_name.IsZoneHandle());
|
| + ASSERT(!arguments->is_empty());
|
| + ASSERT(argument_names.IsZoneHandle());
|
| + ASSERT(Token::IsBinaryToken(token_kind) ||
|
| + Token::IsUnaryToken(token_kind) ||
|
| + Token::IsIndexOperator(token_kind) ||
|
| + token_kind == Token::kGET ||
|
| + token_kind == Token::kSET ||
|
| + token_kind == Token::kILLEGAL);
|
| + }
|
|
|
| - const LocalVariable& exception_var() const { return exception_var_; }
|
| - const LocalVariable& stacktrace_var() const { return stacktrace_var_; }
|
| + DECLARE_CALL_COMPUTATION(InstanceCall)
|
|
|
| - DECLARE_COMPUTATION(CatchEntry)
|
| + const ICData* ic_data() const { return ic_data_; }
|
| + bool HasICData() const {
|
| + return (ic_data() != NULL) && !ic_data()->IsNull();
|
| + }
|
| +
|
| + intptr_t token_pos() const { return token_pos_; }
|
| + const String& function_name() const { return function_name_; }
|
| + Token::Kind token_kind() const { return token_kind_; }
|
| + virtual intptr_t ArgumentCount() const { return arguments_->length(); }
|
| + PushArgumentInstr* ArgumentAt(intptr_t index) const {
|
| + return (*arguments_)[index];
|
| + }
|
| + const Array& argument_names() const { return argument_names_; }
|
| + intptr_t checked_argument_count() const { return checked_argument_count_; }
|
|
|
| virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kIllegalCid; }
|
| + virtual bool CanDeoptimize() const { return true; }
|
| + virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| private:
|
| - const LocalVariable& exception_var_;
|
| - const LocalVariable& stacktrace_var_;
|
| + const ICData* ic_data_;
|
| + const intptr_t token_pos_;
|
| + const String& function_name_;
|
| + const Token::Kind token_kind_; // Binary op, unary op, kGET or kILLEGAL.
|
| + ZoneGrowableArray<PushArgumentInstr*>* const arguments_;
|
| + const Array& argument_names_;
|
| + const intptr_t checked_argument_count_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(CatchEntryComp);
|
| + DISALLOW_COPY_AND_ASSIGN(InstanceCallComp);
|
| };
|
|
|
|
|
| -class CheckEitherNonSmiComp : public TemplateComputation<2> {
|
| +class PolymorphicInstanceCallComp : public TemplateComputation<0> {
|
| public:
|
| - CheckEitherNonSmiComp(Value* left,
|
| - Value* right,
|
| - InstanceCallComp* instance_call)
|
| - : instance_call_(instance_call) {
|
| - ASSERT(left != NULL);
|
| - ASSERT(right != NULL);
|
| - inputs_[0] = left;
|
| - inputs_[1] = right;
|
| - }
|
| -
|
| - DECLARE_COMPUTATION(CheckEitherNonSmi)
|
| + PolymorphicInstanceCallComp(InstanceCallComp* comp,
|
| + const ICData& ic_data,
|
| + bool with_checks)
|
| + : instance_call_(comp), ic_data_(ic_data), with_checks_(with_checks) {
|
| + ASSERT(instance_call_ != NULL);
|
| + }
|
|
|
| - virtual bool CanDeoptimize() const { return true; }
|
| - virtual intptr_t ResultCid() const { return kIllegalCid; }
|
| + InstanceCallComp* instance_call() const { return instance_call_; }
|
| + bool with_checks() const { return with_checks_; }
|
|
|
| - virtual bool AttributesEqual(Computation* other) const { return true; }
|
| + void PrintTo(BufferFormatter* f) const;
|
|
|
| - virtual bool HasSideEffect() const { return false; }
|
| + virtual intptr_t ArgumentCount() const {
|
| + return instance_call()->ArgumentCount();
|
| + }
|
|
|
| - Value* left() const { return inputs_[0]; }
|
| + DECLARE_CALL_COMPUTATION(PolymorphicInstanceCall)
|
|
|
| - Value* right() const { return inputs_[1]; }
|
| + const ICData& ic_data() const { return ic_data_; }
|
|
|
| - virtual Definition* TryReplace(BindInstr* instr) const;
|
| + virtual bool CanDeoptimize() const { return true; }
|
| + virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| private:
|
| InstanceCallComp* instance_call_;
|
| + const ICData& ic_data_;
|
| + const bool with_checks_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(CheckEitherNonSmiComp);
|
| + DISALLOW_COPY_AND_ASSIGN(PolymorphicInstanceCallComp);
|
| };
|
|
|
|
|
| -class BoxDoubleComp : public TemplateComputation<1> {
|
| +class ComparisonComp : public TemplateComputation<2> {
|
| public:
|
| - BoxDoubleComp(Value* value, InstanceCallComp* instance_call)
|
| - : token_pos_((instance_call != NULL) ? instance_call->token_pos() : 0) {
|
| - ASSERT(value != NULL);
|
| - inputs_[0] = value;
|
| + ComparisonComp(Token::Kind kind, Value* left, Value* right) : kind_(kind) {
|
| + ASSERT(left != NULL);
|
| + ASSERT(right != NULL);
|
| + inputs_[0] = left;
|
| + inputs_[1] = right;
|
| }
|
|
|
| - Value* value() const { return inputs_[0]; }
|
| + Value* left() const { return inputs_[0]; }
|
| + Value* right() const { return inputs_[1]; }
|
|
|
| - intptr_t token_pos() const { return token_pos_; }
|
| + virtual ComparisonComp* AsComparison() { return this; }
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| - virtual bool HasSideEffect() const { return false; }
|
| - virtual bool AttributesEqual(Computation* other) const { return true; }
|
| + Token::Kind kind() const { return kind_; }
|
|
|
| - virtual intptr_t ResultCid() const;
|
| + private:
|
| + Token::Kind kind_;
|
| +};
|
|
|
| - virtual Representation RequiredInputRepresentation(intptr_t idx) const {
|
| - ASSERT(idx == 0);
|
| - return kUnboxedDouble;
|
| - }
|
|
|
| - DECLARE_COMPUTATION(BoxDouble)
|
| +// Inlined functions from class BranchInstr that forward to their comparison.
|
| +inline intptr_t BranchInstr::ArgumentCount() const {
|
| + return computation()->ArgumentCount();
|
| +}
|
|
|
| - private:
|
| - const intptr_t token_pos_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(BoxDoubleComp);
|
| -};
|
| +inline intptr_t BranchInstr::InputCount() const {
|
| + return computation()->InputCount();
|
| +}
|
|
|
|
|
| -class UnboxDoubleComp : public TemplateComputation<1> {
|
| - public:
|
| - UnboxDoubleComp(Value* value, intptr_t deopt_id)
|
| - : deopt_id_(deopt_id) {
|
| - ASSERT(value != NULL);
|
| - inputs_[0] = value;
|
| - }
|
| +inline Value* BranchInstr::InputAt(intptr_t i) const {
|
| + return computation()->InputAt(i);
|
| +}
|
|
|
| - Value* value() const { return inputs_[0]; }
|
|
|
| - virtual bool CanDeoptimize() const {
|
| - return value()->ResultCid() != kDoubleCid;
|
| - }
|
| +inline void BranchInstr::SetInputAt(intptr_t i, Value* value) {
|
| + computation()->SetInputAt(i, value);
|
| +}
|
|
|
| - // The output is not an instance but when it is boxed it becomes double.
|
| - virtual intptr_t ResultCid() const { return kDoubleCid; }
|
|
|
| - virtual Representation representation() const {
|
| - return kUnboxedDouble;
|
| +inline bool BranchInstr::CanDeoptimize() const {
|
| + return computation()->CanDeoptimize();
|
| +}
|
| +
|
| +
|
| +inline LocationSummary* BranchInstr::locs() {
|
| + if (computation_->locs_ == NULL) {
|
| + LocationSummary* summary = computation_->MakeLocationSummary();
|
| + // Branches don't produce a result.
|
| + summary->set_out(Location::NoLocation());
|
| + computation_->locs_ = summary;
|
| }
|
| + return computation_->locs_;
|
| +}
|
|
|
| - virtual bool HasSideEffect() const { return false; }
|
| - virtual bool AttributesEqual(Computation* other) const { return true; }
|
|
|
| - DECLARE_COMPUTATION(UnboxDouble)
|
| +inline intptr_t BranchInstr::DeoptimizationTarget() const {
|
| + return computation_->DeoptimizationTarget();
|
| +}
|
|
|
| - private:
|
| - const intptr_t deopt_id_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(UnboxDoubleComp);
|
| -};
|
| +inline Representation BranchInstr::RequiredInputRepresentation(
|
| + intptr_t i) const {
|
| + return computation()->RequiredInputRepresentation(i);
|
| +}
|
|
|
|
|
| -class UnboxedDoubleBinaryOpComp : public TemplateComputation<2> {
|
| +class StrictCompareComp : public ComparisonComp {
|
| public:
|
| - UnboxedDoubleBinaryOpComp(Token::Kind op_kind,
|
| - Value* left,
|
| - Value* right,
|
| - InstanceCallComp* call)
|
| - : op_kind_(op_kind), deopt_id_(call->deopt_id()) {
|
| - ASSERT(left != NULL);
|
| - ASSERT(right != NULL);
|
| - inputs_[0] = left;
|
| - inputs_[1] = right;
|
| + StrictCompareComp(Token::Kind kind, Value* left, Value* right)
|
| + : ComparisonComp(kind, left, right) {
|
| + ASSERT((kind == Token::kEQ_STRICT) || (kind == Token::kNE_STRICT));
|
| }
|
|
|
| - Value* left() const { return inputs_[0]; }
|
| - Value* right() const { return inputs_[1]; }
|
| -
|
| - Token::Kind op_kind() const { return op_kind_; }
|
| + DECLARE_COMPUTATION(StrictCompare)
|
|
|
| virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| virtual bool CanDeoptimize() const { return false; }
|
| - virtual bool HasSideEffect() const { return false; }
|
| -
|
| - virtual bool AttributesEqual(Computation* other) const {
|
| - return op_kind() == other->AsUnboxedDoubleBinaryOp()->op_kind();
|
| - }
|
| -
|
| - // The output is not an instance but when it is boxed it becomes double.
|
| - virtual intptr_t ResultCid() const { return kDoubleCid; }
|
|
|
| - virtual Representation representation() const {
|
| - return kUnboxedDouble;
|
| - }
|
| -
|
| - virtual Representation RequiredInputRepresentation(intptr_t idx) const {
|
| - ASSERT((idx == 0) || (idx == 1));
|
| - return kUnboxedDouble;
|
| - }
|
| + virtual Definition* TryReplace(BindInstr* instr) const;
|
|
|
| - virtual intptr_t DeoptimizationTarget() const {
|
| - return deopt_id_;
|
| - }
|
| + virtual intptr_t ResultCid() const { return kBoolCid; }
|
|
|
| - DECLARE_COMPUTATION(UnboxedDoubleBinaryOp)
|
| + virtual void EmitBranchCode(FlowGraphCompiler* compiler,
|
| + BranchInstr* branch);
|
|
|
| private:
|
| - const Token::Kind op_kind_;
|
| - const intptr_t deopt_id_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(UnboxedDoubleBinaryOpComp);
|
| + DISALLOW_COPY_AND_ASSIGN(StrictCompareComp);
|
| };
|
|
|
|
|
| -class BinarySmiOpComp : public TemplateComputation<2> {
|
| +class EqualityCompareComp : public ComparisonComp {
|
| public:
|
| - BinarySmiOpComp(Token::Kind op_kind,
|
| - InstanceCallComp* instance_call,
|
| - Value* left,
|
| - Value* right)
|
| - : op_kind_(op_kind),
|
| - instance_call_(instance_call) {
|
| - ASSERT(left != NULL);
|
| - ASSERT(right != NULL);
|
| - inputs_[0] = left;
|
| - inputs_[1] = right;
|
| + EqualityCompareComp(intptr_t token_pos,
|
| + Token::Kind kind,
|
| + Value* left,
|
| + Value* right)
|
| + : ComparisonComp(kind, left, right),
|
| + ic_data_(Isolate::Current()->GetICDataForDeoptId(deopt_id())),
|
| + token_pos_(token_pos),
|
| + receiver_class_id_(kIllegalCid) {
|
| + ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
|
| }
|
|
|
| - Value* left() const { return inputs_[0]; }
|
| - Value* right() const { return inputs_[1]; }
|
| + DECLARE_COMPUTATION(EqualityCompare)
|
|
|
| - Token::Kind op_kind() const { return op_kind_; }
|
| + const ICData* ic_data() const { return ic_data_; }
|
| + bool HasICData() const {
|
| + return (ic_data() != NULL) && !ic_data()->IsNull();
|
| + }
|
|
|
| - InstanceCallComp* instance_call() const { return instance_call_; }
|
| + intptr_t token_pos() const { return token_pos_; }
|
|
|
| - const ICData* ic_data() const { return instance_call()->ic_data(); }
|
| + // Receiver class id is computed from collected ICData.
|
| + void set_receiver_class_id(intptr_t value) { receiver_class_id_ = value; }
|
| + intptr_t receiver_class_id() const { return receiver_class_id_; }
|
|
|
| virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - DECLARE_COMPUTATION(BinarySmiOp)
|
| -
|
| - virtual bool CanDeoptimize() const;
|
| + virtual bool CanDeoptimize() const {
|
| + return (receiver_class_id() != kDoubleCid);
|
| + }
|
|
|
| virtual intptr_t ResultCid() const;
|
|
|
| + virtual void EmitBranchCode(FlowGraphCompiler* compiler,
|
| + BranchInstr* branch);
|
| +
|
| + virtual intptr_t DeoptimizationTarget() const {
|
| + return GetDeoptId();
|
| + }
|
| +
|
| + virtual Representation RequiredInputRepresentation(intptr_t idx) const {
|
| + ASSERT((idx == 0) || (idx == 1));
|
| + return (receiver_class_id() == kDoubleCid) ? kUnboxedDouble : kTagged;
|
| + }
|
| +
|
| private:
|
| - const Token::Kind op_kind_;
|
| - InstanceCallComp* instance_call_;
|
| + const ICData* ic_data_;
|
| + const intptr_t token_pos_;
|
| + intptr_t receiver_class_id_; // Set by optimizer.
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(BinarySmiOpComp);
|
| + DISALLOW_COPY_AND_ASSIGN(EqualityCompareComp);
|
| };
|
|
|
|
|
| -class BinaryMintOpComp : public TemplateComputation<2> {
|
| +class RelationalOpComp : public ComparisonComp {
|
| public:
|
| - BinaryMintOpComp(Token::Kind op_kind,
|
| - InstanceCallComp* instance_call,
|
| + RelationalOpComp(intptr_t token_pos,
|
| + Token::Kind kind,
|
| Value* left,
|
| Value* right)
|
| - : op_kind_(op_kind),
|
| - instance_call_(instance_call) {
|
| - ASSERT(left != NULL);
|
| - ASSERT(right != NULL);
|
| - inputs_[0] = left;
|
| - inputs_[1] = right;
|
| + : ComparisonComp(kind, left, right),
|
| + ic_data_(Isolate::Current()->GetICDataForDeoptId(deopt_id())),
|
| + token_pos_(token_pos),
|
| + operands_class_id_(kIllegalCid) {
|
| + ASSERT(Token::IsRelationalOperator(kind));
|
| }
|
|
|
| - Value* left() const { return inputs_[0]; }
|
| - Value* right() const { return inputs_[1]; }
|
| + DECLARE_COMPUTATION(RelationalOp)
|
|
|
| - Token::Kind op_kind() const { return op_kind_; }
|
| + const ICData* ic_data() const { return ic_data_; }
|
| + bool HasICData() const {
|
| + return (ic_data() != NULL) && !ic_data()->IsNull();
|
| + }
|
|
|
| - InstanceCallComp* instance_call() const { return instance_call_; }
|
| + intptr_t token_pos() const { return token_pos_; }
|
|
|
| - const ICData* ic_data() const { return instance_call()->ic_data(); }
|
| + // TODO(srdjan): instead of class-id pass an enum that can differentiate
|
| + // between boxed and unboxed doubles and integers.
|
| + void set_operands_class_id(intptr_t value) {
|
| + operands_class_id_ = value;
|
| + }
|
| +
|
| + intptr_t operands_class_id() const { return operands_class_id_; }
|
|
|
| virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - DECLARE_COMPUTATION(BinaryMintOp)
|
| + virtual bool CanDeoptimize() const {
|
| + return operands_class_id() != kDoubleCid;
|
| + }
|
|
|
| - virtual bool CanDeoptimize() const { return true; }
|
| virtual intptr_t ResultCid() const;
|
|
|
| - private:
|
| - const Token::Kind op_kind_;
|
| - InstanceCallComp* instance_call_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(BinaryMintOpComp);
|
| -};
|
| + virtual void EmitBranchCode(FlowGraphCompiler* compiler,
|
| + BranchInstr* branch);
|
|
|
|
|
| -class BinaryDoubleOpComp : public TemplateComputation<0> {
|
| - public:
|
| - BinaryDoubleOpComp(Token::Kind op_kind, InstanceCallComp* instance_call)
|
| - : op_kind_(op_kind), instance_call_(instance_call) { }
|
| + virtual intptr_t DeoptimizationTarget() const {
|
| + return GetDeoptId();
|
| + }
|
|
|
| - Token::Kind op_kind() const { return op_kind_; }
|
| + virtual Representation RequiredInputRepresentation(intptr_t idx) const {
|
| + ASSERT((idx == 0) || (idx == 1));
|
| + return (operands_class_id() == kDoubleCid) ? kUnboxedDouble : kTagged;
|
| + }
|
|
|
| - InstanceCallComp* instance_call() const { return instance_call_; }
|
| + private:
|
| + const ICData* ic_data_;
|
| + const intptr_t token_pos_;
|
| + intptr_t operands_class_id_; // class id of both operands.
|
|
|
| - const ICData* ic_data() const { return instance_call()->ic_data(); }
|
| + DISALLOW_COPY_AND_ASSIGN(RelationalOpComp);
|
| +};
|
|
|
| - virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - DECLARE_CALL_COMPUTATION(BinaryDoubleOp)
|
| +class StaticCallComp : public TemplateComputation<0> {
|
| + public:
|
| + StaticCallComp(intptr_t token_pos,
|
| + const Function& function,
|
| + const Array& argument_names,
|
| + ZoneGrowableArray<PushArgumentInstr*>* arguments)
|
| + : token_pos_(token_pos),
|
| + function_(function),
|
| + argument_names_(argument_names),
|
| + arguments_(arguments),
|
| + recognized_(MethodRecognizer::kUnknown) {
|
| + ASSERT(function.IsZoneHandle());
|
| + ASSERT(argument_names.IsZoneHandle());
|
| + }
|
|
|
| - virtual intptr_t ArgumentCount() const { return 2; }
|
| + DECLARE_CALL_COMPUTATION(StaticCall)
|
| +
|
| + // Accessors forwarded to the AST node.
|
| + const Function& function() const { return function_; }
|
| + const Array& argument_names() const { return argument_names_; }
|
| + intptr_t token_pos() const { return token_pos_; }
|
| +
|
| + virtual intptr_t ArgumentCount() const { return arguments_->length(); }
|
| + PushArgumentInstr* ArgumentAt(intptr_t index) const {
|
| + return (*arguments_)[index];
|
| + }
|
| +
|
| + MethodRecognizer::Kind recognized() const { return recognized_; }
|
| + void set_recognized(MethodRecognizer::Kind kind) { recognized_ = kind; }
|
| +
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| virtual bool CanDeoptimize() const { return true; }
|
| - virtual intptr_t ResultCid() const;
|
| + virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| private:
|
| - const Token::Kind op_kind_;
|
| - InstanceCallComp* instance_call_;
|
| + const intptr_t token_pos_;
|
| + const Function& function_;
|
| + const Array& argument_names_;
|
| + ZoneGrowableArray<PushArgumentInstr*>* arguments_;
|
| + MethodRecognizer::Kind recognized_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(BinaryDoubleOpComp);
|
| + DISALLOW_COPY_AND_ASSIGN(StaticCallComp);
|
| };
|
|
|
|
|
| -// Handles both Smi operations: BIT_OR and NEGATE.
|
| -class UnarySmiOpComp : public TemplateComputation<1> {
|
| +class LoadLocalComp : public TemplateComputation<0> {
|
| public:
|
| - UnarySmiOpComp(Token::Kind op_kind,
|
| - InstanceCallComp* instance_call,
|
| - Value* value)
|
| - : op_kind_(op_kind), instance_call_(instance_call) {
|
| - ASSERT((op_kind == Token::kNEGATE) || (op_kind == Token::kBIT_NOT));
|
| - ASSERT(value != NULL);
|
| - inputs_[0] = value;
|
| - }
|
| + LoadLocalComp(const LocalVariable& local, intptr_t context_level)
|
| + : local_(local),
|
| + context_level_(context_level) { }
|
|
|
| - Value* value() const { return inputs_[0]; }
|
| - Token::Kind op_kind() const { return op_kind_; }
|
| + DECLARE_COMPUTATION(LoadLocal)
|
|
|
| - InstanceCallComp* instance_call() const { return instance_call_; }
|
| + const LocalVariable& local() const { return local_; }
|
| + intptr_t context_level() const { return context_level_; }
|
|
|
| virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - DECLARE_COMPUTATION(UnarySmiOp)
|
| -
|
| - virtual bool CanDeoptimize() const { return op_kind() == Token::kNEGATE; }
|
| - virtual intptr_t ResultCid() const { return kSmiCid; }
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| private:
|
| - const Token::Kind op_kind_;
|
| - InstanceCallComp* instance_call_;
|
| + const LocalVariable& local_;
|
| + const intptr_t context_level_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(UnarySmiOpComp);
|
| + DISALLOW_COPY_AND_ASSIGN(LoadLocalComp);
|
| };
|
|
|
|
|
| -// Handles non-Smi NEGATE operations
|
| -class NumberNegateComp : public TemplateComputation<1> {
|
| +class StoreLocalComp : public TemplateComputation<1> {
|
| public:
|
| - NumberNegateComp(InstanceCallComp* instance_call,
|
| - Value* value) : instance_call_(instance_call) {
|
| + StoreLocalComp(const LocalVariable& local,
|
| + Value* value,
|
| + intptr_t context_level)
|
| + : local_(local),
|
| + context_level_(context_level) {
|
| ASSERT(value != NULL);
|
| inputs_[0] = value;
|
| }
|
|
|
| - Value* value() const { return inputs_[0]; }
|
| + DECLARE_COMPUTATION(StoreLocal)
|
|
|
| - InstanceCallComp* instance_call() const { return instance_call_; }
|
| + const LocalVariable& local() const { return local_; }
|
| + Value* value() const { return inputs_[0]; }
|
| + intptr_t context_level() const { return context_level_; }
|
|
|
| - const ICData* ic_data() const { return instance_call()->ic_data(); }
|
| + virtual void RecordAssignedVars(BitVector* assigned_vars,
|
| + intptr_t fixed_parameter_count);
|
|
|
| - DECLARE_COMPUTATION(NumberNegate)
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - virtual bool CanDeoptimize() const { return true; }
|
| - virtual intptr_t ResultCid() const { return kDoubleCid; }
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| private:
|
| - InstanceCallComp* instance_call_;
|
| + const LocalVariable& local_;
|
| + const intptr_t context_level_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(NumberNegateComp);
|
| + DISALLOW_COPY_AND_ASSIGN(StoreLocalComp);
|
| };
|
|
|
|
|
| -class CheckStackOverflowComp : public TemplateComputation<0> {
|
| +class NativeCallComp : public TemplateComputation<0> {
|
| public:
|
| - explicit CheckStackOverflowComp(intptr_t token_pos)
|
| - : token_pos_(token_pos) {}
|
| -
|
| - intptr_t token_pos() const { return token_pos_; }
|
| + explicit NativeCallComp(NativeBodyNode* node)
|
| + : ast_node_(*node) {}
|
|
|
| - DECLARE_COMPUTATION(CheckStackOverflow)
|
| + DECLARE_COMPUTATION(NativeCall)
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| - virtual intptr_t ResultCid() const { return kIllegalCid; }
|
| + intptr_t token_pos() const { return ast_node_.token_pos(); }
|
|
|
| - private:
|
| - const intptr_t token_pos_;
|
| + const String& native_name() const {
|
| + return ast_node_.native_c_function_name();
|
| + }
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(CheckStackOverflowComp);
|
| -};
|
| + NativeFunction native_c_function() const {
|
| + return ast_node_.native_c_function();
|
| + }
|
|
|
| + intptr_t argument_count() const { return ast_node_.argument_count(); }
|
|
|
| -class DoubleToDoubleComp : public TemplateComputation<1> {
|
| - public:
|
| - DoubleToDoubleComp(Value* value, InstanceCallComp* instance_call)
|
| - : instance_call_(instance_call) {
|
| - ASSERT(value != NULL);
|
| - inputs_[0] = value;
|
| + bool has_optional_parameters() const {
|
| + return ast_node_.has_optional_parameters();
|
| }
|
|
|
| - Value* value() const { return inputs_[0]; }
|
| -
|
| - InstanceCallComp* instance_call() const { return instance_call_; }
|
| + bool is_native_instance_closure() const {
|
| + return ast_node_.is_native_instance_closure();
|
| + }
|
|
|
| - DECLARE_COMPUTATION(DoubleToDouble)
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - virtual bool CanDeoptimize() const { return true; }
|
| - virtual intptr_t ResultCid() const { return kDoubleCid; }
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| private:
|
| - InstanceCallComp* instance_call_;
|
| + const NativeBodyNode& ast_node_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(DoubleToDoubleComp);
|
| + DISALLOW_COPY_AND_ASSIGN(NativeCallComp);
|
| };
|
|
|
|
|
| -class SmiToDoubleComp : public TemplateComputation<0> {
|
| +class LoadInstanceFieldComp : public TemplateComputation<1> {
|
| public:
|
| - explicit SmiToDoubleComp(InstanceCallComp* instance_call)
|
| - : instance_call_(instance_call) { }
|
| + LoadInstanceFieldComp(const Field& field, Value* instance) : field_(field) {
|
| + ASSERT(instance != NULL);
|
| + inputs_[0] = instance;
|
| + }
|
|
|
| - InstanceCallComp* instance_call() const { return instance_call_; }
|
| + DECLARE_COMPUTATION(LoadInstanceField)
|
|
|
| - DECLARE_CALL_COMPUTATION(SmiToDouble)
|
| + const Field& field() const { return field_; }
|
| + Value* instance() const { return inputs_[0]; }
|
|
|
| - virtual intptr_t ArgumentCount() const { return 1; }
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - virtual bool CanDeoptimize() const { return true; }
|
| - virtual intptr_t ResultCid() const { return kDoubleCid; }
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| private:
|
| - InstanceCallComp* instance_call_;
|
| + const Field& field_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(SmiToDoubleComp);
|
| + DISALLOW_COPY_AND_ASSIGN(LoadInstanceFieldComp);
|
| };
|
|
|
|
|
| -class CheckClassComp : public TemplateComputation<1> {
|
| +class StoreInstanceFieldComp : public TemplateComputation<2> {
|
| public:
|
| - CheckClassComp(Value* value,
|
| - InstanceCallComp* instance_call,
|
| - const ICData& unary_checks)
|
| - : instance_call_(instance_call),
|
| - unary_checks_(unary_checks) {
|
| + StoreInstanceFieldComp(const Field& field,
|
| + Value* instance,
|
| + Value* value)
|
| + : field_(field) {
|
| + ASSERT(instance != NULL);
|
| ASSERT(value != NULL);
|
| - inputs_[0] = value;
|
| + inputs_[0] = instance;
|
| + inputs_[1] = value;
|
| }
|
|
|
| - DECLARE_COMPUTATION(CheckClass)
|
| + DECLARE_COMPUTATION(StoreInstanceField)
|
|
|
| - virtual bool CanDeoptimize() const { return true; }
|
| - virtual intptr_t ResultCid() const { return kIllegalCid; }
|
| + const Field& field() const { return field_; }
|
|
|
| - virtual bool AttributesEqual(Computation* other) const;
|
| + Value* instance() const { return inputs_[0]; }
|
| + Value* value() const { return inputs_[1]; }
|
|
|
| - virtual bool HasSideEffect() const { return false; }
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - Value* value() const { return inputs_[0]; }
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| - const ICData& unary_checks() const { return unary_checks_; }
|
| + private:
|
| + const Field& field_;
|
|
|
| - virtual intptr_t deopt_id() const { return instance_call_->deopt_id(); }
|
| + DISALLOW_COPY_AND_ASSIGN(StoreInstanceFieldComp);
|
| +};
|
|
|
| - virtual Definition* TryReplace(BindInstr* instr) const;
|
| +
|
| +class LoadStaticFieldComp : public TemplateComputation<0> {
|
| + public:
|
| + explicit LoadStaticFieldComp(const Field& field) : field_(field) {}
|
| +
|
| + DECLARE_COMPUTATION(LoadStaticField);
|
| +
|
| + const Field& field() const { return field_; }
|
|
|
| virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kDynamicCid; }
|
| +
|
| private:
|
| - InstanceCallComp* instance_call_;
|
| - const ICData& unary_checks_;
|
| + const Field& field_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(CheckClassComp);
|
| + DISALLOW_COPY_AND_ASSIGN(LoadStaticFieldComp);
|
| };
|
|
|
|
|
| -class CheckSmiComp : public TemplateComputation<1> {
|
| +class StoreStaticFieldComp : public TemplateComputation<1> {
|
| public:
|
| - CheckSmiComp(Value* value, intptr_t original_deopt_id)
|
| - : original_deopt_id_(original_deopt_id) {
|
| + StoreStaticFieldComp(const Field& field, Value* value)
|
| + : field_(field) {
|
| + ASSERT(field.IsZoneHandle());
|
| ASSERT(value != NULL);
|
| - ASSERT(original_deopt_id != Isolate::kNoDeoptId);
|
| inputs_[0] = value;
|
| }
|
|
|
| - DECLARE_COMPUTATION(CheckSmi)
|
| + DECLARE_COMPUTATION(StoreStaticField);
|
|
|
| - virtual bool CanDeoptimize() const { return true; }
|
| - virtual intptr_t ResultCid() const { return kIllegalCid; }
|
| + const Field& field() const { return field_; }
|
| + Value* value() const { return inputs_[0]; }
|
|
|
| - virtual bool AttributesEqual(Computation* other) const { return true; }
|
| -
|
| - virtual bool HasSideEffect() const { return false; }
|
| -
|
| - virtual Definition* TryReplace(BindInstr* instr) const;
|
| -
|
| - Value* value() const { return inputs_[0]; }
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - virtual intptr_t deopt_id() const { return original_deopt_id_; }
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| private:
|
| - const intptr_t original_deopt_id_;
|
| + const Field& field_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(CheckSmiComp);
|
| + DISALLOW_COPY_AND_ASSIGN(StoreStaticFieldComp);
|
| };
|
|
|
|
|
| -class CheckArrayBoundComp : public TemplateComputation<2> {
|
| +class LoadIndexedComp : public TemplateComputation<2> {
|
| public:
|
| - CheckArrayBoundComp(Value* array,
|
| - Value* index,
|
| - intptr_t array_type,
|
| - InstanceCallComp* instance_call)
|
| - : array_type_(array_type), instance_call_(instance_call) {
|
| + LoadIndexedComp(Value* array,
|
| + Value* index,
|
| + intptr_t receiver_type)
|
| + : receiver_type_(receiver_type) {
|
| ASSERT(array != NULL);
|
| ASSERT(index != NULL);
|
| inputs_[0] = array;
|
| inputs_[1] = index;
|
| }
|
|
|
| - DECLARE_COMPUTATION(CheckArrayBound)
|
| -
|
| - virtual bool CanDeoptimize() const { return true; }
|
| - virtual intptr_t ResultCid() const { return kIllegalCid; }
|
| -
|
| - virtual bool AttributesEqual(Computation* other) const;
|
| -
|
| - virtual bool HasSideEffect() const { return false; }
|
| + DECLARE_COMPUTATION(LoadIndexed)
|
|
|
| Value* array() const { return inputs_[0]; }
|
| Value* index() const { return inputs_[1]; }
|
|
|
| - intptr_t array_type() const { return array_type_; }
|
| + intptr_t receiver_type() const { return receiver_type_; }
|
|
|
| - virtual intptr_t deopt_id() const { return instance_call_->deopt_id(); }
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| private:
|
| - intptr_t array_type_;
|
| - InstanceCallComp* instance_call_;
|
| + intptr_t receiver_type_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(CheckArrayBoundComp);
|
| + DISALLOW_COPY_AND_ASSIGN(LoadIndexedComp);
|
| };
|
|
|
|
|
| -#undef DECLARE_COMPUTATION
|
| -
|
| -
|
| -// Implementation of type testers and cast functins.
|
| -#define DEFINE_COMPUTATION_PREDICATE(ShortName, ClassName) \
|
| -bool Computation::Is##ShortName() const { \
|
| - return computation_kind() == k##ShortName; \
|
| -} \
|
| -const ClassName* Computation::As##ShortName() const { \
|
| - if (!Is##ShortName()) return NULL; \
|
| - return static_cast<const ClassName*>(this); \
|
| -} \
|
| -ClassName* Computation::As##ShortName() { \
|
| - if (!Is##ShortName()) return NULL; \
|
| - return static_cast<ClassName*>(this); \
|
| -}
|
| -FOR_EACH_COMPUTATION(DEFINE_COMPUTATION_PREDICATE)
|
| -#undef DEFINE_COMPUTATION_PREDICATE
|
| -
|
| -// Instructions.
|
| +class StoreIndexedComp : public TemplateComputation<3> {
|
| + public:
|
| + StoreIndexedComp(Value* array,
|
| + Value* index,
|
| + Value* value,
|
| + intptr_t receiver_type)
|
| + : receiver_type_(receiver_type) {
|
| + ASSERT(array != NULL);
|
| + ASSERT(index != NULL);
|
| + ASSERT(value != NULL);
|
| + inputs_[0] = array;
|
| + inputs_[1] = index;
|
| + inputs_[2] = value;
|
| + }
|
|
|
| -// M is a single argument macro. It is applied to each concrete instruction
|
| -// type name. The concrete instruction classes are the name with Instr
|
| -// concatenated.
|
| -#define FOR_EACH_INSTRUCTION(M) \
|
| - M(GraphEntry) \
|
| - M(JoinEntry) \
|
| - M(TargetEntry) \
|
| - M(Phi) \
|
| - M(Bind) \
|
| - M(Parameter) \
|
| - M(ParallelMove) \
|
| - M(PushArgument) \
|
| - M(Return) \
|
| - M(Throw) \
|
| - M(ReThrow) \
|
| - M(Goto) \
|
| - M(Branch) \
|
| + DECLARE_COMPUTATION(StoreIndexed)
|
|
|
| + Value* array() const { return inputs_[0]; }
|
| + Value* index() const { return inputs_[1]; }
|
| + Value* value() const { return inputs_[2]; }
|
|
|
| -// Forward declarations for Instruction classes.
|
| -class BlockEntryInstr;
|
| -class FlowGraphBuilder;
|
| -class Environment;
|
| + intptr_t receiver_type() const { return receiver_type_; }
|
|
|
| -#define FORWARD_DECLARATION(type) class type##Instr;
|
| -FOR_EACH_INSTRUCTION(FORWARD_DECLARATION)
|
| -#undef FORWARD_DECLARATION
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| + private:
|
| + intptr_t receiver_type_;
|
|
|
| -// Functions required in all concrete instruction classes.
|
| -#define DECLARE_INSTRUCTION(type) \
|
| - virtual void Accept(FlowGraphVisitor* visitor); \
|
| - virtual bool Is##type() const { return true; } \
|
| - virtual type##Instr* As##type() { return this; } \
|
| - virtual const char* DebugName() const { return #type; } \
|
| - virtual void PrintTo(BufferFormatter* f) const; \
|
| - virtual void PrintToVisualizer(BufferFormatter* f) const;
|
| + DISALLOW_COPY_AND_ASSIGN(StoreIndexedComp);
|
| +};
|
|
|
|
|
| -class Instruction : public ZoneAllocated {
|
| +// Note overrideable, built-in: value? false : true.
|
| +class BooleanNegateComp : public TemplateComputation<1> {
|
| public:
|
| - Instruction()
|
| - : lifetime_position_(-1), previous_(NULL), next_(NULL), env_(NULL) { }
|
| -
|
| - virtual bool IsBlockEntry() const { return false; }
|
| - BlockEntryInstr* AsBlockEntry() {
|
| - return IsBlockEntry() ? reinterpret_cast<BlockEntryInstr*>(this) : NULL;
|
| + explicit BooleanNegateComp(Value* value) {
|
| + ASSERT(value != NULL);
|
| + inputs_[0] = value;
|
| }
|
| - virtual bool IsDefinition() const { return false; }
|
| - virtual Definition* AsDefinition() { return NULL; }
|
| - virtual bool IsControl() const { return false; }
|
|
|
| - virtual intptr_t InputCount() const = 0;
|
| - virtual Value* InputAt(intptr_t i) const = 0;
|
| - virtual void SetInputAt(intptr_t i, Value* value) = 0;
|
| + DECLARE_COMPUTATION(BooleanNegate)
|
|
|
| - // Call instructions override this function and return the
|
| - // number of pushed arguments.
|
| - virtual intptr_t ArgumentCount() const = 0;
|
| + Value* value() const { return inputs_[0]; }
|
|
|
| - // Returns true, if this instruction can deoptimize.
|
| - virtual bool CanDeoptimize() const = 0;
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kBoolCid; }
|
|
|
| - // Visiting support.
|
| - virtual void Accept(FlowGraphVisitor* visitor) = 0;
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(BooleanNegateComp);
|
| +};
|
|
|
| - Instruction* previous() const { return previous_; }
|
| - void set_previous(Instruction* instr) {
|
| - ASSERT(!IsBlockEntry());
|
| - previous_ = instr;
|
| - }
|
|
|
| - Instruction* next() const { return next_; }
|
| - void set_next(Instruction* instr) {
|
| - ASSERT(!IsGraphEntry());
|
| - ASSERT(!IsReturn());
|
| - ASSERT(!IsControl());
|
| - ASSERT(!IsPhi());
|
| - ASSERT(instr == NULL || !instr->IsBlockEntry());
|
| - // TODO(fschneider): Also add Throw and ReThrow to the list of instructions
|
| - // that do not have a successor. Currently, the graph builder will continue
|
| - // to append instruction in case of a Throw inside an expression. This
|
| - // condition should be handled in the graph builder
|
| - next_ = instr;
|
| +class InstanceOfComp : public TemplateComputation<3> {
|
| + public:
|
| + InstanceOfComp(intptr_t token_pos,
|
| + Value* value,
|
| + Value* instantiator,
|
| + Value* instantiator_type_arguments,
|
| + const AbstractType& type,
|
| + bool negate_result)
|
| + : token_pos_(token_pos),
|
| + type_(type),
|
| + negate_result_(negate_result) {
|
| + ASSERT(value != NULL);
|
| + ASSERT(instantiator != NULL);
|
| + ASSERT(instantiator_type_arguments != NULL);
|
| + ASSERT(!type.IsNull());
|
| + inputs_[0] = value;
|
| + inputs_[1] = instantiator;
|
| + inputs_[2] = instantiator_type_arguments;
|
| }
|
|
|
| - // Removed this instruction from the graph.
|
| - Instruction* RemoveFromGraph(bool return_previous = true);
|
| + DECLARE_COMPUTATION(InstanceOf)
|
|
|
| - // Normal instructions can have 0 (inside a block) or 1 (last instruction in
|
| - // a block) successors. Branch instruction with >1 successors override this
|
| - // function.
|
| - virtual intptr_t SuccessorCount() const;
|
| - virtual BlockEntryInstr* SuccessorAt(intptr_t index) const;
|
| + Value* value() const { return inputs_[0]; }
|
| + Value* instantiator() const { return inputs_[1]; }
|
| + Value* instantiator_type_arguments() const { return inputs_[2]; }
|
|
|
| - void Goto(JoinEntryInstr* entry);
|
| + bool negate_result() const { return negate_result_; }
|
| + const AbstractType& type() const { return type_; }
|
| + intptr_t token_pos() const { return token_pos_; }
|
|
|
| - // Discover basic-block structure by performing a recursive depth first
|
| - // traversal of the instruction graph reachable from this instruction. As
|
| - // a side effect, the block entry instructions in the graph are assigned
|
| - // numbers in both preorder and postorder. The array 'preorder' maps
|
| - // preorder block numbers to the block entry instruction with that number
|
| - // and analogously for the array 'postorder'. The depth first spanning
|
| - // tree is recorded in the array 'parent', which maps preorder block
|
| - // numbers to the preorder number of the block's spanning-tree parent.
|
| - // The array 'assigned_vars' maps preorder block numbers to the set of
|
| - // assigned frame-allocated local variables in the block. As a side
|
| - // effect of this function, the set of basic block predecessors (e.g.,
|
| - // block entry instructions of predecessor blocks) and also the last
|
| - // instruction in the block is recorded in each entry instruction.
|
| - virtual void DiscoverBlocks(
|
| - BlockEntryInstr* current_block,
|
| - GrowableArray<BlockEntryInstr*>* preorder,
|
| - GrowableArray<BlockEntryInstr*>* postorder,
|
| - GrowableArray<intptr_t>* parent,
|
| - GrowableArray<BitVector*>* assigned_vars,
|
| - intptr_t variable_count,
|
| - intptr_t fixed_parameter_count) {
|
| - // Never called for instructions except block entries and branches.
|
| - UNREACHABLE();
|
| - }
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - // Mutate assigned_vars to add the local variable index for all
|
| - // frame-allocated locals assigned to by the instruction.
|
| - virtual void RecordAssignedVars(BitVector* assigned_vars,
|
| - intptr_t fixed_parameter_count);
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kBoolCid; }
|
|
|
| - // Printing support.
|
| - virtual void PrintTo(BufferFormatter* f) const = 0;
|
| - virtual void PrintToVisualizer(BufferFormatter* f) const = 0;
|
| + private:
|
| + const intptr_t token_pos_;
|
| + Value* value_;
|
| + Value* instantiator_;
|
| + Value* type_arguments_;
|
| + const AbstractType& type_;
|
| + const bool negate_result_;
|
|
|
| -#define INSTRUCTION_TYPE_CHECK(type) \
|
| - virtual bool Is##type() const { return false; } \
|
| - virtual type##Instr* As##type() { return NULL; }
|
| -FOR_EACH_INSTRUCTION(INSTRUCTION_TYPE_CHECK)
|
| -#undef INSTRUCTION_TYPE_CHECK
|
| + DISALLOW_COPY_AND_ASSIGN(InstanceOfComp);
|
| +};
|
|
|
| - // Returns structure describing location constraints required
|
| - // to emit native code for this instruction.
|
| - virtual LocationSummary* locs() {
|
| - // TODO(vegorov): This should be pure virtual method.
|
| - // However we are temporary using NULL for instructions that
|
| - // were not converted to the location based code generation yet.
|
| - return NULL;
|
| - }
|
|
|
| - virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
|
| - UNIMPLEMENTED();
|
| +class AllocateObjectComp : public TemplateComputation<0> {
|
| + public:
|
| + AllocateObjectComp(ConstructorCallNode* node,
|
| + ZoneGrowableArray<PushArgumentInstr*>* arguments)
|
| + : ast_node_(*node), arguments_(arguments) {
|
| + // Either no arguments or one type-argument and one instantiator.
|
| + ASSERT(arguments->is_empty() || (arguments->length() == 2));
|
| }
|
|
|
| - Environment* env() const { return env_; }
|
| - void set_env(Environment* env) { env_ = env; }
|
| -
|
| - intptr_t lifetime_position() const { return lifetime_position_; }
|
| - void set_lifetime_position(intptr_t pos) {
|
| - lifetime_position_ = pos;
|
| - }
|
| + DECLARE_CALL_COMPUTATION(AllocateObject)
|
|
|
| - // Returns representation expected for the input operand at the given index.
|
| - virtual Representation RequiredInputRepresentation(intptr_t idx) const {
|
| - return kTagged;
|
| + virtual intptr_t ArgumentCount() const { return arguments_->length(); }
|
| + PushArgumentInstr* ArgumentAt(intptr_t index) const {
|
| + return (*arguments_)[index];
|
| }
|
|
|
| - // Representation of the value produced by this computation.
|
| - virtual Representation representation() const {
|
| - return kTagged;
|
| - }
|
| + const Function& constructor() const { return ast_node_.constructor(); }
|
| + intptr_t token_pos() const { return ast_node_.token_pos(); }
|
|
|
| - bool WasEliminated() const {
|
| - return next() == NULL;
|
| - }
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - // Returns deoptimization id that corresponds to the deoptimization target
|
| - // that input operands conversions inserted for this instruction can jump
|
| - // to.
|
| - virtual intptr_t DeoptimizationTarget() const {
|
| - UNREACHABLE();
|
| - return Isolate::kNoDeoptId;
|
| - }
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| private:
|
| - friend class BindInstr; // Needed for BindInstr::InsertBefore.
|
| + const ConstructorCallNode& ast_node_;
|
| + ZoneGrowableArray<PushArgumentInstr*>* const arguments_;
|
|
|
| - intptr_t lifetime_position_; // Position used by register allocator.
|
| - Instruction* previous_;
|
| - Instruction* next_;
|
| - Environment* env_;
|
| - DISALLOW_COPY_AND_ASSIGN(Instruction);
|
| + DISALLOW_COPY_AND_ASSIGN(AllocateObjectComp);
|
| };
|
|
|
|
|
| -template<intptr_t N>
|
| -class TemplateInstruction: public Instruction {
|
| +class AllocateObjectWithBoundsCheckComp : public TemplateComputation<2> {
|
| public:
|
| - TemplateInstruction<N>() : locs_(NULL) { }
|
| -
|
| - virtual intptr_t InputCount() const { return N; }
|
| - virtual Value* InputAt(intptr_t i) const { return inputs_[i]; }
|
| - virtual void SetInputAt(intptr_t i, Value* value) {
|
| - ASSERT(value != NULL);
|
| - inputs_[i] = value;
|
| + AllocateObjectWithBoundsCheckComp(ConstructorCallNode* node,
|
| + Value* type_arguments,
|
| + Value* instantiator)
|
| + : ast_node_(*node) {
|
| + ASSERT(type_arguments != NULL);
|
| + ASSERT(instantiator != NULL);
|
| + inputs_[0] = type_arguments;
|
| + inputs_[1] = instantiator;
|
| }
|
|
|
| - virtual LocationSummary* locs() {
|
| - if (locs_ == NULL) {
|
| - locs_ = MakeLocationSummary();
|
| - }
|
| - return locs_;
|
| - }
|
| + DECLARE_COMPUTATION(AllocateObjectWithBoundsCheck)
|
|
|
| - virtual LocationSummary* MakeLocationSummary() const = 0;
|
| + const Function& constructor() const { return ast_node_.constructor(); }
|
| + intptr_t token_pos() const { return ast_node_.token_pos(); }
|
|
|
| - protected:
|
| - EmbeddedArray<Value*, N> inputs_;
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| +
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| private:
|
| - LocationSummary* locs_;
|
| + const ConstructorCallNode& ast_node_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(AllocateObjectWithBoundsCheckComp);
|
| };
|
|
|
|
|
| -class MoveOperands : public ZoneAllocated {
|
| +class CreateArrayComp : public TemplateComputation<1> {
|
| public:
|
| - MoveOperands(Location dest, Location src) : dest_(dest), src_(src) { }
|
| + CreateArrayComp(intptr_t token_pos,
|
| + ZoneGrowableArray<PushArgumentInstr*>* arguments,
|
| + const AbstractType& type,
|
| + Value* element_type)
|
| + : token_pos_(token_pos),
|
| + arguments_(arguments),
|
| + type_(type) {
|
| +#if defined(DEBUG)
|
| + for (int i = 0; i < ArgumentCount(); ++i) {
|
| + ASSERT(ArgumentAt(i) != NULL);
|
| + }
|
| + ASSERT(element_type != NULL);
|
| + ASSERT(type_.IsZoneHandle());
|
| + ASSERT(!type_.IsNull());
|
| + ASSERT(type_.IsFinalized());
|
| +#endif
|
| + inputs_[0] = element_type;
|
| + }
|
|
|
| - Location src() const { return src_; }
|
| - Location dest() const { return dest_; }
|
| + DECLARE_CALL_COMPUTATION(CreateArray)
|
|
|
| - Location* src_slot() { return &src_; }
|
| - Location* dest_slot() { return &dest_; }
|
| + virtual intptr_t ArgumentCount() const { return arguments_->length(); }
|
|
|
| - void set_src(const Location& value) { src_ = value; }
|
| - void set_dest(const Location& value) { dest_ = value; }
|
| + intptr_t token_pos() const { return token_pos_; }
|
| + PushArgumentInstr* ArgumentAt(intptr_t i) const { return (*arguments_)[i]; }
|
| + const AbstractType& type() const { return type_; }
|
| + Value* element_type() const { return inputs_[0]; }
|
|
|
| - // The parallel move resolver marks moves as "in-progress" by clearing the
|
| - // destination (but not the source).
|
| - Location MarkPending() {
|
| - ASSERT(!IsPending());
|
| - Location dest = dest_;
|
| - dest_ = Location::NoLocation();
|
| - return dest;
|
| - }
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - void ClearPending(Location dest) {
|
| - ASSERT(IsPending());
|
| - dest_ = dest;
|
| - }
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| - bool IsPending() const {
|
| - ASSERT(!src_.IsInvalid() || dest_.IsInvalid());
|
| - return dest_.IsInvalid() && !src_.IsInvalid();
|
| - }
|
| + private:
|
| + const intptr_t token_pos_;
|
| + ZoneGrowableArray<PushArgumentInstr*>* const arguments_;
|
| + const AbstractType& type_;
|
|
|
| - // True if this move a move from the given location.
|
| - bool Blocks(Location loc) const {
|
| - return !IsEliminated() && src_.Equals(loc);
|
| - }
|
| + DISALLOW_COPY_AND_ASSIGN(CreateArrayComp);
|
| +};
|
|
|
| - // A move is redundant if it's been eliminated, if its source and
|
| - // destination are the same, or if its destination is unneeded.
|
| - bool IsRedundant() const {
|
| - return IsEliminated() || dest_.IsInvalid() || src_.Equals(dest_);
|
| - }
|
|
|
| - // We clear both operands to indicate move that's been eliminated.
|
| - void Eliminate() { src_ = dest_ = Location::NoLocation(); }
|
| - bool IsEliminated() const {
|
| - ASSERT(!src_.IsInvalid() || dest_.IsInvalid());
|
| - return src_.IsInvalid();
|
| +class CreateClosureComp : public TemplateComputation<0> {
|
| + public:
|
| + CreateClosureComp(ClosureNode* node,
|
| + ZoneGrowableArray<PushArgumentInstr*>* arguments)
|
| + : ast_node_(*node),
|
| + arguments_(arguments) { }
|
| +
|
| + DECLARE_CALL_COMPUTATION(CreateClosure)
|
| +
|
| + intptr_t token_pos() const { return ast_node_.token_pos(); }
|
| + const Function& function() const { return ast_node_.function(); }
|
| +
|
| + virtual intptr_t ArgumentCount() const { return arguments_->length(); }
|
| + PushArgumentInstr* ArgumentAt(intptr_t index) const {
|
| + return (*arguments_)[index];
|
| }
|
|
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| +
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kDynamicCid; }
|
| +
|
| private:
|
| - Location dest_;
|
| - Location src_;
|
| + const ClosureNode& ast_node_;
|
| + ZoneGrowableArray<PushArgumentInstr*>* arguments_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(MoveOperands);
|
| + DISALLOW_COPY_AND_ASSIGN(CreateClosureComp);
|
| };
|
|
|
|
|
| -class ParallelMoveInstr : public TemplateInstruction<0> {
|
| +class LoadVMFieldComp : public TemplateComputation<1> {
|
| public:
|
| - ParallelMoveInstr() : moves_(4) { }
|
| + LoadVMFieldComp(Value* value,
|
| + intptr_t offset_in_bytes,
|
| + const AbstractType& type)
|
| + : offset_in_bytes_(offset_in_bytes),
|
| + type_(type),
|
| + result_cid_(kDynamicCid) {
|
| + ASSERT(value != NULL);
|
| + ASSERT(type.IsZoneHandle()); // May be null if field is not an instance.
|
| + inputs_[0] = value;
|
| + }
|
|
|
| - DECLARE_INSTRUCTION(ParallelMove)
|
| + DECLARE_COMPUTATION(LoadVMField)
|
|
|
| - virtual intptr_t ArgumentCount() const { return 0; }
|
| + Value* value() const { return inputs_[0]; }
|
| + intptr_t offset_in_bytes() const { return offset_in_bytes_; }
|
| + const AbstractType& type() const { return type_; }
|
| + void set_result_cid(intptr_t value) { result_cid_ = value; }
|
| +
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return result_cid_; }
|
|
|
| - MoveOperands* AddMove(Location dest, Location src) {
|
| - MoveOperands* move = new MoveOperands(dest, src);
|
| - moves_.Add(move);
|
| - return move;
|
| - }
|
| + private:
|
| + const intptr_t offset_in_bytes_;
|
| + const AbstractType& type_;
|
| + intptr_t result_cid_;
|
|
|
| - MoveOperands* MoveOperandsAt(intptr_t index) const { return moves_[index]; }
|
| + DISALLOW_COPY_AND_ASSIGN(LoadVMFieldComp);
|
| +};
|
|
|
| - void SetSrcSlotAt(intptr_t index, const Location& loc);
|
| - void SetDestSlotAt(intptr_t index, const Location& loc);
|
|
|
| - intptr_t NumMoves() const { return moves_.length(); }
|
| +class StoreVMFieldComp : public TemplateComputation<2> {
|
| + public:
|
| + StoreVMFieldComp(Value* dest,
|
| + intptr_t offset_in_bytes,
|
| + Value* value,
|
| + const AbstractType& type)
|
| + : offset_in_bytes_(offset_in_bytes), type_(type) {
|
| + ASSERT(value != NULL);
|
| + ASSERT(dest != NULL);
|
| + ASSERT(type.IsZoneHandle()); // May be null if field is not an instance.
|
| + inputs_[0] = value;
|
| + inputs_[1] = dest;
|
| + }
|
|
|
| - LocationSummary* MakeLocationSummary() const { return NULL; }
|
| + DECLARE_COMPUTATION(StoreVMField)
|
|
|
| - void EmitNativeCode(FlowGraphCompiler* compiler) { UNREACHABLE(); }
|
| + Value* value() const { return inputs_[0]; }
|
| + Value* dest() const { return inputs_[1]; }
|
| + intptr_t offset_in_bytes() const { return offset_in_bytes_; }
|
| + const AbstractType& type() const { return type_; }
|
| +
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| +
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| private:
|
| - GrowableArray<MoveOperands*> moves_; // Elements cannot be null.
|
| + const intptr_t offset_in_bytes_;
|
| + const AbstractType& type_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(ParallelMoveInstr);
|
| + DISALLOW_COPY_AND_ASSIGN(StoreVMFieldComp);
|
| };
|
|
|
|
|
| -// Basic block entries are administrative nodes. There is a distinguished
|
| -// graph entry with no predecessor. Joins are the only nodes with multiple
|
| -// predecessors. Targets are all other basic block entries. The types
|
| -// enforce edge-split form---joins are forbidden as the successors of
|
| -// branches.
|
| -class BlockEntryInstr : public Instruction {
|
| +class InstantiateTypeArgumentsComp : public TemplateComputation<1> {
|
| public:
|
| - virtual bool IsBlockEntry() const { return true; }
|
| + InstantiateTypeArgumentsComp(intptr_t token_pos,
|
| + const AbstractTypeArguments& type_arguments,
|
| + Value* instantiator)
|
| + : token_pos_(token_pos),
|
| + type_arguments_(type_arguments) {
|
| + ASSERT(type_arguments.IsZoneHandle());
|
| + ASSERT(instantiator != NULL);
|
| + inputs_[0] = instantiator;
|
| + }
|
|
|
| - virtual intptr_t PredecessorCount() const = 0;
|
| - virtual BlockEntryInstr* PredecessorAt(intptr_t index) const = 0;
|
| - virtual void AddPredecessor(BlockEntryInstr* predecessor) = 0;
|
| - virtual void PrepareEntry(FlowGraphCompiler* compiler) = 0;
|
| + DECLARE_COMPUTATION(InstantiateTypeArguments)
|
|
|
| - intptr_t preorder_number() const { return preorder_number_; }
|
| - void set_preorder_number(intptr_t number) { preorder_number_ = number; }
|
| + Value* instantiator() const { return inputs_[0]; }
|
| + const AbstractTypeArguments& type_arguments() const {
|
| + return type_arguments_;
|
| + }
|
| + intptr_t token_pos() const { return token_pos_; }
|
|
|
| - intptr_t postorder_number() const { return postorder_number_; }
|
| - void set_postorder_number(intptr_t number) { postorder_number_ = number; }
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - intptr_t block_id() const { return block_id_; }
|
| - void set_block_id(intptr_t value) { block_id_ = value; }
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| - void set_start_pos(intptr_t pos) { start_pos_ = pos; }
|
| - intptr_t start_pos() const { return start_pos_; }
|
| - void set_end_pos(intptr_t pos) { end_pos_ = pos; }
|
| - intptr_t end_pos() const { return end_pos_; }
|
| + private:
|
| + const intptr_t token_pos_;
|
| + const AbstractTypeArguments& type_arguments_;
|
|
|
| - BlockEntryInstr* dominator() const { return dominator_; }
|
| - void set_dominator(BlockEntryInstr* instr) { dominator_ = instr; }
|
| + DISALLOW_COPY_AND_ASSIGN(InstantiateTypeArgumentsComp);
|
| +};
|
|
|
| - const GrowableArray<BlockEntryInstr*>& dominated_blocks() {
|
| - return dominated_blocks_;
|
| - }
|
|
|
| - void AddDominatedBlock(BlockEntryInstr* block) {
|
| - dominated_blocks_.Add(block);
|
| +class ExtractConstructorTypeArgumentsComp : public TemplateComputation<1> {
|
| + public:
|
| + ExtractConstructorTypeArgumentsComp(
|
| + intptr_t token_pos,
|
| + const AbstractTypeArguments& type_arguments,
|
| + Value* instantiator)
|
| + : token_pos_(token_pos),
|
| + type_arguments_(type_arguments) {
|
| + ASSERT(instantiator != NULL);
|
| + inputs_[0] = instantiator;
|
| }
|
|
|
| - Instruction* last_instruction() const { return last_instruction_; }
|
| - void set_last_instruction(Instruction* instr) { last_instruction_ = instr; }
|
| + DECLARE_COMPUTATION(ExtractConstructorTypeArguments)
|
|
|
| - ParallelMoveInstr* parallel_move() const {
|
| - return parallel_move_;
|
| + Value* instantiator() const { return inputs_[0]; }
|
| + const AbstractTypeArguments& type_arguments() const {
|
| + return type_arguments_;
|
| }
|
| + intptr_t token_pos() const { return token_pos_; }
|
|
|
| - bool HasParallelMove() const {
|
| - return parallel_move_ != NULL;
|
| - }
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - ParallelMoveInstr* GetParallelMove() {
|
| - if (parallel_move_ == NULL) {
|
| - parallel_move_ = new ParallelMoveInstr();
|
| - }
|
| - return parallel_move_;
|
| - }
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| - virtual void DiscoverBlocks(
|
| - BlockEntryInstr* current_block,
|
| - GrowableArray<BlockEntryInstr*>* preorder,
|
| - GrowableArray<BlockEntryInstr*>* postorder,
|
| - GrowableArray<intptr_t>* parent,
|
| - GrowableArray<BitVector*>* assigned_vars,
|
| - intptr_t variable_count,
|
| - intptr_t fixed_parameter_count);
|
| + private:
|
| + const intptr_t token_pos_;
|
| + const AbstractTypeArguments& type_arguments_;
|
|
|
| - virtual intptr_t InputCount() const { return 0; }
|
| - virtual Value* InputAt(intptr_t i) const {
|
| - UNREACHABLE();
|
| - return NULL;
|
| - }
|
| - virtual void SetInputAt(intptr_t i, Value* value) { UNREACHABLE(); }
|
| + DISALLOW_COPY_AND_ASSIGN(ExtractConstructorTypeArgumentsComp);
|
| +};
|
|
|
| - virtual intptr_t ArgumentCount() const { return 0; }
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| +class ExtractConstructorInstantiatorComp : public TemplateComputation<1> {
|
| + public:
|
| + ExtractConstructorInstantiatorComp(ConstructorCallNode* ast_node,
|
| + Value* instantiator)
|
| + : ast_node_(*ast_node) {
|
| + ASSERT(instantiator != NULL);
|
| + inputs_[0] = instantiator;
|
| + }
|
|
|
| - intptr_t try_index() const { return try_index_; }
|
| + DECLARE_COMPUTATION(ExtractConstructorInstantiator)
|
|
|
| - protected:
|
| - explicit BlockEntryInstr(intptr_t try_index)
|
| - : try_index_(try_index),
|
| - preorder_number_(-1),
|
| - postorder_number_(-1),
|
| - block_id_(-1),
|
| - dominator_(NULL),
|
| - dominated_blocks_(1),
|
| - last_instruction_(NULL),
|
| - parallel_move_(NULL) { }
|
| + Value* instantiator() const { return inputs_[0]; }
|
| + const AbstractTypeArguments& type_arguments() const {
|
| + return ast_node_.type_arguments();
|
| + }
|
| + const Function& constructor() const { return ast_node_.constructor(); }
|
| + intptr_t token_pos() const { return ast_node_.token_pos(); }
|
|
|
| - private:
|
| - const intptr_t try_index_;
|
| - intptr_t preorder_number_;
|
| - intptr_t postorder_number_;
|
| - // Starting and ending lifetime positions for this block. Used by
|
| - // the linear scan register allocator.
|
| - intptr_t block_id_;
|
| - intptr_t start_pos_;
|
| - intptr_t end_pos_;
|
| - BlockEntryInstr* dominator_; // Immediate dominator, NULL for graph entry.
|
| - // TODO(fschneider): Optimize the case of one child to save space.
|
| - GrowableArray<BlockEntryInstr*> dominated_blocks_;
|
| - Instruction* last_instruction_;
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| - // Parallel move that will be used by linear scan register allocator to
|
| - // connect live ranges at the start of the block.
|
| - ParallelMoveInstr* parallel_move_;
|
| + private:
|
| + const ConstructorCallNode& ast_node_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(BlockEntryInstr);
|
| + DISALLOW_COPY_AND_ASSIGN(ExtractConstructorInstantiatorComp);
|
| };
|
|
|
|
|
| -class ForwardInstructionIterator : public ValueObject {
|
| +class AllocateContextComp : public TemplateComputation<0> {
|
| public:
|
| - explicit ForwardInstructionIterator(BlockEntryInstr* block_entry)
|
| - : block_entry_(block_entry), current_(block_entry) {
|
| - ASSERT(block_entry_->last_instruction()->next() == NULL);
|
| - Advance();
|
| - }
|
| + AllocateContextComp(intptr_t token_pos,
|
| + intptr_t num_context_variables)
|
| + : token_pos_(token_pos),
|
| + num_context_variables_(num_context_variables) {}
|
|
|
| - void Advance() {
|
| - ASSERT(!Done());
|
| - current_ = current_->next();
|
| - }
|
| + DECLARE_COMPUTATION(AllocateContext);
|
|
|
| - bool Done() const { return current_ == NULL; }
|
| + intptr_t token_pos() const { return token_pos_; }
|
| + intptr_t num_context_variables() const { return num_context_variables_; }
|
|
|
| - // Removes 'current_' from graph and sets 'current_' to previous instruction.
|
| - void RemoveCurrentFromGraph();
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - Instruction* Current() const { return current_; }
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kDynamicCid; }
|
|
|
| private:
|
| - BlockEntryInstr* block_entry_;
|
| - Instruction* current_;
|
| + const intptr_t token_pos_;
|
| + const intptr_t num_context_variables_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(AllocateContextComp);
|
| };
|
|
|
|
|
| -class BackwardInstructionIterator : public ValueObject {
|
| +class ChainContextComp : public TemplateComputation<1> {
|
| public:
|
| - explicit BackwardInstructionIterator(BlockEntryInstr* block_entry)
|
| - : block_entry_(block_entry), current_(block_entry->last_instruction()) {
|
| - ASSERT(block_entry_->previous() == NULL);
|
| + explicit ChainContextComp(Value* context_value) {
|
| + ASSERT(context_value != NULL);
|
| + inputs_[0] = context_value;
|
| }
|
|
|
| - void Advance() {
|
| - ASSERT(!Done());
|
| - current_ = current_->previous();
|
| - }
|
| + DECLARE_COMPUTATION(ChainContext)
|
|
|
| - bool Done() const { return current_ == block_entry_; }
|
| + Value* context_value() const { return inputs_[0]; }
|
|
|
| - Instruction* Current() const { return current_; }
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kIllegalCid; }
|
|
|
| private:
|
| - BlockEntryInstr* block_entry_;
|
| - Instruction* current_;
|
| + DISALLOW_COPY_AND_ASSIGN(ChainContextComp);
|
| };
|
|
|
|
|
| -class GraphEntryInstr : public BlockEntryInstr {
|
| +class CloneContextComp : public TemplateComputation<1> {
|
| public:
|
| - explicit GraphEntryInstr(TargetEntryInstr* normal_entry);
|
| -
|
| - DECLARE_INSTRUCTION(GraphEntry)
|
| -
|
| - virtual intptr_t PredecessorCount() const { return 0; }
|
| - virtual BlockEntryInstr* PredecessorAt(intptr_t index) const {
|
| - UNREACHABLE();
|
| - return NULL;
|
| + CloneContextComp(intptr_t token_pos,
|
| + Value* context_value)
|
| + : token_pos_(token_pos) {
|
| + ASSERT(context_value != NULL);
|
| + inputs_[0] = context_value;
|
| }
|
| - virtual void AddPredecessor(BlockEntryInstr* predecessor) { UNREACHABLE(); }
|
| -
|
| - virtual intptr_t SuccessorCount() const;
|
| - virtual BlockEntryInstr* SuccessorAt(intptr_t index) const;
|
| -
|
| - virtual void DiscoverBlocks(
|
| - BlockEntryInstr* current_block,
|
| - GrowableArray<BlockEntryInstr*>* preorder,
|
| - GrowableArray<BlockEntryInstr*>* postorder,
|
| - GrowableArray<intptr_t>* parent,
|
| - GrowableArray<BitVector*>* assigned_vars,
|
| - intptr_t variable_count,
|
| - intptr_t fixed_parameter_count);
|
| -
|
| - void AddCatchEntry(TargetEntryInstr* entry) { catch_entries_.Add(entry); }
|
| -
|
| - virtual void PrepareEntry(FlowGraphCompiler* compiler);
|
| -
|
| - Environment* start_env() const { return start_env_; }
|
| - void set_start_env(Environment* env) { start_env_ = env; }
|
|
|
| - Definition* constant_null() const { return constant_null_; }
|
| + intptr_t token_pos() const { return token_pos_; }
|
| + Value* context_value() const { return inputs_[0]; }
|
|
|
| - intptr_t spill_slot_count() const { return spill_slot_count_; }
|
| - void set_spill_slot_count(intptr_t count) {
|
| - ASSERT(count >= 0);
|
| - spill_slot_count_ = count;
|
| - }
|
| + DECLARE_COMPUTATION(CloneContext)
|
|
|
| - TargetEntryInstr* normal_entry() const { return normal_entry_; }
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kIllegalCid; }
|
|
|
| private:
|
| - TargetEntryInstr* normal_entry_;
|
| - GrowableArray<TargetEntryInstr*> catch_entries_;
|
| - Environment* start_env_;
|
| - Definition* constant_null_;
|
| - intptr_t spill_slot_count_;
|
| + const intptr_t token_pos_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(GraphEntryInstr);
|
| + DISALLOW_COPY_AND_ASSIGN(CloneContextComp);
|
| };
|
|
|
|
|
| -class JoinEntryInstr : public BlockEntryInstr {
|
| +class CatchEntryComp : public TemplateComputation<0> {
|
| public:
|
| - explicit JoinEntryInstr(intptr_t try_index)
|
| - : BlockEntryInstr(try_index),
|
| - predecessors_(2), // Two is the assumed to be the common case.
|
| - phis_(NULL),
|
| - phi_count_(0) { }
|
| -
|
| - DECLARE_INSTRUCTION(JoinEntry)
|
| -
|
| - virtual intptr_t PredecessorCount() const { return predecessors_.length(); }
|
| - virtual BlockEntryInstr* PredecessorAt(intptr_t index) const {
|
| - return predecessors_[index];
|
| - }
|
| - virtual void AddPredecessor(BlockEntryInstr* predecessor) {
|
| - predecessors_.Add(predecessor);
|
| - }
|
| -
|
| - // Returns -1 if pred is not in the list.
|
| - intptr_t IndexOfPredecessor(BlockEntryInstr* pred) const;
|
| + CatchEntryComp(const LocalVariable& exception_var,
|
| + const LocalVariable& stacktrace_var)
|
| + : exception_var_(exception_var), stacktrace_var_(stacktrace_var) {}
|
|
|
| - ZoneGrowableArray<PhiInstr*>* phis() const { return phis_; }
|
| + const LocalVariable& exception_var() const { return exception_var_; }
|
| + const LocalVariable& stacktrace_var() const { return stacktrace_var_; }
|
|
|
| - virtual void PrepareEntry(FlowGraphCompiler* compiler);
|
| + DECLARE_COMPUTATION(CatchEntry)
|
|
|
| - void InsertPhi(intptr_t var_index, intptr_t var_count);
|
| - void RemoveDeadPhis();
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - intptr_t phi_count() const { return phi_count_; }
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kIllegalCid; }
|
|
|
| private:
|
| - GrowableArray<BlockEntryInstr*> predecessors_;
|
| - ZoneGrowableArray<PhiInstr*>* phis_;
|
| - intptr_t phi_count_;
|
| + const LocalVariable& exception_var_;
|
| + const LocalVariable& stacktrace_var_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(JoinEntryInstr);
|
| + DISALLOW_COPY_AND_ASSIGN(CatchEntryComp);
|
| };
|
|
|
|
|
| -class TargetEntryInstr : public BlockEntryInstr {
|
| +class CheckEitherNonSmiComp : public TemplateComputation<2> {
|
| public:
|
| - explicit TargetEntryInstr(intptr_t try_index)
|
| - : BlockEntryInstr(try_index),
|
| - predecessor_(NULL),
|
| - catch_try_index_(CatchClauseNode::kInvalidTryIndex) { }
|
| + CheckEitherNonSmiComp(Value* left,
|
| + Value* right,
|
| + InstanceCallComp* instance_call)
|
| + : instance_call_(instance_call) {
|
| + ASSERT(left != NULL);
|
| + ASSERT(right != NULL);
|
| + inputs_[0] = left;
|
| + inputs_[1] = right;
|
| + }
|
|
|
| - // Used for exception catch entries.
|
| - TargetEntryInstr(intptr_t try_index, intptr_t catch_try_index)
|
| - : BlockEntryInstr(try_index),
|
| - predecessor_(NULL),
|
| - catch_try_index_(catch_try_index) { }
|
| + DECLARE_COMPUTATION(CheckEitherNonSmi)
|
|
|
| - DECLARE_INSTRUCTION(TargetEntry)
|
| + virtual bool CanDeoptimize() const { return true; }
|
| + virtual intptr_t ResultCid() const { return kIllegalCid; }
|
|
|
| - virtual intptr_t PredecessorCount() const {
|
| - return (predecessor_ == NULL) ? 0 : 1;
|
| - }
|
| - virtual BlockEntryInstr* PredecessorAt(intptr_t index) const {
|
| - ASSERT((index == 0) && (predecessor_ != NULL));
|
| - return predecessor_;
|
| - }
|
| - virtual void AddPredecessor(BlockEntryInstr* predecessor) {
|
| - ASSERT(predecessor_ == NULL);
|
| - predecessor_ = predecessor;
|
| - }
|
| + virtual bool AttributesEqual(Computation* other) const { return true; }
|
|
|
| - // Returns true if this Block is an entry of a catch handler.
|
| - bool IsCatchEntry() const {
|
| - return catch_try_index_ != CatchClauseNode::kInvalidTryIndex;
|
| - }
|
| + virtual bool HasSideEffect() const { return false; }
|
|
|
| - // Returns try index for the try block to which this catch handler
|
| - // corresponds.
|
| - intptr_t catch_try_index() const {
|
| - ASSERT(IsCatchEntry());
|
| - return catch_try_index_;
|
| - }
|
| + Value* left() const { return inputs_[0]; }
|
|
|
| - virtual void PrepareEntry(FlowGraphCompiler* compiler);
|
| + Value* right() const { return inputs_[1]; }
|
| +
|
| + virtual Definition* TryReplace(BindInstr* instr) const;
|
|
|
| private:
|
| - BlockEntryInstr* predecessor_;
|
| - const intptr_t catch_try_index_;
|
| + InstanceCallComp* instance_call_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(TargetEntryInstr);
|
| + DISALLOW_COPY_AND_ASSIGN(CheckEitherNonSmiComp);
|
| };
|
|
|
|
|
| -// Abstract super-class of all instructions that define a value (Bind, Phi).
|
| -class Definition : public Instruction {
|
| +class BoxDoubleComp : public TemplateComputation<1> {
|
| public:
|
| - Definition()
|
| - : temp_index_(-1),
|
| - ssa_temp_index_(-1),
|
| - propagated_type_(AbstractType::Handle()),
|
| - propagated_cid_(kIllegalCid),
|
| - input_use_list_(NULL),
|
| - env_use_list_(NULL) { }
|
| -
|
| - virtual bool IsDefinition() const { return true; }
|
| - virtual Definition* AsDefinition() { return this; }
|
| -
|
| - intptr_t temp_index() const { return temp_index_; }
|
| - void set_temp_index(intptr_t index) { temp_index_ = index; }
|
| -
|
| - intptr_t ssa_temp_index() const { return ssa_temp_index_; }
|
| - void set_ssa_temp_index(intptr_t index) {
|
| - ASSERT(index >= 0);
|
| - ssa_temp_index_ = index;
|
| + BoxDoubleComp(Value* value, InstanceCallComp* instance_call)
|
| + : token_pos_((instance_call != NULL) ? instance_call->token_pos() : 0) {
|
| + ASSERT(value != NULL);
|
| + inputs_[0] = value;
|
| }
|
| - bool HasSSATemp() const { return ssa_temp_index_ >= 0; }
|
| -
|
| - // Compile time type of the definition, which may be requested before type
|
| - // propagation during graph building.
|
| - virtual RawAbstractType* CompileType() const = 0;
|
|
|
| - bool HasPropagatedType() const {
|
| - return !propagated_type_.IsNull();
|
| - }
|
| - RawAbstractType* PropagatedType() const {
|
| - ASSERT(HasPropagatedType());
|
| - return propagated_type_.raw();
|
| - }
|
| - // Returns true if the propagated type has changed.
|
| - bool SetPropagatedType(const AbstractType& propagated_type) {
|
| - if (propagated_type.IsNull()) {
|
| - // Not a typed definition, e.g. access to a VM field.
|
| - return false;
|
| - }
|
| - const bool changed =
|
| - propagated_type_.IsNull() || !propagated_type.Equals(propagated_type_);
|
| - propagated_type_ = propagated_type.raw();
|
| - return changed;
|
| - }
|
| + Value* value() const { return inputs_[0]; }
|
|
|
| - bool has_propagated_cid() const { return propagated_cid_ != kIllegalCid; }
|
| - intptr_t propagated_cid() const { return propagated_cid_; }
|
| - // May compute and set propagated cid.
|
| - virtual intptr_t GetPropagatedCid() = 0;
|
| + intptr_t token_pos() const { return token_pos_; }
|
|
|
| - // Returns true if the propagated cid has changed.
|
| - bool SetPropagatedCid(intptr_t cid);
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual bool HasSideEffect() const { return false; }
|
| + virtual bool AttributesEqual(Computation* other) const { return true; }
|
|
|
| - Value* input_use_list() { return input_use_list_; }
|
| - void set_input_use_list(Value* head) { input_use_list_ = head; }
|
| + virtual intptr_t ResultCid() const;
|
|
|
| - Value* env_use_list() { return env_use_list_; }
|
| - void set_env_use_list(Value* head) { env_use_list_ = head; }
|
| + virtual Representation RequiredInputRepresentation(intptr_t idx) const {
|
| + ASSERT(idx == 0);
|
| + return kUnboxedDouble;
|
| + }
|
|
|
| - // Replace uses of this definition with uses of other definition or value.
|
| - // Precondition: use lists must be properly calculated.
|
| - // Postcondition: use lists and use values are still valid.
|
| - void ReplaceUsesWith(Definition* other);
|
| + DECLARE_COMPUTATION(BoxDouble)
|
|
|
| private:
|
| - intptr_t temp_index_;
|
| - intptr_t ssa_temp_index_;
|
| - // TODO(regis): GrowableArray<const AbstractType*> propagated_types_;
|
| - // For now:
|
| - AbstractType& propagated_type_;
|
| - intptr_t propagated_cid_;
|
| - Value* input_use_list_;
|
| - Value* env_use_list_;
|
| + const intptr_t token_pos_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(Definition);
|
| + DISALLOW_COPY_AND_ASSIGN(BoxDoubleComp);
|
| };
|
|
|
|
|
| -class BindInstr : public Definition {
|
| +class UnboxDoubleComp : public TemplateComputation<1> {
|
| public:
|
| - enum UseKind { kUnused, kUsed };
|
| -
|
| - BindInstr(UseKind used, Computation* computation)
|
| - : computation_(computation), is_used_(used != kUnused) {
|
| - ASSERT(computation != NULL);
|
| + UnboxDoubleComp(Value* value, intptr_t deopt_id)
|
| + : deopt_id_(deopt_id) {
|
| + ASSERT(value != NULL);
|
| + inputs_[0] = value;
|
| }
|
|
|
| - DECLARE_INSTRUCTION(Bind)
|
| + Value* value() const { return inputs_[0]; }
|
|
|
| - virtual intptr_t ArgumentCount() const {
|
| - return computation()->ArgumentCount();
|
| + virtual bool CanDeoptimize() const {
|
| + return value()->ResultCid() != kDoubleCid;
|
| }
|
| - intptr_t InputCount() const { return computation()->InputCount(); }
|
|
|
| - Value* InputAt(intptr_t i) const { return computation()->InputAt(i); }
|
| + // The output is not an instance but when it is boxed it becomes double.
|
| + virtual intptr_t ResultCid() const { return kDoubleCid; }
|
|
|
| - void SetInputAt(intptr_t i, Value* value) {
|
| - computation()->SetInputAt(i, value);
|
| + virtual Representation representation() const {
|
| + return kUnboxedDouble;
|
| }
|
|
|
| - virtual bool CanDeoptimize() const { return computation()->CanDeoptimize(); }
|
| + virtual bool HasSideEffect() const { return false; }
|
| + virtual bool AttributesEqual(Computation* other) const { return true; }
|
|
|
| - Computation* computation() const { return computation_; }
|
| - void set_computation(Computation* value) { computation_ = value; }
|
| - bool is_used() const { return is_used_; }
|
| + DECLARE_COMPUTATION(UnboxDouble)
|
|
|
| - virtual RawAbstractType* CompileType() const;
|
| - virtual intptr_t GetPropagatedCid();
|
| + private:
|
| + const intptr_t deopt_id_;
|
|
|
| - virtual void RecordAssignedVars(BitVector* assigned_vars,
|
| - intptr_t fixed_parameter_count);
|
| + DISALLOW_COPY_AND_ASSIGN(UnboxDoubleComp);
|
| +};
|
|
|
| - intptr_t Hashcode() const { return computation()->Hashcode(); }
|
|
|
| - bool Equals(BindInstr* other) const {
|
| - return computation()->Equals(other->computation());
|
| +class UnboxedDoubleBinaryOpComp : public TemplateComputation<2> {
|
| + public:
|
| + UnboxedDoubleBinaryOpComp(Token::Kind op_kind,
|
| + Value* left,
|
| + Value* right,
|
| + InstanceCallComp* call)
|
| + : op_kind_(op_kind), deopt_id_(call->deopt_id()) {
|
| + ASSERT(left != NULL);
|
| + ASSERT(right != NULL);
|
| + inputs_[0] = left;
|
| + inputs_[1] = right;
|
| }
|
|
|
| - virtual LocationSummary* locs() {
|
| - return computation()->locs();
|
| - }
|
| + Value* left() const { return inputs_[0]; }
|
| + Value* right() const { return inputs_[1]; }
|
|
|
| - virtual void EmitNativeCode(FlowGraphCompiler* compiler);
|
| + Token::Kind op_kind() const { return op_kind_; }
|
|
|
| - // Insert this instruction before 'next'.
|
| - void InsertBefore(Instruction* next);
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - // Insert this instruction after 'prev'.
|
| - void InsertAfter(Instruction* prev);
|
| + virtual bool CanDeoptimize() const { return false; }
|
| + virtual bool HasSideEffect() const { return false; }
|
|
|
| - virtual Representation RequiredInputRepresentation(intptr_t i) const {
|
| - return computation()->RequiredInputRepresentation(i);
|
| + virtual bool AttributesEqual(Computation* other) const {
|
| + return op_kind() == other->AsUnboxedDoubleBinaryOp()->op_kind();
|
| }
|
|
|
| + // The output is not an instance but when it is boxed it becomes double.
|
| + virtual intptr_t ResultCid() const { return kDoubleCid; }
|
| +
|
| virtual Representation representation() const {
|
| - return computation()->representation();
|
| + return kUnboxedDouble;
|
| + }
|
| +
|
| + virtual Representation RequiredInputRepresentation(intptr_t idx) const {
|
| + ASSERT((idx == 0) || (idx == 1));
|
| + return kUnboxedDouble;
|
| }
|
|
|
| virtual intptr_t DeoptimizationTarget() const {
|
| - return computation()->DeoptimizationTarget();
|
| + return deopt_id_;
|
| }
|
|
|
| + DECLARE_COMPUTATION(UnboxedDoubleBinaryOp)
|
| +
|
| private:
|
| - Computation* computation_;
|
| - const bool is_used_;
|
| + const Token::Kind op_kind_;
|
| + const intptr_t deopt_id_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(BindInstr);
|
| + DISALLOW_COPY_AND_ASSIGN(UnboxedDoubleBinaryOpComp);
|
| };
|
|
|
|
|
| -class PhiInstr : public Definition {
|
| +class BinarySmiOpComp : public TemplateComputation<2> {
|
| public:
|
| - explicit PhiInstr(JoinEntryInstr* block, intptr_t num_inputs)
|
| - : block_(block),
|
| - inputs_(num_inputs),
|
| - is_alive_(false),
|
| - representation_(kTagged) {
|
| - for (intptr_t i = 0; i < num_inputs; ++i) {
|
| - inputs_.Add(NULL);
|
| - }
|
| + BinarySmiOpComp(Token::Kind op_kind,
|
| + InstanceCallComp* instance_call,
|
| + Value* left,
|
| + Value* right)
|
| + : op_kind_(op_kind),
|
| + instance_call_(instance_call) {
|
| + ASSERT(left != NULL);
|
| + ASSERT(right != NULL);
|
| + inputs_[0] = left;
|
| + inputs_[1] = right;
|
| }
|
|
|
| - JoinEntryInstr* block() const { return block_; }
|
| + Value* left() const { return inputs_[0]; }
|
| + Value* right() const { return inputs_[1]; }
|
|
|
| - virtual RawAbstractType* CompileType() const;
|
| - virtual intptr_t GetPropagatedCid() { return propagated_cid(); }
|
| + Token::Kind op_kind() const { return op_kind_; }
|
|
|
| - virtual intptr_t ArgumentCount() const { return 0; }
|
| + InstanceCallComp* instance_call() const { return instance_call_; }
|
|
|
| - intptr_t InputCount() const { return inputs_.length(); }
|
| + const ICData* ic_data() const { return instance_call()->ic_data(); }
|
|
|
| - Value* InputAt(intptr_t i) const { return inputs_[i]; }
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - void SetInputAt(intptr_t i, Value* value) { inputs_[i] = value; }
|
| + DECLARE_COMPUTATION(BinarySmiOp)
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| + virtual bool CanDeoptimize() const;
|
|
|
| - // TODO(regis): This helper will be removed once we support type sets.
|
| - RawAbstractType* LeastSpecificInputType() const;
|
| + virtual intptr_t ResultCid() const;
|
|
|
| - // Phi is alive if it reaches a non-environment use.
|
| - bool is_alive() const { return is_alive_; }
|
| - void mark_alive() { is_alive_ = true; }
|
| + private:
|
| + const Token::Kind op_kind_;
|
| + InstanceCallComp* instance_call_;
|
|
|
| - virtual Representation RequiredInputRepresentation(intptr_t i) const {
|
| - return representation_;
|
| - }
|
| + DISALLOW_COPY_AND_ASSIGN(BinarySmiOpComp);
|
| +};
|
|
|
| - virtual Representation representation() const {
|
| - return representation_;
|
| - }
|
|
|
| - virtual void set_representation(Representation r) {
|
| - representation_ = r;
|
| +class BinaryMintOpComp : public TemplateComputation<2> {
|
| + public:
|
| + BinaryMintOpComp(Token::Kind op_kind,
|
| + InstanceCallComp* instance_call,
|
| + Value* left,
|
| + Value* right)
|
| + : op_kind_(op_kind),
|
| + instance_call_(instance_call) {
|
| + ASSERT(left != NULL);
|
| + ASSERT(right != NULL);
|
| + inputs_[0] = left;
|
| + inputs_[1] = right;
|
| }
|
|
|
| - DECLARE_INSTRUCTION(Phi)
|
| + Value* left() const { return inputs_[0]; }
|
| + Value* right() const { return inputs_[1]; }
|
| +
|
| + Token::Kind op_kind() const { return op_kind_; }
|
| +
|
| + InstanceCallComp* instance_call() const { return instance_call_; }
|
| +
|
| + const ICData* ic_data() const { return instance_call()->ic_data(); }
|
| +
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
| +
|
| + DECLARE_COMPUTATION(BinaryMintOp)
|
| +
|
| + virtual bool CanDeoptimize() const { return true; }
|
| + virtual intptr_t ResultCid() const;
|
|
|
| private:
|
| - JoinEntryInstr* block_;
|
| - GrowableArray<Value*> inputs_;
|
| - bool is_alive_;
|
| - Representation representation_;
|
| + const Token::Kind op_kind_;
|
| + InstanceCallComp* instance_call_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(PhiInstr);
|
| + DISALLOW_COPY_AND_ASSIGN(BinaryMintOpComp);
|
| };
|
|
|
|
|
| -class ParameterInstr : public Definition {
|
| +class BinaryDoubleOpComp : public TemplateComputation<0> {
|
| public:
|
| - explicit ParameterInstr(intptr_t index) : index_(index) { }
|
| + BinaryDoubleOpComp(Token::Kind op_kind, InstanceCallComp* instance_call)
|
| + : op_kind_(op_kind), instance_call_(instance_call) { }
|
|
|
| - DECLARE_INSTRUCTION(Parameter)
|
| + Token::Kind op_kind() const { return op_kind_; }
|
|
|
| - intptr_t index() const { return index_; }
|
| + InstanceCallComp* instance_call() const { return instance_call_; }
|
|
|
| - // Compile type of the passed-in parameter.
|
| - virtual RawAbstractType* CompileType() const;
|
| - // No known propagated cid for parameters.
|
| - virtual intptr_t GetPropagatedCid() { return propagated_cid(); }
|
| + const ICData* ic_data() const { return instance_call()->ic_data(); }
|
|
|
| - virtual intptr_t ArgumentCount() const { return 0; }
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - intptr_t InputCount() const { return 0; }
|
| - Value* InputAt(intptr_t i) const {
|
| - UNREACHABLE();
|
| - return NULL;
|
| - }
|
| - void SetInputAt(intptr_t i, Value* value) { UNREACHABLE(); }
|
| + DECLARE_CALL_COMPUTATION(BinaryDoubleOp)
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ArgumentCount() const { return 2; }
|
| +
|
| + virtual bool CanDeoptimize() const { return true; }
|
| + virtual intptr_t ResultCid() const;
|
|
|
| private:
|
| - const intptr_t index_;
|
| + const Token::Kind op_kind_;
|
| + InstanceCallComp* instance_call_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(ParameterInstr);
|
| + DISALLOW_COPY_AND_ASSIGN(BinaryDoubleOpComp);
|
| };
|
|
|
|
|
| -class PushArgumentInstr : public Definition {
|
| +// Handles both Smi operations: BIT_OR and NEGATE.
|
| +class UnarySmiOpComp : public TemplateComputation<1> {
|
| public:
|
| - explicit PushArgumentInstr(Value* value) : value_(value), locs_(NULL) {
|
| + UnarySmiOpComp(Token::Kind op_kind,
|
| + InstanceCallComp* instance_call,
|
| + Value* value)
|
| + : op_kind_(op_kind), instance_call_(instance_call) {
|
| + ASSERT((op_kind == Token::kNEGATE) || (op_kind == Token::kBIT_NOT));
|
| ASSERT(value != NULL);
|
| + inputs_[0] = value;
|
| }
|
|
|
| - DECLARE_INSTRUCTION(PushArgument)
|
| -
|
| - intptr_t InputCount() const { return 1; }
|
| - Value* InputAt(intptr_t i) const {
|
| - ASSERT(i == 0);
|
| - return value_;
|
| - }
|
| - void SetInputAt(intptr_t i, Value* value) {
|
| - ASSERT(i == 0);
|
| - value_ = value;
|
| - }
|
| -
|
| - virtual intptr_t ArgumentCount() const { return 0; }
|
| -
|
| - virtual RawAbstractType* CompileType() const;
|
| - virtual intptr_t GetPropagatedCid() { return propagated_cid(); }
|
| -
|
| - Value* value() const { return value_; }
|
| -
|
| - virtual LocationSummary* locs() {
|
| - if (locs_ == NULL) {
|
| - locs_ = MakeLocationSummary();
|
| - }
|
| - return locs_;
|
| - }
|
| + Value* value() const { return inputs_[0]; }
|
| + Token::Kind op_kind() const { return op_kind_; }
|
|
|
| - LocationSummary* MakeLocationSummary() const;
|
| + InstanceCallComp* instance_call() const { return instance_call_; }
|
|
|
| - virtual void EmitNativeCode(FlowGraphCompiler* compiler);
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| + DECLARE_COMPUTATION(UnarySmiOp)
|
| +
|
| + virtual bool CanDeoptimize() const { return op_kind() == Token::kNEGATE; }
|
| + virtual intptr_t ResultCid() const { return kSmiCid; }
|
|
|
| private:
|
| - Value* value_;
|
| - LocationSummary* locs_;
|
| + const Token::Kind op_kind_;
|
| + InstanceCallComp* instance_call_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(PushArgumentInstr);
|
| + DISALLOW_COPY_AND_ASSIGN(UnarySmiOpComp);
|
| };
|
|
|
|
|
| -class ReturnInstr : public TemplateInstruction<1> {
|
| +// Handles non-Smi NEGATE operations
|
| +class NumberNegateComp : public TemplateComputation<1> {
|
| public:
|
| - ReturnInstr(intptr_t token_pos, Value* value)
|
| - : deopt_id_(Isolate::Current()->GetNextDeoptId()),
|
| - token_pos_(token_pos) {
|
| + NumberNegateComp(InstanceCallComp* instance_call,
|
| + Value* value) : instance_call_(instance_call) {
|
| ASSERT(value != NULL);
|
| inputs_[0] = value;
|
| }
|
|
|
| - DECLARE_INSTRUCTION(Return)
|
| -
|
| - virtual intptr_t ArgumentCount() const { return 0; }
|
| -
|
| - intptr_t deopt_id() const { return deopt_id_; }
|
| - intptr_t token_pos() const { return token_pos_; }
|
| Value* value() const { return inputs_[0]; }
|
|
|
| - virtual LocationSummary* MakeLocationSummary() const;
|
| + InstanceCallComp* instance_call() const { return instance_call_; }
|
|
|
| - virtual void EmitNativeCode(FlowGraphCompiler* compiler);
|
| + const ICData* ic_data() const { return instance_call()->ic_data(); }
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| + DECLARE_COMPUTATION(NumberNegate)
|
| +
|
| + virtual bool CanDeoptimize() const { return true; }
|
| + virtual intptr_t ResultCid() const { return kDoubleCid; }
|
|
|
| private:
|
| - const intptr_t deopt_id_;
|
| - const intptr_t token_pos_;
|
| + InstanceCallComp* instance_call_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(ReturnInstr);
|
| + DISALLOW_COPY_AND_ASSIGN(NumberNegateComp);
|
| };
|
|
|
|
|
| -class ThrowInstr : public TemplateInstruction<0> {
|
| +class CheckStackOverflowComp : public TemplateComputation<0> {
|
| public:
|
| - explicit ThrowInstr(intptr_t token_pos) : token_pos_(token_pos) { }
|
| -
|
| - DECLARE_INSTRUCTION(Throw)
|
| -
|
| - virtual intptr_t ArgumentCount() const { return 1; }
|
| + explicit CheckStackOverflowComp(intptr_t token_pos)
|
| + : token_pos_(token_pos) {}
|
|
|
| intptr_t token_pos() const { return token_pos_; }
|
|
|
| - virtual LocationSummary* MakeLocationSummary() const;
|
| -
|
| - virtual void EmitNativeCode(FlowGraphCompiler* compiler);
|
| + DECLARE_COMPUTATION(CheckStackOverflow)
|
|
|
| virtual bool CanDeoptimize() const { return false; }
|
| + virtual intptr_t ResultCid() const { return kIllegalCid; }
|
|
|
| private:
|
| const intptr_t token_pos_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(ThrowInstr);
|
| + DISALLOW_COPY_AND_ASSIGN(CheckStackOverflowComp);
|
| };
|
|
|
|
|
| -class ReThrowInstr : public TemplateInstruction<0> {
|
| +class DoubleToDoubleComp : public TemplateComputation<1> {
|
| public:
|
| - explicit ReThrowInstr(intptr_t token_pos) : token_pos_(token_pos) { }
|
| + DoubleToDoubleComp(Value* value, InstanceCallComp* instance_call)
|
| + : instance_call_(instance_call) {
|
| + ASSERT(value != NULL);
|
| + inputs_[0] = value;
|
| + }
|
|
|
| - DECLARE_INSTRUCTION(ReThrow)
|
| + Value* value() const { return inputs_[0]; }
|
|
|
| - virtual intptr_t ArgumentCount() const { return 2; }
|
| + InstanceCallComp* instance_call() const { return instance_call_; }
|
|
|
| - intptr_t token_pos() const { return token_pos_; }
|
| + DECLARE_COMPUTATION(DoubleToDouble)
|
|
|
| - virtual LocationSummary* MakeLocationSummary() const;
|
| + virtual bool CanDeoptimize() const { return true; }
|
| + virtual intptr_t ResultCid() const { return kDoubleCid; }
|
|
|
| - virtual void EmitNativeCode(FlowGraphCompiler* compiler);
|
| + private:
|
| + InstanceCallComp* instance_call_;
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| + DISALLOW_COPY_AND_ASSIGN(DoubleToDoubleComp);
|
| +};
|
| +
|
| +
|
| +class SmiToDoubleComp : public TemplateComputation<0> {
|
| + public:
|
| + explicit SmiToDoubleComp(InstanceCallComp* instance_call)
|
| + : instance_call_(instance_call) { }
|
| +
|
| + InstanceCallComp* instance_call() const { return instance_call_; }
|
| +
|
| + DECLARE_CALL_COMPUTATION(SmiToDouble)
|
| +
|
| + virtual intptr_t ArgumentCount() const { return 1; }
|
| +
|
| + virtual bool CanDeoptimize() const { return true; }
|
| + virtual intptr_t ResultCid() const { return kDoubleCid; }
|
|
|
| private:
|
| - const intptr_t token_pos_;
|
| + InstanceCallComp* instance_call_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(ReThrowInstr);
|
| + DISALLOW_COPY_AND_ASSIGN(SmiToDoubleComp);
|
| };
|
|
|
|
|
| -class GotoInstr : public TemplateInstruction<0> {
|
| +class CheckClassComp : public TemplateComputation<1> {
|
| public:
|
| - explicit GotoInstr(JoinEntryInstr* entry)
|
| - : successor_(entry),
|
| - parallel_move_(NULL) { }
|
| + CheckClassComp(Value* value,
|
| + InstanceCallComp* instance_call,
|
| + const ICData& unary_checks)
|
| + : instance_call_(instance_call),
|
| + unary_checks_(unary_checks) {
|
| + ASSERT(value != NULL);
|
| + inputs_[0] = value;
|
| + }
|
|
|
| - DECLARE_INSTRUCTION(Goto)
|
| + DECLARE_COMPUTATION(CheckClass)
|
|
|
| - virtual intptr_t ArgumentCount() const { return 0; }
|
| + virtual bool CanDeoptimize() const { return true; }
|
| + virtual intptr_t ResultCid() const { return kIllegalCid; }
|
|
|
| - JoinEntryInstr* successor() const { return successor_; }
|
| - void set_successor(JoinEntryInstr* successor) { successor_ = successor; }
|
| - virtual intptr_t SuccessorCount() const;
|
| - virtual BlockEntryInstr* SuccessorAt(intptr_t index) const;
|
| + virtual bool AttributesEqual(Computation* other) const;
|
|
|
| - virtual LocationSummary* MakeLocationSummary() const;
|
| + virtual bool HasSideEffect() const { return false; }
|
|
|
| - virtual void EmitNativeCode(FlowGraphCompiler* compiler);
|
| + Value* value() const { return inputs_[0]; }
|
|
|
| - virtual bool CanDeoptimize() const { return false; }
|
| + const ICData& unary_checks() const { return unary_checks_; }
|
|
|
| - ParallelMoveInstr* parallel_move() const {
|
| - return parallel_move_;
|
| - }
|
| + virtual intptr_t deopt_id() const { return instance_call_->deopt_id(); }
|
|
|
| - bool HasParallelMove() const {
|
| - return parallel_move_ != NULL;
|
| - }
|
| + virtual Definition* TryReplace(BindInstr* instr) const;
|
|
|
| - ParallelMoveInstr* GetParallelMove() {
|
| - if (parallel_move_ == NULL) {
|
| - parallel_move_ = new ParallelMoveInstr();
|
| - }
|
| - return parallel_move_;
|
| - }
|
| + virtual void PrintOperandsTo(BufferFormatter* f) const;
|
|
|
| private:
|
| - JoinEntryInstr* successor_;
|
| + InstanceCallComp* instance_call_;
|
| + const ICData& unary_checks_;
|
|
|
| - // Parallel move that will be used by linear scan register allocator to
|
| - // connect live ranges at the end of the block and resolve phis.
|
| - ParallelMoveInstr* parallel_move_;
|
| + DISALLOW_COPY_AND_ASSIGN(CheckClassComp);
|
| };
|
|
|
|
|
| -class ControlInstruction : public Instruction {
|
| +class CheckSmiComp : public TemplateComputation<1> {
|
| public:
|
| - ControlInstruction() : true_successor_(NULL), false_successor_(NULL) { }
|
| + CheckSmiComp(Value* value, intptr_t original_deopt_id)
|
| + : original_deopt_id_(original_deopt_id) {
|
| + ASSERT(value != NULL);
|
| + ASSERT(original_deopt_id != Isolate::kNoDeoptId);
|
| + inputs_[0] = value;
|
| + }
|
|
|
| - virtual bool IsControl() const { return true; }
|
| + DECLARE_COMPUTATION(CheckSmi)
|
|
|
| - TargetEntryInstr* true_successor() const { return true_successor_; }
|
| - TargetEntryInstr* false_successor() const { return false_successor_; }
|
| + virtual bool CanDeoptimize() const { return true; }
|
| + virtual intptr_t ResultCid() const { return kIllegalCid; }
|
|
|
| - TargetEntryInstr** true_successor_address() { return &true_successor_; }
|
| - TargetEntryInstr** false_successor_address() { return &false_successor_; }
|
| + virtual bool AttributesEqual(Computation* other) const { return true; }
|
|
|
| - virtual intptr_t SuccessorCount() const;
|
| - virtual BlockEntryInstr* SuccessorAt(intptr_t index) const;
|
| + virtual bool HasSideEffect() const { return false; }
|
|
|
| - virtual void DiscoverBlocks(
|
| - BlockEntryInstr* current_block,
|
| - GrowableArray<BlockEntryInstr*>* preorder,
|
| - GrowableArray<BlockEntryInstr*>* postorder,
|
| - GrowableArray<intptr_t>* parent,
|
| - GrowableArray<BitVector*>* assigned_vars,
|
| - intptr_t variable_count,
|
| - intptr_t fixed_parameter_count);
|
| + virtual Definition* TryReplace(BindInstr* instr) const;
|
|
|
| + Value* value() const { return inputs_[0]; }
|
|
|
| - void EmitBranchOnCondition(FlowGraphCompiler* compiler,
|
| - Condition true_condition);
|
| + virtual intptr_t deopt_id() const { return original_deopt_id_; }
|
|
|
| private:
|
| - TargetEntryInstr* true_successor_;
|
| - TargetEntryInstr* false_successor_;
|
| + const intptr_t original_deopt_id_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(ControlInstruction);
|
| + DISALLOW_COPY_AND_ASSIGN(CheckSmiComp);
|
| };
|
|
|
|
|
| -class BranchInstr : public ControlInstruction {
|
| +class CheckArrayBoundComp : public TemplateComputation<2> {
|
| public:
|
| - explicit BranchInstr(ComparisonComp* computation)
|
| - : computation_(computation), locs_(NULL) { }
|
| -
|
| - DECLARE_INSTRUCTION(Branch)
|
| -
|
| - virtual intptr_t ArgumentCount() const {
|
| - return computation()->ArgumentCount();
|
| + CheckArrayBoundComp(Value* array,
|
| + Value* index,
|
| + intptr_t array_type,
|
| + InstanceCallComp* instance_call)
|
| + : array_type_(array_type), instance_call_(instance_call) {
|
| + ASSERT(array != NULL);
|
| + ASSERT(index != NULL);
|
| + inputs_[0] = array;
|
| + inputs_[1] = index;
|
| }
|
| - intptr_t InputCount() const { return computation()->InputCount(); }
|
| -
|
| - Value* InputAt(intptr_t i) const { return computation()->InputAt(i); }
|
|
|
| - void SetInputAt(intptr_t i, Value* value) {
|
| - computation()->SetInputAt(i, value);
|
| - }
|
| + DECLARE_COMPUTATION(CheckArrayBound)
|
|
|
| - virtual bool CanDeoptimize() const { return computation()->CanDeoptimize(); }
|
| + virtual bool CanDeoptimize() const { return true; }
|
| + virtual intptr_t ResultCid() const { return kIllegalCid; }
|
|
|
| - ComparisonComp* computation() const { return computation_; }
|
| - void set_computation(ComparisonComp* value) { computation_ = value; }
|
| + virtual bool AttributesEqual(Computation* other) const;
|
|
|
| - virtual void EmitNativeCode(FlowGraphCompiler* compiler);
|
| + virtual bool HasSideEffect() const { return false; }
|
|
|
| - virtual LocationSummary* locs() {
|
| - if (computation_->locs_ == NULL) {
|
| - LocationSummary* summary = computation_->MakeLocationSummary();
|
| - // Branches don't produce a result.
|
| - summary->set_out(Location::NoLocation());
|
| - computation_->locs_ = summary;
|
| - }
|
| - return computation_->locs_;
|
| - }
|
| + Value* array() const { return inputs_[0]; }
|
| + Value* index() const { return inputs_[1]; }
|
|
|
| - virtual intptr_t DeoptimizationTarget() const {
|
| - return computation_->DeoptimizationTarget();
|
| - }
|
| + intptr_t array_type() const { return array_type_; }
|
|
|
| - virtual Representation RequiredInputRepresentation(intptr_t i) const {
|
| - return computation()->RequiredInputRepresentation(i);
|
| - }
|
| + virtual intptr_t deopt_id() const { return instance_call_->deopt_id(); }
|
|
|
| private:
|
| - ComparisonComp* computation_;
|
| - LocationSummary* locs_;
|
| + intptr_t array_type_;
|
| + InstanceCallComp* instance_call_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(BranchInstr);
|
| + DISALLOW_COPY_AND_ASSIGN(CheckArrayBoundComp);
|
| };
|
|
|
|
|
| -#undef DECLARE_INSTRUCTION
|
| +#undef DECLARE_COMPUTATION
|
| +
|
| +
|
| +// Implementation of type testers and cast functins.
|
| +#define DEFINE_COMPUTATION_PREDICATE(ShortName, ClassName) \
|
| +bool Computation::Is##ShortName() const { \
|
| + return computation_kind() == k##ShortName; \
|
| +} \
|
| +const ClassName* Computation::As##ShortName() const { \
|
| + if (!Is##ShortName()) return NULL; \
|
| + return static_cast<const ClassName*>(this); \
|
| +} \
|
| +ClassName* Computation::As##ShortName() { \
|
| + if (!Is##ShortName()) return NULL; \
|
| + return static_cast<ClassName*>(this); \
|
| +}
|
| +FOR_EACH_COMPUTATION(DEFINE_COMPUTATION_PREDICATE)
|
| +#undef DEFINE_COMPUTATION_PREDICATE
|
|
|
|
|
| class Environment : public ZoneAllocated {
|
|
|