DIRECTORY AMEvents USING [CallDebugger], Environment USING [wordsPerPage], FastBreak USING [FastBreakData, FastBreakId, FastBreakProc], Frame USING [GetReturnFrame], Mopcodes USING [zBRK], PrincOps USING [BYTE, BytePC, Frame, FrameHandle, GlobalFrameHandle, InstWord, NullLink, StateVector], Space USING [Create, Delete, Handle, LongPointer, Map, virtualMemory], SpecialSpace USING [MakeCodeResident, MakeGlobalFrameResident, MakeResident, MakeSwappable], WorldVM USING [ClearBreak, LocalWorld, Read, SetBreak], XferTrap USING [ReadXTS, WriteXTS]; FastBreakImpl: MONITOR IMPORTS AMEvents, Frame, Space, SpecialSpace, WorldVM, XferTrap EXPORTS FastBreak = BEGIN OPEN FastBreak; FastBreakEntryPtr: TYPE = LONG POINTER TO FastBreakEntry; FastBreakEntry: TYPE = RECORD [ count: INT _ 0, next: FastBreakEntryPtr _ NIL, code: LONG POINTER _ NIL, pc: PrincOps.BytePC _ [0], inst: PrincOps.BYTE _ 0, data: LONG POINTER _ NIL, proc: FastBreakProc _ NIL ]; FastBreakPages: CARDINAL = 4; MaxFastBreaks: CARDINAL = (FastBreakPages*Environment.wordsPerPage) / SIZE[FastBreakEntry]; FastBreakArrayPtr: TYPE = LONG POINTER TO FastBreakArray; FastBreakArray: TYPE = ARRAY [0..MaxFastBreaks) OF FastBreakEntry; arrayPtr: FastBreakArrayPtr _ NIL; space: Space.Handle; -- valid iff arrayPtr # NIL oldBreakTrap: PROC _ NIL; fastBreaksLeft: NAT _ MaxFastBreaks; inUseChain: FastBreakEntryPtr _ NIL; freeChain: FastBreakEntryPtr _ NIL; firstTime: BOOL _ TRUE; SpecifyDefaultBreakHandler: PUBLIC PROC [old: PROC] = { oldBreakTrap _ old; }; FastBreakHandler: PUBLIC PROC = { state: RECORD [ padding: ARRAY [0..2) OF UNSPECIFIED, v: PrincOps.StateVector]; fp: PrincOps.FrameHandle; state.v _ STATE; fp _ Frame.GetReturnFrame[]; IF inUseChain # NIL THEN { pc: PrincOps.BytePC _ fp.pc; gf: PrincOps.GlobalFrameHandle _ fp.accesslink; code: LONG POINTER _ gf.code.longbase; ep: FastBreakEntryPtr _ inUseChain; inst: PrincOps.BYTE _ Mopcodes.zBRK; useOld: BOOL _ FALSE; WHILE ep # NIL DO entry: FastBreakEntry _ ep^; -- copy in one burst to reduce races IF entry.code = code AND entry.pc = pc THEN { inst _ entry.inst; ep.count _ entry.count + 1; IF entry.proc # NIL THEN IF entry.proc[entry.data, fp, @state.v] THEN useOld _ TRUE; }; ep _ entry.next; ENDLOOP; IF inst # Mopcodes.zBRK THEN { IF XferTrap.ReadXTS[] = on THEN XferTrap.WriteXTS[skip1]; IF useOld THEN { AMEvents.CallDebugger["FastBreak proc requested a break."]; }; state.v.source _ PrincOps.NullLink; state.v.dest _ LOOPHOLE[fp]; state.v.instbyte _ inst; RETURN WITH state.v; }; }; IF XferTrap.ReadXTS[] = on THEN XferTrap.WriteXTS[skip1]; state.v.source _ LOOPHOLE[fp]; state.v.dest _ LOOPHOLE[oldBreakTrap]; RETURN WITH state.v; }; FastBreaksLeft: PUBLIC PROC RETURNS [NAT] = TRUSTED { RETURN [fastBreaksLeft]; }; SetFastBreak: PUBLIC ENTRY PROC [code: LONG POINTER, pc: PrincOps.BytePC, proc: FastBreakProc _ NIL, data: FastBreakData _ NIL] RETURNS [id: FastBreakId] = TRUSTED { ENABLE UNWIND => NULL; ep: FastBreakEntryPtr _ freeChain; inst: PrincOps.BYTE _ Mopcodes.zBRK; needToSet: BOOL _ TRUE; IF arrayPtr = NIL THEN { fb: FastBreakEntryPtr; IF firstTime THEN { SpecialSpace.MakeGlobalFrameResident[FastBreakImpl]; SpecialSpace.MakeCodeResident[FastBreakImpl]; firstTime _ FALSE; }; Space.Map[space _ Space.Create[FastBreakPages, Space.virtualMemory]]; SpecialSpace.MakeResident[space]; arrayPtr _ LOOPHOLE[Space.LongPointer[space]]; fastBreaksLeft _ MaxFastBreaks; arrayPtr^ _ ALL[FastBreakEntry[]]; ep _ freeChain _ fb _ @arrayPtr[0]; FOR i: CARDINAL IN [0..MaxFastBreaks-1) DO next: FastBreakEntryPtr _ fb + SIZE[FastBreakEntry]; fb.next _ next; fb _ next; ENDLOOP; }; IF ep = NIL THEN RETURN [NIL]; inst _ ReadCodeByte[code, pc]; IF inst = Mopcodes.zBRK THEN { FOR eep: FastBreakEntryPtr _ inUseChain, eep.next WHILE eep # NIL DO IF eep.code = code AND eep.pc = pc THEN { inst _ eep.inst; needToSet _ FALSE; EXIT}; ENDLOOP; IF inst = Mopcodes.zBRK THEN RETURN [NIL]; }; id _ @ep.count; freeChain _ ep.next; ep^ _ [count: 0, next: inUseChain, code: code, pc: pc, inst: inst, data: data, proc: proc]; inUseChain _ ep; IF needToSet THEN ep.inst _ WorldVM.SetBreak[WorldVM.LocalWorld[], LOOPHOLE[code], pc]; }; ClearFastBreak: PUBLIC ENTRY PROC [id: FastBreakId, proc: FastBreakProc _ NIL, data: FastBreakData _ NIL] RETURNS [found: BOOL _ FALSE] = TRUSTED { ENABLE UNWIND => NULL; ep: FastBreakEntryPtr _ inUseChain; lag: FastBreakEntryPtr _ NIL; WHILE ep # NIL DO IF LOOPHOLE[id, FastBreakEntryPtr] = ep AND ep.proc = proc AND ep.data = data THEN { ClearInternal[ep, lag]; RETURN [TRUE]; }; lag _ ep; ep _ ep.next; ENDLOOP; }; ClearAllFastBreaks: PUBLIC ENTRY PROC [releaseResources: BOOL _ TRUE] RETURNS [cleared: NAT _ 0] = TRUSTED { ENABLE UNWIND => NULL; WHILE inUseChain # NIL DO ClearInternal[inUseChain]; cleared _ cleared + 1; ENDLOOP; IF releaseResources AND arrayPtr # NIL THEN { arrayPtr _ NIL; -- SpecialSpace.MakeCodeSwappable[FastBreakImpl]; SpecialSpace.MakeSwappable[space]; Space.Delete[space]; fastBreaksLeft _ MaxFastBreaks; }; }; ClearInternal: INTERNAL PROC [ep: FastBreakEntryPtr, lag: FastBreakEntryPtr _ NIL] = { SELECT CountBreaksAtLocation[ep.code, ep.pc] FROM 0 => RETURN; 1 => { WorldVM.ClearBreak[WorldVM.LocalWorld[], LOOPHOLE[ep.code], ep.pc, ep.inst]; }; ENDCASE; IF lag = NIL THEN inUseChain _ ep.next ELSE lag.next _ ep.next; ep.next _ freeChain; freeChain _ ep; fastBreaksLeft _ fastBreaksLeft + 1; }; CountBreaksAtLocation: INTERNAL PROC [code: LONG POINTER, pc: PrincOps.BytePC] RETURNS [count: CARDINAL _ 0] = { ep: FastBreakEntryPtr _ inUseChain; WHILE ep # NIL DO IF ep.code = code AND ep.pc = pc THEN count _ count + 1; ep _ ep.next; ENDLOOP; }; ReadCodeByte: PROC [code: LONG POINTER, pc: PrincOps.BytePC] RETURNS [byte: PrincOps.BYTE] = { addr: LONG CARDINAL _ LOOPHOLE[code]; word: PrincOps.InstWord _ LOOPHOLE[WorldVM.Read[WorldVM.LocalWorld[], addr+pc/2]]; IF pc MOD 2 = 1 THEN byte _ word.oddbyte ELSE byte _ word.evenbyte; }; END. òFastBreakImpl.mesa Russ Atkinson, April 28, 1983 2:03 am SpecifyDefaultBreakHandler[old] specifies the old breakpoint handler to be used when a non-fast break is encountered. It should be called before FastBreakHandler is installed. Executed by (non-worry) BRK instruction. Examines our wonder little resident data structure to determine whether or not to take a FAST break. If not, then we pass control to the old break handler (whatever it is). There can be races between this procedure and the setting/cearing procedures, but it is not easy to remove these races due to atomicity considerations. call the user's routine We have handled a fast break. Now we must clean up our act to allow continuation. Notice that we do not allow upper-level breakpoints AND fast breaks, although we allow multiple fast breaks. We have handled a fast break, but we have been requested to make this into a pseudo-break event. The easiest way is just to call the debugger. At this point we have NOT handled a fast break, so we have to go to the old break handler in the hopes that it knows what to do. FastBreaksLeft[] returns the number of fast break slots remaining in the table. SetFastBreak[code, pc, proc, data] adds a fast break at the specified location. The pointer returned is used to distinguish which break to clear when clearing the break. If NIL is returned, then the breakpoint could not be set (due to the table being full). Make a new array, and make sure that it is resident. this is the latest time that we can make ourselves resident and still be safe about it There is already a breakpoint here, so let's check our inUseChain for other instances. There is already a break at this location, so punt. Remove the entry from the free chain Fill in the entry Put the entry on the inUseChain ClearFastBreak[id, proc, data] clears the specified fast break, provided that the parameters agree with an active fast break. TRUE is returned iff such a break was found. ClearAllFastBreaks[] clears all fast breaks. It also releases system resources used by fast breaks if releaseResources = TRUE. It returns the number of fast breaks removed. Clear out one break Time to restore the old instruction Now, remove the entry from the inUseChain Put the block back on the free chain Ê ˜Jšœ™Jšœ%™%J˜šÏk ˜ Jšœ œ˜Jšœ œ˜!Jšœ œ-˜