Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Classes | Namespaces | Macros | Enumerations | Functions
il_test_helper.h File Reference
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include "include/dart_api.h"
#include "platform/allocation.h"
#include "vm/compiler/backend/flow_graph.h"
#include "vm/compiler/backend/il.h"
#include "vm/compiler/backend/inliner.h"
#include "vm/compiler/compiler_pass.h"
#include "vm/compiler/compiler_state.h"
#include "vm/compiler/jit/compiler.h"
#include "vm/unit_test.h"

Go to the source code of this file.

Classes

class  dart::TestPipeline
 
class  dart::MatchCode
 
class  dart::ILMatcher
 
class  dart::FlowGraphBuilderHelper
 
class  dart::FlowGraphBuilderHelper::IncomingDef
 

Namespaces

namespace  dart
 

Macros

#define DEFINE_MATCH_OPCODES(Instruction, _)
 
#define DEFINE_TYPED_CONSTRUCTOR(Type, ignored)
 
#define ENTITY_TOCSTRING(v)   ((v)->ToCString())
 
#define EXPECT_PROPERTY(entity, property)
 

Enumerations

enum  dart::MatchOpCode {
  dart::kMatchAndMoveBranchTrue , dart::kMatchAndMoveBranchFalse , dart::kNop , dart::kMoveAny ,
  dart::kMoveParallelMoves , dart::kMoveGlob , dart::kMoveDebugStepChecks , dart::kInvalidMatchOpCode
}
 
enum class  dart::ParallelMovesHandling { dart::kDefault , dart::kSkip }
 

Functions

LibraryPtr dart::LoadTestScript (const char *script, Dart_NativeEntryResolver resolver, const char *lib_uri)
 
 dart::NOT_IN_PRODUCT (LibraryPtr ReloadTestScript(const char *script))
 
FunctionPtr dart::GetFunction (const Library &lib, const char *name)
 
ClassPtr dart::GetClass (const Library &lib, const char *name)
 
TypeParameterPtr dart::GetClassTypeParameter (const Class &klass, intptr_t index)
 
TypeParameterPtr dart::GetFunctionTypeParameter (const Function &fun, intptr_t index)
 
ObjectPtr dart::Invoke (const Library &lib, const char *name)
 
InstructionsPtr dart::BuildInstructions (std::function< void(compiler::Assembler *assembler)> fun)
 

Macro Definition Documentation

◆ DEFINE_MATCH_OPCODES

#define DEFINE_MATCH_OPCODES (   Instruction,
 
)
Value:
kMatch##Instruction, kMatchAndMove##Instruction, \
kMatchAndMoveOptional##Instruction,

Definition at line 119 of file il_test_helper.h.

153 {
154 public:
155 MatchCode(MatchOpCode opcode) // NOLINT
156 : opcode_(opcode), capture_(nullptr) {}
157
158 MatchCode(MatchOpCode opcode, Instruction** capture)
159 : opcode_(opcode), capture_(capture) {}
160
161#define DEFINE_TYPED_CONSTRUCTOR(Type, ignored) \
162 MatchCode(MatchOpCode opcode, Type##Instr** capture) \
163 : opcode_(opcode), capture_(reinterpret_cast<Instruction**>(capture)) { \
164 RELEASE_ASSERT(opcode == kMatch##Type || opcode == kMatchAndMove##Type); \
165 }
168#undef DEFINE_TYPED_CONSTRUCTOR
169
170 MatchOpCode opcode() { return opcode_; }
171
172 private:
173 friend class ILMatcher;
174
175 MatchOpCode opcode_;
176 Instruction** capture_;
177};
178
179enum class ParallelMovesHandling {
180 // Matcher doesn't do anything special with ParallelMove instructions.
181 kDefault,
182 // All ParallelMove instructions are skipped.
183 // This mode is useful when matching a flow graph after the whole
184 // compiler pipeline, as it may have ParallelMove instructions
185 // at arbitrary architecture-dependent places.
186 kSkip,
187};
188
189// Used for matching a sequence of IL instructions including capturing support.
190//
191// Example:
192//
193// TargetEntryInstr* entry = ....;
194// BranchInstr* branch = nullptr;
195//
196// ILMatcher matcher(flow_graph, entry);
197// if (matcher.TryMatch({ kMoveGlob, {kMatchBranch, &branch}, })) {
198// EXPECT(branch->operation_cid() == kMintCid);
199// ...
200// }
201//
202// This match will start at [entry], follow any number instructions (including
203// [GotoInstr]s until a [BranchInstr] is found).
204//
205// If the match was successful, this returns `true` and updates the current
206// value for the cursor.
207class ILMatcher : public ValueObject {
208 public:
209 ILMatcher(FlowGraph* flow_graph,
210 Instruction* cursor,
211 bool trace = true,
212 ParallelMovesHandling parallel_moves_handling =
213 ParallelMovesHandling::kDefault)
214 : flow_graph_(flow_graph),
215 cursor_(cursor),
216 parallel_moves_handling_(parallel_moves_handling),
217 // clang-format off
218#if !defined(PRODUCT)
219 trace_(trace) {}
220#else
221 trace_(false) {}
222#endif
223 // clang-format on
224
225 Instruction* value() { return cursor_; }
226
227 // From the current [value] according to match_codes.
228 //
229 // Returns `true` if the match was successful and cursor has been updated,
230 // otherwise returns `false`.
231 //
232 // If [insert_before] is a valid match opcode, then it will be inserted
233 // before each MatchCode in [match_codes] prior to matching.
234 bool TryMatch(std::initializer_list<MatchCode> match_codes,
235 MatchOpCode insert_before = kInvalidMatchOpCode);
236
237 private:
238 Instruction* MatchInternal(std::vector<MatchCode> match_codes,
239 size_t i,
240 Instruction* cursor);
241
242 const char* MatchOpCodeToCString(MatchOpCode code);
243
244 FlowGraph* flow_graph_;
245 Instruction* cursor_;
246 ParallelMovesHandling parallel_moves_handling_;
247 bool trace_;
248};
249
250#if !defined(PRODUCT)
251#define ENTITY_TOCSTRING(v) ((v)->ToCString())
252#else
253#define ENTITY_TOCSTRING(v) "<?>"
254#endif
255
256// Helper to check various IL and object properties and informative error
257// messages if check fails. [entity] should be a pointer to a value.
258// [property] should be an expression which can refer to [entity] using
259// variable named [it].
260// [entity] is expected to have a ToCString() method in non-PRODUCT builds.
261#define EXPECT_PROPERTY(entity, property) \
262 do { \
263 auto& it = *entity; \
264 if (!(property)) { \
265 dart::Expect(__FILE__, __LINE__) \
266 .Fail("expected " #property " for " #entity " which is %s.\n", \
267 ENTITY_TOCSTRING(entity)); \
268 } \
269 } while (0)
270
271class FlowGraphBuilderHelper {
272 public:
273 explicit FlowGraphBuilderHelper(intptr_t num_parameters = 0)
274 : state_(CompilerState::Current()),
275 flow_graph_(MakeDummyGraph(Thread::Current(),
276 num_parameters,
277 state_.is_optimizing())) {
278 flow_graph_.CreateCommonConstants();
279 }
280
281 TargetEntryInstr* TargetEntry(intptr_t try_index = kInvalidTryIndex) const {
282 return new TargetEntryInstr(flow_graph_.allocate_block_id(), try_index,
283 state_.GetNextDeoptId());
284 }
285
286 JoinEntryInstr* JoinEntry(intptr_t try_index = kInvalidTryIndex) const {
287 return new JoinEntryInstr(flow_graph_.allocate_block_id(), try_index,
288 state_.GetNextDeoptId());
289 }
290
291 ConstantInstr* IntConstant(int64_t value) const {
292 return flow_graph_.GetConstant(
293 Integer::Handle(Integer::NewCanonical(value)));
294 }
295
296 ConstantInstr* DoubleConstant(double value) {
297 return flow_graph_.GetConstant(Double::Handle(Double::NewCanonical(value)));
298 }
299
300 // Adds a variable into the scope which would provide inferred argument type
301 // for the parameter.
302 void AddVariable(const char* name,
303 const AbstractType& static_type,
304 CompileType* inferred_arg_type = nullptr) {
305 LocalVariable* v =
306 new LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
307 String::Handle(Symbols::New(Thread::Current(), name)),
308 static_type, LocalVariable::kNoKernelOffset,
309 new CompileType(CompileType::FromAbstractType(
310 static_type, CompileType::kCanBeNull,
311 CompileType::kCannotBeSentinel)),
312 inferred_arg_type);
313 v->set_type_check_mode(LocalVariable::kTypeCheckedByCaller);
314 flow_graph()->parsed_function().scope()->AddVariable(v);
315 }
316
317 enum class IncomingDefKind {
318 kImmediate,
319 kDelayed,
320 };
321
322 class IncomingDef {
323 public:
324 IncomingDef(BlockEntryInstr* from, Definition* defn)
325 : kind_(IncomingDefKind::kImmediate), from_(from), defn_(defn) {}
326
327 template <typename T,
328 typename = typename std::enable_if<
329 std::is_base_of<Definition, T>::value>::type>
330 IncomingDef(BlockEntryInstr* from, T** defn_source)
331 : kind_(IncomingDefKind::kDelayed),
332 from_(from),
333 defn_source_(reinterpret_cast<Definition**>(defn_source)) {}
334
335 BlockEntryInstr* from() const { return from_; }
336 Definition* defn() const {
337 return kind_ == IncomingDefKind::kImmediate ? defn_ : *defn_source_;
338 }
339
340 private:
341 IncomingDefKind kind_;
342 BlockEntryInstr* from_;
343 union {
344 Definition* defn_;
345 Definition** defn_source_;
346 };
347 };
348
349 PhiInstr* Phi(JoinEntryInstr* join,
350 std::initializer_list<IncomingDef> incoming) {
351 auto phi = new PhiInstr(join, incoming.size());
352 for (size_t i = 0; i < incoming.size(); i++) {
353 auto input = new Value(flow_graph_.constant_dead());
354 phi->SetInputAt(i, input);
355 input->definition()->AddInputUse(input);
356 }
357 for (auto def : incoming) {
358 pending_phis_.Add({phi, def});
359 }
360 return phi;
361 }
362
363 void FinishGraph() {
364 flow_graph_.DiscoverBlocks();
365 GrowableArray<BitVector*> dominance_frontier;
366 flow_graph_.ComputeDominators(&dominance_frontier);
367
368 for (auto& pending : pending_phis_) {
369 auto join = pending.phi->block();
370 EXPECT(pending.phi->InputCount() == join->PredecessorCount());
371 auto pred_index = join->IndexOfPredecessor(pending.incoming.from());
372 EXPECT(pred_index != -1);
373 pending.phi->InputAt(pred_index)->BindTo(pending.incoming.defn());
374 }
375 }
376
377 FlowGraph* flow_graph() { return &flow_graph_; }
378
379 private:
380 static FlowGraph& MakeDummyGraph(Thread* thread,
381 intptr_t num_parameters,
382 bool is_optimizing) {
383 const FunctionType& signature =
384 FunctionType::ZoneHandle(FunctionType::New());
385 signature.set_num_fixed_parameters(num_parameters);
386 const Function& func = Function::ZoneHandle(Function::New(
387 signature, String::Handle(Symbols::New(thread, "dummy")),
388 UntaggedFunction::kRegularFunction,
389 /*is_static=*/true,
390 /*is_const=*/false,
391 /*is_abstract=*/false,
392 /*is_external=*/false,
393 /*is_native=*/true,
394 Class::Handle(thread->isolate_group()->object_store()->object_class()),
395 TokenPosition::kNoSource));
396
397 Zone* zone = thread->zone();
398 ParsedFunction* parsed_function = new (zone) ParsedFunction(thread, func);
399
400 parsed_function->set_scope(new LocalScope(nullptr, 0, 0));
401
402 auto graph_entry =
403 new GraphEntryInstr(*parsed_function, Compiler::kNoOSRDeoptId);
404
405 const intptr_t block_id = 1; // 0 is GraphEntry.
406 graph_entry->set_normal_entry(
407 new FunctionEntryInstr(graph_entry, block_id, kInvalidTryIndex,
408 CompilerState::Current().GetNextDeoptId()));
409 return *new FlowGraph(*parsed_function, graph_entry, block_id,
410 PrologueInfo{-1, -1},
411 FlowGraph::CompilationModeFrom(is_optimizing));
412 }
413
414 CompilerState& state_;
415 FlowGraph& flow_graph_;
416
417 struct PendingPhiInput {
418 PhiInstr* phi;
419 IncomingDef incoming;
420 };
421 GrowableArray<PendingPhiInput> pending_phis_;
422};
423
424} // namespace dart
425
426#endif // RUNTIME_VM_COMPILER_BACKEND_IL_TEST_HELPER_H_
#define EXPECT(type, expectedAlignment, expectedSize)
if(end==-1)
uint8_t value
const char * name
Definition fuchsia.cc:50
#define FOR_EACH_INSTRUCTION(M)
Definition il.h:405
#define FOR_EACH_ABSTRACT_INSTRUCTION(M)
Definition il.h:553
#define DEFINE_TYPED_CONSTRUCTOR(Type, ignored)
ParallelMovesHandling
SINT Vec< 2 *N, T > join(const Vec< N, T > &lo, const Vec< N, T > &hi)
Definition SkVx.h:242
#define T

