diff options
Diffstat (limited to 'src/lj_crecord.c')
-rw-r--r-- | src/lj_crecord.c | 103 |
1 files changed, 83 insertions, 20 deletions
diff --git a/src/lj_crecord.c b/src/lj_crecord.c index 4e6a644a..3dd6f495 100644 --- a/src/lj_crecord.c +++ b/src/lj_crecord.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include "lj_cparse.h" | 18 | #include "lj_cparse.h" |
19 | #include "lj_cconv.h" | 19 | #include "lj_cconv.h" |
20 | #include "lj_clib.h" | 20 | #include "lj_clib.h" |
21 | #include "lj_ccall.h" | ||
21 | #include "lj_ir.h" | 22 | #include "lj_ir.h" |
22 | #include "lj_jit.h" | 23 | #include "lj_jit.h" |
23 | #include "lj_ircall.h" | 24 | #include "lj_ircall.h" |
@@ -364,7 +365,7 @@ static TRef crec_tv_ct(jit_State *J, CType *s, CTypeID sid, TRef sp) | |||
364 | 365 | ||
365 | /* -- Convert TValue to C type (store) ------------------------------------ */ | 366 | /* -- Convert TValue to C type (store) ------------------------------------ */ |
366 | 367 | ||
367 | static TRef crec_ct_tv(jit_State *J, CType *d, TRef dp, TRef sp, TValue *sval) | 368 | static TRef crec_ct_tv(jit_State *J, CType *d, TRef dp, TRef sp, cTValue *sval) |
368 | { | 369 | { |
369 | CTState *cts = ctype_ctsG(J2G(J)); | 370 | CTState *cts = ctype_ctsG(J2G(J)); |
370 | CTypeID sid = CTID_P_VOID; | 371 | CTypeID sid = CTID_P_VOID; |
@@ -747,29 +748,88 @@ static TRef crec_call_args(jit_State *J, RecordFFData *rd, | |||
747 | CTState *cts, CType *ct) | 748 | CTState *cts, CType *ct) |
748 | { | 749 | { |
749 | TRef args[CCI_NARGS_MAX]; | 750 | TRef args[CCI_NARGS_MAX]; |
751 | CTypeID fid; | ||
750 | MSize i, n; | 752 | MSize i, n; |
751 | TRef tr; | 753 | TRef tr, *base; |
754 | cTValue *o; | ||
755 | #if LJ_TARGET_X86 | ||
756 | #if LJ_ABI_WIN | ||
757 | TRef *arg0 = NULL, *arg1 = NULL; | ||
758 | #endif | ||
759 | int ngpr = 0; | ||
760 | if (ctype_cconv(ct->info) == CTCC_THISCALL) | ||
761 | ngpr = 1; | ||
762 | else if (ctype_cconv(ct->info) == CTCC_FASTCALL) | ||
763 | ngpr = 2; | ||
764 | #endif | ||
765 | |||
766 | /* Skip initial attributes. */ | ||
767 | fid = ct->sib; | ||
768 | while (fid) { | ||
769 | CType *ctf = ctype_get(cts, fid); | ||
770 | if (!ctype_isattrib(ctf->info)) break; | ||
771 | fid = ctf->sib; | ||
772 | } | ||
752 | args[0] = TREF_NIL; | 773 | args[0] = TREF_NIL; |
753 | for (n = 0; J->base[n+1]; n++) { | 774 | for (n = 0, base = J->base+1, o = rd->argv+1; *base; n++, base++, o++) { |
775 | CTypeID did; | ||
754 | CType *d; | 776 | CType *d; |
755 | do { | 777 | |
756 | if (!ct->sib || n >= CCI_NARGS_MAX) | 778 | if (n >= CCI_NARGS_MAX) |
757 | lj_trace_err(J, LJ_TRERR_NYICALL); | ||
758 | ct = ctype_get(cts, ct->sib); | ||
759 | } while (ctype_isattrib(ct->info)); | ||
760 | if (!ctype_isfield(ct->info)) | ||
761 | lj_trace_err(J, LJ_TRERR_NYICALL); | 779 | lj_trace_err(J, LJ_TRERR_NYICALL); |
762 | d = ctype_rawchild(cts, ct); | 780 | |
781 | if (fid) { /* Get argument type from field. */ | ||
782 | CType *ctf = ctype_get(cts, fid); | ||
783 | fid = ctf->sib; | ||
784 | lua_assert(ctype_isfield(ctf->info)); | ||
785 | did = ctype_cid(ctf->info); | ||
786 | } else { | ||
787 | if (!(ct->info & CTF_VARARG)) | ||
788 | lj_trace_err(J, LJ_TRERR_NYICALL); /* Too many arguments. */ | ||
789 | did = lj_ccall_ctid_vararg(cts, o); /* Infer vararg type. */ | ||
790 | } | ||
791 | d = ctype_raw(cts, did); | ||
763 | if (!(ctype_isnum(d->info) || ctype_isptr(d->info) || | 792 | if (!(ctype_isnum(d->info) || ctype_isptr(d->info) || |
764 | ctype_isenum(d->info))) | 793 | ctype_isenum(d->info))) |
765 | lj_trace_err(J, LJ_TRERR_NYICALL); | 794 | lj_trace_err(J, LJ_TRERR_NYICALL); |
766 | tr = crec_ct_tv(J, d, 0, J->base[n+1], &rd->argv[n+1]); | 795 | tr = crec_ct_tv(J, d, 0, *base, o); |
767 | if (ctype_isinteger_or_bool(d->info) && d->size < 4) { | 796 | if (ctype_isinteger_or_bool(d->info)) { |
768 | if ((d->info & CTF_UNSIGNED)) | 797 | if (d->size < 4) { |
769 | tr = emitconv(tr, IRT_INT, d->size==1 ? IRT_U8 : IRT_U16, 0); | 798 | if ((d->info & CTF_UNSIGNED)) |
770 | else | 799 | tr = emitconv(tr, IRT_INT, d->size==1 ? IRT_U8 : IRT_U16, 0); |
771 | tr = emitconv(tr, IRT_INT, d->size==1 ? IRT_I8 : IRT_I16, IRCONV_SEXT); | 800 | else |
801 | tr = emitconv(tr, IRT_INT, d->size==1 ? IRT_I8 : IRT_I16,IRCONV_SEXT); | ||
802 | } | ||
772 | } | 803 | } |
804 | #if LJ_TARGET_X86 | ||
805 | /* 64 bit args must not end up in registers for fastcall/thiscall. */ | ||
806 | #if LJ_ABI_WIN | ||
807 | if (!ctype_isfp(d->info)) { | ||
808 | /* Sigh, the Windows/x86 ABI allows reordering across 64 bit args. */ | ||
809 | if (tref_typerange(tr, IRT_I64, IRT_U64)) { | ||
810 | if (ngpr) { | ||
811 | arg0 = &args[n]; args[n++] = TREF_NIL; ngpr--; | ||
812 | if (ngpr) { | ||
813 | arg1 = &args[n]; args[n++] = TREF_NIL; ngpr--; | ||
814 | } | ||
815 | } | ||
816 | } else { | ||
817 | if (arg0) { *arg0 = tr; arg0 = NULL; n--; continue; } | ||
818 | if (arg1) { *arg1 = tr; arg1 = NULL; n--; continue; } | ||
819 | if (ngpr) ngpr--; | ||
820 | } | ||
821 | } | ||
822 | #else | ||
823 | if (!ctype_isfp(d->info) && ngpr) { | ||
824 | if (tref_typerange(tr, IRT_I64, IRT_U64)) { | ||
825 | /* No reordering for other x86 ABIs. Simply add alignment args. */ | ||
826 | do { args[n++] = TREF_NIL; } while (--ngpr); | ||
827 | } else { | ||
828 | ngpr--; | ||
829 | } | ||
830 | } | ||
831 | #endif | ||
832 | #endif | ||
773 | args[n] = tr; | 833 | args[n] = tr; |
774 | } | 834 | } |
775 | tr = args[0]; | 835 | tr = args[0]; |
@@ -801,12 +861,15 @@ static int crec_call(jit_State *J, RecordFFData *rd, GCcdata *cd) | |||
801 | } | 861 | } |
802 | if (!(ctype_isnum(ctr->info) || ctype_isptr(ctr->info) || | 862 | if (!(ctype_isnum(ctr->info) || ctype_isptr(ctr->info) || |
803 | ctype_isvoid(ctr->info)) || | 863 | ctype_isvoid(ctr->info)) || |
804 | ctype_isbool(ctr->info) || (ct->info & CTF_VARARG) || | 864 | ctype_isbool(ctr->info) || t == IRT_CDATA) |
865 | lj_trace_err(J, LJ_TRERR_NYICALL); | ||
866 | if ((ct->info & CTF_VARARG) | ||
805 | #if LJ_TARGET_X86 | 867 | #if LJ_TARGET_X86 |
806 | ctype_cconv(ct->info) != CTCC_CDECL || | 868 | || ctype_cconv(ct->info) != CTCC_CDECL |
807 | #endif | 869 | #endif |
808 | t == IRT_CDATA) | 870 | ) |
809 | lj_trace_err(J, LJ_TRERR_NYICALL); | 871 | func = emitir(IRT(IR_CARG, IRT_NIL), func, |
872 | lj_ir_kint(J, ctype_typeid(cts, ct))); | ||
810 | tr = emitir(IRT(IR_CALLXS, t), crec_call_args(J, rd, cts, ct), func); | 873 | tr = emitir(IRT(IR_CALLXS, t), crec_call_args(J, rd, cts, ct), func); |
811 | if (t == IRT_FLOAT || t == IRT_U32) { | 874 | if (t == IRT_FLOAT || t == IRT_U32) { |
812 | tr = emitconv(tr, IRT_NUM, t, 0); | 875 | tr = emitconv(tr, IRT_NUM, t, 0); |