1/* 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. 3 * Copyright (C) 2011, 2012 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 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 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#include "WorkerScriptController.h" 30 31#include "JSDOMBinding.h" 32#include "JSDedicatedWorkerGlobalScope.h" 33#include "ScriptSourceCode.h" 34#include "WebCoreJSClientData.h" 35#include "WorkerGlobalScope.h" 36#include "WorkerObjectProxy.h" 37#include "WorkerScriptDebugServer.h" 38#include "WorkerThread.h" 39#include <bindings/ScriptValue.h> 40#include <heap/StrongInlines.h> 41#include <interpreter/Interpreter.h> 42#include <runtime/Completion.h> 43#include <runtime/ExceptionHelpers.h> 44#include <runtime/Error.h> 45#include <runtime/JSLock.h> 46 47#if ENABLE(SHARED_WORKERS) 48#include "JSSharedWorkerGlobalScope.h" 49#endif 50 51using namespace JSC; 52 53namespace WebCore { 54 55WorkerScriptController::WorkerScriptController(WorkerGlobalScope* workerGlobalScope) 56 : m_vm(VM::create()) 57 , m_workerGlobalScope(workerGlobalScope) 58 , m_workerGlobalScopeWrapper(*m_vm) 59 , m_executionForbidden(false) 60{ 61 initNormalWorldClientData(m_vm.get()); 62} 63 64WorkerScriptController::~WorkerScriptController() 65{ 66 JSLockHolder lock(vm()); 67 m_workerGlobalScopeWrapper.clear(); 68 m_vm.clear(); 69} 70 71void WorkerScriptController::initScript() 72{ 73 ASSERT(!m_workerGlobalScopeWrapper); 74 75 JSLockHolder lock(m_vm.get()); 76 77 // Explicitly protect the global object's prototype so it isn't collected 78 // when we allocate the global object. (Once the global object is fully 79 // constructed, it can mark its own prototype.) 80 Structure* workerGlobalScopePrototypeStructure = JSWorkerGlobalScopePrototype::createStructure(*m_vm, 0, jsNull()); 81 Strong<JSWorkerGlobalScopePrototype> workerGlobalScopePrototype(*m_vm, JSWorkerGlobalScopePrototype::create(*m_vm, 0, workerGlobalScopePrototypeStructure)); 82 83 if (m_workerGlobalScope->isDedicatedWorkerGlobalScope()) { 84 Structure* dedicatedContextPrototypeStructure = JSDedicatedWorkerGlobalScopePrototype::createStructure(*m_vm, 0, workerGlobalScopePrototype.get()); 85 Strong<JSDedicatedWorkerGlobalScopePrototype> dedicatedContextPrototype(*m_vm, JSDedicatedWorkerGlobalScopePrototype::create(*m_vm, 0, dedicatedContextPrototypeStructure)); 86 Structure* structure = JSDedicatedWorkerGlobalScope::createStructure(*m_vm, 0, dedicatedContextPrototype.get()); 87 88 m_workerGlobalScopeWrapper.set(*m_vm, JSDedicatedWorkerGlobalScope::create(*m_vm, structure, static_cast<DedicatedWorkerGlobalScope*>(m_workerGlobalScope))); 89 workerGlobalScopePrototypeStructure->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get()); 90 dedicatedContextPrototypeStructure->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get()); 91 ASSERT(structure->globalObject() == m_workerGlobalScopeWrapper); 92 ASSERT(m_workerGlobalScopeWrapper->structure()->globalObject() == m_workerGlobalScopeWrapper); 93 workerGlobalScopePrototype->structure()->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get()); 94 dedicatedContextPrototype->structure()->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get()); 95#if ENABLE(SHARED_WORKERS) 96 } else { 97 ASSERT(m_workerGlobalScope->isSharedWorkerGlobalScope()); 98 Structure* sharedContextPrototypeStructure = JSSharedWorkerGlobalScopePrototype::createStructure(*m_vm, 0, workerGlobalScopePrototype.get()); 99 Strong<JSSharedWorkerGlobalScopePrototype> sharedContextPrototype(*m_vm, JSSharedWorkerGlobalScopePrototype::create(*m_vm, 0, sharedContextPrototypeStructure)); 100 Structure* structure = JSSharedWorkerGlobalScope::createStructure(*m_vm, 0, sharedContextPrototype.get()); 101 102 m_workerGlobalScopeWrapper.set(*m_vm, JSSharedWorkerGlobalScope::create(*m_vm, structure, static_cast<SharedWorkerGlobalScope*>(m_workerGlobalScope))); 103 workerGlobalScopePrototype->structure()->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get()); 104 sharedContextPrototype->structure()->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get()); 105#endif 106 } 107 ASSERT(m_workerGlobalScopeWrapper->globalObject() == m_workerGlobalScopeWrapper); 108 ASSERT(asObject(m_workerGlobalScopeWrapper->prototype())->globalObject() == m_workerGlobalScopeWrapper); 109} 110 111void WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode) 112{ 113 if (isExecutionForbidden()) 114 return; 115 116 Deprecated::ScriptValue exception; 117 evaluate(sourceCode, &exception); 118 if (exception.jsValue()) { 119 JSLockHolder lock(vm()); 120 reportException(m_workerGlobalScopeWrapper->globalExec(), exception.jsValue()); 121 } 122} 123 124void WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, Deprecated::ScriptValue* exception) 125{ 126 if (isExecutionForbidden()) 127 return; 128 129 initScriptIfNeeded(); 130 131 ExecState* exec = m_workerGlobalScopeWrapper->globalExec(); 132 JSLockHolder lock(exec); 133 134 JSValue evaluationException; 135 JSC::evaluate(exec, sourceCode.jsSourceCode(), m_workerGlobalScopeWrapper->globalThis(), &evaluationException); 136 137 VM& vm = exec->vm(); 138 if ((evaluationException && isTerminatedExecutionException(evaluationException)) 139 || (vm.watchdog && vm.watchdog->didFire())) { 140 forbidExecution(); 141 return; 142 } 143 144 if (evaluationException) { 145 String errorMessage; 146 int lineNumber = 0; 147 int columnNumber = 0; 148 String sourceURL = sourceCode.url().string(); 149 if (m_workerGlobalScope->sanitizeScriptError(errorMessage, lineNumber, columnNumber, sourceURL, sourceCode.cachedScript())) 150 *exception = Deprecated::ScriptValue(*m_vm, exec->vm().throwException(exec, createError(exec, errorMessage.impl()))); 151 else 152 *exception = Deprecated::ScriptValue(*m_vm, evaluationException); 153 } 154} 155 156void WorkerScriptController::setException(const Deprecated::ScriptValue& exception) 157{ 158 m_workerGlobalScopeWrapper->globalExec()->vm().throwException(m_workerGlobalScopeWrapper->globalExec(), exception.jsValue()); 159} 160 161void WorkerScriptController::scheduleExecutionTermination() 162{ 163 // The mutex provides a memory barrier to ensure that once 164 // termination is scheduled, isExecutionTerminating will 165 // accurately reflect that state when called from another thread. 166 MutexLocker locker(m_scheduledTerminationMutex); 167 if (m_vm->watchdog) 168 m_vm->watchdog->fire(); 169} 170 171bool WorkerScriptController::isExecutionTerminating() const 172{ 173 // See comments in scheduleExecutionTermination regarding mutex usage. 174 MutexLocker locker(m_scheduledTerminationMutex); 175 if (m_vm->watchdog) 176 return m_vm->watchdog->didFire(); 177 return false; 178} 179 180void WorkerScriptController::forbidExecution() 181{ 182 ASSERT(m_workerGlobalScope->isContextThread()); 183 m_executionForbidden = true; 184} 185 186bool WorkerScriptController::isExecutionForbidden() const 187{ 188 ASSERT(m_workerGlobalScope->isContextThread()); 189 return m_executionForbidden; 190} 191 192void WorkerScriptController::disableEval(const String& errorMessage) 193{ 194 initScriptIfNeeded(); 195 JSLockHolder lock(vm()); 196 197 m_workerGlobalScopeWrapper->setEvalEnabled(false, errorMessage); 198} 199 200void WorkerScriptController::attachDebugger(JSC::Debugger* debugger) 201{ 202 initScriptIfNeeded(); 203 debugger->attach(m_workerGlobalScopeWrapper->globalObject()); 204} 205 206void WorkerScriptController::detachDebugger(JSC::Debugger* debugger) 207{ 208 debugger->detach(m_workerGlobalScopeWrapper->globalObject(), JSC::Debugger::TerminatingDebuggingSession); 209} 210 211} // namespace WebCore 212