Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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;
233 va_start(args, format);
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
258 return std::unique_ptr<char, decltype(std::free)*>{str, std::free};
259}
260
261static void GetLastErrorAsString(char** error) {
262 if (error == nullptr) return; // Nothing to do.
263
264#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS) || \
265 defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_FUCHSIA)
266 const char* status = dlerror();
267 *error = status != nullptr ? strdup(status) : nullptr;
268#elif defined(DART_HOST_OS_WINDOWS)
269 const int status = GetLastError();
270 if (status != 0) {
271 char* description = nullptr;
272 int length = FormatMessageA(
273 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
274 FORMAT_MESSAGE_IGNORE_INSERTS,
275 nullptr, status, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
276 reinterpret_cast<char*>(&description), 0, nullptr);
277 if (length == 0) {
278 // Seems like there is no message for this error code.
279 *error = Utils::SCreate("error code %i", status);
280 } else {
281 *error = Utils::SCreate("%s (error code: %i)", description, status);
282 }
283
284 LocalFree(description);
285 } else {
286 *error = nullptr;
287 }
288#else
289 *error = Utils::StrDup("loading dynamic libraries is not supported");
290#endif
291}
292
293void* Utils::LoadDynamicLibrary(const char* library_path, char** error) {
294 void* handle = nullptr;
295
296#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS) || \
297 defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_FUCHSIA)
298 handle = dlopen(library_path, RTLD_LAZY);
299#elif defined(DART_HOST_OS_WINDOWS)
300 SetLastError(0); // Clear any errors.
301
302 if (library_path == nullptr) {
303 handle = GetModuleHandle(nullptr);
304 } else {
305 // Convert to wchar_t string.
306 const int name_len = MultiByteToWideChar(
307 CP_UTF8, /*dwFlags=*/0, library_path, /*cbMultiByte=*/-1, nullptr, 0);
308 if (name_len != 0) {
309 std::unique_ptr<wchar_t[]> name(new wchar_t[name_len]);
310 const int written_len =
311 MultiByteToWideChar(CP_UTF8, /*dwFlags=*/0, library_path,
312 /*cbMultiByte=*/-1, name.get(), name_len);
313 RELEASE_ASSERT(written_len == name_len);
314 handle = LoadLibraryW(name.get());
315 }
316 }
317#endif
318
319 if (handle == nullptr) {
321 }
322
323 return handle;
324}
325
326void* Utils::ResolveSymbolInDynamicLibrary(void* library_handle,
327 const char* symbol,
328 char** error) {
329 void* result = nullptr;
330
331#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS) || \
332 defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_FUCHSIA)
333 dlerror(); // Clear any errors.
334 result = dlsym(library_handle, symbol);
335 // Note: nullptr might be a valid return from dlsym. Must call dlerror
336 // to differentiate.
338 return result;
339#elif defined(DART_HOST_OS_WINDOWS)
340 SetLastError(0);
341 result = reinterpret_cast<void*>(
342 GetProcAddress(reinterpret_cast<HMODULE>(library_handle), symbol));
343#endif
344
345 if (result == nullptr) {
347 }
348
349 return result;
350}
351
352void Utils::UnloadDynamicLibrary(void* library_handle, char** error) {
353 bool ok = false;
354
355#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS) || \
356 defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_FUCHSIA)
357 ok = dlclose(library_handle) == 0;
358#elif defined(DART_HOST_OS_WINDOWS)
359 SetLastError(0); // Clear any errors.
360
361 ok = FreeLibrary(reinterpret_cast<HMODULE>(library_handle));
362#endif
363
364 if (!ok) {
366 }
367}
368
369} // 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:293
static char * StrDup(const char *s)
static CStringUniquePtr CreateCStringUniquePtr(char *str)
Definition utils.cc:257
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
std::unique_ptr< char, decltype(std::free) * > CStringUniquePtr
Definition utils.h:644
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:352
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:326
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
static const uint8_t buffer[]
const uint8_t uint32_t uint32_t GError ** error
GAsyncResult * result
uint32_t uint32_t * format
size_t length
double x
const char *const name
static void GetLastErrorAsString(char **error)
Definition utils.cc:261
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
#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