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 "config.h"
27 #include "bindings/core/v8/V8PerIsolateData.h"
28
29 #include "bindings/core/v8/DOMDataStore.h"
30 #include "bindings/core/v8/PageScriptDebugServer.h"
31 #include "bindings/core/v8/ScriptGCEvent.h"
32 #include "bindings/core/v8/ScriptProfiler.h"
33 #include "bindings/core/v8/V8Binding.h"
34 #include "bindings/core/v8/V8HiddenValue.h"
35 #include "bindings/core/v8/V8ObjectConstructor.h"
36 #include "bindings/core/v8/V8RecursionScope.h"
37 #include "bindings/core/v8/V8ScriptRunner.h"
38 #include "core/frame/UseCounter.h"
39 #include "public/platform/Platform.h"
40 #include "wtf/MainThread.h"
41
42 namespace blink {
43
44 static V8PerIsolateData* mainThreadPerIsolateData = 0;
45
46 #if ENABLE(ASSERT)
assertV8RecursionScope()47 static void assertV8RecursionScope()
48 {
49 ASSERT(V8RecursionScope::properlyUsed(v8::Isolate::GetCurrent()));
50 }
51 #endif
52
useCounterCallback(v8::Isolate * isolate,v8::Isolate::UseCounterFeature feature)53 static void useCounterCallback(v8::Isolate* isolate, v8::Isolate::UseCounterFeature feature)
54 {
55 switch (feature) {
56 case v8::Isolate::kUseAsm:
57 UseCounter::count(currentExecutionContext(isolate), UseCounter::UseAsm);
58 break;
59 default:
60 ASSERT_NOT_REACHED();
61 }
62 }
63
V8PerIsolateData()64 V8PerIsolateData::V8PerIsolateData()
65 : m_destructionPending(false)
66 , m_isolateHolder(adoptPtr(new gin::IsolateHolder()))
67 , m_stringCache(adoptPtr(new StringCache(isolate())))
68 , m_hiddenValue(adoptPtr(new V8HiddenValue()))
69 , m_constructorMode(ConstructorMode::CreateNewObject)
70 , m_recursionLevel(0)
71 , m_isHandlingRecursionLevelError(false)
72 #if ENABLE(ASSERT)
73 , m_internalScriptRecursionLevel(0)
74 #endif
75 , m_gcEventData(adoptPtr(new GCEventData()))
76 , m_performingMicrotaskCheckpoint(false)
77 {
78 // FIXME: Remove once all v8::Isolate::GetCurrent() calls are gone.
79 isolate()->Enter();
80 #if ENABLE(ASSERT)
81 // currentThread will always be non-null in production, but can be null in Chromium unit tests.
82 if (blink::Platform::current()->currentThread())
83 isolate()->AddCallCompletedCallback(&assertV8RecursionScope);
84 #endif
85 if (isMainThread()) {
86 mainThreadPerIsolateData = this;
87 PageScriptDebugServer::setMainThreadIsolate(isolate());
88 }
89 isolate()->SetUseCounterCallback(&useCounterCallback);
90 }
91
~V8PerIsolateData()92 V8PerIsolateData::~V8PerIsolateData()
93 {
94 if (m_scriptRegexpScriptState)
95 m_scriptRegexpScriptState->disposePerContextData();
96 if (isMainThread())
97 mainThreadPerIsolateData = 0;
98 }
99
mainThreadIsolate()100 v8::Isolate* V8PerIsolateData::mainThreadIsolate()
101 {
102 ASSERT(isMainThread());
103 ASSERT(mainThreadPerIsolateData);
104 return mainThreadPerIsolateData->isolate();
105 }
106
initialize()107 v8::Isolate* V8PerIsolateData::initialize()
108 {
109 V8PerIsolateData* data = new V8PerIsolateData();
110 v8::Isolate* isolate = data->isolate();
111 isolate->SetData(gin::kEmbedderBlink, data);
112 return isolate;
113 }
114
ensureLiveRoot()115 v8::Persistent<v8::Value>& V8PerIsolateData::ensureLiveRoot()
116 {
117 if (m_liveRoot.isEmpty())
118 m_liveRoot.set(isolate(), v8::Null(isolate()));
119 return m_liveRoot.getUnsafe();
120 }
121
willBeDestroyed(v8::Isolate * isolate)122 void V8PerIsolateData::willBeDestroyed(v8::Isolate* isolate)
123 {
124 V8PerIsolateData* data = from(isolate);
125
126 ASSERT(!data->m_destructionPending);
127 data->m_destructionPending = true;
128
129 // Clear any data that may have handles into the heap,
130 // prior to calling ThreadState::detach().
131 data->m_idbPendingTransactionMonitor.clear();
132 }
133
destroy(v8::Isolate * isolate)134 void V8PerIsolateData::destroy(v8::Isolate* isolate)
135 {
136 #if ENABLE(ASSERT)
137 if (blink::Platform::current()->currentThread())
138 isolate->RemoveCallCompletedCallback(&assertV8RecursionScope);
139 #endif
140 V8PerIsolateData* data = from(isolate);
141 // FIXME: Remove once all v8::Isolate::GetCurrent() calls are gone.
142 isolate->Exit();
143 delete data;
144 }
145
currentDOMTemplateMap()146 V8PerIsolateData::DOMTemplateMap& V8PerIsolateData::currentDOMTemplateMap()
147 {
148 if (DOMWrapperWorld::current(isolate()).isMainWorld())
149 return m_domTemplateMapForMainWorld;
150 return m_domTemplateMapForNonMainWorld;
151 }
152
domTemplate(void * domTemplateKey,v8::FunctionCallback callback,v8::Handle<v8::Value> data,v8::Handle<v8::Signature> signature,int length)153 v8::Handle<v8::FunctionTemplate> V8PerIsolateData::domTemplate(void* domTemplateKey, v8::FunctionCallback callback, v8::Handle<v8::Value> data, v8::Handle<v8::Signature> signature, int length)
154 {
155 DOMTemplateMap& domTemplateMap = currentDOMTemplateMap();
156 DOMTemplateMap::iterator result = domTemplateMap.find(domTemplateKey);
157 if (result != domTemplateMap.end())
158 return result->value.Get(isolate());
159
160 v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate(), callback, data, signature, length);
161 domTemplateMap.add(domTemplateKey, v8::Eternal<v8::FunctionTemplate>(isolate(), templ));
162 return templ;
163 }
164
existingDOMTemplate(void * domTemplateKey)165 v8::Handle<v8::FunctionTemplate> V8PerIsolateData::existingDOMTemplate(void* domTemplateKey)
166 {
167 DOMTemplateMap& domTemplateMap = currentDOMTemplateMap();
168 DOMTemplateMap::iterator result = domTemplateMap.find(domTemplateKey);
169 if (result != domTemplateMap.end())
170 return result->value.Get(isolate());
171 return v8::Local<v8::FunctionTemplate>();
172 }
173
setDOMTemplate(void * domTemplateKey,v8::Handle<v8::FunctionTemplate> templ)174 void V8PerIsolateData::setDOMTemplate(void* domTemplateKey, v8::Handle<v8::FunctionTemplate> templ)
175 {
176 currentDOMTemplateMap().add(domTemplateKey, v8::Eternal<v8::FunctionTemplate>(isolate(), v8::Local<v8::FunctionTemplate>(templ)));
177 }
178
ensureScriptRegexpContext()179 v8::Local<v8::Context> V8PerIsolateData::ensureScriptRegexpContext()
180 {
181 if (!m_scriptRegexpScriptState) {
182 v8::Local<v8::Context> context(v8::Context::New(isolate()));
183 m_scriptRegexpScriptState = ScriptState::create(context, DOMWrapperWorld::create());
184 }
185 return m_scriptRegexpScriptState->context();
186 }
187
hasInstance(const WrapperTypeInfo * info,v8::Handle<v8::Value> value)188 bool V8PerIsolateData::hasInstance(const WrapperTypeInfo* info, v8::Handle<v8::Value> value)
189 {
190 return hasInstance(info, value, m_domTemplateMapForMainWorld)
191 || hasInstance(info, value, m_domTemplateMapForNonMainWorld);
192 }
193
hasInstance(const WrapperTypeInfo * info,v8::Handle<v8::Value> value,DOMTemplateMap & domTemplateMap)194 bool V8PerIsolateData::hasInstance(const WrapperTypeInfo* info, v8::Handle<v8::Value> value, DOMTemplateMap& domTemplateMap)
195 {
196 DOMTemplateMap::iterator result = domTemplateMap.find(info);
197 if (result == domTemplateMap.end())
198 return false;
199 v8::Handle<v8::FunctionTemplate> templ = result->value.Get(isolate());
200 return templ->HasInstance(value);
201 }
202
findInstanceInPrototypeChain(const WrapperTypeInfo * info,v8::Handle<v8::Value> value)203 v8::Handle<v8::Object> V8PerIsolateData::findInstanceInPrototypeChain(const WrapperTypeInfo* info, v8::Handle<v8::Value> value)
204 {
205 v8::Handle<v8::Object> wrapper = findInstanceInPrototypeChain(info, value, m_domTemplateMapForMainWorld);
206 if (!wrapper.IsEmpty())
207 return wrapper;
208 return findInstanceInPrototypeChain(info, value, m_domTemplateMapForNonMainWorld);
209 }
210
findInstanceInPrototypeChain(const WrapperTypeInfo * info,v8::Handle<v8::Value> value,DOMTemplateMap & domTemplateMap)211 v8::Handle<v8::Object> V8PerIsolateData::findInstanceInPrototypeChain(const WrapperTypeInfo* info, v8::Handle<v8::Value> value, DOMTemplateMap& domTemplateMap)
212 {
213 if (value.IsEmpty() || !value->IsObject())
214 return v8::Handle<v8::Object>();
215 DOMTemplateMap::iterator result = domTemplateMap.find(info);
216 if (result == domTemplateMap.end())
217 return v8::Handle<v8::Object>();
218 v8::Handle<v8::FunctionTemplate> templ = result->value.Get(isolate());
219 return v8::Handle<v8::Object>::Cast(value)->FindInstanceInPrototypeChain(templ);
220 }
221
constructorOfToString(const v8::FunctionCallbackInfo<v8::Value> & info)222 static void constructorOfToString(const v8::FunctionCallbackInfo<v8::Value>& info)
223 {
224 // The DOM constructors' toString functions grab the current toString
225 // for Functions by taking the toString function of itself and then
226 // calling it with the constructor as its receiver. This means that
227 // changes to the Function prototype chain or toString function are
228 // reflected when printing DOM constructors. The only wart is that
229 // changes to a DOM constructor's toString's toString will cause the
230 // toString of the DOM constructor itself to change. This is extremely
231 // obscure and unlikely to be a problem.
232 v8::Handle<v8::Value> value = info.Callee()->Get(v8AtomicString(info.GetIsolate(), "toString"));
233 if (!value->IsFunction()) {
234 v8SetReturnValue(info, v8::String::Empty(info.GetIsolate()));
235 return;
236 }
237 v8SetReturnValue(info, V8ScriptRunner::callInternalFunction(v8::Handle<v8::Function>::Cast(value), info.This(), 0, 0, info.GetIsolate()));
238 }
239
toStringTemplate()240 v8::Handle<v8::FunctionTemplate> V8PerIsolateData::toStringTemplate()
241 {
242 if (m_toStringTemplate.isEmpty())
243 m_toStringTemplate.set(isolate(), v8::FunctionTemplate::New(isolate(), constructorOfToString));
244 return m_toStringTemplate.newLocal(isolate());
245 }
246
ensureIDBPendingTransactionMonitor()247 IDBPendingTransactionMonitor* V8PerIsolateData::ensureIDBPendingTransactionMonitor()
248 {
249 if (!m_idbPendingTransactionMonitor)
250 m_idbPendingTransactionMonitor = adoptPtr(new IDBPendingTransactionMonitor());
251 return m_idbPendingTransactionMonitor.get();
252 }
253
254 } // namespace blink
255