git » swiftpm » main » tree

[main] / Sources / c_snikket / iinclude / hx / StackContext.h

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
#ifndef HX_STACK_CONTEXT_H
#define HX_STACK_CONTEXT_H

#include "QuickVec.h"

#ifdef HXCPP_SINGLE_THREADED_APP
  #define HX_CTX_GET ::hx::gMainThreadContext
#else
  #define HX_CTX_GET ((::hx::StackContext *)::hx::tlsStackContext)
#endif

// Set:
// HXCPP_STACK_LINE if stack line numbers need to be tracked
// HXCPP_STACK_TRACE if stack frames need to be tracked

// Keep track of lines - more accurate stack traces for exceptions, also
// needed for the debugger
#if (defined(HXCPP_DEBUG) || defined(HXCPP_DEBUGGER)) && !defined(HXCPP_STACK_LINE)
#define HXCPP_STACK_LINE
#endif

// Do we need to keep a stack trace - for basic exception handelling, also needed for the debugger
// At a minimum, you can track the functions calls and nothing else
#if (defined(HXCPP_STACK_LINE) || defined(HXCPP_TELEMETRY) || defined(HXCPP_PROFILER) || defined(HXCPP_DEBUG)) && !defined(HXCPP_STACK_TRACE)
   #define HXCPP_STACK_TRACE
#endif

#if defined(HXCPP_STACK_TRACE) && defined(HXCPP_SCRIPTABLE)
#define HXCPP_STACK_SCRIPTABLE
#endif
// HXCPP_DEBUG_HASH == HXCPP_DEBUGGER
// HXCPP_STACK_VARS == HXCPP_DEBUGGER


// HX_STACKFRAME(pos)    - tracks position according to define.  May be optimized away.
// HX_GC_STACKFRAME(pos) - tracks position according to define, but is never optimized away
// HX_JUST_GC_STACKFRAME - never tracks position, never optimized away

// Setup the _hx_stackframe variable
#ifdef HXCPP_STACK_TRACE
   // Setup the 'HX_DEFINE_STACK_FRAME' 'HX_LOCAL_STACK_FRAME' macro.
   // This will be empty, just track functions(release), track functions and lines(debug) or track everything (debugger)
   #define HX_DECLARE_STACK_FRAME(name) extern ::hx::StackPosition name;

   #ifdef HXCPP_STACK_LINE

      #ifdef HXCPP_DEBUGGER
         #define HX_DEFINE_STACK_FRAME(varName, className, functionName, classFunctionHash, fullName,fileName,     \
                             lineNumber, fileHash ) \
          ::hx::StackPosition varName(className, functionName, fullName, fileName, lineNumber, \
                                            classFunctionHash, fileHash);
      #else
         #define HX_DEFINE_STACK_FRAME(varName, className, functionName, classFunctionHash, fullName,fileName,     \
                          lineNumber, fileHash ) \
          ::hx::StackPosition varName(className, functionName, fullName, fileName, lineNumber);
      #endif
   #else

      #define HX_DEFINE_STACK_FRAME(varName, className, functionName, classFunctionHash, fullName,fileName,     \
                          lineNumber, fileHash ) \
      ::hx::StackPosition varName(className, functionName, fullName, fileName);

   #endif

   #define HX_LOCAL_STACK_FRAME(a,b,c,d,e,f,g,h) static HX_DEFINE_STACK_FRAME(a,b,c,d,e,f,g,h)

   // Haxe < 330 does not create position pointers, and we must use a local one.
   // This code will hst the 'HX_STACK_FRAME' macro
   #define HX_STACK_FRAME(className, functionName, classFunctionHash, fullName,fileName, lineNumber, fileHash ) \
      HX_DEFINE_STACK_FRAME(__stackPosition, className, functionName, classFunctionHash, fullName,fileName, lineNumber, fileHash ) \
      ::hx::StackFrame _hx_stackframe(&__stackPosition);

   // Newer code will use the HX_STACKFRAME macro
   #define HX_STACKFRAME(pos) ::hx::StackFrame _hx_stackframe(pos);
   #define HX_GC_STACKFRAME(pos) ::hx::StackFrame _hx_stackframe(pos);
   
   // Must record the stack state at the catch
   #define HX_STACK_BEGIN_CATCH __hxcpp_stack_begin_catch();
   #define HX_JUST_GC_STACKFRAME ::hx::JustGcStackFrame _hx_stackframe;
   #define HX_CTX _hx_stackframe.ctx
