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 | } |
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: | 411 / 995 |
Version history: | 99 change(s) |
Referenced in: | [show references] |