1 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
2 /* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is [Open Source Virtual Machine].
18 * The Initial Developer of the Original Code is
19 * Adobe System Incorporated.
20 * Portions created by the Initial Developer are Copyright (C) 2004-2007
21 * the Initial Developer. All Rights Reserved.
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #ifndef __nanojit_CodeAlloc__
41 #define __nanojit_CodeAlloc__
46 * CodeList is a single block of code. The next field is used to
47 * form linked lists of non-contiguous blocks of code. Clients use CodeList*
48 * to point to the first block in a list.
52 friend class CodeAlloc;
54 /** for making singly linked lists of blocks in any order */
57 /** adjacent block at lower address. This field plus higher
58 form a doubly linked list of blocks in address order, used
59 for splitting and coalescing blocks. */
62 /** pointer to the heapblock terminal that represents the code chunk containing this block */
65 /** true if block is free, false otherwise */
68 /** (only valid for terminator blocks). Set true just before calling
69 * markCodeChunkExec() and false just after markCodeChunkWrite() */
73 // this union is used in leu of pointer punning in code
74 // the end of this block is always the address of the next higher block
75 CodeList* higher; // adjacent block at higher address
76 NIns* end; // points just past the end
79 /** code holds this block's payload of binary code, from
81 NIns code[1]; // more follows
83 /** return the starting address for this block only */
84 NIns* start() { return &code[0]; }
86 /** return just the usable size of this block */
87 size_t size() const { return uintptr_t(end) - uintptr_t(&code[0]); }
89 /** return the whole size of this block including overhead */
90 size_t blockSize() const { return uintptr_t(end) - uintptr_t(this); }
93 /** true is the given NIns is contained within this block */
94 bool isInBlock(NIns* n) { return (n >= this->start() && n < this->end); }
98 * Code memory allocator is a long lived manager for many code blocks that
99 * manages interaction with an underlying code memory allocator,
100 * sets page permissions. CodeAlloc provides APIs for allocating and freeing
101 * individual blocks of code memory (for methods, stubs, or compiled
102 * traces), static functions for managing lists of allocated code, and has
103 * a few pure virtual methods that embedders must implement to provide
104 * memory to the allocator.
106 * A "chunk" is a region of memory obtained from allocCodeChunk; it must
107 * be page aligned and be a multiple of the system page size.
109 * A "block" is a region of memory within a chunk. It can be arbitrarily
110 * sized and aligned, but is always contained within a single chunk.
111 * class CodeList represents one block; the members of CodeList track the
112 * extent of the block and support creating lists of blocks.
114 * The allocator coalesces free blocks when it can, in free(), but never
119 static const size_t sizeofMinBlock = offsetof(CodeList, code);
120 static const size_t minAllocSize = LARGEST_UNDERRUN_PROT;
122 // Return the number of bytes needed for the header of 'n' blocks
123 static size_t headerSpaceFor(uint32_t nbrBlks) { return nbrBlks * sizeofMinBlock; }
125 // Return the number of bytes needed in order to safely construct 'n' blocks
126 static size_t blkSpaceFor(uint32_t nbrBlks) { return (nbrBlks * minAllocSize) + headerSpaceFor(nbrBlks); }
128 /** Terminator blocks. All active and free allocations
129 are reachable by traversing this chain and each
130 element's lower chain. */
131 CodeList* heapblocks;
133 /** Reusable blocks. */
134 CodeList* availblocks;
135 size_t totalAllocated;
137 /** Cached value of VMPI_getVMPageSize */
138 const size_t bytesPerPage;
140 /** Number of bytes to request from VMPI layer, always a multiple of the page size */
141 const size_t bytesPerAlloc;
143 /** remove one block from a list */
144 static CodeList* removeBlock(CodeList* &list);
146 /** add one block to a list */
147 static void addBlock(CodeList* &blocks, CodeList* b);
149 /** compute the CodeList pointer from a [start, end) range */
150 static CodeList* getBlock(NIns* start, NIns* end);
152 /** add raw memory to the free list */
155 /** make sure all the higher/lower pointers are correct for every block */
158 /** find the beginning of the heapblock terminated by term */
159 CodeList* firstBlock(CodeList* term);
162 // CodeAlloc's SPI (Service Provider Interface). Implementations must be
163 // defined by nanojit embedder. Allocation failures should cause an exception
164 // or longjmp; nanojit intentionally does not check for null.
167 /** allocate nbytes of memory to hold code. Never return null! */
168 void* allocCodeChunk(size_t nbytes);
170 /** free a block previously allocated by allocCodeMem. nbytes will
171 * match the previous allocCodeMem, but is provided here as well
172 * to mirror the mmap()/munmap() api. markCodeChunkWrite() will have
173 * been called if necessary, so it is not necessary for freeCodeChunk()
175 void freeCodeChunk(void* addr, size_t nbytes);
177 /** make this specific extent ready to execute (might remove write) */
178 void markCodeChunkExec(void* addr, size_t nbytes);
180 /** make this extent ready to modify (might remove exec) */
181 void markCodeChunkWrite(void* addr, size_t nbytes);
187 /** return all the memory allocated through this allocator to the gcheap. */
190 /** allocate some memory (up to 'byteLimit' bytes) for code returning pointers to the region. A zero 'byteLimit' means no limit */
191 void alloc(NIns* &start, NIns* &end, size_t byteLimit);
193 /** free a block of memory previously returned by alloc() */
194 void free(NIns* start, NIns* end);
196 /** free several blocks */
197 void freeAll(CodeList* &code);
199 /** flush the icache for all code in the list, before executing */
200 static void flushICache(CodeList* &blocks);
202 /** flush the icache for a specific extent */
203 static void flushICache(void *start, size_t len);
205 /** add the ranges [start, holeStart) and [holeEnd, end) to code, and
206 free [holeStart, holeEnd) if the hole is >= minsize */
207 void addRemainder(CodeList* &code, NIns* start, NIns* end, NIns* holeStart, NIns* holeEnd);
209 /** add a block previously returned by alloc(), to code */
210 static void add(CodeList* &code, NIns* start, NIns* end);
212 /** return the number of bytes in all the code blocks in "code", including block overhead */
214 static size_t size(const CodeList* code);
217 /** return the total number of bytes held by this CodeAlloc. */
220 /** print out stats about heap usage */
223 /** protect all code managed by this CodeAlloc */
226 /** protect all mem in the block list */
227 void markExec(CodeList* &blocks);
229 /** protect an entire chunk */
230 void markChunkExec(CodeList* term);
232 /** unprotect the code chunk containing just this one block */
233 void markBlockWrite(CodeList* b);
237 #endif // __nanojit_CodeAlloc__