freenode/#sicl - IRC Chatlog
Search
14:11:24
beach
For example, it might be good to define one or more environment-augmentation functions, rather than CONS and MAKE-...-ENTRY.
14:12:11
Bike
oh, well, yes. I was focused on the Cleavir part. those functions could still be more on the backend level, I think.
14:12:19
beach
Also, I need to think about the idea of keeping references to parent ASTs and to the function AST. Maybe a special type of variable holding the environment would be better.
14:13:05
Bike
With the references I think the thing is this does need to be available in HIR somehow or another, because it comes up in inlining.
14:13:59
beach
If the environment references turn into lexical variables (maybe a special type of such variables) then I think that would fix the problem.
14:16:33
Bike
so function-ast refers to a special lexical-ast, block-ast and etc. have one as input and one as output?
14:16:49
Bike
I was kind of going off analogy with closures, since the closure variable doesn't exist at ast level and all. but it's a different situation.
14:17:08
beach
In the SICL x86 backend chapter, I wrote that the time stamp is kept in the static environment of a function. Your suggestion makes me think that the dynamic environment should be treated like any other local variable, subject to capture, etc.
14:18:16
Bike
I'm not sure what would capture a dynamic environment - that would be treating it more like a lexical environment
14:19:36
beach
So, it can't be all on the call stack, because the stack can be popped and pushed even though some closure might contain a RETURN-FROM or a GO.
14:20:28
Bike
In the static environment, you said? Like the closed over environment? I think I missed that bit.
14:20:38
beach
But that's basically just another way of saying that the dynamic environment can be captured.
14:21:22
beach
So, essentially, the dynamic environment is captured, but what is captured can be rendered useless when the block/tagbody exists normally.
14:23:17
beach
But there could be a (f (lambda () (return-from ...))) inside the BLOCK and we might not know what F is doing with the closure.
14:25:06
beach
So, semantically speaking, the dynamic environment can not be allocated on the stack, because then there is no way of checking whether the exit point is still valid when a GO or a RETURN-FROM is encountered.
14:26:04
beach
By making the entire thing into a lexical variable that may or may not have dynamic extent in various situations, we handle the problem.
14:27:26
beach
Then, the implementation can choose whether to be strict about checking the validity of exit points, or not.
14:28:08
Bike
I think that if dynamic environments were written out like in the examples in the text, like just regular nested LETs, and every call explicitly referred to one that had the environment in scope, we actually wouldn't need to invalidate exit points upon normal exit from a block scope- invalidated exit points would just not be present in other calls
14:29:30
beach
But my example above with (lambda () (return-from ...)) is a situation where a strict implementation would need to invalidate.
14:30:24
Bike
Like (defun f (c) (setf *global* c)), and then (block nil (f (lambda () (return ...)))) - that's what you mean, right?
14:31:13
Bike
So in that case, if *global* was called after the block returns, the closure would refer to a block that would not be present in the dynamic environment of that call. So no special invalidation is required.
14:32:25
Bike
"Whenever transfer of control to an exit point is initiated, the exit point is rst searched for. If no valid exit point can be found, an error is signaled." this part.
14:34:24
beach
In the lexical environment of the function that does the transfer, so it is subject to capture and is not necessarily dynamic extent.
14:35:04
Bike
Yes, but it's not the dynamic environment, it's a saved tag. It's the lexical variable I already added the last time I decided to change everything
14:35:33
Bike
So like, if that is the same as the dynamic environment entry, that _entry_ isn't dynamic-extent, no.
14:36:41
beach
The dynamic environment could just as well be a chain of entries held in local variables.
14:36:42
Bike
Right. Yes. Parts of the entry are certainly not dynamic-extent and have to be saved in closures- but the dynamic environment itself, the cons, I think that still is stack-allocatable.
14:38:00
beach
That "cons" (which is not quite what it is) could be just two lexical variables subject to the register allocator, capture, and what have you.
14:38:53
Bike
I got the impression it was an actual structure (though not necessarily a cons). The doc says it's a simply linked list.
14:39:43
beach
But it is very simple, so it doesn't have to be treated as anything of a particular class or type.
14:40:03
Bike
Right, but I thought it was still some kind of runtime structure- it gets passed to functions and all
14:45:15
Bike
my model for how this works is the hir translator in sicl, which uses conses, but of course it's not the same as how the backend would work
14:48:38
beach
And that is PRECISELY what will allow us to invalidate the exit point, even though it is no longer "on the stack".
14:50:17
Bike
what i was thinking was like, in these terms... the catch-instruction, the block entry point, has two outputs. The one that already exists and this new one for the new-env. The block entry does something like (let* ((timestamp whatever) (new-env (make-block timestamp ... old-env))) ...). If we have a closure with a return, it refers to timestamp, but NOT to new-env. so timestamp is not dynamic-extent, but new-env is, always.
14:52:43
Bike
well, i mean, clasp does something completely different. but i think the fundamental "HIR reflects block nesting" thing might be required by any backend.
14:53:41
beach
Oh, one more thing about what I was suggesting above. Even when there is capture, the memory for the special kind of struct that implements an entry in the dynamic environment would not be allocated on the heap.
14:55:43
beach
But, like I said, now I am thinking of an implementation that doesn't require a time stamp.
14:56:09
beach
Because the entire captured entry would be in the static environment of the function, so only an invalidation flag is needed.
14:57:18
beach
Essentially, if there is a chance that an entry would be referred to after it is invalid, it would not be allocated on the stack.
14:59:20
Bike
So you think the dynamic environment variables should maybe be explicit in the AST so that if an implementation chooses to do something like that, it can
14:59:48
beach
It would still (I hope) be possible for an implementation to use the time-stamp idea.
15:00:53
beach
But with this (preliminary) idea, we would simplify the entire processing of it, and reduce it to ordinary dynamic-extent things.
15:02:43
Bike
It'll take a bit to explain. I put an explanation in the file, actually, but then decided it was off topic
15:03:36
Bike
The common point is it still has this block nesting structure as well as marking calls with it
15:03:42
beach
Anyway, I think you idea is great and that we need to think more about details like this.
15:24:58
Bike
So as this particular issue goes - I'll look at what I need to do to support some kind of block chaining, and we can decide whether to do variables or something else later
16:41:26
Bike
i think this can and should be limited to cst-to-ast, rather than involving the environment- given the idea of cleavir-env as a separate repo it doesn't make too much sense to incorporate this, i don't think
17:49:09
Bike
adding this won't be a problem. doing it with ast level variables means block-ast and such having more slots, but that's not terrible. having locations at hir level is nice because it means the connection between blocks/catches can go both ways.
17:49:35
Bike
kind of wondering about tagbody though. currently a tagbody will have one catch instruction for every tag, which works kind of weird if the tagbody has only one entry