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

Handler runtime improvements #282

Open
wants to merge 30 commits into
base: hkmc2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
74e3f39
Move handler definition from Predef to Runtime
AnsonYeung Feb 10, 2025
41721f7
Improve debugability and unify fixup sites at one place
AnsonYeung Feb 12, 2025
da0f953
Remove need of fixup and more robust detection of tail call using com…
AnsonYeung Feb 12, 2025
56366ba
cleanup of double underscore and moving functions
AnsonYeung Feb 12, 2025
87907b5
Tail call optimization with finer Return handling
AnsonYeung Feb 13, 2025
3808175
Yet another rewrite of handler logic, removed completed field
AnsonYeung Feb 14, 2025
916b11e
Put old test back
AnsonYeung Feb 15, 2025
72021db
Added OCaml user thread example
AnsonYeung Feb 15, 2025
8317282
Added full OCaml example
AnsonYeung Feb 15, 2025
5c35e6e
Minor fixes
AnsonYeung Feb 15, 2025
76cc988
Fix for old symbol lookup
AnsonYeung Feb 15, 2025
c574232
Added test case and import runtime function
AnsonYeung Feb 15, 2025
30de025
Manual effect binding and update test
AnsonYeung Feb 15, 2025
5280b78
Fix handler bug
CAG2Mark Feb 15, 2025
68dd782
update test
CAG2Mark Feb 15, 2025
f6a6918
Merge branch 'handler-runtime' of github.com:CAG2Mark/mlscript into h…
CAG2Mark Feb 15, 2025
ceffef3
Change Origin to use os.Path
AnsonYeung Feb 15, 2025
af2a355
Remove next field from constructor
AnsonYeung Feb 15, 2025
f67402b
Update old test comment
AnsonYeung Feb 15, 2025
ab58636
Rerun test
AnsonYeung Feb 15, 2025
addc2ec
Added interesting test case
AnsonYeung Feb 15, 2025
d685d89
Added a thin wrapper in Predef for enterHandleBlock
AnsonYeung Feb 15, 2025
a91c5da
Remove Tuple2 in UserThread test
AnsonYeung Feb 15, 2025
78eb973
Minor argument issue fix
AnsonYeung Feb 15, 2025
2ee1d08
Remove obselete comment
AnsonYeung Feb 15, 2025
73f440f
Shadow Runtime symbol
AnsonYeung Feb 16, 2025
e5f218a
Merge branch 'hkmc2' into handler-runtime
AnsonYeung Feb 22, 2025
e68065c
Remove Runtime decls
AnsonYeung Feb 22, 2025
6da2090
Remove usage of bind in test
AnsonYeung Feb 22, 2025
228e87a
Update whitespace
AnsonYeung Feb 22, 2025
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
4 changes: 4 additions & 0 deletions hkmc2/shared/src/test/mlscript-compile/Predef.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import runtime from "./Runtime.mjs";
import Runtime from "./Runtime.mjs";
let Predef1;
Predef1 = class Predef {
static {
Expand Down Expand Up @@ -388,6 +389,9 @@ Predef1 = class Predef {
} else {
return runtime.Unit
}
}
static enterHandleBlock(handler, body) {
return Runtime.enterHandleBlock(handler, body)
}
static toString() { return "Predef"; }
};
Expand Down
8 changes: 8 additions & 0 deletions hkmc2/shared/src/test/mlscript-compile/Predef.mls
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

import "./Runtime.mls"

module Predef with ...

fun id(x) = x
Expand Down Expand Up @@ -158,3 +160,9 @@ module TraceLogger with
class Test with
print("Test")
val y = 1

// This binds the handler in body, which means body can raise effects in handler
fun enterHandleBlock(handler, body) =
// This is a simple wrapper of a handler runtime function, which must not be instrumented so cannot be directly implemented here.
// It also calls other internal runtime functions as well.
Runtime.enterHandleBlock(handler, body)
1 change: 0 additions & 1 deletion hkmc2/shared/src/test/mlscript-compile/Runtime.mls
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ fun deboundMethod(mtdName, clsName) =

// Private definitions for algebraic effects

// completed is used to detect tail call
abstract class FunctionContFrame(next) with
fun resume(value)
class HandlerContFrame(next, nextHandler, handler)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
:js
:effectHandlers

