Update Files

This commit is contained in:
2025-01-22 16:18:30 +01:00
parent ed4603cf95
commit a36294b518
16718 changed files with 2960346 additions and 0 deletions

View File

@ -0,0 +1,66 @@
class TestIntHash extends haxe.unit.TestCase
{
function spamAlot()
{
var values = new Array< Null<Int> >();
values[0] = null;
var h = new Map<Int,Int>();
for(i in 0...2000)
{
for(j in 0...2000)
{
var idx = Std.int(Math.random()*2999);
if (h.get(idx)!=values[idx])
throw "Bad value";
if ( (i % 4)== 1 || Math.random()>0.5 )
{
if (h.remove(idx) != (values[idx]!=null))
throw "Error in remove!";
values[idx] = null;
}
else
{
h.set(idx,j);
values[idx] = j;
}
}
var keys = h.keys();
var keyed = new Array<Bool>();
for(i in 0...values.length)
keyed[i] = false;
for( key in h.keys())
keyed[ key ] = true;
for(i in 0...values.length)
if (keyed[i]!=(values[i]!=null))
throw "Bad value";
var valued = new Array<Int>();
for( val in h.iterator())
valued[val]++;
for(val in values)
if (val!=null)
{
if (valued[val]<1)
throw "Not valued!";
valued[val]--;
}
}
}
public function test()
{
var err = "";
try
{
spamAlot();
}
catch(e:String)
{
err = e;
}
assertTrue(err=="");
}
}

View File

@ -0,0 +1,49 @@
private enum GnarlyEnum
{
e0;
GnarlyEnum;
narlyEnum;
Dynamic;
getFixed(i:Int);
getInt;
init(i:Int);
String;
index(i:Int);
const;
super(i:Int);
tag(i:Int);
getTag(i:Int);
getObject(i:Int);
}
class TestKeywords extends haxe.unit.TestCase
{
public function new() super();
//public function getGnarly() { return GnarlyEnum.super(1); }
public function getGnarly() { return Dynamic; }
public function testEnum()
{
var count =
switch( getGnarly() )
{
case e0: 1;
//case GnarlyEnum: 1;
case narlyEnum: 1;
case Dynamic: 3;
case getFixed(i): 1;
case getInt: 1;
case init(i): 1;
case String: 1;
case index(i): 1;
case const: 1;
//case GnarlyEnum.super(i): 2;
case tag(i): 1;
case getTag(i): 1;
case getObject(i): 1;
default: 0;
}
assertTrue(count==3);
}
}

View File

@ -0,0 +1,76 @@
package;
import gc.TestGC;
class TestMain #if nme extends nme.display.Sprite #end {
static function runTests():Int
{
var passes = 1;
#if !nme
var args = Sys.args();
if (args.length>0)
passes = Std.parseInt(args[0]);
#end
var r = new haxe.unit.TestRunner();
r.add(new TestTypes());
r.add(new TestKeywords());
r.add(new TestSort());
r.add(new TestGC());
#if !nme
r.add(new gc.TestGCThreaded());
#end
r.add(new TestIntHash());
r.add(new TestStringHash());
r.add(new TestObjectHash());
r.add(new TestWeakHash());
#if !nme
r.add(new file.TestFile());
#end
#if cpp
r.add(new native.TestFinalizer());
#end
for(i in 0...passes)
{
var t0 = haxe.Timer.stamp();
var success = r.run();
trace(" Time : " + (haxe.Timer.stamp()-t0)*1000 );
if (!success)
return 1;
}
return 0;
}
#if nme
var frameCount = 0;
var tf:nme.text.TextField;
public function new()
{
super();
tf = new nme.text.TextField();
tf.text="RUN...";
addChild(tf);
addEventListener( nme.events.Event.ENTER_FRAME, onFrame );
}
function onFrame(_)
{
var err = runTests();
tf.text = "" + (++frameCount);
stage.opaqueBackground = err==0 ? 0xff00ff00: 0xffff0000;
}
static function endTest(error:Int) trace(error==0 ? "All tests OK" : "Tests Failed!");
#else
public static function main()
{
Sys.exit(runTests());
}
public static function endTest(error:Int) Sys.exit(error);
#end
}

