/* -*- 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 { // Temporary tracemonkey hack until namespaces are sorted out. using namespace MMgc; /** return true if ptr is in the range [start, end) */ inline bool containsPtr(const NIns* start, const NIns* end, const NIns* ptr) { return ptr >= start && ptr < end; } /** * CodeList is a linked list of non-contigous blocks of code. Clients use CodeList* * 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; /** true if block is free, false otherwise */ bool isFree; 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); } /** return true if just this block contains p */ bool contains(NIns* p) const { return containsPtr(&code[0], end, p); } }; /** * Code memory allocator. * 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. */ class CodeAlloc : public GCFinalizedObject { static const size_t sizeofMinBlock = offsetof(CodeList, code); static const size_t minAllocSize = LARGEST_UNDERRUN_PROT; /** 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; /** 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 */ static CodeList* firstBlock(CodeList* term); // // 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 * to mirror the mmap()/munmap() api. */ void freeCodeChunk(void* addr, size_t nbytes); public: CodeAlloc(); ~CodeAlloc(); /** 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 */ void flushICache(CodeList* &blocks); /** 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); /** move all the code in list "from" to list "to", and leave from empty. */ static void moveAll(CodeList* &to, CodeList* &from); /** return true if any block in list "code" contains the code pointer p */ static bool contains(const CodeList* code, NIns* p); /** return the number of bytes in all the code blocks in "code", including block overhead */ static size_t size(const CodeList* code); /** return the total number of bytes held by this CodeAlloc. */ size_t size(); /** print out stats about heap usage */ void logStats(); enum CodePointerKind { kUnknown, kFree, kUsed }; /** determine whether the given address is not code, or is allocated or free */ CodePointerKind classifyPtr(NIns *p); /** return any completely empty pages */ void sweep(); }; } #endif // __nanojit_CodeAlloc__