aboutsummaryrefslogtreecommitdiff
path: root/src/lj_ccallback.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_ccallback.c')
-rw-r--r--src/lj_ccallback.c280
1 files changed, 216 insertions, 64 deletions
diff --git a/src/lj_ccallback.c b/src/lj_ccallback.c
index 5a6785c6..43e44305 100644
--- a/src/lj_ccallback.c
+++ b/src/lj_ccallback.c
@@ -27,7 +27,7 @@
27 27
28#if LJ_OS_NOJIT 28#if LJ_OS_NOJIT
29 29
30/* Disabled callback support. */ 30/* Callbacks disabled. */
31#define CALLBACK_SLOT2OFS(slot) (0*(slot)) 31#define CALLBACK_SLOT2OFS(slot) (0*(slot))
32#define CALLBACK_OFS2SLOT(ofs) (0*(ofs)) 32#define CALLBACK_OFS2SLOT(ofs) (0*(ofs))
33#define CALLBACK_MAX_SLOT 0 33#define CALLBACK_MAX_SLOT 0
@@ -35,7 +35,7 @@
35#elif LJ_TARGET_X86ORX64 35#elif LJ_TARGET_X86ORX64
36 36
37#define CALLBACK_MCODE_HEAD (LJ_64 ? 8 : 0) 37#define CALLBACK_MCODE_HEAD (LJ_64 ? 8 : 0)
38#define CALLBACK_MCODE_GROUP (-2+1+2+5+(LJ_64 ? 6 : 5)) 38#define CALLBACK_MCODE_GROUP (-2+1+2+(LJ_GC64 ? 10 : 5)+(LJ_64 ? 6 : 5))
39 39
40#define CALLBACK_SLOT2OFS(slot) \ 40#define CALLBACK_SLOT2OFS(slot) \
41 (CALLBACK_MCODE_HEAD + CALLBACK_MCODE_GROUP*((slot)/32) + 4*(slot)) 41 (CALLBACK_MCODE_HEAD + CALLBACK_MCODE_GROUP*((slot)/32) + 4*(slot))
@@ -54,23 +54,22 @@ static MSize CALLBACK_OFS2SLOT(MSize ofs)
54#elif LJ_TARGET_ARM 54#elif LJ_TARGET_ARM
55 55
56#define CALLBACK_MCODE_HEAD 32 56#define CALLBACK_MCODE_HEAD 32
57#define CALLBACK_SLOT2OFS(slot) (CALLBACK_MCODE_HEAD + 8*(slot)) 57
58#define CALLBACK_OFS2SLOT(ofs) (((ofs)-CALLBACK_MCODE_HEAD)/8) 58#elif LJ_TARGET_ARM64
59#define CALLBACK_MAX_SLOT (CALLBACK_OFS2SLOT(CALLBACK_MCODE_SIZE)) 59
60#define CALLBACK_MCODE_HEAD 32
60 61
61#elif LJ_TARGET_PPC 62#elif LJ_TARGET_PPC
62 63
63#define CALLBACK_MCODE_HEAD 24 64#define CALLBACK_MCODE_HEAD 24
64#define CALLBACK_SLOT2OFS(slot) (CALLBACK_MCODE_HEAD + 8*(slot))
65#define CALLBACK_OFS2SLOT(ofs) (((ofs)-CALLBACK_MCODE_HEAD)/8)
66#define CALLBACK_MAX_SLOT (CALLBACK_OFS2SLOT(CALLBACK_MCODE_SIZE))
67 65
68#elif LJ_TARGET_MIPS 66#elif LJ_TARGET_MIPS32
69 67
70#define CALLBACK_MCODE_HEAD 24 68#define CALLBACK_MCODE_HEAD 20
71#define CALLBACK_SLOT2OFS(slot) (CALLBACK_MCODE_HEAD + 8*(slot)) 69
72#define CALLBACK_OFS2SLOT(ofs) (((ofs)-CALLBACK_MCODE_HEAD)/8) 70#elif LJ_TARGET_MIPS64
73#define CALLBACK_MAX_SLOT (CALLBACK_OFS2SLOT(CALLBACK_MCODE_SIZE)) 71
72#define CALLBACK_MCODE_HEAD 52
74 73
75#else 74#else
76 75
@@ -81,6 +80,12 @@ static MSize CALLBACK_OFS2SLOT(MSize ofs)
81 80
82#endif 81#endif
83 82
83#ifndef CALLBACK_SLOT2OFS
84#define CALLBACK_SLOT2OFS(slot) (CALLBACK_MCODE_HEAD + 8*(slot))
85#define CALLBACK_OFS2SLOT(ofs) (((ofs)-CALLBACK_MCODE_HEAD)/8)
86#define CALLBACK_MAX_SLOT (CALLBACK_OFS2SLOT(CALLBACK_MCODE_SIZE))
87#endif
88
84/* Convert callback slot number to callback function pointer. */ 89/* Convert callback slot number to callback function pointer. */
85static void *callback_slot2ptr(CTState *cts, MSize slot) 90static void *callback_slot2ptr(CTState *cts, MSize slot)
86{ 91{
@@ -102,9 +107,9 @@ MSize lj_ccallback_ptr2slot(CTState *cts, void *p)
102/* Initialize machine code for callback function pointers. */ 107/* Initialize machine code for callback function pointers. */
103#if LJ_OS_NOJIT 108#if LJ_OS_NOJIT
104/* Disabled callback support. */ 109/* Disabled callback support. */
105#define callback_mcode_init(g, p) UNUSED(p) 110#define callback_mcode_init(g, p) (p)
106#elif LJ_TARGET_X86ORX64 111#elif LJ_TARGET_X86ORX64
107static void callback_mcode_init(global_State *g, uint8_t *page) 112static void *callback_mcode_init(global_State *g, uint8_t *page)
108{ 113{
109 uint8_t *p = page; 114 uint8_t *p = page;
110 uint8_t *target = (uint8_t *)(void *)lj_vm_ffi_callback; 115 uint8_t *target = (uint8_t *)(void *)lj_vm_ffi_callback;
@@ -119,8 +124,13 @@ static void callback_mcode_init(global_State *g, uint8_t *page)
119 /* push ebp/rbp; mov ah, slot>>8; mov ebp, &g. */ 124 /* push ebp/rbp; mov ah, slot>>8; mov ebp, &g. */
120 *p++ = XI_PUSH + RID_EBP; 125 *p++ = XI_PUSH + RID_EBP;
121 *p++ = XI_MOVrib | (RID_EAX+4); *p++ = (uint8_t)(slot >> 8); 126 *p++ = XI_MOVrib | (RID_EAX+4); *p++ = (uint8_t)(slot >> 8);
127#if LJ_GC64
128 *p++ = 0x48; *p++ = XI_MOVri | RID_EBP;
129 *(uint64_t *)p = (uint64_t)(g); p += 8;
130#else
122 *p++ = XI_MOVri | RID_EBP; 131 *p++ = XI_MOVri | RID_EBP;
123 *(int32_t *)p = i32ptr(g); p += 4; 132 *(int32_t *)p = i32ptr(g); p += 4;
133#endif
124#if LJ_64 134#if LJ_64
125 /* jmp [rip-pageofs] where lj_vm_ffi_callback is stored. */ 135 /* jmp [rip-pageofs] where lj_vm_ffi_callback is stored. */
126 *p++ = XI_GROUP5; *p++ = XM_OFS0 + (XOg_JMP<<3) + RID_EBP; 136 *p++ = XI_GROUP5; *p++ = XM_OFS0 + (XOg_JMP<<3) + RID_EBP;
@@ -133,10 +143,10 @@ static void callback_mcode_init(global_State *g, uint8_t *page)
133 *p++ = XI_JMPs; *p++ = (uint8_t)((2+2)*(31-(slot&31)) - 2); 143 *p++ = XI_JMPs; *p++ = (uint8_t)((2+2)*(31-(slot&31)) - 2);
134 } 144 }
135 } 145 }
136 lua_assert(p - page <= CALLBACK_MCODE_SIZE); 146 return p;
137} 147}
138#elif LJ_TARGET_ARM 148#elif LJ_TARGET_ARM
139static void callback_mcode_init(global_State *g, uint32_t *page) 149static void *callback_mcode_init(global_State *g, uint32_t *page)
140{ 150{
141 uint32_t *p = page; 151 uint32_t *p = page;
142 void *target = (void *)lj_vm_ffi_callback; 152 void *target = (void *)lj_vm_ffi_callback;
@@ -155,10 +165,30 @@ static void callback_mcode_init(global_State *g, uint32_t *page)
155 *p = ARMI_B | ((page-p-2) & 0x00ffffffu); 165 *p = ARMI_B | ((page-p-2) & 0x00ffffffu);
156 p++; 166 p++;
157 } 167 }
158 lua_assert(p - page <= CALLBACK_MCODE_SIZE); 168 return p;
169}
170#elif LJ_TARGET_ARM64
171static void *callback_mcode_init(global_State *g, uint32_t *page)
172{
173 uint32_t *p = page;
174 void *target = (void *)lj_vm_ffi_callback;
175 MSize slot;
176 *p++ = A64I_LE(A64I_LDRLx | A64F_D(RID_X11) | A64F_S19(4));
177 *p++ = A64I_LE(A64I_LDRLx | A64F_D(RID_X10) | A64F_S19(5));
178 *p++ = A64I_LE(A64I_BR | A64F_N(RID_X11));
179 *p++ = A64I_LE(A64I_NOP);
180 ((void **)p)[0] = target;
181 ((void **)p)[1] = g;
182 p += 4;
183 for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) {
184 *p++ = A64I_LE(A64I_MOVZw | A64F_D(RID_X9) | A64F_U16(slot));
185 *p = A64I_LE(A64I_B | A64F_S26((page-p) & 0x03ffffffu));
186 p++;
187 }
188 return p;
159} 189}
160#elif LJ_TARGET_PPC 190#elif LJ_TARGET_PPC
161static void callback_mcode_init(global_State *g, uint32_t *page) 191static void *callback_mcode_init(global_State *g, uint32_t *page)
162{ 192{
163 uint32_t *p = page; 193 uint32_t *p = page;
164 void *target = (void *)lj_vm_ffi_callback; 194 void *target = (void *)lj_vm_ffi_callback;
@@ -174,30 +204,43 @@ static void callback_mcode_init(global_State *g, uint32_t *page)
174 *p = PPCI_B | (((page-p) & 0x00ffffffu) << 2); 204 *p = PPCI_B | (((page-p) & 0x00ffffffu) << 2);
175 p++; 205 p++;
176 } 206 }
177 lua_assert(p - page <= CALLBACK_MCODE_SIZE); 207 return p;
178} 208}
179#elif LJ_TARGET_MIPS 209#elif LJ_TARGET_MIPS
180static void callback_mcode_init(global_State *g, uint32_t *page) 210static void *callback_mcode_init(global_State *g, uint32_t *page)
181{ 211{
182 uint32_t *p = page; 212 uint32_t *p = page;
183 void *target = (void *)lj_vm_ffi_callback; 213 uintptr_t target = (uintptr_t)(void *)lj_vm_ffi_callback;
214 uintptr_t ug = (uintptr_t)(void *)g;
184 MSize slot; 215 MSize slot;
185 *p++ = MIPSI_SW | MIPSF_T(RID_R1)|MIPSF_S(RID_SP) | 0; 216#if LJ_TARGET_MIPS32
186 *p++ = MIPSI_LUI | MIPSF_T(RID_R3) | (u32ptr(target) >> 16); 217 *p++ = MIPSI_LUI | MIPSF_T(RID_R3) | (target >> 16);
187 *p++ = MIPSI_LUI | MIPSF_T(RID_R2) | (u32ptr(g) >> 16); 218 *p++ = MIPSI_LUI | MIPSF_T(RID_R2) | (ug >> 16);
188 *p++ = MIPSI_ORI | MIPSF_T(RID_R3)|MIPSF_S(RID_R3) |(u32ptr(target)&0xffff); 219#else
220 *p++ = MIPSI_LUI | MIPSF_T(RID_R3) | (target >> 48);
221 *p++ = MIPSI_LUI | MIPSF_T(RID_R2) | (ug >> 48);
222 *p++ = MIPSI_ORI | MIPSF_T(RID_R3)|MIPSF_S(RID_R3) | ((target >> 32) & 0xffff);
223 *p++ = MIPSI_ORI | MIPSF_T(RID_R2)|MIPSF_S(RID_R2) | ((ug >> 32) & 0xffff);
224 *p++ = MIPSI_DSLL | MIPSF_D(RID_R3)|MIPSF_T(RID_R3) | MIPSF_A(16);
225 *p++ = MIPSI_DSLL | MIPSF_D(RID_R2)|MIPSF_T(RID_R2) | MIPSF_A(16);
226 *p++ = MIPSI_ORI | MIPSF_T(RID_R3)|MIPSF_S(RID_R3) | ((target >> 16) & 0xffff);
227 *p++ = MIPSI_ORI | MIPSF_T(RID_R2)|MIPSF_S(RID_R2) | ((ug >> 16) & 0xffff);
228 *p++ = MIPSI_DSLL | MIPSF_D(RID_R3)|MIPSF_T(RID_R3) | MIPSF_A(16);
229 *p++ = MIPSI_DSLL | MIPSF_D(RID_R2)|MIPSF_T(RID_R2) | MIPSF_A(16);
230#endif
231 *p++ = MIPSI_ORI | MIPSF_T(RID_R3)|MIPSF_S(RID_R3) | (target & 0xffff);
189 *p++ = MIPSI_JR | MIPSF_S(RID_R3); 232 *p++ = MIPSI_JR | MIPSF_S(RID_R3);
190 *p++ = MIPSI_ORI | MIPSF_T(RID_R2)|MIPSF_S(RID_R2) | (u32ptr(g)&0xffff); 233 *p++ = MIPSI_ORI | MIPSF_T(RID_R2)|MIPSF_S(RID_R2) | (ug & 0xffff);
191 for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) { 234 for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) {
192 *p = MIPSI_B | ((page-p-1) & 0x0000ffffu); 235 *p = MIPSI_B | ((page-p-1) & 0x0000ffffu);
193 p++; 236 p++;
194 *p++ = MIPSI_LI | MIPSF_T(RID_R1) | slot; 237 *p++ = MIPSI_LI | MIPSF_T(RID_R1) | slot;
195 } 238 }
196 lua_assert(p - page <= CALLBACK_MCODE_SIZE); 239 return p;
197} 240}
198#else 241#else
199/* Missing support for this architecture. */ 242/* Missing support for this architecture. */
200#define callback_mcode_init(g, p) UNUSED(p) 243#define callback_mcode_init(g, p) (p)
201#endif 244#endif
202 245
203/* -- Machine code management --------------------------------------------- */ 246/* -- Machine code management --------------------------------------------- */
@@ -213,6 +256,11 @@ static void callback_mcode_init(global_State *g, uint32_t *page)
213#ifndef MAP_ANONYMOUS 256#ifndef MAP_ANONYMOUS
214#define MAP_ANONYMOUS MAP_ANON 257#define MAP_ANONYMOUS MAP_ANON
215#endif 258#endif
259#ifdef PROT_MPROTECT
260#define CCPROT_CREATE (PROT_MPROTECT(PROT_EXEC))
261#else
262#define CCPROT_CREATE 0
263#endif
216 264
217#endif 265#endif
218 266
@@ -220,15 +268,15 @@ static void callback_mcode_init(global_State *g, uint32_t *page)
220static void callback_mcode_new(CTState *cts) 268static void callback_mcode_new(CTState *cts)
221{ 269{
222 size_t sz = (size_t)CALLBACK_MCODE_SIZE; 270 size_t sz = (size_t)CALLBACK_MCODE_SIZE;
223 void *p; 271 void *p, *pe;
224 if (CALLBACK_MAX_SLOT == 0) 272 if (CALLBACK_MAX_SLOT == 0)
225 lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV); 273 lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
226#if LJ_TARGET_WINDOWS 274#if LJ_TARGET_WINDOWS
227 p = VirtualAlloc(NULL, sz, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); 275 p = LJ_WIN_VALLOC(NULL, sz, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
228 if (!p) 276 if (!p)
229 lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV); 277 lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
230#elif LJ_TARGET_POSIX 278#elif LJ_TARGET_POSIX
231 p = mmap(NULL, sz, (PROT_READ|PROT_WRITE), MAP_PRIVATE|MAP_ANONYMOUS, 279 p = mmap(NULL, sz, (PROT_READ|PROT_WRITE|CCPROT_CREATE), MAP_PRIVATE|MAP_ANONYMOUS,
232 -1, 0); 280 -1, 0);
233 if (p == MAP_FAILED) 281 if (p == MAP_FAILED)
234 lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV); 282 lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
@@ -237,12 +285,15 @@ static void callback_mcode_new(CTState *cts)
237 p = lj_mem_new(cts->L, sz); 285 p = lj_mem_new(cts->L, sz);
238#endif 286#endif
239 cts->cb.mcode = p; 287 cts->cb.mcode = p;
240 callback_mcode_init(cts->g, p); 288 pe = callback_mcode_init(cts->g, p);
289 UNUSED(pe);
290 lj_assertCTS((size_t)((char *)pe - (char *)p) <= sz,
291 "miscalculated CALLBACK_MAX_SLOT");
241 lj_mcode_sync(p, (char *)p + sz); 292 lj_mcode_sync(p, (char *)p + sz);
242#if LJ_TARGET_WINDOWS 293#if LJ_TARGET_WINDOWS
243 { 294 {
244 DWORD oprot; 295 DWORD oprot;
245 VirtualProtect(p, sz, PAGE_EXECUTE_READ, &oprot); 296 LJ_WIN_VPROTECT(p, sz, PAGE_EXECUTE_READ, &oprot);
246 } 297 }
247#elif LJ_TARGET_POSIX 298#elif LJ_TARGET_POSIX
248 mprotect(p, sz, (PROT_READ|PROT_EXEC)); 299 mprotect(p, sz, (PROT_READ|PROT_EXEC));
@@ -351,33 +402,78 @@ void lj_ccallback_mcode_free(CTState *cts)
351 goto done; \ 402 goto done; \
352 } CALLBACK_HANDLE_REGARG_FP2 403 } CALLBACK_HANDLE_REGARG_FP2
353 404
354#elif LJ_TARGET_PPC 405#elif LJ_TARGET_ARM64
355 406
356#define CALLBACK_HANDLE_REGARG \ 407#define CALLBACK_HANDLE_REGARG \
357 if (isfp) { \ 408 if (isfp) { \
358 if (nfpr + 1 <= CCALL_NARG_FPR) { \ 409 if (nfpr + n <= CCALL_NARG_FPR) { \
359 sp = &cts->cb.fpr[nfpr++]; \ 410 sp = &cts->cb.fpr[nfpr]; \
360 cta = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */ \ 411 nfpr += n; \
361 goto done; \ 412 goto done; \
413 } else { \
414 nfpr = CCALL_NARG_FPR; /* Prevent reordering. */ \
362 } \ 415 } \
363 } else { /* Try to pass argument in GPRs. */ \ 416 } else { \
364 if (n > 1) { \ 417 if (!LJ_TARGET_OSX && n > 1) \
365 lua_assert(ctype_isinteger(cta->info) && n == 2); /* int64_t. */ \ 418 ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \
366 ngpr = (ngpr + 1u) & ~1u; /* Align int64_t to regpair. */ \
367 } \
368 if (ngpr + n <= maxgpr) { \ 419 if (ngpr + n <= maxgpr) { \
369 sp = &cts->cb.gpr[ngpr]; \ 420 sp = &cts->cb.gpr[ngpr]; \
370 ngpr += n; \ 421 ngpr += n; \
371 goto done; \ 422 goto done; \
423 } else { \
424 ngpr = CCALL_NARG_GPR; /* Prevent reordering. */ \
425 } \
426 }
427
428#elif LJ_TARGET_PPC
429
430#define CALLBACK_HANDLE_GPR \
431 if (n > 1) { \
432 lj_assertCTS(((LJ_ABI_SOFTFP && ctype_isnum(cta->info)) || /* double. */ \
433 ctype_isinteger(cta->info)) && n == 2, /* int64_t. */ \
434 "bad GPR type"); \
435 ngpr = (ngpr + 1u) & ~1u; /* Align int64_t to regpair. */ \
436 } \
437 if (ngpr + n <= maxgpr) { \
438 sp = &cts->cb.gpr[ngpr]; \
439 ngpr += n; \
440 goto done; \
441 }
442
443#if LJ_ABI_SOFTFP
444#define CALLBACK_HANDLE_REGARG \
445 CALLBACK_HANDLE_GPR \
446 UNUSED(isfp);
447#else
448#define CALLBACK_HANDLE_REGARG \
449 if (isfp) { \
450 if (nfpr + 1 <= CCALL_NARG_FPR) { \
451 sp = &cts->cb.fpr[nfpr++]; \
452 cta = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */ \
453 goto done; \
372 } \ 454 } \
455 } else { /* Try to pass argument in GPRs. */ \
456 CALLBACK_HANDLE_GPR \
373 } 457 }
458#endif
374 459
460#if !LJ_ABI_SOFTFP
375#define CALLBACK_HANDLE_RET \ 461#define CALLBACK_HANDLE_RET \
376 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \ 462 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
377 *(double *)dp = *(float *)dp; /* FPRs always hold doubles. */ 463 *(double *)dp = *(float *)dp; /* FPRs always hold doubles. */
464#endif
378 465
379#elif LJ_TARGET_MIPS 466#elif LJ_TARGET_MIPS32
380 467
468#define CALLBACK_HANDLE_GPR \
469 if (n > 1) ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \
470 if (ngpr + n <= maxgpr) { \
471 sp = &cts->cb.gpr[ngpr]; \
472 ngpr += n; \
473 goto done; \
474 }
475
476#if !LJ_ABI_SOFTFP /* MIPS32 hard-float */
381#define CALLBACK_HANDLE_REGARG \ 477#define CALLBACK_HANDLE_REGARG \
382 if (isfp && nfpr < CCALL_NARG_FPR) { /* Try to pass argument in FPRs. */ \ 478 if (isfp && nfpr < CCALL_NARG_FPR) { /* Try to pass argument in FPRs. */ \
383 sp = (void *)((uint8_t *)&cts->cb.fpr[nfpr] + ((LJ_BE && n==1) ? 4 : 0)); \ 479 sp = (void *)((uint8_t *)&cts->cb.fpr[nfpr] + ((LJ_BE && n==1) ? 4 : 0)); \
@@ -385,13 +481,36 @@ void lj_ccallback_mcode_free(CTState *cts)
385 goto done; \ 481 goto done; \
386 } else { /* Try to pass argument in GPRs. */ \ 482 } else { /* Try to pass argument in GPRs. */ \
387 nfpr = CCALL_NARG_FPR; \ 483 nfpr = CCALL_NARG_FPR; \
388 if (n > 1) ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \ 484 CALLBACK_HANDLE_GPR \
389 if (ngpr + n <= maxgpr) { \ 485 }
390 sp = &cts->cb.gpr[ngpr]; \ 486#else /* MIPS32 soft-float */
391 ngpr += n; \ 487#define CALLBACK_HANDLE_REGARG \
392 goto done; \ 488 CALLBACK_HANDLE_GPR \
393 } \ 489 UNUSED(isfp);
490#endif
491
492#define CALLBACK_HANDLE_RET \
493 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
494 ((float *)dp)[1] = *(float *)dp;
495
496#elif LJ_TARGET_MIPS64
497
498#if !LJ_ABI_SOFTFP /* MIPS64 hard-float */
499#define CALLBACK_HANDLE_REGARG \
500 if (ngpr + n <= maxgpr) { \
501 sp = isfp ? (void*) &cts->cb.fpr[ngpr] : (void*) &cts->cb.gpr[ngpr]; \
502 ngpr += n; \
503 goto done; \
394 } 504 }
505#else /* MIPS64 soft-float */
506#define CALLBACK_HANDLE_REGARG \
507 if (ngpr + n <= maxgpr) { \
508 UNUSED(isfp); \
509 sp = (void*) &cts->cb.gpr[ngpr]; \
510 ngpr += n; \
511 goto done; \
512 }
513#endif
395 514
396#define CALLBACK_HANDLE_RET \ 515#define CALLBACK_HANDLE_RET \
397 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \ 516 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
@@ -411,6 +530,7 @@ static void callback_conv_args(CTState *cts, lua_State *L)
411 int gcsteps = 0; 530 int gcsteps = 0;
412 CType *ct; 531 CType *ct;
413 GCfunc *fn; 532 GCfunc *fn;
533 int fntp;
414 MSize ngpr = 0, nsp = 0, maxgpr = CCALL_NARG_GPR; 534 MSize ngpr = 0, nsp = 0, maxgpr = CCALL_NARG_GPR;
415#if CCALL_NARG_FPR 535#if CCALL_NARG_FPR
416 MSize nfpr = 0; 536 MSize nfpr = 0;
@@ -421,18 +541,27 @@ static void callback_conv_args(CTState *cts, lua_State *L)
421 541
422 if (slot < cts->cb.sizeid && (id = cts->cb.cbid[slot]) != 0) { 542 if (slot < cts->cb.sizeid && (id = cts->cb.cbid[slot]) != 0) {
423 ct = ctype_get(cts, id); 543 ct = ctype_get(cts, id);
424 rid = ctype_cid(ct->info); 544 rid = ctype_cid(ct->info); /* Return type. x86: +(spadj<<16). */
425 fn = funcV(lj_tab_getint(cts->miscmap, (int32_t)slot)); 545 fn = funcV(lj_tab_getint(cts->miscmap, (int32_t)slot));
546 fntp = LJ_TFUNC;
426 } else { /* Must set up frame first, before throwing the error. */ 547 } else { /* Must set up frame first, before throwing the error. */
427 ct = NULL; 548 ct = NULL;
428 rid = 0; 549 rid = 0;
429 fn = (GCfunc *)L; 550 fn = (GCfunc *)L;
551 fntp = LJ_TTHREAD;
552 }
553 /* Continuation returns from callback. */
554 if (LJ_FR2) {
555 (o++)->u64 = LJ_CONT_FFI_CALLBACK;
556 (o++)->u64 = rid;
557 } else {
558 o->u32.lo = LJ_CONT_FFI_CALLBACK;
559 o->u32.hi = rid;
560 o++;
430 } 561 }
431 o->u32.lo = LJ_CONT_FFI_CALLBACK; /* Continuation returns from callback. */ 562 setframe_gc(o, obj2gco(fn), fntp);
432 o->u32.hi = rid; /* Return type. x86: +(spadj<<16). */ 563 if (LJ_FR2) o++;
433 o++; 564 setframe_ftsz(o, ((char *)(o+1) - (char *)L->base) + FRAME_CONT);
434 setframe_gc(o, obj2gco(fn));
435 setframe_ftsz(o, (int)((char *)(o+1) - (char *)L->base) + FRAME_CONT);
436 L->top = L->base = ++o; 565 L->top = L->base = ++o;
437 if (!ct) 566 if (!ct)
438 lj_err_caller(cts->L, LJ_ERR_FFI_BADCBACK); 567 lj_err_caller(cts->L, LJ_ERR_FFI_BADCBACK);
@@ -459,7 +588,7 @@ static void callback_conv_args(CTState *cts, lua_State *L)
459 CTSize sz; 588 CTSize sz;
460 int isfp; 589 int isfp;
461 MSize n; 590 MSize n;
462 lua_assert(ctype_isfield(ctf->info)); 591 lj_assertCTS(ctype_isfield(ctf->info), "field expected");
463 cta = ctype_rawchild(cts, ctf); 592 cta = ctype_rawchild(cts, ctf);
464 isfp = ctype_isfp(cta->info); 593 isfp = ctype_isfp(cta->info);
465 sz = (cta->size + CTSIZE_PTR-1) & ~(CTSIZE_PTR-1); 594 sz = (cta->size + CTSIZE_PTR-1) & ~(CTSIZE_PTR-1);
@@ -474,7 +603,11 @@ static void callback_conv_args(CTState *cts, lua_State *L)
474 nsp += n; 603 nsp += n;
475 604
476 done: 605 done:
477 if (LJ_BE && cta->size < CTSIZE_PTR) 606 if (LJ_BE && cta->size < CTSIZE_PTR
607#if LJ_TARGET_MIPS64
608 && !(isfp && nsp)
609#endif
610 )
478 sp = (void *)((uint8_t *)sp + CTSIZE_PTR-cta->size); 611 sp = (void *)((uint8_t *)sp + CTSIZE_PTR-cta->size);
479 gcsteps += lj_cconv_tv_ct(cts, cta, 0, o++, sp); 612 gcsteps += lj_cconv_tv_ct(cts, cta, 0, o++, sp);
480 } 613 }
@@ -483,9 +616,14 @@ static void callback_conv_args(CTState *cts, lua_State *L)
483 L->top = o; 616 L->top = o;
484#if LJ_TARGET_X86 617#if LJ_TARGET_X86
485 /* Store stack adjustment for returns from non-cdecl callbacks. */ 618 /* Store stack adjustment for returns from non-cdecl callbacks. */
486 if (ctype_cconv(ct->info) != CTCC_CDECL) 619 if (ctype_cconv(ct->info) != CTCC_CDECL) {
620#if LJ_FR2
621 (L->base-3)->u64 |= (nsp << (16+2));
622#else
487 (L->base-2)->u32.hi |= (nsp << (16+2)); 623 (L->base-2)->u32.hi |= (nsp << (16+2));
488#endif 624#endif
625 }
626#endif
489 while (gcsteps-- > 0) 627 while (gcsteps-- > 0)
490 lj_gc_check(L); 628 lj_gc_check(L);
491} 629}
@@ -493,7 +631,11 @@ static void callback_conv_args(CTState *cts, lua_State *L)
493/* Convert Lua object to callback result. */ 631/* Convert Lua object to callback result. */
494static void callback_conv_result(CTState *cts, lua_State *L, TValue *o) 632static void callback_conv_result(CTState *cts, lua_State *L, TValue *o)
495{ 633{
634#if LJ_FR2
635 CType *ctr = ctype_raw(cts, (uint16_t)(L->base-3)->u64);
636#else
496 CType *ctr = ctype_raw(cts, (uint16_t)(L->base-2)->u32.hi); 637 CType *ctr = ctype_raw(cts, (uint16_t)(L->base-2)->u32.hi);
638#endif
497#if LJ_TARGET_X86 639#if LJ_TARGET_X86
498 cts->cb.gpr[2] = 0; 640 cts->cb.gpr[2] = 0;
499#endif 641#endif
@@ -503,6 +645,10 @@ static void callback_conv_result(CTState *cts, lua_State *L, TValue *o)
503 if (ctype_isfp(ctr->info)) 645 if (ctype_isfp(ctr->info))
504 dp = (uint8_t *)&cts->cb.fpr[0]; 646 dp = (uint8_t *)&cts->cb.fpr[0];
505#endif 647#endif
648#if LJ_TARGET_ARM64 && LJ_BE
649 if (ctype_isfp(ctr->info) && ctr->size == sizeof(float))
650 dp = (uint8_t *)&cts->cb.fpr[0].f[1];
651#endif
506 lj_cconv_ct_tv(cts, ctr, dp, o, 0); 652 lj_cconv_ct_tv(cts, ctr, dp, o, 0);
507#ifdef CALLBACK_HANDLE_RET 653#ifdef CALLBACK_HANDLE_RET
508 CALLBACK_HANDLE_RET 654 CALLBACK_HANDLE_RET
@@ -516,6 +662,12 @@ static void callback_conv_result(CTState *cts, lua_State *L, TValue *o)
516 *(int32_t *)dp = ctr->size == 1 ? (int32_t)*(int8_t *)dp : 662 *(int32_t *)dp = ctr->size == 1 ? (int32_t)*(int8_t *)dp :
517 (int32_t)*(int16_t *)dp; 663 (int32_t)*(int16_t *)dp;
518 } 664 }
665#if LJ_TARGET_MIPS64 || (LJ_TARGET_ARM64 && LJ_BE)
666 /* Always sign-extend results to 64 bits. Even a soft-fp 'float'. */
667 if (ctr->size <= 4 &&
668 (LJ_ABI_SOFTFP || ctype_isinteger_or_bool(ctr->info)))
669 *(int64_t *)dp = (int64_t)*(int32_t *)dp;
670#endif
519#if LJ_TARGET_X86 671#if LJ_TARGET_X86
520 if (ctype_isfp(ctr->info)) 672 if (ctype_isfp(ctr->info))
521 cts->cb.gpr[2] = ctr->size == sizeof(float) ? 1 : 2; 673 cts->cb.gpr[2] = ctr->size == sizeof(float) ? 1 : 2;
@@ -528,8 +680,8 @@ lua_State * LJ_FASTCALL lj_ccallback_enter(CTState *cts, void *cf)
528{ 680{
529 lua_State *L = cts->L; 681 lua_State *L = cts->L;
530 global_State *g = cts->g; 682 global_State *g = cts->g;
531 lua_assert(L != NULL); 683 lj_assertG(L != NULL, "uninitialized cts->L in callback");
532 if (gcref(g->jit_L)) { 684 if (tvref(g->jit_base)) {
533 setstrV(L, L->top++, lj_err_str(L, LJ_ERR_FFI_BADCBACK)); 685 setstrV(L, L->top++, lj_err_str(L, LJ_ERR_FFI_BADCBACK));
534 if (g->panic) g->panic(L); 686 if (g->panic) g->panic(L);
535 exit(EXIT_FAILURE); 687 exit(EXIT_FAILURE);
@@ -562,9 +714,9 @@ void LJ_FASTCALL lj_ccallback_leave(CTState *cts, TValue *o)
562 } 714 }
563 callback_conv_result(cts, L, o); 715 callback_conv_result(cts, L, o);
564 /* Finally drop C frame and continuation frame. */ 716 /* Finally drop C frame and continuation frame. */
565 L->cframe = cframe_prev(L->cframe); 717 L->top -= 2+2*LJ_FR2;
566 L->top -= 2;
567 L->base = obase; 718 L->base = obase;
719 L->cframe = cframe_prev(L->cframe);
568 cts->cb.slot = 0; /* Blacklist C function that called the callback. */ 720 cts->cb.slot = 0; /* Blacklist C function that called the callback. */
569} 721}
570 722
@@ -613,7 +765,7 @@ static CType *callback_checkfunc(CTState *cts, CType *ct)
613 CType *ctf = ctype_get(cts, fid); 765 CType *ctf = ctype_get(cts, fid);
614 if (!ctype_isattrib(ctf->info)) { 766 if (!ctype_isattrib(ctf->info)) {
615 CType *cta; 767 CType *cta;
616 lua_assert(ctype_isfield(ctf->info)); 768 lj_assertCTS(ctype_isfield(ctf->info), "field expected");
617 cta = ctype_rawchild(cts, ctf); 769 cta = ctype_rawchild(cts, ctf);
618 if (!(ctype_isenum(cta->info) || ctype_isptr(cta->info) || 770 if (!(ctype_isenum(cta->info) || ctype_isptr(cta->info) ||
619 (ctype_isnum(cta->info) && cta->size <= 8)) || 771 (ctype_isnum(cta->info) && cta->size <= 8)) ||