Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
call_specializer.h
Go to the documentation of this file.
1// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
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.
4
5#ifndef RUNTIME_VM_COMPILER_CALL_SPECIALIZER_H_
6#define RUNTIME_VM_COMPILER_CALL_SPECIALIZER_H_
7
8#if defined(DART_PRECOMPILED_RUNTIME)
9#error "AOT runtime should not use compiler sources (including header files)"
10#endif // defined(DART_PRECOMPILED_RUNTIME)
11
14
15namespace dart {
16
17class SpeculativeInliningPolicy;
18
19// Call specialization pass is responsible for replacing instance calls by
20// faster alternatives based on type feedback (JIT), type speculations (AOT),
21// locally propagated type information or global type information.
22//
23// This pass for example can
24//
25// * Replace a call to a binary arithmetic operator with corresponding IL
26// instructions and necessary checks;
27// * Replace a dynamic call with a static call, if receiver is known
28// to have a certain class id;
29// * Replace type check with a range check
30//
31// CallSpecializer is a base class that contains logic shared between
32// JIT and AOT compilation pipelines, see JitCallSpecializer for JIT specific
33// optimizations and AotCallSpecializer for AOT specific optimizations.
35 public:
37 SpeculativeInliningPolicy* speculative_policy,
38 bool should_clone_fields)
39 : FlowGraphVisitor(flow_graph->reverse_postorder()),
40 speculative_policy_(speculative_policy),
41 should_clone_fields_(should_clone_fields),
42 flow_graph_(flow_graph) {}
43
44 virtual ~CallSpecializer() {}
45
46 FlowGraph* flow_graph() const { return flow_graph_; }
47
52
53 // Use ICData to optimize, replace or eliminate instructions.
54 void ApplyICData();
55
56 // Use propagated class ids to optimize, replace or eliminate instructions.
57 void ApplyClassIds();
58
60
62 Instruction* instr,
64 FlowGraph::UseKind use_kind) {
65 flow_graph_->InsertBefore(next, instr, env, use_kind);
66 }
68 Instruction* instr,
70 FlowGraph::UseKind use_kind) {
71 flow_graph_->InsertSpeculativeBefore(next, instr, env, use_kind);
72 }
73
74 virtual void VisitStaticCall(StaticCallInstr* instr);
75
76 // TODO(dartbug.com/30633) these methods have nothing to do with
77 // specialization of calls. They are here for historical reasons.
78 // Find a better place for them.
79 virtual void VisitLoadCodeUnits(LoadCodeUnitsInstr* instr);
80
82 const bool is_exact;
84 };
85
86 protected:
87 Thread* thread() const { return flow_graph_->thread(); }
88 IsolateGroup* isolate_group() const { return flow_graph_->isolate_group(); }
89 Zone* zone() const { return flow_graph_->zone(); }
90 const Function& function() const { return flow_graph_->function(); }
91
94
97
100
103
104 // Replaces a call where the replacement code does not end in a
105 // value-returning instruction, so we must specify what definition should be
106 // used instead to replace uses of the call return value.
108 Instruction* replacement,
110 void ReplaceCall(Definition* call, Definition* replacement);
111
112 // Add a class check for the call's first argument (receiver).
114 AddCheckClass(call->Receiver()->definition(), call->Targets(),
115 call->deopt_id(), call->env(), call);
116 }
117
118 // Insert a null check if needed.
119 void AddCheckNull(Value* to_check,
120 const String& function_name,
121 intptr_t deopt_id,
122 Environment* deopt_environment,
123 Instruction* insert_before);
124
125 // Attempt to build ICData for call using propagated class-ids.
126 virtual bool TryCreateICData(InstanceCallInstr* call);
127
129 const AbstractType& type);
130
132
133 protected:
134 void InlineImplicitInstanceGetter(Definition* call, const Field& field);
135
136 // Insert a check of 'to_check' determined by 'unary_checks'. If the
137 // check fails it will deoptimize to 'deopt_id' using the deoptimization
138 // environment 'deopt_environment'. The check is inserted immediately
139 // before 'insert_before'.
140 void AddCheckClass(Definition* to_check,
141 const Cids& cids,
142 intptr_t deopt_id,
143 Environment* deopt_environment,
144 Instruction* insert_before);
145
148
149 private:
150 bool TypeCheckAsClassEquality(const AbstractType& type, intptr_t* type_cid);
151
152 // Insert a Smi check if needed.
153 void AddCheckSmi(Definition* to_check,
154 intptr_t deopt_id,
155 Environment* deopt_environment,
156 Instruction* insert_before);
157
158 // Add a class check for a call's nth argument immediately before the
159 // call, using the call's IC data to determine the check, and the call's
160 // deopt ID and deoptimization environment if the check fails.
161 void AddChecksForArgNr(InstanceCallInstr* call,
162 Definition* argument,
163 int argument_number);
164
165 bool InlineSimdBinaryOp(InstanceCallInstr* call,
166 intptr_t cid,
167 Token::Kind op_kind);
168
169 bool TryInlineImplicitInstanceGetter(InstanceCallInstr* call);
170
171 BoolPtr InstanceOfAsBool(const ICData& ic_data,
172 const AbstractType& type,
173 ZoneGrowableArray<intptr_t>* results) const;
174
175 bool TryOptimizeInstanceOfUsingStaticTypes(InstanceCallInstr* call,
176 const AbstractType& type);
177
178 bool TryStringLengthOneEquality(InstanceCallInstr* call, Token::Kind op_kind);
179
180 void SpecializePolymorphicInstanceCall(PolymorphicInstanceCallInstr* call);
181
182 // Tries to add cid tests to 'results' so that no deoptimization is
183 // necessary for common number-related type tests. Unconditionally adds an
184 // entry for the Smi type to the start of the array.
185 static bool SpecializeTestCidsForNumericTypes(
187 const AbstractType& type);
188
189 static bool TryReplaceInstanceCallWithInline(
192 InstanceCallInstr* call,
194
195 static bool TryReplaceStaticCallWithInline(
198 StaticCallInstr* call,
200
201 static bool TryInlineRecognizedMethod(FlowGraph* flow_graph,
202 intptr_t receiver_cid,
203 const Function& target,
204 Definition* call,
205 Definition* receiver,
207 const ICData* ic_data,
208 GraphEntryInstr* graph_entry,
209 FunctionEntryInstr** entry,
210 Instruction** last,
213 ExactnessInfo* exactness = nullptr);
214
215 FlowGraph* flow_graph_;
216};
217
218#define PUBLIC_TYPED_DATA_CLASS_LIST(V) \
219 V(Int8List, int8_list_type_, int_type_, kTypedDataInt8ArrayCid) \
220 V(Uint8List, uint8_list_type_, int_type_, kTypedDataUint8ArrayCid) \
221 V(Uint8ClampedList, uint8_clamped_type_, int_type_, \
222 kTypedDataUint8ClampedArrayCid) \
223 V(Int16List, int16_list_type_, int_type_, kTypedDataInt16ArrayCid) \
224 V(Uint16List, uint16_list_type_, int_type_, kTypedDataUint16ArrayCid) \
225 V(Int32List, int32_list_type_, int_type_, kTypedDataInt32ArrayCid) \
226 V(Uint32List, uint32_list_type_, int_type_, kTypedDataUint32ArrayCid) \
227 V(Int64List, int64_list_type_, int_type_, kTypedDataInt64ArrayCid) \
228 V(Uint64List, uint64_list_type_, int_type_, kTypedDataUint64ArrayCid) \
229 V(Float32List, float32_list_type_, double_type_, kTypedDataFloat32ArrayCid) \
230 V(Float64List, float64_list_type_, double_type_, kTypedDataFloat64ArrayCid)
231
232// Specializes instance/static calls with receiver type being a typed data
233// interface (if that interface is only implemented by internal/external/view
234// typed data classes).
235//
236// For example:
237//
238// foo(Uint8List bytes) => bytes[0];
239//
240// Would be translated to something like this:
241//
242// v0 <- Constant(0)
243//
244// // Ensures the list is non-null.
245// v1 <- ParameterInstr(0)
246// v2 <- CheckNull(v1)
247//
248// // Load the length & perform bounds checks
249// v3 <- LoadField(v2, "TypedDataBase.length");
250// v4 <- GenericCheckBounds(v3, v0);
251//
252// // Directly access the byte, independent of whether `bytes` is
253// // _Uint8List, _Uint8ArrayView or _ExternalUint8Array.
254// v5 <- LoadField(Slot::PointerBase_data(), v1);
255// v5 <- LoadIndexed(v5, v4)
256//
258 public:
259 static void Optimize(FlowGraph* flow_graph);
260
261 virtual void VisitInstanceCall(InstanceCallInstr* instr);
262 virtual void VisitStaticCall(StaticCallInstr* instr);
263
264 private:
265 // clang-format off
266 explicit TypedDataSpecializer(FlowGraph* flow_graph)
267 : FlowGraphVisitor(flow_graph->reverse_postorder()),
268 thread_(Thread::Current()),
269 zone_(thread_->zone()),
270 flow_graph_(flow_graph),
271#define ALLOCATE_HANDLE(iface, member_name, type, cid) \
272 member_name(AbstractType::Handle(zone_)),
274#undef INIT_HANDLE
275 int_type_(AbstractType::Handle()),
276 double_type_(AbstractType::Handle()),
277 implementor_(Class::Handle()) {
278 }
279 // clang-format on
280
281 void EnsureIsInitialized();
282 void TryInlineCall(TemplateDartCall<0>* call);
283 void ReplaceWithLengthGetter(TemplateDartCall<0>* call);
284 void ReplaceWithIndexGet(TemplateDartCall<0>* call, classid_t cid);
285 void ReplaceWithIndexSet(TemplateDartCall<0>* call, classid_t cid);
286 void AppendNullCheck(TemplateDartCall<0>* call, Definition** array);
287 void AppendMutableCheck(TemplateDartCall<0>* call, Definition** array);
288 void AppendBoundsCheck(TemplateDartCall<0>* call,
289 Definition* array,
290 Definition** index);
291 Definition* AppendLoadLength(TemplateDartCall<0>* call, Definition* array);
292 Definition* AppendLoadIndexed(TemplateDartCall<0>* call,
293 Definition* array,
294 Definition* index,
295 classid_t cid);
296 void AppendStoreIndexed(TemplateDartCall<0>* call,
297 Definition* array,
298 Definition* index,
300 classid_t cid);
301
302 Zone* zone() const { return zone_; }
303
304 Thread* thread_;
305 Zone* zone_;
306 FlowGraph* flow_graph_;
307 bool initialized_ = false;
308
309#define DEF_HANDLE(iface, member_name, type, cid) AbstractType& member_name;
311#undef DEF_HANDLE
312
313 AbstractType& int_type_;
314 AbstractType& double_type_;
315 Class& implementor_;
316};
317
318} // namespace dart
319
320#endif // RUNTIME_VM_COMPILER_CALL_SPECIALIZER_H_
static float next(float f)
#define DEF_HANDLE(iface, member_name, type, cid)
#define PUBLIC_TYPED_DATA_CLASS_LIST(V)
#define ALLOCATE_HANDLE(iface, member_name, type, cid)
virtual void VisitStaticCall(StaticCallInstr *instr)
IsolateGroup * isolate_group() const
void AddReceiverCheck(InstanceCallInstr *call)
void set_flow_graph(FlowGraph *flow_graph)
bool TryReplaceWithEqualityOp(InstanceCallInstr *call, Token::Kind op_kind)
FlowGraph * flow_graph() const
void AddCheckNull(Value *to_check, const String &function_name, intptr_t deopt_id, Environment *deopt_environment, Instruction *insert_before)
void AddCheckClass(Definition *to_check, const Cids &cids, intptr_t deopt_id, Environment *deopt_environment, Instruction *insert_before)
void ReplaceCall(Definition *call, Definition *replacement)
bool TryInlineInstanceSetter(InstanceCallInstr *call)
CallSpecializer(FlowGraph *flow_graph, SpeculativeInliningPolicy *speculative_policy, bool should_clone_fields)
void InsertBefore(Instruction *next, Instruction *instr, Environment *env, FlowGraph::UseKind use_kind)
void ReplaceCallWithResult(Definition *call, Instruction *replacement, Definition *result)
Thread * thread() const
virtual void VisitLoadCodeUnits(LoadCodeUnitsInstr *instr)
virtual bool TryCreateICData(InstanceCallInstr *call)
void InlineImplicitInstanceGetter(Definition *call, const Field &field)
bool TryInlineInstanceGetter(InstanceCallInstr *call)
bool TryReplaceWithRelationalOp(InstanceCallInstr *call, Token::Kind op_kind)
virtual bool TryOptimizeStaticCallUsingStaticTypes(StaticCallInstr *call)=0
bool TryReplaceWithUnaryOp(InstanceCallInstr *call, Token::Kind op_kind)
SpeculativeInliningPolicy * speculative_policy_
const Function & function() const
virtual void ReplaceInstanceCallsWithDispatchTableCalls()
void ReplaceWithInstanceOf(InstanceCallInstr *instr)
bool TryReplaceWithBinaryOp(InstanceCallInstr *call, Token::Kind op_kind)
bool TryInlineInstanceMethod(InstanceCallInstr *call)
virtual bool TryReplaceInstanceOfWithRangeCheck(InstanceCallInstr *call, const AbstractType &type)
void InsertSpeculativeBefore(Instruction *next, Instruction *instr, Environment *env, FlowGraph::UseKind use_kind)
void set_block_order(const GrowableArray< BlockEntryInstr * > &block_order)
Definition il.h:11801
const GrowableArray< BlockEntryInstr * > & reverse_postorder() const
Definition flow_graph.h:207
IsolateGroup * isolate_group() const
Definition flow_graph.h:262
Zone * zone() const
Definition flow_graph.h:261
Thread * thread() const
Definition flow_graph.h:260
const Function & function() const
Definition flow_graph.h:130
void InsertBefore(Instruction *next, Instruction *instr, Environment *env, UseKind use_kind)
Definition flow_graph.h:312
void InsertSpeculativeBefore(Instruction *next, Instruction *instr, Environment *env, UseKind use_kind)
Definition flow_graph.h:318
static Object & Handle()
Definition object.h:407
static Thread * Current()
Definition thread.h:361
virtual void VisitStaticCall(StaticCallInstr *instr)
virtual void VisitInstanceCall(InstanceCallInstr *instr)
static void Optimize(FlowGraph *flow_graph)
SkBitmap source
Definition examples.cpp:28
uint8_t value
GAsyncResult * result
uint32_t * target
int32_t classid_t
Definition globals.h:524
const intptr_t cid
const char *const function_name
Definition __init__.py:1