Skip to content

Commit c2e8f3b

Browse files
author
Jakub Wieczorek
committed
Add a memoize! macro and use it throughout rustc
1 parent 5201bf1 commit c2e8f3b

File tree

3 files changed

+125
-113
lines changed

3 files changed

+125
-113
lines changed

src/librustc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ pub mod middle {
9797
pub mod intrinsicck;
9898
pub mod lang_items;
9999
pub mod liveness;
100+
pub mod macros;
100101
pub mod mem_categorization;
101102
pub mod pat_util;
102103
pub mod privacy;

src/librustc/middle/macros.rs

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright 2014 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+
#![macro_escape]
12+
13+
macro_rules! memoize_expand_block(
14+
($cache_map:expr, $cache_key:expr, $($param_name:ident: $param_ty:ty),*) => { {
15+
match ($cache_map).borrow().find(&$cache_key) {
16+
Some(ref result) => return (*result).clone(),
17+
None => {}
18+
}
19+
let result = inner($($param_name), *);
20+
($cache_map).borrow_mut().insert($cache_key, result.clone());
21+
result
22+
} }
23+
)
24+
25+
/// Memoizes a function using a cache that is available by evaluating the
26+
/// `$cache_map` exression in the context of the function's arguments.
27+
/// `$cache_key` is the expression that will be used to compute the cache key
28+
/// for each function invocation.
29+
///
30+
/// The macro assumes the cache to be a RefCell containing a HashMap,
31+
/// which is in practice how most caching in rustc is currently carried out.
32+
///
33+
/// # Example
34+
///
35+
/// ```
36+
/// struct Context {
37+
/// fibonacci_cache: RefCell<HashMap<uint, uint>>
38+
/// }
39+
///
40+
/// memoize!(context.fibonacci_cache, n,
41+
/// fn fibonacci(context: &Context, n: uint) -> uint {
42+
/// match n {
43+
/// 0 | 1 => n,
44+
/// _ => fibonacci(n - 2) + fibonacci(n - 1)
45+
/// }
46+
/// }
47+
/// )
48+
/// ```
49+
macro_rules! memoize(
50+
($cache_map:expr, $cache_key:expr,
51+
fn $name:ident(
52+
$($param_name:ident: $param_ty:ty),*
53+
) -> $output_ty:ty $block:block
54+
) => {
55+
fn $name($($param_name: $param_ty), *) -> $output_ty {
56+
fn inner($($param_name: $param_ty), *) -> $output_ty $block
57+
memoize_expand_block!($cache_map, $cache_key, $($param_name: $param_ty), *)
58+
}
59+
};
60+
61+
($cache_map:expr, $cache_key:expr,
62+
pub fn $name:ident(
63+
$($param_name:ident: $param_ty:ty),*
64+
) -> $output_ty:ty $block:block
65+
) => {
66+
pub fn $name($($param_name: $param_ty), *) -> $output_ty {
67+
fn inner($($param_name: $param_ty), *) -> $output_ty $block
68+
memoize_expand_block!($cache_map, $cache_key, $($param_name: $param_ty), *)
69+
}
70+
}
71+
)

src/librustc/middle/ty.rs

+53-113
Original file line numberDiff line numberDiff line change
@@ -2117,55 +2117,38 @@ pub fn type_needs_drop(cx: &ctxt, ty: t) -> bool {
21172117
// task can free them all at once later. Currently only things
21182118
// that only contain scalars and shared boxes can avoid unwind
21192119
// cleanups.
2120-
pub fn type_needs_unwind_cleanup(cx: &ctxt, ty: t) -> bool {
2121-
match cx.needs_unwind_cleanup_cache.borrow().find(&ty) {
2122-
Some(&result) => return result,
2123-
None => ()
2124-
}
2125-
2126-
let mut tycache = HashSet::new();
2127-
let needs_unwind_cleanup =
2128-
type_needs_unwind_cleanup_(cx, ty, &mut tycache);
2129-
cx.needs_unwind_cleanup_cache.borrow_mut().insert(ty, needs_unwind_cleanup);
2130-
needs_unwind_cleanup
2131-
}
2132-
2133-
fn type_needs_unwind_cleanup_(cx: &ctxt, ty: t,
2134-
tycache: &mut HashSet<t>) -> bool {
2135-
2120+
memoize!(cx.needs_unwind_cleanup_cache, ty,
2121+
fn type_needs_unwind_cleanup_(cx: &ctxt, ty: t, tycache: &mut HashSet<t>) -> bool {
21362122
// Prevent infinite recursion
21372123
if !tycache.insert(ty) {
21382124
return false;
21392125
}
21402126

21412127
let mut needs_unwind_cleanup = false;
21422128
maybe_walk_ty(ty, |ty| {
2143-
let result = match get(ty).sty {
2144-
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
2145-
ty_tup(_) | ty_ptr(_) => {
2146-
true
2147-
}
2148-
ty_enum(did, ref substs) => {
2149-
for v in (*enum_variants(cx, did)).iter() {
2150-
for aty in v.args.iter() {
2151-
let t = aty.subst(cx, substs);
2152-
needs_unwind_cleanup |=
2153-
type_needs_unwind_cleanup_(cx, t, tycache);
2154-
}
2155-
}
2156-
!needs_unwind_cleanup
2157-
}
2158-
_ => {
2159-
needs_unwind_cleanup = true;
2160-
false
2161-
}
2162-
};
2129+
needs_unwind_cleanup |= match get(ty).sty {
2130+
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) |
2131+
ty_float(_) | ty_tup(_) | ty_ptr(_) => false,
2132+
2133+
ty_enum(did, ref substs) =>
2134+
enum_variants(cx, did).iter().any(|v|
2135+
v.args.iter().any(|aty| {
2136+
let t = aty.subst(cx, substs);
2137+
type_needs_unwind_cleanup_(cx, t, tycache)
2138+
})
2139+
),
21632140

2164-
result
2141+
_ => true
2142+
};
2143+
!needs_unwind_cleanup
21652144
});
2166-
21672145
needs_unwind_cleanup
21682146
}
2147+
)
2148+
2149+
pub fn type_needs_unwind_cleanup(cx: &ctxt, ty: t) -> bool {
2150+
type_needs_unwind_cleanup_(cx, ty, &mut HashSet::new())
2151+
}
21692152

21702153
/**
21712154
* Type contents is how the type checker reasons about kinds.
@@ -2179,6 +2162,7 @@ fn type_needs_unwind_cleanup_(cx: &ctxt, ty: t,
21792162
* easier for me (nmatsakis) to think about what is contained within
21802163
* a type than to think about what is *not* contained within a type.
21812164
*/
2165+
#[deriving(Clone)]
21822166
pub struct TypeContents {
21832167
pub bits: u64
21842168
}
@@ -2358,19 +2342,9 @@ pub fn type_interior_is_unsafe(cx: &ctxt, t: ty::t) -> bool {
23582342
type_contents(cx, t).interior_unsafe()
23592343
}
23602344

2345+
memoize!(cx.tc_cache, type_id(ty),
23612346
pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
2362-
let ty_id = type_id(ty);
2363-
2364-
match cx.tc_cache.borrow().find(&ty_id) {
2365-
Some(tc) => { return *tc; }
2366-
None => {}
2367-
}
2368-
2369-
let mut cache = HashMap::new();
2370-
let result = tc_ty(cx, ty, &mut cache);
2371-
2372-
cx.tc_cache.borrow_mut().insert(ty_id, result);
2373-
return result;
2347+
return tc_ty(cx, ty, &mut HashMap::new());
23742348

23752349
fn tc_ty(cx: &ctxt,
23762350
ty: t,
@@ -2685,6 +2659,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
26852659
}
26862660
}
26872661
}
2662+
)
26882663

