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 / safety.txt < prev    next >
Text File  |  2000-03-20  |  11KB  |  227 lines

  1. -*- Text -*-
  2.  
  3. $Id: safety.txt,v 1.4 2000/03/21 04:29:53 cph Exp $
  4.  
  5.         COMPILER SAFETY INFORMATION 
  6.         Liar versions 4.77 and later
  7.  
  8. This article describes how to control the compilation process in order
  9. to achieve the desired mix of safety, debuggability, and speed.
  10.  
  11. The task of the native-code compiler is to translate a source (or
  12. Scode) program into the native machine language in order to make the
  13. program run faster than when interpreted.
  14.  
  15. Although a straight-forward translation speeds the program
  16. significantly, much of the achievable performance comes from
  17. optimizations that the compiler can perform after statically analyzing
  18. the program text.  There is a limit, however, to the extent of the
  19. information that can be collected statically, and, in order to achieve
  20. higher performance (often desired, occasionally necessary), the
  21. compiler can be directed to assume additional information that is not
  22. apparent after analyzing the program text.
  23.  
  24. Compilation switches are (global) variables whose value when the
  25. compiler is run determines how the compilation proceeds.  Some of the
  26. switches provide information that cannot be deduced statically and
  27. allow the relaxation of some runtime consistency checking and the
  28. collection of information to be displayed when an error is detected
  29. and signalled.  Relaxing the runtime constraints often makes the
  30. generated code smaller and faster, but may cause problems if the
  31. program being compiled has not been fully debugged, or is invoked with
  32. inappropriate arguments at run time.
  33.  
  34. Safety (correctness) can primarily be compromised by eliminating
  35. checks that the program should perform at runtime.  These checks
  36. are divided into a few categories:
  37.  
  38. - Heap availability checks.  Programs need to invoke the storage
  39. manager (garbage collector) when they need more memory than is
  40. available.  Each time that storage is needed, its availability should
  41. be checked.  If this is not done, the system may be damaged.
  42.  
  43. - Stack availability checks.  Storage is divided into a heap used to
  44. allocate objects with indefinite extent, and a stack used for
  45. procedure call frames with dynamic extent
  46. (call-with-current-continuation copies the stack when invoked).
  47. Availability of storage must be checked in the appropriate region.  A
  48. very deep recursion may cause the stack to overflow, and this
  49. condition must be checked in order to avoid overwriting other regions
  50. of memory.
  51.  
  52. - Type checks.  Scheme is a strongly (albeit dynamically) typed
  53. language.  Operations are only defined on certain types of objects,
  54. and a program is in error if it attempts to operate on the wrong type
  55. of data.
  56.  
  57. - Range checks.  The type of some arguments to a procedure may be
  58. correct, but there may be further restrictions on them which may not
  59. be satisfied.  For example, vector and string indices must be
  60. non-negative integers smaller than the length of the vector or string,
  61. filenames represented as strings must denote existing files with the
  62. appropriate protection when the files are going to be opened for
  63. reading, etc.
  64.  
  65. These checks obviously require some code, when compared to the code
  66. that could be generated assuming that no violations will occur at
  67. runtime.  This code requires space, and time to execute, but
  68. furthermore, may cause other performance degradation with respect to
  69. the version where no violations are guaranteed to occur.  This
  70. additional performance degradation arises because the compiler is
  71. prevented from making better register assignments or reusing the
  72. results of previous computations.
  73.  
  74. For a translation to be safe, ie. completely correct, all these checks
  75. must be performed at runtime except in those situations when the
  76. compiler can prove that violations cannot occur at runtime.  These
  77. situations are very rare, so for most programs, most checks would be
  78. included in the code generated by the compiler.
  79.  
  80. The MIT Scheme compiler treats each of these consistency checks as
  81. follows:
  82.  
  83. - Heap availability checks. Heap availability is currently not checked
  84. on every allocation, but instead is checked when allocating large
  85. blocks of storage, and otherwise checked frequently, typically on
  86. entry to procedures and continuations.  The storage manager reserves a
  87. block of storage past the end of the logical end of storage in order
  88. to allow this scheme to work.  This scheme is, however, unsafe.  It is
  89. possible, but unlikely, to write programs that, after being compiled,
  90. will overflow the heap and cause the system to crash at runtime.  The
  91. current heuristic has not being observed to fail, but future versions
  92. of the compiler will improve matters by allowing more careful code
  93. generation, and/or limiting the amount of allocation between checks to
  94. the size of the storage manager's overflow buffer.
  95.  
  96. - Stack availability checks: Stack availability is currently not
  97. checked at all by compiled code.  A very deep or infinite recursion
  98. will cause the system to crash.  This WILL be fixed in the near
  99. future.
  100.  
  101. - Type checks and range checks: A Scheme program can be considered to
  102. be a set of calls to primitive operations and some higher-level glue
  103. that pieces them together.  The higher-level glue does not directly
  104. manipulate objects, but instead passes them around to the various
  105. primitives in a controlled fashion.  Thus type and range checks are
  106. not needed in the higher-level glue, but only in the primitives
  107. themselves.  There are various switches that control how primitives
  108. are treated by the compiler, and they provide the main form of user
  109. control of the safety of compiled code.
  110.  
  111.     Control of the open coding (in-lining) of primitives
  112.  
  113. Primitives may be open-coded or called out of line.  The out-of-line
  114. versions are safe, ie. they perform all pertinent consistency checks.
  115. The compilation switches listed below control how the primitives are
  116. open coded.
  117.  
  118. Some important considerations:
  119.  
  120. - Under all possible settings of the switches described below, any
  121. generated code corresponding to a primitive call, whether open coded
  122. or not, will operate correctly on correct inputs.
  123.  
  124. - If the compiler does not know that the operator of a combination is
  125. a primitive procedure, it will not open code it.  In particular, if
  126. the compiler does not know that a variable is bound to a particular
  127. primitive procedure, no combinations with that variable as the
  128. operator will be open coded.  Usually the compiler is informed of such
  129. constant bindings by making use of declarations like
  130. USUAL-INTEGRATIONS.  See the documentation for sf for additional
  131. information on declarations.
  132.  
  133. - The compiler will not make an unsafe program safe, ie. safe
  134. translation does not compensate for unsafe programs.
  135.  
  136. This article describes whether and when the translation of the program
  137. into native code will reduce the safety of the program (as compared to
  138. the interpreted version), but there is no realistic way to increase
  139. its safety.  A program may be inherently unsafe if it uses inherenty
  140. unsafe primitives inappropriately.
  141.  
  142. Some primitives of the MIT Scheme system are inherently unsafe.  They
  143. are used for system maintenance and low-level system operation, but,
  144. like everything else in the system, they are available to users.
  145. Their use should be avoided except in rare occasions.  Using them
  146. arbitrarily may cause the system to crash, or worse, damage it in
  147. subtle ways that will produce spurious wrong results or later crashes.
  148. There is nothing the compiler can effectively do to prevent this,
  149. since any other action might change the meaning of the program on
  150. correct inputs.
  151.  
  152. - The switches listed below are not orthogonal.  Their meaning
  153. sometimes depends on the settings of the other switches.
  154.  
  155. The following compilation switches affect the open-coding of
  156. primitives:
  157.  
  158.  
  159.     COMPILER:OPEN-CODE-PRIMITIVES?
  160.  
  161. This N-ary switch can take several values as described below.  Two of
  162. the values (true and false) are booleans, the rest symbols.  
  163.  
  164. Note that if a primitive call is open coded when a switch setting is
  165. used, it will also be open coded with settings that appear below in
  166. the list.
  167.  
  168. The possible values for this switch are:
  169.  
  170. -- false: No primitive calls are open-coded.  All primitives are
  171. called out-of-line and the code is fully safe.
  172.  
  173. -- CORRECT: Open code only those primitive calls whose corresponding
  174. code is always correct, and therefore safe.
  175.  
  176. -- INNOCUOUS: Open code primitive calls whose corresponding code is
  177. correct when given appropriate arguments, and will not crash
  178. immediately when given inappropriate arguments.  Primitive calls may
  179. return values when they should have signalled an error, but the values
  180. returned are relatively innocuous: they are guaranteed to be valid
  181. Scheme objects.  The overall program or the system may still fail,
  182. since these incorrect values may cause the program to take the wrong
  183. branches later and end up in unsafe or unexpected code that it would
  184. never have executed had the errors been signalled.  Damage to the
  185. system is unlikely.
  186.  
  187. -- ALLOW-READS: Open code even if arbitrary memory locations may be
  188. read with inappropriate arguments.  This may cause a memory trap if
  189. the location is read-protected by the Operating System, or the
  190. resulting address is not valid (eg. not aligned properly), and may
  191. cause the garbage collector or other parts of the program and system
  192. to crash if the data stored at the location read is not a valid object
  193. but looks like one.  If the extracted data is only used temporarily
  194. and never stored in long living data structures or environments,
  195. damage to the system is unlikely.
  196.  
  197. -- ALLOW-WRITES: Open code even if arbitrary memory locations may be
  198. written.  This may cause an immediate failure if the location is not
  199. writable, or other problems if the integrity of some data is destroyed
  200. causing (often obscure) errors or crashes later.
  201.  
  202. -- true: open code all primitive calls (that the compiler is capable of
  203. open-coding) without regard for safety.
  204.  
  205.     COMPILER:GENERATE-TYPE-CHECKS?
  206.     COMPILER:GENERATE-RANGE-CHECKS?
  207.  
  208. These boolean switches control whether type or range checks should be
  209. issued.  The code generated is longer and slower when they are.  Note
  210. that a primitive call that would not fall in the CORRECT setting of
  211. COMPILER:OPEN-CODE-PRIMITIVES? if these checks where not issued, might
  212. very well fall in it when they are.  For most intents and purposes,
  213. turning both of these switches on bumps COMPILER:OPEN-CODE-PRIMITIVES?
  214. to ALLOW-WRITES unless it is false.
  215.  
  216.  
  217.     COMPILER:PRIMITIVE-ERRORS-RESTARTABLE?
  218.  
  219. This boolean switch controls how errors will be signalled if they are
  220. detected at runtime due to incorrect arguments found by checks in the
  221. open coding of primitive calls.  If set to true, the code will be
  222. longer and slower, but will provide the maximum amount of debugging
  223. information, and in addition, the primitive call may be bypassed and
  224. the computation restarted as if it had completed successfully.  If set
  225. to false, the code may be noticeably smaller and faster, but there may
  226. be less debugging information and some restarting ability may be lost.
  227.