View File

@ -0,0 +1,91 @@
class ObjectData
{
public var id:Int;
public function new(inId:Int) id = inId;
}
class TestObjectHash extends haxe.unit.TestCase
{
function spamAlot()
{
var values = new Array< Null<Int> >();
values[0] = null;
var h = new Map<ObjectData,Int>();
var idxToKey = new Array<ObjectData>();
for(idx in 0...3000)
idxToKey[idx] = new ObjectData(idx);
for(i in 0...2000)
{
for(j in 0...2000)
{
var idxInt = Std.int(Math.random()*2999);
var idx = idxToKey[idxInt];
if (h.get(idx)!=values[idxInt])
{
throw "Bad value";
}
if ( (i % 4)== 1 || Math.random()>0.5 )
{
if (h.remove(idx) != (values[idxInt]!=null))
{
trace("Bad remove");
throw "Error in remove!";
}
values[idxInt] = null;
}
else
{
h.set(idx,j);
values[idxInt] = j;
}
}
var keys = h.keys();
var keyed = new Array<Bool>();
for(i in 0...values.length)
keyed[i] = false;
for( key in h.keys())
{
var idxInt = key.id;
keyed[ idxInt ] = true;
}
for(i in 0...values.length)
if (keyed[i]!=(values[i]!=null))
throw "Bad value";
var valued = new Array<Int>();
#if neko
valued[3000]=0;
for(i in 0...3000)
valued[i] = 0;
#end
for( val in h.iterator())
valued[val]++;
for(val in values)
if (val!=null)
{
if (valued[val]<1)
throw "Not valued!";
valued[val]--;
}
}
}
public function test()
{
var err = "";
try
{
spamAlot();
}
catch(e:Dynamic)
{
trace(e);
err = e;
}
assertTrue(err=="");
}
}

View File

@ -0,0 +1,60 @@
class SortData
{
public var value:Int;
public var id:Int;
static var ids = 0;
public function new()
{
value = Std.int(Math.random()*500);
id = ids++;
}
}
class TestSort extends haxe.unit.TestCase
{
public function testObjects()
{
var tests = new Array<SortData>();
for(i in 0...100000)
tests.push( new SortData() );
var sorted = tests.copy();
sorted.sort( function(a,b) return a.value - b.value );
for(i in 1...sorted.length)
{
if (sorted[i].value < sorted[i-1].value)
throw "Index out of order";
if (sorted[i].value == sorted[i-1].value &&
sorted[i].id <= sorted[i-1].id )
throw "Not stable sort";
}
var sorted = tests.copy();
var compares = 0;
sorted.sort( function(a,b) {
// Churn some GC
var array = new Array<Int>();
compares++;
array.push(a.value);
array.push(b.value);
return array[0] < array[1] ? 1 : array[0] > array[1] ? -1 : 0;
});
//Sys.println("\nCompares per log elements:" + (compares/(tests.length*Math.log(tests.length))));
for(i in 1...sorted.length)
{
if (sorted[i].value > sorted[i-1].value)
throw "Index out of order";
if (sorted[i].value == sorted[i-1].value &&
sorted[i].id <= sorted[i-1].id )
throw "Not stable sort";
}
assertTrue(true);
}
}

View File

