@@ -189,6 +189,22 @@ impl<'tcx> OpTy<'tcx> {
189189 }
190190}
191191
192+ // Use the existing layout if given (but sanity check in debug mode),
193+ // or compute the layout.
194+ #[ inline( always) ]
195+ fn from_known_layout < ' tcx > (
196+ layout : Option < TyLayout < ' tcx > > ,
197+ compute : impl FnOnce ( ) -> EvalResult < ' tcx , TyLayout < ' tcx > >
198+ ) -> EvalResult < ' tcx , TyLayout < ' tcx > > {
199+ match layout {
200+ None => compute ( ) ,
201+ Some ( layout) => {
202+ debug_assert_eq ! ( layout. ty, compute( ) ?. ty) ;
203+ Ok ( layout)
204+ }
205+ }
206+ }
207+
192208impl < ' a , ' mir , ' tcx , M : Machine < ' mir , ' tcx > > EvalContext < ' a , ' mir , ' tcx , M > {
193209 /// Try reading a value in memory; this is interesting particularily for ScalarPair.
194210 /// Return None if the layout does not permit loading this as a value.
@@ -377,21 +393,25 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
377393 }
378394
379395 // Evaluate a place with the goal of reading from it. This lets us sometimes
380- // avoid allocations.
396+ // avoid allocations. If you already know the layout, you can pass it in
397+ // to avoid looking it up again.
381398 fn eval_place_to_op (
382399 & mut self ,
383400 mir_place : & mir:: Place < ' tcx > ,
401+ layout : Option < TyLayout < ' tcx > > ,
384402 ) -> EvalResult < ' tcx , OpTy < ' tcx > > {
385403 use rustc:: mir:: Place :: * ;
386404 Ok ( match * mir_place {
387405 Local ( mir:: RETURN_PLACE ) => return err ! ( ReadFromReturnPointer ) ,
388406 Local ( local) => {
389407 let op = * self . frame ( ) . locals [ local] . access ( ) ?;
390- OpTy { op, layout : self . layout_of_local ( self . cur_frame ( ) , local) ? }
408+ let layout = from_known_layout ( layout,
409+ || self . layout_of_local ( self . cur_frame ( ) , local) ) ?;
410+ OpTy { op, layout }
391411 } ,
392412
393413 Projection ( ref proj) => {
394- let op = self . eval_place_to_op ( & proj. base ) ?;
414+ let op = self . eval_place_to_op ( & proj. base , None ) ?;
395415 self . operand_projection ( op, & proj. elem ) ?
396416 }
397417
@@ -406,17 +426,25 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
406426 }
407427
408428 /// Evaluate the operand, returning a place where you can then find the data.
409- pub fn eval_operand ( & mut self , mir_op : & mir:: Operand < ' tcx > ) -> EvalResult < ' tcx , OpTy < ' tcx > > {
429+ /// if you already know the layout, you can save two some table lookups
430+ /// by passing it in here.
431+ pub fn eval_operand (
432+ & mut self ,
433+ mir_op : & mir:: Operand < ' tcx > ,
434+ layout : Option < TyLayout < ' tcx > > ,
435+ ) -> EvalResult < ' tcx , OpTy < ' tcx > > {
410436 use rustc:: mir:: Operand :: * ;
411437 let op = match * mir_op {
412438 // FIXME: do some more logic on `move` to invalidate the old location
413439 Copy ( ref place) |
414440 Move ( ref place) =>
415- self . eval_place_to_op ( place) ?,
441+ self . eval_place_to_op ( place, layout ) ?,
416442
417443 Constant ( ref constant) => {
418- let ty = self . monomorphize ( mir_op. ty ( self . mir ( ) , * self . tcx ) , self . substs ( ) ) ;
419- let layout = self . layout_of ( ty) ?;
444+ let layout = from_known_layout ( layout, || {
445+ let ty = self . monomorphize ( mir_op. ty ( self . mir ( ) , * self . tcx ) , self . substs ( ) ) ;
446+ self . layout_of ( ty)
447+ } ) ?;
420448 let op = self . const_value_to_op ( constant. literal . val ) ?;
421449 OpTy { op, layout }
422450 }
@@ -431,7 +459,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
431459 ops : & [ mir:: Operand < ' tcx > ] ,
432460 ) -> EvalResult < ' tcx , Vec < OpTy < ' tcx > > > {
433461 ops. into_iter ( )
434- . map ( |op| self . eval_operand ( op) )
462+ . map ( |op| self . eval_operand ( op, None ) )
435463 . collect ( )
436464 }
437465
@@ -473,7 +501,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
473501 & mut self ,
474502 op : & mir:: Operand < ' tcx > ,
475503 ) -> EvalResult < ' tcx , ValTy < ' tcx > > {
476- let op = self . eval_operand ( op) ?;
504+ let op = self . eval_operand ( op, None ) ?;
477505 self . read_value ( op)
478506 }
479507 pub fn eval_operand_and_read_scalar (
0 commit comments