#else
   // No need to track frame
   #define HX_DECLARE_STACK_FRAME(name)
   #define HX_STACK_BEGIN_CATCH
   #define HX_DEFINE_STACK_FRAME(__stackPosition, className, functionName, classFunctionHash, fullName,fileName, lineNumber, fileHash )
   #define HX_LOCAL_STACK_FRAME(a,b,c,d,e,f,g,h)
   #define HX_STACK_FRAME(className, functionName, classFunctionHash, fullName,fileName, lineNumber, fileHash )
   #define HX_STACKFRAME(pos)
   #define HX_JUST_GC_STACKFRAME ::hx::StackContext *_hx_ctx = HX_CTX_GET;
   #define HX_GC_STACKFRAME(pos) HX_JUST_GC_STACKFRAME
   #define HX_CTX _hx_ctx
#endif

#define HX_GC_CTX HX_CTX


// Setup debugger catchable and variable macros...
#ifdef HXCPP_DEBUGGER

   // Emitted at the beginning of every instance fuction.  ptr is "this".
   // Only if stack variables are to be tracked
   #define HX_STACK_THIS(ptr) ::hx::StackThis __stackthis(_hx_stackframe.variables, ptr);

   // Emitted at the beginning of every function that takes arguments.
   // name is the name of the argument.
   // For the lifetime of this object, the argument will be in the [arguments]
   // list of the stack frame in which the arg was declared
   // Only if stack variables are to be tracked
   #define HX_STACK_ARG(cpp_var, haxe_name) \
       ::hx::StackVariable __stackargument_##cpp_var(_hx_stackframe.variables, true, haxe_name, &cpp_var);

   // Emitted whenever a Haxe value is pushed on the stack.  cpp_var is the local
   // cpp variable, haxe_name is the name that was used in haxe for it
   // Only if stack variables are to be tracked
   #define HX_STACK_VAR(cpp_var, haxe_name)                                \
       ::hx::StackVariable __stackvariable_##cpp_var(_hx_stackframe.variables, false, haxe_name, &cpp_var);

   #define HX_STACK_CATCHABLE(T, n)                                        \
       hx::StackCatchable __stackcatchable_##n                             \
           (_hx_stackframe, reinterpret_cast<T *>(&_hx_stackframe));

   // If HXCPP_DEBUGGER is enabled, then a throw is checked to see if it
   // can be caught and if not, the debugger is entered.  Otherwise, the
   // throw proceeds as normal.
   #define HX_STACK_DO_THROW(e) __hxcpp_dbg_checkedThrow(e)
   #define HX_STACK_DO_RETHROW(e) __hxcpp_dbg_checkedRethrow(e)


   #define HX_VAR(type,name) type name; HX_STACK_VAR(name, #name)
   #define HX_VARI(type,name) type name; HX_STACK_VAR(name, #name) name
   #define HX_VAR_NAME(type,name,dbgName) type name; HX_STACK_VAR(name, dbgName)
   #define HX_VARI_NAME(type,name,dbgName) type name; HX_STACK_VAR(name, dbgName) name

#else // Non-debugger versions.  Just stub-out.

   #define HX_STACK_THIS(ptr)
   #define HX_STACK_ARG(cpp_var, haxe_name)
   #define HX_STACK_VAR(cpp_var, haxe_name)
   #define HX_STACK_CATCHABLE(T, n)

   #define HX_VAR(type,name) type name
   #define HX_VARI(type,name) type name
   #define HX_VAR_NAME(type,name,dbgName) type name
   #define HX_VARI_NAME(type,name,dbgName) type name

   // Just throw - move to hx::Throw function?
   #define HX_STACK_DO_THROW(e) ::hx::Throw(e)
   #define HX_STACK_DO_RETHROW(e) ::hx::Rethrow(e)
#endif // HXCPP_STACK_VARS




