diff --git a/stix/lib/gc.c b/stix/lib/gc.c new file mode 100644 index 0000000..787d6c6 --- /dev/null +++ b/stix/lib/gc.c @@ -0,0 +1,245 @@ +/* + * $Id$ + * + Copyright (c) 2014-2015 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "stix-prv.h" + +static void cleanup_symbols_for_gc (stix_t* stix, stix_oop_t _nil) +{ +#if 0 + stix_oop_oop_t buc; + stix_oop_char_t sym; + stix_oow_t tally, index, i, x, y, z; + + tally = STIX_OOP_TO_SMINT (stix->symtab->slot[STIX_SYMTAB_TALLY]); + if (tally <= 0) return; + + buc = (stix_oop_oop_t) stix->symtab->slot[STIX_SYMTAB_BUCKET]; + for (index = 0; index < buc->size; ) + { + if (buc->slot[index]->flags & STIX_OBJ_FLAG_MOVED) + { + index++; + continue; + } + + STIX_ASSERT (buc->slot[index] != _nil); + +{ +sym = (stix_oop_char_t)buc->slot[index]; +wprintf (L">> DISPOSING %d [%S] from the symbol table\n", (int)index, sym->slot); +} + for (i = 0, x = index, y = index; i < buc->size; i++) + { + y = (y + 1) % buc->size; + + /* done if the slot at the current hash index is _nil */ + if (buc->slot[y] == _nil) break; + + /* get the natural hash index for the data in the slot + * at the current hash index */ + sym = (stix_oop_char_t)buc->slot[y]; + + STIX_ASSERT (STIX_CLASSOF(stix,sym) == (stix_oop_t)stix->cc.symbol); + + z = hash_chars (sym->slot, sym->size) % buc->size; + + /* move an element if necessary */ + if ((y > x && (z <= x || z > y)) || + (y < x && (z <= x && z > y))) + { + buc->slot[x] = buc->slot[y]; + x = y; + } + } + + buc->slot[x] = _nil; + tally--; + } + + stix->symtab->slot[STIX_SYMTAB_TALLY] = STIX_OOP_FROM_SMINT(tally); +#endif +} + +static stix_oop_t move_one (stix_t* stix, stix_oop_t oop) +{ + STIX_ASSERT (STIX_OOP_IS_POINTER(oop)); + + if (oop->flags & STIX_OBJ_FLAG_MOVED) + { + /* this object has migrated to the new heap. + * the class field has been updated to the new object + * in the 'else' block below. i can simply return it + * without further migration. */ + return oop->_class; + } + else + { + stix_oow_t nbytes, nbytes_aligned; + stix_oop_t tmp; + + /* calculate the payload size in bytes */ + nbytes = (oop->size + oop->extra) * oop->unit; + nbytes_aligned = STIX_ALIGN (nbytes, STIX_SIZEOF(stix_oop_t)); + + /* allocate space in the new heap */ + tmp = stix_allocheapmem ( + stix, stix->newheap, STIX_SIZEOF(stix_obj_t) + nbytes_aligned); + + /* allocation here must not fail because + * i'm allocating the new space in a new heap for + * moving an existing object in the current heap. + * + * assuming the new heap is as large as the old heap, + * and garbage collection doesn't allocate more objects + * than in the old heap, it must not fail. */ + STIX_ASSERT (tmp != STIX_NULL); + + /* copy the payload to the new object */ + STIX_MEMCPY (tmp, oop, STIX_SIZEOF(stix_obj_t) + nbytes_aligned); + + /* mark the old object that it has migrated to the new heap */ + oop->flags |= STIX_OBJ_FLAG_MOVED; + + /* let the class field of the old object point to the new + * object allocated in the new heap. it is returned in + * the 'if' block at the top of this function. */ + oop->_class = tmp; + + /* return the new object */ + return tmp; + } +} + +static stix_uint8_t* scan_new_heap (stix_t* stix, stix_uint8_t* ptr) +{ + while (ptr < stix->newheap->ptr) + { + stix_oow_t i; + stix_oow_t nbytes, nbytes_aligned; + stix_oop_t oop; + + oop = (stix_oop_t)ptr; + nbytes = (oop->size + oop->extra) * oop->unit; + nbytes_aligned = STIX_ALIGN (nbytes, STIX_SIZEOF(stix_oop_t)); + + oop->_class = move_one (stix, oop->_class); + + if (oop->type == STIX_OBJ_TYPE_OOP) + { + stix_obj_oop_t* xtmp; + + xtmp = (stix_oop_oop_t)oop; + for (i = 0; i < oop->size; i++) + { + if (STIX_OOP_IS_POINTER(xtmp->slot[i])) + xtmp->slot[i] = move_one (stix, xtmp->slot[i]); + } + } + +/*wprintf (L"ptr in gc => %p size => %d, aligned size => %d\n", ptr, (int)nbytes, (int)nbytes_aligned);*/ + ptr = ptr + STIX_SIZEOF(stix_obj_t) + nbytes_aligned; + } + + /* return the pointer to the beginning of the free space in the heap */ + return ptr; +} + +void stix_gc (stix_t* stix) +{ + /* + * move a referenced object to the new heap. + * inspect the fields of the moved object in the new heap. + * move objects pointed to by the fields to the new heap. + * finally perform some tricky symbol table clean-up. + */ + + stix_uint8_t* ptr; + stix_heap_t* tmp; + stix_oop_t old__nil; + + /* TODO: allocate common objects like _nil and the root dictionary + * in the permanant heap. minimize moving around */ + + old__nil = stix->_nil; + + /* move _nil and the root object table */ + stix->_nil = move_one (stix, stix->_nil); + stix->root = (stix_oop_oop_t) move_one (stix, (stix_oop_t)stix->root); + stix->_true = move_one (stix, stix->_true); + stix->_false = move_one (stix, stix->_false); + + stix->cc.array = (stix_oop_oop_t) move_one (stix, (stix_oop_t)stix->cc.array); + stix->cc.association = (stix_oop_oop_t) move_one (stix, (stix_oop_t)stix->cc.association); + /*stix->cc.metaclass = (stix_oop_oop_t) move_one (stix, (stix_oop_t)stix->cc.metaclass);*/ + stix->cc.string = (stix_oop_oop_t) move_one (stix, (stix_oop_t)stix->cc.string); + stix->cc.symbol = (stix_oop_oop_t) move_one (stix, (stix_oop_t)stix->cc.symbol); + stix->cc.sysdic = (stix_oop_oop_t) move_one (stix, (stix_oop_t)stix->cc.sysdic); + stix->cc.numeric[0] = (stix_oop_oop_t) move_one (stix, (stix_oop_t)stix->cc.numeric[0]); + stix->cc.numeric[1] = (stix_oop_oop_t) move_one (stix, (stix_oop_t)stix->cc.numeric[1]); + + /* scan the new heap to move referenced objects */ + ptr = (stix_uint8_t*) STIX_ALIGN ((stix_uintptr_t)stix->newheap->base, STIX_SIZEOF(stix_oop_t)); + ptr = scan_new_heap (stix, ptr); + + /* traverse the symbol table for unreferenced symbols. + * if the symbol has not moved to the new heap, the symbol + * is not referenced by any other objects than the symbol + * table itself */ + cleanup_symbols_for_gc (stix, old__nil); + + /* move the symbol table itself */ + stix->symtab = (stix_oop_oop_t) move_one (stix, (stix_oop_t)stix->symtab); + + /* scan the new heap again from the end position of + * the previous scan to move referenced objects by + * the symbol table. */ + ptr = scan_new_heap (stix, ptr); + + /* swap the current heap and old heap */ + tmp = stix->curheap; + stix->curheap = stix->newheap; + stix->newheap = tmp; + +/* +{ +stix_oow_t index; +stix_oop_oop_t buc; +printf ("=== SURVIVING SYMBOLS ===\n"); +buc = (stix_oop_oop_t) stix->symtab->slot[STIX_SYMTAB_BUCKET]; +for (index = 0; index < buc->size; index++) +{ + if ((stix_oop_t)buc->slot[index] != stix->_nil) + { + const stix_oop_char_t* p = ((stix_oop_char_t)buc->slot[index])->slot; + printf ("SYM ["); + while (*p) printf ("%c", *p++); + printf ("]\n"); + } +} +printf ("===========================\n"); +} +*/ +} diff --git a/stix/lib/heap.c b/stix/lib/heap.c new file mode 100644 index 0000000..d12723a --- /dev/null +++ b/stix/lib/heap.c @@ -0,0 +1,78 @@ +/* + * $Id$ + * + Copyright (c) 2014-2015 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "stix-prv.h" + +stix_heap_t* stix_makeheap (stix_t* stix, stix_size_t size) +{ + stix_heap_t* heap; + + heap = (stix_heap_t*)STIX_MMGR_ALLOC(stix->mmgr, STIX_SIZEOF(*heap) + size); + if (!heap) + { + stix->errnum = STIX_ENOMEM; + return STIX_NULL; + } + + STIX_MEMSET (heap, 0, STIX_SIZEOF(*heap) + size); + + heap->base = (stix_uint8_t*)(heap + 1); + /* adjust the initial allocation pointer to a multiple of the oop size */ + heap->ptr = (stix_uint8_t*)STIX_ALIGN(((stix_uintptr_t)heap->base), STIX_SIZEOF(stix_oop_t)); + heap->limit = heap->base + size; + + STIX_ASSERT (heap->ptr >= heap->base); + + /* if size is too small, heap->ptr may go past heap->limit even at + * this moment depending on the alignment of heap->base. subsequent + * calls to substix_allocheapmem() are bound to fail. Make sure to + * pass a heap size large enough */ + + return heap; +} + +void stix_killheap (stix_t* stix, stix_heap_t* heap) +{ + STIX_MMGR_FREE (stix->mmgr, heap); +} + +void* stix_allocheapmem (stix_t* stix, stix_heap_t* heap, stix_size_t size) +{ + stix_uint8_t* ptr; + + /* check the heap size limit */ + if (heap->ptr >= heap->limit || heap->limit - heap->ptr < size) + { + stix->errnum = STIX_ENOMEM; + return STIX_NULL; + } + + /* allocation is as simple as moving the heap pointer */ + ptr = heap->ptr; + heap->ptr += size; + + return ptr; +} diff --git a/stix/lib/obj.c b/stix/lib/obj.c new file mode 100644 index 0000000..a18f4c8 --- /dev/null +++ b/stix/lib/obj.c @@ -0,0 +1,209 @@ +/* + * $Id$ + * + Copyright (c) 2014-2015 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "stix-prv.h" + +static void* alloc_bytes (stix_t* stix, stix_size_t size) +{ + stix_uint8_t* ptr; + + ptr = stix_allocheapmem (stix, stix->curheap, size); + if (!ptr && !(stix->option.trait & STIX_NOGC)) + { + stix_gc (stix); + ptr = stix_allocheapmem (stix, stix->curheap, size); + } + + return ptr; +} + +stix_oop_t stix_allocoopobj (stix_t* stix, stix_oow_t size) +{ + stix_oop_oop_t hdr; + stix_oow_t nbytes, nbytes_aligned; + + nbytes = size * STIX_SIZEOF(stix_oop_t); + + /* this isn't really necessary since nbytes must be + * aligned already. */ + nbytes_aligned = STIX_ALIGN(nbytes, STIX_SIZEOF(stix_oop_t)); + + /* making the number of bytes to allocate a multiple of + * STIX_SIZEOF(stix_oop_t) will guarantee the starting address + * of the allocated space to be an even number. + * see STIX_OOP_IS_NUMERIC() and STIX_OOP_IS_POINTER() */ + hdr = alloc_bytes (stix, STIX_SIZEOF(stix_obj_t) + nbytes_aligned); + if (!hdr) return STIX_NULL; + + hdr->flags = 0; + hdr->type = STIX_OBJ_TYPE_OOP; + hdr->extra = 0; + hdr->unit = STIX_SIZEOF(stix_oop_t); + hdr->size = size; + hdr->_class = stix->_nil; + + while (size > 0) hdr->slot[--size] = stix->_nil; + + return (stix_oop_t)hdr; +} + +static stix_oop_t alloc_numeric_array (stix_t* stix, const void* ptr, stix_oow_t len, stix_obj_type_t type, stix_oow_t unit, int extra) +{ + /* allocate a variable object */ + + stix_oop_t hdr; + stix_oow_t xbytes, nbytes, nbytes_aligned; + + xbytes = len * unit; + /* 'extra' indicates an extra unit to append at the end. + * it's useful to store a string with a terminating null */ + nbytes = extra? xbytes + len: xbytes; + nbytes_aligned = STIX_ALIGN(nbytes, STIX_SIZEOF(stix_oop_t)); + /* TODO: check overflow in size calculation*/ + + /* making the number of bytes to allocate a multiple of + * STIX_SIZEOF(stix_oop_t) will guarantee the starting address + * of the allocated space to be an even number. + * see STIX_OOP_IS_NUMERIC() and STIX_OOP_IS_POINTER() */ + hdr = alloc_bytes (stix, STIX_SIZEOF(stix_obj_t) + nbytes_aligned); + if (!hdr) return STIX_NULL; + + hdr->flags = 0; + hdr->type = type; + hdr->extra = extra; + hdr->unit = unit; + hdr->size = len; + hdr->_class = stix->_nil; + + if (ptr) + { + /* copy data */ + STIX_MEMCPY (hdr + 1, ptr, xbytes); + STIX_MEMSET ((stix_uint8_t*)(hdr + 1) + xbytes, 0, nbytes_aligned - xbytes); + } + else + { + /* initialize with zeros when the string pointer is not given */ + STIX_MEMSET ((hdr + 1), 0, nbytes_aligned); + } + + return hdr; +} + +stix_oop_t stix_alloccharobj (stix_t* stix, const stix_char_t* ptr, stix_oow_t len) +{ + return alloc_numeric_array (stix, ptr, len, STIX_OBJ_TYPE_CHAR, STIX_SIZEOF(stix_char_t), 1); +} + +stix_oop_t stix_allocuint8obj (stix_t* stix, const stix_uint8_t* ptr, stix_oow_t len) +{ + + return alloc_numeric_array (stix, ptr, len, STIX_OBJ_TYPE_UINT8, STIX_SIZEOF(stix_uint8_t), 0); +} + +stix_oop_t stix_allocuint16obj (stix_t* stix, const stix_uint16_t* ptr, stix_oow_t len) +{ + return alloc_numeric_array (stix, ptr, len, STIX_OBJ_TYPE_UINT16, STIX_SIZEOF(stix_uint16_t), 0); +} + +stix_oop_t stix_instantiate (stix_t* stix, stix_oop_t _class, const void* vptr, stix_oow_t vlen) +{ + stix_oop_t oop; + stix_oow_t spec; + stix_oow_t fixed; + stix_obj_type_t vtype; + + STIX_ASSERT (stix->_nil != STIX_NULL); + + STIX_ASSERT (STIX_OOP_IS_POINTER(_class)); + /*STIX_ASSERT (STIX_CLASSOF(_class) == stix->_class); */ + + STIX_ASSERT (STIX_OOP_IS_SMINT(((stix_oop_class_t)_class)->spec)); + spec = STIX_OOP_TO_SMINT(((stix_oop_class_t)_class)->spec); + + fixed = STIX_CLASS_SPEC_FIXED(spec); /* size of the fixed part */ + + if (!STIX_CLASS_SPEC_ISVAR(spec)) + { + /* named instance variables only. treat it as if it is a + * variable-pointer class with no variable data */ + vtype = STIX_OBJ_TYPE_OOP; + vlen = 0; + } + else + { + vtype = STIX_CLASS_SPEC_VTYPE(spec); + if (vtype != STIX_OBJ_TYPE_OOP && fixed > 0) + { + /* a variable-non-pointer class can't have named instance variables */ + stix->errnum = STIX_EINVAL; + return STIX_NULL; + } + } + + switch (vtype) + { + case STIX_OBJ_TYPE_OOP: + /* class for a variable object. + * both the fixed-sized part and the variable part are allowed. */ + oop = stix_allocoopobj(stix, fixed + vlen); + if (!oop) return STIX_NULL; + + if (vlen > 0) + { + stix_oop_oop_t hdr = (stix_oop_oop_t)oop; + STIX_MEMCPY (&hdr->slot[fixed], vptr, vlen * STIX_SIZEOF(stix_oop_t)); + } + break; + + case STIX_OBJ_TYPE_CHAR: + /* variable-char class can't have instance variables */ + STIX_ASSERT (fixed == 0); + oop = stix_alloccharobj(stix, vptr, vlen); + if (!oop) return STIX_NULL; + break; + + case STIX_OBJ_TYPE_UINT8: + /* variable-byte class can't have instance variables */ + STIX_ASSERT (fixed == 0); + oop = stix_allocuint8obj(stix, vptr, vlen); + if (!oop) return STIX_NULL; + break; + + case STIX_OBJ_TYPE_UINT16: + STIX_ASSERT (fixed == 0); + oop = stix_allocuint16obj(stix, vptr, vlen); + if (!oop) return STIX_NULL; + break; + + default: + stix->errnum = STIX_EINTERN; + return STIX_NULL; + } + + oop->_class = _class; + return oop; +} diff --git a/stix/lib/stix-prv.h b/stix/lib/stix-prv.h new file mode 100644 index 0000000..572ee99 --- /dev/null +++ b/stix/lib/stix-prv.h @@ -0,0 +1,178 @@ +/* + * $Id$ + * + Copyright (c) 2014-2015 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _STIX_PRV_H_ +#define _STIX_PRV_H_ + +#include "stix.h" + +#include /* TODO: delete these header inclusion lines */ +#include +#include + +#define STIX_MEMSET(dst,src,size) memset(dst,src,size) +#define STIX_MEMCPY(dst,src,size) memcpy(dst,src,size) +#define STIX_ASSERT(x) assert(x) + +#define STIX_ALIGN(x,y) ((((x) + (y) - 1) / (y)) * (y)) +/* make a low bit mask that can mask off low n bits*/ +#define STIX_LBMASK(type,n) (~(~((type)0) << (n))) + +/* ========================================================================= */ +/* CLASS */ +/* ========================================================================= */ + +/* The stix_class_t type defines the internal structure of a class object. */ +struct stix_class_t +{ + STIX_OBJ_HEADER; + stix_oow_t spec; + stix_oop_oop_t methods; + stix_oop_oop_t superclass; + stix_oop_char_t name; + stix_oop_char_t instvars; + stix_oop_char_t classvars; + + /* variable part afterwards */ +}; + +typedef struct stix_class_t stix_class_t; +typedef struct stix_class_t* stix_oop_class_t; + +/* + * The spec field of a class object encodes the size of the fixed part + * and the type of the variable part. The fixed part is the number of + * instance variables. The variable part can be specified when the object + * is instantiated if it is variadic. + * + * vtype is one of the #stix_obj_type_t enumerators. + * + * The maximum number of named(fixed) instance variables for a class is: + * 2 ^ (BITS-IN-OOW - STIX_OBJ_TYPE_BITS - 1) + * + * The number of named instance variables can be greater than 0 if the class + * is not variable or if it's a variable-pointer class(vtype == STIX_OBJ_TYPE_OOP) + * + * See also #stix_obj_type_t. + */ +#define STIX_CLASS_SPEC_MAKE(fixed,variadic,vtype) ( \ + (((stix_oow_t)(fixed)) << (STIX_OBJ_TYPE_BITS + 1)) | \ + (((stix_oow_t)(vtype)) << 1) | (((stix_oow_t)variadic) & 1) ) + +/* what is the number of named instance variables? */ +#define STIX_CLASS_SPEC_FIXED(spec) ((spec) >> STIX_OBJ_TYPE_BITS) + +/* is a variable class? */ +#define STIX_CLASS_SPEC_ISVAR(spec) ((spec) & 1) + +/* if so, what variable class is it? variable-character? variable-pointer? etc? */ +#define STIX_CLASS_SPEC_VTYPE(spec) ((spec) & (STIX_LBMASK(stix_oow_t, STIX_OBJ_TYPE_BITS) << 1)) + +/* VM-level macros */ +#define STIX_CLASSOF(stix,oop) \ + (STIX_OOP_IS_NUMERIC(oop)? \ + ((stix_oop_t)(stix)->cc.numeric[((stix_oow_t)oop&3)-1]): \ + (oop)->_class) + +/* +#define STIX_BYTESOF(stix,oop) \ + (STIX_OOP_IS_NUMERIC(oop)? \ + (STIX_SIZEOF(stix_oow_t)): \ + (STIX_SIZEOF(stix_obj_t) + STIX_ALIGN(((oop)->size + (oop)->extra) * (oop)->unit), STIX_SIZEOF(stix_oop_t)) \ + ) +*/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/* ========================================================================= */ +/* heap.c */ +/* ========================================================================= */ + +/** + * The stix_makeheap() function creates a new heap of the \a size bytes. + * + * \return heap pointer on success and #STIX_NULL on failure. + */ +stix_heap_t* stix_makeheap ( + stix_t* stix, + stix_size_t size +); + +/** + * The stix_killheap() function destroys the heap pointed to by \a heap. + */ +void stix_killheap ( + stix_t* stix, + stix_heap_t* heap +); + +/** + * The stix_allocheapmem() function allocates \a size bytes in the heap pointed + * to by \a heap. + * + * \return memory pointer on success and #STIX_NULL on failure. + */ +void* stix_allocheapmem ( + stix_t* stix, + stix_heap_t* heap, + stix_size_t size +); + + +/* ========================================================================= */ +/* obj.c */ +/* ========================================================================= */ +stix_oop_t stix_allocoopobj ( + stix_t* stix, + stix_oow_t size +); + +stix_oop_t stix_alloccharobj ( + stix_t* stix, + const stix_char_t* ptr, + stix_oow_t len +); + +stix_oop_t stix_allocuint8obj ( + stix_t* stix, + const stix_uint8_t* ptr, + stix_oow_t len +); + +stix_oop_t stix_allocuint16obj ( + stix_t* stix, + const stix_uint16_t* ptr, + stix_oow_t len +); + +#if defined(__cplusplus) +} +#endif + + +#endif diff --git a/stix/lib/stix.h b/stix/lib/stix.h new file mode 100644 index 0000000..912338c --- /dev/null +++ b/stix/lib/stix.h @@ -0,0 +1,771 @@ +/* + * $Id$ + * + Copyright (c) 2014-2015 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _STIX_H_ +#define _STIX_H_ + +/* ========================================================================== */ +/* TODO: define these types and macros using autoconf */ +typedef unsigned char stix_uint8_t; +typedef unsigned short int stix_uint16_t; +/*typedef unsigned int stix_uint32_t;*/ +#if defined(__MWERKS__) && defined(macintosh) + /* the metrowerks codewarrior compiler produces the 'illegal bitfield declaration' + * if a non-int type is used in the bit-field declaration */ + typedef unsigned int stix_uintptr_t; + typedef unsigned int stix_size_t; +#else + typedef unsigned long int stix_uintptr_t; + typedef unsigned long int stix_size_t; +#endif + +typedef unsigned short int stix_char_t; /* TODO ... wchar_t??? */ + +#define STIX_SIZEOF(x) (sizeof(x)) +#define STIX_COUNTOF(x) (sizeof(x) / sizeof(x[0])) + +/** + * The STIX_OFFSETOF() macro returns the offset of a field from the beginning + * of a structure. + */ +#define STIX_OFFSETOF(type,member) ((stix_uintptr_t)&((type*)0)->member) + +/** + * The STIX_ALIGNOF() macro returns the alignment size of a structure. + * Note that this macro may not work reliably depending on the type given. + */ +#define STIX_ALIGNOF(type) STIX_OFFSETOF(struct { stix_uint8_t d1; type d2; }, d2) + /*(sizeof(struct { stix_uint8_t d1; type d2; }) - sizeof(type))*/ + +#if defined(__cplusplus) +# if (__cplusplus >= 201103L) /* C++11 */ +# define STIX_NULL nullptr +# else +# define STIX_NULL (0) +# endif +#else +# define STIX_NULL ((void*)0) +#endif + + +typedef struct stix_mmgr_t stix_mmgr_t; + +/** + * allocate a memory chunk of the size \a n. + * @return pointer to a memory chunk on success, #STIX_NULL on failure. + */ +typedef void* (*stix_mmgr_alloc_t) (stix_mmgr_t* mmgr, stix_size_t n); +/** + * resize a memory chunk pointed to by \a ptr to the size \a n. + * @return pointer to a memory chunk on success, #STIX_NULL on failure. + */ +typedef void* (*stix_mmgr_realloc_t) (stix_mmgr_t* mmgr, void* ptr, stix_size_t n); +/** + * free a memory chunk pointed to by \a ptr. + */ +typedef void (*stix_mmgr_free_t) (stix_mmgr_t* mmgr, void* ptr); + +/** + * The stix_mmgr_t type defines the memory management interface. + * As the type is merely a structure, it is just used as a single container + * for memory management functions with a pointer to user-defined data. + * The user-defined data pointer \a ctx is passed to each memory management + * function whenever it is called. You can allocate, reallocate, and free + * a memory chunk. + * + * For example, a stix_xxx_open() function accepts a pointer of the stix_mmgr_t + * type and the xxx object uses it to manage dynamic data within the object. + */ +struct stix_mmgr_t +{ + stix_mmgr_alloc_t alloc; /**< allocation function */ + stix_mmgr_realloc_t realloc; /**< resizing function */ + stix_mmgr_free_t free; /**< disposal function */ + void* ctx; /**< user-defined data pointer */ +}; + +/** + * The STIX_MMGR_ALLOC() macro allocates a memory block of the \a size bytes + * using the \a mmgr memory manager. + */ +#define STIX_MMGR_ALLOC(mmgr,size) ((mmgr)->alloc(mmgr,size)) + +/** + * The STIX_MMGR_REALLOC() macro resizes a memory block pointed to by \a ptr + * to the \a size bytes using the \a mmgr memory manager. + */ +#define STIX_MMGR_REALLOC(mmgr,ptr,size) ((mmgr)->realloc(mmgr,ptr,size)) + +/** + * The STIX_MMGR_FREE() macro deallocates the memory block pointed to by \a ptr. + */ +#define STIX_MMGR_FREE(mmgr,ptr) ((mmgr)->free(mmgr,ptr)) + + +#if defined(_WIN32) || defined(__WATCOMC__) +# define STIX_IMPORT __declspec(dllimport) +# define STIX_EXPORT __declspec(dllexport) +# define STIX_PRIVATE +#elif defined(__GNUC__) && (__GNUC__>=4) +# define STIX_IMPORT __attribute__((visibility("default"))) +# define STIX_EXPORT __attribute__((visibility("default"))) +# define STIX_PRIVATE __attribute__((visibility("hidden"))) +/*# define STIX_PRIVATE __attribute__((visibility("internal")))*/ +#else +# define STIX_IMPORT +# define STIX_EXPORT +# define STIX_PRIVATE +#endif + +#if defined(__STDC_VERSION__) && (__STDC_VERSION__>=199901L) +# define STIX_INLINE inline +# define STIX_HAVE_INLINE +#elif defined(__GNUC__) && defined(__GNUC_GNU_INLINE__) + /* gcc disables inline when -std=c89 or -ansi is used. + * so use __inline__ supported by gcc regardless of the options */ +# define STIX_INLINE /*extern*/ __inline__ +# define STIX_HAVE_INLINE +#else +# define STIX_INLINE +# undef STIX_HAVE_INLINE +#endif + + +/* ========================================================================== */ + +/** + * The stix_errnum_t type defines the error codes. + */ +enum stix_errnum_t +{ + STIX_ENOERR, /**< no error */ + STIX_EOTHER, /**< other error */ + STIX_ENOIMPL, /**< not implemented */ + STIX_ESYSERR, /**< subsystem error */ + STIX_EINTERN, /**< internal error */ + STIX_ENOMEM, /**< insufficient memory */ + STIX_EINVAL, /**< invalid parameter or data */ + STIX_ENOENT /**< no matching entry */ +}; +typedef enum stix_errnum_t stix_errnum_t; + +enum stix_option_t +{ + STIX_TRAIT +}; +typedef enum stix_option_t stix_option_t; + +enum stix_trait_t +{ + /* perform no garbage collection when the heap is full. + * you still can use stix_gc() explicitly. */ + STIX_NOGC = (1 << 0) +}; +typedef enum stix_trait_t stix_trait_t; + +/* NOTE: sizeof(stix_oop_t) must be equal to sizeof(stix_oow_t) */ +typedef stix_uintptr_t stix_oow_t; +typedef struct stix_obj_t stix_obj_t; +typedef struct stix_obj_t* stix_oop_t; + +/* these are more specialized types for stix_obj_t */ +typedef struct stix_obj_oop_t stix_obj_oop_t; +typedef struct stix_obj_char_t stix_obj_char_t; +typedef struct stix_obj_uint8_t stix_obj_uint8_t; +typedef struct stix_obj_uint16_t stix_obj_uint16_t; + +/* these are more specialized types for stix_oop_t */ +typedef struct stix_obj_oop_t* stix_oop_oop_t; +typedef struct stix_obj_char_t* stix_oop_char_t; +typedef struct stix_obj_uint8_t* stix_oop_uint8_t; +typedef struct stix_obj_uint16_t* stix_oop_uint16_t; + +/* + * The Smalltalk-80 Bytecodes + * Range Bits Function + * ------------------------------------------------------------- + * 0-15 0000iiii Push Receiver Variable #iiii + * 16-31 0001iiii Push Temporary Location #iiii + * 32-63 001iiiii Push Literal Constant #iiiii + * 64-95 010iiiii Push Literal Variable #iiiii + * 96-103 01100iii Pop and Store Receiver Variable #iii + * 104-111 01101iii Pop and Store Temporary Location #iii + * 112-119 01110iii Push (receiver, _true, _false, _nil, -1, 0, 1, 2) [iii] + * 120-123 011110ii Return (receiver, _true, _false, _nil) [ii] From Message + * 124-125 0111110i Return Stack Top From (Message, Block) [i] + * 126-127 0111111i unused + * 128 10000000 jjkkkkkk Push (Receiver Variable, Temporary Location, Literal Constant, Literal Variable) [jj] #kkkkkk + * 129 10000001 jjkkkkkk Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk + * 130 10000010 jjkkkkkk Pop and Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk + * 131 10000011 jjjkkkkk Send Literal Selector #kkkkk With jjj Arguments + * 132 10000100 jjjjjjjj kkkkkkkk Send Literal Selector #kkkkkkkk With jjjjjjjj Arguments + * 133 10000101 jjjkkkkk Send Literal Selector #kkkkk To Superclass With jjj Arguments + * 134 10000110 jjjjjjjj kkkkkkkk Send Literal Selector #kkkkkkkk To Superclass With jjjjjjjj Arguments + * 135 10000111 Pop Stack Top + * 136 10001000 Duplicate Stack Top + * 137 10001001 Push Active Context + * 138-143 unused + * 144-151 10010iii Jump iii + 1 (i.e., 1 through 8) + * 152-159 10011iii Pop and Jump On False iii +1 (i.e., 1 through 8) + * 160-167 10100iii jjjjjjjj Jump(iii - 4) *256+jjjjjjjj + * 168-171 101010ii jjjjjjjj Pop and Jump On True ii *256+jjjjjjjj + * 172-175 101011ii jjjjjjjj Pop and Jump On False ii *256+jjjjjjjj + * 176-191 1011iiii Send Arithmetic Message #iiii + * 192-207 1100iiii Send Special Message #iiii + * 208-223 1101iiii Send Literal Selector #iiii With No Arguments + * 224-239 1110iiii Send Literal Selector #iiii With 1 Argument + * 240-255 1111iiii Send Literal Selector #iiii With 2 Arguments + */ + +/** + * The stix_code_t type defines byte-code enumerators. + */ +enum stix_code_t +{ + /* 0-15 */ + STIX_PUSH_RECEIVER_VARIABLE = 0x00, + + /* 16-31 */ + STIX_PUSH_TEMPORARY_LOCATION = 0x10, + + /* 32-63 */ + STIX_PUSH_LITERAL_CONSTANT = 0x20, + + /* 64-95 */ + STIX_PUSH_LITERAL_VARIABLE = 0x40, + + /* 96-103 */ + STIX_POP_STORE_RECEIVER_VARIABLE = 0x60, + + /* 104-111 */ + STIX_POP_STORE_TEMPORARY_LOCATION = 0x68, + + /* 112-119 */ + STIX_PUSH_RECEIVER = 0x70, + STIX_PUSH_TRUE = 0x71, + STIX_PUSH_FALSE = 0x72, + STIX_PUSH_NIL = 0x73, + STIX_PUSH_MINUSONE = 0x74, + STIX_PUSH_ZERO = 0x75, + STIX_PUSH_ONE = 0x76, + STIX_PUSH_TWO = 0x77, + + /* 120-123 */ + STIX_RETURN_RECEIVER = 0x78, + STIX_RETURN_TRUE = 0x79, + STIX_RETURN_FALSE = 0x7A, + STIX_RETURN_NIL = 0x7B, + + /* 124-125 */ + STIX_RETURN_FROM_MESSAGE = 0x7C, + STIX_RETURN_FROM_BLOCK = 0x7D, + + /* 128 */ + STIX_PUSH_EXTENDED = 0x80, + + /* 129 */ + STIX_STORE_EXTENDED = 0x81, + + /* 130 */ + STIX_POP_STORE_EXTENDED = 0x82, + + /* 131 */ + STIX_SEND_TO_SELF = 0x83, + + /* 132 */ + STIX_SEND_TO_SUPER = 0x84, + + /* 133 */ + STIX_SEND_TO_SELF_EXTENDED = 0x85, + + /* 134 */ + STIX_SEND_TO_SUPER_EXTENDED = 0x86, + + /* 135 */ + STIX_POP_STACK_TOP = 0x87, + + /* 136 */ + STIX_DUP_STACK_TOP = 0x88, + + /* 137 */ + STIX_PUSH_ACTIVE_CONTEXT = 0x89, + + /* 138 */ + STIX_DO_PRIMITIVE = 0x8A, + + /* 144-151 */ + STIX_JUMP = 0x90, + + /* 152-159 */ + STIX_POP_JUMP_ON_FALSE = 0x98, + + /* 160-167 */ + STIX_JUMP_EXTENDED = 0xA0, + + /* 168-171 */ + STIX_POP_JUMP_ON_TRUE_EXTENDED = 0xA8, + + /* 172-175 */ + STIX_POP_JUMP_ON_FALSE_EXTENDED = 0xAC, + +#if 0 + STIX_PUSH_RECEIVER_VARIABLE_EXTENDED = 0x60 + STIX_PUSH_TEMPORARY_LOCATION_EXTENDED = 0x61 + STIX_PUSH_LITERAL_CONSTANT_EXTENDED = 0x62 + STIX_PUSH_LITERAL_VARIABLE_EXTENDED = 0x63 + STIX_STORE_RECEIVER_VARIABLE_EXTENDED = 0x64 + STIX_STORE_TEMPORARY_LOCATION_EXTENDED = 0x65 + + STIX_POP_STACK_TOP = 0x67 + STIX_DUPLICATE_STACK_TOP = 0x68 + STIX_PUSH_ACTIVE_CONTEXT = 0x69 + STIX_PUSH_NIL = 0x6A + STIX_PUSH_TRUE = 0x6B + STIX_PUSH_FALSE = 0x6C + STIX_PUSH_RECEIVER = 0x6D + + STIX_SEND_TO_SELF = 0x70 + STIX_SEND_TO_SUPER = 0x71 + STIX_SEND_TO_SELF_EXTENDED = 0x72 + STIX_SEND_TO_SUPER_EXTENDED = 0x73 + + STIX_RETURN_RECEIVER = 0x78 + STIX_RETURN_TRUE = 0x79 + STIX_RETURN_FALSE = 0x7A + STIX_RETURN_NIL = 0x7B + STIX_RETURN_FROM_MESSAGE = 0x7C + STIX_RETURN_FROM_BLOCK = 0x7D + + STIX_DO_PRIMITIVE = 0xF0 +#endif +}; + +typedef enum stix_code_t stix_code_t; + + +typedef struct stix_heap_t stix_heap_t; + +struct stix_heap_t +{ + stix_uint8_t* base; /* start of a heap */ + stix_uint8_t* limit; /* end of a heap */ + stix_uint8_t* ptr; /* next allocation pointer */ +}; + +typedef struct stix_t stix_t; + +struct stix_t +{ + stix_mmgr_t* mmgr; + stix_errnum_t errnum; + + struct + { + int trait; + } option; + + /* ========================= */ + + stix_heap_t* permheap; + stix_heap_t* curheap; + stix_heap_t* newheap; + + /* ========================= */ + + stix_oop_t _nil; /* pointer to the nil object */ + stix_oop_t _true; + stix_oop_t _false; + + stix_oop_oop_t root; /* pointer to the system dictionary */ + stix_oop_oop_t symtab; /* system-wide symbol table */ + + struct + { + stix_oop_oop_t array; + stix_oop_oop_t association; + /*stix_oop_oop_t metaclass;*/ + stix_oop_oop_t string; + stix_oop_oop_t symbol; + stix_oop_oop_t sysdic; + stix_oop_oop_t numeric[2]; /* [0]: smint [1]: character */ + } cc; /* common kernel classes */ +}; + + +/* + * OOP encoding + * An object pointer(OOP) is an ordinary pointer value to an object. + * but some simple numeric values are also encoded into OOP using a simple + * bit-shifting and masking. + * + * A real OOP is stored without any bit-shifting while a non-OOP value encoded + * in an OOP is bit-shifted to the left by 2 and the 2 least-significant bits + * are set to 1 or 2. + * + * This scheme works because the object allocators aligns the object size to + * a multiple of sizeof(stix_oop_t). This way, the 2 least-significant bits + * of a real OOP are always 0s. + */ + +#define STIX_OOP_TYPE_BITS 2 +#define STIX_OOP_TYPE_SMINT 1 +#define STIX_OOP_TYPE_CHAR 2 + +#define STIX_OOP_IS_NUMERIC(oop) (((stix_oow_t)oop) & (STIX_OOP_TYPE_SMINT | STIX_OOP_TYPE_CHAR)) +#define STIX_OOP_IS_POINTER(oop) (!STIX_OOP_IS_NUMERIC(oop)) + +#define STIX_OOP_IS_SMINT(oop) (((stix_oow_t)oop) & STIX_OOP_TYPE_SMINT) +#define STIX_OOP_IS_CHAR(oop) (((stix_oow_t)oop) & STIX_OOP_TYPE_CHAR) +#define STIX_OOP_FROM_SMINT(num) ((stix_oop_t)(((num) << STIX_OOP_TYPE_BITS) | STIX_OOP_TYPE_SMINT)) +#define STIX_OOP_TO_SMINT(oop) (((stix_oow_t)oop) >> STIX_OOP_TYPE_BITS) +#define STIX_OOP_FROM_CHAR(num) ((stix_oop_t)(((num) << STIX_OOP_TYPE_BITS) | STIX_OOP_TYPE_CHAR)) +#define STIX_OOP_TO_CHAR(oop) (((stix_oow_t)oop) >> STIX_OOP_TYPE_BITS) + +/* + * Object structure + */ +#define STIX_OBJ_TYPE_BITS 6 +#define STIX_OBJ_FLAG_BITS 5 +#define STIX_OBJ_EXTRA_BITS 1 +#define STIX_OBJ_UNIT_BITS 4 + +enum stix_obj_type_t +{ + STIX_OBJ_TYPE_OOP, + STIX_OBJ_TYPE_CHAR, + STIX_OBJ_TYPE_UINT8, + STIX_OBJ_TYPE_UINT16 + +/* NOTE: you can have STIX_OBJ_SHORT, STIX_OBJ_INT + * STIX_OBJ_LONG, STIX_OBJ_FLOAT, STIX_OBJ_DOUBLE, etc + * type type field being 6 bits long, you can have up to 64 different types. + + STIX_OBJ_TYPE_SHORT, + STIX_OBJ_TYPE_INT, + STIX_OBJ_TYPE_LONG, + STIX_OBJ_TYPE_FLOAT, + STIX_OBJ_TYPE_DOUBLE */ +}; +typedef enum stix_obj_type_t stix_obj_type_t; + + +/* KERNEL indicates that the object is known to the virtual + * machine. VM doesn't allow layout changes of such objects. */ +enum stix_obj_flag_t +{ + STIX_OBJ_FLAG_KERNEL = (1 << 0), + STIX_OBJ_FLAG_HYBRID = (1 << 1), + STIX_OBJ_FLAG_MOVED = (1 << 2) +}; +typedef enum stix_obj_flag_t stix_obj_flag_t; + +/* ------------------------------------------------------------------------- + * type: the type of a payload item. + * one of STIX_OBJ_TYPE_OOP, STIX_OBJ_TYPE_CHAR, + * STIX_OBJ_TYPE_UINT8, STIX_OBJ_TYPE_UINT16 + * flags: bitwise-ORed of stix_obj_flag_t + * extra: 0 or 1. 1 indicates that the payload contains 1 more + * item than the value of the size field. mostly used for a + * terminating null in a variable-char object. + * unit: the size of a payload item in bytes. + * size: the number of payload items in an object. + * it doesn't include the header size. + * + * The total number of bytes occupied by an object can be calculated + * with this fomula: + * sizeof(stix_obj_t) + ALIGN((size + extra) * unit), sizeof(stix_oop_t)) + * + * The ALIGN() macro is used above since allocation adjusts the payload + * size to a multiple of sizeof(stix_oop_t). it assumes that sizeof(stix_obj_t) + * is a multiple of sizeof(stix_oop_t). See the STIX_BYTESOF() macro. + * + * Due to the header structure, an object can only contain items of + * homogeneous data types in the payload. + * + * It's actually possible to split the size field into 2. For example, + * the upper half contains the number of oops and the lower half contains + * the number of bytes/chars. This way, a variable-byte class or a variable-char + * class can have normal instance variables. On the contrary, the actual byte + * size calculation and the access to the payload fields become more complex. + * Therefore, i've dropped the idea. + * ------------------------------------------------------------------------- */ +#define STIX_OBJ_HEADER \ + stix_oow_t type: STIX_OBJ_TYPE_BITS; \ + stix_oow_t flags: STIX_OBJ_FLAG_BITS; \ + stix_oow_t extra: STIX_OBJ_EXTRA_BITS; \ + stix_oow_t unit: STIX_OBJ_UNIT_BITS; \ + stix_oow_t size; \ + stix_oop_t _class + +struct stix_obj_t +{ + STIX_OBJ_HEADER; +}; + +struct stix_obj_oop_t +{ + STIX_OBJ_HEADER; + stix_oop_t slot[1]; +}; + +struct stix_obj_char_t +{ + STIX_OBJ_HEADER; + stix_char_t slot[1]; +}; + +struct stix_obj_uint8_t +{ + STIX_OBJ_HEADER; + stix_uint8_t slot[1]; +}; + +struct stix_obj_uint16_t +{ + STIX_OBJ_HEADER; + stix_uint16_t slot[1]; +}; + +#if 0 + +/* ----------------------------------------- + * class structures for classes known to VM + * ----------------------------------------- */ +enum stix_class_desc_t +{ + /* STIX_XXX_SIZE represents the size of the class. other + * enumerators represent the index of instance variables of + * the class */ + + STIX_ASSOCIATION_KEY = 0, + STIX_ASSOCIATION_VALUE, + STIX_ASSOCIATION_SIZE, + + STIX_DICTIONARY_TALLY = 0, + STIX_DICTIONARY_BUCKET, + STIX_DICTIONARY_SIZE, + + STIX_BEHAVIOR_SPEC = 0, + STIX_BEHAVIOR_METHODS, + STIX_BEHAVIOR_SUPERCLASS, + STIX_BEHAVIOR_SUBCLASSES, + STIX_BEHAVIOR_SIZE, + + STIX_CLASS_SPEC = 0, + STIX_CLASS_METHODS, + STIX_CLASS_SUPERCLASS, + STIX_CLASS_SUBCLASSES, + STIX_CLASS_NAME, + STIX_CLASS_INSTANCE_VARIABLES, + STIX_CLASS_CLASS_VARIABLES, + STIX_CLASS_POOL_DICTIONARIES, + STIX_CLASS_SIZE, + + STIX_METACLASS_SPEC = 0, + STIX_METACLASS_METHODS, + STIX_METACLASS_SUPERCLASS, + STIX_METACLASS_SUBCLASSES, + STIX_METACLASS_INSTANCE_CLASS, + STIX_METACLASS_INSTANCE_VARIABLES, + STIX_METACLASS_SIZE, + + STIX_BLOCK_CONTEXT = 0, + STIX_BLOCK_ARG_COUNT, + STIX_BLOCK_ARG_LOC, + STIX_BLOCK_BYTE_POINTER, + STIX_BLOCK_SIZE, + + STIX_CONTEXT_STACK = 0, + STIX_CONTEXT_STACK_TOP, + STIX_CONTEXT_RECEIVER, + STIX_CONTEXT_PC, + STIX_CONTEXT_METHOD, + STIX_CONTEXT_SIZE, + + STIX_METHOD_TEXT = 0, + STIX_METHOD_SELECTOR, + STIX_METHOD_BYTECODES, + STIX_METHOD_TMPCOUNT, + STIX_METHOD_ARGCOUNT, + STIX_METHOD_SIZE, + + STIX_SYMTAB_TALLY = 0, + STIX_SYMTAB_BUCKET, + STIX_SYMTAB_SIZE, + + STIX_SYSDIC_TALLY = STIX_DICTIONARY_TALLY, + STIX_SYSDIC_BUCKET = STIX_DICTIONARY_BUCKET, + STIX_SYSDIC_SIZE = STIX_DICTIONARY_SIZE +}; + + + +struct stix_kcinfo_t +{ + const stix_char_t* name; + int super; + int fixed; /* the number of fixed fields */ + int vtype; /* variable class type */ + + int nivars; /* instance variables */ + stix_cstr_t ivars[10]; + + int ncvars; /* class variables */ + stix_cstr_t cvars[10]; + + int ncivars; /* class instance variables */ + stix_cstr_t civars[10]; +}; + +typedef struct stix_kcinfo_t stix_kcinfo_t; + +enum stix_kc_t +{ + STIX_VM_KC_OBJECT, + STIX_VM_KC_UNDEFINED_OBJECT, + STIX_VM_KC_BEHAVIOR, + STIX_VM_KC_CLASS, + STIX_VM_KC_METACLASS, + STIX_VM_KC_BLOCK, + STIX_VM_KC_BOOLEAN, + STIX_VM_KC_TRUE, + STIX_VM_KC_FALSE, + STIX_VM_KC_CONTEXT, + STIX_VM_KC_METHOD, + STIX_VM_KC_MAGNITUDE, + STIX_VM_KC_ASSOCIATION, + STIX_VM_KC_CHARACTER, + STIX_VM_KC_NUMBER, + STIX_VM_KC_INTEGER, + STIX_VM_KC_SMALL_INTEGER, + STIX_VM_KC_LARGE_INTEGER, + STIX_VM_KC_COLLECTION, + STIX_VM_KC_INDEXED_COLLECTION, + STIX_VM_KC_ARRAY, + STIX_VM_KC_BYTE_ARRAY, + STIX_VM_KC_SYMBOL_TABLE, + STIX_VM_KC_DICTIONARY, + STIX_VM_KC_SYSTEM_DICTIONARY, + STIX_VM_KC_STRING, + STIX_VM_KC_SYMBOL, + + STIX_VM_KC_MAX /* indicate the number of kernel classes */ +}; +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +STIX_EXPORT stix_t* stix_open ( + stix_mmgr_t* mmgr, + stix_size_t xtnsize, + stix_size_t heapsize, + stix_errnum_t* errnum +); + +STIX_EXPORT void stix_close ( + stix_t* vm +); + +STIX_EXPORT int stix_init ( + stix_t* vm, + stix_mmgr_t* mmgr, + stix_size_t heapsz +); + +STIX_EXPORT void stix_fini ( + stix_t* vm +); + +/** + * The stix_getoption() function gets the value of an option + * specified by \a id into the buffer pointed to by \a value. + * + * \return 0 on success, -1 on failure + */ +STIX_EXPORT int stix_getoption ( + stix_t* vm, + stix_option_t id, + void* value +); + +/** + * The stix_setoption() function sets the value of an option + * specified by \a id to the value pointed to by \a value. + * + * \return 0 on success, -1 on failure + */ +STIX_EXPORT int stix_setoption ( + stix_t* vm, + stix_option_t id, + const void* value +); + +/** + * The stix_gc() function performs garbage collection. + * It is not affected by #STIX_NOGC. + */ +STIX_EXPORT void stix_gc ( + stix_t* vm +); + +/** + * The stix_findclass() function searchs the root system dictionary + * for a class named \a name. The class object pointer is set to the + * memory location pointed to by \a oop. + * + * \return 0 if found, -1 if not found. + */ +STIX_EXPORT int stix_findclass ( + stix_t* vm, + const stix_char_t* name, + stix_oop_t* oop +); + + +/** + * The stix_instantiate() function creates a new object of the class + * \a _class. The size of the fixed part is taken from the information + * contained in the class defintion. The \a vlen parameter specifies + * the length of the variable part. The \a vptr parameter points to + * the memory area to copy into the variable part of the new object. + * If \a vptr is #STIX_NULL, the variable part is initialized to 0 or + * an equivalent value depending on the type. + */ +STIX_EXPORT stix_oop_t stix_instantiate ( + stix_t* stix, + stix_oop_t _class, + const void* vptr, + stix_oow_t vlen +); + +#if defined(__cplusplus) +} +#endif + + +#endif