about summary refs log tree commit diff
diff options
context:
space:
mode:
authorKeegan McAllister <kmcallister@mozilla.com>2014-12-31 19:48:39 -0800
committerKeegan McAllister <kmcallister@mozilla.com>2015-01-05 18:21:13 -0800
commitf314e2c4ea48c2027e627fdfca821bb6e0012e59 (patch)
tree26d83d97f04f460583535c604b78b4c7515c4105
parent677b7cad3d0ca1347f65ae9b409078343a5f302e (diff)
downloadrust-f314e2c4ea48c2027e627fdfca821bb6e0012e59.tar.gz
rust-f314e2c4ea48c2027e627fdfca821bb6e0012e59.zip
creader: Load parts of plugin metadata on demand
-rw-r--r--src/librustc/metadata/creader.rs148
-rw-r--r--src/librustc/plugin/load.rs59
2 files changed, 125 insertions, 82 deletions
diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs
index 3bf0e41ae9c..34e72008066 100644
--- a/src/librustc/metadata/creader.rs
+++ b/src/librustc/metadata/creader.rs
@@ -16,11 +16,10 @@ use back::svh::Svh;
 use session::{config, Session};
 use session::search_paths::PathKind;
 use metadata::cstore;
-use metadata::cstore::{CStore, CrateSource};
+use metadata::cstore::{CStore, CrateSource, MetadataBlob};
 use metadata::decoder;
 use metadata::loader;
 use metadata::loader::CratePaths;
-use plugin::load::PluginMetadata;
 use util::nodemap::FnvHashMap;
 
 use std::rc::Rc;
@@ -154,6 +153,29 @@ fn register_native_lib(sess: &Session,
     sess.cstore.add_used_library(name, kind);
 }
 
