+2012-05-16 Mark Hahnenberg <mhahnenberg@apple.com>
+
+ GC in the middle of JSObject::allocatePropertyStorage can cause badness
+ https://bugs.webkit.org/show_bug.cgi?id=83839
+
+ Reviewed by Geoff Garen.
+
+ * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
+ * jit/JITStubs.cpp: Making changes to use the new return value of growPropertyStorage.
+ (JSC::DEFINE_STUB_FUNCTION):
+ * runtime/JSObject.cpp:
+ (JSC::JSObject::growPropertyStorage): Renamed to more accurately reflect that we're
+ growing our already-existing PropertyStorage.
+ * runtime/JSObject.h:
+ (JSObject):
+ (JSC::JSObject::setPropertyStorage): "Atomically" sets the new property storage
+ and the new structure so that we can be sure a GC never occurs when our Structure
+ info is out of sync with our PropertyStorage.
+ (JSC):
+ (JSC::JSObject::putDirectInternal): Moved the check to see if we should
+ allocate more backing store before the actual property insertion into
+ the structure.
+ (JSC::JSObject::putDirectWithoutTransition): Ditto.
+ (JSC::JSObject::transitionTo): Ditto.
+ * runtime/Structure.cpp:
+ (JSC::Structure::suggestedNewPropertyStorageSize): Added to keep the resize policy
+ for property backing stores contained within the Structure class.
+ (JSC):
+ * runtime/Structure.h:
+ (JSC::Structure::shouldGrowPropertyStorage): Lets clients know if another insertion
+ into the Structure would require resizing the property backing store so that they can
+ preallocate the required storage.
+ (Structure):
+
2012-05-16 Geoffrey Garen <ggaren@apple.com>
GC is not thread-safe when moving values between C stacks
bool staticFunctionsReified() { return structure()->staticFunctionsReified(); }
void reifyStaticFunctionsForDelete(ExecState* exec);
- JS_EXPORT_PRIVATE void allocatePropertyStorage(JSGlobalData&, size_t oldSize, size_t newSize);
+ 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); }
+ void setPropertyStorage(JSGlobalData&, PropertyStorage, Structure*);
void* addressOfPropertyStorage()
{
return structure()->typeInfo().type() == GlobalThisType;
}
+inline void JSObject::setPropertyStorage(JSGlobalData& globalData, PropertyStorage storage, Structure* structure)
+{
+ ASSERT(storage);
+ ASSERT(structure);
+ setStructure(globalData, structure);
+ m_propertyStorage.set(globalData, this, storage);
+}
+
inline JSObject* constructEmptyObject(ExecState* exec, Structure* structure)
{
return JSFinalObject::create(exec, structure);
if ((mode == PutModePut) && !isExtensible())
return false;
- size_t currentCapacity = structure()->propertyStorageCapacity();
+ PropertyStorage newStorage = propertyStorage();
+ if (structure()->shouldGrowPropertyStorage())
+ newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), structure()->suggestedNewPropertyStorageSize());
offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, specificFunction);
- if (currentCapacity != structure()->propertyStorageCapacity())
- allocatePropertyStorage(globalData, currentCapacity, structure()->propertyStorageCapacity());
+ setPropertyStorage(globalData, newStorage, structure());
ASSERT(offset < structure()->propertyStorageCapacity());
putDirectOffset(globalData, offset, value);
size_t offset;
size_t currentCapacity = structure()->propertyStorageCapacity();
- if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName, attributes, specificFunction, offset)) {
+ if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName, attributes, specificFunction, offset)) {
+ PropertyStorage newStorage = propertyStorage();
if (currentCapacity != structure->propertyStorageCapacity())
- allocatePropertyStorage(globalData, currentCapacity, structure->propertyStorageCapacity());
+ newStorage = growPropertyStorage(globalData, currentCapacity, structure->propertyStorageCapacity());
ASSERT(offset < structure->propertyStorageCapacity());
- setStructure(globalData, structure);
+ setPropertyStorage(globalData, newStorage, 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.
if ((mode == PutModePut) && !isExtensible())
return false;
- Structure* structure = Structure::addPropertyTransition(globalData, this->structure(), propertyName, attributes, specificFunction, offset);
+ PropertyStorage newStorage = propertyStorage();
+ if (structure()->shouldGrowPropertyStorage())
+ newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), structure()->suggestedNewPropertyStorageSize());
- if (currentCapacity != structure->propertyStorageCapacity())
- allocatePropertyStorage(globalData, currentCapacity, structure->propertyStorageCapacity());
+ Structure* structure = Structure::addPropertyTransition(globalData, this->structure(), propertyName, attributes, specificFunction, offset);
ASSERT(offset < structure->propertyStorageCapacity());
- setStructure(globalData, structure);
+ setPropertyStorage(globalData, newStorage, 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.
inline void JSObject::putDirectWithoutTransition(JSGlobalData& globalData, PropertyName propertyName, JSValue value, unsigned attributes)
{
ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
- size_t currentCapacity = structure()->propertyStorageCapacity();
+ PropertyStorage newStorage = propertyStorage();
+ if (structure()->shouldGrowPropertyStorage())
+ newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), structure()->suggestedNewPropertyStorageSize());
size_t offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, getJSFunction(value));
- if (currentCapacity != structure()->propertyStorageCapacity())
- allocatePropertyStorage(globalData, currentCapacity, structure()->propertyStorageCapacity());
+ setPropertyStorage(globalData, newStorage, structure());
putDirectOffset(globalData, offset, value);
}
inline void JSObject::transitionTo(JSGlobalData& globalData, Structure* newStructure)
{
+ PropertyStorage newStorage = propertyStorage();
if (structure()->propertyStorageCapacity() != newStructure->propertyStorageCapacity())
- allocatePropertyStorage(globalData, structure()->propertyStorageCapacity(), newStructure->propertyStorageCapacity());
- setStructure(globalData, newStructure);
+ newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), newStructure->propertyStorageCapacity());
+ setPropertyStorage(globalData, newStorage, newStructure);
}
inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const