// Emitted after every Haxe line.  number is the original Haxe line number.
// Only if stack lines are to be tracked
#ifdef HXCPP_STACK_LINE
   // If the debugger is enabled, must check for a breakpoint at every line.
   #ifdef HXCPP_DEBUGGER
      #define HX_STACK_LINE(number)                                           \
          _hx_stackframe.lineNumber = number;                                   \
          /* This is incorrect - a read memory barrier is needed here. */     \
          /* For now, just live with the exceedingly rare cases where */      \
          /* breakpoints are missed */                                        \
          if (::hx::gShouldCallHandleBreakpoints) {                             \
              __hxcpp_on_line_changed(_hx_stackframe.ctx);                    \
         }
      #define HX_STACK_LINE_QUICK(number) _hx_stackframe.lineNumber = number;
   #else
      // Just set it
      #define HX_STACK_LINE(number) _hx_stackframe.lineNumber = number;
      #define HX_STACK_LINE_QUICK(number) _hx_stackframe.lineNumber = number;
   #endif
#else
   #define HX_STACK_LINE(number)
   #define HX_STACK_LINE_QUICK(number)
#endif


// For tidier generated code
#define HXLINE(number) HX_STACK_LINE(number)
#define HXDLIN(number)


// To support older versions of the haxe compiler that emit HX_STACK_PUSH
// instead of HX_STACK_FRAME.  If the old haxe compiler is used with this
// new debugger implementation, className.functionName breakpoints will
// not work, and stack reporting will be a little weird.  If you want to
// use debugging, you really should upgrade to a newer haxe compiler.

#undef HX_STACK_PUSH
#define HX_STACK_PUSH(fullName, fileName, lineNumber)                  \
    HX_STACK_FRAME("", fullName, 0, fullName, fileName, lineNumber, 0)

#if defined(HXCPP_STACK_TRACE) || defined(HXCPP_TELEMETRY)
   #define HXCPP_STACK_IDS
#endif


namespace hx
{


class StackFrame;
struct StackContext;

class Profiler;
void profDestroy(Profiler *);
void profAttach(Profiler *, StackContext *);
void profDetach(Profiler *, StackContext *);
void profSample(Profiler *, StackContext *inContext);


class Telemetry;
Telemetry *tlmCreate(StackContext *);
void tlmDestroy(Telemetry *);
void tlmAttach(Telemetry *, StackContext *);
void tlmDetach(Telemetry *);
void tlmSampleEnter(Telemetry *, StackFrame *inFrame);
void tlmSampleExit(Telemetry *);


class DebuggerContext;
DebuggerContext *dbgCtxCreate(StackContext *);
void dbgCtxDestroy(DebuggerContext *);
void dbgCtxAttach(DebuggerContext *, StackContext *);
void dbgCtxDetach(DebuggerContext *);
void dbgCtxEnable(DebuggerContext *, bool inEnable);


struct scriptCallable;
class StackVariable;
class StackCatchable;

template<typename T> struct Hash;
struct TWeakStringSet;
typedef Hash<TWeakStringSet> WeakStringSet;

extern const char* EXTERN_CLASS_NAME;


#ifdef HXCPP_DEBUGGER
extern volatile bool gShouldCallHandleBreakpoints;


// These must match the values present in cpp.vm.Debugger
enum DebugStatus
{
    DBG_STATUS_INVALID = 0, // Not present or needed in cpp.vm.Debugger
    DBG_STATUS_RUNNING = 1,
    DBG_STATUS_STOPPED_BREAK_IMMEDIATE = 2,
    DBG_STATUS_STOPPED_BREAKPOINT = 3,
    DBG_STATUS_STOPPED_UNCAUGHT_EXCEPTION = 4,
    DBG_STATUS_STOPPED_CRITICAL_ERROR = 5
};

enum ExecutionTrace
{
   exeTraceOff = 0,
   exeTraceFuncs = 1,
   exeTraceLines = 2,
};

extern ExecutionTrace sExecutionTrace;

#endif





class StackPosition
{
public:
    // These are constant during the lifetime of the stack frame
    const char *className;
    const char *functionName;
    const char *fullName; // this is className.functionName - used for profiler
    const char *fileName;
    int firstLineNumber;

    #if defined(HXCPP_STACK_SCRIPTABLE)
    // Information about the current cppia function
    struct ScriptCallable *scriptCallable;
    #endif

    // These are only used if HXCPP_DEBUGGER is defined
    #ifdef HXCPP_DEBUGGER
    int fileHash;
    int classFuncHash;
    #else
    enum { fileHash = 0, classFuncHash=0 };
    #endif

