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
3 // found in the LICENSE file.
5 #include "gin/public/isolate_holder.h"
10 #include "base/files/memory_mapped_file.h"
11 #include "base/logging.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/rand_util.h"
14 #include "base/sys_info.h"
15 #include "gin/array_buffer.h"
16 #include "gin/debug_impl.h"
17 #include "gin/function_template.h"
18 #include "gin/per_isolate_data.h"
19 #include "gin/public/v8_platform.h"
20 #include "gin/run_microtasks_observer.h"
22 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
23 #include "base/path_service.h"
24 #endif // V8_USE_EXTERNAL_STARTUP_DATA
30 v8::ArrayBuffer::Allocator
* g_array_buffer_allocator
= NULL
;
32 bool GenerateEntropy(unsigned char* buffer
, size_t amount
) {
33 base::RandBytes(buffer
, amount
);
37 base::MemoryMappedFile
* g_mapped_natives
= NULL
;
38 base::MemoryMappedFile
* g_mapped_snapshot
= NULL
;
40 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
41 bool MapV8Files(base::FilePath
* natives_path
, base::FilePath
* snapshot_path
,
42 int natives_fd
= -1, int snapshot_fd
= -1) {
43 int flags
= base::File::FLAG_OPEN
| base::File::FLAG_READ
;
45 g_mapped_natives
= new base::MemoryMappedFile
;
46 if (!g_mapped_natives
->IsValid()) {
48 ? !g_mapped_natives
->Initialize(base::File(*natives_path
, flags
))
49 : !g_mapped_natives
->Initialize(base::File(natives_fd
))) {
50 delete g_mapped_natives
;
51 g_mapped_natives
= NULL
;
52 LOG(FATAL
) << "Couldn't mmap v8 natives data file";
57 g_mapped_snapshot
= new base::MemoryMappedFile
;
58 if (!g_mapped_snapshot
->IsValid()) {
60 ? !g_mapped_snapshot
->Initialize(base::File(*snapshot_path
, flags
))
61 : !g_mapped_snapshot
->Initialize(base::File(snapshot_fd
))) {
62 delete g_mapped_snapshot
;
63 g_mapped_snapshot
= NULL
;
64 LOG(ERROR
) << "Couldn't mmap v8 snapshot data file";
71 #endif // V8_USE_EXTERNAL_STARTUP_DATA
76 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
78 bool IsolateHolder::LoadV8Snapshot() {
79 if (g_mapped_natives
&& g_mapped_snapshot
)
82 base::FilePath data_path
;
84 #if defined(OS_ANDROID)
85 base::DIR_ANDROID_APP_DATA
,
86 #elif defined(OS_POSIX)
90 DCHECK(!data_path
.empty());
92 base::FilePath natives_path
= data_path
.AppendASCII("natives_blob.bin");
93 base::FilePath snapshot_path
= data_path
.AppendASCII("snapshot_blob.bin");
95 return MapV8Files(&natives_path
, &snapshot_path
);
99 bool IsolateHolder::LoadV8SnapshotFD(int natives_fd
, int snapshot_fd
) {
100 if (g_mapped_natives
&& g_mapped_snapshot
)
103 return MapV8Files(NULL
, NULL
, natives_fd
, snapshot_fd
);
105 #endif // V8_USE_EXTERNAL_STARTUP_DATA
108 void IsolateHolder::GetV8ExternalSnapshotData(const char** natives_data_out
,
109 int* natives_size_out
,
110 const char** snapshot_data_out
,
111 int* snapshot_size_out
) {
112 if (!g_mapped_natives
|| !g_mapped_snapshot
) {
113 *natives_data_out
= *snapshot_data_out
= NULL
;
114 *natives_size_out
= *snapshot_size_out
= 0;
117 *natives_data_out
= reinterpret_cast<const char*>(g_mapped_natives
->data());
118 *snapshot_data_out
= reinterpret_cast<const char*>(g_mapped_snapshot
->data());
119 *natives_size_out
= static_cast<int>(g_mapped_natives
->length());
120 *snapshot_size_out
= static_cast<int>(g_mapped_snapshot
->length());
123 IsolateHolder::IsolateHolder() {
124 CHECK(g_array_buffer_allocator
)
125 << "You need to invoke gin::IsolateHolder::Initialize first";
126 v8::Isolate::CreateParams params
;
127 params
.entry_hook
= DebugImpl::GetFunctionEntryHook();
128 params
.code_event_handler
= DebugImpl::GetJitCodeEventHandler();
129 params
.constraints
.ConfigureDefaults(base::SysInfo::AmountOfPhysicalMemory(),
130 base::SysInfo::AmountOfVirtualMemory(),
131 base::SysInfo::NumberOfProcessors());
132 isolate_
= v8::Isolate::New(params
);
133 isolate_data_
.reset(new PerIsolateData(isolate_
, g_array_buffer_allocator
));
138 isolate_
->GetCodeRange(&code_range
, &size
);
139 Debug::CodeRangeCreatedCallback callback
=
140 DebugImpl::GetCodeRangeCreatedCallback();
141 if (code_range
&& size
&& callback
)
142 callback(code_range
, size
);
147 IsolateHolder::~IsolateHolder() {
148 if (task_observer_
.get())
149 base::MessageLoop::current()->RemoveTaskObserver(task_observer_
.get());
154 isolate_
->GetCodeRange(&code_range
, &size
);
155 Debug::CodeRangeDeletedCallback callback
=
156 DebugImpl::GetCodeRangeDeletedCallback();
157 if (code_range
&& callback
)
158 callback(code_range
);
161 isolate_data_
.reset();
166 void IsolateHolder::Initialize(ScriptMode mode
,
167 v8::ArrayBuffer::Allocator
* allocator
) {
169 static bool v8_is_initialized
= false;
170 if (v8_is_initialized
)
172 v8::V8::InitializePlatform(V8Platform::Get());
173 v8::V8::SetArrayBufferAllocator(allocator
);
174 g_array_buffer_allocator
= allocator
;
175 if (mode
== gin::IsolateHolder::kStrictMode
) {
176 static const char v8_flags
[] = "--use_strict";
177 v8::V8::SetFlagsFromString(v8_flags
, sizeof(v8_flags
) - 1);
179 v8::V8::SetEntropySource(&GenerateEntropy
);
180 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
181 v8::StartupData natives
;
182 natives
.data
= reinterpret_cast<const char*>(g_mapped_natives
->data());
183 natives
.raw_size
= static_cast<int>(g_mapped_natives
->length());
184 natives
.compressed_size
= static_cast<int>(g_mapped_natives
->length());
185 v8::V8::SetNativesDataBlob(&natives
);
187 v8::StartupData snapshot
;
188 snapshot
.data
= reinterpret_cast<const char*>(g_mapped_snapshot
->data());
189 snapshot
.raw_size
= static_cast<int>(g_mapped_snapshot
->length());
190 snapshot
.compressed_size
= static_cast<int>(g_mapped_snapshot
->length());
191 v8::V8::SetSnapshotDataBlob(&snapshot
);
192 #endif // V8_USE_EXTERNAL_STARTUP_DATA
193 v8::V8::Initialize();
194 v8_is_initialized
= true;
197 void IsolateHolder::AddRunMicrotasksObserver() {
198 DCHECK(!task_observer_
.get());
199 task_observer_
.reset(new RunMicrotasksObserver(isolate_
));;
200 base::MessageLoop::current()->AddTaskObserver(task_observer_
.get());
203 void IsolateHolder::RemoveRunMicrotasksObserver() {
204 DCHECK(task_observer_
.get());
205 base::MessageLoop::current()->RemoveTaskObserver(task_observer_
.get());
206 task_observer_
.reset();