44import act .asm .*;
55import act .asm .tree .*;
66import act .controller .meta .HandlerMethodMetaInfo ;
7- import act .controller .meta .LocalVariableMetaInfo ;
87import act .controller .meta .HandlerParamMetaInfo ;
8+ import act .controller .meta .LocalVariableMetaInfo ;
99import act .util .AsmTypes ;
1010import org .osgl .logging .LogManager ;
1111import org .osgl .logging .Logger ;
1616
1717import java .util .*;
1818
19+ import static act .asm .tree .AbstractInsnNode .*;
20+
1921public 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