Add support for global short assignments.

In other words 'a = 1' now works.
This commit is contained in:
Michael Munday 2016-12-16 17:23:46 -05:00
parent 24bdb7576d
commit bee112d431
3 changed files with 238 additions and 48 deletions

View File

@ -1190,6 +1190,10 @@ map_op = {
stfl_1 = "0000b2b10000sS", stfl_1 = "0000b2b10000sS",
-- I- mode instructions -- I- mode instructions
svc_1 = "000000000a00iI", svc_1 = "000000000a00iI",
-- RI-a mode instructions
-- TODO: change "i" to "RI-a"
mhi_2 = "0000a70c0000i",
mghi_2 = "0000a70d0000i",
-- RI-b mode instructions -- RI-b mode instructions
bras_2 = "0000a7050000RI-b", bras_2 = "0000a7050000RI-b",
-- RI-c mode instructions -- RI-c mode instructions

View File

@ -367,7 +367,7 @@
#define LJ_TARGET_MASKSHIFT 1 #define LJ_TARGET_MASKSHIFT 1
#define LJ_TARGET_MASKROT 1 #define LJ_TARGET_MASKROT 1
#define LJ_TARGET_UNALIGNED 1 #define LJ_TARGET_UNALIGNED 1
#define LJ_ARCH_NUMMODE LJ_NUMMODE_SINGLE_DUAL #define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL
#define LJ_TARGET_GC64 1 #define LJ_TARGET_GC64 1
#define LJ_ARCH_NOJIT 1 /* NYI */ #define LJ_ARCH_NOJIT 1 /* NYI */
#define LJ_ARCH_NOFFI 1 /* Disable FFI for now. */ #define LJ_ARCH_NOFFI 1 /* Disable FFI for now. */

View File

@ -57,7 +57,8 @@
|.define CRET1, r2 |.define CRET1, r2
| |
|.define OP, r2 |.define OP, r2
|.define TMP1, r14 |.define TMPR1, r14
|.define TMPR2, r0
| |
|// Stack layout while in interpreter. Must match with lj_frame.h. |// Stack layout while in interpreter. Must match with lj_frame.h.
|.define CFRAME_SPACE, 240 // Delta for sp, 8 byte aligned. |.define CFRAME_SPACE, 240 // Delta for sp, 8 byte aligned.
@ -66,9 +67,9 @@
|.define SAVE_GPRS, 288(sp) // Save area for r6-r15 (10*8 bytes). |.define SAVE_GPRS, 288(sp) // Save area for r6-r15 (10*8 bytes).
|.define SAVE_GPRS_P, 48(sp) // Save area for r6-r15 (10*8 bytes) in prologue (before stack frame is allocated). |.define SAVE_GPRS_P, 48(sp) // Save area for r6-r15 (10*8 bytes) in prologue (before stack frame is allocated).
| |
|// Argument save area, each slot is 8-bytes (32-bit types are sign/zero extended). |// Argument save area.
|.define SAVE_ERRF, 280(sp) // Argument 4, in r5. |.define SAVE_ERRF, 280(sp) // Argument 4, in r5.
|.define SAVE_NRES, 272(sp) // Argument 3, in r4. |.define SAVE_NRES, 272(sp) // Argument 3, in r4. Size is 4-bytes.
|.define SAVE_CFRAME, 264(sp) // Argument 2, in r3. |.define SAVE_CFRAME, 264(sp) // Argument 2, in r3.
|.define SAVE_L, 256(sp) // Argument 1, in r2. |.define SAVE_L, 256(sp) // Argument 1, in r2.
|.define RESERVED, 248(sp) // Reserved for compiler use. |.define RESERVED, 248(sp) // Reserved for compiler use.
@ -85,6 +86,7 @@
|.define SAVE_FPR8, 176(sp) |.define SAVE_FPR8, 176(sp)
|.define SAVE_PC, 168(sp) |.define SAVE_PC, 168(sp)
|.define SAVE_MULTRES, 160(sp) |.define SAVE_MULTRES, 160(sp)
|.define TMP_STACK, 160(sp) // Overlaps SAVE_MULTRES
| |
|// Callee save area (allocated by interpreter). |// Callee save area (allocated by interpreter).
|.define CALLEESAVE, 000(sp) // <- sp in interpreter. |.define CALLEESAVE, 000(sp) // <- sp in interpreter.
@ -140,7 +142,7 @@
|.macro ins_ABC; .endmacro |.macro ins_ABC; .endmacro
|.macro ins_AB_; .endmacro |.macro ins_AB_; .endmacro
|.macro ins_A_C; .endmacro |.macro ins_A_C; .endmacro
|.macro ins_AND; .endmacro |.macro ins_AND; lghi TMPR1, -1; xgr RD, TMPR1; .endmacro // RD = ~RD
| |
|// Instruction decode+dispatch. |// Instruction decode+dispatch.
| // TODO: tune this, right now we always decode RA-D even if they aren't used. | // TODO: tune this, right now we always decode RA-D even if they aren't used.
@ -157,9 +159,10 @@
| srlg RB, RB, 8(r0) | srlg RB, RB, 8(r0)
| llgcr RC, RD | llgcr RC, RD
| la PC, 4(PC) | la PC, 4(PC)
| llgfr TMP1, OP | llgfr TMPR1, OP
| sllg TMP1, TMP1, 3(r0) // TMP1=OP*8 | sllg TMPR1, TMPR1, 3(r0) // TMPR1=OP*8
| b 0(TMP1, DISPATCH) | lg TMPR1, 0(TMPR1, DISPATCH)
| br TMPR1
|.endmacro |.endmacro
| |
|// Instruction footer. |// Instruction footer.
@ -184,10 +187,10 @@
| lg PC, LFUNC:RB->pc | lg PC, LFUNC:RB->pc
| llgf RA, 0(PC) // TODO: combine loads? | llgf RA, 0(PC) // TODO: combine loads?
| llgcr OP, RA | llgcr OP, RA
| sllg TMP1, OP, 3(r0) | sllg TMPR1, OP, 3(r0)
| la PC, 4(PC) | la PC, 4(PC)
| lg TMP1, 0(TMP1, DISPATCH) | lg TMPR1, 0(TMPR1, DISPATCH)
| br TMP1 | br TMPR1
|.endmacro |.endmacro
| |
|.macro ins_call |.macro ins_call
@ -210,6 +213,11 @@
| oihh reg, ((tp>>1) &0xffff) | oihh reg, ((tp>>1) &0xffff)
| oihl reg, ((tp<<15)&0x8000) | oihl reg, ((tp<<15)&0x8000)
|.endmacro |.endmacro
|.macro settp, dst, reg, tp
| llihh dst, ((tp>>1) &0xffff)
| iihl dst, ((tp<<15)&0x8000)
| ogr dst, reg
|.endmacro
|.macro setint, reg |.macro setint, reg
| settp reg, LJ_TISNUM | settp reg, LJ_TISNUM
|.endmacro |.endmacro
@ -257,10 +265,24 @@
| |
|// Set current VM state. |// Set current VM state.
|.macro set_vmstate, st |.macro set_vmstate, st
| lghi TMP1, ~LJ_VMST_..st | lghi TMPR1, ~LJ_VMST_..st
| stg TMP1, DISPATCH_GL(vmstate)(DISPATCH) | stg TMPR1, DISPATCH_GL(vmstate)(DISPATCH)
|.endmacro |.endmacro
| |
|// Move table write barrier back. Overwrites reg.
|.macro barrierback, tab, reg
| // TODO: more efficient way?
| llgc reg, tab->marked
| nill reg, (uint16_t)~LJ_GC_BLACK // black2gray(tab)
| stc reg, tab->marked
| lg reg, (DISPATCH_GL(gc.grayagain))(DISPATCH)
| stg tab, (DISPATCH_GL(gc.grayagain))(DISPATCH)
| stg reg, tab->gclist
|.endmacro
#if !LJ_DUALNUM
#error "Only dual-number mode supported for s390x target"
#endif
/* Generate subroutines used by opcodes and other parts of the VM. */ /* Generate subroutines used by opcodes and other parts of the VM. */
/* The .code_sub section should be last to help static branch prediction. */ /* The .code_sub section should be last to help static branch prediction. */
@ -294,8 +316,8 @@ static void build_subroutines(BuildCtx *ctx)
| |
|->vm_return: |->vm_return:
| // BASE = base, RA = resultofs, RD = nresults+1 (= MULTRES), PC = return | // BASE = base, RA = resultofs, RD = nresults+1 (= MULTRES), PC = return
| lghi TMP1, FRAME_C | lghi TMPR1, FRAME_C
| xgr PC, TMP1 | xgr PC, TMPR1
| tmll PC, FRAME_TYPE | tmll PC, FRAME_TYPE
| jne ->vm_returnp | jne ->vm_returnp
| |
@ -318,7 +340,7 @@ static void build_subroutines(BuildCtx *ctx)
| stg PC, L:RB->base | stg PC, L:RB->base
|3: |3:
| lg RD, SAVE_MULTRES | lg RD, SAVE_MULTRES
| lg RA, SAVE_NRES // RA = wanted nresults+1 | lgf RA, SAVE_NRES // RA = wanted nresults+1
|4: |4:
| cgr RA, RD | cgr RA, RD
| jne >6 // More/less results wanted? | jne >6 // More/less results wanted?
@ -340,8 +362,8 @@ static void build_subroutines(BuildCtx *ctx)
| // More results wanted. Check stack size and fill up results with nil. | // More results wanted. Check stack size and fill up results with nil.
| cg BASE, L:RB->maxstack | cg BASE, L:RB->maxstack
| jh >8 | jh >8
| lghi TMP1, LJ_TNIL | lghi TMPR1, LJ_TNIL
| stg TMP1, -16(BASE) | stg TMPR1, -16(BASE)
| la BASE, 8(BASE) | la BASE, 8(BASE)
| aghi RD, 1 | aghi RD, 1
| j <4 | j <4
@ -350,8 +372,8 @@ static void build_subroutines(BuildCtx *ctx)
| cghi RA, 0 | cghi RA, 0
| je <5 // But check for LUA_MULTRET+1. | je <5 // But check for LUA_MULTRET+1.
| sgr RA, RD // Negative result! | sgr RA, RD // Negative result!
| sllg TMP1, RA, 3(r0) | sllg TMPR1, RA, 3(r0)
| lay BASE, 0(TMP1, BASE) // Correct top. | lay BASE, 0(TMPR1, BASE) // Correct top.
| j <5 | j <5
| |
|8: // Corner case: need to grow stack for filling up results. |8: // Corner case: need to grow stack for filling up results.
@ -378,8 +400,8 @@ static void build_subroutines(BuildCtx *ctx)
|->vm_unwind_c_eh: // Landing pad for external unwinder. |->vm_unwind_c_eh: // Landing pad for external unwinder.
| lg L:RB, SAVE_L | lg L:RB, SAVE_L
| lg GL:RB, L:RB->glref | lg GL:RB, L:RB->glref
| lghi TMP1, ~LJ_VMST_C | lghi TMPR1, ~LJ_VMST_C
| stg TMP1, GL:RB->vmstate | stg TMPR1, GL:RB->vmstate
| j ->vm_leave_unw | j ->vm_leave_unw
| |
|->vm_unwind_rethrow: |->vm_unwind_rethrow:
@ -448,7 +470,7 @@ static void build_subroutines(BuildCtx *ctx)
| aghi DISPATCH, GG_G2DISP | aghi DISPATCH, GG_G2DISP
| stg RD, SAVE_PC // Any value outside of bytecode is ok. | stg RD, SAVE_PC // Any value outside of bytecode is ok.
| stg RD, SAVE_CFRAME | stg RD, SAVE_CFRAME
| stg RD, SAVE_NRES | st RD, SAVE_NRES
| stg RD, SAVE_ERRF | stg RD, SAVE_ERRF
| stg KBASE, L:RB->cframe | stg KBASE, L:RB->cframe
| clm RD, 1, L:RB->status | clm RD, 1, L:RB->status
@ -484,8 +506,7 @@ static void build_subroutines(BuildCtx *ctx)
| lghi PC, FRAME_C | lghi PC, FRAME_C
| |
|1: // Entry point for vm_pcall above (PC = ftype). |1: // Entry point for vm_pcall above (PC = ftype).
| lgfr CARG3, CARG3 | st CARG3, SAVE_NRES
| stg CARG3, SAVE_NRES
| lgr L:RB, CARG1 | lgr L:RB, CARG1
| stg CARG1, SAVE_L | stg CARG1, SAVE_L
| lgr RA, CARG2 | lgr RA, CARG2
@ -531,7 +552,7 @@ static void build_subroutines(BuildCtx *ctx)
| lg DISPATCH, L:LREG->glref // Setup pointer to dispatch table. | lg DISPATCH, L:LREG->glref // Setup pointer to dispatch table.
| lghi RA, 0 | lghi RA, 0
| stg RA, SAVE_ERRF // No error function. | stg RA, SAVE_ERRF // No error function.
| stg KBASE, SAVE_NRES // Neg. delta means cframe w/o frame. | st KBASE, SAVE_NRES // Neg. delta means cframe w/o frame.
| aghi DISPATCH, GG_G2DISP | aghi DISPATCH, GG_G2DISP
| // Handler may change cframe_nres(L->cframe) or cframe_errfunc(L->cframe). | // Handler may change cframe_nres(L->cframe) or cframe_errfunc(L->cframe).
| |
@ -1081,8 +1102,13 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
| stg r0, 0(r0) | stg r0, 0(r0)
break; break;
case BC_KSHORT: case BC_KSHORT:
| stg r0, 0(r0) | ins_AD // RA = dst, RD = signed int16 literal
| stg r0, 0(r0) | // Assumes DUALNUM.
| lhr RD, RD // Sign-extend literal to 32-bits.
| setint RD
| sllg TMPR1, RA, 3(r0)
| stg RD, 0(RA, BASE)
| ins_next
break; break;
case BC_KNUM: case BC_KNUM:
| stg r0, 0(r0) | stg r0, 0(r0)
@ -1132,21 +1158,67 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
| stg r0, 0(r0) | stg r0, 0(r0)
| stg r0, 0(r0) | stg r0, 0(r0)
break; break;
case BC_GGET: case BC_GGET:
| stg r0, 0(r0) | ins_AND // RA = dst, RD = str const (~)
| stg r0, 0(r0) | lg LFUNC:RB, -16(BASE)
| cleartp LFUNC:RB
| lg TAB:RB, LFUNC:RB->env
| sllg TMPR1, RD, 3(r0)
| lg STR:RC, 0(TMPR1, KBASE)
| j ->BC_TGETS_Z
break; break;
case BC_GSET: case BC_GSET:
| stg r0, 0(r0) | ins_AND // RA = src, RD = str const (~)
| stg r0, 0(r0) | lg LFUNC:RB, -16(BASE)
| cleartp LFUNC:RB
| lg TAB:RB, LFUNC:RB->env
| sllg TMPR1, RD, 3(r0)
| lg STR:RC, 0(TMPR1, KBASE)
| j ->BC_TSETS_Z
break; break;
case BC_TGETV: case BC_TGETV:
| stg r0, 0(r0) | stg r0, 0(r0)
| stg r0, 0(r0) | stg r0, 0(r0)
break; break;
case BC_TGETS: case BC_TGETS:
| stg r0, 0(r0) | stg r0, 0(r0) // Not yet implemented.
| stg r0, 0(r0) |
|->BC_TGETS_Z: // RB = GCtab *, RC = GCstr *
| l TMPR1, TAB:RB->hmask
| n TMPR1, STR:RC->hash
| lgfr TMPR1, TMPR1
| mghi TMPR1, #NODE // TODO: not sure about this one, original: imul TMPRd, #NODE
| ag NODE:TMPR1, TAB:RB->node
| settp ITYPE, STR:RC, LJ_TSTR
|1:
| cg ITYPE, NODE:TMPR1->key
| jne >4
| // Get node value.
| lg ITYPE, NODE:TMPR1->val
| cghi ITYPE, LJ_TNIL
| je >5 // Key found, but nil value?
|2:
| sllg RA, RA, 3(r0)
| stg ITYPE, 0(TMPR1, RA)
| ins_next
|
|4: // Follow hash chain.
| lg NODE:TMPR1, NODE:TMPR1->next
| cghi NODE:TMPR1, 0
| jne <1
| // End of hash chain: key not found, nil result.
| lghi ITYPE, LJ_TNIL
|
|5: // Check for __index if table value is nil.
| lg TAB:TMPR1, TAB:RB->metatable
| cghi TAB:TMPR1, 0
| je <2 // No metatable: done.
| llgc TMPR2, TAB:TMPR1->nomm
| tmll TMPR2, 1<<MM_index
| jne <2 // 'no __index' flag set: done.
| j ->vmeta_tgets // Caveat: preserve STR:RC.
break; break;
case BC_TGETB: case BC_TGETB:
| stg r0, 0(r0) | stg r0, 0(r0)
@ -1162,7 +1234,73 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
break; break;
case BC_TSETS: case BC_TSETS:
| stg r0, 0(r0) | stg r0, 0(r0)
| stg r0, 0(r0) |
|->BC_TSETS_Z: // RB = GCtab *, RC = GCstr *
| l TMPR1, TAB:RB->hmask
| n TMPR1, STR:RC->hash
| lgfr TMPR1, TMPR1
| mghi TMPR1, #NODE
| xr TMPR2, TMPR2
| stc TMPR2, TAB:RB->nomm // Clear metamethod cache.
| ag NODE:TMPR1, TAB:RB->node
| settp ITYPE, STR:RC, LJ_TSTR
|1:
| cg ITYPE, NODE:TMPR1->key
| jne >5
| // Ok, key found. Assumes: offsetof(Node, val) == 0
| lghi TMPR2, LJ_TNIL
| cg TMPR2, 0(TMPR1)
| je >4 // Previous value is nil?
|2:
| llgc TMPR2, TAB:RB->marked
| tmll TMPR2, LJ_GC_BLACK // isblack(table)
| jne >7
|3: // Set node value.
| sllg RA, RA, 3(r0)
| lg ITYPE, 0(RA, BASE)
| stg ITYPE, 0(TMPR1)
| ins_next
|
|4: // Check for __newindex if previous value is nil.
| lg TAB:ITYPE, TAB:RB->metatable
| cghi TAB:ITYPE, 0
| je <2
| llgc TMPR2, TAB:ITYPE->nomm
| tmll TMPR2, 1<<MM_newindex
| je ->vmeta_tsets // 'no __newindex' flag NOT set: check.
| j <2
|
|5: // Follow hash chain.
| lg NODE:TMPR1, NODE:TMPR1->next
| cghi NODE:TMPR1, 0
| jne <1
| // End of hash chain: key not found, add a new one.
|
| // But check for __newindex first.
| lg TAB:TMPR1, TAB:RB->metatable
| cghi TAB:TMPR1, 0
| je >6 // No metatable: continue.
| llgc TMPR2, TAB:TMPR1->nomm
| tmll TMPR2, 1<<MM_newindex
| je ->vmeta_tsets // 'no __newindex' flag NOT set: check.
|6:
| stg ITYPE, TMP_STACK
| lg L:CARG1, SAVE_L
| stg BASE, L:CARG1->base
| la CARG3, TMP_STACK // TODO: lea CARG3, ITYPE... not sure.
| lgr CARG2, TAB:RB
| stg PC, SAVE_PC
| brasl r14, extern lj_tab_newkey // (lua_State *L, GCtab *t, TValue *k)
| // Handles write barrier for the new key. TValue * returned in r2 (CRET1).
| lgr TMPR1, CRET1
| lg L:CRET1, SAVE_L
| lg BASE, L:CRET1->base
| llgc RA, PC_RA
| j <2 // Must check write barrier for value.
|
|7: // Possible table write barrier for the value. Skip valiswhite check.
| barrierback TAB:RB, ITYPE
| j <3
break; break;
case BC_TSETB: case BC_TSETB:
| stg r0, 0(r0) | stg r0, 0(r0)
@ -1245,8 +1383,8 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
/* fallthrough */ /* fallthrough */
case BC_RET0: case BC_RET0:
|5: |5:
| llgc TMP1, PC_RB | llgc TMPR1, PC_RB
| cgr TMP1, RD | cgr TMPR1, RD
| jh >6 | jh >6
default: default:
break; break;
@ -1262,13 +1400,13 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
| ins_next | ins_next
| |
|6: // Fill up results with nil. |6: // Fill up results with nil.
| lghi TMP1, LJ_TNIL | lghi TMPR1, LJ_TNIL
if (op == BC_RET) { if (op == BC_RET) {
| stg TMP1, -16(KBASE) // Note: relies on shifted base. | stg TMPR1, -16(KBASE) // Note: relies on shifted base.
| la KBASE, 8(KBASE) | la KBASE, 8(KBASE)
} else { } else {
| sllg RC, RD, 3(r0) // RC used as temp. | sllg RC, RD, 3(r0) // RC used as temp.
| stg TMP1, -24(RC, BASE) | stg TMPR1, -24(RC, BASE)
} }
| la RD, 1(RD) | la RD, 1(RD)
| j <5 | j <5
@ -1348,13 +1486,61 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
| stg r0, 0(r0) | stg r0, 0(r0)
| stg r0, 0(r0) | stg r0, 0(r0)
break; break;
case BC_JFUNCV: case BC_JFUNCV:
| stg r0, 0(r0) #if !LJ_HASJIT
| stg r0, 0(r0)
break; break;
#endif
| stg r0, 0(r0) // NYI: compiled vararg functions
break; /* NYI: compiled vararg functions. */
case BC_IFUNCV: case BC_IFUNCV:
| stg r0, 0(r0) // Not implemented, seg fault. | ins_AD // BASE = new base, RA = framesize, RD = nargs+1
| stg r0, 0(r0) | sllg TMPR1, NARGS:RD, 3(r0)
| la RB, (FRAME_VARG+8)(TMPR1)
| la RD, 8(TMPR1, BASE)
| lg LFUNC:KBASE, -16(BASE)
| stg RB, -8(RD) // Store delta + FRAME_VARG.
| stg LFUNC:KBASE, -16(RD) // Store copy of LFUNC.
| lg L:RB, SAVE_L
| sllg RA, RA, 3(r0)
| la RA, 0(RA, RD)
| cg RA, L:RB->maxstack
| jh ->vm_growstack_v // Need to grow stack.
| lgr RA, BASE
| lgr BASE, RD
| llgc RB, (PC2PROTO(numparams)-4)(PC)
| cghi RB, 0
| je >2
| aghi RA, 8
| lghi TMPR1, LJ_TNIL
|1: // Copy fixarg slots up to new frame.
| la RA, 8(RA)
| cgr RA, BASE
| jnl >3 // Less args than parameters?
| lg KBASE, -16(RA)
| stg KBASE, 0(RD)
| la RD, 8(RD)
| stg TMPR1, -16(RA) // Clear old fixarg slot (help the GC).
| aghi RB, -1
| jne <1
| // TODO: brctg instead of decrement/branch
|2:
if (op == BC_JFUNCV) {
| llgh RD, PC_RD
| j =>BC_JLOOP
} else {
| lg KBASE, (PC2PROTO(k)-4)(PC)
| ins_next
}
|
|3: // Clear missing parameters.
| stg TMPR1, 0(RD) // TMPR1=LJ_TNIL (-1) here.
| la RD, 8(RD)
| aghi RB, -1
| jne <3
| // TODO: brctg instead of decrement/branch
| j <2
break; break;
case BC_FUNCC: case BC_FUNCC:
@ -1380,16 +1566,16 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop)
| basr r14, KBASE // (lua_State *L) | basr r14, KBASE // (lua_State *L)
} else { } else {
| // (lua_State *L, lua_CFunction f) | // (lua_State *L, lua_CFunction f)
| lg TMP1, (DISPATCH_GL(wrapf))(DISPATCH) | lg TMPR1, (DISPATCH_GL(wrapf))(DISPATCH)
| basr r14, TMP1 // TODO: TMP1==r14, is this ok? | basr r14, TMPR1 // TODO: TMPR1==r14, is this ok?
} }
| // nresults returned in r2 (CRET1). | // nresults returned in r2 (CRET1).
| lgr RD, CRET1 | lgr RD, CRET1
| lg BASE, L:RB->base | lg BASE, L:RB->base
| stg L:RB, (DISPATCH_GL(cur_L))(DISPATCH) | stg L:RB, (DISPATCH_GL(cur_L))(DISPATCH)
| set_vmstate INTERP | set_vmstate INTERP
| sllg TMP1, RD, 3(r0) | sllg TMPR1, RD, 3(r0)
| la RA, 0(TMP1, BASE) | la RA, 0(TMPR1, BASE)
| lcgr RA, RA | lcgr RA, RA
| ag RA, L:RB->top // RA = (L->top-(L->base+nresults))*8 | ag RA, L:RB->top // RA = (L->top-(L->base+nresults))*8
| lg PC, -8(BASE) // Fetch PC of caller. | lg PC, -8(BASE) // Fetch PC of caller.