diff options
Diffstat (limited to 'src/lj_crecord.c')
-rw-r--r-- | src/lj_crecord.c | 153 |
1 files changed, 121 insertions, 32 deletions
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. */ | ||
464 | static 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 | |||
462 | void LJ_FASTCALL recff_cdata_index(jit_State *J, RecordFFData *rd) | 498 | void 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 | ||
516 | again: | ||
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; |
529 | index_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. */ | ||
918 | static 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 | |||
852 | void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd) | 938 | void 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 | ||