1/* 2 * Copyright (C) 2011, 2012 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 Computer, 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 <wtf/Platform.h> 33 34#if ENABLE(VALUE_PROFILER) 35 36#include "Heap.h" 37#include "JSArray.h" 38#include "SpeculatedType.h" 39#include "Structure.h" 40#include "WriteBarrier.h" 41#include <wtf/PrintStream.h> 42#include <wtf/StringPrintStream.h> 43 44namespace JSC { 45 46template<unsigned numberOfBucketsArgument> 47struct ValueProfileBase { 48 static const unsigned numberOfBuckets = numberOfBucketsArgument; 49 static const unsigned numberOfSpecFailBuckets = 1; 50 static const unsigned bucketIndexMask = numberOfBuckets - 1; 51 static const unsigned totalNumberOfBuckets = numberOfBuckets + numberOfSpecFailBuckets; 52 53 ValueProfileBase() 54 : m_bytecodeOffset(-1) 55 , m_prediction(SpecNone) 56 , m_numberOfSamplesInPrediction(0) 57 , m_singletonValueIsTop(false) 58 { 59 for (unsigned i = 0; i < totalNumberOfBuckets; ++i) 60 m_buckets[i] = JSValue::encode(JSValue()); 61 } 62 63 ValueProfileBase(int bytecodeOffset) 64 : m_bytecodeOffset(bytecodeOffset) 65 , m_prediction(SpecNone) 66 , m_numberOfSamplesInPrediction(0) 67 , m_singletonValueIsTop(false) 68 { 69 for (unsigned i = 0; i < totalNumberOfBuckets; ++i) 70 m_buckets[i] = JSValue::encode(JSValue()); 71 } 72 73 EncodedJSValue* specFailBucket(unsigned i) 74 { 75 ASSERT(numberOfBuckets + i < totalNumberOfBuckets); 76 return m_buckets + numberOfBuckets + i; 77 } 78 79 const ClassInfo* classInfo(unsigned bucket) const 80 { 81 JSValue value = JSValue::decode(m_buckets[bucket]); 82 if (!!value) { 83 if (!value.isCell()) 84 return 0; 85 return value.asCell()->structure()->classInfo(); 86 } 87 return 0; 88 } 89 90 unsigned numberOfSamples() const 91 { 92 unsigned result = 0; 93 for (unsigned i = 0; i < totalNumberOfBuckets; ++i) { 94 if (!!JSValue::decode(m_buckets[i])) 95 result++; 96 } 97 return result; 98 } 99 100 unsigned totalNumberOfSamples() const 101 { 102 return numberOfSamples() + m_numberOfSamplesInPrediction; 103 } 104 105 bool isLive() const 106 { 107 for (unsigned i = 0; i < totalNumberOfBuckets; ++i) { 108 if (!!JSValue::decode(m_buckets[i])) 109 return true; 110 } 111 return false; 112 } 113 114 CString briefDescription() 115 { 116 computeUpdatedPrediction(); 117 118 StringPrintStream out; 119 120 if (m_singletonValueIsTop) 121 out.print("predicting ", SpeculationDump(m_prediction)); 122 else if (m_singletonValue) 123 out.print("predicting ", m_singletonValue); 124 125 return out.toCString(); 126 } 127 128 void dump(PrintStream& out) 129 { 130 out.print("samples = ", totalNumberOfSamples(), " prediction = ", SpeculationDump(m_prediction)); 131 out.printf(", value = "); 132 if (m_singletonValueIsTop) 133 out.printf("TOP"); 134 else 135 out.print(m_singletonValue); 136 bool first = true; 137 for (unsigned i = 0; i < totalNumberOfBuckets; ++i) { 138 JSValue value = JSValue::decode(m_buckets[i]); 139 if (!!value) { 140 if (first) { 141 out.printf(": "); 142 first = false; 143 } else 144 out.printf(", "); 145 out.print(value); 146 } 147 } 148 } 149 150 // Updates the prediction and returns the new one. 151 SpeculatedType computeUpdatedPrediction(OperationInProgress operation = NoOperation) 152 { 153 for (unsigned i = 0; i < totalNumberOfBuckets; ++i) { 154 JSValue value = JSValue::decode(m_buckets[i]); 155 if (!value) 156 continue; 157 158 m_numberOfSamplesInPrediction++; 159 mergeSpeculation(m_prediction, speculationFromValue(value)); 160 161 if (!m_singletonValueIsTop && !!value) { 162 if (!m_singletonValue) 163 m_singletonValue = value; 164 else if (m_singletonValue != value) 165 m_singletonValueIsTop = true; 166 } 167 168 m_buckets[i] = JSValue::encode(JSValue()); 169 } 170 171 if (operation == Collection 172 && !m_singletonValueIsTop 173 && !!m_singletonValue 174 && m_singletonValue.isCell() 175 && !Heap::isMarked(m_singletonValue.asCell())) 176 m_singletonValueIsTop = true; 177 178 return m_prediction; 179 } 180 181 int m_bytecodeOffset; // -1 for prologue 182 183 SpeculatedType m_prediction; 184 unsigned m_numberOfSamplesInPrediction; 185 186 bool m_singletonValueIsTop; 187 JSValue m_singletonValue; 188 189 EncodedJSValue m_buckets[totalNumberOfBuckets]; 190}; 191 192struct MinimalValueProfile : public ValueProfileBase<0> { 193 MinimalValueProfile(): ValueProfileBase<0>() { } 194 MinimalValueProfile(int bytecodeOffset): ValueProfileBase<0>(bytecodeOffset) { } 195}; 196 197template<unsigned logNumberOfBucketsArgument> 198struct ValueProfileWithLogNumberOfBuckets : public ValueProfileBase<1 << logNumberOfBucketsArgument> { 199 static const unsigned logNumberOfBuckets = logNumberOfBucketsArgument; 200 201 ValueProfileWithLogNumberOfBuckets() 202 : ValueProfileBase<1 << logNumberOfBucketsArgument>() 203 { 204 } 205 ValueProfileWithLogNumberOfBuckets(int bytecodeOffset) 206 : ValueProfileBase<1 << logNumberOfBucketsArgument>(bytecodeOffset) 207 { 208 } 209}; 210 211struct ValueProfile : public ValueProfileWithLogNumberOfBuckets<0> { 212 ValueProfile(): ValueProfileWithLogNumberOfBuckets<0>() { } 213 ValueProfile(int bytecodeOffset): ValueProfileWithLogNumberOfBuckets<0>(bytecodeOffset) { } 214}; 215 216template<typename T> 217inline int getValueProfileBytecodeOffset(T* valueProfile) 218{ 219 return valueProfile->m_bytecodeOffset; 220} 221 222// This is a mini value profile to catch pathologies. It is a counter that gets 223// incremented when we take the slow path on any instruction. 224struct RareCaseProfile { 225 RareCaseProfile(int bytecodeOffset) 226 : m_bytecodeOffset(bytecodeOffset) 227 , m_counter(0) 228 { 229 } 230 231 int m_bytecodeOffset; 232 uint32_t m_counter; 233}; 234 235inline int getRareCaseProfileBytecodeOffset(RareCaseProfile* rareCaseProfile) 236{ 237 return rareCaseProfile->m_bytecodeOffset; 238} 239 240} // namespace JSC 241 242#endif // ENABLE(VALUE_PROFILER) 243 244#endif // ValueProfile_h 245 246