added experimental code to support byte trailer of a pointer object. the main purpose is to embed byte codes into the back of the compiled method object.

fixed buggy code using the freed pointer when reallocation has occurred - callers of clone_keyword(), clone_assignee(), clone_binsel()
This commit is contained in:
hyunghwan.chung 2015-07-01 15:01:39 +00:00
parent d6a9ca91fa
commit 60299cda5b
8 changed files with 723 additions and 80 deletions

391
stix/lib/Stix.st Normal file
View File

@ -0,0 +1,391 @@
#class Stix(nil)
{
#dcl(#class) sysdic.
#method(#class) yourself
{
^self.
}
#method yourself
{
^self.
}
#method(#class) dump
{
<primitive: 0>
}
#method dump
{
<primitive: 0>
}
#method(#class) new
{
<primitive: 1>
}
#method(#class) new: anInteger
{
<primitive: 2>
}
#method basicSize
{
<primitive: 3>
^0
}
#method basicAt: anInteger
{
<primitive: 4>
## self error: 'out of range'.
}
#method basicAt: anInteger put: anObject
{
<primitive: 5>
## self error: 'out of range'.
}
#method badReturnError
{
## TODO: implement this
}
#method mustBeBoolean
{
## TODO: implement this
}
#method doesNotUnderstand: aMessageSymbol
{
## TODO: implement this
}
#method error: anErrorString
{
anErrorString dump.
}
}
#class Object(Stix)
{
}
#class NilObject(Stix)
{
}
#class(#pointer) Class(Stix)
{
#dcl spec selfspec superclass subclasses name instvars classvars classinstvars instmthdic classmthdic.
}
#class Magnitude(Object)
{
}
#class Association(Magnitude)
{
#dcl key value.
}
#class Character(Magnitude)
{
}
#class Number(Magnitude)
{
#method add: aNumber
{
<primitive: 7>
}
#method + aNumber
{
<primitive: 7>
}
#method - aNumber
{
<primitive: 8>
}
#method * aNumber
{
<primitive: 8>
}
#method = aNumber
{
<primitive: 10>
}
#method < aNumber
{
<primitive: 11>
}
#method > aNumber
{
<primitive: 12>
}
}
#class SmallInteger(Number)
{
}
#class Boolean(Object)
{
}
#class True(Boolean)
{
#method ifTrue: trueBlock ifFalse: falseBlock
{
^trueBlock value.
}
#method ifTrue: trueBlock
{
^trueBlock value.
}
#method ifFalse: falseBlock
{
^nil.
}
}
#class False(Boolean)
{
#method ifTrue: trueBlock ifFalse: falseBlock
{
^falseBlock value.
}
#method ifTrue: trueBlock
{
^nil.
}
#method ifFalse: falseBlock
{
^falseBlock value.
}
}
#class Collection(Object)
{
}
#class(#byte) ByteArray(Collection)
{
#method at: anInteger
{
^self basicAt: anInteger.
}
#method at: anInteger put: aValue
{
^self basicAt: anInteger put: aValue.
}
}
#class(#pointer) Array(Collection)
{
#method at: anInteger
{
^self basicAt: anInteger.
}
#method at: anInteger put: aValue
{
^self basicAt: anInteger put: aValue.
}
}
#class(#character) String(Array)
{
}
#class(#character) Symbol(Array)
{
}
#class Set(Collection)
{
#dcl tally bucket.
}
#class SymbolSet(Set)
{
}
#class Dictionary(Set)
{
}
#class SystemDictionary(Dictionary)
{
}
#class MethodDictionary(Dictionary)
{
}
#class(#pointer) Context(Stix)
{
}
#class(#pointer) MethodContext(Context)
{
#dcl sender ip sp ntmprs method receiver home origin.
#method pc
{
^ip
}
#method pc: anInteger
{
ip := anInteger.
"sp := sp - 1." "whould this always work??? "
}
#method sp
{
^sp.
}
#method sp: anInteger
{
sp := anInteger.
}
#method pc: aPC sp: aSP
{
ip := aPC.
sp := aSP.
##sp := sp - 1.
}
}
#class(#pointer) BlockContext(Context)
{
#dcl caller ip sp ntmprs nargs source home origin.
#method value
{
<primitive: 6>
}
#method value: a
{
<primitive: 6>
}
#method value: a value: b
{
<primitive: 6>
}
#method value: a value: b value: c
{
<primitive: 6>
}
#method whileTrue: aBlock
{
## http://stackoverflow.com/questions/2500483/is-there-a-way-in-a-message-only-language-to-define-a-whiletrue-message-without
## ----------------------------------------------------------------------------
## ^(self value) ifTrue: [aBlock value. self whileTrue: aBlock].
## ----------------------------------------------------------------------------
## less block context before whileTrue: is recursively sent.
## whileTrue: is sent in a method context.
## (self value) ifFalse: [^nil].
## aBlock value.
## self whileTrue: aBlock.
## ----------------------------------------------------------------------------
## ----------------------------------------------------------------------------
| pc sp xsp |
sp := thisContext sp.
sp := sp - 1. "decrement sp by 1 becuase thisContext pushed above affects the sp method"
pc := thisContext pc.
self value ifFalse: [ ^nil "^self" ].
aBlock value.
##thisContext pc: pc - 3 sp: sp.
##thisContext pc: pc + 2 sp: sp.
thisContext pc: pc + 1 sp: sp.
## this +2 or - 3 above is dependent on the byte code instruction size used for 'store'
## +2 to skip STORE_INTO_TEMP(pc) and POP_STACKTOP.
## TODO: make it independent of the byte code size
## ----------------------------------------------------------------------------
## #<label>:
## thisContext pc: #<label> sp: sp.
##
## | pc |
## pc := thisContext pc.
## ^self value ifTrue: [aBlock value. thisContext pc: pc]
## ----------------------------------------------------------------------------
## self value ifTrue: [ aBlock value. thisContext restart. ].
}
#method pc
{
^ip
}
#method pc: anInteger
{
ip := anInteger.
}
#method sp
{
^sp
}
#method sp: anInteger
{
sp := anInteger.
}
#method restart
{
ip := source pc.
}
}
#class(#pointer) CompiledMethod(Object)
{
#dcl owner preamble ntmprs nargs code source.
}
#################################################################
## MAIN
#################################################################

