diff --git a/src/hx/cppia/CppiaVars.cpp b/src/hx/cppia/CppiaVars.cpp index ad98ca47e..29bb1d4c8 100644 --- a/src/hx/cppia/CppiaVars.cpp +++ b/src/hx/cppia/CppiaVars.cpp @@ -227,7 +227,12 @@ Dynamic CppiaVar::setValue(hx::Object *inThis, Dynamic inValue) case fsInt: *(int *)(base) = inValue; return inValue; case fsBool: *(bool *)(base) = inValue; return inValue; case fsFloat: *(Float *)(base) = inValue; return inValue; - case fsString: *(String *)(base) = inValue; return inValue; + case fsString: + *(String *)(base) = inValue; + #ifdef HXCPP_GC_GENERATIONAL + HX_OBJ_WB_GET(inThis, hx::PointerOf(*(String *)(base))); + #endif + return inValue; case fsObject: switch(type->arrayType) { @@ -259,6 +264,10 @@ Dynamic CppiaVar::setValue(hx::Object *inThis, Dynamic inValue) *(Array *)(base) = inValue; break; } + // Every case above stores one object pointer at base. + #ifdef HXCPP_GC_GENERATIONAL + HX_OBJ_WB_GET(inThis, *(hx::Object **)(base)); + #endif return inValue; case fsUnknown: break; diff --git a/test/cppia/Client.hx b/test/cppia/Client.hx index 710373f4b..7a3944a2f 100644 --- a/test/cppia/Client.hx +++ b/test/cppia/Client.hx @@ -14,6 +14,13 @@ class ClientFoo implements IFoo { } } +class ClientHolder { + + public var values:Array; + + public function new() {} +} + class Client { public static var clientBool0 = true; diff --git a/test/cppia/cases/TestCommon.hx b/test/cppia/cases/TestCommon.hx index eaacb5a76..30cd0171c 100644 --- a/test/cppia/cases/TestCommon.hx +++ b/test/cppia/cases/TestCommon.hx @@ -1,6 +1,8 @@ package cases; import cpp.cppia.Host; +import cpp.vm.Gc; +import cpp.vm.WeakRef; import utest.Test; import utest.Assert; @@ -59,6 +61,27 @@ class TestCommon extends Test { Assert.equals(2, Common.callbackSet, 'Bad cppia closure'); } + @:depends(testStatus) + function testSetFieldOfOldObject() { + final holder = Type.createInstance(Type.resolveClass('ClientHolder'), []); + + // Full collections make the holder old: a generational collection no longer traverses it. + for (_ in 0...3) { + Gc.run(true); + } + final values = setValues(holder); + Gc.run(false); + + Assert.notNull(values.get(), 'Freed a value set by name on an old object'); + } + + // Only a weak reference to the value leaves this frame, so that the stack does not keep it. + static function setValues(holder:Dynamic):WeakRef> { + final values = [42]; + Reflect.setField(holder, 'values', values); + return new WeakRef(values); + } + @:depends(testStatus) function testInterfaceCalling() { final obj : IFoo = Type.createInstance(Type.resolveClass('ClientFoo'), []); diff --git a/test/cppia/compile-host.hxml b/test/cppia/compile-host.hxml index 76bf2d790..051e26186 100644 --- a/test/cppia/compile-host.hxml +++ b/test/cppia/compile-host.hxml @@ -1,6 +1,7 @@ -m CppiaHost HostExtendedRoot -D scriptable +-D HXCPP_GC_GENERATIONAL -D dll_export=host_classes.info -L utest --dce no