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

[perl #29200] [NCI Feature Request] Handle Out Parameters

5 views
Skip to first unread message

Chromatic

unread,
Apr 27, 2004, 1:08:00 AM4/27/04
to bugs-bi...@rt.perl.org
# New Ticket Created by chromatic
# Please include the string: [perl #29200]
# in the subject line of all future correspondence about this issue.
# <URL: http://rt.perl.org:80/rt3/Ticket/Display.html?id=29200 >


I've just come across the following signature for which I want to write
NCI bindings:

/* Get the dimensions of a rendered string of text */
int SDLCALL TTF_SizeText(TTF_Font *font, const char *text, int *w, int
*h);

*w and *h are out parameters.

Per my reading of the NCI PDD and the code, this isn't yet supported.

I *could* fake it up by passing in an unmanaged struct and hoping that
the alignment all works out. That's really not a long-term solution.
It may also have portability issues, besides the general ugliness. (I
do love tweaking people who think that C has a working type system,
though.)

Ideally, there'd be an NCI signature that told the NCI wrapper to
generate and pass in the appropriate out parameters and then store them
in the appropriate registers, so I could call this from Parrot with:

(width, height) = SizeText(font, text);

It does mean revamping PDD16 a bit though. Dan?

-- c

Leopold Toetsch

unread,
Apr 27, 2004, 2:15:50 AM4/27/04
to perl6-i...@perl.org
Chromatic <bugs-...@netlabs.develooper.com> wrote:
> int SDLCALL TTF_SizeText(TTF_Font *font, const char *text, int *w, int
> *h);

> *w and *h are out parameters.

> Per my reading of the NCI PDD and the code, this isn't yet supported.

Then the POD is missing some items:

,--[ src/call_list.txt ]
| # 2 - pointer to short
| # 3 - pointer to int
| # 4 - pointer to long
`-----------------------

> (width, height) = SizeText(font, text);

This signature doesn't match the call's signature. Shuffling return
values around like that isn't really pleasant and you don't get it that
way from C.

> It does mean revamping PDD16 a bit though. Dan?

leo

Chromatic

unread,
Apr 27, 2004, 11:44:28 PM4/27/04
to l...@toetsch.at, perl6-i...@perl.org
On Mon, 2004-04-26 at 23:15, Leopold Toetsch wrote:

> > Per my reading of the NCI PDD and the code, this isn't yet supported.
>
> Then the POD is missing some items:
>
> ,--[ src/call_list.txt ]
> | # 2 - pointer to short
> | # 3 - pointer to int
> | # 4 - pointer to long
> `-----------------------

Patch attached for those.

> > (width, height) = SizeText(font, text);
>
> This signature doesn't match the call's signature. Shuffling return
> values around like that isn't really pleasant and you don't get it that
> way from C.

That's true. Still, there has to be some extra support for out
parameters, or else NCI will walk all over the newly-updated contents of
the registers with the return results.

I patched pcf_i_pt33() manually to prevent it from assigning to I5 and
the following call does exactly what I want:

(width, height) = SizeText( font, text, width, height )

I don't particularly mind if I have to give it a signature of 'ipt3!3!'
or whatever to signify that I want the NCI sub to write into the
appropriate registers, but I do want to be able to fetch the values it
writes.

-- c

nci_pointer_docs.patch

Leopold Toetsch

unread,
Apr 28, 2004, 6:23:18 AM4/28/04
to Chromatic, perl6-i...@perl.org
Chromatic <chro...@wgz.org> wrote:

> ... Still, there has to be some extra support for out


> parameters, or else NCI will walk all over the newly-updated contents of
> the registers with the return results.

Ah yep. That's a problem.

> I patched pcf_i_pt33()

missing test?

> ... manually to prevent it from assigning to I5 and


> the following call does exactly what I want:

> (width, height) = SizeText( font, text, width, height )

Well, that's ok for this one. Bu, what if we have:

int foo(int *i, int *j) {}

in I5 in I6
out I5

We could fake that as:

(i, j, retval) = foo(i, j)

and count each pointer type as retval too. Or something...

Or, we forget about these special cased pointer to int and pass a
managed struct.

leo

Chromatic

unread,
Apr 29, 2004, 1:36:00 AM4/29/04
to l...@toetsch.at, perl6-i...@perl.org
On Wed, 2004-04-28 at 03:23, Leopold Toetsch wrote:

> > I patched pcf_i_pt33()
>
> missing test?

That's an autogenerated file and my patch was only a local proof of
concept. I'm not sure exactly how the interface should look, so I
haven't written the test yet.

> Well, that's ok for this one. Bu, what if we have:
>
> int foo(int *i, int *j) {}
>
> in I5 in I6
> out I5
>
> We could fake that as:
>
> (i, j, retval) = foo(i, j)
>
> and count each pointer type as retval too. Or something...

That seems the easiest to me. It's clearer, Parrot-wise, to follow with
the calling conventions. I'd rather expose those return conventions
than the C out parameter interface. Yuck.

> Or, we forget about these special cased pointer to int and pass a
> managed struct.

That's cleaner from the C side, but it's enough of a pain to set up
managed structs on the calling side that I'd rather do it only when it's
absolutely necessary.

Provided we pick a convention that makes sense (that is, out parameters
go in I5, I6, ... In, and then the actual returned value goes at the end
of the list in In+1) and stick with it, I like option A a little better.

If that's the case, we need some way of marking parameters as having
important return values in src/call_list.txt and a bit of modification
to save those values in the generated src/nci.c.

-- c

Tim Bunce

unread,
Apr 29, 2004, 6:05:58 AM4/29/04
to chromatic, l...@toetsch.at, perl6-i...@perl.org
On Wed, Apr 28, 2004 at 10:36:00PM -0700, chromatic wrote:

> > Or, we forget about these special cased pointer to int and pass a
> > managed struct.
>
> That's cleaner from the C side, but it's enough of a pain to set up
> managed structs on the calling side that I'd rather do it only when it's
> absolutely necessary.
>
> Provided we pick a convention that makes sense (that is, out parameters
> go in I5, I6, ... In, and then the actual returned value goes at the end
> of the list in In+1) and stick with it, I like option A a little better.

Is there a good reason not to put the returned value first?
Makes more sense to me.

Tim.

Dan Sugalski

unread,
Apr 29, 2004, 8:43:45 AM4/29/04
to chromatic, l...@toetsch.at, perl6-i...@perl.org
At 10:36 PM -0700 4/28/04, chromatic wrote:
>On Wed, 2004-04-28 at 03:23, Leopold Toetsch wrote:
> > Well, that's ok for this one. Bu, what if we have:
>>
>> int foo(int *i, int *j) {}
>>
>> in I5 in I6
>> out I5
>>
>> We could fake that as:
>>
>> (i, j, retval) = foo(i, j)
>>
>> and count each pointer type as retval too. Or something...
>
>That seems the easiest to me. It's clearer, Parrot-wise, to follow with
>the calling conventions. I'd rather expose those return conventions
>than the C out parameter interface. Yuck.

While it's much nicer to reorder the parameters, I left them in that
way on purpose. Once you start reordering in and out parameters then
you get into multiple joined parameters (buffer pointers and lengths)
and then it starts (well, continues) to get really nasty.

I'm not opposed to a scheme, mind, but I wonder if maybe we'd be
better off leaving NCI what it is (really primitive) and building a
tool to do the cleanup of the parameters that generates bytecode to
do it instead.
--
Dan

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

Chromatic

unread,
Apr 29, 2004, 11:45:23 AM4/29/04
to Dan Sugalski, perl6-i...@perl.org
On Thu, 2004-04-29 at 05:43, Dan Sugalski wrote:

> While it's much nicer to reorder the parameters, I left them in that
> way on purpose. Once you start reordering in and out parameters then
> you get into multiple joined parameters (buffer pointers and lengths)
> and then it starts (well, continues) to get really nasty.

Would following Tim's suggestion to put retval in the first return
register and the out parameters in subsequent registers be more to your
liking?

> I'm not opposed to a scheme, mind, but I wonder if maybe we'd be
> better off leaving NCI what it is (really primitive) and building a
> tool to do the cleanup of the parameters that generates bytecode to
> do it instead.

Unless we go with Leo's other idea of passing in a struct containing out
parameters, there's currently no way to do this from bytecode. By the
time you're back to bytecode from the thunk in nci.c, one of your out
parameters is gone forever, if a collision occurred.

The struct approach has merit in that it keeps the simple case simple
and requires few, simple changes to nci.c (if at all). It has a
drawbacks though. It increases the differences between the function
signatures for the native calls and the setup for Parrot calls in a way
that's visible to users. (Oh, it wants an int pointer and a string
pointer, but I have to pass one thing, a pointer to a struct containing
an int and a string.)

