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() 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 92 V8PerIsolateData::~V8PerIsolateData() 93 { 94 if (m_scriptRegexpScriptState) 95 m_scriptRegexpScriptState->disposePerContextData(); 96 if (isMainThread()) 97 mainThreadPerIsolateData = 0; 98 } 99 100 v8::Isolate* V8PerIsolateData::mainThreadIsolate() 101 { 102 ASSERT(isMainThread()); 103 ASSERT(mainThreadPerIsolateData); 104 return mainThreadPerIsolateData->isolate(); 105 } 106 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 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 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 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 146 V8PerIsolateData::DOMTemplateMap& V8PerIsolateData::currentDOMTemplateMap() 147 { 148 if (DOMWrapperWorld::current(isolate()).isMainWorld()) 149 return m_domTemplateMapForMainWorld; 150 return m_domTemplateMapForNonMainWorld; 151 } 152 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 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 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 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 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 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 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 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 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 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 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