Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Calling conventions. Again

8 views
Skip to first unread message

Dan Sugalski

unread,
Nov 12, 2003, 11:46:02 AM11/12/03
to perl6-i...@perl.org
'Kay, here's the proposed changes:

1) Return conventions die. Chopped entirely out of the list
2) The hash for the sub/method name goes, though we may later regret that.
3) The return type info that was in I3 is gone. It's really "calling
context" and I think we may need a better way for things in the system to
figure out what context they're being called in.
4) The parameter list count that was in I1 is dead. If you care, ask the
damn array
5) We 'fess up and admit there's no difference between call and return
6) Note that non-PMC counts only need to be filled in if we're marked
"prototyped"

The call section is as follows. It's not checked in -- I want some list
abuse^Wdiscussion first, since it's Yet Another Damn Call Overhaul.

=head2 Calling conventions

The following registers are used in calling all subs and methods

=over 4

=item P0

Holds the object representing the subroutine.

=item P1

Holds the return continuation for the caller.

=item P2

Holds the object the sub was called on. (For method calls)

=item P3

The overflow parameters. Everything that wouldn't fit in a register
is in here. This PMC should act as an array, and belongs to the
called sub/function/method. The caller should not assume anything
about the state of the PMC passed in here after the call is made.

=item S0

The fully qualified name of the method or sub being called

=item I0

True if the sub is being called with prototyped parameters.

=item I1

The number of params in integer registers

=item I2

The number of parameters in PMC registers.

=item I3

The number of string parameters

=item I4

The number of numeric parameters

Dan

--------------------------------------"it's like this"-------------------
Dan Sugalski even samurai
d...@sidhe.org have teddy bears and even
teddy bears get drunk

Leopold Toetsch

unread,
Nov 12, 2003, 12:08:45 PM11/12/03
to Dan Sugalski, perl6-i...@perl.org
Dan Sugalski <d...@sidhe.org> wrote:

[ I,N,S counts ]

> 6) Note that non-PMC counts only need to be filled in if we're marked
> "prototyped"

Again, this is IMHO unneeded or at least suboptimal. The caller has 3
more instructions. And what should the assembler generate for the
callee?

if I1 == 0 goto no_iparam
# I5 is valid
no_iparam: # now what

When this is for some vararg stuff, it's by far simpler to check one
param count, then to have 4 counts.

All possible speedup is probably gone, when there are expensive runtime
checks.

> Dan

leo

Dan Sugalski

unread,
Nov 12, 2003, 1:51:18 PM11/12/03
to Leopold Toetsch, perl6-i...@perl.org
On Wed, 12 Nov 2003, Leopold Toetsch wrote:

> Dan Sugalski <d...@sidhe.org> wrote:
>
> [ I,N,S counts ]
>
> > 6) Note that non-PMC counts only need to be filled in if we're marked
> > "prototyped"
>
> Again, this is IMHO unneeded or at least suboptimal. The caller has 3
> more instructions. And what should the assembler generate for the
> callee?
>
> if I1 == 0 goto no_iparam
> # I5 is valid
> no_iparam: # now what

You pitch an exception.

> When this is for some vararg stuff, it's by far simpler to check one
> param count, then to have 4 counts.
>
> All possible speedup is probably gone, when there are expensive runtime
> checks.

Not when you're trading arg counts for PMC construction it isn't, no.

Joe Wilson

unread,
Nov 12, 2003, 5:39:55 PM11/12/03
to perl6-i...@perl.org
I agree with Leo.

What good are param counts for the different return types anyway?

How can you tell the difference between a function returning
(int, int, string, PMC, string, float, string, PMC)
and a function returning
(string, int, int, PMC, string, float, PMC, string)?
Both will have the same register counts in spite of the
differing function returns.

Order matters, yet that information is lost in the
proposed calling/return convention.
The return register counts are not useful for reflection purposes
for this reason.

An ordered array of parameters makes far more sense.
The "overflow array" of PMCs ought to be the general case,
not just the exceptional case.

_____________________________

From: Leopold Toetsch
Subject: Re: Calling conventions. Again
Date: 2003-11-12 09:48:35 PST

Dan Sugalski <d...@sidhe.org> wrote:

[ I,N,S counts ]

