@@ -14,7 +14,6 @@ use cranelift_codegen::ir::types::*;
14
14
use cranelift_codegen:: ir:: { self , types} ;
15
15
use cranelift_codegen:: ir:: { ArgumentPurpose , Function , InstBuilder , MemFlags } ;
16
16
use cranelift_codegen:: isa:: { TargetFrontendConfig , TargetIsa } ;
17
- use cranelift_entity:: packed_option:: ReservedValue as _;
18
17
use cranelift_entity:: { EntityRef , PrimaryMap , SecondaryMap } ;
19
18
use cranelift_frontend:: FunctionBuilder ;
20
19
use cranelift_frontend:: Variable ;
@@ -118,6 +117,9 @@ pub struct FuncEnvironment<'module_environment> {
118
117
/// The Cranelift global holding the vmctx address.
119
118
vmctx : Option < ir:: GlobalValue > ,
120
119
120
+ /// The Cranelift global for our vmctx's `*mut VMStoreContext`.
121
+ vm_store_context : Option < ir:: GlobalValue > ,
122
+
121
123
/// The PCC memory type describing the vmctx layout, if we're
122
124
/// using PCC.
123
125
pcc_vmctx_memtype : Option < ir:: MemoryType > ,
@@ -136,12 +138,6 @@ pub struct FuncEnvironment<'module_environment> {
136
138
/// in `*const VMStoreContext`
137
139
fuel_var : cranelift_frontend:: Variable ,
138
140
139
- /// A function-local variable which caches the value of `*const
140
- /// VMStoreContext` for this function's vmctx argument. This pointer is stored
141
- /// in the vmctx itself, but never changes for the lifetime of the function,
142
- /// so if we load it up front we can continue to use it throughout.
143
- vmstore_context_ptr : ir:: Value ,
144
-
145
141
/// A cached epoch deadline value, when performing epoch-based
146
142
/// interruption. Loaded from `VMStoreContext` and reloaded after
147
143
/// any yield.
@@ -196,14 +192,14 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
196
192
heaps : PrimaryMap :: default ( ) ,
197
193
tables : SecondaryMap :: default ( ) ,
198
194
vmctx : None ,
195
+ vm_store_context : None ,
199
196
pcc_vmctx_memtype : None ,
200
197
builtin_functions,
201
198
offsets : VMOffsets :: new ( compiler. isa ( ) . pointer_bytes ( ) , & translation. module ) ,
202
199
tunables,
203
200
fuel_var : Variable :: new ( 0 ) ,
204
201
epoch_deadline_var : Variable :: new ( 0 ) ,
205
202
epoch_ptr_var : Variable :: new ( 0 ) ,
206
- vmstore_context_ptr : ir:: Value :: reserved_value ( ) ,
207
203
208
204
// Start with at least one fuel being consumed because even empty
209
205
// functions should consume at least some fuel.
@@ -308,22 +304,29 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
308
304
}
309
305
}
310
306
311
- fn declare_vmstore_context_ptr ( & mut self , builder : & mut FunctionBuilder < ' _ > ) {
312
- // We load the `*const VMStoreContext` value stored within vmctx at the
313
- // head of the function and reuse the same value across the entire
314
- // function. This is possible since we know that the pointer never
315
- // changes for the lifetime of the function.
316
- let pointer_type = self . pointer_type ( ) ;
317
- let vmctx = self . vmctx ( builder. func ) ;
318
- let base = builder. ins ( ) . global_value ( pointer_type, vmctx) ;
319
- let offset = i32:: from ( self . offsets . ptr . vmctx_store_context ( ) ) ;
320
- debug_assert ! ( self . vmstore_context_ptr. is_reserved_value( ) ) ;
321
- self . vmstore_context_ptr = builder. ins ( ) . load (
322
- pointer_type,
323
- ir:: MemFlags :: trusted ( ) . with_readonly ( ) . with_can_move ( ) ,
307
+ /// Get or create the `ir::Global` for the `*mut VMStoreContext` in our
308
+ /// `VMContext`.
309
+ fn get_vmstore_context_ptr_global ( & mut self , func : & mut ir:: Function ) -> ir:: GlobalValue {
310
+ if let Some ( ptr) = self . vm_store_context {
311
+ return ptr;
312
+ }
313
+
314
+ let offset = self . offsets . ptr . vmctx_store_context ( ) ;
315
+ let base = self . vmctx ( func) ;
316
+ let ptr = func. create_global_value ( ir:: GlobalValueData :: Load {
324
317
base,
325
- offset,
326
- ) ;
318
+ offset : Offset32 :: new ( offset. into ( ) ) ,
319
+ global_type : self . pointer_type ( ) ,
320
+ flags : ir:: MemFlags :: trusted ( ) . with_readonly ( ) . with_can_move ( ) ,
321
+ } ) ;
322
+ self . vm_store_context = Some ( ptr) ;
323
+ ptr
324
+ }
325
+
326
+ /// Get the `*mut VMStoreContext` value for our `VMContext`.
327
+ fn get_vmstore_context_ptr ( & mut self , builder : & mut FunctionBuilder ) -> ir:: Value {
328
+ let global = self . get_vmstore_context_ptr_global ( & mut builder. func ) ;
329
+ builder. ins ( ) . global_value ( self . pointer_type ( ) , global)
327
330
}
328
331
329
332
fn fuel_function_entry ( & mut self , builder : & mut FunctionBuilder < ' _ > ) {
@@ -471,7 +474,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
471
474
472
475
/// Loads the fuel consumption value from `VMStoreContext` into `self.fuel_var`
473
476
fn fuel_load_into_var ( & mut self , builder : & mut FunctionBuilder < ' _ > ) {
474
- let ( addr, offset) = self . fuel_addr_offset ( ) ;
477
+ let ( addr, offset) = self . fuel_addr_offset ( builder ) ;
475
478
let fuel = builder
476
479
. ins ( )
477
480
. load ( ir:: types:: I64 , ir:: MemFlags :: trusted ( ) , addr, offset) ;
@@ -481,7 +484,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
481
484
/// Stores the fuel consumption value from `self.fuel_var` into
482
485
/// `VMStoreContext`.
483
486
fn fuel_save_from_var ( & mut self , builder : & mut FunctionBuilder < ' _ > ) {
484
- let ( addr, offset) = self . fuel_addr_offset ( ) ;
487
+ let ( addr, offset) = self . fuel_addr_offset ( builder ) ;
485
488
let fuel_consumed = builder. use_var ( self . fuel_var ) ;
486
489
builder
487
490
. ins ( )
@@ -490,10 +493,13 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
490
493
491
494
/// Returns the `(address, offset)` of the fuel consumption within
492
495
/// `VMStoreContext`, used to perform loads/stores later.
493
- fn fuel_addr_offset ( & mut self ) -> ( ir:: Value , ir:: immediates:: Offset32 ) {
494
- debug_assert ! ( !self . vmstore_context_ptr. is_reserved_value( ) ) ;
496
+ fn fuel_addr_offset (
497
+ & mut self ,
498
+ builder : & mut FunctionBuilder < ' _ > ,
499
+ ) -> ( ir:: Value , ir:: immediates:: Offset32 ) {
500
+ let vmstore_ctx = self . get_vmstore_context_ptr ( builder) ;
495
501
(
496
- self . vmstore_context_ptr ,
502
+ vmstore_ctx ,
497
503
i32:: from ( self . offsets . ptr . vmstore_context_fuel_consumed ( ) ) . into ( ) ,
498
504
)
499
505
}
@@ -678,10 +684,11 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
678
684
// We keep the deadline cached in a register to speed the checks
679
685
// in the common case (between epoch ticks) but we want to do a
680
686
// precise check here by reloading the cache first.
687
+ let vmstore_ctx = self . get_vmstore_context_ptr ( builder) ;
681
688
let deadline = builder. ins ( ) . load (
682
689
ir:: types:: I64 ,
683
690
ir:: MemFlags :: trusted ( ) ,
684
- self . vmstore_context_ptr ,
691
+ vmstore_ctx ,
685
692
ir:: immediates:: Offset32 :: new ( self . offsets . ptr . vmstore_context_epoch_deadline ( ) as i32 ) ,
686
693
) ;
687
694
builder. def_var ( self . epoch_deadline_var , deadline) ;
@@ -3098,15 +3105,11 @@ impl FuncEnvironment<'_> {
3098
3105
self . conditionally_trap ( builder, overflow, ir:: TrapCode :: STACK_OVERFLOW ) ;
3099
3106
}
3100
3107
3101
- // If the `vmstore_context_ptr` variable will get used then we
3102
- // initialize it here.
3103
- if self . tunables . consume_fuel || self . tunables . epoch_interruption {
3104
- self . declare_vmstore_context_ptr ( builder) ;
3105
- }
3106
3108
// Additionally we initialize `fuel_var` if it will get used.
3107
3109
if self . tunables . consume_fuel {
3108
3110
self . fuel_function_entry ( builder) ;
3109
3111
}
3112
+
3110
3113
// Initialize `epoch_var` with the current epoch.
3111
3114
if self . tunables . epoch_interruption {
3112
3115
self . epoch_function_entry ( builder) ;
0 commit comments