Ignore:
Timestamp:
Feb 16, 2011, 1:35:19 PM (14 years ago)
Author:
[email protected]
Message:

Bug 54524 - Allow JSObject to fully utilize cell's capacity for inline storage.

Reviewed by Geoff Garen.

Currently JSObject is both directly instantiated for regular JS objects, and
derived to implement subtypes. A consequence of this is that we need to ensure
that sufficient space from the cell is left unused and available for any data
members that will be introduced by subclasses of JSObject. By restructuring
the internal storage array out of JSObject we can increase the size in the
internal storage for regular objects.

Add classes JSFinalObject and JSNonFinalObject. JSNonFinalObject retains as
much additional capacity as is currently available to allow for data members
in subclasses. JSFinalObject utilizes all available space for internal storage,
and only allows construction through JSFinalObject::create().

Source/JavaScriptCore:

The additional storage made available in the JSObject means that we need no
longer rely on a union of the internal storage with a pointer to storage that
is only valid for external storage. This means we can go back to always having
a valid pointer to property storage, regardless of whether this is internal or
external. This simplifies some cases of access to the array from C code, and
significantly simplifies JIT access, since repatching no longer needs to be
able to change between a load of the storage pointer / a LEA of the internal
storage.

  • API/JSObjectRef.cpp:

(JSObjectMake):

  • assembler/ARMAssembler.h:
  • assembler/ARMv7Assembler.h:
  • assembler/AbstractMacroAssembler.h:

(JSC::AbstractMacroAssembler::repatchPointer):

  • assembler/MIPSAssembler.h:
  • assembler/MacroAssemblerARM.h:
  • assembler/MacroAssemblerARMv7.h:
  • assembler/MacroAssemblerMIPS.h:
  • assembler/MacroAssemblerX86.h:
  • assembler/MacroAssemblerX86_64.h:
  • assembler/RepatchBuffer.h:
  • assembler/X86Assembler.h:
  • debugger/DebuggerActivation.cpp:

(JSC::DebuggerActivation::DebuggerActivation):

  • debugger/DebuggerActivation.h:
  • interpreter/Interpreter.cpp:

(JSC::Interpreter::privateExecute):

  • jit/JIT.h:
  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_resolve_global):

  • jit/JITOpcodes32_64.cpp:

(JSC::JIT::emit_op_resolve_global):

  • jit/JITPropertyAccess.cpp:

(JSC::JIT::compileGetDirectOffset):
(JSC::JIT::emit_op_get_by_pname):
(JSC::JIT::compileGetByIdHotPath):
(JSC::JIT::emit_op_put_by_id):
(JSC::JIT::compilePutDirectOffset):
(JSC::JIT::patchGetByIdSelf):
(JSC::JIT::patchPutByIdReplace):
(JSC::JIT::privateCompileGetByIdProto):
(JSC::JIT::privateCompileGetByIdSelfList):
(JSC::JIT::privateCompileGetByIdProtoList):
(JSC::JIT::privateCompileGetByIdChainList):
(JSC::JIT::privateCompileGetByIdChain):

  • jit/JITPropertyAccess32_64.cpp:

(JSC::JIT::compileGetByIdHotPath):
(JSC::JIT::emit_op_put_by_id):
(JSC::JIT::compilePutDirectOffset):
(JSC::JIT::compileGetDirectOffset):
(JSC::JIT::patchGetByIdSelf):
(JSC::JIT::patchPutByIdReplace):
(JSC::JIT::privateCompileGetByIdProto):
(JSC::JIT::privateCompileGetByIdSelfList):
(JSC::JIT::privateCompileGetByIdProtoList):
(JSC::JIT::privateCompileGetByIdChainList):
(JSC::JIT::privateCompileGetByIdChain):
(JSC::JIT::emit_op_get_by_pname):

  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

  • runtime/Arguments.h:

(JSC::Arguments::Arguments):

  • runtime/ErrorInstance.cpp:

(JSC::ErrorInstance::ErrorInstance):

  • runtime/ErrorInstance.h:
  • runtime/ExceptionHelpers.cpp:

(JSC::InterruptedExecutionError::InterruptedExecutionError):
(JSC::TerminatedExecutionError::TerminatedExecutionError):

  • runtime/JSArray.cpp:

(JSC::JSArray::JSArray):

  • runtime/JSArray.h:
  • runtime/JSByteArray.cpp:

(JSC::JSByteArray::JSByteArray):

  • runtime/JSByteArray.h:

(JSC::JSByteArray::JSByteArray):

  • runtime/JSFunction.cpp:

(JSC::JSFunction::getOwnPropertySlot):

  • runtime/JSGlobalData.cpp:

(JSC::JSGlobalData::JSGlobalData):

  • runtime/JSGlobalObject.h:

(JSC::constructEmptyObject):

  • runtime/JSNotAnObject.h:

(JSC::JSNotAnObject::JSNotAnObject):

  • runtime/JSObject.cpp:

(JSC::JSObject::createInheritorID):
(JSC::JSObject::allocatePropertyStorage):

  • runtime/JSObject.h:

