github.com/tardisgo/tardisgo@v0.0.0-20161119180838-e0dd9a7e46b5/haxe/haxeRuntime.go (about)

     1  // Copyright 2014 Elliott Stoneham and The TARDIS Go Authors
     2  // Use of this source code is governed by an MIT-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package haxe
     6  
     7  // Runtime Haxe code for Go, which may eventually become a haxe library when the system settles down.
     8  // TODO All runtime class names are currently carried through if the haxe code uses "import tardis.Go;" and some are too generic,
     9  // others, like Int64, will overload the Haxe standard library version for some platforms, which may cause other problems.
    10  // So the haxe Class names eventually need to be prefaced with "Go" to ensure there are no name-clashes.
    11  // TODO using a library would reduce some of the compilation overhead of always re-compiling this code.
    12  // However, there are references to Go->Haxe generated classes, like "Go", that would need to be managed somehow.
    13  // TODO consider merging and possibly renaming the Deep and Force classes as they both hold general utility code
    14  
    15  func (l langType) haxeruntime() string {
    16  
    17  	l.PogoComp().WriteAsClass("Console", `
    18  
    19  class Console {
    20  	public static inline function naclWrite(v:String){
    21  		#if ( cpp || cs || java || neko || php || python )
    22  			Sys.print(v);
    23  		#else
    24  			haxe.Log.trace(v);
    25  		#end
    26  	}
    27  	public static inline function println(v:Array<Dynamic>) {
    28  		#if ( cpp || cs || java || neko || php || python )
    29  			Sys.println(join(v));
    30  		#else
    31  			haxe.Log.trace(join(v));
    32  		#end
    33  	}
    34  	public static inline function print(v:Array<Dynamic>) {
    35  		#if ( cpp || cs || java || neko || php || python )
    36  			Sys.print(join(v));
    37  		#else
    38  			haxe.Log.trace(join(v));
    39  		#end
    40  	}
    41  	static function join(v:Array<Dynamic>):String {
    42  		var s = "";
    43  		if(v==null) return s;
    44  		for (i in 0...v.length) {
    45  			if(v[i]==null) 
    46  				s += " ";
    47  			else
    48  				s += Std.string(v[i]) + " " ;
    49  		}
    50  		return Force.toHaxeString(s);
    51  	}
    52  	public static function readln():Null<String> {
    53  		#if (cpp || cs || java || neko || php )
    54  			var s:String="";
    55  			var ch:Int=0;
    56  			while(ch != 13 ){ // carrage return (mac)
    57  				ch = Sys.getChar(true);
    58  				//Sys.println(ch);
    59  				if(ch == 127){ // backspace (mac)
    60  					s = s.substr(0,s.length-1);
    61  					Sys.print("\n"+s);
    62  				}else{
    63  					s += String.fromCharCode(ch);
    64  				}
    65  			}
    66  			s = s.substr(0,s.length-1); // loose final CR
    67  			Sys.print("\n");
    68  			if(s.length==0)
    69  				return null;
    70  			else
    71  				return s;
    72  		#else
    73  			return null;
    74  		#end
    75  	}
    76  }
    77  
    78  `)
    79  	l.PogoComp().WriteAsClass("Force", `
    80  // TODO: consider putting these go-compatibiliy classes into a separate library for general Haxe use when calling Go
    81  
    82  class Force { // TODO maybe this should not be a separate haxe class, as no non-Go code needs access to it
    83  	public static inline function toUint8(v:Int): #if cpp cpp.UInt8 #else Int #end
    84  	{
    85  		#if cpp 
    86  			return v;
    87  		#elseif cs
    88  			return cast(cast(v,cs.StdTypes.UInt8),Int);
    89  		#else
    90  			return v & 0xFF;
    91  		#end
    92  	}	
    93  	public static inline function toUint16(v:Int): #if cpp cpp.UInt16 #else Int #end {
    94  		#if cpp 
    95  			return v; 
    96  		#elseif cs
    97  			return cast(cast(v,cs.StdTypes.UInt16),Int);
    98  		#else
    99  			return v & 0xFFFF;
   100  		#end
   101  	}	
   102  	public static inline function toUint32(v:Int):Int { 
   103  		#if js 
   104  			return v >>> untyped __js__("0"); // using GopherJS method (with workround to stop it being optimized away by Haxe)
   105  		#elseif php
   106         		return v & untyped __php__("0xffffffff");
   107  		#else
   108  			return v; 
   109  		#end
   110  	}	
   111  	public static inline function toUint64(v:GOint64):GOint64 {
   112  		return v;
   113  	}	
   114  	public static #if (cpp||java||cs) inline #end function toInt8(v:Int): #if cpp cpp.Int8 #else Int #end  {
   115  		#if cpp 
   116  			return v; 
   117  		#elseif java
   118  			return cast(cast(v,java.StdTypes.Int8),Int);
   119  		#elseif cs
   120  			return cast(cast(v,cs.StdTypes.Int8),Int);
   121  		#else
   122  			var r:Int = v & 0xFF;
   123  			if ((r & 0x80) != 0){ // it should be -ve
   124  				return -1 - 0xFF + r;
   125  			}
   126  			return r;
   127  		#end
   128  	}	
   129  	public static #if (cpp||java||cs) inline #end function toInt16(v:Int): #if cpp cpp.Int16 #else Int #end {
   130  		#if cpp 
   131  			return v; 
   132  		#elseif java
   133  			return cast(cast(v,java.StdTypes.Int16),Int);
   134  		#elseif cs
   135  			return cast(cast(v,cs.StdTypes.Int16),Int);
   136  		#else
   137  			var r:Int = v & 0xFFFF;
   138  			if ((r & 0x8000) != 0){ // it should be -ve
   139  				return -1 - 0xFFFF + r;
   140  			}
   141  			return r;
   142  		#end
   143  	}	
   144  	public static inline function toInt32(v:Int):Int {
   145  		#if js 
   146  			return v >> untyped __js__("0"); // using GopherJS method (with workround to stop it being optimized away by Haxe)
   147  		#elseif php
   148  			//see: http://stackoverflow.com/questions/300840/force-php-integer-overflow
   149       		v = (v & untyped __php__("0xFFFFFFFF"));
   150   		    if( (v & untyped __php__("0x80000000")) != 0)
   151  		        v = -((~v & untyped __php__("0xFFFFFFFF")) + 1);
   152  		    return v;
   153  		#else
   154  			return v;
   155  		#end
   156  	}	
   157  	public static inline function toInt64(v:GOint64):GOint64 { // this in case special handling is required for some platforms
   158  		return v;
   159  	}	
   160  	public static function toInt(v:Dynamic):Int { // get an Int from a Dynamic variable (uintptr is stored as Dynamic)
   161  		if(v==null) return 0;
   162  		if (Reflect.isObject(v)) 
   163  			if(Std.is(v,Interface)) {
   164  				v=v.val; 						// it is in an interface, so get the value
   165  				return toInt(v); 				// recurse to handle 64-bit or float or uintptr
   166  			} else								// it should be an Int64 if not an interface
   167  				if(Std.is(v,Pointer)) {
   168  					//Scheduler.panicFromHaxe("attempt to do Pointer arithmetic"); 
   169  					return v.hashInt();
   170  				}else
   171  					return GOint64.toInt(v);	// may never get here if GOint64 is an abstract
   172  		else
   173  			if(Std.is(v,Int))
   174  				return v;
   175  			else
   176  				if(Std.is(v,Float)) 			
   177  					return v>=0?Math.floor(v):Math.ceil(v);
   178  				else
   179  					if(haxe.Int64.is(v)) // detect the abstract
   180  						return haxe.Int64.toInt(v);
   181  					else
   182  						return cast(v,Int);	// default cast
   183  	}
   184  	public static inline function toFloat(v:Float):Float {
   185  		// neko target platform requires special handling because it auto-converts whole-number Float into Int without asking
   186  		// see: https://github.com/HaxeFoundation/haxe/issues/1282 which was marked as closed, but was not fixed as at 2013.9.6
   187  		// NOTE: this issue means that the neko/--interp is useless for testing anything math-based
   188  		#if neko
   189  			if(Std.is(v,Int)) {
   190  				return v + 2.2251e-308; // add the smallest value possible for a 64-bit float to ensure neko doesn't still think it is an int
   191  			} else
   192  				return v;
   193  		#else
   194  			return v;
   195  		#end
   196  	}	
   197  	#if (cpp || neko)
   198  		static public var f64byts = haxe.io.Bytes.alloc(8);
   199  	#elseif js  // NOTE this code uses js dataview even when not in fullunsafe mode
   200  		static private var f32dView = new js.html.DataView(new js.html.ArrayBuffer(8),0,8); 
   201  	#end
   202  	public static function toFloat32(v:Float):Float {
   203  		#if (cpp || neko)
   204  			f64byts.setFloat(0,v);
   205  			return f64byts.getFloat(0);
   206  		#elseif js 
   207  			f32dView.setFloat32(0,v); 
   208  			return f32dView.getFloat32(0); 
   209  		#elseif cs
   210  			return untyped __cs__("(double)((float)v)");
   211  		#elseif java
   212  			return untyped __java__("(double)((float)v)");
   213  		#else
   214  			if(Go.haxegoruntime_IInFF32fb.load_bool()) { // in the Float32frombits() function so don't recurse
   215  				return v;
   216  			} else {
   217  				return Go_haxegoruntime_FFloat32frombits.callFromRT(0,Go_haxegoruntime_FFloat32bits.callFromRT(0,v));
   218  			}
   219  		#end
   220  	}
   221  	// TODO implement speed improvements when code below is correct
   222  	//START POTENTIAL SPEED-UP CODE
   223  	/*
   224  	public static function Float32bits(v:Float):Int {
   225  		#if (cpp || neko)
   226  			f64byts.setFloat(0,v);
   227  			return toUint32( f64byts.get(0) | (f64byts.get(1)<<8)  | (f64byts.get(2)<<16)  | (f64byts.get(3)<<24) ); //little-endian
   228  		#elseif js 
   229  			f32dView.setFloat32(0,v); 
   230  			return toUint32(f32dView.getUint32(0)); 
   231  		#else
   232  			Scheduler.panicFromHaxe("Force.Float32bits unreachable code");
   233  			return 0; 
   234  		#end
   235  	}
   236  	public static function Float32frombits(v:Int):Float {
   237  		#if (cpp || neko)
   238  			f64byts.set(0,v&0xff);
   239  			f64byts.set(1,(v>>8)&0xff);
   240  			f64byts.set(2,(v>>16)&0xff);
   241  			f64byts.set(3,(v>>24)&0xff); //little-endian
   242  			return f64byts.getFloat(0);
   243  		#elseif js 
   244  			f32dView.setUint32(0,v);
   245  			return f32dView.getFloat32(0); 
   246  		#else
   247  			Scheduler.panicFromHaxe("Force.Float32frombits unreachable code"); 
   248  			return 0;
   249  		#end
   250  	}
   251  	*/
   252  	public static function Float64bits(v:Float):GOint64 {
   253  		#if cs
   254  			var rv:haxe.Int64 = untyped __cs__("System.BitConverter.DoubleToInt64Bits(v)");
   255  			return rv;
   256  		//#elseif (cpp || neko)
   257  		//	f64byts.setDouble(0,v);
   258  		//	return GOint64.make(
   259  		//		f64byts.get(4) | (f64byts.get(5)<<8)  | (f64byts.get(6)<<16)  | (f64byts.get(7)<<24) ,
   260  		//		f64byts.get(0) | (f64byts.get(1)<<8)  | (f64byts.get(2)<<16)  | (f64byts.get(3)<<24) ); //little-endian
   261  		//#elseif js 
   262  		//	f32dView.setFloat64(0,v); 
   263  		//	return GOint64.make(f32dView.getUint32(4),f32dView.getUint32(0)); 
   264  		#else
   265  			Scheduler.panicFromHaxe("Force.Float64bits unreachable code");
   266  			return GOint64.ofInt(0); 
   267  		#end
   268  	}
   269  	public static function Float64frombits(v:GOint64):Float {
   270  		#if cs
   271  			var hv:haxe.Int64=v;
   272  			return untyped __cs__("System.BitConverter.Int64BitsToDouble(hv)");
   273  		//#elseif (cpp || neko)
   274  		//	var v0 = GOint64.getLow(v);
   275  		//	var v1 = GOint64.getHigh(v);
   276  		//	f64byts.set(0,v0&0xff);
   277  		//	f64byts.set(1,(v0>>8)&0xff);
   278  		//	f64byts.set(2,(v0>>16)&0xff);
   279  		//	f64byts.set(3,(v0>>24)&0xff); //little-endian
   280  		//	f64byts.set(4,v1&0xff);
   281  		//	f64byts.set(5,(v1>>8)&0xff);
   282  		//	f64byts.set(6,(v1>>16)&0xff);
   283  		//	f64byts.set(7,(v1>>24)&0xff); //little-endian
   284  		//	return f64byts.getDouble(0);
   285  		//#elseif js 
   286  		//	f32dView.setUint32(0,GOint64.getLow(v));
   287  		//	f32dView.setUint32(4,GOint64.getHigh(v));
   288  		//	return f32dView.getFloat64(0); 
   289  		#else
   290  			Scheduler.panicFromHaxe("Force.Float64frombits unreachable code"); 
   291  			return 0;
   292  		#end
   293  	}
   294  	//END POTENTIAL SPEED-UP CODE
   295  	//
   296  	public static function uintCompare(x:Int,y:Int):Int { // +ve if uint(x)>unint(y), 0 equal, else -ve 
   297  		#if js x=x>>>untyped __js__("0");y=y>>>untyped __js__("0"); #end
   298  		if(x==y) return 0; // simple case first for speed TODO is it faster with this in or out?
   299  		if(x>=0) {
   300  			if(y>=0){ // both +ve so normal comparison
   301  				return (x-y);
   302  			}else{ // y -ve and so larger than x
   303  				return -1;
   304  			}
   305  		}else { // x -ve
   306  			if(y>=0){ // -ve x larger than +ve y
   307  				return 1;
   308  			}else{ // both are -ve so the normal comparison
   309  				return (x-y); //eg -1::-7 gives -1--7 = +6 meaning -1 > -7
   310  			}
   311  		}
   312  	}
   313  	private static function checkIntDiv(x:Int,y:Int,byts:Int):Int { // implement the special processing required by Go
   314  		var r:Int=y;
   315  		switch(y) {
   316  		case 0:
   317  			Scheduler.panicFromHaxe("attempt to divide integer value by 0"); 
   318  		case -1:
   319  			switch (byts) {
   320  			case 1:
   321  				if(x== -128) r=1; // special case in the Go spec
   322  			case 2:
   323  				if(x== -32768) r=1; // special case in the Go spec
   324   			case 4:
   325  				if(x== -2147483648) r=1; // special case in the Go spec
   326  			default:
   327  				// noOp - 0 => unsigned
   328  			}
   329  		}
   330  		return r;
   331  	}
   332  	//TODO maybe optimize by not passing the special value and having multiple versions of functions
   333  	public static function intDiv(x:Int,y:Int,sv:Int):Int {
   334  		y = checkIntDiv(x,y,sv);
   335  		if(y==1) return x; // x div 1 is x
   336  		if((sv>0)||((x>0)&&(y>0))){ // signed division will work (even though it may be unsigned)
   337  			var f:Float=  cast(x,Float) / cast(y,Float);
   338  			return f>=0?Math.floor(f):Math.ceil(f);
   339  		} else { // unsigned division 
   340  			return toUint32(GOint64.toInt(GOint64.div(GOint64.make(0x0,x),GOint64.make(0x0,y),false)));
   341  		}
   342  	}
   343  	public static function intMod(x:Int,y:Int,sv:Int):Int {
   344  		y = checkIntDiv(x,y,sv);
   345  		if(y==1) return 0; // x mod 1 is 0
   346  		if((sv>0)||((x>0)&&(y>0))){ // signed mod will work (even though it may be unsigned)
   347  			return x % y;
   348  		} else { // unsigned mod (do it in 64 bits to ensure unsigned)
   349  			return toUint32(GOint64.toInt(GOint64.mod(GOint64.make(0x0,x),GOint64.make(0x0,y),false)));
   350  		}
   351  	}
   352  	public static inline function intMul(x:Int,y:Int,sv:Int):Int { // TODO optimize away sv
   353  		#if (js || php)
   354  			if(sv>0){ // signed mul
   355  				return  x*y; //toInt32(GOint64.toInt(GOint64.mul(GOint64.ofInt(x),GOint64.ofInt(y)))); // TODO review if this required
   356  			} else { // unsigned mul 
   357  				return toUint32(GOint64.toInt(GOint64.mul(GOint64.ofUInt(x),GOint64.ofUInt(y)))); // required for overflowing mul
   358  			}
   359  		#else
   360  			return x * y;
   361  		#end
   362  	}
   363  	public static var minusZero:Float= 1.0 / Math.NEGATIVE_INFINITY ; 
   364  	private static var zero:Float=0.0;
   365  	private static var MinFloat64:Float = -1.797693134862315708145274237317043567981e+308; // 2**1023 * (2**53 - 1) / 2**52
   366  	public static #if !php  inline #end function floatDiv(x:Float,y:Float):Float {
   367  		#if ( php ) 
   368  			// NOTE for php 0 != 0.0 !!!
   369  			if(y==0) // divide by zero gives +/- infinity - so valid ... TODO check back to Go spec
   370  				if(x==0) 
   371  					return Math.NaN; // NaN +/-
   372  				else
   373  					if(x>0) return Math.POSITIVE_INFINITY;
   374  					else return Math.NEGATIVE_INFINITY;
   375  			if(x==0)
   376  				if(y>0) return 0; // x==y==0.0 already handled above
   377  				else return minusZero; // should be -0
   378  		#end
   379  		return x/y;
   380  	}
   381  	public static function floatMod(x:Float,y:Float):Float {
   382  		if(y==0.0)
   383  			Scheduler.panicFromHaxe("attempt to modulo float value by 0"); 
   384  		#if ( php  ) 
   385  			if(x==0)
   386  				if(y>=0) return x; // to allow for -0
   387  				else return return zero * -1; // should be -0
   388  		#end
   389  		return x%y;
   390  	}
   391  
   392  	public static inline function toUTF8length(gr:Int,s:String):Int {
   393  		return s.length;
   394  	}
   395  	// return the UTF8 version of a string in a Slice
   396  	public static function toUTF8slice(gr:Int,s:String):Slice { // TODO remove gr param
   397  		var sl=s.length;
   398  		var obj = Object.make(sl);
   399  		for(i in 0...sl) {
   400  			#if (js || php || neko ) // nullable targets
   401  				var t:Null<Int>=s.charCodeAt(i);
   402  				if(t==null) t=0;
   403  				obj.set_uint8(i,t);
   404  			#else
   405  				obj.set_uint8(i,s.charCodeAt(i));
   406  			#end
   407  		}
   408  		var ptr = Pointer.make(obj);
   409  		var ret = new Slice(ptr,0,-1,sl,1);
   410  		#if nulltempvars
   411  			ptr=null; obj=null; // for GC
   412  		#end
   413  		return ret;
   414  	}
   415  	public static function toRawString(gr:Int,sl:Slice):String { // TODO remove gr param
   416  		if(sl==null) return "";
   417  		var sll=sl.len();
   418  		if(sll==0) return "";
   419  		var ptr = sl.itemAddr(0); // pointer to the start of the slice
   420  		var obj = ptr.obj; // the object containing the slice data
   421  		var off = ptr.off; // the offset to the start of that data
   422  		var end = sll+off;
   423  		#if cpp
   424  			var buf=haxe.io.Bytes.alloc(sll);
   425  			for( i in off...end) {
   426  				buf.set(i-off,obj.get_uint8(i));
   427  			}
   428  			var ret=buf.getString(0,sll);
   429  			#if nulltempvars
   430  				buf=null;
   431  				ptr=null;
   432  				obj=null;
   433  			#end
   434  			return ret;
   435  		#else
   436  			// very slow for cpp:
   437  			var ret = new StringBuf(); // use StringBuf for speed
   438  			for( i in off...end ) {
   439  				ret.addChar( obj.get_uint8(i) );
   440  			}
   441  			var s=ret.toString();
   442  			#if nulltempvars
   443  				ptr=null;
   444  				obj=null;
   445  				ret=null;
   446  			#end
   447  			return s;
   448  		#end
   449  	}
   450  
   451  	public static function toHaxeParam(v:Dynamic):Dynamic { // TODO optimize if we know it is a function or string
   452  		if(v==null) return null;
   453  		if(Std.is(v,Interface)){
   454  			if(Std.is(v.val,Closure) && v.typ!=-1){ // a closure not made by hx.CallbackFunc
   455  				return v.val.buildCallbackFn();
   456  			}else{
   457  				v = v.val;
   458  				return toHaxeParam(v);
   459  			}
   460  		}
   461  		if(Std.is(v,String)){
   462  			v=toHaxeString(v);
   463  		}
   464  		// TODO !
   465  		//if(GOint64.is(v)) { 
   466  		//	v=cast(v,haxe.Int64);
   467  		//}
   468  		return v;
   469  	}
   470  	
   471  	public static #if (cpp || neko || php) inline #end function toHaxeString(v:String):String {
   472  		#if !( cpp || neko || php ) // need to translate back to UTF16 when passing back to Haxe
   473  			#if js if(v==null) return ""; #end 
   474  			if(v.length==0) return "";
   475  			var sli:Slice=new Slice(Pointer.make(Object.make(v.length)),0,-1,v.length,1);
   476  			var ptr:Pointer=null;
   477  			var ch:Int=0;
   478  			for(i in 0...v.length){
   479  				//if(v.charCodeAt(i)>0xff) return v; // probably already encoded as UTF-16
   480  				ptr=sli.itemAddr(i);
   481  				ch=v.charCodeAt(i);
   482  				//trace("DEBUG toHaxeString utf8 in=",i,ch);
   483  				ptr.store_uint8(ch);
   484  			}
   485  			//trace("DEBUG sli=",sli);
   486  			var slr = Go_haxegoruntime_UUTTFF8toRRunes.callFromRT(0,sli);
   487  			//trace("DEBUG slr=",slr);
   488  			var slo = Go_haxegoruntime_RRunesTToUUTTFF16.callFromRT(0,slr);
   489  			//trace("DEBUG slo=",slo);
   490  			v=""; 
   491  			for(i in 0...slo.len()) {
   492  				ptr = slo.itemAddr(i);
   493  				ch = ptr.load_uint16();
   494  				//trace("DEBUG toHaxeString utf16 out=",i,ptr,ch);
   495  				v += String.fromCharCode( ch );
   496  			}
   497  			#if nulltempvars
   498  				ptr=null;
   499  				slr=null;
   500  				slo=null;
   501  			#end
   502  		#end
   503  		return v;
   504  	}
   505  
   506  	public static #if (cpp || neko || php) inline #end function fromHaxeString(v:String):String {
   507  		#if !( cpp || neko || php ) // need to translate from UTF16 to UTF8 when passing back to Go
   508  			#if (js || php) if(v==null) return ""; #end
   509  			var sli:Slice=new Slice(Pointer.make(Object.make(v.length<<1)),0,-1,v.length,2);
   510  			var ptr:Pointer;
   511  			for(i in 0...v.length){
   512  				ptr=sli.itemAddr(i);
   513  				ptr.store_uint16(v.charCodeAt(i));
   514  			}
   515  			var slr = Go_haxegoruntime_UUTTFF16toRRunes.callFromRT(0,sli);
   516  			var slo = Go_haxegoruntime_RRunesTToUUTTFF8.callFromRT(0,slr);
   517  			v="";
   518  			for(i in 0...slo.len()) {
   519  				ptr=slo.itemAddr(i);
   520  				v += String.fromCharCode( ptr.load_uint8() );
   521  			}
   522  			#if nulltempvars
   523  				ptr=null;
   524  				slr=null;
   525  				slo=null;
   526  			#end
   527  		#end
   528  		return v;
   529  	}
   530  
   531  	public static function checkTuple(t:Dynamic):Dynamic {
   532  		if(t==null) Scheduler.panicFromHaxe("tuple returned from function or range is null");
   533  		return t;
   534  	}
   535  
   536  	public static function stringAt(s:String,i:Int):Int{
   537  		var c = s.charCodeAt(i);
   538  		if(c==null) 
   539  			Scheduler.panicFromHaxe("string index out of range");
   540  		return toUint8(c);
   541  	}
   542  	public static function stringAtOK(s:String,i:Int):Dynamic {
   543  		var c = s.charCodeAt(i);
   544  		if(c==null)
   545  			return {r0:0,r1:false};
   546  		else 
   547  			return {r0:toUint8(c),r1:true};
   548  	}
   549  	public static function isEqualDynamic(a:Dynamic,b:Dynamic):Bool{
   550  		if(a==b) 
   551  			return true; // simple equality
   552  		if(Reflect.isObject(a) && Reflect.isObject(b)){
   553  			if(Std.is(a,String) && Std.is(b,String))
   554  				return a==b;
   555  			if(Std.is(a,Pointer) && Std.is(b,Pointer))
   556  				return Pointer.isEqual(a,b); // could still be equal within a Pointer type     
   557  			if(Std.is(a,Complex) && Std.is(b,Complex))
   558  				return Complex.eq(a,b);
   559  			if(Std.is(a,Interface) && Std.is(b,Interface))
   560  				return Interface.isEqual(a,b); // interfaces   
   561  			#if !abstractobjects
   562  			if(Std.is(a,Object) && Std.is(b,Object))
   563  				return a.isEqual(0,b,0);
   564  			#end
   565  
   566  			if(Std.is(a,GOmap)||Std.is(a,Closure)||Std.is(a,Slice)||Std.is(a,Channel)) {
   567  				Scheduler.panicFromHaxe("Unsupported isEqualDynamic haxe type:"+a);
   568  				return false; // never equal
   569  			}
   570  	  
   571  			// assume GOint64 - Std.is() does not work for abstract types
   572  			return GOint64.compare(a,b)==0;
   573  		}
   574  		if(Std.is(a,Float)&&Std.is(b,Float)){
   575  			return GOint64.compare(
   576  				Go_haxegoruntime_FFloat64bits.callFromRT(0,a),
   577  				Go_haxegoruntime_FFloat64bits.callFromRT(0,b))==0;
   578  		}
   579  		return false;	
   580  	}
   581  	public static function stringFromRune(rune:Int):String{
   582  		var _ret:String="";
   583  		var _r:Slice=Go_haxegoruntime_RRune2RRaw.callFromRT(0,rune);
   584  		var _ptr:Pointer;
   585  		var rl=_r.len();
   586  		for(_i in 0...rl){
   587  			_ptr=_r.itemAddr(_i);
   588  			_ret+=String.fromCharCode(_ptr.load_int32());
   589  		}
   590  		#if nulltempvars
   591  			_ptr=null;
   592  			_r=null;
   593  		#end
   594  		return	_ret;
   595  	}
   596  }
   597  `)
   598  	objClass := `
   599  
   600  // Object code
   601  // a single type of Go object
   602  @:keep
   603  #if abstractobjects
   604  abstract Object (haxe.ds.Vector<Dynamic>) to haxe.ds.Vector<Dynamic> from haxe.ds.Vector<Dynamic> {
   605  #else
   606  class Object { 
   607  #end
   608  	public static inline function make(size:Int,?byts:haxe.io.Bytes):Object {
   609  		#if abstractobjects
   610  			var ret = new haxe.ds.Vector<Dynamic>(size);
   611  			if(byts!=null){ 
   612  				for(i in 0 ... byts.length) ret[i] = byts.get(i);
   613  			}
   614  			return ret;
   615  		#else
   616  			return new Object(size,byts);
   617  		#end
   618  	}
   619  
   620  	#if ((js || cpp || neko) && fullunsafe) 
   621  		public static var nativeFloats:Bool=true; 
   622  	#else
   623  		public static var nativeFloats:Bool=false; 	
   624  	#end
   625  
   626  #if abstractobjects
   627  	public var length(get, never):Int;
   628  	function get_length() return this.length;
   629  	public inline function len():Int {
   630  		return length;
   631  	}
   632  	public inline function uniqueRef():Int {
   633  		Console.naclWrite("uniqueRef!\n");
   634  		return 0; // TODO
   635  	}
   636  #else
   637  	private var dVec4:haxe.ds.Vector<Dynamic>; // on 4-byte boundaries 
   638  	#if (js && fullunsafe) // native memory access (nearly)
   639  		private var arrayBuffer:js.html.ArrayBuffer;
   640  		private var dView:js.html.DataView;
   641  	#elseif !fullunsafe	// Simple! 1 address per byte, non-Int types are always on 4-byte
   642  		private var iVec:haxe.ds.Vector<Int>; 
   643  	#else // fullunsafe position is to allow unsafe pointers, and therefore run slowly...
   644  		private var byts:haxe.io.Bytes;
   645  	#end
   646  	public inline function len():Int {
   647  		return length;
   648  	}
   649  	private var length:Int;
   650  	public inline function uniqueRef():Int {
   651  		return uRef;
   652  	}
   653  	private var uRef:Int; // to give pointers a unique numerical value
   654  #end
   655  	private static var uniqueCount:Int=0;
   656  	#if godebug
   657  		public static var memory = new Map<Int,Object>();
   658  	#end
   659  
   660  #if abstractobjects
   661    	inline public function new(v:haxe.ds.Vector<Dynamic>) {
   662      	this = v;
   663    	}
   664  #else
   665  	public function new(byteSize:Int,?bytes:haxe.io.Bytes){ // size is in bytes
   666  		dVec4 = new haxe.ds.Vector<Dynamic>(1+(byteSize>>2)); // +1 to make sure non-zero
   667  		if(bytes!=null) byteSize = bytes.length;
   668  		#if (js && fullunsafe)
   669  			arrayBuffer = new js.html.ArrayBuffer(byteSize);
   670  			if(byteSize>0)
   671  				dView = new js.html.DataView(arrayBuffer,0,byteSize); // complains if size is 0, TODO review
   672  			if(bytes!=null)
   673  				for(i in 0 ... byteSize) 
   674  					set_uint8(i, bytes.get(i));
   675  		#elseif !fullunsafe
   676  			iVec = new haxe.ds.Vector<Int>(byteSize);
   677  			if(bytes!=null)
   678  				for(i in 0 ... byteSize) 
   679  					iVec[i] = bytes.get(i);
   680  		#else
   681  			if(bytes==null)	{
   682  				byts = haxe.io.Bytes.alloc(byteSize);
   683  				//byts.fill(0,byteSize,0); 
   684  			} else byts = bytes;
   685  		#end
   686  		length = byteSize;
   687  		uniqueCount += 1;
   688  		uRef = uniqueCount;
   689  		#if godebug
   690  			memory.set(uniqueRef(),this);
   691  		#end
   692  		#if nonulltests
   693  			#if (js || php || neko ) 
   694  				for(i in 0...length)
   695  					set_uint8(i,0); 
   696  			#end
   697  		#end
   698  	}
   699  #end
   700  	public function getBytes():haxe.io.Bytes {
   701  		#if (js && fullunsafe)
   702  			var byts = haxe.io.Bytes.alloc(length);
   703  			for(i in 0 ... length) 
   704  				byts.set(i,get_uint8(i));
   705  		#elseif abstractobjects
   706  			var byts = haxe.io.Bytes.alloc(this.length);
   707  			for(i in 0 ... this.length) 
   708  				byts.set(i,this[i]);
   709  		#elseif !fullunsafe
   710  			var byts = haxe.io.Bytes.alloc(length);
   711  			for(i in 0 ... length) 
   712  				byts.set(i,iVec[i]);
   713  		#else
   714  			// the byts field already exists
   715  		#end
   716  		return byts;
   717  	}
   718  	public function clear():Object {
   719  		for(i in 0...this.length){
   720  			set_uint8(i,0);
   721  			if(i&3==0) set(i,null);
   722  		}
   723  		return this; // to allow use without a temp var
   724  	}
   725  	public function isEqual(off:Int,target:Object,tgtOff:Int):Bool { // TODO check if correct, used by interface{} value comparison
   726  		if((this.length-off)!=(target.len()-tgtOff)) return false;
   727  		for(i in 0...(this.length-off)) {
   728  			if((i+off)&3==0){
   729  				var a:Dynamic=this.get(i+off);
   730  				var b:Dynamic=target.get(i+tgtOff);
   731  				if(!Force.isEqualDynamic(a,b)) return false;
   732  			}
   733   			#if fullunsafe
   734  				if(this.get_uint8(i+off)!=target.get_uint8(i+tgtOff))
   735  					return false;
   736   			#elseif abstractobjects
   737   				var ths=this.get(i+off);
   738   				var tgt=target.get(i+tgtOff);
   739  				if(ths!=tgt) 
   740  					if(ths==null)
   741  						if(Std.is(tgt,Int))
   742  							return cast(tgt,Int)!=0;
   743  						else
   744  							if(Std.is(tgt,Float))
   745  								return cast(tgt,Float)!=0;
   746  							else
   747  								if(Std.is(tgt,Bool))
   748  									return cast(tgt,Bool)!=false;
   749  								else
   750  									return false;
   751  					else
   752  						if(tgt==null)
   753  							if(Std.is(ths,Int))
   754  								return cast(ths,Int)!=0;
   755  							else
   756  								if(Std.is(ths,Float))
   757  									return cast(ths,Float)!=0;
   758  								else
   759  									if(Std.is(ths,Bool))
   760  										return cast(ths,Bool)!=false;
   761  									else
   762  										return false;
   763  						else
   764  							return false;
   765  			#else
   766  				if(this.get_uint32(i+off)!=target.get_uint32(i+tgtOff))
   767  					return false;
   768  			#end
   769  		}
   770  		return true;
   771  	}
   772  	public static function objBlit(src:Object,srcPos:Int,dest:Object,destPos:Int,size:Int):Void{
   773  		if(size>0&&src!=null) {
   774  `
   775  	if l.PogoComp().DebugFlag {
   776  		objClass += `
   777  		#if !abstractobjects
   778  			if(!Std.is(src,Object)) { 
   779  				Scheduler.panicFromHaxe("Object.objBlt() src parameter is not an Object - Value: "+Std.string(src)+" Type: "+Type.typeof(src));
   780  				return;
   781  			}
   782  			if(!Std.is(dest,Object)) { 
   783  				Scheduler.panicFromHaxe("Object.objBlt() dest parameter is not an Object - Value: "+Std.string(dest)+" Type: "+Type.typeof(dest));
   784  				return;
   785  			}
   786  		#end
   787  		if(srcPos<0 || srcPos>=src.length){
   788  			Scheduler.panicFromHaxe("Object.objBlt() srcPos out-of-range - Value= "+Std.string(srcPos)+
   789  				" src.length= "+Std.string(src.length));
   790  			return;			
   791  		}
   792  		if(destPos<0 || destPos>=dest.length){
   793  			Scheduler.panicFromHaxe("Object.objBlt() destPos out-of-range - Value= "+Std.string(destPos)+
   794  				" dest.length= "+Std.string(dest.length));
   795  			return;			
   796  		}
   797  		//if(size>(src.length-srcPos) ) size = src.length-srcPos ; // TODO review why this defensive code is needed
   798  		if(size<0 || size > (dest.length-destPos) || size>(src.length-srcPos) ) {
   799  			Scheduler.panicFromHaxe("Object.objBlt() size out-of-range - Value: "+Std.string(size)+
   800  				" DestSize: "+Std.string(dest.length-destPos)+
   801  				" SrcSize: "+Std.string(src.length-srcPos));
   802  			return;			
   803  		}
   804  `
   805  	} else {
   806  		/*objClass += `
   807  		if(size>(src.length-srcPos) ) size = src.length-srcPos ; // TODO review why this defensive code is needed
   808  		`*/
   809  	}
   810  	objClass += `
   811  		#if fullunsafe //(js && fullunsafe)
   812  			if((size&3==0)&&(srcPos&3==0)&&(destPos&3==0)) {
   813  				var i:Int=0;
   814  				var s:Int=srcPos;
   815  				var d:Int=destPos;
   816  				while(i<size){
   817  					dest.set_uint32(d,src.get_uint32(s)); 
   818  					dest.set(d,src.get(s));
   819  					i+=4;
   820  					s+=4;
   821  					d+=4;
   822  				}
   823  			}
   824  			else{
   825  				var s:Int=srcPos;
   826  				var d:Int=destPos;
   827  				for(i in 0...size) {
   828  					dest.set_uint8(d,src.get_uint8(s));
   829  					if(((size-i)>3)&&(s&3)==0){ 
   830  						dest.set(d,src.get(s));
   831  					}
   832  					s+=1;
   833  					d+=1;
   834  				}
   835  			}
   836  		#elseif abstractobjects
   837  			haxe.ds.Vector.blit(src,srcPos, dest, destPos, size); 
   838  		#else //if !fullunsafe
   839  			if((size>>2)>0)
   840  				haxe.ds.Vector.blit(src.dVec4,srcPos>>2, dest.dVec4, destPos>>2, size>>2); 
   841  			haxe.ds.Vector.blit(src.iVec,srcPos, dest.iVec, destPos, size); 
   842  		#end
   843  		} // end of: if(size>0&&src!=null) {
   844  	}
   845  	public inline function get_object(size:Int,from:Int):Object { // TODO SubObj class that is effectively a pointer?
   846  		var so:Object = make(size);
   847  		objBlit(this,from, so, 0, size); 
   848  		return so;
   849  	}
   850  	public inline function set_object(size:Int, to:Int, from:Object):Void {
   851  		//#if php
   852  		//	if(!Std.is(from,Object)) { 
   853  		//		Scheduler.panicFromHaxe("Object.set_object() from parameter is not an Object - Value: "+Std.string(from)+" Type: "+Type.typeof(from));
   854  		//		return; // treat as null object (seen examples have been integer 0)
   855  		//	}
   856  		//#end
   857  		objBlit(from,0,this,to,size);
   858  	}
   859  	public inline function copy():Object{
   860  		return get_object(len(),0);
   861  	}
   862  	public inline function get(i:Int):Dynamic {
   863  		#if abstractobjects
   864  			return this[i];
   865  		#else
   866  			return dVec4[i>>2];
   867  		#end
   868  	}
   869  	public inline function get_bool(i:Int):Bool { 
   870  		#if (js && fullunsafe)
   871  			return dView.getUint8(i)==0?false:true;
   872  		#elseif abstractobjects
   873  			if(this[i]==null) return false; 
   874  			return this[i];
   875  		#elseif !fullunsafe
   876  			var r:Int=iVec[i]; 
   877  			#if (js || php || neko ) 
   878  				return r==null?false:(r==0?false:true); 
   879  			#else 
   880  				return r==0?false:true; 
   881  			#end
   882  		#else
   883  			return byts.get(i)==0?false:true;
   884  		#end
   885  	}
   886  	public inline function get_int8(i:Int):Int { 
   887  		#if (js && fullunsafe)
   888  			return dView.getInt8(i);
   889  		#elseif abstractobjects
   890  			#if (js || php || neko ) return this[i]==null?0:0|this[i]; #else return this[i]; #end
   891  		#elseif !fullunsafe
   892  			#if ((js || php || neko )&&!nonulltests) return iVec[i]==null?0:0|iVec[i]; #else return iVec[i]; #end
   893  		#else
   894  			return Force.toInt8(byts.get(i));
   895  		#end
   896  	}
   897  	public inline function get_int16(i:Int):Int { 
   898  		#if (js && fullunsafe)
   899  			return dView.getInt16(i,true); // little-endian
   900  		#elseif abstractobjects
   901  			#if (js || php || neko ) return this[i]==null?0:0|this[i]; #else return this[i]; #end
   902  		#elseif !fullunsafe
   903  			#if ((js || php || neko )&&!nonulltests) return iVec[i]==null?0:0|iVec[i]; #else return iVec[i]; #end
   904  		#else
   905  			return Force.toInt16((get_uint8(i+1)<<8)|get_uint8(i)); // little end 1st
   906  		#end
   907  	}
   908  	public inline function get_int32(i:Int):Int {
   909  		#if (js && fullunsafe)
   910  			return dView.getInt32(i,true); // little-endian
   911  		#elseif abstractobjects
   912  			#if (js || php || neko ) return this[i]==null?0:0|this[i]; #else return this[i]; #end
   913  		#elseif !fullunsafe
   914  			#if ((js || php || neko )&&!nonulltests) return iVec[i]==null?0:0|iVec[i]; #else return iVec[i]; #end
   915  		#else
   916  			return Force.toInt32((get_uint16(i+2)<<16)|get_uint16(i)); // little end 1st			
   917  		#end
   918  	}
   919  	public inline function get_int64(i:Int):GOint64 {
   920  		#if !fullunsafe
   921  			if(get(i)==null) return GOint64.ofInt(0);	
   922  			return get(i); 
   923  		#else
   924  			return Force.toInt64(GOint64.make(get_uint32(i+4),get_uint32(i)));
   925  		#end
   926  	} 
   927  	public inline function get_uint8(i:Int):Int { 
   928  		#if (js && fullunsafe)
   929  			return dView.getUint8(i);
   930  		#elseif abstractobjects
   931  			#if (js || php || neko ) return this[i]==null?0:0|this[i]; #else return this[i]; #end
   932  		#elseif !fullunsafe
   933  			#if ((js || php || neko )&&!nonulltests) return iVec[i]==null?0:0|iVec[i]; #else return iVec[i]; #end
   934  		#else 
   935  			return Force.toUint8(byts.get(i));
   936  		#end
   937  	}
   938  	public inline function get_uint16(i:Int):Int {
   939  		#if (js && fullunsafe)
   940  			return dView.getUint16(i,true); // little-endian
   941  		#elseif abstractobjects
   942  			#if (js || php || neko ) return this[i]==null?0:0|this[i]; #else return this[i]; #end
   943  		#elseif !fullunsafe
   944  			#if ((js || php || neko )&&!nonulltests) return iVec[i]==null?0:0|iVec[i]; #else return iVec[i]; #end
   945  		#else
   946  			return Force.toUint16((get_uint8(i+1)<<8)|get_uint8(i)); // little end 1st
   947  		#end
   948  	}
   949  	public inline function get_uint32(i:Int):Int {
   950  		#if (js && fullunsafe)
   951  			return dView.getUint32(i,true); // little-endian
   952  		#elseif abstractobjects
   953  			#if (js || php || neko ) return this[i]==null?0:0|this[i]; #else return this[i]; #end
   954  		#elseif !fullunsafe
   955  			#if ((js || php || neko )&&!nonulltests) return iVec[i]==null?0:0|iVec[i]; #else return iVec[i]; #end
   956  		#else
   957  			return Force.toUint32((get_uint16(i+2)<<16)|get_uint16(i)); // little end 1st
   958  		#end
   959  	}
   960  	public inline function get_uint64(i:Int):GOint64 { 
   961  		#if !fullunsafe
   962  			if(get(i)==null) return GOint64.ofInt(0); 
   963  			return get(i); 
   964  		#else
   965  			return Force.toUint64(GOint64.make(get_uint32(i+4),get_uint32(i)));
   966  		#end
   967  	} 
   968  	public inline function get_uintptr(i:Int):Dynamic { // uintptr holds Haxe objects
   969  		// TODO consider some type of read-from-mem if Dynamic type is Int 
   970  		return get(i); 
   971  	} 
   972  	public inline function get_float32(i:Int):Float { 
   973  		#if (js && fullunsafe)
   974  			return dView.getFloat32(i,true); // little-endian
   975  		#elseif !fullunsafe
   976  			return get(i)==null?0.0:get(i); 
   977  		#else 
   978  			return byts.getFloat(i); // Go_haxegoruntime_FFloat32frombits.callFromRT(0,get_uint32(i)); 
   979  		#end
   980  	}
   981  	public inline function get_float64(i:Int):Float { 
   982  		#if (js && fullunsafe)
   983  			return dView.getFloat64(i,true); // little-endian
   984  		#elseif !fullunsafe
   985  			return get(i)==null?0.0:get(i); 
   986  		#else
   987  			return byts.getDouble(i); // Go_haxegoruntime_FFloat64frombits.callFromRT(0,get_uint64(i)); 		
   988  		#end
   989  	}
   990  	public inline function get_complex64(i:Int):Complex {
   991  		// TODO optimize for dataview & unsafe
   992  		var r:Complex=get(i); 
   993  		return r==null?new Complex(0.0,0.0):r;			
   994  	}
   995  	public inline function get_complex128(i:Int):Complex { 
   996  		// TODO optimize for dataview & unsafe
   997  		var r:Complex=get(i); 
   998  		return r==null?new Complex(0.0,0.0):r;			
   999  	}
  1000  	public inline function get_string(i:Int):String { 
  1001  		var r=get(i); 
  1002  		return r==null?"":Std.string(r);
  1003  	}
  1004  	public inline function set(i:Int,v:Dynamic):Void { 
  1005  		#if abstractobjects
  1006  			this[i]=v;
  1007  		#else
  1008  			dVec4[i>>2]=v;
  1009  		#end
  1010  	}
  1011  	public inline function set_bool(i:Int,v:Bool):Void { 
  1012  		#if (js && fullunsafe)
  1013  			dView.setUint8(i,v?1:0);
  1014  		#elseif abstractobjects
  1015  			set(i,v);//this[i]=v?1:null;
  1016  		#elseif !fullunsafe
  1017  			iVec[i]=v?1:0;
  1018  			#if ((js || php || neko ) &&!nonulltests)
  1019  				if(iVec[i]==0) iVec[i]=null; 
  1020  			#end
  1021  		#else
  1022  			byts.set(i,v?1:0); 
  1023  		#end
  1024  	} 
  1025  	public inline function set_int8(i:Int,v:Int):Void { 
  1026  		#if (js && fullunsafe)
  1027  			dView.setInt8(i,v);
  1028  		#elseif abstractobjects
  1029  			set(i,v);//this[i]=v==0?null:v;
  1030  		#elseif !fullunsafe
  1031  			iVec[i]=v;
  1032  			#if ((js || php || neko ) &&!nonulltests)
  1033  				if(iVec[i]==0) iVec[i]=null; 
  1034  			#end
  1035  		#else
  1036  			byts.set(i,v&0xff); 
  1037  		#end
  1038  	}
  1039  	public inline function set_int16(i:Int,v:Int):Void { 
  1040  		#if (js && fullunsafe)
  1041  			dView.setInt16(i,v,true); // little-endian
  1042  		#elseif abstractobjects
  1043  			set(i,v);//this[i]=v==0?null:v;
  1044  		#elseif !fullunsafe
  1045  			iVec[i]=v;
  1046  			#if ((js || php || neko ) &&!nonulltests)
  1047  				if(iVec[i]==0) iVec[i]=null; 
  1048  			#end
  1049  		#else
  1050  			set_int8(i,v);
  1051  			set_int8(i+1,v>>8);
  1052  		#end
  1053  	}
  1054  	public inline function set_int32(i:Int,v:Int):Void { 
  1055  		#if (js && fullunsafe)
  1056  			dView.setInt32(i,v,true); // little-endian
  1057  		#elseif abstractobjects
  1058  			set(i,v);//this[i]=v==0?null:v;
  1059  		#elseif !fullunsafe
  1060  			#if ((js || php || neko ) &&!nonulltests)
  1061  				iVec[i]=v==0?null:v; 
  1062  			#else
  1063  				iVec[i]=v;
  1064  			#end
  1065  		#else
  1066  			set_int16(i,v);
  1067  			set_int16(i+2,v>>16); 
  1068  		#end
  1069  	}
  1070  	public inline function set_int64(i:Int,v:GOint64):Void { 
  1071  		#if !fullunsafe
  1072  			if(GOint64.isZero(v)) 	set(i,null);
  1073  			else					set(i,v);  
  1074  		#else
  1075  			set_uint32(i,GOint64.getLow(v));
  1076  			set_uint32(i+4,GOint64.getHigh(v));
  1077  		#end
  1078  	} 
  1079  	public inline function set_uint8(i:Int,v:Int):Void { 
  1080  		#if (js && fullunsafe)
  1081  			dView.setUint8(i,v);
  1082  		#elseif abstractobjects
  1083  			set(i,v);//this[i]=v==0?null:v;
  1084  		#elseif !fullunsafe
  1085  			iVec[i]=v;
  1086  			#if ((js || php || neko ) &&!nonulltests)
  1087  				if(iVec[i]==0) iVec[i]=null; 
  1088  			#end
  1089  		#else
  1090  			byts.set(i,v&0xff);
  1091  		#end
  1092  	}
  1093  	public inline function set_uint16(i:Int,v:Int):Void { 
  1094  		#if (js && fullunsafe)
  1095  			dView.setUint16(i,v,true); // little-endian
  1096  		#elseif abstractobjects
  1097  			set(i,v);//this[i]=v==0?null:v;
  1098  		#elseif !fullunsafe
  1099  			iVec[i]=v;
  1100  			#if ((js || php || neko ) &&!nonulltests)
  1101  				if(iVec[i]==0) iVec[i]=null; 
  1102  			#end
  1103  		#else
  1104  			set_uint8(i,v); 
  1105  			set_uint8(i+1,v>>8); 
  1106  		#end
  1107  	}
  1108  	public inline function set_uint32(i:Int,v:Int):Void { 
  1109  		#if (js && fullunsafe)
  1110  			dView.setUint32(i,v,true); // little-endian
  1111  		#elseif abstractobjects
  1112  			set(i,v);//this[i]=v==0?null:v;
  1113  		#elseif !fullunsafe
  1114  			iVec[i]=v;
  1115  			#if ((js || php || neko ) &&!nonulltests)
  1116  				if(iVec[i]==0) iVec[i]=null; 
  1117  			#end
  1118  		#else
  1119  			set_uint16(i,v);
  1120  			set_uint16(i+2,v>>16); 
  1121  		#end
  1122  	}
  1123  	public inline function set_uint64(i:Int,v:GOint64):Void { 
  1124  		#if !fullunsafe
  1125  			if(GOint64.isZero(v)) 	set(i,null);
  1126  			else					set(i,v);  
  1127  		#else
  1128  			set_uint32(i,GOint64.getLow(v));
  1129  			set_uint32(i+4,GOint64.getHigh(v));
  1130  		#end
  1131  	} 
  1132  	public inline function set_uintptr(i:Int,v:Dynamic):Void { 
  1133  		if(Std.is(v,Int)) {
  1134  			set(i,Force.toUint32(v)); // make sure we only store 32 bits if int
  1135  			#if !abstractobjects
  1136  				set_uint32(i,v); // also write through to ordinary memory if the type is Int
  1137  			#end
  1138  			return;
  1139  		}
  1140  		set(i,v);
  1141  		#if !abstractobjects
  1142  			set_uint32(i,0); // value overwritten
  1143  		#end
  1144  	}
  1145  	public static var MinFloat64:Float = -1.797693134862315708145274237317043567981e+308; // 2**1023 * (2**53 - 1) / 2**52
  1146  	public inline function set_float32(i:Int,v:Float):Void {
  1147  		#if (js && fullunsafe)
  1148  			dView.setFloat32(i,v,true); // little-endian
  1149  		#elseif !fullunsafe
  1150  			v=Force.toFloat32(v);
  1151  			#if (js || php || neko ) 
  1152  				if(v==0.0) {
  1153  					#if !php
  1154  					var t:Float=1/v; // result is +/- infinity
  1155  					if(t>MinFloat64) // ie not -0
  1156  					#end
  1157  						v=null; 
  1158  				}
  1159  			#end
  1160  			set(i,v);
  1161  		#else 
  1162  			#if (cpp||neko)
  1163  				byts.setFloat(i,v);
  1164  			#else
  1165  				set_uint32(i,Go_haxegoruntime_FFloat32bits.callFromRT(0,v));
  1166  			#end 
  1167  		#end	
  1168  	}
  1169  	public inline function set_float64(i:Int,v:Float):Void {
  1170  	 	#if (js && fullunsafe)
  1171  			dView.setFloat64(i,v,true); // little-endian
  1172  		#elseif !fullunsafe
  1173  			#if (js || php || neko ) 
  1174  				if(v==0.0) {
  1175  					#if !php
  1176  					var t:Float=1/v; // result is +/- infinity
  1177  					if(t>MinFloat64) // ie not -0
  1178  					#end
  1179  						v=null;
  1180  				} 
  1181  			#end
  1182  			set(i,v);
  1183  		#else
  1184  			#if (cpp||neko)
  1185  				byts.setDouble(i,v);
  1186  			#else
  1187  				set_uint64(i,Go_haxegoruntime_FFloat64bits.callFromRT(0,v));
  1188  			#end 
  1189  		#end	
  1190  	}
  1191  	
  1192  	public inline function set_complex64(i:Int,v:Complex):Void { 
  1193  		if(v.real==0 && v.imag==0) set(i,null);
  1194  		else set(i,v); // TODO review
  1195  	} 
  1196  	public inline function set_complex128(i:Int,v:Complex):Void { 
  1197  		if(v.real==0 && v.imag==0) set(i,null);
  1198  		else set(i,v); // TODO review
  1199  	} 
  1200  	public inline function set_string(i:Int,v:String):Void { 
  1201  		if(v=="") set(i,null);
  1202  		else set(i,v); 
  1203  	}
  1204  	private static function str(v:Dynamic):String{
  1205  		return v==null?"nil":Std.is(v,Pointer)?v.toUniqueVal():Std.string(v);
  1206  	}
  1207  	public function toString(addr:Int=0,count:Int=-1):String{
  1208  		if(count==-1) count=this.length;
  1209  		if(addr<0) addr=0;
  1210  		if(count<0 || count>(this.length-addr)) count = this.length-addr;
  1211  		var ret:String =  "{";
  1212  		for(i in 0...count){
  1213  			if(i>0) ret = ret + ",";
  1214  			#if abstractobjects
  1215  				ret += str(get(addr));
  1216  			#else
  1217  				if((addr)&3==0) ret += str(get(addr));
  1218  				ret = ret+"<"+Std.string(get_uint8(addr))+">";
  1219  			#end
  1220  			addr = addr+1;
  1221  		}
  1222  		return ret+"}";
  1223  	}
  1224  }
  1225  `
  1226  	l.PogoComp().WriteAsClass("Object", objClass)
  1227  
  1228  	ptrClass := `
  1229  @:keep
  1230  class Pointer { 
  1231  	public var obj:Object; // reference to the object holding the value
  1232  	public var off:Int; // the offset into the object, if any 
  1233  `
  1234  	if l.PogoComp().DebugFlag {
  1235  		ptrClass += `
  1236  	public function new(from:Object,offset:Int){
  1237  		if(from==null) Scheduler.panicFromHaxe("attempt to make a new Pointer from a nil object");
  1238  `
  1239  	} else {
  1240  		ptrClass += `
  1241  	public #if inlinepointers inline #end function new(from:Object,offset:Int){
  1242  `
  1243  	}
  1244  	ptrClass += `		obj = from; 
  1245  	off = offset;
  1246  	}
  1247  	public function len(){
  1248  		if(obj==null) return 0;
  1249  		return obj.len()-off;
  1250  	}
  1251  	public function hashInt():Int {
  1252  		var ur:Int=obj.uniqueRef();
  1253  		var r = ((ur&0xffff)<<16) | (off&0xffff); // hash value for a pointer
  1254  		//trace("DEBUG Pointer.hashInt="+Std.string(r)+" this="+this.toUniqueVal());
  1255  		return r;
  1256  	}
  1257  `
  1258  	if l.PogoComp().DebugFlag {
  1259  		ptrClass += `	public static function check(p:Dynamic):Pointer {
  1260  		if(p==null) {
  1261  			Scheduler.panicFromHaxe("nil pointer de-reference");
  1262  			return null;
  1263  		}
  1264  		if(Std.is(p,Pointer)) return p;
  1265  		if(Std.is(p,Int)) 
  1266  			Scheduler.panicFromHaxe("TARDISgo/Haxe implementation cannot convert from uintptr to pointer");
  1267  		Scheduler.panicFromHaxe("non-Pointer cannot be used as a pointer");
  1268  		return null;
  1269  	}
  1270  `
  1271  	} else { // TODO null test could be removed in some future NoChecking mode maybe?
  1272  		ptrClass += `	public inline static function check(p:Pointer):Pointer {
  1273  			return p;
  1274  		}`
  1275  	}
  1276  	l.PogoComp().WriteAsClass("Pointer", ptrClass+
  1277  		`	public static function isEqual(p1:Pointer,p2:Pointer):Bool {
  1278  		if(p1==p2) return true; // simple case of being the same haxe object
  1279  		if(p1==null || p2==null) return false; // one of them is null (if above handles both null)
  1280  		if(p1.obj.uniqueRef()==p2.obj.uniqueRef() && p1.off==p2.off) return true; // point to same object & offset
  1281  		return false;
  1282  	}
  1283  	public static inline function make(from:Object):Pointer {
  1284  		return new Pointer(from,0);
  1285  	} 
  1286  	public #if inlinepointers inline #end function addr(byteOffset:Int):Pointer {
  1287  		return byteOffset==0?this:new Pointer(obj,off+byteOffset);
  1288  	}
  1289  	public inline function fieldAddr(byteOffset:Int):Pointer {
  1290  		return addr(byteOffset);
  1291  	}
  1292  	public inline function copy():Pointer {
  1293  		return this;
  1294  	}
  1295  	public #if inlinepointers inline #end function load_object(sz:Int):Object { 
  1296  		return obj.get_object(sz,off);
  1297  	}
  1298  	public #if inlinepointers inline #end function load():Dynamic {
  1299  		return obj.get(off);
  1300  	}
  1301  	public #if inlinepointers inline #end function load_bool():Bool { 
  1302  		return obj.get_bool(off);
  1303  	}
  1304  	public #if inlinepointers inline #end function load_int8():Int { 
  1305  		return obj.get_int8(off);
  1306  	}
  1307  	public #if inlinepointers inline #end function load_int16():Int { 
  1308  		return obj.get_int16(off);
  1309  	}
  1310  	public #if inlinepointers inline #end function load_int32():Int {
  1311  		return obj.get_int32(off);
  1312  	}
  1313  	public #if inlinepointers inline #end function load_int64():GOint64 { 
  1314  		return obj.get_int64(off);
  1315  	} 
  1316  	public #if inlinepointers inline #end function load_uint8():Int { 
  1317  		return obj.get_uint8(off);
  1318  	}
  1319  	public #if inlinepointers inline #end function load_uint16():Int {
  1320  		return obj.get_uint16(off);
  1321  	}
  1322  	public #if inlinepointers inline #end function load_uint32():Int {
  1323  		return obj.get_uint32(off);
  1324  	}
  1325  	public #if inlinepointers inline #end function load_uint64():GOint64 { 
  1326  		return obj.get_uint64(off);
  1327  	} 
  1328  	public #if inlinepointers inline #end function load_uintptr():Dynamic { 
  1329  		return obj.get_uintptr(off);
  1330  	} 
  1331  	public #if inlinepointers inline #end function load_float32():Float { 
  1332  		return obj.get_float32(off);
  1333  	}
  1334  	public #if inlinepointers inline #end function load_float64():Float { 
  1335  		return obj.get_float64(off);
  1336  	}
  1337  	public #if inlinepointers inline #end function load_complex64():Complex {
  1338  		return obj.get_complex64(off);
  1339  	}
  1340  	public #if inlinepointers inline #end function load_complex128():Complex { 
  1341  		return obj.get_complex128(off);
  1342  	}
  1343  	public #if inlinepointers inline #end function load_string():String { 
  1344  		return obj.get_string(off);
  1345  	}
  1346  	public #if inlinepointers inline #end function store_object(sz:Int,v:Object):Void {
  1347  		obj.set_object(sz,off,v);
  1348  	}
  1349  	public #if inlinepointers inline #end function store(v:Dynamic):Void {
  1350  		obj.set(off,v);
  1351  	}
  1352  	public #if inlinepointers inline #end function store_bool(v:Bool):Void { obj.set_bool(off,v); }
  1353  	public #if inlinepointers inline #end function store_int8(v:Int):Void { obj.set_int8(off,v); }
  1354  	public #if inlinepointers inline #end function store_int16(v:Int):Void { obj.set_int16(off,v); }
  1355  	public #if inlinepointers inline #end function store_int32(v:Int):Void { obj.set_int32(off,v); }
  1356  	public #if inlinepointers inline #end function store_int64(v:GOint64):Void { obj.set_int64(off,v); }  
  1357  	public #if inlinepointers inline #end function store_uint8(v:Int):Void { obj.set_uint8(off,v); }
  1358  	public #if inlinepointers inline #end function store_uint16(v:Int):Void { obj.set_uint16(off,v); }
  1359  	public #if inlinepointers inline #end function store_uint32(v:Int):Void { obj.set_uint32(off,v); }
  1360  	public #if inlinepointers inline #end function store_uint64(v:GOint64):Void { obj.set_uint64(off,v); } 
  1361  	public #if inlinepointers inline #end function store_uintptr(v:Dynamic):Void { obj.set_uintptr(off,v); }
  1362  	public #if inlinepointers inline #end function store_float32(v:Float):Void { obj.set_float32(off,v); }
  1363  	public #if inlinepointers inline #end function store_float64(v:Float):Void { obj.set_float64(off,v); }
  1364  	public #if inlinepointers inline #end function store_complex64(v:Complex):Void { obj.set_complex64(off,v); }
  1365  	public #if inlinepointers inline #end function store_complex128(v:Complex):Void { obj.set_complex128(off,v); }
  1366  	public #if inlinepointers inline #end function store_string(v:String):Void { obj.set_string(off,v); }
  1367  	public #if inlinepointers inline #end function toString(sz:Int=-1):String {
  1368  		return " &{ "+obj.toString(off,sz)+" } ";
  1369  	}
  1370  	public function toUniqueVal():String {
  1371  		return "&<"+Std.string(obj.uniqueRef())+":"+Std.string(off)+">";
  1372  	}
  1373  }
  1374  `)
  1375  	sliceClass := `
  1376  @:keep
  1377  class Slice {
  1378  	public var baseArray:Pointer;
  1379  	public var itemSize:Int; // for the size of each item in bytes 
  1380  	private var start:Int;
  1381  	private var end:Int;
  1382  	private var capacity:Int; // of the array, in items
  1383  
  1384  	public var length:Int;
  1385  	inline function setLength() {
  1386  		length=end-start;
  1387  	}
  1388  	public static #if inlinepointers inline #end function nullLen(s:Slice):Int{
  1389  		if(s==null) return 0;
  1390  		else return s.length;
  1391  	}
  1392  	public function new(fromArray:Pointer, low:Int, high:Int, ularraysz:Int, isz:Int) { 
  1393  		baseArray = fromArray;
  1394  		itemSize = isz;
  1395  		if(baseArray==null) {
  1396  			start = 0;
  1397  			end = 0;
  1398  			capacity = 0;
  1399  		} else {
  1400  			if( low<0 ) Scheduler.panicFromHaxe( "new Slice() low bound -ve"); 
  1401  			var ulCap = Math.floor(baseArray.len()/itemSize);
  1402  			if( ulCap < ularraysz) {
  1403  				ularraysz = ulCap; // ignore the given size & use the actual rather than panic TODO review+tidy
  1404  			//	Scheduler.panicFromHaxe("new Slice() internal error: underlying array capacity="+ulCap+
  1405  			//		" less than stated slice capacity="+ularraysz); // slices of existing data will have ulCap greater 
  1406  			}
  1407  			capacity = ularraysz; // the capacity of the array
  1408  			if(high==-1) high = ularraysz; //default upper bound is the capacity of the underlying array
  1409  			if( high > ularraysz ) Scheduler.panicFromHaxe("new Slice() high bound exceeds underlying array length"); 
  1410  			if( low>high ) Scheduler.panicFromHaxe("new Slice() low bound exceeds high bound"); 
  1411  			start = low;
  1412  			end = high;
  1413  		}
  1414  		setLength();
  1415  	} 
  1416  	public static function fromResource(name:String):Slice {
  1417  		return fromBytes(haxe.Resource.getBytes(name));
  1418  	}
  1419  	public static function fromBytes(res:haxe.io.Bytes):Slice {
  1420  		var obj = res==null?Object.make(0):Object.make(res.length,res); 
  1421  		var ptr = Pointer.make(obj);
  1422  		var ret = new Slice(ptr,0,-1,res==null?0:res.length,1); // []byte
  1423  		#if nulltempvars
  1424  			obj=null;ptr=null;
  1425  		#end
  1426  		return ret;
  1427  	}
  1428  	public static function toBytes(sl:Slice):haxe.io.Bytes {
  1429  		var wdSz = 4;
  1430  		var szAdj = (wdSz - (sl.length % wdSz)) % wdSz; // get to a wdSz-byte boundary
  1431  		var byts = haxe.io.Bytes.alloc(sl.length+szAdj);
  1432  		for(i in 0...sl.length)
  1433  			byts.set(i,sl.itemAddr(i).load_uint8()); 
  1434  		return byts;
  1435  	}	
  1436  	public function subSlice(low:Int, high:Int):Slice {
  1437  		if(high==-1) high = length; //default upper bound is the length of the current slice
  1438  		return new Slice(baseArray,low+start,high+start,capacity,itemSize);
  1439  	}
  1440  	public static function append(oldEnt:Slice,newEnt:Slice):Slice{ // TODO optimize further - heavily used
  1441  		if(oldEnt==null && newEnt==null) return null;
  1442  		if(newEnt==null || newEnt.len()==0) {
  1443  			return oldEnt; // NOTE not a clone as with the line below 
  1444  			//return new Slice(oldEnt.baseArray.addr(oldEnt.start*oldEnt.itemSize),0,oldEnt.len(),oldEnt.cap(),oldEnt.itemSize);
  1445  		}
  1446  		if(oldEnt==null) { // must create a copy rather than just return the new one
  1447  			oldEnt=new Slice(Pointer.make(Object.make(0)),0,0,0,newEnt.itemSize); // trigger newObj code below
  1448  		}
  1449  		if(oldEnt.itemSize!=newEnt.itemSize)
  1450  			Scheduler.panicFromHaxe("new Slice() internal error: itemSizes do not match");
  1451  		if(oldEnt.cap()>=(oldEnt.len()+newEnt.len())){
  1452  			var retEnt=new Slice(oldEnt.baseArray,oldEnt.start,oldEnt.end,oldEnt.capacity,oldEnt.itemSize);
  1453  			var offset=retEnt.len();
  1454  			for(i in 0...newEnt.len()){
  1455  				retEnt.end++; 
  1456  				//retEnt.itemAddr(offset+i).store_object(oldEnt.itemSize,newEnt.itemAddr(i).load_object(newEnt.itemSize));
  1457  				Object.objBlit(newEnt.baseArray.obj,newEnt.itemOff(i)+newEnt.baseArray.off,
  1458  					retEnt.baseArray.obj,retEnt.itemOff(offset+i)+retEnt.baseArray.off,oldEnt.itemSize);
  1459  			}
  1460  			#if nulltempvars
  1461  				oldEnt=null;newEnt=null;
  1462  			#end
  1463  			retEnt.setLength();
  1464  			return retEnt;
  1465  		}else{
  1466  			var newLen = oldEnt.length+newEnt.len();
  1467  			var newCap = newLen+(newLen>>2); // NOTE auto-create 50pc new capacity 
  1468  			var newObj:Object = Object.make(newCap*oldEnt.itemSize);
  1469  			for(i in 0...oldEnt.length) {
  1470  				//newObj.set_object(oldEnt.itemSize,i*oldEnt.itemSize,oldEnt.itemAddr(i).load_object(oldEnt.itemSize));
  1471  				Object.objBlit(oldEnt.baseArray.obj,oldEnt.itemOff(i)+oldEnt.baseArray.off,
  1472  					newObj,i*oldEnt.itemSize,oldEnt.itemSize);
  1473  			}
  1474  			for(i in 0...newEnt.len()){
  1475  				//newObj.set_object(oldEnt.itemSize,
  1476  				//	oldEnt.length*oldEnt.itemSize+i*oldEnt.itemSize,newEnt.itemAddr(i).load_object(oldEnt.itemSize));
  1477  				Object.objBlit(newEnt.baseArray.obj,newEnt.itemOff(i)+newEnt.baseArray.off,
  1478  					newObj,(oldEnt.length*oldEnt.itemSize)+(i*oldEnt.itemSize),oldEnt.itemSize);
  1479  			}
  1480  			var ptr = Pointer.make(newObj);
  1481  			var ret = new Slice(ptr,0,newLen,newCap,oldEnt.itemSize);
  1482  			#if nulltempvars
  1483  				oldEnt=null;newEnt=null;newObj=null;ptr=null;
  1484  			#end
  1485  			ret.setLength();
  1486  			return ret;
  1487  		}
  1488  	}
  1489  	public static function copy(target:Slice,source:Slice):Int{ 
  1490  		if(target==null) return 0;
  1491  		if(source==null) return 0;
  1492  		var copySize:Int=target.len();
  1493  		if(source.len()<copySize) 
  1494  			copySize=source.len(); 
  1495  		if(copySize==0) return 0;
  1496  		// Optimise not to create any temporary objects
  1497  		if(target.baseArray==source.baseArray){ // copy within the same slice
  1498  			if(target.start<=source.start){
  1499  				for(i in 0...copySize){
  1500  					//target.itemAddr(i).store_object(target.itemSize,source.itemAddr(i).load_object(target.itemSize));
  1501  					Object.objBlit(source.baseArray.obj,source.itemOff(i)+source.baseArray.off,
  1502  						target.baseArray.obj,target.itemOff(i)+target.baseArray.off,
  1503  						target.itemSize);
  1504  				}
  1505  			}else{
  1506  				var i = copySize-1;
  1507  				while(i>=0){
  1508  					//target.itemAddr(i).store_object(target.itemSize,source.itemAddr(i).load_object(target.itemSize));
  1509  					Object.objBlit(source.baseArray.obj,source.itemOff(i)+source.baseArray.off,
  1510  						target.baseArray.obj,target.itemOff(i)+target.baseArray.off,
  1511  						target.itemSize);
  1512  					i-=1;
  1513  				}
  1514  			}
  1515  		}else{
  1516  			for(i in 0...copySize){
  1517  				//target.itemAddr(i).store_object(target.itemSize,source.itemAddr(i).load_object(target.itemSize));
  1518  				Object.objBlit(source.baseArray.obj,source.itemOff(i)+source.baseArray.off,
  1519  					target.baseArray.obj,target.itemOff(i)+target.baseArray.off,
  1520  					target.itemSize);
  1521  			}
  1522  		}
  1523  		target.setLength();
  1524  		return copySize;
  1525  	}
  1526  	public function param(idx:Int):Dynamic { // special case for .hx pseudo functions
  1527  		var ptr=itemAddr(idx);
  1528  		var ret=ptr.load();
  1529  		#if nulltempvars
  1530  			ptr=null;
  1531  		#end
  1532  		return ret;
  1533  	}
  1534  	//public inline function getAt(idx:Int):Dynamic {
  1535  	//	//if (idx<0 || idx>=(end-start)) Scheduler.panicFromHaxe("Slice index out of range for getAt()");
  1536  	//	return baseArray.addr(idx+start).load();
  1537  	//}
  1538  	//public inline function setAt(idx:Int,v:Dynamic) {
  1539  	//	//if (idx<0 || idx>=(end-start)) Scheduler.panicFromHaxe("Slice index out of range for setAt()");
  1540  	//	baseArray.addr(idx+start).store(v); // this code relies on the object reference passing back
  1541  	//}
  1542  	public function len():Int {
  1543  		if(length!=end-start)  Scheduler.panicFromHaxe("Slice internal error: length!=end-start");
  1544  		return length;
  1545  	}
  1546  	public function setLen(n:Int) {
  1547  		if(n<0||n>this.cap())  Scheduler.panicFromHaxe("Slice setLen invalid:"+n);
  1548  		end = start+n;
  1549  		setLength();
  1550  	}
  1551  	public function cap():Int {
  1552  		// TODO remove null and capacity test when stable
  1553  		if(baseArray==null){
  1554  			if(capacity!=0) Scheduler.panicFromHaxe("Slice interal error: BaseArray==null but capacity="+capacity);
  1555  		}else{
  1556  			var ulCap = Math.floor(baseArray.len()/itemSize);
  1557  			if(capacity>ulCap) // slices of existing data will have ulCap greater 
  1558  				Scheduler.panicFromHaxe("Slice interal error: capacity="+capacity+" but underlying capacity="+ulCap);
  1559  		}
  1560  		return capacity-start;
  1561  	}
  1562  `
  1563  	if l.PogoComp().DebugFlag { // Normal range checking should cover this, so only in debug mode
  1564  		sliceClass += `
  1565  	public function itemAddr(idx:Int):Pointer {
  1566  		if (idx<0 || idx>=len()) 
  1567  			Scheduler.panicFromHaxe(
  1568  				"Slice index "+Std.string(idx)+" out of range 0 <= index < "+Std.string(len())+
  1569  				"\nSlice itemSize,capacity,start,end,baseArray: "+
  1570  				Std.string(itemSize)+","+Std.string(capacity)+","+
  1571  				Std.string(start)+","+Std.string(end)+","+Std.string(baseArray));
  1572  `
  1573  	} else { // TODO should this function be inline?
  1574  		sliceClass += `
  1575  		public #if inlinepointers inline #end function itemAddr(idx:Int):Pointer {
  1576  	`
  1577  	}
  1578  	sliceClass += `
  1579  		return new Pointer(baseArray.obj,baseArray.off+itemOff(idx));
  1580  	}
  1581  	public inline function itemOff(idx:Int):Int {
  1582  		return (idx+start)*itemSize;
  1583  	}
  1584  	public function toString():String {
  1585  		var ret:String = "Slice{[";
  1586  		var ptr:Pointer;
  1587  		if(baseArray!=null) 
  1588  			for(i in start...end) {
  1589  				if(i!=start) ret += ",";
  1590  				ptr=baseArray.addr(i*itemSize);
  1591  				ret+=ptr.toString(itemSize); // only works for basic types
  1592  			}
  1593  		#if nulltempvars
  1594  			ptr=null;
  1595  		#end
  1596  		return ret+"]}";
  1597  	}
  1598  }
  1599  `
  1600  	l.PogoComp().WriteAsClass("Slice", sliceClass)
  1601  	l.PogoComp().WriteAsClass("Closure", `
  1602  
  1603  @:keep
  1604  class Closure { // "closure" is a keyword in PHP but solved using compiler flag  --php-prefix go  //TODO tidy names
  1605  	public var fn:Dynamic; 
  1606  	public var bds:Array<Dynamic>;
  1607  
  1608  	public function new(f:Dynamic,b:Array<Dynamic>) {
  1609  		if(Std.is(f,Closure))	{
  1610  			if(!Reflect.isFunction(f.fn)) Scheduler.panicFromHaxe( "invalid function reference in existing Closure passed to make Closure(): "+f.fn);
  1611  			fn=f.fn; 
  1612  		} else{
  1613  			if(!Reflect.isFunction(f)) Scheduler.panicFromHaxe("invalid function reference passed to make Closure(): "+f); 
  1614  	 		fn=f;
  1615  		}
  1616  		if(fn==null) Scheduler.panicFromHaxe("new Closure() function has become null!"); // error test for flash/cpp TODO remove when issue resolved
  1617  		bds=b;
  1618  	}
  1619  	public function toString():String {
  1620  		var ret:String = "Closure{"+fn+",";
  1621  		if(bds!=null)
  1622  			for(i in 0...bds.length) {
  1623  				if(i!=0) ret += ",";
  1624  				ret+= bds[i];
  1625  			}
  1626  		return ret+"}";
  1627  	}
  1628  	public function methVal(t:Dynamic,v:Dynamic):Dynamic{
  1629  		return Reflect.callMethod(null, fn, [[],t,v]);
  1630  	}
  1631  	public static function callFn(cl:Closure,params:Dynamic):Dynamic {
  1632  		if(cl==null) {
  1633  			Scheduler.panicFromHaxe("attempt to call via null closure in Closure.callFn()");
  1634  			return null;
  1635  		}
  1636  		if(cl.fn==null) {
  1637  		 	Scheduler.panicFromHaxe("attempt to call null function reference in Closure.callFn()");
  1638  		 	return null;
  1639  		}
  1640  		if(!Reflect.isFunction(cl.fn)) {
  1641  			Scheduler.panicFromHaxe("invalid function reference in Closure(): "+cl.fn);
  1642  			return null;
  1643  		}
  1644  		return Reflect.callMethod(null, cl.fn, params);
  1645  	}
  1646  	// This technique is used to create callback functions
  1647  	public function buildCallbackFn():Dynamic { 
  1648  		//trace("buildCallbackFn");
  1649  		function bcf(params:Array<Dynamic>):Dynamic {
  1650  			//trace("bcf");
  1651  			if(!Go.doneInit) Go.init();
  1652  			params.insert(0,bds); // the variables bound in the closure (at final index 1)
  1653  			params.insert(0,0); // use goroutine 0 (at final index 0)
  1654  			var SF:StackFrame=Reflect.callMethod(null, fn, params); 
  1655  			while(SF._incomplete) Scheduler.runAll();
  1656  			return SF.res();
  1657  		}
  1658  		return Reflect.makeVarArgs(bcf); 
  1659  	}
  1660  }
  1661  `)
  1662  	l.PogoComp().WriteAsClass("Interface", `
  1663  
  1664  class Interface { // "interface" is a keyword in PHP but solved using compiler flag  --php-prefix tgo //TODO tidy names 
  1665  	public var typ:Int; // the possibly interface type that has been cast to
  1666  	public var val:Dynamic;
  1667  
  1668  	public inline function new(t:Int,v:Dynamic){
  1669  		typ=t;
  1670  		val=v; 
  1671  	}
  1672  	public function toString():String {
  1673  		var nam:String;
  1674  		#if (js || neko || php)
  1675  			if(typ==null) 
  1676  				nam="nil";
  1677  			else
  1678  				nam=TypeInfo.getName(typ);
  1679  		#else
  1680  			nam=TypeInfo.getName(typ);			
  1681  		#end
  1682  		if(val==null)
  1683  			return "Interface{nil:"+nam+"}";
  1684  		else
  1685  			if(Std.is(val,Pointer))
  1686  				return "interface{"+val.toUniqueVal()+":"+nam+"}"; // To stop recursion
  1687  			else
  1688  				return "Interface{"+Std.string(val)+":"+nam+"}";
  1689  	}
  1690  	public static function toDynamic(v:Interface):Dynamic {
  1691  		if(v==null)
  1692  			return null;
  1693  		return v.val;
  1694  	}
  1695  	public static function fromDynamic(v:Dynamic):Interface {
  1696  		if(v==null)
  1697  			return null;
  1698  		if(Std.is(v,Bool))
  1699  			return new Interface(TypeInfo.getId("bool"),v); 
  1700  		if(Std.is(v,Int))
  1701  			return new Interface(TypeInfo.getId("int"),v); 
  1702  		if(Std.is(v,Float))
  1703  			return new Interface(TypeInfo.getId("float64"),v); 
  1704  		if(Std.is(v,String))
  1705  			return new Interface(TypeInfo.getId("string"),v); 
  1706  		// TODO consider testing for other types here?
  1707  		return new Interface(TypeInfo.getId("uintptr"),v); 
  1708  	}
  1709  	public static function change(t:Int,i:Interface):Interface {
  1710  		if(i==null)	
  1711  			if(TypeInfo.isConcrete(t))  
  1712  				return new Interface(t,TypeZero.zeroValue(t)); 
  1713  			else {
  1714  				return null; // e.g. error(nil) 
  1715  			}
  1716  		else 
  1717  			if(Std.is(i,Interface)) 	
  1718  				if(TypeInfo.isConcrete(t)) 
  1719  					return new Interface(t,i.val); 
  1720  				else
  1721  					return new Interface(i.typ,i.val); // do not allow non-concrete types for Interfaces
  1722  			else {
  1723  				Scheduler.panicFromHaxe( "Can't change the Interface of a non-Interface type:"+i+" to: "+TypeInfo.getName(t));  
  1724  				return new Interface(t,TypeZero.zeroValue(t));	 //dummy value as we have hit the panic button
  1725  			}
  1726  	}
  1727  	public static function isEqual(a:Interface,b:Interface):Bool {		
  1728  	// TODO ensure this very wide definition of equality is OK 
  1729  	// TODO is another special case required for Slice/Object?
  1730  		if(a==null) 
  1731  			if(b==null) return true;
  1732  			else 		return false;
  1733  		if(b==null)		
  1734  			return false;
  1735  		if(! (TypeInfo.isIdentical(a.typ,b.typ)||TypeAssign.isAssignableTo(a.typ,b.typ)||TypeAssign.isAssignableTo(b.typ,a.typ)) ) 
  1736  			return false;	
  1737  		return Force.isEqualDynamic(a.val,b.val);
  1738  	}			
  1739  	/* from the SSA documentation:
  1740  	If AssertedType is a concrete type, TypeAssert checks whether the dynamic type in Interface X is equal to it, and if so, 
  1741  		the result of the conversion is a copy of the value in the Interface.
  1742  	If AssertedType is an Interface, TypeAssert checks whether the dynamic type of the Interface is assignable to it, 
  1743  		and if so, the result of the conversion is a copy of the Interface value X. If AssertedType is a superInterface of X.Type(), 
  1744  		the operation will fail iff the operand is nil. (Contrast with ChangeInterface, which performs no nil-check.)
  1745  	*/
  1746  	public static function assert(assTyp:Int,ifce:Interface):Dynamic{
  1747  		// TODO add code to deal with overloaded types? i.e. those created by reflect
  1748  		if(ifce==null) {
  1749  			Scheduler.panicFromHaxe( "Interface.assert null Interface");
  1750  		} else {
  1751  			if(TypeInfo.isConcrete(assTyp))	{
  1752  				if(ifce.typ==assTyp)
  1753  					return ifce.val;
  1754  				else
  1755  					Scheduler.panicFromHaxe( "concrete type assert failed: expected "+TypeInfo.getName(assTyp)+", got "+TypeInfo.getName(ifce.typ) );	
  1756  			} else {
  1757  				if(assertCache(ifce.typ,assTyp) /*ifce.typ==assTyp||Go_haxegoruntime_assertableTTo.callFromRT(0,ifce.typ,assTyp)*/ ){
  1758  					//was:TypeAssert.assertableTo(ifce.typ,assTyp)){
  1759  					return new Interface(ifce.typ,ifce.val);
  1760  				} else {
  1761  					Scheduler.panicFromHaxe( "interface type assert failed: cannot assert to "+TypeInfo.getName(assTyp)+" from "+TypeInfo.getName(ifce.typ) );
  1762  				}
  1763  			}
  1764  		}
  1765  		return null;
  1766  	}
  1767  	public static function assertOk(assTyp:Int,ifce:Interface):{r0:Dynamic,r1:Bool} {
  1768  		if(ifce==null) 
  1769  			return {r0:TypeZero.zeroValue(assTyp),r1:false};
  1770  		if(!assertCache(ifce.typ,assTyp) /*(ifce.typ==assTyp||Go_haxegoruntime_assertableTTo.callFromRT(0,ifce.typ,assTyp))*/ ) //was:TypeAssert.assertableTo(ifce.typ,assTyp)))
  1771  			return {r0:TypeZero.zeroValue(assTyp),r1:false};
  1772  		if(TypeInfo.isConcrete(assTyp))	
  1773  			return {r0:ifce.val,r1:true};
  1774  		else	
  1775  			return {r0:new Interface(ifce.typ,ifce.val),r1:true};
  1776  	}
  1777  	static var assertCacheMap = new Map<Int,Bool>();
  1778  	public static function assertCache(ifceTyp:Int,assTyp:Int):Bool {
  1779  		var key:Int= Force.toUint16(ifceTyp)<<16 | Force.toUint16(assTyp) ; // more than 65k types and we hava a problem...
  1780  		var ret:Bool;
  1781  		if(assertCacheMap.exists(key)){
  1782  			ret=assertCacheMap.get(key);
  1783  		}else{
  1784  			ret=(ifceTyp==assTyp||Go_haxegoruntime_assertableTTo.callFromRT(0,ifceTyp,assTyp));
  1785  			assertCacheMap.set(key,ret);
  1786  		}
  1787  		return ret;
  1788  	}
  1789  	static var methodCache = new Map<String,Dynamic>();
  1790  	public static function invoke(ifce:Interface,path:String,meth:String,args:Array<Dynamic>):Dynamic {
  1791  		if(ifce==null) 
  1792  			Scheduler.panicFromHaxe( "Interface.invoke null Interface"); 
  1793  		if(!Std.is(ifce,Interface)) 
  1794  			Scheduler.panicFromHaxe( "Interface.invoke on non-Interface value"); 
  1795  		var key=Std.string(ifce.typ)+":"+path+":"+meth;
  1796  		var fn:Dynamic=methodCache.get(key);
  1797  		if(fn==null) {
  1798  			fn=Go_haxegoruntime_getMMethod.callFromRT(0,ifce.typ,path,meth); //MethodTypeInfo.method(ifce.typ,meth);
  1799  			methodCache.set(key,fn);
  1800  		}
  1801  		var ret=Reflect.callMethod(null, fn, args);
  1802  		#if nulltempvars
  1803  			// set created objects to null for GC
  1804  			key=null;
  1805  			fn=null;
  1806  		#end
  1807  		// return what was asked for
  1808  		return ret;
  1809  	}
  1810  }
  1811  `)
  1812  	l.PogoComp().WriteAsClass("Channel", `
  1813  
  1814  class Channel { // NOTE single-threaded implementation, no locking
  1815  var entries:Array<Dynamic>;
  1816  var max_entries:Int;
  1817  var num_entries:Int;
  1818  var oldest_entry:Int;	
  1819  var closed:Bool;
  1820  var capa:Int;
  1821  var uniqueId:Int;
  1822  
  1823  static var nextId:Int=0;
  1824  
  1825  public function new(how_many_entries:Int) {
  1826  	capa = how_many_entries;
  1827  	if(how_many_entries<=0)
  1828  		how_many_entries=1;
  1829  	entries = new Array<Dynamic>();
  1830  	max_entries = how_many_entries;
  1831  	oldest_entry = 0;
  1832  	num_entries = 0;
  1833  	closed = false;
  1834  	uniqueId = nextId;
  1835  	nextId++;
  1836  }
  1837  public static function hasSpace(ch:Channel):Bool {
  1838  	if(ch==null) return false; // non-existant channels never have space
  1839  	if(ch.closed) return false; // closed channels don't have space
  1840  	return ch.num_entries < ch.max_entries;
  1841  }
  1842  public function send(source:Dynamic):Bool {
  1843  	if(closed) 
  1844  		Scheduler.panicFromHaxe( "attempt to send to closed channel"); 
  1845  	if (hasSpace(this)) {
  1846  		var next_element:Int;
  1847  		next_element = (oldest_entry + num_entries) % max_entries;
  1848  		num_entries++;
  1849  		entries[next_element]=source;  
  1850  		return true;
  1851  	} 
  1852  	return false;
  1853  }
  1854  public static function hasNoContents(ch:Channel):Bool { // used by channel read
  1855  	if (ch==null) return true; // spec: "Receiving from a nil channel blocks forever."
  1856  	if (ch.closed) return false; // spec: "Receiving from a closed channel always succeeds..."
  1857  	else return ch.num_entries == 0;
  1858  }
  1859  public static function hasContents(ch:Channel):Bool { // used by select
  1860  	if (ch==null) return false; // spec: "Receiving from a nil channel blocks forever."
  1861  	if (ch.closed) return true; // spec: "Receiving from a closed channel always succeeds..."
  1862  	return ch.num_entries != 0;
  1863  }
  1864  public function receive(zero:Dynamic):{r0:Dynamic ,r1:Bool} {
  1865  	var ret:Dynamic=zero;
  1866  	if (num_entries > 0) {
  1867  		ret=entries[oldest_entry];
  1868  		oldest_entry = (oldest_entry + 1) % max_entries;
  1869  		num_entries--;
  1870  		return {r0:ret,r1:true};
  1871  	} else
  1872  		if(closed)
  1873  			return {r0:ret,r1:false}; // spec: "Receiving from a closed channel always succeeds, immediately returning the element type's zero value."
  1874  		else {
  1875  			Scheduler.panicFromHaxe( "channel receive unreachable code!"); 
  1876  			return {r0:ret,r1:false}; //dummy value as we have hit the panic button
  1877  		}
  1878  }
  1879  public inline function len():Int { 
  1880  	return num_entries; 
  1881  }
  1882  public inline function cap():Int { 
  1883  	return capa; // give back the cap we were told
  1884  }
  1885  public function close() {
  1886  	if(this==null) Scheduler.panicFromHaxe( "attempt to close a nil channel" ); 
  1887  	closed = true;
  1888  }
  1889  public function toString():String{
  1890  	return "<ChanId:"+Std.string(uniqueId)+">";
  1891  }
  1892  }
  1893  `)
  1894  	l.PogoComp().WriteAsClass("Complex", `
  1895  
  1896  class Complex {
  1897  	public var real:Float;
  1898  	public var imag:Float;
  1899  public function new(r:Float, i:Float) {
  1900  	real = r;
  1901  	imag = i;
  1902  }
  1903  public static function neg(x:Complex):Complex {
  1904  	return new Complex(0.0-x.real,0.0-x.imag);
  1905  }
  1906  public static function add(x:Complex,y:Complex):Complex {
  1907  	return new Complex(x.real+y.real,x.imag+y.imag);
  1908  }
  1909  public static function sub(x:Complex,y:Complex):Complex {
  1910  	return new Complex(x.real-y.real,x.imag-y.imag);
  1911  }
  1912  public static function mul(x:Complex,y:Complex):Complex {
  1913  	return new Complex( (x.real * y.real) - (x.imag * y.imag), (x.imag * y.real) + (x.real * y.imag));
  1914  }
  1915  public static function div(x:Complex,y:Complex):Complex {
  1916  	if( (y.real == 0.0) && (y.imag == 0.0) ){
  1917  		Scheduler.panicFromHaxe( "complex divide by zero");
  1918  		return new Complex(0.0,0.0); //dummy value as we have hit the panic button
  1919  	} else {
  1920  		return new Complex(
  1921  			((x.real * y.real) + (x.imag * y.imag)) / ((y.real * y.real) + (y.imag * y.imag)) ,
  1922  			((x.imag * y.real) - (x.real * y.imag)) / ((y.real * y.real) + (y.imag * y.imag)) );
  1923  	}
  1924  }
  1925  public static function eq(x:Complex,y:Complex):Bool { // "=="
  1926  	return (x.real == y.real) && (x.imag == y.imag);
  1927  }
  1928  public static function neq(x:Complex,y:Complex):Bool { // "!="
  1929  	return (x.real != y.real) || (x.imag != y.imag);
  1930  }
  1931  public static function toString(x:Complex):String {
  1932  	return Std.string(x.real)+"+"+Std.string(x.imag)+"i";
  1933  }
  1934  }
  1935  
  1936  `)
  1937  	l.PogoComp().WriteAsClass("GOint64", `
  1938  
  1939  #if ( neko || cpp || cs || java ) 
  1940  	typedef HaxeInt64Typedef = haxe.Int64; // these implementations are using native types
  1941  #else
  1942  	typedef HaxeInt64Typedef = Int64;  // use the copied and modified version of the standard library class below
  1943  	// TODO revert to haxe.Int64 when the version below (or better) reaches the released libray
  1944  #end
  1945  
  1946  // this abstract type to enable correct handling for Go of HaxeInt64Typedef
  1947  abstract HaxeInt64abs(HaxeInt64Typedef) 
  1948  from HaxeInt64Typedef to HaxeInt64Typedef 
  1949  { 
  1950  public inline function new(v:HaxeInt64Typedef) this=v;
  1951  
  1952  #if !( neko || cpp || cs || java ) // allow casting to/from haxe.Int64 if using own version
  1953    @:from
  1954    static public function fromHI64(v:haxe.Int64) {
  1955    	return HaxeInt64abs.make(v.high,v.low); 
  1956    }
  1957    @:to
  1958    public inline function toHI64():haxe.Int64 {
  1959    	return haxe.Int64.make(Int64.getHigh(this),Int64.getLow(this));
  1960    }
  1961  #end
  1962  
  1963  public static inline function getLow(v:HaxeInt64Typedef):Int {
  1964  	#if ( neko || cpp || cs || java )
  1965  		return v.low;
  1966  	#else
  1967  		return HaxeInt64Typedef.getLow(v);
  1968  	#end
  1969  }
  1970  public static inline function getHigh(v:HaxeInt64Typedef):Int {
  1971  	#if ( neko || cpp || cs || java )
  1972  		return v.high;
  1973  	#else
  1974  		return HaxeInt64Typedef.getHigh(v);
  1975  	#end
  1976  }
  1977  
  1978  public static inline function toInt(v:HaxeInt64abs):Int {
  1979  	return HaxeInt64abs.getLow(v); // NOTE: does not throw an error if value overflows Int
  1980  }
  1981  public static inline function ofInt(v:Int):HaxeInt64abs {
  1982  	return new HaxeInt64abs(HaxeInt64Typedef.ofInt(v));
  1983  }
  1984  public static inline function ofUInt(v:Int):HaxeInt64abs {
  1985  	return make(0,v);
  1986  }
  1987  public static function toFloat(vp:HaxeInt64abs):Float{ // signed int64 to float (TODO auto-cast of Unsigned pos problem)
  1988  		//TODO native versions for java & cs
  1989  		var v:HaxeInt64Typedef=vp;
  1990  		var isNegVal:Bool=false;
  1991  		if(isNeg(v)) {
  1992  			if(compare(v,make(0x80000000,0))==0) return -9223372036854775808.0; // most -ve value can't be made +ve
  1993  			isNegVal=true;
  1994  			v=neg(v);	
  1995  		}
  1996  		var ret:Float=toUFloat(v);
  1997  		if(isNegVal) return -ret;
  1998  		return ret;
  1999  }
  2000  public static function toUFloat(vp:HaxeInt64abs):Float{ // unsigned int64 to float
  2001  		//TODO native versions for java & cs
  2002  		var v:HaxeInt64Typedef=vp;
  2003  		var ret:Float=0.0;
  2004  		var multiplier:Float=1.0;
  2005  		var one:HaxeInt64abs=make(0,1);
  2006  		for(i in 0...64) { 
  2007  			if(!isZero(and(v,one)))
  2008  	 			ret += multiplier;
  2009  			multiplier *= 2.0;
  2010  			v=ushr(v,1);
  2011  		}
  2012  		return ret;
  2013  }
  2014  public static function ofFloat(v:Float):HaxeInt64abs { // float to signed int64 (TODO auto-cast of Unsigned is a posible problem)
  2015  		//TODO native versions for java & cs
  2016  		if(v==0.0) return make(0,0); 
  2017  		if(Math.isNaN(v)) return make(0x80000000,0); // largest -ve number is returned by Go in this situation
  2018  		var isNegVal:Bool=false;
  2019  		if(v<0.0){
  2020  			isNegVal=true;
  2021  			v = -v;
  2022  		} 
  2023  		if(v<2147483647.0) { // optimization: if just a small integer, don't do the full conversion code below
  2024  			if(isNegVal) 	return new HaxeInt64abs(HaxeInt64Typedef.neg(HaxeInt64Typedef.ofInt(Math.floor(v)))); // ceil?
  2025  			else			return new HaxeInt64abs(HaxeInt64Typedef.ofInt(Math.floor(v)));
  2026  		}
  2027  		if(v>9223372036854775807.0) { // number too big to encode in 63 bits 
  2028  			if(isNegVal)	return new HaxeInt64abs(HaxeInt64Typedef.make(0x80000000,0)); 			// largest -ve number
  2029  			else			return new HaxeInt64abs(HaxeInt64Typedef.make(0x7fffffff,0xffffffff)); 	// largest +ve number
  2030  		}
  2031  		var res:HaxeInt64Typedef = ofUFloat(v);
  2032  		if(isNegVal) return new HaxeInt64abs(HaxeInt64Typedef.neg(res));
  2033  		return new HaxeInt64abs(res);
  2034  }
  2035  public static function ofUFloat(v:Float):HaxeInt64abs { // float to un-signed int64 
  2036  		//TODO native versions for java & cs
  2037  		if(v<0.0){
  2038  			//Scheduler.panicFromHaxe("-ve value passed to internal haxe function ofUFloat()");
  2039  			return make(0,0); // -ve values are invalid here, so return 0
  2040  		} 
  2041  		if(Math.isNaN(v)) return make(0x80000000,0); // largest -ve number is returned by Go in this situation
  2042  		if(v<2147483647.0) { // optimization: if just a small integer, don't do the full conversion code below
  2043  			return ofInt(Math.floor(v));
  2044  		}
  2045  		if(v>18446744073709551615.0) { // number too big to encode in 64 bits 
  2046  			return new HaxeInt64abs(HaxeInt64Typedef.make(0xffffffff,0xffffffff)); 	// largest unsigned number
  2047  		}
  2048  		var f32:Float = 4294967296.0 ; // the number of combinations in 32-bits
  2049  		var f16:Float = 65536.0; // the number of combinations in 16-bits
  2050  		v = Math.ffloor(v); // remove any fractional part
  2051  		var high:Float = Math.ffloor(v/f32);
  2052  		var highTop16:Float = Math.ffloor(high/f16);
  2053  		var highBot16:Float = high-(highTop16*f16);
  2054  		var highBits:Int = Math.floor(highTop16)<<16 | Math.floor(highBot16);
  2055  		var low:Float = v-(high*f32);
  2056  		var lowTop16:Float = Math.ffloor(low/f16);
  2057  		var lowBot16:Float = low-(lowTop16*f16);
  2058  		var lowBits:Int = Math.floor(lowTop16)<<16 | Math.floor(lowBot16);
  2059  		return HaxeInt64Typedef.make(highBits,lowBits);
  2060  }
  2061  public static #if !(cs||java) inline #end function make(h:Int,l:Int):HaxeInt64abs { 
  2062  // NOTE cs & java have problems inlining the '0xffffffffL' constant
  2063  		return new HaxeInt64abs(HaxeInt64Typedef.make(h,l));
  2064  }
  2065  public static inline function toString(v:HaxeInt64abs):String {
  2066  	return HaxeInt64Typedef.toStr(v);
  2067  }
  2068  public static inline function toStr(v:HaxeInt64abs):String {
  2069  	return HaxeInt64Typedef.toStr(v);
  2070  }
  2071  public static inline function neg(v:HaxeInt64abs):HaxeInt64abs {
  2072  	return new HaxeInt64abs(HaxeInt64Typedef.neg(v));
  2073  }
  2074  public static inline function isZero(v:HaxeInt64abs):Bool {
  2075  	return HaxeInt64Typedef.isZero(v);
  2076  }
  2077  public static inline function isNeg(v:HaxeInt64abs):Bool {
  2078  	return HaxeInt64Typedef.isNeg(v);
  2079  }
  2080  public static inline function add(x:HaxeInt64abs,y:HaxeInt64abs):HaxeInt64abs {
  2081  	return new HaxeInt64abs(HaxeInt64Typedef.add(x,y));
  2082  }
  2083  public static inline function and(x:HaxeInt64abs,y:HaxeInt64abs):HaxeInt64abs {
  2084  	return new HaxeInt64abs(HaxeInt64Typedef.and(x,y));
  2085  }
  2086  private static function checkDiv(x:HaxeInt64abs,y:HaxeInt64abs,isSigned:Bool):HaxeInt64abs {
  2087  	if(HaxeInt64Typedef.isZero(y))
  2088  		Scheduler.panicFromHaxe( "attempt to divide 64-bit value by 0"); 
  2089  	if(isSigned && (HaxeInt64Typedef.compare(y,HaxeInt64Typedef.ofInt(-1))==0) && (HaxeInt64Typedef.compare(x,HaxeInt64Typedef.make(0x80000000,0))==0) ) 
  2090  	{
  2091  		//trace("checkDiv 64-bit special case");
  2092  		y=HaxeInt64Typedef.ofInt(1); // special case in the Go spec
  2093  	}
  2094  	return new HaxeInt64abs(y);
  2095  }
  2096  public static function div(x:HaxeInt64abs,y:HaxeInt64abs,isSigned:Bool):HaxeInt64abs {
  2097  	y=checkDiv(x,y,isSigned);
  2098  	if(HaxeInt64Typedef.compare(y,HaxeInt64Typedef.ofInt(1))==0) return new HaxeInt64abs(x);
  2099  	if(isSigned || (!HaxeInt64Typedef.isNeg(x) && !HaxeInt64Typedef.isNeg(y)))
  2100  		return new HaxeInt64abs(HaxeInt64Typedef.div(x,y));
  2101  	else {
  2102  		if(	HaxeInt64Typedef.isNeg(x) ) {
  2103  			if( HaxeInt64Typedef.isNeg(y) ){ // both x and y are "-ve""
  2104  				if( HaxeInt64Typedef.compare(x,y) < 0 ) { // x is more "-ve" than y, so the smaller uint   
  2105  					return new HaxeInt64abs(HaxeInt64Typedef.ofInt(0));						
  2106  				} else {
  2107  					return new HaxeInt64abs(HaxeInt64Typedef.ofInt(1));	// both have top bit set & uint(x)>uint(y)
  2108  				}
  2109  			} else { // only x is -ve
  2110  				var pt1:HaxeInt64Typedef = HaxeInt64Typedef.make(0x7FFFFFFF,0xFFFFFFFF); // the largest part of the numerator
  2111  				var pt2:HaxeInt64Typedef = HaxeInt64Typedef.and(x,pt1); // the smaller part of the numerator
  2112  				var rem:HaxeInt64Typedef = HaxeInt64Typedef.make(0,1); // the left-over bit
  2113  				rem = HaxeInt64Typedef.add(rem,HaxeInt64Typedef.mod(pt1,y));
  2114  				rem = HaxeInt64Typedef.add(rem,HaxeInt64Typedef.mod(pt2,y));
  2115  				if( HaxeInt64Typedef.ucompare(rem,y) >= 0 ) { // the remainder is >= divisor  
  2116  					rem = HaxeInt64Typedef.ofInt(1);
  2117  				} else {
  2118  					rem = HaxeInt64Typedef.ofInt(0);
  2119  				}
  2120  				pt1 = HaxeInt64Typedef.div(pt1,y);	
  2121  				pt2 = HaxeInt64Typedef.div(pt2,y);			
  2122  				return new HaxeInt64abs(HaxeInt64Typedef.add(pt1,HaxeInt64Typedef.add(pt2,rem)));	
  2123  			}
  2124  		}else{ // logically, y is "-ve"" but x is "+ve" so y>x , so any integer divide will yeild 0
  2125  				return new HaxeInt64abs(HaxeInt64Typedef.ofInt(0));	
  2126  		}
  2127  	}
  2128  }
  2129  public static function mod(x:HaxeInt64abs,y:HaxeInt64abs,isSigned:Bool):HaxeInt64abs {
  2130  	y=checkDiv(x,y,isSigned);
  2131  	if(HaxeInt64Typedef.compare(y,HaxeInt64Typedef.ofInt(1))==0) return new HaxeInt64abs(HaxeInt64Typedef.ofInt(0));
  2132  	if(isSigned)
  2133  		return new HaxeInt64abs(HaxeInt64Typedef.mod(x,y));
  2134  	else {
  2135  		return new HaxeInt64abs(sub(x,mul(div(x,y,false),y)));
  2136  	}
  2137  }
  2138  public static inline function mul(x:HaxeInt64abs,y:HaxeInt64abs):HaxeInt64abs {
  2139  	return new HaxeInt64abs(HaxeInt64Typedef.mul(x,y));
  2140  }
  2141  public static inline function or(x:HaxeInt64abs,y:HaxeInt64abs):HaxeInt64abs {
  2142  	return new HaxeInt64abs(HaxeInt64Typedef.or(x,y));
  2143  }
  2144  public static function shl(x:HaxeInt64abs,y:Int):HaxeInt64abs {
  2145  	if(y==0) return new HaxeInt64abs(x);
  2146  	if(y<0 || y>=64) // this amount of shl is not handled correcty by the underlying code
  2147  		return new HaxeInt64abs(HaxeInt64Typedef.ofInt(0));	
  2148  	else
  2149  		return new HaxeInt64abs(HaxeInt64Typedef.shl(x,y));
  2150  }
  2151  public static function shr(x:HaxeInt64abs,y:Int):HaxeInt64abs { // note, not inline
  2152  	if(y==0) return new HaxeInt64abs(x);
  2153  	if(y<0 || y>=64)
  2154  		if(isNeg(x))
  2155  			return new HaxeInt64abs(HaxeInt64Typedef.ofInt(-1));		
  2156  		else
  2157  			return new HaxeInt64abs(HaxeInt64Typedef.ofInt(0));		
  2158  	return new HaxeInt64abs(HaxeInt64Typedef.shr(x,y));
  2159  }
  2160  public static function ushr(x:HaxeInt64abs,y:Int):HaxeInt64abs { // note, not inline
  2161  	if(y==0) return new HaxeInt64abs(x);
  2162  	if(y<0 || y>=64)
  2163  		return new HaxeInt64abs(HaxeInt64Typedef.ofInt(0));		
  2164  	#if php
  2165  	if(y==32){ // error with php on 32 bit right shift for uint64, so do 2x16
  2166  		var ret:HaxeInt64Typedef = HaxeInt64Typedef.ushr(x,16);
  2167  		return new HaxeInt64abs(HaxeInt64Typedef.ushr(ret,16));
  2168  	}
  2169  	#end
  2170  	return new HaxeInt64abs(HaxeInt64Typedef.ushr(x,y));
  2171  }
  2172  public static inline function sub(x:HaxeInt64abs,y:HaxeInt64abs):HaxeInt64abs {
  2173  	return new HaxeInt64abs(HaxeInt64Typedef.sub(x,y));
  2174  }
  2175  public static inline function xor(x:HaxeInt64abs,y:HaxeInt64abs):HaxeInt64abs {
  2176  	return new HaxeInt64abs(HaxeInt64Typedef.xor(x,y));
  2177  }
  2178  public static inline function compare(x:HaxeInt64abs,y:HaxeInt64abs):Int {
  2179  	return HaxeInt64Typedef.compare(x,y);
  2180  }
  2181  public static function ucompare(x:HaxeInt64abs,y:HaxeInt64abs):Int {
  2182  	//#if cpp
  2183  	 	return HaxeInt64Typedef.ucompare(x,y);
  2184  	//#else
  2185  	// unsigned compare library code does not work properly for all platforms 
  2186  	/*was:
  2187  		if(HaxeInt64Typedef.isZero(x)) {
  2188  			if(HaxeInt64Typedef.isZero(y)) {
  2189  				return 0;
  2190  			} else {
  2191  				return -1; // any value is larger than x 
  2192  			}
  2193  		}
  2194  		if(HaxeInt64Typedef.isZero(y)) { // if we are here, we know that x is non-zero
  2195  				return 1; // any value of x is larger than y 
  2196  		}
  2197  		if(!HaxeInt64Typedef.isNeg(x)) { // x +ve
  2198  			if(!HaxeInt64Typedef.isNeg(y)){ // both +ve so normal comparison
  2199  				return HaxeInt64Typedef.compare(x,y);
  2200  			}else{ // y -ve and so larger than x
  2201  				return -1;
  2202  			}
  2203  		}else { // x -ve
  2204  			if(!HaxeInt64Typedef.isNeg(y)){ // -ve x larger than +ve y
  2205  				return 1;
  2206  			}else{ // both are -ve so the normal comparison works ok
  2207  				return HaxeInt64Typedef.compare(x,y); 
  2208  			}
  2209  		}
  2210  	*/
  2211  	//#end
  2212  }
  2213  }
  2214  
  2215  	typedef GOint64 = HaxeInt64abs;
  2216  
  2217  //**************** rewrite of std Haxe library function haxe.Int64 for PHP integer overflow an other errors
  2218  /*
  2219  Modify haxe.Int64.hx to work on php and fix other errors
  2220  - php integer overflow and ushr are incorrect (for 32-bits Int),
  2221  special functions now correct for these faults for Int64.
  2222  - both div and mod now have the sign correct when double-negative.
  2223  - special cases of div or mod by 0 or 1 now correct.
  2224  */
  2225  /*
  2226   * Copyright (C)2005-2012 Haxe Foundation
  2227   *
  2228   * Permission is hereby granted, free of charge, to any person obtaining a
  2229   * copy of this software and associated documentation files (the "Software"),
  2230   * to deal in the Software without restriction, including without limitation
  2231   * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  2232   * and/or sell copies of the Software, and to permit persons to whom the
  2233   * Software is furnished to do so, subject to the following conditions:
  2234   *
  2235   * The above copyright notice and this permission notice shall be included in
  2236   * all copies or substantial portions of the Software.
  2237   *
  2238   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  2239   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  2240   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  2241   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  2242   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  2243   * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  2244   * DEALINGS IN THE SOFTWARE.
  2245   */
  2246  class Int64 { 
  2247  
  2248  	var high : Int;
  2249  	var low : Int;
  2250  
  2251  	inline function new(high, low) {
  2252  		this.high = i32(high);
  2253  		this.low = i32(low);
  2254  	}
  2255  
  2256  	#if php
  2257  	/*
  2258  		private function to correctly handle 32-bit integer overflow on php 
  2259  		see: http://stackoverflow.com/questions/300840/force-php-integer-overflow
  2260  	*/
  2261  	private static function i32php(value:Int):Int { 
  2262  			value = (value & untyped __php__("0xFFFFFFFF"));
  2263   		    if ( (value & untyped __php__("0x80000000"))!=0 )
  2264  		        value = -(((~value) & untyped __php__("0xFFFFFFFF")) + 1);
  2265  		    return value;
  2266  	}
  2267  	#end
  2268  
  2269  	/*
  2270  		private function to correctly handle 32-bit ushr on php
  2271  		see: https://github.com/HaxeFoundation/haxe/commit/1a878aa90708040a41b0dd59f518d83b09ede209
  2272  	*/
  2273  	private static inline function ushr32(v:Int,n:Int):Int { 
  2274  		#if php
  2275  		 	return (v >> n) & (untyped __php__("0x7fffffff") >> (n-1));
  2276  		#else
  2277  			return v>>>n;
  2278  		#end
  2279  	}
  2280  
  2281  	@:extern static inline function i32(i) {
  2282  		return 
  2283  		#if !(cpp || java || cs || flash) 
  2284  			i==null?0:
  2285  		#end
  2286  		#if (js || flash8)
  2287  			i | 0;
  2288  		#elseif php
  2289  			i32php(i); // handle overflow of 32-bit integers correctly 
  2290  		#else
  2291  			i;
  2292  		#end
  2293  	}
  2294  
  2295  	@:extern static inline function i32mul(a:Int,b:Int) {
  2296  		#if (php || js || flash8)
  2297  		/*
  2298  			We can't simply use i32(a*b) since we might overflow (52 bits precision in doubles)
  2299  		*/
  2300  		return i32(i32((a * (b >>> 16)) << 16) + (a * (b&0xFFFF)));
  2301  		#else
  2302  		return a * b;
  2303  		#end
  2304  	}
  2305  	
  2306  	#if as3 public #end function toString() {
  2307  		if ((high|low) == 0 )
  2308  			return "0";
  2309  		var str = "";
  2310  		var neg = false;
  2311  		var i = this;
  2312  		if( isNeg(i) ) {
  2313  			neg = true;
  2314  			i = Int64.neg(i);
  2315  		}
  2316  		var ten = ofInt(10);
  2317  		while( !isZero(i) ) {
  2318  			var r = divMod(i, ten);
  2319  			str = r.modulus.low + str; 
  2320  			i = r.quotient; 
  2321  		}
  2322  		if( neg ) str = "-" + str;
  2323  		return str;
  2324  	}
  2325  
  2326  	public static inline function make( high : Int, low : Int ) : Int64 {
  2327  		return new Int64(high, low); 
  2328  	}
  2329  
  2330  	public static inline function ofInt( x : Int ) : Int64 {
  2331  		return new Int64(x >> 31,x);
  2332  	}
  2333  
  2334  	public static function toInt( x : Int64 ) : Int {
  2335  		if( x.high != 0 ) {
  2336  			if( x.high < 0 )
  2337  				return -toInt(neg(x));
  2338  			throw "Overflow"; //NOTE go panic not used here as it is in the Haxe libary code
  2339  		}
  2340  		return x.low; 
  2341  	}
  2342  
  2343  	public static function getLow( x : Int64 ) : Int {
  2344  		return x.low;
  2345  	}
  2346  
  2347  	public static function getHigh( x : Int64 ) : Int {
  2348  		return x.high;
  2349  	}
  2350  
  2351  	public static function add( a : Int64, b : Int64 ) : Int64 {
  2352  		var high = i32(a.high + b.high);
  2353  		var low = i32(a.low + b.low);
  2354  		if( uicompare(low,a.low) < 0 )
  2355  			high++;
  2356  		return new Int64(high, low);
  2357  	}
  2358  
  2359  	public static function sub( a : Int64, b : Int64 ) : Int64 {
  2360  		var high = i32(a.high - b.high); // i32() call required to match add
  2361  		var low = i32(a.low - b.low); // i32() call required to match add
  2362  		if( uicompare(a.low,b.low) < 0 )
  2363  			high--;
  2364  		return new Int64(high, low);
  2365  	}
  2366  
  2367  	public static function mul( a : Int64, b : Int64 ) : Int64 {
  2368  		var mask = 0xFFFF;
  2369  		var al = a.low & mask, ah = ushr32(a.low , 16); 
  2370  		var bl = b.low & mask, bh = ushr32(b.low , 16); 
  2371  		var p00 = al * bl;
  2372  		var p10 = ah * bl;
  2373  		var p01 = al * bh;
  2374  		var p11 = ah * bh;
  2375  		var low = p00;
  2376  		var high = i32(p11 + ushr32(p01 , 16) + ushr32(p10 , 16));
  2377  		p01 = i32(p01 << 16); low = i32(low + p01); if( uicompare(low, p01) < 0 ) high = i32(high + 1);
  2378  		p10 = i32(p10 << 16); low = i32(low + p10); if( uicompare(low, p10) < 0 ) high = i32(high + 1);
  2379  		high = i32(high + i32mul(a.low,b.high));
  2380  		high = i32(high + i32mul(a.high,b.low));
  2381  		return new Int64(high, low);
  2382  	}
  2383  
  2384  	static function divMod( modulus : Int64, divisor : Int64 ) {
  2385  		var quotient = new Int64(0, 0);
  2386  		var mask = new Int64(0, 1);
  2387  		divisor = new Int64(divisor.high, divisor.low);
  2388  		while( divisor.high >= 0 ) { 
  2389  			var cmp = ucompare(divisor, modulus);
  2390  			divisor.high = i32( i32(divisor.high << 1) | ushr32(divisor.low , 31) ); 
  2391  			divisor.low = i32(divisor.low << 1); 
  2392  			mask.high = i32( i32(mask.high << 1) | ushr32(mask.low , 31) ); 
  2393  			mask.low = i32(mask.low << 1);
  2394  			if( cmp >= 0 ) break;
  2395  		}
  2396  		while( i32(mask.low | mask.high) != 0 ) { 
  2397  			if( ucompare(modulus, divisor) >= 0 ) {
  2398  				quotient.high= i32(quotient.high | mask.high); 
  2399  				quotient.low= i32(quotient.low | mask.low); 
  2400  				modulus = sub(modulus,divisor);
  2401  			}
  2402  			mask.low = i32( ushr32(mask.low , 1) | i32(mask.high << 31) ); 
  2403  			mask.high = ushr32(mask.high , 1); 
  2404  
  2405  			divisor.low = i32( ushr32(divisor.low , 1) | i32(divisor.high << 31) ); 
  2406  			divisor.high = ushr32(divisor.high , 1); 
  2407  		}
  2408  		return { quotient : quotient, modulus : modulus };
  2409  	}
  2410  
  2411  	public static function div( a : Int64, b : Int64 ) : Int64 { 
  2412  		if(b.high==0) // handle special cases of 0 and 1
  2413  			switch(b.low) {
  2414  			case 0:	throw "divide by zero";  //NOTE go panic not used here as it is in the Haxe libary code
  2415  			case 1: return new Int64(a.high,a.low);
  2416  			} 
  2417  		var sign = ((a.high<0) || (b.high<0)) && (!( (a.high<0) && (b.high<0))); // make sure we get the correct sign
  2418  		if( a.high < 0 ) a = neg(a);
  2419  		if( b.high < 0 ) b = neg(b);
  2420  		var q = divMod(a, b).quotient;
  2421  		return sign ? neg(q) : q;
  2422  	}
  2423  
  2424  	public static function mod( a : Int64, b : Int64 ) : Int64 {
  2425  		if(b.high==0) // handle special cases of 0 and 1
  2426  			switch(b.low) {
  2427  			case 0:	throw "modulus by zero";  //NOTE go panic not used here as it is in the Haxe libary code
  2428  			case 1: return ofInt(0);
  2429  			}
  2430  		var sign = a.high<0; // the sign of a modulus is the sign of the value being mod'ed
  2431  		if( a.high < 0 ) a = neg(a);
  2432  		if( b.high < 0 ) b = neg(b);
  2433  		var m = divMod(a, b).modulus;
  2434  		return sign ? neg(m) : m;
  2435  	}
  2436  
  2437  	public static inline function shl( a : Int64, b : Int ) : Int64 {
  2438  		return if( b & 63 == 0 ) a else if( b & 63 < 32 ) new Int64( (a.high << b) | ushr32(a.low, i32(32-(b&63))), a.low << b ) else new Int64( a.low << i32(b - 32), 0 );
  2439  	}
  2440  
  2441  	public static inline function shr( a : Int64, b : Int ) : Int64 {
  2442  		return if( b & 63 == 0 ) a else if( b & 63 < 32 ) new Int64( a.high >> b, ushr32(a.low,b) | (a.high << i32(32 - (b&63))) ) else new Int64( a.high >> 31, a.high >> i32(b - 32) );
  2443  	}
  2444  
  2445  	public static inline function ushr( a : Int64, b : Int ) : Int64 {
  2446  		return if( b & 63 == 0 ) a else if( b & 63 < 32 ) new Int64( ushr32(a.high, b), ushr32(a.low, b) | (a.high << i32(32 - (b&63))) ) else new Int64( 0, ushr32(a.high, i32(b - 32)) );
  2447  	}
  2448  
  2449  	public static inline function and( a : Int64, b : Int64 ) : Int64 {
  2450  		return new Int64( a.high & b.high, a.low & b.low );
  2451  	}
  2452  
  2453  	public static inline function or( a : Int64, b : Int64 ) : Int64 {
  2454  		return new Int64( a.high | b.high, a.low | b.low );
  2455  	}
  2456  
  2457  	public static inline function xor( a : Int64, b : Int64 ) : Int64 {
  2458  		return new Int64( a.high ^ b.high, a.low ^ b.low );
  2459  	}
  2460  
  2461  	public static inline function neg( a : Int64 ) : Int64 {
  2462  		var high = i32(~a.high); 
  2463  		var low = i32(-a.low); 
  2464  		if( low == 0 )
  2465  			high++;
  2466  		return new Int64(high,low);
  2467  	}
  2468  
  2469  	public static inline function isNeg( a : Int64 ) : Bool {
  2470  		return a.high < 0;
  2471  	}
  2472  
  2473  	public static inline function isZero( a : Int64 ) : Bool {
  2474  		return (a.high | a.low) == 0;
  2475  	}
  2476  
  2477  	static function uicompare( a : Int, b : Int ) {
  2478  		return a < 0 ? (b < 0 ? i32(~b - ~a) : 1) : (b < 0 ? -1 : i32(a - b));
  2479  	}
  2480  
  2481  	public static inline function compare( a : Int64, b : Int64 ) : Int {
  2482  		var v = i32(i32(a.high) - i32(b.high)); 
  2483  		return if( v != 0 ) v else uicompare(a.low,b.low);
  2484  	}
  2485  
  2486  	/**
  2487  		Compare two Int64 in unsigned mode.
  2488  	**/
  2489  	public static inline function ucompare( a : Int64, b : Int64 ) : Int {
  2490  		var v = uicompare(a.high,b.high);
  2491  		return if( v != 0 ) v else uicompare(a.low, b.low);
  2492  	}
  2493  
  2494  	public static inline function toStr( a : Int64 ) : String {
  2495  		return a.toString();
  2496  	}
  2497  
  2498  }
  2499  //**************** END REWRITE of haxe.Int64 for php and to correct errors
  2500  
  2501  `)
  2502  	l.PogoComp().WriteAsClass("StackFrameBasis", `
  2503  
  2504  // GoRoutine 
  2505  class StackFrameBasis
  2506  {
  2507  public var _Next:Int=0;
  2508  public var _recoverNext:Null<Int>=null;
  2509  public var _incomplete:Bool=true;
  2510  public var _latestPH:Int=0;
  2511  public var _latestBlock:Int=0;
  2512  public var _functionPH:Int;
  2513  public var _functionName:String;
  2514  public var _goroutine(default,null):Int;
  2515  public var _bds:Array<Dynamic>; // bindings for closures
  2516  public var _deferStack:List<StackFrame>;
  2517  public var _debugVars:Map<String,Dynamic>;
  2518  #if godebug
  2519  	var _debugVarsLast:Map<String,Dynamic>;
  2520  	static var _debugBP:Map<Int,Bool>;
  2521  #end
  2522  
  2523  public function new(gr:Int,ph:Int,name:String){
  2524  	_goroutine=gr;
  2525  	_functionPH=ph;
  2526  	_functionName=name;
  2527  	#if godebug
  2528  		_debugVars=new Map<String,Dynamic>();
  2529  		_debugVarsLast= new Map<String,Dynamic>();
  2530  	#end
  2531  	this.setPH(ph); // so that we call the debugger, if it is enabled
  2532  	// TODO optionally profile function entry here
  2533  }
  2534  
  2535  public inline function nullOnExitSF(){
  2536  	#if nulltempvars
  2537  		_functionName=null;
  2538  		// TODO the next three items could be optimized to only be set to null on exit if they are used in a Go func
  2539  		_bds=null;
  2540  		_deferStack=null;
  2541  		_debugVars=null;
  2542  		#if godebug
  2543  			_debugVarsLast=null;
  2544  		#end
  2545  	#end
  2546  }
  2547  
  2548  public function setDebugVar(name:String,value:Dynamic){
  2549  	if(_debugVars==null) 
  2550  		_debugVars=new Map<String,Dynamic>();
  2551  	_debugVars.set(name,value);	
  2552  }
  2553  
  2554  public function setLatest(ph:Int,blk:Int){ // this can be done inline, but generates too much code
  2555  	_latestBlock=blk;
  2556  	this.setPH(ph);
  2557  	// TODO optionally profile block entry here
  2558  }
  2559  
  2560  public function breakpoint(){
  2561  	#if (godebug && (cpp || neko))
  2562  		trace("GODEBUG: runtime.Breakpoint()");
  2563  		_debugBP.set(_latestPH,true); // set a constant debug trap
  2564  		setPH(_latestPH); // run the debugger
  2565  	#else
  2566  		//trace("GODEBUG: runtime.Breakpoint() to run debugger (cpp/neko only) use: haxe -D godebug");
  2567  	#end
  2568  }
  2569  
  2570  public function setPH(ph:Int){
  2571  	_latestPH=ph;
  2572  	// TODO optionally profile instruction line entry here	
  2573  	// optionally add debugger code here, if the target supports Console.readln()
  2574  	#if (godebug && (cpp || neko))
  2575  		// TODO add support for: cs || java || php 
  2576  		if(_debugBP==null||_debugBP.exists(ph)){
  2577  			var stay=true;
  2578  			var ln:Null<String>;
  2579  			while(stay){
  2580  				printDebugState();
  2581  				ln=Console.readln();
  2582  				if(ln==null)
  2583  					stay=false; // effectively step a line 
  2584  				else {
  2585  					// debugger commands
  2586  					var fb=new Array<Dynamic>();
  2587  					var bits=ln.split(" ");
  2588  					switch(ln.charAt(0)){
  2589  					case "S","s","R","r":
  2590  						if(bits.length<3)
  2591  							fb[0]="please use the format: S/R filename linenumber";
  2592  						else{
  2593  							if(_debugBP==null){
  2594  								_debugBP=new Map<Int,Bool>();
  2595  							}
  2596  							var base=Go.getStartCPos(bits[1]);
  2597  							if(base==-1)
  2598  								fb[0]="sorry, can't find file: "+bits[1];
  2599  							else{
  2600  								var off=Std.parseInt(bits[2]);
  2601  								if(off==null)
  2602  									fb[0]="sorry, can't parseInt: "+bits[2];
  2603  								else{
  2604  									fb[0]="break-point ";
  2605  									switch(ln.charAt(0)){
  2606  									case "S","s":
  2607  										fb[1]="set";						
  2608  										_debugBP.set(base+off,true);
  2609  									case "R","r":
  2610  										fb[1]="removed";						
  2611  										if(_debugBP.exists(base+off))
  2612  											_debugBP.remove(base+off);
  2613  									}
  2614  									fb[2]=" at: "+Go.CPos(base+off);
  2615  								}
  2616  							}	
  2617  						}
  2618  					case "B","b":
  2619  						if(_debugBP==null){
  2620  							fb[0]="no break-points set";
  2621  						} else {
  2622  							fb[0]="break-points:\n";
  2623  							var ent=1;
  2624  							for(b in _debugBP.keys()){
  2625  								fb[ent]="\t"+Go.CPos(b)+"\n";
  2626  								ent+=1;
  2627  							}
  2628  						}							
  2629  					case "C","c":
  2630  						_debugBP=null;
  2631  						fb[0]="all break-points cleared";
  2632  					case "L","l":
  2633  						if(bits.length>=2)
  2634  							if(_debugVars.exists(bits[1])){
  2635  								var v:String;
  2636  								if(bits[1].indexOf(".")!=-1) // global
  2637  									v="global: "+_debugVars.get(bits[1]).toString();
  2638  								else
  2639  								 	v=Std.string(_debugVars.get(bits[1]));
  2640  								fb[0]="Local assignment to: "+bits[1]+" = "+v.substr(0,500);
  2641  							} else
  2642  								fb[0]="Can't find local assignment: "+bits[1];
  2643  						else{
  2644  							fb[0]="Local assignments:\n";
  2645  							var ent=1;
  2646  							for(b in _debugVars.keys()){
  2647  								if(b.indexOf(".")==-1) { // local
  2648  									fb[ent]="\t"+b+" = "+Std.string(_debugVars.get(b)).substr(0,500)+"\n";
  2649  									ent+=1;
  2650  								}	
  2651  							}
  2652  						}							
  2653  					case "G","g":
  2654  						if(bits.length<2)
  2655  							fb[0]="please use the format: G globalname ";
  2656  						else 
  2657  							fb[0]="Global: "+Go.getGlobal(bits[1]).substr(0,500);	
  2658  					case "M","m":
  2659  						if(bits.length<3)
  2660  							fb[0]="please use the format: M objectID offset ";
  2661  						else {
  2662  							var id=Std.parseInt(bits[1]);
  2663  							if(id==null)
  2664  									fb[0]="sorry, can't parseInt: "+bits[1];
  2665  							else{
  2666  								var off=Std.parseInt(bits[2]);
  2667  								if(off==null)
  2668  									fb[0]="sorry, can't parseInt: "+bits[2];
  2669  								else
  2670  									fb[0]="Memory: "+Object.memory.get(id).toString(off).substr(0,500);	
  2671  							}
  2672  						}
  2673  					case "D","d":
  2674  						fb[0]=Scheduler.stackDump();					
  2675  					case "P","p":
  2676  						Scheduler.panicFromHaxe("panic from debugger");					
  2677  						fb[0]="Panicing from debugger to exit program";
  2678  						_debugBP=new Map<Int,Bool>();
  2679  						_debugBP.set(-1,true); // unreachable break-point
  2680  						stay=false;
  2681  					case "X","x":
  2682  						//_debugBP=new Map<Int,Bool>();
  2683  						//_debugBP.set(-1,true); // unreachable break-point
  2684  						fb[0]="eXecute program";
  2685  						stay=false;
  2686  					default:
  2687  						fb[0]="commands: blank=step, B=BrakePointList, S/R=Set/RemoveBP name line, C=ClearAllBP, L=Local name, G=Global name, M=Memory id offset, D=stackDump, X=eXecute program, P=Panic (^C does not work)";
  2688  					}
  2689  					Console.println(fb);
  2690  				}
  2691  			}
  2692  		}
  2693  	#end
  2694  }
  2695  
  2696  #if godebug
  2697  public function printDebugState():Void{
  2698  	var guf=new Array<Dynamic>();
  2699  	var gc=1;
  2700  	guf[0]="GR:"+_goroutine+" - "+_functionName+" @ "+Go.CPos(_latestPH);
  2701  	for(k in _debugVars.keys()){
  2702  		if(_debugVars.get(k)!=_debugVarsLast.get(k)){
  2703  			if(k.indexOf(".")!=-1) // global
  2704  				guf[gc]="\n"+k+" = "+cast(_debugVars.get(k),Pointer).toString().substr(0,500);
  2705  			else
  2706  				guf[gc]="\n"+k+" = "+Std.string(_debugVars.get(k)).substr(0,500);
  2707  			gc+=1;
  2708  			_debugVarsLast.set(k,_debugVars.get(k));
  2709  		}
  2710  	}
  2711  	Console.println(guf);
  2712  }
  2713  #end
  2714  
  2715  public function defer(fn:StackFrame){
  2716  	if(_deferStack==null)
  2717  		_deferStack=new List<StackFrame>();
  2718  	_deferStack.add(fn); // add to the end of the list, so that runDefers() get them in the right order
  2719  }
  2720  
  2721  public function runDefers(){
  2722  	if(_deferStack!=null)
  2723  		while(!_deferStack.isEmpty()){
  2724  			Scheduler.push(_goroutine,_deferStack.pop());
  2725  		}
  2726  }
  2727  
  2728  }
  2729  `)
  2730  	l.PogoComp().WriteAsClass("StackFrame", `
  2731  
  2732  interface StackFrame
  2733  {
  2734  public var _Next:Int;
  2735  public var _recoverNext:Null<Int>;
  2736  public var _incomplete:Bool;
  2737  public var _latestPH:Int;
  2738  public var _latestBlock:Int;
  2739  public var _functionPH:Int;
  2740  public var _functionName:String;
  2741  public var _goroutine(default,null):Int;
  2742  public var _bds:Array<Dynamic>; // bindings for closures
  2743  public var _deferStack:List<StackFrame>;
  2744  public var _debugVars:Map<String,Dynamic>;
  2745  function run():StackFrame; // function state machine (set up by each Go function Haxe class)
  2746  function res():Dynamic; // function result (set up by each Go function Haxe class)
  2747  function nullOnExitSF():Void; // call this when exiting the function
  2748  function setDebugVar(name:String,value:Dynamic):Void;
  2749  }
  2750  `)
  2751  	l.PogoComp().WriteAsClass("Scheduler", `
  2752  
  2753  @:cppFileCode('extern "C" int tardisgo_timereventhandler(int rl) { tardis::Scheduler_obj::runLimit=rl; tardis::Scheduler_obj::timerEventHandler(0); return 0; }')
  2754  
  2755  @:keep
  2756  class Scheduler { // NOTE this code requires a single-thread, as there is no locking TODO detect deadlocks
  2757  // public
  2758  public static var doneInit:Bool=false; // flag to limit go-routines to 1 during the init() processing phase
  2759  // private
  2760  static var grStacks:Array<Array<StackFrame>>=new Array<Array<StackFrame>>(); 
  2761  static var grInPanic:Array<Bool>=new Array<Bool>();
  2762  static var grPanicMsg:Array<Interface>=new Array<Interface>();
  2763  static var panicStackDump:String="";
  2764  static var entryCount:Int=0; // this to be able to monitor the re-entrys into this routine for debug
  2765  static var currentGR:Int=0; // the current goroutine, used by Scheduler.panicFromHaxe(), NOTE this requires a single thread
  2766  
  2767  // if the scheduler is being run from a timer, this is where it comes to
  2768  public static var runLimit:Int=0;
  2769  public static function timerEventHandler(dummy:Dynamic) {
  2770  	if(runLimit<2) 
  2771  		runAll();
  2772  	else
  2773  		runToStasis(runLimit); 
  2774  }
  2775  
  2776  static inline function runToStasis(cyclesLimit:Int) {
  2777  	var lastHash:Int=0;
  2778  	var thisHash:Int=makeStateHash();
  2779  	var cycles:Int=0;
  2780  	while( lastHash!=thisHash && cycles<cyclesLimit ){
  2781  		lastHash = thisHash;
  2782  		runAll();
  2783  		thisHash = makeStateHash();
  2784  		cycles += 1;
  2785  	}
  2786  	//if(cycles<cyclesLimit)
  2787  	//	trace("Stasis achieved after "+cycles+" cycles");
  2788  	//else
  2789  	//	trace("Stasis not achieved");
  2790  }
  2791  
  2792  static inline function makeStateHash():Int { // TODO improve by checking for change on the fly?
  2793  	var numGR=grStacks.length;
  2794  	var hash:Int=numGR;
  2795  	for( gr in 0 ... numGR ){  
  2796  		var thisGR=grStacks[gr];
  2797  		var stacklen=thisGR.length;
  2798  		if( stacklen>0 ) {
  2799  			var top=thisGR[stacklen-1];
  2800  			hash+=stacklen+top._functionPH+top._Next;
  2801  		}
  2802  	}
  2803  	//trace("makeStateHash()="+hash);
  2804  	return hash;
  2805  }
  2806  
  2807  public static function runAll() { // this must be re-entrant, in order to allow Haxe->Go->Haxe->Go for some runtime functions
  2808  	var cg:Int=0; // reentrant current goroutine
  2809  	entryCount++;
  2810  	if(entryCount>2) { // this is the simple limit to runtime recursion  
  2811  		throw "Scheduler.runAll() entryCount exceeded - "+stackDump();
  2812  	}
  2813  
  2814  	var thisStack:Array<StackFrame>;
  2815  	var thisStackLen:Int;
  2816  
  2817  	// special handling for goroutine 0, which is used in the initialisation phase and re-entrantly, where only one goroutine may operate		
  2818  	thisStack=grStacks[0];
  2819  	thisStackLen=thisStack.length;
  2820  	if(thisStackLen==0) { // check if there is ever likley to be anything to do
  2821  		if(grStacks.length<=1) { 
  2822  			//throw "Scheduler: there is only one goroutine and its stack is empty\n"+stackDump();		
  2823  			return; // nothing to do...
  2824  		}
  2825  	} else { // run goroutine zero
  2826  		runOne(0,entryCount,thisStack,thisStackLen);
  2827  	}
  2828  
  2829  	if(doneInit && entryCount==1 ) {	 // don't run extra goroutines when we are re-entrant or have not finished initialistion
  2830  									     // NOTE this means that Haxe->Go->Haxe->Go code cannot run goroutines 
  2831  		var grStacksLen=grStacks.length;
  2832  		for(cg in 1...grStacksLen) { // length may grow during a run through, NOTE goroutine 0 not run again
  2833  			thisStack=grStacks[cg];
  2834  			thisStackLen=thisStack.length;
  2835  			if(thisStackLen>0) {
  2836  				runOne(cg,entryCount,thisStack,thisStackLen);
  2837  			}
  2838  		}
  2839  
  2840  		// prune the list of goroutines only at the end (goroutine numbers are in the stack frames, so can't be altered) 
  2841  		grStacksLen=grStacks.length;// there may be more goroutines than we started with
  2842  		if(grStacksLen>1) // we must always have goroutine 0
  2843  			if(grStacks[grStacksLen-1].length==0) 
  2844  				grStacks.pop();
  2845  	}
  2846  	#if nulltempvars
  2847  		thisStack=null; // for GC
  2848  	#end
  2849  	entryCount--;
  2850  }
  2851  static inline function runOne(gr:Int,entryCount:Int,thisStack:Array<StackFrame>,thisStackLen:Int){ // called from above to call individual goroutines TODO: Review for multi-threading
  2852  	if(grInPanic[gr]) {
  2853  		if(entryCount!=1) { // we are in re-entrant code, so we can't panic again, as this may be part of the panic handling...
  2854  				// NOTE this means that Haxe->Go->Haxe->Go code cannot use panic() reliably 
  2855  				run1a(gr,thisStack,thisStackLen);
  2856  		} else {
  2857  			while(grInPanic[gr]){
  2858  				if(grStacks[gr].length==0){
  2859  					 Console.naclWrite("Panic in goroutine "+gr+"\n"+panicStackDump); // use stored stack dump
  2860  					 throw "Go panic";
  2861  				} else {
  2862  					var sf:StackFrame=grStacks[gr].pop();
  2863  					if(sf._deferStack!=null)
  2864  						while(!sf._deferStack.isEmpty() && grInPanic[gr]) { 
  2865  							// NOTE this will run all of the defered code for a function, 
  2866  							// NOTE if recover() is encountered it should set grInPanic[gr] to false.
  2867  							// TODO consider merging code with RunDefers()
  2868  							var def:StackFrame=sf._deferStack.pop();
  2869  							//trace("DEBUG runOne panic defer:",def._functionName);
  2870  							Scheduler.push(gr,def);
  2871  							while(def._incomplete) 
  2872  								runAll(); // with entryCount >1, so run as above 
  2873  						}
  2874  					if(!grInPanic[gr]){
  2875  					 	//trace("DEBUG runOne panic - recovered");
  2876  						if(sf._recoverNext != null) {
  2877  						 	//trace("DEBUG runOne panic - running recovery code");
  2878  							sf._Next = sf._recoverNext; // set the re-entry point
  2879  						} 
  2880  						grStacks[gr].push(sf); // now run the recovery code
  2881  					}
  2882  					#if nulltempvars
  2883  						sf=null; // for GC
  2884  					#end
  2885  				}
  2886  			}
  2887  		}
  2888  	} else {
  2889  		run1a(gr,thisStack,thisStackLen);
  2890  	}
  2891  }
  2892  public static inline function run1a(gr:Int,thisStack:Array<StackFrame>,thisStackLen:Int){ 
  2893  	currentGR=gr;
  2894  	thisStack[thisStackLen-1].run();  
  2895  }
  2896  public static inline function run1(gr:Int){ // used by callFromRT() for every go function
  2897  	run1a(gr,grStacks[gr],grStacks[gr].length); // run() may call haxe which calls these routines recursively 
  2898  }
  2899  public static function makeGoroutine():Int {
  2900  	for (r in 1 ... grStacks.length) // goroutine zero is reserved for init activities, main.main() and Haxe call-backs
  2901  		if(grStacks[r].length==0)
  2902  		{
  2903  			grInPanic[r]=false;
  2904  			grPanicMsg[r]=null;
  2905  			return r;	// reuse a previous goroutine number if possible
  2906  		}
  2907  	var l:Int=grStacks.length;
  2908  	grStacks[l]=new Array<StackFrame>(); 
  2909  	grInPanic[l]=false;
  2910  	grPanicMsg[l]=null;
  2911  	return l;
  2912  }
  2913  public static inline function pop(gr:Int):StackFrame {
  2914  	return grStacks[gr].pop(); // NOTE removing old object pointer does not improve GC (tested 3 times)
  2915  }
  2916  public static inline function push(gr:Int,sf:StackFrame){
  2917  	grStacks[gr].push(sf);
  2918  }
  2919  public static inline function NumGoroutine():Int {
  2920  	return grStacks.length;
  2921  }
  2922  public static inline function ThisGoroutine():Int {
  2923  	return currentGR;
  2924  }
  2925  
  2926  public static function stackDump():String {
  2927  	var ret:String = "";
  2928  	var gr:Int;
  2929  	ret += "runAll() entryCount="+entryCount+"\n";
  2930  	for(gr in 0...grStacks.length) {
  2931  		ret += "---\nGoroutine " + gr + " "+grPanicMsg[gr]+"\n"; //may need to unpack the interface
  2932  		if(grStacks[gr].length==0) {
  2933  			ret += "Stack is empty\n";
  2934  		} else {
  2935  			ret += "Stack has " +grStacks[gr].length+ " entries:\n";
  2936  			var e = grStacks[gr].length -1;
  2937  			while( e >= 0){
  2938  				var ent = grStacks[gr][e];
  2939  				if(ent==null) {
  2940  					ret += "\tStack entry is null\n";
  2941  				} else {
  2942  					ret += "\t"+ent._functionName+" starting at "+Go.CPos(ent._functionPH);
  2943  					ret += " latest position "+Go.CPos(ent._latestPH);
  2944  					ret += " latest block "+ent._latestBlock+"\n";
  2945  					if(ent._debugVars!=null){
  2946  						for(k in ent._debugVars.keys()) {
  2947  							if(k.indexOf(".")==-1){ // not a global assignment, so showing only locals
  2948  								var t:Dynamic=ent._debugVars.get(k);
  2949  								if(t==null) t="nil";
  2950  								if(Std.is(t,Pointer)) t=t.toUniqueVal();
  2951  								ret += "\t\tvar "+k+" = "+t+"\n";
  2952  								#if nulltempvars
  2953  									t=null; // for GC
  2954  								#end
  2955  							}
  2956  						}
  2957  					}
  2958  				}
  2959  				#if nulltempvars
  2960  					ent=null; // for GC
  2961  				#end
  2962  				e -= 1;
  2963  			}
  2964  		}
  2965  	}
  2966  	return ret;
  2967  }
  2968  
  2969  public static function getNumCallers(gr:Int):Int {
  2970  	if(grStacks[gr].length==0) {
  2971  		return 0;
  2972  	} else {
  2973  		return grStacks[gr].length;
  2974  	}
  2975  }
  2976  
  2977  public static function getCallerX(gr:Int,x:Int):Int {
  2978  	if(grStacks[gr].length==0) {
  2979  		return 0; // error
  2980  	} else {
  2981  		var e = grStacks[gr].length -1;
  2982  		while(e >= 0){
  2983  			var ent=grStacks[gr][e];
  2984  			if(x==0) {
  2985  				if(ent==null) {
  2986  					return 0; // this is an error 
  2987  				} else {
  2988  					return ent._latestPH;
  2989  				}
  2990  			}
  2991  			#if nulltempvars
  2992  				ent=null; // for GC
  2993  			#end
  2994  			x -= 1;
  2995  			e -= 1;
  2996  		}
  2997  	}
  2998  	return 0; // error
  2999  }
  3000  
  3001  public static function traceStackDump() {trace(stackDump());}
  3002  
  3003  public static function panic(gr:Int,err:Interface){
  3004  	if(gr>=grStacks.length||gr<0)
  3005  		throw "Scheduler.panic() invalid goroutine";
  3006  	if(grInPanic[gr]) { // if we are already in a panic, not much we can do...
  3007  		//trace("Scheduler.panic() panic within panic for goroutine "+Std.string(gr)+" message: "+err.toString());		
  3008  	}else{
  3009  		grInPanic[gr]=true;
  3010  		grPanicMsg[gr]=err;
  3011  		panicStackDump=stackDump();
  3012  		#if godebug
  3013  			trace("GODEBUG: panic in goroutine "+Std.string(gr)+" message: "+err.toString());
  3014  			var top = grStacks[gr][grStacks[gr].length-1] //grStacks[gr].first();
  3015  			if(top!=null)
  3016  				cast(top,StackFrameBasis).breakpoint();
  3017  		#end
  3018  	} 
  3019  }
  3020  public static function recover(gr:Int):Interface{
  3021  	if(gr>=grStacks.length||gr<0)
  3022  		throw "Scheduler.recover() invalid goroutine";
  3023  	if(grInPanic[gr]==false)
  3024  		return null;
  3025  	#if godebug
  3026  		trace("GODEBUG: recover in goroutine "+Std.string(gr)+" message: "+grPanicMsg[gr]);
  3027  		var top = grStacks[gr][grStacks[gr].length-1] //grStacks[gr].first();
  3028  		if(top!=null)
  3029  			cast(top,StackFrameBasis).breakpoint();
  3030  	#end
  3031  	grInPanic[gr]=false;
  3032  	var t = grPanicMsg[gr];
  3033  	grPanicMsg[gr]=null;
  3034  	return t;
  3035  }
  3036  public static function panicFromHaxe(err:String) { 
  3037  	if(currentGR>=grStacks.length||currentGR<0) 
  3038  		// if current goroutine is -ve, or out of range, always panics in goroutine 0
  3039  		panic(0,new Interface(TypeInfo.getId("string"),"Runtime panic, unknown goroutine, "+err+" "));
  3040  	else
  3041  		panic(currentGR,new Interface(TypeInfo.getId("string"),"Runtime panic, "+err+" "));
  3042  	Console.naclWrite(panicStackDump); 
  3043  	throw "Haxe panic"; // NOTE can't be recovered!
  3044  }
  3045  public static function bbi() {
  3046  	panicFromHaxe("bad block ID (internal phi error)");
  3047  }
  3048  public static function ioor() {
  3049  	panicFromHaxe("index out of range");
  3050  }
  3051  public static function htc(c:Dynamic,pos:Int) {
  3052  	panicFromHaxe("Haxe try-catch exception <"+Std.string(c)+"> position "+Std.string(pos)+
  3053  		" at or before: "+Go.CPos(pos));
  3054  }
  3055  public static #if inlinepointers inline #end function wraprangechk(val:Int,sz:Int) {
  3056  	if((val<0)||(val>=sz)) ioor();
  3057  }
  3058  public static function unt():Dynamic {
  3059  		panicFromHaxe("nil interface target for method");	
  3060  		return null;
  3061  }
  3062  static function unp() {
  3063  		panicFromHaxe("unexpected nil pointer (ssa:wrapnilchk)");	
  3064  }
  3065  public static function wrapnilchk(p:Pointer):Pointer {
  3066  	if(p==null) unp();
  3067  	return p;
  3068  }
  3069  }
  3070  `)
  3071  	l.PogoComp().WriteAsClass("GOmap", `
  3072  
  3073  class GOmap {
  3074  	// TODO write a more sophisticated (and hopefully faster) version of this code 
  3075  	// TODO in Haxe, the keys can be Int, String or "object" (by reference)
  3076  	// TODO there is also a very sophisticated go implementation in runtime
  3077  
  3078  	public var baseMap:Map<String,{key:Dynamic,val:Dynamic}>;
  3079  	public var kz:Dynamic;
  3080  	public var vz:Dynamic;
  3081  
  3082  	public function new (kDef:Dynamic,vDef:Dynamic) {
  3083  		//trace("DEBUG new",kDef,vDef);
  3084  		baseMap = new Map<String,{key:Dynamic,val:Dynamic}>();
  3085  		kz = kDef;
  3086  		vz = vDef;
  3087  	}
  3088  
  3089  	#if cpp
  3090  		static var setDefaultFormat:Bool=true;
  3091  	#end
  3092  	public static function makeKey(a:Dynamic):String{
  3093  		#if cpp
  3094  			if(setDefaultFormat){ // TODO rewrite this so that we don't check every time
  3095  				cpp.Lib.setFloatFormat("%.17g");
  3096  				setDefaultFormat=false;
  3097  			}
  3098  		#end
  3099  		//trace("DEBUG makeKey",a);
  3100  		if(a==null) return "<<<<NULL>>>>"; // TODO how can this be more unique?
  3101  		if(Reflect.isObject(a)){
  3102  			if(Std.is(a,String))
  3103  				return a;
  3104  			if(Std.is(a,Pointer))
  3105  				return cast(a,Pointer).toUniqueVal();  
  3106  			// NOTE Object could be an abstract
  3107  			#if !abstractobjects
  3108  			if(Std.is(a,Object)){
  3109  				//trace("DEBUG makeKey Object found");
  3110  				var r=cast(a,Object).toString(); 
  3111  				//trace("DEBUG makeKey Object="+r);
  3112  				return r;
  3113  			}
  3114  			#end
  3115  			if(Std.is(a,Complex)){
  3116  				return Complex.toString(a);
  3117  			}
  3118  			if(Std.is(a,Interface))
  3119  				return cast(a,Interface).toString();
  3120  			if(Std.is(a,Slice)) 
  3121  				return a.toString();
  3122  			if(Std.is(a,Channel))
  3123  				return a.toString();
  3124  			if(Std.is(a,GOmap)||Std.is(a,Closure)) {
  3125  				Scheduler.panicFromHaxe("haxeruntime.GOmap.makeKey() unsupported haxe type: "+a);
  3126  				return "";
  3127  			}
  3128  			#if abstractobjects
  3129  				return a.toString(); // must be an Object or Int64
  3130  			#else
  3131  				return GOint64.toString(a);
  3132  			#end
  3133  		}
  3134  		#if cs			
  3135  			if(Std.is(a,Float)) {
  3136  				// in cpp & cs, Std.string(1.9999999999999998) => "2"
  3137  				// TODO consider how to deal with this issue in the compound types above
  3138  				return GOint64.toString(Go_haxegoruntime_FFloat64bits.callFromRT(0,a));
  3139  			}
  3140  		#end
  3141  		return Std.string(a);
  3142  	}
  3143  
  3144  	public function set(realKey:Dynamic,value:Dynamic){
  3145  		var sKey = makeKey(realKey);
  3146  		//trace("DEBUG set",sKey,realKey);
  3147  		if(baseMap.exists(sKey)){
  3148  			if(!Force.isEqualDynamic(baseMap.get(sKey).key,realKey))
  3149  				Scheduler.panicFromHaxe("haxeruntime.GOmap non-unique key for: "+sKey);
  3150  		}
  3151  		baseMap.set(sKey,{key:realKey,val:value});
  3152  	}
  3153  
  3154  	public function get(rKey:Dynamic):Dynamic {
  3155  		var sKey = makeKey(rKey);
  3156  		//trace("DEBUG get",sKey,rKey);		
  3157  		if(baseMap.exists(sKey))	return baseMap.get(sKey).val;
  3158  		else 						return vz; // the zero value
  3159  	}
  3160  
  3161  	public function exists(rKey:Dynamic):Bool {
  3162  		var sKey = makeKey(rKey);
  3163  		//trace("DEBUG exists",sKey,rKey);		
  3164  		return baseMap.exists(sKey);
  3165  	}
  3166  
  3167  	public function remove(r:Dynamic){
  3168  		var s = makeKey(r);
  3169  		//trace("DEBUG remove",s,r);		
  3170  		baseMap.remove(s);
  3171  	}
  3172  
  3173  	public function len():Int {
  3174  		var _l:Int=0;
  3175  		var _it=baseMap.iterator();
  3176  		while(_it.hasNext()) {_l++; _it.next();};
  3177  		//trace("DEBUG len",_l);		
  3178  		return _l;
  3179  	}
  3180  
  3181  	public function range():GOmapRange {
  3182  		var keys = new Array<String>();
  3183  		var k = baseMap.keys(); // in C# and Java, this may not work if new items are added to the map
  3184  		while(k.hasNext()) 
  3185  			keys.push(k.next());
  3186  		return new GOmapRange(keys,this);
  3187  	}
  3188  
  3189  }
  3190  `)
  3191  	l.PogoComp().WriteAsClass("GOmapRange", `
  3192  
  3193  class GOmapRange {
  3194  	private var k:Array<String>;
  3195  	private var m:GOmap;
  3196  
  3197  	public function new(kv:Array<String>, mv:GOmap){
  3198  		k=kv;
  3199  		m=mv;
  3200  	}
  3201  
  3202  	public function next():{r0:Bool,r1:Dynamic,r2:Dynamic} {
  3203  		var _hn:Bool=k.length>0;
  3204  		if(_hn){
  3205  			var _nxt=k.pop();
  3206  			if(m.baseMap.exists(_nxt))
  3207  				return {r0:true,r1:m.baseMap.get(_nxt).key,r2:m.baseMap.get(_nxt).val};
  3208  			else
  3209  				return next(); // recurse if this key is not found (deleted in-between?)
  3210  		}else{
  3211  			return {r0:false,r1:m.kz,r2:m.vz};
  3212  		}
  3213  	}
  3214  }
  3215  `)
  3216  	l.PogoComp().WriteAsClass("GOstringRange", `
  3217  
  3218  class GOstringRange {
  3219  	private var g:Int;
  3220  	private var k:Int;
  3221  	private var v:Slice;
  3222  
  3223  	public function new(gr:Int,s:String){
  3224  		g=gr;
  3225  		k=0;
  3226  		v=Force.toUTF8slice(gr,s);
  3227  	}
  3228  
  3229  	public function next():{r0:Bool,r1:Int,r2:Int} {
  3230  		var _thisK:Int=k;
  3231  		if(k>=v.len())
  3232  			return {r0:false,r1:0,r2:0};
  3233  		else {
  3234  			var _dr:{r0:Int,r1:Int}=Go_unicode_slsh_utf8_DDecodeRRune.callFromRT(g,v.subSlice(_thisK,-1));
  3235  			k+=_dr.r1;
  3236  			return {r0:true,r1:_thisK,r2:_dr.r0};
  3237  		}
  3238  	}
  3239  }
  3240  
  3241  
  3242  `)
  3243  
  3244  	return ""
  3245  }