Flutter Engine
The Flutter Engine
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
12#include <array>
13
16
17namespace dart {
18
19class SpeculativeInliningPolicy;
20
21// Call specialization pass is responsible for replacing instance calls by
22// faster alternatives based on type feedback (JIT), type speculations (AOT),
23// locally propagated type information or global type information.
24//
25// This pass for example can
26//
27// * Replace a call to a binary arithmetic operator with corresponding IL
28// instructions and necessary checks;
29// * Replace a dynamic call with a static call, if receiver is known
30// to have a certain class id;
31// * Replace type check with a range check
32//
33// CallSpecializer is a base class that contains logic shared between
34// JIT and AOT compilation pipelines, see JitCallSpecializer for JIT specific
35// optimizations and AotCallSpecializer for AOT specific optimizations.
37 public:
39 SpeculativeInliningPolicy* speculative_policy,
40 bool should_clone_fields)
41 : FlowGraphVisitor(flow_graph->reverse_postorder()),
42 speculative_policy_(speculative_policy),
43 should_clone_fields_(should_clone_fields),
44 flow_graph_(flow_graph) {}
45
46 virtual ~CallSpecializer() {}
47
48 FlowGraph* flow_graph() const { return flow_graph_; }
49
51 flow_graph_ = flow_graph;
53 }
54
55 // Use ICData to optimize, replace or eliminate instructions.
56 void ApplyICData();
57
58 // Use propagated class ids to optimize, replace or eliminate instructions.
59 void ApplyClassIds();
60
62
64 Instruction* instr,
66 FlowGraph::UseKind use_kind) {
67 flow_graph_->InsertBefore(next, instr, env, use_kind);
68 }
70 Instruction* instr,
72 FlowGraph::UseKind use_kind) {
73 flow_graph_->InsertSpeculativeBefore(next, instr, env, use_kind);
74 }
75
76 virtual void VisitStaticCall(StaticCallInstr* instr);
77
78 // TODO(dartbug.com/30633) these methods have nothing to do with
79 // specialization of calls. They are here for historical reasons.
80 // Find a better place for them.
81 virtual void VisitLoadCodeUnits(LoadCodeUnitsInstr* instr);
82
84 const bool is_exact;
86 };
87
88 protected:
89 Thread* thread() const { return flow_graph_->thread(); }
90 IsolateGroup* isolate_group() const { return flow_graph_->isolate_group(); }
91 Zone* zone() const { return flow_graph_->zone(); }
92 const Function& function() const { return flow_graph_->function(); }
93
96
99
102
105
106 // Replaces a call where the replacement code does not end in a
107 // value-returning instruction, so we must specify what definition should be
108 // used instead to replace uses of the call return value.
110 Instruction* replacement,
112 void ReplaceCall(Definition* call, Definition* replacement);
113
114 // Add a class check for the call's first argument (receiver).
116 AddCheckClass(call->Receiver()->definition(), call->Targets(),
117 call->deopt_id(), call->env(), call);
118 }
119
120 // Insert a null check if needed.
121 void AddCheckNull(Value* to_check,
122 const String& function_name,
123 intptr_t deopt_id,
124 Environment* deopt_environment,
125 Instruction* insert_before);
126
127 // Attempt to build ICData for call using propagated class-ids.
129
131 const AbstractType& type);
132
134
135 protected:
137
138 // Insert a check of 'to_check' determined by 'unary_checks'. If the
139 // check fails it will deoptimize to 'deopt_id' using the deoptimization
140 // environment 'deopt_environment'. The check is inserted immediately
141 // before 'insert_before'.
142 void AddCheckClass(Definition* to_check,
143 const Cids& cids,
144 intptr_t deopt_id,
145 Environment* deopt_environment,
146 Instruction* insert_before);
147
150
151 private:
152 bool TypeCheckAsClassEquality(const AbstractType& type, intptr_t* type_cid);
153
154 // Insert a Smi check if needed.
155 void AddCheckSmi(Definition* to_check,
156 intptr_t deopt_id,
157 Environment* deopt_environment,
158 Instruction* insert_before);
159
160 // Add a class check for a call's nth argument immediately before the
161 // call, using the call's IC data to determine the check, and the call's
162 // deopt ID and deoptimization environment if the check fails.
163 void AddChecksForArgNr(InstanceCallInstr* call,
164 Definition* argument,
165 int argument_number);
166
167 bool InlineSimdBinaryOp(InstanceCallInstr* call,
168 intptr_t cid,
169 Token::Kind op_kind);
170
171 bool TryInlineImplicitInstanceGetter(InstanceCallInstr* call);
172
173 BoolPtr InstanceOfAsBool(const ICData& ic_data,
174 const AbstractType& type,
175 ZoneGrowableArray<intptr_t>* results) const;
176
177 bool TryOptimizeInstanceOfUsingStaticTypes(InstanceCallInstr* call,
178 const AbstractType& type);
179
180 bool TryStringLengthOneEquality(InstanceCallInstr* call, Token::Kind op_kind);
181
182 void SpecializePolymorphicInstanceCall(PolymorphicInstanceCallInstr* call);
183
184 // Tries to add cid tests to 'results' so that no deoptimization is
185 // necessary for common number-related type tests. Unconditionally adds an
186 // entry for the Smi type to the start of the array.
187 static bool SpecializeTestCidsForNumericTypes(
189 const AbstractType& type);
190
191 static bool TryReplaceInstanceCallWithInline(
196
197 static bool TryReplaceStaticCallWithInline(
202
203 static bool TryInlineRecognizedMethod(FlowGraph* flow_graph,
204 intptr_t receiver_cid,
205 const Function& target,
207 Definition* receiver,
209 const ICData* ic_data,
210 GraphEntryInstr* graph_entry,
211 FunctionEntryInstr** entry,
212 Instruction** last,
215 ExactnessInfo* exactness = nullptr);
216
217 FlowGraph* flow_graph_;
218};
219
220#define PUBLIC_TYPED_DATA_CLASS_LIST(V) \
221 V(Int8List, int_type_, kTypedDataInt8ArrayCid) \
222 V(Uint8List, int_type_, kTypedDataUint8ArrayCid) \
223 V(Uint8ClampedList, int_type_, kTypedDataUint8ClampedArrayCid) \
224 V(Int16List, int_type_, kTypedDataInt16ArrayCid) \
225 V(Uint16List, int_type_, kTypedDataUint16ArrayCid) \
226 V(Int32List, int_type_, kTypedDataInt32ArrayCid) \
227 V(Uint32List, int_type_, kTypedDataUint32ArrayCid) \
228 V(Int64List, int_type_, kTypedDataInt64ArrayCid) \
229 V(Uint64List, int_type_, kTypedDataUint64ArrayCid) \
230 V(Float32List, double_type_, kTypedDataFloat32ArrayCid) \
231 V(Float64List, double_type_, kTypedDataFloat64ArrayCid) \
232 V(Float32x4List, float32x4_type_, kTypedDataFloat32x4ArrayCid) \
233 V(Int32x4List, int32x4_type_, kTypedDataInt32x4ArrayCid) \
234 V(Float64x2List, float64x2_type_, kTypedDataFloat64x2ArrayCid)
235
236// Specializes instance/static calls with receiver type being a typed data
237// interface (if that interface is only implemented by internal/external/view
238// typed data classes).
239//
240// For example:
241//
242// foo(Uint8List bytes) => bytes[0];
243//
244// Would be translated to something like this:
245//
246// v0 <- Constant(0)
247//
248// // Ensures the list is non-null.
249// v1 <- ParameterInstr(0)
250// v2 <- CheckNull(v1)
251//
252// // Load the length & perform bounds checks
253// v3 <- LoadField(v2, "TypedDataBase.length");
254// v4 <- GenericCheckBounds(v3, v0);
255//
256// // Directly access the byte, independent of whether `bytes` is
257// // _Uint8List, _Uint8ArrayView or _ExternalUint8Array.
258// v5 <- LoadField(Slot::PointerBase_data(), v1);
259// v5 <- LoadIndexed(v5, v4)
260//
262 public:
263 static void Optimize(FlowGraph* flow_graph);
264
265 virtual void VisitInstanceCall(InstanceCallInstr* instr);
266 virtual void VisitStaticCall(StaticCallInstr* instr);
267
268 private:
269 // clang-format off
270 explicit TypedDataSpecializer(FlowGraph* flow_graph)
271 : FlowGraphVisitor(flow_graph->reverse_postorder()),
272 thread_(Thread::Current()),
273 zone_(thread_->zone()),
274 flow_graph_(flow_graph),
275 int_type_(AbstractType::Handle()),
276 double_type_(AbstractType::Handle()),
277 float32x4_type_(AbstractType::Handle()),
278 int32x4_type_(AbstractType::Handle()),
279 float64x2_type_(AbstractType::Handle()),
280 implementor_(Class::Handle()) {
281 }
282 // clang-format on
283
284 void EnsureIsInitialized();
285 void TryInlineCall(TemplateDartCall<0>* call);
286 void ReplaceWithLengthGetter(TemplateDartCall<0>* call);
287 void ReplaceWithIndexGet(TemplateDartCall<0>* call, classid_t cid);
288 void ReplaceWithIndexSet(TemplateDartCall<0>* call, classid_t cid);
289 void AppendNullCheck(TemplateDartCall<0>* call, Definition** array);
290 void AppendMutableCheck(TemplateDartCall<0>* call, Definition** array);
291 void AppendBoundsCheck(TemplateDartCall<0>* call,
292 Definition* array,
293 Definition** index);
294 Definition* AppendLoadLength(TemplateDartCall<0>* call, Definition* array);
295 Definition* AppendLoadIndexed(TemplateDartCall<0>* call,
296 Definition* array,
297 Definition* index,
298 classid_t cid);
299 void AppendStoreIndexed(TemplateDartCall<0>* call,
300 Definition* array,
301 Definition* index,
303 classid_t cid);
304
305 Zone* zone() const { return zone_; }
306
307 Thread* thread_;
308 Zone* zone_;
309 FlowGraph* flow_graph_;
310 bool initialized_ = false;
311
312 struct TypedDataVariant {
314 intptr_t array_cid = kIllegalCid;
315 AbstractType& element_type = AbstractType::Handle();
316 };
317
318 enum {
319#define DEFINE_INDEX(iface, type, cid) k##iface##Index,
321#undef DEFINE_INDEX
322 kNumTypedDataVariants
323 };
324
325 std::array<TypedDataVariant, kNumTypedDataVariants> typed_data_variants_;
326
327 AbstractType& int_type_;
328 AbstractType& double_type_;
329 AbstractType& float32x4_type_;
330 AbstractType& int32x4_type_;
331 AbstractType& float64x2_type_;
332 Class& implementor_;
333};
334
335} // namespace dart
336
337#endif // RUNTIME_VM_COMPILER_CALL_SPECIALIZER_H_
static float next(float f)
GLenum type
#define DEFINE_INDEX(iface, type, cid)
#define PUBLIC_TYPED_DATA_CLASS_LIST(V)
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)
Definition: il.h:736
void set_block_order(const GrowableArray< BlockEntryInstr * > &block_order)
Definition: il.h:11855
FlowGraphVisitor(const GrowableArray< BlockEntryInstr * > &block_order)
Definition: il.h:11842
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:362
virtual void VisitStaticCall(StaticCallInstr *instr)
virtual void VisitInstanceCall(InstanceCallInstr *instr)
static void Optimize(FlowGraph *flow_graph)
Definition: il.h:75
SkBitmap source
Definition: examples.cpp:28
uint8_t value
GAsyncResult * result
uint32_t * target
Definition: dart_vm.cc:33
int32_t classid_t
Definition: globals.h:524
@ kIllegalCid
Definition: class_id.h:214
const intptr_t cid
const char *const function_name
def call(args)
Definition: dom.py:159
Definition: __init__.py:1
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network policy
Definition: switches.h:248
def array_type(data_type)
Definition: systemnative.py:28