(JSC::JSObject::propertyStorage):
(JSC::JSNonFinalObject::JSNonFinalObject):
(JSC::JSNonFinalObject::createStructure):
(JSC::JSFinalObject::create):
(JSC::JSFinalObject::createStructure):
(JSC::JSFinalObject::JSFinalObject):
(JSC::JSObject::offsetOfInlineStorage):
(JSC::constructEmptyObject):
(JSC::createEmptyObjectStructure):
(JSC::JSObject::JSObject):
(JSC::JSObject::~JSObject):
(JSC::Structure::isUsingInlineStorage):

  • runtime/JSObjectWithGlobalObject.cpp:

(JSC::JSObjectWithGlobalObject::JSObjectWithGlobalObject):

  • runtime/JSObjectWithGlobalObject.h:

(JSC::JSObjectWithGlobalObject::JSObjectWithGlobalObject):

  • runtime/JSTypeInfo.h:

(JSC::TypeInfo::TypeInfo):
(JSC::TypeInfo::isVanilla):

  • runtime/JSVariableObject.h:

(JSC::JSVariableObject::JSVariableObject):

  • runtime/JSWrapperObject.h:

(JSC::JSWrapperObject::JSWrapperObject):

  • runtime/ObjectConstructor.cpp:

(JSC::constructObject):

  • runtime/ObjectPrototype.cpp:

(JSC::ObjectPrototype::ObjectPrototype):

  • runtime/ObjectPrototype.h:
  • runtime/StrictEvalActivation.cpp:

(JSC::StrictEvalActivation::StrictEvalActivation):

  • runtime/StrictEvalActivation.h:
  • runtime/Structure.cpp:

(JSC::Structure::Structure):
(JSC::Structure::growPropertyStorageCapacity):

Source/JavaScriptGlue:

  • UserObjectImp.cpp:
  • UserObjectImp.h:

Update JSObject -> JSNonFinalObject.

Source/WebCore:

  • bindings/js/JSDOMWindowShell.h:

