OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2009 Google Inc. All rights reserved. | |
3 * | |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions | |
6 * are met: | |
7 * 1. Redistributions of source code must retain the above copyright | |
8 * notice, this list of conditions and the following disclaimer. | |
9 * 2. Redistributions in binary form must reproduce the above copyright | |
10 * notice, this list of conditions and the following disclaimer in the | |
11 * documentation and/or other materials provided with the distribution. | |
12 * | |
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' | |
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS | |
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
23 * THE POSSIBILITY OF SUCH DAMAGE. | |
24 */ | |
25 | |
26 #include "bindings/core/v8/V8PerIsolateData.h" | |
27 | |
28 #include <memory> | |
29 | |
30 #include "bindings/core/v8/DOMDataStore.h" | |
31 #include "bindings/core/v8/ScriptSourceCode.h" | |
32 #include "bindings/core/v8/V8Binding.h" | |
33 #include "bindings/core/v8/V8ObjectConstructor.h" | |
34 #include "bindings/core/v8/V8PrivateProperty.h" | |
35 #include "bindings/core/v8/V8ScriptRunner.h" | |
36 #include "bindings/core/v8/V8ValueCache.h" | |
37 #include "platform/ScriptForbiddenScope.h" | |
38 #include "platform/wtf/LeakAnnotations.h" | |
39 #include "platform/wtf/PtrUtil.h" | |
40 #include "public/platform/Platform.h" | |
41 #include "v8/include/v8-debug.h" | |
42 | |
43 namespace blink { | |
44 | |
45 static V8PerIsolateData* g_main_thread_per_isolate_data = 0; | |
46 | |
47 static void BeforeCallEnteredCallback(v8::Isolate* isolate) { | |
48 CHECK(!ScriptForbiddenScope::IsScriptForbidden()); | |
49 } | |
50 | |
51 static void MicrotasksCompletedCallback(v8::Isolate* isolate) { | |
52 V8PerIsolateData::From(isolate)->RunEndOfScopeTasks(); | |
53 } | |
54 | |
55 V8PerIsolateData::V8PerIsolateData(WebTaskRunner* task_runner) | |
56 : isolate_holder_( | |
57 task_runner ? task_runner->ToSingleThreadTaskRunner() : nullptr, | |
58 gin::IsolateHolder::kSingleThread, | |
59 IsMainThread() ? gin::IsolateHolder::kDisallowAtomicsWait | |
60 : gin::IsolateHolder::kAllowAtomicsWait), | |
61 string_cache_(WTF::WrapUnique(new StringCache(GetIsolate()))), | |
62 private_property_(V8PrivateProperty::Create()), | |
63 constructor_mode_(ConstructorMode::kCreateNewObject), | |
64 use_counter_disabled_(false), | |
65 is_handling_recursion_level_error_(false), | |
66 is_reporting_exception_(false) { | |
67 // FIXME: Remove once all v8::Isolate::GetCurrent() calls are gone. | |
68 GetIsolate()->Enter(); | |
69 GetIsolate()->AddBeforeCallEnteredCallback(&BeforeCallEnteredCallback); | |
70 GetIsolate()->AddMicrotasksCompletedCallback(&MicrotasksCompletedCallback); | |
71 if (IsMainThread()) | |
72 g_main_thread_per_isolate_data = this; | |
73 } | |
74 | |
75 V8PerIsolateData::~V8PerIsolateData() {} | |
76 | |
77 v8::Isolate* V8PerIsolateData::MainThreadIsolate() { | |
78 DCHECK(g_main_thread_per_isolate_data); | |
79 return g_main_thread_per_isolate_data->GetIsolate(); | |
80 } | |
81 | |
82 v8::Isolate* V8PerIsolateData::Initialize(WebTaskRunner* task_runner) { | |
83 V8PerIsolateData* data = new V8PerIsolateData(task_runner); | |
84 v8::Isolate* isolate = data->GetIsolate(); | |
85 isolate->SetData(gin::kEmbedderBlink, data); | |
86 return isolate; | |
87 } | |
88 | |
89 void V8PerIsolateData::EnableIdleTasks( | |
90 v8::Isolate* isolate, | |
91 std::unique_ptr<gin::V8IdleTaskRunner> task_runner) { | |
92 From(isolate)->isolate_holder_.EnableIdleTasks(std::move(task_runner)); | |
93 } | |
94 | |
95 v8::Persistent<v8::Value>& V8PerIsolateData::EnsureLiveRoot() { | |
96 if (live_root_.IsEmpty()) | |
97 live_root_.Set(GetIsolate(), v8::Null(GetIsolate())); | |
98 return live_root_.Get(); | |
99 } | |
100 | |
101 // willBeDestroyed() clear things that should be cleared before | |
102 // ThreadState::detach() gets called. | |
103 void V8PerIsolateData::WillBeDestroyed(v8::Isolate* isolate) { | |
104 V8PerIsolateData* data = From(isolate); | |
105 | |
106 data->thread_debugger_.reset(); | |
107 // Clear any data that may have handles into the heap, | |
108 // prior to calling ThreadState::detach(). | |
109 data->ClearEndOfScopeTasks(); | |
110 | |
111 data->active_script_wrappables_.Clear(); | |
112 } | |
113 | |
114 // destroy() clear things that should be cleared after ThreadState::detach() | |
115 // gets called but before the Isolate exits. | |
116 void V8PerIsolateData::Destroy(v8::Isolate* isolate) { | |
117 isolate->RemoveBeforeCallEnteredCallback(&BeforeCallEnteredCallback); | |
118 isolate->RemoveMicrotasksCompletedCallback(&MicrotasksCompletedCallback); | |
119 V8PerIsolateData* data = From(isolate); | |
120 | |
121 // Clear everything before exiting the Isolate. | |
122 if (data->script_regexp_script_state_) | |
123 data->script_regexp_script_state_->DisposePerContextData(); | |
124 data->live_root_.Clear(); | |
125 data->private_property_.reset(); | |
126 data->string_cache_->Dispose(); | |
127 data->string_cache_.reset(); | |
128 data->interface_template_map_for_non_main_world_.clear(); | |
129 data->interface_template_map_for_main_world_.clear(); | |
130 data->operation_template_map_for_non_main_world_.clear(); | |
131 data->operation_template_map_for_main_world_.clear(); | |
132 if (IsMainThread()) | |
133 g_main_thread_per_isolate_data = 0; | |
134 | |
135 // FIXME: Remove once all v8::Isolate::GetCurrent() calls are gone. | |
136 isolate->Exit(); | |
137 delete data; | |
138 } | |
139 | |
140 V8PerIsolateData::V8FunctionTemplateMap& | |
141 V8PerIsolateData::SelectInterfaceTemplateMap(const DOMWrapperWorld& world) { | |
142 return world.IsMainWorld() ? interface_template_map_for_main_world_ | |
143 : interface_template_map_for_non_main_world_; | |
144 } | |
145 | |
146 V8PerIsolateData::V8FunctionTemplateMap& | |
147 V8PerIsolateData::SelectOperationTemplateMap(const DOMWrapperWorld& world) { | |
148 return world.IsMainWorld() ? operation_template_map_for_main_world_ | |
149 : operation_template_map_for_non_main_world_; | |
150 } | |
151 | |
152 v8::Local<v8::FunctionTemplate> V8PerIsolateData::FindOrCreateOperationTemplate( | |
153 const DOMWrapperWorld& world, | |
154 const void* key, | |
155 v8::FunctionCallback callback, | |
156 v8::Local<v8::Value> data, | |
157 v8::Local<v8::Signature> signature, | |
158 int length) { | |
159 auto& map = SelectOperationTemplateMap(world); | |
160 auto result = map.find(key); | |
161 if (result != map.end()) | |
162 return result->value.Get(GetIsolate()); | |
163 | |
164 v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New( | |
165 GetIsolate(), callback, data, signature, length); | |
166 templ->RemovePrototype(); | |
167 map.insert(key, v8::Eternal<v8::FunctionTemplate>(GetIsolate(), templ)); | |
168 return templ; | |
169 } | |
170 | |
171 v8::Local<v8::FunctionTemplate> V8PerIsolateData::FindInterfaceTemplate( | |
172 const DOMWrapperWorld& world, | |
173 const void* key) { | |
174 auto& map = SelectInterfaceTemplateMap(world); | |
175 auto result = map.find(key); | |
176 if (result != map.end()) | |
177 return result->value.Get(GetIsolate()); | |
178 return v8::Local<v8::FunctionTemplate>(); | |
179 } | |
180 | |
181 void V8PerIsolateData::SetInterfaceTemplate( | |
182 const DOMWrapperWorld& world, | |
183 const void* key, | |
184 v8::Local<v8::FunctionTemplate> value) { | |
185 auto& map = SelectInterfaceTemplateMap(world); | |
186 map.insert(key, v8::Eternal<v8::FunctionTemplate>(GetIsolate(), value)); | |
187 } | |
188 | |
189 const v8::Eternal<v8::Name>* V8PerIsolateData::FindOrCreateEternalNameCache( | |
190 const void* lookup_key, | |
191 const char* const names[], | |
192 size_t count) { | |
193 auto it = eternal_name_cache_.find(lookup_key); | |
194 const Vector<v8::Eternal<v8::Name>>* vector = nullptr; | |
195 if (UNLIKELY(it == eternal_name_cache_.end())) { | |
196 v8::Isolate* isolate = this->GetIsolate(); | |
197 Vector<v8::Eternal<v8::Name>> new_vector(count); | |
198 std::transform( | |
199 names, names + count, new_vector.begin(), [isolate](const char* name) { | |
200 return v8::Eternal<v8::Name>(isolate, V8AtomicString(isolate, name)); | |
201 }); | |
202 vector = &eternal_name_cache_.Set(lookup_key, std::move(new_vector)) | |
203 .stored_value->value; | |
204 } else { | |
205 vector = &it->value; | |
206 } | |
207 DCHECK_EQ(vector->size(), count); | |
208 return vector->data(); | |
209 } | |
210 | |
211 v8::Local<v8::Context> V8PerIsolateData::EnsureScriptRegexpContext() { | |
212 if (!script_regexp_script_state_) { | |
213 LEAK_SANITIZER_DISABLED_SCOPE; | |
214 v8::Local<v8::Context> context(v8::Context::New(GetIsolate())); | |
215 script_regexp_script_state_ = ScriptState::Create( | |
216 context, DOMWrapperWorld::Create(GetIsolate(), | |
217 DOMWrapperWorld::WorldType::kRegExp)); | |
218 } | |
219 return script_regexp_script_state_->GetContext(); | |
220 } | |
221 | |
222 void V8PerIsolateData::ClearScriptRegexpContext() { | |
223 if (script_regexp_script_state_) | |
224 script_regexp_script_state_->DisposePerContextData(); | |
225 script_regexp_script_state_.Clear(); | |
226 } | |
227 | |
228 bool V8PerIsolateData::HasInstance( | |
229 const WrapperTypeInfo* untrusted_wrapper_type_info, | |
230 v8::Local<v8::Value> value) { | |
231 return HasInstance(untrusted_wrapper_type_info, value, | |
232 interface_template_map_for_main_world_) || | |
233 HasInstance(untrusted_wrapper_type_info, value, | |
234 interface_template_map_for_non_main_world_); | |
235 } | |
236 | |
237 bool V8PerIsolateData::HasInstance( | |
238 const WrapperTypeInfo* untrusted_wrapper_type_info, | |
239 v8::Local<v8::Value> value, | |
240 V8FunctionTemplateMap& map) { | |
241 auto result = map.find(untrusted_wrapper_type_info); | |
242 if (result == map.end()) | |
243 return false; | |
244 v8::Local<v8::FunctionTemplate> templ = result->value.Get(GetIsolate()); | |
245 return templ->HasInstance(value); | |
246 } | |
247 | |
248 v8::Local<v8::Object> V8PerIsolateData::FindInstanceInPrototypeChain( | |
249 const WrapperTypeInfo* info, | |
250 v8::Local<v8::Value> value) { | |
251 v8::Local<v8::Object> wrapper = FindInstanceInPrototypeChain( | |
252 info, value, interface_template_map_for_main_world_); | |
253 if (!wrapper.IsEmpty()) | |
254 return wrapper; | |
255 return FindInstanceInPrototypeChain( | |
256 info, value, interface_template_map_for_non_main_world_); | |
257 } | |
258 | |
259 v8::Local<v8::Object> V8PerIsolateData::FindInstanceInPrototypeChain( | |
260 const WrapperTypeInfo* info, | |
261 v8::Local<v8::Value> value, | |
262 V8FunctionTemplateMap& map) { | |
263 if (value.IsEmpty() || !value->IsObject()) | |
264 return v8::Local<v8::Object>(); | |
265 auto result = map.find(info); | |
266 if (result == map.end()) | |
267 return v8::Local<v8::Object>(); | |
268 v8::Local<v8::FunctionTemplate> templ = result->value.Get(GetIsolate()); | |
269 return v8::Local<v8::Object>::Cast(value)->FindInstanceInPrototypeChain( | |
270 templ); | |
271 } | |
272 | |
273 void V8PerIsolateData::AddEndOfScopeTask(std::unique_ptr<EndOfScopeTask> task) { | |
274 end_of_scope_tasks_.push_back(std::move(task)); | |
275 } | |
276 | |
277 void V8PerIsolateData::RunEndOfScopeTasks() { | |
278 Vector<std::unique_ptr<EndOfScopeTask>> tasks; | |
279 tasks.swap(end_of_scope_tasks_); | |
280 for (const auto& task : tasks) | |
281 task->Run(); | |
282 DCHECK(end_of_scope_tasks_.IsEmpty()); | |
283 } | |
284 | |
285 void V8PerIsolateData::ClearEndOfScopeTasks() { | |
286 end_of_scope_tasks_.clear(); | |
287 } | |
288 | |
289 void V8PerIsolateData::SetThreadDebugger( | |
290 std::unique_ptr<V8PerIsolateData::Data> thread_debugger) { | |
291 DCHECK(!thread_debugger_); | |
292 thread_debugger_ = std::move(thread_debugger); | |
293 } | |
294 | |
295 V8PerIsolateData::Data* V8PerIsolateData::ThreadDebugger() { | |
296 return thread_debugger_.get(); | |
297 } | |
298 | |
299 void V8PerIsolateData::AddActiveScriptWrappable( | |
300 ActiveScriptWrappableBase* wrappable) { | |
301 if (!active_script_wrappables_) | |
302 active_script_wrappables_ = new ActiveScriptWrappableSet(); | |
303 | |
304 active_script_wrappables_->insert(wrappable); | |
305 } | |
306 | |
307 void V8PerIsolateData::TemporaryScriptWrappableVisitorScope:: | |
308 SwapWithV8PerIsolateDataVisitor( | |
309 std::unique_ptr<ScriptWrappableVisitor>& visitor) { | |
310 ScriptWrappableVisitor* current = CurrentVisitor(); | |
311 if (current) | |
312 current->PerformCleanup(); | |
313 | |
314 V8PerIsolateData::From(isolate_)->script_wrappable_visitor_.swap( | |
315 saved_visitor_); | |
316 isolate_->SetEmbedderHeapTracer(CurrentVisitor()); | |
317 } | |
318 | |
319 } // namespace blink | |
OLD | NEW |