2015-06-04 18:34:37 +00:00
/*
* $ Id $
*
2016-02-12 16:23:26 +00:00
Copyright ( c ) 2014 - 2016 Chung , Hyung - Hwan . All rights reserved .
2015-06-04 18:34:37 +00:00
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 .
*/
2017-01-09 09:54:49 +00:00
# include "moo-prv.h"
2015-06-04 18:34:37 +00:00
2016-05-19 13:06:05 +00:00
/* TODO: remove these headers after having migrated system-dependent functions of of this file */
2016-05-12 05:53:35 +00:00
# if defined(_WIN32)
# include <windows.h>
2016-05-19 13:06:05 +00:00
# elif defined(__OS2__)
# define INCL_DOSMISC
# define INCL_DOSDATETIME
# define INCL_DOSERRORS
# include <os2.h>
# include <time.h>
2016-05-13 15:10:34 +00:00
# elif defined(__MSDOS__)
# include <time.h>
2016-05-19 03:49:23 +00:00
# elif defined(macintosh)
# include <Types.h>
# include <OSUtils.h>
# include <Timer.h>
2016-05-13 15:10:34 +00:00
# else
# if defined(HAVE_TIME_H)
# include <time.h>
# endif
# if defined(HAVE_SYS_TIME_H)
# include <sys / time.h>
# endif
2016-05-12 05:53:35 +00:00
# endif
2016-06-24 15:01:51 +00:00
# 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
2016-03-22 14:18:07 +00:00
# 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) ( \
2017-01-09 09:54:49 +00:00
( MOO_OOP_TO_SMOOI ( ( x ) - > heap_ftime_sec ) < MOO_OOP_TO_SMOOI ( ( y ) - > heap_ftime_sec ) ) | | \
( MOO_OOP_TO_SMOOI ( ( x ) - > heap_ftime_sec ) = = MOO_OOP_TO_SMOOI ( ( y ) - > heap_ftime_sec ) & & MOO_OOP_TO_SMOOI ( ( x ) - > heap_ftime_nsec ) < MOO_OOP_TO_SMOOI ( ( y ) - > heap_ftime_nsec ) ) \
2016-03-22 14:18:07 +00:00
)
2016-02-15 18:07:20 +00:00
2015-06-26 15:49:08 +00:00
2017-01-09 09:54:49 +00:00
# define LOAD_IP(moo, v_ctx) ((moo)->ip = MOO_OOP_TO_SMOOI((v_ctx)->ip))
# define STORE_IP(moo, v_ctx) ((v_ctx)->ip = MOO_SMOOI_TO_OOP((moo)->ip))
2015-06-12 13:52:30 +00:00
2017-01-09 09:54:49 +00:00
# define LOAD_SP(moo, v_ctx) ((moo)->sp = MOO_OOP_TO_SMOOI((v_ctx)->sp))
# define STORE_SP(moo, v_ctx) ((v_ctx)->sp = MOO_SMOOI_TO_OOP((moo)->sp))
2015-06-16 04:31:28 +00:00
2017-01-09 09:54:49 +00:00
# define LOAD_ACTIVE_IP(moo) LOAD_IP(moo, (moo)->active_context)
# define STORE_ACTIVE_IP(moo) STORE_IP(moo, (moo)->active_context)
2015-06-16 04:31:28 +00:00
2017-01-09 09:54:49 +00:00
# define LOAD_ACTIVE_SP(moo) LOAD_SP(moo, (moo)->processor->active)
# define STORE_ACTIVE_SP(moo) STORE_SP(moo, (moo)->processor->active)
2015-06-04 18:34:37 +00:00
2017-01-09 09:54:49 +00:00
# define SWITCH_ACTIVE_CONTEXT(moo,v_ctx) \
2016-06-24 15:01:51 +00:00
do \
{ \
2017-01-09 09:54:49 +00:00
STORE_ACTIVE_IP ( moo ) ; \
( moo ) - > active_context = ( v_ctx ) ; \
( moo ) - > active_method = ( moo_oop_method_t ) ( moo ) - > active_context - > origin - > method_or_nargs ; \
SET_ACTIVE_METHOD_CODE ( moo ) ; \
LOAD_ACTIVE_IP ( moo ) ; \
( moo ) - > processor - > active - > current_context = ( moo ) - > active_context ; \
2016-06-24 15:01:51 +00:00
} while ( 0 )
2015-06-20 03:07:11 +00:00
2017-01-09 09:54:49 +00:00
# define FETCH_BYTE_CODE(moo) ((moo)->active_code[(moo)->ip++])
# define FETCH_BYTE_CODE_TO(moo, v_ooi) (v_ooi = FETCH_BYTE_CODE(moo))
# if (MOO_BCODE_LONG_PARAM_SIZE == 2)
# define FETCH_PARAM_CODE_TO(moo, v_ooi) \
2016-02-12 16:23:26 +00:00
do { \
2017-01-09 09:54:49 +00:00
v_ooi = FETCH_BYTE_CODE ( moo ) ; \
v_ooi = ( v_ooi < < 8 ) | FETCH_BYTE_CODE ( moo ) ; \
2016-02-12 16:23:26 +00:00
} while ( 0 )
2015-07-01 15:01:39 +00:00
# else
2017-01-09 09:54:49 +00:00
# define FETCH_PARAM_CODE_TO(moo, v_ooi) (v_ooi = FETCH_BYTE_CODE(moo))
2015-07-01 15:01:39 +00:00
# endif
2017-01-09 09:54:49 +00:00
# if defined(MOO_DEBUG_VM_EXEC)
# define LOG_MASK_INST (MOO_LOG_IC | MOO_LOG_MNEMONIC)
2016-06-05 18:01:35 +00:00
2016-10-06 14:17:24 +00:00
/* TODO: for send_message, display the method name. or include the method name before 'ip' */
2017-01-09 09:54:49 +00:00
# define LOG_INST_0(moo,fmt) MOO_LOG1(moo, LOG_MASK_INST, " %06zd " fmt "\n", fetched_instruction_pointer)
# define LOG_INST_1(moo,fmt,a1) MOO_LOG2(moo, LOG_MASK_INST, " %06zd " fmt "\n",fetched_instruction_pointer, a1)
# define LOG_INST_2(moo,fmt,a1,a2) MOO_LOG3(moo, LOG_MASK_INST, " %06zd " fmt "\n", fetched_instruction_pointer, a1, a2)
# define LOG_INST_3(moo,fmt,a1,a2,a3) MOO_LOG4(moo, LOG_MASK_INST, " %06zd " fmt "\n", fetched_instruction_pointer, a1, a2, a3)
2015-10-08 14:26:04 +00:00
# else
2017-01-09 09:54:49 +00:00
# define LOG_INST_0(moo,fmt)
# define LOG_INST_1(moo,fmt,a1)
# define LOG_INST_2(moo,fmt,a1,a2)
# define LOG_INST_3(moo,fmt,a1,a2,a3)
2015-10-08 14:26:04 +00:00
# endif
2016-06-30 13:44:37 +00:00
# define __PRIMITIVE_NAME__ (&__FUNCTION__[4])
2016-06-26 15:03:12 +00:00
2016-05-12 05:53:35 +00:00
/* ------------------------------------------------------------------------- */
2017-01-09 09:54:49 +00:00
static MOO_INLINE void vm_gettime ( moo_t * moo , moo_ntime_t * now )
2016-03-24 14:58:47 +00:00
{
2016-05-19 13:06:05 +00:00
# if defined(_WIN32)
/* TODO: */
# elif defined(__OS2__)
ULONG out ;
/* TODO: handle overflow?? */
/* TODO: use DosTmrQueryTime() and DosTmrQueryFreq()? */
2017-01-09 09:54:49 +00:00
DosQuerySysInfo ( QSV_MS_COUNT , QSV_MS_COUNT , & out , MOO_SIZEOF ( out ) ) ; /* milliseconds */
2016-05-19 13:06:05 +00:00
/* it must return NO_ERROR */
2017-01-09 09:54:49 +00:00
MOO_INITNTIME ( now , MOO_MSEC_TO_SEC ( out ) , MOO_MSEC_TO_NSEC ( out ) ) ;
2016-05-19 13:06:05 +00:00
# elif defined(__MSDOS__) && defined(_INTELC32_)
2016-05-13 15:10:34 +00:00
clock_t c ;
/* TODO: handle overflow?? */
c = clock ( ) ;
now - > sec = c / CLOCKS_PER_SEC ;
# if (CLOCKS_PER_SEC == 1000)
2017-01-09 09:54:49 +00:00
now - > nsec = MOO_MSEC_TO_NSEC ( c % CLOCKS_PER_SEC ) ;
2016-05-13 15:10:34 +00:00
# elif (CLOCKS_PER_SEC == 1000000L)
2017-01-09 09:54:49 +00:00
now - > nsec = MOO_USEC_TO_NSEC ( c % CLOCKS_PER_SEC ) ;
2016-05-13 15:10:34 +00:00
# elif (CLOCKS_PER_SEC == 1000000000L)
now - > nsec = ( c % CLOCKS_PER_SEC ) ;
# else
# error UNSUPPORTED CLOCKS_PER_SEC
# endif
2016-05-19 03:49:23 +00:00
# elif defined(macintosh)
UnsignedWide tick ;
2017-01-09 09:54:49 +00:00
moo_uint64_t tick64 ;
2016-05-19 03:49:23 +00:00
Microseconds ( & tick ) ;
2017-01-09 09:54:49 +00:00
tick64 = * ( moo_uint64_t * ) & tick ;
MOO_INITNTIME ( now , MOO_USEC_TO_SEC ( tick64 ) , MOO_USEC_TO_NSEC ( tick64 ) ) ;
2016-05-13 15:10:34 +00:00
2016-06-24 15:53:00 +00:00
# elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
2016-03-24 14:58:47 +00:00
struct timespec ts ;
clock_gettime ( CLOCK_MONOTONIC , & ts ) ;
2017-01-09 09:54:49 +00:00
MOO_INITNTIME ( now , ts . tv_sec , ts . tv_nsec ) ;
2016-06-24 15:53:00 +00:00
# elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
struct timespec ts ;
2016-04-30 15:48:08 +00:00
clock_gettime ( CLOCK_REALTIME , & ts ) ;
2017-01-09 09:54:49 +00:00
MOO_INITNTIME ( now , ts . tv_sec , ts . tv_nsec ) ;
MOO_SUBNTIME ( now , now , & moo - > vm_time_offset ) ; /* offset */
2016-04-30 15:48:08 +00:00
# else
struct timeval tv ;
2017-01-09 09:54:49 +00:00
gettimeofday ( & tv , MOO_NULL ) ;
MOO_INITNTIME ( now , tv . tv_sec , MOO_USEC_TO_NSEC ( tv . tv_usec ) ) ;
2016-06-24 15:53:00 +00:00
/* at the first call, vm_time_offset should be 0. so subtraction takes
* no effect . once it becomes non - zero , it offsets the actual time .
* this is to keep the returned time small enough to be held in a
* small integer on platforms where the small integer is not large enough */
2017-01-09 09:54:49 +00:00
MOO_SUBNTIME ( now , now , & moo - > vm_time_offset ) ;
2016-04-30 15:48:08 +00:00
# endif
2016-03-24 14:58:47 +00:00
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE void vm_sleep ( moo_t * moo , const moo_ntime_t * dur )
2016-03-24 14:58:47 +00:00
{
2016-05-12 05:53:35 +00:00
# if defined(_WIN32)
2017-01-09 09:54:49 +00:00
if ( moo - > waitable_timer )
2016-05-12 05:53:35 +00:00
{
LARGE_INTEGER li ;
2017-01-09 09:54:49 +00:00
li . QuadPart = - MOO_SECNSEC_TO_NSEC ( dur - > sec , dur - > nsec ) ;
if ( SetWaitableTimer ( timer , & li , 0 , MOO_NULL , MOO_NULL , FALSE ) = = FALSE ) goto normal_sleep ;
2016-05-12 05:53:35 +00:00
WaitForSingleObject ( timer , INFINITE ) ;
}
else
{
normal_sleep :
/* fallback to normal Sleep() */
2017-01-09 09:54:49 +00:00
Sleep ( MOO_SECNSEC_TO_MSEC ( dur - > sec , dur - > nsec ) ) ;
2016-05-12 05:53:35 +00:00
}
2016-05-19 13:06:05 +00:00
# elif defined(__OS2__)
/* TODO: in gui mode, this is not a desirable method???
* this must be made event - driven coupled with the main event loop */
2017-01-09 09:54:49 +00:00
DosSleep ( MOO_SECNSEC_TO_MSEC ( dur - > sec , dur - > nsec ) ) ;
2016-05-12 05:53:35 +00:00
2016-05-19 03:49:23 +00:00
# elif defined(macintosh)
/* TODO: ... */
2016-05-13 15:10:34 +00:00
# elif defined(__MSDOS__) && defined(_INTELC32_)
clock_t c ;
c = clock ( ) ;
c + = dur - > sec * CLOCKS_PER_SEC ;
# if (CLOCKS_PER_SEC == 1000)
2017-01-09 09:54:49 +00:00
c + = MOO_NSEC_TO_MSEC ( dur - > nsec ) ;
2016-05-13 15:10:34 +00:00
# elif (CLOCKS_PER_SEC == 1000000L)
2017-01-09 09:54:49 +00:00
c + = MOO_NSEC_TO_USEC ( dur - > nsec ) ;
2016-05-13 15:10:34 +00:00
# elif (CLOCKS_PER_SEC == 1000000000L)
c + = dur - > nsec ;
# else
# error UNSUPPORTED CLOCKS_PER_SEC
# endif
/* TODO: handle clock overvlow */
/* TODO: check if there is abortion request or interrupt */
while ( c > clock ( ) ) ;
2016-05-12 05:53:35 +00:00
# else
2016-03-24 14:58:47 +00:00
struct timespec ts ;
ts . tv_sec = dur - > sec ;
ts . tv_nsec = dur - > nsec ;
2017-01-09 09:54:49 +00:00
nanosleep ( & ts , MOO_NULL ) ;
2016-05-12 05:53:35 +00:00
# endif
2016-03-24 14:58:47 +00:00
}
2016-06-24 15:53:00 +00:00
2017-01-09 09:54:49 +00:00
static void vm_startup ( moo_t * moo )
2016-06-24 15:53:00 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ntime_t now ;
2016-06-24 15:53:00 +00:00
# if defined(_WIN32)
2017-01-09 09:54:49 +00:00
moo - > waitable_timer = CreateWaitableTimer ( MOO_NULL , TRUE , MOO_NULL ) ;
2016-06-24 15:53:00 +00:00
# endif
2017-01-09 09:54:49 +00:00
/* reset moo->vm_time_offset so that vm_gettime is not affected */
MOO_INITNTIME ( & moo - > vm_time_offset , 0 , 0 ) ;
vm_gettime ( moo , & now ) ;
moo - > vm_time_offset = now ;
2016-06-24 15:53:00 +00:00
}
2017-01-09 09:54:49 +00:00
static void vm_cleanup ( moo_t * moo )
2016-06-24 15:53:00 +00:00
{
# if defined(_WIN32)
2017-01-09 09:54:49 +00:00
if ( moo - > waitable_timer )
2016-06-24 15:53:00 +00:00
{
2017-01-09 09:54:49 +00:00
CloseHandle ( moo - > waitable_timer ) ;
moo - > waitable_timer = MOO_NULL ;
2016-06-24 15:53:00 +00:00
}
# endif
}
2016-05-12 05:53:35 +00:00
/* ------------------------------------------------------------------------- */
2017-01-09 09:54:49 +00:00
static moo_oop_process_t make_process ( moo_t * moo , moo_oop_context_t c )
2015-10-18 15:06:17 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_process_t proc ;
2015-10-18 15:06:17 +00:00
2017-01-09 09:54:49 +00:00
moo_pushtmp ( moo , ( moo_oop_t * ) & c ) ;
proc = ( moo_oop_process_t ) moo_instantiate ( moo , moo - > _process , MOO_NULL , moo - > option . dfl_procstk_size ) ;
moo_poptmp ( moo ) ;
if ( ! proc ) return MOO_NULL ;
2015-10-18 15:06:17 +00:00
2017-01-09 09:54:49 +00:00
proc - > state = MOO_SMOOI_TO_OOP ( PROC_STATE_SUSPENDED ) ;
2015-10-19 06:16:43 +00:00
proc - > initial_context = c ;
2016-02-19 15:52:56 +00:00
proc - > current_context = c ;
2017-01-09 09:54:49 +00:00
proc - > sp = MOO_SMOOI_TO_OOP ( - 1 ) ;
2015-10-18 15:06:17 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , ( moo_oop_t ) c - > sender = = moo - > _nil ) ;
2016-05-02 13:50:42 +00:00
2017-01-09 09:54:49 +00:00
# if defined(MOO_DEBUG_VM_PROCESSOR)
MOO_LOG2 ( moo , MOO_LOG_IC | MOO_LOG_DEBUG , " Processor - made process %O of size %zu \n " , proc , MOO_OBJ_GET_SIZE ( proc ) ) ;
2016-02-12 16:23:26 +00:00
# endif
2015-10-18 15:06:17 +00:00
return proc ;
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE void sleep_active_process ( moo_t * moo , int state )
2015-10-19 06:16:43 +00:00
{
2017-01-09 09:54:49 +00:00
# if defined(MOO_DEBUG_VM_PROCESSOR)
MOO_LOG3 ( moo , MOO_LOG_IC | MOO_LOG_DEBUG , " Processor - put process %O context %O ip=%zd to sleep \n " , moo - > processor - > active , moo - > active_context , moo - > ip ) ;
2015-12-02 16:14:37 +00:00
# endif
2015-10-19 06:16:43 +00:00
2017-01-09 09:54:49 +00:00
STORE_ACTIVE_SP ( moo ) ;
2016-02-12 16:23:26 +00:00
2016-02-19 15:52:56 +00:00
/* store the current active context to the current process.
* it is the suspended context of the process to be suspended */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , moo - > processor - > active ! = moo - > nil_process ) ;
moo - > processor - > active - > current_context = moo - > active_context ;
moo - > processor - > active - > state = MOO_SMOOI_TO_OOP ( state ) ;
2016-03-23 02:34:13 +00:00
}
2016-02-12 16:23:26 +00:00
2017-01-09 09:54:49 +00:00
static MOO_INLINE void wake_new_process ( moo_t * moo , moo_oop_process_t proc )
2016-03-23 02:34:13 +00:00
{
2016-02-19 15:52:56 +00:00
/* activate the given process */
2017-01-09 09:54:49 +00:00
proc - > state = MOO_SMOOI_TO_OOP ( PROC_STATE_RUNNING ) ;
moo - > processor - > active = proc ;
2016-02-12 16:23:26 +00:00
2017-01-09 09:54:49 +00:00
LOAD_ACTIVE_SP ( moo ) ;
2015-10-19 06:16:43 +00:00
2016-02-19 15:52:56 +00:00
/* activate the suspended context of the new process */
2017-01-09 09:54:49 +00:00
SWITCH_ACTIVE_CONTEXT ( moo , proc - > current_context ) ;
2016-02-12 16:23:26 +00:00
2017-01-09 09:54:49 +00:00
# if defined(MOO_DEBUG_VM_PROCESSOR)
MOO_LOG3 ( moo , MOO_LOG_IC | MOO_LOG_DEBUG , " Processor - woke up process %O context %O ip=%zd \n " , moo - > processor - > active , moo - > active_context , moo - > ip ) ;
2015-12-02 16:14:37 +00:00
# endif
2016-03-23 02:34:13 +00:00
}
2017-01-09 09:54:49 +00:00
static void switch_to_process ( moo_t * moo , moo_oop_process_t proc , int new_state_for_old_active )
2016-03-23 02:34:13 +00:00
{
/* the new process must not be the currently active process */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , moo - > processor - > active ! = proc ) ;
2016-03-23 02:34:13 +00:00
/* the new process must be in the runnable state */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , proc - > state = = MOO_SMOOI_TO_OOP ( PROC_STATE_RUNNABLE ) | |
proc - > state = = MOO_SMOOI_TO_OOP ( PROC_STATE_WAITING ) ) ;
2016-03-23 02:34:13 +00:00
2017-01-09 09:54:49 +00:00
sleep_active_process ( moo , new_state_for_old_active ) ;
wake_new_process ( moo , proc ) ;
2016-02-19 15:52:56 +00:00
2017-01-09 09:54:49 +00:00
moo - > proc_switched = 1 ;
2015-10-19 06:16:43 +00:00
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE moo_oop_process_t find_next_runnable_process ( moo_t * moo )
2015-10-19 06:16:43 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_process_t npr ;
2016-05-15 15:51:41 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , moo - > processor - > active - > state = = MOO_SMOOI_TO_OOP ( PROC_STATE_RUNNING ) ) ;
npr = moo - > processor - > active - > next ;
if ( ( moo_oop_t ) npr = = moo - > _nil ) npr = moo - > processor - > runnable_head ;
2016-02-19 15:52:56 +00:00
return npr ;
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE void switch_to_next_runnable_process ( moo_t * moo )
2016-02-19 15:52:56 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_process_t nrp ;
2016-02-19 15:52:56 +00:00
2017-01-09 09:54:49 +00:00
nrp = find_next_runnable_process ( moo ) ;
if ( nrp ! = moo - > processor - > active ) switch_to_process ( moo , nrp , PROC_STATE_RUNNABLE ) ;
2015-10-19 06:16:43 +00:00
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE int chain_into_processor ( moo_t * moo , moo_oop_process_t proc )
2015-10-18 15:06:17 +00:00
{
2015-12-02 15:24:13 +00:00
/* the process is not scheduled at all.
* link it to the processor ' s process list . */
2017-01-09 09:54:49 +00:00
moo_ooi_t tally ;
2015-10-18 15:06:17 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , ( moo_oop_t ) proc - > prev = = moo - > _nil ) ;
MOO_ASSERT ( moo , ( moo_oop_t ) proc - > next = = moo - > _nil ) ;
2016-02-15 18:07:20 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , proc - > state = = MOO_SMOOI_TO_OOP ( PROC_STATE_SUSPENDED ) ) ;
2015-12-02 15:24:13 +00:00
2017-01-09 09:54:49 +00:00
tally = MOO_OOP_TO_SMOOI ( moo - > processor - > tally ) ;
2016-02-12 16:23:26 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , tally > = 0 ) ;
if ( tally > = MOO_SMOOI_MAX )
2015-12-02 15:24:13 +00:00
{
2017-01-09 09:54:49 +00:00
# if defined(MOO_DEBUG_VM_PROCESSOR)
MOO_LOG0 ( moo , MOO_LOG_IC | MOO_LOG_FATAL , " Processor - too many process \n " ) ;
2015-12-02 16:14:37 +00:00
# endif
2017-01-09 09:54:49 +00:00
moo - > errnum = MOO_EPFULL ;
2015-12-02 15:24:13 +00:00
return - 1 ;
}
2016-02-18 17:49:56 +00:00
2016-02-19 15:52:56 +00:00
/* append to the runnable list */
2016-02-29 17:26:40 +00:00
if ( tally > 0 )
{
2017-01-09 09:54:49 +00:00
proc - > prev = moo - > processor - > runnable_tail ;
moo - > processor - > runnable_tail - > next = proc ;
2016-02-29 17:26:40 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
moo - > processor - > runnable_head = proc ;
2016-02-29 17:26:40 +00:00
}
2017-01-09 09:54:49 +00:00
moo - > processor - > runnable_tail = proc ;
2016-02-19 15:52:56 +00:00
2016-02-18 17:49:56 +00:00
tally + + ;
2017-01-09 09:54:49 +00:00
moo - > processor - > tally = MOO_SMOOI_TO_OOP ( tally ) ;
2015-10-18 15:06:17 +00:00
2015-12-02 15:24:13 +00:00
return 0 ;
}
2015-10-19 06:16:43 +00:00
2017-01-09 09:54:49 +00:00
static MOO_INLINE void unchain_from_processor ( moo_t * moo , moo_oop_process_t proc , int state )
2016-02-18 17:49:56 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t tally ;
2016-02-18 17:49:56 +00:00
2016-03-23 12:58:30 +00:00
/* the processor's process chain must be composed of running/runnable
* processes only */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , proc - > state = = MOO_SMOOI_TO_OOP ( PROC_STATE_RUNNING ) | |
proc - > state = = MOO_SMOOI_TO_OOP ( PROC_STATE_RUNNABLE ) ) ;
2016-02-18 17:49:56 +00:00
2017-01-09 09:54:49 +00:00
tally = MOO_OOP_TO_SMOOI ( moo - > processor - > tally ) ;
MOO_ASSERT ( moo , tally > 0 ) ;
2016-02-18 17:49:56 +00:00
2017-01-09 09:54:49 +00:00
if ( ( moo_oop_t ) proc - > prev ! = moo - > _nil ) proc - > prev - > next = proc - > next ;
else moo - > processor - > runnable_head = proc - > next ;
if ( ( moo_oop_t ) proc - > next ! = moo - > _nil ) proc - > next - > prev = proc - > prev ;
else moo - > processor - > runnable_tail = proc - > prev ;
2016-02-29 17:26:40 +00:00
2017-01-09 09:54:49 +00:00
proc - > prev = ( moo_oop_process_t ) moo - > _nil ;
proc - > next = ( moo_oop_process_t ) moo - > _nil ;
proc - > state = MOO_SMOOI_TO_OOP ( state ) ;
2016-02-18 17:49:56 +00:00
tally - - ;
2017-01-09 09:54:49 +00:00
if ( tally = = 0 ) moo - > processor - > active = moo - > nil_process ;
moo - > processor - > tally = MOO_SMOOI_TO_OOP ( tally ) ;
2016-02-18 17:49:56 +00:00
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE void chain_into_semaphore ( moo_t * moo , moo_oop_process_t proc , moo_oop_semaphore_t sem )
2016-02-29 17:26:40 +00:00
{
/* append a process to the process list of a semaphore*/
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , ( moo_oop_t ) proc - > sem = = moo - > _nil ) ;
MOO_ASSERT ( moo , ( moo_oop_t ) proc - > prev = = moo - > _nil ) ;
MOO_ASSERT ( moo , ( moo_oop_t ) proc - > next = = moo - > _nil ) ;
2016-02-29 17:26:40 +00:00
2017-01-09 09:54:49 +00:00
if ( ( moo_oop_t ) sem - > waiting_head = = moo - > _nil )
2016-02-29 17:26:40 +00:00
{
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , ( moo_oop_t ) sem - > waiting_tail = = moo - > _nil ) ;
2016-02-29 17:26:40 +00:00
sem - > waiting_head = proc ;
}
else
{
2016-03-16 02:27:18 +00:00
proc - > prev = sem - > waiting_tail ;
sem - > waiting_tail - > next = proc ;
2016-02-29 17:26:40 +00:00
}
sem - > waiting_tail = proc ;
proc - > sem = sem ;
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE void unchain_from_semaphore ( moo_t * moo , moo_oop_process_t proc )
2016-02-29 17:26:40 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_semaphore_t sem ;
2016-02-29 17:26:40 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , ( moo_oop_t ) proc - > sem ! = moo - > _nil ) ;
2016-02-29 17:26:40 +00:00
sem = proc - > sem ;
2017-01-09 09:54:49 +00:00
if ( ( moo_oop_t ) proc - > prev ! = moo - > _nil ) proc - > prev - > next = proc - > next ;
2016-03-16 02:27:18 +00:00
else sem - > waiting_head = proc - > next ;
2017-01-09 09:54:49 +00:00
if ( ( moo_oop_t ) proc - > next ! = moo - > _nil ) proc - > next - > prev = proc - > prev ;
2016-03-16 02:27:18 +00:00
else sem - > waiting_tail = proc - > prev ;
2016-02-29 17:26:40 +00:00
2017-01-09 09:54:49 +00:00
proc - > prev = ( moo_oop_process_t ) moo - > _nil ;
proc - > next = ( moo_oop_process_t ) moo - > _nil ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
proc - > sem = ( moo_oop_semaphore_t ) moo - > _nil ;
2016-02-29 17:26:40 +00:00
}
2017-01-09 09:54:49 +00:00
static void terminate_process ( moo_t * moo , moo_oop_process_t proc )
2016-02-13 17:39:11 +00:00
{
2017-01-09 09:54:49 +00:00
if ( proc - > state = = MOO_SMOOI_TO_OOP ( PROC_STATE_RUNNING ) | |
proc - > state = = MOO_SMOOI_TO_OOP ( PROC_STATE_RUNNABLE ) )
2016-02-13 17:39:11 +00:00
{
2016-02-19 15:52:56 +00:00
/* RUNNING/RUNNABLE ---> TERMINATED */
2016-06-05 18:01:35 +00:00
2017-01-09 09:54:49 +00:00
# if defined(MOO_DEBUG_VM_PROCESSOR)
MOO_LOG1 ( moo , MOO_LOG_IC | MOO_LOG_DEBUG , " Processor - process %O RUNNING/RUNNABLE->TERMINATED \n " , proc ) ;
2016-06-05 18:01:35 +00:00
# endif
2017-01-09 09:54:49 +00:00
if ( proc = = moo - > processor - > active )
2016-02-19 15:52:56 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_process_t nrp ;
2016-02-13 17:39:11 +00:00
2017-01-09 09:54:49 +00:00
nrp = find_next_runnable_process ( moo ) ;
2016-02-13 17:39:11 +00:00
2017-01-09 09:54:49 +00:00
unchain_from_processor ( moo , proc , PROC_STATE_TERMINATED ) ;
proc - > sp = MOO_SMOOI_TO_OOP ( - 1 ) ; /* invalidate the process stack */
2016-02-19 15:52:56 +00:00
proc - > current_context = proc - > initial_context ; /* not needed but just in case */
2016-02-13 17:39:11 +00:00
2016-02-29 17:26:40 +00:00
/* a runnable or running process must not be chanined to the
* process list of a semaphore */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , ( moo_oop_t ) proc - > sem = = moo - > _nil ) ;
2016-02-13 17:39:11 +00:00
2016-02-19 15:52:56 +00:00
if ( nrp = = proc )
{
/* no runnable process after termination */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , moo - > processor - > active = = moo - > nil_process ) ;
MOO_LOG0 ( moo , MOO_LOG_IC | MOO_LOG_DEBUG , " No runnable process after process termination \n " ) ;
2016-02-19 15:52:56 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
switch_to_process ( moo , nrp , PROC_STATE_TERMINATED ) ;
2016-02-19 15:52:56 +00:00
}
2016-02-13 17:39:11 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
unchain_from_processor ( moo , proc , PROC_STATE_TERMINATED ) ;
proc - > sp = MOO_SMOOI_TO_OOP ( - 1 ) ; /* invalidate the process stack */
2016-02-13 17:39:11 +00:00
}
2016-02-19 15:52:56 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( proc - > state = = MOO_SMOOI_TO_OOP ( PROC_STATE_SUSPENDED ) )
2016-02-19 15:52:56 +00:00
{
/* SUSPENDED ---> TERMINATED */
2017-01-09 09:54:49 +00:00
# if defined(MOO_DEBUG_VM_PROCESSOR)
MOO_LOG1 ( moo , MOO_LOG_IC | MOO_LOG_DEBUG , " Processor - process %O SUSPENDED->TERMINATED \n " , proc ) ;
2016-06-05 18:01:35 +00:00
# endif
2017-01-09 09:54:49 +00:00
proc - > state = MOO_SMOOI_TO_OOP ( PROC_STATE_TERMINATED ) ;
proc - > sp = MOO_SMOOI_TO_OOP ( - 1 ) ; /* invalidate the proce stack */
2016-02-29 17:26:40 +00:00
2017-01-09 09:54:49 +00:00
if ( ( moo_oop_t ) proc - > sem ! = moo - > _nil )
2016-02-29 17:26:40 +00:00
{
2017-01-09 09:54:49 +00:00
unchain_from_semaphore ( moo , proc ) ;
2016-02-29 17:26:40 +00:00
}
2016-02-19 15:52:56 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( proc - > state = = MOO_SMOOI_TO_OOP ( PROC_STATE_WAITING ) )
2016-02-19 15:52:56 +00:00
{
/* WAITING ---> TERMINATED */
/* TODO: */
2016-02-13 17:39:11 +00:00
}
}
2017-01-09 09:54:49 +00:00
static void resume_process ( moo_t * moo , moo_oop_process_t proc )
2015-12-02 15:24:13 +00:00
{
2017-01-09 09:54:49 +00:00
if ( proc - > state = = MOO_SMOOI_TO_OOP ( PROC_STATE_SUSPENDED ) )
2016-02-13 17:39:11 +00:00
{
2016-02-19 15:52:56 +00:00
/* SUSPENED ---> RUNNING */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , ( moo_oop_t ) proc - > prev = = moo - > _nil ) ;
MOO_ASSERT ( moo , ( moo_oop_t ) proc - > next = = moo - > _nil ) ;
2016-02-19 15:52:56 +00:00
2017-01-09 09:54:49 +00:00
# if defined(MOO_DEBUG_VM_PROCESSOR)
MOO_LOG1 ( moo , MOO_LOG_IC | MOO_LOG_DEBUG , " Processor - process %O SUSPENDED->RUNNING \n " , proc ) ;
2016-06-05 18:01:35 +00:00
# endif
2017-01-09 09:54:49 +00:00
chain_into_processor ( moo , proc ) ; /* TODO: error check */
2016-02-18 17:49:56 +00:00
2016-02-29 15:27:10 +00:00
/*proc->current_context = proc->initial_context;*/
2017-01-09 09:54:49 +00:00
proc - > state = MOO_SMOOI_TO_OOP ( PROC_STATE_RUNNABLE ) ;
2016-02-19 15:52:56 +00:00
2016-03-24 14:58:47 +00:00
/* don't switch to this process. just set the state to RUNNING */
2015-10-19 06:16:43 +00:00
}
2016-02-19 15:52:56 +00:00
#if 0
2017-01-09 09:54:49 +00:00
else if ( proc - > state = = MOO_SMOOI_TO_OOP ( PROC_STATE_RUNNABLE ) )
2015-10-19 06:16:43 +00:00
{
2016-02-19 15:52:56 +00:00
/* RUNNABLE ---> RUNNING */
/* TODO: should i allow this? */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , moo - > processor - > active ! = proc ) ;
switch_to_process ( moo , proc , PROC_STATE_RUNNABLE ) ;
2015-10-19 06:16:43 +00:00
}
2016-02-19 15:52:56 +00:00
# endif
2015-10-18 15:06:17 +00:00
}
2017-01-09 09:54:49 +00:00
static void suspend_process ( moo_t * moo , moo_oop_process_t proc )
2016-02-18 17:49:56 +00:00
{
2017-01-09 09:54:49 +00:00
if ( proc - > state = = MOO_SMOOI_TO_OOP ( PROC_STATE_RUNNING ) | |
proc - > state = = MOO_SMOOI_TO_OOP ( PROC_STATE_RUNNABLE ) )
2016-02-18 17:49:56 +00:00
{
2016-02-19 15:52:56 +00:00
/* RUNNING/RUNNABLE ---> SUSPENDED */
2017-01-09 09:54:49 +00:00
# if defined(MOO_DEBUG_VM_PROCESSOR)
MOO_LOG1 ( moo , MOO_LOG_IC | MOO_LOG_DEBUG , " Processor - process %O RUNNING/RUNNABLE->SUSPENDED \n " , proc ) ;
2016-06-05 18:01:35 +00:00
# endif
2017-01-09 09:54:49 +00:00
if ( proc = = moo - > processor - > active )
2016-02-19 15:52:56 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_process_t nrp ;
2016-02-19 15:52:56 +00:00
2017-01-09 09:54:49 +00:00
nrp = find_next_runnable_process ( moo ) ;
2016-02-19 15:52:56 +00:00
if ( nrp = = proc )
{
/* no runnable process after suspension */
2017-01-09 09:54:49 +00:00
sleep_active_process ( moo , PROC_STATE_RUNNABLE ) ;
unchain_from_processor ( moo , proc , PROC_STATE_SUSPENDED ) ;
2016-02-29 15:27:10 +00:00
2016-03-23 12:58:30 +00:00
/* the last running/runnable process has been unchained
* from the processor and set to SUSPENDED . the active
2016-06-05 18:01:35 +00:00
* process must be the nil process */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , moo - > processor - > active = = moo - > nil_process ) ;
2016-02-19 15:52:56 +00:00
}
else
{
2016-03-23 02:34:13 +00:00
/* keep the unchained process at the runnable state for
* the immediate call to switch_to_process ( ) below */
2017-01-09 09:54:49 +00:00
unchain_from_processor ( moo , proc , PROC_STATE_RUNNABLE ) ;
2016-03-23 02:34:13 +00:00
/* unchain_from_processor() leaves the active process
* untouched unless the unchained process is the last
2016-03-23 12:58:30 +00:00
* running / runnable process . so calling switch_to_process ( )
* which expects the active process to be valid is safe */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , moo - > processor - > active ! = moo - > nil_process ) ;
switch_to_process ( moo , nrp , PROC_STATE_SUSPENDED ) ;
2016-02-19 15:52:56 +00:00
}
}
else
{
2017-01-09 09:54:49 +00:00
unchain_from_processor ( moo , proc , PROC_STATE_SUSPENDED ) ;
2016-02-19 15:52:56 +00:00
}
2016-02-18 17:49:56 +00:00
}
}
2017-01-09 09:54:49 +00:00
static void yield_process ( moo_t * moo , moo_oop_process_t proc )
2016-02-18 17:49:56 +00:00
{
2017-01-09 09:54:49 +00:00
if ( proc - > state = = MOO_SMOOI_TO_OOP ( PROC_STATE_RUNNING ) )
2016-02-19 15:52:56 +00:00
{
/* RUNNING --> RUNNABLE */
2017-01-09 09:54:49 +00:00
moo_oop_process_t nrp ;
2016-02-19 15:52:56 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , proc = = moo - > processor - > active ) ;
2016-02-19 15:52:56 +00:00
2017-01-09 09:54:49 +00:00
nrp = find_next_runnable_process ( moo ) ;
2016-02-19 15:52:56 +00:00
/* if there are more than 1 runnable processes, the next
* runnable process must be different from proc */
2016-02-29 15:27:10 +00:00
if ( nrp ! = proc )
{
2017-01-09 09:54:49 +00:00
# if defined(MOO_DEBUG_VM_PROCESSOR)
MOO_LOG1 ( moo , MOO_LOG_IC | MOO_LOG_DEBUG , " Processor - process %O RUNNING->RUNNABLE \n " , proc ) ;
2016-06-05 18:01:35 +00:00
# endif
2017-01-09 09:54:49 +00:00
switch_to_process ( moo , nrp , PROC_STATE_RUNNABLE ) ;
2016-02-29 15:27:10 +00:00
}
}
}
2017-01-09 09:54:49 +00:00
static int async_signal_semaphore ( moo_t * moo , moo_oop_semaphore_t sem )
2016-02-29 15:27:10 +00:00
{
2017-01-09 09:54:49 +00:00
if ( moo - > sem_list_count > = SEM_LIST_MAX )
2016-03-22 14:18:07 +00:00
{
2017-01-09 09:54:49 +00:00
moo - > errnum = MOO_ESLFULL ;
2016-03-22 14:18:07 +00:00
return - 1 ;
}
2017-01-09 09:54:49 +00:00
if ( moo - > sem_list_count > = moo - > sem_list_capa )
2016-02-29 15:27:10 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oow_t new_capa ;
moo_oop_semaphore_t * tmp ;
2016-03-16 02:27:18 +00:00
2017-01-09 09:54:49 +00:00
new_capa = moo - > sem_list_capa + SEM_LIST_INC ; /* TODO: overflow check.. */
tmp = moo_reallocmem ( moo , moo - > sem_list , MOO_SIZEOF ( moo_oop_semaphore_t ) * new_capa ) ;
2016-03-16 02:27:18 +00:00
if ( ! tmp ) return - 1 ;
2017-01-09 09:54:49 +00:00
moo - > sem_list = tmp ;
moo - > sem_list_capa = new_capa ;
2016-02-19 15:52:56 +00:00
}
2016-02-29 15:27:10 +00:00
2017-01-09 09:54:49 +00:00
moo - > sem_list [ moo - > sem_list_count ] = sem ;
moo - > sem_list_count + + ;
2016-02-29 15:27:10 +00:00
return 0 ;
2016-02-18 17:49:56 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_oop_process_t signal_semaphore ( moo_t * moo , moo_oop_semaphore_t sem )
2016-02-18 17:49:56 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_process_t proc ;
moo_ooi_t count ;
2016-02-18 17:49:56 +00:00
2017-01-09 09:54:49 +00:00
if ( ( moo_oop_t ) sem - > waiting_head = = moo - > _nil )
2016-02-18 17:49:56 +00:00
{
2016-02-29 15:27:10 +00:00
/* no process is waiting on this semaphore */
2017-01-09 09:54:49 +00:00
count = MOO_OOP_TO_SMOOI ( sem - > count ) ;
2016-02-18 17:49:56 +00:00
count + + ;
2017-01-09 09:54:49 +00:00
sem - > count = MOO_SMOOI_TO_OOP ( count ) ;
2016-03-24 14:58:47 +00:00
/* no process has been resumed */
2017-01-09 09:54:49 +00:00
return ( moo_oop_process_t ) moo - > _nil ;
2016-02-18 17:49:56 +00:00
}
else
{
proc = sem - > waiting_head ;
2016-03-24 14:58:47 +00:00
2017-01-09 09:54:49 +00:00
/* [NOTE] no GC must occur as 'proc' isn't protected with moo_pushtmp(). */
2016-03-24 14:58:47 +00:00
2017-01-09 09:54:49 +00:00
unchain_from_semaphore ( moo , proc ) ;
resume_process ( moo , proc ) ; /* TODO: error check */
2016-03-24 14:58:47 +00:00
/* return the resumed process */
return proc ;
2016-02-18 17:49:56 +00:00
}
}
2017-01-09 09:54:49 +00:00
static void await_semaphore ( moo_t * moo , moo_oop_semaphore_t sem )
2016-02-18 17:49:56 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_process_t proc ;
moo_ooi_t count ;
2016-02-18 17:49:56 +00:00
2017-01-09 09:54:49 +00:00
count = MOO_OOP_TO_SMOOI ( sem - > count ) ;
2016-02-18 17:49:56 +00:00
if ( count > 0 )
{
2016-02-29 15:27:10 +00:00
/* it's already signalled */
2016-02-18 17:49:56 +00:00
count - - ;
2017-01-09 09:54:49 +00:00
sem - > count = MOO_SMOOI_TO_OOP ( count ) ;
2016-02-18 17:49:56 +00:00
}
else
{
2016-02-29 15:27:10 +00:00
/* not signaled. need to wait */
2017-01-09 09:54:49 +00:00
proc = moo - > processor - > active ;
2016-02-18 17:49:56 +00:00
2016-02-29 17:26:40 +00:00
/* suspend the active process */
2017-01-09 09:54:49 +00:00
suspend_process ( moo , proc ) ;
2016-02-29 17:26:40 +00:00
2016-03-24 14:58:47 +00:00
/* link the suspended process to the semaphore's process list */
2017-01-09 09:54:49 +00:00
chain_into_semaphore ( moo , proc , sem ) ;
2016-02-18 17:49:56 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , sem - > waiting_tail = = proc ) ;
2016-03-24 14:58:47 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , moo - > processor - > active ! = proc ) ;
2016-02-18 17:49:56 +00:00
}
}
2017-01-09 09:54:49 +00:00
static void sift_up_sem_heap ( moo_t * moo , moo_ooi_t index )
2016-03-22 14:18:07 +00:00
{
if ( index > 0 )
{
2017-01-09 09:54:49 +00:00
moo_ooi_t parent ;
moo_oop_semaphore_t sem , parsem ;
2016-03-22 14:18:07 +00:00
parent = SEM_HEAP_PARENT ( index ) ;
2017-01-09 09:54:49 +00:00
sem = moo - > sem_heap [ index ] ;
parsem = moo - > sem_heap [ parent ] ;
if ( SEM_HEAP_EARLIER_THAN ( moo , sem , parsem ) )
2016-03-22 14:18:07 +00:00
{
do
{
/* move down the parent to the current position */
2017-01-09 09:54:49 +00:00
parsem - > heap_index = MOO_SMOOI_TO_OOP ( index ) ;
moo - > sem_heap [ index ] = parsem ;
2016-03-22 14:18:07 +00:00
/* traverse up */
index = parent ;
if ( index < = 0 ) break ;
parent = SEM_HEAP_PARENT ( parent ) ;
2017-01-09 09:54:49 +00:00
parsem = moo - > sem_heap [ parent ] ;
2016-03-22 14:18:07 +00:00
}
2017-01-09 09:54:49 +00:00
while ( SEM_HEAP_EARLIER_THAN ( moo , sem , parsem ) ) ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
sem - > heap_index = MOO_SMOOI_TO_OOP ( index ) ;
moo - > sem_heap [ index ] = sem ;
2016-03-22 14:18:07 +00:00
}
}
}
2017-01-09 09:54:49 +00:00
static void sift_down_sem_heap ( moo_t * moo , moo_ooi_t index )
2016-03-22 14:18:07 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t base = moo - > sem_heap_count / 2 ;
2016-03-22 14:18:07 +00:00
if ( index < base ) /* at least 1 child is under the 'index' position */
{
2017-01-09 09:54:49 +00:00
moo_ooi_t left , right , child ;
moo_oop_semaphore_t sem , chisem ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
sem = moo - > sem_heap [ index ] ;
2016-03-22 14:18:07 +00:00
do
{
left = SEM_HEAP_LEFT ( index ) ;
right = SEM_HEAP_RIGHT ( index ) ;
2017-01-09 09:54:49 +00:00
if ( right < moo - > sem_heap_count & & SEM_HEAP_EARLIER_THAN ( moo , moo - > sem_heap [ left ] , moo - > sem_heap [ right ] ) )
2016-03-22 14:18:07 +00:00
{
child = right ;
}
else
{
child = left ;
}
2017-01-09 09:54:49 +00:00
chisem = moo - > sem_heap [ child ] ;
if ( SEM_HEAP_EARLIER_THAN ( moo , sem , chisem ) ) break ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
chisem - > heap_index = MOO_SMOOI_TO_OOP ( index ) ;
moo - > sem_heap [ index ] = chisem ;
2016-03-22 14:18:07 +00:00
index = child ;
}
while ( index < base ) ;
2017-01-09 09:54:49 +00:00
sem - > heap_index = MOO_SMOOI_TO_OOP ( index ) ;
moo - > sem_heap [ index ] = sem ;
2016-03-22 14:18:07 +00:00
}
}
2017-01-09 09:54:49 +00:00
static int add_to_sem_heap ( moo_t * moo , moo_oop_semaphore_t sem )
2016-03-22 14:18:07 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t index ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
if ( moo - > sem_heap_count > = SEM_HEAP_MAX )
2016-03-22 14:18:07 +00:00
{
2017-01-09 09:54:49 +00:00
moo - > errnum = MOO_ESHFULL ;
2016-03-22 14:18:07 +00:00
return - 1 ;
}
2017-01-09 09:54:49 +00:00
if ( moo - > sem_heap_count > = moo - > sem_heap_capa )
2016-03-22 14:18:07 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oow_t new_capa ;
moo_oop_semaphore_t * tmp ;
2016-03-22 14:18:07 +00:00
/* no overflow check when calculating the new capacity
* owing to SEM_HEAP_MAX check above */
2017-01-09 09:54:49 +00:00
new_capa = moo - > sem_heap_capa + SEM_HEAP_INC ;
tmp = moo_reallocmem ( moo , moo - > sem_heap , MOO_SIZEOF ( moo_oop_semaphore_t ) * new_capa ) ;
2016-03-22 14:18:07 +00:00
if ( ! tmp ) return - 1 ;
2017-01-09 09:54:49 +00:00
moo - > sem_heap = tmp ;
moo - > sem_heap_capa = new_capa ;
2016-03-22 14:18:07 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , moo - > sem_heap_count < = MOO_SMOOI_MAX ) ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
index = moo - > sem_heap_count ;
moo - > sem_heap [ index ] = sem ;
sem - > heap_index = MOO_SMOOI_TO_OOP ( index ) ;
moo - > sem_heap_count + + ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
sift_up_sem_heap ( moo , index ) ;
2016-03-22 14:18:07 +00:00
return 0 ;
}
2017-01-09 09:54:49 +00:00
static void delete_from_sem_heap ( moo_t * moo , moo_ooi_t index )
2016-03-22 14:18:07 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_semaphore_t sem , lastsem ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
sem = moo - > sem_heap [ index ] ;
sem - > heap_index = MOO_SMOOI_TO_OOP ( - 1 ) ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
moo - > sem_heap_count - - ;
if ( moo - > sem_heap_count > 0 & & index ! = moo - > sem_heap_count )
2016-03-22 14:18:07 +00:00
{
/* move the last item to the deletion position */
2017-01-09 09:54:49 +00:00
lastsem = moo - > sem_heap [ moo - > sem_heap_count ] ;
lastsem - > heap_index = MOO_SMOOI_TO_OOP ( index ) ;
moo - > sem_heap [ index ] = lastsem ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
if ( SEM_HEAP_EARLIER_THAN ( moo , lastsem , sem ) )
sift_up_sem_heap ( moo , index ) ;
2016-03-22 14:18:07 +00:00
else
2017-01-09 09:54:49 +00:00
sift_down_sem_heap ( moo , index ) ;
2016-03-22 14:18:07 +00:00
}
}
2017-01-09 09:54:49 +00:00
static void update_sem_heap ( moo_t * moo , moo_ooi_t index , moo_oop_semaphore_t newsem )
2016-03-22 14:18:07 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_semaphore_t sem ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
sem = moo - > sem_heap [ index ] ;
sem - > heap_index = MOO_SMOOI_TO_OOP ( - 1 ) ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
newsem - > heap_index = MOO_SMOOI_TO_OOP ( index ) ;
moo - > sem_heap [ index ] = newsem ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
if ( SEM_HEAP_EARLIER_THAN ( moo , newsem , sem ) )
sift_up_sem_heap ( moo , index ) ;
2016-03-22 14:18:07 +00:00
else
2017-01-09 09:54:49 +00:00
sift_down_sem_heap ( moo , index ) ;
2016-03-22 14:18:07 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_oop_process_t start_initial_process ( moo_t * moo , moo_oop_context_t c )
2015-12-02 15:24:13 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_process_t proc ;
2015-12-02 15:24:13 +00:00
2016-02-12 16:23:26 +00:00
/* there must be no active process when this function is called */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , moo - > processor - > tally = = MOO_SMOOI_TO_OOP ( 0 ) ) ;
MOO_ASSERT ( moo , moo - > processor - > active = = moo - > nil_process ) ;
2016-02-12 16:23:26 +00:00
2017-01-09 09:54:49 +00:00
proc = make_process ( moo , c ) ;
if ( ! proc ) return MOO_NULL ;
2015-10-18 15:06:17 +00:00
2017-01-09 09:54:49 +00:00
if ( chain_into_processor ( moo , proc ) < = - 1 ) return MOO_NULL ;
proc - > state = MOO_SMOOI_TO_OOP ( PROC_STATE_RUNNING ) ; /* skip RUNNABLE and go to RUNNING */
moo - > processor - > active = proc ;
2016-02-12 16:23:26 +00:00
2016-02-18 17:49:56 +00:00
/* do somthing that resume_process() would do with less overhead */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , ( moo_oop_t ) proc - > current_context ! = moo - > _nil ) ;
MOO_ASSERT ( moo , proc - > current_context = = proc - > initial_context ) ;
SWITCH_ACTIVE_CONTEXT ( moo , proc - > current_context ) ;
2016-02-12 16:23:26 +00:00
2015-12-02 15:24:13 +00:00
return proc ;
}
2015-10-13 14:51:04 +00:00
2017-01-09 09:54:49 +00:00
static MOO_INLINE int activate_new_method ( moo_t * moo , moo_oop_method_t mth , moo_ooi_t actual_nargs )
2015-06-04 18:34:37 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_context_t ctx ;
moo_ooi_t i , j ;
moo_ooi_t ntmprs , nargs , actual_ntmprs ;
2015-06-04 18:34:37 +00:00
2017-01-09 09:54:49 +00:00
ntmprs = MOO_OOP_TO_SMOOI ( mth - > tmpr_count ) ;
nargs = MOO_OOP_TO_SMOOI ( mth - > tmpr_nargs ) ;
2016-05-02 13:50:42 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , ntmprs > = 0 ) ;
MOO_ASSERT ( moo , nargs < = ntmprs ) ;
2015-06-04 18:34:37 +00:00
2016-12-14 07:18:01 +00:00
if ( actual_nargs > nargs )
{
/* more arguments than the method specification have been passed in.
* it must be a variadic unary method . othewise , the compiler is buggy */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_METHOD_GET_PREAMBLE_FLAGS ( MOO_OOP_TO_SMOOI ( mth - > preamble ) ) & MOO_METHOD_PREAMBLE_FLAG_VARIADIC ) ;
2016-12-14 07:18:01 +00:00
actual_ntmprs = ntmprs + ( actual_nargs - nargs ) ;
}
else actual_ntmprs = ntmprs ;
2017-01-09 09:54:49 +00:00
moo_pushtmp ( moo , ( moo_oop_t * ) & mth ) ;
ctx = ( moo_oop_context_t ) moo_instantiate ( moo , moo - > _method_context , MOO_NULL , actual_ntmprs ) ;
moo_poptmp ( moo ) ;
2015-06-26 15:49:08 +00:00
if ( ! ctx ) return - 1 ;
2017-01-09 09:54:49 +00:00
ctx - > sender = moo - > active_context ;
ctx - > ip = MOO_SMOOI_TO_OOP ( 0 ) ;
2016-05-02 13:50:42 +00:00
/* ctx->sp will be set further down */
2016-06-24 15:01:51 +00:00
/* A context is compose of a fixed part and a variable part.
2016-12-13 15:18:19 +00:00
* the variable part holds temporary varibles including arguments .
2015-06-06 07:24:35 +00:00
*
2016-06-24 15:01:51 +00:00
* Assuming a method context with 2 arguments and 3 local temporary
* variables , the context will look like this .
2015-06-06 07:24:35 +00:00
* + - - - - - - - - - - - - - - - - - - - - - +
* | fixed part |
* | |
* | |
* | |
* + - - - - - - - - - - - - - - - - - - - - - +
* | tmp1 ( arg1 ) | slot [ 0 ]
* | tmp2 ( arg2 ) | slot [ 1 ]
2016-06-24 15:01:51 +00:00
* | tmp3 | slot [ 2 ]
* | tmp4 | slot [ 3 ]
* | tmp5 | slot [ 4 ]
2015-06-06 07:24:35 +00:00
* + - - - - - - - - - - - - - - - - - - - - - +
*/
2016-06-24 15:01:51 +00:00
2017-01-09 09:54:49 +00:00
ctx - > ntmprs = MOO_SMOOI_TO_OOP ( ntmprs ) ;
ctx - > method_or_nargs = ( moo_oop_t ) mth ;
/* the 'home' field of a method context is always moo->_nil.
ctx - > home = moo - > _nil ; */
2015-06-21 14:45:45 +00:00
ctx - > origin = ctx ; /* point to self */
2015-06-04 18:34:37 +00:00
/*
2015-06-06 07:24:35 +00:00
* Assume this message sending expression :
2015-06-04 18:34:37 +00:00
* obj1 do : # this with : # that with : # it
*
2015-06-06 07:24:35 +00:00
* It would be compiled to these logical byte - code sequences shown below :
2015-06-04 18:34:37 +00:00
* 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.
*/
2016-12-14 07:18:01 +00:00
if ( actual_nargs > = nargs )
2015-06-04 18:34:37 +00:00
{
2016-12-14 07:18:01 +00:00
for ( i = actual_nargs , j = ntmprs + ( actual_nargs - nargs ) ; i > nargs ; i - - )
{
/* place variadic arguments after local temporaries */
2017-01-09 09:54:49 +00:00
ctx - > slot [ - - j ] = MOO_STACK_GETTOP ( moo ) ;
MOO_STACK_POP ( moo ) ;
2016-12-14 07:18:01 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , i = = nargs ) ;
2016-12-14 07:18:01 +00:00
while ( i > 0 )
{
/* place normal argument before local temporaries */
2017-01-09 09:54:49 +00:00
ctx - > slot [ - - i ] = MOO_STACK_GETTOP ( moo ) ;
MOO_STACK_POP ( moo ) ;
2016-12-14 07:18:01 +00:00
}
}
else
{
for ( i = actual_nargs ; i > 0 ; )
{
/* place normal argument before local temporaries */
2017-01-09 09:54:49 +00:00
ctx - > slot [ - - i ] = MOO_STACK_GETTOP ( moo ) ;
MOO_STACK_POP ( moo ) ;
2016-12-14 07:18:01 +00:00
}
2015-06-04 18:34:37 +00:00
}
2015-06-09 12:14:18 +00:00
/* copy receiver */
2017-01-09 09:54:49 +00:00
ctx - > receiver_or_source = MOO_STACK_GETTOP ( moo ) ;
MOO_STACK_POP ( moo ) ;
2015-06-04 18:34:37 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , moo - > sp > = - 1 ) ;
2015-06-04 18:34:37 +00:00
2016-06-24 15:01:51 +00:00
/* the stack pointer in a context is a stack pointer of a process
* before it is activated . this stack pointer is stored to the context
* so that it is used to restore the process stack pointer upon returning
* from a method context . */
2017-01-09 09:54:49 +00:00
ctx - > sp = MOO_SMOOI_TO_OOP ( moo - > sp ) ;
2016-02-16 17:00:10 +00:00
2016-06-24 15:01:51 +00:00
/* switch the active context to the newly instantiated one*/
2017-01-09 09:54:49 +00:00
SWITCH_ACTIVE_CONTEXT ( moo , ctx ) ;
2015-06-08 13:24:02 +00:00
2015-06-04 18:34:37 +00:00
return 0 ;
}
2017-01-09 09:54:49 +00:00
static moo_oop_method_t find_method ( moo_t * moo , moo_oop_t receiver , const moo_oocs_t * message , int super )
2015-06-04 18:34:37 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_class_t cls ;
moo_oop_association_t ass ;
moo_oop_t c ;
moo_oop_set_t mthdic ;
2015-06-06 07:24:35 +00:00
int dic_no ;
2015-06-08 13:24:02 +00:00
/* TODO: implement method lookup cache */
2015-06-04 18:34:37 +00:00
2017-01-09 09:54:49 +00:00
cls = ( moo_oop_class_t ) MOO_CLASSOF ( moo , receiver ) ;
if ( ( moo_oop_t ) cls = = moo - > _class )
2015-06-04 18:34:37 +00:00
{
2016-05-03 10:10:28 +00:00
/* receiver is a class object (an instance of Class) */
2015-06-08 13:24:02 +00:00
c = receiver ;
2017-01-09 09:54:49 +00:00
dic_no = MOO_METHOD_CLASS ;
2015-06-08 13:24:02 +00:00
}
2015-06-04 18:34:37 +00:00
else
{
2016-11-21 13:56:20 +00:00
/* receiver is not a class object. so take its class */
2017-01-09 09:54:49 +00:00
c = ( moo_oop_t ) cls ;
dic_no = MOO_METHOD_INSTANCE ;
2015-06-06 07:24:35 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , c ! = moo - > _nil ) ;
2016-11-21 13:56:20 +00:00
if ( super )
2015-06-06 07:24:35 +00:00
{
2016-11-21 13:56:20 +00:00
/*
2017-01-09 09:54:49 +00:00
moo_oop_method_t m ;
MOO_ASSERT ( moo , MOO_CLASSOF ( moo , moo - > active_context - > origin ) = = moo - > _method_context ) ;
m = ( moo_oop_method_t ) moo - > active_context - > origin - > method_or_nargs ;
c = ( ( moo_oop_class_t ) m - > owner ) - > superclass ;
2016-11-21 13:56:20 +00:00
*/
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , moo - > active_method ) ;
MOO_ASSERT ( moo , moo - > active_method - > owner ) ;
c = ( ( moo_oop_class_t ) moo - > active_method - > owner ) - > superclass ;
if ( c = = moo - > _nil ) goto not_found ; /* reached the top of the hierarchy */
2016-11-21 13:56:20 +00:00
}
2015-06-06 07:24:35 +00:00
2016-11-21 13:56:20 +00:00
do
{
2017-01-09 09:54:49 +00:00
mthdic = ( ( moo_oop_class_t ) c ) - > mthdic [ dic_no ] ;
MOO_ASSERT ( moo , ( moo_oop_t ) mthdic ! = moo - > _nil ) ;
MOO_ASSERT ( moo , MOO_CLASSOF ( moo , mthdic ) = = moo - > _method_dictionary ) ;
2015-06-09 12:14:18 +00:00
2017-01-09 09:54:49 +00:00
ass = ( moo_oop_association_t ) moo_lookupdic ( moo , mthdic , message ) ;
2016-11-21 13:56:20 +00:00
if ( ass )
{
/* found the method */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_CLASSOF ( moo , ass - > value ) = = moo - > _method ) ;
return ( moo_oop_method_t ) ass - > value ;
2015-06-06 07:24:35 +00:00
}
2017-01-09 09:54:49 +00:00
c = ( ( moo_oop_class_t ) c ) - > superclass ;
2015-06-04 18:34:37 +00:00
}
2017-01-09 09:54:49 +00:00
while ( c ! = moo - > _nil ) ;
2015-06-04 18:34:37 +00:00
2015-06-09 12:14:18 +00:00
not_found :
2017-01-09 09:54:49 +00:00
if ( ( moo_oop_t ) cls = = moo - > _class )
2016-05-03 10:10:28 +00:00
{
/* the object is an instance of Class. find the method
* in an instance method dictionary of Class also */
2017-01-09 09:54:49 +00:00
mthdic = ( ( moo_oop_class_t ) cls ) - > mthdic [ MOO_METHOD_INSTANCE ] ;
MOO_ASSERT ( moo , ( moo_oop_t ) mthdic ! = moo - > _nil ) ;
MOO_ASSERT ( moo , MOO_CLASSOF ( moo , mthdic ) = = moo - > _method_dictionary ) ;
2016-05-03 10:10:28 +00:00
2017-01-09 09:54:49 +00:00
ass = ( moo_oop_association_t ) moo_lookupdic ( moo , mthdic , message ) ;
2016-05-03 10:10:28 +00:00
if ( ass )
{
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_CLASSOF ( moo , ass - > value ) = = moo - > _method ) ;
return ( moo_oop_method_t ) ass - > value ;
2016-05-03 10:10:28 +00:00
}
}
2017-01-09 09:54:49 +00:00
MOO_DEBUG3 ( moo , " Method [%.*js] not found for %O \n " , message - > len , message - > ptr , receiver ) ;
moo - > errnum = MOO_ENOENT ;
return MOO_NULL ;
2015-06-04 18:34:37 +00:00
}
2017-01-09 09:54:49 +00:00
static int start_initial_process_and_context ( moo_t * moo , const moo_oocs_t * objname , const moo_oocs_t * mthname )
2015-06-04 18:34:37 +00:00
{
2015-06-08 13:24:02 +00:00
/* 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
*/
2017-01-09 09:54:49 +00:00
moo_oop_context_t ctx ;
moo_oop_association_t ass ;
moo_oop_method_t mth ;
moo_oop_process_t proc ;
2015-06-08 13:24:02 +00:00
2016-06-24 15:01:51 +00:00
/* create a fake initial context. */
2017-01-09 09:54:49 +00:00
ctx = ( moo_oop_context_t ) moo_instantiate ( moo , moo - > _method_context , MOO_NULL , 0 ) ;
2015-06-08 13:24:02 +00:00
if ( ! ctx ) return - 1 ;
2015-06-04 18:34:37 +00:00
2017-01-09 09:54:49 +00:00
ass = moo_lookupsysdic ( moo , objname ) ;
2015-06-04 18:34:37 +00:00
if ( ! ass ) return - 1 ;
2017-01-09 09:54:49 +00:00
mth = find_method ( moo , ass - > value , mthname , 0 ) ;
2015-06-04 18:34:37 +00:00
if ( ! mth ) return - 1 ;
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_TO_SMOOI ( mth - > tmpr_nargs ) > 0 )
2015-06-06 07:24:35 +00:00
{
/* this method expects more than 0 arguments.
* i can ' t use it as a start - up method .
TODO : overcome this problem
*/
2017-01-09 09:54:49 +00:00
moo - > errnum = MOO_EINVAL ;
2015-06-06 07:24:35 +00:00
return - 1 ;
}
2015-06-14 07:15:53 +00:00
/* TODO: handle preamble */
2015-06-06 07:24:35 +00:00
/* the initial context starts the life of the entire VM
* and is not really worked on except that it is used to call the
2016-02-11 14:26:26 +00:00
* initial method . so it doesn ' t really require any extra stack space . */
/* TODO: verify this theory of mine. */
2017-01-09 09:54:49 +00:00
moo - > ip = 0 ;
moo - > sp = - 1 ;
2015-06-25 13:37:50 +00:00
2017-01-09 09:54:49 +00:00
ctx - > ip = MOO_SMOOI_TO_OOP ( 0 ) ; /* point to the beginning */
ctx - > sp = MOO_SMOOI_TO_OOP ( - 1 ) ; /* pointer to -1 below the bottom */
2016-02-11 14:26:26 +00:00
ctx - > origin = ctx ; /* point to self */
2017-01-09 09:54:49 +00:00
ctx - > method_or_nargs = ( moo_oop_t ) mth ; /* fake. help SWITCH_ACTIVE_CONTEXT() not fail. TODO: create a static fake method and use it... instead of 'mth' */
2015-10-18 15:06:17 +00:00
/* [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 */
2015-06-04 18:34:37 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , moo - > active_context = = MOO_NULL ) ;
MOO_ASSERT ( moo , moo - > active_method = = MOO_NULL ) ;
2015-06-20 03:07:11 +00:00
2017-01-09 09:54:49 +00:00
/* moo_gc() uses moo->processor when moo->active_context
* is not NULL . at this poinst , moo - > processor should point to
2016-02-12 16:23:26 +00:00
* an instance of ProcessScheduler . */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , ( moo_oop_t ) moo - > processor ! = moo - > _nil ) ;
MOO_ASSERT ( moo , moo - > processor - > tally = = MOO_SMOOI_TO_OOP ( 0 ) ) ;
2015-06-16 04:31:28 +00:00
2016-02-12 16:23:26 +00:00
/* start_initial_process() calls the SWITCH_ACTIVE_CONTEXT() macro.
2017-01-09 09:54:49 +00:00
* the macro assumes a non - null value in moo - > active_context .
2016-02-12 16:23:26 +00:00
* let ' s force set active_context to ctx directly . */
2017-01-09 09:54:49 +00:00
moo - > active_context = ctx ;
2016-02-12 16:23:26 +00:00
2017-01-09 09:54:49 +00:00
moo_pushtmp ( moo , ( moo_oop_t * ) & ctx ) ;
moo_pushtmp ( moo , ( moo_oop_t * ) & mth ) ;
moo_pushtmp ( moo , ( moo_oop_t * ) & ass ) ;
proc = start_initial_process ( moo , ctx ) ;
moo_poptmps ( moo , 3 ) ;
2015-10-18 15:06:17 +00:00
if ( ! proc ) return - 1 ;
2017-01-09 09:54:49 +00:00
MOO_STACK_PUSH ( moo , ass - > value ) ; /* push the receiver - the object referenced by 'objname' */
STORE_ACTIVE_SP ( moo ) ; /* moo->active_context->sp = MOO_SMOOI_TO_OOP(moo->sp) */
2016-02-12 16:23:26 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , moo - > processor - > active = = proc ) ;
MOO_ASSERT ( moo , moo - > processor - > active - > initial_context = = ctx ) ;
MOO_ASSERT ( moo , moo - > processor - > active - > current_context = = ctx ) ;
MOO_ASSERT ( moo , moo - > active_context = = ctx ) ;
2016-02-12 16:23:26 +00:00
/* emulate the message sending */
2017-01-09 09:54:49 +00:00
return activate_new_method ( moo , mth , 0 ) ;
2015-06-04 18:34:37 +00:00
}
2015-10-03 15:29:03 +00:00
/* ------------------------------------------------------------------------- */
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_dump ( moo_t * moo , moo_ooi_t nargs )
2015-06-11 09:11:18 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t i ;
2015-06-11 09:11:18 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs > = 0 ) ;
2015-06-14 07:15:53 +00:00
2017-01-09 09:54:49 +00:00
moo_logbfmt ( moo , 0 , " RECEIVER: %O \n " , MOO_STACK_GET ( moo , moo - > sp - nargs ) ) ;
2015-06-14 07:15:53 +00:00
for ( i = nargs ; i > 0 ; )
2015-06-09 12:14:18 +00:00
{
2015-06-14 07:15:53 +00:00
- - i ;
2017-01-09 09:54:49 +00:00
moo_logbfmt ( moo , 0 , " ARGUMENT %zd: %O \n " , i , MOO_STACK_GET ( moo , moo - > sp - i ) ) ;
2015-06-14 07:15:53 +00:00
}
2015-06-11 09:11:18 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRETTORCV ( moo , nargs ) ; /* ^self */
return MOO_PF_SUCCESS ;
2015-06-14 07:15:53 +00:00
}
2015-06-09 12:14:18 +00:00
2017-01-09 09:54:49 +00:00
static void log_char_object ( moo_t * moo , moo_oow_t mask , moo_oop_char_t msg )
2016-07-01 16:31:47 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t n ;
moo_oow_t rem ;
const moo_ooch_t * ptr ;
2016-07-01 16:31:47 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_OBJ_GET_FLAGS_TYPE ( msg ) = = MOO_OBJ_TYPE_CHAR ) ;
2016-07-01 16:31:47 +00:00
2017-01-09 09:54:49 +00:00
rem = MOO_OBJ_GET_SIZE ( msg ) ;
2016-07-01 16:31:47 +00:00
ptr = msg - > slot ;
start_over :
while ( rem > 0 )
{
if ( * ptr = = ' \0 ' )
{
2017-01-09 09:54:49 +00:00
n = moo_logbfmt ( moo , mask , " %jc " , * ptr ) ;
MOO_ASSERT ( moo , n = = 1 ) ;
2016-07-01 16:31:47 +00:00
rem - = n ;
ptr + = n ;
goto start_over ;
}
2017-01-09 09:54:49 +00:00
n = moo_logbfmt ( moo , mask , " %.*js " , rem , ptr ) ;
2016-07-01 16:31:47 +00:00
if ( n < = - 1 ) break ;
if ( n = = 0 )
{
/* to skip the unprinted character.
2017-01-06 10:42:59 +00:00
* actually , this check is not needed because of ' \0 ' skipped
2016-07-01 16:31:47 +00:00
* at the beginning of the loop */
2017-01-09 09:54:49 +00:00
n = moo_logbfmt ( moo , mask , " %jc " , * ptr ) ;
MOO_ASSERT ( moo , n = = 1 ) ;
2016-07-01 16:31:47 +00:00
}
rem - = n ;
ptr + = n ;
}
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_log ( moo_t * moo , moo_ooi_t nargs )
2016-06-30 13:44:37 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t msg , level ;
moo_oow_t mask ;
moo_ooi_t k ;
2016-06-30 13:44:37 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs > = 2 ) ;
2016-06-30 13:44:37 +00:00
2017-01-09 09:54:49 +00:00
level = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
if ( ! MOO_OOP_IS_SMOOI ( level ) ) mask = MOO_LOG_APP | MOO_LOG_INFO ;
else mask = MOO_LOG_APP | MOO_OOP_TO_SMOOI ( level ) ;
2016-06-30 13:44:37 +00:00
2016-10-06 17:50:27 +00:00
for ( k = 1 ; k < nargs ; k + + )
2016-06-30 13:44:37 +00:00
{
2017-01-09 09:54:49 +00:00
msg = MOO_STACK_GETARG ( moo , nargs , k ) ;
2016-06-30 13:44:37 +00:00
2017-01-09 09:54:49 +00:00
if ( msg = = moo - > _nil | | msg = = moo - > _true | | msg = = moo - > _false )
2016-07-01 16:31:47 +00:00
{
goto dump_object ;
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_POINTER ( msg ) )
2016-06-30 13:44:37 +00:00
{
2017-01-09 09:54:49 +00:00
if ( MOO_OBJ_GET_FLAGS_TYPE ( msg ) = = MOO_OBJ_TYPE_CHAR )
2016-06-30 13:44:37 +00:00
{
2017-01-09 09:54:49 +00:00
log_char_object ( moo , mask , ( moo_oop_char_t ) msg ) ;
2016-06-30 13:44:37 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OBJ_GET_FLAGS_TYPE ( msg ) = = MOO_OBJ_TYPE_OOP )
2016-06-30 13:44:37 +00:00
{
2016-07-01 16:31:47 +00:00
/* visit only 1-level down into an array-like object */
2017-01-09 09:54:49 +00:00
moo_oop_t inner , _class ;
moo_oow_t i , spec ;
2016-07-01 16:31:47 +00:00
2017-01-09 09:54:49 +00:00
_class = MOO_CLASSOF ( moo , msg ) ;
2016-07-04 15:36:10 +00:00
2017-01-09 09:54:49 +00:00
spec = MOO_OOP_TO_SMOOI ( ( ( moo_oop_class_t ) _class ) - > spec ) ;
if ( MOO_CLASS_SPEC_NAMED_INSTVAR ( spec ) > 0 | | ! MOO_CLASS_SPEC_IS_INDEXED ( spec ) ) goto dump_object ;
2016-07-01 16:31:47 +00:00
2017-01-09 09:54:49 +00:00
for ( i = 0 ; i < MOO_OBJ_GET_SIZE ( msg ) ; i + + )
2016-07-01 16:31:47 +00:00
{
2017-01-09 09:54:49 +00:00
inner = ( ( moo_oop_oop_t ) msg ) - > slot [ i ] ;
2016-07-04 15:36:10 +00:00
2017-01-09 09:54:49 +00:00
if ( i > 0 ) moo_logbfmt ( moo , mask , " " ) ;
if ( MOO_OOP_IS_POINTER ( inner ) & &
MOO_OBJ_GET_FLAGS_TYPE ( inner ) = = MOO_OBJ_TYPE_CHAR )
2016-07-01 16:31:47 +00:00
{
2017-01-09 09:54:49 +00:00
log_char_object ( moo , mask , ( moo_oop_char_t ) inner ) ;
2016-07-01 16:31:47 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
moo_logbfmt ( moo , mask , " %O " , inner ) ;
2016-07-01 16:31:47 +00:00
}
}
2016-06-30 13:44:37 +00:00
}
2016-07-01 16:31:47 +00:00
else goto dump_object ;
}
else
{
dump_object :
2017-01-09 09:54:49 +00:00
moo_logbfmt ( moo , mask , " %O " , msg ) ;
2016-06-30 13:44:37 +00:00
}
}
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRETTORCV ( moo , nargs ) ; /* ^self */
return MOO_PF_SUCCESS ;
2016-06-30 13:44:37 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_identical ( moo_t * moo , moo_ooi_t nargs )
2015-10-08 14:26:04 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg , b ;
2015-10-08 14:26:04 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-10-08 14:26:04 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-10-08 14:26:04 +00:00
2017-01-09 09:54:49 +00:00
b = ( rcv = = arg ) ? moo - > _true : moo - > _false ;
2015-10-08 14:26:04 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , b ) ;
return MOO_PF_SUCCESS ;
2015-10-08 14:26:04 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_not_identical ( moo_t * moo , moo_ooi_t nargs )
2015-10-08 14:26:04 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg , b ;
2015-10-08 14:26:04 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-10-08 14:26:04 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-10-08 14:26:04 +00:00
2017-01-09 09:54:49 +00:00
b = ( rcv ! = arg ) ? moo - > _true : moo - > _false ;
2015-10-08 14:26:04 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , b ) ;
return MOO_PF_SUCCESS ;
2015-10-08 14:26:04 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t _equal_objects ( moo_t * moo , moo_ooi_t nargs )
2017-01-06 09:53:40 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg ;
2017-01-06 13:27:49 +00:00
int rtag ;
2017-01-06 09:53:40 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2017-01-06 09:53:40 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2017-01-06 13:27:49 +00:00
if ( rcv = = arg ) return 1 ; /* identical. so equal */
2017-01-06 09:53:40 +00:00
2017-01-09 09:54:49 +00:00
rtag = MOO_OOP_GET_TAG ( rcv ) ;
if ( rtag ! = MOO_OOP_GET_TAG ( arg ) ) return 0 ;
2017-01-06 09:53:40 +00:00
2017-01-09 09:54:49 +00:00
switch ( MOO_OOP_GET_TAG ( rcv ) )
2017-01-06 13:27:49 +00:00
{
2017-01-09 09:54:49 +00:00
case MOO_OOP_TAG_SMINT :
return MOO_OOP_TO_SMOOI ( rcv ) = = MOO_OOP_TO_SMOOI ( arg ) ? 1 : 0 ;
2017-01-06 13:27:49 +00:00
2017-01-09 09:54:49 +00:00
case MOO_OOP_TAG_CHAR :
return MOO_OOP_TO_CHAR ( rcv ) = = MOO_OOP_TO_CHAR ( arg ) ? 1 : 0 ;
2017-01-06 13:27:49 +00:00
2017-01-09 09:54:49 +00:00
case MOO_OOP_TAG_ERROR :
return MOO_OOP_TO_ERROR ( rcv ) = = MOO_OOP_TO_ERROR ( arg ) ? 1 : 0 ;
2017-01-06 13:27:49 +00:00
default :
{
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_OOP_IS_POINTER ( rcv ) ) ;
2017-01-06 13:27:49 +00:00
2017-01-09 09:54:49 +00:00
if ( MOO_OBJ_GET_CLASS ( rcv ) ! = MOO_OBJ_GET_CLASS ( arg ) ) return 0 ; /* different class, not equal */
MOO_ASSERT ( moo , MOO_OBJ_GET_FLAGS_TYPE ( rcv ) = = MOO_OBJ_GET_FLAGS_TYPE ( arg ) ) ;
2017-01-06 13:27:49 +00:00
2017-01-09 09:54:49 +00:00
if ( MOO_OBJ_GET_CLASS ( rcv ) = = moo - > _class & & rcv ! = arg )
2017-01-06 13:27:49 +00:00
{
/* a class object are supposed to be unique */
return 0 ;
}
2017-01-09 09:54:49 +00:00
if ( MOO_OBJ_GET_SIZE ( rcv ) ! = MOO_OBJ_GET_SIZE ( arg ) ) return 0 ; /* different size, not equal */
2017-01-06 13:27:49 +00:00
2017-01-09 09:54:49 +00:00
switch ( MOO_OBJ_GET_FLAGS_TYPE ( rcv ) )
2017-01-06 13:27:49 +00:00
{
2017-01-09 09:54:49 +00:00
case MOO_OBJ_TYPE_BYTE :
case MOO_OBJ_TYPE_CHAR :
case MOO_OBJ_TYPE_HALFWORD :
case MOO_OBJ_TYPE_WORD :
return ( MOO_MEMCMP ( ( ( moo_oop_byte_t ) rcv ) - > slot , ( ( moo_oop_byte_t ) arg ) - > slot , MOO_BYTESOF ( moo , rcv ) ) = = 0 ) ? 1 : 0 ;
2017-01-06 13:27:49 +00:00
default :
2017-01-09 09:54:49 +00:00
if ( rcv = = moo - > _nil ) return arg = = moo - > _nil ? 1 : 0 ;
if ( rcv = = moo - > _true ) return arg = = moo - > _true ? 1 : 0 ;
if ( rcv = = moo - > _false ) return arg = = moo - > _false ? 1 : 0 ;
2017-01-06 13:27:49 +00:00
2017-01-09 09:54:49 +00:00
/* MOO_OBJ_TYPE_OOP, ... */
MOO_DEBUG1 ( moo , " <_equal_objects> Cannot compare objects of type %d \n " , ( int ) MOO_OBJ_GET_FLAGS_TYPE ( rcv ) ) ;
2017-01-06 13:27:49 +00:00
return - 1 ;
}
}
}
2017-01-06 09:53:40 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_equal ( moo_t * moo , moo_ooi_t nargs )
2017-01-06 09:53:40 +00:00
{
2017-01-06 13:27:49 +00:00
int n ;
2017-01-06 09:53:40 +00:00
2017-01-09 09:54:49 +00:00
n = _equal_objects ( moo , nargs ) ;
if ( n < = - 1 ) return MOO_PF_FAILURE ;
2017-01-06 09:53:40 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , ( n ? moo - > _true : moo - > _false ) ) ;
return MOO_PF_SUCCESS ;
2017-01-06 13:27:49 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_not_equal ( moo_t * moo , moo_ooi_t nargs )
2017-01-06 13:27:49 +00:00
{
int n ;
2017-01-06 09:53:40 +00:00
2017-01-09 09:54:49 +00:00
n = _equal_objects ( moo , nargs ) ;
if ( n < = - 1 ) return MOO_PF_FAILURE ;
2017-01-06 09:53:40 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , ( n ? moo - > _false : moo - > _true ) ) ;
return MOO_PF_SUCCESS ;
2017-01-06 09:53:40 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_class ( moo_t * moo , moo_ooi_t nargs )
2015-10-08 14:26:04 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , c ;
2015-10-08 14:26:04 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 0 ) ;
2016-08-13 06:46:14 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
c = MOO_CLASSOF ( moo , rcv ) ;
2016-08-13 06:46:14 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , c ) ;
return MOO_PF_SUCCESS ;
2015-10-08 14:26:04 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_basic_new ( moo_t * moo , moo_ooi_t nargs )
2015-06-14 07:15:53 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , obj ;
2015-06-14 07:15:53 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 0 ) ;
2015-06-14 07:15:53 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
if ( MOO_CLASSOF ( moo , rcv ) ! = moo - > _class )
2015-06-14 07:15:53 +00:00
{
/* the receiver is not a class object */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-06-09 12:14:18 +00:00
}
2017-01-09 09:54:49 +00:00
obj = moo_instantiate ( moo , rcv , MOO_NULL , 0 ) ;
if ( ! obj ) return MOO_PF_HARD_FAILURE ;
2015-06-14 07:15:53 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , obj ) ;
return MOO_PF_SUCCESS ;
2015-06-14 07:15:53 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_basic_new_with_size ( moo_t * moo , moo_ooi_t nargs )
2015-06-14 07:15:53 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , szoop , obj ;
moo_oow_t size ;
2015-06-14 07:15:53 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-06-14 07:15:53 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
if ( MOO_CLASSOF ( moo , rcv ) ! = moo - > _class )
2015-06-14 07:15:53 +00:00
{
/* the receiver is not a class object */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-06-14 07:15:53 +00:00
}
2015-06-12 13:52:30 +00:00
2017-01-09 09:54:49 +00:00
szoop = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
if ( moo_inttooow ( moo , szoop , & size ) < = 0 )
2015-06-14 07:15:53 +00:00
{
2015-12-27 18:02:59 +00:00
/* integer out of range or not integer */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-06-14 07:15:53 +00:00
}
2017-01-09 09:54:49 +00:00
/* moo_instantiate() ignores size if the instance specification
2015-06-16 04:31:28 +00:00
* disallows indexed ( variable ) parts . */
/* TODO: should i check the specification before calling
2017-01-09 09:54:49 +00:00
* moo_instantiate ( ) ? */
obj = moo_instantiate ( moo , rcv , MOO_NULL , size ) ;
2015-06-20 03:07:11 +00:00
if ( ! obj )
{
2017-01-09 09:54:49 +00:00
return MOO_PF_HARD_FAILURE ;
2015-06-20 03:07:11 +00:00
}
2015-06-14 07:15:53 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , obj ) ;
return MOO_PF_SUCCESS ;
2015-06-09 12:14:18 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_ngc_new ( moo_t * moo , moo_ooi_t nargs )
2015-12-27 18:02:59 +00:00
{
2017-01-06 09:53:40 +00:00
/* TODO: implement this.
* if NGC is allowed for non - OOP objects , GC issues get very simple .
*
* also allow NGC code in non - safe mode . in safe mode , ngc_new is same as normal new .
* ngc_dispose should not do anything in safe mode . */
2017-01-09 09:54:49 +00:00
return pf_basic_new ( moo , nargs ) ;
2015-12-27 18:02:59 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_ngc_new_with_size ( moo_t * moo , moo_ooi_t nargs )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
return pf_basic_new_with_size ( moo , nargs ) ;
2015-12-27 18:02:59 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_ngc_dispose ( moo_t * moo , moo_ooi_t nargs )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv ;
2015-12-27 18:02:59 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 0 ) ;
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
2015-12-27 18:02:59 +00:00
2017-01-09 09:54:49 +00:00
moo_freemem ( moo , rcv ) ;
2015-12-27 18:02:59 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , moo - > _nil ) ;
return MOO_PF_SUCCESS ;
2015-12-27 18:02:59 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_shallow_copy ( moo_t * moo , moo_ooi_t nargs )
2015-10-30 15:36:37 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , obj ;
2015-10-30 15:36:37 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 0 ) ;
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
2015-10-30 15:36:37 +00:00
2017-01-09 09:54:49 +00:00
obj = moo_shallowcopy ( moo , rcv ) ;
if ( ! obj ) return MOO_PF_HARD_FAILURE ;
2015-10-30 15:36:37 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , obj ) ;
return MOO_PF_SUCCESS ;
2015-10-30 15:36:37 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_basic_size ( moo_t * moo , moo_ooi_t nargs )
2015-06-21 03:50:35 +00:00
{
2016-06-13 15:52:09 +00:00
/* return the number of indexable fields */
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , sz ;
2015-12-27 18:02:59 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 0 ) ;
2015-06-21 03:50:35 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
2015-12-27 18:02:59 +00:00
2017-01-09 09:54:49 +00:00
if ( ! MOO_OOP_IS_POINTER ( rcv ) )
2016-06-13 15:52:09 +00:00
{
2017-01-09 09:54:49 +00:00
sz = MOO_SMOOI_TO_OOP ( 0 ) ;
2016-06-13 15:52:09 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
sz = moo_oowtoint ( moo , MOO_OBJ_GET_SIZE ( rcv ) ) ;
if ( ! sz ) return MOO_PF_HARD_FAILURE ; /* hard failure */
2016-06-13 15:52:09 +00:00
}
2015-12-27 18:02:59 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , sz ) ;
return MOO_PF_SUCCESS ;
2015-06-21 03:50:35 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_basic_at ( moo_t * moo , moo_ooi_t nargs )
2015-06-21 03:50:35 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , pos , v ;
moo_oow_t idx ;
2015-06-21 03:50:35 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-06-21 03:50:35 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
if ( ! MOO_OOP_IS_POINTER ( rcv ) )
2015-06-21 03:50:35 +00:00
{
/* the receiver is a special numeric object, not a normal pointer */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-06-21 03:50:35 +00:00
}
2017-01-09 09:54:49 +00:00
pos = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
if ( moo_inttooow ( moo , pos , & idx ) < = 0 )
2015-06-21 03:50:35 +00:00
{
2016-03-16 14:05:34 +00:00
/* negative integer or not integer */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-06-21 03:50:35 +00:00
}
2017-01-09 09:54:49 +00:00
if ( idx > = MOO_OBJ_GET_SIZE ( rcv ) )
2015-06-21 03:50:35 +00:00
{
/* index out of range */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-06-21 03:50:35 +00:00
}
2017-01-09 09:54:49 +00:00
switch ( MOO_OBJ_GET_FLAGS_TYPE ( rcv ) )
2015-06-21 03:50:35 +00:00
{
2017-01-09 09:54:49 +00:00
case MOO_OBJ_TYPE_BYTE :
v = MOO_SMOOI_TO_OOP ( ( ( moo_oop_byte_t ) rcv ) - > slot [ idx ] ) ;
2015-06-21 03:50:35 +00:00
break ;
2017-01-09 09:54:49 +00:00
case MOO_OBJ_TYPE_CHAR :
v = MOO_CHAR_TO_OOP ( ( ( moo_oop_char_t ) rcv ) - > slot [ idx ] ) ;
2015-06-21 03:50:35 +00:00
break ;
2017-01-09 09:54:49 +00:00
case MOO_OBJ_TYPE_HALFWORD :
2015-10-29 15:24:46 +00:00
/* TODO: LargeInteger if the halfword is too large */
2017-01-09 09:54:49 +00:00
v = MOO_SMOOI_TO_OOP ( ( ( moo_oop_halfword_t ) rcv ) - > slot [ idx ] ) ;
2015-10-29 15:24:46 +00:00
break ;
2017-01-09 09:54:49 +00:00
case MOO_OBJ_TYPE_WORD :
v = moo_oowtoint ( moo , ( ( moo_oop_word_t ) rcv ) - > slot [ idx ] ) ;
if ( ! v ) return MOO_PF_HARD_FAILURE ;
2015-06-21 03:50:35 +00:00
break ;
2017-01-09 09:54:49 +00:00
case MOO_OBJ_TYPE_OOP :
v = ( ( moo_oop_oop_t ) rcv ) - > slot [ idx ] ;
2015-06-21 03:50:35 +00:00
break ;
default :
2017-01-09 09:54:49 +00:00
moo - > errnum = MOO_EINTERN ;
return MOO_PF_HARD_FAILURE ;
2015-06-21 03:50:35 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , v ) ;
return MOO_PF_SUCCESS ;
2015-06-21 03:50:35 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_basic_at_put ( moo_t * moo , moo_ooi_t nargs )
2015-06-21 03:50:35 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , pos , val ;
moo_oow_t idx ;
2015-06-21 03:50:35 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 2 ) ;
2015-06-21 03:50:35 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
if ( ! MOO_OOP_IS_POINTER ( rcv ) )
2015-06-21 03:50:35 +00:00
{
/* the receiver is a special numeric object, not a normal pointer */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-06-21 03:50:35 +00:00
}
2017-01-09 09:54:49 +00:00
pos = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
val = MOO_STACK_GETARG ( moo , nargs , 1 ) ;
2015-12-27 18:02:59 +00:00
2017-01-09 09:54:49 +00:00
if ( moo_inttooow ( moo , pos , & idx ) < = 0 )
2015-06-21 03:50:35 +00:00
{
2016-03-16 14:05:34 +00:00
/* negative integer or not integer */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-06-21 03:50:35 +00:00
}
2017-01-09 09:54:49 +00:00
if ( idx > = MOO_OBJ_GET_SIZE ( rcv ) )
2015-06-21 03:50:35 +00:00
{
/* index out of range */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-06-21 03:50:35 +00:00
}
2017-01-09 09:54:49 +00:00
if ( MOO_OBJ_GET_CLASS ( rcv ) = = moo - > _symbol )
2015-10-30 15:36:37 +00:00
{
/* 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??? */
2017-01-09 09:54:49 +00:00
/* read-only object */ /* TODO: DEVISE A WAY TO PASS a proper error from the primitive handler to MOO */
return MOO_PF_FAILURE ;
2015-10-30 15:36:37 +00:00
}
2017-01-09 09:54:49 +00:00
switch ( MOO_OBJ_GET_FLAGS_TYPE ( rcv ) )
2015-06-21 03:50:35 +00:00
{
2017-01-09 09:54:49 +00:00
case MOO_OBJ_TYPE_BYTE :
if ( ! MOO_OOP_IS_SMOOI ( val ) )
2015-06-21 03:50:35 +00:00
{
/* the value is not a character */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-06-21 03:50:35 +00:00
}
/* TOOD: must I check the range of the value? */
2017-01-09 09:54:49 +00:00
( ( moo_oop_char_t ) rcv ) - > slot [ idx ] = MOO_OOP_TO_SMOOI ( val ) ;
2015-06-21 03:50:35 +00:00
break ;
2017-01-09 09:54:49 +00:00
case MOO_OBJ_TYPE_CHAR :
if ( ! MOO_OOP_IS_CHAR ( val ) )
2015-06-21 03:50:35 +00:00
{
/* the value is not a character */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-06-21 03:50:35 +00:00
}
2017-01-09 09:54:49 +00:00
( ( moo_oop_char_t ) rcv ) - > slot [ idx ] = MOO_OOP_TO_CHAR ( val ) ;
2015-06-21 03:50:35 +00:00
break ;
2017-01-09 09:54:49 +00:00
case MOO_OBJ_TYPE_HALFWORD :
if ( ! MOO_OOP_IS_SMOOI ( val ) )
2015-10-29 15:24:46 +00:00
{
/* the value is not a number */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-10-29 15:24:46 +00:00
}
/* if the small integer is too large, it will get truncated */
2017-01-09 09:54:49 +00:00
( ( moo_oop_halfword_t ) rcv ) - > slot [ idx ] = MOO_OOP_TO_SMOOI ( val ) ;
2015-10-29 15:24:46 +00:00
break ;
2017-01-09 09:54:49 +00:00
case MOO_OBJ_TYPE_WORD :
2017-01-06 09:53:40 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oow_t w ;
2017-01-06 09:53:40 +00:00
2017-01-09 09:54:49 +00:00
if ( moo_inttooow ( moo , val , & w ) < = 0 )
2015-06-21 03:50:35 +00:00
{
2017-01-06 09:53:40 +00:00
/* the value is not a number, out of range, or negative */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-06-21 03:50:35 +00:00
}
2017-01-09 09:54:49 +00:00
( ( moo_oop_word_t ) rcv ) - > slot [ idx ] = w ;
2015-06-21 03:50:35 +00:00
break ;
2017-01-06 09:53:40 +00:00
}
2015-06-21 03:50:35 +00:00
2017-01-09 09:54:49 +00:00
case MOO_OBJ_TYPE_OOP :
( ( moo_oop_oop_t ) rcv ) - > slot [ idx ] = val ;
2015-06-21 03:50:35 +00:00
break ;
default :
2017-01-09 09:54:49 +00:00
moo - > errnum = MOO_EINTERN ;
return MOO_PF_HARD_FAILURE ;
2015-06-21 03:50:35 +00:00
}
/* TODO: return receiver or value? */
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , val ) ;
return MOO_PF_SUCCESS ;
2015-06-21 03:50:35 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_hash ( moo_t * moo , moo_ooi_t nargs )
2017-01-05 10:16:04 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv ;
moo_oow_t hv ;
2017-01-05 10:16:04 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 0 ) ;
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
2017-01-05 10:16:04 +00:00
2017-01-09 09:54:49 +00:00
switch ( MOO_OOP_GET_TAG ( rcv ) )
2017-01-05 10:16:04 +00:00
{
2017-01-09 09:54:49 +00:00
case MOO_OOP_TAG_SMINT :
hv = MOO_OOP_TO_SMOOI ( rcv ) ;
2017-01-05 10:16:04 +00:00
break ;
2017-01-09 09:54:49 +00:00
case MOO_OOP_TAG_CHAR :
hv = MOO_OOP_TO_CHAR ( rcv ) ;
2017-01-05 10:16:04 +00:00
break ;
2017-01-09 09:54:49 +00:00
case MOO_OOP_TAG_ERROR :
hv = MOO_OOP_TO_ERROR ( rcv ) ;
2017-01-05 10:16:04 +00:00
break ;
default :
{
int type ;
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_OOP_IS_POINTER ( rcv ) ) ;
type = MOO_OBJ_GET_FLAGS_TYPE ( rcv ) ;
2017-01-05 10:16:04 +00:00
switch ( type )
{
2017-01-09 09:54:49 +00:00
case MOO_OBJ_TYPE_BYTE :
hv = moo_hashbytes ( ( ( moo_oop_byte_t ) rcv ) - > slot , MOO_OBJ_GET_SIZE ( rcv ) ) ;
2017-01-05 10:16:04 +00:00
break ;
2017-01-09 09:54:49 +00:00
case MOO_OBJ_TYPE_CHAR :
hv = moo_hashoochars ( ( ( moo_oop_char_t ) rcv ) - > slot , MOO_OBJ_GET_SIZE ( rcv ) ) ;
2017-01-05 10:16:04 +00:00
break ;
2017-01-09 09:54:49 +00:00
case MOO_OBJ_TYPE_HALFWORD :
hv = moo_hashhalfwords ( ( ( moo_oop_halfword_t ) rcv ) - > slot , MOO_OBJ_GET_SIZE ( rcv ) ) ;
2017-01-05 10:16:04 +00:00
break ;
2017-01-09 09:54:49 +00:00
case MOO_OBJ_TYPE_WORD :
hv = moo_hashwords ( ( ( moo_oop_word_t ) rcv ) - > slot , MOO_OBJ_GET_SIZE ( rcv ) ) ;
2017-01-05 10:16:04 +00:00
break ;
default :
2017-01-09 09:54:49 +00:00
/* MOO_OBJ_TYPE_OOP, ... */
MOO_DEBUG1 ( moo , " <pf_hash> Cannot hash an object of type %d \n " , type ) ;
return MOO_PF_FAILURE ;
2017-01-05 10:16:04 +00:00
}
break ;
}
}
2017-01-09 09:54:49 +00:00
/* moo_hashxxx() functions should limit the return value to fall
* in the range between 0 and MOO_SMOOI_MAX inclusive */
MOO_ASSERT ( moo , hv > = 0 & & hv < = MOO_SMOOI_MAX ) ;
2017-01-06 13:27:49 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , MOO_SMOOI_TO_OOP ( hv ) ) ;
return MOO_PF_SUCCESS ;
2017-01-05 10:16:04 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_exceptionize_error ( moo_t * moo , moo_ooi_t nargs )
2017-01-05 10:16:04 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv ;
2017-01-05 10:16:04 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2017-01-05 10:16:04 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
if ( ! MOO_OOP_IS_POINTER ( rcv ) )
2017-01-05 10:16:04 +00:00
{
/* the receiver is a special numeric object, not a normal pointer.
* excceptionization is not supported for small integers , characters , and errors .
* first of all , methods of these classes must not return errors */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2017-01-05 10:16:04 +00:00
}
// TODO: .......
2017-01-09 09:54:49 +00:00
// MOO_OBJ_SET_FLAGS_EXTRA (rcv, xxx);
MOO_STACK_SETRETTORCV ( moo , nargs ) ;
return MOO_PF_SUCCESS ;
2017-01-05 10:16:04 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_context_goto ( moo_t * moo , moo_ooi_t nargs )
2016-05-18 11:10:54 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv ;
moo_oop_t pc ;
2016-05-18 11:10:54 +00:00
/* this primivie provides the similar functionality to MethodContext>>pc:
* except that it pops the receiver and arguments and doesn ' t push a
* return value . it ' s useful when you want to change the instruction
* pointer while maintaining the stack level before the call */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2016-05-18 11:10:54 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
if ( MOO_CLASSOF ( moo , rcv ) ! = moo - > _method_context )
2016-05-18 11:10:54 +00:00
{
2017-01-09 09:54:49 +00:00
MOO_LOG2 ( moo , MOO_LOG_PRIMITIVE | MOO_LOG_ERROR ,
2016-06-30 13:44:37 +00:00
" Error(%hs) - invalid receiver, not a method context - %O \n " , __PRIMITIVE_NAME__ , rcv ) ;
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2016-05-18 11:10:54 +00:00
}
2017-01-09 09:54:49 +00:00
pc = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
if ( ! MOO_OOP_IS_SMOOI ( pc ) | | MOO_OOP_TO_SMOOI ( pc ) < 0 )
2016-05-18 11:10:54 +00:00
{
2017-01-09 09:54:49 +00:00
MOO_LOG1 ( moo , MOO_LOG_PRIMITIVE | MOO_LOG_ERROR ,
2016-06-26 15:03:12 +00:00
" Error(%hs) - invalid pc \n " , __PRIMITIVE_NAME__ ) ;
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2016-05-18 11:10:54 +00:00
}
2017-01-09 09:54:49 +00:00
( ( moo_oop_context_t ) rcv ) - > ip = pc ;
LOAD_ACTIVE_IP ( moo ) ;
2016-05-18 11:10:54 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs + 1 = = 2 ) ;
MOO_STACK_POPS ( moo , 2 ) ; /* pop both the argument and the receiver */
return MOO_PF_SUCCESS ;
2016-05-18 11:10:54 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t __block_value ( moo_t * moo , moo_oop_context_t rcv_blkctx , moo_ooi_t nargs , moo_ooi_t num_first_arg_elems , moo_oop_context_t * pblkctx )
2015-06-17 13:46:16 +00:00
{
2016-02-11 14:26:26 +00:00
/* prepare a new block context for activation.
* the receiver must be a block context which becomes the base
* for a new block context . */
2017-01-09 09:54:49 +00:00
moo_oop_context_t blkctx ;
moo_ooi_t local_ntmprs , i ;
moo_ooi_t actual_arg_count ;
2015-10-22 02:47:25 +00:00
actual_arg_count = ( num_first_arg_elems > 0 ) ? num_first_arg_elems : nargs ;
2015-06-17 13:46:16 +00:00
2015-06-22 14:21:46 +00:00
/* TODO: find a better way to support a reentrant block context. */
2015-06-17 13:46:16 +00:00
2015-06-22 14:21:46 +00:00
/* | 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
*/
2016-08-10 14:41:45 +00:00
/* the receiver must be a block context */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_CLASSOF ( moo , rcv_blkctx ) = = moo - > _block_context ) ;
if ( rcv_blkctx - > receiver_or_source ! = moo - > _nil )
2015-06-25 13:37:50 +00:00
{
2015-06-26 15:49:08 +00:00
/* the 'source' field is not nil.
* this block context has already been activated once .
2015-06-25 13:37:50 +00:00
* you can ' t send ' value ' again to reactivate it .
2016-03-26 06:39:56 +00:00
* For example , [ thisContext value ] value . */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_OBJ_GET_SIZE ( rcv_blkctx ) > MOO_CONTEXT_NAMED_INSTVARS ) ;
MOO_LOG2 ( moo , MOO_LOG_PRIMITIVE | MOO_LOG_ERROR ,
2016-06-26 15:03:12 +00:00
" Error(%hs) - re-valuing of a block context - %O \n " , __PRIMITIVE_NAME__ , rcv_blkctx ) ;
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-06-25 13:37:50 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_OBJ_GET_SIZE ( rcv_blkctx ) = = MOO_CONTEXT_NAMED_INSTVARS ) ;
2015-06-25 13:37:50 +00:00
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_TO_SMOOI ( rcv_blkctx - > method_or_nargs ) ! = actual_arg_count /* nargs */ )
2015-06-17 13:46:16 +00:00
{
2017-01-09 09:54:49 +00:00
MOO_LOG4 ( moo , MOO_LOG_PRIMITIVE | MOO_LOG_ERROR ,
2016-06-26 15:03:12 +00:00
" Error(%hs) - wrong number of arguments to a block context %O - expecting %zd, got %zd \n " ,
2017-01-09 09:54:49 +00:00
__PRIMITIVE_NAME__ , rcv_blkctx , MOO_OOP_TO_SMOOI ( rcv_blkctx - > method_or_nargs ) , actual_arg_count ) ;
return MOO_PF_FAILURE ;
2015-06-17 13:46:16 +00:00
}
2016-02-12 16:23:26 +00:00
/* 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 */
2017-01-09 09:54:49 +00:00
local_ntmprs = MOO_OOP_TO_SMOOI ( rcv_blkctx - > ntmprs ) -
MOO_OOP_TO_SMOOI ( ( ( moo_oop_context_t ) rcv_blkctx - > home ) - > ntmprs ) ;
MOO_ASSERT ( moo , local_ntmprs > = actual_arg_count ) ;
2016-02-12 16:23:26 +00:00
2016-03-26 06:39:56 +00:00
/* create a new block context to clone rcv_blkctx */
2017-01-09 09:54:49 +00:00
moo_pushtmp ( moo , ( moo_oop_t * ) & rcv_blkctx ) ;
blkctx = ( moo_oop_context_t ) moo_instantiate ( moo , moo - > _block_context , MOO_NULL , local_ntmprs ) ;
moo_poptmp ( moo ) ;
if ( ! blkctx ) return MOO_PF_HARD_FAILURE ;
2015-06-22 14:21:46 +00:00
2015-06-25 13:37:50 +00:00
#if 0
/* shallow-copy the named part including home, origin, etc. */
2017-01-09 09:54:49 +00:00
for ( i = 0 ; i < MOO_CONTEXT_NAMED_INSTVARS ; i + + )
2015-06-22 14:21:46 +00:00
{
2017-01-09 09:54:49 +00:00
( ( moo_oop_oop_t ) blkctx ) - > slot [ i ] = ( ( moo_oop_oop_t ) rcv_blkctx ) - > slot [ i ] ;
2015-06-22 14:21:46 +00:00
}
2015-06-25 13:37:50 +00:00
# else
2016-03-26 06:39:56 +00:00
blkctx - > ip = rcv_blkctx - > ip ;
blkctx - > ntmprs = rcv_blkctx - > ntmprs ;
blkctx - > method_or_nargs = rcv_blkctx - > method_or_nargs ;
2017-01-09 09:54:49 +00:00
blkctx - > receiver_or_source = ( moo_oop_t ) rcv_blkctx ;
2016-03-26 06:39:56 +00:00
blkctx - > home = rcv_blkctx - > home ;
blkctx - > origin = rcv_blkctx - > origin ;
2015-10-08 14:26:04 +00:00
# endif
2015-06-22 14:21:46 +00:00
/* TODO: check the stack size of a block context to see if it's large enough to hold arguments */
2015-10-22 02:47:25 +00:00
if ( num_first_arg_elems > 0 )
2015-06-22 14:21:46 +00:00
{
2016-01-29 04:04:39 +00:00
/* the first argument should be an array. this function is ordered
* to pass array elements to the new block */
2017-01-09 09:54:49 +00:00
moo_oop_oop_t xarg ;
MOO_ASSERT ( moo , nargs = = 1 ) ;
xarg = ( moo_oop_oop_t ) MOO_STACK_GETTOP ( moo ) ;
MOO_ASSERT ( moo , MOO_ISTYPEOF ( moo , xarg , MOO_OBJ_TYPE_OOP ) ) ;
MOO_ASSERT ( moo , MOO_OBJ_GET_SIZE ( xarg ) = = num_first_arg_elems ) ;
2015-10-22 02:47:25 +00:00
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 + + )
{
2017-01-09 09:54:49 +00:00
blkctx - > slot [ i ] = MOO_STACK_GETARG ( moo , nargs , i ) ;
2015-10-22 02:47:25 +00:00
}
2015-06-22 14:21:46 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_STACK_POPS ( moo , nargs + 1 ) ; /* pop arguments and receiver */
2015-06-22 14:21:46 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , blkctx - > home ! = moo - > _nil ) ;
blkctx - > sp = MOO_SMOOI_TO_OOP ( - 1 ) ; /* not important at all */
blkctx - > sender = moo - > active_context ;
2015-06-17 13:46:16 +00:00
2015-10-22 02:47:25 +00:00
* pblkctx = blkctx ;
2017-01-09 09:54:49 +00:00
return MOO_PF_SUCCESS ;
2015-10-22 02:47:25 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_block_value ( moo_t * moo , moo_ooi_t nargs )
2015-10-22 02:47:25 +00:00
{
2017-01-09 09:54:49 +00:00
moo_pfrc_t x ;
moo_oop_context_t rcv_blkctx , blkctx ;
2015-10-22 02:47:25 +00:00
2017-01-09 09:54:49 +00:00
rcv_blkctx = ( moo_oop_context_t ) MOO_STACK_GETRCV ( moo , nargs ) ;
if ( MOO_CLASSOF ( moo , rcv_blkctx ) ! = moo - > _block_context )
2016-08-10 14:41:45 +00:00
{
/* the receiver must be a block context */
2017-01-09 09:54:49 +00:00
MOO_LOG2 ( moo , MOO_LOG_PRIMITIVE | MOO_LOG_ERROR ,
2016-08-10 14:41:45 +00:00
" Error(%hs) - invalid receiver, not a block context - %O \n " , __PRIMITIVE_NAME__ , rcv_blkctx ) ;
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2016-08-10 14:41:45 +00:00
}
2017-01-09 09:54:49 +00:00
x = __block_value ( moo , rcv_blkctx , nargs , 0 , & blkctx ) ;
if ( x < = MOO_PF_FAILURE ) return x ; /* hard failure and soft failure */
2015-10-22 02:47:25 +00:00
2017-01-09 09:54:49 +00:00
SWITCH_ACTIVE_CONTEXT ( moo , ( moo_oop_context_t ) blkctx ) ;
return MOO_PF_SUCCESS ;
2015-06-17 13:46:16 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_block_new_process ( moo_t * moo , moo_ooi_t nargs )
2015-10-18 15:06:17 +00:00
{
2016-02-11 14:26:26 +00:00
/* 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 )
*/
2015-10-22 02:47:25 +00:00
int x ;
2017-01-09 09:54:49 +00:00
moo_oop_context_t rcv_blkctx , blkctx ;
moo_oop_process_t proc ;
moo_ooi_t num_first_arg_elems = 0 ;
2015-10-22 02:47:25 +00:00
if ( nargs > 1 )
{
/* too many arguments */
/* TODO: proper error handling */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-10-22 02:47:25 +00:00
}
if ( nargs = = 1 )
{
2017-01-09 09:54:49 +00:00
moo_oop_t xarg ;
2015-10-22 02:47:25 +00:00
2017-01-09 09:54:49 +00:00
xarg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
if ( ! MOO_ISTYPEOF ( moo , xarg , MOO_OBJ_TYPE_OOP ) )
2015-10-22 02:47:25 +00:00
{
2016-02-11 14:26:26 +00:00
/* the only optional argument must be an OOP-indexable
* object like an array */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-10-22 02:47:25 +00:00
}
2017-01-09 09:54:49 +00:00
num_first_arg_elems = MOO_OBJ_GET_SIZE ( xarg ) ;
2015-10-22 02:47:25 +00:00
}
2017-01-09 09:54:49 +00:00
rcv_blkctx = ( moo_oop_context_t ) MOO_STACK_GETRCV ( moo , nargs ) ;
if ( MOO_CLASSOF ( moo , rcv_blkctx ) ! = moo - > _block_context )
2016-03-26 06:39:56 +00:00
{
/* the receiver must be a block context */
2017-01-09 09:54:49 +00:00
MOO_LOG2 ( moo , MOO_LOG_PRIMITIVE | MOO_LOG_ERROR ,
2016-08-10 14:41:45 +00:00
" Error(%hs) - invalid receiver, not a block context - %O \n " , __PRIMITIVE_NAME__ , rcv_blkctx ) ;
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2016-03-26 06:39:56 +00:00
}
2015-10-22 02:47:25 +00:00
/* this primitive creates a new process with a block as if the block
* is sent the value message */
2017-01-09 09:54:49 +00:00
x = __block_value ( moo , rcv_blkctx , nargs , num_first_arg_elems , & blkctx ) ;
2016-02-11 14:26:26 +00:00
if ( x < = 0 ) return x ; /* both hard failure and soft failure */
2015-10-22 02:47:25 +00:00
2017-01-09 09:54:49 +00:00
/* reset the sender field to moo->_nil because this block context
2016-05-02 13:50:42 +00:00
* will be the initial context of a new process . you can simply
* inspect the sender field to see if a context is an initial
* context of a process . */
2017-01-09 09:54:49 +00:00
blkctx - > sender = ( moo_oop_context_t ) moo - > _nil ;
2016-05-02 13:50:42 +00:00
2017-01-09 09:54:49 +00:00
proc = make_process ( moo , blkctx ) ;
if ( ! proc ) return MOO_PF_HARD_FAILURE ; /* hard failure */ /* TOOD: can't this be treated as a soft failure? */
2015-10-22 02:47:25 +00:00
/* __block_value() has popped all arguments and the receiver.
* PUSH the return value instead of changing the stack top */
2017-01-09 09:54:49 +00:00
MOO_STACK_PUSH ( moo , ( moo_oop_t ) proc ) ;
return MOO_PF_SUCCESS ;
2015-10-18 15:06:17 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_process_resume ( moo_t * moo , moo_ooi_t nargs )
2016-02-19 15:52:56 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv ;
MOO_ASSERT ( moo , nargs = = 0 ) ;
2016-02-19 15:52:56 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
if ( MOO_CLASSOF ( moo , rcv ) ! = moo - > _process ) return MOO_PF_FAILURE ;
2016-02-19 15:52:56 +00:00
2017-01-09 09:54:49 +00:00
resume_process ( moo , ( moo_oop_process_t ) rcv ) ; /* TODO: error check */
2016-02-19 15:52:56 +00:00
/* keep the receiver in the stack top */
2017-01-09 09:54:49 +00:00
return MOO_PF_SUCCESS ;
2016-02-19 15:52:56 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_process_terminate ( moo_t * moo , moo_ooi_t nargs )
2016-02-14 06:35:18 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv ;
MOO_ASSERT ( moo , nargs = = 0 ) ;
2016-02-14 06:35:18 +00:00
2016-06-30 13:44:37 +00:00
/* TODO: need to run ensure blocks here..
* when it ' s executed here . it does ' t have to be in Exception > > handleException when there is no exception handler */
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
if ( MOO_CLASSOF ( moo , rcv ) ! = moo - > _process ) return MOO_PF_FAILURE ;
2016-02-14 06:35:18 +00:00
2017-01-09 09:54:49 +00:00
terminate_process ( moo , ( moo_oop_process_t ) rcv ) ;
2016-02-14 06:35:18 +00:00
/* keep the receiver in the stack top */
2017-01-09 09:54:49 +00:00
return MOO_PF_SUCCESS ;
2016-02-14 06:35:18 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_process_yield ( moo_t * moo , moo_ooi_t nargs )
2016-02-19 15:52:56 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv ;
MOO_ASSERT ( moo , nargs = = 0 ) ;
2016-02-19 15:52:56 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
if ( MOO_CLASSOF ( moo , rcv ) ! = moo - > _process ) return MOO_PF_FAILURE ;
2016-02-19 15:52:56 +00:00
2017-01-09 09:54:49 +00:00
yield_process ( moo , ( moo_oop_process_t ) rcv ) ;
2016-02-19 15:52:56 +00:00
/* keep the receiver in the stack top */
2017-01-09 09:54:49 +00:00
return MOO_PF_SUCCESS ;
2016-02-19 15:52:56 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_process_suspend ( moo_t * moo , moo_ooi_t nargs )
2016-07-04 15:36:10 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv ;
MOO_ASSERT ( moo , nargs = = 0 ) ;
2016-07-04 15:36:10 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
if ( MOO_CLASSOF ( moo , rcv ) ! = moo - > _process ) return MOO_PF_FAILURE ;
2016-07-04 15:36:10 +00:00
2017-01-09 09:54:49 +00:00
suspend_process ( moo , ( moo_oop_process_t ) rcv ) ;
2016-07-04 15:36:10 +00:00
/* keep the receiver in the stack top */
2017-01-09 09:54:49 +00:00
return MOO_PF_SUCCESS ;
2016-07-04 15:36:10 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_semaphore_signal ( moo_t * moo , moo_ooi_t nargs )
2016-02-18 17:49:56 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv ;
MOO_ASSERT ( moo , nargs = = 0 ) ;
2016-02-18 17:49:56 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
if ( MOO_CLASSOF ( moo , rcv ) ! = moo - > _semaphore ) return MOO_PF_FAILURE ;
2016-02-18 17:49:56 +00:00
2017-01-09 09:54:49 +00:00
signal_semaphore ( moo , ( moo_oop_semaphore_t ) rcv ) ;
2016-02-18 17:49:56 +00:00
/* keep the receiver in the stack top */
2017-01-09 09:54:49 +00:00
return MOO_PF_SUCCESS ;
2016-02-18 17:49:56 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_semaphore_wait ( moo_t * moo , moo_ooi_t nargs )
2016-02-18 17:49:56 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv ;
MOO_ASSERT ( moo , nargs = = 0 ) ;
2016-02-18 17:49:56 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
if ( MOO_CLASSOF ( moo , rcv ) ! = moo - > _semaphore ) return MOO_PF_FAILURE ;
2016-02-18 17:49:56 +00:00
2017-01-09 09:54:49 +00:00
await_semaphore ( moo , ( moo_oop_semaphore_t ) rcv ) ;
2016-02-18 17:49:56 +00:00
/* keep the receiver in the stack top */
2017-01-09 09:54:49 +00:00
return MOO_PF_SUCCESS ;
2016-02-18 17:49:56 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_processor_schedule ( moo_t * moo , moo_ooi_t nargs )
2016-02-14 06:35:18 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg ;
2016-02-14 06:35:18 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2016-02-14 06:35:18 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2016-02-14 06:35:18 +00:00
2017-01-09 09:54:49 +00:00
if ( rcv ! = ( moo_oop_t ) moo - > processor | | MOO_CLASSOF ( moo , arg ) ! = moo - > _process )
2016-02-14 06:35:18 +00:00
{
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2016-02-14 06:35:18 +00:00
}
2017-01-09 09:54:49 +00:00
resume_process ( moo , ( moo_oop_process_t ) arg ) ; /* TODO: error check */
return MOO_PF_SUCCESS ;
2016-02-14 06:35:18 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_processor_add_timed_semaphore ( moo_t * moo , moo_ooi_t nargs )
2016-03-22 14:18:07 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , sec , nsec ;
moo_oop_semaphore_t sem ;
moo_ntime_t now , ft ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs > = 2 | | nargs < = 3 ) ;
2016-03-22 14:18:07 +00:00
if ( nargs = = 3 )
{
2017-01-09 09:54:49 +00:00
nsec = MOO_STACK_GETARG ( moo , nargs , 2 ) ;
if ( ! MOO_OOP_IS_SMOOI ( nsec ) ) return MOO_PF_FAILURE ;
2016-03-22 14:18:07 +00:00
}
2017-01-09 09:54:49 +00:00
else nsec = MOO_SMOOI_TO_OOP ( 0 ) ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
sec = MOO_STACK_GETARG ( moo , nargs , 1 ) ;
sem = ( moo_oop_semaphore_t ) MOO_STACK_GETARG ( moo , nargs , 0 ) ;
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
if ( rcv ! = ( moo_oop_t ) moo - > processor ) return MOO_PF_FAILURE ;
if ( MOO_CLASSOF ( moo , sem ) ! = moo - > _semaphore ) return MOO_PF_FAILURE ;
if ( ! MOO_OOP_IS_SMOOI ( sec ) ) return MOO_PF_FAILURE ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( sem - > heap_index ) & &
sem - > heap_index ! = MOO_SMOOI_TO_OOP ( - 1 ) )
2016-03-22 14:18:07 +00:00
{
2017-01-09 09:54:49 +00:00
delete_from_sem_heap ( moo , MOO_OOP_TO_SMOOI ( sem - > heap_index ) ) ;
MOO_ASSERT ( moo , sem - > heap_index = = MOO_SMOOI_TO_OOP ( - 1 ) ) ;
2016-03-22 14:18:07 +00:00
/*
Is this more desired ? ? ?
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , moo - > _false ) ;
return MOO_PF_SUCCESS ;
2016-03-22 14:18:07 +00:00
*/
}
/* TODO: make clock_gettime to be platform independent
*
* this code assumes that the monotonic clock returns a small value
2016-06-24 15:53:00 +00:00
* that can fit into a SmallInteger , even after some additions . . . */
2017-01-09 09:54:49 +00:00
vm_gettime ( moo , & now ) ;
MOO_ADDNTIMESNS ( & ft , & now , MOO_OOP_TO_SMOOI ( sec ) , MOO_OOP_TO_SMOOI ( nsec ) ) ;
if ( ft . sec < 0 | | ft . sec > MOO_SMOOI_MAX )
2016-03-22 14:18:07 +00:00
{
2016-06-24 15:53:00 +00:00
/* soft error - cannot represent the expiry time in
2016-03-22 14:18:07 +00:00
* a small integer . */
2017-01-09 09:54:49 +00:00
MOO_LOG3 ( moo , MOO_LOG_PRIMITIVE | MOO_LOG_ERROR ,
2016-06-26 15:03:12 +00:00
" Error(%hs) - time (%ld) out of range(0 - %zd) when adding a timed semaphore \n " ,
2017-01-09 09:54:49 +00:00
__PRIMITIVE_NAME__ , ( unsigned long int ) ft . sec , ( moo_ooi_t ) MOO_SMOOI_MAX ) ;
return MOO_PF_FAILURE ;
2016-03-22 14:18:07 +00:00
}
2017-01-09 09:54:49 +00:00
sem - > heap_ftime_sec = MOO_SMOOI_TO_OOP ( ft . sec ) ;
sem - > heap_ftime_nsec = MOO_SMOOI_TO_OOP ( ft . nsec ) ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
if ( add_to_sem_heap ( moo , sem ) < = - 1 ) return MOO_PF_HARD_FAILURE ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRETTORCV ( moo , nargs ) ; /* ^self */
return MOO_PF_SUCCESS ;
2016-03-22 14:18:07 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_processor_remove_semaphore ( moo_t * moo , moo_ooi_t nargs )
2016-03-22 14:18:07 +00:00
{
2016-03-24 14:58:47 +00:00
/* remove a semaphore from processor's signal scheduling */
2017-01-09 09:54:49 +00:00
moo_oop_t rcv ;
moo_oop_semaphore_t sem ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
sem = ( moo_oop_semaphore_t ) MOO_STACK_GETARG ( moo , nargs , 0 ) ;
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
2016-03-24 14:58:47 +00:00
/* TODO: remove a semaphore from IO handler if it's registered...
* remove a semaphore from XXXXXXXXXXXXXX */
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
if ( rcv ! = ( moo_oop_t ) moo - > processor ) return MOO_PF_FAILURE ;
if ( MOO_CLASSOF ( moo , sem ) ! = moo - > _semaphore ) return MOO_PF_FAILURE ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( sem - > heap_index ) & &
sem - > heap_index ! = MOO_SMOOI_TO_OOP ( - 1 ) )
2016-03-22 14:18:07 +00:00
{
2016-03-24 14:58:47 +00:00
/* the semaphore is in the timed semaphore heap */
2017-01-09 09:54:49 +00:00
delete_from_sem_heap ( moo , MOO_OOP_TO_SMOOI ( sem - > heap_index ) ) ;
MOO_ASSERT ( moo , sem - > heap_index = = MOO_SMOOI_TO_OOP ( - 1 ) ) ;
2016-03-22 14:18:07 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRETTORCV ( moo , nargs ) ; /* ^self */
return MOO_PF_SUCCESS ;
2016-03-22 14:18:07 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_processor_return_to ( moo_t * moo , moo_ooi_t nargs )
2016-03-28 13:25:36 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , ret , ctx ;
2016-03-28 13:25:36 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 2 ) ;
2016-03-28 13:25:36 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
ret = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
ctx = MOO_STACK_GETARG ( moo , nargs , 1 ) ;
2016-03-28 13:25:36 +00:00
2017-01-09 09:54:49 +00:00
if ( rcv ! = ( moo_oop_t ) moo - > processor ) return MOO_PF_FAILURE ;
2016-03-28 13:25:36 +00:00
2017-01-09 09:54:49 +00:00
if ( MOO_CLASSOF ( moo , ctx ) ! = moo - > _block_context & &
MOO_CLASSOF ( moo , ctx ) ! = moo - > _method_context ) return MOO_PF_FAILURE ;
2016-04-30 05:56:35 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_POPS ( moo , nargs + 1 ) ; /* pop arguments and receiver */
2016-06-24 14:29:43 +00:00
/* TODO: verify if this is correct? does't it correct restore the stack pointer?
* test complex chains of method contexts and block contexts */
2017-01-09 09:54:49 +00:00
if ( MOO_CLASSOF ( moo , ctx ) = = moo - > _method_context )
2016-06-24 14:29:43 +00:00
{
/* when returning to a method context, load the sp register with
* the value stored in the context */
2017-01-09 09:54:49 +00:00
moo - > sp = MOO_OOP_TO_SMOOI ( ( ( moo_oop_context_t ) ctx ) - > sp ) ;
2016-06-24 14:29:43 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_STACK_PUSH ( moo , ret ) ;
2016-05-02 13:50:42 +00:00
2017-01-09 09:54:49 +00:00
SWITCH_ACTIVE_CONTEXT ( moo , ( moo_oop_context_t ) ctx ) ;
return MOO_PF_SUCCESS ;
2016-05-02 13:50:42 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_integer_add ( moo_t * moo , moo_ooi_t nargs )
2015-06-20 03:07:11 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg , res ;
2015-06-20 03:07:11 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-06-20 03:07:11 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-06-20 03:07:11 +00:00
2017-01-09 09:54:49 +00:00
res = moo_addints ( moo , rcv , arg ) ;
if ( ! res ) return ( moo - > errnum = = MOO_EINVAL ? MOO_PF_FAILURE : MOO_PF_HARD_FAILURE ) ;
2015-10-30 15:36:37 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , res ) ;
return MOO_PF_SUCCESS ;
2015-06-22 14:21:46 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_integer_sub ( moo_t * moo , moo_ooi_t nargs )
2015-06-22 14:21:46 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg , res ;
2015-06-22 14:21:46 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-06-22 14:21:46 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-06-22 14:21:46 +00:00
2017-01-09 09:54:49 +00:00
res = moo_subints ( moo , rcv , arg ) ;
if ( ! res ) return ( moo - > errnum = = MOO_EINVAL ? MOO_PF_FAILURE : MOO_PF_HARD_FAILURE ) ;
2015-10-30 15:36:37 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , res ) ;
return MOO_PF_SUCCESS ;
2015-06-22 14:21:46 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_integer_mul ( moo_t * moo , moo_ooi_t nargs )
2015-07-01 07:21:54 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg , res ;
2015-07-01 07:21:54 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-07-01 07:21:54 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-07-01 07:21:54 +00:00
2017-01-09 09:54:49 +00:00
res = moo_mulints ( moo , rcv , arg ) ;
if ( ! res ) return ( moo - > errnum = = MOO_EINVAL ? MOO_PF_FAILURE : MOO_PF_HARD_FAILURE ) ;
2015-11-11 13:31:05 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , res ) ;
return MOO_PF_SUCCESS ;
2015-11-22 13:32:06 +00:00
}
2015-07-01 07:21:54 +00:00
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_integer_quo ( moo_t * moo , moo_ooi_t nargs )
2015-11-22 13:32:06 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg , quo ;
2015-07-01 07:21:54 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-11-22 13:32:06 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-11-22 13:32:06 +00:00
2017-01-09 09:54:49 +00:00
quo = moo_divints ( moo , rcv , arg , 0 , MOO_NULL ) ;
if ( ! quo ) return ( moo - > errnum = = MOO_EINVAL ? MOO_PF_FAILURE : MOO_PF_HARD_FAILURE ) ;
/* TODO: MOO_EDIVBY0 soft or hard failure? */
2015-11-11 13:31:05 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , quo ) ;
return MOO_PF_SUCCESS ;
2015-11-22 13:32:06 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_integer_rem ( moo_t * moo , moo_ooi_t nargs )
2015-11-22 13:32:06 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg , quo , rem ;
2015-11-22 13:32:06 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-11-22 13:32:06 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-11-22 13:32:06 +00:00
2017-01-09 09:54:49 +00:00
quo = moo_divints ( moo , rcv , arg , 0 , & rem ) ;
if ( ! quo ) return ( moo - > errnum = = MOO_EINVAL ? MOO_PF_FAILURE : MOO_PF_HARD_FAILURE ) ;
/* TODO: MOO_EDIVBY0 soft or hard failure? */
2015-11-22 14:48:09 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , rem ) ;
return MOO_PF_SUCCESS ;
2015-11-22 14:48:09 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_integer_quo2 ( moo_t * moo , moo_ooi_t nargs )
2015-11-22 14:48:09 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg , quo ;
2015-11-22 14:48:09 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-11-22 14:48:09 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-11-22 14:48:09 +00:00
2017-01-09 09:54:49 +00:00
quo = moo_divints ( moo , rcv , arg , 1 , MOO_NULL ) ;
if ( ! quo ) return ( moo - > errnum = = MOO_EINVAL ? MOO_PF_FAILURE : MOO_PF_HARD_FAILURE ) ;
/* TODO: MOO_EDIVBY0 soft or hard failure? */
2015-11-22 14:48:09 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , quo ) ;
return MOO_PF_SUCCESS ;
2015-11-22 14:48:09 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_integer_rem2 ( moo_t * moo , moo_ooi_t nargs )
2015-11-22 14:48:09 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg , quo , rem ;
2015-11-22 14:48:09 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-11-22 14:48:09 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-11-22 14:48:09 +00:00
2017-01-09 09:54:49 +00:00
quo = moo_divints ( moo , rcv , arg , 1 , & rem ) ;
if ( ! quo ) return ( moo - > errnum = = MOO_EINVAL ? MOO_PF_FAILURE : MOO_PF_HARD_FAILURE ) ;
/* TODO: MOO_EDIVBY0 soft or hard failure? */
2015-11-22 13:32:06 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , rem ) ;
return MOO_PF_SUCCESS ;
2015-07-01 07:21:54 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_integer_negated ( moo_t * moo , moo_ooi_t nargs )
2015-12-25 05:09:17 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , res ;
2015-12-25 05:09:17 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 0 ) ;
2015-12-25 05:09:17 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
2015-12-25 05:09:17 +00:00
2017-01-09 09:54:49 +00:00
res = moo_negateint ( moo , rcv ) ;
if ( ! res ) return ( moo - > errnum = = MOO_EINVAL ? MOO_PF_FAILURE : MOO_PF_HARD_FAILURE ) ;
2015-12-25 05:09:17 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , res ) ;
return MOO_PF_SUCCESS ;
2015-12-25 05:09:17 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_integer_bitat ( moo_t * moo , moo_ooi_t nargs )
2015-12-25 05:09:17 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg , res ;
2015-12-25 05:09:17 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-12-25 05:09:17 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-12-25 05:09:17 +00:00
2017-01-09 09:54:49 +00:00
res = moo_bitatint ( moo , rcv , arg ) ;
if ( ! res ) return ( moo - > errnum = = MOO_EINVAL ? MOO_PF_FAILURE : MOO_PF_HARD_FAILURE ) ;
2015-12-25 05:09:17 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , res ) ;
return MOO_PF_SUCCESS ;
2015-12-25 05:09:17 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_integer_bitand ( moo_t * moo , moo_ooi_t nargs )
2015-12-10 14:23:09 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg , res ;
2015-12-10 14:23:09 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-12-10 14:23:09 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-12-10 14:23:09 +00:00
2017-01-09 09:54:49 +00:00
res = moo_bitandints ( moo , rcv , arg ) ;
if ( ! res ) return ( moo - > errnum = = MOO_EINVAL ? MOO_PF_FAILURE : MOO_PF_HARD_FAILURE ) ;
2015-12-10 14:23:09 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , res ) ;
return MOO_PF_SUCCESS ;
2015-12-10 14:23:09 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_integer_bitor ( moo_t * moo , moo_ooi_t nargs )
2015-12-10 14:23:09 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg , res ;
2015-12-10 14:23:09 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-12-10 14:23:09 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-12-10 14:23:09 +00:00
2017-01-09 09:54:49 +00:00
res = moo_bitorints ( moo , rcv , arg ) ;
if ( ! res ) return ( moo - > errnum = = MOO_EINVAL ? MOO_PF_FAILURE : MOO_PF_HARD_FAILURE ) ;
2015-12-10 14:23:09 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , res ) ;
return MOO_PF_SUCCESS ;
2015-12-10 14:23:09 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_integer_bitxor ( moo_t * moo , moo_ooi_t nargs )
2015-12-10 14:23:09 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg , res ;
2015-12-10 14:23:09 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-12-10 14:23:09 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-12-10 14:23:09 +00:00
2017-01-09 09:54:49 +00:00
res = moo_bitxorints ( moo , rcv , arg ) ;
if ( ! res ) return ( moo - > errnum = = MOO_EINVAL ? MOO_PF_FAILURE : MOO_PF_HARD_FAILURE ) ;
2015-12-10 14:23:09 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , res ) ;
return MOO_PF_SUCCESS ;
2015-12-10 14:23:09 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_integer_bitinv ( moo_t * moo , moo_ooi_t nargs )
2015-12-17 16:37:26 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , res ;
2015-12-17 16:37:26 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 0 ) ;
2015-12-17 16:37:26 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
2015-12-17 16:37:26 +00:00
2017-01-09 09:54:49 +00:00
res = moo_bitinvint ( moo , rcv ) ;
if ( ! res ) return ( moo - > errnum = = MOO_EINVAL ? MOO_PF_FAILURE : MOO_PF_HARD_FAILURE ) ;
2015-12-17 16:37:26 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , res ) ;
return MOO_PF_SUCCESS ;
2015-12-17 16:37:26 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_integer_bitshift ( moo_t * moo , moo_ooi_t nargs )
2015-12-18 15:58:45 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg , res ;
2015-12-18 15:58:45 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-12-18 15:58:45 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-12-18 15:58:45 +00:00
2017-01-09 09:54:49 +00:00
res = moo_bitshiftint ( moo , rcv , arg ) ;
if ( ! res ) return ( moo - > errnum = = MOO_EINVAL ? MOO_PF_FAILURE : MOO_PF_HARD_FAILURE ) ;
2015-12-18 15:58:45 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , res ) ;
return MOO_PF_SUCCESS ;
2015-12-18 15:58:45 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_integer_eq ( moo_t * moo , moo_ooi_t nargs )
2015-07-01 07:21:54 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg , res ;
2015-07-01 07:21:54 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-07-01 07:21:54 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-07-01 07:21:54 +00:00
2017-01-09 09:54:49 +00:00
res = moo_eqints ( moo , rcv , arg ) ;
if ( ! res ) return ( moo - > errnum = = MOO_EINVAL ? MOO_PF_FAILURE : MOO_PF_HARD_FAILURE ) ;
2015-07-01 07:21:54 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , res ) ;
return MOO_PF_SUCCESS ;
2015-07-01 07:21:54 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_integer_ne ( moo_t * moo , moo_ooi_t nargs )
2015-10-04 16:21:31 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg , res ;
2015-10-04 16:21:31 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-10-04 16:21:31 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-10-04 16:21:31 +00:00
2017-01-09 09:54:49 +00:00
res = moo_neints ( moo , rcv , arg ) ;
if ( ! res ) return ( moo - > errnum = = MOO_EINVAL ? MOO_PF_FAILURE : MOO_PF_HARD_FAILURE ) ;
2015-10-04 16:21:31 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , res ) ;
return MOO_PF_SUCCESS ;
2015-10-04 16:21:31 +00:00
}
2015-12-27 18:02:59 +00:00
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_integer_lt ( moo_t * moo , moo_ooi_t nargs )
2015-06-22 14:21:46 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg , res ;
2015-06-22 14:21:46 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-06-22 14:21:46 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-06-22 14:21:46 +00:00
2017-01-09 09:54:49 +00:00
res = moo_ltints ( moo , rcv , arg ) ;
if ( ! res ) return ( moo - > errnum = = MOO_EINVAL ? MOO_PF_FAILURE : MOO_PF_HARD_FAILURE ) ;
2015-06-20 03:07:11 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , res ) ;
return MOO_PF_SUCCESS ;
2015-06-20 03:07:11 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_integer_gt ( moo_t * moo , moo_ooi_t nargs )
2015-06-22 14:21:46 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg , res ;
2015-06-22 14:21:46 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-06-22 14:21:46 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-06-22 14:21:46 +00:00
2017-01-09 09:54:49 +00:00
res = moo_gtints ( moo , rcv , arg ) ;
if ( ! res ) return ( moo - > errnum = = MOO_EINVAL ? MOO_PF_FAILURE : MOO_PF_HARD_FAILURE ) ;
2015-06-22 14:21:46 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , res ) ;
return MOO_PF_SUCCESS ;
2015-06-22 14:21:46 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_integer_le ( moo_t * moo , moo_ooi_t nargs )
2015-10-04 16:21:31 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg , res ;
2015-10-04 16:21:31 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-10-04 16:21:31 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-10-04 16:21:31 +00:00
2017-01-09 09:54:49 +00:00
res = moo_leints ( moo , rcv , arg ) ;
if ( ! res ) return ( moo - > errnum = = MOO_EINVAL ? MOO_PF_FAILURE : MOO_PF_HARD_FAILURE ) ;
2015-10-04 16:21:31 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , res ) ;
return MOO_PF_SUCCESS ;
2015-10-04 16:21:31 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_integer_ge ( moo_t * moo , moo_ooi_t nargs )
2015-10-04 16:21:31 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg , res ;
2015-10-04 16:21:31 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-10-04 16:21:31 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-10-04 16:21:31 +00:00
2017-01-09 09:54:49 +00:00
res = moo_geints ( moo , rcv , arg ) ;
if ( ! res ) return ( moo - > errnum = = MOO_EINVAL ? MOO_PF_FAILURE : MOO_PF_HARD_FAILURE ) ;
2015-10-04 16:21:31 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , res ) ;
return MOO_PF_SUCCESS ;
2015-10-04 16:21:31 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_integer_inttostr ( moo_t * moo , moo_ooi_t nargs )
2015-12-02 15:24:13 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg , str ;
moo_ooi_t radix ;
2015-12-02 15:24:13 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-12-13 16:08:05 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-12-02 15:24:13 +00:00
2017-01-09 09:54:49 +00:00
if ( ! MOO_OOP_IS_SMOOI ( arg ) ) return MOO_PF_FAILURE ;
radix = MOO_OOP_TO_SMOOI ( arg ) ;
2015-12-02 15:24:13 +00:00
2017-01-09 09:54:49 +00:00
if ( radix < 2 | | radix > 36 ) return MOO_PF_FAILURE ;
str = moo_inttostr ( moo , rcv , radix ) ;
if ( ! str ) return ( moo - > errnum = = MOO_EINVAL ? 0 : - 1 ) ;
2015-12-02 15:24:13 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , str ) ;
return MOO_PF_SUCCESS ;
2015-12-02 15:24:13 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_smooi_as_character ( moo_t * moo , moo_ooi_t nargs )
2016-12-28 19:12:14 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv ;
moo_ooi_t ec ;
2016-12-28 19:12:14 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 0 ) ;
2016-12-28 19:12:14 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
if ( ! MOO_OOP_IS_SMOOI ( rcv ) ) return MOO_PF_FAILURE ;
2016-12-28 19:12:14 +00:00
2017-01-09 09:54:49 +00:00
ec = MOO_OOP_TO_SMOOI ( rcv ) ;
2016-12-28 19:12:14 +00:00
if ( ec < 0 ) ec = 0 ;
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , MOO_CHAR_TO_OOP ( ec ) ) ;
return MOO_PF_SUCCESS ;
2016-12-28 19:12:14 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_smooi_as_error ( moo_t * moo , moo_ooi_t nargs )
2016-12-28 19:12:14 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv ;
moo_ooi_t ec ;
2016-12-28 19:12:14 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 0 ) ;
2016-12-28 19:12:14 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
if ( ! MOO_OOP_IS_SMOOI ( rcv ) ) return MOO_PF_FAILURE ;
2016-12-28 19:12:14 +00:00
2017-01-09 09:54:49 +00:00
ec = MOO_OOP_TO_SMOOI ( rcv ) ;
2016-12-28 19:12:14 +00:00
if ( ec < 0 ) ec = 0 ;
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , MOO_ERROR_TO_OOP ( ec ) ) ;
return MOO_PF_SUCCESS ;
2016-12-28 19:12:14 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_error_as_character ( moo_t * moo , moo_ooi_t nargs )
2016-12-28 13:42:12 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv ;
moo_ooi_t ec ;
2016-12-28 13:42:12 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 0 ) ;
2016-12-28 13:42:12 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
if ( ! MOO_OOP_IS_ERROR ( rcv ) ) return MOO_PF_FAILURE ;
2016-12-28 13:42:12 +00:00
2017-01-09 09:54:49 +00:00
ec = MOO_OOP_TO_ERROR ( rcv ) ;
MOO_ASSERT ( moo , MOO_IN_SMOOI_RANGE ( ec ) ) ;
MOO_STACK_SETRET ( moo , nargs , MOO_CHAR_TO_OOP ( ec ) ) ;
return MOO_PF_SUCCESS ;
2016-12-28 13:42:12 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_error_as_integer ( moo_t * moo , moo_ooi_t nargs )
2016-12-26 18:44:47 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv ;
moo_ooi_t ec ;
2016-12-26 18:44:47 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 0 ) ;
2016-12-26 18:44:47 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
if ( ! MOO_OOP_IS_ERROR ( rcv ) ) return MOO_PF_FAILURE ;
2016-12-26 18:44:47 +00:00
2017-01-09 09:54:49 +00:00
ec = MOO_OOP_TO_ERROR ( rcv ) ;
MOO_ASSERT ( moo , MOO_IN_SMOOI_RANGE ( ec ) ) ;
MOO_STACK_SETRET ( moo , nargs , MOO_SMOOI_TO_OOP ( ec ) ) ;
return MOO_PF_SUCCESS ;
2016-12-26 18:44:47 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_error_as_string ( moo_t * moo , moo_ooi_t nargs )
2016-12-26 18:44:47 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , ss ;
moo_ooi_t ec ;
const moo_ooch_t * s ;
2016-12-26 18:44:47 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 0 ) ;
2016-12-27 18:15:35 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
if ( ! MOO_OOP_IS_ERROR ( rcv ) ) return MOO_PF_FAILURE ;
2016-12-27 18:15:35 +00:00
2017-01-09 09:54:49 +00:00
ec = MOO_OOP_TO_ERROR ( rcv ) ;
MOO_ASSERT ( moo , MOO_IN_SMOOI_RANGE ( ec ) ) ;
2016-12-27 18:15:35 +00:00
/* TODO: error string will be mostly the same.. do i really have to call makestring every time? */
2017-01-09 09:54:49 +00:00
s = moo_errnumtoerrstr ( ec ) ;
ss = moo_makestring ( moo , s , moo_countoocstr ( s ) ) ;
if ( ! ss ) return MOO_PF_HARD_FAILURE ;
2016-12-27 18:15:35 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , ss ) ;
return MOO_PF_SUCCESS ;
2016-12-26 18:44:47 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_ffi_open ( moo_t * moo , moo_ooi_t nargs )
2015-10-03 15:29:03 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg ;
2015-10-03 15:29:03 +00:00
void * handle ;
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-10-03 15:29:03 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-10-03 15:29:03 +00:00
2017-01-09 09:54:49 +00:00
if ( ! MOO_ISTYPEOF ( moo , arg , MOO_OBJ_TYPE_CHAR ) )
2015-10-03 15:29:03 +00:00
{
/* TODO: more info on error */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-10-03 15:29:03 +00:00
}
2017-01-09 09:54:49 +00:00
if ( ! moo - > vmprim . dl_open )
2015-10-03 15:29:03 +00:00
{
/* TODO: more info on error */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-10-03 15:29:03 +00:00
}
2015-10-14 13:25:36 +00:00
2015-10-13 14:51:04 +00:00
/* TODO: check null-termination... */
2017-01-09 09:54:49 +00:00
handle = moo - > vmprim . dl_open ( moo , ( ( moo_oop_char_t ) arg ) - > slot ) ;
2015-10-13 14:51:04 +00:00
if ( ! handle )
2015-10-03 15:29:03 +00:00
{
/* TODO: more info on error */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-10-03 15:29:03 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_STACK_POP ( moo ) ;
2015-12-03 05:46:11 +00:00
/* TODO: how to hold an address? as an integer???? or a byte array? fix this not to loose accuracy*/
2017-01-09 09:54:49 +00:00
MOO_STACK_SETTOP ( moo , MOO_SMOOI_TO_OOP ( handle ) ) ;
2015-10-03 15:29:03 +00:00
2017-01-09 09:54:49 +00:00
return MOO_PF_SUCCESS ;
2015-10-03 15:29:03 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_ffi_close ( moo_t * moo , moo_ooi_t nargs )
2015-10-03 15:29:03 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , arg ;
2015-10-03 15:29:03 +00:00
void * handle ;
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 1 ) ;
2015-10-03 15:29:03 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GETRCV ( moo , nargs ) ;
arg = MOO_STACK_GETARG ( moo , nargs , 0 ) ;
2015-10-03 15:29:03 +00:00
2017-01-09 09:54:49 +00:00
if ( ! MOO_OOP_IS_SMOOI ( arg ) )
2015-10-03 15:29:03 +00:00
{
/* TODO: more info on error */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-10-03 15:29:03 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_STACK_POP ( moo ) ;
2015-10-03 15:29:03 +00:00
2017-01-09 09:54:49 +00:00
handle = ( void * ) MOO_OOP_TO_SMOOI ( arg ) ; /* TODO: how to store void* ???. fix this not to loose accuracy */
if ( moo - > vmprim . dl_close ) moo - > vmprim . dl_close ( moo , handle ) ;
return MOO_PF_SUCCESS ;
2015-10-03 15:29:03 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_ffi_call ( moo_t * moo , moo_ooi_t nargs )
2015-10-03 15:29:03 +00:00
{
2015-11-03 14:58:19 +00:00
# if defined(USE_DYNCALL)
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , fun , sig , args ;
2015-10-03 15:29:03 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 3 ) ;
2015-10-03 15:29:03 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GET ( moo , moo - > sp - 3 ) ;
fun = MOO_STACK_GET ( moo , moo - > sp - 2 ) ;
sig = MOO_STACK_GET ( moo , moo - > sp - 1 ) ;
args = MOO_STACK_GET ( moo , moo - > sp ) ;
2015-10-03 15:29:03 +00:00
2017-01-09 09:54:49 +00:00
if ( ! MOO_OOP_IS_SMOOI ( fun ) ) /* TODO: how to store pointer */
2015-10-03 15:29:03 +00:00
{
/* TODO: more info on error */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-10-03 15:29:03 +00:00
}
2017-01-09 09:54:49 +00:00
if ( ! MOO_ISTYPEOF ( moo , sig , MOO_OBJ_TYPE_CHAR ) | | MOO_OBJ_GET_SIZE ( sig ) < = 0 )
2015-10-04 16:21:31 +00:00
{
2017-01-09 09:54:49 +00:00
MOO_DEBUG0 ( moo , " FFI: wrong signature... \n " ) ;
return MOO_PF_FAILURE ;
2015-10-04 16:21:31 +00:00
}
2017-01-09 09:54:49 +00:00
if ( MOO_CLASSOF ( moo , args ) ! = moo - > _array ) /* TODO: check if arr is a kind of array??? or check if it's indexed */
2015-10-03 15:29:03 +00:00
{
/* TODO: more info on error */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-10-03 15:29:03 +00:00
}
2015-10-04 16:21:31 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oow_t i ;
2015-10-04 16:21:31 +00:00
DCCallVM * dc ;
void * f ;
2017-01-09 09:54:49 +00:00
moo_oop_oop_t arr ;
2015-10-04 16:21:31 +00:00
int mode_set ;
2017-01-09 09:54:49 +00:00
f = MOO_OOP_TO_SMOOI ( fun ) ; /* TODO: decode pointer properly */
arr = ( moo_oop_oop_t ) args ;
2015-10-04 16:21:31 +00:00
dc = dcNewCallVM ( 4096 ) ;
2017-01-09 09:54:49 +00:00
if ( ! dc ) return MOO_PF_HARD_FAILURE ; /* TODO: proper error handling */
2015-10-04 16:21:31 +00:00
2017-01-09 09:54:49 +00:00
MOO_DEBUG1 ( moo , " FFI: CALLING............%p \n " , f ) ;
2015-10-14 09:06:44 +00:00
/*dcMode (dc, DC_CALL_C_DEFAULT);
dcReset ( dc ) ; */
2015-10-04 16:21:31 +00:00
2017-01-09 09:54:49 +00:00
/*for (i = 2; i < MOO_OBJ_GET_SIZE(sig); i++)
2015-10-04 16:21:31 +00:00
{
2017-01-09 09:54:49 +00:00
if ( ( ( moo_oop_char_t ) sig ) - > slot [ i ] = = ' | ' )
2015-10-04 16:21:31 +00:00
{
dcMode ( dc , DC_CALL_C_ELLIPSIS ) ;
2017-01-09 09:54:49 +00:00
MOO_DEBUG0 ( moo , " CALL MODE 111 ERROR %d %d \n " , dcGetError ( dc ) , DC_ERROR_UNSUPPORTED_MODE ) ;
2015-10-04 16:21:31 +00:00
mode_set = 1 ;
break ;
}
}
if ( ! mode_set ) */ dcMode ( dc , DC_CALL_C_DEFAULT ) ;
2017-01-09 09:54:49 +00:00
for ( i = 2 ; i < MOO_OBJ_GET_SIZE ( sig ) ; i + + )
2015-10-04 16:21:31 +00:00
{
2017-01-09 09:54:49 +00:00
MOO_DEBUG1 ( moo , " FFI: CALLING ARG %c \n " , ( ( moo_oop_char_t ) sig ) - > slot [ i ] ) ;
switch ( ( ( moo_oop_char_t ) sig ) - > slot [ i ] )
2015-10-04 16:21:31 +00:00
{
/* TODO: support more types... */
/*
case ' | ' :
dcMode ( dc , DC_CALL_C_ELLIPSIS_VARARGS ) ;
2017-01-09 09:54:49 +00:00
MOO_DEBUG2 ( moo , " CALL MODE 222 ERROR %d %d \n " , dcGetError ( dc ) , DC_ERROR_UNSUPPORTED_MODE ) ;
2015-10-04 16:21:31 +00:00
break ;
*/
case ' c ' :
/* TODO: sanity check on the argument type */
2017-01-09 09:54:49 +00:00
dcArgChar ( dc , MOO_OOP_TO_CHAR ( arr - > slot [ i - 2 ] ) ) ;
2015-10-04 16:21:31 +00:00
break ;
case ' i ' :
2017-01-09 09:54:49 +00:00
dcArgInt ( dc , MOO_OOP_TO_SMOOI ( arr - > slot [ i - 2 ] ) ) ;
2015-10-04 16:21:31 +00:00
break ;
case ' l ' :
2017-01-09 09:54:49 +00:00
dcArgLong ( dc , MOO_OOP_TO_SMOOI ( arr - > slot [ i - 2 ] ) ) ;
2015-10-04 16:21:31 +00:00
break ;
case ' L ' :
2017-01-09 09:54:49 +00:00
dcArgLongLong ( dc , MOO_OOP_TO_SMOOI ( arr - > slot [ i - 2 ] ) ) ;
2015-10-04 16:21:31 +00:00
break ;
case ' s ' :
{
2017-01-09 09:54:49 +00:00
moo_oow_t bcslen , ucslen ;
moo_bch_t bcs [ 1024 ] ;
2015-10-04 16:21:31 +00:00
2017-01-09 09:54:49 +00:00
ucslen = MOO_OBJ_GET_SIZE ( arr - > slot [ i - 2 ] ) ;
moo_convootobchars ( moo , ( ( moo_oop_char_t ) arr - > slot [ i - 2 ] ) - > slot , & ucslen , bcs , & bcslen ) ; /* proper string conversion */
2015-10-04 16:21:31 +00:00
bcs [ bcslen ] = ' \0 ' ;
dcArgPointer ( dc , bcs ) ;
break ;
}
default :
/* TODO: ERROR HANDLING */
break ;
}
}
2017-01-09 09:54:49 +00:00
MOO_STACK_POPS ( moo , nargs ) ;
2015-10-04 16:21:31 +00:00
2017-01-09 09:54:49 +00:00
switch ( ( ( moo_oop_char_t ) sig ) - > slot [ 0 ] )
2015-10-04 16:21:31 +00:00
{
/* TODO: support more types... */
/* TODO: proper return value conversion */
case ' c ' :
{
char r = dcCallChar ( dc , f ) ;
2017-01-09 09:54:49 +00:00
MOO_STACK_SETTOP ( moo , MOO_CHAR_TO_OOP ( r ) ) ;
2015-10-04 16:21:31 +00:00
break ;
}
case ' i ' :
{
int r = dcCallInt ( dc , f ) ;
2017-01-09 09:54:49 +00:00
MOO_DEBUG1 ( moo , " CALLED... %d \n " , r ) ;
MOO_DEBUG2 ( moo , " CALL ERROR %d %d \n " , dcGetError ( dc ) , DC_ERROR_UNSUPPORTED_MODE ) ;
MOO_STACK_SETTOP ( moo , MOO_SMOOI_TO_OOP ( r ) ) ;
2015-10-04 16:21:31 +00:00
break ;
}
case ' l ' :
{
long r = dcCallLong ( dc , f ) ;
2017-01-09 09:54:49 +00:00
MOO_STACK_SETTOP ( moo , MOO_SMOOI_TO_OOP ( r ) ) ;
2015-10-04 16:21:31 +00:00
break ;
}
case ' L ' :
{
long long r = dcCallLongLong ( dc , f ) ;
2017-01-09 09:54:49 +00:00
MOO_STACK_SETTOP ( moo , MOO_SMOOI_TO_OOP ( r ) ) ;
2015-10-04 16:21:31 +00:00
break ;
}
case ' s ' :
{
2017-01-09 09:54:49 +00:00
moo_oow_t bcslen , ucslen ;
moo_ooch_t ucs [ 1024 ] ;
moo_oop_t s ;
2015-10-04 16:21:31 +00:00
char * r = dcCallPointer ( dc , f ) ;
2016-11-27 15:37:14 +00:00
2015-10-04 16:21:31 +00:00
bcslen = strlen ( r ) ;
2017-01-09 09:54:49 +00:00
moo_convbtooochars ( moo , r , & bcslen , ucs , & ucslen ) ; /* proper string conversion */
2015-10-04 16:21:31 +00:00
2017-01-09 09:54:49 +00:00
s = moo_makestring ( moo , ucs , ucslen )
2015-12-02 15:24:13 +00:00
if ( ! s )
{
dcFree ( dc ) ;
2017-01-09 09:54:49 +00:00
return MOO_PF_HARD_FAILURE ; /* TODO: proper error h andling */
2015-12-02 15:24:13 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_STACK_SETTOP ( moo , s ) ;
2015-10-04 16:21:31 +00:00
break ;
}
default :
/* TOOD: ERROR HANDLING */
break ;
}
dcFree ( dc ) ;
}
2017-01-09 09:54:49 +00:00
return MOO_PF_SUCCESS ;
2015-11-03 14:58:19 +00:00
# else
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-11-03 14:58:19 +00:00
# endif
2015-10-03 15:29:03 +00:00
}
2017-01-09 09:54:49 +00:00
static moo_pfrc_t pf_ffi_getsym ( moo_t * moo , moo_ooi_t nargs )
2015-10-03 15:29:03 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t rcv , hnd , fun ;
2015-10-04 16:21:31 +00:00
void * sym ;
2015-10-03 15:29:03 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs = = 2 ) ;
2015-10-03 15:29:03 +00:00
2017-01-09 09:54:49 +00:00
rcv = MOO_STACK_GET ( moo , moo - > sp - 2 ) ;
fun = MOO_STACK_GET ( moo , moo - > sp - 1 ) ;
hnd = MOO_STACK_GET ( moo , moo - > sp ) ;
2015-10-03 15:29:03 +00:00
2017-01-09 09:54:49 +00:00
if ( ! MOO_OOP_IS_SMOOI ( hnd ) ) /* TODO: how to store pointer */
2015-10-03 15:29:03 +00:00
{
/* TODO: more info on error */
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-10-03 15:29:03 +00:00
}
2017-01-09 09:54:49 +00:00
if ( ! MOO_ISTYPEOF ( moo , fun , MOO_OBJ_TYPE_CHAR ) )
2015-10-03 15:29:03 +00:00
{
2017-01-09 09:54:49 +00:00
MOO_DEBUG0 ( moo , " wrong function name... \n " ) ;
return MOO_PF_FAILURE ;
2015-10-03 15:29:03 +00:00
}
2017-01-09 09:54:49 +00:00
if ( ! moo - > vmprim . dl_getsym )
2015-10-03 15:29:03 +00:00
{
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-10-03 15:29:03 +00:00
}
2017-01-09 09:54:49 +00:00
sym = moo - > vmprim . dl_getsym ( moo , ( void * ) MOO_OOP_TO_SMOOI ( hnd ) , ( ( moo_oop_char_t ) fun ) - > slot ) ;
2015-10-13 14:51:04 +00:00
if ( ! sym )
2015-10-03 15:29:03 +00:00
{
2017-01-09 09:54:49 +00:00
return MOO_PF_FAILURE ;
2015-10-03 15:29:03 +00:00
}
/* TODO: how to hold an address? as an integer???? or a byte array? */
2017-01-09 09:54:49 +00:00
MOO_STACK_SETRET ( moo , nargs , MOO_SMOOI_TO_OOP ( sym ) ) ;
2015-10-03 15:29:03 +00:00
2017-01-09 09:54:49 +00:00
return MOO_PF_SUCCESS ;
2015-10-03 15:29:03 +00:00
}
2015-06-22 14:21:46 +00:00
2017-01-09 09:54:49 +00:00
# define MAX_NARGS MOO_TYPE_MAX(moo_ooi_t)
2016-11-29 05:25:08 +00:00
struct pf_t
2015-06-14 07:15:53 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t min_nargs ; /* expected number of arguments */
moo_ooi_t max_nargs ; /* expected number of arguments */
moo_pfimpl_t handler ;
2016-11-29 05:25:08 +00:00
const char * name ; /* the name is supposed to be 7-bit ascii only */
2015-06-14 07:15:53 +00:00
} ;
2016-11-29 05:25:08 +00:00
typedef struct pf_t pf_t ;
static pf_t pftab [ ] =
{
{ 0 , MAX_NARGS , pf_dump , " _dump " } ,
{ 2 , MAX_NARGS , pf_log , " _log " } ,
{ 1 , 1 , pf_identical , " _identical " } ,
{ 1 , 1 , pf_not_identical , " _not_identical " } ,
2017-01-06 09:53:40 +00:00
{ 1 , 1 , pf_equal , " _equal " } ,
{ 1 , 1 , pf_not_equal , " _not_equal " } ,
2016-11-29 05:25:08 +00:00
{ 0 , 0 , pf_class , " _class " } ,
{ 0 , 0 , pf_basic_new , " _basic_new " } ,
{ 1 , 1 , pf_basic_new_with_size , " _basic_new_with_size " } ,
{ 0 , 0 , pf_ngc_new , " _ngc_new " } ,
{ 1 , 1 , pf_ngc_new_with_size , " _ngc_new_with_size " } ,
{ 0 , 0 , pf_ngc_dispose , " _ngc_dispose " } ,
{ 0 , 0 , pf_shallow_copy , " _shallow_copy " } ,
{ 0 , 0 , pf_basic_size , " _basic_size " } ,
{ 1 , 1 , pf_basic_at , " _basic_at " } ,
{ 2 , 2 , pf_basic_at_put , " _basic_at_put " } ,
2017-01-05 10:16:04 +00:00
{ 0 , 0 , pf_hash , " _hash " } ,
{ 1 , 1 , pf_exceptionize_error , " _exceptionize_error " } ,
2016-11-29 05:25:08 +00:00
{ 1 , 1 , pf_context_goto , " _context_goto " } ,
{ 0 , MAX_NARGS , pf_block_value , " _block_value " } ,
{ 0 , MAX_NARGS , pf_block_new_process , " _block_new_process " } ,
{ 0 , 0 , pf_process_resume , " _process_resume " } ,
{ 0 , 0 , pf_process_terminate , " _process_terminate " } ,
{ 0 , 0 , pf_process_yield , " _process_yield " } ,
{ 0 , 0 , pf_process_suspend , " _process_suspend " } ,
{ 0 , 0 , pf_semaphore_signal , " _semaphore_signal " } ,
{ 0 , 0 , pf_semaphore_wait , " _semaphore_wait " } ,
{ 1 , 1 , pf_processor_schedule , " _processor_schedule " } ,
{ 2 , 3 , pf_processor_add_timed_semaphore , " _processor_add_timed_semaphore " } ,
{ 1 , 1 , pf_processor_remove_semaphore , " _processor_remove_semaphore " } ,
{ 2 , 2 , pf_processor_return_to , " _processor_return_to " } ,
{ 1 , 1 , pf_integer_add , " _integer_add " } ,
{ 1 , 1 , pf_integer_sub , " _integer_sub " } ,
{ 1 , 1 , pf_integer_mul , " _integer_mul " } ,
{ 1 , 1 , pf_integer_quo , " _integer_quo " } ,
{ 1 , 1 , pf_integer_rem , " _integer_rem " } ,
{ 1 , 1 , pf_integer_quo2 , " _integer_quo2 " } ,
{ 1 , 1 , pf_integer_rem2 , " _integer_rem2 " } ,
{ 0 , 0 , pf_integer_negated , " _integer_negated " } ,
{ 1 , 1 , pf_integer_bitat , " _integer_bitat " } ,
{ 1 , 1 , pf_integer_bitand , " _integer_bitand " } ,
{ 1 , 1 , pf_integer_bitor , " _integer_bitor " } ,
{ 1 , 1 , pf_integer_bitxor , " _integer_bitxor " } ,
{ 0 , 0 , pf_integer_bitinv , " _integer_bitinv " } ,
{ 1 , 1 , pf_integer_bitshift , " _integer_bitshift " } ,
{ 1 , 1 , pf_integer_eq , " _integer_eq " } ,
{ 1 , 1 , pf_integer_ne , " _integer_ne " } ,
{ 1 , 1 , pf_integer_lt , " _integer_lt " } ,
{ 1 , 1 , pf_integer_gt , " _integer_gt " } ,
{ 1 , 1 , pf_integer_le , " _integer_le " } ,
{ 1 , 1 , pf_integer_ge , " _integer_ge " } ,
{ 1 , 1 , pf_integer_inttostr , " _integer_inttostr " } ,
2016-12-28 19:12:14 +00:00
{ 0 , 0 , pf_smooi_as_character , " _smooi_as_character " } ,
{ 0 , 0 , pf_smooi_as_error , " _smooi_as_error " } ,
2016-12-28 13:42:12 +00:00
{ 0 , 0 , pf_error_as_character , " _error_as_character " } ,
2016-12-27 18:15:35 +00:00
{ 0 , 0 , pf_error_as_integer , " _error_as_integer " } ,
2016-12-26 18:44:47 +00:00
{ 0 , 0 , pf_error_as_string , " _error_as_string " } ,
2016-12-27 18:15:35 +00:00
2016-11-29 05:25:08 +00:00
{ 1 , 1 , pf_ffi_open , " _ffi_open " } ,
{ 1 , 1 , pf_ffi_close , " _ffi_close " } ,
{ 2 , 2 , pf_ffi_getsym , " _ffi_getsym " } ,
{ 3 , 3 , pf_ffi_call , " _ffi_call " }
2015-10-13 14:51:04 +00:00
2015-06-14 07:15:53 +00:00
} ;
2015-06-11 09:11:18 +00:00
2017-01-09 09:54:49 +00:00
int moo_getpfnum ( moo_t * moo , const moo_ooch_t * ptr , moo_oow_t len )
2015-10-03 15:29:03 +00:00
{
int i ;
2017-01-09 09:54:49 +00:00
for ( i = 0 ; i < MOO_COUNTOF ( pftab ) ; i + + )
2015-10-03 15:29:03 +00:00
{
2017-01-09 09:54:49 +00:00
if ( moo_compoocharsbcstr ( ptr , len , pftab [ i ] . name ) = = 0 )
2015-10-03 15:29:03 +00:00
{
return i ;
}
}
2017-01-09 09:54:49 +00:00
moo - > errnum = MOO_ENOENT ;
2015-10-03 15:29:03 +00:00
return - 1 ;
}
2015-12-27 10:19:36 +00:00
/* ------------------------------------------------------------------------- */
2017-01-09 09:54:49 +00:00
static int start_method ( moo_t * moo , moo_oop_method_t method , moo_oow_t nargs )
2015-12-27 10:19:36 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t preamble , preamble_code ;
2015-12-27 10:19:36 +00:00
2017-01-09 09:54:49 +00:00
# if defined(MOO_DEBUG_VM_EXEC)
moo_ooi_t fetched_instruction_pointer = 0 ; /* set it to a fake value */
2016-10-06 14:17:24 +00:00
# endif
2017-01-09 09:54:49 +00:00
preamble = MOO_OOP_TO_SMOOI ( method - > preamble ) ;
2016-12-14 07:18:01 +00:00
2017-01-09 09:54:49 +00:00
if ( nargs ! = MOO_OOP_TO_SMOOI ( method - > tmpr_nargs ) )
2016-12-13 15:18:19 +00:00
{
2016-12-14 07:18:01 +00:00
2017-01-09 09:54:49 +00:00
moo_ooi_t preamble_flags ;
2016-12-14 07:18:01 +00:00
2017-01-09 09:54:49 +00:00
preamble_flags = MOO_METHOD_GET_PREAMBLE_FLAGS ( preamble ) ;
if ( ! ( preamble_flags & MOO_METHOD_PREAMBLE_FLAG_VARIADIC ) )
2016-12-14 07:18:01 +00:00
{
2017-01-09 09:54:49 +00:00
/* TODO: better to throw a moo exception so that the caller can catch it??? */
MOO_LOG3 ( moo , MOO_LOG_IC | MOO_LOG_FATAL ,
2016-12-14 07:18:01 +00:00
" Fatal error - Argument count mismatch for a non-variadic method [%O] - %zd expected, %zu given \n " ,
2017-01-09 09:54:49 +00:00
method - > name , MOO_OOP_TO_SMOOI ( method - > tmpr_nargs ) , nargs ) ;
moo - > errnum = MOO_EINVAL ;
2016-12-14 07:18:01 +00:00
return - 1 ;
}
2016-12-13 15:18:19 +00:00
}
2015-12-27 10:19:36 +00:00
2017-01-09 09:54:49 +00:00
preamble_code = MOO_METHOD_GET_PREAMBLE_CODE ( preamble ) ;
2015-12-27 10:19:36 +00:00
switch ( preamble_code )
{
2017-01-09 09:54:49 +00:00
case MOO_METHOD_PREAMBLE_RETURN_RECEIVER :
LOG_INST_0 ( moo , " preamble_return_receiver " ) ;
MOO_STACK_POPS ( moo , nargs ) ; /* pop arguments only*/
2015-12-27 10:19:36 +00:00
break ;
2017-01-09 09:54:49 +00:00
case MOO_METHOD_PREAMBLE_RETURN_NIL :
LOG_INST_0 ( moo , " preamble_return_nil " ) ;
MOO_STACK_POPS ( moo , nargs ) ;
MOO_STACK_SETTOP ( moo , moo - > _nil ) ;
2015-12-27 10:19:36 +00:00
break ;
2017-01-09 09:54:49 +00:00
case MOO_METHOD_PREAMBLE_RETURN_TRUE :
LOG_INST_0 ( moo , " preamble_return_true " ) ;
MOO_STACK_POPS ( moo , nargs ) ;
MOO_STACK_SETTOP ( moo , moo - > _true ) ;
2015-12-27 10:19:36 +00:00
break ;
2017-01-09 09:54:49 +00:00
case MOO_METHOD_PREAMBLE_RETURN_FALSE :
LOG_INST_0 ( moo , " preamble_return_false " ) ;
MOO_STACK_POPS ( moo , nargs ) ;
MOO_STACK_SETTOP ( moo , moo - > _false ) ;
2015-12-27 10:19:36 +00:00
break ;
2017-01-09 09:54:49 +00:00
case MOO_METHOD_PREAMBLE_RETURN_INDEX :
2016-06-05 18:01:35 +00:00
/* preamble_index field is used to store a positive integer */
2017-01-09 09:54:49 +00:00
LOG_INST_1 ( moo , " preamble_return_index %zd " , MOO_METHOD_GET_PREAMBLE_INDEX ( preamble ) ) ;
MOO_STACK_POPS ( moo , nargs ) ;
MOO_STACK_SETTOP ( moo , MOO_SMOOI_TO_OOP ( MOO_METHOD_GET_PREAMBLE_INDEX ( preamble ) ) ) ;
2015-12-27 10:19:36 +00:00
break ;
2017-01-09 09:54:49 +00:00
case MOO_METHOD_PREAMBLE_RETURN_NEGINDEX :
2016-06-05 18:01:35 +00:00
/* preamble_index field is used to store a negative integer */
2017-01-09 09:54:49 +00:00
LOG_INST_1 ( moo , " preamble_return_negindex %zd " , MOO_METHOD_GET_PREAMBLE_INDEX ( preamble ) ) ;
MOO_STACK_POPS ( moo , nargs ) ;
MOO_STACK_SETTOP ( moo , MOO_SMOOI_TO_OOP ( - MOO_METHOD_GET_PREAMBLE_INDEX ( preamble ) ) ) ;
2015-12-27 10:19:36 +00:00
break ;
2017-01-09 09:54:49 +00:00
case MOO_METHOD_PREAMBLE_RETURN_INSTVAR :
2015-12-27 10:19:36 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_oop_t rcv ;
2015-12-27 10:19:36 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_POPS ( moo , nargs ) ; /* pop arguments only */
2015-12-27 10:19:36 +00:00
2017-01-09 09:54:49 +00:00
LOG_INST_1 ( moo , " preamble_return_instvar %zd " , MOO_METHOD_GET_PREAMBLE_INDEX ( preamble ) ) ;
2015-12-27 10:19:36 +00:00
/* replace the receiver by an instance variable of the receiver */
2017-01-09 09:54:49 +00:00
rcv = ( moo_oop_oop_t ) MOO_STACK_GETTOP ( moo ) ;
MOO_ASSERT ( moo , MOO_OBJ_GET_FLAGS_TYPE ( rcv ) = = MOO_OBJ_TYPE_OOP ) ;
MOO_ASSERT ( moo , MOO_OBJ_GET_SIZE ( rcv ) > MOO_METHOD_GET_PREAMBLE_INDEX ( preamble ) ) ;
2015-12-27 10:19:36 +00:00
2017-01-09 09:54:49 +00:00
if ( rcv = = ( moo_oop_oop_t ) moo - > active_context )
2015-12-27 10:19:36 +00:00
{
/* 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 .
*/
2017-01-09 09:54:49 +00:00
STORE_ACTIVE_IP ( moo ) ;
STORE_ACTIVE_SP ( moo ) ;
2015-12-27 10:19:36 +00:00
}
/* this accesses the instance variable of the receiver */
2017-01-09 09:54:49 +00:00
MOO_STACK_SET ( moo , moo - > sp , rcv - > slot [ MOO_METHOD_GET_PREAMBLE_INDEX ( preamble ) ] ) ;
2015-12-27 10:19:36 +00:00
break ;
}
2017-01-09 09:54:49 +00:00
case MOO_METHOD_PREAMBLE_PRIMITIVE :
2015-12-27 10:19:36 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t pfnum ;
2015-12-27 10:19:36 +00:00
2017-01-09 09:54:49 +00:00
pfnum = MOO_METHOD_GET_PREAMBLE_INDEX ( preamble ) ;
LOG_INST_1 ( moo , " preamble_primitive %zd " , pf_no ) ;
2015-12-27 10:19:36 +00:00
2017-01-09 09:54:49 +00:00
if ( pfnum > = 0 & & pfnum < MOO_COUNTOF ( pftab ) & &
2016-11-29 05:25:08 +00:00
( nargs > = pftab [ pfnum ] . min_nargs & & nargs < = pftab [ pfnum ] . max_nargs ) )
2015-12-27 10:19:36 +00:00
{
int n ;
2017-01-09 09:54:49 +00:00
moo_pushtmp ( moo , ( moo_oop_t * ) & method ) ;
n = pftab [ pfnum ] . handler ( moo , nargs ) ;
moo_poptmp ( moo ) ;
if ( n < = MOO_PF_HARD_FAILURE ) return - 1 ;
if ( n > = MOO_PF_SUCCESS ) break ;
2015-12-27 10:19:36 +00:00
}
/* soft primitive failure */
2017-01-09 09:54:49 +00:00
if ( activate_new_method ( moo , method , nargs ) < = - 1 ) return - 1 ;
2015-12-27 10:19:36 +00:00
break ;
}
2017-01-09 09:54:49 +00:00
case MOO_METHOD_PREAMBLE_NAMED_PRIMITIVE :
2015-12-27 10:19:36 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t pf_name_index ;
moo_oop_t name ;
moo_pfimpl_t handler ;
moo_oow_t w ;
moo_ooi_t /*sp,*/ sb ;
2016-11-12 03:02:12 +00:00
2017-01-09 09:54:49 +00:00
/*sp = moo->sp;*/
sb = moo - > sp - nargs - 1 ; /* stack base before receiver and arguments */
2015-12-27 10:19:36 +00:00
2017-01-09 09:54:49 +00:00
pf_name_index = MOO_METHOD_GET_PREAMBLE_INDEX ( preamble ) ;
LOG_INST_1 ( moo , " preamble_named_primitive %zd " , pf_name_index ) ;
2015-12-27 10:19:36 +00:00
/* merge two SmallIntegers to get a full pointer */
2017-01-09 09:54:49 +00:00
w = ( moo_oow_t ) MOO_OOP_TO_SMOOI ( method - > preamble_data [ 0 ] ) < < ( MOO_OOW_BITS / 2 ) |
( moo_oow_t ) MOO_OOP_TO_SMOOI ( method - > preamble_data [ 1 ] ) ;
handler = ( moo_pfimpl_t ) w ;
2016-11-12 03:02:12 +00:00
if ( handler ) goto exec_handler ;
else
{
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , pf_name_index > = 0 ) ;
2016-11-29 05:25:08 +00:00
name = method - > slot [ pf_name_index ] ;
2016-11-12 03:02:12 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_ISTYPEOF ( moo , name , MOO_OBJ_TYPE_CHAR ) ) ;
MOO_ASSERT ( moo , MOO_OBJ_GET_FLAGS_EXTRA ( name ) ) ;
MOO_ASSERT ( moo , MOO_CLASSOF ( moo , name ) = = moo - > _symbol ) ;
2016-11-12 03:02:12 +00:00
2017-01-09 09:54:49 +00:00
handler = moo_querymod ( moo , ( ( moo_oop_char_t ) name ) - > slot , MOO_OBJ_GET_SIZE ( name ) ) ;
2016-11-12 03:02:12 +00:00
}
2015-12-27 10:19:36 +00:00
if ( handler )
{
int n ;
/* split a pointer to two OOP fields as SmallIntegers for storing. */
2017-01-09 09:54:49 +00:00
method - > preamble_data [ 0 ] = MOO_SMOOI_TO_OOP ( ( moo_oow_t ) handler > > ( MOO_OOW_BITS / 2 ) ) ;
method - > preamble_data [ 1 ] = MOO_SMOOI_TO_OOP ( ( moo_oow_t ) handler & MOO_LBMASK ( moo_oow_t , MOO_OOW_BITS / 2 ) ) ;
2015-12-27 10:19:36 +00:00
2016-11-12 03:02:12 +00:00
exec_handler :
2017-01-09 09:54:49 +00:00
moo_pushtmp ( moo , ( moo_oop_t * ) & method ) ;
2016-12-14 07:18:01 +00:00
/* the primitive handler is executed without activating the method itself.
* one major difference between the primitive function and the normal method
* invocation is that the primitive function handler should access arguments
* directly in the stack unlik a normal activated method context where the
* arguments are copied to the back . */
2016-12-14 09:40:41 +00:00
2017-01-09 09:54:49 +00:00
n = handler ( moo , nargs ) ;
2016-12-13 15:18:19 +00:00
2017-01-09 09:54:49 +00:00
moo_poptmp ( moo ) ;
if ( n < = MOO_PF_HARD_FAILURE )
2016-11-12 03:02:12 +00:00
{
2017-01-09 09:54:49 +00:00
MOO_DEBUG2 ( moo , " Hard failure indicated by primitive function %p - return code %d \n " , handler , n ) ;
2016-11-12 03:02:12 +00:00
return - 1 ; /* hard primitive failure */
}
2017-01-09 09:54:49 +00:00
if ( n > = MOO_PF_SUCCESS ) break ; /* primitive ok*/
2015-12-27 10:19:36 +00:00
2016-12-03 18:08:31 +00:00
/* soft primitive failure */
2017-01-09 09:54:49 +00:00
MOO_DEBUG1 ( moo , " Soft failure indicated by primitive function %p \n " , handler ) ;
2016-12-03 18:08:31 +00:00
}
else
{
/* no handler found */
2017-01-09 09:54:49 +00:00
MOO_DEBUG0 ( moo , " Soft failure for non-existent primitive function \n " ) ;
2016-12-03 18:08:31 +00:00
}
2016-11-12 03:02:12 +00:00
2017-01-09 09:54:49 +00:00
# if defined(MOO_USE_OBJECT_TRAILER)
MOO_ASSERT ( moo , MOO_OBJ_GET_FLAGS_TRAILER ( method ) ) ;
if ( MOO_METHOD_GET_CODE_SIZE ( method ) = = 0 ) /* this trailer size field not a small integer */
2016-11-12 03:02:12 +00:00
# else
2017-01-09 09:54:49 +00:00
if ( method - > code = = moo - > _nil )
2016-11-12 03:02:12 +00:00
# endif
{
/* no byte code to execute */
/* TODO: what is the best tactics? emulate "self primitiveFailed"? */
/* force restore stack pointers */
2017-01-09 09:54:49 +00:00
moo - > sp = sb ;
MOO_STACK_PUSH ( moo , moo - > _nil ) ;
2016-11-12 03:02:12 +00:00
return - 1 ;
}
else
{
2017-01-09 09:54:49 +00:00
if ( activate_new_method ( moo , method , nargs ) < = - 1 ) return - 1 ;
2016-11-12 03:02:12 +00:00
}
2015-12-27 10:19:36 +00:00
break ;
}
default :
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , preamble_code = = MOO_METHOD_PREAMBLE_NONE | |
preamble_code = = MOO_METHOD_PREAMBLE_EXCEPTION | |
preamble_code = = MOO_METHOD_PREAMBLE_ENSURE ) ;
if ( activate_new_method ( moo , method , nargs ) < = - 1 ) return - 1 ;
2015-12-27 10:19:36 +00:00
break ;
}
return 0 ;
}
2017-01-09 09:54:49 +00:00
static int send_message ( moo_t * moo , moo_oop_char_t selector , int to_super , moo_ooi_t nargs )
2016-06-20 15:42:51 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oocs_t mthname ;
moo_oop_t receiver ;
moo_oop_method_t method ;
2016-06-20 15:42:51 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_OOP_IS_POINTER ( selector ) ) ;
MOO_ASSERT ( moo , MOO_OBJ_GET_FLAGS_TYPE ( selector ) = = MOO_OBJ_TYPE_CHAR ) ;
MOO_ASSERT ( moo , MOO_CLASSOF ( moo , selector ) = = moo - > _symbol ) ;
2016-06-20 15:42:51 +00:00
2017-01-09 09:54:49 +00:00
receiver = MOO_STACK_GET ( moo , moo - > sp - nargs ) ;
2016-06-20 15:42:51 +00:00
mthname . ptr = selector - > slot ;
2017-01-09 09:54:49 +00:00
mthname . len = MOO_OBJ_GET_SIZE ( selector ) ;
method = find_method ( moo , receiver , & mthname , to_super ) ;
2016-06-20 15:42:51 +00:00
if ( ! method )
{
2017-01-09 09:54:49 +00:00
static moo_ooch_t fbm [ ] = {
2016-06-20 15:42:51 +00:00
' d ' , ' o ' , ' e ' , ' s ' ,
' N ' , ' o ' , ' t ' ,
' U ' , ' n ' , ' d ' , ' e ' , ' r ' , ' s ' , ' t ' , ' a ' , ' n ' , ' d ' , ' : '
} ;
mthname . ptr = fbm ;
mthname . len = 18 ;
2017-01-09 09:54:49 +00:00
method = find_method ( moo , receiver , & mthname , 0 ) ;
2016-06-20 15:42:51 +00:00
if ( ! method )
{
/* this must not happen as long as doesNotUnderstand: is implemented under Apex.
* this check should indicate a very serious internal problem */
2017-01-09 09:54:49 +00:00
MOO_LOG4 ( moo , MOO_LOG_IC | MOO_LOG_FATAL ,
2017-01-06 10:42:59 +00:00
" Fatal error - receiver [%O] of class [%O] does not understand a message [%.*js] \n " ,
2017-01-09 09:54:49 +00:00
receiver , MOO_CLASSOF ( moo , receiver ) , mthname . len , mthname . ptr ) ;
2016-06-20 15:42:51 +00:00
2017-01-09 09:54:49 +00:00
moo - > errnum = MOO_EMSGSND ;
2016-06-20 15:42:51 +00:00
return - 1 ;
}
else
{
2016-08-13 06:46:14 +00:00
/* manipulate the stack as if 'receier doesNotUnderstand: selector'
2016-06-20 15:42:51 +00:00
* has been called . */
2016-08-13 06:46:14 +00:00
/* TODO: if i manipulate the stack this way here, the stack trace for the last call is kind of lost.
2016-06-20 15:42:51 +00:00
* how can i preserve it gracefully ? */
2017-01-09 09:54:49 +00:00
MOO_STACK_POPS ( moo , nargs ) ;
2016-06-20 15:42:51 +00:00
nargs = 1 ;
2017-01-09 09:54:49 +00:00
MOO_STACK_PUSH ( moo , ( moo_oop_t ) selector ) ;
2016-06-20 15:42:51 +00:00
}
}
2017-01-09 09:54:49 +00:00
return start_method ( moo , method , nargs ) ;
2016-06-20 15:42:51 +00:00
}
2017-01-09 09:54:49 +00:00
static int send_private_message ( moo_t * moo , const moo_ooch_t * nameptr , moo_oow_t namelen , int to_super , moo_ooi_t nargs )
2016-06-20 15:42:51 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oocs_t mthname ;
moo_oop_t receiver ;
moo_oop_method_t method ;
2016-06-20 15:42:51 +00:00
2017-01-09 09:54:49 +00:00
receiver = MOO_STACK_GET ( moo , moo - > sp - nargs ) ;
2016-06-20 15:42:51 +00:00
2017-01-09 09:54:49 +00:00
mthname . ptr = ( moo_ooch_t * ) nameptr ;
2016-06-20 15:42:51 +00:00
mthname . len = namelen ;
2017-01-09 09:54:49 +00:00
method = find_method ( moo , receiver , & mthname , to_super ) ;
2016-06-20 15:42:51 +00:00
if ( ! method )
{
2017-01-09 09:54:49 +00:00
MOO_LOG4 ( moo , MOO_LOG_IC | MOO_LOG_FATAL ,
2017-01-06 10:42:59 +00:00
" Fatal error - receiver [%O] of class [%O] does not understand a private message [%.*js] \n " ,
2017-01-09 09:54:49 +00:00
receiver , MOO_CLASSOF ( moo , receiver ) , mthname . len , mthname . ptr ) ;
moo - > errnum = MOO_EMSGSND ;
2016-06-20 15:42:51 +00:00
return - 1 ;
}
2017-01-09 09:54:49 +00:00
return start_method ( moo , method , nargs ) ;
2016-06-20 15:42:51 +00:00
}
2015-10-03 15:29:03 +00:00
/* ------------------------------------------------------------------------- */
2017-01-09 09:54:49 +00:00
int moo_execute ( moo_t * moo )
2015-06-04 18:34:37 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oob_t bcode ;
moo_oow_t b1 , b2 ;
moo_oop_t return_value ;
2016-06-20 15:42:51 +00:00
int unwind_protect ;
2017-01-09 09:54:49 +00:00
moo_oop_context_t unwind_start ;
moo_oop_context_t unwind_stop ;
2015-06-06 07:24:35 +00:00
2017-01-09 09:54:49 +00:00
# if defined(MOO_PROFILE_VM)
moo_uintmax_t inst_counter = 0 ;
2015-10-08 14:26:04 +00:00
# endif
2015-06-24 11:53:19 +00:00
2017-01-09 09:54:49 +00:00
# if defined(MOO_DEBUG_VM_EXEC)
moo_ooi_t fetched_instruction_pointer ;
2016-10-06 14:17:24 +00:00
# endif
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , moo - > active_context ! = MOO_NULL ) ;
2015-06-11 09:11:18 +00:00
2017-01-09 09:54:49 +00:00
vm_startup ( moo ) ;
moo - > proc_switched = 0 ;
2016-02-19 15:52:56 +00:00
2015-06-04 18:34:37 +00:00
while ( 1 )
{
2017-01-09 09:54:49 +00:00
if ( moo - > sem_heap_count > 0 )
2016-03-23 12:58:30 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ntime_t ft , now ;
vm_gettime ( moo , & now ) ;
2016-03-22 14:18:07 +00:00
2016-03-23 12:58:30 +00:00
do
2016-03-22 14:18:07 +00:00
{
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_OOP_IS_SMOOI ( moo - > sem_heap [ 0 ] - > heap_ftime_sec ) ) ;
MOO_ASSERT ( moo , MOO_OOP_IS_SMOOI ( moo - > sem_heap [ 0 ] - > heap_ftime_nsec ) ) ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
MOO_INITNTIME ( & ft ,
MOO_OOP_TO_SMOOI ( moo - > sem_heap [ 0 ] - > heap_ftime_sec ) ,
MOO_OOP_TO_SMOOI ( moo - > sem_heap [ 0 ] - > heap_ftime_nsec )
2016-03-24 14:58:47 +00:00
) ;
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
if ( MOO_CMPNTIME ( & ft , ( moo_ntime_t * ) & now ) < = 0 )
2016-03-22 14:18:07 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_process_t proc ;
2016-03-22 14:18:07 +00:00
2016-03-24 14:58:47 +00:00
/* waited long enough. signal the semaphore */
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
proc = signal_semaphore ( moo , moo - > sem_heap [ 0 ] ) ;
/* [NOTE] no moo_pushtmp() on proc. no GC must occur
2016-03-24 14:58:47 +00:00
* in the following line until it ' s used for
* wake_new_process ( ) below . */
2017-01-09 09:54:49 +00:00
delete_from_sem_heap ( moo , 0 ) ;
2016-03-23 02:34:13 +00:00
2016-03-24 14:58:47 +00:00
/* if no process is waiting on the semaphore,
2017-01-09 09:54:49 +00:00
* signal_semaphore ( ) returns moo - > _nil . */
2016-03-24 14:58:47 +00:00
2017-01-09 09:54:49 +00:00
if ( moo - > processor - > active = = moo - > nil_process & & ( moo_oop_t ) proc ! = moo - > _nil )
2016-03-23 12:58:30 +00:00
{
2016-03-24 14:58:47 +00:00
/* this is the only runnable process.
* switch the process to the running state .
* it uses wake_new_process ( ) instead of
* switch_to_process ( ) as there is no running
* process at this moment */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , proc - > state = = MOO_SMOOI_TO_OOP ( PROC_STATE_RUNNABLE ) ) ;
MOO_ASSERT ( moo , proc = = moo - > processor - > runnable_head ) ;
2016-03-23 02:34:13 +00:00
2017-01-09 09:54:49 +00:00
wake_new_process ( moo , proc ) ;
moo - > proc_switched = 1 ;
2016-03-22 14:18:07 +00:00
}
2016-03-23 12:58:30 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( moo - > processor - > active = = moo - > nil_process )
2016-03-23 12:58:30 +00:00
{
2017-01-09 09:54:49 +00:00
MOO_SUBNTIME ( & ft , & ft , ( moo_ntime_t * ) & now ) ;
vm_sleep ( moo , & ft ) ; /* TODO: change this to i/o multiplexer??? */
vm_gettime ( moo , & now ) ;
2016-03-23 12:58:30 +00:00
}
else
{
break ;
}
}
2017-01-09 09:54:49 +00:00
while ( moo - > sem_heap_count > 0 ) ;
2016-03-23 12:58:30 +00:00
}
2016-05-15 15:51:41 +00:00
2017-01-09 09:54:49 +00:00
if ( moo - > processor - > active = = moo - > nil_process )
2016-03-23 12:58:30 +00:00
{
/* no more waiting semaphore and no more process */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , moo - > processor - > tally = MOO_SMOOI_TO_OOP ( 0 ) ) ;
MOO_LOG0 ( moo , MOO_LOG_IC | MOO_LOG_DEBUG , " No more runnable process \n " ) ;
2016-05-18 11:10:54 +00:00
2016-10-06 14:17:24 +00:00
#if 0
if ( there is semaphore awaited . . . . )
{
/* DO SOMETHING */
}
# endif
2016-05-18 11:10:54 +00:00
2016-02-15 18:07:20 +00:00
break ;
}
2016-03-22 14:18:07 +00:00
2017-01-09 09:54:49 +00:00
while ( moo - > sem_list_count > 0 )
2016-02-29 15:27:10 +00:00
{
2016-03-22 14:18:07 +00:00
/* handle async signals */
2017-01-09 09:54:49 +00:00
- - moo - > sem_list_count ;
signal_semaphore ( moo , moo - > sem_list [ moo - > sem_list_count ] ) ;
2016-02-29 15:27:10 +00:00
}
2016-03-22 14:18:07 +00:00
/*
if ( semaphore heap has pending request )
{
signal them . . .
} */
2016-02-29 15:27:10 +00:00
2016-02-19 15:52:56 +00:00
/* TODO: implement different process switching scheme - time-slice or clock based??? */
2017-01-09 09:54:49 +00:00
# if defined(MOO_EXTERNAL_PROCESS_SWITCH)
if ( ! moo - > proc_switched & & moo - > switch_proc ) { switch_to_next_runnable_process ( moo ) ; }
moo - > switch_proc = 0 ;
2016-05-17 15:12:27 +00:00
# else
2017-01-09 09:54:49 +00:00
if ( ! moo - > proc_switched ) { switch_to_next_runnable_process ( moo ) ; }
2016-05-17 15:12:27 +00:00
# endif
2017-01-09 09:54:49 +00:00
moo - > proc_switched = 0 ;
2015-10-19 06:16:43 +00:00
2017-01-09 09:54:49 +00:00
# if defined(MOO_DEBUG_VM_EXEC)
fetched_instruction_pointer = moo - > ip ;
2016-10-06 14:17:24 +00:00
# endif
2017-01-09 09:54:49 +00:00
FETCH_BYTE_CODE_TO ( moo , bcode ) ;
/*while (bcode == BCODE_NOOP) FETCH_BYTE_CODE_TO (moo, bcode);*/
2015-06-07 14:36:26 +00:00
2017-01-09 09:54:49 +00:00
# if defined(MOO_PROFILE_VM)
2015-10-08 14:26:04 +00:00
inst_counter + + ;
# endif
2015-06-06 07:24:35 +00:00
2015-06-29 13:52:40 +00:00
switch ( bcode )
{
/* ------------------------------------------------- */
case BCODE_PUSH_INSTVAR_X :
2017-01-09 09:54:49 +00:00
FETCH_PARAM_CODE_TO ( moo , b1 ) ;
2015-06-29 13:52:40 +00:00
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 :
2017-01-09 09:54:49 +00:00
LOG_INST_1 ( moo , " push_instvar %zu " , b1 ) ;
MOO_ASSERT ( moo , MOO_OBJ_GET_FLAGS_TYPE ( moo - > active_context - > origin - > receiver_or_source ) = = MOO_OBJ_TYPE_OOP ) ;
MOO_STACK_PUSH ( moo , ( ( moo_oop_oop_t ) moo - > active_context - > origin - > receiver_or_source ) - > slot [ b1 ] ) ;
2015-06-07 14:36:26 +00:00
break ;
2015-06-29 13:52:40 +00:00
/* ------------------------------------------------- */
case BCODE_STORE_INTO_INSTVAR_X :
2017-01-09 09:54:49 +00:00
FETCH_PARAM_CODE_TO ( moo , b1 ) ;
2015-06-29 13:52:40 +00:00
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 :
2017-01-09 09:54:49 +00:00
LOG_INST_1 ( moo , " store_into_instvar %zu " , b1 ) ;
MOO_ASSERT ( moo , MOO_OBJ_GET_FLAGS_TYPE ( moo - > active_context - > receiver_or_source ) = = MOO_OBJ_TYPE_OOP ) ;
( ( moo_oop_oop_t ) moo - > active_context - > origin - > receiver_or_source ) - > slot [ b1 ] = MOO_STACK_GETTOP ( moo ) ;
2015-06-29 13:52:40 +00:00
break ;
/* ------------------------------------------------- */
case BCODE_POP_INTO_INSTVAR_X :
2017-01-09 09:54:49 +00:00
FETCH_PARAM_CODE_TO ( moo , b1 ) ;
2015-06-29 13:52:40 +00:00
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 :
2017-01-09 09:54:49 +00:00
LOG_INST_1 ( moo , " pop_into_instvar %zu " , b1 ) ;
MOO_ASSERT ( moo , MOO_OBJ_GET_FLAGS_TYPE ( moo - > active_context - > receiver_or_source ) = = MOO_OBJ_TYPE_OOP ) ;
( ( moo_oop_oop_t ) moo - > active_context - > origin - > receiver_or_source ) - > slot [ b1 ] = MOO_STACK_GETTOP ( moo ) ;
MOO_STACK_POP ( moo ) ;
2015-06-29 13:52:40 +00:00
break ;
/* ------------------------------------------------- */
case BCODE_PUSH_TEMPVAR_X :
case BCODE_STORE_INTO_TEMPVAR_X :
case BCODE_POP_INTO_TEMPVAR_X :
2017-01-09 09:54:49 +00:00
FETCH_PARAM_CODE_TO ( moo , b1 ) ;
2015-06-29 13:52:40 +00:00
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 :
2015-06-30 14:47:39 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_context_t ctx ;
moo_ooi_t bx ;
2015-06-30 14:47:39 +00:00
2015-06-29 13:52:40 +00:00
b1 = bcode & 0x7 ; /* low 3 bits */
handle_tempvar :
2015-06-30 15:12:37 +00:00
2017-01-09 09:54:49 +00:00
# if defined(MOO_USE_CTXTEMPVAR)
2016-01-29 04:04:39 +00:00
/* 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 */
2017-01-09 09:54:49 +00:00
ctx = moo - > active_context - > origin ;
2015-06-30 15:12:37 +00:00
bx = b1 ;
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_CLASSOF ( moo , ctx ) = = moo - > _method_context ) ;
2015-06-30 15:12:37 +00:00
# else
2016-01-29 04:04:39 +00:00
/* otherwise, the index may point to a temporaries
* declared inside a block */
2017-01-09 09:54:49 +00:00
if ( moo - > active_context - > home ! = moo - > _nil )
2015-06-22 14:21:46 +00:00
{
2015-06-23 14:00:26 +00:00
/* this code assumes that the method context and
* the block context place some key fields in the
2015-06-22 14:21:46 +00:00
* same offset . such fields include ' home ' , ' ntmprs ' */
2017-01-09 09:54:49 +00:00
moo_oop_t home ;
moo_ooi_t home_ntmprs ;
2015-06-22 14:21:46 +00:00
2017-01-09 09:54:49 +00:00
ctx = moo - > active_context ;
2015-06-22 14:21:46 +00:00
home = ctx - > home ;
do
{
2016-02-11 14:26:26 +00:00
/* ntmprs contains the number of defined temporaries
* including those defined in the home context */
2017-01-09 09:54:49 +00:00
home_ntmprs = MOO_OOP_TO_SMOOI ( ( ( moo_oop_context_t ) home ) - > ntmprs ) ;
2015-06-22 14:21:46 +00:00
if ( b1 > = home_ntmprs ) break ;
2017-01-09 09:54:49 +00:00
ctx = ( moo_oop_context_t ) home ;
home = ( ( moo_oop_context_t ) home ) - > home ;
if ( home = = moo - > _nil )
2015-06-22 14:21:46 +00:00
{
home_ntmprs = 0 ;
break ;
}
}
while ( 1 ) ;
2016-02-11 14:26:26 +00:00
/* bx is the actual index within the actual context
* containing the temporary */
2015-06-29 13:52:40 +00:00
bx = b1 - home_ntmprs ;
}
else
{
2017-01-09 09:54:49 +00:00
ctx = moo - > active_context ;
2015-06-29 13:52:40 +00:00
bx = b1 ;
}
2015-06-30 15:12:37 +00:00
# endif
2015-06-22 14:21:46 +00:00
2015-06-29 13:52:40 +00:00
if ( ( bcode > > 4 ) & 1 )
{
2016-02-11 14:26:26 +00:00
/* push - bit 4 on */
2017-01-09 09:54:49 +00:00
LOG_INST_1 ( moo , " push_tempvar %zu " , b1 ) ;
MOO_STACK_PUSH ( moo , ctx - > slot [ bx ] ) ;
2015-06-22 14:21:46 +00:00
}
else
{
2015-06-29 13:52:40 +00:00
/* store or pop - bit 5 off */
2017-01-09 09:54:49 +00:00
ctx - > slot [ bx ] = MOO_STACK_GETTOP ( moo ) ;
2015-06-22 14:21:46 +00:00
2015-06-29 13:52:40 +00:00
if ( ( bcode > > 3 ) & 1 )
{
/* pop - bit 3 on */
2017-01-09 09:54:49 +00:00
LOG_INST_1 ( moo , " pop_into_tempvar %zu " , b1 ) ;
MOO_STACK_POP ( moo ) ;
2015-06-29 13:52:40 +00:00
}
2015-10-08 14:26:04 +00:00
else
{
2017-01-09 09:54:49 +00:00
LOG_INST_1 ( moo , " store_into_tempvar %zu " , b1 ) ;
2015-10-08 14:26:04 +00:00
}
2015-06-22 14:21:46 +00:00
}
2016-06-05 18:01:35 +00:00
2015-06-07 14:36:26 +00:00
break ;
2015-06-30 14:47:39 +00:00
}
2015-06-07 14:36:26 +00:00
2015-06-29 13:52:40 +00:00
/* ------------------------------------------------- */
case BCODE_PUSH_LITERAL_X :
2017-01-09 09:54:49 +00:00
FETCH_PARAM_CODE_TO ( moo , b1 ) ;
2015-06-29 13:52:40 +00:00
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 :
2017-01-09 09:54:49 +00:00
LOG_INST_1 ( moo , " push_literal @%zu " , b1 ) ;
MOO_STACK_PUSH ( moo , moo - > active_method - > slot [ b1 ] ) ;
2015-06-07 14:36:26 +00:00
break ;
2015-06-29 13:52:40 +00:00
/* ------------------------------------------------- */
case BCODE_PUSH_OBJECT_X :
case BCODE_STORE_INTO_OBJECT_X :
case BCODE_POP_INTO_OBJECT_X :
2017-01-09 09:54:49 +00:00
FETCH_PARAM_CODE_TO ( moo , b1 ) ;
2015-06-29 13:52:40 +00:00
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 :
2015-06-30 14:47:39 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_association_t ass ;
2015-06-30 14:47:39 +00:00
2015-06-29 13:52:40 +00:00
b1 = bcode & 0x3 ; /* low 2 bits */
handle_object :
2017-01-09 09:54:49 +00:00
ass = ( moo_oop_association_t ) moo - > active_method - > slot [ b1 ] ;
MOO_ASSERT ( moo , MOO_CLASSOF ( moo , ass ) = = moo - > _association ) ;
2015-06-30 14:47:39 +00:00
2015-06-29 13:52:40 +00:00
if ( ( bcode > > 3 ) & 1 )
2015-06-22 14:21:46 +00:00
{
2015-06-29 13:52:40 +00:00
/* store or pop */
2017-01-09 09:54:49 +00:00
ass - > value = MOO_STACK_GETTOP ( moo ) ;
2015-06-30 14:47:39 +00:00
2015-06-29 13:52:40 +00:00
if ( ( bcode > > 2 ) & 1 )
2015-06-22 14:21:46 +00:00
{
2015-06-29 13:52:40 +00:00
/* pop */
2017-01-09 09:54:49 +00:00
LOG_INST_1 ( moo , " pop_into_object @%zu " , b1 ) ;
MOO_STACK_POP ( moo ) ;
2015-06-22 14:21:46 +00:00
}
2015-10-08 14:26:04 +00:00
else
{
2017-01-09 09:54:49 +00:00
LOG_INST_1 ( moo , " store_into_object @%zu " , b1 ) ;
2015-10-08 14:26:04 +00:00
}
2015-06-22 14:21:46 +00:00
}
else
{
2015-06-29 13:52:40 +00:00
/* push */
2017-01-09 09:54:49 +00:00
LOG_INST_1 ( moo , " push_object @%zu " , b1 ) ;
MOO_STACK_PUSH ( moo , ass - > value ) ;
2015-06-22 14:21:46 +00:00
}
2015-06-07 14:36:26 +00:00
break ;
2015-06-30 14:47:39 +00:00
}
2015-06-07 14:36:26 +00:00
2015-06-29 13:52:40 +00:00
/* -------------------------------------------------------- */
2015-06-16 04:31:28 +00:00
2015-06-29 13:52:40 +00:00
case BCODE_JUMP_FORWARD_X :
2017-01-09 09:54:49 +00:00
FETCH_PARAM_CODE_TO ( moo , b1 ) ;
LOG_INST_1 ( moo , " jump_forward %zu " , b1 ) ;
moo - > ip + = b1 ;
2015-06-16 04:31:28 +00:00
break ;
2015-06-07 14:36:26 +00:00
2015-06-29 13:52:40 +00:00
case BCODE_JUMP_FORWARD_0 :
case BCODE_JUMP_FORWARD_1 :
case BCODE_JUMP_FORWARD_2 :
case BCODE_JUMP_FORWARD_3 :
2017-01-09 09:54:49 +00:00
LOG_INST_1 ( moo , " jump_forward %zu " , ( moo_oow_t ) ( bcode & 0x3 ) ) ;
moo - > ip + = ( bcode & 0x3 ) ; /* low 2 bits */
2015-06-29 13:52:40 +00:00
break ;
2015-06-09 12:14:18 +00:00
2015-06-29 13:52:40 +00:00
case BCODE_JUMP_BACKWARD_X :
2017-01-09 09:54:49 +00:00
FETCH_PARAM_CODE_TO ( moo , b1 ) ;
LOG_INST_1 ( moo , " jump_backward %zu " , b1 ) ;
moo - > ip + = b1 ;
2015-06-29 13:52:40 +00:00
break ;
case BCODE_JUMP_BACKWARD_0 :
case BCODE_JUMP_BACKWARD_1 :
case BCODE_JUMP_BACKWARD_2 :
case BCODE_JUMP_BACKWARD_3 :
2017-01-09 09:54:49 +00:00
LOG_INST_1 ( moo , " jump_backward %zu " , ( moo_oow_t ) ( bcode & 0x3 ) ) ;
moo - > ip - = ( bcode & 0x3 ) ; /* low 2 bits */
2015-06-29 13:52:40 +00:00
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 :
2017-01-09 09:54:49 +00:00
MOO_LOG0 ( moo , MOO_LOG_IC | MOO_LOG_FATAL , " <<<<<<<<<<<<<< JUMP NOT IMPLEMENTED YET >>>>>>>>>>>> \n " ) ;
moo - > errnum = MOO_ENOIMPL ;
2015-06-29 13:52:40 +00:00
return - 1 ;
2015-07-01 07:21:54 +00:00
case BCODE_JUMP2_FORWARD :
2017-01-09 09:54:49 +00:00
FETCH_PARAM_CODE_TO ( moo , b1 ) ;
LOG_INST_1 ( moo , " jump2_forward %zu " , b1 ) ;
moo - > ip + = MAX_CODE_JUMP + b1 ;
2015-07-01 07:21:54 +00:00
break ;
case BCODE_JUMP2_BACKWARD :
2017-01-09 09:54:49 +00:00
FETCH_PARAM_CODE_TO ( moo , b1 ) ;
LOG_INST_1 ( moo , " jump2_backward %zu " , b1 ) ;
moo - > ip - = MAX_CODE_JUMP + b1 ;
2015-06-29 13:52:40 +00:00
break ;
/* -------------------------------------------------------- */
case BCODE_PUSH_CTXTEMPVAR_X :
case BCODE_STORE_INTO_CTXTEMPVAR_X :
case BCODE_POP_INTO_CTXTEMPVAR_X :
2017-01-09 09:54:49 +00:00
FETCH_PARAM_CODE_TO ( moo , b1 ) ;
FETCH_PARAM_CODE_TO ( moo , b2 ) ;
2015-06-29 13:52:40 +00:00
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 :
2015-06-30 14:47:39 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t i ;
moo_oop_context_t ctx ;
2015-06-30 14:47:39 +00:00
2015-06-29 13:52:40 +00:00
b1 = bcode & 0x3 ; /* low 2 bits */
2017-01-09 09:54:49 +00:00
FETCH_BYTE_CODE_TO ( moo , b2 ) ;
2015-06-30 14:47:39 +00:00
2015-06-29 13:52:40 +00:00
handle_ctxtempvar :
2015-06-30 14:47:39 +00:00
2017-01-09 09:54:49 +00:00
ctx = moo - > active_context ;
MOO_ASSERT ( moo , ( moo_oop_t ) ctx ! = moo - > _nil ) ;
2015-06-30 14:47:39 +00:00
for ( i = 0 ; i < b1 ; i + + )
{
2017-01-09 09:54:49 +00:00
ctx = ( moo_oop_context_t ) ctx - > home ;
2015-06-30 14:47:39 +00:00
}
2015-06-29 13:52:40 +00:00
if ( ( bcode > > 3 ) & 1 )
{
/* store or pop */
2017-01-09 09:54:49 +00:00
ctx - > slot [ b2 ] = MOO_STACK_GETTOP ( moo ) ;
2015-06-30 14:47:39 +00:00
2015-06-29 13:52:40 +00:00
if ( ( bcode > > 2 ) & 1 )
{
/* pop */
2017-01-09 09:54:49 +00:00
MOO_STACK_POP ( moo ) ;
LOG_INST_2 ( moo , " pop_into_ctxtempvar %zu %zu " , b1 , b2 ) ;
2015-10-08 14:26:04 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
LOG_INST_2 ( moo , " store_into_ctxtempvar %zu %zu " , b1 , b2 ) ;
2015-06-29 13:52:40 +00:00
}
}
else
{
/* push */
2017-01-09 09:54:49 +00:00
MOO_STACK_PUSH ( moo , ctx - > slot [ b2 ] ) ;
LOG_INST_2 ( moo , " push_ctxtempvar %zu %zu " , b1 , b2 ) ;
2015-06-29 13:52:40 +00:00
}
2015-10-08 14:26:04 +00:00
2015-06-29 13:52:40 +00:00
break ;
2015-06-30 14:47:39 +00:00
}
2015-06-29 13:52:40 +00:00
/* -------------------------------------------------------- */
case BCODE_PUSH_OBJVAR_X :
case BCODE_STORE_INTO_OBJVAR_X :
case BCODE_POP_INTO_OBJVAR_X :
2017-01-09 09:54:49 +00:00
FETCH_PARAM_CODE_TO ( moo , b1 ) ;
FETCH_PARAM_CODE_TO ( moo , b2 ) ;
2015-06-29 13:52:40 +00:00
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 :
2015-06-30 14:47:39 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_oop_t t ;
2015-06-30 14:47:39 +00:00
2015-06-23 14:00:26 +00:00
/* b1 -> variable index to the object indicated by b2.
* b2 - > object index stored in the literal frame . */
2015-06-29 13:52:40 +00:00
b1 = bcode & 0x3 ; /* low 2 bits */
2017-01-09 09:54:49 +00:00
FETCH_BYTE_CODE_TO ( moo , b2 ) ;
2015-06-12 13:52:30 +00:00
2015-06-29 13:52:40 +00:00
handle_objvar :
2017-01-09 09:54:49 +00:00
t = ( moo_oop_oop_t ) moo - > active_method - > slot [ b2 ] ;
MOO_ASSERT ( moo , MOO_OBJ_GET_FLAGS_TYPE ( t ) = = MOO_OBJ_TYPE_OOP ) ;
MOO_ASSERT ( moo , b1 < MOO_OBJ_GET_SIZE ( t ) ) ;
2015-06-23 14:00:26 +00:00
2015-06-29 13:52:40 +00:00
if ( ( bcode > > 3 ) & 1 )
{
/* store or pop */
2015-06-12 13:52:30 +00:00
2017-01-09 09:54:49 +00:00
t - > slot [ b1 ] = MOO_STACK_GETTOP ( moo ) ;
2015-06-23 14:00:26 +00:00
2015-06-29 13:52:40 +00:00
if ( ( bcode > > 2 ) & 1 )
{
/* pop */
2017-01-09 09:54:49 +00:00
MOO_STACK_POP ( moo ) ;
LOG_INST_2 ( moo , " pop_into_objvar %zu %zu " , b1 , b2 ) ;
2015-10-08 14:26:04 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
LOG_INST_2 ( moo , " store_into_objvar %zu %zu " , b1 , b2 ) ;
2015-06-29 13:52:40 +00:00
}
}
else
{
/* push */
2017-01-09 09:54:49 +00:00
LOG_INST_2 ( moo , " push_objvar %zu %zu " , b1 , b2 ) ;
MOO_STACK_PUSH ( moo , t - > slot [ b1 ] ) ;
2015-06-29 13:52:40 +00:00
}
2015-06-12 13:52:30 +00:00
break ;
2015-06-30 14:47:39 +00:00
}
2015-06-12 13:52:30 +00:00
2015-06-29 13:52:40 +00:00
/* -------------------------------------------------------- */
case BCODE_SEND_MESSAGE_X :
case BCODE_SEND_MESSAGE_TO_SUPER_X :
2015-12-27 10:19:36 +00:00
/* b1 -> number of arguments
* b2 - > selector index stored in the literal frame */
2017-01-09 09:54:49 +00:00
FETCH_PARAM_CODE_TO ( moo , b1 ) ;
FETCH_PARAM_CODE_TO ( moo , b2 ) ;
2015-06-29 13:52:40 +00:00
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 :
2015-06-08 13:24:02 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_char_t selector ;
2015-06-29 13:52:40 +00:00
b1 = bcode & 0x3 ; /* low 2 bits */
2017-01-09 09:54:49 +00:00
FETCH_BYTE_CODE_TO ( moo , b2 ) ;
2015-06-08 13:24:02 +00:00
2015-12-27 10:19:36 +00:00
handle_send_message :
2015-06-08 13:24:02 +00:00
/* get the selector from the literal frame */
2017-01-09 09:54:49 +00:00
selector = ( moo_oop_char_t ) moo - > active_method - > slot [ b2 ] ;
2015-06-08 13:24:02 +00:00
2017-01-09 09:54:49 +00:00
LOG_INST_3 ( moo , " send_message%hs %zu @%zu " , ( ( ( bcode > > 2 ) & 1 ) ? " _to_super " : " " ) , b1 , b2 ) ;
2016-06-05 18:01:35 +00:00
2017-01-09 09:54:49 +00:00
if ( send_message ( moo , selector , ( ( bcode > > 2 ) & 1 ) , b1 ) < = - 1 ) goto oops ;
2015-06-09 12:14:18 +00:00
break ; /* CMD_SEND_MESSAGE */
}
2015-06-29 13:52:40 +00:00
/* -------------------------------------------------------- */
2015-06-07 14:36:26 +00:00
2015-06-29 13:52:40 +00:00
case BCODE_PUSH_RECEIVER :
2017-01-09 09:54:49 +00:00
LOG_INST_0 ( moo , " push_receiver " ) ;
MOO_STACK_PUSH ( moo , moo - > active_context - > origin - > receiver_or_source ) ;
2015-06-29 13:52:40 +00:00
break ;
2015-06-07 14:36:26 +00:00
2015-06-29 13:52:40 +00:00
case BCODE_PUSH_NIL :
2017-01-09 09:54:49 +00:00
LOG_INST_0 ( moo , " push_nil " ) ;
MOO_STACK_PUSH ( moo , moo - > _nil ) ;
2015-06-29 13:52:40 +00:00
break ;
2015-06-07 14:36:26 +00:00
2015-06-29 13:52:40 +00:00
case BCODE_PUSH_TRUE :
2017-01-09 09:54:49 +00:00
LOG_INST_0 ( moo , " push_true " ) ;
MOO_STACK_PUSH ( moo , moo - > _true ) ;
2015-06-29 13:52:40 +00:00
break ;
2015-06-07 14:36:26 +00:00
2015-06-29 13:52:40 +00:00
case BCODE_PUSH_FALSE :
2017-01-09 09:54:49 +00:00
LOG_INST_0 ( moo , " push_false " ) ;
MOO_STACK_PUSH ( moo , moo - > _false ) ;
2015-06-29 13:52:40 +00:00
break ;
2015-06-09 12:14:18 +00:00
2015-06-29 13:52:40 +00:00
case BCODE_PUSH_CONTEXT :
2017-01-09 09:54:49 +00:00
LOG_INST_0 ( moo , " push_context " ) ;
MOO_STACK_PUSH ( moo , ( moo_oop_t ) moo - > active_context ) ;
2015-06-29 13:52:40 +00:00
break ;
2015-06-16 04:31:28 +00:00
2016-07-05 15:22:29 +00:00
case BCODE_PUSH_PROCESS :
2017-01-09 09:54:49 +00:00
LOG_INST_0 ( moo , " push_process " ) ;
MOO_STACK_PUSH ( moo , ( moo_oop_t ) moo - > processor - > active ) ;
2016-07-05 15:22:29 +00:00
break ;
2015-06-29 13:52:40 +00:00
case BCODE_PUSH_NEGONE :
2017-01-09 09:54:49 +00:00
LOG_INST_0 ( moo , " push_negone " ) ;
MOO_STACK_PUSH ( moo , MOO_SMOOI_TO_OOP ( - 1 ) ) ;
2015-06-29 13:52:40 +00:00
break ;
2015-06-16 04:31:28 +00:00
2015-06-29 13:52:40 +00:00
case BCODE_PUSH_ZERO :
2017-01-09 09:54:49 +00:00
LOG_INST_0 ( moo , " push_zero " ) ;
MOO_STACK_PUSH ( moo , MOO_SMOOI_TO_OOP ( 0 ) ) ;
2015-06-29 13:52:40 +00:00
break ;
2015-06-16 04:31:28 +00:00
2015-06-29 13:52:40 +00:00
case BCODE_PUSH_ONE :
2017-01-09 09:54:49 +00:00
LOG_INST_0 ( moo , " push_one " ) ;
MOO_STACK_PUSH ( moo , MOO_SMOOI_TO_OOP ( 1 ) ) ;
2015-06-29 13:52:40 +00:00
break ;
2015-06-09 12:14:18 +00:00
2015-06-29 13:52:40 +00:00
case BCODE_PUSH_TWO :
2017-01-09 09:54:49 +00:00
LOG_INST_0 ( moo , " push_two " ) ;
MOO_STACK_PUSH ( moo , MOO_SMOOI_TO_OOP ( 2 ) ) ;
2015-06-29 13:52:40 +00:00
break ;
2015-06-07 14:36:26 +00:00
2015-07-02 15:45:48 +00:00
case BCODE_PUSH_INTLIT :
2017-01-09 09:54:49 +00:00
FETCH_PARAM_CODE_TO ( moo , b1 ) ;
LOG_INST_1 ( moo , " push_intlit %zu " , b1 ) ;
MOO_STACK_PUSH ( moo , MOO_SMOOI_TO_OOP ( b1 ) ) ;
2015-07-02 15:45:48 +00:00
break ;
case BCODE_PUSH_NEGINTLIT :
2016-10-04 17:58:28 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t num ;
FETCH_PARAM_CODE_TO ( moo , b1 ) ;
2016-10-04 17:58:28 +00:00
num = b1 ;
2017-01-09 09:54:49 +00:00
LOG_INST_1 ( moo , " push_negintlit %zu " , b1 ) ;
MOO_STACK_PUSH ( moo , MOO_SMOOI_TO_OOP ( - num ) ) ;
2015-07-02 15:45:48 +00:00
break ;
2016-10-04 17:58:28 +00:00
}
2015-07-02 15:45:48 +00:00
2016-09-14 04:56:00 +00:00
case BCODE_PUSH_CHARLIT :
2017-01-09 09:54:49 +00:00
FETCH_PARAM_CODE_TO ( moo , b1 ) ;
LOG_INST_1 ( moo , " push_charlit %zu " , b1 ) ;
MOO_STACK_PUSH ( moo , MOO_CHAR_TO_OOP ( b1 ) ) ;
2016-09-14 04:56:00 +00:00
break ;
2015-06-29 13:52:40 +00:00
/* -------------------------------------------------------- */
2015-06-09 12:14:18 +00:00
2015-06-29 13:52:40 +00:00
case BCODE_DUP_STACKTOP :
{
2017-01-09 09:54:49 +00:00
moo_oop_t t ;
LOG_INST_0 ( moo , " dup_stacktop " ) ;
MOO_ASSERT ( moo , ! MOO_STACK_ISEMPTY ( moo ) ) ;
t = MOO_STACK_GETTOP ( moo ) ;
MOO_STACK_PUSH ( moo , t ) ;
2015-06-29 13:52:40 +00:00
break ;
}
2015-06-22 14:21:46 +00:00
2015-06-29 13:52:40 +00:00
case BCODE_POP_STACKTOP :
2017-01-09 09:54:49 +00:00
LOG_INST_0 ( moo , " pop_stacktop " ) ;
MOO_ASSERT ( moo , ! MOO_STACK_ISEMPTY ( moo ) ) ;
MOO_STACK_POP ( moo ) ;
2015-06-29 13:52:40 +00:00
break ;
2015-06-08 13:24:02 +00:00
2015-06-29 13:52:40 +00:00
case BCODE_RETURN_STACKTOP :
2017-01-09 09:54:49 +00:00
LOG_INST_0 ( moo , " return_stacktop " ) ;
return_value = MOO_STACK_GETTOP ( moo ) ;
MOO_STACK_POP ( moo ) ;
2015-06-29 13:52:40 +00:00
goto handle_return ;
2015-06-08 13:24:02 +00:00
2015-06-29 13:52:40 +00:00
case BCODE_RETURN_RECEIVER :
2017-01-09 09:54:49 +00:00
LOG_INST_0 ( moo , " return_receiver " ) ;
return_value = moo - > active_context - > origin - > receiver_or_source ;
2015-10-08 14:26:04 +00:00
2015-06-29 13:52:40 +00:00
handle_return :
2016-02-15 18:07:20 +00:00
#if 0
2015-06-29 13:52:40 +00:00
/* 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
*
*/
2017-01-09 09:54:49 +00:00
moo - > ip - - ;
2016-02-15 18:07:20 +00:00
# else
2017-01-09 09:54:49 +00:00
if ( moo - > active_context - > origin = = moo - > processor - > active - > initial_context - > origin )
2015-10-19 06:16:43 +00:00
{
2016-02-15 18:07:20 +00:00
/* 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.
* }
*/
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_CLASSOF ( moo , moo - > active_context ) = = moo - > _block_context ) ;
MOO_ASSERT ( moo , MOO_CLASSOF ( moo , moo - > processor - > active - > initial_context ) = = moo - > _block_context ) ;
2016-02-15 18:07:20 +00:00
2016-06-20 15:42:51 +00:00
/* decrement the instruction pointer back to the return instruction.
2016-02-15 18:07:20 +00:00
* even if the context is reentered , it will just return .
2017-01-09 09:54:49 +00:00
* moo - > ip - - ; */
2016-06-20 15:42:51 +00:00
2017-01-09 09:54:49 +00:00
terminate_process ( moo , moo - > processor - > active ) ;
2015-10-19 06:16:43 +00:00
}
2016-02-15 18:07:20 +00:00
else
2015-10-19 06:16:43 +00:00
{
2016-06-20 15:42:51 +00:00
unwind_protect = 0 ;
2016-02-15 18:07:20 +00:00
/* set the instruction pointer to an invalid value.
* this is stored into the current method context
* before context switching and marks a dead context */
2017-01-09 09:54:49 +00:00
if ( moo - > active_context - > origin = = moo - > active_context )
2016-02-15 18:07:20 +00:00
{
/* returning from a method */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_CLASSOF ( moo , moo - > active_context ) = = moo - > _method_context ) ;
moo - > ip = - 1 ;
2016-02-15 18:07:20 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
moo_oop_context_t ctx ;
2016-06-20 15:42:51 +00:00
2016-02-15 18:07:20 +00:00
/* method return from within a block(including a non-local return) */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_CLASSOF ( moo , moo - > active_context ) = = moo - > _block_context ) ;
2016-06-20 15:42:51 +00:00
2017-01-09 09:54:49 +00:00
ctx = moo - > active_context ;
while ( ( moo_oop_t ) ctx ! = moo - > _nil )
2016-06-20 15:42:51 +00:00
{
2017-01-09 09:54:49 +00:00
if ( MOO_CLASSOF ( moo , ctx ) = = moo - > _method_context )
2016-06-22 03:23:14 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t preamble ;
preamble = MOO_OOP_TO_SMOOI ( ( ( moo_oop_method_t ) ctx - > method_or_nargs ) - > preamble ) ;
if ( MOO_METHOD_GET_PREAMBLE_CODE ( preamble ) = = MOO_METHOD_PREAMBLE_ENSURE )
2016-06-22 03:23:14 +00:00
{
if ( ! unwind_protect )
{
unwind_protect = 1 ;
unwind_start = ctx ;
}
unwind_stop = ctx ;
}
}
2017-01-09 09:54:49 +00:00
if ( ctx = = moo - > active_context - > origin ) goto non_local_return_ok ;
2016-06-20 15:42:51 +00:00
ctx = ctx - > sender ;
}
/* cannot return from a method that has returned already */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_CLASSOF ( moo , moo - > active_context - > origin ) = = moo - > _method_context ) ;
MOO_ASSERT ( moo , moo - > active_context - > origin - > ip = = MOO_SMOOI_TO_OOP ( - 1 ) ) ;
2016-06-22 03:23:14 +00:00
2017-01-09 09:54:49 +00:00
MOO_LOG0 ( moo , MOO_LOG_IC | MOO_LOG_ERROR , " Error - cannot return from dead context \n " ) ;
moo - > errnum = MOO_EINTERN ; /* TODO: can i make this error catchable at the moo level? */
2016-06-20 15:42:51 +00:00
return - 1 ;
non_local_return_ok :
2017-01-09 09:54:49 +00:00
/*MOO_DEBUG2 (moo, "NON_LOCAL RETURN OK TO... %p %p\n", moo->active_context->origin, moo->active_context->origin->sender);*/
moo - > active_context - > origin - > ip = MOO_SMOOI_TO_OOP ( - 1 ) ;
2016-02-15 18:07:20 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_CLASSOF ( moo , moo - > active_context - > origin ) = = moo - > _method_context ) ;
2016-02-16 17:00:10 +00:00
/* restore the stack pointer */
2017-01-09 09:54:49 +00:00
moo - > sp = MOO_OOP_TO_SMOOI ( moo - > active_context - > origin - > sp ) ;
SWITCH_ACTIVE_CONTEXT ( moo , moo - > active_context - > origin - > sender ) ;
2015-06-08 13:24:02 +00:00
2016-06-20 15:42:51 +00:00
if ( unwind_protect )
{
2017-01-09 09:54:49 +00:00
static moo_ooch_t fbm [ ] = {
2016-06-20 15:42:51 +00:00
' u ' , ' n ' , ' w ' , ' i ' , ' n ' , ' d ' , ' T ' , ' o ' , ' : ' ,
' r ' , ' e ' , ' t ' , ' u ' , ' r ' , ' n ' , ' : '
} ;
2017-01-09 09:54:49 +00:00
MOO_STACK_PUSH ( moo , ( moo_oop_t ) unwind_start ) ;
MOO_STACK_PUSH ( moo , ( moo_oop_t ) unwind_stop ) ;
MOO_STACK_PUSH ( moo , ( moo_oop_t ) return_value ) ;
2015-06-20 03:07:11 +00:00
2017-01-09 09:54:49 +00:00
if ( send_private_message ( moo , fbm , 16 , 0 , 2 ) < = - 1 ) return - 1 ;
2016-06-20 15:42:51 +00:00
}
else
2015-10-19 06:16:43 +00:00
{
2016-06-20 15:42:51 +00:00
/* push the return value to the stack of the new active context */
2017-01-09 09:54:49 +00:00
MOO_STACK_PUSH ( moo , return_value ) ;
2016-06-20 15:42:51 +00:00
2017-01-09 09:54:49 +00:00
if ( moo - > active_context = = moo - > initial_context )
2016-06-20 15:42:51 +00:00
{
/* the new active context is the fake initial context.
* this context can ' t get executed further . */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , ( moo_oop_t ) moo - > active_context - > sender = = moo - > _nil ) ;
MOO_ASSERT ( moo , MOO_CLASSOF ( moo , moo - > active_context ) = = moo - > _method_context ) ;
MOO_ASSERT ( moo , moo - > active_context - > receiver_or_source = = moo - > _nil ) ;
MOO_ASSERT ( moo , moo - > active_context = = moo - > processor - > active - > initial_context ) ;
MOO_ASSERT ( moo , moo - > active_context - > origin = = moo - > processor - > active - > initial_context - > origin ) ;
MOO_ASSERT ( moo , moo - > active_context - > origin = = moo - > active_context ) ;
2016-06-20 15:42:51 +00:00
/* NOTE: this condition is true for the processified block context also.
2017-01-09 09:54:49 +00:00
* moo - > active_context - > origin = = moo - > processor - > active - > initial_context - > origin
2016-06-20 15:42:51 +00:00
* however , the check here is done after context switching and the
* processified block check has been done against the context before switching */
/* the stack contains the final return value so the stack pointer must be 0. */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , moo - > sp = = 0 ) ;
2016-06-20 15:42:51 +00:00
2017-01-09 09:54:49 +00:00
if ( moo - > option . trait & MOO_AWAIT_PROCS )
terminate_process ( moo , moo - > processor - > active ) ;
2016-06-20 15:42:51 +00:00
else
goto done ;
/* TODO: store the return value to the VM register.
2017-01-09 09:54:49 +00:00
* the caller to moo_execute ( ) can fetch it to return it to the system */
2016-06-20 15:42:51 +00:00
}
2015-10-19 06:16:43 +00:00
}
2015-06-29 13:52:40 +00:00
}
2016-05-15 15:51:41 +00:00
2016-02-15 18:07:20 +00:00
# endif
2015-06-20 03:07:11 +00:00
2015-06-29 13:52:40 +00:00
break ;
2015-06-25 13:37:50 +00:00
2015-06-29 13:52:40 +00:00
case BCODE_RETURN_FROM_BLOCK :
2017-01-09 09:54:49 +00:00
LOG_INST_0 ( moo , " return_from_block " ) ;
2015-10-08 14:26:04 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_CLASSOF ( moo , moo - > active_context ) = = moo - > _block_context ) ;
2015-06-25 13:37:50 +00:00
2017-01-09 09:54:49 +00:00
if ( moo - > active_context = = moo - > processor - > active - > initial_context )
2015-10-19 06:16:43 +00:00
{
2016-06-05 18:01:35 +00:00
/* the active context to return from is an initial context of
* the active process . this process must have been created
* over a block using the newProcess method . let ' s terminate
* the process . */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , ( moo_oop_t ) moo - > active_context - > sender = = moo - > _nil ) ;
terminate_process ( moo , moo - > processor - > active ) ;
2015-10-19 06:16:43 +00:00
}
else
{
2016-06-05 18:01:35 +00:00
/* it is a normal block return as the active block context
* is not the initial context of a process */
2016-02-12 16:23:26 +00:00
/* the process stack is shared. the return value
* doesn ' t need to get moved . */
2017-01-09 09:54:49 +00:00
SWITCH_ACTIVE_CONTEXT ( moo , ( moo_oop_context_t ) moo - > active_context - > sender ) ;
2015-10-19 06:16:43 +00:00
}
2015-06-29 13:52:40 +00:00
break ;
2015-06-17 13:46:16 +00:00
2015-07-03 13:06:01 +00:00
case BCODE_MAKE_BLOCK :
{
2017-01-09 09:54:49 +00:00
moo_oop_context_t blkctx ;
2015-07-03 13:06:01 +00:00
/* b1 - number of block arguments
* b2 - number of block temporaries */
2017-01-09 09:54:49 +00:00
FETCH_PARAM_CODE_TO ( moo , b1 ) ;
FETCH_PARAM_CODE_TO ( moo , b2 ) ;
2015-07-03 13:06:01 +00:00
2017-01-09 09:54:49 +00:00
LOG_INST_2 ( moo , " make_block %zu %zu " , b1 , b2 ) ;
2015-07-03 13:06:01 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , b1 > = 0 ) ;
MOO_ASSERT ( moo , b2 > = b1 ) ;
2015-07-03 13:06:01 +00:00
2016-02-11 14:26:26 +00:00
/* the block context object created here is used as a base
2016-11-29 05:25:08 +00:00
* object for block context activation . pf_block_value ( )
2016-02-11 14:26:26 +00:00
* clones a block context and activates the cloned context .
* this base block context is created with no stack for
* this reason */
2017-01-09 09:54:49 +00:00
blkctx = ( moo_oop_context_t ) moo_instantiate ( moo , moo - > _block_context , MOO_NULL , 0 ) ;
2015-07-03 13:06:01 +00:00
if ( ! blkctx ) return - 1 ;
/* the long forward jump instruction has the format of
* 11000100 KKKKKKKK or 11000100 KKKKKKKK KKKKKKKK
2017-01-09 09:54:49 +00:00
* depending on MOO_BCODE_LONG_PARAM_SIZE . change ' ip ' to point to
2015-07-03 13:06:01 +00:00
* the instruction after the jump . */
2017-01-09 09:54:49 +00:00
blkctx - > ip = MOO_SMOOI_TO_OOP ( moo - > ip + MOO_BCODE_LONG_PARAM_SIZE + 1 ) ;
2016-02-11 14:26:26 +00:00
/* stack pointer below the bottom. this base block context
* has an empty stack anyway . */
2017-01-09 09:54:49 +00:00
blkctx - > sp = MOO_SMOOI_TO_OOP ( - 1 ) ;
2015-07-03 13:06:01 +00:00
/* the number of arguments for a block context is local to the block */
2017-01-09 09:54:49 +00:00
blkctx - > method_or_nargs = MOO_SMOOI_TO_OOP ( b1 ) ;
2015-07-03 13:06:01 +00:00
/* the number of temporaries here is an accumulated count including
* the number of temporaries of a home context */
2017-01-09 09:54:49 +00:00
blkctx - > ntmprs = MOO_SMOOI_TO_OOP ( b2 ) ;
2015-07-03 13:06:01 +00:00
2016-02-11 14:26:26 +00:00
/* set the home context where it's defined */
2017-01-09 09:54:49 +00:00
blkctx - > home = ( moo_oop_t ) moo - > active_context ;
2016-02-11 14:26:26 +00:00
/* no source for a base block context. */
2017-01-09 09:54:49 +00:00
blkctx - > receiver_or_source = moo - > _nil ;
2015-07-03 13:06:01 +00:00
2017-01-09 09:54:49 +00:00
blkctx - > origin = moo - > active_context - > origin ;
2016-02-11 14:26:26 +00:00
/* push the new block context to the stack of the active context */
2017-01-09 09:54:49 +00:00
MOO_STACK_PUSH ( moo , ( moo_oop_t ) blkctx ) ;
2015-07-03 13:06:01 +00:00
break ;
}
2015-06-29 13:52:40 +00:00
case BCODE_SEND_BLOCK_COPY :
{
2017-01-09 09:54:49 +00:00
moo_ooi_t nargs , ntmprs ;
moo_oop_context_t rctx ;
moo_oop_context_t blkctx ;
2015-10-08 14:26:04 +00:00
2017-01-09 09:54:49 +00:00
LOG_INST_0 ( moo , " send_block_copy " ) ;
2015-10-08 14:26:04 +00:00
2015-06-29 13:52:40 +00:00
/* it emulates thisContext blockCopy: nargs ofTmprCount: ntmprs */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , moo - > sp > = 2 ) ;
2015-06-29 13:52:40 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_CLASSOF ( moo , MOO_STACK_GETTOP ( moo ) ) = = moo - > _small_integer ) ;
ntmprs = MOO_OOP_TO_SMOOI ( MOO_STACK_GETTOP ( moo ) ) ;
MOO_STACK_POP ( moo ) ;
2015-06-29 13:52:40 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_CLASSOF ( moo , MOO_STACK_GETTOP ( moo ) ) = = moo - > _small_integer ) ;
nargs = MOO_OOP_TO_SMOOI ( MOO_STACK_GETTOP ( moo ) ) ;
MOO_STACK_POP ( moo ) ;
2015-06-29 13:52:40 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , nargs > = 0 ) ;
MOO_ASSERT ( moo , ntmprs > = nargs ) ;
2015-06-29 13:52:40 +00:00
/* the block context object created here is used
* as a base object for block context activation .
2016-11-29 05:25:08 +00:00
* pf_block_value ( ) clones a block
2015-06-29 13:52:40 +00:00
* context and activates the cloned context .
* this base block context is created with no
* stack for this reason . */
2017-01-09 09:54:49 +00:00
blkctx = ( moo_oop_context_t ) moo_instantiate ( moo , moo - > _block_context , MOO_NULL , 0 ) ;
2015-06-29 13:52:40 +00:00
if ( ! blkctx ) return - 1 ;
/* get the receiver to the block copy message after block context instantiation
* not to get affected by potential GC */
2017-01-09 09:54:49 +00:00
rctx = ( moo_oop_context_t ) MOO_STACK_GETTOP ( moo ) ;
MOO_ASSERT ( moo , rctx = = moo - > active_context ) ;
2015-06-29 13:52:40 +00:00
/* [NOTE]
2016-01-29 04:04:39 +00:00
* blkctx - > sender is left to nil . it is set to the
2015-06-29 13:52:40 +00:00
* active context before it gets activated . see
2016-11-29 05:25:08 +00:00
* pf_block_value ( ) .
2015-06-29 13:52:40 +00:00
*
* 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
2016-01-29 04:04:39 +00:00
* blockCopy : withNtmprs : . BCODE_MAKE_BLOCK has been
* added to replace BCODE_SEND_BLOCK_COPY and pusing
* arguments to the stack .
2015-06-29 13:52:40 +00:00
*
* blkctx - > origin is set here by copying the origin
* of the active context .
*/
2015-06-17 13:46:16 +00:00
2015-06-29 13:52:40 +00:00
/* the extended jump instruction has the format of
* 0000 XXXX KKKKKKKK or 0000 XXXX KKKKKKKK KKKKKKKK
2017-01-09 09:54:49 +00:00
* depending on MOO_BCODE_LONG_PARAM_SIZE . change ' ip ' to point to
2015-06-29 13:52:40 +00:00
* the instruction after the jump . */
2017-01-09 09:54:49 +00:00
blkctx - > ip = MOO_SMOOI_TO_OOP ( moo - > ip + MOO_BCODE_LONG_PARAM_SIZE + 1 ) ;
blkctx - > sp = MOO_SMOOI_TO_OOP ( - 1 ) ;
2015-06-29 13:52:40 +00:00
/* the number of arguments for a block context is local to the block */
2017-01-09 09:54:49 +00:00
blkctx - > method_or_nargs = MOO_SMOOI_TO_OOP ( nargs ) ;
2015-06-29 13:52:40 +00:00
/* the number of temporaries here is an accumulated count including
* the number of temporaries of a home context */
2017-01-09 09:54:49 +00:00
blkctx - > ntmprs = MOO_SMOOI_TO_OOP ( ntmprs ) ;
2015-06-29 13:52:40 +00:00
2017-01-09 09:54:49 +00:00
blkctx - > home = ( moo_oop_t ) rctx ;
blkctx - > receiver_or_source = moo - > _nil ;
2015-06-07 14:36:26 +00:00
2015-06-29 13:52:40 +00:00
#if 0
2017-01-09 09:54:49 +00:00
if ( rctx - > home = = moo - > _nil )
2015-06-29 13:52:40 +00:00
{
/* the context that receives the blockCopy message is a method context */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_CLASSOF ( moo , rctx ) = = moo - > _method_context ) ;
MOO_ASSERT ( moo , rctx = = ( moo_oop_t ) moo - > active_context ) ;
blkctx - > origin = ( moo_oop_context_t ) rctx ;
2015-06-29 13:52:40 +00:00
}
else
{
/* a block context is active */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_CLASSOF ( moo , rctx ) = = moo - > _block_context ) ;
blkctx - > origin = ( ( moo_oop_block_context_t ) rctx ) - > origin ;
2015-06-29 13:52:40 +00:00
}
# else
2015-06-08 13:24:02 +00:00
2015-06-29 13:52:40 +00:00
/* [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
2015-06-28 14:20:37 +00:00
2017-01-09 09:54:49 +00:00
MOO_STACK_SETTOP ( moo , ( moo_oop_t ) blkctx ) ;
2015-06-29 13:52:40 +00:00
break ;
}
2015-06-28 14:20:37 +00:00
2015-06-29 13:52:40 +00:00
case BCODE_NOOP :
/* do nothing */
2017-01-09 09:54:49 +00:00
LOG_INST_0 ( moo , " noop " ) ;
2015-06-29 13:52:40 +00:00
break ;
2015-06-25 13:37:50 +00:00
2015-06-08 13:24:02 +00:00
2015-06-29 13:52:40 +00:00
default :
2017-01-09 09:54:49 +00:00
MOO_LOG1 ( moo , MOO_LOG_IC | MOO_LOG_FATAL , " Fatal error - unknown byte code 0x%zx \n " , bcode ) ;
moo - > errnum = MOO_EINTERN ;
2016-10-04 17:58:28 +00:00
goto oops ;
2015-06-07 14:36:26 +00:00
}
2015-06-04 18:34:37 +00:00
}
2015-06-07 14:36:26 +00:00
done :
2015-10-08 14:26:04 +00:00
2017-01-09 09:54:49 +00:00
vm_cleanup ( moo ) ;
# if defined(MOO_PROFILE_VM)
MOO_LOG1 ( moo , MOO_LOG_IC | MOO_LOG_INFO , " TOTAL_INST_COUTNER = %zu \n " , inst_counter ) ;
2015-10-08 14:26:04 +00:00
# endif
2015-06-07 14:36:26 +00:00
return 0 ;
2015-06-11 09:11:18 +00:00
oops :
2015-06-21 14:45:45 +00:00
/* TODO: anything to do here? */
2015-06-11 09:11:18 +00:00
return - 1 ;
2015-06-04 18:34:37 +00:00
}
2017-01-09 09:54:49 +00:00
int moo_invoke ( moo_t * moo , const moo_oocs_t * objname , const moo_oocs_t * mthname )
2015-06-04 18:34:37 +00:00
{
2016-05-15 15:51:41 +00:00
int n ;
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , moo - > initial_context = = MOO_NULL ) ;
MOO_ASSERT ( moo , moo - > active_context = = MOO_NULL ) ;
MOO_ASSERT ( moo , moo - > active_method = = MOO_NULL ) ;
2016-05-15 15:51:41 +00:00
2017-01-09 09:54:49 +00:00
if ( start_initial_process_and_context ( moo , objname , mthname ) < = - 1 ) return - 1 ;
moo - > initial_context = moo - > processor - > active - > initial_context ;
2016-05-15 15:51:41 +00:00
2017-01-09 09:54:49 +00:00
n = moo_execute ( moo ) ;
2016-05-15 15:51:41 +00:00
/* TODO: reset processor fields. set processor->tally to zero. processor->active to nil_process... */
2017-01-09 09:54:49 +00:00
moo - > initial_context = MOO_NULL ;
moo - > active_context = MOO_NULL ;
moo - > active_method = MOO_NULL ;
2016-05-15 15:51:41 +00:00
return n ;
2015-06-04 18:34:37 +00:00
}
2015-10-08 14:26:04 +00:00