diff options
Diffstat (limited to 'src/lj_ccall.c')
-rw-r--r-- | src/lj_ccall.c | 39 |
1 files changed, 26 insertions, 13 deletions
diff --git a/src/lj_ccall.c b/src/lj_ccall.c index ae69cd28..d5f092ea 100644 --- a/src/lj_ccall.c +++ b/src/lj_ccall.c | |||
@@ -781,17 +781,24 @@ static unsigned int ccall_classify_struct(CTState *cts, CType *ct) | |||
781 | { | 781 | { |
782 | CTSize sz = ct->size; | 782 | CTSize sz = ct->size; |
783 | unsigned int r = 0, n = 0, isu = (ct->info & CTF_UNION); | 783 | unsigned int r = 0, n = 0, isu = (ct->info & CTF_UNION); |
784 | while (ct->sib) { | 784 | while (ct->sib && n <= 4) { |
785 | unsigned int m = 1; | ||
785 | CType *sct; | 786 | CType *sct; |
786 | ct = ctype_get(cts, ct->sib); | 787 | ct = ctype_get(cts, ct->sib); |
787 | if (ctype_isfield(ct->info)) { | 788 | if (ctype_isfield(ct->info)) { |
788 | sct = ctype_rawchild(cts, ct); | 789 | sct = ctype_rawchild(cts, ct); |
790 | if (ctype_isarray(sct->info)) { | ||
791 | CType *cct = ctype_rawchild(cts, sct); | ||
792 | if (!cct->size) continue; | ||
793 | m = sct->size / cct->size; | ||
794 | sct = cct; | ||
795 | } | ||
789 | if (ctype_isfp(sct->info)) { | 796 | if (ctype_isfp(sct->info)) { |
790 | r |= sct->size; | 797 | r |= sct->size; |
791 | if (!isu) n++; else if (n == 0) n = 1; | 798 | if (!isu) n += m; else if (n < m) n = m; |
792 | } else if (ctype_iscomplex(sct->info)) { | 799 | } else if (ctype_iscomplex(sct->info)) { |
793 | r |= (sct->size >> 1); | 800 | r |= (sct->size >> 1); |
794 | if (!isu) n += 2; else if (n < 2) n = 2; | 801 | if (!isu) n += 2*m; else if (n < 2*m) n = 2*m; |
795 | } else if (ctype_isstruct(sct->info)) { | 802 | } else if (ctype_isstruct(sct->info)) { |
796 | goto substruct; | 803 | goto substruct; |
797 | } else { | 804 | } else { |
@@ -803,10 +810,11 @@ static unsigned int ccall_classify_struct(CTState *cts, CType *ct) | |||
803 | sct = ctype_rawchild(cts, ct); | 810 | sct = ctype_rawchild(cts, ct); |
804 | substruct: | 811 | substruct: |
805 | if (sct->size > 0) { | 812 | if (sct->size > 0) { |
806 | unsigned int s = ccall_classify_struct(cts, sct); | 813 | unsigned int s = ccall_classify_struct(cts, sct), sn; |
807 | if (s <= 1) goto noth; | 814 | if (s <= 1) goto noth; |
808 | r |= (s & 255); | 815 | r |= (s & 255); |
809 | if (!isu) n += (s >> 8); else if (n < (s >>8)) n = (s >> 8); | 816 | sn = (s >> 8) * m; |
817 | if (!isu) n += sn; else if (n < sn) n = sn; | ||
810 | } | 818 | } |
811 | } | 819 | } |
812 | } | 820 | } |
@@ -893,7 +901,9 @@ static void ccall_copy_struct(CCallState *cc, CType *ctr, void *dp, void *sp, | |||
893 | 901 | ||
894 | /* -- Common C call handling ---------------------------------------------- */ | 902 | /* -- Common C call handling ---------------------------------------------- */ |
895 | 903 | ||
896 | /* Infer the destination CTypeID for a vararg argument. */ | 904 | /* Infer the destination CTypeID for a vararg argument. |
905 | ** Note: may reallocate cts->tab and invalidate CType pointers. | ||
906 | */ | ||
897 | CTypeID lj_ccall_ctid_vararg(CTState *cts, cTValue *o) | 907 | CTypeID lj_ccall_ctid_vararg(CTState *cts, cTValue *o) |
898 | { | 908 | { |
899 | if (tvisnumber(o)) { | 909 | if (tvisnumber(o)) { |
@@ -921,13 +931,16 @@ CTypeID lj_ccall_ctid_vararg(CTState *cts, cTValue *o) | |||
921 | } | 931 | } |
922 | } | 932 | } |
923 | 933 | ||
924 | /* Setup arguments for C call. */ | 934 | /* Setup arguments for C call. |
935 | ** Note: may reallocate cts->tab and invalidate CType pointers. | ||
936 | */ | ||
925 | static int ccall_set_args(lua_State *L, CTState *cts, CType *ct, | 937 | static int ccall_set_args(lua_State *L, CTState *cts, CType *ct, |
926 | CCallState *cc) | 938 | CCallState *cc) |
927 | { | 939 | { |
928 | int gcsteps = 0; | 940 | int gcsteps = 0; |
929 | TValue *o, *top = L->top; | 941 | TValue *o, *top = L->top; |
930 | CTypeID fid; | 942 | CTypeID fid; |
943 | CTInfo info = ct->info; /* lj_ccall_ctid_vararg may invalidate ct pointer. */ | ||
931 | CType *ctr; | 944 | CType *ctr; |
932 | MSize maxgpr, ngpr = 0, nsp = 0, narg; | 945 | MSize maxgpr, ngpr = 0, nsp = 0, narg; |
933 | #if CCALL_NARG_FPR | 946 | #if CCALL_NARG_FPR |
@@ -946,7 +959,7 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct, | |||
946 | #if LJ_TARGET_X86 | 959 | #if LJ_TARGET_X86 |
947 | /* x86 has several different calling conventions. */ | 960 | /* x86 has several different calling conventions. */ |
948 | cc->resx87 = 0; | 961 | cc->resx87 = 0; |
949 | switch (ctype_cconv(ct->info)) { | 962 | switch (ctype_cconv(info)) { |
950 | case CTCC_FASTCALL: maxgpr = 2; break; | 963 | case CTCC_FASTCALL: maxgpr = 2; break; |
951 | case CTCC_THISCALL: maxgpr = 1; break; | 964 | case CTCC_THISCALL: maxgpr = 1; break; |
952 | default: maxgpr = 0; break; | 965 | default: maxgpr = 0; break; |
@@ -963,7 +976,7 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct, | |||
963 | } else if (ctype_iscomplex(ctr->info) || ctype_isstruct(ctr->info)) { | 976 | } else if (ctype_iscomplex(ctr->info) || ctype_isstruct(ctr->info)) { |
964 | /* Preallocate cdata object and anchor it after arguments. */ | 977 | /* Preallocate cdata object and anchor it after arguments. */ |
965 | CTSize sz = ctr->size; | 978 | CTSize sz = ctr->size; |
966 | GCcdata *cd = lj_cdata_new(cts, ctype_cid(ct->info), sz); | 979 | GCcdata *cd = lj_cdata_new(cts, ctype_cid(info), sz); |
967 | void *dp = cdataptr(cd); | 980 | void *dp = cdataptr(cd); |
968 | setcdataV(L, L->top++, cd); | 981 | setcdataV(L, L->top++, cd); |
969 | if (ctype_isstruct(ctr->info)) { | 982 | if (ctype_isstruct(ctr->info)) { |
@@ -986,7 +999,7 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct, | |||
986 | } | 999 | } |
987 | 1000 | ||
988 | #if LJ_TARGET_ARM64 && LJ_ABI_WIN | 1001 | #if LJ_TARGET_ARM64 && LJ_ABI_WIN |
989 | if ((ct->info & CTF_VARARG)) { | 1002 | if ((info & CTF_VARARG)) { |
990 | nsp -= maxgpr * CTSIZE_PTR; /* May end up with negative nsp. */ | 1003 | nsp -= maxgpr * CTSIZE_PTR; /* May end up with negative nsp. */ |
991 | ngpr = maxgpr; | 1004 | ngpr = maxgpr; |
992 | nfpr = CCALL_NARG_FPR; | 1005 | nfpr = CCALL_NARG_FPR; |
@@ -1007,7 +1020,7 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct, | |||
1007 | lj_assertL(ctype_isfield(ctf->info), "field expected"); | 1020 | lj_assertL(ctype_isfield(ctf->info), "field expected"); |
1008 | did = ctype_cid(ctf->info); | 1021 | did = ctype_cid(ctf->info); |
1009 | } else { | 1022 | } else { |
1010 | if (!(ct->info & CTF_VARARG)) | 1023 | if (!(info & CTF_VARARG)) |
1011 | lj_err_caller(L, LJ_ERR_FFI_NUMARG); /* Too many arguments. */ | 1024 | lj_err_caller(L, LJ_ERR_FFI_NUMARG); /* Too many arguments. */ |
1012 | did = lj_ccall_ctid_vararg(cts, o); /* Infer vararg type. */ | 1025 | did = lj_ccall_ctid_vararg(cts, o); /* Infer vararg type. */ |
1013 | isva = 1; | 1026 | isva = 1; |
@@ -1178,11 +1191,11 @@ int lj_ccall_func(lua_State *L, GCcdata *cd) | |||
1178 | ct = ctype_rawchild(cts, ct); | 1191 | ct = ctype_rawchild(cts, ct); |
1179 | } | 1192 | } |
1180 | if (ctype_isfunc(ct->info)) { | 1193 | if (ctype_isfunc(ct->info)) { |
1194 | CTypeID id = ctype_typeid(cts, ct); | ||
1181 | CCallState cc; | 1195 | CCallState cc; |
1182 | int gcsteps, ret; | 1196 | int gcsteps, ret; |
1183 | cc.func = (void (*)(void))cdata_getptr(cdataptr(cd), sz); | 1197 | cc.func = (void (*)(void))cdata_getptr(cdataptr(cd), sz); |
1184 | gcsteps = ccall_set_args(L, cts, ct, &cc); | 1198 | gcsteps = ccall_set_args(L, cts, ct, &cc); |
1185 | ct = (CType *)((intptr_t)ct-(intptr_t)cts->tab); | ||
1186 | cts->cb.slot = ~0u; | 1199 | cts->cb.slot = ~0u; |
1187 | lj_vm_ffi_call(&cc); | 1200 | lj_vm_ffi_call(&cc); |
1188 | if (cts->cb.slot != ~0u) { /* Blacklist function that called a callback. */ | 1201 | if (cts->cb.slot != ~0u) { /* Blacklist function that called a callback. */ |
@@ -1190,7 +1203,7 @@ int lj_ccall_func(lua_State *L, GCcdata *cd) | |||
1190 | tv.u64 = ((uintptr_t)(void *)cc.func >> 2) | U64x(800000000, 00000000); | 1203 | tv.u64 = ((uintptr_t)(void *)cc.func >> 2) | U64x(800000000, 00000000); |
1191 | setboolV(lj_tab_set(L, cts->miscmap, &tv), 1); | 1204 | setboolV(lj_tab_set(L, cts->miscmap, &tv), 1); |
1192 | } | 1205 | } |
1193 | ct = (CType *)((intptr_t)ct+(intptr_t)cts->tab); /* May be reallocated. */ | 1206 | ct = ctype_get(cts, id); /* Table may have been reallocated. */ |
1194 | gcsteps += ccall_get_results(L, cts, ct, &cc, &ret); | 1207 | gcsteps += ccall_get_results(L, cts, ct, &cc, &ret); |
1195 | #if LJ_TARGET_X86 && LJ_ABI_WIN | 1208 | #if LJ_TARGET_X86 && LJ_ABI_WIN |
1196 | /* Automatically detect __stdcall and fix up C function declaration. */ | 1209 | /* Automatically detect __stdcall and fix up C function declaration. */ |