Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (121604 => 121605)
--- trunk/Source/_javascript_Core/ChangeLog 2012-06-30 00:20:21 UTC (rev 121604)
+++ trunk/Source/_javascript_Core/ChangeLog 2012-06-30 00:25:01 UTC (rev 121605)
@@ -1,3 +1,74 @@
+2012-06-29 Filip Pizlo <[email protected]>
+
+ JSObject wastes too much memory on unused property slots
+ https://bugs.webkit.org/show_bug.cgi?id=90255
+
+ Reviewed by Mark Hahnenberg.
+
+ 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-28 Filip Pizlo <[email protected]>
DFG recompilation heuristics should be based on count, not rate
Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.cpp (121604 => 121605)
--- trunk/Source/_javascript_Core/interpreter/Interpreter.cpp 2012-06-30 00:20:21 UTC (rev 121604)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.cpp 2012-06-30 00:25:01 UTC (rev 121605)
@@ -1,5 +1,5 @@
/*
- * 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 <[email protected]>
*
* Redistribution and use in source and binary forms, with or without
@@ -3602,7 +3602,7 @@
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;
Modified: trunk/Source/_javascript_Core/jit/JIT.cpp (121604 => 121605)
--- trunk/Source/_javascript_Core/jit/JIT.cpp 2012-06-30 00:20:21 UTC (rev 121604)
+++ trunk/Source/_javascript_Core/jit/JIT.cpp 2012-06-30 00:25:01 UTC (rev 121605)
@@ -1,5 +1,5 @@
/*
- * 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
@@ -472,8 +472,6 @@
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)
Modified: trunk/Source/_javascript_Core/jit/JIT.h (121604 => 121605)
--- trunk/Source/_javascript_Core/jit/JIT.h 2012-06-30 00:20:21 UTC (rev 121604)
+++ trunk/Source/_javascript_Core/jit/JIT.h 2012-06-30 00:25:01 UTC (rev 121605)
@@ -1,5 +1,5 @@
/*
- * 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
@@ -423,7 +423,6 @@
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)
@@ -750,8 +749,6 @@
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);
Modified: trunk/Source/_javascript_Core/jit/JITInlineMethods.h (121604 => 121605)
--- trunk/Source/_javascript_Core/jit/JITInlineMethods.h 2012-06-30 00:20:21 UTC (rev 121604)
+++ trunk/Source/_javascript_Core/jit/JITInlineMethods.h 2012-06-30 00:25:01 UTC (rev 121605)
@@ -1,5 +1,5 @@
/*
- * 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
@@ -429,8 +429,11 @@
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)
@@ -438,28 +441,6 @@
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();
Modified: trunk/Source/_javascript_Core/jit/JITOpcodes.cpp (121604 => 121605)
--- trunk/Source/_javascript_Core/jit/JITOpcodes.cpp 2012-06-30 00:20:21 UTC (rev 121604)
+++ trunk/Source/_javascript_Core/jit/JITOpcodes.cpp 2012-06-30 00:25:01 UTC (rev 121605)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2012 Apple Inc. All rights reserved.
* Copyright (C) 2010 Patrick Gansterer <[email protected]>
*
* Redistribution and use in source and binary forms, with or without
@@ -1618,12 +1618,10 @@
#endif
}
- FunctionExecutable* executable = m_codeBlock->functionDecl(currentInstruction[2].u.operand);
- emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT2);
- emitAllocateJSFunction(executable, regT2, regT0, regT1);
+ JITStubCall stubCall(this, cti_op_new_func);
+ stubCall.addArgument(TrustedImmPtr(m_codeBlock->functionDecl(currentInstruction[2].u.operand)));
+ stubCall.call(dst);
- emitStoreCell(dst, regT0);
-
if (currentInstruction[3].u.operand) {
#if USE(JSVALUE32_64)
unmap();
@@ -1634,44 +1632,13 @@
}
}
-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;
Modified: trunk/Source/_javascript_Core/runtime/JSFunction.cpp (121604 => 121605)
--- trunk/Source/_javascript_Core/runtime/JSFunction.cpp 2012-06-30 00:20:21 UTC (rev 121604)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.cpp 2012-06-30 00:25:01 UTC (rev 121605)
@@ -103,13 +103,16 @@
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)
Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (121604 => 121605)
--- trunk/Source/_javascript_Core/runtime/JSObject.h 2012-06-30 00:20:21 UTC (rev 121604)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h 2012-06-30 00:25:01 UTC (rev 121605)
@@ -79,6 +79,14 @@
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;
@@ -221,16 +229,25 @@
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);
@@ -250,14 +267,13 @@
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());
}
@@ -316,16 +332,6 @@
};
-#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.
@@ -340,22 +346,23 @@
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;
@@ -376,10 +383,14 @@
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());
@@ -417,7 +428,6 @@
inline size_t JSObject::offsetOfInlineStorage()
{
- ASSERT(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) == OBJECT_OFFSETOF(JSNonFinalObject, m_inlineStorage));
return OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage);
}
@@ -465,6 +475,8 @@
{
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);
}
@@ -530,9 +542,17 @@
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
@@ -681,7 +701,7 @@
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());
@@ -746,14 +766,11 @@
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());
+ setStructureAndReallocateStorageIfNecessary(globalData, structure);
- ASSERT(offset < structure->propertyStorageCapacity());
- 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.
@@ -762,6 +779,26 @@
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->suggestedNewPropertyStorageSize());
+ 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);
@@ -788,21 +825,13 @@
{
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);
Modified: trunk/Source/_javascript_Core/runtime/Structure.cpp (121604 => 121605)
--- trunk/Source/_javascript_Core/runtime/Structure.cpp 2012-06-30 00:20:21 UTC (rev 121604)
+++ trunk/Source/_javascript_Core/runtime/Structure.cpp 2012-06-30 00:25:01 UTC (rev 121605)
@@ -156,7 +156,7 @@
, 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)
@@ -256,19 +256,21 @@
}
}
+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)
Modified: trunk/Source/_javascript_Core/runtime/Structure.h (121604 => 121605)
--- trunk/Source/_javascript_Core/runtime/Structure.h 2012-06-30 00:20:21 UTC (rev 121604)
+++ trunk/Source/_javascript_Core/runtime/Structure.h 2012-06-30 00:25:01 UTC (rev 121605)
@@ -1,5 +1,5 @@
/*
- * 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
@@ -103,7 +103,23 @@
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*);
@@ -139,6 +155,7 @@
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);