2009-07-10 11:21:53 -07:00
|
|
|
/* -*- 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
|
|
|
|
{
|
|
|
|
/**
|
2009-07-10 12:58:34 -07:00
|
|
|
* CodeList is a linked list of non-contigous blocks of code. Clients use CodeList*
|
2009-07-10 11:21:53 -07:00
|
|
|
* to point to a list, and each CodeList instance tracks a single contiguous
|
|
|
|
* block of code.
|
|
|
|
*/
|
|
|
|
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;
|
|
|
|
|
2010-01-22 12:18:12 -08:00
|
|
|
/** pointer to the heapblock terminal that represents the code chunk containing this block */
|
|
|
|
CodeList* terminator;
|
|
|
|
|
2009-07-10 11:21:53 -07:00
|
|
|
/** true if block is free, false otherwise */
|
|
|
|
bool isFree;
|
2010-01-22 12:18:12 -08:00
|
|
|
|
|
|
|
/** (only valid for terminator blocks). Set true just before calling
|
|
|
|
* markCodeChunkExec() and false just after markCodeChunkWrite() */
|
|
|
|
bool isExec;
|
|
|
|
|
2009-07-10 11:21:53 -07:00
|
|
|
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); }
|
|
|
|
};
|
|
|
|
|
2009-07-10 12:58:34 -07:00
|
|
|
/**
|
|
|
|
* Code memory allocator.
|
2009-07-10 11:21:53 -07:00
|
|
|
* Long lived manager for many code blocks,
|
|
|
|
* manages interaction with an underlying code memory allocator,
|
|
|
|
* setting page permissions, api's for allocating and freeing
|
|
|
|
* individual blocks of code memory (for methods, stubs, or compiled
|
|
|
|
* traces), and also static functions for managing lists of allocated
|
|
|
|
* code.
|
2009-07-10 12:58:34 -07:00
|
|
|
*/
|
2009-08-04 11:53:56 -07:00
|
|
|
class CodeAlloc
|
2009-07-10 12:58:34 -07:00
|
|
|
{
|
2009-07-10 11:21:53 -07:00
|
|
|
static const size_t sizeofMinBlock = offsetof(CodeList, code);
|
|
|
|
static const size_t minAllocSize = LARGEST_UNDERRUN_PROT;
|
|
|
|
|
2009-07-15 16:50:01 -07:00
|
|
|
/** Terminator blocks. All active and free allocations
|
|
|
|
are reachable by traversing this chain and each
|
|
|
|
element's lower chain. */
|
2009-07-10 11:21:53 -07:00
|
|
|
CodeList* heapblocks;
|
|
|
|
|
2009-07-15 16:50:01 -07:00
|
|
|
/** Reusable blocks. */
|
|
|
|
CodeList* availblocks;
|
|
|
|
size_t totalAllocated;
|
|
|
|
|
2010-04-05 13:17:01 -07:00
|
|
|
/** Cached value of VMPI_getVMPageSize */
|
|
|
|
const size_t bytesPerPage;
|
2010-04-26 07:53:32 -07:00
|
|
|
|
2010-04-05 13:17:01 -07:00
|
|
|
/** Number of bytes to request from VMPI layer, always a multiple of the page size */
|
|
|
|
const size_t bytesPerAlloc;
|
|
|
|
|
2009-07-10 11:21:53 -07:00
|
|
|
/** 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 */
|
|
|
|
CodeList* addMem(void* mem, size_t bytes);
|
|
|
|
|
|
|
|
/** make sure all the higher/lower pointers are correct for every block */
|
|
|
|
void sanity_check();
|
|
|
|
|
|
|
|
/** find the beginning of the heapblock terminated by term */
|
2010-04-05 13:17:01 -07:00
|
|
|
CodeList* firstBlock(CodeList* term);
|
2009-07-10 11:21:53 -07:00
|
|
|
|
2009-07-15 16:50:01 -07:00
|
|
|
//
|
|
|
|
// CodeAlloc's SPI. 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
|
2010-01-22 12:18:12 -08:00
|
|
|
* to mirror the mmap()/munmap() api. markCodeChunkWrite() will have
|
|
|
|
* been called if necessary, so it is not necessary for freeCodeChunk()
|
|
|
|
* to do it again. */
|
2009-07-15 16:50:01 -07:00
|
|
|
void freeCodeChunk(void* addr, size_t nbytes);
|
|
|
|
|
2010-01-22 12:18:12 -08:00
|
|
|
/** 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);
|
|
|
|
|
2009-07-10 12:58:34 -07:00
|
|
|
public:
|
2009-07-15 16:50:01 -07:00
|
|
|
CodeAlloc();
|
2009-07-10 11:21:53 -07:00
|
|
|
~CodeAlloc();
|
|
|
|
|
2009-09-12 23:06:51 -07:00
|
|
|
/** return all the memory allocated through this allocator to the gcheap. */
|
|
|
|
void reset();
|
|
|
|
|
2009-07-10 11:21:53 -07:00
|
|
|
/** allocate some memory for code, return pointers to the region. */
|
|
|
|
void alloc(NIns* &start, NIns* &end);
|
|
|
|
|
|
|
|
/** 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 */
|
2009-10-21 16:26:52 -07:00
|
|
|
static void flushICache(CodeList* &blocks);
|
|
|
|
|
|
|
|
/** flush the icache for a specific extent */
|
|
|
|
static void flushICache(void *start, size_t len);
|
2009-07-10 11:21:53 -07:00
|
|
|
|
|
|
|
/** 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);
|
|
|
|
|
2009-07-15 16:50:01 -07:00
|
|
|
/** return the total number of bytes held by this CodeAlloc. */
|
|
|
|
size_t size();
|
|
|
|
|
2009-07-10 11:21:53 -07:00
|
|
|
/** print out stats about heap usage */
|
|
|
|
void logStats();
|
|
|
|
|
2010-01-22 12:18:12 -08:00
|
|
|
/** protect all code in this code alloc */
|
|
|
|
void markAllExec();
|
|
|
|
|
|
|
|
/** unprotect the code chunk containing just this one block */
|
|
|
|
void markBlockWrite(CodeList* b);
|
2009-07-10 12:58:34 -07:00
|
|
|
};
|
2009-07-10 11:21:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif // __nanojit_CodeAlloc__
|