Remove excessive headers from JavaScriptCore
[WebKit-https.git] / Source / JavaScriptCore / bytecode / ValueProfile.h
index 3ff4b4c..ba4ffb7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2013, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -10,7 +10,7 @@
  * 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.
- * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
  *     its contributors may be used to endorse or promote products derived
  *     from this software without specific prior written permission.
  *
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef ValueProfile_h
-#define ValueProfile_h
+#pragma once
 
-#include "JSArray.h"
+#include "ConcurrentJSLock.h"
+#include "SpeculatedType.h"
 #include "Structure.h"
-#include "WriteBarrier.h"
+#include <wtf/PrintStream.h>
+#include <wtf/StringPrintStream.h>
 
 namespace JSC {
 
-#if ENABLE(VALUE_PROFILER)
-struct ValueProfile {
-    static const unsigned logNumberOfBuckets = 3; // 8 buckets
-    static const unsigned numberOfBuckets = 1 << logNumberOfBuckets;
+template<unsigned numberOfBucketsArgument>
+struct ValueProfileBase {
+    static const unsigned numberOfBuckets = numberOfBucketsArgument;
+    static const unsigned numberOfSpecFailBuckets = 1;
     static const unsigned bucketIndexMask = numberOfBuckets - 1;
-    static const unsigned certainty = numberOfBuckets * numberOfBuckets;
-    static const unsigned majority = certainty / 2;
+    static const unsigned totalNumberOfBuckets = numberOfBuckets + numberOfSpecFailBuckets;
     
-    ValueProfile(int bytecodeOffset)
-        : bytecodeOffset(bytecodeOffset)
+    ValueProfileBase()
+        : m_bytecodeOffset(-1)
+        , m_prediction(SpecNone)
+        , m_numberOfSamplesInPrediction(0)
     {
-        for (unsigned i = 0; i < numberOfBuckets; ++i)
-            buckets[i] = JSValue::encode(JSValue());
+        for (unsigned i = 0; i < totalNumberOfBuckets; ++i)
+            m_buckets[i] = JSValue::encode(JSValue());
+    }
+    
+    ValueProfileBase(int bytecodeOffset)
+        : m_bytecodeOffset(bytecodeOffset)
+        , m_prediction(SpecNone)
+        , m_numberOfSamplesInPrediction(0)
+    {
+        for (unsigned i = 0; i < totalNumberOfBuckets; ++i)
+            m_buckets[i] = JSValue::encode(JSValue());
+    }
+    
+    EncodedJSValue* specFailBucket(unsigned i)
+    {
+        ASSERT(numberOfBuckets + i < totalNumberOfBuckets);
+        return m_buckets + numberOfBuckets + i;
     }
     
     const ClassInfo* classInfo(unsigned bucket) const
     {
-        if (!!buckets[bucket]) {
-            JSValue value = JSValue::decode(buckets[bucket]);
+        JSValue value = JSValue::decode(m_buckets[bucket]);
+        if (!!value) {
             if (!value.isCell())
                 return 0;
             return value.asCell()->structure()->classInfo();
         }
-        return weakBuckets[bucket].getClassInfo();
+        return 0;
     }
     
     unsigned numberOfSamples() const
     {
         unsigned result = 0;
-        for (unsigned i = 0; i < numberOfBuckets; ++i) {
-            if (!!buckets[i] || !!weakBuckets[i])
+        for (unsigned i = 0; i < totalNumberOfBuckets; ++i) {
+            if (!!JSValue::decode(m_buckets[i]))
                 result++;
         }
         return result;
     }
     
-    static unsigned computeProbability(unsigned counts, unsigned numberOfSamples)
+    unsigned totalNumberOfSamples() const
     {
-        if (!numberOfSamples)
-            return 0;
-        return counts * certainty / numberOfSamples;
+        return numberOfSamples() + m_numberOfSamplesInPrediction;
     }
     
-    unsigned numberOfInt32s() const
+    bool isLive() const
     {
-        unsigned result = 0;
-        for (unsigned i = 0; i < numberOfBuckets; ++i) {
-            if (!!buckets[i] && JSValue::decode(buckets[i]).isInt32())
-                result++;
-        }
-        return result;
-    }
-        
-    unsigned numberOfDoubles() const
-    {
-        unsigned result = 0;
-        for (unsigned i = 0; i < numberOfBuckets; ++i) {
-            if (!!buckets[i] && JSValue::decode(buckets[i]).isDouble())
-                result++;
-        }
-        return result;
-    }
-        
-    unsigned numberOfCells() const
-    {
-        unsigned result = 0;
-        for (unsigned i = 0; i < numberOfBuckets; ++i) {
-            if (!!classInfo(i))
-                result++;
+        for (unsigned i = 0; i < totalNumberOfBuckets; ++i) {
+            if (!!JSValue::decode(m_buckets[i]))
+                return true;
         }
-        return result;
+        return false;
     }
     
-    unsigned numberOfArrays() const
+    CString briefDescription(const ConcurrentJSLocker& locker)
     {
-        unsigned result = 0;
-        for (unsigned i = 0; i < numberOfBuckets; ++i) {
-            if (classInfo(i) == &JSArray::s_info)
-                result++;
-        }
-        return result;
-    }
-        
-    // These methods are not particularly optimized, in that they will each
-    // perform two passes over the buckets array. However, they are
-    // probably the best bet unless you are sure that you will be making
-    // these calls with high frequency.
+        computeUpdatedPrediction(locker);
         
-    unsigned probabilityOfInt32() const
-    {
-        return computeProbability(numberOfInt32s(), numberOfSamples());
-    }
-        
-    unsigned probabilityOfDouble() const
-    {
-        return computeProbability(numberOfDoubles(), numberOfSamples());
+        StringPrintStream out;
+        out.print("predicting ", SpeculationDump(m_prediction));
+        return out.toCString();
     }
     
-    unsigned probabilityOfCell() const
-    {
-        return computeProbability(numberOfCells(), numberOfSamples());
-    }
-    
-    unsigned probabilityOfArray() const
-    {
-        return computeProbability(numberOfArrays(), numberOfSamples());
-    }
-
-#ifndef NDEBUG
-    void dump(FILE* out)
+    void dump(PrintStream& out)
     {
-        fprintf(out,
-                "samples = %u, int32 = %u, double = %u, cell = %u, array = %u",
-                numberOfSamples(),
-                numberOfInt32s(),
-                numberOfDoubles(),
-                numberOfCells(),
-                numberOfArrays());
+        out.print("samples = ", totalNumberOfSamples(), " prediction = ", SpeculationDump(m_prediction));
         bool first = true;
-        for (unsigned i = 0; i < numberOfBuckets; ++i) {
-            if (!!buckets[i] || !!weakBuckets[i]) {
+        for (unsigned i = 0; i < totalNumberOfBuckets; ++i) {
+            JSValue value = JSValue::decode(m_buckets[i]);
+            if (!!value) {
                 if (first) {
-                    fprintf(out, ": ");
+                    out.printf(": ");
                     first = false;
                 } else
-                    fprintf(out, ", ");
+                    out.printf(", ");
+                out.print(value);
             }
-            
-            if (!!buckets[i])
-                fprintf(out, "%s", JSValue::decode(buckets[i]).description());
-            
-            if (!!weakBuckets[i])
-                fprintf(out, "DeadCell");
         }
     }
-#endif
     
-    struct Statistics {
-        unsigned samples;
-        unsigned int32s;
-        unsigned doubles;
-        unsigned cells;
-        unsigned arrays;
-    };
-
-    // Optimized method for getting all counts at once.
-    void computeStatistics(JSGlobalData& globalData, Statistics& statistics) const
+    // Updates the prediction and returns the new one. Never call this from any thread
+    // that isn't executing the code.
+    SpeculatedType computeUpdatedPrediction(const ConcurrentJSLocker&)
     {
-        unsigned samples = 0;
-        unsigned int32s  = 0;
-        unsigned doubles = 0;
-        unsigned cells   = 0;
-        unsigned arrays  = 0;
-        
-        for (unsigned i = 0; i < numberOfBuckets; ++i) {
-            if (!buckets[i]) {
-                WeakBucket weakBucket = weakBuckets[i];
-                if (!!weakBucket) {
-                    samples++;
-                    cells++;
-                    if (weakBucket.getClassInfo() == &JSArray::s_info)
-                        arrays++;
-                }
-                
+        for (unsigned i = 0; i < totalNumberOfBuckets; ++i) {
+            JSValue value = JSValue::decode(m_buckets[i]);
+            if (!value)
                 continue;
-            }
             
-            samples++;
+            m_numberOfSamplesInPrediction++;
+            mergeSpeculation(m_prediction, speculationFromValue(value));
             
-            JSValue value = JSValue::decode(buckets[i]);
-            if (value.isInt32())
-                int32s++;
-            else if (value.isDouble())
-                doubles++;
-            else if (value.isCell()) {
-                cells++;
-                if (isJSArray(&globalData, value.asCell()))
-                    arrays++;
-            }
+            m_buckets[i] = JSValue::encode(JSValue());
         }
         
-        statistics.samples = samples;
-        statistics.int32s  = int32s;
-        statistics.doubles = doubles;
-        statistics.cells   = cells;
-        statistics.arrays  = arrays;
+        return m_prediction;
     }
     
-    int bytecodeOffset; // -1 for prologue
-    EncodedJSValue buckets[numberOfBuckets];
+    int m_bytecodeOffset; // -1 for prologue
     
-    class WeakBucket {
-    public:
-        WeakBucket()
-            : m_value(0)
-        {
-        }
-        
-        WeakBucket(Structure* structure)
-            : m_value(reinterpret_cast<uintptr_t>(structure))
-        {
-        }
-        
-        WeakBucket(const ClassInfo* classInfo)
-            : m_value(reinterpret_cast<uintptr_t>(classInfo) | 1)
-        {
-        }
-        
-        bool operator!() const
-        {
-            return !m_value;
-        }
-        
-        bool isEmpty() const
-        {
-            return !m_value;
-        }
-        
-        bool isClassInfo() const
-        {
-            return !!(m_value & 1);
-        }
-        
-        bool isStructure() const
-        {
-            return !isEmpty() && !isClassInfo();
-        }
-        
-        Structure* asStructure() const
-        {
-            ASSERT(isStructure());
-            return reinterpret_cast<Structure*>(m_value);
-        }
-        
-        const ClassInfo* asClassInfo() const
-        {
-            ASSERT(isClassInfo());
-            return reinterpret_cast<ClassInfo*>(m_value & ~static_cast<uintptr_t>(1));
-        }
-        
-        const ClassInfo* getClassInfo() const
-        {
-            if (isEmpty())
-                return 0;
-            if (isClassInfo())
-                return asClassInfo();
-            return asStructure()->classInfo();
-        }
-        
-    private:
-        uintptr_t m_value;
-    };
+    SpeculatedType m_prediction;
+    unsigned m_numberOfSamplesInPrediction;
     
-    WeakBucket weakBuckets[numberOfBuckets]; // this is not covered by a write barrier because it is only set from GC
+    EncodedJSValue m_buckets[totalNumberOfBuckets];
 };
 
-inline int getValueProfileBytecodeOffset(ValueProfile* valueProfile)
+struct MinimalValueProfile : public ValueProfileBase<0> {
+    MinimalValueProfile(): ValueProfileBase<0>() { }
+    MinimalValueProfile(int bytecodeOffset): ValueProfileBase<0>(bytecodeOffset) { }
+};
+
+template<unsigned logNumberOfBucketsArgument>
+struct ValueProfileWithLogNumberOfBuckets : public ValueProfileBase<1 << logNumberOfBucketsArgument> {
+    static const unsigned logNumberOfBuckets = logNumberOfBucketsArgument;
+    
+    ValueProfileWithLogNumberOfBuckets()
+        : ValueProfileBase<1 << logNumberOfBucketsArgument>()
+    {
+    }
+    ValueProfileWithLogNumberOfBuckets(int bytecodeOffset)
+        : ValueProfileBase<1 << logNumberOfBucketsArgument>(bytecodeOffset)
+    {
+    }
+};
+
+struct ValueProfile : public ValueProfileWithLogNumberOfBuckets<0> {
+    ValueProfile(): ValueProfileWithLogNumberOfBuckets<0>() { }
+    ValueProfile(int bytecodeOffset): ValueProfileWithLogNumberOfBuckets<0>(bytecodeOffset) { }
+};
+
+template<typename T>
+inline int getValueProfileBytecodeOffset(T* valueProfile)
 {
-    return valueProfile->bytecodeOffset;
+    return valueProfile->m_bytecodeOffset;
 }
-#endif
 
-}
+// This is a mini value profile to catch pathologies. It is a counter that gets
+// incremented when we take the slow path on any instruction.
+struct RareCaseProfile {
+    RareCaseProfile(int bytecodeOffset)
+        : m_bytecodeOffset(bytecodeOffset)
+        , m_counter(0)
+    {
+    }
+    
+    int m_bytecodeOffset;
+    uint32_t m_counter;
+};
 
-#endif
+inline int getRareCaseProfileBytecodeOffset(RareCaseProfile* rareCaseProfile)
+{
+    return rareCaseProfile->m_bytecodeOffset;
+}
 
+} // namespace JSC