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

Re: cvs commit: parrot/ops pmc.ops

5 views
Skip to first unread message

Leopold Toetsch

unread,
Dec 15, 2004, 12:54:53 PM12/15/04
to Sam Ruby, perl6-i...@perl.org
Sam Ruby <ru...@cvs.perl.org> wrote:

> I don't understand this. At all. But the test case added to pyclass.t
> (motivated by test 4 in pie/b3.t) only passes if this change to the
> get_repr op is made.

[ ... ]
> -op get_repr(out STR, in PMC) {
> - $1 = $2->vtable->get_repr(interpreter, $2);
> +inline op get_repr(out STR, in PMC) {
> + STRING *s = $2->vtable->get_repr(interpreter, $2);
> + $1 = s;
> goto NEXT();
> }

Strange. Stranger. Strangest. Did the test fail with JIT/i386 only?

leo

Sam Ruby

unread,
Dec 16, 2004, 8:33:34 AM12/16/04
to l...@toetsch.at, perl6-i...@perl.org
Leopold Toetsch wrote:

I didn't mean to commit the "inline" portion of the change... that
didn't make a difference.

I've never investigated how to select another "core"... I've done all my
runs using the default for i386. While in gdb, I have seen mention of
"slow_core" and in this case, breakpoints that I set on
Parrot_get_repr_s_p were hit.

The symptoms I see are that get_repr returns the correct string, but the
appropriate REG_STR does not get updated.

- Sam Ruby

Leopold Toetsch

unread,
Dec 16, 2004, 9:34:55 AM12/16/04
to Sam Ruby, perl6-i...@perl.org
Sam Ruby wrote:

>
> Leopold Toetsch wrote:
>>> +inline op get_repr(out STR, in PMC) {
>>> + STRING *s = $2->vtable->get_repr(interpreter, $2);
>>> + $1 = s;
>>> goto NEXT();
>>> }
>>
>>
>> Strange. Stranger. Strangest. Did the test fail with JIT/i386 only?
>
>
> I didn't mean to commit the "inline" portion of the change... that
> didn't make a difference.

op or inline has no effect

> I've never investigated how to select another "core"...

$ parrot --help

specifically -j -S -C -g

> The symptoms I see are that get_repr returns the correct string, but the
> appropriate REG_STR does not get updated.

Then there is a problem elsewhere. You can inspect interpreter registers
too:

gdb> p *interpreter->ctx.bp

or with the hints in docs/jit.pod or docs/debug.pod (after loading the
stabs file) you can even:

gdb> p *S7 # print contents of Parrot REG_STR(7)

leo


Sam Ruby

unread,
Dec 16, 2004, 10:47:02 AM12/16/04
to Leopold Toetsch, perl6-i...@perl.org
Leopold Toetsch wrote:

> Sam Ruby wrote:
>
>> Leopold Toetsch wrote:
>>
>>>> +inline op get_repr(out STR, in PMC) {
>>>> + STRING *s = $2->vtable->get_repr(interpreter, $2);
>>>> + $1 = s;
>>>> goto NEXT();
>>>> }
>>>
>>> Strange. Stranger. Strangest. Did the test fail with JIT/i386 only?
>>
>> I didn't mean to commit the "inline" portion of the change... that
>> didn't make a difference.
>
> op or inline has no effect
>
>> I've never investigated how to select another "core"...
>
> $ parrot --help
>
> specifically -j -S -C -g

Here's the results *with* the above change:

rubys@rubix:~/parrot$ parrot test.pir
5 T(5)
rubys@rubix:~/parrot$ parrot -j test.pir
5 T(5)
rubys@rubix:~/parrot$ parrot -S test.pir
5 T(5)
rubys@rubix:~/parrot$ parrot -C test.pir
5 T(5)
rubys@rubix:~/parrot$ parrot -g test.pir
5 T(5)

Here's the results *without* the above change:

rubys@rubix:~/parrot$ parrot test.pir
5
rubys@rubix:~/parrot$ parrot -j test.pir
5
rubys@rubix:~/parrot$ parrot -S test.pir
5 T(5)
rubys@rubix:~/parrot$ parrot -C test.pir
5 T(5)
rubys@rubix:~/parrot$ parrot -g test.pir
5

>> The symptoms I see are that get_repr returns the correct string, but
>> the appropriate REG_STR does not get updated.
>
> Then there is a problem elsewhere. You can inspect interpreter registers
> too:
>
> gdb> p *interpreter->ctx.bp

In Parrot_PyClass_get_repr, line 197 is:

temp = Parrot_run_meth_fromc_args(INTERP, repr, SELF, REPR, "P");

Before this line is executed,

(gdb) p interpreter->ctx.bp
$1 = (struct parrot_regs_t *) 0x40b6bd88

After the above line is executed:

(gdb) p interpreter->ctx.bp
$2 = (struct parrot_regs_t *) 0x40b6bae8

Two questions come to mind:

1) Should this call to run_meth change the context? In this case, repr
happens to be a Closure based on some assumptions I made early on in
this process that I need to revisit. Arguably, this is a bug, but in
the general case, can one always assume that the context does not change?

