diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/runtime/GenericArgumentsInlines.h | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/runtime/GenericArgumentsInlines.h')
-rw-r--r-- | Source/JavaScriptCore/runtime/GenericArgumentsInlines.h | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/runtime/GenericArgumentsInlines.h b/Source/JavaScriptCore/runtime/GenericArgumentsInlines.h new file mode 100644 index 000000000..0c33bbbe4 --- /dev/null +++ b/Source/JavaScriptCore/runtime/GenericArgumentsInlines.h @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2015-2017 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#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; + } + } + + std::optional<uint32_t> index = parseIndex(ident); + if (index && !thisObject->isModifiedArgumentDescriptor(index.value()) && thisObject->isMappedArgument(index.value())) { + slot.setValue(thisObject, None, thisObject->getIndexQuickly(index.value())); + return true; + } + + bool result = Base::getOwnPropertySlot(thisObject, exec, ident, slot); + + if (index && thisObject->isMappedArgument(index.value())) + slot.setValue(thisObject, slot.attributes(), thisObject->getIndexQuickly(index.value())); + + return result; +} + +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)) + slot.setValue(thisObject, slot.attributes(), thisObject->getIndexQuickly(index)); + + 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; // This put is not cacheable, so we shadow the slot that was given to us. + return Base::put(thisObject, exec, ident, value, dummy); + } + + // https://tc39.github.io/ecma262/#sec-arguments-exotic-objects-set-p-v-receiver + // Fall back to the OrdinarySet when the receiver is altered from the thisObject. + 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); + + std::optional<uint32_t> index = parseIndex(ident); + if (index && !thisObject->isModifiedArgumentDescriptor(index.value()) && thisObject->isMappedArgument(index.value())) { + thisObject->unmapArgument(vm, index.value()); + thisObject->setModifiedArgumentDescriptor(vm, index.value()); + return true; + } + + 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(); + + if (!thisObject->isModifiedArgumentDescriptor(index) && thisObject->isMappedArgument(index)) { + thisObject->unmapArgument(vm, index); + thisObject->setModifiedArgumentDescriptor(vm, index); + return true; + } + + return Base::deletePropertyByIndex(cell, exec, index); +} + +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 the property is not deleted and we are using a non-accessor descriptor, then + // make sure that the aliased argument sees the value. + if (descriptor.value()) + thisObject->setIndexQuickly(vm, index, descriptor.value()); + + // If the property is not deleted and we are using a non-accessor, writable, + // configurable and enumerable descriptor and isn't modified, then we are done. + // The argument continues to be aliased. + if (descriptor.writable() && descriptor.configurable() && descriptor.enumerable() && !thisObject->isModifiedArgumentDescriptor(index)) + return true; + + if (!thisObject->isModifiedArgumentDescriptor(index)) { + // If it is a new entry, we need to put direct to initialize argument[i] descriptor properly + JSValue value = thisObject->getIndexQuickly(index); + ASSERT(value); + object->putDirectMayBeIndex(exec, ident, value); + ASSERT(!scope.exception()); + + thisObject->setModifiedArgumentDescriptor(vm, index); + } + } + + if (thisObject->isMappedArgument(index)) { + // Just unmap arguments if its descriptor contains {writable: false}. + // Check https://tc39.github.io/ecma262/#sec-createunmappedargumentsobject + // and https://tc39.github.io/ecma262/#sec-createmappedargumentsobject to verify that all data + // property from arguments object are {writable: true, configurable: true, enumerable: true} by default + 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); + } + } + } + } + + // Now just let the normal object machinery do its thing. + 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()); + } + } +} + +} // namespace JSC |