| OLD | NEW |
| (Empty) | |
| 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 "bin/snapshot_utils.h" |
| 6 |
| 7 #include "bin/dartutils.h" |
| 8 #include "bin/error_exit.h" |
| 9 #include "bin/extensions.h" |
| 10 #include "bin/file.h" |
| 11 #include "bin/platform.h" |
| 12 #include "include/dart_api.h" |
| 13 #include "platform/utils.h" |
| 14 |
| 15 namespace dart { |
| 16 namespace bin { |
| 17 |
| 18 extern const char* kVmSnapshotDataSymbolName; |
| 19 extern const char* kVmSnapshotInstructionsSymbolName; |
| 20 extern const char* kIsolateSnapshotDataSymbolName; |
| 21 extern const char* kIsolateSnapshotInstructionsSymbolName; |
| 22 |
| 23 static const int64_t kAppSnapshotHeaderSize = 5 * kInt64Size; |
| 24 static const int64_t kAppSnapshotMagicNumber = 0xf6f6dcdc; |
| 25 static const int64_t kAppSnapshotPageSize = 4 * KB; |
| 26 |
| 27 static bool ReadAppSnapshotBlobs(const char* script_name, |
| 28 const uint8_t** vm_data_buffer, |
| 29 const uint8_t** vm_instructions_buffer, |
| 30 const uint8_t** isolate_data_buffer, |
| 31 const uint8_t** isolate_instructions_buffer) { |
| 32 File* file = File::Open(script_name, File::kRead); |
| 33 if (file == NULL) { |
| 34 return false; |
| 35 } |
| 36 if (file->Length() < kAppSnapshotHeaderSize) { |
| 37 file->Release(); |
| 38 return false; |
| 39 } |
| 40 int64_t header[5]; |
| 41 ASSERT(sizeof(header) == kAppSnapshotHeaderSize); |
| 42 if (!file->ReadFully(&header, kAppSnapshotHeaderSize)) { |
| 43 file->Release(); |
| 44 return false; |
| 45 } |
| 46 if (header[0] != kAppSnapshotMagicNumber) { |
| 47 file->Release(); |
| 48 return false; |
| 49 } |
| 50 |
| 51 int64_t vm_data_size = header[1]; |
| 52 int64_t vm_data_position = |
| 53 Utils::RoundUp(file->Position(), kAppSnapshotPageSize); |
| 54 int64_t vm_instructions_size = header[2]; |
| 55 int64_t vm_instructions_position = vm_data_position + vm_data_size; |
| 56 if (vm_instructions_size != 0) { |
| 57 vm_instructions_position = |
| 58 Utils::RoundUp(vm_instructions_position, kAppSnapshotPageSize); |
| 59 } |
| 60 int64_t isolate_data_size = header[3]; |
| 61 int64_t isolate_data_position = Utils::RoundUp( |
| 62 vm_instructions_position + vm_instructions_size, kAppSnapshotPageSize); |
| 63 int64_t isolate_instructions_size = header[4]; |
| 64 int64_t isolate_instructions_position = |
| 65 isolate_data_position + isolate_data_size; |
| 66 if (isolate_instructions_size != 0) { |
| 67 isolate_instructions_position = |
| 68 Utils::RoundUp(isolate_instructions_position, kAppSnapshotPageSize); |
| 69 } |
| 70 |
| 71 if (vm_data_size != 0) { |
| 72 *vm_data_buffer = reinterpret_cast<const uint8_t*>( |
| 73 file->Map(File::kReadOnly, vm_data_position, vm_data_size)); |
| 74 if (vm_data_buffer == NULL) { |
| 75 Log::PrintErr("Failed to memory map snapshot\n"); |
| 76 Platform::Exit(kErrorExitCode); |
| 77 } |
| 78 } |
| 79 |
| 80 if (vm_instructions_size != 0) { |
| 81 *vm_instructions_buffer = reinterpret_cast<const uint8_t*>(file->Map( |
| 82 File::kReadExecute, vm_instructions_position, vm_instructions_size)); |
| 83 if (*vm_instructions_buffer == NULL) { |
| 84 Log::PrintErr("Failed to memory map snapshot\n"); |
| 85 Platform::Exit(kErrorExitCode); |
| 86 } |
| 87 } |
| 88 |
| 89 *isolate_data_buffer = reinterpret_cast<const uint8_t*>( |
| 90 file->Map(File::kReadOnly, isolate_data_position, isolate_data_size)); |
| 91 if (isolate_data_buffer == NULL) { |
| 92 Log::PrintErr("Failed to memory map snapshot\n"); |
| 93 Platform::Exit(kErrorExitCode); |
| 94 } |
| 95 |
| 96 if (isolate_instructions_size == 0) { |
| 97 *isolate_instructions_buffer = NULL; |
| 98 } else { |
| 99 *isolate_instructions_buffer = reinterpret_cast<const uint8_t*>( |
| 100 file->Map(File::kReadExecute, isolate_instructions_position, |
| 101 isolate_instructions_size)); |
| 102 if (*isolate_instructions_buffer == NULL) { |
| 103 Log::PrintErr("Failed to memory map snapshot\n"); |
| 104 Platform::Exit(kErrorExitCode); |
| 105 } |
| 106 } |
| 107 |
| 108 file->Release(); |
| 109 return true; |
| 110 } |
| 111 |
| 112 |
| 113 #if defined(DART_PRECOMPILED_RUNTIME) |
| 114 static bool ReadAppSnapshotDynamicLibrary( |
| 115 const char* script_name, |
| 116 const uint8_t** vm_data_buffer, |
| 117 const uint8_t** vm_instructions_buffer, |
| 118 const uint8_t** isolate_data_buffer, |
| 119 const uint8_t** isolate_instructions_buffer) { |
| 120 void* library = Extensions::LoadExtensionLibrary(script_name); |
| 121 if (library == NULL) { |
| 122 return false; |
| 123 } |
| 124 |
| 125 *vm_data_buffer = reinterpret_cast<const uint8_t*>( |
| 126 Extensions::ResolveSymbol(library, kVmSnapshotDataSymbolName)); |
| 127 if (*vm_data_buffer == NULL) { |
| 128 Log::PrintErr("Failed to resolve symbol '%s'\n", kVmSnapshotDataSymbolName); |
| 129 Platform::Exit(kErrorExitCode); |
| 130 } |
| 131 |
| 132 *vm_instructions_buffer = reinterpret_cast<const uint8_t*>( |
| 133 Extensions::ResolveSymbol(library, kVmSnapshotInstructionsSymbolName)); |
| 134 if (*vm_instructions_buffer == NULL) { |
| 135 Log::PrintErr("Failed to resolve symbol '%s'\n", |
| 136 kVmSnapshotInstructionsSymbolName); |
| 137 Platform::Exit(kErrorExitCode); |
| 138 } |
| 139 |
| 140 *isolate_data_buffer = reinterpret_cast<const uint8_t*>( |
| 141 Extensions::ResolveSymbol(library, kIsolateSnapshotDataSymbolName)); |
| 142 if (*isolate_data_buffer == NULL) { |
| 143 Log::PrintErr("Failed to resolve symbol '%s'\n", |
| 144 kIsolateSnapshotDataSymbolName); |
| 145 Platform::Exit(kErrorExitCode); |
| 146 } |
| 147 |
| 148 *isolate_instructions_buffer = |
| 149 reinterpret_cast<const uint8_t*>(Extensions::ResolveSymbol( |
| 150 library, kIsolateSnapshotInstructionsSymbolName)); |
| 151 if (*isolate_instructions_buffer == NULL) { |
| 152 Log::PrintErr("Failed to resolve symbol '%s'\n", |
| 153 kIsolateSnapshotInstructionsSymbolName); |
| 154 Platform::Exit(kErrorExitCode); |
| 155 } |
| 156 |
| 157 return true; |
| 158 } |
| 159 #endif // defined(DART_PRECOMPILED_RUNTIME) |
| 160 |
| 161 |
| 162 bool Snapshot::ReadAppSnapshot(const char* script_name, |
| 163 const uint8_t** vm_data_buffer, |
| 164 const uint8_t** vm_instructions_buffer, |
| 165 const uint8_t** isolate_data_buffer, |
| 166 const uint8_t** isolate_instructions_buffer) { |
| 167 if (File::GetType(script_name, true) != File::kIsFile) { |
| 168 // If 'script_name' refers to a pipe, don't read to check for an app |
| 169 // snapshot since we cannot rewind if it isn't (and couldn't mmap it in |
| 170 // anyway if it was). |
| 171 return false; |
| 172 } |
| 173 if (ReadAppSnapshotBlobs(script_name, vm_data_buffer, vm_instructions_buffer, |
| 174 isolate_data_buffer, isolate_instructions_buffer)) { |
| 175 return true; |
| 176 } |
| 177 #if defined(DART_PRECOMPILED_RUNTIME) |
| 178 // For testing AOT with the standalone embedder, we also support loading |
| 179 // from a dynamic library to simulate what happens on iOS. |
| 180 return ReadAppSnapshotDynamicLibrary( |
| 181 script_name, vm_data_buffer, vm_instructions_buffer, isolate_data_buffer, |
| 182 isolate_instructions_buffer); |
| 183 #else |
| 184 return false; |
| 185 #endif // defined(DART_PRECOMPILED_RUNTIME) |
| 186 } |
| 187 |
| 188 |
| 189 static void WriteSnapshotFile(const char* filename, |
| 190 bool write_magic_number, |
| 191 const uint8_t* buffer, |
| 192 const intptr_t size) { |
| 193 File* file = File::Open(filename, File::kWriteTruncate); |
| 194 if (file == NULL) { |
| 195 ErrorExit(kErrorExitCode, "Unable to open file %s for writing snapshot\n", |
| 196 filename); |
| 197 } |
| 198 |
| 199 if (write_magic_number) { |
| 200 // Write the magic number to indicate file is a script snapshot. |
| 201 DartUtils::WriteMagicNumber(file); |
| 202 } |
| 203 |
| 204 if (!file->WriteFully(buffer, size)) { |
| 205 ErrorExit(kErrorExitCode, "Unable to write file %s for writing snapshot\n", |
| 206 filename); |
| 207 } |
| 208 file->Release(); |
| 209 } |
| 210 |
| 211 |
| 212 static bool WriteInt64(File* file, int64_t size) { |
| 213 return file->WriteFully(&size, sizeof(size)); |
| 214 } |
| 215 |
| 216 |
| 217 static void WriteAppSnapshot(const char* filename, |
| 218 uint8_t* vm_data_buffer, |
| 219 intptr_t vm_data_size, |
| 220 uint8_t* vm_instructions_buffer, |
| 221 intptr_t vm_instructions_size, |
| 222 uint8_t* isolate_data_buffer, |
| 223 intptr_t isolate_data_size, |
| 224 uint8_t* isolate_instructions_buffer, |
| 225 intptr_t isolate_instructions_size) { |
| 226 File* file = File::Open(filename, File::kWriteTruncate); |
| 227 if (file == NULL) { |
| 228 ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n", filename); |
| 229 } |
| 230 |
| 231 file->WriteFully(&kAppSnapshotMagicNumber, sizeof(kAppSnapshotMagicNumber)); |
| 232 WriteInt64(file, vm_data_size); |
| 233 WriteInt64(file, vm_instructions_size); |
| 234 WriteInt64(file, isolate_data_size); |
| 235 WriteInt64(file, isolate_instructions_size); |
| 236 ASSERT(file->Position() == kAppSnapshotHeaderSize); |
| 237 |
| 238 file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize)); |
| 239 if (!file->WriteFully(vm_data_buffer, vm_data_size)) { |
| 240 ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n", filename); |
| 241 } |
| 242 |
| 243 if (vm_instructions_size != 0) { |
| 244 file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize)); |
| 245 if (!file->WriteFully(vm_instructions_buffer, vm_instructions_size)) { |
| 246 ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n", |
| 247 filename); |
| 248 } |
| 249 } |
| 250 |
| 251 file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize)); |
| 252 if (!file->WriteFully(isolate_data_buffer, isolate_data_size)) { |
| 253 ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n", filename); |
| 254 } |
| 255 |
| 256 if (isolate_instructions_size != 0) { |
| 257 file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize)); |
| 258 if (!file->WriteFully(isolate_instructions_buffer, |
| 259 isolate_instructions_size)) { |
| 260 ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n", |
| 261 filename); |
| 262 } |
| 263 } |
| 264 |
| 265 file->Flush(); |
| 266 file->Release(); |
| 267 } |
| 268 |
| 269 |
| 270 void Snapshot::GenerateScript(const char* snapshot_filename) { |
| 271 // First create a snapshot. |
| 272 uint8_t* buffer = NULL; |
| 273 intptr_t size = 0; |
| 274 Dart_Handle result = Dart_CreateScriptSnapshot(&buffer, &size); |
| 275 if (Dart_IsError(result)) { |
| 276 ErrorExit(kErrorExitCode, "%s\n", Dart_GetError(result)); |
| 277 } |
| 278 |
| 279 WriteSnapshotFile(snapshot_filename, true, buffer, size); |
| 280 } |
| 281 |
| 282 |
| 283 void Snapshot::GenerateAppJIT(const char* snapshot_filename) { |
| 284 #if defined(TARGET_ARCH_X64) |
| 285 uint8_t* isolate_data_buffer = NULL; |
| 286 intptr_t isolate_data_size = 0; |
| 287 uint8_t* isolate_instructions_buffer = NULL; |
| 288 intptr_t isolate_instructions_size = 0; |
| 289 Dart_Handle result = Dart_CreateAppJITSnapshotAsBlobs( |
| 290 &isolate_data_buffer, &isolate_data_size, &isolate_instructions_buffer, |
| 291 &isolate_instructions_size); |
| 292 if (Dart_IsError(result)) { |
| 293 ErrorExit(kErrorExitCode, "%s\n", Dart_GetError(result)); |
| 294 } |
| 295 WriteAppSnapshot(snapshot_filename, NULL, 0, NULL, 0, isolate_data_buffer, |
| 296 isolate_data_size, isolate_instructions_buffer, |
| 297 isolate_instructions_size); |
| 298 #else |
| 299 uint8_t* isolate_buffer = NULL; |
| 300 intptr_t isolate_size = 0; |
| 301 |
| 302 Dart_Handle result = |
| 303 Dart_CreateSnapshot(NULL, NULL, &isolate_buffer, &isolate_size); |
| 304 if (Dart_IsError(result)) { |
| 305 ErrorExit(kErrorExitCode, "%s\n", Dart_GetError(result)); |
| 306 } |
| 307 |
| 308 WriteAppSnapshot(snapshot_filename, NULL, 0, NULL, 0, isolate_buffer, |
| 309 isolate_size, NULL, 0); |
| 310 #endif // defined(TARGET_ARCH_X64) |
| 311 } |
| 312 |
| 313 |
| 314 void Snapshot::GenerateAppAOTAsBlobs(const char* snapshot_filename) { |
| 315 uint8_t* vm_data_buffer = NULL; |
| 316 intptr_t vm_data_size = 0; |
| 317 uint8_t* vm_instructions_buffer = NULL; |
| 318 intptr_t vm_instructions_size = 0; |
| 319 uint8_t* isolate_data_buffer = NULL; |
| 320 intptr_t isolate_data_size = 0; |
| 321 uint8_t* isolate_instructions_buffer = NULL; |
| 322 intptr_t isolate_instructions_size = 0; |
| 323 Dart_Handle result = Dart_CreateAppAOTSnapshotAsBlobs( |
| 324 &vm_data_buffer, &vm_data_size, &vm_instructions_buffer, |
| 325 &vm_instructions_size, &isolate_data_buffer, &isolate_data_size, |
| 326 &isolate_instructions_buffer, &isolate_instructions_size); |
| 327 if (Dart_IsError(result)) { |
| 328 ErrorExit(kErrorExitCode, "%s\n", Dart_GetError(result)); |
| 329 } |
| 330 WriteAppSnapshot(snapshot_filename, vm_data_buffer, vm_data_size, |
| 331 vm_instructions_buffer, vm_instructions_size, |
| 332 isolate_data_buffer, isolate_data_size, |
| 333 isolate_instructions_buffer, isolate_instructions_size); |
| 334 } |
| 335 |
| 336 |
| 337 void Snapshot::GenerateAppAOTAsAssembly(const char* snapshot_filename) { |
| 338 uint8_t* assembly_buffer = NULL; |
| 339 intptr_t assembly_size = 0; |
| 340 Dart_Handle result = |
| 341 Dart_CreateAppAOTSnapshotAsAssembly(&assembly_buffer, &assembly_size); |
| 342 if (Dart_IsError(result)) { |
| 343 ErrorExit(kErrorExitCode, "%s\n", Dart_GetError(result)); |
| 344 } |
| 345 WriteSnapshotFile(snapshot_filename, false, assembly_buffer, assembly_size); |
| 346 } |
| 347 |
| 348 } // namespace bin |
| 349 } // namespace dart |
| OLD | NEW |