diff --git a/extra/CHANGES.txt b/extra/CHANGES.txt index 6aa74bf9924..ffd5659ad0f 100644 --- a/extra/CHANGES.txt +++ b/extra/CHANGES.txt @@ -56,6 +56,8 @@ all : [std] allow setting haxe.Exception.stack (#12213) all : [std] Serializer: implement reset method (#12068) all : [std] use Vectors in haxe.zip (#11034) + all : [std] add haxe.IHandle interface (#12766) + all : [std] add haxe.GcFinalizer with handle-based API (#12766) all : [messageReparting] pretty errors as default message reporting (#11587) all : [messageReporting] add config to use absolute positions (#11439) all : [display] diagnostics as json rpc (#11412) diff --git a/std/cpp/_std/haxe/GcFinalizer.hx b/std/cpp/_std/haxe/GcFinalizer.hx new file mode 100644 index 00000000000..06914a300c8 --- /dev/null +++ b/std/cpp/_std/haxe/GcFinalizer.hx @@ -0,0 +1,91 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package haxe; + +import haxe.atomic.AtomicBool; + +private class Registration { + public var heldValue:Null; + public var callback:NullVoid>; + public var cancelled:AtomicBool; + public var weakTarget:cpp.vm.WeakRef; + + public function new(target:Dynamic, heldValue:T, callback:T->Void) { + this.weakTarget = new cpp.vm.WeakRef(target); + this.heldValue = heldValue; + this.callback = callback; + this.cancelled = new AtomicBool(false); + } +} + +private class Handle implements IHandle { + var reg:Registration; + + public function new(reg:Registration) { + this.reg = reg; + } + + public function close():Void { + if (reg.cancelled.compareExchange(false, true) == false) { + reg.callback = null; + reg.heldValue = null; + } + } +} + +@:coreApi +class GcFinalizer { + var callback:T->Void; + var registrations:Array>; + + public function new(callback:T->Void) { + this.callback = callback; + this.registrations = []; + } + + function pollQueue():Void { + var i = registrations.length - 1; + while (i >= 0) { + var reg = registrations[i]; + if (reg.weakTarget.get() == null) { + if (reg.cancelled.compareExchange(false, true) == false) { + reg.callback(reg.heldValue); + reg.callback = null; + reg.heldValue = null; + } + registrations.splice(i, 1); + } else if (reg.cancelled.load()) { + // close() already nulled fields + registrations.splice(i, 1); + } + i--; + } + } + + public function register(target:{}, heldValue:T):IHandle { + pollQueue(); + var reg = new Registration(target, heldValue, callback); + registrations.push(reg); + return new Handle(reg); + } +} diff --git a/std/eval/_std/haxe/GcFinalizer.hx b/std/eval/_std/haxe/GcFinalizer.hx new file mode 100644 index 00000000000..678a2385f48 --- /dev/null +++ b/std/eval/_std/haxe/GcFinalizer.hx @@ -0,0 +1,74 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package haxe; + +import haxe.atomic.AtomicBool; + +private class Registration { + public var heldValue:Null; + public var cancelled:AtomicBool; + public var callback:NullVoid>; + + public function new(heldValue:T, callback:T->Void) { + this.heldValue = heldValue; + this.cancelled = new AtomicBool(false); + this.callback = callback; + } +} + +private class Handle implements IHandle { + var reg:Registration; + + public function new(reg:Registration) { + this.reg = reg; + } + + public function close():Void { + if (reg.cancelled.compareExchange(false, true) == false) { + reg.callback = null; + reg.heldValue = null; + } + } +} + +@:coreApi +class GcFinalizer { + var callback:T->Void; + + public function new(callback:T->Void) { + this.callback = callback; + } + + public function register(target:{}, heldValue:T):IHandle { + var reg = new Registration(heldValue, callback); + eval.vm.Gc.finalise(function(_) { + if (reg.cancelled.compareExchange(false, true) == false) { + reg.callback(reg.heldValue); + reg.callback = null; + reg.heldValue = null; + } + }, target); + + return new Handle(reg); + } +} diff --git a/std/haxe/GcFinalizer.hx b/std/haxe/GcFinalizer.hx new file mode 100644 index 00000000000..8f8bd5ded01 --- /dev/null +++ b/std/haxe/GcFinalizer.hx @@ -0,0 +1,55 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package haxe; + +/** + A GC finalizer registry that invokes a callback when a watched object + is garbage-collected. Modeled after JavaScript's `FinalizationRegistry`. + + The callback receives a held value (not the collected object itself), + which is safe because the object may already be in an invalid state. + + Not all targets support GC finalizers. On unsupported targets, the + constructor throws `NotImplementedException`. +**/ +class GcFinalizer { + /** + Creates a new `GcFinalizer` with the given cleanup `callback`. + The callback will be invoked with the held value when a registered + target object is garbage-collected. + **/ + public function new(callback:T->Void) { + throw new haxe.exceptions.NotImplementedException("Not implemented for this platform"); + } + + /** + Registers `target` for clean-up. When `target` is garbage-collected, + the callback will be invoked with `heldValue`. + + Returns an `IHandle` handle. Calling `close()` on the handle + cancels the registration, preventing the callback from firing. + **/ + public function register(target:{}, heldValue:T):IHandle { + return null; + } +} diff --git a/std/haxe/IHandle.hx b/std/haxe/IHandle.hx new file mode 100644 index 00000000000..240371e2f7d --- /dev/null +++ b/std/haxe/IHandle.hx @@ -0,0 +1,33 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package haxe; + +/** + A general-purpose interface for handles that can be released + by calling `close()`. Used by `GcFinalizer` to return cancellation + handles, and intended for thread callback handles, coroutine + scheduler handles, and similar patterns. +**/ +interface IHandle { + function close():Void; +} diff --git a/std/js/_std/haxe/GcFinalizer.hx b/std/js/_std/haxe/GcFinalizer.hx new file mode 100644 index 00000000000..c8548d46c1f --- /dev/null +++ b/std/js/_std/haxe/GcFinalizer.hx @@ -0,0 +1,38 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package haxe; + +@:coreApi +class GcFinalizer { + var h:js.lib.FinalizationRegistry; + + public inline function new(callback:T->Void) { + h = new js.lib.FinalizationRegistry(callback); + } + + public inline function register(target:{}, heldValue:T):IHandle { + var token = {}; + h.register(target, heldValue, token); + return cast {close: function() h.unregister(token)}; + } +} diff --git a/std/js/lib/FinalizationRegistry.hx b/std/js/lib/FinalizationRegistry.hx new file mode 100644 index 00000000000..a822dbefb6c --- /dev/null +++ b/std/js/lib/FinalizationRegistry.hx @@ -0,0 +1,49 @@ +package js.lib; +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + A `FinalizationRegistry` object lets you request a callback when a value is garbage-collected. + + Documentation [FinalizationRegistry](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry) by + [Mozilla Contributors](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry/contributors.txt), + licensed under [CC-BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/). +**/ +@:native("FinalizationRegistry") +extern class FinalizationRegistry { + /** + Creates a new `FinalizationRegistry` with the given cleanup callback. + **/ + function new(cleanupCallback:T->Void); + + /** + Registers a target object with the registry, associating it with a held value + and an optional unregister token. + **/ + function register(target:{}, heldValue:T, ?unregisterToken:{}):Void; + + /** + Unregisters any registrations associated with the given unregister token. + Returns `true` if at least one registration was removed. + **/ + function unregister(unregisterToken:{}):Bool; +} diff --git a/std/jvm/_std/haxe/GcFinalizer.hx b/std/jvm/_std/haxe/GcFinalizer.hx new file mode 100644 index 00000000000..1eee0f7d9fa --- /dev/null +++ b/std/jvm/_std/haxe/GcFinalizer.hx @@ -0,0 +1,89 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package haxe; + +import haxe.atomic.AtomicBool; +import java.lang.ref.WeakReference; +import java.lang.ref.ReferenceQueue; + +private class Registration extends WeakReference { + public var heldValue:Null; + public var callback:NullVoid>; + public var cancelled:AtomicBool; + + public function new(target:Dynamic, heldValue:T, callback:T->Void, queue:ReferenceQueue) { + super(target, queue); + this.heldValue = heldValue; + this.callback = callback; + this.cancelled = new AtomicBool(false); + } +} + +private class Handle implements IHandle { + var reg:Registration; + + public function new(reg:Registration) { + this.reg = reg; + } + + public function close():Void { + if (reg.cancelled.compareExchange(false, true) == false) { + reg.callback = null; + reg.heldValue = null; + } + } +} + +@:coreApi +class GcFinalizer { + var callback:T->Void; + var queue:ReferenceQueue; + var allRegs:Array>; + + public function new(callback:T->Void) { + this.callback = callback; + this.queue = new ReferenceQueue(); + this.allRegs = []; + } + + function pollQueue():Void { + var ref:Dynamic = null; + while ((ref = queue.poll()) != null) { + var reg:Registration = cast ref; + if (reg.cancelled.compareExchange(false, true) == false) { + reg.callback(reg.heldValue); + reg.callback = null; + reg.heldValue = null; + } + allRegs.remove(reg); + } + } + + public function register(target:{}, heldValue:T):IHandle { + pollQueue(); + var reg = new Registration(target, heldValue, callback, queue); + allRegs.push(reg); + + return new Handle(reg); + } +} diff --git a/std/lua/_std/haxe/GcFinalizer.hx b/std/lua/_std/haxe/GcFinalizer.hx new file mode 100644 index 00000000000..11aaf3aac64 --- /dev/null +++ b/std/lua/_std/haxe/GcFinalizer.hx @@ -0,0 +1,47 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package haxe; + +@:coreApi +class GcFinalizer { + var callback:T->Void; + var nextId:Int; + + public function new(callback:T->Void) { + this.callback = callback; + this.nextId = 0; + } + + public function register(target:{}, heldValue:T):IHandle { + var cb = callback; + var id = nextId++; + var proxy:Dynamic = lua.Syntax.code( + "setmetatable({held = {0}, cb = {1}}, {__gc = function(self) if self.cb then self.cb(self.held) end end})", + heldValue, cb); + lua.Syntax.code("rawset({0}, '__hx_gc_' .. {1}, {2})", target, id, proxy); + + return cast { + close: function() lua.Syntax.code("{0}.cb = nil", proxy) + }; + } +} diff --git a/std/python/_std/haxe/GcFinalizer.hx b/std/python/_std/haxe/GcFinalizer.hx new file mode 100644 index 00000000000..dbed3b271d7 --- /dev/null +++ b/std/python/_std/haxe/GcFinalizer.hx @@ -0,0 +1,39 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package haxe; + +import python.lib.Weakref.PythonFinalizer; + +@:coreApi +class GcFinalizer { + var callback:T->Void; + + public function new(callback:T->Void) { + this.callback = callback; + } + + public function register(target:{}, heldValue:T):IHandle { + var fin = new PythonFinalizer(target, callback, heldValue); + return cast {close: function() fin.detach()}; + } +} diff --git a/std/python/lib/Weakref.hx b/std/python/lib/Weakref.hx new file mode 100644 index 00000000000..7f620a33fb2 --- /dev/null +++ b/std/python/lib/Weakref.hx @@ -0,0 +1,38 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package python.lib; + +@:pythonImport("weakref") +extern class Weakref { + static function ref(object:T):WeakrefCallable; +} + +extern class WeakrefCallable { + @:selfCall function call():Null; +} + +@:pythonImport("weakref", "finalize") +extern class PythonFinalizer { + function new(obj:{}, func:Dynamic, held:Dynamic); + function detach():Bool; +} diff --git a/tests/unit/src/unit/TestGcFinalizer.hx b/tests/unit/src/unit/TestGcFinalizer.hx new file mode 100644 index 00000000000..d97c7c007a0 --- /dev/null +++ b/tests/unit/src/unit/TestGcFinalizer.hx @@ -0,0 +1,79 @@ +package unit; + +class TestGcFinalizer extends Test { + function testConstructNoThrow() { + #if (js || python || eval || lua || jvm || cpp) + var finalizer = new haxe.GcFinalizer(function(v:String) {}); + t(finalizer != null); + #else + noAssert(); + #end + } + + function testRegisterNoThrow() { + #if (js || python || eval || lua || jvm || cpp) + var finalizer = new haxe.GcFinalizer(function(v:String) {}); + var target = {id: 1}; + var handle = finalizer.register(target, "hello"); + t(handle != null); + #else + noAssert(); + #end + } + + function testCloseNoThrow() { + #if (js || python || eval || lua || jvm || cpp) + var finalizer = new haxe.GcFinalizer(function(v:String) {}); + var target = {id: 1}; + var handle = finalizer.register(target, "hello"); + handle.close(); + t(true); + #else + noAssert(); + #end + } + + function testUnsupportedTargetThrows() { + #if !(js || python || eval || lua || jvm || cpp) + exc(function() new haxe.GcFinalizer(function(v:String) {})); + #else + noAssert(); + #end + } + + function testCallbackFiresAfterGc() { + #if eval + var called = false; + var heldResult:Null = null; + var finalizer = new haxe.GcFinalizer(function(v:String) { + called = true; + heldResult = v; + }); + finalizer.register({id: 1}, "collected"); + // Force GC + eval.vm.Gc.full_major(); + eval.vm.Gc.full_major(); + t(called); + eq(heldResult, "collected"); + #else + noAssert(); + #end + } + + function testClosePreventsCallback() { + #if eval + var called = false; + var finalizer = new haxe.GcFinalizer(function(v:String) { + called = true; + }); + var handle = finalizer.register({id: 1}, "collected"); + handle.close(); + // Force GC + eval.vm.Gc.full_major(); + eval.vm.Gc.full_major(); + f(called); + #else + noAssert(); + #end + } +} diff --git a/tests/unit/src/unit/TestMain.hx b/tests/unit/src/unit/TestMain.hx index 8cc773e8283..fb10ca054d9 100644 --- a/tests/unit/src/unit/TestMain.hx +++ b/tests/unit/src/unit/TestMain.hx @@ -99,6 +99,7 @@ function main() { #end new TestMapComprehension(), new TestMacro(), + new TestGcFinalizer(), new TestKeyValueIterator(), new TestFieldVariance(), new TestConstrainedMonomorphs(),