12 Memory

12.1 Overview

(1) All the storage of a state is in the block the host gave (5.1) and is placed at load, apart from memory the host lends and vouches for (12.1 (2)). No storage appears while running. There is no garbage collector, and no value refers to another by address.

(2) Values lie in four kinds of places:

(3) So the upper bound of the memory a program uses is known at load. Using up the region or a capacity shows as a fault or a failure while running; it never leads the processor to ask for more memory.

12.2 The region and marks

(1) Words that make new bytes — cat, str.upper, the words that turn numbers into text and so on — write the result into the region and give a view of it. The region is filled from the front. The word region_free gives the number of bytes left.

(2) mark gives the current place in the region as an owned value (type mark). mark release rewinds the region to that place; every byte made after the mark can be used again. A loop that makes much text marks and releases in every turn.

(3) Bytes put into stored text (str(N)) are copied there, so they survive rewinding the region.

12-region.pnx

use io
use str
global kept str(32)
word line (i int gives str) cat ("line number ", i) end
word demo ()
  region_free to start
  1 line to a                                 rem a view of 13 new bytes in the region
  a set kept                                   rem stored text: the bytes are copied out
  start region_free sub to one
  mark to m
  2 1000 range do (i int) i line drop end each
  start region_free sub to many
  m release                                   rem back to the place of the mark
  start region_free sub to after
  cat ("one line: ", one, ", 999 lines: ", many, ", after release: ", after) io.println
  kept io.println
end
demo

Output

$ pnx 12-region.pnx
one line: 13, 999 lines: 14877, after release: 13
line number 1

(4) A str result the host receives can be used only until the next call on that state. Text the host keeps longer it copies into its own memory (clause 19).

Faults

(5) A region too small is the fault full.

12-region-full.pnx

word fill ()
  loop cat ("this line takes some bytes of the region ", 0) drop end
end
fill

Fault

$ pnx 12-region-full.pnx
12-region-full.pnx:2: a declared capacity is used up

12.3 The life of views

(1) A view into the region cannot be used once its bytes are rewound. A processor checks this at load. Within one body (a word, a block value, the code outside definitions) it counts, for each str value, the marks made before it. mark release takes back the values made after that mark.

Constraints

(2) A release while a value it takes back is still on the stack is refused.

12-release-stack.pnx

word f (gives str)
  mark to m
  cat ("a", "b")
  m release
end

Refused

$ pnx 12-release-stack.pnx
12-release-stack.pnx:4:5: a str made after this mark is still on the stack; the release gives its bytes back

(2a) A release in deferred code that runs because the word fails (or_fail, fail; 10.7 (1)) does not count the values the word leaves on the stack: the word ends there, its stack is not read again, and deferred code takes nothing from it (10.7 (4)). The values of the deferred code itself count as in (2), and a local holding a value taken back is as in (3). A failure carries only its code (11.2), so no str leaves the word that way.

12-release-failing.pnx

use io
use str
word check (w str or fail)
  w str.len 5 gt if err.range fail end
end
word words_of (line str or fail)
  loop
    mark to m
    defer m release end
    line str.lower str.words do (w str) w check or_fail  w io.println end each
    break
  end
end
"Pinax interprets" words_of or_else (e) cat ("failed: ", e err_text) io.println end

Output

$ pnx 12-release-failing.pnx
pinax
failed: range

(3) A local holding a value taken back cannot be read until something is stored into it again.

12-release-view.pnx

use io
word f ()
  mark to m
  cat ("made after ", "the mark") to s
  m release
  s io.println
end

Refused

$ pnx 12-release-view.pnx
12-release-view.pnx:6:3: this str was made after a mark that was released since; the region may hold other bytes there now

(4) The check leans to caution. String literals are not in the region and are never taken back. Every other str — views, stored text read back, values words give — counts as made where it appears. Where paths meet, a value counts as the latest and a mark as the earliest. So it may refuse a correct program; then keep the value in a str(N) or move the mark.

(5) Handing an owned mark to a word counts as a release there. A word that takes a mark counts its str inputs as made after that mark. Two tasks sharing one region are not followed by this check (clause 14).

12.4 Owned values

(1) owned before a type means an owned value: an open file and other handles, a row taken from a pool, a mark of the region. A processor checks at load that such a value is handed over exactly once on every path.

(2) An owned value is used in two ways:

(3) An owned value is put into a local or handed over at once. It cannot be doubled with dup or discarded with drop. It shall be handed over on the paths of failures (or_fail or_return) and at return too.

12-owned-file.pnx

use io
use file
word write_note (path str or fail)
  path file.open_write or_fail to f            rem an owned file: it must be closed on every path
  "a note" f file.write or_else (e) f file.close e fail end
  f file.close
end
word read_note (path str gives s str or fail) path file.read_all or_fail end
"note.txt" write_note or_else (e) "cannot write" io.println end
"note.txt" read_note or_else (e) "cannot read" end io.println

Output

$ pnx 12-owned-file.pnx
a note
Constraints

(4) Using a value again after handing it over is refused.

12-owned-twice.pnx

use file
word f (path str or fail)
  path file.open_read or_fail to h
  h file.close
  h file.close
end

Refused

$ pnx 12-owned-twice.pnx
12-owned-twice.pnx:5:3: this local gave its owned value away; it holds nothing to read

(5) Doubling or discarding an owned value is refused.

12-owned-dup.pnx

use file
word f (path str or fail)
  path file.open_read or_fail dup file.close file.close
end

Refused

$ pnx 12-owned-dup.pnx
12-owned-dup.pnx:3:31: an owned value is kept in a local or given on at once; this word would lose it

(6) A single path that does not hand it over is enough to refuse.

12-owned-path.pnx

use file
word f (path str, quick bool or fail)
  path file.open_read or_fail to h
  quick if return end
  h file.close
end

Refused

$ pnx 12-owned-path.pnx
12-owned-path.pnx:4:12: an owned value in a local is not given on every path (close, free or store it)

(7) In a run that ends with a fault, the processor closes the handles that run opened (11.3 (3)).

Diagnostics
ConditionMessage
A value taken back is on the stack at releasea str made after this mark is still on the stack; the release gives its bytes back
Reading a value taken backthis str was made after a mark that was released since; the region may hold other bytes there now
Reading a value handed overthis local gave its owned value away; it holds nothing to read
Doubling or discarding an owned valuean owned value is kept in a local or given on at once; this word would lose it
A path that does not hand it overan owned value in a local is not given on every path (close, free or store it)