#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>
static CompleteSubspace* subspaceFor(VM& vm)
{
RELEASE_ASSERT(!CellType::needsDestruction);
return &vm.jsValueGigacageCellSpace;
}
static DirectArguments* createUninitialized(VM&, Structure*, unsigned length, unsigned capacity);
static DirectArguments* create(VM&, Structure*, unsigned length, unsigned capacity);
static DirectArguments* createByCopying(ExecState*);
static size_t estimatedSize(JSCell*, VM&);
static void visitChildren(JSCell*, SlotVisitor&);
uint32_t internalLength() const
{
return m_length;
}
uint32_t length(ExecState* exec) const
{
if (UNLIKELY(m_mappedArguments)) {
VM& vm = exec->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
JSValue value = get(exec, vm.propertyNames->length);
RETURN_IF_EXCEPTION(scope, 0);
scope.release();
return value.toUInt32(exec);
}
return m_length;
}
bool isMappedArgument(uint32_t i) const
{
return i < m_length && (!m_mappedArguments || !m_mappedArguments[i]);
}
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(VM&);
void overrideThingsIfNecessary(VM&);
void unmapArgument(VM&, unsigned index);
void initModifiedArgumentsDescriptorIfNecessary(VM& vm)
{
GenericArguments<DirectArguments>::initModifiedArgumentsDescriptorIfNecessary(vm, m_length);
}
void setModifiedArgumentDescriptor(VM& vm, unsigned index)
{
GenericArguments<DirectArguments>::setModifiedArgumentDescriptor(vm, index, m_length);
}
bool isModifiedArgumentDescriptor(unsigned index)
{
return GenericArguments<DirectArguments>::isModifiedArgumentDescriptor(index, m_length);
}
void copyToArguments(ExecState*, VirtualRegister 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; CagedBarrierPtr<Gigacage::Primitive, bool> m_mappedArguments; };
}