]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - interpreter/RegisterFile.h
JavaScriptCore-1097.3.3.tar.gz
[apple/javascriptcore.git] / interpreter / RegisterFile.h
index def9e2549195a0def3c7374cd490fc5984986485..21ad7fbaea596fd6e81d5e13a6ad3b0209773e07 100644 (file)
 #ifndef RegisterFile_h
 #define RegisterFile_h
 
-#include "Collector.h"
 #include "ExecutableAllocator.h"
 #include "Register.h"
-#include "WeakGCPtr.h"
-#include <stdio.h>
 #include <wtf/Noncopyable.h>
+#include <wtf/PageReservation.h>
 #include <wtf/VMTags.h>
 
-#if HAVE(MMAP)
-#include <errno.h>
-#include <sys/mman.h>
-#endif
-
 namespace JSC {
 
-/*
-    A register file is a stack of register frames. We represent a register
-    frame by its offset from "base", the logical first entry in the register
-    file. The bottom-most register frame's offset from base is 0.
-
-    In a program where function "a" calls function "b" (global code -> a -> b),
-    the register file might look like this:
-
-    |       global frame     |        call frame      |        call frame      |     spare capacity     |
-    -----------------------------------------------------------------------------------------------------
-    |  0 |  1 |  2 |  3 |  4 |  5 |  6 |  7 |  8 |  9 | 10 | 11 | 12 | 13 | 14 |    |    |    |    |    | <-- index in buffer
-    -----------------------------------------------------------------------------------------------------
-    | -3 | -2 | -1 |  0 |  1 |  2 |  3 |  4 |  5 |  6 |  7 |  8 |  9 | 10 | 11 |    |    |    |    |    | <-- index relative to base
-    -----------------------------------------------------------------------------------------------------
-    |    <-globals | temps-> |  <-vars | temps->      |                 <-vars |
-       ^              ^                   ^                                       ^
-       |              |                   |                                       |
-     buffer    base (frame 0)          frame 1                                 frame 2
-
-    Since all variables, including globals, are accessed by negative offsets
-    from their register frame pointers, to keep old global offsets correct, new
-    globals must appear at the beginning of the register file, shifting base
-    to the right.
-
-    If we added one global variable to the register file depicted above, it
-    would look like this:
-
-    |         global frame        |<                                                                    >
-    ------------------------------->                                                                    <
-    |  0 |  1 |  2 |  3 |  4 |  5 |<                             >snip<                                 > <-- index in buffer
-    ------------------------------->                                                                    <
-    | -4 | -3 | -2 | -1 |  0 |  1 |<                                                                    > <-- index relative to base
-    ------------------------------->                                                                    <
-    |         <-globals | temps-> |
-       ^                   ^
-       |                   |
-     buffer         base (frame 0)
-
-    As you can see, global offsets relative to base have stayed constant,
-    but base itself has moved. To keep up with possible changes to base,
-    clients keep an indirect pointer, so their calculations update
-    automatically when base changes.
+    class ConservativeRoots;
+    class DFGCodeBlocks;
+    class LLIntOffsetsExtractor;
 
-    For client simplicity, the RegisterFile measures size and capacity from
-    "base", not "buffer".
-*/
-
-    class JSGlobalObject;
-
-    class RegisterFile : public Noncopyable {
-        friend class JIT;
+    class RegisterFile {
+        WTF_MAKE_NONCOPYABLE(RegisterFile);
     public:
         enum CallFrameHeaderEntry {
-            CallFrameHeaderSize = 8,
-
-            CodeBlock = -8,
-            ScopeChain = -7,
-            CallerFrame = -6,
-            ReturnPC = -5, // This is either an Instruction* or a pointer into JIT generated code stored as an Instruction*.
-            ReturnValueRegister = -4,
-            ArgumentCount = -3,
-            Callee = -2,
-            OptionalCalleeArguments = -1,
+            CallFrameHeaderSize = 6,
+
+            ArgumentCount = -6,
+            CallerFrame = -5,
+            Callee = -4,
+            ScopeChain = -3,
+            ReturnPC = -2, // This is either an Instruction* or a pointer into JIT generated code stored as an Instruction*.
+            CodeBlock = -1,
         };
 
-        enum { ProgramCodeThisRegister = -CallFrameHeaderSize - 1 };
-        enum { ArgumentsRegister = 0 };
-
-        static const size_t defaultCapacity = 524288;
-        static const size_t defaultMaxGlobals = 8192;
-        static const size_t commitSize = 1 << 14;
+        static const size_t defaultCapacity = 512 * 1024;
+        static const size_t commitSize = 16 * 1024;
         // Allow 8k of excess registers before we start trying to reap the registerfile
         static const ptrdiff_t maxExcessCapacity = 8 * 1024;
 
-        RegisterFile(size_t capacity = defaultCapacity, size_t maxGlobals = defaultMaxGlobals);
+        RegisterFile(size_t capacity = defaultCapacity);
         ~RegisterFile();
+        
+        void gatherConservativeRoots(ConservativeRoots&);
+        void gatherConservativeRoots(ConservativeRoots&, DFGCodeBlocks&);
 
-        Register* start() const { return m_start; }
+        Register* begin() const { return static_cast<Register*>(m_reservation.base()); }
         Register* end() const { return m_end; }
-        size_t size() const { return m_end - m_start; }
-
-        void setGlobalObject(JSGlobalObject*);
-        bool clearGlobalObject(JSGlobalObject*);
-        JSGlobalObject* globalObject();
+        size_t size() const { return end() - begin(); }
 
-        bool grow(Register* newEnd);
-        void shrink(Register* newEnd);
+        bool grow(Register*);
+        void shrink(Register*);
         
-        void setNumGlobals(size_t numGlobals) { m_numGlobals = numGlobals; }
-        int numGlobals() const { return m_numGlobals; }
-        size_t maxGlobals() const { return m_maxGlobals; }
+        static size_t committedByteCount();
+        static void initializeThreading();
 
-        Register* lastGlobal() const { return m_start - m_numGlobals; }
-        
-        void markGlobals(MarkStack& markStack, Heap* heap) { heap->markConservatively(markStack, lastGlobal(), m_start); }
-        void markCallFrames(MarkStack& markStack, Heap* heap) { heap->markConservatively(markStack, m_start, m_end); }
+        Register* const * addressOfEnd() const
+        {
+            return &m_end;
+        }
 
     private:
+        friend class LLIntOffsetsExtractor;
+        
+        bool growSlowCase(Register*);
         void releaseExcessCapacity();
-        size_t m_numGlobals;
-        const size_t m_maxGlobals;
-        Register* m_start;
+        void addToCommittedByteCount(long);
         Register* m_end;
-        Register* m_max;
-        Register* m_buffer;
-        Register* m_maxUsed;
-
-#if HAVE(VIRTUALALLOC)
         Register* m_commitEnd;
-#endif
-
-        WeakGCPtr<JSGlobalObject> m_globalObject; // The global object whose vars are currently stored in the register file.
+        PageReservation m_reservation;
     };
 
-    // FIXME: Add a generic getpagesize() to WTF, then move this function to WTF as well.
-    inline bool isPageAligned(size_t size) { return size != 0 && size % (8 * 1024) == 0; }
-
-    inline RegisterFile::RegisterFile(size_t capacity, size_t maxGlobals)
-        : m_numGlobals(0)
-        , m_maxGlobals(maxGlobals)
-        , m_start(0)
-        , m_end(0)
-        , m_max(0)
-        , m_buffer(0)
+    inline RegisterFile::RegisterFile(size_t capacity)
+        : m_end(0)
     {
-        // Verify that our values will play nice with mmap and VirtualAlloc.
-        ASSERT(isPageAligned(maxGlobals));
-        ASSERT(isPageAligned(capacity));
+        ASSERT(capacity && isPageAligned(capacity));
 
-        size_t bufferLength = (capacity + maxGlobals) * sizeof(Register);
-    #if HAVE(MMAP)
-        m_buffer = static_cast<Register*>(mmap(0, bufferLength, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, VM_TAG_FOR_REGISTERFILE_MEMORY, 0));
-        if (m_buffer == MAP_FAILED) {
-#if OS(WINCE)
-            fprintf(stderr, "Could not allocate register file: %d\n", GetLastError());
-#else
-            fprintf(stderr, "Could not allocate register file: %d\n", errno);
-#endif
-            CRASH();
-        }
-    #elif HAVE(VIRTUALALLOC)
-        m_buffer = static_cast<Register*>(VirtualAlloc(0, roundUpAllocationSize(bufferLength, commitSize), MEM_RESERVE, PAGE_READWRITE));
-        if (!m_buffer) {
-#if OS(WINCE)
-            fprintf(stderr, "Could not allocate register file: %d\n", GetLastError());
-#else
-            fprintf(stderr, "Could not allocate register file: %d\n", errno);
-#endif
-            CRASH();
-        }
-        size_t committedSize = roundUpAllocationSize(maxGlobals * sizeof(Register), commitSize);
-        void* commitCheck = VirtualAlloc(m_buffer, committedSize, MEM_COMMIT, PAGE_READWRITE);
-        if (commitCheck != m_buffer) {
-#if OS(WINCE)
-            fprintf(stderr, "Could not allocate register file: %d\n", GetLastError());
-#else
-            fprintf(stderr, "Could not allocate register file: %d\n", errno);
-#endif
-            CRASH();
-        }
-        m_commitEnd = reinterpret_cast<Register*>(reinterpret_cast<char*>(m_buffer) + committedSize);
-    #else 
-        /* 
-         * If neither MMAP nor VIRTUALALLOC are available - use fastMalloc instead.
-         *
-         * Please note that this is the fallback case, which is non-optimal.
-         * If any possible, the platform should provide for a better memory
-         * allocation mechanism that allows for "lazy commit" or dynamic
-         * pre-allocation, similar to mmap or VirtualAlloc, to avoid waste of memory.
-         */
-        m_buffer = static_cast<Register*>(fastMalloc(bufferLength));
-    #endif
-        m_start = m_buffer + maxGlobals;
-        m_end = m_start;
-        m_maxUsed = m_end;
-        m_max = m_start + capacity;
+        m_reservation = PageReservation::reserve(roundUpAllocationSize(capacity * sizeof(Register), commitSize), OSAllocator::JSVMStackPages);
+        m_end = static_cast<Register*>(m_reservation.base());
+        m_commitEnd = static_cast<Register*>(m_reservation.base());
     }
 
     inline void RegisterFile::shrink(Register* newEnd)
@@ -227,38 +107,15 @@ namespace JSC {
         if (newEnd >= m_end)
             return;
         m_end = newEnd;
-        if (m_end == m_start && (m_maxUsed - m_start) > maxExcessCapacity)
+        if (m_end == m_reservation.base() && (m_commitEnd - begin()) >= maxExcessCapacity)
             releaseExcessCapacity();
     }
 
     inline bool RegisterFile::grow(Register* newEnd)
     {
-        if (newEnd < m_end)
+        if (newEnd <= m_end)
             return true;
-
-        if (newEnd > m_max)
-            return false;
-
-#if !HAVE(MMAP) && HAVE(VIRTUALALLOC)
-        if (newEnd > m_commitEnd) {
-            size_t size = roundUpAllocationSize(reinterpret_cast<char*>(newEnd) - reinterpret_cast<char*>(m_commitEnd), commitSize);
-            if (!VirtualAlloc(m_commitEnd, size, MEM_COMMIT, PAGE_READWRITE)) {
-#if OS(WINCE)
-                fprintf(stderr, "Could not allocate register file: %d\n", GetLastError());
-#else
-                fprintf(stderr, "Could not allocate register file: %d\n", errno);
-#endif
-                CRASH();
-            }
-            m_commitEnd = reinterpret_cast<Register*>(reinterpret_cast<char*>(m_commitEnd) + size);
-        }
-#endif
-
-        if (newEnd > m_maxUsed)
-            m_maxUsed = newEnd;
-
-        m_end = newEnd;
-        return true;
+        return growSlowCase(newEnd);
     }
 
 } // namespace JSC