void SamplingProfiler::dispatchIfNecessary(const LockHolder& locker) { if (m_isActive && !m_hasDispatchedFunction && m_jscExecutionThread && m_vm.entryScope) { ref(); // Matching deref() is inside m_handler when m_handler stops recursing. dispatchFunction(locker); } }
void BatchingUIManager::measure(folly::dynamic&& args, facebook::xplat::module::CxxModule::Callback cb) { auto manager = shared_from_this(); dispatchFunction([manager, args, cb]() { static_cast<IUIManager*>(manager.get())->measure(jsArgAsInt(args, 0), cb); }); }
void BatchingUIManager::removeRootView(folly::dynamic&& args) { auto manager = std::static_pointer_cast<UIManager>(shared_from_this()); dispatchFunction([manager, args]() { manager->removeRootView(jsArgAsInt(args, 0)); }); }
void BatchingUIManager::replaceExistingNonRootView(folly::dynamic&& args) { auto manager = shared_from_this(); dispatchFunction([manager, args]() { static_cast<IUIManager*>(manager.get())->replaceExistingNonRootView(jsArgAsInt(args, 0), jsArgAsInt(args, 1)); }); }
void BatchingUIManager::removeSubviewsFromContainerWithID(folly::dynamic&& args) { auto manager = shared_from_this(); dispatchFunction([manager, args]() { static_cast<IUIManager*>(manager.get())->removeSubviewsFromContainerWithID(jsArgAsInt(args, 0)); }); }
void BatchingUIManager::createView(folly::dynamic&& args) { auto manager = shared_from_this(); dispatchFunction([manager, args]() { auto arg3 = jsArgAsDynamic(args, 3); static_cast<IUIManager*>(manager.get())->createView(jsArgAsInt(args, 0), jsArgAsString(args, 1), jsArgAsInt(args, 2), std::move(arg3)); }); }
void BatchingUIManager::configureNextLayoutAnimation(folly::dynamic&& args, facebook::xplat::module::CxxModule::Callback success, facebook::xplat::module::CxxModule::Callback error) { auto manager = shared_from_this(); dispatchFunction([manager, args, success, error]() { auto config = jsArgAsDynamic(args, 3); manager->configureNextLayoutAnimation(std::move(config), success, error); }); }
void BatchingUIManager::dispatchViewManagerCommand(folly::dynamic&& args) { auto manager = shared_from_this(); dispatchFunction([manager, args]() { auto arg2 = jsArgAsDynamic(args, 2); static_cast<IUIManager*>(manager.get())->dispatchViewManagerCommand(jsArgAsInt(args, 0), jsArgAsInt(args, 1), std::move(arg2)); }); }
void BatchingUIManager::setChildren(folly::dynamic&& args) { auto manager = shared_from_this(); dispatchFunction([manager, args]() { auto arg1 = jsArgAsArray(args, 1); static_cast<IUIManager*>(manager.get())->setChildren(jsArgAsInt(args, 0), std::move(arg1)); }); }
void BatchingUIManager::manageChildren(folly::dynamic&& args) { auto manager = shared_from_this(); dispatchFunction([manager, args]() { auto arg1 = jsArgAsDynamic(args, 1); auto arg2 = jsArgAsDynamic(args, 2); auto arg3 = jsArgAsDynamic(args, 3); auto arg4 = jsArgAsDynamic(args, 4); auto arg5 = jsArgAsDynamic(args, 5); static_cast<IUIManager*>(manager.get())->manageChildren(jsArgAsInt(args, 0), arg1, arg2, arg3, arg4, arg5); }); }
SamplingProfiler::SamplingProfiler(VM& vm, RefPtr<Stopwatch>&& stopwatch) : m_vm(vm) , m_stopwatch(WTFMove(stopwatch)) , m_indexOfNextStackTraceToVerify(0) , m_timingInterval(std::chrono::microseconds(1000)) , m_totalTime(0) , m_timerQueue(WorkQueue::create("jsc.sampling-profiler.queue", WorkQueue::Type::Serial, WorkQueue::QOS::UserInteractive)) , m_jscExecutionThread(nullptr) , m_isActive(false) , m_isPaused(false) , m_hasDispatchedFunction(false) { if (sReportStats) { sNumTotalWalks = 0; sNumFailedWalks = 0; } m_currentFrames.grow(256); m_handler = [this] () { LockHolder samplingProfilerLocker(m_lock); if (!m_isActive || !m_jscExecutionThread || m_isPaused) { m_hasDispatchedFunction = false; deref(); return; } if (m_vm.entryScope) { double nowTime = m_stopwatch->elapsedTime(); LockHolder machineThreadsLocker(m_vm.heap.machineThreads().getLock()); LockHolder codeBlockSetLocker(m_vm.heap.codeBlockSet().getLock()); LockHolder executableAllocatorLocker(m_vm.executableAllocator.getLock()); bool didSuspend = m_jscExecutionThread->suspend(); if (didSuspend) { // While the JSC thread is suspended, we can't do things like malloc because the JSC thread // may be holding the malloc lock. ExecState* callFrame; void* pc; { MachineThreads::Thread::Registers registers; m_jscExecutionThread->getRegisters(registers); callFrame = static_cast<ExecState*>(registers.framePointer()); pc = registers.instructionPointer(); m_jscExecutionThread->freeRegisters(registers); } // FIXME: Lets have a way of detecting when we're parsing code. // https://bugs.webkit.org/show_bug.cgi?id=152761 if (m_vm.executableAllocator.isValidExecutableMemory(executableAllocatorLocker, pc)) { if (m_vm.isExecutingInRegExpJIT) { // FIXME: We're executing a regexp. Lets gather more intersting data. // https://bugs.webkit.org/show_bug.cgi?id=152729 callFrame = m_vm.topCallFrame; // We need to do this or else we'd fail our backtrace validation b/c this isn't a JS frame. } } else if (LLInt::isLLIntPC(pc)) { // We're okay to take a normal stack trace when the PC // is in LLInt code. } else { // We resort to topCallFrame to see if we can get anything // useful. We usually get here when we're executing C code. callFrame = m_vm.topCallFrame; } size_t walkSize; bool wasValidWalk; bool didRunOutOfVectorSpace; bool stacktraceNeedsVerification; { FrameWalker walker(callFrame, m_vm, codeBlockSetLocker, machineThreadsLocker); walkSize = walker.walk(m_currentFrames, didRunOutOfVectorSpace, stacktraceNeedsVerification); wasValidWalk = walker.wasValidWalk(); } m_jscExecutionThread->resume(); // We can now use data structures that malloc, and do other interesting things, again. // FIXME: It'd be interesting to take data about the program's state when // we fail to take a stack trace: https://bugs.webkit.org/show_bug.cgi?id=152758 if (wasValidWalk && walkSize) { if (sReportStats) { sNumTotalStackTraces++; if (stacktraceNeedsVerification) sNumUnverifiedStackTraces++; } Vector<StackFrame> stackTrace; stackTrace.reserveInitialCapacity(walkSize); for (size_t i = 0; i < walkSize; i++) { StackFrame frame = m_currentFrames[i]; stackTrace.uncheckedAppend(frame); if (frame.frameType == FrameType::VerifiedExecutable) m_seenExecutables.add(frame.u.verifiedExecutable); } m_stackTraces.append(StackTrace{ stacktraceNeedsVerification, nowTime, WTFMove(stackTrace) }); if (didRunOutOfVectorSpace) m_currentFrames.grow(m_currentFrames.size() * 1.25); m_totalTime += nowTime - m_lastTime; } } } m_lastTime = m_stopwatch->elapsedTime(); dispatchFunction(samplingProfilerLocker); }; }