aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/luajit-2.0/src/lj_ccallback.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/luajit-2.0/src/lj_ccallback.c')
-rw-r--r--libraries/luajit-2.0/src/lj_ccallback.c544
1 files changed, 0 insertions, 544 deletions
diff --git a/libraries/luajit-2.0/src/lj_ccallback.c b/libraries/luajit-2.0/src/lj_ccallback.c
deleted file mode 100644
index f347458..0000000
--- a/libraries/luajit-2.0/src/lj_ccallback.c
+++ /dev/null
@@ -1,544 +0,0 @@
1/*
2** FFI C callback handling.
3** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h
4*/
5
6#include "lj_obj.h"
7
8#if LJ_HASFFI
9
10#include "lj_gc.h"
11#include "lj_err.h"
12#include "lj_tab.h"
13#include "lj_state.h"
14#include "lj_frame.h"
15#include "lj_ctype.h"
16#include "lj_cconv.h"
17#include "lj_ccall.h"
18#include "lj_ccallback.h"
19#include "lj_target.h"
20#include "lj_mcode.h"
21#include "lj_vm.h"
22
23/* -- Target-specific handling of callback slots -------------------------- */
24
25#define CALLBACK_MCODE_SIZE (LJ_PAGESIZE * LJ_NUM_CBPAGE)
26
27#if LJ_TARGET_X86ORX64
28
29#define CALLBACK_MCODE_HEAD (LJ_64 ? 8 : 0)
30#define CALLBACK_MCODE_GROUP (-2+1+2+5+(LJ_64 ? 6 : 5))
31
32#define CALLBACK_SLOT2OFS(slot) \
33 (CALLBACK_MCODE_HEAD + CALLBACK_MCODE_GROUP*((slot)/32) + 4*(slot))
34
35static MSize CALLBACK_OFS2SLOT(MSize ofs)
36{
37 MSize group;
38 ofs -= CALLBACK_MCODE_HEAD;
39 group = ofs / (32*4 + CALLBACK_MCODE_GROUP);
40 return (ofs % (32*4 + CALLBACK_MCODE_GROUP))/4 + group*32;
41}
42
43#define CALLBACK_MAX_SLOT \
44 (((CALLBACK_MCODE_SIZE-CALLBACK_MCODE_HEAD)/(CALLBACK_MCODE_GROUP+4*32))*32)
45
46#elif LJ_TARGET_ARM
47
48#define CALLBACK_MCODE_HEAD 32
49#define CALLBACK_SLOT2OFS(slot) (CALLBACK_MCODE_HEAD + 8*(slot))
50#define CALLBACK_OFS2SLOT(ofs) (((ofs)-CALLBACK_MCODE_HEAD)/8)
51#define CALLBACK_MAX_SLOT (CALLBACK_OFS2SLOT(CALLBACK_MCODE_SIZE))
52
53#elif LJ_TARGET_PPC
54
55#define CALLBACK_MCODE_HEAD 24
56#define CALLBACK_SLOT2OFS(slot) (CALLBACK_MCODE_HEAD + 8*(slot))
57#define CALLBACK_OFS2SLOT(ofs) (((ofs)-CALLBACK_MCODE_HEAD)/8)
58#define CALLBACK_MAX_SLOT (CALLBACK_OFS2SLOT(CALLBACK_MCODE_SIZE))
59
60#else
61
62/* Missing support for this architecture. */
63#define CALLBACK_SLOT2OFS(slot) (0*(slot))
64#define CALLBACK_OFS2SLOT(ofs) (0*(ofs))
65#define CALLBACK_MAX_SLOT 0
66
67#endif
68
69/* Convert callback slot number to callback function pointer. */
70static void *callback_slot2ptr(CTState *cts, MSize slot)
71{
72 return (uint8_t *)cts->cb.mcode + CALLBACK_SLOT2OFS(slot);
73}
74
75/* Convert callback function pointer to slot number. */
76MSize lj_ccallback_ptr2slot(CTState *cts, void *p)
77{
78 uintptr_t ofs = (uintptr_t)((uint8_t *)p -(uint8_t *)cts->cb.mcode);
79 if (ofs < CALLBACK_MCODE_SIZE) {
80 MSize slot = CALLBACK_OFS2SLOT((MSize)ofs);
81 if (CALLBACK_SLOT2OFS(slot) == (MSize)ofs)
82 return slot;
83 }
84 return ~0u; /* Not a known callback function pointer. */
85}
86
87/* Initialize machine code for callback function pointers. */
88#if LJ_TARGET_X86ORX64
89static void callback_mcode_init(global_State *g, uint8_t *page)
90{
91 uint8_t *p = page;
92 uint8_t *target = (uint8_t *)(void *)lj_vm_ffi_callback;
93 MSize slot;
94#if LJ_64
95 *(void **)p = target; p += 8;
96#endif
97 for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) {
98 /* mov al, slot; jmp group */
99 *p++ = XI_MOVrib | RID_EAX; *p++ = (uint8_t)slot;
100 if ((slot & 31) == 31 || slot == CALLBACK_MAX_SLOT-1) {
101 /* push ebp/rbp; mov ah, slot>>8; mov ebp, &g. */
102 *p++ = XI_PUSH + RID_EBP;
103 *p++ = XI_MOVrib | (RID_EAX+4); *p++ = (uint8_t)(slot >> 8);
104 *p++ = XI_MOVri | RID_EBP;
105 *(int32_t *)p = i32ptr(g); p += 4;
106#if LJ_64
107 /* jmp [rip-pageofs] where lj_vm_ffi_callback is stored. */
108 *p++ = XI_GROUP5; *p++ = XM_OFS0 + (XOg_JMP<<3) + RID_EBP;
109 *(int32_t *)p = (int32_t)(page-(p+4)); p += 4;
110#else
111 /* jmp lj_vm_ffi_callback. */
112 *p++ = XI_JMP; *(int32_t *)p = target-(p+4); p += 4;
113#endif
114 } else {
115 *p++ = XI_JMPs; *p++ = (uint8_t)((2+2)*(31-(slot&31)) - 2);
116 }
117 }
118 lua_assert(p - page <= CALLBACK_MCODE_SIZE);
119}
120#elif LJ_TARGET_ARM
121static void callback_mcode_init(global_State *g, uint32_t *page)
122{
123 uint32_t *p = page;
124 void *target = (void *)lj_vm_ffi_callback;
125 MSize slot;
126 /* This must match with the saveregs macro in buildvm_arm.dasc. */
127 *p++ = ARMI_SUB|ARMF_D(RID_R12)|ARMF_N(RID_R12)|ARMF_M(RID_PC);
128 *p++ = ARMI_PUSH|ARMF_N(RID_SP)|RSET_RANGE(RID_R4,RID_R11+1)|RID2RSET(RID_LR);
129 *p++ = ARMI_SUB|ARMI_K12|ARMF_D(RID_R12)|ARMF_N(RID_R12)|CALLBACK_MCODE_HEAD;
130 *p++ = ARMI_STR|ARMI_LS_P|ARMI_LS_W|ARMF_D(RID_R12)|ARMF_N(RID_SP)|(CFRAME_SIZE-4*9);
131 *p++ = ARMI_LDR|ARMI_LS_P|ARMI_LS_U|ARMF_D(RID_R12)|ARMF_N(RID_PC);
132 *p++ = ARMI_LDR|ARMI_LS_P|ARMI_LS_U|ARMF_D(RID_PC)|ARMF_N(RID_PC);
133 *p++ = u32ptr(g);
134 *p++ = u32ptr(target);
135 for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) {
136 *p++ = ARMI_MOV|ARMF_D(RID_R12)|ARMF_M(RID_PC);
137 *p = ARMI_B | ((page-p-2) & 0x00ffffffu);
138 p++;
139 }
140 lua_assert(p - page <= CALLBACK_MCODE_SIZE);
141}
142#elif LJ_TARGET_PPC
143static void callback_mcode_init(global_State *g, uint32_t *page)
144{
145 uint32_t *p = page;
146 void *target = (void *)lj_vm_ffi_callback;
147 MSize slot;
148 *p++ = PPCI_LIS | PPCF_T(RID_TMP) | (u32ptr(target) >> 16);
149 *p++ = PPCI_LIS | PPCF_T(RID_R12) | (u32ptr(g) >> 16);
150 *p++ = PPCI_ORI | PPCF_A(RID_TMP)|PPCF_T(RID_TMP) | (u32ptr(target) & 0xffff);
151 *p++ = PPCI_ORI | PPCF_A(RID_R12)|PPCF_T(RID_R12) | (u32ptr(g) & 0xffff);
152 *p++ = PPCI_MTCTR | PPCF_T(RID_TMP);
153 *p++ = PPCI_BCTR;
154 for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) {
155 *p++ = PPCI_LI | PPCF_T(RID_R11) | slot;
156 *p = PPCI_B | (((page-p) & 0x00ffffffu) << 2);
157 p++;
158 }
159 lua_assert(p - page <= CALLBACK_MCODE_SIZE);
160}
161#else
162/* Missing support for this architecture. */
163#define callback_mcode_init(g, p) UNUSED(p)
164#endif
165
166/* -- Machine code management --------------------------------------------- */
167
168#if LJ_TARGET_WINDOWS
169
170#define WIN32_LEAN_AND_MEAN
171#include <windows.h>
172
173#elif LJ_TARGET_POSIX
174
175#include <sys/mman.h>
176#ifndef MAP_ANONYMOUS
177#define MAP_ANONYMOUS MAP_ANON
178#endif
179
180#endif
181
182/* Allocate and initialize area for callback function pointers. */
183static void callback_mcode_new(CTState *cts)
184{
185 size_t sz = (size_t)CALLBACK_MCODE_SIZE;
186 void *p;
187 if (CALLBACK_MAX_SLOT == 0)
188 lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
189#if LJ_TARGET_WINDOWS
190 p = VirtualAlloc(NULL, sz, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
191 if (!p)
192 lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
193#elif LJ_TARGET_POSIX
194 p = mmap(NULL, sz, (PROT_READ|PROT_WRITE), MAP_PRIVATE|MAP_ANONYMOUS,
195 -1, 0);
196 if (p == MAP_FAILED)
197 lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
198#else
199 /* Fallback allocator. Fails if memory is not executable by default. */
200 p = lj_mem_new(cts->L, sz);
201#endif
202 cts->cb.mcode = p;
203 callback_mcode_init(cts->g, p);
204 lj_mcode_sync(p, (char *)p + sz);
205#if LJ_TARGET_WINDOWS
206 {
207 DWORD oprot;
208 VirtualProtect(p, sz, PAGE_EXECUTE_READ, &oprot);
209 }
210#elif LJ_TARGET_POSIX
211 mprotect(p, sz, (PROT_READ|PROT_EXEC));
212#endif
213}
214
215/* Free area for callback function pointers. */
216void lj_ccallback_mcode_free(CTState *cts)
217{
218 size_t sz = (size_t)CALLBACK_MCODE_SIZE;
219 void *p = cts->cb.mcode;
220 if (p == NULL) return;
221#if LJ_TARGET_WINDOWS
222 VirtualFree(p, 0, MEM_RELEASE);
223 UNUSED(sz);
224#elif LJ_TARGET_POSIX
225 munmap(p, sz);
226#else
227 lj_mem_free(cts->g, p, sz);
228#endif
229}
230
231/* -- C callback entry ---------------------------------------------------- */
232
233/* Target-specific handling of register arguments. Similar to lj_ccall.c. */
234#if LJ_TARGET_X86
235
236#define CALLBACK_HANDLE_REGARG \
237 if (!isfp) { /* Only non-FP values may be passed in registers. */ \
238 if (n > 1) { /* Anything > 32 bit is passed on the stack. */ \
239 if (!LJ_ABI_WIN) ngpr = maxgpr; /* Prevent reordering. */ \
240 } else if (ngpr + 1 <= maxgpr) { \
241 sp = &cts->cb.gpr[ngpr]; \
242 ngpr += n; \
243 goto done; \
244 } \
245 }
246
247#elif LJ_TARGET_X64 && LJ_ABI_WIN
248
249/* Windows/x64 argument registers are strictly positional (use ngpr). */
250#define CALLBACK_HANDLE_REGARG \
251 if (isfp) { \
252 if (ngpr < 4) { sp = &cts->cb.fpr[ngpr++]; nfpr = ngpr; goto done; } \
253 } else { \
254 if (ngpr < 4) { sp = &cts->cb.gpr[ngpr++]; goto done; } \
255 }
256
257#elif LJ_TARGET_X64
258
259#define CALLBACK_HANDLE_REGARG \
260 if (isfp) { \
261 if (nfpr + n <= CCALL_NARG_FPR) { \
262 sp = &cts->cb.fpr[nfpr]; \
263 nfpr += n; \
264 goto done; \
265 } \
266 } else { \
267 if (ngpr + n <= maxgpr) { \
268 sp = &cts->cb.gpr[ngpr]; \
269 ngpr += n; \
270 goto done; \
271 } \
272 }
273
274#elif LJ_TARGET_ARM
275
276#define CALLBACK_HANDLE_REGARG \
277 if (n > 1) ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \
278 if (ngpr + n <= maxgpr) { \
279 sp = &cts->cb.gpr[ngpr]; \
280 ngpr += n; \
281 goto done; \
282 }
283
284#elif LJ_TARGET_PPC
285
286#define CALLBACK_HANDLE_REGARG \
287 if (isfp) { \
288 if (nfpr + 1 <= CCALL_NARG_FPR) { \
289 sp = &cts->cb.fpr[nfpr]; \
290 nfpr += 1; \
291 cta = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */ \
292 goto done; \
293 } \
294 } else { /* Try to pass argument in GPRs. */ \
295 if (n > 1) { \
296 lua_assert(ctype_isinteger(cta->info) && n == 2); /* int64_t. */ \
297 ngpr = (ngpr + 1u) & ~1u; /* Align int64_t to regpair. */ \
298 } \
299 if (ngpr + n <= maxgpr) { \
300 sp = &cts->cb.gpr[ngpr]; \
301 ngpr += n; \
302 goto done; \
303 } \
304 }
305
306#define CALLBACK_HANDLE_RET \
307 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
308 *(double *)dp = *(float *)dp; /* FPRs always hold doubles. */
309
310#else
311#error "Missing calling convention definitions for this architecture"
312#endif
313
314/* Convert and push callback arguments to Lua stack. */
315static void callback_conv_args(CTState *cts, lua_State *L)
316{
317 TValue *o = L->top;
318 intptr_t *stack = cts->cb.stack;
319 MSize slot = cts->cb.slot;
320 CTypeID id = 0, rid, fid;
321 CType *ct;
322 GCfunc *fn;
323 MSize ngpr = 0, nsp = 0, maxgpr = CCALL_NARG_GPR;
324#if CCALL_NARG_FPR
325 MSize nfpr = 0;
326#endif
327
328 if (slot < cts->cb.sizeid && (id = cts->cb.cbid[slot]) != 0) {
329 ct = ctype_get(cts, id);
330 rid = ctype_cid(ct->info);
331 fn = funcV(lj_tab_getint(cts->miscmap, (int32_t)slot));
332 } else { /* Must set up frame first, before throwing the error. */
333 ct = NULL;
334 rid = 0;
335 fn = (GCfunc *)L;
336 }
337 o->u32.lo = LJ_CONT_FFI_CALLBACK; /* Continuation returns from callback. */
338 o->u32.hi = rid; /* Return type. x86: +(spadj<<16). */
339 o++;
340 setframe_gc(o, obj2gco(fn));
341 setframe_ftsz(o, (int)((char *)(o+1) - (char *)L->base) + FRAME_CONT);
342 L->top = L->base = ++o;
343 if (!ct)
344 lj_err_caller(cts->L, LJ_ERR_FFI_BADCBACK);
345 if (isluafunc(fn))
346 setcframe_pc(L->cframe, proto_bc(funcproto(fn))+1);
347 lj_state_checkstack(L, LUA_MINSTACK); /* May throw. */
348 o = L->base; /* Might have been reallocated. */
349
350#if LJ_TARGET_X86
351 /* x86 has several different calling conventions. */
352 switch (ctype_cconv(ct->info)) {
353 case CTCC_FASTCALL: maxgpr = 2; break;
354 case CTCC_THISCALL: maxgpr = 1; break;
355 default: maxgpr = 0; break;
356 }
357#endif
358
359 fid = ct->sib;
360 while (fid) {
361 CType *ctf = ctype_get(cts, fid);
362 if (!ctype_isattrib(ctf->info)) {
363 CType *cta;
364 void *sp;
365 CTSize sz;
366 int isfp;
367 MSize n;
368 lua_assert(ctype_isfield(ctf->info));
369 cta = ctype_rawchild(cts, ctf);
370 if (ctype_isenum(cta->info)) cta = ctype_child(cts, cta);
371 isfp = ctype_isfp(cta->info);
372 sz = (cta->size + CTSIZE_PTR-1) & ~(CTSIZE_PTR-1);
373 n = sz / CTSIZE_PTR; /* Number of GPRs or stack slots needed. */
374
375 CALLBACK_HANDLE_REGARG /* Handle register arguments. */
376
377 /* Otherwise pass argument on stack. */
378 if (CCALL_ALIGN_STACKARG && LJ_32 && sz == 8)
379 nsp = (nsp + 1) & ~1u; /* Align 64 bit argument on stack. */
380 sp = &stack[nsp];
381 nsp += n;
382
383 done:
384 if (LJ_BE && cta->size < CTSIZE_PTR)
385 sp = (void *)((uint8_t *)sp + CTSIZE_PTR-cta->size);
386 lj_cconv_tv_ct(cts, cta, 0, o++, sp);
387 }
388 fid = ctf->sib;
389 }
390 L->top = o;
391#if LJ_TARGET_X86
392 /* Store stack adjustment for returns from fastcall/stdcall callbacks. */
393 switch (ctype_cconv(ct->info)) {
394 case CTCC_FASTCALL: case CTCC_STDCALL:
395 (L->base-2)->u32.hi |= (nsp << (16+2));
396 break;
397 }
398#endif
399}
400
401/* Convert Lua object to callback result. */
402static void callback_conv_result(CTState *cts, lua_State *L, TValue *o)
403{
404 CType *ctr = ctype_raw(cts, (uint16_t)(L->base-2)->u32.hi);
405#if LJ_TARGET_X86
406 cts->cb.gpr[2] = 0;
407#endif
408 if (!ctype_isvoid(ctr->info)) {
409 uint8_t *dp = (uint8_t *)&cts->cb.gpr[0];
410#if CCALL_NUM_FPR
411 if (ctype_isfp(ctr->info))
412 dp = (uint8_t *)&cts->cb.fpr[0];
413#endif
414 lj_cconv_ct_tv(cts, ctr, dp, o, 0);
415#ifdef CALLBACK_HANDLE_RET
416 CALLBACK_HANDLE_RET
417#endif
418 /* Extend returned integers to (at least) 32 bits. */
419 if (ctype_isinteger_or_bool(ctr->info) && ctr->size < 4) {
420 if (ctr->info & CTF_UNSIGNED)
421 *(uint32_t *)dp = ctr->size == 1 ? (uint32_t)*(uint8_t *)dp :
422 (uint32_t)*(uint16_t *)dp;
423 else
424 *(int32_t *)dp = ctr->size == 1 ? (int32_t)*(int8_t *)dp :
425 (int32_t)*(int16_t *)dp;
426 }
427#if LJ_TARGET_X86
428 if (ctype_isfp(ctr->info))
429 cts->cb.gpr[2] = ctr->size == sizeof(float) ? 1 : 2;
430#endif
431 }
432}
433
434/* Enter callback. */
435lua_State * LJ_FASTCALL lj_ccallback_enter(CTState *cts, void *cf)
436{
437 lua_State *L = cts->L;
438 lua_assert(L != NULL);
439 if (gcref(cts->g->jit_L))
440 lj_err_caller(gco2th(gcref(cts->g->jit_L)), LJ_ERR_FFI_BADCBACK);
441 /* Setup C frame. */
442 cframe_prev(cf) = L->cframe;
443 setcframe_L(cf, L);
444 cframe_errfunc(cf) = -1;
445 cframe_nres(cf) = 0;
446 L->cframe = cf;
447 callback_conv_args(cts, L);
448 return L; /* Now call the function on this stack. */
449}
450
451/* Leave callback. */
452void LJ_FASTCALL lj_ccallback_leave(CTState *cts, TValue *o)
453{
454 lua_State *L = cts->L;
455 GCfunc *fn;
456 TValue *obase = L->base;
457 L->base = L->top; /* Keep continuation frame for throwing errors. */
458 /* PC of RET* is lost. Point to last line for result conv. errors. */
459 fn = curr_func(L);
460 if (isluafunc(fn)) {
461 GCproto *pt = funcproto(fn);
462 setcframe_pc(L->cframe, proto_bc(pt)+pt->sizebc+1);
463 }
464 callback_conv_result(cts, L, o);
465 /* Finally drop C frame and continuation frame. */
466 L->cframe = cframe_prev(L->cframe);
467 L->top -= 2;
468 L->base = obase;
469}
470
471/* -- C callback management ----------------------------------------------- */
472
473/* Get an unused slot in the callback slot table. */
474static MSize callback_slot_new(CTState *cts, CType *ct)
475{
476 CTypeID id = ctype_typeid(cts, ct);
477 CTypeID1 *cbid = cts->cb.cbid;
478 MSize top;
479 for (top = cts->cb.topid; top < cts->cb.sizeid; top++)
480 if (LJ_LIKELY(cbid[top] == 0))
481 goto found;
482#if CALLBACK_MAX_SLOT
483 if (top >= CALLBACK_MAX_SLOT)
484#endif
485 lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
486 if (!cts->cb.mcode)
487 callback_mcode_new(cts);
488 lj_mem_growvec(cts->L, cbid, cts->cb.sizeid, CALLBACK_MAX_SLOT, CTypeID1);
489 cts->cb.cbid = cbid;
490 memset(cbid+top, 0, (cts->cb.sizeid-top)*sizeof(CTypeID1));
491found:
492 cbid[top] = id;
493 cts->cb.topid = top+1;
494 return top;
495}
496
497/* Check for function pointer and supported argument/result types. */
498static CType *callback_checkfunc(CTState *cts, CType *ct)
499{
500 int narg = 0;
501 if (!ctype_isptr(ct->info) || (LJ_64 && ct->size != CTSIZE_PTR))
502 return NULL;
503 ct = ctype_rawchild(cts, ct);
504 if (ctype_isfunc(ct->info)) {
505 CType *ctr = ctype_rawchild(cts, ct);
506 CTypeID fid = ct->sib;
507 if (!(ctype_isvoid(ctr->info) || ctype_isenum(ctr->info) ||
508 ctype_isptr(ctr->info) || (ctype_isnum(ctr->info) && ctr->size <= 8)))
509 return NULL;
510 if ((ct->info & CTF_VARARG))
511 return NULL;
512 while (fid) {
513 CType *ctf = ctype_get(cts, fid);
514 if (!ctype_isattrib(ctf->info)) {
515 CType *cta;
516 lua_assert(ctype_isfield(ctf->info));
517 cta = ctype_rawchild(cts, ctf);
518 if (!(ctype_isenum(cta->info) || ctype_isptr(cta->info) ||
519 (ctype_isnum(cta->info) && cta->size <= 8)) ||
520 ++narg >= LUA_MINSTACK-3)
521 return NULL;
522 }
523 fid = ctf->sib;
524 }
525 return ct;
526 }
527 return NULL;
528}
529
530/* Create a new callback and return the callback function pointer. */
531void *lj_ccallback_new(CTState *cts, CType *ct, GCfunc *fn)
532{
533 ct = callback_checkfunc(cts, ct);
534 if (ct) {
535 MSize slot = callback_slot_new(cts, ct);
536 GCtab *t = cts->miscmap;
537 setfuncV(cts->L, lj_tab_setint(cts->L, t, (int32_t)slot), fn);
538 lj_gc_anybarriert(cts->L, t);
539 return callback_slot2ptr(cts, slot);
540 }
541 return NULL; /* Bad conversion. */
542}
543
544#endif