Flutter Engine
The Flutter Engine
reachability_fence_test.cc
Go to the documentation of this file.
1// Copyright (c) 2020, 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#include <vector>
6
12#include "vm/object.h"
13#include "vm/unit_test.h"
14
15namespace dart {
16
17ISOLATE_UNIT_TEST_CASE(ReachabilityFence_Simple) {
18 // clang-format off
19 const char* kScript = R"(
20 import 'dart:_internal' show reachabilityFence;
21
22 int someGlobal = 0;
23
24 class A {
25 int? a;
26 }
27
28 void someFunction(int arg) {
29 someGlobal += arg;
30 }
31
32 main() {
33 final object = A()..a = 10;
34 someFunction(object.a!);
35 reachabilityFence(object);
36 }
37 )";
38 // clang-format on
39
40 const auto& root_library = Library::Handle(LoadTestScript(kScript));
41
42 Invoke(root_library, "main");
43
44 const auto& function = Function::Handle(GetFunction(root_library, "main"));
46 FlowGraph* flow_graph = pipeline.RunPasses({});
47 ASSERT(flow_graph != nullptr);
48
49 auto entry = flow_graph->graph_entry()->normal_entry();
50 EXPECT(entry != nullptr);
51
52 // v2 <- AllocateObject(A <not-aliased>) T{A}
53 // ...
54 // [use field of object v2]
55 // ReachabilityFence(v2)
56 AllocateObjectInstr* allocate_object = nullptr;
57 ReachabilityFenceInstr* fence = nullptr;
58
59 ILMatcher cursor(flow_graph, entry);
61 kMoveGlob,
62 // Allocate the object.
63 {kMatchAndMoveAllocateObject, &allocate_object},
65 // The call.
66 kMatchAndMoveStoreStaticField,
67 // The fence should not be moved before the call.
68 {kMatchAndMoveReachabilityFence, &fence},
69 }));
70
71 EXPECT(fence->value()->definition() == allocate_object);
72}
73
74ISOLATE_UNIT_TEST_CASE(ReachabilityFence_Loop) {
75 // clang-format off
76 const char* kScript = R"(
77 import 'dart:_internal' show reachabilityFence;
78
79 int someGlobal = 0;
80
81 class A {
82 int? a;
83 }
84
85 @pragma('vm:never-inline')
86 A makeSomeA() {
87 return A()..a = 10;
88 }
89
90 void someFunction(int arg) {
91 someGlobal += arg;
92 }
93
94 main() {
95 final object = makeSomeA();
96 for(int i = 0; i < 100000; i++) {
97 someFunction(object.a!);
98 reachabilityFence(object);
99 }
100 }
101 )";
102 // clang-format on
103
104 const auto& root_library = Library::Handle(LoadTestScript(kScript));
105
106 Invoke(root_library, "main");
107
108 const auto& function = Function::Handle(GetFunction(root_library, "main"));
109 TestPipeline pipeline(function, CompilerPass::kJIT);
110 FlowGraph* flow_graph = pipeline.RunPasses({});
111 ASSERT(flow_graph != nullptr);
112
113 auto entry = flow_graph->graph_entry()->normal_entry();
114 EXPECT(entry != nullptr);
115
116 StaticCallInstr* object = nullptr;
117 LoadFieldInstr* field_load = nullptr;
118 ReachabilityFenceInstr* fence = nullptr;
119
120 ILMatcher cursor(flow_graph, entry);
122 {
123 // Get the object from some method
124 {kMatchAndMoveStaticCall, &object},
125 // Load the field outside the loop.
126 {kMatchAndMoveLoadField, &field_load},
127 // Go into the loop.
129 // The fence should not be moved outside of the loop.
130 {kMatchAndMoveReachabilityFence, &fence},
131 },
132 /*insert_before=*/kMoveGlob));
133
134 EXPECT(field_load->instance()->definition() == object);
135 EXPECT(fence->value()->definition() == object);
136}
137
138ISOLATE_UNIT_TEST_CASE(ReachabilityFence_NoCanonicalize) {
139 // clang-format off
140 const char* kScript = R"(
141 import 'dart:_internal' show reachabilityFence;
142
143 int someGlobal = 0;
144
145 class A {
146 int? a;
147 }
148
149 @pragma('vm:never-inline')
150 A makeSomeA() {
151 return A()..a = 10;
152 }
153
154 void someFunction(int arg) {
155 someGlobal += arg;
156 }
157
158 main() {
159 final object = makeSomeA();
160 reachabilityFence(object);
161 for(int i = 0; i < 100000; i++) {
162 someFunction(object.a!);
163 reachabilityFence(object);
164 }
165 reachabilityFence(object);
166 reachabilityFence(object);
167 }
168 )";
169 // clang-format on
170
171 const auto& root_library = Library::Handle(LoadTestScript(kScript));
172
173 Invoke(root_library, "main");
174
175 const auto& function = Function::Handle(GetFunction(root_library, "main"));
176 TestPipeline pipeline(function, CompilerPass::kJIT);
177 FlowGraph* flow_graph = pipeline.RunPasses({});
178 ASSERT(flow_graph != nullptr);
179
180 auto entry = flow_graph->graph_entry()->normal_entry();
181 EXPECT(entry != nullptr);
182
183 StaticCallInstr* object = nullptr;
184 ReachabilityFenceInstr* fence1 = nullptr;
185 ReachabilityFenceInstr* fence2 = nullptr;
186 ReachabilityFenceInstr* fence3 = nullptr;
187 ReachabilityFenceInstr* fence4 = nullptr;
188
189 ILMatcher cursor(flow_graph, entry);
191 {
192 {kMatchAndMoveStaticCall, &object},
193 {kMatchAndMoveReachabilityFence, &fence1},
195 {kMatchAndMoveReachabilityFence, &fence2},
197 {kMatchAndMoveReachabilityFence, &fence3},
198 {kMatchAndMoveReachabilityFence, &fence4},
199 },
200 /*insert_before=*/kMoveGlob));
201
202 EXPECT(fence1->value()->definition() == object);
203 EXPECT(fence2->value()->definition() == object);
204 EXPECT(fence3->value()->definition() == object);
205 EXPECT(fence4->value()->definition() == object);
206}
207
208} // namespace dart
#define EXPECT(type, expectedAlignment, expectedSize)
#define RELEASE_ASSERT(cond)
Definition: assert.h:327
GraphEntryInstr * graph_entry() const
Definition: flow_graph.h:268
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
FlowGraph * RunPasses(std::initializer_list< CompilerPass::Id > passes)
#define ASSERT(E)
Dart_NativeFunction function
Definition: fuchsia.cc:51
Definition: dart_vm.cc:33
LibraryPtr LoadTestScript(const char *script, Dart_NativeEntryResolver resolver, const char *lib_uri)
@ kMatchAndMoveBranchFalse
@ kMatchAndMoveBranchTrue
ObjectPtr Invoke(const Library &lib, const char *name)
FunctionPtr GetFunction(const Library &lib, const char *name)
ISOLATE_UNIT_TEST_CASE(StackAllocatedDestruction)
#define ISOLATE_UNIT_TEST_CASE(name)
Definition: unit_test.h:64