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 /**
17 * Garbage collector implementation
18 */
19
20 #include "ecma-alloc.h"
21 #include "ecma-array-object.h"
22 #include "ecma-container-object.h"
23 #include "ecma-function-object.h"
24 #include "ecma-globals.h"
25 #include "ecma-gc.h"
26 #include "ecma-helpers.h"
27 #include "ecma-objects.h"
28 #include "ecma-property-hashmap.h"
29 #include "ecma-proxy-object.h"
30 #include "jcontext.h"
31 #include "jrt.h"
32 #include "jrt-libc-includes.h"
33 #include "jrt-bit-fields.h"
34 #include "re-compiler.h"
35 #include "vm-defines.h"
36 #include "vm-stack.h"
37
38 #if defined(JERRY_HEAPDUMP)
39 #include "heapdump.h"
40 #endif
41
42 #if defined(JERRY_REF_TRACKER)
43 #include "tracker.h"
44 #endif
45
46 #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY)
47 #include "ecma-typedarray-object.h"
48 #endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */
49 #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE)
50 #include "ecma-promise-object.h"
51 #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */
52
53 /* TODO: Extract GC to a separate component */
54
55 /** \addtogroup ecma ECMA
56 * @{
57 *
58 * \addtogroup ecmagc Garbage collector
59 * @{
60 */
61
62 /*
63 * The garbage collector uses the reference counter
64 * of object: it increases the counter by one when
65 * the object is marked at the first time.
66 */
67
68 /**
69 * Get visited flag of the object.
70 *
71 * @return true - if visited
72 * false - otherwise
73 */
74 static inline bool JERRY_ATTR_ALWAYS_INLINE
ecma_gc_is_object_visited(ecma_object_t * object_p)75 ecma_gc_is_object_visited (ecma_object_t *object_p) /**< object */
76 {
77 JERRY_ASSERT (object_p != NULL);
78
79 return (object_p->type_flags_refs < ECMA_OBJECT_NON_VISITED);
80 } /* ecma_gc_is_object_visited */
81
82 /**
83 * Mark objects as visited starting from specified object as root
84 */
85 static void ecma_gc_mark (ecma_object_t *object_p);
86
87 /**
88 * Set visited flag of the object.
89 */
90 static void
ecma_gc_set_object_visited(ecma_object_t * object_p)91 ecma_gc_set_object_visited (ecma_object_t *object_p) /**< object */
92 {
93 if (object_p->type_flags_refs >= ECMA_OBJECT_NON_VISITED)
94 {
95 #if (JERRY_GC_MARK_LIMIT != 0)
96 if (JERRY_CONTEXT (ecma_gc_mark_recursion_limit) != 0)
97 {
98 JERRY_CONTEXT (ecma_gc_mark_recursion_limit)--;
99 /* Set the reference count of gray object to 0 */
100 object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs & (ECMA_OBJECT_REF_ONE - 1));
101 ecma_gc_mark (object_p);
102 JERRY_CONTEXT (ecma_gc_mark_recursion_limit)++;
103 }
104 else
105 {
106 /* Set the reference count of the non-marked gray object to 1 */
107 object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs & ((ECMA_OBJECT_REF_ONE << 1) - 1));
108 JERRY_ASSERT (object_p->type_flags_refs >= ECMA_OBJECT_REF_ONE);
109 }
110 #else /* (JERRY_GC_MARK_LIMIT == 0) */
111 /* Set the reference count of gray object to 0 */
112 object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs & (ECMA_OBJECT_REF_ONE - 1));
113 #endif /* (JERRY_GC_MARK_LIMIT != 0) */
114 }
115 } /* ecma_gc_set_object_visited */
116
117 /**
118 * Initialize GC information for the object
119 */
120 inline void
ecma_init_gc_info(ecma_object_t * object_p)121 ecma_init_gc_info (ecma_object_t *object_p) /**< object */
122 {
123 JERRY_CONTEXT (ecma_gc_objects_number)++;
124 JERRY_CONTEXT (ecma_gc_new_objects)++;
125
126 JERRY_ASSERT (object_p->type_flags_refs < ECMA_OBJECT_REF_ONE);
127 object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs | ECMA_OBJECT_REF_ONE);
128
129 object_p->gc_next_cp = JERRY_CONTEXT (ecma_gc_objects_cp);
130 ECMA_SET_NON_NULL_POINTER (JERRY_CONTEXT (ecma_gc_objects_cp), object_p);
131 #if defined(JERRY_REF_TRACKER)
132 ReportObjRefManip(object_p, kRefInit);
133 #endif
134 } /* ecma_init_gc_info */
135
136 /**
137 * Increase reference counter of an object
138 */
139 void
ecma_ref_object(ecma_object_t * object_p)140 ecma_ref_object (ecma_object_t *object_p) /**< object */
141 {
142 if (JERRY_LIKELY (object_p->type_flags_refs < ECMA_OBJECT_MAX_REF))
143 {
144 object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs + ECMA_OBJECT_REF_ONE);
145 }
146 else
147 {
148 jerry_fatal (ERR_REF_COUNT_LIMIT);
149 }
150 #if defined(JERRY_REF_TRACKER)
151 ReportObjRefManip(object_p, kRefRef);
152 #endif
153 } /* ecma_ref_object */
154
155 /**
156 * Decrease reference counter as a routine of GC reset marks phase.
157 */
158 inline void JERRY_ATTR_ALWAYS_INLINE
ecma_unmark_deref_object(ecma_object_t * object_p)159 ecma_unmark_deref_object (ecma_object_t *object_p) /**< object */
160 {
161 JERRY_ASSERT (object_p->type_flags_refs >= ECMA_OBJECT_REF_ONE);
162 object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs - ECMA_OBJECT_REF_ONE);
163 #if defined(JERRY_REF_TRACKER)
164 ReportObjRefManip(object_p, kRefUnmark);
165 #endif
166 } /* ecma_unmark_deref_object */
167
168 /**
169 * Decrease reference counter of an object
170 */
171 inline void JERRY_ATTR_ALWAYS_INLINE
ecma_deref_object(ecma_object_t * object_p)172 ecma_deref_object (ecma_object_t *object_p) /**< object */
173 {
174 JERRY_ASSERT (object_p->type_flags_refs >= ECMA_OBJECT_REF_ONE);
175 object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs - ECMA_OBJECT_REF_ONE);
176 #if defined(JERRY_REF_TRACKER)
177 ReportObjRefManip(object_p, kRefDeref);
178 #endif
179 } /* ecma_deref_object */
180
181 /**
182 * Mark referenced object from property
183 */
184 static inline void JERRY_ATTR_ALWAYS_INLINE
ecma_gc_mark_properties(ecma_property_pair_t * property_pair_p)185 ecma_gc_mark_properties (ecma_property_pair_t *property_pair_p) /**< property pair */
186 {
187 for (uint32_t index = 0; index < ECMA_PROPERTY_PAIR_ITEM_COUNT; index++)
188 {
189 uint8_t property = property_pair_p->header.types[index];
190
191 switch (ECMA_PROPERTY_GET_TYPE (property))
192 {
193 case ECMA_PROPERTY_TYPE_NAMEDDATA:
194 {
195 ecma_value_t value = property_pair_p->values[index].value;
196
197 if (ecma_is_value_object (value))
198 {
199 ecma_object_t *value_obj_p = ecma_get_object_from_value (value);
200
201 ecma_gc_set_object_visited (value_obj_p);
202 }
203 break;
204 }
205 case ECMA_PROPERTY_TYPE_NAMEDACCESSOR:
206 {
207 ecma_property_value_t *accessor_objs_p = property_pair_p->values + index;
208
209 ecma_getter_setter_pointers_t *get_set_pair_p = ecma_get_named_accessor_property (accessor_objs_p);
210
211 if (get_set_pair_p->getter_cp != JMEM_CP_NULL)
212 {
213 ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->getter_cp));
214 }
215
216 if (get_set_pair_p->setter_cp != JMEM_CP_NULL)
217 {
218 ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->setter_cp));
219 }
220 break;
221 }
222 case ECMA_PROPERTY_TYPE_INTERNAL:
223 {
224 JERRY_ASSERT (ECMA_PROPERTY_GET_NAME_TYPE (property) == ECMA_DIRECT_STRING_MAGIC
225 && property_pair_p->names_cp[index] >= LIT_FIRST_INTERNAL_MAGIC_STRING);
226 break;
227 }
228 default:
229 {
230 JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_SPECIAL);
231
232 JERRY_ASSERT (property == ECMA_PROPERTY_TYPE_HASHMAP
233 || property == ECMA_PROPERTY_TYPE_DELETED);
234 break;
235 }
236 }
237 }
238 } /* ecma_gc_mark_properties */
239
240 /**
241 * Mark objects referenced by bound function object.
242 */
243 static void JERRY_ATTR_NOINLINE
ecma_gc_mark_bound_function_object(ecma_object_t * object_p)244 ecma_gc_mark_bound_function_object (ecma_object_t *object_p) /**< bound function object */
245 {
246 JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION);
247
248 ecma_bound_function_t *bound_func_p = (ecma_bound_function_t *) object_p;
249
250 ecma_object_t *target_func_p;
251 target_func_p = ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t,
252 bound_func_p->header.u.bound_function.target_function);
253
254 ecma_gc_set_object_visited (target_func_p);
255
256 ecma_value_t args_len_or_this = bound_func_p->header.u.bound_function.args_len_or_this;
257
258 if (!ecma_is_value_integer_number (args_len_or_this))
259 {
260 if (ecma_is_value_object (args_len_or_this))
261 {
262 ecma_gc_set_object_visited (ecma_get_object_from_value (args_len_or_this));
263 }
264
265 return;
266 }
267
268 ecma_integer_value_t args_length = ecma_get_integer_from_value (args_len_or_this);
269 ecma_value_t *args_p = (ecma_value_t *) (bound_func_p + 1);
270
271 JERRY_ASSERT (args_length > 0);
272
273 for (ecma_integer_value_t i = 0; i < args_length; i++)
274 {
275 if (ecma_is_value_object (args_p[i]))
276 {
277 ecma_gc_set_object_visited (ecma_get_object_from_value (args_p[i]));
278 }
279 }
280 } /* ecma_gc_mark_bound_function_object */
281
282 #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE)
283 /**
284 * Mark objects referenced by Promise built-in.
285 */
286 static void
ecma_gc_mark_promise_object(ecma_extended_object_t * ext_object_p)287 ecma_gc_mark_promise_object (ecma_extended_object_t *ext_object_p) /**< extended object */
288 {
289 /* Mark promise result. */
290 ecma_value_t result = ext_object_p->u.class_prop.u.value;
291
292 if (ecma_is_value_object (result))
293 {
294 ecma_gc_set_object_visited (ecma_get_object_from_value (result));
295 }
296
297 /* Mark all reactions. */
298 ecma_promise_object_t *promise_object_p = (ecma_promise_object_t *) ext_object_p;
299 ecma_collection_t *collection_p = promise_object_p->reactions;
300
301 if (collection_p != NULL)
302 {
303 ecma_value_t *buffer_p = collection_p->buffer_p;
304 ecma_value_t *buffer_end_p = buffer_p + collection_p->item_count;
305
306 while (buffer_p < buffer_end_p)
307 {
308 ecma_value_t value = *buffer_p++;
309
310 ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, value));
311
312 if (JMEM_CP_GET_FIRST_BIT_FROM_POINTER_TAG (value))
313 {
314 ecma_gc_set_object_visited (ecma_get_object_from_value (*buffer_p++));
315 }
316
317 if (JMEM_CP_GET_SECOND_BIT_FROM_POINTER_TAG (value))
318 {
319 ecma_gc_set_object_visited (ecma_get_object_from_value (*buffer_p++));
320 }
321 }
322 }
323 } /* ecma_gc_mark_promise_object */
324
325 #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */
326
327 #if ENABLED (JERRY_ES2015_BUILTIN_MAP)
328 /**
329 * Mark objects referenced by Map built-in.
330 */
331 static void
ecma_gc_mark_map_object(ecma_object_t * object_p)332 ecma_gc_mark_map_object (ecma_object_t *object_p) /**< object */
333 {
334 JERRY_ASSERT (object_p != NULL);
335
336 ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p;
337 ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
338 map_object_p->u.class_prop.u.value);
339 ecma_value_t *start_p = ECMA_CONTAINER_START (container_p);
340 uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p);
341
342 for (uint32_t i = 0; i < entry_count; i+= ECMA_CONTAINER_PAIR_SIZE)
343 {
344 ecma_container_pair_t *entry_p = (ecma_container_pair_t *) (start_p + i);
345
346 if (ecma_is_value_empty (entry_p->key))
347 {
348 continue;
349 }
350
351 if (ecma_is_value_object (entry_p->key))
352 {
353 ecma_gc_set_object_visited (ecma_get_object_from_value (entry_p->key));
354 }
355
356 if (ecma_is_value_object (entry_p->value))
357 {
358 ecma_gc_set_object_visited (ecma_get_object_from_value (entry_p->value));
359 }
360 }
361 } /* ecma_gc_mark_map_object */
362 #endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */
363
364 #if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP)
365 /**
366 * Mark objects referenced by WeakMap built-in.
367 */
368 static void
ecma_gc_mark_weakmap_object(ecma_object_t * object_p)369 ecma_gc_mark_weakmap_object (ecma_object_t *object_p) /**< object */
370 {
371 JERRY_ASSERT (object_p != NULL);
372
373 ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p;
374 ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
375 map_object_p->u.class_prop.u.value);
376 ecma_value_t *start_p = ECMA_CONTAINER_START (container_p);
377 uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p);
378
379 for (uint32_t i = 0; i < entry_count; i+= ECMA_CONTAINER_PAIR_SIZE)
380 {
381 ecma_container_pair_t *entry_p = (ecma_container_pair_t *) (start_p + i);
382
383 if (ecma_is_value_empty (entry_p->key))
384 {
385 continue;
386 }
387
388 if (ecma_is_value_object (entry_p->value))
389 {
390 ecma_gc_set_object_visited (ecma_get_object_from_value (entry_p->value));
391 }
392 }
393 } /* ecma_gc_mark_weakmap_object */
394 #endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */
395
396 #if ENABLED (JERRY_ES2015_BUILTIN_SET)
397 /**
398 * Mark objects referenced by Set built-in.
399 */
400 static void
ecma_gc_mark_set_object(ecma_object_t * object_p)401 ecma_gc_mark_set_object (ecma_object_t *object_p) /**< object */
402 {
403 JERRY_ASSERT (object_p != NULL);
404
405 ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p;
406 ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
407 map_object_p->u.class_prop.u.value);
408 ecma_value_t *start_p = ECMA_CONTAINER_START (container_p);
409 uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p);
410
411 for (uint32_t i = 0; i < entry_count; i+= ECMA_CONTAINER_VALUE_SIZE)
412 {
413 ecma_value_t *entry_p = start_p + i;
414
415 if (ecma_is_value_empty (*entry_p))
416 {
417 continue;
418 }
419
420 if (ecma_is_value_object (*entry_p))
421 {
422 ecma_gc_set_object_visited (ecma_get_object_from_value (*entry_p));
423 }
424 }
425 } /* ecma_gc_mark_set_object */
426 #endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */
427
428 #if ENABLED (JERRY_ES2015)
429 /**
430 * Mark objects referenced by inactive generator functions, async functions, etc.
431 */
432 static void
ecma_gc_mark_executable_object(ecma_object_t * object_p)433 ecma_gc_mark_executable_object (ecma_object_t *object_p) /**< object */
434 {
435 vm_executable_object_t *executable_object_p = (vm_executable_object_t *) object_p;
436
437 if (!ECMA_EXECUTABLE_OBJECT_IS_SUSPENDED (executable_object_p->extended_object.u.class_prop.extra_info))
438 {
439 /* All objects referenced by running executable objects are strong roots,
440 * and a finished executable object cannot refer to other values. */
441 return;
442 }
443
444 if (executable_object_p->extended_object.u.class_prop.extra_info & ECMA_GENERATOR_ITERATE_AND_YIELD)
445 {
446 ecma_value_t iterator = executable_object_p->extended_object.u.class_prop.u.value;
447 ecma_gc_set_object_visited (ecma_get_object_from_value (iterator));
448 }
449
450 ecma_gc_set_object_visited (executable_object_p->frame_ctx.lex_env_p);
451
452 if (ecma_is_value_object (executable_object_p->frame_ctx.this_binding))
453 {
454 ecma_gc_set_object_visited (ecma_get_object_from_value (executable_object_p->frame_ctx.this_binding));
455 }
456
457 const ecma_compiled_code_t *bytecode_header_p = executable_object_p->frame_ctx.bytecode_header_p;
458 size_t register_end;
459
460 if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
461 {
462 cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_header_p;
463 register_end = args_p->register_end;
464 }
465 else
466 {
467 cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_header_p;
468 register_end = args_p->register_end;
469 }
470
471 ecma_value_t *register_p = VM_GET_REGISTERS (&executable_object_p->frame_ctx);
472 ecma_value_t *register_end_p = register_p + register_end;
473
474 while (register_p < register_end_p)
475 {
476 if (ecma_is_value_object (*register_p))
477 {
478 ecma_gc_set_object_visited (ecma_get_object_from_value (*register_p));
479 }
480
481 register_p++;
482 }
483
484 register_p += executable_object_p->frame_ctx.context_depth;
485 register_end_p = executable_object_p->frame_ctx.stack_top_p;
486
487 while (register_p < register_end_p)
488 {
489 if (ecma_is_value_object (*register_p))
490 {
491 ecma_gc_set_object_visited (ecma_get_object_from_value (*register_p));
492 }
493
494 register_p++;
495 }
496 } /* ecma_gc_mark_executable_object */
497
498 #endif /* ENABLED (JERRY_ES2015) */
499
500 #if ENABLED (JERRY_ES2015_BUILTIN_PROXY)
501 /**
502 * Mark the objects referenced by a proxy object
503 */
504 static void
ecma_gc_mark_proxy_object(ecma_object_t * object_p)505 ecma_gc_mark_proxy_object (ecma_object_t *object_p) /**< proxy object */
506 {
507 JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (object_p));
508
509 ecma_proxy_object_t *proxy_p = (ecma_proxy_object_t *) object_p;
510
511 if (!ecma_is_value_null (proxy_p->target))
512 {
513 ecma_gc_set_object_visited (ecma_get_object_from_value (proxy_p->target));
514 }
515
516 if (!ecma_is_value_null (proxy_p->handler))
517 {
518 ecma_gc_set_object_visited (ecma_get_object_from_value (proxy_p->handler));
519 }
520 } /* ecma_gc_mark_proxy_object */
521 #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */
522
523 /**
524 * Mark objects as visited starting from specified object as root
525 */
526 static void
ecma_gc_mark(ecma_object_t * object_p)527 ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
528 {
529 JERRY_ASSERT (object_p != NULL);
530 JERRY_ASSERT (ecma_gc_is_object_visited (object_p));
531
532 if (ecma_is_lexical_environment (object_p))
533 {
534 jmem_cpointer_t outer_lex_env_cp = object_p->u2.outer_reference_cp;
535
536 if (outer_lex_env_cp != JMEM_CP_NULL)
537 {
538 ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER (ecma_object_t, outer_lex_env_cp));
539 }
540
541 if (ecma_get_lex_env_type (object_p) != ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
542 {
543 ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object (object_p);
544 ecma_gc_set_object_visited (binding_object_p);
545
546 return;
547 }
548 }
549 else
550 {
551 jmem_cpointer_t proto_cp = object_p->u2.prototype_cp;
552
553 if (proto_cp != JMEM_CP_NULL)
554 {
555 ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp));
556 }
557
558 switch (ecma_get_object_type (object_p))
559 {
560 case ECMA_OBJECT_TYPE_CLASS:
561 {
562 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
563
564 switch (ext_object_p->u.class_prop.class_id)
565 {
566 #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE)
567 case LIT_MAGIC_STRING_PROMISE_UL:
568 {
569 ecma_gc_mark_promise_object (ext_object_p);
570 break;
571 }
572 #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */
573 #if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW)
574 case LIT_MAGIC_STRING_DATAVIEW_UL:
575 {
576 ecma_dataview_object_t *dataview_p = (ecma_dataview_object_t *) object_p;
577 ecma_gc_set_object_visited (dataview_p->buffer_p);
578 break;
579 }
580 #endif /* ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) */
581 #if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER)
582 #if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET)
583 case LIT_MAGIC_STRING_WEAKSET_UL:
584 {
585 break;
586 }
587 #endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */
588 #if ENABLED (JERRY_ES2015_BUILTIN_SET)
589 case LIT_MAGIC_STRING_SET_UL:
590 {
591 ecma_gc_mark_set_object (object_p);
592 break;
593 }
594 #endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */
595 #if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP)
596 case LIT_MAGIC_STRING_WEAKMAP_UL:
597 {
598 ecma_gc_mark_weakmap_object (object_p);
599 break;
600 }
601 #endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */
602 #if ENABLED (JERRY_ES2015_BUILTIN_MAP)
603 case LIT_MAGIC_STRING_MAP_UL:
604 {
605 ecma_gc_mark_map_object (object_p);
606 break;
607 }
608 #endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */
609 #endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */
610 #if ENABLED (JERRY_ES2015)
611 case LIT_MAGIC_STRING_GENERATOR_UL:
612 {
613 ecma_gc_mark_executable_object (object_p);
614 break;
615 }
616 #endif /* ENABLED (JERRY_ES2015) */
617 default:
618 {
619 break;
620 }
621 }
622
623 break;
624 }
625 case ECMA_OBJECT_TYPE_PSEUDO_ARRAY:
626 {
627 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
628
629 switch (ext_object_p->u.pseudo_array.type)
630 {
631 #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY)
632 case ECMA_PSEUDO_ARRAY_TYPEDARRAY:
633 case ECMA_PSEUDO_ARRAY_TYPEDARRAY_WITH_INFO:
634 {
635 ecma_gc_set_object_visited (ecma_typedarray_get_arraybuffer (object_p));
636 break;
637 }
638 #endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */
639 #if ENABLED (JERRY_ES2015)
640 case ECMA_PSEUDO_ARRAY_ITERATOR:
641 case ECMA_PSEUDO_SET_ITERATOR:
642 case ECMA_PSEUDO_MAP_ITERATOR:
643 {
644 ecma_value_t iterated_value = ext_object_p->u.pseudo_array.u2.iterated_value;
645 if (!ecma_is_value_empty (iterated_value))
646 {
647 ecma_gc_set_object_visited (ecma_get_object_from_value (iterated_value));
648 }
649 break;
650 }
651 case ECMA_PSEUDO_STRING_ITERATOR:
652 {
653 break;
654 }
655 #endif /* ENABLED (JERRY_ES2015) */
656 default:
657 {
658 JERRY_ASSERT (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ARGUMENTS);
659
660 ecma_object_t *lex_env_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
661 ext_object_p->u.pseudo_array.u2.lex_env_cp);
662
663 ecma_gc_set_object_visited (lex_env_p);
664 break;
665 }
666 }
667
668 break;
669 }
670 case ECMA_OBJECT_TYPE_ARRAY:
671 {
672 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
673
674 if (ecma_op_array_is_fast_array (ext_object_p))
675 {
676 if (object_p->u1.property_list_cp != JMEM_CP_NULL)
677 {
678 ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp);
679
680 for (uint32_t i = 0; i < ext_object_p->u.array.length; i++)
681 {
682 if (ecma_is_value_object (values_p[i]))
683 {
684 ecma_gc_set_object_visited (ecma_get_object_from_value (values_p[i]));
685 }
686 }
687 }
688
689 return;
690 }
691 break;
692 }
693 #if ENABLED (JERRY_ES2015_BUILTIN_PROXY)
694 case ECMA_OBJECT_TYPE_PROXY:
695 {
696 ecma_gc_mark_proxy_object (object_p);
697 break;
698 }
699 #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */
700 case ECMA_OBJECT_TYPE_BOUND_FUNCTION:
701 {
702 ecma_gc_mark_bound_function_object (object_p);
703 break;
704 }
705 case ECMA_OBJECT_TYPE_FUNCTION:
706 {
707 if (!ecma_get_object_is_builtin (object_p))
708 {
709 ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p;
710 ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t,
711 ext_func_p->u.function.scope_cp));
712
713 #if ENABLED (JERRY_ES2015)
714 const ecma_compiled_code_t *byte_code_p = ecma_op_function_get_compiled_code (ext_func_p);
715
716 if (byte_code_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION)
717 {
718 ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p;
719
720 if (ecma_is_value_object (arrow_func_p->this_binding))
721 {
722 ecma_gc_set_object_visited (ecma_get_object_from_value (arrow_func_p->this_binding));
723 }
724
725 if (ecma_is_value_object (arrow_func_p->new_target))
726 {
727 ecma_gc_set_object_visited (ecma_get_object_from_value (arrow_func_p->new_target));
728 }
729 }
730 #endif /* ENABLED (JERRY_ES2015) */
731 }
732 break;
733 }
734 #if ENABLED (JERRY_ES2015)
735 case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION:
736 {
737 ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p;
738
739 if (ext_func_p->u.external_handler_cb == ecma_proxy_revoke_cb)
740 {
741 ecma_revocable_proxy_object_t *rev_proxy_p = (ecma_revocable_proxy_object_t *) object_p;
742
743 if (!ecma_is_value_null (rev_proxy_p->proxy))
744 {
745 ecma_gc_set_object_visited (ecma_get_object_from_value (rev_proxy_p->proxy));
746 }
747 }
748 break;
749 }
750 #endif /* ENABLED (JERRY_ES2015) */
751 default:
752 {
753 break;
754 }
755 }
756 }
757
758 jmem_cpointer_t prop_iter_cp = object_p->u1.property_list_cp;
759
760 #if ENABLED (JERRY_PROPRETY_HASHMAP)
761 if (prop_iter_cp != JMEM_CP_NULL)
762 {
763 ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp);
764 if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP)
765 {
766 prop_iter_cp = prop_iter_p->next_property_cp;
767 }
768 }
769 #endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
770
771 while (prop_iter_cp != JMEM_CP_NULL)
772 {
773 ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp);
774 JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));
775
776 ecma_gc_mark_properties ((ecma_property_pair_t *) prop_iter_p);
777
778 prop_iter_cp = prop_iter_p->next_property_cp;
779 }
780 } /* ecma_gc_mark */
781
782 /**
783 * Free the native handle/pointer by calling its free callback.
784 */
785 static void
ecma_gc_free_native_pointer(ecma_property_t * property_p)786 ecma_gc_free_native_pointer (ecma_property_t *property_p) /**< property */
787 {
788 JERRY_ASSERT (property_p != NULL);
789
790 ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
791 ecma_native_pointer_t *native_pointer_p;
792
793 native_pointer_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_t,
794 value_p->value);
795
796 while (native_pointer_p != NULL)
797 {
798 if (native_pointer_p->info_p != NULL)
799 {
800 ecma_object_native_free_callback_t free_cb = native_pointer_p->info_p->free_cb;
801
802 if (free_cb != NULL)
803 {
804 free_cb (native_pointer_p->data_p);
805 }
806 }
807
808 ecma_native_pointer_t *next_p = native_pointer_p->next_p;
809
810 jmem_heap_free_block (native_pointer_p, sizeof (ecma_native_pointer_t));
811
812 native_pointer_p = next_p;
813 }
814 } /* ecma_gc_free_native_pointer */
815
816 /**
817 * Free specified fast access mode array object.
818 */
819 static void
ecma_free_fast_access_array(ecma_object_t * object_p)820 ecma_free_fast_access_array (ecma_object_t *object_p) /**< fast access mode array object to free */
821 {
822 JERRY_ASSERT (ecma_op_object_is_fast_array (object_p));
823
824 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
825 const uint32_t aligned_length = ECMA_FAST_ARRAY_ALIGN_LENGTH (ext_object_p->u.array.length);
826
827 if (object_p->u1.property_list_cp != JMEM_CP_NULL)
828 {
829 ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp);
830
831 for (uint32_t i = 0; i < aligned_length; i++)
832 {
833 ecma_free_value_if_not_object (values_p[i]);
834 }
835
836 jmem_heap_free_block (values_p, aligned_length * sizeof (ecma_value_t));
837 }
838
839 ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t));
840 } /* ecma_free_fast_access_array */
841
842 #if ENABLED (JERRY_ES2015)
843
844 /**
845 * Free non-objects referenced by inactive generator functions, async functions, etc.
846 *
847 * @return total object size
848 */
849 static size_t
ecma_gc_free_executable_object(ecma_object_t * object_p)850 ecma_gc_free_executable_object (ecma_object_t *object_p) /**< object */
851 {
852 vm_executable_object_t *executable_object_p = (vm_executable_object_t *) object_p;
853
854 const ecma_compiled_code_t *bytecode_header_p = executable_object_p->frame_ctx.bytecode_header_p;
855 size_t size, register_end;
856
857 if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
858 {
859 cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_header_p;
860
861 register_end = args_p->register_end;
862 size = (register_end + (size_t) args_p->stack_limit) * sizeof (ecma_value_t);
863 }
864 else
865 {
866 cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_header_p;
867
868 register_end = args_p->register_end;
869 size = (register_end + (size_t) args_p->stack_limit) * sizeof (ecma_value_t);
870 }
871
872 size = JERRY_ALIGNUP (sizeof (vm_executable_object_t) + size, sizeof (uintptr_t));
873
874 JERRY_ASSERT (!(executable_object_p->extended_object.u.class_prop.extra_info & ECMA_EXECUTABLE_OBJECT_RUNNING));
875
876 ecma_bytecode_deref ((ecma_compiled_code_t *) bytecode_header_p);
877
878 if (executable_object_p->extended_object.u.class_prop.extra_info & ECMA_EXECUTABLE_OBJECT_COMPLETED)
879 {
880 return size;
881 }
882
883 ecma_free_value_if_not_object (executable_object_p->frame_ctx.this_binding);
884
885 ecma_value_t *register_p = VM_GET_REGISTERS (&executable_object_p->frame_ctx);
886 ecma_value_t *register_end_p = register_p + register_end;
887
888 while (register_p < register_end_p)
889 {
890 ecma_free_value_if_not_object (*register_p++);
891 }
892
893 if (executable_object_p->frame_ctx.context_depth > 0)
894 {
895 ecma_value_t *context_end_p = register_p;
896
897 register_p += executable_object_p->frame_ctx.context_depth;
898
899 ecma_value_t *context_top_p = register_p;
900
901 do
902 {
903 context_top_p[-1] &= (uint32_t) ~(VM_CONTEXT_HAS_LEX_ENV | VM_CONTEXT_CLOSE_ITERATOR);
904
905 uint32_t offsets = vm_get_context_value_offsets (context_top_p);
906
907 while (VM_CONTEXT_HAS_NEXT_OFFSET (offsets))
908 {
909 int32_t offset = VM_CONTEXT_GET_NEXT_OFFSET (offsets);
910
911 if (ecma_is_value_object (context_top_p[offset]))
912 {
913 context_top_p[offset] = ECMA_VALUE_UNDEFINED;
914 }
915
916 offsets >>= VM_CONTEXT_OFFSET_SHIFT;
917 }
918
919 context_top_p = vm_stack_context_abort (&executable_object_p->frame_ctx, context_top_p);
920 }
921 while (context_top_p > context_end_p);
922 }
923
924 register_end_p = executable_object_p->frame_ctx.stack_top_p;
925
926 while (register_p < register_end_p)
927 {
928 ecma_free_value_if_not_object (*register_p++);
929 }
930
931 return size;
932 } /* ecma_gc_free_executable_object */
933
934 #endif /* ENABLED (JERRY_ES2015) */
935
936 /**
937 * Free properties of an object
938 */
939 void
ecma_gc_free_properties(ecma_object_t * object_p)940 ecma_gc_free_properties (ecma_object_t *object_p) /**< object */
941 {
942 jmem_cpointer_t prop_iter_cp = object_p->u1.property_list_cp;
943
944 #if ENABLED (JERRY_PROPRETY_HASHMAP)
945 if (prop_iter_cp != JMEM_CP_NULL)
946 {
947 ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t,
948 prop_iter_cp);
949 if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP)
950 {
951 ecma_property_hashmap_free (object_p);
952 prop_iter_cp = object_p->u1.property_list_cp;
953 }
954 }
955 #endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
956
957 while (prop_iter_cp != JMEM_CP_NULL)
958 {
959 ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp);
960 JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));
961
962 /* Both cannot be deleted. */
963 JERRY_ASSERT (prop_iter_p->types[0] != ECMA_PROPERTY_TYPE_DELETED
964 || prop_iter_p->types[1] != ECMA_PROPERTY_TYPE_DELETED);
965
966 ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p;
967
968 for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
969 {
970 ecma_property_t *property_p = (ecma_property_t *) (prop_iter_p->types + i);
971 jmem_cpointer_t name_cp = prop_pair_p->names_cp[i];
972
973 if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_MAGIC)
974 {
975 /* Call the native's free callback. */
976 if (JERRY_UNLIKELY (name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER))
977 {
978 ecma_gc_free_native_pointer (property_p);
979 }
980 #if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET)
981 else if (JERRY_UNLIKELY (name_cp == LIT_INTERNAL_MAGIC_STRING_WEAK_REFS))
982 {
983 ecma_collection_t *refs_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
984 ECMA_PROPERTY_VALUE_PTR (property_p)->value);
985 for (uint32_t j = 0; j < refs_p->item_count; j++)
986 {
987 const ecma_value_t value = refs_p->buffer_p[j];
988 if (!ecma_is_value_empty (value))
989 {
990 ecma_object_t *container_p = ecma_get_object_from_value (value);
991
992 ecma_op_container_remove_weak_entry (container_p,
993 ecma_make_object_value (object_p));
994 }
995 }
996
997 ecma_collection_destroy (refs_p);
998 }
999 #endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */
1000 }
1001
1002 if (prop_iter_p->types[i] != ECMA_PROPERTY_TYPE_DELETED)
1003 {
1004 ecma_free_property (object_p, name_cp, property_p);
1005 }
1006 }
1007
1008 prop_iter_cp = prop_iter_p->next_property_cp;
1009
1010 ecma_dealloc_property_pair (prop_pair_p);
1011 }
1012 } /* ecma_gc_free_properties */
1013
1014 /**
1015 * Free specified object.
1016 */
1017 static void
ecma_gc_free_object(ecma_object_t * object_p)1018 ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
1019 {
1020 JERRY_ASSERT (object_p != NULL
1021 && !ecma_gc_is_object_visited (object_p)
1022 && ((object_p->type_flags_refs & ECMA_OBJECT_REF_MASK) == ECMA_OBJECT_NON_VISITED));
1023
1024 JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_objects_number) > 0);
1025 JERRY_CONTEXT (ecma_gc_objects_number)--;
1026
1027 if (ecma_is_lexical_environment (object_p))
1028 {
1029 if (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
1030 {
1031 ecma_gc_free_properties (object_p);
1032 }
1033
1034 ecma_dealloc_object (object_p);
1035 return;
1036 }
1037
1038 ecma_object_type_t object_type = ecma_get_object_type (object_p);
1039
1040 size_t ext_object_size = sizeof (ecma_extended_object_t);
1041
1042 if (JERRY_UNLIKELY (ecma_get_object_is_builtin (object_p)))
1043 {
1044 uint8_t length_and_bitset_size;
1045
1046 if (object_type == ECMA_OBJECT_TYPE_CLASS
1047 || object_type == ECMA_OBJECT_TYPE_ARRAY)
1048 {
1049 ext_object_size = sizeof (ecma_extended_built_in_object_t);
1050 length_and_bitset_size = ((ecma_extended_built_in_object_t *) object_p)->built_in.length_and_bitset_size;
1051 ext_object_size += (2 * sizeof (uint32_t)) * (length_and_bitset_size >> ECMA_BUILT_IN_BITSET_SHIFT);
1052 }
1053 else
1054 {
1055 length_and_bitset_size = ((ecma_extended_object_t *) object_p)->u.built_in.length_and_bitset_size;
1056 ext_object_size += (2 * sizeof (uint32_t)) * (length_and_bitset_size >> ECMA_BUILT_IN_BITSET_SHIFT);
1057
1058 ecma_gc_free_properties (object_p);
1059 ecma_dealloc_extended_object (object_p, ext_object_size);
1060 return;
1061 }
1062 }
1063
1064 switch (object_type)
1065 {
1066 case ECMA_OBJECT_TYPE_GENERAL:
1067 {
1068 ecma_gc_free_properties (object_p);
1069 ecma_dealloc_object (object_p);
1070 return;
1071 }
1072 case ECMA_OBJECT_TYPE_ARRAY:
1073 {
1074 if (ecma_op_array_is_fast_array ((ecma_extended_object_t *) object_p))
1075 {
1076 ecma_free_fast_access_array (object_p);
1077 return;
1078 }
1079 break;
1080 }
1081 case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION:
1082 {
1083 #if ENABLED (JERRY_ES2015)
1084 ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p;
1085
1086 if (ext_func_p->u.external_handler_cb == ecma_proxy_revoke_cb)
1087 {
1088 ext_object_size = sizeof (ecma_revocable_proxy_object_t);
1089 }
1090 #endif /* ENABLED (JERRY_ES2015) */
1091 break;
1092 }
1093 case ECMA_OBJECT_TYPE_CLASS:
1094 {
1095 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
1096
1097 switch (ext_object_p->u.class_prop.class_id)
1098 {
1099 #if ENABLED (JERRY_ES2015)
1100 case LIT_MAGIC_STRING_SYMBOL_UL:
1101 #endif /* ENABLED (JERRY_ES2015) */
1102 case LIT_MAGIC_STRING_STRING_UL:
1103 case LIT_MAGIC_STRING_NUMBER_UL:
1104 {
1105 ecma_free_value (ext_object_p->u.class_prop.u.value);
1106 break;
1107 }
1108
1109 case LIT_MAGIC_STRING_DATE_UL:
1110 {
1111 ecma_number_t *num_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_number_t,
1112 ext_object_p->u.class_prop.u.value);
1113 ecma_dealloc_number (num_p);
1114 break;
1115 }
1116 case LIT_MAGIC_STRING_REGEXP_UL:
1117 {
1118 ecma_compiled_code_t *bytecode_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (ecma_compiled_code_t,
1119 ext_object_p->u.class_prop.u.value);
1120
1121 ecma_bytecode_deref (bytecode_p);
1122
1123 break;
1124 }
1125 #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY)
1126 case LIT_MAGIC_STRING_ARRAY_BUFFER_UL:
1127 {
1128 ecma_length_t arraybuffer_length = ext_object_p->u.class_prop.u.length;
1129
1130 if (ECMA_ARRAYBUFFER_HAS_EXTERNAL_MEMORY (ext_object_p))
1131 {
1132 ext_object_size = sizeof (ecma_arraybuffer_external_info);
1133
1134 /* Call external free callback if any. */
1135 ecma_arraybuffer_external_info *array_p = (ecma_arraybuffer_external_info *) ext_object_p;
1136 JERRY_ASSERT (array_p != NULL);
1137
1138 if (array_p->free_cb != NULL)
1139 {
1140 (array_p->free_cb) (array_p->buffer_p);
1141 }
1142 }
1143 else
1144 {
1145 ext_object_size += arraybuffer_length;
1146 }
1147
1148 break;
1149 }
1150 #endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */
1151 #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE)
1152 case LIT_MAGIC_STRING_PROMISE_UL:
1153 {
1154 ecma_free_value_if_not_object (ext_object_p->u.class_prop.u.value);
1155
1156 /* Reactions only contains objects. */
1157 ecma_collection_destroy (((ecma_promise_object_t *) object_p)->reactions);
1158
1159 ext_object_size = sizeof (ecma_promise_object_t);
1160 break;
1161 }
1162 #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */
1163 #if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER)
1164 #if ENABLED (JERRY_ES2015_BUILTIN_MAP)
1165 case LIT_MAGIC_STRING_MAP_UL:
1166 #endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */
1167 #if ENABLED (JERRY_ES2015_BUILTIN_SET)
1168 case LIT_MAGIC_STRING_SET_UL:
1169 #endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */
1170 #if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP)
1171 case LIT_MAGIC_STRING_WEAKMAP_UL:
1172 #endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */
1173 #if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET)
1174 case LIT_MAGIC_STRING_WEAKSET_UL:
1175 #endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */
1176 {
1177 ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p;
1178 ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
1179 map_object_p->u.class_prop.u.value);
1180 ecma_op_container_free_entries (object_p);
1181 ecma_collection_destroy (container_p);
1182
1183 break;
1184 }
1185 #endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */
1186 #if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW)
1187 case LIT_MAGIC_STRING_DATAVIEW_UL:
1188 {
1189 ext_object_size = sizeof (ecma_dataview_object_t);
1190 break;
1191 }
1192 #endif /* ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) */
1193 #if ENABLED (JERRY_ES2015)
1194 case LIT_MAGIC_STRING_GENERATOR_UL:
1195 {
1196 ext_object_size = ecma_gc_free_executable_object (object_p);
1197 break;
1198 }
1199 #endif /* ENABLED (JERRY_ES2015) */
1200 default:
1201 {
1202 /* The undefined id represents an uninitialized class. */
1203 JERRY_ASSERT (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_UNDEFINED
1204 || ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_ARGUMENTS_UL
1205 || ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_BOOLEAN_UL
1206 || ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_ERROR_UL
1207 || ext_object_p->u.class_prop.class_id == LIT_INTERNAL_MAGIC_STRING_INTERNAL_OBJECT);
1208 break;
1209 }
1210 }
1211
1212 break;
1213 }
1214 #if ENABLED (JERRY_ES2015_BUILTIN_PROXY)
1215 case ECMA_OBJECT_TYPE_PROXY:
1216 {
1217 ext_object_size = sizeof (ecma_proxy_object_t);
1218 break;
1219 }
1220 #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */
1221 case ECMA_OBJECT_TYPE_FUNCTION:
1222 {
1223 /* Function with byte-code (not a built-in function). */
1224 ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p;
1225
1226 #if ENABLED (JERRY_SNAPSHOT_EXEC)
1227 if (ext_func_p->u.function.bytecode_cp != ECMA_NULL_POINTER)
1228 {
1229 #endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */
1230 ecma_compiled_code_t *byte_code_p = (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t,
1231 ext_func_p->u.function.bytecode_cp));
1232
1233 #if ENABLED (JERRY_ES2015)
1234 if (byte_code_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION)
1235 {
1236 ecma_free_value_if_not_object (((ecma_arrow_function_t *) object_p)->this_binding);
1237 ecma_free_value_if_not_object (((ecma_arrow_function_t *) object_p)->new_target);
1238 ext_object_size = sizeof (ecma_arrow_function_t);
1239 }
1240 #endif /* ENABLED (JERRY_ES2015) */
1241
1242 ecma_bytecode_deref (byte_code_p);
1243 #if ENABLED (JERRY_SNAPSHOT_EXEC)
1244 }
1245 else
1246 {
1247 ext_object_size = sizeof (ecma_static_function_t);
1248 }
1249 #endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */
1250 break;
1251 }
1252 case ECMA_OBJECT_TYPE_PSEUDO_ARRAY:
1253 {
1254 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
1255
1256 switch (ext_object_p->u.pseudo_array.type)
1257 {
1258 case ECMA_PSEUDO_ARRAY_ARGUMENTS:
1259 {
1260 JERRY_ASSERT (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ARGUMENTS);
1261
1262 ecma_length_t formal_params_number = ext_object_p->u.pseudo_array.u1.length;
1263 ecma_value_t *arg_Literal_p = (ecma_value_t *) (ext_object_p + 1);
1264
1265 for (ecma_length_t i = 0; i < formal_params_number; i++)
1266 {
1267 if (arg_Literal_p[i] != ECMA_VALUE_EMPTY)
1268 {
1269 ecma_string_t *name_p = ecma_get_string_from_value (arg_Literal_p[i]);
1270 ecma_deref_ecma_string (name_p);
1271 }
1272 }
1273
1274 size_t formal_params_size = formal_params_number * sizeof (ecma_value_t);
1275 ext_object_size += formal_params_size;
1276 break;
1277 }
1278 #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY)
1279 case ECMA_PSEUDO_ARRAY_TYPEDARRAY_WITH_INFO:
1280 {
1281 ext_object_size = sizeof (ecma_extended_typedarray_object_t);
1282 break;
1283 }
1284 #endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */
1285 #if ENABLED (JERRY_ES2015)
1286 case ECMA_PSEUDO_STRING_ITERATOR:
1287 {
1288 ecma_value_t iterated_value = ext_object_p->u.pseudo_array.u2.iterated_value;
1289
1290 if (!ecma_is_value_empty (iterated_value))
1291 {
1292 ecma_deref_ecma_string (ecma_get_string_from_value (iterated_value));
1293 }
1294
1295 break;
1296 }
1297 #endif /* ENABLED (JERRY_ES2015) */
1298 default:
1299 {
1300 JERRY_ASSERT (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_TYPEDARRAY
1301 || ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ITERATOR
1302 || ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_SET_ITERATOR
1303 || ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_MAP_ITERATOR);
1304 break;
1305 }
1306 }
1307
1308 break;
1309 }
1310 case ECMA_OBJECT_TYPE_BOUND_FUNCTION:
1311 {
1312 ext_object_size = sizeof (ecma_bound_function_t);
1313 ecma_bound_function_t *bound_func_p = (ecma_bound_function_t *) object_p;
1314
1315 ecma_value_t args_len_or_this = bound_func_p->header.u.bound_function.args_len_or_this;
1316
1317 if (!ecma_is_value_integer_number (args_len_or_this))
1318 {
1319 ecma_free_value_if_not_object (args_len_or_this);
1320 break;
1321 }
1322
1323 ecma_integer_value_t args_length = ecma_get_integer_from_value (args_len_or_this);
1324 ecma_value_t *args_p = (ecma_value_t *) (bound_func_p + 1);
1325
1326 for (ecma_integer_value_t i = 0; i < args_length; i++)
1327 {
1328 ecma_free_value_if_not_object (args_p[i]);
1329 }
1330
1331 size_t args_size = ((size_t) args_length) * sizeof (ecma_value_t);
1332 ext_object_size += args_size;
1333 break;
1334 }
1335 default:
1336 {
1337 JERRY_UNREACHABLE ();
1338 }
1339 }
1340
1341 ecma_gc_free_properties (object_p);
1342 ecma_dealloc_extended_object (object_p, ext_object_size);
1343 } /* ecma_gc_free_object */
1344
1345 /**
1346 * Run garbage collection, freeing objects that are no longer referenced.
1347 */
1348 void
ecma_gc_run(void)1349 ecma_gc_run (void)
1350 {
1351 #if (JERRY_GC_MARK_LIMIT != 0)
1352 JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_mark_recursion_limit) == JERRY_GC_MARK_LIMIT);
1353 #endif /* (JERRY_GC_MARK_LIMIT != 0) */
1354
1355 JERRY_CONTEXT (ecma_gc_new_objects) = 0;
1356
1357 ecma_object_t black_list_head;
1358 black_list_head.gc_next_cp = JMEM_CP_NULL;
1359 ecma_object_t *black_end_p = &black_list_head;
1360
1361 ecma_object_t white_gray_list_head;
1362 white_gray_list_head.gc_next_cp = JERRY_CONTEXT (ecma_gc_objects_cp);
1363
1364 ecma_object_t *obj_prev_p = &white_gray_list_head;
1365 jmem_cpointer_t obj_iter_cp = obj_prev_p->gc_next_cp;
1366 ecma_object_t *obj_iter_p;
1367
1368 /* Move root objects (i.e. they have global or stack references) to the black list. */
1369 while (obj_iter_cp != JMEM_CP_NULL)
1370 {
1371 obj_iter_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_object_t, obj_iter_cp);
1372 const jmem_cpointer_t obj_next_cp = obj_iter_p->gc_next_cp;
1373
1374 JERRY_ASSERT (obj_prev_p == NULL
1375 || ECMA_GET_NON_NULL_POINTER (ecma_object_t, obj_prev_p->gc_next_cp) == obj_iter_p);
1376
1377 if (obj_iter_p->type_flags_refs >= ECMA_OBJECT_REF_ONE)
1378 {
1379 /* Moving the object to list of marked objects. */
1380 obj_prev_p->gc_next_cp = obj_next_cp;
1381
1382 black_end_p->gc_next_cp = obj_iter_cp;
1383 black_end_p = obj_iter_p;
1384 }
1385 else
1386 {
1387 obj_iter_p->type_flags_refs |= ECMA_OBJECT_NON_VISITED;
1388 obj_prev_p = obj_iter_p;
1389 }
1390
1391 obj_iter_cp = obj_next_cp;
1392 }
1393
1394 black_end_p->gc_next_cp = JMEM_CP_NULL;
1395
1396 /* Mark root objects. */
1397 obj_iter_cp = black_list_head.gc_next_cp;
1398 while (obj_iter_cp != JMEM_CP_NULL)
1399 {
1400 obj_iter_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_object_t, obj_iter_cp);
1401 ecma_gc_mark (obj_iter_p);
1402 #if defined(JERRY_HEAPDUMP)
1403 if (GetHeapdumpTracing()) {
1404 DumpInfoObject(obj_iter_p, HEAPDUMP_OBJECT_ROOT);
1405 }
1406 #endif
1407 obj_iter_cp = obj_iter_p->gc_next_cp;
1408 }
1409
1410 /* Mark non-root objects. */
1411 bool marked_anything_during_current_iteration;
1412
1413 do
1414 {
1415 #if (JERRY_GC_MARK_LIMIT != 0)
1416 JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_mark_recursion_limit) == JERRY_GC_MARK_LIMIT);
1417 #endif /* (JERRY_GC_MARK_LIMIT != 0) */
1418
1419 marked_anything_during_current_iteration = false;
1420
1421 obj_prev_p = &white_gray_list_head;
1422 obj_iter_cp = obj_prev_p->gc_next_cp;
1423
1424 while (obj_iter_cp != JMEM_CP_NULL)
1425 {
1426 obj_iter_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_object_t, obj_iter_cp);
1427 const jmem_cpointer_t obj_next_cp = obj_iter_p->gc_next_cp;
1428
1429 JERRY_ASSERT (obj_prev_p == NULL
1430 || ECMA_GET_NON_NULL_POINTER (ecma_object_t, obj_prev_p->gc_next_cp) == obj_iter_p);
1431
1432 if (ecma_gc_is_object_visited (obj_iter_p))
1433 {
1434 /* Moving the object to list of marked objects */
1435 obj_prev_p->gc_next_cp = obj_next_cp;
1436
1437 black_end_p->gc_next_cp = obj_iter_cp;
1438 black_end_p = obj_iter_p;
1439
1440 #if (JERRY_GC_MARK_LIMIT != 0)
1441 if (obj_iter_p->type_flags_refs >= ECMA_OBJECT_REF_ONE)
1442 {
1443 /* Set the reference count of non-marked gray object to 0 */
1444 obj_iter_p->type_flags_refs = (uint16_t) (obj_iter_p->type_flags_refs & (ECMA_OBJECT_REF_ONE - 1));
1445 ecma_gc_mark (obj_iter_p);
1446 #if defined(JERRY_HEAPDUMP)
1447 if (GetHeapdumpTracing()) {
1448 DumpInfoObject(obj_iter_p, HEAPDUMP_OBJECT_SIMPLE);
1449 }
1450 #endif
1451 marked_anything_during_current_iteration = true;
1452 }
1453 #else /* (JERRY_GC_MARK_LIMIT == 0) */
1454 marked_anything_during_current_iteration = true;
1455 #endif /* (JERRY_GC_MARK_LIMIT != 0) */
1456 }
1457 else
1458 {
1459 obj_prev_p = obj_iter_p;
1460 }
1461
1462 obj_iter_cp = obj_next_cp;
1463 }
1464 }
1465 while (marked_anything_during_current_iteration);
1466
1467 black_end_p->gc_next_cp = JMEM_CP_NULL;
1468 JERRY_CONTEXT (ecma_gc_objects_cp) = black_list_head.gc_next_cp;
1469
1470 /* Sweep objects that are currently unmarked. */
1471 obj_iter_cp = white_gray_list_head.gc_next_cp;
1472
1473 while (obj_iter_cp != JMEM_CP_NULL)
1474 {
1475 obj_iter_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_object_t, obj_iter_cp);
1476 const jmem_cpointer_t obj_next_cp = obj_iter_p->gc_next_cp;
1477
1478 JERRY_ASSERT (!ecma_gc_is_object_visited (obj_iter_p));
1479
1480 ecma_gc_free_object (obj_iter_p);
1481 obj_iter_cp = obj_next_cp;
1482 }
1483
1484 #if ENABLED (JERRY_BUILTIN_REGEXP)
1485 /* Free RegExp bytecodes stored in cache */
1486 re_cache_gc ();
1487 #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
1488 } /* ecma_gc_run */
1489
1490 /**
1491 * Try to free some memory (depending on memory pressure).
1492 *
1493 * When called with JMEM_PRESSURE_FULL, the engine will be terminated with ERR_OUT_OF_MEMORY.
1494 */
1495 void
ecma_free_unused_memory(jmem_pressure_t pressure)1496 ecma_free_unused_memory (jmem_pressure_t pressure) /**< current pressure */
1497 {
1498 #if ENABLED (JERRY_DEBUGGER)
1499 while ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
1500 /* This shall prevent receiving messaging during evaluation */
1501 && !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_IGNORE)
1502 && JERRY_CONTEXT (debugger_byte_code_free_tail) != ECMA_NULL_POINTER)
1503 {
1504 /* Wait until all byte code is freed or the connection is aborted. */
1505 jerry_debugger_receive (NULL);
1506 }
1507 #endif /* ENABLED (JERRY_DEBUGGER) */
1508
1509 if (JERRY_LIKELY (pressure == JMEM_PRESSURE_LOW))
1510 {
1511 #if ENABLED (JERRY_PROPRETY_HASHMAP)
1512 if (JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) > ECMA_PROP_HASHMAP_ALLOC_ON)
1513 {
1514 --JERRY_CONTEXT (ecma_prop_hashmap_alloc_state);
1515 }
1516 JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_HIGH_PRESSURE_GC;
1517 #endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
1518 /*
1519 * If there is enough newly allocated objects since last GC, probably it is worthwhile to start GC now.
1520 * Otherwise, probability to free sufficient space is considered to be low.
1521 */
1522 size_t new_objects_fraction = CONFIG_ECMA_GC_NEW_OBJECTS_FRACTION;
1523
1524 if (JERRY_CONTEXT (ecma_gc_new_objects) * new_objects_fraction > JERRY_CONTEXT (ecma_gc_objects_number))
1525 {
1526 ecma_gc_run ();
1527 }
1528
1529 return;
1530 }
1531 else if (pressure == JMEM_PRESSURE_HIGH)
1532 {
1533 /* Freeing as much memory as we currently can */
1534 #if ENABLED (JERRY_PROPRETY_HASHMAP)
1535 if (JERRY_CONTEXT (status_flags) & ECMA_STATUS_HIGH_PRESSURE_GC)
1536 {
1537 JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) = ECMA_PROP_HASHMAP_ALLOC_MAX;
1538 }
1539 else if (JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) < ECMA_PROP_HASHMAP_ALLOC_MAX)
1540 {
1541 ++JERRY_CONTEXT (ecma_prop_hashmap_alloc_state);
1542 JERRY_CONTEXT (status_flags) |= ECMA_STATUS_HIGH_PRESSURE_GC;
1543 }
1544 #endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
1545
1546 ecma_gc_run ();
1547
1548 #if ENABLED (JERRY_PROPRETY_HASHMAP)
1549 /* Free hashmaps of remaining objects. */
1550 jmem_cpointer_t obj_iter_cp = JERRY_CONTEXT (ecma_gc_objects_cp);
1551
1552 while (obj_iter_cp != JMEM_CP_NULL)
1553 {
1554 ecma_object_t *obj_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, obj_iter_cp);
1555
1556 if (!ecma_is_lexical_environment (obj_iter_p)
1557 || ecma_get_lex_env_type (obj_iter_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
1558 {
1559 if (!ecma_is_lexical_environment (obj_iter_p)
1560 && ecma_op_object_is_fast_array (obj_iter_p))
1561 {
1562 obj_iter_cp = obj_iter_p->gc_next_cp;
1563 continue;
1564 }
1565
1566 jmem_cpointer_t prop_iter_cp = obj_iter_p->u1.property_list_cp;
1567
1568 if (prop_iter_cp != JMEM_CP_NULL)
1569 {
1570 ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp);
1571
1572 if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP)
1573 {
1574 ecma_property_hashmap_free (obj_iter_p);
1575 }
1576 }
1577
1578 }
1579
1580 obj_iter_cp = obj_iter_p->gc_next_cp;
1581 }
1582 #endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
1583
1584 jmem_pools_collect_empty ();
1585 return;
1586 }
1587 else if (JERRY_UNLIKELY (pressure == JMEM_PRESSURE_FULL))
1588 {
1589 jerry_fatal (ERR_OUT_OF_MEMORY);
1590 }
1591 else
1592 {
1593 JERRY_ASSERT (pressure == JMEM_PRESSURE_NONE);
1594 JERRY_UNREACHABLE ();
1595 }
1596 } /* ecma_free_unused_memory */
1597
1598 /**
1599 * @}
1600 * @}
1601 */
1602