diff --git a/.travis.yml b/.travis.yml index a2810f6..612d83a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: haxe haxe: - development + - 3.4.2 - 3.2.1 os: @@ -9,9 +10,23 @@ os: - osx sudo: false +addons: + apt: + packages: + # C++ (for rebuilding hxcpp) + - gcc-multilib + - g++-multilib install: - - haxelib install hxcpp + - if [ "${TRAVIS_HAXE_VERSION}" = "development" ]; then + haxelib git hxcpp https://github.com/HaxeFoundation/hxcpp.git; + pushd $(haxelib path hxcpp | head -1); + pushd tools/hxcpp; haxe compile.hxml; popd; + pushd project; neko build.n; popd; + popd; + else + haxelib install hxcpp; + fi - haxelib dev hxcpp-debugger . - haxelib list diff --git a/Changes.md b/Changes.md index 4e2c66b..6d61e41 100644 --- a/Changes.md +++ b/Changes.md @@ -1,4 +1,10 @@ +1.2.0 +--------------- +* Switched to using arrays instead of lists for files, classes and variables. Lists have a problem when they grow too big and they become unusable. +* Bumped protocol version to 0.1.0. +1.1.0 +--------------- * Change haxelib.json license to MIT, which is in the same spirit as Apache from source code. 1.0 diff --git a/appveyor.yml b/appveyor.yml index a69c0c9..93301da 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,7 +6,7 @@ environment: install: # Install the haxe chocolatey package (https://chocolatey.org/packages/haxe) - - cinst haxe -version 3.2.1 -y + - cinst haxe -version 3.4.2 -y - RefreshEnv # Setup haxelib - mkdir "%HAXELIB_ROOT%" diff --git a/debugger/CommandLineController.hx b/debugger/CommandLineController.hx index 643cbd5..ce7e9d8 100644 --- a/debugger/CommandLineController.hx +++ b/debugger/CommandLineController.hx @@ -857,37 +857,27 @@ class CommandLineController implements IController // Utility functions and helpers ----------------------------------------- - private static function printStringList(list : StringList, sep : String) + private static function printStringList(list : StringArray, sep : String) { var need_sep = false; - while (true) { - switch (list) { - case Terminator: - break; - case Element(string, next): - if (need_sep) { - Sys.print(sep); - } - else { - need_sep = true; - } - Sys.print(string); - list = next; + for(string in list) { + if (need_sep) { + Sys.print(sep); } + else { + need_sep = true; + } + Sys.print(string); } } private static function printUnresolvableClasses( - unresolvableClasses : StringList) - { - switch (unresolvableClasses) { - case Terminator: - case Element(string, next): - Sys.print("Unresolvable classes: "); - printStringList(unresolvableClasses, ", "); - Sys.println("."); - } + unresolvableClasses : StringArray) + { + Sys.print("Unresolvable classes: "); + printStringList(unresolvableClasses, ", "); + Sys.println("."); } private static function findEndQuote(str : String, index : Int) : Int diff --git a/debugger/DebuggerThread.hx b/debugger/DebuggerThread.hx index 643b08e..5f8f147 100644 --- a/debugger/DebuggerThread.hx +++ b/debugger/DebuggerThread.hx @@ -314,34 +314,22 @@ class DebuggerThread mController.acceptMessage(message); } - private function filesToList(files:Array) : StringList - { - var list : StringList = Terminator; - - // Preserve order - for (f in 0...files.length) { - list = Element(files[files.length-1-f], list); - } - - return list; - } - private function files() : Message { // Preserve order to match filesFullPath - return Files( filesToList( Debugger.getFiles() ) ); + return Files( Debugger.getFiles() ); } private function filesFullPath() : Message { - return Files( filesToList( Debugger.getFilesFullPath() ) ); + return Files( Debugger.getFilesFullPath() ); } private function allClasses() : Message { var classes = Debugger.getClasses(); - var list : StringList = Terminator; + var list : StringArray = new StringArray(); // Sort the classes in reverse so that the list can be created easily classes.sort(function (a : String, b : String) { @@ -349,7 +337,7 @@ class DebuggerThread }); for (f in classes) { - list = Element(f, list); + list.push(f); } return AllClasses(list); @@ -389,13 +377,15 @@ class DebuggerThread return Reflect.compare(b, a); }); - var list : ClassList = ((continuation == null) ? - Terminator : Continued(continuation)); + var ca = new Array(); for (f in classes_to_use) { - list = Element(f, hasStaticValue(f), list); + var ce : ClassEnum = ClassFunction(f, hasStaticValue(f)); + ca.push(ce); } + var list : ClassList = ClassFunction(ca, continuation); + return Classes(list); } @@ -524,10 +514,10 @@ class DebuggerThread var breakpoint = mBreakpointsByDescription.get(desc); breakpoint.enable(); return ClassFunctionBreakpointNumber - (breakpoint.number, Terminator); + (breakpoint.number, null); } - var badClasses : StringList = Terminator; + var badClasses : StringArray = new StringArray(); var classNames = Debugger.getClasses(); for (cn in classNames) { @@ -553,7 +543,7 @@ class DebuggerThread } var klass = Type.resolveClass(cn); if (klass == null) { - badClasses = Element(cn, badClasses); + badClasses.push(cn); } else { this.breakFunction(desc, cn, klass, functionName, @@ -996,7 +986,7 @@ class DebuggerThread mStateMutex.release(); - var list : StringList = Terminator; + var list : StringArray = new StringArray(); // Sort the variables in reverse so that the list can be created easily variables.sort(function (a : String, b : String) { @@ -1004,7 +994,7 @@ class DebuggerThread }); for (f in variables) { - list = Element(f, list); + list.push(f); } return Variables(list); @@ -1232,6 +1222,8 @@ class DebuggerThread private class TypeHelpers { + private static inline var MAX_RECORD_AMOUNT = 100; + public static function getValueTypeName(value : Dynamic) : String { switch (Type.typeof(value)) { @@ -1272,8 +1264,9 @@ private class TypeHelpers return "INVALID"; } - public static function getValueString(value : Dynamic, indent : String = "", - ellipseForObjects : Bool = false) : String + public static function getValueString + (value : Dynamic, indent : String = "", + ellipseForObjects : Bool = false) : String { switch (Type.typeof(value)) { case TUnknown: @@ -1285,9 +1278,14 @@ private class TypeHelpers case TFunction: return Std.string(value); case TObject: - if (Std.is(value, Class)) { + var klass = null; + try { + klass = cast(value, Class); + } catch (e:Dynamic) { + } + if (klass != null) { return ("Class<" + Std.string(value) + ">" + - getClassValueString(value, indent)); + getClassValueString(klass, indent)); } if (ellipseForObjects) { return "..."; @@ -1295,12 +1293,12 @@ private class TypeHelpers var ret = "{\n"; for (f in Reflect.fields(value)) { ret += indent; + ret += f + ' : '; ret += getValueString(Reflect.field(value, f), indent + " ", ellipseForObjects); ret += "\n"; } return ret + indent + "}"; - case TClass(Array): var arr : Array = cast value; if (arr.length == 0) { @@ -1329,11 +1327,11 @@ private class TypeHelpers if (ellipseForObjects) { return "..."; } - var klass = Type.getClass(value); + var klass:Class = Type.getClass(value); if (klass == null) { return "???"; } - return getInstanceValueString(Type.getClass(value), value, indent); + return getInstanceValueString(klass, value, indent); } return Std.string(value); @@ -1382,32 +1380,36 @@ private class TypeHelpers for (f in fields) { var fieldValue = Reflect.getProperty(value, f); + ret += (indent + " " + f + " : " + getValueTypeName(fieldValue) + " = " + getValueString(fieldValue, indent + " ", true) + "\n"); } - fields = new Array(); - // Although the instance fields returned by Type seem to include super // class variables also, class variables do not, so iterate through // super classes manually while (klass != null) { + fields = new Array(); + for (f in Type.getClassFields(klass)) { - if (Reflect.isFunction(Reflect.field(value, f))) { + if (Reflect.isFunction(Reflect.field(klass, f))) { continue; } fields.push(f); } + + for (f in fields) { + var fieldValue = Reflect.getProperty(klass, f); + ret += (indent + " " + f + " : static " + + getValueTypeName(fieldValue) + " = " + + getValueString(fieldValue, indent + " ", true) + + "\n"); + } + klass = Type.getSuperClass(klass); } - for (f in fields) { - var fieldValue = Reflect.getProperty(value, f); - ret += (indent + " " + f + " : static " + - getValueTypeName(fieldValue) + " = " + - getValueString(fieldValue, indent + " ", true) + "\n"); - } return ret + indent + "}"; } @@ -1475,7 +1477,8 @@ private class TypeHelpers return className; } - private static function getClassFieldNames(value : Dynamic, klass : Class) + private static function getClassFieldNames(value : Dynamic, + klass : Class) : Array { // We walk the class hierarchy to find all statics. @@ -1519,8 +1522,9 @@ private class TypeHelpers var property : Dynamic = Reflect.getProperty(klass, f); if (null == property) { // Variable was inlined. - fieldValue = Single(getStructuredValueType(null), - Std.string("No instances (inlined)")); + fieldValue = Single + (getStructuredValueType(null), + Std.string("No instances (inlined)")); } else { fieldValue = getStructuredValue(property, true, @@ -1555,6 +1559,11 @@ private class TypeHelpers var subexp = expression + "[" + i + "]"; list = Element(Std.string(i), getStructuredValue(val, true, subexp), list); + // Skip items if too many + if (i > MAX_RECORD_AMOUNT) { + list = Element("...", Single(TypeNull, "..."), list); + i = MAX_RECORD_AMOUNT; + } i -= 1; } } @@ -2871,4 +2880,4 @@ private class DebugTimer { private var mLogLevel : Int; private var mStartTime : Float; private var mMessage: Dynamic; -} \ No newline at end of file +} diff --git a/debugger/HaxeProtocol.hx b/debugger/HaxeProtocol.hx index ad737ea..5ee1ff1 100644 --- a/debugger/HaxeProtocol.hx +++ b/debugger/HaxeProtocol.hx @@ -132,7 +132,7 @@ class HaxeProtocol } private static var gClientIdentification = - "Haxe debug client v1.1 coming at you!\n\n"; + "Haxe debug client v1.2 coming at you!\n\n"; private static var gServerIdentification = - "Haxe debug server v1.1 ready and willing, sir!\n\n"; + "Haxe debug server v1.2 ready and willing, sir!\n\n"; } diff --git a/debugger/HaxeRemote.hx b/debugger/HaxeRemote.hx index 29e5106..117a2c1 100644 --- a/debugger/HaxeRemote.hx +++ b/debugger/HaxeRemote.hx @@ -169,6 +169,7 @@ class HaxeRemote implements IController LogDebuggerMessage("Failed to connect to debugging server at " + mHost + ":" + mPort + " : " + e); } + closeSocket(); LogDebuggerMessage("Trying again in 3 seconds."); Sys.sleep(3); } diff --git a/debugger/HaxeServer.hx b/debugger/HaxeServer.hx index ae4d012..70d3cbb 100644 --- a/debugger/HaxeServer.hx +++ b/debugger/HaxeServer.hx @@ -73,7 +73,7 @@ class HaxeServer default: Sys.println("ERROR - invalid argument: " + argv[i]); Sys.println("Usage: HaxeServer [-host (defaults to " + - "local host name"); + "0.0.0.0 which means all local interfaces"); Sys.println(" [-port ] (defaults to " + "6972"); Sys.exit(-1); @@ -81,7 +81,7 @@ class HaxeServer } if (host == null) { - host = sys.net.Host.localhost(); + host = '0.0.0.0'; } new HaxeServer(new CommandLineController(), host, port); @@ -92,7 +92,7 @@ class HaxeServer /** * Creates a server. This function never returns. **/ - public function new(controller : CommandLineController, host : String, + public function new(controller : IController, host : String, port : Int) { mController = controller; @@ -139,8 +139,18 @@ class HaxeServer var peer = socket.peer(); Sys.println("\nReceived connection from " + peer.host + "."); - HaxeProtocol.writeServerIdentification(socket.output); - HaxeProtocol.readClientIdentification(socket.input); + try { + HaxeProtocol.writeServerIdentification(socket.output); + HaxeProtocol.readClientIdentification(socket.input); + } + catch (e : Dynamic) { + Sys.println("Client version not supported."); + Sys.println(e); + // Make sure the socket is being closed so that it doesn't hang + socket.close(); + // Rethrow the exception in case the calling code needs to know about it + throw(e); + } // Push the socket to the command thread to read from mSocketQueue.push(socket); @@ -215,7 +225,7 @@ class HaxeServer } } - private var mController : CommandLineController; + private var mController : IController; private var mSocketQueue : Deque; private var mCommandQueue : Deque; private var mReadCommandQueue : Deque; diff --git a/debugger/IController.hx b/debugger/IController.hx index 3e09137..000bf4e 100644 --- a/debugger/IController.hx +++ b/debugger/IController.hx @@ -162,30 +162,30 @@ enum Command // ErrorEvaluatingExpression } +/** + * An array of strings + **/ +typedef StringArray = Array; /** - * A list of strings + * An enum describing a class **/ -enum StringList +enum ClassEnum { - Terminator; - Element(string : String, next : StringList); + ClassFunction(className : String, hasStatics : Bool); } - /** - * A list of class, possibly truncated so as not to be too large. - * If truncated, a subsequent query for the remainder of the list can be done - * using the continued expression. + * An array of enums, possibly truncated so that it's not too large. + * If truncated, a subsequent query for the remainder of the array can be done + * using the nextIndex parameter that points to the next index of the original + * array containing the list of the classes. **/ enum ClassList { - Terminator; - Continued(continuation : String); - Element(className : String, hasStatics : Bool, next : ClassList); + ClassFunction(classArray : Array, nextIndex : String); } - /** * A list of breakpoints **/ @@ -344,7 +344,7 @@ enum Message ErrorBadClassNameRegex(details : String); ErrorBadFunctionNameRegex(details : String); ErrorNoMatchingFunctions(className : String, functionName : String, - unresolvableClasses : StringList); + unresolvableClasses : StringArray); ErrorBadCount(count : Int); ErrorCurrentThreadNotStopped(threadNumber : Int); ErrorEvaluatingExpression(details : String); @@ -353,8 +353,8 @@ enum Message OK; Exited; Detached; - Files(list : StringList); - AllClasses(list : StringList); + Files(list : StringArray); + AllClasses(list : StringArray); Classes(list : ClassList); MemBytes(bytes : Int); Compacted(bytesBefore : Int, bytesAfter : Int); @@ -363,12 +363,12 @@ enum Message functionName : String, fileName : String, lineNumber : Int); FileLineBreakpointNumber(number : Int); ClassFunctionBreakpointNumber(number : Int, - unresolvableClasses : StringList); + unresolvableClasses : StringArray); Breakpoints(list : BreakpointList); BreakpointDescription(number : Int, list : BreakpointLocationList); BreakpointStatuses(list : BreakpointStatusList); ThreadsWhere(list : ThreadWhereList); - Variables(list : StringList); + Variables(list : StringArray); Value(expression : String, type : String, value : String); Structured(structuredValue : StructuredValue); diff --git a/debugger/Version.hx b/debugger/Version.hx index fe49038..cb74f82 100644 --- a/debugger/Version.hx +++ b/debugger/Version.hx @@ -1,5 +1,5 @@ package debugger; class Version { - public static inline var name="0.0.0"; + public static inline var name="0.1.0"; } diff --git a/haxelib.json b/haxelib.json index ddc035b..1c73ac9 100644 --- a/haxelib.json +++ b/haxelib.json @@ -1,9 +1,9 @@ { "name" : "hxcpp-debugger", "license" : "Apache", - "version" : "1.1.0", + "version" : "1.2.0", "description" : "Haxe classes implementing a debugger interface to the cpp.vm.Debugger class", - "contributors" : [ "gamehaxe" ], + "contributors" : [ "gamehaxe", "tanis2000" ], "releasenote" : "See Changes.md", "dependencies" : { "hxcpp" : "" diff --git a/run-server.hxml b/run-server.hxml new file mode 100644 index 0000000..ad35d36 --- /dev/null +++ b/run-server.hxml @@ -0,0 +1,5 @@ +-cp . +-main debugger.HaxeServer +-neko bin/HaxeServer.n +-prompt +-cmd start neko bin/HaxeServer.n