753 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			753 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#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
 | 
						|
 | 
						|
   #if HXCPP_API_LEVEL > 330
 | 
						|
   const hx::StackPosition *position;
 | 
						|
   #else
 | 
						|
   const char *className;
 | 
						|
   const char *functionName;
 | 
						|
   const char *fileName;
 | 
						|
   #endif
 | 
						|
 | 
						|
   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
 |