RTTCacheImpl:
CEDAR
MONITOR
IMPORTS Rope
EXPORTS RTTCache
= BEGIN OPEN Rope, RTTCache, SafeStorage;
InvalidIndex: PUBLIC ERROR = CODE;
HashSize: CARDINAL = 256;
HashRange: TYPE = CARDINAL [0..HashSize);
intCache: IntCache ← NEW[IntCacheRep];
IntCache: TYPE = REF IntCacheRep;
IntCacheRep:
TYPE =
RECORD [
enabled: BOOL ← TRUE,
probes, misses, filled: INT ← 0,
hashVec: ARRAY HashRange OF IntEntry];
refCache: RefCache ← NEW[RefCacheRep];
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] = {
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 ← 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] = {
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] = {
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] = {
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 ← 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] = {
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] = {
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 ← 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] = {
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] = {
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[];
};