#include "CopiedSpaceInlines.h"
#include "CopyVisitor.h"
#include "CopyVisitorInlines.h"
+#include "CustomGetterSetter.h"
#include "DatePrototype.h"
#include "ErrorConstructor.h"
#include "Executable.h"
#include "NativeErrorConstructor.h"
#include "Nodes.h"
#include "ObjectPrototype.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "PropertyDescriptor.h"
#include "PropertyNameArray.h"
#include "Reject.h"
JSCell* getCallableObjectSlow(JSCell* cell)
{
- Structure* structure = cell->structure();
- if (structure->typeInfo().type() == JSFunctionType)
+ if (cell->type() == JSFunctionType)
return cell;
- if (structure->classInfo()->isSubClassOf(&InternalFunction::s_info))
+ if (cell->structure()->classInfo()->isSubClassOf(InternalFunction::info()))
return cell;
return 0;
}
-ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSObject);
-ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSFinalObject);
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSObject);
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSFinalObject);
const char* StrictModeReadonlyPropertyWriteError = "Attempted to assign to readonly property.";
static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode, bool didReify)
{
+ VM& vm = exec->vm();
+
// Add properties from the static hashtables of properties
for (; classInfo; classInfo = classInfo->parentClass) {
- const HashTable* table = classInfo->propHashTable(exec);
+ const HashTable* table = classInfo->propHashTable(vm);
if (!table)
continue;
- table->initializeIfNeeded(exec);
- ASSERT(table->table);
-
- int hashSizeMask = table->compactSize - 1;
- const HashEntry* entry = table->table;
- for (int i = 0; i <= hashSizeMask; ++i, ++entry) {
- if (entry->key() && (!(entry->attributes() & DontEnum) || (mode == IncludeDontEnumProperties)) && !((entry->attributes() & Function) && didReify))
- propertyNames.add(entry->key());
+
+ for (auto iter = table->begin(vm); iter != table->end(vm); ++iter) {
+ if ((!(iter->attributes() & DontEnum) || (mode == IncludeDontEnumProperties)) && !((iter->attributes() & BuiltinOrFunction) && didReify))
+ propertyNames.add(Identifier(&vm, iter.key()));
}
}
}
size_t propertyCapacity = structure->outOfLineCapacity();
size_t preCapacity;
size_t indexingPayloadSizeInBytes;
- bool hasIndexingHeader = JSC::hasIndexingHeader(structure->indexingType());
+ bool hasIndexingHeader = this->hasIndexingHeader();
if (UNLIKELY(hasIndexingHeader)) {
preCapacity = butterfly->indexingHeader()->preCapacity(structure);
indexingPayloadSizeInBytes = butterfly->indexingHeader()->indexingPayloadSizeInBytes(structure);
WriteBarrier<Unknown>* currentSource;
size_t count;
- switch (structure->indexingType()) {
+ switch (this->indexingType()) {
case ALL_UNDECIDED_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
case ALL_INT32_INDEXING_TYPES:
count = newButterfly->arrayStorage()->vectorLength();
break;
}
+
default:
- CRASH();
currentTarget = 0;
currentSource = 0;
count = 0;
memcpy(currentTarget, currentSource, count * sizeof(EncodedJSValue));
}
- m_butterfly = newButterfly;
+ m_butterfly.setWithoutWriteBarrier(newButterfly);
visitor.didCopy(butterfly->base(preCapacity, propertyCapacity), capacityInBytes);
}
}
{
ASSERT(butterfly);
- Structure* structure = this->structure();
+ Structure* structure = this->structure(visitor.vm());
size_t propertyCapacity = structure->outOfLineCapacity();
size_t preCapacity;
size_t indexingPayloadSizeInBytes;
- bool hasIndexingHeader = JSC::hasIndexingHeader(structure->indexingType());
+ bool hasIndexingHeader = this->hasIndexingHeader();
if (UNLIKELY(hasIndexingHeader)) {
preCapacity = butterfly->indexingHeader()->preCapacity(structure);
indexingPayloadSizeInBytes = butterfly->indexingHeader()->indexingPayloadSizeInBytes(structure);
// Mark the properties.
visitor.appendValues(butterfly->propertyStorage() - storageSize, storageSize);
- visitor.copyLater(this, butterfly->base(preCapacity, propertyCapacity), capacityInBytes);
+ visitor.copyLater(
+ this, ButterflyCopyToken,
+ butterfly->base(preCapacity, propertyCapacity), capacityInBytes);
// Mark the array if appropriate.
- switch (structure->indexingType()) {
+ switch (this->indexingType()) {
case ALL_CONTIGUOUS_INDEXING_TYPES:
visitor.appendValues(butterfly->contiguous().data(), butterfly->publicLength());
break;
void JSObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
JSObject* thisObject = jsCast<JSObject*>(cell);
- ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
#if !ASSERT_DISABLED
bool wasCheckingForDefaultMarkViolation = visitor.m_isCheckingForDefaultMarkViolation;
visitor.m_isCheckingForDefaultMarkViolation = false;
Butterfly* butterfly = thisObject->butterfly();
if (butterfly)
- thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
+ thisObject->visitButterfly(visitor, butterfly, thisObject->structure(visitor.vm())->outOfLineSize());
#if !ASSERT_DISABLED
visitor.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation;
#endif
}
-void JSObject::copyBackingStore(JSCell* cell, CopyVisitor& visitor)
+void JSObject::copyBackingStore(JSCell* cell, CopyVisitor& visitor, CopyToken token)
{
JSObject* thisObject = jsCast<JSObject*>(cell);
- ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+
+ if (token != ButterflyCopyToken)
+ return;
Butterfly* butterfly = thisObject->butterfly();
if (butterfly)
void JSFinalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
JSFinalObject* thisObject = jsCast<JSFinalObject*>(cell);
- ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
#if !ASSERT_DISABLED
bool wasCheckingForDefaultMarkViolation = visitor.m_isCheckingForDefaultMarkViolation;
visitor.m_isCheckingForDefaultMarkViolation = false;
JSCell::visitChildren(thisObject, visitor);
+ Structure* structure = thisObject->structure();
Butterfly* butterfly = thisObject->butterfly();
if (butterfly)
- thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
+ thisObject->visitButterfly(visitor, butterfly, structure->outOfLineSize());
- size_t storageSize = thisObject->structure()->inlineSize();
+ size_t storageSize = structure->inlineSize();
visitor.appendValues(thisObject->inlineStorage(), storageSize);
#if !ASSERT_DISABLED
return info->className;
}
-bool JSObject::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned i, PropertySlot& slot)
+bool JSObject::getOwnPropertySlotByIndex(JSObject* thisObject, ExecState* exec, unsigned i, PropertySlot& slot)
{
// NB. The fact that we're directly consulting our indexed storage implies that it is not
// legal for anyone to override getOwnPropertySlot() without also overriding
// getOwnPropertySlotByIndex().
- JSObject* thisObject = jsCast<JSObject*>(cell);
-
if (i > MAX_ARRAY_INDEX)
- return thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, Identifier::from(exec, i), slot);
+ return thisObject->methodTable(exec->vm())->getOwnPropertySlot(thisObject, exec, Identifier::from(exec, i), slot);
- switch (thisObject->structure()->indexingType()) {
+ switch (thisObject->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
case ALL_UNDECIDED_INDEXING_TYPES:
break;
case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES: {
- Butterfly* butterfly = thisObject->m_butterfly;
+ Butterfly* butterfly = thisObject->butterfly();
if (i >= butterfly->vectorLength())
return false;
JSValue value = butterfly->contiguous()[i].get();
if (value) {
- slot.setValue(value);
+ slot.setValue(thisObject, None, value);
return true;
}
}
case ALL_DOUBLE_INDEXING_TYPES: {
- Butterfly* butterfly = thisObject->m_butterfly;
+ Butterfly* butterfly = thisObject->butterfly();
if (i >= butterfly->vectorLength())
return false;
double value = butterfly->contiguousDouble()[i];
if (value == value) {
- slot.setValue(JSValue(JSValue::EncodeAsDouble, value));
+ slot.setValue(thisObject, None, JSValue(JSValue::EncodeAsDouble, value));
return true;
}
if (i < storage->vectorLength()) {
JSValue value = storage->m_vector[i].get();
if (value) {
- slot.setValue(value);
+ slot.setValue(thisObject, None, value);
return true;
}
} else if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
SparseArrayValueMap::iterator it = map->find(i);
if (it != map->notFound()) {
- it->value.get(slot);
+ it->value.get(thisObject, slot);
return true;
}
}
// Check if there are any setters or getters in the prototype chain
JSValue prototype;
if (propertyName != exec->propertyNames().underscoreProto) {
- for (JSObject* obj = thisObject; !obj->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) {
+ for (JSObject* obj = thisObject; !obj->structure(vm)->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) {
prototype = obj->prototype();
if (prototype.isNull()) {
- ASSERT(!thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName));
+ ASSERT(!thisObject->structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName));
if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot, getCallableObject(value))
&& slot.isStrictMode())
throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
for (obj = thisObject; ; obj = asObject(prototype)) {
unsigned attributes;
JSCell* specificValue;
- PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes, specificValue);
+ PropertyOffset offset = obj->structure(vm)->get(vm, propertyName, attributes, specificValue);
if (isValidOffset(offset)) {
if (attributes & ReadOnly) {
- ASSERT(thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject);
+ ASSERT(thisObject->structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject);
if (slot.isStrictMode())
- throwError(exec, createTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError)));
+ exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError)));
return;
}
JSValue gs = obj->getDirect(offset);
if (gs.isGetterSetter()) {
- ASSERT(attributes & Accessor);
- ASSERT(thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject);
- JSObject* setterFunc = asGetterSetter(gs)->setter();
- if (!setterFunc) {
- if (slot.isStrictMode())
- throwError(exec, createTypeError(exec, ASCIILiteral("setting a property that has only a getter")));
- return;
- }
-
- CallData callData;
- CallType callType = setterFunc->methodTable()->getCallData(setterFunc, callData);
- MarkedArgumentBuffer args;
- args.append(value);
-
- // If this is WebCore's global object then we need to substitute the shell.
- call(exec, setterFunc, callType, callData, thisObject->methodTable()->toThisObject(thisObject, exec), args);
+ callSetter(exec, cell, gs, value, slot.isStrictMode() ? StrictMode : NotStrictMode);
+ if (!thisObject->structure()->isDictionary())
+ slot.setCacheableSetter(obj, offset);
return;
- } else
- ASSERT(!(attributes & Accessor));
+ }
+ if (gs.isCustomGetterSetter()) {
+ callCustomSetter(exec, gs, obj, slot.thisValue(), value);
+ slot.setCustomProperty(obj, jsCast<CustomGetterSetter*>(gs.asCell())->setter());
+ return;
+ }
+ ASSERT(!(attributes & Accessor));
// If there's an existing property on the object or one of its
// prototypes it should be replaced, so break here.
break;
}
-
+ const ClassInfo* info = obj->classInfo();
+ if (info->hasStaticSetterOrReadonlyProperties(vm)) {
+ if (const HashTableValue* entry = obj->findPropertyHashEntry(vm, propertyName)) {
+ putEntry(exec, entry, obj, propertyName, value, slot);
+ return;
+ }
+ }
prototype = obj->prototype();
if (prototype.isNull())
break;
}
- ASSERT(!thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject);
+ ASSERT(!thisObject->structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject);
if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot, getCallableObject(value)) && slot.isStrictMode())
throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
return;
JSObject* thisObject = jsCast<JSObject*>(cell);
if (propertyName > MAX_ARRAY_INDEX) {
- PutPropertySlot slot(shouldThrow);
+ PutPropertySlot slot(cell, shouldThrow);
thisObject->methodTable()->put(thisObject, exec, Identifier::from(exec, propertyName), value, slot);
return;
}
- switch (thisObject->structure()->indexingType()) {
+ switch (thisObject->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
break;
putByIndex(cell, exec, propertyName, value, shouldThrow);
return;
}
- // Fall through.
+ FALLTHROUGH;
}
case ALL_CONTIGUOUS_INDEXING_TYPES: {
- Butterfly* butterfly = thisObject->m_butterfly;
+ Butterfly* butterfly = thisObject->butterfly();
if (propertyName >= butterfly->vectorLength())
break;
butterfly->contiguous()[propertyName].set(exec->vm(), thisObject, value);
putByIndex(cell, exec, propertyName, value, shouldThrow);
return;
}
- Butterfly* butterfly = thisObject->m_butterfly;
+ Butterfly* butterfly = thisObject->butterfly();
if (propertyName >= butterfly->vectorLength())
break;
butterfly->contiguousDouble()[propertyName] = valueAsDouble;
map->add(this, i).iterator->value.set(vm, this, value);
}
- Butterfly* newButterfly = storage->butterfly()->resizeArray(vm, structure(), 0, ArrayStorage::sizeFor(0));
+ DeferGC deferGC(vm.heap);
+ Butterfly* newButterfly = storage->butterfly()->resizeArray(vm, this, structure(vm), 0, ArrayStorage::sizeFor(0));
RELEASE_ASSERT(newButterfly);
-
- m_butterfly = newButterfly;
newButterfly->arrayStorage()->m_indexBias = 0;
newButterfly->arrayStorage()->setVectorLength(0);
newButterfly->arrayStorage()->m_sparseMap.set(vm, this, map);
+ setButterflyWithoutChangingStructure(vm, newButterfly);
return newButterfly->arrayStorage();
}
void JSObject::enterDictionaryIndexingMode(VM& vm)
{
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
case ALL_UNDECIDED_INDEXING_TYPES:
case ALL_INT32_INDEXING_TYPES:
if (mayInterceptIndexedAccesses())
return;
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AddIndexedAccessors), m_butterfly);
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AddIndexedAccessors));
if (!vm.prototypeMap.isPrototype(this))
return;
Butterfly* JSObject::createInitialIndexedStorage(VM& vm, unsigned length, size_t elementSize)
{
ASSERT(length < MAX_ARRAY_INDEX);
- IndexingType oldType = structure()->indexingType();
+ IndexingType oldType = indexingType();
ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
ASSERT(!structure()->needsSlowPutIndexing());
ASSERT(!indexingShouldBeSparse());
unsigned vectorLength = std::max(length, BASE_VECTOR_LEN);
- Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(m_butterfly,
- vm, structure(), structure()->outOfLineCapacity(), false, 0,
+ Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(
+ m_butterfly.get(), vm, this, structure(), structure()->outOfLineCapacity(), false, 0,
elementSize * vectorLength);
newButterfly->setPublicLength(length);
newButterfly->setVectorLength(vectorLength);
Butterfly* JSObject::createInitialUndecided(VM& vm, unsigned length)
{
+ DeferGC deferGC(vm.heap);
Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue));
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateUndecided);
- setButterfly(vm, newButterfly, newStructure);
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), AllocateUndecided);
+ setStructureAndButterfly(vm, newStructure, newButterfly);
return newButterfly;
}
ContiguousJSValues JSObject::createInitialInt32(VM& vm, unsigned length)
{
+ DeferGC deferGC(vm.heap);
Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue));
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateInt32);
- setButterfly(vm, newButterfly, newStructure);
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), AllocateInt32);
+ setStructureAndButterfly(vm, newStructure, newButterfly);
return newButterfly->contiguousInt32();
}
ContiguousDoubles JSObject::createInitialDouble(VM& vm, unsigned length)
{
+ DeferGC deferGC(vm.heap);
Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(double));
for (unsigned i = newButterfly->vectorLength(); i--;)
- newButterfly->contiguousDouble()[i] = QNaN;
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateDouble);
- setButterfly(vm, newButterfly, newStructure);
+ newButterfly->contiguousDouble()[i] = PNaN;
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), AllocateDouble);
+ setStructureAndButterfly(vm, newStructure, newButterfly);
return newButterfly->contiguousDouble();
}
ContiguousJSValues JSObject::createInitialContiguous(VM& vm, unsigned length)
{
+ DeferGC deferGC(vm.heap);
Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue));
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateContiguous);
- setButterfly(vm, newButterfly, newStructure);
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), AllocateContiguous);
+ setStructureAndButterfly(vm, newStructure, newButterfly);
return newButterfly->contiguous();
}
ArrayStorage* JSObject::createArrayStorage(VM& vm, unsigned length, unsigned vectorLength)
{
- IndexingType oldType = structure()->indexingType();
+ DeferGC deferGC(vm.heap);
+ Structure* structure = this->structure(vm);
+ IndexingType oldType = indexingType();
ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
- Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(m_butterfly,
- vm, structure(), structure()->outOfLineCapacity(), false, 0,
+ Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(
+ m_butterfly.get(), vm, this, structure, structure->outOfLineCapacity(), false, 0,
ArrayStorage::sizeFor(vectorLength));
RELEASE_ASSERT(newButterfly);
result->m_sparseMap.clear();
result->m_numValuesInVector = 0;
result->m_indexBias = 0;
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), structure()->suggestedArrayStorageTransition());
- setButterfly(vm, newButterfly, newStructure);
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure, structure->suggestedArrayStorageTransition());
+ setStructureAndButterfly(vm, newStructure, newButterfly);
return result;
}
ContiguousJSValues JSObject::convertUndecidedToInt32(VM& vm)
{
- ASSERT(hasUndecided(structure()->indexingType()));
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateInt32), m_butterfly);
+ ASSERT(hasUndecided(indexingType()));
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateInt32));
return m_butterfly->contiguousInt32();
}
ContiguousDoubles JSObject::convertUndecidedToDouble(VM& vm)
{
- ASSERT(hasUndecided(structure()->indexingType()));
+ ASSERT(hasUndecided(indexingType()));
for (unsigned i = m_butterfly->vectorLength(); i--;)
- m_butterfly->contiguousDouble()[i] = QNaN;
+ m_butterfly->contiguousDouble()[i] = PNaN;
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble), m_butterfly);
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateDouble));
return m_butterfly->contiguousDouble();
}
ContiguousJSValues JSObject::convertUndecidedToContiguous(VM& vm)
{
- ASSERT(hasUndecided(structure()->indexingType()));
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous), m_butterfly);
+ ASSERT(hasUndecided(indexingType()));
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateContiguous));
return m_butterfly->contiguous();
}
ArrayStorage* JSObject::constructConvertedArrayStorageWithoutCopyingElements(VM& vm, unsigned neededLength)
{
+ Structure* structure = this->structure(vm);
unsigned publicLength = m_butterfly->publicLength();
- unsigned propertyCapacity = structure()->outOfLineCapacity();
- unsigned propertySize = structure()->outOfLineSize();
+ unsigned propertyCapacity = structure->outOfLineCapacity();
+ unsigned propertySize = structure->outOfLineSize();
Butterfly* newButterfly = Butterfly::createUninitialized(
- vm, 0, propertyCapacity, true, ArrayStorage::sizeFor(neededLength));
+ vm, this, 0, propertyCapacity, true, ArrayStorage::sizeFor(neededLength));
memcpy(
newButterfly->propertyStorage() - propertySize,
ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength)
{
- ASSERT(hasUndecided(structure()->indexingType()));
+ DeferGC deferGC(vm.heap);
+ ASSERT(hasUndecided(indexingType()));
ArrayStorage* storage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength);
// No need to copy elements.
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition);
- setButterfly(vm, storage->butterfly(), newStructure);
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), transition);
+ setStructureAndButterfly(vm, newStructure, storage->butterfly());
return storage;
}
ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm)
{
- return convertUndecidedToArrayStorage(vm, structure()->suggestedArrayStorageTransition());
+ return convertUndecidedToArrayStorage(vm, structure(vm)->suggestedArrayStorageTransition());
}
ContiguousDoubles JSObject::convertInt32ToDouble(VM& vm)
{
- ASSERT(hasInt32(structure()->indexingType()));
+ ASSERT(hasInt32(indexingType()));
for (unsigned i = m_butterfly->vectorLength(); i--;) {
WriteBarrier<Unknown>* current = &m_butterfly->contiguousInt32()[i];
double* currentAsDouble = bitwise_cast<double*>(current);
JSValue v = current->get();
if (!v) {
- *currentAsDouble = QNaN;
+ *currentAsDouble = PNaN;
continue;
}
ASSERT(v.isInt32());
*currentAsDouble = v.asInt32();
}
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble), m_butterfly);
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateDouble));
return m_butterfly->contiguousDouble();
}
ContiguousJSValues JSObject::convertInt32ToContiguous(VM& vm)
{
- ASSERT(hasInt32(structure()->indexingType()));
+ ASSERT(hasInt32(indexingType()));
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous), m_butterfly);
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateContiguous));
return m_butterfly->contiguous();
}
ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength)
{
- ASSERT(hasInt32(structure()->indexingType()));
+ ASSERT(hasInt32(indexingType()));
+ DeferGC deferGC(vm.heap);
ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength);
for (unsigned i = m_butterfly->publicLength(); i--;) {
JSValue v = m_butterfly->contiguous()[i].get();
newStorage->m_numValuesInVector++;
}
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition);
- setButterfly(vm, newStorage->butterfly(), newStructure);
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), transition);
+ setStructureAndButterfly(vm, newStructure, newStorage->butterfly());
return newStorage;
}
ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm)
{
- return convertInt32ToArrayStorage(vm, structure()->suggestedArrayStorageTransition());
+ return convertInt32ToArrayStorage(vm, structure(vm)->suggestedArrayStorageTransition());
}
template<JSObject::DoubleToContiguousMode mode>
ContiguousJSValues JSObject::genericConvertDoubleToContiguous(VM& vm)
{
- ASSERT(hasDouble(structure()->indexingType()));
+ ASSERT(hasDouble(indexingType()));
for (unsigned i = m_butterfly->vectorLength(); i--;) {
double* current = &m_butterfly->contiguousDouble()[i];
case RageConvertDoubleToValue:
v = jsNumber(value);
break;
+ default:
+ v = JSValue();
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
}
ASSERT(v.isNumber());
currentAsValue->setWithoutWriteBarrier(v);
}
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous), m_butterfly);
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateContiguous));
return m_butterfly->contiguous();
}
ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength)
{
- ASSERT(hasDouble(structure()->indexingType()));
+ DeferGC deferGC(vm.heap);
+ ASSERT(hasDouble(indexingType()));
ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength);
for (unsigned i = m_butterfly->publicLength(); i--;) {
newStorage->m_numValuesInVector++;
}
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition);
- setButterfly(vm, newStorage->butterfly(), newStructure);
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), transition);
+ setStructureAndButterfly(vm, newStructure, newStorage->butterfly());
return newStorage;
}
ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm)
{
- return convertDoubleToArrayStorage(vm, structure()->suggestedArrayStorageTransition());
+ return convertDoubleToArrayStorage(vm, structure(vm)->suggestedArrayStorageTransition());
}
ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength)
{
- ASSERT(hasContiguous(structure()->indexingType()));
+ DeferGC deferGC(vm.heap);
+ ASSERT(hasContiguous(indexingType()));
ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength);
for (unsigned i = m_butterfly->publicLength(); i--;) {
newStorage->m_numValuesInVector++;
}
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition);
- setButterfly(vm, newStorage->butterfly(), newStructure);
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), transition);
+ setStructureAndButterfly(vm, newStructure, newStorage->butterfly());
return newStorage;
}
ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm)
{
- return convertContiguousToArrayStorage(vm, structure()->suggestedArrayStorageTransition());
+ return convertContiguousToArrayStorage(vm, structure(vm)->suggestedArrayStorageTransition());
}
void JSObject::convertUndecidedForValue(VM& vm, JSValue value)
return;
}
- if (value.isDouble()) {
+ 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());
ContiguousJSValues JSObject::ensureInt32Slow(VM& vm)
{
- ASSERT(inherits(&s_info));
+ ASSERT(inherits(info()));
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
- if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
+ if (UNLIKELY(indexingShouldBeSparse() || structure(vm)->needsSlowPutIndexing()))
return ContiguousJSValues();
return createInitialInt32(vm, 0);
ContiguousDoubles JSObject::ensureDoubleSlow(VM& vm)
{
- ASSERT(inherits(&s_info));
+ ASSERT(inherits(info()));
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
- if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
+ if (UNLIKELY(indexingShouldBeSparse() || structure(vm)->needsSlowPutIndexing()))
return ContiguousDoubles();
return createInitialDouble(vm, 0);
ContiguousJSValues JSObject::ensureContiguousSlow(VM& vm, DoubleToContiguousMode mode)
{
- ASSERT(inherits(&s_info));
+ ASSERT(inherits(info()));
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
- if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
+ if (UNLIKELY(indexingShouldBeSparse() || structure(vm)->needsSlowPutIndexing()))
return ContiguousJSValues();
return createInitialContiguous(vm, 0);
ArrayStorage* JSObject::ensureArrayStorageSlow(VM& vm)
{
- ASSERT(inherits(&s_info));
+ ASSERT(inherits(info()));
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
if (UNLIKELY(indexingShouldBeSparse()))
return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm);
case ALL_UNDECIDED_INDEXING_TYPES:
ASSERT(!indexingShouldBeSparse());
- ASSERT(!structure()->needsSlowPutIndexing());
+ ASSERT(!structure(vm)->needsSlowPutIndexing());
return convertUndecidedToArrayStorage(vm);
case ALL_INT32_INDEXING_TYPES:
ASSERT(!indexingShouldBeSparse());
- ASSERT(!structure()->needsSlowPutIndexing());
+ ASSERT(!structure(vm)->needsSlowPutIndexing());
return convertInt32ToArrayStorage(vm);
case ALL_DOUBLE_INDEXING_TYPES:
ASSERT(!indexingShouldBeSparse());
- ASSERT(!structure()->needsSlowPutIndexing());
+ ASSERT(!structure(vm)->needsSlowPutIndexing());
return convertDoubleToArrayStorage(vm);
case ALL_CONTIGUOUS_INDEXING_TYPES:
ASSERT(!indexingShouldBeSparse());
- ASSERT(!structure()->needsSlowPutIndexing());
+ ASSERT(!structure(vm)->needsSlowPutIndexing());
return convertContiguousToArrayStorage(vm);
default:
ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(VM& vm)
{
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES: {
createArrayStorage(vm, 0, 0);
SparseArrayValueMap* map = allocateSparseIndexMap(vm);
void JSObject::switchToSlowPutArrayStorage(VM& vm)
{
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ALL_UNDECIDED_INDEXING_TYPES:
convertUndecidedToArrayStorage(vm, AllocateSlowPutArrayStorage);
break;
case NonArrayWithArrayStorage:
case ArrayWithArrayStorage: {
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), SwitchToSlowPutArrayStorage);
- setStructure(vm, newStructure, m_butterfly);
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), SwitchToSlowPutArrayStorage);
+ setStructure(vm, newStructure);
break;
}
}
}
-void JSObject::putDirectVirtual(JSObject* object, ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes)
-{
- ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
- PutPropertySlot slot;
- object->putDirectInternal<PutModeDefineOwnProperty>(exec->vm(), propertyName, value, attributes, slot, getCallableObject(value));
-}
-
void JSObject::setPrototype(VM& vm, JSValue prototype)
{
ASSERT(prototype);
if (prototype.isObject())
vm.prototypeMap.addPrototype(asObject(prototype));
- Structure* newStructure = Structure::changePrototypeTransition(vm, structure(), prototype);
- setStructure(vm, newStructure, m_butterfly);
+ Structure* newStructure = Structure::changePrototypeTransition(vm, structure(vm), prototype);
+ setStructure(vm, newStructure);
if (!newStructure->anyObjectInChainMayInterceptIndexedAccesses())
return;
return;
}
- if (!hasIndexingHeader(structure()->indexingType()))
+ if (!hasIndexedProperties(indexingType()))
return;
- if (shouldUseSlowPut(structure()->indexingType()))
+ if (shouldUseSlowPut(indexingType()))
return;
switchToSlowPutArrayStorage(vm);
}
-bool JSObject::setPrototypeWithCycleCheck(VM& vm, JSValue prototype)
+bool JSObject::setPrototypeWithCycleCheck(ExecState* exec, JSValue prototype)
{
- JSValue checkFor = this;
- if (this->isGlobalObject())
- checkFor = jsCast<JSGlobalObject*>(this)->globalExec()->thisValue();
-
+ ASSERT(methodTable(exec->vm())->toThis(this, exec, NotStrictMode) == this);
JSValue nextPrototype = prototype;
while (nextPrototype && nextPrototype.isObject()) {
- if (nextPrototype == checkFor)
+ if (nextPrototype == this)
return false;
nextPrototype = asObject(nextPrototype)->prototype();
}
- setPrototype(vm, prototype);
+ setPrototype(exec->vm(), prototype);
return true;
}
return;
}
- VM& vm = exec->vm();
+ putDirectNonIndexAccessor(exec->vm(), propertyName, value, attributes);
+}
- PutPropertySlot slot;
+void JSObject::putDirectCustomAccessor(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
+{
+ ASSERT(propertyName.asIndex() == PropertyName::NotAnIndex);
+
+ PutPropertySlot slot(this);
+ putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot, getCallableObject(value));
+
+ ASSERT(slot.type() == PutPropertySlot::NewProperty);
+
+ Structure* structure = this->structure(vm);
+ if (attributes & ReadOnly)
+ structure->setContainsReadOnlyProperties();
+ structure->setHasCustomGetterSetterProperties(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, getCallableObject(value));
// putDirect will change our Structure if we add a new property. For
// getters and setters, though, we also need to change our Structure
// if we override an existing non-getter or non-setter.
if (slot.type() != PutPropertySlot::NewProperty)
- setStructure(vm, Structure::attributeChangeTransition(vm, structure(), propertyName, attributes), m_butterfly);
+ setStructure(vm, Structure::attributeChangeTransition(vm, structure(vm), propertyName, attributes));
+ Structure* structure = this->structure(vm);
if (attributes & ReadOnly)
- structure()->setContainsReadOnlyProperties();
+ structure->setContainsReadOnlyProperties();
- structure()->setHasGetterSetterProperties(propertyName == vm.propertyNames->underscoreProto);
+ structure->setHasGetterSetterProperties(propertyName == vm.propertyNames->underscoreProto);
}
bool JSObject::hasProperty(ExecState* exec, PropertyName propertyName) const
{
- PropertySlot slot;
+ PropertySlot slot(this);
return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
}
bool JSObject::hasProperty(ExecState* exec, unsigned propertyName) const
{
- PropertySlot slot;
+ PropertySlot slot(this);
return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
}
unsigned i = propertyName.asIndex();
if (i != PropertyName::NotAnIndex)
- return thisObject->methodTable()->deletePropertyByIndex(thisObject, exec, i);
+ return thisObject->methodTable(exec->vm())->deletePropertyByIndex(thisObject, exec, i);
if (!thisObject->staticFunctionsReified())
thisObject->reifyStaticFunctionsForDelete(exec);
unsigned attributes;
JSCell* specificValue;
- if (isValidOffset(thisObject->structure()->get(exec->vm(), propertyName, attributes, specificValue))) {
- if (attributes & DontDelete && !exec->vm().isInDefineOwnProperty())
+ VM& vm = exec->vm();
+ if (isValidOffset(thisObject->structure(vm)->get(vm, propertyName, attributes, specificValue))) {
+ if (attributes & DontDelete && !vm.isInDefineOwnProperty())
return false;
- thisObject->removeDirect(exec->vm(), propertyName);
+ thisObject->removeDirect(vm, propertyName);
return true;
}
// Look in the static hashtable of properties
- const HashEntry* entry = thisObject->findPropertyHashEntry(exec, propertyName);
+ const HashTableValue* entry = thisObject->findPropertyHashEntry(vm, propertyName);
if (entry) {
- if (entry->attributes() & DontDelete && !exec->vm().isInDefineOwnProperty())
+ if (entry->attributes() & DontDelete && !vm.isInDefineOwnProperty())
return false; // this builtin property can't be deleted
- putEntry(exec, entry, propertyName, jsUndefined(), thisObject);
+ PutPropertySlot slot(thisObject);
+ putEntry(exec, entry, thisObject, propertyName, jsUndefined(), slot);
}
return true;
bool JSObject::hasOwnProperty(ExecState* exec, PropertyName propertyName) const
{
- PropertySlot slot;
- return const_cast<JSObject*>(this)->methodTable()->getOwnPropertySlot(const_cast<JSObject*>(this), exec, propertyName, slot);
+ PropertySlot slot(this);
+ return const_cast<JSObject*>(this)->methodTable(exec->vm())->getOwnPropertySlot(const_cast<JSObject*>(this), exec, propertyName, slot);
}
bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
JSObject* thisObject = jsCast<JSObject*>(cell);
if (i > MAX_ARRAY_INDEX)
- return thisObject->methodTable()->deleteProperty(thisObject, exec, Identifier::from(exec, i));
+ return thisObject->methodTable(exec->vm())->deleteProperty(thisObject, exec, Identifier::from(exec, i));
- switch (thisObject->structure()->indexingType()) {
+ switch (thisObject->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
case ALL_UNDECIDED_INDEXING_TYPES:
return true;
case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES: {
- Butterfly* butterfly = thisObject->m_butterfly;
+ Butterfly* butterfly = thisObject->butterfly();
if (i >= butterfly->vectorLength())
return true;
butterfly->contiguous()[i].clear();
}
case ALL_DOUBLE_INDEXING_TYPES: {
- Butterfly* butterfly = thisObject->m_butterfly;
+ Butterfly* butterfly = thisObject->butterfly();
if (i >= butterfly->vectorLength())
return true;
- butterfly->contiguousDouble()[i] = QNaN;
+ butterfly->contiguousDouble()[i] = PNaN;
return true;
}
bool JSObject::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result) const
{
- result = methodTable()->defaultValue(this, exec, PreferNumber);
+ result = methodTable(exec->vm())->defaultValue(this, exec, PreferNumber);
number = result.toNumber(exec);
return !result.isString();
}
ASSERT(!exec->hadException());
- return throwError(exec, createTypeError(exec, ASCIILiteral("No default value")));
+ return exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("No default value")));
}
-const HashEntry* JSObject::findPropertyHashEntry(ExecState* exec, PropertyName propertyName) const
+const HashTableValue* JSObject::findPropertyHashEntry(VM& vm, PropertyName propertyName) const
{
for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
- if (const HashTable* propHashTable = info->propHashTable(exec)) {
- if (const HashEntry* entry = propHashTable->entry(exec, propertyName))
+ if (const HashTable* propHashTable = info->propHashTable(vm)) {
+ if (const HashTableValue* entry = propHashTable->entry(vm, propertyName))
return entry;
}
}
bool JSObject::hasInstance(ExecState* exec, JSValue value)
{
- TypeInfo info = structure()->typeInfo();
+ VM& vm = exec->vm();
+ TypeInfo info = structure(vm)->typeInfo();
if (info.implementsDefaultHasInstance())
return defaultHasInstance(exec, value, get(exec, exec->propertyNames().prototype));
if (info.implementsHasInstance())
- return methodTable()->customHasInstance(this, exec, value);
- throwError(exec, createInvalidParamError(exec, "instanceof" , this));
+ return methodTable(vm)->customHasInstance(this, exec, value);
+ vm.throwException(exec, createInvalidParameterError(exec, "instanceof" , this));
return false;
}
return false;
if (!proto.isObject()) {
- throwError(exec, createTypeError(exec, ASCIILiteral("instanceof called on an object with an invalid prototype property.")));
+ exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("instanceof called on an object with an invalid prototype property.")));
return false;
}
return false;
}
-bool JSObject::propertyIsEnumerable(ExecState* exec, const Identifier& propertyName) const
-{
- PropertyDescriptor descriptor;
- if (!const_cast<JSObject*>(this)->methodTable()->getOwnPropertyDescriptor(const_cast<JSObject*>(this), exec, propertyName, descriptor))
- return false;
- return descriptor.enumerable();
-}
-
bool JSObject::getPropertySpecificValue(ExecState* exec, PropertyName propertyName, JSCell*& specificValue) const
{
+ VM& vm = exec->vm();
unsigned attributes;
- if (isValidOffset(structure()->get(exec->vm(), propertyName, attributes, specificValue)))
+ if (isValidOffset(structure(vm)->get(vm, propertyName, attributes, specificValue)))
return true;
// This could be a function within the static table? - should probably
void JSObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
propertyNames.setBaseObject(object);
- object->methodTable()->getOwnPropertyNames(object, exec, propertyNames, mode);
+ object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, propertyNames, mode);
if (object->prototype().isNull())
return;
+ VM& vm = exec->vm();
JSObject* prototype = asObject(object->prototype());
while(1) {
- if (prototype->structure()->typeInfo().overridesGetPropertyNames()) {
- prototype->methodTable()->getPropertyNames(prototype, exec, propertyNames, mode);
+ if (prototype->structure(vm)->typeInfo().overridesGetPropertyNames()) {
+ prototype->methodTable(vm)->getPropertyNames(prototype, exec, propertyNames, mode);
break;
}
- prototype->methodTable()->getOwnPropertyNames(prototype, exec, propertyNames, mode);
+ prototype->methodTable(vm)->getOwnPropertyNames(prototype, exec, propertyNames, mode);
JSValue nextProto = prototype->prototype();
if (nextProto.isNull())
break;
// FIXME: Filling PropertyNameArray with an identifier for every integer
// is incredibly inefficient for large arrays. We need a different approach,
// which almost certainly means a different structure for PropertyNameArray.
- switch (object->structure()->indexingType()) {
+ switch (object->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
case ALL_UNDECIDED_INDEXING_TYPES:
break;
case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES: {
- Butterfly* butterfly = object->m_butterfly;
+ Butterfly* butterfly = object->butterfly();
unsigned usedLength = butterfly->publicLength();
for (unsigned i = 0; i < usedLength; ++i) {
if (!butterfly->contiguous()[i])
}
case ALL_DOUBLE_INDEXING_TYPES: {
- Butterfly* butterfly = object->m_butterfly;
+ Butterfly* butterfly = object->butterfly();
unsigned usedLength = butterfly->publicLength();
for (unsigned i = 0; i < usedLength; ++i) {
double value = butterfly->contiguousDouble()[i];
RELEASE_ASSERT_NOT_REACHED();
}
- object->methodTable()->getOwnNonIndexPropertyNames(object, exec, propertyNames, mode);
+ object->methodTable(exec->vm())->getOwnNonIndexPropertyNames(object, exec, propertyNames, mode);
}
void JSObject::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
getClassPropertyNames(exec, object->classInfo(), propertyNames, mode, object->staticFunctionsReified());
+ VM& vm = exec->vm();
bool canCachePropertiesFromStructure = !propertyNames.size();
- object->structure()->getPropertyNamesFromStructure(exec->vm(), propertyNames, mode);
+ object->structure(vm)->getPropertyNamesFromStructure(vm, propertyNames, mode);
if (canCachePropertiesFromStructure)
propertyNames.setNumCacheableSlotsForObject(object, propertyNames.size());
return primitive.toString(exec);
}
-JSObject* JSObject::toThisObject(JSCell* cell, ExecState*)
+JSValue JSObject::toThis(JSCell* cell, ExecState*, ECMAMode)
{
return jsCast<JSObject*>(cell);
}
if (isSealed(vm))
return;
preventExtensions(vm);
- setStructure(vm, Structure::sealTransition(vm, structure()), m_butterfly);
+ setStructure(vm, Structure::sealTransition(vm, structure(vm)));
}
void JSObject::freeze(VM& vm)
if (isFrozen(vm))
return;
preventExtensions(vm);
- setStructure(vm, Structure::freezeTransition(vm, structure()), m_butterfly);
+ setStructure(vm, Structure::freezeTransition(vm, structure(vm)));
}
void JSObject::preventExtensions(VM& vm)
{
enterDictionaryIndexingMode(vm);
if (isExtensible())
- setStructure(vm, Structure::preventExtensionsTransition(vm, structure()), m_butterfly);
+ setStructure(vm, Structure::preventExtensionsTransition(vm, structure(vm)));
}
// This presently will flatten to an uncachable dictionary; this is suitable
// If this object's ClassInfo has no static properties, then nothing to reify!
// We can safely set the flag to avoid the expensive check again in the future.
if (!classInfo()->hasStaticProperties()) {
- structure()->setStaticFunctionsReified();
+ structure(vm)->setStaticFunctionsReified();
return;
}
- if (!structure()->isUncacheableDictionary())
- setStructure(vm, Structure::toUncacheableDictionaryTransition(vm, structure()), m_butterfly);
+ if (!structure(vm)->isUncacheableDictionary())
+ setStructure(vm, Structure::toUncacheableDictionaryTransition(vm, structure(vm)));
for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
- const HashTable* hashTable = info->propHashTable(globalObject()->globalExec());
+ const HashTable* hashTable = info->propHashTable(vm);
if (!hashTable)
continue;
- PropertySlot slot;
- for (HashTable::ConstIterator iter = hashTable->begin(vm); iter != hashTable->end(vm); ++iter) {
- if (iter->attributes() & Function)
- setUpStaticFunctionSlot(globalObject()->globalExec(), *iter, this, Identifier(&vm, iter->key()), slot);
+ PropertySlot slot(this);
+ for (auto iter = hashTable->begin(vm); iter != hashTable->end(vm); ++iter) {
+ if (iter->attributes() & BuiltinOrFunction)
+ setUpStaticFunctionSlot(globalObject()->globalExec(), iter.value(), this, Identifier(&vm, iter.key()), slot);
}
}
- structure()->setStaticFunctionsReified();
+ structure(vm)->setStaticFunctionsReified();
}
bool JSObject::removeDirect(VM& vm, PropertyName propertyName)
{
- if (!isValidOffset(structure()->get(vm, propertyName)))
+ Structure* structure = this->structure(vm);
+ if (!isValidOffset(structure->get(vm, propertyName)))
return false;
PropertyOffset offset;
- if (structure()->isUncacheableDictionary()) {
- offset = structure()->removePropertyWithoutTransition(vm, propertyName);
+ if (structure->isUncacheableDictionary()) {
+ offset = structure->removePropertyWithoutTransition(vm, propertyName);
if (offset == invalidOffset)
return false;
putDirectUndefined(offset);
return true;
}
- setStructure(vm, Structure::removePropertyTransition(vm, structure(), propertyName, offset), m_butterfly);
+ setStructure(vm, Structure::removePropertyTransition(vm, structure, propertyName, offset));
if (offset == invalidOffset)
return false;
putDirectUndefined(offset);
return true;
}
-NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, PropertyOffset offset)
+NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue getterSetter, unsigned attributes, PropertyOffset offset)
{
- if (JSObject* getterFunction = asGetterSetter(getDirect(offset))->getter()) {
- if (!structure()->isDictionary())
- slot.setCacheableGetterSlot(this, getterFunction, offset);
- else
- slot.setGetterSlot(getterFunction);
- } else
- slot.setUndefined();
+ if (structure()->isDictionary()) {
+ slot.setGetterSlot(this, attributes, jsCast<GetterSetter*>(getterSetter));
+ return;
+ }
+ slot.setCacheableGetterSlot(this, attributes, jsCast<GetterSetter*>(getterSetter), offset);
}
-void JSObject::putIndexedDescriptor(ExecState* exec, SparseArrayEntry* entryInMap, PropertyDescriptor& descriptor, PropertyDescriptor& oldDescriptor)
+void JSObject::putIndexedDescriptor(ExecState* exec, SparseArrayEntry* entryInMap, const PropertyDescriptor& descriptor, PropertyDescriptor& oldDescriptor)
{
+ VM& vm = exec->vm();
+
if (descriptor.isDataDescriptor()) {
if (descriptor.value())
- entryInMap->set(exec->vm(), this, descriptor.value());
+ entryInMap->set(vm, this, descriptor.value());
else if (oldDescriptor.isAccessorDescriptor())
- entryInMap->set(exec->vm(), this, jsUndefined());
+ entryInMap->set(vm, this, jsUndefined());
entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~Accessor;
return;
}
else if (oldDescriptor.isAccessorDescriptor())
setter = oldDescriptor.setterObject();
- GetterSetter* accessor = GetterSetter::create(exec);
+ GetterSetter* accessor = GetterSetter::create(vm);
if (getter)
- accessor->setGetter(exec->vm(), getter);
+ accessor->setGetter(vm, getter);
if (setter)
- accessor->setSetter(exec->vm(), setter);
+ accessor->setSetter(vm, setter);
- entryInMap->set(exec->vm(), this, accessor);
+ entryInMap->set(vm, this, accessor);
entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~ReadOnly;
return;
}
}
// Defined in ES5.1 8.12.9
-bool JSObject::defineOwnIndexedProperty(ExecState* exec, unsigned index, PropertyDescriptor& descriptor, bool throwException)
+bool JSObject::defineOwnIndexedProperty(ExecState* exec, unsigned index, const PropertyDescriptor& descriptor, bool throwException)
{
ASSERT(index <= MAX_ARRAY_INDEX);
template<IndexingType indexingShape>
void JSObject::putByIndexBeyondVectorLengthWithoutAttributes(ExecState* exec, unsigned i, JSValue value)
{
- ASSERT((structure()->indexingType() & IndexingShapeMask) == indexingShape);
+ ASSERT((indexingType() & IndexingShapeMask) == indexingShape);
ASSERT(!indexingShouldBeSparse());
// For us to get here, the index is either greater than the public length, or greater than
if (i >= MAX_ARRAY_INDEX - 1
|| (i >= MIN_SPARSE_ARRAY_INDEX
- && !isDenseEnoughForVector(i, countElements<indexingShape>(m_butterfly)))
+ && !isDenseEnoughForVector(i, countElements<indexingShape>(butterfly())))
|| indexIsSufficientlyBeyondLengthForSparseMap(i, m_butterfly->vectorLength())) {
ASSERT(i <= MAX_ARRAY_INDEX);
ensureArrayStorageSlow(vm);
// i should be a valid array index that is outside of the current vector.
ASSERT(i <= MAX_ARRAY_INDEX);
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES: {
if (indexingShouldBeSparse()) {
putByIndexBeyondVectorLengthWithArrayStorage(
exec, i, value, shouldThrow, createArrayStorage(vm, 0, 0));
break;
}
- if (structure()->needsSlowPutIndexing()) {
+ if (structure(vm)->needsSlowPutIndexing()) {
ArrayStorage* storage = createArrayStorage(vm, i + 1, getNewVectorLength(0, 0, i + 1));
storage->m_vector[i].set(vm, this, value);
storage->m_numValuesInVector++;
break;
}
-
- createInitialContiguous(vm, i + 1)[i].set(vm, this, value);
+
+ createInitialForValueAndSet(vm, i, value);
break;
}
SparseArrayValueMap* map = arrayStorage()->m_sparseMap.get();
if (!(map && map->contains(i)) && attemptToInterceptPutByIndexOnHole(exec, i, value, shouldThrow))
return;
- // Otherwise, fall though.
+ FALLTHROUGH;
}
case NonArrayWithArrayStorage:
VM& vm = exec->vm();
// i should be a valid array index that is outside of the current vector.
- ASSERT(hasArrayStorage(structure()->indexingType()));
+ ASSERT(hasAnyArrayStorage(indexingType()));
ASSERT(arrayStorage() == storage);
ASSERT(i >= storage->vectorLength() || attributes);
ASSERT(i <= MAX_ARRAY_INDEX);
if (attributes & (ReadOnly | Accessor))
notifyPresenceOfIndexedAccessors(vm);
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES: {
if (indexingShouldBeSparse() || attributes) {
return putDirectIndexBeyondVectorLengthWithArrayStorage(
return putDirectIndexBeyondVectorLengthWithArrayStorage(
exec, i, value, attributes, mode, createArrayStorage(vm, 0, 0));
}
- if (structure()->needsSlowPutIndexing()) {
+ if (structure(vm)->needsSlowPutIndexing()) {
ArrayStorage* storage = createArrayStorage(vm, i + 1, getNewVectorLength(0, 0, i + 1));
storage->m_vector[i].set(vm, this, value);
storage->m_numValuesInVector++;
return true;
}
- createInitialContiguous(vm, i + 1)[i].set(vm, this, value);
+ createInitialForValueAndSet(vm, i, value);
return true;
}
}
}
-void JSObject::putDirectNativeFunction(ExecState* exec, JSGlobalObject* globalObject, const PropertyName& propertyName, unsigned functionLength, NativeFunction nativeFunction, Intrinsic intrinsic, unsigned attributes)
+void JSObject::putDirectNativeFunction(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, unsigned functionLength, NativeFunction nativeFunction, Intrinsic intrinsic, unsigned attributes)
{
StringImpl* name = propertyName.publicName();
+ if (!name)
+ name = vm.propertyNames->anonymous.impl();
ASSERT(name);
-
- JSFunction* function =
- JSFunction::create(exec, globalObject, functionLength, name, nativeFunction, intrinsic);
- putDirect(exec->vm(), propertyName, function, attributes);
+
+ JSFunction* function = JSFunction::create(vm, globalObject, functionLength, name, nativeFunction, intrinsic);
+ putDirect(vm, propertyName, function, attributes);
+}
+
+JSFunction* JSObject::putDirectBuiltinFunction(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, FunctionExecutable* functionExecutable, unsigned attributes)
+{
+ StringImpl* name = propertyName.publicName();
+ if (!name)
+ name = vm.propertyNames->anonymous.impl();
+ ASSERT(name);
+ JSFunction* function = JSFunction::createBuiltinFunction(vm, static_cast<FunctionExecutable*>(functionExecutable), globalObject);
+ putDirect(vm, propertyName, function, attributes);
+ return function;
+}
+
+JSFunction* JSObject::putDirectBuiltinFunctionWithoutTransition(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, FunctionExecutable* functionExecutable, unsigned attributes)
+{
+ StringImpl* name = propertyName.publicName();
+ if (!name)
+ name = vm.propertyNames->anonymous.impl();
+ ASSERT(name);
+ JSFunction* function = JSFunction::createBuiltinFunction(vm, static_cast<FunctionExecutable*>(functionExecutable), globalObject);
+ putDirectWithoutTransition(vm, propertyName, function, attributes);
+ return function;
+}
+
+void JSObject::putDirectNativeFunctionWithoutTransition(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, unsigned functionLength, NativeFunction nativeFunction, Intrinsic intrinsic, unsigned attributes)
+{
+ StringImpl* name = propertyName.publicName();
+ ASSERT(name);
+
+ JSFunction* function = JSFunction::create(vm, globalObject, functionLength, name, nativeFunction, intrinsic);
+ putDirectWithoutTransition(vm, propertyName, function, attributes);
}
ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned currentVectorLength, unsigned currentLength, unsigned desiredLength)
unsigned vectorLength;
unsigned length;
- if (hasIndexedProperties(structure()->indexingType())) {
+ if (hasIndexedProperties(indexingType())) {
vectorLength = m_butterfly->vectorLength();
length = m_butterfly->publicLength();
} else {
unsigned JSObject::countElements()
{
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
case ALL_UNDECIDED_INDEXING_TYPES:
return 0;
case ALL_INT32_INDEXING_TYPES:
- return countElements<Int32Shape>(m_butterfly);
+ return countElements<Int32Shape>(butterfly());
case ALL_DOUBLE_INDEXING_TYPES:
- return countElements<DoubleShape>(m_butterfly);
+ return countElements<DoubleShape>(butterfly());
case ALL_CONTIGUOUS_INDEXING_TYPES:
- return countElements<ContiguousShape>(m_butterfly);
+ return countElements<ContiguousShape>(butterfly());
default:
CRASH();
unsigned newVectorLength = getNewVectorLength(newLength);
// Fast case - there is no precapacity. In these cases a realloc makes sense.
+ Structure* structure = this->structure(vm);
if (LIKELY(!indexBias)) {
- Butterfly* newButterfly = storage->butterfly()->growArrayRight(vm, structure(), structure()->outOfLineCapacity(), true, ArrayStorage::sizeFor(vectorLength), ArrayStorage::sizeFor(newVectorLength));
+ DeferGC deferGC(vm.heap);
+ Butterfly* newButterfly = storage->butterfly()->growArrayRight(
+ vm, this, structure, structure->outOfLineCapacity(), true,
+ ArrayStorage::sizeFor(vectorLength), ArrayStorage::sizeFor(newVectorLength));
if (!newButterfly)
return false;
- m_butterfly = newButterfly;
newButterfly->arrayStorage()->setVectorLength(newVectorLength);
+ setButterflyWithoutChangingStructure(vm, newButterfly);
return true;
}
// Remove some, but not all of the precapacity. Atomic decay, & capped to not overflow array length.
+ DeferGC deferGC(vm.heap);
unsigned newIndexBias = std::min(indexBias >> 1, MAX_STORAGE_VECTOR_LENGTH - newVectorLength);
Butterfly* newButterfly = storage->butterfly()->resizeArray(
- vm,
- structure()->outOfLineCapacity(), true, ArrayStorage::sizeFor(vectorLength),
+ vm, this,
+ structure->outOfLineCapacity(), true, ArrayStorage::sizeFor(vectorLength),
newIndexBias, true, ArrayStorage::sizeFor(newVectorLength));
if (!newButterfly)
return false;
-
- m_butterfly = newButterfly;
newButterfly->arrayStorage()->setVectorLength(newVectorLength);
newButterfly->arrayStorage()->m_indexBias = newIndexBias;
+ setButterflyWithoutChangingStructure(vm, newButterfly);
return true;
}
void JSObject::ensureLengthSlow(VM& vm, unsigned length)
{
ASSERT(length < MAX_ARRAY_INDEX);
- ASSERT(hasContiguous(structure()->indexingType()) || hasInt32(structure()->indexingType()) || hasDouble(structure()->indexingType()) || hasUndecided(structure()->indexingType()));
+ ASSERT(hasContiguous(indexingType()) || hasInt32(indexingType()) || hasDouble(indexingType()) || hasUndecided(indexingType()));
ASSERT(length > m_butterfly->vectorLength());
unsigned newVectorLength = std::min(
length << 1,
MAX_STORAGE_VECTOR_LENGTH);
unsigned oldVectorLength = m_butterfly->vectorLength();
- m_butterfly = m_butterfly->growArrayRight(
- vm, structure(), structure()->outOfLineCapacity(), true,
+ DeferGC deferGC(vm.heap);
+ m_butterfly.set(vm, this, m_butterfly->growArrayRight(
+ vm, this, structure(), structure()->outOfLineCapacity(), true,
oldVectorLength * sizeof(EncodedJSValue),
- newVectorLength * sizeof(EncodedJSValue));
- if (hasDouble(structure()->indexingType())) {
+ newVectorLength * sizeof(EncodedJSValue)));
+
+ m_butterfly->setVectorLength(newVectorLength);
+
+ if (hasDouble(indexingType())) {
for (unsigned i = oldVectorLength; i < newVectorLength; ++i)
- m_butterfly->contiguousDouble().data()[i] = QNaN;
+ m_butterfly->contiguousDouble().data()[i] = PNaN;
}
- m_butterfly->setVectorLength(newVectorLength);
}
Butterfly* JSObject::growOutOfLineStorage(VM& vm, size_t oldSize, size_t newSize)
// It's important that this function not rely on structure(), for the property
// capacity, since we might have already mutated the structure in-place.
- return m_butterfly->growPropertyStorage(vm, structure(), oldSize, newSize);
+ return Butterfly::createOrGrowPropertyStorage(m_butterfly.get(), vm, this, structure(vm), oldSize, newSize);
}
-bool JSObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
+bool JSObject::getOwnPropertyDescriptor(ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
{
- unsigned attributes = 0;
- JSCell* cell = 0;
- PropertyOffset offset = object->structure()->get(exec->vm(), propertyName, attributes, cell);
- if (isValidOffset(offset)) {
- descriptor.setDescriptor(object->getDirect(offset), attributes);
- return true;
- }
-
- unsigned i = propertyName.asIndex();
- if (i == PropertyName::NotAnIndex)
+ JSC::PropertySlot slot(this);
+ if (!methodTable(exec->vm())->getOwnPropertySlot(this, exec, propertyName, slot))
return false;
-
- switch (object->structure()->indexingType()) {
- case ALL_BLANK_INDEXING_TYPES:
- case ALL_UNDECIDED_INDEXING_TYPES:
+ /* Workaround, JSDOMWindow::getOwnPropertySlot searches the prototype chain. :-( */
+ if (slot.slotBase() != this && slot.slotBase() && slot.slotBase()->methodTable(exec->vm())->toThis(slot.slotBase(), exec, NotStrictMode) != this)
return false;
-
- case ALL_INT32_INDEXING_TYPES:
- case ALL_CONTIGUOUS_INDEXING_TYPES: {
- Butterfly* butterfly = object->m_butterfly;
- if (i >= butterfly->vectorLength())
- return false;
- JSValue value = butterfly->contiguous()[i].get();
- if (!value)
- return false;
- descriptor.setDescriptor(value, 0);
- return true;
- }
-
- case ALL_DOUBLE_INDEXING_TYPES: {
- Butterfly* butterfly = object->m_butterfly;
- if (i >= butterfly->vectorLength())
- return false;
- double value = butterfly->contiguousDouble()[i];
- if (value != value)
- return false;
- descriptor.setDescriptor(JSValue(JSValue::EncodeAsDouble, value), 0);
- return true;
- }
-
- case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
- ArrayStorage* storage = object->m_butterfly->arrayStorage();
- if (i >= storage->length())
- return false;
- if (i < storage->vectorLength()) {
- WriteBarrier<Unknown>& value = storage->m_vector[i];
- if (!value)
- return false;
- descriptor.setDescriptor(value.get(), 0);
- return true;
- }
- if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
- SparseArrayValueMap::iterator it = map->find(i);
- if (it == map->notFound())
- return false;
- it->value.get(descriptor);
- return true;
- }
- return false;
- }
-
- default:
- RELEASE_ASSERT_NOT_REACHED();
- return false;
- }
-}
-
-bool JSObject::getPropertyDescriptor(ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
-{
- JSObject* object = this;
- while (true) {
- if (object->methodTable()->getOwnPropertyDescriptor(object, exec, propertyName, descriptor))
- return true;
- JSValue prototype = object->prototype();
- if (!prototype.isObject())
- return false;
- object = asObject(prototype);
- }
+ if (slot.isAccessor())
+ descriptor.setAccessorDescriptor(slot.getterSetter(), slot.attributes());
+ else if (slot.attributes() & CustomAccessor)
+ descriptor.setCustomDescriptor(slot.attributes());
+ else
+ descriptor.setDescriptor(slot.getValue(exec, propertyName), slot.attributes());
+ return true;
}
-static bool putDescriptor(ExecState* exec, JSObject* target, PropertyName propertyName, PropertyDescriptor& descriptor, unsigned attributes, const PropertyDescriptor& oldDescriptor)
+static bool putDescriptor(ExecState* exec, JSObject* target, PropertyName propertyName, const PropertyDescriptor& descriptor, unsigned attributes, const PropertyDescriptor& oldDescriptor)
{
+ VM& vm = exec->vm();
if (descriptor.isGenericDescriptor() || descriptor.isDataDescriptor()) {
if (descriptor.isGenericDescriptor() && oldDescriptor.isAccessorDescriptor()) {
- GetterSetter* accessor = GetterSetter::create(exec);
+ GetterSetter* accessor = GetterSetter::create(vm);
if (oldDescriptor.getterPresent())
- accessor->setGetter(exec->vm(), oldDescriptor.getterObject());
+ accessor->setGetter(vm, oldDescriptor.getterObject());
if (oldDescriptor.setterPresent())
- accessor->setSetter(exec->vm(), oldDescriptor.setterObject());
+ accessor->setSetter(vm, oldDescriptor.setterObject());
target->putDirectAccessor(exec, propertyName, accessor, attributes | Accessor);
return true;
}
newValue = descriptor.value();
else if (oldDescriptor.value())
newValue = oldDescriptor.value();
- target->putDirect(exec->vm(), propertyName, newValue, attributes & ~Accessor);
+ target->putDirect(vm, propertyName, newValue, attributes & ~Accessor);
if (attributes & ReadOnly)
- target->structure()->setContainsReadOnlyProperties();
+ target->structure(vm)->setContainsReadOnlyProperties();
return true;
}
attributes &= ~ReadOnly;
- GetterSetter* accessor = GetterSetter::create(exec);
+ GetterSetter* accessor = GetterSetter::create(vm);
if (descriptor.getterPresent())
- accessor->setGetter(exec->vm(), descriptor.getterObject());
+ accessor->setGetter(vm, descriptor.getterObject());
else if (oldDescriptor.getterPresent())
- accessor->setGetter(exec->vm(), oldDescriptor.getterObject());
+ accessor->setGetter(vm, oldDescriptor.getterObject());
if (descriptor.setterPresent())
- accessor->setSetter(exec->vm(), descriptor.setterObject());
+ accessor->setSetter(vm, descriptor.setterObject());
else if (oldDescriptor.setterPresent())
- accessor->setSetter(exec->vm(), oldDescriptor.setterObject());
+ accessor->setSetter(vm, oldDescriptor.setterObject());
target->putDirectAccessor(exec, propertyName, accessor, attributes | Accessor);
return true;
VM& m_vm;
};
-bool JSObject::defineOwnNonIndexProperty(ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor, bool throwException)
+bool JSObject::defineOwnNonIndexProperty(ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException)
{
// Track on the globaldata that we're in define property.
// Currently DefineOwnProperty uses delete to remove properties when they are being replaced
// If we have a new property we can just put it on normally
PropertyDescriptor current;
- if (!methodTable()->getOwnPropertyDescriptor(this, exec, propertyName, current)) {
+ if (!getOwnPropertyDescriptor(exec, propertyName, current)) {
// unless extensions are prevented!
if (!isExtensible()) {
if (throwException)
- throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to define property on object that is not extensible.")));
+ exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to define property on object that is not extensible.")));
return false;
}
PropertyDescriptor oldDescriptor;
if (!current.configurable()) {
if (descriptor.configurable()) {
if (throwException)
- throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to configurable attribute of unconfigurable property.")));
+ exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to configurable attribute of unconfigurable property.")));
return false;
}
if (descriptor.enumerablePresent() && descriptor.enumerable() != current.enumerable()) {
if (throwException)
- throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change enumerable attribute of unconfigurable property.")));
+ exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change enumerable attribute of unconfigurable property.")));
return false;
}
}
// A generic descriptor is simply changing the attributes of an existing property
if (descriptor.isGenericDescriptor()) {
if (!current.attributesEqual(descriptor)) {
- methodTable()->deleteProperty(this, exec, propertyName);
+ methodTable(exec->vm())->deleteProperty(this, exec, propertyName);
return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
}
return true;
if (descriptor.isDataDescriptor() != current.isDataDescriptor()) {
if (!current.configurable()) {
if (throwException)
- throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change access mechanism for an unconfigurable property.")));
+ exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change access mechanism for an unconfigurable property.")));
return false;
}
- methodTable()->deleteProperty(this, exec, propertyName);
+ methodTable(exec->vm())->deleteProperty(this, exec, propertyName);
return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
}
if (!current.configurable()) {
if (!current.writable() && descriptor.writable()) {
if (throwException)
- throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change writable attribute of unconfigurable property.")));
+ exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change writable attribute of unconfigurable property.")));
return false;
}
if (!current.writable()) {
if (descriptor.value() && !sameValue(exec, current.value(), descriptor.value())) {
if (throwException)
- throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change value of a readonly property.")));
+ exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change value of a readonly property.")));
return false;
}
}
}
if (current.attributesEqual(descriptor) && !descriptor.value())
return true;
- methodTable()->deleteProperty(this, exec, propertyName);
+ methodTable(exec->vm())->deleteProperty(this, exec, propertyName);
return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
}
if (!current.configurable()) {
if (descriptor.setterPresent() && !(current.setterPresent() && JSValue::strictEqual(exec, current.setter(), descriptor.setter()))) {
if (throwException)
- throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change the setter of an unconfigurable property.")));
+ exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change the setter of an unconfigurable property.")));
return false;
}
if (descriptor.getterPresent() && !(current.getterPresent() && JSValue::strictEqual(exec, current.getter(), descriptor.getter()))) {
if (throwException)
- throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change the getter of an unconfigurable property.")));
+ exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change the getter of an unconfigurable property.")));
+ return false;
+ }
+ if (current.attributes() & CustomAccessor) {
+ if (throwException)
+ exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change access mechanism for an unconfigurable property.")));
return false;
}
}
JSValue accessor = getDirect(exec->vm(), propertyName);
if (!accessor)
return false;
- GetterSetter* getterSetter = asGetterSetter(accessor);
+ GetterSetter* getterSetter;
+ if (accessor.isCustomGetterSetter())
+ getterSetter = GetterSetter::create(exec->vm());
+ else {
+ ASSERT(accessor.isGetterSetter());
+ getterSetter = asGetterSetter(accessor);
+ }
if (descriptor.setterPresent())
getterSetter->setSetter(exec->vm(), descriptor.setterObject());
if (descriptor.getterPresent())
getterSetter->setGetter(exec->vm(), descriptor.getterObject());
if (current.attributesEqual(descriptor))
return true;
- methodTable()->deleteProperty(this, exec, propertyName);
+ methodTable(exec->vm())->deleteProperty(this, exec, propertyName);
unsigned attrs = descriptor.attributesOverridingCurrent(current);
putDirectAccessor(exec, propertyName, getterSetter, attrs | Accessor);
return true;
}
-bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor, bool throwException)
+bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException)
{
// If it's an array index, then use the indexed property storage.
unsigned index = propertyName.asIndex();
return object->defineOwnNonIndexProperty(exec, propertyName, descriptor, throwException);
}
-bool JSObject::getOwnPropertySlotSlow(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+JSObject* throwTypeError(ExecState* exec, const String& message)
{
- unsigned i = propertyName.asIndex();
- if (i != PropertyName::NotAnIndex)
- return getOwnPropertySlotByIndex(this, exec, i, slot);
- return false;
+ return exec->vm().throwException(exec, createTypeError(exec, message));
}
-JSObject* throwTypeError(ExecState* exec, const String& message)
+void JSObject::shiftButterflyAfterFlattening(VM& vm, size_t outOfLineCapacityBefore, size_t outOfLineCapacityAfter)
{
- return throwError(exec, createTypeError(exec, message));
+ Butterfly* butterfly = this->butterfly();
+ size_t preCapacity = this->butterflyPreCapacity();
+ void* currentBase = butterfly->base(preCapacity, outOfLineCapacityAfter);
+ void* newBase = butterfly->base(preCapacity, outOfLineCapacityBefore);
+
+ memmove(newBase, currentBase, this->butterflyTotalSize());
+ setButterflyWithoutChangingStructure(vm, Butterfly::fromBase(newBase, preCapacity, outOfLineCapacityAfter));
}
} // namespace JSC