/src/qt/qtwebkit/Source/JavaScriptCore/runtime/JSObject.cpp
C++ | 1388 lines | 1089 code | 238 blank | 61 comment | 183 complexity | 76a08c3e0f7784e53dbcef3eca0e3ada MD5 | raw file
- /*
- * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
- * Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2012, 2013 Apple Inc. All rights reserved.
- * Copyright (C) 2007 Eric Seidel (eric@webkit.org)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
- #include "config.h"
- #include "JSObject.h"
- #include "ButterflyInlines.h"
- #include "CopiedSpaceInlines.h"
- #include "CopyVisitor.h"
- #include "CopyVisitorInlines.h"
- #include "DatePrototype.h"
- #include "ErrorConstructor.h"
- #include "Executable.h"
- #include "GetterSetter.h"
- #include "IndexingHeaderInlines.h"
- #include "JSFunction.h"
- #include "JSGlobalObject.h"
- #include "Lookup.h"
- #include "NativeErrorConstructor.h"
- #include "Nodes.h"
- #include "ObjectPrototype.h"
- #include "Operations.h"
- #include "PropertyDescriptor.h"
- #include "PropertyNameArray.h"
- #include "Reject.h"
- #include "SlotVisitorInlines.h"
- #include <math.h>
- #include <wtf/Assertions.h>
- namespace JSC {
- // We keep track of the size of the last array after it was grown. We use this
- // as a simple heuristic for as the value to grow the next array from size 0.
- // This value is capped by the constant FIRST_VECTOR_GROW defined in
- // ArrayConventions.h.
- static unsigned lastArraySize = 0;
- JSCell* getCallableObjectSlow(JSCell* cell)
- {
- Structure* structure = cell->structure();
- if (structure->typeInfo().type() == JSFunctionType)
- return cell;
- if (structure->classInfo()->isSubClassOf(&InternalFunction::s_info))
- return cell;
- return 0;
- }
- ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSObject);
- ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSFinalObject);
- const char* StrictModeReadonlyPropertyWriteError = "Attempted to assign to readonly property.";
- const ClassInfo JSObject::s_info = { "Object", 0, 0, 0, CREATE_METHOD_TABLE(JSObject) };
- const ClassInfo JSFinalObject::s_info = { "Object", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSFinalObject) };
- static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode, bool didReify)
- {
- // Add properties from the static hashtables of properties
- for (; classInfo; classInfo = classInfo->parentClass) {
- const HashTable* table = classInfo->propHashTable(exec);
- if (!table)
- continue;
- table->initializeIfNeeded(exec);
- ASSERT(table->table);
- int hashSizeMask = table->compactSize - 1;
- const HashEntry* entry = table->table;
- for (int i = 0; i <= hashSizeMask; ++i, ++entry) {
- if (entry->key() && (!(entry->attributes() & DontEnum) || (mode == IncludeDontEnumProperties)) && !((entry->attributes() & Function) && didReify))
- propertyNames.add(entry->key());
- }
- }
- }
- ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butterfly, size_t storageSize)
- {
- ASSERT(butterfly);
-
- Structure* structure = this->structure();
-
- size_t propertyCapacity = structure->outOfLineCapacity();
- size_t preCapacity;
- size_t indexingPayloadSizeInBytes;
- bool hasIndexingHeader = JSC::hasIndexingHeader(structure->indexingType());
- if (UNLIKELY(hasIndexingHeader)) {
- preCapacity = butterfly->indexingHeader()->preCapacity(structure);
- indexingPayloadSizeInBytes = butterfly->indexingHeader()->indexingPayloadSizeInBytes(structure);
- } else {
- preCapacity = 0;
- indexingPayloadSizeInBytes = 0;
- }
- size_t capacityInBytes = Butterfly::totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
- if (visitor.checkIfShouldCopy(butterfly->base(preCapacity, propertyCapacity))) {
- Butterfly* newButterfly = Butterfly::createUninitializedDuringCollection(visitor, preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
-
- // Copy the properties.
- PropertyStorage currentTarget = newButterfly->propertyStorage();
- PropertyStorage currentSource = butterfly->propertyStorage();
- for (size_t count = storageSize; count--;)
- (--currentTarget)->setWithoutWriteBarrier((--currentSource)->get());
-
- if (UNLIKELY(hasIndexingHeader)) {
- *newButterfly->indexingHeader() = *butterfly->indexingHeader();
-
- // Copy the array if appropriate.
-
- WriteBarrier<Unknown>* currentTarget;
- WriteBarrier<Unknown>* currentSource;
- size_t count;
-
- switch (structure->indexingType()) {
- case ALL_UNDECIDED_INDEXING_TYPES:
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- case ALL_INT32_INDEXING_TYPES:
- case ALL_DOUBLE_INDEXING_TYPES: {
- currentTarget = newButterfly->contiguous().data();
- currentSource = butterfly->contiguous().data();
- RELEASE_ASSERT(newButterfly->publicLength() <= newButterfly->vectorLength());
- count = newButterfly->vectorLength();
- break;
- }
-
- case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
- newButterfly->arrayStorage()->copyHeaderFromDuringGC(*butterfly->arrayStorage());
- currentTarget = newButterfly->arrayStorage()->m_vector;
- currentSource = butterfly->arrayStorage()->m_vector;
- count = newButterfly->arrayStorage()->vectorLength();
- break;
- }
- default:
- CRASH();
- currentTarget = 0;
- currentSource = 0;
- count = 0;
- break;
- }
- memcpy(currentTarget, currentSource, count * sizeof(EncodedJSValue));
- }
-
- m_butterfly = newButterfly;
- visitor.didCopy(butterfly->base(preCapacity, propertyCapacity), capacityInBytes);
- }
- }
- ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* butterfly, size_t storageSize)
- {
- ASSERT(butterfly);
-
- Structure* structure = this->structure();
-
- size_t propertyCapacity = structure->outOfLineCapacity();
- size_t preCapacity;
- size_t indexingPayloadSizeInBytes;
- bool hasIndexingHeader = JSC::hasIndexingHeader(structure->indexingType());
- if (UNLIKELY(hasIndexingHeader)) {
- preCapacity = butterfly->indexingHeader()->preCapacity(structure);
- indexingPayloadSizeInBytes = butterfly->indexingHeader()->indexingPayloadSizeInBytes(structure);
- } else {
- preCapacity = 0;
- indexingPayloadSizeInBytes = 0;
- }
- size_t capacityInBytes = Butterfly::totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
- // Mark the properties.
- visitor.appendValues(butterfly->propertyStorage() - storageSize, storageSize);
- visitor.copyLater(this, butterfly->base(preCapacity, propertyCapacity), capacityInBytes);
-
- // Mark the array if appropriate.
- switch (structure->indexingType()) {
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- visitor.appendValues(butterfly->contiguous().data(), butterfly->publicLength());
- break;
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- visitor.appendValues(butterfly->arrayStorage()->m_vector, butterfly->arrayStorage()->vectorLength());
- if (butterfly->arrayStorage()->m_sparseMap)
- visitor.append(&butterfly->arrayStorage()->m_sparseMap);
- break;
- default:
- break;
- }
- }
- void JSObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
- {
- JSObject* thisObject = jsCast<JSObject*>(cell);
- ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
- #if !ASSERT_DISABLED
- bool wasCheckingForDefaultMarkViolation = visitor.m_isCheckingForDefaultMarkViolation;
- visitor.m_isCheckingForDefaultMarkViolation = false;
- #endif
-
- JSCell::visitChildren(thisObject, visitor);
- Butterfly* butterfly = thisObject->butterfly();
- if (butterfly)
- thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
- #if !ASSERT_DISABLED
- visitor.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation;
- #endif
- }
- void JSObject::copyBackingStore(JSCell* cell, CopyVisitor& visitor)
- {
- JSObject* thisObject = jsCast<JSObject*>(cell);
- ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
-
- Butterfly* butterfly = thisObject->butterfly();
- if (butterfly)
- thisObject->copyButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
- }
- void JSFinalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
- {
- JSFinalObject* thisObject = jsCast<JSFinalObject*>(cell);
- ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
- #if !ASSERT_DISABLED
- bool wasCheckingForDefaultMarkViolation = visitor.m_isCheckingForDefaultMarkViolation;
- visitor.m_isCheckingForDefaultMarkViolation = false;
- #endif
-
- JSCell::visitChildren(thisObject, visitor);
- Butterfly* butterfly = thisObject->butterfly();
- if (butterfly)
- thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
- size_t storageSize = thisObject->structure()->inlineSize();
- visitor.appendValues(thisObject->inlineStorage(), storageSize);
- #if !ASSERT_DISABLED
- visitor.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation;
- #endif
- }
- String JSObject::className(const JSObject* object)
- {
- const ClassInfo* info = object->classInfo();
- ASSERT(info);
- return info->className;
- }
- bool JSObject::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned i, PropertySlot& slot)
- {
- // NB. The fact that we're directly consulting our indexed storage implies that it is not
- // legal for anyone to override getOwnPropertySlot() without also overriding
- // getOwnPropertySlotByIndex().
-
- JSObject* thisObject = jsCast<JSObject*>(cell);
-
- if (i > MAX_ARRAY_INDEX)
- return thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, Identifier::from(exec, i), slot);
-
- switch (thisObject->structure()->indexingType()) {
- case ALL_BLANK_INDEXING_TYPES:
- case ALL_UNDECIDED_INDEXING_TYPES:
- break;
-
- case ALL_INT32_INDEXING_TYPES:
- case ALL_CONTIGUOUS_INDEXING_TYPES: {
- Butterfly* butterfly = thisObject->m_butterfly;
- if (i >= butterfly->vectorLength())
- return false;
-
- JSValue value = butterfly->contiguous()[i].get();
- if (value) {
- slot.setValue(value);
- return true;
- }
-
- return false;
- }
-
- case ALL_DOUBLE_INDEXING_TYPES: {
- Butterfly* butterfly = thisObject->m_butterfly;
- if (i >= butterfly->vectorLength())
- return false;
-
- double value = butterfly->contiguousDouble()[i];
- if (value == value) {
- slot.setValue(JSValue(JSValue::EncodeAsDouble, value));
- return true;
- }
-
- return false;
- }
-
- case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
- ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
- if (i >= storage->length())
- return false;
-
- if (i < storage->vectorLength()) {
- JSValue value = storage->m_vector[i].get();
- if (value) {
- slot.setValue(value);
- return true;
- }
- } else if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
- SparseArrayValueMap::iterator it = map->find(i);
- if (it != map->notFound()) {
- it->value.get(slot);
- return true;
- }
- }
- break;
- }
-
- default:
- RELEASE_ASSERT_NOT_REACHED();
- break;
- }
-
- return false;
- }
- // ECMA 8.6.2.2
- void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
- {
- JSObject* thisObject = jsCast<JSObject*>(cell);
- ASSERT(value);
- ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
- VM& vm = exec->vm();
-
- // Try indexed put first. This is required for correctness, since loads on property names that appear like
- // valid indices will never look in the named property storage.
- unsigned i = propertyName.asIndex();
- if (i != PropertyName::NotAnIndex) {
- putByIndex(thisObject, exec, i, value, slot.isStrictMode());
- return;
- }
-
- // Check if there are any setters or getters in the prototype chain
- JSValue prototype;
- if (propertyName != exec->propertyNames().underscoreProto) {
- for (JSObject* obj = thisObject; !obj->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) {
- prototype = obj->prototype();
- if (prototype.isNull()) {
- ASSERT(!thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName));
- if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot, getCallableObject(value))
- && slot.isStrictMode())
- throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
- return;
- }
- }
- }
- JSObject* obj;
- for (obj = thisObject; ; obj = asObject(prototype)) {
- unsigned attributes;
- JSCell* specificValue;
- PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes, specificValue);
- if (isValidOffset(offset)) {
- if (attributes & ReadOnly) {
- ASSERT(thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject);
- if (slot.isStrictMode())
- throwError(exec, createTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError)));
- return;
- }
- JSValue gs = obj->getDirect(offset);
- if (gs.isGetterSetter()) {
- ASSERT(attributes & Accessor);
- ASSERT(thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject);
- JSObject* setterFunc = asGetterSetter(gs)->setter();
- if (!setterFunc) {
- if (slot.isStrictMode())
- throwError(exec, createTypeError(exec, ASCIILiteral("setting a property that has only a getter")));
- return;
- }
-
- CallData callData;
- CallType callType = setterFunc->methodTable()->getCallData(setterFunc, callData);
- MarkedArgumentBuffer args;
- args.append(value);
- // If this is WebCore's global object then we need to substitute the shell.
- call(exec, setterFunc, callType, callData, thisObject->methodTable()->toThisObject(thisObject, exec), args);
- return;
- } else
- ASSERT(!(attributes & Accessor));
- // If there's an existing property on the object or one of its
- // prototypes it should be replaced, so break here.
- break;
- }
- prototype = obj->prototype();
- if (prototype.isNull())
- break;
- }
-
- ASSERT(!thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject);
- if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot, getCallableObject(value)) && slot.isStrictMode())
- throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
- return;
- }
- void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
- {
- JSObject* thisObject = jsCast<JSObject*>(cell);
-
- if (propertyName > MAX_ARRAY_INDEX) {
- PutPropertySlot slot(shouldThrow);
- thisObject->methodTable()->put(thisObject, exec, Identifier::from(exec, propertyName), value, slot);
- return;
- }
-
- switch (thisObject->structure()->indexingType()) {
- case ALL_BLANK_INDEXING_TYPES:
- break;
-
- case ALL_UNDECIDED_INDEXING_TYPES: {
- thisObject->convertUndecidedForValue(exec->vm(), value);
- // Reloop.
- putByIndex(cell, exec, propertyName, value, shouldThrow);
- return;
- }
-
- case ALL_INT32_INDEXING_TYPES: {
- if (!value.isInt32()) {
- thisObject->convertInt32ForValue(exec->vm(), value);
- putByIndex(cell, exec, propertyName, value, shouldThrow);
- return;
- }
- // Fall through.
- }
-
- case ALL_CONTIGUOUS_INDEXING_TYPES: {
- Butterfly* butterfly = thisObject->m_butterfly;
- if (propertyName >= butterfly->vectorLength())
- break;
- butterfly->contiguous()[propertyName].set(exec->vm(), thisObject, value);
- if (propertyName >= butterfly->publicLength())
- butterfly->setPublicLength(propertyName + 1);
- return;
- }
-
- case ALL_DOUBLE_INDEXING_TYPES: {
- if (!value.isNumber()) {
- thisObject->convertDoubleToContiguous(exec->vm());
- // Reloop.
- putByIndex(cell, exec, propertyName, value, shouldThrow);
- return;
- }
- double valueAsDouble = value.asNumber();
- if (valueAsDouble != valueAsDouble) {
- thisObject->convertDoubleToContiguous(exec->vm());
- // Reloop.
- putByIndex(cell, exec, propertyName, value, shouldThrow);
- return;
- }
- Butterfly* butterfly = thisObject->m_butterfly;
- if (propertyName >= butterfly->vectorLength())
- break;
- butterfly->contiguousDouble()[propertyName] = valueAsDouble;
- if (propertyName >= butterfly->publicLength())
- butterfly->setPublicLength(propertyName + 1);
- return;
- }
-
- case NonArrayWithArrayStorage:
- case ArrayWithArrayStorage: {
- ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
-
- if (propertyName >= storage->vectorLength())
- break;
-
- WriteBarrier<Unknown>& valueSlot = storage->m_vector[propertyName];
- unsigned length = storage->length();
-
- // Update length & m_numValuesInVector as necessary.
- if (propertyName >= length) {
- length = propertyName + 1;
- storage->setLength(length);
- ++storage->m_numValuesInVector;
- } else if (!valueSlot)
- ++storage->m_numValuesInVector;
-
- valueSlot.set(exec->vm(), thisObject, value);
- return;
- }
-
- case NonArrayWithSlowPutArrayStorage:
- case ArrayWithSlowPutArrayStorage: {
- ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
-
- if (propertyName >= storage->vectorLength())
- break;
-
- WriteBarrier<Unknown>& valueSlot = storage->m_vector[propertyName];
- unsigned length = storage->length();
-
- // Update length & m_numValuesInVector as necessary.
- if (propertyName >= length) {
- if (thisObject->attemptToInterceptPutByIndexOnHole(exec, propertyName, value, shouldThrow))
- return;
- length = propertyName + 1;
- storage->setLength(length);
- ++storage->m_numValuesInVector;
- } else if (!valueSlot) {
- if (thisObject->attemptToInterceptPutByIndexOnHole(exec, propertyName, value, shouldThrow))
- return;
- ++storage->m_numValuesInVector;
- }
-
- valueSlot.set(exec->vm(), thisObject, value);
- return;
- }
-
- default:
- RELEASE_ASSERT_NOT_REACHED();
- }
-
- thisObject->putByIndexBeyondVectorLength(exec, propertyName, value, shouldThrow);
- }
- ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(VM& vm, ArrayStorage* storage)
- {
- SparseArrayValueMap* map = storage->m_sparseMap.get();
- if (!map)
- map = allocateSparseIndexMap(vm);
- if (map->sparseMode())
- return storage;
- map->setSparseMode();
- unsigned usedVectorLength = std::min(storage->length(), storage->vectorLength());
- for (unsigned i = 0; i < usedVectorLength; ++i) {
- JSValue value = storage->m_vector[i].get();
- // This will always be a new entry in the map, so no need to check we can write,
- // and attributes are default so no need to set them.
- if (value)
- map->add(this, i).iterator->value.set(vm, this, value);
- }
- Butterfly* newButterfly = storage->butterfly()->resizeArray(vm, structure(), 0, ArrayStorage::sizeFor(0));
- RELEASE_ASSERT(newButterfly);
-
- m_butterfly = newButterfly;
- newButterfly->arrayStorage()->m_indexBias = 0;
- newButterfly->arrayStorage()->setVectorLength(0);
- newButterfly->arrayStorage()->m_sparseMap.set(vm, this, map);
-
- return newButterfly->arrayStorage();
- }
- void JSObject::enterDictionaryIndexingMode(VM& vm)
- {
- switch (structure()->indexingType()) {
- case ALL_BLANK_INDEXING_TYPES:
- case ALL_UNDECIDED_INDEXING_TYPES:
- case ALL_INT32_INDEXING_TYPES:
- case ALL_DOUBLE_INDEXING_TYPES:
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- // NOTE: this is horribly inefficient, as it will perform two conversions. We could optimize
- // this case if we ever cared.
- enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, ensureArrayStorageSlow(vm));
- break;
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, m_butterfly->arrayStorage());
- break;
-
- default:
- break;
- }
- }
- void JSObject::notifyPresenceOfIndexedAccessors(VM& vm)
- {
- if (mayInterceptIndexedAccesses())
- return;
-
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AddIndexedAccessors));
-
- if (!vm.prototypeMap.isPrototype(this))
- return;
-
- globalObject()->haveABadTime(vm);
- }
- Butterfly* JSObject::createInitialIndexedStorage(VM& vm, unsigned length, size_t elementSize)
- {
- ASSERT(length < MAX_ARRAY_INDEX);
- IndexingType oldType = structure()->indexingType();
- ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
- ASSERT(!structure()->needsSlowPutIndexing());
- ASSERT(!indexingShouldBeSparse());
- unsigned vectorLength = std::max(length, BASE_VECTOR_LEN);
- Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(m_butterfly,
- vm, structure(), structure()->outOfLineCapacity(), false, 0,
- elementSize * vectorLength);
- newButterfly->setPublicLength(length);
- newButterfly->setVectorLength(vectorLength);
- return newButterfly;
- }
- Butterfly* JSObject::createInitialUndecided(VM& vm, unsigned length)
- {
- Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue));
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateUndecided);
- setButterfly(vm, newButterfly, newStructure);
- return newButterfly;
- }
- ContiguousJSValues JSObject::createInitialInt32(VM& vm, unsigned length)
- {
- Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue));
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateInt32);
- setButterfly(vm, newButterfly, newStructure);
- return newButterfly->contiguousInt32();
- }
- ContiguousDoubles JSObject::createInitialDouble(VM& vm, unsigned length)
- {
- Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(double));
- for (unsigned i = newButterfly->vectorLength(); i--;)
- newButterfly->contiguousDouble()[i] = QNaN;
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateDouble);
- setButterfly(vm, newButterfly, newStructure);
- return newButterfly->contiguousDouble();
- }
- ContiguousJSValues JSObject::createInitialContiguous(VM& vm, unsigned length)
- {
- Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue));
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateContiguous);
- setButterfly(vm, newButterfly, newStructure);
- return newButterfly->contiguous();
- }
- ArrayStorage* JSObject::createArrayStorage(VM& vm, unsigned length, unsigned vectorLength)
- {
- IndexingType oldType = structure()->indexingType();
- ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
- Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(m_butterfly,
- vm, structure(), structure()->outOfLineCapacity(), false, 0,
- ArrayStorage::sizeFor(vectorLength));
- RELEASE_ASSERT(newButterfly);
- ArrayStorage* result = newButterfly->arrayStorage();
- result->setLength(length);
- result->setVectorLength(vectorLength);
- result->m_sparseMap.clear();
- result->m_numValuesInVector = 0;
- result->m_indexBias = 0;
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), structure()->suggestedArrayStorageTransition());
- setButterfly(vm, newButterfly, newStructure);
- return result;
- }
- ArrayStorage* JSObject::createInitialArrayStorage(VM& vm)
- {
- return createArrayStorage(vm, 0, BASE_VECTOR_LEN);
- }
- ContiguousJSValues JSObject::convertUndecidedToInt32(VM& vm)
- {
- ASSERT(hasUndecided(structure()->indexingType()));
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateInt32));
- return m_butterfly->contiguousInt32();
- }
- ContiguousDoubles JSObject::convertUndecidedToDouble(VM& vm)
- {
- ASSERT(hasUndecided(structure()->indexingType()));
-
- for (unsigned i = m_butterfly->vectorLength(); i--;)
- m_butterfly->contiguousDouble()[i] = QNaN;
-
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble));
- return m_butterfly->contiguousDouble();
- }
- ContiguousJSValues JSObject::convertUndecidedToContiguous(VM& vm)
- {
- ASSERT(hasUndecided(structure()->indexingType()));
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous));
- return m_butterfly->contiguous();
- }
- ArrayStorage* JSObject::constructConvertedArrayStorageWithoutCopyingElements(VM& vm, unsigned neededLength)
- {
- unsigned publicLength = m_butterfly->publicLength();
- unsigned propertyCapacity = structure()->outOfLineCapacity();
- unsigned propertySize = structure()->outOfLineSize();
-
- Butterfly* newButterfly = Butterfly::createUninitialized(
- vm, 0, propertyCapacity, true, ArrayStorage::sizeFor(neededLength));
-
- memcpy(
- newButterfly->propertyStorage() - propertySize,
- m_butterfly->propertyStorage() - propertySize,
- propertySize * sizeof(EncodedJSValue));
-
- ArrayStorage* newStorage = newButterfly->arrayStorage();
- newStorage->setVectorLength(neededLength);
- newStorage->setLength(publicLength);
- newStorage->m_sparseMap.clear();
- newStorage->m_indexBias = 0;
- newStorage->m_numValuesInVector = 0;
-
- return newStorage;
- }
- ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength)
- {
- ASSERT(hasUndecided(structure()->indexingType()));
-
- ArrayStorage* storage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength);
- // No need to copy elements.
-
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition);
- setButterfly(vm, storage->butterfly(), newStructure);
- return storage;
- }
- ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm, NonPropertyTransition transition)
- {
- return convertUndecidedToArrayStorage(vm, transition, m_butterfly->vectorLength());
- }
- ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm)
- {
- return convertUndecidedToArrayStorage(vm, structure()->suggestedArrayStorageTransition());
- }
- ContiguousDoubles JSObject::convertInt32ToDouble(VM& vm)
- {
- ASSERT(hasInt32(structure()->indexingType()));
-
- for (unsigned i = m_butterfly->vectorLength(); i--;) {
- WriteBarrier<Unknown>* current = &m_butterfly->contiguousInt32()[i];
- double* currentAsDouble = bitwise_cast<double*>(current);
- JSValue v = current->get();
- if (!v) {
- *currentAsDouble = QNaN;
- continue;
- }
- ASSERT(v.isInt32());
- *currentAsDouble = v.asInt32();
- }
-
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble));
- return m_butterfly->contiguousDouble();
- }
- ContiguousJSValues JSObject::convertInt32ToContiguous(VM& vm)
- {
- ASSERT(hasInt32(structure()->indexingType()));
-
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous));
- return m_butterfly->contiguous();
- }
- ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength)
- {
- ASSERT(hasInt32(structure()->indexingType()));
-
- ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength);
- for (unsigned i = m_butterfly->publicLength(); i--;) {
- JSValue v = m_butterfly->contiguous()[i].get();
- if (!v)
- continue;
- newStorage->m_vector[i].setWithoutWriteBarrier(v);
- newStorage->m_numValuesInVector++;
- }
-
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition);
- setButterfly(vm, newStorage->butterfly(), newStructure);
- return newStorage;
- }
- ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm, NonPropertyTransition transition)
- {
- return convertInt32ToArrayStorage(vm, transition, m_butterfly->vectorLength());
- }
- ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm)
- {
- return convertInt32ToArrayStorage(vm, structure()->suggestedArrayStorageTransition());
- }
- template<JSObject::DoubleToContiguousMode mode>
- ContiguousJSValues JSObject::genericConvertDoubleToContiguous(VM& vm)
- {
- ASSERT(hasDouble(structure()->indexingType()));
-
- for (unsigned i = m_butterfly->vectorLength(); i--;) {
- double* current = &m_butterfly->contiguousDouble()[i];
- WriteBarrier<Unknown>* currentAsValue = bitwise_cast<WriteBarrier<Unknown>*>(current);
- double value = *current;
- if (value != value) {
- currentAsValue->clear();
- continue;
- }
- JSValue v;
- switch (mode) {
- case EncodeValueAsDouble:
- v = JSValue(JSValue::EncodeAsDouble, value);
- break;
- case RageConvertDoubleToValue:
- v = jsNumber(value);
- break;
- }
- ASSERT(v.isNumber());
- currentAsValue->setWithoutWriteBarrier(v);
- }
-
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous));
- return m_butterfly->contiguous();
- }
- ContiguousJSValues JSObject::convertDoubleToContiguous(VM& vm)
- {
- return genericConvertDoubleToContiguous<EncodeValueAsDouble>(vm);
- }
- ContiguousJSValues JSObject::rageConvertDoubleToContiguous(VM& vm)
- {
- return genericConvertDoubleToContiguous<RageConvertDoubleToValue>(vm);
- }
- ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength)
- {
- ASSERT(hasDouble(structure()->indexingType()));
-
- ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength);
- for (unsigned i = m_butterfly->publicLength(); i--;) {
- double value = m_butterfly->contiguousDouble()[i];
- if (value != value)
- continue;
- newStorage->m_vector[i].setWithoutWriteBarrier(JSValue(JSValue::EncodeAsDouble, value));
- newStorage->m_numValuesInVector++;
- }
-
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition);
- setButterfly(vm, newStorage->butterfly(), newStructure);
- return newStorage;
- }
- ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm, NonPropertyTransition transition)
- {
- return convertDoubleToArrayStorage(vm, transition, m_butterfly->vectorLength());
- }
- ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm)
- {
- return convertDoubleToArrayStorage(vm, structure()->suggestedArrayStorageTransition());
- }
- ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength)
- {
- ASSERT(hasContiguous(structure()->indexingType()));
-
- ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength);
- for (unsigned i = m_butterfly->publicLength(); i--;) {
- JSValue v = m_butterfly->contiguous()[i].get();
- if (!v)
- continue;
- newStorage->m_vector[i].setWithoutWriteBarrier(v);
- newStorage->m_numValuesInVector++;
- }
-
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition);
- setButterfly(vm, newStorage->butterfly(), newStructure);
- return newStorage;
- }
- ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm, NonPropertyTransition transition)
- {
- return convertContiguousToArrayStorage(vm, transition, m_butterfly->vectorLength());
- }
- ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm)
- {
- return convertContiguousToArrayStorage(vm, structure()->suggestedArrayStorageTransition());
- }
- void JSObject::convertUndecidedForValue(VM& vm, JSValue value)
- {
- if (value.isInt32()) {
- convertUndecidedToInt32(vm);
- return;
- }
-
- if (value.isDouble()) {
- convertUndecidedToDouble(vm);
- return;
- }
-
- convertUndecidedToContiguous(vm);
- }
- void JSObject::convertInt32ForValue(VM& vm, JSValue value)
- {
- ASSERT(!value.isInt32());
-
- if (value.isDouble()) {
- convertInt32ToDouble(vm);
- return;
- }
-
- convertInt32ToContiguous(vm);
- }
- void JSObject::setIndexQuicklyToUndecided(VM& vm, unsigned index, JSValue value)
- {
- ASSERT(index < m_butterfly->publicLength());
- ASSERT(index < m_butterfly->vectorLength());
- convertUndecidedForValue(vm, value);
- setIndexQuickly(vm, index, value);
- }
- void JSObject::convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(VM& vm, unsigned index, JSValue value)
- {
- ASSERT(!value.isInt32());
- convertInt32ForValue(vm, value);
- setIndexQuickly(vm, index, value);
- }
- void JSObject::convertDoubleToContiguousWhilePerformingSetIndex(VM& vm, unsigned index, JSValue value)
- {
- ASSERT(!value.isNumber() || value.asNumber() != value.asNumber());
- convertDoubleToContiguous(vm);
- setIndexQuickly(vm, index, value);
- }
- ContiguousJSValues JSObject::ensureInt32Slow(VM& vm)
- {
- ASSERT(inherits(&s_info));
-
- switch (structure()->indexingType()) {
- case ALL_BLANK_INDEXING_TYPES:
- if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
- return ContiguousJSValues();
- return createInitialInt32(vm, 0);
-
- case ALL_UNDECIDED_INDEXING_TYPES:
- return convertUndecidedToInt32(vm);
-
- case ALL_DOUBLE_INDEXING_TYPES:
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return ContiguousJSValues();
-
- default:
- CRASH();
- return ContiguousJSValues();
- }
- }
- ContiguousDoubles JSObject::ensureDoubleSlow(VM& vm)
- {
- ASSERT(inherits(&s_info));
-
- switch (structure()->indexingType()) {
- case ALL_BLANK_INDEXING_TYPES:
- if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
- return ContiguousDoubles();
- return createInitialDouble(vm, 0);
-
- case ALL_UNDECIDED_INDEXING_TYPES:
- return convertUndecidedToDouble(vm);
-
- case ALL_INT32_INDEXING_TYPES:
- return convertInt32ToDouble(vm);
-
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return ContiguousDoubles();
-
- default:
- CRASH();
- return ContiguousDoubles();
- }
- }
- ContiguousJSValues JSObject::ensureContiguousSlow(VM& vm, DoubleToContiguousMode mode)
- {
- ASSERT(inherits(&s_info));
-
- switch (structure()->indexingType()) {
- case ALL_BLANK_INDEXING_TYPES:
- if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
- return ContiguousJSValues();
- return createInitialContiguous(vm, 0);
-
- case ALL_UNDECIDED_INDEXING_TYPES:
- return convertUndecidedToContiguous(vm);
-
- case ALL_INT32_INDEXING_TYPES:
- return convertInt32ToContiguous(vm);
-
- case ALL_DOUBLE_INDEXING_TYPES:
- if (mode == RageConvertDoubleToValue)
- return rageConvertDoubleToContiguous(vm);
- return convertDoubleToContiguous(vm);
-
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return ContiguousJSValues();
-
- default:
- CRASH();
- return ContiguousJSValues();
- }
- }
- ContiguousJSValues JSObject::ensureContiguousSlow(VM& vm)
- {
- return ensureContiguousSlow(vm, EncodeValueAsDouble);
- }
- ContiguousJSValues JSObject::rageEnsureContiguousSlow(VM& vm)
- {
- return ensureContiguousSlow(vm, RageConvertDoubleToValue);
- }
- ArrayStorage* JSObject::ensureArrayStorageSlow(VM& vm)
- {
- ASSERT(inherits(&s_info));
-
- switch (structure()->indexingType()) {
- case ALL_BLANK_INDEXING_TYPES:
- if (UNLIKELY(indexingShouldBeSparse()))
- return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm);
- return createInitialArrayStorage(vm);
-
- case ALL_UNDECIDED_INDEXING_TYPES:
- ASSERT(!indexingShouldBeSparse());
- ASSERT(!structure()->needsSlowPutIndexing());
- return convertUndecidedToArrayStorage(vm);
-
- case ALL_INT32_INDEXING_TYPES:
- ASSERT(!indexingShouldBeSparse());
- ASSERT(!structure()->needsSlowPutIndexing());
- return convertInt32ToArrayStorage(vm);
-
- case ALL_DOUBLE_INDEXING_TYPES:
- ASSERT(!indexingShouldBeSparse());
- ASSERT(!structure()->needsSlowPutIndexing());
- return convertDoubleToArrayStorage(vm);
-
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- ASSERT(!indexingShouldBeSparse());
- ASSERT(!structure()->needsSlowPutIndexing());
- return convertContiguousToArrayStorage(vm);
-
- default:
- RELEASE_ASSERT_NOT_REACHED();
- return 0;
- }
- }
- ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(VM& vm)
- {
- switch (structure()->indexingType()) {
- case ALL_BLANK_INDEXING_TYPES: {
- createArrayStorage(vm, 0, 0);
- SparseArrayValueMap* map = allocateSparseIndexMap(vm);
- map->setSparseMode();
- return arrayStorage();
- }
-
- case ALL_UNDECIDED_INDEXING_TYPES:
- return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertUndecidedToArrayStorage(vm));
-
- case ALL_INT32_INDEXING_TYPES:
- return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertInt32ToArrayStorage(vm));
-
- case ALL_DOUBLE_INDEXING_TYPES:
- return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertDoubleToArrayStorage(vm));
-
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertContiguousToArrayStorage(vm));
-
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, m_butterfly->arrayStorage());
-
- default:
- CRASH();
- return 0;
- }
- }
- void JSObject::switchToSlowPutArrayStorage(VM& vm)
- {
- switch (structure()->indexingType()) {
- case ALL_UNDECIDED_INDEXING_TYPES:
- convertUndecidedToArrayStorage(vm, AllocateSlowPutArrayStorage);
- break;
-
- case ALL_INT32_INDEXING_TYPES:
- convertInt32ToArrayStorage(vm, AllocateSlowPutArrayStorage);
- break;
-
- case ALL_DOUBLE_INDEXING_TYPES:
- convertDoubleToArrayStorage(vm, AllocateSlowPutArrayStorage);
- break;
-
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- convertContiguousToArrayStorage(vm, AllocateSlowPutArrayStorage);
- break;
-
- case NonArrayWithArrayStorage:
- case ArrayWithArrayStorage: {
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), SwitchToSlowPutArrayStorage);
- setStructure(vm, newStructure);
- break;
- }
-
- default:
- CRASH();
- break;
- }
- }
- void JSObject::putDirectVirtual(JSObject* object, ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes)
- {
- ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
- PutPropertySlot slot;
- object->putDirectInternal<PutModeDefineOwnProperty>(exec->vm(), propertyName, value, attributes, slot, getCallableObject(value));
- }
- void JSObject::setPrototype(VM& vm, JSValue prototype)
- {
- ASSERT(prototype);
- if (prototype.isObject())
- vm.prototypeMap.addPrototype(asObject(prototype));
-
- Structure* newStructure = Structure::changePrototypeTransition(vm, structure(), prototype);
- setStructure(vm, newStructure);
-
- if (!newStructure->anyObjectInChainMayInterceptIndexedAccesses())
- return;
-
- if (vm.prototypeMap.isPrototype(this)) {
- newStructure->globalObject()->haveABadTime(vm);
- return;
- }
-
- if (!hasIndexingHeader(structure()->indexingType()))
- return;
-
- if (shouldUseSlowPut(structure()->indexingType()))
- return;
-
- switchToSlowPutArrayStorage(vm);
- }
- bool JSObject::setPrototypeWithCycleCheck(VM& vm, JSValue prototype)
- {
- JSValue checkFor = this;
- if (this->isGlobalObject())
- checkFor = jsCast<JSGlobalObject*>(this)->globalExec()->thisValue();
- JSValue nextPrototype = prototype;
- while (nextPrototype && nextPrototype.isObject()) {
- if (nextPrototype == checkFor)
- return false;
- nextPrototype = asObject(nextPrototype)->prototype();
- }
- setPrototype(vm, prototype);
- return true;
- }
- bool JSObject::allowsAccessFrom(ExecState* exec)
- {
- JSGlobalObject* globalObject = this->globalObject();
- return globalObject->globalObjectMethodTable()->allowsAccessFrom(globalObject, exec);
- }
- void JSObject::putDirectAccessor(ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes)
- {
- ASSERT(value.isGetterSetter() && (attributes & Accessor));
- unsigned index = propertyName.asIndex();
- if (index != PropertyName::NotAnIndex) {
- putDirectIndex(exec, index, value, attributes, PutDirectIndexLikePutDirect);
- return;
- }
- VM& vm = exec->vm();
- PutPropertySlot slot;
- putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot, getCallableObject(value));
- // putDirect will change our Structure if we add a new property. For
- // getters and setters, though, we also need to change our Structure
- // if we override an existing non-getter or non-setter.
- if (slot.type() != PutPropertySlot::NewProperty)
- setStructure(vm, Structure::attributeChangeTransition(vm, structure(), propertyName, attributes));
- if (attributes & ReadOnly)
- structure()->setContainsReadOnlyProperties();
- structure()->setHasGetterSetterProperties(propertyName == vm.propertyNames->underscoreProto);
- }
- bool JSObject::hasProperty(ExecState* exec, PropertyName propertyName) const
- {
- PropertySlot slot;
- return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
- }
- bool JSObject::hasProperty(ExecState* exec, unsigned propertyName) const
- {
- PropertySlot slot;
- return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
- }
- // ECMA 8.6.2.5
- bool JSObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
- {
- JSObject* thisObject = jsCast<JSObject*>(cell);
-
- unsigned i = propertyName.asIndex();
- if (i != PropertyName::NotAnIndex)
- return thisObject->methodTable()->deletePropertyByIndex(thisObject, exec, i);
- if (!thisObject->staticFunctionsReified())
- thisObject->reifyStaticFunctionsForDelete(exec);
- unsigned attributes;
- JSCell* specificValue;
- if (isValidOffset(thisObject->structure()->get(exec->vm(), propertyName, attributes, specificValue))) {
- if (attributes & DontDelete && !exec->vm().isInDefineOwnProperty())
- return false;
- thisObject->removeDirect(exec->vm(), propertyName);
- return true;
- }
- // Look in the static hashtable of properties
- const HashEntry* entry = thisObject->findPropertyHashEntry(exec, propertyName);
- if (entry) {
- if (entry->attributes() & DontDelete && !exec->vm().isInDefineOwnProperty())
- return false; // this builtin property can't be deleted
- putEntry(exec, entry, propertyName, jsUndefined(), thisObject);
- }
- return true;
- }
- bool JSObject::hasOwnProperty(ExecState* exec, PropertyName propertyName) const
- {
- PropertySlot slot;
- return const_cast<JSObject*>(this)->methodTable()->getOwnPropertySlot(const_cast<JSObject*>(this), exec, propertyName, slot);
- }
- bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
- {
- JSObject* thisObject = jsCast<JSObject*>(cell);
-
- if (i > MAX_ARRAY_INDEX)
- return thisObject->methodTable()->deleteProperty(thisObject, exec, Identifier::from(exec, i));
-
- switch (thisObject->structure()->indexingType()) {
- case ALL_BLANK_INDEXING_TYPES:
- case ALL_UNDECIDED_INDEXING_TYPES:
- return true;
-
- case ALL_INT32_INDEXING_TYPES:
- case ALL_CONTIGUOUS_INDEXING_TYPES: {
- Butterfly* butterfly = thisObject->m_butterfly;
- if (i >= butterfly->vectorLength())
- return true;
- butterfly->contiguous()[i].clear();
- return true;
- }
-
- case ALL_DOUBLE_INDEXING_TYPES: {
- Butterfly* butterfly = thisObject->m_butterfly;
- if (i >= butterfly->vectorLength())
- return true;
- butterfly->contiguousDouble()[i] = QNaN;
- return true;
- }
-
- case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
- ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
-
- if (i < storage->vectorLength()) {
- WriteBarrier<Unknown>& valueSlot = storage->m_vector[i];
- if (valueSlot) {
- valueSlot.clear();
- --storage->m_numValuesInVector;
- }
- } else if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
- SparseArrayValueMap::iterator it = map->find(i);
- if (it != map->notFound()) {
- if (it->value.attributes & DontDelete)
- return false;
- map->remove(it);
- }
- }
-
- return true;
- }
-
- default:
- RELEASE_ASSERT_NOT_REACHED();
- return false;
- }
- }
- static ALWAYS_INLINE JSValue callDefaultValueFunction(ExecState* exec, const JSObject* object, PropertyName propertyName)
- {
- JSValue function = object->get(exec, propertyName);
- CallData callData;
- CallType callType = getCallData(function, callData);
- if (callType == CallTypeNone)
- return exec->exception();
- // Prevent "toString" and "valueOf" from observing execution if an exception
- // is pending.
- if (exec->hadException())
- return exec->exception();
- JSValue result = call(exec, function, callType, callData, const_cast<JSObject*>(object), exec->emptyList());
- ASSERT(!result.isGetterSetter());
- if (exec->hadException())
- return exec->exception();
- if (result.isObject())
- return JSValue();
- return result;
- }
- bool JSObject::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result) const
- {
- result = methodTable()->defaultValue(this, exec, PreferNumber);
- number = result.toNumber(exec);
- return !result.isString();
- }
- // ECMA 8.6.2.6
- JSValue JSObject::defaultValue(const JSObject* object, ExecState* exec, PreferredPrimitiveType hint)
- {
- // Must call toString first for Date objects.
- if ((hint == PreferString) || (hint != PreferNumber && object->prototype() == exec->lexicalGlobalObject()->datePrototype())) {
- JSValue value = callDefaultValueFunction(exec, object, exec->propertyNames().toString);
- if (value)
- return value;
- value = callDefaultValueFunction(exec, object, exec->propertyNames().valueOf);
- if (value)
- return value;
- } else {
- JSValue value = callDefaultValueFunction(exec, object, exec->propertyNames().valueOf);
- if (value)
- return value;
- value = callDefaultValueFunction(exec, object, exec->propertyNames().toString);
- if (value)
- return value;
- }
- ASSERT(!exec->hadException());
- return throwError(exec, createTypeError(exec, ASCIILiteral("No default value")));
- }
- const HashEntry* JSObject::findPropertyHashEntry(ExecState* exec, PropertyName propertyName) const
- {
- for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
- if (co