Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

346
LINES

< > BotCompany Repo | #1034309 // MethodMaker [BCEL helper]

JavaX fragment (include) [tags: use-pretranspiled]

Uses 679K of libraries. Click here for Pure Java version (14251L/81K).

1  
!include once #1019934 // BCEL
2  
3  
sclass MethodMaker {
4  
  replace Type with org.apache.bcel.generic.Type.
5  
  
6  
  ClassGen cg;
7  
  MethodGen mg;
8  
  new InstructionList il;
9  
  ConstantPoolGen cp;
10  
  InstructionFactory factory;
11  
  int frameSize;
12  
  Type[] argTypes;
13  
  int[] argStackIndex;
14  
15  
  settable bool verboseAdd;
16  
  
17  
  delegate none, objValue, intValue, doubleValue to JVMStackCellType.
18  
  
19  
  bool classConstantWorkaround;
20  
    
21  
  *(ClassMaker classMaker, Class returnType, S methodName, Class... argumentTypes) {
22  
    this(classMaker.cg, returnType, methodName, argumentTypes);
23  
  }
24  
  
25  
  *(ClassGen cg, Class returnType, S methodName, Class... argumentTypes) {
26  
    this(cg, Const.ACC_PUBLIC, returnType, methodName, argumentTypes);
27  
  }
28  
  
29  
  // types: Class or S
30  
  *(ClassGen *cg, short modifiers, O returnType, S methodName, O... argumentTypes) {
31  
    cp = cg.getConstantPool();
32  
    factory = new InstructionFactory(cg);
33  
  
34  
    argTypes = wrapTypes(argumentTypes);
35  
      
36  
    mg = new MethodGen(modifiers,
37  
      wrapType(returnType),
38  
      argTypes, null /* argNames */, methodName, cg.getClassName(), il, cp);
39  
      
40  
    layoutStack();
41  
  }
42  
43  
  *(ClassGen *cg, short modifiers, Class returnType, S methodName, Class... argumentTypes) {
44  
    cp = cg.getConstantPool();
45  
    factory = new InstructionFactory(cg);
46  
  
47  
    argTypes = wrapTypes(argumentTypes);
48  
      
49  
    mg = new MethodGen(modifiers,
50  
      wrapType(returnType),
51  
      argTypes, null /* argNames */, methodName, cg.getClassName(), il, cp);
52  
      
53  
    layoutStack();
54  
  }
55  
  
56  
  void layoutStack {
57  
    frameSize = 1; // assume method is not static
58  
    argStackIndex = new int[l(argTypes)];
59  
    for i over argTypes: {
60  
      argStackIndex[i] = frameSize;
61  
      frameSize += eqOneOf(argTypes[i], Type.LONG, Type.DOUBLE) ? 2 : 1;
62  
    }
63  
  }
64  
65  
  static Type[] wrapTypes(O[] classes) {  
66  
    Type[] types = new[l(classes)];
67  
    for i over classes:
68  
      types[i] = wrapType(classes[i]);
69  
    ret types;
70  
  }
71  
  
72  
  static Type wrapType(O o) {
73  
    if (o cast Class)
74  
      ret classToBCELType(o);
75  
    if (o cast S) {
76  
      Class c = parsePrimitiveType(o);
77  
      if (c != null) ret classToBCELType(c);
78  
      ret new ObjectType(o);
79  
    }
80  
    null;
81  
  }
82  
83  
  // create local variable and return its index
84  
  int newLocalVar() { ret frameSize++; }
85  
  
86  
  selfType newObject(Class c, Class... argTypes) {
87  
    il.append(factory.createNew(className(c)));
88  
    il.append(InstructionConst.DUP);
89  
    invokeConstructor(c, argTypes);
90  
    this;
91  
  }
92  
  
93  
  selfType invokeConstructor(Class c, Class... argTypes) {
94  
    Constructor ctor = findConstructor_precise_onTypes(c, argTypes);
95  
    il.append(factory.createInvoke(className(c), "<init>",
96  
      Type.VOID, wrapTypes(ctor.getParameterTypes()),
97  
      Const.INVOKESPECIAL));
98  
    this;
99  
  }
100  
  
101  
  selfType dup() {
102  
    il.append(InstructionConst.DUP);
103  
    this;
104  
  }
105  
  
106  
  // store object in local variable
107  
  selfType astore(int var) {
108  
    il.append(new ASTORE(var));
109  
    this;
110  
  }
111  
  
112  
  int argIdx(int iArg) {
113  
    ret argStackIndex[iArg];
114  
  }
115  
  
116  
  selfType aloadArgWithAutoboxing(int iArg) {  
117  
    var type = argTypes[iArg];
118  
    int stackIdx = argStackIndex[iArg];
119  
120  
    if (type == Type.BYTE) {
121  
      il.append(new ILOAD(stackIdx));
122  
      invokeStatic(Byte.class, Byte.class, "valueOf", byte.class);
123  
      this;
124  
    }
125  
    
126  
    if (type == Type.BOOLEAN) {
127  
      il.append(new ILOAD(stackIdx));
128  
      invokeStatic(Bool.class, Bool.class, "valueOf", bool.class);
129  
      this;
130  
    }
131  
    
132  
    if (type == Type.CHAR) {
133  
      il.append(new ILOAD(stackIdx));
134  
      invokeStatic(Char.class, Char.class, "valueOf", char.class);
135  
      this;
136  
    }
137  
    
138  
    if (type == Type.SHORT) {
139  
      il.append(new ILOAD(stackIdx));
140  
      invokeStatic(Short.class, Short.class, "valueOf", short.class);
141  
      this;
142  
    }
143  
    
144  
    if (type == Type.INT) {
145  
      il.append(new ILOAD(stackIdx));
146  
      invokeStatic(Int.class, Int.class, "valueOf", int.class);
147  
      this;
148  
    }
149  
    
150  
    if (type == Type.LONG) {
151  
      il.append(new LLOAD(stackIdx));
152  
      invokeStatic(Long.class, Long.class, "valueOf", long.class);
153  
      this;
154  
    }
155  
      
156  
    if (type == Type.FLOAT) {
157  
      il.append(new LLOAD(stackIdx));
158  
      invokeStatic(Float.class, Float.class, "valueOf", float.class);
159  
      this;
160  
    }
161  
      
162  
    if (type == Type.DOUBLE) {
163  
      il.append(new DLOAD(stackIdx));
164  
      invokeStatic(Double.class, Double.class, "valueOf", double.class);
165  
      this;
166  
    }
167  
      
168  
    ret aload(stackIdx);
169  
  }
170  
    
171  
  selfType aload(int stackIdx) {  
172  
    il.append(new ALOAD(stackIdx));
173  
    this;
174  
  }
175  
  
176  
  selfType stringConstant(S s) {
177  
    il.append(new PUSH(cp, s));
178  
    this;
179  
  }
180  
  
181  
  selfType classConstant(Class c) {
182  
    if (classConstantWorkaround) {
183  
      stringConstant(c.getName());
184  
      invokeStatic(Class.class, Class.class, "forName", S);
185  
    } else {
186  
      var ldc = new LDC(classRef(c));
187  
      assertEquals("classConstant", ldc.getValue(cp), wrapType(c));
188  
      il.append(ldc);
189  
    }
190  
    this;
191  
  }
192  
  
193  
  selfType intConstant aka intConst(int i) {
194  
    if (i >= -1 && i <= 5) ret add(new ICONST(i));
195  
    if (i == (byte) i) ret add(new BIPUSH((byte) i));
196  
    if (i == (short) i) ret add(new SIPUSH((short) i));
197  
    ret add(new LDC(cp.addInteger(i)));
198  
  }
199  
  
200  
  selfType doubleConstant aka doubleConst(double d) {
201  
    ret add(new LDC2_W(cp.addDouble(d)));
202  
  }
203  
  
204  
  selfType boolConstant(bool b) {
205  
    ret intConstant(b ? 1 : 0);
206  
  }
207  
  
208  
  selfType invokeVirtual(Class c, Class returnType, S methodName,
209  
    Class... argTypes) {
210  
    Method m = findNonStaticMethod_precise_onTypes(c, methodName, argTypes);
211  
    if (m == null) fail("Method not found: " + className(c) + "."
212  
      + formatFunctionCall(methodName, argTypes) + " returning " + className(returnType));
213  
    il.append(factory.createInvoke(className(c), methodName,
214  
      wrapType(m.getReturnType()),
215  
      wrapTypes(m.getParameterTypes()), Const.INVOKEVIRTUAL));
216  
    this;
217  
  }
218  
    
219  
  selfType invokeInterface(Class c, Class returnType, S methodName,
220  
    Class... argTypes) {
221  
    Method m = mostApplicableMethod_onTypes(
222  
      filter(nonDefaultInterfaceMethods(c), _m -> _m.getName().equals(methodName)),
223  
      argTypes);
224  
    if (m == null) fail("Method not found: " + className(c) + "."
225  
      + formatFunctionCall(methodName, argTypes) + " returning " + className(returnType));
226  
    il.append(factory.createInvoke(className(c), methodName,
227  
      wrapType(m.getReturnType()),
228  
      wrapTypes(m.getParameterTypes()), Const.INVOKEINTERFACE));
229  
    this;
230  
  }
231  
    
232  
  selfType invokeStatic(Class c, Class returnType, S methodName,
233  
    Class... argTypes) {
234  
    Method m = findMethod_precise_onTypes(c, methodName, argTypes);
235  
    if (m == null) fail("Method not found: " + className(c) + "."
236  
      + formatFunctionCall(methodName, argTypes) + " returning " + className(returnType));
237  
    il.append(factory.createInvoke(className(c), methodName,
238  
      wrapType(m.getReturnType()),
239  
      wrapTypes(m.getParameterTypes()), Const.INVOKESTATIC));
240  
    this;
241  
  }
242  
  
243  
  selfType areturn() {
244  
    il.append(InstructionConst.ARETURN);
245  
    this;
246  
  }
247  
  
248  
  selfType _return() {
249  
    il.append(InstructionConst.RETURN);
250  
    this;
251  
  }
252  
  
253  
  selfType returnPrimitive(Class type) {
254  
    il.append(primitiveReturnInstruction(type));
255  
    this;
256  
  }
257  
  
258  
  ReturnInstruction primitiveReturnInstruction(Class type) {
259  
    assertTrue(isPrimitiveType(type));
260  
    
261  
    if (type == long.class) ret InstructionConst.LRETURN;
262  
    if (type == float.class) ret InstructionConst.FRETURN;
263  
    if (type == double.class) ret InstructionConst.DRETURN;
264  
    ret InstructionConst.IRETURN;
265  
  }
266  
  
267  
  meta-for Instruction also as BranchInstruction {
268  
    selfType add(Instruction i) {
269  
      il.append(i);
270  
      if (verboseAdd)
271  
        print("> " + i);
272  
      this;
273  
    }
274  
    
275  
    <A extends Instruction> A addAndReturn(A i) {
276  
      add(i);
277  
      ret i;
278  
    }
279  
  }
280  
281  
  void done() {
282  
    mg.stripAttributes(true);
283  
    mg.setMaxStack();
284  
    mg.setMaxLocals();
285  
    cg.addMethod(mg.getMethod());
286  
  }
287  
  
288  
  JVMStackCellType convertToObject(JVMStackCellType stackTop) {
289  
    if (stackTop == objValue) {}
290  
    else if (stackTop == JVMStackCellType.intValue)
291  
      invokeStatic(Int, Int, "valueOf", int.class);
292  
    else if (stackTop == JVMStackCellType.doubleValue)
293  
      invokeStatic(Double.class, Double.class, "valueOf", double.class);
294  
    else if (stackTop == JVMStackCellType.none)
295  
      add(new ACONST_NULL);
296  
    else
297  
      fail("TODO: add conversion for stack cell type: " + stackTop);
298  
    ret objValue;
299  
  }
300  
  
301  
  void discardStackTop(JVMStackCellType stackTop) {
302  
    if (stackTop == JVMStackCellType.none) {}
303  
    else if (stackTop == JVMStackCellType.doubleValue
304  
      || stackTop == JVMStackCellType.longValue)
305  
      add(new POP2);
306  
    else
307  
      add(new POP);
308  
  }
309  
  
310  
  int classRef(O c) {
311  
    ret cp.addClass((ObjectType) wrapType(assertNotNull(c)));
312  
  }
313  
  
314  
  selfType checkCast(O c) {
315  
    ret add(new CHECKCAST(classRef(c)));
316  
  }
317  
318  
  selfType loadNull() {
319  
    ret add(new ACONST_NULL);
320  
  }
321  
  
322  
  InstructionHandle here() {
323  
    ret il.append(new NOP);
324  
  }
325  
  
326  
  GOTO forwardGoto() {
327  
    ret addAndReturn(new GOTO(null));
328  
  }
329  
  
330  
  void returnWithType(JVMStackCellType stackTop) {
331  
    if (stackTop == JVMStackCellType.objValue)
332  
      areturn();
333  
    else if (stackTop == JVMStackCellType.intValue)
334  
      add(new IRETURN);
335  
    else if (stackTop == JVMStackCellType.doubleValue)
336  
      add(new DRETURN);
337  
    else if (stackTop == JVMStackCellType.none)
338  
      _return();
339  
    else
340  
      fail("TODO: add return for stack cell type: " + stackTop);
341  
  }
342  
  
343  
  void getStaticField(S className, S fieldName, Class type) {
344  
    il.append(factory.createGetStatic(className, fieldName, wrapType(type));
345  
  }
346  
}

Author comment

Began life as a copy of #1034300

download  show line numbers  debug dex  old transpilations   

Travelled to 4 computer(s): bhatertpkbcr, ekrmjmnbrukm, mowyntqkapby, mqqgnosmbjvj

No comments. add comment

Snippet ID: #1034309
Snippet name: MethodMaker [BCEL helper]
Eternal ID of this version: #1034309/100
Text MD5: 8bc08537462734c591d36bb396d28b74
Transpilation MD5: bba3e38fc737735f2b3463fe3ac01d01
Author: stefan
Category: javax / byte code generation
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-12-18 03:55:00
Source code size: 9936 bytes / 346 lines
Pitched / IR pitched: No / No
Views / Downloads: 318 / 880
Version history: 99 change(s)
Referenced in: [show references]