Flutter Engine
The Flutter Engine
utils.cc
Go to the documentation of this file.
1// Copyright (c) 2012, 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 "platform/utils.h"
6
8#include "platform/globals.h"
9
10#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS) || \
11 defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_FUCHSIA)
12#include <dlfcn.h>
13#endif
14
15namespace dart {
16
17uint64_t Utils::ReverseBits64(uint64_t x) {
18 x = ((x >> 32) & 0x00000000ffffffff) | (x << 32);
19 x = ((x >> 16) & 0x0000ffff0000ffff) | ((x & 0x0000ffff0000ffff) << 16);
20 x = ((x >> 8) & 0x00ff00ff00ff00ff) | ((x & 0x00ff00ff00ff00ff) << 8);
21 x = ((x >> 4) & 0x0f0f0f0f0f0f0f0f) | ((x & 0x0f0f0f0f0f0f0f0f) << 4);
22 x = ((x >> 2) & 0x3333333333333333) | ((x & 0x3333333333333333) << 2);
23 x = ((x >> 1) & 0x5555555555555555) | ((x & 0x5555555555555555) << 1);
24 return x;
25}
26
27uint32_t Utils::ReverseBits32(uint32_t x) {
28 x = ((x >> 16) & 0x0000ffff) | ((x & 0x0000ffff) << 16);
29 x = ((x >> 8) & 0x00ff00ff) | ((x & 0x00ff00ff) << 8);
30 x = ((x >> 4) & 0x0f0f0f0f) | ((x & 0x0f0f0f0f) << 4);
31 x = ((x >> 2) & 0x33333333) | ((x & 0x33333333) << 2);
32 x = ((x >> 1) & 0x55555555) | ((x & 0x55555555) << 1);
33 return x;
34}
35
36// Implementation according to H.S.Warren's "Hacker's Delight"
37// (Addison Wesley, 2002) Chapter 10 and T.Grablund, P.L.Montgomery's
38// "Division by Invariant Integers Using Multiplication" (PLDI 1994).
40 int64_t* magic,
41 int64_t* shift) {
42 ASSERT(divisor <= -2 || divisor >= 2);
43 /* The magic number M and shift S can be calculated in the following way:
44 * Let nc be the most positive value of numerator(n) such that nc = kd - 1,
45 * where divisor(d) >= 2.
46 * Let nc be the most negative value of numerator(n) such that nc = kd + 1,
47 * where divisor(d) <= -2.
48 * Thus nc can be calculated like:
49 * nc = exp + exp % d - 1, where d >= 2 and exp = 2^63.
50 * nc = -exp + (exp + 1) % d, where d >= 2 and exp = 2^63.
51 *
52 * So the shift p is the smallest p satisfying
53 * 2^p > nc * (d - 2^p % d), where d >= 2
54 * 2^p > nc * (d + 2^p % d), where d <= -2.
55 *
56 * The magic number M is calculated by
57 * M = (2^p + d - 2^p % d) / d, where d >= 2
58 * M = (2^p - d - 2^p % d) / d, where d <= -2.
59 */
60 int64_t p = 63;
61 const uint64_t exp = 1LL << 63;
62
63 // Initialize the computations.
64 uint64_t abs_d = (divisor >= 0) ? divisor : -static_cast<uint64_t>(divisor);
65 uint64_t sign_bit = static_cast<uint64_t>(divisor) >> 63;
66 uint64_t tmp = exp + sign_bit;
67 uint64_t abs_nc = tmp - 1 - (tmp % abs_d);
68 uint64_t quotient1 = exp / abs_nc;
69 uint64_t remainder1 = exp % abs_nc;
70 uint64_t quotient2 = exp / abs_d;
71 uint64_t remainder2 = exp % abs_d;
72
73 // To avoid handling both positive and negative divisor,
74 // "Hacker's Delight" introduces a method to handle these
75 // two cases together to avoid duplication.
76 uint64_t delta;
77 do {
78 p++;
79 quotient1 = 2 * quotient1;
80 remainder1 = 2 * remainder1;
81 if (remainder1 >= abs_nc) {
82 quotient1++;
83 remainder1 = remainder1 - abs_nc;
84 }
85 quotient2 = 2 * quotient2;
86 remainder2 = 2 * remainder2;
87 if (remainder2 >= abs_d) {
88 quotient2++;
89 remainder2 = remainder2 - abs_d;
90 }
91 delta = abs_d - remainder2;
92 } while (quotient1 < delta || (quotient1 == delta && remainder1 == 0));
93
94 *magic = (divisor > 0) ? (quotient2 + 1) : (-quotient2 - 1);
95 *shift = p - 64;
96}
97
98// This implementation is based on the public domain MurmurHash
99// version 2.0. The constants M and R have been determined
100// to work well experimentally.
101static constexpr uint32_t kStringHashM = 0x5bd1e995;
102static constexpr int kStringHashR = 24;
103
104// hash and part must be lvalues.
105#define MIX(hash, part) \
106 { \
107 (part) *= kStringHashM; \
108 (part) ^= (part) >> kStringHashR; \
109 (part) *= kStringHashM; \
110 (hash) *= kStringHashM; \
111 (hash) ^= (part); \
112 }
113
114uint32_t Utils::StringHash(const void* data, int length) {
115 int size = length;
116 uint32_t hash = size;
117
118 auto cursor = reinterpret_cast<const uint8_t*>(data);
119
120 if (size >= kInt32Size) {
121 const intptr_t misalignment =
122 reinterpret_cast<intptr_t>(cursor) % kInt32Size;
123 if (misalignment > 0) {
124 // Stores 4-byte values starting from the start of the string to mimic
125 // the algorithm on aligned data.
126 uint32_t data_window = 0;
127
128 // Shift sizes for adjusting the data window when adding the next aligned
129 // piece of data.
130 const uint32_t sr = misalignment * kBitsPerByte;
131 const uint32_t sl = kBitsPerInt32 - sr;
132
133 const intptr_t pre_alignment_length = kInt32Size - misalignment;
134 switch (pre_alignment_length) {
135 case 3:
136 data_window |= cursor[2] << 16;
138 case 2:
139 data_window |= cursor[1] << 8;
141 case 1:
142 data_window |= cursor[0];
143 }
144 cursor += pre_alignment_length;
145 size -= pre_alignment_length;
146
147 // Mix four bytes at a time now that we're at an aligned spot.
148 for (; size >= kInt32Size; cursor += kInt32Size, size -= kInt32Size) {
149 uint32_t aligned_part = *reinterpret_cast<const uint32_t*>(cursor);
150 data_window |= (aligned_part << sl);
151 MIX(hash, data_window);
152 data_window = aligned_part >> sr;
153 }
154
155 if (size >= misalignment) {
156 // There's one more full window in the data. We'll let the normal tail
157 // code handle any partial window.
158 switch (misalignment) {
159 case 3:
160 data_window |= cursor[2] << (16 + sl);
162 case 2:
163 data_window |= cursor[1] << (8 + sl);
165 case 1:
166 data_window |= cursor[0] << sl;
167 }
168 MIX(hash, data_window);
169 cursor += misalignment;
170 size -= misalignment;
171 } else {
172 // This is a partial window, so just xor and multiply by M.
173 switch (size) {
174 case 2:
175 data_window |= cursor[1] << (8 + sl);
177 case 1:
178 data_window |= cursor[0] << sl;
179 }
180 hash ^= data_window;
182 cursor += size;
183 size = 0;
184 }
185 } else {
186 // Mix four bytes at a time into the hash.
187 for (; size >= kInt32Size; size -= kInt32Size, cursor += kInt32Size) {
188 uint32_t part = *reinterpret_cast<const uint32_t*>(cursor);
189 MIX(hash, part);
190 }
191 }
192 }
193
194 // Handle the last few bytes of the string if any.
195 switch (size) {
196 case 3:
197 hash ^= cursor[2] << 16;
199 case 2:
200 hash ^= cursor[1] << 8;
202 case 1:
203 hash ^= cursor[0];
205 }
206
207 // Do a few final mixes of the hash to ensure the last few bytes are
208 // well-incorporated.
209 hash ^= hash >> 13;
211 hash ^= hash >> 15;
212 return hash;
213}
214
215#undef MIX
216
217uint32_t Utils::WordHash(intptr_t key) {
218 // TODO(iposva): Need to check hash spreading.
219 // This example is from http://www.concentric.net/~Ttwang/tech/inthash.htm
220 // via. http://web.archive.org/web/20071223173210/http://www.concentric.net/~Ttwang/tech/inthash.htm
221 uword a = static_cast<uword>(key);
222 a = (a + 0x7ed55d16) + (a << 12);
223 a = (a ^ 0xc761c23c) ^ (a >> 19);
224 a = (a + 0x165667b1) + (a << 5);
225 a = (a + 0xd3a2646c) ^ (a << 9);
226 a = (a + 0xfd7046c5) + (a << 3);
227 a = (a ^ 0xb55a4f09) ^ (a >> 16);
228 return static_cast<uint32_t>(a);
229}
230
231char* Utils::SCreate(const char* format, ...) {
232 va_list args;
234 char* buffer = VSCreate(format, args);
235 va_end(args);
236 return buffer;
237}
238
239char* Utils::VSCreate(const char* format, va_list args) {
240 // Measure.
241 va_list measure_args;
242 va_copy(measure_args, args);
243 intptr_t len = VSNPrint(nullptr, 0, format, measure_args);
244 va_end(measure_args);
245
246 char* buffer = reinterpret_cast<char*>(malloc(len + 1));
247 ASSERT(buffer != nullptr);
248
249 // Print.
250 va_list print_args;
251 va_copy(print_args, args);
252 VSNPrint(buffer, len + 1, format, print_args);
253 va_end(print_args);
254 return buffer;
255}
256
257static void GetLastErrorAsString(char** error) {
258 if (error == nullptr) return; // Nothing to do.
259
260#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS) || \
261 defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_FUCHSIA)
262 const char* status = dlerror();
263 *error = status != nullptr ? strdup(status) : nullptr;
264#elif defined(DART_HOST_OS_WINDOWS)
265 const int status = GetLastError();
266 if (status != 0) {
267 char* description = nullptr;
268 int length = FormatMessageA(
269 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
270 FORMAT_MESSAGE_IGNORE_INSERTS,
271 nullptr, status, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
272 reinterpret_cast<char*>(&description), 0, nullptr);
273 if (length == 0) {
274 // Seems like there is no message for this error code.
275 *error = Utils::SCreate("error code %i", status);
276 } else {
277 *error = Utils::SCreate("%s (error code: %i)", description, status);
278 }
279
280 LocalFree(description);
281 } else {
282 *error = nullptr;
283 }
284#else
285 *error = Utils::StrDup("loading dynamic libraries is not supported");
286#endif
287}
288
289void* Utils::LoadDynamicLibrary(const char* library_path, char** error) {
290 void* handle = nullptr;
291
292#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS) || \
293 defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_FUCHSIA)
294 handle = dlopen(library_path, RTLD_LAZY);
295#elif defined(DART_HOST_OS_WINDOWS)
296 SetLastError(0); // Clear any errors.
297
298 if (library_path == nullptr) {
299 handle = GetModuleHandle(nullptr);
300 } else {
301 // Convert to wchar_t string.
302 const int name_len = MultiByteToWideChar(
303 CP_UTF8, /*dwFlags=*/0, library_path, /*cbMultiByte=*/-1, nullptr, 0);
304 if (name_len != 0) {
305 std::unique_ptr<wchar_t[]> name(new wchar_t[name_len]);
306 const int written_len =
307 MultiByteToWideChar(CP_UTF8, /*dwFlags=*/0, library_path,
308 /*cbMultiByte=*/-1, name.get(), name_len);
309 RELEASE_ASSERT(written_len == name_len);
310 handle = LoadLibraryW(name.get());
311 }
312 }
313#endif
314
315 if (handle == nullptr) {
317 }
318
319 return handle;
320}
321
322void* Utils::ResolveSymbolInDynamicLibrary(void* library_handle,
323 const char* symbol,
324 char** error) {
325 void* result = nullptr;
326
327#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS) || \
328 defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_FUCHSIA)
329 dlerror(); // Clear any errors.
330 result = dlsym(library_handle, symbol);
331 // Note: nullptr might be a valid return from dlsym. Must call dlerror
332 // to differentiate.
334 return result;
335#elif defined(DART_HOST_OS_WINDOWS)
336 SetLastError(0);
337 result = reinterpret_cast<void*>(
338 GetProcAddress(reinterpret_cast<HMODULE>(library_handle), symbol));
339#endif
340
341 if (result == nullptr) {
343 }
344
345 return result;
346}
347
348void Utils::UnloadDynamicLibrary(void* library_handle, char** error) {
349 bool ok = false;
350
351#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS) || \
352 defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_FUCHSIA)
353 ok = dlclose(library_handle) == 0;
354#elif defined(DART_HOST_OS_WINDOWS)
355 SetLastError(0); // Clear any errors.
356
357 ok = FreeLibrary(reinterpret_cast<HMODULE>(library_handle));
358#endif
359
360 if (!ok) {
362 }
363}
364
365} // namespace dart
static bool ok(int result)
static uint32_t hash(const SkShaderBase::GradientInfo &v)
#define RELEASE_ASSERT(cond)
Definition: assert.h:327
static void CalculateMagicAndShiftForDivRem(int64_t divisor, int64_t *magic, int64_t *shift)
Definition: utils.cc:39
static void * LoadDynamicLibrary(const char *library_path, char **error=nullptr)
Definition: utils.cc:289
static char * StrDup(const char *s)
static char static char * VSCreate(const char *format, va_list args)
Definition: utils.cc:239
static int static int VSNPrint(char *str, size_t size, const char *format, va_list args)
static uint32_t WordHash(intptr_t key)
Definition: utils.cc:217
static uint32_t StringHash(const void *data, int length)
Definition: utils.cc:114
static void UnloadDynamicLibrary(void *library_handle, char **error=nullptr)
Definition: utils.cc:348
static char * SCreate(const char *format,...) PRINTF_ATTRIBUTE(1
Definition: utils.cc:231
static void * ResolveSymbolInDynamicLibrary(void *library_handle, const char *symbol, char **error=nullptr)
Definition: utils.cc:322
static uint32_t ReverseBits32(uint32_t x)
Definition: utils.cc:27
static uint64_t ReverseBits64(uint64_t x)
Definition: utils.cc:17
#define ASSERT(E)
struct MyStruct a[10]
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const uint8_t uint32_t uint32_t GError ** error
GAsyncResult * result
uint32_t uint32_t * format
size_t length
double x
va_start(args, format)
va_end(args)
Definition: dart_vm.cc:33
const char *const name
static void GetLastErrorAsString(char **error)
Definition: utils.cc:257
void * malloc(size_t size)
Definition: allocation.cc:19
constexpr intptr_t kBitsPerByte
Definition: globals.h:463
uintptr_t uword
Definition: globals.h:501
constexpr intptr_t kInt32Size
Definition: globals.h:450
static constexpr uint32_t kStringHashM
Definition: utils.cc:101
constexpr intptr_t kBitsPerInt32
Definition: globals.h:466
static int8_t data[kExtLength]
static constexpr int kStringHashR
Definition: utils.cc:102
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
char * strdup(const char *str1)
#define FALL_THROUGH
Definition: globals.h:15
#define MIX(hash, part)
Definition: utils.cc:105
WINBASEAPI VOID WINAPI SetLastError(_In_ DWORD dwErrCode)
WINBASEAPI _Check_return_ _Post_equals_last_error_ DWORD WINAPI GetLastError(VOID)
HINSTANCE HMODULE
Definition: windows_types.h:96