+pub struct PluginMetadata<'a> {
+    sess: &'a Session,
+    metadata: PMDSource,
+    dylib: Option<Path>,
+    info: CrateInfo,
+    vi_span: Span,
+    target_only: bool,
+}
+
+enum PMDSource {
+    Registered(Rc<cstore::crate_metadata>),
+    Owned(MetadataBlob),
+}
+
+impl PMDSource {
+    pub fn as_slice<'a>(&'a self) -> &'a [u8] {
+        match *self {
+            PMDSource::Registered(ref cmd) => cmd.data(),
+            PMDSource::Owned(ref mdb) => mdb.as_slice(),
+        }
+    }
+}
+
 impl<'a> CrateReader<'a> {
     pub fn new(sess: &'a Session) -> CrateReader<'a> {
         CrateReader {
@@ -450,17 +472,20 @@ impl<'a> CrateReader<'a> {
         }).collect()
     }
 
-    pub fn read_plugin_metadata(&mut self,
-                                krate: &ast::ViewItem) -> PluginMetadata {
-        let info = self.extract_crate_info(krate).unwrap();
+    pub fn read_plugin_metadata<'b>(&'b mut self,
+                                    vi: &'b ast::ViewItem) -> PluginMetadata<'b> {
+        let info = self.extract_crate_info(vi).unwrap();
         let target_triple = self.sess.opts.target_triple[];
         let is_cross = target_triple != config::host_triple();
         let mut should_link = info.should_link && !is_cross;
+        let mut target_only = false;
+        let ident = info.ident.clone();
+        let name = info.name.clone();
         let mut load_ctxt = loader::Context {
             sess: self.sess,
-            span: krate.span,
-            ident: info.ident[],
-            crate_name: info.name[],
+            span: vi.span,
+            ident: ident[],
+            crate_name: name[],
             hash: None,
             filesearch: self.sess.host_filesearch(PathKind::Crate),
             triple: config::host_triple(),
@@ -472,32 +497,49 @@ impl<'a> CrateReader<'a> {
         let library = match load_ctxt.maybe_load_library_crate() {
             Some(l) => l,
             None if is_cross => {
-                // try loading from target crates (only valid if there are
-                // no syntax extensions)
+                // Try loading from target crates. This will abort later if we try to
+                // load a plugin registrar function,
+                target_only = true;
+                should_link = info.should_link;
+
                 load_ctxt.triple = target_triple;
                 load_ctxt.filesearch = self.sess.target_filesearch(PathKind::Crate);
-                let lib = load_ctxt.load_library_crate();
-                if decoder::get_plugin_registrar_fn(lib.metadata.as_slice()).is_some() {
-                    let message = format!("crate `{}` contains a plugin_registrar fn but \
-                                           only a version for triple `{}` could be found (need {})",
-                                           info.ident, target_triple, config::host_triple());
-                    self.sess.span_err(krate.span, message[]);
-                    // need to abort now because the syntax expansion
-                    // code will shortly attempt to load and execute
-                    // code from the found library.
-                    self.sess.abort_if_errors();
-                }
-                should_link = info.should_link;
-                lib
+                load_ctxt.load_library_crate()
             }
             None => { load_ctxt.report_load_errs(); unreachable!() },
         };
 
-        // Read exported macros
-        let imported_from = Some(token::intern(info.ident[]).ident());
-        let source_name = format!("<{} macros>", info.ident[]);
+        let dylib = library.dylib.clone();
+        let register = should_link && self.existing_match(info.name[], None).is_none();
+        let metadata = if register {
+            // Register crate now to avoid double-reading metadata
+            let (_, cmd, _) = self.register_crate(&None, info.ident[],
+                                info.name[], vi.span, library);
+            PMDSource::Registered(cmd)
+        } else {
+            // Not registering the crate; just hold on to the metadata
+            PMDSource::Owned(library.metadata)
+        };
+
+        PluginMetadata {
+            sess: self.sess,
+            metadata: metadata,
+            dylib: dylib,
+            info: info,
+            vi_span: vi.span,
+            target_only: target_only,
+        }
+    }
+}
+
+impl<'a> PluginMetadata<'a> {
+    /// Read exported macros
+    pub fn exported_macros(&self) -> Vec<ast::MacroDef> {
+        let imported_from = Some(token::intern(self.info.ident[]).ident());
+        let source_name = format!("<{} macros>", self.info.ident[]);
         let mut macros = vec![];
-        decoder::each_exported_macro(library.metadata.as_slice(), &*self.sess.cstore.intr,
+        decoder::each_exported_macro(self.metadata.as_slice(),
+                                     &*self.sess.cstore.intr,
             |name, attrs, body| {
                 // NB: Don't use parse::parse_tts_from_source_str because it parses with
                 // quote_depth > 0.
@@ -520,31 +562,37 @@ impl<'a> CrateReader<'a> {
                 true
             }
         );
+        macros
+    }
 
-        // Look for a plugin registrar
-        let registrar = decoder::get_plugin_registrar_fn(library.metadata.as_slice()).map(|id| {
-            decoder::get_symbol(library.metadata.as_slice(), id)
-        });
-        if library.dylib.is_none() && registrar.is_some() {
-            let message = format!("plugin crate `{}` only found in rlib format, \
-                                   but must be available in dylib format",
-                                   info.ident);
-            self.sess.span_err(krate.span, message[]);
-            // No need to abort because the loading code will just ignore this
-            // empty dylib.
+    /// Look for a plugin registrar. Returns library path and symbol name.
+    pub fn plugin_registrar(&self) -> Option<(Path, String)> {
+        if self.target_only {
+            // Need to abort before syntax expansion.
+            let message = format!("plugin crate `{}` is not available for triple `{}` \
+                                   (only found {})",
+                                  self.info.ident,
+                                  config::host_triple(),
+                                  self.sess.opts.target_triple);
+            self.sess.span_err(self.vi_span, message[]);
+            self.sess.abort_if_errors();
         }
-        let pc = PluginMetadata {
-            macros: macros,
-            registrar: match (library.dylib.as_ref(), registrar) {
-                (Some(dylib), Some(reg)) => Some((dylib.clone(), reg)),
-                _ => None,
-            },
-        };
-        if should_link && self.existing_match(info.name[], None).is_none() {
-            // register crate now to avoid double-reading metadata
-            self.register_crate(&None, info.ident[],
-                                info.name[], krate.span, library);
+
+        let registrar = decoder::get_plugin_registrar_fn(self.metadata.as_slice())
+            .map(|id| decoder::get_symbol(self.metadata.as_slice(), id));
+
+        match (self.dylib.as_ref(), registrar) {
+            (Some(dylib), Some(reg)) => Some((dylib.clone(), reg)),
+            (None, Some(_)) => {
+                let message = format!("plugin crate `{}` only found in rlib format, \
+                                       but must be available in dylib format",
+                                       self.info.ident);
+                self.sess.span_err(self.vi_span, message[]);
+                // No need to abort because the loading code will just ignore this
+                // empty dylib.
+                None
+            }
+            _ => None,
         }
-        pc
     }
 }
diff --git a/src/librustc/plugin/load.rs b/src/librustc/plugin/load.rs
index 9aa7d8fe990..78730defc7f 100644
--- a/src/librustc/plugin/load.rs
+++ b/src/librustc/plugin/load.rs
@@ -23,14 +23,6 @@ use syntax::visit;
 use syntax::visit::Visitor;
 use syntax::attr::AttrMetaMethods;
 
-/// Metadata for a single plugin crate.
-pub struct PluginMetadata {
-    /// Macros exported by the crate.
-    pub macros: Vec<ast::MacroDef>,
-    /// Path to the shared library file, and registrar function symbol.
-    pub registrar: Option<(Path, String)>,
-}
-
 /// Pointer to a registrar function.
 pub type PluginRegistrarFun =
     fn(&mut Registry);
@@ -86,37 +78,40 @@ pub fn load_plugins(sess: &Session, krate: &ast::Crate,
 // note that macros aren't expanded yet, and therefore macros can't add plugins.
 impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
     fn visit_view_item(&mut self, vi: &ast::ViewItem) {
+        // We're only interested in `extern crate`.
         match vi.node {
-            ast::ViewItemExternCrate(_, _, _) => {
-                let mut plugin_phase = false;
-
-                for attr in vi.attrs.iter().filter(|a| a.check_name("phase")) {
-                    let phases = attr.meta_item_list().unwrap_or(&[]);
-                    if attr::contains_name(phases, "plugin") {
-                        plugin_phase = true;
-                    }
-                    if attr::contains_name(phases, "syntax") {
-                        plugin_phase = true;
-                        self.sess.span_warn(attr.span,
-                            "phase(syntax) is a deprecated synonym for phase(plugin)");
-                    }
-                }
+            ast::ViewItemExternCrate(..) => (),
+            _ => return,
+        }
 
-                if !plugin_phase { return; }
+        let mut plugin_phase = false;
+        for attr in vi.attrs.iter().filter(|a| a.check_name("phase")) {
+            let phases = attr.meta_item_list().unwrap_or(&[]);
+            if attr::contains_name(phases, "plugin") {
+                plugin_phase = true;
+            }
+            if attr::contains_name(phases, "syntax") {
+                plugin_phase = true;
+                self.sess.span_warn(attr.span,
+                    "phase(syntax) is a deprecated synonym for phase(plugin)");
+            }
+        }
 
-                let PluginMetadata { macros, registrar } =
-                    self.reader.read_plugin_metadata(vi);
+        let mut macros = vec![];
+        let mut registrar = None;
 
-                self.plugins.macros.extend(macros.into_iter());
+        if plugin_phase {
+            let pmd = self.reader.read_plugin_metadata(vi);
+            macros = pmd.exported_macros();
+            registrar = pmd.plugin_registrar();
+        }
 
-                match registrar {
-                    Some((lib, symbol)) => self.dylink_registrar(vi, lib, symbol),
-                    _ => (),
-                }
-            }
-            _ => (),
+        self.plugins.macros.extend(macros.into_iter());
+        if let Some((lib, symbol)) = registrar {
+            self.dylink_registrar(vi, lib, symbol);
         }
     }
+
     fn visit_mac(&mut self, _: &ast::Mac) {
         // bummer... can't see plugins inside macros.
         // do nothing.