    inline StackPosition() { }

    // The constructor automatically adds the StackFrame to the list of
    // stack frames for the current thread
    inline StackPosition(const char *inClassName, const char *inFunctionName,
                         const char *inFullName, const char *inFileName
                         #ifdef HXCPP_STACK_LINE
                         , int inLineNumber
                         #endif
                         #ifdef HXCPP_DEBUGGER
                         ,int inClassFunctionHash, int inFileHash
                         #endif
                  )

       : className(inClassName), functionName(inFunctionName)
         ,fullName(inFullName), fileName(inFileName)
         #ifdef HXCPP_DEBUGGER
         ,classFuncHash(inClassFunctionHash)
         ,fileHash(inFileHash)
         #endif
         #ifdef HXCPP_STACK_LINE
         ,firstLineNumber(inLineNumber)
         #endif
    {
       #if defined(HXCPP_STACK_SCRIPTABLE)
       // Information about the current cppia function
       scriptCallable = 0;
       #endif
    }

};






#ifdef HXCPP_STACK_TRACE
struct ExceptionStackFrame
{
   #ifdef HXCPP_STACK_LINE
   int line;
   #endif

   const hx::StackPosition *position;

   ExceptionStackFrame(const StackFrame &inFrame);
   ::String format(bool inForDisplay);
   ::String toDisplay();
   ::String toString();
};
#endif


#ifdef HXCPP_SCRIPTABLE
enum
{
   bcrBreak    = 0x01,
   bcrContinue = 0x02,
   bcrReturn   = 0x04,

   bcrLoop     = (bcrBreak | bcrContinue),
};



#endif


struct MarkChunk
{
   enum { SIZE = 62 };
   enum { OBJ_ARRAY_JOB = -1 };

   inline MarkChunk() : count(0), next(0) { }

   int        count;

   union
   {
      hx::Object *stack[SIZE];
      struct
      {
         hx::Object **arrayBase;
         int        arrayElements;
      };
   };
   MarkChunk  *next;

   inline void push(Object *inObj)
   {
      stack[count++] = inObj;
   }
   inline hx::Object *pop()
   {
      if (count)
         return stack[--count];
      return 0;
   }
   MarkChunk *swapForNew();
};



struct StackContext : public hx::ImmixAllocator
{
   #ifdef HXCPP_STACK_IDS
      int  mThreadId;
   #endif

   #ifdef HXCPP_STACK_TRACE
      hx::QuickVec<StackFrame *> mStackFrames;
      hx::QuickVec<hx::ExceptionStackFrame> mExceptionStack;
      // Updated only when a thrown exception unwinds the stack
      bool mIsUnwindingException;

      #ifdef HXCPP_STACK_SCRIPTABLE
         // TODO - combine CppaCtx and StackContext
      #endif

      #ifdef HXCPP_DEBUGGER
         DebuggerContext  *mDebugger;
      #endif

      #ifdef HXCPP_PROFILER
         // Profiling support
         Profiler *mProfiler;
      #endif

   #endif

   #ifdef HXCPP_TELEMETRY
      // Telemetry support
      Telemetry *mTelemetry;
   #endif

   #ifdef HXCPP_COMBINE_STRINGS
   WeakStringSet *stringSet;
   #endif

   #ifdef HXCPP_GC_GENERATIONAL
   MarkChunk *mOldReferrers;
   inline void pushReferrer(hx::Object *inObj)
   {
      // If collector is running on non-generational mode, mOldReferrers will be null
      if (mOldReferrers)
      {
         mOldReferrers->push(inObj);
         if (mOldReferrers->count==MarkChunk::SIZE)
            mOldReferrers = mOldReferrers->swapForNew();
      }
   }
   #endif

   #ifdef HXCPP_CATCH_SEGV
      #ifdef _MSC_VER
      _se_translator_function mOldSignalFunc;
      #else
      void (*mOldSignalFunc)(int);
      #endif
   #endif

   StackContext();
   ~StackContext();
   void onThreadAttach();
   void onThreadDetach();


   #ifdef HXCPP_STACK_TRACE // {
   void tracePosition();