Building structs to pass around is currently very verbose and my least
favorite part of NCI. (Again, it's not nearly as tricky as XS, for
which I'm very grateful.)

On the other hand, this is likely an odd case. It only shows up when
there's a return value of the same register type as an out parameter in
the first parameter register. That's a bit of a coincidence.

It still would be nice to have that work deliberately, not accidentally.

-- c

Chromatic

unread,
Apr 29, 2004, 11:45:16 AM4/29/04
to Tim Bunce, perl6-i...@perl.org
On Thu, 2004-04-29 at 03:05, Tim Bunce wrote:

> > Provided we pick a convention that makes sense (that is, out parameters
> > go in I5, I6, ... In, and then the actual returned value goes at the end
> > of the list in In+1) and stick with it, I like option A a little better.
>
> Is there a good reason not to put the returned value first?
> Makes more sense to me.

Nope, no reason. I flipped a coin and described the scheme for
'heads'. After thinking a little more, I agree with you.

-- c

Leopold Toetsch

unread,
Apr 29, 2004, 12:35:25 PM4/29/04
to Chromatic, perl6-i...@perl.org
Chromatic <chro...@wgz.org> wrote:

> Building structs to pass around is currently very verbose and my least
> favorite part of NCI. (Again, it's not nearly as tricky as XS, for
> which I'm very grateful.)

Building a struct is still the right thing. We currently already have
some more (unimplemented?) pointer stuff:

# 2 - pointer to short
# 3 - pointer to int
# 4 - pointer to long

# P - void * <<< that's probably 'b'
# B - void **

# L - Long array
# T - Array of string pointers (Converted to cstrings)

Now put in some permutations of these to generated more signatures and
src/nci.c will fill the disc ;) All that stuff above is just one
signature 'p' plus an accompanied struct PMC describing the contents.

What about the managed struct generator that was discussed some time
ago?

leo

Dan Sugalski

unread,
Apr 29, 2004, 1:06:01 PM4/29/04
to l...@toetsch.at, Chromatic, perl6-i...@perl.org
At 6:35 PM +0200 4/29/04, Leopold Toetsch wrote:
>Chromatic <chro...@wgz.org> wrote:
>
>> Building structs to pass around is currently very verbose and my least
>> favorite part of NCI. (Again, it's not nearly as tricky as XS, for
>> which I'm very grateful.)
>
>Building a struct is still the right thing. We currently already have
>some more (unimplemented?) pointer stuff:

Nah, those work. And I'm using quite a number of them as part of the
postgres wrapper. (One of the reasons I have a non-jit build, since
they're not implemented in it)

Leopold Toetsch

unread,
Apr 29, 2004, 1:25:26 PM4/29/04
to Dan Sugalski, perl6-i...@perl.org
Dan Sugalski <d...@sidhe.org> wrote:

> Nah, those work. And I'm using quite a number of them as part of the
> postgres wrapper. (One of the reasons I have a non-jit build, since
> they're not implemented in it)

If JIT can't build a signature like 'L' or whatnot, it falls back to
hard-wired constructed functions. Or at least it should. Did you actually
test it. A propos test ... you know it ;)

I'm still thinking that we should reduce the amount of signatures. Some
special pointer types could be ok, though, *if* we can find something
for/against the in/out problem.

leo

Dan Sugalski

unread,
Apr 29, 2004, 1:44:37 PM4/29/04
to l...@toetsch.at, perl6-i...@perl.org
At 7:25 PM +0200 4/29/04, Leopold Toetsch wrote:
>Dan Sugalski <d...@sidhe.org> wrote:
>
>> Nah, those work. And I'm using quite a number of them as part of the
>> postgres wrapper. (One of the reasons I have a non-jit build, since
>> they're not implemented in it)
>
>If JIT can't build a signature like 'L' or whatnot, it falls back to
>hard-wired constructed functions. Or at least it should. Did you actually
>test it. A propos test ... you know it ;)

Yes, of course. Parrot built with the JIT throws a fatal exception
when loading up the postgres.imc library.

>I'm still thinking that we should reduce the amount of signatures. Some
>special pointer types could be ok, though, *if* we can find something
>for/against the in/out problem.

I'm fine with that, if we can.

Chromatic

unread,
Apr 29, 2004, 1:49:46 PM4/29/04
to l...@toetsch.at, perl6-i...@perl.org
On Thu, 2004-04-29 at 10:25, Leopold Toetsch wrote:

> I'm still thinking that we should reduce the amount of signatures. Some
> special pointer types could be ok, though, *if* we can find something
> for/against the in/out problem.

Brainstorming again, I had a bit of insight.

The real problem isn't the impedence mismatch between stack calls and
register calls. It's that low-level values in Parrot I, N, and S
registers are too transient.

Would it be easier to require that all out parameters use PMCs instead
that are converted to their low-level types? For example, for my
signature of:

int SDLCALL TTF_SizeText(TTF_Font *font, const char *text, int *w, int
*h);

... instead of passing values in I5 and I6, I'd pass two PerlInt (or
ParrotInt or whatever) PMCs in P6 and P7. If the NCI thunk could
convert these, I wouldn't need parameter reordering or anything as I'd
still have some way to get at the value.

I think that'd also be shorter than setting up a temporary struct.

I'm at work now (writing about video games -- yeah, you guys should hate
me today), so I don't really have time to wire up a test, but I don't
see any drawbacks at the moment.

-- c

Leopold Toetsch

unread,
Apr 29, 2004, 2:27:11 PM4/29/04
to Dan Sugalski, perl6-i...@perl.org
Dan Sugalski <d...@sidhe.org> wrote:

> Yes, of course. Parrot built with the JIT throws a fatal exception
> when loading up the postgres.imc library.

Should be fixed now.

leo

Dan Sugalski

unread,
Apr 29, 2004, 3:03:13 PM4/29/04
to l...@toetsch.at, perl6-i...@perl.org

Cool, thanks.

Leopold Toetsch

unread,
Apr 29, 2004, 2:30:12 PM4/29/04
to Chromatic, perl6-i...@perl.org
Chromatic <chro...@wgz.org> wrote:

> Would it be easier to require that all out parameters use PMCs instead
> that are converted to their low-level types? For example, for my
> signature of:

> int SDLCALL TTF_SizeText(TTF_Font *font, const char *text, int *w, int
> *h);

A PMC doesn't work for int constants (or not w/o overhead). But for the
"int* w" types, a PMC wouldn't hurt - or better, yes, sounds good.

Any integer typed PMC with PMC_int_val(pmc) holding the INTVAL would do
it.

leo

0 new messages