2) If there is the possibility that the context can change, into which
context should the results of get_repr be placed? Splitting the
statement in op get_repr as I did above guarantees that the macro will
expand using the values *after* the call.

Note: if the context is not supposed to change as a result of runops,
perhaps an internal exception should be thrown.

- Sam Ruby

Leopold Toetsch

unread,
Dec 16, 2004, 11:19:41 AM12/16/04
to Sam Ruby, perl6-i...@perl.org
Sam Ruby wrote:
> Before this line is executed,
>
> (gdb) p interpreter->ctx.bp
> $1 = (struct parrot_regs_t *) 0x40b6bd88
>
> After the above line is executed:
>
> (gdb) p interpreter->ctx.bp
> $2 = (struct parrot_regs_t *) 0x40b6bae8

Then is obviously your implementation of get_repr broken.

> Two questions come to mind:
>
> 1) Should this call to run_meth change the context?

Yes because a subroutine is run. But returning from it via a (return-)
continuation restores the context and the register frame pointer or it
ought to.

> ... In this case, repr

> happens to be a Closure based on some assumptions I made early on in
> this process that I need to revisit. Arguably, this is a bug, but in
> the general case, can one always assume that the context does not change?

Only function calls / returns may change the context. A simple opcode
like get_repr isn't allowed to do that.

> Note: if the context is not supposed to change as a result of runops,
> perhaps an internal exception should be thrown.

We can't check that on each opcode. That just must not happen :)

But before you implement more and more methods I'd rather have
inheritance and method calling conventions fixed. Parrot should call the
approriate method if it exists in the class namespace (if find_method
did return something).

> - Sam Ruby

leo

Sam Ruby

unread,
Dec 16, 2004, 1:36:00 PM12/16/04
to Leopold Toetsch, perl6-i...@perl.org
Leopold Toetsch wrote:

> Sam Ruby wrote:
>
>> Before this line is executed,
>>
>> (gdb) p interpreter->ctx.bp
>> $1 = (struct parrot_regs_t *) 0x40b6bd88
>>
>> After the above line is executed:
>>
>> (gdb) p interpreter->ctx.bp
>> $2 = (struct parrot_regs_t *) 0x40b6bae8
>
> Then is obviously your implementation of get_repr broken.
>
>> Two questions come to mind:
>>
>> 1) Should this call to run_meth change the context?
>
> Yes because a subroutine is run. But returning from it via a (return-)
> continuation restores the context and the register frame pointer or it
> ought to.
>
>> ... In this case, repr happens to be a Closure based on some
>> assumptions I made early on in this process that I need to revisit.
>> Arguably, this is a bug, but in the general case, can one always
>> assume that the context does not change?
>
> Only function calls / returns may change the context. A simple opcode
> like get_repr isn't allowed to do that.

The question isn't about what opcodes are or are not allowed to do. The
question is what VTABLE_* functions are or are not allowed to do. Can
VTABLE_invoke change the context? How about VTABLE_get_string?

If you look at the current delegate PMC, every VTABLE call is translated
to a call of a method. Are such methods allowed to change the context?

What are the rules?

>> Note: if the context is not supposed to change as a result of runops,
>> perhaps an internal exception should be thrown.
>
> We can't check that on each opcode. That just must not happen :)

I mustn't have been clear.

If things invoked by runops are not allowed to change the context, then
runops should throw an internal exception if the context changes.

On the other hand, if runops can't change the context, then why is
runops_args careful to capture the context prior to calling runops?

Again, what are the rules?

