• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
67 enum
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)
98 typedef uint32_t jmem_cpointer_t;
99 #else /* !ENABLED (JERRY_CPOINTER_32_BIT) */
100 typedef uint16_t jmem_cpointer_t;
101 #endif /* ENABLED (JERRY_CPOINTER_32_BIT) */
102 
103 /**
104  * Compressed pointer with tag value
105  */
106 typedef 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  */
117 typedef 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  */
128 typedef 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  */
136 typedef 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 
142 void jmem_init (void);
143 void jmem_finalize (void);
144 
145 void *jmem_heap_alloc_block (const size_t size);
146 void *jmem_heap_alloc_block_null_on_error (const size_t size);
147 void *jmem_heap_realloc_block (void *ptr, const size_t old_size, const size_t new_size);
148 void jmem_heap_free_block (void *ptr, const size_t size);
149 
150 #if ENABLED (JERRY_MEM_STATS)
151 /**
152  * Heap memory usage statistics
153  */
154 typedef 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 
177 void jmem_stats_allocate_byte_code_bytes (size_t property_size);
178 void jmem_stats_free_byte_code_bytes (size_t property_size);
179 void jmem_stats_allocate_string_bytes (size_t string_size);
180 void jmem_stats_free_string_bytes (size_t string_size);
181 void jmem_stats_allocate_object_bytes (size_t object_size);
182 void jmem_stats_free_object_bytes (size_t string_size);
183 void jmem_stats_allocate_property_bytes (size_t property_size);
184 void jmem_stats_free_property_bytes (size_t property_size);
185 
186 void jmem_heap_get_stats (jmem_heap_stats_t *);
187 void jmem_heap_stats_reset_peak (void);
188 void jmem_heap_stats_print (void);
189 #endif /* ENABLED (JERRY_MEM_STATS) */
190 
191 jmem_cpointer_t JERRY_ATTR_PURE jmem_compress_pointer (const void *pointer_p);
192 void * 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  * Get value of each tag from specified pointer-tag value
282  */
283 #define JMEM_CP_GET_FIRST_BIT_FROM_POINTER_TAG(cp_value) \
284   (cp_value & JMEM_FIRST_TAG_BIT_MASK) /**< get first tag bit **/
285 #define JMEM_CP_GET_SECOND_BIT_FROM_POINTER_TAG(cp_value) \
286   (cp_value & JMEM_SECOND_TAG_BIT_MASK) /**< get second tag bit **/
287 #define JMEM_CP_GET_THIRD_BIT_FROM_POINTER_TAG(cp_value) \
288   (cp_value & JMEM_THIRD_TAG_BIT_MASK) /**< get third tag bit **/
289 
290 /**
291  * Set value of each tag to specified pointer-tag value
292  */
293 #define JMEM_CP_SET_FIRST_BIT_TO_POINTER_TAG(cp_value) \
294   (cp_value) = (cp_value | JMEM_FIRST_TAG_BIT_MASK) /**< set first tag bit **/
295 #define JMEM_CP_SET_SECOND_BIT_TO_POINTER_TAG(cp_value) \
296   (cp_value) = (cp_value | JMEM_SECOND_TAG_BIT_MASK) /**< set second tag bit **/
297 #define JMEM_CP_SET_THIRD_BIT_TO_POINTER_TAG(cp_value) \
298   (cp_value) = (cp_value | JMEM_THIRD_TAG_BIT_MASK) /**< set third tag bit **/
299 
300 /**
301  * @}
302  * \addtogroup poolman Memory pool manager
303  * @{
304  */
305 
306 void *jmem_pools_alloc (size_t size);
307 void jmem_pools_free (void *chunk_p, size_t size);
308 void jmem_pools_collect_empty (void);
309 
310 /**
311  * @}
312  * @}
313  */
314 
315 #endif /* !JMEM_H */
316