Ignore:
Timestamp:
Jun 27, 2008, 3:35:33 PM (17 years ago)
Author:
[email protected]
Message:

JavaScriptCore:

2008-06-27 Geoffrey Garen <[email protected]>

Reviewed by Oliver Hunt.


One RegisterFile to rule them all!


SunSpider reports a 0.2% speedup.

This patch removes the RegisterFileStack abstraction and replaces it with
a single register file that


(a) allocates a fixed storage area, including a fixed area for global
vars, so that no operation may cause the register file to reallocate


and

(b) swaps between global storage areas when executing code in different
global objects.


This patch also changes the layout of the register file so that all call
frames, including call frames for global code, get a header. This is
required to support re-entrant global code. It also just makes things simpler.


  • VM/CodeGenerator.cpp: (KJS::CodeGenerator::addGlobalVar): New function. Differs from addVar in that


(a) global vars don't contribute to a CodeBlock's numLocals count, since
global storage is fixed and allocated at startup


and


(b) references to global vars get shifted to elide intermediate stack
between "r" and the global storage area.


  • VM/Machine.cpp: (KJS::Machine::dumpRegisters): Updated this function to match the new register file layout, and added the ability to dump exact identifiers for the different parts of a call frame.


(KJS::Machine::unwindCallFrame): Updated this function to match the new
register file layout.


(KJS::Machine::execute): Updated this function to initialize a call frame
header for global code, and to swap global storage areas when switching
to execution in a new global object.


(KJS::Machine::privateExecute): Got rid of "safeForReentry" and re-reading
of registerBase because the register file is always safe for reentry now,
and registerBase never changes.


  • VM/Machine.h: Moved the call frame header enum from Machine to RegisterFile, to resolve a header dependency problem (a good sign that the enum belonged in RegisterFile all along!)
  • VM/RegisterFile.cpp:
  • VM/RegisterFile.h: Changed RegisterFile to mmap a fixed size register area. This allows us to avoid re-allocting the register file later on. Instead, we rely on the OS to allocate physical pages to the register file as necessary.
  • VM/RegisterFileStack.cpp: Removed. Tada!
  • VM/RegisterFileStack.h: Removed. Tada!
  • kjs/DebuggerCallFrame.cpp: Updated this class to match the new register file layout, greatly simplifying it in the process.
  • kjs/JSActivation.h:
  • kjs/JSActivation.cpp: Moved some of this logic up to JSVariableObject, since the global object now needs to be able to tear off its registers just like the activation object.
  • kjs/JSFunction.cpp: No need to fiddle with the register file anymore.
  • kjs/JSGlobalObject.h:
  • kjs/JSGlobalObject.cpp: Updated JSGlobalObject to support moving its global storage area into and out of the register file.
  • kjs/PropertySlot.cpp: No need to fiddle with the register file anymore.
  • kjs/collector.cpp: Renamed markStackObjectConservatively to markConservatively, since we don't just mark stack objects this way.


Also, added code to mark the machine's register file.

  • kjs/config.h: Moved some platforms #defines from here...
  • wtf/Platform.h: ...to here, to support mmap/VirtualAlloc detection in RegisterFile.h.

LayoutTests:

2008-06-26 Geoffrey Garen <[email protected]>

Reviewed by Oliver Hunt.


