1: #include "../h/config.h" 2: 3: /* psusp - suspends a value from an Icon procedure. The procedure 4: * calling psusp is suspending and the value to suspend appears as 5: * an argument to psusp. The generator or expression frame 6: * immediately containing the frame of the suspending procedure is 7: * duplicated. 8: * 9: * psusp returns through the duplicated procedure frame and leaves the 10: * value being suspended on the top of the stack. When an alternative 11: * is needed, efail causes a return through the original procedure frame 12: * which was created by invoke. 13: */ 14: Global(_deref) /* Dereference a variable */ 15: Global(_strace) /* Trace procedure suspension */ 16: Global(_boundary) /* Icon/C boundary address */ 17: Global(_current) /* Current expression stack */ 18: Global(_line) /* Current line number */ 19: Global(_file) /* Current file name */ 20: Global(_k_level) /* Value of &level */ 21: Global(_k_trace) /* Value of &trace */ 22: 23: Global(_psusp) 24: #ifdef VAX 25: _psusp: 26: /* 27: * Construct the generator frame. 28: */ 29: Mask STDSV # Start new generator frame by saving 30: # registers upon entry to psusp. 31: movl fp,_boundary # Establish boundary value to be saved 32: # in frame. boundary is also needed 33: # because deref may be called. 34: pushl fp # Save the boundary in the frame. 35: /* 36: * Dereference the return value if it is a local variable or an 37: * argument. 38: */ 39: # The return value is on the stack as 40: # an argument, put type field of return 41: movl 8(ap),r1 # value in r1 for testing. 42: bitl $F_NQUAL,r1 # If return value is a string, 43: beql cmpltfrm # it doesn't need dereferencing. 44: bitl $F_VAR,r1 # If return value isn't a variable, 45: beql cmpltfrm # it doesn't need dereferencing. 46: bitl $F_TVAR,r1 # If return value is a trapped variable, 47: bneq chktv # it requires some work. 48: movl 12(ap),r1 # Otherwise, get the address of the 49: jmp chkloc # data block for more testing. 50: 51: chktv: # A trapped variable is being returned, 52: # only substring trapped variables need 53: # dereferencing. 54: bicl2 $~TYPEMASK,r1 # "and" off all but bits in type field 55: cmpl $T_TVSUBS,r1 # If the variable isn't a substring t.v., 56: bneq cmpltfrm # it doesn't need dereferencing. 57: movl 12(ap),r1 # Point r1 at data block for s.s.t.v. 58: movl 16(r1),r1 # Then at actual address of variable 59: chkloc: # 60: # See if the variable is on the stack. 61: # If it is, it will lie between the 62: # sp and the base of the current 63: # expression stack. r1 holds address 64: # of variable. 65: cmpl r1,sp # If address is below the sp, 66: blssu cmpltfrm # it's not a local or an argument 67: movl _current+4,r0 # Point r0 at data block for current 68: # expression. 69: cmpl r1,12(r0) # Fourth word is the base of the stack 70: # for the current expression. If the 71: # variable address is above the stack 72: bgtru cmpltfrm # base, it's not a local or an argument. 73: # Otherwise, it is a local or an argument 74: # and must be dereferenced. 75: pushal 8(ap) # Push address of return value 76: calls $1,_deref # and dereference it. 77: /* 78: * Complete the generator frame. 79: */ 80: cmpltfrm: 81: movl sp,gfp # Boundary value is on top of stack, 82: # make it word 0 of generator frame 83: pushl _k_level # Push &level, 84: pushl _line # line number, 85: pushl _file # and file name to complete the frame. 86: /* 87: * Determine region to be duplicated and copy it. 88: */ 89: # Note that because the call to psusp 90: # made a frame, the saved ap and fp 91: # values in that frame must be used. 92: movl 12(fp),r7 # Low word of region to be copied is the 93: # low word of procedure frame of suspending 94: # procedure. 95: 96: # If the saved gfp is non-zero, the 97: # generator frame marker serves as the 98: # upper bound of the expression frame. 99: # If it is zero, the expression frame 100: # marker pointed at by the saved 101: # efp is the upper bound of the frame 102: # to be copied. 103: # Note that the marker itself is not 104: # copied, the region only extends to 105: # the marker and not through it. 106: # This code counts on efp and gfp being 107: # saved in the frame of the suspender. 108: movl 8(fp),r2 # Get ap of suspending procedure in r2 109: movl -8(r2),r4 # Get gfp from procedure frame of suspending 110: # procedure. 111: bneq f1 # If it is zero, 112: movl -4(r2),r4 # get saved efp and 113: subl2 $8,r4 # use efp - 8. 114: jmp f2 115: f1: # gfp is not zero, 116: subl2 $12,r4 # use gfp - 12. 117: /* 118: * Copy region to be duplicated to top of stack. 119: */ 120: # r7 points at the low word of the region 121: # to be copied. r4 points at the high end 122: # of the region. (i.e. r4 is the first 123: # word not_ to copy.) 124: f2: 125: subl2 r7,r4 # r4 = r4 - r7, giving r4 number of bytes 126: # in region. 127: subl2 r4,sp # Move stack pointer down to make space 128: # for region. 129: movc3 r4,(r7),(sp) # Copy the region by moving r4 bytes starting 130: # at r7 to the top of the stack. 131: /* 132: * Produce trace message if tracing is on. 133: */ 134: decl _k_level # Decrement &level because a procedure 135: # is being "exited". 136: tstl _k_trace # If &trace is 0, 137: jeql tracedone # no tracing. 138: # Otherwise, call strace with address 139: # of suspending procedure block and 140: # value being suspended. 141: pushal 8(ap) # Push pointer to value being suspended. 142: # arg0 in the suspender's argument list 143: # is the descriptor for the suspending 144: # procedure. 145: movl 8(fp),r1 # Get suspender's ap into r1. 146: ashl $3,4(r1),r0 # &arg0 = nargs * 8 147: addl2 $8,r0 # + 8 148: addl2 r1,r0 # + ap 149: pushl 4(r0) # Push second word (the address) of 150: # the descriptor for the procedure block 151: calls $2,_strace # strace(&procblock,&suspending-value) 152: /* 153: * Return from suspending function; resumption will return from suspend. 154: */ 155: tracedone: 156: movl 12(fp),r1 # Get fp of suspending procedure into r1 and 157: movl -4(r1),_line # restore _line and 158: movl -8(r1),_file # _file from the frame. 159: # The duplicated frame must be fixed up. 160: # Specifically, the saved gfp is replaced 161: # by the new gfp, and the value being 162: # suspended replaces arg0, the descriptor 163: # of the suspending procedure. 164: subl3 r1,8(fp),r0 # Calculate distance between fp and ap 165: # in suspender's frame, specifically, 166: # r0 = ap - fp 167: addl2 sp,r0 # sp points at the first word of the 168: # duplicated procedure frame on the 169: # stack. By adding it to r0, r0 points 170: # at nwords word in argument list of 171: # duplicated frame. That is, r0 is 172: # serving as a pseudo ap. 173: subl3 $8,r0,r1 # Point r1 at location of saved gfp 174: # in duplicated frame. 175: movl gfp,(r1) # Replace saved gfp with new gfp value 176: # Calculate address of arg0 via 177: # &arg0 = 178: ashl $2,(r0),r1 # nwords * 4 179: addl2 $4,r1 # + 4 (bytes for nwords word) 180: addl2 r1,r0 # + (pseudo) ap 181: movq 8(ap),(r0) # Replace arg0 with suspending value 182: # 183: movl sp,fp # Point fp at duplicated procedure frame 184: # in preparation for return through it. 185: clrl _boundary # Clear the boundary since control is 186: # going back into Icon code. 187: ret # Return through duplicated frame. This 188: # looks like the original invoke for the 189: # suspending procedure has returned. The 190: # suspended value is left on the top 191: # of the stack. 192: 193: #endif VAX 194: 195: #ifdef PORT 196: DummyFcn(_psusp) 197: #endif PORT 198: #ifdef PDP11 199: / psusp - suspend from an Icon procedure. 200: / Duplicates the most recent generator frame outside the 201: / calling procedure frame. The procedure calling psusp is 202: / suspending, and the saved value of r3 in its frame marker 203: / points to the beginning of the generator frame to be 204: / duplicated. Psusp does not return directly. The caller 205: / is reactivated when an alternative is needed; the return 206: / actually comes from efail. 207: 208: / Register usage: 209: / r0: pointer to top of stack region to be copied, 210: / which is just above the procedure descriptor (arg0) of the 211: / suspending procedure 212: / r2: suspending procedure frame pointer 213: / r3: new generator frame pointer 214: / r4: old generator frame pointer, indexed down to r0 during copy 215: / r5: current procedure frame pointer 216: 217: .globl _deref / dereference a variable 218: .globl _strace / suspend trace routine 219: 220: .globl _boundary / Icon/C boundary address 221: .globl _current / current expression stack 222: .globl _file / current file name 223: .globl _k_level / value of &level 224: .globl _k_trace / value of &trace 225: .globl _line / current line number 226: 227: .globl _psusp 228: _psusp: 229: mov r5,-(sp) / create new procedure frame 230: mov sp,r5 231: mov r4,-(sp) / save registers 232: mov r3,-(sp) 233: mov r2,-(sp) 234: mov r5,-(sp) / create Icon/C boundary 235: mov r5,_boundary 236: 237: / Dereference return value if necessary. 238: 239: mov 6(r5),r1 / get type field of return value into r1 240: bit $F_NQUAL,r1 / if return value is the 241: beq 1f / name of a local variable 242: bit $F_VAR,r1 / or argument, then it 243: beq 1f / needs dereferencing 244: bit $F_TVAR,r1 245: bne 2f 246: mov 8.(r5),r1 / get pointer field into r1 247: br 3f 248: 2: 249: bic $!TYPEMASK,r1 / check type code for substring t.v. 250: cmp $T_TVSUBS,r1 / if not, it doesn't need 251: bne 1f / dereferencing 252: mov 8.(r5),r1 / get pointer field from b_tvsubs 253: mov 8.(r1),r1 / block into r1 254: 3: 255: cmp r1,sp / if pointer is between 256: blo 1f / sp and sbase, it is a local 257: mov _current+2,r0 / or an argument 258: cmp r1,6(r0) 259: bhi 1f 260: mov r5,-(sp) / dereference it 261: add $6,(sp) 262: jsr pc,_deref 263: tst (sp)+ 264: 1: 265: 266: / Calculate addresses of new generator frame. 267: 268: mov sp,r3 / r3 <- pointer to new generator frame 269: mov _k_level,-(sp) / save &level 270: mov _line,-(sp) / save current line number 271: mov _file,-(sp) / and file name 272: mov (r5),r2 / r2 <- pointer to calling procedure frame 273: mov 4(r2),r0 / r0 <- pointer to top of region to be copied 274: asl r0 / (= r2 + 10 + 4*nargs) 275: asl r0 276: add r2,r0 277: add $10.,r0 278: mov -4(r2),r4 / r4 <- generator frame pointer from caller 279: bne 1f / use saved r3 (gfp) - 6 if non-zero, 280: mov -2(r2),r4 / else use saved r4 (efp) - 4 281: cmp -(r4),-(r4) 282: br 2f 283: 1: 284: sub $6,r4 285: br 2f 286: 287: / Copy surrounding expression frame. 288: 289: 1: 290: mov -(r4),-(sp) / copy old generator frame 291: 2: 292: cmp r4,r0 / stop at end of frame 293: bhi 1b 294: 295: / Copy return value of suspending procedure. 296: 297: mov 8.(r5),-(sp) 298: mov 6(r5),-(sp) 299: 300: / Decrement &level; print trace message if &trace is set. 301: 302: dec _k_level 303: tst _k_trace / print trace if &trace != 0 304: beq 1f 305: mov r5,-(sp) / push address of suspending value 306: add $6,(sp) 307: mov -(r0),-(sp) / push address of procedure block 308: jsr pc,_strace / call strace 309: cmp (sp)+,(sp)+ 310: 311: / Return from suspending procedure; reactivation will return from psusp. 312: 313: 1: 314: mov r2,r0 315: mov 2(r0),r1 / r1 <- return pc 316: mov (r0),r5 / restore old registers 317: mov -(r0),r4 318: tst -(r0) / except generator frame pointer 319: mov -(r0),r2 320: mov -(r0),_line 321: mov -(r0),_file 322: clr _boundary / returning to Icon code 323: jmp (r1) / this really suspends 324: #endif PDP11