home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mitsch75.zip / scheme-7_5_17-src.zip / scheme-7.5.17 / src / compiler / documentation / cmpint.txt < prev    next >
Text File  |  2000-03-20  |  49KB  |  1,094 lines

  1. -*- Text -*-
  2.  
  3. $Id: cmpint.txt,v 1.12 2000/03/21 04:29:53 cph Exp $
  4.  
  5.  
  6. Copyright (c) 1991-1992 Massachusetts Institute of Technology
  7.  
  8.  
  9.         Documentation of the C interface to
  10.             MIT Scheme compiled code
  11.                  *DRAFT*
  12.  
  13.  
  14.  
  15.     Remarks:
  16.  
  17. In the following, whenever Scheme is used, unless otherwise specified,
  18. we refer to the MIT Scheme dialect and its CScheme implementation.
  19.  
  20. This file describes the compiled-code data structures and macros
  21. defined in cmpint-md.h and required by cmpint.c and cmpgc.h .
  22.  
  23. cmpaux.txt describes the assembly language code that must be written
  24. to get all of this to work.
  25.  
  26. cmpint-md.h is the machine dependent header file that defines many of
  27. these parameters.  A new version must be written for each
  28. architecture.
  29.  
  30. The "settable" fields in cmpint-md.h are described in the paragraphs
  31. marked with "=>".
  32.  
  33. In the following, word and longword are the size of an item that fills
  34. a processor register, typically 32 bits.  Halfword is half this size,
  35. and byte is typically 8 bits.
  36.  
  37.     Description of compiled-code objects and relevant types:
  38.  
  39. The Scheme compiler compiles scode expressions (often procedure
  40. definitions) into native code.  As its output, it produces Scheme
  41. objects that represent compiled expressions.  To execute these
  42. expressions, they are passed as arguments to scode-eval together with
  43. an environment.
  44.  
  45. Typically these expressions will construct some pointers to compiled
  46. procedures and define them in the environment.  These procedures can
  47. then be invoked normally from the read-eval-print loop, from
  48. interpreted code, or from other compiled code.
  49.  
  50. In the course of their computation, these procedures will need to
  51. call other procedures and then proceed the computation.  In order to
  52. accomplish this, they will push compiled return addresses on the
  53. stack, and these will eventually be popped and "jumped through" to
  54. return.
  55.  
  56. Compiled code and objects referenced by it are collected into
  57. "vector-like" objects called compiled-code blocks.
  58.  
  59. The above four classes of objects (compiled expressions, compiled
  60. procedures, compiled return addresses, and compiled-code blocks) are
  61. implemented using two microcode types:
  62.  
  63. TC_COMPILED_CODE_BLOCK is used to implement compiled-code blocks.  It
  64. is a vector type, that is, it is a pointer type, the word addressed by
  65. the pointer contains the length of the vector (not including the
  66. length header word), and the rest of the words (length) follow at
  67. increasing addresses in memory.  Typically the first word after the
  68. header is a non-marked-vector header, and the instructions follow it.
  69. The non-marked-vector header covers all the instructions, but the
  70. vector may contain arbitrary objects after the instructions, covered
  71. only by the normal vector header.  The optional, additional space at
  72. the end of the block is called the "constants" section, since it is
  73. used, among other things, to keep copies of constant objects used by
  74. the compiled code.  See the picture below for a diagram of the typical
  75. layout.
  76.  
  77. TC_COMPILED_ENTRY is used to implement compiled expressions,
  78. compiled return addresses, compiled procedures, and some other entry
  79. points that the compiler and the compiled-code interface need.  A
  80. compiled entry is a non-standard pointer type described below. 
  81.  
  82.     Description of compiled entries:
  83.  
  84. The address portion of a compiled entry object points to an
  85. instruction in the "middle" of a compiled-code block.
  86.  
  87. In order for the garbage collector to be able to move the whole
  88. block as a unit it must be able to determine the address of the
  89. first word.  Note that this word contains the length of the whole
  90. block, so this need not be specified again.
  91.  
  92. The address of the first word of the block can be found from the
  93. address of the instruction, and a few bytes, currently a halfword
  94. preceding the instruction.  These bytes are called the offset field of
  95. a compiled entry object, and typically encode the distance (in bytes)
  96. between the beginning of the block and the compiled entry.
  97.  
  98. A few bytes preceding the offset field are called the format field and
  99. encode the type of compiled entry (procedure vs. expression, etc.) and
  100. some type-specific information (number of arguments, offset to next
  101. return address on the stack, etc.).
  102.  
  103. The gc-offset field and the format field must be the same size, and
  104. their size is determined by the C typedef of format_word at the
  105. beginning of cmpint-md.h.  Note that, to date, the compiler has only
  106. been ported to systems where this size is 2 bytes (for each), but it
  107. should be possible to port it to systems where these fields are
  108. larger.
  109.  
  110.     Encoding of the offset field:
  111.  
  112. The offset field is decoded as follows:
  113.  
  114. If the low order bit is 0 the offset is a simple offset, ie.
  115. subtracting the offset from the address of the compiled entry
  116. results in the address of the compiled-code block that contains the
  117. entry.
  118.  
  119. If the low order bit is 1, it is a continued offset, ie. subtracting
  120. the offset from the address of the compiled entry results in the
  121. address of another compiled entry whose offset may or may not have a
  122. low bit of 0.
  123.  
  124. The rest of the bits (typically 15) are some encoding of the offset:
  125.  
  126. - If instructions can appear at arbitrary byte addresses (including
  127. odd addresses), this field is the offset itself.
  128.  
  129. - If instructions have alignment constraints (ie. halfword alignment
  130. on MC68K, or longword alignment on many RISCs), this field is the
  131. offset shifted appropriately.  In this way, no bits are wasted, and
  132. the range of offsets is increased.
  133.  
  134. For example,
  135.  
  136. The DEC VAX can have instructions at any byte location.  The 15 bits
  137. are the offset.
  138.  
  139. The MC68020 can have instructions only at halfword boundaries.  The 15
  140. bit field shifted left by 1 is the real offset.  Note that in this
  141. case, if the low bit of the offset field is 0, the offset field is the
  142. real offset.
  143.  
  144. The HP Precision Architecture, and many other RISCs, can have
  145. instructions only at longword boundaries.  The 15 bit field shifted
  146. left by 2 is the real offset.
  147.  
  148.     Encoding of the format field:
  149.  
  150. The preceding bytes encode the kind of compiled entry in the following
  151. way:
  152.  
  153. The format field is further subdivided into two equal sized halves,
  154. used, roughly, for the minimum (high order half) and maximum (low
  155. order half) number of arguments that a compiled procedure will accept.
  156. Inappropriate values for these numbers of arguments imply that the
  157. entry is not a procedure, and then the two halves may be combined to
  158. generate information appropriate to the entry type.  The examples
  159. below assume that the format field is 2 bytes long.
  160.  
  161. - For compiled expressions it is always -1 (0xffff)
  162.  
  163. - For compiled entries it is always -3 or -2 (0xfff[d-e]).  It is -2
  164. for compiler generated entries, -3 for compiler-interface generated
  165. entries.
  166.  
  167. - For compiled return addresses with saved dynamic links it is always
  168. -4 (0xfffc).  The next item on the stack is then a dynamic link.
  169.  
  170. - For the special return address `return_to_interpreter' it is
  171. always -5 (0xfffb).
  172.  
  173. - For all other compiled return addresses, both halves (bytes) must
  174. have their sign bit set, that is, they must appear negative when
  175. sign-extended.  The remaining bits of the high-order half of the field
  176. (all but the sign bit) and all but the two most significant bits of
  177. the low-order half of the field (sign bit and adjacent bit), when
  178. concatenated, form the offset in the stack to the previous (earlier)
  179. return address.  This information is used by the debugger to "parse"
  180. the stack into frames.  The sub-fields are actually concatenated
  181. backwards, with the bits from the high order half being the low order
  182. bits in the result.  If the format field is two bytes long, each half
  183. is a single byte, and the valid range for the high-order half is
  184. 0x80-0xff, while the valid range for the low-order half is 0x80-0xdf
  185.  
  186. - For compiled procedures, the format field describes the arity
  187. (number of parameters) and the format of the frame on the stack:
  188.  
  189. The high order half of the field is (1+ REQ) where REQ is the number
  190. of required arguments.  Note that REQ must such that the resulting
  191. half of the format field does not appear negative!  If the format
  192. field is two bytes long, REQ must be less than 127.
  193.  
  194. The low order half of the field is given by the expression
  195. (* (EXPT -1 REST?) FRAME-SIZE)
  196. where FRAME-SIZE is (+ 1 REQ OPT REST?), REQ is as above, OPT
  197. is the number of named optional arguments, and REST? is 1 if
  198. the procedure has a rest parameter (ie. it is a "lexpr"), or 0
  199. otherwise.  FRAME-SIZE must not appear negative, thus if the format
  200. field is two bytes long, FRAME-SIZE must be less than 127.
  201.  
  202.     Picture of typical compiled-code block and entry:
  203.                            
  204.           ----------------------------------------         
  205.   start_address      | MANIFEST-VECTOR |              tl |         
  206.           ----------------------------------------<---------\
  207.           | NM-HEADER        |              il |         \
  208.           ----------------------------------------<---\          |
  209.           |                     |     \      |
  210.           |                     |    |     |
  211.           |                     |    |     |
  212.           |                     |    |     |
  213.           |         some instructions         |    |     |
  214.           |                     |    |     |
  215.           |                     |    |     |
  216.           |                     |    |     |
  217.           |                     |    |     |
  218.           ----------------------------------------    |     |
  219.           |   format_field_1 |    offset_field_1     |    |     |
  220.           ----------------------------------------    |     |
  221.   entry_address_1 |          movel arg0,reg0         |    |     |
  222.           ----------------------------------------    |     |
  223.           |                     |    |     |
  224.           |                     |    |     |
  225.           |                     |     > il |
  226.           |                     |    |     |
  227.           |          more instructions         |    |     |       
  228.           |                     |    |     |       
  229.           |                     |    |     |       
  230.           |                     |    |     |       
  231.           ----------------------------------------    |      > tl
  232.           |   format_field_2 |    offset_field_2     |    |     |       
  233.           ----------------------------------------    |     |       
  234.   entry_address_2 |    andl pointer_mask,arg0,reg0     |    |     |       
  235.           ----------------------------------------    |     |       
  236.           |                     |    |     |       
  237.           |                     |    |     |       
  238.           |                     |    |     |       
  239.           |                     |    |     |       
  240.           |          more instructions         |    |     |       
  241.           |                     |    |     |       
  242.           |                     |    |     |       
  243.           |                     |     /      |       
  244.          /--->----------------------------------------<---/          |       
  245.         /      |          Scheme object         |          |
  246.        |      ----------------------------------------          |
  247.   "cons-   |      |                     |          |
  248.    tants"  |      |                     |          |    
  249.        |      |                     |          |    
  250.       <      |                     |          |    
  251.        |      |       more Scheme objects         |          | 
  252.   section  |      |                     |          |
  253.        |      |                     |          |
  254.        |      |                     |          |
  255.         \      |                     |          /
  256.          \--->----------------------------------------<----------/
  257.  
  258. Note: The picture above assumes that each machine instruction takes the same
  259. space as a scheme object, and that this is also the combined length of
  260. the gc-offset and format fields.  The type tags are always at the most
  261. significant end of the word, which depending on endianness may be at
  262. the lowest or highest addressed part of the word in memory.  The
  263. picture above depicts them on the left.
  264.            
  265.     Description of picture:
  266.  
  267. [TC_COMPILED_CODE_BLOCK | start_address] would be the object
  268. representing the compiled-code block.
  269.  
  270. [TC_COMPILED_ENTRY | entry_address_1] would represent entry1.
  271.  
  272. [TC_COMPILED_ENTRY | entry_address_2] would represent entry2.
  273.  
  274. 1) Assuming that instructions are longword aligned and that
  275. entry_address_1 is close enough to start_address not to need an
  276. extension, but entry_address_2 is not, then
  277.  
  278. offset_field_1 = ((entry_address_1 - start_address) >> 1)
  279. offset_field_2 = (((entry_address_2 - entry_address_1) >> 1) | 1)
  280.  
  281. note that entry_address_1 - start_address is a multiple of 4 because
  282. of the alignment assumption.
  283.  
  284. 2) Assuming that instructions are halfword aligned and that
  285. entry_address_1 is close enough to start_address not to need an
  286. extension, but entry_address_2 is not, then
  287.  
  288. offset_field_1 = (entry_address_1 - start_address)
  289. offset_field_2 = ((entry_address_2 - entry_address_1) | 1)
  290.  
  291. note that entry_address_1 - start_address is a multiple of 2 because
  292. of the alignment assumption.
  293.  
  294. 3) Assuming that instructions are byte aligned and that
  295. entry_address_1 is close enough to start_address not to need an
  296. extension, but entry_address_2 is not, then
  297.  
  298. offset_field_1 = ((entry_address_1 - start_address) << 1)
  299. offset_field_2 = (((entry_address_2 - entry_address_1) << 1) | 1)
  300.  
  301. The length of the "constants" section is (tl - il).
  302. There are (tl + 1) total words in the object.
  303.  
  304. => Macro PC_ZERO_BITS should be defined to be the number of bits in
  305. instruction addresses that are always 0 (0 if no alignment
  306. constraints, 1 if halfword, etc.).
  307.  
  308. => format_word should be 'typedefd' to be the size of the descriptor
  309. fields.  It is assumed that the offset field and the format field are
  310. the same size.  This definition is unlikely to need modification.
  311.  
  312.     Compiled closures:
  313.  
  314. Most compiled procedures are represented as a simple compiled entry
  315. pointing to the compiled-code block generated by the compiler.
  316.  
  317. Some procedures, called closures, have free variables whose locations
  318. cannot be determined statically by the compiler or the linker.  The
  319. compiler will generate code to construct a tiny compiled-code block on
  320. the fly and make the compiled procedure be an entry point pointing to
  321. this dynamically allocated compiled-code block.
  322.  
  323. For example, consider the following code, appearing at top level,
  324.  
  325.     (define foo
  326.       (lambda (x)
  327.     (lambda (y) (+ x y))))        ;lambda-1
  328.  
  329. The outer LAMBDA will be represented as a compiled entry pointing to
  330. the appropriate block.  The inner LAMBDA cannot be since there may be
  331. more than one instance, each with its independent value for X:
  332.  
  333.     (define foo1 (foo 1))
  334.     (define foo2 (foo 2))
  335.  
  336. Compiled closures are implemented in the following way: The entry
  337. corresponding to the procedure points to a jump-to-subroutine (or
  338. branch-and-link) instruction.  The target of this jump is the code
  339. corresponding to the body of the procedure.  This code resides in the
  340. compiled-code block that the compiler generated.  The free variables
  341. follow the jump-to-subroutine instruction (after aligning to longword).
  342.  
  343. Using this representation, the caller need not know whether it is
  344. invoking a "normal" compiled procedure or a compiled closure.  When
  345. the closure is invoked normally, it jumps to the real code for the
  346. procedure, after leaving a "return address" into the closure object in
  347. a standard place (stack or link register).  This "return address" is
  348. the address of the free variables of the procedure, so the code can
  349. reference them by using indirect loads through the "return address".
  350.  
  351. Here is a stylized picture of the situation, where the procedure
  352. object (closure entry point) is a pointer to <1>.
  353.  
  354. closure object:
  355.     +-------------------------------+
  356.     |                |
  357.     |    <header>            |
  358.     |                |
  359.     +-------------------------------+
  360. <1>    |    jsr instruction to <2>    |
  361.     +-------------------------------+
  362.     |    <value of X>        |
  363.     +-------------------------------+
  364.  
  365. compiled code blok produced by the compiler:
  366.  
  367.     +-------------------------------+
  368.     |                |
  369.     |    ...            |
  370.     |                |
  371.     +-------------------------------+
  372. <2>    |    <code for inner lambda>    |
  373.     |        |        |
  374.     |            V        |
  375.     |                |
  376.     +-------------------------------+
  377.  
  378. The code above could be compiled as (in pseudo-assembly language, in
  379. which & denotes an immediate value):
  380.  
  381.     const    format-word:0x0202;gc-offset:??
  382. foo:    
  383.     mov    rfree,reg0
  384.     mov    &[TC_MANIFEST_CLOSURE | 4],reg1    ; gc header
  385.     mov    reg1,0(reg0)
  386.     mov    &[format_field | offset_field],reg1    ; entry descriptor
  387.     mov    reg1,NEXT_WORD(reg0)
  388.     mov    &[JSR absolute opcode],reg1    ; jsr absolute opcode/prefix
  389.     mov    reg1,2*NEXT_WORD(reg0)
  390.     mova    lambda-1,reg1            ; entry point
  391.     mov    reg1,3*NEXT_WORD(reg0)
  392.     mov    arg1,4*NEXT_WORD(reg0)        ; x
  393.     mov    &5*NEXT_WORD,reg1
  394.     add    reg0,reg1,rfree
  395.     mov    &[TC_COMPILED_ENTRY | 2*NEXT_WORD],reg1
  396.     add    reg0,reg1,retval
  397.     ret
  398.  
  399.     const    format-word:0xfffe;gc-offset:??
  400. lambda-1:
  401.     mov    arg1,reg0            ; y
  402.     mov    x_offset(retlnk),reg1        ; x    x_offset = 0
  403.     add    reg1,reg0,reg0
  404.     mov    reg0,retval
  405.     ret
  406.  
  407. A more detailed picture of the closure object would be:
  408.  
  409.     ----------------------------------------
  410.     | MANIFEST-CLOSURE |                 4 |
  411.     ----------------------------------------
  412.     |   format_field   |  gc_offset_field  |    ;format = 0x0202
  413.     ----------------------------------------    ;offset = encode(8)
  414. entry    |   JSR absolute opcode                |
  415.     ----------------------------------------
  416.     |   address of lambda-1                |
  417.     ----------------------------------------    ;address of retadd
  418. retadd    |   value of x                         |    ; -> retlnk before
  419.     ----------------------------------------    ; entering lambda-1
  420.  
  421. The following macros are used to manipulate closure objects:
  422.  
  423. => COMPILED_CLOSURE_ENTRY_SIZE specifies the size of a compiled
  424. closure entry (there may be many in a single compiled closure block)
  425. in bytes.  In the example above this would be 12 bytes (4 total for
  426. the format and gc offset fields, 4 for JSR opcode, and 4 for the
  427. address of the real entry point).
  428.  
  429. => EXTRACT_CLOSURE_ENTRY_ADDRESS is used to extract the real address
  430. of the entry point from a closure object when given the address of the
  431. closure entry.  Note that the real entry point may be smeared out over
  432. multiple instructions.  In the example above, given the address the
  433. word labeled ENTRY, it would extract the address of LAMBDA-1.
  434.  
  435. => STORE_CLOSURE_ENTRY_ADDRESS is the inverse of
  436. EXTRACT_CLOSURE_ENTRY_ADDRESS.  That is, given the address of a
  437. closure entry point, and a real entry point, it stores the real entry
  438. point in the closure object.  In the example above, given the address
  439. of the word labeled ENTRY, and a different entry point, say for
  440. LAMBDA-2, it would make the closure jump to LAMBDA-2 instead. This is
  441. used to relocate closures after garbage collection and similar
  442. processes.
  443.  
  444.     Some caveats:
  445.  
  446. - The code for lambda-1 described above does not match what the compiler
  447. would currently generate.
  448.  
  449. The current parameter-passing convention specifies that all the state
  450. needed to continue the computation at a procedure's entry point must
  451. be on the stack and all the information on the stack must be valid
  452. objects (for GC correctness in case of interrupt, more on this below).
  453. Thus the contents of retlnk must be pushed on the stack as a valid
  454. object, and this is done by reconstructing the closure object whose
  455. datum field encodes the address of entry and whose type tag is
  456. TC_COMPILED_ENTRY, and then pushing it onto the stack.  Note that on
  457. some machines, the return address for the subroutine-call instruction
  458. is pushed on the stack by the hardware, and thus this value might have
  459. to be popped, adjusted, and re-pushed if it cannot be adjusted in
  460. place.
  461.  
  462. The code for lambda-1 would then be closer to:
  463.  
  464. lambda-1:
  465.     sub    retlnk,&retadd-entry,retlnk
  466.     or    &[TC_COMPILED_ENTRY | 0],retlnk,retlnk ; set type code
  467.     push    retlnk
  468.     <interrupt check>                ; more on this below
  469.     mov    arg1,reg0
  470.     mov    top_of_stack,reg1
  471.     and    &[0 | -1],reg1,reg1            ; remove type code
  472.     mov    x_offset+retadd-entry(reg1),reg1
  473.     add    reg1,reg0,retval
  474.     pop                        ; the closure object
  475.     ret
  476.  
  477. Note that (retadd-entry) is a constant known at compile time, and is the
  478. same for the first entry point of all closures.  On many machines, the
  479. combination sub/or can be obtained with a single add instruction:
  480.     add    &([TC_COMPILED_ENTRY | 0]-(retadd-entry)),retlnk,retlnk
  481.  
  482. This value is called the "magic constant", encoded in the first few
  483. instructions of a closure's code.
  484.  
  485. - Multiple closures sharing free variables can share storage by having
  486. multiple entry points (multiple JSR instructions) in the closure
  487. object.  The compiler occasionally merges multiple related closures
  488. into single objects.
  489.  
  490. A complication arises when closure entry points are not necessarily
  491. long-word aligned, since the compiler expects all variable offsets
  492. (like x_offset above) to be long-word offsets.
  493.  
  494. This problem only occurs on machines where instructions are not all
  495. long-word aligned and for closures with multiple entry points, since
  496. the first entry point is guaranteed to be aligned on a long-word
  497. boundary on all machines.
  498.  
  499. The current solution to this problem, on those machines on which it is
  500. a problem, is to choose a canonical entry point (the first one)
  501. guaranteed to be aligned properly, and push that on the stack on entry
  502. to a closure's code.  The compiler keeps track of what actual entry
  503. point the code belongs to even though the value on the stack may
  504. correspond to a different entry point.
  505.  
  506. The "magic constant" becomes an entry-point dependent value, since each
  507. return address may have to be bumped back to the first entry point in
  508. the closure object rather than to the immediately preceding entry point.
  509.  
  510.     Interrupts:
  511.  
  512. Scheme polls for interrupts.  That is, interrupt processing is divided
  513. into two stages:
  514.  
  515. - When an asynchronous interrupt arrives, the handler (written in C)
  516. invoked by the operating system sets a bit in a pending-interrupts
  517. mask, stores the relevant information (if any) in a queue, and
  518. proceeds the computation where it was interrupted.
  519.  
  520. - The interpreter and compiled code periodically check whether an
  521. interrupt is pending and if so, invoke an interrupt handler written in
  522. Scheme to process the interrupt.  The interpreter checks for
  523. interrupts at the apply point.  Compiled code currently checks at
  524. every procedure entry (including loops) and at every continuation
  525. invocation.  This may change in the future, although it will always be
  526. the case that interrupts will be checked at least once in each
  527. iteration of a loop or recursion.
  528.  
  529. Compiled code does not actually check the bits in the mask to
  530. determine whether an interrupt is pending.  It assumes that the
  531. first-level interrupt handler (the handler written in C) not only sets
  532. the bits, but also changes the copy of the MemTop (top of consing
  533. area) pointer used by the compiler so that it will appear that we have
  534. run out of consing room.  Thus compiled code merely checks whether the
  535. Free pointer (pointer into the heap) is numerically larger than the
  536. MemTop pointer, and if so it invokes an assembly-language or C utility
  537. that decides whether a garbage collection is needed or an interrupt
  538. must be processed.  Sometimes this utility will decide that the
  539. interrupt need not be processed (it is disabled, for example), and
  540. will need to return to the compiled code skipping the interrupt check
  541. since otherwise we will get into an infinite loop.
  542.  
  543. The interrupt check code is fixed (so that the handler can determine
  544. how much code to skip) and comes in two varieties: closure interrupt
  545. code, and normal-entry (other) interrupt code.  Normal-entry interrupt
  546. code is always the first code in an entry point (procedure or
  547. continuation, but not closure code) and merely compares the Free and
  548. MemTop pointers and branches.  Closure code does this comparison after
  549. setting up the closure object.  Closure code assumes that the closure
  550. object is in the first parameter location (the closure itself is
  551. argument 0) so that free variables can be fetched.  Thus a closure
  552. label must first set this up correctly, and then check for interrupts.
  553.  
  554. In pseudo-assembly language, a "normal" entry might look like
  555.  
  556. gc_or_int    LOADI    #interrupt-handler-index,rindex
  557.         LOADA    entry,rentry
  558.         JMP    scheme-to-interface
  559.         format word and gc word for the entry
  560. entry        CMP    Free,MemTop
  561.         BGE    gc_or_int
  562. after_entry    <actual code for the entry>
  563.  
  564. a "closure" entry might look like (this is not in the closure object,
  565. but in the code block at which the closure object points)
  566.  
  567. gc_or_int    LOADI    #interrupt-handler-index,rindex
  568.         LOADA    entry,rentry
  569.         JMP    scheme-to-interface
  570.         format word and gc word for the entry
  571. entry        ADDI    offset,retadd,ret_add    ; bump ret. add. to entry point
  572.         ORI    #[TC_CLOSURE | 0],ret_add
  573.         PUSH    ret_add            ; arguments on the stack
  574.         CMP    Free,MemTop
  575.         BGE    gc_or_int
  576. after_entry    <actual code for the entry>
  577.  
  578. The following macros are used by the C utility and handler to
  579. determine how much code to skip:
  580.  
  581. => ENTRY_SKIPPED_CHECK_OFFSET is the number of bytes between
  582. entry and after_entry in a normal entry.
  583.  
  584. => CLOSURE_SKIPPED_CHECK_OFFSET is the number of bytes
  585. between entry and after_entry in a closure entry.
  586.  
  587. => ENTRY_PREFIX_LENGTH is the number of bytes between gc_or_int and
  588. entry in a normal entry, not counting those taken up by the format
  589. word and the gc word.
  590.  
  591.     Important considerations:
  592.  
  593. The Scheme compiled code register set includes the current copy of the
  594. Free pointer, but does not include the copy of MemTop, although it is
  595. mostly constant.  The reason is that the C-level interrupt handler
  596. does not have convenient access to the register set at the point of
  597. the interrupt, and thus would have a hard time changing the version of
  598. MemTop used by compiled code at the point of the interrupt.  Thus the
  599. copy of MemTop used by compiled code is kept in memory.
  600.  
  601. On machines where register-to-memory comparisons can be done directly
  602. this is no problem, but on load/store architectures (most RISCs for
  603. example), this is not feasible.  Furthermore, most RISCs have a few
  604. cycles of delay for memory loads, and adjacent instructions may not be
  605. interlocked by the hardware.  Thus a sequence like
  606.  
  607.     LOAD    Memory_MemTop,Rtemp
  608.     CMP    Rfree,Rtemp
  609.     BGE    gc_or_int
  610.  
  611. may be very slow and NOPs may have to be inserted explicitly between
  612. the LOAD and CMP instructions to make the code work.
  613.  
  614. Since Scheme's interrupt response is not immediate, and polling is
  615. frequent, the following sequence can be used instead:
  616.  
  617.     CMP    Rfree,Rmemtop
  618.     BGE    gc_or_int
  619.     LOAD    Memory_MemTop,Rmemtop
  620.  
  621. Where Rmemtop is a register that holds a recent value of MemTop and is
  622. reloaded at every interrupt check.  Thus interrupt processing will
  623. start at the second interrupt check after the actual interrupt comes
  624. in.  In other words, if the sequence of entry points executed
  625. dynamically is ep1, ep2, ep3, and an asynchronous interrupt occurs
  626. between ep1 and ep2, the interrupt handler will not be invoked until
  627. ep3, rather than ep2.
  628.  
  629. This instruction sequence eliminates the need to wait for the LOAD to
  630. complete, and the LOAD will have completed (or will be handled by the
  631. hardware's interlock mechanism) by the next check since at least one
  632. instruction (a branch instruction), and often many more, will
  633. intervene.
  634.  
  635. Note that this delayed checking does not affect garbage collection
  636. interruptions since MemTop is constant between garbage collections,
  637. and thus the value being loaded is always the same, in the absence of
  638. asynchronous interrupts.
  639.  
  640. Various operating systems allow the signal handler convenient access
  641. to the interrupted code's register set.  In such a situation, the LOAD
  642. instruction can be eliminated and the C-level interrupt handler can
  643. modify Rmemtop directly.  Rmemtop should be chosen from the
  644. caller-saves convention (super-temporary) registers if possible, since
  645. these registers must be explicitly saved by the signal handler, rather
  646. than implicitly by the calling convention.
  647.  
  648.     Interrupts and closures that share storage:
  649.  
  650. If an interrupt arrives on entry to the closure, the correct closure
  651. object must be reconstructed so that the computation will continue
  652. correctly on return from the interrupt.  The code to reconstruct the
  653. correct closure is also issued by the compiler, which at compile time
  654. maintains the identity of each closure and the distance to the
  655. canonical closure used for environment purposes.
  656.  
  657. If the interrupt is dismissed, instead of processed, we need to
  658. continue the computation bypassing the interrupt checking code in
  659. order to avoid an infinite loop.  This is what the macro
  660. CLOSURE_SKIPPED_CHECK_OFFSET is used for.  We must skip the preamble
  661. of the closure code and emulate part of it, that is, adjust the object
  662. on top of the stack to be the closure object that the code expects to
  663. have there.  This can be done by extracting the magic constant from
  664. the entry point, and bumping the corresponding return address by this
  665. value.  The macro ADJUST_CLOSURE_AT_CALL accomplishes this feat on
  666. those machines where it is needed.
  667.  
  668. => ADJUST_CLOSURE_AT_CALL, when given an entry point and a location,
  669. adjusts the closure object stored at location so that it is the
  670. closure object that the entry point expects on top of the stack.  On
  671. machines where all instructions are long-word aligned, it is a NOP, on
  672. other machines (eg. 68k, VAX), it extracts the magic constant from the
  673. closure's code, and uses it to construct the appropriate closure
  674. object.
  675.  
  676.     External calls from compiled code:
  677.  
  678. Many calls in scheme code (and particularly in large programs) are
  679. calls to independently compiled procedures or procedures appearing at
  680. the top level of a file.  All these calls are calls to potentially
  681. unknown procedures since the names to which they are bound can be
  682. unbound or redefined dynamically at run time.  
  683.  
  684. The code issued by the compiler for such an external call must take
  685. into account the possibility of the lack of a valid value, run-time
  686. definition, and run-time assignment.  This is done as follows:
  687.  
  688. For each external procedure called with a fixed number of arguments
  689. (more on this below), a small contiguous space is allocated in the
  690. "constants" section of the compiled-code block.
  691.  
  692. This space initially contains the name of the external variable
  693. whose value is being invoked, and the number of arguments (+ 1 for
  694. technical reasons) being passed to the procedure.
  695.  
  696. These locations will be replaced at load time by an absolute jump to
  697. the correct entry point of the called procedure if the number of
  698. arguments matches and the callee (target procedure) is compiled, or by
  699. an absolute jump to some utility code generated on the fly to
  700. interface the caller and the callee (called a trampoline procedure).
  701. Note that both procedures need not be in the same compiled-code block.
  702.  
  703. The fixed code in the code section of the compiled-code block contains
  704. a pc-relative branch instruction to this space allocated in the
  705. "constants" section.
  706.  
  707. When the compiled-code block is loaded, a linker that resolves these
  708. references and replaces the name and arguments with machine-specific
  709. code to do the absolute jump is invoked.  The linker also records the
  710. locations of all such jump instructions so that a subsequent
  711. redefinition or assigment of the same name will cause the jump
  712. instruction to be replaced by a new one to the correct value.  Note
  713. that the number of arguments needs to be checked only by the linker,
  714. so no instructions are issued to check it at run time.  It is for this
  715. reason that the number of arguments is part of the information left by
  716. the compiler in the "constants" section.
  717.  
  718. These entries in the "constants" section are called execute caches,
  719. operator links, or "UUO" links for historical reasons.  They must be
  720. large enough to contain the instructions required for an absolute jump
  721. (and possibly some delay slot instructions in a RISC-style machine),
  722. and the number of arguments passed in the call.  This number of
  723. arguments is not used in the call sequence, but is used by the linker
  724. when initially linking and when relinking.
  725.  
  726. Execute caches are contiguous in the "constants" section, and the
  727. whole lot is preceded by a GC header of type TC_LINKAGE_SECTION which
  728. contains two fields.  The least-significant halfword of the header
  729. contains the size in longwords of the execute-cache section (note that
  730. each cache entry may take up more than one longword).  The remaining
  731. bits (ignoring the type code) MUST be 0.  If a file makes enough
  732. external calls that this halfword field cannot hold the size, the
  733. links caches must be separated into multiple blocks each with its own
  734. header.
  735.  
  736. Occasionally a procedure is called with more than one number of
  737. arguments within the same file.  For example, the LIST procedure may
  738. be called with three and seven arguments in the same file.  In this
  739. case there would be two execute caches for LIST.  One would correspond
  740. to the argument count of three, and the other to seven.
  741.  
  742. As an example, consider the code generated for
  743.  
  744. (sort <some list> <some predicate>)
  745.  
  746. where sort is the "global" procedure sort.
  747.  
  748. The code section would contain
  749.     
  750.     <compute some predicate>
  751.     push    <some predicate>
  752.     <compute some list>
  753.     push    <some list>
  754.     branch    sort-uuo-link
  755.  
  756. In the constants section there would be a label that would contain the
  757. following after linking
  758.     
  759. sort-uuo-link:
  760.     jump    sort        ; Absolute address for sort
  761.     3            ; Number of arguments + 1
  762.  
  763. Before linking it would contain
  764.  
  765. sort-uuo-link:
  766.     SORT            ; The symbol SORT
  767.     3            ; Number of arguments + 1
  768.  
  769. This assumes that the absolute jump instruction takes one word.  If it
  770. takes more, the appropriate padding would have to be inserted between
  771. the symbol SORT and the number 3.  On machines where instructions are
  772. not necessarily longword aligned (MC68020 and VAX, for example), the
  773. padding bits for the instruction can be used to contain the argument
  774. count.  Note that the order of the instructions and the count are
  775. machine dependent, although typically the instructions precede the
  776. count.
  777.  
  778. The following macros are used to manipulate execute caches:
  779.  
  780. => EXECUTE_CACHE_ENTRY_SIZE specifies the length (in longwords) of an
  781. execute-cache entry.  This includes the size of the instructions and
  782. the argument count.  For the example above it would be 3, assuming
  783. that the jump instruction and the absolute address take two words
  784. together (the third is for the argument count).  Note that on RISC
  785. machines, this size may have to include the size of the branch delay
  786. slot instruction.
  787.  
  788. => EXTRACT_EXECUTE_CACHE_ARITY specifies how to read the argument
  789. count from an execute-cache entry when given the address of the entry.
  790. In the above example, it would extract 3 from the address labeled
  791. sort-uuo-link.
  792.  
  793. => EXTRACT_EXECUTE_CACHE_SYMBOL specifies how to read the symbol from
  794. an execute-cache entry (before it is actually linked) when given the
  795. address of an entry.  In the above example, it would extract the
  796. symbol SORT from sort-uuo-link.
  797.  
  798. => EXTRACT_EXECUTE_CACHE_ADDRESS fetches the real entry point stored
  799. in an execute-cache entry when given the address of the entry.  In the
  800. above example, it would extract the entry point of the sort procedure
  801. when given the address of the jump instruction (labeled as
  802. sort-uuo-link).
  803.  
  804. => STORE_EXECUTE_CACHE_ADDRESS is the inverse of this, ie. when given a
  805. target entry point and the address of an execute cache entry, it
  806. stores the entry point there.  In the above example, given a new entry
  807. point for sort, and sort-uuo-link, it would modify the jump
  808. instruction to jump to the new location.
  809.  
  810. => STORE_EXECUTE_CACHE_CODE stores the fixed instructions (opcodes),
  811. if any, in an execute cache cell.  If the opcodes depend on the actual
  812. target address, this macro should be a NOP, and all the work should be
  813. done by STORE_EXECUTE_CACHE_ADDRESS.  These two macros are separated
  814. to avoid extra work at garbage collection time on architectures where
  815. some or all of the code need not change.  In the example above, this
  816. macro would store the jump opcode.
  817.  
  818.  
  819.     Trampolines:
  820.  
  821. Trampolines are the linker-generated procedures that interface the
  822. caller and the callee when they are not directly compatible.  They may
  823. not be directly compatible because the callee may not exist, may not
  824. be a compiled procedure, or may expect arguments in different
  825. locations.  Trampolines typically call a C or assembly-language
  826. procedure to reformat the argument list or invoke the error handler.
  827. C procedures are invoked using the scheme_to_interface (and
  828. trampoline_to_interface) code described below.
  829.  
  830. A trampoline is similar to a compiled closure in that it is a small
  831. compiled-code block with some additional storage needed by the
  832. trampoline handler (like the actual procedure being invoked, the
  833. variable that is unbound, or the number of arguments being passed).
  834. The code typically invokes an out-of-line handler passing it the
  835. address of the storage section, and an index into a table of C or
  836. assembly language procedures that handle the actual transfer.
  837.  
  838. A typical trampoline looks like
  839.  
  840.     ----------------------------------------
  841. block    | MANIFEST-VECTOR  |                 6 | (4 + words of storage)
  842.     ----------------------------------------
  843.     | NM-HEADER        |                 3 | (fixed)
  844.     ----------------------------------------
  845.     |   format_field   |    offset_field   | (fixed)
  846.     ----------------------------------------
  847. entry    |   LOADI   #index,rindex              | (index varies)
  848.     ----------------------------------------
  849.     |   JSR     trampoline_to_interface    | (fixed)
  850.     ----------------------------------------
  851. retadd    |   first word of storage              | (variable)
  852.     ----------------------------------------
  853.     |   second word of storage             | (variable)
  854.     ----------------------------------------
  855.  
  856. => TRAMPOLINE_ENTRY_SIZE is the size in longwords of the compiled-code
  857. portion of a trampoline.  It is similar to COMPILED_CLOSURE_ENTRY_SIZE
  858. but in longwords, and will typically represent less storage since an
  859. absolute address is not needed (or desirable).  It must include the
  860. format word and the GC offset for the entry.  In the example above it
  861. would be 3.  Note that it must be an integer number of longwords, so the
  862. code should be padded if necessary.
  863.  
  864. => TRAMPOLINE_ENTRY_POINT returns the address of the entry point of a
  865. trampoline when given the address of a trampoline's block, i.e. the
  866. address of the word that will contain the manifest vector header.  In
  867. the picture above, when given the address of the byte labeled `block',
  868. it will return the address of the byte labeled `entry'.
  869.  
  870. => TRAMPOLINE_STORAGE returns the address of the first storage word in
  871. a trampoline when given the addres of the first instruction (the entry
  872. point of the trampoline).  In the picture above it would return the
  873. address of the word labeled `retadd' when given the address of the
  874. word labeled `entry'.
  875.  
  876. Most versions of cmpint-md.h define the last two macros in the same
  877. way, in terms of TRAMPOLINE_BLOCK_TO_ENTRY, which is used only for
  878. this purpose.  The definitions that use TRAMPOLINE_BLOCK_TO_ENTRY
  879. assume that the first instruction of a trampoline is aligned on a
  880. longword boundary.  If this is the case, you can define
  881. TRAMPOLINE_BLOCK_TO_ENTRY appropriately and use the definitions of
  882. TRAMPOLINE_ENTRY_POINT and TRAMPOLINE_STORAGE from another machine.
  883. TRAMPOLINE_BLOCK_TO_ENTRY is the number of longwords from the start
  884. of a trampoline's block (the manifest vector header in the picture
  885. above), to the first instruction, which must be longword aligned.
  886. This will typically be 3 since there are two scheme header words, and
  887. the gc and format word typically take one longword together.
  888.  
  889. => STORE_TRAMPOLINE_ENTRY stores the "compiled" code into an "empty"
  890. trampoline.  It is given the address of the entry point, and the index
  891. of the C procedure to invoke (they are all in a table), and stores the
  892. machine code necessary to invoke scheme_to_interface (or
  893. trampoline_to_interface), passing the index and the address of the
  894. trampoline storage area as parameters.  In the example above this
  895. macro would store the LOADI (load immediate) and JSR instructions.
  896.  
  897.     Compiled code and processor caches:
  898.     
  899. Many modern computers have processor caches that speed up the average
  900. memory reference if the code exhibits sufficient locality in its
  901. reference patterns.  In order to obtain increased performance at a
  902. lower cost, many processors have split caches for instructions and
  903. data that are not guaranteed to be consistent, ie. they are not
  904. necessarily invisible to the programmer.
  905.  
  906. This presents problems for self-modifying code and for dynamic loaders
  907. and linkers, since instructions are stored using data references (and
  908. therefore the data cache), but the instruction cache may not reflect
  909. the updates.  Modern hardware with split caches often provides some
  910. way to synchronize both caches so that the operating system can
  911. guarantee correct operation of newly-loaded programs.
  912.  
  913. The Scheme compiled code support performs some of the same tasks that
  914. operating systems do, and therefore runs into these problems.
  915.  
  916. The ways in which the consistency problem arises in the Scheme system
  917. are:
  918.  
  919. - Newly allocated instructions.  The compiler can be invoked
  920. dynamically, compiled code can be loaded dynamically into freshly
  921. allocated storage, and compiled closures are created dynamically.  The
  922. instruction cache must reflect the changes made to memory through the
  923. data cache.  The operating system's program loader must solve
  924. precisely this problem.
  925.  
  926. - Execute caches may change their contents.  Execute caches contain
  927. jump instructions to the appropriate code, but these instructions may
  928. change when the corresponding variables are assigned.  If the
  929. instruction cache is not updated, the wrong code may be entered on
  930. subsequent calls.  Operating systems with dynamic linking must solve
  931. this problem as well.
  932.  
  933. - Code is moved by the garbage collector, since code space is not
  934. separate from data space and static.  If the caches are not
  935. synchronized after a garbage collection, subsequent instruction
  936. fetches may result in the execution of incorrect instructions.
  937. The operating system must solve this problem when it re-allocates
  938. virtual memory pages.
  939.  
  940. The problem can be solved by synchronizing the caches in the
  941. appropriate places.  The relevant places in the Scheme system have
  942. been identified, and use two machine-dependent macros to
  943. synchronize both caches or flush the instruction cache.
  944.  
  945. => FLUSH_I_CACHE is used to flush the portion of the I-cache that
  946. Scheme code addresses may be in, or alternatively, to guarantee that
  947. the I-cache contains only valid data.  It may flush/synchronize the
  948. entire I-cache instead, if it is easier.  It is used after garbage
  949. collections and image loads.
  950.  
  951. => FLUSH_I_CACHE_REGION is used to flush or synchronize a region of
  952. the address space from the I-cache.  It is given the base address and
  953. the number of long-words of the region of memory that has just been
  954. modified and whose new contents must be copied into the I-cache for
  955. correct execution.
  956.  
  957. It is used after updating an execute cache while running between
  958. garbage collections.  It is not used during garbage collection since
  959. FLUSH_I_CACHE will be used afterwards.
  960.  
  961. These macros need not be defined if it is not needed to flush the
  962. cache.  A NOP version is provided by the code when they are not
  963. defined in cmpint-md.h
  964.  
  965. Note that on some machine/OS combinations, all system calls cause a
  966. cache flush, thus an innocuous system call (eg., a time reading call)
  967. may be used to achieve this purpose.
  968.  
  969. Many modern machines only make their cache flushing instructions
  970. available to the operating system (they are priviledged instructions),
  971. and some operating systems provide no system calls to perform this
  972. task.  In the absence of information on the structure and
  973. characteristics of the cache (the information could be used to write
  974. flushing routines), the Scheme compiler and system may have to be
  975. changed in order to run on such machines.  Here is a set of changes
  976. that will bypass the problem, at the expense of some functionality and
  977. perhaps performance:
  978.  
  979. - Change the entry code for closures and execute caches.
  980.  
  981. The code in execute caches can be changed from
  982.  
  983.     jump    target
  984.  
  985. to
  986.  
  987.     jsr    fixed-utility-routine
  988.     target address
  989.  
  990. where fixed-utility-routine extracts target address from the return
  991. address and invokes it.  The same change can be made to the closure
  992. entry code.
  993.  
  994. This solves the problem of assignment to variables with execute
  995. caches.
  996.  
  997. This change can be done quite easily since the format of closures and
  998. execute caches is already machine dependent, and all the accessors,
  999. constructors, and mutators have been abstracted into macros or can
  1000. be easily rewritten in the compiler.
  1001.  
  1002. - Change the storage management scheme to accomodate a code area that
  1003. is never garbage collected so that code, once placed there, never
  1004. moves.
  1005.  
  1006. This would constitue a major change to the system.  The main problem
  1007. that this change would present is the following:
  1008.  
  1009. Closures are data structures created and dropped on the fly, thus they
  1010. cannot be allocated from a region of memory that is never reclaimed.
  1011. Thus closures would have to be allocated from data space, and could no
  1012. longer contain instructions.  This implies that the format of entry
  1013. points would have to change, since the relevant information would no
  1014. longer consist of a single address, but two, ie.  the address of the
  1015. code in code space and the address of the data in data space.  This
  1016. would imply many changes to the compiler for there are implicit
  1017. assumptions throughout that compiled entry points take no space
  1018. besides the space taken by the code.  In particular, simple closures
  1019. would disappear, and multi-closures would have to be redesigned.
  1020.  
  1021.     Implementation registers and utilities
  1022.  
  1023. The C runtime support maintains some state variables that Scheme code
  1024. may need to access.  In order to make these variables easily
  1025. accessible to both languages, all these variables are collected into a
  1026. contiguous vector (the register block) accesible by both.  The C
  1027. variable "Registers" holds the address of this vector, and while
  1028. compiled Scheme code is being executed, a processor register also
  1029. holds the address of the vector.  Among other data, the register block
  1030. contains the memory version of MemTop, the interpreter's expression
  1031. and environment registers, the interrupt mask and pending interrupt
  1032. words.
  1033.  
  1034. In addition, the compiler occasionally needs static memory locations
  1035. into which it can spill the values contained in processor registers.
  1036. Rather than using another register to hold the address of the spill
  1037. locations, these are allocated on the same vector as the register
  1038. block, and the register that holds the address of the register block
  1039. can be used to access the spill locations as well.
  1040.  
  1041. Compiled code also needs to invoke assembly language and C utilities
  1042. to perform certain tasks that would take too much space to code
  1043. in-line.  Rather than choosing fixed addresses for these routines, or
  1044. having to update them every time a piece of code is loaded or dumped,
  1045. a register is reserved to hold the address of one of them, and the
  1046. distance between them is pre-determined, so that compiled code can
  1047. invoke any of them by adding an offset to the value in the register
  1048. and jumping there.
  1049.  
  1050. On processors with few registers (eg. 68k), it would be wasteful to
  1051. reserve two registers in this fashion.  Both registers are therefore
  1052. merged.  Yet another section of the register block array is reserved
  1053. for utility procedures, and appropriate jump instructions are placed
  1054. there so that compiled code can invoke the utilities by jumping into
  1055. the register block array.
  1056.  
  1057. The following macros define the sizes of the various areas of the
  1058. array.  None of them need to be defined except to override the
  1059. default.  The default assumes that there are enough processor
  1060. registers that another one can be reserved to point to the utility
  1061. handles.
  1062.  
  1063. => COMPILER_REGBLOCK_N_FIXED is the size of the register block
  1064. section of the array.  It must accomodate at least as many locations
  1065. as the interpreter expects to have.
  1066.  
  1067. => COMPILER_REGBLOCK_N_TEMPS is the number of spill locations.
  1068.  
  1069. => COMPILER_TEMP_SIZE is the size (in long words) of the contents of a
  1070. floating point register if different from a double.  For example, an
  1071. MC68881 saves registers in 96 bit (3 longword) blocks.  The default is
  1072. fine for most machines.
  1073.  
  1074. => COMPILER_REGBLOCK_EXTRA_SIZE is the additional size (in longwords)
  1075. to be reserved for utility handles.  It is typically defined the
  1076. following way as (COMPILER_REGBLOCK_N_HOOKS * COMPILER_HOOK_SIZE).
  1077.  
  1078. => COMPILER_REGBLOCK_N_HOOKS is the maximum number of utility handles.
  1079.  
  1080. => COMPILER_HOOK_SIZE is the size in longwords of a utility handle (an
  1081. absolute jump instruction).
  1082.  
  1083. => Macro ASM_RESET_HOOK can be used to initialize the register block
  1084. array.  It is invoked at boot time.
  1085.  
  1086.     Miscellany:
  1087.  
  1088. Macro IN_CMPINT_C, defined in cmpint.c, can be used to conditionally
  1089. include code (extern procedures) needed by the port.  It is only
  1090. defined when cmpint-md.h is included by cmpint.c .
  1091.  
  1092. => Macro COMPILER_PROCESSOR_TYPE identifies the processor type.  It
  1093. should be unique for each kind of processor.
  1094.