-- JaMVMImpl.mesa
-- Pilot version
-- Original version by Martin Newell, February 1979
-- Updated June 12, 1979  4:42 PM by MN
-- Last changed by Bill Paxton, November 5, 1982 9:45 am

DIRECTORY
  JaMBasic,
  JaMVM,
  Inline,
  Space,
  RTOS;

JaMVMImpl: MONITOR
IMPORTS JaMVM, Inline, RTOS
EXPORTS JaMVM = {
OPEN JaMBasic;

-- Globals

Offs: TYPE = [0..1];
Ptr: TYPE = LONG POINTER;

segment: Ptr ← NIL; -- to base of current chunk of storage
size: LONG CARDINAL ← 0; -- size of current segment
words: LONG CARDINAL ← 0; -- number of words allocated from this chunk
offset: CARDINAL ← 0;

-- Procedures

WordsForPages: PROC[p: CARDINAL] RETURNS[LONG CARDINAL] = INLINE {
  RETURN[Inline.LongMult[p,Space.wordsPerPage]] };
PagesForWords: PROC[w: LONG CARDINAL] RETURNS[CARDINAL] = INLINE {
  RETURN[Inline.LongDiv[w + Space.wordsPerPage - 1, Space.wordsPerPage]] };

Expand: PROC [atleast: LONG CARDINAL] = {
  want: CARDINAL ← PagesForWords[atleast];
  pages: CARDINAL ← 4*((MAX[want,64]+1)/4); -- round up to multiple of 4
  size ← WordsForPages[pages];
  -- create a space to the hold monster
  segment ← RTOS.GetDataPagesFromNewSpace[nPages: pages];
  words ← 0;
  offset ← 0;
  };

AllocWords: ENTRY PROC[n: LONG CARDINAL] RETURNS[Ptr] = {
  DO
  ptr: Ptr;
  IF offset > 0 THEN { words ← words + 1; offset ← 0 };
  ptr ← segment + words;
  words ← words + n;
  IF words >= size THEN { Expand[n]; LOOP };
  RETURN[ptr];
  ENDLOOP;
  };

AllocChars: ENTRY PROC[n: CARDINAL] RETURNS[Ptr,Offs] = {
  DO
  ptr: Ptr ← segment + words;
  offs: Offs ← offset;
  frac: CARDINAL ← offs + n MOD 2;
  words ← words + n/2 + frac/2; -- mind overflow!
  offset ← frac MOD 2;
  IF words >= size THEN { Expand[n/2 + frac/2]; LOOP };
  RETURN[ptr,offs];
  ENDLOOP;
  };

AllocString: PUBLIC PROC[length: StringLength] RETURNS[string Object] = {
  string: string Object ← [L,string[length: length, text: , offset: ]];
  [string.text,string.offset] ← AllocChars[length];
  RETURN[string];
  };

AllocArray: PUBLIC PROC[length: CARDINAL] RETURNS[array Object] = {
  array: array Object ← [L,array[length: length, base: ]];
  array.base ← AllocWords[Inline.LongMult[length,SIZE[Object]]];
  RETURN[array];
  };

AllocTuples: PROC[size: CARDINAL] RETURNS[beg,end: TuplePtr] = {
  words: LONG CARDINAL ← Inline.LongMult[size,SIZE[Tuple]];
  beg ← AllocWords[words]; end ← beg + words;
  RETURN[beg,end];
  };

AllocDict: PUBLIC PROC[size: CARDINAL] RETURNS[dict Object] = {
  dict: dict Object ← [L,dict[AllocWords[SIZE[DictBody]]]];
  dd: DictBody ← [curlen: 0, maxlen: 0, size: size,
    beg: , end: , curatt: 0, attach: [L,array[0,NIL]]];
  [dd.beg,dd.end] ← AllocTuples[size];
  JaMVM.PutDict[dict,dd];
  RETURN[dict];
  };

CopyArray: PUBLIC PROC[src,dst: array Object] = {
  count: CARDINAL ← MIN[src.length,dst.length]; -- number of objects to copy
  sptr: LONG POINTER ← src.base;
  dptr: LONG POINTER ← dst.base;
  words: LONG CARDINAL ← Inline.LongMult[count,SIZE[Object]];
  chunk: CARDINAL = (LAST[CARDINAL]/SIZE[Object])*SIZE[Object];
  WHILE words>0 DO
    w: CARDINAL ← Inline.LowHalf[MIN[words,chunk]];
    Inline.LongCOPY[from: sptr, nwords: w, to: dptr];
    sptr ← sptr + w; dptr ← dptr + w; words ← words - w;
    ENDLOOP;
  };

GetText: PUBLIC PROC[string: string Object, text: LONG STRING] = {
  count: CARDINAL ← MIN[string.length,text.maxlength];
  stext: LONG POINTER TO TextBody ← string.text;
  soffs: CARDINAL ← string.offset;
  FOR i: CARDINAL IN[0..count) DO text[i] ← stext[soffs+i] ENDLOOP;
  text.length ← count;
  };

PutText: PUBLIC PROC[string: string Object, text: LONG STRING] = {
  count: CARDINAL ← MIN[string.length,text.length];
  stext: LONG POINTER TO TextBody ← string.text;
  soffs: CARDINAL ← string.offset;
  FOR i: CARDINAL IN[0..count) DO stext[soffs+i] ← text[i] ENDLOOP;
  };

CopyString: PUBLIC PROC[src,dst: string Object] = {
  count: CARDINAL ← MIN[src.length,dst.length]; -- number of chars to copy
  stext: LONG POINTER TO TextBody ← src.text;
  dtext: LONG POINTER TO TextBody ← dst.text;
  soffs: CARDINAL ← src.offset;
  doffs: CARDINAL ← dst.offset;
  FOR i: CARDINAL IN[0..count) DO dtext[doffs+i] ← stext[soffs+i] ENDLOOP;
  };

rootInfo: LONG POINTER TO Root ← NIL;

GetRoot: PUBLIC PROC[root: LONG POINTER TO Root] = { root↑ ← rootInfo↑ };
PutRoot: PUBLIC PROC[root: LONG POINTER TO Root] = { rootInfo↑ ← root↑ };

Start: PUBLIC PROC = {
  rootInfo ← AllocWords[SIZE[Root]];
  };

}.