bool invalidateBailedOutScripts() { RootedScript script(cx_, fun_->toFunction()->nonLazyScript()); // Sometimes the script is collected or invalidated already, // for example when a full GC runs at an inconvenient time. if (!script->hasParallelIonScript()) { JS_ASSERT(hasNoPendingInvalidations()); return true; } IonScript *ion = script->parallelIonScript(); JS_ASSERT(pendingInvalidations.length() == ion->parallelInvalidatedScriptEntries()); Vector<types::RecompileInfo> invalid(cx_); for (uint32_t i = 0; i < pendingInvalidations.length(); i++) { JSScript *script = pendingInvalidations[i]; if (script && !hasScript(invalid, script)) { JS_ASSERT(script->hasParallelIonScript()); if (!invalid.append(script->parallelIonScript()->recompileInfo())) return false; ion->parallelInvalidatedScriptList()[i] = script; } pendingInvalidations[i] = NULL; } Invalidate(cx_, invalid); return true; }
inline bool hasNoPendingInvalidations() { for (uint32_t i = 0; i < pendingInvalidations.length(); i++) { if (pendingInvalidations[i] != NULL) return false; } return true; }
ExecutionStatus apply() { SpewBeginOp(cx_, "ParallelDo"); if (!ion::IsEnabled(cx_)) return SpewEndOp(disqualifyFromParallelExecution()); if (!pendingInvalidations.resize(ForkJoinSlices(cx_))) return SpewEndOp(ExecutionFatal); // Try to execute in parallel. If a bailout occurs, re-warmup // and then try again. Repeat this a few times. while (bailouts < MAX_BAILOUTS) { MethodStatus status = compileForParallelExecution(); if (status == Method_Error) return SpewEndOp(ExecutionFatal); if (status != Method_Compiled) return SpewEndOp(disqualifyFromParallelExecution()); ParallelResult result = js::ExecuteForkJoinOp(cx_, *this); switch (result) { case TP_RETRY_SEQUENTIALLY: Spew(SpewBailouts, "Bailout not categorized"); break; case TP_SUCCESS: return SpewEndOp(ExecutionParallel); case TP_FATAL: return SpewEndOp(ExecutionFatal); } bailouts += 1; SpewBailout(bailouts); if (!invalidateBailedOutScripts()) return SpewEndOp(ExecutionFatal); if (!warmupForParallelExecution()) return SpewEndOp(ExecutionFatal); } // After enough tries, just execute sequentially. return SpewEndOp(disqualifyFromParallelExecution()); }