> But before you implement more and more methods I'd rather have
> inheritance and method calling conventions fixed. Parrot should call the
> approriate method if it exists in the class namespace (if find_method
> did return something).

How I chose to invest my time is up to me. If all that comes of it is
the few minor contributions I have made to the core of Parrot... then I
will be OK with that.

In most cases, I think I could adapt to a change in a matter of minutes.
You've seen me clone classes like BigInt and Complex wholesale, only
to gut them back once I had some partial ability to inherit MMD methods.

In the worst case, adapting to a major change would be a matter of days.
Again, my time to burn. Also, if you note, I am only writing the
minimum necessary to pass the given set of tests. That way there is
less for me to change when things change.

The reason why I am proceeding this way is that I found the previous
discussions on topics like object, classes, and metaclasses to be
frustrating. I want the next round to be based on specifics.

In particular, I don't want to have to respond to statements like "It
doesn't buy us anything, if we force all languages to create wrappers.".
I want to be able to point at a specific wrapper and ask the question:
how could it be done better?

Parrot_PyClass_get_repr is one such wrapper. How could it be done
better? If you make a specific suggestion there, I'll either adopt it
or produce a test case as a counter example.

- Sam Ruby

Leopold Toetsch

unread,
Dec 16, 2004, 3:26:55 PM12/16/04
to Sam Ruby, perl6-i...@perl.org, d...@sidhe.org
Sam Ruby wrote:
>
> Leopold Toetsch wrote:

>> Only function calls / returns may change the context. A simple opcode
>> like get_repr isn't allowed to do that.

> The question isn't about what opcodes are or are not allowed to do. The
> question is what VTABLE_* functions are or are not allowed to do. Can
> VTABLE_invoke change the context? How about VTABLE_get_string?

Well, I think it's all answered in the two quoted lines. C<invoke> can
change the context, but the next opcode after invoke has again the
original context, because of the function return restores the context.

All other methods aren't allowed to change the context.

> If you look at the current delegate PMC, every VTABLE call is translated
> to a call of a method. Are such methods allowed to change the context?

The delegate vtables or MMD wrappers call a method. That returns with
the passed in return continuation. So all the wrapped methods behave
exactly as if an opcode would have done the job. So no.

> If things invoked by runops are not allowed to change the context, then
> runops should throw an internal exception if the context changes.

Well, as already said, that would need a check for each opcode and we
don't do that. It's like a C compiler should check the stack pointer
after each execute hardware opcode.

> On the other hand, if runops can't change the context, then why is
> runops_args careful to capture the context prior to calling runops?

C<runops> is a low-level function that awaits all properly setup. Around
that are more function that e.g. create a return continuation and do
argument or returnvalue passing. Just use one of these functions as
delegate.c does.

> Again, what are the rules?

Simple: plain opcodes don't change the context. A function call does,
but the return has to restore the context. Ovleroading doesn't change
anything here.

>> But before you implement more and more methods I'd rather have
>> inheritance and method calling conventions fixed.

> How I chose to invest my time is up to me.

Of course. You have promised a summary ;)

> The reason why I am proceeding this way is that I found the previous
> discussions on topics like object, classes, and metaclasses to be
> frustrating. I want the next round to be based on specifics.

I was very specific. Parrot (or the runcore, the engine) does method
dispatch (when all is fixed and adjusted).

add Px, Py, Pz

is equivalent to a method call:

Px = Py."__add"(Pz)

The class (of Py) is queried via VTABLE_find_method() if it "can" do the
"add", which will eventually cause more find_method calls to find a
matching or best suited MMD method. After the method is found, it'll be
called, being it a C function or an overloaded piece of code.

That'll cost some cycles on the first execution of this one opcode. The
next one on that bytecode location is running 30%-70% faster as the
current static MMD lookup.

The signature of an overloaded function for above is

.sub myadd
.param left
.param right
...
.return(dest)
.end

"myadd" can be added via add_method() to the class (as "__add") or
Parrot picks up an existing "__add" in the appropriate namespace (which
will call add_method()). A class system can provide it's own
add_method/find_method pair or use Parrot's scheme.

The same basics holds for all overloadable operations, being it
currently vtable or MMD methods.

> I want to be able to point at a specific wrapper and ask the question:
> how could it be done better?

You need a wrapper, if the Parrot implementation of the method for that
class isn't matching Python semantics, e.g. to adjust return results. Or
you just install your own method, e.g. for "__repr". Almost all basic
methematical, logical, bitwise, ... operations should just have a
reasonable implementation in core, and all HLLs will just use that.

