Skip to content

Commit 244ae8e

Browse files
committed
Introduce try_read_value to avoid allocations.
Attempt reading a primitive value out of any source lvalue and write that into the destination without making an allocation if possible.
1 parent 140b21e commit 244ae8e

File tree

1 file changed

+22
-15
lines changed

1 file changed

+22
-15
lines changed

src/interpreter/mod.rs

+22-15
Original file line numberDiff line numberDiff line change
@@ -1265,12 +1265,16 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
12651265
// if they referred to the same allocation, since then a change to one would
12661266
// implicitly change the other.
12671267
//
1268-
// TODO(solson): It would be valid to attempt reading a primitive value out of
1269-
// the source and writing that into the destination without making an
1270-
// allocation. This would be a pure optimization.
1271-
let dest_ptr = self.alloc_ptr(dest_ty)?;
1272-
self.copy(src_ptr, dest_ptr, dest_ty)?;
1273-
write_dest(self, Value::ByRef(dest_ptr));
1268+
// It is a valid optimization to attempt reading a primitive value out of the
1269+
// source and write that into the destination without making an allocation, so
1270+
// we do so here.
1271+
if let Ok(Some(src_val)) = self.try_read_value(src_ptr, dest_ty) {
1272+
write_dest(self, src_val);
1273+
} else {
1274+
let dest_ptr = self.alloc_ptr(dest_ty)?;
1275+
self.copy(src_ptr, dest_ptr, dest_ty)?;
1276+
write_dest(self, Value::ByRef(dest_ptr));
1277+
}
12741278

12751279
} else {
12761280
// Finally, we have the simple case where neither source nor destination are
@@ -1400,6 +1404,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
14001404
}
14011405

14021406
fn read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
1407+
if let Some(val) = self.try_read_value(ptr, ty)? {
1408+
Ok(val)
1409+
} else {
1410+
bug!("primitive read failed for type: {:?}", ty);
1411+
}
1412+
}
1413+
1414+
fn try_read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
14031415
use syntax::ast::FloatTy;
14041416

14051417
let val = match ty.sty {
@@ -1439,11 +1451,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
14391451
ty::TyFloat(FloatTy::F32) => PrimVal::from_f32(self.memory.read_f32(ptr)?),
14401452
ty::TyFloat(FloatTy::F64) => PrimVal::from_f64(self.memory.read_f64(ptr)?),
14411453

1442-
// TODO(solson): Should this even be here? Fn items aren't primvals, are they?
1443-
ty::TyFnDef(def_id, substs, fn_ty) => {
1444-
PrimVal::from_ptr(self.memory.create_fn_ptr(self.tcx, def_id, substs, fn_ty))
1445-
},
1446-
14471454
ty::TyFnPtr(_) => self.memory.read_ptr(ptr).map(PrimVal::from_ptr)?,
14481455
ty::TyBox(ty) |
14491456
ty::TyRef(_, ty::TypeAndMut { ty, .. }) |
@@ -1460,7 +1467,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
14601467
ty::TyStr => PrimVal::from_uint(self.memory.read_usize(extra)?),
14611468
_ => bug!("unsized primval ptr read from {:?}", ty),
14621469
};
1463-
return Ok(Value::ByValPair(PrimVal::from_ptr(p), extra));
1470+
return Ok(Some(Value::ByValPair(PrimVal::from_ptr(p), extra)));
14641471
}
14651472
}
14661473

@@ -1474,14 +1481,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
14741481
PrimVal::from_uint(self.memory.read_uint(ptr, size)?)
14751482
}
14761483
} else {
1477-
bug!("primitive read of non-clike enum: {:?}", ty);
1484+
return Ok(None);
14781485
}
14791486
},
14801487

1481-
_ => bug!("primitive read of non-primitive type: {:?}", ty),
1488+
_ => return Ok(None),
14821489
};
14831490

1484-
Ok(Value::ByVal(val))
1491+
Ok(Some(Value::ByVal(val)))
14851492
}
14861493

14871494
fn frame(&self) -> &Frame<'tcx> {

0 commit comments

Comments
 (0)