+ ASSERT(hasDouble(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 = JSValue(JSValue::EncodeAsDouble, value);
+ currentAsValue->setWithoutWriteBarrier(v);
+ }
+
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateContiguous));
+ return m_butterfly->contiguous();
+}
+
+ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm, NonPropertyTransition transition)
+{
+ DeferGC deferGC(vm.heap);
+ ASSERT(hasDouble(indexingType()));
+
+ unsigned vectorLength = m_butterfly->vectorLength();
+ ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength);
+ for (unsigned i = 0; i < m_butterfly->publicLength(); i++) {
+ double value = m_butterfly->contiguousDouble()[i];
+ if (value == value) {
+ newStorage->m_vector[i].setWithoutWriteBarrier(JSValue(JSValue::EncodeAsDouble, value));
+ newStorage->m_numValuesInVector++;
+ } else
+ ASSERT(newStorage->m_vector[i].get().isEmpty());
+ }
+
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), transition);
+ setStructureAndButterfly(vm, newStructure, newStorage->butterfly());
+ return newStorage;
+}
+
+ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm)
+{
+ return convertDoubleToArrayStorage(vm, structure(vm)->suggestedArrayStorageTransition());
+}
+
+ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm, NonPropertyTransition transition)
+{
+ DeferGC deferGC(vm.heap);
+ ASSERT(hasContiguous(indexingType()));
+
+ unsigned vectorLength = m_butterfly->vectorLength();
+ ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength);
+ for (unsigned i = 0; i < m_butterfly->publicLength(); i++) {
+ JSValue v = m_butterfly->contiguous()[i].get();
+ if (v) {
+ newStorage->m_vector[i].setWithoutWriteBarrier(v);
+ newStorage->m_numValuesInVector++;
+ } else
+ ASSERT(newStorage->m_vector[i].get().isEmpty());
+ }
+
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), transition);
+ setStructureAndButterfly(vm, newStructure, newStorage->butterfly());
+ return newStorage;
+}
+
+ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm)
+{
+ return convertContiguousToArrayStorage(vm, structure(vm)->suggestedArrayStorageTransition());
+}
+
+void JSObject::convertUndecidedForValue(VM& vm, JSValue value)
+{
+ if (value.isInt32()) {
+ convertUndecidedToInt32(vm);
+ return;
+ }
+
+ if (value.isDouble() && value.asNumber() == value.asNumber()) {
+ convertUndecidedToDouble(vm);
+ return;
+ }
+
+ convertUndecidedToContiguous(vm);
+}
+
+void JSObject::createInitialForValueAndSet(VM& vm, unsigned index, JSValue value)
+{
+ if (value.isInt32()) {
+ createInitialInt32(vm, index + 1)[index].set(vm, this, value);
+ return;
+ }
+
+ if (value.isDouble()) {
+ double doubleValue = value.asNumber();
+ if (doubleValue == doubleValue) {
+ createInitialDouble(vm, index + 1)[index] = doubleValue;
+ return;
+ }
+ }
+
+ createInitialContiguous(vm, index + 1)[index].set(vm, this, value);
+}
+
+void JSObject::convertInt32ForValue(VM& vm, JSValue value)
+{
+ ASSERT(!value.isInt32());
+
+ if (value.isDouble() && !std::isnan(value.asDouble())) {
+ 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(info()));
+
+ switch (indexingType()) {
+ case ALL_BLANK_INDEXING_TYPES:
+ if (UNLIKELY(indexingShouldBeSparse() || structure(vm)->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(info()));
+
+ switch (indexingType()) {
+ case ALL_BLANK_INDEXING_TYPES:
+ if (UNLIKELY(indexingShouldBeSparse() || structure(vm)->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)
+{
+ ASSERT(inherits(info()));
+
+ switch (indexingType()) {
+ case ALL_BLANK_INDEXING_TYPES:
+ if (UNLIKELY(indexingShouldBeSparse() || structure(vm)->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:
+ return convertDoubleToContiguous(vm);
+
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ return ContiguousJSValues();
+
+ default:
+ CRASH();
+ return ContiguousJSValues();
+ }
+}
+
+ArrayStorage* JSObject::ensureArrayStorageSlow(VM& vm)
+{
+ ASSERT(inherits(info()));
+
+ switch (indexingType()) {
+ case ALL_BLANK_INDEXING_TYPES:
+ if (UNLIKELY(indexingShouldBeSparse()))
+ return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm);
+ return createInitialArrayStorage(vm);
+
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ ASSERT(!indexingShouldBeSparse());
+ ASSERT(!structure(vm)->needsSlowPutIndexing());
+ return convertUndecidedToArrayStorage(vm);
+
+ case ALL_INT32_INDEXING_TYPES:
+ ASSERT(!indexingShouldBeSparse());
+ ASSERT(!structure(vm)->needsSlowPutIndexing());
+ return convertInt32ToArrayStorage(vm);
+
+ case ALL_DOUBLE_INDEXING_TYPES:
+ ASSERT(!indexingShouldBeSparse());
+ ASSERT(!structure(vm)->needsSlowPutIndexing());
+ return convertDoubleToArrayStorage(vm);
+
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ ASSERT(!indexingShouldBeSparse());
+ ASSERT(!structure(vm)->needsSlowPutIndexing());
+ return convertContiguousToArrayStorage(vm);
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ return 0;
+ }
+}
+
+ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(VM& vm)
+{
+ switch (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 (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(vm), SwitchToSlowPutArrayStorage);
+ setStructure(vm, newStructure);
+ break;
+ }
+
+ default:
+ CRASH();
+ break;
+ }
+}
+
+void JSObject::setPrototype(VM& vm, JSValue prototype)
+{
+ ASSERT(prototype);
+ if (prototype.isObject())
+ vm.prototypeMap.addPrototype(asObject(prototype));
+
+ Structure* newStructure = Structure::changePrototypeTransition(vm, structure(vm), prototype);
+ setStructure(vm, newStructure);
+
+ if (!newStructure->anyObjectInChainMayInterceptIndexedAccesses())
+ return;
+
+ if (vm.prototypeMap.isPrototype(this)) {
+ newStructure->globalObject()->haveABadTime(vm);
+ return;
+ }
+
+ if (!hasIndexedProperties(indexingType()))
+ return;
+
+ if (shouldUseSlowPut(indexingType()))
+ return;
+
+ switchToSlowPutArrayStorage(vm);
+}
+
+bool JSObject::setPrototypeWithCycleCheck(ExecState* exec, JSValue prototype)
+{
+ ASSERT(methodTable(exec->vm())->toThis(this, exec, NotStrictMode) == this);
+ JSValue nextPrototype = prototype;
+ while (nextPrototype && nextPrototype.isObject()) {
+ if (nextPrototype == this)
+ return false;
+ nextPrototype = asObject(nextPrototype)->prototype();
+ }
+ setPrototype(exec->vm(), prototype);
+ return true;
+}
+
+bool JSObject::allowsAccessFrom(ExecState* exec)
+{
+ JSGlobalObject* globalObject = this->globalObject();
+ return globalObject->globalObjectMethodTable()->allowsAccessFrom(globalObject, exec);
+}
+
+void JSObject::putGetter(ExecState* exec, PropertyName propertyName, JSValue getter)
+{
+ PropertyDescriptor descriptor;
+ descriptor.setGetter(getter);
+ descriptor.setEnumerable(true);
+ descriptor.setConfigurable(true);
+ defineOwnProperty(this, exec, propertyName, descriptor, false);
+}
+
+void JSObject::putSetter(ExecState* exec, PropertyName propertyName, JSValue setter)
+{
+ PropertyDescriptor descriptor;
+ descriptor.setSetter(setter);
+ descriptor.setEnumerable(true);
+ descriptor.setConfigurable(true);
+ defineOwnProperty(this, exec, propertyName, descriptor, false);
+}
+
+void JSObject::putDirectAccessor(ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes)
+{
+ ASSERT(value.isGetterSetter() && (attributes & Accessor));
+
+ if (Optional<uint32_t> index = parseIndex(propertyName)) {
+ putDirectIndex(exec, index.value(), value, attributes, PutDirectIndexLikePutDirect);
+ return;
+ }
+
+ putDirectNonIndexAccessor(exec->vm(), propertyName, value, attributes);
+}
+
+void JSObject::putDirectCustomAccessor(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
+{
+ ASSERT(!parseIndex(propertyName));
+
+ PutPropertySlot slot(this);
+ putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot);
+
+ ASSERT(slot.type() == PutPropertySlot::NewProperty);
+
+ Structure* structure = this->structure(vm);
+ if (attributes & ReadOnly)
+ structure->setContainsReadOnlyProperties();
+ structure->setHasCustomGetterSetterPropertiesWithProtoCheck(propertyName == vm.propertyNames->underscoreProto);
+}
+
+void JSObject::putDirectNonIndexAccessor(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
+{
+ PutPropertySlot slot(this);
+ putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot);
+
+ Structure* structure = this->structure(vm);
+ if (attributes & ReadOnly)
+ structure->setContainsReadOnlyProperties();
+
+ structure->setHasGetterSetterPropertiesWithProtoCheck(propertyName == vm.propertyNames->underscoreProto);
+}
+
+bool JSObject::hasProperty(ExecState* exec, PropertyName propertyName) const
+{
+ PropertySlot slot(this);