Changeset 91199 in webkit


Ignore:
Timestamp:
Jul 18, 2011 11:55:48 AM (13 years ago)
Author:
commit-queue@webkit.org
Message:

JSC JIT does not inline GC allocation fast paths
https://bugs.webkit.org/show_bug.cgi?id=64582

Patch by Filip Pizlo <fpizlo@apple.com> on 2011-07-18
Reviewed by Oliver Hunt.

This addresses inlining allocation for the easiest-to-allocate cases:
op_new_object and op_create_this. Inlining GC allocation fast paths
required three changes. First, the JSGlobalData now saves the vtable
pointer of JSFinalObject, since that's what op_new_object and
op_create_this allocate. Second, the Heap exposes a reference to
the appropriate SizeClass, so that the JIT may inline accesses
directly to the SizeClass for JSFinalObject allocations. And third,
the JIT is extended with code to emit inline fast paths for GC
allocation. A stub call is emitted in the case where the inline fast
path fails.

  • heap/Heap.h:

(JSC::Heap::sizeClassFor):
(JSC::Heap::allocate):

  • jit/JIT.cpp:

(JSC::JIT::privateCompileSlowCases):

  • jit/JIT.h:
  • jit/JITInlineMethods.h:

(JSC::JIT::emitAllocateJSFinalObject):

  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_new_object):
(JSC::JIT::emitSlow_op_new_object):
(JSC::JIT::emit_op_create_this):
(JSC::JIT::emitSlow_op_create_this):

  • jit/JITOpcodes32_64.cpp:

(JSC::JIT::emit_op_new_object):
(JSC::JIT::emitSlow_op_new_object):
(JSC::JIT::emit_op_create_this):
(JSC::JIT::emitSlow_op_create_this):

  • runtime/JSGlobalData.cpp:

(JSC::JSGlobalData::storeVPtrs):

  • runtime/JSGlobalData.h:
  • runtime/JSObject.h:

(JSC::JSFinalObject::JSFinalObject):
(JSC::JSObject::offsetOfInheritorID):

