/* * Copyright (C) 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef APIShims_h #define APIShims_h #include "CallFrame.h" #include "GCActivityCallback.h" #include "IncrementalSweeper.h" #include "JSLock.h" #include namespace JSC { class APIEntryShimWithoutLock { protected: APIEntryShimWithoutLock(VM* vm, bool registerThread) : m_vm(vm) , m_entryIdentifierTable(wtfThreadData().setCurrentIdentifierTable(vm->identifierTable)) { if (registerThread) vm->heap.machineThreads().addCurrentThread(); } ~APIEntryShimWithoutLock() { wtfThreadData().setCurrentIdentifierTable(m_entryIdentifierTable); } protected: RefPtr m_vm; IdentifierTable* m_entryIdentifierTable; }; class APIEntryShim : public APIEntryShimWithoutLock { public: // Normal API entry APIEntryShim(ExecState* exec, bool registerThread = true) : APIEntryShimWithoutLock(&exec->vm(), registerThread) , m_lockHolder(exec->vm().exclusiveThread ? 0 : exec) { } // JSPropertyNameAccumulator only has a vm. APIEntryShim(VM* vm, bool registerThread = true) : APIEntryShimWithoutLock(vm, registerThread) , m_lockHolder(vm->exclusiveThread ? 0 : vm) { } ~APIEntryShim() { // Destroying our JSLockHolder should also destroy the VM. m_vm.clear(); } private: JSLockHolder m_lockHolder; }; class APICallbackShim { public: APICallbackShim(ExecState* exec) : m_dropAllLocks(shouldDropAllLocks(exec->vm()) ? exec : nullptr) , m_vm(&exec->vm()) { wtfThreadData().resetCurrentIdentifierTable(); } APICallbackShim(VM& vm) : m_dropAllLocks(shouldDropAllLocks(vm) ? &vm : nullptr) , m_vm(&vm) { wtfThreadData().resetCurrentIdentifierTable(); } ~APICallbackShim() { wtfThreadData().setCurrentIdentifierTable(m_vm->identifierTable); } private: static bool shouldDropAllLocks(VM& vm) { if (vm.exclusiveThread) return false; // If the VM is in the middle of being destroyed then we don't want to resurrect it // by allowing DropAllLocks to ref it. By this point the APILock has already been // released anyways, so it doesn't matter that DropAllLocks is a no-op. if (!vm.refCount()) return false; return true; } JSLock::DropAllLocks m_dropAllLocks; VM* m_vm; }; } #endif