> 6) Note that non-PMC counts only need to be filled in if we're marked
> "prototyped"

Again, this is IMHO unneeded or at least suboptimal. The caller has 3
more instructions. And what should the assembler generate for the
callee?

if I1 == 0 goto no_iparam
# I5 is valid
no_iparam: # now what

When this is for some vararg stuff, it's by far simpler to check one


param count, then to have 4 counts.

All possible speedup is probably gone, when there are expensive runtime
checks.

> Dan

leo

__________________________________
Do you Yahoo!?
Protect your identity with Yahoo! Mail AddressGuard
http://antispam.yahoo.com/whatsnewfree

Steve Fink

unread,
Nov 13, 2003, 3:33:35 AM11/13/03
to Dan Sugalski, Leopold Toetsch, perl6-i...@perl.org
I'm getting a little confused about what we're arguing about. I will
take a stab at describing the playing field, so people can correct me
where I'm wrong:

Nonprototyped functions: these are simpler. The only point of
contention here is whether args should be passed in P5..P15,
overflowing into P3; or just everything in P3. Dan has stated at least
once that he much prefers the P5..P15, and there hasn't been much
disagreement, so I'll assume that that's the way it'll be.

Prototyped functions: there are a range of possibilities.

1. Everything gets PMC-ized and passed in P3. (Oops, I wasn't going
to mention this. I did because Joe Wilson seemed to be proposing
this.) No arg counts.

2. Everything gets PMC-ized and passed in P5..P15+P3. Ix is an arg
count for the number of args passed in P5..P15. P3 is empty if
argcount <= 11 (so you have to completely fill P5..P15 before
putting stuff in P3.)

3. Same as above, but you can start overflowing into P3 whenever you
want. Mentioned for completeness. Not gonna happen.

In fact, anything above this point ain't gonna happen.

4. PMCs get passed in P5..P15+P3, ints get passed in I5..I15+P3, etc.
Ix is a total argument count (number of non-overflowed PMC args +
number of non-overflowed int args + ...). Arguments are always
ordered, so it is unambiguous which ones were omitted in a varargs
situation. I think this is what Leo is arguing for.

5. PMCs get passed in P5..P15+P3, ints get passed in I5..I15+P3, etc.
Ix is the number of non-overflowed PMC args, Iy is the number of
non-overflowed int args, etc. I think this is what Dan is arguing
for.

6. PMCs get passed in Px..P15+P3, ints get passed in I5..I15+P4, etc.
Ix is the number of non-overflowed PMC args, Iy is the number of
non-overflowed int args, etc. I made this one up; see below.

Given that all different types of arguments get overflowed into the
same array (P3) in #4 and #5, #4 makes some sense -- if you want to
separate out the types, then perhaps it should be done consistently
with both argument counts _and_ overflow arrays. That's what #6 would
be. Note that it burns a lot of PMC registers.

The other question is how much high-level argument passing stuff (eg,
default values) should be crammed in. The argument against is that it
will bloat the interface and slow down calling. The argument for is
that it increases the amount of shared semantics between Parrot-hosted
languages. An example of how default values could be wedged in is to
say that any PMC parameter can be passed a Null PMC, which is the
signal to use the default value (which would need to be computed in
the callee, remember), or die loudly if the parameter is required.
Supporting optional integer, numeric, or string parameters would be
trickier. Or disallowed.

Hopefully I got all that right.

Leopold Toetsch

unread,
Nov 13, 2003, 4:30:58 AM11/13/03
to perl6-i...@perl.org
Steve Fink wrote:

> Prototyped functions: there are a range of possibilities.

> 2. Everything gets PMC-ized and passed in P5..P15+P3. Ix is an arg
> count for the number of args passed in P5..P15. P3 is empty if
> argcount <= 11 (so you have to completely fill P5..P15 before
> putting stuff in P3.)

That is exactly the unprototyped case.

> 4. PMCs get passed in P5..P15+P3, ints get passed in I5..I15+P3, etc.
> Ix is a total argument count (number of non-overflowed PMC args +
> number of non-overflowed int args + ...). Arguments are always
> ordered, so it is unambiguous which ones were omitted in a varargs
> situation. I think this is what Leo is arguing for.