> Parrot_PyClass_get_repr is one such wrapper. How could it be done
> better? If you make a specific suggestion there, I'll either adopt it
> or produce a test case as a counter example.

You'd need in pyclass.pmc:

PMC* get_repr() {
return pmc_new_string( ... "<class ...>")
}

A method that returns the string representation of a PyClass object.

That's not a wrapper but an implementation for one specific class. No
wrapper for other classes or a dispatch through run_meth_fromc_args is
needed.

Nothing more will be needed, *when* all is fixed:

* we return PMCs normally (other types are optimizations)
* the methods create new PMCs - no LHS PMC is passed in
* all overloadable MMDs and vtables are registered as NCI methods
like the current METHOD syntax in .pmc files.
* Parrot knows common type names (Integer, Float, String, Bool, ...) of
the supported languages
* all dispatch is based on VTABLE_find_method

That's a simple scheme and should be well suited for all current target
languages - IMHO.

> - Sam Ruby

leo

Sam Ruby

unread,
Dec 16, 2004, 4:22:52 PM12/16/04
to Leopold Toetsch, perl6-i...@perl.org, d...@sidhe.org
Leopold Toetsch wrote:
>
>> Parrot_PyClass_get_repr is one such wrapper. How could it be done
>> better? If you make a specific suggestion there, I'll either adopt it
>> or produce a test case as a counter example.
>
> You'd need in pyclass.pmc:
>
> PMC* get_repr() {
> return pmc_new_string( ... "<class ...>")
> }

Just to be clarify, this is from the header comment in pyclass.pmc:

> These are the vtable functions for the Python Class base class (i.e.,
> methods you would expect to see on python objects).

For reference, here is the current definition of get_repr.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

/*

=item C<STRING *get_repr()>

Return the representation of this object.

=cut

*/

