3895 lines
107 KiB
C
3895 lines
107 KiB
C
/*
|
|
* $Id$
|
|
*
|
|
Copyright (c) 2014-2016 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 WAfRRANTIES
|
|
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"
|
|
|
|
/* TODO: remove this header after having changed clock_gettime() to a
|
|
* platform independent function */
|
|
#include <time.h>
|
|
|
|
#define PROC_STATE_RUNNING 3
|
|
#define PROC_STATE_WAITING 2
|
|
#define PROC_STATE_RUNNABLE 1
|
|
#define PROC_STATE_SUSPENDED 0
|
|
#define PROC_STATE_TERMINATED -1
|
|
|
|
#define SEM_LIST_INC 256
|
|
#define SEM_HEAP_INC 256
|
|
#define SEM_LIST_MAX (SEM_LIST_INC * 1000)
|
|
#define SEM_HEAP_MAX (SEM_HEAP_INC * 1000)
|
|
|
|
#define SEM_HEAP_PARENT(x) (((x) - 1) / 2)
|
|
#define SEM_HEAP_LEFT(x) ((x) * 2 + 1)
|
|
#define SEM_HEAP_RIGHT(x) ((x) * 2 + 2)
|
|
|
|
#define SEM_HEAP_EARLIER_THAN(stx,x,y) ( \
|
|
(STIX_OOP_TO_SMOOI((x)->heap_ftime_sec) < STIX_OOP_TO_SMOOI((y)->heap_ftime_sec)) || \
|
|
(STIX_OOP_TO_SMOOI((x)->heap_ftime_sec) == STIX_OOP_TO_SMOOI((y)->heap_ftime_sec) && STIX_OOP_TO_SMOOI((x)->heap_ftime_nsec) < STIX_OOP_TO_SMOOI((y)->heap_ftime_nsec)) \
|
|
)
|
|
|
|
#if defined(USE_DYNCALL)
|
|
/* TODO: defined dcAllocMem and dcFreeMeme before builing the dynload and dyncall library */
|
|
# include <dyncall.h> /* TODO: remove this. make dyXXXX calls to callbacks */
|
|
#endif
|
|
|
|
/* TODO: context's stack overflow check in various part of this file */
|
|
/* TOOD: determine the right stack size */
|
|
#if defined(STIX_USE_PROCSTK)
|
|
# define CONTEXT_STACK_SIZE 0
|
|
#else
|
|
# define CONTEXT_STACK_SIZE 96
|
|
#endif
|
|
|
|
#define LOAD_IP(stix, v_ctx) ((stix)->ip = STIX_OOP_TO_SMOOI((v_ctx)->ip))
|
|
#define STORE_IP(stix, v_ctx) ((v_ctx)->ip = STIX_SMOOI_TO_OOP((stix)->ip))
|
|
|
|
#define LOAD_SP(stix, v_ctx) ((stix)->sp = STIX_OOP_TO_SMOOI((v_ctx)->sp))
|
|
#define STORE_SP(stix, v_ctx) ((v_ctx)->sp = STIX_SMOOI_TO_OOP((stix)->sp))
|
|
|
|
#define LOAD_ACTIVE_IP(stix) LOAD_IP(stix, (stix)->active_context)
|
|
#define STORE_ACTIVE_IP(stix) STORE_IP(stix, (stix)->active_context)
|
|
|
|
#if defined(STIX_USE_PROCSTK)
|
|
#define LOAD_ACTIVE_SP(stix) LOAD_SP(stix, (stix)->processor->active)
|
|
#define STORE_ACTIVE_SP(stix) STORE_SP(stix, (stix)->processor->active)
|
|
|
|
#define ACTIVE_STACK_PUSH(stix,v) \
|
|
do { \
|
|
(stix)->sp = (stix)->sp + 1; \
|
|
(stix)->processor->active->slot[(stix)->sp] = v; \
|
|
} while (0)
|
|
|
|
#define ACTIVE_STACK_GET(stix,v_sp) ((stix)->processor->active->slot[v_sp])
|
|
#define ACTIVE_STACK_SET(stix,v_sp,v_obj) ((stix)->processor->active->slot[v_sp] = v_obj)
|
|
|
|
#else
|
|
#define LOAD_ACTIVE_SP(stix) LOAD_SP(stix, (stix)->active_context)
|
|
#define STORE_ACTIVE_SP(stix) STORE_SP(stix, (stix)->active_context)
|
|
|
|
#define ACTIVE_STACK_PUSH(stix,v) \
|
|
do { \
|
|
(stix)->sp = (stix)->sp + 1; \
|
|
(stix)->active_context->slot[(stix)->sp] = v; \
|
|
} while (0)
|
|
|
|
#define ACTIVE_STACK_GET(stix,v_sp) ((stix)->active_context->slot[v_sp])
|
|
#define ACTIVE_STACK_SET(stix,v_sp,v_obj) ((stix)->active_context->slot[v_sp] = v_obj)
|
|
#endif
|
|
|
|
#define ACTIVE_STACK_GETTOP(stix) ACTIVE_STACK_GET(stix, (stix)->sp)
|
|
#define ACTIVE_STACK_SETTOP(stix,v_obj) ACTIVE_STACK_SET(stix, (stix)->sp, v_obj)
|
|
|
|
#define ACTIVE_STACK_POP(stix) ((stix)->sp = (stix)->sp - 1)
|
|
#define ACTIVE_STACK_UNPOP(stix) ((stix)->sp = (stix)->sp + 1)
|
|
#define ACTIVE_STACK_POPS(stix,count) ((stix)->sp = (stix)->sp - (count))
|
|
#define ACTIVE_STACK_ISEMPTY(stix) ((stix)->sp <= -1)
|
|
|
|
#if defined(STIX_USE_PROCSTK)
|
|
#define SWITCH_ACTIVE_CONTEXT(stix,v_ctx) \
|
|
do \
|
|
{ \
|
|
STORE_ACTIVE_IP (stix); \
|
|
(stix)->active_context = (v_ctx); \
|
|
(stix)->active_method = (stix_oop_method_t)(stix)->active_context->origin->method_or_nargs; \
|
|
SET_ACTIVE_METHOD_CODE(stix); \
|
|
LOAD_ACTIVE_IP (stix); \
|
|
} while (0)
|
|
#else
|
|
#define SWITCH_ACTIVE_CONTEXT(stix,v_ctx) \
|
|
do \
|
|
{ \
|
|
STORE_ACTIVE_IP (stix); \
|
|
STORE_ACTIVE_SP (stix); \
|
|
(stix)->active_context = (v_ctx); \
|
|
(stix)->active_method = (stix_oop_method_t)(stix)->active_context->origin->method_or_nargs; \
|
|
SET_ACTIVE_METHOD_CODE(stix); \
|
|
LOAD_ACTIVE_IP (stix); \
|
|
LOAD_ACTIVE_SP (stix); \
|
|
} while (0)
|
|
#endif
|
|
|
|
#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
|
|
|
|
|
|
#if defined(STIX_DEBUG_EXEC_001)
|
|
# define DBGOUT_EXEC_0(fmt) printf(fmt "\n")
|
|
# define DBGOUT_EXEC_1(fmt,a1) printf(fmt "\n",a1)
|
|
# define DBGOUT_EXEC_2(fmt,a1,a2) printf(fmt "\n", a1, a2)
|
|
# define DBGOUT_EXEC_3(fmt,a1,a2,a3) printf(fmt "\n", a1, a2, a3)
|
|
#else
|
|
# define DBGOUT_EXEC_0(fmt)
|
|
# define DBGOUT_EXEC_1(fmt,a1)
|
|
# define DBGOUT_EXEC_2(fmt,a1,a2)
|
|
# define DBGOUT_EXEC_3(fmt,a1,a2,a3)
|
|
#endif
|
|
|
|
|
|
static stix_oop_process_t make_process (stix_t* stix, stix_oop_context_t c)
|
|
{
|
|
stix_oop_process_t proc;
|
|
|
|
stix_pushtmp (stix, (stix_oop_t*)&c);
|
|
proc = (stix_oop_process_t)stix_instantiate (stix, stix->_process, STIX_NULL, stix->option.dfl_procstk_size);
|
|
stix_poptmp (stix);
|
|
if (!proc) return STIX_NULL;
|
|
|
|
proc->state = STIX_SMOOI_TO_OOP(PROC_STATE_SUSPENDED);
|
|
proc->initial_context = c;
|
|
proc->current_context = c;
|
|
proc->sp = STIX_SMOOI_TO_OOP(-1);
|
|
|
|
#if defined(STIX_DEBUG_PROCESSOR)
|
|
printf ("PROCESS %p SIZE => %ld\n", proc, (long int)STIX_OBJ_GET_SIZE(proc));
|
|
#endif
|
|
return proc;
|
|
}
|
|
|
|
static STIX_INLINE void sleep_active_process (stix_t* stix, int state)
|
|
{
|
|
#if defined(STIX_DEBUG_PROCESSOR)
|
|
printf ("PROCESS-SWITCHING: PUT ACTIVE_CONTEXT TO SLEEP..%d %p\n", (int)stix->ip, stix->active_context);
|
|
#endif
|
|
|
|
#if defined(STIX_USE_PROCSTK)
|
|
STORE_ACTIVE_SP(stix);
|
|
#else
|
|
/* nothing special */
|
|
#endif
|
|
|
|
/* store the current active context to the current process.
|
|
* it is the suspended context of the process to be suspended */
|
|
STIX_ASSERT (stix->processor->active != stix->nil_process);
|
|
stix->processor->active->current_context = stix->active_context;
|
|
stix->processor->active->state = STIX_SMOOI_TO_OOP(state);
|
|
}
|
|
|
|
static STIX_INLINE void wake_new_process (stix_t* stix, stix_oop_process_t proc)
|
|
{
|
|
/* activate the given process */
|
|
proc->state = STIX_SMOOI_TO_OOP(PROC_STATE_RUNNING);
|
|
stix->processor->active = proc;
|
|
|
|
#if defined(STIX_USE_PROCSTK)
|
|
LOAD_ACTIVE_SP(stix);
|
|
#else
|
|
/* nothing special */
|
|
#endif
|
|
|
|
/* activate the suspended context of the new process */
|
|
SWITCH_ACTIVE_CONTEXT (stix, proc->current_context);
|
|
|
|
#if defined(STIX_DEBUG_PROCESSOR)
|
|
printf ("PROCESS-SWITCHING: WAKE NEW PROCESS...%d %p\n", (int)stix->ip, stix->active_context);
|
|
#endif
|
|
}
|
|
|
|
static void switch_to_process (stix_t* stix, stix_oop_process_t proc, int new_state_for_old_active)
|
|
{
|
|
/* the new process must not be the currently active process */
|
|
STIX_ASSERT (stix->processor->active != proc);
|
|
|
|
/* the new process must be in the runnable state */
|
|
STIX_ASSERT (proc->state == STIX_SMOOI_TO_OOP(PROC_STATE_RUNNABLE) ||
|
|
proc->state == STIX_SMOOI_TO_OOP(PROC_STATE_WAITING));
|
|
|
|
sleep_active_process (stix, new_state_for_old_active);
|
|
wake_new_process (stix, proc);
|
|
|
|
stix->proc_switched = 1;
|
|
}
|
|
|
|
static STIX_INLINE stix_oop_process_t find_next_runnable_process (stix_t* stix)
|
|
{
|
|
stix_oop_process_t npr;
|
|
STIX_ASSERT (stix->processor->active->state == STIX_SMOOI_TO_OOP(PROC_STATE_RUNNING));
|
|
npr = stix->processor->active->next;
|
|
if ((stix_oop_t)npr == stix->_nil) npr = stix->processor->runnable_head;
|
|
return npr;
|
|
}
|
|
|
|
static STIX_INLINE void switch_to_next_runnable_process (stix_t* stix)
|
|
{
|
|
stix_oop_process_t nrp;
|
|
|
|
nrp = find_next_runnable_process (stix);
|
|
if (nrp != stix->processor->active) switch_to_process (stix, nrp, PROC_STATE_RUNNABLE);
|
|
}
|
|
|
|
static STIX_INLINE int chain_into_processor (stix_t* stix, stix_oop_process_t proc)
|
|
{
|
|
/* the process is not scheduled at all.
|
|
* link it to the processor's process list. */
|
|
stix_ooi_t tally;
|
|
|
|
STIX_ASSERT ((stix_oop_t)proc->prev == stix->_nil);
|
|
STIX_ASSERT ((stix_oop_t)proc->next == stix->_nil);
|
|
|
|
STIX_ASSERT (proc->state == STIX_SMOOI_TO_OOP(PROC_STATE_SUSPENDED));
|
|
|
|
tally = STIX_OOP_TO_SMOOI(stix->processor->tally);
|
|
|
|
STIX_ASSERT (tally >= 0);
|
|
if (tally >= STIX_SMOOI_MAX)
|
|
{
|
|
#if defined(STIX_DEBUG_PROCESSOR)
|
|
printf ("TOO MANY PROCESS\n");
|
|
#endif
|
|
stix->errnum = STIX_EPFULL;
|
|
return -1;
|
|
}
|
|
|
|
/* append to the runnable list */
|
|
if (tally > 0)
|
|
{
|
|
proc->prev = stix->processor->runnable_tail;
|
|
stix->processor->runnable_tail->next = proc;
|
|
}
|
|
else
|
|
{
|
|
stix->processor->runnable_head = proc;
|
|
}
|
|
stix->processor->runnable_tail = proc;
|
|
|
|
tally++;
|
|
stix->processor->tally = STIX_SMOOI_TO_OOP(tally);
|
|
#if defined(STIX_DEBUG_PROCESSOR)
|
|
printf ("INSERTED PROCESS %d TO PROCESSOR\n", (int)tally);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static STIX_INLINE void unchain_from_processor (stix_t* stix, stix_oop_process_t proc, int state)
|
|
{
|
|
stix_ooi_t tally;
|
|
|
|
STIX_ASSERT (proc->state == STIX_SMOOI_TO_OOP(PROC_STATE_RUNNING) ||
|
|
proc->state == STIX_SMOOI_TO_OOP(PROC_STATE_RUNNABLE));
|
|
|
|
tally = STIX_OOP_TO_SMOOI(stix->processor->tally);
|
|
STIX_ASSERT (tally > 0);
|
|
|
|
if ((stix_oop_t)proc->prev != stix->_nil) proc->prev->next = proc->next;
|
|
else stix->processor->runnable_head = proc->next;
|
|
if ((stix_oop_t)proc->next != stix->_nil) proc->next->prev = proc->prev;
|
|
else stix->processor->runnable_tail = proc->prev;
|
|
|
|
proc->prev = (stix_oop_process_t)stix->_nil;
|
|
proc->next = (stix_oop_process_t)stix->_nil;
|
|
proc->state = STIX_SMOOI_TO_OOP(state);
|
|
|
|
tally--;
|
|
if (tally == 0) stix->processor->active = stix->nil_process;
|
|
stix->processor->tally = STIX_SMOOI_TO_OOP(tally);
|
|
}
|
|
|
|
static STIX_INLINE void chain_into_semaphore (stix_t* stix, stix_oop_process_t proc, stix_oop_semaphore_t sem)
|
|
{
|
|
/* append a process to the process list of a semaphore*/
|
|
|
|
STIX_ASSERT ((stix_oop_t)proc->sem == stix->_nil);
|
|
STIX_ASSERT ((stix_oop_t)proc->prev == stix->_nil);
|
|
STIX_ASSERT ((stix_oop_t)proc->next == stix->_nil);
|
|
|
|
if ((stix_oop_t)sem->waiting_head == stix->_nil)
|
|
{
|
|
STIX_ASSERT ((stix_oop_t)sem->waiting_tail == stix->_nil);
|
|
sem->waiting_head = proc;
|
|
}
|
|
else
|
|
{
|
|
proc->prev = sem->waiting_tail;
|
|
sem->waiting_tail->next = proc;
|
|
}
|
|
sem->waiting_tail = proc;
|
|
|
|
proc->sem = sem;
|
|
}
|
|
|
|
static STIX_INLINE void unchain_from_semaphore (stix_t* stix, stix_oop_process_t proc)
|
|
{
|
|
stix_oop_semaphore_t sem;
|
|
|
|
STIX_ASSERT ((stix_oop_t)proc->sem != stix->_nil);
|
|
|
|
sem = proc->sem;
|
|
if ((stix_oop_t)proc->prev != stix->_nil) proc->prev->next = proc->next;
|
|
else sem->waiting_head = proc->next;
|
|
if ((stix_oop_t)proc->next != stix->_nil) proc->next->prev = proc->prev;
|
|
else sem->waiting_tail = proc->prev;
|
|
|
|
proc->prev = (stix_oop_process_t)stix->_nil;
|
|
proc->next = (stix_oop_process_t)stix->_nil;
|
|
|
|
proc->sem = (stix_oop_semaphore_t)stix->_nil;
|
|
}
|
|
|
|
static void terminate_process (stix_t* stix, stix_oop_process_t proc)
|
|
{
|
|
if (proc->state == STIX_SMOOI_TO_OOP(PROC_STATE_RUNNING) ||
|
|
proc->state == STIX_SMOOI_TO_OOP(PROC_STATE_RUNNABLE))
|
|
{
|
|
/* RUNNING/RUNNABLE ---> TERMINATED */
|
|
if (proc == stix->processor->active)
|
|
{
|
|
stix_oop_process_t nrp;
|
|
|
|
nrp = find_next_runnable_process (stix);
|
|
|
|
unchain_from_processor (stix, proc, PROC_STATE_TERMINATED);
|
|
proc->sp = STIX_SMOOI_TO_OOP(-1); /* invalidate the process stack */
|
|
proc->current_context = proc->initial_context; /* not needed but just in case */
|
|
|
|
/* a runnable or running process must not be chanined to the
|
|
* process list of a semaphore */
|
|
STIX_ASSERT ((stix_oop_t)proc->sem == stix->_nil);
|
|
|
|
if (nrp == proc)
|
|
{
|
|
/* no runnable process after termination */
|
|
STIX_ASSERT (stix->processor->active == stix->nil_process);
|
|
}
|
|
else
|
|
{
|
|
switch_to_process (stix, nrp, PROC_STATE_TERMINATED);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unchain_from_processor (stix, proc, PROC_STATE_TERMINATED);
|
|
proc->sp = STIX_SMOOI_TO_OOP(-1); /* invalidate the process stack */
|
|
}
|
|
}
|
|
else if (proc->state == STIX_SMOOI_TO_OOP(PROC_STATE_SUSPENDED))
|
|
{
|
|
/* SUSPENDED ---> TERMINATED */
|
|
proc->state = STIX_SMOOI_TO_OOP(PROC_STATE_TERMINATED);
|
|
proc->sp = STIX_SMOOI_TO_OOP(-1); /* invalidate the proce stack */
|
|
|
|
if ((stix_oop_t)proc->sem != stix->_nil)
|
|
{
|
|
unchain_from_semaphore (stix, proc);
|
|
}
|
|
}
|
|
else if (proc->state == STIX_SMOOI_TO_OOP(PROC_STATE_WAITING))
|
|
{
|
|
/* WAITING ---> TERMINATED */
|
|
/* TODO: */
|
|
}
|
|
}
|
|
|
|
static void resume_process (stix_t* stix, stix_oop_process_t proc)
|
|
{
|
|
printf ("TO RESUME PROCESS = %p %d\n", proc, (int)STIX_OOP_TO_SMOOI(proc->state));
|
|
if (proc->state == STIX_SMOOI_TO_OOP(PROC_STATE_SUSPENDED))
|
|
{
|
|
/* SUSPENED ---> RUNNING */
|
|
|
|
printf ("TO RESUME PROCESS = %p %d SUSPENED ----> RUNNING\n", proc, (int)STIX_OOP_TO_SMOOI(proc->state));
|
|
STIX_ASSERT ((stix_oop_t)proc->prev == stix->_nil);
|
|
STIX_ASSERT ((stix_oop_t)proc->next == stix->_nil);
|
|
|
|
chain_into_processor (stix, proc); /* TODO: error check */
|
|
|
|
/*proc->current_context = proc->initial_context;*/
|
|
proc->state = STIX_SMOOI_TO_OOP(PROC_STATE_RUNNABLE);
|
|
|
|
/*switch_to_process (stix, proc);*/
|
|
}
|
|
#if 0
|
|
else if (proc->state == STIX_SMOOI_TO_OOP(PROC_STATE_RUNNABLE))
|
|
{
|
|
/* RUNNABLE ---> RUNNING */
|
|
/* TODO: should i allow this? */
|
|
STIX_ASSERT (stix->processor->active != proc);
|
|
switch_to_process (stix, proc, PROC_STATE_RUNNABLE);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void suspend_process (stix_t* stix, stix_oop_process_t proc)
|
|
{
|
|
if (proc->state == STIX_SMOOI_TO_OOP(PROC_STATE_RUNNING) ||
|
|
proc->state == STIX_SMOOI_TO_OOP(PROC_STATE_RUNNABLE))
|
|
{
|
|
/* RUNNING/RUNNABLE ---> SUSPENDED */
|
|
|
|
if (proc == stix->processor->active)
|
|
{
|
|
stix_oop_process_t nrp;
|
|
|
|
nrp = find_next_runnable_process (stix);
|
|
|
|
printf ("TO SUSPEND...%p %d\n", proc, (int)STIX_OOP_TO_SMOOI(proc->state));
|
|
if (nrp == proc)
|
|
{
|
|
/* no runnable process after suspension */
|
|
printf ("NO RUNNABLE PROCESS AFTER SUPSENDISION\n");
|
|
sleep_active_process (stix, PROC_STATE_RUNNABLE);
|
|
unchain_from_processor (stix, proc, PROC_STATE_SUSPENDED);
|
|
|
|
/* the last has been unchained from the processor and
|
|
* set to SUSPENDED. the active process must be the nil
|
|
* nil process */
|
|
STIX_ASSERT (stix->processor->active == stix->nil_process);
|
|
}
|
|
else
|
|
{
|
|
printf ("SWITCHING TO XXXXXXXXXXXXXXXXXXXXx\n");
|
|
/* keep the unchained process at the runnable state for
|
|
* the immediate call to switch_to_process() below */
|
|
unchain_from_processor (stix, proc, PROC_STATE_RUNNABLE);
|
|
/* unchain_from_processor() leaves the active process
|
|
* untouched unless the unchained process is the last
|
|
* process. so calling switch_to_process() which expects
|
|
* the active process to be valid is safe */
|
|
STIX_ASSERT (stix->processor->active != stix->nil_process);
|
|
switch_to_process (stix, nrp, PROC_STATE_SUSPENDED);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unchain_from_processor (stix, proc, PROC_STATE_SUSPENDED);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void yield_process (stix_t* stix, stix_oop_process_t proc)
|
|
{
|
|
if (proc->state == STIX_SMOOI_TO_OOP(PROC_STATE_RUNNING))
|
|
{
|
|
/* RUNNING --> RUNNABLE */
|
|
|
|
stix_oop_process_t nrp;
|
|
|
|
STIX_ASSERT (proc == stix->processor->active);
|
|
|
|
nrp = find_next_runnable_process (stix);
|
|
/* if there are more than 1 runnable processes, the next
|
|
* runnable process must be different from proc */
|
|
if (nrp != proc)
|
|
{
|
|
switch_to_process (stix, nrp, PROC_STATE_RUNNABLE);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int async_signal_semaphore (stix_t* stix, stix_oop_semaphore_t sem)
|
|
{
|
|
if (stix->sem_list_count >= SEM_LIST_MAX)
|
|
{
|
|
stix->errnum = STIX_ESLFULL;
|
|
return -1;
|
|
}
|
|
|
|
if (stix->sem_list_count >= stix->sem_list_capa)
|
|
{
|
|
stix_oow_t new_capa;
|
|
stix_oop_semaphore_t* tmp;
|
|
|
|
new_capa = stix->sem_list_capa + SEM_LIST_INC; /* TODO: overflow check.. */
|
|
tmp = stix_reallocmem (stix, stix->sem_list, STIX_SIZEOF(stix_oop_semaphore_t) * new_capa);
|
|
if (!tmp) return -1;
|
|
|
|
stix->sem_list = tmp;
|
|
stix->sem_list_capa = new_capa;
|
|
}
|
|
|
|
stix->sem_list[stix->sem_list_count] = sem;
|
|
stix->sem_list_count++;
|
|
return 0;
|
|
}
|
|
|
|
static void signal_semaphore (stix_t* stix, stix_oop_semaphore_t sem)
|
|
{
|
|
stix_oop_process_t proc;
|
|
stix_ooi_t count;
|
|
|
|
if ((stix_oop_t)sem->waiting_head == stix->_nil)
|
|
{
|
|
printf ("signal semaphore...1111\n");
|
|
/* no process is waiting on this semaphore */
|
|
count = STIX_OOP_TO_SMOOI(sem->count);
|
|
count++;
|
|
sem->count = STIX_SMOOI_TO_OOP(count);
|
|
}
|
|
else
|
|
{
|
|
printf ("signal semaphore...2222\n");
|
|
proc = sem->waiting_head;
|
|
unchain_from_semaphore (stix, proc);
|
|
resume_process (stix, proc); /* TODO: error check */
|
|
}
|
|
}
|
|
|
|
static void await_semaphore (stix_t* stix, stix_oop_semaphore_t sem)
|
|
{
|
|
stix_oop_process_t proc;
|
|
stix_ooi_t count;
|
|
|
|
count = STIX_OOP_TO_SMOOI(sem->count);
|
|
if (count > 0)
|
|
{
|
|
/* it's already signalled */
|
|
count--;
|
|
sem->count = STIX_SMOOI_TO_OOP(count);
|
|
printf (">>>>>>>>>>>>>> AWAIT SEMAPHORE - NO SUSPENDING ...................\n");
|
|
}
|
|
else
|
|
{
|
|
/* not signaled. need to wait */
|
|
proc = stix->processor->active;
|
|
|
|
printf (">>>>>>>>>>>>>> AWAIT SEMAPHORE - SUEPENDING ACTIVE PROCESS...............\n");
|
|
/* suspend the active process */
|
|
suspend_process (stix, proc);
|
|
|
|
/* link the suspened process to the semaphore's process list */
|
|
chain_into_semaphore (stix, proc, sem);
|
|
|
|
STIX_ASSERT (stix->processor->active != proc);
|
|
}
|
|
}
|
|
|
|
static void sift_up_sem_heap (stix_t* stix, stix_ooi_t index)
|
|
{
|
|
if (index > 0)
|
|
{
|
|
stix_ooi_t parent;
|
|
stix_oop_semaphore_t sem, parsem;
|
|
|
|
parent = SEM_HEAP_PARENT(index);
|
|
sem = stix->sem_heap[index];
|
|
parsem = stix->sem_heap[parent];
|
|
if (SEM_HEAP_EARLIER_THAN(stix, sem, parsem))
|
|
{
|
|
do
|
|
{
|
|
/* move down the parent to the current position */
|
|
parsem->heap_index = STIX_SMOOI_TO_OOP(index);
|
|
stix->sem_heap[index] = parsem;
|
|
|
|
/* traverse up */
|
|
index = parent;
|
|
if (index <= 0) break;
|
|
|
|
parent = SEM_HEAP_PARENT(parent);
|
|
parsem = stix->sem_heap[parent];
|
|
}
|
|
while (SEM_HEAP_EARLIER_THAN(stix, sem, parsem));
|
|
|
|
sem->heap_index = STIX_SMOOI_TO_OOP(index);
|
|
stix->sem_heap[index] = sem;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void sift_down_sem_heap (stix_t* stix, stix_ooi_t index)
|
|
{
|
|
stix_ooi_t base = stix->sem_heap_count / 2;
|
|
|
|
if (index < base) /* at least 1 child is under the 'index' position */
|
|
{
|
|
stix_ooi_t left, right, child;
|
|
stix_oop_semaphore_t sem, chisem;
|
|
|
|
sem = stix->sem_heap[index];
|
|
do
|
|
{
|
|
left = SEM_HEAP_LEFT(index);
|
|
right = SEM_HEAP_RIGHT(index);
|
|
|
|
if (right < stix->sem_heap_count && SEM_HEAP_EARLIER_THAN(stix, stix->sem_heap[left], stix->sem_heap[right]))
|
|
{
|
|
child = right;
|
|
}
|
|
else
|
|
{
|
|
child = left;
|
|
}
|
|
|
|
chisem = stix->sem_heap[child];
|
|
if (SEM_HEAP_EARLIER_THAN(stix, sem, chisem)) break;
|
|
|
|
chisem->heap_index = STIX_SMOOI_TO_OOP(index);
|
|
stix->sem_heap[index ] = chisem;
|
|
|
|
index = child;
|
|
}
|
|
while (index < base);
|
|
|
|
sem->heap_index = STIX_SMOOI_TO_OOP(index);
|
|
stix->sem_heap[index] = sem;
|
|
}
|
|
}
|
|
|
|
static int add_to_sem_heap (stix_t* stix, stix_oop_semaphore_t sem)
|
|
{
|
|
stix_ooi_t index;
|
|
|
|
if (stix->sem_heap_count >= SEM_HEAP_MAX)
|
|
{
|
|
stix->errnum = STIX_ESHFULL;
|
|
return -1;
|
|
}
|
|
|
|
if (stix->sem_heap_count >= stix->sem_heap_capa)
|
|
{
|
|
stix_oow_t new_capa;
|
|
stix_oop_semaphore_t* tmp;
|
|
|
|
/* no overflow check when calculating the new capacity
|
|
* owing to SEM_HEAP_MAX check above */
|
|
new_capa = stix->sem_heap_capa + SEM_HEAP_INC;
|
|
tmp = stix_reallocmem (stix, stix->sem_heap, STIX_SIZEOF(stix_oop_semaphore_t) * new_capa);
|
|
if (!tmp) return -1;
|
|
|
|
stix->sem_heap = tmp;
|
|
stix->sem_heap_capa = new_capa;
|
|
}
|
|
|
|
STIX_ASSERT (stix->sem_heap_count <= STIX_SMOOI_MAX);
|
|
|
|
index = stix->sem_heap_count;
|
|
stix->sem_heap[index] = sem;
|
|
sem->heap_index = STIX_SMOOI_TO_OOP(index);
|
|
stix->sem_heap_count++;
|
|
|
|
sift_up_sem_heap (stix, index);
|
|
return 0;
|
|
}
|
|
|
|
static void delete_from_sem_heap (stix_t* stix, stix_ooi_t index)
|
|
{
|
|
stix_oop_semaphore_t sem, lastsem;
|
|
|
|
sem = stix->sem_heap[index];
|
|
sem->heap_index = STIX_SMOOI_TO_OOP(-1);
|
|
|
|
stix->sem_heap_count--;
|
|
if (stix->sem_heap_count > 0 && index != stix->sem_heap_count)
|
|
{
|
|
/* move the last item to the deletion position */
|
|
lastsem = stix->sem_heap[stix->sem_heap_count];
|
|
lastsem->heap_index = STIX_SMOOI_TO_OOP(index);
|
|
stix->sem_heap[index] = lastsem;
|
|
|
|
if (SEM_HEAP_EARLIER_THAN(stix, lastsem, sem))
|
|
sift_up_sem_heap (stix, index);
|
|
else
|
|
sift_down_sem_heap (stix, index);
|
|
}
|
|
}
|
|
|
|
static void update_sem_heap (stix_t* stix, stix_ooi_t index, stix_oop_semaphore_t newsem)
|
|
{
|
|
stix_oop_semaphore_t sem;
|
|
|
|
sem = stix->sem_heap[index];
|
|
sem->heap_index = STIX_SMOOI_TO_OOP(-1);
|
|
|
|
newsem->heap_index = STIX_SMOOI_TO_OOP(index);
|
|
stix->sem_heap[index] = newsem;
|
|
|
|
if (SEM_HEAP_EARLIER_THAN(stix, newsem, sem))
|
|
sift_up_sem_heap (stix, index);
|
|
else
|
|
sift_down_sem_heap (stix, index);
|
|
}
|
|
|
|
static stix_oop_process_t start_initial_process (stix_t* stix, stix_oop_context_t c)
|
|
{
|
|
stix_oop_process_t proc;
|
|
|
|
/* there must be no active process when this function is called */
|
|
STIX_ASSERT (stix->processor->tally == STIX_SMOOI_TO_OOP(0));
|
|
STIX_ASSERT (stix->processor->active == stix->nil_process);
|
|
|
|
proc = make_process (stix, c);
|
|
if (!proc) return STIX_NULL;
|
|
|
|
if (chain_into_processor (stix, proc) <= -1) return STIX_NULL;
|
|
proc->state = STIX_SMOOI_TO_OOP(PROC_STATE_RUNNING); /* skip RUNNABLE and go to RUNNING */
|
|
stix->processor->active = proc;
|
|
|
|
/* do somthing that resume_process() would do with less overhead */
|
|
STIX_ASSERT ((stix_oop_t)proc->current_context != stix->_nil);
|
|
STIX_ASSERT (proc->current_context == proc->initial_context);
|
|
SWITCH_ACTIVE_CONTEXT (stix, proc->current_context);
|
|
|
|
return proc;
|
|
}
|
|
|
|
static STIX_INLINE int activate_new_method (stix_t* stix, stix_oop_method_t mth)
|
|
{
|
|
stix_oop_context_t ctx;
|
|
stix_ooi_t i;
|
|
stix_ooi_t ntmprs, nargs;
|
|
|
|
/* message sending requires a receiver to be pushed.
|
|
* the stack pointer of the sending context cannot be -1.
|
|
* if one-argumented message is invoked the stack of the
|
|
* sending context looks like this.
|
|
*
|
|
* Sending Context
|
|
*
|
|
* +---------------------+
|
|
* | fixed part |
|
|
* | |
|
|
* | |
|
|
* | |
|
|
* +---------------------+
|
|
* | .... | slot[0]
|
|
* | .... | slot[..]
|
|
* | .... | slot[..]
|
|
* | receiver | slot[..] <-- sp - nargs(1)
|
|
* | arg1 | slot[..] <-- sp
|
|
* | .... | slot[..]
|
|
* | | slot[stack_size - 1]
|
|
* +---------------------+
|
|
*/
|
|
ntmprs = STIX_OOP_TO_SMOOI(mth->tmpr_count);
|
|
nargs = STIX_OOP_TO_SMOOI(mth->tmpr_nargs);
|
|
|
|
STIX_ASSERT (ntmprs >= 0);
|
|
STIX_ASSERT (nargs <= ntmprs);
|
|
#if defined(STIX_USE_PROCSTK)
|
|
/* nothing special */
|
|
#else
|
|
STIX_ASSERT (stix->sp >= 0);
|
|
STIX_ASSERT (stix->sp >= nargs);
|
|
#endif
|
|
|
|
stix_pushtmp (stix, (stix_oop_t*)&mth);
|
|
ctx = (stix_oop_context_t)stix_instantiate (stix, stix->_method_context, STIX_NULL, ntmprs + CONTEXT_STACK_SIZE);
|
|
stix_poptmp (stix);
|
|
if (!ctx) return -1;
|
|
|
|
ctx->sender = stix->active_context;
|
|
ctx->ip = STIX_SMOOI_TO_OOP(0);
|
|
/* the front part of a stack has temporary variables including arguments.
|
|
*
|
|
* New Context
|
|
*
|
|
* +---------------------+
|
|
* | fixed part |
|
|
* | |
|
|
* | |
|
|
* | |
|
|
* +---------------------+
|
|
* | tmp1 (arg1) | slot[0]
|
|
* | tmp2 (arg2) | slot[1]
|
|
* | .... | slot[..]
|
|
* | tmpX | slot[..] <-- initial sp
|
|
* | | slot[..]
|
|
* | | slot[..]
|
|
* | | slot[stack_size - 2]
|
|
* | | slot[stack_size - 1]
|
|
* +---------------------+
|
|
*
|
|
* if no temporaries exist, the initial sp is -1.
|
|
*/
|
|
#if defined(STIX_USE_PROCSTK)
|
|
/* ctx->sp will be set further down */
|
|
#else
|
|
ctx->sp = STIX_SMOOI_TO_OOP(ntmprs - 1);
|
|
#endif
|
|
ctx->ntmprs = STIX_SMOOI_TO_OOP(ntmprs);
|
|
ctx->method_or_nargs = (stix_oop_t)mth;
|
|
/* the 'home' field of a method context is always stix->_nil.
|
|
ctx->home = stix->_nil;*/
|
|
ctx->origin = ctx; /* point to self */
|
|
|
|
/*
|
|
* Assume this message sending expression:
|
|
* obj1 do: #this with: #that with: #it
|
|
*
|
|
* It would be compiled to these logical byte-code sequences shown below:
|
|
* push obj1
|
|
* push #this
|
|
* push #that
|
|
* push #it
|
|
* send #do:with:
|
|
*
|
|
* After three pushes, the stack looks like this.
|
|
*
|
|
* | #it | <- sp
|
|
* | #that | sp - 1
|
|
* | #this | sp - 2
|
|
* | obj1 | sp - nargs
|
|
*
|
|
* Since the number of arguments is 3, stack[sp - 3] points to
|
|
* the receiver. When the stack is empty, sp is -1.
|
|
*/
|
|
for (i = nargs; i > 0; )
|
|
{
|
|
/* copy argument */
|
|
ctx->slot[--i] = ACTIVE_STACK_GETTOP (stix);
|
|
ACTIVE_STACK_POP (stix);
|
|
}
|
|
/* copy receiver */
|
|
ctx->receiver_or_source = ACTIVE_STACK_GETTOP (stix);
|
|
ACTIVE_STACK_POP (stix);
|
|
|
|
STIX_ASSERT (stix->sp >= -1);
|
|
|
|
#if defined(STIX_USE_PROCSTK)
|
|
/* when process stack is used, the stack pointer in a context
|
|
* is a stack pointer of a process before it is activated */
|
|
ctx->sp = STIX_SMOOI_TO_OOP(stix->sp);
|
|
#else
|
|
/* do nothing */
|
|
#endif
|
|
|
|
/* switch the active context */
|
|
SWITCH_ACTIVE_CONTEXT (stix, ctx);
|
|
|
|
#if defined(STIX_DEBUG_EXEC_001)
|
|
printf ("<<ENTERING>> SP=%d\n", (int)stix->sp);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static stix_oop_method_t find_method (stix_t* stix, stix_oop_t receiver, const stix_oocs_t* message, int super)
|
|
{
|
|
stix_oop_class_t cls;
|
|
stix_oop_association_t ass;
|
|
stix_oop_t c;
|
|
stix_oop_set_t mthdic;
|
|
int dic_no;
|
|
/* TODO: implement method lookup cache */
|
|
|
|
#if defined(STIX_DEBUG_EXEC_002)
|
|
printf ("==== FINDING METHOD FOR %p [", receiver);
|
|
print_oocs (message);
|
|
printf ("] in ");
|
|
#endif
|
|
|
|
cls = (stix_oop_class_t)STIX_CLASSOF(stix, receiver);
|
|
if ((stix_oop_t)cls == stix->_class)
|
|
{
|
|
/* receiver is a class object */
|
|
c = receiver;
|
|
dic_no = STIX_CLASS_MTHDIC_CLASS;
|
|
#if defined(STIX_DEBUG_EXEC_002)
|
|
printf ("class method dictioanry of ");
|
|
print_object(stix, (stix_oop_t)((stix_oop_class_t)c)->name);
|
|
printf ("\n");
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
c = (stix_oop_t)cls;
|
|
dic_no = STIX_CLASS_MTHDIC_INSTANCE;
|
|
#if defined(STIX_DEBUG_EXEC_002)
|
|
printf ("instance method dictioanry of ");
|
|
print_object(stix, (stix_oop_t)((stix_oop_class_t)c)->name);
|
|
printf ("\n");
|
|
#endif
|
|
}
|
|
|
|
|
|
if (c != stix->_nil)
|
|
{
|
|
if (super)
|
|
{
|
|
c = ((stix_oop_class_t)c)->superclass;
|
|
if (c == stix->_nil) goto not_found;
|
|
}
|
|
|
|
do
|
|
{
|
|
mthdic = ((stix_oop_class_t)c)->mthdic[dic_no];
|
|
STIX_ASSERT ((stix_oop_t)mthdic != stix->_nil);
|
|
STIX_ASSERT (STIX_CLASSOF(stix, mthdic) == stix->_method_dictionary);
|
|
|
|
/*dump_dictionary (stix, mthdic, "Method dictionary");*/
|
|
ass = (stix_oop_association_t)stix_lookupdic (stix, mthdic, message);
|
|
if (ass)
|
|
{
|
|
STIX_ASSERT (STIX_CLASSOF(stix, ass->value) == stix->_method);
|
|
return (stix_oop_method_t)ass->value;
|
|
}
|
|
c = ((stix_oop_class_t)c)->superclass;
|
|
}
|
|
while (c != stix->_nil);
|
|
}
|
|
|
|
not_found:
|
|
stix->errnum = STIX_ENOENT;
|
|
return STIX_NULL;
|
|
}
|
|
|
|
static int start_initial_process_and_context (stix_t* stix, const stix_oocs_t* objname, const stix_oocs_t* mthname)
|
|
{
|
|
/* the initial context is a fake context. if objname is 'Stix' and
|
|
* mthname is 'main', this function emulates message sending 'Stix main'.
|
|
* it should emulate the following logical byte-code sequences:
|
|
*
|
|
* push Stix
|
|
* send #main
|
|
*/
|
|
stix_oop_context_t ctx;
|
|
stix_oop_association_t ass;
|
|
stix_oop_method_t mth;
|
|
stix_oop_process_t proc;
|
|
|
|
/* create a fake initial context */
|
|
ctx = (stix_oop_context_t)stix_instantiate (stix, stix->_method_context, STIX_NULL, 1);
|
|
if (!ctx) return -1;
|
|
|
|
ass = stix_lookupsysdic (stix, objname);
|
|
if (!ass) return -1;
|
|
|
|
mth = find_method (stix, ass->value, mthname, 0);
|
|
if (!mth) return -1;
|
|
|
|
if (STIX_OOP_TO_SMOOI(mth->tmpr_nargs) > 0)
|
|
{
|
|
/* this method expects more than 0 arguments.
|
|
* i can't use it as a start-up method.
|
|
TODO: overcome this problem
|
|
*/
|
|
stix->errnum = STIX_EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
/* TODO: handle preamble */
|
|
|
|
/* the initial context starts the life of the entire VM
|
|
* and is not really worked on except that it is used to call the
|
|
* initial method. so it doesn't really require any extra stack space. */
|
|
/* TODO: verify this theory of mine. */
|
|
stix->ip = 0;
|
|
stix->sp = -1;
|
|
|
|
ctx->ip = STIX_SMOOI_TO_OOP(0); /* point to the beginning */
|
|
ctx->sp = STIX_SMOOI_TO_OOP(-1); /* pointer to -1 below the bottom */
|
|
ctx->origin = ctx; /* point to self */
|
|
ctx->method_or_nargs = (stix_oop_t)mth; /* fake. help SWITCH_ACTIVE_CONTEXT() not fail*/
|
|
|
|
/* [NOTE]
|
|
* the receiver field and the sender field of ctx are nils.
|
|
* especially, the fact that the sender field is nil is used by
|
|
* the main execution loop for breaking out of the loop */
|
|
|
|
STIX_ASSERT (stix->active_context == STIX_NULL);
|
|
STIX_ASSERT (stix->active_method == STIX_NULL);
|
|
|
|
/* stix_gc() uses stix->processor when stix->active_context
|
|
* is not NULL. at this poinst, stix->processor should point to
|
|
* an instance of ProcessScheduler. */
|
|
STIX_ASSERT ((stix_oop_t)stix->processor != stix->_nil);
|
|
STIX_ASSERT (stix->processor->tally == STIX_SMOOI_TO_OOP(0));
|
|
|
|
/* start_initial_process() calls the SWITCH_ACTIVE_CONTEXT() macro.
|
|
* the macro assumes a non-null value in stix->active_context.
|
|
* let's force set active_context to ctx directly. */
|
|
stix->active_context = ctx;
|
|
|
|
stix_pushtmp (stix, (stix_oop_t*)&ctx);
|
|
stix_pushtmp (stix, (stix_oop_t*)&mth);
|
|
stix_pushtmp (stix, (stix_oop_t*)&ass);
|
|
proc = start_initial_process (stix, ctx);
|
|
stix_poptmps (stix, 3);
|
|
if (!proc) return -1;
|
|
|
|
ACTIVE_STACK_PUSH (stix, ass->value); /* push the receiver */
|
|
STORE_ACTIVE_SP (stix); /* stix->active_context->sp = STIX_SMOOI_TO_OOP(stix->sp) */
|
|
|
|
STIX_ASSERT (stix->processor->active == proc);
|
|
STIX_ASSERT (stix->processor->active->initial_context == ctx);
|
|
STIX_ASSERT (stix->processor->active->current_context == ctx);
|
|
STIX_ASSERT (stix->active_context == ctx);
|
|
|
|
|
|
/* emulate the message sending */
|
|
return activate_new_method (stix, mth);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
static int prim_dump (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_ooi_t i;
|
|
|
|
STIX_ASSERT (nargs >= 0);
|
|
|
|
printf ("RECEIVER: ");
|
|
print_object (stix, ACTIVE_STACK_GET(stix, stix->sp - nargs));
|
|
printf ("\n");
|
|
for (i = nargs; i > 0; )
|
|
{
|
|
--i;
|
|
printf ("ARGUMENT: ");
|
|
print_object (stix, ACTIVE_STACK_GET(stix, stix->sp - i));
|
|
printf ("\n");
|
|
}
|
|
|
|
ACTIVE_STACK_POPS (stix, nargs);
|
|
return 1; /* success */
|
|
}
|
|
|
|
static int prim_identical (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg, b;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
b = (rcv == arg)? stix->_true: stix->_false;
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
ACTIVE_STACK_SETTOP (stix, b);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_not_identical (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg, b;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
b = (rcv != arg)? stix->_true: stix->_false;
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
ACTIVE_STACK_SETTOP (stix, b);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_class (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, c;
|
|
|
|
STIX_ASSERT (nargs == 0);
|
|
rcv = ACTIVE_STACK_GETTOP (stix);
|
|
c = STIX_CLASSOF(stix, rcv);
|
|
ACTIVE_STACK_SETTOP (stix, c);
|
|
return 1; /* success */
|
|
}
|
|
|
|
static int prim_basic_new (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, obj;
|
|
|
|
STIX_ASSERT (nargs == 0);
|
|
|
|
rcv = ACTIVE_STACK_GETTOP (stix);
|
|
|
|
if (STIX_CLASSOF(stix, rcv) != stix->_class)
|
|
{
|
|
/* the receiver is not a class object */
|
|
return 0;
|
|
}
|
|
|
|
obj = stix_instantiate (stix, rcv, STIX_NULL, 0);
|
|
if (!obj) return -1;
|
|
|
|
/* emulate 'pop receiver' and 'push result' */
|
|
ACTIVE_STACK_SETTOP (stix, obj);
|
|
return 1; /* success */
|
|
}
|
|
|
|
static int prim_basic_new_with_size (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, szoop, obj;
|
|
stix_oow_t size;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
if (STIX_CLASSOF(stix, rcv) != stix->_class)
|
|
{
|
|
/* the receiver is not a class object */
|
|
return 0;
|
|
}
|
|
|
|
szoop = ACTIVE_STACK_GET(stix, stix->sp);
|
|
if (stix_inttooow (stix, szoop, &size) <= 0)
|
|
{
|
|
/* integer out of range or not integer */
|
|
return 0;
|
|
}
|
|
|
|
/* stix_instantiate() ignores size if the instance specification
|
|
* disallows indexed(variable) parts. */
|
|
/* TODO: should i check the specification before calling
|
|
* stix_instantiate()? */
|
|
obj = stix_instantiate (stix, rcv, STIX_NULL, size);
|
|
if (!obj)
|
|
{
|
|
return -1; /* hard failure */
|
|
}
|
|
|
|
/* remove the argument and replace the receiver with a new object
|
|
* instantiated */
|
|
ACTIVE_STACK_POP (stix);
|
|
ACTIVE_STACK_SETTOP (stix, obj);
|
|
|
|
return 1; /* success */
|
|
}
|
|
|
|
static int prim_ngc_new (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
int n;
|
|
|
|
n = prim_basic_new (stix, nargs);
|
|
if (n <= 0) return n;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int prim_ngc_new_with_size (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
int n;
|
|
|
|
n = prim_basic_new_with_size (stix, nargs);
|
|
if (n <= 0) return n;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int prim_ngc_dispose (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv;
|
|
|
|
STIX_ASSERT (nargs == 0);
|
|
rcv = ACTIVE_STACK_GETTOP (stix);
|
|
|
|
stix_freemem (stix, rcv);
|
|
|
|
ACTIVE_STACK_SETTOP (stix, stix->_nil);
|
|
return 1; /* success */
|
|
}
|
|
|
|
static int prim_shallow_copy (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, obj;
|
|
|
|
STIX_ASSERT (nargs == 0);
|
|
|
|
rcv = ACTIVE_STACK_GETTOP (stix);
|
|
|
|
obj = stix_shallowcopy (stix, rcv);
|
|
if (!obj) return -1;
|
|
|
|
/* emulate 'pop receiver' and 'push result' */
|
|
ACTIVE_STACK_SETTOP (stix, obj);
|
|
return 1; /* success */
|
|
}
|
|
|
|
static int prim_basic_size (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, sz;
|
|
|
|
STIX_ASSERT (nargs == 0);
|
|
|
|
rcv = ACTIVE_STACK_GETTOP(stix);
|
|
|
|
sz = stix_oowtoint (stix, STIX_OBJ_GET_SIZE(rcv));
|
|
if (!sz) return -1; /* hard failure */
|
|
ACTIVE_STACK_SETTOP(stix, sz);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int prim_basic_at (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, pos, v;
|
|
stix_oow_t idx;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
if (!STIX_OOP_IS_POINTER(rcv))
|
|
{
|
|
/* the receiver is a special numeric object, not a normal pointer */
|
|
return 0;
|
|
}
|
|
|
|
pos = ACTIVE_STACK_GET(stix, stix->sp);
|
|
if (stix_inttooow (stix, pos, &idx) <= 0)
|
|
{
|
|
/* negative integer or not integer */
|
|
return 0;
|
|
}
|
|
if (idx >= STIX_OBJ_GET_SIZE(rcv))
|
|
{
|
|
/* index out of range */
|
|
return 0;
|
|
}
|
|
|
|
switch (STIX_OBJ_GET_FLAGS_TYPE(rcv))
|
|
{
|
|
case STIX_OBJ_TYPE_BYTE:
|
|
v = STIX_SMOOI_TO_OOP(((stix_oop_byte_t)rcv)->slot[idx]);
|
|
break;
|
|
|
|
case STIX_OBJ_TYPE_CHAR:
|
|
v = STIX_CHAR_TO_OOP(((stix_oop_char_t)rcv)->slot[idx]);
|
|
break;
|
|
|
|
case STIX_OBJ_TYPE_HALFWORD:
|
|
/* TODO: LargeInteger if the halfword is too large */
|
|
v = STIX_SMOOI_TO_OOP(((stix_oop_halfword_t)rcv)->slot[idx]);
|
|
break;
|
|
|
|
case STIX_OBJ_TYPE_WORD:
|
|
/* TODO: LargeInteger if the word is too large */
|
|
v = STIX_SMOOI_TO_OOP(((stix_oop_word_t)rcv)->slot[idx]);
|
|
break;
|
|
|
|
case STIX_OBJ_TYPE_OOP:
|
|
v = ((stix_oop_oop_t)rcv)->slot[idx];
|
|
break;
|
|
|
|
default:
|
|
stix->errnum = STIX_EINTERN;
|
|
return -1;
|
|
}
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
ACTIVE_STACK_SETTOP (stix, v);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_basic_at_put (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, pos, val;
|
|
stix_oow_t idx;
|
|
|
|
STIX_ASSERT (nargs == 2);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 2);
|
|
if (!STIX_OOP_IS_POINTER(rcv))
|
|
{
|
|
/* the receiver is a special numeric object, not a normal pointer */
|
|
return 0;
|
|
}
|
|
pos = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
val = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
if (stix_inttooow (stix, pos, &idx) <= 0)
|
|
{
|
|
/* negative integer or not integer */
|
|
return 0;
|
|
}
|
|
if (idx >= STIX_OBJ_GET_SIZE(rcv))
|
|
{
|
|
/* index out of range */
|
|
return 0;
|
|
}
|
|
|
|
if (STIX_OBJ_GET_CLASS(rcv) == stix->_symbol)
|
|
{
|
|
/* TODO: disallow change of some key kernel objects???? */
|
|
/* TODO: is it better to introduct a read-only mark in the object header instead of this class check??? */
|
|
/* read-only object */ /* TODO: DEVISE A WAY TO PASS a proper error from the primitive handler to STIX */
|
|
return 0;
|
|
}
|
|
|
|
switch (STIX_OBJ_GET_FLAGS_TYPE(rcv))
|
|
{
|
|
case STIX_OBJ_TYPE_BYTE:
|
|
if (!STIX_OOP_IS_SMOOI(val))
|
|
{
|
|
/* the value is not a character */
|
|
return 0;
|
|
}
|
|
/* TOOD: must I check the range of the value? */
|
|
((stix_oop_char_t)rcv)->slot[idx] = STIX_OOP_TO_SMOOI(val);
|
|
break;
|
|
|
|
case STIX_OBJ_TYPE_CHAR:
|
|
if (!STIX_OOP_IS_CHAR(val))
|
|
{
|
|
/* the value is not a character */
|
|
return 0;
|
|
}
|
|
((stix_oop_char_t)rcv)->slot[idx] = STIX_OOP_TO_CHAR(val);
|
|
break;
|
|
|
|
case STIX_OBJ_TYPE_HALFWORD:
|
|
if (!STIX_OOP_IS_SMOOI(val))
|
|
{
|
|
/* the value is not a number */
|
|
return 0;
|
|
}
|
|
|
|
/* if the small integer is too large, it will get truncated */
|
|
((stix_oop_halfword_t)rcv)->slot[idx] = STIX_OOP_TO_SMOOI(val);
|
|
break;
|
|
|
|
case STIX_OBJ_TYPE_WORD:
|
|
/* TODO: handle LargeInteger */
|
|
if (!STIX_OOP_IS_SMOOI(val))
|
|
{
|
|
/* the value is not a number */
|
|
return 0;
|
|
}
|
|
((stix_oop_word_t)rcv)->slot[idx] = STIX_OOP_TO_SMOOI(val);
|
|
break;
|
|
|
|
case STIX_OBJ_TYPE_OOP:
|
|
((stix_oop_oop_t)rcv)->slot[idx] = val;
|
|
break;
|
|
|
|
default:
|
|
stix->errnum = STIX_EINTERN;
|
|
return -1;
|
|
}
|
|
|
|
ACTIVE_STACK_POPS (stix, 2);
|
|
/* TODO: return receiver or value? */
|
|
ACTIVE_STACK_SETTOP (stix, val);
|
|
return 1;
|
|
}
|
|
|
|
static int __block_value (stix_t* stix, stix_ooi_t nargs, stix_ooi_t num_first_arg_elems, stix_oop_context_t* pblkctx)
|
|
{
|
|
/* prepare a new block context for activation.
|
|
* the receiver must be a block context which becomes the base
|
|
* for a new block context. */
|
|
|
|
stix_oop_context_t blkctx, org_blkctx;
|
|
stix_ooi_t local_ntmprs, i;
|
|
stix_ooi_t actual_arg_count;
|
|
|
|
actual_arg_count = (num_first_arg_elems > 0)? num_first_arg_elems: nargs;
|
|
|
|
/* TODO: find a better way to support a reentrant block context. */
|
|
|
|
/* | sum |
|
|
* sum := [ :n | (n < 2) ifTrue: [1] ifFalse: [ n + (sum value: (n - 1))] ].
|
|
* (sum value: 10).
|
|
*
|
|
* For the code above, sum is a block context and it is sent value: inside
|
|
* itself. Let me simply clone a block context to allow reentrancy like this
|
|
* while the block context is active
|
|
*/
|
|
org_blkctx = (stix_oop_context_t)ACTIVE_STACK_GET(stix, stix->sp - nargs);
|
|
if (STIX_CLASSOF(stix, org_blkctx) != stix->_block_context)
|
|
{
|
|
/* the receiver must be a block context */
|
|
#if defined(STIX_DEBUG_EXEC_001)
|
|
printf ("PRIMITVE VALUE RECEIVER IS NOT A BLOCK CONTEXT\n");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
if (org_blkctx->receiver_or_source != stix->_nil)
|
|
{
|
|
/* the 'source' field is not nil.
|
|
* this block context has already been activated once.
|
|
* you can't send 'value' again to reactivate it.
|
|
* For example, [thisContext value] value.
|
|
*/
|
|
STIX_ASSERT (STIX_OBJ_GET_SIZE(org_blkctx) > STIX_CONTEXT_NAMED_INSTVARS);
|
|
#if defined(STIX_DEBUG_EXEC_001)
|
|
printf ("PRIM REVALUING AN BLOCKCONTEXT\n");
|
|
#endif
|
|
return 0;
|
|
}
|
|
STIX_ASSERT (STIX_OBJ_GET_SIZE(org_blkctx) == STIX_CONTEXT_NAMED_INSTVARS);
|
|
|
|
if (STIX_OOP_TO_SMOOI(org_blkctx->method_or_nargs) != actual_arg_count /* nargs */)
|
|
{
|
|
/* the number of argument doesn't match */
|
|
#if defined(STIX_DEBUG_EXEC_001)
|
|
/* TODO: better handling of primitive failure */
|
|
printf ("PRIM BlockContext value FAIL - NARGS MISMATCH\n");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/* the number of temporaries stored in the block context
|
|
* accumulates the number of temporaries starting from the origin.
|
|
* simple calculation is needed to find the number of local temporaries */
|
|
local_ntmprs = STIX_OOP_TO_SMOOI(org_blkctx->ntmprs) -
|
|
STIX_OOP_TO_SMOOI(((stix_oop_context_t)org_blkctx->home)->ntmprs);
|
|
STIX_ASSERT (local_ntmprs >= actual_arg_count);
|
|
|
|
/* create a new block context to clone org_blkctx */
|
|
blkctx = (stix_oop_context_t) stix_instantiate (stix, stix->_block_context, STIX_NULL, local_ntmprs + CONTEXT_STACK_SIZE);
|
|
if (!blkctx) return -1;
|
|
|
|
/* get org_blkctx again to be GC-safe for stix_instantiate() above */
|
|
org_blkctx = (stix_oop_context_t)ACTIVE_STACK_GET(stix, stix->sp - nargs);
|
|
STIX_ASSERT (STIX_CLASSOF(stix, org_blkctx) == stix->_block_context);
|
|
|
|
#if 0
|
|
/* shallow-copy the named part including home, origin, etc. */
|
|
for (i = 0; i < STIX_CONTEXT_NAMED_INSTVARS; i++)
|
|
{
|
|
((stix_oop_oop_t)blkctx)->slot[i] = ((stix_oop_oop_t)org_blkctx)->slot[i];
|
|
}
|
|
#else
|
|
blkctx->ip = org_blkctx->ip;
|
|
blkctx->ntmprs = org_blkctx->ntmprs;
|
|
blkctx->method_or_nargs = org_blkctx->method_or_nargs;
|
|
blkctx->receiver_or_source = (stix_oop_t)org_blkctx;
|
|
blkctx->home = org_blkctx->home;
|
|
blkctx->origin = org_blkctx->origin;
|
|
#endif
|
|
|
|
/* TODO: check the stack size of a block context to see if it's large enough to hold arguments */
|
|
if (num_first_arg_elems > 0)
|
|
{
|
|
/* the first argument should be an array. this function is ordered
|
|
* to pass array elements to the new block */
|
|
stix_oop_oop_t xarg;
|
|
STIX_ASSERT (nargs == 1);
|
|
xarg = (stix_oop_oop_t)ACTIVE_STACK_GETTOP (stix);
|
|
STIX_ASSERT (STIX_ISTYPEOF(stix,xarg,STIX_OBJ_TYPE_OOP));
|
|
STIX_ASSERT (STIX_OBJ_GET_SIZE(xarg) == num_first_arg_elems);
|
|
for (i = 0; i < num_first_arg_elems; i++)
|
|
{
|
|
blkctx->slot[i] = xarg->slot[i];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* copy the arguments to the stack */
|
|
for (i = 0; i < nargs; i++)
|
|
{
|
|
blkctx->slot[i] = ACTIVE_STACK_GET(stix, stix->sp - nargs + i + 1);
|
|
}
|
|
}
|
|
ACTIVE_STACK_POPS (stix, nargs + 1); /* pop arguments and receiver */
|
|
|
|
STIX_ASSERT (blkctx->home != stix->_nil);
|
|
blkctx->sp = STIX_SMOOI_TO_OOP(local_ntmprs - 1);
|
|
blkctx->sender = stix->active_context;
|
|
|
|
*pblkctx = blkctx;
|
|
return 1;
|
|
}
|
|
|
|
static int prim_block_value (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
int x;
|
|
stix_oop_context_t blkctx;
|
|
|
|
x = __block_value (stix, nargs, 0, &blkctx);
|
|
if (x <= 0) return x; /* hard failure and soft failure */
|
|
|
|
#if defined(STIX_DEBUG_EXEC_001)
|
|
printf ("<<ENTERING BLOCK>> SP=%ld\n", (long int)stix->sp);
|
|
#endif
|
|
SWITCH_ACTIVE_CONTEXT (stix, (stix_oop_context_t)blkctx);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_block_new_process (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
/* create a new process from a block context.
|
|
* the receiver must be be a block.
|
|
* [ 1 + 2 ] newProcess.
|
|
* [ :a :b | a + b ] newProcess: #(1 2)
|
|
*/
|
|
|
|
int x;
|
|
stix_oop_context_t blkctx;
|
|
stix_oop_process_t proc;
|
|
stix_ooi_t num_first_arg_elems = 0;
|
|
|
|
if (nargs > 1)
|
|
{
|
|
/* too many arguments */
|
|
/* TODO: proper error handling */
|
|
return 0;
|
|
}
|
|
|
|
if (nargs == 1)
|
|
{
|
|
stix_oop_t xarg;
|
|
|
|
xarg = ACTIVE_STACK_GETTOP(stix);
|
|
if (!STIX_ISTYPEOF(stix,xarg,STIX_OBJ_TYPE_OOP))
|
|
{
|
|
/* the only optional argument must be an OOP-indexable
|
|
* object like an array */
|
|
return 0;
|
|
}
|
|
|
|
num_first_arg_elems = STIX_OBJ_GET_SIZE(xarg);
|
|
}
|
|
|
|
/* this primitive creates a new process with a block as if the block
|
|
* is sent the value message */
|
|
x = __block_value (stix, nargs, num_first_arg_elems, &blkctx);
|
|
if (x <= 0) return x; /* both hard failure and soft failure */
|
|
|
|
proc = make_process (stix, blkctx);
|
|
if (!proc) return -1; /* hard failure */ /* TOOD: can't this be treated as a soft failure? */
|
|
|
|
/* __block_value() has popped all arguments and the receiver.
|
|
* PUSH the return value instead of changing the stack top */
|
|
ACTIVE_STACK_PUSH (stix, (stix_oop_t)proc);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_process_resume (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv;
|
|
STIX_ASSERT (nargs == 0);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp);
|
|
if (STIX_CLASSOF(stix,rcv) != stix->_process) return 0;
|
|
|
|
resume_process (stix, (stix_oop_process_t)rcv); /* TODO: error check */
|
|
|
|
/* keep the receiver in the stack top */
|
|
return 1;
|
|
}
|
|
|
|
static int prim_process_terminate (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv;
|
|
STIX_ASSERT (nargs == 0);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp);
|
|
if (STIX_CLASSOF(stix,rcv) != stix->_process) return 0;
|
|
|
|
terminate_process (stix, (stix_oop_process_t)rcv);
|
|
|
|
/* keep the receiver in the stack top */
|
|
return 1;
|
|
}
|
|
|
|
static int prim_process_yield (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv;
|
|
STIX_ASSERT (nargs == 0);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp);
|
|
if (STIX_CLASSOF(stix,rcv) != stix->_process) return 0;
|
|
|
|
yield_process (stix, (stix_oop_process_t)rcv);
|
|
|
|
/* keep the receiver in the stack top */
|
|
return 1;
|
|
}
|
|
|
|
static int prim_semaphore_signal (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv;
|
|
STIX_ASSERT (nargs == 0);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp);
|
|
if (STIX_CLASSOF(stix,rcv) != stix->_semaphore) return 0;
|
|
|
|
signal_semaphore (stix, (stix_oop_semaphore_t)rcv);
|
|
|
|
/* keep the receiver in the stack top */
|
|
return 1;
|
|
}
|
|
|
|
static int prim_semaphore_wait (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv;
|
|
STIX_ASSERT (nargs == 0);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp);
|
|
if (STIX_CLASSOF(stix,rcv) != stix->_semaphore) return 0;
|
|
|
|
await_semaphore (stix, (stix_oop_semaphore_t)rcv);
|
|
|
|
/* keep the receiver in the stack top */
|
|
return 1;
|
|
}
|
|
|
|
static int prim_processor_schedule (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
if (rcv != (stix_oop_t)stix->processor || STIX_CLASSOF(stix,arg) != stix->_process)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
resume_process (stix, (stix_oop_process_t)arg); /* TODO: error check */
|
|
return 1;
|
|
}
|
|
|
|
static int prim_processor_remove (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
/* TODO: */
|
|
return 0;
|
|
}
|
|
|
|
static int prim_processor_sleep (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
/* TODO: */
|
|
return 0;
|
|
}
|
|
|
|
static int prim_processor_add_timed_semaphore (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, sec, nsec;
|
|
stix_oop_semaphore_t sem;
|
|
struct timespec ts, ft;
|
|
|
|
STIX_ASSERT (nargs >= 2 || nargs <= 3);
|
|
|
|
if (nargs == 3)
|
|
{
|
|
nsec = ACTIVE_STACK_GET (stix, stix->sp);
|
|
if (!STIX_OOP_IS_SMOOI(nsec)) return 0;
|
|
}
|
|
else nsec = STIX_SMOOI_TO_OOP(0);
|
|
|
|
sec = ACTIVE_STACK_GET(stix, stix->sp - nargs + 2);
|
|
sem = (stix_oop_semaphore_t)ACTIVE_STACK_GET(stix, stix->sp - nargs + 1);
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - nargs);
|
|
|
|
if (rcv != (stix_oop_t)stix->processor) return 0;
|
|
if (STIX_CLASSOF(stix,sem) != stix->_semaphore) return 0;
|
|
if (!STIX_OOP_IS_SMOOI(sec)) return 0;
|
|
|
|
if (STIX_OOP_IS_SMOOI(sem->heap_index) &&
|
|
sem->heap_index != STIX_SMOOI_TO_OOP(-1))
|
|
{
|
|
delete_from_sem_heap (stix, STIX_OOP_TO_SMOOI(sem->heap_index));
|
|
STIX_ASSERT(sem->heap_index == STIX_SMOOI_TO_OOP(-1));
|
|
|
|
/*
|
|
Is this more desired???
|
|
ACTIVE_STACK_POPS (stix, nargs);
|
|
ACTIVE_STACK_SETTOP (stix, stix->_false);
|
|
return 1;
|
|
*/
|
|
}
|
|
|
|
/* TODO: make clock_gettime to be platform independent
|
|
*
|
|
* this code assumes that the monotonic clock returns a small value
|
|
* that can fit into a small integer, even after some addtions... */
|
|
if (clock_gettime (CLOCK_MONOTONIC, &ts) == -1)
|
|
{
|
|
/* TODO: soft error handling */
|
|
printf ("clock_gettime() failure....\n");
|
|
return 0;
|
|
}
|
|
|
|
ft.tv_nsec = ts.tv_nsec + STIX_OOP_TO_SMOOI(nsec);
|
|
ft.tv_sec = ts.tv_sec + STIX_OOP_TO_SMOOI(sec);
|
|
while (ft.tv_nsec >= 1000000000)
|
|
{
|
|
ft.tv_sec++;
|
|
ft.tv_nsec -= 1000000000;
|
|
}
|
|
|
|
if (ft.tv_sec < 0 || ft.tv_sec > STIX_SMOOI_MAX)
|
|
{
|
|
/* soft error - cannot represent the expiry time in
|
|
* a small integer. */
|
|
return 0;
|
|
}
|
|
|
|
sem->heap_ftime_sec = STIX_SMOOI_TO_OOP(ft.tv_sec);
|
|
sem->heap_ftime_nsec = STIX_SMOOI_TO_OOP(ft.tv_nsec);
|
|
|
|
if (add_to_sem_heap (stix, sem) <= -1) return -1;
|
|
|
|
ACTIVE_STACK_POPS (stix, nargs);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_processor_del_time_semaphore (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv;
|
|
stix_oop_semaphore_t sem;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
sem = (stix_oop_semaphore_t)ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
if (rcv != (stix_oop_t)stix->processor) return 0;
|
|
if (STIX_CLASSOF(stix,sem) != stix->_semaphore) return 0;
|
|
|
|
if (STIX_OOP_IS_SMOOI(sem->heap_index) &&
|
|
sem->heap_index != STIX_SMOOI_TO_OOP(-1))
|
|
{
|
|
delete_from_sem_heap (stix, STIX_OOP_TO_SMOOI(sem));
|
|
STIX_ASSERT(sem->heap_index == STIX_SMOOI_TO_OOP(-1));
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int prim_integer_add (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg, res;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
res = stix_addints (stix, rcv, arg);
|
|
if (!res) return (stix->errnum == STIX_EINVAL? 0: -1); /* soft or hard failure */
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
ACTIVE_STACK_SETTOP (stix, res);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_integer_sub (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg, res;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
res = stix_subints (stix, rcv, arg);
|
|
if (!res) return (stix->errnum == STIX_EINVAL? 0: -1); /* soft or hard failure */
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
ACTIVE_STACK_SETTOP (stix, res);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_integer_mul (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg, res;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
res = stix_mulints (stix, rcv, arg);
|
|
if (!res) return (stix->errnum == STIX_EINVAL? 0: -1); /* soft or hard failure */
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
ACTIVE_STACK_SETTOP (stix, res);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_integer_quo (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg, quo;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
quo = stix_divints (stix, rcv, arg, 0, STIX_NULL);
|
|
if (!quo) return (stix->errnum == STIX_EINVAL? 0: -1); /* soft or hard failure */
|
|
/* TODO: STIX_EDIVBY0 soft or hard failure? */
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
ACTIVE_STACK_SETTOP (stix, quo);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_integer_rem (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg, quo, rem;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
quo = stix_divints (stix, rcv, arg, 0, &rem);
|
|
if (!quo) return (stix->errnum == STIX_EINVAL? 0: -1); /* soft or hard failure */
|
|
/* TODO: STIX_EDIVBY0 soft or hard failure? */
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
ACTIVE_STACK_SETTOP (stix, rem);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_integer_quo2 (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg, quo;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
quo = stix_divints (stix, rcv, arg, 1, STIX_NULL);
|
|
if (!quo) return (stix->errnum == STIX_EINVAL? 0: -1); /* soft or hard failure */
|
|
/* TODO: STIX_EDIVBY0 soft or hard failure? */
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
ACTIVE_STACK_SETTOP (stix, quo);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_integer_rem2 (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg, quo, rem;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
quo = stix_divints (stix, rcv, arg, 1, &rem);
|
|
if (!quo) return (stix->errnum == STIX_EINVAL? 0: -1); /* soft or hard failure */
|
|
/* TODO: STIX_EDIVBY0 soft or hard failure? */
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
ACTIVE_STACK_SETTOP (stix, rem);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_integer_negated (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, res;
|
|
|
|
STIX_ASSERT (nargs == 0);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
res = stix_negateint (stix, rcv);
|
|
if (!res) return (stix->errnum == STIX_EINVAL? 0: -1); /* soft or hard failure */
|
|
|
|
ACTIVE_STACK_SETTOP (stix, res);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_integer_bitat (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg, res;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
res = stix_bitatint (stix, rcv, arg);
|
|
if (!res) return (stix->errnum == STIX_EINVAL? 0: -1); /* soft or hard failure */
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
ACTIVE_STACK_SETTOP (stix, res);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_integer_bitand (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg, res;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
res = stix_bitandints (stix, rcv, arg);
|
|
if (!res) return (stix->errnum == STIX_EINVAL? 0: -1); /* soft or hard failure */
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
ACTIVE_STACK_SETTOP (stix, res);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_integer_bitor (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg, res;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
res = stix_bitorints (stix, rcv, arg);
|
|
if (!res) return (stix->errnum == STIX_EINVAL? 0: -1); /* soft or hard failure */
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
ACTIVE_STACK_SETTOP (stix, res);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_integer_bitxor (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg, res;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
res = stix_bitxorints (stix, rcv, arg);
|
|
if (!res) return (stix->errnum == STIX_EINVAL? 0: -1); /* soft or hard failure */
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
ACTIVE_STACK_SETTOP (stix, res);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_integer_bitinv (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, res;
|
|
|
|
STIX_ASSERT (nargs == 0);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
res = stix_bitinvint (stix, rcv);
|
|
if (!res) return (stix->errnum == STIX_EINVAL? 0: -1); /* soft or hard failure */
|
|
|
|
ACTIVE_STACK_SETTOP (stix, res);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_integer_bitshift (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg, res;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
res = stix_bitshiftint (stix, rcv, arg);
|
|
if (!res) return (stix->errnum == STIX_EINVAL? 0: -1); /* soft or hard failure */
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
ACTIVE_STACK_SETTOP (stix, res);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_integer_eq (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg, res;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
res = stix_eqints (stix, rcv, arg);
|
|
if (!res) return (stix->errnum == STIX_EINVAL? 0: -1); /* soft or hard failure */
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
ACTIVE_STACK_SETTOP (stix, res);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_integer_ne (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg, res;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
res = stix_neints (stix, rcv, arg);
|
|
if (!res) return (stix->errnum == STIX_EINVAL? 0: -1); /* soft or hard failure */
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
ACTIVE_STACK_SETTOP (stix, res);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_integer_lt (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg, res;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
res = stix_ltints (stix, rcv, arg);
|
|
if (!res) return (stix->errnum == STIX_EINVAL? 0: -1); /* soft or hard failure */
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
ACTIVE_STACK_SETTOP (stix, res);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_integer_gt (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg, res;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
res = stix_gtints (stix, rcv, arg);
|
|
if (!res) return (stix->errnum == STIX_EINVAL? 0: -1); /* soft or hard failure */
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
ACTIVE_STACK_SETTOP (stix, res);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_integer_le (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg, res;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
res = stix_leints (stix, rcv, arg);
|
|
if (!res) return (stix->errnum == STIX_EINVAL? 0: -1); /* soft or hard failure */
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
ACTIVE_STACK_SETTOP (stix, res);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_integer_ge (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg, res;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
res = stix_geints (stix, rcv, arg);
|
|
if (!res) return (stix->errnum == STIX_EINVAL? 0: -1); /* soft or hard failure */
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
ACTIVE_STACK_SETTOP (stix, res);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_integer_inttostr (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg, str;
|
|
stix_ooi_t radix;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
if (!STIX_OOP_IS_SMOOI(arg)) return 0; /* soft failure */
|
|
radix = STIX_OOP_TO_SMOOI(arg);
|
|
|
|
if (radix < 2 || radix > 36) return 0; /* soft failure */
|
|
str = stix_inttostr (stix, rcv, radix);
|
|
if (!str) return (stix->errnum == STIX_EINVAL? 0: -1);
|
|
|
|
ACTIVE_STACK_SETTOP (stix, str);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_ffi_open (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg;
|
|
void* handle;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
if (!STIX_ISTYPEOF(stix, arg, STIX_OBJ_TYPE_CHAR))
|
|
{
|
|
/* TODO: more info on error */
|
|
return 0;
|
|
}
|
|
|
|
if (!stix->vmprim.mod_open)
|
|
{
|
|
/* TODO: more info on error */
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* TODO: check null-termination... */
|
|
handle = stix->vmprim.mod_open (stix, ((stix_oop_char_t)arg)->slot);
|
|
if (!handle)
|
|
{
|
|
/* TODO: more info on error */
|
|
return 0;
|
|
}
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
/* TODO: how to hold an address? as an integer???? or a byte array? fix this not to loose accuracy*/
|
|
ACTIVE_STACK_SETTOP (stix, STIX_SMOOI_TO_OOP(handle));
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int prim_ffi_close (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, arg;
|
|
void* handle;
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
STIX_ASSERT (nargs == 1);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
arg = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
if (!STIX_OOP_IS_SMOOI(arg))
|
|
{
|
|
/* TODO: more info on error */
|
|
return 0;
|
|
}
|
|
|
|
ACTIVE_STACK_POP (stix);
|
|
|
|
handle = (void*)STIX_OOP_TO_SMOOI(arg); /* TODO: how to store void* ???. fix this not to loose accuracy */
|
|
if (stix->vmprim.mod_close) stix->vmprim.mod_close (stix, handle);
|
|
return 1;
|
|
}
|
|
|
|
static int prim_ffi_call (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
#if defined(USE_DYNCALL)
|
|
stix_oop_t rcv, fun, sig, args;
|
|
|
|
STIX_ASSERT (nargs == 3);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 3);
|
|
fun = ACTIVE_STACK_GET(stix, stix->sp - 2);
|
|
sig = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
args = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
if (!STIX_OOP_IS_SMOOI(fun)) /* TODO: how to store pointer */
|
|
{
|
|
/* TODO: more info on error */
|
|
return 0;
|
|
}
|
|
|
|
if (!STIX_ISTYPEOF(stix, sig, STIX_OBJ_TYPE_CHAR) || STIX_OBJ_GET_SIZE(sig) <= 0)
|
|
{
|
|
printf ("wrong signature...\n");
|
|
return 0;
|
|
}
|
|
|
|
if (STIX_CLASSOF(stix,args) != stix->_array) /* TODO: check if arr is a kind of array??? or check if it's indexed */
|
|
{
|
|
/* TODO: more info on error */
|
|
return 0;
|
|
}
|
|
|
|
{
|
|
stix_oow_t i;
|
|
DCCallVM* dc;
|
|
void* f;
|
|
stix_oop_oop_t arr;
|
|
int mode_set;
|
|
|
|
f = STIX_OOP_TO_SMOOI(fun); /* TODO: decode pointer properly */
|
|
arr = (stix_oop_oop_t)args;
|
|
|
|
dc = dcNewCallVM (4096);
|
|
if (!dc) return -1; /* TODO: proper error handling */
|
|
|
|
printf ("CALLING............%p\n", f);
|
|
/*dcMode (dc, DC_CALL_C_DEFAULT);
|
|
dcReset (dc);*/
|
|
|
|
/*for (i = 2; i < STIX_OBJ_GET_SIZE(sig); i++)
|
|
{
|
|
if (((stix_oop_char_t)sig)->slot[i] == '|')
|
|
{
|
|
dcMode (dc, DC_CALL_C_ELLIPSIS);
|
|
printf ("CALL MODE 111 ERROR %d %d\n", dcGetError (dc), DC_ERROR_UNSUPPORTED_MODE);
|
|
mode_set = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!mode_set) */ dcMode (dc, DC_CALL_C_DEFAULT);
|
|
|
|
for (i = 2; i < STIX_OBJ_GET_SIZE(sig); i++)
|
|
{
|
|
printf ("CALLING ARG %c\n", ((stix_oop_char_t)sig)->slot[i]);
|
|
switch (((stix_oop_char_t)sig)->slot[i])
|
|
{
|
|
/* TODO: support more types... */
|
|
/*
|
|
case '|':
|
|
dcMode (dc, DC_CALL_C_ELLIPSIS_VARARGS);
|
|
printf ("CALL MODE 222 ERROR %d %d\n", dcGetError (dc), DC_ERROR_UNSUPPORTED_MODE);
|
|
break;
|
|
*/
|
|
|
|
case 'c':
|
|
/* TODO: sanity check on the argument type */
|
|
dcArgChar (dc, STIX_OOP_TO_CHAR(arr->slot[i - 2]));
|
|
break;
|
|
|
|
case 'i':
|
|
dcArgInt (dc, STIX_OOP_TO_SMOOI(arr->slot[i - 2]));
|
|
break;
|
|
|
|
case 'l':
|
|
dcArgLong (dc, STIX_OOP_TO_SMOOI(arr->slot[i - 2]));
|
|
break;
|
|
|
|
case 'L':
|
|
dcArgLongLong (dc, STIX_OOP_TO_SMOOI(arr->slot[i - 2]));
|
|
break;
|
|
|
|
case 's':
|
|
{
|
|
stix_oow_t bcslen, ucslen;
|
|
stix_bch_t bcs[1024];
|
|
|
|
ucslen = STIX_OBJ_GET_SIZE(arr->slot[i - 2]);
|
|
stix_ucstoutf8 (((stix_oop_char_t)arr->slot[i - 2])->slot, &ucslen, bcs, &bcslen); /* proper string conversion */
|
|
|
|
bcs[bcslen] = '\0';
|
|
dcArgPointer (dc, bcs);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
/* TODO: ERROR HANDLING */
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
ACTIVE_STACK_POPS (stix, nargs);
|
|
|
|
switch (((stix_oop_char_t)sig)->slot[0])
|
|
{
|
|
/* TODO: support more types... */
|
|
/* TODO: proper return value conversion */
|
|
case 'c':
|
|
{
|
|
char r = dcCallChar (dc, f);
|
|
ACTIVE_STACK_SETTOP (stix, STIX_CHAR_TO_OOP(r));
|
|
break;
|
|
}
|
|
|
|
case 'i':
|
|
{
|
|
int r = dcCallInt (dc, f);
|
|
printf ("CALLED... %d\n", r);
|
|
printf ("CALL ERROR %d %d\n", dcGetError (dc), DC_ERROR_UNSUPPORTED_MODE);
|
|
ACTIVE_STACK_SETTOP (stix, STIX_SMOOI_TO_OOP(r));
|
|
break;
|
|
}
|
|
|
|
case 'l':
|
|
{
|
|
long r = dcCallLong (dc, f);
|
|
ACTIVE_STACK_SETTOP (stix, STIX_SMOOI_TO_OOP(r));
|
|
break;
|
|
}
|
|
|
|
case 'L':
|
|
{
|
|
long long r = dcCallLongLong (dc, f);
|
|
ACTIVE_STACK_SETTOP (stix, STIX_SMOOI_TO_OOP(r));
|
|
break;
|
|
}
|
|
|
|
case 's':
|
|
{
|
|
stix_oow_t bcslen, ucslen;
|
|
stix_ooch_t ucs[1024];
|
|
stix_oop_t s;
|
|
char* r = dcCallPointer (dc, f);
|
|
|
|
bcslen = strlen(r);
|
|
stix_utf8toucs (r, &bcslen, ucs, &ucslen); /* proper string conversion */
|
|
|
|
s = stix_makestring(stix, ucs, ucslen)
|
|
if (!s)
|
|
{
|
|
dcFree (dc);
|
|
return -1; /* TODO: proper error h andling */
|
|
}
|
|
|
|
ACTIVE_STACK_SETTOP (stix, s);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
/* TOOD: ERROR HANDLING */
|
|
break;
|
|
}
|
|
|
|
dcFree (dc);
|
|
}
|
|
|
|
return 1;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
static int prim_ffi_getsym (stix_t* stix, stix_ooi_t nargs)
|
|
{
|
|
stix_oop_t rcv, hnd, fun;
|
|
void* sym;
|
|
|
|
STIX_ASSERT (nargs == 2);
|
|
|
|
rcv = ACTIVE_STACK_GET(stix, stix->sp - 2);
|
|
fun = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
|
hnd = ACTIVE_STACK_GET(stix, stix->sp);
|
|
|
|
if (!STIX_OOP_IS_SMOOI(hnd)) /* TODO: how to store pointer */
|
|
{
|
|
/* TODO: more info on error */
|
|
return 0;
|
|
}
|
|
|
|
if (!STIX_ISTYPEOF(stix,fun,STIX_OBJ_TYPE_CHAR))
|
|
{
|
|
printf ("wrong function name...\n");
|
|
return 0;
|
|
}
|
|
|
|
if (!stix->vmprim.mod_getsym)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
sym = stix->vmprim.mod_getsym (stix, (void*)STIX_OOP_TO_SMOOI(hnd), ((stix_oop_char_t)fun)->slot);
|
|
if (!sym)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
ACTIVE_STACK_POPS (stix, 2);
|
|
/* TODO: how to hold an address? as an integer???? or a byte array? */
|
|
ACTIVE_STACK_SETTOP (stix, STIX_SMOOI_TO_OOP(sym));
|
|
|
|
return 1;
|
|
}
|
|
|
|
#define MAX_NARGS STIX_TYPE_MAX(stix_ooi_t)
|
|
struct prim_t
|
|
{
|
|
stix_ooi_t min_nargs; /* expected number of arguments */
|
|
stix_ooi_t max_nargs; /* expected number of arguments */
|
|
stix_prim_impl_t handler;
|
|
const char* name; /* the name is supposed to be 7-bit ascii only */
|
|
};
|
|
typedef struct prim_t prim_t;
|
|
|
|
static prim_t primitives[] =
|
|
{
|
|
{ 0, MAX_NARGS, prim_dump, "_dump" },
|
|
|
|
{ 1, 1, prim_identical, "_identical" },
|
|
{ 1, 1, prim_not_identical, "_not_identical" },
|
|
{ 0, 0, prim_class, "_class" },
|
|
|
|
{ 0, 0, prim_basic_new, "_basic_new" },
|
|
{ 1, 1, prim_basic_new_with_size, "_basic_new_with_size" },
|
|
{ 0, 0, prim_ngc_new, "_ngc_new" },
|
|
{ 1, 1, prim_ngc_new_with_size, "_ngc_new_with_size" },
|
|
{ 0, 0, prim_ngc_dispose, "_ngc_dispose" },
|
|
{ 0, 0, prim_shallow_copy, "_shallow_copy" },
|
|
|
|
{ 0, 0, prim_basic_size, "_basic_size" },
|
|
{ 1, 1, prim_basic_at, "_basic_at" },
|
|
{ 2, 2, prim_basic_at_put, "_basic_at_put" },
|
|
|
|
|
|
{ 0, MAX_NARGS, prim_block_value, "_block_value" },
|
|
{ 0, MAX_NARGS, prim_block_new_process, "_block_new_process" },
|
|
|
|
{ 0, 0, prim_process_resume, "_process_resume" },
|
|
{ 0, 0, prim_process_terminate, "_process_terminate" },
|
|
{ 0, 0, prim_process_yield, "_process_yield" },
|
|
{ 0, 0, prim_semaphore_signal, "_semaphore_signal" },
|
|
{ 0, 0, prim_semaphore_wait, "_semaphore_wait" },
|
|
|
|
{ 1, 1, prim_processor_schedule, "_processor_schedule" },
|
|
{ 1, 1, prim_processor_remove, "_processor_remove" },
|
|
{ 1, 1, prim_processor_sleep, "_processor_sleep" },
|
|
{ 2, 3, prim_processor_add_timed_semaphore, "_processor_add_timed_semaphore" },
|
|
|
|
{ 1, 1, prim_integer_add, "_integer_add" },
|
|
{ 1, 1, prim_integer_sub, "_integer_sub" },
|
|
{ 1, 1, prim_integer_mul, "_integer_mul" },
|
|
{ 1, 1, prim_integer_quo, "_integer_quo" },
|
|
{ 1, 1, prim_integer_rem, "_integer_rem" },
|
|
{ 1, 1, prim_integer_quo2, "_integer_quo2" },
|
|
{ 1, 1, prim_integer_rem2, "_integer_rem2" },
|
|
{ 0, 0, prim_integer_negated, "_integer_negated" },
|
|
{ 1, 1, prim_integer_bitat, "_integer_bitat" },
|
|
{ 1, 1, prim_integer_bitand, "_integer_bitand" },
|
|
{ 1, 1, prim_integer_bitor, "_integer_bitor" },
|
|
{ 1, 1, prim_integer_bitxor, "_integer_bitxor" },
|
|
{ 0, 0, prim_integer_bitinv, "_integer_bitinv" },
|
|
{ 1, 1, prim_integer_bitshift, "_integer_bitshift" },
|
|
{ 1, 1, prim_integer_eq, "_integer_eq" },
|
|
{ 1, 1, prim_integer_ne, "_integer_ne" },
|
|
{ 1, 1, prim_integer_lt, "_integer_lt" },
|
|
{ 1, 1, prim_integer_gt, "_integer_gt" },
|
|
{ 1, 1, prim_integer_le, "_integer_le" },
|
|
{ 1, 1, prim_integer_ge, "_integer_ge" },
|
|
{ 1, 1, prim_integer_inttostr, "_integer_inttostr" },
|
|
|
|
{ 1, 1, prim_ffi_open, "_ffi_open" },
|
|
{ 1, 1, prim_ffi_close, "_ffi_close" },
|
|
{ 2, 2, prim_ffi_getsym, "_ffi_getsym" },
|
|
{ 3, 3, prim_ffi_call, "_ffi_call" }
|
|
|
|
};
|
|
|
|
int stix_getprimno (stix_t* stix, const stix_oocs_t* name)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < STIX_COUNTOF(primitives); i++)
|
|
{
|
|
if (stix_compucxbcstr(name->ptr, name->len, primitives[i].name) == 0)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
stix->errnum = STIX_ENOENT;
|
|
return -1;
|
|
}
|
|
|
|
static stix_prim_impl_t query_prim_module (stix_t* stix, const stix_ooch_t* name, stix_oow_t len)
|
|
{
|
|
stix_rbt_pair_t* pair;
|
|
stix_prim_mod_data_t* mdp;
|
|
const stix_ooch_t* sep;
|
|
stix_oow_t mod_name_len;
|
|
stix_prim_impl_t handler;
|
|
int n;
|
|
|
|
sep = stix_findoochar (name, len, '_');
|
|
STIX_ASSERT (sep != STIX_NULL);
|
|
mod_name_len = sep - name;
|
|
|
|
pair = stix_rbt_search (&stix->pmtable, name, mod_name_len);
|
|
if (pair)
|
|
{
|
|
mdp = (stix_prim_mod_data_t*)STIX_RBT_VPTR(pair);
|
|
}
|
|
else
|
|
{
|
|
stix_prim_mod_data_t md;
|
|
stix_prim_mod_load_t load = STIX_NULL;
|
|
|
|
/* maximum module name length is STIX_MOD_NAME_LEN_MAX.
|
|
* 16 is decomposed to 14 + 1 + 1.
|
|
* 14 for stix_prim_mod_.
|
|
* 1 for _ at the end when stix_prim_mod_xxx_ is attempted.
|
|
* 1 for the terminating '\0'.
|
|
*/
|
|
stix_ooch_t buf[STIX_MOD_NAME_LEN_MAX + 16];
|
|
|
|
/* the terminating null isn't needed in buf here */
|
|
stix_copybchtooochars (buf, "stix_prim_mod_", 14);
|
|
|
|
if (mod_name_len > STIX_COUNTOF(buf) - 16)
|
|
{
|
|
/* module name too long */
|
|
stix->errnum = STIX_EINVAL; /* TODO: change the error number to something more specific */
|
|
return STIX_NULL;
|
|
}
|
|
|
|
stix_copyoochars (&buf[14], name, mod_name_len);
|
|
buf[14 + mod_name_len] = '\0';
|
|
|
|
#if defined(STIX_ENABLE_STATIC_MODULE)
|
|
/* attempt to find a statically linked module */
|
|
|
|
/*TODO: CHANGE THIS PART */
|
|
|
|
/* TODO: binary search ... */
|
|
for (n = 0; n < STIX_COUNTOF(static_modtab); n++)
|
|
{
|
|
if (stix_compoocstr (static_modtab[n].modname, name) == 0)
|
|
{
|
|
load = static_modtab[n].modload;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (n >= STIX_COUNTOF(static_modtab))
|
|
{
|
|
stix->errnum = STIX_ENOENT;
|
|
return STIX_NULL;
|
|
}
|
|
|
|
if (load)
|
|
{
|
|
/* found the module in the staic module table */
|
|
|
|
STIX_MEMSET (&md, 0, STIX_SIZEOF(md));
|
|
/* Note md.handle is STIX_NULL for a static module */
|
|
|
|
/* i copy-insert 'md' into the table before calling 'load'.
|
|
* to pass the same address to load(), query(), etc */
|
|
pair = stix_rbt_insert (stix->modtab, name, mod_name_len, &md, STIX_SIZEOF(md));
|
|
if (pair == STIX_NULL)
|
|
{
|
|
stix->errnum = STIX_ESYSMEM;
|
|
return STIX_NULL;
|
|
}
|
|
|
|
mdp = (stix_mod_data_t*)STIX_RBT_VPTR(pair);
|
|
if (load (&mdp->mod, stix) <= -1)
|
|
{
|
|
stix_rbt_delete (stix->modtab, segs[0].ptr, segs[0].len);
|
|
return STIX_NULL;
|
|
}
|
|
|
|
goto done;
|
|
}
|
|
#endif
|
|
|
|
/* attempt to find an external module */
|
|
STIX_MEMSET (&md, 0, STIX_SIZEOF(md));
|
|
if (stix->vmprim.mod_open && stix->vmprim.mod_getsym && stix->vmprim.mod_close)
|
|
{
|
|
md.handle = stix->vmprim.mod_open (stix, &buf[14]);
|
|
}
|
|
|
|
if (md.handle == STIX_NULL)
|
|
{
|
|
stix->errnum = STIX_ENOENT; /* TODO: be more descriptive about the error */
|
|
return STIX_NULL;
|
|
}
|
|
|
|
/* attempt to get stix_prim_mod_xxx */
|
|
load = stix->vmprim.mod_getsym (stix, md.handle, buf);
|
|
if (!load)
|
|
{
|
|
stix->errnum = STIX_ENOENT; /* TODO: be more descriptive about the error */
|
|
stix->vmprim.mod_close (stix, md.handle);
|
|
return STIX_NULL;
|
|
}
|
|
|
|
/* i copy-insert 'md' into the table before calling 'load'.
|
|
* to pass the same address to load(), query(), etc */
|
|
pair = stix_rbt_insert (&stix->pmtable, (void*)name, mod_name_len, &md, STIX_SIZEOF(md));
|
|
if (pair == STIX_NULL)
|
|
{
|
|
stix->errnum = STIX_ESYSMEM;
|
|
stix->vmprim.mod_close (stix, md.handle);
|
|
return STIX_NULL;
|
|
}
|
|
|
|
mdp = (stix_prim_mod_data_t*)STIX_RBT_VPTR(pair);
|
|
if (load (stix, &mdp->mod) <= -1)
|
|
{
|
|
stix->errnum = STIX_ENOENT; /* TODO: proper error code and handling */
|
|
stix_rbt_delete (&stix->pmtable, name, mod_name_len);
|
|
stix->vmprim.mod_close (stix, mdp->handle);
|
|
return STIX_NULL;
|
|
}
|
|
|
|
/* the module loader must ensure to set a proper query handler */
|
|
STIX_ASSERT (mdp->mod.query != STIX_NULL);
|
|
}
|
|
|
|
done:
|
|
if ((handler = mdp->mod.query (stix, &mdp->mod, sep + 1)) == STIX_NULL)
|
|
{
|
|
stix->errnum = STIX_ENOENT; /* TODO: proper error code and handling */
|
|
return STIX_NULL;
|
|
}
|
|
return handler;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
static int send_message (stix_t* stix, stix_oop_char_t selector, int to_super, stix_ooi_t nargs)
|
|
{
|
|
stix_oocs_t mthname;
|
|
stix_oop_t receiver;
|
|
stix_oop_method_t method;
|
|
stix_ooi_t preamble, preamble_code;
|
|
|
|
STIX_ASSERT (STIX_OOP_IS_POINTER(selector));
|
|
STIX_ASSERT (STIX_OBJ_GET_FLAGS_TYPE(selector) == STIX_OBJ_TYPE_CHAR);
|
|
STIX_ASSERT (STIX_CLASSOF(stix, selector) == stix->_symbol);
|
|
|
|
receiver = ACTIVE_STACK_GET(stix, stix->sp - nargs);
|
|
|
|
#if defined(STIX_DEBUG_EXEC_001)
|
|
printf (" RECEIVER = ");
|
|
print_object(stix, receiver);
|
|
printf ("\n");
|
|
#endif
|
|
|
|
mthname.ptr = selector->slot;
|
|
mthname.len = STIX_OBJ_GET_SIZE(selector);
|
|
method = find_method (stix, receiver, &mthname, to_super);
|
|
if (!method)
|
|
{
|
|
/* TODO: implement doesNotUnderstand: XXXXX instead of returning -1. */
|
|
stix_oop_t c;
|
|
|
|
c = STIX_CLASSOF(stix,receiver);
|
|
printf ("ERROR [NOT IMPLEMENTED YET] - receiver [");
|
|
print_object (stix, receiver);
|
|
printf ("] class ");
|
|
print_object (stix, c);
|
|
printf (" doesNotUnderstand: [");
|
|
print_oocs (&mthname);
|
|
printf ("]\n");
|
|
|
|
return -1;
|
|
}
|
|
|
|
STIX_ASSERT (STIX_OOP_TO_SMOOI(method->tmpr_nargs) == nargs);
|
|
|
|
preamble = STIX_OOP_TO_SMOOI(method->preamble);
|
|
preamble_code = STIX_METHOD_GET_PREAMBLE_CODE(preamble);
|
|
switch (preamble_code)
|
|
{
|
|
case STIX_METHOD_PREAMBLE_RETURN_RECEIVER:
|
|
DBGOUT_EXEC_0 ("METHOD_PREAMBLE_RETURN_RECEIVER");
|
|
ACTIVE_STACK_POPS (stix, nargs); /* pop arguments only*/
|
|
break;
|
|
|
|
case STIX_METHOD_PREAMBLE_RETURN_NIL:
|
|
DBGOUT_EXEC_0 ("METHOD_PREAMBLE_RETURN_NIL");
|
|
ACTIVE_STACK_POPS (stix, nargs);
|
|
ACTIVE_STACK_SETTOP (stix, stix->_nil);
|
|
break;
|
|
|
|
case STIX_METHOD_PREAMBLE_RETURN_TRUE:
|
|
DBGOUT_EXEC_0 ("METHOD_PREAMBLE_RETURN_TRUE");
|
|
ACTIVE_STACK_POPS (stix, nargs);
|
|
ACTIVE_STACK_SETTOP (stix, stix->_true);
|
|
break;
|
|
|
|
case STIX_METHOD_PREAMBLE_RETURN_FALSE:
|
|
DBGOUT_EXEC_0 ("METHOD_PREAMBLE_RETURN_FALSE");
|
|
ACTIVE_STACK_POPS (stix, nargs);
|
|
ACTIVE_STACK_SETTOP (stix, stix->_false);
|
|
break;
|
|
|
|
case STIX_METHOD_PREAMBLE_RETURN_INDEX:
|
|
DBGOUT_EXEC_1 ("METHOD_PREAMBLE_RETURN_INDEX %d", (int)STIX_METHOD_GET_PREAMBLE_INDEX(preamble));
|
|
ACTIVE_STACK_POPS (stix, nargs);
|
|
ACTIVE_STACK_SETTOP (stix, STIX_SMOOI_TO_OOP(STIX_METHOD_GET_PREAMBLE_INDEX(preamble)));
|
|
break;
|
|
|
|
case STIX_METHOD_PREAMBLE_RETURN_NEGINDEX:
|
|
DBGOUT_EXEC_1 ("METHOD_PREAMBLE_RETURN_NEGINDEX %d", (int)STIX_METHOD_GET_PREAMBLE_INDEX(preamble));
|
|
ACTIVE_STACK_POPS (stix, nargs);
|
|
ACTIVE_STACK_SETTOP (stix, STIX_SMOOI_TO_OOP(-STIX_METHOD_GET_PREAMBLE_INDEX(preamble)));
|
|
break;
|
|
|
|
case STIX_METHOD_PREAMBLE_RETURN_INSTVAR:
|
|
{
|
|
stix_oop_oop_t rcv;
|
|
|
|
ACTIVE_STACK_POPS (stix, nargs); /* pop arguments only */
|
|
|
|
DBGOUT_EXEC_1 ("METHOD_PREAMBLE_RETURN_INSTVAR %d", (int)STIX_METHOD_GET_PREAMBLE_INDEX(preamble));
|
|
|
|
/* replace the receiver by an instance variable of the receiver */
|
|
rcv = (stix_oop_oop_t)ACTIVE_STACK_GETTOP(stix);
|
|
STIX_ASSERT (STIX_OBJ_GET_FLAGS_TYPE(rcv) == STIX_OBJ_TYPE_OOP);
|
|
STIX_ASSERT (STIX_OBJ_GET_SIZE(rcv) > STIX_METHOD_GET_PREAMBLE_INDEX(preamble));
|
|
|
|
if (rcv == (stix_oop_oop_t)stix->active_context)
|
|
{
|
|
/* the active context object doesn't keep
|
|
* the most up-to-date information in the
|
|
* 'ip' and 'sp' field. commit these fields
|
|
* when the object to be accessed is
|
|
* the active context. this manual commit
|
|
* is required because this premable handling
|
|
* skips activation of a new method context
|
|
* that would commit these fields.
|
|
*/
|
|
STORE_ACTIVE_IP (stix);
|
|
STORE_ACTIVE_SP (stix);
|
|
}
|
|
|
|
/* this accesses the instance variable of the receiver */
|
|
ACTIVE_STACK_SET (stix, stix->sp, rcv->slot[STIX_METHOD_GET_PREAMBLE_INDEX(preamble)]);
|
|
break;
|
|
}
|
|
|
|
|
|
case STIX_METHOD_PREAMBLE_PRIMITIVE:
|
|
{
|
|
stix_ooi_t prim_no;
|
|
|
|
prim_no = STIX_METHOD_GET_PREAMBLE_INDEX(preamble);
|
|
DBGOUT_EXEC_1 ("METHOD_PREAMBLE_PRIMITIVE %d", (int)prim_no);
|
|
|
|
if (prim_no >= 0 && prim_no < STIX_COUNTOF(primitives) &&
|
|
(nargs >= primitives[prim_no].min_nargs && nargs <= primitives[prim_no].max_nargs))
|
|
{
|
|
int n;
|
|
|
|
stix_pushtmp (stix, (stix_oop_t*)&method);
|
|
n = primitives[prim_no].handler (stix, nargs);
|
|
stix_poptmp (stix);
|
|
if (n <= -1) return -1; /* hard primitive failure */
|
|
if (n >= 1) break; /* primitive ok */
|
|
}
|
|
|
|
/* soft primitive failure */
|
|
if (activate_new_method (stix, method) <= -1) return -1;
|
|
break;
|
|
}
|
|
|
|
case STIX_METHOD_PREAMBLE_NAMED_PRIMITIVE:
|
|
{
|
|
stix_ooi_t prim_name_index;
|
|
stix_oop_t name;
|
|
stix_prim_impl_t handler;
|
|
register stix_oow_t w;
|
|
|
|
prim_name_index = STIX_METHOD_GET_PREAMBLE_INDEX(preamble);
|
|
DBGOUT_EXEC_1 ("METHOD_PREAMBLE_NAMED_PRIMITIVE %d", (int)prim_name_index);
|
|
|
|
name = method->slot[prim_name_index];
|
|
|
|
STIX_ASSERT (STIX_ISTYPEOF(stix,name,STIX_OBJ_TYPE_CHAR));
|
|
STIX_ASSERT (STIX_OBJ_GET_FLAGS_EXTRA(name));
|
|
STIX_ASSERT (STIX_CLASSOF(stix,name) == stix->_symbol);
|
|
|
|
/* merge two SmallIntegers to get a full pointer */
|
|
w = (stix_oow_t)STIX_OOP_TO_SMOOI(method->preamble_data[0]) << (STIX_OOW_BITS / 2) |
|
|
(stix_oow_t)STIX_OOP_TO_SMOOI(method->preamble_data[1]);
|
|
handler = (stix_prim_impl_t)w;
|
|
if (!handler) handler = query_prim_module (stix, ((stix_oop_char_t)name)->slot, STIX_OBJ_GET_SIZE(name));
|
|
|
|
if (handler)
|
|
{
|
|
int n;
|
|
|
|
/* split a pointer to two OOP fields as SmallIntegers for storing. */
|
|
method->preamble_data[0] = STIX_SMOOI_TO_OOP((stix_oow_t)handler >> (STIX_OOW_BITS / 2));
|
|
method->preamble_data[1] = STIX_SMOOI_TO_OOP((stix_oow_t)handler & STIX_LBMASK(stix_oow_t, STIX_OOW_BITS / 2));
|
|
|
|
stix_pushtmp (stix, (stix_oop_t*)&method);
|
|
n = handler (stix, nargs);
|
|
stix_poptmp (stix);
|
|
if (n <= -1) return -1; /* hard primitive failure */
|
|
if (n >= 1) break; /* primitive ok*/
|
|
}
|
|
|
|
/* soft primitive failure or handler not found*/
|
|
if (activate_new_method (stix, method) <= -1) return -1;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
STIX_ASSERT (preamble_code == STIX_METHOD_PREAMBLE_NONE);
|
|
if (activate_new_method (stix, method) <= -1) return -1;
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
int stix_execute (stix_t* stix)
|
|
{
|
|
stix_oob_t bcode;
|
|
stix_ooi_t b1, b2;
|
|
stix_oop_t return_value;
|
|
|
|
#if defined(STIX_PROFILE_EXEC)
|
|
stix_oow_t inst_counter = 0;
|
|
#endif
|
|
|
|
STIX_ASSERT (stix->active_context != STIX_NULL);
|
|
|
|
stix->proc_switched = 0;
|
|
|
|
while (1)
|
|
{
|
|
if (stix->processor->active == stix->nil_process)
|
|
{
|
|
/* no more process in the system */
|
|
STIX_ASSERT (stix->processor->tally = STIX_SMOOI_TO_OOP(0));
|
|
printf ("NO MORE RUNNABLE PROCESS...\n");
|
|
|
|
|
|
if (stix->sem_heap_count > 0)
|
|
{
|
|
struct timespec now, ft;
|
|
|
|
clock_gettime (CLOCK_MONOTONIC, &now);
|
|
|
|
do
|
|
{
|
|
STIX_ASSERT (STIX_OOP_IS_SMOOI(stix->sem_heap[0]->heap_ftime_sec));
|
|
STIX_ASSERT (STIX_OOP_IS_SMOOI(stix->sem_heap[0]->heap_ftime_nsec));
|
|
|
|
ft.tv_sec = STIX_OOP_TO_SMOOI(stix->sem_heap[0]->heap_ftime_sec);
|
|
ft.tv_nsec = STIX_OOP_TO_SMOOI(stix->sem_heap[0]->heap_ftime_nsec);
|
|
|
|
if (ft.tv_sec < now.tv_sec || (ft.tv_sec == now.tv_sec && ft.tv_nsec <= now.tv_nsec))
|
|
{
|
|
signal_semaphore (stix, stix->sem_heap[0]);
|
|
delete_from_sem_heap (stix, 0);
|
|
}
|
|
else
|
|
{
|
|
stix_oop_process_t proc;
|
|
|
|
/* THIS PART IS JUST EXPERIMENTAL... PROPER WAITING WITH IO MULTIPLEXER IS NEEDED ... */
|
|
sleep (ft.tv_sec - now.tv_sec);
|
|
|
|
proc = stix->sem_heap[0]->waiting_head;
|
|
|
|
signal_semaphore (stix, stix->sem_heap[0]);
|
|
delete_from_sem_heap (stix, 0);
|
|
|
|
STIX_ASSERT (proc->state == STIX_SMOOI_TO_OOP(PROC_STATE_RUNNABLE));
|
|
STIX_ASSERT (proc == stix->processor->runnable_head);
|
|
|
|
wake_new_process (stix, proc);
|
|
stix->proc_switched = 1;
|
|
|
|
goto carry_on_switching;
|
|
}
|
|
}
|
|
while (stix->sem_heap_count > 0);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
carry_on_switching:
|
|
/*
|
|
else if (stix->processor->active == stix->idle_process)
|
|
{
|
|
IDLEING WAITING FOR PROCESS WAKE-UP...
|
|
}
|
|
*/
|
|
|
|
while (stix->sem_list_count > 0)
|
|
{
|
|
/* handle async signals */
|
|
--stix->sem_list_count;
|
|
signal_semaphore (stix, stix->sem_list[stix->sem_list_count]);
|
|
}
|
|
/*
|
|
if (semaphore heap has pending request)
|
|
{
|
|
signal them...
|
|
}*/
|
|
|
|
/* TODO: implement different process switching scheme - time-slice or clock based??? */
|
|
if (!stix->proc_switched) { switch_to_next_runnable_process (stix); }
|
|
stix->proc_switched = 0;
|
|
|
|
FETCH_BYTE_CODE_TO (stix, bcode);
|
|
/*while (bcode == BCODE_NOOP) FETCH_BYTE_CODE_TO (stix, bcode);*/
|
|
|
|
#if 0
|
|
printf ("BCODE = %x\n", bcode);
|
|
#endif
|
|
|
|
#if defined(STIX_PROFILE_EXEC)
|
|
inst_counter++;
|
|
#endif
|
|
|
|
switch (bcode)
|
|
{
|
|
/* ------------------------------------------------- */
|
|
|
|
case BCODE_PUSH_INSTVAR_X:
|
|
FETCH_PARAM_CODE_TO (stix, b1);
|
|
goto push_instvar;
|
|
case BCODE_PUSH_INSTVAR_0:
|
|
case BCODE_PUSH_INSTVAR_1:
|
|
case BCODE_PUSH_INSTVAR_2:
|
|
case BCODE_PUSH_INSTVAR_3:
|
|
case BCODE_PUSH_INSTVAR_4:
|
|
case BCODE_PUSH_INSTVAR_5:
|
|
case BCODE_PUSH_INSTVAR_6:
|
|
case BCODE_PUSH_INSTVAR_7:
|
|
b1 = bcode & 0x7; /* low 3 bits */
|
|
push_instvar:
|
|
DBGOUT_EXEC_1 ("PUSH_INSTVAR %d", (int)b1);
|
|
STIX_ASSERT (STIX_OBJ_GET_FLAGS_TYPE(stix->active_context->origin->receiver_or_source) == STIX_OBJ_TYPE_OOP);
|
|
ACTIVE_STACK_PUSH (stix, ((stix_oop_oop_t)stix->active_context->origin->receiver_or_source)->slot[b1]);
|
|
break;
|
|
|
|
/* ------------------------------------------------- */
|
|
|
|
case BCODE_STORE_INTO_INSTVAR_X:
|
|
FETCH_PARAM_CODE_TO (stix, b1);
|
|
goto store_instvar;
|
|
case BCODE_STORE_INTO_INSTVAR_0:
|
|
case BCODE_STORE_INTO_INSTVAR_1:
|
|
case BCODE_STORE_INTO_INSTVAR_2:
|
|
case BCODE_STORE_INTO_INSTVAR_3:
|
|
case BCODE_STORE_INTO_INSTVAR_4:
|
|
case BCODE_STORE_INTO_INSTVAR_5:
|
|
case BCODE_STORE_INTO_INSTVAR_6:
|
|
case BCODE_STORE_INTO_INSTVAR_7:
|
|
b1 = bcode & 0x7; /* low 3 bits */
|
|
store_instvar:
|
|
DBGOUT_EXEC_1 ("STORE_INTO_INSTVAR %d", (int)b1);
|
|
STIX_ASSERT (STIX_OBJ_GET_FLAGS_TYPE(stix->active_context->receiver_or_source) == STIX_OBJ_TYPE_OOP);
|
|
((stix_oop_oop_t)stix->active_context->origin->receiver_or_source)->slot[b1] = ACTIVE_STACK_GETTOP(stix);
|
|
break;
|
|
|
|
/* ------------------------------------------------- */
|
|
case BCODE_POP_INTO_INSTVAR_X:
|
|
FETCH_PARAM_CODE_TO (stix, b1);
|
|
goto pop_into_instvar;
|
|
case BCODE_POP_INTO_INSTVAR_0:
|
|
case BCODE_POP_INTO_INSTVAR_1:
|
|
case BCODE_POP_INTO_INSTVAR_2:
|
|
case BCODE_POP_INTO_INSTVAR_3:
|
|
case BCODE_POP_INTO_INSTVAR_4:
|
|
case BCODE_POP_INTO_INSTVAR_5:
|
|
case BCODE_POP_INTO_INSTVAR_6:
|
|
case BCODE_POP_INTO_INSTVAR_7:
|
|
b1 = bcode & 0x7; /* low 3 bits */
|
|
pop_into_instvar:
|
|
DBGOUT_EXEC_1 ("POP_INTO_INSTVAR %d", (int)b1);
|
|
STIX_ASSERT (STIX_OBJ_GET_FLAGS_TYPE(stix->active_context->receiver_or_source) == STIX_OBJ_TYPE_OOP);
|
|
((stix_oop_oop_t)stix->active_context->origin->receiver_or_source)->slot[b1] = ACTIVE_STACK_GETTOP(stix);
|
|
ACTIVE_STACK_POP (stix);
|
|
break;
|
|
|
|
/* ------------------------------------------------- */
|
|
case BCODE_PUSH_TEMPVAR_X:
|
|
case BCODE_STORE_INTO_TEMPVAR_X:
|
|
case BCODE_POP_INTO_TEMPVAR_X:
|
|
FETCH_PARAM_CODE_TO (stix, b1);
|
|
goto handle_tempvar;
|
|
|
|
case BCODE_PUSH_TEMPVAR_0:
|
|
case BCODE_PUSH_TEMPVAR_1:
|
|
case BCODE_PUSH_TEMPVAR_2:
|
|
case BCODE_PUSH_TEMPVAR_3:
|
|
case BCODE_PUSH_TEMPVAR_4:
|
|
case BCODE_PUSH_TEMPVAR_5:
|
|
case BCODE_PUSH_TEMPVAR_6:
|
|
case BCODE_PUSH_TEMPVAR_7:
|
|
case BCODE_STORE_INTO_TEMPVAR_0:
|
|
case BCODE_STORE_INTO_TEMPVAR_1:
|
|
case BCODE_STORE_INTO_TEMPVAR_2:
|
|
case BCODE_STORE_INTO_TEMPVAR_3:
|
|
case BCODE_STORE_INTO_TEMPVAR_4:
|
|
case BCODE_STORE_INTO_TEMPVAR_5:
|
|
case BCODE_STORE_INTO_TEMPVAR_6:
|
|
case BCODE_STORE_INTO_TEMPVAR_7:
|
|
case BCODE_POP_INTO_TEMPVAR_0:
|
|
case BCODE_POP_INTO_TEMPVAR_1:
|
|
case BCODE_POP_INTO_TEMPVAR_2:
|
|
case BCODE_POP_INTO_TEMPVAR_3:
|
|
case BCODE_POP_INTO_TEMPVAR_4:
|
|
case BCODE_POP_INTO_TEMPVAR_5:
|
|
case BCODE_POP_INTO_TEMPVAR_6:
|
|
case BCODE_POP_INTO_TEMPVAR_7:
|
|
{
|
|
stix_oop_context_t ctx;
|
|
stix_ooi_t bx;
|
|
|
|
b1 = bcode & 0x7; /* low 3 bits */
|
|
handle_tempvar:
|
|
|
|
#if defined(STIX_USE_CTXTEMPVAR)
|
|
/* when CTXTEMPVAR inststructions are used, the above
|
|
* instructions are used only for temporary access
|
|
* outside a block. i can assume that the temporary
|
|
* variable index is pointing to one of temporaries
|
|
* in the relevant method context */
|
|
ctx = stix->active_context->origin;
|
|
bx = b1;
|
|
STIX_ASSERT (STIX_CLASSOF(stix, ctx) == stix->_method_context);
|
|
#else
|
|
/* otherwise, the index may point to a temporaries
|
|
* declared inside a block */
|
|
|
|
if (stix->active_context->home != stix->_nil)
|
|
{
|
|
/* this code assumes that the method context and
|
|
* the block context place some key fields in the
|
|
* same offset. such fields include 'home', 'ntmprs' */
|
|
stix_oop_t home;
|
|
stix_ooi_t home_ntmprs;
|
|
|
|
ctx = stix->active_context;
|
|
home = ctx->home;
|
|
|
|
do
|
|
{
|
|
/* ntmprs contains the number of defined temporaries
|
|
* including those defined in the home context */
|
|
home_ntmprs = STIX_OOP_TO_SMOOI(((stix_oop_context_t)home)->ntmprs);
|
|
if (b1 >= home_ntmprs) break;
|
|
|
|
ctx = (stix_oop_context_t)home;
|
|
home = ((stix_oop_context_t)home)->home;
|
|
if (home == stix->_nil)
|
|
{
|
|
home_ntmprs = 0;
|
|
break;
|
|
}
|
|
}
|
|
while (1);
|
|
|
|
/* bx is the actual index within the actual context
|
|
* containing the temporary */
|
|
bx = b1 - home_ntmprs;
|
|
}
|
|
else
|
|
{
|
|
ctx = stix->active_context;
|
|
bx = b1;
|
|
}
|
|
#endif
|
|
|
|
if ((bcode >> 4) & 1)
|
|
{
|
|
/* push - bit 4 on */
|
|
DBGOUT_EXEC_1 ("PUSH_TEMPVAR %d", (int)b1);
|
|
ACTIVE_STACK_PUSH (stix, ctx->slot[bx]);
|
|
}
|
|
else
|
|
{
|
|
/* store or pop - bit 5 off */
|
|
ctx->slot[bx] = ACTIVE_STACK_GETTOP(stix);
|
|
|
|
if ((bcode >> 3) & 1)
|
|
{
|
|
/* pop - bit 3 on */
|
|
DBGOUT_EXEC_1 ("POP_INTO_TEMPVAR %d", (int)b1);
|
|
ACTIVE_STACK_POP (stix);
|
|
}
|
|
else
|
|
{
|
|
DBGOUT_EXEC_1 ("STORE_INTO_TEMPVAR %d", (int)b1);
|
|
}
|
|
}
|
|
/*
|
|
print_object (stix, ctx->slot[bx]);
|
|
printf ("\n");
|
|
*/
|
|
break;
|
|
}
|
|
|
|
/* ------------------------------------------------- */
|
|
case BCODE_PUSH_LITERAL_X:
|
|
FETCH_PARAM_CODE_TO (stix, b1);
|
|
goto push_literal;
|
|
|
|
case BCODE_PUSH_LITERAL_0:
|
|
case BCODE_PUSH_LITERAL_1:
|
|
case BCODE_PUSH_LITERAL_2:
|
|
case BCODE_PUSH_LITERAL_3:
|
|
case BCODE_PUSH_LITERAL_4:
|
|
case BCODE_PUSH_LITERAL_5:
|
|
case BCODE_PUSH_LITERAL_6:
|
|
case BCODE_PUSH_LITERAL_7:
|
|
b1 = bcode & 0x7; /* low 3 bits */
|
|
push_literal:
|
|
DBGOUT_EXEC_1 ("PUSH_LITERAL %d", (int)b1);
|
|
/*
|
|
print_object (stix, stix->active_method->slot[b1]);
|
|
printf ("\n");
|
|
*/
|
|
ACTIVE_STACK_PUSH (stix, stix->active_method->slot[b1]);
|
|
break;
|
|
|
|
/* ------------------------------------------------- */
|
|
case BCODE_PUSH_OBJECT_X:
|
|
case BCODE_STORE_INTO_OBJECT_X:
|
|
case BCODE_POP_INTO_OBJECT_X:
|
|
FETCH_PARAM_CODE_TO (stix, b1);
|
|
goto handle_object;
|
|
|
|
case BCODE_PUSH_OBJECT_0:
|
|
case BCODE_PUSH_OBJECT_1:
|
|
case BCODE_PUSH_OBJECT_2:
|
|
case BCODE_PUSH_OBJECT_3:
|
|
case BCODE_STORE_INTO_OBJECT_0:
|
|
case BCODE_STORE_INTO_OBJECT_1:
|
|
case BCODE_STORE_INTO_OBJECT_2:
|
|
case BCODE_STORE_INTO_OBJECT_3:
|
|
case BCODE_POP_INTO_OBJECT_0:
|
|
case BCODE_POP_INTO_OBJECT_1:
|
|
case BCODE_POP_INTO_OBJECT_2:
|
|
case BCODE_POP_INTO_OBJECT_3:
|
|
{
|
|
stix_oop_association_t ass;
|
|
|
|
b1 = bcode & 0x3; /* low 2 bits */
|
|
handle_object:
|
|
ass = (stix_oop_association_t)stix->active_method->slot[b1];
|
|
STIX_ASSERT (STIX_CLASSOF(stix, ass) == stix->_association);
|
|
|
|
if ((bcode >> 3) & 1)
|
|
{
|
|
/* store or pop */
|
|
ass->value = ACTIVE_STACK_GETTOP(stix);
|
|
|
|
if ((bcode >> 2) & 1)
|
|
{
|
|
/* pop */
|
|
DBGOUT_EXEC_1("POP_INTO_OBJECT %d", (int)b1);
|
|
ACTIVE_STACK_POP (stix);
|
|
}
|
|
else
|
|
{
|
|
DBGOUT_EXEC_1("STORE_INTO_OBJECT %d", (int)b1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* push */
|
|
DBGOUT_EXEC_1("PUSH_OBJECT %d", (int)b1);
|
|
ACTIVE_STACK_PUSH (stix, ass->value);
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* -------------------------------------------------------- */
|
|
|
|
case BCODE_JUMP_FORWARD_X:
|
|
FETCH_PARAM_CODE_TO (stix, b1);
|
|
DBGOUT_EXEC_1 ("JUMP_FORWARD %d", (int)b1);
|
|
stix->ip += b1;
|
|
break;
|
|
|
|
case BCODE_JUMP_FORWARD_0:
|
|
case BCODE_JUMP_FORWARD_1:
|
|
case BCODE_JUMP_FORWARD_2:
|
|
case BCODE_JUMP_FORWARD_3:
|
|
DBGOUT_EXEC_1 ("JUMP_FORWARD %d", (int)(bcode & 0x3));
|
|
stix->ip += (bcode & 0x3); /* low 2 bits */
|
|
break;
|
|
|
|
case BCODE_JUMP_BACKWARD_X:
|
|
FETCH_PARAM_CODE_TO (stix, b1);
|
|
DBGOUT_EXEC_1 ("JUMP_BACKWARD %d", (int)b1);
|
|
stix->ip += b1;
|
|
break;
|
|
|
|
case BCODE_JUMP_BACKWARD_0:
|
|
case BCODE_JUMP_BACKWARD_1:
|
|
case BCODE_JUMP_BACKWARD_2:
|
|
case BCODE_JUMP_BACKWARD_3:
|
|
DBGOUT_EXEC_1 ("JUMP_BACKWARD %d", (int)(bcode & 0x3));
|
|
stix->ip -= (bcode & 0x3); /* low 2 bits */
|
|
break;
|
|
|
|
case BCODE_JUMP_IF_TRUE_X:
|
|
case BCODE_JUMP_IF_FALSE_X:
|
|
case BCODE_JUMP_IF_TRUE_0:
|
|
case BCODE_JUMP_IF_TRUE_1:
|
|
case BCODE_JUMP_IF_TRUE_2:
|
|
case BCODE_JUMP_IF_TRUE_3:
|
|
case BCODE_JUMP_IF_FALSE_0:
|
|
case BCODE_JUMP_IF_FALSE_1:
|
|
case BCODE_JUMP_IF_FALSE_2:
|
|
case BCODE_JUMP_IF_FALSE_3:
|
|
printf ("<<<<<<<<<<<<<< JUMP NOT IMPLEMENTED YET >>>>>>>>>>>> \n");
|
|
stix->errnum = STIX_ENOIMPL;
|
|
return -1;
|
|
|
|
case BCODE_JUMP2_FORWARD:
|
|
FETCH_PARAM_CODE_TO (stix, b1);
|
|
DBGOUT_EXEC_1 ("JUMP2_FORWARD %d", (int)b1);
|
|
stix->ip += MAX_CODE_JUMP + b1;
|
|
break;
|
|
break;
|
|
|
|
case BCODE_JUMP2_BACKWARD:
|
|
FETCH_PARAM_CODE_TO (stix, b1);
|
|
DBGOUT_EXEC_1 ("JUMP2_BACKWARD %d", (int)b1);
|
|
stix->ip -= MAX_CODE_JUMP + b1;
|
|
break;
|
|
|
|
/* -------------------------------------------------------- */
|
|
|
|
case BCODE_PUSH_CTXTEMPVAR_X:
|
|
case BCODE_STORE_INTO_CTXTEMPVAR_X:
|
|
case BCODE_POP_INTO_CTXTEMPVAR_X:
|
|
FETCH_PARAM_CODE_TO (stix, b1);
|
|
FETCH_PARAM_CODE_TO (stix, b2);
|
|
goto handle_ctxtempvar;
|
|
case BCODE_PUSH_CTXTEMPVAR_0:
|
|
case BCODE_PUSH_CTXTEMPVAR_1:
|
|
case BCODE_PUSH_CTXTEMPVAR_2:
|
|
case BCODE_PUSH_CTXTEMPVAR_3:
|
|
case BCODE_STORE_INTO_CTXTEMPVAR_0:
|
|
case BCODE_STORE_INTO_CTXTEMPVAR_1:
|
|
case BCODE_STORE_INTO_CTXTEMPVAR_2:
|
|
case BCODE_STORE_INTO_CTXTEMPVAR_3:
|
|
case BCODE_POP_INTO_CTXTEMPVAR_0:
|
|
case BCODE_POP_INTO_CTXTEMPVAR_1:
|
|
case BCODE_POP_INTO_CTXTEMPVAR_2:
|
|
case BCODE_POP_INTO_CTXTEMPVAR_3:
|
|
{
|
|
stix_ooi_t i;
|
|
stix_oop_context_t ctx;
|
|
|
|
b1 = bcode & 0x3; /* low 2 bits */
|
|
FETCH_BYTE_CODE_TO (stix, b2);
|
|
|
|
handle_ctxtempvar:
|
|
|
|
ctx = stix->active_context;
|
|
STIX_ASSERT ((stix_oop_t)ctx != stix->_nil);
|
|
for (i = 0; i < b1; i++)
|
|
{
|
|
ctx = (stix_oop_context_t)ctx->home;
|
|
}
|
|
|
|
if ((bcode >> 3) & 1)
|
|
{
|
|
/* store or pop */
|
|
ctx->slot[b2] = ACTIVE_STACK_GETTOP(stix);
|
|
|
|
if ((bcode >> 2) & 1)
|
|
{
|
|
/* pop */
|
|
ACTIVE_STACK_POP (stix);
|
|
DBGOUT_EXEC_2 ("POP_INTO_CTXTEMPVAR %d %d", (int)b1, (int)b2);
|
|
}
|
|
else
|
|
{
|
|
DBGOUT_EXEC_2 ("STORE_INTO_CTXTEMPVAR %d %d", (int)b1, (int)b2);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* push */
|
|
ACTIVE_STACK_PUSH (stix, ctx->slot[b2]);
|
|
DBGOUT_EXEC_2 ("PUSH_CTXTEMPVAR %d %d", (int)b1, (int)b2);
|
|
}
|
|
/*
|
|
print_object (stix, ctx->slot[b2]);
|
|
printf ("\n");
|
|
*/
|
|
|
|
break;
|
|
}
|
|
/* -------------------------------------------------------- */
|
|
|
|
case BCODE_PUSH_OBJVAR_X:
|
|
case BCODE_STORE_INTO_OBJVAR_X:
|
|
case BCODE_POP_INTO_OBJVAR_X:
|
|
FETCH_PARAM_CODE_TO (stix, b1);
|
|
FETCH_PARAM_CODE_TO (stix, b2);
|
|
goto handle_objvar;
|
|
|
|
case BCODE_PUSH_OBJVAR_0:
|
|
case BCODE_PUSH_OBJVAR_1:
|
|
case BCODE_PUSH_OBJVAR_2:
|
|
case BCODE_PUSH_OBJVAR_3:
|
|
case BCODE_STORE_INTO_OBJVAR_0:
|
|
case BCODE_STORE_INTO_OBJVAR_1:
|
|
case BCODE_STORE_INTO_OBJVAR_2:
|
|
case BCODE_STORE_INTO_OBJVAR_3:
|
|
case BCODE_POP_INTO_OBJVAR_0:
|
|
case BCODE_POP_INTO_OBJVAR_1:
|
|
case BCODE_POP_INTO_OBJVAR_2:
|
|
case BCODE_POP_INTO_OBJVAR_3:
|
|
{
|
|
stix_oop_oop_t t;
|
|
|
|
/* b1 -> variable index to the object indicated by b2.
|
|
* b2 -> object index stored in the literal frame. */
|
|
b1 = bcode & 0x3; /* low 2 bits */
|
|
FETCH_BYTE_CODE_TO (stix, b2);
|
|
|
|
handle_objvar:
|
|
t = (stix_oop_oop_t)stix->active_method->slot[b2];
|
|
STIX_ASSERT (STIX_OBJ_GET_FLAGS_TYPE(t) == STIX_OBJ_TYPE_OOP);
|
|
STIX_ASSERT (b1 < STIX_OBJ_GET_SIZE(t));
|
|
|
|
if ((bcode >> 3) & 1)
|
|
{
|
|
/* store or pop */
|
|
|
|
t->slot[b1] = ACTIVE_STACK_GETTOP(stix);
|
|
|
|
if ((bcode >> 2) & 1)
|
|
{
|
|
/* pop */
|
|
ACTIVE_STACK_POP (stix);
|
|
DBGOUT_EXEC_2 ("POP_INTO_OBJVAR %d %d", (int)b1, (int)b2);
|
|
}
|
|
else
|
|
{
|
|
DBGOUT_EXEC_2 ("STORE_INTO_OBJVAR %d %d", (int)b1, (int)b2);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* push */
|
|
DBGOUT_EXEC_2 ("PUSH_OBJVAR %d %d", (int)b1, (int)b2);
|
|
ACTIVE_STACK_PUSH (stix, t->slot[b1]);
|
|
}
|
|
/*
|
|
print_object (stix, t->slot[b1]);
|
|
printf ("\n");
|
|
*/
|
|
break;
|
|
}
|
|
|
|
/* -------------------------------------------------------- */
|
|
case BCODE_SEND_MESSAGE_X:
|
|
case BCODE_SEND_MESSAGE_TO_SUPER_X:
|
|
/* b1 -> number of arguments
|
|
* b2 -> selector index stored in the literal frame */
|
|
FETCH_PARAM_CODE_TO (stix, b1);
|
|
FETCH_PARAM_CODE_TO (stix, b2);
|
|
goto handle_send_message;
|
|
|
|
case BCODE_SEND_MESSAGE_0:
|
|
case BCODE_SEND_MESSAGE_1:
|
|
case BCODE_SEND_MESSAGE_2:
|
|
case BCODE_SEND_MESSAGE_3:
|
|
case BCODE_SEND_MESSAGE_TO_SUPER_0:
|
|
case BCODE_SEND_MESSAGE_TO_SUPER_1:
|
|
case BCODE_SEND_MESSAGE_TO_SUPER_2:
|
|
case BCODE_SEND_MESSAGE_TO_SUPER_3:
|
|
{
|
|
stix_oop_char_t selector;
|
|
|
|
b1 = bcode & 0x3; /* low 2 bits */
|
|
FETCH_BYTE_CODE_TO (stix, b2);
|
|
|
|
handle_send_message:
|
|
/* get the selector from the literal frame */
|
|
selector = (stix_oop_char_t)stix->active_method->slot[b2];
|
|
|
|
#if defined(STIX_DEBUG_EXEC_001)
|
|
printf ("SEND_MESSAGE%s TO RECEIVER AT STACKPOS=%d NARGS=%d SELECTOR=", (((bcode >> 2) & 1)? "_TO_SUPER": ""), (int)(stix->sp - b1), (int)b1);
|
|
print_object (stix, (stix_oop_t)selector);
|
|
fflush (stdout);
|
|
#endif
|
|
if (send_message (stix, selector, ((bcode >> 2) & 1), b1) <= -1) goto oops;
|
|
break; /* CMD_SEND_MESSAGE */
|
|
}
|
|
|
|
/* -------------------------------------------------------- */
|
|
|
|
case BCODE_PUSH_RECEIVER:
|
|
DBGOUT_EXEC_0 ("PUSH_RECEIVER");
|
|
ACTIVE_STACK_PUSH (stix, stix->active_context->origin->receiver_or_source);
|
|
break;
|
|
|
|
case BCODE_PUSH_NIL:
|
|
DBGOUT_EXEC_0 ("PUSH_NIL");
|
|
ACTIVE_STACK_PUSH (stix, stix->_nil);
|
|
break;
|
|
|
|
case BCODE_PUSH_TRUE:
|
|
DBGOUT_EXEC_0 ("PUSH_TRUE");
|
|
ACTIVE_STACK_PUSH (stix, stix->_true);
|
|
break;
|
|
|
|
case BCODE_PUSH_FALSE:
|
|
DBGOUT_EXEC_0 ("PUSH_FALSE");
|
|
ACTIVE_STACK_PUSH (stix, stix->_false);
|
|
break;
|
|
|
|
case BCODE_PUSH_CONTEXT:
|
|
DBGOUT_EXEC_0 ("PUSH_CONTEXT");
|
|
ACTIVE_STACK_PUSH (stix, (stix_oop_t)stix->active_context);
|
|
break;
|
|
|
|
case BCODE_PUSH_NEGONE:
|
|
DBGOUT_EXEC_0 ("PUSH_NEGONE");
|
|
ACTIVE_STACK_PUSH (stix, STIX_SMOOI_TO_OOP(-1));
|
|
break;
|
|
|
|
case BCODE_PUSH_ZERO:
|
|
DBGOUT_EXEC_0 ("PUSH_ZERO");
|
|
ACTIVE_STACK_PUSH (stix, STIX_SMOOI_TO_OOP(0));
|
|
break;
|
|
|
|
case BCODE_PUSH_ONE:
|
|
DBGOUT_EXEC_0 ("PUSH_ONE");
|
|
ACTIVE_STACK_PUSH (stix, STIX_SMOOI_TO_OOP(1));
|
|
break;
|
|
|
|
case BCODE_PUSH_TWO:
|
|
DBGOUT_EXEC_0 ("PUSH_TWO");
|
|
ACTIVE_STACK_PUSH (stix, STIX_SMOOI_TO_OOP(2));
|
|
break;
|
|
|
|
case BCODE_PUSH_INTLIT:
|
|
FETCH_PARAM_CODE_TO (stix, b1);
|
|
DBGOUT_EXEC_1 ("PUSH_INTLIT %d", (int)b1);
|
|
ACTIVE_STACK_PUSH (stix, STIX_SMOOI_TO_OOP(b1));
|
|
break;
|
|
|
|
case BCODE_PUSH_NEGINTLIT:
|
|
FETCH_PARAM_CODE_TO (stix, b1);
|
|
DBGOUT_EXEC_1 ("PUSH_NEGINTLIT %d", (int)-b1);
|
|
ACTIVE_STACK_PUSH (stix, STIX_SMOOI_TO_OOP(-b1));
|
|
break;
|
|
|
|
/* -------------------------------------------------------- */
|
|
|
|
case BCODE_DUP_STACKTOP:
|
|
{
|
|
stix_oop_t t;
|
|
DBGOUT_EXEC_0 ("DUP_STACKTOP");
|
|
STIX_ASSERT (!ACTIVE_STACK_ISEMPTY(stix));
|
|
t = ACTIVE_STACK_GETTOP(stix);
|
|
ACTIVE_STACK_PUSH (stix, t);
|
|
break;
|
|
}
|
|
|
|
case BCODE_POP_STACKTOP:
|
|
DBGOUT_EXEC_0 ("POP_STACKTOP");
|
|
STIX_ASSERT (!ACTIVE_STACK_ISEMPTY(stix));
|
|
ACTIVE_STACK_POP (stix);
|
|
break;
|
|
|
|
case BCODE_RETURN_STACKTOP:
|
|
DBGOUT_EXEC_0 ("RETURN_STACKTOP");
|
|
return_value = ACTIVE_STACK_GETTOP(stix);
|
|
ACTIVE_STACK_POP (stix);
|
|
goto handle_return;
|
|
|
|
case BCODE_RETURN_RECEIVER:
|
|
DBGOUT_EXEC_0 ("RETURN_RECEIVER");
|
|
return_value = stix->active_context->origin->receiver_or_source;
|
|
|
|
handle_return:
|
|
#if defined(STIX_DEBUG_EXEC_001)
|
|
printf ("<<LEAVING>> SP=%d\n", (int)stix->sp);
|
|
#endif
|
|
|
|
#if 0
|
|
/* put the instruction pointer back to the return
|
|
* instruction (RETURN_RECEIVER or RETURN_RECEIVER)
|
|
* if a context returns into this context again,
|
|
* it'll be able to return as well again.
|
|
*
|
|
* Consider a program like this:
|
|
*
|
|
* #class MyObject(Object)
|
|
* {
|
|
* #declare(#classinst) t1 t2.
|
|
* #method(#class) xxxx
|
|
* {
|
|
* | g1 g2 |
|
|
* t1 dump.
|
|
* t2 := [ g1 := 50. g2 := 100. ^g1 + g2 ].
|
|
* (t1 < 100) ifFalse: [ ^self ].
|
|
* t1 := t1 + 1.
|
|
* ^self xxxx.
|
|
* }
|
|
* #method(#class) main
|
|
* {
|
|
* t1 := 1.
|
|
* self xxxx.
|
|
* t2 := t2 value.
|
|
* t2 dump.
|
|
* }
|
|
* }
|
|
*
|
|
* the 'xxxx' method invoked by 'self xxxx' has
|
|
* returned even before 't2 value' is executed.
|
|
* the '^' operator makes the active context to
|
|
* switch to its 'origin->sender' which is the
|
|
* method context of 'xxxx' itself. placing its
|
|
* instruction pointer at the 'return' instruction
|
|
* helps execute another return when the switching
|
|
* occurs.
|
|
*
|
|
* TODO: verify if this really works
|
|
*
|
|
*/
|
|
stix->ip--;
|
|
#else
|
|
if (stix->active_context->origin == stix->processor->active->initial_context->origin)
|
|
{
|
|
/* method return from a processified block
|
|
*
|
|
* #method(#class) main
|
|
* {
|
|
* [^100] newProcess resume.
|
|
* '1111' dump.
|
|
* '1111' dump.
|
|
* '1111' dump.
|
|
* ^300.
|
|
* }
|
|
*
|
|
* ^100 doesn't terminate a main process as the block
|
|
* has been processified. on the other hand, ^100
|
|
* in the following program causes main to exit.
|
|
*
|
|
* #method(#class) main
|
|
* {
|
|
* [^100] value.
|
|
* '1111' dump.
|
|
* '1111' dump.
|
|
* '1111' dump.
|
|
* ^300.
|
|
* }
|
|
*/
|
|
|
|
STIX_ASSERT (STIX_CLASSOF(stix, stix->active_context) == stix->_block_context);
|
|
STIX_ASSERT (STIX_CLASSOF(stix, stix->processor->active->initial_context) == stix->_block_context);
|
|
|
|
/* place the instruction pointer back at the return instruction.
|
|
* even if the context is reentered, it will just return.
|
|
*stix->ip--;*/
|
|
|
|
|
|
#if defined(STIX_DEBUG_EXEC_002)
|
|
printf ("TERMINATING A PROCESS RETURNING old_active context %p\n", stix->active_context);
|
|
#endif
|
|
terminate_process (stix, stix->processor->active);
|
|
#if defined(STIX_DEBUG_EXEC_002)
|
|
printf ("TERMINATED A PROCESS RETURNING %lld new active_context %p\n", (long long int)stix->ip, stix->active_context);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
if (stix->active_context->origin->ip == STIX_SMOOI_TO_OOP(STIX_SMOOI_MIN))
|
|
{
|
|
printf ("ERROR: CAN'T RETURN FROM DEAD METHOD CONTEXT orgin->ip %ld origin->sender->ip %ld\n",
|
|
(long int)STIX_OOP_TO_SMOOI(stix->active_context->origin->ip), (long int)STIX_OOP_TO_SMOOI(stix->active_context->origin->sender->ip));
|
|
printf ("ERROR: CAN'T RETURN FROM DEAD METHOD CONTEXT origin %p origin->sender %p\n", stix->active_context->origin, stix->active_context->origin->sender);
|
|
printf ("ERROR: CAN'T RETURN FROM DEAD METHOD CONTEXT\n");
|
|
|
|
/* TODO: proper error handling */
|
|
stix->errnum = STIX_EINTERN; /* TODO: this should be caughtable at the stix level... */
|
|
return -1;
|
|
}
|
|
|
|
/* set the instruction pointer to an invalid value.
|
|
* this is stored into the current method context
|
|
* before context switching and marks a dead context */
|
|
if (stix->active_context->origin == stix->active_context)
|
|
{
|
|
/* returning from a method */
|
|
#if defined(STIX_DEBUG_EXEC_002)
|
|
printf (">>>>>>>>>>>>> METHOD RETURN...\n");
|
|
#endif
|
|
STIX_ASSERT (STIX_CLASSOF(stix, stix->active_context) == stix->_method_context);
|
|
stix->ip = STIX_SMOOI_MIN;
|
|
}
|
|
else
|
|
{
|
|
/* method return from within a block(including a non-local return) */
|
|
STIX_ASSERT (STIX_CLASSOF(stix, stix->active_context) == stix->_block_context);
|
|
#if defined(STIX_DEBUG_EXEC_002)
|
|
printf (">>>>>>>>>>>>>>>> METHOD RETURN FROM WITHIN A BLOCK. NON-LOCAL RETURN.. RESETTUBG IP OF CONTEXT %p.\n", stix->active_context->origin);
|
|
#endif
|
|
stix->active_context->origin->ip = STIX_SMOOI_TO_OOP(STIX_SMOOI_MIN);
|
|
}
|
|
|
|
STIX_ASSERT (STIX_CLASSOF(stix, stix->active_context->origin) == stix->_method_context);
|
|
#if defined(STIX_USE_PROCSTK)
|
|
/* restore the stack pointer */
|
|
stix->sp = STIX_OOP_TO_SMOOI(stix->active_context->origin->sp);
|
|
#else
|
|
/* do nothing */
|
|
#endif
|
|
SWITCH_ACTIVE_CONTEXT (stix, stix->active_context->origin->sender);
|
|
|
|
/* push the return value to the stack of the new active context */
|
|
ACTIVE_STACK_PUSH (stix, return_value);
|
|
|
|
if ((stix_oop_t)stix->active_context->sender == stix->_nil)
|
|
{
|
|
/* the sender of the intial context is nil.
|
|
* use this fact to tell an initial context from a normal context. */
|
|
STIX_ASSERT (stix->active_context->receiver_or_source == stix->_nil);
|
|
|
|
/* when sender is nil, the following condition must be true.
|
|
* but it's not always true the other way around */
|
|
STIX_ASSERT (stix->active_context == stix->processor->active->initial_context);
|
|
|
|
#if defined(STIX_DEBUG_EXEC_001)
|
|
printf ("<<<RETURNIGN TO THE INITIAL CONTEXT>>> TERMINATING SP => %ld\n", (long int)stix->sp);
|
|
#endif
|
|
|
|
|
|
/* the stack contains the final return value so the stack pointer must be 0. */
|
|
STIX_ASSERT (stix->sp == 0);
|
|
|
|
if (stix->option.trait & STIX_AWAIT_PROCS)
|
|
terminate_process (stix, stix->processor->active);
|
|
else
|
|
goto done;
|
|
|
|
|
|
/* TODO: store the return value to the VM register.
|
|
* the caller to stix_execute() can fetch it to return it to the system */
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
break;
|
|
|
|
case BCODE_RETURN_FROM_BLOCK:
|
|
DBGOUT_EXEC_0 ("RETURN_FROM_BLOCK");
|
|
|
|
STIX_ASSERT(STIX_CLASSOF(stix, stix->active_context) == stix->_block_context);
|
|
|
|
if (stix->active_context == stix->processor->active->initial_context)
|
|
{
|
|
#if defined(STIX_DEBUG_EXEC_002)
|
|
printf ("TERMINATE A PROCESS RETURNING FROM BLOCK\n");
|
|
#endif
|
|
terminate_process (stix, stix->processor->active);
|
|
#if defined(STIX_DEBUG_EXEC_002)
|
|
|
|
printf ("TERMINATED A PROCESS RETURNING FROM BLOCK %lld new active_context %p\n", (long long int)stix->ip, stix->active_context);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#if defined(STIX_DEBUG_EXEC_001)
|
|
printf ("<<LEAVING BLOCK>>\n");
|
|
#endif
|
|
#if defined(STIX_USE_PROCSTK)
|
|
/* the process stack is shared. the return value
|
|
* doesn't need to get moved. */
|
|
SWITCH_ACTIVE_CONTEXT (stix, (stix_oop_context_t)stix->active_context->sender);
|
|
#else
|
|
/* NOTE: GC must not performed between here and */
|
|
return_value = ACTIVE_STACK_GETTOP(stix);
|
|
ACTIVE_STACK_POP (stix); /* pop off the return value */
|
|
|
|
SWITCH_ACTIVE_CONTEXT (stix, (stix_oop_context_t)stix->active_context->sender);
|
|
ACTIVE_STACK_PUSH (stix, return_value); /* push it to the sender */
|
|
/* NOTE: here. if so, return_value will point to a garbage. */
|
|
#endif
|
|
}
|
|
|
|
break;
|
|
|
|
case BCODE_MAKE_BLOCK:
|
|
{
|
|
stix_oop_context_t blkctx;
|
|
|
|
/* b1 - number of block arguments
|
|
* b2 - number of block temporaries */
|
|
FETCH_PARAM_CODE_TO (stix, b1);
|
|
FETCH_PARAM_CODE_TO (stix, b2);
|
|
|
|
DBGOUT_EXEC_2 ("MAKE_BLOCK %d %d", (int)b1, (int)b2);
|
|
|
|
STIX_ASSERT (b1 >= 0);
|
|
STIX_ASSERT (b2 >= b1);
|
|
|
|
/* the block context object created here is used as a base
|
|
* object for block context activation. prim_block_value()
|
|
* clones a block context and activates the cloned context.
|
|
* this base block context is created with no stack for
|
|
* this reason */
|
|
blkctx = (stix_oop_context_t)stix_instantiate (stix, stix->_block_context, STIX_NULL, 0);
|
|
if (!blkctx) return -1;
|
|
|
|
/* the long forward jump instruction has the format of
|
|
* 11000100 KKKKKKKK or 11000100 KKKKKKKK KKKKKKKK
|
|
* depending on STIX_BCODE_LONG_PARAM_SIZE. change 'ip' to point to
|
|
* the instruction after the jump. */
|
|
blkctx->ip = STIX_SMOOI_TO_OOP(stix->ip + STIX_BCODE_LONG_PARAM_SIZE + 1);
|
|
/* stack pointer below the bottom. this base block context
|
|
* has an empty stack anyway. */
|
|
blkctx->sp = STIX_SMOOI_TO_OOP(-1);
|
|
/* the number of arguments for a block context is local to the block */
|
|
blkctx->method_or_nargs = STIX_SMOOI_TO_OOP(b1);
|
|
/* the number of temporaries here is an accumulated count including
|
|
* the number of temporaries of a home context */
|
|
blkctx->ntmprs = STIX_SMOOI_TO_OOP(b2);
|
|
|
|
/* set the home context where it's defined */
|
|
blkctx->home = (stix_oop_t)stix->active_context;
|
|
/* no source for a base block context. */
|
|
blkctx->receiver_or_source = stix->_nil;
|
|
|
|
blkctx->origin = stix->active_context->origin;
|
|
|
|
/* push the new block context to the stack of the active context */
|
|
ACTIVE_STACK_PUSH (stix, (stix_oop_t)blkctx);
|
|
break;
|
|
}
|
|
|
|
case BCODE_SEND_BLOCK_COPY:
|
|
{
|
|
stix_ooi_t nargs, ntmprs;
|
|
stix_oop_context_t rctx;
|
|
stix_oop_context_t blkctx;
|
|
|
|
DBGOUT_EXEC_0 ("SEND_BLOCK_COPY");
|
|
|
|
/* it emulates thisContext blockCopy: nargs ofTmprCount: ntmprs */
|
|
STIX_ASSERT (stix->sp >= 2);
|
|
|
|
STIX_ASSERT (STIX_CLASSOF(stix, ACTIVE_STACK_GETTOP(stix)) == stix->_small_integer);
|
|
ntmprs = STIX_OOP_TO_SMOOI(ACTIVE_STACK_GETTOP(stix));
|
|
ACTIVE_STACK_POP (stix);
|
|
|
|
STIX_ASSERT (STIX_CLASSOF(stix, ACTIVE_STACK_GETTOP(stix)) == stix->_small_integer);
|
|
nargs = STIX_OOP_TO_SMOOI(ACTIVE_STACK_GETTOP(stix));
|
|
ACTIVE_STACK_POP (stix);
|
|
|
|
STIX_ASSERT (nargs >= 0);
|
|
STIX_ASSERT (ntmprs >= nargs);
|
|
|
|
/* the block context object created here is used
|
|
* as a base object for block context activation.
|
|
* prim_block_value() clones a block
|
|
* context and activates the cloned context.
|
|
* this base block context is created with no
|
|
* stack for this reason. */
|
|
blkctx = (stix_oop_context_t)stix_instantiate (stix, stix->_block_context, STIX_NULL, 0);
|
|
if (!blkctx) return -1;
|
|
|
|
/* get the receiver to the block copy message after block context instantiation
|
|
* not to get affected by potential GC */
|
|
rctx = (stix_oop_context_t)ACTIVE_STACK_GETTOP(stix);
|
|
STIX_ASSERT (rctx == stix->active_context);
|
|
|
|
/* [NOTE]
|
|
* blkctx->sender is left to nil. it is set to the
|
|
* active context before it gets activated. see
|
|
* prim_block_value().
|
|
*
|
|
* blkctx->home is set here to the active context.
|
|
* it's redundant to have them pushed to the stack
|
|
* though it is to emulate the message sending of
|
|
* blockCopy:withNtmprs:. BCODE_MAKE_BLOCK has been
|
|
* added to replace BCODE_SEND_BLOCK_COPY and pusing
|
|
* arguments to the stack.
|
|
*
|
|
* blkctx->origin is set here by copying the origin
|
|
* of the active context.
|
|
*/
|
|
|
|
/* the extended jump instruction has the format of
|
|
* 0000XXXX KKKKKKKK or 0000XXXX KKKKKKKK KKKKKKKK
|
|
* depending on STIX_BCODE_LONG_PARAM_SIZE. change 'ip' to point to
|
|
* the instruction after the jump. */
|
|
blkctx->ip = STIX_SMOOI_TO_OOP(stix->ip + STIX_BCODE_LONG_PARAM_SIZE + 1);
|
|
blkctx->sp = STIX_SMOOI_TO_OOP(-1);
|
|
/* the number of arguments for a block context is local to the block */
|
|
blkctx->method_or_nargs = STIX_SMOOI_TO_OOP(nargs);
|
|
/* the number of temporaries here is an accumulated count including
|
|
* the number of temporaries of a home context */
|
|
blkctx->ntmprs = STIX_SMOOI_TO_OOP(ntmprs);
|
|
|
|
blkctx->home = (stix_oop_t)rctx;
|
|
blkctx->receiver_or_source = stix->_nil;
|
|
|
|
#if 0
|
|
if (rctx->home == stix->_nil)
|
|
{
|
|
/* the context that receives the blockCopy message is a method context */
|
|
STIX_ASSERT (STIX_CLASSOF(stix, rctx) == stix->_method_context);
|
|
STIX_ASSERT (rctx == (stix_oop_t)stix->active_context);
|
|
blkctx->origin = (stix_oop_context_t)rctx;
|
|
}
|
|
else
|
|
{
|
|
/* a block context is active */
|
|
STIX_ASSERT (STIX_CLASSOF(stix, rctx) == stix->_block_context);
|
|
blkctx->origin = ((stix_oop_block_context_t)rctx)->origin;
|
|
}
|
|
#else
|
|
|
|
/* [NOTE]
|
|
* the origin of a method context is set to itself
|
|
* when it's created. so it's safe to simply copy
|
|
* the origin field this way.
|
|
*/
|
|
blkctx->origin = rctx->origin;
|
|
#endif
|
|
|
|
ACTIVE_STACK_SETTOP (stix, (stix_oop_t)blkctx);
|
|
break;
|
|
}
|
|
|
|
case BCODE_NOOP:
|
|
/* do nothing */
|
|
break;
|
|
|
|
|
|
default:
|
|
printf ("UNKNOWN BYTE CODE ENCOUNTERED %x\n", (int)bcode);
|
|
stix->errnum = STIX_EINTERN;
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
done:
|
|
|
|
#if defined(STIX_PROFILE_EXEC)
|
|
printf ("TOTAL_INST_COUTNER = %lu\n", (unsigned long int)inst_counter);
|
|
#endif
|
|
return 0;
|
|
|
|
|
|
oops:
|
|
/* TODO: anything to do here? */
|
|
return -1;
|
|
}
|
|
|
|
int stix_invoke (stix_t* stix, const stix_oocs_t* objname, const stix_oocs_t* mthname)
|
|
{
|
|
if (start_initial_process_and_context (stix, objname, mthname) <= -1) return -1;
|
|
return stix_execute (stix);
|
|
/* TODO: reset stix->active_context & stix->active_method to STIX_NULL
|
|
*
|
|
* TODO: remove the process. set processor->tally to zero. processor->active to nil_process...
|
|
*/
|
|
}
|
|
|