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