Copyright 1996-2000, Critical Mass, Inc. All rights reserved.
See file COPYRIGHT-CMASS for details.
UNSAFE MODULE RTType EXPORTS RTType, RTTypeSRC, RTHooks;
IMPORT RT0, RTMisc, RTException, RTHeapRep, RTModule, M3toC;
IMPORT Ctypes, Cstdlib, Cstring, Word, RuntimeError;
TYPE
TK = RT0.TypeKind;
RTE = RuntimeError.T;
TYPE
InfoPtr = UNTRACED REF Info;
Info = RECORD
def : RT0.TypeDefn;
opaqueID : INTEGER;
module : RT0.ModulePtr;
END;
VAR
types := InfoMap {"typecodes", TypecodeEq, TypecodeRehash, 1024, 1024};
uids := InfoMap {"typeuids", UIDEq, UIDRehash, 1024, 512};
brands := InfoMap {"brands", BrandEq, BrandRehash, 512, 256};
------------------------------------------------ user callable routines ---
PROCEDURE MaxTypecode (): Typecode =
BEGIN
RETURN types.cnt - 1;
END MaxTypecode;
PROCEDURE IsSubtype (a, b: Typecode): BOOLEAN =
VAR t: RT0.TypeDefn;
BEGIN
IF (a = RT0.NilTypecode) THEN RETURN TRUE END;
t := Get (a);
IF (t = NIL) THEN RETURN FALSE; END;
IF (t.typecode = b) THEN RETURN TRUE END;
WHILE (t.kind = ORD (TK.Obj)) DO
IF (t.link_state = 0) THEN FinishTypecell (t, NIL); END;
t := LOOPHOLE (t, RT0.ObjectTypeDefn).parent;
IF (t = NIL) THEN RETURN FALSE; END;
IF (t.typecode = b) THEN RETURN TRUE; END;
END;
IF (t.traced # 0)
THEN RETURN (b = RT0.RefanyTypecode);
ELSE RETURN (b = RT0.AddressTypecode);
END;
END IsSubtype;
PROCEDURE Supertype (tc: Typecode): Typecode =
VAR t := Get (tc); ot := LOOPHOLE (t, RT0.ObjectTypeDefn);
BEGIN
IF (t.kind # ORD (TK.Obj)) THEN RETURN NoSuchType; END;
IF (t.link_state = 0) THEN FinishTypecell (t, NIL); END;
IF (ot.parent = NIL) THEN RETURN NoSuchType; END;
RETURN ot.parent.typecode;
END Supertype;
PROCEDURE IsTraced (tc: Typecode): BOOLEAN =
VAR t := Get (tc);
BEGIN
RETURN (t.traced # 0);
END IsTraced;
PROCEDURE Get (tc: Typecode): RT0.TypeDefn =
VAR p: SlotPtr := types.map + tc * ADRSIZE (InfoPtr);
BEGIN
IF (tc >= types.cnt) THEN
<*NOWARN*> EVAL VAL (-1, CARDINAL); (* force a range fault *)
ELSIF (p^ = NIL) THEN
Fail (RTE.MissingType, NIL, NIL, NIL);
END;
RETURN p^.def;
END Get;
PROCEDURE GetNDimensions (tc: Typecode): CARDINAL =
VAR t := Get (tc);
BEGIN
IF (t.kind = ORD (TK.Array))
THEN RETURN LOOPHOLE (t, RT0.ArrayTypeDefn).nDimensions;
ELSE RETURN 0;
END;
END GetNDimensions;
PROCEDURE TypeName (ref: REFANY): TEXT =
VAR t := Get (TYPECODE (ref));
BEGIN
RETURN TypeDefnToName (t);
END TypeName;
PROCEDURE TypecodeName (tc: Typecode): TEXT =
VAR t := Get (tc);
BEGIN
RETURN TypeDefnToName (t);
END TypecodeName;
PROCEDURE TypeDefnToName (t: RT0.TypeDefn): TEXT =
BEGIN
IF (t.name = NIL) THEN RETURN "<anon type>"; END;
RETURN M3toC.CopyStoT (LOOPHOLE (t.name, Ctypes.char_star));
END TypeDefnToName;
--------------------------------------------------------------- RTHooks ---
PROCEDURE CheckIsType (ref: REFANY; type: ADDRESS(*RT0.TypeDefn*)): INTEGER =
BEGIN
RETURN ORD (IsSubtype (TYPECODE (ref),
LOOPHOLE (type, RT0.TypeDefn).typecode));
END CheckIsType;
PROCEDURE ScanTypecase (ref: REFANY;
x: ADDRESS(*ARRAY [0..] OF Cell*)): INTEGER =
VAR p: UNTRACED REF TypecaseCell; i: INTEGER; tc, xc: Typecode;
BEGIN
IF (ref = NIL) THEN RETURN 0; END;
tc := TYPECODE (ref);
p := x; i := 0;
LOOP
IF (p.uid = 0) THEN RETURN i; END;
IF (p.defn = NIL) THEN
p.defn := FindType (p.uid);
IF (p.defn = NIL) THEN
Fail (RTE.MissingType, RTModule.FromDataAddress(x),
LOOPHOLE (p.uid, ADDRESS), NIL);
END;
END;
xc := LOOPHOLE (p.defn, RT0.TypeDefn).typecode;
IF (tc = xc) OR IsSubtype (tc, xc) THEN RETURN i; END;
INC (p, ADRSIZE (p^)); INC (i);
END;
END ScanTypecase;
--------------------------------------------------- UID -> typecell map ---
PROCEDURE FindType (id: INTEGER): RT0.TypeDefn =
VAR pi := FindSlot (uids, id, NIL); def: RT0.TypeDefn;
BEGIN
IF (pi^ = NIL) THEN RETURN NIL; END;
def := pi^.def;
IF (def = NIL) THEN RETURN NIL; END;
IF (def.link_state = 0) THEN FinishTypecell (def, pi^.module); END;
RETURN def;
END FindType;
------------------------------------------------- brand -> typecell map ---
PROCEDURE NoteBrand (info: InfoPtr) =
VAR pi := FindSlot (brands, HashBrand (info.def.brand_ptr), info);
BEGIN
IF (pi^ = NIL) THEN
(* it's a new brand, record the new entry *)
pi^ := info; INC (brands.cnt);
ELSE
Fail (RTE.DuplicateBrand, info.module, info.def, pi^.def);
END;
END NoteBrand;
-------------------------------------------------------- initialization ---
PROCEDURE AddTypecell (def: RT0.TypeDefn; m: RT0.ModulePtr) =
VAR pi := FindSlot (uids, def.selfID, NIL); in: InfoPtr;
BEGIN
IF (pi^ = NIL) THEN
(* this is a new type *)
in := NewInfo (def, m, 0);
pi^ := in; INC (uids.cnt); (* record him in the UID map *)
AssignTypecode (in);
IF (def.brand_ptr # NIL) THEN NoteBrand (in); END;
ELSIF (pi^.def = NIL) THEN
(* this is the first typecell for this UID *)
pi^.def := def;
pi^.module := m;
AssignTypecode (pi^);
IF (def.brand_ptr # NIL) THEN NoteBrand (pi^); END;
ELSE
(* this is a duplicate typecell *)
NoteDuplicate (pi^, def, m);
END;
END AddTypecell;
PROCEDURE NoteDuplicate (in: InfoPtr; new: RT0.TypeDefn;
new_mod: RT0.ModulePtr) =
VAR old := in.def;
BEGIN
IF (in.module = NIL) THEN in.module := new_mod; END;
new.next := old.next; old.next := new;
IF (old.name = NIL) THEN old.name := new.name; END;
IF (new.brand_ptr # NIL) THEN
Fail (RTE.DuplicateBrand, new_mod, new, old);
END;
IF (old.link_state # 0) THEN UpdateCell (old, new); END;
END NoteDuplicate;
PROCEDURE AssignTypecode (in: InfoPtr) =
VAR pi: SlotPtr;
BEGIN
IF (types.cnt = 0) THEN AssignBuiltinTypes (); END;
pi := FindSlot (types, types.cnt, NIL);
<*ASSERT pi^ = NIL*>
in.def.typecode := types.cnt;
pi^ := in; INC (types.cnt);
END AssignTypecode;
PROCEDURE FinishObjectTypes () =
VAR p: SlotPtr := types.map;
BEGIN
FOR i := 0 TO types.cnt-1 DO
IF (p^ = NIL) THEN
Fail (RTE.MissingType, NIL, NIL, NIL);
ELSIF (p^.def = NIL) THEN
Fail (RTE.MissingType, NIL, NIL, NIL);
ELSIF (p^.def.link_state = 0) THEN
FinishTypecell (p^.def, p^.module);
IF (p^.def.link_state = 0) THEN
Fail (RTE.MissingType, RTModule.FromDataAddress (p^.def), NIL, NIL);
END;
END;
INC (p, ADRSIZE (p^));
END;
END FinishObjectTypes;
PROCEDURE FinishTypecell (def: RT0.TypeDefn; m: RT0.ModulePtr) =
VAR
odef, t, u: RT0.ObjectTypeDefn;
a: UNTRACED REF ADDRESS;
BEGIN
IF (def.link_state # 0) THEN RETURN; END;
IF (def.kind = ORD (TK.Obj)) THEN
(* finish the object definition, if possible *)
odef := LOOPHOLE (def, RT0.ObjectTypeDefn);
IF (odef.parent = NIL) THEN
odef.parent := FindType (odef.parentID);
IF (odef.parent = NIL) THEN
(* we still can't finish this guy yet! *)
RETURN;
END;
(* check for a cycle in the parent links *)
t := odef; u := odef;
WHILE (u # NIL) AND (t # NIL) DO
t := LOOPHOLE (t.parent, RT0.ObjectTypeDefn);
IF (t = NIL) OR (t.common.kind # ORD (TK.Obj)) THEN EXIT; END;
u := LOOPHOLE (u.parent, RT0.ObjectTypeDefn);
IF (u = NIL) OR (u.common.kind # ORD (TK.Obj)) THEN EXIT; END;
u := LOOPHOLE (u.parent, RT0.ObjectTypeDefn);
IF (u = NIL) OR (u.common.kind # ORD (TK.Obj)) THEN EXIT; END;
IF (t = u) THEN
IF (m = NIL) THEN m := RTModule.FromDataAddress (def); END;
Fail (RTE.SupertypeCycle, m, odef, NIL);
RETURN;
END;
END;
END;
IF (odef.parent # NIL) THEN
IF (odef.parent.link_state = 0) THEN
FinishTypecell (odef.parent, NIL);
IF (odef.parent.link_state = 0) THEN
(* we still can't finish this guy yet! *)
RETURN;
END;
END;
END;
IF (odef.parent # NIL) AND (odef.dataOffset = 0) THEN
t := LOOPHOLE (odef.parent, RT0.ObjectTypeDefn);
IF (t.common.kind # ORD (TK.Obj)) THEN
odef.dataOffset := ADRSIZE (ADDRESS);
odef.methodOffset := 0;
ELSE
odef.dataOffset := RTMisc.Upper (t.common.dataSize, def.dataAlignment);
INC (def.dataSize, odef.dataOffset);
def.dataAlignment := MAX (def.dataAlignment, t.common.dataAlignment);
odef.methodOffset := t.methodSize;
INC (odef.methodSize, odef.methodOffset);
END;
END;
(* allocate my default method list *)
IF (odef.methodSize > 0) AND (odef.defaultMethods = NIL) THEN
odef.defaultMethods := Cstdlib.calloc (1, odef.methodSize);
IF odef.defaultMethods = NIL THEN
Fail (RTE.OutOfMemory, m, odef, NIL);
END;
(* initialize my method suite from my parent *)
IF (t.common.kind = ORD (TK.Obj)) AND (t.defaultMethods # NIL) THEN
RTMisc.Copy (t.defaultMethods, odef.defaultMethods, t.methodSize);
END;
(* call the link proc to fill in any other methods... *)
IF (odef.linkProc # NIL) THEN odef.linkProc (def); END;
END;
(* initialize any remaining methods to the undefined procedure *)
IF (odef.methodSize > 0) THEN
a := odef.defaultMethods;
FOR j := 0 TO odef.methodSize DIV BYTESIZE (ADDRESS) - 1 DO
IF (a^ = NIL) THEN a^ := LOOPHOLE (UndefinedMethod, ADDRESS) END;
INC (a, ADRSIZE (a^));
END;
END;
END;
(* everybody gets a size that's a multiple of a header word *)
def.dataSize := RTMisc.Upper (def.dataSize, BYTESIZE (RTHeapRep.Header));
(* check that all data alignments are small powers of two so that
| "RTMisc.Align (addr, alignment)"
can be safely replaced by
| "addr + align [Word.And (addr, 7), alignment]"
in "RTHeapRep.AllocTraced".*)
IF (def.dataAlignment # 4) AND (def.dataAlignment # 8)
AND (def.dataAlignment # 1) AND (def.dataAlignment # 2) THEN
IF (m = NIL) THEN m := RTModule.FromDataAddress (m); END;
Fail (RTE.ValueOutOfRange, m, def, NIL);
END;
(* ensure that any equivalent typecells are also "finished" *)
VAR d: RT0.TypeDefn := def; BEGIN
WHILE (d.next # NIL) DO d := d.next; UpdateCell (def, d); END;
END;
def.link_state := 1;
END FinishTypecell;
PROCEDURE UpdateCell (old, new: RT0.TypeDefn) =
(* make sure any computed information is copied into the new cell *)
BEGIN
new.typecode := old.typecode;
new.link_state := old.link_state;
new.dataAlignment := old.dataAlignment;
new.dataSize := old.dataSize;
IF (new.kind = ORD (TK.Obj)) THEN
VAR
onew := LOOPHOLE (new, RT0.ObjectTypeDefn);
oold := LOOPHOLE (old, RT0.ObjectTypeDefn);
BEGIN
onew.dataOffset := oold.dataOffset;
onew.methodOffset := oold.methodOffset;
onew.methodSize := oold.methodSize;
onew.defaultMethods := oold.defaultMethods;
onew.parent := oold.parent;
END;
END;
END UpdateCell;
PROCEDURE ResolveTypeLink (uid: INTEGER; t: RT0.TypeLinkPtr; m: RT0.ModulePtr) =
VAR pi := FindSlot (uids, uid, NIL);
BEGIN
IF (pi^ = NIL) OR (pi^.def = NIL) THEN
Fail (RTE.MissingType, m, LOOPHOLE (uid, ADDRESS), NIL);
ELSE
t.defn := pi^.def;
t.typecode := pi^.def.typecode;
END;
END ResolveTypeLink;
PROCEDURE NoteFullRevelation (r: RT0.RevPtr; m: RT0.ModulePtr) =
VAR rhs, lhs: InfoPtr; p_rhs, p_lhs: SlotPtr; old_tc: INTEGER;
BEGIN
p_rhs := FindSlot (uids, r.rhs_id, NIL); rhs := NIL;
p_lhs := FindSlot (uids, r.lhs_id, NIL); lhs := NIL;
IF (p_rhs^ # NIL) THEN rhs := p_rhs^; END;
IF (p_lhs^ # NIL) THEN lhs := p_lhs^; END;
IF (rhs = NIL) OR (rhs.def = NIL) THEN
Fail (RTE.MissingType, m, LOOPHOLE (r.rhs_id, ADDRESS), NIL);
END;
IF (lhs = NIL) THEN
p_lhs^ := rhs; INC (uids.cnt); (* ok, remember the binding *)
IF (rhs.opaqueID # 0) AND (rhs.opaqueID # r.lhs_id) THEN
Fail (RTE.OpaqueTypeRedefined, m, LOOPHOLE (r.lhs_id, ADDRESS),
LOOPHOLE (r.rhs_id, ADDRESS));
END;
rhs.opaqueID := r.lhs_id;
ELSIF (lhs = rhs) THEN
(* ok, the two types are already identified *)
ELSIF (r.lhs_id = RT0.TextLiteralID) AND (lhs.def = NIL) THEN
(* steal the RHS typecell for the opaque type *)
old_tc := rhs.def.typecode;
rhs.def.typecode := RT0.TextLitTypecode;
rhs.opaqueID := RT0.TextLiteralID;
p_lhs^ := rhs; (* fix the UID mapping *)
(* fix the old RHS typecode to use the LHS info & a dummy typecell *)
p_lhs := types.map + old_tc * ADRSIZE (InfoPtr);
p_lhs^ := lhs;
lhs.def := ADR (Dummy1_typecell);
lhs.def.typecode := old_tc;
lhs.opaqueID := 0;
(* fix the LHS typecode to use the new RHS info *)
p_lhs := types.map + RT0.TextLitTypecode * ADRSIZE (InfoPtr);
p_lhs^ := rhs;
ELSIF (r.lhs_id = RT0.MutexID) AND (lhs.def = NIL) THEN
(* steal the RHS typecell for the opaque type *)
old_tc := rhs.def.typecode;
rhs.def.typecode := RT0.MutexTypecode;
rhs.opaqueID := RT0.MutexID;
p_lhs^ := rhs; (* fix the UID mapping *)
(* fix the old RHS typecode to use the LHS info & a dummy typecell *)
p_lhs := types.map + old_tc * ADRSIZE (InfoPtr);
p_lhs^ := lhs;
lhs.def := ADR (Dummy3_typecell);
lhs.def.typecode := old_tc;
lhs.opaqueID := 0;
(* fix the LHS typecode to use the new RHS info *)
p_lhs := types.map + RT0.MutexTypecode * ADRSIZE (InfoPtr);
p_lhs^ := rhs;
ELSE
Fail (RTE.OpaqueTypeRedefined, m, LOOPHOLE (r.lhs_id, ADDRESS),
LOOPHOLE (r.rhs_id, ADDRESS));
END;
END NoteFullRevelation;
PROCEDURE VerifyPartialRevelation (r: RT0.RevPtr; m: RT0.ModulePtr) =
VAR rhs, lhs: InfoPtr; p_rhs, p_lhs: SlotPtr;
BEGIN
p_rhs := FindSlot (uids, r.rhs_id, NIL); rhs := NIL;
p_lhs := FindSlot (uids, r.lhs_id, NIL); lhs := NIL;
IF (p_rhs^ # NIL) THEN rhs := p_rhs^; END;
IF (p_lhs^ # NIL) THEN lhs := p_lhs^; END;
IF (lhs = NIL) OR (lhs.def = NIL) THEN
Fail (RTE.MissingType, m, LOOPHOLE (r.lhs_id, ADDRESS), NIL);
ELSIF (rhs = NIL) OR (rhs.def = NIL) THEN
Fail (RTE.MissingType, m, LOOPHOLE (r.rhs_id, ADDRESS), NIL);
ELSIF NOT IsSubtype (lhs.def.typecode, rhs.def.typecode) THEN
Fail (RTE.InconsistentRevelation, m, LOOPHOLE (r.lhs_id, ADDRESS),
LOOPHOLE (r.rhs_id, ADDRESS));
END;
END VerifyPartialRevelation;
--------------------------------------------------------- builtin types ---
PROCEDURE AssignBuiltinTypes () =
BEGIN
GenOpaque (RT0.TextLiteralID, RT0.TextLitTypecode);
GenOpaque (RT0.MutexID, RT0.MutexTypecode);
GenBuiltin (ADR (NULL_typecell), "NULL");
GenBuiltin (ADR (REFANY_typecell), "REFANY");
GenBuiltin (ADR (ADDRESS_typecell), "ADDRESS");
GenBuiltin (ADR (ROOT_typecell.common), "ROOT");
GenBuiltin (ADR (UNROOT_typecell.common), "UNTRACED ROOT");
types.cnt := MAX (types.cnt, RT0.FirstUserTypecode);
END AssignBuiltinTypes;
PROCEDURE GenBuiltin (def: RT0.TypeDefn; nm: TEXT) =
VAR pi: SlotPtr; in := NewInfo (def, NIL, 0);
BEGIN
def.name := LOOPHOLE (M3toC.FlatTtoS (nm), RT0.String);
pi := FindSlot (uids, def.selfID, NIL);
<*ASSERT pi^ = NIL*>
pi^ := in; INC (uids.cnt);
pi := FindSlot (types, def.typecode, NIL);
<*ASSERT pi^ = NIL*>
pi^ := in; INC (types.cnt);
END GenBuiltin;
PROCEDURE GenOpaque (uid: INTEGER; typecode: INTEGER) =
VAR pi: SlotPtr; in := NewInfo (NIL, NIL, uid);
BEGIN
pi := FindSlot (uids, uid, NIL);
<*ASSERT pi^ = NIL*>
pi^ := in; INC (uids.cnt);
pi := FindSlot (types, typecode, NIL);
<*ASSERT pi^ = NIL*>
pi^ := in; INC (types.cnt);
END GenOpaque;
VAR
Dummy1_typecell := RT0.Typecell {
typecode := 0,
selfID := -1,
fp := RT0.Fingerprint {16_ff, 16_ff, 16_ff, 16_ff,
16_ff, 16_ff, 16_ff, 16_ff},
traced := 0,
kind := ORD (TK.Ref),
link_state := 0,
dataAlignment := 1,
dataSize := 0,
type_map := NIL,
gc_map := NIL,
type_desc := NIL,
initProc := NIL,
brand_ptr := NIL,
name := NIL,
next := NIL
};
Dummy3_typecell := RT0.Typecell {
typecode := 0,
selfID := -3,
fp := RT0.Fingerprint {16_fd, 16_ff, 16_ff, 16_ff,
16_fd, 16_ff, 16_ff, 16_ff},
traced := 0,
kind := ORD (TK.Ref),
link_state := 0,
dataAlignment := 1,
dataSize := 0,
type_map := NIL,
gc_map := NIL,
type_desc := NIL,
initProc := NIL,
brand_ptr := NIL,
name := NIL,
next := NIL
};
FP ($null
) ==> 16_248000006c6c756e => 16_48ec756e = 1223456110
VAR
NULL_typecell := RT0.Typecell {
typecode := RT0.NilTypecode,
selfID := 16_48ec756e,
fp := RT0.Fingerprint {16_6e, 16_75, 16_6c, 16_6c,
16_00, 16_00, 16_80, 16_24},
traced := 0,
kind := ORD (TK.Ref),
link_state := 0,
dataAlignment := 1,
dataSize := 0,
type_map := NIL,
gc_map := NIL,
type_desc := NIL,
initProc := NIL,
brand_ptr := NIL,
name := NIL,
next := NIL
};
FP ($objectadr
) ==> 16_f80919c87187be41 => 16_898ea789 = -1987139703
VAR
UNROOT_typecell := RT0.ObjectTypecell {
common := RT0.Typecell {
typecode := RT0.UnRootTypecode,
selfID := -1987139703,
fp := RT0.Fingerprint {16_41, 16_be, 16_87, 16_71,
16_c8, 16_19, 16_09, 16_f8},
traced := 0,
kind := ORD (TK.Obj),
link_state := 0,
dataAlignment := BYTESIZE (ADDRESS),
dataSize := BYTESIZE (ADDRESS),
type_map := NIL,
gc_map := NIL,
type_desc := NIL,
initProc := NIL,
brand_ptr := NIL,
name := NIL,
next := NIL },
parentID := ADDRESS_uid,
linkProc := NIL,
dataOffset := ADRSIZE (ADDRESS),
methodOffset := 0,
methodSize := 0,
defaultMethods:= NIL,
parent := NIL
};
FP ($objectref
) ==> 16_f80919c86586ad41 => 16_9d8fb489 = -1651526519
VAR
ROOT_typecell := RT0.ObjectTypecell {
common := RT0.Typecell {
typecode := RT0.RootTypecode,
selfID := -1651526519,
fp := RT0.Fingerprint {16_41, 16_ad, 16_86, 16_65,
16_c8, 16_19, 16_09, 16_f8},
traced := 1,
kind := ORD (TK.Obj),
link_state := 0,
dataAlignment := BYTESIZE (ADDRESS),
dataSize := BYTESIZE (ADDRESS),
type_map := NIL,
gc_map := NIL,
type_desc := NIL,
initProc := NIL,
brand_ptr := NIL,
name := NIL,
next := NIL },
parentID := REFANY_uid,
linkProc := NIL,
dataOffset := ADRSIZE (ADDRESS),
methodOffset := 0,
methodSize := 0,
defaultMethods:= NIL,
parent := NIL
};
FP ($refany
) ==> 16_65722480796e6166 => 16_1c1c45e6 = 471614950
CONST
REFANY_uid = 16_1c1c45e6;
VAR
REFANY_typecell := RT0.Typecell {
typecode := RT0.RefanyTypecode,
selfID := REFANY_uid,
fp := RT0.Fingerprint {16_66, 16_61, 16_6e, 16_79,
16_80, 16_24, 16_72, 16_65},
traced := 1,
kind := ORD (TK.Ref),
link_state := 0,
dataAlignment := BYTESIZE (ADDRESS),
dataSize := BYTESIZE (ADDRESS),
type_map := NIL,
gc_map := NIL,
type_desc := NIL,
initProc := NIL,
brand_ptr := NIL,
name := NIL,
next := NIL
};
FP ($address
) ==> 16_628a21916aca01f2 => 16_8402063 = 138420323
CONST
ADDRESS_uid = 138420323;
VAR
ADDRESS_typecell := RT0.Typecell {
typecode := RT0.AddressTypecode,
selfID := ADDRESS_uid,
fp := RT0.Fingerprint {16_f2, 16_01, 16_ca, 16_6a,
16_91, 16_21, 16_8a, 16_62},
traced := 0,
kind := ORD (TK.Ref),
link_state := 0,
dataAlignment := BYTESIZE (ADDRESS),
dataSize := BYTESIZE (ADDRESS),
type_map := NIL,
gc_map := NIL,
type_desc := NIL,
initProc := NIL,
brand_ptr := NIL,
name := NIL,
next := NIL
};
----------------------------------------------------------- Info cells ---
CONST
InfoChunk = 512;
TYPE
InfoVec = UNTRACED REF ARRAY [0..InfoChunk-1] OF Info;
VAR
n_info : CARDINAL := InfoChunk;
info_pool : InfoVec := NIL;
PROCEDURE NewInfo (def: RT0.TypeDefn; m: RT0.ModulePtr; uid: INTEGER): InfoPtr =
VAR p: InfoPtr;
BEGIN
IF (n_info >= InfoChunk) THEN
info_pool := Cstdlib.calloc (InfoChunk, BYTESIZE (Info));
IF info_pool = NIL THEN
Fail (RTE.OutOfMemory, m, def, NIL);
END;
n_info := 0;
END;
p := info_pool + n_info * ADRSIZE (Info);
INC (n_info);
p.def := def;
p.module := m;
p.opaqueID := uid;
RETURN p;
END NewInfo;
---------------------------------------------------- key->InfoPtr maps ---
TYPE
SlotPtr = UNTRACED REF InfoPtr;
InfoMap = RECORD
name : TEXT;
is_equal : PROCEDURE (key: INTEGER; aux: ADDRESS; info: InfoPtr): BOOLEAN;
rehash : PROCEDURE (info: InfoPtr; VAR key1, key2: INTEGER);
initial_size : CARDINAL;
full : CARDINAL;
cnt : CARDINAL := 0;
max : CARDINAL := 0; (* must be a power of two! *)
mask : INTEGER := 0;
map : ADDRESS := NIL; (* UNTRACED REF ARRAY [0..max-1] OF InfoPtr *)
END;
PROCEDURE FindSlot (VAR m: InfoMap; key: INTEGER; aux: ADDRESS): SlotPtr =
VAR x: INTEGER; pi: SlotPtr;
BEGIN
IF (m.map = NIL) OR (m.cnt >= m.full) THEN Expand (m); END;
x := Word.And (m.mask, key);
pi := m.map + x * ADRSIZE (InfoPtr);
LOOP
IF (pi^ = NIL) OR m.is_equal (key, aux, pi^) THEN
(* we found an empty slot or a match *)
RETURN pi;
END;
INC (x); INC (pi, ADRSIZE (pi^));
IF (x >= m.max) THEN x := 0; pi := m.map; END;
END;
END FindSlot;
PROCEDURE Expand (VAR m: InfoMap) =
CONST NOKEY = FIRST(INTEGER);
VAR
new : InfoMap;
pi, pt: SlotPtr;
key1, key2: INTEGER;
BEGIN
IF m.map = NIL THEN
(* First time... *)
m.cnt := 0;
m.max := m.initial_size; (* must be a power of two *)
m.mask := m.max - 1;
m.map := Cstdlib.calloc (m.max, BYTESIZE (InfoPtr));
IF m.map = NIL THEN
Fail (RTE.OutOfMemory, NIL, NIL, NIL);
END;
ELSE
new := m;
new.cnt := 0;
new.full := m.full + m.full;
new.max := m.max + m.max;
new.mask := new.max - 1;
new.map := Cstdlib.calloc (new.max, BYTESIZE (InfoPtr));
IF new.map = NIL THEN
Fail (RTE.OutOfMemory, NIL, NIL, NIL);
END;
(* re-insert the existing elements *)
pi := m.map;
FOR i := 0 TO m.max-1 DO
IF (pi^ # NIL) THEN
key1 := NOKEY; key2 := NOKEY;
m.rehash (pi^, key1, key2);
IF (key1 # NOKEY) THEN
pt := FindSlot (new, key1, pi^);
IF (pt^ = NIL) THEN pt^ := pi^; INC (new.cnt); END;
END;
IF (key2 # NOKEY) THEN
pt := FindSlot (new, key2, pi^);
IF (pt^ = NIL) THEN pt^ := pi^; INC (new.cnt); END;
END;
END;
INC (pi, ADRSIZE (pi^));
END;
(* free the old map and reset it to the new one *)
Cstdlib.free (m.map);
m := new;
END;
END Expand;
PROCEDURE TypecodeEq (key: INTEGER; <*UNUSED*>aux: ADDRESS;
info: InfoPtr): BOOLEAN =
BEGIN
RETURN info.def.typecode = key;
END TypecodeEq;
PROCEDURE TypecodeRehash (info: InfoPtr; VAR key1: INTEGER;
<*UNUSED*>VAR key2: INTEGER) =
BEGIN
key1 := info.def.typecode;
END TypecodeRehash;
PROCEDURE UIDEq (key: INTEGER; <*UNUSED*>aux: ADDRESS;
info: InfoPtr): BOOLEAN =
BEGIN
RETURN (info.opaqueID = key)
OR ((info.def # NIL) AND (info.def.selfID = key));
END UIDEq;
PROCEDURE UIDRehash (info: InfoPtr; VAR key1, key2: INTEGER) =
BEGIN
IF (info.def # NIL) THEN key1 := info.def.selfID; END;
IF (info.opaqueID # 0) THEN key2 := info.opaqueID; END;
END UIDRehash;
PROCEDURE BrandEq (<*UNUSED*> key: INTEGER; aux: ADDRESS;
info: InfoPtr): BOOLEAN =
VAR
x: RT0.BrandPtr := LOOPHOLE (aux, InfoPtr).def.brand_ptr;
y: RT0.BrandPtr;
BEGIN
IF (info.def = NIL) OR (info.def.brand_ptr = NIL) THEN RETURN FALSE; END;
y := info.def.brand_ptr;
RETURN (x.length = y.length)
AND Cstring.memcmp (ADR(x.chars[0]), ADR(y.chars[0]), x.length) = 0;
END BrandEq;
PROCEDURE BrandRehash (info: InfoPtr; VAR key1: INTEGER;
<*UNUSED*>VAR key2: INTEGER) =
BEGIN
IF (info.def # NIL) AND (info.def.brand_ptr # NIL) THEN
key1 := HashBrand (info.def.brand_ptr);
END;
END BrandRehash;
PROCEDURE HashBrand (b: RT0.BrandPtr): INTEGER =
VAR
hash : INTEGER := 0;
len : INTEGER := b.length;
cp : UNTRACED REF CHAR := ADR (b.chars[0]);
BEGIN
WHILE (len > 0) DO
hash := Word.Plus (Word.LeftShift (hash, 1), ORD (cp^));
INC (cp, BYTESIZE (cp^)); DEC (len);
END;
RETURN hash;
END HashBrand;
-------------------------------------------------------- runtime errors ---
PROCEDURE UndefinedMethod (self: REFANY) =
VAR
tc : INTEGER := TYPECODE (self);
info : InfoPtr := types.map + tc * ADRSIZE (Info);
def : RT0.TypeDefn := NIL;
m : RT0.ModulePtr := NIL;
BEGIN
IF (tc < types.cnt) AND (info # NIL) THEN
def := info.def;
m := info.module;
END;
Fail (RTE.UndefinedMethod, m, def, NIL);
END UndefinedMethod;
PROCEDURE Fail (rte: RTE; m: RT0.ModulePtr; x, y: ADDRESS) =
<*FATAL ANY*>
VAR a: RT0.RaiseActivation;
BEGIN
a.exception := RuntimeError.Self ();
a.arg := LOOPHOLE (ORD (rte), RT0.ExceptionArg);
a.module := m;
a.line := 0;
a.pc := NIL;
a.info0 := x;
a.info1 := y;
a.un_except := NIL;
a.un_arg := NIL;
RTException.Raise (a);
END Fail;
BEGIN
END RTType.