Update JSObject -> JSNonFinalObject.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/JSObject.h

    r77269 r78732  
    8181
    8282    public:
    83         explicit JSObject(NonNullPassRefPtr<Structure>);
    84 
    8583        virtual void markChildren(MarkStack&);
    8684        ALWAYS_INLINE void markChildrenDirect(MarkStack& markStack);
     
    216214
    217215        void allocatePropertyStorage(size_t oldSize, size_t newSize);
    218         void allocatePropertyStorageInline(size_t oldSize, size_t newSize);
    219216        bool isUsingInlineStorage() const { return m_structure->isUsingInlineStorage(); }
    220217
    221         static const unsigned inlineStorageCapacity = sizeof(EncodedJSValue) == 2 * sizeof(void*) ? 4 : 3;
    222         static const unsigned nonInlineBaseStorageCapacity = 16;
    223 
    224         static PassRefPtr<Structure> createStructure(JSValue prototype)
    225         {
    226             return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
    227         }
     218        static const unsigned baseExternalStorageCapacity = 16;
    228219
    229220        void flattenDictionaryObject(JSGlobalData& globalData)
     
    247238            return locationForOffset(index)->get();
    248239        }
     240
     241        static size_t offsetOfInlineStorage();
    249242       
    250243    protected:
    251244        static const unsigned StructureFlags = 0;
    252        
     245
    253246        void putThisToAnonymousValue(unsigned index)
    254247        {
    255248            locationForOffset(index)->setWithoutWriteBarrier(this);
    256249        }
    257        
     250
     251        // To instantiate objects you likely want JSFinalObject, below.
     252        // To create derived types you likely want JSNonFinalObject, below.
     253        JSObject(NonNullPassRefPtr<Structure>, PropertyStorage inlineStorage);
     254
    258255    private:
    259256        // Nobody should ever ask any of these questions on something already known to be a JSObject.
     
    266263        void isString();
    267264       
    268         ConstPropertyStorage propertyStorage() const { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); }
    269         PropertyStorage propertyStorage() { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); }
     265        ConstPropertyStorage propertyStorage() const { return m_propertyStorage; }
     266        PropertyStorage propertyStorage() { return m_propertyStorage; }
    270267
    271268        const WriteBarrierBase<Unknown>* locationForOffset(size_t offset) const
     
    288285        Structure* createInheritorID();
    289286
    290         union {
    291             PropertyStorage m_externalStorage;
    292             WriteBarrierBase<Unknown> m_inlineStorage[inlineStorageCapacity];
    293         };
    294 
     287        PropertyStorage m_propertyStorage;
    295288        RefPtr<Structure> m_inheritorID;
    296289    };
    297    
     290
     291
     292#if USE(JSVALUE32_64)
     293#define JSNonFinalObject_inlineStorageCapacity 4
     294#define JSFinalObject_inlineStorageCapacity 6
     295#else
     296#define JSNonFinalObject_inlineStorageCapacity 2
     297#define JSFinalObject_inlineStorageCapacity 4
     298#endif
     299
     300COMPILE_ASSERT((JSFinalObject_inlineStorageCapacity >= JSNonFinalObject_inlineStorageCapacity), final_storage_is_at_least_as_large_as_non_final);
     301
     302    // JSNonFinalObject is a type of JSObject that has some internal storage,
     303    // but also preserves some space in the collector cell for additional
     304    // data members in derived types.
     305    class JSNonFinalObject : public JSObject {
     306        friend class JSObject;
     307
     308    public:
     309        explicit JSNonFinalObject(NonNullPassRefPtr<Structure> structure)
     310            : JSObject(structure, m_inlineStorage)
     311        {
     312            ASSERT(OBJECT_OFFSETOF(JSNonFinalObject, m_inlineStorage) % sizeof(double) == 0);
     313        }
     314
     315        static PassRefPtr<Structure> createStructure(JSValue prototype)
     316        {
     317            return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
     318        }
     319
     320    private:
     321        WriteBarrierBase<Unknown> m_inlineStorage[JSNonFinalObject_inlineStorageCapacity];
     322    };
     323
     324    // JSFinalObject is a type of JSObject that contains sufficent internal
     325    // storage to fully make use of the colloctor cell containing it.
     326    class JSFinalObject : public JSObject {
     327        friend class JSObject;
     328
     329    public:
     330        static JSFinalObject* create(ExecState* exec, NonNullPassRefPtr<Structure> structure)
     331        {
     332            return new (exec) JSFinalObject(structure);
     333        }
     334
     335        static PassRefPtr<Structure> createStructure(JSValue prototype)
     336        {
     337            return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
     338        }
     339
     340    private:
     341        explicit JSFinalObject(NonNullPassRefPtr<Structure> structure)
     342            : JSObject(structure, m_inlineStorage)
     343        {
     344            ASSERT(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) % sizeof(double) == 0);
     345        }
     346
     347        static const unsigned StructureFlags = JSObject::StructureFlags | IsJSFinalObject;
     348
     349        WriteBarrierBase<Unknown> m_inlineStorage[JSFinalObject_inlineStorageCapacity];
     350    };
     351
     352inline size_t JSObject::offsetOfInlineStorage()
     353{
     354    ASSERT(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) == OBJECT_OFFSETOF(JSNonFinalObject, m_inlineStorage));
     355    return OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage);
     356}
     357
     358inline JSObject* constructEmptyObject(ExecState* exec, NonNullPassRefPtr<Structure> structure)
     359{
     360    return JSFinalObject::create(exec, structure);
     361}
     362
     363inline PassRefPtr<Structure> createEmptyObjectStructure(JSValue prototype)
     364{
     365    return JSFinalObject::createStructure(prototype);
     366}
     367
    298368inline JSObject* asObject(JSCell* cell)
    299369{
     
    307377}
    308378
    309 inline JSObject::JSObject(NonNullPassRefPtr<Structure> structure)
     379inline JSObject::JSObject(NonNullPassRefPtr<Structure> structure, PropertyStorage inlineStorage)
    310380    : JSCell(structure.releaseRef()) // ~JSObject balances this ref()
    311 {
    312     ASSERT(m_structure->propertyStorageCapacity() == inlineStorageCapacity);
     381    , m_propertyStorage(inlineStorage)
     382{
     383    ASSERT(m_structure->propertyStorageCapacity() < baseExternalStorageCapacity);
    313384    ASSERT(m_structure->isEmpty());
    314385    ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
    315     ASSERT(OBJECT_OFFSETOF(JSObject, m_inlineStorage) % sizeof(double) == 0);
    316386}
    317387
     
    320390    ASSERT(m_structure);
    321391    if (!isUsingInlineStorage())
    322         delete [] m_externalStorage;
     392        delete [] m_propertyStorage;
    323393    m_structure->deref();
    324394}
     
    364434inline bool Structure::isUsingInlineStorage() const
    365435{
    366     return (propertyStorageCapacity() == JSObject::inlineStorageCapacity);
     436    return propertyStorageCapacity() < JSObject::baseExternalStorageCapacity;
    367437}
    368438
     
    728798}
    729799
    730 ALWAYS_INLINE void JSObject::allocatePropertyStorageInline(size_t oldSize, size_t newSize)
    731 {
    732     ASSERT(newSize > oldSize);
    733 
    734     // It's important that this function not rely on m_structure, since
    735     // we might be in the middle of a transition.
    736     bool wasInline = (oldSize == JSObject::inlineStorageCapacity);
    737 
    738     PropertyStorage oldPropertyStorage = (wasInline ? m_inlineStorage : m_externalStorage);
    739     PropertyStorage newPropertyStorage = new WriteBarrierBase<Unknown>[newSize];
    740 
    741     for (unsigned i = 0; i < oldSize; ++i)
    742        newPropertyStorage[i] = oldPropertyStorage[i];
    743 
    744     if (!wasInline)
    745         delete [] oldPropertyStorage;
    746 
    747     m_externalStorage = newPropertyStorage;
    748 }
    749 
    750800ALWAYS_INLINE void JSObject::markChildrenDirect(MarkStack& markStack)
    751801{
Note: See TracChangeset for help on using the changeset viewer.