Added a test for what happens when a script exceeds the limit on declared
global variables.

  • fast/js/global-var-limit-expected.txt: Added.
  • fast/js/global-var-limit.html: Added.
  • fast/js/global-recursion-on-full-stack-expected.txt: Updated for new (slightly more correct) behavior. Since the stack overflow happens in the middle of a try/catch block, it should be caught, instead of logged to the console.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/VM/RegisterFile.h

    r34659 r34838  
    3232#include "Register.h"
    3333#include "collector.h"
     34#if HAVE(MMAP)
     35#include <sys/mman.h>
     36#endif
    3437#include <wtf/Noncopyable.h>
    3538
     
    8386*/
    8487
    85     class RegisterFileStack;
     88    class JSGlobalObject;
    8689
    8790    class RegisterFile : Noncopyable {
    8891    public:
    89         enum { DefaultRegisterFileSize = 2 * 1024 * 1024 };
     92        enum {
     93            CallerCodeBlock = 0,
     94            ReturnVPC,
     95            CallerScopeChain,
     96            CallerRegisterOffset,
     97            ReturnValueRegister,
     98            ArgumentStartRegister,
     99            ArgumentCount,
     100            CalledAsConstructor,
     101            Callee,
     102            OptionalCalleeActivation,
     103            CallFrameHeaderSize
     104        };
    90105
    91         RegisterFile(size_t maxSize, RegisterFileStack* m_baseObserver)
    92             : m_safeForReentry(true)
    93             , m_size(0)
    94             , m_capacity(0)
    95             , m_maxSize(maxSize)
     106        enum { ProgramCodeThisRegister = - 1 };
     107
     108        enum { DefaultCapacity = 2 * 1024 * 1024 };
     109        enum { DefaultMaxGlobals = 8 * 1024 };
     110
     111        RegisterFile(size_t capacity = DefaultCapacity, size_t maxGlobals = DefaultMaxGlobals)
     112            : m_size(0)
     113            , m_capacity(capacity)
     114            , m_numGlobals(0)
     115            , m_maxGlobals(maxGlobals)
    96116            , m_base(0)
    97117            , m_buffer(0)
    98             , m_baseObserver(m_baseObserver)
     118            , m_globalObject(0)
    99119        {
     120            size_t bufferLength = (capacity + maxGlobals) * sizeof(Register);
     121#if HAVE(MMAP)
     122            m_buffer = static_cast<Register*>(mmap(0, bufferLength, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0));
     123#elif HAVE(VIRTUALALLOC)
     124            // FIXME: Use VirtualAlloc, and commit pages as we go.
     125            m_buffer = fastMalloc(bufferLength);
     126#else
     127            #error "Don't know how to reserve virtual memory on this platform."
     128#endif
     129            m_base = m_buffer + maxGlobals;
    100130        }
    101131
    102         ~RegisterFile()
    103         {
    104             setBuffer(0);
    105         }
     132        ~RegisterFile();
    106133
    107134        // Pointer to a value that holds the base of this register file.
    108135        Register** basePointer() { return &m_base; }
     136       
     137        void setGlobalObject(JSGlobalObject* globalObject) { m_globalObject = globalObject; }
     138        JSGlobalObject* globalObject() { return m_globalObject; }
    109139
    110140        void shrink(size_t size)
     
    117147        {
    118148            if (size > m_size) {
    119                 if (size > m_capacity) {
    120                     if (size > m_maxSize)
    121                         return false;
    122                     growBuffer(size, m_maxSize);
    123                 }
     149                if (size > m_capacity)
     150                    return false;
     151#if !HAVE(MMAP) && HAVE(VIRTUALALLOC)
     152                // FIXME: Use VirtualAlloc, and commit pages as we go.
     153#endif
    124154                m_size = size;
    125155            }
     
    128158
    129159        size_t size() { return m_size; }
    130         size_t maxSize() { return m_maxSize; }
     160       
     161        void setNumGlobals(size_t numGlobals) { m_numGlobals = numGlobals; }
     162        int numGlobals() { return m_numGlobals; }
     163        size_t maxGlobals() { return m_maxGlobals; }
    131164
    132         void clear();
    133 
    134         void addGlobalSlots(size_t count);
    135         int numGlobalSlots() { return static_cast<int>(m_base - m_buffer); }
    136 
    137         void copyGlobals(RegisterFile* src);
     165        Register* lastGlobal() { return m_base - m_numGlobals; }
    138166
    139167        void mark(Heap* heap)
    140168        {
    141             heap->markStackObjectsConservatively(m_buffer, m_base + m_size);
     169            heap->markConservatively(lastGlobal(), m_base + m_size);
    142170        }
    143171
    144         bool isGlobal() { return !!m_baseObserver; }
    145 
    146         bool safeForReentry() { return m_safeForReentry; }
    147         void setSafeForReentry(bool safeForReentry) { m_safeForReentry = safeForReentry; }
    148 
    149172    private:
    150         size_t newBuffer(size_t size, size_t capacity, size_t minCapacity, size_t maxSize, size_t offset);
    151         bool growBuffer(size_t minCapacity, size_t maxSize);
    152         void setBuffer(Register* buffer)
    153         {
    154             if (m_buffer)
    155                 fastFree(m_buffer);
    156 
    157             m_buffer = buffer;
    158         }
    159 
    160         void setBase(Register*);
    161 
    162         bool m_safeForReentry;
    163173        size_t m_size;
    164174        size_t m_capacity;
    165         size_t m_maxSize;
     175        size_t m_numGlobals;
     176        size_t m_maxGlobals;
    166177        Register* m_base;
    167178        Register* m_buffer;
    168         RegisterFileStack* m_baseObserver;
     179        JSGlobalObject* m_globalObject; // The global object whose vars are currently stored in the register file.
    169180    };
    170181
Note: See TracChangeset for help on using the changeset viewer.