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