STRING* get_repr() {
PMC *repr = VTABLE_find_method(INTERP, SELF, REPR);

if (repr) {
PMC *temp = Parrot_run_meth_fromc_args(INTERP, repr, SELF,
REPR,
"PP", SELF);
return VTABLE_get_string(INTERP, temp);
}
else {
STRING *res;

res = string_from_cstring(INTERP, "<", 0);
res = string_append(INTERP, res,
VTABLE_name(INTERP, VTABLE_get_class(INTERP, SELF)), 0);
res = string_append(INTERP, res,
const_string(INTERP, " instance at "), 0);
res = string_append(INTERP, res,
Parrot_sprintf_c(INTERP, "%#x", (INTVAL) SELF), 0);
res = string_append(INTERP, res,
const_string(INTERP, ">"), 0);

return res;
}
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

In this case, there is a Python specific default. In other cases, there
are other Python specific behaviors like mapping not found to an
exception or to None. In short, I don't see wrappers going away.

> A method that returns the string representation of a PyClass object.
>
> That's not a wrapper but an implementation for one specific class. No
> wrapper for other classes or a dispatch through run_meth_fromc_args is
> needed.
>
> Nothing more will be needed, *when* all is fixed:
>
> * we return PMCs normally (other types are optimizations)
> * the methods create new PMCs - no LHS PMC is passed in
> * all overloadable MMDs and vtables are registered as NCI methods
> like the current METHOD syntax in .pmc files.

get_repr is overloadable. Being overloadable is the norm rather than
the exception in Python.

> * Parrot knows common type names (Integer, Float, String, Bool, ...) of
> the supported languages

The alternative (which is supported today) is that callers pass in a PMC
which defines a morph method which maps common type names to language
specific alternatives. Take a look at PyObject.pmc where I substitute
PyLong for BigInt.

The advantage of what exists today is that adding a new language does
not require any changes to Parrot. The caller defines the mapping.

> * all dispatch is based on VTABLE_find_method

Just to be clear, in the cases where a wrapper is needed (which I would
argue is the majority of cases), this works out to be: a call to
VTABLE_find_method for the wrapper which in turn uses VTABLE_find_method
to access the "real" logic.

> That's a simple scheme and should be well suited for all current target
> languages - IMHO.

Again, just to be clear: this hinges on dual assumptions: (1) that
wrappers aren't needed in the majority of cases, and (2) every time
someone gets or sets a method, a mapping can be done from language
defined names to Parrot conventions.

Note that in Python, all attributes may potentially be a method.

- Sam Ruby

Sam Ruby

unread,
Dec 16, 2004, 5:49:29 PM12/16/04
to Leopold Toetsch, perl6-i...@perl.org, d...@sidhe.org
Leopold Toetsch wrote:

>> On the other hand, if runops can't change the context, then why is
>> runops_args careful to capture the context prior to calling runops?
>
> C<runops> is a low-level function that awaits all properly setup. Around
> that are more function that e.g. create a return continuation and do
> argument or returnvalue passing. Just use one of these functions as
> delegate.c does.

I *am* using Parrot_run_meth_fromc_args, just like delegate.c does.

Single stepping through the debugger, I find that interpreter->ctx.bp is
changed by Parrot_Sub_invoke, line 299. The value is not changed after
that point, and still retains this new value when control returns to
Parrot_get_repr_s_p.

- Sam Ruby

Leopold Toetsch

unread,
Dec 17, 2004, 3:29:02 AM12/17/04
to Sam Ruby, perl6-i...@perl.org
Sam Ruby wrote:
>
> Leopold Toetsch wrote:
>>
>> You'd need in pyclass.pmc:
>>
>> PMC* get_repr() {
>> return pmc_new_string( ... "<class ...>")
>> }

> In this case, there is a Python specific default. In other cases, there

> are other Python specific behaviors like mapping not found to an
> exception or to None. In short, I don't see wrappers going away.

Yes, I already said that some methods might need either a wrapper or
just simpler the class implementes the method.

The problem with you code is: you call again VTABLE_find_method and
then, if a method is found, run_meth_fromc_args. This is already done by
Parrot eventually, you are already in PyClass.__repr__. No redispatch is
needed, just return a string.

> get_repr is overloadable. Being overloadable is the norm rather than
> the exception in Python.

Yes, of course. But that's part of the dispatch that Parrot is doing,
not part of *each* method in PyClass or such. If get_repr was overloaded
then Parrot runs the user code.

Again:

STRING* get_repr() {
PMC *repr = VTABLE_find_method(INTERP, SELF, REPR);

if (repr) {
PMC *temp = Parrot_run_meth_fromc_args(INTERP, repr, SELF, REPR

This part is done in the run-core. The HLLs part is to install a
function with add_method that is found if needed.

>> * Parrot knows common type names (Integer, Float, String, Bool, ...)
>> of the supported languages

> The alternative (which is supported today) is that callers pass in a PMC
> which defines a morph method which maps common type names to language
> specific alternatives.

Well and this scheme doesn't match overloaded methods. So we'd have two
different calling conventions, which of course would need glue code to
make them compatible. We don't need that glue code or wrapper, if
overloaded function syntax matches the internal C implementation.

> The advantage of what exists today is that adding a new language does
> not require any changes to Parrot. The caller defines the mapping.

Such a mapping is easily extendible. New languages aren't added
silently, Parrot needs to know a few bits about the HLL.

>> * all dispatch is based on VTABLE_find_method

> Just to be clear, in the cases where a wrapper is needed (which I would
> argue is the majority of cases), this works out to be: a call to
> VTABLE_find_method for the wrapper which in turn uses VTABLE_find_method
> to access the "real" logic.

No. VTABLE_find_method locates the very method that should be run. Being
it a C function or a user provided subroutine. So when e.g.
Parrot_PyInt_divide_PyInt is called, you know exactly the class (in case
of MMD both classes). As you know that the base class is Integer, you
can just call the baseclass function directly, if you desire so.
A user can't insert another __bases__ in core classes, so that's save.

For overloaded methods again the pair add_method/find_method is doing
the job. If the result of find_method is a Sub PMC, the run-core runs
the function.

> Again, just to be clear: this hinges on dual assumptions: (1) that
> wrappers aren't needed in the majority of cases,

Yes. Basic mathematical functions are just the same in Python or Perl6
or whatever.

> ... and (2) every time

> someone gets or sets a method, a mapping can be done from language
> defined names to Parrot conventions.

Of course. How else would you be able to overload "add Px, Py, Pz" if
you can't detect that certain manipulations of attributes have that effect?

> Note that in Python, all attributes may potentially be a method.

Yes. Your implementation of find_method has to cope with it. You need
that anyway.

> - Sam Ruby

leo

0 new messages