Discussion:
Dynamically Allocated Arrays
(too old to reply)
August Karlstrom
2008-09-12 11:25:39 UTC
Permalink
Hi,

Does anyone know why Oberon (including Oberon-07) as opposed to Oberon-2
lacks dynamically allocated arrays? Are they hard to implement or did
Wirth consider them superfluous?


August
Chris Burrows
2008-09-12 13:09:00 UTC
Permalink
Post by August Karlstrom
Hi,
Does anyone know why Oberon (including Oberon-07) as opposed to Oberon-2
lacks dynamically allocated arrays? Are they hard to implement or did
Wirth consider them superfluous?
Although they aren't included in the Oberon-07 Language Report Wirth
actually implemented dynamically allocated arrays as an extension to the
language in his Oberon-07 Compiler for the ARM Processor

<quote>
Dynamic arrays are here introduced as an addition to Oberon. An array is
called dynamic, if its length is determined "dynamically", i.e. at execution
time. This is done by a call to the intrinsic procedure NEW with a second
parameter indicating the desired length. Example:

VAR a: ARRAY OF INTEGER;

BEGIN . NEW(a, len) .

where len is an expression of type INTEGER and a non-negative value.
</quote>

Note that this implementation of dynamically allocated arrays is subject to
the restrictions that they are one-dimensional and cannot be elements of
other data structures.

--
Chris Burrows
Armaide: Oberon-07 for ARM Development System
http://www.armaide.com
thutt
2008-09-16 01:54:18 UTC
Permalink
Post by August Karlstrom
Hi,
Does anyone know why Oberon (including Oberon-07) as opposed to Oberon-2
lacks dynamically allocated arrays? Are they hard to implement or did
Wirth consider them superfluous?
August
It's a complication for the garbage collector to have dynamic arrays.
Once you have dynamic arrays, you probably want to support
multidimensional arrays, and then you want them to be of records,
pointers and other arrays.

The GC has to be completely redesigned to handle this, and the
original Oberon system did not support this at all.

thutt
Oberon Paladin (in lieu of Cheryl Lins)
--
The pages on a book and pictures on a screen
We shape ourselves like clay from someone elses dream.
-- Not My Slave (Oingo Boingo)
August Karlstrom
2008-09-16 08:29:22 UTC
Permalink
Post by thutt
It's a complication for the garbage collector to have dynamic arrays.
Once you have dynamic arrays, you probably want to support
multidimensional arrays, and then you want them to be of records,
pointers and other arrays.
At least, the GC already supports records of pointers to records.
Post by thutt
The GC has to be completely redesigned to handle this, and the
original Oberon system did not support this at all.
I thought an extra for-loop in the GC for arrays would do the trick, as
it will when manually freeing an array of pointers in e.g. C.


August
thutt
2008-09-18 16:31:42 UTC
Permalink
Post by August Karlstrom
Post by thutt
It's a complication for the garbage collector to have dynamic arrays.
Once you have dynamic arrays, you probably want to support
multidimensional arrays, and then you want them to be of records,
pointers and other arrays.
At least, the GC already supports records of pointers to records.
Post by thutt
The GC has to be completely redesigned to handle this, and the
original Oberon system did not support this at all.
I thought an extra for-loop in the GC for arrays would do the trick,
as it will when manually freeing an array of pointers in e.g. C.
August
Well, the complication in the GC implemenation is significant, but
easily achievable once your heap block descriptors have been fully
flushed out. So, to sum things up:

1. You need to come up with block descriptors for each type of
thing which can be allocated on the heap.

a) record
b) array of integral type (real, integer, char)
c) array of record with no pointers
d) system blocks (not collected)
e) ...

When I did my Oberon system back in the early to mid-90s, I had
11 different types of things which can be allocated on the heap.

Here's the constants I defined for each type of block that can
allocated:

