DIRECTORY TargetArchitecture, Shepherd, Breakpoint, BreakWorldShepherd, PCRMonitorDefs, BreakWorldArchitecture, RuntimeError; BreakWorldShepherdImpl: CEDAR PROGRAM IMPORTS Shepherd, TargetArchitecture, BreakWorldArchitecture, RuntimeError EXPORTS Shepherd ~ { Meadow: PUBLIC TYPE ~ BreakWorldShepherd.Meadow _ Shepherd.nullMeadow; MeadowRep: PUBLIC TYPE ~ BreakWorldShepherd.MeadowRep; Patch: PUBLIC TYPE ~ BreakWorldShepherd.Patch _ Shepherd.nullPatch; PatchRep: PUBLIC TYPE ~ BreakWorldShepherd.PatchRep; ReservePatch: PUBLIC PROCEDURE [ pc: BreakWorldArchitecture.Address, codeSize: BreakWorldArchitecture.ByteSize] RETURNS [Shepherd.Patch] ~ { ENABLE BreakWorldArchitecture.Cant => ERROR Shepherd.Cant[message]; patch: BreakWorldShepherd.Patch _ BreakWorldShepherd.nullPatch; IF pc.IsNullAddress[] THEN { ERROR Shepherd.Cant[message: "ReservePatch[nullAddress]"]; }; { meadow: BreakWorldShepherd.Meadow ~ MeadowFromPC[pc: pc]; ReserveUnderMonitor: PROCEDURE [] RETURNS [] ~ { Reserve: PROCEDURE [ meadow: BreakWorldShepherd.Meadow, pc: BreakWorldArchitecture.Address, codeSize: BreakWorldArchitecture.ByteSize] ~ { patch _ AllocatePatch[meadow: meadow, codeSize: codeSize]; SetPatchPC[ patch: patch, pc: pc.TargetAddressFromBreakWorldAddress[]]; RETURN; }; IF Shepherd.IsBusyPC[pc: pc] THEN { ERROR Shepherd.BusyPC[message: "That address is busy"]; }; Reserve[meadow: meadow, pc: pc, codeSize: codeSize]; RETURN; }; IF Shepherd.IsNullMeadow[meadow: meadow] THEN { ERROR Shepherd.NoMeadow[message: "No meadow for that address"]; }; { -- extra block to contain EXITS. meadowAddress: BreakWorldArchitecture.Address ~ AddressFromMeadow[ meadow: meadow]; BreakWorldArchitecture.MonitoredCall[ address: meadowAddress, proc: ReserveUnderMonitor ! BreakWorldArchitecture.WouldBlock => { GO TO wouldBlock; }]; EXITS wouldBlock => { ERROR Shepherd.BusyMeadow[message: "Meadow for that address is busy"]; }; }; }; RETURN [patch]; }; ReleasePatch: PUBLIC PROCEDURE [patch: Shepherd.Patch] ~ { IF Shepherd.IsNullPatch[patch: patch] THEN { ERROR Shepherd.Cant[message: "ReleasePatch[nullPatch]"]; }; { meadow: Shepherd.Meadow ~ MeadowFromPatch[patch: patch]; ReleaseUnderMonitor: PROCEDURE [] RETURNS [] ~ { Release: PROCEDURE [patch: Shepherd.Patch] ~ { SetPatchPC[patch: patch, pc: TargetArchitecture.nullAddress]; DeallocatePatch[patch: patch]; }; Release[patch: patch]; }; IF Shepherd.IsNullMeadow[meadow: meadow] THEN { ERROR Shepherd.NoMeadow[message: "No meadow for that address"]; }; { -- extra block to contain EXITS. meadowAddress: BreakWorldArchitecture.Address ~ AddressFromMeadow[ meadow: meadow]; BreakWorldArchitecture.MonitoredCall[ address: meadowAddress, proc: ReleaseUnderMonitor ! BreakWorldArchitecture.WouldBlock => { GO TO wouldBlock; }]; EXITS wouldBlock => { ERROR Shepherd.BusyMeadow[message: "Meadow for that address is busy"]; }; }; }; RETURN; }; IsNullMeadow: PUBLIC PROCEDURE [meadow: Shepherd.Meadow] RETURNS [BOOLEAN] ~ { isNullMeadow: BOOLEAN ~ meadow = Shepherd.nullMeadow; RETURN [isNullMeadow]; }; IsNullPatch: PUBLIC PROCEDURE [patch: Shepherd.Patch] RETURNS [BOOLEAN] ~ { isNullPatch: BOOLEAN ~ patch = Shepherd.nullPatch; RETURN [isNullPatch]; }; PCFromPatch: PUBLIC PROCEDURE [patch: BreakWorldShepherd.Patch] RETURNS [BreakWorldArchitecture.Address] ~ { IF Shepherd.IsNullPatch[patch: patch] THEN { ERROR Shepherd.Cant[message: "PCFromPatch[nullPatch]"]; }; { targetAddress: TargetArchitecture.Address ~ GetPatchPC[patch: patch]; pc: BreakWorldArchitecture.Address ~ BreakWorldArchitecture.NewAddress[ breakWorld: BreakWorldArchitecture.BreakWorldFromBreakWorldAddress[ address: PatchAddressFromPatch[patch: patch]], address: targetAddress]; RETURN [pc]; }; }; AddressFromMeadow: PRIVATE PROCEDURE [meadow: BreakWorldShepherd.Meadow] RETURNS [BreakWorldArchitecture.Address] ~ { IF IsNullMeadow[meadow: meadow] THEN { ERROR Shepherd.Cant[message: "AddressFromMeadow[nullMeadow]"]; }; RETURN [meadow.address]; }; SizeFromMeadow: PRIVATE PROCEDURE [meadow: BreakWorldShepherd.Meadow] RETURNS [BreakWorldArchitecture.ByteSize] ~ { IF IsNullMeadow[meadow: meadow] THEN { ERROR Shepherd.Cant[message: "SizeFromMeadow[nullMeadow]"]; }; RETURN [meadow.byteSize]; }; MeadowFromPatch: PUBLIC PROCEDURE [patch: Shepherd.Patch] RETURNS [Shepherd.Meadow] ~ { meadow: Shepherd.Meadow ~ Shepherd.nullMeadow; IF IsNullPatch[patch: patch] THEN { ERROR Shepherd.Cant[message: "MeadowFromPatch[nullPatch]"]; }; RETURN [patch.meadow]; }; PatchAddressFromPatch: PUBLIC PROCEDURE [patch: BreakWorldShepherd.Patch] RETURNS [BreakWorldArchitecture.Address] ~ { IF IsNullPatch[patch: patch] THEN { ERROR Shepherd.Cant[message: "PatchAddressFromPatch[nullPatch]"]; }; RETURN [patch.patchAddress]; }; CodeAddressFromPatch: PUBLIC PROCEDURE [patch: BreakWorldShepherd.Patch] RETURNS [BreakWorldArchitecture.Address] ~ { IF IsNullPatch[patch: patch] THEN { ERROR Shepherd.Cant[message: "PatchAddressFromPatch[nullPatch]"]; }; RETURN [patch.codeAddress]; }; PatchFromPC: PUBLIC PROCEDURE [pc: BreakWorldArchitecture.Address] RETURNS [Shepherd.Patch] ~ { found: Shepherd.Patch _ Shepherd.nullPatch; IF pc.IsNullAddress[] THEN { ERROR Shepherd.Cant[message: "PatchFromPC[nullAddress]"]; }; { meadow: Shepherd.Meadow ~ MeadowFromPC[pc: pc]; targetPC: TargetArchitecture.Address ~ BreakWorldArchitecture.TargetAddressFromBreakWorldAddress[address: pc]; IF IsNullMeadow[meadow: meadow] THEN { ERROR Shepherd.Cant[message: "PatchFromPC[nullMeadow]"]; }; FOR patch: Shepherd.Patch _ FirstPatch[meadow: meadow], NextPatch[patch: patch] UNTIL Shepherd.IsNullPatch[patch: patch] DO { IF NOT IsAllocatedPatch[patch: patch] THEN { EXIT; }; IF targetPC = GetPatchPC[patch: patch] THEN { found _ patch; EXIT; }; } ENDLOOP; }; RETURN [found]; }; IsAllocatedPatch: PUBLIC PROCEDURE [patch: Shepherd.Patch] RETURNS [BOOLEAN] ~ { IF IsNullPatch[patch: patch] THEN { ERROR Shepherd.Cant[message: "IsAllocatedPatch[nullPatch]"]; }; { size: BreakWorldArchitecture.ByteSize ~ GetPatchSize[patch: patch]; RETURN [size # 0]; }; }; IsBusyPC: PUBLIC PROCEDURE [pc: BreakWorldArchitecture.Address] RETURNS [BOOLEAN] ~ { IF pc.IsNullAddress[] THEN { ERROR Shepherd.Cant[message: "IsBusyPC[nullAddress]"]; }; { patch: Shepherd.Patch ~ PatchFromPC[pc: pc]; isBusy: BOOLEAN ~ NOT IsNullPatch[patch: patch]; RETURN [isBusy]; }; }; NoRoom: PUBLIC ERROR [message: Shepherd.ErrorMessage] ~ CODE; NoMeadow: PUBLIC ERROR [message: Shepherd.ErrorMessage] ~ CODE; BusyMeadow: PUBLIC ERROR [message: Shepherd.ErrorMessage] ~ CODE; BusyPC: PUBLIC ERROR [message: Shepherd.ErrorMessage] ~ CODE; CantReach: PUBLIC ERROR [message: Shepherd.ErrorMessage] ~ CODE; Cant: PUBLIC ERROR [message: Shepherd.ErrorMessage] ~ CODE; NewMeadow: PRIVATE PROCEDURE [ address: BreakWorldArchitecture.Address, byteSize: BreakWorldArchitecture.ByteSize] RETURNS [Shepherd.Meadow] ~ { meadow: BreakWorldShepherd.Meadow ~ NEW[BreakWorldShepherd.MeadowRep _ [ address: address, byteSize: byteSize]]; RETURN [meadow]; }; NewPatch: PRIVATE PROCEDURE [ meadow: Shepherd.Meadow, address: BreakWorldArchitecture.Address] RETURNS [Shepherd.Patch] ~ { IF meadow.IsNullMeadow[] THEN { ERROR Shepherd.Cant[message: "NewPatch[nullMeadow]"]; }; IF address.IsNullAddress[] THEN { ERROR Shepherd.Cant[message: "NewPatch[nullAddress]"]; }; { PatchCodeOffset: PROCEDURE [] RETURNS [TargetArchitecture.Displacement] ~ TRUSTED { PatchStruct: TYPE ~ MACHINE DEPENDENT RECORD [ header: Shepherd.PatchHeaderStruct, code: TargetArchitecture.Instruction]; patchStruct: PatchStruct; patchStructAddress: LONG POINTER TO PatchStruct ~ @patchStruct; patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress]; codeAddress: LONG POINTER TO TargetArchitecture.Instruction ~ @patchStruct.code; codeCard: CARD32 ~ LOOPHOLE[codeAddress]; offset: TargetArchitecture.Displacement ~ (codeCard - patchStructCard) * BYTES[UNIT]; RETURN [offset]; }; codeAddress: BreakWorldArchitecture.Address ~ BreakWorldArchitecture.AddressFromDisplacement[ address: address, displacement: PatchCodeOffset[]]; patch: BreakWorldShepherd.Patch ~ NEW[BreakWorldShepherd.PatchRep _ [ meadow: meadow, patchAddress: address, codeAddress: codeAddress]]; RETURN [patch]; }; }; MeadowFromPC: PRIVATE PROCEDURE [pc: BreakWorldArchitecture.Address] RETURNS [Shepherd.Meadow] ~ { ENABLE BreakWorldArchitecture.Cant => ERROR Shepherd.Cant[message]; meadow: Shepherd.Meadow _ Shepherd.nullMeadow; IF pc.IsNullAddress[] THEN { ERROR Shepherd.Cant[message: "MeadowFromPC[nullAddress]"]; }; { patchArea: BreakWorldArchitecture.PatchArea ~ BreakWorldArchitecture.GetPatchArea[address: pc]; IF NOT BreakWorldArchitecture.IsNullPatchArea[patchArea: patchArea] THEN { meadow _ NewMeadow[address: patchArea.address, byteSize: patchArea.byteSize]; }; }; RETURN [meadow]; }; AllocatePatch: PRIVATE PROCEDURE [ meadow: Shepherd.Meadow, codeSize: BreakWorldArchitecture.ByteSize] RETURNS [Shepherd.Patch] ~ { patch: Shepherd.Patch _ Shepherd.nullPatch; IF meadow.IsNullMeadow[] THEN { ERROR Shepherd.Cant[message: "AllocatePatch[nullMeadow]"]; }; { meadowAddress: TargetArchitecture.Address ~ BreakWorldArchitecture.TargetAddressFromBreakWorldAddress[ address: AddressFromMeadow[meadow: meadow]]; meadowSize: BreakWorldArchitecture.ByteSize ~ SizeFromMeadow[meadow: meadow]; patchSize: BreakWorldArchitecture.ByteSize ~ codeSize + BYTES[Shepherd.PatchHeaderStruct]; FOR newPatch: Shepherd.Patch _ FirstPatch[meadow: meadow], NextPatch[patch: newPatch] DO { IF Shepherd.IsNullPatch[patch: newPatch] THEN { ERROR Shepherd.NoRoom[message: "No more patches in the meadow"]; }; IF NOT IsAllocatedPatch[patch: newPatch] THEN { patchAddress: TargetArchitecture.Address ~ BreakWorldArchitecture.TargetAddressFromBreakWorldAddress[ address: PatchAddressFromPatch[patch: newPatch]]; patchDisplacement: TargetArchitecture.Displacement ~ TargetArchitecture.DisplacementFromAddresses[ here: meadowAddress, there: patchAddress]; requiredSize: BreakWorldArchitecture.ByteSize ~ patchDisplacement + patchSize; IF requiredSize > meadowSize THEN { ERROR Shepherd.NoRoom[message: "No room for patch in the meadow"]; }; SetPatchSize[patch: newPatch, size: patchSize]; patch _ newPatch; EXIT; }; } ENDLOOP; }; RETURN [patch]; }; DeallocatePatch: PRIVATE PROCEDURE [patch: Shepherd.Patch] RETURNS [] ~ { IF Shepherd.IsNullPatch[patch: patch] THEN { ERROR Shepherd.Cant[message: "DeallocatePatch[nullPatch]"]; }; RETURN; }; MeadowHeader: PRIVATE TYPE ~ MACHINE DEPENDENT RECORD [ monitorLock: PCRMonitorDefs.MonitorLock, next: TargetArchitecture.Address ]; FirstPatch: PRIVATE PROCEDURE [meadow: Shepherd.Meadow] RETURNS [Shepherd.Patch] ~ { patch: BreakWorldShepherd.Patch _ Shepherd.nullPatch; IF meadow.IsNullMeadow[] THEN { ERROR Shepherd.Cant[message: "FirstPatch[nullMeadow]"]; }; { meadowAddress: TargetArchitecture.Address ~ BreakWorldArchitecture.TargetAddressFromBreakWorldAddress[ address: AddressFromMeadow[meadow: meadow]]; meadowSize: BreakWorldArchitecture.ByteSize ~ SizeFromMeadow[meadow: meadow]; patchAddress: TargetArchitecture.Address ~ TargetArchitecture.AddressFromDisplacement[ address: meadowAddress, displacement: BYTES[MeadowHeader]]; patchDisplacement: TargetArchitecture.Displacement ~ TargetArchitecture.DisplacementFromAddresses[ here: meadowAddress, there: patchAddress]; IF BreakWorldArchitecture.ByteSize[patchDisplacement] < meadowSize THEN { patchBreakWorldAddress: BreakWorldArchitecture.Address ~ BreakWorldArchitecture.NewAddress[ breakWorld: BreakWorldArchitecture.BreakWorldFromBreakWorldAddress[ address: AddressFromMeadow[meadow: meadow]], address: patchAddress]; patch _ NewPatch[meadow: meadow, address: patchBreakWorldAddress]; }; }; RETURN [patch]; }; NextPatch: PRIVATE PROCEDURE [patch: Shepherd.Patch] RETURNS [Shepherd.Patch] ~ { nextPatch: BreakWorldShepherd.Patch _ Shepherd.nullPatch; IF patch.IsNullPatch[] THEN { ERROR Shepherd.Cant[message: "NextPatch[nullPatch]"]; }; { meadow: BreakWorldShepherd.Meadow ~ MeadowFromPatch[patch: patch]; meadowAddress: TargetArchitecture.Address ~ BreakWorldArchitecture.TargetAddressFromBreakWorldAddress[ address: AddressFromMeadow[meadow: meadow]]; meadowSize: BreakWorldArchitecture.ByteSize ~ SizeFromMeadow[meadow: meadow]; patchAddress: TargetArchitecture.Address ~ BreakWorldArchitecture.TargetAddressFromBreakWorldAddress[ address: PatchAddressFromPatch[patch: patch]]; patchSize: BreakWorldArchitecture.ByteSize ~ GetPatchSize[patch: patch]; newTargetAddress: TargetArchitecture.Address ~ TargetArchitecture.AddressFromDisplacement[ address: patchAddress, displacement: patchSize]; newDisplacement: TargetArchitecture.Displacement ~ TargetArchitecture.DisplacementFromAddresses[ here: meadowAddress, there: newTargetAddress]; IF BreakWorldArchitecture.ByteSize[newDisplacement] < meadowSize THEN { newBreakWorldAddress: BreakWorldArchitecture.Address ~ BreakWorldArchitecture.NewAddress[ breakWorld: BreakWorldArchitecture.BreakWorldFromBreakWorldAddress[ address: PatchAddressFromPatch[patch: patch]], address: newTargetAddress]; nextPatch _ NewPatch[meadow: meadow, address: newBreakWorldAddress]; }; }; RETURN [nextPatch]; }; GetPatchHeader: PRIVATE PROCEDURE [patch: Shepherd.Patch] RETURNS [Shepherd.PatchHeaderStruct] ~ { IF patch.IsNullPatch[] THEN { ERROR Shepherd.Cant[message: "GetPatchHeader[nullPatch]"]; }; { contents: TargetArchitecture.Contents ~ BreakWorldArchitecture.PeekContents[ address: PatchAddressFromPatch[patch: patch]]; patchHeaderStruct: Shepherd.PatchHeaderStruct ~ LOOPHOLE[contents]; RETURN [patchHeaderStruct]; }; }; SetPatchHeader: PRIVATE PROCEDURE [ patch: Shepherd.Patch, patchHeaderStruct: Shepherd.PatchHeaderStruct] RETURNS [] ~ { IF patch.IsNullPatch[] THEN { ERROR Shepherd.Cant[message: "SetPatchHeader[nullPatch]"]; }; { contents: TargetArchitecture.Contents ~ LOOPHOLE[patchHeaderStruct]; BreakWorldArchitecture.PokeContents[ address: PatchAddressFromPatch[patch: patch], contents: contents]; }; RETURN; }; GetPatchSize: PRIVATE PROCEDURE [patch: Shepherd.Patch] RETURNS [Shepherd.PatchSize] ~ { IF patch.IsNullPatch[] THEN { ERROR Shepherd.Cant[message: "GetPatchSize[nullPatch]"]; }; { patchHeaderStruct: Shepherd.PatchHeaderStruct ~ GetPatchHeader[patch: patch]; RETURN [patchHeaderStruct.size * BYTES[TargetArchitecture.Contents]]; }; }; SetPatchSize: PRIVATE PROCEDURE [patch: Shepherd.Patch, size: BreakWorldArchitecture.ByteSize] RETURNS [] ~ { IF patch.IsNullPatch[] THEN { ERROR Shepherd.Cant[message: "SetPatchSize[nullPatch]"]; }; { patchHeaderStruct: Shepherd.PatchHeaderStruct _ GetPatchHeader[patch: patch]; wordSize: Shepherd.PatchSize ~ (size + BYTES[TargetArchitecture.Contents] - 1) / BYTES[TargetArchitecture.Contents]; patchHeaderStruct.size _ wordSize; SetPatchHeader[patch: patch, patchHeaderStruct: patchHeaderStruct]; RETURN; }; }; GetPatchPC: PUBLIC PROCEDURE [patch: Shepherd.Patch] RETURNS [TargetArchitecture.Address] ~ { address: TargetArchitecture.Address _ TargetArchitecture.nullAddress; IF patch.IsNullPatch[] THEN { ERROR Shepherd.Cant[message: "GetPatchPC[nullPatch]"]; }; { relPC: Shepherd.RelPC ~ GetPatchRelPC[patch: patch]; IF relPC # TargetArchitecture.nullDisplacement THEN { patchAddress: TargetArchitecture.Address ~ BreakWorldArchitecture.TargetAddressFromBreakWorldAddress[ address: PatchAddressFromPatch[patch: patch]]; displacementBytes: TargetArchitecture.Displacement ~ relPC * BYTES[TargetArchitecture.Contents]; address _ TargetArchitecture.AddressFromDisplacement[ address: patchAddress, displacement: displacementBytes]; }; }; RETURN [address]; }; GetPatchRelPC: PRIVATE PROCEDURE [patch: Shepherd.Patch] RETURNS [Shepherd.RelPC] ~ { IF patch.IsNullPatch[] THEN { ERROR Shepherd.Cant[message: "GetPatchRelPC[nullPatch]"]; }; { patchHeaderStruct: Shepherd.PatchHeaderStruct ~ GetPatchHeader[patch: patch]; relPCLS: Shepherd.RelPCLS ~ patchHeaderStruct.relPCLS; relPCMS: Shepherd.RelPCMS ~ patchHeaderStruct.relPCMS; card: CARD32 ~ (relPCMS * (CARD32[Shepherd.lastRelPCLS] + 1)) + relPCLS; signBits: CARD32 ~ (LAST[CARD32] / ((CARD32[Shepherd.lastRelPCMS] + 1) * (CARD32[Shepherd.lastRelPCLS] + 1))) * ((CARD32[Shepherd.lastRelPCMS] + 1) * (CARD32[Shepherd.lastRelPCLS] + 1)); relPC: Shepherd.RelPC ~ IF card <= CARD32[Shepherd.lastRelPC] THEN card ELSE LOOPHOLE[card + signBits]; IF relPC NOT IN [Shepherd.firstRelPC .. Shepherd.lastRelPC] THEN { ERROR RuntimeError.BoundsFault; }; RETURN [relPC]; }; }; SetPatchPC: PUBLIC PROCEDURE [patch: Shepherd.Patch, pc: TargetArchitecture.Address] RETURNS [] ~ { relPC: Shepherd.RelPC _ TargetArchitecture.nullDisplacement; IF patch.IsNullPatch[] THEN { ERROR Shepherd.Cant[message: "GetPatchRelPC[nullPatch]"]; }; IF pc # TargetArchitecture.nullAddress THEN { patchAddress: TargetArchitecture.Address ~ BreakWorldArchitecture.TargetAddressFromBreakWorldAddress[ address: PatchAddressFromPatch[patch: patch]]; displacementBytes: TargetArchitecture.Displacement ~ TargetArchitecture.DisplacementFromAddresses[here: patchAddress, there: pc]; relPC _ displacementBytes / BYTES[TargetArchitecture.Contents]; IF relPC NOT IN [Shepherd.firstRelPC .. Shepherd.lastRelPC] THEN { ERROR Shepherd.CantReach[message: "Patch too far from PC"]; }; }; SetPatchRelPC[patch: patch, relPC: relPC]; RETURN; }; SetPatchRelPC: PRIVATE PROCEDURE [patch: Shepherd.Patch, relPC: Shepherd.RelPC] RETURNS [] ~ { IF patch.IsNullPatch[] THEN { ERROR Shepherd.Cant[message: "GetPatchRelPC[nullPatch]"]; }; { patchHeaderStruct: Shepherd.PatchHeaderStruct _ GetPatchHeader[patch: patch]; card: CARD32 ~ LOOPHOLE[relPC]; relPCLS: Shepherd.RelPCLS ~ card MOD (CARD32[Shepherd.lastRelPCLS] + 1); relPCMS: Shepherd.RelPCMS ~ (card / (CARD32[Shepherd.lastRelPCLS] + 1)) MOD (CARD32[Shepherd.lastRelPCMS] + 1); IF relPC NOT IN [Shepherd.firstRelPC .. Shepherd.lastRelPC] THEN { ERROR RuntimeError.BoundsFault; }; patchHeaderStruct.relPCLS _ relPCLS; patchHeaderStruct.relPCMS _ relPCMS; SetPatchHeader[patch: patch, patchHeaderStruct: patchHeaderStruct]; RETURN; }; }; }. ς BreakWorldShepherdImpl.mesa Copyright Σ 1989, 1990 by Xerox Corporation. All rights reserved. Peter B. Kessler, July 30, 1990 10:27 am PDT Philip James, June 25, 1991 3:12 pm PDT Types EXPORT'ed to Shepherd. Public Procedures EXPORT'ed to Shepherd. Public Errors. Private Procedures. This depends on Shepherd.PatchHeaderStruct leaving the patch code space aligned correctly for instructions. We don't deallocate patches, since we can't reuse them until the garbage collection problem is solved. the monitor lock for the meadow. a pointer to an extension of the meadow. Watch this! We do target address arithmetic using structures we've defined over here! Watch this! We do target address arithmetic using structures we've defined over here! Κ5•NewlineDelimiter – "cedar" style™code™Kšœ Οrœ7™BKšœ,™,K™'—™šΟk ˜ K˜Kšœ ˜ K˜ Kšœ˜K˜K˜Kšœ ˜ —K˜—unitšΠlnœžœž˜%šžœ˜K–0 bp restIndentšœB˜B—šžœ˜Kšœ˜—Kšœ˜head™šœžœžœ3˜FKšœ žœžœ ˜6K˜—šœžœžœ1˜CKšœ žœžœ˜4K˜——™(šΟn œžœž œSžœ˜šžœ˜Kšœžœ˜Kšœ˜—Kšžœ˜Kšœ˜K˜—š œžœž œ&žœ&˜tšžœžœ˜&Kšžœ6˜;Kšœ˜—Kšžœ˜Kšœ˜K˜—š œžœž œžœ˜XKšœ.˜.K˜šžœžœ˜#Kšžœ6˜;Kšœ˜—Kšžœ˜K˜K˜—š œžœž œ$žœ%˜wšžœžœ˜#Kšžœ<˜AKšœ˜—Kšžœ˜Kšœ˜K˜—š œžœž œ$žœ%˜všžœžœ˜#Kšžœ<˜AKšœ˜—Kšžœ˜Kšœ˜K˜—š  œžœž œ'žœ˜`Kšœ+˜+K˜šžœžœ˜Kšžœ4˜9Kšœ˜—˜Kšœ/˜/šœ'˜'KšœG˜G—K˜šžœžœ˜&Kšžœ3˜8Kšœ˜—šžœMžœ$žœ˜}šžœžœ žœ˜,Jšžœ˜Jšœ˜—šžœ%žœ˜-Jšœ˜Jšžœ˜J˜—Kšœžœ˜ —K˜—Kšžœ ˜K˜K˜—š  œžœž œžœžœ˜Pšžœžœ˜#Kšžœ7˜žœ˜JKšœM˜MKšœ˜—K˜—Kšžœ ˜K˜K˜—š  œžœž œIžœ˜…Kšœ+˜+K˜šžœžœ˜Kšžœ5˜:K˜—˜˜,˜:K˜,——KšœM˜Mšœ-˜-Kšœ žœ˜-Kšœl™l—K˜šžœTžœ˜[šžœ'žœ˜/Kšžœ;˜@K˜—šžœžœ#žœ˜/˜+˜:Kšœ1˜1——šœ5˜5šœ-˜-Kšœ*˜*——KšœN˜NK˜šžœžœ˜#Kšžœ=˜BK˜—Kšœ/˜/K˜Kšžœ˜K˜—Kšœžœ˜ —K˜—Kšžœ ˜Kšœ˜K˜—š œžœž œžœ˜IK™fšžœ$žœ˜,Kšžœ6˜;K˜—Kšžœ˜Kšœ˜K˜—š œžœžœžœž œžœ˜7šœ(˜(K™ —˜ K™(—K˜K˜—š  œžœž œžœ˜UKšœ5˜5K˜šžœžœ˜Kšžœ2˜7K˜—˜K™V˜,˜:K˜,——KšœM˜M˜+˜+Kšœ&žœ˜;——šœ5˜5šœ-˜-Kšœ*˜*——K˜šžœAžœ˜Išœ9˜9šœ"˜"šœC˜CKšœ-˜-—Kšœ˜——K˜KšœB˜BK˜—K˜—Kšžœ ˜Kšœ˜K˜—š  œžœž œžœ˜RKšœ9˜9K˜šžœžœ˜Kšžœ0˜5K˜—˜K™VKšœB˜B˜,˜:K˜,——KšœM˜M˜+˜:Kšœ.˜.——KšœH˜H˜/šœ+˜+Kšœ0˜0——šœ3˜3šœ-˜-Kšœ.˜.——K˜šžœ?žœ˜Gšœ7˜7šœ"˜"šœC˜CKšœ/˜/—Kšœ˜——K˜KšœD˜DK˜—K˜—Kšžœ ˜Kšœ˜K˜—š œžœž œžœ!˜cšžœžœ˜Kšžœ5˜:K˜—˜šœL˜LKšœ.˜.—Kšœ0žœ ˜CK˜Kšžœ˜K˜—Kšœ˜K˜—š œžœž œJžœ˜yšžœžœ˜Kšžœ5˜:K˜—˜Kšœ(žœ˜DK˜šœ$˜$KšœB˜B—K˜—Kšžœ˜Kšœ˜K˜—š  œžœž œžœ˜Yšžœžœ˜Kšžœ3˜8K˜—˜KšœM˜MK˜Kšžœžœ˜EK˜—Kšœ˜K˜—š  œžœž œAžœ˜nšžœžœ˜Kšžœ3˜8K˜—˜KšœM˜Mšœ˜Kšœžœ%žœ˜U—K˜Kšœ"˜"KšœC˜CKšžœ˜K˜—Kšœ˜K˜—š  œžœž œžœ!˜^K˜EK˜šžœžœ˜Kšžœ1˜6K˜—˜Kšœ4˜4K˜šžœ,žœ˜5K˜+˜:Kšœ.˜.—˜5Kšœžœ˜+—K˜˜5K˜8—K˜—K˜K˜—Kšžœ ˜K˜K˜—š  œžœž œžœ˜Všžœžœ˜Kšžœ4˜9K˜—˜KšœM˜MKšœ6˜6Kšœ6˜6Kšœžœžœ'˜Hšœ žœ˜šœžœžœ˜Kšœžœžœ ˜MKšœžœžœ˜J——šœ˜šžœ žœ˜%Kšžœ˜ Kšžœžœ˜——K˜šžœžœžœ-žœ˜BKšžœ˜K˜—Kšžœ ˜K˜—Kšœ˜K˜—š  œžœž œ:žœ˜dKšœ<˜