#pragma once
#include "CagedBarrierPtr.h"
#include "DirectArgumentsOffset.h"
#include "GenericArguments.h"
#include <wtf/CagedPtr.h>
namespace JSC {
class DirectArguments final : public GenericArguments<DirectArguments> {
private:
DirectArguments(VM&, Structure*, unsigned length, unsigned capacity);
public:
template<typename CellType, SubspaceAccess>
static CompleteSubspace* subspaceFor(VM& vm)
{
static_assert(!CellType::needsDestruction, "");
return &vm.variableSizedCellSpace;
}
static DirectArguments* createUninitialized(VM&, Structure*, unsigned length, unsigned capacity);
static DirectArguments* create(VM&, Structure*, unsigned length, unsigned capacity);
static DirectArguments* createByCopying(JSGlobalObject*, CallFrame*);
static size_t estimatedSize(JSCell*, VM&);
static void visitChildren(JSCell*, SlotVisitor&);
uint32_t internalLength() const
{
return m_length;
}
uint32_t length(JSGlobalObject* globalObject) const
{
if (UNLIKELY(m_mappedArguments)) {
VM& vm = getVM(globalObject);
auto scope = DECLARE_THROW_SCOPE(vm);
JSValue value = get(globalObject, vm.propertyNames->length);
RETURN_IF_EXCEPTION(scope, 0);
RELEASE_AND_RETURN(scope, value.toUInt32(globalObject));
}
return m_length;
}
bool isMappedArgument(uint32_t i) const
{
return i < m_length && (!m_mappedArguments || !m_mappedArguments.at(i, m_length));
}
bool isMappedArgumentInDFG(uint32_t i) const
{
return i < m_length && !overrodeThings();
}
JSValue getIndexQuickly(uint32_t i) const
{
ASSERT_WITH_SECURITY_IMPLICATION(isMappedArgument(i));
return const_cast<DirectArguments*>(this)->storage()[i].get();
}
void setIndexQuickly(VM& vm, uint32_t i, JSValue value)
{
ASSERT_WITH_SECURITY_IMPLICATION(isMappedArgument(i));
storage()[i].set(vm, this, value);
}
JSFunction* callee()
{
return m_callee.get();
}
void setCallee(VM& vm, JSFunction* function)
{
m_callee.set(vm, this, function);
}
WriteBarrier<Unknown>& argument(DirectArgumentsOffset offset)
{
ASSERT(offset);
ASSERT_WITH_SECURITY_IMPLICATION(offset.offset() < std::max(m_length, m_minCapacity));
return storage()[offset.offset()];
}
bool overrodeThings() const { return !!m_mappedArguments; }
void overrideThings(JSGlobalObject*);
void overrideThingsIfNecessary(JSGlobalObject*);
void unmapArgument(JSGlobalObject*, unsigned index);
void initModifiedArgumentsDescriptorIfNecessary(JSGlobalObject* globalObject)
{
GenericArguments<DirectArguments>::initModifiedArgumentsDescriptorIfNecessary(globalObject, m_length);
}
void setModifiedArgumentDescriptor(JSGlobalObject* globalObject, unsigned index)
{
GenericArguments<DirectArguments>::setModifiedArgumentDescriptor(globalObject, index, m_length);
}
bool isModifiedArgumentDescriptor(unsigned index)
{
return GenericArguments<DirectArguments>::isModifiedArgumentDescriptor(index, m_length);
}
void copyToArguments(JSGlobalObject*, JSValue* firstElementDest, unsigned offset, unsigned length);
DECLARE_INFO;
static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
static ptrdiff_t offsetOfCallee() { return OBJECT_OFFSETOF(DirectArguments, m_callee); }
static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(DirectArguments, m_length); }
static ptrdiff_t offsetOfMinCapacity() { return OBJECT_OFFSETOF(DirectArguments, m_minCapacity); }
static ptrdiff_t offsetOfMappedArguments() { return OBJECT_OFFSETOF(DirectArguments, m_mappedArguments); }
static ptrdiff_t offsetOfModifiedArgumentsDescriptor() { return OBJECT_OFFSETOF(DirectArguments, m_modifiedArgumentsDescriptor); }
static size_t storageOffset()
{
return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(DirectArguments));
}
static size_t offsetOfSlot(Checked<size_t> index)
{
return (storageOffset() + sizeof(WriteBarrier<Unknown>) * index).unsafeGet();
}
static size_t allocationSize(Checked<size_t> capacity)
{
return offsetOfSlot(capacity);
}
private:
WriteBarrier<Unknown>* storage()
{
return bitwise_cast<WriteBarrier<Unknown>*>(bitwise_cast<char*>(this) + storageOffset());
}
unsigned mappedArgumentsSize();
WriteBarrier<JSFunction> m_callee;
uint32_t m_length; uint32_t m_minCapacity; using MappedArguments = CagedBarrierPtr<Gigacage::Primitive, bool>;
MappedArguments m_mappedArguments;
friend size_t cellSize(VM&, JSCell*);
};
}