1
1
open Common ;;
2
+ open Fmt ;;
2
3
3
4
let log (sess :Session.sess ) =
4
5
Session. log " lib"
@@ -12,6 +13,224 @@ let iflog (sess:Session.sess) (thunk:(unit -> unit)) : unit =
12
13
else ()
13
14
;;
14
15
16
+ (*
17
+ * Stuff associated with 'crate interfaces'.
18
+ *
19
+ * The interface of a crate used to be defined by the accompanying DWARF
20
+ * structure in the object file. This was an experiment -- we talked to
21
+ * DWARF hackers before hand and they thought it worth trying -- which did
22
+ * work, and had the advantage of economy of metadata-emitting, but several
23
+ * downsides:
24
+ *
25
+ * - The reader -- which we want a copy of at runtime in the linker -- has
26
+ * to know how to read DWARF. It's not the simplest format.
27
+ *
28
+ * - The complexity of the encoding meant we didn't always keep pace with
29
+ * the AST, and maintaining any degree of inter-change compatibility was
30
+ * going ot be a serious challenge.
31
+ *
32
+ * - Diagnostic tools are atrocious, as is the definition of
33
+ * well-formedness. It's largely trial and error when talking to gdb,
34
+ * say.
35
+ *
36
+ * - Because it was doing double-duty as *driving linkage*, we were never
37
+ * going to get to the linkage efficiency of native symbols (hash
38
+ * lookup) anyway. Runtime linkage -- even when lazy -- really ought to
39
+ * be fast.
40
+ *
41
+ * - LLVM, our "main" backend (in rustc) does not really want to make
42
+ * promises about preserving dwarf.
43
+ *
44
+ * - LLVM also *is* going to emit native symbols; complete with relocs and
45
+ * such. We'd actually have to do *extra work* to inhibit that.
46
+ *
47
+ * - Most tools are set up to think of DWARF as "debug", meaning
48
+ * "optional", and may well strip it or otherwise mangle it.
49
+ *
50
+ * - Many tools want native symbols anyways, and don't know how to look at
51
+ * DWARF.
52
+ *
53
+ * - All the tooling arguments go double on win32. Pretty much only
54
+ * objdump and gdb understand DWARF-in-PE. Everything else is just blank
55
+ * stares.
56
+ *
57
+ * For all these reasons we're moving to a self-made format for describing
58
+ * our interfaces. This will be stored in the .note.rust section as we
59
+ * presently store the meta tags. The encoding is ASCII-compatible (the set
60
+ * of "numbers" to encode is small enough, especially compared to dwarf,
61
+ * that we can just use a text form) and is very easy to read with a simple
62
+ * byte-at-a-time parser.
63
+ *
64
+ *)
65
+
66
+ (*
67
+ * Encoding goals:
68
+ *
69
+ * - Simple. Minimal state or read-ambiguity in reader.
70
+ *
71
+ * - Compact. Shouldn't add a lot to the size of the binary to glue this
72
+ * on to it.
73
+ *
74
+ * - Front-end-y. Doesn't need to contain much beyond parse-level of the
75
+ * crate's exported items; it'll be fed into the front-end of the
76
+ * pipeline anyway. No need to have all types or names resolved.
77
+ *
78
+ * - Testable. Human-legible and easy to identify/fix/test errors in.
79
+ *
80
+ * - Very fast to read the 'identifying' prefix (version, meta tags, hash)
81
+ *
82
+ * - Tolerably fast to read in its entirety.
83
+ *
84
+ * - Safe from version-drift (or at least able to notice it and abort).
85
+ *
86
+ * Anti-goals:
87
+ *
88
+ * - Random access.
89
+ *
90
+ * - Generality to other languages.
91
+ *
92
+ * Structure:
93
+ *
94
+ * - Line oriented.
95
+ *
96
+ * - Whitespace-separated and whitespace-agnostic. Indent for legibility.
97
+ *
98
+ * - Each line is a record. A record is either a full item, an item bracket,
99
+ * a comment, or metadata.
100
+ *
101
+ * - First byte describes type of record, unless first byte is +, in which
102
+ * case it's oh-no-we-ran-out-of-tags and it's followed by 2 type-bytes.
103
+ * (Continue to +++ if you happen to run out *there* as well. You
104
+ * won't.)
105
+ *
106
+ * - Metadata type is !
107
+ *
108
+ * - Comment type is #
109
+ *
110
+ * - Full item types are: y for type, c for const, f for fn, i for iter,
111
+ * g for tag constructor.
112
+ *
113
+ * - Item brackets are those that open/close a scope of
114
+ * sub-records. These would be obj (o), mod (m), tag (t) to open. The
115
+ * closer is always '.'. So a mod looks like:
116
+ *
117
+ * m foo
118
+ * c bar
119
+ * .
120
+ *
121
+ * - After first byte of openers and full items is whitespace, then an
122
+ * ident.
123
+ *
124
+ * - After that, if it's a ty, fn, iter, obj or tag, there may be [, a
125
+ * list of comma-separated ty param names, and ].
126
+ *
127
+ * - After that, if it's a fn, iter, obj or tag constructor, there is a (,
128
+ * a list of comma-separated type-encoded slot/ident pairs, and a ).
129
+ *
130
+ * - After that, if it's a fn or iter, there's a '->' and a type-encoded
131
+ * output.
132
+ *
133
+ * - After that, a newline '\n'.
134
+ *
135
+ * - Type encoding is a longer issue! We'll get to that.
136
+ *)
137
+
138
+ let fmt_iface (ff :Format.formatter ) (crate :Ast.crate ) : unit =
139
+ let fmt_ty_param ff (p :Ast.ty_param identified ) : unit =
140
+ fmt ff " %s" (fst p.node)
141
+ in
142
+ let rec fmt_ty ff (t :Ast.ty ) : unit =
143
+ match t with
144
+ Ast. TY_any -> fmt ff " a"
145
+ | Ast. TY_nil -> fmt ff " n"
146
+ | Ast. TY_bool -> fmt ff " b"
147
+ | Ast. TY_mach tm -> fmt ff " %s" (string_of_ty_mach tm)
148
+ | Ast. TY_int -> fmt ff " i"
149
+ | Ast. TY_uint -> fmt ff " u"
150
+ | Ast. TY_char -> fmt ff " c"
151
+ | Ast. TY_str -> fmt ff " s"
152
+
153
+ | Ast. TY_tup ttup ->
154
+ fmt_bracketed_arr_sep " (" " )" " ,"
155
+ fmt_ty ff ttup
156
+ | Ast. TY_vec ty ->
157
+ fmt ff " v[" ; fmt_ty ff ty; fmt ff " ]"
158
+ | Ast. TY_chan ty ->
159
+ fmt ff " C[" ; fmt_ty ff ty; fmt ff " ]"
160
+
161
+ | Ast. TY_port ty ->
162
+ fmt ff " P[" ; fmt_ty ff ty; fmt ff " ]"
163
+
164
+ | Ast. TY_task ->
165
+ fmt ff " T"
166
+
167
+ | Ast. TY_named n -> fmt ff " :" ; fmt_name ff n
168
+ | Ast. TY_type -> fmt ff " Y"
169
+
170
+ | Ast. TY_box t -> fmt ff " @@" ; fmt_ty ff t
171
+ | Ast. TY_mutable t -> fmt ff " ~" ; fmt_ty ff t
172
+
173
+ (* FIXME: finish this. *)
174
+ | Ast. TY_rec _
175
+ | Ast. TY_tag _
176
+ | Ast. TY_fn _
177
+ | Ast. TY_obj _
178
+ | Ast. TY_native _
179
+ | Ast. TY_param _
180
+ | Ast. TY_constrained _ -> fmt ff " Z"
181
+
182
+ and fmt_name ff n =
183
+ match n with
184
+ Ast. NAME_base (Ast. BASE_ident id ) -> fmt ff " %s" id
185
+ | Ast. NAME_base (Ast. BASE_temp _ ) -> failwith " temp in fmt_name"
186
+ | Ast. NAME_base (Ast. BASE_app (id , tys )) ->
187
+ fmt ff " %s" id;
188
+ fmt_bracketed_arr_sep " [" " ]" " ,"
189
+ fmt_ty ff tys;
190
+ | Ast. NAME_ext (n , Ast. COMP_ident id ) ->
191
+ fmt_name ff n;
192
+ fmt ff " .%s" id
193
+ | Ast. NAME_ext (n , Ast. COMP_app (id , tys )) ->
194
+ fmt_name ff n;
195
+ fmt ff " .%s" id;
196
+ fmt_bracketed_arr_sep " [" " ]" " ,"
197
+ fmt_ty ff tys;
198
+ | Ast. NAME_ext (n , Ast. COMP_idx i ) ->
199
+ fmt_name ff n;
200
+ fmt ff " ._%d" i
201
+ in
202
+ let rec fmt_mod_item (id :Ast.ident ) (mi :Ast.mod_item ) : unit =
203
+ let i c = fmt ff " @\n %c %s" c id in
204
+
205
+ let o c = fmt ff " @\n " ; fmt_obox ff; fmt ff " %c %s" c id in
206
+ let p _ =
207
+ if (Array. length mi.node.Ast. decl_params) <> 0
208
+ then
209
+ fmt_bracketed_arr_sep " [" " ]" " ,"
210
+ fmt_ty_param ff mi.node.Ast. decl_params
211
+ in
212
+ let c _ = fmt_cbox ff; fmt ff " @\n ." in
213
+ match mi.node.Ast. decl_item with
214
+ Ast. MOD_ITEM_type _ -> i 'y' ; p()
215
+ | Ast. MOD_ITEM_tag _ -> i 'g' ; p()
216
+ | Ast. MOD_ITEM_fn _ -> i 'f' ; p() ;
217
+ | Ast. MOD_ITEM_const _ -> i 'c'
218
+ | Ast. MOD_ITEM_obj _ ->
219
+ o 'o' ; p() ;
220
+ c ()
221
+ | Ast. MOD_ITEM_mod (_ , items ) ->
222
+ o 'm' ;
223
+ fmt_mod_items items;
224
+ c ()
225
+ and fmt_mod_items items =
226
+ sorted_htab_iter fmt_mod_item items
227
+ in
228
+ let (_,items) = crate.node.Ast. crate_items in
229
+ fmt_mod_items items
230
+ ;;
231
+
232
+ (* Mechanisms for scanning libraries. *)
233
+
15
234
(* FIXME (issue #67): move these to sess. *)
16
235
let ar_cache = Hashtbl. create 0 ;;
17
236
let sects_cache = Hashtbl. create 0 ;;
0 commit comments