Move the code cache into Environment, and out of knight/shared.
This commit is contained in:
parent
57ba8fd09b
commit
c70e87d582
@ -1,33 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include "KeCommon.h"
|
|
||||||
|
|
||||||
using namespace Knight;
|
|
||||||
|
|
||||||
size_t Knight::KE_PFormat(char *buffer, size_t maxlength, const char *fmt, ...)
|
|
||||||
{
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, fmt);
|
|
||||||
len = KE_PFormatArgs(buffer, maxlength, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Knight::KE_PFormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap)
|
|
||||||
{
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
len = vsnprintf(buffer, maxlength, fmt, ap);
|
|
||||||
|
|
||||||
if (len >= maxlength)
|
|
||||||
{
|
|
||||||
buffer[maxlength - 1] = '\0';
|
|
||||||
return (maxlength - 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
#ifndef _INCLUDE_KNIGHT_KE_COMMON_UTILS_H_
|
|
||||||
#define _INCLUDE_KNIGHT_KE_COMMON_UTILS_H_
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
namespace Knight
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @brief Formats a buffer with C platform rules.
|
|
||||||
*
|
|
||||||
* Unlink platform snprintf, this will never return nonsense values like -1.
|
|
||||||
*
|
|
||||||
* @param buffer Buffer to store to.
|
|
||||||
* @param maxlength Maximum length of buffer (including null terminator).
|
|
||||||
* @param fmt printf() format string.
|
|
||||||
* @param ... Formatting arguments.
|
|
||||||
* @return Number of characters written.
|
|
||||||
*/
|
|
||||||
extern size_t KE_PFormat(char *buffer, size_t maxlength, const char *fmt, ...);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Formats a buffer with C platform rules.
|
|
||||||
*
|
|
||||||
* Unlink platform snprintf, this will never return nonsense values like -1.
|
|
||||||
*
|
|
||||||
* @param buffer Buffer to store to.
|
|
||||||
* @param maxlength Maximum length of buffer (including null terminator).
|
|
||||||
* @param fmt printf() format string.
|
|
||||||
* @param args Formatting arguments.
|
|
||||||
* @return Number of characters written.
|
|
||||||
*/
|
|
||||||
extern size_t KE_PFormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list args);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //_INCLUDE_KNIGHT_KE_COMMON_UTILS_H_
|
|
@ -1,416 +0,0 @@
|
|||||||
#include <string.h>
|
|
||||||
#include <KeHashTable.h>
|
|
||||||
|
|
||||||
using namespace Knight;
|
|
||||||
|
|
||||||
struct KeHashNode
|
|
||||||
{
|
|
||||||
KeHashNode *next;
|
|
||||||
uint32_t key_hash;
|
|
||||||
const void *key;
|
|
||||||
void *value;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace Knight
|
|
||||||
{
|
|
||||||
class KeHashTable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
KeHashNode **buckets;
|
|
||||||
uint32_t num_buckets;
|
|
||||||
uint32_t shift;
|
|
||||||
uint32_t num_entries;
|
|
||||||
KeHashGenerator key_gen;
|
|
||||||
KeHashMarshal key_m;
|
|
||||||
KeHashMarshal val_m;
|
|
||||||
ke_allocator_t *node_alloc;
|
|
||||||
size_t key_offs;
|
|
||||||
size_t val_offs;
|
|
||||||
size_t node_size;
|
|
||||||
uint32_t grow_limit;
|
|
||||||
KeHashNode *free_list;
|
|
||||||
bool keep_free_list;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void *ke_DefHashMalloc(ke_allocator_t *alloc, size_t amt)
|
|
||||||
{
|
|
||||||
return malloc(amt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ke_DefHashFree(ke_allocator_t *alloc, void *addr)
|
|
||||||
{
|
|
||||||
free(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
ke_allocator_t s_DefHashAllocator =
|
|
||||||
{
|
|
||||||
ke_DefHashMalloc,
|
|
||||||
ke_DefHashFree,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
KeHashTable *Knight::KE_CreateHashTable(
|
|
||||||
uint32_t bits,
|
|
||||||
KeHashGenerator key_gen,
|
|
||||||
const KeHashMarshal *key_marshal,
|
|
||||||
const KeHashMarshal *val_marshal,
|
|
||||||
ke_allocator_t *nodeAlloc,
|
|
||||||
bool keep_free_list)
|
|
||||||
{
|
|
||||||
KeHashTable *table;
|
|
||||||
|
|
||||||
if (bits >= 27)
|
|
||||||
{
|
|
||||||
bits = 26;
|
|
||||||
}
|
|
||||||
else if (bits < 4)
|
|
||||||
{
|
|
||||||
bits = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Validate marshals. */
|
|
||||||
if ((key_marshal->bytes != 0
|
|
||||||
&& key_marshal->ctor == NULL)
|
|
||||||
|| (val_marshal->bytes != 0
|
|
||||||
&& val_marshal->ctor == NULL))
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
table = new KeHashTable;
|
|
||||||
table->key_gen = key_gen;
|
|
||||||
table->key_m = *key_marshal;
|
|
||||||
table->val_m = *val_marshal;
|
|
||||||
table->num_entries = 0;
|
|
||||||
table->shift = 32 - bits;
|
|
||||||
table->node_alloc = nodeAlloc == NULL ? &s_DefHashAllocator : nodeAlloc;
|
|
||||||
table->num_buckets = (1 << bits);
|
|
||||||
table->grow_limit = (uint32_t)(0.9f * table->num_buckets);
|
|
||||||
table->keep_free_list = keep_free_list;
|
|
||||||
table->free_list = NULL;
|
|
||||||
table->buckets = (KeHashNode **)malloc(sizeof(KeHashNode *) * table->num_buckets);
|
|
||||||
memset(table->buckets, 0, sizeof(KeHashNode *) * table->num_buckets);
|
|
||||||
|
|
||||||
table->key_offs = sizeof(KeHashNode);
|
|
||||||
if (table->key_m.bytes != 0 && table->key_m.bytes % 8 != 0)
|
|
||||||
{
|
|
||||||
table->key_m.bytes += 8;
|
|
||||||
table->key_m.bytes -= (table->key_m.bytes % 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
table->val_offs = table->key_offs + table->key_m.bytes;
|
|
||||||
table->node_size = table->val_offs + table->val_m.bytes;
|
|
||||||
|
|
||||||
return table;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define KE_GET_BUCKET(tbl, hsh) (&(tbl)->buckets[((hsh) * 0x9E3779B9) >> (tbl)->shift])
|
|
||||||
|
|
||||||
KeHashNode **ke_HashInternalFind(KeHashTable *table, uint32_t key_hash, const void *key)
|
|
||||||
{
|
|
||||||
KeHashNode *node;
|
|
||||||
KeHashNode **bucket;
|
|
||||||
|
|
||||||
bucket = KE_GET_BUCKET(table, key_hash);
|
|
||||||
|
|
||||||
/* :TODO: move to the front once found? */
|
|
||||||
|
|
||||||
while ((node = *bucket) != NULL)
|
|
||||||
{
|
|
||||||
if (node->key_hash == key_hash
|
|
||||||
&& ((table->key_m.cmp != NULL && table->key_m.cmp(node->key, key))
|
|
||||||
|| node->key == key))
|
|
||||||
{
|
|
||||||
return bucket;
|
|
||||||
}
|
|
||||||
bucket = &node->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return bucket;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ke_ResizeHashTable(KeHashTable *table, uint32_t new_shift)
|
|
||||||
{
|
|
||||||
uint32_t entries;
|
|
||||||
KeHashNode *next;
|
|
||||||
KeHashNode *node;
|
|
||||||
KeHashNode **rbucket;
|
|
||||||
KeHashNode **old_buckets;
|
|
||||||
uint32_t old_num_buckets;
|
|
||||||
|
|
||||||
/* Save old data */
|
|
||||||
old_num_buckets = table->num_buckets;
|
|
||||||
old_buckets = table->buckets;
|
|
||||||
entries = table->num_entries;
|
|
||||||
|
|
||||||
/* Save new data */
|
|
||||||
table->num_buckets = (1 << new_shift);
|
|
||||||
table->shift = 32 - new_shift;
|
|
||||||
table->grow_limit = (uint32_t)(0.9f * table->num_buckets);
|
|
||||||
|
|
||||||
table->buckets = (KeHashNode **)malloc(sizeof(KeHashNode *) * table->num_buckets);
|
|
||||||
memset(table->buckets, 0, sizeof(KeHashNode *) * table->num_buckets);
|
|
||||||
|
|
||||||
/* For each old bucket... */
|
|
||||||
for (uint32_t i = 0;
|
|
||||||
i < old_num_buckets && entries != 0;
|
|
||||||
i++)
|
|
||||||
{
|
|
||||||
node = old_buckets[i];
|
|
||||||
/* Get each item in its list... */
|
|
||||||
while (node != NULL)
|
|
||||||
{
|
|
||||||
next = node->next;
|
|
||||||
|
|
||||||
/* Find the new replacement bucket it needs to go in. */
|
|
||||||
rbucket = KE_GET_BUCKET(table, node->key_hash);
|
|
||||||
|
|
||||||
/* Link this node to the next node in the new bucket. */
|
|
||||||
if (*rbucket == NULL)
|
|
||||||
{
|
|
||||||
node->next = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node->next = *rbucket;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add us to the front of that bucket's list. */
|
|
||||||
*rbucket = node;
|
|
||||||
|
|
||||||
node = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(old_buckets);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Knight::KE_AddToHashTable(KeHashTable *table, const void *key, void *val)
|
|
||||||
{
|
|
||||||
KeHashNode *node;
|
|
||||||
uint32_t key_hash;
|
|
||||||
KeHashNode **bucket;
|
|
||||||
|
|
||||||
key_hash = table->key_gen(key);
|
|
||||||
bucket = ke_HashInternalFind(table, key_hash, key);
|
|
||||||
|
|
||||||
if ((node = *bucket) != NULL)
|
|
||||||
{
|
|
||||||
/* Already in the table */
|
|
||||||
if ((table->val_m.cmp != NULL && table->val_m.cmp(node->value, val))
|
|
||||||
|| node->value == val)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Destroy old value if it's set. */
|
|
||||||
if (node->value != NULL && table->val_m.dtor != NULL)
|
|
||||||
{
|
|
||||||
table->val_m.dtor(node->value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Construct or set the new value. */
|
|
||||||
if (table->val_m.bytes != 0)
|
|
||||||
{
|
|
||||||
table->val_m.ctor(node->value, val);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node->value = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we're overloaded, we may need to resize.
|
|
||||||
* Right now, we do this if we hit a .9 entry:buckets ratio.
|
|
||||||
*/
|
|
||||||
if (table->num_entries >= table->grow_limit)
|
|
||||||
{
|
|
||||||
ke_ResizeHashTable(table, table->shift << 1);
|
|
||||||
bucket = ke_HashInternalFind(table, key_hash, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (table->free_list != NULL)
|
|
||||||
{
|
|
||||||
node = table->free_list;
|
|
||||||
table->free_list = node->next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node = (KeHashNode *)table->node_alloc->alloc(table->node_alloc, table->node_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (table->key_m.bytes == 0)
|
|
||||||
{
|
|
||||||
node->key = key;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node->key = (char *)node + table->key_offs;
|
|
||||||
table->key_m.ctor((void *)node->key, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (table->val_m.bytes == 0)
|
|
||||||
{
|
|
||||||
node->value = val;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node->value = (char *)node + table->val_offs;
|
|
||||||
table->val_m.ctor(node->value, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
node->next = *bucket;
|
|
||||||
node->key_hash = key_hash;
|
|
||||||
*bucket = node;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void ke_CleanUpHashNode(KeHashTable *table, KeHashNode *node)
|
|
||||||
{
|
|
||||||
/* Destroy old value if it's set. */
|
|
||||||
if (node->value != NULL && table->val_m.dtor != NULL)
|
|
||||||
{
|
|
||||||
table->val_m.dtor(node->value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Destroy the key. */
|
|
||||||
if (table->key_m.dtor != NULL)
|
|
||||||
{
|
|
||||||
table->key_m.dtor(node->key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Deallocate us as appropriate. */
|
|
||||||
if (table->keep_free_list)
|
|
||||||
{
|
|
||||||
node->next = table->free_list;
|
|
||||||
table->free_list = node;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
table->node_alloc->dealloc(table->node_alloc, node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Knight::KE_RemoveFromHashTable(KeHashTable *table, const void *key)
|
|
||||||
{
|
|
||||||
KeHashNode *node;
|
|
||||||
uint32_t key_hash;
|
|
||||||
KeHashNode **bucket;
|
|
||||||
|
|
||||||
key_hash = table->key_gen(key);
|
|
||||||
bucket = ke_HashInternalFind(table, key_hash, key);
|
|
||||||
|
|
||||||
if ((node = *bucket) == NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Link the bucket to its next (removing us). */
|
|
||||||
*bucket = node->next;
|
|
||||||
|
|
||||||
ke_CleanUpHashNode(table, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Knight::KE_FindInHashTable(KeHashTable *table, const void *key, void **value)
|
|
||||||
{
|
|
||||||
KeHashNode *node;
|
|
||||||
uint32_t key_hash;
|
|
||||||
KeHashNode **bucket;
|
|
||||||
|
|
||||||
key_hash = table->key_gen(key);
|
|
||||||
bucket = ke_HashInternalFind(table, key_hash, key);
|
|
||||||
|
|
||||||
if ((node = *bucket) == NULL)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value != NULL)
|
|
||||||
{
|
|
||||||
*value = node->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Knight::KE_DestroyHashTable(KeHashTable *table)
|
|
||||||
{
|
|
||||||
KeHashNode *node, *next;
|
|
||||||
|
|
||||||
/* Turn off this caching! */
|
|
||||||
table->keep_free_list = false;
|
|
||||||
|
|
||||||
/* Find entries in buckets that need to be freed. */
|
|
||||||
for (uint32_t i = 0; i < table->num_buckets; i++)
|
|
||||||
{
|
|
||||||
node = table->buckets[i];
|
|
||||||
|
|
||||||
while (node != NULL)
|
|
||||||
{
|
|
||||||
next = node->next;
|
|
||||||
ke_CleanUpHashNode(table, node);
|
|
||||||
node = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free the free list */
|
|
||||||
while (table->free_list != NULL)
|
|
||||||
{
|
|
||||||
next = table->free_list->next;
|
|
||||||
ke_CleanUpHashNode(table, table->free_list);
|
|
||||||
table->free_list = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Destroy everything now. */
|
|
||||||
free(table->buckets);
|
|
||||||
delete table;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Knight::KE_ClearHashTable(KeHashTable *table)
|
|
||||||
{
|
|
||||||
KeHashNode *node, *next;
|
|
||||||
|
|
||||||
/* Free every entry in the table. */
|
|
||||||
for (uint32_t i = 0; i < table->num_buckets; i++)
|
|
||||||
{
|
|
||||||
node = table->buckets[i];
|
|
||||||
|
|
||||||
while (node != NULL)
|
|
||||||
{
|
|
||||||
next = node->next;
|
|
||||||
ke_CleanUpHashNode(table, node);
|
|
||||||
node = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined _MSC_VER && (defined _M_IX86 || defined _M_AMD64 || defined _M_X64)
|
|
||||||
#pragma intrinsic(_rotl)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint32_t Knight::KE_HashString(const void *str)
|
|
||||||
{
|
|
||||||
uint32_t h;
|
|
||||||
const unsigned char *us;
|
|
||||||
|
|
||||||
h = 0;
|
|
||||||
|
|
||||||
for (us = (const unsigned char *)str; *us != 0; us++)
|
|
||||||
{
|
|
||||||
#if defined _MSC_VER && (defined _M_IX86 || defined _M_AMD64 || defined _M_X64)
|
|
||||||
h = _rotl(h, 4) ^ *us;
|
|
||||||
#else
|
|
||||||
h = ((h << 4) | (h >> 28)) ^ *us;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Knight::KE_AreStringsEqual(const void* str1, const void* str2)
|
|
||||||
{
|
|
||||||
return (strcmp((const char*)str1, (const char*)str2) == 0) ? true : false;
|
|
||||||
}
|
|
||||||
|
|
@ -1,139 +0,0 @@
|
|||||||
#ifndef _INCLUDE_KNIGHT_KE_HASHTABLE_H_
|
|
||||||
#define _INCLUDE_KNIGHT_KE_HASHTABLE_H_
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <KnightAllocator.h>
|
|
||||||
|
|
||||||
namespace Knight
|
|
||||||
{
|
|
||||||
class KeHashTable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Must generate a hash function given a key.
|
|
||||||
*
|
|
||||||
* @param key Pointer to the key.
|
|
||||||
* @return Hash value.
|
|
||||||
*/
|
|
||||||
typedef uint32_t (*KeHashGenerator)(const void *key);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Must compare two values.
|
|
||||||
*
|
|
||||||
* @param val1 First value.
|
|
||||||
* @param val2 Second value.
|
|
||||||
* @return True if equal, false if not.
|
|
||||||
*/
|
|
||||||
typedef bool (*KeHashComparator)(const void *val1, const void *val2);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Must call the destructor of the given data, and free if necessary.
|
|
||||||
*
|
|
||||||
* @param val Pointer to data.
|
|
||||||
*/
|
|
||||||
typedef void (*KeHashDestructor)(const void *val);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Must transfer the contents of an object from the source to the destination.
|
|
||||||
*
|
|
||||||
* @param dest Destination address.
|
|
||||||
* @param source Source address.
|
|
||||||
*/
|
|
||||||
typedef void (*KeHashCopyCtor)(void *dest, const void *source);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Contains information about how to process keys and values in a hash table.
|
|
||||||
*/
|
|
||||||
struct KeHashMarshal
|
|
||||||
{
|
|
||||||
size_t bytes; /**< Bytes of storage needed (0 to use pointers). */
|
|
||||||
KeHashComparator cmp; /**< Comparator (if NULL, void * comparison used) */
|
|
||||||
KeHashDestructor dtor; /**< Optional function for performing dtor cleanup. */
|
|
||||||
KeHashCopyCtor ctor; /**< If bytes != 0, must be a valid function
|
|
||||||
(ignored otherwise). */
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Creates a new hash table structure.
|
|
||||||
*
|
|
||||||
* @param bits Dictates starting number of buckets as a power of two.
|
|
||||||
* Pass 0 for the default (which is 4).
|
|
||||||
* @param key_gen Key generation function.
|
|
||||||
* @param key_marshal Structure detailing how to marshal keys.
|
|
||||||
* @param vak_marshal Structure detailing how to marshal values.
|
|
||||||
* @param nodeAlloc Node allocator (can be NULL for malloc/free).
|
|
||||||
* @param keep_free_list True to keep a free list of nodes, false otherwise.
|
|
||||||
* @return New hash table container.
|
|
||||||
*/
|
|
||||||
extern KeHashTable *KE_CreateHashTable(
|
|
||||||
uint32_t bits,
|
|
||||||
KeHashGenerator key_gen,
|
|
||||||
const KeHashMarshal *key_marshal,
|
|
||||||
const KeHashMarshal *val_marshal,
|
|
||||||
ke_allocator_t *nodeAlloc,
|
|
||||||
bool keep_free_list
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Destroys a hash table.
|
|
||||||
*
|
|
||||||
* @param table Hash table.
|
|
||||||
*/
|
|
||||||
extern void KE_DestroyHashTable(KeHashTable *table);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Adds a key/value to the hash table. If the pair already exists, the old value
|
|
||||||
* is overwritten (calling any destructors as necessary).
|
|
||||||
*
|
|
||||||
* @param table Hash table.
|
|
||||||
* @param key Key pointer.
|
|
||||||
* @param val Value pointer.
|
|
||||||
*/
|
|
||||||
extern void KE_AddToHashTable(KeHashTable *table, const void *key, void *val);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Removes a key entry from the hash table.
|
|
||||||
*
|
|
||||||
* @param table Hash table.
|
|
||||||
* @param key Key pointer.
|
|
||||||
*/
|
|
||||||
extern void KE_RemoveFromHashTable(KeHashTable *table, const void *key);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Finds an entry in the hash table.
|
|
||||||
*
|
|
||||||
* @param table Hash table.
|
|
||||||
* @param key Key pointer.
|
|
||||||
* @param value Pointer to store the value (optional).
|
|
||||||
* @return On success, true is returned and value is filled if given.
|
|
||||||
* On failure, false is failed and outputs are undefined.
|
|
||||||
*/
|
|
||||||
extern bool KE_FindInHashTable(KeHashTable *table, const void *key, void **value);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Clears all entries in the hash table (caching free entries when possible).
|
|
||||||
*
|
|
||||||
* @param table Hash table.
|
|
||||||
*/
|
|
||||||
extern void KE_ClearHashTable(KeHashTable *table);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Generic function for hashing strings.
|
|
||||||
*
|
|
||||||
* @param str Key string.
|
|
||||||
* @return Hash value.
|
|
||||||
*/
|
|
||||||
extern uint32_t KE_HashString(const void *str);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Generic case-sensitive comparison of strings.
|
|
||||||
*
|
|
||||||
* @param str1 First string.
|
|
||||||
* @param str2 Second string.
|
|
||||||
* @return True if equal, false otherwise.
|
|
||||||
*/
|
|
||||||
extern bool KE_AreStringsEqual(const void* str1, const void* str2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //_INCLUDE_KNIGHT_KE_HASHTABLE_H_
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
|||||||
#ifndef _INCLUDE_KNIGHT_LINKING_H_
|
|
||||||
#define _INCLUDE_KNIGHT_LINKING_H_
|
|
||||||
|
|
||||||
#if defined KE_LINK_IMPORT
|
|
||||||
#error "Not yet supported"
|
|
||||||
#elif defined KE_LINK_EXPORT
|
|
||||||
#error "Not yet supported"
|
|
||||||
#else
|
|
||||||
#define KE_LINK
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif //_INCLUDE_KNIGHT_LINKING_H_
|
|
@ -1,263 +0,0 @@
|
|||||||
#include "KePlatform.h"
|
|
||||||
#include <KeLumpAllocator.h>
|
|
||||||
#include <KeVector.h>
|
|
||||||
|
|
||||||
using namespace Knight;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* :TODO: don't make this part of the page, because touching it means
|
|
||||||
* dirtying a page. Instead, we should have a separate linked list.
|
|
||||||
* Maybe that linked list itself could be marshalled from one page.
|
|
||||||
*/
|
|
||||||
struct KeLumpRegion
|
|
||||||
{
|
|
||||||
char *base;
|
|
||||||
char *cur;
|
|
||||||
size_t size;
|
|
||||||
size_t avail;
|
|
||||||
KeLumpRegion *next;
|
|
||||||
KeLumpRegion *prev;
|
|
||||||
};
|
|
||||||
|
|
||||||
class KeLumpAllocator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
KeLumpAllocator() : m_pUsableRegions(NULL), m_pUnusableRegions(NULL)
|
|
||||||
{
|
|
||||||
m_DefLumpSize = 65536;
|
|
||||||
|
|
||||||
#if defined KE_PLATFORM_WINDOWS
|
|
||||||
SYSTEM_INFO info;
|
|
||||||
|
|
||||||
GetSystemInfo(&info);
|
|
||||||
if (info.dwAllocationGranularity > m_DefLumpSize)
|
|
||||||
{
|
|
||||||
m_DefLumpSize = info.dwAllocationGranularity;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
~KeLumpAllocator()
|
|
||||||
{
|
|
||||||
FreeRegionChain(m_pUsableRegions);
|
|
||||||
FreeRegionChain(m_pUnusableRegions);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reset()
|
|
||||||
{
|
|
||||||
KeLumpRegion *region;
|
|
||||||
|
|
||||||
/* Find the tail of the usable regions. */
|
|
||||||
region = m_pUsableRegions;
|
|
||||||
while (region != NULL)
|
|
||||||
{
|
|
||||||
if (region->next == NULL)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Link the unusable chain into the usable chain. */
|
|
||||||
if (region == NULL)
|
|
||||||
{
|
|
||||||
m_pUsableRegions = m_pUnusableRegions;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
region->next = m_pUnusableRegions;
|
|
||||||
m_pUnusableRegions->prev = region;
|
|
||||||
}
|
|
||||||
m_pUnusableRegions = NULL;
|
|
||||||
|
|
||||||
region = m_pUsableRegions;
|
|
||||||
while (region != NULL)
|
|
||||||
{
|
|
||||||
region->avail = region->size;
|
|
||||||
region->cur = region->base;
|
|
||||||
region = region->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FreeRegionChain(KeLumpRegion *region)
|
|
||||||
{
|
|
||||||
KeLumpRegion *next;
|
|
||||||
|
|
||||||
while (region != NULL)
|
|
||||||
{
|
|
||||||
next = region->next;
|
|
||||||
|
|
||||||
#if defined KE_PLATFORM_WINDOWS
|
|
||||||
VirtualFree(region, 0, MEM_RELEASE);
|
|
||||||
#else
|
|
||||||
free(region);
|
|
||||||
#endif
|
|
||||||
region = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void *Alloc(size_t size)
|
|
||||||
{
|
|
||||||
char *blob;
|
|
||||||
KeLumpRegion *region;
|
|
||||||
|
|
||||||
if (size % 8 != 0)
|
|
||||||
{
|
|
||||||
size += 8;
|
|
||||||
size -= size % 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
region = FindRegionForSize(size);
|
|
||||||
|
|
||||||
blob = region->cur;
|
|
||||||
region->avail -= size;
|
|
||||||
region->cur += size;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Technically we could make one last small allocation, but
|
|
||||||
* this edge case is not worth the extra work.
|
|
||||||
*/
|
|
||||||
if (region->avail < 8)
|
|
||||||
{
|
|
||||||
/* Unlink us from the usable list */
|
|
||||||
if (region == m_pUsableRegions)
|
|
||||||
{
|
|
||||||
m_pUsableRegions = m_pUsableRegions->next;
|
|
||||||
m_pUsableRegions->prev = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
region->prev->next = region->next;
|
|
||||||
if (region->next != NULL)
|
|
||||||
{
|
|
||||||
region->next->prev = region->prev;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Link us into the unusable list */
|
|
||||||
region->prev = NULL;
|
|
||||||
region->next = m_pUnusableRegions;
|
|
||||||
|
|
||||||
if (m_pUnusableRegions != NULL)
|
|
||||||
{
|
|
||||||
m_pUnusableRegions->prev = region;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_pUnusableRegions = region;
|
|
||||||
}
|
|
||||||
|
|
||||||
return blob;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
KeLumpRegion *FindRegionForSize(size_t size)
|
|
||||||
{
|
|
||||||
char *base;
|
|
||||||
KeLumpRegion *region;
|
|
||||||
size_t size_of_region;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* :TODO: replace this with a priority queue or something
|
|
||||||
* that's actually fast. Even worse is we dirty pages by
|
|
||||||
* doing this. Ouch!
|
|
||||||
*/
|
|
||||||
region = m_pUsableRegions;
|
|
||||||
while (region != NULL)
|
|
||||||
{
|
|
||||||
if (region->avail >= size)
|
|
||||||
{
|
|
||||||
return region;
|
|
||||||
}
|
|
||||||
region = region->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure regions end at 8-byte alignment. */
|
|
||||||
size_of_region = sizeof(KeLumpRegion);
|
|
||||||
if (size_of_region % 8 != 0)
|
|
||||||
{
|
|
||||||
size_of_region += 8;
|
|
||||||
size_of_region -= size_of_region % 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the size is too big, fix that. */
|
|
||||||
if (size > m_DefLumpSize - size_of_region)
|
|
||||||
{
|
|
||||||
size += m_DefLumpSize;
|
|
||||||
size -= size % m_DefLumpSize;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
size = m_DefLumpSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined KE_PLATFORM_WINDOWS
|
|
||||||
base = (char *)VirtualAlloc(
|
|
||||||
NULL,
|
|
||||||
m_DefLumpSize,
|
|
||||||
MEM_COMMIT|MEM_RESERVE,
|
|
||||||
PAGE_READWRITE);
|
|
||||||
#else
|
|
||||||
base = (char*)valloc(m_DefLumpSize);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Initialize the region */
|
|
||||||
region = (KeLumpRegion *)base;
|
|
||||||
region->base = &base[size_of_region];
|
|
||||||
region->size = size - size_of_region;
|
|
||||||
region->cur = region->base;
|
|
||||||
region->avail = region->size;
|
|
||||||
region->prev = NULL;
|
|
||||||
region->next = m_pUsableRegions;
|
|
||||||
|
|
||||||
if (m_pUsableRegions != NULL)
|
|
||||||
{
|
|
||||||
m_pUsableRegions->prev = region;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_pUsableRegions = region;
|
|
||||||
|
|
||||||
return region;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
KeLumpRegion *m_pUsableRegions;
|
|
||||||
KeLumpRegion *m_pUnusableRegions;
|
|
||||||
size_t m_DefLumpSize;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline KeLumpAllocator *ke_LumpFromAllocator(ke_allocator_t *arena)
|
|
||||||
{
|
|
||||||
return (KeLumpAllocator *)arena->user;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *ke_LumpAlloc(ke_allocator_t *arena, size_t size)
|
|
||||||
{
|
|
||||||
return ke_LumpFromAllocator(arena)->Alloc(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ke_LumpFree(ke_allocator_t *arena, void *ptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ke_allocator_t * KE_LINK Knight::KE_CreateLumpAllocator()
|
|
||||||
{
|
|
||||||
ke_allocator_t *alloc;
|
|
||||||
|
|
||||||
alloc = new ke_allocator_t;
|
|
||||||
alloc->alloc = ke_LumpAlloc;
|
|
||||||
alloc->dealloc = ke_LumpFree;
|
|
||||||
alloc->user = new KeLumpAllocator();
|
|
||||||
|
|
||||||
return alloc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void KE_LINK Knight::KE_DestroyLumpAllocator(ke_allocator_t *alloc)
|
|
||||||
{
|
|
||||||
delete ke_LumpFromAllocator(alloc);
|
|
||||||
delete alloc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void KE_LINK Knight::KE_ResetLumpAllocator(ke_allocator_t *alloc)
|
|
||||||
{
|
|
||||||
ke_LumpFromAllocator(alloc)->Reset();
|
|
||||||
}
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
|||||||
#ifndef _INCLUDE_KNIGHT_KE_LUMP_ALLOCATOR_H_
|
|
||||||
#define _INCLUDE_KNIGHT_KE_LUMP_ALLOCATOR_H_
|
|
||||||
|
|
||||||
#include <KeLinking.h>
|
|
||||||
#include <KnightAllocator.h>
|
|
||||||
|
|
||||||
namespace Knight
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @brief Creates a new lump allocator.
|
|
||||||
*
|
|
||||||
* The lump allocator is intended for cases where there are many allocations
|
|
||||||
* and none need to be freed. There is memory wastage, and the lump allocator
|
|
||||||
* is typically thrown away after use.
|
|
||||||
*
|
|
||||||
* @return New lump allocator.
|
|
||||||
*/
|
|
||||||
extern ke_allocator_t * KE_CreateLumpAllocator();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Destroys a lump allocator, freeing all of its resources.
|
|
||||||
*
|
|
||||||
* @param lump Lump allocator.
|
|
||||||
*/
|
|
||||||
extern void KE_DestroyLumpAllocator(ke_allocator_t *alloc);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Clears a lump allocator, so its memory can be re-used from
|
|
||||||
* the start.
|
|
||||||
*
|
|
||||||
* @param lump Lump allocator.
|
|
||||||
*/
|
|
||||||
extern void KE_ResetLumpAllocator(ke_allocator_t *alloc);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //_INCLUDE_KNIGHT_KE_LUMP_ALLOCATOR_H_
|
|
@ -1,148 +0,0 @@
|
|||||||
#include "KePageAllocator.h"
|
|
||||||
|
|
||||||
using namespace Knight;
|
|
||||||
|
|
||||||
struct PageInfo
|
|
||||||
{
|
|
||||||
PageInfo *next;
|
|
||||||
void *base;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Knight::KePageAllocator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
size_t page_size;
|
|
||||||
size_t page_granularity;
|
|
||||||
PageInfo *free_pages;
|
|
||||||
PageInfo *page_blocks;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void *ke_LumpPageAlloc(KePageAllocator *alloc)
|
|
||||||
{
|
|
||||||
void *base;
|
|
||||||
char *page;
|
|
||||||
PageInfo *lump;
|
|
||||||
size_t pagesInBlock;
|
|
||||||
|
|
||||||
#if defined KE_PLATFORM_WINDOWS
|
|
||||||
base = VirtualAlloc(
|
|
||||||
NULL,
|
|
||||||
alloc->page_granularity,
|
|
||||||
MEM_COMMIT|MEM_RESERVE,
|
|
||||||
PAGE_READWRITE);
|
|
||||||
#elif defined KE_PLATFORM_POSIX
|
|
||||||
base = valloc(alloc->page_granularity);
|
|
||||||
#else
|
|
||||||
#error "Unsupported platform"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (base == NULL)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
lump = new PageInfo;
|
|
||||||
lump->base = base;
|
|
||||||
lump->next = alloc->page_blocks;
|
|
||||||
alloc->page_blocks = lump->next;
|
|
||||||
|
|
||||||
page = (char *)base + alloc->page_size;
|
|
||||||
pagesInBlock = alloc->page_granularity / alloc->page_size;
|
|
||||||
|
|
||||||
for (size_t i = 1; i < pagesInBlock; i++)
|
|
||||||
{
|
|
||||||
lump = new PageInfo;
|
|
||||||
lump->base = page;
|
|
||||||
lump->next = alloc->free_pages;
|
|
||||||
alloc->free_pages = lump;
|
|
||||||
page += alloc->page_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base;
|
|
||||||
}
|
|
||||||
|
|
||||||
KePageAllocator *Knight::KE_CreatePageAllocator()
|
|
||||||
{
|
|
||||||
KePageAllocator *alloc;
|
|
||||||
|
|
||||||
alloc = new KePageAllocator;
|
|
||||||
|
|
||||||
#if defined KE_PLATFORM_WINDOWS
|
|
||||||
SYSTEM_INFO info;
|
|
||||||
|
|
||||||
GetSystemInfo(&info);
|
|
||||||
alloc->page_size = info.dwPageSize;
|
|
||||||
alloc->page_granularity = info.dwAllocationGranularity;
|
|
||||||
#elif defined KE_PLATFORM_POSIX
|
|
||||||
alloc->page_size = sysconf(_SC_PAGESIZE);
|
|
||||||
alloc->page_granularity = alloc->page_size * 16;
|
|
||||||
#else
|
|
||||||
#error "Unsupported platform"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
alloc->free_pages = NULL;
|
|
||||||
alloc->page_blocks = NULL;
|
|
||||||
|
|
||||||
return alloc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Knight::KE_DestroyPageAllocator(KePageAllocator *alloc)
|
|
||||||
{
|
|
||||||
PageInfo *info, *next;
|
|
||||||
|
|
||||||
info = alloc->page_blocks;
|
|
||||||
while (info != NULL)
|
|
||||||
{
|
|
||||||
next = info->next;
|
|
||||||
#if defined KE_PLATFORM_WINDOWS
|
|
||||||
VirtualFree(info->base, 0, MEM_RELEASE);
|
|
||||||
#elif defined KE_PLATFORM_WINDOWS
|
|
||||||
free(info->base);
|
|
||||||
#else
|
|
||||||
#error "Unsupported platform"
|
|
||||||
#endif
|
|
||||||
delete info;
|
|
||||||
next = info;
|
|
||||||
}
|
|
||||||
|
|
||||||
info = alloc->free_pages;
|
|
||||||
while (info != NULL)
|
|
||||||
{
|
|
||||||
next = info->next;
|
|
||||||
delete info;
|
|
||||||
info = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void *Knight::KE_PageAlloc(KePageAllocator *alloc)
|
|
||||||
{
|
|
||||||
if (alloc->free_pages != NULL)
|
|
||||||
{
|
|
||||||
void *base;
|
|
||||||
PageInfo *info;
|
|
||||||
|
|
||||||
info = alloc->free_pages;
|
|
||||||
alloc->free_pages = info->next;
|
|
||||||
base = info->base;
|
|
||||||
delete info;
|
|
||||||
|
|
||||||
return base;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ke_LumpPageAlloc(alloc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Knight::KE_PageFree(KePageAllocator *alloc, void *page)
|
|
||||||
{
|
|
||||||
PageInfo *info;
|
|
||||||
|
|
||||||
info = new PageInfo;
|
|
||||||
info->base = page;
|
|
||||||
info->next = alloc->free_pages;
|
|
||||||
alloc->free_pages = info->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Knight::KE_PageSize(KePageAllocator *alloc)
|
|
||||||
{
|
|
||||||
return alloc->page_size;
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
#ifndef _INCLUDE_KNIGHT_KE_PAGE_ALLOCATOR_H_
|
|
||||||
#define _INCLUDE_KNIGHT_KE_PAGE_ALLOCATOR_H_
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
namespace Knight
|
|
||||||
{
|
|
||||||
class KePageAllocator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Creates a page allocator.
|
|
||||||
*
|
|
||||||
* @return New page allocator.
|
|
||||||
*/
|
|
||||||
extern KePageAllocator *KE_CreatePageAllocator();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Destroys a page allocator, freeing all live pages it owns.
|
|
||||||
*
|
|
||||||
* @param Page allocator.
|
|
||||||
*/
|
|
||||||
extern void KE_DestroyPageAllocator(KePageAllocator *alloc);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Allocates a page of memory.
|
|
||||||
*
|
|
||||||
* @param alloc Page allocator.
|
|
||||||
* @return Page of memory.
|
|
||||||
*/
|
|
||||||
extern void *KE_PageAlloc(KePageAllocator *alloc);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Frees a page of memory.
|
|
||||||
*
|
|
||||||
* @param alloc Page allocator.
|
|
||||||
* @param page Page of memory.
|
|
||||||
*/
|
|
||||||
extern void KE_PageFree(KePageAllocator *alloc, void *page);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the size of a page.
|
|
||||||
*
|
|
||||||
* @param alloc Page allocator.
|
|
||||||
* @return Page size.
|
|
||||||
*/
|
|
||||||
extern size_t KE_PageSize(KePageAllocator *alloc);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //_INCLUDE_KNIGHT_KE_PAGE_ALLOCATOR_H_
|
|
@ -1,29 +0,0 @@
|
|||||||
#ifndef _INCLUDE_KNIGHT_KE_PLATFORM_H_
|
|
||||||
#define _INCLUDE_KNIGHT_KE_PLATFORM_H_
|
|
||||||
|
|
||||||
#if defined WIN32
|
|
||||||
|
|
||||||
#define KE_PLATFORM_WINDOWS
|
|
||||||
#define WINDOWS_LEAN_AND_MEAN
|
|
||||||
#include <windows.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
|
|
||||||
#if !defined alloca
|
|
||||||
#define alloca _alloca
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define KE_PLATFORM_POSIX
|
|
||||||
|
|
||||||
#if defined __linux__
|
|
||||||
#define KE_PLATFORM_LINUX
|
|
||||||
#elif defined __APPLE__
|
|
||||||
#define KE_PLATFORM_APPLE
|
|
||||||
#else
|
|
||||||
#error "TODO"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif //_INCLUDE_KNIGHT_KE_PLATFORM_H_
|
|
@ -1,162 +0,0 @@
|
|||||||
#ifndef _INCLUDE_KNIGHT_KE_SECTOR_STACK_H_
|
|
||||||
#define _INCLUDE_KNIGHT_KE_SECTOR_STACK_H_
|
|
||||||
|
|
||||||
#include <KnightAllocator.h>
|
|
||||||
#include <KeVector.h>
|
|
||||||
|
|
||||||
namespace Knight
|
|
||||||
{
|
|
||||||
template <class T>
|
|
||||||
class KeSectorStack
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static const size_t DEFAULT_SECTOR_SIZE = 64;
|
|
||||||
|
|
||||||
KeSectorStack() : m_SectorSize(DEFAULT_SECTOR_SIZE), m_UsedSize(0), m_MaxUsedSize(0)
|
|
||||||
{
|
|
||||||
m_pAlloc = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
KeSectorStack(size_t sectorSize) : m_SectorSize(sectorSize), m_UsedSize(0), m_MaxUsedSize(0)
|
|
||||||
{
|
|
||||||
m_pAlloc = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
KeSectorStack(size_t sectorSize, ke_allocator_t *alloc) :
|
|
||||||
m_SectorSize(sectorSize), m_UsedSize(0), m_pAlloc(alloc), m_MaxUsedSize(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~KeSectorStack()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
T *sector;
|
|
||||||
size_t last_sector;
|
|
||||||
size_t last_sector_item;
|
|
||||||
|
|
||||||
if (m_MaxUsedSize == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
last_sector = (m_MaxUsedSize - 1) / m_SectorSize;
|
|
||||||
last_sector_item = (m_MaxUsedSize - 1) % m_SectorSize;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < last_sector; i++)
|
|
||||||
{
|
|
||||||
sector = m_Sectors[i];
|
|
||||||
|
|
||||||
for (size_t j = 0; j < m_SectorSize; j++)
|
|
||||||
{
|
|
||||||
sector[j].~T();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sector = m_Sectors[last_sector];
|
|
||||||
for (size_t i = 0; i <= last_sector_item; i++)
|
|
||||||
{
|
|
||||||
sector[i].~T();
|
|
||||||
}
|
|
||||||
|
|
||||||
clear_no_dtors();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear_no_dtors()
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < m_Sectors.size(); i++)
|
|
||||||
{
|
|
||||||
free_sector(m_Sectors[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Sectors.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool empty()
|
|
||||||
{
|
|
||||||
return (m_UsedSize == 0) ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void push(const T & val)
|
|
||||||
{
|
|
||||||
if ((m_UsedSize / m_SectorSize) >= m_Sectors.size())
|
|
||||||
{
|
|
||||||
/* Create a new sector */
|
|
||||||
T * sector;
|
|
||||||
|
|
||||||
if (m_pAlloc == NULL)
|
|
||||||
{
|
|
||||||
sector = (T *)malloc(sizeof(T) * m_SectorSize);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sector = (T *)m_pAlloc->alloc(m_pAlloc, sizeof(T) * m_SectorSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Sectors.push_back(sector);
|
|
||||||
}
|
|
||||||
|
|
||||||
at(m_UsedSize) = val;
|
|
||||||
|
|
||||||
m_UsedSize++;
|
|
||||||
|
|
||||||
/* Keep track of the maximum used size so we can defer the
|
|
||||||
* massive destruction job until the end.
|
|
||||||
*/
|
|
||||||
if (m_UsedSize > m_MaxUsedSize)
|
|
||||||
{
|
|
||||||
m_MaxUsedSize = m_UsedSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void pop()
|
|
||||||
{
|
|
||||||
m_UsedSize--;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pop_all()
|
|
||||||
{
|
|
||||||
m_UsedSize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
T & front()
|
|
||||||
{
|
|
||||||
return at(m_UsedSize - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t size()
|
|
||||||
{
|
|
||||||
return m_UsedSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
T & at(size_t x)
|
|
||||||
{
|
|
||||||
return m_Sectors[x / m_SectorSize][x % m_SectorSize];
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_sector(T * sector)
|
|
||||||
{
|
|
||||||
if (m_pAlloc == NULL)
|
|
||||||
{
|
|
||||||
free(sector);
|
|
||||||
}
|
|
||||||
else if (m_pAlloc->dealloc != NULL)
|
|
||||||
{
|
|
||||||
m_pAlloc->dealloc(m_pAlloc, sector);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
KeVector<T *> m_Sectors;
|
|
||||||
size_t m_SectorSize;
|
|
||||||
size_t m_UsedSize;
|
|
||||||
ke_allocator_t *m_pAlloc;
|
|
||||||
size_t m_MaxUsedSize;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //_INCLUDE_KNIGHT_KE_SECTOR_STACK_H_
|
|
@ -1,158 +0,0 @@
|
|||||||
#ifndef _INCLUDE_KNIGHT_KE_VECTOR_H_
|
|
||||||
#define _INCLUDE_KNIGHT_KE_VECTOR_H_
|
|
||||||
|
|
||||||
#include <new>
|
|
||||||
|
|
||||||
namespace Knight
|
|
||||||
{
|
|
||||||
template <class T>
|
|
||||||
class KeVector
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
KeVector<T>() : m_Data(NULL), m_Size(0), m_CurrentUsedSize(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
KeVector<T>(const KeVector<T> & other)
|
|
||||||
{
|
|
||||||
m_Size = other.m_CurrentUsedSize;
|
|
||||||
m_CurrentUsedSize = other.m_CurrentUsedSize;
|
|
||||||
|
|
||||||
if (m_Size > 0)
|
|
||||||
{
|
|
||||||
m_Data = new T[other.m_CurrentUsedSize];
|
|
||||||
|
|
||||||
for (size_t i = 0; i < m_Size; i++)
|
|
||||||
{
|
|
||||||
m_Data[i] = other.m_Data[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_Data = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~KeVector<T>()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
KeVector & operator =(const KeVector<T> & other)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
|
|
||||||
if (other.m_CurrentUsedSize)
|
|
||||||
{
|
|
||||||
m_Data = new T[other.m_CurrentUsedSize];
|
|
||||||
m_Size = other.m_CurrentUsedSize;
|
|
||||||
m_CurrentUsedSize = other.m_CurrentUsedSize;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < m_Size; i++)
|
|
||||||
{
|
|
||||||
m_Data[i] = other.m_Data[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t size() const
|
|
||||||
{
|
|
||||||
return m_CurrentUsedSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
void push_back(const T & elem)
|
|
||||||
{
|
|
||||||
GrowIfNeeded(1);
|
|
||||||
|
|
||||||
new (&m_Data[m_CurrentUsedSize]) T(elem);
|
|
||||||
|
|
||||||
m_CurrentUsedSize++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pop_back(const T & elem)
|
|
||||||
{
|
|
||||||
if (m_CurrentUsedSize == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_CurrentUsedSize--;
|
|
||||||
m_Data[m_CurrentUsedSize].~T();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_empty()
|
|
||||||
{
|
|
||||||
return (m_CurrentUsedSize == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
T & operator [](size_t pos)
|
|
||||||
{
|
|
||||||
return m_Data[pos];
|
|
||||||
}
|
|
||||||
|
|
||||||
const T & operator [](size_t pos) const
|
|
||||||
{
|
|
||||||
return m_Data[pos];
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < m_CurrentUsedSize; i++)
|
|
||||||
{
|
|
||||||
m_Data[i].~T();
|
|
||||||
}
|
|
||||||
|
|
||||||
free(m_Data);
|
|
||||||
|
|
||||||
m_Data = NULL;
|
|
||||||
m_Size = 0;
|
|
||||||
m_CurrentUsedSize = 0;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
void Grow(size_t amount)
|
|
||||||
{
|
|
||||||
T *new_data;
|
|
||||||
size_t new_size;
|
|
||||||
|
|
||||||
if (m_Size == 0)
|
|
||||||
{
|
|
||||||
new_size = 8;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
new_size = m_Size * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (m_CurrentUsedSize + amount > new_size)
|
|
||||||
{
|
|
||||||
new_size *= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
new_data = (T *)malloc(sizeof(T) * new_size);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < m_CurrentUsedSize; i++)
|
|
||||||
{
|
|
||||||
new (&new_data[i]) T(m_Data[i]);
|
|
||||||
m_Data[i].~T();
|
|
||||||
}
|
|
||||||
|
|
||||||
free(m_Data);
|
|
||||||
m_Data = new_data;
|
|
||||||
m_Size = new_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GrowIfNeeded(size_t amount)
|
|
||||||
{
|
|
||||||
if (m_CurrentUsedSize + amount >= m_Size)
|
|
||||||
{
|
|
||||||
Grow(amount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
T *m_Data;
|
|
||||||
size_t m_Size;
|
|
||||||
size_t m_CurrentUsedSize;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //_INCLUDE_KNIGHT_KE_VECTOR_H_
|
|
@ -1,37 +0,0 @@
|
|||||||
#ifndef _INCLUDE_KNIGHT_ALLOCATOR_H_
|
|
||||||
#define _INCLUDE_KNIGHT_ALLOCATOR_H_
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
struct ke_allocator_s;
|
|
||||||
typedef struct ke_allocator_s ke_allocator_t;
|
|
||||||
|
|
||||||
typedef void *(*KEFN_ALLOCATOR)(ke_allocator_t *, size_t);
|
|
||||||
typedef void (*KEFN_DEALLOCATOR)(ke_allocator_t *, void *);
|
|
||||||
|
|
||||||
struct ke_allocator_s
|
|
||||||
{
|
|
||||||
KEFN_ALLOCATOR alloc;
|
|
||||||
KEFN_DEALLOCATOR dealloc;
|
|
||||||
void *user;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void *operator new(size_t size, ke_allocator_t *alloc)
|
|
||||||
{
|
|
||||||
return alloc->alloc(alloc, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void *operator new [](size_t size, ke_allocator_t *alloc)
|
|
||||||
{
|
|
||||||
return alloc->alloc(alloc, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void ke_destroy(ke_allocator_t *alloc, T * data)
|
|
||||||
{
|
|
||||||
data->~T();
|
|
||||||
alloc->dealloc(alloc, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //_INCLUDE_KNIGHT_ALLOCATOR_H_
|
|
@ -9,7 +9,6 @@ Includes = [
|
|||||||
os.path.join(builder.sourcePath, 'public', 'amtl'),
|
os.path.join(builder.sourcePath, 'public', 'amtl'),
|
||||||
os.path.join(builder.sourcePath, 'public', 'jit'),
|
os.path.join(builder.sourcePath, 'public', 'jit'),
|
||||||
os.path.join(builder.sourcePath, 'public', 'jit', 'x86'),
|
os.path.join(builder.sourcePath, 'public', 'jit', 'x86'),
|
||||||
os.path.join(builder.sourcePath, 'knight', 'shared'),
|
|
||||||
|
|
||||||
# The include path for SP v2 stuff.
|
# The include path for SP v2 stuff.
|
||||||
os.path.join(builder.sourcePath, 'sourcepawn', 'include'),
|
os.path.join(builder.sourcePath, 'sourcepawn', 'include'),
|
||||||
@ -31,6 +30,7 @@ def setup(binary):
|
|||||||
library = setup(builder.compiler.StaticLibrary('sourcepawn'))
|
library = setup(builder.compiler.StaticLibrary('sourcepawn'))
|
||||||
library.sources += [
|
library.sources += [
|
||||||
'api.cpp',
|
'api.cpp',
|
||||||
|
'code-allocator.cpp',
|
||||||
'plugin-runtime.cpp',
|
'plugin-runtime.cpp',
|
||||||
'compiled-function.cpp',
|
'compiled-function.cpp',
|
||||||
'debug-trace.cpp',
|
'debug-trace.cpp',
|
||||||
@ -54,7 +54,6 @@ library.sources += [
|
|||||||
'zlib/uncompr.c',
|
'zlib/uncompr.c',
|
||||||
'zlib/zutil.c',
|
'zlib/zutil.c',
|
||||||
'md5/md5.cpp',
|
'md5/md5.cpp',
|
||||||
'../../knight/shared/KeCodeAllocator.cpp',
|
|
||||||
'../../public/jit/x86/assembler-x86.cpp',
|
'../../public/jit/x86/assembler-x86.cpp',
|
||||||
]
|
]
|
||||||
libsourcepawn = builder.Add(library).binary
|
libsourcepawn = builder.Add(library).binary
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <KeCodeAllocator.h>
|
|
||||||
#include "x86/jit_x86.h"
|
#include "x86/jit_x86.h"
|
||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
#include "api.h"
|
#include "api.h"
|
||||||
@ -74,7 +73,7 @@ SourcePawnEngine::ExecAlloc(size_t size)
|
|||||||
void *
|
void *
|
||||||
SourcePawnEngine::AllocatePageMemory(size_t size)
|
SourcePawnEngine::AllocatePageMemory(size_t size)
|
||||||
{
|
{
|
||||||
return g_Jit.AllocCode(size);
|
return Environment::get()->AllocateCode(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -92,7 +91,7 @@ SourcePawnEngine::SetReadWrite(void *ptr)
|
|||||||
void
|
void
|
||||||
SourcePawnEngine::FreePageMemory(void *ptr)
|
SourcePawnEngine::FreePageMemory(void *ptr)
|
||||||
{
|
{
|
||||||
g_Jit.FreeCode(ptr);
|
Environment::get()->FreeCode(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
#include <KePlatform.h>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <am-utility.h>
|
||||||
|
|
||||||
#if defined KE_PLATFORM_WINDOWS
|
#if defined(WIN32)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#elif defined KE_PLATFORM_POSIX
|
#else
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#else
|
|
||||||
#error "TODO"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "KeCodeAllocator.h"
|
#include "code-allocator.h"
|
||||||
|
|
||||||
#define ALIGNMENT 16
|
#define ALIGNMENT 16
|
||||||
|
|
||||||
@ -91,7 +89,7 @@ KeCodeCache *Knight::KE_CreateCodeCache()
|
|||||||
|
|
||||||
memset(cache, 0, sizeof(KeCodeCache));
|
memset(cache, 0, sizeof(KeCodeCache));
|
||||||
|
|
||||||
#if defined KE_PLATFORM_WINDOWS
|
#if defined(WIN32)
|
||||||
SYSTEM_INFO info;
|
SYSTEM_INFO info;
|
||||||
|
|
||||||
GetSystemInfo(&info);
|
GetSystemInfo(&info);
|
||||||
@ -264,13 +262,11 @@ KeCodeRegion *ke_AddRegionForSize(KeCodeCache *cache, size_t size)
|
|||||||
size += cache->page_granularity * 2;
|
size += cache->page_granularity * 2;
|
||||||
size -= size % cache->page_granularity;
|
size -= size % cache->page_granularity;
|
||||||
|
|
||||||
#if defined KE_PLATFORM_WINDOWS
|
#if defined(WIN32)
|
||||||
region->block_start = (unsigned char *)VirtualAlloc(NULL, size, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
region->block_start = (unsigned char *)VirtualAlloc(NULL, size, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||||
#elif defined KE_PLATFORM_POSIX
|
#else
|
||||||
region->block_start = (unsigned char *)mmap(NULL, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANON, -1, 0);
|
region->block_start = (unsigned char *)mmap(NULL, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANON, -1, 0);
|
||||||
region->block_start = (region->block_start == MAP_FAILED) ? NULL : region->block_start;
|
region->block_start = (region->block_start == MAP_FAILED) ? NULL : region->block_start;
|
||||||
#else
|
|
||||||
#error "TODO"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (region->block_start == NULL)
|
if (region->block_start == NULL)
|
||||||
@ -381,7 +377,7 @@ KeCodeRegion *ke_DestroyRegion(KeCodeRegion *region)
|
|||||||
|
|
||||||
next = region->next;
|
next = region->next;
|
||||||
|
|
||||||
#if defined KE_PLATFORM_WINDOWS
|
#if defined(WIN32)
|
||||||
VirtualFree(region->block_start, 0, MEM_RELEASE);
|
VirtualFree(region->block_start, 0, MEM_RELEASE);
|
||||||
#else
|
#else
|
||||||
munmap(region->block_start, region->total_size);
|
munmap(region->block_start, region->total_size);
|
@ -1,7 +1,6 @@
|
|||||||
#ifndef _INCLUDE_KNIGHT_KE_CODE_ALLOCATOR_H_
|
#ifndef _INCLUDE_KNIGHT_KE_CODE_ALLOCATOR_H_
|
||||||
#define _INCLUDE_KNIGHT_KE_CODE_ALLOCATOR_H_
|
#define _INCLUDE_KNIGHT_KE_CODE_ALLOCATOR_H_
|
||||||
|
|
||||||
#include <KeLinking.h>
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
@ -11,7 +11,9 @@
|
|||||||
// SourcePawn. If not, see http://www.gnu.org/licenses/.
|
// SourcePawn. If not, see http://www.gnu.org/licenses/.
|
||||||
//
|
//
|
||||||
#include "compiled-function.h"
|
#include "compiled-function.h"
|
||||||
#include "x86/jit_x86.h"
|
#include "environment.h"
|
||||||
|
|
||||||
|
using namespace sp;
|
||||||
|
|
||||||
CompiledFunction::CompiledFunction(void *entry_addr, cell_t pcode_offs, FixedArray<LoopEdge> *edges)
|
CompiledFunction::CompiledFunction(void *entry_addr, cell_t pcode_offs, FixedArray<LoopEdge> *edges)
|
||||||
: entry_(entry_addr),
|
: entry_(entry_addr),
|
||||||
@ -22,5 +24,5 @@ CompiledFunction::CompiledFunction(void *entry_addr, cell_t pcode_offs, FixedArr
|
|||||||
|
|
||||||
CompiledFunction::~CompiledFunction()
|
CompiledFunction::~CompiledFunction()
|
||||||
{
|
{
|
||||||
g_Jit.FreeCode(entry_);
|
Environment::get()->FreeCode(entry_);
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,8 @@ Environment::Environment()
|
|||||||
: debugger_(nullptr),
|
: debugger_(nullptr),
|
||||||
profiler_(nullptr),
|
profiler_(nullptr),
|
||||||
jit_enabled_(true),
|
jit_enabled_(true),
|
||||||
profiling_enabled_(false)
|
profiling_enabled_(false),
|
||||||
|
code_pool_(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,14 +42,14 @@ Environment::New()
|
|||||||
if (sEnvironment)
|
if (sEnvironment)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
Environment *env = new Environment();
|
sEnvironment = new Environment();
|
||||||
if (!env->Initialize()) {
|
if (!sEnvironment->Initialize()) {
|
||||||
delete env;
|
delete sEnvironment;
|
||||||
|
sEnvironment = nullptr;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
sEnvironment = env;
|
return sEnvironment;
|
||||||
return env;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Environment *
|
Environment *
|
||||||
@ -64,6 +65,10 @@ Environment::Initialize()
|
|||||||
api_v2_ = new SourcePawnEngine2();
|
api_v2_ = new SourcePawnEngine2();
|
||||||
watchdog_timer_ = new WatchdogTimer();
|
watchdog_timer_ = new WatchdogTimer();
|
||||||
|
|
||||||
|
if ((code_pool_ = Knight::KE_CreateCodeCache()) == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Safe to initialize JIT now that we have the code cache.
|
||||||
if (!g_Jit.InitializeJIT())
|
if (!g_Jit.InitializeJIT())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -75,6 +80,10 @@ Environment::Shutdown()
|
|||||||
{
|
{
|
||||||
watchdog_timer_->Shutdown();
|
watchdog_timer_->Shutdown();
|
||||||
g_Jit.ShutdownJIT();
|
g_Jit.ShutdownJIT();
|
||||||
|
Knight::KE_DestroyCodeCache(code_pool_);
|
||||||
|
|
||||||
|
assert(sEnvironment == this);
|
||||||
|
sEnvironment = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -160,3 +169,15 @@ Environment::ReportError(PluginRuntime *runtime, int err, const char *errstr, ce
|
|||||||
|
|
||||||
debugger_->OnContextExecuteError(runtime->GetDefaultContext(), &trace);
|
debugger_->OnContextExecuteError(runtime->GetDefaultContext(), &trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
Environment::AllocateCode(size_t size)
|
||||||
|
{
|
||||||
|
return Knight::KE_AllocCode(code_pool_, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Environment::FreeCode(void *code)
|
||||||
|
{
|
||||||
|
Knight::KE_FreeCode(code_pool_, code);
|
||||||
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include <sp_vm_api.h>
|
#include <sp_vm_api.h>
|
||||||
#include <am-utility.h> // Replace with am-cxx later.
|
#include <am-utility.h> // Replace with am-cxx later.
|
||||||
|
#include "code-allocator.h"
|
||||||
|
|
||||||
class PluginRuntime;
|
class PluginRuntime;
|
||||||
|
|
||||||
@ -54,6 +55,10 @@ class Environment : public ISourcePawnEnvironment
|
|||||||
const char *GetErrorString(int err);
|
const char *GetErrorString(int err);
|
||||||
void ReportError(PluginRuntime *runtime, int err, const char *errstr, cell_t rp_start);
|
void ReportError(PluginRuntime *runtime, int err, const char *errstr, cell_t rp_start);
|
||||||
|
|
||||||
|
// Allocate and free executable memory.
|
||||||
|
void *AllocateCode(size_t size);
|
||||||
|
void FreeCode(void *code);
|
||||||
|
|
||||||
// Helpers.
|
// Helpers.
|
||||||
void SetProfiler(IProfilingTool *profiler) {
|
void SetProfiler(IProfilingTool *profiler) {
|
||||||
profiler_ = profiler;
|
profiler_ = profiler;
|
||||||
@ -96,6 +101,8 @@ class Environment : public ISourcePawnEnvironment
|
|||||||
IProfilingTool *profiler_;
|
IProfilingTool *profiler_;
|
||||||
bool jit_enabled_;
|
bool jit_enabled_;
|
||||||
bool profiling_enabled_;
|
bool profiling_enabled_;
|
||||||
|
|
||||||
|
Knight::KeCodeCache *code_pool_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EnterProfileScope
|
class EnterProfileScope
|
||||||
|
@ -40,7 +40,6 @@
|
|||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
|
|
||||||
using namespace sp;
|
using namespace sp;
|
||||||
using namespace Knight;
|
|
||||||
|
|
||||||
#if defined USE_UNGEN_OPCODES
|
#if defined USE_UNGEN_OPCODES
|
||||||
#include "ungen_opcodes.h"
|
#include "ungen_opcodes.h"
|
||||||
@ -49,7 +48,6 @@ using namespace Knight;
|
|||||||
#define __ masm.
|
#define __ masm.
|
||||||
|
|
||||||
JITX86 g_Jit;
|
JITX86 g_Jit;
|
||||||
KeCodeCache *g_pCodeCache = NULL;
|
|
||||||
|
|
||||||
static inline uint8_t *
|
static inline uint8_t *
|
||||||
LinkCode(AssemblerX86 &masm)
|
LinkCode(AssemblerX86 &masm)
|
||||||
@ -57,7 +55,7 @@ LinkCode(AssemblerX86 &masm)
|
|||||||
if (masm.outOfMemory())
|
if (masm.outOfMemory())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
void *code = Knight::KE_AllocCode(g_pCodeCache, masm.length());
|
void *code = Environment::get()->AllocateCode(masm.length());
|
||||||
if (!code)
|
if (!code)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -1901,8 +1899,6 @@ JITX86::JITX86()
|
|||||||
bool
|
bool
|
||||||
JITX86::InitializeJIT()
|
JITX86::InitializeJIT()
|
||||||
{
|
{
|
||||||
g_pCodeCache = KE_CreateCodeCache();
|
|
||||||
|
|
||||||
m_pJitEntry = GenerateEntry(&m_pJitReturn, &m_pJitTimeout);
|
m_pJitEntry = GenerateEntry(&m_pJitReturn, &m_pJitTimeout);
|
||||||
if (!m_pJitEntry)
|
if (!m_pJitEntry)
|
||||||
return false;
|
return false;
|
||||||
@ -1913,7 +1909,6 @@ JITX86::InitializeJIT()
|
|||||||
if (!code)
|
if (!code)
|
||||||
return false;
|
return false;
|
||||||
MacroAssemblerX86::RunFeatureDetection(code);
|
MacroAssemblerX86::RunFeatureDetection(code);
|
||||||
KE_FreeCode(g_pCodeCache, code);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1921,7 +1916,6 @@ JITX86::InitializeJIT()
|
|||||||
void
|
void
|
||||||
JITX86::ShutdownJIT()
|
JITX86::ShutdownJIT()
|
||||||
{
|
{
|
||||||
KE_DestroyCodeCache(g_pCodeCache);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CompiledFunction *
|
CompiledFunction *
|
||||||
@ -1981,7 +1975,7 @@ JITX86::CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData)
|
|||||||
void
|
void
|
||||||
JITX86::DestroyFakeNative(SPVM_NATIVE_FUNC func)
|
JITX86::DestroyFakeNative(SPVM_NATIVE_FUNC func)
|
||||||
{
|
{
|
||||||
KE_FreeCode(g_pCodeCache, (void *)func);
|
Environment::get()->FreeCode((void *)func);
|
||||||
}
|
}
|
||||||
|
|
||||||
ICompilation *
|
ICompilation *
|
||||||
@ -2046,18 +2040,6 @@ JITX86::InvokeFunction(PluginRuntime *runtime, CompiledFunction *fn, cell_t *res
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
|
||||||
JITX86::AllocCode(size_t size)
|
|
||||||
{
|
|
||||||
return Knight::KE_AllocCode(g_pCodeCache, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
JITX86::FreeCode(void *code)
|
|
||||||
{
|
|
||||||
KE_FreeCode(g_pCodeCache, code);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
JITX86::RegisterRuntime(PluginRuntime *rt)
|
JITX86::RegisterRuntime(PluginRuntime *rt)
|
||||||
{
|
{
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include <sp_vm_types.h>
|
#include <sp_vm_types.h>
|
||||||
#include <sp_vm_api.h>
|
#include <sp_vm_api.h>
|
||||||
#include <KeCodeAllocator.h>
|
|
||||||
#include <macro-assembler-x86.h>
|
#include <macro-assembler-x86.h>
|
||||||
#include <am-vector.h>
|
#include <am-vector.h>
|
||||||
#include "jit_shared.h"
|
#include "jit_shared.h"
|
||||||
@ -173,9 +172,6 @@ class JITX86
|
|||||||
ExternalAddress GetUniversalReturn() {
|
ExternalAddress GetUniversalReturn() {
|
||||||
return ExternalAddress(m_pJitReturn);
|
return ExternalAddress(m_pJitReturn);
|
||||||
}
|
}
|
||||||
void *AllocCode(size_t size);
|
|
||||||
void FreeCode(void *code);
|
|
||||||
|
|
||||||
uintptr_t FrameId() const {
|
uintptr_t FrameId() const {
|
||||||
return frame_id_;
|
return frame_id_;
|
||||||
}
|
}
|
||||||
@ -203,7 +199,6 @@ const Register dat = esi;
|
|||||||
const Register tmp = ecx;
|
const Register tmp = ecx;
|
||||||
const Register frm = ebx;
|
const Register frm = ebx;
|
||||||
|
|
||||||
extern Knight::KeCodeCache *g_pCodeCache;
|
|
||||||
extern JITX86 g_Jit;
|
extern JITX86 g_Jit;
|
||||||
|
|
||||||
#endif //_INCLUDE_SOURCEPAWN_JIT_X86_H_
|
#endif //_INCLUDE_SOURCEPAWN_JIT_X86_H_
|
||||||
|
Loading…
Reference in New Issue
Block a user