@@ -13,7 +13,7 @@ use crate::util::heap::{PageResource, VMRequest};
1313use crate :: util:: options:: Options ;
1414use crate :: vm:: { ActivePlan , Collection } ;
1515
16- use crate :: util:: constants:: LOG_BYTES_IN_MBYTE ;
16+ use crate :: util:: constants:: { LOG_BYTES_IN_MBYTE , LOG_BYTES_IN_PAGE } ;
1717use crate :: util:: conversions;
1818use crate :: util:: opaque_pointer:: * ;
1919
@@ -46,8 +46,42 @@ pub trait Space<VM: VMBinding>: 'static + SFT + Sync + Downcast {
4646 /// Currently after we create a boxed plan, spaces in the plan have a non-moving address.
4747 fn initialize_sft ( & self ) ;
4848
49+ /// A check for the obvious out-of-memory case: if the requested size is larger than
50+ /// the heap size, it is definitely an OOM. We would like to identify that, and
51+ /// allows the binding to deal with OOM. Without this check, we will attempt
52+ /// to allocate from the page resource. If the requested size is unrealistically large
53+ /// (such as `usize::MAX`), it breaks the assumptions of our implementation of
54+ /// page resource, vm map, etc. This check prevents that, and allows us to
55+ /// handle the OOM case.
56+ /// Each allocator that may request an arbitrary size should call this method before
57+ /// acquring memory from the space. For example, bump pointer allocator and large object
58+ /// allocator need to call this method. On the other hand, allocators that only allocate
59+ /// memory in fixed size blocks do not need to call this method.
60+ /// An allocator should call this method before doing any computation on the size to
61+ /// avoid arithmatic overflow. If we have to do computation in the allocation fastpath and
62+ /// overflow happens there, there is nothing we can do about it.
63+ /// Return a boolean to indicate if we will be out of memory, determined by the check.
64+ fn will_oom_on_acquire ( & self , tls : VMThread , size : usize ) -> bool {
65+ let max_pages = self . get_gc_trigger ( ) . policy . get_max_heap_size_in_pages ( ) ;
66+ let requested_pages = size >> LOG_BYTES_IN_PAGE ;
67+ if requested_pages > max_pages {
68+ VM :: VMCollection :: out_of_memory (
69+ tls,
70+ crate :: util:: alloc:: AllocationError :: HeapOutOfMemory ,
71+ ) ;
72+ return true ;
73+ }
74+ false
75+ }
76+
4977 fn acquire ( & self , tls : VMThread , pages : usize ) -> Address {
5078 trace ! ( "Space.acquire, tls={:?}" , tls) ;
79+
80+ debug_assert ! (
81+ !self . will_oom_on_acquire( tls, pages << LOG_BYTES_IN_PAGE ) ,
82+ "The requested pages is larger than the max heap size. Is will_go_oom_on_acquire used before acquring memory?"
83+ ) ;
84+
5185 // Should we poll to attempt to GC?
5286 // - If tls is collector, we cannot attempt a GC.
5387 // - If gc is disabled, we cannot attempt a GC.
0 commit comments