Location:
trunk/Source/JavaScriptCore
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r91194 r91199  
     12011-07-18  Filip Pizlo  <fpizlo@apple.com>
     2
     3        JSC JIT does not inline GC allocation fast paths
     4        https://bugs.webkit.org/show_bug.cgi?id=64582
     5
     6        Reviewed by Oliver Hunt.
     7
     8        This addresses inlining allocation for the easiest-to-allocate cases:
     9        op_new_object and op_create_this.  Inlining GC allocation fast paths
     10        required three changes.  First, the JSGlobalData now saves the vtable
     11        pointer of JSFinalObject, since that's what op_new_object and
     12        op_create_this allocate.  Second, the Heap exposes a reference to
     13        the appropriate SizeClass, so that the JIT may inline accesses
     14        directly to the SizeClass for JSFinalObject allocations.  And third,
     15        the JIT is extended with code to emit inline fast paths for GC
     16        allocation.  A stub call is emitted in the case where the inline fast
     17        path fails.
     18
     19        * heap/Heap.h:
     20        (JSC::Heap::sizeClassFor):
     21        (JSC::Heap::allocate):
     22        * jit/JIT.cpp:
     23        (JSC::JIT::privateCompileSlowCases):
     24        * jit/JIT.h:
     25        * jit/JITInlineMethods.h:
     26        (JSC::JIT::emitAllocateJSFinalObject):
     27        * jit/JITOpcodes.cpp:
     28        (JSC::JIT::emit_op_new_object):
     29        (JSC::JIT::emitSlow_op_new_object):
     30        (JSC::JIT::emit_op_create_this):
     31        (JSC::JIT::emitSlow_op_create_this):
     32        * jit/JITOpcodes32_64.cpp:
     33        (JSC::JIT::emit_op_new_object):
     34        (JSC::JIT::emitSlow_op_new_object):
     35        (JSC::JIT::emit_op_create_this):
     36        (JSC::JIT::emitSlow_op_create_this):
     37        * runtime/JSGlobalData.cpp:
     38        (JSC::JSGlobalData::storeVPtrs):
     39        * runtime/JSGlobalData.h:
     40        * runtime/JSObject.h:
     41        (JSC::JSFinalObject::JSFinalObject):
     42        (JSC::JSObject::offsetOfInheritorID):
     43
    1442011-07-18  Mark Hahnenberg  <mhahnenberg@apple.com>
    245
  • trunk/Source/JavaScriptCore/heap/Heap.h

    r91039 r91199  
    8383
    8484        void* allocate(size_t);
     85        NewSpace::SizeClass& sizeClassFor(size_t);
    8586        void* allocate(NewSpace::SizeClass&);
    8687        void notifyIsSafeToCollect() { m_isSafeToCollect = true; }
     
    290291    }
    291292   
     293    inline NewSpace::SizeClass& Heap::sizeClassFor(size_t bytes)
     294    {
     295        return m_newSpace.sizeClassFor(bytes);
     296    }
     297   
    292298    inline void* Heap::allocate(NewSpace::SizeClass& sizeClass)
    293299    {
     
    304310    {
    305311        ASSERT(isValidAllocation(bytes));
    306         NewSpace::SizeClass& sizeClass = m_newSpace.sizeClassFor(bytes);
     312        NewSpace::SizeClass& sizeClass = sizeClassFor(bytes);
    307313        return allocate(sizeClass);
    308314    }
  • trunk/Source/JavaScriptCore/jit/JIT.cpp

    r91095 r91199  
    402402        DEFINE_SLOWCASE_OP(op_construct)
    403403        DEFINE_SLOWCASE_OP(op_convert_this)
     404        DEFINE_SLOWCASE_OP(op_create_this)
    404405        DEFINE_SLOWCASE_OP(op_div)
    405406        DEFINE_SLOWCASE_OP(op_eq)
     
    436437#endif
    437438        DEFINE_SLOWCASE_OP(op_neq)
     439        DEFINE_SLOWCASE_OP(op_new_object)
    438440        DEFINE_SLOWCASE_OP(op_not)
    439441        DEFINE_SLOWCASE_OP(op_nstricteq)
  • trunk/Source/JavaScriptCore/jit/JIT.h

    r91095 r91199  
    300300
    301301        void emitWriteBarrier(RegisterID owner, RegisterID scratch);
     302       
     303        template<typename T>
     304        void emitAllocateJSFinalObject(T structure, RegisterID result, RegisterID scratch);
    302305
    303306#if USE(JSVALUE32_64)
     
    854857        void emitSlow_op_construct(Instruction*, Vector<SlowCaseEntry>::iterator&);
    855858        void emitSlow_op_convert_this(Instruction*, Vector<SlowCaseEntry>::iterator&);
     859        void emitSlow_op_create_this(Instruction*, Vector<SlowCaseEntry>::iterator&);
    856860        void emitSlow_op_div(Instruction*, Vector<SlowCaseEntry>::iterator&);
    857861        void emitSlow_op_eq(Instruction*, Vector<SlowCaseEntry>::iterator&);
     
    886890        void emitSlow_op_negate(Instruction*, Vector<SlowCaseEntry>::iterator&);
    887891        void emitSlow_op_neq(Instruction*, Vector<SlowCaseEntry>::iterator&);
     892        void emitSlow_op_new_object(Instruction*, Vector<SlowCaseEntry>::iterator&);
    888893        void emitSlow_op_not(Instruction*, Vector<SlowCaseEntry>::iterator&);
    889894        void emitSlow_op_nstricteq(Instruction*, Vector<SlowCaseEntry>::iterator&);
  • trunk/Source/JavaScriptCore/jit/JITInlineMethods.h

    r85432 r91199  
    375375}
    376376
     377template<typename T>
     378inline void JIT::emitAllocateJSFinalObject(T structure, RegisterID result, RegisterID scratch)
     379{
     380    NewSpace::SizeClass* sizeClass = &m_globalData->heap.sizeClassFor(sizeof(JSFinalObject));
     381    loadPtr(&sizeClass->firstFreeCell, result);
     382    addSlowCase(branchTestPtr(Zero, result));
     383   
     384    // remove the object from the free list
     385    loadPtr(Address(result), scratch);
     386    storePtr(scratch, &sizeClass->firstFreeCell);
     387   
     388    // initialize the object's vtable
     389    storePtr(ImmPtr(m_globalData->jsFinalObjectVPtr), Address(result));
     390   
     391    // initialize the object's structure
     392    storePtr(structure, Address(result, JSCell::structureOffset()));
     393   
     394    // initialize the inheritor ID
     395    storePtr(ImmPtr(0), Address(result, JSObject::offsetOfInheritorID()));
     396   
     397    // initialize the object's property storage pointer
     398    addPtr(Imm32(sizeof(JSObject)), result, scratch);
     399    storePtr(scratch, Address(result, JSObject::offsetOfPropertyStorage()));
     400}
     401
    377402#if USE(JSVALUE32_64)
    378403
  • trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp

    r91095 r91199  
    3030
    3131#include "Arguments.h"
     32#include "Heap.h"
    3233#include "JITInlineMethods.h"
    3334#include "JITStubCall.h"
     
    331332void JIT::emit_op_new_object(Instruction* currentInstruction)
    332333{
     334    emitAllocateJSFinalObject(ImmPtr(m_codeBlock->globalObject()->emptyObjectStructure()), regT0, regT1);
     335   
     336    emitPutVirtualRegister(currentInstruction[1].u.operand);
     337}
     338
     339void JIT::emitSlow_op_new_object(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     340{
     341    linkSlowCase(iter);
    333342    JITStubCall(this, cti_op_new_object).call(currentInstruction[1].u.operand);
    334343}
     
    11571166void JIT::emit_op_create_this(Instruction* currentInstruction)
    11581167{
     1168    emitGetVirtualRegister(currentInstruction[2].u.operand, regT2);
     1169    emitJumpSlowCaseIfNotJSCell(regT2, currentInstruction[2].u.operand);
     1170    loadPtr(Address(regT2, JSCell::structureOffset()), regT1);
     1171    addSlowCase(branch8(NotEqual, Address(regT1, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType)));
     1172   
     1173    // now we know that the prototype is an object, but we don't know if it's got an
     1174    // inheritor ID
     1175   
     1176    loadPtr(Address(regT2, JSObject::offsetOfInheritorID()), regT2);
     1177    addSlowCase(branchTestPtr(Zero, regT2));
     1178   
     1179    // now regT2 contains the inheritorID, which is the structure that the newly
     1180    // allocated object will have.
     1181   
     1182    emitAllocateJSFinalObject(regT2, regT0, regT1);
     1183   
     1184    emitPutVirtualRegister(currentInstruction[1].u.operand);
     1185}
     1186
     1187void JIT::emitSlow_op_create_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     1188{
     1189    linkSlowCaseIfNotJSCell(iter, currentInstruction[2].u.operand); // not a cell
     1190    linkSlowCase(iter); // not an object
     1191    linkSlowCase(iter); // doesn't have an inheritor ID
     1192    linkSlowCase(iter); // allocation failed
    11591193    JITStubCall stubCall(this, cti_op_create_this);
    11601194    stubCall.addArgument(currentInstruction[2].u.operand, regT1);
  • trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp

    r91095 r91199  
    486486void JIT::emit_op_new_object(Instruction* currentInstruction)
    487487{
     488    emitAllocateJSFinalObject(ImmPtr(m_codeBlock->globalObject()->emptyObjectStructure()), regT0, regT1);
     489   
     490    emitStoreCell(currentInstruction[1].u.operand, regT0);
     491}
     492
     493void JIT::emitSlow_op_new_object(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     494{
     495    linkSlowCase(iter);
    488496    JITStubCall(this, cti_op_new_object).call(currentInstruction[1].u.operand);
    489497}
     
    14391447void JIT::emit_op_create_this(Instruction* currentInstruction)
    14401448{
     1449    emitLoad(currentInstruction[2].u.operand, regT1, regT0);
     1450    emitJumpSlowCaseIfNotJSCell(currentInstruction[2].u.operand, regT1);
     1451    loadPtr(Address(regT0, JSCell::structureOffset()), regT1);
     1452    addSlowCase(branch8(NotEqual, Address(regT1, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType)));
     1453   
     1454    // now we know that the prototype is an object, but we don't know if it's got an
     1455    // inheritor ID
     1456   
     1457    loadPtr(Address(regT0, JSObject::offsetOfInheritorID()), regT2);
     1458    addSlowCase(branchTestPtr(Zero, regT2));
     1459   
     1460    // now regT2 contains the inheritorID, which is the structure that the newly
     1461    // allocated object will have.
     1462   
     1463    emitAllocateJSFinalObject(regT2, regT0, regT1);
     1464
     1465    emitStoreCell(currentInstruction[1].u.operand, regT0);
     1466}
     1467
     1468void JIT::emitSlow_op_create_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     1469{
     1470    linkSlowCaseIfNotJSCell(iter, currentInstruction[2].u.operand); // not a cell
     1471    linkSlowCase(iter); // not an object
     1472    linkSlowCase(iter); // doesn't have an inheritor ID
     1473    linkSlowCase(iter); // allocation failed
    14411474    unsigned protoRegister = currentInstruction[2].u.operand;
    14421475    emitLoad(protoRegister, regT1, regT0);
  • trunk/Source/JavaScriptCore/runtime/JSGlobalData.cpp

    r90865 r91199  
    114114extern JSC_CONST_HASHTABLE HashTable stringConstructorTable;
    115115
     116void* JSGlobalData::jsFinalObjectVPtr;
    116117void* JSGlobalData::jsArrayVPtr;
    117118void* JSGlobalData::jsByteArrayVPtr;
     
    133134    // COMPILE_ASSERTS below check that this is true.
    134135    char storage[64];
     136
     137    COMPILE_ASSERT(sizeof(JSFinalObject) <= sizeof(storage), sizeof_JSFinalObject_must_be_less_than_storage);
     138    JSCell* jsFinalObject = new (storage) JSFinalObject(JSFinalObject::VPtrStealingHack);
     139    CLOBBER_MEMORY();
     140    JSGlobalData::jsFinalObjectVPtr = jsFinalObject->vptr();
    135141
    136142    COMPILE_ASSERT(sizeof(JSArray) <= sizeof(storage), sizeof_JSArray_must_be_less_than_storage);
  • trunk/Source/JavaScriptCore/runtime/JSGlobalData.h

    r90423 r91199  
    183183
    184184        static void storeVPtrs();
     185        static JS_EXPORTDATA void* jsFinalObjectVPtr;
    185186        static JS_EXPORTDATA void* jsArrayVPtr;
    186187        static JS_EXPORTDATA void* jsByteArrayVPtr;
  • trunk/Source/JavaScriptCore/runtime/JSObject.h

    r91194 r91199  
    4949    class HashEntry;
    5050    class InternalFunction;
     51    class MarkedBlock;
    5152    class PropertyDescriptor;
    5253    class PropertyNameArray;
     
    7677        friend class JIT;
    7778        friend class JSCell;
     79        friend class MarkedBlock;
    7880        friend void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot);
    7981
     
    251253        static size_t offsetOfInlineStorage();
    252254        static size_t offsetOfPropertyStorage();
     255        static size_t offsetOfInheritorID();
    253256
    254257        static JS_EXPORTDATA const ClassInfo s_info;
     
    358361
    359362    public:
     363        explicit JSFinalObject(VPtrStealingHackType)
     364            : JSObject(VPtrStealingHack, m_inlineStorage)
     365        {
     366        }
     367       
    360368        static JSFinalObject* create(ExecState* exec, Structure* structure)
    361369        {
     
    390398{
    391399    return OBJECT_OFFSETOF(JSObject, m_propertyStorage);
     400}
     401
     402inline size_t JSObject::offsetOfInheritorID()
     403{
     404    return OBJECT_OFFSETOF(JSObject, m_inheritorID);
    392405}
    393406
Note: See TracChangeset for help on using the changeset viewer.