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 48 using namespace JSC; 49 50 namespace WebCore { 51 52 WorkerScriptController::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 61 WorkerScriptController::~WorkerScriptController() 62 { 63 m_workerContextWrapper.clear(); // Unprotect the global object. 64 m_globalData->clearBuiltinStructures(); 65 m_globalData->heap.destroy(); 66 } 67 68 void WorkerScriptController::initScript() 69 { 70 ASSERT(!m_workerContextWrapper); 71 72 JSLock lock(SilenceAssertionsOnly); 73 74 // Explicitly protect the global object's prototype so it isn't collected 75 // when we allocate the global object. (Once the global object is fully 76 // constructed, it can mark its own prototype.) 77 Structure* workerContextPrototypeStructure = JSWorkerContextPrototype::createStructure(*m_globalData, jsNull()); 78 Strong<JSWorkerContextPrototype> workerContextPrototype(*m_globalData, new (m_globalData.get()) JSWorkerContextPrototype(*m_globalData, 0, workerContextPrototypeStructure)); 79 80 if (m_workerContext->isDedicatedWorkerContext()) { 81 Structure* dedicatedContextPrototypeStructure = JSDedicatedWorkerContextPrototype::createStructure(*m_globalData, workerContextPrototype.get()); 82 Strong<JSDedicatedWorkerContextPrototype> dedicatedContextPrototype(*m_globalData, new (m_globalData.get()) JSDedicatedWorkerContextPrototype(*m_globalData, 0, dedicatedContextPrototypeStructure)); 83 Structure* structure = JSDedicatedWorkerContext::createStructure(*m_globalData, dedicatedContextPrototype.get()); 84 85 m_workerContextWrapper.set(*m_globalData, new (m_globalData.get()) JSDedicatedWorkerContext(*m_globalData, structure, m_workerContext->toDedicatedWorkerContext())); 86 workerContextPrototype->putAnonymousValue(*m_globalData, 0, m_workerContextWrapper.get()); 87 dedicatedContextPrototype->putAnonymousValue(*m_globalData, 0, m_workerContextWrapper.get()); 88 #if ENABLE(SHARED_WORKERS) 89 } else { 90 ASSERT(m_workerContext->isSharedWorkerContext()); 91 Structure* sharedContextPrototypeStructure = JSSharedWorkerContextPrototype::createStructure(*m_globalData, workerContextPrototype.get()); 92 Strong<JSSharedWorkerContextPrototype> sharedContextPrototype(*m_globalData, new (m_globalData.get()) JSSharedWorkerContextPrototype(*m_globalData, 0, sharedContextPrototypeStructure)); 93 Structure* structure = JSSharedWorkerContext::createStructure(*m_globalData, sharedContextPrototype.get()); 94 95 m_workerContextWrapper.set(*m_globalData, new (m_globalData.get()) JSSharedWorkerContext(*m_globalData, structure, m_workerContext->toSharedWorkerContext())); 96 workerContextPrototype->putAnonymousValue(*m_globalData, 0, m_workerContextWrapper.get()); 97 sharedContextPrototype->putAnonymousValue(*m_globalData, 0, m_workerContextWrapper.get()); 98 #endif 99 } 100 } 101 102 ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode) 103 { 104 if (isExecutionForbidden()) 105 return ScriptValue(); 106 107 ScriptValue exception; 108 ScriptValue result(evaluate(sourceCode, &exception)); 109 if (exception.jsValue()) { 110 JSLock lock(SilenceAssertionsOnly); 111 reportException(m_workerContextWrapper->globalExec(), exception.jsValue()); 112 } 113 return result; 114 } 115 116 ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, ScriptValue* exception) 117 { 118 if (isExecutionForbidden()) 119 return ScriptValue(); 120 121 initScriptIfNeeded(); 122 JSLock lock(SilenceAssertionsOnly); 123 124 ExecState* exec = m_workerContextWrapper->globalExec(); 125 m_workerContextWrapper->globalData().timeoutChecker.start(); 126 Completion comp = JSC::evaluate(exec, exec->dynamicGlobalObject()->globalScopeChain(), sourceCode.jsSourceCode(), m_workerContextWrapper.get()); 127 m_workerContextWrapper->globalData().timeoutChecker.stop(); 128 129 130 ComplType completionType = comp.complType(); 131 132 if (completionType == Terminated || m_workerContextWrapper->globalData().terminator.shouldTerminate()) { 133 forbidExecution(); 134 return ScriptValue(); 135 } 136 137 if (completionType == Normal || completionType == ReturnValue) 138 return ScriptValue(*m_globalData, comp.value()); 139 140 if (completionType == Throw) { 141 String errorMessage; 142 int lineNumber = 0; 143 String sourceURL = sourceCode.url().string(); 144 if (m_workerContext->sanitizeScriptError(errorMessage, lineNumber, sourceURL)) 145 *exception = ScriptValue(*m_globalData, throwError(exec, createError(exec, errorMessage.impl()))); 146 else 147 *exception = ScriptValue(*m_globalData, comp.value()); 148 } 149 return ScriptValue(); 150 } 151 152 void WorkerScriptController::setException(ScriptValue exception) 153 { 154 throwError(m_workerContextWrapper->globalExec(), exception.jsValue()); 155 } 156 157 void WorkerScriptController::scheduleExecutionTermination() 158 { 159 m_globalData->terminator.terminateSoon(); 160 } 161 162 void WorkerScriptController::forbidExecution() 163 { 164 ASSERT(m_workerContext->isContextThread()); 165 m_executionForbidden = true; 166 } 167 168 bool WorkerScriptController::isExecutionForbidden() const 169 { 170 ASSERT(m_workerContext->isContextThread()); 171 return m_executionForbidden; 172 } 173 174 } // namespace WebCore 175 176 #endif // ENABLE(WORKERS) 177