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
 |