https://bugs.webkit.org/show_bug.cgi?id=90255
Reviewed by Mark Hahnenberg.
Rolling back in after applying a simple fix: it appears that
JSObject::setStructureAndReallocateStorageIfNecessary() was allocating more
property storage than necessary. Fixing this appears to resolve the crash.
This does a few things:
- JSNonFinalObject no longer has inline property storage.
- Initial out-of-line property storage size is 4 slots for JSNonFinalObject,
or 2x the inline storage for JSFinalObject.
- Property storage is only reallocated if it needs to be. Previously, we
would reallocate the property storage on any transition where the original
structure said shouldGrowProperyStorage(), but this led to spurious
reallocations when doing transitionless property adds and there are
deleted property slots available. That in turn led to crashes, because we
would switch to out-of-line storage even if the capacity matched the
criteria for inline storage.
- Inline JSFunction allocation is killed off because we don't have a good
way of inlining property storage allocation. This didn't hurt performance.
Killing off code is better than fixing it if that code wasn't doing any
good.
This looks like a 1% progression on V8.
* interpreter/Interpreter.cpp:
(JSC::Interpreter::privateExecute):
* jit/JIT.cpp:
(JSC::JIT::privateCompileSlowCases):
* jit/JIT.h:
* jit/JITInlineMethods.h:
(JSC::JIT::emitAllocateBasicJSObject):
(JSC):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_new_func):
(JSC):
(JSC::JIT::emit_op_new_func_exp):
* runtime/JSFunction.cpp:
(JSC::JSFunction::finishCreation):
* runtime/JSObject.h:
(JSC::JSObject::isUsingInlineStorage):
(JSObject):
(JSC::JSObject::finishCreation):
(JSC):
(JSC::JSNonFinalObject::hasInlineStorage):
(JSNonFinalObject):
(JSC::JSNonFinalObject::JSNonFinalObject):
(JSC::JSNonFinalObject::finishCreation):
(JSC::JSFinalObject::hasInlineStorage):
(JSC::JSFinalObject::finishCreation):
(JSC::JSObject::offsetOfInlineStorage):
(JSC::JSObject::setPropertyStorage):
(JSC::Structure::inlineStorageCapacity):
(JSC::Structure::isUsingInlineStorage):
(JSC::JSObject::putDirectInternal):
(JSC::JSObject::setStructureAndReallocateStorageIfNecessary):
(JSC::JSObject::putDirectWithoutTransition):
* runtime/Structure.cpp:
(JSC::Structure::Structure):
(JSC::nextPropertyStorageCapacity):
(JSC):
(JSC::Structure::growPropertyStorageCapacity):
(JSC::Structure::suggestedNewPropertyStorageSize):
* runtime/Structure.h:
(JSC::Structure::putWillGrowPropertyStorage):
(Structure):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@121633
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
2012-06-29 Filip Pizlo <fpizlo@apple.com>
+ JSObject wastes too much memory on unused property slots
+ https://bugs.webkit.org/show_bug.cgi?id=90255
+
+ Reviewed by Mark Hahnenberg.
+
+ Rolling back in after applying a simple fix: it appears that
+ JSObject::setStructureAndReallocateStorageIfNecessary() was allocating more
+ property storage than necessary. Fixing this appears to resolve the crash.
+
+ This does a few things:
+
+ - JSNonFinalObject no longer has inline property storage.
+
+ - Initial out-of-line property storage size is 4 slots for JSNonFinalObject,
+ or 2x the inline storage for JSFinalObject.
+
+ - Property storage is only reallocated if it needs to be. Previously, we
+ would reallocate the property storage on any transition where the original
+ structure said shouldGrowProperyStorage(), but this led to spurious
+ reallocations when doing transitionless property adds and there are
+ deleted property slots available. That in turn led to crashes, because we
+ would switch to out-of-line storage even if the capacity matched the
+ criteria for inline storage.
+
+ - Inline JSFunction allocation is killed off because we don't have a good
+ way of inlining property storage allocation. This didn't hurt performance.
+ Killing off code is better than fixing it if that code wasn't doing any
+ good.
+
+ This looks like a 1% progression on V8.
+
+ * interpreter/Interpreter.cpp:
+ (JSC::Interpreter::privateExecute):
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompileSlowCases):
+ * jit/JIT.h:
+ * jit/JITInlineMethods.h:
+ (JSC::JIT::emitAllocateBasicJSObject):
+ (JSC):
+ * jit/JITOpcodes.cpp:
+ (JSC::JIT::emit_op_new_func):
+ (JSC):
+ (JSC::JIT::emit_op_new_func_exp):
+ * runtime/JSFunction.cpp:
+ (JSC::JSFunction::finishCreation):
+ * runtime/JSObject.h:
+ (JSC::JSObject::isUsingInlineStorage):
+ (JSObject):
+ (JSC::JSObject::finishCreation):
+ (JSC):
+ (JSC::JSNonFinalObject::hasInlineStorage):
+ (JSNonFinalObject):
+ (JSC::JSNonFinalObject::JSNonFinalObject):
+ (JSC::JSNonFinalObject::finishCreation):
+ (JSC::JSFinalObject::hasInlineStorage):
+ (JSC::JSFinalObject::finishCreation):
+ (JSC::JSObject::offsetOfInlineStorage):
+ (JSC::JSObject::setPropertyStorage):
+ (JSC::Structure::inlineStorageCapacity):
+ (JSC::Structure::isUsingInlineStorage):
+ (JSC::JSObject::putDirectInternal):
+ (JSC::JSObject::setStructureAndReallocateStorageIfNecessary):
+ (JSC::JSObject::putDirectWithoutTransition):
+ * runtime/Structure.cpp:
+ (JSC::Structure::Structure):
+ (JSC::nextPropertyStorageCapacity):
+ (JSC):
+ (JSC::Structure::growPropertyStorageCapacity):
+ (JSC::Structure::suggestedNewPropertyStorageSize):
+ * runtime/Structure.h:
+ (JSC::Structure::putWillGrowPropertyStorage):
+ (Structure):
+
+2012-06-29 Filip Pizlo <fpizlo@apple.com>
+
Webkit crashes in DFG on Google Docs when creating a new document
https://bugs.webkit.org/show_bug.cgi?id=90209
/*
- * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009, 2010, 2012 Apple Inc. All rights reserved.
* Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
*
* Redistribution and use in source and binary forms, with or without
proto = asObject(proto)->structure()->prototypeForLookup(callFrame);
}
}
- baseObject->transitionTo(*globalData, newStructure);
+ baseObject->setStructureAndReallocateStorageIfNecessary(*globalData, newStructure);
int value = vPC[3].u.operand;
unsigned offset = vPC[7].u.operand;
/*
- * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009, 2012 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
DEFINE_SLOWCASE_OP(op_neq)
DEFINE_SLOWCASE_OP(op_new_array)
DEFINE_SLOWCASE_OP(op_new_object)
- DEFINE_SLOWCASE_OP(op_new_func)
- DEFINE_SLOWCASE_OP(op_new_func_exp)
DEFINE_SLOWCASE_OP(op_not)
DEFINE_SLOWCASE_OP(op_nstricteq)
DEFINE_SLOWCASE_OP(op_post_dec)
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2012 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
template<typename ClassType, bool destructor, typename StructureType> void emitAllocateBasicJSObject(StructureType, RegisterID result, RegisterID storagePtr);
void emitAllocateBasicStorage(size_t, RegisterID result, RegisterID storagePtr);
template<typename T> void emitAllocateJSFinalObject(T structure, RegisterID result, RegisterID storagePtr);
- void emitAllocateJSFunction(FunctionExecutable*, RegisterID scopeChain, RegisterID result, RegisterID storagePtr);
void emitAllocateJSArray(unsigned valuesRegister, unsigned length, RegisterID cellResult, RegisterID storageResult, RegisterID storagePtr);
#if ENABLE(VALUE_PROFILER)
void emitSlow_op_to_jsnumber(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_to_primitive(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_urshift(Instruction*, Vector<SlowCaseEntry>::iterator&);
- void emitSlow_op_new_func(Instruction*, Vector<SlowCaseEntry>::iterator&);
- void emitSlow_op_new_func_exp(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_new_array(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitRightShift(Instruction*, bool isUnsigned);
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2012 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
storePtr(TrustedImmPtr(0), Address(result, JSObject::offsetOfInheritorID()));
// initialize the object's property storage pointer
- addPtr(TrustedImm32(sizeof(JSObject)), result, storagePtr);
- storePtr(storagePtr, Address(result, ClassType::offsetOfPropertyStorage()));
+ if (ClassType::hasInlineStorage()) {
+ addPtr(TrustedImm32(sizeof(JSObject)), result, storagePtr);
+ storePtr(storagePtr, Address(result, ClassType::offsetOfPropertyStorage()));
+ } else
+ storePtr(TrustedImmPtr(0), Address(result, ClassType::offsetOfPropertyStorage()));
}
template <typename T> inline void JIT::emitAllocateJSFinalObject(T structure, RegisterID result, RegisterID scratch)
emitAllocateBasicJSObject<JSFinalObject, false, T>(structure, result, scratch);
}
-inline void JIT::emitAllocateJSFunction(FunctionExecutable* executable, RegisterID scopeChain, RegisterID result, RegisterID storagePtr)
-{
- emitAllocateBasicJSObject<JSFunction, true>(TrustedImmPtr(m_codeBlock->globalObject()->namedFunctionStructure()), result, storagePtr);
-
- // store the function's scope chain
- storePtr(scopeChain, Address(result, JSFunction::offsetOfScopeChain()));
-
- // store the function's executable member
- storePtr(TrustedImmPtr(executable), Address(result, JSFunction::offsetOfExecutable()));
-
- // clear the function's inheritorID
- storePtr(TrustedImmPtr(0), Address(result, JSFunction::offsetOfCachedInheritorID()));
-
- // store the function's name
- ASSERT(executable->nameValue());
- int functionNameOffset = sizeof(JSValue) * m_codeBlock->globalObject()->functionNameOffset();
- storePtr(TrustedImmPtr(executable->nameValue()), Address(regT1, functionNameOffset + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
-#if USE(JSVALUE32_64)
- store32(TrustedImm32(JSValue::CellTag), Address(regT1, functionNameOffset + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
-#endif
-}
-
inline void JIT::emitAllocateBasicStorage(size_t size, RegisterID result, RegisterID storagePtr)
{
CopiedAllocator* allocator = &m_globalData->heap.storageAllocator();
/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2012 Apple Inc. All rights reserved.
* Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
*
* Redistribution and use in source and binary forms, with or without
#endif
}
- FunctionExecutable* executable = m_codeBlock->functionDecl(currentInstruction[2].u.operand);
- emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT2);
- emitAllocateJSFunction(executable, regT2, regT0, regT1);
-
- emitStoreCell(dst, regT0);
+ JITStubCall stubCall(this, cti_op_new_func);
+ stubCall.addArgument(TrustedImmPtr(m_codeBlock->functionDecl(currentInstruction[2].u.operand)));
+ stubCall.call(dst);
if (currentInstruction[3].u.operand) {
#if USE(JSVALUE32_64)
}
}
-void JIT::emitSlow_op_new_func(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
-{
- linkSlowCase(iter);
- JITStubCall stubCall(this, cti_op_new_func);
- stubCall.addArgument(TrustedImmPtr(m_codeBlock->functionDecl(currentInstruction[2].u.operand)));
- stubCall.call(currentInstruction[1].u.operand);
-}
-
void JIT::emit_op_new_func_exp(Instruction* currentInstruction)
{
- FunctionExecutable* executable = m_codeBlock->functionExpr(currentInstruction[2].u.operand);
-
- // We only inline the allocation of a anonymous function expressions
- // If we want to be able to allocate a named function expression, we would
- // need to be able to do inline allocation of a JSStaticScopeObject.
- if (executable->name().isNull()) {
- emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT2);
- emitAllocateJSFunction(executable, regT2, regT0, regT1);
- emitStoreCell(currentInstruction[1].u.operand, regT0);
- return;
- }
-
JITStubCall stubCall(this, cti_op_new_func_exp);
stubCall.addArgument(TrustedImmPtr(m_codeBlock->functionExpr(currentInstruction[2].u.operand)));
stubCall.call(currentInstruction[1].u.operand);
}
-void JIT::emitSlow_op_new_func_exp(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
-{
- FunctionExecutable* executable = m_codeBlock->functionExpr(currentInstruction[2].u.operand);
- if (!executable->name().isNull())
- return;
- linkSlowCase(iter);
- JITStubCall stubCall(this, cti_op_new_func_exp);
- stubCall.addArgument(TrustedImmPtr(executable));
- stubCall.call(currentInstruction[1].u.operand);
-}
-
void JIT::emit_op_new_array(Instruction* currentInstruction)
{
int length = currentInstruction[3].u.operand;
void JSFunction::finishCreation(ExecState* exec, FunctionExecutable* executable, ScopeChainNode* scopeChainNode)
{
- Base::finishCreation(exec->globalData());
+ JSGlobalData& globalData = exec->globalData();
+ Base::finishCreation(globalData);
ASSERT(inherits(&s_info));
// Switching the structure here is only safe if we currently have the function structure!
ASSERT(structure() == scopeChainNode->globalObject->functionStructure());
- setStructure(exec->globalData(), scopeChainNode->globalObject->namedFunctionStructure());
- putDirectOffset(exec->globalData(), scopeChainNode->globalObject->functionNameOffset(), executable->nameValue());
+ setStructureAndReallocateStorageIfNecessary(
+ globalData,
+ scopeChainNode->globalObject->namedFunctionStructure());
+ putDirectOffset(globalData, scopeChainNode->globalObject->functionNameOffset(), executable->nameValue());
}
Structure* JSFunction::cacheInheritorID(ExecState* exec)
Accessor = 1 << 5, // property is a getter/setter
};
+#if USE(JSVALUE32_64)
+#define JSFinalObject_inlineStorageCapacity 6
+#else
+#define JSFinalObject_inlineStorageCapacity 4
+#endif
+
+COMPILE_ASSERT((JSFinalObject_inlineStorageCapacity >= 0), final_storage_non_negative);
+
class JSObject : public JSCell {
friend class BatchedTransitionOptimizer;
friend class JIT;
void reifyStaticFunctionsForDelete(ExecState* exec);
JS_EXPORT_PRIVATE PropertyStorage growPropertyStorage(JSGlobalData&, size_t oldSize, size_t newSize);
- bool isUsingInlineStorage() const { return static_cast<const void*>(m_propertyStorage.get()) == static_cast<const void*>(this + 1); }
+ bool isUsingInlineStorage() const
+ {
+ bool result =
+ !m_propertyStorage.get()
+ || static_cast<const void*>(m_propertyStorage.get()) == static_cast<const void*>(this + 1);
+ ASSERT(result == structure()->isUsingInlineStorage());
+ return result;
+ }
void setPropertyStorage(JSGlobalData&, PropertyStorage, Structure*);
+
+ bool reallocateStorageIfNecessary(JSGlobalData&, unsigned oldCapacity, Structure*);
+ void setStructureAndReallocateStorageIfNecessary(JSGlobalData&, unsigned oldCapacity, Structure*);
+ void setStructureAndReallocateStorageIfNecessary(JSGlobalData&, Structure*);
void* addressOfPropertyStorage()
{
return &m_propertyStorage;
}
- static const unsigned baseExternalStorageCapacity = 16;
-
void flattenDictionaryObject(JSGlobalData& globalData)
{
structure()->flattenDictionaryStructure(globalData, this);
static JS_EXPORTDATA const ClassInfo s_info;
protected:
- void finishCreation(JSGlobalData& globalData, PropertyStorage inlineStorage)
+ void finishCreation(JSGlobalData& globalData)
{
Base::finishCreation(globalData);
ASSERT(inherits(&s_info));
- ASSERT(structure()->propertyStorageCapacity() < baseExternalStorageCapacity);
+ ASSERT(structure()->isUsingInlineStorage());
ASSERT(structure()->isEmpty());
ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
- ASSERT_UNUSED(inlineStorage, static_cast<void*>(inlineStorage) == static_cast<void*>(this + 1));
ASSERT(structure()->isObject());
ASSERT(classInfo());
}
};
-#if USE(JSVALUE32_64)
-#define JSNonFinalObject_inlineStorageCapacity 4
-#define JSFinalObject_inlineStorageCapacity 6
-#else
-#define JSNonFinalObject_inlineStorageCapacity 2
-#define JSFinalObject_inlineStorageCapacity 4
-#endif
-
-COMPILE_ASSERT((JSFinalObject_inlineStorageCapacity >= JSNonFinalObject_inlineStorageCapacity), final_storage_is_at_least_as_large_as_non_final);
-
// JSNonFinalObject is a type of JSObject that has some internal storage,
// but also preserves some space in the collector cell for additional
// data members in derived types.
return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
}
+ static bool hasInlineStorage()
+ {
+ return false;
+ }
+
protected:
explicit JSNonFinalObject(JSGlobalData& globalData, Structure* structure)
- : JSObject(globalData, structure, m_inlineStorage)
+ : JSObject(globalData, structure, 0)
{
}
void finishCreation(JSGlobalData& globalData)
{
- Base::finishCreation(globalData, m_inlineStorage);
- ASSERT(!(OBJECT_OFFSETOF(JSNonFinalObject, m_inlineStorage) % sizeof(double)));
- ASSERT(this->structure()->propertyStorageCapacity() == JSNonFinalObject_inlineStorageCapacity);
+ Base::finishCreation(globalData);
+ ASSERT(!this->structure()->propertyStorageCapacity());
ASSERT(classInfo());
}
-
- private:
- WriteBarrier<Unknown> m_inlineStorage[JSNonFinalObject_inlineStorageCapacity];
};
class JSFinalObject;
static JS_EXPORTDATA const ClassInfo s_info;
+ static bool hasInlineStorage()
+ {
+ return true;
+ }
protected:
void finishCreation(JSGlobalData& globalData)
{
- Base::finishCreation(globalData, m_inlineStorage);
+ Base::finishCreation(globalData);
ASSERT(!(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) % sizeof(double)));
ASSERT(this->structure()->propertyStorageCapacity() == JSFinalObject_inlineStorageCapacity);
ASSERT(classInfo());
inline size_t JSObject::offsetOfInlineStorage()
{
- ASSERT(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) == OBJECT_OFFSETOF(JSNonFinalObject, m_inlineStorage));
return OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage);
}
{
ASSERT(storage);
ASSERT(structure);
+ ASSERT(!structure->isUsingInlineStorage()
+ || (classInfo() == &JSFinalObject::s_info && static_cast<void*>(storage) == static_cast<void*>(this + 1)));
setStructure(globalData, structure);
m_propertyStorage.set(globalData, this, storage);
}
return createInheritorID(globalData);
}
+inline size_t Structure::inlineStorageCapacity() const
+{
+ if (classInfo() == &JSFinalObject::s_info)
+ return JSFinalObject_inlineStorageCapacity;
+ return 0;
+}
+
inline bool Structure::isUsingInlineStorage() const
{
- return propertyStorageCapacity() < JSObject::baseExternalStorageCapacity;
+ ASSERT(propertyStorageCapacity() >= inlineStorageCapacity());
+ return propertyStorageCapacity() == inlineStorageCapacity();
}
inline bool JSCell::inherits(const ClassInfo* info) const
return false;
PropertyStorage newStorage = propertyStorage();
- if (structure()->shouldGrowPropertyStorage())
+ if (structure()->putWillGrowPropertyStorage())
newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), structure()->suggestedNewPropertyStorageSize());
offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, specificFunction);
setPropertyStorage(globalData, newStorage, structure());
if ((mode == PutModePut) && !isExtensible())
return false;
- PropertyStorage newStorage = propertyStorage();
- if (structure()->shouldGrowPropertyStorage())
- newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), structure()->suggestedNewPropertyStorageSize());
-
Structure* structure = Structure::addPropertyTransition(globalData, this->structure(), propertyName, attributes, specificFunction, offset);
-
+
ASSERT(offset < structure->propertyStorageCapacity());
- setPropertyStorage(globalData, newStorage, structure);
+ setStructureAndReallocateStorageIfNecessary(globalData, structure);
+
putDirectOffset(globalData, offset, value);
// This is a new property; transitions with specific values are not currently cachable,
// so leave the slot in an uncachable state.
return true;
}
+inline void JSObject::setStructureAndReallocateStorageIfNecessary(JSGlobalData& globalData, unsigned oldCapacity, Structure* newStructure)
+{
+ ASSERT(oldCapacity <= newStructure->propertyStorageCapacity());
+
+ if (oldCapacity == newStructure->propertyStorageCapacity()) {
+ setStructure(globalData, newStructure);
+ return;
+ }
+
+ PropertyStorage newStorage = growPropertyStorage(
+ globalData, oldCapacity, newStructure->propertyStorageCapacity());
+ setPropertyStorage(globalData, newStorage, newStructure);
+}
+
+inline void JSObject::setStructureAndReallocateStorageIfNecessary(JSGlobalData& globalData, Structure* newStructure)
+{
+ setStructureAndReallocateStorageIfNecessary(
+ globalData, structure()->propertyStorageCapacity(), newStructure);
+}
+
inline bool JSObject::putOwnDataProperty(JSGlobalData& globalData, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
{
ASSERT(value);
{
ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
PropertyStorage newStorage = propertyStorage();
- if (structure()->shouldGrowPropertyStorage())
+ if (structure()->putWillGrowPropertyStorage())
newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), structure()->suggestedNewPropertyStorageSize());
size_t offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, getCallableObject(value));
setPropertyStorage(globalData, newStorage, structure());
putDirectOffset(globalData, offset, value);
}
-inline void JSObject::transitionTo(JSGlobalData& globalData, Structure* newStructure)
-{
- PropertyStorage newStorage = propertyStorage();
- if (structure()->propertyStorageCapacity() != newStructure->propertyStorageCapacity())
- newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), newStructure->propertyStorageCapacity());
- setPropertyStorage(globalData, newStorage, newStructure);
-}
-
inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
{
return methodTable()->defaultValue(this, exec, preferredType);
, m_prototype(globalData, this, prototype)
, m_classInfo(classInfo)
, m_transitionWatchpointSet(InitializedWatching)
- , m_propertyStorageCapacity(typeInfo.isFinalObject() ? JSFinalObject_inlineStorageCapacity : JSNonFinalObject_inlineStorageCapacity)
+ , m_propertyStorageCapacity(typeInfo.isFinalObject() ? JSFinalObject_inlineStorageCapacity : 0)
, m_offset(noOffset)
, m_dictionaryKind(NoneDictionaryKind)
, m_isPinnedPropertyTable(false)
}
}
+inline size_t nextPropertyStorageCapacity(size_t currentCapacity)
+{
+ if (!currentCapacity)
+ return 4;
+ return currentCapacity * 2;
+}
+
void Structure::growPropertyStorageCapacity()
{
- if (isUsingInlineStorage())
- m_propertyStorageCapacity = JSObject::baseExternalStorageCapacity;
- else
- m_propertyStorageCapacity *= 2;
+ m_propertyStorageCapacity = nextPropertyStorageCapacity(m_propertyStorageCapacity);
}
size_t Structure::suggestedNewPropertyStorageSize()
{
- if (isUsingInlineStorage())
- return JSObject::baseExternalStorageCapacity;
- return m_propertyStorageCapacity * 2;
+ return nextPropertyStorageCapacity(m_propertyStorageCapacity);
}
void Structure::despecifyDictionaryFunction(JSGlobalData& globalData, PropertyName propertyName)
/*
- * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009, 2012 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
bool isFrozen(JSGlobalData&);
bool isExtensible() const { return !m_preventExtensions; }
bool didTransition() const { return m_didTransition; }
- bool shouldGrowPropertyStorage() { return propertyStorageCapacity() == propertyStorageSize(); }
+ bool putWillGrowPropertyStorage()
+ {
+ ASSERT(propertyStorageCapacity() >= propertyStorageSize());
+
+ if (!m_propertyTable) {
+ unsigned currentSize = static_cast<unsigned>(m_offset + 1);
+ ASSERT(propertyStorageCapacity() >= currentSize);
+ return currentSize == propertyStorageCapacity();
+ }
+
+ ASSERT(propertyStorageCapacity() >= m_propertyTable->propertyStorageSize());
+ if (m_propertyTable->hasDeletedOffset())
+ return false;
+
+ ASSERT(propertyStorageCapacity() >= m_propertyTable->size());
+ return m_propertyTable->size() == propertyStorageCapacity();
+ }
JS_EXPORT_PRIVATE size_t suggestedNewPropertyStorageSize();
Structure* flattenDictionaryStructure(JSGlobalData&, JSObject*);
void growPropertyStorageCapacity();
unsigned propertyStorageCapacity() const { ASSERT(structure()->classInfo() == &s_info); return m_propertyStorageCapacity; }
unsigned propertyStorageSize() const { ASSERT(structure()->classInfo() == &s_info); return (m_propertyTable ? m_propertyTable->propertyStorageSize() : static_cast<unsigned>(m_offset + 1)); }
+ size_t inlineStorageCapacity() const;
bool isUsingInlineStorage() const;
size_t get(JSGlobalData&, PropertyName);