3 use util::ppaux::ty_to_str;
10 use syntax::print::pprust;
11 use syntax::{ast_util, visit};
12 use syntax::ast_util::*;
15 use middle::ty::node_id_to_type;
21 use syntax::diagnostic::span_handler;
23 use hash::{Hash, HashUtil};
24 use to_bytes::IterBytes;
27 export encode_metadata;
30 export encode_inlined_item;
31 export metadata_encoding_version;
40 type abbrev_map = map::HashMap<ty::t, tyencode::ty_abbrev>;
42 type encode_inlined_item = fn@(ecx: @encode_ctxt,
43 ebml_w: ebml::Serializer,
45 ii: ast::inlined_item);
50 reachable: HashMap<ast::node_id, ()>,
51 reexports2: middle::resolve::ExportMap2,
52 item_symbols: HashMap<ast::node_id, ~str>,
53 discrim_symbols: HashMap<ast::node_id, ~str>,
55 cstore: cstore::CStore,
56 encode_inlined_item: encode_inlined_item
60 mut inline_bytes: uint,
64 mut index_bytes: uint,
66 mut total_bytes: uint,
75 reachable: HashMap<ast::node_id, ()>,
76 reexports2: middle::resolve::ExportMap2,
77 item_symbols: HashMap<ast::node_id, ~str>,
78 discrim_symbols: HashMap<ast::node_id, ~str>,
80 cstore: cstore::CStore,
81 encode_inlined_item: encode_inlined_item,
82 type_abbrevs: abbrev_map
85 fn reachable(ecx: @encode_ctxt, id: node_id) -> bool {
86 ecx.reachable.contains_key(id)
89 fn encode_name(ecx: @encode_ctxt, ebml_w: ebml::Serializer, name: ident) {
90 ebml_w.wr_tagged_str(tag_paths_data_name, ecx.tcx.sess.str_of(name));
93 fn encode_impl_type_basename(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
95 ebml_w.wr_tagged_str(tag_item_impl_type_basename,
96 ecx.tcx.sess.str_of(name));
99 fn encode_def_id(ebml_w: ebml::Serializer, id: def_id) {
100 ebml_w.wr_tagged_str(tag_def_id, def_to_str(id));
103 fn encode_region_param(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
105 let opt_rp = ecx.tcx.region_paramd_items.find(it.id);
106 for opt_rp.each |rp| {
107 do ebml_w.wr_tag(tag_region_param) {
108 (*rp).serialize(&ebml_w);
113 fn encode_mutability(ebml_w: ebml::Serializer, mt: class_mutability) {
114 do ebml_w.wr_tag(tag_class_mut) {
116 class_immutable => 'a',
119 ebml_w.writer.write(&[val as u8]);
123 type entry<T> = {val: T, pos: uint};
125 fn add_to_index(ecx: @encode_ctxt, ebml_w: ebml::Serializer, path: &[ident],
126 index: &mut ~[entry<~str>], name: ident) {
127 let mut full_path = ~[];
128 full_path.push_all(path);
129 full_path.push(name);
131 {val: ast_util::path_name_i(full_path,
132 ecx.tcx.sess.parse_sess.interner),
133 pos: ebml_w.writer.tell()});
136 fn encode_trait_ref(ebml_w: ebml::Serializer, ecx: @encode_ctxt,
138 ebml_w.start_tag(tag_impl_trait);
139 encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, t.ref_id));
144 // Item info table encoding
145 fn encode_family(ebml_w: ebml::Serializer, c: char) {
146 ebml_w.start_tag(tag_items_data_item_family);
147 ebml_w.writer.write(&[c as u8]);
151 fn def_to_str(did: def_id) -> ~str { fmt!("%d:%d", did.crate, did.node) }
153 fn encode_ty_type_param_bounds(ebml_w: ebml::Serializer, ecx: @encode_ctxt,
154 params: @~[ty::param_bounds]) {
155 let ty_str_ctxt = @{diag: ecx.diag,
158 reachable: |a| reachable(ecx, a),
159 abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)};
160 for params.each |param| {
161 ebml_w.start_tag(tag_items_data_item_ty_param_bounds);
162 tyencode::enc_bounds(ebml_w.writer, ty_str_ctxt, *param);
167 fn encode_type_param_bounds(ebml_w: ebml::Serializer, ecx: @encode_ctxt,
168 params: ~[ty_param]) {
169 let ty_param_bounds =
170 @params.map(|param| ecx.tcx.ty_param_bounds.get(param.id));
171 encode_ty_type_param_bounds(ebml_w, ecx, ty_param_bounds);
175 fn encode_variant_id(ebml_w: ebml::Serializer, vid: def_id) {
176 ebml_w.start_tag(tag_items_data_item_variant);
177 ebml_w.writer.write(str::to_bytes(def_to_str(vid)));
181 fn write_type(ecx: @encode_ctxt, ebml_w: ebml::Serializer, typ: ty::t) {
186 reachable: |a| reachable(ecx, a),
187 abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)};
188 tyencode::enc_ty(ebml_w.writer, ty_str_ctxt, typ);
191 fn write_vstore(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
192 vstore: ty::vstore) {
197 reachable: |a| reachable(ecx, a),
198 abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)};
199 tyencode::enc_vstore(ebml_w.writer, ty_str_ctxt, vstore);
202 fn encode_type(ecx: @encode_ctxt, ebml_w: ebml::Serializer, typ: ty::t) {
203 ebml_w.start_tag(tag_items_data_item_type);
204 write_type(ecx, ebml_w, typ);
208 fn encode_symbol(ecx: @encode_ctxt, ebml_w: ebml::Serializer, id: node_id) {
209 ebml_w.start_tag(tag_items_data_item_symbol);
210 let sym = match ecx.item_symbols.find(id) {
213 ecx.diag.handler().bug(
214 fmt!("encode_symbol: id not found %d", id));
217 ebml_w.writer.write(str::to_bytes(sym));
221 fn encode_discriminant(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
223 ebml_w.start_tag(tag_items_data_item_symbol);
224 ebml_w.writer.write(str::to_bytes(ecx.discrim_symbols.get(id)));
228 fn encode_disr_val(_ecx: @encode_ctxt, ebml_w: ebml::Serializer,
230 ebml_w.start_tag(tag_disr_val);
231 ebml_w.writer.write(str::to_bytes(int::to_str(disr_val,10u)));
235 fn encode_parent_item(ebml_w: ebml::Serializer, id: def_id) {
236 ebml_w.start_tag(tag_items_data_parent_item);
237 ebml_w.writer.write(str::to_bytes(def_to_str(id)));
241 fn encode_enum_variant_info(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
242 id: node_id, variants: ~[variant],
243 path: ast_map::path, index: @mut ~[entry<int>],
244 ty_params: ~[ty_param]) {
245 let mut disr_val = 0;
247 let vi = ty::enum_variants(ecx.tcx, {crate: local_crate, node: id});
248 for variants.each |variant| {
249 index.push({val: variant.node.id, pos: ebml_w.writer.tell()});
250 ebml_w.start_tag(tag_items_data_item);
251 encode_def_id(ebml_w, local_def(variant.node.id));
252 encode_family(ebml_w, 'v');
253 encode_name(ecx, ebml_w, variant.node.name);
254 encode_parent_item(ebml_w, local_def(id));
255 encode_type(ecx, ebml_w,
256 node_id_to_type(ecx.tcx, variant.node.id));
257 match variant.node.kind {
258 ast::tuple_variant_kind(args)
259 if args.len() > 0 && ty_params.len() == 0 => {
260 encode_symbol(ecx, ebml_w, variant.node.id);
262 ast::tuple_variant_kind(_) | ast::struct_variant_kind(_) |
263 ast::enum_variant_kind(_) => {}
265 encode_discriminant(ecx, ebml_w, variant.node.id);
266 if vi[i].disr_val != disr_val {
267 encode_disr_val(ecx, ebml_w, vi[i].disr_val);
268 disr_val = vi[i].disr_val;
270 encode_type_param_bounds(ebml_w, ecx, ty_params);
271 encode_path(ecx, ebml_w, path, ast_map::path_name(variant.node.name));
278 fn encode_path(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
279 path: ast_map::path, name: ast_map::path_elt) {
280 fn encode_path_elt(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
281 elt: ast_map::path_elt) {
282 let (tag, name) = match elt {
283 ast_map::path_mod(name) => (tag_path_elt_mod, name),
284 ast_map::path_name(name) => (tag_path_elt_name, name)
287 ebml_w.wr_tagged_str(tag, ecx.tcx.sess.str_of(name));
290 do ebml_w.wr_tag(tag_path) {
291 ebml_w.wr_tagged_u32(tag_path_len, (vec::len(path) + 1u) as u32);
292 for vec::each(path) |pe| {
293 encode_path_elt(ecx, ebml_w, *pe);
295 encode_path_elt(ecx, ebml_w, name);
299 fn encode_info_for_mod(ecx: @encode_ctxt, ebml_w: ebml::Serializer, md: _mod,
300 id: node_id, path: ast_map::path, name: ident) {
301 ebml_w.start_tag(tag_items_data_item);
302 encode_def_id(ebml_w, local_def(id));
303 encode_family(ebml_w, 'm');
304 encode_name(ecx, ebml_w, name);
305 debug!("(encoding info for module) encoding info for module ID %d", id);
307 // Encode info about all the module children.
308 for md.items.each |item| {
310 item_impl(*) | item_class(*) => {
311 let (ident, did) = (item.ident, item.id);
312 debug!("(encoding info for module) ... encoding impl %s \
313 (%?/%?), exported? %?",
314 ecx.tcx.sess.str_of(ident),
316 ast_map::node_id_to_str(ecx.tcx.items, did, ecx.tcx
317 .sess.parse_sess.interner),
318 ast_util::is_exported(ident, md));
320 ebml_w.start_tag(tag_mod_impl);
321 ebml_w.wr_str(def_to_str(local_def(did)));
324 _ => {} // XXX: Encode these too.
328 encode_path(ecx, ebml_w, path, ast_map::path_mod(name));
330 // Encode the reexports of this module.
331 debug!("(encoding info for module) encoding reexports for %d", id);
332 match ecx.reexports2.find(id) {
334 debug!("(encoding info for module) found reexports for %d", id);
335 for exports.each |exp| {
336 debug!("(encoding info for module) reexport '%s' for %d",
338 ebml_w.start_tag(tag_items_data_item_reexport);
339 ebml_w.start_tag(tag_items_data_item_reexport_def_id);
340 ebml_w.wr_str(def_to_str(exp.def_id));
342 ebml_w.start_tag(tag_items_data_item_reexport_name);
343 ebml_w.wr_str(exp.name);
349 debug!("(encoding info for module) found no reexports for %d",
357 fn encode_visibility(ebml_w: ebml::Serializer, visibility: visibility) {
358 encode_family(ebml_w, match visibility {
365 fn encode_self_type(ebml_w: ebml::Serializer, self_type: ast::self_ty_) {
366 ebml_w.start_tag(tag_item_trait_method_self_ty);
368 // Encode the base self type.
371 sty_static => { ch = 's' as u8; }
372 sty_by_ref => { ch = 'r' as u8; }
373 sty_value => { ch = 'v' as u8; }
374 sty_region(_) => { ch = '&' as u8; }
375 sty_box(_) => { ch = '@' as u8; }
376 sty_uniq(_) => { ch = '~' as u8; }
378 ebml_w.writer.write(&[ ch ]);
380 // Encode mutability.
382 sty_static | sty_by_ref | sty_value => { /* No-op. */ }
383 sty_region(m_imm) | sty_box(m_imm) | sty_uniq(m_imm) => {
384 ebml_w.writer.write(&[ 'i' as u8 ]);
386 sty_region(m_mutbl) | sty_box(m_mutbl) | sty_uniq(m_mutbl) => {
387 ebml_w.writer.write(&[ 'm' as u8 ]);
389 sty_region(m_const) | sty_box(m_const) | sty_uniq(m_const) => {
390 ebml_w.writer.write(&[ 'c' as u8 ]);
397 fn encode_method_sort(ebml_w: ebml::Serializer, sort: char) {
398 ebml_w.start_tag(tag_item_trait_method_sort);
399 ebml_w.writer.write(&[ sort as u8 ]);
403 /* Returns an index of items in this class */
404 fn encode_info_for_class(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
405 id: node_id, path: ast_map::path,
406 class_tps: ~[ty_param],
407 fields: ~[@struct_field],
409 global_index: @mut~[entry<int>]) -> ~[entry<int>] {
410 /* Each class has its own index, since different classes
411 may have fields with the same name */
412 let index = @mut ~[];
414 /* We encode both private and public fields -- need to include
415 private fields to get the offsets right */
416 for fields.each |field| {
417 match field.node.kind {
418 named_field(nm, mt, vis) => {
419 let id = field.node.id;
420 index.push({val: id, pos: ebml_w.writer.tell()});
421 global_index.push({val: id,
422 pos: ebml_w.writer.tell()});
423 ebml_w.start_tag(tag_items_data_item);
424 debug!("encode_info_for_class: doing %s %d",
425 tcx.sess.str_of(nm), id);
426 encode_visibility(ebml_w, vis);
427 encode_name(ecx, ebml_w, nm);
428 encode_path(ecx, ebml_w, path, ast_map::path_name(nm));
429 encode_type(ecx, ebml_w, node_id_to_type(tcx, id));
430 encode_mutability(ebml_w, mt);
431 encode_def_id(ebml_w, local_def(id));
438 for methods.each |m| {
440 public | inherited => {
441 index.push({val: m.id, pos: ebml_w.writer.tell()});
443 {val: m.id, pos: ebml_w.writer.tell()});
444 let impl_path = vec::append_one(path,
445 ast_map::path_name(m.ident));
446 debug!("encode_info_for_class: doing %s %d",
447 ecx.tcx.sess.str_of(m.ident), m.id);
448 encode_info_for_method(ecx, ebml_w, impl_path,
449 should_inline(m.attrs), id, *m,
450 vec::append(class_tps, m.tps));
452 _ => { /* don't encode private methods */ }
459 // This is for encoding info for ctors and dtors
460 fn encode_info_for_ctor(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
461 id: node_id, ident: ident, path: ast_map::path,
462 item: Option<inlined_item>, tps: ~[ty_param]) {
463 ebml_w.start_tag(tag_items_data_item);
464 encode_name(ecx, ebml_w, ident);
465 encode_def_id(ebml_w, local_def(id));
466 encode_family(ebml_w, purity_fn_family(ast::impure_fn));
467 encode_type_param_bounds(ebml_w, ecx, tps);
468 let its_ty = node_id_to_type(ecx.tcx, id);
469 debug!("fn name = %s ty = %s its node id = %d",
470 ecx.tcx.sess.str_of(ident),
471 util::ppaux::ty_to_str(ecx.tcx, its_ty), id);
472 encode_type(ecx, ebml_w, its_ty);
473 encode_path(ecx, ebml_w, path, ast_map::path_name(ident));
476 ecx.encode_inlined_item(ecx, ebml_w, path, it);
479 encode_symbol(ecx, ebml_w, id);
485 fn encode_info_for_method(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
486 impl_path: ast_map::path, should_inline: bool,
488 m: @method, all_tps: ~[ty_param]) {
489 debug!("encode_info_for_method: %d %s %u", m.id,
490 ecx.tcx.sess.str_of(m.ident), all_tps.len());
491 ebml_w.start_tag(tag_items_data_item);
492 encode_def_id(ebml_w, local_def(m.id));
493 match m.self_ty.node {
495 encode_family(ebml_w, purity_static_method_family(m.purity));
497 _ => encode_family(ebml_w, purity_fn_family(m.purity))
499 encode_type_param_bounds(ebml_w, ecx, all_tps);
500 encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, m.id));
501 encode_name(ecx, ebml_w, m.ident);
502 encode_path(ecx, ebml_w, impl_path, ast_map::path_name(m.ident));
503 encode_self_type(ebml_w, m.self_ty.node);
504 if all_tps.len() > 0u || should_inline {
505 ecx.encode_inlined_item(
506 ecx, ebml_w, impl_path,
507 ii_method(local_def(parent_id), m));
509 encode_symbol(ecx, ebml_w, m.id);
514 fn purity_fn_family(p: purity) -> char {
522 fn purity_static_method_family(p: purity) -> char {
527 _ => fail ~"extern fn can't be static"
532 fn should_inline(attrs: ~[attribute]) -> bool {
533 match attr::find_inline_attr(attrs) {
534 attr::ia_none | attr::ia_never => false,
535 attr::ia_hint | attr::ia_always => true
540 fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
541 item: @item, index: @mut ~[entry<int>],
542 path: ast_map::path) {
547 item_enum(_, _) | item_impl(*)
548 | item_trait(*) | item_class(*) => true,
551 if !must_write && !reachable(ecx, item.id) { return; }
553 fn add_to_index_(item: @item, ebml_w: ebml::Serializer,
554 index: @mut ~[entry<int>]) {
555 index.push({val: item.id, pos: ebml_w.writer.tell()});
557 let add_to_index = |copy ebml_w| add_to_index_(item, ebml_w, index);
560 item_const(_, _) => {
562 ebml_w.start_tag(tag_items_data_item);
563 encode_def_id(ebml_w, local_def(item.id));
564 encode_family(ebml_w, 'c');
565 encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
566 encode_symbol(ecx, ebml_w, item.id);
567 encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
570 item_fn(_, purity, tps, _) => {
572 ebml_w.start_tag(tag_items_data_item);
573 encode_def_id(ebml_w, local_def(item.id));
574 encode_family(ebml_w, purity_fn_family(purity));
575 encode_type_param_bounds(ebml_w, ecx, tps);
576 encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
577 encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
578 encode_attributes(ebml_w, item.attrs);
579 if tps.len() > 0u || should_inline(item.attrs) {
580 ecx.encode_inlined_item(ecx, ebml_w, path, ii_item(item));
582 encode_symbol(ecx, ebml_w, item.id);
588 encode_info_for_mod(ecx, ebml_w, m, item.id, path, item.ident);
590 item_foreign_mod(_) => {
592 ebml_w.start_tag(tag_items_data_item);
593 encode_def_id(ebml_w, local_def(item.id));
594 encode_family(ebml_w, 'n');
595 encode_name(ecx, ebml_w, item.ident);
596 encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
601 ebml_w.start_tag(tag_items_data_item);
602 encode_def_id(ebml_w, local_def(item.id));
603 encode_family(ebml_w, 'y');
604 encode_type_param_bounds(ebml_w, ecx, tps);
605 encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
606 encode_name(ecx, ebml_w, item.ident);
607 encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
608 encode_region_param(ecx, ebml_w, item);
611 item_enum(enum_definition, tps) => {
613 do ebml_w.wr_tag(tag_items_data_item) {
614 encode_def_id(ebml_w, local_def(item.id));
615 encode_family(ebml_w, 't');
616 encode_type_param_bounds(ebml_w, ecx, tps);
617 encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
618 encode_name(ecx, ebml_w, item.ident);
619 for enum_definition.variants.each |v| {
620 encode_variant_id(ebml_w, local_def(v.node.id));
622 ecx.encode_inlined_item(ecx, ebml_w, path, ii_item(item));
623 encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
624 encode_region_param(ecx, ebml_w, item);
626 encode_enum_variant_info(ecx, ebml_w, item.id,
627 enum_definition.variants, path, index, tps);
629 item_class(struct_def, tps) => {
630 /* First, encode the fields and methods
631 These come first because we need to write them to make
632 the index, and the index needs to be in the item for the
634 let idx = encode_info_for_class(ecx, ebml_w, item.id, path, tps,
635 struct_def.fields, struct_def.methods,
637 /* Encode the dtor */
638 do struct_def.dtor.iter |dtor| {
639 index.push({val: dtor.node.id, pos: ebml_w.writer.tell()});
640 encode_info_for_ctor(ecx, ebml_w, dtor.node.id,
641 ecx.tcx.sess.ident_of(
642 ecx.tcx.sess.str_of(item.ident) +
644 path, if tps.len() > 0u {
645 Some(ii_dtor(*dtor, item.ident, tps,
646 local_def(item.id))) }
652 /* Now, make an item for the class itself */
653 ebml_w.start_tag(tag_items_data_item);
654 encode_def_id(ebml_w, local_def(item.id));
655 encode_family(ebml_w, 'S');
656 encode_type_param_bounds(ebml_w, ecx, tps);
657 encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
658 encode_name(ecx, ebml_w, item.ident);
659 encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
660 encode_region_param(ecx, ebml_w, item);
661 for struct_def.traits.each |t| {
662 encode_trait_ref(ebml_w, ecx, *t);
664 /* Encode the dtor */
665 /* Encode id for dtor */
666 do struct_def.dtor.iter |dtor| {
667 do ebml_w.wr_tag(tag_item_dtor) {
668 encode_def_id(ebml_w, local_def(dtor.node.id));
672 /* Encode def_ids for each field and method
673 for methods, write all the stuff get_trait_method
675 for struct_def.fields.each |f| {
677 named_field(ident, _, vis) => {
678 ebml_w.start_tag(tag_item_field);
679 encode_visibility(ebml_w, vis);
680 encode_name(ecx, ebml_w, ident);
681 encode_def_id(ebml_w, local_def(f.node.id));
688 for struct_def.methods.each |m| {
690 private => { /* do nothing */ }
691 public | inherited => {
692 /* Write the info that's needed when viewing this class
694 ebml_w.start_tag(tag_item_trait_method);
695 encode_family(ebml_w, purity_fn_family(m.purity));
696 encode_name(ecx, ebml_w, m.ident);
697 encode_type_param_bounds(ebml_w, ecx, m.tps);
698 encode_type(ecx, ebml_w, node_id_to_type(tcx, m.id));
699 encode_def_id(ebml_w, local_def(m.id));
700 encode_self_type(ebml_w, m.self_ty.node);
702 /* Write the info that's needed when viewing this class
703 as an impl (just the method def_id and self type) */
704 ebml_w.start_tag(tag_item_impl_method);
705 ebml_w.writer.write(to_bytes(def_to_str(local_def(m.id))));
710 /* Each class has its own index -- encode it */
711 let bkts = create_index(idx);
712 encode_index(ebml_w, bkts, write_int);
715 item_impl(tps, opt_trait, ty, methods) => {
717 ebml_w.start_tag(tag_items_data_item);
718 encode_def_id(ebml_w, local_def(item.id));
719 encode_family(ebml_w, 'i');
720 encode_region_param(ecx, ebml_w, item);
721 encode_type_param_bounds(ebml_w, ecx, tps);
722 encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
723 encode_name(ecx, ebml_w, item.ident);
724 encode_attributes(ebml_w, item.attrs);
726 ast::ty_path(path, _) if path.idents.len() == 1 => {
727 encode_impl_type_basename(ecx, ebml_w,
728 ast_util::path_to_ident(path));
732 for methods.each |m| {
733 ebml_w.start_tag(tag_item_impl_method);
734 ebml_w.writer.write(str::to_bytes(def_to_str(local_def(m.id))));
737 do opt_trait.iter() |associated_trait| {
738 encode_trait_ref(ebml_w, ecx, *associated_trait)
740 encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
743 let impl_path = vec::append_one(path,
744 ast_map::path_name(item.ident));
745 for methods.each |m| {
746 index.push({val: m.id, pos: ebml_w.writer.tell()});
747 encode_info_for_method(ecx, ebml_w, impl_path,
748 should_inline(m.attrs), item.id, *m,
749 vec::append(tps, m.tps));
752 item_trait(tps, traits, ms) => {
753 let provided_methods = dvec::DVec();
756 ebml_w.start_tag(tag_items_data_item);
757 encode_def_id(ebml_w, local_def(item.id));
758 encode_family(ebml_w, 'I');
759 encode_region_param(ecx, ebml_w, item);
760 encode_type_param_bounds(ebml_w, ecx, tps);
761 encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
762 encode_name(ecx, ebml_w, item.ident);
763 encode_attributes(ebml_w, item.attrs);
765 for vec::each(*ty::trait_methods(tcx, local_def(item.id))) |mty| {
768 ebml_w.start_tag(tag_item_trait_method);
769 encode_def_id(ebml_w, local_def(ty_m.id));
770 encode_name(ecx, ebml_w, mty.ident);
771 encode_type_param_bounds(ebml_w, ecx, ty_m.tps);
772 encode_type(ecx, ebml_w, ty::mk_fn(tcx, mty.fty));
773 encode_family(ebml_w, purity_fn_family(mty.fty.meta.purity));
774 encode_self_type(ebml_w, mty.self_ty);
775 encode_method_sort(ebml_w, 'r');
779 provided_methods.push(m);
781 ebml_w.start_tag(tag_item_trait_method);
782 encode_def_id(ebml_w, local_def(m.id));
783 encode_name(ecx, ebml_w, mty.ident);
784 encode_type_param_bounds(ebml_w, ecx, m.tps);
785 encode_type(ecx, ebml_w, ty::mk_fn(tcx, mty.fty));
786 encode_family(ebml_w, purity_fn_family(mty.fty.meta.purity));
787 encode_self_type(ebml_w, mty.self_ty);
788 encode_method_sort(ebml_w, 'p');
794 encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
795 for traits.each |associated_trait| {
796 encode_trait_ref(ebml_w, ecx, *associated_trait)
800 // Now, output all of the static methods as items. Note that for the
801 // method info, we output static methods with type signatures as
802 // written. Here, we output the *real* type signatures. I feel like
803 // maybe we should only ever handle the real type signatures.
804 for vec::each(ms) |m| {
805 let ty_m = ast_util::trait_method_to_ty_method(*m);
806 if ty_m.self_ty.node != ast::sty_static { loop; }
808 index.push({val: ty_m.id, pos: ebml_w.writer.tell()});
810 ebml_w.start_tag(tag_items_data_item);
811 encode_def_id(ebml_w, local_def(ty_m.id));
812 encode_parent_item(ebml_w, local_def(item.id));
813 encode_name(ecx, ebml_w, ty_m.ident);
814 encode_family(ebml_w,
815 purity_static_method_family(ty_m.purity));
816 let polyty = ecx.tcx.tcache.get(local_def(ty_m.id));
817 encode_ty_type_param_bounds(ebml_w, ecx, polyty.bounds);
818 encode_type(ecx, ebml_w, polyty.ty);
819 encode_path(ecx, ebml_w, path, ast_map::path_name(ty_m.ident));
823 // Finally, output all the provided methods as items.
824 for provided_methods.each |m| {
825 index.push({val: m.id, pos: ebml_w.writer.tell()});
826 encode_info_for_method(ecx, ebml_w, path, true, item.id, *m,
830 item_mac(*) => fail ~"item macros unimplemented"
834 fn encode_info_for_foreign_item(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
835 nitem: @foreign_item,
836 index: @mut ~[entry<int>],
837 path: ast_map::path, abi: foreign_abi) {
838 if !reachable(ecx, nitem.id) { return; }
839 index.push({val: nitem.id, pos: ebml_w.writer.tell()});
841 ebml_w.start_tag(tag_items_data_item);
843 foreign_item_fn(_, purity, tps) => {
844 encode_def_id(ebml_w, local_def(nitem.id));
845 encode_family(ebml_w, purity_fn_family(purity));
846 encode_type_param_bounds(ebml_w, ecx, tps);
847 encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id));
848 if abi == foreign_abi_rust_intrinsic {
849 ecx.encode_inlined_item(ecx, ebml_w, path,
852 encode_symbol(ecx, ebml_w, nitem.id);
854 encode_path(ecx, ebml_w, path, ast_map::path_name(nitem.ident));
856 foreign_item_const(*) => {
857 encode_def_id(ebml_w, local_def(nitem.id));
858 encode_family(ebml_w, 'c');
859 encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id));
860 encode_symbol(ecx, ebml_w, nitem.id);
861 encode_path(ecx, ebml_w, path, ast_map::path_name(nitem.ident));
867 fn encode_info_for_items(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
868 crate: @crate) -> ~[entry<int>] {
869 let index = @mut ~[];
870 ebml_w.start_tag(tag_items_data);
871 index.push({val: crate_node_id, pos: ebml_w.writer.tell()});
872 encode_info_for_mod(ecx, ebml_w, crate.node.module,
874 syntax::parse::token::special_idents::invalid);
875 visit::visit_crate(*crate, (), visit::mk_vt(@{
876 visit_expr: |_e, _cx, _v| { },
877 visit_item: |i, cx, v, copy ebml_w| {
878 visit::visit_item(i, cx, v);
879 match ecx.tcx.items.get(i.id) {
880 ast_map::node_item(_, pt) => {
881 encode_info_for_item(ecx, ebml_w, i, index, *pt);
883 _ => fail ~"bad item"
886 visit_foreign_item: |ni, cx, v, copy ebml_w| {
887 visit::visit_foreign_item(ni, cx, v);
888 match ecx.tcx.items.get(ni.id) {
889 ast_map::node_foreign_item(_, abi, pt) => {
890 encode_info_for_foreign_item(ecx, ebml_w, ni,
893 // case for separate item and foreign-item tables
894 _ => fail ~"bad foreign item"
897 ,.. *visit::default_visitor()
904 // Path and definition ID indexing
906 fn create_index<T: Copy Hash IterBytes>(index: ~[entry<T>]) ->
908 let mut buckets: ~[@mut ~[entry<T>]] = ~[];
909 for uint::range(0u, 256u) |_i| { buckets.push(@mut ~[]); };
910 for index.each |elt| {
911 let h = elt.val.hash() as uint;
912 buckets[h % 256].push(*elt);
915 let mut buckets_frozen = ~[];
916 for buckets.each |bucket| {
917 buckets_frozen.push(@**bucket);
919 return buckets_frozen;
922 fn encode_index<T>(ebml_w: ebml::Serializer, buckets: ~[@~[entry<T>]],
923 write_fn: fn(io::Writer, T)) {
924 let writer = ebml_w.writer;
925 ebml_w.start_tag(tag_index);
926 let mut bucket_locs: ~[uint] = ~[];
927 ebml_w.start_tag(tag_index_buckets);
928 for buckets.each |bucket| {
929 bucket_locs.push(ebml_w.writer.tell());
930 ebml_w.start_tag(tag_index_buckets_bucket);
931 for vec::each(**bucket) |elt| {
932 ebml_w.start_tag(tag_index_buckets_bucket_elt);
933 assert elt.pos < 0xffff_ffff;
934 writer.write_be_u32(elt.pos as u32);
935 write_fn(writer, elt.val);
941 ebml_w.start_tag(tag_index_table);
942 for bucket_locs.each |pos| {
943 assert *pos < 0xffff_ffff;
944 writer.write_be_u32(*pos as u32);
950 fn write_str(writer: io::Writer, &&s: ~str) { writer.write_str(s); }
952 fn write_int(writer: io::Writer, &&n: int) {
953 assert n < 0x7fff_ffff;
954 writer.write_be_u32(n as u32);
957 fn encode_meta_item(ebml_w: ebml::Serializer, mi: meta_item) {
960 ebml_w.start_tag(tag_meta_item_word);
961 ebml_w.start_tag(tag_meta_item_name);
962 ebml_w.writer.write(str::to_bytes(name));
966 meta_name_value(name, value) => {
969 ebml_w.start_tag(tag_meta_item_name_value);
970 ebml_w.start_tag(tag_meta_item_name);
971 ebml_w.writer.write(str::to_bytes(name));
973 ebml_w.start_tag(tag_meta_item_value);
974 ebml_w.writer.write(str::to_bytes(*value));
978 _ => {/* FIXME (#623): encode other variants */ }
981 meta_list(name, items) => {
982 ebml_w.start_tag(tag_meta_item_list);
983 ebml_w.start_tag(tag_meta_item_name);
984 ebml_w.writer.write(str::to_bytes(name));
986 for items.each |inner_item| {
987 encode_meta_item(ebml_w, **inner_item);
994 fn encode_attributes(ebml_w: ebml::Serializer, attrs: ~[attribute]) {
995 ebml_w.start_tag(tag_attributes);
996 for attrs.each |attr| {
997 ebml_w.start_tag(tag_attribute);
998 encode_meta_item(ebml_w, attr.node.value);
1004 // So there's a special crate attribute called 'link' which defines the
1005 // metadata that Rust cares about for linking crates. This attribute requires
1006 // 'name' and 'vers' items, so if the user didn't provide them we will throw
1007 // them in anyway with default values.
1008 fn synthesize_crate_attrs(ecx: @encode_ctxt, crate: @crate) -> ~[attribute] {
1010 fn synthesize_link_attr(ecx: @encode_ctxt, items: ~[@meta_item]) ->
1013 assert (ecx.link_meta.name != ~"");
1014 assert (ecx.link_meta.vers != ~"");
1017 attr::mk_name_value_item_str(~"name", ecx.link_meta.name);
1019 attr::mk_name_value_item_str(~"vers", ecx.link_meta.vers);
1023 let tmp = attr::remove_meta_items_by_name(items, ~"name");
1024 attr::remove_meta_items_by_name(tmp, ~"vers")
1027 let meta_items = vec::append(~[name_item, vers_item], other_items);
1028 let link_item = attr::mk_list_item(~"link", meta_items);
1030 return attr::mk_attr(link_item);
1033 let mut attrs: ~[attribute] = ~[];
1034 let mut found_link_attr = false;
1035 for crate.node.attrs.each |attr| {
1037 if attr::get_attr_name(*attr) != ~"link" {
1040 match attr.node.value.node {
1041 meta_list(_, l) => {
1042 found_link_attr = true;;
1043 synthesize_link_attr(ecx, l)
1050 if !found_link_attr { attrs.push(synthesize_link_attr(ecx, ~[])); }
1055 fn encode_crate_deps(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
1056 cstore: cstore::CStore) {
1058 fn get_ordered_deps(ecx: @encode_ctxt, cstore: cstore::CStore)
1059 -> ~[decoder::crate_dep] {
1061 type hashkv = @{key: crate_num, val: cstore::crate_metadata};
1062 type numdep = decoder::crate_dep;
1064 // Pull the cnums and name,vers,hash out of cstore
1065 let mut deps: ~[numdep] = ~[];
1066 do cstore::iter_crate_data(cstore) |key, val| {
1067 let dep = {cnum: key, name: ecx.tcx.sess.ident_of(val.name),
1068 vers: decoder::get_crate_vers(val.data),
1069 hash: decoder::get_crate_hash(val.data)};
1074 pure fn lteq(kv1: &numdep, kv2: &numdep) -> bool {
1075 kv1.cnum <= kv2.cnum
1077 std::sort::quick_sort(deps, lteq);
1079 // Sanity-check the crate numbers
1080 let mut expected_cnum = 1;
1082 assert (n.cnum == expected_cnum);
1086 // mut -> immutable hack for vec::map
1087 return vec::slice(deps, 0u, vec::len(deps));
1090 // We're just going to write a list of crate 'name-hash-version's, with
1091 // the assumption that they are numbered 1 to n.
1092 // FIXME (#2166): This is not nearly enough to support correct versioning
1093 // but is enough to get transitive crate dependencies working.
1094 ebml_w.start_tag(tag_crate_deps);
1095 for get_ordered_deps(ecx, cstore).each |dep| {
1096 encode_crate_dep(ecx, ebml_w, *dep);
1101 fn encode_crate_dep(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
1102 dep: decoder::crate_dep) {
1103 ebml_w.start_tag(tag_crate_dep);
1104 ebml_w.start_tag(tag_crate_dep_name);
1105 ebml_w.writer.write(str::to_bytes(ecx.tcx.sess.str_of(dep.name)));
1107 ebml_w.start_tag(tag_crate_dep_vers);
1108 ebml_w.writer.write(str::to_bytes(dep.vers));
1110 ebml_w.start_tag(tag_crate_dep_hash);
1111 ebml_w.writer.write(str::to_bytes(dep.hash));
1116 fn encode_hash(ebml_w: ebml::Serializer, hash: ~str) {
1117 ebml_w.start_tag(tag_crate_hash);
1118 ebml_w.writer.write(str::to_bytes(hash));
1122 // NB: Increment this as you change the metadata encoding version.
1123 const metadata_encoding_version : &[u8] = &[0x72, //'r' as u8,
1129 fn encode_metadata(parms: encode_parms, crate: @crate) -> ~[u8] {
1130 let wr = @io::BytesWriter();
1132 {mut inline_bytes: 0,
1140 let ecx: @encode_ctxt = @encode_ctxt({
1144 reachable: parms.reachable,
1145 reexports2: parms.reexports2,
1146 item_symbols: parms.item_symbols,
1147 discrim_symbols: parms.discrim_symbols,
1148 link_meta: parms.link_meta,
1149 cstore: parms.cstore,
1150 encode_inlined_item: parms.encode_inlined_item,
1151 type_abbrevs: ty::new_ty_hash()
1154 let ebml_w = ebml::Serializer(wr as io::Writer);
1156 encode_hash(ebml_w, ecx.link_meta.extras_hash);
1159 let crate_attrs = synthesize_crate_attrs(ecx, crate);
1160 encode_attributes(ebml_w, crate_attrs);
1161 ecx.stats.attr_bytes = wr.pos - i;
1164 encode_crate_deps(ecx, ebml_w, ecx.cstore);
1165 ecx.stats.dep_bytes = wr.pos - i;
1167 // Encode and index the items.
1168 ebml_w.start_tag(tag_items);
1170 let items_index = encode_info_for_items(ecx, ebml_w, crate);
1171 ecx.stats.item_bytes = wr.pos - i;
1174 let items_buckets = create_index(items_index);
1175 encode_index(ebml_w, items_buckets, write_int);
1176 ecx.stats.index_bytes = wr.pos - i;
1179 ecx.stats.total_bytes = wr.pos;
1181 if (parms.tcx.sess.meta_stats()) {
1183 do wr.bytes.borrow |v| {
1186 ecx.stats.zero_bytes += 1;
1192 io::println("metadata stats:");
1193 io::println(fmt!(" inline bytes: %u", ecx.stats.inline_bytes));
1194 io::println(fmt!(" attribute bytes: %u", ecx.stats.attr_bytes));
1195 io::println(fmt!(" dep bytes: %u", ecx.stats.dep_bytes));
1196 io::println(fmt!(" item bytes: %u", ecx.stats.item_bytes));
1197 io::println(fmt!(" index bytes: %u", ecx.stats.index_bytes));
1198 io::println(fmt!(" zero bytes: %u", ecx.stats.zero_bytes));
1199 io::println(fmt!(" total bytes: %u", ecx.stats.total_bytes));
1202 // Pad this, since something (LLVM, presumably) is cutting off the
1203 // remaining % 4 bytes.
1204 wr.write(&[0u8, 0u8, 0u8, 0u8]);
1206 // FIXME #3396: weird bug here, for reasons unclear this emits random
1207 // looking bytes (mostly 0x1) if we use the version byte-array constant
1208 // above; so we use a string constant inline instead.
1212 // vec::from_slice(metadata_encoding_version) +
1214 (do str::as_bytes(&~"rust\x00\x00\x00\x01") |bytes| {
1215 vec::slice(*bytes, 0, 8)
1216 }) + flate::deflate_bytes(wr.bytes.check_out(|buf| buf))
1219 // Get the encoded string for a type
1220 fn encoded_ty(tcx: ty::ctxt, t: ty::t) -> ~str {
1221 let cx = @{diag: tcx.diag,
1224 reachable: |_id| false,
1225 abbrevs: tyencode::ac_no_abbrevs};
1226 do io::with_str_writer |wr| {
1227 tyencode::enc_ty(wr, cx, t);
1235 // indent-tabs-mode: nil
1236 // c-basic-offset: 4
1237 // buffer-file-coding-system: utf-8-unix