Pharo-dev
By thread
pharo-dev@lists.pharo.org
By month
Messages by month
- ----- 2026 -----
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- 3 participants
- 144622 messages
Re: [Pharo-project] Classes that implement unsafe #=
by Frank Shearar
On 31 May 2012 04:37, Chris Muller <asqueaker(a)gmail.com> wrote:
> Another flexible option could be to test it respondsTo: each attribute
> being used for comparison.
This works quite well, and preserves "dynamic-ness": instead of
checking for class membership or set-of-class membership (#species),
you're saying "things that speak the same protocol/language might be
equal, but definitely not if they don't speak the same language".
That would permit non-transparent proxies to be #= to the things they
proxy, for instance. (I use non-transparent proxies quite a lot, for
instance as a means of providing an immutable pointer (Ref) to
something _apparently_ immutable, but which I can change willy nilly
without affecting anything pointing to the Ref.)
frank
> On Wed, May 30, 2012 at 8:32 AM, Henrik Sperre Johansen
> <henrik.s.johansen(a)veloxit.no> wrote:
>> On 30.05.2012 15:02, Mariano Martinez Peck wrote:
>>
>>
>>
>> On Wed, May 30, 2012 at 2:37 PM, Henrik Sperre Johansen
>> <henrik.s.johansen(a)veloxit.no> wrote:
>>>
>>> On 30.05.2012 14:05, Mariano Martinez Peck wrote:
>>>>
>>>> Hi guys. I found a problem while working with FuelPreview where we store
>>>> objects of the graph in a Set. While doing a collect, there was an error
>>>> because an implementation of #= was assuming that the argument was of a
>>>> certain shape. Of course, that should answer false instead. So I wrote this
>>>> test to see all existing wrong implementations:
>>>>
>>>> testAllClassesImplementSafeEqualsMethod
>>>> "This tests that all classes in the system that implements #= do it in a
>>>> way that they don't throw error when passing as an argument something
>>>> different from expected. The correct behavior is that #= answers false."
>>>> Â Â | wrongClasses |
>>>>   wrongClasses := IdentityDictionary  new.
>>>> Â Â ((SystemNavigation default allImplementorsOf: #=)
>>>> Â Â Â Â Â Â collect: [:each | each methodClass])
>>>> Â Â Â Â Â Â do: [:each |
>>>> Â Â Â Â Â Â Â Â | instance |
>>>> Â Â Â Â Â Â Â Â "Some classes like CompiledMethod override basicNew to
>>>> throw an error.
>>>> Â Â Â Â Â Â Â Â In any case, the comparison will be false, so no problem"
>>>> Â Â Â Â Â Â Â Â [instance := each basicNew] on: Error do: [].
>>>> Â Â Â Â Â Â Â Â [instance = Object new]
>>>> Â Â Â Â Â Â Â Â Â Â on: Error
>>>> Â Â Â Â Â Â Â Â Â Â do: [: err | wrongClasses at: each put: err ]].
>>>> Â Â self assert: wrongClasses isEmpty
>>>>
>>>>
>>>> The result is: {Magnitude. WideCharacterSet. KMKeymap. MCMockDefinition.
>>>> ScaledDecimal. MCSnapshot}
>>>>
>>>> So, my I think we should change #= in those classes by adding:
>>>>
>>>> Â Â self == aKeymap
>>>> Â Â Â Â ifTrue: [ ^ true ].
>>>> Â Â self class = aKeymap class
>>>> Â Â Â Â ifFalse: [ ^ false ].
>>>>
>>>> at the beginning of the #=
>>>>
>>>> what do you think? Â if agree, I open an issue.
>>>>
>>>>
>>>> --
>>>> Mariano
>>>> http://marianopeck.wordpress.com
>>>>
>>> I'd test against self species rather than self class, since it gives
>>> greater flexibility for user-defined instances to potentially = classes in
>>> the system.
>>>
>>> In other word, #class has a very strict meaning which would hinder
>>> extensibility, #species less so.
>>>
>>
>> Ok, I see. But the classes are only a few (five). So you recommend you use
>> self species instead of self class even if we "analyze" those 5 classes to
>> see if it is worth it or not (for example, we check if they do override
>> #species or not) ?
>>
>> Yes.
>> The default implementation of #species in Object uses the class primitive
>> directly, so there's no overhead.
>>
>> The benefit is that I could write a custom MyMagnitude class, override
>> species:
>> species
>> Â Â Â ^Magnitude
>>
>> and not have to override the base system Magnitude = implementation in order
>> to compare with MyMagnitude instances and have a true result.
>> In other words, using species in #= even if it's not needed, is setting a
>> good example.
>>
>>
>>
>> and btw...the automatic #hash and #= generator, shouldn't use #species
>> rather then #classes to?
>>
>> thanks
>>
>> Yes, I've never used those :)
>>
>> Cheers,
>> Henry
>
May 31, 2012
Re: [Pharo-project] Classes that implement unsafe #=
by Chris Muller
Good catch Mariano -- I have run your test on Squeak and fixed a
couple of instances there too.
On Wed, May 30, 2012 at 7:05 AM, Mariano Martinez Peck
<marianopeck(a)gmail.com> wrote:
> Hi guys. I found a problem while working with FuelPreview where we store
> objects of the graph in a Set. While doing a collect, there was an error
> because an implementation of #= was assuming that the argument was of a
> certain shape. Of course, that should answer false instead. So I wrote this
> test to see all existing wrong implementations:
>
> testAllClassesImplementSafeEqualsMethod
> "This tests that all classes in the system that implements #= do it in a way
> that they don't throw error when passing as an argument something different
> from expected. The correct behavior is that #= answers false."
> Â Â Â | wrongClasses |
>    wrongClasses := IdentityDictionary new.
> Â Â Â Â ((SystemNavigation default allImplementorsOf: #=)
> Â Â Â Â Â Â Â Â Â collect: [:each | each methodClass])
> Â Â Â Â Â Â Â Â Â do: [:each |
> Â Â Â Â Â Â Â Â Â Â Â Â | instance |
> Â Â Â Â Â Â Â Â Â Â Â Â "Some classes like CompiledMethod override basicNew to throw
> an error.
> Â Â Â Â Â Â Â Â Â Â Â Â In any case, the comparison will be false, so no problem"
> Â Â Â Â Â Â Â Â Â Â Â Â [instance := each basicNew] on: Error do: [].
> Â Â Â Â Â Â Â Â Â Â Â Â [instance = Object new]
> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â on: Error
> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â do: [: err | wrongClasses at: each put: err ]].
> Â Â Â self assert: wrongClasses isEmpty
>
>
> The result is: {Magnitude. WideCharacterSet. KMKeymap. MCMockDefinition.
> ScaledDecimal. MCSnapshot}
>
> So, my I think we should change #= in those classes by adding:
>
> Â Â Â self == aKeymap
> Â Â Â Â Â Â ifTrue: [ ^ true ].
> Â Â Â self class = aKeymap class
> Â Â Â Â Â Â ifFalse: [ ^ false ].
>
> at the beginning of the #=
>
> what do you think? if agree, I open an issue.
>
>
> --
> Mariano
> http://marianopeck.wordpress.com
>
May 31, 2012
Re: [Pharo-project] Classes that implement unsafe #=
by Chris Muller
Another flexible option could be to test it respondsTo: each attribute
being used for comparison.
On Wed, May 30, 2012 at 8:32 AM, Henrik Sperre Johansen
<henrik.s.johansen(a)veloxit.no> wrote:
> On 30.05.2012 15:02, Mariano Martinez Peck wrote:
>
>
>
> On Wed, May 30, 2012 at 2:37 PM, Henrik Sperre Johansen
> <henrik.s.johansen(a)veloxit.no> wrote:
>>
>> On 30.05.2012 14:05, Mariano Martinez Peck wrote:
>>>
>>> Hi guys. I found a problem while working with FuelPreview where we store
>>> objects of the graph in a Set. While doing a collect, there was an error
>>> because an implementation of #= was assuming that the argument was of a
>>> certain shape. Of course, that should answer false instead. So I wrote this
>>> test to see all existing wrong implementations:
>>>
>>> testAllClassesImplementSafeEqualsMethod
>>> "This tests that all classes in the system that implements #= do it in a
>>> way that they don't throw error when passing as an argument something
>>> different from expected. The correct behavior is that #= answers false."
>>> Â Â | wrongClasses |
>>>   wrongClasses := IdentityDictionary  new.
>>> Â Â ((SystemNavigation default allImplementorsOf: #=)
>>> Â Â Â Â Â Â collect: [:each | each methodClass])
>>> Â Â Â Â Â Â do: [:each |
>>> Â Â Â Â Â Â Â Â | instance |
>>> Â Â Â Â Â Â Â Â "Some classes like CompiledMethod override basicNew to
>>> throw an error.
>>> Â Â Â Â Â Â Â Â In any case, the comparison will be false, so no problem"
>>> Â Â Â Â Â Â Â Â [instance := each basicNew] on: Error do: [].
>>> Â Â Â Â Â Â Â Â [instance = Object new]
>>> Â Â Â Â Â Â Â Â Â Â on: Error
>>> Â Â Â Â Â Â Â Â Â Â do: [: err | wrongClasses at: each put: err ]].
>>> Â Â self assert: wrongClasses isEmpty
>>>
>>>
>>> The result is: {Magnitude. WideCharacterSet. KMKeymap. MCMockDefinition.
>>> ScaledDecimal. MCSnapshot}
>>>
>>> So, my I think we should change #= in those classes by adding:
>>>
>>> Â Â self == aKeymap
>>> Â Â Â Â ifTrue: [ ^ true ].
>>> Â Â self class = aKeymap class
>>> Â Â Â Â ifFalse: [ ^ false ].
>>>
>>> at the beginning of the #=
>>>
>>> what do you think? Â if agree, I open an issue.
>>>
>>>
>>> --
>>> Mariano
>>> http://marianopeck.wordpress.com
>>>
>> I'd test against self species rather than self class, since it gives
>> greater flexibility for user-defined instances to potentially = classes in
>> the system.
>>
>> In other word, #class has a very strict meaning which would hinder
>> extensibility, #species less so.
>>
>
> Ok, I see. But the classes are only a few (five). So you recommend you use
> self species instead of self class even if we "analyze" those 5 classes to
> see if it is worth it or not (for example, we check if they do override
> #species or not) ?
>
> Yes.
> The default implementation of #species in Object uses the class primitive
> directly, so there's no overhead.
>
> The benefit is that I could write a custom MyMagnitude class, override
> species:
> species
> Â Â Â ^Magnitude
>
> and not have to override the base system Magnitude = implementation in order
> to compare with MyMagnitude instances and have a true result.
> In other words, using species in #= even if it's not needed, is setting a
> good example.
>
>
>
> and btw...the automatic #hash and #= generator, shouldn't use #species
> rather then #classes to?
>
> thanks
>
> Yes, I've never used those :)
>
> Cheers,
> Henry
May 31, 2012
Re: [Pharo-project] [ANN] NativeBoost 1.2 version released (#development)
by Igor Stasenko
Update:
i synchronized Athens Cairo backend with latest changes in NativeBoost.
ConfigurationOfAthens version 1.2
is now working with NB v 1.2
(same version numbers are just coincidence)
--
Best regards,
Igor Stasenko.
May 31, 2012
Re: [Pharo-project] omni browser
by Guillermo Polito
On Wed, May 30, 2012 at 11:58 PM, Milan Mimica <milan.mimica(a)gmail.com>wrote:
> On 30 May 2012 23:07, Bernardo Ezequiel Contreras <vonbecmann(a)gmail.com>wrote:
>
>> try this:
>>
>> #. MetacelloConfigurationBrowser open.
>> #. select ConfigurationOfOmniBrowser-*
>> #. right click on "load configuration and stable version"
>>
>
> I get an OmniBrowser without syntax highlight and without
> code completion working.
>
Thats because it loads the default group.
Try with this script after loading the configuration from
MetacelloRepository:
Gofer it
squeaksource: 'MetacelloRepository';
package: 'ConfigurationOfOmniBrowser';
load.
(ConfigurationOfOmniBrowser
project version: #stable) load: #( 'Dev' 'Dev Tests').
cheers,
Guille
>
> more info,
>>
>> http://stackoverflow.com/questions/10518095/install-script-for-omnibrowser-…
>>
>>
> "OmniBrowser is unlikely to ever be supported in Pharo 1.4"
>
> Kind a sums it up. Hello Nautilus!
>
>
> --
> Milan Mimica
> http://sparklet.sf.net
>
May 30, 2012
Re: [Pharo-project] omni browser
by Milan Mimica
On 30 May 2012 23:07, Bernardo Ezequiel Contreras <vonbecmann(a)gmail.com>wrote:
> try this:
>
> #. MetacelloConfigurationBrowser open.
> #. select ConfigurationOfOmniBrowser-*
> #. right click on "load configuration and stable version"
>
I get an OmniBrowser without syntax highlight and without
code completion working.
more info,
>
> http://stackoverflow.com/questions/10518095/install-script-for-omnibrowser-…
>
>
"OmniBrowser is unlikely to ever be supported in Pharo 1.4"
Kind a sums it up. Hello Nautilus!
--
Milan Mimica
http://sparklet.sf.net
May 30, 2012
Re: [Pharo-project] [Vm-dev] Re: Plan/discussion/communication around new object format
by Igor Stasenko
Here are couple (2) of mine, highly valuable cents :)
2^20 for classes?
might be fine (or even overkill) for smalltalk systems, but could be
quite limiting for one who would like experiment and implementing a
prototype-based frameworks,
where every object is a "class" by itself.
---
8: slot size (255 => extra header word with large size)
3: odd bytes/fixed fields (odd bytes for non-pointer, fixed fields for
pointer, 7 => # fixed fields is in the class)
4 bits: format (pointers, indexable, bytes/shorts/longs/doubles
indexable, compiled method, ephemerons, weak, etc)
1: immutability
3: GC 2 mark bits. 1 forwarded bit
20: identity hash
20: class index
---
what takes most of the space in object header? right - hash!
Now, since we will have lazy become i am back to my idea of having
extra & arbitrary properties
per object.
In a nutshell, the idea is to not store hash in an object header, but
instead use just a single bit 'hash present'.
When identity hash of object is requested (via corresponding primitive)
the implementation could check if 'hash present' is set,
then if it's not there , we do a 'lazy become' of existing object to same object
copied into another place, but with hash bit set, and with extra 64-bit field,
where hash value can be stored.
So, when you requesting an identity hash for object which don't have it,
the object of from:
[header][...data.. ]
copied to new memory region with new layout:
[header][hash bits][...data..]
and old object, is of course 'corpsed' to forwarding pointer to new location.
Next step is going from holding just hash to having an arbitrary &
dynamic number of extra fields per object.
In same way, we use 1 extra bit, indicating that object having extra properties.
And when object don't have it, we lazy-become it from being
[header][...data.. ]
or
[header][hash bits][...data..]
to:
[header][hash bits][oop][...data..]
where 'oop' can be anything - instance of Array/Dictionary (depends
how language-side will decide to store extra properties of object)
This , for instance , would allow us to store extra properties for
special object formats like variable bytes or compiled methods, which
don't have the instance variables.
Not need to mention, how useful being able to attach extra properties
per object, without changing the object's class.
And , of course the freed 18 bits (20 - 2) in header can be allocated
for other purposes.
(Stef, how many bits you need for experiments? ;)
------------
About immediates zoo.
Keep in mind, that the more immediates we have, the more complex implementation
tends to be.
I would just keep 2 data types:
- integers
- floats
and third, special 'arbitrary' immediate , which seen by VM as a 60-bit value.
The interpretation of this value depends on lookup in range-table,
where developer specifying the correspondence between the value
interval and class:
[min .. max] -> class
intervals, of course, cannot overlap.
Determining a class of such immediate might be slower - O(log2(n)) at
best (where n is size of range table), but from other side,
how many different kinds of immediates you can fit into 60-bit value?
Right, it is 2^60. Much more than proposed 8 isn't? :)
And this extra cost can be mitigated completely by inline cache.
- in case of regular reference, you must fetch the object's class and
then compare it with one, stored in cache.
- in case of immediate reference, you compare immediate value with min
and max stored in cache fields.
And if value is in range, you got a cache hit, and free to proceed.
So, its just 1 extra comparison comparing to 'classic' inline cache.
And, after thinking how inline cache is organized, now you can scratch
the first my paragraph related to immediates!
We really don't need to discriminate between small integers/floats/rest!!
They could also be nothing more than just one of a range(s) defined in
our zoo of 'special' immediates!
So, at the end we will have just two kinds of references:
- zero bit == 0 -- an object pointer
- zero bit == 1 -- an immediate
Voila!.
We can have real zoo of immediates, and simple implementation to support them.
And not saying that range-table is provided by language-side, so we're
free to rearrange them at any moment.
And of course, it doesn't means that VM could not reserve some of the
ranges for own 'contracted'
immediates, like Characters, and even class reference for example.
Think about it :)
May 30, 2012
Re: [Pharo-project] [Vm-dev] Re: Plan/discussion/communication around new object format
by Eliot Miranda
On Wed, May 30, 2012 at 1:53 PM, Mariano Martinez Peck <
marianopeck(a)gmail.com> wrote:
>
>
>
> On Wed, May 30, 2012 at 10:22 PM, Eliot Miranda <eliot.miranda(a)gmail.com>wrote:
>
>>
>>
>>
>> On Wed, May 30, 2012 at 12:59 PM, Stéphane Ducasse <
>> stephane.ducasse(a)inria.fr> wrote:
>>
>>> I would like to be sure that we can have
>>> - bit for immutable objects
>>> - bits for experimenting.
>>>
>>
>> There will be quite a few. And one will be able to steal bits from the
>> class field if one needs fewer classes. I'm not absolutely sure of the
>> layout yet. But for example
>>
>> 8: slot size (255 => extra header word with large size)
>> 3: odd bytes/fixed fields (odd bytes for non-pointer, fixed fields for
>> pointer, 7 => # fixed fields is in the class)
>> 4 bits: format (pointers, indexable, bytes/shorts/longs/doubles
>> indexable, compiled method, ephemerons, weak, etc)
>> 1: immutability
>> 3: GC 2 mark bits. 1 forwarded bit
>> 20: identity hash
>>
>
> and we can make it lazy, that is, we compute it not at instantiation time
> but rather the first time the primitive is call.
>
>
>
>> 20: class index
>>
>
> This would probably work for a while. I think that it would be good to let
> an "open door" so that in the future we can just add one more word for a
> class pointer.
>
Turns out that's not such a simple change. Class indices have two
advantages. One is that they're more compact (2^20 classes is still a lot
of classes). The other is that they're constant, which has two main
benefits. First, in method caches and in-line caches the class field holds
an index and hence doesn't need to be updated by the GC. The GC no longer
has top visit send sites. Second, because they're constants both checking
for well-known classes and instantiating well-known classes can be done
without going to the specialObjectsArray. One just uses the constant. Now
undoing these optimizations to open a back-dorr is not trivial. So best
accept the benefits and exploit them to a maximum.
>
>>
>> still leaves 5 bits unused. And stealing 4 bits each from class index
>> still leaves 64k classes. So this format is simple and provides lots of
>> unused bits. The format field is a great idea as it combines a number of
>> orthogonal properties in very few bits. I don't want to include odd bytes
>> in format because I think a separate field that holds odd bytes and fixed
>> fields is better use of space. But we can gather statistics before
>> deciding.
>>
>>
>>> Stef
>>>
>>> On May 30, 2012, at 8:48 AM, Stéphane Ducasse wrote:
>>>
>>> > Hi guys
>>> >
>>> > Here is an important topic I would like to see discussed so that we
>>> see how we can improve and join forces.
>>> > May a mail discussion then a wiki for the summary would be good.
>>> >
>>> >
>>> > stef
>>> >
>>> >
>>> >
>>> > Begin forwarded message:
>>> >
>>> >> From: Eliot Miranda <eliot.miranda(a)gmail.com>
>>> >> Subject: Re: Plan/discussion/communication around new object format
>>> >> Date: May 27, 2012 10:49:54 PM GMT+02:00
>>> >> To: Stéphane Ducasse <stephane.ducasse(a)inria.fr>
>>> >>
>>> >>
>>> >>
>>> >> On Sat, May 26, 2012 at 1:46 AM, Stéphane Ducasse <
>>> stephane.ducasse(a)inria.fr> wrote:
>>> >> Hi eliot
>>> >>
>>> >> do you have a description of the new object format you want to
>>> introduce?
>>> >>
>>> >> The design is in the class comment of CogMemoryManager in the Cog
>>> VMMaker packages.
>>> >>
>>> >> Then what is your schedule?
>>> >>
>>> >> This is difficult. I have made a small start and should be able to
>>> spend time on it starting soon. I want to have it finished by early next
>>> year. But it depends on work schedules etc.
>>> >>
>>> >>
>>> >> I would like to see if we can allocate igor/esteban time before we
>>> run out of money
>>> >> to help on that important topic.
>>> >> Now the solution is unclear and I did not see any document where we
>>> can evaluate
>>> >> and plan how we can help. So do you want help on that topic? Then how
>>> can people
>>> >> contribute if any?
>>> >>
>>> >> The first thing to do is to read the design document, to see if the
>>> Pharo community thinks it is the right direction, and to review it, spot
>>> deficiencies etc. So please get those interested to read the class comment
>>> of CogMemoryManager in the latest VMMaker.oscog.
>>> >>
>>> >> Here's the current version of it:
>>> >>
>>> >> CogMemoryManager is currently a place-holder for the design of the
>>> new Cog VM's object representation and garbage collector. The goals for
>>> the GC are
>>> >>
>>> >> - efficient object representation a la Eliot Miranda's VisualWorks
>>> 64-bit object representation that uses a 64-bit header, eliminating direct
>>> class references so that all objects refer to their classes indirectly.
>>> Instead the header contains a constant class index, in a field smaller
>>> than a full pointer, These class indices are used in inline and first-level
>>> method caches, hence they do not have to be updated on GC (although they do
>>> have to be traced to be able to GC classes). Classes are held in a sparse
>>> weak table. The class table needs only to be indexed by an instance's
>>> class index in class hierarchy search, in the class primitive, and in
>>> tracing live objects in the heap. The additional header space is allocated
>>> to a much expanded identity hash field, reducing hash efficiency problems
>>> in identity collections due to the extremely small (11 bit) hash field in
>>> the old Squeak GC. The identity hash field is also a key element of the
>>> class index scheme. A class's identity hash is its index into the class
>>> table, so to create an instance of a class one merely copies its identity
>>> hash into the class index field of the new instance. This implies that
>>> when classes gain their identity hash they are entered into the class table
>>> and their identity hash is that of a previously unused index in the table.
>>> It also implies that there is a maximum number of classes in the table.
>>> At least for a few years 64k classes should be enough. A class is entered
>>> into the class table in the following operations:
>>> >> behaviorHash
>>> >> adoptInstance
>>> >> instantiate
>>> >> become (i.e. if an old class becomes a new class)
>>> >> if target class field's = to original's id hash
>>> >> and replacement's id hash is zero
>>> >> enter replacement in class table
>>> >> behaviorHash is a special version of identityHash that must be
>>> implemented in the image by any object that can function as a class (i.e.
>>> Behavior).
>>> >>
>>> >> - more immediate classes. An immediate Character class would speed
>>> up String accessing, especially for WideString, since no instatiation needs
>>> to be done on at:put: and no dereference need be done on at:. In a 32-bit
>>> system tag checking is complex since it is thought important to retain
>>> 31-bit SmallIntegers. Hence, as in current Squeak, the least significant
>>> bit set implies a SmallInteger, but Characters would likely have a tag
>>> pattern of xxx10. Hence masking with 11 results in two values for
>>> SmallInteger, xxx01 and xxx11. 30-bit characters are more than adequate
>>> for Unicode. In a 64-bit system we can use the full three bits and
>>> usefully implement an immediate Float. As in VisualWorks a functional
>>> representation takes three bits away from the exponent. Rotating to put
>>> the sign bit in the least significant non-tag bit makes expanding and
>>> contracting the 8-bit exponent to the 11-bit IEEE double exponent easy ad
>>> makes comparing negative and positive zero easier (an immediate Float is
>>> zero if its unsigned 64-bits are < 16). So the representation looks like
>>> >> | 8 bit exponent | 52 bit mantissa | sign bit | 3 tag bits |
>>> >> For details see "60-bit immediate Floats" below.
>>> >>
>>> >>
>>> >> - efficient scavenging. The current Squeak GC uses a slow
>>> pointer-reversal collector that writes every field in live objects three
>>> times in each collection, twice in the pointer-reversing heap traversal to
>>> mark live objects and once to update the pointer to its new location. A
>>> scavenger writes every field of live data twice in each collection, once as
>>> it does a block copy of the object when copying to to space, once as it
>>> traverses the live pointers in the to space objects. Of course the block
>>> copy is a relatively cheap write.
>>> >>
>>> >> - lazy become. The JIT's use of inline cacheing provides a cheap way
>>> of avoiding scanning the heap as part of a become (which is the simple
>>> approach to implementing become in a system with direct pointers). A
>>> becomeForward: on a (set of) non-zero-sized object(s) turns the object into
>>> a "corpse" or "forwarding object" whose first (non-header) word/slot is
>>> replaced by a pointer to the target of the becomeForward:. The corpse's
>>> class index is set to one that identifies corpses and, because it is a
>>> hidden class index, will always fail an inline cache test. The inline
>>> cache failure code is then responsible for following the forwarding pointer
>>> chain (these are Iliffe vectors :) ) and resolving to the actual target.
>>> We have yet to determine exactly how this is done (e.g. change the
>>> receiver register and/or stack contents and retry the send, perhaps
>>> scanning the current activation). See below on how we deal with becomes on
>>> objects with named inst vars. Note that we probably don't have to worry
>>> about zero-sized objects. These are unlikely to be passed through the FFI
>>> (there is nothing to pass :) ) and so will rarely be becommed. If they do,
>>> they can become slowly. Alternatively we can insist that objects are at
>>> least 16 bytes in size (see a8-byte alignment below) so that there will
>>> always be space for a forwarding pointer. Since none of the immediate
>>> classes can have non-immediate instances and since we allocate the
>>> immediate classes indices corresponding to their tag pattern (SmallInteger
>>> = 1, Character = 3, SmallFloat = 4?) we can use all the class indices from
>>> 0 to 7 for special uses, 0 = forward, and e.g. 1 = header-sized filler.
>>> >>
>>> >> - pinning. To support a robust and easy-to-use FFI the memory
>>> manager must support temporary pinning where individual objects can be
>>> prevented from being moved by the GC for as long as required, either by
>>> being one of an in-progress FFI call's arguments, or by having pinning
>>> asserted by a primitive (allowing objects to be passed to external code
>>> that retains a reference to the object after returning). Pinning probably
>>> implies a per-object "is-pinned" bit in the object header. Pinning will be
>>> done via lazy become; i..e an object in new space will be becommed into a
>>> pinned object in old space. We will only support pinning in old space.
>>> >>
>>> >> - efficient old space collection. An incremental collector (a la
>>> Dijkstra's three colour algorithm) collects old space, e.g. via an amount
>>> of tracing being hung off scavenges and/or old space allocations at an
>>> adaptive rate that keeps full garbage collections to a minimum. (see free
>>> space/free list below)
>>> >>
>>> >> - 8-byte alignment. It is advantageous for the FFI, for
>>> floating-point access, for object movement and for 32/64-bit
>>> compatibility to keep object sizes in units of 8 bytes. For the FFI,
>>> 8-byte alignment means passing objects to code that expects that
>>> requirement (such as modern x86 numeric processing instructions). This
>>> implies that
>>> >> - the starts of all spaces are aligned on 8-byte boundaries
>>> >> - object allocation rounds up the requested size to a multiple
>>> of 8 bytes
>>> >> - the overflow size field is also 8 bytes
>>> >> We shall probably keep the minimum object size at 16 bytes so that
>>> there is always room for a forwarding pointer. But this implies that we
>>> will need to implement an 8-byte filler to fill holes between objects > 16
>>> bytes whose length mod 16 bytes is 8 bytes and following pinned objects.
>>> We can do this using a special class index, e.g. 1, so that the method
>>> that answers the size of an object looks like, e.g.
>>> >> chunkSizeOf: oop
>>> >> <var: #oop type: #'object *'>
>>> >> ^object classIndex = 1
>>> >> ifTrue: [BaseHeaderSize]
>>> >> ifFalse: [BaseHeaderSize
>>> >> + (object slotSize = OverflowSlotSize
>>> >> ifTrue:
>>> [OverflowSizeBytes]
>>> >> ifFalse: [0])
>>> >> + (object slotSize * BytesPerSlot)]
>>> >>
>>> >> chunkStartOf: oop
>>> >> <var: #oop type: #'object *'>
>>> >> ^(self cCoerceSimple: oop to: #'char *')
>>> >> - ((object classIndex = 1
>>> >> or: [object slotSize ~= OverflowSlotSize])
>>> >> ifTrue: [0]
>>> >> ifFalse: [OverflowSizeBytes])
>>> >>
>>> >> For the moment we do not tackle the issue of heap growth and
>>> shrinkage with the ability to allocate and deallocate heap segments via
>>> memory-mapping. This technique allows space to be released back to the OS
>>> by unmapping empty segments. We may revisit this but it is not a key
>>> requirement for the first implementation.
>>> >>
>>> >> The basic approach is to use a fixed size new space and a growable
>>> old space. The new space is a classic three-space nursery a la Ungar's
>>> Generation Scavenging, a large eden for new objects and two smaller
>>> survivor spaces that exchange roles on each collection, one being the to
>>> space to which surviving objects are copied, the other being the from space
>>> of the survivors of the previous collection, i.e. the previous to space.
>>> >>
>>> >> To provide apparent pinning in new space we rely on lazy become.
>>> Since most pinned objects will be byte data and these do not require stack
>>> zone activation scanning, the overhead is simply an old space allocation
>>> and corpsing.
>>> >>
>>> >> To provide pinning in old space, large objects are implicitly pinned
>>> (because it is expensive to move large objects and, because they are both
>>> large and relatively rare, they contribute little to overall fragmentation
>>> - as in aggregates, small objects can be used to fill-in the spaces between
>>> karge objects). Hence, objects above a particular size are automatically
>>> allocated in old space, rather than new space. Small objects are pinned as
>>> per objects in new space, by asserting the pin bit, which will be set
>>> automaticaly when allocating a large object. As a last resort, or by
>>> programmer control (the fullGC primitive) old space is collected via
>>> mark-sweep (mark-compact) and so the mark phase must build the list of
>>> pinned objects around which the sweep/compact phase must carefully step.
>>> >>
>>> >> Free space in old space is organized by a free list/free tree as in
>>> Eliot's VisualWorks 5i old space allocator. There are 64 free lists,
>>> indices 1 through 63 holding blocks of space of that size, index 0 holding
>>> a semi-balanced ordered tree of free blocks, each node being the head of
>>> the list of free blocks of that size. At the start of the mark phase the
>>> free list is thrown away and the sweep phase coallesces free space and
>>> steps over pinned objects as it proceeds. We can reuse the forwarding
>>> pointer compaction scheme used in the old collector. Incremental
>>> collections merely move unmarked objects to the free lists (as well as
>>> nilling weak pointers in weak arrays and scheduling them for finalization).
>>> The occupancy of the free lists is represented by a bitmap in a 64-bit
>>> integer so that an allocation of size 63 or less can know whether there
>>> exists a free chunk of that size, but more importantly can know whether a
>>> free chunk larger than it exists in the fixed size free lists without
>>> having to search all larger free list heads.
>>> >>
>>> >> The incremental collector (a la Dijkstra's three colour algorithm)
>>> collects old space via an amount of tracing being hung off scavenges and/or
>>> old space allocations at an adaptive rate that keeps full garbage
>>> collections to a minimum. [N.B. Not sure how to do this yet. The
>>> incremental collector needs to complete a pass often enough to reclaim
>>> objects, but infrequent enough not to waste time. So some form of feedback
>>> should work. In VisualWorks tracing is broken into quanta or work where
>>> image-level code determines the size of a quantum based on how fast the
>>> machine is, and how big the heap is. This code could easily live in the
>>> VM, controllable through vmParameterAt:put:. An alternative would be to
>>> use the heartbeat to bound quanta by time. But in any case some amount of
>>> incremental collection would be done on old space allocation and
>>> scavenging, the ammount being chosen to keep pause times acceptably short,
>>> and at a rate to reclaim old space before a full GC is required, i.e. at a
>>> rate proportional to the growth in old space]. The incemental collector is
>>> a state machine, being either marking, nilling weak pointers, or freeing.
>>> If nilling weak pointers is not done atomically then there must be a read
>>> barrier in weak array at: so that reading from an old space weak array that
>>> is holding stale un-nilled references to unmarked objects. Tricks such as
>>> including the weak bit in bounds calculations can make this cheap for
>>> non-weak arrays. Alternatively nilling weak pointers can be made an atomic
>>> part of incremental collection, which can be made cheaper by maintaining
>>> the set of weak arrays (e.g. on a list).
>>> >>
>>> >> The incremental collector implies a more complex write barrier.
>>> Objects are of three colours, black, having been scanned, grey, being
>>> scanned, and white, unreached. A mark stack holds the grey objects. If
>>> the incremental collector is marking and an unmarked white object is stored
>>> into a black object then the stored object must become grey, being added to
>>> the mark stack. So the wrte barrier is essentially
>>> >> target isYoung ifFalse:
>>> >> [newValue isYoung
>>> >> ifTrue: [target isInRememberedSet ifFalse:
>>> >> [target addToRememberedSet]]
>>> "target now refers to a young object; it is a root for scavenges"
>>> >> ifFalse:
>>> >> [(target isBlack
>>> >> and: [igc marking
>>> >> and: [newValue isWhite]]) ifTrue:
>>> >> [newValue beGrey]]] "add
>>> newValue to IGC's markStack for subsequent scanning"
>>> >>
>>> >> The incremental collector does not detect already marked objects all
>>> of whose references have been overwritten by other stores (e.g. in the
>>> above if newValue overwrites the sole remaining reference to a marked
>>> object). So the incremental collector only guarantees to collect all
>>> garbage created in cycle N at the end of cycle N + 1. The cost is hence
>>> slightly worse memory density but the benefit, provided the IGC works hard
>>> enough, is the elimination of long pauses due to full garbage collections,
>>> which become actions of last resort or programmer desire.
>>> >>
>>> >> Lazy become.
>>> >>
>>> >> As described earlier the basic idea behind lazy become is to use
>>> corpses (forwarding objects) that are followed lazily during GC and inline
>>> cache miss. However, a lazy scheme cannot be used on objects with named
>>> inst vars without adding checking to all inst var accesses, which we judge
>>> too expensive. Instead, when becomming objects with named inst vars, we
>>> scan all activations in the stack zone, eagerly becomming these references,
>>> and we check for corpses when faulting in a context into the stack zone.
>>> Essentially, the invariant is that there are no references to corpses from
>>> the receiver slots of stack activations. A detail is whether we allow or
>>> forbid pinning of closure indirection vectors, or scan the entire stack of
>>> each activation. Using a special class index pun for indirection vectors
>>> is a cheap way of preventing their becomming/pinning etc. Although "don't
>>> do that" (don't attempt to pin/become indirection vectors) is also an
>>> acceptable response.
>>> >>
>>> >> 60-bit immediate Floats
>>> >> Representation for immediate doubles, only used in the 64-bit
>>> implementation. Immediate doubles have the same 52 bit mantissa as IEEE
>>> double-precision floating-point, but only have 8 bits of exponent. So
>>> they occupy just less than the middle 1/8th of the double range. They
>>> overlap the normal single-precision floats which also have 8 bit exponents,
>>> but exclude the single-precision denormals (exponent-127) and the
>>> single-precsion NaNs (exponent +127). +/- zero is just a pair of values
>>> with both exponent and mantissa 0.
>>> >> So the non-zero immediate doubles range from
>>> >> +/- 0x3800,0000,0000,0001 / 5.8774717541114d-39
>>> >> to +/- 0x47ff,ffff,ffff,ffff / 6.8056473384188d+38
>>> >> The encoded tagged form has the sign bit moved to the least
>>> significant bit, which allows for faster encode/decode because offsetting
>>> the exponent can't overflow into the sign bit and because testing for +/- 0
>>> is an unsigned compare for <= 0xf:
>>> >> msb
>>> lsb
>>> >> [8 exponent subset bits][52 mantissa bits ][1 sign bit][3 tag
>>> bits]
>>> >> So assuming the tag is 5, the tagged non-zero bit patterns are
>>> >> 0x0000,0000,0000,001[d/5]
>>> >> to 0xffff,ffff,ffff,fff[d/5]
>>> >> and +/- 0d is 0x0000,0000,0000,000[d/5]
>>> >> Encode/decode of non-zero values in machine code looks like:
>>> >> msb
>>> lsb
>>> >> Decode:
>>> [8expsubset][52mantissa][1s][3tags]
>>> >> shift away tags: [ 000
>>> ][8expsubset][52mantissa][1s]
>>> >> add exponent offset: [ 11 exponent ][52mantissa][1s]
>>> >> rot sign: [1s][ 11 exponent
>>> ][52mantissa]
>>> >>
>>> >> Encode: [1s][ 11 exponent
>>> ][52mantissa]
>>> >> rot sign: [ 11 exponent
>>> ][52mantissa][1s]
>>> >> sub exponent offset: [ 000 ][8expsubset][52 mantissa][1s]
>>> >> shift: [8expsubset][52
>>> mantissa][1s][ 000 ]
>>> >> or/add tags: [8expsubset][52mantissa][1s][3tags]
>>> >> but is slower in C because
>>> >> a) there is no rotate, and
>>> >> b) raw conversion between double and quadword must (at least in the
>>> source) move bits through memory ( quadword = *(q64 *)&doubleVariable).
>>> >>
>>> >> Issues:
>>> >> How do we avoid the Size4Bit for 64-bits? The format word encodes
>>> the number of odd bytes, but currently has only 4 bits and hence only
>>> supports odd bytes of 0 - 3. We need odd bytes of 0 - 7. But I don't like
>>> the separate Size4Bit. Best to change the VI code and have a 5 bit format?
>>> We loose one bit but save two bits (isEphemeron and isWeak (or three, if
>>> isPointers)) for a net gain of one (or two)
>>> >>
>>> >> Further, keep Squeak's format idea or go for separate bits? For
>>> 64-bits we need a 5 bit format field. This contrasts with isPointers,
>>> isWeak, isEphemeron, 3 odd size bits (or byte size).. format field is
>>> quite economical.
>>> >>
>>> >> Are class indices in inline caches strong references to classes or
>>> weak references?
>>> >> If strong then they must be scanned during GC and the methodZone must
>>> be flushed on fullGC to reclaim all classes (this looks to be a bug in the
>>> V3 Cogit).
>>> >> If weak then when the class table loses references, PICs containing
>>> freed classes must be freed and then sends to freed PICs or containing
>>> freed clases must be unlinked.
>>> >> The second approach is faster; the common case is scanning the class
>>> table, the uncommon case is freeing classes. The second approach is
>>> better; in-line caches do not prevent reclamation of classes.
>>> >>
>>> >>
>>> >> Stef
>>> >>
>>> >>
>>> >>
>>> >> --
>>> >> best,
>>> >> Eliot
>>> >>
>>> >
>>>
>>>
>>>
>>
>>
>> --
>> best,
>> Eliot
>>
>>
>>
>
>
> --
> Mariano
> http://marianopeck.wordpress.com
>
>
>
--
best,
Eliot
May 30, 2012
Re: [Pharo-project] omni browser
by Bernardo Ezequiel Contreras
on pharo 1.3, I'm using
http://jenkins.lukas-renggli.ch/job/Development/lastSuccessfulBuild/artifac…
On Wed, May 30, 2012 at 6:07 PM, Bernardo Ezequiel Contreras <
vonbecmann(a)gmail.com> wrote:
> try this:
>
> #. MetacelloConfigurationBrowser open.
> #. select ConfigurationOfOmniBrowser-*
> #. right click on "load configuration and stable version"
>
> more info,
>
> http://stackoverflow.com/questions/10518095/install-script-for-omnibrowser-…
>
> good luck.
>
>
>
> On Wed, May 30, 2012 at 5:17 PM, Milan Mimica <milan.mimica(a)gmail.com>wrote:
>
>> I don't get it. What do I do to load a working OmniBrowser in latest
>> Pharo 1.4?
>>
>>
>> --
>> Milan Mimica
>> http://sparklet.sf.net
>>
>
>
>
> --
> Bernardo E.C.
>
--
Bernardo E.C.
May 30, 2012
Re: [Pharo-project] [Vm-dev] Re: Plan/discussion/communication around new object format
by Eliot Miranda
On Wed, May 30, 2012 at 1:57 PM, Stefan Marr <smalltalk(a)stefan-marr.de>wrote:
>
> Hi Eliot:
>
> From my experience with the RoarVM, it seems to be a rather simple
> exercise to enable the VM to support a custom 'pre-header' for objects.
> That is, a constant offset in the memory that comes from the allocator,
> and is normally ignored by the GC.
>
That's a great idea. So for experimental use one simply throws a whole
word at the problem and forgets about the issue. Thanks, Stefan. That
leaves me free to focus on something fast and compact that is still
flexible. Great!
>
> That allows me to do all kind of stuff. Of course at a cost of a word per
> object, and at the cost of recompiling the VM.
> But, that should be a reasonable price to pay for someone doing research
> on these kind of things.
>
> Sometimes a few bits are just not enough, and such a pre-header gives much
> much more flexibility.
> For the people interested in that, I could dig out the details (I think, I
> did that already once on this list).
>
> Best regards
> Stefan
>
>
> On 30 May 2012, at 22:22, Eliot Miranda wrote:
>
> >
> >
> > On Wed, May 30, 2012 at 12:59 PM, Stéphane Ducasse <
> stephane.ducasse(a)inria.fr> wrote:
> > I would like to be sure that we can have
> > - bit for immutable objects
> > - bits for experimenting.
> >
> > There will be quite a few. And one will be able to steal bits from the
> class field if one needs fewer classes. I'm not absolutely sure of the
> layout yet. But for example
> >
> > 8: slot size (255 => extra header word with large size)
> > 3: odd bytes/fixed fields (odd bytes for non-pointer, fixed fields for
> pointer, 7 => # fixed fields is in the class)
> > 4 bits: format (pointers, indexable, bytes/shorts/longs/doubles
> indexable, compiled method, ephemerons, weak, etc)
> > 1: immutability
> > 3: GC 2 mark bits. 1 forwarded bit
> > 20: identity hash
> > 20: class index
> >
> > still leaves 5 bits unused. And stealing 4 bits each from class index
> still leaves 64k classes. So this format is simple and provides lots of
> unused bits. The format field is a great idea as it combines a number of
> orthogonal properties in very few bits. I don't want to include odd bytes
> in format because I think a separate field that holds odd bytes and fixed
> fields is better use of space. But we can gather statistics before
> deciding.
> >
> >
> > Stef
> >
> > On May 30, 2012, at 8:48 AM, Stéphane Ducasse wrote:
> >
> > > Hi guys
> > >
> > > Here is an important topic I would like to see discussed so that we
> see how we can improve and join forces.
> > > May a mail discussion then a wiki for the summary would be good.
> > >
> > >
> > > stef
> > >
> > >
> > >
> > > Begin forwarded message:
> > >
> > >> From: Eliot Miranda <eliot.miranda(a)gmail.com>
> > >> Subject: Re: Plan/discussion/communication around new object format
> > >> Date: May 27, 2012 10:49:54 PM GMT+02:00
> > >> To: Stéphane Ducasse <stephane.ducasse(a)inria.fr>
> > >>
> > >>
> > >>
> > >> On Sat, May 26, 2012 at 1:46 AM, Stéphane Ducasse <
> stephane.ducasse(a)inria.fr> wrote:
> > >> Hi eliot
> > >>
> > >> do you have a description of the new object format you want to
> introduce?
> > >>
> > >> The design is in the class comment of CogMemoryManager in the Cog
> VMMaker packages.
> > >>
> > >> Then what is your schedule?
> > >>
> > >> This is difficult. I have made a small start and should be able to
> spend time on it starting soon. I want to have it finished by early next
> year. But it depends on work schedules etc.
> > >>
> > >>
> > >> I would like to see if we can allocate igor/esteban time before we
> run out of money
> > >> to help on that important topic.
> > >> Now the solution is unclear and I did not see any document where we
> can evaluate
> > >> and plan how we can help. So do you want help on that topic? Then how
> can people
> > >> contribute if any?
> > >>
> > >> The first thing to do is to read the design document, to see if the
> Pharo community thinks it is the right direction, and to review it, spot
> deficiencies etc. So please get those interested to read the class comment
> of CogMemoryManager in the latest VMMaker.oscog.
> > >>
> > >> Here's the current version of it:
> > >>
> > >> CogMemoryManager is currently a place-holder for the design of the
> new Cog VM's object representation and garbage collector. The goals for
> the GC are
> > >>
> > >> - efficient object representation a la Eliot Miranda's VisualWorks
> 64-bit object representation that uses a 64-bit header, eliminating direct
> class references so that all objects refer to their classes indirectly.
> Instead the header contains a constant class index, in a field smaller
> than a full pointer, These class indices are used in inline and first-level
> method caches, hence they do not have to be updated on GC (although they do
> have to be traced to be able to GC classes). Classes are held in a sparse
> weak table. The class table needs only to be indexed by an instance's
> class index in class hierarchy search, in the class primitive, and in
> tracing live objects in the heap. The additional header space is allocated
> to a much expanded identity hash field, reducing hash efficiency problems
> in identity collections due to the extremely small (11 bit) hash field in
> the old Squeak GC. The identity hash field is also a key element of the
> class index scheme. A class's identity hash is its index into the class
> table, so to create an instance of a class one merely copies its identity
> hash into the class index field of the new instance. This implies that
> when classes gain their identity hash they are entered into the class table
> and their identity hash is that of a previously unused index in the table.
> It also implies that there is a maximum number of classes in the table.
> At least for a few years 64k classes should be enough. A class is entered
> into the class table in the following operations:
> > >> behaviorHash
> > >> adoptInstance
> > >> instantiate
> > >> become (i.e. if an old class becomes a new class)
> > >> if target class field's = to original's id hash
> > >> and replacement's id hash is zero
> > >> enter replacement in class table
> > >> behaviorHash is a special version of identityHash that must be
> implemented in the image by any object that can function as a class (i.e.
> Behavior).
> > >>
> > >> - more immediate classes. An immediate Character class would speed
> up String accessing, especially for WideString, since no instatiation needs
> to be done on at:put: and no dereference need be done on at:. In a 32-bit
> system tag checking is complex since it is thought important to retain
> 31-bit SmallIntegers. Hence, as in current Squeak, the least significant
> bit set implies a SmallInteger, but Characters would likely have a tag
> pattern of xxx10. Hence masking with 11 results in two values for
> SmallInteger, xxx01 and xxx11. 30-bit characters are more than adequate
> for Unicode. In a 64-bit system we can use the full three bits and
> usefully implement an immediate Float. As in VisualWorks a functional
> representation takes three bits away from the exponent. Rotating to put
> the sign bit in the least significant non-tag bit makes expanding and
> contracting the 8-bit exponent to the 11-bit IEEE double exponent easy ad
> makes comparing negative and positive zero easier (an immediate Float is
> zero if its unsigned 64-bits are < 16). So the representation looks like
> > >> | 8 bit exponent | 52 bit mantissa | sign bit | 3 tag bits |
> > >> For details see "60-bit immediate Floats" below.
> > >>
> > >>
> > >> - efficient scavenging. The current Squeak GC uses a slow
> pointer-reversal collector that writes every field in live objects three
> times in each collection, twice in the pointer-reversing heap traversal to
> mark live objects and once to update the pointer to its new location. A
> scavenger writes every field of live data twice in each collection, once as
> it does a block copy of the object when copying to to space, once as it
> traverses the live pointers in the to space objects. Of course the block
> copy is a relatively cheap write.
> > >>
> > >> - lazy become. The JIT's use of inline cacheing provides a cheap way
> of avoiding scanning the heap as part of a become (which is the simple
> approach to implementing become in a system with direct pointers). A
> becomeForward: on a (set of) non-zero-sized object(s) turns the object into
> a "corpse" or "forwarding object" whose first (non-header) word/slot is
> replaced by a pointer to the target of the becomeForward:. The corpse's
> class index is set to one that identifies corpses and, because it is a
> hidden class index, will always fail an inline cache test. The inline
> cache failure code is then responsible for following the forwarding pointer
> chain (these are Iliffe vectors :) ) and resolving to the actual target.
> We have yet to determine exactly how this is done (e.g. change the
> receiver register and/or stack contents and retry the send, perhaps
> scanning the current activation). See below on how we deal with becomes on
> objects with named inst vars. Note that we probably don't have to worry
> about zero-sized objects. These are unlikely to be passed through the FFI
> (there is nothing to pass :) ) and so will rarely be becommed. If they do,
> they can become slowly. Alternatively we can insist that objects are at
> least 16 bytes in size (see a8-byte alignment below) so that there will
> always be space for a forwarding pointer. Since none of the immediate
> classes can have non-immediate instances and since we allocate the
> immediate classes indices corresponding to their tag pattern (SmallInteger
> = 1, Character = 3, SmallFloat = 4?) we can use all the class indices from
> 0 to 7 for special uses, 0 = forward, and e.g. 1 = header-sized filler.
> > >>
> > >> - pinning. To support a robust and easy-to-use FFI the memory
> manager must support temporary pinning where individual objects can be
> prevented from being moved by the GC for as long as required, either by
> being one of an in-progress FFI call's arguments, or by having pinning
> asserted by a primitive (allowing objects to be passed to external code
> that retains a reference to the object after returning). Pinning probably
> implies a per-object "is-pinned" bit in the object header. Pinning will be
> done via lazy become; i..e an object in new space will be becommed into a
> pinned object in old space. We will only support pinning in old space.
> > >>
> > >> - efficient old space collection. An incremental collector (a la
> Dijkstra's three colour algorithm) collects old space, e.g. via an amount
> of tracing being hung off scavenges and/or old space allocations at an
> adaptive rate that keeps full garbage collections to a minimum. (see free
> space/free list below)
> > >>
> > >> - 8-byte alignment. It is advantageous for the FFI, for
> floating-point access, for object movement and for 32/64-bit compatibility
> to keep object sizes in units of 8 bytes. For the FFI, 8-byte alignment
> means passing objects to code that expects that requirement (such as modern
> x86 numeric processing instructions). This implies that
> > >> - the starts of all spaces are aligned on 8-byte boundaries
> > >> - object allocation rounds up the requested size to a multiple
> of 8 bytes
> > >> - the overflow size field is also 8 bytes
> > >> We shall probably keep the minimum object size at 16 bytes so that
> there is always room for a forwarding pointer. But this implies that we
> will need to implement an 8-byte filler to fill holes between objects > 16
> bytes whose length mod 16 bytes is 8 bytes and following pinned objects.
> We can do this using a special class index, e.g. 1, so that the method
> that answers the size of an object looks like, e.g.
> > >> chunkSizeOf: oop
> > >> <var: #oop type: #'object *'>
> > >> ^object classIndex = 1
> > >> ifTrue: [BaseHeaderSize]
> > >> ifFalse: [BaseHeaderSize
> > >> + (object slotSize = OverflowSlotSize
> > >> ifTrue:
> [OverflowSizeBytes]
> > >> ifFalse: [0])
> > >> + (object slotSize * BytesPerSlot)]
> > >>
> > >> chunkStartOf: oop
> > >> <var: #oop type: #'object *'>
> > >> ^(self cCoerceSimple: oop to: #'char *')
> > >> - ((object classIndex = 1
> > >> or: [object slotSize ~= OverflowSlotSize])
> > >> ifTrue: [0]
> > >> ifFalse: [OverflowSizeBytes])
> > >>
> > >> For the moment we do not tackle the issue of heap growth and
> shrinkage with the ability to allocate and deallocate heap segments via
> memory-mapping. This technique allows space to be released back to the OS
> by unmapping empty segments. We may revisit this but it is not a key
> requirement for the first implementation.
> > >>
> > >> The basic approach is to use a fixed size new space and a growable
> old space. The new space is a classic three-space nursery a la Ungar's
> Generation Scavenging, a large eden for new objects and two smaller
> survivor spaces that exchange roles on each collection, one being the to
> space to which surviving objects are copied, the other being the from space
> of the survivors of the previous collection, i.e. the previous to space.
> > >>
> > >> To provide apparent pinning in new space we rely on lazy become.
> Since most pinned objects will be byte data and these do not require stack
> zone activation scanning, the overhead is simply an old space allocation
> and corpsing.
> > >>
> > >> To provide pinning in old space, large objects are implicitly pinned
> (because it is expensive to move large objects and, because they are both
> large and relatively rare, they contribute little to overall fragmentation
> - as in aggregates, small objects can be used to fill-in the spaces between
> karge objects). Hence, objects above a particular size are automatically
> allocated in old space, rather than new space. Small objects are pinned as
> per objects in new space, by asserting the pin bit, which will be set
> automaticaly when allocating a large object. As a last resort, or by
> programmer control (the fullGC primitive) old space is collected via
> mark-sweep (mark-compact) and so the mark phase must build the list of
> pinned objects around which the sweep/compact phase must carefully step.
> > >>
> > >> Free space in old space is organized by a free list/free tree as in
> Eliot's VisualWorks 5i old space allocator. There are 64 free lists,
> indices 1 through 63 holding blocks of space of that size, index 0 holding
> a semi-balanced ordered tree of free blocks, each node being the head of
> the list of free blocks of that size. At the start of the mark phase the
> free list is thrown away and the sweep phase coallesces free space and
> steps over pinned objects as it proceeds. We can reuse the forwarding
> pointer compaction scheme used in the old collector. Incremental
> collections merely move unmarked objects to the free lists (as well as
> nilling weak pointers in weak arrays and scheduling them for finalization).
> The occupancy of the free lists is represented by a bitmap in a 64-bit
> integer so that an allocation of size 63 or less can know whether there
> exists a free chunk of that size, but more importantly can know whether a
> free chunk larger than it exists in the fixed size free lists without
> having to search all larger free list heads.
> > >>
> > >> The incremental collector (a la Dijkstra's three colour algorithm)
> collects old space via an amount of tracing being hung off scavenges and/or
> old space allocations at an adaptive rate that keeps full garbage
> collections to a minimum. [N.B. Not sure how to do this yet. The
> incremental collector needs to complete a pass often enough to reclaim
> objects, but infrequent enough not to waste time. So some form of feedback
> should work. In VisualWorks tracing is broken into quanta or work where
> image-level code determines the size of a quantum based on how fast the
> machine is, and how big the heap is. This code could easily live in the
> VM, controllable through vmParameterAt:put:. An alternative would be to
> use the heartbeat to bound quanta by time. But in any case some amount of
> incremental collection would be done on old space allocation and
> scavenging, the ammount being chosen to keep pause times acceptably short,
> and at a rate to reclaim old space before a full GC is required, i.e. at a
> rate proportional to the growth in old space]. The incemental collector is
> a state machine, being either marking, nilling weak pointers, or freeing.
> If nilling weak pointers is not done atomically then there must be a read
> barrier in weak array at: so that reading from an old space weak array that
> is holding stale un-nilled references to unmarked objects. Tricks such as
> including the weak bit in bounds calculations can make this cheap for
> non-weak arrays. Alternatively nilling weak pointers can be made an atomic
> part of incremental collection, which can be made cheaper by maintaining
> the set of weak arrays (e.g. on a list).
> > >>
> > >> The incremental collector implies a more complex write barrier.
> Objects are of three colours, black, having been scanned, grey, being
> scanned, and white, unreached. A mark stack holds the grey objects. If
> the incremental collector is marking and an unmarked white object is stored
> into a black object then the stored object must become grey, being added to
> the mark stack. So the wrte barrier is essentially
> > >> target isYoung ifFalse:
> > >> [newValue isYoung
> > >> ifTrue: [target isInRememberedSet ifFalse:
> > >> [target addToRememberedSet]]
> "target now refers to a young object; it is a root for scavenges"
> > >> ifFalse:
> > >> [(target isBlack
> > >> and: [igc marking
> > >> and: [newValue isWhite]]) ifTrue:
> > >> [newValue beGrey]]] "add
> newValue to IGC's markStack for subsequent scanning"
> > >>
> > >> The incremental collector does not detect already marked objects all
> of whose references have been overwritten by other stores (e.g. in the
> above if newValue overwrites the sole remaining reference to a marked
> object). So the incremental collector only guarantees to collect all
> garbage created in cycle N at the end of cycle N + 1. The cost is hence
> slightly worse memory density but the benefit, provided the IGC works hard
> enough, is the elimination of long pauses due to full garbage collections,
> which become actions of last resort or programmer desire.
> > >>
> > >> Lazy become.
> > >>
> > >> As described earlier the basic idea behind lazy become is to use
> corpses (forwarding objects) that are followed lazily during GC and inline
> cache miss. However, a lazy scheme cannot be used on objects with named
> inst vars without adding checking to all inst var accesses, which we judge
> too expensive. Instead, when becomming objects with named inst vars, we
> scan all activations in the stack zone, eagerly becomming these references,
> and we check for corpses when faulting in a context into the stack zone.
> Essentially, the invariant is that there are no references to corpses from
> the receiver slots of stack activations. A detail is whether we allow or
> forbid pinning of closure indirection vectors, or scan the entire stack of
> each activation. Using a special class index pun for indirection vectors
> is a cheap way of preventing their becomming/pinning etc. Although "don't
> do that" (don't attempt to pin/become indirection vectors) is also an
> acceptable response.
> > >>
> > >> 60-bit immediate Floats
> > >> Representation for immediate doubles, only used in the 64-bit
> implementation. Immediate doubles have the same 52 bit mantissa as IEEE
> double-precision floating-point, but only have 8 bits of exponent. So
> they occupy just less than the middle 1/8th of the double range. They
> overlap the normal single-precision floats which also have 8 bit exponents,
> but exclude the single-precision denormals (exponent-127) and the
> single-precsion NaNs (exponent +127). +/- zero is just a pair of values
> with both exponent and mantissa 0.
> > >> So the non-zero immediate doubles range from
> > >> +/- 0x3800,0000,0000,0001 / 5.8774717541114d-39
> > >> to +/- 0x47ff,ffff,ffff,ffff / 6.8056473384188d+38
> > >> The encoded tagged form has the sign bit moved to the least
> significant bit, which allows for faster encode/decode because offsetting
> the exponent can't overflow into the sign bit and because testing for +/- 0
> is an unsigned compare for <= 0xf:
> > >> msb
> lsb
> > >> [8 exponent subset bits][52 mantissa bits ][1 sign bit][3 tag
> bits]
> > >> So assuming the tag is 5, the tagged non-zero bit patterns are
> > >> 0x0000,0000,0000,001[d/5]
> > >> to 0xffff,ffff,ffff,fff[d/5]
> > >> and +/- 0d is 0x0000,0000,0000,000[d/5]
> > >> Encode/decode of non-zero values in machine code looks like:
> > >> msb
> lsb
> > >> Decode:
> [8expsubset][52mantissa][1s][3tags]
> > >> shift away tags: [ 000
> ][8expsubset][52mantissa][1s]
> > >> add exponent offset: [ 11 exponent ][52mantissa][1s]
> > >> rot sign: [1s][ 11 exponent
> ][52mantissa]
> > >>
> > >> Encode: [1s][ 11 exponent
> ][52mantissa]
> > >> rot sign: [ 11 exponent
> ][52mantissa][1s]
> > >> sub exponent offset: [ 000 ][8expsubset][52 mantissa][1s]
> > >> shift: [8expsubset][52
> mantissa][1s][ 000 ]
> > >> or/add tags: [8expsubset][52mantissa][1s][3tags]
> > >> but is slower in C because
> > >> a) there is no rotate, and
> > >> b) raw conversion between double and quadword must (at least in the
> source) move bits through memory ( quadword = *(q64 *)&doubleVariable).
> > >>
> > >> Issues:
> > >> How do we avoid the Size4Bit for 64-bits? The format word encodes
> the number of odd bytes, but currently has only 4 bits and hence only
> supports odd bytes of 0 - 3. We need odd bytes of 0 - 7. But I don't like
> the separate Size4Bit. Best to change the VI code and have a 5 bit format?
> We loose one bit but save two bits (isEphemeron and isWeak (or three, if
> isPointers)) for a net gain of one (or two)
> > >>
> > >> Further, keep Squeak's format idea or go for separate bits? For
> 64-bits we need a 5 bit format field. This contrasts with isPointers,
> isWeak, isEphemeron, 3 odd size bits (or byte size).. format field is
> quite economical.
> > >>
> > >> Are class indices in inline caches strong references to classes or
> weak references?
> > >> If strong then they must be scanned during GC and the methodZone must
> be flushed on fullGC to reclaim all classes (this looks to be a bug in the
> V3 Cogit).
> > >> If weak then when the class table loses references, PICs containing
> freed classes must be freed and then sends to freed PICs or containing
> freed clases must be unlinked.
> > >> The second approach is faster; the common case is scanning the class
> table, the uncommon case is freeing classes. The second approach is
> better; in-line caches do not prevent reclamation of classes.
> > >>
> > >>
> > >> Stef
> > >>
> > >>
> > >>
> > >> --
> > >> best,
> > >> Eliot
> > >>
> > >
> >
> >
> >
> >
> >
> > --
> > best,
> > Eliot
> >
>
> --
> Stefan Marr
> Software Languages Lab
> Vrije Universiteit Brussel
> Pleinlaan 2 / B-1050 Brussels / Belgium
> http://soft.vub.ac.be/~smarr
> Phone: +32 2 629 2974
> Fax: +32 2 629 3525
>
>
--
best,
Eliot
May 30, 2012