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

Value PMCs in Parrot?

0 views
Skip to first unread message

Audrey Tang

unread,
Mar 11, 2006, 1:35:11 PM3/11/06
to p6i, allison Randal, ch...@pobox.com
With Leo's help, I'm porting Pugs's native PIL VM to Parrot (HLL "Perl6"
under "pugs_group"), and we immediately stuck on translating the notion
of a "value object" to Parrot.

First, some backgrounds from Perl 6's class hierarchy. There are three
kinds of classes in Perl 6:

"Native" classes: bit, int, buf, str, num, complex...
"Value" classes: Undef, Ref, List, Bit, Int, Str, ...
"Container" classes: Scalar, Array, Hash, ...

Container classes are naturally PMCs.

We can map "int", "str" and "num" to registers, and "bit"/"buf"
can be emulated by "int"/"str" registers. However, for "complex" we
need either multiple registers, or (easier) always use a boxed Value class.

Unfortunately, Parrot has no natural way to represent Values. In Perl 5,
it's modelled as a "const" SV* with SVf_READONLY set:

$ perl -e 'for (1) { $_++ }'
Modification of a read-only value attempted at -e line 1.

Currently, the only way to mark a PMC as a "Value" PMC is to derive from
the mutable "scalar" interface first, and then manually disable all the
vmethods marked as "mutable" (e.g. "increment"). If we don't do this,
bizarre things like $_++ above can occur without checking.

Moreover, because Value PMCs never change their content, they can be
shared for autoboxing purposes (i.e. if I0 and I1 contains the same
integer, they box into the same PMC), as well as for other various
purposes, which may affect GC as well.

The easy workaround for now is to have a "does readonly" interface in
addition to the current "does scalar", which forbids all self-mutable
vmethods.

I don't know whether it makes sense to mark value-ness and use them
elsewhere -- certainly a too-drastic way is to have V* registers that
affects GC -- but at least I'd like a way for "1.id == 1.id" to work
reliably in the future.

Thanks,
Audrey

signature.asc

Joshua Isom

unread,
Mar 11, 2006, 8:55:11 PM3/11/06
to Audrey Tang, p6i
If the compiler goes through all the constants at compile time to find
identical ones, why not use ".const float number = 0.0"? With pmc's,
only .Sub is supported I think. But for more complex types, the best I
can think of is being able to freeze a pmc and store it into the const
table, such as in an :immediate sub just without running the opcodes
after compile time. I don't think it's possible to freeze a pmc into
the pbc, right now.

Leopold Toetsch

unread,
Mar 12, 2006, 6:46:36 AM3/12/06
to Joshua Isom, p6i

On Mar 12, 2006, at 2:55, Joshua Isom wrote:

> If the compiler goes through all the constants at compile time to find
> identical ones, why not use ".const float number = 0.0"?

That covers only a small part of the problem. 'Const's are still
mutable, they still morph, and PMCs with the same value don't have the
same .id. While Parrot PMCs pretend to be values too, they are much
more like vars.

irb(main):002:0> 2.id
=> 5
irb(main):003:0> (1+1).id
=> 5

$ cat c.pir
.sub main :main
.const .Integer i = "42"
print i
print "\n"
inc i
print i
print "\n"
i = 3.14
print i
print "\n"
.end

$ ./parrot c.pir
42
43
3.14

leo

Chip Salzenberg

unread,
Apr 4, 2006, 12:48:31 PM4/4/06
to Audrey Tang, p6i, allison Randal
As a followup to my previous early opinions:

I've done some [more] reading up on value types. I'm now more sure now than
ever that my initial decision was the right one: Parrot 1.0 will _not_ have
native support for anything like value types. Parrot 1.0's type universe
will consist entirely of [ISNP].

Thus, any implementation (emulation?) of value semantics will be built on
PMCs like other types, and will thus continue to live in the GC universe,
all a la JValue.

On Sun, Mar 12, 2006 at 02:35:11AM +0800, Audrey Tang wrote:
> The easy workaround for now is to have a "does readonly" interface in
> addition to the current "does scalar", which forbids all self-mutable
> vmethods.

That's a good hack.

Perhaps unrelated, perhaps not: Parrot will soon have a flyweight read-only
proxy PMC, which will address the use case of "sub foo($a)", in which $a
must be a read-only alias of the passed argument. Language implementors may
find this useful in some otherwise value-oriented situations.

PS: Rant against the annoying introduction of scalar containers in Perl 6
elided here, partly for brevity, but mostly for blood pressure.
--
Chip Salzenberg <ch...@pobox.com>