@ -0,0 +1,88 @@
class TestStringHash extends haxe.unit.TestCase
{
function spamAlot()
{
var values = new Array< Null<Int> >();
values[0] = null;
var h = new Map<String,Int>();
var idxToKey = new Array<String>();
for(idx in 0...3000)
idxToKey[idx] = Std.string(idx);
for(i in 0...2000)
{
for(j in 0...2000)
{
var idxInt = Std.int(Math.random()*2999);
var idx = idxToKey[idxInt];
if (h.get(idx)!=values[idxInt])
{
throw "Bad value";
}
if ( (i % 4)== 1 || Math.random()>0.5 )
{
if (h.remove(idx) != (values[idxInt]!=null))
{
trace("Bad remove");
throw "Error in remove!";
}
values[idxInt] = null;
}
else
{
h.set(idx,j);
values[idxInt] = j;
}
}
var arr = [0,1,2];
var keys = h.keys();
// Empty allocations can mess with the GC nursery
cpp.NativeArray.setSize(arr,0);
cpp.NativeArray.setSize(arr,3);
var keyed = new Array<Bool>();
for(i in 0...values.length)
keyed[i] = false;
for( key in h.keys())
{
var idxInt = Std.parseInt(key);
keyed[ idxInt ] = true;
}
for(i in 0...values.length)
if (keyed[i]!=(values[i]!=null))
throw "Bad value";
var valued = new Array<Int>();
#if neko
valued[3000]=0;
for(i in 0...3000)
valued[i] = 0;
#end
for( val in h.iterator())
valued[val]++;
for(val in values)
if (val!=null)
{
if (valued[val]<1)
throw "Not valued!";
valued[val]--;
}
}
}
public function test()
{
var err = "";
try
{
spamAlot();
}
catch(e:Dynamic)
{
trace(e);
err = e;
}
assertTrue(err=="");
}
}

View File

@ -0,0 +1,49 @@
class TestTypes extends haxe.unit.TestCase
{
var i0:Int = 1;
var i1:cpp.Int32 = 1;
var i2:cpp.UInt32 = 1;
var i3:cpp.Int64 = 1;
var i4:cpp.UInt64 = 1;
var i5:cpp.Int8 = 1;
var i6:cpp.UInt8 = 1;
var i7:cpp.Int16 = 1;
var i8:cpp.UInt16 = 1;
public function new() super();
function stringToCcs(string:String) : cpp.ConstCharStar
{
return string;
}
function ccsToString(ccs:cpp.ConstCharStar) : String
{
return ccs;
}
function ccsToStringCast(ccs:cpp.ConstCharStar) : String
{
return cast ccs;
}
public function testConstCharStar()
{
var ccs = stringToCcs("hello");
assertTrue( ccsToString(ccs)=="hello" );
assertTrue( ccsToStringCast(ccs)=="hello" );
}
public function testDynamic()
{
var d:Dynamic = this;
assertTrue(d.i0==1);
assertTrue(d.i1==1);
assertTrue(d.i2==1);
assertTrue(d.i3==1);
assertTrue(d.i4==1);
assertTrue(d.i5==1);
assertTrue(d.i6==1);
assertTrue(d.i7==1);
}
}

View File

@ -0,0 +1,93 @@
import haxe.ds.WeakMap;
class WeakObjectData
{
public var id:Int;
public function new(inId:Int) id = inId;
public function toString() return "Data " + id;
}
class TestWeakHash extends haxe.unit.TestCase
{
var retained:Array<WeakObjectData>;
function createMap(inCount:Int)
{
retained = [];
var map = new WeakMap<WeakObjectData,Int>();
for(i in 0...inCount)
{
var obj = new WeakObjectData(i);
if ( (i&1)==0 )
retained.push(obj);
map.set(obj,i);
}
return map;
}
function createMapDeep(inDepth:Int, inCount:Int)
{
if (inDepth<1)
return createMap(inCount);
return createMapDeep(inDepth-1, inCount);
}
function checkMap(map:WeakMap<WeakObjectData,Int>, expect:Int)
{
var valid = 0;
var oddFound = 0;
for(k in map.keys())
{
if( (k.id&1)!= 0)
{
oddFound ++;
//throw "Odd retained " + k.id;
}
else
valid++;
}
// There may be one or two values lurking on the stack, which is conservatively marked
if (oddFound>2)
trace("Too many odd values retained " + oddFound);
if (!(valid>=expect && valid<expect+2))
trace("WeakHash invalid range "+ expect + "..." + valid + "..." + (expect+2) );
assertTrue(valid>=expect && valid<expect+2);
}
function deepCheckMap(inDepth:Int, map:WeakMap<WeakObjectData,Int>, expect:Int)
{
if (inDepth<1)
checkMap(map,expect);
else
deepCheckMap(inDepth-1, map, expect);
}
function deepClearRetained(inRecurse:Int)
{
if (inRecurse>0)
deepClearRetained(inRecurse-1);
else
retained = [];
}
public function test()
{
var err = "";
try
{
var map = createMapDeep(20,1000);
cpp.vm.Gc.run(true);
deepCheckMap(10,map,500);
deepClearRetained(10);
cpp.vm.Gc.run(true);
checkMap(map,0);
}
catch(e:String)
{
trace(e);
err = e;
}
assertTrue(err=="");
}
}