   // Note that the stack frames are manipulated without holding any locks.
   // This is because the manipulation of stack frames can only be done by
   // the thread that "owns" that stack frame.  The only other contention on
   // the call stack is from calls to GetThreadInfo() and GetThreadInfos(),
   // and these should only be called when the thread for which the call
   // stack is being acquired is stopped in a breakpoint anyway, thus there
   // can be no contention on the contents of the CallStack in that case
   // either.

   inline void pushFrame(StackFrame *inFrame)
   {
      #ifdef HXCPP_PROFILER
      if (mProfiler)
         profSample(mProfiler,this);
      #endif

      #ifdef HXCPP_TELEMETRY
      if (mTelemetry)
         tlmSampleEnter(mTelemetry,inFrame);
      #endif

      mIsUnwindingException = false;
      mStackFrames.push(inFrame);

      #ifdef HXCPP_DEBUGGER
      if (sExecutionTrace!=exeTraceOff)
         tracePosition();
      #endif
   }

   inline void popFrame(StackFrame *inFrame)
   {
      #ifdef HXCPP_TELEMETRY
      if (mTelemetry)
         tlmSampleExit(mTelemetry);
      #endif

      if (mIsUnwindingException)
      {
         // Use default operator=
         mExceptionStack.push( *inFrame );
      }

      mStackFrames.pop_back();
   }

   void getCurrentCallStackAsStrings(Array<String> result, bool skipLast);
   void getCurrentExceptionStackAsStrings(Array<String> result);
   StackFrame *getCurrentStackFrame() { return mStackFrames.back(); }
   StackFrame *getStackFrame(int inIndex) { return mStackFrames[inIndex]; }
   int getDepth() const { return mStackFrames.size(); }
   inline const char *getFullNameAtDepth(int depth) const;
   void  dumpExceptionStack();

   // Called when a throw occurs
   void setLastException();
   void pushLastException();
    // Called when a catch block begins to be executed.  hxcpp wants to track
    // the stack back through the catches so that it can be dumped if
    // uncaught.  If inAll is true, the entire stack is captured immediately.
    // If inAll is false, only the last stack frame is captured.
    void beginCatch(bool inAll);

   #endif // } HXCPP_STACK_TRACE

   #ifdef HXCPP_DEBUGGER
   void enableCurrentThreadDebugging(bool inEnable)
   {
      dbgCtxEnable(mDebugger,inEnable);
   }
   #endif

   static inline StackContext *getCurrent()
   {
      return HX_CTX_GET;
   }

   #ifdef HXCPP_STACK_IDS
   static void getAllStackIds( QuickVec<int> &outIds );
   static StackContext *getStackForId(int id);
   #endif


   #ifdef HXCPP_SCRIPTABLE
   unsigned char *stack;
   unsigned char *pointer;
   unsigned char *frame;
   class Object  *exception;

   unsigned int breakContReturn;
   int  byteMarkId;

   template<typename T>
   void push(T inValue)
   {
      *(T *)pointer = inValue;
      pointer += sizeof(T);
   }
   unsigned char *stackAlloc(int inSize)
   {
      unsigned char *p = pointer;
      pointer += inSize;
      return p;
   }
   void stackFree(int inSize)
   {
      pointer -= inSize;
   }

   int getFrameSize() const { return pointer-frame; }

   int runInt(void *vtable);
   Float runFloat(void *vtable);
   String runString(void *vtable);
   void runVoid(void *vtable);
   Dynamic runObject(void *vtable);
   hx::Object *runObjectPtr(void *vtable);

   void push(bool &inValue) { *(int *)pointer = inValue; pointer += sizeof(int); }
   inline void pushBool(bool b) { *(int *)pointer = b; pointer += sizeof(int); }
   inline void pushInt(int i) { *(int *)pointer = i; pointer += sizeof(int); }

   inline void pushFloat(Float f);
   inline void pushString(const String &s);
   inline void pushObject(Dynamic d);
   inline void returnFloat(Float f);
   inline void returnString(const String &s);
   inline void returnObject(Dynamic d);
   inline hx::Object *getThis(bool inCheckPtr=true);

   inline void returnBool(bool b) { *(int *)frame = b; }
   inline void returnInt(int i) { *(int *)frame = i; }
   inline bool getBool(int inPos=0) { return *(bool *)(frame+inPos); }
   inline int getInt(int inPos=0) { return *(int *)(frame+inPos); }

