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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "public/web/WebKit.h" 33 34 #include "bindings/v8/V8Binding.h" 35 #include "bindings/v8/V8GCController.h" 36 #include "bindings/v8/V8Initializer.h" 37 #include "core/Init.h" 38 #include "core/animation/AnimationClock.h" 39 #include "core/dom/Microtask.h" 40 #include "core/frame/Settings.h" 41 #include "core/page/Page.h" 42 #include "core/workers/WorkerGlobalScopeProxy.h" 43 #include "gin/public/v8_platform.h" 44 #include "modules/InitModules.h" 45 #include "platform/LayoutTestSupport.h" 46 #include "platform/Logging.h" 47 #include "platform/RuntimeEnabledFeatures.h" 48 #include "platform/graphics/ImageDecodingStore.h" 49 #include "platform/graphics/media/MediaPlayer.h" 50 #include "platform/heap/Heap.h" 51 #include "platform/heap/glue/MessageLoopInterruptor.h" 52 #include "platform/heap/glue/PendingGCRunner.h" 53 #include "public/platform/Platform.h" 54 #include "public/platform/WebPrerenderingSupport.h" 55 #include "public/platform/WebThread.h" 56 #include "web/IndexedDBClientImpl.h" 57 #include "web/WebMediaPlayerClientImpl.h" 58 #include "wtf/Assertions.h" 59 #include "wtf/CryptographicallyRandomNumber.h" 60 #include "wtf/MainThread.h" 61 #include "wtf/WTF.h" 62 #include "wtf/text/AtomicString.h" 63 #include "wtf/text/TextEncoding.h" 64 #include <v8.h> 65 66 namespace blink { 67 68 namespace { 69 70 class EndOfTaskRunner : public WebThread::TaskObserver { 71 public: 72 virtual void willProcessTask() OVERRIDE 73 { 74 WebCore::AnimationClock::notifyTaskStart(); 75 } 76 virtual void didProcessTask() OVERRIDE 77 { 78 WebCore::Microtask::performCheckpoint(); 79 WebCore::V8GCController::reportDOMMemoryUsageToV8(mainThreadIsolate()); 80 } 81 }; 82 83 } // namespace 84 85 static WebThread::TaskObserver* s_endOfTaskRunner = 0; 86 static WebThread::TaskObserver* s_pendingGCRunner = 0; 87 static WebCore::ThreadState::Interruptor* s_messageLoopInterruptor = 0; 88 static WebCore::ThreadState::Interruptor* s_isolateInterruptor = 0; 89 90 // Make sure we are not re-initialized in the same address space. 91 // Doing so may cause hard to reproduce crashes. 92 static bool s_webKitInitialized = false; 93 94 static bool generateEntropy(unsigned char* buffer, size_t length) 95 { 96 if (Platform::current()) { 97 Platform::current()->cryptographicallyRandomValues(buffer, length); 98 return true; 99 } 100 return false; 101 } 102 103 void initialize(Platform* platform) 104 { 105 initializeWithoutV8(platform); 106 107 v8::V8::InitializePlatform(gin::V8Platform::Get()); 108 v8::Isolate* isolate = v8::Isolate::New(); 109 isolate->Enter(); 110 WebCore::V8Initializer::initializeMainThreadIfNeeded(isolate); 111 v8::V8::SetEntropySource(&generateEntropy); 112 v8::V8::SetArrayBufferAllocator(WebCore::v8ArrayBufferAllocator()); 113 v8::V8::Initialize(); 114 WebCore::V8PerIsolateData::ensureInitialized(isolate); 115 116 s_isolateInterruptor = new WebCore::V8IsolateInterruptor(v8::Isolate::GetCurrent()); 117 WebCore::ThreadState::current()->addInterruptor(s_isolateInterruptor); 118 119 // currentThread will always be non-null in production, but can be null in Chromium unit tests. 120 if (WebThread* currentThread = platform->currentThread()) { 121 ASSERT(!s_endOfTaskRunner); 122 s_endOfTaskRunner = new EndOfTaskRunner; 123 currentThread->addTaskObserver(s_endOfTaskRunner); 124 } 125 } 126 127 v8::Isolate* mainThreadIsolate() 128 { 129 return WebCore::V8PerIsolateData::mainThreadIsolate(); 130 } 131 132 static double currentTimeFunction() 133 { 134 return Platform::current()->currentTime(); 135 } 136 137 static double monotonicallyIncreasingTimeFunction() 138 { 139 return Platform::current()->monotonicallyIncreasingTime(); 140 } 141 142 static void cryptographicallyRandomValues(unsigned char* buffer, size_t length) 143 { 144 Platform::current()->cryptographicallyRandomValues(buffer, length); 145 } 146 147 static void callOnMainThreadFunction(WTF::MainThreadFunction function, void* context) 148 { 149 Platform::current()->callOnMainThread(function, context); 150 } 151 152 void initializeWithoutV8(Platform* platform) 153 { 154 ASSERT(!s_webKitInitialized); 155 s_webKitInitialized = true; 156 157 ASSERT(platform); 158 Platform::initialize(platform); 159 160 WTF::setRandomSource(cryptographicallyRandomValues); 161 WTF::initialize(currentTimeFunction, monotonicallyIncreasingTimeFunction); 162 WTF::initializeMainThread(callOnMainThreadFunction); 163 WebCore::Heap::init(); 164 165 WebCore::ThreadState::attachMainThread(); 166 // currentThread will always be non-null in production, but can be null in Chromium unit tests. 167 if (WebThread* currentThread = platform->currentThread()) { 168 ASSERT(!s_pendingGCRunner); 169 s_pendingGCRunner = new WebCore::PendingGCRunner; 170 currentThread->addTaskObserver(s_pendingGCRunner); 171 172 ASSERT(!s_messageLoopInterruptor); 173 s_messageLoopInterruptor = new WebCore::MessageLoopInterruptor(currentThread); 174 WebCore::ThreadState::current()->addInterruptor(s_messageLoopInterruptor); 175 } 176 177 DEFINE_STATIC_LOCAL(WebCore::ModulesInitializer, initializer, ()); 178 initializer.init(); 179 180 // There are some code paths (for example, running WebKit in the browser 181 // process and calling into LocalStorage before anything else) where the 182 // UTF8 string encoding tables are used on a background thread before 183 // they're set up. This is a problem because their set up routines assert 184 // they're running on the main WebKitThread. It might be possible to make 185 // the initialization thread-safe, but given that so many code paths use 186 // this, initializing this lazily probably doesn't buy us much. 187 WTF::UTF8Encoding(); 188 189 WebCore::setIndexedDBClientCreateFunction(blink::IndexedDBClientImpl::create); 190 191 WebCore::MediaPlayer::setMediaEngineCreateFunction(blink::WebMediaPlayerClientImpl::create); 192 } 193 194 void shutdown() 195 { 196 // currentThread will always be non-null in production, but can be null in Chromium unit tests. 197 if (Platform::current()->currentThread()) { 198 ASSERT(s_endOfTaskRunner); 199 Platform::current()->currentThread()->removeTaskObserver(s_endOfTaskRunner); 200 delete s_endOfTaskRunner; 201 s_endOfTaskRunner = 0; 202 } 203 204 ASSERT(s_isolateInterruptor); 205 WebCore::ThreadState::current()->removeInterruptor(s_isolateInterruptor); 206 207 // currentThread will always be non-null in production, but can be null in Chromium unit tests. 208 if (Platform::current()->currentThread()) { 209 ASSERT(s_pendingGCRunner); 210 delete s_pendingGCRunner; 211 s_pendingGCRunner = 0; 212 213 ASSERT(s_messageLoopInterruptor); 214 WebCore::ThreadState::current()->removeInterruptor(s_messageLoopInterruptor); 215 delete s_messageLoopInterruptor; 216 s_messageLoopInterruptor = 0; 217 } 218 219 // Detach the main thread before starting the shutdown sequence 220 // so that the main thread won't get involved in a GC during the shutdown. 221 WebCore::ThreadState::detachMainThread(); 222 223 v8::Isolate* isolate = WebCore::V8PerIsolateData::mainThreadIsolate(); 224 WebCore::V8PerIsolateData::dispose(isolate); 225 isolate->Exit(); 226 isolate->Dispose(); 227 228 shutdownWithoutV8(); 229 } 230 231 void shutdownWithoutV8() 232 { 233 ASSERT(!s_endOfTaskRunner); 234 WebCore::shutdown(); 235 WebCore::Heap::shutdown(); 236 WTF::shutdown(); 237 Platform::shutdown(); 238 WebPrerenderingSupport::shutdown(); 239 } 240 241 void setLayoutTestMode(bool value) 242 { 243 WebCore::setIsRunningLayoutTest(value); 244 } 245 246 bool layoutTestMode() 247 { 248 return WebCore::isRunningLayoutTest(); 249 } 250 251 void setFontAntialiasingEnabledForTest(bool value) 252 { 253 WebCore::setFontAntialiasingEnabledForTest(value); 254 } 255 256 bool fontAntialiasingEnabledForTest() 257 { 258 return WebCore::isFontAntialiasingEnabledForTest(); 259 } 260 261 void enableLogChannel(const char* name) 262 { 263 #if !LOG_DISABLED 264 WTFLogChannel* channel = WebCore::getChannelFromName(name); 265 if (channel) 266 channel->state = WTFLogChannelOn; 267 #endif // !LOG_DISABLED 268 } 269 270 void resetPluginCache(bool reloadPages) 271 { 272 WebCore::Page::refreshPlugins(reloadPages); 273 } 274 275 } // namespace blink 276