1 /* 2 * Copyright (C) 2008 Apple 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 COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 */ 26 27 #include "config.h" 28 29 #if ENABLE(WORKERS) 30 31 #include "WorkerScriptController.h" 32 33 #include "JSDOMBinding.h" 34 #include "JSDedicatedWorkerContext.h" 35 #include "JSSharedWorkerContext.h" 36 #include "ScriptSourceCode.h" 37 #include "ScriptValue.h" 38 #include "WorkerContext.h" 39 #include "WorkerObjectProxy.h" 40 #include "WorkerThread.h" 41 #include <interpreter/Interpreter.h> 42 #include <runtime/Completion.h> 43 #include <runtime/Completion.h> 44 #include <runtime/JSLock.h> 45 46 using namespace JSC; 47 48 namespace WebCore { 49 50 WorkerScriptController::WorkerScriptController(WorkerContext* workerContext) 51 : m_globalData(JSGlobalData::create()) 52 , m_workerContext(workerContext) 53 , m_executionForbidden(false) 54 { 55 m_globalData->clientData = new WebCoreJSClientData(m_globalData.get()); 56 } 57 58 WorkerScriptController::~WorkerScriptController() 59 { 60 m_workerContextWrapper = 0; // Unprotect the global object. 61 m_globalData->heap.destroy(); 62 } 63 64 void WorkerScriptController::initScript() 65 { 66 ASSERT(!m_workerContextWrapper); 67 68 JSLock lock(SilenceAssertionsOnly); 69 70 // Explicitly protect the global object's prototype so it isn't collected 71 // when we allocate the global object. (Once the global object is fully 72 // constructed, it can mark its own prototype.) 73 RefPtr<Structure> workerContextPrototypeStructure = JSWorkerContextPrototype::createStructure(jsNull()); 74 ProtectedPtr<JSWorkerContextPrototype> workerContextPrototype = new (m_globalData.get()) JSWorkerContextPrototype(workerContextPrototypeStructure.release()); 75 76 if (m_workerContext->isDedicatedWorkerContext()) { 77 RefPtr<Structure> dedicatedContextPrototypeStructure = JSDedicatedWorkerContextPrototype::createStructure(workerContextPrototype); 78 ProtectedPtr<JSDedicatedWorkerContextPrototype> dedicatedContextPrototype = new (m_globalData.get()) JSDedicatedWorkerContextPrototype(dedicatedContextPrototypeStructure.release()); 79 RefPtr<Structure> structure = JSDedicatedWorkerContext::createStructure(dedicatedContextPrototype); 80 81 m_workerContextWrapper = new (m_globalData.get()) JSDedicatedWorkerContext(structure.release(), m_workerContext->toDedicatedWorkerContext()); 82 #if ENABLE(SHARED_WORKERS) 83 } else { 84 ASSERT(m_workerContext->isSharedWorkerContext()); 85 RefPtr<Structure> sharedContextPrototypeStructure = JSSharedWorkerContextPrototype::createStructure(workerContextPrototype); 86 ProtectedPtr<JSSharedWorkerContextPrototype> sharedContextPrototype = new (m_globalData.get()) JSSharedWorkerContextPrototype(sharedContextPrototypeStructure.release()); 87 RefPtr<Structure> structure = JSSharedWorkerContext::createStructure(sharedContextPrototype); 88 89 m_workerContextWrapper = new (m_globalData.get()) JSSharedWorkerContext(structure.release(), m_workerContext->toSharedWorkerContext()); 90 #endif 91 } 92 } 93 94 ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode) 95 { 96 { 97 MutexLocker lock(m_sharedDataMutex); 98 if (m_executionForbidden) 99 return JSValue(); 100 } 101 ScriptValue exception; 102 ScriptValue result = evaluate(sourceCode, &exception); 103 if (exception.jsValue()) { 104 JSLock lock(SilenceAssertionsOnly); 105 reportException(m_workerContextWrapper->globalExec(), exception.jsValue()); 106 } 107 return result; 108 } 109 110 ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, ScriptValue* exception) 111 { 112 { 113 MutexLocker lock(m_sharedDataMutex); 114 if (m_executionForbidden) 115 return JSValue(); 116 } 117 118 initScriptIfNeeded(); 119 JSLock lock(SilenceAssertionsOnly); 120 121 ExecState* exec = m_workerContextWrapper->globalExec(); 122 m_workerContextWrapper->globalData()->timeoutChecker.start(); 123 Completion comp = JSC::evaluate(exec, exec->dynamicGlobalObject()->globalScopeChain(), sourceCode.jsSourceCode(), m_workerContextWrapper); 124 m_workerContextWrapper->globalData()->timeoutChecker.stop(); 125 126 if (comp.complType() == Normal || comp.complType() == ReturnValue) 127 return comp.value(); 128 129 if (comp.complType() == Throw) 130 *exception = comp.value(); 131 return JSValue(); 132 } 133 134 void WorkerScriptController::setException(ScriptValue exception) 135 { 136 m_workerContextWrapper->globalExec()->setException(exception.jsValue()); 137 } 138 139 void WorkerScriptController::forbidExecution() 140 { 141 // This function is called from another thread. 142 // Mutex protection for m_executionForbidden is needed to guarantee that the value is synchronized between processors, because 143 // if it were not, the worker could re-enter JSC::evaluate(), but with timeout already reset. 144 // It is not critical for Interpreter::m_timeoutTime to be synchronized, we just rely on it reaching the worker thread's processor sooner or later. 145 MutexLocker lock(m_sharedDataMutex); 146 m_executionForbidden = true; 147 m_globalData->timeoutChecker.setTimeoutInterval(1); // 1ms is the smallest timeout that can be set. 148 } 149 150 } // namespace WebCore 151 152 #endif // ENABLE(WORKERS) 153