Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / nanojit / CodeAlloc.h
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
5  *
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/
10  *
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
14  * License.
15  *
16  * The Original Code is [Open Source Virtual Machine].
17  *
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.
22  *
23  * Contributor(s):
24  *   Adobe AS3 Team
25  *
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.
37  *
38  * ***** END LICENSE BLOCK ***** */
39
40 #ifndef __nanojit_CodeAlloc__
41 #define __nanojit_CodeAlloc__
42
43 namespace nanojit
44 {
45     /**
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.
49      */
50     class CodeList
51     {
52         friend class CodeAlloc;
53
54         /** for making singly linked lists of blocks in any order */
55         CodeList* next;
56
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. */
60         CodeList* lower;
61
62         /** pointer to the heapblock terminal that represents the code chunk containing this block */
63         CodeList* terminator;
64
65         /** true if block is free, false otherwise */
66         bool isFree;
67
68         /** (only valid for terminator blocks).  Set true just before calling
69          * markCodeChunkExec() and false just after markCodeChunkWrite() */
70         bool isExec;
71
72         union {
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
77         };
78
79         /** code holds this block's payload of binary code, from
80             here to this->end */
81         NIns  code[1]; // more follows
82
83         /** return the starting address for this block only */
84         NIns* start() { return &code[0]; }
85
86         /** return just the usable size of this block */
87         size_t size() const { return uintptr_t(end) - uintptr_t(&code[0]); }
88
89         /** return the whole size of this block including overhead */
90         size_t blockSize() const { return uintptr_t(end) - uintptr_t(this); }
91
92     public:
93         /** true is the given NIns is contained within this block */
94         bool isInBlock(NIns* n) { return (n >= this->start() && n < this->end); }
95     };
96
97     /**
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.
105      *
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.
108      *
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.
113      *
114      * The allocator coalesces free blocks when it can, in free(), but never
115      * coalesces chunks.
116      */
117     class CodeAlloc
118     {
119         static const size_t sizeofMinBlock = offsetof(CodeList, code);
120         static const size_t minAllocSize = LARGEST_UNDERRUN_PROT;
121
122         // Return the number of bytes needed for the header of 'n' blocks
123         static size_t headerSpaceFor(uint32_t nbrBlks)  { return nbrBlks * sizeofMinBlock; }
124
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); }
127
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;
132
133         /** Reusable blocks. */
134         CodeList* availblocks;
135         size_t totalAllocated;
136
137         /** Cached value of VMPI_getVMPageSize */
138         const size_t bytesPerPage;
139
140         /** Number of bytes to request from VMPI layer, always a multiple of the page size */
141         const size_t bytesPerAlloc;
142
143         /** remove one block from a list */
144         static CodeList* removeBlock(CodeList* &list);
145
146         /** add one block to a list */
147         static void addBlock(CodeList* &blocks, CodeList* b);
148
149         /** compute the CodeList pointer from a [start, end) range */
150         static CodeList* getBlock(NIns* start, NIns* end);
151
152         /** add raw memory to the free list */
153         void addMem();
154
155         /** make sure all the higher/lower pointers are correct for every block */
156         void sanity_check();
157
158         /** find the beginning of the heapblock terminated by term */
159         CodeList* firstBlock(CodeList* term);
160
161         //
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.
165         //
166
167         /** allocate nbytes of memory to hold code.  Never return null! */
168         void* allocCodeChunk(size_t nbytes);
169
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()
174          * to do it again. */
175         void freeCodeChunk(void* addr, size_t nbytes);
176
177         /** make this specific extent ready to execute (might remove write) */
178         void markCodeChunkExec(void* addr, size_t nbytes);
179
180         /** make this extent ready to modify (might remove exec) */
181         void markCodeChunkWrite(void* addr, size_t nbytes);
182
183     public:
184         CodeAlloc();
185         ~CodeAlloc();
186
187         /** return all the memory allocated through this allocator to the gcheap. */
188         void reset();
189
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);
192
193         /** free a block of memory previously returned by alloc() */
194         void free(NIns* start, NIns* end);
195
196         /** free several blocks */
197         void freeAll(CodeList* &code);
198
199         /** flush the icache for all code in the list, before executing */
200         static void flushICache(CodeList* &blocks);
201
202         /** flush the icache for a specific extent */
203         static void flushICache(void *start, size_t len);
204
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);
208
209         /** add a block previously returned by alloc(), to code */
210         static void add(CodeList* &code, NIns* start, NIns* end);
211
212         /** return the number of bytes in all the code blocks in "code", including block overhead */
213 #ifdef PERFM
214         static size_t size(const CodeList* code);
215 #endif
216
217         /** return the total number of bytes held by this CodeAlloc. */
218         size_t size();
219
220         /** print out stats about heap usage */
221         void logStats();
222
223         /** protect all code managed by this CodeAlloc */
224         void markAllExec();
225
226         /** protect all mem in the block list */
227         void markExec(CodeList* &blocks);
228
229         /** protect an entire chunk */
230         void markChunkExec(CodeList* term);
231
232         /** unprotect the code chunk containing just this one block */
233         void markBlockWrite(CodeList* b);
234     };
235 }
236
237 #endif // __nanojit_CodeAlloc__