Skip to content

Commit

Permalink
Add a query to convert from ConstValue to Allocation
Browse files Browse the repository at this point in the history
  • Loading branch information
Zoxc committed May 11, 2018
1 parent fdd9787 commit 0aa92ac
Show file tree
Hide file tree
Showing 10 changed files with 110 additions and 21 deletions.
11 changes: 6 additions & 5 deletions src/librustc/dep_graph/dep_node.rs
Expand Up @@ -621,13 +621,14 @@ define_dep_nodes!( <'tcx>
[input] UsedCrateSource(CrateNum),
[input] PostorderCnums,

// This query is not expected to have inputs -- as a result, it's
// not a good candidate for "replay" because it's essentially a
// pure function of its input (and hence the expectation is that
// no caller would be green **apart** from just this
// query). Making it anonymous avoids hashing the result, which
// These queries are not expected to have inputs -- as a result, they
// are not good candidates for "replay" because they are essentially
// pure functions of their input (and hence the expectation is that
// no caller would be green **apart** from just these
// queries). Making them anonymous avoids hashing the result, which
// may save a bit of time.
[anon] EraseRegionsTy { ty: Ty<'tcx> },
[anon] ConstValueToAllocation { val: ConstValue<'tcx>, ty: Ty<'tcx> },

[input] Freevars(DefId),
[input] MaybeUnusedTraitImport(DefId),
Expand Down
6 changes: 6 additions & 0 deletions src/librustc/ty/maps/config.rs
Expand Up @@ -137,6 +137,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::super_predicates_of<'tcx> {
}
}

impl<'tcx> QueryDescription<'tcx> for queries::const_value_to_allocation<'tcx> {
fn describe(_tcx: TyCtxt, (val, ty): (ConstValue<'tcx>, Ty<'tcx>)) -> String {
format!("converting value `{:?}` ({}) to an allocation", val, ty)
}
}

impl<'tcx> QueryDescription<'tcx> for queries::erase_regions_ty<'tcx> {
fn describe(_tcx: TyCtxt, ty: Ty<'tcx>) -> String {
format!("erasing regions from `{:?}`", ty)
Expand Down
9 changes: 9 additions & 0 deletions src/librustc/ty/maps/keys.rs
Expand Up @@ -145,6 +145,15 @@ impl<'tcx> Key for ty::PolyTraitRef<'tcx>{
}
}

impl<'tcx> Key for (mir::interpret::ConstValue<'tcx>, Ty<'tcx>) {
fn map_crate(&self) -> CrateNum {
LOCAL_CRATE
}
fn default_span(&self, _: TyCtxt) -> Span {
DUMMY_SP
}
}

impl<'tcx> Key for Ty<'tcx> {
fn map_crate(&self) -> CrateNum {
LOCAL_CRATE
Expand Down
11 changes: 11 additions & 0 deletions src/librustc/ty/maps/mod.rs
Expand Up @@ -228,6 +228,11 @@ define_maps! { <'tcx>
[] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
-> EvalResult<'tcx>,

/// Converts a constant value to an constant allocation
[] fn const_value_to_allocation: const_value_to_allocation(
(ConstValue<'tcx>, Ty<'tcx>)
) -> &'tcx Allocation,

[] fn check_match: CheckMatch(DefId)
-> Result<(), ErrorReported>,

Expand Down Expand Up @@ -478,6 +483,12 @@ fn erase_regions_ty<'tcx>(ty: Ty<'tcx>) -> DepConstructor<'tcx> {
DepConstructor::EraseRegionsTy { ty }
}

fn const_value_to_allocation<'tcx>(
(val, ty): (ConstValue<'tcx>, Ty<'tcx>)
) -> DepConstructor<'tcx> {
DepConstructor::ConstValueToAllocation { val, ty }
}

fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
DepConstructor::TypeParamPredicates {
item_id,
Expand Down
1 change: 1 addition & 0 deletions src/librustc/ty/maps/plumbing.rs
Expand Up @@ -956,6 +956,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
DepKind::FulfillObligation |
DepKind::VtableMethods |
DepKind::EraseRegionsTy |
DepKind::ConstValueToAllocation |
DepKind::NormalizeProjectionTy |
DepKind::NormalizeTyAfterErasingRegions |
DepKind::DropckOutlives |
Expand Down
28 changes: 26 additions & 2 deletions src/librustc_mir/interpret/const_eval.rs
Expand Up @@ -8,12 +8,13 @@ use rustc::ty::subst::Subst;

use syntax::ast::Mutability;
use syntax::codemap::Span;
use syntax::codemap::DUMMY_SP;

use rustc::mir::interpret::{
EvalResult, EvalError, EvalErrorKind, GlobalId,
Value, Pointer, PrimVal, AllocId, Allocation, ConstValue,
};
use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory};
use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory, MemoryKind};

