From 7ed120b7041c0d18a03948373bb96f85863e24fc Mon Sep 17 00:00:00 2001 From: Lobby Date: Tue, 1 Sep 2020 10:27:13 +0200 Subject: [PATCH 1/3] Update LuaClosure.java Re-use stack frames in LuaClosure if possible to reduce number of allocations per function call --- src/core/org/luaj/vm2/LuaClosure.java | 85 +++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 12 deletions(-) diff --git a/src/core/org/luaj/vm2/LuaClosure.java b/src/core/org/luaj/vm2/LuaClosure.java index 46a3556f..a2a0658a 100644 --- a/src/core/org/luaj/vm2/LuaClosure.java +++ b/src/core/org/luaj/vm2/LuaClosure.java @@ -23,6 +23,9 @@ package org.luaj.vm2; import org.luaj.vm2.lib.DebugLib.CallFrame; +import java.util.ArrayList; +import java.util.List; + /** * Extension of {@link LuaFunction} which executes lua bytecode. *

@@ -128,44 +131,98 @@ public class LuaClosure extends LuaFunction { public String tojstring() { return "function: " + p.toString(); } - + + + private List stackPool = new ArrayList<>(); private LuaValue[] getNewStack() { + if (stackPool.isEmpty()) { + return getNewStackRaw(); + } else { + return stackPool.remove(stackPool.size() - 1); + } + } + + private LuaValue[] getNewStackRaw() { int max = p.maxstacksize; LuaValue[] stack = new LuaValue[max]; System.arraycopy(NILS, 0, stack, 0, max); return stack; } + + private void releaseStack(LuaValue[] stack) { + System.arraycopy(NILS, 0, stack, 0, stack.length); + stackPool.add(stack); + } public final LuaValue call() { LuaValue[] stack = getNewStack(); - return execute(stack,NONE).arg1(); + LuaValue result = execute(stack,NONE).arg1(); + releaseStack(stack); + return result; } public final LuaValue call(LuaValue arg) { LuaValue[] stack = getNewStack(); + LuaValue result; switch ( p.numparams ) { - default: stack[0]=arg; return execute(stack,NONE).arg1(); - case 0: return execute(stack,arg).arg1(); + default: + 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) { LuaValue[] stack = getNewStack(); + LuaValue result; switch ( p.numparams ) { - default: stack[0]=arg1; stack[1]=arg2; return execute(stack,NONE).arg1(); - case 1: stack[0]=arg1; return execute(stack,arg2).arg1(); - case 0: return execute(stack,p.is_vararg!=0? varargsOf(arg1,arg2): NONE).arg1(); + default: + stack[0]=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) { LuaValue[] stack = getNewStack(); + LuaValue result; switch ( p.numparams ) { - default: stack[0]=arg1; stack[1]=arg2; stack[2]=arg3; return execute(stack,NONE).arg1(); - case 2: stack[0]=arg1; stack[1]=arg2; return execute(stack,arg3).arg1(); - case 1: stack[0]=arg1; return execute(stack,p.is_vararg!=0? varargsOf(arg2,arg3): NONE).arg1(); - case 0: return execute(stack,p.is_vararg!=0? varargsOf(arg1,arg2,arg3): NONE).arg1(); + default: + stack[0]=arg1; + stack[1]=arg2; + 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) { @@ -176,7 +233,11 @@ public class LuaClosure extends LuaFunction { LuaValue[] stack = getNewStack(); for ( int i=0; i Date: Tue, 1 Sep 2020 10:29:49 +0200 Subject: [PATCH 2/3] Revert "Update LuaClosure.java" This reverts commit 7ed120b7041c0d18a03948373bb96f85863e24fc. --- src/core/org/luaj/vm2/LuaClosure.java | 85 ++++----------------------- 1 file changed, 12 insertions(+), 73 deletions(-) diff --git a/src/core/org/luaj/vm2/LuaClosure.java b/src/core/org/luaj/vm2/LuaClosure.java index a2a0658a..46a3556f 100644 --- a/src/core/org/luaj/vm2/LuaClosure.java +++ b/src/core/org/luaj/vm2/LuaClosure.java @@ -23,9 +23,6 @@ package org.luaj.vm2; import org.luaj.vm2.lib.DebugLib.CallFrame; -import java.util.ArrayList; -import java.util.List; - /** * Extension of {@link LuaFunction} which executes lua bytecode. *

@@ -131,98 +128,44 @@ public class LuaClosure extends LuaFunction { public String tojstring() { return "function: " + p.toString(); } - - - private List stackPool = new ArrayList<>(); + private LuaValue[] getNewStack() { - if (stackPool.isEmpty()) { - return getNewStackRaw(); - } else { - return stackPool.remove(stackPool.size() - 1); - } - } - - private LuaValue[] getNewStackRaw() { int max = p.maxstacksize; LuaValue[] stack = new LuaValue[max]; System.arraycopy(NILS, 0, stack, 0, max); return stack; } - - private void releaseStack(LuaValue[] stack) { - System.arraycopy(NILS, 0, stack, 0, stack.length); - stackPool.add(stack); - } public final LuaValue call() { LuaValue[] stack = getNewStack(); - LuaValue result = execute(stack,NONE).arg1(); - releaseStack(stack); - return result; + return execute(stack,NONE).arg1(); } public final LuaValue call(LuaValue arg) { LuaValue[] stack = getNewStack(); - LuaValue result; switch ( p.numparams ) { - default: - stack[0]=arg; - result = execute(stack,NONE).arg1(); - break; - case 0: - result = execute(stack,arg).arg1(); - break; + default: stack[0]=arg; return execute(stack,NONE).arg1(); + case 0: return execute(stack,arg).arg1(); } - releaseStack(stack); - return result; } public final LuaValue call(LuaValue arg1, LuaValue arg2) { LuaValue[] stack = getNewStack(); - LuaValue result; switch ( p.numparams ) { - default: - stack[0]=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; + default: stack[0]=arg1; stack[1]=arg2; return execute(stack,NONE).arg1(); + case 1: stack[0]=arg1; return execute(stack,arg2).arg1(); + case 0: return execute(stack,p.is_vararg!=0? varargsOf(arg1,arg2): NONE).arg1(); } - releaseStack(stack); - return result; } public final LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) { LuaValue[] stack = getNewStack(); - LuaValue result; switch ( p.numparams ) { - default: - stack[0]=arg1; - stack[1]=arg2; - 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; + default: stack[0]=arg1; stack[1]=arg2; stack[2]=arg3; return execute(stack,NONE).arg1(); + case 2: stack[0]=arg1; stack[1]=arg2; return execute(stack,arg3).arg1(); + case 1: stack[0]=arg1; return execute(stack,p.is_vararg!=0? varargsOf(arg2,arg3): NONE).arg1(); + case 0: return execute(stack,p.is_vararg!=0? varargsOf(arg1,arg2,arg3): NONE).arg1(); } - releaseStack(stack); - return result; } public final Varargs invoke(Varargs varargs) { @@ -233,11 +176,7 @@ public class LuaClosure extends LuaFunction { LuaValue[] stack = getNewStack(); for ( int i=0; i Date: Tue, 1 Sep 2020 10:38:36 +0200 Subject: [PATCH 3/3] Reduce allocations per LuaClosure call Every call of a LuaClosure issues creation of a new stack frame for the function execution. Since this stack is usually thrown away after execution pooling them can help to reduce garbage collection overhead (there's one exception to this: the stack can be used as part of the returned varargs object, in that case it cannot be reused since that could cause conflicts). In my use case this change was a useful for calling a lot of Lua functions on a mobile device. --- src/core/org/luaj/vm2/LuaClosure.java | 85 +++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 12 deletions(-) diff --git a/src/core/org/luaj/vm2/LuaClosure.java b/src/core/org/luaj/vm2/LuaClosure.java index 46a3556f..a2a0658a 100644 --- a/src/core/org/luaj/vm2/LuaClosure.java +++ b/src/core/org/luaj/vm2/LuaClosure.java @@ -23,6 +23,9 @@ package org.luaj.vm2; import org.luaj.vm2.lib.DebugLib.CallFrame; +import java.util.ArrayList; +import java.util.List; + /** * Extension of {@link LuaFunction} which executes lua bytecode. *

@@ -128,44 +131,98 @@ public class LuaClosure extends LuaFunction { public String tojstring() { return "function: " + p.toString(); } - + + + private List stackPool = new ArrayList<>(); private LuaValue[] getNewStack() { + if (stackPool.isEmpty()) { + return getNewStackRaw(); + } else { + return stackPool.remove(stackPool.size() - 1); + } + } + + private LuaValue[] getNewStackRaw() { int max = p.maxstacksize; LuaValue[] stack = new LuaValue[max]; System.arraycopy(NILS, 0, stack, 0, max); return stack; } + + private void releaseStack(LuaValue[] stack) { + System.arraycopy(NILS, 0, stack, 0, stack.length); + stackPool.add(stack); + } public final LuaValue call() { LuaValue[] stack = getNewStack(); - return execute(stack,NONE).arg1(); + LuaValue result = execute(stack,NONE).arg1(); + releaseStack(stack); + return result; } public final LuaValue call(LuaValue arg) { LuaValue[] stack = getNewStack(); + LuaValue result; switch ( p.numparams ) { - default: stack[0]=arg; return execute(stack,NONE).arg1(); - case 0: return execute(stack,arg).arg1(); + default: + 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) { LuaValue[] stack = getNewStack(); + LuaValue result; switch ( p.numparams ) { - default: stack[0]=arg1; stack[1]=arg2; return execute(stack,NONE).arg1(); - case 1: stack[0]=arg1; return execute(stack,arg2).arg1(); - case 0: return execute(stack,p.is_vararg!=0? varargsOf(arg1,arg2): NONE).arg1(); + default: + stack[0]=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) { LuaValue[] stack = getNewStack(); + LuaValue result; switch ( p.numparams ) { - default: stack[0]=arg1; stack[1]=arg2; stack[2]=arg3; return execute(stack,NONE).arg1(); - case 2: stack[0]=arg1; stack[1]=arg2; return execute(stack,arg3).arg1(); - case 1: stack[0]=arg1; return execute(stack,p.is_vararg!=0? varargsOf(arg2,arg3): NONE).arg1(); - case 0: return execute(stack,p.is_vararg!=0? varargsOf(arg1,arg2,arg3): NONE).arg1(); + default: + stack[0]=arg1; + stack[1]=arg2; + 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) { @@ -176,7 +233,11 @@ public class LuaClosure extends LuaFunction { LuaValue[] stack = getNewStack(); for ( int i=0; i