View File

@ -0,0 +1,5 @@
-cpp bin
-main TestMain
-resource TestMain.hx
-D HXCPP_GC_GENERATIONAL
-cp ../unit

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<project>
<meta
title="GCTests"
package="org.haxe.hxcpp.gctest"
version="1.0.0"
company="haxefoundation"
/>
<app
file="TestMain"
main="TestMain"
/>
<window
width="640"
height="480"
orientation="landscape"
fps="60"
background="0xeeeeee"
require_shaders="true"
resizable="true"
hardware="true"
/>
<haxelib name="nme" />
<haxedef name="HXCPP_GC_GENERATIONAL" />
<haxedef name="HXCPP_DEBUG_LINK" />
<haxeflag name="-resource TestMain.hx" />
<cp path="../unit" />
</project>

View File

@ -0,0 +1,10 @@
package file;
class TestFile extends haxe.unit.TestCase
{
public function testGetContentEmptyFile()
{
assertEquals('', sys.io.File.getContent('./file/empty.txt'));
}
}

View File

@ -0,0 +1,102 @@
package gc;
class TestBigStack
{
var refs:Array<TestBigStack>;
var self:TestBigStack;
public function new()
{
refs = [];
self = this;
}
function check()
{
if (self!=this)
throw("Bad self reference");
}
function checkRec()
{
if (self!=this)
throw("Bad self reference");
for(r in refs)
r.checkRec();
}
function runRec(depth:Int)
{
var d = depth-1;
if (d==0)
return this;
var b0 = new TestBigStack().runRec(d);
var b1 = new TestBigStack().runRec(d);
var b2 = new TestBigStack().runRec(d);
var b3 = new TestBigStack().runRec(d);
var b4 = new TestBigStack().runRec(d);
var b5 = new TestBigStack().runRec(d);
var b6 = new TestBigStack().runRec(d);
var b7 = new TestBigStack().runRec(d);
var b8 = new TestBigStack().runRec(d);
var b9 = new TestBigStack().runRec(d);
var b10 = new TestBigStack().runRec(d);
var b11 = new TestBigStack().runRec(d);
var b12 = new TestBigStack().runRec(d);
var b13 = new TestBigStack().runRec(d);
var b14 = new TestBigStack().runRec(d);
var b15 = new TestBigStack().runRec(d);
var b16 = new TestBigStack().runRec(d);
var b17 = new TestBigStack().runRec(d);
var b18 = new TestBigStack().runRec(d);
var b19 = new TestBigStack().runRec(d);
refs.push(b0);
b0.check();
b1.check();
b2.check();
b3.check();
b4.check();
b5.check();
b6.check();
b7.check();
b8.check();
b9.check();
b10.check();
b11.check();
b12.check();
b13.check();
b14.check();
b15.check();
b16.check();
b17.check();
b18.check();
b19.check();
return this;
}
function run(passes:Int, depth:Int)
{
for(p in 0...passes)
{
//if ( (p%1000)==0 )
// Sys.println('Pass $p...');
refs = [];
runRec(depth);
checkRec();
}
}
public static function test() : Bool
{
try {
var b = new TestBigStack();
b.run(5000,5);
return true;
}
catch(e:Dynamic)
{
return false;
}
}
}

View File

