Package org.luaj.vm2.luajc

Source Code of org.luaj.vm2.luajc.JavaBuilder

/*******************************************************************************
* Copyright (c) 2010 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.IOException;
import java.util.HashMap;
import java.util.Map;

import org.apache.bcel.Constants;
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.CompoundInstruction;
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.Instruction;
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.OneArgFunction;
import org.luaj.vm2.lib.ThreeArgFunction;
import org.luaj.vm2.lib.TwoArgFunction;
import org.luaj.vm2.lib.VarArgFunction;
import org.luaj.vm2.lib.ZeroArgFunction;

public class JavaBuilder {
 
  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 String STR_STRING = String.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 ArrayType TYPE_CHARARRAY = new ArrayType( Type.CHAR, 1 );

 
  private static final Class[] NO_INNER_CLASSES = {};

  private static final String STR_FUNCV = VarArgFunction.class.getName();
  private static final String STR_FUNC0 = ZeroArgFunction.class.getName();
  private static final String STR_FUNC1 = OneArgFunction.class.getName();
  private static final String STR_FUNC2 = TwoArgFunction.class.getName();
  private static final String STR_FUNC3 = ThreeArgFunction.class.getName();

  // argument list types
  private static final Type[] ARG_TYPES_NONE = {};
  private static final Type[] ARG_TYPES_INT =  { Type.INT };
  private static final Type[] ARG_TYPES_DOUBLE = { Type.DOUBLE };
  private static final Type[] ARG_TYPES_STRING = { Type.STRING };
  private static final Type[] ARG_TYPES_CHARARRAY = { TYPE_CHARARRAY };
  private static final Type[] ARG_TYPES_VARARGS_INT =  { TYPE_VARARGS, Type.INT }
  private static final Type[] ARG_TYPES_INT_LUAVALUE = { Type.INT, TYPE_LUAVALUE };
  private static final Type[] ARG_TYPES_INT_VARARGS = { Type.INT, TYPE_VARARGS };
  private static final Type[] ARG_TYPES_LUAVALUE_VARARGS = { TYPE_LUAVALUE, TYPE_VARARGS };
  private static final Type[] ARG_TYPES_LUAVALUE_LUAVALUE_VARARGS = { TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_VARARGS };
  private static final Type[] ARG_TYPES_LUAVALUEARRAY = { new ArrayType( TYPE_LUAVALUE, 1 ) };
  private static final Type[] ARG_TYPES_LUAVALUEARRAY_VARARGS = { new ArrayType( TYPE_LUAVALUE, 1 ), TYPE_VARARGS };
  private static final Type[] ARG_TYPES_LUAVALUE_LUAVALUE_LUAVALUE = { TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_LUAVALUE };
  private static final Type[] ARG_TYPES_VARARGS = { TYPE_VARARGS };
  private static final Type[] ARG_TYPES_LUAVALUE_LUAVALUE = { TYPE_LUAVALUE, TYPE_LUAVALUE };
  private static final Type[] ARG_TYPES_INT_INT = { Type.INT, Type.INT };
  private static final Type[] ARG_TYPES_LUAVALUE = { TYPE_LUAVALUE };
  private static final Type[] ARG_TYPES_BUFFER = { TYPE_BUFFER };

  // names, arg types for main prototype classes
  private static final String[]     SUPER_NAME_N   = { STR_FUNC0, STR_FUNC1, STR_FUNC2, STR_FUNC3, STR_FUNCV, };
  private static final ObjectType[] RETURN_TYPE_N  = { TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_LUAVALUE, TYPE_VARARGS, };
  private static final Type[][]     ARG_TYPES_N    = { ARG_TYPES_NONE, ARG_TYPES_LUAVALUE, ARG_TYPES_LUAVALUE_LUAVALUE, ARG_TYPES_LUAVALUE_LUAVALUE_LUAVALUE, ARG_TYPES_VARARGS,  };
  private static final String[][]   ARG_NAMES_N    = { {}, {"arg"}, {"arg1","arg2"}, {"arg1","arg2","arg3"}, {"args"}, };
  private static final String[]     METH_NAME_N    = { "call", "call", "call", "call", "onInvoke", };
 
 
 
  // varable naming
  private static final String PREFIX_CONSTANT     = "k";
  private static final String PREFIX_UPVALUE      = "u";
  private static final String PREFIX_PLAIN_SLOT   = "s";
  private static final String PREFIX_UPVALUE_SLOT = "a";
  private static final String NAME_VARRESULT      = "v";
 
  // basic info
  private final ProtoInfo pi;
  private final Prototype p;
  private final String classname;
 
  // bcel variables
  private final ClassGen cg;
  private final ConstantPoolGen cp;
  private final InstructionFactory factory;
 
  // main instruction list for the main function of this class
  private final InstructionList init;
  private final InstructionList main;
  private final MethodGen mg;
 
  // the superclass arg count, 0-3 args, 4=varargs
  private int superclassType;
  private static int SUPERTYPE_VARARGS = 4;
 
  // storage for goto locations
  private final int[] targets;
  private final BranchInstruction[] branches;
  private final InstructionHandle[] branchDestHandles;
  private InstructionHandle beginningOfLuaInstruction;
 
  // hold vararg result
  private LocalVariableGen varresult = null;
 
  public JavaBuilder(ProtoInfo pi, String classname, String filename) {
    this.pi = pi;
    this.p = pi.prototype;
    this.classname = classname;
   
    // what class to inherit from
    superclassType = p.numparams;
    if ( p.is_vararg != 0 || superclassType >= SUPERTYPE_VARARGS )
      superclassType = SUPERTYPE_VARARGS;
    for ( int i=0, n=p.code.length; i<n; i++ ) {
      int inst = p.code[i];
      int o = Lua.GET_OPCODE(inst);
      if ( (o == Lua.OP_TAILCALL) ||
           ((o == Lua.OP_RETURN) && (Lua.GETARG_B(inst) < 1 || Lua.GETARG_B(inst) > 2)) ) {
        superclassType = SUPERTYPE_VARARGS;
        break;
      }
    }
   
    // create class generator
    cg = new ClassGen(classname, SUPER_NAME_N[superclassType], filename,
        Constants.ACC_PUBLIC | Constants.ACC_SUPER, null);
    cp = cg.getConstantPool(); // cg creates constant pool

    // main instruction lists
    factory = new InstructionFactory(cg);
    init = new InstructionList();
    main = new InstructionList();

    // create the fields
    for ( int i=0; i<p.nups; i++ ) {
      boolean isrw = pi.isReadWriteUpvalue( pi.upvals[i] );
      Type uptype = isrw? (Type) TYPE_LOCALUPVALUE: (Type) TYPE_LUAVALUE;
      FieldGen fg = new FieldGen(0, uptype, upvalueName(i), cp);
      cg.addField(fg.getField());
    }
   
    // create the method
    mg = new MethodGen( Constants.ACC_PUBLIC | Constants.ACC_FINAL, // access flags
        RETURN_TYPE_N[superclassType], // return type
        ARG_TYPES_N[superclassType], // argument types
        ARG_NAMES_N[superclassType], // arg names
        METH_NAME_N[superclassType],
        STR_LUAVALUE, // method, defining class
        main, cp);
   
    // initialize the values in the slots
    initializeSlots()

    // initialize branching
    int nc = p.code.length;
    targets = new int[nc];
    branches = new BranchInstruction[nc];
    branchDestHandles = new InstructionHandle[nc];
  }
 
  public void initializeSlots() {
    int slot = 0;
    createUpvalues(-1, 0, p.maxstacksize);
    if ( superclassType == SUPERTYPE_VARARGS ) {
      for ( slot=0; slot<p.numparams; slot++ ) {
        if ( pi.isInitialValueUsed(slot) ) {
          append(new ALOAD(1));
          append(new PUSH(cp, slot+1));
          append(factory.createInvoke(STR_VARARGS, "arg", TYPE_LUAVALUE, ARG_TYPES_INT, Constants.INVOKEVIRTUAL));
          storeLocal(-1, slot);
        }
      }
      boolean needsarg = ((p.is_vararg & Lua.VARARG_NEEDSARG) != 0);
      if ( needsarg ) {
        append(new ALOAD(1));
        append(new PUSH(cp, 1 + p.numparams));
        append(factory.createInvoke(STR_LUAVALUE, "tableOf", TYPE_LUATABLE, ARG_TYPES_VARARGS_INT, Constants.INVOKESTATIC));
        storeLocal(-1, slot++ );
      }
      else if ( p.numparams > 0 ) {
        append(new ALOAD(1));
        append(new PUSH(cp, 1 + p.numparams));
        append(factory.createInvoke(STR_VARARGS, "subargs", TYPE_VARARGS, ARG_TYPES_INT, Constants.INVOKEVIRTUAL));
        append(new ASTORE(1));
      }
    } else {
      // fixed arg function between 0 and 3 arguments
      for ( slot=0; slot<p.numparams; slot++ ) {
        this.plainSlotVars.put( Integer.valueOf(slot), Integer.valueOf(1+slot) );
        if ( pi.isUpvalueCreate(-1, slot) ) {
          append(new ALOAD(1+slot));
          storeLocal(-1, slot);
        }
      }
    }
   
    // nil parameters
    for ( ; slot<p.maxstacksize; slot++ ) {
      if ( pi.isInitialValueUsed(slot) ) {
        loadNil();
        storeLocal(-1, slot);
      }
    }   
  }
 
  public byte[] completeClass() {

    // add class initializer
    if ( ! init.isEmpty() ) {
      MethodGen mg = new MethodGen(Constants.ACC_STATIC, Type.VOID,
          ARG_TYPES_NONE, new String[] {}, "<clinit>",
          cg.getClassName(), init, cg.getConstantPool());
      init.append(InstructionConstants.RETURN);
      mg.setMaxStack();
      cg.addMethod(mg.getMethod());
      init.dispose();
    }

    // add default constructor
    cg.addEmptyConstructor(Constants.ACC_PUBLIC);
   
    // gen method
    resolveBranches();
    mg.setMaxStack();
    cg.addMethod(mg.getMethod());
    main.dispose();
   
    // convert to class bytes
    try {
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      cg.getJavaClass().dump(baos);
      return baos.toByteArray();
    } catch ( IOException ioe ) {
      throw new RuntimeException("JavaClass.dump() threw "+ioe);
    }
  }

  public void dup() {
    append(InstructionConstants.DUP);
  }

  public void pop() {
    append(InstructionConstants.POP);
  }

  public void loadNil() {
    append(factory.createFieldAccess(STR_LUAVALUE, "NIL", TYPE_LUAVALUE, Constants.GETSTATIC));
  }
 
  public void loadNone() {
    append(factory.createFieldAccess(STR_LUAVALUE, "NONE", TYPE_LUAVALUE, Constants.GETSTATIC));
  }

  public void loadBoolean(boolean b) {
    String field = (b? "TRUE": "FALSE");
    append(factory.createFieldAccess(STR_LUAVALUE, field, TYPE_LUABOOLEAN, Constants.GETSTATIC));
  }
 
  private Map<Integer,Integer> plainSlotVars = new HashMap<Integer,Integer>();
  private Map<Integer,Integer> upvalueSlotVars = new HashMap<Integer,Integer>();
  private int findSlot( int slot, Map<Integer,Integer> map, String prefix, Type type ) {
    Integer islot = Integer.valueOf(slot);
    if ( map.containsKey(islot) )
      return ((Integer)map.get(islot)).intValue();
    String name = prefix+slot;
    LocalVariableGen local = mg.addLocalVariable(name, type, null, null);
    int index = local.getIndex();
    map.put(islot, Integer.valueOf(index));
    return index;
  }
  private int findSlotIndex( int slot, boolean isupvalue ) {
    return isupvalue?
        findSlot( slot, upvalueSlotVars, PREFIX_UPVALUE_SLOT, TYPE_LOCALUPVALUE ):
        findSlot( slot, plainSlotVars, PREFIX_PLAIN_SLOT, TYPE_LUAVALUE );
  }

  public void loadLocal(int pc, int slot) {
    boolean isupval = pi.isUpvalueRefer(pc, slot);
    int index = findSlotIndex( slot, isupval );
    append(new ALOAD(index));
    if (isupval) {
      append(new PUSH(cp, 0));
      append(InstructionConstants.AALOAD);
    }
  }

  public void storeLocal(int pc, int slot) {
    boolean isupval = pi.isUpvalueAssign(pc, slot);
    int index = findSlotIndex( slot, isupval );
    if (isupval) {
      boolean isupcreate = pi.isUpvalueCreate(pc, slot);
      if ( isupcreate ) {
        append(factory.createInvoke(classname, "newupe", TYPE_LOCALUPVALUE, ARG_TYPES_NONE, Constants.INVOKESTATIC));
        append(InstructionConstants.DUP);
        append(new ASTORE(index));
      } else {
        append(new ALOAD(index));
      }
      append(InstructionConstants.SWAP);
      append(new PUSH(cp, 0));
      append(InstructionConstants.SWAP);
      append(InstructionConstants.AASTORE);
    } else {
      append(new ASTORE(index));
    }
  }

  public void createUpvalues(int pc, int firstslot, int numslots) {
    for ( int i=0; i<numslots; i++ ) {
      int slot = firstslot + i;
      boolean isupcreate = pi.isUpvalueCreate(pc, slot);
      if ( isupcreate ) {
        int index = findSlotIndex( slot, true );
        append(factory.createInvoke(classname, "newupn", TYPE_LOCALUPVALUE, ARG_TYPES_NONE, Constants.INVOKESTATIC));
        append(new ASTORE(index));
      }
    }
  }

  public void convertToUpvalue(int pc, int slot) {
    boolean isupassign = pi.isUpvalueAssign(pc, slot);
    if ( isupassign ) {
      int index = findSlotIndex( slot, false );
      append(new ALOAD(index));
      append(factory.createInvoke(classname, "newupl", TYPE_LOCALUPVALUE,  ARG_TYPES_LUAVALUE, Constants.INVOKESTATIC));
      int upindex = findSlotIndex( slot, true );
      append(new ASTORE(upindex));
    }
  }
 
  private static String upvalueName(int upindex) {
    return PREFIX_UPVALUE+upindex;
  }
 
  public void loadUpvalue(int upindex) {
    boolean isrw = pi.isReadWriteUpvalue( pi.upvals[upindex] );
    append(InstructionConstants.THIS);
    if ( isrw ) {
      append(factory.createFieldAccess(classname, upvalueName(upindex), TYPE_LOCALUPVALUE, Constants.GETFIELD));
      append(new PUSH(cp,0));
      append(InstructionConstants.AALOAD);
    } else {
      append(factory.createFieldAccess(classname, upvalueName(upindex), TYPE_LUAVALUE, Constants.GETFIELD));
    }
  }

  public void storeUpvalue(int pc, int upindex, int slot) {
    boolean isrw = pi.isReadWriteUpvalue( pi.upvals[upindex] );
    append(InstructionConstants.THIS);
    if ( isrw ) {
      append(factory.createFieldAccess(classname, upvalueName(upindex), TYPE_LOCALUPVALUE, Constants.GETFIELD));
      append(new PUSH(cp,0));
      loadLocal(pc, slot);
      append(InstructionConstants.AASTORE);
    } else {
      loadLocal(pc, slot);
      append(factory.createFieldAccess(classname, upvalueName(upindex), TYPE_LUAVALUE, Constants.PUTFIELD));
    }
  }

 
  public void newTable( int b, int c ) {
    append(new PUSH(cp, b));
    append(new PUSH(cp, c));
    append(factory.createInvoke(STR_LUAVALUE, "tableOf", TYPE_LUATABLE, ARG_TYPES_INT_INT, Constants.INVOKESTATIC));
  }

  public void loadEnv() {
    append(InstructionConstants.THIS);
    append(factory.createFieldAccess(classname, "env", TYPE_LUAVALUE, Constants.GETFIELD));
  }

  public void loadVarargs() {
    append(new ALOAD(1));
  }
 
  public void loadVarargs(int argindex) {
    loadVarargs();
    arg(argindex);
  }

  public void arg(int argindex) {
    if ( argindex == 1 ) {
      append(factory.createInvoke(STR_VARARGS, "arg1", TYPE_LUAVALUE, ARG_TYPES_NONE, Constants.INVOKEVIRTUAL));
    } else {
      append(new PUSH(cp, argindex));
      append(factory.createInvoke(STR_VARARGS, "arg", TYPE_LUAVALUE, ARG_TYPES_INT, Constants.INVOKEVIRTUAL));
    }
  }

  private int getVarresultIndex() {
    if ( varresult == null )
      varresult = mg.addLocalVariable(NAME_VARRESULT, TYPE_VARARGS, null, null);
    return varresult.getIndex();
  }
 
  public void loadVarresult() {
    append(new ALOAD(getVarresultIndex()));
  }
 
  public void storeVarresult() {
    append(new ASTORE(getVarresultIndex()));
  }

  public void subargs(int firstarg) {
    append(new PUSH(cp, firstarg));
    append(factory.createInvoke(STR_VARARGS, "subargs", TYPE_VARARGS, ARG_TYPES_INT, Constants.INVOKEVIRTUAL));
  }
 
  public void getTable() {
        append(factory.createInvoke(STR_LUAVALUE, "get", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL));
  }
 
  public void setTable() {
        append(factory.createInvoke(STR_LUAVALUE, "set", Type.VOID, ARG_TYPES_LUAVALUE_LUAVALUE, Constants.INVOKEVIRTUAL));
  }

  public void unaryop(int o) {
    String op;
    switch (o) {
      default:
      case Lua.OP_UNM: op = "neg"; break;
      case Lua.OP_NOT: op = "not"; break;
      case Lua.OP_LEN: op = "len"; break;
    }
        append(factory.createInvoke(STR_LUAVALUE, op, TYPE_LUAVALUE, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
  }
 
  public void binaryop(int o) {
    String op;
    switch (o) {
      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;
    }
        append(factory.createInvoke(STR_LUAVALUE, op, TYPE_LUAVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL));
  }

  public void compareop(int o) {
    String op;
    switch (o) {
      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;
    }
        append(factory.createInvoke(STR_LUAVALUE, op, Type.BOOLEAN, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL));
  }

  public void areturn() {
    append(InstructionConstants.ARETURN);
  }
 
  public void toBoolean() {
        append(factory.createInvoke(STR_LUAVALUE, "toboolean", Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
  }

  public void tostring() {
        append(factory.createInvoke(STR_BUFFER, "tostring", TYPE_LUASTRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
  }

  public void isNil() {
        append(factory.createInvoke(STR_LUAVALUE, "isnil", Type.BOOLEAN, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
  }

  public void testForLoop() {
    append(factory.createInvoke(STR_LUAVALUE, "testfor_b", Type.BOOLEAN, ARG_TYPES_LUAVALUE_LUAVALUE, Constants.INVOKEVIRTUAL));
  }

  public void loadArrayArgs(int pc, int firstslot, int nargs) {
    append(new PUSH(cp, nargs));
    append(new ANEWARRAY(cp.addClass(STR_LUAVALUE)));
    for ( int i=0; i<nargs; i++ ) {
      append(InstructionConstants.DUP);
      append(new PUSH(cp, i));
      loadLocal(pc, firstslot++);
      append(new AASTORE());
   
  }
 
  public void newVarargs(int pc, int firstslot, int nargs) {
    switch ( nargs ) {
    case 0: loadNone();
      break;
    case 1: loadLocal(pc, firstslot);
      break;
    case 2: loadLocal(pc, firstslot); loadLocal(pc, firstslot+1);
      append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, ARG_TYPES_LUAVALUE_VARARGS, Constants.INVOKESTATIC));
      break;
    case 3: loadLocal(pc, firstslot); loadLocal(pc, firstslot+1); loadLocal(pc, firstslot+2);
      append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, ARG_TYPES_LUAVALUE_LUAVALUE_VARARGS, Constants.INVOKESTATIC));
      break;
    default:
      loadArrayArgs(pc, firstslot, nargs);
      append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, ARG_TYPES_LUAVALUEARRAY, Constants.INVOKESTATIC));
      break;
    }
  }

  public void newVarargsVarresult(int pc, int firstslot, int nslots) {
    loadArrayArgs(pc, firstslot, nslots );
    loadVarresult();
    append(factory.createInvoke(STR_LUAVALUE, "varargsOf", TYPE_VARARGS, ARG_TYPES_LUAVALUEARRAY_VARARGS, Constants.INVOKESTATIC));
  }
 
  public void call(int nargs) {
    switch ( nargs ) {
    case 0: append(factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, ARG_TYPES_NONE, Constants.INVOKEVIRTUAL)); break;
    case 1: append(factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL)); break;
    case 2: append(factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE_LUAVALUE, Constants.INVOKEVIRTUAL)); break;
    case 3: append(factory.createInvoke(STR_LUAVALUE, "call", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE_LUAVALUE_LUAVALUE, Constants.INVOKEVIRTUAL)); break;
    default: throw new IllegalArgumentException("can't call with "+nargs+" args");
    }
  }

  public void newTailcallVarargs() {
    append(factory.createInvoke(STR_LUAVALUE, "tailcallOf", TYPE_VARARGS, ARG_TYPES_LUAVALUE_VARARGS, Constants.INVOKESTATIC));
  }
 
  public void invoke(int nargs) {
    switch ( nargs ) {
    case -1: append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_VARARGS, Constants.INVOKEVIRTUAL)); break;
    case 0: append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_NONE, Constants.INVOKEVIRTUAL)); break;
    case 1: append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_VARARGS, Constants.INVOKEVIRTUAL)); break;
    case 2: append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_LUAVALUE_VARARGS, Constants.INVOKEVIRTUAL)); break;
    case 3: append(factory.createInvoke(STR_LUAVALUE, "invoke", TYPE_VARARGS, ARG_TYPES_LUAVALUE_LUAVALUE_VARARGS, Constants.INVOKEVIRTUAL)); break;
    default: throw new IllegalArgumentException("can't invoke with "+nargs+" args");
    }
  }

 
  // ------------------------ closures ------------------------
 
  public void closureCreate(String protoname) {
    append(factory.createNew(new ObjectType(protoname)));
    append(InstructionConstants.DUP);
    append(factory.createInvoke(protoname, "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL));
    append(InstructionConstants.DUP);
    loadEnv();
    append(factory.createInvoke(STR_LUAVALUE, "setfenv", Type.VOID, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL));
  }

  public void closureInitUpvalueFromUpvalue(String protoname, int newup, int upindex) {
    boolean isrw = pi.isReadWriteUpvalue( pi.upvals[upindex] );
    Type uptype = isrw? (Type) TYPE_LOCALUPVALUE: (Type) TYPE_LUAVALUE;
    String srcname = upvalueName(upindex);
    String destname = upvalueName(newup);
    append(InstructionConstants.THIS);
    append(factory.createFieldAccess(classname, srcname, uptype, Constants.GETFIELD));
    append(factory.createFieldAccess(protoname, destname, uptype, Constants.PUTFIELD));
  }

  public void closureInitUpvalueFromLocal(String protoname, int newup, int pc, int srcslot) {
    boolean isrw = pi.isReadWriteUpvalue( pi.vars[srcslot][pc].upvalue );
    Type uptype = isrw? (Type) TYPE_LOCALUPVALUE: (Type) TYPE_LUAVALUE;
    String destname = upvalueName(newup);
    int index = findSlotIndex( srcslot, isrw );
    append(new ALOAD(index));
    append(factory.createFieldAccess(protoname, destname, uptype, Constants.PUTFIELD));
  }
 
  private Map<LuaValue,String> constants = new HashMap<LuaValue,String>();
 
  public void loadConstant(LuaValue value) {
    switch ( value.type() ) {
    case LuaValue.TNIL:
      loadNil();
      break;
    case LuaValue.TBOOLEAN:
      loadBoolean( value.toboolean() );
      break;
    case LuaValue.TNUMBER:
    case LuaValue.TSTRING:
      String name = (String) constants.get(value);
      if ( name == null ) {
        name = value.type() == LuaValue.TNUMBER?
            value.isinttype()?
              createLuaIntegerField(value.checkint()):
              createLuaDoubleField(value.checkdouble()):
            createLuaStringField(value.checkstring());
        constants.put(value, name);
      }
      append(factory.createGetStatic(classname, name, TYPE_LUAVALUE));
      break;
    default:
      throw new IllegalArgumentException("bad constant type: "+value.type());
    }
  }

  private String createLuaIntegerField(int value) {
    String name = PREFIX_CONSTANT+constants.size();
    FieldGen fg = new FieldGen(Constants.ACC_STATIC | Constants.ACC_FINAL,
        TYPE_LUAVALUE, name, cp);
    cg.addField(fg.getField());
    init.append(new PUSH(cp, value));
    init.append(factory.createInvoke(STR_LUAVALUE, "valueOf",
        TYPE_LUAINTEGER, ARG_TYPES_INT, Constants.INVOKESTATIC));
    init.append(factory.createPutStatic(classname, name, TYPE_LUAVALUE));
    return name;
  }
 
  private String createLuaDoubleField(double value) {
    String name = PREFIX_CONSTANT+constants.size();
    FieldGen fg = new FieldGen(Constants.ACC_STATIC | Constants.ACC_FINAL,
        TYPE_LUAVALUE, name, cp);
    cg.addField(fg.getField());
    init.append(new PUSH(cp, value));
    init.append(factory.createInvoke(STR_LUAVALUE, "valueOf",
        TYPE_LUANUMBER, ARG_TYPES_DOUBLE, Constants.INVOKESTATIC));
    init.append(factory.createPutStatic(classname, name, TYPE_LUAVALUE));     
    return name;
  }

  private String createLuaStringField(LuaString value) {
    String name = PREFIX_CONSTANT+constants.size();
    FieldGen fg = new FieldGen(Constants.ACC_STATIC | Constants.ACC_FINAL,
        TYPE_LUAVALUE, name, cp);
    cg.addField(fg.getField());
    LuaString ls = value.checkstring();
    if ( ls.isValidUtf8() ) {
      init.append(new PUSH(cp, value.tojstring()));
      init.append(factory.createInvoke(STR_LUASTRING, "valueOf",
          TYPE_LUASTRING, ARG_TYPES_STRING, Constants.INVOKESTATIC));
    } else {
      char[] c = new char[ls.m_length];
      for ( int j=0; j<ls.m_length; j++ )
        c[j] = (char) (0xff & (int) (ls.m_bytes[ls.m_offset+j]));
      init.append(new PUSH(cp, new String(c)));
      init.append(factory.createInvoke(STR_STRING, "toCharArray",
          TYPE_CHARARRAY, Type.NO_ARGS,
          Constants.INVOKEVIRTUAL));
      init.append(factory.createInvoke(STR_LUASTRING, "valueOf",
          TYPE_LUASTRING, ARG_TYPES_CHARARRAY,
          Constants.INVOKESTATIC));
    }
    init.append(factory.createPutStatic(classname, name, TYPE_LUAVALUE));     
    return name;
  }

  // --------------------- branching support -------------------------
  public static final int BRANCH_GOTO = 1;
  public static final int BRANCH_IFNE = 2;
  public static final int BRANCH_IFEQ = 3;
 
  public void addBranch( int pc, int branchType, int targetpc ) {
    switch ( branchType ) {
    default:
    case BRANCH_GOTO: branches[pc= new GOTO(null); break;
    case BRANCH_IFNE:  branches[pc] = new IFNE(null); break;
    case BRANCH_IFEQ:  branches[pc] = new IFEQ(null); break;
    }
    targets[pc] = targetpc;
    append(branches[pc]);
  }


  private void append( Instruction i ) {
    conditionalSetBeginningOfLua( main.append(i) );
  }
 
  private void append( CompoundInstruction i ) {
    conditionalSetBeginningOfLua( main.append(i) );
  }
 
  private void append( BranchInstruction i ) {
    conditionalSetBeginningOfLua( main.append(i) );
  }
 
  private void conditionalSetBeginningOfLua(InstructionHandle ih) {
    if ( beginningOfLuaInstruction == null )
      beginningOfLuaInstruction = ih;
  }

  public void onEndOfLuaInstruction(int pc) {
    branchDestHandles[pc] = beginningOfLuaInstruction;
    beginningOfLuaInstruction = null;
  }
 
  private void resolveBranches() {
    int nc = p.code.length;
    for (int pc = 0; pc < nc; pc++) {
      if (branches[pc] != null) {
        int t=targets[pc];
        while ( t<branchDestHandles.length && branchDestHandles[t] == null )
          t++;
        if ( t>= branchDestHandles.length )
           throw new IllegalArgumentException("no target at or after "+targets[pc]+" op="+Lua.GET_OPCODE(p.code[targets[pc]]));
        branches[pc].setTarget(branchDestHandles[t]);
      }
    }
  }
 
  public void setlistStack(int pc, int a0, int index0, int nvals) {
    for ( int i=0; i<nvals; i++ ) {
      dup();
      append(new PUSH(cp, index0+i));
      loadLocal( pc, a0+i );
          append(factory.createInvoke(STR_LUAVALUE, "rawset", Type.VOID, ARG_TYPES_INT_LUAVALUE, Constants.INVOKEVIRTUAL));
      }
  }

  public void setlistVarargs(int index0, int vresultbase) {
    append(new PUSH(cp, index0));
    loadVarresult();
    append(factory.createInvoke(STR_LUAVALUE, "rawsetlist", Type.VOID, ARG_TYPES_INT_VARARGS, Constants.INVOKEVIRTUAL));
  }

  public void concatvalue() {
        append(factory.createInvoke(STR_LUAVALUE, "concat", TYPE_LUAVALUE, ARG_TYPES_LUAVALUE, Constants.INVOKEVIRTUAL));
  }
 
  public void concatbuffer() {
        append(factory.createInvoke(STR_LUAVALUE, "concat", TYPE_BUFFER, ARG_TYPES_BUFFER, Constants.INVOKEVIRTUAL));
  }

  public void tobuffer() {
        append(factory.createInvoke(STR_LUAVALUE, "buffer", TYPE_BUFFER, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
  }

  public void tovalue() {
        append(factory.createInvoke(STR_BUFFER, "value", TYPE_LUAVALUE, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
  }
}
TOP

Related Classes of org.luaj.vm2.luajc.JavaBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.