// SwatStack.bcpl - code for stack manipulation
// Copyright Xerox Corporation 1979, 1981, 1982
// Last modified March 21, 1982  1:55 PM by Boggs

// All you do is just...08/10/73   (ALB)

get "Swat.decl"

external
[
// outgoing procedures
StackSwapIn; StackSysIn; StackSysOut
MapStack; Frame; PrintFrame; GetRetPC

// incoming procedures from Swat
VMFetch; ReportFail; AddrToSym; OpenCell

// incoming procedures from OS
Endofs; Gets; Puts; Wss; PutTemplate

// outgoing statics
openFrame

// incoming statics
dsp; stackDubious; xmFlag
]

static
[
openFrame	// currently open frame
opfnum
fnp
]

//----------------------------------------------------------------------------
let StackSwapIn() be openFrame = VMFetch(userAC2)
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
and StackSysOut(sysOut) be Puts(sysOut, openFrame)
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
and StackSysIn(sysIn) be
//----------------------------------------------------------------------------
   openFrame = Endofs(sysIn)? VMFetch(userAC2), Gets(sysIn)

//----------------------------------------------------------------------------
and Frame(n) be 
//----------------------------------------------------------------------------
// Dump the parameters in the nth frame, and set $
[
MapStack(n, Frame1, nil, VMFetch(userAC2))
if opfnum ne n then ReportFail("Frame not found")
for i = 1 to fnp do
   PutTemplate(dsp, "$UO: $UO*N", openFrame+3+i, VMFetch(openFrame+3+i))
OpenCell(openFrame+3+fnp)
]

//----------------------------------------------------------------------------
and GetRetPC(n) = valof
//----------------------------------------------------------------------------
// Get the pc at which we jump back into the nth frame.
// Used by the "index$↑P" command.
[
MapStack(n, Frame1, nil, VMFetch(userAC2))
if opfnum ne n then ReportFail("Frame not found")
resultis VMFetch(openFrame+1) +1
]

//----------------------------------------------------------------------------
and Frame1(level, frame, numArgs, nil) be
//----------------------------------------------------------------------------
   [ openFrame, opfnum, fnp = frame, level, numArgs ]

//----------------------------------------------------------------------------
and PrintFrame(level, frame, numArgs, stream) be
//----------------------------------------------------------------------------
[
let bank = 0
let retAddr = VMFetch(frame eq VMFetch(userAC2)? userPC, frame+1)
if xmFlag then
   [
   let retInst = VMFetch(retAddr+1)
   if (retInst & xJmpInstMask) eq xJmp0 & retAddr eq (frame+xJmp-1) then
      [
      retAddr = VMFetch(retAddr+2)  //i.e. xPC in extended frame
      bank = retInst & xJmpBankMask
      ]
   ]
if level ge 1 then stackDubious = false  // used in SwatResident.bcpl
PutTemplate(stream, "$2O $6UO $5UO $1O ",
 level, frame, VMFetch(frame)-frame, bank)
AddrToSym(stream, retAddr, bank)
Wss(stream, "--(")
for i = 1 to numArgs do PutTemplate(stream, "$UO$S",
 VMFetch(frame+3+i), (numArgs eq i? "", ", "))
Wss(stream, ")*N")
]

//----------------------------------------------------------------------------
and MapStack(lastLevel, proc, arg, root) be
//----------------------------------------------------------------------------
[
let thisLevel, thisFrame = 0, root
until thisLevel gr lastLevel do
   [
   let prevFrame = VMFetch(thisFrame)
   let retAddr = VMFetch(prevFrame+1)
   let numArgs = VMFetch(retAddr)
   let prevFrameValid = valof
      [
      if (numArgs & 177700B) ne 0 then [ numArgs = 0; resultis false ]
      if prevFrame eq 0 % prevFrame eq thisFrame % 
       prevFrame ugr 176777b % retAddr eq 0 resultis false
      resultis true
      ]

   proc(thisLevel, thisFrame, numArgs, arg)
   unless prevFrameValid return
   thisFrame = prevFrame
   thisLevel = thisLevel +1
   ]
]