Storing Classes in Bytecode
Peter Lobsinger
plobsing at gmail.com
Wed Aug 4 05:47:02 UTC 2010
On Tue, Aug 3, 2010 at 6:11 AM, Jonathan Worthington <jonathan at jnthn.net> wrote:
> On 02/08/2010 08:05, Peter Lobsinger wrote:
>>
>> On Fri, Jul 30, 2010 at 8:08 PM, Jonathan Worthington
>> <jonathan at jnthn.net> wrote:
>>
>>>
>>> Here's one critical thing, however. This is _not_ about a constant
>>> segment.
>>> I could have a module...
>>>
>>> class Lolspeak {
>>> method lol() { say "oh lol" }
>>> }
>>>
>>> That I pre-compile to a PBC. I then do in a script:
>>>
>>> use Lolspeak;
>>> augment class Lolspeak {
>>> method wtf() { say "omg you forgot a wtf method?" }
>>> }
>>>
>>> Which would call .add_method on the meta-class which would then have to
>>> change its internal state to know about the new method. Thus these things
>>> aren't constants once they're loaded into memory (they *may* be, but not
>>> by
>>> default). Same for subs, which we may end up calling .wrap on. Really,
>>> they're just objects we've serialized, and want to deserialize at
>>> startup.
>>>
>>
>> "Constant" is a bit of misnomer. The objects contained in a PBC
>> constant segment are not immutable simply by originating there. It is
>> simply a collection of strings and PMCs associated with a segment of
>> bytecode. This may be useful for implementing constants, but it is not
>> limited to that.
>>
>> .sub 'consty' :anon :immediate
>> $P0 = new ['String']
>> $P0 = "Hi"
>> .return ($P0)
>> .end
>>
>> .sub 'main' :main
>> .const 'Sub' $P0 = 'consty'
>> say $P0
>> $P0 = "Lo"
>>
>> .const 'Sub' $P1 = 'consty'
>> say $P1
>> .end
>>
>>
>
> OK - does the GC actually walk through the things referenced from this
> segment too? If so, then yes, we probably could get away with using the
> "constant" segment (and maybe rename it :-)).
Yes, the GC traverses these objects.
Agreed, "constant" has too much associated (and misleading) meaning.
At the risk of being too generic sounding, I propose the name "data
segment" or "runtime data segment".
>>> A tricky issue that will need some thought is if I then wrote:
>>>
>>> use Lolspeak;
>>> class MoreLolspeak is Lolspeak {
>>> method omg() { say "OMG you accidentally the WHOLE MOP!" }
>>> }
>>>
>>> Then the meta-object for MoreLolspeak is going to reference the one from
>>> Lolspeak. Somehow, there will need to be some "bounding" on what we
>>> freeze
>>> and a cross-PBC way to do referencing. That's going to be tricky, but
>>> important. Alas, I've probably introduced enough things to ponder in this
>>> email so far, and it'd be good to get some reactions. :-)
>>>
>>
>> On the surface it is tricky, but there is a simple answer: let the
>> class implementation take care of it.
>
> No, that answers nothing. I think you missed the point of what I was saying.
> There will be no class implementation that isn't itself just an object. Put
> another way, everything is going to be an object, it's just that one of them
> will happen to implement the MOP in a way that specifies the semantics of
> something that we consider class-y.
Object, class, prototype, whatever you want to call the thing that
backs the object by providing (among other things) vtables.
In the current design, objects know more about how to serialize
themselves than does the serializer. Knowing points at which to stop
traversing the object graph is no different. After all, it is each
object's vtable that indicates that the serializer should traverse
further.
>> If it is desired that classes not recurse indefinitely up the chain of
>> ancestors, the class freeze/thaw vtable implementation should serialize only
>> the names of
>> the resources it requires,
>
> Even if there was something we could identify as a "class" and choose to
> give it different serialization semantics, this still doesn't help us if we
> want to serialize an object whose type object/meta-objects live in another
> PBC.
We do need an easy, user-accessible API to lookup a PMC in PBCs; but
its use should be driven by object vtable methods.
>> looking them up symbolically upon deserialization.
>>
>
> Won't work with anonymous classes.
If you don't have a way of uniquely refering to the resource, how do
you expect Parrot to have one?
>> Alternate solutions exist such as configuring or overriding (eg:
>> through hll_mapping) the serializer to do similar things, but these
>> are likely not as clean or as simple.
>>
>
> No, the clean solution is to make the general mechanism I originally
> proposed. I know it's not _simple_ - but I suspect something simpler than it
> falls short of requirements.
We already have half of what you want. The basic concept of
SerializationContext maps fairly well to the PackfileConstantTable PMC
when compiling straight to PBC using the Packfile PMCs. The only issue
is how to make the traversal smart and cover the edge cases described.
>>> I imagine that however other HLLs choose to represent their classes,
>>> they'll
>>> all benefit from being able to get them into the PBC. This is something
>>> we
>>> could integrate some support for into HLL::Compiler, perhaps. Not to
>>> mention
>>> it's a solution for other constant objects too.
>>>
>>
>> A better API for getting at this and other PBC functionality would be
>> very useful.
>
> Aye though I'd like to keep the API for this mostly apart from PBC.
That's just a question of how many abstraction layers you want to put
between yourself and Parrot. In the end, if it is running in Parrot,
it is PBC.
>> This will probably come about quite naturally from
>> efforts to cut PIR out of the PCT compilation sequence. A better API
>> within PIR is also possible by making the current PIR compiler
>> accessible as an object in :immediate subs.
>>
>>
>
> I wasn't expecting to use intermediate subs at all. We'd just create the
> objects from action methods and add them to the serialization context. I
> shouldn't have to compile code to make the objects I want, I should just be
> able to Foo.new 'em.
>
> Thanks,
>
> Jonathan
>
>
More information about the parrot-dev
mailing list