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