You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by dd...@apache.org on 2015/12/15 23:23:46 UTC

[05/23] incubator-freemarker git commit: Simplified stack trace handling (no hide-in-parent logic), allows some optimization in the "elementsToVisit" returning mechanism.

Simplified stack trace handling (no hide-in-parent logic), allows some optimization in the "elementsToVisit" returning mechanism.


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/89585c8e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/89585c8e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/89585c8e

Branch: refs/heads/2.3
Commit: 89585c8e5d23f169389c801d0cb012c76b18406a
Parents: c64251e
Author: ddekany <dd...@apache.org>
Authored: Fri Dec 4 00:41:21 2015 +0100
Committer: ddekany <dd...@apache.org>
Committed: Sat Dec 5 16:53:57 2015 +0100

----------------------------------------------------------------------
 src/main/java/freemarker/core/Assignment.java   |  2 +-
 .../freemarker/core/AssignmentInstruction.java  |  4 +-
 src/main/java/freemarker/core/AttemptBlock.java |  7 +-
 src/main/java/freemarker/core/AutoEscBlock.java |  4 +-
 .../java/freemarker/core/BlockAssignment.java   |  2 +-
 .../java/freemarker/core/BodyInstruction.java   |  7 +-
 .../java/freemarker/core/BreakInstruction.java  |  2 +-
 src/main/java/freemarker/core/Case.java         |  4 +-
 src/main/java/freemarker/core/Comment.java      |  2 +-
 .../java/freemarker/core/CompressedBlock.java   |  2 +-
 .../java/freemarker/core/ConditionalBlock.java  |  4 +-
 src/main/java/freemarker/core/DebugBreak.java   |  2 +-
 .../java/freemarker/core/DollarVariable.java    |  2 +-
 src/main/java/freemarker/core/ElseOfList.java   |  4 +-
 src/main/java/freemarker/core/Environment.java  | 67 +++++++-------------
 src/main/java/freemarker/core/EscapeBlock.java  | 13 ++--
 .../freemarker/core/FallbackInstruction.java    |  7 +-
 .../java/freemarker/core/FlushInstruction.java  |  2 +-
 src/main/java/freemarker/core/IfBlock.java      |  9 +--
 src/main/java/freemarker/core/Include.java      |  8 ++-
 src/main/java/freemarker/core/Items.java        |  2 +-
 .../java/freemarker/core/IteratorBlock.java     | 12 ++--
 src/main/java/freemarker/core/LibraryLoad.java  |  8 ++-
 .../java/freemarker/core/ListElseContainer.java |  2 +-
 src/main/java/freemarker/core/Macro.java        |  9 +--
 src/main/java/freemarker/core/MixedContent.java |  9 +--
 .../java/freemarker/core/NoAutoEscBlock.java    |  4 +-
 .../java/freemarker/core/NoEscapeBlock.java     |  4 +-
 .../java/freemarker/core/NumericalOutput.java   |  2 +-
 .../java/freemarker/core/OutputFormatBlock.java |  4 +-
 .../java/freemarker/core/PropertySetting.java   |  2 +-
 .../java/freemarker/core/RecoveryBlock.java     |  4 +-
 src/main/java/freemarker/core/RecurseNode.java  |  7 +-
 .../java/freemarker/core/ReturnInstruction.java |  2 +-
 src/main/java/freemarker/core/Sep.java          |  4 +-
 .../freemarker/core/StackTraceVisibility.java   |  8 +++
 .../java/freemarker/core/StopInstruction.java   |  2 +-
 src/main/java/freemarker/core/SwitchBlock.java  |  6 +-
 .../java/freemarker/core/TemplateElement.java   | 29 +++++----
 .../core/TemplateElementsToVisit.java           | 16 +----
 src/main/java/freemarker/core/TextBlock.java    |  2 +-
 ...nterruptionSupportTemplatePostProcessor.java |  2 +-
 .../java/freemarker/core/TransformBlock.java    |  7 +-
 .../java/freemarker/core/TrimInstruction.java   |  2 +-
 src/main/java/freemarker/core/UnifiedCall.java  |  7 +-
 src/main/java/freemarker/core/VisitNode.java    |  7 +-
 46 files changed, 157 insertions(+), 160 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/Assignment.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Assignment.java b/src/main/java/freemarker/core/Assignment.java
