Home | History | Annotate | Download | only in js
      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