WorkerScriptController.cpp revision 81bc750723a18f21cd17d1b173cd2a4dda9cea6e
1/* 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. 3 * Copyright (C) 2011 Google Inc. All Rights Reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 */ 27 28#include "config.h" 29 30#if ENABLE(WORKERS) 31 32#include "WorkerScriptController.h" 33 34#include "JSDedicatedWorkerContext.h" 35#include "JSSharedWorkerContext.h" 36#include "ScriptSourceCode.h" 37#include "ScriptValue.h" 38#include "WebCoreJSClientData.h" 39#include "WorkerContext.h" 40#include "WorkerObjectProxy.h" 41#include "WorkerThread.h" 42#include <interpreter/Interpreter.h> 43#include <runtime/Completion.h> 44#include <runtime/Completion.h> 45#include <runtime/Error.h> 46#include <runtime/JSLock.h> 47 48using namespace JSC; 49 50namespace WebCore { 51 52WorkerScriptController::WorkerScriptController(WorkerContext* workerContext) 53 : m_globalData(JSGlobalData::create(ThreadStackTypeSmall)) 54 , m_workerContext(workerContext) 55 , m_workerContextWrapper(*m_globalData) 56 , m_executionForbidden(false) 57{ 58 initNormalWorldClientData(m_globalData.get()); 59} 60 61WorkerScriptController::~WorkerScriptController() 62{ 63 m_workerContextWrapper.clear(); // Unprotect the global object. 64 m_globalData->heap.destroy(); 65} 66 67void WorkerScriptController::initScript() 68{ 69 ASSERT(!m_workerContextWrapper); 70 71 JSLock lock(SilenceAssertionsOnly); 72 73 // Explicitly protect the global object's prototype so it isn't collected 74 // when we allocate the global object. (Once the global object is fully 75 // constructed, it can mark its own prototype.) 76 RefPtr<Structure> workerContextPrototypeStructure = JSWorkerContextPrototype::createStructure(jsNull()); 77 Global<JSWorkerContextPrototype> workerContextPrototype(*m_globalData, new (m_globalData.get()) JSWorkerContextPrototype(0, workerContextPrototypeStructure.release())); 78 79 if (m_workerContext->isDedicatedWorkerContext()) { 80 RefPtr<Structure> dedicatedContextPrototypeStructure = JSDedicatedWorkerContextPrototype::createStructure(workerContextPrototype.get()); 81 Global<JSDedicatedWorkerContextPrototype> dedicatedContextPrototype(*m_globalData, new (m_globalData.get()) JSDedicatedWorkerContextPrototype(0, dedicatedContextPrototypeStructure.release())); 82 RefPtr<Structure> structure = JSDedicatedWorkerContext::createStructure(dedicatedContextPrototype.get()); 83 84 m_workerContextWrapper.set(*m_globalData, new (m_globalData.get()) JSDedicatedWorkerContext(structure.release(), m_workerContext->toDedicatedWorkerContext())); 85 workerContextPrototype->putAnonymousValue(*m_globalData, 0, m_workerContextWrapper.get()); 86 dedicatedContextPrototype->putAnonymousValue(*m_globalData, 0, m_workerContextWrapper.get()); 87#if ENABLE(SHARED_WORKERS) 88 } else { 89 ASSERT(m_workerContext->isSharedWorkerContext()); 90 RefPtr<Structure> sharedContextPrototypeStructure = JSSharedWorkerContextPrototype::createStructure(workerContextPrototype.get()); 91 Global<JSSharedWorkerContextPrototype> sharedContextPrototype(*m_globalData, new (m_globalData.get()) JSSharedWorkerContextPrototype(0, sharedContextPrototypeStructure.release())); 92 RefPtr<Structure> structure = JSSharedWorkerContext::createStructure(sharedContextPrototype.get()); 93 94 m_workerContextWrapper.set(*m_globalData, new (m_globalData.get()) JSSharedWorkerContext(structure.release(), m_workerContext->toSharedWorkerContext())); 95 workerContextPrototype->putAnonymousValue(*m_globalData, 0, m_workerContextWrapper.get()); 96 sharedContextPrototype->putAnonymousValue(*m_globalData, 0, m_workerContextWrapper.get()); 97#endif 98 } 99} 100 101ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode) 102{ 103 { 104 MutexLocker lock(m_sharedDataMutex); 105 if (m_executionForbidden) 106 return ScriptValue(); 107 } 108 ScriptValue exception; 109 ScriptValue result(evaluate(sourceCode, &exception)); 110 if (exception.jsValue()) { 111 JSLock lock(SilenceAssertionsOnly); 112 reportException(m_workerContextWrapper->globalExec(), exception.jsValue()); 113 } 114 return result; 115} 116 117ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, ScriptValue* exception) 118{ 119 { 120 MutexLocker lock(m_sharedDataMutex); 121 if (m_executionForbidden) 122 return ScriptValue(); 123 } 124 125 initScriptIfNeeded(); 126 JSLock lock(SilenceAssertionsOnly); 127 128 ExecState* exec = m_workerContextWrapper->globalExec(); 129 m_workerContextWrapper->globalData().timeoutChecker.start(); 130 Completion comp = JSC::evaluate(exec, exec->dynamicGlobalObject()->globalScopeChain(), sourceCode.jsSourceCode(), m_workerContextWrapper.get()); 131 m_workerContextWrapper->globalData().timeoutChecker.stop(); 132 133 if (comp.complType() == Normal || comp.complType() == ReturnValue) 134 return ScriptValue(*m_globalData, comp.value()); 135 136 if (comp.complType() == Throw) { 137 String errorMessage; 138 int lineNumber = 0; 139 String sourceURL = sourceCode.url().string(); 140 if (m_workerContext->sanitizeScriptError(errorMessage, lineNumber, sourceURL)) 141 *exception = ScriptValue(*m_globalData, throwError(exec, createError(exec, errorMessage.impl()))); 142 else 143 *exception = ScriptValue(*m_globalData, comp.value()); 144 } 145 return ScriptValue(); 146} 147 148void WorkerScriptController::setException(ScriptValue exception) 149{ 150 throwError(m_workerContextWrapper->globalExec(), exception.jsValue()); 151} 152 153void WorkerScriptController::forbidExecution(ForbidExecutionOption option) 154{ 155 // This function may be called from another thread. 156 // Mutex protection for m_executionForbidden is needed to guarantee that the value is synchronized between processors, because 157 // if it were not, the worker could re-enter JSC::evaluate(), but with timeout already reset. 158 // It is not critical for Terminator::m_shouldTerminate to be synchronized, we just rely on it reaching the worker thread's processor sooner or later. 159 MutexLocker lock(m_sharedDataMutex); 160 m_executionForbidden = true; 161 if (option == TerminateRunningScript) 162 m_globalData->terminator.terminateSoon(); 163} 164 165} // namespace WebCore 166 167#endif // ENABLE(WORKERS) 168