Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / bindings / core / v8 / V8PerIsolateData.cpp
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)
47 static void assertV8RecursionScope()
48 {
49     ASSERT(V8RecursionScope::properlyUsed(v8::Isolate::GetCurrent()));
50 }
51 #endif
52
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
64 V8PerIsolateData::V8PerIsolateData(v8::Isolate* isolate)
65     : m_isolate(isolate)
66     , m_isolateHolder(adoptPtr(new gin::IsolateHolder(m_isolate, v8ArrayBufferAllocator())))
67     , m_stringCache(adoptPtr(new StringCache(m_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 #if ENABLE(ASSERT)
79     // currentThread will always be non-null in production, but can be null in Chromium unit tests.
80     if (blink::Platform::current()->currentThread())
81         isolate->AddCallCompletedCallback(&assertV8RecursionScope);
82 #endif
83     if (isMainThread()) {
84         mainThreadPerIsolateData = this;
85         PageScriptDebugServer::setMainThreadIsolate(isolate);
86     }
87     isolate->SetUseCounterCallback(&useCounterCallback);
88 }
89
90 V8PerIsolateData::~V8PerIsolateData()
91 {
92     if (m_scriptRegexpScriptState)
93         m_scriptRegexpScriptState->disposePerContextData();
94     if (isMainThread())
95         mainThreadPerIsolateData = 0;
96 }
97
98 v8::Isolate* V8PerIsolateData::mainThreadIsolate()
99 {
100     ASSERT(isMainThread());
101     ASSERT(mainThreadPerIsolateData);
102     return mainThreadPerIsolateData->isolate();
103 }
104
105 void V8PerIsolateData::ensureInitialized(v8::Isolate* isolate)
106 {
107     ASSERT(isolate);
108     if (!isolate->GetData(gin::kEmbedderBlink)) {
109         V8PerIsolateData* data = new V8PerIsolateData(isolate);
110         isolate->SetData(gin::kEmbedderBlink, data);
111     }
112 }
113
114 v8::Persistent<v8::Value>& V8PerIsolateData::ensureLiveRoot()
115 {
116     if (m_liveRoot.isEmpty())
117         m_liveRoot.set(m_isolate, v8::Null(m_isolate));
118     return m_liveRoot.getUnsafe();
119 }
120
121 void V8PerIsolateData::dispose(v8::Isolate* isolate)
122 {
123 #if ENABLE(ASSERT)
124     if (blink::Platform::current()->currentThread())
125         isolate->RemoveCallCompletedCallback(&assertV8RecursionScope);
126 #endif
127     void* data = isolate->GetData(gin::kEmbedderBlink);
128     delete static_cast<V8PerIsolateData*>(data);
129     isolate->SetData(gin::kEmbedderBlink, 0);
130 }
131
132 V8PerIsolateData::DOMTemplateMap& V8PerIsolateData::currentDOMTemplateMap()
133 {
134     if (DOMWrapperWorld::current(m_isolate).isMainWorld())
135         return m_domTemplateMapForMainWorld;
136     return m_domTemplateMapForNonMainWorld;
137 }
138
139 v8::Handle<v8::FunctionTemplate> V8PerIsolateData::domTemplate(void* domTemplateKey, v8::FunctionCallback callback, v8::Handle<v8::Value> data, v8::Handle<v8::Signature> signature, int length)
140 {
141     DOMTemplateMap& domTemplateMap = currentDOMTemplateMap();
142     DOMTemplateMap::iterator result = domTemplateMap.find(domTemplateKey);
143     if (result != domTemplateMap.end())
144         return result->value.Get(m_isolate);
145
146     v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(m_isolate, callback, data, signature, length);
147     domTemplateMap.add(domTemplateKey, v8::Eternal<v8::FunctionTemplate>(m_isolate, templ));
148     return templ;
149 }
150
151 v8::Handle<v8::FunctionTemplate> V8PerIsolateData::existingDOMTemplate(void* domTemplateKey)
152 {
153     DOMTemplateMap& domTemplateMap = currentDOMTemplateMap();
154     DOMTemplateMap::iterator result = domTemplateMap.find(domTemplateKey);
155     if (result != domTemplateMap.end())
156         return result->value.Get(m_isolate);
157     return v8::Local<v8::FunctionTemplate>();
158 }
159
160 void V8PerIsolateData::setDOMTemplate(void* domTemplateKey, v8::Handle<v8::FunctionTemplate> templ)
161 {
162     currentDOMTemplateMap().add(domTemplateKey, v8::Eternal<v8::FunctionTemplate>(m_isolate, v8::Local<v8::FunctionTemplate>(templ)));
163 }
164
165 v8::Local<v8::Context> V8PerIsolateData::ensureScriptRegexpContext()
166 {
167     if (!m_scriptRegexpScriptState) {
168         v8::Local<v8::Context> context(v8::Context::New(m_isolate));
169         m_scriptRegexpScriptState = ScriptState::create(context, DOMWrapperWorld::create());
170     }
171     return m_scriptRegexpScriptState->context();
172 }
173
174 bool V8PerIsolateData::hasInstance(const WrapperTypeInfo* info, v8::Handle<v8::Value> value)
175 {
176     return hasInstance(info, value, m_domTemplateMapForMainWorld)
177         || hasInstance(info, value, m_domTemplateMapForNonMainWorld);
178 }
179
180 bool V8PerIsolateData::hasInstance(const WrapperTypeInfo* info, v8::Handle<v8::Value> value, DOMTemplateMap& domTemplateMap)
181 {
182     DOMTemplateMap::iterator result = domTemplateMap.find(info);
183     if (result == domTemplateMap.end())
184         return false;
185     v8::Handle<v8::FunctionTemplate> templ = result->value.Get(m_isolate);
186     return templ->HasInstance(value);
187 }
188
189 v8::Handle<v8::Object> V8PerIsolateData::findInstanceInPrototypeChain(const WrapperTypeInfo* info, v8::Handle<v8::Value> value)
190 {
191     v8::Handle<v8::Object> wrapper = findInstanceInPrototypeChain(info, value, m_domTemplateMapForMainWorld);
192     if (!wrapper.IsEmpty())
193         return wrapper;
194     return findInstanceInPrototypeChain(info, value, m_domTemplateMapForNonMainWorld);
195 }
196
197 v8::Handle<v8::Object> V8PerIsolateData::findInstanceInPrototypeChain(const WrapperTypeInfo* info, v8::Handle<v8::Value> value, DOMTemplateMap& domTemplateMap)
198 {
199     if (value.IsEmpty() || !value->IsObject())
200         return v8::Handle<v8::Object>();
201     DOMTemplateMap::iterator result = domTemplateMap.find(info);
202     if (result == domTemplateMap.end())
203         return v8::Handle<v8::Object>();
204     v8::Handle<v8::FunctionTemplate> templ = result->value.Get(m_isolate);
205     return v8::Handle<v8::Object>::Cast(value)->FindInstanceInPrototypeChain(templ);
206 }
207
208 static void constructorOfToString(const v8::FunctionCallbackInfo<v8::Value>& info)
209 {
210     // The DOM constructors' toString functions grab the current toString
211     // for Functions by taking the toString function of itself and then
212     // calling it with the constructor as its receiver. This means that
213     // changes to the Function prototype chain or toString function are
214     // reflected when printing DOM constructors. The only wart is that
215     // changes to a DOM constructor's toString's toString will cause the
216     // toString of the DOM constructor itself to change. This is extremely
217     // obscure and unlikely to be a problem.
218     v8::Handle<v8::Value> value = info.Callee()->Get(v8AtomicString(info.GetIsolate(), "toString"));
219     if (!value->IsFunction()) {
220         v8SetReturnValue(info, v8::String::Empty(info.GetIsolate()));
221         return;
222     }
223     v8SetReturnValue(info, V8ScriptRunner::callInternalFunction(v8::Handle<v8::Function>::Cast(value), info.This(), 0, 0, info.GetIsolate()));
224 }
225
226 v8::Handle<v8::FunctionTemplate> V8PerIsolateData::toStringTemplate()
227 {
228     if (m_toStringTemplate.isEmpty())
229         m_toStringTemplate.set(m_isolate, v8::FunctionTemplate::New(m_isolate, constructorOfToString));
230     return m_toStringTemplate.newLocal(m_isolate);
231 }
232
233 } // namespace blink