|
From: Kevin K. <kev...@gm...> - 2017-06-23 17:07:52
|
On Fri, Jun 23, 2017 at 10:12 AM, Donal K. Fellows
<don...@ma...> wrote:
> On 23/06/2017 04:50, Kevin Kenny wrote:
>>
>> About the only thing that I see that's obviously still needed is that
>> the code issuer is still emitting some warnings:
>>
>> WARNING:stdlib.tcl:3513:tcl.callframe.init not yet finished
>> WARNING:stdlib.tcl:3541:tcl.callframe.clear not yet finished
>>
>> I don't know what the significance of those warnings is, otherwise I'd
>> simply have promoted the code already. We obviously lack a test case
>> for whatever is missing.
>
>
> After looking at the comments in the code in codegen/stdlib.tcl…
>
> The initialisation of the callframe isn't complete yet, as you'd find
> out if you used [info level] (I need to list the actual arguments
> somehow, or to make something up). Similarly, we don't currently delete
> the list of arguments, and so the deletion of the frame is also not yet
> a finished task. Unfortunately, we're not currently passing the actual
> objv array in (and that whole concept doesn't really exist with inner
> frames) so I'm not quite sure what to do at the moment. It'd be much
> easier if we were working with a callback-based API at this point, as
> that would let us postpone the costly stuff until really required. But
> that's not where we are right now.
>
> So it's all tangled up with an annoying edge case where something that
> was trivial has just become really awkward for good reasons. :-(
Let me see if I'm following you. Is [info level] the only reason that
we need to maintain the actual arg list? If so, I suspect you need my
help here.
Remember, first, that we don't support calls to entirely unknown and
uncontrolled code. Handling things like overloading Core commands with
a compiled proc already in progress is, at the moment, a bridge to
far. I have ideas about how this could be accomplished, by storing
everything in the callframe before calling out to unknown code, but
I'm hoping to postpone that until quite late in the game. We can still
do a very useful compiler under a 'closed world' assumption!
With that said, I'm comfortable with having [info level] among the
things we don't support at present, just as totally uncontrolled
[eval] is. Since it wasn't supported before we implemented the
callframe stuff, I can live with an incomplete implementation for
now. We can push the boundaries as we go.
If it turns out that the arg list is important for other reasons (for
instance, does correct error message generation require it?) then I
can certainly help with preserving it. I have enough information early
in translation to construct a list object containing the args and we
can invent a quadcode instruction to stash that in the
callframe. I can build that part easily. The entry block of the
quadcode sequence is really the right place for it; the thunk
doesn't run on all the execution paths, and the code in stdlib.tcl for
emitting the procedure entry sequence doesn't, as you noticed, have
quite the right information.
Since stashing the arg list creates an additional reference to each
arg (and requires boxing args that today can be handled unboxed), we
really want to make sure that we can avoid it if possible, so I'd
appreciate it if you could help me figure out when it's actually
required.
[info level] in code that we manage is a little tricky, but should be
entirely doable, by boxing the args when [info level] is executed. We
don't have to call the builtin [info] command when doing [info level]
in compiled code, so we're free to construct the arg list when it's
required. I'd do that in the 'middle end' by putting each arg into a
dummy variable, and then optimizing those dummies away as dead code if
nothing that uses [info level] is present. There would also need to be
a little bit of stuff added to the specializer to assert 'this proc
may access a caller's frame using [info level],' and I've already got
most of a design of how the corresponding question might be answered
for [upvar]. I think I can get it to where the arg list is constructed
only on the first call to [info level] for any given callframe, and
to where we can jump-thread that so that subsequent [info level] calls
are zero cost.
I don't consider [info level] to be a blocker for merging into the
trunk. There are lots of Tcl features that we don't support yet, and
[info level] isn't a regression from earlier versions of quadcode.
Could we just have the arg list be
{theProcName {compiled proc, args unknown}}
or something for now, and tackle [info level] as its own subproject
when we get around to that particular feature?
|