diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lj_record.c | 38 |
1 files changed, 26 insertions, 12 deletions
diff --git a/src/lj_record.c b/src/lj_record.c index f1dd8e3e..e9841102 100644 --- a/src/lj_record.c +++ b/src/lj_record.c | |||
| @@ -661,7 +661,32 @@ int lj_record_mm_lookup(jit_State *J, RecordIndex *ix, MMS mm) | |||
| 661 | mt = tabref(tabV(&ix->tabv)->metatable); | 661 | mt = tabref(tabV(&ix->tabv)->metatable); |
| 662 | mix.tab = emitir(IRT(IR_FLOAD, IRT_TAB), ix->tab, IRFL_TAB_META); | 662 | mix.tab = emitir(IRT(IR_FLOAD, IRT_TAB), ix->tab, IRFL_TAB_META); |
| 663 | } else if (tref_isudata(ix->tab)) { | 663 | } else if (tref_isudata(ix->tab)) { |
| 664 | int udtype = udataV(&ix->tabv)->udtype; | ||
| 664 | mt = tabref(udataV(&ix->tabv)->metatable); | 665 | mt = tabref(udataV(&ix->tabv)->metatable); |
| 666 | /* The metatables of special userdata objects are treated as immutable. */ | ||
| 667 | if (udtype != UDTYPE_USERDATA) { | ||
| 668 | cTValue *mo; | ||
| 669 | if (LJ_HASFFI && udtype == UDTYPE_FFI_CLIB) { | ||
| 670 | /* Specialize to the C library namespace object. */ | ||
| 671 | emitir(IRTG(IR_EQ, IRT_P32), ix->tab, lj_ir_kptr(J, udataV(&ix->tabv))); | ||
| 672 | } else { | ||
| 673 | /* Specialize to the type of userdata. */ | ||
| 674 | TRef tr = emitir(IRT(IR_FLOAD, IRT_U8), ix->tab, IRFL_UDATA_UDTYPE); | ||
| 675 | emitir(IRTGI(IR_EQ), tr, lj_ir_kint(J, udtype)); | ||
| 676 | } | ||
| 677 | immutable_mt: | ||
| 678 | mo = lj_tab_getstr(mt, mmname_str(J2G(J), mm)); | ||
| 679 | if (!mo || tvisnil(mo)) | ||
| 680 | return 0; /* No metamethod. */ | ||
| 681 | /* Treat metamethod or index table as immutable, too. */ | ||
| 682 | if (!(tvisfunc(mo) || tvistab(mo))) | ||
| 683 | lj_trace_err(J, LJ_TRERR_BADTYPE); | ||
| 684 | copyTV(J->L, &ix->mobjv, mo); | ||
| 685 | ix->mobj = lj_ir_kgc(J, gcV(mo), tvisfunc(mo) ? IRT_FUNC : IRT_TAB); | ||
| 686 | ix->mtv = mt; | ||
| 687 | ix->mt = TREF_NIL; /* Dummy value for comparison semantics. */ | ||
| 688 | return 1; /* Got metamethod or index table. */ | ||
| 689 | } | ||
| 665 | mix.tab = emitir(IRT(IR_FLOAD, IRT_TAB), ix->tab, IRFL_UDATA_META); | 690 | mix.tab = emitir(IRT(IR_FLOAD, IRT_TAB), ix->tab, IRFL_UDATA_META); |
| 666 | } else { | 691 | } else { |
| 667 | /* Specialize to base metatable. Must flush mcode in lua_setmetatable(). */ | 692 | /* Specialize to base metatable. Must flush mcode in lua_setmetatable(). */ |
| @@ -670,19 +695,8 @@ int lj_record_mm_lookup(jit_State *J, RecordIndex *ix, MMS mm) | |||
| 670 | ix->mt = TREF_NIL; | 695 | ix->mt = TREF_NIL; |
| 671 | return 0; /* No metamethod. */ | 696 | return 0; /* No metamethod. */ |
| 672 | } | 697 | } |
| 673 | #if LJ_HASFFI | ||
| 674 | /* The cdata metatable is treated as immutable. */ | 698 | /* The cdata metatable is treated as immutable. */ |
| 675 | if (tref_iscdata(ix->tab)) { | 699 | if (LJ_HASFFI && tref_iscdata(ix->tab)) goto immutable_mt; |
| 676 | cTValue *mo = lj_tab_getstr(mt, mmname_str(J2G(J), mm)); | ||
| 677 | if (!mo || tvisnil(mo)) | ||
| 678 | return 0; /* No metamethod. */ | ||
| 679 | setfuncV(J->L, &ix->mobjv, funcV(mo)); | ||
| 680 | ix->mobj = lj_ir_kfunc(J, funcV(mo)); /* Immutable metamethod. */ | ||
| 681 | ix->mtv = mt; | ||
| 682 | ix->mt = TREF_NIL; /* Dummy value for comparison semantics. */ | ||
| 683 | return 1; /* Got cdata metamethod. */ | ||
| 684 | } | ||
| 685 | #endif | ||
| 686 | ix->mt = mix.tab = lj_ir_ktab(J, mt); | 700 | ix->mt = mix.tab = lj_ir_ktab(J, mt); |
| 687 | goto nocheck; | 701 | goto nocheck; |
| 688 | } | 702 | } |