use std::fmt;
use std::error::Error;
Expand Down Expand Up @@ -470,7 +471,6 @@ pub fn const_variant_index<'a, 'tcx>(
let (ptr, align) = match value {
Value::ByValPair(..) | Value::ByVal(_) => {
let layout = ecx.layout_of(ty)?;
use super::MemoryKind;
let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?;
let ptr: Pointer = ptr.into();
ecx.write_value_to_ptr(value, ptr, layout.align, ty)?;
Expand All @@ -482,6 +482,30 @@ pub fn const_variant_index<'a, 'tcx>(
ecx.read_discriminant_as_variant_index(place, ty)
}

pub fn const_value_to_allocation_provider<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
(val, ty): (ConstValue<'tcx>, Ty<'tcx>),
) -> &'tcx Allocation {
match val {
ConstValue::ByRef(alloc) => return alloc,
_ => ()
}
let result = || -> EvalResult<'tcx, &'tcx Allocation> {
let mut ecx = EvalContext::new(
tcx.at(DUMMY_SP),
ty::ParamEnv::reveal_all(),
CompileTimeEvaluator,
());
let value = ecx.const_value_to_value(val, ty)?;
let layout = ecx.layout_of(ty)?;
let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?;
ecx.write_value_to_ptr(value, ptr.into(), layout.align, ty)?;
let alloc = ecx.memory.get(ptr.alloc_id)?;
Ok(tcx.intern_const_alloc(alloc.clone()))
};
result().expect("unable to convert ConstVal to Allocation")
}

pub fn const_eval_provider<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
Expand Down
50 changes: 42 additions & 8 deletions src/librustc_mir/interpret/memory.rs
@@ -1,14 +1,17 @@
use std::collections::{btree_map, VecDeque};
use std::ptr;

use rustc::hir::def_id::DefId;
use rustc::ty::Instance;
use rustc::ty::ParamEnv;
use rustc::ty::maps::TyCtxtAt;
use rustc::ty::layout::{self, Align, TargetDataLayout};
use syntax::ast::Mutability;
use rustc::middle::const_val::{ConstVal, ErrKind};

use rustc_data_structures::fx::{FxHashSet, FxHashMap};
use rustc::mir::interpret::{MemoryPointer, AllocId, Allocation, AccessKind, Value, Pointer,
EvalResult, PrimVal, EvalErrorKind};
EvalResult, PrimVal, EvalErrorKind, GlobalId};
pub use rustc::mir::interpret::{write_target_uint, write_target_int, read_target_uint};

use super::{EvalContext, Machine};
Expand Down Expand Up @@ -274,6 +277,31 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {

/// Allocation accessors
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
fn const_eval_static(&self, def_id: DefId) -> EvalResult<'tcx, &'tcx Allocation> {
let instance = Instance::mono(self.tcx.tcx, def_id);
let gid = GlobalId {
instance,
promoted: None,
};
self.tcx.const_eval(ParamEnv::reveal_all().and(gid)).map_err(|err| {
match *err.kind {
ErrKind::Miri(ref err, _) => match err.kind {
EvalErrorKind::TypeckError |
EvalErrorKind::Layout(_) => EvalErrorKind::TypeckError.into(),
_ => EvalErrorKind::ReferencedConstant.into(),
},
ErrKind::TypeckError => EvalErrorKind::TypeckError.into(),
ref other => bug!("const eval returned {:?}", other),
}
}).map(|val| {
let const_val = match val.val {
ConstVal::Value(val) => val,
ConstVal::Unevaluated(..) => bug!("should be evaluated"),
};
self.tcx.const_value_to_allocation((const_val, val.ty))
})
}

pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
// normal alloc?
match self.alloc_map.get(&id) {
Expand All @@ -283,13 +311,19 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
Some(alloc) => Ok(alloc),
None => {
// static alloc?
self.tcx.interpret_interner.get_alloc(id)
// no alloc? produce an error
.ok_or_else(|| if self.tcx.interpret_interner.get_fn(id).is_some() {
EvalErrorKind::DerefFunctionPointer.into()
} else {
EvalErrorKind::DanglingPointerDeref.into()
})
if let Some(a) = self.tcx.interpret_interner.get_alloc(id) {
return Ok(a);
}
// static variable?
if let Some(did) = self.tcx.interpret_interner.get_static(id) {
return self.const_eval_static(did);
}
// otherwise return an error
Err(if self.tcx.interpret_interner.get_fn(id).is_some() {
EvalErrorKind::DerefFunctionPointer.into()
} else {
EvalErrorKind::DanglingPointerDeref.into()
})
},
},
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc_mir/interpret/mod.rs
Expand Up @@ -23,6 +23,7 @@ pub use self::const_eval::{
mk_borrowck_eval_cx,
eval_body,
CompileTimeEvaluator,
const_value_to_allocation_provider,
const_eval_provider,
const_val_field,
const_variant_index,
Expand Down
1 change: 1 addition & 0 deletions src/librustc_mir/lib.rs
Expand Up @@ -85,6 +85,7 @@ pub fn provide(providers: &mut Providers) {
shim::provide(providers);
transform::provide(providers);
providers.const_eval = interpret::const_eval_provider;
providers.const_value_to_allocation = interpret::const_value_to_allocation_provider;
providers.check_match = hair::pattern::check_match;
}

Expand Down
13 changes: 7 additions & 6 deletions src/librustc_trans/base.rs
Expand Up @@ -1373,6 +1373,7 @@ mod temp_stable_hash_impls {

fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec<u8>) {
use rustc::mir::interpret::GlobalId;
use rustc::middle::const_val::ConstVal;

info!("loading wasm section {:?}", id);

Expand All @@ -1391,11 +1392,11 @@ fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec<u8>) {
let param_env = ty::ParamEnv::reveal_all();
let val = tcx.const_eval(param_env.and(cid)).unwrap();

let mem = val.to_ptr().expect("should be pointer");
assert_eq!(mem.offset, 0);
let alloc = tcx
.interpret_interner
.get_alloc(mem.alloc_id)
.expect("miri allocation never successfully created");
let const_val = match val.val {
ConstVal::Value(val) => val,
ConstVal::Unevaluated(..) => bug!("should be evaluated"),
};

let alloc = tcx.const_value_to_allocation((const_val, val.ty));
(section.to_string(), alloc.bytes.clone())
}

0 comments on commit 0aa92ac

Please sign in to comment.