@ -0,0 +1,129 @@
package gc;
import haxe.io.Bytes;
import cpp.vm.Gc;
class CustomObject {
public function new():Void {}
}
class TestGC extends haxe.unit.TestCase {
function createDummy(val:Dynamic):Dynamic {
return { dummy: val };
}
function gc():Dynamic {
Gc.run(true);
return Gc.getNextZombie();
}
/**
For avoiding the simple call being optimized in some way.
*/
function create(f:Void->Void):Void {
f();
clearStack(10);
}
function clearStack(count:Int, ?nothing:Dynamic):Dynamic
{
if (count==0)
return 0;
return clearStack(count-1);
}
function createAbc():Void {
var object = { test: "abc" };
Gc.doNotKill(object);
}
public function testObject():Void {
create(createAbc);
var zombie = gc();
assertTrue(zombie != null);
assertEquals("abc", zombie.test);
assertTrue(gc() == null);
}
// Null<int> for numbers < 256 are special cases
// Infact, there are no guarantees that Null<Int> will be actual objects in the future
/*
function create1234():Void {
var object:Null<Int> = 1234;
Gc.doNotKill(object);
};
public function testBoxedInt():Void {
create(create1234);
var zombie:Dynamic = gc();
assertTrue(zombie != null);
assertEquals(1234, zombie);
assertTrue(gc() == null);
}
*/
function createFunction():Void {
var object = function() return "abc";
Gc.doNotKill(object);
};
public function testFunc():Void {
create(createFunction);
var zombie = gc();
assertTrue(zombie != null);
assertEquals("abc", zombie());
assertTrue(gc() == null);
}
function createCustom():Void {
var object = new CustomObject();
Gc.doNotKill(object);
};
public function testCustomObject():Void {
create(createCustom);
var zombie = gc();
assertTrue(zombie != null);
assertTrue(Std.isOfType(zombie, CustomObject));
assertTrue(gc() == null);
}
function createBytes():Void {
var object = Bytes.alloc(1);
Gc.doNotKill(object);
};
public function testBytes():Void {
create(createBytes);
var zombie = gc();
assertTrue(zombie != null);
assertTrue(Std.isOfType(zombie, Bytes));
assertTrue(gc() == null);
}
public function testBigStack():Void {
assertTrue( TestBigStack.test() );
}
#if !cppia
public function testConstStrings():Void {
// Const strings void Gc overhead
var strings = new Array<String>();
strings.push( haxe.Resource.getString("TestMain.hx") );
strings.push( "some string" );
var chars = "abc123";
// Optimization for single chars...
for(c in 0...chars.length)
strings.push( chars.substr(c,1) );
for(string in strings)
assertTrue( untyped __global__.__hxcpp_is_const_string(string) );
Gc.run(true);
for(string in strings)
assertTrue( untyped __global__.__hxcpp_is_const_string(string) );
var strings = new Array<String>();
strings.push( haxe.Resource.getString("TestMain.hx").substr(10) );
strings.push( "some string" + chars );
for(c in 0...chars.length-1)
strings.push( chars.substr(c,2) );
for(string in strings)
assertFalse( untyped __global__.__hxcpp_is_const_string(string) );
}
#end
}

View File

@ -0,0 +1,134 @@
package gc;
import haxe.io.Bytes;
import haxe.crypto.Md5;
import cpp.vm.Gc;
import sys.io.File;
#if haxe4
import sys.thread.Thread;
#else
import cpp.vm.Thread;
#end
class Wrapper
{
public var a:Int;
public function new(inA:Int) a = inA;
}
@:cppInclude("./ZoneTest.cpp")
@:depend("./ZoneTest.cpp")
class TestGCThreaded extends haxe.unit.TestCase
{
@:keep
static var keepRunning = false;
@:keep
static var nativeRunning = false;
var bigText:String;
override public function setup()
{
var lines = [ for(i in 0...100000) "abc123\n" ];
#if nme
bigText = lines.join("");
#else
File.saveContent( "gc/big.txt", lines.join("") );
#end
}
public function testThreadOnce():Void
{
startNative();
doThreadedWork(4,100);
stopNative();
assertTrue(true);
}
public function testThreadMany():Void
{
startNative();
for(i in 0...10)
#if nme
doThreadedWork(4,100);
#else
doThreadedWork(100,100);
#end
stopNative();
assertTrue(true);
}
@:native("nativeLoop")
extern static function nativeLoop() : Void;
function startNative()
{
Thread.create( () -> {
nativeRunning = true;
keepRunning = true;
nativeLoop();
});
}
function stopNative()
{
keepRunning = false;
while(nativeRunning)
Sys.sleep(0.1);
}
function doThreadedWork(numThreads, numWork):Void
{
var threads:Array<Thread> = makeThreads(numThreads);
for (i in 0...numWork)
threads[i % threads.length].sendMessage('doWork');
for (i in 0...numThreads)
{
threads[i].sendMessage('exit');
Thread.readMessage(true);
}
}
function makeThreads(numThreads:Int):Array<Thread>
{
#if nme
var text:String = bigText;
#else
var text:String = File.getContent("gc/big.txt");
#end
var main:Thread = Thread.current();
var threads:Array<Thread> = [];
for (i in 0...numThreads)
{
threads.push( Thread.create(function() {
while(true) {
var message:Dynamic = Thread.readMessage(true);
if(message == 'exit')
break;
else
Md5.encode(text);
var arrays = new Array<Array<Wrapper>>();
for(i in 0...100)
{
var wrappers = new Array<Wrapper>();
arrays.push(wrappers);
for(j in 0...1000)
wrappers.push( new Wrapper(1) );
}
var sum = 0;
for(a in arrays)
for(w in a)
sum += w.a;
assertTrue(sum==100000);
}
main.sendMessage('done');
}) );
}
return threads;
}
}

