#pragma once
#include "ConcurrentJSLock.h"
#include "Structure.h"
#include <wtf/SegmentedVector.h>
namespace JSC {
class CodeBlock;
class LLIntOffsetsExtractor;
typedef unsigned ArrayModes;
const ArrayModes CopyOnWriteArrayWithInt32ArrayMode = 1 << 16;
const ArrayModes CopyOnWriteArrayWithDoubleArrayMode = 1 << 17;
const ArrayModes CopyOnWriteArrayWithContiguousArrayMode = 1 << 18;
const ArrayModes Int8ArrayMode = 1 << 19;
const ArrayModes Int16ArrayMode = 1 << 20;
const ArrayModes Int32ArrayMode = 1 << 21;
const ArrayModes Uint8ArrayMode = 1 << 22;
const ArrayModes Uint8ClampedArrayMode = 1 << 23;
const ArrayModes Uint16ArrayMode = 1 << 24;
const ArrayModes Uint32ArrayMode = 1 << 25;
const ArrayModes Float32ArrayMode = 1 << 26;
const ArrayModes Float64ArrayMode = 1 << 27;
inline constexpr ArrayModes asArrayModes(IndexingType indexingMode)
{
if (isCopyOnWrite(indexingMode)) {
switch (indexingMode) {
case CopyOnWriteArrayWithInt32:
return CopyOnWriteArrayWithInt32ArrayMode;
case CopyOnWriteArrayWithDouble:
return CopyOnWriteArrayWithDoubleArrayMode;
case CopyOnWriteArrayWithContiguous:
return CopyOnWriteArrayWithContiguousArrayMode;
default:
UNREACHABLE_FOR_PLATFORM();
return 0;
}
}
return static_cast<unsigned>(1) << static_cast<unsigned>(indexingMode);
}
#define ALL_TYPED_ARRAY_MODES \
(Int8ArrayMode \
| Int16ArrayMode \
| Int32ArrayMode \
| Uint8ArrayMode \
| Uint8ClampedArrayMode \
| Uint16ArrayMode \
| Uint32ArrayMode \
| Float32ArrayMode \
| Float64ArrayMode \
)
#define ALL_NON_ARRAY_ARRAY_MODES \
(asArrayModes(NonArray) \
| asArrayModes(NonArrayWithInt32) \
| asArrayModes(NonArrayWithDouble) \
| asArrayModes(NonArrayWithContiguous) \
| asArrayModes(NonArrayWithArrayStorage) \
| asArrayModes(NonArrayWithSlowPutArrayStorage) \
| ALL_TYPED_ARRAY_MODES)
#define ALL_COPY_ON_WRITE_ARRAY_MODES \
(CopyOnWriteArrayWithInt32ArrayMode \
| CopyOnWriteArrayWithDoubleArrayMode \
| CopyOnWriteArrayWithContiguousArrayMode)
#define ALL_WRITABLE_ARRAY_ARRAY_MODES \
(asArrayModes(ArrayClass) \
| asArrayModes(ArrayWithUndecided) \
| asArrayModes(ArrayWithInt32) \
| asArrayModes(ArrayWithDouble) \
| asArrayModes(ArrayWithContiguous) \
| asArrayModes(ArrayWithArrayStorage) \
| asArrayModes(ArrayWithSlowPutArrayStorage))
#define ALL_ARRAY_ARRAY_MODES \
(ALL_WRITABLE_ARRAY_ARRAY_MODES \
| ALL_COPY_ON_WRITE_ARRAY_MODES)
#define ALL_ARRAY_MODES (ALL_NON_ARRAY_ARRAY_MODES | ALL_ARRAY_ARRAY_MODES)
inline ArrayModes arrayModeFromStructure(Structure* structure)
{
switch (structure->classInfo()->typedArrayStorageType) {
case TypeInt8:
return Int8ArrayMode;
case TypeUint8:
return Uint8ArrayMode;
case TypeUint8Clamped:
return Uint8ClampedArrayMode;
case TypeInt16:
return Int16ArrayMode;
case TypeUint16:
return Uint16ArrayMode;
case TypeInt32:
return Int32ArrayMode;
case TypeUint32:
return Uint32ArrayMode;
case TypeFloat32:
return Float32ArrayMode;
case TypeFloat64:
return Float64ArrayMode;
case TypeDataView:
case NotTypedArray:
break;
}
return asArrayModes(structure->indexingMode());
}
void dumpArrayModes(PrintStream&, ArrayModes);
MAKE_PRINT_ADAPTOR(ArrayModesDump, ArrayModes, dumpArrayModes);
inline bool mergeArrayModes(ArrayModes& left, ArrayModes right)
{
ArrayModes newModes = left | right;
if (newModes == left)
return false;
left = newModes;
return true;
}
inline bool arrayModesAreClearOrTop(ArrayModes modes)
{
return !modes || modes == ALL_ARRAY_MODES;
}
inline bool arrayModesAlreadyChecked(ArrayModes proven, ArrayModes expected)
{
return (expected | proven) == expected;
}
inline bool arrayModesInclude(ArrayModes arrayModes, IndexingType shape)
{
ArrayModes modes = asArrayModes(NonArray | shape) | asArrayModes(ArrayClass | shape);
if (hasInt32(shape) || hasDouble(shape) || hasContiguous(shape))
modes |= asArrayModes(ArrayClass | shape | CopyOnWrite);
return !!(arrayModes & modes);
}
inline bool shouldUseSlowPutArrayStorage(ArrayModes arrayModes)
{
return arrayModesInclude(arrayModes, SlowPutArrayStorageShape);
}
inline bool shouldUseFastArrayStorage(ArrayModes arrayModes)
{
return arrayModesInclude(arrayModes, ArrayStorageShape);
}
inline bool shouldUseContiguous(ArrayModes arrayModes)
{
return arrayModesInclude(arrayModes, ContiguousShape);
}
inline bool shouldUseDouble(ArrayModes arrayModes)
{
return arrayModesInclude(arrayModes, DoubleShape);
}
inline bool shouldUseInt32(ArrayModes arrayModes)
{
return arrayModesInclude(arrayModes, Int32Shape);
}
inline bool hasSeenArray(ArrayModes arrayModes)
{
return arrayModes & ALL_ARRAY_ARRAY_MODES;
}
inline bool hasSeenNonArray(ArrayModes arrayModes)
{
return arrayModes & ALL_NON_ARRAY_ARRAY_MODES;
}
inline bool hasSeenWritableArray(ArrayModes arrayModes)
{
return arrayModes & ALL_WRITABLE_ARRAY_ARRAY_MODES;
}
inline bool hasSeenCopyOnWriteArray(ArrayModes arrayModes)
{
return arrayModes & ALL_COPY_ON_WRITE_ARRAY_MODES;
}
class ArrayProfile {
public:
ArrayProfile()
: m_bytecodeOffset(std::numeric_limits<unsigned>::max())
, m_lastSeenStructureID(0)
, m_mayStoreToHole(false)
, m_outOfBounds(false)
, m_mayInterceptIndexedAccesses(false)
, m_usesOriginalArrayStructures(true)
, m_didPerformFirstRunPruning(false)
, m_observedArrayModes(0)
{
}
ArrayProfile(unsigned bytecodeOffset)
: m_bytecodeOffset(bytecodeOffset)
, m_lastSeenStructureID(0)
, m_mayStoreToHole(false)
, m_outOfBounds(false)
, m_mayInterceptIndexedAccesses(false)
, m_usesOriginalArrayStructures(true)
, m_didPerformFirstRunPruning(false)
, m_observedArrayModes(0)
{
}
unsigned bytecodeOffset() const { return m_bytecodeOffset; }
StructureID* addressOfLastSeenStructureID() { return &m_lastSeenStructureID; }
ArrayModes* addressOfArrayModes() { return &m_observedArrayModes; }
bool* addressOfMayStoreToHole() { return &m_mayStoreToHole; }
void setOutOfBounds() { m_outOfBounds = true; }
bool* addressOfOutOfBounds() { return &m_outOfBounds; }
void observeStructure(Structure* structure)
{
m_lastSeenStructureID = structure->id();
}
void computeUpdatedPrediction(const ConcurrentJSLocker&, CodeBlock*);
void computeUpdatedPrediction(const ConcurrentJSLocker&, CodeBlock*, Structure* lastSeenStructure);
void observeArrayMode(ArrayModes mode) { m_observedArrayModes |= mode; }
void observeIndexedRead(VM&, JSCell*, unsigned index);
ArrayModes observedArrayModes(const ConcurrentJSLocker&) const { return m_observedArrayModes; }
bool mayInterceptIndexedAccesses(const ConcurrentJSLocker&) const { return m_mayInterceptIndexedAccesses; }
bool mayStoreToHole(const ConcurrentJSLocker&) const { return m_mayStoreToHole; }
bool outOfBounds(const ConcurrentJSLocker&) const { return m_outOfBounds; }
bool usesOriginalArrayStructures(const ConcurrentJSLocker&) const { return m_usesOriginalArrayStructures; }
CString briefDescription(const ConcurrentJSLocker&, CodeBlock*);
CString briefDescriptionWithoutUpdating(const ConcurrentJSLocker&);
#if !ASSERT_DISABLED
inline bool isValid() const { return m_typeName == s_typeName; }
#endif
private:
friend class LLIntOffsetsExtractor;
static Structure* polymorphicStructure() { return static_cast<Structure*>(reinterpret_cast<void*>(1)); }
unsigned m_bytecodeOffset;
StructureID m_lastSeenStructureID;
bool m_mayStoreToHole; bool m_outOfBounds;
bool m_mayInterceptIndexedAccesses : 1;
bool m_usesOriginalArrayStructures : 1;
bool m_didPerformFirstRunPruning : 1;
ArrayModes m_observedArrayModes;
#if !ASSERT_DISABLED
static const char* const s_typeName;
const char* m_typeName { s_typeName };
#endif
};
typedef SegmentedVector<ArrayProfile, 4> ArrayProfileVector;
}