aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMike Pall <mike>2011-04-12 19:15:00 +0200
committerMike Pall <mike>2011-04-12 19:16:39 +0200
commit3b6f37dd2c336987251d53a4678396ef38921b3e (patch)
tree6e6176c37b600e461d078dbe663008dcc84d2418 /src
parentfa5cd010e8e28c7fe2338d0fdd538e95ddd88bcc (diff)
downloadluajit-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.dep13
-rw-r--r--src/lib_ffi.c116
-rw-r--r--src/lj_asm.c6
-rw-r--r--src/lj_carith.c42
-rw-r--r--src/lj_cdata.c26
-rw-r--r--src/lj_crecord.c153
-rw-r--r--src/lj_ctype.c16
-rw-r--r--src/lj_ctype.h2
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 \
21lib_debug.o: lib_debug.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \ 21lib_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
23lib_ffi.o: lib_ffi.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \ 23lib_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
27lib_init.o: lib_init.c lua.h luaconf.h lauxlib.h lualib.h lj_arch.h 27lib_init.o: lib_init.c lua.h luaconf.h lauxlib.h lualib.h lj_arch.h
28lib_io.o: lib_io.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \ 28lib_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 \
57lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \ 57lj_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
59lj_carith.o: lj_carith.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 59lj_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
62lj_ccall.o: lj_ccall.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 62lj_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 \
77lj_crecord.o: lj_crecord.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 77lj_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
81lj_ctype.o: lj_ctype.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 82lj_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
83lj_dispatch.o: lj_dispatch.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 84lj_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. */
101static 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
99LJLIB_CF(ffi_meta___index) LJLIB_REC(cdata_index 0) 135LJLIB_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
141LJLIB_CF(ffi_meta___len) 184LJLIB_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
156LJLIB_CF(ffi_meta___concat) 199LJLIB_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. */
205static 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. */
162static int lj_cf_ffi_new(lua_State *L); 215static 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
295LJLIB_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
524LJLIB_PUSH(top-7) LJLIB_SET(!) /* Store reference to weak table. */ 597LJLIB_PUSH(top-8) LJLIB_SET(!) /* Store reference to metatype table. */
598
599LJLIB_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
623LJLIB_PUSH(top-7) LJLIB_SET(!) /* Store reference to finalizer table. */
525 624
526LJLIB_CF(ffi_gc) 625LJLIB_CF(ffi_gc)
527{ 626{
@@ -590,6 +689,7 @@ static void ffi_register_module(lua_State *L)
590LUALIB_API int luaopen_ffi(lua_State *L) 689LUALIB_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. */
191int lj_carith_op(lua_State *L, MMS mm) 193static 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. */
218int 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. */
464static 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
462void LJ_FASTCALL recff_cdata_index(jit_State *J, RecordFFData *rd) 498void 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
516again:
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;
529index_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. */
918static 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
852void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd) 938void 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. */
310cTValue *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);
426LJ_FUNC CTSize lj_ctype_size(CTState *cts, CTypeID id); 427LJ_FUNC CTSize lj_ctype_size(CTState *cts, CTypeID id);
427LJ_FUNC CTSize lj_ctype_vlsize(CTState *cts, CType *ct, CTSize nelem); 428LJ_FUNC CTSize lj_ctype_vlsize(CTState *cts, CType *ct, CTSize nelem);
428LJ_FUNC CTInfo lj_ctype_info(CTState *cts, CTypeID id, CTSize *szp); 429LJ_FUNC CTInfo lj_ctype_info(CTState *cts, CTypeID id, CTSize *szp);
430LJ_FUNC cTValue *lj_ctype_meta(CTState *cts, CTypeID id, MMS mm);
429LJ_FUNC GCstr *lj_ctype_repr(lua_State *L, CTypeID id, GCstr *name); 431LJ_FUNC GCstr *lj_ctype_repr(lua_State *L, CTypeID id, GCstr *name);
430LJ_FUNC GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned); 432LJ_FUNC GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned);
431LJ_FUNC GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size); 433LJ_FUNC GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size);