1/* Copyright JS Foundation and other contributors, http://js.foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef JMEM_H
17#define JMEM_H
18
19#include "jrt.h"
20
21/** \addtogroup mem Memory allocation
22 * @{
23 *
24 * \addtogroup heap Heap
25 * @{
26 */
27
28/**
29 * Logarithm of required alignment for allocated units/blocks
30 */
31#define JMEM_ALIGNMENT_LOG 3
32
33/**
34 * Representation of NULL value for compressed pointers
35 */
36#define JMEM_CP_NULL ((jmem_cpointer_t) 0)
37
38/**
39 * Required alignment for allocated units/blocks
40 */
41#define JMEM_ALIGNMENT (1u << JMEM_ALIGNMENT_LOG)
42
43/**
44 * Pointer value can be directly stored without compression
45 */
46#if UINTPTR_MAX <= UINT32_MAX
47#define JMEM_CAN_STORE_POINTER_VALUE_DIRECTLY
48#endif /* UINTPTR_MAX <= UINT32_MAX */
49
50/**
51 * Mask for tag part in jmem_cpointer_tag_t
52 */
53#define JMEM_TAG_MASK 0x7u
54
55/**
56 * Shift for tag part in jmem_cpointer_tag_t
57 */
58#if defined (JMEM_CAN_STORE_POINTER_VALUE_DIRECTLY) && ENABLED (JERRY_CPOINTER_32_BIT)
59#define JMEM_TAG_SHIFT 0
60#else /* !JMEM_CAN_STORE_POINTER_VALUE_DIRECTLY || !ENABLED (JERRY_CPOINTER_32_BIT) */
61#define JMEM_TAG_SHIFT 3
62#endif /* JMEM_CAN_STORE_POINTER_VALUE_DIRECTLY && ENABLED (JERRY_CPOINTER_32_BIT) */
63
64/**
65 * Bit mask for tag part in jmem_cpointer_tag_t
66 */
67enum
68{
69 JMEM_FIRST_TAG_BIT_MASK = (1u << 0), /**< first tag bit mask **/
70 JMEM_SECOND_TAG_BIT_MASK = (1u << 1), /**< second tag bit mask **/
71 JMEM_THIRD_TAG_BIT_MASK = (1u << 2), /**< third tag bit mask **/
72};
73
74/**
75 * Compressed pointer representations
76 *
77 * 16 bit representation:
78 * The jmem_cpointer_t is defined as uint16_t
79 * and it can contain any sixteen bit value.
80 *
81 * 32 bit representation:
82 * The jmem_cpointer_t is defined as uint32_t.
83 * The lower JMEM_ALIGNMENT_LOG bits must be zero.
84 * The other bits can have any value.
85 *
86 * The 16 bit representation always encodes an offset from
87 * a heap base. The 32 bit representation currently encodes
88 * raw 32 bit JMEM_ALIGNMENT aligned pointers on 32 bit systems.
89 * This can be extended to encode a 32 bit offset from a heap
90 * base on 64 bit systems in the future. There are no plans
91 * to support more than 4G address space for JerryScript.
92 */
93
94/**
95 * Compressed pointer
96 */
97#if ENABLED (JERRY_CPOINTER_32_BIT)
98typedef uint32_t jmem_cpointer_t;
99#else /* !ENABLED (JERRY_CPOINTER_32_BIT) */
100typedef uint16_t jmem_cpointer_t;
101#endif /* ENABLED (JERRY_CPOINTER_32_BIT) */
102
103/**
104 * Compressed pointer with tag value
105 */
106typedef uint32_t jmem_cpointer_tag_t;
107
108/**
109 * Memory usage pressure for reclaiming unused memory.
110 *
111 * Each failed allocation will try to reclaim memory with increasing pressure,
112 * until enough memory is freed to fulfill the allocation request.
113 *
114 * If not enough memory is freed and JMEM_PRESSURE_FULL is reached,
115 * then the engine is shut down with ERR_OUT_OF_MEMORY.
116 */
117typedef enum
118{
119 JMEM_PRESSURE_NONE, /**< no memory pressure */
120 JMEM_PRESSURE_LOW, /**< low memory pressure */
121 JMEM_PRESSURE_HIGH, /**< high memory pressure */
122 JMEM_PRESSURE_FULL, /**< memory full */
123} jmem_pressure_t;
124
125/**
126 * Node for free chunk list
127 */
128typedef struct jmem_pools_chunk_t
129{
130 struct jmem_pools_chunk_t *next_p; /**< pointer to next pool chunk */
131} jmem_pools_chunk_t;
132
133/**
134 * Free region node
135 */
136typedef struct
137{
138 uint32_t next_offset; /**< Offset of next region in list */
139 uint32_t size; /**< Size of region */
140} jmem_heap_free_t;
141
142void jmem_init (void);
143void jmem_finalize (void);
144
145void *jmem_heap_alloc_block (const size_t size);
146void *jmem_heap_alloc_block_null_on_error (const size_t size);
147void *jmem_heap_realloc_block (void *ptr, const size_t old_size, const size_t new_size);
148void jmem_heap_free_block (void *ptr, const size_t size);
149
150#if ENABLED (JERRY_MEM_STATS)
151/**
152 * Heap memory usage statistics
153 */
154typedef struct
155{
156 size_t size; /**< heap total size */
157
158 size_t allocated_bytes; /**< currently allocated bytes */
159 size_t peak_allocated_bytes; /**< peak allocated bytes */
160
161 size_t waste_bytes; /**< bytes waste due to blocks filled partially */
162 size_t peak_waste_bytes; /**< peak wasted bytes */
163
164 size_t byte_code_bytes; /**< allocated memory for byte code */
165 size_t peak_byte_code_bytes; /**< peak allocated memory for byte code */
166
167 size_t string_bytes; /**< allocated memory for strings */
168 size_t peak_string_bytes; /**< peak allocated memory for strings */
169
170 size_t object_bytes; /**< allocated memory for objects */
171 size_t peak_object_bytes; /**< peak allocated memory for objects */
172
173 size_t property_bytes; /**< allocated memory for properties */
174 size_t peak_property_bytes; /**< peak allocated memory for properties */
175} jmem_heap_stats_t;
176
177void jmem_stats_allocate_byte_code_bytes (size_t property_size);
178void jmem_stats_free_byte_code_bytes (size_t property_size);
179void jmem_stats_allocate_string_bytes (size_t string_size);
180void jmem_stats_free_string_bytes (size_t string_size);
181void jmem_stats_allocate_object_bytes (size_t object_size);
182void jmem_stats_free_object_bytes (size_t string_size);
183void jmem_stats_allocate_property_bytes (size_t property_size);
184void jmem_stats_free_property_bytes (size_t property_size);
185
186void jmem_heap_get_stats (jmem_heap_stats_t *);
187void jmem_heap_stats_reset_peak (void);
188void jmem_heap_stats_print (void);
189#endif /* ENABLED (JERRY_MEM_STATS) */
190
191jmem_cpointer_t JERRY_ATTR_PURE jmem_compress_pointer (const void *pointer_p);
192void * JERRY_ATTR_PURE jmem_decompress_pointer (uintptr_t compressed_pointer);
193
194/**
195 * Define a local array variable and allocate memory for the array on the heap.
196 *
197 * If requested number of elements is zero, assign NULL to the variable.
198 *
199 * Warning:
200 * if there is not enough memory on the heap, shutdown engine with ERR_OUT_OF_MEMORY.
201 */
202#define JMEM_DEFINE_LOCAL_ARRAY(var_name, number, type) \
203{ \
204 size_t var_name ## ___size = (size_t) (number) * sizeof (type); \
205 type *var_name = (type *) (jmem_heap_alloc_block (var_name ## ___size));
206
207/**
208 * Free the previously defined local array variable, freeing corresponding block on the heap,
209 * if it was allocated (i.e. if the array's size was non-zero).
210 */
211#define JMEM_FINALIZE_LOCAL_ARRAY(var_name) \
212 if (var_name != NULL) \
213 { \
214 JERRY_ASSERT (var_name ## ___size != 0); \
215 \
216 jmem_heap_free_block (var_name, var_name ## ___size); \
217 } \
218 else \
219 { \
220 JERRY_ASSERT (var_name ## ___size == 0); \
221 } \
222}
223
224/**
225 * Get value of pointer from specified non-null compressed pointer value
226 */
227#define JMEM_CP_GET_NON_NULL_POINTER(type, cp_value) \
228 ((type *) (jmem_decompress_pointer (cp_value)))
229
230/**
231 * Get value of pointer from specified compressed pointer value
232 */
233#define JMEM_CP_GET_POINTER(type, cp_value) \
234 (((JERRY_UNLIKELY ((cp_value) == JMEM_CP_NULL)) ? NULL : JMEM_CP_GET_NON_NULL_POINTER (type, cp_value)))
235
236/**
237 * Set value of non-null compressed pointer so that it will correspond
238 * to specified non_compressed_pointer
239 */
240#define JMEM_CP_SET_NON_NULL_POINTER(cp_value, non_compressed_pointer) \
241 (cp_value) = jmem_compress_pointer (non_compressed_pointer)
242
243/**
244 * Set value of compressed pointer so that it will correspond
245 * to specified non_compressed_pointer
246 */
247#define JMEM_CP_SET_POINTER(cp_value, non_compressed_pointer) \
248 do \
249 { \
250 void *ptr_value = (void *) non_compressed_pointer; \
251 \
252 if (JERRY_UNLIKELY ((ptr_value) == NULL)) \
253 { \
254 (cp_value) = JMEM_CP_NULL; \
255 } \
256 else \
257 { \
258 JMEM_CP_SET_NON_NULL_POINTER (cp_value, ptr_value); \
259 } \
260 } while (false);
261
262/**
263 * Set value of pointer-tag value so that it will correspond
264 * to specified non_compressed_pointer along with tag
265 */
266#define JMEM_CP_SET_NON_NULL_POINTER_TAG(cp_value, pointer, tag) \
267 do \
268 { \
269 JERRY_ASSERT ((uintptr_t) tag < (uintptr_t) (JMEM_ALIGNMENT)); \
270 jmem_cpointer_tag_t compressed_ptr = jmem_compress_pointer (pointer); \
271 (cp_value) = (jmem_cpointer_tag_t) ((compressed_ptr << JMEM_TAG_SHIFT) | tag); \
272 } while (false);
273
274/**
275 * Extract value of pointer from specified pointer-tag value
276 */
277#define JMEM_CP_GET_NON_NULL_POINTER_FROM_POINTER_TAG(type, cp_value) \
278 ((type *) (jmem_decompress_pointer ((cp_value & ~JMEM_TAG_MASK) >> JMEM_TAG_SHIFT)))
279
280/**
281 * Extract tag bits from pointer-tag value
282 */
283#define JMEM_CP_GET_POINTER_TAG_BITS(cp_value) \
284 (cp_value & (JMEM_FIRST_TAG_BIT_MASK | JMEM_SECOND_TAG_BIT_MASK | JMEM_THIRD_TAG_BIT_MASK))
285
286/**
287 * Get value of each tag from specified pointer-tag value
288 */
289#define JMEM_CP_GET_FIRST_BIT_FROM_POINTER_TAG(cp_value) \
290 (cp_value & JMEM_FIRST_TAG_BIT_MASK) /**< get first tag bit **/
291#define JMEM_CP_GET_SECOND_BIT_FROM_POINTER_TAG(cp_value) \
292 (cp_value & JMEM_SECOND_TAG_BIT_MASK) /**< get second tag bit **/
293#define JMEM_CP_GET_THIRD_BIT_FROM_POINTER_TAG(cp_value) \
294 (cp_value & JMEM_THIRD_TAG_BIT_MASK) /**< get third tag bit **/
295
296/**
297 * Set value of each tag to specified pointer-tag value
298 */
299#define JMEM_CP_SET_FIRST_BIT_TO_POINTER_TAG(cp_value) \
300 (cp_value) = (cp_value | JMEM_FIRST_TAG_BIT_MASK) /**< set first tag bit **/
301#define JMEM_CP_SET_SECOND_BIT_TO_POINTER_TAG(cp_value) \
302 (cp_value) = (cp_value | JMEM_SECOND_TAG_BIT_MASK) /**< set second tag bit **/
303#define JMEM_CP_SET_THIRD_BIT_TO_POINTER_TAG(cp_value) \
304 (cp_value) = (cp_value | JMEM_THIRD_TAG_BIT_MASK) /**< set third tag bit **/
305
306/**
307 * @}
308 * \addtogroup poolman Memory pool manager
309 * @{
310 */
311
312void *jmem_pools_alloc (size_t size);
313void jmem_pools_free (void *chunk_p, size_t size);
314void jmem_pools_collect_empty (void);
315
316/**
317 * @}
318 * @}
319 */
320
321#endif /* !JMEM_H */
322