mirror of
https://github.com/LuaJIT/LuaJIT.git
synced 2025-02-07 23:24:09 +00:00
FFI: Check for __new metamethod when calling a constructor.
This commit is contained in:
parent
e9e45313e7
commit
8b71ab1080
@ -599,8 +599,9 @@ C type pointed to by the reference.
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
The pre-defined operations are always tried first before deferring to a
|
The pre-defined operations are always tried first before deferring to a
|
||||||
metamethod or index table (if any) for the corresponding ctype. An error
|
metamethod or index table (if any) for the corresponding ctype (except
|
||||||
is raised if the metamethod lookup or index table lookup fails.
|
for <tt>__new</tt>). An error is raised if the metamethod lookup or
|
||||||
|
index table lookup fails.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h3 id="cdata_array">Indexing a cdata object</h3>
|
<h3 id="cdata_array">Indexing a cdata object</h3>
|
||||||
@ -669,7 +670,12 @@ to <tt>foo.c</tt>.
|
|||||||
<ul>
|
<ul>
|
||||||
|
|
||||||
<li><b>Constructor</b>: a ctype object can be called and used as a
|
<li><b>Constructor</b>: a ctype object can be called and used as a
|
||||||
<a href="ext_ffi_api.html#ffi_new">constructor</a>.</li>
|
<a href="ext_ffi_api.html#ffi_new">constructor</a>. This is equivalent
|
||||||
|
to <tt>ffi.new(ct, ...)</tt>, unless a <tt>__new</tt> metamethod is
|
||||||
|
defined. The <tt>__new</tt> metamethod is called with the ctype object
|
||||||
|
plus any other arguments passed to the contructor. Note that you have to
|
||||||
|
use <tt>ffi.new</tt> inside of it, since calling <tt>ct(...)</tt> would
|
||||||
|
cause infinite recursion.</li>
|
||||||
|
|
||||||
<li><b>C function call</b>: a cdata function or cdata function
|
<li><b>C function call</b>: a cdata function or cdata function
|
||||||
pointer can be called. The passed arguments are
|
pointer can be called. The passed arguments are
|
||||||
|
@ -206,31 +206,34 @@ LJLIB_CF(ffi_meta___concat) LJLIB_REC(cdata_arith MM_concat)
|
|||||||
return ffi_arith(L);
|
return ffi_arith(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle ctype __call metamethod. */
|
|
||||||
static int ffi_call_meta(lua_State *L, CTypeID id)
|
|
||||||
{
|
|
||||||
CTState *cts = ctype_cts(L);
|
|
||||||
CType *ct = ctype_raw(cts, id);
|
|
||||||
cTValue *tv;
|
|
||||||
if (ctype_isptr(ct->info)) id = ctype_cid(ct->info);
|
|
||||||
tv = lj_ctype_meta(cts, id, MM_call);
|
|
||||||
if (!tv)
|
|
||||||
lj_err_callerv(L, LJ_ERR_FFI_BADCALL, strdata(lj_ctype_repr(L, id, NULL)));
|
|
||||||
return lj_meta_tailcall(L, tv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Forward declaration. */
|
/* Forward declaration. */
|
||||||
static int lj_cf_ffi_new(lua_State *L);
|
static int lj_cf_ffi_new(lua_State *L);
|
||||||
|
|
||||||
LJLIB_CF(ffi_meta___call) LJLIB_REC(cdata_call)
|
LJLIB_CF(ffi_meta___call) LJLIB_REC(cdata_call)
|
||||||
{
|
{
|
||||||
|
CTState *cts = ctype_cts(L);
|
||||||
GCcdata *cd = ffi_checkcdata(L, 1);
|
GCcdata *cd = ffi_checkcdata(L, 1);
|
||||||
int ret;
|
CTypeID id = cd->typeid;
|
||||||
if (cd->typeid == CTID_CTYPEID)
|
CType *ct;
|
||||||
return lj_cf_ffi_new(L);
|
cTValue *tv;
|
||||||
if ((ret = lj_ccall_func(L, cd)) < 0)
|
MMS mm = MM_call;
|
||||||
return ffi_call_meta(L, cd->typeid);
|
if (cd->typeid == CTID_CTYPEID) {
|
||||||
return ret;
|
id = *(CTypeID *)cdataptr(cd);
|
||||||
|
mm = MM_new;
|
||||||
|
} else {
|
||||||
|
int ret = lj_ccall_func(L, cd);
|
||||||
|
if (ret >= 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
/* Handle ctype __call/__new metamethod. */
|
||||||
|
ct = ctype_raw(cts, id);
|
||||||
|
if (ctype_isptr(ct->info)) id = ctype_cid(ct->info);
|
||||||
|
tv = lj_ctype_meta(cts, id, mm);
|
||||||
|
if (tv)
|
||||||
|
return lj_meta_tailcall(L, tv);
|
||||||
|
else if (mm == MM_call)
|
||||||
|
lj_err_callerv(L, LJ_ERR_FFI_BADCALL, strdata(lj_ctype_repr(L, id, NULL)));
|
||||||
|
return lj_cf_ffi_new(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
LJLIB_CF(ffi_meta___add) LJLIB_REC(cdata_arith MM_add)
|
LJLIB_CF(ffi_meta___add) LJLIB_REC(cdata_arith MM_add)
|
||||||
|
@ -941,30 +941,36 @@ static int crec_call(jit_State *J, RecordFFData *rd, GCcdata *cd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Record ctype call metamethod. */
|
|
||||||
static void crec_call_meta(jit_State *J, RecordFFData *rd, CTypeID id)
|
|
||||||
{
|
|
||||||
CTState *cts = ctype_ctsG(J2G(J));
|
|
||||||
CType *ct = ctype_raw(cts, id);
|
|
||||||
cTValue *tv;
|
|
||||||
if (ctype_isptr(ct->info)) id = ctype_cid(ct->info);
|
|
||||||
tv = lj_ctype_meta(cts, id, MM_call);
|
|
||||||
if (tv && tvisfunc(tv)) {
|
|
||||||
J->base[-1] = lj_ir_kfunc(J, funcV(tv)) | TREF_FRAME;
|
|
||||||
rd->nres = -1; /* Pending tailcall. */
|
|
||||||
} else {
|
|
||||||
/* NYI: non-function metamethods. */
|
|
||||||
lj_trace_err(J, LJ_TRERR_BADTYPE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LJ_FASTCALL recff_cdata_call(jit_State *J, RecordFFData *rd)
|
void LJ_FASTCALL recff_cdata_call(jit_State *J, RecordFFData *rd)
|
||||||
{
|
{
|
||||||
|
CTState *cts = ctype_ctsG(J2G(J));
|
||||||
GCcdata *cd = argv2cdata(J, J->base[0], &rd->argv[0]);
|
GCcdata *cd = argv2cdata(J, J->base[0], &rd->argv[0]);
|
||||||
if (cd->typeid == CTID_CTYPEID)
|
CTypeID id = cd->typeid;
|
||||||
crec_alloc(J, rd, crec_constructor(J, cd, J->base[0]));
|
CType *ct;
|
||||||
else if (!crec_call(J, rd, cd))
|
cTValue *tv;
|
||||||
crec_call_meta(J, rd, cd->typeid);
|
MMS mm = MM_call;
|
||||||
|
if (id == CTID_CTYPEID) {
|
||||||
|
id = crec_constructor(J, cd, J->base[0]);
|
||||||
|
mm = MM_new;
|
||||||
|
} else if (crec_call(J, rd, cd)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Record ctype __call/__new metamethod. */
|
||||||
|
ct = ctype_raw(cts, id);
|
||||||
|
if (ctype_isptr(ct->info)) id = ctype_cid(ct->info);
|
||||||
|
tv = lj_ctype_meta(cts, id, mm);
|
||||||
|
if (tv) {
|
||||||
|
if (tvisfunc(tv)) {
|
||||||
|
J->base[-1] = lj_ir_kfunc(J, funcV(tv)) | TREF_FRAME;
|
||||||
|
rd->nres = -1; /* Pending tailcall. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (mm == MM_new) {
|
||||||
|
crec_alloc(J, rd, id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* No metamethod or NYI: non-function metamethods. */
|
||||||
|
lj_trace_err(J, LJ_TRERR_BADTYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static TRef crec_arith_int64(jit_State *J, TRef *sp, CType **s, MMS mm)
|
static TRef crec_arith_int64(jit_State *J, TRef *sp, CType **s, MMS mm)
|
||||||
|
@ -437,6 +437,12 @@ enum {
|
|||||||
#define setvmstate(g, st) ((g)->vmstate = ~LJ_VMST_##st)
|
#define setvmstate(g, st) ((g)->vmstate = ~LJ_VMST_##st)
|
||||||
|
|
||||||
/* Metamethods. ORDER MM */
|
/* Metamethods. ORDER MM */
|
||||||
|
#ifdef LJ_HASFFI
|
||||||
|
#define MMDEF_FFI(_) _(new)
|
||||||
|
#else
|
||||||
|
#define MMDEF_FFI(_)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef LUAJIT_ENABLE_LUA52COMPAT
|
#ifdef LUAJIT_ENABLE_LUA52COMPAT
|
||||||
#define MMDEF_52(_) _(pairs) _(ipairs)
|
#define MMDEF_52(_) _(pairs) _(ipairs)
|
||||||
#else
|
#else
|
||||||
@ -450,7 +456,7 @@ enum {
|
|||||||
/* The following must be in ORDER ARITH. */ \
|
/* The following must be in ORDER ARITH. */ \
|
||||||
_(add) _(sub) _(mul) _(div) _(mod) _(pow) _(unm) \
|
_(add) _(sub) _(mul) _(div) _(mod) _(pow) _(unm) \
|
||||||
/* The following are used in the standard libraries. */ \
|
/* The following are used in the standard libraries. */ \
|
||||||
_(metatable) _(tostring) MMDEF_52(_)
|
_(metatable) _(tostring) MMDEF_FFI(_) MMDEF_52(_)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
#define MMENUM(name) MM_##name,
|
#define MMENUM(name) MM_##name,
|
||||||
|
Loading…
Reference in New Issue
Block a user