Almost. An argument count doesn't help in the general case (e.g. against
swapped params of the same type or such). So I'd just omit it for the
probably more common case of fixed and known arguments.

But, we need something for varargs or even changed signatures (wherever
they might come from). The HLL compiler shouldn't know much about the
underlying calling conventions. OTOH the code generated for argument
binding in the callee has to interface with the HLL code for providing
values for missing (default) arguments.
We might need something like this

.sub prototyped var_args # I1 is count of I-args
.param int a # I5 when presemt
.if_missing_param a # if I1 >= 1 goto a_is_valid
# HLL code to set a # ...
# a = some # I5 = ...
.end # a_is_valid:

So while its up to the HLL to produce the code for providing a default
value, its up to our calling conventions to allow such code to
interface, when a param is missing. Just having counts isn't enough to
provide all we need. We must provide an interface for the HLL to fill in
code for missing arguments.

Changed signatures can't be handled with counts anyway.


> The other question is how much high-level argument passing stuff (eg,
> default values) should be crammed in.

See above.

> ... The argument against is that it


> will bloat the interface and slow down calling.

I'd really have fixed and vararg cases separated for this reason.
The fib() benchmark measuring raw call speed mainly, is already slow enough.

leo

Dan Sugalski

unread,
Nov 13, 2003, 10:05:40 AM11/13/03
to Steve Fink, Leopold Toetsch, perl6-i...@perl.org
On Thu, 13 Nov 2003, Steve Fink wrote:

> I'm getting a little confused about what we're arguing about. I will
> take a stab at describing the playing field, so people can correct me
> where I'm wrong:

The current big issue is whether non-PMC parameter types get counts.
There's not really anything else up for dispute. I think the for/against
argument there is:

for) Since we can't guarantee any sort of compiletime/runtime coherence,
if we're passing parameters in I/S/N registers we need to note how many.

against) That takes a lot of time and is unneeded most of the time

While I sympathize with the argument against, for it to be a feasable
soulution would require that runtime signatures not change from what was
in place at compiletime. Given that there may be some significant amount
of time between run and compile times (what with precompiled executables
and libraries), and that we are in general targeting, supporting, and
expecting fairly dynamic languages I'm expecting that we're going to have
issues here.

While the code that uses N/I/S registers is likely going to run at a lower
level than most perl/python/ruby code, we're looking to encourage their
use with HLL prototypes and such, which means we're going to see more use
of low-level types than we might have in the past, so we're going to get
more use of them than I think folks might be expecting.

> The other question is how much high-level argument passing stuff (eg,
> default values) should be crammed in. The argument against is that it
> will bloat the interface and slow down calling. The argument for is
> that it increases the amount of shared semantics between Parrot-hosted
> languages. An example of how default values could be wedged in is to
> say that any PMC parameter can be passed a Null PMC, which is the
> signal to use the default value (which would need to be computed in
> the callee, remember), or die loudly if the parameter is required.
> Supporting optional integer, numeric, or string parameters would be
> trickier. Or disallowed.

That's something separate, though needing addressing.

Pete Lomax

unread,
Nov 13, 2003, 6:30:22 PM11/13/03
to perl6-i...@perl.org
Hi,
New to this list, so please excuse any glaring stupidity.
<such as posting this direct to Dan instead of the list, sorry>

I've been thinking about porting a small language to run on parrot,
and the call/return conventions. This is what I plan to do, at least
for my local routines. I'll follow the rules a bit more closely for
globals and external calls (but not this week).

I'd be interested to see what sort of signature changes between
compile and runtime you think are likely to happen, as I have to admit
I have never encountered such a beast. Doesn't that force
non-prototyped calls?

As I understand it, the requirements are:

Call a routine explicitly and be as efficient as possible/practical.
You know what the parameters are and where they should go.

Call a routine indirectly given two items:
The address of the routine, and
A list (or similar structure) of the parameters.
You don't know, and you probably don't care what they are.
Generally speaking, efficiency in this case is less important.

Optional parameters in both calling methods.


Without optional parameters I will simply translate as follows:

procedure fred(integer x, string y)

to:

_u_fred:
I5=P3[1]
S5=P3[2]
_fred:


Basically, replace the 0/1 prototype flag with a mangled label.

