#pragma once
#if ENABLE(WEBASSEMBLY)
#include "B3Type.h"
#include "WasmOps.h"
#include <cstdint>
#include <cstring>
#include <wtf/CheckedArithmetic.h>
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
#include <wtf/HashTraits.h>
#include <wtf/StdLibExtras.h>
#include <wtf/ThreadSafeRefCounted.h>
#include <wtf/Vector.h>
namespace WTF {
class PrintStream;
}
namespace JSC {
namespace Wasm {
using SignatureArgCount = uint32_t;
using SignatureIndex = uint64_t;
class Signature : public ThreadSafeRefCounted<Signature> {
WTF_MAKE_FAST_ALLOCATED;
Signature() = delete;
Signature(const Signature&) = delete;
Signature(SignatureArgCount retCount, SignatureArgCount argCount)
: m_retCount(retCount)
, m_argCount(argCount)
{
}
Type* storage(SignatureArgCount i)
{
return i + reinterpret_cast<Type*>(reinterpret_cast<char*>(this) + sizeof(Signature));
}
Type* storage(SignatureArgCount i) const { return const_cast<Signature*>(this)->storage(i); }
static size_t allocatedSize(Checked<SignatureArgCount> retCount, Checked<SignatureArgCount> argCount)
{
return (sizeof(Signature) + (retCount + argCount) * sizeof(Type)).unsafeGet();
}
public:
SignatureArgCount returnCount() const { return m_retCount; }
SignatureArgCount argumentCount() const { return m_argCount; }
Type returnType(SignatureArgCount i) const { ASSERT(i < returnCount()); return const_cast<Signature*>(this)->getReturnType(i); }
bool returnsVoid() const { return !returnCount(); }
Type argument(SignatureArgCount i) const { return const_cast<Signature*>(this)->getArgument(i); }
SignatureIndex index() const { return bitwise_cast<SignatureIndex>(this); }
WTF::String toString() const;
void dump(WTF::PrintStream& out) const;
bool operator==(const Signature& rhs) const { return this == &rhs; }
unsigned hash() const;
static const constexpr SignatureIndex invalidIndex = 0;
private:
friend class SignatureInformation;
friend struct ParameterTypes;
static RefPtr<Signature> tryCreate(SignatureArgCount returnCount, SignatureArgCount argumentCount);
Type& getReturnType(SignatureArgCount i) { ASSERT(i < returnCount()); return *storage(i); }
Type& getArgument(SignatureArgCount i) { ASSERT(i < argumentCount()); return *storage(returnCount() + i); }
SignatureArgCount m_retCount;
SignatureArgCount m_argCount;
};
struct SignatureHash {
RefPtr<Signature> key { nullptr };
SignatureHash() = default;
explicit SignatureHash(Ref<Signature>&& key)
: key(WTFMove(key))
{ }
explicit SignatureHash(WTF::HashTableDeletedValueType)
: key(WTF::HashTableDeletedValue)
{ }
bool operator==(const SignatureHash& rhs) const { return equal(*this, rhs); }
static bool equal(const SignatureHash& lhs, const SignatureHash& rhs) { return lhs.key == rhs.key; }
static unsigned hash(const SignatureHash& signature) { return signature.key ? signature.key->hash() : 0; }
static constexpr bool safeToCompareToEmptyOrDeleted = false;
bool isHashTableDeletedValue() const { return key.isHashTableDeletedValue(); }
};
} }
namespace WTF {
template<typename T> struct DefaultHash;
template<> struct DefaultHash<JSC::Wasm::SignatureHash> : JSC::Wasm::SignatureHash { };
template<typename T> struct HashTraits;
template<> struct HashTraits<JSC::Wasm::SignatureHash> : SimpleClassHashTraits<JSC::Wasm::SignatureHash> {
static constexpr bool emptyValueIsZero = true;
};
}
namespace JSC { namespace Wasm {
class SignatureInformation {
WTF_MAKE_NONCOPYABLE(SignatureInformation);
WTF_MAKE_FAST_ALLOCATED;
SignatureInformation();
public:
static SignatureInformation& singleton();
static RefPtr<Signature> signatureFor(const Vector<Type, 1>& returnTypes, const Vector<Type>& argumentTypes);
ALWAYS_INLINE const Signature* thunkFor(Type type) const { return thunkSignatures[linearizeType(type)]; }
static const Signature& get(SignatureIndex);
static SignatureIndex get(const Signature&);
static void tryCleanup();
private:
HashSet<Wasm::SignatureHash> m_signatureSet;
const Signature* thunkSignatures[numTypes];
Lock m_lock;
JS_EXPORT_PRIVATE static SignatureInformation* theOne;
JS_EXPORT_PRIVATE static std::once_flag signatureInformationFlag;
};
} }
#endif // ENABLE(WEBASSEMBLY)