OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "gin/v8_initializer.h" | 5 #include "gin/v8_initializer.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include "base/debug/alias.h" | 10 #include "base/debug/alias.h" |
11 #include "base/files/file.h" | 11 #include "base/files/file.h" |
12 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
13 #include "base/files/memory_mapped_file.h" | 13 #include "base/files/memory_mapped_file.h" |
| 14 #include "base/lazy_instance.h" |
14 #include "base/logging.h" | 15 #include "base/logging.h" |
15 #include "base/memory/scoped_ptr.h" | 16 #include "base/memory/scoped_ptr.h" |
16 #include "base/metrics/histogram.h" | 17 #include "base/metrics/histogram.h" |
17 #include "base/rand_util.h" | 18 #include "base/rand_util.h" |
18 #include "base/strings/sys_string_conversions.h" | 19 #include "base/strings/sys_string_conversions.h" |
19 #include "base/threading/platform_thread.h" | 20 #include "base/threading/platform_thread.h" |
20 #include "base/time/time.h" | 21 #include "base/time/time.h" |
21 #include "crypto/sha2.h" | 22 #include "crypto/sha2.h" |
22 | 23 |
23 #if defined(V8_USE_EXTERNAL_STARTUP_DATA) | 24 #if defined(V8_USE_EXTERNAL_STARTUP_DATA) |
(...skipping 19 matching lines...) Expand all Loading... |
43 const base::PlatformFile kInvalidPlatformFile = | 44 const base::PlatformFile kInvalidPlatformFile = |
44 #if defined(OS_WIN) | 45 #if defined(OS_WIN) |
45 INVALID_HANDLE_VALUE; | 46 INVALID_HANDLE_VALUE; |
46 #else | 47 #else |
47 -1; | 48 -1; |
48 #endif | 49 #endif |
49 | 50 |
50 // File handles intentionally never closed. Not using File here because its | 51 // File handles intentionally never closed. Not using File here because its |
51 // Windows implementation guards against two instances owning the same | 52 // Windows implementation guards against two instances owning the same |
52 // PlatformFile (which we allow since we know it is never freed). | 53 // PlatformFile (which we allow since we know it is never freed). |
53 base::PlatformFile g_natives_pf = kInvalidPlatformFile; | 54 typedef std::map<const char*, |
54 base::PlatformFile g_snapshot_pf = kInvalidPlatformFile; | 55 std::pair<base::PlatformFile, base::MemoryMappedFile::Region>> |
55 base::MemoryMappedFile::Region g_natives_region; | 56 OpenedFileMap; |
56 base::MemoryMappedFile::Region g_snapshot_region; | 57 static base::LazyInstance<OpenedFileMap>::Leaky g_opened_files = |
| 58 LAZY_INSTANCE_INITIALIZER; |
| 59 |
| 60 OpenedFileMap::mapped_type& GetOpenedFile(const char* file) { |
| 61 OpenedFileMap& opened_files(g_opened_files.Get()); |
| 62 if (opened_files.find(file) == opened_files.end()) { |
| 63 opened_files[file] = |
| 64 std::make_pair(kInvalidPlatformFile, base::MemoryMappedFile::Region()); |
| 65 } |
| 66 return opened_files[file]; |
| 67 } |
57 | 68 |
58 #if defined(OS_ANDROID) | 69 #if defined(OS_ANDROID) |
59 #ifdef __LP64__ | 70 const char kNativesFileName64[] = "natives_blob_64.bin"; |
60 const char kNativesFileName[] = "natives_blob_64.bin"; | 71 const char kSnapshotFileName64[] = "snapshot_blob_64.bin"; |
61 const char kSnapshotFileName[] = "snapshot_blob_64.bin"; | 72 const char kNativesFileName32[] = "natives_blob_32.bin"; |
| 73 const char kSnapshotFileName32[] = "snapshot_blob_32.bin"; |
| 74 |
| 75 #if defined(__LP64__) |
| 76 #define kNativesFileName kNativesFileName64 |
| 77 #define kSnapshotFileName kSnapshotFileName64 |
62 #else | 78 #else |
63 const char kNativesFileName[] = "natives_blob_32.bin"; | 79 #define kNativesFileName kNativesFileName32 |
64 const char kSnapshotFileName[] = "snapshot_blob_32.bin"; | 80 #define kSnapshotFileName kSnapshotFileName32 |
65 #endif // __LP64__ | 81 #endif |
66 | 82 |
67 #else // defined(OS_ANDROID) | 83 #else // defined(OS_ANDROID) |
68 const char kNativesFileName[] = "natives_blob.bin"; | 84 const char kNativesFileName[] = "natives_blob.bin"; |
69 const char kSnapshotFileName[] = "snapshot_blob.bin"; | 85 const char kSnapshotFileName[] = "snapshot_blob.bin"; |
70 #endif // defined(OS_ANDROID) | 86 #endif // defined(OS_ANDROID) |
71 | 87 |
72 void GetV8FilePath(const char* file_name, base::FilePath* path_out) { | 88 void GetV8FilePath(const char* file_name, base::FilePath* path_out) { |
73 #if !defined(OS_MACOSX) | 89 #if !defined(OS_MACOSX) |
74 base::FilePath data_path; | 90 base::FilePath data_path; |
75 #if defined(OS_ANDROID) | 91 #if defined(OS_ANDROID) |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 } | 179 } |
164 } | 180 } |
165 #endif // defined(OS_ANDROID) | 181 #endif // defined(OS_ANDROID) |
166 | 182 |
167 UMA_HISTOGRAM_ENUMERATION("V8.Initializer.OpenV8File.Result", | 183 UMA_HISTOGRAM_ENUMERATION("V8.Initializer.OpenV8File.Result", |
168 result, | 184 result, |
169 OpenV8FileResult::MAX_VALUE); | 185 OpenV8FileResult::MAX_VALUE); |
170 return file.TakePlatformFile(); | 186 return file.TakePlatformFile(); |
171 } | 187 } |
172 | 188 |
173 void OpenNativesFileIfNecessary() { | 189 static const OpenedFileMap::mapped_type OpenFileIfNecessary( |
174 if (g_natives_pf == kInvalidPlatformFile) { | 190 const char* file_name) { |
175 g_natives_pf = OpenV8File(kNativesFileName, &g_natives_region); | 191 OpenedFileMap::mapped_type& opened = GetOpenedFile(file_name); |
| 192 if (opened.first == kInvalidPlatformFile) { |
| 193 opened.first = OpenV8File(file_name, &opened.second); |
176 } | 194 } |
177 } | 195 return opened; |
178 | |
179 void OpenSnapshotFileIfNecessary() { | |
180 if (g_snapshot_pf == kInvalidPlatformFile) { | |
181 g_snapshot_pf = OpenV8File(kSnapshotFileName, &g_snapshot_region); | |
182 } | |
183 } | 196 } |
184 | 197 |
185 #if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) | 198 #if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) |
186 bool VerifyV8StartupFile(base::MemoryMappedFile** file, | 199 bool VerifyV8StartupFile(base::MemoryMappedFile** file, |
187 const unsigned char* fingerprint) { | 200 const unsigned char* fingerprint) { |
188 unsigned char output[crypto::kSHA256Length]; | 201 unsigned char output[crypto::kSHA256Length]; |
189 crypto::SHA256HashString( | 202 crypto::SHA256HashString( |
190 base::StringPiece(reinterpret_cast<const char*>((*file)->data()), | 203 base::StringPiece(reinterpret_cast<const char*>((*file)->data()), |
191 (*file)->length()), | 204 (*file)->length()), |
192 output, sizeof(output)); | 205 output, sizeof(output)); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
229 #endif // V8_VERIFY_EXTERNAL_STARTUP_DATA | 242 #endif // V8_VERIFY_EXTERNAL_STARTUP_DATA |
230 | 243 |
231 enum LoadV8FileResult { | 244 enum LoadV8FileResult { |
232 V8_LOAD_SUCCESS = 0, | 245 V8_LOAD_SUCCESS = 0, |
233 V8_LOAD_FAILED_OPEN, | 246 V8_LOAD_FAILED_OPEN, |
234 V8_LOAD_FAILED_MAP, | 247 V8_LOAD_FAILED_MAP, |
235 V8_LOAD_FAILED_VERIFY, | 248 V8_LOAD_FAILED_VERIFY, |
236 V8_LOAD_MAX_VALUE | 249 V8_LOAD_MAX_VALUE |
237 }; | 250 }; |
238 | 251 |
239 static LoadV8FileResult MapVerify(base::PlatformFile platform_file, | 252 static LoadV8FileResult MapVerify(const OpenedFileMap::mapped_type& file_region, |
240 const base::MemoryMappedFile::Region& region, | |
241 #if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) | 253 #if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) |
242 const unsigned char* fingerprint, | 254 const unsigned char* fingerprint, |
243 #endif | 255 #endif |
244 base::MemoryMappedFile** mmapped_file_out) { | 256 base::MemoryMappedFile** mmapped_file_out) { |
245 if (platform_file == kInvalidPlatformFile) | 257 if (file_region.first == kInvalidPlatformFile) |
246 return V8_LOAD_FAILED_OPEN; | 258 return V8_LOAD_FAILED_OPEN; |
247 if (!MapV8File(platform_file, region, mmapped_file_out)) | 259 if (!MapV8File(file_region.first, file_region.second, mmapped_file_out)) |
248 return V8_LOAD_FAILED_MAP; | 260 return V8_LOAD_FAILED_MAP; |
249 #if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) | 261 #if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) |
250 if (!VerifyV8StartupFile(mmapped_file_out, fingerprint)) | 262 if (!VerifyV8StartupFile(mmapped_file_out, fingerprint)) |
251 return V8_LOAD_FAILED_VERIFY; | 263 return V8_LOAD_FAILED_VERIFY; |
252 #endif // V8_VERIFY_EXTERNAL_STARTUP_DATA | 264 #endif // V8_VERIFY_EXTERNAL_STARTUP_DATA |
253 return V8_LOAD_SUCCESS; | 265 return V8_LOAD_SUCCESS; |
254 } | 266 } |
255 | 267 |
256 // static | 268 // static |
257 void V8Initializer::LoadV8Snapshot() { | 269 void V8Initializer::LoadV8Snapshot() { |
258 if (g_mapped_snapshot) | 270 if (g_mapped_snapshot) |
259 return; | 271 return; |
260 | 272 |
261 OpenSnapshotFileIfNecessary(); | 273 OpenFileIfNecessary(kSnapshotFileName); |
262 LoadV8FileResult result = MapVerify(g_snapshot_pf, g_snapshot_region, | 274 LoadV8FileResult result = MapVerify(GetOpenedFile(kSnapshotFileName), |
263 #if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) | 275 #if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) |
264 g_snapshot_fingerprint, | 276 g_snapshot_fingerprint, |
265 #endif | 277 #endif |
266 &g_mapped_snapshot); | 278 &g_mapped_snapshot); |
267 // V8 can't start up without the source of the natives, but it can | 279 // V8 can't start up without the source of the natives, but it can |
268 // start up (slower) without the snapshot. | 280 // start up (slower) without the snapshot. |
269 UMA_HISTOGRAM_ENUMERATION("V8.Initializer.LoadV8Snapshot.Result", result, | 281 UMA_HISTOGRAM_ENUMERATION("V8.Initializer.LoadV8Snapshot.Result", result, |
270 V8_LOAD_MAX_VALUE); | 282 V8_LOAD_MAX_VALUE); |
271 } | 283 } |
272 | 284 |
273 void V8Initializer::LoadV8Natives() { | 285 void V8Initializer::LoadV8Natives() { |
274 if (g_mapped_natives) | 286 if (g_mapped_natives) |
275 return; | 287 return; |
276 | 288 |
277 OpenNativesFileIfNecessary(); | 289 OpenFileIfNecessary(kNativesFileName); |
278 LoadV8FileResult result = MapVerify(g_natives_pf, g_natives_region, | 290 LoadV8FileResult result = MapVerify(GetOpenedFile(kNativesFileName), |
279 #if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) | 291 #if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) |
280 g_natives_fingerprint, | 292 g_natives_fingerprint, |
281 #endif | 293 #endif |
282 &g_mapped_natives); | 294 &g_mapped_natives); |
283 if (result != V8_LOAD_SUCCESS) { | 295 if (result != V8_LOAD_SUCCESS) { |
284 LOG(FATAL) << "Couldn't mmap v8 natives data file, status code is " | 296 LOG(FATAL) << "Couldn't mmap v8 natives data file, status code is " |
285 << static_cast<int>(result); | 297 << static_cast<int>(result); |
286 } | 298 } |
287 } | 299 } |
288 | 300 |
(...skipping 15 matching lines...) Expand all Loading... |
304 } | 316 } |
305 | 317 |
306 LoadV8FileResult result = V8_LOAD_SUCCESS; | 318 LoadV8FileResult result = V8_LOAD_SUCCESS; |
307 if (!MapV8File(snapshot_pf, snapshot_region, &g_mapped_snapshot)) | 319 if (!MapV8File(snapshot_pf, snapshot_region, &g_mapped_snapshot)) |
308 result = V8_LOAD_FAILED_MAP; | 320 result = V8_LOAD_FAILED_MAP; |
309 #if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) | 321 #if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) |
310 if (!VerifyV8StartupFile(&g_mapped_snapshot, g_snapshot_fingerprint)) | 322 if (!VerifyV8StartupFile(&g_mapped_snapshot, g_snapshot_fingerprint)) |
311 result = V8_LOAD_FAILED_VERIFY; | 323 result = V8_LOAD_FAILED_VERIFY; |
312 #endif // V8_VERIFY_EXTERNAL_STARTUP_DATA | 324 #endif // V8_VERIFY_EXTERNAL_STARTUP_DATA |
313 if (result == V8_LOAD_SUCCESS) { | 325 if (result == V8_LOAD_SUCCESS) { |
314 g_snapshot_pf = snapshot_pf; | 326 g_opened_files.Get()[kSnapshotFileName] = |
315 g_snapshot_region = snapshot_region; | 327 std::make_pair(snapshot_pf, snapshot_region); |
316 } | 328 } |
317 UMA_HISTOGRAM_ENUMERATION("V8.Initializer.LoadV8Snapshot.Result", result, | 329 UMA_HISTOGRAM_ENUMERATION("V8.Initializer.LoadV8Snapshot.Result", result, |
318 V8_LOAD_MAX_VALUE); | 330 V8_LOAD_MAX_VALUE); |
319 } | 331 } |
320 | 332 |
321 // static | 333 // static |
322 void V8Initializer::LoadV8NativesFromFD(base::PlatformFile natives_pf, | 334 void V8Initializer::LoadV8NativesFromFD(base::PlatformFile natives_pf, |
323 int64_t natives_offset, | 335 int64_t natives_offset, |
324 int64_t natives_size) { | 336 int64_t natives_size) { |
325 if (g_mapped_natives) | 337 if (g_mapped_natives) |
326 return; | 338 return; |
327 | 339 |
328 CHECK_NE(natives_pf, kInvalidPlatformFile); | 340 CHECK_NE(natives_pf, kInvalidPlatformFile); |
329 | 341 |
330 base::MemoryMappedFile::Region natives_region = | 342 base::MemoryMappedFile::Region natives_region = |
331 base::MemoryMappedFile::Region::kWholeFile; | 343 base::MemoryMappedFile::Region::kWholeFile; |
332 if (natives_size != 0 || natives_offset != 0) { | 344 if (natives_size != 0 || natives_offset != 0) { |
333 natives_region.offset = natives_offset; | 345 natives_region.offset = natives_offset; |
334 natives_region.size = natives_size; | 346 natives_region.size = natives_size; |
335 } | 347 } |
336 | 348 |
337 if (!MapV8File(natives_pf, natives_region, &g_mapped_natives)) { | 349 if (!MapV8File(natives_pf, natives_region, &g_mapped_natives)) { |
338 LOG(FATAL) << "Couldn't mmap v8 natives data file"; | 350 LOG(FATAL) << "Couldn't mmap v8 natives data file"; |
339 } | 351 } |
340 #if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) | 352 #if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) |
341 if (!VerifyV8StartupFile(&g_mapped_natives, g_natives_fingerprint)) { | 353 if (!VerifyV8StartupFile(&g_mapped_natives, g_natives_fingerprint)) { |
342 LOG(FATAL) << "Couldn't verify contents of v8 natives data file"; | 354 LOG(FATAL) << "Couldn't verify contents of v8 natives data file"; |
343 } | 355 } |
344 #endif // V8_VERIFY_EXTERNAL_STARTUP_DATA | 356 #endif // V8_VERIFY_EXTERNAL_STARTUP_DATA |
345 g_natives_pf = natives_pf; | 357 g_opened_files.Get()[kNativesFileName] = |
346 g_natives_region = natives_region; | 358 std::make_pair(natives_pf, natives_region); |
347 } | 359 } |
348 | 360 |
349 // static | 361 // static |
350 base::PlatformFile V8Initializer::GetOpenNativesFileForChildProcesses( | 362 base::PlatformFile V8Initializer::GetOpenNativesFileForChildProcesses( |
351 base::MemoryMappedFile::Region* region_out) { | 363 base::MemoryMappedFile::Region* region_out) { |
352 OpenNativesFileIfNecessary(); | 364 const OpenedFileMap::mapped_type& opened = |
353 *region_out = g_natives_region; | 365 OpenFileIfNecessary(kNativesFileName); |
354 return g_natives_pf; | 366 *region_out = opened.second; |
| 367 return opened.first; |
355 } | 368 } |
356 | 369 |
357 // static | 370 // static |
358 base::PlatformFile V8Initializer::GetOpenSnapshotFileForChildProcesses( | 371 base::PlatformFile V8Initializer::GetOpenSnapshotFileForChildProcesses( |
359 base::MemoryMappedFile::Region* region_out) { | 372 base::MemoryMappedFile::Region* region_out) { |
360 OpenSnapshotFileIfNecessary(); | 373 const OpenedFileMap::mapped_type& opened = |
361 *region_out = g_snapshot_region; | 374 OpenFileIfNecessary(kSnapshotFileName); |
362 return g_snapshot_pf; | 375 *region_out = opened.second; |
| 376 return opened.first; |
363 } | 377 } |
| 378 |
| 379 #if defined(OS_ANDROID) |
| 380 // static |
| 381 base::PlatformFile V8Initializer::GetOpenNativesFileForChildProcesses( |
| 382 base::MemoryMappedFile::Region* region_out, |
| 383 bool abi_32_bit) { |
| 384 const char* natives_file = |
| 385 abi_32_bit ? kNativesFileName32 : kNativesFileName64; |
| 386 const OpenedFileMap::mapped_type& opened = OpenFileIfNecessary(natives_file); |
| 387 *region_out = opened.second; |
| 388 return opened.first; |
| 389 } |
| 390 |
| 391 // static |
| 392 base::PlatformFile V8Initializer::GetOpenSnapshotFileForChildProcesses( |
| 393 base::MemoryMappedFile::Region* region_out, |
| 394 bool abi_32_bit) { |
| 395 const char* snapshot_file = |
| 396 abi_32_bit ? kSnapshotFileName32 : kSnapshotFileName64; |
| 397 const OpenedFileMap::mapped_type& opened = OpenFileIfNecessary(snapshot_file); |
| 398 *region_out = opened.second; |
| 399 return opened.first; |
| 400 } |
| 401 #endif // defined(OS_ANDROID) |
364 #endif // defined(V8_USE_EXTERNAL_STARTUP_DATA) | 402 #endif // defined(V8_USE_EXTERNAL_STARTUP_DATA) |
365 | 403 |
366 // static | 404 // static |
367 void V8Initializer::Initialize(IsolateHolder::ScriptMode mode, | 405 void V8Initializer::Initialize(IsolateHolder::ScriptMode mode, |
368 IsolateHolder::V8ExtrasMode v8_extras_mode) { | 406 IsolateHolder::V8ExtrasMode v8_extras_mode) { |
369 static bool v8_is_initialized = false; | 407 static bool v8_is_initialized = false; |
370 if (v8_is_initialized) | 408 if (v8_is_initialized) |
371 return; | 409 return; |
372 | 410 |
373 v8::V8::InitializePlatform(V8Platform::Get()); | 411 v8::V8::InitializePlatform(V8Platform::Get()); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
416 if (g_mapped_snapshot) { | 454 if (g_mapped_snapshot) { |
417 *snapshot_data_out = | 455 *snapshot_data_out = |
418 reinterpret_cast<const char*>(g_mapped_snapshot->data()); | 456 reinterpret_cast<const char*>(g_mapped_snapshot->data()); |
419 *snapshot_size_out = static_cast<int>(g_mapped_snapshot->length()); | 457 *snapshot_size_out = static_cast<int>(g_mapped_snapshot->length()); |
420 } else { | 458 } else { |
421 *snapshot_data_out = NULL; | 459 *snapshot_data_out = NULL; |
422 *snapshot_size_out = 0; | 460 *snapshot_size_out = 0; |
423 } | 461 } |
424 } | 462 } |
425 | 463 |
| 464 #if defined(OS_ANDROID) |
| 465 // static |
| 466 base::FilePath V8Initializer::GetNativesFilePath(bool abi_32_bit) { |
| 467 base::FilePath path; |
| 468 GetV8FilePath(abi_32_bit ? kNativesFileName32 : kNativesFileName64, &path); |
| 469 return path; |
| 470 } |
| 471 |
| 472 // static |
| 473 base::FilePath V8Initializer::GetSnapshotFilePath(bool abi_32_bit) { |
| 474 base::FilePath path; |
| 475 GetV8FilePath(abi_32_bit ? kSnapshotFileName32 : kSnapshotFileName64, &path); |
| 476 return path; |
| 477 } |
| 478 #endif // defined(OS_ANDROID) |
| 479 |
426 } // namespace gin | 480 } // namespace gin |
OLD | NEW |