@@ -223,6 +223,7 @@ public class Compiler implements Opcodes{
223223static final public Var METHOD = Var .create (null ).setDynamic ();
224224
225225//null or not
226+ static final public Var IN_TRY_BLOCK = Var .create (null ).setDynamic ();
226227static final public Var IN_CATCH_FINALLY = Var .create (null ).setDynamic ();
227228
228229static final public Var NO_RECUR = Var .create (null ).setDynamic ();
@@ -371,6 +372,10 @@ static boolean isSpecial(Object sym){
371372 return specials .containsKey (sym );
372373}
373374
375+ static boolean inTailCall (C context ) {
376+ return (context == C .RETURN ) && (IN_TRY_BLOCK .deref () == null );
377+ }
378+
374379static Symbol resolveSymbol (Symbol sym ){
375380 //already qualified or classname?
376381 if (sym .name .indexOf ('.' ) > 0 )
@@ -1002,12 +1007,13 @@ else if(instance != null && instance.hasJavaClass() && instance.getJavaClass() !
10021007 Symbol sym = (Symbol ) RT .first (call );
10031008 Symbol tag = tagOf (form );
10041009 PersistentVector args = PersistentVector .EMPTY ;
1010+ boolean tailPosition = inTailCall (context );
10051011 for (ISeq s = RT .next (call ); s != null ; s = s .next ())
10061012 args = args .cons (analyze (context == C .EVAL ? context : C .EXPRESSION , s .first ()));
10071013 if (c != null )
1008- return new StaticMethodExpr (source , line , column , tag , c , munge (sym .name ), args );
1014+ return new StaticMethodExpr (source , line , column , tag , c , munge (sym .name ), args , tailPosition );
10091015 else
1010- return new InstanceMethodExpr (source , line , column , tag , instance , munge (sym .name ), args );
1016+ return new InstanceMethodExpr (source , line , column , tag , instance , munge (sym .name ), args , tailPosition );
10111017 }
10121018 }
10131019 }
@@ -1444,13 +1450,15 @@ static class InstanceMethodExpr extends MethodExpr{
14441450 public final int line ;
14451451 public final int column ;
14461452 public final Symbol tag ;
1453+ public final boolean tailPosition ;
14471454 public final java .lang .reflect .Method method ;
14481455
14491456 final static Method invokeInstanceMethodMethod =
14501457 Method .getMethod ("Object invokeInstanceMethod(Object,String,Object[])" );
14511458
14521459
1453- public InstanceMethodExpr (String source , int line , int column , Symbol tag , Expr target , String methodName , IPersistentVector args )
1460+ public InstanceMethodExpr (String source , int line , int column , Symbol tag , Expr target ,
1461+ String methodName , IPersistentVector args , boolean tailPosition )
14541462 {
14551463 this .source = source ;
14561464 this .line = line ;
@@ -1459,6 +1467,7 @@ public InstanceMethodExpr(String source, int line, int column, Symbol tag, Expr
14591467 this .methodName = methodName ;
14601468 this .target = target ;
14611469 this .tag = tag ;
1470+ this .tailPosition = tailPosition ;
14621471 if (target .hasJavaClass () && target .getJavaClass () != null )
14631472 {
14641473 List methods = Reflector .getMethods (target .getJavaClass (), args .count (), methodName , false );
@@ -1552,10 +1561,10 @@ public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){
15521561 gen .checkCast (type );
15531562 MethodExpr .emitTypedArgs (objx , gen , method .getParameterTypes (), args );
15541563 gen .visitLineNumber (line , gen .mark ());
1555- if (context == C . RETURN )
1564+ if (tailPosition )
15561565 {
15571566 ObjMethod method = (ObjMethod ) METHOD .deref ();
1558- method .emitClearLocals (gen );
1567+ method .emitClearThis (gen );
15591568 }
15601569 Method m = new Method (methodName , Type .getReturnType (method ), Type .getArgumentTypes (method ));
15611570 if (method .getDeclaringClass ().isInterface ())
@@ -1626,12 +1635,14 @@ static class StaticMethodExpr extends MethodExpr{
16261635 public final int column ;
16271636 public final java .lang .reflect .Method method ;
16281637 public final Symbol tag ;
1638+ public final boolean tailPosition ;
16291639 final static Method forNameMethod = Method .getMethod ("Class classForName(String)" );
16301640 final static Method invokeStaticMethodMethod =
16311641 Method .getMethod ("Object invokeStaticMethod(Class,String,Object[])" );
16321642 final static Keyword warnOnBoxedKeyword = Keyword .intern ("warn-on-boxed" );
16331643
1634- public StaticMethodExpr (String source , int line , int column , Symbol tag , Class c , String methodName , IPersistentVector args )
1644+ public StaticMethodExpr (String source , int line , int column , Symbol tag , Class c ,
1645+ String methodName , IPersistentVector args , boolean tailPosition )
16351646 {
16361647 this .c = c ;
16371648 this .methodName = methodName ;
@@ -1640,6 +1651,7 @@ public StaticMethodExpr(String source, int line, int column, Symbol tag, Class c
16401651 this .line = line ;
16411652 this .column = column ;
16421653 this .tag = tag ;
1654+ this .tailPosition = tailPosition ;
16431655
16441656 List methods = Reflector .getMethods (c , args .count (), methodName , true );
16451657 if (methods .isEmpty ())
@@ -1778,10 +1790,10 @@ public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
17781790 MethodExpr .emitTypedArgs (objx , gen , method .getParameterTypes (), args );
17791791 gen .visitLineNumber (line , gen .mark ());
17801792 //Type type = Type.getObjectType(className.replace('.', '/'));
1781- if (context == C . RETURN )
1793+ if (tailPosition )
17821794 {
17831795 ObjMethod method = (ObjMethod ) METHOD .deref ();
1784- method .emitClearLocals (gen );
1796+ method .emitClearThis (gen );
17851797 }
17861798 Type type = Type .getType (c );
17871799 Method m = new Method (methodName , Type .getReturnType (method ), Type .getArgumentTypes (method ));
@@ -2265,13 +2277,14 @@ public Expr parse(C context, Object frm) {
22652277 }
22662278 else
22672279 {
2268- if (bodyExpr == null )
2269- try {
2270- Var .pushThreadBindings (RT .map (NO_RECUR , true ));
2271- bodyExpr = (new BodyExpr .Parser ()).parse (context , RT .seq (body ));
2272- } finally {
2273- Var .popThreadBindings ();
2274- }
2280+ if (bodyExpr == null )
2281+ try {
2282+ Var .pushThreadBindings (RT .map (NO_RECUR , true , IN_TRY_BLOCK , RT .T ));
2283+ bodyExpr = (new BodyExpr .Parser ()).parse (context , RT .seq (body ));
2284+ } finally {
2285+ Var .popThreadBindings ();
2286+ }
2287+
22752288 if (Util .equals (op , CATCH ))
22762289 {
22772290 Class c = HostExpr .maybeClass (RT .second (f ), false );
@@ -2319,17 +2332,21 @@ public Expr parse(C context, Object frm) {
23192332 }
23202333 }
23212334 }
2322- if (bodyExpr == null ) {
2323- try
2324- {
2325- Var .pushThreadBindings (RT .map (NO_RECUR , true ));
2326- bodyExpr = (new BodyExpr .Parser ()).parse (C .EXPRESSION , RT .seq (body ));
2327- }
2328- finally
2329- {
2330- Var .popThreadBindings ();
2331- }
2332- }
2335+ if (bodyExpr == null )
2336+ {
2337+ // this codepath is hit when there is neither catch or finally, e.g. (try (expr))
2338+ // return a body expr directly
2339+ try
2340+ {
2341+ Var .pushThreadBindings (RT .map (NO_RECUR , true ));
2342+ bodyExpr = (new BodyExpr .Parser ()).parse (context , RT .seq (body ));
2343+ }
2344+ finally
2345+ {
2346+ Var .popThreadBindings ();
2347+ }
2348+ return bodyExpr ;
2349+ }
23332350
23342351 return new TryExpr (bodyExpr , catches , finallyExpr , retLocal ,
23352352 finallyLocal );
@@ -2577,23 +2594,13 @@ public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
25772594 gen .newInstance (type );
25782595 gen .dup ();
25792596 MethodExpr .emitTypedArgs (objx , gen , ctor .getParameterTypes (), args );
2580- if (context == C .RETURN )
2581- {
2582- ObjMethod method = (ObjMethod ) METHOD .deref ();
2583- method .emitClearLocals (gen );
2584- }
25852597 gen .invokeConstructor (type , new Method ("<init>" , Type .getConstructorDescriptor (ctor )));
25862598 }
25872599 else
25882600 {
25892601 gen .push (destubClassName (c .getName ()));
25902602 gen .invokeStatic (RT_TYPE , forNameMethod );
25912603 MethodExpr .emitArgsAsArray (args , objx , gen );
2592- if (context == C .RETURN )
2593- {
2594- ObjMethod method = (ObjMethod ) METHOD .deref ();
2595- method .emitClearLocals (gen );
2596- }
25972604 gen .invokeStatic (REFLECTOR_TYPE , invokeConstructorMethod );
25982605 }
25992606 if (context == C .STATEMENT )
@@ -3570,6 +3577,7 @@ static class InvokeExpr implements Expr{
35703577 public final IPersistentVector args ;
35713578 public final int line ;
35723579 public final int column ;
3580+ public final boolean tailPosition ;
35733581 public final String source ;
35743582 public boolean isProtocol = false ;
35753583 public boolean isDirect = false ;
@@ -3579,12 +3587,14 @@ static class InvokeExpr implements Expr{
35793587 static Keyword onKey = Keyword .intern ("on" );
35803588 static Keyword methodMapKey = Keyword .intern ("method-map" );
35813589
3582- public InvokeExpr (String source , int line , int column , Symbol tag , Expr fexpr , IPersistentVector args ) {
3590+ public InvokeExpr (String source , int line , int column , Symbol tag , Expr fexpr , IPersistentVector args , boolean tailPosition ) {
35833591 this .source = source ;
35843592 this .fexpr = fexpr ;
35853593 this .args = args ;
35863594 this .line = line ;
35873595 this .column = column ;
3596+ this .tailPosition = tailPosition ;
3597+
35883598 if (fexpr instanceof VarExpr )
35893599 {
35903600 Var fvar = ((VarExpr )fexpr ).var ;
@@ -3736,10 +3746,10 @@ void emitArgsAndCall(int firstArgToEmit, C context, ObjExpr objx, GeneratorAdapt
37363746 }
37373747 gen .visitLineNumber (line , gen .mark ());
37383748
3739- if (context == C . RETURN )
3749+ if (tailPosition )
37403750 {
37413751 ObjMethod method = (ObjMethod ) METHOD .deref ();
3742- method .emitClearLocals (gen );
3752+ method .emitClearThis (gen );
37433753 }
37443754
37453755 gen .invokeInterface (IFN_TYPE , new Method ("invoke" , OBJECT_TYPE , ARG_TYPES [Math .min (MAX_POSITIONAL_ARITY + 1 ,
@@ -3755,6 +3765,7 @@ public Class getJavaClass() {
37553765 }
37563766
37573767 static public Expr parse (C context , ISeq form ) {
3768+ boolean tailPosition = inTailCall (context );
37583769 if (context != C .EVAL )
37593770 context = C .EXPRESSION ;
37603771 Expr fexpr = analyze (context , form .first ());
@@ -3817,7 +3828,7 @@ static public Expr parse(C context, ISeq form) {
38173828// throw new IllegalArgumentException(
38183829// String.format("No more than %d args supported", MAX_POSITIONAL_ARITY));
38193830
3820- return new InvokeExpr ((String ) SOURCE .deref (), lineDeref (), columnDeref (), tagOf (form ), fexpr , args );
3831+ return new InvokeExpr ((String ) SOURCE .deref (), lineDeref (), columnDeref (), tagOf (form ), fexpr , args , tailPosition );
38213832 }
38223833}
38233834
@@ -5758,6 +5769,11 @@ void emitClearLocalsOld(GeneratorAdapter gen){
57585769 }
57595770 }
57605771 }
5772+
5773+ void emitClearThis (GeneratorAdapter gen ) {
5774+ gen .visitInsn (Opcodes .ACONST_NULL );
5775+ gen .visitVarInsn (Opcodes .ASTORE , 0 );
5776+ }
57615777}
57625778
57635779public static class LocalBinding {
@@ -6183,14 +6199,14 @@ public Expr parse(C context, Object frm) {
61836199 {
61846200 if (recurMismatches != null && RT .booleanCast (recurMismatches .nth (i /2 )))
61856201 {
6186- init = new StaticMethodExpr ("" , 0 , 0 , null , RT .class , "box" , RT .vector (init ));
6202+ init = new StaticMethodExpr ("" , 0 , 0 , null , RT .class , "box" , RT .vector (init ), false );
61876203 if (RT .booleanCast (RT .WARN_ON_REFLECTION .deref ()))
61886204 RT .errPrintWriter ().println ("Auto-boxing loop arg: " + sym );
61896205 }
61906206 else if (maybePrimitiveType (init ) == int .class )
6191- init = new StaticMethodExpr ("" , 0 , 0 , null , RT .class , "longCast" , RT .vector (init ));
6207+ init = new StaticMethodExpr ("" , 0 , 0 , null , RT .class , "longCast" , RT .vector (init ), false );
61926208 else if (maybePrimitiveType (init ) == float .class )
6193- init = new StaticMethodExpr ("" , 0 , 0 , null , RT .class , "doubleCast" , RT .vector (init ));
6209+ init = new StaticMethodExpr ("" , 0 , 0 , null , RT .class , "doubleCast" , RT .vector (init ), false );
61946210 }
61956211 //sequential enhancement of env (like Lisp let*)
61966212 try
0 commit comments