DescFlagsRecord* = 0;
DescFlagsDynArray0* = 1;
DescFlagsDynArray1* = 2;
DescFlagsDynArray2* = 3;
DescFlagsDynArray3* = 4;
DescFlagsDynArray4* = 5;
DescFlagsDynArray5* = 6;
DescFlagsStaticArray0* =7;
DescFlagsStaticArray1* = 8;
DescFlagsStaticArray2* = 9;
DescNofArrayType = 10;

(* element is a simple or procedure type *)
SimpleElemSet* = {DescFlagsDynArray0,
DescFlagsDynArray3,
DescFlagsStaticArray0};
(* element is a pointer type *)
PointerElemSet* = {DescFlagsDynArray1,
DescFlagsDynArray4,
DescFlagsStaticArray1};
(* element is a record type *)
RecordElemSet* = {DescFlagsDynArray2,
DescFlagsDynArray5,
DescFlagsStaticArray2};

That's not altogether the most descriptive information without
the printed documentation, but it should give you an idea of the
maximal amount of types that can be allocated on the heap. If
you're inclined, you can try to figure out the 11 different
types of objects.

2. Compiler must create a descriptor for each of the items in
number 1.

3. Linker / load must handle fixups to the items in number 2.
This should 'just work' if your compiler is written well.

4. Allocator must be updated to handle multi-dimensional arrays.
This is done in the compiler & the runtime system. The heap
allocator must not only calculate the amount of memory required
for each allocation of a multi-dimensional array, but it must
also update the block descriptor to indicate the 'actual' length
of each array index.

5. For runtime checking, the compiler must generate code to use
the block descriptor when determining if the index is
out-of-bounds.

6. GC must be updated to handle all the types of blocks that can
occur in the heap.

It's a lot of work, and it's tedious.

Oberon-2 has always supported multidimensional arrays on the heap, but
the early ETH systems did not GC blocks allocated for such items. I
spent a significant amount of time developing the system so that it
would actually collect those blocks.

thutt
Reformed Oberon Paladin, VHDL novice
--
Every person new to soldering will try to
catch a falling soldering iron exactly once.
August Karlstrom
2008-09-19 09:43:49 UTC
Permalink
Post by thutt
Post by August Karlstrom
Post by thutt
The GC has to be completely redesigned to handle this, and the
original Oberon system did not support this at all.
I thought an extra for-loop in the GC for arrays would do the trick,
as it will when manually freeing an array of pointers in e.g. C.
Well, the complication in the GC implemenation is significant, but
easily achievable once your heap block descriptors have been fully
1. You need to come up with block descriptors for each type of
thing which can be allocated on the heap.
[...]

Thanks for the thorough explanation. As your example shows, allowing
dynamically allocated arrays certainly makes the runtime more complex.


August
Chris Burrows
2008-09-22 00:13:12 UTC
Permalink
Post by August Karlstrom
Thanks for the thorough explanation. As your example shows, allowing
dynamically allocated arrays certainly makes the runtime more complex.
One useful consequence of the restrictions placed on dynamically allocated
arrays in the extension to Oberon-07 is that when such arrays are declared
as local variables they can be safely allocated on the stack. Thus no
garbage collector or special treatment is required to free their memory when
the procedure terminates.

Unfortunately the same cannot be said for local pointer variables as, if
aliased to a global, their contents are required to exist beyond the
lifetime of the procedure call.

--
Chris Burrows
Armaide: Oberon-07 for ARM Development System
http://www.armaide.com
August Karlstrom
2008-09-22 10:42:31 UTC
Permalink
Post by Chris Burrows
One useful consequence of the restrictions placed on dynamically allocated
arrays in the extension to Oberon-07 is that when such arrays are declared
as local variables they can be safely allocated on the stack. Thus no
garbage collector or special treatment is required to free their memory when
the procedure terminates.
I see, pretty much like the function alloca in the GNU C Library.
Post by Chris Burrows
Unfortunately the same cannot be said for local pointer variables as, if
aliased to a global, their contents are required to exist beyond the
lifetime of the procedure call.
OK, so the optimization technique of allocating dynamic arrays on the
stack would not be possible if dynamic arrays were bound to array
pointers as in Oberon-2.


August

Loading...