about summary refs log tree commit diff
path: root/src/librustc_middle
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-06-16 06:22:52 +0000
committerbors <bors@rust-lang.org>2020-06-16 06:22:52 +0000
commitc8a9c340de32cb70c8bad8af1a4474f805c5a969 (patch)
treebf4dcf744636576c34c3ebb13d5908e42a3f93f5 /src/librustc_middle
parentf315c35a77e40bd11ce81fedc0556be0f410bbf4 (diff)
parentea668d9c548d4490ae9e8ea9b4e8942bae02a8fe (diff)
downloadrust-c8a9c340de32cb70c8bad8af1a4474f805c5a969.tar.gz
rust-c8a9c340de32cb70c8bad8af1a4474f805c5a969.zip
Auto merge of #72962 - lcnr:ObligationCause-lrc, r=ecstatic-morse
store `ObligationCause` on the heap

Stores `ObligationCause` on the heap using an `Rc`.

This PR trades off some transient memory allocations to reduce the size of–and thus the number of instructions required to memcpy–a few widely used data structures in trait solving.
Diffstat (limited to 'src/librustc_middle')
-rw-r--r--src/librustc_middle/traits/mod.rs51
-rw-r--r--src/librustc_middle/traits/structural_impls.rs6
2 files changed, 47 insertions, 10 deletions
diff --git a/src/librustc_middle/traits/mod.rs b/src/librustc_middle/traits/mod.rs
index 56787304d4e..17ea84836bf 100644
--- a/src/librustc_middle/traits/mod.rs
+++ b/src/librustc_middle/traits/mod.rs
@@ -20,7 +20,8 @@ use rustc_span::{Span, DUMMY_SP};
 use smallvec::SmallVec;
 
 use std::borrow::Cow;
-use std::fmt::Debug;
+use std::fmt;
+use std::ops::Deref;
 use std::rc::Rc;
 
 pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache};
@@ -80,8 +81,39 @@ pub enum Reveal {
 }
 
 /// The reason why we incurred this obligation; used for error reporting.
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+///
+/// As the happy path does not care about this struct, storing this on the heap
+/// ends up increasing performance.
+///
+/// We do not want to intern this as there are a lot of obligation causes which
+/// only live for a short period of time.
+#[derive(Clone, PartialEq, Eq, Hash)]
 pub struct ObligationCause<'tcx> {
+    /// `None` for `ObligationCause::dummy`, `Some` otherwise.
+    data: Option<Rc<ObligationCauseData<'tcx>>>,
+}
+
+const DUMMY_OBLIGATION_CAUSE_DATA: ObligationCauseData<'static> =
+    ObligationCauseData { span: DUMMY_SP, body_id: hir::CRATE_HIR_ID, code: MiscObligation };
+
+// Correctly format `ObligationCause::dummy`.
+impl<'tcx> fmt::Debug for ObligationCause<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        ObligationCauseData::fmt(self, f)
+    }
+}
+
+impl Deref for ObligationCause<'tcx> {
+    type Target = ObligationCauseData<'tcx>;
+
+    #[inline(always)]
+    fn deref(&self) -> &Self::Target {
+        self.data.as_deref().unwrap_or(&DUMMY_OBLIGATION_CAUSE_DATA)
+    }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct ObligationCauseData<'tcx> {
     pub span: Span,
 
     /// The ID of the fn body that triggered this obligation. This is
@@ -102,15 +134,24 @@ impl<'tcx> ObligationCause<'tcx> {
         body_id: hir::HirId,
         code: ObligationCauseCode<'tcx>,
     ) -> ObligationCause<'tcx> {
-        ObligationCause { span, body_id, code }
+        ObligationCause { data: Some(Rc::new(ObligationCauseData { span, body_id, code })) }
     }
 
     pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> {
-        ObligationCause { span, body_id, code: MiscObligation }
+        ObligationCause::new(span, body_id, MiscObligation)
     }
 
+    pub fn dummy_with_span(span: Span) -> ObligationCause<'tcx> {
+        ObligationCause::new(span, hir::CRATE_HIR_ID, MiscObligation)
+    }
+
+    #[inline(always)]
     pub fn dummy() -> ObligationCause<'tcx> {
-        ObligationCause { span: DUMMY_SP, body_id: hir::CRATE_HIR_ID, code: MiscObligation }
+        ObligationCause { data: None }
+    }
+
+    pub fn make_mut(&mut self) -> &mut ObligationCauseData<'tcx> {
+        Rc::make_mut(self.data.get_or_insert_with(|| Rc::new(DUMMY_OBLIGATION_CAUSE_DATA)))
     }
 
     pub fn span(&self, tcx: TyCtxt<'tcx>) -> Span {
diff --git a/src/librustc_middle/traits/structural_impls.rs b/src/librustc_middle/traits/structural_impls.rs
index 218bb144469..faaa576f179 100644
--- a/src/librustc_middle/traits/structural_impls.rs
+++ b/src/librustc_middle/traits/structural_impls.rs
@@ -232,11 +232,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::DerivedObligationCause<'a> {
 impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCause<'a> {
     type Lifted = traits::ObligationCause<'tcx>;
     fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.code).map(|code| traits::ObligationCause {
-            span: self.span,
-            body_id: self.body_id,
-            code,
-        })
+        tcx.lift(&self.code).map(|code| traits::ObligationCause::new(self.span, self.body_id, code))
     }
 }