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 */
74static inline bool JERRY_ATTR_ALWAYS_INLINE
75ecma_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 */
85static void ecma_gc_mark (ecma_object_t *object_p);
86
87/**
88 * Set visited flag of the object.
89 */
90static void
91ecma_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 */
120inline void
121ecma_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 */
139void
140ecma_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 */
158inline void JERRY_ATTR_ALWAYS_INLINE
159ecma_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 */
171inline void JERRY_ATTR_ALWAYS_INLINE
172ecma_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 */
184static inline void JERRY_ATTR_ALWAYS_INLINE
185ecma_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 */
243static void JERRY_ATTR_NOINLINE
244ecma_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 */
286static void
287ecma_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 */
331static void
332ecma_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 */
368static void
369ecma_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 */
400static void
401ecma_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 */
432static void
433ecma_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 */
504static void
505ecma_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 */
526static void
527ecma_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 */
785static void
786ecma_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 */
819static void
820ecma_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 */
849static size_t
850ecma_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 */
939void
940ecma_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 */
1017static void
1018ecma_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
1345bool g_isGCEnabled = true;
1346void EnableGC()
1347{
1348  g_isGCEnabled = true;
1349  ecma_gc_run();
1350}
1351
1352void DisableGC()
1353{
1354  g_isGCEnabled = false;
1355}
1356
1357/**
1358 * Run garbage collection, freeing objects that are no longer referenced.
1359 */
1360void
1361ecma_gc_run (void)
1362{
1363#if (JERRY_GC_MARK_LIMIT != 0)
1364  JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_mark_recursion_limit) == JERRY_GC_MARK_LIMIT);
1365#endif /* (JERRY_GC_MARK_LIMIT != 0) */
1366
1367  JERRY_CONTEXT (ecma_gc_new_objects) = 0;
1368
1369  if (!g_isGCEnabled) {
1370    return;
1371  }
1372
1373  ecma_object_t black_list_head;
1374  black_list_head.gc_next_cp = JMEM_CP_NULL;
1375  ecma_object_t *black_end_p = &black_list_head;
1376
1377  ecma_object_t white_gray_list_head;
1378  white_gray_list_head.gc_next_cp = JERRY_CONTEXT (ecma_gc_objects_cp);
1379
1380  ecma_object_t *obj_prev_p = &white_gray_list_head;
1381  jmem_cpointer_t obj_iter_cp = obj_prev_p->gc_next_cp;
1382  ecma_object_t *obj_iter_p;
1383
1384  /* Move root objects (i.e. they have global or stack references) to the black list. */
1385  while (obj_iter_cp != JMEM_CP_NULL)
1386  {
1387    obj_iter_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_object_t, obj_iter_cp);
1388    const jmem_cpointer_t obj_next_cp = obj_iter_p->gc_next_cp;
1389
1390    JERRY_ASSERT (obj_prev_p == NULL
1391                  || ECMA_GET_NON_NULL_POINTER (ecma_object_t, obj_prev_p->gc_next_cp) == obj_iter_p);
1392
1393    if (obj_iter_p->type_flags_refs >= ECMA_OBJECT_REF_ONE)
1394    {
1395      /* Moving the object to list of marked objects. */
1396      obj_prev_p->gc_next_cp = obj_next_cp;
1397
1398      black_end_p->gc_next_cp = obj_iter_cp;
1399      black_end_p = obj_iter_p;
1400    }
1401    else
1402    {
1403      obj_iter_p->type_flags_refs |= ECMA_OBJECT_NON_VISITED;
1404      obj_prev_p = obj_iter_p;
1405    }
1406
1407    obj_iter_cp = obj_next_cp;
1408  }
1409
1410  black_end_p->gc_next_cp = JMEM_CP_NULL;
1411
1412  /* Mark root objects. */
1413  obj_iter_cp = black_list_head.gc_next_cp;
1414  while (obj_iter_cp != JMEM_CP_NULL)
1415  {
1416    obj_iter_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_object_t, obj_iter_cp);
1417    ecma_gc_mark (obj_iter_p);
1418#if defined(JERRY_HEAPDUMP)
1419    if (GetHeapdumpTracing()) {
1420      DumpInfoObject(obj_iter_p, HEAPDUMP_OBJECT_ROOT);
1421    }
1422#endif
1423    obj_iter_cp = obj_iter_p->gc_next_cp;
1424  }
1425
1426  /* Mark non-root objects. */
1427  bool marked_anything_during_current_iteration;
1428
1429  do
1430  {
1431#if (JERRY_GC_MARK_LIMIT != 0)
1432    JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_mark_recursion_limit) == JERRY_GC_MARK_LIMIT);
1433#endif /* (JERRY_GC_MARK_LIMIT != 0) */
1434
1435    marked_anything_during_current_iteration = false;
1436
1437    obj_prev_p = &white_gray_list_head;
1438    obj_iter_cp = obj_prev_p->gc_next_cp;
1439
1440    while (obj_iter_cp != JMEM_CP_NULL)
1441    {
1442      obj_iter_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_object_t, obj_iter_cp);
1443      const jmem_cpointer_t obj_next_cp = obj_iter_p->gc_next_cp;
1444
1445      JERRY_ASSERT (obj_prev_p == NULL
1446                    || ECMA_GET_NON_NULL_POINTER (ecma_object_t, obj_prev_p->gc_next_cp) == obj_iter_p);
1447
1448      if (ecma_gc_is_object_visited (obj_iter_p))
1449      {
1450        /* Moving the object to list of marked objects */
1451        obj_prev_p->gc_next_cp = obj_next_cp;
1452
1453        black_end_p->gc_next_cp = obj_iter_cp;
1454        black_end_p = obj_iter_p;
1455
1456#if (JERRY_GC_MARK_LIMIT != 0)
1457        if (obj_iter_p->type_flags_refs >= ECMA_OBJECT_REF_ONE)
1458        {
1459          /* Set the reference count of non-marked gray object to 0 */
1460          obj_iter_p->type_flags_refs = (uint16_t) (obj_iter_p->type_flags_refs & (ECMA_OBJECT_REF_ONE - 1));
1461          ecma_gc_mark (obj_iter_p);
1462#if defined(JERRY_HEAPDUMP)
1463        if (GetHeapdumpTracing()) {
1464          DumpInfoObject(obj_iter_p, HEAPDUMP_OBJECT_SIMPLE);
1465        }
1466#endif
1467          marked_anything_during_current_iteration = true;
1468        }
1469#else /* (JERRY_GC_MARK_LIMIT == 0) */
1470        marked_anything_during_current_iteration = true;
1471#endif /* (JERRY_GC_MARK_LIMIT != 0) */
1472      }
1473      else
1474      {
1475        obj_prev_p = obj_iter_p;
1476      }
1477
1478      obj_iter_cp = obj_next_cp;
1479    }
1480  }
1481  while (marked_anything_during_current_iteration);
1482
1483  black_end_p->gc_next_cp = JMEM_CP_NULL;
1484  JERRY_CONTEXT (ecma_gc_objects_cp) = black_list_head.gc_next_cp;
1485
1486  /* Sweep objects that are currently unmarked. */
1487  obj_iter_cp = white_gray_list_head.gc_next_cp;
1488
1489  while (obj_iter_cp != JMEM_CP_NULL)
1490  {
1491    obj_iter_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_object_t, obj_iter_cp);
1492    const jmem_cpointer_t obj_next_cp = obj_iter_p->gc_next_cp;
1493
1494    JERRY_ASSERT (!ecma_gc_is_object_visited (obj_iter_p));
1495
1496    ecma_gc_free_object (obj_iter_p);
1497    obj_iter_cp = obj_next_cp;
1498  }
1499
1500#if ENABLED (JERRY_BUILTIN_REGEXP)
1501  /* Free RegExp bytecodes stored in cache */
1502  re_cache_gc ();
1503#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
1504} /* ecma_gc_run */
1505
1506/**
1507 * Try to free some memory (depending on memory pressure).
1508 *
1509 * When called with JMEM_PRESSURE_FULL, the engine will be terminated with ERR_OUT_OF_MEMORY.
1510 */
1511void
1512ecma_free_unused_memory (jmem_pressure_t pressure) /**< current pressure */
1513{
1514#if ENABLED (JERRY_DEBUGGER)
1515  while ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
1516         /* This shall prevent receiving messaging during evaluation */
1517         && !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_IGNORE)
1518         && JERRY_CONTEXT (debugger_byte_code_free_tail) != ECMA_NULL_POINTER)
1519  {
1520    /* Wait until all byte code is freed or the connection is aborted. */
1521    jerry_debugger_receive (NULL);
1522  }
1523#endif /* ENABLED (JERRY_DEBUGGER) */
1524
1525  if (JERRY_LIKELY (pressure == JMEM_PRESSURE_LOW))
1526  {
1527#if ENABLED (JERRY_PROPRETY_HASHMAP)
1528    if (JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) > ECMA_PROP_HASHMAP_ALLOC_ON)
1529    {
1530      --JERRY_CONTEXT (ecma_prop_hashmap_alloc_state);
1531    }
1532    JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_HIGH_PRESSURE_GC;
1533#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
1534    /*
1535     * If there is enough newly allocated objects since last GC, probably it is worthwhile to start GC now.
1536     * Otherwise, probability to free sufficient space is considered to be low.
1537     */
1538    size_t new_objects_fraction = CONFIG_ECMA_GC_NEW_OBJECTS_FRACTION;
1539
1540    if (JERRY_CONTEXT (ecma_gc_new_objects) * new_objects_fraction > JERRY_CONTEXT (ecma_gc_objects_number))
1541    {
1542      ecma_gc_run ();
1543    }
1544
1545    return;
1546  }
1547  else if (pressure == JMEM_PRESSURE_HIGH)
1548  {
1549    /* Freeing as much memory as we currently can */
1550#if ENABLED (JERRY_PROPRETY_HASHMAP)
1551    if (JERRY_CONTEXT (status_flags) & ECMA_STATUS_HIGH_PRESSURE_GC)
1552    {
1553      JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) = ECMA_PROP_HASHMAP_ALLOC_MAX;
1554    }
1555    else if (JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) < ECMA_PROP_HASHMAP_ALLOC_MAX)
1556    {
1557      ++JERRY_CONTEXT (ecma_prop_hashmap_alloc_state);
1558      JERRY_CONTEXT (status_flags) |= ECMA_STATUS_HIGH_PRESSURE_GC;
1559    }
1560#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
1561
1562    ecma_gc_run ();
1563
1564#if ENABLED (JERRY_PROPRETY_HASHMAP)
1565    /* Free hashmaps of remaining objects. */
1566    jmem_cpointer_t obj_iter_cp = JERRY_CONTEXT (ecma_gc_objects_cp);
1567
1568    while (obj_iter_cp != JMEM_CP_NULL)
1569    {
1570      ecma_object_t *obj_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, obj_iter_cp);
1571
1572      if (!ecma_is_lexical_environment (obj_iter_p)
1573          || ecma_get_lex_env_type (obj_iter_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
1574      {
1575        if (!ecma_is_lexical_environment (obj_iter_p)
1576            && ecma_op_object_is_fast_array (obj_iter_p))
1577        {
1578          obj_iter_cp = obj_iter_p->gc_next_cp;
1579          continue;
1580        }
1581
1582        jmem_cpointer_t prop_iter_cp = obj_iter_p->u1.property_list_cp;
1583
1584        if (prop_iter_cp != JMEM_CP_NULL)
1585        {
1586          ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp);
1587
1588          if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP)
1589          {
1590            ecma_property_hashmap_free (obj_iter_p);
1591          }
1592        }
1593
1594      }
1595
1596      obj_iter_cp = obj_iter_p->gc_next_cp;
1597    }
1598#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
1599
1600    jmem_pools_collect_empty ();
1601    return;
1602  }
1603  else if (JERRY_UNLIKELY (pressure == JMEM_PRESSURE_FULL))
1604  {
1605    jerry_fatal (ERR_OUT_OF_MEMORY);
1606  }
1607  else
1608  {
1609    JERRY_ASSERT (pressure == JMEM_PRESSURE_NONE);
1610    JERRY_UNREACHABLE ();
1611  }
1612} /* ecma_free_unused_memory */
1613
1614/**
1615 * @}
1616 * @}
1617 */
1618