Yes/no?


For optional parameter handling, I will do something like:

procedure fred(integer x=0, string y="Default")

_u_fred:
length I1, P3 # total number of params
lt I1, 1, _fred
I5=P3[1]
lt I1, 2, _fred
S5=P3[2]
_fred:
eq I1, 2 fred_main # where 2 is max_params
set S5 "Default"
eq I1, 1 fred_main
set I5 0
fred_main:

In this first stab, all optional parameters must be grouped on
the rhs. Not sure yet how much more complicated it gets if not.

I don't know what games might need to be played with overflow
parameters in P3, I can imagine needing to extend a short P3 with
some defaults and chop off the first 11 somewhere in _u_fred.

Any comments?

Pete

Leopold Toetsch

unread,
Nov 14, 2003, 2:12:26 AM11/14/03
to Pete Lomax, perl6-i...@perl.org
Pete Lomax <pete...@blueyonder.co.uk> wrote:
> Hi,
> New to this list, so please excuse any glaring stupidity.

Welcome here.

> I'd be interested to see what sort of signature changes between
> compile and runtime you think are likely to happen, as I have to admit
> I have never encountered such a beast. Doesn't that force
> non-prototyped calls?

*Me* thinks, Dan is considering calling into old and possibly outdated
libraries. Trying to catch such errors at subroutine level seems
strange.

> procedure fred(integer x, string y)

> _u_fred:


> I5=P3[1]
> S5=P3[2]
> _fred:

There is no P3[] involved. "_fred" just starts with whatever is in
registers I5/S5.

> For optional parameter handling, I will do something like:

Please read my proposal WRT default params posted elsewhere in this thread.
The default value could be the result of an arbitrary expression, so its
not that simple.

> Pete

leo

Pete Lomax

unread,
Nov 14, 2003, 3:09:54 AM11/14/03
to perl6-i...@perl.org
On Fri, 14 Nov 2003 08:12:26 +0100, Leopold Toetsch <l...@toetsch.at>
wrote:

>> _u_fred:
>> I5=P3[1]
>> S5=P3[2]
>> _fred:
>
>There is no P3[] involved. "_fred" just starts with whatever is in
>registers I5/S5.

Yes, "_fred" wades straight in, expecting everything to be set up. It
is _u_fred which is sucking them out of P3, and falling through.
If the function is always called prototyped, _u_fred won't be
referenced and imcc will strip that code (according to the Pirate
document, iirc). If it is called non prototyped from several places,
it makes a smaller footprint.


>
>Please read my proposal WRT default params posted elsewhere in this thread.
>The default value could be the result of an arbitrary expression, so its
>not that simple.

On re-reading your post it seems I was trying to say the same thing.

Pete

Leopold Toetsch

unread,
Nov 14, 2003, 3:53:08 AM11/14/03
to Pete Lomax, perl6-i...@perl.org
Pete Lomax <pete...@blueyonder.co.uk> wrote:
> On Fri, 14 Nov 2003 08:12:26 +0100, Leopold Toetsch <l...@toetsch.at>
> wrote:

>>> _u_fred:
>>> I5=P3[1]
>>> S5=P3[2]
>>> _fred:
>>
>>There is no P3[] involved. "_fred" just starts with whatever is in
>>registers I5/S5.
> Yes, "_fred" wades straight in, expecting everything to be set up. It
> is _u_fred which is sucking them out of P3, and falling through.

P3 (*overflow* array) is only used if there are more then 11 arguments
of one kind. For an unprototyped call P5, P6 would be used in your
example.

> Pete

leo

Dan Sugalski

unread,
Nov 14, 2003, 9:31:24 AM11/14/03
to Pete Lomax, perl6-i...@perl.org
On Thu, 13 Nov 2003, Pete Lomax wrote:

> I'd be interested to see what sort of signature changes between
> compile and runtime you think are likely to happen, as I have to admit
> I have never encountered such a beast. Doesn't that force
> non-prototyped calls?

I've seen it with some depressing regularity over the years. It generally
takes the form of an upgrade to a library that breaks existing
executables, something we're going to have to deal with as we're looking
to encourage long-term use of bytecode-compiled programs. But there are
several issues here:

