Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Atomic operations. #10610

Merged
merged 28 commits into from
Nov 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
2bd2d36
Atomic operations.
Apprentice-Alchemist Feb 15, 2022
a11f64a
Fix hashlink's atomic operations.
Apprentice-Alchemist Mar 1, 2022
6b859a0
Add a target.atomics define.
Apprentice-Alchemist Mar 1, 2022
86f2802
Prevent complaint about "no assertions".
Apprentice-Alchemist Mar 1, 2022
7bfff9c
Fix doc gen.
Apprentice-Alchemist Mar 1, 2022
6ebc9e4
Try to fix things...
Apprentice-Alchemist Mar 1, 2022
5943e63
Rework api a bit.
Apprentice-Alchemist Mar 2, 2022
46e831a
Add threaded atomic test, fix C#, fix a method signature.
Apprentice-Alchemist Mar 2, 2022
0a91345
Make AtomicInt work on cppia, add JS implementation.
Apprentice-Alchemist Mar 4, 2022
4040658
Remove atomics on C#.
Apprentice-Alchemist Mar 5, 2022
e3fc06a
Fix doc gen, again.
Apprentice-Alchemist Mar 5, 2022
a8d4cb9
`do ... while` loop for Java.
Apprentice-Alchemist Mar 26, 2022
73a3acd
Fix a potential race condition in the Java impl.
Apprentice-Alchemist Mar 26, 2022
e35c910
Fix NativeStackTrace.callStack for hl 1.12+.
Apprentice-Alchemist Mar 26, 2022
e56771b
Use cpp.AtomicInt instead of Int.
Apprentice-Alchemist Apr 9, 2022
7b68727
Update AtomicInt.hx
Apprentice-Alchemist May 10, 2022
9a105c8
[hashlink] use library functions instead opcodes
Apprentice-Alchemist Aug 31, 2022
22bc4d9
Fix typo and add warning note to AtomicObject.
Apprentice-Alchemist Aug 31, 2022
6d39920
[hl] Fix AtomicObject, and bump hl-ver to make tests run.
Apprentice-Alchemist Aug 31, 2022
5acbe55
Add AtomicBool
Apprentice-Alchemist Oct 16, 2022
a1ea419
Inline AtomicBool
Apprentice-Alchemist Oct 16, 2022
05a737a
Add C# atomics back.
Apprentice-Alchemist Oct 16, 2022
cb84c30
Fix doc gen for atomic bool.
Apprentice-Alchemist Oct 16, 2022
466a330
Fix typo.
Apprentice-Alchemist Oct 16, 2022
323ff45
Add AtomicBool unit test and fix typo.
Apprentice-Alchemist Oct 16, 2022
5b31ac6
Fix hxcpp.
Apprentice-Alchemist Nov 21, 2022
8b4719e
Remove leftover debug printf.
Apprentice-Alchemist Nov 21, 2022
f3a429b
Try to fix the C# CI failure.
Apprentice-Alchemist Nov 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions extra/ImportAll.hx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ class ImportAll {
case "haxe.remoting.SyncSocketConnection": if( !(Context.defined("neko") || Context.defined("php") || Context.defined("cpp")) ) continue;
case "neko.vm.Ui" | "sys.db.Sqlite" | "sys.db.Mysql" if ( Context.defined("interp") ): continue;
case "sys.db.Sqlite" | "sys.db.Mysql" | "cs.db.AdoNet" if ( Context.defined("cs") ): continue;
case "haxe.atomic.AtomicBool" if(!Context.defined("target.atomics")): continue;
case "haxe.atomic.AtomicInt" if(!Context.defined("target.atomics")): continue;
case "haxe.atomic.AtomicObject" if(!Context.defined("target.atomics") || Context.defined("js") || Context.defined("cpp")): continue;
}
Context.getModule(cl);
} else if( sys.FileSystem.isDirectory(p + "/" + file) )
Expand Down
21 changes: 16 additions & 5 deletions src/context/common.ml
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ type platform_config = {
pf_exceptions : exceptions_config;
(** the scoping of local variables *)
pf_scoping : var_scoping_config;
(** target supports atomic operations via haxe.Atomic **)
pf_supports_atomics : bool;
}

class compiler_callbacks = object(self)
Expand Down Expand Up @@ -539,7 +541,8 @@ let default_config =
pf_scoping = {
vs_scope = BlockScope;
vs_flags = [];
}
};
pf_supports_atomics = false;
}

