• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright JS Foundation and other contributors, http://js.foundation
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 /**
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