View File

@ -1844,7 +1844,7 @@ done:
return pos;
}
static int clone_assignee (stix_t* stix, stix_ucs_t* name)
static int clone_assignee (stix_t* stix, const stix_ucs_t* name, stix_size_t* offset)
{
int n;
stix_size_t old_len;
@ -1854,11 +1854,12 @@ static int clone_assignee (stix_t* stix, stix_ucs_t* name)
if (n <= -1) return -1;
/* update the pointer to of the name. its length is the same. */
name->ptr = stix->c->mth.assignees.ptr + old_len;
/*name->ptr = stix->c->mth.assignees.ptr + old_len;*/
*offset = old_len;
return 0;
}
static int clone_binary_selector (stix_t* stix, stix_ucs_t* name)
static int clone_binary_selector (stix_t* stix, const stix_ucs_t* name, stix_size_t* offset)
{
int n;
stix_size_t old_len;
@ -1868,11 +1869,12 @@ static int clone_binary_selector (stix_t* stix, stix_ucs_t* name)
if (n <= -1) return -1;
/* update the pointer to of the name. its length is the same. */
name->ptr = stix->c->mth.binsels.ptr + old_len;
/*name->ptr = stix->c->mth.binsels.ptr + old_len;*/
*offset = old_len;
return 0;
}
static int clone_keyword (stix_t* stix, stix_ucs_t* name)
static int clone_keyword (stix_t* stix, const stix_ucs_t* name, stix_size_t* offset)
{
int n;
stix_size_t old_len;
@ -1882,7 +1884,8 @@ static int clone_keyword (stix_t* stix, stix_ucs_t* name)
if (n <= -1) return -1;
/* update the pointer to of the name. its length is the same. */
name->ptr = stix->c->mth.kwsels.ptr + old_len;
/*name->ptr = stix->c->mth.kwsels.ptr + old_len;*/
*offset = old_len;
return 0;
}
@ -3052,7 +3055,7 @@ static int compile_binary_message (stix_t* stix, int to_super)
stix_size_t index;
int to_super2;
stix_ucs_t binsel;
stix_size_t saved_binsels_len;
stix_size_t saved_binsels_len, binsel_offset;
STIX_ASSERT (stix->c->tok.type == STIX_IOTOK_BINSEL);
@ -3061,7 +3064,7 @@ static int compile_binary_message (stix_t* stix, int to_super)
binsel = stix->c->tok.name;
saved_binsels_len = stix->c->mth.binsels.len;
if (clone_binary_selector(stix, &binsel) <= -1) goto oops;
if (clone_binary_selector(stix, &binsel, &binsel_offset) <= -1) goto oops;
GET_TOKEN (stix);
@ -3069,6 +3072,10 @@ static int compile_binary_message (stix_t* stix, int to_super)
if (stix->c->tok.type == STIX_IOTOK_IDENT && compile_unary_message(stix, to_super2) <= -1) goto oops;
/* update the pointer to the cloned selector now
* to be free from reallocation risk for the recursive call
* to compile_expression_primary(). */
binsel.ptr = &stix->c->mth.binsels.ptr[binsel_offset];
if (add_symbol_literal(stix, &binsel, &index) <= -1 ||
emit_double_param_instruction(stix, send_message_cmd[to_super], 1, index) <= -1) goto oops;
printf ("\tsend binary message %d [", (int)index);
@ -3098,6 +3105,7 @@ static int compile_keyword_message (stix_t* stix, int to_super)
stix_ucs_t kw, kwsel;
stix_ioloc_t saved_kwsel_loc;
stix_size_t saved_kwsel_len;
stix_size_t kw_offset;
stix_size_t nargs = 0;
saved_kwsel_loc = stix->c->tok.loc;
@ -3106,7 +3114,7 @@ static int compile_keyword_message (stix_t* stix, int to_super)
do
{
kw = stix->c->tok.name;
if (clone_keyword(stix, &kw) <= -1) goto oops;
if (clone_keyword(stix, &kw, &kw_offset) <= -1) goto oops;
GET_TOKEN (stix);
@ -3114,6 +3122,7 @@ static int compile_keyword_message (stix_t* stix, int to_super)
if (stix->c->tok.type == STIX_IOTOK_IDENT && compile_unary_message(stix, to_super2) <= -1) goto oops;
if (stix->c->tok.type == STIX_IOTOK_BINSEL && compile_binary_message(stix, to_super2) <= -1) goto oops;
kw.ptr = &stix->c->mth.kwsels.ptr[kw_offset];
if (nargs >= MAX_CODE_NARGS)
{
/* 'kw' points to only one segment of the full keyword message.
@ -3297,10 +3306,13 @@ static int compile_method_expression (stix_t* stix, int pop)
if (stix->c->tok.type == STIX_IOTOK_IDENT)
{
stix_ioloc_t assignee_loc;
stix_size_t assignee_offset;
/* store the assignee name to the internal buffer
* to make it valid after the token buffer has been overwritten */
assignee = stix->c->tok.name;
if (clone_assignee(stix, &assignee) <= -1) return -1;
if (clone_assignee(stix, &assignee, &assignee_offset) <= -1) return -1;
assignee_loc = stix->c->tok.loc;
@ -3316,8 +3328,16 @@ printf ("ASSIGNIUNG TO ....");
print_ucs (&assignee);
printf ("\n");
if (compile_method_expression(stix, 0) <= -1 ||
get_variable_info(stix, &assignee, &assignee_loc, &var) <= -1) goto oops;
if (compile_method_expression(stix, 0) <= -1) goto oops;
/* compile_method_expression() is called after clone_assignee().
* clone_assignee() may reallocate a single buffer to hold
* a series of assigness names. the pointer based operation is
* fragile as it can change. use the offset of the cloned
* assignee to update the actual pointer after the recursive
* compile_method_expression() call */
assignee.ptr = &stix->c->mth.assignees.ptr[assignee_offset];
if (get_variable_info(stix, &assignee, &assignee_loc, &var) <= -1) goto oops;
switch (var.type)
{
@ -3383,6 +3403,7 @@ printf ("\t%s_into_object %d\n", (pop? "pop":"store"), (int)index);
}
else
{
assignee.ptr = &stix->c->mth.assignees.ptr[assignee_offset];
if (compile_basic_expression(stix, &assignee, &assignee_loc) <= -1) goto oops;
}
}
@ -3453,7 +3474,6 @@ if (n == 0) printf ("\tpop_stacktop\n");
}
}
static int compile_method_statements (stix_t* stix)
{
/*
@ -3498,7 +3518,11 @@ static int add_compiled_method (stix_t* stix)
{
stix_oop_t name; /* selector */
stix_oop_method_t mth; /* method */
#if defined(STIX_USE_OBJECT_TRAILER)
/* nothing extra */
#else
stix_oop_byte_t code;
#endif
stix_size_t tmp_count = 0;
stix_size_t i;
stix_ooi_t preamble_code, preamble_index;
@ -3508,8 +3532,13 @@ static int add_compiled_method (stix_t* stix)
stix_pushtmp (stix, &name); tmp_count++;
/* The variadic data part passed to stix_instantiate() is not GC-safe */
#if defined(STIX_USE_OBJECT_TRAILER)
mth = (stix_oop_method_t)stix_instantiatewithtrailer (stix, stix->_method, stix->c->mth.literal_count, stix->c->mth.code.ptr, stix->c->mth.code.len);
#else
mth = (stix_oop_method_t)stix_instantiate (stix, stix->_method, STIX_NULL, stix->c->mth.literal_count);
#endif
if (!mth) goto oops;
for (i = 0; i < stix->c->mth.literal_count; i++)
{
/* let's do the variadic data initialization here */
@ -3517,9 +3546,13 @@ static int add_compiled_method (stix_t* stix)
}
stix_pushtmp (stix, (stix_oop_t*)&mth); tmp_count++;
#if defined(STIX_USE_OBJECT_TRAILER)
/* do nothing */
#else
code = (stix_oop_byte_t)stix_instantiate (stix, stix->_byte_array, stix->c->mth.code.ptr, stix->c->mth.code.len);
if (!code) goto oops;
stix_pushtmp (stix, (stix_oop_t*)&code); tmp_count++;
#endif
preamble_code = STIX_METHOD_PREAMBLE_NONE;
preamble_index = 0;
@ -3564,6 +3597,7 @@ static int add_compiled_method (stix_t* stix)
}
}
}
/* TODO: check more special cases like 'return true' and encode it to this preamble */
}
}
else
@ -3578,7 +3612,12 @@ static int add_compiled_method (stix_t* stix)
mth->preamble = STIX_OOP_FROM_SMINT(STIX_METHOD_MAKE_PREAMBLE(preamble_code, preamble_index));
mth->tmpr_count = STIX_OOP_FROM_SMINT(stix->c->mth.tmpr_count);
mth->tmpr_nargs = STIX_OOP_FROM_SMINT(stix->c->mth.tmpr_nargs);
#if defined(STIX_USE_OBJECT_TRAILER)
/* do nothing */
#else
mth->code = code;
#endif
/*TODO: preserve source??? mth->text = stix->c->mth.text
the compiler must collect all source method string collected so far.

View File

@ -60,7 +60,6 @@
#define ACTIVE_STACK_ISEMPTY(stix) ((stix)->sp <= -1)
#define SWITCH_ACTIVE_CONTEXT(stix,v_ctx) \
do \
{ \
@ -68,11 +67,24 @@
STORE_ACTIVE_SP (stix); \
(stix)->active_context = (v_ctx); \
(stix)->active_method = (stix_oop_method_t)(stix)->active_context->origin->method_or_nargs; \
(stix)->active_code = (stix)->active_method->code; \
SET_ACTIVE_METHOD_CODE(stix); \
LOAD_ACTIVE_IP (stix); \
LOAD_ACTIVE_SP (stix); \
} while (0) \
#define FETCH_BYTE_CODE(stix) ((stix)->active_code[(stix)->ip++])
#define FETCH_BYTE_CODE_TO(stix, v_ooi) (v_ooi = FETCH_BYTE_CODE(stix))
#if (STIX_BCODE_LONG_PARAM_SIZE == 2)
#define FETCH_PARAM_CODE_TO(stix, v_ooi) \
do { \
v_ooi = FETCH_BYTE_CODE(stix); \
v_ooi = (v_ooi << 8) | FETCH_BYTE_CODE(stix); \
} while (0)
#else
#define FETCH_PARAM_CODE_TO(stix, v_ooi) (v_ooi = FETCH_BYTE_CODE(stix))
#endif
static STIX_INLINE int activate_new_method (stix_t* stix, stix_oop_method_t mth)
{
stix_oop_context_t ctx;
@ -863,24 +875,6 @@ static primitive_t primitives[] =
{ 1, primitive_integer_gt } /* 12 */
};
#define FETCH_BYTE_CODE_TO(stix, v_ooi) (v_ooi = (stix)->active_code->slot[(stix)->ip++])
#if (STIX_BCODE_LONG_PARAM_SIZE == 2)
#define FETCH_PARAM_CODE_TO(stix, v_ooi) \
do { \
v_ooi = (stix)->active_code->slot[(stix)->ip++]; \
v_ooi = (v_ooi << 8) | (stix)->active_code->slot[stix->ip++]; \
} while (0)
#else /* STIX_BCODE_LONG_PARAM_SIZE == 2 */
#define FETCH_PARAM_CODE_TO(stix, v_ooi) (v_ooi = (stix)->active_code->slot[(stix)->ip++])
#endif /* STIX_BCODE_LONG_PARAM_SIZE == 2 */
int stix_execute (stix_t* stix)
{
stix_byte_t bcode;

View File

@ -51,13 +51,6 @@ static void compact_symbol_table (stix_t* stix, stix_oop_t _nil)
STIX_ASSERT (stix->symtab->bucket->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 < bucket_size; i++)
{
y = (y + 1) % bucket_size;
@ -96,7 +89,6 @@ stix_oop_t stix_moveoop (stix_t* stix, stix_oop_t oop)
if (!oop) return oop;
#endif
STIX_ASSERT (STIX_OOP_IS_POINTER(oop));
/*if (STIX_OOP_IS_POINTER(oop)) return oop;*/
@ -113,8 +105,39 @@ stix_oop_t stix_moveoop (stix_t* stix, stix_oop_t oop)
stix_oow_t nbytes_aligned;
stix_oop_t tmp;
#if defined(STIX_USE_OBJECT_TRAILER)
if (STIX_OBJ_GET_FLAGS_TRAILER(oop))
{
stix_oow_t nbytes;
/* only an OOP object can have the trailer.
*
* | _flags |
* | _size | <-- if it's 3
* | _class |
* | X |
* | X |
* | X |
* | Y | <-- it may exist if EXTRA is set in _flags.
* | Z | <-- if TRAILER is set, it is the number of bytes in the trailer
* | | | | |
*/
STIX_ASSERT (STIX_OBJ_GET_FLAGS_TYPE(oop) == STIX_OBJ_TYPE_OOP);
STIX_ASSERT (STIX_OBJ_GET_FLAGS_UNIT(oop) == STIX_SIZEOF(stix_oow_t));
STIX_ASSERT (STIX_OBJ_GET_FLAGS_EXTRA(oop) == 0); /* no 'extra' for an OOP object */
nbytes = STIX_OBJ_BYTESOF(oop) + STIX_SIZEOF(stix_oow_t) + \
(stix_oow_t)((stix_oop_oop_t)oop)->slot[STIX_OBJ_GET_SIZE(oop)];
nbytes_aligned = STIX_ALIGN (nbytes, STIX_SIZEOF(stix_oop_t));
}
else
{
#endif
/* calculate the payload size in bytes */
nbytes_aligned = STIX_ALIGN (STIX_OBJ_BYTESOF(oop), STIX_SIZEOF(stix_oop_t));
#if defined(STIX_USE_OBJECT_TRAILER)
}
#endif
/* allocate space in the new heap */
tmp = stix_allocheapmem (stix, stix->newheap, STIX_SIZEOF(stix_obj_t) + nbytes_aligned);
@ -154,7 +177,27 @@ static stix_uint8_t* scan_new_heap (stix_t* stix, stix_uint8_t* ptr)
stix_oop_t oop;
oop = (stix_oop_t)ptr;
#if defined(STIX_USE_OBJECT_TRAILER)
if (STIX_OBJ_GET_FLAGS_TRAILER(oop))
{
stix_oow_t nbytes;
STIX_ASSERT (STIX_OBJ_GET_FLAGS_TYPE(oop) == STIX_OBJ_TYPE_OOP);
STIX_ASSERT (STIX_OBJ_GET_FLAGS_UNIT(oop) == STIX_SIZEOF(stix_oow_t));
STIX_ASSERT (STIX_OBJ_GET_FLAGS_EXTRA(oop) == 0); /* no 'extra' for an OOP object */
nbytes = STIX_OBJ_BYTESOF(oop) + STIX_SIZEOF(stix_oow_t) + \
(stix_oow_t)((stix_oop_oop_t)oop)->slot[STIX_OBJ_GET_SIZE(oop)];
nbytes_aligned = STIX_ALIGN (nbytes, STIX_SIZEOF(stix_oop_t));
}
else
{
#endif
nbytes_aligned = STIX_ALIGN (STIX_OBJ_BYTESOF(oop), STIX_SIZEOF(stix_oop_t));
#if defined(STIX_USE_OBJECT_TRAILER)
}
#endif
STIX_OBJ_SET_CLASS (oop, stix_moveoop(stix, STIX_OBJ_GET_CLASS(oop)));
if (STIX_OBJ_GET_FLAGS_TYPE(oop) == STIX_OBJ_TYPE_OOP)
@ -182,7 +225,6 @@ static stix_uint8_t* scan_new_heap (stix_t* stix, stix_uint8_t* ptr)
if (STIX_OOP_IS_POINTER(xtmp->slot[i]))
xtmp->slot[i] = stix_moveoop (stix, xtmp->slot[i]);
}
}
/*ptr = ptr + STIX_SIZEOF(stix_obj_t) + nbytes_aligned;*/
@ -255,7 +297,6 @@ void stix_gc (stix_t* stix)
stix->active_context = (stix_oop_context_t)stix_moveoop (stix, (stix_oop_t)stix->active_context);
stix->active_method = (stix_oop_method_t)stix_moveoop (stix, (stix_oop_t)stix->active_method);
stix->active_code = (stix_oop_byte_t)stix_moveoop (stix, (stix_oop_t)stix->active_code);
for (cb = stix->cblist; cb; cb = cb->next)
{
@ -309,6 +350,7 @@ for (index = 0; index < buc->size; index++)
printf ("===========================\n");
}
*/
if (stix->active_method) SET_ACTIVE_METHOD_CODE (stix); /* update stix->active_code */
}

