GenericArgumentsInlines.h [plain text]
#pragma once
#include "GenericArguments.h"
#include "JSCInlines.h"
namespace JSC {
template<typename Type>
void GenericArguments<Type>::visitChildren(JSCell* thisCell, SlotVisitor& visitor)
{
Type* thisObject = static_cast<Type*>(thisCell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
if (thisObject->m_modifiedArgumentsDescriptor)
visitor.markAuxiliary(thisObject->m_modifiedArgumentsDescriptor.get());
}
template<typename Type>
bool GenericArguments<Type>::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName ident, PropertySlot& slot)
{
Type* thisObject = jsCast<Type*>(object);
VM& vm = exec->vm();
if (!thisObject->overrodeThings()) {
if (ident == vm.propertyNames->length) {
slot.setValue(thisObject, DontEnum, jsNumber(thisObject->internalLength()));
return true;
}
if (ident == vm.propertyNames->callee) {
slot.setValue(thisObject, DontEnum, thisObject->callee().get());
return true;
}
if (ident == vm.propertyNames->iteratorSymbol) {
slot.setValue(thisObject, DontEnum, thisObject->globalObject()->arrayProtoValuesFunction());
return true;
}
}
if (std::optional<uint32_t> index = parseIndex(ident))
return GenericArguments<Type>::getOwnPropertySlotByIndex(thisObject, exec, *index, slot);
return Base::getOwnPropertySlot(thisObject, exec, ident, slot);
}
template<typename Type>
bool GenericArguments<Type>::getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned index, PropertySlot& slot)
{
Type* thisObject = jsCast<Type*>(object);
if (!thisObject->isModifiedArgumentDescriptor(index) && thisObject->isMappedArgument(index)) {
slot.setValue(thisObject, None, thisObject->getIndexQuickly(index));
return true;
}
bool result = Base::getOwnPropertySlotByIndex(object, exec, index, slot);
if (thisObject->isMappedArgument(index)) {
ASSERT(result);
slot.setValue(thisObject, slot.attributes(), thisObject->getIndexQuickly(index));
return true;
}
return result;
}
template<typename Type>
void GenericArguments<Type>::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& array, EnumerationMode mode)
{
Type* thisObject = jsCast<Type*>(object);
if (array.includeStringProperties()) {
for (unsigned i = 0; i < thisObject->internalLength(); ++i) {
if (!thisObject->isMappedArgument(i))
continue;
array.add(Identifier::from(exec, i));
}
}
if (mode.includeDontEnumProperties() && !thisObject->overrodeThings()) {
array.add(exec->propertyNames().length);
array.add(exec->propertyNames().callee);
if (array.includeSymbolProperties())
array.add(exec->propertyNames().iteratorSymbol);
}
Base::getOwnPropertyNames(thisObject, exec, array, mode);
}
template<typename Type>
bool GenericArguments<Type>::put(JSCell* cell, ExecState* exec, PropertyName ident, JSValue value, PutPropertySlot& slot)
{
Type* thisObject = jsCast<Type*>(cell);
VM& vm = exec->vm();
if (!thisObject->overrodeThings()
&& (ident == vm.propertyNames->length
|| ident == vm.propertyNames->callee
|| ident == vm.propertyNames->iteratorSymbol)) {
thisObject->overrideThings(vm);
PutPropertySlot dummy = slot; return Base::put(thisObject, exec, ident, value, dummy);
}
if (UNLIKELY(isThisValueAltered(slot, thisObject)))
return ordinarySetSlow(exec, thisObject, ident, value, slot.thisValue(), slot.isStrictMode());
std::optional<uint32_t> index = parseIndex(ident);
if (index && thisObject->isMappedArgument(index.value())) {
thisObject->setIndexQuickly(vm, index.value(), value);
return true;
}
return Base::put(thisObject, exec, ident, value, slot);
}
template<typename Type>
bool GenericArguments<Type>::putByIndex(JSCell* cell, ExecState* exec, unsigned index, JSValue value, bool shouldThrow)
{
Type* thisObject = jsCast<Type*>(cell);
VM& vm = exec->vm();
if (thisObject->isMappedArgument(index)) {
thisObject->setIndexQuickly(vm, index, value);
return true;
}
return Base::putByIndex(cell, exec, index, value, shouldThrow);
}
template<typename Type>
bool GenericArguments<Type>::deleteProperty(JSCell* cell, ExecState* exec, PropertyName ident)
{
Type* thisObject = jsCast<Type*>(cell);
VM& vm = exec->vm();
if (!thisObject->overrodeThings()
&& (ident == vm.propertyNames->length
|| ident == vm.propertyNames->callee
|| ident == vm.propertyNames->iteratorSymbol))
thisObject->overrideThings(vm);
if (std::optional<uint32_t> index = parseIndex(ident))
return GenericArguments<Type>::deletePropertyByIndex(thisObject, exec, *index);
return Base::deleteProperty(thisObject, exec, ident);
}
template<typename Type>
bool GenericArguments<Type>::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned index)
{
Type* thisObject = jsCast<Type*>(cell);
VM& vm = exec->vm();
bool propertyMightBeInJSObjectStorage = thisObject->isModifiedArgumentDescriptor(index) || !thisObject->isMappedArgument(index);
bool deletedProperty = true;
if (propertyMightBeInJSObjectStorage)
deletedProperty = Base::deletePropertyByIndex(cell, exec, index);
if (deletedProperty) {
if (thisObject->isMappedArgument(index)) {
thisObject->unmapArgument(vm, index);
}
thisObject->setModifiedArgumentDescriptor(vm, index);
}
return deletedProperty;
}
template<typename Type>
bool GenericArguments<Type>::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName ident, const PropertyDescriptor& descriptor, bool shouldThrow)
{
Type* thisObject = jsCast<Type*>(object);
VM& vm = exec->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
if (ident == vm.propertyNames->length
|| ident == vm.propertyNames->callee
|| ident == vm.propertyNames->iteratorSymbol)
thisObject->overrideThingsIfNecessary(vm);
else {
std::optional<uint32_t> optionalIndex = parseIndex(ident);
if (optionalIndex) {
uint32_t index = optionalIndex.value();
if (!descriptor.isAccessorDescriptor() && thisObject->isMappedArgument(optionalIndex.value())) {
if (descriptor.value())
thisObject->setIndexQuickly(vm, index, descriptor.value());
if (descriptor.writable() && descriptor.configurable() && descriptor.enumerable() && !thisObject->isModifiedArgumentDescriptor(index))
return true;
if (!thisObject->isModifiedArgumentDescriptor(index)) {
JSValue value = thisObject->getIndexQuickly(index);
ASSERT(value);
object->putDirectMayBeIndex(exec, ident, value);
scope.assertNoException();
thisObject->setModifiedArgumentDescriptor(vm, index);
}
}
if (thisObject->isMappedArgument(index)) {
if ((descriptor.writablePresent() && !descriptor.writable()) || descriptor.isAccessorDescriptor()) {
if (!descriptor.isAccessorDescriptor()) {
JSValue value = thisObject->getIndexQuickly(index);
ASSERT(value);
object->putDirectMayBeIndex(exec, ident, value);
}
thisObject->unmapArgument(vm, index);
thisObject->setModifiedArgumentDescriptor(vm, index);
}
}
}
}
scope.release();
return Base::defineOwnProperty(object, exec, ident, descriptor, shouldThrow);
}
template<typename Type>
void GenericArguments<Type>::initModifiedArgumentsDescriptor(VM& vm, unsigned argsLength)
{
RELEASE_ASSERT(!m_modifiedArgumentsDescriptor);
if (argsLength) {
void* backingStore = vm.auxiliarySpace.tryAllocate(WTF::roundUpToMultipleOf<8>(argsLength));
RELEASE_ASSERT(backingStore);
bool* modifiedArguments = static_cast<bool*>(backingStore);
m_modifiedArgumentsDescriptor.set(vm, this, modifiedArguments);
for (unsigned i = argsLength; i--;)
modifiedArguments[i] = false;
}
}
template<typename Type>
void GenericArguments<Type>::initModifiedArgumentsDescriptorIfNecessary(VM& vm, unsigned argsLength)
{
if (!m_modifiedArgumentsDescriptor)
initModifiedArgumentsDescriptor(vm, argsLength);
}
template<typename Type>
void GenericArguments<Type>::setModifiedArgumentDescriptor(VM& vm, unsigned index, unsigned length)
{
initModifiedArgumentsDescriptorIfNecessary(vm, length);
if (index < length)
m_modifiedArgumentsDescriptor.get()[index] = true;
}
template<typename Type>
bool GenericArguments<Type>::isModifiedArgumentDescriptor(unsigned index, unsigned length)
{
if (!m_modifiedArgumentsDescriptor)
return false;
if (index < length)
return m_modifiedArgumentsDescriptor.get()[index];
return false;
}
template<typename Type>
void GenericArguments<Type>::copyToArguments(ExecState* exec, VirtualRegister firstElementDest, unsigned offset, unsigned length)
{
VM& vm = exec->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
Type* thisObject = static_cast<Type*>(this);
for (unsigned i = 0; i < length; ++i) {
if (thisObject->isMappedArgument(i + offset))
exec->r(firstElementDest + i) = thisObject->getIndexQuickly(i + offset);
else {
exec->r(firstElementDest + i) = get(exec, i + offset);
RETURN_IF_EXCEPTION(scope, void());
}
}
}
}