+ return 0;
+}
+
+ArrayProfile* CodeBlock::getOrAddArrayProfile(unsigned bytecodeOffset)
+{
+ ArrayProfile* result = getArrayProfile(bytecodeOffset);
+ if (result)
+ return result;
+ return addArrayProfile(bytecodeOffset);
+}
+
+void CodeBlock::updateAllPredictionsAndCountLiveness(
+ OperationInProgress operation, unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles)
+{
+ numberOfLiveNonArgumentValueProfiles = 0;
+ numberOfSamplesInProfiles = 0; // If this divided by ValueProfile::numberOfBuckets equals numberOfValueProfiles() then value profiles are full.
+ for (unsigned i = 0; i < totalNumberOfValueProfiles(); ++i) {
+ ValueProfile* profile = getFromAllValueProfiles(i);
+ unsigned numSamples = profile->totalNumberOfSamples();
+ if (numSamples > ValueProfile::numberOfBuckets)
+ numSamples = ValueProfile::numberOfBuckets; // We don't want profiles that are extremely hot to be given more weight.
+ numberOfSamplesInProfiles += numSamples;
+ if (profile->m_bytecodeOffset < 0) {
+ profile->computeUpdatedPrediction(operation);
+ continue;
+ }
+ if (profile->numberOfSamples() || profile->m_prediction != SpecNone)
+ numberOfLiveNonArgumentValueProfiles++;
+ profile->computeUpdatedPrediction(operation);
+ }
+
+#if ENABLE(DFG_JIT)
+ m_lazyOperandValueProfiles.computeUpdatedPredictions(operation);
+#endif
+}
+
+void CodeBlock::updateAllValueProfilePredictions(OperationInProgress operation)
+{
+ unsigned ignoredValue1, ignoredValue2;
+ updateAllPredictionsAndCountLiveness(operation, ignoredValue1, ignoredValue2);
+}
+
+void CodeBlock::updateAllArrayPredictions(OperationInProgress operation)
+{
+ for (unsigned i = m_arrayProfiles.size(); i--;)
+ m_arrayProfiles[i].computeUpdatedPrediction(this, operation);
+
+ // Don't count these either, for similar reasons.
+ for (unsigned i = m_arrayAllocationProfiles.size(); i--;)
+ m_arrayAllocationProfiles[i].updateIndexingType();
+}
+
+void CodeBlock::updateAllPredictions(OperationInProgress operation)
+{
+ updateAllValueProfilePredictions(operation);
+ updateAllArrayPredictions(operation);
+}
+
+bool CodeBlock::shouldOptimizeNow()
+{
+#if ENABLE(JIT_VERBOSE_OSR)
+ dataLog("Considering optimizing ", *this, "...\n");
+#endif
+
+#if ENABLE(VERBOSE_VALUE_PROFILE)
+ dumpValueProfiles();
+#endif
+
+ if (m_optimizationDelayCounter >= Options::maximumOptimizationDelay())
+ return true;
+
+ updateAllArrayPredictions();
+
+ unsigned numberOfLiveNonArgumentValueProfiles;
+ unsigned numberOfSamplesInProfiles;
+ updateAllPredictionsAndCountLiveness(NoOperation, numberOfLiveNonArgumentValueProfiles, numberOfSamplesInProfiles);
+
+#if ENABLE(JIT_VERBOSE_OSR)
+ dataLogF("Profile hotness: %lf (%u / %u), %lf (%u / %u)\n", (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles(), numberOfLiveNonArgumentValueProfiles, numberOfValueProfiles(), (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles(), 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())
+ return true;
+
+ ASSERT(m_optimizationDelayCounter < std::numeric_limits<uint8_t>::max());
+ m_optimizationDelayCounter++;
+ optimizeAfterWarmUp();
+ return false;
+}
+#endif
+
+#if ENABLE(DFG_JIT)
+void CodeBlock::tallyFrequentExitSites()
+{
+ ASSERT(getJITType() == JITCode::DFGJIT);
+ ASSERT(alternative()->getJITType() == JITCode::BaselineJIT);
+ ASSERT(!!m_dfgData);
+
+ CodeBlock* profiledBlock = alternative();
+
+ for (unsigned i = 0; i < m_dfgData->osrExit.size(); ++i) {
+ DFG::OSRExit& exit = m_dfgData->osrExit[i];
+
+ if (!exit.considerAddingAsFrequentExitSite(profiledBlock))
+ continue;
+
+#if DFG_ENABLE(DEBUG_VERBOSE)
+ dataLog("OSR exit #", i, " (bc#", exit.m_codeOrigin.bytecodeIndex, ", ", exit.m_kind, ") for ", *this, " occurred frequently: counting as frequent exit site.\n");
+#endif
+ }
+}
+#endif // ENABLE(DFG_JIT)
+
+#if ENABLE(VERBOSE_VALUE_PROFILE)
+void CodeBlock::dumpValueProfiles()
+{
+ dataLog("ValueProfile for ", *this, ":\n");
+ for (unsigned i = 0; i < totalNumberOfValueProfiles(); ++i) {
+ ValueProfile* profile = getFromAllValueProfiles(i);
+ if (profile->m_bytecodeOffset < 0) {
+ ASSERT(profile->m_bytecodeOffset == -1);
+ dataLogF(" arg = %u: ", i);
+ } else
+ dataLogF(" bc = %d: ", profile->m_bytecodeOffset);
+ if (!profile->numberOfSamples() && profile->m_prediction == SpecNone) {
+ dataLogF("<empty>\n");
+ continue;
+ }
+ profile->dump(WTF::dataFile());
+ dataLogF("\n");
+ }
+ dataLog("RareCaseProfile for ", *this, ":\n");
+ for (unsigned i = 0; i < numberOfRareCaseProfiles(); ++i) {
+ RareCaseProfile* profile = rareCaseProfile(i);
+ dataLogF(" bc = %d: %u\n", profile->m_bytecodeOffset, profile->m_counter);
+ }
+ dataLog("SpecialFastCaseProfile for ", *this, ":\n");
+ for (unsigned i = 0; i < numberOfSpecialFastCaseProfiles(); ++i) {
+ RareCaseProfile* profile = specialFastCaseProfile(i);
+ dataLogF(" bc = %d: %u\n", profile->m_bytecodeOffset, profile->m_counter);
+ }
+}
+#endif // ENABLE(VERBOSE_VALUE_PROFILE)
+
+size_t CodeBlock::predictedMachineCodeSize()
+{
+ // This will be called from CodeBlock::CodeBlock before either m_vm or the
+ // instructions have been initialized. It's OK to return 0 because what will really
+ // matter is the recomputation of this value when the slow path is triggered.
+ if (!m_vm)
+ return 0;
+
+ if (!m_vm->machineCodeBytesPerBytecodeWordForBaselineJIT)
+ return 0; // It's as good of a prediction as we'll get.
+
+ // Be conservative: return a size that will be an overestimation 84% of the time.
+ double multiplier = m_vm->machineCodeBytesPerBytecodeWordForBaselineJIT.mean() +
+ m_vm->machineCodeBytesPerBytecodeWordForBaselineJIT.standardDeviation();
+
+ // Be paranoid: silently reject bogus multipiers. Silently doing the "wrong" thing
+ // here is OK, since this whole method is just a heuristic.
+ if (multiplier < 0 || multiplier > 1000)
+ return 0;
+
+ double doubleResult = multiplier * m_instructions.size();
+
+ // Be even more paranoid: silently reject values that won't fit into a size_t. If
+ // the function is so huge that we can't even fit it into virtual memory then we
+ // should probably have some other guards in place to prevent us from even getting
+ // to this point.
+ if (doubleResult > std::numeric_limits<size_t>::max())
+ return 0;
+
+ return static_cast<size_t>(doubleResult);
+}
+
+bool CodeBlock::usesOpcode(OpcodeID opcodeID)
+{
+ Interpreter* interpreter = vm()->interpreter;
+ Instruction* instructionsBegin = instructions().begin();
+ unsigned instructionCount = instructions().size();
+
+ for (unsigned bytecodeOffset = 0; bytecodeOffset < instructionCount; ) {
+ switch (interpreter->getOpcodeID(instructionsBegin[bytecodeOffset].u.opcode)) {
+#define DEFINE_OP(curOpcode, length) \
+ case curOpcode: \
+ if (curOpcode == opcodeID) \
+ return true; \
+ bytecodeOffset += length; \
+ break;
+ FOR_EACH_OPCODE_ID(DEFINE_OP)
+#undef DEFINE_OP
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+ }
+
+ return false;
+}
+
+String CodeBlock::nameForRegister(int registerNumber)
+{
+ SymbolTable::iterator end = symbolTable()->end();
+ for (SymbolTable::iterator ptr = symbolTable()->begin(); ptr != end; ++ptr) {
+ if (ptr->value.getIndex() == registerNumber)
+ return String(ptr->key);
+ }
+ if (needsActivation() && registerNumber == activationRegister())
+ return ASCIILiteral("activation");
+ if (registerNumber == thisRegister())
+ return ASCIILiteral("this");
+ if (usesArguments()) {
+ if (registerNumber == argumentsRegister())
+ return ASCIILiteral("arguments");
+ if (unmodifiedArgumentsRegister(argumentsRegister()) == registerNumber)
+ return ASCIILiteral("real arguments");
+ }
+ if (registerNumber < 0) {
+ int argumentPosition = -registerNumber;
+ argumentPosition -= JSStack::CallFrameHeaderSize + 1;
+ return String::format("arguments[%3d]", argumentPosition - 1).impl();
+ }
+ return "";