diff --git a/.classpath b/.classpath
index 4cfd46e4..7b5ef63e 100644
--- a/.classpath
+++ b/.classpath
@@ -15,5 +15,6 @@
+
diff --git a/src/core/org/luaj/vm2/LoadState.java b/src/core/org/luaj/vm2/LoadState.java
index 33577ba5..7cb03cf2 100644
--- a/src/core/org/luaj/vm2/LoadState.java
+++ b/src/core/org/luaj/vm2/LoadState.java
@@ -39,8 +39,7 @@ public class LoadState {
/** format corresponding to number-patched lua, all numbers are 32-bit (4 byte) ints */
public static final int NUMBER_FORMAT_NUM_PATCH_INT32 = 4;
- // type constants
-
+ // type constants
public static final int LUA_TINT = (-2);
public static final int LUA_TNONE = (-1);
public static final int LUA_TNIL = 0;
@@ -56,7 +55,10 @@ public class LoadState {
/** Interface for the compiler, if it is installed. */
public interface LuaCompiler {
+ /** Compile into a prototype, without taking the additional step of create a LuaFunction or LuaClosure */
public Prototype compile(int firstByte, InputStream stream, String name) throws IOException;
+ /** Load into a Closure or LuaFunction, with the supplied initial environment */
+ public LuaFunction load(int firstByte, InputStream stream, String name, LuaValue env) throws IOException;
}
/** Compiler instance, if installed */
@@ -266,12 +268,11 @@ public class LoadState {
luacNumberFormat = is.readByte();
}
- public static Prototype undump( InputStream stream, String name ) throws IOException {
- // check first byte to see if its a precompiled chunk
+ public static LuaFunction load( InputStream stream, String name, LuaValue env ) throws IOException {
int c = stream.read();
if ( c != LUA_SIGNATURE[0] ) {
if ( compiler != null )
- return compiler.compile(c, stream, name);
+ return compiler.load(c, stream, name, env);
throw new LuaError("no compiler");
}
@@ -296,7 +297,8 @@ public class LoadState {
throw new LuaError("unsupported int size");
}
- return s.loadFunction( LuaString.valueOf(sname) );
+ Prototype p = s.loadFunction( LuaString.valueOf(sname) );
+ return new LuaClosure( p, env );
}
public static String getSourceName(String name) {
diff --git a/src/core/org/luaj/vm2/LuaValue.java b/src/core/org/luaj/vm2/LuaValue.java
index efa1d2bc..74e53630 100644
--- a/src/core/org/luaj/vm2/LuaValue.java
+++ b/src/core/org/luaj/vm2/LuaValue.java
@@ -310,6 +310,7 @@ public class LuaValue extends Varargs {
// table initializers
public static LuaTable tableOf() { return new LuaTable(); }
+ public static LuaTable tableOf(int narray, int nhash) { return new LuaTable(narray, nhash); }
public static LuaTable listOf(LuaValue[] unnamedValues) { return new LuaTable(null,unnamedValues,null); }
public static LuaTable listOf(LuaValue[] unnamedValues,Varargs lastarg) { return new LuaTable(null,unnamedValues,lastarg); }
public static LuaTable tableOf(LuaValue[] namedValues) { return new LuaTable(namedValues,null,null); }
diff --git a/src/core/org/luaj/vm2/Print.java b/src/core/org/luaj/vm2/Print.java
index 12762483..afdad44d 100644
--- a/src/core/org/luaj/vm2/Print.java
+++ b/src/core/org/luaj/vm2/Print.java
@@ -299,7 +299,11 @@ public class Print extends Lua {
}
}
- public void printFunction(Prototype f, boolean full) {
+ public static void print(Prototype p) {
+ printFunction(p, true);
+ }
+
+ public static void printFunction(Prototype f, boolean full) {
int i, n = f.p.length;
printHeader(f);
printCode(f);
diff --git a/src/core/org/luaj/vm2/compiler/LuaC.java b/src/core/org/luaj/vm2/compiler/LuaC.java
index 4e9dbb64..05e2fec7 100644
--- a/src/core/org/luaj/vm2/compiler/LuaC.java
+++ b/src/core/org/luaj/vm2/compiler/LuaC.java
@@ -27,10 +27,12 @@ import java.util.Hashtable;
import org.luaj.vm2.LocVars;
import org.luaj.vm2.Lua;
+import org.luaj.vm2.LuaClosure;
import org.luaj.vm2.LuaError;
-import org.luaj.vm2.Prototype;
+import org.luaj.vm2.LuaFunction;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaValue;
+import org.luaj.vm2.Prototype;
import org.luaj.vm2.LoadState.LuaCompiler;
@@ -158,8 +160,19 @@ public class LuaC extends Lua implements LuaCompiler {
/** Utility method to invoke the compiler for an input stream
*/
- public static Prototype compile(InputStream is, String string) throws IOException {
- return new LuaC().compile(is.read(), is, string);
+ public static Prototype compile(InputStream is, String name) throws IOException {
+ return new LuaC().compile(is.read(), is, name);
+ }
+
+ /** Load into a Closure or LuaFunction, with the supplied initial environment */
+ public static LuaFunction load(InputStream is, String name, LuaValue env) throws IOException {
+ return new LuaC().load(is.read(), is, name, env);
+ }
+
+ /** Load into a Closure or LuaFunction, with the supplied initial environment */
+ public LuaFunction load(int firstByte, InputStream stream, String name, LuaValue env) throws IOException {
+ Prototype p = compile(firstByte, stream, name);
+ return new LuaClosure( p, env );
}
/** Compile source bytes into a LPrototype.
diff --git a/src/core/org/luaj/vm2/lib/BaseLib.java b/src/core/org/luaj/vm2/lib/BaseLib.java
index 0edf66e4..95349e91 100644
--- a/src/core/org/luaj/vm2/lib/BaseLib.java
+++ b/src/core/org/luaj/vm2/lib/BaseLib.java
@@ -222,8 +222,7 @@ public class BaseLib extends LuaTable implements ResourceFinder {
try {
LuaValue func = args.checkfunction(1);
String chunkname = args.optString(2, "function");
- Prototype p = LoadState.undump(new StringInputStream(func), chunkname);
- return new LuaClosure(p,LuaThread.getRunningEnv(env));
+ return LoadState.load(new StringInputStream(func), chunkname, LuaThread.getRunningEnv(env));
} catch ( Exception e ) {
return varargsOf(NIL, valueOf(e.getMessage()));
}
@@ -240,8 +239,7 @@ public class BaseLib extends LuaTable implements ResourceFinder {
try {
LuaString script = args.checkstring(1);
LuaString chunkname = args.optstring(2, script);
- Prototype p = LoadState.undump(script.toInputStream(), chunkname.toString());
- return new LuaClosure(p,LuaThread.getRunningEnv(env));
+ return LoadState.load(script.toInputStream(), chunkname.toString(),LuaThread.getRunningEnv(env));
} catch ( Exception e ) {
return varargsOf(NIL, valueOf(e.getMessage()));
}
@@ -344,8 +342,7 @@ public class BaseLib extends LuaTable implements ResourceFinder {
if ( is == null )
return varargsOf(NIL, valueOf("not found: "+filename));
try {
- Prototype p = LoadState.undump(is, filename);
- return new LuaClosure(p,LuaThread.getRunningEnv(env));
+ return LoadState.load(is, filename, LuaThread.getRunningEnv(env));
} finally {
is.close();
}
diff --git a/src/jse/lua.java b/src/jse/lua.java
index c7df8d17..5de9364a 100644
--- a/src/jse/lua.java
+++ b/src/jse/lua.java
@@ -29,9 +29,8 @@ import java.io.InputStreamReader;
import org.luaj.vm2.LoadState;
import org.luaj.vm2.Lua;
-import org.luaj.vm2.LuaClosure;
+import org.luaj.vm2.LuaFunction;
import org.luaj.vm2.LuaValue;
-import org.luaj.vm2.Prototype;
import org.luaj.vm2.compiler.LuaC;
import org.luaj.vm2.lib.DebugLib;
import org.luaj.vm2.lib.JsePlatform;
@@ -167,10 +166,9 @@ public class lua {
private static void processScript( InputStream script, String chunkname, String[] args, int offset ) throws IOException {
try {
- LuaClosure c;
+ LuaFunction c;
try {
- Prototype p = LoadState.undump(script, chunkname );
- c = new LuaClosure(p,_G);
+ c = LoadState.load(script, chunkname, _G);
} finally {
script.close();
}
diff --git a/src/jse/org/luaj/vm2/luajc/JavaBytecodeCompiler.java b/src/jse/org/luaj/vm2/luajc/JavaBytecodeCompiler.java
new file mode 100644
index 00000000..b3ff682f
--- /dev/null
+++ b/src/jse/org/luaj/vm2/luajc/JavaBytecodeCompiler.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Luaj.org. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * 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
+ * THE SOFTWARE.
+ ******************************************************************************/
+package org.luaj.vm2.luajc;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.luaj.vm2.LoadState;
+import org.luaj.vm2.LuaClosure;
+import org.luaj.vm2.LuaFunction;
+import org.luaj.vm2.LuaValue;
+import org.luaj.vm2.Prototype;
+import org.luaj.vm2.LoadState.LuaCompiler;
+import org.luaj.vm2.compiler.LuaC;
+
+public class JavaBytecodeCompiler implements LuaCompiler {
+
+ private static JavaBytecodeCompiler instance;
+ private JavaBytecodeGenerator gen;
+ private LuaC luac;
+
+ public static JavaBytecodeCompiler getInstance() {
+ if ( instance == null )
+ instance = new JavaBytecodeCompiler();
+ return instance;
+ }
+
+ /**
+ * Install the compiler as the main compiler to use.
+ * Will fall back to the LuaC prototype compiler.
+ */
+ public static final void install() {
+ LoadState.compiler = getInstance();
+ }
+
+ private JavaBytecodeCompiler() {
+ luac = new LuaC();
+ gen = new JavaBytecodeGenerator();
+ }
+
+ /** Compile into protoype form. */
+ public Prototype compile(int firstByte, InputStream stream, String name) throws IOException {
+ return luac.compile(firstByte, stream, name);
+ }
+
+ /** Compile into class form. */
+ public LuaFunction load(int firstByte, InputStream stream, String name, LuaValue env) throws IOException {
+ Prototype p = compile( firstByte, stream, name);
+ try {
+ System.out.println("compiling "+name);
+ Class c = gen.toJavaBytecode(p, name);
+ Object o = c.newInstance();
+ System.out.println("instance is: "+o);
+ LuaFunction f = (LuaFunction) o;
+ f.setfenv(env);
+ return f;
+ } catch ( Throwable t ) {
+ t.printStackTrace();
+ return new LuaClosure( p, env );
+ }
+
+ }
+
+}
diff --git a/src/jse/org/luaj/vm2/luajc/JavaBytecodeGenerator.java b/src/jse/org/luaj/vm2/luajc/JavaBytecodeGenerator.java
new file mode 100644
index 00000000..904b9a05
--- /dev/null
+++ b/src/jse/org/luaj/vm2/luajc/JavaBytecodeGenerator.java
@@ -0,0 +1,1051 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Luaj.org. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * 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
+ * THE SOFTWARE.
+ ******************************************************************************/
+package org.luaj.vm2.luajc;
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.bcel.Constants;
+import org.apache.bcel.classfile.Field;
+import org.apache.bcel.generic.AASTORE;
+import org.apache.bcel.generic.ALOAD;
+import org.apache.bcel.generic.ANEWARRAY;
+import org.apache.bcel.generic.ASTORE;
+import org.apache.bcel.generic.ArrayType;
+import org.apache.bcel.generic.BranchInstruction;
+import org.apache.bcel.generic.ClassGen;
+import org.apache.bcel.generic.ConstantPoolGen;
+import org.apache.bcel.generic.FieldGen;
+import org.apache.bcel.generic.GOTO;
+import org.apache.bcel.generic.IFEQ;
+import org.apache.bcel.generic.IFNE;
+import org.apache.bcel.generic.InstructionConstants;
+import org.apache.bcel.generic.InstructionFactory;
+import org.apache.bcel.generic.InstructionHandle;
+import org.apache.bcel.generic.InstructionList;
+import org.apache.bcel.generic.LocalVariableGen;
+import org.apache.bcel.generic.MethodGen;
+import org.apache.bcel.generic.ObjectType;
+import org.apache.bcel.generic.PUSH;
+import org.apache.bcel.generic.Type;
+import org.luaj.vm2.Buffer;
+import org.luaj.vm2.Lua;
+import org.luaj.vm2.LuaBoolean;
+import org.luaj.vm2.LuaDouble;
+import org.luaj.vm2.LuaInteger;
+import org.luaj.vm2.LuaNumber;
+import org.luaj.vm2.LuaString;
+import org.luaj.vm2.LuaTable;
+import org.luaj.vm2.LuaValue;
+import org.luaj.vm2.Prototype;
+import org.luaj.vm2.Varargs;
+import org.luaj.vm2.lib.VarArgFunction;
+
+import com.sun.org.apache.xalan.internal.xsltc.runtime.Hashtable;
+
+
+public class JavaBytecodeGenerator {
+ public static boolean DUMPCLASSES = "true".equals(System.getProperty("DUMPCLASSES"));
+
+ private static final String STR_FUNCV = VarArgFunction.class.getName();
+ private static final String STR_VARARGS = Varargs.class.getName();
+ private static final String STR_LUAVALUE = LuaValue.class.getName();
+ private static final String STR_LUASTRING = LuaString.class.getName();
+ private static final String STR_LUAINTEGER = LuaInteger.class.getName();
+ private static final String STR_LUADOUBLE = LuaDouble.class.getName();
+ private static final String STR_LUANUMBER = LuaNumber.class.getName();
+ private static final String STR_LUABOOLEAN = LuaBoolean.class.getName();
+ private static final String STR_LUATABLE = LuaTable.class.getName();
+ private static final String STR_BUFFER = Buffer.class.getName();
+
+ private static final ObjectType TYPE_VARARGS = new ObjectType(STR_VARARGS);
+ private static final ObjectType TYPE_LUAVALUE = new ObjectType(STR_LUAVALUE);
+ private static final ObjectType TYPE_LUASTRING = new ObjectType(STR_LUASTRING);
+ private static final ObjectType TYPE_LUAINTEGER = new ObjectType(STR_LUAINTEGER);
+ private static final ObjectType TYPE_LUADOUBLE = new ObjectType(STR_LUADOUBLE);
+ private static final ObjectType TYPE_LUANUMBER = new ObjectType(STR_LUANUMBER);
+ private static final ObjectType TYPE_LUABOOLEAN = new ObjectType(STR_LUABOOLEAN);
+ private static final ObjectType TYPE_LUATABLE = new ObjectType(STR_LUATABLE);
+ private static final ObjectType TYPE_BUFFER = new ObjectType(STR_BUFFER);
+
+ private static final ArrayType TYPE_LOCALUPVALUE = new ArrayType( TYPE_LUAVALUE, 1 );
+
+ private static final Class[] NO_INNER_CLASSES = {};
+
+ private static String toLegalLocalName(String string) {
+ String better = string.replaceAll("[^\\w]", "_");
+ return string.equals(better)? string: "$"+better;
+ }
+
+ /**
+ * Turn a lua prototype into a Java class using the Bcel Java Bytecode Generator
+ * @param p Prototype to encode as java, must not have upvalues itself.
+ * @param name String name to apply, without extensions
+ * @return Java Class that extends LuaValue that can be instatiated via newInstance
+ * @throws Exception
+ */
+ public static Class toJavaBytecode( Prototype p, String classname ) throws Exception {
+ return new JavaBytecodeGenerator().loadPrototype( p, classname );
+ }
+
+ private final Hashtable prototypes;
+ private final ClassLoader classLoader;
+
+ JavaBytecodeGenerator() {
+ // load the file
+ prototypes = new Hashtable();
+ classLoader = new ClassLoader() {
+ public Class findClass(String name) throws ClassNotFoundException {
+ Object o = prototypes.get(name);
+ if ( o instanceof Prototype) {
+ try {
+ byte[] b = generateBytecode( (Prototype) o, name );
+ prototypes.put(name, Boolean.TRUE);
+ return defineClass(name, b, 0, b.length);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return super.findClass(name);
+ }
+
+ };
+ }
+
+ private Class loadPrototype(Prototype p, String classname) throws ClassNotFoundException {
+ indexPrototype( p, classname );
+ return classLoader.loadClass(classname);
+ }
+
+ private void indexPrototype(Prototype p, String name) {
+ if ( prototypes.containsKey(name) )
+ return;
+ prototypes.put(name, p);
+ Class[] inners = (p.p!=null && p.p.length>0? new Class[p.p.length]: NO_INNER_CLASSES);
+ for ( int i=0, n=inners.length; i> 6) & 0xff;
+ }
+ private static final int B(int i) {
+ return i >>> 23;
+ }
+ private static final int Bx(int i) {
+ return i >>> 14;
+ }
+ private static final int C(int i) {
+ return (i >> 14) & 0x1ff;
+ }
+
+ private byte[] generateBytecode(Prototype p, String CLASSNAME)
+ throws IOException {
+
+ // compile our class next
+ ClassGen cg = new ClassGen(CLASSNAME, STR_FUNCV, "tryit.lua",
+ Constants.ACC_PUBLIC | Constants.ACC_SUPER, null);
+ ConstantPoolGen cp = cg.getConstantPool(); // cg creates constant pool
+
+ // add static constants
+ int nk = p.k.length;
+ Field[] k = new Field[nk];
+ for (int i = 0; i < nk; i++) {
+ FieldGen fg = new FieldGen(Constants.ACC_STATIC
+ | Constants.ACC_FINAL, // access
+ TYPE_LUAVALUE, // type
+ "k" + (i + 1), // name
+ cp);
+ k[i] = fg.getField();
+ cg.addField(k[i]);
+ }
+
+ // static initializer for static constants
+ {
+ InstructionList il = new InstructionList();
+ MethodGen mg = new MethodGen(Constants.ACC_STATIC, Type.VOID,
+ new Type[] {}, new String[] {}, "", cg
+ .getClassName(), il, cg.getConstantPool());
+ InstructionFactory factory = new InstructionFactory(cg);
+
+ // initialze the constants
+ for (int i = 0; i < nk; i++) {
+ LuaValue ki = p.k[i];
+ switch (ki.type()) {
+ case LuaValue.TNIL:
+ il.append(factory.createFieldAccess(STR_LUAVALUE, "NIL",
+ TYPE_LUAVALUE, Constants.GETSTATIC));
+ il.append(factory.createPutStatic(CLASSNAME,
+ k[i].getName(), k[i].getType()));
+ break;
+ case LuaValue.TBOOLEAN:
+ String b = ki.toboolean() ? "TRUE" : "FALSE";
+ il.append(factory.createFieldAccess(STR_LUAVALUE, b,
+ TYPE_LUABOOLEAN, Constants.GETSTATIC));
+ il.append(factory.createPutStatic(CLASSNAME,
+ k[i].getName(), k[i].getType()));
+ break;
+ case LuaValue.TSTRING:
+ il.append(new PUSH(cp, ki.toString()));
+ il.append(factory.createInvoke(STR_LUASTRING, "valueOf",
+ TYPE_LUASTRING, new Type[] { Type.STRING },
+ Constants.INVOKESTATIC));
+ il.append(factory.createPutStatic(CLASSNAME,
+ k[i].getName(), k[i].getType()));
+ break;
+ case LuaValue.TNUMBER:
+ if (ki.isinttype()) {
+ il.append(new PUSH(cp, ki.toint()));
+ il.append(factory
+ .createInvoke(STR_LUAINTEGER, "valueOf",
+ TYPE_LUAINTEGER,
+ new Type[] { Type.INT },
+ Constants.INVOKESTATIC));
+ il.append(factory.createPutStatic(CLASSNAME, k[i]
+ .getName(), k[i].getType()));
+ } else {
+ il.append(new PUSH(cp, ki.todouble()));
+ il.append(factory.createInvoke(STR_LUADOUBLE,
+ "valueOf", TYPE_LUANUMBER,
+ new Type[] { Type.DOUBLE },
+ Constants.INVOKESTATIC));
+ il.append(factory.createPutStatic(CLASSNAME, k[i]
+ .getName(), k[i].getType()));
+ }
+ break;
+ default:
+ throw new RuntimeException("illegal constant type: "
+ + ki.type());
+ }
+ }
+
+ il.append(InstructionConstants.RETURN);
+ mg.setMaxStack();
+ cg.addMethod(mg.getMethod());
+ il.dispose(); // Allow instruction handles to be reused
+ }
+
+ // upvalues are fields
+ int nu = p.upvalues.length;
+ Field[] u = new Field[nu];
+ for (int i = 0; i < nu; i++) {
+ String name = getUpvalueName(p.upvalues, i);
+ FieldGen fg = new FieldGen(Constants.ACC_PUBLIC, // | ACC_FINAL, //
+ // access
+ TYPE_LOCALUPVALUE, // type
+ name, // name
+ cp);
+ u[i] = fg.getField();
+ cg.addField(u[i]);
+ }
+
+ // implement LuaValue.invoke(Varargs args)
+ InstructionList il = new InstructionList();
+ MethodGen mg = new MethodGen(
+ Constants.ACC_PUBLIC | Constants.ACC_FINAL, // access flags
+ TYPE_VARARGS, // return type
+ new Type[] { TYPE_VARARGS }, // argument types
+ new String[] { "args" }, // arg names
+ "invoke", STR_LUAVALUE, // method, class
+ il, cp);
+ InstructionFactory factory = new InstructionFactory(cg);
+
+ // common iterators used for code
+ int[] code = p.code;
+ int nc = code.length;
+ int pc, i, a, b, c;
+
+ // create locals
+ int np = p.numparams;
+ int nl = p.maxstacksize;
+ LocalVariableGen[] locals = new LocalVariableGen[nl];
+
+ // find upvalues
+ boolean isup[] = new boolean[nl];
+ for (pc = 0; pc < nc; pc++) {
+ if (OP(code[pc]) == Lua.OP_CLOSURE) {
+ b = Bx(code[pc]);
+ Prototype newp = p.p[b];
+ for (int j = 0, nup = newp.nups; j < nup; ++j) {
+ i = code[++pc];
+ if ((i & 4) == 0)
+ isup[B(i)] = true;
+ }
+ }
+ }
+
+ // initialize locals
+ LocalVariableGen nil = null;
+ for (int j = 0; j < nl; j++) {
+
+ String name = j < p.locvars.length && p.locvars[j].varname != null ?
+ toLegalLocalName(p.locvars[j].varname.toString()):
+ "r" + j;
+
+ locals[j] = mg.addLocalVariable(name, isup[j] ? TYPE_LOCALUPVALUE
+ : TYPE_LUAVALUE, null, null);
+
+ if (isup[j]) { // upvalue storage
+ il.append(new PUSH(cp, 1));
+ il.append(new ANEWARRAY(cp.addClass(STR_LUAVALUE)));
+ il.append(InstructionConstants.DUP);
+ il.append(new ASTORE(locals[j].getIndex()));
+ il.append(new PUSH(cp, 0));
+ // leave array & index 0 on stack
+ }
+ // put initial value onto stack
+ if (j < np) {
+ il.append(new ALOAD(1));
+ il.append(new PUSH(cp, j + 1));
+ il.append(factory.createInvoke(STR_VARARGS, "arg",
+ TYPE_LUAVALUE, new Type[] { Type.INT },
+ Constants.INVOKEVIRTUAL));
+ } else {
+ nil = il_initLocalNil(mg, factory, il, nil);
+ il.append(new ALOAD(nil.getIndex()));
+ }
+ if (isup[j]) { // upvalue local, array is already on stack
+ il.append(InstructionConstants.AASTORE);
+ } else { // plain local
+ il.append(new ASTORE(locals[j].getIndex()));
+ }
+ }
+
+ // trim varargs to those that are in excess of what is needed
+ if ((p.is_vararg & Lua.VARARG_ISVARARG) != 0 && np > 0) {
+ il.append(new ALOAD(1));
+ il.append(new PUSH(cp, 1 + np));
+ il.append(factory.createInvoke(STR_VARARGS, "subargs",
+ TYPE_VARARGS, new Type[] { Type.INT },
+ Constants.INVOKEVIRTUAL));
+ il.append(new ASTORE(1));
+ }
+
+ // this local variable stores varargs,
+ // and is only created by functions that need it.
+ // TODO: only include if necessary
+ LocalVariableGen v = null;
+ int vbase = 0;
+ v = mg.addLocalVariable("v", TYPE_VARARGS, null, null);
+ il.append(factory.createFieldAccess(STR_LUAVALUE, "NONE",
+ TYPE_LUAVALUE, Constants.GETSTATIC));
+ il.append(new ASTORE(v.getIndex()));
+
+ // storage for goto locations
+ int[] targets = new int[nc];
+ BranchInstruction[] branches = new BranchInstruction[nc];
+ InstructionHandle[] ih = new InstructionHandle[nc];
+
+ // each lua bytecode gets some java bytecodes
+ for (pc = 0; pc < nc; pc++) {
+
+ // pull out instruction
+ i = code[pc];
+ a = A(i);
+
+ // process the op code
+ switch ( OP(i) ) {
+
+ case Lua.OP_MOVE:/* A B R(A):= R(B) */
+ ih[pc] =
+ il_append_new_ALOAD(cp,il, (locals[B(i)]));
+ il_append_new_ASTORE(cp,il, (locals[a]));
+ break;
+
+ case Lua.OP_LOADK:/* A Bx R(A):= Kst(Bx) */
+ ih[pc] =
+ il.append(factory.createFieldAccess(CLASSNAME, k[Bx(i)].getName(), TYPE_LUAVALUE, Constants.GETSTATIC));
+ il_append_new_ASTORE(cp,il, (locals[a]));
+ break;
+
+ case Lua.OP_LOADBOOL:/* A B C R(A):= (Bool)B: if (C) pc++ */
+ //stack[a] = (B(i)!=0)? LuaValue.TRUE: LuaValue.FALSE;
+ ih[pc] =
+ il.append(factory.createFieldAccess(STR_LUAVALUE, ((B(i)!=0)? "TRUE": "FALSE"), TYPE_LUABOOLEAN, Constants.GETSTATIC));
+ il_append_new_ASTORE(cp,il, (locals[a]));
+ if (C(i) != 0) {
+ // pc++; /* skip next instruction (if C) */
+ branches[pc] = new GOTO(null);
+ targets[pc] = pc + 2;
+ }
+ break;
+
+ case Lua.OP_LOADNIL: /* A B R(A):= ...:= R(B):= nil */
+ ih[pc] =
+ il.append(factory.createFieldAccess(STR_LUAVALUE, "NIL", TYPE_LUAVALUE, Constants.GETSTATIC));
+ for ( b=B(i); a<=b; ) {
+ il.append(InstructionConstants.DUP);
+ il_append_new_ASTORE(cp,il, (locals[a++]));
+ }
+ il.append(InstructionConstants.POP);
+ break;
+
+ case Lua.OP_GETUPVAL: /* A B R(A):= UpValue[B] */
+ ih[pc] =
+ il.append(InstructionConstants.THIS);
+ il.append(factory.createFieldAccess(CLASSNAME, u[B(i)].getName(), TYPE_LOCALUPVALUE, Constants.GETFIELD));
+ il.append(new PUSH(cp,0));
+ il.append(InstructionConstants.AALOAD);
+ il_append_new_ASTORE(cp,il, (locals[a]));
+ break;
+
+ case Lua.OP_GETGLOBAL: /* A Bx R(A):= Gbl[Kst(Bx)] */
+ ih[pc] =
+ il.append(InstructionConstants.THIS);
+ il.append(factory.createFieldAccess(CLASSNAME, "env", TYPE_LUAVALUE, Constants.GETFIELD));
+ il.append(factory.createFieldAccess(CLASSNAME, k[Bx(i)].getName(), TYPE_LUAVALUE, Constants.GETSTATIC));
+ il.append(factory.createInvoke(STR_LUAVALUE, "get", TYPE_LUAVALUE, new Type[] { TYPE_LUAVALUE }, Constants.INVOKEVIRTUAL));
+ il_append_new_ASTORE(cp,il, (locals[a]));
+ break;
+
+ case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */
+ // stack[a] = stack[B(i)].get((c=C(i))>0xff? k[c&0x0ff]: stack[c]);
+ ih[pc] =
+ il_append_new_ALOAD(cp,il, (locals[B(i)]));
+ if ((c=C(i))>0xff)
+ il.append(factory.createFieldAccess(CLASSNAME, k[c&0x0ff].getName(), TYPE_LUAVALUE, Constants.GETSTATIC));
+ else
+ il_append_new_ALOAD(cp,il, (locals[c]));
+ il.append(factory.createInvoke(STR_LUAVALUE, "get", TYPE_LUAVALUE, new Type[] { TYPE_LUAVALUE }, Constants.INVOKEVIRTUAL));
+ il_append_new_ASTORE(cp,il, (locals[a]));
+ break;
+
+ case Lua.OP_SETGLOBAL: /* A Bx Gbl[Kst(Bx)]:= R(A) */
+ // env.set(k[Bx(i)], stack[a]);
+ ih[pc] =
+ il.append(InstructionConstants.THIS);
+ il.append(factory.createFieldAccess(CLASSNAME, "env", TYPE_LUAVALUE, Constants.GETFIELD));
+ il.append(factory.createFieldAccess(CLASSNAME, k[Bx(i)].getName(), TYPE_LUAVALUE, Constants.GETSTATIC));
+ il_append_new_ALOAD(cp,il, (locals[a]));
+ il.append(factory.createInvoke(STR_LUAVALUE, "set", Type.VOID, new Type[] { TYPE_LUAVALUE, TYPE_LUAVALUE }, Constants.INVOKEVIRTUAL));
+ break;
+
+ case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
+ // upValues[B(i)].setValue(stack[a]);
+ ih[pc] =
+ il.append(InstructionConstants.THIS);
+ il.append(factory.createFieldAccess(CLASSNAME, u[B(i)].getName(), TYPE_LOCALUPVALUE, Constants.GETFIELD));
+ il.append(new PUSH(cp,0));
+ il_append_new_ALOAD(cp,il, (locals[a]));
+ il.append(InstructionConstants.AASTORE);
+ break;
+
+ case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */
+ // stack[a].set(((b=B(i))>0xff? k[b&0x0ff]: stack[b]), (c=C(i))>0xff? k[c&0x0ff]: stack[c]);
+ ih[pc] =
+ il_append_new_ALOAD(cp,il, (locals[a]));
+ if ((b=B(i))>0xff)
+ il.append(factory.createFieldAccess(CLASSNAME, k[b&0x0ff].getName(), TYPE_LUAVALUE, Constants.GETSTATIC));
+ else
+ il_append_new_ALOAD(cp,il, (locals[b]));
+ if ((c=C(i))>0xff)
+ il.append(factory.createFieldAccess(CLASSNAME, k[c&0x0ff].getName(), TYPE_LUAVALUE, Constants.GETSTATIC));
+ else
+ il_append_new_ALOAD(cp,il, (locals[c]));
+ il.append(factory.createInvoke(STR_LUAVALUE, "set", Type.VOID, new Type[] { TYPE_LUAVALUE, TYPE_LUAVALUE }, Constants.INVOKEVIRTUAL));
+ break;
+
+ case Lua.OP_NEWTABLE: /* A B C R(A):= {} (size = B,C) */
+ // stack[a] = new LuaTable(B(i),C(i));
+ ih[pc] =
+ il.append(new PUSH(cp, B(i)));
+ il.append(new PUSH(cp, C(i)));
+ il.append(factory.createInvoke(STR_LUAVALUE, "tableOf", TYPE_LUATABLE, new Type[] { Type.INT, Type.INT }, Constants.INVOKESTATIC));
+ il_append_new_ASTORE(cp,il, (locals[a]));
+ break;
+
+ case Lua.OP_SELF: /* A B C R(A+1):= R(B): R(A):= R(B)[RK(C)] */
+ // stack[a+1] = (o = stack[B(i)]);
+ ih[pc] =
+ il_append_new_ALOAD(cp,il, (locals[B(i)]));
+ il_append_new_ASTORE(cp,il, (locals[a+1]));
+ // stack[a] = o.get((c=C(i))>0xff? k[c&0x0ff]: stack[c]);
+ if ((c=C(i))>0xff)
+ il.append(factory.createFieldAccess(CLASSNAME, k[c&0x0ff].getName(), TYPE_LUAVALUE, Constants.GETSTATIC));
+ else
+ il_append_new_ALOAD(cp,il, (locals[c]));
+ il.append(factory.createInvoke(STR_LUAVALUE, "get", TYPE_LUAVALUE, new Type[] { TYPE_LUAVALUE }, Constants.INVOKEVIRTUAL));
+ il_append_new_ASTORE(cp,il, (locals[a]));
+ break;
+
+ case Lua.OP_ADD: /* A B C R(A):= RK(B) + RK(C) */
+ case Lua.OP_SUB: /* A B C R(A):= RK(B) - RK(C) */
+ case Lua.OP_MUL: /* A B C R(A):= RK(B) * RK(C) */
+ case Lua.OP_DIV: /* A B C R(A):= RK(B) / RK(C) */
+ case Lua.OP_MOD: /* A B C R(A):= RK(B) % RK(C) */
+ case Lua.OP_POW: /* A B C R(A):= RK(B) ^ RK(C) */
+ {
+ String op;
+ switch (OP(i)) {
+ default:
+ case Lua.OP_ADD: op = "add"; break;
+ case Lua.OP_SUB: op = "sub"; break;
+ case Lua.OP_MUL: op = "mul"; break;
+ case Lua.OP_DIV: op = "div"; break;
+ case Lua.OP_MOD: op = "mod"; break;
+ case Lua.OP_POW: op = "pow"; break;
+ }
+ // stack[a] = ((b=B(i))>0xff? k[b&0x0ff]: stack[b]).add((c=C(i))>0xff? k[c&0x0ff]: stack[c]);
+ if ((b=B(i))>0xff)
+ ih[pc] =
+ il.append(factory.createFieldAccess(CLASSNAME, k[b&0x0ff].getName(), TYPE_LUAVALUE, Constants.GETSTATIC));
+ else
+ ih[pc] =
+ il_append_new_ALOAD(cp,il, (locals[b]));
+ if ((c=C(i))>0xff)
+ il.append(factory.createFieldAccess(CLASSNAME, k[c&0x0ff].getName(), TYPE_LUAVALUE, Constants.GETSTATIC));
+ else
+ il_append_new_ALOAD(cp,il, (locals[c]));
+ il.append(factory.createInvoke(STR_LUAVALUE, op, TYPE_LUAVALUE, new Type[] { TYPE_LUAVALUE }, Constants.INVOKEVIRTUAL));
+ il_append_new_ASTORE(cp,il, (locals[a]));
+ break;
+ }
+ case Lua.OP_UNM: /* A B R(A):= -R(B) */
+ // stack[a] = stack[B(i)].neg();
+ ih[pc] =
+ il_append_new_ALOAD(cp,il, (locals[B(i)]));
+ il.append(factory.createInvoke(STR_LUAVALUE, "neg", TYPE_LUAVALUE, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
+ il_append_new_ASTORE(cp,il, (locals[a]));
+ break;
+
+ case Lua.OP_NOT: /* A B R(A):= not R(B) */
+ // stack[a] = stack[B(i)].not();
+ ih[pc] =
+ il_append_new_ALOAD(cp,il, (locals[B(i)]));
+ il.append(factory.createInvoke(STR_LUAVALUE, "not", TYPE_LUAVALUE, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
+ il_append_new_ASTORE(cp,il, (locals[a]));
+ break;
+
+ case Lua.OP_LEN: /* A B R(A):= length of R(B) */
+ // stack[a] = stack[B(i)].len();
+ ih[pc] =
+ il_append_new_ALOAD(cp,il, (locals[B(i)]));
+ il.append(factory.createInvoke(STR_LUAVALUE, "len", TYPE_LUAVALUE, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
+ il_append_new_ASTORE(cp,il, (locals[a]));
+ break;
+
+ case Lua.OP_CONCAT: /* A B C R(A):= R(B).. ... ..R(C) */
+ {
+ b = B(i);
+ c = C(i);
+
+ // Buffer sb = new Buffer();
+ ih[pc] =
+ il.append(factory.createNew(TYPE_BUFFER));
+ il.append(InstructionConstants.DUP);
+ il.append(factory.createInvoke(STR_BUFFER, "", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL));
+
+ // concatenate
+ for ( ; b<=c; ) {
+ // sb.append( stack[b++].checkstring() );
+ il.append(InstructionConstants.DUP);
+ il_append_new_ALOAD(cp,il, (locals[b++]));
+ il.append(factory.createInvoke(STR_LUAVALUE, "checkstring", TYPE_LUASTRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
+ il.append(factory.createInvoke(STR_BUFFER, "append", Type.VOID, new Type[] { TYPE_LUASTRING }, Constants.INVOKEVIRTUAL));
+ }
+
+ // store
+ // stack[a] = sb.tostrvalue();
+ il.append(factory.createInvoke(STR_BUFFER, "tostrvalue", TYPE_LUASTRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
+ il_append_new_ASTORE(cp,il, (locals[a]));
+ }
+ break;
+
+ case Lua.OP_JMP: /* sBx pc+=sBx */
+ // pc += (Bx(i))-0x1ffff;
+ branches[pc] = new GOTO(null);
+ targets[pc] = pc + 1 + (Bx(i))-0x1ffff;
+ ih[pc] =
+ il.append(branches[pc]);
+ break;
+
+ case Lua.OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
+ case Lua.OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
+ case Lua.OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
+ {
+ String op;
+ switch (OP(i)) {
+ default:
+ case Lua.OP_EQ: op = "eq_b"; break;
+ case Lua.OP_LT: op = "lt_b"; break;
+ case Lua.OP_LE: op = "lteq_b"; break;
+ }
+ if ((b=B(i))>0xff)
+ ih[pc] =
+ il.append(factory.createFieldAccess(CLASSNAME, k[b&0x0ff].getName(), TYPE_LUAVALUE, Constants.GETSTATIC));
+ else
+ ih[pc] =
+ il_append_new_ALOAD(cp,il, (locals[b]));
+ if ((c=C(i))>0xff)
+ il.append(factory.createFieldAccess(CLASSNAME, k[c&0x0ff].getName(), TYPE_LUAVALUE, Constants.GETSTATIC));
+ else
+ il_append_new_ALOAD(cp,il, (locals[c]));
+ il.append(factory.createInvoke(STR_LUAVALUE, op, Type.BOOLEAN, new Type[] { TYPE_LUAVALUE }, Constants.INVOKEVIRTUAL));
+ branches[pc] = (a!=0)? new IFEQ(null): new IFNE(null);
+ targets[pc] = pc + 2;
+ il.append(branches[pc]);
+ break;
+ }
+ case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
+ ih[pc] =
+ il_append_new_ALOAD(cp,il, (locals[a]));
+ il.append(factory.createInvoke(STR_LUAVALUE, "toboolean", Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
+ branches[pc] = (C(i)!=0)? new IFEQ(null): new IFNE(null);
+ targets[pc] = pc + 2;
+ il.append(branches[pc]);
+ break;
+
+ 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[B(i)]).toboolean() != (C(i)!=0) )
+ // ++pc;
+ //else
+ // stack[a] = o; // TODO: should be sBx?
+ ih[pc] =
+ il_append_new_ALOAD(cp,il, (locals[B(i)]));
+ il.append(factory.createInvoke(STR_LUAVALUE, "toboolean", Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
+ branches[pc] = (C(i)!=0)? new IFEQ(null): new IFNE(null);
+ targets[pc] = pc + 2;
+ il.append(branches[pc]);
+ il_append_new_ALOAD(cp,il, (locals[B(i)]));
+ il_append_new_ASTORE(cp,il, (locals[a]));
+ break;
+
+ case Lua.OP_CALL: /* A B C R(A), ... ,R(A+C-2):= R(A)(R(A+1), ... ,R(A+B-1)) */
+ case Lua.OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
+ ih[pc] =
+ il_append_new_ALOAD(cp,il, (locals[a]));
+ b = B(i);
+ c = C(i);
+ switch ( b ) {
+ case 1: // noargs
+ il.append(factory.createFieldAccess(STR_LUAVALUE, "NONE", TYPE_LUAVALUE, Constants.GETSTATIC));
+ break;
+ case 2: // one arg
+ il_append_new_ALOAD(cp,il, (locals[a+1]));
+ break;
+ case 3: // two args
+ il_append_new_ALOAD(cp,il, (locals[a+1]));
+ il_append_new_ALOAD(cp,il, (locals[a+2]));
+ il.append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, new Type[] { TYPE_LUAVALUE, TYPE_VARARGS }, Constants.INVOKESTATIC));
+ break;
+ case 4: // three args
+ il_append_new_ALOAD(cp,il, (locals[a+1]));
+ il_append_new_ALOAD(cp,il, (locals[a+2]));
+ il_append_new_ALOAD(cp,il, (locals[a+3]));
+ il.append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, new Type[] { TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_VARARGS }, Constants.INVOKESTATIC));
+ break;
+ default: // fixed arg count
+ il.append(new PUSH(cp, b-1));
+ il.append(new ANEWARRAY(cp.addClass(STR_LUAVALUE)));
+ for ( int j=0; j=) R(A)*/
+ break;
+
+ case Lua.OP_CLOSURE: /* A Bx R(A):= closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
+ {
+ b = Bx(i);
+ Prototype newp = p.p[b];
+ String protoname = CLASSNAME+"$"+b;
+
+ // instantiate the class
+ ih[pc] =
+ il.append(factory.createNew(new ObjectType(protoname)));
+ il.append(InstructionConstants.DUP);
+ il.append(factory.createInvoke(protoname, "", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL));
+
+ // set the environment
+ il.append(InstructionConstants.DUP);
+ il.append(InstructionConstants.THIS);
+ il.append(factory.createFieldAccess(CLASSNAME, "env", TYPE_LUAVALUE, Constants.GETFIELD));
+ il.append(factory.createInvoke(STR_LUAVALUE, "setfenv", Type.VOID, new Type[] { TYPE_LUAVALUE }, Constants.INVOKEVIRTUAL));
+
+ // initialize upvalues of new instance
+ for ( int j=0, nup=newp.nups; j