1425bb815Sopenharmony_ci/* Copyright JS Foundation and other contributors, http://js.foundation 2425bb815Sopenharmony_ci * 3425bb815Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4425bb815Sopenharmony_ci * you may not use this file except in compliance with the License. 5425bb815Sopenharmony_ci * You may obtain a copy of the License at 6425bb815Sopenharmony_ci * 7425bb815Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8425bb815Sopenharmony_ci * 9425bb815Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10425bb815Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS 11425bb815Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12425bb815Sopenharmony_ci * See the License for the specific language governing permissions and 13425bb815Sopenharmony_ci * limitations under the License. 14425bb815Sopenharmony_ci */ 15425bb815Sopenharmony_ci 16425bb815Sopenharmony_ci#ifndef JMEM_H 17425bb815Sopenharmony_ci#define JMEM_H 18425bb815Sopenharmony_ci 19425bb815Sopenharmony_ci#include "jrt.h" 20425bb815Sopenharmony_ci 21425bb815Sopenharmony_ci/** \addtogroup mem Memory allocation 22425bb815Sopenharmony_ci * @{ 23425bb815Sopenharmony_ci * 24425bb815Sopenharmony_ci * \addtogroup heap Heap 25425bb815Sopenharmony_ci * @{ 26425bb815Sopenharmony_ci */ 27425bb815Sopenharmony_ci 28425bb815Sopenharmony_ci/** 29425bb815Sopenharmony_ci * Logarithm of required alignment for allocated units/blocks 30425bb815Sopenharmony_ci */ 31425bb815Sopenharmony_ci#define JMEM_ALIGNMENT_LOG 3 32425bb815Sopenharmony_ci 33425bb815Sopenharmony_ci/** 34425bb815Sopenharmony_ci * Representation of NULL value for compressed pointers 35425bb815Sopenharmony_ci */ 36425bb815Sopenharmony_ci#define JMEM_CP_NULL ((jmem_cpointer_t) 0) 37425bb815Sopenharmony_ci 38425bb815Sopenharmony_ci/** 39425bb815Sopenharmony_ci * Required alignment for allocated units/blocks 40425bb815Sopenharmony_ci */ 41425bb815Sopenharmony_ci#define JMEM_ALIGNMENT (1u << JMEM_ALIGNMENT_LOG) 42425bb815Sopenharmony_ci 43425bb815Sopenharmony_ci/** 44425bb815Sopenharmony_ci * Pointer value can be directly stored without compression 45425bb815Sopenharmony_ci */ 46425bb815Sopenharmony_ci#if UINTPTR_MAX <= UINT32_MAX 47425bb815Sopenharmony_ci#define JMEM_CAN_STORE_POINTER_VALUE_DIRECTLY 48425bb815Sopenharmony_ci#endif /* UINTPTR_MAX <= UINT32_MAX */ 49425bb815Sopenharmony_ci 50425bb815Sopenharmony_ci/** 51425bb815Sopenharmony_ci * Mask for tag part in jmem_cpointer_tag_t 52425bb815Sopenharmony_ci */ 53425bb815Sopenharmony_ci#define JMEM_TAG_MASK 0x7u 54425bb815Sopenharmony_ci 55425bb815Sopenharmony_ci/** 56425bb815Sopenharmony_ci * Shift for tag part in jmem_cpointer_tag_t 57425bb815Sopenharmony_ci */ 58425bb815Sopenharmony_ci#if defined (JMEM_CAN_STORE_POINTER_VALUE_DIRECTLY) && ENABLED (JERRY_CPOINTER_32_BIT) 59425bb815Sopenharmony_ci#define JMEM_TAG_SHIFT 0 60425bb815Sopenharmony_ci#else /* !JMEM_CAN_STORE_POINTER_VALUE_DIRECTLY || !ENABLED (JERRY_CPOINTER_32_BIT) */ 61425bb815Sopenharmony_ci#define JMEM_TAG_SHIFT 3 62425bb815Sopenharmony_ci#endif /* JMEM_CAN_STORE_POINTER_VALUE_DIRECTLY && ENABLED (JERRY_CPOINTER_32_BIT) */ 63425bb815Sopenharmony_ci 64425bb815Sopenharmony_ci/** 65425bb815Sopenharmony_ci * Bit mask for tag part in jmem_cpointer_tag_t 66425bb815Sopenharmony_ci */ 67425bb815Sopenharmony_cienum 68425bb815Sopenharmony_ci{ 69425bb815Sopenharmony_ci JMEM_FIRST_TAG_BIT_MASK = (1u << 0), /**< first tag bit mask **/ 70425bb815Sopenharmony_ci JMEM_SECOND_TAG_BIT_MASK = (1u << 1), /**< second tag bit mask **/ 71425bb815Sopenharmony_ci JMEM_THIRD_TAG_BIT_MASK = (1u << 2), /**< third tag bit mask **/ 72425bb815Sopenharmony_ci}; 73425bb815Sopenharmony_ci 74425bb815Sopenharmony_ci/** 75425bb815Sopenharmony_ci * Compressed pointer representations 76425bb815Sopenharmony_ci * 77425bb815Sopenharmony_ci * 16 bit representation: 78425bb815Sopenharmony_ci * The jmem_cpointer_t is defined as uint16_t 79425bb815Sopenharmony_ci * and it can contain any sixteen bit value. 80425bb815Sopenharmony_ci * 81425bb815Sopenharmony_ci * 32 bit representation: 82425bb815Sopenharmony_ci * The jmem_cpointer_t is defined as uint32_t. 83425bb815Sopenharmony_ci * The lower JMEM_ALIGNMENT_LOG bits must be zero. 84425bb815Sopenharmony_ci * The other bits can have any value. 85425bb815Sopenharmony_ci * 86425bb815Sopenharmony_ci * The 16 bit representation always encodes an offset from 87425bb815Sopenharmony_ci * a heap base. The 32 bit representation currently encodes 88425bb815Sopenharmony_ci * raw 32 bit JMEM_ALIGNMENT aligned pointers on 32 bit systems. 89425bb815Sopenharmony_ci * This can be extended to encode a 32 bit offset from a heap 90425bb815Sopenharmony_ci * base on 64 bit systems in the future. There are no plans 91425bb815Sopenharmony_ci * to support more than 4G address space for JerryScript. 92425bb815Sopenharmony_ci */ 93425bb815Sopenharmony_ci 94425bb815Sopenharmony_ci/** 95425bb815Sopenharmony_ci * Compressed pointer 96425bb815Sopenharmony_ci */ 97425bb815Sopenharmony_ci#if ENABLED (JERRY_CPOINTER_32_BIT) 98425bb815Sopenharmony_citypedef uint32_t jmem_cpointer_t; 99425bb815Sopenharmony_ci#else /* !ENABLED (JERRY_CPOINTER_32_BIT) */ 100425bb815Sopenharmony_citypedef uint16_t jmem_cpointer_t; 101425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_CPOINTER_32_BIT) */ 102425bb815Sopenharmony_ci 103425bb815Sopenharmony_ci/** 104425bb815Sopenharmony_ci * Compressed pointer with tag value 105425bb815Sopenharmony_ci */ 106425bb815Sopenharmony_citypedef uint32_t jmem_cpointer_tag_t; 107425bb815Sopenharmony_ci 108425bb815Sopenharmony_ci/** 109425bb815Sopenharmony_ci * Memory usage pressure for reclaiming unused memory. 110425bb815Sopenharmony_ci * 111425bb815Sopenharmony_ci * Each failed allocation will try to reclaim memory with increasing pressure, 112425bb815Sopenharmony_ci * until enough memory is freed to fulfill the allocation request. 113425bb815Sopenharmony_ci * 114425bb815Sopenharmony_ci * If not enough memory is freed and JMEM_PRESSURE_FULL is reached, 115425bb815Sopenharmony_ci * then the engine is shut down with ERR_OUT_OF_MEMORY. 116425bb815Sopenharmony_ci */ 117425bb815Sopenharmony_citypedef enum 118425bb815Sopenharmony_ci{ 119425bb815Sopenharmony_ci JMEM_PRESSURE_NONE, /**< no memory pressure */ 120425bb815Sopenharmony_ci JMEM_PRESSURE_LOW, /**< low memory pressure */ 121425bb815Sopenharmony_ci JMEM_PRESSURE_HIGH, /**< high memory pressure */ 122425bb815Sopenharmony_ci JMEM_PRESSURE_FULL, /**< memory full */ 123425bb815Sopenharmony_ci} jmem_pressure_t; 124425bb815Sopenharmony_ci 125425bb815Sopenharmony_ci/** 126425bb815Sopenharmony_ci * Node for free chunk list 127425bb815Sopenharmony_ci */ 128425bb815Sopenharmony_citypedef struct jmem_pools_chunk_t 129425bb815Sopenharmony_ci{ 130425bb815Sopenharmony_ci struct jmem_pools_chunk_t *next_p; /**< pointer to next pool chunk */ 131425bb815Sopenharmony_ci} jmem_pools_chunk_t; 132425bb815Sopenharmony_ci 133425bb815Sopenharmony_ci/** 134425bb815Sopenharmony_ci * Free region node 135425bb815Sopenharmony_ci */ 136425bb815Sopenharmony_citypedef struct 137425bb815Sopenharmony_ci{ 138425bb815Sopenharmony_ci uint32_t next_offset; /**< Offset of next region in list */ 139425bb815Sopenharmony_ci uint32_t size; /**< Size of region */ 140425bb815Sopenharmony_ci} jmem_heap_free_t; 141425bb815Sopenharmony_ci 142425bb815Sopenharmony_civoid jmem_init (void); 143425bb815Sopenharmony_civoid jmem_finalize (void); 144425bb815Sopenharmony_ci 145425bb815Sopenharmony_civoid *jmem_heap_alloc_block (const size_t size); 146425bb815Sopenharmony_civoid *jmem_heap_alloc_block_null_on_error (const size_t size); 147425bb815Sopenharmony_civoid *jmem_heap_realloc_block (void *ptr, const size_t old_size, const size_t new_size); 148425bb815Sopenharmony_civoid jmem_heap_free_block (void *ptr, const size_t size); 149425bb815Sopenharmony_ci 150425bb815Sopenharmony_ci#if ENABLED (JERRY_MEM_STATS) 151425bb815Sopenharmony_ci/** 152425bb815Sopenharmony_ci * Heap memory usage statistics 153425bb815Sopenharmony_ci */ 154425bb815Sopenharmony_citypedef struct 155425bb815Sopenharmony_ci{ 156425bb815Sopenharmony_ci size_t size; /**< heap total size */ 157425bb815Sopenharmony_ci 158425bb815Sopenharmony_ci size_t allocated_bytes; /**< currently allocated bytes */ 159425bb815Sopenharmony_ci size_t peak_allocated_bytes; /**< peak allocated bytes */ 160425bb815Sopenharmony_ci 161425bb815Sopenharmony_ci size_t waste_bytes; /**< bytes waste due to blocks filled partially */ 162425bb815Sopenharmony_ci size_t peak_waste_bytes; /**< peak wasted bytes */ 163425bb815Sopenharmony_ci 164425bb815Sopenharmony_ci size_t byte_code_bytes; /**< allocated memory for byte code */ 165425bb815Sopenharmony_ci size_t peak_byte_code_bytes; /**< peak allocated memory for byte code */ 166425bb815Sopenharmony_ci 167425bb815Sopenharmony_ci size_t string_bytes; /**< allocated memory for strings */ 168425bb815Sopenharmony_ci size_t peak_string_bytes; /**< peak allocated memory for strings */ 169425bb815Sopenharmony_ci 170425bb815Sopenharmony_ci size_t object_bytes; /**< allocated memory for objects */ 171425bb815Sopenharmony_ci size_t peak_object_bytes; /**< peak allocated memory for objects */ 172425bb815Sopenharmony_ci 173425bb815Sopenharmony_ci size_t property_bytes; /**< allocated memory for properties */ 174425bb815Sopenharmony_ci size_t peak_property_bytes; /**< peak allocated memory for properties */ 175425bb815Sopenharmony_ci} jmem_heap_stats_t; 176425bb815Sopenharmony_ci 177425bb815Sopenharmony_civoid jmem_stats_allocate_byte_code_bytes (size_t property_size); 178425bb815Sopenharmony_civoid jmem_stats_free_byte_code_bytes (size_t property_size); 179425bb815Sopenharmony_civoid jmem_stats_allocate_string_bytes (size_t string_size); 180425bb815Sopenharmony_civoid jmem_stats_free_string_bytes (size_t string_size); 181425bb815Sopenharmony_civoid jmem_stats_allocate_object_bytes (size_t object_size); 182425bb815Sopenharmony_civoid jmem_stats_free_object_bytes (size_t string_size); 183425bb815Sopenharmony_civoid jmem_stats_allocate_property_bytes (size_t property_size); 184425bb815Sopenharmony_civoid jmem_stats_free_property_bytes (size_t property_size); 185425bb815Sopenharmony_ci 186425bb815Sopenharmony_civoid jmem_heap_get_stats (jmem_heap_stats_t *); 187425bb815Sopenharmony_civoid jmem_heap_stats_reset_peak (void); 188425bb815Sopenharmony_civoid jmem_heap_stats_print (void); 189425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_MEM_STATS) */ 190425bb815Sopenharmony_ci 191425bb815Sopenharmony_cijmem_cpointer_t JERRY_ATTR_PURE jmem_compress_pointer (const void *pointer_p); 192425bb815Sopenharmony_civoid * JERRY_ATTR_PURE jmem_decompress_pointer (uintptr_t compressed_pointer); 193425bb815Sopenharmony_ci 194425bb815Sopenharmony_ci/** 195425bb815Sopenharmony_ci * Define a local array variable and allocate memory for the array on the heap. 196425bb815Sopenharmony_ci * 197425bb815Sopenharmony_ci * If requested number of elements is zero, assign NULL to the variable. 198425bb815Sopenharmony_ci * 199425bb815Sopenharmony_ci * Warning: 200425bb815Sopenharmony_ci * if there is not enough memory on the heap, shutdown engine with ERR_OUT_OF_MEMORY. 201425bb815Sopenharmony_ci */ 202425bb815Sopenharmony_ci#define JMEM_DEFINE_LOCAL_ARRAY(var_name, number, type) \ 203425bb815Sopenharmony_ci{ \ 204425bb815Sopenharmony_ci size_t var_name ## ___size = (size_t) (number) * sizeof (type); \ 205425bb815Sopenharmony_ci type *var_name = (type *) (jmem_heap_alloc_block (var_name ## ___size)); 206425bb815Sopenharmony_ci 207425bb815Sopenharmony_ci/** 208425bb815Sopenharmony_ci * Free the previously defined local array variable, freeing corresponding block on the heap, 209425bb815Sopenharmony_ci * if it was allocated (i.e. if the array's size was non-zero). 210425bb815Sopenharmony_ci */ 211425bb815Sopenharmony_ci#define JMEM_FINALIZE_LOCAL_ARRAY(var_name) \ 212425bb815Sopenharmony_ci if (var_name != NULL) \ 213425bb815Sopenharmony_ci { \ 214425bb815Sopenharmony_ci JERRY_ASSERT (var_name ## ___size != 0); \ 215425bb815Sopenharmony_ci \ 216425bb815Sopenharmony_ci jmem_heap_free_block (var_name, var_name ## ___size); \ 217425bb815Sopenharmony_ci } \ 218425bb815Sopenharmony_ci else \ 219425bb815Sopenharmony_ci { \ 220425bb815Sopenharmony_ci JERRY_ASSERT (var_name ## ___size == 0); \ 221425bb815Sopenharmony_ci } \ 222425bb815Sopenharmony_ci} 223425bb815Sopenharmony_ci 224425bb815Sopenharmony_ci/** 225425bb815Sopenharmony_ci * Get value of pointer from specified non-null compressed pointer value 226425bb815Sopenharmony_ci */ 227425bb815Sopenharmony_ci#define JMEM_CP_GET_NON_NULL_POINTER(type, cp_value) \ 228425bb815Sopenharmony_ci ((type *) (jmem_decompress_pointer (cp_value))) 229425bb815Sopenharmony_ci 230425bb815Sopenharmony_ci/** 231425bb815Sopenharmony_ci * Get value of pointer from specified compressed pointer value 232425bb815Sopenharmony_ci */ 233425bb815Sopenharmony_ci#define JMEM_CP_GET_POINTER(type, cp_value) \ 234425bb815Sopenharmony_ci (((JERRY_UNLIKELY ((cp_value) == JMEM_CP_NULL)) ? NULL : JMEM_CP_GET_NON_NULL_POINTER (type, cp_value))) 235425bb815Sopenharmony_ci 236425bb815Sopenharmony_ci/** 237425bb815Sopenharmony_ci * Set value of non-null compressed pointer so that it will correspond 238425bb815Sopenharmony_ci * to specified non_compressed_pointer 239425bb815Sopenharmony_ci */ 240425bb815Sopenharmony_ci#define JMEM_CP_SET_NON_NULL_POINTER(cp_value, non_compressed_pointer) \ 241425bb815Sopenharmony_ci (cp_value) = jmem_compress_pointer (non_compressed_pointer) 242425bb815Sopenharmony_ci 243425bb815Sopenharmony_ci/** 244425bb815Sopenharmony_ci * Set value of compressed pointer so that it will correspond 245425bb815Sopenharmony_ci * to specified non_compressed_pointer 246425bb815Sopenharmony_ci */ 247425bb815Sopenharmony_ci#define JMEM_CP_SET_POINTER(cp_value, non_compressed_pointer) \ 248425bb815Sopenharmony_ci do \ 249425bb815Sopenharmony_ci { \ 250425bb815Sopenharmony_ci void *ptr_value = (void *) non_compressed_pointer; \ 251425bb815Sopenharmony_ci \ 252425bb815Sopenharmony_ci if (JERRY_UNLIKELY ((ptr_value) == NULL)) \ 253425bb815Sopenharmony_ci { \ 254425bb815Sopenharmony_ci (cp_value) = JMEM_CP_NULL; \ 255425bb815Sopenharmony_ci } \ 256425bb815Sopenharmony_ci else \ 257425bb815Sopenharmony_ci { \ 258425bb815Sopenharmony_ci JMEM_CP_SET_NON_NULL_POINTER (cp_value, ptr_value); \ 259425bb815Sopenharmony_ci } \ 260425bb815Sopenharmony_ci } while (false); 261425bb815Sopenharmony_ci 262425bb815Sopenharmony_ci/** 263425bb815Sopenharmony_ci * Set value of pointer-tag value so that it will correspond 264425bb815Sopenharmony_ci * to specified non_compressed_pointer along with tag 265425bb815Sopenharmony_ci */ 266425bb815Sopenharmony_ci#define JMEM_CP_SET_NON_NULL_POINTER_TAG(cp_value, pointer, tag) \ 267425bb815Sopenharmony_ci do \ 268425bb815Sopenharmony_ci { \ 269425bb815Sopenharmony_ci JERRY_ASSERT ((uintptr_t) tag < (uintptr_t) (JMEM_ALIGNMENT)); \ 270425bb815Sopenharmony_ci jmem_cpointer_tag_t compressed_ptr = jmem_compress_pointer (pointer); \ 271425bb815Sopenharmony_ci (cp_value) = (jmem_cpointer_tag_t) ((compressed_ptr << JMEM_TAG_SHIFT) | tag); \ 272425bb815Sopenharmony_ci } while (false); 273425bb815Sopenharmony_ci 274425bb815Sopenharmony_ci/** 275425bb815Sopenharmony_ci * Extract value of pointer from specified pointer-tag value 276425bb815Sopenharmony_ci */ 277425bb815Sopenharmony_ci#define JMEM_CP_GET_NON_NULL_POINTER_FROM_POINTER_TAG(type, cp_value) \ 278425bb815Sopenharmony_ci ((type *) (jmem_decompress_pointer ((cp_value & ~JMEM_TAG_MASK) >> JMEM_TAG_SHIFT))) 279425bb815Sopenharmony_ci 280425bb815Sopenharmony_ci/** 281425bb815Sopenharmony_ci * Get value of each tag from specified pointer-tag value 282425bb815Sopenharmony_ci */ 283425bb815Sopenharmony_ci#define JMEM_CP_GET_FIRST_BIT_FROM_POINTER_TAG(cp_value) \ 284425bb815Sopenharmony_ci (cp_value & JMEM_FIRST_TAG_BIT_MASK) /**< get first tag bit **/ 285425bb815Sopenharmony_ci#define JMEM_CP_GET_SECOND_BIT_FROM_POINTER_TAG(cp_value) \ 286425bb815Sopenharmony_ci (cp_value & JMEM_SECOND_TAG_BIT_MASK) /**< get second tag bit **/ 287425bb815Sopenharmony_ci#define JMEM_CP_GET_THIRD_BIT_FROM_POINTER_TAG(cp_value) \ 288425bb815Sopenharmony_ci (cp_value & JMEM_THIRD_TAG_BIT_MASK) /**< get third tag bit **/ 289425bb815Sopenharmony_ci 290425bb815Sopenharmony_ci/** 291425bb815Sopenharmony_ci * Set value of each tag to specified pointer-tag value 292425bb815Sopenharmony_ci */ 293425bb815Sopenharmony_ci#define JMEM_CP_SET_FIRST_BIT_TO_POINTER_TAG(cp_value) \ 294425bb815Sopenharmony_ci (cp_value) = (cp_value | JMEM_FIRST_TAG_BIT_MASK) /**< set first tag bit **/ 295425bb815Sopenharmony_ci#define JMEM_CP_SET_SECOND_BIT_TO_POINTER_TAG(cp_value) \ 296425bb815Sopenharmony_ci (cp_value) = (cp_value | JMEM_SECOND_TAG_BIT_MASK) /**< set second tag bit **/ 297425bb815Sopenharmony_ci#define JMEM_CP_SET_THIRD_BIT_TO_POINTER_TAG(cp_value) \ 298425bb815Sopenharmony_ci (cp_value) = (cp_value | JMEM_THIRD_TAG_BIT_MASK) /**< set third tag bit **/ 299425bb815Sopenharmony_ci 300425bb815Sopenharmony_ci/** 301425bb815Sopenharmony_ci * @} 302425bb815Sopenharmony_ci * \addtogroup poolman Memory pool manager 303425bb815Sopenharmony_ci * @{ 304425bb815Sopenharmony_ci */ 305425bb815Sopenharmony_ci 306425bb815Sopenharmony_civoid *jmem_pools_alloc (size_t size); 307425bb815Sopenharmony_civoid jmem_pools_free (void *chunk_p, size_t size); 308425bb815Sopenharmony_civoid jmem_pools_collect_empty (void); 309425bb815Sopenharmony_ci 310425bb815Sopenharmony_ci/** 311425bb815Sopenharmony_ci * @} 312425bb815Sopenharmony_ci * @} 313425bb815Sopenharmony_ci */ 314425bb815Sopenharmony_ci 315425bb815Sopenharmony_ci#endif /* !JMEM_H */ 316