let get_config com =
Expand Down Expand Up @@ -569,7 +572,8 @@ let get_config com =
vs_flags =
(if defined Define.JsUnflatten then ReserveAllTopLevelSymbols else ReserveAllTypesFlat)
:: if es6 then [NoShadowing; SwitchCasesNoBlocks;] else [VarHoisting; NoCatchVarShadowing];
}
};
pf_supports_atomics = true;
}
| Lua ->
{
Expand Down Expand Up @@ -652,7 +656,8 @@ let get_config com =
pf_scoping = { default_config.pf_scoping with
vs_flags = [NoShadowing];
vs_scope = FunctionScope;
}
};
pf_supports_atomics = true;
}
| Cs ->
{
Expand Down Expand Up @@ -680,6 +685,7 @@ let get_config com =
vs_scope = FunctionScope;
vs_flags = [NoShadowing]
};
pf_supports_atomics = true;
}
| Java ->
{
Expand Down Expand Up @@ -709,7 +715,8 @@ let get_config com =
{
vs_scope = FunctionScope;
vs_flags = [NoShadowing; ReserveAllTopLevelSymbols; ReserveNames(["_"])];
}
};
pf_supports_atomics = true;
}
| Python ->
{
Expand Down Expand Up @@ -740,6 +747,7 @@ let get_config com =
pf_capture_policy = CPWrapRef;
pf_pad_nulls = true;
pf_supports_threads = true;
pf_supports_atomics = true;
}
| Eval ->
{
Expand Down Expand Up @@ -937,7 +945,10 @@ let init_platform com pf =
raw_define com "target.unicode";
end;
raw_define_value com.defines "target.name" name;
raw_define com name
raw_define com name;
if com.config.pf_supports_atomics then begin
raw_define com "target.atomics"
end

let set_platform com pf file =
if com.platform <> Cross then failwith "Multiple targets";
Expand Down
1 change: 0 additions & 1 deletion src/generators/hlcode.ml
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,6 @@ let ostr fstr o =
| ORefData (r,d) -> Printf.sprintf "refdata %d, %d" r d
| ORefOffset (r,r2,off) -> Printf.sprintf "refoffset %d, %d, %d" r r2 off
| ONop s -> if s = "" then "nop" else "nop " ^ s

let fundecl_name f = if snd f.fpath = "" then "fun$" ^ (string_of_int f.findex) else (fst f.fpath) ^ "." ^ (snd f.fpath)

let dump pr code =
Expand Down
2 changes: 1 addition & 1 deletion src/generators/hlinterp.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2546,7 +2546,7 @@ let check code macros =
reg r (rtype r2);
reg off HI32;
| ONop _ ->
()
();
) f.code
(* TODO : check that all path correctly initialize NULL values and reach a return *)
in
Expand Down
46 changes: 46 additions & 0 deletions std/cpp/_std/haxe/atomic/AtomicInt.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package haxe.atomic;

#if cppia
extern
#end
abstract AtomicInt(cpp.Pointer<Int>) {
public #if !(scriptable || cppia) inline #end function new(value:Int) {
this = cpp.Pointer.ofArray([value]);
}

public #if !(scriptable || cppia) inline #end function add(b:Int):Int {
return untyped __cpp__("_hx_atomic_add({0}, {1})", this, b);
}

public #if !(scriptable || cppia) inline #end function sub(b:Int):Int {
return untyped __cpp__("_hx_atomic_sub({0}, {1})", this, b);
}

public #if !(scriptable || cppia) inline #end function and(b:Int):Int {
return untyped __cpp__("_hx_atomic_and({0}, {1})", this, b);
}

public #if !(scriptable || cppia) inline #end function or(b:Int):Int {
return untyped __cpp__("_hx_atomic_or({0}, {1})", this, b);
}

public #if !(scriptable || cppia) inline #end function xor(b:Int):Int {
return untyped __cpp__("_hx_atomic_xor({0}, {1})", this, b);
}

public #if !(scriptable || cppia) inline #end function compareExchange(expected:Int, replacement:Int):Int {
return untyped __cpp__("_hx_atomic_compare_exchange({0}, {1}, {2})", this, expected, replacement);
}

public #if !(scriptable || cppia) inline #end function exchange(value:Int):Int {
return untyped __cpp__("_hx_atomic_exchange({0}, {1})", this, value);
}

public #if !(scriptable || cppia) inline #end function load():Int {
return untyped __cpp__("_hx_atomic_load({0})", this);
}

public #if !(scriptable || cppia) inline #end function store(value:Int):Int {
return untyped __cpp__("_hx_atomic_store({0}, {1})", this, value);
}
}
1 change: 1 addition & 0 deletions std/cpp/cppia/HostClasses.hx
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ class HostClasses {
"List",
"Map",
"String",
"haxe.atomic.AtomicInt"
];

