-- RTTCacheImpl.mesa
-- Russ Atkinson, June 28, 1982 1:32 pm
DIRECTORY
Rope USING [Equal, ROPE],
RTBasic USING [nullType, Type],
RTTCache,
SafeStorage USING [NewZone];
RTTCacheImpl: CEDAR MONITOR
IMPORTS Rope, SafeStorage
EXPORTS RTTCache
= BEGIN OPEN Rope, RTBasic, RTTCache;
InvalidIndex: PUBLIC ERROR = CODE;
HashSize: CARDINAL = 256;
HashRange: TYPE = CARDINAL [0..HashSize);
IntCache: TYPE = REF IntCacheRep;
IntCacheRep: TYPE = RECORD
[enabled: BOOL ← TRUE,
probes, misses, filled: INT ← 0,
hashVec: ARRAY HashRange OF IntEntry];
RefCache: TYPE = REF RefCacheRep;
RefCacheRep: TYPE = RECORD
[enabled: BOOL ← TRUE,
probes, misses, filled: INT ← 0,
hashVec: ARRAY HashRange OF RefEntry];
Hash: PROC [type: Type, proc: ProcKey] RETURNS [HashRange] = {
RETURN [(LOOPHOLE[type, CARDINAL] + LOOPHOLE[proc, CARDINAL])
MOD HashSize];
};
LookupInt: PUBLIC ENTRY PROC
[type: Type, proc: ProcKey] RETURNS [entry: IntEntry] = {
-- comment
ENABLE UNWIND => NULL;
hash: HashRange ← Hash[type, proc];
intCache.probes ← intCache.probes + 1;
FOR entry ← intCache.hashVec[hash], entry.next WHILE entry # NIL DO
IF entry.type = type AND entry.proc = proc THEN RETURN;
ENDLOOP;
entry ← pz.NEW[IntEntryRep ← [next: intCache.hashVec[hash], type: type, proc: proc]];
intCache.hashVec[hash] ← entry;
intCache.misses ← intCache.misses + 1;
};
FillIntEntry: PUBLIC ENTRY PROC
[entry: IntEntry, value: INT] RETURNS [alreadyFull: BOOL] = {
-- comment
ENABLE UNWIND => NULL;
IF NOT intCache.enabled THEN RETURN [TRUE];
IF entry.valid THEN RETURN [TRUE];
entry.int ← value;
entry.valid ← TRUE;
intCache.filled ← intCache.filled + 1;
RETURN [FALSE];
};
ClearIntEntry: PUBLIC ENTRY PROC [entry: IntEntry] = {
-- comment
ENABLE UNWIND => NULL;
IF NOT entry.valid THEN RETURN;
entry.int ← -1;
entry.valid ← FALSE;
intCache.filled ← intCache.filled - 1;
};
GetInt: PUBLIC ENTRY PROC [entry: IntEntry] RETURNS [value: INT, valid: BOOL] = {
-- atomically retrieves the value in the entry
RETURN [entry.int, entry.valid];
};
LookupRef: PUBLIC ENTRY PROC
[type: Type, proc: ProcKey] RETURNS [entry: RefEntry] = {
-- comment
ENABLE UNWIND => NULL;
hash: HashRange ← Hash[type, proc];
refCache.probes ← refCache.probes + 1;
FOR entry ← refCache.hashVec[hash], entry.next WHILE entry # NIL DO
IF entry.type = type AND entry.proc = proc THEN RETURN;
ENDLOOP;
entry ← pz.NEW[RefEntryRep ← [next: refCache.hashVec[hash], type: type, proc: proc]];
refCache.hashVec[hash] ← entry;
refCache.misses ← refCache.misses + 1;
};
FillRefEntry: PUBLIC ENTRY PROC
[entry: RefEntry, value: REF] RETURNS [alreadyFull: BOOL] = {
-- comment
ENABLE UNWIND => NULL;
IF NOT refCache.enabled THEN RETURN [TRUE];
IF entry.valid THEN RETURN [TRUE];
entry.ref ← value;
entry.valid ← TRUE;
refCache.filled ← refCache.filled + 1;
RETURN [FALSE];
};
ClearRefEntry: PUBLIC ENTRY PROC [entry: RefEntry] = {
-- comment
ENABLE UNWIND => NULL;
IF NOT entry.valid THEN RETURN;
entry.ref ← NIL;
entry.valid ← FALSE;
refCache.filled ← refCache.filled - 1;
};
GetRef: PUBLIC ENTRY PROC [entry: RefEntry] RETURNS [value: REF, valid: BOOL] = {
-- atomically retrieves the value in the entry
RETURN [entry.ref, entry.valid];
};
GetStats: PUBLIC ENTRY PROC
RETURNS [intProbes, intMisses, intFilled, refProbes, refMisses, refFilled: INT] = {
ENABLE UNWIND => NULL;
RETURN [intCache.probes, intCache.misses, intCache.filled,
refCache.probes, refCache.misses, refCache.filled];
};
NewComponentMap: PUBLIC PROC [len: NAT] RETURNS [map: ComponentMap] = {
map ← pz.NEW[ComponentMapRep[len]];
FOR i: NAT IN [0..len) DO
map[i] ← NullComponentEntry;
ENDLOOP;
};
FillNameComponent: PUBLIC ENTRY PROC
[map: ComponentMap, index: INT, name: ROPE] RETURNS [alreadyFull: BOOL] = {
-- comment
ENABLE UNWIND => NULL;
x: NAT ← 0;
IF index < 0 OR index >= map.len THEN RETURN WITH ERROR InvalidIndex;
x ← index;
IF map[x].validName THEN RETURN [TRUE];
map[x].name ← name;
map[x].validName ← TRUE;
map.filledNames ← map.filledNames + 1;
RETURN [FALSE];
};
FillTypeComponent: PUBLIC ENTRY PROC
[map: ComponentMap, index: INT, type: Type] RETURNS [alreadyFull: BOOL] = {
-- comment
ENABLE UNWIND => NULL;
x: NAT ← 0;
IF index < 0 OR index >= map.len THEN RETURN WITH ERROR InvalidIndex;
x ← index;
IF map[x].validType THEN RETURN [TRUE];
map[x].type ← type;
map[x].validType ← TRUE;
map.filledTypes ← map.filledTypes + 1;
RETURN [FALSE];
};
GetComponentAtIndex: PUBLIC ENTRY PROC
[map: ComponentMap, index: INT] RETURNS [comp: ComponentEntry] = {
-- atomically returns the given component entry
-- will ERROR InvalidIndex if index NOT IN [0..map.len)
ENABLE UNWIND => NULL;
IF index NOT IN [0..map.len) THEN RETURN WITH ERROR InvalidIndex;
RETURN [map[index]];
};
GetComponentForName: PUBLIC ENTRY PROC
[map: ComponentMap, name: ROPE, case: BOOL ← TRUE]
RETURNS [index: INT, comp: ComponentEntry] = {
-- atomically returns the given component entry for the given name
-- IF case = TRUE, then name search is case-sensitive (Rope convention)
-- will return [-1, NullComponentEntry] if no such name
ENABLE UNWIND => NULL;
FOR i: NAT IN [0..map.len) DO
comp: ComponentEntry ← map[i];
IF Rope.Equal[name, comp.name, case] THEN
RETURN [i, comp];
ENDLOOP;
RETURN [-1, NullComponentEntry];
};
-- internal procs for flushing the cache
DisableAndFlushIntCache: ENTRY PROC = {
ENABLE UNWIND => NULL;
intCache.enabled ← FALSE;
intCache.probes ← intCache.misses ← intCache.filled ← 0;
FOR i: HashRange IN HashRange DO
FOR list: IntEntry ← intCache.hashVec[i], list.next UNTIL list = NIL DO
list.valid ← FALSE;
list.int ← -1;
ENDLOOP;
ENDLOOP;
};
DisableAndFlushRefCache: ENTRY PROC = {
ENABLE UNWIND => NULL;
refCache.enabled ← FALSE;
refCache.probes ← refCache.misses ← refCache.filled ← 0;
FOR i: HashRange IN HashRange DO
FOR list: RefEntry ← refCache.hashVec[i], list.next UNTIL list = NIL DO
list.valid ← FALSE;
list.ref ← NIL;
ENDLOOP;
ENDLOOP;
};
DisableAndFlushAllCaches: PROC = {
DisableAndFlushIntCache[];
DisableAndFlushRefCache[];
};
pz: ZONE;
intCache: IntCache;
refCache: RefCache;
TRUSTED {pz ← SafeStorage.NewZone[prefixed]};
intCache ← pz.NEW[IntCacheRep];
refCache ← pz.NEW[RefCacheRep];
END.