/ bytecode / ExecutionCounter.h
ExecutionCounter.h
  1  /*
  2   * Copyright (C) 2012-2017 Apple Inc. All rights reserved.
  3   *
  4   * Redistribution and use in source and binary forms, with or without
  5   * modification, are permitted provided that the following conditions
  6   * are met:
  7   * 1. Redistributions of source code must retain the above copyright
  8   *    notice, this list of conditions and the following disclaimer.
  9   * 2. Redistributions in binary form must reproduce the above copyright
 10   *    notice, this list of conditions and the following disclaimer in the
 11   *    documentation and/or other materials provided with the distribution.
 12   *
 13   * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 17   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21   * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 24   */
 25  
 26  #pragma once
 27  
 28  #include "JSGlobalObject.h"
 29  #include "Options.h"
 30  #include <wtf/PrintStream.h>
 31  
 32  namespace JSC {
 33  
 34  class CodeBlock;
 35  
 36  enum CountingVariant {
 37      CountingForBaseline,
 38      CountingForUpperTiers
 39  };
 40  
 41  double applyMemoryUsageHeuristics(int32_t value, CodeBlock*);
 42  int32_t applyMemoryUsageHeuristicsAndConvertToInt(int32_t value, CodeBlock*);
 43  
 44  inline int32_t formattedTotalExecutionCount(float value)
 45  {
 46      union {
 47          int32_t i;
 48          float f;
 49      } u;
 50      u.f = value;
 51      return u.i;
 52  }
 53  
 54  template<CountingVariant countingVariant>
 55  class ExecutionCounter {
 56      WTF_MAKE_FAST_ALLOCATED;
 57      WTF_MAKE_NONMOVABLE(ExecutionCounter);
 58  public:
 59      ExecutionCounter();
 60      void forceSlowPathConcurrently(); // If you use this, checkIfThresholdCrossedAndSet() may still return false.
 61      bool checkIfThresholdCrossedAndSet(CodeBlock*);
 62      bool hasCrossedThreshold() const { return m_counter >= 0; }
 63      void setNewThreshold(int32_t threshold, CodeBlock*);
 64      void deferIndefinitely();
 65      double count() const { return static_cast<double>(m_totalCount) + m_counter; }
 66      void dump(PrintStream&) const;
 67      
 68      void setNewThresholdForOSRExit(uint32_t activeThreshold, double memoryUsageAdjustedThreshold)
 69      {
 70          m_activeThreshold = activeThreshold;
 71          m_counter = static_cast<int32_t>(-memoryUsageAdjustedThreshold);
 72          m_totalCount = memoryUsageAdjustedThreshold;
 73      }
 74  
 75      static int32_t maximumExecutionCountsBetweenCheckpoints()
 76      {
 77          switch (countingVariant) {
 78          case CountingForBaseline:
 79              return Options::maximumExecutionCountsBetweenCheckpointsForBaseline();
 80          case CountingForUpperTiers:
 81              return Options::maximumExecutionCountsBetweenCheckpointsForUpperTiers();
 82          default:
 83              RELEASE_ASSERT_NOT_REACHED();
 84              return 0;
 85          }
 86      }
 87      
 88      template<typename T>
 89      static T clippedThreshold(JSGlobalObject* globalObject, T threshold)
 90      {
 91          int32_t maxThreshold;
 92          if (Options::randomizeExecutionCountsBetweenCheckpoints() && globalObject)
 93              maxThreshold = globalObject->weakRandomInteger() % maximumExecutionCountsBetweenCheckpoints();
 94          else
 95              maxThreshold = maximumExecutionCountsBetweenCheckpoints();
 96          if (threshold > maxThreshold)
 97              threshold = maxThreshold;
 98          return threshold;
 99      }
100  
101  private:
102      bool hasCrossedThreshold(CodeBlock*) const;
103      bool setThreshold(CodeBlock*);
104      void reset();
105  
106  public:
107      // NB. These are intentionally public because it will be modified from machine code.
108      
109      // This counter is incremented by the JIT or LLInt. It starts out negative and is
110      // counted up until it becomes non-negative. At the start of a counting period,
111      // the threshold we wish to reach is m_totalCount + m_counter, in the sense that
112      // we will add X to m_totalCount and subtract X from m_counter.
113      int32_t m_counter;
114  
115      // Counts the total number of executions we have seen plus the ones we've set a
116      // threshold for in m_counter. Because m_counter's threshold is negative, the
117      // total number of actual executions can always be computed as m_totalCount +
118      // m_counter.
119      float m_totalCount;
120  
121      // This is the threshold we were originally targeting, without any correction for
122      // the memory usage heuristics.
123      int32_t m_activeThreshold;
124  };
125  
126  typedef ExecutionCounter<CountingForBaseline> BaselineExecutionCounter;
127  typedef ExecutionCounter<CountingForUpperTiers> UpperTierExecutionCounter;
128  
129  } // namespace JSC