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); |