import "../../mlscript-compile/Runtime.mls"
open Runtime { enterHandleBlock }

abstract class Effect with
fun perform(): ()

Expand Down
28 changes: 13 additions & 15 deletions hkmc2/shared/src/test/mlscript/handlers/RecursiveHandlers.mls
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
:js
:effectHandlers

import "../../mlscript-compile/Runtime.mls"
open Runtime { enterHandleBlock }

abstract class Effect[A] with
fun perform(arg: A): A
Expand All @@ -21,13 +19,13 @@ h1.perform("hello")
:e
h1
//│ ╔══[ERROR] Name not found: h1
//│ ║ l.22: h1
//│ ║ l.20: h1
//│ ╙── ^^

:e
h1.perform("oops")
//│ ╔══[ERROR] Name not found: h1
//│ ║ l.28: h1.perform("oops")
//│ ║ l.26: h1.perform("oops")
//│ ╙── ^^

:re
Expand Down Expand Up @@ -73,7 +71,7 @@ handle h2 = Effect with
h2.perform(3)
]
//│ ╔══[ERROR] Name not found: h2
//│ ║ l.67: then h2.perform(arg - 1) + " " + arg
//│ ║ l.65: then h2.perform(arg - 1) + " " + arg
//│ ╙── ^^
//│ > –––
//│ > performing 2
Expand Down Expand Up @@ -167,9 +165,9 @@ str
//│ }
//│ perform(arg) {
//│ return runtime.mkEffect(h1, (k) => {
//│ let tmp12, tmp13, tmp14, Cont$handler$h1$RecursiveHandlers$_mls_L141_58_1301;
//│ Cont$handler$h1$RecursiveHandlers$_mls_L141_58_1301 = function Cont$handler$h1$RecursiveHandlers$_mls_L141_58_130(pc1) { return new Cont$handler$h1$RecursiveHandlers$_mls_L141_58_130.class(pc1); };
//│ Cont$handler$h1$RecursiveHandlers$_mls_L141_58_1301.class = class Cont$handler$h1$RecursiveHandlers$_mls_L141_58_130 extends runtime.FunctionContFrame.class {
//│ let tmp12, tmp13, tmp14, Cont$handler$h1$RecursiveHandlers$_mls_L139_58_1301;
//│ Cont$handler$h1$RecursiveHandlers$_mls_L139_58_1301 = function Cont$handler$h1$RecursiveHandlers$_mls_L139_58_130(pc1) { return new Cont$handler$h1$RecursiveHandlers$_mls_L139_58_130.class(pc1); };
//│ Cont$handler$h1$RecursiveHandlers$_mls_L139_58_1301.class = class Cont$handler$h1$RecursiveHandlers$_mls_L139_58_130 extends runtime.FunctionContFrame.class {
//│ constructor(pc) {
//│ let tmp15;
//│ tmp15 = super(null);
Expand All @@ -194,13 +192,13 @@ str
//│ break;
//│ }
//│ }
//│ toString() { return "Cont$handler$h1$RecursiveHandlers$_mls_L141_58_130(" + globalThis.Predef.render(this.pc) + ")"; }
//│ toString() { return "Cont$handler$h1$RecursiveHandlers$_mls_L139_58_130(" + globalThis.Predef.render(this.pc) + ")"; }
//│ };
//│ tmp12 = str + "A";
//│ str = tmp12;
//│ tmp13 = runtime.safeCall(k(arg));
//│ if (tmp13 instanceof runtime.EffectSig.class) {
//│ tmp13.contTrace.last.next = new Cont$handler$h1$RecursiveHandlers$_mls_L141_58_1301.class(6);
//│ tmp13.contTrace.last.next = new Cont$handler$h1$RecursiveHandlers$_mls_L139_58_1301.class(6);
//│ tmp13.contTrace.last = tmp13.contTrace.last.next;
//│ return tmp13
//│ }
Expand Down Expand Up @@ -250,9 +248,9 @@ str
//│ }
//│ perform(arg) {
//│ return runtime.mkEffect(h2, (k) => {
//│ let tmp13, tmp14, tmp15, tmp16, tmp17, Cont$handler$h2$RecursiveHandlers$_mls_L141_165_2491;
//│ Cont$handler$h2$RecursiveHandlers$_mls_L141_165_2491 = function Cont$handler$h2$RecursiveHandlers$_mls_L141_165_249(pc1) { return new Cont$handler$h2$RecursiveHandlers$_mls_L141_165_249.class(pc1); };
//│ Cont$handler$h2$RecursiveHandlers$_mls_L141_165_2491.class = class Cont$handler$h2$RecursiveHandlers$_mls_L141_165_249 extends runtime.FunctionContFrame.class {
//│ let tmp13, tmp14, tmp15, tmp16, tmp17, Cont$handler$h2$RecursiveHandlers$_mls_L139_165_2491;
//│ Cont$handler$h2$RecursiveHandlers$_mls_L139_165_2491 = function Cont$handler$h2$RecursiveHandlers$_mls_L139_165_249(pc1) { return new Cont$handler$h2$RecursiveHandlers$_mls_L139_165_249.class(pc1); };
//│ Cont$handler$h2$RecursiveHandlers$_mls_L139_165_2491.class = class Cont$handler$h2$RecursiveHandlers$_mls_L139_165_249 extends runtime.FunctionContFrame.class {
//│ constructor(pc) {
//│ let tmp18;
//│ tmp18 = super(null);
Expand All @@ -278,14 +276,14 @@ str
//│ break;
//│ }
//│ }
//│ toString() { return "Cont$handler$h2$RecursiveHandlers$_mls_L141_165_249(" + globalThis.Predef.render(this.pc) + ")"; }
//│ toString() { return "Cont$handler$h2$RecursiveHandlers$_mls_L139_165_249(" + globalThis.Predef.render(this.pc) + ")"; }
//│ };
//│ tmp13 = str + "B";
//│ tmp14 = str + tmp13;
//│ str = tmp14;
//│ tmp15 = runtime.safeCall(k(arg));
//│ if (tmp15 instanceof runtime.EffectSig.class) {
//│ tmp15.contTrace.last.next = new Cont$handler$h2$RecursiveHandlers$_mls_L141_165_2491.class(2);
//│ tmp15.contTrace.last.next = new Cont$handler$h2$RecursiveHandlers$_mls_L139_165_2491.class(2);
//│ tmp15.contTrace.last = tmp15.contTrace.last.next;
//│ return tmp15
//│ }
Expand Down
2 changes: 0 additions & 2 deletions hkmc2/shared/src/test/mlscript/handlers/StackSafety.mls
Original file line number Diff line number Diff line change
Expand Up @@ -406,8 +406,6 @@ bad()
:effectHandlers
:stackSafe 100
:expect 0
import "../../mlscript-compile/Runtime.mls"
open Runtime { enterHandleBlock }
let depth = 0
handle h = Object with
fun whoops()(k) =
Expand Down
17 changes: 7 additions & 10 deletions hkmc2/shared/src/test/mlscript/handlers/UserThreads.mls
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
:js
:effectHandlers

