diff options
| author | Mike Pall <mike> | 2011-04-12 19:15:00 +0200 |
|---|---|---|
| committer | Mike Pall <mike> | 2011-04-12 19:16:39 +0200 |
| commit | 3b6f37dd2c336987251d53a4678396ef38921b3e (patch) | |
| tree | 6e6176c37b600e461d078dbe663008dcc84d2418 /src | |
| parent | fa5cd010e8e28c7fe2338d0fdd538e95ddd88bcc (diff) | |
| download | luajit-3b6f37dd2c336987251d53a4678396ef38921b3e.tar.gz luajit-3b6f37dd2c336987251d53a4678396ef38921b3e.tar.bz2 luajit-3b6f37dd2c336987251d53a4678396ef38921b3e.zip | |
FFI: Add ctype metamethods and ffi.metatype().
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.dep | 13 | ||||
| -rw-r--r-- | src/lib_ffi.c | 116 | ||||
| -rw-r--r-- | src/lj_asm.c | 6 | ||||
| -rw-r--r-- | src/lj_carith.c | 42 | ||||
| -rw-r--r-- | src/lj_cdata.c | 26 | ||||
| -rw-r--r-- | src/lj_crecord.c | 153 | ||||
| -rw-r--r-- | src/lj_ctype.c | 16 | ||||
| -rw-r--r-- | src/lj_ctype.h | 2 |
8 files changed, 296 insertions, 78 deletions
diff --git a/src/Makefile.dep b/src/Makefile.dep index 57904877..c06060ce 100644 --- a/src/Makefile.dep +++ b/src/Makefile.dep | |||
| @@ -21,9 +21,9 @@ lib_bit.o: lib_bit.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \ | |||
| 21 | lib_debug.o: lib_debug.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \ | 21 | lib_debug.o: lib_debug.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \ |
| 22 | lj_def.h lj_arch.h lj_err.h lj_errmsg.h lj_lib.h lj_libdef.h | 22 | lj_def.h lj_arch.h lj_err.h lj_errmsg.h lj_lib.h lj_libdef.h |
| 23 | lib_ffi.o: lib_ffi.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \ | 23 | lib_ffi.o: lib_ffi.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \ |
| 24 | lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_ctype.h \ | 24 | lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h \ |
| 25 | lj_cparse.h lj_cdata.h lj_cconv.h lj_carith.h lj_ccall.h lj_clib.h \ | 25 | lj_ctype.h lj_cparse.h lj_cdata.h lj_cconv.h lj_carith.h lj_ccall.h \ |
| 26 | lj_ff.h lj_ffdef.h lj_lib.h lj_libdef.h | 26 | lj_clib.h lj_ff.h lj_ffdef.h lj_lib.h lj_libdef.h |
| 27 | lib_init.o: lib_init.c lua.h luaconf.h lauxlib.h lualib.h lj_arch.h | 27 | lib_init.o: lib_init.c lua.h luaconf.h lauxlib.h lualib.h lj_arch.h |
| 28 | lib_io.o: lib_io.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \ | 28 | lib_io.o: lib_io.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \ |
| 29 | lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ff.h lj_ffdef.h \ | 29 | lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ff.h lj_ffdef.h \ |
| @@ -57,8 +57,8 @@ lj_asm.o: lj_asm.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ | |||
| 57 | lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \ | 57 | lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \ |
| 58 | lj_bcdef.h | 58 | lj_bcdef.h |
| 59 | lj_carith.o: lj_carith.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ | 59 | lj_carith.o: lj_carith.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ |
| 60 | lj_gc.h lj_err.h lj_errmsg.h lj_ctype.h lj_cconv.h lj_cdata.h \ | 60 | lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_meta.h lj_ctype.h lj_cconv.h \ |
| 61 | lj_carith.h | 61 | lj_cdata.h lj_carith.h |
| 62 | lj_ccall.o: lj_ccall.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ | 62 | lj_ccall.o: lj_ccall.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ |
| 63 | lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ctype.h lj_cconv.h lj_cdata.h \ | 63 | lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ctype.h lj_cconv.h lj_cdata.h \ |
| 64 | lj_ccall.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h lj_bc.h \ | 64 | lj_ccall.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h lj_bc.h \ |
| @@ -77,7 +77,8 @@ lj_cparse.o: lj_cparse.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ | |||
| 77 | lj_crecord.o: lj_crecord.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ | 77 | lj_crecord.o: lj_crecord.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ |
| 78 | lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h \ | 78 | lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h \ |
| 79 | lj_gc.h lj_cparse.h lj_cconv.h lj_clib.h lj_ir.h lj_jit.h lj_iropt.h \ | 79 | lj_gc.h lj_cparse.h lj_cconv.h lj_clib.h lj_ir.h lj_jit.h lj_iropt.h \ |
| 80 | lj_trace.h lj_dispatch.h lj_traceerr.h lj_ffrecord.h lj_crecord.h | 80 | lj_trace.h lj_dispatch.h lj_traceerr.h lj_record.h lj_ffrecord.h \ |
| 81 | lj_crecord.h | ||
| 81 | lj_ctype.o: lj_ctype.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ | 82 | lj_ctype.o: lj_ctype.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ |
| 82 | lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_ctype.h | 83 | lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_ctype.h |
| 83 | lj_dispatch.o: lj_dispatch.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ | 84 | lj_dispatch.o: lj_dispatch.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ |
diff --git a/src/lib_ffi.c b/src/lib_ffi.c index cb001ae9..fe84ca7d 100644 --- a/src/lib_ffi.c +++ b/src/lib_ffi.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include "lj_err.h" | 18 | #include "lj_err.h" |
| 19 | #include "lj_str.h" | 19 | #include "lj_str.h" |
| 20 | #include "lj_tab.h" | 20 | #include "lj_tab.h" |
| 21 | #include "lj_meta.h" | ||
| 21 | #include "lj_ctype.h" | 22 | #include "lj_ctype.h" |
| 22 | #include "lj_cparse.h" | 23 | #include "lj_cparse.h" |
| 23 | #include "lj_cdata.h" | 24 | #include "lj_cdata.h" |
| @@ -96,6 +97,41 @@ static int32_t ffi_checkint(lua_State *L, int narg) | |||
| 96 | 97 | ||
| 97 | #define LJLIB_MODULE_ffi_meta | 98 | #define LJLIB_MODULE_ffi_meta |
| 98 | 99 | ||
| 100 | /* Handle ctype __index/__newindex metamethods. */ | ||
| 101 | static int ffi_index_meta(lua_State *L, CTState *cts, CType *ct, MMS mm) | ||
| 102 | { | ||
| 103 | CTypeID id = ctype_typeid(cts, ct); | ||
| 104 | cTValue *tv = lj_ctype_meta(cts, id, mm); | ||
| 105 | TValue *base = L->base; | ||
| 106 | if (!tv) { | ||
| 107 | const char *s; | ||
| 108 | err_index: | ||
| 109 | s = strdata(lj_ctype_repr(L, id, NULL)); | ||
| 110 | if (tvisstr(L->base+1)) | ||
| 111 | lj_err_callerv(L, LJ_ERR_FFI_BADMEMBER, s, strVdata(L->base+1)); | ||
| 112 | else | ||
| 113 | lj_err_callerv(L, LJ_ERR_FFI_BADIDX, s); | ||
| 114 | } | ||
| 115 | if (!tvisfunc(tv)) { | ||
| 116 | if (mm == MM_index) { | ||
| 117 | cTValue *o = lj_meta_tget(L, tv, base+1); | ||
| 118 | if (o) { | ||
| 119 | if (tvisnil(o)) goto err_index; | ||
| 120 | copyTV(L, L->top-1, o); | ||
| 121 | return 1; | ||
| 122 | } | ||
| 123 | } else { | ||
| 124 | TValue *o = lj_meta_tset(L, tv, base+1); | ||
| 125 | if (o) { | ||
| 126 | copyTV(L, o, base+2); | ||
| 127 | return 0; | ||
| 128 | } | ||
| 129 | } | ||
| 130 | tv = L->top-1; | ||
| 131 | } | ||
| 132 | return lj_meta_tailcall(L, tv); | ||
| 133 | } | ||
| 134 | |||
| 99 | LJLIB_CF(ffi_meta___index) LJLIB_REC(cdata_index 0) | 135 | LJLIB_CF(ffi_meta___index) LJLIB_REC(cdata_index 0) |
| 100 | { | 136 | { |
| 101 | CTState *cts = ctype_cts(L); | 137 | CTState *cts = ctype_cts(L); |
| @@ -106,6 +142,8 @@ LJLIB_CF(ffi_meta___index) LJLIB_REC(cdata_index 0) | |||
| 106 | if (!(o+1 < L->top && tviscdata(o))) /* Also checks for presence of key. */ | 142 | if (!(o+1 < L->top && tviscdata(o))) /* Also checks for presence of key. */ |
| 107 | lj_err_argt(L, 1, LUA_TCDATA); | 143 | lj_err_argt(L, 1, LUA_TCDATA); |
| 108 | ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual); | 144 | ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual); |
| 145 | if ((qual & 1)) | ||
| 146 | return ffi_index_meta(L, cts, ct, MM_index); | ||
| 109 | if (lj_cdata_get(cts, ct, L->top-1, p)) | 147 | if (lj_cdata_get(cts, ct, L->top-1, p)) |
| 110 | lj_gc_check(L); | 148 | lj_gc_check(L); |
| 111 | return 1; | 149 | return 1; |
| @@ -121,6 +159,11 @@ LJLIB_CF(ffi_meta___newindex) LJLIB_REC(cdata_index 1) | |||
| 121 | if (!(o+2 < L->top && tviscdata(o))) /* Also checks for key and value. */ | 159 | if (!(o+2 < L->top && tviscdata(o))) /* Also checks for key and value. */ |
| 122 | lj_err_argt(L, 1, LUA_TCDATA); | 160 | lj_err_argt(L, 1, LUA_TCDATA); |
| 123 | ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual); | 161 | ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual); |
| 162 | if ((qual & 1)) { | ||
| 163 | if ((qual & CTF_CONST)) | ||
| 164 | lj_err_caller(L, LJ_ERR_FFI_WRCONST); | ||
| 165 | return ffi_index_meta(L, cts, ct, MM_newindex); | ||
| 166 | } | ||
| 124 | lj_cdata_set(cts, ct, p, o+2, qual); | 167 | lj_cdata_set(cts, ct, p, o+2, qual); |
| 125 | return 0; | 168 | return 0; |
| 126 | } | 169 | } |
| @@ -138,7 +181,7 @@ LJLIB_CF(ffi_meta___eq) LJLIB_REC(cdata_arith MM_eq) | |||
| 138 | return ffi_arith(L); | 181 | return ffi_arith(L); |
| 139 | } | 182 | } |
| 140 | 183 | ||
| 141 | LJLIB_CF(ffi_meta___len) | 184 | LJLIB_CF(ffi_meta___len) LJLIB_REC(cdata_arith MM_len) |
| 142 | { | 185 | { |
| 143 | return ffi_arith(L); | 186 | return ffi_arith(L); |
| 144 | } | 187 | } |
| @@ -153,11 +196,21 @@ LJLIB_CF(ffi_meta___le) LJLIB_REC(cdata_arith MM_le) | |||
| 153 | return ffi_arith(L); | 196 | return ffi_arith(L); |
| 154 | } | 197 | } |
| 155 | 198 | ||
| 156 | LJLIB_CF(ffi_meta___concat) | 199 | LJLIB_CF(ffi_meta___concat) LJLIB_REC(cdata_arith MM_concat) |
| 157 | { | 200 | { |
| 158 | return ffi_arith(L); | 201 | return ffi_arith(L); |
| 159 | } | 202 | } |
| 160 | 203 | ||
| 204 | /* Handle ctype __call metamethod. */ | ||
| 205 | static int ffi_call_meta(lua_State *L, CTypeID id) | ||
| 206 | { | ||
| 207 | CTState *cts = ctype_cts(L); | ||
| 208 | cTValue *tv = lj_ctype_meta(cts, id, MM_call); | ||
| 209 | if (!tv) | ||
| 210 | lj_err_callerv(L, LJ_ERR_FFI_BADCALL, strdata(lj_ctype_repr(L, id, NULL))); | ||
| 211 | return lj_meta_tailcall(L, tv); | ||
| 212 | } | ||
| 213 | |||
| 161 | /* Forward declaration. */ | 214 | /* Forward declaration. */ |
| 162 | static int lj_cf_ffi_new(lua_State *L); | 215 | static int lj_cf_ffi_new(lua_State *L); |
| 163 | 216 | ||
| @@ -168,8 +221,7 @@ LJLIB_CF(ffi_meta___call) LJLIB_REC(cdata_call) | |||
| 168 | if (cd->typeid == CTID_CTYPEID) | 221 | if (cd->typeid == CTID_CTYPEID) |
| 169 | return lj_cf_ffi_new(L); | 222 | return lj_cf_ffi_new(L); |
| 170 | if ((ret = lj_ccall_func(L, cd)) < 0) | 223 | if ((ret = lj_ccall_func(L, cd)) < 0) |
| 171 | lj_err_callerv(L, LJ_ERR_FFI_BADCALL, | 224 | return ffi_call_meta(L, cd->typeid); |
| 172 | strdata(lj_ctype_repr(L, cd->typeid, NULL))); | ||
| 173 | return ret; | 225 | return ret; |
| 174 | } | 226 | } |
| 175 | 227 | ||
| @@ -226,6 +278,12 @@ LJLIB_CF(ffi_meta___tostring) | |||
| 226 | setstrV(L, L->top-1, lj_ctype_repr_int64(L, *(uint64_t *)cdataptr(cd), | 278 | setstrV(L, L->top-1, lj_ctype_repr_int64(L, *(uint64_t *)cdataptr(cd), |
| 227 | (ct->info & CTF_UNSIGNED))); | 279 | (ct->info & CTF_UNSIGNED))); |
| 228 | goto checkgc; | 280 | goto checkgc; |
| 281 | } else if (ctype_isstruct(ct->info) || ctype_isvector(ct->info)) { | ||
| 282 | /* Handle ctype __tostring metamethod. */ | ||
| 283 | CTState *cts = ctype_cts(L); | ||
| 284 | cTValue *tv = lj_ctype_meta(cts, id, MM_tostring); | ||
| 285 | if (tv) | ||
| 286 | return lj_meta_tailcall(L, tv); | ||
| 229 | } | 287 | } |
| 230 | } | 288 | } |
| 231 | lj_str_pushf(L, msg, strdata(lj_ctype_repr(L, id, NULL)), cdataptr(cd)); | 289 | lj_str_pushf(L, msg, strdata(lj_ctype_repr(L, id, NULL)), cdataptr(cd)); |
| @@ -234,6 +292,8 @@ checkgc: | |||
| 234 | return 1; | 292 | return 1; |
| 235 | } | 293 | } |
| 236 | 294 | ||
| 295 | LJLIB_PUSH("ffi") LJLIB_SET(__metatable) | ||
| 296 | |||
| 237 | #include "lj_libdef.h" | 297 | #include "lj_libdef.h" |
| 238 | 298 | ||
| 239 | /* -- C library metamethods ----------------------------------------------- */ | 299 | /* -- C library metamethods ----------------------------------------------- */ |
| @@ -331,14 +391,14 @@ LJLIB_CF(ffi_new) LJLIB_REC(.) | |||
| 331 | { | 391 | { |
| 332 | CTState *cts = ctype_cts(L); | 392 | CTState *cts = ctype_cts(L); |
| 333 | CTypeID id = ffi_checkctype(L, cts); | 393 | CTypeID id = ffi_checkctype(L, cts); |
| 394 | CType *ct = ctype_raw(cts, id); | ||
| 334 | CTSize sz; | 395 | CTSize sz; |
| 335 | CTInfo info = lj_ctype_info(cts, id, &sz); | 396 | CTInfo info = lj_ctype_info(cts, id, &sz); |
| 336 | TValue *o = L->base+1; | 397 | TValue *o = L->base+1; |
| 337 | GCcdata *cd; | 398 | GCcdata *cd; |
| 338 | if ((info & CTF_VLA)) { | 399 | if ((info & CTF_VLA)) { |
| 339 | o++; | 400 | o++; |
| 340 | sz = lj_ctype_vlsize(cts, ctype_raw(cts, id), | 401 | sz = lj_ctype_vlsize(cts, ct, (CTSize)ffi_checkint(L, 2)); |
| 341 | (CTSize)ffi_checkint(L, 2)); | ||
| 342 | } | 402 | } |
| 343 | if (sz == CTSIZE_INVALID) | 403 | if (sz == CTSIZE_INVALID) |
| 344 | lj_err_arg(L, 1, LJ_ERR_FFI_INVSIZE); | 404 | lj_err_arg(L, 1, LJ_ERR_FFI_INVSIZE); |
| @@ -347,8 +407,21 @@ LJLIB_CF(ffi_new) LJLIB_REC(.) | |||
| 347 | else | 407 | else |
| 348 | cd = lj_cdata_newv(cts, id, sz, ctype_align(info)); | 408 | cd = lj_cdata_newv(cts, id, sz, ctype_align(info)); |
| 349 | setcdataV(L, o-1, cd); /* Anchor the uninitialized cdata. */ | 409 | setcdataV(L, o-1, cd); /* Anchor the uninitialized cdata. */ |
| 350 | lj_cconv_ct_init(cts, ctype_raw(cts, id), sz, cdataptr(cd), | 410 | lj_cconv_ct_init(cts, ct, sz, cdataptr(cd), |
| 351 | o, (MSize)(L->top - o)); /* Initialize cdata. */ | 411 | o, (MSize)(L->top - o)); /* Initialize cdata. */ |
| 412 | if (ctype_isstruct(ct->info)) { | ||
| 413 | /* Handle ctype __gc metamethod. Use the fast lookup here. */ | ||
| 414 | cTValue *tv = lj_tab_getint(cts->metatype, (int32_t)id); | ||
| 415 | if (tv && tvistab(tv) && (tv = lj_meta_fast(L, tabV(tv), MM_gc))) { | ||
| 416 | GCtab *t = cts->finalizer; | ||
| 417 | if (gcref(t->metatable)) { | ||
| 418 | /* Add to finalizer table, if still enabled. */ | ||
| 419 | copyTV(L, lj_tab_set(L, t, o-1), tv); | ||
| 420 | lj_gc_anybarriert(L, t); | ||
| 421 | cd->marked |= LJ_GC_CDATA_FIN; | ||
| 422 | } | ||
| 423 | } | ||
| 424 | } | ||
| 352 | L->top = o; /* Only return the cdata itself. */ | 425 | L->top = o; /* Only return the cdata itself. */ |
| 353 | lj_gc_check(L); | 426 | lj_gc_check(L); |
| 354 | return 1; | 427 | return 1; |
| @@ -521,7 +594,33 @@ LJLIB_CF(ffi_abi) LJLIB_REC(.) | |||
| 521 | 594 | ||
| 522 | #undef H_ | 595 | #undef H_ |
| 523 | 596 | ||
| 524 | LJLIB_PUSH(top-7) LJLIB_SET(!) /* Store reference to weak table. */ | 597 | LJLIB_PUSH(top-8) LJLIB_SET(!) /* Store reference to metatype table. */ |
| 598 | |||
| 599 | LJLIB_CF(ffi_metatype) | ||
| 600 | { | ||
| 601 | CTState *cts = ctype_cts(L); | ||
| 602 | CTypeID id = ffi_checkctype(L, cts); | ||
| 603 | GCtab *mt = lj_lib_checktab(L, 2); | ||
| 604 | GCtab *t = cts->metatype; | ||
| 605 | CType *ct = ctype_get(cts, id); /* Only allow raw types. */ | ||
| 606 | TValue *tv; | ||
| 607 | GCcdata *cd; | ||
| 608 | if (!(ctype_isstruct(ct->info) || ctype_iscomplex(ct->info) || | ||
| 609 | ctype_isvector(ct->info))) | ||
| 610 | lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE); | ||
| 611 | tv = lj_tab_setint(L, t, (int32_t)id); | ||
| 612 | if (!tvisnil(tv)) | ||
| 613 | lj_err_caller(L, LJ_ERR_PROTMT); | ||
| 614 | settabV(L, tv, mt); | ||
| 615 | lj_gc_anybarriert(L, t); | ||
| 616 | cd = lj_cdata_new(cts, CTID_CTYPEID, 4); | ||
| 617 | *(CTypeID *)cdataptr(cd) = id; | ||
| 618 | setcdataV(L, L->top-1, cd); | ||
| 619 | lj_gc_check(L); | ||
| 620 | return 1; | ||
| 621 | } | ||
| 622 | |||
| 623 | LJLIB_PUSH(top-7) LJLIB_SET(!) /* Store reference to finalizer table. */ | ||
| 525 | 624 | ||
| 526 | LJLIB_CF(ffi_gc) | 625 | LJLIB_CF(ffi_gc) |
| 527 | { | 626 | { |
| @@ -590,6 +689,7 @@ static void ffi_register_module(lua_State *L) | |||
| 590 | LUALIB_API int luaopen_ffi(lua_State *L) | 689 | LUALIB_API int luaopen_ffi(lua_State *L) |
| 591 | { | 690 | { |
| 592 | CTState *cts = lj_ctype_init(L); | 691 | CTState *cts = lj_ctype_init(L); |
| 692 | settabV(L, L->top++, (cts->metatype = lj_tab_new(L, 0, 0))); | ||
| 593 | cts->finalizer = ffi_finalizer(L); | 693 | cts->finalizer = ffi_finalizer(L); |
| 594 | LJ_LIB_REG(L, NULL, ffi_meta); | 694 | LJ_LIB_REG(L, NULL, ffi_meta); |
| 595 | /* NOBARRIER: basemt is a GC root. */ | 695 | /* NOBARRIER: basemt is a GC root. */ |
diff --git a/src/lj_asm.c b/src/lj_asm.c index a69f4461..8e7c98ee 100644 --- a/src/lj_asm.c +++ b/src/lj_asm.c | |||
| @@ -2558,6 +2558,7 @@ static void asm_cnew(ASMState *as, IRIns *ir) | |||
| 2558 | lj_ctype_size(cts, typeid) : (CTSize)IR(ir->op2)->i; | 2558 | lj_ctype_size(cts, typeid) : (CTSize)IR(ir->op2)->i; |
| 2559 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_mem_newgco]; | 2559 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_mem_newgco]; |
| 2560 | IRRef args[2]; | 2560 | IRRef args[2]; |
| 2561 | int gcfin = 0; | ||
| 2561 | lua_assert(sz != CTSIZE_INVALID); | 2562 | lua_assert(sz != CTSIZE_INVALID); |
| 2562 | 2563 | ||
| 2563 | args[0] = ASMREF_L; /* lua_State *L */ | 2564 | args[0] = ASMREF_L; /* lua_State *L */ |
| @@ -2604,12 +2605,15 @@ static void asm_cnew(ASMState *as, IRIns *ir) | |||
| 2604 | } while (1); | 2605 | } while (1); |
| 2605 | #endif | 2606 | #endif |
| 2606 | lua_assert(sz == 4 || (sz == 8 && (LJ_64 || LJ_HASFFI))); | 2607 | lua_assert(sz == 4 || (sz == 8 && (LJ_64 || LJ_HASFFI))); |
| 2608 | } else { | ||
| 2609 | if (lj_ctype_meta(cts, typeid, MM_gc) != NULL) | ||
| 2610 | gcfin = LJ_GC_CDATA_FIN; | ||
| 2607 | } | 2611 | } |
| 2608 | 2612 | ||
| 2609 | /* Combine initialization of marked, gct and typeid. */ | 2613 | /* Combine initialization of marked, gct and typeid. */ |
| 2610 | emit_movtomro(as, RID_ECX, RID_RET, offsetof(GCcdata, marked)); | 2614 | emit_movtomro(as, RID_ECX, RID_RET, offsetof(GCcdata, marked)); |
| 2611 | emit_gri(as, XG_ARITHi(XOg_OR), RID_ECX, | 2615 | emit_gri(as, XG_ARITHi(XOg_OR), RID_ECX, |
| 2612 | (int32_t)((~LJ_TCDATA<<8)+(typeid<<16))); | 2616 | (int32_t)((~LJ_TCDATA<<8)+(typeid<<16)+gcfin)); |
| 2613 | emit_gri(as, XG_ARITHi(XOg_AND), RID_ECX, LJ_GC_WHITES); | 2617 | emit_gri(as, XG_ARITHi(XOg_AND), RID_ECX, LJ_GC_WHITES); |
| 2614 | emit_opgl(as, XO_MOVZXb, RID_ECX, gc.currentwhite); | 2618 | emit_opgl(as, XO_MOVZXb, RID_ECX, gc.currentwhite); |
| 2615 | 2619 | ||
diff --git a/src/lj_carith.c b/src/lj_carith.c index a59665d8..8f644d83 100644 --- a/src/lj_carith.c +++ b/src/lj_carith.c | |||
| @@ -9,6 +9,8 @@ | |||
| 9 | 9 | ||
| 10 | #include "lj_gc.h" | 10 | #include "lj_gc.h" |
| 11 | #include "lj_err.h" | 11 | #include "lj_err.h" |
| 12 | #include "lj_tab.h" | ||
| 13 | #include "lj_meta.h" | ||
| 12 | #include "lj_ctype.h" | 14 | #include "lj_ctype.h" |
| 13 | #include "lj_cconv.h" | 15 | #include "lj_cconv.h" |
| 14 | #include "lj_cdata.h" | 16 | #include "lj_cdata.h" |
| @@ -187,24 +189,20 @@ static int carith_int64(lua_State *L, CTState *cts, CDArith *ca, MMS mm) | |||
| 187 | return 0; | 189 | return 0; |
| 188 | } | 190 | } |
| 189 | 191 | ||
| 190 | /* Arithmetic operators for cdata. */ | 192 | /* Handle ctype arithmetic metamethods. */ |
| 191 | int lj_carith_op(lua_State *L, MMS mm) | 193 | static int lj_carith_meta(lua_State *L, CTState *cts, CDArith *ca, MMS mm) |
| 192 | { | 194 | { |
| 193 | CTState *cts = ctype_cts(L); | 195 | cTValue *tv = NULL; |
| 194 | CDArith ca; | 196 | if (tviscdata(L->base)) |
| 195 | if (carith_checkarg(L, cts, &ca)) { | 197 | tv = lj_ctype_meta(cts, cdataV(L->base)->typeid, mm); |
| 196 | if (carith_int64(L, cts, &ca, mm) || carith_ptr(L, cts, &ca, mm)) { | 198 | if (!tv && L->base+1 < L->top && tviscdata(L->base+1)) |
| 197 | copyTV(L, &G(L)->tmptv2, L->top-1); /* Remember for trace recorder. */ | 199 | tv = lj_ctype_meta(cts, cdataV(L->base+1)->typeid, mm); |
| 198 | return 1; | 200 | if (!tv) { |
| 199 | } | ||
| 200 | } | ||
| 201 | /* NYI: per-cdata metamethods. */ | ||
| 202 | { | ||
| 203 | const char *repr[2]; | 201 | const char *repr[2]; |
| 204 | int i; | 202 | int i; |
| 205 | for (i = 0; i < 2; i++) { | 203 | for (i = 0; i < 2; i++) { |
| 206 | if (ca.ct[i]) | 204 | if (ca->ct[i]) |
| 207 | repr[i] = strdata(lj_ctype_repr(L, ctype_typeid(cts, ca.ct[i]), NULL)); | 205 | repr[i] = strdata(lj_ctype_repr(L, ctype_typeid(cts, ca->ct[i]), NULL)); |
| 208 | else | 206 | else |
| 209 | repr[i] = typename(&L->base[i]); | 207 | repr[i] = typename(&L->base[i]); |
| 210 | } | 208 | } |
| @@ -213,7 +211,21 @@ int lj_carith_op(lua_State *L, MMS mm) | |||
| 213 | mm < MM_add ? LJ_ERR_FFI_BADCOMP : LJ_ERR_FFI_BADARITH, | 211 | mm < MM_add ? LJ_ERR_FFI_BADCOMP : LJ_ERR_FFI_BADARITH, |
| 214 | repr[0], repr[1]); | 212 | repr[0], repr[1]); |
| 215 | } | 213 | } |
| 216 | return 0; /* unreachable */ | 214 | return lj_meta_tailcall(L, tv); |
| 215 | } | ||
| 216 | |||
| 217 | /* Arithmetic operators for cdata. */ | ||
| 218 | int lj_carith_op(lua_State *L, MMS mm) | ||
| 219 | { | ||
| 220 | CTState *cts = ctype_cts(L); | ||
| 221 | CDArith ca; | ||
| 222 | if (carith_checkarg(L, cts, &ca)) { | ||
| 223 | if (carith_int64(L, cts, &ca, mm) || carith_ptr(L, cts, &ca, mm)) { | ||
| 224 | copyTV(L, &G(L)->tmptv2, L->top-1); /* Remember for trace recorder. */ | ||
| 225 | return 1; | ||
| 226 | } | ||
| 227 | } | ||
| 228 | return lj_carith_meta(L, cts, &ca, mm); | ||
| 217 | } | 229 | } |
| 218 | 230 | ||
| 219 | /* -- 64 bit integer arithmetic helpers ----------------------------------- */ | 231 | /* -- 64 bit integer arithmetic helpers ----------------------------------- */ |
diff --git a/src/lj_cdata.c b/src/lj_cdata.c index 11c84d8e..53605e7e 100644 --- a/src/lj_cdata.c +++ b/src/lj_cdata.c | |||
| @@ -129,13 +129,7 @@ collect_attrib: | |||
| 129 | } | 129 | } |
| 130 | } else if (tvisstr(key)) { /* String key. */ | 130 | } else if (tvisstr(key)) { /* String key. */ |
| 131 | GCstr *name = strV(key); | 131 | GCstr *name = strV(key); |
| 132 | if (ctype_isptr(ct->info)) { /* Automatically perform '->'. */ | 132 | if (ctype_isstruct(ct->info)) { |
| 133 | if (ctype_isstruct(ctype_rawchild(cts, ct)->info)) { | ||
| 134 | p = (uint8_t *)cdata_getptr(p, ct->size); | ||
| 135 | ct = ctype_child(cts, ct); | ||
| 136 | goto collect_attrib; | ||
| 137 | } | ||
| 138 | } if (ctype_isstruct(ct->info)) { | ||
| 139 | CTSize ofs; | 133 | CTSize ofs; |
| 140 | CType *fct = lj_ctype_getfield(cts, ct, name, &ofs); | 134 | CType *fct = lj_ctype_getfield(cts, ct, name, &ofs); |
| 141 | if (fct) { | 135 | if (fct) { |
| @@ -155,7 +149,7 @@ collect_attrib: | |||
| 155 | } | 149 | } |
| 156 | } else if (cd->typeid == CTID_CTYPEID) { | 150 | } else if (cd->typeid == CTID_CTYPEID) { |
| 157 | /* Allow indexing a (pointer to) struct constructor to get constants. */ | 151 | /* Allow indexing a (pointer to) struct constructor to get constants. */ |
| 158 | CType *sct = ct = ctype_raw(cts, *(CTypeID *)p); | 152 | CType *sct = ctype_raw(cts, *(CTypeID *)p); |
| 159 | if (ctype_isptr(sct->info)) | 153 | if (ctype_isptr(sct->info)) |
| 160 | sct = ctype_rawchild(cts, sct); | 154 | sct = ctype_rawchild(cts, sct); |
| 161 | if (ctype_isstruct(sct->info)) { | 155 | if (ctype_isstruct(sct->info)) { |
| @@ -165,16 +159,16 @@ collect_attrib: | |||
| 165 | return fct; | 159 | return fct; |
| 166 | } | 160 | } |
| 167 | } | 161 | } |
| 168 | { | ||
| 169 | GCstr *s = lj_ctype_repr(cts->L, ctype_typeid(cts, ct), NULL); | ||
| 170 | lj_err_callerv(cts->L, LJ_ERR_FFI_BADMEMBER, strdata(s), strdata(name)); | ||
| 171 | } | ||
| 172 | } | 162 | } |
| 173 | { | 163 | if (ctype_isptr(ct->info)) { /* Automatically perform '->'. */ |
| 174 | GCstr *s = lj_ctype_repr(cts->L, ctype_typeid(cts, ct), NULL); | 164 | if (ctype_isstruct(ctype_rawchild(cts, ct)->info)) { |
| 175 | lj_err_callerv(cts->L, LJ_ERR_FFI_BADIDX, strdata(s)); | 165 | p = (uint8_t *)cdata_getptr(p, ct->size); |
| 166 | ct = ctype_child(cts, ct); | ||
| 167 | goto collect_attrib; | ||
| 168 | } | ||
| 176 | } | 169 | } |
| 177 | return NULL; /* unreachable */ | 170 | *qual |= 1; /* Lookup failed. */ |
| 171 | return ct; /* But return the resolved raw type. */ | ||
| 178 | } | 172 | } |
| 179 | 173 | ||
| 180 | /* -- C data getters ------------------------------------------------------ */ | 174 | /* -- C data getters ------------------------------------------------------ */ |
diff --git a/src/lj_crecord.c b/src/lj_crecord.c index 0c4f5ca4..04c962d5 100644 --- a/src/lj_crecord.c +++ b/src/lj_crecord.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include "lj_jit.h" | 22 | #include "lj_jit.h" |
| 23 | #include "lj_iropt.h" | 23 | #include "lj_iropt.h" |
| 24 | #include "lj_trace.h" | 24 | #include "lj_trace.h" |
| 25 | #include "lj_record.h" | ||
| 25 | #include "lj_ffrecord.h" | 26 | #include "lj_ffrecord.h" |
| 26 | #include "lj_crecord.h" | 27 | #include "lj_crecord.h" |
| 27 | #include "lj_dispatch.h" | 28 | #include "lj_dispatch.h" |
| @@ -459,6 +460,41 @@ static TRef crec_reassoc_ofs(jit_State *J, TRef tr, ptrdiff_t *ofsp, MSize sz) | |||
| 459 | return tr; | 460 | return tr; |
| 460 | } | 461 | } |
| 461 | 462 | ||
| 463 | /* Record ctype __index/__newindex metamethods. */ | ||
| 464 | static void crec_index_meta(jit_State *J, CTState *cts, CType *ct, | ||
| 465 | RecordFFData *rd) | ||
| 466 | { | ||
| 467 | CTypeID id = ctype_typeid(cts, ct); | ||
| 468 | cTValue *tv = lj_ctype_meta(cts, id, rd->data ? MM_newindex : MM_index); | ||
| 469 | if (!tv) | ||
| 470 | lj_trace_err(J, LJ_TRERR_BADTYPE); | ||
| 471 | if (tvisfunc(tv)) { | ||
| 472 | J->base[-1] = lj_ir_kfunc(J, funcV(tv)) | TREF_FRAME; | ||
| 473 | rd->nres = -1; /* Pending tailcall. */ | ||
| 474 | } else if (rd->data == 0 && tvistab(tv) && tref_isstr(J->base[1])) { | ||
| 475 | /* Specialize to result of __index lookup. */ | ||
| 476 | cTValue *o = lj_tab_get(J->L, tabV(tv), &rd->argv[1]); | ||
| 477 | IRType t = itype2irt(o); | ||
| 478 | if (tvisgcv(o)) | ||
| 479 | J->base[0] = lj_ir_kgc(J, gcV(o), t); | ||
| 480 | else if (tvisint(o)) | ||
| 481 | J->base[0] = lj_ir_kint(J, intV(o)); | ||
| 482 | else if (tvisnum(o)) | ||
| 483 | J->base[0] = lj_ir_knumint(J, numV(o)); | ||
| 484 | else if (tvisbool(o)) | ||
| 485 | J->base[0] = TREF_PRI(t); | ||
| 486 | else | ||
| 487 | lj_trace_err(J, LJ_TRERR_BADTYPE); | ||
| 488 | /* Always specialize to the key. */ | ||
| 489 | emitir(IRTG(IR_EQ, IRT_STR), J->base[1], lj_ir_kstr(J, strV(&rd->argv[1]))); | ||
| 490 | } else { | ||
| 491 | /* NYI: resolving of non-function metamethods. */ | ||
| 492 | /* NYI: non-string keys for __index table. */ | ||
| 493 | /* NYI: stores to __newindex table. */ | ||
| 494 | lj_trace_err(J, LJ_TRERR_BADTYPE); | ||
| 495 | } | ||
| 496 | } | ||
| 497 | |||
| 462 | void LJ_FASTCALL recff_cdata_index(jit_State *J, RecordFFData *rd) | 498 | void LJ_FASTCALL recff_cdata_index(jit_State *J, RecordFFData *rd) |
| 463 | { | 499 | { |
| 464 | TRef idx, ptr = J->base[0]; | 500 | TRef idx, ptr = J->base[0]; |
| @@ -477,12 +513,13 @@ void LJ_FASTCALL recff_cdata_index(jit_State *J, RecordFFData *rd) | |||
| 477 | ptr = crec_reassoc_ofs(J, ptr, &ofs, 1); | 513 | ptr = crec_reassoc_ofs(J, ptr, &ofs, 1); |
| 478 | } | 514 | } |
| 479 | 515 | ||
| 516 | again: | ||
| 480 | idx = J->base[1]; | 517 | idx = J->base[1]; |
| 481 | if (tref_isnumber(idx)) { | 518 | if (tref_isnumber(idx)) { |
| 482 | idx = lj_opt_narrow_cindex(J, idx); | 519 | idx = lj_opt_narrow_cindex(J, idx); |
| 483 | integer_key: | ||
| 484 | if (ctype_ispointer(ct->info)) { | 520 | if (ctype_ispointer(ct->info)) { |
| 485 | CTSize sz; | 521 | CTSize sz; |
| 522 | integer_key: | ||
| 486 | if ((ct->info & CTF_COMPLEX)) | 523 | if ((ct->info & CTF_COMPLEX)) |
| 487 | idx = emitir(IRT(IR_BAND, IRT_INTP), idx, lj_ir_kintp(J, 1)); | 524 | idx = emitir(IRT(IR_BAND, IRT_INTP), idx, lj_ir_kintp(J, 1)); |
| 488 | sz = lj_ctype_size(cts, (sid = ctype_cid(ct->info))); | 525 | sz = lj_ctype_size(cts, (sid = ctype_cid(ct->info))); |
| @@ -495,7 +532,8 @@ void LJ_FASTCALL recff_cdata_index(jit_State *J, RecordFFData *rd) | |||
| 495 | CType *ctk = ctype_raw(cts, cdk->typeid); | 532 | CType *ctk = ctype_raw(cts, cdk->typeid); |
| 496 | IRType t; | 533 | IRType t; |
| 497 | if (ctype_isenum(ctk->info)) ctk = ctype_child(cts, ctk); | 534 | if (ctype_isenum(ctk->info)) ctk = ctype_child(cts, ctk); |
| 498 | if (ctype_isinteger(ctk->info) && (t = crec_ct2irt(ctk)) != IRT_CDATA) { | 535 | if (ctype_ispointer(ct->info) && |
| 536 | ctype_isinteger(ctk->info) && (t = crec_ct2irt(ctk)) != IRT_CDATA) { | ||
| 499 | if (ctk->size == 8) { | 537 | if (ctk->size == 8) { |
| 500 | idx = emitir(IRT(IR_FLOAD, t), idx, IRFL_CDATA_INT64); | 538 | idx = emitir(IRT(IR_FLOAD, t), idx, IRFL_CDATA_INT64); |
| 501 | } else { | 539 | } else { |
| @@ -513,22 +551,15 @@ void LJ_FASTCALL recff_cdata_index(jit_State *J, RecordFFData *rd) | |||
| 513 | } | 551 | } |
| 514 | } else if (tref_isstr(idx)) { | 552 | } else if (tref_isstr(idx)) { |
| 515 | GCstr *name = strV(&rd->argv[1]); | 553 | GCstr *name = strV(&rd->argv[1]); |
| 516 | /* Always specialize to the field name. */ | ||
| 517 | emitir(IRTG(IR_EQ, IRT_STR), idx, lj_ir_kstr(J, name)); | ||
| 518 | if (cd->typeid == CTID_CTYPEID) | 554 | if (cd->typeid == CTID_CTYPEID) |
| 519 | ct = ctype_raw(cts, crec_constructor(J, cd, ptr)); | 555 | ct = ctype_raw(cts, crec_constructor(J, cd, ptr)); |
| 520 | if (ctype_isptr(ct->info)) { /* Automatically perform '->'. */ | 556 | if (ctype_isstruct(ct->info)) { |
| 521 | CType *cct = ctype_rawchild(cts, ct); | ||
| 522 | if (ctype_isstruct(cct->info)) { | ||
| 523 | ct = cct; | ||
| 524 | goto index_struct; | ||
| 525 | } | ||
| 526 | } else if (ctype_isstruct(ct->info)) { | ||
| 527 | CTSize fofs; | 557 | CTSize fofs; |
| 528 | CType *fct; | 558 | CType *fct; |
| 529 | index_struct: | ||
| 530 | fct = lj_ctype_getfield(cts, ct, name, &fofs); | 559 | fct = lj_ctype_getfield(cts, ct, name, &fofs); |
| 531 | if (fct) { | 560 | if (fct) { |
| 561 | /* Always specialize to the field name. */ | ||
| 562 | emitir(IRTG(IR_EQ, IRT_STR), idx, lj_ir_kstr(J, name)); | ||
| 532 | if (ctype_isconstval(fct->info)) { | 563 | if (ctype_isconstval(fct->info)) { |
| 533 | if (fct->size >= 0x80000000u && | 564 | if (fct->size >= 0x80000000u && |
| 534 | (ctype_child(cts, fct)->info & CTF_UNSIGNED)) { | 565 | (ctype_child(cts, fct)->info & CTF_UNSIGNED)) { |
| @@ -546,11 +577,26 @@ index_struct: | |||
| 546 | ofs += (ptrdiff_t)fofs; | 577 | ofs += (ptrdiff_t)fofs; |
| 547 | } | 578 | } |
| 548 | } else if (ctype_iscomplex(ct->info)) { | 579 | } else if (ctype_iscomplex(ct->info)) { |
| 549 | if (strdata(name)[0] == 'i') ofs += (ct->size >> 1); | 580 | if (name->len == 2 && |
| 550 | sid = ctype_cid(ct->info); | 581 | ((strdata(name)[0] == 'r' && strdata(name)[1] == 'e') || |
| 582 | (strdata(name)[0] == 'i' && strdata(name)[1] == 'm'))) { | ||
| 583 | /* Always specialize to the field name. */ | ||
| 584 | emitir(IRTG(IR_EQ, IRT_STR), idx, lj_ir_kstr(J, name)); | ||
| 585 | if (strdata(name)[0] == 'i') ofs += (ct->size >> 1); | ||
| 586 | sid = ctype_cid(ct->info); | ||
| 587 | } | ||
| 551 | } | 588 | } |
| 552 | } | 589 | } |
| 553 | if (!sid) lj_trace_err(J, LJ_TRERR_BADTYPE); | 590 | if (!sid) { |
| 591 | if (ctype_isptr(ct->info)) { /* Automatically perform '->'. */ | ||
| 592 | CType *cct = ctype_rawchild(cts, ct); | ||
| 593 | if (ctype_isstruct(cct->info)) { | ||
| 594 | ct = cct; | ||
| 595 | if (tref_isstr(idx)) goto again; | ||
| 596 | } | ||
| 597 | } | ||
| 598 | return crec_index_meta(J, cts, ct, rd); | ||
| 599 | } | ||
| 554 | 600 | ||
| 555 | if (ofs) | 601 | if (ofs) |
| 556 | ptr = emitir(IRT(IR_ADD, IRT_PTR), ptr, lj_ir_kintp(J, ofs)); | 602 | ptr = emitir(IRT(IR_ADD, IRT_PTR), ptr, lj_ir_kintp(J, ofs)); |
| @@ -592,6 +638,7 @@ static void crec_alloc(jit_State *J, RecordFFData *rd, CTypeID id) | |||
| 592 | J->base[0] = emitir(IRTG(IR_CNEWI, IRT_CDATA), trid, sp); | 638 | J->base[0] = emitir(IRTG(IR_CNEWI, IRT_CDATA), trid, sp); |
| 593 | } else { | 639 | } else { |
| 594 | TRef trcd = emitir(IRTG(IR_CNEW, IRT_CDATA), trid, TREF_NIL); | 640 | TRef trcd = emitir(IRTG(IR_CNEW, IRT_CDATA), trid, TREF_NIL); |
| 641 | cTValue *fin; | ||
| 595 | J->base[0] = trcd; | 642 | J->base[0] = trcd; |
| 596 | if (J->base[1] && !J->base[2] && !lj_cconv_multi_init(d, &rd->argv[1])) { | 643 | if (J->base[1] && !J->base[2] && !lj_cconv_multi_init(d, &rd->argv[1])) { |
| 597 | goto single_init; | 644 | goto single_init; |
| @@ -660,6 +707,24 @@ static void crec_alloc(jit_State *J, RecordFFData *rd, CTypeID id) | |||
| 660 | crec_ct_tv(J, d, dp, lj_ir_kint(J, 0), &tv); | 707 | crec_ct_tv(J, d, dp, lj_ir_kint(J, 0), &tv); |
| 661 | } | 708 | } |
| 662 | } | 709 | } |
| 710 | /* Handle __gc metamethod. */ | ||
| 711 | fin = lj_ctype_meta(cts, id, MM_gc); | ||
| 712 | if (fin) { | ||
| 713 | RecordIndex ix; | ||
| 714 | ix.idxchain = 0; | ||
| 715 | settabV(J->L, &ix.tabv, cts->finalizer); | ||
| 716 | ix.tab = lj_ir_ktab(J, cts->finalizer); | ||
| 717 | setboolV(&ix.keyv, 0); /* The key is new. Dummy value is ok here. */ | ||
| 718 | ix.key = trcd; | ||
| 719 | copyTV(J->L, &ix.valv, fin); | ||
| 720 | if (tvisfunc(fin)) | ||
| 721 | ix.val = lj_ir_kfunc(J, funcV(fin)); | ||
| 722 | else if (tviscdata(fin)) | ||
| 723 | ix.val = lj_ir_kgc(J, obj2gco(cdataV(fin)), IRT_CDATA); | ||
| 724 | else | ||
| 725 | lj_trace_err(J, LJ_TRERR_BADTYPE); | ||
| 726 | lj_record_idx(J, &ix); | ||
| 727 | } | ||
| 663 | } | 728 | } |
| 664 | } | 729 | } |
| 665 | 730 | ||
| @@ -849,6 +914,27 @@ static TRef crec_arith_ptr(jit_State *J, TRef *sp, CType **s, MMS mm) | |||
| 849 | } | 914 | } |
| 850 | } | 915 | } |
| 851 | 916 | ||
| 917 | /* Record ctype arithmetic metamethods. */ | ||
| 918 | static void crec_arith_meta(jit_State *J, CTState *cts, RecordFFData *rd) | ||
| 919 | { | ||
| 920 | cTValue *tv = NULL; | ||
| 921 | if (J->base[0]) { | ||
| 922 | if (tviscdata(&rd->argv[0])) | ||
| 923 | tv = lj_ctype_meta(cts, argv2cdata(J, J->base[0], &rd->argv[0])->typeid, | ||
| 924 | (MMS)rd->data); | ||
| 925 | if (!tv && J->base[1] && tviscdata(&rd->argv[1])) | ||
| 926 | tv = lj_ctype_meta(cts, argv2cdata(J, J->base[1], &rd->argv[1])->typeid, | ||
| 927 | (MMS)rd->data); | ||
| 928 | } | ||
| 929 | if (tv && tvisfunc(tv)) { | ||
| 930 | J->base[-1] = lj_ir_kfunc(J, funcV(tv)) | TREF_FRAME; | ||
| 931 | rd->nres = -1; /* Pending tailcall. */ | ||
| 932 | } else { | ||
| 933 | /* NYI: non-function metamethods. */ | ||
| 934 | lj_trace_err(J, LJ_TRERR_BADTYPE); | ||
| 935 | } | ||
| 936 | } | ||
| 937 | |||
| 852 | void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd) | 938 | void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd) |
| 853 | { | 939 | { |
| 854 | CTState *cts = ctype_ctsG(J2G(J)); | 940 | CTState *cts = ctype_ctsG(J2G(J)); |
| @@ -858,7 +944,9 @@ void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd) | |||
| 858 | for (i = 0; i < 2; i++) { | 944 | for (i = 0; i < 2; i++) { |
| 859 | TRef tr = J->base[i]; | 945 | TRef tr = J->base[i]; |
| 860 | CType *ct = ctype_get(cts, CTID_DOUBLE); | 946 | CType *ct = ctype_get(cts, CTID_DOUBLE); |
| 861 | if (tref_iscdata(tr)) { | 947 | if (!tr) { |
| 948 | goto trymeta; | ||
| 949 | } else if (tref_iscdata(tr)) { | ||
| 862 | CTypeID id = argv2cdata(J, tr, &rd->argv[i])->typeid; | 950 | CTypeID id = argv2cdata(J, tr, &rd->argv[i])->typeid; |
| 863 | ct = ctype_raw(cts, id); | 951 | ct = ctype_raw(cts, id); |
| 864 | if (ctype_isptr(ct->info)) { /* Resolve pointer or reference. */ | 952 | if (ctype_isptr(ct->info)) { /* Resolve pointer or reference. */ |
| @@ -876,11 +964,11 @@ void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd) | |||
| 876 | if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct); | 964 | if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct); |
| 877 | if (ctype_isnum(ct->info)) { | 965 | if (ctype_isnum(ct->info)) { |
| 878 | IRType t = crec_ct2irt(ct); | 966 | IRType t = crec_ct2irt(ct); |
| 879 | if (t == IRT_CDATA) goto err_type; | 967 | if (t == IRT_CDATA) goto trymeta; |
| 880 | if (t == IRT_I64 || t == IRT_U64) lj_needsplit(J); | 968 | if (t == IRT_I64 || t == IRT_U64) lj_needsplit(J); |
| 881 | tr = emitir(IRT(IR_XLOAD, t), tr, 0); | 969 | tr = emitir(IRT(IR_XLOAD, t), tr, 0); |
| 882 | } else if (!(ctype_isptr(ct->info) || ctype_isrefarray(ct->info))) { | 970 | } else if (!(ctype_isptr(ct->info) || ctype_isrefarray(ct->info))) { |
| 883 | goto err_type; | 971 | goto trymeta; |
| 884 | } | 972 | } |
| 885 | } else if (tref_isnil(tr)) { | 973 | } else if (tref_isnil(tr)) { |
| 886 | tr = lj_ir_kptr(J, NULL); | 974 | tr = lj_ir_kptr(J, NULL); |
| @@ -888,7 +976,7 @@ void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd) | |||
| 888 | } else if (tref_isinteger(tr)) { | 976 | } else if (tref_isinteger(tr)) { |
| 889 | ct = ctype_get(cts, CTID_INT32); | 977 | ct = ctype_get(cts, CTID_INT32); |
| 890 | } else if (!tref_isnum(tr)) { | 978 | } else if (!tref_isnum(tr)) { |
| 891 | goto err_type; | 979 | goto trymeta; |
| 892 | } | 980 | } |
| 893 | ok: | 981 | ok: |
| 894 | s[i] = ct; | 982 | s[i] = ct; |
| @@ -896,21 +984,22 @@ void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd) | |||
| 896 | } | 984 | } |
| 897 | { | 985 | { |
| 898 | TRef tr; | 986 | TRef tr; |
| 899 | if (!(tr = crec_arith_int64(J, sp, s, (MMS)rd->data)) && | 987 | if ((tr = crec_arith_int64(J, sp, s, (MMS)rd->data)) || |
| 900 | !(tr = crec_arith_ptr(J, sp, s, (MMS)rd->data))) { | 988 | (tr = crec_arith_ptr(J, sp, s, (MMS)rd->data))) { |
| 901 | err_type: | 989 | J->base[0] = tr; |
| 902 | lj_trace_err(J, LJ_TRERR_BADTYPE); | 990 | /* Fixup cdata comparisons, too. Avoids some cdata escapes. */ |
| 903 | } | 991 | if (J->postproc == LJ_POST_FIXGUARD && frame_iscont(J->L->base-1)) { |
| 904 | /* Fixup cdata comparisons, too. Avoids some cdata escapes. */ | 992 | const BCIns *pc = frame_contpc(J->L->base-1) - 1; |
| 905 | if (J->postproc == LJ_POST_FIXGUARD && frame_iscont(J->L->base-1)) { | 993 | if (bc_op(*pc) <= BC_ISNEP) { |
| 906 | const BCIns *pc = frame_contpc(J->L->base-1) - 1; | 994 | setframe_pc(&J2G(J)->tmptv, pc); |
| 907 | if (bc_op(*pc) <= BC_ISNEP) { | 995 | J2G(J)->tmptv.u32.lo = ((tref_istrue(tr) ^ bc_op(*pc)) & 1); |
| 908 | setframe_pc(&J2G(J)->tmptv, pc); | 996 | J->postproc = LJ_POST_FIXCOMP; |
| 909 | J2G(J)->tmptv.u32.lo = ((tref_istrue(tr) ^ bc_op(*pc)) & 1); | 997 | } |
| 910 | J->postproc = LJ_POST_FIXCOMP; | ||
| 911 | } | 998 | } |
| 999 | } else { | ||
| 1000 | trymeta: | ||
| 1001 | crec_arith_meta(J, cts, rd); | ||
| 912 | } | 1002 | } |
| 913 | J->base[0] = tr; | ||
| 914 | } | 1003 | } |
| 915 | } | 1004 | } |
| 916 | 1005 | ||
diff --git a/src/lj_ctype.c b/src/lj_ctype.c index ae360b54..0b59b48d 100644 --- a/src/lj_ctype.c +++ b/src/lj_ctype.c | |||
| @@ -306,6 +306,22 @@ CTInfo lj_ctype_info(CTState *cts, CTypeID id, CTSize *szp) | |||
| 306 | return qual; | 306 | return qual; |
| 307 | } | 307 | } |
| 308 | 308 | ||
| 309 | /* Get ctype metamethod. */ | ||
| 310 | cTValue *lj_ctype_meta(CTState *cts, CTypeID id, MMS mm) | ||
| 311 | { | ||
| 312 | CType *ct = ctype_get(cts, id); | ||
| 313 | cTValue *tv; | ||
| 314 | while (ctype_isattrib(ct->info)) { | ||
| 315 | id = ctype_cid(ct->info); | ||
| 316 | ct = ctype_get(cts, id); | ||
| 317 | } | ||
| 318 | tv = lj_tab_getint(cts->metatype, (int32_t)id); | ||
| 319 | if (tv && tvistab(tv) && | ||
| 320 | (tv = lj_tab_getstr(tabV(tv), mmname_str(cts->g, mm))) && !tvisnil(tv)) | ||
| 321 | return tv; | ||
| 322 | return NULL; | ||
| 323 | } | ||
| 324 | |||
| 309 | /* -- C type representation ----------------------------------------------- */ | 325 | /* -- C type representation ----------------------------------------------- */ |
| 310 | 326 | ||
| 311 | /* Fixed max. length of a C type representation. */ | 327 | /* Fixed max. length of a C type representation. */ |
diff --git a/src/lj_ctype.h b/src/lj_ctype.h index a45767c2..f7a7121b 100644 --- a/src/lj_ctype.h +++ b/src/lj_ctype.h | |||
| @@ -159,6 +159,7 @@ typedef struct CTState { | |||
| 159 | lua_State *L; /* Lua state (needed for errors and allocations). */ | 159 | lua_State *L; /* Lua state (needed for errors and allocations). */ |
| 160 | global_State *g; /* Global state. */ | 160 | global_State *g; /* Global state. */ |
| 161 | GCtab *finalizer; /* Map of cdata to finalizer. */ | 161 | GCtab *finalizer; /* Map of cdata to finalizer. */ |
| 162 | GCtab *metatype; /* Map of CTypeID to metatable. */ | ||
| 162 | CTypeID1 hash[CTHASH_SIZE]; /* Hash anchors for C type table. */ | 163 | CTypeID1 hash[CTHASH_SIZE]; /* Hash anchors for C type table. */ |
| 163 | } CTState; | 164 | } CTState; |
| 164 | 165 | ||
| @@ -426,6 +427,7 @@ LJ_FUNC CType *lj_ctype_rawref(CTState *cts, CTypeID id); | |||
| 426 | LJ_FUNC CTSize lj_ctype_size(CTState *cts, CTypeID id); | 427 | LJ_FUNC CTSize lj_ctype_size(CTState *cts, CTypeID id); |
| 427 | LJ_FUNC CTSize lj_ctype_vlsize(CTState *cts, CType *ct, CTSize nelem); | 428 | LJ_FUNC CTSize lj_ctype_vlsize(CTState *cts, CType *ct, CTSize nelem); |
| 428 | LJ_FUNC CTInfo lj_ctype_info(CTState *cts, CTypeID id, CTSize *szp); | 429 | LJ_FUNC CTInfo lj_ctype_info(CTState *cts, CTypeID id, CTSize *szp); |
| 430 | LJ_FUNC cTValue *lj_ctype_meta(CTState *cts, CTypeID id, MMS mm); | ||
| 429 | LJ_FUNC GCstr *lj_ctype_repr(lua_State *L, CTypeID id, GCstr *name); | 431 | LJ_FUNC GCstr *lj_ctype_repr(lua_State *L, CTypeID id, GCstr *name); |
| 430 | LJ_FUNC GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned); | 432 | LJ_FUNC GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned); |
| 431 | LJ_FUNC GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size); | 433 | LJ_FUNC GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size); |
