Flutter Engine
The Flutter Engine
inliner_test.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
12#include "vm/object.h"
13#include "vm/unit_test.h"
14
15namespace dart {
16
17// Test that the redefinition for an inlined polymorphic function used with
18// multiple receiver cids does not have a concrete type.
19ISOLATE_UNIT_TEST_CASE(Inliner_PolyInliningRedefinition) {
20 const char* kScript = R"(
21 abstract class A {
22 String toInline() { return "A"; }
23 }
24
25 class B extends A {}
26 class C extends A {
27 @override
28 String toInline() { return "C";}
29 }
30 class D extends A {}
31
32 testInlining(A arg) {
33 arg.toInline();
34 }
35
36 main() {
37 for (var i = 0; i < 10; i++) {
38 testInlining(B());
39 testInlining(C());
40 testInlining(D());
41 }
42 }
43 )";
44
45 const auto& root_library = Library::Handle(LoadTestScript(kScript));
46 const auto& function =
47 Function::Handle(GetFunction(root_library, "testInlining"));
48
49 Invoke(root_library, "main");
50
52 FlowGraph* flow_graph = pipeline.RunPasses({
53 CompilerPass::kComputeSSA,
54 CompilerPass::kApplyICData,
55 CompilerPass::kTryOptimizePatterns,
56 CompilerPass::kSetOuterInliningId,
57 CompilerPass::kTypePropagation,
58 CompilerPass::kApplyClassIds,
59 CompilerPass::kInlining,
60 });
61
62 auto entry = flow_graph->graph_entry()->normal_entry();
63 EXPECT(entry != nullptr);
64
65 EXPECT(entry->initial_definitions()->length() == 1);
66 EXPECT(entry->initial_definitions()->At(0)->IsParameter());
67 ParameterInstr* param = entry->initial_definitions()->At(0)->AsParameter();
68
69 // First we find the start of the prelude for the inlined instruction,
70 // and also keep a reference to the LoadClassId instruction for later.
71 LoadClassIdInstr* lcid = nullptr;
72 BranchInstr* prelude = nullptr;
73
74 ILMatcher cursor(flow_graph, entry);
76 {
77 {kMatchLoadClassId, &lcid},
78 {kMatchBranch, &prelude},
79 },
80 /*insert_before=*/kMoveGlob));
81
82 const Class& cls = Class::Handle(
83 root_library.LookupClass(String::Handle(Symbols::New(thread, "B"))));
84
85 Definition* cid_B = flow_graph->GetConstant(Smi::Handle(Smi::New(cls.id())));
86 Instruction* current = prelude;
87
88 // We walk false branches until we either reach a branch instruction that uses
89 // B's cid for comparison to the value returned from the LCID instruction
90 // above, or a default case if there was no branch instruction for B's cid.
91 while (true) {
92 EXPECT(current->IsBranch());
93 const ComparisonInstr* check = current->AsBranch()->comparison();
94 EXPECT(check->left()->definition() == lcid);
95 if (check->right()->definition() == cid_B) break;
96 current = current->SuccessorAt(1);
97 // By following false paths, we should be walking a series of blocks that
98 // looks like:
99 // B#[target]:#
100 // Branch if <check on class ID>
101 // If we end up not finding a branch, then we're in a default case
102 // that contains a class check.
103 current = current->next();
104 if (!current->IsBranch()) {
105 break;
106 }
107 }
108 // If we found a branch that checks against the class ID, we follow the true
109 // branch to a block that contains only a goto to the desired join block.
110 if (current->IsBranch()) {
111 current = current->SuccessorAt(0);
112 } else {
113 // We're in the default case, which will check the class ID to make sure
114 // it's the one expected for the fallthrough. That check will be followed
115 // by a goto to the desired join block.
116 EXPECT(current->IsRedefinition());
117 const auto redef = current->AsRedefinition();
118 EXPECT(redef->value()->definition() == lcid);
119 current = current->next();
120 EXPECT(current->IsCheckClassId());
121 EXPECT(current->AsCheckClassId()->value()->definition() == redef);
122 }
123 current = current->next();
124 EXPECT(current->IsGoto());
125 current = current->AsGoto()->successor();
126 // Now we should be at a block that starts like:
127 // BY[join]:# pred(...)
128 // vW <- Redefinition(vV)
129 //
130 // where vV is a reference to the function parameter (the receiver of
131 // the inlined function).
132 current = current->next();
133 EXPECT(current->IsRedefinition());
134 EXPECT(current->AsRedefinition()->value()->definition() == param);
135 EXPECT(current->AsRedefinition()->Type()->ToCid() == kDynamicCid);
136}
137
138ISOLATE_UNIT_TEST_CASE(Inliner_TypedData_Regress7551) {
139 const char* kScript = R"(
140 import 'dart:typed_data';
141
142 setValue(Int32List list, int value) {
143 list[0] = value;
144 }
145
146 main() {
147 final list = Int32List(10);
148 setValue(list, 0x1122334455);
149 }
150 )";
151
152 const auto& root_library = Library::Handle(LoadTestScript(kScript));
153 const auto& function =
154 Function::Handle(GetFunction(root_library, "setValue"));
155
156 Invoke(root_library, "main");
157
158 TestPipeline pipeline(function, CompilerPass::kJIT);
159 FlowGraph* flow_graph = pipeline.RunPasses({
160 CompilerPass::kComputeSSA,
161 CompilerPass::kApplyICData,
162 CompilerPass::kTryOptimizePatterns,
163 CompilerPass::kSetOuterInliningId,
164 CompilerPass::kTypePropagation,
165 CompilerPass::kApplyClassIds,
166 CompilerPass::kInlining,
167 });
168
169 auto entry = flow_graph->graph_entry()->normal_entry();
170
171 EXPECT(entry->initial_definitions()->length() == 2);
172 EXPECT(entry->initial_definitions()->At(0)->IsParameter());
173 EXPECT(entry->initial_definitions()->At(1)->IsParameter());
174 ParameterInstr* list_param =
175 entry->initial_definitions()->At(0)->AsParameter();
176 ParameterInstr* value_param =
177 entry->initial_definitions()->At(1)->AsParameter();
178
179 ILMatcher cursor(flow_graph, entry);
180
181 CheckArrayBoundInstr* bounds_check_instr = nullptr;
182 UnboxInt32Instr* unbox_instr = nullptr;
183 StoreIndexedInstr* store_instr = nullptr;
184
185 RELEASE_ASSERT(cursor.TryMatch({
186 {kMoveGlob},
187 {kMatchAndMoveCheckArrayBound, &bounds_check_instr},
188 {kMatchAndMoveUnboxInt32, &unbox_instr},
189 {kMatchAndMoveStoreIndexed, &store_instr},
190 }));
191
192 RELEASE_ASSERT(unbox_instr->InputAt(0)->definition()->OriginalDefinition() ==
193 value_param);
194 RELEASE_ASSERT(store_instr->InputAt(0)->definition() == list_param);
195 RELEASE_ASSERT(store_instr->InputAt(2)->definition() == unbox_instr);
196 RELEASE_ASSERT(unbox_instr->is_truncating());
197}
198
199#if defined(DART_PRECOMPILER)
200
201// Verifies that all calls are inlined in List.generate call
202// with a simple closure.
203ISOLATE_UNIT_TEST_CASE(Inliner_List_generate) {
204 const char* kScript = R"(
205 foo(n) => List<int>.generate(n, (int x) => x, growable: false);
206 main() {
207 foo(100);
208 }
209 )";
210
211 const auto& root_library = Library::Handle(LoadTestScript(kScript));
212 const auto& function = Function::Handle(GetFunction(root_library, "foo"));
213
214 TestPipeline pipeline(function, CompilerPass::kAOT);
215 FlowGraph* flow_graph = pipeline.RunPasses({});
216
217 auto entry = flow_graph->graph_entry()->normal_entry();
218 ILMatcher cursor(flow_graph, entry, /*trace=*/true,
219 ParallelMovesHandling::kSkip);
220
221 RELEASE_ASSERT(cursor.TryMatch({
222 kMoveGlob,
223 kMatchAndMoveCreateArray,
224 kMatchAndMoveUnboxInt64,
225 kMatchAndMoveGoto,
226
227 // Loop header
228 kMatchAndMoveJoinEntry,
229 kMatchAndMoveCheckStackOverflow,
230 kMatchAndMoveBranchTrue,
231
232 // Loop body
233 kMatchAndMoveTargetEntry,
234 kMatchAndMoveBoxInt64,
235 kMatchAndMoveStoreIndexed,
236 kMatchAndMoveBinaryInt64Op,
237 kMatchAndMoveGoto,
238
239 // Loop header once again
240 kMatchAndMoveJoinEntry,
241 kMatchAndMoveCheckStackOverflow,
242 kMatchAndMoveBranchFalse,
243
244 // After loop
245 kMatchAndMoveTargetEntry,
246 kMatchDartReturn,
247 }));
248}
249
250// Verifies that pragma-decorated call gets inlined.
251ISOLATE_UNIT_TEST_CASE(Inliner_always_consider_inlining) {
252 const char* kScript = R"(
253 choice() {
254 dynamic x;
255 return x == 123;
256 }
257
258 @pragma("vm:always-consider-inlining")
259 bar(baz) {
260 if (baz is String) {
261 return 1;
262 }
263 if (baz is num) {
264 return 2;
265 }
266 if (baz is bool) {
267 dynamic j = 0;
268 for (int i = 0; i < 1024; i++) {
269 j += "i: $i".length;
270 }
271 return j;
272 }
273 return 4;
274 }
275
276 bbar(bbaz, something) {
277 if (bbaz == null) {
278 return "null";
279 }
280 return bar(bbaz);
281 }
282
283 main(args) {
284 print(bbar(42, "something"));
285 print(bbar(choice() ? "abc": 42, "something"));
286 print(bbar("abc", "something"));
287 }
288 )";
289
290 const auto& root_library = Library::Handle(LoadTestScript(kScript));
291 const auto& function = Function::Handle(GetFunction(root_library, "main"));
292
293 TestPipeline pipeline(function, CompilerPass::kAOT);
294 FlowGraph* flow_graph = pipeline.RunPasses({});
295
296 auto entry = flow_graph->graph_entry()->normal_entry();
297 ILMatcher cursor(flow_graph, entry, /*trace=*/true);
298
299 StaticCallInstr* call_print1;
300 StaticCallInstr* call_print2;
301 StaticCallInstr* call_print3;
302 StaticCallInstr* call_bar;
303 RELEASE_ASSERT(cursor.TryMatch({
304 kMoveGlob,
305 {kMatchAndMoveStaticCall, &call_print1},
306 kMoveGlob,
307 {kMatchAndMoveStaticCall, &call_bar},
308 kMoveGlob,
309 {kMatchAndMoveStaticCall, &call_print2},
310 kMoveGlob,
311 {kMatchAndMoveStaticCall, &call_print3},
312 kMoveGlob,
313 kMatchDartReturn,
314 }));
315 EXPECT(strcmp(call_print1->function().UserVisibleNameCString(), "print") ==
316 0);
317 EXPECT(strcmp(call_print2->function().UserVisibleNameCString(), "print") ==
318 0);
319 EXPECT(strcmp(call_print3->function().UserVisibleNameCString(), "print") ==
320 0);
321 EXPECT(strcmp(call_bar->function().UserVisibleNameCString(), "bar") == 0);
322}
323
324// Verifies that List.of gets inlined.
325ISOLATE_UNIT_TEST_CASE(Inliner_List_of_inlined) {
326 const char* kScript = R"(
327 main() {
328 final foo = List<String>.filled(100, "bar");
329 final the_copy1 = List.of(foo, growable: false);
330 print('${the_copy1.length}');
331 }
332 )";
333
334 const auto& root_library = Library::Handle(LoadTestScript(kScript));
335 const auto& function = Function::Handle(GetFunction(root_library, "main"));
336
337 TestPipeline pipeline(function, CompilerPass::kAOT);
338 FlowGraph* flow_graph = pipeline.RunPasses({});
339
340 auto entry = flow_graph->graph_entry()->normal_entry();
341 ILMatcher cursor(flow_graph, entry, /*trace=*/true);
342
343 StaticCallInstr* call_print;
344 RELEASE_ASSERT(cursor.TryMatch({
345 kMoveGlob,
346 kMatchAndMoveJoinEntry,
347 kMoveGlob,
348 kMatchAndMoveBranchTrue,
349 kMoveGlob,
350 kMatchAndMoveJoinEntry,
351 kMatchAndMoveCheckStackOverflow,
352 kMatchAndMoveBranchFalse,
353 kMatchAndMoveTargetEntry,
354 kMoveGlob,
355 kMatchAndMoveJoinEntry,
356 kMoveGlob,
357 kMatchAndMoveBranchFalse,
358 kMoveGlob,
359 {kMatchAndMoveStaticCall, &call_print},
360 kMoveGlob,
361 kMatchDartReturn,
362 }));
363 EXPECT(strcmp(call_print->function().UserVisibleNameCString(), "print") == 0);
364 // Length is fully forwarded and string interpolation is constant folded.
365 EXPECT_PROPERTY(call_print->ArgumentAt(0),
366 it.IsConstant() && it.AsConstant()->value().IsString() &&
367 String::Cast(it.AsConstant()->value()).Equals("100"));
368}
369
370#endif // defined(DART_PRECOMPILER)
371
372// Test that when force-optimized functions get inlined, deopt_id and
373// environment for instructions coming from those functions get overwritten
374// by deopt_id and environment from the call itself.
375ISOLATE_UNIT_TEST_CASE(Inliner_InlineForceOptimized) {
376 const char* kScript = R"(
377 import 'dart:ffi';
378
379 @pragma('vm:never-inline')
380 int foo(int x) {
381 dynamic ptr = Pointer.fromAddress(x);
382 return x + ptr.hashCode;
383 }
384 main() {
385 int r = 0;
386 for (int i = 0; i < 1000; i++) {
387 r += foo(r);
388 }
389 return r;
390 }
391 )";
392
393 const auto& root_library = Library::Handle(LoadTestScript(kScript));
394 const auto& function = Function::Handle(GetFunction(root_library, "foo"));
395
396 Invoke(root_library, "main");
397
398 TestPipeline pipeline(function, CompilerPass::kJIT);
399 FlowGraph* flow_graph = pipeline.RunPasses({
400 CompilerPass::kComputeSSA,
401 CompilerPass::kApplyICData,
402 CompilerPass::kTryOptimizePatterns,
403 CompilerPass::kSetOuterInliningId,
404 CompilerPass::kTypePropagation,
405 CompilerPass::kApplyClassIds,
406 });
407
408 auto entry = flow_graph->graph_entry()->normal_entry();
409 StaticCallInstr* call_instr = nullptr;
410 {
411 ILMatcher cursor(flow_graph, entry);
412 RELEASE_ASSERT(cursor.TryMatch({
413 {kMoveGlob},
414 {kMatchAndMoveStaticCall, &call_instr},
415 }));
416 EXPECT(strcmp(call_instr->function().UserVisibleNameCString(),
417 "Pointer.fromAddress") == 0);
418 }
419
420 pipeline.RunAdditionalPasses({
421 CompilerPass::kInlining,
422 });
423
424 AllocateObjectInstr* allocate_object_instr = nullptr;
425 {
426 ILMatcher cursor(flow_graph, entry);
427 RELEASE_ASSERT(cursor.TryMatch({
428 {kMoveGlob},
429 {kMatchAndMoveAllocateObject, &allocate_object_instr},
430 }));
431 }
432
433 // Ensure that AllocateObject instruction that came from force-optimized
434 // function has deopt and environment taken from the Call instruction.
435 EXPECT(call_instr->deopt_id() == allocate_object_instr->deopt_id());
436 EXPECT(DeoptId::IsDeoptBefore(call_instr->deopt_id()));
437
438 auto allocate_object_instr_env = allocate_object_instr->env();
439 EXPECT(allocate_object_instr_env->LazyDeoptToBeforeDeoptId());
440 EXPECT(allocate_object_instr_env->Outermost()->GetDeoptId() ==
441 call_instr->deopt_id());
442 const auto call_instr_env = call_instr->env();
443 const intptr_t call_first_index =
444 call_instr_env->Length() - call_instr->InputCount();
445 const intptr_t allocate_first_index =
446 allocate_object_instr_env->Length() - call_instr->InputCount();
447 for (intptr_t i = 0; i < call_instr->InputCount(); i++) {
448 EXPECT(call_instr_env->ValueAt(call_first_index + i)->definition() ==
449 allocate_object_instr_env->ValueAt(allocate_first_index + i)
450 ->definition());
451 }
452}
453
457 const char* str = nullptr;
458 Dart_StringToCString(handle, &str);
459 OS::Print("%s\n", str);
461}
462
464#ifndef PRODUCT
466
467 Dart_StackTrace stacktrace;
470
471 intptr_t frame_count = 0;
472 result = Dart_StackTraceLength(stacktrace, &frame_count);
474 EXPECT_EQ(3, frame_count);
475 // Test something bigger than the preallocated size to verify nothing was
476 // truncated.
477 EXPECT(102 > StackTrace::kPreallocatedStackdepth);
478
480 Dart_Handle script_url;
481 intptr_t line_number = 0;
482 intptr_t column_number = 0;
483 const char* cstr = "";
484 const char* test_lib = "file:///test-lib";
485
486 // Top frame is InspectStack().
488 result = Dart_GetActivationFrame(stacktrace, 0, &frame);
491 &line_number, &column_number);
494 EXPECT_STREQ("InspectStack", cstr);
495 Dart_StringToCString(script_url, &cstr);
496 EXPECT_STREQ(test_lib, cstr);
497 EXPECT_EQ(11, line_number);
498 EXPECT_EQ(24, column_number);
499
500 // Second frame is foo() positioned at call to InspectStack().
501 result = Dart_GetActivationFrame(stacktrace, 1, &frame);
504 &line_number, &column_number);
507 EXPECT_STREQ("foo", cstr);
508 Dart_StringToCString(script_url, &cstr);
509 EXPECT_STREQ(test_lib, cstr);
510
511 // Bottom frame positioned at main().
512 result = Dart_GetActivationFrame(stacktrace, frame_count - 1, &frame);
515 &line_number, &column_number);
518 EXPECT_STREQ("main", cstr);
519 Dart_StringToCString(script_url, &cstr);
520 EXPECT_STREQ(test_lib, cstr);
521
522 // Out-of-bounds frames.
523 result = Dart_GetActivationFrame(stacktrace, frame_count, &frame);
525 result = Dart_GetActivationFrame(stacktrace, -1, &frame);
527
530#endif // !PRODUCT
531}
532
534 int argument_count,
535 bool* auto_setup_scope) {
536 ASSERT(auto_setup_scope != nullptr);
537 *auto_setup_scope = true;
538 const char* cstr = nullptr;
541 if (strcmp(cstr, "testPrint") == 0) {
542 return &TestPrint;
543 } else {
544 return &InspectStack;
545 }
546}
547
548TEST_CASE(Inliner_InlineAndRunForceOptimized) {
549 auto check_handle = [](Dart_Handle handle) {
550 if (Dart_IsError(handle)) {
551 OS::PrintErr("Encountered unexpected error: %s\n", Dart_GetError(handle));
552 FATAL("Aborting");
553 }
554 return handle;
555 };
556
557 auto get_integer = [&](Dart_Handle lib, const char* name) {
558 Dart_Handle handle = Dart_GetField(lib, check_handle(NewString(name)));
559 check_handle(handle);
560
561 int64_t value = 0;
562 handle = Dart_IntegerToInt64(handle, &value);
563 check_handle(handle);
564 OS::Print("Field '%s': %" Pd64 "\n", name, value);
565 return value;
566 };
567
568 const char* kScriptChars = R"(
569import 'dart:ffi';
570import 'dart:_internal';
571
572int _add(int a, int b) => a + b;
573
574@pragma('vm:external-name', "testPrint")
575external void print(String s);
576
577@pragma("vm:external-name", "InspectStack")
578external InspectStack();
579
580@pragma('vm:never-inline')
581void nop() {}
582
583int prologueCount = 0;
584int epilogueCount = 0;
585
586@pragma('vm:never-inline')
587void countPrologue() {
588 prologueCount++;
589 print('countPrologue: $prologueCount');
590}
591
592@pragma('vm:never-inline')
593void countEpilogue() {
594 epilogueCount++;
595 print('countEpilogue: $epilogueCount');
596}
597
598@pragma('vm:force-optimize')
599@pragma('vm:idempotent')
600@pragma('vm:prefer-inline')
601int idempotentForceOptimizedFunction(int x) {
602 countPrologue();
603 print('deoptimizing');
604
605 InspectStack();
606 VMInternalsForTesting.deoptimizeFunctionsOnStack();
607 InspectStack();
608 print('deoptimizing after');
609 countEpilogue();
610 return _add(x, 1);
611}
612
613@pragma('vm:never-inline')
614int foo(int x, {bool onlyOptimizeFunction = false}) {
615 if (onlyOptimizeFunction) {
616 print('Optimizing `foo`');
617 for (int i = 0; i < 100000; i++) nop();
618 }
619 print('Running `foo`');
620 return x + idempotentForceOptimizedFunction(x+1) + 1;
621}
622
623void main() {
624 for (int i = 0; i < 100; i++) {
625 print('\n\nround=$i');
626
627 // Get the `foo` function optimized while leaving prologue/epilogue counters
628 // untouched.
629 final (a, b) = (prologueCount, epilogueCount);
630 foo(i, onlyOptimizeFunction: true);
631 prologueCount = a;
632 epilogueCount = b;
633
634 // Execute the optimized function `foo` function (which has the
635 // `idempotentForceOptimizedFunction` inlined).
636 final result = foo(i);
637 if (result != (2 * i + 3)) throw 'Expected ${2 * i + 3} but got $result!';
638 }
639}
640 )";
642
643 Dart_Handle lib =
644 check_handle(TestCase::LoadTestScript(kScriptChars, nullptr));
646
647 // We disable OSR to ensure we control when the function gets optimized,
648 // namely afer a call to `foo(..., onlyOptimizeFunction:true)` it will be
649 // optimized and during a call to `foo(...)` it will get deoptimized.
650 IsolateGroup::Current()->set_use_osr(false);
651
652 // Run the test.
653 check_handle(Dart_Invoke(lib, NewString("main"), 0, nullptr));
654
655 // Examine the result.
656 const int64_t prologue_count = get_integer(lib, "prologueCount");
657 const int64_t epilogue_count = get_integer(lib, "epilogueCount");
658
659 // We always call the "foo" function when its optimized (and it's optimized
660 // code has the call to `idempotentForceOptimizedFunction` inlined).
661 //
662 // The `idempotentForceOptimizedFunction` will always execute prologue,
663 // lazy-deoptimize the `foo` frame, that will make the `foo` re-try the call
664 // to `idempotentForceOptimizedFunction`.
665 // = > We should see the prologue of the force-optimized function to be
666 // executed twice as many times as epilogue.
667 EXPECT_EQ(epilogue_count * 2, prologue_count);
668}
669
670} // namespace dart
#define check(reporter, ref, unref, make, kill)
Definition: RefCntTest.cpp:85
#define EXPECT(type, expectedAlignment, expectedSize)
#define RELEASE_ASSERT(cond)
Definition: assert.h:327
GraphEntryInstr * graph_entry() const
Definition: flow_graph.h:268
const char * UserVisibleNameCString() const
Definition: object.cc:10990
FunctionEntryInstr * normal_entry() const
Definition: il.h:2001
bool TryMatch(std::initializer_list< MatchCode > match_codes, MatchOpCode insert_before=kInvalidMatchOpCode)
static Object & Handle()
Definition: object.h:407
static SmiPtr New(intptr_t value)
Definition: object.h:10006
const Function & function() const
Definition: il.h:5623
static StringPtr New(Thread *thread, const char *cstr)
Definition: symbols.h:723
FlowGraph * RunPasses(std::initializer_list< CompilerPass::Id > passes)
DART_EXPORT Dart_Handle Dart_SetNativeResolver(Dart_Handle library, Dart_NativeEntryResolver resolver, Dart_NativeEntrySymbol symbol)
DART_EXPORT void Dart_EnterScope(void)
DART_EXPORT void Dart_ExitScope(void)
DART_EXPORT Dart_Handle Dart_IntegerToInt64(Dart_Handle integer, int64_t *value)
struct _Dart_Handle * Dart_Handle
Definition: dart_api.h:258
DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_Invoke(Dart_Handle target, Dart_Handle name, int number_of_arguments, Dart_Handle *arguments)
DART_EXPORT Dart_Handle Dart_GetNativeArgument(Dart_NativeArguments args, int index)
struct _Dart_NativeArguments * Dart_NativeArguments
Definition: dart_api.h:3019
DART_EXPORT void Dart_SetReturnValue(Dart_NativeArguments args, Dart_Handle retval)
DART_EXPORT Dart_Handle Dart_StringToCString(Dart_Handle str, const char **cstr)
void(* Dart_NativeFunction)(Dart_NativeArguments arguments)
Definition: dart_api.h:3207
DART_EXPORT Dart_Handle Dart_NewInteger(int64_t value)
DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_GetField(Dart_Handle container, Dart_Handle name)
DART_EXPORT bool Dart_IsError(Dart_Handle handle)
DART_EXPORT const char * Dart_GetError(Dart_Handle handle)
#define ASSERT(E)
double frame
Definition: examples.cpp:31
#define FATAL(error)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint8_t value
GAsyncResult * result
Dart_NativeFunction function
Definition: fuchsia.cc:51
int argument_count
Definition: fuchsia.cc:52
#define EXPECT_PROPERTY(entity, property)
Definition: dart_vm.cc:33
LibraryPtr LoadTestScript(const char *script, Dart_NativeEntryResolver resolver, const char *lib_uri)
Dart_Handle Dart_StackTraceLength(Dart_StackTrace trace, intptr_t *length)
Dart_Handle Dart_ActivationFrameInfo(Dart_ActivationFrame activation_frame, Dart_Handle *function_name, Dart_Handle *script_url, intptr_t *line_number, intptr_t *column_number)
Dart_Handle Dart_GetStackTrace(Dart_StackTrace *trace)
@ kDynamicCid
Definition: class_id.h:253
ObjectPtr Invoke(const Library &lib, const char *name)
FunctionPtr GetFunction(const Library &lib, const char *name)
void InspectStack(Dart_NativeArguments args)
struct _Dart_ActivationFrame * Dart_ActivationFrame
Dart_Handle Dart_GetActivationFrame(Dart_StackTrace trace, int frame_index, Dart_ActivationFrame *frame)
ISOLATE_UNIT_TEST_CASE(StackAllocatedDestruction)
static void TestPrint(Dart_NativeArguments args)
struct _Dart_StackTrace * Dart_StackTrace
const char *const function_name
static Dart_NativeFunction PrintAndInspectResolver(Dart_Handle name, int argument_count, bool *auto_setup_scope)
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
#define Pd64
Definition: globals.h:416
#define ISOLATE_UNIT_TEST_CASE(name)
Definition: unit_test.h:64
Dart_Handle NewString(const char *str)
Definition: unit_test.h:229
#define TEST_CASE(name)
Definition: unit_test.h:85
#define EXPECT_VALID(handle)
Definition: unit_test.h:643