1) vararg calls with non-pmc registers involved
2) Runtime modification of sub definitions
3) Drift in interface definitions

There are definite performance issues--there are at least four integer
stores and for paranoid subs for integer comparisons. The calling
conventions make it reasonably clear, though, that they're there because
definitions may change, and the engine doesn't place restrictions on how
they change. Because of that we have to pass in sufficient information to
validate things at the interface, which means at least arg counts.

It's easy to lose sight of the characteristics of our target languages
since we don't have any fully-functional compilers for them yet, so we've
got to be careful. Dynamism is fundamental to the engine and the calling
conventions are a recognition of that fact. (Doesn't matter whether I
*like* it or not, it's the reality we have to deal with)

If someone wants to propose we have an alternate, more static convention
that lends itself better to one-off static linking with link-time
signature checking for verification, which is what the complaints all seem
to allde to, well... go ahead and if you do we'll see where we go from
there.

Leopold Toetsch

unread,
Nov 14, 2003, 10:05:30 AM11/14/03
to Dan Sugalski, perl6-i...@perl.org
Dan Sugalski <d...@sidhe.org> wrote:

> I've seen it with some depressing regularity over the years. It generally
> takes the form of an upgrade to a library that breaks existing
> executables, something we're going to have to deal with as we're looking
> to encourage long-term use of bytecode-compiled programs.

This seems to me the same, as that strcpy(3) should be guarded against
wrong argument count at runtime. But swapped destination/source can't be
detected anyway ;)

> ... But there are
> several issues here:

> 1) vararg calls with non-pmc registers involved

I already did propose the syntax:

.sub prototyped var_args

If the HLL can't provide this information, we could use the opposite:

.sub prototyped fixed_args

at least, so that runtime checks can be omitted for certain cases.

> 2) Runtime modification of sub definitions

are evil, forbidden, disallowed. This just can't work.

> 3) Drift in interface definitions

needs code adaption and recompiling.

> ... Because of that we have to pass in sufficient information to


> validate things at the interface, which means at least arg counts.

If someone changes libc behind the curtain in an incompatible way,
existing programs probably just segfault.

> If someone wants to propose we have an alternate, more static convention
> that lends itself better to one-off static linking with link-time
> signature checking for verification, which is what the complaints all seem
> to allde to, well... go ahead and if you do we'll see where we go from
> there.

e.g. version checking at program load. The main program has something
like:

load_lib "mylib", "0.22"

If the lib version doesn't match, we spit out a warning. If the lib is
compatible the code can get adjusted to read:

load_lib "mylib", "0.22-0.24"

There could be some implicit rules, that state, e.g. versions with the
same major version numbers are compatible by default. Module authors and
users have responsibilities, which we can't solve with runtime checks.

> Dan

leo

Dan Sugalski

unread,
Nov 14, 2003, 10:33:37 AM11/14/03
to Leopold Toetsch, perl6-i...@perl.org
On Fri, 14 Nov 2003, Leopold Toetsch wrote:

> Dan Sugalski <d...@sidhe.org> wrote:
>
> > I've seen it with some depressing regularity over the years. It generally
> > takes the form of an upgrade to a library that breaks existing
> > executables, something we're going to have to deal with as we're looking
> > to encourage long-term use of bytecode-compiled programs.
>
> This seems to me the same, as that strcpy(3) should be guarded against
> wrong argument count at runtime. But swapped destination/source can't be
> detected anyway ;)

We can't detect bugs like that, true. But we can detect when someone calls
us with two arguments and someone has, in the mean time, "helpfully" added
an optional length arg to strcpy.

> > ... But there are
> > several issues here:
>
> > 1) vararg calls with non-pmc registers involved
>
> I already did propose the syntax:

[Snip]


> at least, so that runtime checks can be omitted for certain cases.

No IMCC syntax that's purely compile-time is of any help here. The code
doing the calling

> > 2) Runtime modification of sub definitions
>
> are evil, forbidden, disallowed. This just can't work.

True, false, false. It happens, in some cases a *lot*. This is perl,
python, and ruby we're talking about, where changing the definition of a
sub is as trivial as a reference assignment into a global hash. It's easy,
people do it. Often, in some cases. (Heck, I've done it)

Methods also cause significant headaches, since there are *no* signatures
available to the calling code, as there's no way for it to look up the
signature. (And yeah, that's a reasonable argument for all method calls to
be unprototyped, but I'm not sure I want to place that restriction in
right now)

> > 3) Drift in interface definitions
>
> needs code adaption and recompiling.

