LeaseHolder::LeaseHolder(const Func* func, TransKind kind, bool isWorker) : m_func{RuntimeOption::EvalJitConcurrently > 0 ? func : nullptr} { assertx(func || RuntimeOption::EvalJitConcurrently == 0); auto const level = m_func ? lockLevel(kind) : LockLevel::Global; if (level == LockLevel::Func && !threadCanAcquireConcurrent) return; if (level == LockLevel::Global && !s_globalLease.amOwner()) { auto const blocking = RuntimeOption::EvalJitRequireWriteLease && RuntimeOption::EvalJitConcurrently == 0; if (!(m_acquiredGlobal = s_globalLease.acquire(blocking))) return; } SCOPE_EXIT { if (m_level == LockLevel::None) dropLocks(); }; if (level == LockLevel::Kind && !acquireKind(kind)) return; if (m_func) { auto const funcId = m_func->getFuncId(); s_funcOwners.ensureSize(funcId + 1); auto& owner = s_funcOwners[funcId]; auto oldOwner = owner.load(std::memory_order_relaxed); auto const self = Treadmill::threadIdx(); if (oldOwner == self) { // We already have the lock on this Func. } else if (oldOwner != Treadmill::kInvalidThreadIdx) { // Already owned by another thread. return; } else { // Unowned. Try to grab it. Only non-worker threads with LockLevel::Func // count towards the Eval.JitThreads limit. if (!isWorker && level == LockLevel::Func) { auto threads = s_jittingThreads.load(std::memory_order_relaxed); if (threads >= RuntimeOption::EvalJitThreads) return; threads = s_jittingThreads.fetch_add(1, std::memory_order_relaxed); m_acquiredThread = true; if (threads >= RuntimeOption::EvalJitThreads) return; } assertx(oldOwner == Treadmill::kInvalidThreadIdx); if (!owner.compare_exchange_strong(oldOwner, self, std::memory_order_acq_rel)) { return; } m_acquiredFunc = true; } } // If we made it this far, we acquired all the locks we need to translate. m_level = level; }
LeaseHolder::LeaseHolder(Lease& l, const Func* func, TransKind kind) : m_lease(l) , m_func{RuntimeOption::EvalJitConcurrently > 0 ? func : nullptr} { auto const need_global = m_func == nullptr || NeedGlobal(kind); if (!need_global && !threadCanAcquireConcurrent) return; if (need_global && !m_lease.amOwner()) { auto const blocking = RuntimeOption::EvalJitRequireWriteLease && RuntimeOption::EvalJitConcurrently == 0; if (!(m_acquired = m_lease.acquire(blocking))) return; } SCOPE_EXIT { if (!m_canTranslate) dropLocks(); }; if (m_func) { auto const funcId = m_func->getFuncId(); s_funcOwners.ensureSize(funcId + 1); auto& owner = s_funcOwners[funcId]; auto oldOwner = owner.load(std::memory_order_acquire); auto const self = Treadmill::threadIdx(); if (oldOwner == self) { // We already have the lock on this Func. } else if (oldOwner != Treadmill::kInvalidThreadIdx) { // Already owned by another thread. return; } else { // Unowned. Try to grab it. Threads with the global write lease don't // count towards Eval.JitThreads. if (!need_global) { auto threads = s_jittingThreads.load(std::memory_order_relaxed); if (threads >= RuntimeOption::EvalJitThreads) return; threads = s_jittingThreads.fetch_add(1, std::memory_order_relaxed); m_acquiredThread = true; if (threads >= RuntimeOption::EvalJitThreads) return; } if (!owner.compare_exchange_strong(oldOwner, self, std::memory_order_relaxed)) { return; } m_acquiredFunc = true; } } // If we made it this far, we acquired all the locks we need to translate. m_canTranslate = true; }
JSValuePtr UserObjectImp::callAsFunction(ExecState *exec, JSObject *thisObj, const ArgList &args) { JSValuePtr result = jsUndefined(); JSUserObject* jsThisObj = KJSValueToJSObject(thisObj, exec); if (jsThisObj) { CFIndex argCount = args.size(); CFArrayCallBacks arrayCallBacks; JSTypeGetCFArrayCallBacks(&arrayCallBacks); CFMutableArrayRef jsArgs = CFArrayCreateMutable(0, 0, &arrayCallBacks); if (jsArgs) { for (CFIndex i = 0; i < argCount; i++) { JSUserObject* jsArg = KJSValueToJSObject(args.at(exec, i), exec); CFArrayAppendValue(jsArgs, (void*)jsArg); jsArg->Release(); } } JSUserObject* jsResult; { // scope JSLock::DropAllLocks dropLocks(exec); // getCallData should have guarded against a NULL fJSUserObject. assert(fJSUserObject); jsResult = fJSUserObject->CallFunction(jsThisObj, jsArgs); } if (jsResult) { result = JSObjectKJSValue(jsResult); jsResult->Release(); } ReleaseCFType(jsArgs); jsThisObj->Release(); } return result; }
LeaseHolder::~LeaseHolder() { dropLocks(); }