-
Notifications
You must be signed in to change notification settings - Fork 2
Named handlers extension #48
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
base: main
Are you sure you want to change the base?
Conversation
f3c3bf5
to
a08eebf
Compare
a08eebf
to
d9df8cd
Compare
53d6b96
to
946e356
Compare
@@ -37,12 +38,14 @@ and struct_type = StructT of field_type list | |||
and array_type = ArrayT of field_type | |||
and func_type = FuncT of result_type * result_type | |||
and cont_type = ContT of heap_type | |||
and handler_type = HandlerT of result_type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dont think that it is actually necessary to entangle the handler_type with the result type.
The reason is that you have to provide a tag when you use suspend_to. There does not seem to be any additional safety: suspend_to means to find the appropriate tag with the appropriate value of handler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you are correct. We can get away without result types on handler names.
One thing I'd like to experiment with is embedding the "types" of tags into the handler name type, that way, we would be able to statically ensure a given handler handles the suspension (if the handler exists). Then one can imagine suspend_to
generating a static index into the handler's dispatch table.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that such a static index is possible. A given handle type may originate from different handler resume points. (In fact, that is pretty likely in my view.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I am not talking about the handler installation point / resume point / stack, but the index into the particular (on ...)
dispatch table.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Umm. This is not computing for me. That is the resume point. Or rather, it is the suspension return point. Again, knowing the type of the handle will not permit this index to be statically known.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are two things going on: 1) locate the handler (resume point); and 2) jump to the right branch inside the handler. It is the latter I am talking about.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still don't see it.
OTOH, assuming that you model the handle value as an integer, you could split the integer: have the lower few bits encode that index. Since the handle is tied to a particular tag; and assuming that a given tag cannot occur multiple times in the handler table, then that will allow you jump to the right handler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand what you mean by "the handle is tied to a particular tag". The assumption that a given tag cannot occur multiple times is false without some runtime processing/optimisation. In general, you cannot tell until module instantiation and linking whether any two tags are the same, because it is possible to import and export tags. Irrespectively, you don't know anything about the shape of the handler clause dispatch table when you suspend
/suspend_to
, so I don't see how your proposal would work.
If we could somehow talk about the types of tags, then we could embed them in the handler name type, which would then precisely describe the shape of the handler dispatch table (e.g. we could make it a validation error to have more or fewer (on ...)
clauses than the handler name type). In essence, the handler name type would be a kind of variant type. The dispatch table can then be coded as a simple variant case-split elimination, which can be represented as a dense array mapping indexes to labels. The indexes can be computed statically by looking at the type of the handler name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We seem to be misunderstanding each other.
- I am assuming that a given handler table (associated with a resume_with) may be the target of both suspend & suspend_to instructions.
- Even if a coroutine is resumed using resume_with, it may use either (or both at different times) a suspend and suspend_to to suspend itself.
- A given tag may be used in a resume handler table and a resume_with handler table
- A given tag may be used in different 'shapes' of handler tables. This is important as it allows coalescing of use cases (combining (for example) green thread-style yields with message channel stuffing).
What this means, I believe, is that there is no obvious ADT that models definitively the reasons for suspending. (You can force it, which is what I was doing in bag o stacks design.)
I.e. the pair handle/tag cant necessarily provide an index into all possible handler tables.
Perhaps, my assumptions are not matching yours?
This patch implements a semantics for named handlers. It adds the following new types and instructions:
handler ts*
resume_with $ct (on ...) : [ts1* (ref null $ct)] -> [ts2*]
$ct ~~ func [ts1* (ref $handler)] -> [ts2*]
$handler ~~ handler ts2*
resume
, but with the small tweak that it generates and passes a unique name to the continuation.suspend_to $handler $tag : [ts1* (ref null $handler)] -> [ts2*]
$handler ~~ handler $ts3
$tag ~~ func [ts1*] -> [ts2*]
suspend
, but rather than suspending to the nearest enclosing handler, it suspend to a particular given handler.I've added a few tests too.