Skip to content

Commit 630ee15

Browse files
committed
improve controller method enhancer, now render arg table support fields and methods in addition to params and local variables
1 parent 290ab06 commit 630ee15

4 files changed

Lines changed: 125 additions & 150 deletions

File tree

src/main/java/act/controller/builtin/CliOverHttp.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package act.controller.builtin;
22

3+
import act.Act;
4+
import act.app.ActionContext;
35
import act.cli.CliDispatcher;
46
import act.conf.AppConfig;
57
import act.controller.Controller;
68
import org.osgl.http.H;
79
import org.osgl.mvc.annotation.GetAction;
810
import org.osgl.mvc.result.Result;
911
import org.osgl.util.C;
12+
import org.osgl.util.S;
1013

1114
import javax.inject.Inject;
1215
import java.util.List;
@@ -30,10 +33,10 @@ public class CliOverHttp {
3033

3134
@GetAction
3235
public Result home() {
33-
List<String> mru = mru();
34-
return render(dispatcher, mru);
36+
return render(dispatcher, mru());
3537
}
3638

39+
3740
private List<String> mru() {
3841
List<String> mru = session.cached("cli_over_http_mru");
3942
if (null == mru) {

src/main/java/act/controller/bytecode/HandlerEnhancer.java

Lines changed: 114 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
import act.asm.*;
55
import act.asm.tree.*;
66
import act.controller.meta.HandlerMethodMetaInfo;
7-
import act.controller.meta.LocalVariableMetaInfo;
87
import act.controller.meta.HandlerParamMetaInfo;
8+
import act.controller.meta.LocalVariableMetaInfo;
99
import act.util.AsmTypes;
1010
import org.osgl.logging.LogManager;
1111
import org.osgl.logging.Logger;
@@ -16,6 +16,8 @@
1616

1717
import java.util.*;
1818

19+
import static act.asm.tree.AbstractInsnNode.*;
20+
1921
public class HandlerEnhancer extends MethodVisitor implements Opcodes {
2022

2123
private static final Logger logger = LogManager.get(HandlerEnhancer.class);
@@ -115,7 +117,7 @@ void doIt() {
115117
Segment cur = null;
116118
while (itr.hasNext()) {
117119
AbstractInsnNode insn = itr.next();
118-
if (insn.getType() == AbstractInsnNode.LABEL) {
120+
if (insn.getType() == LABEL) {
119121
cur = new Segment(((LabelNode) insn).getLabel(), meta, instructions, itr, this);
120122
} else if (null != cur) {
121123
cur.handle(insn);
@@ -159,7 +161,25 @@ AbstractInsnNode.METHOD_INSN, new InvocationHandler(this, meta)
159161
trans.lblList.add(start);
160162
}
161163

162-
protected void handle(AbstractInsnNode node) {
164+
String varName(int index) {
165+
Label lbl = startLabel;
166+
int pos = -1;
167+
List<Label> lblList = trans.lblList;
168+
while (null != lbl) {
169+
LocalVariableMetaInfo var = meta.localVariable(index, lbl);
170+
if (null != var) return var.name();
171+
if (-1 == pos) {
172+
pos = lblList.indexOf(lbl);
173+
if (pos <= 0) {
174+
return null;
175+
}
176+
}
177+
lbl = lblList.get(--pos);
178+
}
179+
return null;
180+
}
181+
182+
void handle(AbstractInsnNode node) {
163183
InstructionHandler handler = handlers.get(node.getType());
164184
if (null != handler) {
165185
handler.handle(node);
@@ -202,29 +222,96 @@ private void injectRenderArgSetCode(AbstractInsnNode invokeNode) {
202222
AbstractInsnNode node = invokeNode.getPrevious();
203223
List<LoadInsnInfo> loadInsnInfoList = C.newList();
204224
String templatePath = null;
225+
String renderArgName = null;
226+
InsnList nodeList = new InsnList();
227+
boolean invalidParam = false;
205228
while (null != node) {
206229
int type = node.getType();
207230
boolean breakWhile = false;
208231
switch (type) {
209-
case AbstractInsnNode.LABEL:
210-
case AbstractInsnNode.FRAME:
232+
case LABEL:
233+
case FRAME:
211234
node = node.getNext();
212235
breakWhile = true;
236+
if (!invalidParam && null != renderArgName) {
237+
loadInsnInfoList.add(new LoadInsnInfo(renderArgName, nodeList));
238+
}
213239
break;
214-
case AbstractInsnNode.VAR_INSN:
215-
VarInsnNode n = (VarInsnNode) node;
216-
if (0 == n.var && !segment.meta.isStatic()) {
217-
// skip "this"
240+
case INSN:
241+
switch (node.getOpcode()) {
242+
case ICONST_0:
243+
case ICONST_1:
244+
case ICONST_2:
245+
case ICONST_3:
246+
case ICONST_4:
247+
case ICONST_5:
248+
if (!invalidParam && null != renderArgName) {
249+
loadInsnInfoList.add(new LoadInsnInfo(renderArgName, nodeList));
250+
}
251+
renderArgName = null;
252+
nodeList = new InsnList();
253+
invalidParam = false;
254+
break;
255+
case AASTORE:
256+
renderArgName = null;
257+
nodeList = new InsnList();
258+
invalidParam = false;
259+
}
260+
break;
261+
case VAR_INSN:
262+
if (null == renderArgName) {
263+
VarInsnNode vn = (VarInsnNode) node;
264+
if (0 == vn.var && !segment.meta.isStatic()) {
265+
// skip "this"
266+
} else {
267+
renderArgName = segment.varName(vn.var);
268+
}
269+
}
270+
nodeList.insert(node.clone(C.<LabelNode, LabelNode>map()));
271+
break;
272+
case METHOD_INSN:
273+
if (invalidParam) {
218274
break;
219275
}
220-
LoadInsn insn = LoadInsn.of(n.getOpcode());
221-
if (insn.isStoreInsn()) {
276+
if (null == renderArgName) {
277+
MethodInsnNode mn = (MethodInsnNode) node;
278+
if (mn.desc.startsWith("()")) {
279+
// if method does not have parameter, e.g. `this.foo()` then
280+
// we take it's name as render arg name
281+
renderArgName = mn.name;
282+
} else if (!"valueOf".equals(mn.name)) {
283+
// if method is not something like `Integer.valueOf` then
284+
// we say it is an invalid render parameter
285+
logger.warn("Invalid render argument found in %s: method with param is not supported", segment.meta.fullName());
286+
invalidParam = true;
287+
}
288+
}
289+
nodeList.insert(node.clone(C.<LabelNode, LabelNode>map()));
290+
break;
291+
case INT_INSN:
292+
if (BIPUSH == node.getOpcode()) {
293+
if (!invalidParam && null != renderArgName) {
294+
loadInsnInfoList.add(new LoadInsnInfo(renderArgName, nodeList));
295+
}
296+
renderArgName = null;
297+
nodeList = new InsnList();
298+
invalidParam = false;
299+
}
300+
break;
301+
case FIELD_INSN:
302+
if (invalidParam) {
222303
break;
223304
}
224-
LoadInsnInfo info = new LoadInsnInfo(insn, n.var);
225-
loadInsnInfoList.add(info);
305+
if (null == renderArgName) {
306+
FieldInsnNode n = (FieldInsnNode) node;
307+
renderArgName = n.name;
308+
}
309+
nodeList.insert(node.clone(C.<LabelNode, LabelNode>map()));
226310
break;
227311
case AbstractInsnNode.LDC_INSN:
312+
if (invalidParam) {
313+
break;
314+
}
228315
LdcInsnNode ldc = (LdcInsnNode) node;
229316
if (null != templatePath) {
230317
logger.warn("Cannot have more than one template path parameter in the render call. Template path[%s] ignored", templatePath);
@@ -233,8 +320,6 @@ private void injectRenderArgSetCode(AbstractInsnNode invokeNode) {
233320
} else {
234321
templatePath = ldc.cst.toString();
235322
}
236-
default:
237-
//System.out.printf("type\n");
238323
}
239324
if (breakWhile) {
240325
break;
@@ -269,7 +354,7 @@ private void injectRenderArgSetCode(AbstractInsnNode invokeNode) {
269354
StringBuilder sb = S.builder();
270355
for (int i = 0; i < len; ++i) {
271356
LoadInsnInfo info = loadInsnInfoList.get(i);
272-
info.appendTo(list, segment, sb);
357+
info.appendTo(list, sb);
273358
}
274359
LdcInsnNode ldc = new LdcInsnNode(sb.toString());
275360
list.add(ldc);
@@ -325,7 +410,7 @@ private void injectThrowCode(AbstractInsnNode invokeNode) {
325410
boolean breakWhile = false;
326411
int type = next.getType();
327412
switch (type) {
328-
case AbstractInsnNode.LABEL:
413+
case LABEL:
329414
next = next.getNext();
330415
break;
331416
case AbstractInsnNode.LINE:
@@ -337,7 +422,7 @@ private void injectThrowCode(AbstractInsnNode invokeNode) {
337422
instructions.remove(next);
338423
next = tmp;
339424
break;
340-
case AbstractInsnNode.INSN:
425+
case INSN:
341426
int op = next.getOpcode();
342427
if (op == RETURN) {
343428
tmp = next.getNext();
@@ -349,7 +434,7 @@ private void injectThrowCode(AbstractInsnNode invokeNode) {
349434
}
350435
break;
351436
}
352-
case AbstractInsnNode.FRAME:
437+
case FRAME:
353438
breakWhile = true;
354439
break;
355440
default:
@@ -365,148 +450,30 @@ private void injectThrowCode(AbstractInsnNode invokeNode) {
365450
}
366451
}
367452

368-
private static final int _I = 'I';
369-
private static final int _Z = 'Z';
370-
private static final int _S = 'S';
371-
private static final int _B = 'B';
372-
private static final int _C = 'C';
373-
374-
private static enum LoadInsn {
375-
I(ILOAD) {
376-
void appendTo(InsnList list, int varIndex, String type) {
377-
super.appendTo(list, varIndex, type);
378-
String owner, desc;
379-
switch (type.hashCode()) {
380-
case _I:
381-
owner = "java/lang/Integer";
382-
desc = "(I)Ljava/lang/Integer;";
383-
break;
384-
case _Z:
385-
owner = "java/lang/Boolean";
386-
desc = "(Z)Ljava/lang/Boolean;";
387-
break;
388-
case _S:
389-
owner = "java/lang/Short";
390-
desc = "(S)Ljava/lang/Short";
391-
break;
392-
case _B:
393-
owner = "java/lang/Byte";
394-
desc = "(B)Ljava/lang/Byte;";
395-
break;
396-
case _C:
397-
owner = "java/lang/Character";
398-
desc = "(C)Ljava/lang/Character;";
399-
break;
400-
default:
401-
throw E.unexpected("int var type not recognized: %s", type);
402-
}
403-
MethodInsnNode method = new MethodInsnNode(INVOKESTATIC, owner, "valueOf", desc, false);
404-
list.add(method);
405-
}
406-
}, L(LLOAD) {
407-
@Override
408-
void appendTo(InsnList list, int varIndex, String type) {
409-
super.appendTo(list, varIndex, type);
410-
MethodInsnNode method = new MethodInsnNode(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
411-
list.add(method);
412-
}
413-
}, F(FLOAD) {
414-
@Override
415-
void appendTo(InsnList list, int varIndex, String type) {
416-
super.appendTo(list, varIndex, type);
417-
MethodInsnNode method = new MethodInsnNode(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
418-
list.add(method);
419-
}
420-
}, D(DLOAD) {
421-
@Override
422-
void appendTo(InsnList list, int varIndex, String type) {
423-
super.appendTo(list, varIndex, type);
424-
MethodInsnNode method = new MethodInsnNode(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
425-
list.add(method);
426-
}
427-
}, A(ALOAD), Store(-1) {
428-
@Override
429-
void appendTo(InsnList list, int varIndex, String type) {
430-
throw E.unsupport();
431-
}
432-
};
433-
private int opcode;
434-
435-
LoadInsn(int opcode) {
436-
this.opcode = opcode;
437-
}
438-
439-
static LoadInsn of(int opcode) {
440-
switch (opcode) {
441-
case ILOAD:
442-
return I;
443-
case LLOAD:
444-
return L;
445-
case FLOAD:
446-
return F;
447-
case DLOAD:
448-
return D;
449-
case ALOAD:
450-
return A;
451-
default:
452-
return Store;
453-
}
454-
}
455-
456-
boolean isStoreInsn() {
457-
return this == Store;
458-
}
459-
460-
void appendTo(InsnList list, int varIndex, String type) {
461-
VarInsnNode load = new VarInsnNode(opcode, varIndex);
462-
list.add(load);
463-
}
464-
}
465-
466453
private static class LoadInsnInfo {
467-
LoadInsn insn;
468-
int index;
454+
private String name;
455+
private InsnList insnList;
469456

470-
LoadInsnInfo(LoadInsn insn, int index) {
471-
this.insn = insn;
472-
this.index = index;
457+
LoadInsnInfo(String name, InsnList insnList) {
458+
this.insnList = insnList;
459+
this.name = name;
473460
}
474461

475-
void appendTo(InsnList list, Segment segment, StringBuilder paramNames) {
476-
LocalVariableMetaInfo var = var(segment);
477-
if (null == var) return;
478-
LdcInsnNode ldc = new LdcInsnNode(var.name());
462+
void appendTo(InsnList list, StringBuilder paramNames) {
463+
LdcInsnNode ldc = new LdcInsnNode(name);
479464
list.add(ldc);
480-
insn.appendTo(list, index, var.type());
465+
list.add(insnList);
481466
MethodInsnNode invokeRenderArg = new MethodInsnNode(INVOKEVIRTUAL, AsmTypes.ACTION_CONTEXT_INTERNAL_NAME, RENDER_NM, RENDER_DESC, false);
482467
list.add(invokeRenderArg);
483468
if (paramNames.length() != 0) {
484469
paramNames.append(',');
485470
}
486-
paramNames.append(var.name());
487-
}
488-
489-
LocalVariableMetaInfo var(Segment segment) {
490-
Label lbl = segment.startLabel;
491-
int pos = -1;
492-
List<Label> lblList = segment.trans.lblList;
493-
while (null != lbl) {
494-
LocalVariableMetaInfo var = segment.meta.localVariable(index, lbl);
495-
if (null != var) return var;
496-
if (-1 == pos) {
497-
pos = lblList.indexOf(lbl);
498-
if (pos <= 0) {
499-
return null;
500-
}
501-
}
502-
lbl = lblList.get(--pos);
503-
}
504-
return null;
471+
paramNames.append(name);
505472
}
506473

507474
@Override
508475
public String toString() {
509-
return S.fmt("%sLoad %s", insn, index);
476+
return S.fmt("Load %s", name);
510477
}
511478
}
512479
}

0 commit comments

Comments
 (0)