To operate properly, yes. To fail properly, no.

> > ... Because of that we have to pass in sufficient information to
> > validate things at the interface, which means at least arg counts.
>
> If someone changes libc behind the curtain in an incompatible way,
> existing programs probably just segfault.

Yes, they do. For us that's unacceptable--we have to be able to let code
provide at least some boundary guarantees with safe failure modes.

> > If someone wants to propose we have an alternate, more static convention
> > that lends itself better to one-off static linking with link-time
> > signature checking for verification, which is what the complaints all seem
> > to allde to, well... go ahead and if you do we'll see where we go from
> > there.
>
> e.g. version checking at program load.

Which doesn't solve the problem. Ask for version 1.20 or higher, get
version 1.33, and find the interface has changed. (An interface that was
fine in versions 1.20 through 1.32) This happens, with some frequency.

Leopold Toetsch

unread,
Nov 14, 2003, 11:23:52 AM11/14/03
to Dan Sugalski, perl6-i...@perl.org
Dan Sugalski <d...@sidhe.org> wrote:
> ... It happens, in some cases a *lot*. This is perl,

> python, and ruby we're talking about, where changing the definition of a
> sub is as trivial as a reference assignment into a global hash. It's easy,
> people do it. Often, in some cases. (Heck, I've done it)

Its definitely simpler then changing libc, yes. So if its necessary, do
die nicely instead of segfault, then I'm for a compile option, to be
able to turn these tests off --cause-i-know-what-im-doing.

> Methods also cause significant headaches, since there are *no* signatures
> available to the calling code, as there's no way for it to look up the
> signature.

If there are prototypes - which could be optional - we could check at
least at compile time.

>> e.g. version checking at program load.

> Which doesn't solve the problem.

No, doesn't solve. But param counts don't either. Both may help a bit.

> Dan

leo

Melvin Smith

unread,
Nov 14, 2003, 11:39:41 AM11/14/03
to l...@toetsch.at, Dan Sugalski, perl6-i...@perl.org

Dan, I think we will still _need_ to support version based deprecation.
Certainly situations will arise with the current scenario when
libraries change in such a way that they don't even detect incompatibilities.

The easy situation is when argument counts change, but the hard situation is
when semantics have changed. In that case we have to have some
sort of version requirement in the bytecode.

-Melvin


Matt Fowles

unread,
Nov 14, 2003, 3:12:05 PM11/14/03
to perl6-i...@perl.org
All~

This might have already been suggested, or their might be a good reason
why not to do this but here is my idea.

Why not have unprotyped calls pass an array in P5 and a hash in P6? The
array can hold the first n positional arguments (possibly 0, for which
Null could be passed to avoid creating the array) and the hash can hold
the remaining m positional or name based arguments (also possibly 0).

Prototyped calls, then pass things in the exact registers they need
I5-I15 for integers, S5-S15 for strings, etc... and protyped calls can
only be made when the full types are EXACT (i.e. no default values, or
anything else...).

This allows the speed freaks to have a fast prototyped call with no
runtime checks, and us mere mortals can go the slow way...

Matt

Tim Bunce

unread,
Nov 14, 2003, 5:00:37 PM11/14/03
to Dan Sugalski, Leopold Toetsch, perl6-i...@perl.org
Does C++ style 'name mangling' have any relevance here?

I also had some half-baked thought that a HLL could generate
two entry points for a prototyped sub...

one with the mangled name encoding the expected arguments and types
(p/s/i) for high-speed no-questions-asked-nothing-checked use, and...

also generate a non-mangled entry point that would check/massage
the params and then call the name-mangled entry point.

Am I totally mad?

Tim [ducking]

Gordon Henriksen

unread,
Nov 14, 2003, 11:57:15 AM11/14/03
to Melvin Smith, perl6-i...@perl.org
Melvin Smith <mrjol...@mindspring.com> wrote:

> The easy situation is when argument counts change, but the
> hard situation is
> when semantics have changed. In that case we have to have some
> sort of version requirement in the bytecode.

Best practice I've seen for this is to have a library advertise 2
version numbers: "Compatible" version, and "current" version. When
searching for a library to link with, the compatible version must match,
and of those the latest "current" version wins. These versions are
usually integers unrelated to the version number of any particular
product. -- But maintaining these puts a lot of faith in the library's
author.

--

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
gor...@iclub.com


Gordon Henriksen

unread,
Nov 14, 2003, 11:42:32 AM11/14/03
to Leopold Toetsch, Dan Sugalski, perl6-i...@perl.org
Leo,

Consider this (as I'm sure you already have)...

class ClassA;
method meth($i is int) { ... }

class ClassB;
method meth($f is float) { ... }

module main;
my $obj = (rand(1.0) < 0.5? ClassA : ClassB)->new;
$obj->meth(1);

Perl's going not going to be able to bind to a HLL prototype, much less
a low-level one. Even if it could bind to the HLL prototype, it has to
protect against mutation of the method. Either perl6 recompiles the
caller when a new version of the sub is linked in, or perl6 uses a
calling convention that always works: Unprototyped.

Prediction: perl6 winds up using One True Parrot Unprototype for ALL of
its method and sub calls.

The parrot calling conventions thus become rather academic to Perl. The
target languages under consideration just aren't going to get little
mileage out of them.


Leo and Dan,

As for encoding varargs in the parrot calling conventions, parameter
counts are very much useless--they're might as well be a very poor
one-way hash of the prototype. Have you considered using 4 bitfields to
indicate what register parameters are what? E.g.

prototype: int in In+0,
float in Nn+1,
string in Sn+2,
string in Sn+3,
float in Nn+4,
int in In+5,
PMC in Pn+6

Iregs = (1 << n+0) + (1 << n+5) = 0b...0100001...
Fregs = (1 << n+1) + (1 << n+4) = 0b...0010010...
Sregs = (1 << n+2) + (1 << n+3) = 0b...0001100...
Pregs = (1 << n+6) = 0b...1000000...

This burns no more space in the register file than the 4 parameter
counts, and it doesn't throw away ordering data. Downside: Counting
total number of arguments is harder.

Four 32-bit bitfields match the 4 sets of 32 registers, so even if the
set of registers used for passing parameters grow, this convention is
safe. Overflow parameters... Well, figure something out; there's plenty
of space in the overflow array. (4 binary Sregs with likewise bitfields?
Or just use the PMC type.)

But imposing the overhead of 4 Ireg assignments on the caller and 4 Ireg
compares and branches on the callee at the beginning of every routine,
just to check that the register conventions are right? Don't think
that's a good idea. What's the recovery scenario going to be, anyhow? To
blow up... What a waste of cycles: It's a needless toll for 99.999999%
of calls. Check that the prototype is right when the sub is loaded into
the runtime: In effect, throw the exception at link time. Then this
vararg cruft can be cut out of the common case. That is, support 3
parrot calling conventions:

- unprototyped ("your parameters are in an array")
- prototyped ("what you want in the register file is there")
- vararg ("I've documented what I put in the register file")


But, honestly, a vararg prototype string in an Sreg probably makes more
sense than either 4 register counts or 4 register masks. It avoids
burning integer registers--the most useful part of the register file for
the sort of low-level code which will actually USE parrot prototypes. It
can be set up by the caller with a single string constant load. It can
be checked by the callee with a single string compare instruction (if
the vararg list is actually static). It's easy to reflect, too.

--

Gordon Henriksen
IT Manager
ICLUBcentral Inc.
gor...@iclub.com


> -----Original Message-----
> From: Dan Sugalski [mailto:d...@sidhe.org]
> Sent: Friday, November 14, 2003 10:34 AM
> To: Leopold Toetsch
> Cc: perl6-i...@perl.org
> Subject: Re: Calling conventions. Again
>
>

Dan Sugalski

unread,
Nov 16, 2003, 1:29:30 PM11/16/03
to Gordon Henriksen, Melvin Smith, perl6-i...@perl.org

Putting full faith in library authors has, historically, been
ill-advised in the general case, but we can do some things to help
that out and let folks have at least a chance of getting things right.
--

0 new messages