added respondsTo: and perform:with:

fixed a bug in Dictionary>>__remove_at:
added gc callback to external modules
This commit is contained in:
hyunghwan.chung
2017-03-19 14:18:37 +00:00
parent 6a2add620b
commit 46ba3bb3f5
12 changed files with 550 additions and 136 deletions

View File

@ -108,6 +108,7 @@
#endif
static void signal_io_semaphore (moo_t* moo, int mask, void* ctx);
static int send_message (moo_t* moo, moo_oop_char_t selector, int to_super, moo_ooi_t nargs);
/* ------------------------------------------------------------------------- */
static MOO_INLINE int vm_startup (moo_t* moo)
@ -1521,6 +1522,7 @@ static moo_pfrc_t pf_basic_at (moo_t* moo, moo_ooi_t nargs)
if (!MOO_OOP_IS_POINTER(rcv))
{
/* the receiver is a special numeric object, not a normal pointer */
moo->errnum = MOO_EINVAL;
return MOO_PF_FAILURE;
}
@ -1528,11 +1530,13 @@ static moo_pfrc_t pf_basic_at (moo_t* moo, moo_ooi_t nargs)
if (moo_inttooow (moo, pos, &idx) <= 0)
{
/* negative integer or not integer */
moo->errnum = MOO_EINVAL;
return MOO_PF_FAILURE;
}
if (idx >= MOO_OBJ_GET_SIZE(rcv))
{
/* index out of range */
moo->errnum = MOO_ERANGE;
return MOO_PF_FAILURE;
}
@ -1580,6 +1584,7 @@ static moo_pfrc_t pf_basic_at_put (moo_t* moo, moo_ooi_t nargs)
if (!MOO_OOP_IS_POINTER(rcv))
{
/* the receiver is a special numeric object, not a normal pointer */
moo->errnum = MOO_EINVAL;
return MOO_PF_FAILURE;
}
pos = MOO_STACK_GETARG(moo, nargs, 0);
@ -1588,11 +1593,13 @@ static moo_pfrc_t pf_basic_at_put (moo_t* moo, moo_ooi_t nargs)
if (moo_inttooow (moo, pos, &idx) <= 0)
{
/* negative integer or not integer */
moo->errnum = MOO_EINVAL;
return MOO_PF_FAILURE;
}
if (idx >= MOO_OBJ_GET_SIZE(rcv))
{
/* index out of range */
moo->errnum = MOO_ERANGE;
return MOO_PF_FAILURE;
}
@ -1601,6 +1608,7 @@ static moo_pfrc_t pf_basic_at_put (moo_t* moo, moo_ooi_t nargs)
/* TODO: disallow change of some key kernel objects???? */
/* TODO: is it better to introduct a read-only mark in the object header instead of this class check??? */
/* read-only object */ /* TODO: DEVISE A WAY TO PASS a proper error from the primitive handler to MOO */
moo->errnum = MOO_EINVAL;
return MOO_PF_FAILURE;
}
@ -1610,6 +1618,7 @@ static moo_pfrc_t pf_basic_at_put (moo_t* moo, moo_ooi_t nargs)
if (!MOO_OOP_IS_SMOOI(val))
{
/* the value is not a character */
moo->errnum = MOO_EINVAL;
return MOO_PF_FAILURE;
}
/* TOOD: must I check the range of the value? */
@ -1620,6 +1629,7 @@ static moo_pfrc_t pf_basic_at_put (moo_t* moo, moo_ooi_t nargs)
if (!MOO_OOP_IS_CHAR(val))
{
/* the value is not a character */
moo->errnum = MOO_EINVAL;
return MOO_PF_FAILURE;
}
((moo_oop_char_t)rcv)->slot[idx] = MOO_OOP_TO_CHAR(val);
@ -1629,6 +1639,7 @@ static moo_pfrc_t pf_basic_at_put (moo_t* moo, moo_ooi_t nargs)
if (!MOO_OOP_IS_SMOOI(val))
{
/* the value is not a number */
moo->errnum = MOO_EINVAL;
return MOO_PF_FAILURE;
}
@ -1643,6 +1654,7 @@ static moo_pfrc_t pf_basic_at_put (moo_t* moo, moo_ooi_t nargs)
if (moo_inttooow (moo, val, &w) <= 0)
{
/* the value is not a number, out of range, or negative */
moo->errnum = MOO_EINVAL;
return MOO_PF_FAILURE;
}
((moo_oop_word_t)rcv)->slot[idx] = w;
@ -1712,6 +1724,7 @@ static moo_pfrc_t pf_hash (moo_t* moo, moo_ooi_t nargs)
default:
/* MOO_OBJ_TYPE_OOP, ... */
MOO_DEBUG1 (moo, "<pf_hash> Cannot hash an object of type %d\n", type);
moo->errnum = MOO_EINVAL;
return MOO_PF_FAILURE;
}
break;
@ -1726,6 +1739,65 @@ static moo_pfrc_t pf_hash (moo_t* moo, moo_ooi_t nargs)
return MOO_PF_SUCCESS;
}
static moo_pfrc_t pf_responds_to (moo_t* moo, moo_ooi_t nargs)
{
moo_oop_t rcv, selector;
moo_oocs_t mthname;
rcv = MOO_STACK_GETRCV(moo, nargs);
selector = MOO_STACK_GETARG(moo, nargs, 0);
if (MOO_CLASSOF(moo,selector) != moo->_symbol)
{
moo->errnum = MOO_EINVAL;
return MOO_PF_FAILURE;
}
mthname.ptr = MOO_OBJ_GET_CHAR_SLOT(selector);
mthname.len = MOO_OBJ_GET_SIZE(selector);
if (find_method (moo, rcv, &mthname, 0))
{
MOO_STACK_SETRET (moo, nargs, moo->_true);
}
else
{
MOO_STACK_SETRET (moo, nargs, moo->_false);
}
return MOO_PF_SUCCESS;
}
static moo_pfrc_t pf_perform (moo_t* moo, moo_ooi_t nargs)
{
moo_oop_t /*rcv,*/ selector;
moo_oow_t ssp, esp, i;
/*rcv = MOO_STACK_GETRCV(moo, nargs);*/
selector = MOO_STACK_GETARG(moo, nargs, 0);
if (MOO_CLASSOF(moo,selector) != moo->_symbol)
{
moo->errnum = MOO_EINVAL;
return MOO_PF_FAILURE;
}
/* remove the selector from the stack */
ssp = MOO_STACK_GETARGSP (moo, nargs, 0);
esp = MOO_STACK_GETARGSP (moo, nargs, nargs - 1);
for (i = ssp; i < esp;)
{
moo_oop_t t;
t = MOO_STACK_GET (moo, i);
i++;
MOO_STACK_SET(moo, i, t);
}
MOO_STACK_POP (moo);
/* emulate message sending */
if (send_message (moo, (moo_oop_char_t)selector, 0, nargs - 1) <= -1) return MOO_PF_HARD_FAILURE;
return MOO_PF_SUCCESS;
}
static moo_pfrc_t pf_exceptionize_error (moo_t* moo, moo_ooi_t nargs)
{
moo_oop_t rcv;
@ -2719,12 +2791,15 @@ static pf_t pftab[] =
{ 0, 0, pf_hash, "_hash" },
{ 1, 1, pf_responds_to, "_responds_to" },
{ 1, MAX_NARGS, pf_perform, "_perform" },
{ 1, 1, pf_exceptionize_error, "_exceptionize_error" },
{ 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" },
@ -3043,7 +3118,7 @@ static int send_message (moo_t* moo, moo_oop_char_t selector, int to_super, moo_
receiver = MOO_STACK_GET(moo, moo->sp - nargs);
mthname.ptr = selector->slot;
mthname.ptr = MOO_OBJ_GET_CHAR_SLOT(selector);
mthname.len = MOO_OBJ_GET_SIZE(selector);
method = find_method (moo, receiver, &mthname, to_super);
if (!method)

View File

@ -562,6 +562,19 @@ static moo_uint8_t* scan_new_heap (moo_t* moo, moo_uint8_t* ptr)
return ptr;
}
static moo_rbt_walk_t call_module_gc (moo_rbt_t* rbt, moo_rbt_pair_t* pair, void* ctx)
{
moo_t* moo = (moo_t*)ctx;
moo_mod_data_t* mdp;
mdp = MOO_RBT_VPTR(pair);
MOO_ASSERT (moo, mdp != MOO_NULL);
if (mdp->mod.gc) mdp->mod.gc (moo, &mdp->mod);
return MOO_RBT_WALK_FORWARD;
}
void moo_gc (moo_t* moo)
{
/*
@ -643,6 +656,8 @@ void moo_gc (moo_t* moo)
if (moo->active_method)
moo->active_method = (moo_oop_method_t)moo_moveoop (moo, (moo_oop_t)moo->active_method);
moo_rbt_walk (&moo->modtab, call_module_gc, moo);
for (cb = moo->cblist; cb; cb = cb->next)
{
if (cb->gc) cb->gc (moo);

View File

@ -462,6 +462,9 @@ static void* dl_open (moo_t* moo, const moo_ooch_t* name, int flags)
return handle;
#else
/* TODO: support various platforms */
/* TODO: implemenent this */
MOO_DEBUG1 (moo, "Dynamic loading not implemented - cannot open %js\n", name);
@ -1320,11 +1323,12 @@ int main (int argc, char* argv[])
}
#endif
memset (&vmprim, 0, MOO_SIZEOF(vmprim));
vmprim.dl_open = dl_open;
vmprim.dl_close = dl_close;
vmprim.dl_getsym = dl_getsym;
vmprim.log_write = log_write;
vmprim.vm_startup = vm_startup;
vmprim.vm_cleanup = vm_cleanup;
vmprim.vm_gettime = vm_gettime;

View File

@ -326,7 +326,10 @@
/* Define to the shared archive member specification, say "(shr.o)". */
#undef LT_SHARED_LIB_MEMBER
/* use libltdl */
/* enable dynamic module capability */
#undef MOO_ENABLE_DYNAMIC_MODULE
/* use libltdl when loading a dynamic module */
#undef MOO_ENABLE_LIBLTDL
/* link modules statically into the main library */

View File

@ -925,15 +925,6 @@ void* moo_allocheapmem (
moo_oow_t size
);
/* ========================================================================= */
/* gc.c */
/* ========================================================================= */
moo_oop_t moo_moveoop (
moo_t* moo,
moo_oop_t oop
);
/* ========================================================================= */
/* obj.c */
/* ========================================================================= */
@ -1185,13 +1176,14 @@ int moo_getpfnum (
/* ========================================================================= */
/* moo.c */
/* moo.c */
/* ========================================================================= */
moo_mod_data_t* moo_openmod (
moo_t* moo,
const moo_ooch_t* name,
moo_oow_t namelen
moo_oow_t namelen,
int hints /* 0 or bitwise-ORed of moo_mod_hint_t enumerators */
);
void moo_closemod (

View File

@ -378,7 +378,7 @@ static_modtab[] =
};
#endif
moo_mod_data_t* moo_openmod (moo_t* moo, const moo_ooch_t* name, moo_oow_t namelen)
moo_mod_data_t* moo_openmod (moo_t* moo, const moo_ooch_t* name, moo_oow_t namelen, int hints)
{
moo_rbt_pair_t* pair;
moo_mod_data_t* mdp;
@ -423,14 +423,6 @@ moo_mod_data_t* moo_openmod (moo_t* moo, const moo_ooch_t* name, moo_oow_t namel
}
}
if (n >= MOO_COUNTOF(static_modtab))
{
MOO_DEBUG2 (moo, "Cannot find a static module [%.*js]\n", namelen, name);
moo->errnum = MOO_ENOENT;
return MOO_NULL;
/* TODO: fall back to find dynamic module further on supported platforms instead of returning error here... */
}
if (load)
{
/* found the module in the staic module table */
@ -449,17 +441,36 @@ moo_mod_data_t* moo_openmod (moo_t* moo, const moo_ooch_t* name, moo_oow_t namel
}
mdp = (moo_mod_data_t*)MOO_RBT_VPTR(pair);
MOO_ASSERT (moo, MOO_SIZEOF(mdp->mod.hints) == MOO_SIZEOF(int));
*(int*)&mdp->mod.hints = hints;
if (load (moo, &mdp->mod) <= -1)
{
moo_rbt_delete (&moo->modtab, (moo_ooch_t*)name, namelen);
return MOO_NULL;
}
mdp->pair = pair;
MOO_DEBUG1 (moo, "Opened a static module [%js]\n", mdp->mod.name);
return mdp;
}
else
{
#if !defined(MOO_ENABLE_DYNAMIC_MODULE)
MOO_DEBUG2 (moo, "Cannot find a static module [%.*js]\n", namelen, name);
moo->errnum = MOO_ENOENT;
return MOO_NULL;
#endif
}
#endif
/* attempt to find an external module */
#if !defined(MOO_ENABLE_DYNAMIC_MODULE)
MOO_DEBUG2 (moo, "Cannot open module [%.*js] - module loading disabled\n", namelen, name);
moo->errnum = MOO_ENOIMPL; /* TODO: is it a good error number for disabled module loading? */
return MOO_NULL;
#endif
/* attempt to find a dynamic external module */
MOO_MEMSET (&md, 0, MOO_SIZEOF(md));
moo_copyoochars ((moo_ooch_t*)md.mod.name, name, namelen);
if (moo->vmprim.dl_open && moo->vmprim.dl_getsym && moo->vmprim.dl_close)
@ -496,6 +507,8 @@ moo_mod_data_t* moo_openmod (moo_t* moo, const moo_ooch_t* name, moo_oow_t namel
}
mdp = (moo_mod_data_t*)MOO_RBT_VPTR(pair);
MOO_ASSERT (moo, MOO_SIZEOF(mdp->mod.hints) == MOO_SIZEOF(int));
*(int*)&mdp->mod.hints = hints;
if (load (moo, &mdp->mod) <= -1)
{
MOO_DEBUG3 (moo, "Module function [%js] returned failure in [%.*js]\n", buf, namelen, name);
@ -525,6 +538,10 @@ void moo_closemod (moo_t* moo, moo_mod_data_t* mdp)
MOO_DEBUG2 (moo, "Closed a module [%js] - %p\n", mdp->mod.name, mdp->handle);
mdp->handle = MOO_NULL;
}
else
{
MOO_DEBUG1 (moo, "Closed a static module [%js] - %p\n", mdp->mod.name);
}
if (mdp->pair)
{
@ -537,7 +554,7 @@ int moo_importmod (moo_t* moo, moo_oop_class_t _class, const moo_ooch_t* name, m
{
moo_rbt_pair_t* pair;
moo_mod_data_t* mdp;
int r = 0;
int r = -1;
/* moo_openmod(), moo_closemod(), etc call a user-defined callback.
* i need to protect _class in case the user-defined callback allocates
@ -550,38 +567,36 @@ int moo_importmod (moo_t* moo, moo_oop_class_t _class, const moo_ooch_t* name, m
{
mdp = (moo_mod_data_t*)MOO_RBT_VPTR(pair);
MOO_ASSERT (moo, mdp != MOO_NULL);
MOO_DEBUG1 (moo, "Cannot import module [%js] - already active\n", mdp->mod.name);
moo->errnum = MOO_EPERM;
goto done2;
}
else
{
mdp = moo_openmod (moo, name, len);
if (!mdp)
{
r = -1;
goto done2;
}
}
mdp = moo_openmod (moo, name, len, MOO_MOD_LOAD_FOR_IMPORT);
if (!mdp) goto done2;
if (!mdp->mod.import)
{
MOO_DEBUG1 (moo, "Cannot import module [%js] - importing not supported by the module\n", mdp->mod.name);
moo->errnum = MOO_ENOIMPL;
r = -1;
goto done;
}
if (mdp->mod.import (moo, &mdp->mod, _class) <= -1)
{
MOO_DEBUG1 (moo, "Cannot import module [%js] - module's import() returned failure\n", mdp->mod.name);
r = -1;
goto done;
}
r = 0; /* everything successful */
done:
if (!pair)
{
/* close the module if it has been opened in this function. */
moo_closemod (moo, mdp);
}
/* close the module opened above.
* [NOTE] if the import callback calls the moo_querymod(), the returned
* function pointers will get all invalidated here. so never do
* anything like that */
moo_closemod (moo, mdp);
done2:
moo_poptmp (moo);
@ -615,8 +630,8 @@ moo_pfimpl_t moo_querymod (moo_t* moo, const moo_ooch_t* pfid, moo_oow_t pfidlen
mod_name_len = sep - pfid;
/* the first through the segment before the last compose a module id.
* the last segment is the primitive function name.
/* the first segment through the segment before the last compose a
* module id. the last segment is the primitive function name.
* for instance, in con.window.open, con.window is a module id and
* open is the primitive function name. */
pair = moo_rbt_search (&moo->modtab, pfid, mod_name_len);
@ -628,7 +643,7 @@ moo_pfimpl_t moo_querymod (moo_t* moo, const moo_ooch_t* pfid, moo_oow_t pfidlen
else
{
/* open a module using the part before the last period */
mdp = moo_openmod (moo, pfid, mod_name_len);
mdp = moo_openmod (moo, pfid, mod_name_len, 0);
if (!mdp) return MOO_NULL;
}
@ -873,3 +888,22 @@ void* moo_getobjtrailer (moo_t* moo, moo_oop_t obj, moo_oow_t* size)
if (size) *size = MOO_OBJ_GET_TRAILER_SIZE(obj);
return MOO_OBJ_GET_TRAILER_BYTE(obj);
}
moo_oop_t moo_findclass (moo_t* moo, moo_oop_set_t nsdic, const moo_ooch_t* name)
{
moo_oop_association_t ass;
moo_oocs_t n;
n.ptr = (moo_ooch_t*)name;
n.len = moo_countoocstr(name);
ass = moo_lookupdic (moo, nsdic, &n);
if (!ass || MOO_CLASSOF(moo,ass->value) != moo->_class)
{
moo->errnum = MOO_ENOENT;
return MOO_NULL;
}
return ass->value;
}

View File

@ -840,9 +840,14 @@ struct moo_pfinfo_t
moo_pfimpl_t handler;
};
typedef struct moo_mod_t moo_mod_t;
enum moo_mod_hint_t
{
MOO_MOD_LOAD_FOR_IMPORT = (1 << 0)
};
typedef enum moo_mod_hint_t moo_mod_hint_t;
typedef int (*moo_mod_load_t) (
moo_t* moo,
moo_mod_t* mod
@ -865,12 +870,22 @@ typedef void (*moo_mod_unload_t) (
moo_mod_t* mod
);
typedef void (*moo_mod_gc_t) (
moo_t* moo,
moo_mod_t* mod
);
struct moo_mod_t
{
/* input */
const moo_ooch_t name[MOO_MOD_NAME_LEN_MAX + 1];
const int hints; /* bitwised-ORed of moo_mod_hint_t enumerators */
/* user-defined data */
moo_mod_import_t import;
moo_mod_query_t query;
moo_mod_unload_t unload;
moo_mod_gc_t gc;
void* ctx;
};
@ -883,7 +898,6 @@ struct moo_mod_data_t
typedef struct moo_mod_data_t moo_mod_data_t;
struct moo_sbuf_t
{
moo_ooch_t* ptr;
@ -1065,6 +1079,7 @@ struct moo_t
#define MOO_STACK_POPS(moo,count) ((moo)->sp = (moo)->sp - (count))
#define MOO_STACK_ISEMPTY(moo) ((moo)->sp <= -1)
#define MOO_STACK_GETARGSP(moo,nargs,idx) ((moo)->sp - ((nargs) - (idx) - 1))
#define MOO_STACK_GETARG(moo,nargs,idx) MOO_STACK_GET(moo, (moo)->sp - ((nargs) - (idx) - 1))
#define MOO_STACK_GETRCV(moo,nargs) MOO_STACK_GET(moo, (moo)->sp - nargs)
@ -1348,6 +1363,15 @@ MOO_EXPORT void moo_gc (
);
/**
* The moo_moveoop() function moves an object and returns an updated pointer
* after having moved. it must be called in the GC callback context only.
*/
MOO_EXPORT moo_oop_t moo_moveoop (
moo_t* moo,
moo_oop_t oop
);
/**
* The moo_instantiate() function creates a new object instance of the class
* \a _class. The size of the fixed part is taken from the information
@ -1457,6 +1481,11 @@ MOO_EXPORT int moo_inttoooi (
moo_ooi_t* i
);
MOO_EXPORT moo_oop_t moo_findclass (
moo_t* moo,
moo_oop_set_t nsdic,
const moo_ooch_t* name
);
/* =========================================================================
* TRAILER MANAGEMENT