/* * Copyright (C) 2012, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ExecutionCounter_h #define ExecutionCounter_h #include "JSGlobalObject.h" #include "Options.h" #include #include namespace JSC { class CodeBlock; enum CountingVariant { CountingForBaseline, CountingForUpperTiers }; double applyMemoryUsageHeuristics(int32_t value, CodeBlock*); int32_t applyMemoryUsageHeuristicsAndConvertToInt(int32_t value, CodeBlock*); inline int32_t formattedTotalExecutionCount(float value) { union { int32_t i; float f; } u; u.f = value; return u.i; } template class ExecutionCounter { public: ExecutionCounter(); void forceSlowPathConcurrently(); // If you use this, checkIfThresholdCrossedAndSet() may still return false. bool checkIfThresholdCrossedAndSet(CodeBlock*); void setNewThreshold(int32_t threshold, CodeBlock*); void deferIndefinitely(); double count() const { return static_cast(m_totalCount) + m_counter; } void dump(PrintStream&) const; static int32_t maximumExecutionCountsBetweenCheckpoints() { switch (countingVariant) { case CountingForBaseline: return Options::maximumExecutionCountsBetweenCheckpointsForBaseline(); case CountingForUpperTiers: return Options::maximumExecutionCountsBetweenCheckpointsForUpperTiers(); default: RELEASE_ASSERT_NOT_REACHED(); return 0; } } template static T clippedThreshold(JSGlobalObject* globalObject, T threshold) { int32_t maxThreshold; if (Options::randomizeExecutionCountsBetweenCheckpoints()) maxThreshold = globalObject->weakRandomInteger() % maximumExecutionCountsBetweenCheckpoints(); else maxThreshold = maximumExecutionCountsBetweenCheckpoints(); if (threshold > maxThreshold) threshold = maxThreshold; return threshold; } private: bool hasCrossedThreshold(CodeBlock*) const; bool setThreshold(CodeBlock*); void reset(); public: // NB. These are intentionally public because it will be modified from machine code. // This counter is incremented by the JIT or LLInt. It starts out negative and is // counted up until it becomes non-negative. At the start of a counting period, // the threshold we wish to reach is m_totalCount + m_counter, in the sense that // we will add X to m_totalCount and subtract X from m_counter. int32_t m_counter; // Counts the total number of executions we have seen plus the ones we've set a // threshold for in m_counter. Because m_counter's threshold is negative, the // total number of actual executions can always be computed as m_totalCount + // m_counter. float m_totalCount; // This is the threshold we were originally targeting, without any correction for // the memory usage heuristics. int32_t m_activeThreshold; }; typedef ExecutionCounter BaselineExecutionCounter; typedef ExecutionCounter UpperTierExecutionCounter; } // namespace JSC #endif // ExecutionCounter_h