@@ -119,6 +119,57 @@ impl<'a> ProductionNativeContext<'a> {
119119 returns_started : Cell :: new ( false ) ,
120120 }
121121 }
122+
123+ /// Borrows the global-storage value at `storage_key`, rooting a reference to
124+ /// it for the rest of the call, or `None` if the value does not exist. A
125+ /// mutable borrow of an external or stale value first deep-copies it into
126+ /// the local heap (copy-on-write).
127+ fn borrow_storage_value (
128+ & self ,
129+ storage_key : InMemoryStorageKey ,
130+ mutable : bool ,
131+ ) -> Result < Option < Ref < ' _ , Opaque > > , VMInternalError > {
132+ // SAFETY: heap and rws are distinct fields (see the aliasing rule).
133+ let rws = unsafe { & mut * * self . rws . get ( ) } ;
134+ let ptr = if mutable {
135+ match rws. try_borrow_global_mut ( self . resource_provider , & storage_key) {
136+ Ok ( EntryPtr :: Writable ( ptr) ) => ptr,
137+ Ok ( EntryPtr :: NonWritable ( ptr) ) => {
138+ // Copy-on-write: an external or stale value must be copied
139+ // into the local heap before it can be mutated.
140+ let heap = unsafe { & mut * * self . heap . get ( ) } ;
141+ // SAFETY: `ptr` is a live object (provider- or older-epoch-owned).
142+ let copied = unsafe {
143+ deep_copy_or_gc (
144+ heap,
145+ self . desc_provider ,
146+ rws,
147+ & self . pool ,
148+ self . extensions ,
149+ self . frame_ptr ,
150+ TopFrame :: Native ( self . abi ) ,
151+ ptr,
152+ )
153+ }
154+ . map_err ( VMInternalError :: from) ?;
155+ rws. commit_borrow_global_mut ( & storage_key, copied) ;
156+ copied
157+ } ,
158+ Err ( RuntimeError :: ResourceDoesNotExist { .. } ) => return Ok ( None ) ,
159+ Err ( e) => return Err ( e. into ( ) ) ,
160+ }
161+ } else {
162+ match rws. borrow_global ( self . resource_provider , & storage_key) {
163+ Ok ( ptr) => ptr,
164+ Err ( RuntimeError :: ResourceDoesNotExist { .. } ) => return Ok ( None ) ,
165+ Err ( e) => return Err ( e. into ( ) ) ,
166+ }
167+ } ;
168+ // SAFETY: `ptr` is the live value; the reference points at its start, so
169+ // the offset is 0. The pool roots it for the rest of the call.
170+ let handle = unsafe { self . pool . root_reference ( ptr. as_ptr ( ) , 0 ) } ;
171+ Ok ( Some ( Ref :: from_handle ( handle) ) )
172+ }
122173}
123174
124175impl NativeContext for ProductionNativeContext < ' _ > {
@@ -434,6 +485,16 @@ impl NativeContext for ProductionNativeContext<'_> {
434485 Ok ( rws. exists ( self . resource_provider , & key) ?)
435486 }
436487
488+ fn borrow_resource (
489+ & self ,
490+ address : AccountAddress ,
491+ mutable : bool ,
492+ ty : InternedType ,
493+ ) -> Result < Option < Ref < ' _ , Opaque > > , VMInternalError > {
494+ let storage_key = InMemoryStorageKey :: resource ( address, ty) ;
495+ self . borrow_storage_value ( storage_key, mutable)
496+ }
497+
437498 fn bcs_serialize_arg ( & self , i : usize , ty : InternedType ) -> Result < Vec < u8 > , VMInternalError > {
438499 let slot = self . abi . args ( ) . get ( i) . copied ( ) . ok_or_else ( || {
439500 VMInternalError :: invariant_violation ( format ! ( "arg index {i} out of bounds" ) )
@@ -514,46 +575,7 @@ impl NativeContext for ProductionNativeContext<'_> {
514575 value_ty : InternedType ,
515576 ) -> Result < Option < Ref < ' _ , Opaque > > , VMInternalError > {
516577 let storage_key = InMemoryStorageKey :: table_item ( * handle, key. into ( ) , value_ty) ;
517- // SAFETY: heap and rws are distinct fields (see the aliasing rule).
518- let rws = unsafe { & mut * * self . rws . get ( ) } ;
519- let ptr = if mutable {
520- match rws. try_borrow_global_mut ( self . resource_provider , & storage_key) {
521- Ok ( EntryPtr :: Writable ( ptr) ) => ptr,
522- Ok ( EntryPtr :: NonWritable ( ptr) ) => {
523- // Copy-on-write: an external or stale value must be copied
524- // into the local heap before it can be mutated.
525- let heap = unsafe { & mut * * self . heap . get ( ) } ;
526- // SAFETY: `ptr` is a live object (provider- or older-epoch-owned).
527- let copied = unsafe {
528- deep_copy_or_gc (
529- heap,
530- self . desc_provider ,
531- rws,
532- & self . pool ,
533- self . extensions ,
534- self . frame_ptr ,
535- TopFrame :: Native ( self . abi ) ,
536- ptr,
537- )
538- }
539- . map_err ( VMInternalError :: from) ?;
540- rws. commit_borrow_global_mut ( & storage_key, copied) ;
541- copied
542- } ,
543- Err ( RuntimeError :: ResourceDoesNotExist { .. } ) => return Ok ( None ) ,
544- Err ( e) => return Err ( e. into ( ) ) ,
545- }
546- } else {
547- match rws. borrow_global ( self . resource_provider , & storage_key) {
548- Ok ( ptr) => ptr,
549- Err ( RuntimeError :: ResourceDoesNotExist { .. } ) => return Ok ( None ) ,
550- Err ( e) => return Err ( e. into ( ) ) ,
551- }
552- } ;
553- // SAFETY: `ptr` is the live entry value; the reference points at its
554- // start, so the offset is 0. The pool roots it for the rest of the call.
555- let handle = unsafe { self . pool . root_reference ( ptr. as_ptr ( ) , 0 ) } ;
556- Ok ( Some ( Ref :: from_handle ( handle) ) )
578+ self . borrow_storage_value ( storage_key, mutable)
557579 }
558580
559581 // TODO(cleanup): See if there's a way to separate out argument-reading from boxing.
0 commit comments