SpyBreaksImpl.mesa
Last Edited by: John Maxwell on: April 28, 1983 3:38 pm
DIRECTORY
AMBridge USING [GFHFromTV, TVForGFHReferent],
AMTypes USING [TV, TVToName],
BBObjectLocation
USING [
EntryLocation, ExitLocation, GFandPCFromLocation, IsLocationAtLocation, Location, LocationFromGFandPC, TVFromLocation],
FastBreak USING [ClearFastBreak, FastBreakId, FastBreakProc, SetFastBreak],
IO
USING [
char, Close, CR, CreateOutputStreamToRope,
GetOutputStreamRope, int, Put, rope, STREAM],
PrincOps USING [BytePC, FrameCodeBase, GlobalFrameHandle],
Rope USING [ROPE],
SpyClient USING [], -- for export
SpyOps USING [active, StartCounting, StopCounting, starts, stops, UserBreak, watching];
SpyBreaksImpl:
MONITOR
IMPORTS
AMBridge, AMTypes, BBObjectLocation, FastBreak, IO, SpyOps
EXPORTS SpyClient, SpyOps = BEGIN
OPEN IO;
ROPE: TYPE = Rope.ROPE;
************************************************************
start and stop breaks
************************************************************
breakList: LIST OF Break ← NIL;
totalStarts, totalStops: INTEGER ← 0;
StartSpy:
PUBLIC
PROCEDURE =
BEGIN
SpyOps.starts ← SpyOps.stops ← 0;
IF breakList = NIL THEN [] ← SpyOps.StartCounting[NIL, NIL, NIL];
END;
StopSpy:
PUBLIC
PROCEDURE =
BEGIN
totalStarts ← SpyOps.starts; totalStops ← SpyOps.stops;
WHILE SpyOps.active > 0 DO [] ← SpyOps.StopCounting[NIL, NIL, NIL]; ENDLOOP;
END;
ClearBreaks:
PUBLIC
PROCEDURE =
BEGIN
FOR breakList ← breakList, breakList.rest
DO
IF breakList = NIL THEN EXIT;
[] ← FastBreak.ClearFastBreak[breakList.first.index];
ENDLOOP;
END;
SetStartBreak:
PUBLIC
PROCEDURE[procedure:
ROPE, loc: BBObjectLocation.Location]
RETURNS[ok: BOOLEAN, msg: ROPE] =
BEGIN
breakId: Break;
output: STREAM ← CreateOutputStreamToRope[];
IF loc =
NIL
THEN {
ok ← FALSE;
IF procedure # NIL THEN output.Put[rope["Please use 'loc' parameter."]]
ELSE output.Put[rope["Could not set break."]]}
ELSE {
ok ← TRUE;
breakId ← SetBreak[loc, SpyOps.StartCounting];
IF breakId = NIL THEN RETURN[FALSE, "Could not set break."];
breakList ← CONS[breakId, breakList];
output.Put[rope["Set Start Break "]];
PrintBreak[output, breakId];
output.Put[char['.]]};
msg ← GetOutputStreamRope[output];
output.Close[];
END;
SetStopBreak:
PUBLIC
PROCEDURE[procedure:
ROPE, loc: BBObjectLocation.Location]
RETURNS[ok: BOOLEAN, msg: ROPE] =
BEGIN
OPEN BBObjectLocation;
breakId: Break;
output: STREAM ← CreateOutputStreamToRope[];
IF loc =
NIL
THEN {
ok ← FALSE;
IF procedure # NIL THEN output.Put[rope["Please use 'loc' parameter."]]
ELSE output.Put[rope["Could not set break."]]}
ELSE {
ok ← TRUE;
IF IsLocationAtLocation[loc, EntryLocation[loc]]
THEN loc ← ExitLocation[loc];
breakId ← SetBreak[loc, SpyOps.StopCounting];
IF breakId = NIL THEN RETURN[FALSE, "Could not set break."];
breakList ← CONS[breakId, breakList];
output.Put[rope["Set Stop Break "]];
PrintBreak[output, breakId];
output.Put[char['.]]};
msg ← GetOutputStreamRope[output];
output.Close[];
END;
************************************************************
user breaks
************************************************************
userBreakList: LIST OF Break ← NIL;
SetUserBreak:
PUBLIC
PROCEDURE[procedure:
ROPE, loc: BBObjectLocation.Location]
RETURNS[ok: BOOLEAN, msg: ROPE] =
BEGIN
breakId: Break;
output: STREAM ← CreateOutputStreamToRope[];
IF loc =
NIL
THEN {
ok ← FALSE;
IF procedure # NIL THEN output.Put[rope["Please use 'loc' parameter."]]
ELSE output.Put[rope["Could not set break."]]}
ELSE {
ok ← TRUE;
breakId ← SetBreak[loc, SpyOps.UserBreak];
IF breakId = NIL THEN RETURN[FALSE, "Could not set break."];
userBreakList ← CONS[breakId, userBreakList];
output.Put[rope["Set User Break "]];
PrintBreak[output, breakId];
output.Put[char['.]]};
msg ← GetOutputStreamRope[output];
output.Close[];
END;
ClearUserBreaks:
PUBLIC
PROCEDURE =
BEGIN
FOR userBreakList ← userBreakList, userBreakList.rest
DO
IF userBreakList = NIL THEN EXIT;
[] ← FastBreak.ClearFastBreak[userBreakList.first.index];
ENDLOOP;
END;
************************************************************
utility procedures
************************************************************
Break: TYPE = REF BreakRec;
BreakRec:
TYPE =
RECORD[
index: FastBreak.FastBreakId ← NIL,
condProc: FastBreak.FastBreakProc ← NIL,
loc: BBObjectLocation.Location ← NIL];
SetBreak:
PROC[loc: BBObjectLocation.Location, condProc: FastBreak.FastBreakProc]
RETURNS[break: Break] = BEGIN
gf: AMTypes.TV;
pc: PrincOps.BytePC;
code: PrincOps.FrameCodeBase;
gfh: PrincOps.GlobalFrameHandle;
[gf, pc] ← BBObjectLocation.GFandPCFromLocation[loc];
IF gf = NIL OR pc = 0 THEN RETURN[NIL];
gfh ← AMBridge.GFHFromTV[gf];
code ← gfh.code;
code.out ← FALSE;
break ← NEW[BreakRec ← []];
break.index ← FastBreak.SetFastBreak[LOOPHOLE[code], pc, condProc];
IF break.index = NIL THEN RETURN[NIL];
break.condProc ← condProc;
break.loc ← loc;
END;
PrintBreaks:
PUBLIC
PROCEDURE[typescript:
IO.
STREAM] =
BEGIN
first: BOOLEAN ← TRUE;
list: LIST OF Break;
IF typescript = NIL THEN RETURN;
print user breaks
IF SpyOps.watching = userDefined OR breakList # NIL THEN typescript.Put[char[CR]];
IF SpyOps.watching = userDefined
THEN {
typescript.Put[rope["User Breaks: "]];
FOR list ← userBreakList, list.rest
DO
IF list =
NIL
THEN
EXIT;
IF ~first THEN typescript.Put[rope[", "]];
PrintBreak[typescript, list.first];
first ← FALSE;
ENDLOOP;
typescript.Put[char['.], char[CR]]};
print start and stop breaks
IF breakList #
NIL
THEN {
first ← TRUE;
typescript.Put[rope["Start Breaks: "]];
FOR list ← breakList, list.rest
DO
IF list = NIL THEN EXIT;
IF list.first.condProc # SpyOps.StartCounting THEN LOOP;
IF ~first THEN typescript.Put[rope[", "]];
PrintBreak[typescript, list.first];
first ← FALSE;
ENDLOOP;
IF first
THEN typescript.Put[char[CR]]
ELSE typescript.Put[char['.], char[CR]];
stop breaks
first ← TRUE;
typescript.Put[rope["Stop Breaks: "]];
FOR list ← breakList, list.rest
DO
IF list =
NIL
THEN
EXIT;
IF list.first.condProc # SpyOps.StopCounting THEN LOOP;
IF ~first THEN typescript.Put[rope[", "]];
PrintBreak[typescript, list.first];
first ← FALSE;
ENDLOOP;
IF first
THEN typescript.Put[char[CR]]
ELSE typescript.Put[char['.], char[CR]];
typescript.Put[int[totalStarts], rope[" start breaks encountered.\n"]];
typescript.Put[int[totalStops], rope[" stop breaks encountered.\n"]]};
END;
PrintBreak:
PROCEDURE[stream:
IO.
STREAM, break: Break] =
BEGIN
OPEN BBObjectLocation;
stream.Put[rope["Break # "], int[break.index], rope[" = "]];
SELECT
TRUE
FROM
IsLocationAtLocation[break.loc, EntryLocation[break.loc]] =>
stream.Put[rope["entry of "]];
IsLocationAtLocation[break.loc, ExitLocation[break.loc]] =>
stream.Put[rope["exit of "]];
ENDCASE => stream.Put[rope["inside of "]];
stream.Put[rope[AMTypes.TVToName[TVFromLocation[break.loc]]]];
END;
ManualSetBreak:
PROCEDURE[gf, pc:
CARDINAL]
RETURNS[
ROPE] =
BEGIN
loc: BBObjectLocation.Location;
loc ← LocationFromGFandPC[LOOPHOLE[gf], [pc]];
IF loc = NIL THEN RETURN["no location"];
RETURN[SetUserBreak[NIL, loc].msg];
END;
LocationFromGFandPC:
PROCEDURE[gf: PrincOps.GlobalFrameHandle, pc: PrincOps.BytePC]
RETURNS[BBObjectLocation.Location] = INLINE
{RETURN[BBObjectLocation.LocationFromGFandPC[AMBridge.TVForGFHReferent[gf], pc]]};
END..
sensitiveBreaks: LIST OF BreakRecord ← NIL;
BreakRecord:
TYPE =
RECORD[
loc: BBObjectLocation.Location,
id: BBObjectLocation.BreakpointId];
loc: ARRAY [0..3] OF RECORD[gf, pc: CARDINAL] ← ALL[[0, 0]];
spaceImplA: PrincOps.GlobalFrameHandle ← LOOPHOLE[25300B];
createAny: PrincOps.BytePC ← [12712B];
deleteAny: PrincOps.BytePC ← [14762B];
ClearSensitiveBreaks:
PROCEDURE =
BEGIN
FOR sensitiveBreaks ← sensitiveBreaks, sensitiveBreaks.rest
DO
IF sensitiveBreaks = NIL THEN EXIT;
[] ← BBObjectLocation.ClearBreakpoint[sensitiveBreaks.first.loc, sensitiveBreaks.first.id];
ENDLOOP;
END;
SetSensitiveBreak:
PUBLIC
PROCEDURE[type: SpyClient.DataType]
RETURNS[msg:
ROPE] =
BEGIN
ok: BOOLEAN ← TRUE;
SetBreak:
PROCEDURE[loc: BBObjectLocation.Location] =
BEGIN
break: BreakRecord;
IF loc = NIL THEN ok ← FALSE;
IF ok = FALSE THEN RETURN;
break.loc ← loc;
break.id ← BBObjectLocation.SetBreakpoint[loc, SensitiveBreak];
sensitiveBreaks ← CONS[break, sensitiveBreaks];
END;
ClearSensitiveBreaks[];
BBContext.ResetSearchCache[];
IF TRUE THEN RETURN["Not implemented."];
SELECT
TRUE
FROM
loc[0] # [0, 0] => {
-- wizard-defined breaks
FOR i:
CARDINAL
IN [0..3]
DO
IF ok = FALSE THEN EXIT;
IF loc[i] = [0, 0] THEN EXIT;
SetBreak[LocationFromGFandPC[LOOPHOLE[loc[i].gf], [loc[i].pc]]];
ENDLOOP;
IF ~ok THEN msg ← "Could not set wizard-defined breaks."};
type = wordsAllocated
OR type = allocations => {
SetBreak[LocationFromName["RTAllocatorImpl.NewQuantizedObject"]];
SetBreak[LocationFromName["RTPrefAllocImpl.NewPrefixedObject"]];
IF ~ok THEN msg ← "Please get RTAllocatorImpl.bcd and RTPrefAllocImpl.bcd from [indigo]<Cedar>Runtime>."};
type = spaces => {
SetBreak[LocationFromGFandPC[spaceImplA, createAny]];
SetBreak[LocationFromGFandPC[spaceImplA, deleteAny]];
IF ~ok THEN msg ← "Could not set space allocation breaks."};
ENDCASE;
IF ~ok THEN ClearSensitiveBreaks[];
END;
SensitiveBreak:
ENTRY BBObjectLocation.BreakpointHandler =
TRUSTED BEGIN
count: CARDINAL ← 1;
Parameters:
TYPE =
RECORD[
zone: ZONE,
size: CARDINAL,
filler: ARRAY [0..11) OF CARDINAL];
IF SpyOps.spyState # on THEN RETURN;
IF SpyOps.watching NOT IN [allocations..spaces] THEN RETURN;
IF SpyOps.watching = wordsAllocated THEN count ← LOOPHOLE[state.stk, Parameters].size;
SpyOps.Record[LOOPHOLE[Process.GetCurrent[]], state.dest.frame, count];
END;
LocationFromName:
PROCEDURE[name:
ROPE]
RETURNS[loc: BBObjectLocation.Location ←
NIL] =
BEGIN
OPEN BBObjectLocation;
tv: AMTypes.TV ← NIL;
module, proc: ROPE ← NIL;
foundOne: SAFE PROC [lgf, ltv: AMTypes.TV, actualName: ROPE] RETURNS [BOOLEAN] =
CHECKED {tv ← ltv; RETURN [TRUE]};
[module, proc] ← Split[name];
IF module = NIL OR proc = NIL THEN RETURN[NIL];
tv ← BBContext.GlobalFrameSearch[NIL, module, proc].tv;
IF tv #
NIL
THEN {
loc: Location ← TVToLocation[tv ! ANY => GO TO oops];
RETURN[loc]};
EXITS oops => RETURN[NIL];
END;
Split:
PROC [name:
ROPE]
RETURNS [Rope.Text, Rope.Text] =
BEGIN
length: INT ← name.Length[];
pos: INT ← name.Index[0, "."];
IF pos = length THEN RETURN[NIL, NIL];
RETURN[name.Flatten[0, pos], name.Flatten[pos + 1, length]];