#pragma once
#include "ExecutableBaseInlines.h"
#include "FunctionExecutable.h"
#include "JSCast.h"
#include "JSFunction.h"
#include "NativeExecutable.h"
namespace JSC {
class CallVariant {
WTF_MAKE_FAST_ALLOCATED;
public:
explicit CallVariant(JSCell* callee = nullptr)
: m_callee(callee)
{
}
CallVariant(WTF::HashTableDeletedValueType)
: m_callee(deletedToken())
{
}
explicit operator bool() const { return !!m_callee; }
ALWAYS_INLINE CallVariant despecifiedClosure() const
{
if (m_callee->type() == JSFunctionType)
return CallVariant(jsCast<JSFunction*>(m_callee)->executable());
return *this;
}
JSCell* rawCalleeCell() const { return m_callee; }
InternalFunction* internalFunction() const
{
return jsDynamicCast<InternalFunction*>(m_callee->vm(), m_callee);
}
JSFunction* function() const
{
return jsDynamicCast<JSFunction*>(m_callee->vm(), m_callee);
}
bool isClosureCall() const { return !!jsDynamicCast<ExecutableBase*>(m_callee->vm(), m_callee); }
ExecutableBase* executable() const
{
if (JSFunction* function = this->function())
return function->executable();
return jsDynamicCast<ExecutableBase*>(m_callee->vm(), m_callee);
}
JSCell* nonExecutableCallee() const
{
RELEASE_ASSERT(!isClosureCall());
return m_callee;
}
Intrinsic intrinsicFor(CodeSpecializationKind kind) const
{
if (ExecutableBase* executable = this->executable())
return executable->intrinsicFor(kind);
return NoIntrinsic;
}
FunctionExecutable* functionExecutable() const
{
if (ExecutableBase* executable = this->executable())
return jsDynamicCast<FunctionExecutable*>(m_callee->vm(), executable);
return nullptr;
}
NativeExecutable* nativeExecutable() const
{
if (ExecutableBase* executable = this->executable())
return jsDynamicCast<NativeExecutable*>(m_callee->vm(), executable);
return nullptr;
}
const DOMJIT::Signature* signatureFor(CodeSpecializationKind kind) const
{
if (NativeExecutable* nativeExecutable = this->nativeExecutable())
return nativeExecutable->signatureFor(kind);
return nullptr;
}
bool finalize(VM&);
bool merge(const CallVariant&);
void filter(VM&, JSValue);
void dump(PrintStream& out) const;
bool isHashTableDeletedValue() const
{
return m_callee == deletedToken();
}
bool operator==(const CallVariant& other) const
{
return m_callee == other.m_callee;
}
bool operator!=(const CallVariant& other) const
{
return !(*this == other);
}
bool operator<(const CallVariant& other) const
{
return m_callee < other.m_callee;
}
bool operator>(const CallVariant& other) const
{
return other < *this;
}
bool operator<=(const CallVariant& other) const
{
return !(*this < other);
}
bool operator>=(const CallVariant& other) const
{
return other <= *this;
}
unsigned hash() const
{
return WTF::PtrHash<JSCell*>::hash(m_callee);
}
private:
static JSCell* deletedToken() { return bitwise_cast<JSCell*>(static_cast<uintptr_t>(1)); }
JSCell* m_callee;
};
struct CallVariantHash {
static unsigned hash(const CallVariant& key) { return key.hash(); }
static bool equal(const CallVariant& a, const CallVariant& b) { return a == b; }
static constexpr bool safeToCompareToEmptyOrDeleted = true;
};
typedef Vector<CallVariant, 1> CallVariantList;
CallVariantList variantListWithVariant(const CallVariantList&, CallVariant);
CallVariantList despecifiedVariantList(const CallVariantList&);
}
namespace WTF {
template<typename T> struct DefaultHash;
template<> struct DefaultHash<JSC::CallVariant> : JSC::CallVariantHash { };
template<typename T> struct HashTraits;
template<> struct HashTraits<JSC::CallVariant> : SimpleClassHashTraits<JSC::CallVariant> { };
}