Chip Salzenberg

unread,
Apr 11, 2006, 1:03:43 PM4/11/06
to Leo Toetsch, Audrey Tang, perl6-i...@perl.org
{ p6i added ... this has turned into an interesting design discussion }

On Wed, Apr 05, 2006 at 03:54:51PM +0200, Leopold Toetsch wrote:
> On Tue, Apr 04, 2006 at 11:42:36AM -0700, Chip Salzenberg wrote:
> > I've done some [more] reading up on value types. [...]


> > Parrot 1.0 will _not_ have native support for anything like value types.
> > Parrot 1.0's type universe will consist entirely of [ISNP].
>

> A value PMC is just a PMC. I don't see a need to extend the type system,
> when supporting value PMCs. I see these more as just another PMC with
> different semantics (compared to current existing morphing PMCs).

Well, there's more than one kind of value type. I'm sure somebody
(*cough*Audrey*cough*) can provide us standard names from the literature,
but the key distinction I see is between a reference model and a value
model. I was talking about the value model, mostly.

1. "Value Model" for value objects

Extending the basic VM treatment of integers -- create and destroy them
without involving the GC subsystem, and copy them with memcpy() -- to new
user-created types. Imagine if time-critical Parrot code could
manipulate e.g. a complex number that was defined as nothing more than a
pair of N values just by copying it around rather than doing the "new
.Complex" zoo dance, perhaps to support high-speed graphics. Right now
you'd have to dive into C to do that sort of thing efficiently.

Cool concept, and will take a fair bit of design work to make useful, but
is not on my short list at the moment, and if Parrot 1.0 does without it,
that'll be OK with me.

Audrey pointed out that one way to handle this sort of value type is to
introduce a new kind of register, which is why saying 'stick with [ISNP]'
is synonymous with 'no value types' [of that nature].

2. "Reference Model" for value objects

In Parrot, this mostly amounts to unique read-only PMCs.
We'll have the read-only part, but the "unique" part, probably not.

By "unique" I'm talking about enforced global uniqueness of a given
value, e.g. string memoization. (A global uniqueness guarantee
ensures that e.g. "(1+1).id == 2.id".) Audrey requested this, but
I'm not planning to provide it. She's willing to do without ... or,
actually, is willing to implement it herself where needed.

(I actually don't object to the idea of enforced global global
uniqueness, but I don't know how Parrot should do it, and until object
construction is reviewed [and possibly reformed], I don't want to hang a
picture on the wall scheduled for demolition.)

Leo:
> Chip:


> > On Sun, Mar 12, 2006 at 02:35:11AM +0800, Audrey Tang wrote:
> > > The easy workaround for now is to have a "does readonly" interface in
> > > addition to the current "does scalar", which forbids all self-mutable
> > > vmethods.
> >
> > That's a good hack.
> >
> > Perhaps unrelated, perhaps not: Parrot will soon have a flyweight read-only
> > proxy PMC, which will address the use case of "sub foo($a)", in which $a
> > must be a read-only alias of the passed argument. Language implementors may
> > find this useful in some otherwise value-oriented situations.
>

> That would work of course. But I'm curious, where the 'flyweight' would
> come from. It would be the same as the existing Ref PMC. Or the same
> weight as a scalar container PMC.

Flyweight in terms of added semantics (very little) and visibility to users
(almost none). "You'll hardly know it's there." OTOH, memory usage will,
as you say, not be very different from a Ref, unless we hack something up
specially. I want to wait to see what actually uses memory before we start
optimizing one use case over another. In the average running Parrot app,
will there be more integers, or more readonly_proxies, or more of ... something
else?
--
Chip Salzenberg <ch...@pobox.com>

Leopold Toetsch

unread,
Apr 12, 2006, 7:55:28 PM4/12/06
to Chip Salzenberg, perl6-i...@perl.org, Audrey Tang

On Apr 11, 2006, at 19:03, Chip Salzenberg wrote:

> 1. "Value Model" for value objects
>

> .... which is why saying 'stick with [ISNP]'


> is synonymous with 'no value types' [of that nature].

Ack. That's certainly an optimization thingy (e.g. native 'complex'
type ...) and not targeted now.

>
> 2. "Reference Model" for value objects
>
> In Parrot, this mostly amounts to unique read-only PMCs.
> We'll have the read-only part, but the "unique" part, probably not.

