Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState) { Graph dfg(vm, *this, longLivedState); if (!parse(dfg)) { finalizer = adoptPtr(new FailedFinalizer(*this)); return FailPath; } // By this point the DFG bytecode parser will have potentially mutated various tables // in the CodeBlock. This is a good time to perform an early shrink, which is more // powerful than a late one. It's safe to do so because we haven't generated any code // that references any of the tables directly, yet. codeBlock->shrinkToFit(CodeBlock::EarlyShrink); if (validationEnabled()) validate(dfg); performCPSRethreading(dfg); performUnification(dfg); performPredictionInjection(dfg); if (validationEnabled()) validate(dfg); performBackwardsPropagation(dfg); performPredictionPropagation(dfg); performFixup(dfg); performTypeCheckHoisting(dfg); unsigned count = 1; dfg.m_fixpointState = FixpointNotConverged; for (;; ++count) { if (logCompilationChanges()) dataLogF("DFG beginning optimization fixpoint iteration #%u.\n", count); bool changed = false; if (validationEnabled()) validate(dfg); performCFA(dfg); changed |= performConstantFolding(dfg); changed |= performArgumentsSimplification(dfg); changed |= performCFGSimplification(dfg); changed |= performCSE(dfg); if (!changed) break; performCPSRethreading(dfg); } if (logCompilationChanges()) dataLogF("DFG optimization fixpoint converged in %u iterations.\n", count); dfg.m_fixpointState = FixpointConverged; performStoreElimination(dfg); // If we're doing validation, then run some analyses, to give them an opportunity // to self-validate. Now is as good a time as any to do this. if (validationEnabled()) { dfg.m_dominators.computeIfNecessary(dfg); dfg.m_naturalLoops.computeIfNecessary(dfg); } #if ENABLE(FTL_JIT) if (Options::useExperimentalFTL() && compileMode == CompileFunction && FTL::canCompile(dfg)) { performCriticalEdgeBreaking(dfg); performLoopPreHeaderCreation(dfg); performCPSRethreading(dfg); performSSAConversion(dfg); performLivenessAnalysis(dfg); performCFA(dfg); performLICM(dfg); performLivenessAnalysis(dfg); performCFA(dfg); performDCE(dfg); // We rely on this to convert dead SetLocals into the appropriate hint, and to kill dead code that won't be recognized as dead by LLVM. performLivenessAnalysis(dfg); performFlushLivenessAnalysis(dfg); performOSRAvailabilityAnalysis(dfg); dumpAndVerifyGraph(dfg, "Graph just before FTL lowering:"); // FIXME: Support OSR entry. // https://bugs.webkit.org/show_bug.cgi?id=113625 FTL::State state(dfg); FTL::lowerDFGToLLVM(state); if (Options::reportCompileTimes()) beforeFTL = currentTimeMS(); if (Options::llvmAlwaysFails()) { FTL::fail(state); return FTLPath; } FTL::compile(state); FTL::link(state); return FTLPath; } #endif // ENABLE(FTL_JIT) performCPSRethreading(dfg); performDCE(dfg); performVirtualRegisterAllocation(dfg); dumpAndVerifyGraph(dfg, "Graph after optimization:"); JITCompiler dataFlowJIT(dfg); if (compileMode == CompileFunction) { dataFlowJIT.compileFunction(); dataFlowJIT.linkFunction(); } else { ASSERT(compileMode == CompileOther); dataFlowJIT.compile(); dataFlowJIT.link(); } return DFGPath; }
void Options::initialize() { static std::once_flag initializeOptionsOnceFlag; std::call_once( initializeOptionsOnceFlag, [] { // Initialize each of the options with their default values: #define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \ name_() = defaultValue_; \ name_##Default() = defaultValue_; JSC_OPTIONS(FOR_EACH_OPTION) #undef FOR_EACH_OPTION overrideDefaults(); // Allow environment vars to override options if applicable. // The evn var should be the name of the option prefixed with // "JSC_". #if PLATFORM(COCOA) bool hasBadOptions = false; for (char** envp = *_NSGetEnviron(); *envp; envp++) { const char* env = *envp; if (!strncmp("JSC_", env, 4)) { if (!Options::setOption(&env[4])) { dataLog("ERROR: invalid option: ", *envp, "\n"); hasBadOptions = true; } } } if (hasBadOptions && Options::validateOptions()) CRASH(); #else // PLATFORM(COCOA) #define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \ overrideOptionWithHeuristic(name_(), name_##ID, "JSC_" #name_, Availability::availability_); JSC_OPTIONS(FOR_EACH_OPTION) #undef FOR_EACH_OPTION #endif // PLATFORM(COCOA) #define FOR_EACH_OPTION(aliasedName_, unaliasedName_, equivalence_) \ overrideAliasedOptionWithHeuristic("JSC_" #aliasedName_); JSC_ALIASED_OPTIONS(FOR_EACH_OPTION) #undef FOR_EACH_OPTION #if 0 ; // Deconfuse editors that do auto indentation #endif #if USE(OPTIONS_FILE) { const char* filename = OPTIONS_FILENAME; FILE* optionsFile = fopen(filename, "r"); if (!optionsFile) { dataLogF("Failed to open file %s. Did you add the file-read-data entitlement to WebProcess.sb?\n", filename); return; } StringBuilder builder; char* line; char buffer[BUFSIZ]; while ((line = fgets(buffer, sizeof(buffer), optionsFile))) builder.append(buffer); const char* optionsStr = builder.toString().utf8().data(); dataLogF("Setting options: %s\n", optionsStr); setOptions(optionsStr); int result = fclose(optionsFile); if (result) dataLogF("Failed to close file %s: %s\n", filename, strerror(errno)); } #endif recomputeDependentOptions(); // Do range checks where needed and make corrections to the options: ASSERT(Options::thresholdForOptimizeAfterLongWarmUp() >= Options::thresholdForOptimizeAfterWarmUp()); ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= Options::thresholdForOptimizeSoon()); ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= 0); dumpOptionsIfNeeded(); ensureOptionsAreCoherent(); }); }
inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr* jitCodeWithArityCheck, unsigned osrEntryBytecodeIndex) { SamplingRegion samplingRegion("DFG Compilation (Driver)"); numCompilations++; ASSERT(codeBlock); ASSERT(codeBlock->alternative()); ASSERT(codeBlock->alternative()->getJITType() == JITCode::BaselineJIT); ASSERT(osrEntryBytecodeIndex != UINT_MAX); if (!Options::useDFGJIT()) return false; #if DFG_ENABLE(DEBUG_VERBOSE) dataLog("DFG compiling ", *codeBlock, ", number of instructions = ", codeBlock->instructionCount(), "\n"); #endif // Derive our set of must-handle values. The compilation must be at least conservative // enough to allow for OSR entry with these values. unsigned numVarsWithValues; if (osrEntryBytecodeIndex) numVarsWithValues = codeBlock->m_numVars; else numVarsWithValues = 0; Operands<JSValue> mustHandleValues(codeBlock->numParameters(), numVarsWithValues); for (size_t i = 0; i < mustHandleValues.size(); ++i) { int operand = mustHandleValues.operandForIndex(i); if (operandIsArgument(operand) && !operandToArgument(operand) && compileMode == CompileFunction && codeBlock->specializationKind() == CodeForConstruct) { // Ugh. If we're in a constructor, the 'this' argument may hold garbage. It will // also never be used. It doesn't matter what we put into the value for this, // but it has to be an actual value that can be grokked by subsequent DFG passes, // so we sanitize it here by turning it into Undefined. mustHandleValues[i] = jsUndefined(); } else mustHandleValues[i] = exec->uncheckedR(operand).jsValue(); } Graph dfg(exec->globalData(), codeBlock, osrEntryBytecodeIndex, mustHandleValues); if (!parse(exec, dfg)) return false; if (compileMode == CompileFunction) dfg.predictArgumentTypes(); // By this point the DFG bytecode parser will have potentially mutated various tables // in the CodeBlock. This is a good time to perform an early shrink, which is more // powerful than a late one. It's safe to do so because we haven't generated any code // that references any of the tables directly, yet. codeBlock->shrinkToFit(CodeBlock::EarlyShrink); validate(dfg); performPredictionPropagation(dfg); performFixup(dfg); performStructureCheckHoisting(dfg); unsigned cnt = 1; dfg.m_fixpointState = FixpointNotConverged; for (;; ++cnt) { #if DFG_ENABLE(DEBUG_VERBOSE) dataLogF("DFG beginning optimization fixpoint iteration #%u.\n", cnt); #endif bool changed = false; performCFA(dfg); changed |= performConstantFolding(dfg); changed |= performArgumentsSimplification(dfg); changed |= performCFGSimplification(dfg); changed |= performCSE(dfg); if (!changed) break; dfg.resetExitStates(); performFixup(dfg); } dfg.m_fixpointState = FixpointConverged; performCSE(dfg); #if DFG_ENABLE(DEBUG_VERBOSE) dataLogF("DFG optimization fixpoint converged in %u iterations.\n", cnt); #endif performVirtualRegisterAllocation(dfg); GraphDumpMode modeForFinalValidate = DumpGraph; #if DFG_ENABLE(DEBUG_VERBOSE) dataLogF("Graph after optimization:\n"); dfg.dump(); modeForFinalValidate = DontDumpGraph; #endif validate(dfg, modeForFinalValidate); JITCompiler dataFlowJIT(dfg); bool result; if (compileMode == CompileFunction) { ASSERT(jitCodeWithArityCheck); result = dataFlowJIT.compileFunction(jitCode, *jitCodeWithArityCheck); } else { ASSERT(compileMode == CompileOther); ASSERT(!jitCodeWithArityCheck); result = dataFlowJIT.compile(jitCode); } return result; }