home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Moscow ML 1.31 / source code / mosml / src / compiler / Link.sml < prev    next >
Encoding:
Text File  |  1996-07-03  |  6.4 KB  |  217 lines  |  [TEXT/R*ch]

  1. (* Production of a bytecode executable file *)
  2.  
  3. open Misc BasicIO Nonstdio Miscsys Obj Fnlib Const Mixture Config;
  4. open Code_dec Symtable Patch Tr_const;
  5.  
  6. (* First pass: check the consistency of files *)
  7.  
  8. fun check_file name toscan =
  9.   let val simplename = Filename.chop_suffix name ".uo"
  10.       val uname = normalizedUnitName(Filename.basename simplename)
  11.       val () =
  12.         if member uname reservedUnitNames then
  13.           raise Fail ("Unit "^uname^" is built-in, and cannot be linked")
  14.         else ()
  15.       val () =
  16.         (ignore(Hasht.find (!watchDog) uname);
  17.          raise Fail ("Unit "^uname^" has been linked already"))
  18.         handle Subscript => ()
  19.       val truename = find_in_path name
  20.       val is = open_in_bin truename
  21.       val tables =
  22.             let val n = input_binary_int is in
  23.               seek_in is n;
  24.               input_value is : compiled_unit_tables
  25.              end
  26.              handle x =>
  27.                (close_in is;
  28.                 msgIBlock 0;
  29.                 errPrompt "Error on file ";
  30.                 msgString truename; msgEOL();
  31.                 msgEBlock();
  32.                 raise x)
  33.   in
  34.     close_in is;
  35.     (* Now we have to check, whether the unit body is compatible *)
  36.     (* with the previously linked units. *)
  37.     Hasht.apply
  38.       (fn uname' => fn stamp' =>
  39.         let val stamp'' = Hasht.find (!watchDog) uname' in
  40.           if stamp'' <> stamp' then
  41.             raise Fail ("Compiled body of unit "^uname^
  42.                         " is incompatible with previously linked unit "^
  43.                         uname')
  44.           else ()
  45.         end
  46.         handle Subscript =>
  47.           raise Fail ("Unit "^uname'^" is mentioned by "^uname^
  48.                       " but not yet linked"))
  49.       (#cu_mentions tables);
  50.     Hasht.insert (!watchDog) uname (#cu_sig_stamp tables);
  51.     (uname, truename, tables) :: toscan
  52.   end;
  53.  
  54. (* Second pass: determine which phrases are required *)
  55.  
  56. val missing_globals =
  57.     ref (Hasht.new 1 : (QualifiedIdent * int, unit) Hasht.t)
  58. ;
  59.  
  60. fun is_in_missing g =
  61.   (Hasht.find (!missing_globals) g; true)
  62.   handle Subscript => false
  63. ;
  64.  
  65. fun remove_from_missing g =
  66.   Hasht.remove (!missing_globals) g
  67. ;
  68.  
  69. fun add_to_missing g =
  70.   Hasht.insert (!missing_globals) g ()
  71. ;
  72.  
  73. fun is_required (Reloc_setglobal g, _) = is_in_missing g
  74.   | is_required _ = false
  75. ;
  76.  
  77. fun remove_required (Reloc_setglobal g, _) = remove_from_missing g
  78.   | remove_required _ = ()
  79. ;
  80.  
  81. fun add_required (Reloc_getglobal g, _) = add_to_missing g
  82.   | add_required _ = ()
  83. ;
  84.  
  85. fun scan_val uname (id, stamp) tolink =
  86.   let val q = {qual=uname, id=id} in
  87.     if is_in_missing (q, 0) then
  88.       (remove_from_missing (q, 0);
  89.        add_to_missing (q, stamp);
  90.        (id, stamp) :: tolink)
  91.     else
  92.       tolink
  93.   end;
  94.  
  95. fun scan_phrase (phr : compiled_phrase) tolink =
  96.   if not(#cph_pure phr) orelse
  97.      List.exists is_required (#cph_reloc phr)
  98.   then
  99.     (List.app remove_required (#cph_reloc phr);
  100.      List.app add_required (#cph_reloc phr);
  101.      phr :: tolink)
  102.   else
  103.     tolink
  104. ;
  105.  
  106. fun scan_file (uname, truename, (tables : compiled_unit_tables)) tolink =
  107.   let val exportedE = #cu_exc_ren_list tables
  108.       val valRenList = #cu_val_ren_list tables
  109.       val exportedV = foldL (scan_val uname) [] valRenList
  110.       val phraseIndex = #cu_phrase_index tables
  111.       val required = foldL scan_phrase [] phraseIndex
  112.   in
  113.     (uname, truename, required, exportedE, exportedV) :: tolink
  114.   end;
  115.  
  116. (* Third pass : link in the required phrases. *)
  117.  
  118. fun link_object os (uname, truename, required, exportedE, exportedV) =
  119.   let val is = open_in_bin truename in
  120.     (List.app
  121.        (fn (phr : compiled_phrase) =>
  122.          let val () = seek_in is (#cph_pos phr)
  123.              val buff = input(is, #cph_len phr)
  124.              val () = if size buff < #cph_len phr
  125.                       then raise Size else ()
  126.          in
  127.            patch_object buff 0 (#cph_reloc phr);
  128.            output(os, buff)
  129.          end)
  130.        required;
  131.      exportPublicNames uname exportedE exportedV;
  132.      close_in is)
  133.     handle x =>
  134.       (close_in is;
  135.        msgIBlock 0;
  136.        errPrompt "Error while linking file ";
  137.        msgString truename; msgEOL();
  138.        msgEBlock();
  139.        raise x)
  140.   end;
  141.  
  142. (* To build the initial table of globals *)
  143.  
  144. local
  145.   prim_val vector_ : int -> '_a -> '_a vector       = 2 "make_vect"
  146.   prim_val sub_    : 'a vector -> int -> 'a         = 2 "get_vect_item"
  147.   prim_val update_ : 'a vector -> int -> 'a -> unit = 3 "set_vect_item"
  148. in
  149.  
  150.   fun emit_data os =
  151.     let val len = number_of_globals()
  152.         val globals = vector_ len (repr 0)
  153.     in
  154.       List.app
  155.         (fn (n,sc) => update_ globals n (translStructuredConst sc))
  156.         (!literal_table);
  157.       output_value os globals
  158.     end;
  159.  
  160. end;
  161.  
  162. (* To build a bytecode executable file *)
  163.  
  164. val write_symbols = ref false;
  165. val no_header = ref false;
  166.  
  167. fun link unit_list exec_name =
  168.   let val _ = missing_globals :=  (* 04Sep95 e *)
  169.                (Hasht.new 263 : (QualifiedIdent * int, unit) Hasht.t)
  170.       val toscan = foldL check_file [] unit_list
  171.       val tolink = foldL scan_file [] toscan
  172.       val os = if !no_header then open_out_bin exec_name
  173.                              else open_out_exe exec_name
  174.   in
  175.     ( (* The header *)
  176.       if !no_header then () else
  177.       let val is = open_in_bin (Filename.concat (!path_library) "header")
  178.           val buff = CharArray.array(4096, #"\000")
  179.           fun copy () =
  180.             case buff_input is buff 0 4096 of
  181.                 0 => ()
  182.               | n => (buff_output os buff 0 n; copy())
  183.       in
  184.         (copy(); close_in is)
  185.           handle x => (close_in is; raise x)
  186.       end;
  187.       missing_globals := (* for gc -- 04Sep95 e *)
  188.        (Hasht.new 1 : (QualifiedIdent * int, unit) Hasht.t);
  189.       (* The bytecode *)
  190.       let val pos1 = pos_out os
  191.           val () = List.app (link_object os) tolink
  192.           val () = output_byte os Opcodes.STOP;
  193.           (* The table of global data *)
  194.           val pos2 = pos_out os
  195.           val () = emit_data os
  196.           (* Linker tables *)
  197.           val pos3 = pos_out os
  198.           val () =
  199.             if !write_symbols then save_linker_tables os
  200.             else ();
  201.           (* Debugging info (none, presently) *)
  202.           val pos4 = pos_out os
  203.       in
  204.         (* The trailer *)
  205.         output_binary_int os (pos2 - pos1);
  206.         output_binary_int os (pos3 - pos2);
  207.         output_binary_int os (pos4 - pos3);
  208.         output_binary_int os 0;
  209.         output(os, "ML07");
  210.         close_out os
  211.       end
  212.     ) handle x =>
  213.        (close_out os;
  214.         remove_file exec_name;
  215.         raise x)
  216.   end;
  217.