26892664
pub fn type_moves_by_default(cx: &ctxt, ty: t) -> bool {
26902665
type_contents(cx, ty).moves_by_default(cx)
@@ -4033,28 +4008,23 @@ pub fn impl_or_trait_item(cx: &ctxt, id: ast::DefId) -> ImplOrTraitItem {
40334008

40344009
/// Returns true if the given ID refers to an associated type and false if it
40354010
/// refers to anything else.
4011+
memoize!(cx.associated_types, id,
40364012
pub fn is_associated_type(cx: &ctxt, id: ast::DefId) -> bool {
4037-
let result = match cx.associated_types.borrow_mut().find(&id) {
4038-
Some(result) => return *result,
4039-
None if id.krate == ast::LOCAL_CRATE => {
4040-
match cx.impl_or_trait_items.borrow().find(&id) {
4041-
Some(ref item) => {
4042-
match **item {
4043-
TypeTraitItem(_) => true,
4044-
MethodTraitItem(_) => false,
4045-
}
4013+
if id.krate == ast::LOCAL_CRATE {
4014+
match cx.impl_or_trait_items.borrow().find(&id) {
4015+
Some(ref item) => {
4016+
match **item {
4017+
TypeTraitItem(_) => true,
4018+
MethodTraitItem(_) => false,
40464019
}
4047-
None => false,
40484020
}
4021+
None => false,
40494022
}
4050-
None => {
4051-
csearch::is_associated_type(&cx.sess.cstore, id)
4052-
}
4053-
};
4054-
4055-
cx.associated_types.borrow_mut().insert(id, result);
4056-
result
4023+
} else {
4024+
csearch::is_associated_type(&cx.sess.cstore, id)
4025+
}
40574026
}
4027+
)
40584028

40594029
/// Returns the parameter index that the given associated type corresponds to.
40604030
pub fn associated_type_parameter_index(cx: &ctxt,
@@ -4110,13 +4080,9 @@ pub fn trait_item_def_ids(cx: &ctxt, id: ast::DefId)
41104080
})
41114081
}
41124082

4083+
memoize!(cx.impl_trait_cache, id,
41134084
pub fn impl_trait_ref(cx: &ctxt, id: ast::DefId) -> Option<Rc<TraitRef>> {
4114-
match cx.impl_trait_cache.borrow().find(&id) {
4115-
Some(ret) => { return ret.clone(); }
4116-
None => {}
4117-
}
4118-
4119-
let ret = if id.krate == ast::LOCAL_CRATE {
4085+
if id.krate == ast::LOCAL_CRATE {
41204086
debug!("(impl_trait_ref) searching for trait impl {:?}", id);
41214087
match cx.map.find(id.node) {
41224088
Some(ast_map::NodeItem(item)) => {
@@ -4136,11 +4102,9 @@ pub fn impl_trait_ref(cx: &ctxt, id: ast::DefId) -> Option<Rc<TraitRef>> {
41364102
}
41374103
} else {
41384104
csearch::get_impl_trait(cx, id)
4139-
};
4140-
4141-
cx.impl_trait_cache.borrow_mut().insert(id, ret.clone());
4142-
ret
4105+
}
41434106
}
4107+
)
41444108

41454109
pub fn trait_ref_to_def_id(tcx: &ctxt, tr: &ast::TraitRef) -> ast::DefId {
41464110
let def = *tcx.def_map.borrow()
@@ -4324,13 +4288,9 @@ pub fn type_is_empty(cx: &ctxt, t: t) -> bool {
43244288
}
43254289
}
43264290

4291+
memoize!(cx.enum_var_cache, id,
43274292
pub fn enum_variants(cx: &ctxt, id: ast::DefId) -> Rc<Vec<Rc<VariantInfo>>> {
4328-
match cx.enum_var_cache.borrow().find(&id) {
4329-
Some(variants) => return variants.clone(),
4330-
_ => { /* fallthrough */ }
4331-
}
4332-
4333-
let result = if ast::LOCAL_CRATE != id.krate {
4293+
if ast::LOCAL_CRATE != id.krate {
43344294
Rc::new(csearch::get_enum_variants(cx, id))
43354295
} else {
43364296
/*
@@ -4385,12 +4345,9 @@ pub fn enum_variants(cx: &ctxt, id: ast::DefId) -> Rc<Vec<Rc<VariantInfo>>> {
43854345
}
43864346
_ => cx.sess.bug("enum_variants: id not bound to an enum")
43874347
}
4388-
};
4389-
4390-
cx.enum_var_cache.borrow_mut().insert(id, result.clone());
4391-
result
4348+
}
43924349
}
4393-
4350+
)
43944351

43954352
// Returns information about the enum variant with the given ID:
43964353
pub fn enum_variant_with_id(cx: &ctxt,
@@ -4415,22 +4372,12 @@ pub fn lookup_item_type(cx: &ctxt,
44154372
}
44164373

44174374
/// Given the did of a trait, returns its canonical trait ref.
4375+
memoize!(cx.trait_defs, did,
44184376
pub fn lookup_trait_def(cx: &ctxt, did: ast::DefId) -> Rc<ty::TraitDef> {
4419-
let mut trait_defs = cx.trait_defs.borrow_mut();
4420-
match trait_defs.find_copy(&did) {
4421-
Some(trait_def) => {
4422-
// The item is in this crate. The caller should have added it to the
4423-
// type cache already
4424-
trait_def
4425-
}
4426-
None => {
4427-
assert!(did.krate != ast::LOCAL_CRATE);
4428-
let trait_def = Rc::new(csearch::get_trait_def(cx, did));
4429-
trait_defs.insert(did, trait_def.clone());
4430-
trait_def
4431-
}
4432-
}
4377+
assert!(did.krate != ast::LOCAL_CRATE);
4378+
Rc::new(csearch::get_trait_def(cx, did))
44334379
}
4380+
)
44344381

44354382
/// Given a reference to a trait, returns the bounds declared on the
44364383
/// trait, with appropriate substitutions applied.
@@ -4489,13 +4436,9 @@ pub fn lookup_simd(tcx: &ctxt, did: DefId) -> bool {
44894436
}
44904437

44914438
/// Obtain the representation annotation for a struct definition.
4439+
memoize!(tcx.repr_hint_cache, did,
44924440
pub fn lookup_repr_hints(tcx: &ctxt, did: DefId) -> Rc<Vec<attr::ReprAttr>> {
4493-
match tcx.repr_hint_cache.borrow().find(&did) {
4494-
None => {}
4495-
Some(ref hints) => return (*hints).clone(),
4496-
}
4497-
4498-
let acc = if did.krate == LOCAL_CRATE {
4441+
Rc::new(if did.krate == LOCAL_CRATE {
44994442
let mut acc = Vec::new();
45004443
ty::each_attr(tcx, did, |meta| {
45014444
acc.extend(attr::find_repr_attrs(tcx.sess.diagnostic(),
@@ -4505,12 +4448,9 @@ pub fn lookup_repr_hints(tcx: &ctxt, did: DefId) -> Rc<Vec<attr::ReprAttr>> {
45054448
acc
45064449
} else {
45074450
csearch::get_repr_attrs(&tcx.sess.cstore, did)
4508-
};
4509-
4510-
let acc = Rc::new(acc);
4511-
tcx.repr_hint_cache.borrow_mut().insert(did, acc.clone());
4512-
acc
4451+
})
45134452
}
4453+
)
45144454

45154455
// Look up a field ID, whether or not it's local
45164456
// Takes a list of type substs in case the struct is generic

0 commit comments

Comments
 (0)