+2012-07-03 Mark Lam <mark.lam@apple.com>
+
+ Add ability to symbolically set and dump JSC VM options.
+ See comments in runtime/Options.h for details on how the options work.
+ https://bugs.webkit.org/show_bug.cgi?id=90420
+
+ Reviewed by Filip Pizlo.
+
+ * assembler/LinkBuffer.cpp:
+ (JSC::LinkBuffer::finalizeCodeWithDisassembly):
+ * assembler/LinkBuffer.h:
+ (JSC):
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::shouldOptimizeNow):
+ * bytecode/CodeBlock.h:
+ (JSC::CodeBlock::likelyToTakeSlowCase):
+ (JSC::CodeBlock::couldTakeSlowCase):
+ (JSC::CodeBlock::likelyToTakeSpecialFastCase):
+ (JSC::CodeBlock::likelyToTakeDeepestSlowCase):
+ (JSC::CodeBlock::likelyToTakeAnySlowCase):
+ (JSC::CodeBlock::jitAfterWarmUp):
+ (JSC::CodeBlock::jitSoon):
+ (JSC::CodeBlock::reoptimizationRetryCounter):
+ (JSC::CodeBlock::countReoptimization):
+ (JSC::CodeBlock::counterValueForOptimizeAfterWarmUp):
+ (JSC::CodeBlock::counterValueForOptimizeAfterLongWarmUp):
+ (JSC::CodeBlock::optimizeSoon):
+ (JSC::CodeBlock::exitCountThresholdForReoptimization):
+ (JSC::CodeBlock::exitCountThresholdForReoptimizationFromLoop):
+ * bytecode/ExecutionCounter.h:
+ (JSC::ExecutionCounter::clippedThreshold):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::handleInlining):
+ * dfg/DFGCapabilities.h:
+ (JSC::DFG::mightCompileEval):
+ (JSC::DFG::mightCompileProgram):
+ (JSC::DFG::mightCompileFunctionForCall):
+ (JSC::DFG::mightCompileFunctionForConstruct):
+ (JSC::DFG::mightInlineFunctionForCall):
+ (JSC::DFG::mightInlineFunctionForConstruct):
+ * dfg/DFGCommon.h:
+ (JSC::DFG::shouldShowDisassembly):
+ * dfg/DFGDriver.cpp:
+ (JSC::DFG::compile):
+ * dfg/DFGOSRExit.cpp:
+ (JSC::DFG::OSRExit::considerAddingAsFrequentExitSiteSlow):
+ * dfg/DFGVariableAccessData.h:
+ (JSC::DFG::VariableAccessData::shouldUseDoubleFormatAccordingToVote):
+ * heap/MarkStack.cpp:
+ (JSC::MarkStackSegmentAllocator::allocate):
+ (JSC::MarkStackSegmentAllocator::shrinkReserve):
+ (JSC::MarkStackArray::MarkStackArray):
+ (JSC::MarkStackThreadSharedData::MarkStackThreadSharedData):
+ (JSC::SlotVisitor::donateKnownParallel):
+ (JSC::SlotVisitor::drain):
+ (JSC::SlotVisitor::drainFromShared):
+ * heap/MarkStack.h:
+ (JSC::MarkStack::mergeOpaqueRootsIfProfitable):
+ (JSC::MarkStack::addOpaqueRoot):
+ * heap/SlotVisitor.h:
+ (JSC::SlotVisitor::donate):
+ * jit/JIT.cpp:
+ (JSC::JIT::emitOptimizationCheck):
+ * jsc.cpp:
+ (printUsageStatement):
+ (parseArguments):
+ * runtime/InitializeThreading.cpp:
+ (JSC::initializeThreadingOnce):
+ * runtime/JSGlobalData.cpp:
+ (JSC::enableAssembler):
+ * runtime/JSGlobalObject.cpp:
+ (JSC::JSGlobalObject::JSGlobalObject):
+ * runtime/Options.cpp:
+ (JSC):
+ (JSC::overrideOptionWithHeuristic):
+ (JSC::Options::initialize):
+ (JSC::Options::setOption):
+ (JSC::Options::dumpAllOptions):
+ (JSC::Options::dumpOption):
+ * runtime/Options.h:
+ (JSC):
+ (Options):
+ (EntryInfo):
+
2012-07-03 Jocelyn Turcotte <jocelyn.turcotte@nokia.com> Joel Dillon <joel.dillon@codethink.co.uk>
[Qt][Win] Fix broken QtWebKit5.lib linking
?deleteAllCompiledCode@Heap@JSC@@QAEXXZ
?displayName@JSFunction@JSC@@QAE?BVUString@2@PAVExecState@2@@Z
?dtoa@WTF@@YAXQADNAA_NAAHAAI@Z
+ ?dumpAllOptions@Options@JSC@@SAXPAU_iobuf@@@Z
?dumpSampleData@JSGlobalData@JSC@@QAEXPAVExecState@2@@Z
?empty@StringImpl@WTF@@SAPAV12@XZ
?enumerable@PropertyDescriptor@JSC@@QBE_NXZ
?setGetter@PropertyDescriptor@JSC@@QAEXVJSValue@2@@Z
?setLoc@StatementNode@JSC@@QAEXHH@Z
?setMainThreadCallbacksPaused@WTF@@YAX_N@Z
+ ?setOption@Options@JSC@@SA_NPBD@Z
?setOrderLowerFirst@Collator@WTF@@QAEX_N@Z
?setPrototype@JSObject@JSC@@QAEXAAVJSGlobalData@2@VJSValue@2@@Z
?setSetter@PropertyDescriptor@JSC@@QAEXVJSValue@2@@Z
LinkBuffer::CodeRef LinkBuffer::finalizeCodeWithDisassembly(const char* format, ...)
{
- ASSERT(Options::showDisassembly || Options::showDFGDisassembly);
+ ASSERT(Options::showDisassembly() || Options::showDFGDisassembly());
CodeRef result = finalizeCodeWithoutDisassembly();
// is true, so you can hide expensive disassembly-only computations inside there.
#define FINALIZE_CODE(linkBufferReference, dataLogArgumentsForHeading) \
- FINALIZE_CODE_IF(Options::showDisassembly, linkBufferReference, dataLogArgumentsForHeading)
+ FINALIZE_CODE_IF(Options::showDisassembly(), linkBufferReference, dataLogArgumentsForHeading)
} // namespace JSC
dumpValueProfiles();
#endif
- if (m_optimizationDelayCounter >= Options::maximumOptimizationDelay)
+ if (m_optimizationDelayCounter >= Options::maximumOptimizationDelay())
return true;
unsigned numberOfLiveNonArgumentValueProfiles;
dataLog("Profile hotness: %lf, %lf\n", (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles(), (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles());
#endif
- if ((!numberOfValueProfiles() || (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles() >= Options::desiredProfileLivenessRate)
- && (!totalNumberOfValueProfiles() || (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / totalNumberOfValueProfiles() >= Options::desiredProfileFullnessRate)
- && static_cast<unsigned>(m_optimizationDelayCounter) + 1 >= Options::minimumOptimizationDelay)
+ if ((!numberOfValueProfiles() || (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles() >= Options::desiredProfileLivenessRate())
+ && (!totalNumberOfValueProfiles() || (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / totalNumberOfValueProfiles() >= Options::desiredProfileFullnessRate())
+ && static_cast<unsigned>(m_optimizationDelayCounter) + 1 >= Options::minimumOptimizationDelay())
return true;
ASSERT(m_optimizationDelayCounter < std::numeric_limits<uint8_t>::max());
if (!numberOfRareCaseProfiles())
return false;
unsigned value = rareCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter;
- return value >= Options::likelyToTakeSlowCaseMinimumCount && static_cast<double>(value) / m_executionEntryCount >= Options::likelyToTakeSlowCaseThreshold;
+ return value >= Options::likelyToTakeSlowCaseMinimumCount() && static_cast<double>(value) / m_executionEntryCount >= Options::likelyToTakeSlowCaseThreshold();
}
bool couldTakeSlowCase(int bytecodeOffset)
if (!numberOfRareCaseProfiles())
return false;
unsigned value = rareCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter;
- return value >= Options::couldTakeSlowCaseMinimumCount && static_cast<double>(value) / m_executionEntryCount >= Options::couldTakeSlowCaseThreshold;
+ return value >= Options::couldTakeSlowCaseMinimumCount() && static_cast<double>(value) / m_executionEntryCount >= Options::couldTakeSlowCaseThreshold();
}
RareCaseProfile* addSpecialFastCaseProfile(int bytecodeOffset)
if (!numberOfRareCaseProfiles())
return false;
unsigned specialFastCaseCount = specialFastCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter;
- return specialFastCaseCount >= Options::likelyToTakeSlowCaseMinimumCount && static_cast<double>(specialFastCaseCount) / m_executionEntryCount >= Options::likelyToTakeSlowCaseThreshold;
+ return specialFastCaseCount >= Options::likelyToTakeSlowCaseMinimumCount() && static_cast<double>(specialFastCaseCount) / m_executionEntryCount >= Options::likelyToTakeSlowCaseThreshold();
}
bool likelyToTakeDeepestSlowCase(int bytecodeOffset)
unsigned slowCaseCount = rareCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter;
unsigned specialFastCaseCount = specialFastCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter;
unsigned value = slowCaseCount - specialFastCaseCount;
- return value >= Options::likelyToTakeSlowCaseMinimumCount && static_cast<double>(value) / m_executionEntryCount >= Options::likelyToTakeSlowCaseThreshold;
+ return value >= Options::likelyToTakeSlowCaseMinimumCount() && static_cast<double>(value) / m_executionEntryCount >= Options::likelyToTakeSlowCaseThreshold();
}
bool likelyToTakeAnySlowCase(int bytecodeOffset)
unsigned slowCaseCount = rareCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter;
unsigned specialFastCaseCount = specialFastCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter;
unsigned value = slowCaseCount + specialFastCaseCount;
- return value >= Options::likelyToTakeSlowCaseMinimumCount && static_cast<double>(value) / m_executionEntryCount >= Options::likelyToTakeSlowCaseThreshold;
+ return value >= Options::likelyToTakeSlowCaseMinimumCount() && static_cast<double>(value) / m_executionEntryCount >= Options::likelyToTakeSlowCaseThreshold();
}
unsigned executionEntryCount() const { return m_executionEntryCount; }
void jitAfterWarmUp()
{
- m_llintExecuteCounter.setNewThreshold(Options::thresholdForJITAfterWarmUp, this);
+ m_llintExecuteCounter.setNewThreshold(Options::thresholdForJITAfterWarmUp(), this);
}
void jitSoon()
{
- m_llintExecuteCounter.setNewThreshold(Options::thresholdForJITSoon, this);
+ m_llintExecuteCounter.setNewThreshold(Options::thresholdForJITSoon(), this);
}
const ExecutionCounter& llintExecuteCounter() const
// to avoid thrashing.
unsigned reoptimizationRetryCounter() const
{
- ASSERT(m_reoptimizationRetryCounter <= Options::reoptimizationRetryCounterMax);
+ ASSERT(m_reoptimizationRetryCounter <= Options::reoptimizationRetryCounterMax());
return m_reoptimizationRetryCounter;
}
void countReoptimization()
{
m_reoptimizationRetryCounter++;
- if (m_reoptimizationRetryCounter > Options::reoptimizationRetryCounterMax)
- m_reoptimizationRetryCounter = Options::reoptimizationRetryCounterMax;
+ if (m_reoptimizationRetryCounter > Options::reoptimizationRetryCounterMax())
+ m_reoptimizationRetryCounter = Options::reoptimizationRetryCounterMax();
}
int32_t counterValueForOptimizeAfterWarmUp()
{
- return Options::thresholdForOptimizeAfterWarmUp << reoptimizationRetryCounter();
+ return Options::thresholdForOptimizeAfterWarmUp() << reoptimizationRetryCounter();
}
int32_t counterValueForOptimizeAfterLongWarmUp()
{
- return Options::thresholdForOptimizeAfterLongWarmUp << reoptimizationRetryCounter();
+ return Options::thresholdForOptimizeAfterLongWarmUp() << reoptimizationRetryCounter();
}
int32_t* addressOfJITExecuteCounter()
// in the baseline code.
void optimizeSoon()
{
- m_jitExecuteCounter.setNewThreshold(Options::thresholdForOptimizeSoon << reoptimizationRetryCounter(), this);
+ m_jitExecuteCounter.setNewThreshold(Options::thresholdForOptimizeSoon() << reoptimizationRetryCounter(), this);
}
uint32_t osrExitCounter() const { return m_osrExitCounter; }
uint32_t exitCountThresholdForReoptimization()
{
- return adjustedExitCountThreshold(Options::osrExitCountForReoptimization);
+ return adjustedExitCountThreshold(Options::osrExitCountForReoptimization());
}
uint32_t exitCountThresholdForReoptimizationFromLoop()
{
- return adjustedExitCountThreshold(Options::osrExitCountForReoptimizationFromLoop);
+ return adjustedExitCountThreshold(Options::osrExitCountForReoptimizationFromLoop());
}
bool shouldReoptimizeNow()
static T clippedThreshold(JSGlobalObject* globalObject, T threshold)
{
int32_t maxThreshold;
- if (Options::randomizeExecutionCountsBetweenCheckpoints)
- maxThreshold = globalObject->weakRandomInteger() % Options::maximumExecutionCountsBetweenCheckpoints;
+ if (Options::randomizeExecutionCountsBetweenCheckpoints())
+ maxThreshold = globalObject->weakRandomInteger() % Options::maximumExecutionCountsBetweenCheckpoints();
else
- maxThreshold = Options::maximumExecutionCountsBetweenCheckpoints;
+ maxThreshold = Options::maximumExecutionCountsBetweenCheckpoints();
if (threshold > maxThreshold)
threshold = maxThreshold;
return threshold;
unsigned depth = 0;
for (InlineStackEntry* entry = m_inlineStackTop; entry; entry = entry->m_caller) {
++depth;
- if (depth >= Options::maximumInliningDepth)
+ if (depth >= Options::maximumInliningDepth())
return false; // Depth exceeded.
if (entry->executable() == executable)
// check opcodes.
inline bool mightCompileEval(CodeBlock* codeBlock)
{
- return codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount;
+ return codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
}
inline bool mightCompileProgram(CodeBlock* codeBlock)
{
- return codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount;
+ return codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
}
inline bool mightCompileFunctionForCall(CodeBlock* codeBlock)
{
- return codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount;
+ return codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
}
inline bool mightCompileFunctionForConstruct(CodeBlock* codeBlock)
{
- return codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount;
+ return codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
}
inline bool mightInlineFunctionForCall(CodeBlock* codeBlock)
{
- return codeBlock->instructionCount() <= Options::maximumFunctionForCallInlineCandidateInstructionCount
+ return codeBlock->instructionCount() <= Options::maximumFunctionForCallInlineCandidateInstructionCount()
&& !codeBlock->ownerExecutable()->needsActivation();
}
inline bool mightInlineFunctionForConstruct(CodeBlock* codeBlock)
{
- return codeBlock->instructionCount() <= Options::maximumFunctionForConstructInlineCandidateInstructionCount
+ return codeBlock->instructionCount() <= Options::maximumFunctionForConstructInlineCandidateInstructionCount()
&& !codeBlock->ownerExecutable()->needsActivation();
}
inline bool shouldShowDisassembly()
{
- return Options::showDisassembly || Options::showDFGDisassembly;
+ return Options::showDisassembly() || Options::showDFGDisassembly();
}
} } // namespace JSC::DFG
#include "DFGRedundantPhiEliminationPhase.h"
#include "DFGValidate.h"
#include "DFGVirtualRegisterAllocationPhase.h"
+#include "Options.h"
namespace JSC { namespace DFG {
ASSERT(codeBlock);
ASSERT(codeBlock->alternative());
ASSERT(codeBlock->alternative()->getJITType() == JITCode::BaselineJIT);
-
+
+ if (!Options::useDFGJIT())
+ return false;
+
#if DFG_ENABLE(DEBUG_VERBOSE)
dataLog("DFG compiling code block %p(%p) for executable %p, number of instructions = %u.\n", codeBlock, codeBlock->alternative(), codeBlock->ownerExecutable(), codeBlock->instructionCount());
#endif
bool OSRExit::considerAddingAsFrequentExitSiteSlow(CodeBlock* dfgCodeBlock, CodeBlock* profiledCodeBlock)
{
- if (static_cast<double>(m_count) / dfgCodeBlock->osrExitCounter() <= Options::osrExitProminenceForFrequentExitSite)
+ if (static_cast<double>(m_count) / dfgCodeBlock->osrExitCounter() <= Options::osrExitProminenceForFrequentExitSite())
return false;
FrequentExitSite exitSite;
// If the variable has been voted to become a double, then make it a
// double.
- if (doubleVoteRatio() >= Options::doubleVoteRatioForDoubleFormat)
+ if (doubleVoteRatio() >= Options::doubleVoteRatioForDoubleFormat())
return true;
return false;
}
}
- return static_cast<MarkStackSegment*>(OSAllocator::reserveAndCommit(Options::gcMarkStackSegmentSize));
+ return static_cast<MarkStackSegment*>(OSAllocator::reserveAndCommit(Options::gcMarkStackSegmentSize()));
}
void MarkStackSegmentAllocator::release(MarkStackSegment* segment)
while (segments) {
MarkStackSegment* toFree = segments;
segments = segments->m_previous;
- OSAllocator::decommitAndRelease(toFree, Options::gcMarkStackSegmentSize);
+ OSAllocator::decommitAndRelease(toFree, Options::gcMarkStackSegmentSize());
}
}
MarkStackArray::MarkStackArray(MarkStackSegmentAllocator& allocator)
: m_allocator(allocator)
- , m_segmentCapacity(MarkStackSegment::capacityFromSize(Options::gcMarkStackSegmentSize))
+ , m_segmentCapacity(MarkStackSegment::capacityFromSize(Options::gcMarkStackSegmentSize()))
, m_top(0)
, m_numberOfPreviousSegments(0)
{
, m_parallelMarkersShouldExit(false)
{
#if ENABLE(PARALLEL_GC)
- for (unsigned i = 1; i < Options::numberOfGCMarkers; ++i) {
+ for (unsigned i = 1; i < Options::numberOfGCMarkers(); ++i) {
SlotVisitor* slotVisitor = new SlotVisitor(*this);
m_markingThreadsMarkStack.append(slotVisitor);
m_markingThreads.append(createThread(markingThreadStartFunc, slotVisitor, "JavaScriptCore::Marking"));
// Otherwise, assume that a thread will go idle soon, and donate.
m_stack.donateSomeCellsTo(m_shared.m_sharedMarkStack);
- if (m_shared.m_numberOfActiveParallelMarkers < Options::numberOfGCMarkers)
+ if (m_shared.m_numberOfActiveParallelMarkers < Options::numberOfGCMarkers())
m_shared.m_markingCondition.broadcast();
}
ASSERT(m_isInParallelMode);
#if ENABLE(PARALLEL_GC)
- if (Options::numberOfGCMarkers > 1) {
+ if (Options::numberOfGCMarkers() > 1) {
while (!m_stack.isEmpty()) {
m_stack.refill();
- for (unsigned countdown = Options::minimumNumberOfScansBetweenRebalance; m_stack.canRemoveLast() && countdown--;)
+ for (unsigned countdown = Options::minimumNumberOfScansBetweenRebalance(); m_stack.canRemoveLast() && countdown--;)
visitChildren(*this, m_stack.removeLast());
donateKnownParallel();
}
{
ASSERT(m_isInParallelMode);
- ASSERT(Options::numberOfGCMarkers);
+ ASSERT(Options::numberOfGCMarkers());
bool shouldBeParallel;
#if ENABLE(PARALLEL_GC)
- shouldBeParallel = Options::numberOfGCMarkers > 1;
+ shouldBeParallel = Options::numberOfGCMarkers() > 1;
#else
- ASSERT(Options::numberOfGCMarkers == 1);
+ ASSERT(Options::numberOfGCMarkers() == 1);
shouldBeParallel = false;
#endif
}
}
- size_t idleThreadCount = Options::numberOfGCMarkers - m_shared.m_numberOfActiveParallelMarkers;
+ size_t idleThreadCount = Options::numberOfGCMarkers() - m_shared.m_numberOfActiveParallelMarkers;
m_stack.stealSomeCellsFrom(m_shared.m_sharedMarkStack, idleThreadCount);
m_shared.m_numberOfActiveParallelMarkers++;
}
void mergeOpaqueRootsIfProfitable()
{
- if (static_cast<unsigned>(m_opaqueRoots.size()) < Options::opaqueRootMergeThreshold)
+ if (static_cast<unsigned>(m_opaqueRoots.size()) < Options::opaqueRootMergeThreshold())
return;
mergeOpaqueRoots();
}
inline void MarkStack::addOpaqueRoot(void* root)
{
#if ENABLE(PARALLEL_GC)
- if (Options::numberOfGCMarkers == 1) {
+ if (Options::numberOfGCMarkers() == 1) {
// Put directly into the shared HashSet.
m_shared.m_opaqueRoots.add(root);
return;
void donate()
{
ASSERT(m_isInParallelMode);
- if (Options::numberOfGCMarkers == 1)
+ if (Options::numberOfGCMarkers() == 1)
return;
donateKnownParallel();
if (!canBeOptimized())
return;
- Jump skipOptimize = branchAdd32(Signed, TrustedImm32(kind == LoopOptimizationCheck ? Options::executionCounterIncrementForLoop : Options::executionCounterIncrementForReturn), AbsoluteAddress(m_codeBlock->addressOfJITExecuteCounter()));
+ Jump skipOptimize = branchAdd32(Signed, TrustedImm32(kind == LoopOptimizationCheck ? Options::executionCounterIncrementForLoop() : Options::executionCounterIncrementForReturn()), AbsoluteAddress(m_codeBlock->addressOfJITExecuteCounter()));
JITStubCall stubCall(this, cti_optimize);
stubCall.addArgument(TrustedImm32(m_bytecodeOffset));
if (kind == EnterOptimizationCheck)
fprintf(stderr, " -s Installs signal handlers that exit on a crash (Unix platforms only)\n");
#endif
fprintf(stderr, " -x Output exit code before terminating\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " --options Dumps all JSC VM options and exits\n");
+ fprintf(stderr, " --dumpOptions Dumps all JSC VM options before continuing\n");
+ fprintf(stderr, " --<jsc VM option>=<value> Sets the specified JSC VM option\n");
+ fprintf(stderr, "\n");
exit(help ? EXIT_SUCCESS : EXIT_FAILURE);
}
static void parseArguments(int argc, char** argv, CommandLine& options)
{
int i = 1;
+ bool needToDumpOptions = false;
+ bool needToExit = false;
+
for (; i < argc; ++i) {
const char* arg = argv[i];
if (!strcmp(arg, "-f")) {
}
if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
printUsageStatement(true);
+
+ if (!strcmp(arg, "--options")) {
+ needToDumpOptions = true;
+ needToExit = true;
+ continue;
+ }
+ if (!strcmp(arg, "--dumpOptions")) {
+ needToDumpOptions = true;
+ continue;
+ }
+
+ // See if the -- option is a JSC VM option.
+ // NOTE: At this point, we know that the arg starts with "--". Skip it.
+ if (JSC::Options::setOption(&arg[2])) {
+ // The arg was recognized as a VM option and has been parsed.
+ continue; // Just continue with the next arg.
+ }
+
+ // This arg is not recognized by the VM nor by jsc. Pass it on to the
+ // script.
options.scripts.append(Script(true, argv[i]));
}
for (; i < argc; ++i)
options.arguments.append(argv[i]);
+
+ if (needToDumpOptions)
+ JSC::Options::dumpAllOptions(stderr);
+ if (needToExit)
+ exit(EXIT_SUCCESS);
}
int jscmain(int argc, char** argv)
{
WTF::double_conversion::initialize();
WTF::initializeThreading();
- Options::initializeOptions();
+ Options::initialize();
#if ENABLE(WRITE_BARRIER_PROFILING)
WriteBarrierCounters::initialize();
#endif
#if ENABLE(ASSEMBLER) && (ENABLE(CLASSIC_INTERPRETER) || ENABLE(LLINT))
static bool enableAssembler(ExecutableAllocator& executableAllocator)
{
- if (!executableAllocator.isValid() || !Options::useJIT)
+ if (!executableAllocator.isValid() || !Options::useJIT())
return false;
#if USE(CF)
JSGlobalObject::JSGlobalObject(JSGlobalData& globalData, Structure* structure, const GlobalObjectMethodTable* globalObjectMethodTable)
: JSSegmentedVariableObject(globalData, structure, &m_symbolTable)
, m_globalScopeChain()
- , m_weakRandom(Options::forceWeakRandomSeed ? Options::forcedWeakRandomSeed : static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
+ , m_weakRandom(Options::forceWeakRandomSeed() ? Options::forcedWeakRandomSeed() : static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
, m_evalEnabled(true)
, m_globalObjectMethodTable(globalObjectMethodTable ? globalObjectMethodTable : &s_globalObjectMethodTable)
{
#include "Options.h"
#include <limits>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <wtf/NumberOfCores.h>
#include <wtf/PageBlock.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/StringExtras.h>
#if OS(DARWIN) && ENABLE(PARALLEL_GC)
#include <sys/sysctl.h>
// Set to 1 to control the heuristics using environment variables.
#define ENABLE_RUN_TIME_HEURISTICS 0
-#if ENABLE(RUN_TIME_HEURISTICS)
-#include <stdio.h>
-#include <stdlib.h>
-#include <wtf/StdLibExtras.h>
-#endif
-
-namespace JSC { namespace Options {
-
-bool useJIT;
-
-bool showDisassembly;
-bool showDFGDisassembly;
-
-unsigned maximumOptimizationCandidateInstructionCount;
-
-unsigned maximumFunctionForCallInlineCandidateInstructionCount;
-unsigned maximumFunctionForConstructInlineCandidateInstructionCount;
-
-unsigned maximumInliningDepth;
-int32_t thresholdForJITAfterWarmUp;
-int32_t thresholdForJITSoon;
+namespace JSC {
-int32_t thresholdForOptimizeAfterWarmUp;
-int32_t thresholdForOptimizeAfterLongWarmUp;
-int32_t thresholdForOptimizeSoon;
-
-int32_t executionCounterIncrementForLoop;
-int32_t executionCounterIncrementForReturn;
-
-bool randomizeExecutionCountsBetweenCheckpoints;
-int32_t maximumExecutionCountsBetweenCheckpoints;
-
-double likelyToTakeSlowCaseThreshold;
-double couldTakeSlowCaseThreshold;
-unsigned likelyToTakeSlowCaseMinimumCount;
-unsigned couldTakeSlowCaseMinimumCount;
-
-double osrExitProminenceForFrequentExitSite;
-unsigned osrExitCountForReoptimization;
-unsigned osrExitCountForReoptimizationFromLoop;
-
-unsigned reoptimizationRetryCounterMax;
-unsigned reoptimizationRetryCounterStep;
-
-unsigned minimumOptimizationDelay;
-unsigned maximumOptimizationDelay;
-double desiredProfileLivenessRate;
-double desiredProfileFullnessRate;
-
-double doubleVoteRatioForDoubleFormat;
-
-unsigned minimumNumberOfScansBetweenRebalance;
-unsigned gcMarkStackSegmentSize;
-unsigned numberOfGCMarkers;
-unsigned opaqueRootMergeThreshold;
-
-bool forceWeakRandomSeed;
-unsigned forcedWeakRandomSeed;
-
-#if ENABLE(RUN_TIME_HEURISTICS)
static bool parse(const char* string, bool& value)
{
if (!strcasecmp(string, "true") || !strcasecmp(string, "yes") || !strcmp(string, "1")) {
return sscanf(string, "%lf", &value) == 1;
}
-template<typename T, typename U>
-void setHeuristic(T& variable, const char* name, U value)
+#if ENABLE(RUN_TIME_HEURISTICS)
+template<typename T>
+void overrideOptionWithHeuristic(T& variable, const char* name)
{
const char* stringValue = getenv(name);
- if (!stringValue) {
- variable = safeCast<T>(value);
+ if (!stringValue)
return;
- }
if (parse(stringValue, variable))
return;
fprintf(stderr, "WARNING: failed to parse %s=%s\n", name, stringValue);
- variable = safeCast<T>(value);
}
-
-#define SET(variable, value) setHeuristic(variable, "JSC_" #variable, value)
-#else
-#define SET(variable, value) variable = value
#endif
+
static unsigned computeNumberOfGCMarkers(int maxNumberOfGCMarkers)
{
int cpusToUse = 1;
return cpusToUse;
}
-void initializeOptions()
-{
- SET(useJIT, true);
-
- SET(showDisassembly, false);
- SET(showDFGDisassembly, false); // DFG disassembly is shown if showDisassembly || showDFGDisassembly
-
- SET(maximumOptimizationCandidateInstructionCount, 10000);
-
- SET(maximumFunctionForCallInlineCandidateInstructionCount, 180);
- SET(maximumFunctionForConstructInlineCandidateInstructionCount, 100);
-
- SET(maximumInliningDepth, 5);
-
- SET(thresholdForJITAfterWarmUp, 100);
- SET(thresholdForJITSoon, 100);
- SET(thresholdForOptimizeAfterWarmUp, 1000);
- SET(thresholdForOptimizeAfterLongWarmUp, 5000);
- SET(thresholdForOptimizeSoon, 1000);
+Options::Entry Options::s_options[Options::numberOfOptions];
- SET(executionCounterIncrementForLoop, 1);
- SET(executionCounterIncrementForReturn, 15);
-
- SET(randomizeExecutionCountsBetweenCheckpoints, false);
- SET(maximumExecutionCountsBetweenCheckpoints, 1000);
+// Realize the names for each of the options:
+const Options::EntryInfo Options::s_optionsInfo[Options::numberOfOptions] = {
+#define FOR_EACH_OPTION(type_, name_, defaultValue_) \
+ { #name_, Options::type_##Type },
+ JSC_OPTIONS(FOR_EACH_OPTION)
+#undef FOR_EACH_OPTION
+};
- SET(likelyToTakeSlowCaseThreshold, 0.15);
- SET(couldTakeSlowCaseThreshold, 0.05); // Shouldn't be zero because some ops will spuriously take slow case, for example for linking or caching.
- SET(likelyToTakeSlowCaseMinimumCount, 100);
- SET(couldTakeSlowCaseMinimumCount, 10);
+void Options::initialize()
+{
+ // Initialize each of the options with their default values:
+#define FOR_EACH_OPTION(type_, name_, defaultValue_) \
+ name_() = defaultValue_;
+ JSC_OPTIONS(FOR_EACH_OPTION)
+#undef FOR_EACH_OPTION
+
+ // Allow environment vars to override options if applicable.
+ // The evn var should be the name of the option prefixed with
+ // "JSC_".
+#if ENABLE(RUN_TIME_HEURISTICS)
+#define FOR_EACH_OPTION(type_, name_, defaultValue_) \
+ overrideOptionWithHeuristic(name_(), "JSC_" #name_);
+ JSC_OPTIONS(FOR_EACH_OPTION)
+#undef FOR_EACH_OPTION
- SET(osrExitProminenceForFrequentExitSite, 0.3);
- SET(osrExitCountForReoptimization, 100);
- SET(osrExitCountForReoptimizationFromLoop, 5);
+#endif // RUN_TIME_HEURISTICS
- SET(reoptimizationRetryCounterStep, 1);
+ // Do range checks where needed and make corrections to the options:
+ ASSERT(thresholdForOptimizeAfterLongWarmUp() >= thresholdForOptimizeAfterWarmUp());
+ ASSERT(thresholdForOptimizeAfterWarmUp() >= thresholdForOptimizeSoon());
+ ASSERT(thresholdForOptimizeAfterWarmUp() >= 0);
- SET(minimumOptimizationDelay, 1);
- SET(maximumOptimizationDelay, 5);
- SET(desiredProfileLivenessRate, 0.75);
- SET(desiredProfileFullnessRate, 0.35);
-
- SET(doubleVoteRatioForDoubleFormat, 2);
-
- SET(minimumNumberOfScansBetweenRebalance, 100);
- SET(gcMarkStackSegmentSize, pageSize());
- SET(opaqueRootMergeThreshold, 1000);
- SET(numberOfGCMarkers, computeNumberOfGCMarkers(7)); // We don't scale so well beyond 7.
-
- ASSERT(thresholdForOptimizeAfterLongWarmUp >= thresholdForOptimizeAfterWarmUp);
- ASSERT(thresholdForOptimizeAfterWarmUp >= thresholdForOptimizeSoon);
- ASSERT(thresholdForOptimizeAfterWarmUp >= 0);
-
// Compute the maximum value of the reoptimization retry counter. This is simply
// the largest value at which we don't overflow the execute counter, when using it
// to left-shift the execution counter by this amount. Currently the value ends
// up being 18, so this loop is not so terrible; it probably takes up ~100 cycles
// total on a 32-bit processor.
- reoptimizationRetryCounterMax = 0;
- while ((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp) << (reoptimizationRetryCounterMax + 1)) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max()))
- reoptimizationRetryCounterMax++;
-
- ASSERT((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp) << reoptimizationRetryCounterMax) > 0);
- ASSERT((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp) << reoptimizationRetryCounterMax) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max()));
-
- SET(forceWeakRandomSeed, false);
- SET(forcedWeakRandomSeed, 0);
+ reoptimizationRetryCounterMax() = 0;
+ while ((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp()) << (reoptimizationRetryCounterMax() + 1)) <= static_cast<int64_t>(std::numeric_limits<int32>::max()))
+ reoptimizationRetryCounterMax()++;
+
+ ASSERT((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp()) << reoptimizationRetryCounterMax()) > 0);
+ ASSERT((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp()) << reoptimizationRetryCounterMax()) <= static_cast<int64_t>(std::numeric_limits<int32>::max()));
+}
+
+// Parses a single command line option in the format "<optionName>=<value>"
+// (no spaces allowed) and set the specified option if appropriate.
+bool Options::setOption(const char* arg)
+{
+ // arg should look like this:
+ // <jscOptionName>=<appropriate value>
+ const char* equalStr = strchr(arg, '=');
+ if (!equalStr)
+ return false;
+
+ const char* valueStr = equalStr + 1;
+
+ // For each option, check if the specify arg is a match. If so, set the arg
+ // if the value makes sense. Otherwise, move on to checking the next option.
+#define FOR_EACH_OPTION(type_, name_, defaultValue_) \
+ if (!strncmp(arg, #name_, equalStr - arg)) { \
+ type_ value; \
+ bool success = parse(valueStr, value); \
+ if (success) { \
+ name_() = value; \
+ return true; \
+ } \
+ return false; \
+ }
+
+ JSC_OPTIONS(FOR_EACH_OPTION)
+#undef FOR_EACH_OPTION
+
+ return false; // No option matched.
+}
+
+void Options::dumpAllOptions(FILE* stream)
+{
+ fprintf(stream, "JSC runtime options:\n");
+ for (int id = 0; id < numberOfOptions; id++)
+ dumpOption(static_cast<OptionID>(id), stream, " ", "\n");
}
-} } // namespace JSC::Options
+void Options::dumpOption(OptionID id, FILE* stream, const char* header, const char* footer)
+{
+ if (id >= numberOfOptions)
+ return; // Illegal option.
+
+ fprintf(stream, "%s%s: ", header, s_optionsInfo[id].name);
+ switch (s_optionsInfo[id].type) {
+ case boolType:
+ fprintf(stream, "%s", s_options[id].u.boolVal?"true":"false");
+ break;
+ case unsignedType:
+ fprintf(stream, "%u", s_options[id].u.unsignedVal);
+ break;
+ case doubleType:
+ fprintf(stream, "%lf", s_options[id].u.doubleVal);
+ break;
+ case int32Type:
+ fprintf(stream, "%d", s_options[id].u.int32Val);
+ break;
+ }
+ fprintf(stream, "%s", footer);
+}
+} // namespace JSC
#ifndef Options_h
#define Options_h
+#include "JSExportMacros.h"
#include <stdint.h>
-
-namespace JSC { namespace Options {
-
-extern bool useJIT;
-
-extern bool showDisassembly;
-extern bool showDFGDisassembly; // showDisassembly implies showDFGDisassembly.
-
-extern unsigned maximumOptimizationCandidateInstructionCount;
-
-extern unsigned maximumFunctionForCallInlineCandidateInstructionCount;
-extern unsigned maximumFunctionForConstructInlineCandidateInstructionCount;
-
-extern unsigned maximumInliningDepth; // Depth of inline stack, so 1 = no inlining, 2 = one level, etc.
-
-extern int32_t thresholdForJITAfterWarmUp;
-extern int32_t thresholdForJITSoon;
-
-extern int32_t thresholdForOptimizeAfterWarmUp;
-extern int32_t thresholdForOptimizeAfterLongWarmUp;
-extern int32_t thresholdForOptimizeSoon;
-extern int32_t thresholdForOptimizeNextInvocation;
-
-extern int32_t executionCounterIncrementForLoop;
-extern int32_t executionCounterIncrementForReturn;
-
-extern bool randomizeExecutionCountsBetweenCheckpoints;
-extern int32_t maximumExecutionCountsBetweenCheckpoints;
-
-extern double likelyToTakeSlowCaseThreshold;
-extern double couldTakeSlowCaseThreshold;
-extern unsigned likelyToTakeSlowCaseMinimumCount;
-extern unsigned couldTakeSlowCaseMinimumCount;
-
-extern double osrExitProminenceForFrequentExitSite;
-extern unsigned osrExitCountForReoptimization;
-extern unsigned osrExitCountForReoptimizationFromLoop;
-
-extern unsigned reoptimizationRetryCounterMax;
-extern unsigned reoptimizationRetryCounterStep;
-
-extern unsigned minimumOptimizationDelay;
-extern unsigned maximumOptimizationDelay;
-extern double desiredProfileLivenessRate;
-extern double desiredProfileFullnessRate;
-
-extern double doubleVoteRatioForDoubleFormat;
-
-extern unsigned minimumNumberOfScansBetweenRebalance;
-extern unsigned gcMarkStackSegmentSize;
-JS_EXPORTDATA extern unsigned numberOfGCMarkers;
-JS_EXPORTDATA extern unsigned opaqueRootMergeThreshold;
-
-extern bool forceWeakRandomSeed;
-extern unsigned forcedWeakRandomSeed;
-
-void initializeOptions();
-
-} } // namespace JSC::Options
+#include <stdio.h>
+
+namespace JSC {
+
+// How do JSC VM options work?
+// ===========================
+// The JSC_OPTIONS() macro below defines a list of all JSC options in use,
+// along with their types and default values. The options values are actually
+// realized as an array of Options::Entry elements.
+//
+// Options::initialize() will initialize the array of options values with
+// the defaults specified in JSC_OPTIONS() below. After that, the values can
+// be programmatically read and written to using an accessor method with the
+// same name as the option. For example, the option "useJIT" can be read and
+// set like so:
+//
+// bool jitIsOn = Options::useJIT(); // Get the option value.
+// Options::useJIT() = false; // Sets the option value.
+//
+// If you want to tweak any of these values programmatically for testing
+// purposes, you can do so in Options::initialize() after the default values
+// are set.
+//
+// Alternatively, you can enable RUN_TIME_HEURISTICS which will allow you
+// to override the default values by specifying environment variables of the
+// form: JSC_<name of JSC option>.
+//
+// Note: Options::initialize() tries to ensure some sanity on the option values
+// which are set by doing some range checks, and value corrections. These
+// checks are done after the option values are set. If you alter the option
+// values after the sanity checks (for your own testing), then you're liable to
+// ensure that the new values set are sane and reasonable for your own run.
+
+
+#define JSC_OPTIONS(v) \
+ v(bool, useJIT, true) \
+ v(bool, useDFGJIT, true) \
+ \
+ /* showDisassembly implies showDFGDisassembly. */ \
+ v(bool, showDisassembly, false) \
+ v(bool, showDFGDisassembly, false) \
+ \
+ v(unsigned, maximumOptimizationCandidateInstructionCount, 10000) \
+ \
+ v(unsigned, maximumFunctionForCallInlineCandidateInstructionCount, 180) \
+ v(unsigned, maximumFunctionForConstructInlineCandidateInstructionCount, 100) \
+ \
+ /* Depth of inline stack, so 1 = no inlining, 2 = one level, etc. */ \
+ v(unsigned, maximumInliningDepth, 5) \
+ \
+ v(int32, thresholdForJITAfterWarmUp, 100) \
+ v(int32, thresholdForJITSoon, 100) \
+ \
+ v(int32, thresholdForOptimizeAfterWarmUp, 1000) \
+ v(int32, thresholdForOptimizeAfterLongWarmUp, 5000) \
+ v(int32, thresholdForOptimizeSoon, 1000) \
+ \
+ v(int32, executionCounterIncrementForLoop, 1) \
+ v(int32, executionCounterIncrementForReturn, 15) \
+ \
+ v(bool, randomizeExecutionCountsBetweenCheckpoints, false) \
+ v(int32, maximumExecutionCountsBetweenCheckpoints, 1000) \
+ \
+ v(double, likelyToTakeSlowCaseThreshold, 0.15) \
+ v(double, couldTakeSlowCaseThreshold, 0.05) \
+ v(unsigned, likelyToTakeSlowCaseMinimumCount, 100) \
+ v(unsigned, couldTakeSlowCaseMinimumCount, 10) \
+ \
+ v(double, osrExitProminenceForFrequentExitSite, 0.3) \
+ v(unsigned, osrExitCountForReoptimization, 100) \
+ v(unsigned, osrExitCountForReoptimizationFromLoop, 5) \
+ \
+ v(unsigned, reoptimizationRetryCounterMax, 0) \
+ v(unsigned, reoptimizationRetryCounterStep, 1) \
+ \
+ v(unsigned, minimumOptimizationDelay, 1) \
+ v(unsigned, maximumOptimizationDelay, 5) \
+ v(double, desiredProfileLivenessRate, 0.75) \
+ v(double, desiredProfileFullnessRate, 0.35) \
+ \
+ v(double, doubleVoteRatioForDoubleFormat, 2) \
+ \
+ v(unsigned, minimumNumberOfScansBetweenRebalance, 100) \
+ v(unsigned, gcMarkStackSegmentSize, pageSize()) \
+ v(unsigned, numberOfGCMarkers, computeNumberOfGCMarkers(7)) \
+ v(unsigned, opaqueRootMergeThreshold, 1000) \
+ \
+ v(bool, forceWeakRandomSeed, false) \
+ v(unsigned, forcedWeakRandomSeed, 0)
+
+
+class Options {
+public:
+ // This typedef is to allow us to eliminate the '_' in the field name in
+ // union inside Entry. This is needed to keep the style checker happy.
+ typedef int32_t int32;
+
+ // Declare the option IDs:
+ enum OptionID {
+#define FOR_EACH_OPTION(type_, name_, defaultValue_) \
+ OPT_##name_,
+ JSC_OPTIONS(FOR_EACH_OPTION)
+#undef FOR_EACH_OPTION
+ numberOfOptions
+ };
+
+
+ static void initialize();
+
+ // Parses a single command line option in the format "<optionName>=<value>"
+ // (no spaces allowed) and set the specified option if appropriate.
+ JS_EXPORT_PRIVATE static bool setOption(const char* arg);
+ JS_EXPORT_PRIVATE static void dumpAllOptions(FILE* stream = stdout);
+ static void dumpOption(OptionID id, FILE* stream = stdout, const char* header = "", const char* footer = "");
+
+ // Declare accessors for each option:
+#define FOR_EACH_OPTION(type_, name_, defaultValue_) \
+ ALWAYS_INLINE static type_& name_() { return s_options[OPT_##name_].u.type_##Val; }
+
+ JSC_OPTIONS(FOR_EACH_OPTION)
+#undef FOR_EACH_OPTION
+
+private:
+ enum EntryType {
+ boolType,
+ unsignedType,
+ doubleType,
+ int32Type
+ };
+
+ // For storing for an option value:
+ struct Entry {
+ union {
+ bool boolVal;
+ unsigned unsignedVal;
+ double doubleVal;
+ int32 int32Val;
+ } u;
+ };
+
+ // For storing constant meta data about each option:
+ struct EntryInfo {
+ const char* name;
+ EntryType type;
+ };
+
+ Options();
+
+ // Declare the options:
+#define FOR_EACH_OPTION(type_, name_, defaultValue_) \
+ type_ m_##name_;
+ JSC_OPTIONS(FOR_EACH_OPTION)
+#undef FOR_EACH_OPTION
+
+ // Declare the singleton instance of the options store:
+ JS_EXPORTDATA static Entry s_options[numberOfOptions];
+ static const EntryInfo s_optionsInfo[numberOfOptions];
+};
+
+} // namespace JSC
#endif // Options_h
-