View File

@ -0,0 +1,15 @@
void nativeLoop()
{
while( gc::TestGCThreaded_obj::keepRunning)
{
for(int i=0; i<100; i++)
::gc::Wrapper_obj::__alloc( HX_CTX_GET ,1);
::Sys_obj::sleep(0.01);
}
gc::TestGCThreaded_obj::nativeRunning = false;
}

View File

@ -0,0 +1,149 @@
package native;
@:native("ExternStruct")
extern class ExternStruct
{
@:native("~ExternStruct")
public function destroy():Void;
@:native("new ExternStruct")
public static function create():cpp.Pointer<ExternStruct>;
}
#if !cppia
@:headerCode('
struct ExternStruct {
ExternStruct() { }
~ExternStruct() { }
};
')
class ExternWrapper
{
var pointer:cpp.Pointer<ExternStruct>;
public static var instances:Int = 0;
public function new()
{
pointer = ExternStruct.create();
instances++;
cpp.vm.Gc.setFinalizer(this, cpp.Function.fromStaticFunction(destroy));
}
@:void static public function destroy(ExternWrapper : ExternWrapper) : Void {
instances--;
ExternWrapper.pointer.destroy();
}
}
class CustomFinalizable
{
public static var count = 0;
public function new()
{
cpp.vm.Gc.setFinalizer(this, cpp.Function.fromStaticFunction(__finalizeCallback));
}
function __finalize() : Void count++;
@:void public static function __finalizeCallback(o : CustomFinalizable) : Void
{
if(o != null)
o.__finalize();
else
Sys.println("Null callback object?");
}
}
#end
class MyFinalizable extends cpp.Finalizable
{
public static var count = 0;
public function new()
{
super();
}
override public function finalize()
{
count ++;
}
}
class TestFinalizer extends haxe.unit.TestCase
{
override public function setup()
{
MyFinalizable.count = 0;
CustomFinalizable.count = 0;
}
#if !cppia
function createExternWrapper(i:Int)
{
if (i<=0)
new ExternWrapper();
else
createExternWrapper(i-1);
}
public function testCount()
{
for(i in 0...10)
{
createExternWrapper(2);
cpp.vm.Gc.run(true);
}
Sys.println("\nExtern instances remaining:" + ExternWrapper.instances);
assertTrue( ExternWrapper.instances < 10 );
}
function createCustomFinalizable(i:Int)
{
if (i<=0)
new CustomFinalizable();
else
createCustomFinalizable(i-1);
}
public function testCustomFinalizable()
{
for(i in 0...100)
createCustomFinalizable(2);
cpp.vm.Gc.run(true);
Sys.println("custom cleared:" + CustomFinalizable.count);
assertTrue(CustomFinalizable.count>0);
}
#end
function createMyFinalizable(i:Int)
{
if (i<=0)
new MyFinalizable();
else
createMyFinalizable(i-1);
}
public function testFinalizable()
{
for(i in 0...100)
createMyFinalizable(2);
cpp.vm.Gc.run(true);
Sys.println("MyFinalizable cleared:" + MyFinalizable.count);
assertTrue(MyFinalizable.count>0);
}
}