Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
typed_data_aot_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
5#include <vector>
6
12#include "vm/object.h"
13#include "vm/unit_test.h"
14
15namespace dart {
16
17#if defined(DART_PRECOMPILER)
18
19// This test asserts that we are inlining accesses to typed data interfaces
20// (e.g. Uint8List) if there are no instantiated 3rd party classes.
21ISOLATE_UNIT_TEST_CASE(IRTest_TypedDataAOT_Inlining) {
22 const char* kScript =
23 R"(
24 import 'dart:typed_data';
25
26 foo(Uint8List list, int from) {
27 if (from >= list.length) {
28 return list[from];
29 }
30 }
31 )";
32
33 const auto& root_library = Library::Handle(LoadTestScript(kScript));
34 const auto& function = Function::Handle(GetFunction(root_library, "foo"));
35
36 TestPipeline pipeline(function, CompilerPass::kAOT);
37 FlowGraph* flow_graph = pipeline.RunPasses({});
38
39 auto entry = flow_graph->graph_entry()->normal_entry();
40 EXPECT(entry != nullptr);
41
42 LoadFieldInstr* load_field = nullptr;
43 GenericCheckBoundInstr* bounds_check = nullptr;
44 LoadFieldInstr* load_untagged = nullptr;
45 LoadIndexedInstr* load_indexed = nullptr;
46
47 ILMatcher cursor(flow_graph, entry);
48 RELEASE_ASSERT(cursor.TryMatch({
49 kMoveGlob,
50 {kMatchAndMoveLoadField, &load_field},
54 {kMatchAndMoveGenericCheckBound, &bounds_check},
55 {kMatchAndMoveLoadField, &load_untagged},
57 {kMatchAndMoveLoadIndexed, &load_indexed},
59 kMatchDartReturn,
60 }));
61
62 EXPECT(load_field->InputAt(0)->definition()->IsParameter());
63 EXPECT(bounds_check->length()
64 ->definition()
65 ->OriginalDefinitionIgnoreBoxingAndConstraints() == load_field);
66 EXPECT(load_untagged->InputAt(0)->definition()->IsParameter());
67 EXPECT(load_indexed->InputAt(0)->definition() == load_untagged);
68}
69
70// This test asserts that we are inlining get:length, [] and []= for all typed
71// data interfaces. It also ensures that the asserted IR actually works by
72// exercising it.
73ISOLATE_UNIT_TEST_CASE(IRTest_TypedDataAOT_FunctionalGetSet) {
74 const char* kTemplate =
75 R"(
76 import 'dart:typed_data';
77
78 void reverse%s(%s list) {
79 final length = list.length;
80 final halfLength = length >> 1;
81 for (int i = 0; i < halfLength; ++i) {
82 final tmp = list[length-i-1];
83 list[length-i-1] = list[i];
84 list[i] = tmp;
85 }
86 }
87 )";
88
89 char script_buffer[1024];
90 char uri_buffer[1024];
91 char function_name[1024];
92 auto& lib = Library::Handle();
93 auto& function = Function::Handle();
94
95 auto check_il = [&](const char* name) {
96 // Fill in the template with the [name].
97 Utils::SNPrint(script_buffer, sizeof(script_buffer), kTemplate, name, name);
98 Utils::SNPrint(uri_buffer, sizeof(uri_buffer), "file:///reverse-%s.dart",
99 name);
100 Utils::SNPrint(function_name, sizeof(function_name), "reverse%s", name);
101
102 // Create a new library, load the function and compile it using our AOT
103 // pipeline.
104 lib = LoadTestScript(script_buffer, nullptr, uri_buffer);
105 function = GetFunction(lib, function_name);
106 TestPipeline pipeline(function, CompilerPass::kAOT);
107 FlowGraph* flow_graph = pipeline.RunPasses({});
108 auto entry = flow_graph->graph_entry()->normal_entry();
109
110 // Ensure the IL matches what we expect.
111 ILMatcher cursor(flow_graph, entry);
112 EXPECT(cursor.TryMatch({
113 // Before loop
114 kMoveGlob,
115 kMatchAndMoveLoadField,
116 kMoveGlob,
117 kMatchAndMoveBranchTrue,
118
119 // Loop
120 kMoveGlob,
121 // Load 1
122 kMatchAndMoveGenericCheckBound,
123 kMoveGlob,
124 kMatchAndMoveLoadField,
125 kMoveParallelMoves,
126 kMatchAndMoveLoadIndexed,
127 kMoveGlob,
128 // Load 2
129 kMatchAndMoveGenericCheckBound,
130 kMoveGlob,
131 kMatchAndMoveLoadField,
132 kMoveParallelMoves,
133 kMatchAndMoveLoadIndexed,
134 kMoveGlob,
135 // Store 1
136 kMatchAndMoveCheckWritable,
137 kMoveParallelMoves,
138 kMatchAndMoveLoadField,
139 kMoveParallelMoves,
140 kMatchAndMoveStoreIndexed,
141 kMoveGlob,
142 // Store 2
143 kMoveParallelMoves,
144 kMatchAndMoveLoadField,
145 kMoveParallelMoves,
146 kMatchAndMoveStoreIndexed,
147 kMoveGlob,
148
149 // Exit the loop.
150 kMatchAndMoveBranchFalse,
151 kMoveGlob,
152 kMatchDartReturn,
153 }));
154 };
155
156 check_il("Uint8List");
157 check_il("Int8List");
158 check_il("Uint8ClampedList");
159 check_il("Int16List");
160 check_il("Uint16List");
161 check_il("Int32List");
162 check_il("Uint32List");
163 check_il("Int64List");
164 check_il("Uint64List");
165 check_il("Float32List");
166 check_il("Float64List");
167}
168
169// This test asserts that we get errors if receiver, index or value are null.
170ISOLATE_UNIT_TEST_CASE(IRTest_TypedDataAOT_FunctionalIndexError) {
171 const char* kTemplate =
172 R"(
173 import 'dart:typed_data';
174 void set%s(%s list, int index, %s value) {
175 list[index] = value;
176 }
177 )";
178
179 char script_buffer[1024];
180 char uri_buffer[1024];
181 char function_name[1024];
182 auto& lib = Library::Handle();
183 auto& function = Function::Handle();
184 auto& arguments = Array::Handle();
185 auto& result = Object::Handle();
186
187 const intptr_t kIndex = 1;
188 const intptr_t kLastStage = 3;
189
190 auto run_test = [&](const char* name, const char* type,
191 const TypedDataBase& data, const Object& value,
192 int stage) {
193 // Fill in the template with the [name].
194 Utils::SNPrint(script_buffer, sizeof(script_buffer), kTemplate, name, name,
195 type);
196 Utils::SNPrint(uri_buffer, sizeof(uri_buffer), "file:///set-%s.dart", name);
197 Utils::SNPrint(function_name, sizeof(function_name), "set%s", name);
198
199 // Create a new library, load the function and compile it using our AOT
200 // pipeline.
201 lib = LoadTestScript(script_buffer, nullptr, uri_buffer);
202 function = GetFunction(lib, function_name);
203 TestPipeline pipeline(function, CompilerPass::kAOT);
204 FlowGraph* flow_graph = pipeline.RunPasses({});
205 auto entry = flow_graph->graph_entry()->normal_entry();
206
207 // Ensure the IL matches what we expect.
208 ILMatcher cursor(flow_graph, entry, /*trace=*/true);
209 EXPECT(cursor.TryMatch({
210 // LoadField length
211 kMoveGlob,
212 kMatchAndMoveLoadField,
213
214 // Bounds check
215 kMoveGlob,
216 kMatchAndMoveGenericCheckBound,
217
218 // Store value.
219 kMoveGlob,
220 kMatchAndMoveLoadField,
221 kMoveParallelMoves,
222 kMatchAndMoveOptionalUnbox,
223 kMoveParallelMoves,
224 kMatchAndMoveStoreIndexed,
225
226 // Return
227 kMoveGlob,
228 kMatchDartReturn,
229 }));
230
231 // Compile the graph and attach the code.
232 pipeline.CompileGraphAndAttachFunction();
233
234 arguments = Array::New(3);
235 arguments.SetAt(0, stage == 0 ? Object::null_object() : data);
236 arguments.SetAt(
237 1, stage == 1 ? Object::null_object() : Smi::Handle(Smi::New(kIndex)));
238 arguments.SetAt(2, stage == 2 ? Object::null_object() : value);
239 result = DartEntry::InvokeFunction(function, arguments);
240
241 // Ensure we didn't deoptimize to unoptimized code.
242 EXPECT(function.unoptimized_code() == Code::null());
243
244 if (stage == kLastStage) {
245 // The last stage must be successful
246 EXPECT(result.IsNull());
247 } else {
248 // Ensure we get an error.
249 EXPECT(result.IsUnhandledException());
250 result = UnhandledException::Cast(result).exception();
251 }
252 };
253
254 const auto& uint8_list =
255 TypedData::Handle(TypedData::New(kTypedDataUint8ArrayCid, 16));
256 const auto& uint8c_list =
257 TypedData::Handle(TypedData::New(kTypedDataUint8ClampedArrayCid, 16));
258 const auto& int16_list =
259 TypedData::Handle(TypedData::New(kTypedDataInt16ArrayCid, 16));
260 const auto& uint16_list =
261 TypedData::Handle(TypedData::New(kTypedDataUint16ArrayCid, 16));
262 const auto& int32_list =
263 TypedData::Handle(TypedData::New(kTypedDataInt32ArrayCid, 16));
264 const auto& uint32_list =
265 TypedData::Handle(TypedData::New(kTypedDataUint32ArrayCid, 16));
266 const auto& int64_list =
267 TypedData::Handle(TypedData::New(kTypedDataInt64ArrayCid, 16));
268 const auto& uint64_list =
269 TypedData::Handle(TypedData::New(kTypedDataUint64ArrayCid, 16));
270 const auto& float32_list =
271 TypedData::Handle(TypedData::New(kTypedDataFloat32ArrayCid, 16));
272 const auto& float64_list =
273 TypedData::Handle(TypedData::New(kTypedDataFloat64ArrayCid, 16));
274 const auto& int8_list =
275 TypedData::Handle(TypedData::New(kTypedDataInt8ArrayCid, 16));
276 const auto& int_value = Integer::Handle(Integer::New(42));
277 const auto& float_value = Double::Handle(Double::New(4.2));
278 // With null safety nulls cannot be passed as non-nullable arguments, so
279 // skip all error stages and only run the last stage.
280 const intptr_t first_stage = kLastStage;
281 for (intptr_t stage = first_stage; stage <= kLastStage; ++stage) {
282 run_test("Uint8List", "int", int8_list, int_value, stage);
283 run_test("Int8List", "int", uint8_list, int_value, stage);
284 run_test("Uint8ClampedList", "int", uint8c_list, int_value, stage);
285 run_test("Int16List", "int", int16_list, int_value, stage);
286 run_test("Uint16List", "int", uint16_list, int_value, stage);
287 run_test("Int32List", "int", int32_list, int_value, stage);
288 run_test("Uint32List", "int", uint32_list, int_value, stage);
289 run_test("Int64List", "int", int64_list, int_value, stage);
290 run_test("Uint64List", "int", uint64_list, int_value, stage);
291 run_test("Float32List", "double", float32_list, float_value, stage);
292 run_test("Float64List", "double", float64_list, float_value, stage);
293 }
294}
295
296#endif // defined(DART_PRECOMPILER)
297
298} // namespace dart
#define EXPECT(type, expectedAlignment, expectedSize)
#define RELEASE_ASSERT(cond)
Definition assert.h:327
static Object & Handle()
Definition object.h:407
uint8_t value
GAsyncResult * result
Dart_NativeFunction function
Definition fuchsia.cc:51
const char * name
Definition fuchsia.cc:50
LibraryPtr LoadTestScript(const char *script, Dart_NativeEntryResolver resolver, const char *lib_uri)
@ kMatchAndMoveBranchTrue
@ kMoveParallelMoves
FunctionPtr GetFunction(const Library &lib, const char *name)
const char *const function_name
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switches.h:41
void run_test(skiatest::Reporter *reporter, Context *context, SkISize surfaceSize, SkISize recordingSize, SkISize replayOffset, DrawCallback draw, const std::vector< Expectation > &expectations)
#define ISOLATE_UNIT_TEST_CASE(name)
Definition unit_test.h:64