]> git.proxmox.com Git - rustc.git/blob - src/librustc/metadata/encoder.rs
Imported Upstream version 0.6
[rustc.git] / src / librustc / metadata / encoder.rs
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11
12 // Metadata encoding
13
14 use core::prelude::*;
15
16 use metadata::common::*;
17 use metadata::cstore;
18 use metadata::decoder;
19 use metadata::tyencode;
20 use middle::trans::reachable;
21 use middle::ty::node_id_to_type;
22 use middle::ty;
23 use middle;
24 use util::ppaux::ty_to_str;
25
26 use core::flate;
27 use core::hash::HashUtil;
28 use core::hashmap::linear::LinearMap;
29 use core::int;
30 use core::io::{Writer, WriterUtil};
31 use core::io;
32 use core::str;
33 use core::to_bytes::IterBytes;
34 use core::uint;
35 use core::vec;
36 use std::serialize::Encodable;
37 use std;
38 use syntax::abi::AbiSet;
39 use syntax::ast::*;
40 use syntax::ast;
41 use syntax::ast_map;
42 use syntax::ast_util::*;
43 use syntax::attr;
44 use syntax::diagnostic::span_handler;
45 use syntax::parse::token::special_idents;
46 use syntax::{ast_util, visit};
47 use syntax::opt_vec::OptVec;
48 use syntax::opt_vec;
49 use syntax;
50 use writer = std::ebml::writer;
51
52 // used by astencode:
53 type abbrev_map = @mut LinearMap<ty::t, tyencode::ty_abbrev>;
54
55 pub type encode_inlined_item = @fn(ecx: @EncodeContext,
56 ebml_w: writer::Encoder,
57 path: &[ast_map::path_elt],
58 ii: ast::inlined_item);
59
60 pub struct EncodeParams {
61 diag: @span_handler,
62 tcx: ty::ctxt,
63 reachable: reachable::map,
64 reexports2: middle::resolve::ExportMap2,
65 item_symbols: @mut LinearMap<ast::node_id, ~str>,
66 discrim_symbols: @mut LinearMap<ast::node_id, ~str>,
67 link_meta: LinkMeta,
68 cstore: @mut cstore::CStore,
69 encode_inlined_item: encode_inlined_item
70 }
71
72 struct Stats {
73 inline_bytes: uint,
74 attr_bytes: uint,
75 dep_bytes: uint,
76 lang_item_bytes: uint,
77 link_args_bytes: uint,
78 item_bytes: uint,
79 index_bytes: uint,
80 zero_bytes: uint,
81 total_bytes: uint,
82
83 n_inlines: uint
84 }
85
86 pub struct EncodeContext {
87 diag: @span_handler,
88 tcx: ty::ctxt,
89 stats: @mut Stats,
90 reachable: reachable::map,
91 reexports2: middle::resolve::ExportMap2,
92 item_symbols: @mut LinearMap<ast::node_id, ~str>,
93 discrim_symbols: @mut LinearMap<ast::node_id, ~str>,
94 link_meta: LinkMeta,
95 cstore: @mut cstore::CStore,
96 encode_inlined_item: encode_inlined_item,
97 type_abbrevs: abbrev_map
98 }
99
100 pub fn reachable(ecx: @EncodeContext, id: node_id) -> bool {
101 ecx.reachable.contains(&id)
102 }
103
104 fn encode_name(ecx: @EncodeContext, ebml_w: writer::Encoder, name: ident) {
105 ebml_w.wr_tagged_str(tag_paths_data_name, *ecx.tcx.sess.str_of(name));
106 }
107
108 fn encode_impl_type_basename(ecx: @EncodeContext, ebml_w: writer::Encoder,
109 name: ident) {
110 ebml_w.wr_tagged_str(tag_item_impl_type_basename,
111 *ecx.tcx.sess.str_of(name));
112 }
113
114 pub fn encode_def_id(ebml_w: writer::Encoder, id: def_id) {
115 ebml_w.wr_tagged_str(tag_def_id, def_to_str(id));
116 }
117
118 fn encode_region_param(ecx: @EncodeContext, ebml_w: writer::Encoder,
119 it: @ast::item) {
120 let opt_rp = ecx.tcx.region_paramd_items.find(&it.id);
121 for opt_rp.each |rp| {
122 do ebml_w.wr_tag(tag_region_param) {
123 (*rp).encode(&ebml_w);
124 }
125 }
126 }
127
128 fn encode_mutability(ebml_w: writer::Encoder, mt: struct_mutability) {
129 do ebml_w.wr_tag(tag_struct_mut) {
130 let val = match mt {
131 struct_immutable => 'a',
132 struct_mutable => 'm'
133 };
134 ebml_w.writer.write(&[val as u8]);
135 }
136 }
137
138 struct entry<T> {
139 val: T,
140 pos: uint
141 }
142
143 fn add_to_index(ecx: @EncodeContext, ebml_w: writer::Encoder, path: &[ident],
144 index: &mut ~[entry<~str>], name: ident) {
145 let mut full_path = ~[];
146 full_path.push_all(path);
147 full_path.push(name);
148 index.push(
149 entry {
150 val: ast_util::path_name_i(full_path,
151 ecx.tcx.sess.parse_sess.interner),
152 pos: ebml_w.writer.tell()
153 });
154 }
155
156 fn encode_trait_ref(ebml_w: writer::Encoder, ecx: @EncodeContext,
157 t: @trait_ref) {
158 ebml_w.start_tag(tag_impl_trait);
159 encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, t.ref_id));
160 ebml_w.end_tag();
161 }
162
163
164 // Item info table encoding
165 fn encode_family(ebml_w: writer::Encoder, c: char) {
166 ebml_w.start_tag(tag_items_data_item_family);
167 ebml_w.writer.write(&[c as u8]);
168 ebml_w.end_tag();
169 }
170
171 pub fn def_to_str(did: def_id) -> ~str { fmt!("%d:%d", did.crate, did.node) }
172
173 fn encode_ty_type_param_bounds(ebml_w: writer::Encoder, ecx: @EncodeContext,
174 params: @~[ty::param_bounds]) {
175 let ty_str_ctxt = @tyencode::ctxt {
176 diag: ecx.diag,
177 ds: def_to_str,
178 tcx: ecx.tcx,
179 reachable: |a| reachable(ecx, a),
180 abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)};
181 for params.each |param| {
182 ebml_w.start_tag(tag_items_data_item_ty_param_bounds);
183 tyencode::enc_bounds(ebml_w.writer, ty_str_ctxt, *param);
184 ebml_w.end_tag();
185 }
186 }
187
188 fn encode_type_param_bounds(ebml_w: writer::Encoder,
189 ecx: @EncodeContext,
190 params: &OptVec<TyParam>) {
191 let ty_param_bounds =
192 @params.map_to_vec(|param| *ecx.tcx.ty_param_bounds.get(&param.id));
193 encode_ty_type_param_bounds(ebml_w, ecx, ty_param_bounds);
194 }
195
196
197 fn encode_variant_id(ebml_w: writer::Encoder, vid: def_id) {
198 ebml_w.start_tag(tag_items_data_item_variant);
199 ebml_w.writer.write(str::to_bytes(def_to_str(vid)));
200 ebml_w.end_tag();
201 }
202
203 pub fn write_type(ecx: @EncodeContext, ebml_w: writer::Encoder, typ: ty::t) {
204 let ty_str_ctxt = @tyencode::ctxt {
205 diag: ecx.diag,
206 ds: def_to_str,
207 tcx: ecx.tcx,
208 reachable: |a| reachable(ecx, a),
209 abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)};
210 tyencode::enc_ty(ebml_w.writer, ty_str_ctxt, typ);
211 }
212
213 pub fn write_vstore(ecx: @EncodeContext, ebml_w: writer::Encoder,
214 vstore: ty::vstore) {
215 let ty_str_ctxt = @tyencode::ctxt {
216 diag: ecx.diag,
217 ds: def_to_str,
218 tcx: ecx.tcx,
219 reachable: |a| reachable(ecx, a),
220 abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)};
221 tyencode::enc_vstore(ebml_w.writer, ty_str_ctxt, vstore);
222 }
223
224 fn encode_type(ecx: @EncodeContext, ebml_w: writer::Encoder, typ: ty::t) {
225 ebml_w.start_tag(tag_items_data_item_type);
226 write_type(ecx, ebml_w, typ);
227 ebml_w.end_tag();
228 }
229
230 fn encode_symbol(ecx: @EncodeContext, ebml_w: writer::Encoder, id: node_id) {
231 ebml_w.start_tag(tag_items_data_item_symbol);
232 match ecx.item_symbols.find(&id) {
233 Some(x) => {
234 debug!("encode_symbol(id=%?, str=%s)", id, *x);
235 ebml_w.writer.write(str::to_bytes(*x));
236 }
237 None => {
238 ecx.diag.handler().bug(
239 fmt!("encode_symbol: id not found %d", id));
240 }
241 }
242 ebml_w.end_tag();
243 }
244
245 fn encode_discriminant(ecx: @EncodeContext, ebml_w: writer::Encoder,
246 id: node_id) {
247 ebml_w.start_tag(tag_items_data_item_symbol);
248 ebml_w.writer.write(str::to_bytes(*ecx.discrim_symbols.get(&id)));
249 ebml_w.end_tag();
250 }
251
252 fn encode_disr_val(_ecx: @EncodeContext, ebml_w: writer::Encoder,
253 disr_val: int) {
254 ebml_w.start_tag(tag_disr_val);
255 ebml_w.writer.write(str::to_bytes(int::to_str(disr_val)));
256 ebml_w.end_tag();
257 }
258
259 fn encode_parent_item(ebml_w: writer::Encoder, id: def_id) {
260 ebml_w.start_tag(tag_items_data_parent_item);
261 ebml_w.writer.write(str::to_bytes(def_to_str(id)));
262 ebml_w.end_tag();
263 }
264
265 fn encode_enum_variant_info(ecx: @EncodeContext, ebml_w: writer::Encoder,
266 id: node_id, variants: &[variant],
267 path: &[ast_map::path_elt],
268 index: @mut ~[entry<int>],
269 generics: &ast::Generics) {
270 debug!("encode_enum_variant_info(id=%?)", id);
271
272 let mut disr_val = 0;
273 let mut i = 0;
274 let vi = ty::enum_variants(ecx.tcx,
275 ast::def_id { crate: local_crate, node: id });
276 for variants.each |variant| {
277 index.push(entry {val: variant.node.id, pos: ebml_w.writer.tell()});
278 ebml_w.start_tag(tag_items_data_item);
279 encode_def_id(ebml_w, local_def(variant.node.id));
280 encode_family(ebml_w, 'v');
281 encode_name(ecx, ebml_w, variant.node.name);
282 encode_parent_item(ebml_w, local_def(id));
283 encode_type(ecx, ebml_w,
284 node_id_to_type(ecx.tcx, variant.node.id));
285 match variant.node.kind {
286 ast::tuple_variant_kind(ref args)
287 if args.len() > 0 && generics.ty_params.len() == 0 => {
288 encode_symbol(ecx, ebml_w, variant.node.id);
289 }
290 ast::tuple_variant_kind(_) | ast::struct_variant_kind(_) => {}
291 }
292 encode_discriminant(ecx, ebml_w, variant.node.id);
293 if vi[i].disr_val != disr_val {
294 encode_disr_val(ecx, ebml_w, vi[i].disr_val);
295 disr_val = vi[i].disr_val;
296 }
297 encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
298 encode_path(ecx, ebml_w, path,
299 ast_map::path_name(variant.node.name));
300 ebml_w.end_tag();
301 disr_val += 1;
302 i += 1;
303 }
304 }
305
306 fn encode_path(ecx: @EncodeContext, ebml_w: writer::Encoder,
307 path: &[ast_map::path_elt], name: ast_map::path_elt) {
308 fn encode_path_elt(ecx: @EncodeContext, ebml_w: writer::Encoder,
309 elt: ast_map::path_elt) {
310 let (tag, name) = match elt {
311 ast_map::path_mod(name) => (tag_path_elt_mod, name),
312 ast_map::path_name(name) => (tag_path_elt_name, name)
313 };
314
315 ebml_w.wr_tagged_str(tag, *ecx.tcx.sess.str_of(name));
316 }
317
318 do ebml_w.wr_tag(tag_path) {
319 ebml_w.wr_tagged_u32(tag_path_len, (path.len() + 1) as u32);
320 for path.each |pe| {
321 encode_path_elt(ecx, ebml_w, *pe);
322 }
323 encode_path_elt(ecx, ebml_w, name);
324 }
325 }
326
327 fn encode_info_for_mod(ecx: @EncodeContext, ebml_w: writer::Encoder,
328 md: &_mod, id: node_id, path: &[ast_map::path_elt],
329 name: ident) {
330 ebml_w.start_tag(tag_items_data_item);
331 encode_def_id(ebml_w, local_def(id));
332 encode_family(ebml_w, 'm');
333 encode_name(ecx, ebml_w, name);
334 debug!("(encoding info for module) encoding info for module ID %d", id);
335
336 // Encode info about all the module children.
337 for md.items.each |item| {
338 match item.node {
339 item_impl(*) => {
340 let (ident, did) = (item.ident, item.id);
341 debug!("(encoding info for module) ... encoding impl %s \
342 (%?/%?)",
343 *ecx.tcx.sess.str_of(ident),
344 did,
345 ast_map::node_id_to_str(ecx.tcx.items, did, ecx.tcx
346 .sess.parse_sess.interner));
347
348 ebml_w.start_tag(tag_mod_impl);
349 ebml_w.wr_str(def_to_str(local_def(did)));
350 ebml_w.end_tag();
351 }
352 _ => {} // FIXME #4573: Encode these too.
353 }
354 }
355
356 encode_path(ecx, ebml_w, path, ast_map::path_mod(name));
357
358 // Encode the reexports of this module.
359 debug!("(encoding info for module) encoding reexports for %d", id);
360 match ecx.reexports2.find(&id) {
361 Some(ref exports) => {
362 debug!("(encoding info for module) found reexports for %d", id);
363 for exports.each |exp| {
364 debug!("(encoding info for module) reexport '%s' for %d",
365 *exp.name, id);
366 ebml_w.start_tag(tag_items_data_item_reexport);
367 ebml_w.start_tag(tag_items_data_item_reexport_def_id);
368 ebml_w.wr_str(def_to_str(exp.def_id));
369 ebml_w.end_tag();
370 ebml_w.start_tag(tag_items_data_item_reexport_name);
371 ebml_w.wr_str(*exp.name);
372 ebml_w.end_tag();
373 ebml_w.end_tag();
374 }
375 }
376 None => {
377 debug!("(encoding info for module) found no reexports for %d",
378 id);
379 }
380 }
381
382 ebml_w.end_tag();
383 }
384
385 fn encode_struct_field_family(ebml_w: writer::Encoder,
386 visibility: visibility) {
387 encode_family(ebml_w, match visibility {
388 public => 'g',
389 private => 'j',
390 inherited => 'N'
391 });
392 }
393
394 fn encode_visibility(ebml_w: writer::Encoder, visibility: visibility) {
395 ebml_w.start_tag(tag_items_data_item_visibility);
396 let ch = match visibility {
397 public => 'y',
398 private => 'n',
399 inherited => 'i',
400 };
401 ebml_w.wr_str(str::from_char(ch));
402 ebml_w.end_tag();
403 }
404
405 fn encode_self_type(ebml_w: writer::Encoder, self_type: ast::self_ty_) {
406 ebml_w.start_tag(tag_item_trait_method_self_ty);
407
408 // Encode the base self type.
409 match self_type {
410 sty_static => {
411 ebml_w.writer.write(&[ 's' as u8 ]);
412 }
413 sty_value => {
414 ebml_w.writer.write(&[ 'v' as u8 ]);
415 }
416 sty_region(_, m) => {
417 // FIXME(#4846) encode custom lifetime
418 ebml_w.writer.write(&[ '&' as u8 ]);
419 encode_mutability(ebml_w, m);
420 }
421 sty_box(m) => {
422 ebml_w.writer.write(&[ '@' as u8 ]);
423 encode_mutability(ebml_w, m);
424 }
425 sty_uniq(m) => {
426 ebml_w.writer.write(&[ '~' as u8 ]);
427 encode_mutability(ebml_w, m);
428 }
429 }
430
431 ebml_w.end_tag();
432
433 fn encode_mutability(ebml_w: writer::Encoder,
434 m: ast::mutability) {
435 match m {
436 m_imm => {
437 ebml_w.writer.write(&[ 'i' as u8 ]);
438 }
439 m_mutbl => {
440 ebml_w.writer.write(&[ 'm' as u8 ]);
441 }
442 m_const => {
443 ebml_w.writer.write(&[ 'c' as u8 ]);
444 }
445 }
446 }
447 }
448
449 fn encode_method_sort(ebml_w: writer::Encoder, sort: char) {
450 ebml_w.start_tag(tag_item_trait_method_sort);
451 ebml_w.writer.write(&[ sort as u8 ]);
452 ebml_w.end_tag();
453 }
454
455 /* Returns an index of items in this class */
456 fn encode_info_for_struct(ecx: @EncodeContext, ebml_w: writer::Encoder,
457 path: &[ast_map::path_elt],
458 fields: &[@struct_field],
459 global_index: @mut~[entry<int>]) -> ~[entry<int>] {
460 /* Each class has its own index, since different classes
461 may have fields with the same name */
462 let index = @mut ~[];
463 let tcx = ecx.tcx;
464 /* We encode both private and public fields -- need to include
465 private fields to get the offsets right */
466 for fields.each |field| {
467 let (nm, mt, vis) = match field.node.kind {
468 named_field(nm, mt, vis) => (nm, mt, vis),
469 unnamed_field => (
470 special_idents::unnamed_field,
471 struct_immutable,
472 inherited
473 )
474 };
475
476 let id = field.node.id;
477 index.push(entry {val: id, pos: ebml_w.writer.tell()});
478 global_index.push(entry {val: id, pos: ebml_w.writer.tell()});
479 ebml_w.start_tag(tag_items_data_item);
480 debug!("encode_info_for_struct: doing %s %d",
481 *tcx.sess.str_of(nm), id);
482 encode_struct_field_family(ebml_w, vis);
483 encode_name(ecx, ebml_w, nm);
484 encode_path(ecx, ebml_w, path, ast_map::path_name(nm));
485 encode_type(ecx, ebml_w, node_id_to_type(tcx, id));
486 encode_mutability(ebml_w, mt);
487 encode_def_id(ebml_w, local_def(id));
488 ebml_w.end_tag();
489 }
490 /*bad*/copy *index
491 }
492
493 // This is for encoding info for ctors and dtors
494 fn encode_info_for_ctor(ecx: @EncodeContext,
495 ebml_w: writer::Encoder,
496 id: node_id,
497 ident: ident,
498 path: &[ast_map::path_elt],
499 item: Option<inlined_item>,
500 generics: &ast::Generics) {
501 ebml_w.start_tag(tag_items_data_item);
502 encode_name(ecx, ebml_w, ident);
503 encode_def_id(ebml_w, local_def(id));
504 encode_family(ebml_w, purity_fn_family(ast::impure_fn));
505 encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
506 let its_ty = node_id_to_type(ecx.tcx, id);
507 debug!("fn name = %s ty = %s its node id = %d",
508 *ecx.tcx.sess.str_of(ident),
509 ty_to_str(ecx.tcx, its_ty), id);
510 encode_type(ecx, ebml_w, its_ty);
511 encode_path(ecx, ebml_w, path, ast_map::path_name(ident));
512 match item {
513 Some(ref it) => {
514 (ecx.encode_inlined_item)(ecx, ebml_w, path, (*it));
515 }
516 None => {
517 encode_symbol(ecx, ebml_w, id);
518 }
519 }
520 ebml_w.end_tag();
521 }
522
523 fn encode_info_for_struct_ctor(ecx: @EncodeContext,
524 ebml_w: writer::Encoder,
525 path: &[ast_map::path_elt],
526 name: ast::ident,
527 ctor_id: node_id,
528 index: @mut ~[entry<int>]) {
529 index.push(entry { val: ctor_id, pos: ebml_w.writer.tell() });
530
531 ebml_w.start_tag(tag_items_data_item);
532 encode_def_id(ebml_w, local_def(ctor_id));
533 encode_family(ebml_w, 'f');
534 encode_name(ecx, ebml_w, name);
535 encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, ctor_id));
536 encode_path(ecx, ebml_w, path, ast_map::path_name(name));
537
538 if ecx.item_symbols.contains_key(&ctor_id) {
539 encode_symbol(ecx, ebml_w, ctor_id);
540 }
541
542 ebml_w.end_tag();
543 }
544
545 fn encode_info_for_method(ecx: @EncodeContext,
546 ebml_w: writer::Encoder,
547 impl_path: &[ast_map::path_elt],
548 should_inline: bool,
549 parent_id: node_id,
550 m: @method,
551 parent_visibility: ast::visibility,
552 owner_generics: &ast::Generics,
553 method_generics: &ast::Generics) {
554 debug!("encode_info_for_method: %d %s %u %u", m.id,
555 *ecx.tcx.sess.str_of(m.ident),
556 owner_generics.ty_params.len(),
557 method_generics.ty_params.len());
558 ebml_w.start_tag(tag_items_data_item);
559 encode_def_id(ebml_w, local_def(m.id));
560
561 match m.self_ty.node {
562 ast::sty_static => {
563 encode_family(ebml_w, purity_static_method_family(m.purity));
564 }
565 _ => encode_family(ebml_w, purity_fn_family(m.purity))
566 }
567
568 let mut combined_ty_params = opt_vec::Empty;
569 combined_ty_params.push_all(&owner_generics.ty_params);
570 combined_ty_params.push_all(&method_generics.ty_params);
571 let len = combined_ty_params.len();
572 encode_type_param_bounds(ebml_w, ecx, &combined_ty_params);
573
574 encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, m.id));
575 encode_name(ecx, ebml_w, m.ident);
576 encode_path(ecx, ebml_w, impl_path, ast_map::path_name(m.ident));
577 encode_self_type(ebml_w, m.self_ty.node);
578
579 // Combine parent visibility and this visibility.
580 let visibility = match m.vis {
581 ast::inherited => parent_visibility,
582 vis => vis,
583 };
584 encode_visibility(ebml_w, visibility);
585
586 if len > 0u || should_inline {
587 (ecx.encode_inlined_item)(
588 ecx, ebml_w, impl_path,
589 ii_method(local_def(parent_id), m));
590 } else {
591 encode_symbol(ecx, ebml_w, m.id);
592 }
593 ebml_w.end_tag();
594 }
595
596 fn purity_fn_family(p: purity) -> char {
597 match p {
598 unsafe_fn => 'u',
599 pure_fn => 'p',
600 impure_fn => 'f',
601 extern_fn => 'e'
602 }
603 }
604
605 fn purity_static_method_family(p: purity) -> char {
606 match p {
607 unsafe_fn => 'U',
608 pure_fn => 'P',
609 impure_fn => 'F',
610 _ => fail!(~"extern fn can't be static")
611 }
612 }
613
614
615 fn should_inline(attrs: &[attribute]) -> bool {
616 match attr::find_inline_attr(attrs) {
617 attr::ia_none | attr::ia_never => false,
618 attr::ia_hint | attr::ia_always => true
619 }
620 }
621
622
623 fn encode_info_for_item(ecx: @EncodeContext, ebml_w: writer::Encoder,
624 item: @item, index: @mut ~[entry<int>],
625 path: &[ast_map::path_elt]) {
626
627 let tcx = ecx.tcx;
628 let must_write =
629 match item.node {
630 item_enum(_, _) | item_impl(*) | item_trait(*) | item_struct(*) |
631 item_mod(*) | item_foreign_mod(*) | item_const(*) => true,
632 _ => false
633 };
634 if !must_write && !reachable(ecx, item.id) { return; }
635
636 fn add_to_index_(item: @item, ebml_w: writer::Encoder,
637 index: @mut ~[entry<int>]) {
638 index.push(entry { val: item.id, pos: ebml_w.writer.tell() });
639 }
640 let add_to_index: &fn() = || add_to_index_(item, ebml_w, index);
641
642 debug!("encoding info for item at %s",
643 ecx.tcx.sess.codemap.span_to_str(item.span));
644
645 match item.node {
646 item_const(_, _) => {
647 add_to_index();
648 ebml_w.start_tag(tag_items_data_item);
649 encode_def_id(ebml_w, local_def(item.id));
650 encode_family(ebml_w, 'c');
651 encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
652 encode_symbol(ecx, ebml_w, item.id);
653 encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
654 (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item));
655 ebml_w.end_tag();
656 }
657 item_fn(_, purity, _, ref generics, _) => {
658 add_to_index();
659 ebml_w.start_tag(tag_items_data_item);
660 encode_def_id(ebml_w, local_def(item.id));
661 encode_family(ebml_w, purity_fn_family(purity));
662 let tps_len = generics.ty_params.len();
663 encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
664 encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
665 encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
666 encode_attributes(ebml_w, item.attrs);
667 if tps_len > 0u || should_inline(item.attrs) {
668 (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item));
669 } else {
670 encode_symbol(ecx, ebml_w, item.id);
671 }
672 ebml_w.end_tag();
673 }
674 item_mod(ref m) => {
675 add_to_index();
676 encode_info_for_mod(ecx, ebml_w, m, item.id, path, item.ident);
677 }
678 item_foreign_mod(_) => {
679 add_to_index();
680 ebml_w.start_tag(tag_items_data_item);
681 encode_def_id(ebml_w, local_def(item.id));
682 encode_family(ebml_w, 'n');
683 encode_name(ecx, ebml_w, item.ident);
684 encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
685 ebml_w.end_tag();
686 }
687 item_ty(_, ref generics) => {
688 add_to_index();
689 ebml_w.start_tag(tag_items_data_item);
690 encode_def_id(ebml_w, local_def(item.id));
691 encode_family(ebml_w, 'y');
692 encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
693 encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
694 encode_name(ecx, ebml_w, item.ident);
695 encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
696 encode_region_param(ecx, ebml_w, item);
697 ebml_w.end_tag();
698 }
699 item_enum(ref enum_definition, ref generics) => {
700 add_to_index();
701 do ebml_w.wr_tag(tag_items_data_item) {
702 encode_def_id(ebml_w, local_def(item.id));
703 encode_family(ebml_w, 't');
704 encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
705 encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
706 encode_name(ecx, ebml_w, item.ident);
707 for (*enum_definition).variants.each |v| {
708 encode_variant_id(ebml_w, local_def(v.node.id));
709 }
710 (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item));
711 encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
712 encode_region_param(ecx, ebml_w, item);
713 }
714 encode_enum_variant_info(ecx,
715 ebml_w,
716 item.id,
717 (*enum_definition).variants,
718 path,
719 index,
720 generics);
721 }
722 item_struct(struct_def, ref generics) => {
723 /* First, encode the fields
724 These come first because we need to write them to make
725 the index, and the index needs to be in the item for the
726 class itself */
727 let idx = encode_info_for_struct(ecx, ebml_w, path,
728 struct_def.fields, index);
729 /* Encode the dtor */
730 for struct_def.dtor.each |dtor| {
731 index.push(entry {val: dtor.node.id, pos: ebml_w.writer.tell()});
732 encode_info_for_ctor(ecx,
733 ebml_w,
734 dtor.node.id,
735 ecx.tcx.sess.ident_of(
736 *ecx.tcx.sess.str_of(item.ident) +
737 ~"_dtor"),
738 path,
739 if generics.ty_params.len() > 0u {
740 Some(ii_dtor(copy *dtor,
741 item.ident,
742 copy *generics,
743 local_def(item.id))) }
744 else {
745 None
746 },
747 generics);
748 }
749
750 /* Index the class*/
751 add_to_index();
752
753 /* Now, make an item for the class itself */
754 ebml_w.start_tag(tag_items_data_item);
755 encode_def_id(ebml_w, local_def(item.id));
756 encode_family(ebml_w, 'S');
757 encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
758 encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
759
760 // If this is a tuple- or enum-like struct, encode the type of the
761 // constructor.
762 if struct_def.fields.len() > 0 &&
763 struct_def.fields[0].node.kind == ast::unnamed_field {
764 let ctor_id = match struct_def.ctor_id {
765 Some(ctor_id) => ctor_id,
766 None => ecx.tcx.sess.bug(~"struct def didn't have ctor id"),
767 };
768
769 encode_info_for_struct_ctor(ecx,
770 ebml_w,
771 path,
772 item.ident,
773 ctor_id,
774 index);
775 }
776
777 encode_name(ecx, ebml_w, item.ident);
778 encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
779 encode_region_param(ecx, ebml_w, item);
780 /* Encode the dtor */
781 /* Encode id for dtor */
782 for struct_def.dtor.each |dtor| {
783 do ebml_w.wr_tag(tag_item_dtor) {
784 encode_def_id(ebml_w, local_def(dtor.node.id));
785 }
786 };
787
788 /* Encode def_ids for each field and method
789 for methods, write all the stuff get_trait_method
790 needs to know*/
791 for struct_def.fields.each |f| {
792 match f.node.kind {
793 named_field(ident, _, vis) => {
794 ebml_w.start_tag(tag_item_field);
795 encode_struct_field_family(ebml_w, vis);
796 encode_name(ecx, ebml_w, ident);
797 encode_def_id(ebml_w, local_def(f.node.id));
798 ebml_w.end_tag();
799 }
800 unnamed_field => {
801 ebml_w.start_tag(tag_item_unnamed_field);
802 encode_def_id(ebml_w, local_def(f.node.id));
803 ebml_w.end_tag();
804 }
805 }
806 }
807
808 /* Each class has its own index -- encode it */
809 let bkts = create_index(idx);
810 encode_index(ebml_w, bkts, write_int);
811 ebml_w.end_tag();
812 }
813 item_impl(ref generics, opt_trait, ty, ref methods) => {
814 add_to_index();
815 ebml_w.start_tag(tag_items_data_item);
816 encode_def_id(ebml_w, local_def(item.id));
817 encode_family(ebml_w, 'i');
818 encode_region_param(ecx, ebml_w, item);
819 encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
820 encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
821 encode_name(ecx, ebml_w, item.ident);
822 encode_attributes(ebml_w, item.attrs);
823 match ty.node {
824 ast::ty_path(path, _) if path.idents.len() == 1 => {
825 encode_impl_type_basename(ecx, ebml_w,
826 ast_util::path_to_ident(path));
827 }
828 _ => {}
829 }
830 for methods.each |m| {
831 ebml_w.start_tag(tag_item_impl_method);
832 let method_def_id = local_def(m.id);
833 ebml_w.writer.write(str::to_bytes(def_to_str(method_def_id)));
834 ebml_w.end_tag();
835 }
836 for opt_trait.each |associated_trait| {
837 encode_trait_ref(ebml_w, ecx, *associated_trait);
838 }
839 encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
840 ebml_w.end_tag();
841
842 // >:-<
843 let mut impl_path = vec::append(~[], path);
844 impl_path += ~[ast_map::path_name(item.ident)];
845
846 // If there is a trait reference, treat the methods as always public.
847 // This is to work around some incorrect behavior in privacy checking:
848 // when the method belongs to a trait, it should acquire the privacy
849 // from the trait, not the impl. Forcing the visibility to be public
850 // makes things sorta work.
851 let parent_visibility = if opt_trait.is_some() {
852 ast::public
853 } else {
854 item.vis
855 };
856
857 for methods.each |m| {
858 index.push(entry {val: m.id, pos: ebml_w.writer.tell()});
859 encode_info_for_method(ecx,
860 ebml_w,
861 impl_path,
862 should_inline(m.attrs),
863 item.id,
864 *m,
865 parent_visibility,
866 generics,
867 &m.generics);
868 }
869 }
870 item_trait(ref generics, ref traits, ref ms) => {
871 let mut provided_methods = ~[];
872
873 add_to_index();
874 ebml_w.start_tag(tag_items_data_item);
875 encode_def_id(ebml_w, local_def(item.id));
876 encode_family(ebml_w, 'I');
877 encode_region_param(ecx, ebml_w, item);
878 encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
879 encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
880 encode_name(ecx, ebml_w, item.ident);
881 encode_attributes(ebml_w, item.attrs);
882 let mut i = 0u;
883 for vec::each(*ty::trait_methods(tcx, local_def(item.id))) |mty| {
884 match (*ms)[i] {
885 required(ref ty_m) => {
886 ebml_w.start_tag(tag_item_trait_method);
887 encode_def_id(ebml_w, local_def((*ty_m).id));
888 encode_name(ecx, ebml_w, mty.ident);
889 encode_type_param_bounds(ebml_w, ecx,
890 &ty_m.generics.ty_params);
891 encode_type(ecx, ebml_w,
892 ty::mk_bare_fn(tcx, copy mty.fty));
893 encode_family(ebml_w, purity_fn_family(mty.fty.purity));
894 encode_self_type(ebml_w, mty.self_ty);
895 encode_method_sort(ebml_w, 'r');
896 encode_visibility(ebml_w, ast::public);
897 ebml_w.end_tag();
898 }
899 provided(m) => {
900 provided_methods.push(m);
901
902 ebml_w.start_tag(tag_item_trait_method);
903 encode_def_id(ebml_w, local_def(m.id));
904 encode_name(ecx, ebml_w, mty.ident);
905 encode_type_param_bounds(ebml_w, ecx,
906 &m.generics.ty_params);
907 encode_type(ecx, ebml_w,
908 ty::mk_bare_fn(tcx, copy mty.fty));
909 encode_family(ebml_w, purity_fn_family(mty.fty.purity));
910 encode_self_type(ebml_w, mty.self_ty);
911 encode_method_sort(ebml_w, 'p');
912 encode_visibility(ebml_w, m.vis);
913 ebml_w.end_tag();
914 }
915 }
916 i += 1;
917 }
918 encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
919 for traits.each |associated_trait| {
920 encode_trait_ref(ebml_w, ecx, *associated_trait)
921 }
922
923 ebml_w.end_tag();
924
925 // Now, output all of the static methods as items. Note that for the
926 // method info, we output static methods with type signatures as
927 // written. Here, we output the *real* type signatures. I feel like
928 // maybe we should only ever handle the real type signatures.
929 for ms.each |m| {
930 let ty_m = ast_util::trait_method_to_ty_method(m);
931 if ty_m.self_ty.node != ast::sty_static { loop; }
932
933 index.push(entry { val: ty_m.id, pos: ebml_w.writer.tell() });
934
935 ebml_w.start_tag(tag_items_data_item);
936 encode_def_id(ebml_w, local_def(ty_m.id));
937 encode_parent_item(ebml_w, local_def(item.id));
938 encode_name(ecx, ebml_w, ty_m.ident);
939 encode_family(ebml_w,
940 purity_static_method_family(ty_m.purity));
941 let polyty = ecx.tcx.tcache.get(&local_def(ty_m.id));
942 encode_ty_type_param_bounds(ebml_w, ecx, polyty.bounds);
943 encode_type(ecx, ebml_w, polyty.ty);
944 let mut m_path = vec::append(~[], path); // :-(
945 m_path += [ast_map::path_name(item.ident)];
946 encode_path(ecx, ebml_w, m_path, ast_map::path_name(ty_m.ident));
947
948 // For now, use the item visibility until trait methods can have
949 // real visibility in the AST.
950 encode_visibility(ebml_w, item.vis);
951
952 ebml_w.end_tag();
953 }
954
955 // Finally, output all the provided methods as items.
956 for provided_methods.each |m| {
957 index.push(entry { val: m.id, pos: ebml_w.writer.tell() });
958
959 // We do not concatenate the generics of the owning impl and that
960 // of provided methods. I am not sure why this is. -ndm
961 let owner_generics = ast_util::empty_generics();
962
963 encode_info_for_method(ecx,
964 ebml_w,
965 /*bad*/copy path,
966 true,
967 item.id,
968 *m,
969 item.vis,
970 &owner_generics,
971 &m.generics);
972 }
973 }
974 item_mac(*) => fail!(~"item macros unimplemented")
975 }
976 }
977
978 fn encode_info_for_foreign_item(ecx: @EncodeContext,
979 ebml_w: writer::Encoder,
980 nitem: @foreign_item,
981 index: @mut ~[entry<int>],
982 +path: ast_map::path,
983 abi: AbiSet) {
984 if !reachable(ecx, nitem.id) { return; }
985 index.push(entry { val: nitem.id, pos: ebml_w.writer.tell() });
986
987 ebml_w.start_tag(tag_items_data_item);
988 match nitem.node {
989 foreign_item_fn(_, purity, ref generics) => {
990 encode_def_id(ebml_w, local_def(nitem.id));
991 encode_family(ebml_w, purity_fn_family(purity));
992 encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
993 encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id));
994 if abi.is_intrinsic() {
995 (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_foreign(nitem));
996 } else {
997 encode_symbol(ecx, ebml_w, nitem.id);
998 }
999 encode_path(ecx, ebml_w, path, ast_map::path_name(nitem.ident));
1000 }
1001 foreign_item_const(*) => {
1002 encode_def_id(ebml_w, local_def(nitem.id));
1003 encode_family(ebml_w, 'c');
1004 encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id));
1005 encode_symbol(ecx, ebml_w, nitem.id);
1006 encode_path(ecx, ebml_w, path, ast_map::path_name(nitem.ident));
1007 }
1008 }
1009 ebml_w.end_tag();
1010 }
1011
1012 fn encode_info_for_items(ecx: @EncodeContext, ebml_w: writer::Encoder,
1013 crate: &crate) -> ~[entry<int>] {
1014 let index = @mut ~[];
1015 ebml_w.start_tag(tag_items_data);
1016 index.push(entry { val: crate_node_id, pos: ebml_w.writer.tell() });
1017 encode_info_for_mod(ecx, ebml_w, &crate.node.module,
1018 crate_node_id, ~[],
1019 syntax::parse::token::special_idents::invalid);
1020 visit::visit_crate(*crate, (), visit::mk_vt(@visit::Visitor {
1021 visit_expr: |_e, _cx, _v| { },
1022 visit_item: {
1023 let ebml_w = copy ebml_w;
1024 |i, cx, v| {
1025 visit::visit_item(i, cx, v);
1026 match *ecx.tcx.items.get(&i.id) {
1027 ast_map::node_item(_, pt) => {
1028 encode_info_for_item(ecx, ebml_w, i,
1029 index, *pt);
1030 }
1031 _ => fail!(~"bad item")
1032 }
1033 }
1034 },
1035 visit_foreign_item: {
1036 let ebml_w = copy ebml_w;
1037 |ni, cx, v| {
1038 visit::visit_foreign_item(ni, cx, v);
1039 match *ecx.tcx.items.get(&ni.id) {
1040 ast_map::node_foreign_item(_, abi, _, pt) => {
1041 encode_info_for_foreign_item(ecx, ebml_w, ni,
1042 index, /*bad*/copy *pt,
1043 abi);
1044 }
1045 // case for separate item and foreign-item tables
1046 _ => fail!(~"bad foreign item")
1047 }
1048 }
1049 },
1050 ..*visit::default_visitor()
1051 }));
1052 ebml_w.end_tag();
1053 return /*bad*/copy *index;
1054 }
1055
1056
1057 // Path and definition ID indexing
1058
1059 fn create_index<T:Copy + Hash + IterBytes>(index: ~[entry<T>]) ->
1060 ~[@~[entry<T>]] {
1061 let mut buckets: ~[@mut ~[entry<T>]] = ~[];
1062 for uint::range(0u, 256u) |_i| { buckets.push(@mut ~[]); };
1063 for index.each |elt| {
1064 let h = elt.val.hash() as uint;
1065 buckets[h % 256].push(*elt);
1066 }
1067
1068 let mut buckets_frozen = ~[];
1069 for buckets.each |bucket| {
1070 buckets_frozen.push(@/*bad*/copy **bucket);
1071 }
1072 return buckets_frozen;
1073 }
1074
1075 fn encode_index<T>(ebml_w: writer::Encoder, buckets: ~[@~[entry<T>]],
1076 write_fn: &fn(@io::Writer, T)) {
1077 let writer = ebml_w.writer;
1078 ebml_w.start_tag(tag_index);
1079 let mut bucket_locs: ~[uint] = ~[];
1080 ebml_w.start_tag(tag_index_buckets);
1081 for buckets.each |bucket| {
1082 bucket_locs.push(ebml_w.writer.tell());
1083 ebml_w.start_tag(tag_index_buckets_bucket);
1084 for vec::each(**bucket) |elt| {
1085 ebml_w.start_tag(tag_index_buckets_bucket_elt);
1086 assert!(elt.pos < 0xffff_ffff);
1087 writer.write_be_u32(elt.pos as u32);
1088 write_fn(writer, elt.val);
1089 ebml_w.end_tag();
1090 }
1091 ebml_w.end_tag();
1092 }
1093 ebml_w.end_tag();
1094 ebml_w.start_tag(tag_index_table);
1095 for bucket_locs.each |pos| {
1096 assert!(*pos < 0xffff_ffff);
1097 writer.write_be_u32(*pos as u32);
1098 }
1099 ebml_w.end_tag();
1100 ebml_w.end_tag();
1101 }
1102
1103 fn write_str(writer: @io::Writer, &&s: ~str) { writer.write_str(s); }
1104
1105 fn write_int(writer: @io::Writer, &&n: int) {
1106 assert!(n < 0x7fff_ffff);
1107 writer.write_be_u32(n as u32);
1108 }
1109
1110 fn encode_meta_item(ebml_w: writer::Encoder, mi: @meta_item) {
1111 match mi.node {
1112 meta_word(name) => {
1113 ebml_w.start_tag(tag_meta_item_word);
1114 ebml_w.start_tag(tag_meta_item_name);
1115 ebml_w.writer.write(str::to_bytes(*name));
1116 ebml_w.end_tag();
1117 ebml_w.end_tag();
1118 }
1119 meta_name_value(name, value) => {
1120 match value.node {
1121 lit_str(value) => {
1122 ebml_w.start_tag(tag_meta_item_name_value);
1123 ebml_w.start_tag(tag_meta_item_name);
1124 ebml_w.writer.write(str::to_bytes(*name));
1125 ebml_w.end_tag();
1126 ebml_w.start_tag(tag_meta_item_value);
1127 ebml_w.writer.write(str::to_bytes(*value));
1128 ebml_w.end_tag();
1129 ebml_w.end_tag();
1130 }
1131 _ => {/* FIXME (#623): encode other variants */ }
1132 }
1133 }
1134 meta_list(name, ref items) => {
1135 ebml_w.start_tag(tag_meta_item_list);
1136 ebml_w.start_tag(tag_meta_item_name);
1137 ebml_w.writer.write(str::to_bytes(*name));
1138 ebml_w.end_tag();
1139 for items.each |inner_item| {
1140 encode_meta_item(ebml_w, *inner_item);
1141 }
1142 ebml_w.end_tag();
1143 }
1144 }
1145 }
1146
1147 fn encode_attributes(ebml_w: writer::Encoder, attrs: &[attribute]) {
1148 ebml_w.start_tag(tag_attributes);
1149 for attrs.each |attr| {
1150 ebml_w.start_tag(tag_attribute);
1151 encode_meta_item(ebml_w, attr.node.value);
1152 ebml_w.end_tag();
1153 }
1154 ebml_w.end_tag();
1155 }
1156
1157 // So there's a special crate attribute called 'link' which defines the
1158 // metadata that Rust cares about for linking crates. This attribute requires
1159 // 'name' and 'vers' items, so if the user didn't provide them we will throw
1160 // them in anyway with default values.
1161 fn synthesize_crate_attrs(ecx: @EncodeContext,
1162 crate: &crate) -> ~[attribute] {
1163
1164 fn synthesize_link_attr(ecx: @EncodeContext, +items: ~[@meta_item]) ->
1165 attribute {
1166
1167 assert!(!ecx.link_meta.name.is_empty());
1168 assert!(!ecx.link_meta.vers.is_empty());
1169
1170 let name_item =
1171 attr::mk_name_value_item_str(@~"name",
1172 @ecx.link_meta.name.to_owned());
1173 let vers_item =
1174 attr::mk_name_value_item_str(@~"vers",
1175 @ecx.link_meta.vers.to_owned());
1176
1177 let other_items =
1178 {
1179 let tmp = attr::remove_meta_items_by_name(items, ~"name");
1180 attr::remove_meta_items_by_name(tmp, ~"vers")
1181 };
1182
1183 let meta_items = vec::append(~[name_item, vers_item], other_items);
1184 let link_item = attr::mk_list_item(@~"link", meta_items);
1185
1186 return attr::mk_attr(link_item);
1187 }
1188
1189 let mut attrs: ~[attribute] = ~[];
1190 let mut found_link_attr = false;
1191 for crate.node.attrs.each |attr| {
1192 attrs.push(
1193 if *attr::get_attr_name(attr) != ~"link" {
1194 /*bad*/copy *attr
1195 } else {
1196 match attr.node.value.node {
1197 meta_list(_, ref l) => {
1198 found_link_attr = true;;
1199 synthesize_link_attr(ecx, /*bad*/copy *l)
1200 }
1201 _ => /*bad*/copy *attr
1202 }
1203 });
1204 }
1205
1206 if !found_link_attr { attrs.push(synthesize_link_attr(ecx, ~[])); }
1207
1208 return attrs;
1209 }
1210
1211 fn encode_crate_deps(ecx: @EncodeContext,
1212 ebml_w: writer::Encoder,
1213 cstore: @mut cstore::CStore) {
1214 fn get_ordered_deps(ecx: @EncodeContext, cstore: @mut cstore::CStore)
1215 -> ~[decoder::crate_dep] {
1216 type numdep = decoder::crate_dep;
1217
1218 // Pull the cnums and name,vers,hash out of cstore
1219 let mut deps = ~[];
1220 do cstore::iter_crate_data(cstore) |key, val| {
1221 let dep = decoder::crate_dep {cnum: key,
1222 name: ecx.tcx.sess.ident_of(/*bad*/ copy *val.name),
1223 vers: decoder::get_crate_vers(val.data),
1224 hash: decoder::get_crate_hash(val.data)};
1225 deps.push(dep);
1226 };
1227
1228 // Sort by cnum
1229 std::sort::quick_sort(deps, |kv1, kv2| kv1.cnum <= kv2.cnum);
1230
1231 // Sanity-check the crate numbers
1232 let mut expected_cnum = 1;
1233 for deps.each |n| {
1234 assert!((n.cnum == expected_cnum));
1235 expected_cnum += 1;
1236 }
1237
1238 // mut -> immutable hack for vec::map
1239 deps.slice(0, deps.len()).to_owned()
1240 }
1241
1242 // We're just going to write a list of crate 'name-hash-version's, with
1243 // the assumption that they are numbered 1 to n.
1244 // FIXME (#2166): This is not nearly enough to support correct versioning
1245 // but is enough to get transitive crate dependencies working.
1246 ebml_w.start_tag(tag_crate_deps);
1247 for get_ordered_deps(ecx, cstore).each |dep| {
1248 encode_crate_dep(ecx, ebml_w, *dep);
1249 }
1250 ebml_w.end_tag();
1251 }
1252
1253 fn encode_lang_items(ecx: @EncodeContext, ebml_w: writer::Encoder) {
1254 ebml_w.start_tag(tag_lang_items);
1255
1256 for ecx.tcx.lang_items.each_item |def_id, i| {
1257 if def_id.crate != local_crate {
1258 loop;
1259 }
1260
1261 ebml_w.start_tag(tag_lang_items_item);
1262
1263 ebml_w.start_tag(tag_lang_items_item_id);
1264 ebml_w.writer.write_be_u32(i as u32);
1265 ebml_w.end_tag(); // tag_lang_items_item_id
1266
1267 ebml_w.start_tag(tag_lang_items_item_node_id);
1268 ebml_w.writer.write_be_u32(def_id.node as u32);
1269 ebml_w.end_tag(); // tag_lang_items_item_node_id
1270
1271 ebml_w.end_tag(); // tag_lang_items_item
1272 }
1273
1274 ebml_w.end_tag(); // tag_lang_items
1275 }
1276
1277 fn encode_link_args(ecx: @EncodeContext,
1278 ebml_w: writer::Encoder) {
1279 ebml_w.start_tag(tag_link_args);
1280
1281 let link_args = cstore::get_used_link_args(ecx.cstore);
1282 for link_args.each |link_arg| {
1283 ebml_w.start_tag(tag_link_args_arg);
1284 ebml_w.writer.write_str(link_arg.to_str());
1285 ebml_w.end_tag();
1286 }
1287
1288 ebml_w.end_tag();
1289 }
1290
1291 fn encode_crate_dep(ecx: @EncodeContext, ebml_w: writer::Encoder,
1292 dep: decoder::crate_dep) {
1293 ebml_w.start_tag(tag_crate_dep);
1294 ebml_w.start_tag(tag_crate_dep_name);
1295 ebml_w.writer.write(str::to_bytes(*ecx.tcx.sess.str_of(dep.name)));
1296 ebml_w.end_tag();
1297 ebml_w.start_tag(tag_crate_dep_vers);
1298 ebml_w.writer.write(str::to_bytes(*dep.vers));
1299 ebml_w.end_tag();
1300 ebml_w.start_tag(tag_crate_dep_hash);
1301 ebml_w.writer.write(str::to_bytes(*dep.hash));
1302 ebml_w.end_tag();
1303 ebml_w.end_tag();
1304 }
1305
1306 fn encode_hash(ebml_w: writer::Encoder, hash: &str) {
1307 ebml_w.start_tag(tag_crate_hash);
1308 ebml_w.writer.write(str::to_bytes(hash));
1309 ebml_w.end_tag();
1310 }
1311
1312 // NB: Increment this as you change the metadata encoding version.
1313 pub static metadata_encoding_version : &'static [u8] =
1314 &[0x72, //'r' as u8,
1315 0x75, //'u' as u8,
1316 0x73, //'s' as u8,
1317 0x74, //'t' as u8,
1318 0, 0, 0, 1 ];
1319
1320 pub fn encode_metadata(+parms: EncodeParams, crate: &crate) -> ~[u8] {
1321 let wr = @io::BytesWriter();
1322 let mut stats = Stats {
1323 inline_bytes: 0,
1324 attr_bytes: 0,
1325 dep_bytes: 0,
1326 lang_item_bytes: 0,
1327 link_args_bytes: 0,
1328 item_bytes: 0,
1329 index_bytes: 0,
1330 zero_bytes: 0,
1331 total_bytes: 0,
1332 n_inlines: 0
1333 };
1334 let EncodeParams{item_symbols, diag, tcx, reachable, reexports2,
1335 discrim_symbols, cstore, encode_inlined_item,
1336 link_meta, _} = parms;
1337 let ecx = @EncodeContext {
1338 diag: diag,
1339 tcx: tcx,
1340 stats: @mut stats,
1341 reachable: reachable,
1342 reexports2: reexports2,
1343 item_symbols: item_symbols,
1344 discrim_symbols: discrim_symbols,
1345 link_meta: link_meta,
1346 cstore: cstore,
1347 encode_inlined_item: encode_inlined_item,
1348 type_abbrevs: @mut LinearMap::new()
1349 };
1350
1351 let ebml_w = writer::Encoder(wr as @io::Writer);
1352
1353 encode_hash(ebml_w, ecx.link_meta.extras_hash);
1354
1355 let mut i = wr.pos;
1356 let crate_attrs = synthesize_crate_attrs(ecx, crate);
1357 encode_attributes(ebml_w, crate_attrs);
1358 ecx.stats.attr_bytes = wr.pos - i;
1359
1360 i = wr.pos;
1361 encode_crate_deps(ecx, ebml_w, ecx.cstore);
1362 ecx.stats.dep_bytes = wr.pos - i;
1363
1364 // Encode the language items.
1365 i = wr.pos;
1366 encode_lang_items(ecx, ebml_w);
1367 ecx.stats.lang_item_bytes = wr.pos - i;
1368
1369 // Encode the link args.
1370 i = wr.pos;
1371 encode_link_args(ecx, ebml_w);
1372 ecx.stats.link_args_bytes = wr.pos - i;
1373
1374 // Encode and index the items.
1375 ebml_w.start_tag(tag_items);
1376 i = wr.pos;
1377 let items_index = encode_info_for_items(ecx, ebml_w, crate);
1378 ecx.stats.item_bytes = wr.pos - i;
1379
1380 i = wr.pos;
1381 let items_buckets = create_index(items_index);
1382 encode_index(ebml_w, items_buckets, write_int);
1383 ecx.stats.index_bytes = wr.pos - i;
1384 ebml_w.end_tag();
1385
1386 ecx.stats.total_bytes = wr.pos;
1387
1388 if (tcx.sess.meta_stats()) {
1389
1390 do wr.bytes.each |e| {
1391 if *e == 0 {
1392 ecx.stats.zero_bytes += 1;
1393 }
1394 true
1395 }
1396
1397 io::println("metadata stats:");
1398 io::println(fmt!(" inline bytes: %u", ecx.stats.inline_bytes));
1399 io::println(fmt!(" attribute bytes: %u", ecx.stats.attr_bytes));
1400 io::println(fmt!(" dep bytes: %u", ecx.stats.dep_bytes));
1401 io::println(fmt!(" lang item bytes: %u", ecx.stats.lang_item_bytes));
1402 io::println(fmt!(" link args bytes: %u", ecx.stats.link_args_bytes));
1403 io::println(fmt!(" item bytes: %u", ecx.stats.item_bytes));
1404 io::println(fmt!(" index bytes: %u", ecx.stats.index_bytes));
1405 io::println(fmt!(" zero bytes: %u", ecx.stats.zero_bytes));
1406 io::println(fmt!(" total bytes: %u", ecx.stats.total_bytes));
1407 }
1408
1409 // Pad this, since something (LLVM, presumably) is cutting off the
1410 // remaining % 4 bytes.
1411 wr.write(&[0u8, 0u8, 0u8, 0u8]);
1412
1413 // FIXME #3396: weird bug here, for reasons unclear this emits random
1414 // looking bytes (mostly 0x1) if we use the version byte-array constant
1415 // above; so we use a string constant inline instead.
1416 //
1417 // Should be:
1418 //
1419 // vec::from_slice(metadata_encoding_version) +
1420
1421 (do str::as_bytes(&~"rust\x00\x00\x00\x01") |bytes| {
1422 vec::slice(*bytes, 0, 8).to_vec()
1423 }) + flate::deflate_bytes(wr.bytes)
1424 }
1425
1426 // Get the encoded string for a type
1427 pub fn encoded_ty(tcx: ty::ctxt, t: ty::t) -> ~str {
1428 let cx = @tyencode::ctxt {
1429 diag: tcx.diag,
1430 ds: def_to_str,
1431 tcx: tcx,
1432 reachable: |_id| false,
1433 abbrevs: tyencode::ac_no_abbrevs};
1434 do io::with_str_writer |wr| {
1435 tyencode::enc_ty(wr, cx, t);
1436 }
1437 }
1438
1439
1440 // Local Variables:
1441 // mode: rust
1442 // fill-column: 78;
1443 // indent-tabs-mode: nil
1444 // c-basic-offset: 4
1445 // buffer-file-coding-system: utf-8-unix
1446 // End: