Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
il_test_helper.cc
Go to the documentation of this file.
1// Copyright (c) 2019, 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
6
19#include "vm/dart_api_impl.h"
20#include "vm/flags.h"
21#include "vm/parser.h"
22#include "vm/unit_test.h"
23
24namespace dart {
25
26LibraryPtr LoadTestScript(const char* script,
28 const char* lib_uri) {
29 Dart_Handle api_lib;
30 {
32 api_lib = TestCase::LoadTestScript(script, resolver, lib_uri);
33 EXPECT_VALID(api_lib);
34 }
35 auto& lib = Library::Handle();
36 lib ^= Api::UnwrapHandle(api_lib);
37 EXPECT(!lib.IsNull());
38 return lib.ptr();
39}
40
41#if !defined(PRODUCT)
42LibraryPtr ReloadTestScript(const char* script) {
43 Dart_Handle api_lib;
44 {
46 api_lib = TestCase::ReloadTestScript(script);
47 EXPECT_VALID(api_lib);
48 }
49 auto& lib = Library::Handle();
50 lib ^= Api::UnwrapHandle(api_lib);
51 EXPECT(!lib.IsNull());
52 return lib.ptr();
53}
54#endif
55
56FunctionPtr GetFunction(const Library& lib, const char* name) {
57 Thread* thread = Thread::Current();
58 const auto& func = Function::Handle(lib.LookupFunctionAllowPrivate(
60 EXPECT(!func.IsNull());
61 return func.ptr();
62}
63
64ClassPtr GetClass(const Library& lib, const char* name) {
65 Thread* thread = Thread::Current();
66 const auto& cls = Class::Handle(
68 EXPECT(!cls.IsNull());
69 return cls.ptr();
70}
71
72TypeParameterPtr GetClassTypeParameter(const Class& klass, intptr_t index) {
73 const auto& param = TypeParameter::Handle(klass.TypeParameterAt(index));
74 EXPECT(!param.IsNull());
75 return param.ptr();
76}
77
78TypeParameterPtr GetFunctionTypeParameter(const Function& fun, intptr_t index) {
79 const auto& param = TypeParameter::Handle(fun.TypeParameterAt(index));
80 EXPECT(!param.IsNull());
81 return param.ptr();
82}
83
84ObjectPtr Invoke(const Library& lib, const char* name) {
85 Thread* thread = Thread::Current();
86 Dart_Handle api_lib = Api::NewHandle(thread, lib.ptr());
88 {
89 TransitionVMToNative transition(thread);
90 result =
91 Dart_Invoke(api_lib, NewString(name), /*argc=*/0, /*argv=*/nullptr);
93 }
95}
96
97InstructionsPtr BuildInstructions(
98 std::function<void(compiler::Assembler* assembler)> fun) {
99 auto thread = Thread::Current();
100 compiler::Assembler assembler(nullptr);
101
102 fun(&assembler);
103
104 auto& code = Code::Handle();
105 auto install_code_fun = [&] {
106 code = Code::FinalizeCode(nullptr, &assembler,
108 /*optimized=*/false, /*stats=*/nullptr);
109 };
110 SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
111 thread->isolate_group()->RunWithStoppedMutators(install_code_fun,
112 /*use_force_growth=*/true);
113 return code.instructions();
114}
115
117 std::initializer_list<CompilerPass::Id> passes) {
118 auto thread = Thread::Current();
119 auto zone = thread->zone();
120 const bool optimized = true;
121 const intptr_t osr_id = Compiler::kNoOSRDeoptId;
122
123 auto pipeline = CompilationPipeline::New(zone, function_);
124
125 parsed_function_ = new (zone)
126 ParsedFunction(thread, Function::ZoneHandle(zone, function_.ptr()));
127 pipeline->ParseFunction(parsed_function_);
128
129 // Extract type feedback before the graph is built, as the graph
130 // builder uses it to attach it to nodes.
131 ic_data_array_ = new (zone) ZoneGrowableArray<const ICData*>();
132 if (mode_ == CompilerPass::kJIT) {
133 function_.RestoreICDataMap(ic_data_array_, /*clone_ic_data=*/false);
134 }
135
136 flow_graph_ = pipeline->BuildFlowGraph(zone, parsed_function_, ic_data_array_,
137 osr_id, optimized);
138
139 if (mode_ == CompilerPass::kAOT) {
140 flow_graph_->PopulateWithICData(function_);
141 }
142
143 if (mode_ == CompilerPass::kJIT && flow_graph_->should_reorder_blocks()) {
145 }
146
147 pass_state_ =
148 new CompilerPassState(thread, flow_graph_, speculative_policy_.get());
149
150 if (optimized) {
151 JitCallSpecializer jit_call_specializer(flow_graph_,
152 speculative_policy_.get());
153 AotCallSpecializer aot_call_specializer(
154 /*precompiler=*/nullptr, flow_graph_, speculative_policy_.get());
155 if (mode_ == CompilerPass::kAOT) {
156 pass_state_->call_specializer = &aot_call_specializer;
157 } else {
158 pass_state_->call_specializer = &jit_call_specializer;
159 }
160
161 if (passes.size() > 0) {
162 flow_graph_ = CompilerPass::RunPipelineWithPasses(pass_state_, passes);
163 } else {
164 flow_graph_ = CompilerPass::RunPipeline(mode_, pass_state_);
165 }
166 pass_state_->call_specializer = nullptr;
167 }
168
169 return flow_graph_;
170}
171
173 std::initializer_list<CompilerPass::Id> passes) {
174 JitCallSpecializer jit_call_specializer(flow_graph_,
175 speculative_policy_.get());
176 AotCallSpecializer aot_call_specializer(/*precompiler=*/nullptr, flow_graph_,
177 speculative_policy_.get());
178 if (mode_ == CompilerPass::kAOT) {
179 pass_state_->call_specializer = &aot_call_specializer;
180 } else {
181 pass_state_->call_specializer = &jit_call_specializer;
182 }
183
184 flow_graph_ = CompilerPass::RunPipelineWithPasses(pass_state_, passes);
185 pass_state_->call_specializer = nullptr;
186}
187
190 CompilerPass::kSetOuterInliningId,
191 CompilerPass::kTypePropagation,
192 CompilerPass::kCanonicalize,
193 CompilerPass::kBranchSimplify,
194 CompilerPass::kIfConvert,
195 CompilerPass::kConstantPropagation,
196 CompilerPass::kTypePropagation,
197 CompilerPass::kWidenSmiToInt32,
198 CompilerPass::kSelectRepresentations_Final,
199 CompilerPass::kTypePropagation,
200 CompilerPass::kTryCatchOptimization,
201 CompilerPass::kEliminateEnvironments,
202 CompilerPass::kEliminateDeadPhis,
203 CompilerPass::kDCE,
204 CompilerPass::kCanonicalize,
205 CompilerPass::kDelayAllocations,
206 CompilerPass::kEliminateWriteBarriers,
207 CompilerPass::kFinalizeGraph,
208 CompilerPass::kAllocateRegisters,
209 CompilerPass::kReorderBlocks,
210 });
211}
212
214 Zone* zone = thread_->zone();
215 const bool optimized = true;
216
217 SpeculativeInliningPolicy speculative_policy(/*enable_suppression=*/false);
218
219#if defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_IA32)
220 const intptr_t far_branch_level = 0;
221#else
222 const intptr_t far_branch_level = 1;
223#endif
224
225 ASSERT(pass_state_->inline_id_to_function.length() ==
226 pass_state_->caller_inline_id.length());
227 compiler::ObjectPoolBuilder object_pool_builder;
228 compiler::Assembler assembler(&object_pool_builder, far_branch_level);
229 FlowGraphCompiler graph_compiler(
230 &assembler, flow_graph_, *parsed_function_, optimized,
231 &speculative_policy, pass_state_->inline_id_to_function,
232 pass_state_->inline_id_to_token_pos, pass_state_->caller_inline_id,
233 ic_data_array_);
234
235 graph_compiler.CompileGraph();
236
237 const auto& deopt_info_array =
238 Array::Handle(zone, graph_compiler.CreateDeoptInfo(&assembler));
239 const auto pool_attachment = Code::PoolAttachment::kAttachPool;
240 Code& code = Code::Handle();
241 {
242 SafepointWriteRwLocker ml(thread_,
243 thread_->isolate_group()->program_lock());
244 code ^= Code::FinalizeCode(&graph_compiler, &assembler, pool_attachment,
245 optimized, nullptr);
246 }
247 code.set_is_optimized(optimized);
248 code.set_owner(function_);
249
250 graph_compiler.FinalizePcDescriptors(code);
251 code.set_deopt_info_array(deopt_info_array);
252
253 graph_compiler.FinalizeStackMaps(code);
254 graph_compiler.FinalizeVarDescriptors(code);
255 graph_compiler.FinalizeExceptionHandlers(code);
256 graph_compiler.FinalizeCatchEntryMovesMap(code);
257 graph_compiler.FinalizeStaticCallTargetsTable(code);
258 graph_compiler.FinalizeCodeSourceMap(code);
259
260 {
261 SafepointWriteRwLocker ml(thread_,
262 thread_->isolate_group()->program_lock());
263 if (optimized) {
264 function_.InstallOptimizedCode(code);
265 } else {
266 function_.set_unoptimized_code(code);
267 function_.AttachCode(code);
268 }
269 }
270
271 // We expect there to be no deoptimizations.
272 if (mode_ == CompilerPass::kAOT) {
273 EXPECT(deopt_info_array.IsNull() || deopt_info_array.Length() == 0);
274 }
275
276#if !defined(PRODUCT)
277 if (FLAG_disassemble_optimized) {
278 Disassembler::DisassembleCode(function_, code, optimized);
279 }
280#endif
281}
282
283bool ILMatcher::TryMatch(std::initializer_list<MatchCode> match_codes,
284 MatchOpCode insert_before) {
285 std::vector<MatchCode> qcodes = match_codes;
286
287 if (insert_before != kInvalidMatchOpCode) {
288 for (auto pos = qcodes.begin(); pos < qcodes.end(); pos++) {
289 pos = qcodes.insert(pos, insert_before) + 1;
290 }
291 }
292
293 if (trace_) {
294 OS::PrintErr("ILMatcher: Matching the following graph\n");
295 FlowGraphPrinter::PrintGraph("ILMatcher", flow_graph_);
296 OS::PrintErr("ILMatcher: Starting match at %s:\n", cursor_->ToCString());
297 }
298
299 Instruction* cursor = cursor_;
300 for (size_t i = 0; i < qcodes.size(); ++i) {
301 Instruction** capture = qcodes[i].capture_;
302 if (parallel_moves_handling_ == ParallelMovesHandling::kSkip) {
303 while (cursor->IsParallelMove()) {
304 cursor = cursor->next();
305 }
306 }
307 if (trace_) {
308 OS::PrintErr(" matching %30s @ %s\n",
309 MatchOpCodeToCString(qcodes[i].opcode()),
310 cursor->ToCString());
311 }
312
313 auto next = MatchInternal(qcodes, i, cursor);
314 if (next == nullptr) {
315 if (trace_) {
316 OS::PrintErr(" -> Match failed\n");
317 }
318 cursor = next;
319 break;
320 }
321 if (capture != nullptr) {
322 *capture = cursor;
323 }
324 cursor = next;
325 }
326 if (cursor != nullptr) {
327 cursor_ = cursor;
328 return true;
329 }
330 return false;
331}
332
333Instruction* ILMatcher::MatchInternal(std::vector<MatchCode> match_codes,
334 size_t i,
335 Instruction* cursor) {
336 const MatchOpCode opcode = match_codes[i].opcode();
337 if (opcode == kMatchAndMoveBranchTrue) {
338 auto branch = cursor->AsBranch();
339 if (branch == nullptr) return nullptr;
340 return branch->true_successor();
341 }
342 if (opcode == kMatchAndMoveBranchFalse) {
343 auto branch = cursor->AsBranch();
344 if (branch == nullptr) return nullptr;
345 return branch->false_successor();
346 }
347 if (opcode == kNop) {
348 return cursor;
349 }
350 if (opcode == kMoveAny) {
351 return cursor->next();
352 }
353 if (opcode == kMoveParallelMoves) {
354 while (cursor != nullptr && cursor->IsParallelMove()) {
355 cursor = cursor->next();
356 }
357 return cursor;
358 }
359
360 if (opcode == kMoveGlob) {
361 ASSERT((i + 1) < match_codes.size());
362 while (true) {
363 if (cursor == nullptr) return nullptr;
364 if (MatchInternal(match_codes, i + 1, cursor) != nullptr) {
365 return cursor;
366 }
367 if (auto as_goto = cursor->AsGoto()) {
368 cursor = as_goto->successor();
369 } else {
370 cursor = cursor->next();
371 }
372 }
373 }
374
375 if (opcode == kMoveDebugStepChecks) {
376 while (cursor != nullptr && cursor->IsDebugStepCheck()) {
377 cursor = cursor->next();
378 }
379 return cursor;
380 }
381
382 if (opcode == kMatchAndMoveGoto) {
383 if (auto goto_instr = cursor->AsGoto()) {
384 return goto_instr->successor();
385 }
386 }
387
388 switch (opcode) {
389#define EMIT_CASE(Instruction, _) \
390 case kMatch##Instruction: { \
391 if (cursor->Is##Instruction()) { \
392 return cursor; \
393 } \
394 return nullptr; \
395 } \
396 case kMatchAndMove##Instruction: { \
397 if (cursor->Is##Instruction()) { \
398 return cursor->next(); \
399 } \
400 return nullptr; \
401 } \
402 case kMatchAndMoveOptional##Instruction: { \
403 if (cursor->Is##Instruction()) { \
404 return cursor->next(); \
405 } \
406 return cursor; \
407 }
410#undef EMIT_CASE
411 default:
412 UNREACHABLE();
413 }
414
415 UNREACHABLE();
416 return nullptr;
417}
418
419const char* ILMatcher::MatchOpCodeToCString(MatchOpCode opcode) {
420 if (opcode == kMatchAndMoveBranchTrue) {
421 return "kMatchAndMoveBranchTrue";
422 }
423 if (opcode == kMatchAndMoveBranchFalse) {
424 return "kMatchAndMoveBranchFalse";
425 }
426 if (opcode == kNop) {
427 return "kNop";
428 }
429 if (opcode == kMoveAny) {
430 return "kMoveAny";
431 }
432 if (opcode == kMoveParallelMoves) {
433 return "kMoveParallelMoves";
434 }
435 if (opcode == kMoveGlob) {
436 return "kMoveGlob";
437 }
438 if (opcode == kMoveDebugStepChecks) {
439 return "kMoveDebugStepChecks";
440 }
441
442 switch (opcode) {
443#define EMIT_CASE(Instruction, _) \
444 case kMatch##Instruction: \
445 return "kMatch" #Instruction; \
446 case kMatchAndMove##Instruction: \
447 return "kMatchAndMove" #Instruction; \
448 case kMatchAndMoveOptional##Instruction: \
449 return "kMatchAndMoveOptional" #Instruction;
452#undef EMIT_CASE
453 default:
454 UNREACHABLE();
455 }
456
457 UNREACHABLE();
458 return nullptr;
459}
460
461} // namespace dart
SkPoint pos
static float next(float f)
#define EXPECT(type, expectedAlignment, expectedSize)
#define UNREACHABLE()
Definition assert.h:248
static Dart_Handle NewHandle(Thread *thread, ObjectPtr raw)
static ObjectPtr UnwrapHandle(Dart_Handle object)
intptr_t length() const
static void AssignEdgeWeights(FlowGraph *flow_graph)
TypeParameterPtr TypeParameterAt(intptr_t index, Nullability nullability=Nullability::kNonNullable) const
Definition object.cc:3739
static CodePtr FinalizeCode(FlowGraphCompiler *compiler, compiler::Assembler *assembler, PoolAttachment pool_attachment, bool optimized, CodeStatistics *stats)
Definition object.cc:18068
static CompilationPipeline * New(Zone *zone, const Function &function)
Definition compiler.cc:202
static DART_WARN_UNUSED_RESULT FlowGraph * RunPipeline(PipelineMode mode, CompilerPassState *state)
static DART_WARN_UNUSED_RESULT FlowGraph * RunPipelineWithPasses(CompilerPassState *state, std::initializer_list< CompilerPass::Id > passes)
static constexpr intptr_t kNoOSRDeoptId
Definition compiler.h:73
static void DisassembleCode(const Function &function, const Code &code, bool optimized)
void FinalizeVarDescriptors(const Code &code)
void FinalizeCatchEntryMovesMap(const Code &code)
void FinalizeStaticCallTargetsTable(const Code &code)
void FinalizeExceptionHandlers(const Code &code)
void FinalizeStackMaps(const Code &code)
void FinalizeCodeSourceMap(const Code &code)
ArrayPtr CreateDeoptInfo(compiler::Assembler *assembler)
void FinalizePcDescriptors(const Code &code)
static void PrintGraph(const char *phase, FlowGraph *flow_graph)
void PopulateWithICData(const Function &function)
bool should_reorder_blocks() const
Definition flow_graph.h:510
void set_unoptimized_code(const Code &value) const
Definition object.cc:8096
void RestoreICDataMap(ZoneGrowableArray< const ICData * > *deopt_id_to_ic_data, bool clone_ic_data) const
Definition object.cc:11275
void InstallOptimizedCode(const Code &code) const
Definition object.cc:7957
void AttachCode(const Code &value) const
Definition object.cc:7985
TypeParameterPtr TypeParameterAt(intptr_t index, Nullability nullability=Nullability::kNonNullable) const
Definition object.cc:8939
bool TryMatch(std::initializer_list< MatchCode > match_codes, MatchOpCode insert_before=kInvalidMatchOpCode)
Instruction * next() const
Definition il.h:1087
const char * ToCString() const
SafepointRwLock * program_lock()
Definition isolate.h:532
ClassPtr LookupClassAllowPrivate(const String &name) const
Definition object.cc:14160
FunctionPtr LookupFunctionAllowPrivate(const String &name) const
Definition object.cc:14131
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
ObjectPtr ptr() const
Definition object.h:332
static Object & Handle()
Definition object.h:407
static Object & ZoneHandle()
Definition object.h:419
static StringPtr New(Thread *thread, const char *cstr)
Definition symbols.h:722
static Dart_Handle LoadTestScript(const char *script, Dart_NativeEntryResolver resolver, const char *lib_uri=RESOLVED_USER_TEST_URI, bool finalize=true, bool allow_compile_errors=false)
Definition unit_test.cc:422
static Dart_Handle ReloadTestScript(const char *script)
Definition unit_test.cc:599
void RunAdditionalPasses(std::initializer_list< CompilerPass::Id > passes)
FlowGraph * RunPasses(std::initializer_list< CompilerPass::Id > passes)
void CompileGraphAndAttachFunction()
void RunForcedOptimizedAfterSSAPasses()
Zone * zone() const
static Thread * Current()
Definition thread.h:361
IsolateGroup * isolate_group() const
Definition thread.h:540
struct _Dart_Handle * Dart_Handle
Definition dart_api.h:258
Dart_NativeFunction(* Dart_NativeEntryResolver)(Dart_Handle name, int num_of_arguments, bool *auto_setup_scope)
Definition dart_api.h:3225
#define ASSERT(E)
GAsyncResult * result
#define FOR_EACH_INSTRUCTION(M)
Definition il.h:405
#define FOR_EACH_ABSTRACT_INSTRUCTION(M)
Definition il.h:553
#define EMIT_CASE(Instruction, _)
LibraryPtr LoadTestScript(const char *script, Dart_NativeEntryResolver resolver, const char *lib_uri)
@ kMatchAndMoveBranchFalse
@ kMoveDebugStepChecks
@ kInvalidMatchOpCode
@ kMatchAndMoveBranchTrue
@ kMoveParallelMoves
const char *const name
DART_EXPORT Dart_Handle Dart_Invoke(Dart_Handle target, Dart_Handle name, int number_of_arguments, Dart_Handle *arguments)
ObjectPtr Invoke(const Library &lib, const char *name)
FunctionPtr GetFunction(const Library &lib, const char *name)
LibraryPtr ReloadTestScript(const char *script)
ClassPtr GetClass(const Library &lib, const char *name)
Dart_Handle NewString(const char *str)
TypeParameterPtr GetClassTypeParameter(const Class &klass, intptr_t index)
TypeParameterPtr GetFunctionTypeParameter(const Function &fun, intptr_t index)
InstructionsPtr BuildInstructions(std::function< void(compiler::Assembler *assembler)> fun)
CallSpecializer * call_specializer
GrowableArray< TokenPosition > inline_id_to_token_pos
GrowableArray< intptr_t > caller_inline_id
GrowableArray< const Function * > inline_id_to_function
#define EXPECT_VALID(handle)
Definition unit_test.h:650