소스 검색

Integrate new debugger support

Hugh 12 년 전
부모
커밋
bdbce58486
2개의 변경된 파일405개의 추가작업 그리고 76개의 파일을 삭제
  1. 57 20
      gencpp.ml
  2. 348 56
      std/cpp/vm/Debugger.hx

+ 57 - 20
gencpp.ml

@@ -1130,8 +1130,9 @@ let hx_stack_push ctx output clazz func_name pos =
    let qfile = "\"" ^ (Ast.s_escape stripped_file) ^ "\"" in
 	ctx.ctx_file_info := PMap.add qfile qfile !(ctx.ctx_file_info);
 	if (ctx.ctx_dump_stack_line) then
-		output ("HX_STACK_PUSH(\"" ^ clazz ^ "::" ^ func_name ^ "\"," ^ qfile ^ ","
-					^ (string_of_int (Lexer.get_error_line pos) ) ^ ");\n")
+		output ("HX_STACK_FRAME(\"" ^ clazz ^ "\",\"" ^ func_name ^ "\",\"" ^ 
+                clazz ^ "." ^ func_name ^ "\"," ^ qfile ^ "," ^
+			    (string_of_int (Lexer.get_error_line pos) ) ^ ")\n")
 ;;
 
 
@@ -1197,8 +1198,8 @@ let rec define_local_function_ctx ctx func_name func_def =
 		writer#begin_block;
       hx_stack_push ctx output_i "*" func_name func_def.tf_expr.epos;
 		if (has_this && ctx.ctx_dump_stack_line) then
-			output_i ("HX_STACK_THIS(__this.mPtr);\n");
-		List.iter (fun (v,_) -> output_i ("HX_STACK_ARG(" ^ (keyword_remap v.v_name) ^ ",\"" ^ v.v_name ^"\");\n") )
+			output_i ("HX_STACK_THIS(__this.mPtr)\n");
+		List.iter (fun (v,_) -> output_i ("HX_STACK_ARG(" ^ (keyword_remap v.v_name) ^ ",\"" ^ v.v_name ^"\")\n") )
             func_def.tf_args;
 
 		if (block) then begin
@@ -1943,10 +1944,19 @@ and gen_expression ctx retval expression =
 			);
 		end
 	| TTry (expression, catch_list) ->
-		output "try";
+		output "try\n";
+        output_i "{\n";
+        let counter = ref 0 in
+        List.iter (fun (v, e) ->
+			let type_name = type_string v.v_type in
+			    output_i ("HX_STACK_CATCHABLE(" ^ type_name ^ ", " ^ string_of_int !counter ^ ");\n");
+                counter := !counter + 1;)
+            catch_list;
+        output_i("");
 		(* Move this "inside" the try call ... *)
 		ctx.ctx_return_from_block <-return_from_internal_node;
 		gen_expression ctx false (to_block expression);
+        output_i "}\n";
 		if (List.length catch_list > 0 ) then begin
 			output_i "catch(Dynamic __e)";
 			ctx.ctx_writer#begin_block;
@@ -1969,15 +1979,18 @@ and gen_expression ctx retval expression =
 				else_str := "else ";
 				) catch_list;
 			if (not !seen_dynamic) then begin
-				output_i "else throw(__e);\n";
+				output_i "else {\n";
+                output_i "    HX_STACK_DO_THROW(__e);\n";
+                output_i "}\n";
 			end;
 			ctx.ctx_writer#end_block;
 		end;
 	| TBreak -> output "break"
 	| TContinue -> output "continue"
-	| TThrow expression -> output "hx::Throw (";
+	| TThrow expression -> 
+	        output "HX_STACK_DO_THROW(";
 			gen_expression ctx true expression;
-			output ")"
+			output ")";
 	| TCast (cast,None) ->
 		let void_cast = retval && ((type_string expression.etype)="Void" ) in
       if (void_cast) then output "Void(";
@@ -2066,8 +2079,8 @@ let gen_field ctx class_def class_name ptr_name is_static is_interface field =
 			ctx.ctx_dump_stack_line <- true;
 			(fun() ->
          hx_stack_push ctx output_i ptr_name field.cf_name function_def.tf_expr.epos;
-         if (not is_static) then output_i ("HX_STACK_THIS(this);\n");
-			List.iter (fun (v,_) -> output_i ("HX_STACK_ARG(" ^ (keyword_remap v.v_name) ^ ",\"" ^ v.v_name ^"\");\n") )
+         if (not is_static) then output_i ("HX_STACK_THIS(this)\n");
+			List.iter (fun (v,_) -> output_i ("HX_STACK_ARG(" ^ (keyword_remap v.v_name) ^ ",\"" ^ v.v_name ^"\")\n") )
             function_def.tf_args )
 		end in
 
