Skip to content

Commit f314e2c

Browse files
author
Keegan McAllister
committed
creader: Load parts of plugin metadata on demand
1 parent 677b7ca commit f314e2c

File tree

2 files changed

+125
-82
lines changed

2 files changed

+125
-82
lines changed

src/librustc/metadata/creader.rs

Lines changed: 98 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,10 @@ use back::svh::Svh;
1616
use session::{config, Session};
1717
use session::search_paths::PathKind;
1818
use metadata::cstore;
19-
use metadata::cstore::{CStore, CrateSource};
19+
use metadata::cstore::{CStore, CrateSource, MetadataBlob};
2020
use metadata::decoder;
2121
use metadata::loader;
2222
use metadata::loader::CratePaths;
23-
use plugin::load::PluginMetadata;
2423
use util::nodemap::FnvHashMap;
2524

2625
use std::rc::Rc;
@@ -154,6 +153,29 @@ fn register_native_lib(sess: &Session,
154153
sess.cstore.add_used_library(name, kind);
155154
}
156155

156+
pub struct PluginMetadata<'a> {
157+
sess: &'a Session,
158+
metadata: PMDSource,
159+
dylib: Option<Path>,
160+
info: CrateInfo,
161+
vi_span: Span,
162+
target_only: bool,
163+
}
164+
165+
enum PMDSource {
166+
Registered(Rc<cstore::crate_metadata>),
167+
Owned(MetadataBlob),
168+
}
169+
170+
impl PMDSource {
171+
pub fn as_slice<'a>(&'a self) -> &'a [u8] {
172+
match *self {
173+
PMDSource::Registered(ref cmd) => cmd.data(),
174+
PMDSource::Owned(ref mdb) => mdb.as_slice(),
175+
}
176+
}
177+
}
178+
157179
impl<'a> CrateReader<'a> {
158180
pub fn new(sess: &'a Session) -> CrateReader<'a> {
159181
CrateReader {
@@ -450,17 +472,20 @@ impl<'a> CrateReader<'a> {
450472
}).collect()
451473
}
452474

453-
pub fn read_plugin_metadata(&mut self,
454-
krate: &ast::ViewItem) -> PluginMetadata {
455-
let info = self.extract_crate_info(krate).unwrap();
475+
pub fn read_plugin_metadata<'b>(&'b mut self,
476+
vi: &'b ast::ViewItem) -> PluginMetadata<'b> {
477+
let info = self.extract_crate_info(vi).unwrap();
456478
let target_triple = self.sess.opts.target_triple[];
457479
let is_cross = target_triple != config::host_triple();
458480
let mut should_link = info.should_link && !is_cross;
481+
let mut target_only = false;
482+
let ident = info.ident.clone();
483+
let name = info.name.clone();
459484
let mut load_ctxt = loader::Context {
460485
sess: self.sess,
461-
span: krate.span,
462-
ident: info.ident[],
463-
crate_name: info.name[],
486+
span: vi.span,
487+
ident: ident[],
488+
crate_name: name[],
464489
hash: None,
465490
filesearch: self.sess.host_filesearch(PathKind::Crate),
466491
triple: config::host_triple(),
@@ -472,32 +497,49 @@ impl<'a> CrateReader<'a> {
472497
let library = match load_ctxt.maybe_load_library_crate() {
473498
Some(l) => l,
474499
None if is_cross => {
475-
// try loading from target crates (only valid if there are
476-
// no syntax extensions)
500+
// Try loading from target crates. This will abort later if we try to
501+
// load a plugin registrar function,
502+
target_only = true;
503+
should_link = info.should_link;
504+
477505
load_ctxt.triple = target_triple;
478506
load_ctxt.filesearch = self.sess.target_filesearch(PathKind::Crate);
479-
let lib = load_ctxt.load_library_crate();
480-
if decoder::get_plugin_registrar_fn(lib.metadata.as_slice()).is_some() {
481-
let message = format!("crate `{}` contains a plugin_registrar fn but \
482-
only a version for triple `{}` could be found (need {})",
483-
info.ident, target_triple, config::host_triple());
484-
self.sess.span_err(krate.span, message[]);
485-
// need to abort now because the syntax expansion
486-
// code will shortly attempt to load and execute
487-
// code from the found library.
488-
self.sess.abort_if_errors();
489-
}
490-
should_link = info.should_link;
491-
lib
507+
load_ctxt.load_library_crate()
492508
}
493509
None => { load_ctxt.report_load_errs(); unreachable!() },
494510
};
495511

496-
// Read exported macros
497-
let imported_from = Some(token::intern(info.ident[]).ident());
498-
let source_name = format!("<{} macros>", info.ident[]);
512+
let dylib = library.dylib.clone();
513+
let register = should_link && self.existing_match(info.name[], None).is_none();
514+
let metadata = if register {
515+
// Register crate now to avoid double-reading metadata
516+
let (_, cmd, _) = self.register_crate(&None, info.ident[],
517+
info.name[], vi.span, library);
518+
PMDSource::Registered(cmd)
519+
} else {
520+
// Not registering the crate; just hold on to the metadata
521+
PMDSource::Owned(library.metadata)
522+
};
523+
524+
PluginMetadata {
525+
sess: self.sess,
526+
metadata: metadata,
527+
dylib: dylib,
528+
info: info,
529+
vi_span: vi.span,
530+
target_only: target_only,
531+
}
532+
}
533+
}
534+
535+
impl<'a> PluginMetadata<'a> {
536+
/// Read exported macros
537+
pub fn exported_macros(&self) -> Vec<ast::MacroDef> {
538+
let imported_from = Some(token::intern(self.info.ident[]).ident());
539+
let source_name = format!("<{} macros>", self.info.ident[]);
499540
let mut macros = vec![];
500-
decoder::each_exported_macro(library.metadata.as_slice(), &*self.sess.cstore.intr,
541+
decoder::each_exported_macro(self.metadata.as_slice(),
542+
&*self.sess.cstore.intr,
501543
|name, attrs, body| {
502544
// NB: Don't use parse::parse_tts_from_source_str because it parses with
503545
// quote_depth > 0.
@@ -520,31 +562,37 @@ impl<'a> CrateReader<'a> {
520562
true
521563
}
522564
);
565+
macros
566+
}
523567

524-
// Look for a plugin registrar
525-
let registrar = decoder::get_plugin_registrar_fn(library.metadata.as_slice()).map(|id| {
526-
decoder::get_symbol(library.metadata.as_slice(), id)
527-
});
528-
if library.dylib.is_none() && registrar.is_some() {
529-
let message = format!("plugin crate `{}` only found in rlib format, \
530-
but must be available in dylib format",
531-
info.ident);
532-
self.sess.span_err(krate.span, message[]);
533-
// No need to abort because the loading code will just ignore this
534-
// empty dylib.
568+
/// Look for a plugin registrar. Returns library path and symbol name.
569+
pub fn plugin_registrar(&self) -> Option<(Path, String)> {
570+
if self.target_only {
571+
// Need to abort before syntax expansion.
572+
let message = format!("plugin crate `{}` is not available for triple `{}` \
573+
(only found {})",
574+
self.info.ident,
575+
config::host_triple(),
576+
self.sess.opts.target_triple);
577+
self.sess.span_err(self.vi_span, message[]);
578+
self.sess.abort_if_errors();
535579
}
536-
let pc = PluginMetadata {
537-
macros: macros,
538-
registrar: match (library.dylib.as_ref(), registrar) {
539-
(Some(dylib), Some(reg)) => Some((dylib.clone(), reg)),
540-
_ => None,
541-
},
542-
};
543-
if should_link && self.existing_match(info.name[], None).is_none() {
544-
// register crate now to avoid double-reading metadata
545-
self.register_crate(&None, info.ident[],
546-
info.name[], krate.span, library);
580+
581+
let registrar = decoder::get_plugin_registrar_fn(self.metadata.as_slice())
582+
.map(|id| decoder::get_symbol(self.metadata.as_slice(), id));
583+
584+
match (self.dylib.as_ref(), registrar) {
585+
(Some(dylib), Some(reg)) => Some((dylib.clone(), reg)),
586+
(None, Some(_)) => {
587+
let message = format!("plugin crate `{}` only found in rlib format, \
588+
but must be available in dylib format",
589+
self.info.ident);
590+
self.sess.span_err(self.vi_span, message[]);
591+
// No need to abort because the loading code will just ignore this
592+
// empty dylib.
593+
None
594+
}
595+
_ => None,
547596
}
548-
pc
549597
}
550598
}

src/librustc/plugin/load.rs

Lines changed: 27 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,6 @@ use syntax::visit;
2323
use syntax::visit::Visitor;
2424
use syntax::attr::AttrMetaMethods;
2525

26-
/// Metadata for a single plugin crate.
27-
pub struct PluginMetadata {
28-
/// Macros exported by the crate.
29-
pub macros: Vec<ast::MacroDef>,
30-
/// Path to the shared library file, and registrar function symbol.
31-
pub registrar: Option<(Path, String)>,
32-
}
33-
3426
/// Pointer to a registrar function.
3527
pub type PluginRegistrarFun =
3628
fn(&mut Registry);
@@ -86,37 +78,40 @@ pub fn load_plugins(sess: &Session, krate: &ast::Crate,
8678
// note that macros aren't expanded yet, and therefore macros can't add plugins.
8779
impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
8880
fn visit_view_item(&mut self, vi: &ast::ViewItem) {
81+
// We're only interested in `extern crate`.
8982
match vi.node {
90-
ast::ViewItemExternCrate(_, _, _) => {
91-
let mut plugin_phase = false;
92-
93-
for attr in vi.attrs.iter().filter(|a| a.check_name("phase")) {
94-
let phases = attr.meta_item_list().unwrap_or(&[]);
95-
if attr::contains_name(phases, "plugin") {
96-
plugin_phase = true;
97-
}
98-
if attr::contains_name(phases, "syntax") {
99-
plugin_phase = true;
100-
self.sess.span_warn(attr.span,
101-
"phase(syntax) is a deprecated synonym for phase(plugin)");
102-
}
103-
}
83+
ast::ViewItemExternCrate(..) => (),
84+
_ => return,
85+
}
10486

105-
if !plugin_phase { return; }
87+
let mut plugin_phase = false;
88+
for attr in vi.attrs.iter().filter(|a| a.check_name("phase")) {
89+
let phases = attr.meta_item_list().unwrap_or(&[]);
90+
if attr::contains_name(phases, "plugin") {
91+
plugin_phase = true;
92+
}
93+
if attr::contains_name(phases, "syntax") {
94+
plugin_phase = true;
95+
self.sess.span_warn(attr.span,
96+
"phase(syntax) is a deprecated synonym for phase(plugin)");
97+
}
98+
}
10699

107-
let PluginMetadata { macros, registrar } =
108-
self.reader.read_plugin_metadata(vi);
100+
let mut macros = vec![];
101+
let mut registrar = None;
109102

110-
self.plugins.macros.extend(macros.into_iter());
103+
if plugin_phase {
104+
let pmd = self.reader.read_plugin_metadata(vi);
105+
macros = pmd.exported_macros();
106+
registrar = pmd.plugin_registrar();
107+
}
111108

112-
match registrar {
113-
Some((lib, symbol)) => self.dylink_registrar(vi, lib, symbol),
114-
_ => (),
115-
}
116-
}
117-
_ => (),
109+
self.plugins.macros.extend(macros.into_iter());
110+
if let Some((lib, symbol)) = registrar {
111+
self.dylink_registrar(vi, lib, symbol);
118112
}
119113
}
114+
120115
fn visit_mac(&mut self, _: &ast::Mac) {
121116
// bummer... can't see plugins inside macros.
122117
// do nothing.

0 commit comments

Comments
 (0)