• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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