@@ -2473,16 +2486,27 @@ let generate_files common_ctx file_info =
 	let base_dir = common_ctx.file in
 	let files_file = new_cpp_file base_dir ([],"__files__") in
 	let output_files = (files_file#write) in
+    let types = common_ctx.types in
 	output_files "#include <hxcpp.h>\n\n";
 	output_files "namespace hx {\n";
 	output_files "const char *__hxcpp_all_files[] = {\n";
 	output_files "#ifdef HXCPP_DEBUGGER\n";
-	List.iter ( fun file -> output_files ("	" ^ file ^ ",\n" ) ) ( List.sort String.compare ( pmap_keys !file_info) );
+	List.iter ( fun file -> output_files ("	HX_CSTRING(" ^ file ^ "),\n" ) ) ( List.sort String.compare ( pmap_keys !file_info) );
 	output_files "#endif\n";
 	output_files " 0 };\n";
-	output_files "const char *__hxcpp_class_path[] = {\n";
+    output_files "\n";
+    output_files "const char *__hxcpp_all_classes[] = {\n";
 	output_files "#ifdef HXCPP_DEBUGGER\n";
-	List.iter ( fun file -> output_files ("	\"" ^ file ^ "\",\n" ) ) (common_ctx.class_path @ common_ctx.std_path);
+    List.iter ( fun object_def ->
+                (match object_def with
+		         | TClassDecl class_def when class_def.cl_extern -> ( )
+		         | TClassDecl class_def when class_def.cl_interface -> ( )
+				 | TClassDecl class_def ->
+                   output_files("    HX_CSTRING(\"" ^ join_class_path class_def.cl_path "." ^ "\"),\n")
+                 | _ -> ( )
+                )
+              )
+              types;
 	output_files "#endif\n";
 	output_files " 0 };\n";
 	output_files "} // namespace hx\n";
@@ -2618,6 +2642,7 @@ let generate_enum_files common_ctx enum_def super_deps meta file_info =
 	output_cpp "};\n\n";
 
 	(* ENUM - Visit static as used by GC *)
+	output_cpp "#ifdef HXCPP_VISIT_ALLOCS\n";
 	output_cpp "static void sVisitStatic(HX_VISIT_PARAMS) {\n";
 	output_cpp ("	HX_VISIT_MEMBER_NAME(" ^ class_name ^ "::__mClass,\"__mClass\");\n");
 	PMap.iter (fun _ constructor ->
@@ -2626,7 +2651,8 @@ let generate_enum_files common_ctx enum_def super_deps meta file_info =
 		| TFun (_,_) -> ()
 		| _ -> output_cpp ("	HX_VISIT_MEMBER_NAME(" ^ class_name ^ "::" ^ name ^ ",\"" ^ name ^ "\");\n") )
 	enum_def.e_constrs;
-	output_cpp "};\n\n";
+	output_cpp "};\n";
+	output_cpp "#endif\n\n";
 
 	output_cpp "static ::String sMemberFields[] = { ::String(null()) };\n";
 
@@ -2639,7 +2665,8 @@ let generate_enum_files common_ctx enum_def super_deps meta file_info =
 	output_cpp ("\nhx::Static(__mClass) = hx::RegisterClass(" ^ text_name ^
 					", hx::TCanCast< " ^ class_name ^ " >,sStaticFields,sMemberFields,\n");
 	output_cpp ("	&__Create_" ^ class_name ^ ", &__Create,\n");
-	output_cpp ("	&super::__SGetClass(), &Create" ^ class_name ^ ", sMarkStatics, sVisitStatic);\n");
+	output_cpp ("	&super::__SGetClass(), &Create" ^ class_name ^ ", sMarkStatics\n");
+	output_cpp("#ifdef HXCPP_VISIT_ALLOCS\n    , sVisitStatic\n#endif\n);\n");
 	output_cpp ("}\n\n");
 
 	output_cpp ("void " ^ class_name ^ "::__boot()\n{\n");
@@ -2761,19 +2788,21 @@ let generate_class_files common_ctx member_types super_deps constructor_deps cla
 	if debug then print_endline ("Found class definition:" ^ ctx.ctx_class_name);
 
 	let ptr_name = "hx::ObjectPtr< " ^ class_name ^ " >" in
-	let constructor_type_var_list =
+	let constructor_arg_var_list =
 		match class_def.cl_constructor with
 		| Some definition ->
 					(match definition.cf_expr with
 						| Some { eexpr = TFunction function_def } ->
-							List.map (fun (v,o) -> gen_arg_type_name v.v_name o v.v_type "__o_")
+							List.map (fun (v,o) -> (v.v_name, gen_arg_type_name v.v_name o v.v_type "__o_"))
 									function_def.tf_args;
 						| _ ->
 							(match follow definition.cf_type with
-								| TFun (args,_) -> List.map (fun (a,_,t) -> (type_string t,a) )  args
+								| TFun (args,_) -> List.map (fun (a,_,t) -> (a, (type_string t, a)) )  args
 								| _ -> [])
 					)
 		| _ -> [] in
+	let constructor_type_var_list =
+	    List.map snd constructor_arg_var_list in
 	let constructor_var_list = List.map snd constructor_type_var_list in
 	let constructor_type_args = String.concat ","
 				(List.map (fun (t,a) -> t ^ " " ^ a) constructor_type_var_list) in
@@ -2821,6 +2850,8 @@ let generate_class_files common_ctx member_types super_deps constructor_deps cla
 					(match  definition.cf_expr with
 					| Some { eexpr = TFunction function_def } ->
       				hx_stack_push ctx output_cpp smart_class_name "new" function_def.tf_expr.epos;
+		            List.iter (fun (a,(t,o)) -> output_cpp ("\nHX_STACK_ARG(" ^ (keyword_remap o) ^ ",\"" ^ a ^"\")\n") ) constructor_arg_var_list;
+
 						if (has_default_values function_def.tf_args) then begin
 							generate_default_values ctx function_def.tf_args "__o_";
 							gen_expression ctx false (to_block function_def.tf_expr);
@@ -3083,6 +3114,7 @@ let generate_class_files common_ctx member_types super_deps constructor_deps cla
 	output_cpp "};\n\n";
 
 	(* Visit static variables *)
+	output_cpp "#ifdef HXCPP_VISIT_ALLOCS\n";
 	output_cpp "static void sVisitStatics(HX_VISIT_PARAMS) {\n";
 	output_cpp ("	HX_VISIT_MEMBER_NAME(" ^ class_name ^ "::__mClass,\"__mClass\");\n");
 	List.iter (fun field ->
@@ -3090,6 +3122,7 @@ let generate_class_files common_ctx member_types super_deps constructor_deps cla
 			output_cpp ("	HX_VISIT_MEMBER_NAME(" ^ class_name ^ "::" ^ (keyword_remap field.cf_name) ^ ",\"" ^  field.cf_name ^ "\");\n") )
 		implemented_fields;
 	output_cpp "};\n\n";
+	output_cpp "#endif\n\n";
 
    if (scriptable ) then begin
       let dump_script_field idx (field,f_args,return_t) =
@@ -3157,7 +3190,9 @@ let generate_class_files common_ctx member_types super_deps constructor_deps cla
 		output_cpp ("	hx::Static(__mClass) = hx::RegisterClass(" ^ (str class_name_text)  ^
 				", hx::TCanCast< " ^ class_name ^ "> ,sStaticFields,sMemberFields,\n");
 		output_cpp ("	&__CreateEmpty, &__Create,\n");
-		output_cpp ("	&super::__SGetClass(), 0, sMarkStatics, sVisitStatics);\n");
+		output_cpp ("	&super::__SGetClass(), 0, sMarkStatics\n");
+		output_cpp ("#ifdef HXCPP_VISIT_ALLOCS\n    , sVisitStatics\n#endif\n");
+		output_cpp (");\n");
       if (scriptable) then
             output_cpp ("  HX_SCRIPTABLE_REGISTER_CLASS(\""^class_name_text^"\"," ^ class_name ^ ");\n");
 		output_cpp ("}\n\n");
@@ -3171,7 +3206,9 @@ let generate_class_files common_ctx member_types super_deps constructor_deps cla
 		output_cpp ("	hx::Static(__mClass) = hx::RegisterClass(" ^ (str class_name_text)  ^
 				", hx::TCanCast< " ^ class_name ^ "> ,0,sMemberFields,\n");
 		output_cpp ("	0, 0,\n");
-		output_cpp ("	&super::__SGetClass(), 0, sMarkStatics, sVisitStatics);\n");
+		output_cpp ("	&super::__SGetClass(), 0, sMarkStatics\n");
+		output_cpp ("#ifdef HXCPP_VISIT_ALLOCS\n    , sVisitStatics\n#endif\n");
+		output_cpp (");\n");
       if (scriptable) then
          output_cpp ("  HX_SCRIPTABLE_REGISTER_INTERFACE(\""^class_name_text^"\"," ^ class_name ^ ");\n");
 		output_cpp ("}\n\n");

+ 348 - 56
std/cpp/vm/Debugger.hx

@@ -21,90 +21,382 @@
  */
 package cpp.vm;
 
-import haxe.CallStack;
 
-class Debugger
+/**
+ * Parameter describes a function parameter.  Instances of this class are
+ * embedded in stack frame objects to describe the function parameters that
+ * were used in the invocation of the function that defines that stack frame.
+ **/
+class Parameter
 {
-   public static inline var BRK_THIS      = -2;
-   public static inline var BRK_TERMINATE = -1;
-
-   public static inline var BRK_NONE  = 0;
-   public static inline var BRK_ASAP  = 1;
-   public static inline var BRK_STEP  = 2;
-   public static inline var BRK_ENTER = 3;
-   public static inline var BRK_LEAVE = 4;
+    public var name(default, null) : String;
+    public var value(default, null) : Dynamic;
 
-   public static function setHandler(inHandler:Void->Void)
+    public function new(name : String, value : Dynamic)
    {
-      untyped __global__.__hxcpp_dbg_set_handler(inHandler);
+        this.name = name;
+        this.value = value;
    }
-
-   public static function setThread(?inDebugThread:Thread)
-   {
-      untyped __global__.__hxcpp_dbg_set_thread(inDebugThread==null?Thread.current().handle:inDebugThread.handle);
    }
 
-
-   // Generate a handler callback ASAP
-   public static function setBreak(inMode:Int)
+/**
+ * StackFrame describes one call stack frame.
+ **/
+class StackFrame
    {
-      untyped __global__.__hxcpp_dbg_set_break(inMode);
-   }
+    public var fileName(default, null) : String;
+    public var lineNumber(default, null) : Int;
+    public var className(default, null) : String;
+    public var functionName(default, null) : String;
+    public var parameters(default, null) : Array<Parameter>;
 
-   public static function exit()
+    public function new(fileName : String, lineNumber : Int,
+                        className : String, functionName : String)
    {
-      untyped __global__.__hxcpp_dbg_set_break(BRK_TERMINATE);
+        this.fileName = fileName;
+        this.lineNumber = lineNumber;
+        this.className = className;
+        this.functionName = functionName;
+        this.parameters = new Array<Parameter>();
    }
-   public static function breakBad()
-   {
-      untyped __global__.__hxcpp_dbg_set_break(BRK_THIS);
    }
 
+/**
+ * ThreadInfo describes the state of a single thread.
+ **/
+class ThreadInfo
+   {
+    public static inline var STATUS_RUNNING = 1;
+    public static inline var STATUS_STOPPED_BREAK_IMMEDIATE = 2;
+    public static inline var STATUS_STOPPED_BREAKPOINT = 3;
+    public static inline var STATUS_STOPPED_UNCAUGHT_EXCEPTION = 4;
+    public static inline var STATUS_STOPPED_CRITICAL_ERROR = 5;
 
+    // 0 is never a valid thread number
+    public var number(default, null) : Int;
+    public var status(default, null) : Int;
+    // If status is "stopped breakpoint", this is the breakpoint number
+    public var breakpoint(default, null) : Int;
+    // If status is "critical error", this describes the error
+    public var criticalErrorDescription(default, null) : String;
+    // Stack will be listed with the lowest frame first
+    public var stack(default, null) : Array<StackFrame>;
 
-   // Breakpoint
-   public static function addBreakpoint(inFileId:Int, inLine:Int)
+    public function new(number : Int, status : Int, breakpoint : Int = -1,
+                        criticalErrorDescription : String = null)
    {
-      untyped __global__.__hxcpp_breakpoints_add(inFileId, inLine);
+        this.number = number;
+        this.status = status;
+        this.breakpoint = breakpoint;
+        this.criticalErrorDescription = criticalErrorDescription;
+        this.stack = new Array<StackFrame>();
    }
-
-   public static function getBreakpoints() : Array<String>
-   {
-      return untyped __global__.__hxcpp_dbg_breakpoints_get();
    }
 
-   public static function deleteBreakpoint(inI:Int)
+/**
+ * This class wraps the hxcpp C++ implementation to provide a Haxe interface
+ * to the low level debugging features
+ **/
+class Debugger
    {
-      untyped __global__.__hxcpp_dbg_breakpoints_delete(inI);
-   }
+    public static inline var THREAD_CREATED = 1;
+    public static inline var THREAD_TERMINATED = 2;
+    public static inline var THREAD_STARTED = 3;
+    public static inline var THREAD_STOPPED = 4;
 
-   // Thread - todo
-   // public static function suspendAll()
+    public static inline var STEP_INTO = 1;
+    public static inline var STEP_OVER = 2;
+    public static inline var STEP_OUT = 3;
 
-   // Callstack
-   public static function getStackFrames() : Array<haxe.StackItem>
-   {
-      return untyped __global__.__hxcpp_dbg_stack_frames_get();
-   }
+    // This tagging value is returned by getStackVariableValue() and
+    // setStackVariableValue if the requested value does not exist at the
+    // requested stack frame
+    public static var NONEXISTENT_VALUE = new String("NONEXISTENT_VALUE");
+    // This tagging value is returned by getStackVariableValue and
+    // setStackVariableValue if the stack variable that is being set is on a
+    // thread that is running, in which case the set does not take place.
+    public static var THREAD_NOT_STOPPED = new String("THREAD_NOT_STOPPED");
 
-   public static function getStackVars(inFrame:Int) : Array<String>
-   {
-      return untyped __global__.__hxcpp_dbg_get_stack_vars(inFrame);
-   }
+    /**
+     * Sets the handler callback to be made when asynchronous events occur,
+     * specifically, when threads are created, terminated, started, or
+     * stopped.  The calling thread becomes the "debugger" thread, which means
+     * that it will be discluded from any breakpoints and will not be reported
+     * on by any thread reporting requests.
+     *
+     * Be aware that this callback is made asynchronously and possibly by
+     * multiple threads simultaneously.
+     *
+     * Setting this to null prevents further callbacks.
+     *
+     * Throws a string exception if the program does not support debugging
+     * because it was not compiled with the HXCPP_DEBUGGER flag set.
+     *
+     * @param handler is a function that will be called back by asynchronous
+     *        thread events.  Note that this function is called directly from
+     *        the thread experiencing the event and the handler should return
+     *        quickly to avoid blocking the calling thread unnecessarily.
+     *        The paramaters to handler are:
+     *          - threadNumber, the thread number of the event
+     *          - event, one of THREAD_CREATED, THREAD_TERMINATED,
+     *            THREAD_STARTED, or THREAD_STOPPED
+     *          - className, the class name at which the thread is stopped,
+     *            undefined if event is not THREAD_STOPPED
+     *          - functionName, the function name at which the thread is
+     *            stopped, undefined if event is not THREAD_STOPPED
+     *          - fileName, the file name at which the thread is stopped,
+     *            undefined if event is not THREAD_STOPPED
+     *          - lineNumber, the line number at which the thread is stopped,
+     *            undefined if event is not THREAD_STOPPED
+     **/
+    public static function setEventNotificationHandler(
+             handler : Int -> Int -> String -> String -> String -> Int -> Void)
+    {
+        untyped __global__.__hxcpp_dbg_setEventNotificationHandler(handler);
+    }
 
-   public static function getStackVar(inFrame:Int,inVar:String) : Dynamic
-   {
-      return untyped __global__.__hxcpp_dbg_get_stack_var(inFrame,inVar);
-   }
+    /**
+     * This can be called to turn off (and then back on) all stopping of
+     * debugged threads temporarily.  It should only be used by classes that
+     * actually implement the debugger to hide themselves from the debugger as
+     * necessary.
+     **/
+    public static function enableCurrentThreadDebugging(enabled : Bool)
+    {
+        untyped __global__.__hxcpp_dbg_enableCurrentThreadDebugging(enabled);
+    }
+
+    /**
+     * Returns the thread number of the calling thread.
+     *
+     * @return the thread number of the calling thread.
+     **/
+	public static function getCurrentThreadNumber() : Int
+	{
+        return untyped __global__.__hxcpp_dbg_getCurrentThreadNumber();
+	}
 
-   public static function setStackVar(inFrame:Int,inVar:String, inValue:Dynamic)
+    /**
+     * Returns the set of source files known to the debugger.  This is a copy
+     * of the original array and could be quite large.  The caller should
+     * cache this value to avoid multiple copies needing to be made.
+     *
+     * @return the set of source files known to the debugger.
+     **/
+    public static function getFiles() : Array<String>
    {
-      untyped __global__.__hxcpp_dbg_set_stack_var(inFrame,inVar,inValue);
+        return untyped __global__.__hxcpp_dbg_getFiles();
    }
 
-   public static function getFiles() : Array<String>
-   {
-      return untyped __global__.__hxcpp_dbg_get_files();
+    /**
+     * Returns the set of class names of all classes known to the debugger.
+     * This is a copy of the original array and could be quite large.  The
+     * caller should cache this value to avoid multiple copies needing to be
+     * made.
+     *
+     * @return the set of class names of all classes known to the debugger.
+     **/
+    public static function getClasses() : Array<String>
+    {
+        return untyped __global__.__hxcpp_dbg_getClasses();
+    }
+    
+    /**
+     * Returns a ThreadInfo object describing every thread that existed at the
+     * moment that the call was made, except for the debugger thread.
+     **/
+    public static function getThreadInfos() : Array<ThreadInfo>
+    {
+        return untyped __global__.__hxcpp_dbg_getThreadInfos();
+    }
+    
+    /**
+     * Returns a ThreadInfo object describing a single thread, or null if
+     * there is no such thread or the thread queried about was the debugger
+     * thread and unsafe was not true.
+     **/
+    public static function getThreadInfo(threadNumber : Int,
+                                         unsafe : Bool) : ThreadInfo
+    {
+        return untyped __global__.__hxcpp_dbg_getThreadInfo
+            (threadNumber, unsafe);
+    }
+    
+    /**
+     * Adds a new file:line breakpoint.  The breakpoint number of the newly
+     * added breakpoint is returned.
+     **/
+    public static function addFileLineBreakpoint(file : String, 
+                                                 line : Int) : Int
+    {
+        return untyped __global__.__hxcpp_dbg_addFileLineBreakpoint
+            (file, line);
+    }
+    
+    /**
+     * Adds a new class:function breakpoint.  The breakpoint number of the
+     * newly added breakpoint is returned.
+     **/
+    public static function addClassFunctionBreakpoint(className : String,
+                                                   functionName : String) : Int
+    {
+        return untyped __global__.__hxcpp_dbg_addClassFunctionBreakpoint
+            (className, functionName);
+    }
+
+    /**
+     * Deletes a breakpoint, or all breakpoints.
+     **/
+    public static function deleteBreakpoint(number : Null<Int>)
+    {
+        if (number == null) {
+            untyped __global__.__hxcpp_dbg_deleteAllBreakpoints();
+        }
+        else {
+            untyped __global__.__hxcpp_dbg_deleteBreakpoint
+                (cast (number, Int));
+        }
+    }
+    
+    /**
+     * Breaks all threads except the debugger thread (which should be the same
+     * as the calling thread!).
+     *
+     * If [wait] is true, waits up to 2 seconds for all threads to be broken.
+     * Threads which are in blocking system calls and cannot break after 2
+     * seconds remain running when this function returns.
+     **/
+    public static function breakNow(wait : Bool = true)
+    {
+        untyped __global__.__hxcpp_dbg_breakNow(wait);
+    }
+    
+    /**
+     * Continue execution of all stopped threads.  If specialThreadNumber
+     * is a valid thread number, then it will be continued past
+     * [continueCount] breakpoints instead of just 1 like all of the other
+     * threads.
+     **/
+    public static function continueThreads(specialThreadNumber : Int,
+                                           continueCount : Int)
+    {
+        untyped __global__.__hxcpp_dbg_continueThreads
+            (specialThreadNumber, continueCount);
+    }
+
+    /**
+     * Single steps the given thread.
+     **/
+    public static function stepThread(threadNumber : Int, 
+                                      stepType : Int,
+                                      stepCount : Int = 1)
+    {
+        untyped __global__.__hxcpp_dbg_stepThread
+            (threadNumber, stepType, stepCount);
+    }
+    
+    /**
+     * Returns the list of local variables (including "this", function
+     * arguments, and local variables) visible to the given thread at the
+     * given stack frame.
+     *
+     * Returns a list with a single entry, THREAD_NOT_STOPPED, if the
+     * thread is not stopped and thus variables cannot be fetched and
+     * unsafe is not true.
+     *
+     * @return the list of local variables (including "this", function
+     *         arguments, and local variables) visible to the given thread at
+     *         the given stack frame.
+     **/
+    public static function getStackVariables(threadNumber : Int,
+                                             stackFrameNumber : Int,
+                                             unsafe : Bool) : Array<String>
+    {
+        return untyped __global__.__hxcpp_dbg_getStackVariables
+            (threadNumber, stackFrameNumber, unsafe, THREAD_NOT_STOPPED);
+    }
+
+    /**
+     * Returns the value of a stack variable, or NONEXISTENT_VALUE if the
+     * requested value does not exist.  If the thread is actively running
+     * and unsafe is not true, returns THREAD_NOT_STOPPED.
+     **/
+    public static function getStackVariableValue(threadNumber : Int, 
+                                                 stackFrameNumber : Int,
+                                                 name : String,
+                                                 unsafe : Bool) : Dynamic
+    {
+        return untyped __global__.__hxcpp_dbg_getStackVariableValue
+            (threadNumber, stackFrameNumber, name, unsafe, NONEXISTENT_VALUE,
+             THREAD_NOT_STOPPED);
+    }
+
+    /**
+     * Sets the value of a stack variable and returns that value.  If the
+     * variable does not exist, on the stack, this function returns
+     * NONEXISTENT_VALUE.  If the thread is actively running and unsafe is not
+     * true, returns THREAD_NOT_STOPPED, and the value is not set.
+     **/
+    public static function setStackVariableValue(threadNumber : Int,
+                                                 stackFrameNumber : Int,
+                                                 name : String,
+                                                 value : Dynamic,
+                                                 unsafe : Bool) : Dynamic
+    {
+        return untyped __global__.__hxcpp_dbg_setStackVariableValue
+            (threadNumber, stackFrameNumber, name, value, unsafe,
+             NONEXISTENT_VALUE, THREAD_NOT_STOPPED);
+    }
+
+    // The hxcpp runtime calls back through these functions to create Haxe
+    // objects as needed, which allows the C++ implementation code to create
+    // Haxe objects without having to actually know the structure of those
+    // objects
+    private static function __init__()
+    {
+        untyped __global__.__hxcpp_dbg_setNewParameterFunction
+        (
+         function (name : String, value : Dynamic) : Dynamic {
+             return new Parameter(name, value);
+         }
+        );
+
+        untyped __global__.__hxcpp_dbg_setNewStackFrameFunction
+        (
+         function (fileName : String, lineNumber : Int,
+                   className : String, functionName : String)
+         {
+             return new StackFrame(fileName, lineNumber,
+                                   className, functionName);
+         }
+        );
+
+        untyped __global__.__hxcpp_dbg_setNewThreadInfoFunction
+        (
+         function (number : Int, status : Int, breakpoint : Int,
+                   criticalErrorDescription : String) : Dynamic {
+             return new ThreadInfo(number, status, breakpoint,
+                                   criticalErrorDescription);
+         }
+        );
+
+        untyped __global__.__hxcpp_dbg_setAddParameterToStackFrameFunction
+        (
+         function(inStackFrame : Dynamic, inParameter : Dynamic) {
+             var stackFrame : StackFrame = cast inStackFrame;
+             var parameter : Parameter = cast inParameter;
+             stackFrame.parameters.push(parameter);
+         }
+        );
+
+        untyped __global__.__hxcpp_dbg_setAddStackFrameToThreadInfoFunction
+        (
+         function(inThreadInfo : Dynamic, inStackFrame : Dynamic) {
+             var threadInfo : ThreadInfo = cast inThreadInfo;
+             var stackFrame : StackFrame = cast inStackFrame;
+             threadInfo.stack.push(stackFrame);
+   }
+        );
    }
 }