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 6 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
134 changes: 80 additions & 54 deletions hkmc2/shared/src/main/scala/hkmc2/codegen/HandlerLowering.scala

Large diffs are not rendered by default.

51 changes: 24 additions & 27 deletions hkmc2/shared/src/main/scala/hkmc2/codegen/StackSafeTransform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ import hkmc2.semantics.*
import hkmc2.syntax.Tree

class StackSafeTransform(depthLimit: Int)(using State):
private val STACK_LIMIT_IDENT: Tree.Ident = Tree.Ident("__stackLimit")
private val STACK_DEPTH_IDENT: Tree.Ident = Tree.Ident("__stackDepth")
private val STACK_OFFSET_IDENT: Tree.Ident = Tree.Ident("__stackOffset")
private val STACK_HANDLER_IDENT: Tree.Ident = Tree.Ident("__stackHandler")

private val predefPath: Path = State.globalThisSymbol.asPath.selN(Tree.Ident("Predef"))
private val checkDepthPath: Path = predefPath.selN(Tree.Ident("checkDepth"))
private val resetDepthPath: Path = predefPath.selN(Tree.Ident("resetDepth"))
private val stackDelayClsPath: Path = predefPath.selN(Tree.Ident("__StackDelay"))
private val stackLimitPath: Path = predefPath.selN(STACK_LIMIT_IDENT)
private val stackDepthPath: Path = predefPath.selN(STACK_DEPTH_IDENT)
private val stackOffsetPath: Path = predefPath.selN(STACK_OFFSET_IDENT)
private val stackHandlerPath: Path = predefPath.selN(STACK_HANDLER_IDENT)
private val STACK_LIMIT_IDENT: Tree.Ident = Tree.Ident("stackLimit")
private val STACK_DEPTH_IDENT: Tree.Ident = Tree.Ident("stackDepth")
private val STACK_OFFSET_IDENT: Tree.Ident = Tree.Ident("stackOffset")
private val STACK_HANDLER_IDENT: Tree.Ident = Tree.Ident("stackHandler")

private val runtimePath: Path = State.runtimeSymbol.asPath
private val checkDepthPath: Path = runtimePath.selN(Tree.Ident("checkDepth"))
private val resetDepthPath: Path = runtimePath.selN(Tree.Ident("resetDepth"))
private val stackDelayClsPath: Path = runtimePath.selN(Tree.Ident("StackDelay"))
private val stackLimitPath: Path = runtimePath.selN(STACK_LIMIT_IDENT)
private val stackDepthPath: Path = runtimePath.selN(STACK_DEPTH_IDENT)
private val stackOffsetPath: Path = runtimePath.selN(STACK_OFFSET_IDENT)
private val stackHandlerPath: Path = runtimePath.selN(STACK_HANDLER_IDENT)

private def intLit(n: BigInt) = Value.Lit(Tree.IntLit(n))

Expand All @@ -33,13 +33,13 @@ class StackSafeTransform(depthLimit: Int)(using State):
def extractRes(res: Result, isTailCall: Bool, f: Result => Block, sym: Option[Symbol], curDepth: => Symbol) =
if isTailCall then
blockBuilder
.assignFieldN(predefPath, STACK_DEPTH_IDENT, op("+", stackDepthPath, intLit(1)))
.assignFieldN(runtimePath, STACK_DEPTH_IDENT, op("+", stackDepthPath, intLit(1)))
.ret(res)
else
val tmp = sym getOrElse TempSymbol(None, "tmp")
val offsetGtDepth = TempSymbol(None, "offsetGtDepth")
blockBuilder
.assignFieldN(predefPath, STACK_DEPTH_IDENT, op("+", stackDepthPath, intLit(1)))
.assignFieldN(runtimePath, STACK_DEPTH_IDENT, op("+", stackDepthPath, intLit(1)))
.assign(tmp, res)
.assign(tmp, Call(resetDepthPath, tmp.asPath.asArg :: curDepth.asPath.asArg :: Nil)(true, false))
.rest(f(tmp.asPath))
Expand All @@ -48,7 +48,6 @@ class StackSafeTransform(depthLimit: Int)(using State):
val resumeSym = VarSymbol(Tree.Ident("resume"))
val handlerSym = TempSymbol(None, "stackHandler")
val resSym = sym getOrElse TempSymbol(None, "res")
val handlerRes = TempSymbol(None, "res")

val clsSym = ClassSymbol(
Tree.TypeDef(syntax.Cls, Tree.Error(), N, N),
Expand All @@ -64,23 +63,21 @@ class StackSafeTransform(depthLimit: Int)(using State):
/*
fun perform() =
stackOffset = stackDepth
let ret = resume()
ret
resume()
*/
blockBuilder
.assignFieldN(predefPath, STACK_OFFSET_IDENT, stackDepthPath)
.assign(handlerRes, Call(Value.Ref(resumeSym), Nil)(true, true))
.ret(handlerRes.asPath)
.assignFieldN(runtimePath, STACK_OFFSET_IDENT, stackDepthPath)
.ret(Call(Value.Ref(resumeSym), Nil)(true, true))
) :: Nil,
blockBuilder
.assignFieldN(predefPath, STACK_LIMIT_IDENT, intLit(depthLimit)) // set stackLimit before call
.assignFieldN(predefPath, STACK_OFFSET_IDENT, intLit(0)) // set stackOffset = 0 before call
.assignFieldN(predefPath, STACK_DEPTH_IDENT, intLit(1)) // set stackDepth = 1 before call
.assignFieldN(predefPath, STACK_HANDLER_IDENT, handlerSym.asPath) // assign stack handler
.assignFieldN(runtimePath, STACK_LIMIT_IDENT, intLit(depthLimit)) // set stackLimit before call
.assignFieldN(runtimePath, STACK_OFFSET_IDENT, intLit(0)) // set stackOffset = 0 before call
.assignFieldN(runtimePath, STACK_DEPTH_IDENT, intLit(1)) // set stackDepth = 1 before call
.assignFieldN(runtimePath, STACK_HANDLER_IDENT, handlerSym.asPath) // assign stack handler
.rest(HandleBlockReturn(res)),
blockBuilder // reset the stack safety values
.assignFieldN(predefPath, STACK_DEPTH_IDENT, intLit(0)) // set stackDepth = 0 after call
.assignFieldN(predefPath, STACK_HANDLER_IDENT, Value.Lit(Tree.UnitLit(true))) // set stackHandler = null
.assignFieldN(runtimePath, STACK_DEPTH_IDENT, intLit(0)) // set stackDepth = 0 after call
.assignFieldN(runtimePath, STACK_HANDLER_IDENT, Value.Lit(Tree.UnitLit(true))) // set stackHandler = null
.rest(f(resSym.asPath))
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ object Elaborator:
val untyped = assumeBuiltinTpe("untyped")
// println(s"Builtins: $Int, $Num, $Str, $untyped")
val Predef = assumeBuiltinMod("Predef")
val Runtime = assumeBuiltinMod("Runtime")
def getBuiltinOp(op: Str): Opt[Str] =
if getBuiltin(op).isDefined then builtinBinOps.get(op) else N
/** Classes that do not use `instanceof` in pattern matching. */
Expand Down
Loading
Loading