View File

@ -253,7 +253,7 @@ int stix_ignite (stix_t* stix)
stix->_nil = stix_allocbytes (stix, STIX_SIZEOF(stix_obj_t));
if (!stix->_nil) return -1;
stix->_nil->_flags = STIX_OBJ_MAKE_FLAGS (STIX_OBJ_TYPE_OOP, STIX_SIZEOF(stix_oop_t), 0, 1, 0);
stix->_nil->_flags = STIX_OBJ_MAKE_FLAGS (STIX_OBJ_TYPE_OOP, STIX_SIZEOF(stix_oop_t), 0, 1, 0, 0);
stix->_nil->_size = 0;
if (ignite_1(stix) <= -1 || ignite_2(stix) <= -1 || ignite_3(stix)) return -1;

View File

@ -64,7 +64,7 @@ stix_oop_t stix_allocoopobj (stix_t* stix, stix_oow_t size)
hdr = stix_allocbytes (stix, STIX_SIZEOF(stix_obj_t) + nbytes_aligned);
if (!hdr) return STIX_NULL;
hdr->_flags = STIX_OBJ_MAKE_FLAGS(STIX_OBJ_TYPE_OOP, STIX_SIZEOF(stix_oop_t), 0, 0, 0);
hdr->_flags = STIX_OBJ_MAKE_FLAGS(STIX_OBJ_TYPE_OOP, STIX_SIZEOF(stix_oop_t), 0, 0, 0, 0);
STIX_OBJ_SET_SIZE (hdr, size);
STIX_OBJ_SET_CLASS (hdr, stix->_nil);
@ -73,6 +73,42 @@ stix_oop_t stix_allocoopobj (stix_t* stix, stix_oow_t size)
return (stix_oop_t)hdr;
}
#if defined(STIX_USE_OBJECT_TRAILER)
stix_oop_t stix_allocoopobjwithtrailer (stix_t* stix, stix_oow_t size, const stix_byte_t* bptr, stix_oow_t blen)
{
stix_oop_oop_t hdr;
stix_oow_t nbytes, nbytes_aligned;
stix_oow_t i;
/* +1 for the trailer size of the stix_oow_t type */
nbytes = (size + 1) * STIX_SIZEOF(stix_oop_t) + blen;
nbytes_aligned = STIX_ALIGN(nbytes, STIX_SIZEOF(stix_oop_t));
hdr = stix_allocbytes (stix, STIX_SIZEOF(stix_obj_t) + nbytes_aligned);
if (!hdr) return STIX_NULL;
hdr->_flags = STIX_OBJ_MAKE_FLAGS(STIX_OBJ_TYPE_OOP, STIX_SIZEOF(stix_oop_t), 0, 0, 0, 1);
STIX_OBJ_SET_SIZE (hdr, size);
STIX_OBJ_SET_CLASS (hdr, stix->_nil);
for (i = 0; i < size; i++) hdr->slot[i] = stix->_nil;
/* [NOTE] this is not converted to a SmallInteger object */
hdr->slot[size] = (stix_oop_t)blen;
if (bptr)
{
STIX_MEMCPY (&hdr->slot[size + 1], bptr, blen);
}
else
{
STIX_MEMSET (&hdr->slot[size + 1], 0, blen);
}
return (stix_oop_t)hdr;
}
#endif
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 */
@ -94,7 +130,7 @@ static stix_oop_t alloc_numeric_array (stix_t* stix, const void* ptr, stix_oow_t
hdr = stix_allocbytes (stix, STIX_SIZEOF(stix_obj_t) + nbytes_aligned);
if (!hdr) return STIX_NULL;
hdr->_flags = STIX_OBJ_MAKE_FLAGS(type, unit, extra, 0, 0);
hdr->_flags = STIX_OBJ_MAKE_FLAGS(type, unit, extra, 0, 0, 0);
hdr->_size = len;
STIX_OBJ_SET_SIZE (hdr, len);
STIX_OBJ_SET_CLASS (hdr, stix->_nil);
@ -119,6 +155,14 @@ stix_oop_t stix_alloccharobj (stix_t* stix, const stix_uch_t* ptr, stix_oow_t le
return alloc_numeric_array (stix, ptr, len, STIX_OBJ_TYPE_CHAR, STIX_SIZEOF(stix_uch_t), 1);
}
/*
TODO: extra bits must be set ...
stix_oop_t stix_allocmbcharobj (stix_t* stix, const stix_uch_t* ptr, stix_oow_t len)
{
return alloc_numeric_array (stix, ptr, len, STIX_OBJ_TYPE_MBCHAR, STIX_SIZEOF(stix_uch_t), 1);
}
*/
stix_oop_t stix_allocbyteobj (stix_t* stix, const stix_byte_t* ptr, stix_oow_t len)
{
return alloc_numeric_array (stix, ptr, len, STIX_OBJ_TYPE_BYTE, STIX_SIZEOF(stix_byte_t), 0);
@ -225,3 +269,77 @@ einval:
stix->errnum = STIX_EINVAL;
return STIX_NULL;
}
#if defined(STIX_USE_OBJECT_TRAILER)
stix_oop_t stix_instantiatewithtrailer (stix_t* stix, stix_oop_t _class, stix_oow_t vlen, const stix_byte_t* tptr, stix_oow_t tlen)
{
stix_oop_t oop;
stix_oow_t spec;
stix_oow_t named_instvar;
stix_obj_type_t indexed_type;
stix_oow_t tmp_count = 0;
STIX_ASSERT (stix->_nil != STIX_NULL);
STIX_ASSERT (STIX_OOP_IS_POINTER(_class));
STIX_ASSERT (STIX_CLASSOF(stix, _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);
named_instvar = STIX_CLASS_SPEC_NAMED_INSTVAR(spec); /* size of the named_instvar part */
if (STIX_CLASS_SPEC_IS_INDEXED(spec))
{
indexed_type = STIX_CLASS_SPEC_INDEXED_TYPE(spec);
if (indexed_type == STIX_OBJ_TYPE_OOP)
{
if (named_instvar > STIX_MAX_NAMED_INSTVARS ||
vlen > STIX_MAX_INDEXED_INSTVARS(named_instvar))
{
goto einval;
}
}
else
{
/* not a class for an OOP object */
goto einval;
}
}
else
{
/* named instance variables only. treat it as if it is an
* indexable class with no variable data */
indexed_type = STIX_OBJ_TYPE_OOP;
vlen = 0;
if (named_instvar > STIX_MAX_NAMED_INSTVARS) goto einval;
}
stix_pushtmp (stix, &_class); tmp_count++;
switch (indexed_type)
{
case STIX_OBJ_TYPE_OOP:
oop = stix_allocoopobjwithtrailer(stix, named_instvar + vlen, tptr, tlen);
break;
default:
stix->errnum = STIX_EINTERN;
oop = STIX_NULL;
break;
}
if (oop) STIX_OBJ_SET_CLASS (oop, _class);
stix_poptmps (stix, tmp_count);
return oop;
einval:
STIX_ASSERT (tmp_count <= 0);
stix->errnum = STIX_EINVAL;
return STIX_NULL;
}
#endif

View File

@ -39,6 +39,11 @@
/* define this to generate CTXTEMVAR instructions */
#define STIX_USE_CTXTEMPVAR
/* define this to allow an pointer(OOP) object to have trailing bytes
* this is used to embed bytes codes into the back of a compile method
* object instead of putting in in a separate byte array. */
#define STIX_USE_OBJECT_TRAILER
/* this is for gc debugging */
#define STIX_DEBUG_GC_001
@ -469,6 +474,14 @@ struct stix_compiler_t
#endif
#if defined(STIX_USE_OBJECT_TRAILER)
/* let it point to the trailer of the method */
# define SET_ACTIVE_METHOD_CODE(stix) ((stix)->active_code = (stix_byte_t*)&(stix)->active_method->slot[STIX_OBJ_GET_SIZE((stix)->active_method) + 1 - STIX_METHOD_NAMED_INSTVARS])
#else
/* let it point to the payload of the code byte array */
# define SET_ACTIVE_METHOD_CODE(stix) ((stix)->active_code = (stix)->active_method->code->slot)
#endif
#if defined(STIX_BCODE_LONG_PARAM_SIZE) && (STIX_BCODE_LONG_PARAM_SIZE == 1)
# define MAX_CODE_INDEX (0xFFu)
# define MAX_CODE_NTMPRS (0xFFu)
@ -660,8 +673,6 @@ enum stix_bcode_t
BCODE_JUMP_IF_FALSE_2 = 0x52, /* 82 */
BCODE_JUMP_IF_FALSE_3 = 0x53, /* 83 */
BCODE_STORE_INTO_CTXTEMPVAR_0 = 0x58, /* 88 */
BCODE_STORE_INTO_CTXTEMPVAR_1 = 0x59, /* 89 */
BCODE_STORE_INTO_CTXTEMPVAR_2 = 0x5A, /* 90 */
@ -849,6 +860,15 @@ stix_oop_t stix_allocoopobj (
stix_oow_t size
);
#if defined(STIX_USE_OBJECT_TRAILER)
stix_oop_t stix_allocoopobjwithtrailer (
stix_t* stix,
stix_oow_t size,
const stix_byte_t* tptr,
stix_oow_t tlen
);
#endif
stix_oop_t stix_alloccharobj (
stix_t* stix,
const stix_uch_t* ptr,
@ -867,6 +887,16 @@ stix_oop_t stix_allocwordobj (
stix_oow_t len
);
#if defined(STIX_USE_OBJECT_TRAILER)
stix_oop_t stix_instantiatewithtrailer (
stix_t* stix,
stix_oop_t _class,
stix_oow_t vlen,
const stix_byte_t* tptr,
stix_oow_t tlen
);
#endif
/* ========================================================================= */
/* sym.c */
/* ========================================================================= */

View File

@ -405,11 +405,15 @@ typedef enum stix_obj_type_t stix_obj_type_t;
* STIX_OBJ_TYPE_BYTE, STIX_OBJ_TYPE_WORD
* unit: the size of a payload item in bytes.
* 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.
* item than the value of the size field. used for a
* terminating null in a variable-char object. internel
* use only.
* kernel: 0 or 1. indicates that the object is a kernel object.
* VM disallows layout changes of a kernel object.
* moved: 0 or 1. used by GC.
* internal use only.
* moved: 0 or 1. used by GC. internal use only.
* trailer: 0 or 1. indicates that there are trailing bytes
* after the object payload. internal use only.
*
* _size: the number of payload items in an object.
* it doesn't include the header size.
@ -418,6 +422,10 @@ typedef enum stix_obj_type_t stix_obj_type_t;
* with this fomula:
* sizeof(stix_obj_t) + ALIGN((size + extra) * unit), sizeof(stix_oop_t))
*
* If the type is known to be not STIX_OBJ_TYPE_CHAR, you can assume that
* 'extra' is 0. So you can simplify the fomula in such a context.
* sizeof(stix_obj_t) + ALIGN(size * 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.
@ -437,18 +445,21 @@ typedef enum stix_obj_type_t stix_obj_type_t;
#define STIX_OBJ_FLAGS_EXTRA_BITS 1
#define STIX_OBJ_FLAGS_KERNEL_BITS 2
#define STIX_OBJ_FLAGS_MOVED_BITS 1
#define STIX_OBJ_FLAGS_TRAILER_BITS 1
#define STIX_OBJ_GET_FLAGS_TYPE(oop) STIX_GETBITS(stix_oow_t, (oop)->_flags, (STIX_OBJ_FLAGS_UNIT_BITS + STIX_OBJ_FLAGS_EXTRA_BITS + STIX_OBJ_FLAGS_KERNEL_BITS + STIX_OBJ_FLAGS_MOVED_BITS), STIX_OBJ_FLAGS_TYPE_BITS)
#define STIX_OBJ_GET_FLAGS_UNIT(oop) STIX_GETBITS(stix_oow_t, (oop)->_flags, (STIX_OBJ_FLAGS_EXTRA_BITS + STIX_OBJ_FLAGS_KERNEL_BITS + STIX_OBJ_FLAGS_MOVED_BITS), STIX_OBJ_FLAGS_UNIT_BITS)
#define STIX_OBJ_GET_FLAGS_EXTRA(oop) STIX_GETBITS(stix_oow_t, (oop)->_flags, (STIX_OBJ_FLAGS_KERNEL_BITS + STIX_OBJ_FLAGS_MOVED_BITS), STIX_OBJ_FLAGS_EXTRA_BITS)
#define STIX_OBJ_GET_FLAGS_KERNEL(oop) STIX_GETBITS(stix_oow_t, (oop)->_flags, (STIX_OBJ_FLAGS_MOVED_BITS), STIX_OBJ_FLAGS_KERNEL_BITS)
#define STIX_OBJ_GET_FLAGS_MOVED(oop) STIX_GETBITS(stix_oow_t, (oop)->_flags, 0, STIX_OBJ_FLAGS_MOVED_BITS)
#define STIX_OBJ_GET_FLAGS_TYPE(oop) STIX_GETBITS(stix_oow_t, (oop)->_flags, (STIX_OBJ_FLAGS_UNIT_BITS + STIX_OBJ_FLAGS_EXTRA_BITS + STIX_OBJ_FLAGS_KERNEL_BITS + STIX_OBJ_FLAGS_MOVED_BITS + STIX_OBJ_FLAGS_TRAILER_BITS), STIX_OBJ_FLAGS_TYPE_BITS)
#define STIX_OBJ_GET_FLAGS_UNIT(oop) STIX_GETBITS(stix_oow_t, (oop)->_flags, (STIX_OBJ_FLAGS_EXTRA_BITS + STIX_OBJ_FLAGS_KERNEL_BITS + STIX_OBJ_FLAGS_MOVED_BITS + STIX_OBJ_FLAGS_TRAILER_BITS), STIX_OBJ_FLAGS_UNIT_BITS)
#define STIX_OBJ_GET_FLAGS_EXTRA(oop) STIX_GETBITS(stix_oow_t, (oop)->_flags, (STIX_OBJ_FLAGS_KERNEL_BITS + STIX_OBJ_FLAGS_MOVED_BITS + STIX_OBJ_FLAGS_TRAILER_BITS), STIX_OBJ_FLAGS_EXTRA_BITS)
#define STIX_OBJ_GET_FLAGS_KERNEL(oop) STIX_GETBITS(stix_oow_t, (oop)->_flags, (STIX_OBJ_FLAGS_MOVED_BITS + STIX_OBJ_FLAGS_TRAILER_BITS), STIX_OBJ_FLAGS_KERNEL_BITS)
#define STIX_OBJ_GET_FLAGS_MOVED(oop) STIX_GETBITS(stix_oow_t, (oop)->_flags, (STIX_OBJ_FLAGS_TRAILER_BITS), STIX_OBJ_FLAGS_MOVED_BITS)
#define STIX_OBJ_GET_FLAGS_TRAILER(oop) STIX_GETBITS(stix_oow_t, (oop)->_flags, 0, STIX_OBJ_FLAGS_TRAILER_BITS)
#define STIX_OBJ_SET_FLAGS_TYPE(oop,v) STIX_SETBITS(stix_oow_t, (oop)->_flags, (STIX_OBJ_FLAGS_UNIT_BITS + STIX_OBJ_FLAGS_EXTRA_BITS + STIX_OBJ_FLAGS_KERNEL_BITS + STIX_OBJ_FLAGS_MOVED_BITS), STIX_OBJ_FLAGS_TYPE_BITS, v)
#define STIX_OBJ_SET_FLAGS_UNIT(oop,v) STIX_SETBITS(stix_oow_t, (oop)->_flags, (STIX_OBJ_FLAGS_EXTRA_BITS + STIX_OBJ_FLAGS_KERNEL_BITS + STIX_OBJ_FLAGS_MOVED_BITS), STIX_OBJ_FLAGS_UNIT_BITS, v)
#define STIX_OBJ_SET_FLAGS_EXTRA(oop,v) STIX_SETBITS(stix_oow_t, (oop)->_flags, (STIX_OBJ_FLAGS_KERNEL_BITS + STIX_OBJ_FLAGS_MOVED_BITS), STIX_OBJ_FLAGS_EXTRA_BITS, v)
#define STIX_OBJ_SET_FLAGS_KERNEL(oop,v) STIX_SETBITS(stix_oow_t, (oop)->_flags, (STIX_OBJ_FLAGS_MOVED_BITS), STIX_OBJ_FLAGS_KERNEL_BITS, v)
#define STIX_OBJ_SET_FLAGS_MOVED(oop,v) STIX_SETBITS(stix_oow_t, (oop)->_flags, 0, STIX_OBJ_FLAGS_MOVED_BITS, v)
#define STIX_OBJ_SET_FLAGS_TYPE(oop,v) STIX_SETBITS(stix_oow_t, (oop)->_flags, (STIX_OBJ_FLAGS_UNIT_BITS + STIX_OBJ_FLAGS_EXTRA_BITS + STIX_OBJ_FLAGS_KERNEL_BITS + STIX_OBJ_FLAGS_MOVED_BITS + STIX_OBJ_FLAGS_TRAILER_BITS), STIX_OBJ_FLAGS_TYPE_BITS, v)
#define STIX_OBJ_SET_FLAGS_UNIT(oop,v) STIX_SETBITS(stix_oow_t, (oop)->_flags, (STIX_OBJ_FLAGS_EXTRA_BITS + STIX_OBJ_FLAGS_KERNEL_BITS + STIX_OBJ_FLAGS_MOVED_BITS + STIX_OBJ_FLAGS_TRAILER_BITS), STIX_OBJ_FLAGS_UNIT_BITS, v)
#define STIX_OBJ_SET_FLAGS_EXTRA(oop,v) STIX_SETBITS(stix_oow_t, (oop)->_flags, (STIX_OBJ_FLAGS_KERNEL_BITS + STIX_OBJ_FLAGS_MOVED_BITS + STIX_OBJ_FLAGS_TRAILER_BITS), STIX_OBJ_FLAGS_EXTRA_BITS, v)
#define STIX_OBJ_SET_FLAGS_KERNEL(oop,v) STIX_SETBITS(stix_oow_t, (oop)->_flags, (STIX_OBJ_FLAGS_MOVED_BITS + STIX_OBJ_FLAGS_TRAILER_BITS), STIX_OBJ_FLAGS_KERNEL_BITS, v)
#define STIX_OBJ_SET_FLAGS_MOVED(oop,v) STIX_SETBITS(stix_oow_t, (oop)->_flags, (STIX_OBJ_FLAGS_TRAILER_BITS), STIX_OBJ_FLAGS_MOVED_BITS, v)
#define STIX_OBJ_SET_FLAGS_TRAILER(oop,v) STIX_SETBITS(stix_oow_t, (oop)->_flags, 0, STIX_OBJ_FLAGS_TRAILER_BITS, v)
#define STIX_OBJ_GET_SIZE(oop) ((oop)->_size)
#define STIX_OBJ_GET_CLASS(oop) ((oop)->_class)
@ -456,17 +467,19 @@ typedef enum stix_obj_type_t stix_obj_type_t;
#define STIX_OBJ_SET_SIZE(oop,v) ((oop)->_size = (v))
#define STIX_OBJ_SET_CLASS(oop,c) ((oop)->_class = (c))
/* [NOTE] this macro doesn't include the size of the trailer */
#define STIX_OBJ_BYTESOF(oop) ((STIX_OBJ_GET_SIZE(oop) + STIX_OBJ_GET_FLAGS_EXTRA(oop)) * STIX_OBJ_GET_FLAGS_UNIT(oop))
/* this macro doesn't check the range of the actual value.
* make sure that the value of each bit fields given fall within the number
* of defined bits */
#define STIX_OBJ_MAKE_FLAGS(t,u,e,k,m) ( \
(((stix_oow_t)(t)) << (STIX_OBJ_FLAGS_UNIT_BITS + STIX_OBJ_FLAGS_EXTRA_BITS + STIX_OBJ_FLAGS_KERNEL_BITS + STIX_OBJ_FLAGS_MOVED_BITS)) | \
(((stix_oow_t)(u)) << (STIX_OBJ_FLAGS_EXTRA_BITS + STIX_OBJ_FLAGS_KERNEL_BITS + STIX_OBJ_FLAGS_MOVED_BITS)) | \
(((stix_oow_t)(e)) << (STIX_OBJ_FLAGS_KERNEL_BITS + STIX_OBJ_FLAGS_MOVED_BITS)) | \
(((stix_oow_t)(k)) << (STIX_OBJ_FLAGS_MOVED_BITS)) | \
(((stix_oow_t)(m)) << 0) \
/* [NOTE] this macro doesn't check the range of the actual value.
* make sure that the value of each bit fields given falls within the
* possible range of the defined bits */
#define STIX_OBJ_MAKE_FLAGS(t,u,e,k,m,r) ( \
(((stix_oow_t)(t)) << (STIX_OBJ_FLAGS_UNIT_BITS + STIX_OBJ_FLAGS_EXTRA_BITS + STIX_OBJ_FLAGS_KERNEL_BITS + STIX_OBJ_FLAGS_MOVED_BITS + STIX_OBJ_FLAGS_TRAILER_BITS)) | \
(((stix_oow_t)(u)) << (STIX_OBJ_FLAGS_EXTRA_BITS + STIX_OBJ_FLAGS_KERNEL_BITS + STIX_OBJ_FLAGS_MOVED_BITS + STIX_OBJ_FLAGS_TRAILER_BITS)) | \
(((stix_oow_t)(e)) << (STIX_OBJ_FLAGS_KERNEL_BITS + STIX_OBJ_FLAGS_MOVED_BITS + STIX_OBJ_FLAGS_TRAILER_BITS)) | \
(((stix_oow_t)(k)) << (STIX_OBJ_FLAGS_MOVED_BITS + STIX_OBJ_FLAGS_TRAILER_BITS)) | \
(((stix_oow_t)(m)) << (STIX_OBJ_FLAGS_TRAILER_BITS)) | \
(((stix_oow_t)(r)) << 0) \
)
#define STIX_OBJ_HEADER \
@ -503,6 +516,13 @@ struct stix_obj_word_t
stix_oow_t slot[1];
};
typedef struct stix_trailer_t stix_trailer_t;
struct stix_trailer_t
{
stix_oow_t size;
stix_byte_t slot[1];
};
#define STIX_SET_NAMED_INSTVARS 2
typedef struct stix_set_t stix_set_t;
typedef struct stix_set_t* stix_oop_set_t;
@ -554,7 +574,11 @@ struct stix_association_t
stix_oop_t value;
};
#define STIX_METHOD_NAMED_INSTVARS 6
#if defined(STIX_USE_OBJECT_TRAILER)
# define STIX_METHOD_NAMED_INSTVARS 5
#else
# define STIX_METHOD_NAMED_INSTVARS 6
#endif
typedef struct stix_method_t stix_method_t;
typedef struct stix_method_t* stix_oop_method_t;
struct stix_method_t
@ -572,7 +596,12 @@ struct stix_method_t
/* number of arguments in temporaries */
stix_oop_t tmpr_nargs; /* SmallInteger */
#if defined(STIX_USE_OBJECT_TRAILER)
/* no code field is used */
#else
stix_oop_byte_t code; /* ByteArray */
#endif
stix_oop_t source; /* TODO: what should I put? */
/* == variable indexed part == */
@ -753,7 +782,7 @@ struct stix_t
/* == EXECUTION REGISTERS == */
stix_oop_context_t active_context;
stix_oop_method_t active_method;
stix_oop_byte_t active_code;
stix_byte_t* active_code;
stix_ooi_t sp;
stix_ooi_t ip;
/* == END EXECUTION REGISTERS == */