The Trunk: System-cwp.660.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
39 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Re: The Trunk: System-cwp.660.mcz

Florin Mateoc-4
On 1/11/2014 4:29 PM, Colin Putney wrote:



On Sat, Jan 11, 2014 at 12:11 PM, Florin Mateoc <[hidden email]> wrote:
 
I would think that materializing proxies or otherwise creating new objects within an allObjectsDo: loop is a bug, just
as it usually is whenever one grows a collection while iterating over it. It is the responsibility of the caller to
ensure that this does not happen.

If that's the case, then the caller may not send any messages to the objects enumerated. That seems overly restrictive to me. 
 
Colin
 



    

I am curious how would you implement #nextObject so that you could iterate over all objects in an image even if you create new objects after the first call to #nextObject.

Florin


Reply | Threaded
Open this post in threaded view
|

Re: The Trunk: System-cwp.660.mcz

Colin Putney-3
In reply to this post by Bert Freudenberg



On Sat, Jan 11, 2014 at 12:35 PM, Bert Freudenberg <[hidden email]> wrote:
 
Or maybe it should use #isInMemory to only check the objects in memory.

That does have the advantage of being implemented in ProtoObject. Perhaps the contract should be that the caller should not send messages (other than #isInMemory) to any object that is not in memory.  Or perhaps #allObjectsDo: shouldn't send objects that are not in memory to the block. 

Colin


Reply | Threaded
Open this post in threaded view
|

Re: The Trunk: System-cwp.660.mcz

Florin Mateoc-4
In reply to this post by Colin Putney-3
On 1/11/2014 4:26 PM, Colin Putney wrote:



On Sat, Jan 11, 2014 at 12:05 PM, Bert Freudenberg <[hidden email]> wrote:
 
... which is when you got the 0. Or are you asking why we need the sentinel? Because if aBlock keeps allocating objects, we would never reach the end.

According to the comment in #allObjectsDo: we need the sentinel because the *execution* of aBlock will allocate an object - the activation context. So regardless of what aBlock actually does, we need the sentinel to avoid an infinite loop.

However, this bug causes the loop to skip over the sentinel. If the comment is right, we should end up in an infinite loop. But we don't, we eventually get 0. Why?

Colin 



    

It does not skip over the sentinel. It encounters the "end" earlier because you create a new object after the sentinel was created.
If you do Object new nextObject you get 0. So when the proxy is materialized and then gets sent nextObject it returns 0

Florin


Reply | Threaded
Open this post in threaded view
|

Re: The Trunk: System-cwp.660.mcz

Colin Putney-3



On Sat, Jan 11, 2014 at 5:12 PM, Florin Mateoc <[hidden email]> wrote:
On 1/11/2014 4:26 PM, Colin Putney wrote:
 
It does not skip over the sentinel. It encounters the "end" earlier because you create a new object after the sentinel was created.
If you do Object new nextObject you get 0. So when the proxy is materialized and then gets sent nextObject it returns 0

This is what I mean. We start enumerating objects with nil, walk through memory until we hit the proxy, jump forward in memory to the materialized ancestry object, and continue until we hit 0. That jump causes a bunch of objects to be skipped, including the sentinel. 

It still doesn't explain why we get to the end of memory. MCProxyInfo faults in its target by reading MC versions into the image from a repository, then searching their ancestries for the object it represents. The object it becomes is virtually guaranteed not to be the most recent object allocated. So #nextObject will answer some object, and we'll execute the block at least once more. That should send us into the infinite loop that the sentinel object is designed to prevent. 

My guess is that Cog (and any StackVM?) is optimizing away the creation of activation contexts. So we do get new objects after the sentinel, but since we don't create new objects on *every* block activation, we eventually catch up and get 0. This makes me wonder if the sentinel is actually necessary. Even the classical interpreter VM recycles activation contexts, and therefor shouldn't create a new object for every block activation. 

We could have the contract offered by #allObjectsDo: be that all objects that exist at the time of the method activation will be enumerated, but any new objects created by the block will not. That would imply using a sentinel. Or we could specify that #allObjectsDo: will enumerate objects created in the block, but it's up to the caller to ensure that memory doesn't grow faster than we can scan through it. That would imply using 0 as the termination condition for the loop. Either way, we should use Levente's idea to prevent skipping large swathes of the object memory. 

Colin





Reply | Threaded
Open this post in threaded view
|

Re: The Trunk: System-cwp.660.mcz

Florin Mateoc-4
On 1/11/2014 6:18 PM, Colin Putney wrote:



On Sat, Jan 11, 2014 at 5:12 PM, Florin Mateoc <[hidden email]> wrote:
On 1/11/2014 4:26 PM, Colin Putney wrote:
 
It does not skip over the sentinel. It encounters the "end" earlier because you create a new object after the sentinel was created.
If you do Object new nextObject you get 0. So when the proxy is materialized and then gets sent nextObject it returns 0

This is what I mean. We start enumerating objects with nil, walk through memory until we hit the proxy, jump forward in memory to the materialized ancestry object, and continue until we hit 0. That jump causes a bunch of objects to be skipped, including the sentinel. 

It still doesn't explain why we get to the end of memory. MCProxyInfo faults in its target by reading MC versions into the image from a repository, then searching their ancestries for the object it represents. The object it becomes is virtually guaranteed not to be the most recent object allocated. So #nextObject will answer some object, and we'll execute the block at least once more. That should send us into the infinite loop that the sentinel object is designed to prevent. 


No, by following the proxy's nextObject, we start iterating a different loop than the original one (constituted by the bunch of objects just created, the proxy being the oldest in the bunch) until we reach the newest one among them, which will return 0.
The sentinel is there because, even if only one block activation is created, we do not want to include it in the iteration, otherwise a check for 0 would be good enough.
If you open code the loop (say [(next := next nextObject) ~= 0] whileTrue: [...loop body...]) there is no block activation, so a check for 0 would be enough (if we don't otherwise create new objects).

Florin


Reply | Threaded
Open this post in threaded view
|

Re: The Trunk: System-cwp.660.mcz

Colin Putney-3



On Sat, Jan 11, 2014 at 6:40 PM, Florin Mateoc <[hidden email]> wrote:
 
No, by following the proxy's nextObject, we start iterating a different loop than the original one (constituted by the bunch of objects just created, the proxy being the oldest in the bunch) until we reach the newest one among them, which will return 0.

I'm pretty sure there's just one loop. #allObjectsDo has one #whileFalse: message, and it keeps iterating until we reach 0. 
 
The sentinel is there because, even if only one block activation is created, we do not want to include it in the iteration, otherwise a check for 0 would be good enough.

According to the comment Andreas wrote, the sentinel is there to prevent an infinite loop. 
 
If you open code the loop (say [(next := next nextObject) ~= 0] whileTrue: [...loop body...]) there is no block activation, so a check for 0 would be enough (if we don't otherwise create new objects).

 There *is* a block activation, because the loop body sends #value: to aBlock.

Colin


Reply | Threaded
Open this post in threaded view
|

Re: The Trunk: System-cwp.660.mcz

Nicolas Cellier

2014/1/12 Colin Putney <[hidden email]>



On Sat, Jan 11, 2014 at 6:40 PM, Florin Mateoc <[hidden email]> wrote:
 
No, by following the proxy's nextObject, we start iterating a different loop than the original one (constituted by the bunch of objects just created, the proxy being the oldest in the bunch) until we reach the newest one among them, which will return 0.

I'm pretty sure there's just one loop. #allObjectsDo has one #whileFalse: message, and it keeps iterating until we reach 0. 
 
The sentinel is there because, even if only one block activation is created, we do not want to include it in the iteration, otherwise a check for 0 would be good enough.

According to the comment Andreas wrote, the sentinel is there to prevent an infinite loop. 
 
If you open code the loop (say [(next := next nextObject) ~= 0] whileTrue: [...loop body...]) there is no block activation, so a check for 0 would be enough (if we don't otherwise create new objects).

 There *is* a block activation, because the loop body sends #value: to aBlock.

Colin


Could it be an effect of recycling the same Context object in classical VMInterpreter ?
In Stack interpreter (thus COG), that's yet another problem, the Context instantiation can be avoided...



Reply | Threaded
Open this post in threaded view
|

Re: The Trunk: System-cwp.660.mcz

Florin Mateoc-4
In reply to this post by Colin Putney-3
On 1/12/2014 9:22 AM, Colin Putney wrote:



On Sat, Jan 11, 2014 at 6:40 PM, Florin Mateoc <[hidden email]> wrote:
 
No, by following the proxy's nextObject, we start iterating a different loop than the original one (constituted by the bunch of objects just created, the proxy being the oldest in the bunch) until we reach the newest one among them, which will return 0.

I'm pretty sure there's just one loop. #allObjectsDo has one #whileFalse: message, and it keeps iterating until we reach 0. 
 

There is no loop per se. #nextObject will always point to a newer object than self. If we, at some point send #nextObject to a newly created object, like in the case of a materialized proxy, this newly created object is already newer than the sentinel and the chain will never point back to before the sentinel. So once #nextObject gets sent to the newer object, it will only follow the chain of objects that are even newer than the former proxy, which is a finite bunch, and when we reach the newest of the bunch it will return 0.

Florin


Reply | Threaded
Open this post in threaded view
|

I would not have thought I ever say that: lets have a new primitve (was: Re: [squeak-dev] The Trunk: System-cwp.660.mcz)

Tobias Pape
Hi all,
On 12.01.2014, at 18:26, Florin Mateoc <[hidden email]> wrote:

> On 1/12/2014 9:22 AM, Colin Putney wrote:
>>
>>
>>
>> On Sat, Jan 11, 2014 at 6:40 PM, Florin Mateoc <[hidden email]> wrote:
>>  
>> No, by following the proxy's nextObject, we start iterating a different loop than the original one (constituted by the bunch of objects just created, the proxy being the oldest in the bunch) until we reach the newest one among them, which will return 0.
>>
>> I'm pretty sure there's just one loop. #allObjectsDo has one #whileFalse: message, and it keeps iterating until we reach 0.
>>  
>
> There is no loop per se. #nextObject will always point to a newer object than self. If we, at some point send #nextObject to a newly created object, like in the case of a materialized proxy, this newly created object is already newer than the sentinel and the chain will never point back to before the sentinel. So once #nextObject gets sent to the newer object, it will only follow the chain of objects that are even newer than the former proxy, which is a finite bunch, and when we reach the newest of the bunch it will return 0.
>
> Florin
>
Let’s be frank here:
As long as the enumeration of all hitherto object is
non-atomic, we always have to be extremely careful as to what
to do about new objects, when to allocate etc.pp.
  I really don’t like to say it, but it seems to me, that a
VM primitive (say #primAllObjectsDo:) would be apt here.
Yes, it is not as elegant as #someObject/#nextObject seems,
but we could surely get a behavior that
• does not depend (image-side) on GC behavior
  (Currently, it seems really just coincidence, that the sentinel
   object is the last one enumerated),
• is more easy implemented by cousin VMs (say, Potato, SqueakJS,
  SPy/RSqueakVM, SqueakMaxine†
  as it does not make assumptions image-side on the Image layout,
• does not expose the sentinel (should there be one) to the image

The current logic could easily be the fallback assumption for VMs up to now.

I am not the person to shout “new primitives”, au contraire, I mostly favor
moving stuff from the VM to the image, but in this instance—and clearly with
seeing the different SqueakVM implementations—I think a new primitive is fair.

Best
        -Tobiad






signature.asc (1K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: The Trunk: System-cwp.660.mcz

Colin Putney-3
In reply to this post by Florin Mateoc-4



On Sun, Jan 12, 2014 at 12:26 PM, Florin Mateoc <[hidden email]> wrote:
 
There is no loop per se. #nextObject will always point to a newer object than self. If we, at some point send #nextObject to a newly created object, like in the case of a materialized proxy, this newly created object is already newer than the sentinel and the chain will never point back to before the sentinel. So once #nextObject gets sent to the newer object, it will only follow the chain of objects that are even newer than the former proxy, which is a finite bunch, and when we reach the newest of the bunch it will return 0.

Ugh. Whatever. 


Reply | Threaded
Open this post in threaded view
|

Re: I would not have thought I ever say that: lets have a new primitve (was: Re: [squeak-dev] The Trunk: System-cwp.660.mcz)

Colin Putney-3
In reply to this post by Tobias Pape



On Sun, Jan 12, 2014 at 12:47 PM, Tobias Pape <[hidden email]> wrote:
 
I am not the person to shout “new primitives”, au contraire, I mostly favor
moving stuff from the VM to the image, but in this instance—and clearly with
seeing the different SqueakVM implementations—I think a new primitive is fair.

You know, this makes me wonder if we should just get rid of #allObjectsDo: entirely. Anyone that wants to visit all the objects in the image can use #someObject and #nextObject directly, and write the loop in a way that makes sense for that use case. That also means we don't have problems on older VMs because inlining the loop means we don't create a block context every time we go through it. 

Colin


Reply | Threaded
Open this post in threaded view
|

Re: The Trunk: System-cwp.660.mcz

Eliot Miranda-2
In reply to this post by Florin Mateoc-4
Hi All,


On Sat, Jan 11, 2014 at 1:51 PM, Florin Mateoc <[hidden email]> wrote:
On 1/11/2014 4:29 PM, Colin Putney wrote:



On Sat, Jan 11, 2014 at 12:11 PM, Florin Mateoc <[hidden email]> wrote:
 
I would think that materializing proxies or otherwise creating new objects within an allObjectsDo: loop is a bug, just
as it usually is whenever one grows a collection while iterating over it. It is the responsibility of the caller to
ensure that this does not happen.

If that's the case, then the caller may not send any messages to the objects enumerated. That seems overly restrictive to me. 
 
Colin
 



    

I am curious how would you implement #nextObject so that you could iterate over all objects in an image even if you create new objects after the first call to #nextObject.
 

The bug is in implementing allObjects in terms of someObject and nextObject in the first place.  It's cheap and cheerful but horribly error-prone and restrictive.  It's cheap because the collection of objects doesn't have to be created, and on the original 16-bit Smalltalk machines that was really important.  It's horribly restrictive because it assumes much about the implementation.

Before closures a sentinel wasn't even needed because enumerating the block didn't create a new object (the block context was reused).  So the code had to be rewritten just to support closures.

Spur has a generation scavenger operating in a distinct new space and that doesn't jive well with a consistent ordering at all.  So far the system is limping along by tenuring all objects on someObject and someInstance (so that newSpace is either empty, or doesn't contain any instances of a specific class) and having nextObject enumerate only objects in oldSpace.

But I think now we can afford a primitive that answers all the objects (remember that average object size means that such a collection will be ~ 10% of the heap, average object size in Squeak V3 is about 10.6 words).  At least that's what Spur will do, along with an allInstancesOf: primitive.  And then the become example won't cause any problems at all.  Far more reliable.  I suppose there are circumstances when enumerating without a container is the only feasible approach, but VisualWorks has got along with only an allObjects primitive for a long time now.  I suspect we can too.

--

best,

Eliot


Reply | Threaded
Open this post in threaded view
|

Re: I would not have thought I ever say that: lets have a new primitve (was: Re: [squeak-dev] The Trunk: System-cwp.660.mcz)

Stefan Marr-3
In reply to this post by Tobias Pape
Hi Tobias:

On 12 Jan 2014, at 18:47, Tobias Pape <[hidden email]> wrote:

>  I really don’t like to say it, but it seems to me, that a
> VM primitive (say #primAllObjectsDo:) would be apt here.
> • is more easy implemented by cousin VMs (say, Potato, SqueakJS,
>  SPy/RSqueakVM, SqueakMaxine†

How do you implement that efficiently in RPython, or Java?
Keeping some kind of object table around?

Best regards
Stefan

--
Stefan Marr
INRIA Lille - Nord Europe
http://stefan-marr.de/research/




Reply | Threaded
Open this post in threaded view
|

Re: I would not have thought I ever say that: lets have a new primitve (was: Re: [squeak-dev] The Trunk: System-cwp.660.mcz)

Tobias Pape

On 13.01.2014, at 21:56, Stefan Marr <[hidden email]> wrote:

> Hi Tobias:
>
> On 12 Jan 2014, at 18:47, Tobias Pape <[hidden email]> wrote:
>
>> I really don’t like to say it, but it seems to me, that a
>> VM primitive (say #primAllObjectsDo:) would be apt here.
>> • is more easy implemented by cousin VMs (say, Potato, SqueakJS,
>> SPy/RSqueakVM, SqueakMaxine†
>
> How do you implement that efficiently in RPython, or Java?
> Keeping some kind of object table around?
>
Well, I have no Idea currently, but i think some #primAllObjectsDo:
(or #primAllObjects, as it seems now) has IMHO less severe constraints
than the #someObject/#nextObject way.
 OT is one path. Manual heap scanning another. Collecting objects from
the roots (special objects array) a third. All these do not require
the #nextObject invariant.

Best
        -Tobias



signature.asc (1K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: I would not have thought I ever say that: lets have a new primitve (was: Re: [squeak-dev] The Trunk: System-cwp.660.mcz)

Stefan Marr-3
Hi Tobias:

On 14 Jan 2014, at 10:41, Tobias Pape <[hidden email]> wrote:

>> How do you implement that efficiently in RPython, or Java?
>> Keeping some kind of object table around?
>
> Well, I have no Idea currently, but i think some #primAllObjectsDo:
> (or #primAllObjects, as it seems now) has IMHO less severe constraints
> than the #someObject/#nextObject way.
> OT is one path. Manual heap scanning another. Collecting objects from
> the roots (special objects array) a third. All these do not require
> the #nextObject invariant.

I am just trying to think of how to implement that in the SOM VMs.
Without GC support for tracing/enumerating the objects, it’s not going to be pretty.

#someObject/#nextObject don’t make any sense for me in the long term. I want to support one form or another of parallel execution. So, if I want to offer #allObjects at all, it needs to be an atomic snapshot. Most likely with stop-the-world semantics, which is a severe burden on performance.

And without support of the underlying platform, I think, #allObjects can’t be complete. Just thinking of how TruffleSOM works, traversing only from specialObjectsArray on, will only find part of the live heap. There are way to many important references on the Java stack, that I can’t easily access. And making them accessible, is going to cost a lot of performance even when #allObjects is never used. I think. :-/
In case you find a nice solution for RSqueak, I would be very interested.

Best regards
Stefan


--
Stefan Marr
INRIA Lille - Nord Europe
http://stefan-marr.de/research/




Reply | Threaded
Open this post in threaded view
|

Re: I would not have thought I ever say that: lets have a new primitve (was: Re: [squeak-dev] The Trunk: System-cwp.660.mcz)

Bert Freudenberg
(moving to vm-dev)

On 14.01.2014, at 10:56, Stefan Marr <[hidden email]> wrote:

> Hi Tobias:
>
> On 14 Jan 2014, at 10:41, Tobias Pape <[hidden email]> wrote:
>
>>> How do you implement that efficiently in RPython, or Java?
>>> Keeping some kind of object table around?
>>
>> Well, I have no Idea currently, but i think some #primAllObjectsDo:
>> (or #primAllObjects, as it seems now) has IMHO less severe constraints
>> than the #someObject/#nextObject way.
>> OT is one path. Manual heap scanning another. Collecting objects from
>> the roots (special objects array) a third. All these do not require
>> the #nextObject invariant.
>
> I am just trying to think of how to implement that in the SOM VMs.
> Without GC support for tracing/enumerating the objects, it’s not going to be pretty.
>
> #someObject/#nextObject don’t make any sense for me in the long term.

Some VMs support those easily and they're more efficient, so I would not abandon them. But, as I wrote before, I'd make them optional, if a VM instead provides allObjects.

> I want to support one form or another of parallel execution. So, if I want to offer #allObjects at all, it needs to be an atomic snapshot. Most likely with stop-the-world semantics, which is a severe burden on performance.

Sure, but then allObjects shouldn't be used in production code anyway. Users need to be aware that it's going to be slow.

> And without support of the underlying platform, I think, #allObjects can’t be complete. Just thinking of how TruffleSOM works, traversing only from specialObjectsArray on, will only find part of the live heap.

You need to traverse from specialObjectsArray and activeContext. This will find all objects.

> There are way to many important references on the Java stack, that I can’t easily access. And making them accessible, is going to cost a lot of performance even when #allObjects is never used. I think. :-/

But if you support thisContext then you must have those mechanisms in place already.

> In case you find a nice solution for RSqueak, I would be very interested.

In SqueakJS I support nextObject for oldspace objects only (old space is a linked list). If you call nextObject on a new object, I do a full GC, which makes it old.

- Bert -



Reply | Threaded
Open this post in threaded view
|

Re: [Vm-dev] I would not have thought I ever say that: lets have a new primitve (was: Re: [squeak-dev] The Trunk: System-cwp.660.mcz)

Stefan Marr-3
Hi Bert:

On 14 Jan 2014, at 12:07, Bert Freudenberg <[hidden email]> wrote:

> (moving to vm-dev)
Thanks!

[careful, rather academic discussion ahead]

> On 14.01.2014, at 10:56, Stefan Marr <[hidden email]> wrote:
>
>> I am just trying to think of how to implement that in the SOM VMs.
>> Without GC support for tracing/enumerating the objects, it’s not going to be pretty.
>>
>> #someObject/#nextObject don’t make any sense for me in the long term.
>
> Some VMs support those easily and they're more efficient, so I would not abandon them. But, as I wrote before, I’d make them optional, if a VM instead provides allObjects.

Yes, right. But I was thinking out loud about SOM. So, I don’t have backward compatibility issues.
Depending on the personal point of view, one might even argue that SOM is not actually a Smalltalk, because it does not provide all the fancy things like thisContext, or #become:.

>> I want to support one form or another of parallel execution. So, if I want to offer #allObjects at all, it needs to be an atomic snapshot. Most likely with stop-the-world semantics, which is a severe burden on performance.
>
> Sure, but then allObjects shouldn't be used in production code anyway. Users need to be aware that it’s going to be slow.

Yes, I guess that’s the way to go.

> You need to traverse from specialObjectsArray and activeContext. This will find all objects.
> But if you support thisContext then you must have those mechanisms in place already.

Well, that’s the thing. I don’t support thisContext. thisContext is to my understanding really bound to one specific implementation technique. Thereby restricting significantly how a VM can implement the language.
I am also not yet sure whether I will provide some replacement for thisContext, but if so, it would need to be a much more specific interface that reifies information from the execution context explicitly on demand only. And since the various SOM implementations with classic approaches in C/C++, using RPython ala PyPy, and using Truffle on top of the JVM all differ significantly, it is for me a nice academic exercise to find an interface that just provides the desired functionality without restricting the implementation too much.

Best regards
Stefan

--
Stefan Marr
INRIA Lille - Nord Europe
http://stefan-marr.de/research/




Reply | Threaded
Open this post in threaded view
|

Re: I would not have thought I ever say that: lets have a new primitve (was: Re: [squeak-dev] The Trunk: System-cwp.660.mcz)

Eliot Miranda-2
In reply to this post by Tobias Pape
Hi Tobias,


On Tue, Jan 14, 2014 at 1:41 AM, Tobias Pape <[hidden email]> wrote:

On 13.01.2014, at 21:56, Stefan Marr <[hidden email]> wrote:

> Hi Tobias:
>
> On 12 Jan 2014, at 18:47, Tobias Pape <[hidden email]> wrote:
>
>> I really don’t like to say it, but it seems to me, that a
>> VM primitive (say #primAllObjectsDo:) would be apt here.
>> • is more easy implemented by cousin VMs (say, Potato, SqueakJS,
>> SPy/RSqueakVM, SqueakMaxine†
>
> How do you implement that efficiently in RPython, or Java?
> Keeping some kind of object table around?
>

Well, I have no Idea currently, but i think some #primAllObjectsDo:
(or #primAllObjects, as it seems now) has IMHO less severe constraints
than the #someObject/#nextObject way.

I've always thought that reentering the VI from a VM primitive, and hence being able to return to the VM primitive from arbitrary code executed in the block, would be problematic.  It's a lot of new machinery to add for one case.  Further, a GC could easily happen while executing the block.

Do you think it's easier than I'm thinking?  I know for example that the VisualAge VM does something somewhat analogous for its unwind-protects (ensure: ifCurtailed:).  But neither the Squeak nor the VisualWorks VMs have anything like this; primitives always run a single contiguous sequence of instructions before either returning to Smalltalk (e.g. basicNew) or resuming Smalltalk (e.g. perform:).
 
 OT is one path. Manual heap scanning another. Collecting objects from
the roots (special objects array) a third. All these do not require
the #nextObject invariant.

Best
        -Tobias
--
best,
Eliot


Reply | Threaded
Open this post in threaded view
|

Re: [Vm-dev] I would not have thought I ever say that: lets have a new primitve (was: Re: [squeak-dev] The Trunk: System-cwp.660.mcz)

Eliot Miranda-2
In reply to this post by Stefan Marr-3
Hi Stefan,


On Tue, Jan 14, 2014 at 4:37 AM, Stefan Marr <[hidden email]> wrote:
Hi Bert:

On 14 Jan 2014, at 12:07, Bert Freudenberg <[hidden email]> wrote:

> (moving to vm-dev)
Thanks!

[careful, rather academic discussion ahead]

> On 14.01.2014, at 10:56, Stefan Marr <[hidden email]> wrote:
>
>> I am just trying to think of how to implement that in the SOM VMs.
>> Without GC support for tracing/enumerating the objects, it’s not going to be pretty.
>>
>> #someObject/#nextObject don’t make any sense for me in the long term.
>
> Some VMs support those easily and they're more efficient, so I would not abandon them. But, as I wrote before, I’d make them optional, if a VM instead provides allObjects.

Yes, right. But I was thinking out loud about SOM. So, I don’t have backward compatibility issues.
Depending on the personal point of view, one might even argue that SOM is not actually a Smalltalk, because it does not provide all the fancy things like thisContext, or #become:.

>> I want to support one form or another of parallel execution. So, if I want to offer #allObjects at all, it needs to be an atomic snapshot. Most likely with stop-the-world semantics, which is a severe burden on performance.
>
> Sure, but then allObjects shouldn't be used in production code anyway. Users need to be aware that it’s going to be slow.

Yes, I guess that’s the way to go.

> You need to traverse from specialObjectsArray and activeContext. This will find all objects.
> But if you support thisContext then you must have those mechanisms in place already.

Well, that’s the thing. I don’t support thisContext. thisContext is to my understanding really bound to one specific implementation technique. Thereby restricting significantly how a VM can implement the language.
I am also not yet sure whether I will provide some replacement for thisContext, but if so, it would need to be a much more specific interface that reifies information from the execution context explicitly on demand only.

I don't see the difference.  In my VMs contexts are only created on demand.  The issue is what kind of object proxy to provide for execution context.  In VisualAge there is a proxy for a stack segment, essentially a pointer, and the VI must construct stack frames from this.  In Cog there is a context which contains a hidden pointer to a single stack frame.  Then there are facilities for manipulating the underlying stack through those interfaces.  In VisualAge I guess one can rewrite the stack arbitrarily.  In Cog, assignments to the sender, pc, stack pointer, etc are supported in the VM by manipulating the underlying stack appropriately.  In both cases a context-like object is adequate.  I also think that a context-like object is an appropriate proxy for a non-stack-like execution model such as continuation-passing.  So viewd from this level of abstraction I think it makes no difference, and hence you might as well provide thisCOntext.  You might disallow assigning to the sender in your implementation, but I don't see how thisContext per se severely constrains your implementation; it's just about where in the system (in the image or in the VM) the mapping from the activation proxy to the underlying execution context is done.

Does this make sense?

And since the various SOM implementations with classic approaches in C/C++, using RPython ala PyPy, and using Truffle on top of the JVM all differ significantly, it is for me a nice academic exercise to find an interface that just provides the desired functionality without restricting the implementation too much.

Best regards
Stefan

--
Stefan Marr
INRIA Lille - Nord Europe
http://stefan-marr.de/research/
--
best,
Eliot


12