   inline Float getFloat(int inPos=0);
   inline String getString(int inPos=0);
   inline Dynamic getObject(int inPos=0);
   inline hx::Object *getObjectPtr(int inPos=0) { return *(hx::Object **)(frame+inPos); }


   void breakFlag() { breakContReturn |= bcrBreak; }
   void continueFlag() { breakContReturn |= bcrContinue; }
   void returnFlag() { breakContReturn |= bcrReturn; }

   #endif

};


typedef StackContext CppiaCtx;



class StackFrame
{
public:
   StackContext        *ctx;

   #ifdef HXCPP_STACK_TRACE // {
   const StackPosition *position;

      #ifdef HXCPP_STACK_LINE
         // Current line number, changes during the lifetime of the stack frame.
         // Only updated if HXCPP_STACK_LINE is defined.
         int lineNumber;

         #ifdef HXCPP_DEBUGGER
         // Function arguments and local variables in reverse order of their
         // declaration.  If a variable name is in here twice, the first version is
         // the most recently scoped one and should be used.  Only updated if
         // HXCPP_DEBUGGER is defined.
         StackVariable *variables;

         // The list of types that can be currently caught in the stack frame.
         StackCatchable *catchables;
         #endif
      #endif

       // The constructor automatically adds the StackFrame to the list of
       // stack frames for the current thread
       inline StackFrame(const StackPosition *inPosition
              ) : position(inPosition)
       {
          #ifdef HXCPP_STACK_LINE
             lineNumber = inPosition->firstLineNumber;
             #ifdef HXCPP_DEBUGGER
             variables = 0;
             catchables = 0;
             #endif
          #endif


          ctx =  HX_CTX_GET;
          ctx->pushFrame(this);
       }


       // The destructor automatically removes the StackFrame from the list of
       // stack frames for the current thread
       ~StackFrame()
       {
          ctx->popFrame(this);
       }

       ::String toString();
       ::String toDisplay();
   #else // }  !HXCPP_STACK_TRACE {

       // Release version only has ctx
       inline StackFrame()
       {
          ctx =  HX_CTX_GET;
       }

   #endif // }

};

#ifdef HXCPP_STACK_TRACE
const char *StackContext::getFullNameAtDepth(int depth) const
{
   return mStackFrames[depth]->position->fullName;
}
#endif

class JustGcStackFrame
{
public:
   StackContext        *ctx;
   inline JustGcStackFrame() : ctx(HX_CTX_GET) { }
};




} // end namespace hx



// Some functions used by AdvancedDebug.cpp
// Returns the thread number of the calling thread
HXCPP_EXTERN_CLASS_ATTRIBUTES
int __hxcpp_GetCurrentThreadNumber();

// Called by the main function when an uncaught exception occurs to dump
// the stack leading to the exception
HXCPP_EXTERN_CLASS_ATTRIBUTES
void __hx_dump_stack();

// The macro HX_STACK_BEGIN_CATCH, which is emitted at the beginning of every
// catch block, calls this in debug mode to let the debugging system know that
// a catch block has been entered
HXCPP_EXTERN_CLASS_ATTRIBUTES
void __hxcpp_stack_begin_catch();

// Last chance to throw an exception for null-pointer access
HXCPP_EXTERN_CLASS_ATTRIBUTES
void __hxcpp_set_critical_error_handler(Dynamic inHandler);

HXCPP_EXTERN_CLASS_ATTRIBUTES
void __hxcpp_execution_trace(int inLevel);

// Used by debug breakpoints and execution trace
HXCPP_EXTERN_CLASS_ATTRIBUTES
void __hxcpp_set_stack_frame_line(int);

HXCPP_EXTERN_CLASS_ATTRIBUTES
void __hxcpp_on_line_changed(hx::StackContext *);

HXCPP_EXTERN_CLASS_ATTRIBUTES
void __hxcpp_set_debugger_info(const char **inAllClasses, const char **inFullPaths);


void __hxcpp_dbg_getScriptableVariables(hx::StackFrame *stackFrame, ::Array< ::Dynamic> outNames);
bool __hxcpp_dbg_getScriptableValue(hx::StackFrame *stackFrame, String inName, ::Dynamic &outValue);
bool __hxcpp_dbg_setScriptableValue(hx::StackFrame *StackFrame, String inName, ::Dynamic inValue);




#endif // HX_STACK_CTX_H