static function parseClassInfo(externs:Map<String, Bool>, filename:String) {
Expand Down
61 changes: 61 additions & 0 deletions std/cs/_std/haxe/atomic/AtomicInt.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package haxe.atomic;

private class IntWrapper {
public var value:Int;

public function new(value:Int) {
this.value = value;
}
}

abstract AtomicInt(IntWrapper) to IntWrapper {
public inline function new(value:Int) {
this = new IntWrapper(value);
}

private inline function cas_loop(value:Int, op:(a:Int, b:Int) -> Int):Int {
var oldValue;
var newValue;
do {
oldValue = load();
newValue = op(oldValue, value);
} while(compareExchange(oldValue, newValue) != oldValue);
return oldValue;
}

public inline function add(b:Int):Int {
return cas_loop(b, (a, b) -> a + b);
}

public inline function sub(b:Int):Int {
return cas_loop(b, (a, b) -> a - b);
}

public inline function and(b:Int):Int {
return cas_loop(b, (a, b) -> cast a & b);
}

public inline function or(b:Int):Int {
return cas_loop(b, (a, b) -> cast a | b);
}

public inline function xor(b:Int):Int {
return cas_loop(b, (a, b) -> cast a ^ b);
}

public inline function compareExchange(expected:Int, replacement:Int):Int {
return cs.Syntax.code("System.Threading.Interlocked.CompareExchange(ref ({0}).value, {1}, {2})", this, replacement, expected);
}

public inline function exchange(value:Int):Int {
return cs.Syntax.code("System.Threading.Interlocked.Exchange(ref ({0}).value, {1})", this, value);
}

public inline function load():Int {
return this.value; // according to the CLI spec reads and writes are atomic
}

public inline function store(value:Int):Int {
return this.value = value; // according to the CLI spec reads and writes are atomic
}
}
33 changes: 33 additions & 0 deletions std/cs/_std/haxe/atomic/AtomicObject.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package haxe.atomic;

import cs.system.threading.Interlocked.*;

private class ObjectWrapper<T:{}> {
public var value:T;

public function new(value:T) {
this.value = value;
}
}

extern abstract AtomicObject<T:{}>(ObjectWrapper<T>) {
public inline function new(value:T) {
this = new ObjectWrapper(value);
}

public inline function compareExchange(expected:T, replacement:T):T {
return cs.Syntax.code("System.Threading.Interlocked.CompareExchange(ref ({0}).value, {1}, {2})", this, replacement, expected);
}

public inline function exchange(value:T):T {
return cs.Syntax.code("System.Threading.Interlocked.Exchange(ref ({0}).value, {1})", this, value);
}

public inline function load():T {
return this.value; // according to the CLI spec reads and writes are atomic
}

public inline function store(value:T):T {
return this.value = value; // according to the CLI spec reads and writes are atomic
}
}
55 changes: 55 additions & 0 deletions std/haxe/atomic/AtomicBool.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package haxe.atomic;

#if !(target.atomics || core_api)
#error "Atomic operations are not supported on this target!"
#end

/**
Atomic boolean.
(js) The Atomics and SharedArrayBuffer objects need to be available. Errors will be thrown if this is not the case.
**/
@:coreApi
abstract AtomicBool(AtomicInt) {
private inline function toInt(v:Bool):Int {
return v ? 1 : 0;
}

private inline function toBool(v:Int):Bool {
return v == 1;
}

public inline function new(value:Bool):Void {
this = new AtomicInt(toInt(value));
}

/**
Atomically compares the value of `a` with `expected` and replaces `a` with `replacement` if they are equal..
Returns the original value of `a`.
**/
public inline function compareExchange(expected:Bool, replacement:Bool):Bool {
return toBool(this.compareExchange(toInt(expected), toInt(replacement)));
}

/**
Atomically exchanges `a` with `value`.
Returns the original value of `a`.
**/
public inline function exchange(value:Bool):Bool {
return toBool(this.exchange(toInt(value)));
}

/**
Atomically fetches the value of `a`.
**/
public inline function load():Bool {
return toBool(this.load());
}

/**
Atomically stores `value` into `a`.
Returns the value that has been stored.
**/
public inline function store(value:Bool):Bool {
return toBool(this.store(toInt(value)));
}
}
67 changes: 67 additions & 0 deletions std/haxe/atomic/AtomicInt.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package haxe.atomic;

#if !(target.atomics || core_api)
#error "This target does not support atomic operations."
#end

/**
Atomic integer.
(js) The Atomics and SharedArrayBuffer objects need to be available. Errors will be thrown if this is not the case.
**/
@:coreType
abstract AtomicInt {
public function new(value:Int):Void;

/**
Atomically adds `b` to `a`.
Returns the original value of `a`.
**/
public function add(b:Int):Int;

/**
Atomically substracts `b` from `a`.
Returns the original value of `a`.
**/
public function sub(b:Int):Int;

/**
Atomically computes the bitwise and of `a` and `b` and stores it in `a`.
Returns the original value of `a`.
**/
public function and(b:Int):Int;

/**
Atomically computes the bitwise or of `a` and `b` and stores it in `a`.
Returns the original value of `a`.
**/
public function or(b:Int):Int;

/**
Atomically computes the bitwise xor of `a` and `b` and stores it in `a`.
Returns the original value of `a`.
**/
public function xor(b:Int):Int;

/**
Atomically compares the value of `a` with `expected` and replaces `a` with `replacement` if they are equal..
Returns the original value of `a`.
**/
public function compareExchange(expected:Int, replacement:Int):Int;

/**
Atomically exchanges `a` with `value`.
Returns the original value of `a`.
**/
public function exchange(value:Int):Int;

/**
Atomically fetches the value of `a`.
**/
public function load():Int;

/**
Atomically stores `value` into `a`.
Returns the value that has been stored.
**/
public function store(value:Int):Int;
}
Loading