| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef VM_INTERMEDIATE_LANGUAGE_H_ | 5 #ifndef VM_INTERMEDIATE_LANGUAGE_H_ |
| 6 #define VM_INTERMEDIATE_LANGUAGE_H_ | 6 #define VM_INTERMEDIATE_LANGUAGE_H_ |
| 7 | 7 |
| 8 #include "vm/allocation.h" | 8 #include "vm/allocation.h" |
| 9 #include "vm/ast.h" | 9 #include "vm/ast.h" |
| 10 #include "vm/growable_array.h" | 10 #include "vm/growable_array.h" |
| 11 #include "vm/handles_impl.h" | 11 #include "vm/handles_impl.h" |
| 12 #include "vm/locations.h" | 12 #include "vm/locations.h" |
| 13 #include "vm/object.h" | 13 #include "vm/object.h" |
| 14 | 14 |
| 15 namespace dart { | 15 namespace dart { |
| 16 | 16 |
| 17 class BindInstr; |
| 18 class BitVector; |
| 19 class BlockEntryInstr; |
| 20 class BufferFormatter; |
| 21 class ComparisonComp; |
| 22 class Computation; |
| 23 class Definition; |
| 24 class Environment; |
| 25 class FlowGraphCompiler; |
| 26 class FlowGraphVisitor; |
| 27 class Instruction; |
| 28 class LocalVariable; |
| 29 |
| 30 |
| 17 // TODO(srdjan): Add _ByteArrayBase, get:length. | 31 // TODO(srdjan): Add _ByteArrayBase, get:length. |
| 18 | 32 |
| 19 #define RECOGNIZED_LIST(V) \ | 33 #define RECOGNIZED_LIST(V) \ |
| 20 V(ObjectArray, get:length, ObjectArrayLength) \ | 34 V(ObjectArray, get:length, ObjectArrayLength) \ |
| 21 V(ImmutableArray, get:length, ImmutableArrayLength) \ | 35 V(ImmutableArray, get:length, ImmutableArrayLength) \ |
| 22 V(GrowableObjectArray, get:length, GrowableArrayLength) \ | 36 V(GrowableObjectArray, get:length, GrowableArrayLength) \ |
| 23 V(StringBase, get:length, StringBaseLength) \ | 37 V(StringBase, get:length, StringBaseLength) \ |
| 24 V(IntegerImplementation, toDouble, IntegerToDouble) \ | 38 V(IntegerImplementation, toDouble, IntegerToDouble) \ |
| 25 V(Double, toDouble, DoubleToDouble) \ | 39 V(Double, toDouble, DoubleToDouble) \ |
| 26 V(::, sqrt, MathSqrt) \ | 40 V(::, sqrt, MathSqrt) \ |
| 27 | 41 |
| 28 // Class that recognizes the name and owner of a function and returns the | 42 // Class that recognizes the name and owner of a function and returns the |
| 29 // corresponding enum. See RECOGNIZED_LIST above for list of recognizable | 43 // corresponding enum. See RECOGNIZED_LIST above for list of recognizable |
| 30 // functions. | 44 // functions. |
| 31 class MethodRecognizer : public AllStatic { | 45 class MethodRecognizer : public AllStatic { |
| 32 public: | 46 public: |
| 33 enum Kind { | 47 enum Kind { |
| 34 kUnknown, | 48 kUnknown, |
| 35 #define DEFINE_ENUM_LIST(class_name, function_name, enum_name) k##enum_name, | 49 #define DEFINE_ENUM_LIST(class_name, function_name, enum_name) k##enum_name, |
| 36 RECOGNIZED_LIST(DEFINE_ENUM_LIST) | 50 RECOGNIZED_LIST(DEFINE_ENUM_LIST) |
| 37 #undef DEFINE_ENUM_LIST | 51 #undef DEFINE_ENUM_LIST |
| 38 }; | 52 }; |
| 39 | 53 |
| 40 static Kind RecognizeKind(const Function& function); | 54 static Kind RecognizeKind(const Function& function); |
| 41 static const char* KindToCString(Kind kind); | 55 static const char* KindToCString(Kind kind); |
| 42 }; | 56 }; |
| 43 | 57 |
| 44 | 58 |
| 45 class BitVector; | 59 class Value : public ZoneAllocated { |
| 46 class FlowGraphAllocator; | 60 public: |
| 47 class FlowGraphCompiler; | 61 explicit Value(Definition* definition) |
| 48 class FlowGraphVisitor; | 62 : definition_(definition), |
| 49 class Function; | 63 next_use_(NULL), |
| 50 class LocalVariable; | 64 instruction_(NULL), |
| 51 | 65 use_index_(-1) { } |
| 52 // M is a two argument macro. It is applied to each concrete instruction's | 66 |
| 53 // (including the values) typename and classname. | 67 Definition* definition() const { return definition_; } |
| 54 #define FOR_EACH_COMPUTATION(M) \ | 68 void set_definition(Definition* definition) { definition_ = definition; } |
| 55 M(AssertAssignable, AssertAssignableComp) \ | 69 |
| 56 M(AssertBoolean, AssertBooleanComp) \ | 70 Value* next_use() const { return next_use_; } |
| 57 M(ArgumentDefinitionTest, ArgumentDefinitionTestComp) \ | 71 void set_next_use(Value* next) { next_use_ = next; } |
| 58 M(CurrentContext, CurrentContextComp) \ | 72 |
| 59 M(StoreContext, StoreContextComp) \ | 73 Instruction* instruction() const { return instruction_; } |
| 60 M(ClosureCall, ClosureCallComp) \ | 74 void set_instruction(Instruction* instruction) { instruction_ = instruction; } |
| 61 M(InstanceCall, InstanceCallComp) \ | 75 |
| 62 M(PolymorphicInstanceCall, PolymorphicInstanceCallComp) \ | 76 intptr_t use_index() const { return use_index_; } |
| 63 M(StaticCall, StaticCallComp) \ | 77 void set_use_index(intptr_t index) { use_index_ = index; } |
| 64 M(LoadLocal, LoadLocalComp) \ | 78 |
| 65 M(StoreLocal, StoreLocalComp) \ | 79 void AddToInputUseList(); |
| 66 M(StrictCompare, StrictCompareComp) \ | 80 void AddToEnvUseList(); |
| 67 M(EqualityCompare, EqualityCompareComp) \ | 81 |
| 68 M(RelationalOp, RelationalOpComp) \ | 82 Value* Copy() { return new Value(definition_); } |
| 69 M(NativeCall, NativeCallComp) \ | 83 |
| 70 M(LoadIndexed, LoadIndexedComp) \ | 84 RawAbstractType* CompileType() const; |
| 71 M(StoreIndexed, StoreIndexedComp) \ | 85 intptr_t ResultCid() const; |
| 72 M(LoadInstanceField, LoadInstanceFieldComp) \ | 86 |
| 73 M(StoreInstanceField, StoreInstanceFieldComp) \ | 87 void PrintTo(BufferFormatter* f) const; |
| 74 M(LoadStaticField, LoadStaticFieldComp) \ | 88 |
| 75 M(StoreStaticField, StoreStaticFieldComp) \ | 89 const char* DebugName() const { return "Value"; } |
| 76 M(BooleanNegate, BooleanNegateComp) \ | 90 |
| 77 M(InstanceOf, InstanceOfComp) \ | 91 // Returns true if the value represents a constant. |
| 78 M(CreateArray, CreateArrayComp) \ | 92 bool BindsToConstant() const; |
| 79 M(CreateClosure, CreateClosureComp) \ | 93 |
| 80 M(AllocateObject, AllocateObjectComp) \ | 94 // Returns true if the value represents the constant null. |
| 81 M(AllocateObjectWithBoundsCheck, AllocateObjectWithBoundsCheckComp) \ | 95 bool BindsToConstantNull() const; |
| 82 M(LoadVMField, LoadVMFieldComp) \ | 96 |
| 83 M(StoreVMField, StoreVMFieldComp) \ | 97 // Assert if BindsToConstant() is false, otherwise returns the constant value. |
| 84 M(InstantiateTypeArguments, InstantiateTypeArgumentsComp) \ | 98 const Object& BoundConstant() const; |
| 85 M(ExtractConstructorTypeArguments, ExtractConstructorTypeArgumentsComp) \ | 99 |
| 86 M(ExtractConstructorInstantiator, ExtractConstructorInstantiatorComp) \ | 100 // Reminder: The type of the constant null is the bottom type, which is more |
| 87 M(AllocateContext, AllocateContextComp) \ | 101 // specific than any type. |
| 88 M(ChainContext, ChainContextComp) \ | 102 bool CompileTypeIsMoreSpecificThan(const AbstractType& dst_type) const; |
| 89 M(CloneContext, CloneContextComp) \ | 103 |
| 90 M(CatchEntry, CatchEntryComp) \ | 104 // Compile time constants, Bool, Smi and Nulls do not need to update |
| 91 M(BinarySmiOp, BinarySmiOpComp) \ | 105 // the store buffer. |
| 92 M(BinaryMintOp, BinaryMintOpComp) \ | 106 bool NeedsStoreBuffer() const; |
| 93 M(BinaryDoubleOp, BinaryDoubleOpComp) \ | 107 |
| 94 M(UnarySmiOp, UnarySmiOpComp) \ | 108 bool Equals(Value* other) const; |
| 95 M(NumberNegate, NumberNegateComp) \ | 109 |
| 96 M(CheckStackOverflow, CheckStackOverflowComp) \ | 110 private: |
| 97 M(DoubleToDouble, DoubleToDoubleComp) \ | 111 Definition* definition_; |
| 98 M(SmiToDouble, SmiToDoubleComp) \ | 112 Value* next_use_; |
| 99 M(CheckClass, CheckClassComp) \ | 113 Instruction* instruction_; |
| 100 M(CheckSmi, CheckSmiComp) \ | 114 intptr_t use_index_; |
| 101 M(Constant, ConstantComp) \ | 115 |
| 102 M(CheckEitherNonSmi, CheckEitherNonSmiComp) \ | 116 DISALLOW_COPY_AND_ASSIGN(Value); |
| 103 M(UnboxedDoubleBinaryOp, UnboxedDoubleBinaryOpComp) \ | 117 }; |
| 104 M(UnboxDouble, UnboxDoubleComp) \ | |
| 105 M(BoxDouble, BoxDoubleComp) \ | |
| 106 M(CheckArrayBound, CheckArrayBoundComp) | |
| 107 | |
| 108 | |
| 109 #define FORWARD_DECLARATION(ShortName, ClassName) class ClassName; | |
| 110 FOR_EACH_COMPUTATION(FORWARD_DECLARATION) | |
| 111 #undef FORWARD_DECLARATION | |
| 112 | |
| 113 // Forward declarations. | |
| 114 class BindInstr; | |
| 115 class BranchInstr; | |
| 116 class BufferFormatter; | |
| 117 class ComparisonComp; | |
| 118 class Definition; | |
| 119 class Definition; | |
| 120 class Instruction; | |
| 121 class PhiInstr; | |
| 122 class PushArgumentInstr; | |
| 123 class Value; | |
| 124 | 118 |
| 125 | 119 |
| 126 enum Representation { | 120 enum Representation { |
| 127 kTagged, kUnboxedDouble | 121 kTagged, kUnboxedDouble |
| 128 }; | 122 }; |
| 129 | 123 |
| 130 | 124 |
| 131 class Computation : public ZoneAllocated { | |
| 132 public: | |
| 133 Computation() | |
| 134 : deopt_id_(Isolate::Current()->GetNextDeoptId()), locs_(NULL) { } | |
| 135 | |
| 136 // Unique id used for deoptimization. | |
| 137 virtual intptr_t deopt_id() const { | |
| 138 ASSERT(CanDeoptimize()); | |
| 139 return deopt_id_; | |
| 140 } | |
| 141 | |
| 142 // Visiting support. | |
| 143 virtual void Accept(FlowGraphVisitor* visitor, BindInstr* instr) = 0; | |
| 144 | |
| 145 virtual intptr_t InputCount() const = 0; | |
| 146 virtual Value* InputAt(intptr_t i) const = 0; | |
| 147 virtual void SetInputAt(intptr_t i, Value* value) = 0; | |
| 148 | |
| 149 // Call computations override this function and return the | |
| 150 // number of pushed arguments. | |
| 151 virtual intptr_t ArgumentCount() const = 0; | |
| 152 | |
| 153 // Returns true, if this computation can deoptimize. | |
| 154 virtual bool CanDeoptimize() const = 0; | |
| 155 | |
| 156 // Returns a replacement for the instruction that wraps this computation. | |
| 157 // Returns NULL if instr can be eliminated. | |
| 158 // By default returns instr (input parameter) which means no change. | |
| 159 virtual Definition* TryReplace(BindInstr* instr) const; | |
| 160 | |
| 161 // Compares two computations. Returns true, if: | |
| 162 // 1. They are of the same kind. | |
| 163 // 2. All input operands match. | |
| 164 // 3. All other attributes match. | |
| 165 bool Equals(Computation* other) const; | |
| 166 | |
| 167 // Returns a hash code for use with hash maps. | |
| 168 virtual intptr_t Hashcode() const; | |
| 169 | |
| 170 // Compare attributes of an computation (except input operands and kind). | |
| 171 // All computations that participate in CSE have to override this function. | |
| 172 virtual bool AttributesEqual(Computation* other) const { | |
| 173 UNREACHABLE(); | |
| 174 return false; | |
| 175 } | |
| 176 | |
| 177 // Returns true if the instruction may have side effects. | |
| 178 // TODO(fschneider): Make this abstract and implement for all computations | |
| 179 // instead of returning the safe default (true). | |
| 180 virtual bool HasSideEffect() const { return true; } | |
| 181 | |
| 182 // Compile time type of the computation, which typically depends on the | |
| 183 // compile time types (and possibly propagated types) of its inputs. | |
| 184 virtual RawAbstractType* CompileType() const = 0; | |
| 185 virtual intptr_t ResultCid() const = 0; | |
| 186 | |
| 187 // Mutate assigned_vars to add the local variable index for all | |
| 188 // frame-allocated locals assigned to by the computation. | |
| 189 virtual void RecordAssignedVars(BitVector* assigned_vars, | |
| 190 intptr_t fixed_parameter_count); | |
| 191 | |
| 192 virtual const char* DebugName() const = 0; | |
| 193 | |
| 194 // Printing support. These functions are sometimes overridden for custom | |
| 195 // formatting. Otherwise, it prints in the format "opcode(op1, op2, op3)". | |
| 196 virtual void PrintTo(BufferFormatter* f) const; | |
| 197 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 198 | |
| 199 // Returns structure describing location constraints required | |
| 200 // to emit native code for this computation. | |
| 201 LocationSummary* locs() { | |
| 202 if (locs_ == NULL) { | |
| 203 locs_ = MakeLocationSummary(); | |
| 204 } | |
| 205 return locs_; | |
| 206 } | |
| 207 | |
| 208 virtual ComparisonComp* AsComparison() { return NULL; } | |
| 209 | |
| 210 // Create a location summary for this computation. | |
| 211 // TODO(fschneider): Temporarily returns NULL for instructions | |
| 212 // that are not yet converted to the location based code generation. | |
| 213 virtual LocationSummary* MakeLocationSummary() const = 0; | |
| 214 | |
| 215 // TODO(fschneider): Make EmitNativeCode and locs const. | |
| 216 virtual void EmitNativeCode(FlowGraphCompiler* compiler) = 0; | |
| 217 | |
| 218 virtual void EmitBranchCode(FlowGraphCompiler* compiler, | |
| 219 BranchInstr* branch) { | |
| 220 UNREACHABLE(); | |
| 221 } | |
| 222 | |
| 223 static LocationSummary* MakeCallSummary(); | |
| 224 | |
| 225 // Declare an enum value used to define kind-test predicates. | |
| 226 enum ComputationKind { | |
| 227 #define DECLARE_COMPUTATION_KIND(ShortName, ClassName) k##ShortName, | |
| 228 | |
| 229 FOR_EACH_COMPUTATION(DECLARE_COMPUTATION_KIND) | |
| 230 | |
| 231 #undef DECLARE_COMPUTATION_KIND | |
| 232 }; | |
| 233 | |
| 234 virtual ComputationKind computation_kind() const = 0; | |
| 235 | |
| 236 // Returns representation expected for the input operand at the given index. | |
| 237 virtual Representation RequiredInputRepresentation(intptr_t idx) const { | |
| 238 return kTagged; | |
| 239 } | |
| 240 | |
| 241 // Representation of the value produced by this computation. | |
| 242 virtual Representation representation() const { | |
| 243 return kTagged; | |
| 244 } | |
| 245 | |
| 246 // Returns deoptimization id that corresponds to the deoptimization target | |
| 247 // that input operands conversions inserted for this instruction can jump | |
| 248 // to. Can return kNoDeoptId. | |
| 249 virtual intptr_t DeoptimizationTarget() const { | |
| 250 UNREACHABLE(); | |
| 251 return Isolate::kNoDeoptId; | |
| 252 } | |
| 253 | |
| 254 // Declare predicate for each computation. | |
| 255 #define DECLARE_PREDICATE(ShortName, ClassName) \ | |
| 256 inline bool Is##ShortName() const; \ | |
| 257 inline const ClassName* As##ShortName() const; \ | |
| 258 inline ClassName* As##ShortName(); | |
| 259 FOR_EACH_COMPUTATION(DECLARE_PREDICATE) | |
| 260 #undef DECLARE_PREDICATE | |
| 261 | |
| 262 protected: | |
| 263 // Fetch deopt id without checking if this computation can deoptimize. | |
| 264 intptr_t GetDeoptId() const { | |
| 265 return deopt_id_; | |
| 266 } | |
| 267 | |
| 268 private: | |
| 269 friend class BranchInstr; | |
| 270 | |
| 271 intptr_t deopt_id_; | |
| 272 LocationSummary* locs_; | |
| 273 | |
| 274 DISALLOW_COPY_AND_ASSIGN(Computation); | |
| 275 }; | |
| 276 | |
| 277 | |
| 278 // An embedded container with N elements of type T. Used (with partial | 125 // An embedded container with N elements of type T. Used (with partial |
| 279 // specialization for N=0) because embedded arrays cannot have size 0. | 126 // specialization for N=0) because embedded arrays cannot have size 0. |
| 280 template<typename T, intptr_t N> | 127 template<typename T, intptr_t N> |
| 281 class EmbeddedArray { | 128 class EmbeddedArray { |
| 282 public: | 129 public: |
| 283 EmbeddedArray() { | 130 EmbeddedArray() { |
| 284 for (intptr_t i = 0; i < N; i++) elements_[i] = NULL; | 131 for (intptr_t i = 0; i < N; i++) elements_[i] = NULL; |
| 285 } | 132 } |
| 286 | 133 |
| 287 intptr_t length() const { return N; } | 134 intptr_t length() const { return N; } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 319 return sentinel; | 166 return sentinel; |
| 320 } | 167 } |
| 321 T& operator[](intptr_t i) { | 168 T& operator[](intptr_t i) { |
| 322 UNREACHABLE(); | 169 UNREACHABLE(); |
| 323 static T sentinel = 0; | 170 static T sentinel = 0; |
| 324 return sentinel; | 171 return sentinel; |
| 325 } | 172 } |
| 326 }; | 173 }; |
| 327 | 174 |
| 328 | 175 |
| 176 // Instructions. |
| 177 |
| 178 // M is a single argument macro. It is applied to each concrete instruction |
| 179 // type name. The concrete instruction classes are the name with Instr |
| 180 // concatenated. |
| 181 #define FOR_EACH_INSTRUCTION(M) \ |
| 182 M(GraphEntry) \ |
| 183 M(JoinEntry) \ |
| 184 M(TargetEntry) \ |
| 185 M(Phi) \ |
| 186 M(Bind) \ |
| 187 M(Parameter) \ |
| 188 M(ParallelMove) \ |
| 189 M(PushArgument) \ |
| 190 M(Return) \ |
| 191 M(Throw) \ |
| 192 M(ReThrow) \ |
| 193 M(Goto) \ |
| 194 M(Branch) \ |
| 195 |
| 196 |
| 197 #define FORWARD_DECLARATION(type) class type##Instr; |
| 198 FOR_EACH_INSTRUCTION(FORWARD_DECLARATION) |
| 199 #undef FORWARD_DECLARATION |
| 200 |
| 201 |
| 202 // Functions required in all concrete instruction classes. |
| 203 #define DECLARE_INSTRUCTION(type) \ |
| 204 virtual void Accept(FlowGraphVisitor* visitor); \ |
| 205 virtual bool Is##type() const { return true; } \ |
| 206 virtual type##Instr* As##type() { return this; } \ |
| 207 virtual const char* DebugName() const { return #type; } \ |
| 208 virtual void PrintTo(BufferFormatter* f) const; \ |
| 209 virtual void PrintToVisualizer(BufferFormatter* f) const; |
| 210 |
| 211 |
| 212 class Instruction : public ZoneAllocated { |
| 213 public: |
| 214 Instruction() |
| 215 : lifetime_position_(-1), previous_(NULL), next_(NULL), env_(NULL) { } |
| 216 |
| 217 virtual bool IsBlockEntry() const { return false; } |
| 218 BlockEntryInstr* AsBlockEntry() { |
| 219 return IsBlockEntry() ? reinterpret_cast<BlockEntryInstr*>(this) : NULL; |
| 220 } |
| 221 virtual bool IsDefinition() const { return false; } |
| 222 virtual Definition* AsDefinition() { return NULL; } |
| 223 virtual bool IsControl() const { return false; } |
| 224 |
| 225 virtual intptr_t InputCount() const = 0; |
| 226 virtual Value* InputAt(intptr_t i) const = 0; |
| 227 virtual void SetInputAt(intptr_t i, Value* value) = 0; |
| 228 |
| 229 // Call instructions override this function and return the |
| 230 // number of pushed arguments. |
| 231 virtual intptr_t ArgumentCount() const = 0; |
| 232 |
| 233 // Returns true, if this instruction can deoptimize. |
| 234 virtual bool CanDeoptimize() const = 0; |
| 235 |
| 236 // Visiting support. |
| 237 virtual void Accept(FlowGraphVisitor* visitor) = 0; |
| 238 |
| 239 Instruction* previous() const { return previous_; } |
| 240 void set_previous(Instruction* instr) { |
| 241 ASSERT(!IsBlockEntry()); |
| 242 previous_ = instr; |
| 243 } |
| 244 |
| 245 Instruction* next() const { return next_; } |
| 246 void set_next(Instruction* instr) { |
| 247 ASSERT(!IsGraphEntry()); |
| 248 ASSERT(!IsReturn()); |
| 249 ASSERT(!IsControl()); |
| 250 ASSERT(!IsPhi()); |
| 251 ASSERT(instr == NULL || !instr->IsBlockEntry()); |
| 252 // TODO(fschneider): Also add Throw and ReThrow to the list of instructions |
| 253 // that do not have a successor. Currently, the graph builder will continue |
| 254 // to append instruction in case of a Throw inside an expression. This |
| 255 // condition should be handled in the graph builder |
| 256 next_ = instr; |
| 257 } |
| 258 |
| 259 // Removed this instruction from the graph. |
| 260 Instruction* RemoveFromGraph(bool return_previous = true); |
| 261 |
| 262 // Normal instructions can have 0 (inside a block) or 1 (last instruction in |
| 263 // a block) successors. Branch instruction with >1 successors override this |
| 264 // function. |
| 265 virtual intptr_t SuccessorCount() const; |
| 266 virtual BlockEntryInstr* SuccessorAt(intptr_t index) const; |
| 267 |
| 268 void Goto(JoinEntryInstr* entry); |
| 269 |
| 270 // Discover basic-block structure by performing a recursive depth first |
| 271 // traversal of the instruction graph reachable from this instruction. As |
| 272 // a side effect, the block entry instructions in the graph are assigned |
| 273 // numbers in both preorder and postorder. The array 'preorder' maps |
| 274 // preorder block numbers to the block entry instruction with that number |
| 275 // and analogously for the array 'postorder'. The depth first spanning |
| 276 // tree is recorded in the array 'parent', which maps preorder block |
| 277 // numbers to the preorder number of the block's spanning-tree parent. |
| 278 // The array 'assigned_vars' maps preorder block numbers to the set of |
| 279 // assigned frame-allocated local variables in the block. As a side |
| 280 // effect of this function, the set of basic block predecessors (e.g., |
| 281 // block entry instructions of predecessor blocks) and also the last |
| 282 // instruction in the block is recorded in each entry instruction. |
| 283 virtual void DiscoverBlocks( |
| 284 BlockEntryInstr* current_block, |
| 285 GrowableArray<BlockEntryInstr*>* preorder, |
| 286 GrowableArray<BlockEntryInstr*>* postorder, |
| 287 GrowableArray<intptr_t>* parent, |
| 288 GrowableArray<BitVector*>* assigned_vars, |
| 289 intptr_t variable_count, |
| 290 intptr_t fixed_parameter_count) { |
| 291 // Never called for instructions except block entries and branches. |
| 292 UNREACHABLE(); |
| 293 } |
| 294 |
| 295 // Mutate assigned_vars to add the local variable index for all |
| 296 // frame-allocated locals assigned to by the instruction. |
| 297 virtual void RecordAssignedVars(BitVector* assigned_vars, |
| 298 intptr_t fixed_parameter_count); |
| 299 |
| 300 // Printing support. |
| 301 virtual void PrintTo(BufferFormatter* f) const = 0; |
| 302 virtual void PrintToVisualizer(BufferFormatter* f) const = 0; |
| 303 |
| 304 #define INSTRUCTION_TYPE_CHECK(type) \ |
| 305 virtual bool Is##type() const { return false; } \ |
| 306 virtual type##Instr* As##type() { return NULL; } |
| 307 FOR_EACH_INSTRUCTION(INSTRUCTION_TYPE_CHECK) |
| 308 #undef INSTRUCTION_TYPE_CHECK |
| 309 |
| 310 // Returns structure describing location constraints required |
| 311 // to emit native code for this instruction. |
| 312 virtual LocationSummary* locs() { |
| 313 // TODO(vegorov): This should be pure virtual method. |
| 314 // However we are temporary using NULL for instructions that |
| 315 // were not converted to the location based code generation yet. |
| 316 return NULL; |
| 317 } |
| 318 |
| 319 virtual void EmitNativeCode(FlowGraphCompiler* compiler) { |
| 320 UNIMPLEMENTED(); |
| 321 } |
| 322 |
| 323 Environment* env() const { return env_; } |
| 324 void set_env(Environment* env) { env_ = env; } |
| 325 |
| 326 intptr_t lifetime_position() const { return lifetime_position_; } |
| 327 void set_lifetime_position(intptr_t pos) { |
| 328 lifetime_position_ = pos; |
| 329 } |
| 330 |
| 331 // Returns representation expected for the input operand at the given index. |
| 332 virtual Representation RequiredInputRepresentation(intptr_t idx) const { |
| 333 return kTagged; |
| 334 } |
| 335 |
| 336 // Representation of the value produced by this computation. |
| 337 virtual Representation representation() const { |
| 338 return kTagged; |
| 339 } |
| 340 |
| 341 bool WasEliminated() const { |
| 342 return next() == NULL; |
| 343 } |
| 344 |
| 345 // Returns deoptimization id that corresponds to the deoptimization target |
| 346 // that input operands conversions inserted for this instruction can jump |
| 347 // to. |
| 348 virtual intptr_t DeoptimizationTarget() const { |
| 349 UNREACHABLE(); |
| 350 return Isolate::kNoDeoptId; |
| 351 } |
| 352 |
| 353 private: |
| 354 friend class BindInstr; // Needed for BindInstr::InsertBefore. |
| 355 |
| 356 intptr_t lifetime_position_; // Position used by register allocator. |
| 357 Instruction* previous_; |
| 358 Instruction* next_; |
| 359 Environment* env_; |
| 360 DISALLOW_COPY_AND_ASSIGN(Instruction); |
| 361 }; |
| 362 |
| 363 |
| 329 template<intptr_t N> | 364 template<intptr_t N> |
| 330 class TemplateComputation : public Computation { | 365 class TemplateInstruction: public Instruction { |
| 331 public: | 366 public: |
| 367 TemplateInstruction<N>() : locs_(NULL) { } |
| 368 |
| 332 virtual intptr_t InputCount() const { return N; } | 369 virtual intptr_t InputCount() const { return N; } |
| 333 virtual Value* InputAt(intptr_t i) const { return inputs_[i]; } | 370 virtual Value* InputAt(intptr_t i) const { return inputs_[i]; } |
| 334 virtual void SetInputAt(intptr_t i, Value* value) { | 371 virtual void SetInputAt(intptr_t i, Value* value) { |
| 335 ASSERT(value != NULL); | 372 ASSERT(value != NULL); |
| 336 inputs_[i] = value; | 373 inputs_[i] = value; |
| 337 } | 374 } |
| 338 | 375 |
| 376 virtual LocationSummary* locs() { |
| 377 if (locs_ == NULL) { |
| 378 locs_ = MakeLocationSummary(); |
| 379 } |
| 380 return locs_; |
| 381 } |
| 382 |
| 383 virtual LocationSummary* MakeLocationSummary() const = 0; |
| 384 |
| 339 protected: | 385 protected: |
| 340 EmbeddedArray<Value*, N> inputs_; | 386 EmbeddedArray<Value*, N> inputs_; |
| 341 }; | 387 |
| 342 | 388 private: |
| 343 | 389 LocationSummary* locs_; |
| 344 class Value : public ZoneAllocated { | 390 }; |
| 345 public: | 391 |
| 346 explicit Value(Definition* definition) | 392 |
| 347 : definition_(definition), | 393 class MoveOperands : public ZoneAllocated { |
| 348 next_use_(NULL), | 394 public: |
| 349 instruction_(NULL), | 395 MoveOperands(Location dest, Location src) : dest_(dest), src_(src) { } |
| 350 use_index_(-1) { } | 396 |
| 351 | 397 Location src() const { return src_; } |
| 352 Definition* definition() const { return definition_; } | 398 Location dest() const { return dest_; } |
| 353 void set_definition(Definition* definition) { definition_ = definition; } | 399 |
| 354 | 400 Location* src_slot() { return &src_; } |
| 355 Value* next_use() const { return next_use_; } | 401 Location* dest_slot() { return &dest_; } |
| 356 void set_next_use(Value* next) { next_use_ = next; } | 402 |
| 357 | 403 void set_src(const Location& value) { src_ = value; } |
| 358 Instruction* instruction() const { return instruction_; } | 404 void set_dest(const Location& value) { dest_ = value; } |
| 359 void set_instruction(Instruction* instruction) { instruction_ = instruction; } | 405 |
| 360 | 406 // The parallel move resolver marks moves as "in-progress" by clearing the |
| 361 intptr_t use_index() const { return use_index_; } | 407 // destination (but not the source). |
| 362 void set_use_index(intptr_t index) { use_index_ = index; } | 408 Location MarkPending() { |
| 363 | 409 ASSERT(!IsPending()); |
| 364 void AddToInputUseList(); | 410 Location dest = dest_; |
| 365 void AddToEnvUseList(); | 411 dest_ = Location::NoLocation(); |
| 366 | 412 return dest; |
| 367 Value* Copy() { return new Value(definition_); } | 413 } |
| 368 | 414 |
| 369 RawAbstractType* CompileType() const; | 415 void ClearPending(Location dest) { |
| 370 intptr_t ResultCid() const; | 416 ASSERT(IsPending()); |
| 371 | 417 dest_ = dest; |
| 372 void PrintTo(BufferFormatter* f) const; | 418 } |
| 373 | 419 |
| 374 const char* DebugName() const { return "Value"; } | 420 bool IsPending() const { |
| 375 | 421 ASSERT(!src_.IsInvalid() || dest_.IsInvalid()); |
| 376 // Returns true if the value represents a constant. | 422 return dest_.IsInvalid() && !src_.IsInvalid(); |
| 377 bool BindsToConstant() const; | 423 } |
| 378 | 424 |
| 379 // Returns true if the value represents the constant null. | 425 // True if this move a move from the given location. |
| 380 bool BindsToConstantNull() const; | 426 bool Blocks(Location loc) const { |
| 381 | 427 return !IsEliminated() && src_.Equals(loc); |
| 382 // Assert if BindsToConstant() is false, otherwise returns the constant value. | 428 } |
| 383 const Object& BoundConstant() const; | 429 |
| 384 | 430 // A move is redundant if it's been eliminated, if its source and |
| 385 // Reminder: The type of the constant null is the bottom type, which is more | 431 // destination are the same, or if its destination is unneeded. |
| 386 // specific than any type. | 432 bool IsRedundant() const { |
| 387 bool CompileTypeIsMoreSpecificThan(const AbstractType& dst_type) const; | 433 return IsEliminated() || dest_.IsInvalid() || src_.Equals(dest_); |
| 388 | 434 } |
| 389 // Compile time constants, Bool, Smi and Nulls do not need to update | 435 |
| 390 // the store buffer. | 436 // We clear both operands to indicate move that's been eliminated. |
| 391 bool NeedsStoreBuffer() const; | 437 void Eliminate() { src_ = dest_ = Location::NoLocation(); } |
| 392 | 438 bool IsEliminated() const { |
| 393 bool Equals(Value* other) const; | 439 ASSERT(!src_.IsInvalid() || dest_.IsInvalid()); |
| 394 | 440 return src_.IsInvalid(); |
| 395 private: | 441 } |
| 396 Definition* definition_; | 442 |
| 397 Value* next_use_; | 443 private: |
| 398 Instruction* instruction_; | 444 Location dest_; |
| 399 intptr_t use_index_; | 445 Location src_; |
| 400 | 446 |
| 401 DISALLOW_COPY_AND_ASSIGN(Value); | 447 DISALLOW_COPY_AND_ASSIGN(MoveOperands); |
| 448 }; |
| 449 |
| 450 |
| 451 class ParallelMoveInstr : public TemplateInstruction<0> { |
| 452 public: |
| 453 ParallelMoveInstr() : moves_(4) { } |
| 454 |
| 455 DECLARE_INSTRUCTION(ParallelMove) |
| 456 |
| 457 virtual intptr_t ArgumentCount() const { return 0; } |
| 458 |
| 459 virtual bool CanDeoptimize() const { return false; } |
| 460 |
| 461 MoveOperands* AddMove(Location dest, Location src) { |
| 462 MoveOperands* move = new MoveOperands(dest, src); |
| 463 moves_.Add(move); |
| 464 return move; |
| 465 } |
| 466 |
| 467 MoveOperands* MoveOperandsAt(intptr_t index) const { return moves_[index]; } |
| 468 |
| 469 void SetSrcSlotAt(intptr_t index, const Location& loc); |
| 470 void SetDestSlotAt(intptr_t index, const Location& loc); |
| 471 |
| 472 intptr_t NumMoves() const { return moves_.length(); } |
| 473 |
| 474 LocationSummary* MakeLocationSummary() const { return NULL; } |
| 475 |
| 476 void EmitNativeCode(FlowGraphCompiler* compiler) { UNREACHABLE(); } |
| 477 |
| 478 private: |
| 479 GrowableArray<MoveOperands*> moves_; // Elements cannot be null. |
| 480 |
| 481 DISALLOW_COPY_AND_ASSIGN(ParallelMoveInstr); |
| 482 }; |
| 483 |
| 484 |
| 485 // Basic block entries are administrative nodes. There is a distinguished |
| 486 // graph entry with no predecessor. Joins are the only nodes with multiple |
| 487 // predecessors. Targets are all other basic block entries. The types |
| 488 // enforce edge-split form---joins are forbidden as the successors of |
| 489 // branches. |
| 490 class BlockEntryInstr : public Instruction { |
| 491 public: |
| 492 virtual bool IsBlockEntry() const { return true; } |
| 493 |
| 494 virtual intptr_t PredecessorCount() const = 0; |
| 495 virtual BlockEntryInstr* PredecessorAt(intptr_t index) const = 0; |
| 496 virtual void AddPredecessor(BlockEntryInstr* predecessor) = 0; |
| 497 virtual void PrepareEntry(FlowGraphCompiler* compiler) = 0; |
| 498 |
| 499 intptr_t preorder_number() const { return preorder_number_; } |
| 500 void set_preorder_number(intptr_t number) { preorder_number_ = number; } |
| 501 |
| 502 intptr_t postorder_number() const { return postorder_number_; } |
| 503 void set_postorder_number(intptr_t number) { postorder_number_ = number; } |
| 504 |
| 505 intptr_t block_id() const { return block_id_; } |
| 506 void set_block_id(intptr_t value) { block_id_ = value; } |
| 507 |
| 508 void set_start_pos(intptr_t pos) { start_pos_ = pos; } |
| 509 intptr_t start_pos() const { return start_pos_; } |
| 510 void set_end_pos(intptr_t pos) { end_pos_ = pos; } |
| 511 intptr_t end_pos() const { return end_pos_; } |
| 512 |
| 513 BlockEntryInstr* dominator() const { return dominator_; } |
| 514 void set_dominator(BlockEntryInstr* instr) { dominator_ = instr; } |
| 515 |
| 516 const GrowableArray<BlockEntryInstr*>& dominated_blocks() { |
| 517 return dominated_blocks_; |
| 518 } |
| 519 |
| 520 void AddDominatedBlock(BlockEntryInstr* block) { |
| 521 dominated_blocks_.Add(block); |
| 522 } |
| 523 |
| 524 Instruction* last_instruction() const { return last_instruction_; } |
| 525 void set_last_instruction(Instruction* instr) { last_instruction_ = instr; } |
| 526 |
| 527 ParallelMoveInstr* parallel_move() const { |
| 528 return parallel_move_; |
| 529 } |
| 530 |
| 531 bool HasParallelMove() const { |
| 532 return parallel_move_ != NULL; |
| 533 } |
| 534 |
| 535 ParallelMoveInstr* GetParallelMove() { |
| 536 if (parallel_move_ == NULL) { |
| 537 parallel_move_ = new ParallelMoveInstr(); |
| 538 } |
| 539 return parallel_move_; |
| 540 } |
| 541 |
| 542 virtual void DiscoverBlocks( |
| 543 BlockEntryInstr* current_block, |
| 544 GrowableArray<BlockEntryInstr*>* preorder, |
| 545 GrowableArray<BlockEntryInstr*>* postorder, |
| 546 GrowableArray<intptr_t>* parent, |
| 547 GrowableArray<BitVector*>* assigned_vars, |
| 548 intptr_t variable_count, |
| 549 intptr_t fixed_parameter_count); |
| 550 |
| 551 virtual intptr_t InputCount() const { return 0; } |
| 552 virtual Value* InputAt(intptr_t i) const { |
| 553 UNREACHABLE(); |
| 554 return NULL; |
| 555 } |
| 556 virtual void SetInputAt(intptr_t i, Value* value) { UNREACHABLE(); } |
| 557 |
| 558 virtual intptr_t ArgumentCount() const { return 0; } |
| 559 |
| 560 virtual bool CanDeoptimize() const { return false; } |
| 561 |
| 562 intptr_t try_index() const { return try_index_; } |
| 563 |
| 564 protected: |
| 565 explicit BlockEntryInstr(intptr_t try_index) |
| 566 : try_index_(try_index), |
| 567 preorder_number_(-1), |
| 568 postorder_number_(-1), |
| 569 block_id_(-1), |
| 570 dominator_(NULL), |
| 571 dominated_blocks_(1), |
| 572 last_instruction_(NULL), |
| 573 parallel_move_(NULL) { } |
| 574 |
| 575 private: |
| 576 const intptr_t try_index_; |
| 577 intptr_t preorder_number_; |
| 578 intptr_t postorder_number_; |
| 579 // Starting and ending lifetime positions for this block. Used by |
| 580 // the linear scan register allocator. |
| 581 intptr_t block_id_; |
| 582 intptr_t start_pos_; |
| 583 intptr_t end_pos_; |
| 584 BlockEntryInstr* dominator_; // Immediate dominator, NULL for graph entry. |
| 585 // TODO(fschneider): Optimize the case of one child to save space. |
| 586 GrowableArray<BlockEntryInstr*> dominated_blocks_; |
| 587 Instruction* last_instruction_; |
| 588 |
| 589 // Parallel move that will be used by linear scan register allocator to |
| 590 // connect live ranges at the start of the block. |
| 591 ParallelMoveInstr* parallel_move_; |
| 592 |
| 593 DISALLOW_COPY_AND_ASSIGN(BlockEntryInstr); |
| 594 }; |
| 595 |
| 596 |
| 597 class ForwardInstructionIterator : public ValueObject { |
| 598 public: |
| 599 explicit ForwardInstructionIterator(BlockEntryInstr* block_entry) |
| 600 : block_entry_(block_entry), current_(block_entry) { |
| 601 ASSERT(block_entry_->last_instruction()->next() == NULL); |
| 602 Advance(); |
| 603 } |
| 604 |
| 605 void Advance() { |
| 606 ASSERT(!Done()); |
| 607 current_ = current_->next(); |
| 608 } |
| 609 |
| 610 bool Done() const { return current_ == NULL; } |
| 611 |
| 612 // Removes 'current_' from graph and sets 'current_' to previous instruction. |
| 613 void RemoveCurrentFromGraph(); |
| 614 |
| 615 Instruction* Current() const { return current_; } |
| 616 |
| 617 private: |
| 618 BlockEntryInstr* block_entry_; |
| 619 Instruction* current_; |
| 620 }; |
| 621 |
| 622 |
| 623 class BackwardInstructionIterator : public ValueObject { |
| 624 public: |
| 625 explicit BackwardInstructionIterator(BlockEntryInstr* block_entry) |
| 626 : block_entry_(block_entry), current_(block_entry->last_instruction()) { |
| 627 ASSERT(block_entry_->previous() == NULL); |
| 628 } |
| 629 |
| 630 void Advance() { |
| 631 ASSERT(!Done()); |
| 632 current_ = current_->previous(); |
| 633 } |
| 634 |
| 635 bool Done() const { return current_ == block_entry_; } |
| 636 |
| 637 Instruction* Current() const { return current_; } |
| 638 |
| 639 private: |
| 640 BlockEntryInstr* block_entry_; |
| 641 Instruction* current_; |
| 642 }; |
| 643 |
| 644 |
| 645 class GraphEntryInstr : public BlockEntryInstr { |
| 646 public: |
| 647 explicit GraphEntryInstr(TargetEntryInstr* normal_entry); |
| 648 |
| 649 DECLARE_INSTRUCTION(GraphEntry) |
| 650 |
| 651 virtual intptr_t PredecessorCount() const { return 0; } |
| 652 virtual BlockEntryInstr* PredecessorAt(intptr_t index) const { |
| 653 UNREACHABLE(); |
| 654 return NULL; |
| 655 } |
| 656 virtual void AddPredecessor(BlockEntryInstr* predecessor) { UNREACHABLE(); } |
| 657 |
| 658 virtual intptr_t SuccessorCount() const; |
| 659 virtual BlockEntryInstr* SuccessorAt(intptr_t index) const; |
| 660 |
| 661 virtual void DiscoverBlocks( |
| 662 BlockEntryInstr* current_block, |
| 663 GrowableArray<BlockEntryInstr*>* preorder, |
| 664 GrowableArray<BlockEntryInstr*>* postorder, |
| 665 GrowableArray<intptr_t>* parent, |
| 666 GrowableArray<BitVector*>* assigned_vars, |
| 667 intptr_t variable_count, |
| 668 intptr_t fixed_parameter_count); |
| 669 |
| 670 void AddCatchEntry(TargetEntryInstr* entry) { catch_entries_.Add(entry); } |
| 671 |
| 672 virtual void PrepareEntry(FlowGraphCompiler* compiler); |
| 673 |
| 674 Environment* start_env() const { return start_env_; } |
| 675 void set_start_env(Environment* env) { start_env_ = env; } |
| 676 |
| 677 Definition* constant_null() const { return constant_null_; } |
| 678 |
| 679 intptr_t spill_slot_count() const { return spill_slot_count_; } |
| 680 void set_spill_slot_count(intptr_t count) { |
| 681 ASSERT(count >= 0); |
| 682 spill_slot_count_ = count; |
| 683 } |
| 684 |
| 685 TargetEntryInstr* normal_entry() const { return normal_entry_; } |
| 686 |
| 687 private: |
| 688 TargetEntryInstr* normal_entry_; |
| 689 GrowableArray<TargetEntryInstr*> catch_entries_; |
| 690 Environment* start_env_; |
| 691 Definition* constant_null_; |
| 692 intptr_t spill_slot_count_; |
| 693 |
| 694 DISALLOW_COPY_AND_ASSIGN(GraphEntryInstr); |
| 695 }; |
| 696 |
| 697 |
| 698 class JoinEntryInstr : public BlockEntryInstr { |
| 699 public: |
| 700 explicit JoinEntryInstr(intptr_t try_index) |
| 701 : BlockEntryInstr(try_index), |
| 702 predecessors_(2), // Two is the assumed to be the common case. |
| 703 phis_(NULL), |
| 704 phi_count_(0) { } |
| 705 |
| 706 DECLARE_INSTRUCTION(JoinEntry) |
| 707 |
| 708 virtual intptr_t PredecessorCount() const { return predecessors_.length(); } |
| 709 virtual BlockEntryInstr* PredecessorAt(intptr_t index) const { |
| 710 return predecessors_[index]; |
| 711 } |
| 712 virtual void AddPredecessor(BlockEntryInstr* predecessor) { |
| 713 predecessors_.Add(predecessor); |
| 714 } |
| 715 |
| 716 // Returns -1 if pred is not in the list. |
| 717 intptr_t IndexOfPredecessor(BlockEntryInstr* pred) const; |
| 718 |
| 719 ZoneGrowableArray<PhiInstr*>* phis() const { return phis_; } |
| 720 |
| 721 virtual void PrepareEntry(FlowGraphCompiler* compiler); |
| 722 |
| 723 void InsertPhi(intptr_t var_index, intptr_t var_count); |
| 724 void RemoveDeadPhis(); |
| 725 |
| 726 intptr_t phi_count() const { return phi_count_; } |
| 727 |
| 728 private: |
| 729 GrowableArray<BlockEntryInstr*> predecessors_; |
| 730 ZoneGrowableArray<PhiInstr*>* phis_; |
| 731 intptr_t phi_count_; |
| 732 |
| 733 DISALLOW_COPY_AND_ASSIGN(JoinEntryInstr); |
| 734 }; |
| 735 |
| 736 |
| 737 class TargetEntryInstr : public BlockEntryInstr { |
| 738 public: |
| 739 explicit TargetEntryInstr(intptr_t try_index) |
| 740 : BlockEntryInstr(try_index), |
| 741 predecessor_(NULL), |
| 742 catch_try_index_(CatchClauseNode::kInvalidTryIndex) { } |
| 743 |
| 744 // Used for exception catch entries. |
| 745 TargetEntryInstr(intptr_t try_index, intptr_t catch_try_index) |
| 746 : BlockEntryInstr(try_index), |
| 747 predecessor_(NULL), |
| 748 catch_try_index_(catch_try_index) { } |
| 749 |
| 750 DECLARE_INSTRUCTION(TargetEntry) |
| 751 |
| 752 virtual intptr_t PredecessorCount() const { |
| 753 return (predecessor_ == NULL) ? 0 : 1; |
| 754 } |
| 755 virtual BlockEntryInstr* PredecessorAt(intptr_t index) const { |
| 756 ASSERT((index == 0) && (predecessor_ != NULL)); |
| 757 return predecessor_; |
| 758 } |
| 759 virtual void AddPredecessor(BlockEntryInstr* predecessor) { |
| 760 ASSERT(predecessor_ == NULL); |
| 761 predecessor_ = predecessor; |
| 762 } |
| 763 |
| 764 // Returns true if this Block is an entry of a catch handler. |
| 765 bool IsCatchEntry() const { |
| 766 return catch_try_index_ != CatchClauseNode::kInvalidTryIndex; |
| 767 } |
| 768 |
| 769 // Returns try index for the try block to which this catch handler |
| 770 // corresponds. |
| 771 intptr_t catch_try_index() const { |
| 772 ASSERT(IsCatchEntry()); |
| 773 return catch_try_index_; |
| 774 } |
| 775 |
| 776 virtual void PrepareEntry(FlowGraphCompiler* compiler); |
| 777 |
| 778 private: |
| 779 BlockEntryInstr* predecessor_; |
| 780 const intptr_t catch_try_index_; |
| 781 |
| 782 DISALLOW_COPY_AND_ASSIGN(TargetEntryInstr); |
| 783 }; |
| 784 |
| 785 |
| 786 // Abstract super-class of all instructions that define a value (Bind, Phi). |
| 787 class Definition : public Instruction { |
| 788 public: |
| 789 Definition() |
| 790 : temp_index_(-1), |
| 791 ssa_temp_index_(-1), |
| 792 propagated_type_(AbstractType::Handle()), |
| 793 propagated_cid_(kIllegalCid), |
| 794 input_use_list_(NULL), |
| 795 env_use_list_(NULL) { } |
| 796 |
| 797 virtual bool IsDefinition() const { return true; } |
| 798 virtual Definition* AsDefinition() { return this; } |
| 799 |
| 800 intptr_t temp_index() const { return temp_index_; } |
| 801 void set_temp_index(intptr_t index) { temp_index_ = index; } |
| 802 |
| 803 intptr_t ssa_temp_index() const { return ssa_temp_index_; } |
| 804 void set_ssa_temp_index(intptr_t index) { |
| 805 ASSERT(index >= 0); |
| 806 ssa_temp_index_ = index; |
| 807 } |
| 808 bool HasSSATemp() const { return ssa_temp_index_ >= 0; } |
| 809 |
| 810 // Compile time type of the definition, which may be requested before type |
| 811 // propagation during graph building. |
| 812 virtual RawAbstractType* CompileType() const = 0; |
| 813 |
| 814 bool HasPropagatedType() const { |
| 815 return !propagated_type_.IsNull(); |
| 816 } |
| 817 RawAbstractType* PropagatedType() const { |
| 818 ASSERT(HasPropagatedType()); |
| 819 return propagated_type_.raw(); |
| 820 } |
| 821 // Returns true if the propagated type has changed. |
| 822 bool SetPropagatedType(const AbstractType& propagated_type) { |
| 823 if (propagated_type.IsNull()) { |
| 824 // Not a typed definition, e.g. access to a VM field. |
| 825 return false; |
| 826 } |
| 827 const bool changed = |
| 828 propagated_type_.IsNull() || !propagated_type.Equals(propagated_type_); |
| 829 propagated_type_ = propagated_type.raw(); |
| 830 return changed; |
| 831 } |
| 832 |
| 833 bool has_propagated_cid() const { return propagated_cid_ != kIllegalCid; } |
| 834 intptr_t propagated_cid() const { return propagated_cid_; } |
| 835 // May compute and set propagated cid. |
| 836 virtual intptr_t GetPropagatedCid() = 0; |
| 837 |
| 838 // Returns true if the propagated cid has changed. |
| 839 bool SetPropagatedCid(intptr_t cid); |
| 840 |
| 841 Value* input_use_list() { return input_use_list_; } |
| 842 void set_input_use_list(Value* head) { input_use_list_ = head; } |
| 843 |
| 844 Value* env_use_list() { return env_use_list_; } |
| 845 void set_env_use_list(Value* head) { env_use_list_ = head; } |
| 846 |
| 847 // Replace uses of this definition with uses of other definition or value. |
| 848 // Precondition: use lists must be properly calculated. |
| 849 // Postcondition: use lists and use values are still valid. |
| 850 void ReplaceUsesWith(Definition* other); |
| 851 |
| 852 private: |
| 853 intptr_t temp_index_; |
| 854 intptr_t ssa_temp_index_; |
| 855 // TODO(regis): GrowableArray<const AbstractType*> propagated_types_; |
| 856 // For now: |
| 857 AbstractType& propagated_type_; |
| 858 intptr_t propagated_cid_; |
| 859 Value* input_use_list_; |
| 860 Value* env_use_list_; |
| 861 |
| 862 DISALLOW_COPY_AND_ASSIGN(Definition); |
| 863 }; |
| 864 |
| 865 |
| 866 class BindInstr : public Definition { |
| 867 public: |
| 868 enum UseKind { kUnused, kUsed }; |
| 869 |
| 870 BindInstr(UseKind used, Computation* computation) |
| 871 : computation_(computation), is_used_(used != kUnused) { |
| 872 ASSERT(computation != NULL); |
| 873 } |
| 874 |
| 875 DECLARE_INSTRUCTION(Bind) |
| 876 |
| 877 virtual intptr_t ArgumentCount() const; |
| 878 intptr_t InputCount() const; |
| 879 Value* InputAt(intptr_t i) const; |
| 880 void SetInputAt(intptr_t i, Value* value); |
| 881 virtual bool CanDeoptimize() const; |
| 882 |
| 883 Computation* computation() const { return computation_; } |
| 884 void set_computation(Computation* value) { computation_ = value; } |
| 885 bool is_used() const { return is_used_; } |
| 886 |
| 887 virtual RawAbstractType* CompileType() const; |
| 888 virtual intptr_t GetPropagatedCid(); |
| 889 |
| 890 virtual void RecordAssignedVars(BitVector* assigned_vars, |
| 891 intptr_t fixed_parameter_count); |
| 892 |
| 893 intptr_t Hashcode() const; |
| 894 bool Equals(BindInstr* other) const; |
| 895 virtual LocationSummary* locs(); |
| 896 virtual void EmitNativeCode(FlowGraphCompiler* compiler); |
| 897 |
| 898 // Insert this instruction before 'next'. |
| 899 void InsertBefore(Instruction* next); |
| 900 |
| 901 // Insert this instruction after 'prev'. |
| 902 void InsertAfter(Instruction* prev); |
| 903 |
| 904 virtual Representation RequiredInputRepresentation(intptr_t i) const; |
| 905 virtual Representation representation() const; |
| 906 virtual intptr_t DeoptimizationTarget() const; |
| 907 |
| 908 private: |
| 909 Computation* computation_; |
| 910 const bool is_used_; |
| 911 |
| 912 DISALLOW_COPY_AND_ASSIGN(BindInstr); |
| 913 }; |
| 914 |
| 915 |
| 916 class PhiInstr : public Definition { |
| 917 public: |
| 918 explicit PhiInstr(JoinEntryInstr* block, intptr_t num_inputs) |
| 919 : block_(block), |
| 920 inputs_(num_inputs), |
| 921 is_alive_(false), |
| 922 representation_(kTagged) { |
| 923 for (intptr_t i = 0; i < num_inputs; ++i) { |
| 924 inputs_.Add(NULL); |
| 925 } |
| 926 } |
| 927 |
| 928 JoinEntryInstr* block() const { return block_; } |
| 929 |
| 930 virtual RawAbstractType* CompileType() const; |
| 931 virtual intptr_t GetPropagatedCid() { return propagated_cid(); } |
| 932 |
| 933 virtual intptr_t ArgumentCount() const { return 0; } |
| 934 |
| 935 intptr_t InputCount() const { return inputs_.length(); } |
| 936 |
| 937 Value* InputAt(intptr_t i) const { return inputs_[i]; } |
| 938 |
| 939 void SetInputAt(intptr_t i, Value* value) { inputs_[i] = value; } |
| 940 |
| 941 virtual bool CanDeoptimize() const { return false; } |
| 942 |
| 943 // TODO(regis): This helper will be removed once we support type sets. |
| 944 RawAbstractType* LeastSpecificInputType() const; |
| 945 |
| 946 // Phi is alive if it reaches a non-environment use. |
| 947 bool is_alive() const { return is_alive_; } |
| 948 void mark_alive() { is_alive_ = true; } |
| 949 |
| 950 virtual Representation RequiredInputRepresentation(intptr_t i) const { |
| 951 return representation_; |
| 952 } |
| 953 |
| 954 virtual Representation representation() const { |
| 955 return representation_; |
| 956 } |
| 957 |
| 958 virtual void set_representation(Representation r) { |
| 959 representation_ = r; |
| 960 } |
| 961 |
| 962 DECLARE_INSTRUCTION(Phi) |
| 963 |
| 964 private: |
| 965 JoinEntryInstr* block_; |
| 966 GrowableArray<Value*> inputs_; |
| 967 bool is_alive_; |
| 968 Representation representation_; |
| 969 |
| 970 DISALLOW_COPY_AND_ASSIGN(PhiInstr); |
| 971 }; |
| 972 |
| 973 |
| 974 class ParameterInstr : public Definition { |
| 975 public: |
| 976 explicit ParameterInstr(intptr_t index) : index_(index) { } |
| 977 |
| 978 DECLARE_INSTRUCTION(Parameter) |
| 979 |
| 980 intptr_t index() const { return index_; } |
| 981 |
| 982 // Compile type of the passed-in parameter. |
| 983 virtual RawAbstractType* CompileType() const; |
| 984 // No known propagated cid for parameters. |
| 985 virtual intptr_t GetPropagatedCid() { return propagated_cid(); } |
| 986 |
| 987 virtual intptr_t ArgumentCount() const { return 0; } |
| 988 |
| 989 intptr_t InputCount() const { return 0; } |
| 990 Value* InputAt(intptr_t i) const { |
| 991 UNREACHABLE(); |
| 992 return NULL; |
| 993 } |
| 994 void SetInputAt(intptr_t i, Value* value) { UNREACHABLE(); } |
| 995 |
| 996 virtual bool CanDeoptimize() const { return false; } |
| 997 |
| 998 private: |
| 999 const intptr_t index_; |
| 1000 |
| 1001 DISALLOW_COPY_AND_ASSIGN(ParameterInstr); |
| 1002 }; |
| 1003 |
| 1004 |
| 1005 class PushArgumentInstr : public Definition { |
| 1006 public: |
| 1007 explicit PushArgumentInstr(Value* value) : value_(value), locs_(NULL) { |
| 1008 ASSERT(value != NULL); |
| 1009 } |
| 1010 |
| 1011 DECLARE_INSTRUCTION(PushArgument) |
| 1012 |
| 1013 intptr_t InputCount() const { return 1; } |
| 1014 Value* InputAt(intptr_t i) const { |
| 1015 ASSERT(i == 0); |
| 1016 return value_; |
| 1017 } |
| 1018 void SetInputAt(intptr_t i, Value* value) { |
| 1019 ASSERT(i == 0); |
| 1020 value_ = value; |
| 1021 } |
| 1022 |
| 1023 virtual intptr_t ArgumentCount() const { return 0; } |
| 1024 |
| 1025 virtual RawAbstractType* CompileType() const; |
| 1026 virtual intptr_t GetPropagatedCid() { return propagated_cid(); } |
| 1027 |
| 1028 Value* value() const { return value_; } |
| 1029 |
| 1030 virtual LocationSummary* locs() { |
| 1031 if (locs_ == NULL) { |
| 1032 locs_ = MakeLocationSummary(); |
| 1033 } |
| 1034 return locs_; |
| 1035 } |
| 1036 |
| 1037 LocationSummary* MakeLocationSummary() const; |
| 1038 |
| 1039 virtual void EmitNativeCode(FlowGraphCompiler* compiler); |
| 1040 |
| 1041 virtual bool CanDeoptimize() const { return false; } |
| 1042 |
| 1043 private: |
| 1044 Value* value_; |
| 1045 LocationSummary* locs_; |
| 1046 |
| 1047 DISALLOW_COPY_AND_ASSIGN(PushArgumentInstr); |
| 1048 }; |
| 1049 |
| 1050 |
| 1051 class ReturnInstr : public TemplateInstruction<1> { |
| 1052 public: |
| 1053 ReturnInstr(intptr_t token_pos, Value* value) |
| 1054 : deopt_id_(Isolate::Current()->GetNextDeoptId()), |
| 1055 token_pos_(token_pos) { |
| 1056 ASSERT(value != NULL); |
| 1057 inputs_[0] = value; |
| 1058 } |
| 1059 |
| 1060 DECLARE_INSTRUCTION(Return) |
| 1061 |
| 1062 virtual intptr_t ArgumentCount() const { return 0; } |
| 1063 |
| 1064 intptr_t deopt_id() const { return deopt_id_; } |
| 1065 intptr_t token_pos() const { return token_pos_; } |
| 1066 Value* value() const { return inputs_[0]; } |
| 1067 |
| 1068 virtual LocationSummary* MakeLocationSummary() const; |
| 1069 |
| 1070 virtual void EmitNativeCode(FlowGraphCompiler* compiler); |
| 1071 |
| 1072 virtual bool CanDeoptimize() const { return false; } |
| 1073 |
| 1074 private: |
| 1075 const intptr_t deopt_id_; |
| 1076 const intptr_t token_pos_; |
| 1077 |
| 1078 DISALLOW_COPY_AND_ASSIGN(ReturnInstr); |
| 1079 }; |
| 1080 |
| 1081 |
| 1082 class ThrowInstr : public TemplateInstruction<0> { |
| 1083 public: |
| 1084 explicit ThrowInstr(intptr_t token_pos) : token_pos_(token_pos) { } |
| 1085 |
| 1086 DECLARE_INSTRUCTION(Throw) |
| 1087 |
| 1088 virtual intptr_t ArgumentCount() const { return 1; } |
| 1089 |
| 1090 intptr_t token_pos() const { return token_pos_; } |
| 1091 |
| 1092 virtual LocationSummary* MakeLocationSummary() const; |
| 1093 |
| 1094 virtual void EmitNativeCode(FlowGraphCompiler* compiler); |
| 1095 |
| 1096 virtual bool CanDeoptimize() const { return false; } |
| 1097 |
| 1098 private: |
| 1099 const intptr_t token_pos_; |
| 1100 |
| 1101 DISALLOW_COPY_AND_ASSIGN(ThrowInstr); |
| 1102 }; |
| 1103 |
| 1104 |
| 1105 class ReThrowInstr : public TemplateInstruction<0> { |
| 1106 public: |
| 1107 explicit ReThrowInstr(intptr_t token_pos) : token_pos_(token_pos) { } |
| 1108 |
| 1109 DECLARE_INSTRUCTION(ReThrow) |
| 1110 |
| 1111 virtual intptr_t ArgumentCount() const { return 2; } |
| 1112 |
| 1113 intptr_t token_pos() const { return token_pos_; } |
| 1114 |
| 1115 virtual LocationSummary* MakeLocationSummary() const; |
| 1116 |
| 1117 virtual void EmitNativeCode(FlowGraphCompiler* compiler); |
| 1118 |
| 1119 virtual bool CanDeoptimize() const { return false; } |
| 1120 |
| 1121 private: |
| 1122 const intptr_t token_pos_; |
| 1123 |
| 1124 DISALLOW_COPY_AND_ASSIGN(ReThrowInstr); |
| 1125 }; |
| 1126 |
| 1127 |
| 1128 class GotoInstr : public TemplateInstruction<0> { |
| 1129 public: |
| 1130 explicit GotoInstr(JoinEntryInstr* entry) |
| 1131 : successor_(entry), |
| 1132 parallel_move_(NULL) { } |
| 1133 |
| 1134 DECLARE_INSTRUCTION(Goto) |
| 1135 |
| 1136 virtual intptr_t ArgumentCount() const { return 0; } |
| 1137 |
| 1138 JoinEntryInstr* successor() const { return successor_; } |
| 1139 void set_successor(JoinEntryInstr* successor) { successor_ = successor; } |
| 1140 virtual intptr_t SuccessorCount() const; |
| 1141 virtual BlockEntryInstr* SuccessorAt(intptr_t index) const; |
| 1142 |
| 1143 virtual LocationSummary* MakeLocationSummary() const; |
| 1144 |
| 1145 virtual void EmitNativeCode(FlowGraphCompiler* compiler); |
| 1146 |
| 1147 virtual bool CanDeoptimize() const { return false; } |
| 1148 |
| 1149 ParallelMoveInstr* parallel_move() const { |
| 1150 return parallel_move_; |
| 1151 } |
| 1152 |
| 1153 bool HasParallelMove() const { |
| 1154 return parallel_move_ != NULL; |
| 1155 } |
| 1156 |
| 1157 ParallelMoveInstr* GetParallelMove() { |
| 1158 if (parallel_move_ == NULL) { |
| 1159 parallel_move_ = new ParallelMoveInstr(); |
| 1160 } |
| 1161 return parallel_move_; |
| 1162 } |
| 1163 |
| 1164 private: |
| 1165 JoinEntryInstr* successor_; |
| 1166 |
| 1167 // Parallel move that will be used by linear scan register allocator to |
| 1168 // connect live ranges at the end of the block and resolve phis. |
| 1169 ParallelMoveInstr* parallel_move_; |
| 1170 }; |
| 1171 |
| 1172 |
| 1173 class ControlInstruction : public Instruction { |
| 1174 public: |
| 1175 ControlInstruction() : true_successor_(NULL), false_successor_(NULL) { } |
| 1176 |
| 1177 virtual bool IsControl() const { return true; } |
| 1178 |
| 1179 TargetEntryInstr* true_successor() const { return true_successor_; } |
| 1180 TargetEntryInstr* false_successor() const { return false_successor_; } |
| 1181 |
| 1182 TargetEntryInstr** true_successor_address() { return &true_successor_; } |
| 1183 TargetEntryInstr** false_successor_address() { return &false_successor_; } |
| 1184 |
| 1185 virtual intptr_t SuccessorCount() const; |
| 1186 virtual BlockEntryInstr* SuccessorAt(intptr_t index) const; |
| 1187 |
| 1188 virtual void DiscoverBlocks( |
| 1189 BlockEntryInstr* current_block, |
| 1190 GrowableArray<BlockEntryInstr*>* preorder, |
| 1191 GrowableArray<BlockEntryInstr*>* postorder, |
| 1192 GrowableArray<intptr_t>* parent, |
| 1193 GrowableArray<BitVector*>* assigned_vars, |
| 1194 intptr_t variable_count, |
| 1195 intptr_t fixed_parameter_count); |
| 1196 |
| 1197 |
| 1198 void EmitBranchOnCondition(FlowGraphCompiler* compiler, |
| 1199 Condition true_condition); |
| 1200 |
| 1201 private: |
| 1202 TargetEntryInstr* true_successor_; |
| 1203 TargetEntryInstr* false_successor_; |
| 1204 |
| 1205 DISALLOW_COPY_AND_ASSIGN(ControlInstruction); |
| 1206 }; |
| 1207 |
| 1208 |
| 1209 class BranchInstr : public ControlInstruction { |
| 1210 public: |
| 1211 explicit BranchInstr(ComparisonComp* computation) |
| 1212 : computation_(computation), locs_(NULL) { } |
| 1213 |
| 1214 DECLARE_INSTRUCTION(Branch) |
| 1215 |
| 1216 virtual intptr_t ArgumentCount() const; |
| 1217 intptr_t InputCount() const; |
| 1218 Value* InputAt(intptr_t i) const; |
| 1219 void SetInputAt(intptr_t i, Value* value); |
| 1220 virtual bool CanDeoptimize() const; |
| 1221 |
| 1222 ComparisonComp* computation() const { return computation_; } |
| 1223 void set_computation(ComparisonComp* value) { computation_ = value; } |
| 1224 |
| 1225 virtual void EmitNativeCode(FlowGraphCompiler* compiler); |
| 1226 |
| 1227 virtual LocationSummary* locs(); |
| 1228 virtual intptr_t DeoptimizationTarget() const; |
| 1229 virtual Representation RequiredInputRepresentation(intptr_t i) const; |
| 1230 |
| 1231 private: |
| 1232 ComparisonComp* computation_; |
| 1233 LocationSummary* locs_; |
| 1234 |
| 1235 DISALLOW_COPY_AND_ASSIGN(BranchInstr); |
| 1236 }; |
| 1237 |
| 1238 |
| 1239 #undef DECLARE_INSTRUCTION |
| 1240 |
| 1241 |
| 1242 // M is a two argument macro. It is applied to each concrete instruction's |
| 1243 // (including the values) typename and classname. |
| 1244 #define FOR_EACH_COMPUTATION(M) \ |
| 1245 M(AssertAssignable, AssertAssignableComp) \ |
| 1246 M(AssertBoolean, AssertBooleanComp) \ |
| 1247 M(ArgumentDefinitionTest, ArgumentDefinitionTestComp) \ |
| 1248 M(CurrentContext, CurrentContextComp) \ |
| 1249 M(StoreContext, StoreContextComp) \ |
| 1250 M(ClosureCall, ClosureCallComp) \ |
| 1251 M(InstanceCall, InstanceCallComp) \ |
| 1252 M(PolymorphicInstanceCall, PolymorphicInstanceCallComp) \ |
| 1253 M(StaticCall, StaticCallComp) \ |
| 1254 M(LoadLocal, LoadLocalComp) \ |
| 1255 M(StoreLocal, StoreLocalComp) \ |
| 1256 M(StrictCompare, StrictCompareComp) \ |
| 1257 M(EqualityCompare, EqualityCompareComp) \ |
| 1258 M(RelationalOp, RelationalOpComp) \ |
| 1259 M(NativeCall, NativeCallComp) \ |
| 1260 M(LoadIndexed, LoadIndexedComp) \ |
| 1261 M(StoreIndexed, StoreIndexedComp) \ |
| 1262 M(LoadInstanceField, LoadInstanceFieldComp) \ |
| 1263 M(StoreInstanceField, StoreInstanceFieldComp) \ |
| 1264 M(LoadStaticField, LoadStaticFieldComp) \ |
| 1265 M(StoreStaticField, StoreStaticFieldComp) \ |
| 1266 M(BooleanNegate, BooleanNegateComp) \ |
| 1267 M(InstanceOf, InstanceOfComp) \ |
| 1268 M(CreateArray, CreateArrayComp) \ |
| 1269 M(CreateClosure, CreateClosureComp) \ |
| 1270 M(AllocateObject, AllocateObjectComp) \ |
| 1271 M(AllocateObjectWithBoundsCheck, AllocateObjectWithBoundsCheckComp) \ |
| 1272 M(LoadVMField, LoadVMFieldComp) \ |
| 1273 M(StoreVMField, StoreVMFieldComp) \ |
| 1274 M(InstantiateTypeArguments, InstantiateTypeArgumentsComp) \ |
| 1275 M(ExtractConstructorTypeArguments, ExtractConstructorTypeArgumentsComp) \ |
| 1276 M(ExtractConstructorInstantiator, ExtractConstructorInstantiatorComp) \ |
| 1277 M(AllocateContext, AllocateContextComp) \ |
| 1278 M(ChainContext, ChainContextComp) \ |
| 1279 M(CloneContext, CloneContextComp) \ |
| 1280 M(CatchEntry, CatchEntryComp) \ |
| 1281 M(BinarySmiOp, BinarySmiOpComp) \ |
| 1282 M(BinaryMintOp, BinaryMintOpComp) \ |
| 1283 M(BinaryDoubleOp, BinaryDoubleOpComp) \ |
| 1284 M(UnarySmiOp, UnarySmiOpComp) \ |
| 1285 M(NumberNegate, NumberNegateComp) \ |
| 1286 M(CheckStackOverflow, CheckStackOverflowComp) \ |
| 1287 M(DoubleToDouble, DoubleToDoubleComp) \ |
| 1288 M(SmiToDouble, SmiToDoubleComp) \ |
| 1289 M(CheckClass, CheckClassComp) \ |
| 1290 M(CheckSmi, CheckSmiComp) \ |
| 1291 M(Constant, ConstantComp) \ |
| 1292 M(CheckEitherNonSmi, CheckEitherNonSmiComp) \ |
| 1293 M(UnboxedDoubleBinaryOp, UnboxedDoubleBinaryOpComp) \ |
| 1294 M(UnboxDouble, UnboxDoubleComp) \ |
| 1295 M(BoxDouble, BoxDoubleComp) \ |
| 1296 M(CheckArrayBound, CheckArrayBoundComp) |
| 1297 |
| 1298 |
| 1299 #define FORWARD_DECLARATION(ShortName, ClassName) class ClassName; |
| 1300 FOR_EACH_COMPUTATION(FORWARD_DECLARATION) |
| 1301 #undef FORWARD_DECLARATION |
| 1302 |
| 1303 |
| 1304 class Computation : public ZoneAllocated { |
| 1305 public: |
| 1306 Computation() |
| 1307 : deopt_id_(Isolate::Current()->GetNextDeoptId()), locs_(NULL) { } |
| 1308 |
| 1309 // Unique id used for deoptimization. |
| 1310 virtual intptr_t deopt_id() const { |
| 1311 ASSERT(CanDeoptimize()); |
| 1312 return deopt_id_; |
| 1313 } |
| 1314 |
| 1315 // Visiting support. |
| 1316 virtual void Accept(FlowGraphVisitor* visitor, BindInstr* instr) = 0; |
| 1317 |
| 1318 virtual intptr_t InputCount() const = 0; |
| 1319 virtual Value* InputAt(intptr_t i) const = 0; |
| 1320 virtual void SetInputAt(intptr_t i, Value* value) = 0; |
| 1321 |
| 1322 // Call computations override this function and return the |
| 1323 // number of pushed arguments. |
| 1324 virtual intptr_t ArgumentCount() const = 0; |
| 1325 |
| 1326 // Returns true, if this computation can deoptimize. |
| 1327 virtual bool CanDeoptimize() const = 0; |
| 1328 |
| 1329 // Returns a replacement for the instruction that wraps this computation. |
| 1330 // Returns NULL if instr can be eliminated. |
| 1331 // By default returns instr (input parameter) which means no change. |
| 1332 virtual Definition* TryReplace(BindInstr* instr) const; |
| 1333 |
| 1334 // Compares two computations. Returns true, if: |
| 1335 // 1. They are of the same kind. |
| 1336 // 2. All input operands match. |
| 1337 // 3. All other attributes match. |
| 1338 bool Equals(Computation* other) const; |
| 1339 |
| 1340 // Returns a hash code for use with hash maps. |
| 1341 virtual intptr_t Hashcode() const; |
| 1342 |
| 1343 // Compare attributes of an computation (except input operands and kind). |
| 1344 // All computations that participate in CSE have to override this function. |
| 1345 virtual bool AttributesEqual(Computation* other) const { |
| 1346 UNREACHABLE(); |
| 1347 return false; |
| 1348 } |
| 1349 |
| 1350 // Returns true if the instruction may have side effects. |
| 1351 // TODO(fschneider): Make this abstract and implement for all computations |
| 1352 // instead of returning the safe default (true). |
| 1353 virtual bool HasSideEffect() const { return true; } |
| 1354 |
| 1355 // Compile time type of the computation, which typically depends on the |
| 1356 // compile time types (and possibly propagated types) of its inputs. |
| 1357 virtual RawAbstractType* CompileType() const = 0; |
| 1358 virtual intptr_t ResultCid() const = 0; |
| 1359 |
| 1360 // Mutate assigned_vars to add the local variable index for all |
| 1361 // frame-allocated locals assigned to by the computation. |
| 1362 virtual void RecordAssignedVars(BitVector* assigned_vars, |
| 1363 intptr_t fixed_parameter_count); |
| 1364 |
| 1365 virtual const char* DebugName() const = 0; |
| 1366 |
| 1367 // Printing support. These functions are sometimes overridden for custom |
| 1368 // formatting. Otherwise, it prints in the format "opcode(op1, op2, op3)". |
| 1369 virtual void PrintTo(BufferFormatter* f) const; |
| 1370 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 1371 |
| 1372 // Returns structure describing location constraints required |
| 1373 // to emit native code for this computation. |
| 1374 LocationSummary* locs() { |
| 1375 if (locs_ == NULL) { |
| 1376 locs_ = MakeLocationSummary(); |
| 1377 } |
| 1378 return locs_; |
| 1379 } |
| 1380 |
| 1381 virtual ComparisonComp* AsComparison() { return NULL; } |
| 1382 |
| 1383 // Create a location summary for this computation. |
| 1384 // TODO(fschneider): Temporarily returns NULL for instructions |
| 1385 // that are not yet converted to the location based code generation. |
| 1386 virtual LocationSummary* MakeLocationSummary() const = 0; |
| 1387 |
| 1388 // TODO(fschneider): Make EmitNativeCode and locs const. |
| 1389 virtual void EmitNativeCode(FlowGraphCompiler* compiler) = 0; |
| 1390 |
| 1391 virtual void EmitBranchCode(FlowGraphCompiler* compiler, |
| 1392 BranchInstr* branch) { |
| 1393 UNREACHABLE(); |
| 1394 } |
| 1395 |
| 1396 static LocationSummary* MakeCallSummary(); |
| 1397 |
| 1398 // Declare an enum value used to define kind-test predicates. |
| 1399 enum ComputationKind { |
| 1400 #define DECLARE_COMPUTATION_KIND(ShortName, ClassName) k##ShortName, |
| 1401 |
| 1402 FOR_EACH_COMPUTATION(DECLARE_COMPUTATION_KIND) |
| 1403 |
| 1404 #undef DECLARE_COMPUTATION_KIND |
| 1405 }; |
| 1406 |
| 1407 virtual ComputationKind computation_kind() const = 0; |
| 1408 |
| 1409 // Returns representation expected for the input operand at the given index. |
| 1410 virtual Representation RequiredInputRepresentation(intptr_t idx) const { |
| 1411 return kTagged; |
| 1412 } |
| 1413 |
| 1414 // Representation of the value produced by this computation. |
| 1415 virtual Representation representation() const { |
| 1416 return kTagged; |
| 1417 } |
| 1418 |
| 1419 // Returns deoptimization id that corresponds to the deoptimization target |
| 1420 // that input operands conversions inserted for this instruction can jump |
| 1421 // to. Can return kNoDeoptId. |
| 1422 virtual intptr_t DeoptimizationTarget() const { |
| 1423 UNREACHABLE(); |
| 1424 return Isolate::kNoDeoptId; |
| 1425 } |
| 1426 |
| 1427 // Declare predicate for each computation. |
| 1428 #define DECLARE_PREDICATE(ShortName, ClassName) \ |
| 1429 inline bool Is##ShortName() const; \ |
| 1430 inline const ClassName* As##ShortName() const; \ |
| 1431 inline ClassName* As##ShortName(); |
| 1432 FOR_EACH_COMPUTATION(DECLARE_PREDICATE) |
| 1433 #undef DECLARE_PREDICATE |
| 1434 |
| 1435 protected: |
| 1436 // Fetch deopt id without checking if this computation can deoptimize. |
| 1437 intptr_t GetDeoptId() const { |
| 1438 return deopt_id_; |
| 1439 } |
| 1440 |
| 1441 private: |
| 1442 friend class BranchInstr; |
| 1443 |
| 1444 intptr_t deopt_id_; |
| 1445 LocationSummary* locs_; |
| 1446 |
| 1447 DISALLOW_COPY_AND_ASSIGN(Computation); |
| 1448 }; |
| 1449 |
| 1450 |
| 1451 // Inlined functions from class BindInstr that forward to their computation. |
| 1452 inline intptr_t BindInstr::ArgumentCount() const { |
| 1453 return computation()->ArgumentCount(); |
| 1454 } |
| 1455 |
| 1456 |
| 1457 inline intptr_t BindInstr::InputCount() const { |
| 1458 return computation()->InputCount(); |
| 1459 } |
| 1460 |
| 1461 |
| 1462 inline Value* BindInstr::InputAt(intptr_t i) const { |
| 1463 return computation()->InputAt(i); |
| 1464 } |
| 1465 |
| 1466 |
| 1467 inline void BindInstr::SetInputAt(intptr_t i, Value* value) { |
| 1468 computation()->SetInputAt(i, value); |
| 1469 } |
| 1470 |
| 1471 inline bool BindInstr::CanDeoptimize() const { |
| 1472 return computation()->CanDeoptimize(); |
| 1473 } |
| 1474 |
| 1475 |
| 1476 inline intptr_t BindInstr::Hashcode() const { |
| 1477 return computation()->Hashcode(); |
| 1478 } |
| 1479 |
| 1480 |
| 1481 inline bool BindInstr::Equals(BindInstr* other) const { |
| 1482 return computation()->Equals(other->computation()); |
| 1483 } |
| 1484 |
| 1485 |
| 1486 inline LocationSummary* BindInstr::locs() { |
| 1487 return computation()->locs(); |
| 1488 } |
| 1489 |
| 1490 |
| 1491 inline Representation BindInstr::RequiredInputRepresentation(intptr_t i) const { |
| 1492 return computation()->RequiredInputRepresentation(i); |
| 1493 } |
| 1494 |
| 1495 |
| 1496 inline Representation BindInstr::representation() const { |
| 1497 return computation()->representation(); |
| 1498 } |
| 1499 |
| 1500 |
| 1501 inline intptr_t BindInstr::DeoptimizationTarget() const { |
| 1502 return computation()->DeoptimizationTarget(); |
| 1503 } |
| 1504 |
| 1505 |
| 1506 template<intptr_t N> |
| 1507 class TemplateComputation : public Computation { |
| 1508 public: |
| 1509 virtual intptr_t InputCount() const { return N; } |
| 1510 virtual Value* InputAt(intptr_t i) const { return inputs_[i]; } |
| 1511 virtual void SetInputAt(intptr_t i, Value* value) { |
| 1512 ASSERT(value != NULL); |
| 1513 inputs_[i] = value; |
| 1514 } |
| 1515 |
| 1516 protected: |
| 1517 EmbeddedArray<Value*, N> inputs_; |
| 402 }; | 1518 }; |
| 403 | 1519 |
| 404 | 1520 |
| 405 // Functions defined in all concrete computation classes. | 1521 // Functions defined in all concrete computation classes. |
| 406 #define DECLARE_COMPUTATION(ShortName) \ | 1522 #define DECLARE_COMPUTATION(ShortName) \ |
| 407 virtual void Accept(FlowGraphVisitor* visitor, BindInstr* instr); \ | 1523 virtual void Accept(FlowGraphVisitor* visitor, BindInstr* instr); \ |
| 408 virtual ComputationKind computation_kind() const { \ | 1524 virtual ComputationKind computation_kind() const { \ |
| 409 return Computation::k##ShortName; \ | 1525 return Computation::k##ShortName; \ |
| 410 } \ | 1526 } \ |
| 411 virtual intptr_t ArgumentCount() const { return 0; } \ | 1527 virtual intptr_t ArgumentCount() const { return 0; } \ |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 485 bool is_eliminated() const { | 1601 bool is_eliminated() const { |
| 486 return is_eliminated_; | 1602 return is_eliminated_; |
| 487 } | 1603 } |
| 488 void eliminate() { | 1604 void eliminate() { |
| 489 ASSERT(!is_eliminated_); | 1605 ASSERT(!is_eliminated_); |
| 490 is_eliminated_ = true; | 1606 is_eliminated_ = true; |
| 491 } | 1607 } |
| 492 | 1608 |
| 493 virtual void PrintOperandsTo(BufferFormatter* f) const; | 1609 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 494 | 1610 |
| 495 virtual bool CanDeoptimize() const { return false; } | |
| 496 virtual intptr_t ResultCid() const { return kDynamicCid; } | |
| 497 | |
| 498 private: | |
| 499 const intptr_t token_pos_; | |
| 500 const AbstractType& dst_type_; | |
| 501 const String& dst_name_; | |
| 502 bool is_eliminated_; | |
| 503 | |
| 504 DISALLOW_COPY_AND_ASSIGN(AssertAssignableComp); | |
| 505 }; | |
| 506 | |
| 507 | |
| 508 class AssertBooleanComp : public TemplateComputation<1> { | |
| 509 public: | |
| 510 AssertBooleanComp(intptr_t token_pos, | |
| 511 Value* value) | |
| 512 : token_pos_(token_pos), | |
| 513 is_eliminated_(false) { | |
| 514 ASSERT(value != NULL); | |
| 515 inputs_[0] = value; | |
| 516 } | |
| 517 | |
| 518 DECLARE_COMPUTATION(AssertBoolean) | |
| 519 | |
| 520 intptr_t token_pos() const { return token_pos_; } | |
| 521 Value* value() const { return inputs_[0]; } | |
| 522 | |
| 523 bool is_eliminated() const { | |
| 524 return is_eliminated_; | |
| 525 } | |
| 526 void eliminate() { | |
| 527 ASSERT(!is_eliminated_); | |
| 528 is_eliminated_ = true; | |
| 529 } | |
| 530 | |
| 531 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 532 | |
| 533 virtual bool CanDeoptimize() const { return false; } | |
| 534 virtual intptr_t ResultCid() const { return kBoolCid; } | |
| 535 | |
| 536 private: | |
| 537 const intptr_t token_pos_; | |
| 538 bool is_eliminated_; | |
| 539 | |
| 540 DISALLOW_COPY_AND_ASSIGN(AssertBooleanComp); | |
| 541 }; | |
| 542 | |
| 543 | |
| 544 class ArgumentDefinitionTestComp : public TemplateComputation<1> { | |
| 545 public: | |
| 546 ArgumentDefinitionTestComp(ArgumentDefinitionTestNode* node, | |
| 547 Value* saved_arguments_descriptor) | |
| 548 : ast_node_(*node) { | |
| 549 ASSERT(saved_arguments_descriptor != NULL); | |
| 550 inputs_[0] = saved_arguments_descriptor; | |
| 551 } | |
| 552 | |
| 553 DECLARE_COMPUTATION(ArgumentDefinitionTest) | |
| 554 | |
| 555 intptr_t token_pos() const { return ast_node_.token_pos(); } | |
| 556 intptr_t formal_parameter_index() const { | |
| 557 return ast_node_.formal_parameter_index(); | |
| 558 } | |
| 559 const String& formal_parameter_name() const { | |
| 560 return ast_node_.formal_parameter_name(); | |
| 561 } | |
| 562 Value* saved_arguments_descriptor() const { return inputs_[0]; } | |
| 563 | |
| 564 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 565 | |
| 566 virtual bool CanDeoptimize() const { return false; } | |
| 567 virtual intptr_t ResultCid() const { return kBoolCid; } | |
| 568 | |
| 569 private: | |
| 570 const ArgumentDefinitionTestNode& ast_node_; | |
| 571 | |
| 572 DISALLOW_COPY_AND_ASSIGN(ArgumentDefinitionTestComp); | |
| 573 }; | |
| 574 | |
| 575 | |
| 576 // Denotes the current context, normally held in a register. This is | |
| 577 // a computation, not a value, because it's mutable. | |
| 578 class CurrentContextComp : public TemplateComputation<0> { | |
| 579 public: | |
| 580 CurrentContextComp() { } | |
| 581 | |
| 582 DECLARE_COMPUTATION(CurrentContext) | |
| 583 | |
| 584 virtual bool CanDeoptimize() const { return false; } | |
| 585 virtual intptr_t ResultCid() const { return kDynamicCid; } | |
| 586 | |
| 587 private: | |
| 588 DISALLOW_COPY_AND_ASSIGN(CurrentContextComp); | |
| 589 }; | |
| 590 | |
| 591 | |
| 592 class StoreContextComp : public TemplateComputation<1> { | |
| 593 public: | |
| 594 explicit StoreContextComp(Value* value) { | |
| 595 ASSERT(value != NULL); | |
| 596 inputs_[0] = value; | |
| 597 } | |
| 598 | |
| 599 DECLARE_COMPUTATION(StoreContext); | |
| 600 | |
| 601 Value* value() const { return inputs_[0]; } | |
| 602 | |
| 603 virtual bool CanDeoptimize() const { return false; } | |
| 604 virtual intptr_t ResultCid() const { return kIllegalCid; } | |
| 605 | |
| 606 private: | |
| 607 DISALLOW_COPY_AND_ASSIGN(StoreContextComp); | |
| 608 }; | |
| 609 | |
| 610 | |
| 611 class ClosureCallComp : public TemplateComputation<0> { | |
| 612 public: | |
| 613 ClosureCallComp(ClosureCallNode* node, | |
| 614 ZoneGrowableArray<PushArgumentInstr*>* arguments) | |
| 615 : ast_node_(*node), | |
| 616 arguments_(arguments) { } | |
| 617 | |
| 618 DECLARE_CALL_COMPUTATION(ClosureCall) | |
| 619 | |
| 620 const Array& argument_names() const { return ast_node_.arguments()->names(); } | |
| 621 intptr_t token_pos() const { return ast_node_.token_pos(); } | |
| 622 | |
| 623 virtual intptr_t ArgumentCount() const { return arguments_->length(); } | |
| 624 PushArgumentInstr* ArgumentAt(intptr_t index) const { | |
| 625 return (*arguments_)[index]; | |
| 626 } | |
| 627 | |
| 628 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 629 | |
| 630 virtual bool CanDeoptimize() const { return true; } | |
| 631 virtual intptr_t ResultCid() const { return kDynamicCid; } | |
| 632 | |
| 633 private: | |
| 634 const ClosureCallNode& ast_node_; | |
| 635 ZoneGrowableArray<PushArgumentInstr*>* arguments_; | |
| 636 | |
| 637 DISALLOW_COPY_AND_ASSIGN(ClosureCallComp); | |
| 638 }; | |
| 639 | |
| 640 | |
| 641 class InstanceCallComp : public TemplateComputation<0> { | |
| 642 public: | |
| 643 InstanceCallComp(intptr_t token_pos, | |
| 644 const String& function_name, | |
| 645 Token::Kind token_kind, | |
| 646 ZoneGrowableArray<PushArgumentInstr*>* arguments, | |
| 647 const Array& argument_names, | |
| 648 intptr_t checked_argument_count) | |
| 649 : ic_data_(Isolate::Current()->GetICDataForDeoptId(deopt_id())), | |
| 650 token_pos_(token_pos), | |
| 651 function_name_(function_name), | |
| 652 token_kind_(token_kind), | |
| 653 arguments_(arguments), | |
| 654 argument_names_(argument_names), | |
| 655 checked_argument_count_(checked_argument_count) { | |
| 656 ASSERT(function_name.IsZoneHandle()); | |
| 657 ASSERT(!arguments->is_empty()); | |
| 658 ASSERT(argument_names.IsZoneHandle()); | |
| 659 ASSERT(Token::IsBinaryToken(token_kind) || | |
| 660 Token::IsUnaryToken(token_kind) || | |
| 661 Token::IsIndexOperator(token_kind) || | |
| 662 token_kind == Token::kGET || | |
| 663 token_kind == Token::kSET || | |
| 664 token_kind == Token::kILLEGAL); | |
| 665 } | |
| 666 | |
| 667 DECLARE_CALL_COMPUTATION(InstanceCall) | |
| 668 | |
| 669 const ICData* ic_data() const { return ic_data_; } | |
| 670 bool HasICData() const { | |
| 671 return (ic_data() != NULL) && !ic_data()->IsNull(); | |
| 672 } | |
| 673 | |
| 674 intptr_t token_pos() const { return token_pos_; } | |
| 675 const String& function_name() const { return function_name_; } | |
| 676 Token::Kind token_kind() const { return token_kind_; } | |
| 677 virtual intptr_t ArgumentCount() const { return arguments_->length(); } | |
| 678 PushArgumentInstr* ArgumentAt(intptr_t index) const { | |
| 679 return (*arguments_)[index]; | |
| 680 } | |
| 681 const Array& argument_names() const { return argument_names_; } | |
| 682 intptr_t checked_argument_count() const { return checked_argument_count_; } | |
| 683 | |
| 684 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 685 | |
| 686 virtual bool CanDeoptimize() const { return true; } | |
| 687 virtual intptr_t ResultCid() const { return kDynamicCid; } | |
| 688 | |
| 689 private: | |
| 690 const ICData* ic_data_; | |
| 691 const intptr_t token_pos_; | |
| 692 const String& function_name_; | |
| 693 const Token::Kind token_kind_; // Binary op, unary op, kGET or kILLEGAL. | |
| 694 ZoneGrowableArray<PushArgumentInstr*>* const arguments_; | |
| 695 const Array& argument_names_; | |
| 696 const intptr_t checked_argument_count_; | |
| 697 | |
| 698 DISALLOW_COPY_AND_ASSIGN(InstanceCallComp); | |
| 699 }; | |
| 700 | |
| 701 | |
| 702 class PolymorphicInstanceCallComp : public TemplateComputation<0> { | |
| 703 public: | |
| 704 PolymorphicInstanceCallComp(InstanceCallComp* comp, | |
| 705 const ICData& ic_data, | |
| 706 bool with_checks) | |
| 707 : instance_call_(comp), ic_data_(ic_data), with_checks_(with_checks) { | |
| 708 ASSERT(instance_call_ != NULL); | |
| 709 } | |
| 710 | |
| 711 InstanceCallComp* instance_call() const { return instance_call_; } | |
| 712 bool with_checks() const { return with_checks_; } | |
| 713 | |
| 714 void PrintTo(BufferFormatter* f) const; | |
| 715 | |
| 716 virtual intptr_t ArgumentCount() const { | |
| 717 return instance_call()->ArgumentCount(); | |
| 718 } | |
| 719 | |
| 720 DECLARE_CALL_COMPUTATION(PolymorphicInstanceCall) | |
| 721 | |
| 722 const ICData& ic_data() const { return ic_data_; } | |
| 723 | |
| 724 virtual bool CanDeoptimize() const { return true; } | |
| 725 virtual intptr_t ResultCid() const { return kDynamicCid; } | |
| 726 | |
| 727 private: | |
| 728 InstanceCallComp* instance_call_; | |
| 729 const ICData& ic_data_; | |
| 730 const bool with_checks_; | |
| 731 | |
| 732 DISALLOW_COPY_AND_ASSIGN(PolymorphicInstanceCallComp); | |
| 733 }; | |
| 734 | |
| 735 | |
| 736 class ComparisonComp : public TemplateComputation<2> { | |
| 737 public: | |
| 738 ComparisonComp(Token::Kind kind, Value* left, Value* right) : kind_(kind) { | |
| 739 ASSERT(left != NULL); | |
| 740 ASSERT(right != NULL); | |
| 741 inputs_[0] = left; | |
| 742 inputs_[1] = right; | |
| 743 } | |
| 744 | |
| 745 Value* left() const { return inputs_[0]; } | |
| 746 Value* right() const { return inputs_[1]; } | |
| 747 | |
| 748 virtual ComparisonComp* AsComparison() { return this; } | |
| 749 | |
| 750 Token::Kind kind() const { return kind_; } | |
| 751 | |
| 752 private: | |
| 753 Token::Kind kind_; | |
| 754 }; | |
| 755 | |
| 756 | |
| 757 class StrictCompareComp : public ComparisonComp { | |
| 758 public: | |
| 759 StrictCompareComp(Token::Kind kind, Value* left, Value* right) | |
| 760 : ComparisonComp(kind, left, right) { | |
| 761 ASSERT((kind == Token::kEQ_STRICT) || (kind == Token::kNE_STRICT)); | |
| 762 } | |
| 763 | |
| 764 DECLARE_COMPUTATION(StrictCompare) | |
| 765 | |
| 766 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 767 | |
| 768 virtual bool CanDeoptimize() const { return false; } | |
| 769 | |
| 770 virtual Definition* TryReplace(BindInstr* instr) const; | |
| 771 | |
| 772 virtual intptr_t ResultCid() const { return kBoolCid; } | |
| 773 | |
| 774 virtual void EmitBranchCode(FlowGraphCompiler* compiler, | |
| 775 BranchInstr* branch); | |
| 776 | |
| 777 private: | |
| 778 DISALLOW_COPY_AND_ASSIGN(StrictCompareComp); | |
| 779 }; | |
| 780 | |
| 781 | |
| 782 class EqualityCompareComp : public ComparisonComp { | |
| 783 public: | |
| 784 EqualityCompareComp(intptr_t token_pos, | |
| 785 Token::Kind kind, | |
| 786 Value* left, | |
| 787 Value* right) | |
| 788 : ComparisonComp(kind, left, right), | |
| 789 ic_data_(Isolate::Current()->GetICDataForDeoptId(deopt_id())), | |
| 790 token_pos_(token_pos), | |
| 791 receiver_class_id_(kIllegalCid) { | |
| 792 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); | |
| 793 } | |
| 794 | |
| 795 DECLARE_COMPUTATION(EqualityCompare) | |
| 796 | |
| 797 const ICData* ic_data() const { return ic_data_; } | |
| 798 bool HasICData() const { | |
| 799 return (ic_data() != NULL) && !ic_data()->IsNull(); | |
| 800 } | |
| 801 | |
| 802 intptr_t token_pos() const { return token_pos_; } | |
| 803 | |
| 804 // Receiver class id is computed from collected ICData. | |
| 805 void set_receiver_class_id(intptr_t value) { receiver_class_id_ = value; } | |
| 806 intptr_t receiver_class_id() const { return receiver_class_id_; } | |
| 807 | |
| 808 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 809 | |
| 810 virtual bool CanDeoptimize() const { | |
| 811 return (receiver_class_id() != kDoubleCid); | |
| 812 } | |
| 813 | |
| 814 virtual intptr_t ResultCid() const; | |
| 815 | |
| 816 virtual void EmitBranchCode(FlowGraphCompiler* compiler, | |
| 817 BranchInstr* branch); | |
| 818 | |
| 819 virtual intptr_t DeoptimizationTarget() const { | |
| 820 return GetDeoptId(); | |
| 821 } | |
| 822 | |
| 823 virtual Representation RequiredInputRepresentation(intptr_t idx) const { | |
| 824 ASSERT((idx == 0) || (idx == 1)); | |
| 825 return (receiver_class_id() == kDoubleCid) ? kUnboxedDouble : kTagged; | |
| 826 } | |
| 827 | |
| 828 private: | |
| 829 const ICData* ic_data_; | |
| 830 const intptr_t token_pos_; | |
| 831 intptr_t receiver_class_id_; // Set by optimizer. | |
| 832 | |
| 833 DISALLOW_COPY_AND_ASSIGN(EqualityCompareComp); | |
| 834 }; | |
| 835 | |
| 836 | |
| 837 class RelationalOpComp : public ComparisonComp { | |
| 838 public: | |
| 839 RelationalOpComp(intptr_t token_pos, | |
| 840 Token::Kind kind, | |
| 841 Value* left, | |
| 842 Value* right) | |
| 843 : ComparisonComp(kind, left, right), | |
| 844 ic_data_(Isolate::Current()->GetICDataForDeoptId(deopt_id())), | |
| 845 token_pos_(token_pos), | |
| 846 operands_class_id_(kIllegalCid) { | |
| 847 ASSERT(Token::IsRelationalOperator(kind)); | |
| 848 } | |
| 849 | |
| 850 DECLARE_COMPUTATION(RelationalOp) | |
| 851 | |
| 852 const ICData* ic_data() const { return ic_data_; } | |
| 853 bool HasICData() const { | |
| 854 return (ic_data() != NULL) && !ic_data()->IsNull(); | |
| 855 } | |
| 856 | |
| 857 intptr_t token_pos() const { return token_pos_; } | |
| 858 | |
| 859 // TODO(srdjan): instead of class-id pass an enum that can differentiate | |
| 860 // between boxed and unboxed doubles and integers. | |
| 861 void set_operands_class_id(intptr_t value) { | |
| 862 operands_class_id_ = value; | |
| 863 } | |
| 864 | |
| 865 intptr_t operands_class_id() const { return operands_class_id_; } | |
| 866 | |
| 867 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 868 | |
| 869 virtual bool CanDeoptimize() const { | |
| 870 return operands_class_id() != kDoubleCid; | |
| 871 } | |
| 872 | |
| 873 virtual intptr_t ResultCid() const; | |
| 874 | |
| 875 virtual void EmitBranchCode(FlowGraphCompiler* compiler, | |
| 876 BranchInstr* branch); | |
| 877 | |
| 878 | |
| 879 virtual intptr_t DeoptimizationTarget() const { | |
| 880 return GetDeoptId(); | |
| 881 } | |
| 882 | |
| 883 virtual Representation RequiredInputRepresentation(intptr_t idx) const { | |
| 884 ASSERT((idx == 0) || (idx == 1)); | |
| 885 return (operands_class_id() == kDoubleCid) ? kUnboxedDouble : kTagged; | |
| 886 } | |
| 887 | |
| 888 private: | |
| 889 const ICData* ic_data_; | |
| 890 const intptr_t token_pos_; | |
| 891 intptr_t operands_class_id_; // class id of both operands. | |
| 892 | |
| 893 DISALLOW_COPY_AND_ASSIGN(RelationalOpComp); | |
| 894 }; | |
| 895 | |
| 896 | |
| 897 class StaticCallComp : public TemplateComputation<0> { | |
| 898 public: | |
| 899 StaticCallComp(intptr_t token_pos, | |
| 900 const Function& function, | |
| 901 const Array& argument_names, | |
| 902 ZoneGrowableArray<PushArgumentInstr*>* arguments) | |
| 903 : token_pos_(token_pos), | |
| 904 function_(function), | |
| 905 argument_names_(argument_names), | |
| 906 arguments_(arguments), | |
| 907 recognized_(MethodRecognizer::kUnknown) { | |
| 908 ASSERT(function.IsZoneHandle()); | |
| 909 ASSERT(argument_names.IsZoneHandle()); | |
| 910 } | |
| 911 | |
| 912 DECLARE_CALL_COMPUTATION(StaticCall) | |
| 913 | |
| 914 // Accessors forwarded to the AST node. | |
| 915 const Function& function() const { return function_; } | |
| 916 const Array& argument_names() const { return argument_names_; } | |
| 917 intptr_t token_pos() const { return token_pos_; } | |
| 918 | |
| 919 virtual intptr_t ArgumentCount() const { return arguments_->length(); } | |
| 920 PushArgumentInstr* ArgumentAt(intptr_t index) const { | |
| 921 return (*arguments_)[index]; | |
| 922 } | |
| 923 | |
| 924 MethodRecognizer::Kind recognized() const { return recognized_; } | |
| 925 void set_recognized(MethodRecognizer::Kind kind) { recognized_ = kind; } | |
| 926 | |
| 927 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 928 | |
| 929 virtual bool CanDeoptimize() const { return true; } | |
| 930 virtual intptr_t ResultCid() const { return kDynamicCid; } | |
| 931 | |
| 932 private: | |
| 933 const intptr_t token_pos_; | |
| 934 const Function& function_; | |
| 935 const Array& argument_names_; | |
| 936 ZoneGrowableArray<PushArgumentInstr*>* arguments_; | |
| 937 MethodRecognizer::Kind recognized_; | |
| 938 | |
| 939 DISALLOW_COPY_AND_ASSIGN(StaticCallComp); | |
| 940 }; | |
| 941 | |
| 942 | |
| 943 class LoadLocalComp : public TemplateComputation<0> { | |
| 944 public: | |
| 945 LoadLocalComp(const LocalVariable& local, intptr_t context_level) | |
| 946 : local_(local), | |
| 947 context_level_(context_level) { } | |
| 948 | |
| 949 DECLARE_COMPUTATION(LoadLocal) | |
| 950 | |
| 951 const LocalVariable& local() const { return local_; } | |
| 952 intptr_t context_level() const { return context_level_; } | |
| 953 | |
| 954 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 955 | |
| 956 virtual bool CanDeoptimize() const { return false; } | |
| 957 virtual intptr_t ResultCid() const { return kDynamicCid; } | |
| 958 | |
| 959 private: | |
| 960 const LocalVariable& local_; | |
| 961 const intptr_t context_level_; | |
| 962 | |
| 963 DISALLOW_COPY_AND_ASSIGN(LoadLocalComp); | |
| 964 }; | |
| 965 | |
| 966 | |
| 967 class StoreLocalComp : public TemplateComputation<1> { | |
| 968 public: | |
| 969 StoreLocalComp(const LocalVariable& local, | |
| 970 Value* value, | |
| 971 intptr_t context_level) | |
| 972 : local_(local), | |
| 973 context_level_(context_level) { | |
| 974 ASSERT(value != NULL); | |
| 975 inputs_[0] = value; | |
| 976 } | |
| 977 | |
| 978 DECLARE_COMPUTATION(StoreLocal) | |
| 979 | |
| 980 const LocalVariable& local() const { return local_; } | |
| 981 Value* value() const { return inputs_[0]; } | |
| 982 intptr_t context_level() const { return context_level_; } | |
| 983 | |
| 984 virtual void RecordAssignedVars(BitVector* assigned_vars, | |
| 985 intptr_t fixed_parameter_count); | |
| 986 | |
| 987 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 988 | |
| 989 virtual bool CanDeoptimize() const { return false; } | |
| 990 virtual intptr_t ResultCid() const { return kDynamicCid; } | |
| 991 | |
| 992 private: | |
| 993 const LocalVariable& local_; | |
| 994 const intptr_t context_level_; | |
| 995 | |
| 996 DISALLOW_COPY_AND_ASSIGN(StoreLocalComp); | |
| 997 }; | |
| 998 | |
| 999 | |
| 1000 class NativeCallComp : public TemplateComputation<0> { | |
| 1001 public: | |
| 1002 explicit NativeCallComp(NativeBodyNode* node) | |
| 1003 : ast_node_(*node) {} | |
| 1004 | |
| 1005 DECLARE_COMPUTATION(NativeCall) | |
| 1006 | |
| 1007 intptr_t token_pos() const { return ast_node_.token_pos(); } | |
| 1008 | |
| 1009 const String& native_name() const { | |
| 1010 return ast_node_.native_c_function_name(); | |
| 1011 } | |
| 1012 | |
| 1013 NativeFunction native_c_function() const { | |
| 1014 return ast_node_.native_c_function(); | |
| 1015 } | |
| 1016 | |
| 1017 intptr_t argument_count() const { return ast_node_.argument_count(); } | |
| 1018 | |
| 1019 bool has_optional_parameters() const { | |
| 1020 return ast_node_.has_optional_parameters(); | |
| 1021 } | |
| 1022 | |
| 1023 bool is_native_instance_closure() const { | |
| 1024 return ast_node_.is_native_instance_closure(); | |
| 1025 } | |
| 1026 | |
| 1027 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 1028 | |
| 1029 virtual bool CanDeoptimize() const { return false; } | |
| 1030 virtual intptr_t ResultCid() const { return kDynamicCid; } | |
| 1031 | |
| 1032 private: | |
| 1033 const NativeBodyNode& ast_node_; | |
| 1034 | |
| 1035 DISALLOW_COPY_AND_ASSIGN(NativeCallComp); | |
| 1036 }; | |
| 1037 | |
| 1038 | |
| 1039 class LoadInstanceFieldComp : public TemplateComputation<1> { | |
| 1040 public: | |
| 1041 LoadInstanceFieldComp(const Field& field, Value* instance) : field_(field) { | |
| 1042 ASSERT(instance != NULL); | |
| 1043 inputs_[0] = instance; | |
| 1044 } | |
| 1045 | |
| 1046 DECLARE_COMPUTATION(LoadInstanceField) | |
| 1047 | |
| 1048 const Field& field() const { return field_; } | |
| 1049 Value* instance() const { return inputs_[0]; } | |
| 1050 | |
| 1051 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 1052 | |
| 1053 virtual bool CanDeoptimize() const { return false; } | |
| 1054 virtual intptr_t ResultCid() const { return kDynamicCid; } | |
| 1055 | |
| 1056 private: | |
| 1057 const Field& field_; | |
| 1058 | |
| 1059 DISALLOW_COPY_AND_ASSIGN(LoadInstanceFieldComp); | |
| 1060 }; | |
| 1061 | |
| 1062 | |
| 1063 class StoreInstanceFieldComp : public TemplateComputation<2> { | |
| 1064 public: | |
| 1065 StoreInstanceFieldComp(const Field& field, | |
| 1066 Value* instance, | |
| 1067 Value* value) | |
| 1068 : field_(field) { | |
| 1069 ASSERT(instance != NULL); | |
| 1070 ASSERT(value != NULL); | |
| 1071 inputs_[0] = instance; | |
| 1072 inputs_[1] = value; | |
| 1073 } | |
| 1074 | |
| 1075 DECLARE_COMPUTATION(StoreInstanceField) | |
| 1076 | |
| 1077 const Field& field() const { return field_; } | |
| 1078 | |
| 1079 Value* instance() const { return inputs_[0]; } | |
| 1080 Value* value() const { return inputs_[1]; } | |
| 1081 | |
| 1082 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 1083 | |
| 1084 virtual bool CanDeoptimize() const { return false; } | |
| 1085 virtual intptr_t ResultCid() const { return kDynamicCid; } | |
| 1086 | |
| 1087 private: | |
| 1088 const Field& field_; | |
| 1089 | |
| 1090 DISALLOW_COPY_AND_ASSIGN(StoreInstanceFieldComp); | |
| 1091 }; | |
| 1092 | |
| 1093 | |
| 1094 class LoadStaticFieldComp : public TemplateComputation<0> { | |
| 1095 public: | |
| 1096 explicit LoadStaticFieldComp(const Field& field) : field_(field) {} | |
| 1097 | |
| 1098 DECLARE_COMPUTATION(LoadStaticField); | |
| 1099 | |
| 1100 const Field& field() const { return field_; } | |
| 1101 | |
| 1102 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 1103 | |
| 1104 virtual bool CanDeoptimize() const { return false; } | |
| 1105 virtual intptr_t ResultCid() const { return kDynamicCid; } | |
| 1106 | |
| 1107 private: | |
| 1108 const Field& field_; | |
| 1109 | |
| 1110 DISALLOW_COPY_AND_ASSIGN(LoadStaticFieldComp); | |
| 1111 }; | |
| 1112 | |
| 1113 | |
| 1114 class StoreStaticFieldComp : public TemplateComputation<1> { | |
| 1115 public: | |
| 1116 StoreStaticFieldComp(const Field& field, Value* value) | |
| 1117 : field_(field) { | |
| 1118 ASSERT(field.IsZoneHandle()); | |
| 1119 ASSERT(value != NULL); | |
| 1120 inputs_[0] = value; | |
| 1121 } | |
| 1122 | |
| 1123 DECLARE_COMPUTATION(StoreStaticField); | |
| 1124 | |
| 1125 const Field& field() const { return field_; } | |
| 1126 Value* value() const { return inputs_[0]; } | |
| 1127 | |
| 1128 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 1129 | |
| 1130 virtual bool CanDeoptimize() const { return false; } | |
| 1131 virtual intptr_t ResultCid() const { return kDynamicCid; } | |
| 1132 | |
| 1133 private: | |
| 1134 const Field& field_; | |
| 1135 | |
| 1136 DISALLOW_COPY_AND_ASSIGN(StoreStaticFieldComp); | |
| 1137 }; | |
| 1138 | |
| 1139 | |
| 1140 class LoadIndexedComp : public TemplateComputation<2> { | |
| 1141 public: | |
| 1142 LoadIndexedComp(Value* array, | |
| 1143 Value* index, | |
| 1144 intptr_t receiver_type) | |
| 1145 : receiver_type_(receiver_type) { | |
| 1146 ASSERT(array != NULL); | |
| 1147 ASSERT(index != NULL); | |
| 1148 inputs_[0] = array; | |
| 1149 inputs_[1] = index; | |
| 1150 } | |
| 1151 | |
| 1152 DECLARE_COMPUTATION(LoadIndexed) | |
| 1153 | |
| 1154 Value* array() const { return inputs_[0]; } | |
| 1155 Value* index() const { return inputs_[1]; } | |
| 1156 | |
| 1157 intptr_t receiver_type() const { return receiver_type_; } | |
| 1158 | |
| 1159 virtual bool CanDeoptimize() const { return false; } | |
| 1160 virtual intptr_t ResultCid() const { return kDynamicCid; } | |
| 1161 | |
| 1162 private: | |
| 1163 intptr_t receiver_type_; | |
| 1164 | |
| 1165 DISALLOW_COPY_AND_ASSIGN(LoadIndexedComp); | |
| 1166 }; | |
| 1167 | |
| 1168 | |
| 1169 class StoreIndexedComp : public TemplateComputation<3> { | |
| 1170 public: | |
| 1171 StoreIndexedComp(Value* array, | |
| 1172 Value* index, | |
| 1173 Value* value, | |
| 1174 intptr_t receiver_type) | |
| 1175 : receiver_type_(receiver_type) { | |
| 1176 ASSERT(array != NULL); | |
| 1177 ASSERT(index != NULL); | |
| 1178 ASSERT(value != NULL); | |
| 1179 inputs_[0] = array; | |
| 1180 inputs_[1] = index; | |
| 1181 inputs_[2] = value; | |
| 1182 } | |
| 1183 | |
| 1184 DECLARE_COMPUTATION(StoreIndexed) | |
| 1185 | |
| 1186 Value* array() const { return inputs_[0]; } | |
| 1187 Value* index() const { return inputs_[1]; } | |
| 1188 Value* value() const { return inputs_[2]; } | |
| 1189 | |
| 1190 intptr_t receiver_type() const { return receiver_type_; } | |
| 1191 | |
| 1192 virtual bool CanDeoptimize() const { return false; } | |
| 1193 virtual intptr_t ResultCid() const { return kDynamicCid; } | |
| 1194 | |
| 1195 private: | |
| 1196 intptr_t receiver_type_; | |
| 1197 | |
| 1198 DISALLOW_COPY_AND_ASSIGN(StoreIndexedComp); | |
| 1199 }; | |
| 1200 | |
| 1201 | |
| 1202 // Note overrideable, built-in: value? false : true. | |
| 1203 class BooleanNegateComp : public TemplateComputation<1> { | |
| 1204 public: | |
| 1205 explicit BooleanNegateComp(Value* value) { | |
| 1206 ASSERT(value != NULL); | |
| 1207 inputs_[0] = value; | |
| 1208 } | |
| 1209 | |
| 1210 DECLARE_COMPUTATION(BooleanNegate) | |
| 1211 | |
| 1212 Value* value() const { return inputs_[0]; } | |
| 1213 | |
| 1214 virtual bool CanDeoptimize() const { return false; } | |
| 1215 virtual intptr_t ResultCid() const { return kBoolCid; } | |
| 1216 | |
| 1217 private: | |
| 1218 DISALLOW_COPY_AND_ASSIGN(BooleanNegateComp); | |
| 1219 }; | |
| 1220 | |
| 1221 | |
| 1222 class InstanceOfComp : public TemplateComputation<3> { | |
| 1223 public: | |
| 1224 InstanceOfComp(intptr_t token_pos, | |
| 1225 Value* value, | |
| 1226 Value* instantiator, | |
| 1227 Value* instantiator_type_arguments, | |
| 1228 const AbstractType& type, | |
| 1229 bool negate_result) | |
| 1230 : token_pos_(token_pos), | |
| 1231 type_(type), | |
| 1232 negate_result_(negate_result) { | |
| 1233 ASSERT(value != NULL); | |
| 1234 ASSERT(instantiator != NULL); | |
| 1235 ASSERT(instantiator_type_arguments != NULL); | |
| 1236 ASSERT(!type.IsNull()); | |
| 1237 inputs_[0] = value; | |
| 1238 inputs_[1] = instantiator; | |
| 1239 inputs_[2] = instantiator_type_arguments; | |
| 1240 } | |
| 1241 | |
| 1242 DECLARE_COMPUTATION(InstanceOf) | |
| 1243 | |
| 1244 Value* value() const { return inputs_[0]; } | |
| 1245 Value* instantiator() const { return inputs_[1]; } | |
| 1246 Value* instantiator_type_arguments() const { return inputs_[2]; } | |
| 1247 | |
| 1248 bool negate_result() const { return negate_result_; } | |
| 1249 const AbstractType& type() const { return type_; } | |
| 1250 intptr_t token_pos() const { return token_pos_; } | |
| 1251 | |
| 1252 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 1253 | |
| 1254 virtual bool CanDeoptimize() const { return false; } | |
| 1255 virtual intptr_t ResultCid() const { return kBoolCid; } | |
| 1256 | |
| 1257 private: | |
| 1258 const intptr_t token_pos_; | |
| 1259 Value* value_; | |
| 1260 Value* instantiator_; | |
| 1261 Value* type_arguments_; | |
| 1262 const AbstractType& type_; | |
| 1263 const bool negate_result_; | |
| 1264 | |
| 1265 DISALLOW_COPY_AND_ASSIGN(InstanceOfComp); | |
| 1266 }; | |
| 1267 | |
| 1268 | |
| 1269 class AllocateObjectComp : public TemplateComputation<0> { | |
| 1270 public: | |
| 1271 AllocateObjectComp(ConstructorCallNode* node, | |
| 1272 ZoneGrowableArray<PushArgumentInstr*>* arguments) | |
| 1273 : ast_node_(*node), arguments_(arguments) { | |
| 1274 // Either no arguments or one type-argument and one instantiator. | |
| 1275 ASSERT(arguments->is_empty() || (arguments->length() == 2)); | |
| 1276 } | |
| 1277 | |
| 1278 DECLARE_CALL_COMPUTATION(AllocateObject) | |
| 1279 | |
| 1280 virtual intptr_t ArgumentCount() const { return arguments_->length(); } | |
| 1281 PushArgumentInstr* ArgumentAt(intptr_t index) const { | |
| 1282 return (*arguments_)[index]; | |
| 1283 } | |
| 1284 | |
| 1285 const Function& constructor() const { return ast_node_.constructor(); } | |
| 1286 intptr_t token_pos() const { return ast_node_.token_pos(); } | |
| 1287 | |
| 1288 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 1289 | |
| 1290 virtual bool CanDeoptimize() const { return false; } | |
| 1291 virtual intptr_t ResultCid() const { return kDynamicCid; } | |
| 1292 | |
| 1293 private: | |
| 1294 const ConstructorCallNode& ast_node_; | |
| 1295 ZoneGrowableArray<PushArgumentInstr*>* const arguments_; | |
| 1296 | |
| 1297 DISALLOW_COPY_AND_ASSIGN(AllocateObjectComp); | |
| 1298 }; | |
| 1299 | |
| 1300 | |
| 1301 class AllocateObjectWithBoundsCheckComp : public TemplateComputation<2> { | |
| 1302 public: | |
| 1303 AllocateObjectWithBoundsCheckComp(ConstructorCallNode* node, | |
| 1304 Value* type_arguments, | |
| 1305 Value* instantiator) | |
| 1306 : ast_node_(*node) { | |
| 1307 ASSERT(type_arguments != NULL); | |
| 1308 ASSERT(instantiator != NULL); | |
| 1309 inputs_[0] = type_arguments; | |
| 1310 inputs_[1] = instantiator; | |
| 1311 } | |
| 1312 | |
| 1313 DECLARE_COMPUTATION(AllocateObjectWithBoundsCheck) | |
| 1314 | |
| 1315 const Function& constructor() const { return ast_node_.constructor(); } | |
| 1316 intptr_t token_pos() const { return ast_node_.token_pos(); } | |
| 1317 | |
| 1318 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 1319 | |
| 1320 virtual bool CanDeoptimize() const { return false; } | |
| 1321 virtual intptr_t ResultCid() const { return kDynamicCid; } | |
| 1322 | |
| 1323 private: | |
| 1324 const ConstructorCallNode& ast_node_; | |
| 1325 | |
| 1326 DISALLOW_COPY_AND_ASSIGN(AllocateObjectWithBoundsCheckComp); | |
| 1327 }; | |
| 1328 | |
| 1329 | |
| 1330 class CreateArrayComp : public TemplateComputation<1> { | |
| 1331 public: | |
| 1332 CreateArrayComp(intptr_t token_pos, | |
| 1333 ZoneGrowableArray<PushArgumentInstr*>* arguments, | |
| 1334 const AbstractType& type, | |
| 1335 Value* element_type) | |
| 1336 : token_pos_(token_pos), | |
| 1337 arguments_(arguments), | |
| 1338 type_(type) { | |
| 1339 #if defined(DEBUG) | |
| 1340 for (int i = 0; i < ArgumentCount(); ++i) { | |
| 1341 ASSERT(ArgumentAt(i) != NULL); | |
| 1342 } | |
| 1343 ASSERT(element_type != NULL); | |
| 1344 ASSERT(type_.IsZoneHandle()); | |
| 1345 ASSERT(!type_.IsNull()); | |
| 1346 ASSERT(type_.IsFinalized()); | |
| 1347 #endif | |
| 1348 inputs_[0] = element_type; | |
| 1349 } | |
| 1350 | |
| 1351 DECLARE_CALL_COMPUTATION(CreateArray) | |
| 1352 | |
| 1353 virtual intptr_t ArgumentCount() const { return arguments_->length(); } | |
| 1354 | |
| 1355 intptr_t token_pos() const { return token_pos_; } | |
| 1356 PushArgumentInstr* ArgumentAt(intptr_t i) const { return (*arguments_)[i]; } | |
| 1357 const AbstractType& type() const { return type_; } | |
| 1358 Value* element_type() const { return inputs_[0]; } | |
| 1359 | |
| 1360 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 1361 | |
| 1362 virtual bool CanDeoptimize() const { return false; } | |
| 1363 virtual intptr_t ResultCid() const { return kDynamicCid; } | |
| 1364 | |
| 1365 private: | |
| 1366 const intptr_t token_pos_; | |
| 1367 ZoneGrowableArray<PushArgumentInstr*>* const arguments_; | |
| 1368 const AbstractType& type_; | |
| 1369 | |
| 1370 DISALLOW_COPY_AND_ASSIGN(CreateArrayComp); | |
| 1371 }; | |
| 1372 | |
| 1373 | |
| 1374 class CreateClosureComp : public TemplateComputation<0> { | |
| 1375 public: | |
| 1376 CreateClosureComp(ClosureNode* node, | |
| 1377 ZoneGrowableArray<PushArgumentInstr*>* arguments) | |
| 1378 : ast_node_(*node), | |
| 1379 arguments_(arguments) { } | |
| 1380 | |
| 1381 DECLARE_CALL_COMPUTATION(CreateClosure) | |
| 1382 | |
| 1383 intptr_t token_pos() const { return ast_node_.token_pos(); } | |
| 1384 const Function& function() const { return ast_node_.function(); } | |
| 1385 | |
| 1386 virtual intptr_t ArgumentCount() const { return arguments_->length(); } | |
| 1387 PushArgumentInstr* ArgumentAt(intptr_t index) const { | |
| 1388 return (*arguments_)[index]; | |
| 1389 } | |
| 1390 | |
| 1391 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 1392 | |
| 1393 virtual bool CanDeoptimize() const { return false; } | |
| 1394 virtual intptr_t ResultCid() const { return kDynamicCid; } | |
| 1395 | |
| 1396 private: | |
| 1397 const ClosureNode& ast_node_; | |
| 1398 ZoneGrowableArray<PushArgumentInstr*>* arguments_; | |
| 1399 | |
| 1400 DISALLOW_COPY_AND_ASSIGN(CreateClosureComp); | |
| 1401 }; | |
| 1402 | |
| 1403 | |
| 1404 class LoadVMFieldComp : public TemplateComputation<1> { | |
| 1405 public: | |
| 1406 LoadVMFieldComp(Value* value, | |
| 1407 intptr_t offset_in_bytes, | |
| 1408 const AbstractType& type) | |
| 1409 : offset_in_bytes_(offset_in_bytes), | |
| 1410 type_(type), | |
| 1411 result_cid_(kDynamicCid) { | |
| 1412 ASSERT(value != NULL); | |
| 1413 ASSERT(type.IsZoneHandle()); // May be null if field is not an instance. | |
| 1414 inputs_[0] = value; | |
| 1415 } | |
| 1416 | |
| 1417 DECLARE_COMPUTATION(LoadVMField) | |
| 1418 | |
| 1419 Value* value() const { return inputs_[0]; } | |
| 1420 intptr_t offset_in_bytes() const { return offset_in_bytes_; } | |
| 1421 const AbstractType& type() const { return type_; } | |
| 1422 void set_result_cid(intptr_t value) { result_cid_ = value; } | |
| 1423 | |
| 1424 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 1425 | |
| 1426 virtual bool CanDeoptimize() const { return false; } | |
| 1427 virtual intptr_t ResultCid() const { return result_cid_; } | |
| 1428 | |
| 1429 private: | |
| 1430 const intptr_t offset_in_bytes_; | |
| 1431 const AbstractType& type_; | |
| 1432 intptr_t result_cid_; | |
| 1433 | |
| 1434 DISALLOW_COPY_AND_ASSIGN(LoadVMFieldComp); | |
| 1435 }; | |
| 1436 | |
| 1437 | |
| 1438 class StoreVMFieldComp : public TemplateComputation<2> { | |
| 1439 public: | |
| 1440 StoreVMFieldComp(Value* dest, | |
| 1441 intptr_t offset_in_bytes, | |
| 1442 Value* value, | |
| 1443 const AbstractType& type) | |
| 1444 : offset_in_bytes_(offset_in_bytes), type_(type) { | |
| 1445 ASSERT(value != NULL); | |
| 1446 ASSERT(dest != NULL); | |
| 1447 ASSERT(type.IsZoneHandle()); // May be null if field is not an instance. | |
| 1448 inputs_[0] = value; | |
| 1449 inputs_[1] = dest; | |
| 1450 } | |
| 1451 | |
| 1452 DECLARE_COMPUTATION(StoreVMField) | |
| 1453 | |
| 1454 Value* value() const { return inputs_[0]; } | |
| 1455 Value* dest() const { return inputs_[1]; } | |
| 1456 intptr_t offset_in_bytes() const { return offset_in_bytes_; } | |
| 1457 const AbstractType& type() const { return type_; } | |
| 1458 | |
| 1459 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 1460 | |
| 1461 virtual bool CanDeoptimize() const { return false; } | |
| 1462 virtual intptr_t ResultCid() const { return kDynamicCid; } | |
| 1463 | |
| 1464 private: | |
| 1465 const intptr_t offset_in_bytes_; | |
| 1466 const AbstractType& type_; | |
| 1467 | |
| 1468 DISALLOW_COPY_AND_ASSIGN(StoreVMFieldComp); | |
| 1469 }; | |
| 1470 | |
| 1471 | |
| 1472 class InstantiateTypeArgumentsComp : public TemplateComputation<1> { | |
| 1473 public: | |
| 1474 InstantiateTypeArgumentsComp(intptr_t token_pos, | |
| 1475 const AbstractTypeArguments& type_arguments, | |
| 1476 Value* instantiator) | |
| 1477 : token_pos_(token_pos), | |
| 1478 type_arguments_(type_arguments) { | |
| 1479 ASSERT(type_arguments.IsZoneHandle()); | |
| 1480 ASSERT(instantiator != NULL); | |
| 1481 inputs_[0] = instantiator; | |
| 1482 } | |
| 1483 | |
| 1484 DECLARE_COMPUTATION(InstantiateTypeArguments) | |
| 1485 | |
| 1486 Value* instantiator() const { return inputs_[0]; } | |
| 1487 const AbstractTypeArguments& type_arguments() const { | |
| 1488 return type_arguments_; | |
| 1489 } | |
| 1490 intptr_t token_pos() const { return token_pos_; } | |
| 1491 | |
| 1492 virtual void PrintOperandsTo(BufferFormatter* f) const; | |
| 1493 | |
| 1494 virtual bool CanDeoptimize() const { return false; } | 1611 virtual bool CanDeoptimize() const { return false; } |
| 1495 virtual intptr_t ResultCid() const { return kDynamicCid; } | 1612 virtual intptr_t ResultCid() const { return kDynamicCid; } |
| 1496 | 1613 |
| 1497 private: | 1614 private: |
| 1498 const intptr_t token_pos_; | 1615 const intptr_t token_pos_; |
| 1616 const AbstractType& dst_type_; |
| 1617 const String& dst_name_; |
| 1618 bool is_eliminated_; |
| 1619 |
| 1620 DISALLOW_COPY_AND_ASSIGN(AssertAssignableComp); |
| 1621 }; |
| 1622 |
| 1623 |
| 1624 class AssertBooleanComp : public TemplateComputation<1> { |
| 1625 public: |
| 1626 AssertBooleanComp(intptr_t token_pos, |
| 1627 Value* value) |
| 1628 : token_pos_(token_pos), |
| 1629 is_eliminated_(false) { |
| 1630 ASSERT(value != NULL); |
| 1631 inputs_[0] = value; |
| 1632 } |
| 1633 |
| 1634 DECLARE_COMPUTATION(AssertBoolean) |
| 1635 |
| 1636 intptr_t token_pos() const { return token_pos_; } |
| 1637 Value* value() const { return inputs_[0]; } |
| 1638 |
| 1639 bool is_eliminated() const { |
| 1640 return is_eliminated_; |
| 1641 } |
| 1642 void eliminate() { |
| 1643 ASSERT(!is_eliminated_); |
| 1644 is_eliminated_ = true; |
| 1645 } |
| 1646 |
| 1647 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 1648 |
| 1649 virtual bool CanDeoptimize() const { return false; } |
| 1650 virtual intptr_t ResultCid() const { return kBoolCid; } |
| 1651 |
| 1652 private: |
| 1653 const intptr_t token_pos_; |
| 1654 bool is_eliminated_; |
| 1655 |
| 1656 DISALLOW_COPY_AND_ASSIGN(AssertBooleanComp); |
| 1657 }; |
| 1658 |
| 1659 |
| 1660 class ArgumentDefinitionTestComp : public TemplateComputation<1> { |
| 1661 public: |
| 1662 ArgumentDefinitionTestComp(ArgumentDefinitionTestNode* node, |
| 1663 Value* saved_arguments_descriptor) |
| 1664 : ast_node_(*node) { |
| 1665 ASSERT(saved_arguments_descriptor != NULL); |
| 1666 inputs_[0] = saved_arguments_descriptor; |
| 1667 } |
| 1668 |
| 1669 DECLARE_COMPUTATION(ArgumentDefinitionTest) |
| 1670 |
| 1671 intptr_t token_pos() const { return ast_node_.token_pos(); } |
| 1672 intptr_t formal_parameter_index() const { |
| 1673 return ast_node_.formal_parameter_index(); |
| 1674 } |
| 1675 const String& formal_parameter_name() const { |
| 1676 return ast_node_.formal_parameter_name(); |
| 1677 } |
| 1678 Value* saved_arguments_descriptor() const { return inputs_[0]; } |
| 1679 |
| 1680 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 1681 |
| 1682 virtual bool CanDeoptimize() const { return false; } |
| 1683 virtual intptr_t ResultCid() const { return kBoolCid; } |
| 1684 |
| 1685 private: |
| 1686 const ArgumentDefinitionTestNode& ast_node_; |
| 1687 |
| 1688 DISALLOW_COPY_AND_ASSIGN(ArgumentDefinitionTestComp); |
| 1689 }; |
| 1690 |
| 1691 |
| 1692 // Denotes the current context, normally held in a register. This is |
| 1693 // a computation, not a value, because it's mutable. |
| 1694 class CurrentContextComp : public TemplateComputation<0> { |
| 1695 public: |
| 1696 CurrentContextComp() { } |
| 1697 |
| 1698 DECLARE_COMPUTATION(CurrentContext) |
| 1699 |
| 1700 virtual bool CanDeoptimize() const { return false; } |
| 1701 virtual intptr_t ResultCid() const { return kDynamicCid; } |
| 1702 |
| 1703 private: |
| 1704 DISALLOW_COPY_AND_ASSIGN(CurrentContextComp); |
| 1705 }; |
| 1706 |
| 1707 |
| 1708 class StoreContextComp : public TemplateComputation<1> { |
| 1709 public: |
| 1710 explicit StoreContextComp(Value* value) { |
| 1711 ASSERT(value != NULL); |
| 1712 inputs_[0] = value; |
| 1713 } |
| 1714 |
| 1715 DECLARE_COMPUTATION(StoreContext); |
| 1716 |
| 1717 Value* value() const { return inputs_[0]; } |
| 1718 |
| 1719 virtual bool CanDeoptimize() const { return false; } |
| 1720 virtual intptr_t ResultCid() const { return kIllegalCid; } |
| 1721 |
| 1722 private: |
| 1723 DISALLOW_COPY_AND_ASSIGN(StoreContextComp); |
| 1724 }; |
| 1725 |
| 1726 |
| 1727 class ClosureCallComp : public TemplateComputation<0> { |
| 1728 public: |
| 1729 ClosureCallComp(ClosureCallNode* node, |
| 1730 ZoneGrowableArray<PushArgumentInstr*>* arguments) |
| 1731 : ast_node_(*node), |
| 1732 arguments_(arguments) { } |
| 1733 |
| 1734 DECLARE_CALL_COMPUTATION(ClosureCall) |
| 1735 |
| 1736 const Array& argument_names() const { return ast_node_.arguments()->names(); } |
| 1737 intptr_t token_pos() const { return ast_node_.token_pos(); } |
| 1738 |
| 1739 virtual intptr_t ArgumentCount() const { return arguments_->length(); } |
| 1740 PushArgumentInstr* ArgumentAt(intptr_t index) const { |
| 1741 return (*arguments_)[index]; |
| 1742 } |
| 1743 |
| 1744 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 1745 |
| 1746 virtual bool CanDeoptimize() const { return true; } |
| 1747 virtual intptr_t ResultCid() const { return kDynamicCid; } |
| 1748 |
| 1749 private: |
| 1750 const ClosureCallNode& ast_node_; |
| 1751 ZoneGrowableArray<PushArgumentInstr*>* arguments_; |
| 1752 |
| 1753 DISALLOW_COPY_AND_ASSIGN(ClosureCallComp); |
| 1754 }; |
| 1755 |
| 1756 |
| 1757 class InstanceCallComp : public TemplateComputation<0> { |
| 1758 public: |
| 1759 InstanceCallComp(intptr_t token_pos, |
| 1760 const String& function_name, |
| 1761 Token::Kind token_kind, |
| 1762 ZoneGrowableArray<PushArgumentInstr*>* arguments, |
| 1763 const Array& argument_names, |
| 1764 intptr_t checked_argument_count) |
| 1765 : ic_data_(Isolate::Current()->GetICDataForDeoptId(deopt_id())), |
| 1766 token_pos_(token_pos), |
| 1767 function_name_(function_name), |
| 1768 token_kind_(token_kind), |
| 1769 arguments_(arguments), |
| 1770 argument_names_(argument_names), |
| 1771 checked_argument_count_(checked_argument_count) { |
| 1772 ASSERT(function_name.IsZoneHandle()); |
| 1773 ASSERT(!arguments->is_empty()); |
| 1774 ASSERT(argument_names.IsZoneHandle()); |
| 1775 ASSERT(Token::IsBinaryToken(token_kind) || |
| 1776 Token::IsUnaryToken(token_kind) || |
| 1777 Token::IsIndexOperator(token_kind) || |
| 1778 token_kind == Token::kGET || |
| 1779 token_kind == Token::kSET || |
| 1780 token_kind == Token::kILLEGAL); |
| 1781 } |
| 1782 |
| 1783 DECLARE_CALL_COMPUTATION(InstanceCall) |
| 1784 |
| 1785 const ICData* ic_data() const { return ic_data_; } |
| 1786 bool HasICData() const { |
| 1787 return (ic_data() != NULL) && !ic_data()->IsNull(); |
| 1788 } |
| 1789 |
| 1790 intptr_t token_pos() const { return token_pos_; } |
| 1791 const String& function_name() const { return function_name_; } |
| 1792 Token::Kind token_kind() const { return token_kind_; } |
| 1793 virtual intptr_t ArgumentCount() const { return arguments_->length(); } |
| 1794 PushArgumentInstr* ArgumentAt(intptr_t index) const { |
| 1795 return (*arguments_)[index]; |
| 1796 } |
| 1797 const Array& argument_names() const { return argument_names_; } |
| 1798 intptr_t checked_argument_count() const { return checked_argument_count_; } |
| 1799 |
| 1800 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 1801 |
| 1802 virtual bool CanDeoptimize() const { return true; } |
| 1803 virtual intptr_t ResultCid() const { return kDynamicCid; } |
| 1804 |
| 1805 private: |
| 1806 const ICData* ic_data_; |
| 1807 const intptr_t token_pos_; |
| 1808 const String& function_name_; |
| 1809 const Token::Kind token_kind_; // Binary op, unary op, kGET or kILLEGAL. |
| 1810 ZoneGrowableArray<PushArgumentInstr*>* const arguments_; |
| 1811 const Array& argument_names_; |
| 1812 const intptr_t checked_argument_count_; |
| 1813 |
| 1814 DISALLOW_COPY_AND_ASSIGN(InstanceCallComp); |
| 1815 }; |
| 1816 |
| 1817 |
| 1818 class PolymorphicInstanceCallComp : public TemplateComputation<0> { |
| 1819 public: |
| 1820 PolymorphicInstanceCallComp(InstanceCallComp* comp, |
| 1821 const ICData& ic_data, |
| 1822 bool with_checks) |
| 1823 : instance_call_(comp), ic_data_(ic_data), with_checks_(with_checks) { |
| 1824 ASSERT(instance_call_ != NULL); |
| 1825 } |
| 1826 |
| 1827 InstanceCallComp* instance_call() const { return instance_call_; } |
| 1828 bool with_checks() const { return with_checks_; } |
| 1829 |
| 1830 void PrintTo(BufferFormatter* f) const; |
| 1831 |
| 1832 virtual intptr_t ArgumentCount() const { |
| 1833 return instance_call()->ArgumentCount(); |
| 1834 } |
| 1835 |
| 1836 DECLARE_CALL_COMPUTATION(PolymorphicInstanceCall) |
| 1837 |
| 1838 const ICData& ic_data() const { return ic_data_; } |
| 1839 |
| 1840 virtual bool CanDeoptimize() const { return true; } |
| 1841 virtual intptr_t ResultCid() const { return kDynamicCid; } |
| 1842 |
| 1843 private: |
| 1844 InstanceCallComp* instance_call_; |
| 1845 const ICData& ic_data_; |
| 1846 const bool with_checks_; |
| 1847 |
| 1848 DISALLOW_COPY_AND_ASSIGN(PolymorphicInstanceCallComp); |
| 1849 }; |
| 1850 |
| 1851 |
| 1852 class ComparisonComp : public TemplateComputation<2> { |
| 1853 public: |
| 1854 ComparisonComp(Token::Kind kind, Value* left, Value* right) : kind_(kind) { |
| 1855 ASSERT(left != NULL); |
| 1856 ASSERT(right != NULL); |
| 1857 inputs_[0] = left; |
| 1858 inputs_[1] = right; |
| 1859 } |
| 1860 |
| 1861 Value* left() const { return inputs_[0]; } |
| 1862 Value* right() const { return inputs_[1]; } |
| 1863 |
| 1864 virtual ComparisonComp* AsComparison() { return this; } |
| 1865 |
| 1866 Token::Kind kind() const { return kind_; } |
| 1867 |
| 1868 private: |
| 1869 Token::Kind kind_; |
| 1870 }; |
| 1871 |
| 1872 |
| 1873 // Inlined functions from class BranchInstr that forward to their comparison. |
| 1874 inline intptr_t BranchInstr::ArgumentCount() const { |
| 1875 return computation()->ArgumentCount(); |
| 1876 } |
| 1877 |
| 1878 |
| 1879 inline intptr_t BranchInstr::InputCount() const { |
| 1880 return computation()->InputCount(); |
| 1881 } |
| 1882 |
| 1883 |
| 1884 inline Value* BranchInstr::InputAt(intptr_t i) const { |
| 1885 return computation()->InputAt(i); |
| 1886 } |
| 1887 |
| 1888 |
| 1889 inline void BranchInstr::SetInputAt(intptr_t i, Value* value) { |
| 1890 computation()->SetInputAt(i, value); |
| 1891 } |
| 1892 |
| 1893 |
| 1894 inline bool BranchInstr::CanDeoptimize() const { |
| 1895 return computation()->CanDeoptimize(); |
| 1896 } |
| 1897 |
| 1898 |
| 1899 inline LocationSummary* BranchInstr::locs() { |
| 1900 if (computation_->locs_ == NULL) { |
| 1901 LocationSummary* summary = computation_->MakeLocationSummary(); |
| 1902 // Branches don't produce a result. |
| 1903 summary->set_out(Location::NoLocation()); |
| 1904 computation_->locs_ = summary; |
| 1905 } |
| 1906 return computation_->locs_; |
| 1907 } |
| 1908 |
| 1909 |
| 1910 inline intptr_t BranchInstr::DeoptimizationTarget() const { |
| 1911 return computation_->DeoptimizationTarget(); |
| 1912 } |
| 1913 |
| 1914 |
| 1915 inline Representation BranchInstr::RequiredInputRepresentation( |
| 1916 intptr_t i) const { |
| 1917 return computation()->RequiredInputRepresentation(i); |
| 1918 } |
| 1919 |
| 1920 |
| 1921 class StrictCompareComp : public ComparisonComp { |
| 1922 public: |
| 1923 StrictCompareComp(Token::Kind kind, Value* left, Value* right) |
| 1924 : ComparisonComp(kind, left, right) { |
| 1925 ASSERT((kind == Token::kEQ_STRICT) || (kind == Token::kNE_STRICT)); |
| 1926 } |
| 1927 |
| 1928 DECLARE_COMPUTATION(StrictCompare) |
| 1929 |
| 1930 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 1931 |
| 1932 virtual bool CanDeoptimize() const { return false; } |
| 1933 |
| 1934 virtual Definition* TryReplace(BindInstr* instr) const; |
| 1935 |
| 1936 virtual intptr_t ResultCid() const { return kBoolCid; } |
| 1937 |
| 1938 virtual void EmitBranchCode(FlowGraphCompiler* compiler, |
| 1939 BranchInstr* branch); |
| 1940 |
| 1941 private: |
| 1942 DISALLOW_COPY_AND_ASSIGN(StrictCompareComp); |
| 1943 }; |
| 1944 |
| 1945 |
| 1946 class EqualityCompareComp : public ComparisonComp { |
| 1947 public: |
| 1948 EqualityCompareComp(intptr_t token_pos, |
| 1949 Token::Kind kind, |
| 1950 Value* left, |
| 1951 Value* right) |
| 1952 : ComparisonComp(kind, left, right), |
| 1953 ic_data_(Isolate::Current()->GetICDataForDeoptId(deopt_id())), |
| 1954 token_pos_(token_pos), |
| 1955 receiver_class_id_(kIllegalCid) { |
| 1956 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); |
| 1957 } |
| 1958 |
| 1959 DECLARE_COMPUTATION(EqualityCompare) |
| 1960 |
| 1961 const ICData* ic_data() const { return ic_data_; } |
| 1962 bool HasICData() const { |
| 1963 return (ic_data() != NULL) && !ic_data()->IsNull(); |
| 1964 } |
| 1965 |
| 1966 intptr_t token_pos() const { return token_pos_; } |
| 1967 |
| 1968 // Receiver class id is computed from collected ICData. |
| 1969 void set_receiver_class_id(intptr_t value) { receiver_class_id_ = value; } |
| 1970 intptr_t receiver_class_id() const { return receiver_class_id_; } |
| 1971 |
| 1972 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 1973 |
| 1974 virtual bool CanDeoptimize() const { |
| 1975 return (receiver_class_id() != kDoubleCid); |
| 1976 } |
| 1977 |
| 1978 virtual intptr_t ResultCid() const; |
| 1979 |
| 1980 virtual void EmitBranchCode(FlowGraphCompiler* compiler, |
| 1981 BranchInstr* branch); |
| 1982 |
| 1983 virtual intptr_t DeoptimizationTarget() const { |
| 1984 return GetDeoptId(); |
| 1985 } |
| 1986 |
| 1987 virtual Representation RequiredInputRepresentation(intptr_t idx) const { |
| 1988 ASSERT((idx == 0) || (idx == 1)); |
| 1989 return (receiver_class_id() == kDoubleCid) ? kUnboxedDouble : kTagged; |
| 1990 } |
| 1991 |
| 1992 private: |
| 1993 const ICData* ic_data_; |
| 1994 const intptr_t token_pos_; |
| 1995 intptr_t receiver_class_id_; // Set by optimizer. |
| 1996 |
| 1997 DISALLOW_COPY_AND_ASSIGN(EqualityCompareComp); |
| 1998 }; |
| 1999 |
| 2000 |
| 2001 class RelationalOpComp : public ComparisonComp { |
| 2002 public: |
| 2003 RelationalOpComp(intptr_t token_pos, |
| 2004 Token::Kind kind, |
| 2005 Value* left, |
| 2006 Value* right) |
| 2007 : ComparisonComp(kind, left, right), |
| 2008 ic_data_(Isolate::Current()->GetICDataForDeoptId(deopt_id())), |
| 2009 token_pos_(token_pos), |
| 2010 operands_class_id_(kIllegalCid) { |
| 2011 ASSERT(Token::IsRelationalOperator(kind)); |
| 2012 } |
| 2013 |
| 2014 DECLARE_COMPUTATION(RelationalOp) |
| 2015 |
| 2016 const ICData* ic_data() const { return ic_data_; } |
| 2017 bool HasICData() const { |
| 2018 return (ic_data() != NULL) && !ic_data()->IsNull(); |
| 2019 } |
| 2020 |
| 2021 intptr_t token_pos() const { return token_pos_; } |
| 2022 |
| 2023 // TODO(srdjan): instead of class-id pass an enum that can differentiate |
| 2024 // between boxed and unboxed doubles and integers. |
| 2025 void set_operands_class_id(intptr_t value) { |
| 2026 operands_class_id_ = value; |
| 2027 } |
| 2028 |
| 2029 intptr_t operands_class_id() const { return operands_class_id_; } |
| 2030 |
| 2031 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 2032 |
| 2033 virtual bool CanDeoptimize() const { |
| 2034 return operands_class_id() != kDoubleCid; |
| 2035 } |
| 2036 |
| 2037 virtual intptr_t ResultCid() const; |
| 2038 |
| 2039 virtual void EmitBranchCode(FlowGraphCompiler* compiler, |
| 2040 BranchInstr* branch); |
| 2041 |
| 2042 |
| 2043 virtual intptr_t DeoptimizationTarget() const { |
| 2044 return GetDeoptId(); |
| 2045 } |
| 2046 |
| 2047 virtual Representation RequiredInputRepresentation(intptr_t idx) const { |
| 2048 ASSERT((idx == 0) || (idx == 1)); |
| 2049 return (operands_class_id() == kDoubleCid) ? kUnboxedDouble : kTagged; |
| 2050 } |
| 2051 |
| 2052 private: |
| 2053 const ICData* ic_data_; |
| 2054 const intptr_t token_pos_; |
| 2055 intptr_t operands_class_id_; // class id of both operands. |
| 2056 |
| 2057 DISALLOW_COPY_AND_ASSIGN(RelationalOpComp); |
| 2058 }; |
| 2059 |
| 2060 |
| 2061 class StaticCallComp : public TemplateComputation<0> { |
| 2062 public: |
| 2063 StaticCallComp(intptr_t token_pos, |
| 2064 const Function& function, |
| 2065 const Array& argument_names, |
| 2066 ZoneGrowableArray<PushArgumentInstr*>* arguments) |
| 2067 : token_pos_(token_pos), |
| 2068 function_(function), |
| 2069 argument_names_(argument_names), |
| 2070 arguments_(arguments), |
| 2071 recognized_(MethodRecognizer::kUnknown) { |
| 2072 ASSERT(function.IsZoneHandle()); |
| 2073 ASSERT(argument_names.IsZoneHandle()); |
| 2074 } |
| 2075 |
| 2076 DECLARE_CALL_COMPUTATION(StaticCall) |
| 2077 |
| 2078 // Accessors forwarded to the AST node. |
| 2079 const Function& function() const { return function_; } |
| 2080 const Array& argument_names() const { return argument_names_; } |
| 2081 intptr_t token_pos() const { return token_pos_; } |
| 2082 |
| 2083 virtual intptr_t ArgumentCount() const { return arguments_->length(); } |
| 2084 PushArgumentInstr* ArgumentAt(intptr_t index) const { |
| 2085 return (*arguments_)[index]; |
| 2086 } |
| 2087 |
| 2088 MethodRecognizer::Kind recognized() const { return recognized_; } |
| 2089 void set_recognized(MethodRecognizer::Kind kind) { recognized_ = kind; } |
| 2090 |
| 2091 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 2092 |
| 2093 virtual bool CanDeoptimize() const { return true; } |
| 2094 virtual intptr_t ResultCid() const { return kDynamicCid; } |
| 2095 |
| 2096 private: |
| 2097 const intptr_t token_pos_; |
| 2098 const Function& function_; |
| 2099 const Array& argument_names_; |
| 2100 ZoneGrowableArray<PushArgumentInstr*>* arguments_; |
| 2101 MethodRecognizer::Kind recognized_; |
| 2102 |
| 2103 DISALLOW_COPY_AND_ASSIGN(StaticCallComp); |
| 2104 }; |
| 2105 |
| 2106 |
| 2107 class LoadLocalComp : public TemplateComputation<0> { |
| 2108 public: |
| 2109 LoadLocalComp(const LocalVariable& local, intptr_t context_level) |
| 2110 : local_(local), |
| 2111 context_level_(context_level) { } |
| 2112 |
| 2113 DECLARE_COMPUTATION(LoadLocal) |
| 2114 |
| 2115 const LocalVariable& local() const { return local_; } |
| 2116 intptr_t context_level() const { return context_level_; } |
| 2117 |
| 2118 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 2119 |
| 2120 virtual bool CanDeoptimize() const { return false; } |
| 2121 virtual intptr_t ResultCid() const { return kDynamicCid; } |
| 2122 |
| 2123 private: |
| 2124 const LocalVariable& local_; |
| 2125 const intptr_t context_level_; |
| 2126 |
| 2127 DISALLOW_COPY_AND_ASSIGN(LoadLocalComp); |
| 2128 }; |
| 2129 |
| 2130 |
| 2131 class StoreLocalComp : public TemplateComputation<1> { |
| 2132 public: |
| 2133 StoreLocalComp(const LocalVariable& local, |
| 2134 Value* value, |
| 2135 intptr_t context_level) |
| 2136 : local_(local), |
| 2137 context_level_(context_level) { |
| 2138 ASSERT(value != NULL); |
| 2139 inputs_[0] = value; |
| 2140 } |
| 2141 |
| 2142 DECLARE_COMPUTATION(StoreLocal) |
| 2143 |
| 2144 const LocalVariable& local() const { return local_; } |
| 2145 Value* value() const { return inputs_[0]; } |
| 2146 intptr_t context_level() const { return context_level_; } |
| 2147 |
| 2148 virtual void RecordAssignedVars(BitVector* assigned_vars, |
| 2149 intptr_t fixed_parameter_count); |
| 2150 |
| 2151 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 2152 |
| 2153 virtual bool CanDeoptimize() const { return false; } |
| 2154 virtual intptr_t ResultCid() const { return kDynamicCid; } |
| 2155 |
| 2156 private: |
| 2157 const LocalVariable& local_; |
| 2158 const intptr_t context_level_; |
| 2159 |
| 2160 DISALLOW_COPY_AND_ASSIGN(StoreLocalComp); |
| 2161 }; |
| 2162 |
| 2163 |
| 2164 class NativeCallComp : public TemplateComputation<0> { |
| 2165 public: |
| 2166 explicit NativeCallComp(NativeBodyNode* node) |
| 2167 : ast_node_(*node) {} |
| 2168 |
| 2169 DECLARE_COMPUTATION(NativeCall) |
| 2170 |
| 2171 intptr_t token_pos() const { return ast_node_.token_pos(); } |
| 2172 |
| 2173 const String& native_name() const { |
| 2174 return ast_node_.native_c_function_name(); |
| 2175 } |
| 2176 |
| 2177 NativeFunction native_c_function() const { |
| 2178 return ast_node_.native_c_function(); |
| 2179 } |
| 2180 |
| 2181 intptr_t argument_count() const { return ast_node_.argument_count(); } |
| 2182 |
| 2183 bool has_optional_parameters() const { |
| 2184 return ast_node_.has_optional_parameters(); |
| 2185 } |
| 2186 |
| 2187 bool is_native_instance_closure() const { |
| 2188 return ast_node_.is_native_instance_closure(); |
| 2189 } |
| 2190 |
| 2191 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 2192 |
| 2193 virtual bool CanDeoptimize() const { return false; } |
| 2194 virtual intptr_t ResultCid() const { return kDynamicCid; } |
| 2195 |
| 2196 private: |
| 2197 const NativeBodyNode& ast_node_; |
| 2198 |
| 2199 DISALLOW_COPY_AND_ASSIGN(NativeCallComp); |
| 2200 }; |
| 2201 |
| 2202 |
| 2203 class LoadInstanceFieldComp : public TemplateComputation<1> { |
| 2204 public: |
| 2205 LoadInstanceFieldComp(const Field& field, Value* instance) : field_(field) { |
| 2206 ASSERT(instance != NULL); |
| 2207 inputs_[0] = instance; |
| 2208 } |
| 2209 |
| 2210 DECLARE_COMPUTATION(LoadInstanceField) |
| 2211 |
| 2212 const Field& field() const { return field_; } |
| 2213 Value* instance() const { return inputs_[0]; } |
| 2214 |
| 2215 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 2216 |
| 2217 virtual bool CanDeoptimize() const { return false; } |
| 2218 virtual intptr_t ResultCid() const { return kDynamicCid; } |
| 2219 |
| 2220 private: |
| 2221 const Field& field_; |
| 2222 |
| 2223 DISALLOW_COPY_AND_ASSIGN(LoadInstanceFieldComp); |
| 2224 }; |
| 2225 |
| 2226 |
| 2227 class StoreInstanceFieldComp : public TemplateComputation<2> { |
| 2228 public: |
| 2229 StoreInstanceFieldComp(const Field& field, |
| 2230 Value* instance, |
| 2231 Value* value) |
| 2232 : field_(field) { |
| 2233 ASSERT(instance != NULL); |
| 2234 ASSERT(value != NULL); |
| 2235 inputs_[0] = instance; |
| 2236 inputs_[1] = value; |
| 2237 } |
| 2238 |
| 2239 DECLARE_COMPUTATION(StoreInstanceField) |
| 2240 |
| 2241 const Field& field() const { return field_; } |
| 2242 |
| 2243 Value* instance() const { return inputs_[0]; } |
| 2244 Value* value() const { return inputs_[1]; } |
| 2245 |
| 2246 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 2247 |
| 2248 virtual bool CanDeoptimize() const { return false; } |
| 2249 virtual intptr_t ResultCid() const { return kDynamicCid; } |
| 2250 |
| 2251 private: |
| 2252 const Field& field_; |
| 2253 |
| 2254 DISALLOW_COPY_AND_ASSIGN(StoreInstanceFieldComp); |
| 2255 }; |
| 2256 |
| 2257 |
| 2258 class LoadStaticFieldComp : public TemplateComputation<0> { |
| 2259 public: |
| 2260 explicit LoadStaticFieldComp(const Field& field) : field_(field) {} |
| 2261 |
| 2262 DECLARE_COMPUTATION(LoadStaticField); |
| 2263 |
| 2264 const Field& field() const { return field_; } |
| 2265 |
| 2266 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 2267 |
| 2268 virtual bool CanDeoptimize() const { return false; } |
| 2269 virtual intptr_t ResultCid() const { return kDynamicCid; } |
| 2270 |
| 2271 private: |
| 2272 const Field& field_; |
| 2273 |
| 2274 DISALLOW_COPY_AND_ASSIGN(LoadStaticFieldComp); |
| 2275 }; |
| 2276 |
| 2277 |
| 2278 class StoreStaticFieldComp : public TemplateComputation<1> { |
| 2279 public: |
| 2280 StoreStaticFieldComp(const Field& field, Value* value) |
| 2281 : field_(field) { |
| 2282 ASSERT(field.IsZoneHandle()); |
| 2283 ASSERT(value != NULL); |
| 2284 inputs_[0] = value; |
| 2285 } |
| 2286 |
| 2287 DECLARE_COMPUTATION(StoreStaticField); |
| 2288 |
| 2289 const Field& field() const { return field_; } |
| 2290 Value* value() const { return inputs_[0]; } |
| 2291 |
| 2292 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 2293 |
| 2294 virtual bool CanDeoptimize() const { return false; } |
| 2295 virtual intptr_t ResultCid() const { return kDynamicCid; } |
| 2296 |
| 2297 private: |
| 2298 const Field& field_; |
| 2299 |
| 2300 DISALLOW_COPY_AND_ASSIGN(StoreStaticFieldComp); |
| 2301 }; |
| 2302 |
| 2303 |
| 2304 class LoadIndexedComp : public TemplateComputation<2> { |
| 2305 public: |
| 2306 LoadIndexedComp(Value* array, |
| 2307 Value* index, |
| 2308 intptr_t receiver_type) |
| 2309 : receiver_type_(receiver_type) { |
| 2310 ASSERT(array != NULL); |
| 2311 ASSERT(index != NULL); |
| 2312 inputs_[0] = array; |
| 2313 inputs_[1] = index; |
| 2314 } |
| 2315 |
| 2316 DECLARE_COMPUTATION(LoadIndexed) |
| 2317 |
| 2318 Value* array() const { return inputs_[0]; } |
| 2319 Value* index() const { return inputs_[1]; } |
| 2320 |
| 2321 intptr_t receiver_type() const { return receiver_type_; } |
| 2322 |
| 2323 virtual bool CanDeoptimize() const { return false; } |
| 2324 virtual intptr_t ResultCid() const { return kDynamicCid; } |
| 2325 |
| 2326 private: |
| 2327 intptr_t receiver_type_; |
| 2328 |
| 2329 DISALLOW_COPY_AND_ASSIGN(LoadIndexedComp); |
| 2330 }; |
| 2331 |
| 2332 |
| 2333 class StoreIndexedComp : public TemplateComputation<3> { |
| 2334 public: |
| 2335 StoreIndexedComp(Value* array, |
| 2336 Value* index, |
| 2337 Value* value, |
| 2338 intptr_t receiver_type) |
| 2339 : receiver_type_(receiver_type) { |
| 2340 ASSERT(array != NULL); |
| 2341 ASSERT(index != NULL); |
| 2342 ASSERT(value != NULL); |
| 2343 inputs_[0] = array; |
| 2344 inputs_[1] = index; |
| 2345 inputs_[2] = value; |
| 2346 } |
| 2347 |
| 2348 DECLARE_COMPUTATION(StoreIndexed) |
| 2349 |
| 2350 Value* array() const { return inputs_[0]; } |
| 2351 Value* index() const { return inputs_[1]; } |
| 2352 Value* value() const { return inputs_[2]; } |
| 2353 |
| 2354 intptr_t receiver_type() const { return receiver_type_; } |
| 2355 |
| 2356 virtual bool CanDeoptimize() const { return false; } |
| 2357 virtual intptr_t ResultCid() const { return kDynamicCid; } |
| 2358 |
| 2359 private: |
| 2360 intptr_t receiver_type_; |
| 2361 |
| 2362 DISALLOW_COPY_AND_ASSIGN(StoreIndexedComp); |
| 2363 }; |
| 2364 |
| 2365 |
| 2366 // Note overrideable, built-in: value? false : true. |
| 2367 class BooleanNegateComp : public TemplateComputation<1> { |
| 2368 public: |
| 2369 explicit BooleanNegateComp(Value* value) { |
| 2370 ASSERT(value != NULL); |
| 2371 inputs_[0] = value; |
| 2372 } |
| 2373 |
| 2374 DECLARE_COMPUTATION(BooleanNegate) |
| 2375 |
| 2376 Value* value() const { return inputs_[0]; } |
| 2377 |
| 2378 virtual bool CanDeoptimize() const { return false; } |
| 2379 virtual intptr_t ResultCid() const { return kBoolCid; } |
| 2380 |
| 2381 private: |
| 2382 DISALLOW_COPY_AND_ASSIGN(BooleanNegateComp); |
| 2383 }; |
| 2384 |
| 2385 |
| 2386 class InstanceOfComp : public TemplateComputation<3> { |
| 2387 public: |
| 2388 InstanceOfComp(intptr_t token_pos, |
| 2389 Value* value, |
| 2390 Value* instantiator, |
| 2391 Value* instantiator_type_arguments, |
| 2392 const AbstractType& type, |
| 2393 bool negate_result) |
| 2394 : token_pos_(token_pos), |
| 2395 type_(type), |
| 2396 negate_result_(negate_result) { |
| 2397 ASSERT(value != NULL); |
| 2398 ASSERT(instantiator != NULL); |
| 2399 ASSERT(instantiator_type_arguments != NULL); |
| 2400 ASSERT(!type.IsNull()); |
| 2401 inputs_[0] = value; |
| 2402 inputs_[1] = instantiator; |
| 2403 inputs_[2] = instantiator_type_arguments; |
| 2404 } |
| 2405 |
| 2406 DECLARE_COMPUTATION(InstanceOf) |
| 2407 |
| 2408 Value* value() const { return inputs_[0]; } |
| 2409 Value* instantiator() const { return inputs_[1]; } |
| 2410 Value* instantiator_type_arguments() const { return inputs_[2]; } |
| 2411 |
| 2412 bool negate_result() const { return negate_result_; } |
| 2413 const AbstractType& type() const { return type_; } |
| 2414 intptr_t token_pos() const { return token_pos_; } |
| 2415 |
| 2416 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 2417 |
| 2418 virtual bool CanDeoptimize() const { return false; } |
| 2419 virtual intptr_t ResultCid() const { return kBoolCid; } |
| 2420 |
| 2421 private: |
| 2422 const intptr_t token_pos_; |
| 2423 Value* value_; |
| 2424 Value* instantiator_; |
| 2425 Value* type_arguments_; |
| 2426 const AbstractType& type_; |
| 2427 const bool negate_result_; |
| 2428 |
| 2429 DISALLOW_COPY_AND_ASSIGN(InstanceOfComp); |
| 2430 }; |
| 2431 |
| 2432 |
| 2433 class AllocateObjectComp : public TemplateComputation<0> { |
| 2434 public: |
| 2435 AllocateObjectComp(ConstructorCallNode* node, |
| 2436 ZoneGrowableArray<PushArgumentInstr*>* arguments) |
| 2437 : ast_node_(*node), arguments_(arguments) { |
| 2438 // Either no arguments or one type-argument and one instantiator. |
| 2439 ASSERT(arguments->is_empty() || (arguments->length() == 2)); |
| 2440 } |
| 2441 |
| 2442 DECLARE_CALL_COMPUTATION(AllocateObject) |
| 2443 |
| 2444 virtual intptr_t ArgumentCount() const { return arguments_->length(); } |
| 2445 PushArgumentInstr* ArgumentAt(intptr_t index) const { |
| 2446 return (*arguments_)[index]; |
| 2447 } |
| 2448 |
| 2449 const Function& constructor() const { return ast_node_.constructor(); } |
| 2450 intptr_t token_pos() const { return ast_node_.token_pos(); } |
| 2451 |
| 2452 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 2453 |
| 2454 virtual bool CanDeoptimize() const { return false; } |
| 2455 virtual intptr_t ResultCid() const { return kDynamicCid; } |
| 2456 |
| 2457 private: |
| 2458 const ConstructorCallNode& ast_node_; |
| 2459 ZoneGrowableArray<PushArgumentInstr*>* const arguments_; |
| 2460 |
| 2461 DISALLOW_COPY_AND_ASSIGN(AllocateObjectComp); |
| 2462 }; |
| 2463 |
| 2464 |
| 2465 class AllocateObjectWithBoundsCheckComp : public TemplateComputation<2> { |
| 2466 public: |
| 2467 AllocateObjectWithBoundsCheckComp(ConstructorCallNode* node, |
| 2468 Value* type_arguments, |
| 2469 Value* instantiator) |
| 2470 : ast_node_(*node) { |
| 2471 ASSERT(type_arguments != NULL); |
| 2472 ASSERT(instantiator != NULL); |
| 2473 inputs_[0] = type_arguments; |
| 2474 inputs_[1] = instantiator; |
| 2475 } |
| 2476 |
| 2477 DECLARE_COMPUTATION(AllocateObjectWithBoundsCheck) |
| 2478 |
| 2479 const Function& constructor() const { return ast_node_.constructor(); } |
| 2480 intptr_t token_pos() const { return ast_node_.token_pos(); } |
| 2481 |
| 2482 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 2483 |
| 2484 virtual bool CanDeoptimize() const { return false; } |
| 2485 virtual intptr_t ResultCid() const { return kDynamicCid; } |
| 2486 |
| 2487 private: |
| 2488 const ConstructorCallNode& ast_node_; |
| 2489 |
| 2490 DISALLOW_COPY_AND_ASSIGN(AllocateObjectWithBoundsCheckComp); |
| 2491 }; |
| 2492 |
| 2493 |
| 2494 class CreateArrayComp : public TemplateComputation<1> { |
| 2495 public: |
| 2496 CreateArrayComp(intptr_t token_pos, |
| 2497 ZoneGrowableArray<PushArgumentInstr*>* arguments, |
| 2498 const AbstractType& type, |
| 2499 Value* element_type) |
| 2500 : token_pos_(token_pos), |
| 2501 arguments_(arguments), |
| 2502 type_(type) { |
| 2503 #if defined(DEBUG) |
| 2504 for (int i = 0; i < ArgumentCount(); ++i) { |
| 2505 ASSERT(ArgumentAt(i) != NULL); |
| 2506 } |
| 2507 ASSERT(element_type != NULL); |
| 2508 ASSERT(type_.IsZoneHandle()); |
| 2509 ASSERT(!type_.IsNull()); |
| 2510 ASSERT(type_.IsFinalized()); |
| 2511 #endif |
| 2512 inputs_[0] = element_type; |
| 2513 } |
| 2514 |
| 2515 DECLARE_CALL_COMPUTATION(CreateArray) |
| 2516 |
| 2517 virtual intptr_t ArgumentCount() const { return arguments_->length(); } |
| 2518 |
| 2519 intptr_t token_pos() const { return token_pos_; } |
| 2520 PushArgumentInstr* ArgumentAt(intptr_t i) const { return (*arguments_)[i]; } |
| 2521 const AbstractType& type() const { return type_; } |
| 2522 Value* element_type() const { return inputs_[0]; } |
| 2523 |
| 2524 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 2525 |
| 2526 virtual bool CanDeoptimize() const { return false; } |
| 2527 virtual intptr_t ResultCid() const { return kDynamicCid; } |
| 2528 |
| 2529 private: |
| 2530 const intptr_t token_pos_; |
| 2531 ZoneGrowableArray<PushArgumentInstr*>* const arguments_; |
| 2532 const AbstractType& type_; |
| 2533 |
| 2534 DISALLOW_COPY_AND_ASSIGN(CreateArrayComp); |
| 2535 }; |
| 2536 |
| 2537 |
| 2538 class CreateClosureComp : public TemplateComputation<0> { |
| 2539 public: |
| 2540 CreateClosureComp(ClosureNode* node, |
| 2541 ZoneGrowableArray<PushArgumentInstr*>* arguments) |
| 2542 : ast_node_(*node), |
| 2543 arguments_(arguments) { } |
| 2544 |
| 2545 DECLARE_CALL_COMPUTATION(CreateClosure) |
| 2546 |
| 2547 intptr_t token_pos() const { return ast_node_.token_pos(); } |
| 2548 const Function& function() const { return ast_node_.function(); } |
| 2549 |
| 2550 virtual intptr_t ArgumentCount() const { return arguments_->length(); } |
| 2551 PushArgumentInstr* ArgumentAt(intptr_t index) const { |
| 2552 return (*arguments_)[index]; |
| 2553 } |
| 2554 |
| 2555 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 2556 |
| 2557 virtual bool CanDeoptimize() const { return false; } |
| 2558 virtual intptr_t ResultCid() const { return kDynamicCid; } |
| 2559 |
| 2560 private: |
| 2561 const ClosureNode& ast_node_; |
| 2562 ZoneGrowableArray<PushArgumentInstr*>* arguments_; |
| 2563 |
| 2564 DISALLOW_COPY_AND_ASSIGN(CreateClosureComp); |
| 2565 }; |
| 2566 |
| 2567 |
| 2568 class LoadVMFieldComp : public TemplateComputation<1> { |
| 2569 public: |
| 2570 LoadVMFieldComp(Value* value, |
| 2571 intptr_t offset_in_bytes, |
| 2572 const AbstractType& type) |
| 2573 : offset_in_bytes_(offset_in_bytes), |
| 2574 type_(type), |
| 2575 result_cid_(kDynamicCid) { |
| 2576 ASSERT(value != NULL); |
| 2577 ASSERT(type.IsZoneHandle()); // May be null if field is not an instance. |
| 2578 inputs_[0] = value; |
| 2579 } |
| 2580 |
| 2581 DECLARE_COMPUTATION(LoadVMField) |
| 2582 |
| 2583 Value* value() const { return inputs_[0]; } |
| 2584 intptr_t offset_in_bytes() const { return offset_in_bytes_; } |
| 2585 const AbstractType& type() const { return type_; } |
| 2586 void set_result_cid(intptr_t value) { result_cid_ = value; } |
| 2587 |
| 2588 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 2589 |
| 2590 virtual bool CanDeoptimize() const { return false; } |
| 2591 virtual intptr_t ResultCid() const { return result_cid_; } |
| 2592 |
| 2593 private: |
| 2594 const intptr_t offset_in_bytes_; |
| 2595 const AbstractType& type_; |
| 2596 intptr_t result_cid_; |
| 2597 |
| 2598 DISALLOW_COPY_AND_ASSIGN(LoadVMFieldComp); |
| 2599 }; |
| 2600 |
| 2601 |
| 2602 class StoreVMFieldComp : public TemplateComputation<2> { |
| 2603 public: |
| 2604 StoreVMFieldComp(Value* dest, |
| 2605 intptr_t offset_in_bytes, |
| 2606 Value* value, |
| 2607 const AbstractType& type) |
| 2608 : offset_in_bytes_(offset_in_bytes), type_(type) { |
| 2609 ASSERT(value != NULL); |
| 2610 ASSERT(dest != NULL); |
| 2611 ASSERT(type.IsZoneHandle()); // May be null if field is not an instance. |
| 2612 inputs_[0] = value; |
| 2613 inputs_[1] = dest; |
| 2614 } |
| 2615 |
| 2616 DECLARE_COMPUTATION(StoreVMField) |
| 2617 |
| 2618 Value* value() const { return inputs_[0]; } |
| 2619 Value* dest() const { return inputs_[1]; } |
| 2620 intptr_t offset_in_bytes() const { return offset_in_bytes_; } |
| 2621 const AbstractType& type() const { return type_; } |
| 2622 |
| 2623 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 2624 |
| 2625 virtual bool CanDeoptimize() const { return false; } |
| 2626 virtual intptr_t ResultCid() const { return kDynamicCid; } |
| 2627 |
| 2628 private: |
| 2629 const intptr_t offset_in_bytes_; |
| 2630 const AbstractType& type_; |
| 2631 |
| 2632 DISALLOW_COPY_AND_ASSIGN(StoreVMFieldComp); |
| 2633 }; |
| 2634 |
| 2635 |
| 2636 class InstantiateTypeArgumentsComp : public TemplateComputation<1> { |
| 2637 public: |
| 2638 InstantiateTypeArgumentsComp(intptr_t token_pos, |
| 2639 const AbstractTypeArguments& type_arguments, |
| 2640 Value* instantiator) |
| 2641 : token_pos_(token_pos), |
| 2642 type_arguments_(type_arguments) { |
| 2643 ASSERT(type_arguments.IsZoneHandle()); |
| 2644 ASSERT(instantiator != NULL); |
| 2645 inputs_[0] = instantiator; |
| 2646 } |
| 2647 |
| 2648 DECLARE_COMPUTATION(InstantiateTypeArguments) |
| 2649 |
| 2650 Value* instantiator() const { return inputs_[0]; } |
| 2651 const AbstractTypeArguments& type_arguments() const { |
| 2652 return type_arguments_; |
| 2653 } |
| 2654 intptr_t token_pos() const { return token_pos_; } |
| 2655 |
| 2656 virtual void PrintOperandsTo(BufferFormatter* f) const; |
| 2657 |
| 2658 virtual bool CanDeoptimize() const { return false; } |
| 2659 virtual intptr_t ResultCid() const { return kDynamicCid; } |
| 2660 |
| 2661 private: |
| 2662 const intptr_t token_pos_; |
| 1499 const AbstractTypeArguments& type_arguments_; | 2663 const AbstractTypeArguments& type_arguments_; |
| 1500 | 2664 |
| 1501 DISALLOW_COPY_AND_ASSIGN(InstantiateTypeArgumentsComp); | 2665 DISALLOW_COPY_AND_ASSIGN(InstantiateTypeArgumentsComp); |
| 1502 }; | 2666 }; |
| 1503 | 2667 |
| 1504 | 2668 |
| 1505 class ExtractConstructorTypeArgumentsComp : public TemplateComputation<1> { | 2669 class ExtractConstructorTypeArgumentsComp : public TemplateComputation<1> { |
| 1506 public: | 2670 public: |
| 1507 ExtractConstructorTypeArgumentsComp( | 2671 ExtractConstructorTypeArgumentsComp( |
| 1508 intptr_t token_pos, | 2672 intptr_t token_pos, |
| (...skipping 644 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2153 if (!Is##ShortName()) return NULL; \ | 3317 if (!Is##ShortName()) return NULL; \ |
| 2154 return static_cast<const ClassName*>(this); \ | 3318 return static_cast<const ClassName*>(this); \ |
| 2155 } \ | 3319 } \ |
| 2156 ClassName* Computation::As##ShortName() { \ | 3320 ClassName* Computation::As##ShortName() { \ |
| 2157 if (!Is##ShortName()) return NULL; \ | 3321 if (!Is##ShortName()) return NULL; \ |
| 2158 return static_cast<ClassName*>(this); \ | 3322 return static_cast<ClassName*>(this); \ |
| 2159 } | 3323 } |
| 2160 FOR_EACH_COMPUTATION(DEFINE_COMPUTATION_PREDICATE) | 3324 FOR_EACH_COMPUTATION(DEFINE_COMPUTATION_PREDICATE) |
| 2161 #undef DEFINE_COMPUTATION_PREDICATE | 3325 #undef DEFINE_COMPUTATION_PREDICATE |
| 2162 | 3326 |
| 2163 // Instructions. | |
| 2164 | |
| 2165 // M is a single argument macro. It is applied to each concrete instruction | |
| 2166 // type name. The concrete instruction classes are the name with Instr | |
| 2167 // concatenated. | |
| 2168 #define FOR_EACH_INSTRUCTION(M) \ | |
| 2169 M(GraphEntry) \ | |
| 2170 M(JoinEntry) \ | |
| 2171 M(TargetEntry) \ | |
| 2172 M(Phi) \ | |
| 2173 M(Bind) \ | |
| 2174 M(Parameter) \ | |
| 2175 M(ParallelMove) \ | |
| 2176 M(PushArgument) \ | |
| 2177 M(Return) \ | |
| 2178 M(Throw) \ | |
| 2179 M(ReThrow) \ | |
| 2180 M(Goto) \ | |
| 2181 M(Branch) \ | |
| 2182 | |
| 2183 | |
| 2184 // Forward declarations for Instruction classes. | |
| 2185 class BlockEntryInstr; | |
| 2186 class FlowGraphBuilder; | |
| 2187 class Environment; | |
| 2188 | |
| 2189 #define FORWARD_DECLARATION(type) class type##Instr; | |
| 2190 FOR_EACH_INSTRUCTION(FORWARD_DECLARATION) | |
| 2191 #undef FORWARD_DECLARATION | |
| 2192 | |
| 2193 | |
| 2194 // Functions required in all concrete instruction classes. | |
| 2195 #define DECLARE_INSTRUCTION(type) \ | |
| 2196 virtual void Accept(FlowGraphVisitor* visitor); \ | |
| 2197 virtual bool Is##type() const { return true; } \ | |
| 2198 virtual type##Instr* As##type() { return this; } \ | |
| 2199 virtual const char* DebugName() const { return #type; } \ | |
| 2200 virtual void PrintTo(BufferFormatter* f) const; \ | |
| 2201 virtual void PrintToVisualizer(BufferFormatter* f) const; | |
| 2202 | |
| 2203 | |
| 2204 class Instruction : public ZoneAllocated { | |
| 2205 public: | |
| 2206 Instruction() | |
| 2207 : lifetime_position_(-1), previous_(NULL), next_(NULL), env_(NULL) { } | |
| 2208 | |
| 2209 virtual bool IsBlockEntry() const { return false; } | |
| 2210 BlockEntryInstr* AsBlockEntry() { | |
| 2211 return IsBlockEntry() ? reinterpret_cast<BlockEntryInstr*>(this) : NULL; | |
| 2212 } | |
| 2213 virtual bool IsDefinition() const { return false; } | |
| 2214 virtual Definition* AsDefinition() { return NULL; } | |
| 2215 virtual bool IsControl() const { return false; } | |
| 2216 | |
| 2217 virtual intptr_t InputCount() const = 0; | |
| 2218 virtual Value* InputAt(intptr_t i) const = 0; | |
| 2219 virtual void SetInputAt(intptr_t i, Value* value) = 0; | |
| 2220 | |
| 2221 // Call instructions override this function and return the | |
| 2222 // number of pushed arguments. | |
| 2223 virtual intptr_t ArgumentCount() const = 0; | |
| 2224 | |
| 2225 // Returns true, if this instruction can deoptimize. | |
| 2226 virtual bool CanDeoptimize() const = 0; | |
| 2227 | |
| 2228 // Visiting support. | |
| 2229 virtual void Accept(FlowGraphVisitor* visitor) = 0; | |
| 2230 | |
| 2231 Instruction* previous() const { return previous_; } | |
| 2232 void set_previous(Instruction* instr) { | |
| 2233 ASSERT(!IsBlockEntry()); | |
| 2234 previous_ = instr; | |
| 2235 } | |
| 2236 | |
| 2237 Instruction* next() const { return next_; } | |
| 2238 void set_next(Instruction* instr) { | |
| 2239 ASSERT(!IsGraphEntry()); | |
| 2240 ASSERT(!IsReturn()); | |
| 2241 ASSERT(!IsControl()); | |
| 2242 ASSERT(!IsPhi()); | |
| 2243 ASSERT(instr == NULL || !instr->IsBlockEntry()); | |
| 2244 // TODO(fschneider): Also add Throw and ReThrow to the list of instructions | |
| 2245 // that do not have a successor. Currently, the graph builder will continue | |
| 2246 // to append instruction in case of a Throw inside an expression. This | |
| 2247 // condition should be handled in the graph builder | |
| 2248 next_ = instr; | |
| 2249 } | |
| 2250 | |
| 2251 // Removed this instruction from the graph. | |
| 2252 Instruction* RemoveFromGraph(bool return_previous = true); | |
| 2253 | |
| 2254 // Normal instructions can have 0 (inside a block) or 1 (last instruction in | |
| 2255 // a block) successors. Branch instruction with >1 successors override this | |
| 2256 // function. | |
| 2257 virtual intptr_t SuccessorCount() const; | |
| 2258 virtual BlockEntryInstr* SuccessorAt(intptr_t index) const; | |
| 2259 | |
| 2260 void Goto(JoinEntryInstr* entry); | |
| 2261 | |
| 2262 // Discover basic-block structure by performing a recursive depth first | |
| 2263 // traversal of the instruction graph reachable from this instruction. As | |
| 2264 // a side effect, the block entry instructions in the graph are assigned | |
| 2265 // numbers in both preorder and postorder. The array 'preorder' maps | |
| 2266 // preorder block numbers to the block entry instruction with that number | |
| 2267 // and analogously for the array 'postorder'. The depth first spanning | |
| 2268 // tree is recorded in the array 'parent', which maps preorder block | |
| 2269 // numbers to the preorder number of the block's spanning-tree parent. | |
| 2270 // The array 'assigned_vars' maps preorder block numbers to the set of | |
| 2271 // assigned frame-allocated local variables in the block. As a side | |
| 2272 // effect of this function, the set of basic block predecessors (e.g., | |
| 2273 // block entry instructions of predecessor blocks) and also the last | |
| 2274 // instruction in the block is recorded in each entry instruction. | |
| 2275 virtual void DiscoverBlocks( | |
| 2276 BlockEntryInstr* current_block, | |
| 2277 GrowableArray<BlockEntryInstr*>* preorder, | |
| 2278 GrowableArray<BlockEntryInstr*>* postorder, | |
| 2279 GrowableArray<intptr_t>* parent, | |
| 2280 GrowableArray<BitVector*>* assigned_vars, | |
| 2281 intptr_t variable_count, | |
| 2282 intptr_t fixed_parameter_count) { | |
| 2283 // Never called for instructions except block entries and branches. | |
| 2284 UNREACHABLE(); | |
| 2285 } | |
| 2286 | |
| 2287 // Mutate assigned_vars to add the local variable index for all | |
| 2288 // frame-allocated locals assigned to by the instruction. | |
| 2289 virtual void RecordAssignedVars(BitVector* assigned_vars, | |
| 2290 intptr_t fixed_parameter_count); | |
| 2291 | |
| 2292 // Printing support. | |
| 2293 virtual void PrintTo(BufferFormatter* f) const = 0; | |
| 2294 virtual void PrintToVisualizer(BufferFormatter* f) const = 0; | |
| 2295 | |
| 2296 #define INSTRUCTION_TYPE_CHECK(type) \ | |
| 2297 virtual bool Is##type() const { return false; } \ | |
| 2298 virtual type##Instr* As##type() { return NULL; } | |
| 2299 FOR_EACH_INSTRUCTION(INSTRUCTION_TYPE_CHECK) | |
| 2300 #undef INSTRUCTION_TYPE_CHECK | |
| 2301 | |
| 2302 // Returns structure describing location constraints required | |
| 2303 // to emit native code for this instruction. | |
| 2304 virtual LocationSummary* locs() { | |
| 2305 // TODO(vegorov): This should be pure virtual method. | |
| 2306 // However we are temporary using NULL for instructions that | |
| 2307 // were not converted to the location based code generation yet. | |
| 2308 return NULL; | |
| 2309 } | |
| 2310 | |
| 2311 virtual void EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 2312 UNIMPLEMENTED(); | |
| 2313 } | |
| 2314 | |
| 2315 Environment* env() const { return env_; } | |
| 2316 void set_env(Environment* env) { env_ = env; } | |
| 2317 | |
| 2318 intptr_t lifetime_position() const { return lifetime_position_; } | |
| 2319 void set_lifetime_position(intptr_t pos) { | |
| 2320 lifetime_position_ = pos; | |
| 2321 } | |
| 2322 | |
| 2323 // Returns representation expected for the input operand at the given index. | |
| 2324 virtual Representation RequiredInputRepresentation(intptr_t idx) const { | |
| 2325 return kTagged; | |
| 2326 } | |
| 2327 | |
| 2328 // Representation of the value produced by this computation. | |
| 2329 virtual Representation representation() const { | |
| 2330 return kTagged; | |
| 2331 } | |
| 2332 | |
| 2333 bool WasEliminated() const { | |
| 2334 return next() == NULL; | |
| 2335 } | |
| 2336 | |
| 2337 // Returns deoptimization id that corresponds to the deoptimization target | |
| 2338 // that input operands conversions inserted for this instruction can jump | |
| 2339 // to. | |
| 2340 virtual intptr_t DeoptimizationTarget() const { | |
| 2341 UNREACHABLE(); | |
| 2342 return Isolate::kNoDeoptId; | |
| 2343 } | |
| 2344 | |
| 2345 private: | |
| 2346 friend class BindInstr; // Needed for BindInstr::InsertBefore. | |
| 2347 | |
| 2348 intptr_t lifetime_position_; // Position used by register allocator. | |
| 2349 Instruction* previous_; | |
| 2350 Instruction* next_; | |
| 2351 Environment* env_; | |
| 2352 DISALLOW_COPY_AND_ASSIGN(Instruction); | |
| 2353 }; | |
| 2354 | |
| 2355 | |
| 2356 template<intptr_t N> | |
| 2357 class TemplateInstruction: public Instruction { | |
| 2358 public: | |
| 2359 TemplateInstruction<N>() : locs_(NULL) { } | |
| 2360 | |
| 2361 virtual intptr_t InputCount() const { return N; } | |
| 2362 virtual Value* InputAt(intptr_t i) const { return inputs_[i]; } | |
| 2363 virtual void SetInputAt(intptr_t i, Value* value) { | |
| 2364 ASSERT(value != NULL); | |
| 2365 inputs_[i] = value; | |
| 2366 } | |
| 2367 | |
| 2368 virtual LocationSummary* locs() { | |
| 2369 if (locs_ == NULL) { | |
| 2370 locs_ = MakeLocationSummary(); | |
| 2371 } | |
| 2372 return locs_; | |
| 2373 } | |
| 2374 | |
| 2375 virtual LocationSummary* MakeLocationSummary() const = 0; | |
| 2376 | |
| 2377 protected: | |
| 2378 EmbeddedArray<Value*, N> inputs_; | |
| 2379 | |
| 2380 private: | |
| 2381 LocationSummary* locs_; | |
| 2382 }; | |
| 2383 | |
| 2384 | |
| 2385 class MoveOperands : public ZoneAllocated { | |
| 2386 public: | |
| 2387 MoveOperands(Location dest, Location src) : dest_(dest), src_(src) { } | |
| 2388 | |
| 2389 Location src() const { return src_; } | |
| 2390 Location dest() const { return dest_; } | |
| 2391 | |
| 2392 Location* src_slot() { return &src_; } | |
| 2393 Location* dest_slot() { return &dest_; } | |
| 2394 | |
| 2395 void set_src(const Location& value) { src_ = value; } | |
| 2396 void set_dest(const Location& value) { dest_ = value; } | |
| 2397 | |
| 2398 // The parallel move resolver marks moves as "in-progress" by clearing the | |
| 2399 // destination (but not the source). | |
| 2400 Location MarkPending() { | |
| 2401 ASSERT(!IsPending()); | |
| 2402 Location dest = dest_; | |
| 2403 dest_ = Location::NoLocation(); | |
| 2404 return dest; | |
| 2405 } | |
| 2406 | |
| 2407 void ClearPending(Location dest) { | |
| 2408 ASSERT(IsPending()); | |
| 2409 dest_ = dest; | |
| 2410 } | |
| 2411 | |
| 2412 bool IsPending() const { | |
| 2413 ASSERT(!src_.IsInvalid() || dest_.IsInvalid()); | |
| 2414 return dest_.IsInvalid() && !src_.IsInvalid(); | |
| 2415 } | |
| 2416 | |
| 2417 // True if this move a move from the given location. | |
| 2418 bool Blocks(Location loc) const { | |
| 2419 return !IsEliminated() && src_.Equals(loc); | |
| 2420 } | |
| 2421 | |
| 2422 // A move is redundant if it's been eliminated, if its source and | |
| 2423 // destination are the same, or if its destination is unneeded. | |
| 2424 bool IsRedundant() const { | |
| 2425 return IsEliminated() || dest_.IsInvalid() || src_.Equals(dest_); | |
| 2426 } | |
| 2427 | |
| 2428 // We clear both operands to indicate move that's been eliminated. | |
| 2429 void Eliminate() { src_ = dest_ = Location::NoLocation(); } | |
| 2430 bool IsEliminated() const { | |
| 2431 ASSERT(!src_.IsInvalid() || dest_.IsInvalid()); | |
| 2432 return src_.IsInvalid(); | |
| 2433 } | |
| 2434 | |
| 2435 private: | |
| 2436 Location dest_; | |
| 2437 Location src_; | |
| 2438 | |
| 2439 DISALLOW_COPY_AND_ASSIGN(MoveOperands); | |
| 2440 }; | |
| 2441 | |
| 2442 | |
| 2443 class ParallelMoveInstr : public TemplateInstruction<0> { | |
| 2444 public: | |
| 2445 ParallelMoveInstr() : moves_(4) { } | |
| 2446 | |
| 2447 DECLARE_INSTRUCTION(ParallelMove) | |
| 2448 | |
| 2449 virtual intptr_t ArgumentCount() const { return 0; } | |
| 2450 | |
| 2451 virtual bool CanDeoptimize() const { return false; } | |
| 2452 | |
| 2453 MoveOperands* AddMove(Location dest, Location src) { | |
| 2454 MoveOperands* move = new MoveOperands(dest, src); | |
| 2455 moves_.Add(move); | |
| 2456 return move; | |
| 2457 } | |
| 2458 | |
| 2459 MoveOperands* MoveOperandsAt(intptr_t index) const { return moves_[index]; } | |
| 2460 | |
| 2461 void SetSrcSlotAt(intptr_t index, const Location& loc); | |
| 2462 void SetDestSlotAt(intptr_t index, const Location& loc); | |
| 2463 | |
| 2464 intptr_t NumMoves() const { return moves_.length(); } | |
| 2465 | |
| 2466 LocationSummary* MakeLocationSummary() const { return NULL; } | |
| 2467 | |
| 2468 void EmitNativeCode(FlowGraphCompiler* compiler) { UNREACHABLE(); } | |
| 2469 | |
| 2470 private: | |
| 2471 GrowableArray<MoveOperands*> moves_; // Elements cannot be null. | |
| 2472 | |
| 2473 DISALLOW_COPY_AND_ASSIGN(ParallelMoveInstr); | |
| 2474 }; | |
| 2475 | |
| 2476 | |
| 2477 // Basic block entries are administrative nodes. There is a distinguished | |
| 2478 // graph entry with no predecessor. Joins are the only nodes with multiple | |
| 2479 // predecessors. Targets are all other basic block entries. The types | |
| 2480 // enforce edge-split form---joins are forbidden as the successors of | |
| 2481 // branches. | |
| 2482 class BlockEntryInstr : public Instruction { | |
| 2483 public: | |
| 2484 virtual bool IsBlockEntry() const { return true; } | |
| 2485 | |
| 2486 virtual intptr_t PredecessorCount() const = 0; | |
| 2487 virtual BlockEntryInstr* PredecessorAt(intptr_t index) const = 0; | |
| 2488 virtual void AddPredecessor(BlockEntryInstr* predecessor) = 0; | |
| 2489 virtual void PrepareEntry(FlowGraphCompiler* compiler) = 0; | |
| 2490 | |
| 2491 intptr_t preorder_number() const { return preorder_number_; } | |
| 2492 void set_preorder_number(intptr_t number) { preorder_number_ = number; } | |
| 2493 | |
| 2494 intptr_t postorder_number() const { return postorder_number_; } | |
| 2495 void set_postorder_number(intptr_t number) { postorder_number_ = number; } | |
| 2496 | |
| 2497 intptr_t block_id() const { return block_id_; } | |
| 2498 void set_block_id(intptr_t value) { block_id_ = value; } | |
| 2499 | |
| 2500 void set_start_pos(intptr_t pos) { start_pos_ = pos; } | |
| 2501 intptr_t start_pos() const { return start_pos_; } | |
| 2502 void set_end_pos(intptr_t pos) { end_pos_ = pos; } | |
| 2503 intptr_t end_pos() const { return end_pos_; } | |
| 2504 | |
| 2505 BlockEntryInstr* dominator() const { return dominator_; } | |
| 2506 void set_dominator(BlockEntryInstr* instr) { dominator_ = instr; } | |
| 2507 | |
| 2508 const GrowableArray<BlockEntryInstr*>& dominated_blocks() { | |
| 2509 return dominated_blocks_; | |
| 2510 } | |
| 2511 | |
| 2512 void AddDominatedBlock(BlockEntryInstr* block) { | |
| 2513 dominated_blocks_.Add(block); | |
| 2514 } | |
| 2515 | |
| 2516 Instruction* last_instruction() const { return last_instruction_; } | |
| 2517 void set_last_instruction(Instruction* instr) { last_instruction_ = instr; } | |
| 2518 | |
| 2519 ParallelMoveInstr* parallel_move() const { | |
| 2520 return parallel_move_; | |
| 2521 } | |
| 2522 | |
| 2523 bool HasParallelMove() const { | |
| 2524 return parallel_move_ != NULL; | |
| 2525 } | |
| 2526 | |
| 2527 ParallelMoveInstr* GetParallelMove() { | |
| 2528 if (parallel_move_ == NULL) { | |
| 2529 parallel_move_ = new ParallelMoveInstr(); | |
| 2530 } | |
| 2531 return parallel_move_; | |
| 2532 } | |
| 2533 | |
| 2534 virtual void DiscoverBlocks( | |
| 2535 BlockEntryInstr* current_block, | |
| 2536 GrowableArray<BlockEntryInstr*>* preorder, | |
| 2537 GrowableArray<BlockEntryInstr*>* postorder, | |
| 2538 GrowableArray<intptr_t>* parent, | |
| 2539 GrowableArray<BitVector*>* assigned_vars, | |
| 2540 intptr_t variable_count, | |
| 2541 intptr_t fixed_parameter_count); | |
| 2542 | |
| 2543 virtual intptr_t InputCount() const { return 0; } | |
| 2544 virtual Value* InputAt(intptr_t i) const { | |
| 2545 UNREACHABLE(); | |
| 2546 return NULL; | |
| 2547 } | |
| 2548 virtual void SetInputAt(intptr_t i, Value* value) { UNREACHABLE(); } | |
| 2549 | |
| 2550 virtual intptr_t ArgumentCount() const { return 0; } | |
| 2551 | |
| 2552 virtual bool CanDeoptimize() const { return false; } | |
| 2553 | |
| 2554 intptr_t try_index() const { return try_index_; } | |
| 2555 | |
| 2556 protected: | |
| 2557 explicit BlockEntryInstr(intptr_t try_index) | |
| 2558 : try_index_(try_index), | |
| 2559 preorder_number_(-1), | |
| 2560 postorder_number_(-1), | |
| 2561 block_id_(-1), | |
| 2562 dominator_(NULL), | |
| 2563 dominated_blocks_(1), | |
| 2564 last_instruction_(NULL), | |
| 2565 parallel_move_(NULL) { } | |
| 2566 | |
| 2567 private: | |
| 2568 const intptr_t try_index_; | |
| 2569 intptr_t preorder_number_; | |
| 2570 intptr_t postorder_number_; | |
| 2571 // Starting and ending lifetime positions for this block. Used by | |
| 2572 // the linear scan register allocator. | |
| 2573 intptr_t block_id_; | |
| 2574 intptr_t start_pos_; | |
| 2575 intptr_t end_pos_; | |
| 2576 BlockEntryInstr* dominator_; // Immediate dominator, NULL for graph entry. | |
| 2577 // TODO(fschneider): Optimize the case of one child to save space. | |
| 2578 GrowableArray<BlockEntryInstr*> dominated_blocks_; | |
| 2579 Instruction* last_instruction_; | |
| 2580 | |
| 2581 // Parallel move that will be used by linear scan register allocator to | |
| 2582 // connect live ranges at the start of the block. | |
| 2583 ParallelMoveInstr* parallel_move_; | |
| 2584 | |
| 2585 DISALLOW_COPY_AND_ASSIGN(BlockEntryInstr); | |
| 2586 }; | |
| 2587 | |
| 2588 | |
| 2589 class ForwardInstructionIterator : public ValueObject { | |
| 2590 public: | |
| 2591 explicit ForwardInstructionIterator(BlockEntryInstr* block_entry) | |
| 2592 : block_entry_(block_entry), current_(block_entry) { | |
| 2593 ASSERT(block_entry_->last_instruction()->next() == NULL); | |
| 2594 Advance(); | |
| 2595 } | |
| 2596 | |
| 2597 void Advance() { | |
| 2598 ASSERT(!Done()); | |
| 2599 current_ = current_->next(); | |
| 2600 } | |
| 2601 | |
| 2602 bool Done() const { return current_ == NULL; } | |
| 2603 | |
| 2604 // Removes 'current_' from graph and sets 'current_' to previous instruction. | |
| 2605 void RemoveCurrentFromGraph(); | |
| 2606 | |
| 2607 Instruction* Current() const { return current_; } | |
| 2608 | |
| 2609 private: | |
| 2610 BlockEntryInstr* block_entry_; | |
| 2611 Instruction* current_; | |
| 2612 }; | |
| 2613 | |
| 2614 | |
| 2615 class BackwardInstructionIterator : public ValueObject { | |
| 2616 public: | |
| 2617 explicit BackwardInstructionIterator(BlockEntryInstr* block_entry) | |
| 2618 : block_entry_(block_entry), current_(block_entry->last_instruction()) { | |
| 2619 ASSERT(block_entry_->previous() == NULL); | |
| 2620 } | |
| 2621 | |
| 2622 void Advance() { | |
| 2623 ASSERT(!Done()); | |
| 2624 current_ = current_->previous(); | |
| 2625 } | |
| 2626 | |
| 2627 bool Done() const { return current_ == block_entry_; } | |
| 2628 | |
| 2629 Instruction* Current() const { return current_; } | |
| 2630 | |
| 2631 private: | |
| 2632 BlockEntryInstr* block_entry_; | |
| 2633 Instruction* current_; | |
| 2634 }; | |
| 2635 | |
| 2636 | |
| 2637 class GraphEntryInstr : public BlockEntryInstr { | |
| 2638 public: | |
| 2639 explicit GraphEntryInstr(TargetEntryInstr* normal_entry); | |
| 2640 | |
| 2641 DECLARE_INSTRUCTION(GraphEntry) | |
| 2642 | |
| 2643 virtual intptr_t PredecessorCount() const { return 0; } | |
| 2644 virtual BlockEntryInstr* PredecessorAt(intptr_t index) const { | |
| 2645 UNREACHABLE(); | |
| 2646 return NULL; | |
| 2647 } | |
| 2648 virtual void AddPredecessor(BlockEntryInstr* predecessor) { UNREACHABLE(); } | |
| 2649 | |
| 2650 virtual intptr_t SuccessorCount() const; | |
| 2651 virtual BlockEntryInstr* SuccessorAt(intptr_t index) const; | |
| 2652 | |
| 2653 virtual void DiscoverBlocks( | |
| 2654 BlockEntryInstr* current_block, | |
| 2655 GrowableArray<BlockEntryInstr*>* preorder, | |
| 2656 GrowableArray<BlockEntryInstr*>* postorder, | |
| 2657 GrowableArray<intptr_t>* parent, | |
| 2658 GrowableArray<BitVector*>* assigned_vars, | |
| 2659 intptr_t variable_count, | |
| 2660 intptr_t fixed_parameter_count); | |
| 2661 | |
| 2662 void AddCatchEntry(TargetEntryInstr* entry) { catch_entries_.Add(entry); } | |
| 2663 | |
| 2664 virtual void PrepareEntry(FlowGraphCompiler* compiler); | |
| 2665 | |
| 2666 Environment* start_env() const { return start_env_; } | |
| 2667 void set_start_env(Environment* env) { start_env_ = env; } | |
| 2668 | |
| 2669 Definition* constant_null() const { return constant_null_; } | |
| 2670 | |
| 2671 intptr_t spill_slot_count() const { return spill_slot_count_; } | |
| 2672 void set_spill_slot_count(intptr_t count) { | |
| 2673 ASSERT(count >= 0); | |
| 2674 spill_slot_count_ = count; | |
| 2675 } | |
| 2676 | |
| 2677 TargetEntryInstr* normal_entry() const { return normal_entry_; } | |
| 2678 | |
| 2679 private: | |
| 2680 TargetEntryInstr* normal_entry_; | |
| 2681 GrowableArray<TargetEntryInstr*> catch_entries_; | |
| 2682 Environment* start_env_; | |
| 2683 Definition* constant_null_; | |
| 2684 intptr_t spill_slot_count_; | |
| 2685 | |
| 2686 DISALLOW_COPY_AND_ASSIGN(GraphEntryInstr); | |
| 2687 }; | |
| 2688 | |
| 2689 | |
| 2690 class JoinEntryInstr : public BlockEntryInstr { | |
| 2691 public: | |
| 2692 explicit JoinEntryInstr(intptr_t try_index) | |
| 2693 : BlockEntryInstr(try_index), | |
| 2694 predecessors_(2), // Two is the assumed to be the common case. | |
| 2695 phis_(NULL), | |
| 2696 phi_count_(0) { } | |
| 2697 | |
| 2698 DECLARE_INSTRUCTION(JoinEntry) | |
| 2699 | |
| 2700 virtual intptr_t PredecessorCount() const { return predecessors_.length(); } | |
| 2701 virtual BlockEntryInstr* PredecessorAt(intptr_t index) const { | |
| 2702 return predecessors_[index]; | |
| 2703 } | |
| 2704 virtual void AddPredecessor(BlockEntryInstr* predecessor) { | |
| 2705 predecessors_.Add(predecessor); | |
| 2706 } | |
| 2707 | |
| 2708 // Returns -1 if pred is not in the list. | |
| 2709 intptr_t IndexOfPredecessor(BlockEntryInstr* pred) const; | |
| 2710 | |
| 2711 ZoneGrowableArray<PhiInstr*>* phis() const { return phis_; } | |
| 2712 | |
| 2713 virtual void PrepareEntry(FlowGraphCompiler* compiler); | |
| 2714 | |
| 2715 void InsertPhi(intptr_t var_index, intptr_t var_count); | |
| 2716 void RemoveDeadPhis(); | |
| 2717 | |
| 2718 intptr_t phi_count() const { return phi_count_; } | |
| 2719 | |
| 2720 private: | |
| 2721 GrowableArray<BlockEntryInstr*> predecessors_; | |
| 2722 ZoneGrowableArray<PhiInstr*>* phis_; | |
| 2723 intptr_t phi_count_; | |
| 2724 | |
| 2725 DISALLOW_COPY_AND_ASSIGN(JoinEntryInstr); | |
| 2726 }; | |
| 2727 | |
| 2728 | |
| 2729 class TargetEntryInstr : public BlockEntryInstr { | |
| 2730 public: | |
| 2731 explicit TargetEntryInstr(intptr_t try_index) | |
| 2732 : BlockEntryInstr(try_index), | |
| 2733 predecessor_(NULL), | |
| 2734 catch_try_index_(CatchClauseNode::kInvalidTryIndex) { } | |
| 2735 | |
| 2736 // Used for exception catch entries. | |
| 2737 TargetEntryInstr(intptr_t try_index, intptr_t catch_try_index) | |
| 2738 : BlockEntryInstr(try_index), | |
| 2739 predecessor_(NULL), | |
| 2740 catch_try_index_(catch_try_index) { } | |
| 2741 | |
| 2742 DECLARE_INSTRUCTION(TargetEntry) | |
| 2743 | |
| 2744 virtual intptr_t PredecessorCount() const { | |
| 2745 return (predecessor_ == NULL) ? 0 : 1; | |
| 2746 } | |
| 2747 virtual BlockEntryInstr* PredecessorAt(intptr_t index) const { | |
| 2748 ASSERT((index == 0) && (predecessor_ != NULL)); | |
| 2749 return predecessor_; | |
| 2750 } | |
| 2751 virtual void AddPredecessor(BlockEntryInstr* predecessor) { | |
| 2752 ASSERT(predecessor_ == NULL); | |
| 2753 predecessor_ = predecessor; | |
| 2754 } | |
| 2755 | |
| 2756 // Returns true if this Block is an entry of a catch handler. | |
| 2757 bool IsCatchEntry() const { | |
| 2758 return catch_try_index_ != CatchClauseNode::kInvalidTryIndex; | |
| 2759 } | |
| 2760 | |
| 2761 // Returns try index for the try block to which this catch handler | |
| 2762 // corresponds. | |
| 2763 intptr_t catch_try_index() const { | |
| 2764 ASSERT(IsCatchEntry()); | |
| 2765 return catch_try_index_; | |
| 2766 } | |
| 2767 | |
| 2768 virtual void PrepareEntry(FlowGraphCompiler* compiler); | |
| 2769 | |
| 2770 private: | |
| 2771 BlockEntryInstr* predecessor_; | |
| 2772 const intptr_t catch_try_index_; | |
| 2773 | |
| 2774 DISALLOW_COPY_AND_ASSIGN(TargetEntryInstr); | |
| 2775 }; | |
| 2776 | |
| 2777 | |
| 2778 // Abstract super-class of all instructions that define a value (Bind, Phi). | |
| 2779 class Definition : public Instruction { | |
| 2780 public: | |
| 2781 Definition() | |
| 2782 : temp_index_(-1), | |
| 2783 ssa_temp_index_(-1), | |
| 2784 propagated_type_(AbstractType::Handle()), | |
| 2785 propagated_cid_(kIllegalCid), | |
| 2786 input_use_list_(NULL), | |
| 2787 env_use_list_(NULL) { } | |
| 2788 | |
| 2789 virtual bool IsDefinition() const { return true; } | |
| 2790 virtual Definition* AsDefinition() { return this; } | |
| 2791 | |
| 2792 intptr_t temp_index() const { return temp_index_; } | |
| 2793 void set_temp_index(intptr_t index) { temp_index_ = index; } | |
| 2794 | |
| 2795 intptr_t ssa_temp_index() const { return ssa_temp_index_; } | |
| 2796 void set_ssa_temp_index(intptr_t index) { | |
| 2797 ASSERT(index >= 0); | |
| 2798 ssa_temp_index_ = index; | |
| 2799 } | |
| 2800 bool HasSSATemp() const { return ssa_temp_index_ >= 0; } | |
| 2801 | |
| 2802 // Compile time type of the definition, which may be requested before type | |
| 2803 // propagation during graph building. | |
| 2804 virtual RawAbstractType* CompileType() const = 0; | |
| 2805 | |
| 2806 bool HasPropagatedType() const { | |
| 2807 return !propagated_type_.IsNull(); | |
| 2808 } | |
| 2809 RawAbstractType* PropagatedType() const { | |
| 2810 ASSERT(HasPropagatedType()); | |
| 2811 return propagated_type_.raw(); | |
| 2812 } | |
| 2813 // Returns true if the propagated type has changed. | |
| 2814 bool SetPropagatedType(const AbstractType& propagated_type) { | |
| 2815 if (propagated_type.IsNull()) { | |
| 2816 // Not a typed definition, e.g. access to a VM field. | |
| 2817 return false; | |
| 2818 } | |
| 2819 const bool changed = | |
| 2820 propagated_type_.IsNull() || !propagated_type.Equals(propagated_type_); | |
| 2821 propagated_type_ = propagated_type.raw(); | |
| 2822 return changed; | |
| 2823 } | |
| 2824 | |
| 2825 bool has_propagated_cid() const { return propagated_cid_ != kIllegalCid; } | |
| 2826 intptr_t propagated_cid() const { return propagated_cid_; } | |
| 2827 // May compute and set propagated cid. | |
| 2828 virtual intptr_t GetPropagatedCid() = 0; | |
| 2829 | |
| 2830 // Returns true if the propagated cid has changed. | |
| 2831 bool SetPropagatedCid(intptr_t cid); | |
| 2832 | |
| 2833 Value* input_use_list() { return input_use_list_; } | |
| 2834 void set_input_use_list(Value* head) { input_use_list_ = head; } | |
| 2835 | |
| 2836 Value* env_use_list() { return env_use_list_; } | |
| 2837 void set_env_use_list(Value* head) { env_use_list_ = head; } | |
| 2838 | |
| 2839 // Replace uses of this definition with uses of other definition or value. | |
| 2840 // Precondition: use lists must be properly calculated. | |
| 2841 // Postcondition: use lists and use values are still valid. | |
| 2842 void ReplaceUsesWith(Definition* other); | |
| 2843 | |
| 2844 private: | |
| 2845 intptr_t temp_index_; | |
| 2846 intptr_t ssa_temp_index_; | |
| 2847 // TODO(regis): GrowableArray<const AbstractType*> propagated_types_; | |
| 2848 // For now: | |
| 2849 AbstractType& propagated_type_; | |
| 2850 intptr_t propagated_cid_; | |
| 2851 Value* input_use_list_; | |
| 2852 Value* env_use_list_; | |
| 2853 | |
| 2854 DISALLOW_COPY_AND_ASSIGN(Definition); | |
| 2855 }; | |
| 2856 | |
| 2857 | |
| 2858 class BindInstr : public Definition { | |
| 2859 public: | |
| 2860 enum UseKind { kUnused, kUsed }; | |
| 2861 | |
| 2862 BindInstr(UseKind used, Computation* computation) | |
| 2863 : computation_(computation), is_used_(used != kUnused) { | |
| 2864 ASSERT(computation != NULL); | |
| 2865 } | |
| 2866 | |
| 2867 DECLARE_INSTRUCTION(Bind) | |
| 2868 | |
| 2869 virtual intptr_t ArgumentCount() const { | |
| 2870 return computation()->ArgumentCount(); | |
| 2871 } | |
| 2872 intptr_t InputCount() const { return computation()->InputCount(); } | |
| 2873 | |
| 2874 Value* InputAt(intptr_t i) const { return computation()->InputAt(i); } | |
| 2875 | |
| 2876 void SetInputAt(intptr_t i, Value* value) { | |
| 2877 computation()->SetInputAt(i, value); | |
| 2878 } | |
| 2879 | |
| 2880 virtual bool CanDeoptimize() const { return computation()->CanDeoptimize(); } | |
| 2881 | |
| 2882 Computation* computation() const { return computation_; } | |
| 2883 void set_computation(Computation* value) { computation_ = value; } | |
| 2884 bool is_used() const { return is_used_; } | |
| 2885 | |
| 2886 virtual RawAbstractType* CompileType() const; | |
| 2887 virtual intptr_t GetPropagatedCid(); | |
| 2888 | |
| 2889 virtual void RecordAssignedVars(BitVector* assigned_vars, | |
| 2890 intptr_t fixed_parameter_count); | |
| 2891 | |
| 2892 intptr_t Hashcode() const { return computation()->Hashcode(); } | |
| 2893 | |
| 2894 bool Equals(BindInstr* other) const { | |
| 2895 return computation()->Equals(other->computation()); | |
| 2896 } | |
| 2897 | |
| 2898 virtual LocationSummary* locs() { | |
| 2899 return computation()->locs(); | |
| 2900 } | |
| 2901 | |
| 2902 virtual void EmitNativeCode(FlowGraphCompiler* compiler); | |
| 2903 | |
| 2904 // Insert this instruction before 'next'. | |
| 2905 void InsertBefore(Instruction* next); | |
| 2906 | |
| 2907 // Insert this instruction after 'prev'. | |
| 2908 void InsertAfter(Instruction* prev); | |
| 2909 | |
| 2910 virtual Representation RequiredInputRepresentation(intptr_t i) const { | |
| 2911 return computation()->RequiredInputRepresentation(i); | |
| 2912 } | |
| 2913 | |
| 2914 virtual Representation representation() const { | |
| 2915 return computation()->representation(); | |
| 2916 } | |
| 2917 | |
| 2918 virtual intptr_t DeoptimizationTarget() const { | |
| 2919 return computation()->DeoptimizationTarget(); | |
| 2920 } | |
| 2921 | |
| 2922 private: | |
| 2923 Computation* computation_; | |
| 2924 const bool is_used_; | |
| 2925 | |
| 2926 DISALLOW_COPY_AND_ASSIGN(BindInstr); | |
| 2927 }; | |
| 2928 | |
| 2929 | |
| 2930 class PhiInstr : public Definition { | |
| 2931 public: | |
| 2932 explicit PhiInstr(JoinEntryInstr* block, intptr_t num_inputs) | |
| 2933 : block_(block), | |
| 2934 inputs_(num_inputs), | |
| 2935 is_alive_(false), | |
| 2936 representation_(kTagged) { | |
| 2937 for (intptr_t i = 0; i < num_inputs; ++i) { | |
| 2938 inputs_.Add(NULL); | |
| 2939 } | |
| 2940 } | |
| 2941 | |
| 2942 JoinEntryInstr* block() const { return block_; } | |
| 2943 | |
| 2944 virtual RawAbstractType* CompileType() const; | |
| 2945 virtual intptr_t GetPropagatedCid() { return propagated_cid(); } | |
| 2946 | |
| 2947 virtual intptr_t ArgumentCount() const { return 0; } | |
| 2948 | |
| 2949 intptr_t InputCount() const { return inputs_.length(); } | |
| 2950 | |
| 2951 Value* InputAt(intptr_t i) const { return inputs_[i]; } | |
| 2952 | |
| 2953 void SetInputAt(intptr_t i, Value* value) { inputs_[i] = value; } | |
| 2954 | |
| 2955 virtual bool CanDeoptimize() const { return false; } | |
| 2956 | |
| 2957 // TODO(regis): This helper will be removed once we support type sets. | |
| 2958 RawAbstractType* LeastSpecificInputType() const; | |
| 2959 | |
| 2960 // Phi is alive if it reaches a non-environment use. | |
| 2961 bool is_alive() const { return is_alive_; } | |
| 2962 void mark_alive() { is_alive_ = true; } | |
| 2963 | |
| 2964 virtual Representation RequiredInputRepresentation(intptr_t i) const { | |
| 2965 return representation_; | |
| 2966 } | |
| 2967 | |
| 2968 virtual Representation representation() const { | |
| 2969 return representation_; | |
| 2970 } | |
| 2971 | |
| 2972 virtual void set_representation(Representation r) { | |
| 2973 representation_ = r; | |
| 2974 } | |
| 2975 | |
| 2976 DECLARE_INSTRUCTION(Phi) | |
| 2977 | |
| 2978 private: | |
| 2979 JoinEntryInstr* block_; | |
| 2980 GrowableArray<Value*> inputs_; | |
| 2981 bool is_alive_; | |
| 2982 Representation representation_; | |
| 2983 | |
| 2984 DISALLOW_COPY_AND_ASSIGN(PhiInstr); | |
| 2985 }; | |
| 2986 | |
| 2987 | |
| 2988 class ParameterInstr : public Definition { | |
| 2989 public: | |
| 2990 explicit ParameterInstr(intptr_t index) : index_(index) { } | |
| 2991 | |
| 2992 DECLARE_INSTRUCTION(Parameter) | |
| 2993 | |
| 2994 intptr_t index() const { return index_; } | |
| 2995 | |
| 2996 // Compile type of the passed-in parameter. | |
| 2997 virtual RawAbstractType* CompileType() const; | |
| 2998 // No known propagated cid for parameters. | |
| 2999 virtual intptr_t GetPropagatedCid() { return propagated_cid(); } | |
| 3000 | |
| 3001 virtual intptr_t ArgumentCount() const { return 0; } | |
| 3002 | |
| 3003 intptr_t InputCount() const { return 0; } | |
| 3004 Value* InputAt(intptr_t i) const { | |
| 3005 UNREACHABLE(); | |
| 3006 return NULL; | |
| 3007 } | |
| 3008 void SetInputAt(intptr_t i, Value* value) { UNREACHABLE(); } | |
| 3009 | |
| 3010 virtual bool CanDeoptimize() const { return false; } | |
| 3011 | |
| 3012 private: | |
| 3013 const intptr_t index_; | |
| 3014 | |
| 3015 DISALLOW_COPY_AND_ASSIGN(ParameterInstr); | |
| 3016 }; | |
| 3017 | |
| 3018 | |
| 3019 class PushArgumentInstr : public Definition { | |
| 3020 public: | |
| 3021 explicit PushArgumentInstr(Value* value) : value_(value), locs_(NULL) { | |
| 3022 ASSERT(value != NULL); | |
| 3023 } | |
| 3024 | |
| 3025 DECLARE_INSTRUCTION(PushArgument) | |
| 3026 | |
| 3027 intptr_t InputCount() const { return 1; } | |
| 3028 Value* InputAt(intptr_t i) const { | |
| 3029 ASSERT(i == 0); | |
| 3030 return value_; | |
| 3031 } | |
| 3032 void SetInputAt(intptr_t i, Value* value) { | |
| 3033 ASSERT(i == 0); | |
| 3034 value_ = value; | |
| 3035 } | |
| 3036 | |
| 3037 virtual intptr_t ArgumentCount() const { return 0; } | |
| 3038 | |
| 3039 virtual RawAbstractType* CompileType() const; | |
| 3040 virtual intptr_t GetPropagatedCid() { return propagated_cid(); } | |
| 3041 | |
| 3042 Value* value() const { return value_; } | |
| 3043 | |
| 3044 virtual LocationSummary* locs() { | |
| 3045 if (locs_ == NULL) { | |
| 3046 locs_ = MakeLocationSummary(); | |
| 3047 } | |
| 3048 return locs_; | |
| 3049 } | |
| 3050 | |
| 3051 LocationSummary* MakeLocationSummary() const; | |
| 3052 | |
| 3053 virtual void EmitNativeCode(FlowGraphCompiler* compiler); | |
| 3054 | |
| 3055 virtual bool CanDeoptimize() const { return false; } | |
| 3056 | |
| 3057 private: | |
| 3058 Value* value_; | |
| 3059 LocationSummary* locs_; | |
| 3060 | |
| 3061 DISALLOW_COPY_AND_ASSIGN(PushArgumentInstr); | |
| 3062 }; | |
| 3063 | |
| 3064 | |
| 3065 class ReturnInstr : public TemplateInstruction<1> { | |
| 3066 public: | |
| 3067 ReturnInstr(intptr_t token_pos, Value* value) | |
| 3068 : deopt_id_(Isolate::Current()->GetNextDeoptId()), | |
| 3069 token_pos_(token_pos) { | |
| 3070 ASSERT(value != NULL); | |
| 3071 inputs_[0] = value; | |
| 3072 } | |
| 3073 | |
| 3074 DECLARE_INSTRUCTION(Return) | |
| 3075 | |
| 3076 virtual intptr_t ArgumentCount() const { return 0; } | |
| 3077 | |
| 3078 intptr_t deopt_id() const { return deopt_id_; } | |
| 3079 intptr_t token_pos() const { return token_pos_; } | |
| 3080 Value* value() const { return inputs_[0]; } | |
| 3081 | |
| 3082 virtual LocationSummary* MakeLocationSummary() const; | |
| 3083 | |
| 3084 virtual void EmitNativeCode(FlowGraphCompiler* compiler); | |
| 3085 | |
| 3086 virtual bool CanDeoptimize() const { return false; } | |
| 3087 | |
| 3088 private: | |
| 3089 const intptr_t deopt_id_; | |
| 3090 const intptr_t token_pos_; | |
| 3091 | |
| 3092 DISALLOW_COPY_AND_ASSIGN(ReturnInstr); | |
| 3093 }; | |
| 3094 | |
| 3095 | |
| 3096 class ThrowInstr : public TemplateInstruction<0> { | |
| 3097 public: | |
| 3098 explicit ThrowInstr(intptr_t token_pos) : token_pos_(token_pos) { } | |
| 3099 | |
| 3100 DECLARE_INSTRUCTION(Throw) | |
| 3101 | |
| 3102 virtual intptr_t ArgumentCount() const { return 1; } | |
| 3103 | |
| 3104 intptr_t token_pos() const { return token_pos_; } | |
| 3105 | |
| 3106 virtual LocationSummary* MakeLocationSummary() const; | |
| 3107 | |
| 3108 virtual void EmitNativeCode(FlowGraphCompiler* compiler); | |
| 3109 | |
| 3110 virtual bool CanDeoptimize() const { return false; } | |
| 3111 | |
| 3112 private: | |
| 3113 const intptr_t token_pos_; | |
| 3114 | |
| 3115 DISALLOW_COPY_AND_ASSIGN(ThrowInstr); | |
| 3116 }; | |
| 3117 | |
| 3118 | |
| 3119 class ReThrowInstr : public TemplateInstruction<0> { | |
| 3120 public: | |
| 3121 explicit ReThrowInstr(intptr_t token_pos) : token_pos_(token_pos) { } | |
| 3122 | |
| 3123 DECLARE_INSTRUCTION(ReThrow) | |
| 3124 | |
| 3125 virtual intptr_t ArgumentCount() const { return 2; } | |
| 3126 | |
| 3127 intptr_t token_pos() const { return token_pos_; } | |
| 3128 | |
| 3129 virtual LocationSummary* MakeLocationSummary() const; | |
| 3130 | |
| 3131 virtual void EmitNativeCode(FlowGraphCompiler* compiler); | |
| 3132 | |
| 3133 virtual bool CanDeoptimize() const { return false; } | |
| 3134 | |
| 3135 private: | |
| 3136 const intptr_t token_pos_; | |
| 3137 | |
| 3138 DISALLOW_COPY_AND_ASSIGN(ReThrowInstr); | |
| 3139 }; | |
| 3140 | |
| 3141 | |
| 3142 class GotoInstr : public TemplateInstruction<0> { | |
| 3143 public: | |
| 3144 explicit GotoInstr(JoinEntryInstr* entry) | |
| 3145 : successor_(entry), | |
| 3146 parallel_move_(NULL) { } | |
| 3147 | |
| 3148 DECLARE_INSTRUCTION(Goto) | |
| 3149 | |
| 3150 virtual intptr_t ArgumentCount() const { return 0; } | |
| 3151 | |
| 3152 JoinEntryInstr* successor() const { return successor_; } | |
| 3153 void set_successor(JoinEntryInstr* successor) { successor_ = successor; } | |
| 3154 virtual intptr_t SuccessorCount() const; | |
| 3155 virtual BlockEntryInstr* SuccessorAt(intptr_t index) const; | |
| 3156 | |
| 3157 virtual LocationSummary* MakeLocationSummary() const; | |
| 3158 | |
| 3159 virtual void EmitNativeCode(FlowGraphCompiler* compiler); | |
| 3160 | |
| 3161 virtual bool CanDeoptimize() const { return false; } | |
| 3162 | |
| 3163 ParallelMoveInstr* parallel_move() const { | |
| 3164 return parallel_move_; | |
| 3165 } | |
| 3166 | |
| 3167 bool HasParallelMove() const { | |
| 3168 return parallel_move_ != NULL; | |
| 3169 } | |
| 3170 | |
| 3171 ParallelMoveInstr* GetParallelMove() { | |
| 3172 if (parallel_move_ == NULL) { | |
| 3173 parallel_move_ = new ParallelMoveInstr(); | |
| 3174 } | |
| 3175 return parallel_move_; | |
| 3176 } | |
| 3177 | |
| 3178 private: | |
| 3179 JoinEntryInstr* successor_; | |
| 3180 | |
| 3181 // Parallel move that will be used by linear scan register allocator to | |
| 3182 // connect live ranges at the end of the block and resolve phis. | |
| 3183 ParallelMoveInstr* parallel_move_; | |
| 3184 }; | |
| 3185 | |
| 3186 | |
| 3187 class ControlInstruction : public Instruction { | |
| 3188 public: | |
| 3189 ControlInstruction() : true_successor_(NULL), false_successor_(NULL) { } | |
| 3190 | |
| 3191 virtual bool IsControl() const { return true; } | |
| 3192 | |
| 3193 TargetEntryInstr* true_successor() const { return true_successor_; } | |
| 3194 TargetEntryInstr* false_successor() const { return false_successor_; } | |
| 3195 | |
| 3196 TargetEntryInstr** true_successor_address() { return &true_successor_; } | |
| 3197 TargetEntryInstr** false_successor_address() { return &false_successor_; } | |
| 3198 | |
| 3199 virtual intptr_t SuccessorCount() const; | |
| 3200 virtual BlockEntryInstr* SuccessorAt(intptr_t index) const; | |
| 3201 | |
| 3202 virtual void DiscoverBlocks( | |
| 3203 BlockEntryInstr* current_block, | |
| 3204 GrowableArray<BlockEntryInstr*>* preorder, | |
| 3205 GrowableArray<BlockEntryInstr*>* postorder, | |
| 3206 GrowableArray<intptr_t>* parent, | |
| 3207 GrowableArray<BitVector*>* assigned_vars, | |
| 3208 intptr_t variable_count, | |
| 3209 intptr_t fixed_parameter_count); | |
| 3210 | |
| 3211 | |
| 3212 void EmitBranchOnCondition(FlowGraphCompiler* compiler, | |
| 3213 Condition true_condition); | |
| 3214 | |
| 3215 private: | |
| 3216 TargetEntryInstr* true_successor_; | |
| 3217 TargetEntryInstr* false_successor_; | |
| 3218 | |
| 3219 DISALLOW_COPY_AND_ASSIGN(ControlInstruction); | |
| 3220 }; | |
| 3221 | |
| 3222 | |
| 3223 class BranchInstr : public ControlInstruction { | |
| 3224 public: | |
| 3225 explicit BranchInstr(ComparisonComp* computation) | |
| 3226 : computation_(computation), locs_(NULL) { } | |
| 3227 | |
| 3228 DECLARE_INSTRUCTION(Branch) | |
| 3229 | |
| 3230 virtual intptr_t ArgumentCount() const { | |
| 3231 return computation()->ArgumentCount(); | |
| 3232 } | |
| 3233 intptr_t InputCount() const { return computation()->InputCount(); } | |
| 3234 | |
| 3235 Value* InputAt(intptr_t i) const { return computation()->InputAt(i); } | |
| 3236 | |
| 3237 void SetInputAt(intptr_t i, Value* value) { | |
| 3238 computation()->SetInputAt(i, value); | |
| 3239 } | |
| 3240 | |
| 3241 virtual bool CanDeoptimize() const { return computation()->CanDeoptimize(); } | |
| 3242 | |
| 3243 ComparisonComp* computation() const { return computation_; } | |
| 3244 void set_computation(ComparisonComp* value) { computation_ = value; } | |
| 3245 | |
| 3246 virtual void EmitNativeCode(FlowGraphCompiler* compiler); | |
| 3247 | |
| 3248 virtual LocationSummary* locs() { | |
| 3249 if (computation_->locs_ == NULL) { | |
| 3250 LocationSummary* summary = computation_->MakeLocationSummary(); | |
| 3251 // Branches don't produce a result. | |
| 3252 summary->set_out(Location::NoLocation()); | |
| 3253 computation_->locs_ = summary; | |
| 3254 } | |
| 3255 return computation_->locs_; | |
| 3256 } | |
| 3257 | |
| 3258 virtual intptr_t DeoptimizationTarget() const { | |
| 3259 return computation_->DeoptimizationTarget(); | |
| 3260 } | |
| 3261 | |
| 3262 virtual Representation RequiredInputRepresentation(intptr_t i) const { | |
| 3263 return computation()->RequiredInputRepresentation(i); | |
| 3264 } | |
| 3265 | |
| 3266 private: | |
| 3267 ComparisonComp* computation_; | |
| 3268 LocationSummary* locs_; | |
| 3269 | |
| 3270 DISALLOW_COPY_AND_ASSIGN(BranchInstr); | |
| 3271 }; | |
| 3272 | |
| 3273 | |
| 3274 #undef DECLARE_INSTRUCTION | |
| 3275 | |
| 3276 | 3327 |
| 3277 class Environment : public ZoneAllocated { | 3328 class Environment : public ZoneAllocated { |
| 3278 public: | 3329 public: |
| 3279 // Construct an environment by constructing uses from an array of definitions. | 3330 // Construct an environment by constructing uses from an array of definitions. |
| 3280 Environment(const GrowableArray<Definition*>& definitions, | 3331 Environment(const GrowableArray<Definition*>& definitions, |
| 3281 intptr_t fixed_parameter_count); | 3332 intptr_t fixed_parameter_count); |
| 3282 | 3333 |
| 3283 void set_locations(Location* locations) { | 3334 void set_locations(Location* locations) { |
| 3284 ASSERT(locations_ == NULL); | 3335 ASSERT(locations_ == NULL); |
| 3285 locations_ = locations; | 3336 locations_ = locations; |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3360 ForwardInstructionIterator* current_iterator_; | 3411 ForwardInstructionIterator* current_iterator_; |
| 3361 | 3412 |
| 3362 private: | 3413 private: |
| 3363 DISALLOW_COPY_AND_ASSIGN(FlowGraphVisitor); | 3414 DISALLOW_COPY_AND_ASSIGN(FlowGraphVisitor); |
| 3364 }; | 3415 }; |
| 3365 | 3416 |
| 3366 | 3417 |
| 3367 } // namespace dart | 3418 } // namespace dart |
| 3368 | 3419 |
| 3369 #endif // VM_INTERMEDIATE_LANGUAGE_H_ | 3420 #endif // VM_INTERMEDIATE_LANGUAGE_H_ |
| OLD | NEW |