Can I/we read this as: "morphing for Parrot core PMCs is history"? - Or
in other words: differently sized PMCs (with a common (PObj) header) is
the way to go?

The C<"unique" part> is, as already mentioned, rather orthogonal, but a
nice to have, when it comes to hash lookups or shared MP items.

leo

Chip Salzenberg

unread,
Apr 16, 2006, 7:34:42 PM4/16/06
to Leopold Toetsch, perl6-i...@perl.org
On Thu, Apr 13, 2006 at 01:55:28AM +0200, Leopold Toetsch wrote:
> On Apr 11, 2006, at 19:03, Chip Salzenberg wrote:
> >2. "Reference Model" for value objects
> > In Parrot, this mostly amounts to unique read-only PMCs.
> > We'll have the read-only part, but the "unique" part, probably not.
>
> Can I/we read this as: "morphing for Parrot core PMCs is history"? - Or
> in other words: differently sized PMCs (with a common (PObj) header) is
> the way to go?

Heh. When I want to say that, I think I know how to be clear. :-)

But on the subject of PMC restructuring:

* Your description of the status quo is that every access to the class-
specific data in a PMC, e.g. to the array elements of a PMC array,
require three indirections: One to the PMC, one to the PMC_EXT, and then
one more to the user-defined data.

But: I see extensive use of PMC_(struct|pmc|int|num|str)_val() in *.pmc.
So triple indirection is hardly universal. Granted it is necessary for
some cases, but the situation isn't as unliveable as I understood you to
say earlier.

+ BTW, I don't see any use of PObj_buf(start|len) in *.pmc, and I find
this odd. Surely there must be PMCs that would find it helpful to
have both a pointer and a length without additional indirections...?

* A consequence of variable-length PMCs would be a merging of PMC_EXT into
PMC.

Why wait for variable-length PMCs to get rid of PMC_EXT? Doing so now
would eliminate an indirection and a pointer, which should help according
to your theory.

I'm told that PMC_EXT was introduced to help cache line behavior, but if
I read the tea leaves^W^Wsource code correctly, sizeof(PMC) is right now
five words on a 32-bit machine, an odd choice -- it should be possible to
hit eight words instead, which ought to be cache-friendlier.

--
Chip Salzenberg <ch...@pobox.com>

Leopold Toetsch

unread,
Apr 17, 2006, 8:42:07 AM4/17/06
to Chip Salzenberg, perl6-i...@perl.org

On Apr 17, 2006, at 1:34, Chip Salzenberg wrote:

> But: I see extensive use of PMC_(struct|pmc|int|num|str)_val() in
> *.pmc.

Sure. There are just these 1 or 2 data items in the PMC and these are
of course heavily used. But e.g. a Resizable<x>Array would need 3
items: n_first_elem, n_elements, and n_allocated.
The Complex or BigInt PMCs don't have enough space to store their data,
so these use a malloced storage hanging off PMC_struct_val...
OTOH a plain Integer just needs one data item...

> So triple indirection is hardly universal. Granted it is necessary
> for
> some cases, but the situation isn't as unliveable as I understood
> you to
> say earlier.
>
> + BTW, I don't see any use of PObj_buf(start|len) in *.pmc, and I
> find
> this odd. Surely there must be PMCs that would find it helpful
> to
> have both a pointer and a length without additional
> indirections...?


PObj_buf{start,len} is used by bufferlike PObjs e.g. STRING* or for the
storage of array PMCs derived from list.c (Array, PerlArray). The
buffer may move during GC (src/resources.c:compact_pool()), which is
sometimes not really wanted.

>
> * A consequence of variable-length PMCs would be a merging of PMC_EXT
> into
> PMC.

Yes, at least for these parts that are really needed. A PMC that
doesn't contain any other PMC doesn't need C<_next_for_GC> (this item
is used for DOD mainly, to avoid deep recursion). C<_metadata> - the
property hash - shouldn't be needed in the long run: a perl6ish '0 but
true' creates a new Role according to S12.

> Why wait for variable-length PMCs to get rid of PMC_EXT? Doing so
> now
> would eliminate an indirection and a pointer, which should help
> according
> to your theory.

Just appending PMC_EXT to the PMC slows down Integer and Float. These 2
PMCs don't need anything from PMC_EXT. OTOH a Complex or BigInt PMC
would still need the malloced storage for it's data.

>
> I'm told that PMC_EXT was introduced to help cache line behavior,

No. It was introduced to reduce PMC size for Integer and Float. The
size reduction of scalar PMCs reduced data cache misses.

leo

0 new messages