import "../../mlscript-compile/Runtime.mls"
open Runtime { enterHandleBlock }

abstract class ThreadEffect with
val tasks = []
Expand Down Expand Up @@ -151,33 +149,32 @@ abstract class ThreadEffect with
fun xchg(x: Int): Int

val tasks = []
fun enqueue(k) =
tasks.push(k)
fun enqueue(k, x) =
tasks.push(k.bind(null, x))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this bind needed, here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is essentially () => k(x), I guess it is confusing so I'm gonna change it to a explicit lambda.

fun dequeue() =
if tasks.length != 0 do
tasks.shift()()
//│ tasks = []

class Tuple2(a, b)
let exchanger = None
//│ exchanger = None

fun start(thread: ThreadEffect -> ()) =
handle h = ThreadEffect with
fun fork(new_thread)(k) =
enqueue(k)
enqueue(k, ())
start(new_thread)
fun yld()(k) =
enqueue(k)
enqueue(k, ())
dequeue()
fun xchg(x)(k) =
if exchanger is
Some(Tuple2(y, k1)) then
Some([y, k1]) then
set exchanger = None
enqueue(k1.bind(null, x))
enqueue(k1, x)
k(y)
None then
set exchanger = Some(Tuple2(x, k))
set exchanger = Some([x, k])
dequeue()
in
thread(h)
Expand Down
Loading