+ ASSERT(v.isNumber());
+ currentAsValue->setWithoutWriteBarrier(v);
+ }
+
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous), m_butterfly);
+ 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, m_butterfly);
+ 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, m_butterfly);
+
+ 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), m_butterfly);
+
+ 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 (const HashTable* propHashTable = info->propHashTable(exec)) {
+ if (const HashEntry* entry = propHashTable->entry(exec, propertyName))
+ return entry;
+ }
+ }
+ return 0;
+}
+
+bool JSObject::hasInstance(ExecState* exec, JSValue value)
+{
+ TypeInfo info = structure()->typeInfo();
+ if (info.implementsDefaultHasInstance())
+ return defaultHasInstance(exec, value, get(exec, exec->propertyNames().prototype));
+ if (info.implementsHasInstance())
+ return methodTable()->customHasInstance(this, exec, value);
+ throwError(exec, createInvalidParamError(exec, "instanceof" , this));
+ return false;
+}
+
+bool JSObject::defaultHasInstance(ExecState* exec, JSValue value, JSValue proto)
+{
+ if (!value.isObject())
+ return false;
+
+ if (!proto.isObject()) {
+ throwError(exec, createTypeError(exec, ASCIILiteral("instanceof called on an object with an invalid prototype property.")));
+ return false;
+ }
+
+ JSObject* object = asObject(value);
+ while ((object = object->prototype().getObject())) {
+ if (proto == object)
+ return true;
+ }
+ return false;
+}
+
+bool JSObject::propertyIsEnumerable(ExecState* exec, const Identifier& propertyName) const
+{
+ PropertyDescriptor descriptor;
+ if (!const_cast<JSObject*>(this)->methodTable()->getOwnPropertyDescriptor(const_cast<JSObject*>(this), exec, propertyName, descriptor))
+ return false;
+ return descriptor.enumerable();
+}
+
+bool JSObject::getPropertySpecificValue(ExecState* exec, PropertyName propertyName, JSCell*& specificValue) const
+{
+ unsigned attributes;
+ if (isValidOffset(structure()->get(exec->vm(), propertyName, attributes, specificValue)))
+ return true;
+
+ // This could be a function within the static table? - should probably
+ // also look in the hash? This currently should not be a problem, since
+ // we've currently always call 'get' first, which should have populated
+ // the normal storage.
+ return false;
+}
+
+void JSObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ propertyNames.setBaseObject(object);
+ object->methodTable()->getOwnPropertyNames(object, exec, propertyNames, mode);
+
+ if (object->prototype().isNull())
+ return;
+
+ JSObject* prototype = asObject(object->prototype());
+ while(1) {
+ if (prototype->structure()->typeInfo().overridesGetPropertyNames()) {
+ prototype->methodTable()->getPropertyNames(prototype, exec, propertyNames, mode);
+ break;
+ }
+ prototype->methodTable()->getOwnPropertyNames(prototype, exec, propertyNames, mode);
+ JSValue nextProto = prototype->prototype();
+ if (nextProto.isNull())
+ break;
+ prototype = asObject(nextProto);
+ }
+}
+
+void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ // Add numeric properties first. That appears to be the accepted convention.
+ // FIXME: Filling PropertyNameArray with an identifier for every integer
+ // is incredibly inefficient for large arrays. We need a different approach,
+ // which almost certainly means a different structure for PropertyNameArray.
+ switch (object->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 = object->m_butterfly;
+ unsigned usedLength = butterfly->publicLength();
+ for (unsigned i = 0; i < usedLength; ++i) {
+ if (!butterfly->contiguous()[i])
+ continue;
+ propertyNames.add(Identifier::from(exec, i));
+ }
+ break;
+ }
+
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ Butterfly* butterfly = object->m_butterfly;
+ unsigned usedLength = butterfly->publicLength();
+ for (unsigned i = 0; i < usedLength; ++i) {
+ double value = butterfly->contiguousDouble()[i];
+ if (value != value)
+ continue;
+ propertyNames.add(Identifier::from(exec, i));
+ }
+ break;
+ }
+
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
+ ArrayStorage* storage = object->m_butterfly->arrayStorage();
+
+ unsigned usedVectorLength = std::min(storage->length(), storage->vectorLength());
+ for (unsigned i = 0; i < usedVectorLength; ++i) {
+ if (storage->m_vector[i])
+ propertyNames.add(Identifier::from(exec, i));
+ }
+
+ if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
+ Vector<unsigned, 0, UnsafeVectorOverflow> keys;
+ keys.reserveInitialCapacity(map->size());
+
+ SparseArrayValueMap::const_iterator end = map->end();
+ for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) {
+ if (mode == IncludeDontEnumProperties || !(it->value.attributes & DontEnum))
+ keys.uncheckedAppend(static_cast<unsigned>(it->key));
+ }
+
+ std::sort(keys.begin(), keys.end());
+ for (unsigned i = 0; i < keys.size(); ++i)
+ propertyNames.add(Identifier::from(exec, keys[i]));
+ }
+ break;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+
+ object->methodTable()->getOwnNonIndexPropertyNames(object, exec, propertyNames, mode);
+}
+
+void JSObject::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ getClassPropertyNames(exec, object->classInfo(), propertyNames, mode, object->staticFunctionsReified());
+
+ bool canCachePropertiesFromStructure = !propertyNames.size();
+ object->structure()->getPropertyNamesFromStructure(exec->vm(), propertyNames, mode);
+
+ if (canCachePropertiesFromStructure)
+ propertyNames.setNumCacheableSlotsForObject(object, propertyNames.size());
+}
+
+double JSObject::toNumber(ExecState* exec) const
+{
+ JSValue primitive = toPrimitive(exec, PreferNumber);
+ if (exec->hadException()) // should be picked up soon in Nodes.cpp
+ return 0.0;
+ return primitive.toNumber(exec);
+}
+
+JSString* JSObject::toString(ExecState* exec) const
+{
+ JSValue primitive = toPrimitive(exec, PreferString);
+ if (exec->hadException())
+ return jsEmptyString(exec);
+ return primitive.toString(exec);
+}
+
+JSObject* JSObject::toThisObject(JSCell* cell, ExecState*)
+{
+ return jsCast<JSObject*>(cell);
+}
+
+void JSObject::seal(VM& vm)
+{
+ if (isSealed(vm))
+ return;
+ preventExtensions(vm);
+ setStructure(vm, Structure::sealTransition(vm, structure()), m_butterfly);
+}
+
+void JSObject::freeze(VM& vm)
+{
+ if (isFrozen(vm))
+ return;
+ preventExtensions(vm);
+ setStructure(vm, Structure::freezeTransition(vm, structure()), m_butterfly);
+}
+
+void JSObject::preventExtensions(VM& vm)
+{
+ enterDictionaryIndexingMode(vm);
+ if (isExtensible())
+ setStructure(vm, Structure::preventExtensionsTransition(vm, structure()), m_butterfly);
+}
+
+// This presently will flatten to an uncachable dictionary; this is suitable
+// for use in delete, we may want to do something different elsewhere.
+void JSObject::reifyStaticFunctionsForDelete(ExecState* exec)
+{
+ ASSERT(!staticFunctionsReified());
+ VM& vm = exec->vm();
+
+ // If this object's ClassInfo has no static properties, then nothing to reify!
+ // We can safely set the flag to avoid the expensive check again in the future.
+ if (!classInfo()->hasStaticProperties()) {
+ structure()->setStaticFunctionsReified();
+ return;
+ }
+
+ if (!structure()->isUncacheableDictionary())
+ setStructure(vm, Structure::toUncacheableDictionaryTransition(vm, structure()), m_butterfly);
+
+ for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
+ const HashTable* hashTable = info->propHashTable(globalObject()->globalExec());
+ if (!hashTable)
+ continue;
+ PropertySlot slot;
+ for (HashTable::ConstIterator iter = hashTable->begin(vm); iter != hashTable->end(vm); ++iter) {
+ if (iter->attributes() & Function)
+ setUpStaticFunctionSlot(globalObject()->globalExec(), *iter, this, Identifier(&vm, iter->key()), slot);
+ }
+ }
+
+ structure()->setStaticFunctionsReified();
+}
+
+bool JSObject::removeDirect(VM& vm, PropertyName propertyName)
+{
+ if (!isValidOffset(structure()->get(vm, propertyName)))
+ return false;
+
+ PropertyOffset offset;
+ if (structure()->isUncacheableDictionary()) {
+ offset = structure()->removePropertyWithoutTransition(vm, propertyName);
+ if (offset == invalidOffset)
+ return false;
+ putDirectUndefined(offset);
+ return true;
+ }
+
+ setStructure(vm, Structure::removePropertyTransition(vm, structure(), propertyName, offset), m_butterfly);
+ if (offset == invalidOffset)
+ return false;
+ putDirectUndefined(offset);
+ return true;
+}
+
+NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, PropertyOffset offset)
+{
+ if (JSObject* getterFunction = asGetterSetter(getDirect(offset))->getter()) {
+ if (!structure()->isDictionary())
+ slot.setCacheableGetterSlot(this, getterFunction, offset);
+ else
+ slot.setGetterSlot(getterFunction);
+ } else
+ slot.setUndefined();
+}
+
+void JSObject::putIndexedDescriptor(ExecState* exec, SparseArrayEntry* entryInMap, PropertyDescriptor& descriptor, PropertyDescriptor& oldDescriptor)
+{
+ if (descriptor.isDataDescriptor()) {
+ if (descriptor.value())
+ entryInMap->set(exec->vm(), this, descriptor.value());
+ else if (oldDescriptor.isAccessorDescriptor())
+ entryInMap->set(exec->vm(), this, jsUndefined());
+ entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~Accessor;
+ return;
+ }
+
+ if (descriptor.isAccessorDescriptor()) {
+ JSObject* getter = 0;
+ if (descriptor.getterPresent())
+ getter = descriptor.getterObject();
+ else if (oldDescriptor.isAccessorDescriptor())
+ getter = oldDescriptor.getterObject();
+ JSObject* setter = 0;
+ if (descriptor.setterPresent())
+ setter = descriptor.setterObject();
+ else if (oldDescriptor.isAccessorDescriptor())
+ setter = oldDescriptor.setterObject();
+
+ GetterSetter* accessor = GetterSetter::create(exec);
+ if (getter)
+ accessor->setGetter(exec->vm(), getter);
+ if (setter)
+ accessor->setSetter(exec->vm(), setter);
+
+ entryInMap->set(exec->vm(), this, accessor);
+ entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~ReadOnly;
+ return;