Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(347)

Side by Side Diff: runtime/vm/intermediate_language.h

Issue 10905015: Change the order of definitions in intermediate_language.h. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rebased to HEAD. Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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_
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698