1 | // Copyright (c) 2017, 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 <memory> |
6 | |
7 | #include "bin/snapshot_utils.h" |
8 | |
9 | #include "bin/dartutils.h" |
10 | #include "bin/dfe.h" |
11 | #include "bin/elf_loader.h" |
12 | #include "bin/error_exit.h" |
13 | #include "bin/extensions.h" |
14 | #include "bin/file.h" |
15 | #include "bin/platform.h" |
16 | #include "include/dart_api.h" |
17 | #include "platform/utils.h" |
18 | |
19 | #define LOG_SECTION_BOUNDARIES false |
20 | |
21 | namespace dart { |
22 | namespace bin { |
23 | |
24 | static const int64_t = 5 * kInt64Size; |
25 | static const int64_t kAppSnapshotPageSize = 16 * KB; |
26 | |
27 | class MappedAppSnapshot : public AppSnapshot { |
28 | public: |
29 | MappedAppSnapshot(MappedMemory* vm_snapshot_data, |
30 | MappedMemory* vm_snapshot_instructions, |
31 | MappedMemory* isolate_snapshot_data, |
32 | MappedMemory* isolate_snapshot_instructions) |
33 | : vm_data_mapping_(vm_snapshot_data), |
34 | vm_instructions_mapping_(vm_snapshot_instructions), |
35 | isolate_data_mapping_(isolate_snapshot_data), |
36 | isolate_instructions_mapping_(isolate_snapshot_instructions) {} |
37 | |
38 | ~MappedAppSnapshot() { |
39 | delete vm_data_mapping_; |
40 | delete vm_instructions_mapping_; |
41 | delete isolate_data_mapping_; |
42 | delete isolate_instructions_mapping_; |
43 | } |
44 | |
45 | void SetBuffers(const uint8_t** vm_data_buffer, |
46 | const uint8_t** vm_instructions_buffer, |
47 | const uint8_t** isolate_data_buffer, |
48 | const uint8_t** isolate_instructions_buffer) { |
49 | if (vm_data_mapping_ != NULL) { |
50 | *vm_data_buffer = |
51 | reinterpret_cast<const uint8_t*>(vm_data_mapping_->address()); |
52 | } |
53 | if (vm_instructions_mapping_ != NULL) { |
54 | *vm_instructions_buffer = |
55 | reinterpret_cast<const uint8_t*>(vm_instructions_mapping_->address()); |
56 | } |
57 | if (isolate_data_mapping_ != NULL) { |
58 | *isolate_data_buffer = |
59 | reinterpret_cast<const uint8_t*>(isolate_data_mapping_->address()); |
60 | } |
61 | if (isolate_instructions_mapping_ != NULL) { |
62 | *isolate_instructions_buffer = reinterpret_cast<const uint8_t*>( |
63 | isolate_instructions_mapping_->address()); |
64 | } |
65 | } |
66 | |
67 | private: |
68 | MappedMemory* vm_data_mapping_; |
69 | MappedMemory* vm_instructions_mapping_; |
70 | MappedMemory* isolate_data_mapping_; |
71 | MappedMemory* isolate_instructions_mapping_; |
72 | }; |
73 | |
74 | static AppSnapshot* TryReadAppSnapshotBlobs(const char* script_name, |
75 | File* file) { |
76 | if ((file->Length() - file->Position()) < kAppSnapshotHeaderSize) { |
77 | return nullptr; |
78 | } |
79 | |
80 | int64_t [5]; |
81 | ASSERT(sizeof(header) == kAppSnapshotHeaderSize); |
82 | if (!file->ReadFully(&header, kAppSnapshotHeaderSize)) { |
83 | return nullptr; |
84 | } |
85 | ASSERT(sizeof(header[0]) == appjit_magic_number.length); |
86 | if (memcmp(&header[0], appjit_magic_number.bytes, |
87 | appjit_magic_number.length) != 0) { |
88 | return nullptr; |
89 | } |
90 | |
91 | int64_t vm_data_size = header[1]; |
92 | int64_t vm_data_position = |
93 | Utils::RoundUp(file->Position(), kAppSnapshotPageSize); |
94 | int64_t vm_instructions_size = header[2]; |
95 | int64_t vm_instructions_position = vm_data_position + vm_data_size; |
96 | if (vm_instructions_size != 0) { |
97 | vm_instructions_position = |
98 | Utils::RoundUp(vm_instructions_position, kAppSnapshotPageSize); |
99 | } |
100 | int64_t isolate_data_size = header[3]; |
101 | int64_t isolate_data_position = Utils::RoundUp( |
102 | vm_instructions_position + vm_instructions_size, kAppSnapshotPageSize); |
103 | int64_t isolate_instructions_size = header[4]; |
104 | int64_t isolate_instructions_position = |
105 | isolate_data_position + isolate_data_size; |
106 | if (isolate_instructions_size != 0) { |
107 | isolate_instructions_position = |
108 | Utils::RoundUp(isolate_instructions_position, kAppSnapshotPageSize); |
109 | } |
110 | |
111 | MappedMemory* vm_data_mapping = nullptr; |
112 | if (vm_data_size != 0) { |
113 | vm_data_mapping = |
114 | file->Map(File::kReadOnly, vm_data_position, vm_data_size); |
115 | if (vm_data_mapping == nullptr) { |
116 | FATAL1("Failed to memory map snapshot: %s\n" , script_name); |
117 | } |
118 | } |
119 | |
120 | MappedMemory* vm_instr_mapping = nullptr; |
121 | if (vm_instructions_size != 0) { |
122 | vm_instr_mapping = file->Map(File::kReadExecute, vm_instructions_position, |
123 | vm_instructions_size); |
124 | if (vm_instr_mapping == nullptr) { |
125 | FATAL1("Failed to memory map snapshot: %s\n" , script_name); |
126 | } |
127 | } |
128 | |
129 | MappedMemory* isolate_data_mapping = nullptr; |
130 | if (isolate_data_size != 0) { |
131 | isolate_data_mapping = |
132 | file->Map(File::kReadOnly, isolate_data_position, isolate_data_size); |
133 | if (isolate_data_mapping == nullptr) { |
134 | FATAL1("Failed to memory map snapshot: %s\n" , script_name); |
135 | } |
136 | } |
137 | |
138 | MappedMemory* isolate_instr_mapping = nullptr; |
139 | if (isolate_instructions_size != 0) { |
140 | isolate_instr_mapping = |
141 | file->Map(File::kReadExecute, isolate_instructions_position, |
142 | isolate_instructions_size); |
143 | if (isolate_instr_mapping == nullptr) { |
144 | FATAL1("Failed to memory map snapshot: %s\n" , script_name); |
145 | } |
146 | } |
147 | |
148 | return new MappedAppSnapshot(vm_data_mapping, vm_instr_mapping, |
149 | isolate_data_mapping, isolate_instr_mapping); |
150 | } |
151 | |
152 | static AppSnapshot* TryReadAppSnapshotBlobs(const char* script_name) { |
153 | File* file = File::Open(NULL, script_name, File::kRead); |
154 | if (file == nullptr) { |
155 | return nullptr; |
156 | } |
157 | RefCntReleaseScope<File> rs(file); |
158 | return TryReadAppSnapshotBlobs(script_name, file); |
159 | } |
160 | |
161 | #if defined(DART_PRECOMPILED_RUNTIME) |
162 | class ElfAppSnapshot : public AppSnapshot { |
163 | public: |
164 | ElfAppSnapshot(Dart_LoadedElf* elf, |
165 | const uint8_t* vm_snapshot_data, |
166 | const uint8_t* vm_snapshot_instructions, |
167 | const uint8_t* isolate_snapshot_data, |
168 | const uint8_t* isolate_snapshot_instructions) |
169 | : elf_(elf), |
170 | vm_snapshot_data_(vm_snapshot_data), |
171 | vm_snapshot_instructions_(vm_snapshot_instructions), |
172 | isolate_snapshot_data_(isolate_snapshot_data), |
173 | isolate_snapshot_instructions_(isolate_snapshot_instructions) {} |
174 | |
175 | virtual ~ElfAppSnapshot() { Dart_UnloadELF(elf_); } |
176 | |
177 | void SetBuffers(const uint8_t** vm_data_buffer, |
178 | const uint8_t** vm_instructions_buffer, |
179 | const uint8_t** isolate_data_buffer, |
180 | const uint8_t** isolate_instructions_buffer) { |
181 | *vm_data_buffer = vm_snapshot_data_; |
182 | *vm_instructions_buffer = vm_snapshot_instructions_; |
183 | *isolate_data_buffer = isolate_snapshot_data_; |
184 | *isolate_instructions_buffer = isolate_snapshot_instructions_; |
185 | } |
186 | |
187 | private: |
188 | Dart_LoadedElf* elf_; |
189 | const uint8_t* vm_snapshot_data_; |
190 | const uint8_t* vm_snapshot_instructions_; |
191 | const uint8_t* isolate_snapshot_data_; |
192 | const uint8_t* isolate_snapshot_instructions_; |
193 | }; |
194 | |
195 | static AppSnapshot* TryReadAppSnapshotElf( |
196 | const char* script_name, |
197 | uint64_t file_offset, |
198 | bool force_load_elf_from_memory = false) { |
199 | const char* error = nullptr; |
200 | const uint8_t *vm_data_buffer = nullptr, *vm_instructions_buffer = nullptr, |
201 | *isolate_data_buffer = nullptr, |
202 | *isolate_instructions_buffer = nullptr; |
203 | Dart_LoadedElf* handle = nullptr; |
204 | #if !defined(HOST_OS_FUCHSIA) |
205 | if (force_load_elf_from_memory) { |
206 | #endif |
207 | File* const file = |
208 | File::Open(/*namespc=*/nullptr, script_name, File::kRead); |
209 | if (file == nullptr) return nullptr; |
210 | MappedMemory* memory = file->Map(File::kReadOnly, /*position=*/0, |
211 | /*length=*/file->Length()); |
212 | if (memory == nullptr) return nullptr; |
213 | const uint8_t* address = |
214 | reinterpret_cast<const uint8_t*>(memory->address()); |
215 | handle = |
216 | Dart_LoadELF_Memory(address + file_offset, file->Length(), &error, |
217 | &vm_data_buffer, &vm_instructions_buffer, |
218 | &isolate_data_buffer, &isolate_instructions_buffer); |
219 | delete memory; |
220 | file->Release(); |
221 | #if !defined(HOST_OS_FUCHSIA) |
222 | } else { |
223 | handle = Dart_LoadELF(script_name, file_offset, &error, &vm_data_buffer, |
224 | &vm_instructions_buffer, &isolate_data_buffer, |
225 | &isolate_instructions_buffer); |
226 | } |
227 | #endif |
228 | if (handle == nullptr) { |
229 | Syslog::PrintErr("Loading failed: %s\n" , error); |
230 | return nullptr; |
231 | } |
232 | return new ElfAppSnapshot(handle, vm_data_buffer, vm_instructions_buffer, |
233 | isolate_data_buffer, isolate_instructions_buffer); |
234 | return nullptr; |
235 | } |
236 | |
237 | AppSnapshot* Snapshot::TryReadAppendedAppSnapshotElf( |
238 | const char* container_path) { |
239 | File* file = File::Open(NULL, container_path, File::kRead); |
240 | if (file == nullptr) { |
241 | return nullptr; |
242 | } |
243 | RefCntReleaseScope<File> rs(file); |
244 | |
245 | // Check for payload appended at the end of the container file. |
246 | // If header is found, jump to payload offset. |
247 | int64_t appended_header[2]; |
248 | if (!file->SetPosition(file->Length() - sizeof(appended_header))) { |
249 | return nullptr; |
250 | } |
251 | if (!file->ReadFully(&appended_header, sizeof(appended_header))) { |
252 | return nullptr; |
253 | } |
254 | // Length is always encoded as Little Endian. |
255 | const uint64_t appended_offset = |
256 | Utils::LittleEndianToHost64(appended_header[0]); |
257 | if (memcmp(&appended_header[1], appjit_magic_number.bytes, |
258 | appjit_magic_number.length) != 0 || |
259 | appended_offset <= 0) { |
260 | return nullptr; |
261 | } |
262 | |
263 | return TryReadAppSnapshotElf(container_path, appended_offset); |
264 | } |
265 | |
266 | class DylibAppSnapshot : public AppSnapshot { |
267 | public: |
268 | DylibAppSnapshot(void* library, |
269 | const uint8_t* vm_snapshot_data, |
270 | const uint8_t* vm_snapshot_instructions, |
271 | const uint8_t* isolate_snapshot_data, |
272 | const uint8_t* isolate_snapshot_instructions) |
273 | : library_(library), |
274 | vm_snapshot_data_(vm_snapshot_data), |
275 | vm_snapshot_instructions_(vm_snapshot_instructions), |
276 | isolate_snapshot_data_(isolate_snapshot_data), |
277 | isolate_snapshot_instructions_(isolate_snapshot_instructions) {} |
278 | |
279 | ~DylibAppSnapshot() { Extensions::UnloadLibrary(library_); } |
280 | |
281 | void SetBuffers(const uint8_t** vm_data_buffer, |
282 | const uint8_t** vm_instructions_buffer, |
283 | const uint8_t** isolate_data_buffer, |
284 | const uint8_t** isolate_instructions_buffer) { |
285 | *vm_data_buffer = vm_snapshot_data_; |
286 | *vm_instructions_buffer = vm_snapshot_instructions_; |
287 | *isolate_data_buffer = isolate_snapshot_data_; |
288 | *isolate_instructions_buffer = isolate_snapshot_instructions_; |
289 | } |
290 | |
291 | private: |
292 | void* library_; |
293 | const uint8_t* vm_snapshot_data_; |
294 | const uint8_t* vm_snapshot_instructions_; |
295 | const uint8_t* isolate_snapshot_data_; |
296 | const uint8_t* isolate_snapshot_instructions_; |
297 | }; |
298 | |
299 | static AppSnapshot* TryReadAppSnapshotDynamicLibrary(const char* script_name) { |
300 | void* library = Extensions::LoadExtensionLibrary(script_name); |
301 | if (library == NULL) { |
302 | return NULL; |
303 | } |
304 | |
305 | const uint8_t* vm_data_buffer = reinterpret_cast<const uint8_t*>( |
306 | Extensions::ResolveSymbol(library, kVmSnapshotDataCSymbol)); |
307 | |
308 | const uint8_t* vm_instructions_buffer = reinterpret_cast<const uint8_t*>( |
309 | Extensions::ResolveSymbol(library, kVmSnapshotInstructionsCSymbol)); |
310 | |
311 | const uint8_t* isolate_data_buffer = reinterpret_cast<const uint8_t*>( |
312 | Extensions::ResolveSymbol(library, kIsolateSnapshotDataCSymbol)); |
313 | if (isolate_data_buffer == NULL) { |
314 | FATAL1("Failed to resolve symbol '%s'\n" , kIsolateSnapshotDataCSymbol); |
315 | } |
316 | |
317 | const uint8_t* isolate_instructions_buffer = reinterpret_cast<const uint8_t*>( |
318 | Extensions::ResolveSymbol(library, kIsolateSnapshotInstructionsCSymbol)); |
319 | if (isolate_instructions_buffer == NULL) { |
320 | FATAL1("Failed to resolve symbol '%s'\n" , |
321 | kIsolateSnapshotInstructionsCSymbol); |
322 | } |
323 | |
324 | return new DylibAppSnapshot(library, vm_data_buffer, vm_instructions_buffer, |
325 | isolate_data_buffer, isolate_instructions_buffer); |
326 | } |
327 | |
328 | #endif // defined(DART_PRECOMPILED_RUNTIME) |
329 | |
330 | AppSnapshot* Snapshot::TryReadAppSnapshot(const char* script_uri, |
331 | bool force_load_elf_from_memory) { |
332 | auto decoded_path = File::UriToPath(script_uri); |
333 | if (decoded_path == nullptr) { |
334 | return nullptr; |
335 | } |
336 | |
337 | const char* script_name = decoded_path.get(); |
338 | if (File::GetType(nullptr, script_name, true) != File::kIsFile) { |
339 | // If 'script_name' refers to a pipe, don't read to check for an app |
340 | // snapshot since we cannot rewind if it isn't (and couldn't mmap it in |
341 | // anyway if it was). |
342 | return nullptr; |
343 | } |
344 | AppSnapshot* snapshot = TryReadAppSnapshotBlobs(script_name); |
345 | if (snapshot != nullptr) { |
346 | return snapshot; |
347 | } |
348 | #if defined(DART_PRECOMPILED_RUNTIME) |
349 | // For testing AOT with the standalone embedder, we also support loading |
350 | // from a dynamic library to simulate what happens on iOS. |
351 | |
352 | #if defined(TARGET_OS_LINUX) || defined(TARGET_OS_MACOS) |
353 | // On Linux and OSX, resolve the script path before passing into dlopen() |
354 | // since dlopen will not search the filesystem for paths like 'libtest.so'. |
355 | std::unique_ptr<char, decltype(std::free)*> absolute_path{ |
356 | realpath(script_name, nullptr), std::free}; |
357 | script_name = absolute_path.get(); |
358 | #endif |
359 | |
360 | if (!force_load_elf_from_memory) { |
361 | snapshot = TryReadAppSnapshotDynamicLibrary(script_name); |
362 | if (snapshot != nullptr) { |
363 | return snapshot; |
364 | } |
365 | } |
366 | |
367 | snapshot = TryReadAppSnapshotElf(script_name, /*file_offset=*/0, |
368 | force_load_elf_from_memory); |
369 | if (snapshot != nullptr) { |
370 | return snapshot; |
371 | } |
372 | #endif // defined(DART_PRECOMPILED_RUNTIME) |
373 | return nullptr; |
374 | } |
375 | |
376 | #if !defined(EXCLUDE_CFE_AND_KERNEL_PLATFORM) && !defined(TESTING) |
377 | static void WriteSnapshotFile(const char* filename, |
378 | const uint8_t* buffer, |
379 | const intptr_t size) { |
380 | File* file = File::Open(NULL, filename, File::kWriteTruncate); |
381 | if (file == NULL) { |
382 | ErrorExit(kErrorExitCode, "Unable to open file %s for writing snapshot\n" , |
383 | filename); |
384 | } |
385 | |
386 | if (!file->WriteFully(buffer, size)) { |
387 | ErrorExit(kErrorExitCode, "Unable to write file %s for writing snapshot\n" , |
388 | filename); |
389 | } |
390 | file->Release(); |
391 | } |
392 | #endif |
393 | |
394 | static bool WriteInt64(File* file, int64_t size) { |
395 | return file->WriteFully(&size, sizeof(size)); |
396 | } |
397 | |
398 | void Snapshot::WriteAppSnapshot(const char* filename, |
399 | uint8_t* vm_data_buffer, |
400 | intptr_t vm_data_size, |
401 | uint8_t* vm_instructions_buffer, |
402 | intptr_t vm_instructions_size, |
403 | uint8_t* isolate_data_buffer, |
404 | intptr_t isolate_data_size, |
405 | uint8_t* isolate_instructions_buffer, |
406 | intptr_t isolate_instructions_size) { |
407 | File* file = File::Open(NULL, filename, File::kWriteTruncate); |
408 | if (file == NULL) { |
409 | ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n" , filename); |
410 | } |
411 | |
412 | file->WriteFully(appjit_magic_number.bytes, appjit_magic_number.length); |
413 | WriteInt64(file, vm_data_size); |
414 | WriteInt64(file, vm_instructions_size); |
415 | WriteInt64(file, isolate_data_size); |
416 | WriteInt64(file, isolate_instructions_size); |
417 | ASSERT(file->Position() == kAppSnapshotHeaderSize); |
418 | |
419 | file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize)); |
420 | if (LOG_SECTION_BOUNDARIES) { |
421 | Syslog::PrintErr("%" Px64 ": VM Data\n" , file->Position()); |
422 | } |
423 | if (!file->WriteFully(vm_data_buffer, vm_data_size)) { |
424 | ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n" , filename); |
425 | } |
426 | |
427 | if (vm_instructions_size != 0) { |
428 | file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize)); |
429 | if (LOG_SECTION_BOUNDARIES) { |
430 | Syslog::PrintErr("%" Px64 ": VM Instructions\n" , file->Position()); |
431 | } |
432 | if (!file->WriteFully(vm_instructions_buffer, vm_instructions_size)) { |
433 | ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n" , |
434 | filename); |
435 | } |
436 | } |
437 | |
438 | file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize)); |
439 | if (LOG_SECTION_BOUNDARIES) { |
440 | Syslog::PrintErr("%" Px64 ": Isolate Data\n" , file->Position()); |
441 | } |
442 | if (!file->WriteFully(isolate_data_buffer, isolate_data_size)) { |
443 | ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n" , filename); |
444 | } |
445 | |
446 | if (isolate_instructions_size != 0) { |
447 | file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize)); |
448 | if (LOG_SECTION_BOUNDARIES) { |
449 | Syslog::PrintErr("%" Px64 ": Isolate Instructions\n" , file->Position()); |
450 | } |
451 | if (!file->WriteFully(isolate_instructions_buffer, |
452 | isolate_instructions_size)) { |
453 | ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n" , |
454 | filename); |
455 | } |
456 | } |
457 | |
458 | file->Flush(); |
459 | file->Release(); |
460 | } |
461 | |
462 | void Snapshot::GenerateKernel(const char* snapshot_filename, |
463 | const char* script_name, |
464 | const char* package_config) { |
465 | #if !defined(EXCLUDE_CFE_AND_KERNEL_PLATFORM) && !defined(TESTING) |
466 | uint8_t* kernel_buffer = NULL; |
467 | intptr_t kernel_buffer_size = 0; |
468 | dfe.ReadScript(script_name, &kernel_buffer, &kernel_buffer_size); |
469 | if (kernel_buffer != NULL) { |
470 | WriteSnapshotFile(snapshot_filename, kernel_buffer, kernel_buffer_size); |
471 | free(kernel_buffer); |
472 | } else { |
473 | Dart_KernelCompilationResult result = |
474 | dfe.CompileScript(script_name, false, package_config); |
475 | if (result.status != Dart_KernelCompilationStatus_Ok) { |
476 | ErrorExit(kErrorExitCode, "%s\n" , result.error); |
477 | } |
478 | WriteSnapshotFile(snapshot_filename, result.kernel, result.kernel_size); |
479 | free(result.kernel); |
480 | } |
481 | #else |
482 | UNREACHABLE(); |
483 | #endif // !defined(EXCLUDE_CFE_AND_KERNEL_PLATFORM) && !defined(TESTING) |
484 | } |
485 | |
486 | void Snapshot::GenerateAppJIT(const char* snapshot_filename) { |
487 | #if defined(TARGET_ARCH_IA32) |
488 | // Snapshots with code are not supported on IA32. |
489 | uint8_t* isolate_buffer = NULL; |
490 | intptr_t isolate_size = 0; |
491 | |
492 | Dart_Handle result = |
493 | Dart_CreateSnapshot(NULL, NULL, &isolate_buffer, &isolate_size); |
494 | if (Dart_IsError(result)) { |
495 | ErrorExit(kErrorExitCode, "%s\n" , Dart_GetError(result)); |
496 | } |
497 | |
498 | WriteAppSnapshot(snapshot_filename, NULL, 0, NULL, 0, isolate_buffer, |
499 | isolate_size, NULL, 0); |
500 | #else |
501 | uint8_t* isolate_data_buffer = NULL; |
502 | intptr_t isolate_data_size = 0; |
503 | uint8_t* isolate_instructions_buffer = NULL; |
504 | intptr_t isolate_instructions_size = 0; |
505 | Dart_Handle result = Dart_CreateAppJITSnapshotAsBlobs( |
506 | &isolate_data_buffer, &isolate_data_size, &isolate_instructions_buffer, |
507 | &isolate_instructions_size); |
508 | if (Dart_IsError(result)) { |
509 | ErrorExit(kErrorExitCode, "%s\n" , Dart_GetError(result)); |
510 | } |
511 | WriteAppSnapshot(snapshot_filename, NULL, 0, NULL, 0, isolate_data_buffer, |
512 | isolate_data_size, isolate_instructions_buffer, |
513 | isolate_instructions_size); |
514 | #endif |
515 | } |
516 | |
517 | static void StreamingWriteCallback(void* callback_data, |
518 | const uint8_t* buffer, |
519 | intptr_t size) { |
520 | File* file = reinterpret_cast<File*>(callback_data); |
521 | if (!file->WriteFully(buffer, size)) { |
522 | ErrorExit(kErrorExitCode, "Unable to write snapshot file\n" ); |
523 | } |
524 | } |
525 | |
526 | void Snapshot::GenerateAppAOTAsAssembly(const char* snapshot_filename) { |
527 | File* file = File::Open(NULL, snapshot_filename, File::kWriteTruncate); |
528 | RefCntReleaseScope<File> rs(file); |
529 | if (file == NULL) { |
530 | ErrorExit(kErrorExitCode, "Unable to open file %s for writing snapshot\n" , |
531 | snapshot_filename); |
532 | } |
533 | Dart_Handle result = Dart_CreateAppAOTSnapshotAsAssembly( |
534 | StreamingWriteCallback, file, /*strip=*/false, |
535 | /*debug_callback_data=*/nullptr); |
536 | if (Dart_IsError(result)) { |
537 | ErrorExit(kErrorExitCode, "%s\n" , Dart_GetError(result)); |
538 | } |
539 | } |
540 | |
541 | bool Snapshot::IsAOTSnapshot(const char* snapshot_filename) { |
542 | // Header is simply "ELF" prefixed with the DEL character. |
543 | const char [] = {0x7F, 0x45, 0x4C, 0x46, 0x0}; |
544 | const int64_t = strlen(elf_header); |
545 | File* file = File::Open(NULL, snapshot_filename, File::kRead); |
546 | if (file == nullptr) { |
547 | return false; |
548 | } |
549 | if (file->Length() < elf_header_len) { |
550 | file->Release(); |
551 | return false; |
552 | } |
553 | auto buf = std::unique_ptr<char[]>(new char[elf_header_len]); |
554 | bool success = file->ReadFully(buf.get(), elf_header_len); |
555 | file->Release(); |
556 | ASSERT(success); |
557 | return (strncmp(elf_header, buf.get(), elf_header_len) == 0); |
558 | } |
559 | |
560 | } // namespace bin |
561 | } // namespace dart |
562 | |