On Sun, Jan 12, 2014 at 09:53:27PM +0100, Bert Freudenberg wrote:
On 12.01.2014, at 20:42, David T. Lewis lewis@mail.msen.com wrote:
It is worth noting that allObjectsDo: relies on assumptions about how the objects memory works internally. It requires that #someObject will always answer the object at the lowest address in the object memory, and also that a newly allocated object will always be placed at a higher address location than all other objects. Either of these assumptions is likely to be a problem as new and better object memories and garbage collectors are implemented.
Dave
Right (as Eliot's vm-dev post shows).
So IMHO the only sensible semantics of allObjectsDo: is as in "allObjects do:" - which might be implemented as a primitive in some VMs soonish. It *should not* enumerate objects created after calling the method.
On Sun, Jan 12, 2014 at 12:01:00PM -0800, Eliot Miranda wrote:
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.
Implementation attached. Works on interpreter VM, not yet tested on Cog but it should be ok there also. If no objections or better suggestions I will commit it to VMMaker tomorrow.
InterpreterPrimitives>>primitiveAllObjects "Answer an array of all objects that exist when the primitive is called, excluding those that may be garbage collected as a side effect of allocating the result array. Multiple references to nil in the last slots of the array are an indication that garbage collection occured, such that some of the unreferenced objects that existed at the time of calling the primitive no longer exist. Sender is responsible for handling multiple references to nil in the result array."
Dave
On 13.01.2014, at 02:13, David T. Lewis lewis@mail.msen.com wrote:
On Sun, Jan 12, 2014 at 12:01:00PM -0800, Eliot Miranda wrote:
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.
Implementation attached. Works on interpreter VM, not yet tested on Cog but it should be ok there also. If no objections or better suggestions I will commit it to VMMaker tomorrow.
InterpreterPrimitives>>primitiveAllObjects "Answer an array of all objects that exist when the primitive is called, excluding those that may be garbage collected as a side effect of allocating the result array. Multiple references to nil in the last slots of the array are an indication that garbage collection occured, such that some of the unreferenced objects that existed at the time of calling the primitive no longer exist. Sender is responsible for handling multiple references to nil in the result array."
Dave
<InterpreterPrimitives-primitiveAllObjects-dtl.1.cs>
Nice, except that I'd fill the remaining slots with 0 instead of nil. Even better: allocate the array as object count + 1 and *always* put a 0 last. That way the image code cannot ever "forget" to check for 0.
In the image I think the code should still prefer the someObject/nextObject interface, because allocating the large array is unnecessary in almost all cases. We could say a VM is allowed to fail the someObject/nextObject prims if it supports primitiveAllObjects, which otherwise is optional.
- Bert -
On Mon, Jan 13, 2014 at 12:28:33PM +0100, Bert Freudenberg wrote:
On 13.01.2014, at 02:13, David T. Lewis lewis@mail.msen.com wrote:
On Sun, Jan 12, 2014 at 12:01:00PM -0800, Eliot Miranda wrote:
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.
Implementation attached. Works on interpreter VM, not yet tested on Cog but it should be ok there also. If no objections or better suggestions I will commit it to VMMaker tomorrow.
InterpreterPrimitives>>primitiveAllObjects "Answer an array of all objects that exist when the primitive is called, excluding those that may be garbage collected as a side effect of allocating the result array. Multiple references to nil in the last slots of the array are an indication that garbage collection occured, such that some of the unreferenced objects that existed at the time of calling the primitive no longer exist. Sender is responsible for handling multiple references to nil in the result array."
Dave
<InterpreterPrimitives-primitiveAllObjects-dtl.1.cs>
Nice, except that I'd fill the remaining slots with 0 instead of nil. Even better: allocate the array as object count + 1 and *always* put a 0 last. That way the image code cannot ever "forget" to check for 0.
Someone would surely accuse me of being an unreformed C programmer ;-)
Another approach might be to provide an explicit object count in addition to the array of objects, so the primitive would answer an array with object count and with the all objects array.
Or we might force a GC in the primitive in order to prevent the condition from ever happening, at the cost of an unnecessary GC.
In the image I think the code should still prefer the someObject/nextObject interface, because allocating the large array is unnecessary in almost all cases. We could say a VM is allowed to fail the someObject/nextObject prims if it supports primitiveAllObjects, which otherwise is optional.
- Bert -
On 13.01.2014, at 13:16, David T. Lewis lewis@mail.msen.com wrote:
On Mon, Jan 13, 2014 at 12:28:33PM +0100, Bert Freudenberg wrote:
On 13.01.2014, at 02:13, David T. Lewis lewis@mail.msen.com wrote:
On Sun, Jan 12, 2014 at 12:01:00PM -0800, Eliot Miranda wrote:
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.
Implementation attached. Works on interpreter VM, not yet tested on Cog but it should be ok there also. If no objections or better suggestions I will commit it to VMMaker tomorrow.
InterpreterPrimitives>>primitiveAllObjects "Answer an array of all objects that exist when the primitive is called, excluding those that may be garbage collected as a side effect of allocating the result array. Multiple references to nil in the last slots of the array are an indication that garbage collection occured, such that some of the unreferenced objects that existed at the time of calling the primitive no longer exist. Sender is responsible for handling multiple references to nil in the result array."
Dave
<InterpreterPrimitives-primitiveAllObjects-dtl.1.cs>
Nice, except that I'd fill the remaining slots with 0 instead of nil. Even better: allocate the array as object count + 1 and *always* put a 0 last. That way the image code cannot ever "forget" to check for 0.
Someone would surely accuse me of being an unreformed C programmer ;-)
Nah, I don't think so. It just mimics the old behavior of answering 0 after the last object. Simplifies the image code (which would otherwise have to keep track whether it enumerated nil yet or not).
Another approach might be to provide an explicit object count in addition to the array of objects, so the primitive would answer an array with object count and with the all objects array.
That's even uglier ;^)
Or we might force a GC in the primitive in order to prevent the condition from ever happening, at the cost of an unnecessary GC.
Forcing a GC would remove the neat feature of being able to access
- Bert -
In the image I think the code should still prefer the someObject/nextObject interface, because allocating the large array is unnecessary in almost all cases. We could say a VM is allowed to fail the someObject/nextObject prims if it supports primitiveAllObjects, which otherwise is optional.
- Bert -
On Mon, Jan 13, 2014 at 12:28:33PM +0100, Bert Freudenberg wrote:
On 13.01.2014, at 02:13, David T. Lewis lewis@mail.msen.com wrote:
On Sun, Jan 12, 2014 at 12:01:00PM -0800, Eliot Miranda wrote:
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.
Implementation attached. Works on interpreter VM, not yet tested on Cog but it should be ok there also. If no objections or better suggestions I will commit it to VMMaker tomorrow.
InterpreterPrimitives>>primitiveAllObjects "Answer an array of all objects that exist when the primitive is called, excluding those that may be garbage collected as a side effect of allocating the result array. Multiple references to nil in the last slots of the array are an indication that garbage collection occured, such that some of the unreferenced objects that existed at the time of calling the primitive no longer exist. Sender is responsible for handling multiple references to nil in the result array."
Dave
<InterpreterPrimitives-primitiveAllObjects-dtl.1.cs>
Nice, except that I'd fill the remaining slots with 0 instead of nil. Even better: allocate the array as object count + 1 and *always* put a 0 last. That way the image code cannot ever "forget" to check for 0.
Attached is an implementation of Bert's proposal. There is at least one integer zero at the end of the result array, or more if the primitive caused a GC.
I sort of like this idea now that I understand the rational for using integer zero as the fill.
But Eliot is right, it would be better to answer only the objects that still exist after any possible GC.
Dave
On 14.01.2014, at 01:36, David T. Lewis lewis@mail.msen.com wrote:
On Mon, Jan 13, 2014 at 12:28:33PM +0100, Bert Freudenberg wrote:
I'd fill the remaining slots with 0 instead of nil. Even better: allocate the array as object count + 1 and *always* put a 0 last. That way the image code cannot ever "forget" to check for 0.
Attached is an implementation of Bert's proposal. There is at least one integer zero at the end of the result array, or more if the primitive caused a GC.
I sort of like this idea now that I understand the rational for using integer zero as the fill.
But Eliot is right, it would be better to answer only the objects that still exist after any possible GC.
Dave
<InterpreterPrimitives-primitiveAllObjects-dtl.2.cs>
Nice. Now we just need the same for allInstances :)
- Bert -
On Tue, Jan 14, 2014 at 02:27:11PM +0100, Bert Freudenberg wrote:
On 14.01.2014, at 01:36, David T. Lewis lewis@mail.msen.com wrote:
On Mon, Jan 13, 2014 at 12:28:33PM +0100, Bert Freudenberg wrote:
I'd fill the remaining slots with 0 instead of nil. Even better: allocate the array as object count + 1 and *always* put a 0 last. That way the image code cannot ever "forget" to check for 0.
Attached is an implementation of Bert's proposal. There is at least one integer zero at the end of the result array, or more if the primitive caused a GC.
I sort of like this idea now that I understand the rational for using integer zero as the fill.
But Eliot is right, it would be better to answer only the objects that still exist after any possible GC.
Dave
<InterpreterPrimitives-primitiveAllObjects-dtl.2.cs>
Nice. Now we just need the same for allInstances :)
- Bert -
One more update for primitiveAllObjects to fix a buglet. If garbage collection occurs during allocation of the result array, then the result array itself was being included in the result. We want to have self includes: self ==> false for the result array. This fixes it.
Truncating the array per Eliot's suggestion remains on the to-do list.
Dave
vm-dev@lists.squeakfoundation.org