void ThreadPoolWorker::run() { // This is hokey in the extreme. To compute the stack limit, // subtract the size of the stack from the address of a local // variable and give a 2k buffer. Is there a better way? uintptr_t stackLimitOffset = WORKER_THREAD_STACK_SIZE - 2*1024; uintptr_t stackLimit = (((uintptr_t)&stackLimitOffset) + stackLimitOffset * JS_STACK_GROWTH_DIRECTION); AutoLockMonitor lock(*this); JS_ASSERT(state_ == ACTIVE); for (;;) { while (!worklist_.empty()) { TaskExecutor *task = worklist_.popCopy(); { AutoUnlockMonitor unlock(*this); task->executeFromWorker(workerId_, stackLimit); } } if (state_ == TERMINATING) break; lock.wait(); } JS_ASSERT(worklist_.empty()); state_ = TERMINATED; lock.notify(); }
/* * In the pathological cases that dominate much of the test case runtime, * rooting analysis spends tons of time scanning the stack during a tight-ish * loop. Since statically, everything is either rooted or it isn't, these scans * are almost certain to be worthless. Detect these cases by checking whether * the addresses of the top several rooters in the stack are recurring. Note * that there may be more than one CheckRoots call within the loop, so we may * alternate between a couple of stacks rather than just repeating the same one * over and over, so we need more than a depth-1 memory. */ static bool SuppressCheckRoots(js::Vector<Rooter, 0, SystemAllocPolicy> &rooters) { static const unsigned int NumStackMemories = 6; static const size_t StackCheckDepth = 10; static uint32_t stacks[NumStackMemories]; static unsigned int numMemories = 0; static unsigned int oldestMemory = 0; // Ugh. Sort the rooters. This should really be an O(n) rank selection // followed by a sort. Interestingly, however, the overall scan goes a bit // *faster* with this sort. Better branch prediction of the later // partitioning pass, perhaps. qsort(rooters.begin(), rooters.length(), sizeof(Rooter), CompareRooters); // Forward-declare a variable so its address can be used to mark the // current top of the stack. unsigned int pos; // Compute the hash of the current stack. uint32_t hash = HashGeneric(&pos); for (unsigned int i = 0; i < Min(StackCheckDepth, rooters.length()); i++) hash = AddToHash(hash, rooters[rooters.length() - i - 1].rooter); // Scan through the remembered stacks to find the current stack. for (pos = 0; pos < numMemories; pos++) { if (stacks[pos] == hash) { // Skip this check. Technically, it is incorrect to not update the // LRU queue position, but it'll cost us at most one extra check // for every time a hot stack falls out of the window. return true; } } // Replace the oldest remembered stack with our current stack. stacks[oldestMemory] = hash; oldestMemory = (oldestMemory + 1) % NumStackMemories; if (numMemories < NumStackMemories) numMemories++; return false; }
bool ThreadPoolWorker::submit(TaskExecutor *task) { AutoLockMonitor lock(*this); JS_ASSERT(state_ == ACTIVE); if (!worklist_.append(task)) return false; lock.notify(); return true; }
static void GatherRooters(js::Vector<Rooter, 0, SystemAllocPolicy> &rooters, Rooted<void*> **thingGCRooters, unsigned thingRootKind) { Rooted<void*> *rooter = thingGCRooters[thingRootKind]; while (rooter) { Rooter r = { rooter, ThingRootKind(thingRootKind) }; JS_ALWAYS_TRUE(rooters.append(r)); rooter = rooter->previous(); } }