diff options
| author | Mike Pall <mike> | 2012-06-20 18:24:49 +0200 |
|---|---|---|
| committer | Mike Pall <mike> | 2012-06-20 18:28:25 +0200 |
| commit | 8b71ab108053c12bc2de9c1de0f786387a2b75e5 (patch) | |
| tree | 98be8d9138d3cb13dac67f5f7621b0bf09bb0fc7 /src | |
| parent | e9e45313e737579bc6db4f74942bcd66e95532c1 (diff) | |
| download | luajit-8b71ab108053c12bc2de9c1de0f786387a2b75e5.tar.gz luajit-8b71ab108053c12bc2de9c1de0f786387a2b75e5.tar.bz2 luajit-8b71ab108053c12bc2de9c1de0f786387a2b75e5.zip | |
FFI: Check for __new metamethod when calling a constructor.
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib_ffi.c | 41 | ||||
| -rw-r--r-- | src/lj_crecord.c | 44 | ||||
| -rw-r--r-- | src/lj_obj.h | 8 |
3 files changed, 54 insertions, 39 deletions
diff --git a/src/lib_ffi.c b/src/lib_ffi.c index f4097041..e7d31fe7 100644 --- a/src/lib_ffi.c +++ b/src/lib_ffi.c | |||
| @@ -206,31 +206,34 @@ LJLIB_CF(ffi_meta___concat) LJLIB_REC(cdata_arith MM_concat) | |||
| 206 | return ffi_arith(L); | 206 | return ffi_arith(L); |
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | /* Handle ctype __call metamethod. */ | ||
| 210 | static int ffi_call_meta(lua_State *L, CTypeID id) | ||
| 211 | { | ||
| 212 | CTState *cts = ctype_cts(L); | ||
| 213 | CType *ct = ctype_raw(cts, id); | ||
| 214 | cTValue *tv; | ||
| 215 | if (ctype_isptr(ct->info)) id = ctype_cid(ct->info); | ||
| 216 | tv = lj_ctype_meta(cts, id, MM_call); | ||
| 217 | if (!tv) | ||
| 218 | lj_err_callerv(L, LJ_ERR_FFI_BADCALL, strdata(lj_ctype_repr(L, id, NULL))); | ||
| 219 | return lj_meta_tailcall(L, tv); | ||
| 220 | } | ||
| 221 | |||
| 222 | /* Forward declaration. */ | 209 | /* Forward declaration. */ |
| 223 | static int lj_cf_ffi_new(lua_State *L); | 210 | static int lj_cf_ffi_new(lua_State *L); |
| 224 | 211 | ||
| 225 | LJLIB_CF(ffi_meta___call) LJLIB_REC(cdata_call) | 212 | LJLIB_CF(ffi_meta___call) LJLIB_REC(cdata_call) |
| 226 | { | 213 | { |
| 214 | CTState *cts = ctype_cts(L); | ||
| 227 | GCcdata *cd = ffi_checkcdata(L, 1); | 215 | GCcdata *cd = ffi_checkcdata(L, 1); |
| 228 | int ret; | 216 | CTypeID id = cd->typeid; |
| 229 | if (cd->typeid == CTID_CTYPEID) | 217 | CType *ct; |
| 230 | return lj_cf_ffi_new(L); | 218 | cTValue *tv; |
| 231 | if ((ret = lj_ccall_func(L, cd)) < 0) | 219 | MMS mm = MM_call; |
| 232 | return ffi_call_meta(L, cd->typeid); | 220 | if (cd->typeid == CTID_CTYPEID) { |
| 233 | return ret; | 221 | id = *(CTypeID *)cdataptr(cd); |
| 222 | mm = MM_new; | ||
| 223 | } else { | ||
| 224 | int ret = lj_ccall_func(L, cd); | ||
| 225 | if (ret >= 0) | ||
| 226 | return ret; | ||
| 227 | } | ||
| 228 | /* Handle ctype __call/__new metamethod. */ | ||
| 229 | ct = ctype_raw(cts, id); | ||
| 230 | if (ctype_isptr(ct->info)) id = ctype_cid(ct->info); | ||
| 231 | tv = lj_ctype_meta(cts, id, mm); | ||
| 232 | if (tv) | ||
| 233 | return lj_meta_tailcall(L, tv); | ||
| 234 | else if (mm == MM_call) | ||
| 235 | lj_err_callerv(L, LJ_ERR_FFI_BADCALL, strdata(lj_ctype_repr(L, id, NULL))); | ||
| 236 | return lj_cf_ffi_new(L); | ||
| 234 | } | 237 | } |
| 235 | 238 | ||
| 236 | LJLIB_CF(ffi_meta___add) LJLIB_REC(cdata_arith MM_add) | 239 | LJLIB_CF(ffi_meta___add) LJLIB_REC(cdata_arith MM_add) |
diff --git a/src/lj_crecord.c b/src/lj_crecord.c index 3097cbf0..95d09e48 100644 --- a/src/lj_crecord.c +++ b/src/lj_crecord.c | |||
| @@ -941,30 +941,36 @@ static int crec_call(jit_State *J, RecordFFData *rd, GCcdata *cd) | |||
| 941 | return 0; | 941 | return 0; |
| 942 | } | 942 | } |
| 943 | 943 | ||
| 944 | /* Record ctype call metamethod. */ | 944 | void LJ_FASTCALL recff_cdata_call(jit_State *J, RecordFFData *rd) |
| 945 | static void crec_call_meta(jit_State *J, RecordFFData *rd, CTypeID id) | ||
| 946 | { | 945 | { |
| 947 | CTState *cts = ctype_ctsG(J2G(J)); | 946 | CTState *cts = ctype_ctsG(J2G(J)); |
| 948 | CType *ct = ctype_raw(cts, id); | 947 | GCcdata *cd = argv2cdata(J, J->base[0], &rd->argv[0]); |
| 948 | CTypeID id = cd->typeid; | ||
| 949 | CType *ct; | ||
| 949 | cTValue *tv; | 950 | cTValue *tv; |
| 951 | MMS mm = MM_call; | ||
| 952 | if (id == CTID_CTYPEID) { | ||
| 953 | id = crec_constructor(J, cd, J->base[0]); | ||
| 954 | mm = MM_new; | ||
| 955 | } else if (crec_call(J, rd, cd)) { | ||
| 956 | return; | ||
| 957 | } | ||
| 958 | /* Record ctype __call/__new metamethod. */ | ||
| 959 | ct = ctype_raw(cts, id); | ||
| 950 | if (ctype_isptr(ct->info)) id = ctype_cid(ct->info); | 960 | if (ctype_isptr(ct->info)) id = ctype_cid(ct->info); |
| 951 | tv = lj_ctype_meta(cts, id, MM_call); | 961 | tv = lj_ctype_meta(cts, id, mm); |
| 952 | if (tv && tvisfunc(tv)) { | 962 | if (tv) { |
| 953 | J->base[-1] = lj_ir_kfunc(J, funcV(tv)) | TREF_FRAME; | 963 | if (tvisfunc(tv)) { |
| 954 | rd->nres = -1; /* Pending tailcall. */ | 964 | J->base[-1] = lj_ir_kfunc(J, funcV(tv)) | TREF_FRAME; |
| 955 | } else { | 965 | rd->nres = -1; /* Pending tailcall. */ |
| 956 | /* NYI: non-function metamethods. */ | 966 | return; |
| 957 | lj_trace_err(J, LJ_TRERR_BADTYPE); | 967 | } |
| 968 | } else if (mm == MM_new) { | ||
| 969 | crec_alloc(J, rd, id); | ||
| 970 | return; | ||
| 958 | } | 971 | } |
| 959 | } | 972 | /* No metamethod or NYI: non-function metamethods. */ |
| 960 | 973 | lj_trace_err(J, LJ_TRERR_BADTYPE); | |
| 961 | void LJ_FASTCALL recff_cdata_call(jit_State *J, RecordFFData *rd) | ||
| 962 | { | ||
| 963 | GCcdata *cd = argv2cdata(J, J->base[0], &rd->argv[0]); | ||
| 964 | if (cd->typeid == CTID_CTYPEID) | ||
| 965 | crec_alloc(J, rd, crec_constructor(J, cd, J->base[0])); | ||
| 966 | else if (!crec_call(J, rd, cd)) | ||
| 967 | crec_call_meta(J, rd, cd->typeid); | ||
| 968 | } | 974 | } |
| 969 | 975 | ||
| 970 | static TRef crec_arith_int64(jit_State *J, TRef *sp, CType **s, MMS mm) | 976 | static TRef crec_arith_int64(jit_State *J, TRef *sp, CType **s, MMS mm) |
diff --git a/src/lj_obj.h b/src/lj_obj.h index 43ed9204..d7e8ec09 100644 --- a/src/lj_obj.h +++ b/src/lj_obj.h | |||
| @@ -437,6 +437,12 @@ enum { | |||
| 437 | #define setvmstate(g, st) ((g)->vmstate = ~LJ_VMST_##st) | 437 | #define setvmstate(g, st) ((g)->vmstate = ~LJ_VMST_##st) |
| 438 | 438 | ||
| 439 | /* Metamethods. ORDER MM */ | 439 | /* Metamethods. ORDER MM */ |
| 440 | #ifdef LJ_HASFFI | ||
| 441 | #define MMDEF_FFI(_) _(new) | ||
| 442 | #else | ||
| 443 | #define MMDEF_FFI(_) | ||
| 444 | #endif | ||
| 445 | |||
| 440 | #ifdef LUAJIT_ENABLE_LUA52COMPAT | 446 | #ifdef LUAJIT_ENABLE_LUA52COMPAT |
| 441 | #define MMDEF_52(_) _(pairs) _(ipairs) | 447 | #define MMDEF_52(_) _(pairs) _(ipairs) |
| 442 | #else | 448 | #else |
| @@ -450,7 +456,7 @@ enum { | |||
| 450 | /* The following must be in ORDER ARITH. */ \ | 456 | /* The following must be in ORDER ARITH. */ \ |
| 451 | _(add) _(sub) _(mul) _(div) _(mod) _(pow) _(unm) \ | 457 | _(add) _(sub) _(mul) _(div) _(mod) _(pow) _(unm) \ |
| 452 | /* The following are used in the standard libraries. */ \ | 458 | /* The following are used in the standard libraries. */ \ |
| 453 | _(metatable) _(tostring) MMDEF_52(_) | 459 | _(metatable) _(tostring) MMDEF_FFI(_) MMDEF_52(_) |
| 454 | 460 | ||
| 455 | typedef enum { | 461 | typedef enum { |
| 456 | #define MMENUM(name) MM_##name, | 462 | #define MMENUM(name) MM_##name, |
