1/* 2 * Copyright (C) 2011, 2012, 2013 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 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#ifndef ValueProfile_h 30#define ValueProfile_h 31 32#include "ConcurrentJITLock.h" 33#include "Heap.h" 34#include "JSArray.h" 35#include "SpeculatedType.h" 36#include "Structure.h" 37#include "WriteBarrier.h" 38#include <wtf/PrintStream.h> 39#include <wtf/StringPrintStream.h> 40 41namespace JSC { 42 43template<unsigned numberOfBucketsArgument> 44struct ValueProfileBase { 45 static const unsigned numberOfBuckets = numberOfBucketsArgument; 46 static const unsigned numberOfSpecFailBuckets = 1; 47 static const unsigned bucketIndexMask = numberOfBuckets - 1; 48 static const unsigned totalNumberOfBuckets = numberOfBuckets + numberOfSpecFailBuckets; 49 50 ValueProfileBase() 51 : m_bytecodeOffset(-1) 52 , m_prediction(SpecNone) 53 , m_numberOfSamplesInPrediction(0) 54 { 55 for (unsigned i = 0; i < totalNumberOfBuckets; ++i) 56 m_buckets[i] = JSValue::encode(JSValue()); 57 } 58 59 ValueProfileBase(int bytecodeOffset) 60 : m_bytecodeOffset(bytecodeOffset) 61 , m_prediction(SpecNone) 62 , m_numberOfSamplesInPrediction(0) 63 { 64 for (unsigned i = 0; i < totalNumberOfBuckets; ++i) 65 m_buckets[i] = JSValue::encode(JSValue()); 66 } 67 68 EncodedJSValue* specFailBucket(unsigned i) 69 { 70 ASSERT(numberOfBuckets + i < totalNumberOfBuckets); 71 return m_buckets + numberOfBuckets + i; 72 } 73 74 const ClassInfo* classInfo(unsigned bucket) const 75 { 76 JSValue value = JSValue::decode(m_buckets[bucket]); 77 if (!!value) { 78 if (!value.isCell()) 79 return 0; 80 return value.asCell()->structure()->classInfo(); 81 } 82 return 0; 83 } 84 85 unsigned numberOfSamples() const 86 { 87 unsigned result = 0; 88 for (unsigned i = 0; i < totalNumberOfBuckets; ++i) { 89 if (!!JSValue::decode(m_buckets[i])) 90 result++; 91 } 92 return result; 93 } 94 95 unsigned totalNumberOfSamples() const 96 { 97 return numberOfSamples() + m_numberOfSamplesInPrediction; 98 } 99 100 bool isLive() const 101 { 102 for (unsigned i = 0; i < totalNumberOfBuckets; ++i) { 103 if (!!JSValue::decode(m_buckets[i])) 104 return true; 105 } 106 return false; 107 } 108 109 CString briefDescription(const ConcurrentJITLocker& locker) 110 { 111 computeUpdatedPrediction(locker); 112 113 StringPrintStream out; 114 out.print("predicting ", SpeculationDump(m_prediction)); 115 return out.toCString(); 116 } 117 118 void dump(PrintStream& out) 119 { 120 out.print("samples = ", totalNumberOfSamples(), " prediction = ", SpeculationDump(m_prediction)); 121 bool first = true; 122 for (unsigned i = 0; i < totalNumberOfBuckets; ++i) { 123 JSValue value = JSValue::decode(m_buckets[i]); 124 if (!!value) { 125 if (first) { 126 out.printf(": "); 127 first = false; 128 } else 129 out.printf(", "); 130 out.print(value); 131 } 132 } 133 } 134 135 // Updates the prediction and returns the new one. Never call this from any thread 136 // that isn't executing the code. 137 SpeculatedType computeUpdatedPrediction(const ConcurrentJITLocker&) 138 { 139 for (unsigned i = 0; i < totalNumberOfBuckets; ++i) { 140 JSValue value = JSValue::decode(m_buckets[i]); 141 if (!value) 142 continue; 143 144 m_numberOfSamplesInPrediction++; 145 mergeSpeculation(m_prediction, speculationFromValue(value)); 146 147 m_buckets[i] = JSValue::encode(JSValue()); 148 } 149 150 return m_prediction; 151 } 152 153 int m_bytecodeOffset; // -1 for prologue 154 155 SpeculatedType m_prediction; 156 unsigned m_numberOfSamplesInPrediction; 157 158 EncodedJSValue m_buckets[totalNumberOfBuckets]; 159}; 160 161struct MinimalValueProfile : public ValueProfileBase<0> { 162 MinimalValueProfile(): ValueProfileBase<0>() { } 163 MinimalValueProfile(int bytecodeOffset): ValueProfileBase<0>(bytecodeOffset) { } 164}; 165 166template<unsigned logNumberOfBucketsArgument> 167struct ValueProfileWithLogNumberOfBuckets : public ValueProfileBase<1 << logNumberOfBucketsArgument> { 168 static const unsigned logNumberOfBuckets = logNumberOfBucketsArgument; 169 170 ValueProfileWithLogNumberOfBuckets() 171 : ValueProfileBase<1 << logNumberOfBucketsArgument>() 172 { 173 } 174 ValueProfileWithLogNumberOfBuckets(int bytecodeOffset) 175 : ValueProfileBase<1 << logNumberOfBucketsArgument>(bytecodeOffset) 176 { 177 } 178}; 179 180struct ValueProfile : public ValueProfileWithLogNumberOfBuckets<0> { 181 ValueProfile(): ValueProfileWithLogNumberOfBuckets<0>() { } 182 ValueProfile(int bytecodeOffset): ValueProfileWithLogNumberOfBuckets<0>(bytecodeOffset) { } 183}; 184 185template<typename T> 186inline int getValueProfileBytecodeOffset(T* valueProfile) 187{ 188 return valueProfile->m_bytecodeOffset; 189} 190 191// This is a mini value profile to catch pathologies. It is a counter that gets 192// incremented when we take the slow path on any instruction. 193struct RareCaseProfile { 194 RareCaseProfile(int bytecodeOffset) 195 : m_bytecodeOffset(bytecodeOffset) 196 , m_counter(0) 197 { 198 } 199 200 int m_bytecodeOffset; 201 uint32_t m_counter; 202}; 203 204inline int getRareCaseProfileBytecodeOffset(RareCaseProfile* rareCaseProfile) 205{ 206 return rareCaseProfile->m_bytecodeOffset; 207} 208 209} // namespace JSC 210 211#endif // ValueProfile_h 212 213