Changeset 251090 in webkit for trunk/Source/JavaScriptCore/bytecode/ArithProfile.h
- Timestamp:
- Oct 14, 2019, 1:28:41 PM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/bytecode/ArithProfile.h
r240138 r251090 67 67 }; 68 68 69 struct ArithProfile { 70 private: 71 static constexpr uint32_t numberOfFlagBits = 6; 72 static constexpr uint32_t rhsResultTypeShift = numberOfFlagBits; 73 static constexpr uint32_t lhsResultTypeShift = rhsResultTypeShift + ResultType::numBitsNeeded; 74 static constexpr uint32_t rhsObservedTypeShift = lhsResultTypeShift + ResultType::numBitsNeeded; 75 static constexpr uint32_t lhsObservedTypeShift = rhsObservedTypeShift + ObservedType::numBitsNeeded; 76 77 static_assert(ObservedType::numBitsNeeded == 3, "We make a hard assumption about that here."); 78 static constexpr uint32_t clearRhsObservedTypeBitMask = static_cast<uint32_t>(~((1 << rhsObservedTypeShift) | (1 << (rhsObservedTypeShift + 1)) | (1 << (rhsObservedTypeShift + 2)))); 79 static constexpr uint32_t clearLhsObservedTypeBitMask = static_cast<uint32_t>(~((1 << lhsObservedTypeShift) | (1 << (lhsObservedTypeShift + 1)) | (1 << (lhsObservedTypeShift + 2)))); 80 81 static constexpr uint32_t resultTypeMask = (1 << ResultType::numBitsNeeded) - 1; 82 static constexpr uint32_t observedTypeMask = (1 << ObservedType::numBitsNeeded) - 1; 83 84 enum class ConstantTag { Constant }; 85 69 template <typename BitfieldType> 70 class ArithProfile { 86 71 public: 87 static constexpr uint32_t specialFastPathBit = 1 << (lhsObservedTypeShift + ObservedType::numBitsNeeded);88 static_assert((lhsObservedTypeShift + ObservedType::numBitsNeeded) <= (sizeof(uint32_t) * 8) - 1, "Should fit in a uint32_t.");89 static_assert(!(specialFastPathBit & ~clearLhsObservedTypeBitMask), "These bits should not intersect.");90 static_assert(specialFastPathBit & clearLhsObservedTypeBitMask, "These bits should intersect.");91 static_assert(specialFastPathBit > ~clearLhsObservedTypeBitMask, "These bits should not intersect and specialFastPathBit should be a higher bit.");92 93 ArithProfile(ResultType arg)94 : ArithProfile(ConstantTag::Constant, arg)95 {96 ASSERT(lhsResultType().bits() == arg.bits());97 ASSERT(lhsObservedType().isEmpty());98 ASSERT(rhsObservedType().isEmpty());99 }100 101 ArithProfile(ResultType lhs, ResultType rhs)102 : ArithProfile(ConstantTag::Constant, lhs, rhs)103 {104 ASSERT(lhsResultType().bits() == lhs.bits() && rhsResultType().bits() == rhs.bits());105 ASSERT(lhsObservedType().isEmpty());106 ASSERT(rhsObservedType().isEmpty());107 }108 109 ArithProfile(OperandTypes types)110 : ArithProfile(types.first(), types.second())111 { }112 113 ArithProfile() = default;114 115 static constexpr ArithProfile fromInt(uint32_t bits)116 {117 return ArithProfile { ConstantTag::Constant, bits };118 }119 120 static constexpr ArithProfile observedUnaryInt()121 {122 constexpr ObservedType observedInt32 { ObservedType().withInt32() };123 constexpr uint32_t bits = observedInt32.bits() << lhsObservedTypeShift;124 static_assert(bits == 0x800000, "");125 return fromInt(bits);126 }127 static constexpr ArithProfile observedUnaryNumber()128 {129 constexpr ObservedType observedNumber { ObservedType().withNumber() };130 constexpr uint32_t bits = observedNumber.bits() << lhsObservedTypeShift;131 static_assert(bits == 0x1000000, "");132 return fromInt(bits);133 }134 static constexpr ArithProfile observedBinaryIntInt()135 {136 constexpr ObservedType observedInt32 { ObservedType().withInt32() };137 constexpr uint32_t bits = (observedInt32.bits() << lhsObservedTypeShift) | (observedInt32.bits() << rhsObservedTypeShift);138 static_assert(bits == 0x900000, "");139 return fromInt(bits);140 }141 static constexpr ArithProfile observedBinaryNumberInt()142 {143 constexpr ObservedType observedNumber { ObservedType().withNumber() };144 constexpr ObservedType observedInt32 { ObservedType().withInt32() };145 constexpr uint32_t bits = (observedNumber.bits() << lhsObservedTypeShift) | (observedInt32.bits() << rhsObservedTypeShift);146 static_assert(bits == 0x1100000, "");147 return fromInt(bits);148 }149 static constexpr ArithProfile observedBinaryIntNumber()150 {151 constexpr ObservedType observedNumber { ObservedType().withNumber() };152 constexpr ObservedType observedInt32 { ObservedType().withInt32() };153 constexpr uint32_t bits = (observedInt32.bits() << lhsObservedTypeShift) | (observedNumber.bits() << rhsObservedTypeShift);154 static_assert(bits == 0xa00000, "");155 return fromInt(bits);156 }157 static constexpr ArithProfile observedBinaryNumberNumber()158 {159 constexpr ObservedType observedNumber { ObservedType().withNumber() };160 constexpr uint32_t bits = (observedNumber.bits() << lhsObservedTypeShift) | (observedNumber.bits() << rhsObservedTypeShift);161 static_assert(bits == 0x1200000, "");162 return fromInt(bits);163 }164 165 72 enum ObservedResults { 166 73 NonNegZeroDouble = 1 << 0, … … 171 78 BigInt = 1 << 5, 172 79 }; 173 174 ResultType lhsResultType() const { return ResultType((m_bits >> lhsResultTypeShift) & resultTypeMask); } 175 ResultType rhsResultType() const { return ResultType((m_bits >> rhsResultTypeShift) & resultTypeMask); } 176 177 constexpr ObservedType lhsObservedType() const { return ObservedType((m_bits >> lhsObservedTypeShift) & observedTypeMask); } 178 constexpr ObservedType rhsObservedType() const { return ObservedType((m_bits >> rhsObservedTypeShift) & observedTypeMask); } 179 void setLhsObservedType(ObservedType type) 180 { 181 uint32_t bits = m_bits; 182 bits &= clearLhsObservedTypeBitMask; 183 bits |= type.bits() << lhsObservedTypeShift; 184 m_bits = bits; 185 ASSERT(lhsObservedType() == type); 186 } 187 188 void setRhsObservedType(ObservedType type) 189 { 190 uint32_t bits = m_bits; 191 bits &= clearRhsObservedTypeBitMask; 192 bits |= type.bits() << rhsObservedTypeShift; 193 m_bits = bits; 194 ASSERT(rhsObservedType() == type); 195 } 196 197 bool tookSpecialFastPath() const { return m_bits & specialFastPathBit; } 80 static constexpr uint32_t observedResultsNumBitsNeeded = 6; 198 81 199 82 bool didObserveNonInt32() const { return hasBits(NonNegZeroDouble | NegZeroDouble | NonNumeric | BigInt); } … … 212 95 void setObservedInt32Overflow() { setBit(Int32Overflow); } 213 96 void setObservedInt52Overflow() { setBit(Int52Overflow); } 214 215 const void* addressOfBits() const { return &m_bits; }216 97 217 98 void observeResult(JSValue value) … … 230 111 } 231 112 113 const void* addressOfBits() const { return &m_bits; } 114 115 #if ENABLE(JIT) 116 // Sets (Int32Overflow | Int52Overflow | NonNegZeroDouble | NegZeroDouble) if it sees a 117 // double. Sets NonNumeric if it sees a non-numeric. 118 void emitObserveResult(CCallHelpers&, JSValueRegs, TagRegistersMode = HaveTagRegisters); 119 120 // Sets (Int32Overflow | Int52Overflow | NonNegZeroDouble | NegZeroDouble). 121 bool shouldEmitSetDouble() const; 122 void emitSetDouble(CCallHelpers&) const; 123 124 // Sets NonNumber. 125 void emitSetNonNumeric(CCallHelpers&) const; 126 bool shouldEmitSetNonNumeric() const; 127 128 // Sets BigInt 129 void emitSetBigInt(CCallHelpers&) const; 130 bool shouldEmitSetBigInt() const; 131 #endif // ENABLE(JIT) 132 133 constexpr uint32_t bits() const { return m_bits; } 134 135 protected: 136 ArithProfile(BitfieldType bits) 137 : m_bits(bits) 138 { 139 } 140 141 bool hasBits(int mask) const { return m_bits & mask; } 142 void setBit(int mask) { m_bits |= mask; } 143 144 BitfieldType m_bits { 0 }; // We take care to update m_bits only in a single operation. We don't ever store an inconsistent bit representation to it. 145 }; 146 147 /* This class stores the following components in 16 bits: 148 * - ObservedResults 149 * - ResultType for the argument 150 * - ObservedType for the argument 151 */ 152 class UnaryArithProfile : public ArithProfile<uint16_t> { 153 static constexpr unsigned argResultTypeShift = observedResultsNumBitsNeeded; 154 static constexpr unsigned argObservedTypeShift = argResultTypeShift + ResultType::numBitsNeeded; 155 156 static_assert(argObservedTypeShift + ObservedType::numBitsNeeded <= sizeof(uint16_t) * 8, "Should fit in a uint16_t"); 157 158 static constexpr uint16_t clearArgObservedTypeBitMask = static_cast<uint16_t>(~(0b111 << argObservedTypeShift)); 159 160 static constexpr uint16_t resultTypeMask = (1 << ResultType::numBitsNeeded) - 1; 161 static constexpr uint16_t observedTypeMask = (1 << ObservedType::numBitsNeeded) - 1; 162 163 public: 164 UnaryArithProfile(ResultType arg) 165 : ArithProfile<uint16_t>(arg.bits() << argResultTypeShift) 166 { 167 ASSERT(argResultType().bits() == arg.bits()); 168 ASSERT(argObservedType().isEmpty()); 169 ASSERT(argObservedType().isEmpty()); 170 } 171 172 UnaryArithProfile() 173 : UnaryArithProfile(ResultType::unknownType()) 174 { 175 } 176 177 static constexpr uint16_t observedIntBits() 178 { 179 constexpr ObservedType observedInt32 { ObservedType().withInt32() }; 180 constexpr uint16_t bits = observedInt32.bits() << argObservedTypeShift; 181 static_assert(bits == 0x2000, ""); 182 return bits; 183 } 184 static constexpr uint16_t observedNumberBits() 185 { 186 constexpr ObservedType observedNumber { ObservedType().withNumber() }; 187 constexpr uint16_t bits = observedNumber.bits() << argObservedTypeShift; 188 static_assert(bits == 0x4000, ""); 189 return bits; 190 } 191 192 ResultType argResultType() const { return ResultType((m_bits >> argResultTypeShift) & resultTypeMask); } 193 194 constexpr ObservedType argObservedType() const { return ObservedType((m_bits >> argObservedTypeShift) & observedTypeMask); } 195 void setArgObservedType(ObservedType type) 196 { 197 uint16_t bits = m_bits; 198 bits &= clearArgObservedTypeBitMask; 199 bits |= type.bits() << argObservedTypeShift; 200 m_bits = bits; 201 ASSERT(argObservedType() == type); 202 } 203 204 void argSawInt32() { setArgObservedType(argObservedType().withInt32()); } 205 void argSawNumber() { setArgObservedType(argObservedType().withNumber()); } 206 void argSawNonNumber() { setArgObservedType(argObservedType().withNonNumber()); } 207 208 void observeArg(JSValue arg) 209 { 210 UnaryArithProfile newProfile = *this; 211 if (arg.isNumber()) { 212 if (arg.isInt32()) 213 newProfile.argSawInt32(); 214 else 215 newProfile.argSawNumber(); 216 } else 217 newProfile.argSawNonNumber(); 218 219 m_bits = newProfile.bits(); 220 } 221 222 bool isObservedTypeEmpty() 223 { 224 return argObservedType().isEmpty(); 225 } 226 227 friend class JSC::LLIntOffsetsExtractor; 228 }; 229 230 /* This class stores the following components in 32 bits: 231 * - ObservedResults 232 * - ResultType for right-hand-side 233 * - ResultType for left-hand-side 234 * - ObservedType for right-hand-side 235 * - ObservedType for left-hand-side 236 * - a bit used by division to indicate whether a special fast path was taken 237 */ 238 class BinaryArithProfile : public ArithProfile<uint32_t> { 239 static constexpr uint32_t rhsResultTypeShift = observedResultsNumBitsNeeded; 240 static constexpr uint32_t lhsResultTypeShift = rhsResultTypeShift + ResultType::numBitsNeeded; 241 static constexpr uint32_t rhsObservedTypeShift = lhsResultTypeShift + ResultType::numBitsNeeded; 242 static constexpr uint32_t lhsObservedTypeShift = rhsObservedTypeShift + ObservedType::numBitsNeeded; 243 244 static_assert(ObservedType::numBitsNeeded == 3, "We make a hard assumption about that here."); 245 static constexpr uint32_t clearRhsObservedTypeBitMask = static_cast<uint32_t>(~(0b111 << rhsObservedTypeShift)); 246 static constexpr uint32_t clearLhsObservedTypeBitMask = static_cast<uint32_t>(~(0b111 << lhsObservedTypeShift)); 247 248 static constexpr uint32_t resultTypeMask = (1 << ResultType::numBitsNeeded) - 1; 249 static constexpr uint32_t observedTypeMask = (1 << ObservedType::numBitsNeeded) - 1; 250 251 public: 252 static constexpr uint32_t specialFastPathBit = 1 << (lhsObservedTypeShift + ObservedType::numBitsNeeded); 253 static_assert((lhsObservedTypeShift + ObservedType::numBitsNeeded + 1) <= sizeof(uint32_t) * 8, "Should fit in a uint32_t."); 254 static_assert(!(specialFastPathBit & ~clearLhsObservedTypeBitMask), "These bits should not intersect."); 255 static_assert(specialFastPathBit & clearLhsObservedTypeBitMask, "These bits should intersect."); 256 static_assert(specialFastPathBit > ~clearLhsObservedTypeBitMask, "These bits should not intersect and specialFastPathBit should be a higher bit."); 257 258 BinaryArithProfile(ResultType lhs, ResultType rhs) 259 : ArithProfile<uint32_t>((lhs.bits() << lhsResultTypeShift) | (rhs.bits() << rhsResultTypeShift)) 260 { 261 ASSERT(lhsResultType().bits() == lhs.bits() && rhsResultType().bits() == rhs.bits()); 262 ASSERT(lhsObservedType().isEmpty()); 263 ASSERT(rhsObservedType().isEmpty()); 264 } 265 266 BinaryArithProfile(OperandTypes types) 267 : BinaryArithProfile(types.first(), types.second()) 268 { } 269 270 BinaryArithProfile() 271 : BinaryArithProfile(ResultType::unknownType(), ResultType::unknownType()) 272 { 273 } 274 275 static constexpr uint32_t observedIntIntBits() 276 { 277 constexpr ObservedType observedInt32 { ObservedType().withInt32() }; 278 constexpr uint32_t bits = (observedInt32.bits() << lhsObservedTypeShift) | (observedInt32.bits() << rhsObservedTypeShift); 279 static_assert(bits == 0x900000, ""); 280 return bits; 281 } 282 static constexpr uint32_t observedNumberIntBits() 283 { 284 constexpr ObservedType observedNumber { ObservedType().withNumber() }; 285 constexpr ObservedType observedInt32 { ObservedType().withInt32() }; 286 constexpr uint32_t bits = (observedNumber.bits() << lhsObservedTypeShift) | (observedInt32.bits() << rhsObservedTypeShift); 287 static_assert(bits == 0x1100000, ""); 288 return bits; 289 } 290 static constexpr uint32_t observedIntNumberBits() 291 { 292 constexpr ObservedType observedNumber { ObservedType().withNumber() }; 293 constexpr ObservedType observedInt32 { ObservedType().withInt32() }; 294 constexpr uint32_t bits = (observedInt32.bits() << lhsObservedTypeShift) | (observedNumber.bits() << rhsObservedTypeShift); 295 static_assert(bits == 0xa00000, ""); 296 return bits; 297 } 298 static constexpr uint32_t observedNumberNumberBits() 299 { 300 constexpr ObservedType observedNumber { ObservedType().withNumber() }; 301 constexpr uint32_t bits = (observedNumber.bits() << lhsObservedTypeShift) | (observedNumber.bits() << rhsObservedTypeShift); 302 static_assert(bits == 0x1200000, ""); 303 return bits; 304 } 305 306 ResultType lhsResultType() const { return ResultType((m_bits >> lhsResultTypeShift) & resultTypeMask); } 307 ResultType rhsResultType() const { return ResultType((m_bits >> rhsResultTypeShift) & resultTypeMask); } 308 309 constexpr ObservedType lhsObservedType() const { return ObservedType((m_bits >> lhsObservedTypeShift) & observedTypeMask); } 310 constexpr ObservedType rhsObservedType() const { return ObservedType((m_bits >> rhsObservedTypeShift) & observedTypeMask); } 311 void setLhsObservedType(ObservedType type) 312 { 313 uint32_t bits = m_bits; 314 bits &= clearLhsObservedTypeBitMask; 315 bits |= type.bits() << lhsObservedTypeShift; 316 m_bits = bits; 317 ASSERT(lhsObservedType() == type); 318 } 319 320 void setRhsObservedType(ObservedType type) 321 { 322 uint32_t bits = m_bits; 323 bits &= clearRhsObservedTypeBitMask; 324 bits |= type.bits() << rhsObservedTypeShift; 325 m_bits = bits; 326 ASSERT(rhsObservedType() == type); 327 } 328 329 bool tookSpecialFastPath() const { return m_bits & specialFastPathBit; } 330 232 331 void lhsSawInt32() { setLhsObservedType(lhsObservedType().withInt32()); } 233 332 void lhsSawNumber() { setLhsObservedType(lhsObservedType().withNumber()); } … … 239 338 void observeLHS(JSValue lhs) 240 339 { 241 ArithProfile newProfile = *this;340 BinaryArithProfile newProfile = *this; 242 341 if (lhs.isNumber()) { 243 342 if (lhs.isInt32()) … … 255 354 observeLHS(lhs); 256 355 257 ArithProfile newProfile = *this;356 BinaryArithProfile newProfile = *this; 258 357 if (rhs.isNumber()) { 259 358 if (rhs.isInt32()) … … 267 366 } 268 367 269 #if ENABLE(JIT) 270 // Sets (Int32Overflow | Int52Overflow | NonNegZeroDouble | NegZeroDouble) if it sees a 271 // double. Sets NonNumeric if it sees a non-numeric. 272 void emitObserveResult(CCallHelpers&, JSValueRegs, TagRegistersMode = HaveTagRegisters); 273 274 // Sets (Int32Overflow | Int52Overflow | NonNegZeroDouble | NegZeroDouble). 275 bool shouldEmitSetDouble() const; 276 void emitSetDouble(CCallHelpers&) const; 277 278 // Sets NonNumber. 279 void emitSetNonNumeric(CCallHelpers&) const; 280 bool shouldEmitSetNonNumeric() const; 281 282 // Sets BigInt 283 void emitSetBigInt(CCallHelpers&) const; 284 bool shouldEmitSetBigInt() const; 285 #endif // ENABLE(JIT) 286 287 constexpr uint32_t bits() const { return m_bits; } 288 289 private: 290 constexpr explicit ArithProfile(ConstantTag, uint32_t bits) 291 : m_bits(bits) 292 { 293 } 294 295 constexpr ArithProfile(ConstantTag, ResultType arg) 296 : m_bits(arg.bits() << lhsResultTypeShift) 297 { 298 } 299 300 constexpr ArithProfile(ConstantTag, ResultType lhs, ResultType rhs) 301 : m_bits((lhs.bits() << lhsResultTypeShift) | (rhs.bits() << rhsResultTypeShift)) 302 { 303 } 304 305 bool hasBits(int mask) const { return m_bits & mask; } 306 void setBit(int mask) { m_bits |= mask; } 307 308 uint32_t m_bits { 0 }; // We take care to update m_bits only in a single operation. We don't ever store an inconsistent bit representation to it. 368 bool isObservedTypeEmpty() 369 { 370 return lhsObservedType().isEmpty() && rhsObservedType().isEmpty(); 371 } 309 372 310 373 friend class JSC::LLIntOffsetsExtractor; … … 315 378 namespace WTF { 316 379 317 void printInternal(PrintStream&, const JSC::ArithProfile&); 380 void printInternal(PrintStream&, const JSC::UnaryArithProfile&); 381 void printInternal(PrintStream&, const JSC::BinaryArithProfile&); 318 382 void printInternal(PrintStream&, const JSC::ObservedType&); 319 383
Note:
See TracChangeset
for help on using the changeset viewer.