2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
4 * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2012, 2013 Apple Inc. All rights reserved.
5 * Copyright (C) 2007 Eric Seidel (eric@webkit.org)
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
27 #include "ButterflyInlines.h"
28 #include "CopiedSpaceInlines.h"
29 #include "CopyVisitor.h"
30 #include "CopyVisitorInlines.h"
31 #include "DatePrototype.h"
32 #include "ErrorConstructor.h"
33 #include "Executable.h"
34 #include "GetterSetter.h"
35 #include "IndexingHeaderInlines.h"
36 #include "JSFunction.h"
37 #include "JSGlobalObject.h"
39 #include "NativeErrorConstructor.h"
41 #include "ObjectPrototype.h"
42 #include "Operations.h"
43 #include "PropertyDescriptor.h"
44 #include "PropertyNameArray.h"
46 #include "SlotVisitorInlines.h"
48 #include <wtf/Assertions.h>
52 // We keep track of the size of the last array after it was grown. We use this
53 // as a simple heuristic for as the value to grow the next array from size 0.
54 // This value is capped by the constant FIRST_VECTOR_GROW defined in
55 // ArrayConventions.h.
56 static unsigned lastArraySize = 0;
58 JSCell* getCallableObjectSlow(JSCell* cell)
60 Structure* structure = cell->structure();
61 if (structure->typeInfo().type() == JSFunctionType)
63 if (structure->classInfo()->isSubClassOf(InternalFunction::info()))
68 ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSObject);
69 ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSFinalObject);
71 const char* StrictModeReadonlyPropertyWriteError = "Attempted to assign to readonly property.";
73 const ClassInfo JSObject::s_info = { "Object", 0, 0, 0, CREATE_METHOD_TABLE(JSObject) };
75 const ClassInfo JSFinalObject::s_info = { "Object", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSFinalObject) };
77 static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode, bool didReify)
79 // Add properties from the static hashtables of properties
80 for (; classInfo; classInfo = classInfo->parentClass) {
81 const HashTable* table = classInfo->propHashTable(exec);
84 table->initializeIfNeeded(exec);
87 int hashSizeMask = table->compactSize - 1;
88 const HashEntry* entry = table->table;
89 for (int i = 0; i <= hashSizeMask; ++i, ++entry) {
90 if (entry->key() && (!(entry->attributes() & DontEnum) || (mode == IncludeDontEnumProperties)) && !((entry->attributes() & Function) && didReify))
91 propertyNames.add(entry->key());
96 ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butterfly, size_t storageSize)
100 Structure* structure = this->structure();
102 size_t propertyCapacity = structure->outOfLineCapacity();
104 size_t indexingPayloadSizeInBytes;
105 bool hasIndexingHeader = this->hasIndexingHeader();
106 if (UNLIKELY(hasIndexingHeader)) {
107 preCapacity = butterfly->indexingHeader()->preCapacity(structure);
108 indexingPayloadSizeInBytes = butterfly->indexingHeader()->indexingPayloadSizeInBytes(structure);
111 indexingPayloadSizeInBytes = 0;
113 size_t capacityInBytes = Butterfly::totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
114 if (visitor.checkIfShouldCopy(butterfly->base(preCapacity, propertyCapacity))) {
115 Butterfly* newButterfly = Butterfly::createUninitializedDuringCollection(visitor, preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
117 // Copy the properties.
118 PropertyStorage currentTarget = newButterfly->propertyStorage();
119 PropertyStorage currentSource = butterfly->propertyStorage();
120 for (size_t count = storageSize; count--;)
121 (--currentTarget)->setWithoutWriteBarrier((--currentSource)->get());
123 if (UNLIKELY(hasIndexingHeader)) {
124 *newButterfly->indexingHeader() = *butterfly->indexingHeader();
126 // Copy the array if appropriate.
128 WriteBarrier<Unknown>* currentTarget;
129 WriteBarrier<Unknown>* currentSource;
132 switch (structure->indexingType()) {
133 case ALL_UNDECIDED_INDEXING_TYPES:
134 case ALL_CONTIGUOUS_INDEXING_TYPES:
135 case ALL_INT32_INDEXING_TYPES:
136 case ALL_DOUBLE_INDEXING_TYPES: {
137 currentTarget = newButterfly->contiguous().data();
138 currentSource = butterfly->contiguous().data();
139 RELEASE_ASSERT(newButterfly->publicLength() <= newButterfly->vectorLength());
140 count = newButterfly->vectorLength();
144 case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
145 newButterfly->arrayStorage()->copyHeaderFromDuringGC(*butterfly->arrayStorage());
146 currentTarget = newButterfly->arrayStorage()->m_vector;
147 currentSource = butterfly->arrayStorage()->m_vector;
148 count = newButterfly->arrayStorage()->vectorLength();
159 memcpy(currentTarget, currentSource, count * sizeof(EncodedJSValue));
162 m_butterfly = newButterfly;
163 visitor.didCopy(butterfly->base(preCapacity, propertyCapacity), capacityInBytes);
167 ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* butterfly, size_t storageSize)
171 Structure* structure = this->structure();
173 size_t propertyCapacity = structure->outOfLineCapacity();
175 size_t indexingPayloadSizeInBytes;
176 bool hasIndexingHeader = this->hasIndexingHeader();
177 if (UNLIKELY(hasIndexingHeader)) {
178 preCapacity = butterfly->indexingHeader()->preCapacity(structure);
179 indexingPayloadSizeInBytes = butterfly->indexingHeader()->indexingPayloadSizeInBytes(structure);
182 indexingPayloadSizeInBytes = 0;
184 size_t capacityInBytes = Butterfly::totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
186 // Mark the properties.
187 visitor.appendValues(butterfly->propertyStorage() - storageSize, storageSize);
189 this, ButterflyCopyToken,
190 butterfly->base(preCapacity, propertyCapacity), capacityInBytes);
192 // Mark the array if appropriate.
193 switch (structure->indexingType()) {
194 case ALL_CONTIGUOUS_INDEXING_TYPES:
195 visitor.appendValues(butterfly->contiguous().data(), butterfly->publicLength());
197 case ALL_ARRAY_STORAGE_INDEXING_TYPES:
198 visitor.appendValues(butterfly->arrayStorage()->m_vector, butterfly->arrayStorage()->vectorLength());
199 if (butterfly->arrayStorage()->m_sparseMap)
200 visitor.append(&butterfly->arrayStorage()->m_sparseMap);
207 void JSObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
209 JSObject* thisObject = jsCast<JSObject*>(cell);
210 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
212 bool wasCheckingForDefaultMarkViolation = visitor.m_isCheckingForDefaultMarkViolation;
213 visitor.m_isCheckingForDefaultMarkViolation = false;
216 JSCell::visitChildren(thisObject, visitor);
218 Butterfly* butterfly = thisObject->butterfly();
220 thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
223 visitor.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation;
227 void JSObject::copyBackingStore(JSCell* cell, CopyVisitor& visitor, CopyToken token)
229 JSObject* thisObject = jsCast<JSObject*>(cell);
230 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
232 if (token != ButterflyCopyToken)
235 Butterfly* butterfly = thisObject->butterfly();
237 thisObject->copyButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
240 void JSFinalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
242 JSFinalObject* thisObject = jsCast<JSFinalObject*>(cell);
243 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
245 bool wasCheckingForDefaultMarkViolation = visitor.m_isCheckingForDefaultMarkViolation;
246 visitor.m_isCheckingForDefaultMarkViolation = false;
249 JSCell::visitChildren(thisObject, visitor);
251 Butterfly* butterfly = thisObject->butterfly();
253 thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
255 size_t storageSize = thisObject->structure()->inlineSize();
256 visitor.appendValues(thisObject->inlineStorage(), storageSize);
259 visitor.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation;
263 String JSObject::className(const JSObject* object)
265 const ClassInfo* info = object->classInfo();
267 return info->className;
270 bool JSObject::getOwnPropertySlotByIndex(JSObject* thisObject, ExecState* exec, unsigned i, PropertySlot& slot)
272 // NB. The fact that we're directly consulting our indexed storage implies that it is not
273 // legal for anyone to override getOwnPropertySlot() without also overriding
274 // getOwnPropertySlotByIndex().
276 if (i > MAX_ARRAY_INDEX)
277 return thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, Identifier::from(exec, i), slot);
279 switch (thisObject->structure()->indexingType()) {
280 case ALL_BLANK_INDEXING_TYPES:
281 case ALL_UNDECIDED_INDEXING_TYPES:
284 case ALL_INT32_INDEXING_TYPES:
285 case ALL_CONTIGUOUS_INDEXING_TYPES: {
286 Butterfly* butterfly = thisObject->m_butterfly;
287 if (i >= butterfly->vectorLength())
290 JSValue value = butterfly->contiguous()[i].get();
292 slot.setValue(thisObject, None, value);
299 case ALL_DOUBLE_INDEXING_TYPES: {
300 Butterfly* butterfly = thisObject->m_butterfly;
301 if (i >= butterfly->vectorLength())
304 double value = butterfly->contiguousDouble()[i];
305 if (value == value) {
306 slot.setValue(thisObject, None, JSValue(JSValue::EncodeAsDouble, value));
313 case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
314 ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
315 if (i >= storage->length())
318 if (i < storage->vectorLength()) {
319 JSValue value = storage->m_vector[i].get();
321 slot.setValue(thisObject, None, value);
324 } else if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
325 SparseArrayValueMap::iterator it = map->find(i);
326 if (it != map->notFound()) {
327 it->value.get(thisObject, slot);
335 RELEASE_ASSERT_NOT_REACHED();
343 void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
345 JSObject* thisObject = jsCast<JSObject*>(cell);
347 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
350 // Try indexed put first. This is required for correctness, since loads on property names that appear like
351 // valid indices will never look in the named property storage.
352 unsigned i = propertyName.asIndex();
353 if (i != PropertyName::NotAnIndex) {
354 putByIndex(thisObject, exec, i, value, slot.isStrictMode());
358 // Check if there are any setters or getters in the prototype chain
360 if (propertyName != exec->propertyNames().underscoreProto) {
361 for (JSObject* obj = thisObject; !obj->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) {
362 prototype = obj->prototype();
363 if (prototype.isNull()) {
364 ASSERT(!thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName));
365 if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot, getCallableObject(value))
366 && slot.isStrictMode())
367 throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
374 for (obj = thisObject; ; obj = asObject(prototype)) {
376 JSCell* specificValue;
377 PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes, specificValue);
378 if (isValidOffset(offset)) {
379 if (attributes & ReadOnly) {
380 ASSERT(thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject);
381 if (slot.isStrictMode())
382 throwError(exec, createTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError)));
386 JSValue gs = obj->getDirect(offset);
387 if (gs.isGetterSetter()) {
388 callSetter(exec, cell, gs, value, slot.isStrictMode() ? StrictMode : NotStrictMode);
391 ASSERT(!(attributes & Accessor));
393 // If there's an existing property on the object or one of its
394 // prototypes it should be replaced, so break here.
398 prototype = obj->prototype();
399 if (prototype.isNull())
403 ASSERT(!thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject);
404 if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot, getCallableObject(value)) && slot.isStrictMode())
405 throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
409 void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
411 JSObject* thisObject = jsCast<JSObject*>(cell);
413 if (propertyName > MAX_ARRAY_INDEX) {
414 PutPropertySlot slot(shouldThrow);
415 thisObject->methodTable()->put(thisObject, exec, Identifier::from(exec, propertyName), value, slot);
419 switch (thisObject->structure()->indexingType()) {
420 case ALL_BLANK_INDEXING_TYPES:
423 case ALL_UNDECIDED_INDEXING_TYPES: {
424 thisObject->convertUndecidedForValue(exec->vm(), value);
426 putByIndex(cell, exec, propertyName, value, shouldThrow);
430 case ALL_INT32_INDEXING_TYPES: {
431 if (!value.isInt32()) {
432 thisObject->convertInt32ForValue(exec->vm(), value);
433 putByIndex(cell, exec, propertyName, value, shouldThrow);
439 case ALL_CONTIGUOUS_INDEXING_TYPES: {
440 Butterfly* butterfly = thisObject->m_butterfly;
441 if (propertyName >= butterfly->vectorLength())
443 butterfly->contiguous()[propertyName].set(exec->vm(), thisObject, value);
444 if (propertyName >= butterfly->publicLength())
445 butterfly->setPublicLength(propertyName + 1);
449 case ALL_DOUBLE_INDEXING_TYPES: {
450 if (!value.isNumber()) {
451 thisObject->convertDoubleToContiguous(exec->vm());
453 putByIndex(cell, exec, propertyName, value, shouldThrow);
456 double valueAsDouble = value.asNumber();
457 if (valueAsDouble != valueAsDouble) {
458 thisObject->convertDoubleToContiguous(exec->vm());
460 putByIndex(cell, exec, propertyName, value, shouldThrow);
463 Butterfly* butterfly = thisObject->m_butterfly;
464 if (propertyName >= butterfly->vectorLength())
466 butterfly->contiguousDouble()[propertyName] = valueAsDouble;
467 if (propertyName >= butterfly->publicLength())
468 butterfly->setPublicLength(propertyName + 1);
472 case NonArrayWithArrayStorage:
473 case ArrayWithArrayStorage: {
474 ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
476 if (propertyName >= storage->vectorLength())
479 WriteBarrier<Unknown>& valueSlot = storage->m_vector[propertyName];
480 unsigned length = storage->length();
482 // Update length & m_numValuesInVector as necessary.
483 if (propertyName >= length) {
484 length = propertyName + 1;
485 storage->setLength(length);
486 ++storage->m_numValuesInVector;
487 } else if (!valueSlot)
488 ++storage->m_numValuesInVector;
490 valueSlot.set(exec->vm(), thisObject, value);
494 case NonArrayWithSlowPutArrayStorage:
495 case ArrayWithSlowPutArrayStorage: {
496 ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
498 if (propertyName >= storage->vectorLength())
501 WriteBarrier<Unknown>& valueSlot = storage->m_vector[propertyName];
502 unsigned length = storage->length();
504 // Update length & m_numValuesInVector as necessary.
505 if (propertyName >= length) {
506 if (thisObject->attemptToInterceptPutByIndexOnHole(exec, propertyName, value, shouldThrow))
508 length = propertyName + 1;
509 storage->setLength(length);
510 ++storage->m_numValuesInVector;
511 } else if (!valueSlot) {
512 if (thisObject->attemptToInterceptPutByIndexOnHole(exec, propertyName, value, shouldThrow))
514 ++storage->m_numValuesInVector;
517 valueSlot.set(exec->vm(), thisObject, value);
522 RELEASE_ASSERT_NOT_REACHED();
525 thisObject->putByIndexBeyondVectorLength(exec, propertyName, value, shouldThrow);
528 ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(VM& vm, ArrayStorage* storage)
530 SparseArrayValueMap* map = storage->m_sparseMap.get();
533 map = allocateSparseIndexMap(vm);
535 if (map->sparseMode())
538 map->setSparseMode();
540 unsigned usedVectorLength = std::min(storage->length(), storage->vectorLength());
541 for (unsigned i = 0; i < usedVectorLength; ++i) {
542 JSValue value = storage->m_vector[i].get();
543 // This will always be a new entry in the map, so no need to check we can write,
544 // and attributes are default so no need to set them.
546 map->add(this, i).iterator->value.set(vm, this, value);
549 DeferGC deferGC(vm.heap);
550 Butterfly* newButterfly = storage->butterfly()->resizeArray(vm, this, structure(), 0, ArrayStorage::sizeFor(0));
551 RELEASE_ASSERT(newButterfly);
553 m_butterfly = newButterfly;
554 newButterfly->arrayStorage()->m_indexBias = 0;
555 newButterfly->arrayStorage()->setVectorLength(0);
556 newButterfly->arrayStorage()->m_sparseMap.set(vm, this, map);
558 return newButterfly->arrayStorage();
561 void JSObject::enterDictionaryIndexingMode(VM& vm)
563 switch (structure()->indexingType()) {
564 case ALL_BLANK_INDEXING_TYPES:
565 case ALL_UNDECIDED_INDEXING_TYPES:
566 case ALL_INT32_INDEXING_TYPES:
567 case ALL_DOUBLE_INDEXING_TYPES:
568 case ALL_CONTIGUOUS_INDEXING_TYPES:
569 // NOTE: this is horribly inefficient, as it will perform two conversions. We could optimize
570 // this case if we ever cared.
571 enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, ensureArrayStorageSlow(vm));
573 case ALL_ARRAY_STORAGE_INDEXING_TYPES:
574 enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, m_butterfly->arrayStorage());
582 void JSObject::notifyPresenceOfIndexedAccessors(VM& vm)
584 if (mayInterceptIndexedAccesses())
587 setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AddIndexedAccessors));
589 if (!vm.prototypeMap.isPrototype(this))
592 globalObject()->haveABadTime(vm);
595 Butterfly* JSObject::createInitialIndexedStorage(VM& vm, unsigned length, size_t elementSize)
597 ASSERT(length < MAX_ARRAY_INDEX);
598 IndexingType oldType = structure()->indexingType();
599 ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
600 ASSERT(!structure()->needsSlowPutIndexing());
601 ASSERT(!indexingShouldBeSparse());
602 unsigned vectorLength = std::max(length, BASE_VECTOR_LEN);
603 Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(
604 m_butterfly, vm, this, structure(), structure()->outOfLineCapacity(), false, 0,
605 elementSize * vectorLength);
606 newButterfly->setPublicLength(length);
607 newButterfly->setVectorLength(vectorLength);
611 Butterfly* JSObject::createInitialUndecided(VM& vm, unsigned length)
613 DeferGC deferGC(vm.heap);
614 Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue));
615 Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateUndecided);
616 setStructureAndButterfly(vm, newStructure, newButterfly);
620 ContiguousJSValues JSObject::createInitialInt32(VM& vm, unsigned length)
622 DeferGC deferGC(vm.heap);
623 Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue));
624 Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateInt32);
625 setStructureAndButterfly(vm, newStructure, newButterfly);
626 return newButterfly->contiguousInt32();
629 ContiguousDoubles JSObject::createInitialDouble(VM& vm, unsigned length)
631 DeferGC deferGC(vm.heap);
632 Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(double));
633 for (unsigned i = newButterfly->vectorLength(); i--;)
634 newButterfly->contiguousDouble()[i] = QNaN;
635 Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateDouble);
636 setStructureAndButterfly(vm, newStructure, newButterfly);
637 return newButterfly->contiguousDouble();
640 ContiguousJSValues JSObject::createInitialContiguous(VM& vm, unsigned length)
642 DeferGC deferGC(vm.heap);
643 Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue));
644 Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateContiguous);
645 setStructureAndButterfly(vm, newStructure, newButterfly);
646 return newButterfly->contiguous();
649 ArrayStorage* JSObject::createArrayStorage(VM& vm, unsigned length, unsigned vectorLength)
651 DeferGC deferGC(vm.heap);
652 IndexingType oldType = structure()->indexingType();
653 ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
654 Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(
655 m_butterfly, vm, this, structure(), structure()->outOfLineCapacity(), false, 0,
656 ArrayStorage::sizeFor(vectorLength));
657 RELEASE_ASSERT(newButterfly);
659 ArrayStorage* result = newButterfly->arrayStorage();
660 result->setLength(length);
661 result->setVectorLength(vectorLength);
662 result->m_sparseMap.clear();
663 result->m_numValuesInVector = 0;
664 result->m_indexBias = 0;
665 Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), structure()->suggestedArrayStorageTransition());
666 setStructureAndButterfly(vm, newStructure, newButterfly);
670 ArrayStorage* JSObject::createInitialArrayStorage(VM& vm)
672 return createArrayStorage(vm, 0, BASE_VECTOR_LEN);
675 ContiguousJSValues JSObject::convertUndecidedToInt32(VM& vm)
677 ASSERT(hasUndecided(structure()->indexingType()));
678 setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateInt32));
679 return m_butterfly->contiguousInt32();
682 ContiguousDoubles JSObject::convertUndecidedToDouble(VM& vm)
684 ASSERT(hasUndecided(structure()->indexingType()));
686 for (unsigned i = m_butterfly->vectorLength(); i--;)
687 m_butterfly->contiguousDouble()[i] = QNaN;
689 setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble));
690 return m_butterfly->contiguousDouble();
693 ContiguousJSValues JSObject::convertUndecidedToContiguous(VM& vm)
695 ASSERT(hasUndecided(structure()->indexingType()));
696 setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous));
697 return m_butterfly->contiguous();
700 ArrayStorage* JSObject::constructConvertedArrayStorageWithoutCopyingElements(VM& vm, unsigned neededLength)
702 unsigned publicLength = m_butterfly->publicLength();
703 unsigned propertyCapacity = structure()->outOfLineCapacity();
704 unsigned propertySize = structure()->outOfLineSize();
706 Butterfly* newButterfly = Butterfly::createUninitialized(
707 vm, this, 0, propertyCapacity, true, ArrayStorage::sizeFor(neededLength));
710 newButterfly->propertyStorage() - propertySize,
711 m_butterfly->propertyStorage() - propertySize,
712 propertySize * sizeof(EncodedJSValue));
714 ArrayStorage* newStorage = newButterfly->arrayStorage();
715 newStorage->setVectorLength(neededLength);
716 newStorage->setLength(publicLength);
717 newStorage->m_sparseMap.clear();
718 newStorage->m_indexBias = 0;
719 newStorage->m_numValuesInVector = 0;
724 ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength)
726 DeferGC deferGC(vm.heap);
727 ASSERT(hasUndecided(structure()->indexingType()));
729 ArrayStorage* storage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength);
730 // No need to copy elements.
732 Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition);
733 setStructureAndButterfly(vm, newStructure, storage->butterfly());
737 ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm, NonPropertyTransition transition)
739 return convertUndecidedToArrayStorage(vm, transition, m_butterfly->vectorLength());
742 ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm)
744 return convertUndecidedToArrayStorage(vm, structure()->suggestedArrayStorageTransition());
747 ContiguousDoubles JSObject::convertInt32ToDouble(VM& vm)
749 ASSERT(hasInt32(structure()->indexingType()));
751 for (unsigned i = m_butterfly->vectorLength(); i--;) {
752 WriteBarrier<Unknown>* current = &m_butterfly->contiguousInt32()[i];
753 double* currentAsDouble = bitwise_cast<double*>(current);
754 JSValue v = current->get();
756 *currentAsDouble = QNaN;
760 *currentAsDouble = v.asInt32();
763 setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble));
764 return m_butterfly->contiguousDouble();
767 ContiguousJSValues JSObject::convertInt32ToContiguous(VM& vm)
769 ASSERT(hasInt32(structure()->indexingType()));
771 setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous));
772 return m_butterfly->contiguous();
775 ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength)
777 ASSERT(hasInt32(structure()->indexingType()));
779 DeferGC deferGC(vm.heap);
780 ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength);
781 for (unsigned i = m_butterfly->publicLength(); i--;) {
782 JSValue v = m_butterfly->contiguous()[i].get();
785 newStorage->m_vector[i].setWithoutWriteBarrier(v);
786 newStorage->m_numValuesInVector++;
789 Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition);
790 setStructureAndButterfly(vm, newStructure, newStorage->butterfly());
794 ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm, NonPropertyTransition transition)
796 return convertInt32ToArrayStorage(vm, transition, m_butterfly->vectorLength());
799 ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm)
801 return convertInt32ToArrayStorage(vm, structure()->suggestedArrayStorageTransition());
804 template<JSObject::DoubleToContiguousMode mode>
805 ContiguousJSValues JSObject::genericConvertDoubleToContiguous(VM& vm)
807 ASSERT(hasDouble(structure()->indexingType()));
809 for (unsigned i = m_butterfly->vectorLength(); i--;) {
810 double* current = &m_butterfly->contiguousDouble()[i];
811 WriteBarrier<Unknown>* currentAsValue = bitwise_cast<WriteBarrier<Unknown>*>(current);
812 double value = *current;
813 if (value != value) {
814 currentAsValue->clear();
819 case EncodeValueAsDouble:
820 v = JSValue(JSValue::EncodeAsDouble, value);
822 case RageConvertDoubleToValue:
826 ASSERT(v.isNumber());
827 currentAsValue->setWithoutWriteBarrier(v);
830 setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous));
831 return m_butterfly->contiguous();
834 ContiguousJSValues JSObject::convertDoubleToContiguous(VM& vm)
836 return genericConvertDoubleToContiguous<EncodeValueAsDouble>(vm);
839 ContiguousJSValues JSObject::rageConvertDoubleToContiguous(VM& vm)
841 return genericConvertDoubleToContiguous<RageConvertDoubleToValue>(vm);
844 ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength)
846 DeferGC deferGC(vm.heap);
847 ASSERT(hasDouble(structure()->indexingType()));
849 ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength);
850 for (unsigned i = m_butterfly->publicLength(); i--;) {
851 double value = m_butterfly->contiguousDouble()[i];
854 newStorage->m_vector[i].setWithoutWriteBarrier(JSValue(JSValue::EncodeAsDouble, value));
855 newStorage->m_numValuesInVector++;
858 Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition);
859 setStructureAndButterfly(vm, newStructure, newStorage->butterfly());
863 ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm, NonPropertyTransition transition)
865 return convertDoubleToArrayStorage(vm, transition, m_butterfly->vectorLength());
868 ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm)
870 return convertDoubleToArrayStorage(vm, structure()->suggestedArrayStorageTransition());
873 ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength)
875 DeferGC deferGC(vm.heap);
876 ASSERT(hasContiguous(structure()->indexingType()));
878 ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength);
879 for (unsigned i = m_butterfly->publicLength(); i--;) {
880 JSValue v = m_butterfly->contiguous()[i].get();
883 newStorage->m_vector[i].setWithoutWriteBarrier(v);
884 newStorage->m_numValuesInVector++;
887 Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition);
888 setStructureAndButterfly(vm, newStructure, newStorage->butterfly());
892 ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm, NonPropertyTransition transition)
894 return convertContiguousToArrayStorage(vm, transition, m_butterfly->vectorLength());
897 ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm)
899 return convertContiguousToArrayStorage(vm, structure()->suggestedArrayStorageTransition());
902 void JSObject::convertUndecidedForValue(VM& vm, JSValue value)
904 if (value.isInt32()) {
905 convertUndecidedToInt32(vm);
909 if (value.isDouble()) {
910 convertUndecidedToDouble(vm);
914 convertUndecidedToContiguous(vm);
917 void JSObject::convertInt32ForValue(VM& vm, JSValue value)
919 ASSERT(!value.isInt32());
921 if (value.isDouble()) {
922 convertInt32ToDouble(vm);
926 convertInt32ToContiguous(vm);
929 void JSObject::setIndexQuicklyToUndecided(VM& vm, unsigned index, JSValue value)
931 ASSERT(index < m_butterfly->publicLength());
932 ASSERT(index < m_butterfly->vectorLength());
933 convertUndecidedForValue(vm, value);
934 setIndexQuickly(vm, index, value);
937 void JSObject::convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(VM& vm, unsigned index, JSValue value)
939 ASSERT(!value.isInt32());
940 convertInt32ForValue(vm, value);
941 setIndexQuickly(vm, index, value);
944 void JSObject::convertDoubleToContiguousWhilePerformingSetIndex(VM& vm, unsigned index, JSValue value)
946 ASSERT(!value.isNumber() || value.asNumber() != value.asNumber());
947 convertDoubleToContiguous(vm);
948 setIndexQuickly(vm, index, value);
951 ContiguousJSValues JSObject::ensureInt32Slow(VM& vm)
953 ASSERT(inherits(info()));
955 switch (structure()->indexingType()) {
956 case ALL_BLANK_INDEXING_TYPES:
957 if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
958 return ContiguousJSValues();
959 return createInitialInt32(vm, 0);
961 case ALL_UNDECIDED_INDEXING_TYPES:
962 return convertUndecidedToInt32(vm);
964 case ALL_DOUBLE_INDEXING_TYPES:
965 case ALL_CONTIGUOUS_INDEXING_TYPES:
966 case ALL_ARRAY_STORAGE_INDEXING_TYPES:
967 return ContiguousJSValues();
971 return ContiguousJSValues();
975 ContiguousDoubles JSObject::ensureDoubleSlow(VM& vm)
977 ASSERT(inherits(info()));
979 switch (structure()->indexingType()) {
980 case ALL_BLANK_INDEXING_TYPES:
981 if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
982 return ContiguousDoubles();
983 return createInitialDouble(vm, 0);
985 case ALL_UNDECIDED_INDEXING_TYPES:
986 return convertUndecidedToDouble(vm);
988 case ALL_INT32_INDEXING_TYPES:
989 return convertInt32ToDouble(vm);
991 case ALL_CONTIGUOUS_INDEXING_TYPES:
992 case ALL_ARRAY_STORAGE_INDEXING_TYPES:
993 return ContiguousDoubles();
997 return ContiguousDoubles();
1001 ContiguousJSValues JSObject::ensureContiguousSlow(VM& vm, DoubleToContiguousMode mode)
1003 ASSERT(inherits(info()));
1005 switch (structure()->indexingType()) {
1006 case ALL_BLANK_INDEXING_TYPES:
1007 if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
1008 return ContiguousJSValues();
1009 return createInitialContiguous(vm, 0);
1011 case ALL_UNDECIDED_INDEXING_TYPES:
1012 return convertUndecidedToContiguous(vm);
1014 case ALL_INT32_INDEXING_TYPES:
1015 return convertInt32ToContiguous(vm);
1017 case ALL_DOUBLE_INDEXING_TYPES:
1018 if (mode == RageConvertDoubleToValue)
1019 return rageConvertDoubleToContiguous(vm);
1020 return convertDoubleToContiguous(vm);
1022 case ALL_ARRAY_STORAGE_INDEXING_TYPES:
1023 return ContiguousJSValues();
1027 return ContiguousJSValues();
1031 ContiguousJSValues JSObject::ensureContiguousSlow(VM& vm)
1033 return ensureContiguousSlow(vm, EncodeValueAsDouble);
1036 ContiguousJSValues JSObject::rageEnsureContiguousSlow(VM& vm)
1038 return ensureContiguousSlow(vm, RageConvertDoubleToValue);
1041 ArrayStorage* JSObject::ensureArrayStorageSlow(VM& vm)
1043 ASSERT(inherits(info()));
1045 switch (structure()->indexingType()) {
1046 case ALL_BLANK_INDEXING_TYPES:
1047 if (UNLIKELY(indexingShouldBeSparse()))
1048 return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm);
1049 return createInitialArrayStorage(vm);
1051 case ALL_UNDECIDED_INDEXING_TYPES:
1052 ASSERT(!indexingShouldBeSparse());
1053 ASSERT(!structure()->needsSlowPutIndexing());
1054 return convertUndecidedToArrayStorage(vm);
1056 case ALL_INT32_INDEXING_TYPES:
1057 ASSERT(!indexingShouldBeSparse());
1058 ASSERT(!structure()->needsSlowPutIndexing());
1059 return convertInt32ToArrayStorage(vm);
1061 case ALL_DOUBLE_INDEXING_TYPES:
1062 ASSERT(!indexingShouldBeSparse());
1063 ASSERT(!structure()->needsSlowPutIndexing());
1064 return convertDoubleToArrayStorage(vm);
1066 case ALL_CONTIGUOUS_INDEXING_TYPES:
1067 ASSERT(!indexingShouldBeSparse());
1068 ASSERT(!structure()->needsSlowPutIndexing());
1069 return convertContiguousToArrayStorage(vm);
1072 RELEASE_ASSERT_NOT_REACHED();
1077 ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(VM& vm)
1079 switch (structure()->indexingType()) {
1080 case ALL_BLANK_INDEXING_TYPES: {
1081 createArrayStorage(vm, 0, 0);
1082 SparseArrayValueMap* map = allocateSparseIndexMap(vm);
1083 map->setSparseMode();
1084 return arrayStorage();
1087 case ALL_UNDECIDED_INDEXING_TYPES:
1088 return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertUndecidedToArrayStorage(vm));
1090 case ALL_INT32_INDEXING_TYPES:
1091 return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertInt32ToArrayStorage(vm));
1093 case ALL_DOUBLE_INDEXING_TYPES:
1094 return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertDoubleToArrayStorage(vm));
1096 case ALL_CONTIGUOUS_INDEXING_TYPES:
1097 return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertContiguousToArrayStorage(vm));
1099 case ALL_ARRAY_STORAGE_INDEXING_TYPES:
1100 return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, m_butterfly->arrayStorage());
1108 void JSObject::switchToSlowPutArrayStorage(VM& vm)
1110 switch (structure()->indexingType()) {
1111 case ALL_UNDECIDED_INDEXING_TYPES:
1112 convertUndecidedToArrayStorage(vm, AllocateSlowPutArrayStorage);
1115 case ALL_INT32_INDEXING_TYPES:
1116 convertInt32ToArrayStorage(vm, AllocateSlowPutArrayStorage);
1119 case ALL_DOUBLE_INDEXING_TYPES:
1120 convertDoubleToArrayStorage(vm, AllocateSlowPutArrayStorage);
1123 case ALL_CONTIGUOUS_INDEXING_TYPES:
1124 convertContiguousToArrayStorage(vm, AllocateSlowPutArrayStorage);
1127 case NonArrayWithArrayStorage:
1128 case ArrayWithArrayStorage: {
1129 Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), SwitchToSlowPutArrayStorage);
1130 setStructure(vm, newStructure);
1140 void JSObject::setPrototype(VM& vm, JSValue prototype)
1143 if (prototype.isObject())
1144 vm.prototypeMap.addPrototype(asObject(prototype));
1146 Structure* newStructure = Structure::changePrototypeTransition(vm, structure(), prototype);
1147 setStructure(vm, newStructure);
1149 if (!newStructure->anyObjectInChainMayInterceptIndexedAccesses())
1152 if (vm.prototypeMap.isPrototype(this)) {
1153 newStructure->globalObject()->haveABadTime(vm);
1157 if (!hasIndexedProperties(structure()->indexingType()))
1160 if (shouldUseSlowPut(structure()->indexingType()))
1163 switchToSlowPutArrayStorage(vm);
1166 bool JSObject::setPrototypeWithCycleCheck(ExecState* exec, JSValue prototype)
1168 ASSERT(methodTable()->toThis(this, exec, NotStrictMode) == this);
1169 JSValue nextPrototype = prototype;
1170 while (nextPrototype && nextPrototype.isObject()) {
1171 if (nextPrototype == this)
1173 nextPrototype = asObject(nextPrototype)->prototype();
1175 setPrototype(exec->vm(), prototype);
1179 bool JSObject::allowsAccessFrom(ExecState* exec)
1181 JSGlobalObject* globalObject = this->globalObject();
1182 return globalObject->globalObjectMethodTable()->allowsAccessFrom(globalObject, exec);
1185 void JSObject::putDirectAccessor(ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes)
1187 ASSERT(value.isGetterSetter() && (attributes & Accessor));
1189 unsigned index = propertyName.asIndex();
1190 if (index != PropertyName::NotAnIndex) {
1191 putDirectIndex(exec, index, value, attributes, PutDirectIndexLikePutDirect);
1195 VM& vm = exec->vm();
1197 PutPropertySlot slot;
1198 putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot, getCallableObject(value));
1200 // putDirect will change our Structure if we add a new property. For
1201 // getters and setters, though, we also need to change our Structure
1202 // if we override an existing non-getter or non-setter.
1203 if (slot.type() != PutPropertySlot::NewProperty)
1204 setStructure(vm, Structure::attributeChangeTransition(vm, structure(), propertyName, attributes));
1206 if (attributes & ReadOnly)
1207 structure()->setContainsReadOnlyProperties();
1209 structure()->setHasGetterSetterProperties(propertyName == vm.propertyNames->underscoreProto);
1212 bool JSObject::hasProperty(ExecState* exec, PropertyName propertyName) const
1214 PropertySlot slot(this);
1215 return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
1218 bool JSObject::hasProperty(ExecState* exec, unsigned propertyName) const
1220 PropertySlot slot(this);
1221 return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
1225 bool JSObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
1227 JSObject* thisObject = jsCast<JSObject*>(cell);
1229 unsigned i = propertyName.asIndex();
1230 if (i != PropertyName::NotAnIndex)
1231 return thisObject->methodTable()->deletePropertyByIndex(thisObject, exec, i);
1233 if (!thisObject->staticFunctionsReified())
1234 thisObject->reifyStaticFunctionsForDelete(exec);
1236 unsigned attributes;
1237 JSCell* specificValue;
1238 if (isValidOffset(thisObject->structure()->get(exec->vm(), propertyName, attributes, specificValue))) {
1239 if (attributes & DontDelete && !exec->vm().isInDefineOwnProperty())
1241 thisObject->removeDirect(exec->vm(), propertyName);
1245 // Look in the static hashtable of properties
1246 const HashEntry* entry = thisObject->findPropertyHashEntry(exec, propertyName);
1248 if (entry->attributes() & DontDelete && !exec->vm().isInDefineOwnProperty())
1249 return false; // this builtin property can't be deleted
1251 putEntry(exec, entry, propertyName, jsUndefined(), thisObject);
1257 bool JSObject::hasOwnProperty(ExecState* exec, PropertyName propertyName) const
1259 PropertySlot slot(this);
1260 return const_cast<JSObject*>(this)->methodTable()->getOwnPropertySlot(const_cast<JSObject*>(this), exec, propertyName, slot);
1263 bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
1265 JSObject* thisObject = jsCast<JSObject*>(cell);
1267 if (i > MAX_ARRAY_INDEX)
1268 return thisObject->methodTable()->deleteProperty(thisObject, exec, Identifier::from(exec, i));
1270 switch (thisObject->structure()->indexingType()) {
1271 case ALL_BLANK_INDEXING_TYPES:
1272 case ALL_UNDECIDED_INDEXING_TYPES:
1275 case ALL_INT32_INDEXING_TYPES:
1276 case ALL_CONTIGUOUS_INDEXING_TYPES: {
1277 Butterfly* butterfly = thisObject->m_butterfly;
1278 if (i >= butterfly->vectorLength())
1280 butterfly->contiguous()[i].clear();
1284 case ALL_DOUBLE_INDEXING_TYPES: {
1285 Butterfly* butterfly = thisObject->m_butterfly;
1286 if (i >= butterfly->vectorLength())
1288 butterfly->contiguousDouble()[i] = QNaN;
1292 case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
1293 ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
1295 if (i < storage->vectorLength()) {
1296 WriteBarrier<Unknown>& valueSlot = storage->m_vector[i];
1299 --storage->m_numValuesInVector;
1301 } else if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
1302 SparseArrayValueMap::iterator it = map->find(i);
1303 if (it != map->notFound()) {
1304 if (it->value.attributes & DontDelete)
1314 RELEASE_ASSERT_NOT_REACHED();
1319 static ALWAYS_INLINE JSValue callDefaultValueFunction(ExecState* exec, const JSObject* object, PropertyName propertyName)
1321 JSValue function = object->get(exec, propertyName);
1323 CallType callType = getCallData(function, callData);
1324 if (callType == CallTypeNone)
1325 return exec->exception();
1327 // Prevent "toString" and "valueOf" from observing execution if an exception
1329 if (exec->hadException())
1330 return exec->exception();
1332 JSValue result = call(exec, function, callType, callData, const_cast<JSObject*>(object), exec->emptyList());
1333 ASSERT(!result.isGetterSetter());
1334 if (exec->hadException())
1335 return exec->exception();
1336 if (result.isObject())
1341 bool JSObject::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result) const
1343 result = methodTable()->defaultValue(this, exec, PreferNumber);
1344 number = result.toNumber(exec);
1345 return !result.isString();
1349 JSValue JSObject::defaultValue(const JSObject* object, ExecState* exec, PreferredPrimitiveType hint)
1351 // Must call toString first for Date objects.
1352 if ((hint == PreferString) || (hint != PreferNumber && object->prototype() == exec->lexicalGlobalObject()->datePrototype())) {
1353 JSValue value = callDefaultValueFunction(exec, object, exec->propertyNames().toString);
1356 value = callDefaultValueFunction(exec, object, exec->propertyNames().valueOf);
1360 JSValue value = callDefaultValueFunction(exec, object, exec->propertyNames().valueOf);
1363 value = callDefaultValueFunction(exec, object, exec->propertyNames().toString);
1368 ASSERT(!exec->hadException());
1370 return throwError(exec, createTypeError(exec, ASCIILiteral("No default value")));
1373 const HashEntry* JSObject::findPropertyHashEntry(ExecState* exec, PropertyName propertyName) const
1375 for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
1376 if (const HashTable* propHashTable = info->propHashTable(exec)) {
1377 if (const HashEntry* entry = propHashTable->entry(exec, propertyName))
1384 bool JSObject::hasInstance(ExecState* exec, JSValue value)
1386 TypeInfo info = structure()->typeInfo();
1387 if (info.implementsDefaultHasInstance())
1388 return defaultHasInstance(exec, value, get(exec, exec->propertyNames().prototype));
1389 if (info.implementsHasInstance())
1390 return methodTable()->customHasInstance(this, exec, value);
1391 throwError(exec, createInvalidParameterError(exec, "instanceof" , this));
1395 bool JSObject::defaultHasInstance(ExecState* exec, JSValue value, JSValue proto)
1397 if (!value.isObject())
1400 if (!proto.isObject()) {
1401 throwError(exec, createTypeError(exec, ASCIILiteral("instanceof called on an object with an invalid prototype property.")));
1405 JSObject* object = asObject(value);
1406 while ((object = object->prototype().getObject())) {
1407 if (proto == object)
1413 bool JSObject::getPropertySpecificValue(ExecState* exec, PropertyName propertyName, JSCell*& specificValue) const
1415 unsigned attributes;
1416 if (isValidOffset(structure()->get(exec->vm(), propertyName, attributes, specificValue)))
1419 // This could be a function within the static table? - should probably
1420 // also look in the hash? This currently should not be a problem, since
1421 // we've currently always call 'get' first, which should have populated
1422 // the normal storage.
1426 void JSObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
1428 propertyNames.setBaseObject(object);
1429 object->methodTable()->getOwnPropertyNames(object, exec, propertyNames, mode);
1431 if (object->prototype().isNull())
1434 JSObject* prototype = asObject(object->prototype());
1436 if (prototype->structure()->typeInfo().overridesGetPropertyNames()) {
1437 prototype->methodTable()->getPropertyNames(prototype, exec, propertyNames, mode);
1440 prototype->methodTable()->getOwnPropertyNames(prototype, exec, propertyNames, mode);
1441 JSValue nextProto = prototype->prototype();
1442 if (nextProto.isNull())
1444 prototype = asObject(nextProto);
1448 void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
1450 // Add numeric properties first. That appears to be the accepted convention.
1451 // FIXME: Filling PropertyNameArray with an identifier for every integer
1452 // is incredibly inefficient for large arrays. We need a different approach,
1453 // which almost certainly means a different structure for PropertyNameArray.
1454 switch (object->structure()->indexingType()) {
1455 case ALL_BLANK_INDEXING_TYPES:
1456 case ALL_UNDECIDED_INDEXING_TYPES:
1459 case ALL_INT32_INDEXING_TYPES:
1460 case ALL_CONTIGUOUS_INDEXING_TYPES: {
1461 Butterfly* butterfly = object->m_butterfly;
1462 unsigned usedLength = butterfly->publicLength();
1463 for (unsigned i = 0; i < usedLength; ++i) {
1464 if (!butterfly->contiguous()[i])
1466 propertyNames.add(Identifier::from(exec, i));
1471 case ALL_DOUBLE_INDEXING_TYPES: {
1472 Butterfly* butterfly = object->m_butterfly;
1473 unsigned usedLength = butterfly->publicLength();
1474 for (unsigned i = 0; i < usedLength; ++i) {
1475 double value = butterfly->contiguousDouble()[i];
1478 propertyNames.add(Identifier::from(exec, i));
1483 case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
1484 ArrayStorage* storage = object->m_butterfly->arrayStorage();
1486 unsigned usedVectorLength = std::min(storage->length(), storage->vectorLength());
1487 for (unsigned i = 0; i < usedVectorLength; ++i) {
1488 if (storage->m_vector[i])
1489 propertyNames.add(Identifier::from(exec, i));
1492 if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
1493 Vector<unsigned, 0, UnsafeVectorOverflow> keys;
1494 keys.reserveInitialCapacity(map->size());
1496 SparseArrayValueMap::const_iterator end = map->end();
1497 for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) {
1498 if (mode == IncludeDontEnumProperties || !(it->value.attributes & DontEnum))
1499 keys.uncheckedAppend(static_cast<unsigned>(it->key));
1502 std::sort(keys.begin(), keys.end());
1503 for (unsigned i = 0; i < keys.size(); ++i)
1504 propertyNames.add(Identifier::from(exec, keys[i]));
1510 RELEASE_ASSERT_NOT_REACHED();
1513 object->methodTable()->getOwnNonIndexPropertyNames(object, exec, propertyNames, mode);
1516 void JSObject::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
1518 getClassPropertyNames(exec, object->classInfo(), propertyNames, mode, object->staticFunctionsReified());
1520 bool canCachePropertiesFromStructure = !propertyNames.size();
1521 object->structure()->getPropertyNamesFromStructure(exec->vm(), propertyNames, mode);
1523 if (canCachePropertiesFromStructure)
1524 propertyNames.setNumCacheableSlotsForObject(object, propertyNames.size());
1527 double JSObject::toNumber(ExecState* exec) const
1529 JSValue primitive = toPrimitive(exec, PreferNumber);
1530 if (exec->hadException()) // should be picked up soon in Nodes.cpp
1532 return primitive.toNumber(exec);
1535 JSString* JSObject::toString(ExecState* exec) const
1537 JSValue primitive = toPrimitive(exec, PreferString);
1538 if (exec->hadException())
1539 return jsEmptyString(exec);
1540 return primitive.toString(exec);
1543 JSValue JSObject::toThis(JSCell* cell, ExecState*, ECMAMode)
1545 return jsCast<JSObject*>(cell);
1548 void JSObject::seal(VM& vm)
1552 preventExtensions(vm);
1553 setStructure(vm, Structure::sealTransition(vm, structure()));
1556 void JSObject::freeze(VM& vm)
1560 preventExtensions(vm);
1561 setStructure(vm, Structure::freezeTransition(vm, structure()));
1564 void JSObject::preventExtensions(VM& vm)
1566 enterDictionaryIndexingMode(vm);
1568 setStructure(vm, Structure::preventExtensionsTransition(vm, structure()));
1571 // This presently will flatten to an uncachable dictionary; this is suitable
1572 // for use in delete, we may want to do something different elsewhere.
1573 void JSObject::reifyStaticFunctionsForDelete(ExecState* exec)
1575 ASSERT(!staticFunctionsReified());
1576 VM& vm = exec->vm();
1578 // If this object's ClassInfo has no static properties, then nothing to reify!
1579 // We can safely set the flag to avoid the expensive check again in the future.
1580 if (!classInfo()->hasStaticProperties()) {
1581 structure()->setStaticFunctionsReified();
1585 if (!structure()->isUncacheableDictionary())
1586 setStructure(vm, Structure::toUncacheableDictionaryTransition(vm, structure()));
1588 for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
1589 const HashTable* hashTable = info->propHashTable(globalObject()->globalExec());
1592 PropertySlot slot(this);
1593 for (HashTable::ConstIterator iter = hashTable->begin(vm); iter != hashTable->end(vm); ++iter) {
1594 if (iter->attributes() & Function)
1595 setUpStaticFunctionSlot(globalObject()->globalExec(), *iter, this, Identifier(&vm, iter->key()), slot);
1599 structure()->setStaticFunctionsReified();
1602 bool JSObject::removeDirect(VM& vm, PropertyName propertyName)
1604 if (!isValidOffset(structure()->get(vm, propertyName)))
1607 PropertyOffset offset;
1608 if (structure()->isUncacheableDictionary()) {
1609 offset = structure()->removePropertyWithoutTransition(vm, propertyName);
1610 if (offset == invalidOffset)
1612 putDirectUndefined(offset);
1616 setStructure(vm, Structure::removePropertyTransition(vm, structure(), propertyName, offset));
1617 if (offset == invalidOffset)
1619 putDirectUndefined(offset);
1623 NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue getterSetter, unsigned attributes, PropertyOffset offset)
1625 if (structure()->isDictionary()) {
1626 slot.setGetterSlot(this, attributes, jsCast<GetterSetter*>(getterSetter));
1630 slot.setCacheableGetterSlot(this, attributes, jsCast<GetterSetter*>(getterSetter), offset);
1633 void JSObject::putIndexedDescriptor(ExecState* exec, SparseArrayEntry* entryInMap, const PropertyDescriptor& descriptor, PropertyDescriptor& oldDescriptor)
1635 if (descriptor.isDataDescriptor()) {
1636 if (descriptor.value())
1637 entryInMap->set(exec->vm(), this, descriptor.value());
1638 else if (oldDescriptor.isAccessorDescriptor())
1639 entryInMap->set(exec->vm(), this, jsUndefined());
1640 entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~Accessor;
1644 if (descriptor.isAccessorDescriptor()) {
1645 JSObject* getter = 0;
1646 if (descriptor.getterPresent())
1647 getter = descriptor.getterObject();
1648 else if (oldDescriptor.isAccessorDescriptor())
1649 getter = oldDescriptor.getterObject();
1650 JSObject* setter = 0;
1651 if (descriptor.setterPresent())
1652 setter = descriptor.setterObject();
1653 else if (oldDescriptor.isAccessorDescriptor())
1654 setter = oldDescriptor.setterObject();
1656 GetterSetter* accessor = GetterSetter::create(exec);
1658 accessor->setGetter(exec->vm(), getter);
1660 accessor->setSetter(exec->vm(), setter);
1662 entryInMap->set(exec->vm(), this, accessor);
1663 entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~ReadOnly;
1667 ASSERT(descriptor.isGenericDescriptor());
1668 entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor);
1671 // Defined in ES5.1 8.12.9
1672 bool JSObject::defineOwnIndexedProperty(ExecState* exec, unsigned index, const PropertyDescriptor& descriptor, bool throwException)
1674 ASSERT(index <= MAX_ARRAY_INDEX);
1676 if (!inSparseIndexingMode()) {
1677 // Fast case: we're putting a regular property to a regular array
1678 // FIXME: this will pessimistically assume that if attributes are missing then they'll default to false
1679 // however if the property currently exists missing attributes will override from their current 'true'
1680 // state (i.e. defineOwnProperty could be used to set a value without needing to entering 'SparseMode').
1681 if (!descriptor.attributes()) {
1682 ASSERT(!descriptor.isAccessorDescriptor());
1683 return putDirectIndex(exec, index, descriptor.value(), 0, throwException ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
1686 ensureArrayStorageExistsAndEnterDictionaryIndexingMode(exec->vm());
1689 if (descriptor.attributes() & (ReadOnly | Accessor))
1690 notifyPresenceOfIndexedAccessors(exec->vm());
1692 SparseArrayValueMap* map = m_butterfly->arrayStorage()->m_sparseMap.get();
1693 RELEASE_ASSERT(map);
1695 // 1. Let current be the result of calling the [[GetOwnProperty]] internal method of O with property name P.
1696 SparseArrayValueMap::AddResult result = map->add(this, index);
1697 SparseArrayEntry* entryInMap = &result.iterator->value;
1699 // 2. Let extensible be the value of the [[Extensible]] internal property of O.
1700 // 3. If current is undefined and extensible is false, then Reject.
1701 // 4. If current is undefined and extensible is true, then
1702 if (result.isNewEntry) {
1703 if (!isExtensible()) {
1704 map->remove(result.iterator);
1705 return reject(exec, throwException, "Attempting to define property on object that is not extensible.");
1708 // 4.a. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then create an own data property
1709 // named P of object O whose [[Value]], [[Writable]], [[Enumerable]] and [[Configurable]] attribute values
1710 // are described by Desc. If the value of an attribute field of Desc is absent, the attribute of the newly
1711 // created property is set to its default value.
1712 // 4.b. Else, Desc must be an accessor Property Descriptor so, create an own accessor property named P of
1713 // object O whose [[Get]], [[Set]], [[Enumerable]] and [[Configurable]] attribute values are described by
1714 // Desc. If the value of an attribute field of Desc is absent, the attribute of the newly created property
1715 // is set to its default value.
1716 // 4.c. Return true.
1718 PropertyDescriptor defaults;
1719 entryInMap->setWithoutWriteBarrier(jsUndefined());
1720 entryInMap->attributes = DontDelete | DontEnum | ReadOnly;
1721 entryInMap->get(defaults);
1723 putIndexedDescriptor(exec, entryInMap, descriptor, defaults);
1724 if (index >= m_butterfly->arrayStorage()->length())
1725 m_butterfly->arrayStorage()->setLength(index + 1);
1729 // 5. Return true, if every field in Desc is absent.
1730 // 6. Return true, if every field in Desc also occurs in current and the value of every field in Desc is the same value as the corresponding field in current when compared using the SameValue algorithm (9.12).
1731 PropertyDescriptor current;
1732 entryInMap->get(current);
1733 if (descriptor.isEmpty() || descriptor.equalTo(exec, current))
1736 // 7. If the [[Configurable]] field of current is false then
1737 if (!current.configurable()) {
1738 // 7.a. Reject, if the [[Configurable]] field of Desc is true.
1739 if (descriptor.configurablePresent() && descriptor.configurable())
1740 return reject(exec, throwException, "Attempting to change configurable attribute of unconfigurable property.");
1741 // 7.b. Reject, if the [[Enumerable]] field of Desc is present and the [[Enumerable]] fields of current and Desc are the Boolean negation of each other.
1742 if (descriptor.enumerablePresent() && current.enumerable() != descriptor.enumerable())
1743 return reject(exec, throwException, "Attempting to change enumerable attribute of unconfigurable property.");
1746 // 8. If IsGenericDescriptor(Desc) is true, then no further validation is required.
1747 if (!descriptor.isGenericDescriptor()) {
1748 // 9. Else, if IsDataDescriptor(current) and IsDataDescriptor(Desc) have different results, then
1749 if (current.isDataDescriptor() != descriptor.isDataDescriptor()) {
1750 // 9.a. Reject, if the [[Configurable]] field of current is false.
1751 if (!current.configurable())
1752 return reject(exec, throwException, "Attempting to change access mechanism for an unconfigurable property.");
1753 // 9.b. If IsDataDescriptor(current) is true, then convert the property named P of object O from a
1754 // data property to an accessor property. Preserve the existing values of the converted property's
1755 // [[Configurable]] and [[Enumerable]] attributes and set the rest of the property's attributes to
1756 // their default values.
1757 // 9.c. Else, convert the property named P of object O from an accessor property to a data property.
1758 // Preserve the existing values of the converted property's [[Configurable]] and [[Enumerable]]
1759 // attributes and set the rest of the property's attributes to their default values.
1760 } else if (current.isDataDescriptor() && descriptor.isDataDescriptor()) {
1761 // 10. Else, if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both true, then
1762 // 10.a. If the [[Configurable]] field of current is false, then
1763 if (!current.configurable() && !current.writable()) {
1764 // 10.a.i. Reject, if the [[Writable]] field of current is false and the [[Writable]] field of Desc is true.
1765 if (descriptor.writable())
1766 return reject(exec, throwException, "Attempting to change writable attribute of unconfigurable property.");
1767 // 10.a.ii. If the [[Writable]] field of current is false, then
1768 // 10.a.ii.1. Reject, if the [[Value]] field of Desc is present and SameValue(Desc.[[Value]], current.[[Value]]) is false.
1769 if (descriptor.value() && !sameValue(exec, descriptor.value(), current.value()))
1770 return reject(exec, throwException, "Attempting to change value of a readonly property.");
1772 // 10.b. else, the [[Configurable]] field of current is true, so any change is acceptable.
1774 ASSERT(current.isAccessorDescriptor() && current.getterPresent() && current.setterPresent());
1775 // 11. Else, IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc) are both true so, if the [[Configurable]] field of current is false, then
1776 if (!current.configurable()) {
1777 // 11.i. Reject, if the [[Set]] field of Desc is present and SameValue(Desc.[[Set]], current.[[Set]]) is false.
1778 if (descriptor.setterPresent() && descriptor.setter() != current.setter())
1779 return reject(exec, throwException, "Attempting to change the setter of an unconfigurable property.");
1780 // 11.ii. Reject, if the [[Get]] field of Desc is present and SameValue(Desc.[[Get]], current.[[Get]]) is false.
1781 if (descriptor.getterPresent() && descriptor.getter() != current.getter())
1782 return reject(exec, throwException, "Attempting to change the getter of an unconfigurable property.");
1787 // 12. For each attribute field of Desc that is present, set the correspondingly named attribute of the property named P of object O to the value of the field.
1788 putIndexedDescriptor(exec, entryInMap, descriptor, current);
1793 SparseArrayValueMap* JSObject::allocateSparseIndexMap(VM& vm)
1795 SparseArrayValueMap* result = SparseArrayValueMap::create(vm);
1796 arrayStorage()->m_sparseMap.set(vm, this, result);
1800 void JSObject::deallocateSparseIndexMap()
1802 if (ArrayStorage* arrayStorage = arrayStorageOrNull())
1803 arrayStorage->m_sparseMap.clear();
1806 bool JSObject::attemptToInterceptPutByIndexOnHoleForPrototype(ExecState* exec, JSValue thisValue, unsigned i, JSValue value, bool shouldThrow)
1808 for (JSObject* current = this; ;) {
1809 // This has the same behavior with respect to prototypes as JSObject::put(). It only
1810 // allows a prototype to intercept a put if (a) the prototype declares the property
1811 // we're after rather than intercepting it via an override of JSObject::put(), and
1812 // (b) that property is declared as ReadOnly or Accessor.
1814 ArrayStorage* storage = current->arrayStorageOrNull();
1815 if (storage && storage->m_sparseMap) {
1816 SparseArrayValueMap::iterator iter = storage->m_sparseMap->find(i);
1817 if (iter != storage->m_sparseMap->notFound() && (iter->value.attributes & (Accessor | ReadOnly))) {
1818 iter->value.put(exec, thisValue, storage->m_sparseMap.get(), value, shouldThrow);
1823 JSValue prototypeValue = current->prototype();
1824 if (prototypeValue.isNull())
1827 current = asObject(prototypeValue);
1831 bool JSObject::attemptToInterceptPutByIndexOnHole(ExecState* exec, unsigned i, JSValue value, bool shouldThrow)
1833 JSValue prototypeValue = prototype();
1834 if (prototypeValue.isNull())
1837 return asObject(prototypeValue)->attemptToInterceptPutByIndexOnHoleForPrototype(exec, this, i, value, shouldThrow);
1840 template<IndexingType indexingShape>
1841 void JSObject::putByIndexBeyondVectorLengthWithoutAttributes(ExecState* exec, unsigned i, JSValue value)
1843 ASSERT((structure()->indexingType() & IndexingShapeMask) == indexingShape);
1844 ASSERT(!indexingShouldBeSparse());
1846 // For us to get here, the index is either greater than the public length, or greater than
1847 // or equal to the vector length.
1848 ASSERT(i >= m_butterfly->vectorLength());
1850 VM& vm = exec->vm();
1852 if (i >= MAX_ARRAY_INDEX - 1
1853 || (i >= MIN_SPARSE_ARRAY_INDEX
1854 && !isDenseEnoughForVector(i, countElements<indexingShape>(m_butterfly)))
1855 || indexIsSufficientlyBeyondLengthForSparseMap(i, m_butterfly->vectorLength())) {
1856 ASSERT(i <= MAX_ARRAY_INDEX);
1857 ensureArrayStorageSlow(vm);
1858 SparseArrayValueMap* map = allocateSparseIndexMap(vm);
1859 map->putEntry(exec, this, i, value, false);
1860 ASSERT(i >= arrayStorage()->length());
1861 arrayStorage()->setLength(i + 1);
1865 ensureLength(vm, i + 1);
1867 RELEASE_ASSERT(i < m_butterfly->vectorLength());
1868 switch (indexingShape) {
1870 ASSERT(value.isInt32());
1871 m_butterfly->contiguousInt32()[i].setWithoutWriteBarrier(value);
1875 ASSERT(value.isNumber());
1876 double valueAsDouble = value.asNumber();
1877 ASSERT(valueAsDouble == valueAsDouble);
1878 m_butterfly->contiguousDouble()[i] = valueAsDouble;
1882 case ContiguousShape:
1883 m_butterfly->contiguous()[i].set(vm, this, value);
1891 void JSObject::putByIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, unsigned i, JSValue value, bool shouldThrow, ArrayStorage* storage)
1893 VM& vm = exec->vm();
1895 // i should be a valid array index that is outside of the current vector.
1896 ASSERT(i <= MAX_ARRAY_INDEX);
1897 ASSERT(i >= storage->vectorLength());
1899 SparseArrayValueMap* map = storage->m_sparseMap.get();
1901 // First, handle cases where we don't currently have a sparse map.
1903 // If the array is not extensible, we should have entered dictionary mode, and created the sparse map.
1904 ASSERT(isExtensible());
1906 // Update m_length if necessary.
1907 if (i >= storage->length())
1908 storage->setLength(i + 1);
1910 // Check that it is sensible to still be using a vector, and then try to grow the vector.
1911 if (LIKELY(!indexIsSufficientlyBeyondLengthForSparseMap(i, storage->vectorLength())
1912 && isDenseEnoughForVector(i, storage->m_numValuesInVector)
1913 && increaseVectorLength(vm, i + 1))) {
1914 // success! - reread m_storage since it has likely been reallocated, and store to the vector.
1915 storage = arrayStorage();
1916 storage->m_vector[i].set(vm, this, value);
1917 ++storage->m_numValuesInVector;
1920 // We don't want to, or can't use a vector to hold this property - allocate a sparse map & add the value.
1921 map = allocateSparseIndexMap(exec->vm());
1922 map->putEntry(exec, this, i, value, shouldThrow);
1926 // Update m_length if necessary.
1927 unsigned length = storage->length();
1929 // Prohibit growing the array if length is not writable.
1930 if (map->lengthIsReadOnly() || !isExtensible()) {
1932 throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
1936 storage->setLength(length);
1939 // We are currently using a map - check whether we still want to be doing so.
1940 // We will continue to use a sparse map if SparseMode is set, a vector would be too sparse, or if allocation fails.
1941 unsigned numValuesInArray = storage->m_numValuesInVector + map->size();
1942 if (map->sparseMode() || !isDenseEnoughForVector(length, numValuesInArray) || !increaseVectorLength(exec->vm(), length)) {
1943 map->putEntry(exec, this, i, value, shouldThrow);
1947 // Reread m_storage after increaseVectorLength, update m_numValuesInVector.
1948 storage = arrayStorage();
1949 storage->m_numValuesInVector = numValuesInArray;
1951 // Copy all values from the map into the vector, and delete the map.
1952 WriteBarrier<Unknown>* vector = storage->m_vector;
1953 SparseArrayValueMap::const_iterator end = map->end();
1954 for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it)
1955 vector[it->key].set(vm, this, it->value.getNonSparseMode());
1956 deallocateSparseIndexMap();
1958 // Store the new property into the vector.
1959 WriteBarrier<Unknown>& valueSlot = vector[i];
1961 ++storage->m_numValuesInVector;
1962 valueSlot.set(vm, this, value);
1965 void JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue value, bool shouldThrow)
1967 VM& vm = exec->vm();
1969 // i should be a valid array index that is outside of the current vector.
1970 ASSERT(i <= MAX_ARRAY_INDEX);
1972 switch (structure()->indexingType()) {
1973 case ALL_BLANK_INDEXING_TYPES: {
1974 if (indexingShouldBeSparse()) {
1975 putByIndexBeyondVectorLengthWithArrayStorage(
1976 exec, i, value, shouldThrow,
1977 ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm));
1980 if (indexIsSufficientlyBeyondLengthForSparseMap(i, 0) || i >= MIN_SPARSE_ARRAY_INDEX) {
1981 putByIndexBeyondVectorLengthWithArrayStorage(
1982 exec, i, value, shouldThrow, createArrayStorage(vm, 0, 0));
1985 if (structure()->needsSlowPutIndexing()) {
1986 ArrayStorage* storage = createArrayStorage(vm, i + 1, getNewVectorLength(0, 0, i + 1));
1987 storage->m_vector[i].set(vm, this, value);
1988 storage->m_numValuesInVector++;
1992 createInitialContiguous(vm, i + 1)[i].set(vm, this, value);
1996 case ALL_UNDECIDED_INDEXING_TYPES: {
2001 case ALL_INT32_INDEXING_TYPES: {
2002 putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, i, value);
2006 case ALL_DOUBLE_INDEXING_TYPES: {
2007 putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, i, value);
2011 case ALL_CONTIGUOUS_INDEXING_TYPES: {
2012 putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, i, value);
2016 case NonArrayWithSlowPutArrayStorage:
2017 case ArrayWithSlowPutArrayStorage: {
2018 // No own property present in the vector, but there might be in the sparse map!
2019 SparseArrayValueMap* map = arrayStorage()->m_sparseMap.get();
2020 if (!(map && map->contains(i)) && attemptToInterceptPutByIndexOnHole(exec, i, value, shouldThrow))
2022 // Otherwise, fall though.
2025 case NonArrayWithArrayStorage:
2026 case ArrayWithArrayStorage:
2027 putByIndexBeyondVectorLengthWithArrayStorage(exec, i, value, shouldThrow, arrayStorage());
2031 RELEASE_ASSERT_NOT_REACHED();
2035 bool JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, unsigned i, JSValue value, unsigned attributes, PutDirectIndexMode mode, ArrayStorage* storage)
2037 VM& vm = exec->vm();
2039 // i should be a valid array index that is outside of the current vector.
2040 ASSERT(hasArrayStorage(structure()->indexingType()));
2041 ASSERT(arrayStorage() == storage);
2042 ASSERT(i >= storage->vectorLength() || attributes);
2043 ASSERT(i <= MAX_ARRAY_INDEX);
2045 SparseArrayValueMap* map = storage->m_sparseMap.get();
2047 // First, handle cases where we don't currently have a sparse map.
2049 // If the array is not extensible, we should have entered dictionary mode, and created the spare map.
2050 ASSERT(isExtensible());
2052 // Update m_length if necessary.
2053 if (i >= storage->length())
2054 storage->setLength(i + 1);
2056 // Check that it is sensible to still be using a vector, and then try to grow the vector.
2059 && (isDenseEnoughForVector(i, storage->m_numValuesInVector))
2060 && !indexIsSufficientlyBeyondLengthForSparseMap(i, storage->vectorLength()))
2061 && increaseVectorLength(vm, i + 1)) {
2062 // success! - reread m_storage since it has likely been reallocated, and store to the vector.
2063 storage = arrayStorage();
2064 storage->m_vector[i].set(vm, this, value);
2065 ++storage->m_numValuesInVector;
2068 // We don't want to, or can't use a vector to hold this property - allocate a sparse map & add the value.
2069 map = allocateSparseIndexMap(exec->vm());
2070 return map->putDirect(exec, this, i, value, attributes, mode);
2073 // Update m_length if necessary.
2074 unsigned length = storage->length();
2076 if (mode != PutDirectIndexLikePutDirect) {
2077 // Prohibit growing the array if length is not writable.
2078 if (map->lengthIsReadOnly())
2079 return reject(exec, mode == PutDirectIndexShouldThrow, StrictModeReadonlyPropertyWriteError);
2080 if (!isExtensible())
2081 return reject(exec, mode == PutDirectIndexShouldThrow, "Attempting to define property on object that is not extensible.");
2084 storage->setLength(length);
2087 // We are currently using a map - check whether we still want to be doing so.
2088 // We will continue to use a sparse map if SparseMode is set, a vector would be too sparse, or if allocation fails.
2089 unsigned numValuesInArray = storage->m_numValuesInVector + map->size();
2090 if (map->sparseMode() || attributes || !isDenseEnoughForVector(length, numValuesInArray) || !increaseVectorLength(exec->vm(), length))
2091 return map->putDirect(exec, this, i, value, attributes, mode);
2093 // Reread m_storage after increaseVectorLength, update m_numValuesInVector.
2094 storage = arrayStorage();
2095 storage->m_numValuesInVector = numValuesInArray;
2097 // Copy all values from the map into the vector, and delete the map.
2098 WriteBarrier<Unknown>* vector = storage->m_vector;
2099 SparseArrayValueMap::const_iterator end = map->end();
2100 for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it)
2101 vector[it->key].set(vm, this, it->value.getNonSparseMode());
2102 deallocateSparseIndexMap();
2104 // Store the new property into the vector.
2105 WriteBarrier<Unknown>& valueSlot = vector[i];
2107 ++storage->m_numValuesInVector;
2108 valueSlot.set(vm, this, value);
2112 bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue value, unsigned attributes, PutDirectIndexMode mode)
2114 VM& vm = exec->vm();
2116 // i should be a valid array index that is outside of the current vector.
2117 ASSERT(i <= MAX_ARRAY_INDEX);
2119 if (attributes & (ReadOnly | Accessor))
2120 notifyPresenceOfIndexedAccessors(vm);
2122 switch (structure()->indexingType()) {
2123 case ALL_BLANK_INDEXING_TYPES: {
2124 if (indexingShouldBeSparse() || attributes) {
2125 return putDirectIndexBeyondVectorLengthWithArrayStorage(
2126 exec, i, value, attributes, mode,
2127 ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm));
2129 if (i >= MIN_SPARSE_ARRAY_INDEX) {
2130 return putDirectIndexBeyondVectorLengthWithArrayStorage(
2131 exec, i, value, attributes, mode, createArrayStorage(vm, 0, 0));
2133 if (structure()->needsSlowPutIndexing()) {
2134 ArrayStorage* storage = createArrayStorage(vm, i + 1, getNewVectorLength(0, 0, i + 1));
2135 storage->m_vector[i].set(vm, this, value);
2136 storage->m_numValuesInVector++;
2140 createInitialContiguous(vm, i + 1)[i].set(vm, this, value);
2144 case ALL_UNDECIDED_INDEXING_TYPES: {
2145 convertUndecidedForValue(exec->vm(), value);
2147 return putDirectIndex(exec, i, value, attributes, mode);
2150 case ALL_INT32_INDEXING_TYPES: {
2151 if (attributes & (ReadOnly | Accessor)) {
2152 return putDirectIndexBeyondVectorLengthWithArrayStorage(
2153 exec, i, value, attributes, mode, convertInt32ToArrayStorage(vm));
2155 if (!value.isInt32()) {
2156 convertInt32ForValue(vm, value);
2157 return putDirectIndexBeyondVectorLength(exec, i, value, attributes, mode);
2159 putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, i, value);
2163 case ALL_DOUBLE_INDEXING_TYPES: {
2164 if (attributes & (ReadOnly | Accessor)) {
2165 return putDirectIndexBeyondVectorLengthWithArrayStorage(
2166 exec, i, value, attributes, mode, convertDoubleToArrayStorage(vm));
2168 if (!value.isNumber()) {
2169 convertDoubleToContiguous(vm);
2170 return putDirectIndexBeyondVectorLength(exec, i, value, attributes, mode);
2172 double valueAsDouble = value.asNumber();
2173 if (valueAsDouble != valueAsDouble) {
2174 convertDoubleToContiguous(vm);
2175 return putDirectIndexBeyondVectorLength(exec, i, value, attributes, mode);
2177 putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, i, value);
2181 case ALL_CONTIGUOUS_INDEXING_TYPES: {
2182 if (attributes & (ReadOnly | Accessor)) {
2183 return putDirectIndexBeyondVectorLengthWithArrayStorage(
2184 exec, i, value, attributes, mode, convertContiguousToArrayStorage(vm));
2186 putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, i, value);
2190 case ALL_ARRAY_STORAGE_INDEXING_TYPES:
2191 return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, arrayStorage());
2194 RELEASE_ASSERT_NOT_REACHED();
2199 void JSObject::putDirectNativeFunction(ExecState* exec, JSGlobalObject* globalObject, const PropertyName& propertyName, unsigned functionLength, NativeFunction nativeFunction, Intrinsic intrinsic, unsigned attributes)
2201 StringImpl* name = propertyName.publicName();
2204 JSFunction* function = JSFunction::create(exec, globalObject, functionLength, name, nativeFunction, intrinsic);
2205 putDirect(exec->vm(), propertyName, function, attributes);
2208 void JSObject::putDirectNativeFunctionWithoutTransition(ExecState* exec, JSGlobalObject* globalObject, const PropertyName& propertyName, unsigned functionLength, NativeFunction nativeFunction, Intrinsic intrinsic, unsigned attributes)
2210 StringImpl* name = propertyName.publicName();
2213 JSFunction* function = JSFunction::create(exec, globalObject, functionLength, name, nativeFunction, intrinsic);
2214 putDirectWithoutTransition(exec->vm(), propertyName, function, attributes);
2217 ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned currentVectorLength, unsigned currentLength, unsigned desiredLength)
2219 ASSERT(desiredLength <= MAX_STORAGE_VECTOR_LENGTH);
2221 unsigned increasedLength;
2222 unsigned maxInitLength = std::min(currentLength, 100000U);
2224 if (desiredLength < maxInitLength)
2225 increasedLength = maxInitLength;
2226 else if (!currentVectorLength)
2227 increasedLength = std::max(desiredLength, lastArraySize);
2229 increasedLength = timesThreePlusOneDividedByTwo(desiredLength);
2232 ASSERT(increasedLength >= desiredLength);
2234 lastArraySize = std::min(increasedLength, FIRST_VECTOR_GROW);
2236 return std::min(increasedLength, MAX_STORAGE_VECTOR_LENGTH);
2239 ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned desiredLength)
2241 unsigned vectorLength;
2244 if (hasIndexedProperties(structure()->indexingType())) {
2245 vectorLength = m_butterfly->vectorLength();
2246 length = m_butterfly->publicLength();
2252 return getNewVectorLength(vectorLength, length, desiredLength);
2255 template<IndexingType indexingShape>
2256 unsigned JSObject::countElements(Butterfly* butterfly)
2258 unsigned numValues = 0;
2259 for (unsigned i = butterfly->publicLength(); i--;) {
2260 switch (indexingShape) {
2262 case ContiguousShape:
2263 if (butterfly->contiguous()[i])
2268 double value = butterfly->contiguousDouble()[i];
2281 unsigned JSObject::countElements()
2283 switch (structure()->indexingType()) {
2284 case ALL_BLANK_INDEXING_TYPES:
2285 case ALL_UNDECIDED_INDEXING_TYPES:
2288 case ALL_INT32_INDEXING_TYPES:
2289 return countElements<Int32Shape>(m_butterfly);
2291 case ALL_DOUBLE_INDEXING_TYPES:
2292 return countElements<DoubleShape>(m_butterfly);
2294 case ALL_CONTIGUOUS_INDEXING_TYPES:
2295 return countElements<ContiguousShape>(m_butterfly);
2303 bool JSObject::increaseVectorLength(VM& vm, unsigned newLength)
2305 // This function leaves the array in an internally inconsistent state, because it does not move any values from sparse value map
2306 // to the vector. Callers have to account for that, because they can do it more efficiently.
2307 if (newLength > MAX_STORAGE_VECTOR_LENGTH)
2310 ArrayStorage* storage = arrayStorage();
2312 if (newLength >= MIN_SPARSE_ARRAY_INDEX
2313 && !isDenseEnoughForVector(newLength, storage->m_numValuesInVector))
2316 unsigned indexBias = storage->m_indexBias;
2317 unsigned vectorLength = storage->vectorLength();
2318 ASSERT(newLength > vectorLength);
2319 unsigned newVectorLength = getNewVectorLength(newLength);
2321 // Fast case - there is no precapacity. In these cases a realloc makes sense.
2322 if (LIKELY(!indexBias)) {
2323 DeferGC deferGC(vm.heap);
2324 Butterfly* newButterfly = storage->butterfly()->growArrayRight(
2325 vm, this, structure(), structure()->outOfLineCapacity(), true,
2326 ArrayStorage::sizeFor(vectorLength), ArrayStorage::sizeFor(newVectorLength));
2329 m_butterfly = newButterfly;
2330 newButterfly->arrayStorage()->setVectorLength(newVectorLength);
2334 // Remove some, but not all of the precapacity. Atomic decay, & capped to not overflow array length.
2335 DeferGC deferGC(vm.heap);
2336 unsigned newIndexBias = std::min(indexBias >> 1, MAX_STORAGE_VECTOR_LENGTH - newVectorLength);
2337 Butterfly* newButterfly = storage->butterfly()->resizeArray(
2339 structure()->outOfLineCapacity(), true, ArrayStorage::sizeFor(vectorLength),
2340 newIndexBias, true, ArrayStorage::sizeFor(newVectorLength));
2344 m_butterfly = newButterfly;
2345 newButterfly->arrayStorage()->setVectorLength(newVectorLength);
2346 newButterfly->arrayStorage()->m_indexBias = newIndexBias;
2350 void JSObject::ensureLengthSlow(VM& vm, unsigned length)
2352 ASSERT(length < MAX_ARRAY_INDEX);
2353 ASSERT(hasContiguous(structure()->indexingType()) || hasInt32(structure()->indexingType()) || hasDouble(structure()->indexingType()) || hasUndecided(structure()->indexingType()));
2354 ASSERT(length > m_butterfly->vectorLength());
2356 unsigned newVectorLength = std::min(
2358 MAX_STORAGE_VECTOR_LENGTH);
2359 unsigned oldVectorLength = m_butterfly->vectorLength();
2360 DeferGC deferGC(vm.heap);
2361 m_butterfly = m_butterfly->growArrayRight(
2362 vm, this, structure(), structure()->outOfLineCapacity(), true,
2363 oldVectorLength * sizeof(EncodedJSValue),
2364 newVectorLength * sizeof(EncodedJSValue));
2365 if (hasDouble(structure()->indexingType())) {
2366 for (unsigned i = oldVectorLength; i < newVectorLength; ++i)
2367 m_butterfly->contiguousDouble().data()[i] = QNaN;
2369 m_butterfly->setVectorLength(newVectorLength);
2372 Butterfly* JSObject::growOutOfLineStorage(VM& vm, size_t oldSize, size_t newSize)
2374 ASSERT(newSize > oldSize);
2376 // It's important that this function not rely on structure(), for the property
2377 // capacity, since we might have already mutated the structure in-place.
2379 return m_butterfly->growPropertyStorage(vm, this, structure(), oldSize, newSize);
2382 bool JSObject::getOwnPropertyDescriptor(ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
2384 JSC::PropertySlot slot(this);
2385 if (!methodTable()->getOwnPropertySlot(this, exec, propertyName, slot))
2387 /* Workaround, JSDOMWindow::getOwnPropertySlot searches the prototype chain. :-( */
2388 if (slot.slotBase() != this && slot.slotBase() && slot.slotBase()->methodTable()->toThis(slot.slotBase(), exec, NotStrictMode) != this)
2390 if (slot.isAccessor())
2391 descriptor.setAccessorDescriptor(slot.getterSetter(), slot.attributes());
2393 descriptor.setDescriptor(slot.getValue(exec, propertyName), slot.attributes());
2397 static bool putDescriptor(ExecState* exec, JSObject* target, PropertyName propertyName, const PropertyDescriptor& descriptor, unsigned attributes, const PropertyDescriptor& oldDescriptor)
2399 if (descriptor.isGenericDescriptor() || descriptor.isDataDescriptor()) {
2400 if (descriptor.isGenericDescriptor() && oldDescriptor.isAccessorDescriptor()) {
2401 GetterSetter* accessor = GetterSetter::create(exec);
2402 if (oldDescriptor.getterPresent())
2403 accessor->setGetter(exec->vm(), oldDescriptor.getterObject());
2404 if (oldDescriptor.setterPresent())
2405 accessor->setSetter(exec->vm(), oldDescriptor.setterObject());
2406 target->putDirectAccessor(exec, propertyName, accessor, attributes | Accessor);
2409 JSValue newValue = jsUndefined();
2410 if (descriptor.value())
2411 newValue = descriptor.value();
2412 else if (oldDescriptor.value())
2413 newValue = oldDescriptor.value();
2414 target->putDirect(exec->vm(), propertyName, newValue, attributes & ~Accessor);
2415 if (attributes & ReadOnly)
2416 target->structure()->setContainsReadOnlyProperties();
2419 attributes &= ~ReadOnly;
2420 GetterSetter* accessor = GetterSetter::create(exec);
2422 if (descriptor.getterPresent())
2423 accessor->setGetter(exec->vm(), descriptor.getterObject());
2424 else if (oldDescriptor.getterPresent())
2425 accessor->setGetter(exec->vm(), oldDescriptor.getterObject());
2426 if (descriptor.setterPresent())
2427 accessor->setSetter(exec->vm(), descriptor.setterObject());
2428 else if (oldDescriptor.setterPresent())
2429 accessor->setSetter(exec->vm(), oldDescriptor.setterObject());
2431 target->putDirectAccessor(exec, propertyName, accessor, attributes | Accessor);
2435 void JSObject::putDirectMayBeIndex(ExecState* exec, PropertyName propertyName, JSValue value)
2437 unsigned asIndex = propertyName.asIndex();
2438 if (asIndex == PropertyName::NotAnIndex)
2439 putDirect(exec->vm(), propertyName, value);
2441 putDirectIndex(exec, asIndex, value);
2444 class DefineOwnPropertyScope {
2446 DefineOwnPropertyScope(ExecState* exec)
2449 m_vm.setInDefineOwnProperty(true);
2452 ~DefineOwnPropertyScope()
2454 m_vm.setInDefineOwnProperty(false);
2461 bool JSObject::defineOwnNonIndexProperty(ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException)
2463 // Track on the globaldata that we're in define property.
2464 // Currently DefineOwnProperty uses delete to remove properties when they are being replaced
2465 // (particularly when changing attributes), however delete won't allow non-configurable (i.e.
2466 // DontDelete) properties to be deleted. For now, we can use this flag to make this work.
2467 DefineOwnPropertyScope scope(exec);
2469 // If we have a new property we can just put it on normally
2470 PropertyDescriptor current;
2471 if (!getOwnPropertyDescriptor(exec, propertyName, current)) {
2472 // unless extensions are prevented!
2473 if (!isExtensible()) {
2475 throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to define property on object that is not extensible.")));
2478 PropertyDescriptor oldDescriptor;
2479 oldDescriptor.setValue(jsUndefined());
2480 return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributes(), oldDescriptor);
2483 if (descriptor.isEmpty())
2486 if (current.equalTo(exec, descriptor))
2489 // Filter out invalid changes
2490 if (!current.configurable()) {
2491 if (descriptor.configurable()) {
2493 throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to configurable attribute of unconfigurable property.")));
2496 if (descriptor.enumerablePresent() && descriptor.enumerable() != current.enumerable()) {
2498 throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change enumerable attribute of unconfigurable property.")));
2503 // A generic descriptor is simply changing the attributes of an existing property
2504 if (descriptor.isGenericDescriptor()) {
2505 if (!current.attributesEqual(descriptor)) {
2506 methodTable()->deleteProperty(this, exec, propertyName);
2507 return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
2512 // Changing between a normal property or an accessor property
2513 if (descriptor.isDataDescriptor() != current.isDataDescriptor()) {
2514 if (!current.configurable()) {
2516 throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change access mechanism for an unconfigurable property.")));
2519 methodTable()->deleteProperty(this, exec, propertyName);
2520 return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
2523 // Changing the value and attributes of an existing property
2524 if (descriptor.isDataDescriptor()) {
2525 if (!current.configurable()) {
2526 if (!current.writable() && descriptor.writable()) {
2528 throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change writable attribute of unconfigurable property.")));
2531 if (!current.writable()) {
2532 if (descriptor.value() && !sameValue(exec, current.value(), descriptor.value())) {
2534 throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change value of a readonly property.")));
2539 if (current.attributesEqual(descriptor) && !descriptor.value())
2541 methodTable()->deleteProperty(this, exec, propertyName);
2542 return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
2545 // Changing the accessor functions of an existing accessor property
2546 ASSERT(descriptor.isAccessorDescriptor());
2547 if (!current.configurable()) {
2548 if (descriptor.setterPresent() && !(current.setterPresent() && JSValue::strictEqual(exec, current.setter(), descriptor.setter()))) {
2550 throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change the setter of an unconfigurable property.")));
2553 if (descriptor.getterPresent() && !(current.getterPresent() && JSValue::strictEqual(exec, current.getter(), descriptor.getter()))) {
2555 throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change the getter of an unconfigurable property.")));
2559 JSValue accessor = getDirect(exec->vm(), propertyName);
2562 GetterSetter* getterSetter = asGetterSetter(accessor);
2563 if (descriptor.setterPresent())
2564 getterSetter->setSetter(exec->vm(), descriptor.setterObject());
2565 if (descriptor.getterPresent())
2566 getterSetter->setGetter(exec->vm(), descriptor.getterObject());
2567 if (current.attributesEqual(descriptor))
2569 methodTable()->deleteProperty(this, exec, propertyName);
2570 unsigned attrs = descriptor.attributesOverridingCurrent(current);
2571 putDirectAccessor(exec, propertyName, getterSetter, attrs | Accessor);
2575 bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException)
2577 // If it's an array index, then use the indexed property storage.
2578 unsigned index = propertyName.asIndex();
2579 if (index != PropertyName::NotAnIndex) {
2580 // c. Let succeeded be the result of calling the default [[DefineOwnProperty]] internal method (8.12.9) on A passing P, Desc, and false as arguments.
2581 // d. Reject if succeeded is false.
2582 // e. If index >= oldLen
2583 // e.i. Set oldLenDesc.[[Value]] to index + 1.
2584 // e.ii. Call the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", oldLenDesc, and false as arguments. This call will always return true.
2586 return object->defineOwnIndexedProperty(exec, index, descriptor, throwException);
2589 return object->defineOwnNonIndexProperty(exec, propertyName, descriptor, throwException);
2592 bool JSObject::getOwnPropertySlotSlow(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
2594 unsigned i = propertyName.asIndex();
2595 if (i != PropertyName::NotAnIndex)
2596 return getOwnPropertySlotByIndex(this, exec, i, slot);
2600 JSObject* throwTypeError(ExecState* exec, const String& message)
2602 return throwError(exec, createTypeError(exec, message));