summaryrefslogtreecommitdiff
path: root/js/src/nanojit/CodeAlloc.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/nanojit/CodeAlloc.h')
-rw-r--r--js/src/nanojit/CodeAlloc.h237
1 files changed, 237 insertions, 0 deletions
diff --git a/js/src/nanojit/CodeAlloc.h b/js/src/nanojit/CodeAlloc.h
new file mode 100644
index 0000000..b5cb2c6
--- /dev/null
+++ b/js/src/nanojit/CodeAlloc.h
@@ -0,0 +1,237 @@
+/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
+/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is [Open Source Virtual Machine].
+ *
+ * The Initial Developer of the Original Code is
+ * Adobe System Incorporated.
+ * Portions created by the Initial Developer are Copyright (C) 2004-2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Adobe AS3 Team
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef __nanojit_CodeAlloc__
+#define __nanojit_CodeAlloc__
+
+namespace nanojit
+{
+ /**
+ * CodeList is a single block of code. The next field is used to
+ * form linked lists of non-contiguous blocks of code. Clients use CodeList*
+ * to point to the first block in a list.
+ */
+ class CodeList
+ {
+ friend class CodeAlloc;
+
+ /** for making singly linked lists of blocks in any order */
+ CodeList* next;
+
+ /** adjacent block at lower address. This field plus higher
+ form a doubly linked list of blocks in address order, used
+ for splitting and coalescing blocks. */
+ CodeList* lower;
+
+ /** pointer to the heapblock terminal that represents the code chunk containing this block */
+ CodeList* terminator;
+
+ /** true if block is free, false otherwise */
+ bool isFree;
+
+ /** (only valid for terminator blocks). Set true just before calling
+ * markCodeChunkExec() and false just after markCodeChunkWrite() */
+ bool isExec;
+
+ union {
+ // this union is used in leu of pointer punning in code
+ // the end of this block is always the address of the next higher block
+ CodeList* higher; // adjacent block at higher address
+ NIns* end; // points just past the end
+ };
+
+ /** code holds this block's payload of binary code, from
+ here to this->end */
+ NIns code[1]; // more follows
+
+ /** return the starting address for this block only */
+ NIns* start() { return &code[0]; }
+
+ /** return just the usable size of this block */
+ size_t size() const { return uintptr_t(end) - uintptr_t(&code[0]); }
+
+ /** return the whole size of this block including overhead */
+ size_t blockSize() const { return uintptr_t(end) - uintptr_t(this); }
+
+ public:
+ /** true is the given NIns is contained within this block */
+ bool isInBlock(NIns* n) { return (n >= this->start() && n < this->end); }
+ };
+
+ /**
+ * Code memory allocator is a long lived manager for many code blocks that
+ * manages interaction with an underlying code memory allocator,
+ * sets page permissions. CodeAlloc provides APIs for allocating and freeing
+ * individual blocks of code memory (for methods, stubs, or compiled
+ * traces), static functions for managing lists of allocated code, and has
+ * a few pure virtual methods that embedders must implement to provide
+ * memory to the allocator.
+ *
+ * A "chunk" is a region of memory obtained from allocCodeChunk; it must
+ * be page aligned and be a multiple of the system page size.
+ *
+ * A "block" is a region of memory within a chunk. It can be arbitrarily
+ * sized and aligned, but is always contained within a single chunk.
+ * class CodeList represents one block; the members of CodeList track the
+ * extent of the block and support creating lists of blocks.
+ *
+ * The allocator coalesces free blocks when it can, in free(), but never
+ * coalesces chunks.
+ */
+ class CodeAlloc
+ {
+ static const size_t sizeofMinBlock = offsetof(CodeList, code);
+ static const size_t minAllocSize = LARGEST_UNDERRUN_PROT;
+
+ // Return the number of bytes needed for the header of 'n' blocks
+ static size_t headerSpaceFor(uint32_t nbrBlks) { return nbrBlks * sizeofMinBlock; }
+
+ // Return the number of bytes needed in order to safely construct 'n' blocks
+ static size_t blkSpaceFor(uint32_t nbrBlks) { return (nbrBlks * minAllocSize) + headerSpaceFor(nbrBlks); }
+
+ /** Terminator blocks. All active and free allocations
+ are reachable by traversing this chain and each
+ element's lower chain. */
+ CodeList* heapblocks;
+
+ /** Reusable blocks. */
+ CodeList* availblocks;
+ size_t totalAllocated;
+
+ /** Cached value of VMPI_getVMPageSize */
+ const size_t bytesPerPage;
+
+ /** Number of bytes to request from VMPI layer, always a multiple of the page size */
+ const size_t bytesPerAlloc;
+
+ /** remove one block from a list */
+ static CodeList* removeBlock(CodeList* &list);
+
+ /** add one block to a list */
+ static void addBlock(CodeList* &blocks, CodeList* b);
+
+ /** compute the CodeList pointer from a [start, end) range */
+ static CodeList* getBlock(NIns* start, NIns* end);
+
+ /** add raw memory to the free list */
+ void addMem();
+
+ /** make sure all the higher/lower pointers are correct for every block */
+ void sanity_check();
+
+ /** find the beginning of the heapblock terminated by term */
+ CodeList* firstBlock(CodeList* term);
+
+ //
+ // CodeAlloc's SPI (Service Provider Interface). Implementations must be
+ // defined by nanojit embedder. Allocation failures should cause an exception
+ // or longjmp; nanojit intentionally does not check for null.
+ //
+
+ /** allocate nbytes of memory to hold code. Never return null! */
+ void* allocCodeChunk(size_t nbytes);
+
+ /** free a block previously allocated by allocCodeMem. nbytes will
+ * match the previous allocCodeMem, but is provided here as well
+ * to mirror the mmap()/munmap() api. markCodeChunkWrite() will have
+ * been called if necessary, so it is not necessary for freeCodeChunk()
+ * to do it again. */
+ void freeCodeChunk(void* addr, size_t nbytes);
+
+ /** make this specific extent ready to execute (might remove write) */
+ void markCodeChunkExec(void* addr, size_t nbytes);
+
+ /** make this extent ready to modify (might remove exec) */
+ void markCodeChunkWrite(void* addr, size_t nbytes);
+
+ public:
+ CodeAlloc();
+ ~CodeAlloc();
+
+ /** return all the memory allocated through this allocator to the gcheap. */
+ void reset();
+
+ /** allocate some memory (up to 'byteLimit' bytes) for code returning pointers to the region. A zero 'byteLimit' means no limit */
+ void alloc(NIns* &start, NIns* &end, size_t byteLimit);
+
+ /** free a block of memory previously returned by alloc() */
+ void free(NIns* start, NIns* end);
+
+ /** free several blocks */
+ void freeAll(CodeList* &code);
+
+ /** flush the icache for all code in the list, before executing */
+ static void flushICache(CodeList* &blocks);
+
+ /** flush the icache for a specific extent */
+ static void flushICache(void *start, size_t len);
+
+ /** add the ranges [start, holeStart) and [holeEnd, end) to code, and
+ free [holeStart, holeEnd) if the hole is >= minsize */
+ void addRemainder(CodeList* &code, NIns* start, NIns* end, NIns* holeStart, NIns* holeEnd);
+
+ /** add a block previously returned by alloc(), to code */
+ static void add(CodeList* &code, NIns* start, NIns* end);
+
+ /** return the number of bytes in all the code blocks in "code", including block overhead */
+#ifdef PERFM
+ static size_t size(const CodeList* code);
+#endif
+
+ /** return the total number of bytes held by this CodeAlloc. */
+ size_t size();
+
+ /** print out stats about heap usage */
+ void logStats();
+
+ /** protect all code managed by this CodeAlloc */
+ void markAllExec();
+
+ /** protect all mem in the block list */
+ void markExec(CodeList* &blocks);
+
+ /** protect an entire chunk */
+ void markChunkExec(CodeList* term);
+
+ /** unprotect the code chunk containing just this one block */
+ void markBlockWrite(CodeList* b);
+ };
+}
+
+#endif // __nanojit_CodeAlloc__