!include once #1019934 // BCEL sclass MethodMaker { replace Type with org.apache.bcel.generic.Type. ClassGen cg; MethodGen mg; new InstructionList il; ConstantPoolGen cp; InstructionFactory factory; int frameSize; settable bool verboseAdd; delegate none, objValue, intValue, doubleValue to JVMStackCellType. bool classConstantWorkaround; *(ClassMaker classMaker, Class returnType, S methodName, Class... argumentTypes) { this(classMaker.cg, returnType, methodName, argumentTypes); } *(ClassGen cg, Class returnType, S methodName, Class... argumentTypes) { this(cg, Const.ACC_PUBLIC, returnType, methodName, argumentTypes); } // types: Class or S *(ClassGen *cg, short modifiers, O returnType, S methodName, O... argumentTypes) { cp = cg.getConstantPool(); factory = new InstructionFactory(cg); Type[] argTypes = wrapTypes(argumentTypes); mg = new MethodGen(modifiers, wrapType(returnType), argTypes, null /* argNames */, methodName, cg.getClassName(), il, cp); frameSize = l(argTypes)+1; // assume method is not static } *(ClassGen *cg, short modifiers, Class returnType, S methodName, Class... argumentTypes) { cp = cg.getConstantPool(); factory = new InstructionFactory(cg); Type[] argTypes = wrapTypes(argumentTypes); mg = new MethodGen(modifiers, wrapType(returnType), argTypes, null /* argNames */, methodName, cg.getClassName(), il, cp); frameSize = l(argTypes)+1; // assume method is not static } static Type[] wrapTypes(O[] classes) { Type[] types = new[l(classes)]; for i over classes: types[i] = wrapType(classes[i]); ret types; } static Type wrapType(O o) { if (o cast Class) ret classToBCELType(c); if (o cast S) ret new ObjectType(className); null; } // create local variable and return its index int newLocalVar() { ret frameSize++; } selfType newObject(Class c, Class... argTypes) { il.append(factory.createNew(className(c))); il.append(InstructionConst.DUP); invokeConstructor(c, argTypes); this; } selfType invokeConstructor(Class c, Class... argTypes) { Constructor ctor = findConstructor_precise_onTypes(c, argTypes); il.append(factory.createInvoke(className(c), "", Type.VOID, wrapTypes(ctor.getParameterTypes()), Const.INVOKESPECIAL)); this; } selfType dup() { il.append(InstructionConst.DUP); this; } // store object in local variable selfType astore(int var) { il.append(new ASTORE(var)); this; } selfType aload(int var) { il.append(new ALOAD(var)); this; } selfType stringConstant(S s) { il.append(new PUSH(cp, s)); this; } selfType classConstant(Class c) { if (classConstantWorkaround) { stringConstant(c.getName()); invokeStatic(Class.class, Class.class, "forName", S); } else { var ldc = new LDC(classRef(c)); assertEquals("classConstant", ldc.getValue(cp), wrapType(c)); il.append(ldc); } this; } selfType intConstant aka intConst(int i) { if (i >= -1 && i <= 5) ret add(new ICONST(i)); if (i == (byte) i) ret add(new BIPUSH((byte) i)); if (i == (short) i) ret add(new SIPUSH((short) i)); ret add(new LDC(cp.addInteger(i))); } selfType doubleConstant aka doubleConst(double d) { ret add(new LDC2_W(cp.addDouble(d))); } selfType boolConstant(bool b) { ret intConstant(b ? 1 : 0); } selfType invokeVirtual(Class c, Class returnType, S methodName, Class... argTypes) { Method m = findNonStaticMethod_precise_onTypes(c, methodName, argTypes); if (m == null) fail("Method not found: " + className(c) + "." + formatFunctionCall(methodName, argTypes) + " returning " + className(returnType)); il.append(factory.createInvoke(className(c), methodName, wrapType(m.getReturnType()), wrapTypes(m.getParameterTypes()), Const.INVOKEVIRTUAL)); this; } selfType invokeInterface(Class c, Class returnType, S methodName, Class... argTypes) { Method m = mostApplicableMethod_onTypes( filter(nonDefaultInterfaceMethods(c), _m -> _m.getName().equals(methodName)), argTypes); if (m == null) fail("Method not found: " + className(c) + "." + formatFunctionCall(methodName, argTypes) + " returning " + className(returnType)); il.append(factory.createInvoke(className(c), methodName, wrapType(m.getReturnType()), wrapTypes(m.getParameterTypes()), Const.INVOKEINTERFACE)); this; } selfType invokeStatic(Class c, Class returnType, S methodName, Class... argTypes) { Method m = findMethod_precise_onTypes(c, methodName, argTypes); if (m == null) fail("Method not found: " + className(c) + "." + formatFunctionCall(methodName, argTypes) + " returning " + className(returnType)); il.append(factory.createInvoke(className(c), methodName, wrapType(m.getReturnType()), wrapTypes(m.getParameterTypes()), Const.INVOKESTATIC)); this; } selfType areturn() { il.append(InstructionConst.ARETURN); this; } selfType _return() { il.append(InstructionConst.RETURN); this; } meta-for Instruction also as BranchInstruction { selfType add(Instruction i) { il.append(i); if (verboseAdd) print("> " + i); this; } A addAndReturn(A i) { add(i); ret i; } } void done() { mg.stripAttributes(true); mg.setMaxStack(); mg.setMaxLocals(); cg.addMethod(mg.getMethod()); } JVMStackCellType convertToObject(JVMStackCellType stackTop) { if (stackTop == objValue) {} else if (stackTop == JVMStackCellType.intValue) invokeStatic(Int, Int, "valueOf", int.class); else if (stackTop == JVMStackCellType.doubleValue) invokeStatic(Double.class, Double.class, "valueOf", double.class); else if (stackTop == JVMStackCellType.none) add(new ACONST_NULL); else fail("TODO: add conversion for stack cell type: " + stackTop); ret objValue; } void discardStackTop(JVMStackCellType stackTop) { if (stackTop == JVMStackCellType.none) {} else if (stackTop == JVMStackCellType.doubleValue || stackTop == JVMStackCellType.longValue) add(new POP2); else add(new POP); } int classRef(Class c) { ret cp.addClass((ObjectType) wrapType(assertNotNull(c))); } selfType checkCast(Class c) { ret add(new CHECKCAST(classRef(c))); } selfType loadNull() { ret add(new ACONST_NULL); } InstructionHandle here() { ret il.append(new NOP); } GOTO forwardGoto() { ret addAndReturn(new GOTO(null)); } void returnWithType(JVMStackCellType stackTop) { if (stackTop == JVMStackCellType.objValue) areturn(); else if (stackTop == JVMStackCellType.intValue) add(new IRETURN); else if (stackTop == JVMStackCellType.doubleValue) add(new DRETURN); else if (stackTop == JVMStackCellType.none) _return(); else fail("TODO: add return for stack cell type: " + stackTop); } void getStaticField(S className, S fieldName, Class type) { il.append(factory.createGetStatic(className, fieldName, wrapType(type)); } }