index 9ec1df7..bdce203 100644
--- a/src/main/java/freemarker/core/Assignment.java
+++ b/src/main/java/freemarker/core/Assignment.java
@@ -101,7 +101,7 @@ final class Assignment extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException {
+    TemplateElement[] accept(Environment env) throws TemplateException {
         final Environment.Namespace namespace;
         if (namespaceExp == null) {
             switch (scope) {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/AssignmentInstruction.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/AssignmentInstruction.java b/src/main/java/freemarker/core/AssignmentInstruction.java
index 3135876..1890b11 100644
--- a/src/main/java/freemarker/core/AssignmentInstruction.java
+++ b/src/main/java/freemarker/core/AssignmentInstruction.java
@@ -51,8 +51,8 @@ final class AssignmentInstruction extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
-        return new TemplateElementsToVisit(getRegulatedChildren());
+    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
+        return getRegulatedChildren();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/AttemptBlock.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/AttemptBlock.java b/src/main/java/freemarker/core/AttemptBlock.java
index 2af619f..390fc92 100644
--- a/src/main/java/freemarker/core/AttemptBlock.java
+++ b/src/main/java/freemarker/core/AttemptBlock.java
@@ -40,7 +40,7 @@ final class AttemptBlock extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
+    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
         env.visitAttemptRecover(attemptBlock, recoveryBlock);
         return null;
     }
@@ -86,11 +86,6 @@ final class AttemptBlock extends TemplateElement {
     }
     
     @Override
-    boolean isShownInStackTrace() {
-        return false;
-    }
-
-    @Override
     boolean isNestedBlockRepeater() {
         return false;
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/AutoEscBlock.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/AutoEscBlock.java b/src/main/java/freemarker/core/AutoEscBlock.java
index 58c188a..9622d39 100644
--- a/src/main/java/freemarker/core/AutoEscBlock.java
+++ b/src/main/java/freemarker/core/AutoEscBlock.java
@@ -33,8 +33,8 @@ final class AutoEscBlock extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
-        return new TemplateElementsToVisit(getNestedBlock(), true);
+    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
+        return new TemplateElement[] { getNestedBlock() };
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/BlockAssignment.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/BlockAssignment.java b/src/main/java/freemarker/core/BlockAssignment.java
index 4b054b2..58f3404 100644
--- a/src/main/java/freemarker/core/BlockAssignment.java
+++ b/src/main/java/freemarker/core/BlockAssignment.java
@@ -49,7 +49,7 @@ final class BlockAssignment extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
+    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
         if (getNestedBlock() != null) {
             env.visitAndTransform(getNestedBlock(), new CaptureOutput(env), null);
         } else {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/BodyInstruction.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/BodyInstruction.java b/src/main/java/freemarker/core/BodyInstruction.java
index 9d7db0d..0c82841 100644
--- a/src/main/java/freemarker/core/BodyInstruction.java
+++ b/src/main/java/freemarker/core/BodyInstruction.java
@@ -55,7 +55,7 @@ final class BodyInstruction extends TemplateElement {
      * I (JR) realized this thanks to some incisive comments from Daniel Dekany.
      */
     @Override
-    TemplateElementsToVisit accept(Environment env) throws IOException, TemplateException {
+    TemplateElement[] accept(Environment env) throws IOException, TemplateException {
         Context bodyContext = new Context(env);
         env.invokeNestedContent(bodyContext);
         return null;
@@ -114,6 +114,11 @@ final class BodyInstruction extends TemplateElement {
     }
     */
     
+    @Override
+    boolean isShownInStackTrace() {
+        return true;
+    }
+
     class Context implements LocalContext {
         Macro.Context invokingMacroContext;
         Environment.Namespace bodyVars;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/BreakInstruction.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/BreakInstruction.java b/src/main/java/freemarker/core/BreakInstruction.java
index 0690c7a..475ed3d 100644
--- a/src/main/java/freemarker/core/BreakInstruction.java
+++ b/src/main/java/freemarker/core/BreakInstruction.java
@@ -25,7 +25,7 @@ package freemarker.core;
 final class BreakInstruction extends TemplateElement {
 
     @Override
-    TemplateElementsToVisit accept(Environment env) {
+    TemplateElement[] accept(Environment env) {
         throw Break.INSTANCE;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/Case.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Case.java b/src/main/java/freemarker/core/Case.java
index 57eebad..586fc3e 100644
--- a/src/main/java/freemarker/core/Case.java
+++ b/src/main/java/freemarker/core/Case.java
@@ -39,9 +39,9 @@ final class Case extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env)
+    TemplateElement[] accept(Environment env)
         throws TemplateException, IOException {
-        return new TemplateElementsToVisit(getNestedBlock(), true);
+        return new TemplateElement[] { getNestedBlock() };
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/Comment.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Comment.java b/src/main/java/freemarker/core/Comment.java
index c2d5a95..89ac087 100644
--- a/src/main/java/freemarker/core/Comment.java
+++ b/src/main/java/freemarker/core/Comment.java
@@ -37,7 +37,7 @@ public final class Comment extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) {
+    TemplateElement[] accept(Environment env) {
         // do nothing, skip the body
         return null;
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/CompressedBlock.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/CompressedBlock.java b/src/main/java/freemarker/core/CompressedBlock.java
index 54794d6..e405e0f 100644
--- a/src/main/java/freemarker/core/CompressedBlock.java
+++ b/src/main/java/freemarker/core/CompressedBlock.java
@@ -36,7 +36,7 @@ final class CompressedBlock extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
+    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
         if (getNestedBlock() != null) {
             env.visitAndTransform(getNestedBlock(), StandardCompress.INSTANCE, null);
         }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/ConditionalBlock.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/ConditionalBlock.java b/src/main/java/freemarker/core/ConditionalBlock.java
index 34ac90c..5a733c1 100644
--- a/src/main/java/freemarker/core/ConditionalBlock.java
+++ b/src/main/java/freemarker/core/ConditionalBlock.java
@@ -45,9 +45,9 @@ final class ConditionalBlock extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
+    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
         if (condition == null || condition.evalToBoolean(env)) {
-            return new TemplateElementsToVisit(getNestedBlock(), true);
+            return new TemplateElement[] { getNestedBlock() };
         }
         return null;
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/DebugBreak.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/DebugBreak.java b/src/main/java/freemarker/core/DebugBreak.java
index 11c1bdf..cea2b77 100644
--- a/src/main/java/freemarker/core/DebugBreak.java
+++ b/src/main/java/freemarker/core/DebugBreak.java
@@ -38,7 +38,7 @@ public class DebugBreak extends TemplateElement {
     }
     
     @Override
-    protected TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
+    protected TemplateElement[] accept(Environment env) throws TemplateException, IOException {
         if (!DebuggerService.suspendEnvironment(
                 env, this.getTemplate().getSourceName(), getNestedBlock().getBeginLine())) {
             return getNestedBlock().accept(env);

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/DollarVariable.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/DollarVariable.java b/src/main/java/freemarker/core/DollarVariable.java
index 08767f9..1f7c933 100644
--- a/src/main/java/freemarker/core/DollarVariable.java
+++ b/src/main/java/freemarker/core/DollarVariable.java
@@ -55,7 +55,7 @@ final class DollarVariable extends Interpolation {
      * Outputs the string value of the enclosed expression.
      */
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
+    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
         final Object moOrStr = calculateInterpolatedStringOrMarkup(env);
         final Writer out = env.getOut();
         if (moOrStr instanceof String) {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/ElseOfList.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/ElseOfList.java b/src/main/java/freemarker/core/ElseOfList.java
index 065f581..240589a 100644
--- a/src/main/java/freemarker/core/ElseOfList.java
+++ b/src/main/java/freemarker/core/ElseOfList.java
@@ -33,8 +33,8 @@ final class ElseOfList extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
-        return new TemplateElementsToVisit(getNestedBlock(), true);
+    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
+        return new TemplateElement[] { getNestedBlock() };
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/Environment.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Environment.java b/src/main/java/freemarker/core/Environment.java
index 2789e02..1bfe589 100644
--- a/src/main/java/freemarker/core/Environment.java
+++ b/src/main/java/freemarker/core/Environment.java
@@ -110,7 +110,7 @@ public final class Environment extends Configurable {
 
     private final Configuration configuration;
     private final TemplateHashModel rootDataModel;
-    private final ArrayList/* <TemplateElement> */ instructionStack = new ArrayList();
+    private final ArrayList<TemplateElement> instructionStack = new ArrayList<TemplateElement>();
     private final ArrayList recoveredErrorStack = new ArrayList();
 
     private TemplateNumberFormat cachedTemplateNumberFormat;
@@ -264,7 +264,7 @@ public final class Environment extends Configurable {
     public DirectiveCallPlace getCurrentDirectiveCallPlace() {
         int ln = instructionStack.size();
         if (ln == 0) return null;
-        TemplateElement te = (TemplateElement) instructionStack.get(ln - 1);
+        TemplateElement te = instructionStack.get(ln - 1);
         if (te instanceof UnifiedCall) return (UnifiedCall) te;
         if (te instanceof Macro && ln > 1 && instructionStack.get(ln - 2) instanceof UnifiedCall) {
             return (UnifiedCall) instructionStack.get(ln - 2);
@@ -298,7 +298,7 @@ public final class Environment extends Configurable {
             clearCachedValues();
             try {
                 doAutoImportsAndIncludes(this);
-                visit(getTemplate().getRootTreeNode(), false);
+                visit(getTemplate().getRootTreeNode());
                 // It's here as we must not flush if there was an exception.
                 if (getAutoFlush()) {
                     out.flush();
@@ -314,47 +314,28 @@ public final class Environment extends Configurable {
 
     /**
      * "Visit" the template element.
-     *
-     * Param 'hideInParent' controls how the instruction stack is handled. If it is set to false, the current
-     * element is pushed to the instruction stack.
-     *
-     * If it is set to true, we replace the top element for the time the parameter element is
-     * visited, and then we restore the top element. The main purpose of this is to get rid of elements in the error
-     * stack trace that from user perspective shouldn't have a stack frame. The typical example is
-     * {@code [#if foo]...[@failsHere/]...[/#if]}, where the #if call shouldn't be in the stack trace. (Simply marking
-     * #if as hidden in stack traces would be wrong, because we still want to show #if when its test expression fails.)
-     */
-    void visit(TemplateElement element, boolean hideInParent) throws IOException, TemplateException {
-        TemplateElement hiddenParent;
-        if (hideInParent) {
-            hiddenParent = replaceTopElement(element);
-        } else {
-            pushElement(element);
-            hiddenParent = null;
-        }
+     */
+    void visit(TemplateElement element) throws IOException, TemplateException {
+        pushElement(element);
         try {
-            TemplateElementsToVisit templateElementsToVisit = element.accept(this);
+            TemplateElement[] templateElementsToVisit = element.accept(this);
             if (templateElementsToVisit != null) {
-                boolean hideInnerElementInParent = templateElementsToVisit.isHideInParent();
-                for (TemplateElement templateElementToVisit : templateElementsToVisit.getTemplateElements()) {
-                    if (templateElementToVisit != null) {
-                        visit(templateElementToVisit, hideInnerElementInParent);
+                for (TemplateElement el : templateElementsToVisit) {
+                    if (el == null) {
+                        break;  // Skip unused trailing buffer capacity 
                     }
+                    visit(el);
                 }
             }
         } catch (TemplateException te) {
             handleTemplateException(te);
         } finally {
-            if (hiddenParent != null) {
-                replaceTopElement(hiddenParent);
-            } else {
-                popElement();
-            }
+            popElement();
         }
     }
 
     private TemplateElement replaceTopElement(TemplateElement element) {
-        return (TemplateElement) instructionStack.set(instructionStack.size() - 1, element);
+        return instructionStack.set(instructionStack.size() - 1, element);
     }
 
     private static final TemplateModel[] NO_OUT_ARGS = new TemplateModel[0];
@@ -423,7 +404,7 @@ public final class Environment extends Configurable {
                 if (tc == null || tc.onStart() != TransformControl.SKIP_BODY) {
                     do {
                         if (element != null) {
-                            visit(element, true);
+                            visit(element);
                         }
                     } while (tc != null && tc.afterBody() == TransformControl.REPEAT_EVALUATION);
                 }
@@ -467,7 +448,7 @@ public final class Environment extends Configurable {
         boolean lastInAttemptBlock = inAttemptBlock;
         try {
             inAttemptBlock = true;
-            visit(attemptBlock, true);
+            visit(attemptBlock);
         } catch (TemplateException te) {
             thrownException = te;
         } finally {
@@ -482,7 +463,7 @@ public final class Environment extends Configurable {
             }
             try {
                 recoveredErrorStack.add(thrownException);
-                visit(recoveryBlock, false);
+                visit(recoveryBlock);
             } finally {
                 recoveredErrorStack.remove(recoveredErrorStack.size() - 1);
             }
@@ -534,7 +515,7 @@ public final class Environment extends Configurable {
                 pushLocalContext(bodyCtx);
             }
             try {
-                visit(nestedContent, false);
+                visit(nestedContent);
             } finally {
                 if (invokingMacroContext.nestedContentParameterNames != null) {
                     popLocalContext();
@@ -2064,8 +2045,8 @@ public final class Environment extends Configurable {
         int ln = instructionStack.size();
 
         for (int i = 0; i < ln; i++) {
-            TemplateElement stackEl = (TemplateElement) instructionStack.get(i);
-            if (i == ln || stackEl.isShownInStackTrace()) {
+            TemplateElement stackEl = instructionStack.get(i);
+            if (i == ln - 1 || stackEl.isShownInStackTrace()) {
                 requiredLength++;
             }
         }
@@ -2075,8 +2056,8 @@ public final class Environment extends Configurable {
         TemplateElement[] result = new TemplateElement[requiredLength];
         int dstIdx = requiredLength - 1;
         for (int i = 0; i < ln; i++) {
-            TemplateElement stackEl = (TemplateElement) instructionStack.get(i);
-            if (i == ln || stackEl.isShownInStackTrace()) {
+            TemplateElement stackEl = instructionStack.get(i);
+            if (i == ln - 1 || stackEl.isShownInStackTrace()) {
                 result[dstIdx--] = stackEl;
             }
         }
@@ -2461,7 +2442,7 @@ public final class Environment extends Configurable {
 
         importMacros(includedTemplate);
         try {
-            visit(includedTemplate.getRootTreeNode(), false);
+            visit(includedTemplate.getRootTreeNode());
         } finally {
             if (parentReplacementOn) {
                 setParent(prevTemplate);
@@ -2582,7 +2563,7 @@ public final class Environment extends Configurable {
         try {
             StringWriter sw = new StringWriter();
             this.out = sw;
-            visit(te, false);
+            visit(te);
             return sw.toString();
         } finally {
             this.out = prevOut;
@@ -2680,7 +2661,7 @@ public final class Environment extends Configurable {
             Writer prevOut = out;
             out = newOut;
             try {
-                visit(element, false);
+                visit(element);
             } finally {
                 out = prevOut;
             }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/EscapeBlock.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/EscapeBlock.java b/src/main/java/freemarker/core/EscapeBlock.java
index be7ed51..1095372 100644
--- a/src/main/java/freemarker/core/EscapeBlock.java
+++ b/src/main/java/freemarker/core/EscapeBlock.java
@@ -19,11 +19,11 @@
 
 package freemarker.core;
 
+import java.io.IOException;
+
 import freemarker.core.Expression.ReplacemenetState;
 import freemarker.template.TemplateException;
 
-import java.io.IOException;
-
 /**
  * Representation of the compile-time #escape directive.
  */
@@ -47,8 +47,8 @@ class EscapeBlock extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
-        return new TemplateElementsToVisit(getNestedBlock(), false);
+    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
+        return new TemplateElement[] { getNestedBlock() };
     }
 
     Expression doEscape(Expression expression) {
@@ -78,11 +78,6 @@ class EscapeBlock extends TemplateElement {
     }
     
     @Override
-    boolean isShownInStackTrace() {
-        return false;
-    }
-    
-    @Override
     int getParameterCount() {
         return 2;
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/FallbackInstruction.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/FallbackInstruction.java b/src/main/java/freemarker/core/FallbackInstruction.java
index 27f0da6..58d6845 100644
--- a/src/main/java/freemarker/core/FallbackInstruction.java
+++ b/src/main/java/freemarker/core/FallbackInstruction.java
@@ -26,7 +26,7 @@ import freemarker.template.TemplateException;
 final class FallbackInstruction extends TemplateElement {
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws IOException, TemplateException {
+    TemplateElement[] accept(Environment env) throws IOException, TemplateException {
         env.fallback();
         return null;
     }
@@ -61,4 +61,9 @@ final class FallbackInstruction extends TemplateElement {
         return false;
     }
     
+    @Override
+    boolean isShownInStackTrace() {
+        return true;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/FlushInstruction.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/FlushInstruction.java b/src/main/java/freemarker/core/FlushInstruction.java
index d836909..ff1338a 100644
--- a/src/main/java/freemarker/core/FlushInstruction.java
+++ b/src/main/java/freemarker/core/FlushInstruction.java
@@ -27,7 +27,7 @@ import java.io.IOException;
 final class FlushInstruction extends TemplateElement {
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws IOException {
+    TemplateElement[] accept(Environment env) throws IOException {
         env.getOut().flush();
         return null;
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/IfBlock.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/IfBlock.java b/src/main/java/freemarker/core/IfBlock.java
index 2c15540..f976c8e 100644
--- a/src/main/java/freemarker/core/IfBlock.java
+++ b/src/main/java/freemarker/core/IfBlock.java
@@ -40,7 +40,7 @@ final class IfBlock extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
+    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
         int ln  = getRegulatedChildCount();
         for (int i = 0; i < ln; i++) {
             ConditionalBlock cblock = (ConditionalBlock) getRegulatedChild(i);
@@ -48,7 +48,7 @@ final class IfBlock extends TemplateElement {
             env.replaceElementStackTop(cblock);
             if (condition == null || condition.evalToBoolean(env)) {
                 if (cblock.getNestedBlock() != null) {
-                    return new TemplateElementsToVisit(cblock.getNestedBlock(), true);
+                    return new TemplateElement[] { cblock.getNestedBlock() };
                 }
             }
         }
@@ -103,11 +103,6 @@ final class IfBlock extends TemplateElement {
     ParameterRole getParameterRole(int idx) {
         throw new IndexOutOfBoundsException();
     }
-    
-    @Override
-    boolean isShownInStackTrace() {
-        return false;
-    }
 
     @Override
     boolean isNestedBlockRepeater() {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/Include.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Include.java b/src/main/java/freemarker/core/Include.java
index 745b5f1..08c8459 100644
--- a/src/main/java/freemarker/core/Include.java
+++ b/src/main/java/freemarker/core/Include.java
@@ -118,7 +118,7 @@ final class Include extends TemplateElement {
     }
     
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
+    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
         final String includedTemplateName = includedTemplateNameExp.evalAndCoerceToPlainText(env);
         final String fullIncludedTemplateName;
         try {
@@ -250,4 +250,10 @@ final class Include extends TemplateElement {
         return true;
     }
 */
+    
+    @Override
+    boolean isShownInStackTrace() {
+        return true;
+    }
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/Items.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Items.java b/src/main/java/freemarker/core/Items.java
index 25b8010..d48c013 100644
--- a/src/main/java/freemarker/core/Items.java
+++ b/src/main/java/freemarker/core/Items.java
@@ -36,7 +36,7 @@ class Items extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
+    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
         final IterationContext iterCtx = IteratorBlock.findEnclosingIterationContext(env, null);
         if (iterCtx == null) {
             // The parser should prevent this situation

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/IteratorBlock.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/IteratorBlock.java b/src/main/java/freemarker/core/IteratorBlock.java
index a74b4fb..e6c760b 100644
--- a/src/main/java/freemarker/core/IteratorBlock.java
+++ b/src/main/java/freemarker/core/IteratorBlock.java
@@ -63,7 +63,7 @@ final class IteratorBlock extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
+    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
         acceptWithResult(env);
         return null;
     }
@@ -245,7 +245,7 @@ final class IteratorBlock extends TemplateElement {
                                 loopVar = iterModel.next();
                                 hasNext = iterModel.hasNext();
                                 if (nestedBlock != null) {
-                                    env.visit(nestedBlock, true);
+                                    env.visit(nestedBlock);
                                 }
                                 index++;
                             }
@@ -258,7 +258,7 @@ final class IteratorBlock extends TemplateElement {
                         // allow one iterator() call.
                         openedIteratorModel = iterModel;
                         if (nestedBlock != null) {
-                            env.visit(nestedBlock, true);
+                            env.visit(nestedBlock);
                         }
                     }
                 }
@@ -273,7 +273,7 @@ final class IteratorBlock extends TemplateElement {
                                 loopVar = seqModel.get(index);
                                 hasNext = (size > index + 1);
                                 if (nestedBlock != null) {
-                                    env.visit(nestedBlock, true);
+                                    env.visit(nestedBlock);
                                 }
                             }
                         } catch (BreakInstruction.Break br) {
@@ -281,7 +281,7 @@ final class IteratorBlock extends TemplateElement {
                         }
                     } else {
                         if (nestedBlock != null) {
-                            env.visit(nestedBlock, true);
+                            env.visit(nestedBlock);
                         }
                     }
                 }
@@ -293,7 +293,7 @@ final class IteratorBlock extends TemplateElement {
                 }
                 try {
                     if (nestedBlock != null) {
-                        env.visit(nestedBlock, true);
+                        env.visit(nestedBlock);
                     }
                 } catch (BreakInstruction.Break br) {
                     // Silently exit "loop"

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/LibraryLoad.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/LibraryLoad.java b/src/main/java/freemarker/core/LibraryLoad.java
index 05a83a5..9305144 100644
--- a/src/main/java/freemarker/core/LibraryLoad.java
+++ b/src/main/java/freemarker/core/LibraryLoad.java
@@ -50,7 +50,7 @@ public final class LibraryLoad extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
+    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
         final String importedTemplateName = importedTemplateNameExp.evalAndCoerceToPlainText(env);
         final String fullImportedTemplateName;
         try {
@@ -123,4 +123,10 @@ public final class LibraryLoad extends TemplateElement {
     boolean isNestedBlockRepeater() {
         return false;
     }
+    
+    @Override
+    boolean isShownInStackTrace() {
+        return true;
+    }
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/ListElseContainer.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/ListElseContainer.java b/src/main/java/freemarker/core/ListElseContainer.java
index a9c61e7..d296719 100644
--- a/src/main/java/freemarker/core/ListElseContainer.java
+++ b/src/main/java/freemarker/core/ListElseContainer.java
@@ -36,7 +36,7 @@ class ListElseContainer extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
+    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
         if (!listPart.acceptWithResult(env)) {
             return elsePart.accept(env);
         }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/Macro.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Macro.java b/src/main/java/freemarker/core/Macro.java
index f2c9a08..5310947 100644
--- a/src/main/java/freemarker/core/Macro.java
+++ b/src/main/java/freemarker/core/Macro.java
@@ -90,7 +90,7 @@ public final class Macro extends TemplateElement implements TemplateModel {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) {
+    TemplateElement[] accept(Environment env) {
         env.visitMacroDef(this);
         return null;
     }
@@ -151,11 +151,6 @@ public final class Macro extends TemplateElement implements TemplateModel {
         return function ? "#function" : "#macro";
     }
     
-    @Override
-    boolean isShownInStackTrace() {
-        return false;
-    }
-    
     public boolean isFunction() {
         return function;
     }
@@ -188,7 +183,7 @@ public final class Macro extends TemplateElement implements TemplateModel {
             sanityCheck(env);
             // Set default values for unspecified parameters
             if (getNestedBlock() != null) {
-                env.visit(getNestedBlock(), false);
+                env.visit(getNestedBlock());
             }
         }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/MixedContent.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/MixedContent.java b/src/main/java/freemarker/core/MixedContent.java
index fc4a1d5..e0ddb89 100644
--- a/src/main/java/freemarker/core/MixedContent.java
+++ b/src/main/java/freemarker/core/MixedContent.java
@@ -50,9 +50,9 @@ final class MixedContent extends TemplateElement {
      * and outputs the resulting text.
      */
     @Override
-    TemplateElementsToVisit accept(Environment env)
+    TemplateElement[] accept(Environment env)
         throws TemplateException, IOException {
-        return new TemplateElementsToVisit(getRegulatedChildren());
+        return getRegulatedChildren();
     }
 
     @Override
@@ -104,11 +104,6 @@ final class MixedContent extends TemplateElement {
     }
     
     @Override
-    boolean isShownInStackTrace() {
-        return false;
-    }
-    
-    @Override
     boolean isIgnorable() {
         return getRegulatedChildCount() == 0;
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/NoAutoEscBlock.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/NoAutoEscBlock.java b/src/main/java/freemarker/core/NoAutoEscBlock.java
index ffd394c..15f3399 100644
--- a/src/main/java/freemarker/core/NoAutoEscBlock.java
+++ b/src/main/java/freemarker/core/NoAutoEscBlock.java
@@ -33,8 +33,8 @@ final class NoAutoEscBlock extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
-        return new TemplateElementsToVisit(getNestedBlock(), true);
+    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
+        return new TemplateElement[] { getNestedBlock() };
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/NoEscapeBlock.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/NoEscapeBlock.java b/src/main/java/freemarker/core/NoEscapeBlock.java
index 5a6b525..8513f1d 100644
--- a/src/main/java/freemarker/core/NoEscapeBlock.java
+++ b/src/main/java/freemarker/core/NoEscapeBlock.java
@@ -32,8 +32,8 @@ class NoEscapeBlock extends TemplateElement {
     }
     
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
-        return new TemplateElementsToVisit(getNestedBlock(), false);
+    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
+        return new TemplateElement[] { getNestedBlock() };
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/NumericalOutput.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/NumericalOutput.java b/src/main/java/freemarker/core/NumericalOutput.java
index 0fb67f7..3e6e53a 100644
--- a/src/main/java/freemarker/core/NumericalOutput.java
+++ b/src/main/java/freemarker/core/NumericalOutput.java
@@ -59,7 +59,7 @@ final class NumericalOutput extends Interpolation {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
+    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
         String s = calculateInterpolatedStringOrMarkup(env);
         Writer out = env.getOut();
         if (autoEscapeOutputFormat != null) {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/OutputFormatBlock.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/OutputFormatBlock.java b/src/main/java/freemarker/core/OutputFormatBlock.java
index 63b0c62..e4da5a1 100644
--- a/src/main/java/freemarker/core/OutputFormatBlock.java
+++ b/src/main/java/freemarker/core/OutputFormatBlock.java
@@ -36,8 +36,8 @@ final class OutputFormatBlock extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
-        return new TemplateElementsToVisit(getNestedBlock(), true);
+    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
+        return new TemplateElement[] { getNestedBlock() };
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/PropertySetting.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/PropertySetting.java b/src/main/java/freemarker/core/PropertySetting.java
index 8e4c23f..1cb81a3 100644
--- a/src/main/java/freemarker/core/PropertySetting.java
+++ b/src/main/java/freemarker/core/PropertySetting.java
@@ -110,7 +110,7 @@ final class PropertySetting extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException {
+    TemplateElement[] accept(Environment env) throws TemplateException {
         TemplateModel mval = value.eval(env);
         String strval;
         if (mval instanceof TemplateScalarModel) {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/RecoveryBlock.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/RecoveryBlock.java b/src/main/java/freemarker/core/RecoveryBlock.java
index 69ae202..7ec1c8a 100644
--- a/src/main/java/freemarker/core/RecoveryBlock.java
+++ b/src/main/java/freemarker/core/RecoveryBlock.java
@@ -30,8 +30,8 @@ final class RecoveryBlock extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
-        return new TemplateElementsToVisit(getNestedBlock(), true);
+    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
+        return new TemplateElement[] { getNestedBlock() };
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/RecurseNode.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/RecurseNode.java b/src/main/java/freemarker/core/RecurseNode.java
index 3b9afed..1c15da8 100644
--- a/src/main/java/freemarker/core/RecurseNode.java
+++ b/src/main/java/freemarker/core/RecurseNode.java
@@ -43,7 +43,7 @@ final class RecurseNode extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws IOException, TemplateException {
+    TemplateElement[] accept(Environment env) throws IOException, TemplateException {
         TemplateModel node = targetNode == null ? null : targetNode.eval(env);
         if (node != null && !(node instanceof TemplateNodeModel)) {
             throw new NonNodeException(targetNode, node, "node", env);
@@ -124,4 +124,9 @@ final class RecurseNode extends TemplateElement {
         return false;
     }
     
+    @Override
+    boolean isShownInStackTrace() {
+        return true;
+    }
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/ReturnInstruction.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/ReturnInstruction.java b/src/main/java/freemarker/core/ReturnInstruction.java
index d2d2985..09852e8 100644
--- a/src/main/java/freemarker/core/ReturnInstruction.java
+++ b/src/main/java/freemarker/core/ReturnInstruction.java
@@ -33,7 +33,7 @@ public final class ReturnInstruction extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException {
+    TemplateElement[] accept(Environment env) throws TemplateException {
         if (exp != null) {
             env.setLastReturnValue(exp.eval(env));
         }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/Sep.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Sep.java b/src/main/java/freemarker/core/Sep.java
index 2dec2d6..522ee2f 100644
--- a/src/main/java/freemarker/core/Sep.java
+++ b/src/main/java/freemarker/core/Sep.java
@@ -33,7 +33,7 @@ class Sep extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
+    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
         final IterationContext iterCtx = IteratorBlock.findEnclosingIterationContext(env, null);
         if (iterCtx == null) {
             // The parser should prevent this situation
@@ -42,7 +42,7 @@ class Sep extends TemplateElement {
         }
         
         if (iterCtx.hasNext()) {
-            return new TemplateElementsToVisit(getNestedBlock(), true);
+            return new TemplateElement[] { getNestedBlock() };
         }
         return null;
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/StackTraceVisibility.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/StackTraceVisibility.java b/src/main/java/freemarker/core/StackTraceVisibility.java
new file mode 100644
index 0000000..6fcd877
--- /dev/null
+++ b/src/main/java/freemarker/core/StackTraceVisibility.java
@@ -0,0 +1,8 @@
+package freemarker.core;
+
+
+public enum StackTraceVisibility {
+    
+    ALWAYS, WHEN_ON_TOP, NEVER
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/StopInstruction.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/StopInstruction.java b/src/main/java/freemarker/core/StopInstruction.java
index 231725c..590d9f1 100644
--- a/src/main/java/freemarker/core/StopInstruction.java
+++ b/src/main/java/freemarker/core/StopInstruction.java
@@ -33,7 +33,7 @@ final class StopInstruction extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException {
+    TemplateElement[] accept(Environment env) throws TemplateException {
         if (exp == null) {
             throw new StopException(env);
         }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/SwitchBlock.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/SwitchBlock.java b/src/main/java/freemarker/core/SwitchBlock.java
index b3dbe70..4f3f461 100644
--- a/src/main/java/freemarker/core/SwitchBlock.java
+++ b/src/main/java/freemarker/core/SwitchBlock.java
@@ -50,7 +50,7 @@ final class SwitchBlock extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env)
+    TemplateElement[] accept(Environment env)
         throws TemplateException, IOException {
         boolean processedCase = false;
         int ln = getRegulatedChildCount();
@@ -69,7 +69,7 @@ final class SwitchBlock extends TemplateElement {
                             EvalUtil.CMP_OP_EQUALS, "case==", cas.condition, cas.condition, env);
                 }
                 if (processCase) {
-                    env.visit(cas, true);
+                    env.visit(cas);
                     processedCase = true;
                 }
             }
@@ -77,7 +77,7 @@ final class SwitchBlock extends TemplateElement {
             // If we didn't process any nestedElements, and we have a default,
             // process it.
             if (!processedCase && defaultCase != null) {
-                env.visit(defaultCase, true);
+                env.visit(defaultCase);
             }
         } catch (BreakInstruction.Break br) {}
         return null;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/TemplateElement.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/TemplateElement.java b/src/main/java/freemarker/core/TemplateElement.java
index 21852b9..2dfcfad 100644
--- a/src/main/java/freemarker/core/TemplateElement.java
+++ b/src/main/java/freemarker/core/TemplateElement.java
@@ -22,15 +22,12 @@ package freemarker.core;
 import java.io.IOException;
 import java.util.Collections;
 import java.util.Enumeration;
-import java.util.List;
 
 import freemarker.template.SimpleSequence;
 import freemarker.template.TemplateException;
 import freemarker.template.TemplateNodeModel;
 import freemarker.template.TemplateSequenceModel;
 
-import static java.util.Arrays.asList;
-
 /**
  * <b>Internal API - subject to change:</b> Represent directive call, interpolation, text block, or other such
  * non-expression node in the parsed template. Some information that can be found here can be accessed through the
@@ -72,12 +69,18 @@ abstract public class TemplateElement extends TemplateObject {
     private int index;
 
     /**
-     * Processes the contents of this <tt>TemplateElement</tt> and
-     * outputs the resulting text
+     * Executes this {@link TemplateElement}. Usually should not be called directly, but through
+     * {@link Environment#visit(TemplateElement)} or a similar {@link Environment} method.
      *
-     * @param env The runtime environment
+     * @param env
+     *            The runtime environment
+     * 
+     * @return The template elements to execute (meant to be used for nested elements), or {@code null}. Can have
+     *         <em>trailing</em> {@code null}-s (unused buffer capacity). Returning the nested elements instead of
+     *         executing them inside this method is a trick used for decreasing stack usage when there's nothing to
+     *         do after the children was processed anyway.
      */
-    abstract TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException;
+    abstract TemplateElement[] accept(Environment env) throws TemplateException, IOException;
 
     /**
      * One-line description of the element, that contain all the information that is used in
@@ -105,13 +108,11 @@ abstract public class TemplateElement extends TemplateObject {
     }
     
     /**
-     * Tells if the element should show up in error stack traces. If you think you need to set this to {@code false} for
-     * an element, always consider if you should pass true instead to {@link Environment#visit(TemplateElement, boolean)}.
-     * 
-     * Note that this will be ignored for the top (current) element of a stack trace, as that's always shown.
+     * Tells if the element should show up in error stack traces. Note that this will be ignored for the top (current)
+     * element of a stack trace, as that's always shown.
      */
     boolean isShownInStackTrace() {
-        return true;
+        return false;
     }
     
     /**
@@ -320,8 +321,8 @@ abstract public class TemplateElement extends TemplateObject {
         return regulatedChildBuffer[index];
     }
 
-    final List<TemplateElement> getRegulatedChildren(){
-        return asList(regulatedChildBuffer);
+    final TemplateElement[] getRegulatedChildren(){
+        return regulatedChildBuffer;
     }
     
     final int getIndex() {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/TemplateElementsToVisit.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/TemplateElementsToVisit.java b/src/main/java/freemarker/core/TemplateElementsToVisit.java
index 3314b96..6159f13 100644
--- a/src/main/java/freemarker/core/TemplateElementsToVisit.java
+++ b/src/main/java/freemarker/core/TemplateElementsToVisit.java
@@ -14,27 +14,17 @@ import java.util.Collections;
 class TemplateElementsToVisit {
 
     private final Collection<TemplateElement> templateElements;
-    private final boolean hideInParent;
-
-    TemplateElementsToVisit(Collection<TemplateElement> templateElements, boolean hideInParent) {
-        this.templateElements = null != templateElements ? templateElements : Collections.<TemplateElement> emptyList();
-        this.hideInParent = hideInParent;
-    }
 
     TemplateElementsToVisit(Collection<TemplateElement> templateElements) {
-        this(templateElements, false);
+        this.templateElements = null != templateElements ? templateElements : Collections.<TemplateElement> emptyList();
     }
 
-    TemplateElementsToVisit(TemplateElement nestedBlock, boolean hideInParent) {
-        this(Collections.singleton(nestedBlock), hideInParent);
+    TemplateElementsToVisit(TemplateElement nestedBlock) {
+        this(Collections.singleton(nestedBlock));
     }
 
     Collection<TemplateElement> getTemplateElements() {
         return templateElements;
     }
-
-    boolean isHideInParent() {
-        return hideInParent;
-    }
     
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/TextBlock.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/TextBlock.java b/src/main/java/freemarker/core/TextBlock.java
index c8a6d5c..2ddf143 100644
--- a/src/main/java/freemarker/core/TextBlock.java
+++ b/src/main/java/freemarker/core/TextBlock.java
@@ -58,7 +58,7 @@ public final class TextBlock extends TemplateElement {
      * Simply outputs the text.
      */
     @Override
-    public TemplateElementsToVisit accept(Environment env)
+    public TemplateElement[] accept(Environment env)
     throws IOException {
         env.getOut().write(text);
         return null;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/ThreadInterruptionSupportTemplatePostProcessor.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/ThreadInterruptionSupportTemplatePostProcessor.java b/src/main/java/freemarker/core/ThreadInterruptionSupportTemplatePostProcessor.java
index 4e0b152..29ec292 100644
--- a/src/main/java/freemarker/core/ThreadInterruptionSupportTemplatePostProcessor.java
+++ b/src/main/java/freemarker/core/ThreadInterruptionSupportTemplatePostProcessor.java
@@ -110,7 +110,7 @@ class ThreadInterruptionSupportTemplatePostProcessor extends TemplatePostProcess
         }
 
         @Override
-        TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
+        TemplateElement[] accept(Environment env) throws TemplateException, IOException {
             // As the API doesn't allow throwing InterruptedException here (nor anywhere else, most importantly,
             // Template.process can't throw it), we must not clear the "interrupted" flag of the thread.
             if (Thread.currentThread().isInterrupted()) {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/TransformBlock.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/TransformBlock.java b/src/main/java/freemarker/core/TransformBlock.java
index 9f07e85..8bde8cf 100644
--- a/src/main/java/freemarker/core/TransformBlock.java
+++ b/src/main/java/freemarker/core/TransformBlock.java
@@ -55,7 +55,7 @@ final class TransformBlock extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env)
+    TemplateElement[] accept(Environment env)
     throws TemplateException, IOException {
         TemplateTransformModel ttm = env.getTransform(transformExpression);
         if (ttm != null) {
@@ -161,5 +161,10 @@ final class TransformBlock extends TemplateElement {
     boolean isNestedBlockRepeater() {
         return false;
     }
+
+    @Override
+    boolean isShownInStackTrace() {
+        return true;
+    }
     
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/TrimInstruction.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/TrimInstruction.java b/src/main/java/freemarker/core/TrimInstruction.java
index 31a6d78..a974e0f 100644
--- a/src/main/java/freemarker/core/TrimInstruction.java
+++ b/src/main/java/freemarker/core/TrimInstruction.java
@@ -38,7 +38,7 @@ final class TrimInstruction extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) {
+    TemplateElement[] accept(Environment env) {
         // This instruction does nothing at render-time, only parse-time.
         return null;
     }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/UnifiedCall.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/UnifiedCall.java b/src/main/java/freemarker/core/UnifiedCall.java
index 2cfd481..fde6451 100644
--- a/src/main/java/freemarker/core/UnifiedCall.java
+++ b/src/main/java/freemarker/core/UnifiedCall.java
@@ -72,7 +72,7 @@ final class UnifiedCall extends TemplateElement implements DirectiveCallPlace {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws TemplateException, IOException {
+    TemplateElement[] accept(Environment env) throws TemplateException, IOException {
         TemplateModel tm = nameExp.eval(env);
         if (tm == Macro.DO_NOTHING_MACRO) return null; // shortcut here.
         if (tm instanceof Macro) {
@@ -337,5 +337,10 @@ final class UnifiedCall extends TemplateElement implements DirectiveCallPlace {
     boolean isNestedBlockRepeater() {
         return true;
     }
+
+    @Override
+    boolean isShownInStackTrace() {
+        return true;
+    }
     
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/89585c8e/src/main/java/freemarker/core/VisitNode.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/VisitNode.java b/src/main/java/freemarker/core/VisitNode.java
index 7bb8375..e116c4a 100644
--- a/src/main/java/freemarker/core/VisitNode.java
+++ b/src/main/java/freemarker/core/VisitNode.java
@@ -42,7 +42,7 @@ final class VisitNode extends TemplateElement {
     }
 
     @Override
-    TemplateElementsToVisit accept(Environment env) throws IOException, TemplateException {
+    TemplateElement[] accept(Environment env) throws IOException, TemplateException {
         TemplateModel node = targetNode.eval(env);
         if (!(node instanceof TemplateNodeModel)) {
             throw new NonNodeException(targetNode, node, env);
@@ -119,5 +119,10 @@ final class VisitNode extends TemplateElement {
     boolean isNestedBlockRepeater() {
         return true;
     }
+
+    @Override
+    boolean isShownInStackTrace() {
+        return true;
+    }
     
 }