1- package luceedebug .coreinject ;
1+ package luceedebug .coreinject . frame ;
22
33import lucee .runtime .PageContext ;
44import lucee .runtime .PageContextImpl ;
1818import com .google .common .collect .MapMaker ;
1919
2020import luceedebug .*;
21+ import luceedebug .coreinject .CfValueDebuggerBridge ;
22+ import luceedebug .coreinject .ClosureScopeLocalScopeAccessorShim ;
23+ import luceedebug .coreinject .DebugEntity ;
24+ import luceedebug .coreinject .UnsafeUtils ;
25+ import luceedebug .coreinject .ValTracker ;
2126import luceedebug .coreinject .CfValueDebuggerBridge .MarkerTrait ;
27+ import luceedebug .coreinject .CfValueDebuggerBridge .MarkerTrait .Scope ;
2228
2329public class DebugFrame implements IDebugFrame {
2430 static private AtomicLong nextId = new AtomicLong (0 );
@@ -63,6 +69,8 @@ void pin(Object obj) {
6369 refsToKeepAlive_ .add (obj );
6470 }
6571
72+ static ThreadLocal <Boolean > isPushingFrame = ThreadLocal .withInitial (() -> false );
73+
6674 // hold strong refs to scopes, because PageContext will swap them out as frames change (variables, local, this)
6775 // (application, server and etc. maybe could be held as globals)
6876 // We don't want to construct tracked refs to them until a debugger asks for them, because it is expensive
@@ -76,21 +84,21 @@ void pin(Object obj) {
7684 // the engine is truly do with its "frame". Fallback here would be use a WeakRef<> but it doesn't
7785 // seem necessary.
7886 //
79- static class FrameContext {
80- final PageContext pageContext ;
81-
82- final lucee .runtime .type .scope .Scope application ;
83- final lucee .runtime .type .scope .Argument arguments ;
84- final lucee .runtime .type .scope .Scope form ;
85- final lucee .runtime .type .scope .Local local ;
86- final lucee .runtime .type .scope .Scope request ;
87- final lucee .runtime .type .scope .Scope session ;
88- final lucee .runtime .type .scope .Scope server ;
89- final lucee .runtime .type .scope .Scope url ;
90- final lucee .runtime .type .scope .Variables variables ;
87+ public static class FrameContext {
88+ final public PageContext pageContext ;
89+
90+ public final lucee .runtime .type .scope .Scope application ;
91+ public final lucee .runtime .type .scope .Argument arguments ;
92+ public final lucee .runtime .type .scope .Scope form ;
93+ public final lucee .runtime .type .scope .Local local ;
94+ public final lucee .runtime .type .scope .Scope request ;
95+ public final lucee .runtime .type .scope .Scope session ;
96+ public final lucee .runtime .type .scope .Scope server ;
97+ public final lucee .runtime .type .scope .Scope url ;
98+ public final lucee .runtime .type .scope .Variables variables ;
9199 // n.b. the `this` scope does not derive from Scope
92- final lucee .runtime .type .Struct this_ ;
93- final lucee .runtime .type .scope .Scope static_ ;
100+ public final lucee .runtime .type .Struct this_ ;
101+ public final lucee .runtime .type .scope .Scope static_ ;
94102
95103 // lazy init because it (might?) be expensive to walk scope chains eagerly every frame
96104 private ArrayList <lucee .runtime .type .scope .ClosureScope > capturedScopeChain = null ;
@@ -104,7 +112,7 @@ static class FrameContext {
104112 // expensive exceptions on literally every frame, e.g. if a scope is disabled by the engine and trying to touch it
105113 // throws an ExpressionException.
106114 //
107- FrameContext (PageContext pageContext ) {
115+ private FrameContext (PageContext pageContext ) {
108116 this .pageContext = pageContext ;
109117 this .application = getScopelikeOrNull (() -> pageContext .applicationScope ());
110118 this .arguments = getScopelikeOrNull (() -> pageContext .argumentsScope ());
@@ -217,11 +225,29 @@ public <T> T doWorkInThisFrame(Supplier<T> f) {
217225 }
218226 }
219227
220- public DebugFrame (String sourceFilePath , int depth , ValTracker valTracker , PageContext pageContext ) {
228+ // DebugFrame >: DummyFrame | Frame
229+ static private DebugFrame dummyFrame = new DebugFrame ("null" , 0 , null , null );
230+
231+ static public DebugFrame maybeMakeFrame (String sourceFilePath , int depth , ValTracker valTracker , PageContext pageContext ) {
232+ if (isPushingFrame .get ()) {
233+ return null ;
234+ }
235+ else {
236+ try {
237+ isPushingFrame .set (true );
238+ return new DebugFrame (sourceFilePath , depth , valTracker , pageContext , DebugFrame .tryGetFrameName (pageContext ));
239+ }
240+ finally {
241+ isPushingFrame .set (false );
242+ }
243+ }
244+ }
245+
246+ private DebugFrame (String sourceFilePath , int depth , ValTracker valTracker , PageContext pageContext ) {
221247 this (sourceFilePath , depth , valTracker , pageContext , DebugFrame .tryGetFrameName (pageContext ));
222248 }
223249
224- public DebugFrame (String sourceFilePath , int depth , ValTracker valTracker , PageContext pageContext , String name ) {
250+ private DebugFrame (String sourceFilePath , int depth , ValTracker valTracker , PageContext pageContext , String name ) {
225251 this .frameContext_ = new FrameContext (pageContext );
226252 this .sourceFilePath = Objects .requireNonNull (sourceFilePath );
227253 this .valTracker = Objects .requireNonNull (valTracker );
@@ -321,7 +347,7 @@ public IDebugEntity[] getScopes() {
321347 return result ;
322348 }
323349
324- CfValueDebuggerBridge trackEvalResult (Object obj ) {
350+ public CfValueDebuggerBridge trackEvalResult (Object obj ) {
325351 var v = new CfValueDebuggerBridge (this , obj );
326352 CfValueDebuggerBridge .pin (obj );
327353 return v ;
0 commit comments