◆ DEFINE_TYPED_CONSTRUCTOR

#define DEFINE_TYPED_CONSTRUCTOR (   Type,
  ignored 
)
Value:
MatchCode(MatchOpCode opcode, Type##Instr** capture) \
: opcode_(opcode), capture_(reinterpret_cast<Instruction**>(capture)) { \
RELEASE_ASSERT(opcode == kMatch##Type || opcode == kMatchAndMove##Type); \
}

Definition at line 161 of file il_test_helper.h.

163 : opcode_(opcode), capture_(reinterpret_cast<Instruction**>(capture)) { \
164 RELEASE_ASSERT(opcode == kMatch##Type || opcode == kMatchAndMove##Type); \
165 }

◆ ENTITY_TOCSTRING

#define ENTITY_TOCSTRING (   v)    ((v)->ToCString())

Definition at line 251 of file il_test_helper.h.

◆ EXPECT_PROPERTY

#define EXPECT_PROPERTY (   entity,
  property 
)
Value:
do { \
auto& it = *entity; \
if (!(property)) { \
dart::Expect(__FILE__, __LINE__) \
.Fail("expected " #property " for " #entity " which is %s.\n", \
ENTITY_TOCSTRING(entity)); \
} \
} while (0)
#define ENTITY_TOCSTRING(v)

Definition at line 261 of file il_test_helper.h.

262 { \
263 auto& it = *entity; \
264 if (!(property)) { \
265 dart::Expect(__FILE__, __LINE__) \
266 .Fail("expected " #property " for " #entity " which is %s.\n", \
267 ENTITY_TOCSTRING(entity)); \
268 } \
269 } while (0)