size and basicAt

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

size and basicAt

Fernando Rodríguez
Hi,

Both mehtods are implemented as primitives but it's not clear to me
how a Collection (for instance) tells the VM that it's an indexable
class.

I'm a bit lost with these indexed variables thing... Any pointer would
be appreciated.

Thanks


Reply | Threaded
Open this post in threaded view
|

Re: size and basicAt

Ian Bartholomew-19
Fernando,

> Both mehtods are implemented as primitives but it's not clear to me
> how a Collection (for instance) tells the VM that it's an indexable
> class.

Have a look at the class definitions.  For example ...

Collection is an "Object subclass".  You can't create usable instances of
Collection (for indexing anyway) so it just a "normal" class with no indexed
instance variables.

Array is an "ArrayedCollection variableSubclass".  This tells the
compiler/vm that it has indexed instance variables after it's named instance
variables.

ByteArray is an "ArrayedCollection variableByteSubclass".  This indicates
that it is only allowed to have byte values in it's indexed instance
variables (and no named instance variables are allowed in subclasses).

> I'm a bit lost with these indexed variables thing... Any pointer would
> be appreciated.

A "normal" class stores it's instance variables in slots associated with
each instance and can only have "named" variables.  For example Point has
two named instance variables #x and #y which can be accessed normally ....

(100 @ 200) x ==> 100

or via the instVar's position

(100 @ 200) instVarAt: 1 ==> 100


A "variableSubclass" has (optionally) named instance variables followed by
indexed instance variables.  Create a subclass of Array named ArrayX, give
it one named instVar called #fred and provide an accessor.

ax := ArrayX new: 5.
ax fred: 123.
ax at: 1 put: 'Hello'.

ax instVarAt: 1 => 123
ax instVarAt: 2 ==> 'Hello'


A "variableByteSubclass" is the same but no named instVars are allowed so

(a at: 1) == (a instVarAt: 1) ==> true


One final point.  named instance variables are added from the superclass(es)
down.  Add an subclass of ArrayX called ArrayY and give it an instVar and
accessor named #bert.

ay := ArrayY new: 5.
ay fred: 22.
ay bert: 33.
ay at: 1 put: 44.

ay instVarAt: 1.==> 22
ay instVarAt: 2.==> 33
ay instVarAt: 3.==> 44

--
Ian

Use the Reply-To address to contact me.
Mail sent to the From address is ignored.


Reply | Threaded
Open this post in threaded view
|

Re: size and basicAt

Reinout Heeck-3
In reply to this post by Fernando Rodríguez
Fernando wrote:
> Hi,
>
> Both mehtods are implemented as primitives but it's not clear to me
> how a Collection (for instance) tells the VM that it's an indexable
> class.

I don't know about Dolphin but in VW it is part of the class definition
template. For example:

Smalltalk.Core defineClass: #OrderedCollection
        superclass: #{Core.SequenceableCollection}
        indexedType: #objects
        private: false
        instanceVariableNames: 'firstIndex lastIndex '
        classInstanceVariableNames: ''
        imports: ''
        category: 'Collections-Sequenceable'


the indexType: determines the type of storage, normal objects have type
#none, ByteArrays have type #bytes and Arrays have type #objects. This
is how the VM is informed about indexability.


In VW the class Object implements #at: and #basicAt: (both identically)
as well as #size and #basicSize (identically). The idea is that methods
starting with 'basic' are never overridden.

So in the case of OrderedCollection above #basicSize will return the
amount of storage available (also known as the collection's capacity)
but #size will return a different value calculated from the instance
variables firstIndex and lastIndex. IOW #size has been overridden in
OrderedCollection to make use of these variables.




Enjoy!

Reinout
-------


Reply | Threaded
Open this post in threaded view
|

Re: size and basicAt

Eliot Miranda
In reply to this post by Fernando Rodríguez
Mark van Gulik (ghoul) wrote:

> The first two replies described instance variables, but that wasn't
> quite the question.  The poster wanted to know how the VM knows about
> it.  The answer is that the class's "format" instance variable encodes
> the number of named instance variables, as well as flags that indicate
> whether there can be numbered pointer instance variables, numbered byte
> instance variables, weak slots (VW), and ephemeral slots (VW).  The
> VM's instance creation machinery uses this information to determine how
> many bytes to allocate, how to initialize those bytes, etc.  The
> garbage collector uses this information to distinguish inter-object
> pointers from raw bytes.

...and flag bits in every object header are used to indicate what kind
of object each is, along with a (potentially indirect) reference to its
class for looking up messages, finding the class's "format" inst var.

The GC only needs inspect the flag bits to do its stuff (e.g. it can
ignore the contents of a byte object when doing a scan-mark).  The
basicAt: & size primitive may have to go to the class to find the number
of fixed fields if a given implementation has no room for that info in
the object header.

--
_______________,,,^..^,,,____________________________
Eliot Miranda              Smalltalk - Scene not herd


Reply | Threaded
Open this post in threaded view
|

Re: size and basicAt

Vassili Bykov-4
In reply to this post by Fernando Rodríguez
Mark van Gulik (ghoul) wrote:

> The first two replies described instance variables, but that wasn't
> quite the question.  The poster wanted to know how the VM knows about
> it.  The answer is that the class's "format" instance variable encodes
> the number of named instance variables, as well as flags that indicate
> whether there can be numbered pointer instance variables, numbered byte
> instance variables, weak slots (VW), and ephemeral slots (VW).  The
> VM's instance creation machinery uses this information to determine how
> many bytes to allocate, how to initialize those bytes, etc.  The
> garbage collector uses this information to distinguish inter-object
> pointers from raw bytes.

To be still more precise, the format stores the number of *fixed fields*
of an object. Named instance variables is a concept introduced at the
image level, and only by ClassDescription rather than base Behavior. VM
is oblivious to names. In the default image, fixed fields and named
variables are the same, but it is theoretically possible to have
subclasses of Behavior for which it wouldn't be so.

Anyway, that still doesn't explain how indexed variables work--for
example, where the result of #basicSize comes from and how #basicAt:
ensures the index is within bounds.

The missing bit of information so far was that not everything is
determined by the class. In case of classes with indexed variables, the
class only contains a flag that says its instances *can* have additional
fields. The actual number of those fields is specified at the instance
creation time (the argument passed with the #new: message) and is stored
in that particular object's header, after adding the number of fixed
fields required by the class format. The header is a block of
information visible to the VM and is not (at least not in a portable
between dialects way) accessible from the image. You can think of the
information passed to #new: as "magically remembered".

As an example, if you have a class A with two instance variables, plus
one inherited from the superclass, the class format has 3 as the fixed
slot count. If the class is declared as variableSubclass, the format
also has the indexed flag set. All together, the format says that any
instance of that class will have at least 3 fields--but possibly more.
"A new: 4" creates an instance with 7 fields total, and remembers 7 as
the instance size in its object header. The primitive for #basicSize
will fetch that 7 from the header, subtract the fixed field count as
declared by the class, and answer 4. "basicAt: 1" will add the 3 from
the class format, ensure that the result is not greater than 7, and
fetch the 4th field of the instance.


--
Vassili Bykov
VisualWorks Engineering, Tools Technical Lead
v b y k o v  A T  c i n c o m  D O T  c o m
http://www.cincomsmalltalk.com/userblogs/vbykov