Pull request: Reduce allocations per LuaClosure call #76

This commit is contained in:
UnlegitDqrk
2026-03-01 13:06:19 +01:00
parent f30c4c3bec
commit 37b68d4d85

View File

@@ -1,28 +1,31 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved. * Copyright (c) 2009 Luaj.org. All rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights * in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2; package org.luaj.vm2;
import org.luaj.vm2.libs.DebugLib.CallFrame; import org.luaj.vm2.libs.DebugLib.CallFrame;
import java.util.ArrayList;
import java.util.List;
/** /**
* Extension of {@link LuaFunction} which executes lua bytecode. * Extension of {@link LuaFunction} which executes lua bytecode.
* <p> * <p>
@@ -129,43 +132,97 @@ public class LuaClosure extends LuaFunction {
return "function: " + p.toString(); return "function: " + p.toString();
} }
private List<LuaValue[]> stackPool = new ArrayList<>();
private LuaValue[] getNewStack() { private LuaValue[] getNewStack() {
if (stackPool.isEmpty()) {
return getNewStackRaw();
} else {
return stackPool.remove(stackPool.size() - 1);
}
}
private LuaValue[] getNewStackRaw() {
int max = p.maxstacksize; int max = p.maxstacksize;
LuaValue[] stack = new LuaValue[max]; LuaValue[] stack = new LuaValue[max];
System.arraycopy(NILS, 0, stack, 0, max); System.arraycopy(NILS, 0, stack, 0, max);
return stack; return stack;
} }
private void releaseStack(LuaValue[] stack) {
System.arraycopy(NILS, 0, stack, 0, stack.length);
stackPool.add(stack);
}
public final LuaValue call() { public final LuaValue call() {
LuaValue[] stack = getNewStack(); LuaValue[] stack = getNewStack();
return execute(stack,NONE).arg1(); LuaValue result = execute(stack,NONE).arg1();
releaseStack(stack);
return result;
} }
public final LuaValue call(LuaValue arg) { public final LuaValue call(LuaValue arg) {
LuaValue[] stack = getNewStack(); LuaValue[] stack = getNewStack();
LuaValue result;
switch ( p.numparams ) { switch ( p.numparams ) {
default: stack[0]=arg; return execute(stack,NONE).arg1(); default:
case 0: return execute(stack,arg).arg1(); stack[0]=arg;
result = execute(stack,NONE).arg1();
break;
case 0:
result = execute(stack,arg).arg1();
break;
} }
releaseStack(stack);
return result;
} }
public final LuaValue call(LuaValue arg1, LuaValue arg2) { public final LuaValue call(LuaValue arg1, LuaValue arg2) {
LuaValue[] stack = getNewStack(); LuaValue[] stack = getNewStack();
LuaValue result;
switch ( p.numparams ) { switch ( p.numparams ) {
default: stack[0]=arg1; stack[1]=arg2; return execute(stack,NONE).arg1(); default:
case 1: stack[0]=arg1; return execute(stack,arg2).arg1(); stack[0]=arg1;
case 0: return execute(stack,p.is_vararg!=0? varargsOf(arg1,arg2): NONE).arg1(); stack[1]=arg2;
result = execute(stack,NONE).arg1();
break;
case 1:
stack[0]=arg1;
result = execute(stack,arg2).arg1();
break;
case 0:
result = execute(stack,p.is_vararg!=0 ? varargsOf(arg1,arg2) : NONE).arg1();
break;
} }
releaseStack(stack);
return result;
} }
public final LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) { public final LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
LuaValue[] stack = getNewStack(); LuaValue[] stack = getNewStack();
LuaValue result;
switch ( p.numparams ) { switch ( p.numparams ) {
default: stack[0]=arg1; stack[1]=arg2; stack[2]=arg3; return execute(stack,NONE).arg1(); default:
case 2: stack[0]=arg1; stack[1]=arg2; return execute(stack,arg3).arg1(); stack[0]=arg1;
case 1: stack[0]=arg1; return execute(stack,p.is_vararg!=0? varargsOf(arg2,arg3): NONE).arg1(); stack[1]=arg2;
case 0: return execute(stack,p.is_vararg!=0? varargsOf(arg1,arg2,arg3): NONE).arg1(); stack[2]=arg3;
result = execute(stack,NONE).arg1();
break;
case 2:
stack[0]=arg1;
stack[1]=arg2;
result = execute(stack,arg3).arg1();
break;
case 1:
stack[0]=arg1;
result = execute(stack,p.is_vararg!=0 ? varargsOf(arg2,arg3) : NONE).arg1();
break;
case 0:
result = execute(stack,p.is_vararg!=0 ? varargsOf(arg1,arg2,arg3) : NONE).arg1();
break;
} }
releaseStack(stack);
return result;
} }
public final Varargs invoke(Varargs varargs) { public final Varargs invoke(Varargs varargs) {
@@ -176,7 +233,11 @@ public class LuaClosure extends LuaFunction {
LuaValue[] stack = getNewStack(); LuaValue[] stack = getNewStack();
for ( int i=0; i<p.numparams; i++ ) for ( int i=0; i<p.numparams; i++ )
stack[i] = varargs.arg(i+1); stack[i] = varargs.arg(i+1);
return execute(stack,p.is_vararg!=0? varargs.subargs(p.numparams+1): NONE); Varargs result = execute(stack,p.is_vararg!=0 ? varargs.subargs(p.numparams+1) : NONE);
if (result instanceof LuaValue) {
releaseStack(stack);
}
return result;
} }
protected Varargs execute( LuaValue[] stack, Varargs varargs ) { protected Varargs execute( LuaValue[] stack, Varargs varargs ) {
@@ -208,108 +269,108 @@ public class LuaClosure extends LuaFunction {
// process the op code // process the op code
switch ( i & 0x3f ) { switch ( i & 0x3f ) {
case Lua.OP_MOVE:/* A B R(A):= R(B) */ case Lua.OP_MOVE:/* A B R(A):= R(B) */
stack[a] = stack[i>>>23]; stack[a] = stack[i>>>23];
continue; continue;
case Lua.OP_LOADK:/* A Bx R(A):= Kst(Bx) */ case Lua.OP_LOADK:/* A Bx R(A):= Kst(Bx) */
stack[a] = k[i>>>14]; stack[a] = k[i>>>14];
continue; continue;
case Lua.OP_LOADKX:/* A R(A) := Kst(extra arg) */ case Lua.OP_LOADKX:/* A R(A) := Kst(extra arg) */
++pc; ++pc;
i = code[pc]; i = code[pc];
if ((i & 0x3f) != Lua.OP_EXTRAARG) { if ((i & 0x3f) != Lua.OP_EXTRAARG) {
int op = i & 0x3f; int op = i & 0x3f;
throw new LuaError("OP_EXTRAARG expected after OP_LOADKX, got " + throw new LuaError("OP_EXTRAARG expected after OP_LOADKX, got " +
(op < Print.OPNAMES.length - 1 ? Print.OPNAMES[op] : "UNKNOWN_OP_" + op)); (op < Print.OPNAMES.length - 1 ? Print.OPNAMES[op] : "UNKNOWN_OP_" + op));
} }
stack[a] = k[i>>>6]; stack[a] = k[i>>>6];
continue; continue;
case Lua.OP_LOADBOOL:/* A B C R(A):= (Bool)B: if (C) pc++ */ case Lua.OP_LOADBOOL:/* A B C R(A):= (Bool)B: if (C) pc++ */
stack[a] = (i>>>23!=0)? LuaValue.TRUE: LuaValue.FALSE; stack[a] = (i>>>23!=0)? LuaValue.TRUE: LuaValue.FALSE;
if ((i&(0x1ff<<14)) != 0) if ((i&(0x1ff<<14)) != 0)
++pc; /* skip next instruction (if C) */ ++pc; /* skip next instruction (if C) */
continue; continue;
case Lua.OP_LOADNIL: /* A B R(A):= ...:= R(A+B):= nil */ case Lua.OP_LOADNIL: /* A B R(A):= ...:= R(A+B):= nil */
for ( b=i>>>23; b-->=0; ) for ( b=i>>>23; b-->=0; )
stack[a++] = LuaValue.NIL; stack[a++] = LuaValue.NIL;
continue; continue;
case Lua.OP_GETUPVAL: /* A B R(A):= UpValue[B] */ case Lua.OP_GETUPVAL: /* A B R(A):= UpValue[B] */
stack[a] = upValues[i>>>23].getValue(); stack[a] = upValues[i>>>23].getValue();
continue; continue;
case Lua.OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */ case Lua.OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */
stack[a] = upValues[i>>>23].getValue().get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); stack[a] = upValues[i>>>23].getValue().get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue; continue;
case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */ case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */
stack[a] = stack[i>>>23].get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); stack[a] = stack[i>>>23].get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue; continue;
case Lua.OP_SETTABUP: /* A B C UpValue[A][RK(B)] := RK(C) */ case Lua.OP_SETTABUP: /* A B C UpValue[A][RK(B)] := RK(C) */
upValues[a].getValue().set(((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]), (c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); upValues[a].getValue().set(((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]), (c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue; continue;
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */ case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
upValues[i>>>23].setValue(stack[a]); upValues[i>>>23].setValue(stack[a]);
continue; continue;
case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */ case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */
stack[a].set(((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]), (c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); stack[a].set(((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]), (c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue; continue;
case Lua.OP_NEWTABLE: /* A B C R(A):= {} (size = B,C) */ case Lua.OP_NEWTABLE: /* A B C R(A):= {} (size = B,C) */
stack[a] = new LuaTable(i>>>23,(i>>14)&0x1ff); stack[a] = new LuaTable(i>>>23,(i>>14)&0x1ff);
continue; continue;
case Lua.OP_SELF: /* A B C R(A+1):= R(B): R(A):= R(B)[RK(C)] */ case Lua.OP_SELF: /* A B C R(A+1):= R(B): R(A):= R(B)[RK(C)] */
stack[a+1] = (o = stack[i>>>23]); stack[a+1] = (o = stack[i>>>23]);
stack[a] = o.get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); stack[a] = o.get((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue; continue;
case Lua.OP_ADD: /* A B C R(A):= RK(B) + RK(C) */ case Lua.OP_ADD: /* A B C R(A):= RK(B) + RK(C) */
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).add((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).add((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue; continue;
case Lua.OP_SUB: /* A B C R(A):= RK(B) - RK(C) */ case Lua.OP_SUB: /* A B C R(A):= RK(B) - RK(C) */
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).sub((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).sub((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue; continue;
case Lua.OP_MUL: /* A B C R(A):= RK(B) * RK(C) */ case Lua.OP_MUL: /* A B C R(A):= RK(B) * RK(C) */
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).mul((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).mul((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue; continue;
case Lua.OP_DIV: /* A B C R(A):= RK(B) / RK(C) */ case Lua.OP_DIV: /* A B C R(A):= RK(B) / RK(C) */
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).div((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).div((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue; continue;
case Lua.OP_MOD: /* A B C R(A):= RK(B) % RK(C) */ case Lua.OP_MOD: /* A B C R(A):= RK(B) % RK(C) */
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).mod((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).mod((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue; continue;
case Lua.OP_POW: /* A B C R(A):= RK(B) ^ RK(C) */ case Lua.OP_POW: /* A B C R(A):= RK(B) ^ RK(C) */
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).pow((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).pow((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue; continue;
case Lua.OP_UNM: /* A B R(A):= -R(B) */ case Lua.OP_UNM: /* A B R(A):= -R(B) */
stack[a] = stack[i>>>23].neg(); stack[a] = stack[i>>>23].neg();
continue; continue;
case Lua.OP_NOT: /* A B R(A):= not R(B) */ case Lua.OP_NOT: /* A B R(A):= not R(B) */
stack[a] = stack[i>>>23].not(); stack[a] = stack[i>>>23].not();
continue; continue;
case Lua.OP_LEN: /* A B R(A):= length of R(B) */ case Lua.OP_LEN: /* A B R(A):= length of R(B) */
stack[a] = stack[i>>>23].len(); stack[a] = stack[i>>>23].len();
continue; continue;
case Lua.OP_CONCAT: /* A B C R(A):= R(B).. ... ..R(C) */ case Lua.OP_CONCAT: /* A B C R(A):= R(B).. ... ..R(C) */
b = i>>>23; b = i>>>23;
c = (i>>14)&0x1ff; c = (i>>14)&0x1ff;
{ {
if ( c > b+1 ) { if ( c > b+1 ) {
Buffer sb = stack[c].buffer(); Buffer sb = stack[c].buffer();
@@ -322,111 +383,111 @@ public class LuaClosure extends LuaFunction {
} }
continue; continue;
case Lua.OP_JMP: /* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */ case Lua.OP_JMP: /* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */
pc += (i>>>14)-0x1ffff; pc += (i>>>14)-0x1ffff;
if (a > 0) { if (a > 0) {
for (--a, b = openups.length; --b>=0; ) for (--a, b = openups.length; --b>=0; )
if (openups[b] != null && openups[b].index >= a) { if (openups[b] != null && openups[b].index >= a) {
openups[b].close(); openups[b].close();
openups[b] = null; openups[b] = null;
} }
}
continue;
case Lua.OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
if ( ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).eq_b((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]) != (a!=0) )
++pc;
continue;
case Lua.OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
if ( ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).lt_b((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]) != (a!=0) )
++pc;
continue;
case Lua.OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
if ( ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).lteq_b((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]) != (a!=0) )
++pc;
continue;
case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
if ( stack[a].toboolean() != ((i&(0x1ff<<14))!=0) )
++pc;
continue;
case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A):= R(B) else pc++ */
/* note: doc appears to be reversed */
if ( (o=stack[i>>>23]).toboolean() != ((i&(0x1ff<<14))!=0) )
++pc;
else
stack[a] = o; // TODO: should be sBx?
continue;
case Lua.OP_CALL: /* A B C R(A), ... ,R(A+C-2):= R(A)(R(A+1), ... ,R(A+B-1)) */
switch ( i & (Lua.MASK_B | Lua.MASK_C) ) {
case (1<<Lua.POS_B) | (0<<Lua.POS_C): v=stack[a].invoke(NONE); top=a+v.narg(); continue;
case (2<<Lua.POS_B) | (0<<Lua.POS_C): v=stack[a].invoke(stack[a+1]); top=a+v.narg(); continue;
case (1<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(); continue;
case (2<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1]); continue;
case (3<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1],stack[a+2]); continue;
case (4<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1],stack[a+2],stack[a+3]); continue;
case (1<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(); continue;
case (2<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(stack[a+1]); continue;
case (3<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(stack[a+1],stack[a+2]); continue;
case (4<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(stack[a+1],stack[a+2],stack[a+3]); continue;
default:
b = i>>>23;
c = (i>>14)&0x1ff;
v = stack[a].invoke(b>0?
varargsOf(stack, a+1, b-1): // exact arg count
varargsOf(stack, a+1, top-v.narg()-(a+1), v)); // from prev top
if ( c > 0 ) {
v.copyto(stack, a, c-1);
v = NONE;
} else {
top = a + v.narg();
v = v.dealias();
} }
continue; continue;
}
case Lua.OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ case Lua.OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
switch ( i & Lua.MASK_B ) { if ( ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).eq_b((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]) != (a!=0) )
case (1<<Lua.POS_B): return new TailcallVarargs(stack[a], NONE); ++pc;
case (2<<Lua.POS_B): return new TailcallVarargs(stack[a], stack[a+1]); continue;
case (3<<Lua.POS_B): return new TailcallVarargs(stack[a], varargsOf(stack[a+1],stack[a+2]));
case (4<<Lua.POS_B): return new TailcallVarargs(stack[a], varargsOf(stack[a+1],stack[a+2],stack[a+3])); case Lua.OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
default: if ( ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).lt_b((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]) != (a!=0) )
++pc;
continue;
case Lua.OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
if ( ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).lteq_b((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]) != (a!=0) )
++pc;
continue;
case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
if ( stack[a].toboolean() != ((i&(0x1ff<<14))!=0) )
++pc;
continue;
case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A):= R(B) else pc++ */
/* note: doc appears to be reversed */
if ( (o=stack[i>>>23]).toboolean() != ((i&(0x1ff<<14))!=0) )
++pc;
else
stack[a] = o; // TODO: should be sBx?
continue;
case Lua.OP_CALL: /* A B C R(A), ... ,R(A+C-2):= R(A)(R(A+1), ... ,R(A+B-1)) */
switch ( i & (Lua.MASK_B | Lua.MASK_C) ) {
case (1<<Lua.POS_B) | (0<<Lua.POS_C): v=stack[a].invoke(NONE); top=a+v.narg(); continue;
case (2<<Lua.POS_B) | (0<<Lua.POS_C): v=stack[a].invoke(stack[a+1]); top=a+v.narg(); continue;
case (1<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(); continue;
case (2<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1]); continue;
case (3<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1],stack[a+2]); continue;
case (4<<Lua.POS_B) | (1<<Lua.POS_C): stack[a].call(stack[a+1],stack[a+2],stack[a+3]); continue;
case (1<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(); continue;
case (2<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(stack[a+1]); continue;
case (3<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(stack[a+1],stack[a+2]); continue;
case (4<<Lua.POS_B) | (2<<Lua.POS_C): stack[a] = stack[a].call(stack[a+1],stack[a+2],stack[a+3]); continue;
default:
b = i>>>23;
c = (i>>14)&0x1ff;
v = stack[a].invoke(b>0?
varargsOf(stack, a+1, b-1): // exact arg count
varargsOf(stack, a+1, top-v.narg()-(a+1), v)); // from prev top
if ( c > 0 ) {
v.copyto(stack, a, c-1);
v = NONE;
} else {
top = a + v.narg();
v = v.dealias();
}
continue;
}
case Lua.OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
switch ( i & Lua.MASK_B ) {
case (1<<Lua.POS_B): return new TailcallVarargs(stack[a], NONE);
case (2<<Lua.POS_B): return new TailcallVarargs(stack[a], stack[a+1]);
case (3<<Lua.POS_B): return new TailcallVarargs(stack[a], varargsOf(stack[a+1],stack[a+2]));
case (4<<Lua.POS_B): return new TailcallVarargs(stack[a], varargsOf(stack[a+1],stack[a+2],stack[a+3]));
default:
b = i>>>23;
v = b>0?
varargsOf(stack,a+1,b-1): // exact arg count
varargsOf(stack, a+1, top-v.narg()-(a+1), v); // from prev top
return new TailcallVarargs( stack[a], v );
}
case Lua.OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */
b = i>>>23; b = i>>>23;
v = b>0? switch ( b ) {
varargsOf(stack,a+1,b-1): // exact arg count case 0: return varargsOf(stack, a, top-v.narg()-a, v);
varargsOf(stack, a+1, top-v.narg()-(a+1), v); // from prev top case 1: return NONE;
return new TailcallVarargs( stack[a], v ); case 2: return stack[a];
} default:
return varargsOf(stack, a, b-1);
}
case Lua.OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */ case Lua.OP_FORLOOP: /* A sBx R(A)+=R(A+2): if R(A) <?= R(A+1) then { pc+=sBx: R(A+3)=R(A) }*/
b = i>>>23;
switch ( b ) {
case 0: return varargsOf(stack, a, top-v.narg()-a, v);
case 1: return NONE;
case 2: return stack[a];
default:
return varargsOf(stack, a, b-1);
}
case Lua.OP_FORLOOP: /* A sBx R(A)+=R(A+2): if R(A) <?= R(A+1) then { pc+=sBx: R(A+3)=R(A) }*/
{ {
LuaValue limit = stack[a + 1]; LuaValue limit = stack[a + 1];
LuaValue step = stack[a + 2]; LuaValue step = stack[a + 2];
LuaValue idx = stack[a].add(step); LuaValue idx = stack[a].add(step);
if (step.gt_b(0)? idx.lteq_b(limit): idx.gteq_b(limit)) { if (step.gt_b(0)? idx.lteq_b(limit): idx.gteq_b(limit)) {
stack[a] = idx; stack[a] = idx;
stack[a + 3] = idx; stack[a + 3] = idx;
pc += (i>>>14)-0x1ffff; pc += (i>>>14)-0x1ffff;
} }
} }
continue; continue;
case Lua.OP_FORPREP: /* A sBx R(A)-=R(A+2): pc+=sBx */ case Lua.OP_FORPREP: /* A sBx R(A)-=R(A+2): pc+=sBx */
{ {
LuaValue init = stack[a].checknumber("'for' initial value must be a number"); LuaValue init = stack[a].checknumber("'for' initial value must be a number");
LuaValue limit = stack[a + 1].checknumber("'for' limit must be a number"); LuaValue limit = stack[a + 1].checknumber("'for' limit must be a number");
@@ -438,44 +499,44 @@ public class LuaClosure extends LuaFunction {
} }
continue; continue;
case Lua.OP_TFORCALL: /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */ case Lua.OP_TFORCALL: /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
v = stack[a].invoke(varargsOf(stack[a+1],stack[a+2])); v = stack[a].invoke(varargsOf(stack[a+1],stack[a+2]));
c = (i>>14) & 0x1ff; c = (i>>14) & 0x1ff;
while (--c >= 0) while (--c >= 0)
stack[a+3+c] = v.arg(c+1); stack[a+3+c] = v.arg(c+1);
v = NONE; v = NONE;
continue; continue;
case Lua.OP_TFORLOOP: /* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx */ case Lua.OP_TFORLOOP: /* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx */
if (!stack[a+1].isnil()) { /* continue loop? */ if (!stack[a+1].isnil()) { /* continue loop? */
stack[a] = stack[a+1]; /* save control varible. */ stack[a] = stack[a+1]; /* save control varible. */
pc += (i>>>14)-0x1ffff; pc += (i>>>14)-0x1ffff;
} }
continue; continue;
case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */ case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */
{ {
if ( (c=(i>>14)&0x1ff) == 0 ) if ( (c=(i>>14)&0x1ff) == 0 )
c = code[++pc]; c = code[++pc];
int offset = (c-1) * Lua.LFIELDS_PER_FLUSH; int offset = (c-1) * Lua.LFIELDS_PER_FLUSH;
o = stack[a]; o = stack[a];
if ( (b=i>>>23) == 0 ) { if ( (b=i>>>23) == 0 ) {
b = top - a - 1; b = top - a - 1;
int m = b - v.narg(); int m = b - v.narg();
int j=1; int j=1;
for ( ;j<=m; j++ ) for ( ;j<=m; j++ )
o.set(offset+j, stack[a + j]); o.set(offset+j, stack[a + j]);
for ( ;j<=b; j++ ) for ( ;j<=b; j++ )
o.set(offset+j, v.arg(j-m)); o.set(offset+j, v.arg(j-m));
} else { } else {
o.presize( offset + b ); o.presize( offset + b );
for (int j=1; j<=b; j++) for (int j=1; j<=b; j++)
o.set(offset+j, stack[a + j]); o.set(offset+j, stack[a + j]);
} }
} }
continue; continue;
case Lua.OP_CLOSURE: /* A Bx R(A):= closure(KPROTO[Bx]) */ case Lua.OP_CLOSURE: /* A Bx R(A):= closure(KPROTO[Bx]) */
{ {
Prototype newp = p.p[i>>>14]; Prototype newp = p.p[i>>>14];
LuaClosure ncl = new LuaClosure(newp, globals); LuaClosure ncl = new LuaClosure(newp, globals);
@@ -490,22 +551,22 @@ public class LuaClosure extends LuaFunction {
} }
continue; continue;
case Lua.OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */ case Lua.OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
b = i>>>23; b = i>>>23;
if ( b == 0 ) { if ( b == 0 ) {
top = a + (b = varargs.narg()); top = a + (b = varargs.narg());
v = varargs; v = varargs;
} else { } else {
for ( int j=1; j<b; ++j ) for ( int j=1; j<b; ++j )
stack[a+j-1] = varargs.arg(j); stack[a+j-1] = varargs.arg(j);
} }
continue; continue;
case Lua.OP_EXTRAARG: case Lua.OP_EXTRAARG:
throw new IllegalArgumentException("Uexecutable opcode: OP_EXTRAARG"); throw new java.lang.IllegalArgumentException("Uexecutable opcode: OP_EXTRAARG");
default: default:
throw new IllegalArgumentException("Illegal opcode: " + (i & 0x3f)); throw new java.lang.IllegalArgumentException("Illegal opcode: " + (i & 0x3f));
} }
} }
} catch ( LuaError le ) { } catch ( LuaError le ) {