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 <memory> | 10 #include <memory> |
11 | 11 |
12 #include "base/debug/alias.h" | 12 #include "base/debug/alias.h" |
13 #include "base/debug/crash_logging.h" | 13 #include "base/debug/crash_logging.h" |
14 #include "base/feature_list.h" | 14 #include "base/feature_list.h" |
15 #include "base/files/file.h" | 15 #include "base/files/file.h" |
16 #include "base/files/file_path.h" | 16 #include "base/files/file_path.h" |
17 #include "base/files/memory_mapped_file.h" | 17 #include "base/files/memory_mapped_file.h" |
18 #include "base/lazy_instance.h" | 18 #include "base/lazy_instance.h" |
19 #include "base/logging.h" | 19 #include "base/logging.h" |
20 #include "base/metrics/histogram_macros.h" | 20 #include "base/metrics/histogram_macros.h" |
21 #include "base/path_service.h" | |
22 #include "base/rand_util.h" | 21 #include "base/rand_util.h" |
23 #include "base/strings/sys_string_conversions.h" | 22 #include "base/strings/sys_string_conversions.h" |
24 #include "base/sys_info.h" | 23 #include "base/sys_info.h" |
25 #include "base/threading/platform_thread.h" | 24 #include "base/threading/platform_thread.h" |
26 #include "base/time/time.h" | 25 #include "base/time/time.h" |
27 #include "build/build_config.h" | |
28 | 26 |
29 #if defined(V8_USE_EXTERNAL_STARTUP_DATA) | 27 #if defined(V8_USE_EXTERNAL_STARTUP_DATA) |
30 #if defined(OS_ANDROID) | 28 #if defined(OS_ANDROID) |
31 #include "base/android/apk_assets.h" | 29 #include "base/android/apk_assets.h" |
32 #elif defined(OS_MACOSX) | 30 #endif |
| 31 #if defined(OS_MACOSX) |
33 #include "base/mac/foundation_util.h" | 32 #include "base/mac/foundation_util.h" |
34 #endif | 33 #endif // OS_MACOSX |
| 34 #include "base/path_service.h" |
35 #endif // V8_USE_EXTERNAL_STARTUP_DATA | 35 #endif // V8_USE_EXTERNAL_STARTUP_DATA |
36 | 36 |
37 namespace gin { | 37 namespace gin { |
38 | 38 |
39 namespace { | 39 namespace { |
40 | 40 |
41 // None of these globals are ever freed nor closed. | 41 // None of these globals are ever freed nor closed. |
42 base::MemoryMappedFile* g_mapped_natives = nullptr; | 42 base::MemoryMappedFile* g_mapped_natives = nullptr; |
43 base::MemoryMappedFile* g_mapped_snapshot = nullptr; | 43 base::MemoryMappedFile* g_mapped_snapshot = nullptr; |
44 base::MemoryMappedFile* g_mapped_v8_context_snapshot = nullptr; | |
45 | 44 |
46 const char kV8ContextSnapshotFileName[] = "v8_context_snapshot.bin"; | 45 #if defined(V8_USE_EXTERNAL_STARTUP_DATA) |
47 | 46 |
48 // File handles intentionally never closed. Not using File here because its | 47 // File handles intentionally never closed. Not using File here because its |
49 // Windows implementation guards against two instances owning the same | 48 // Windows implementation guards against two instances owning the same |
50 // PlatformFile (which we allow since we know it is never freed). | 49 // PlatformFile (which we allow since we know it is never freed). |
51 using OpenedFileMap = | 50 typedef std::map<const char*, |
52 std::map<const char*, | 51 std::pair<base::PlatformFile, base::MemoryMappedFile::Region>> |
53 std::pair<base::PlatformFile, base::MemoryMappedFile::Region>>; | 52 OpenedFileMap; |
54 base::LazyInstance<OpenedFileMap>::Leaky g_opened_files = | 53 static base::LazyInstance<OpenedFileMap>::Leaky g_opened_files = |
55 LAZY_INSTANCE_INITIALIZER; | 54 LAZY_INSTANCE_INITIALIZER; |
56 | 55 |
57 OpenedFileMap::mapped_type& GetOpenedFile(const char* file) { | 56 OpenedFileMap::mapped_type& GetOpenedFile(const char* file) { |
58 OpenedFileMap& opened_files(g_opened_files.Get()); | 57 OpenedFileMap& opened_files(g_opened_files.Get()); |
59 if (opened_files.find(file) == opened_files.end()) { | 58 if (opened_files.find(file) == opened_files.end()) { |
60 opened_files[file] = std::make_pair(base::kInvalidPlatformFile, | 59 opened_files[file] = std::make_pair(base::kInvalidPlatformFile, |
61 base::MemoryMappedFile::Region()); | 60 base::MemoryMappedFile::Region()); |
62 } | 61 } |
63 return opened_files[file]; | 62 return opened_files[file]; |
64 } | 63 } |
65 | 64 |
66 #if defined(V8_USE_EXTERNAL_STARTUP_DATA) | |
67 | |
68 const char kNativesFileName[] = "natives_blob.bin"; | 65 const char kNativesFileName[] = "natives_blob.bin"; |
69 | 66 |
70 #if defined(OS_ANDROID) | 67 #if defined(OS_ANDROID) |
71 const char kSnapshotFileName64[] = "snapshot_blob_64.bin"; | 68 const char kSnapshotFileName64[] = "snapshot_blob_64.bin"; |
72 const char kSnapshotFileName32[] = "snapshot_blob_32.bin"; | 69 const char kSnapshotFileName32[] = "snapshot_blob_32.bin"; |
73 | 70 |
74 #if defined(__LP64__) | 71 #if defined(__LP64__) |
75 #define kSnapshotFileName kSnapshotFileName64 | 72 #define kSnapshotFileName kSnapshotFileName64 |
76 #else | 73 #else |
77 #define kSnapshotFileName kSnapshotFileName32 | 74 #define kSnapshotFileName kSnapshotFileName32 |
78 #endif | 75 #endif |
79 | 76 |
80 #else // defined(OS_ANDROID) | 77 #else // defined(OS_ANDROID) |
81 const char kSnapshotFileName[] = "snapshot_blob.bin"; | 78 const char kSnapshotFileName[] = "snapshot_blob.bin"; |
82 #endif // defined(OS_ANDROID) | 79 #endif // defined(OS_ANDROID) |
83 | 80 |
84 #endif // defined(V8_USE_EXTERNAL_STATUP_DATA) | |
85 | |
86 void GetV8FilePath(const char* file_name, base::FilePath* path_out) { | 81 void GetV8FilePath(const char* file_name, base::FilePath* path_out) { |
87 #if !defined(OS_MACOSX) | 82 #if !defined(OS_MACOSX) |
88 base::FilePath data_path; | 83 base::FilePath data_path; |
89 #if defined(OS_ANDROID) | 84 #if defined(OS_ANDROID) |
90 // This is the path within the .apk. | 85 // This is the path within the .apk. |
91 data_path = base::FilePath(FILE_PATH_LITERAL("assets")); | 86 data_path = base::FilePath(FILE_PATH_LITERAL("assets")); |
92 #elif defined(OS_POSIX) | 87 #elif defined(OS_POSIX) |
93 PathService::Get(base::DIR_EXE, &data_path); | 88 PathService::Get(base::DIR_EXE, &data_path); |
94 #elif defined(OS_WIN) | 89 #elif defined(OS_WIN) |
95 PathService::Get(base::DIR_MODULE, &data_path); | 90 PathService::Get(base::DIR_MODULE, &data_path); |
96 #endif | 91 #endif |
97 DCHECK(!data_path.empty()); | 92 DCHECK(!data_path.empty()); |
98 | 93 |
99 *path_out = data_path.AppendASCII(file_name); | 94 *path_out = data_path.AppendASCII(file_name); |
100 #else // !defined(OS_MACOSX) | 95 #else // !defined(OS_MACOSX) |
101 base::ScopedCFTypeRef<CFStringRef> natives_file_name( | 96 base::ScopedCFTypeRef<CFStringRef> natives_file_name( |
102 base::SysUTF8ToCFStringRef(file_name)); | 97 base::SysUTF8ToCFStringRef(file_name)); |
103 *path_out = base::mac::PathForFrameworkBundleResource(natives_file_name); | 98 *path_out = base::mac::PathForFrameworkBundleResource(natives_file_name); |
104 #endif // !defined(OS_MACOSX) | 99 #endif // !defined(OS_MACOSX) |
| 100 DCHECK(!path_out->empty()); |
105 } | 101 } |
106 | 102 |
107 bool MapV8File(base::PlatformFile platform_file, | 103 static bool MapV8File(base::PlatformFile platform_file, |
108 base::MemoryMappedFile::Region region, | 104 base::MemoryMappedFile::Region region, |
109 base::MemoryMappedFile** mmapped_file_out) { | 105 base::MemoryMappedFile** mmapped_file_out) { |
110 DCHECK(*mmapped_file_out == NULL); | 106 DCHECK(*mmapped_file_out == NULL); |
111 std::unique_ptr<base::MemoryMappedFile> mmapped_file( | 107 std::unique_ptr<base::MemoryMappedFile> mmapped_file( |
112 new base::MemoryMappedFile()); | 108 new base::MemoryMappedFile()); |
113 if (mmapped_file->Initialize(base::File(platform_file), region)) { | 109 if (mmapped_file->Initialize(base::File(platform_file), region)) { |
114 *mmapped_file_out = mmapped_file.release(); | 110 *mmapped_file_out = mmapped_file.release(); |
115 return true; | 111 return true; |
116 } | 112 } |
117 return false; | 113 return false; |
118 } | 114 } |
119 | 115 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 } | 173 } |
178 } | 174 } |
179 #endif // defined(OS_ANDROID) | 175 #endif // defined(OS_ANDROID) |
180 | 176 |
181 UMA_HISTOGRAM_ENUMERATION("V8.Initializer.OpenV8File.Result", | 177 UMA_HISTOGRAM_ENUMERATION("V8.Initializer.OpenV8File.Result", |
182 result, | 178 result, |
183 OpenV8FileResult::MAX_VALUE); | 179 OpenV8FileResult::MAX_VALUE); |
184 return file.TakePlatformFile(); | 180 return file.TakePlatformFile(); |
185 } | 181 } |
186 | 182 |
187 const OpenedFileMap::mapped_type OpenFileIfNecessary(const char* file_name) { | 183 static const OpenedFileMap::mapped_type OpenFileIfNecessary( |
| 184 const char* file_name) { |
188 OpenedFileMap::mapped_type& opened = GetOpenedFile(file_name); | 185 OpenedFileMap::mapped_type& opened = GetOpenedFile(file_name); |
189 if (opened.first == base::kInvalidPlatformFile) { | 186 if (opened.first == base::kInvalidPlatformFile) { |
190 opened.first = OpenV8File(file_name, &opened.second); | 187 opened.first = OpenV8File(file_name, &opened.second); |
191 } | 188 } |
192 return opened; | 189 return opened; |
193 } | 190 } |
194 | 191 |
| 192 #endif // V8_USE_EXTERNAL_STARTUP_DATA |
| 193 |
195 bool GenerateEntropy(unsigned char* buffer, size_t amount) { | 194 bool GenerateEntropy(unsigned char* buffer, size_t amount) { |
196 base::RandBytes(buffer, amount); | 195 base::RandBytes(buffer, amount); |
197 return true; | 196 return true; |
198 } | 197 } |
199 | 198 |
| 199 } // namespace |
| 200 |
| 201 #if defined(V8_USE_EXTERNAL_STARTUP_DATA) |
| 202 |
| 203 namespace { |
| 204 |
200 enum LoadV8FileResult { | 205 enum LoadV8FileResult { |
201 V8_LOAD_SUCCESS = 0, | 206 V8_LOAD_SUCCESS = 0, |
202 V8_LOAD_FAILED_OPEN, | 207 V8_LOAD_FAILED_OPEN, |
203 V8_LOAD_FAILED_MAP, | 208 V8_LOAD_FAILED_MAP, |
204 V8_LOAD_FAILED_VERIFY, // Deprecated. | 209 V8_LOAD_FAILED_VERIFY, // Deprecated. |
205 V8_LOAD_MAX_VALUE | 210 V8_LOAD_MAX_VALUE |
206 }; | 211 }; |
207 | 212 |
208 LoadV8FileResult MapOpenedFile(const OpenedFileMap::mapped_type& file_region, | 213 static LoadV8FileResult MapOpenedFile( |
209 base::MemoryMappedFile** mmapped_file_out) { | 214 const OpenedFileMap::mapped_type& file_region, |
| 215 base::MemoryMappedFile** mmapped_file_out) { |
210 if (file_region.first == base::kInvalidPlatformFile) | 216 if (file_region.first == base::kInvalidPlatformFile) |
211 return V8_LOAD_FAILED_OPEN; | 217 return V8_LOAD_FAILED_OPEN; |
212 if (!MapV8File(file_region.first, file_region.second, mmapped_file_out)) | 218 if (!MapV8File(file_region.first, file_region.second, mmapped_file_out)) |
213 return V8_LOAD_FAILED_MAP; | 219 return V8_LOAD_FAILED_MAP; |
214 return V8_LOAD_SUCCESS; | 220 return V8_LOAD_SUCCESS; |
215 } | 221 } |
216 | 222 |
217 } // namespace | 223 } // namespace |
218 | 224 |
219 #if defined(V8_USE_EXTERNAL_STARTUP_DATA) | |
220 | |
221 // static | 225 // static |
222 void V8Initializer::LoadV8Snapshot() { | 226 void V8Initializer::LoadV8Snapshot() { |
223 if (g_mapped_snapshot) | 227 if (g_mapped_snapshot) |
224 return; | 228 return; |
225 | 229 |
226 OpenFileIfNecessary(kSnapshotFileName); | 230 OpenFileIfNecessary(kSnapshotFileName); |
227 LoadV8FileResult result = MapOpenedFile(GetOpenedFile(kSnapshotFileName), | 231 LoadV8FileResult result = MapOpenedFile(GetOpenedFile(kSnapshotFileName), |
228 &g_mapped_snapshot); | 232 &g_mapped_snapshot); |
229 // V8 can't start up without the source of the natives, but it can | 233 // V8 can't start up without the source of the natives, but it can |
230 // start up (slower) without the snapshot. | 234 // start up (slower) without the snapshot. |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
359 static const char flag[] = "--experimental_extras"; | 363 static const char flag[] = "--experimental_extras"; |
360 v8::V8::SetFlagsFromString(flag, sizeof(flag) - 1); | 364 v8::V8::SetFlagsFromString(flag, sizeof(flag) - 1); |
361 } | 365 } |
362 | 366 |
363 #if defined(V8_USE_EXTERNAL_STARTUP_DATA) | 367 #if defined(V8_USE_EXTERNAL_STARTUP_DATA) |
364 v8::StartupData natives; | 368 v8::StartupData natives; |
365 natives.data = reinterpret_cast<const char*>(g_mapped_natives->data()); | 369 natives.data = reinterpret_cast<const char*>(g_mapped_natives->data()); |
366 natives.raw_size = static_cast<int>(g_mapped_natives->length()); | 370 natives.raw_size = static_cast<int>(g_mapped_natives->length()); |
367 v8::V8::SetNativesDataBlob(&natives); | 371 v8::V8::SetNativesDataBlob(&natives); |
368 | 372 |
369 if (g_mapped_snapshot) { | 373 if (g_mapped_snapshot != NULL) { |
370 v8::StartupData snapshot; | 374 v8::StartupData snapshot; |
371 snapshot.data = reinterpret_cast<const char*>(g_mapped_snapshot->data()); | 375 snapshot.data = reinterpret_cast<const char*>(g_mapped_snapshot->data()); |
372 snapshot.raw_size = static_cast<int>(g_mapped_snapshot->length()); | 376 snapshot.raw_size = static_cast<int>(g_mapped_snapshot->length()); |
373 v8::V8::SetSnapshotDataBlob(&snapshot); | 377 v8::V8::SetSnapshotDataBlob(&snapshot); |
374 } | 378 } |
375 #endif // V8_USE_EXTERNAL_STARTUP_DATA | 379 #endif // V8_USE_EXTERNAL_STARTUP_DATA |
376 | 380 |
377 v8::V8::SetEntropySource(&GenerateEntropy); | 381 v8::V8::SetEntropySource(&GenerateEntropy); |
378 v8::V8::Initialize(); | 382 v8::V8::Initialize(); |
379 | 383 |
(...skipping 15 matching lines...) Expand all Loading... |
395 if (g_mapped_snapshot) { | 399 if (g_mapped_snapshot) { |
396 *snapshot_data_out = | 400 *snapshot_data_out = |
397 reinterpret_cast<const char*>(g_mapped_snapshot->data()); | 401 reinterpret_cast<const char*>(g_mapped_snapshot->data()); |
398 *snapshot_size_out = static_cast<int>(g_mapped_snapshot->length()); | 402 *snapshot_size_out = static_cast<int>(g_mapped_snapshot->length()); |
399 } else { | 403 } else { |
400 *snapshot_data_out = NULL; | 404 *snapshot_data_out = NULL; |
401 *snapshot_size_out = 0; | 405 *snapshot_size_out = 0; |
402 } | 406 } |
403 } | 407 } |
404 | 408 |
405 // static | |
406 void V8Initializer::LoadV8ContextSnapshot() { | |
407 if (g_mapped_v8_context_snapshot) | |
408 return; | |
409 | |
410 OpenFileIfNecessary(kV8ContextSnapshotFileName); | |
411 MapOpenedFile(GetOpenedFile(kV8ContextSnapshotFileName), | |
412 &g_mapped_v8_context_snapshot); | |
413 | |
414 // TODO(peria): Check if the snapshot file is loaded successfully. | |
415 } | |
416 | |
417 // static | |
418 void V8Initializer::LoadV8ContextSnapshotFromFD(base::PlatformFile snapshot_pf, | |
419 int64_t snapshot_offset, | |
420 int64_t snapshot_size) { | |
421 if (g_mapped_v8_context_snapshot) | |
422 return; | |
423 CHECK_NE(base::kInvalidPlatformFile, snapshot_pf); | |
424 | |
425 base::MemoryMappedFile::Region snapshot_region = | |
426 base::MemoryMappedFile::Region::kWholeFile; | |
427 if (snapshot_size != 0 || snapshot_offset != 0) { | |
428 snapshot_region.offset = snapshot_offset; | |
429 snapshot_region.size = snapshot_size; | |
430 } | |
431 | |
432 if (MapV8File(snapshot_pf, snapshot_region, &g_mapped_v8_context_snapshot)) { | |
433 g_opened_files.Get()[kV8ContextSnapshotFileName] = | |
434 std::make_pair(snapshot_pf, snapshot_region); | |
435 } | |
436 } | |
437 | |
438 // static | |
439 void V8Initializer::GetV8ContextSnapshotData(const char** snapshot_data_out, | |
440 int* snapshot_size_out) { | |
441 if (g_mapped_v8_context_snapshot) { | |
442 *snapshot_data_out = | |
443 reinterpret_cast<const char*>(g_mapped_v8_context_snapshot->data()); | |
444 *snapshot_size_out = | |
445 static_cast<int>(g_mapped_v8_context_snapshot->length()); | |
446 } else { | |
447 *snapshot_data_out = nullptr; | |
448 *snapshot_size_out = 0; | |
449 } | |
450 } | |
451 | |
452 } // namespace gin | 409 } // namespace gin |
OLD | NEW |