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#include "ecma-alloc.h"
17#include "ecma-array-object.h"
18#include "ecma-gc.h"
19#include "ecma-globals.h"
20#include "ecma-helpers.h"
21#include "ecma-lcache.h"
22#include "ecma-property-hashmap.h"
23#include "jcontext.h"
24#include "jrt-bit-fields.h"
25#include "byte-code.h"
26#include "re-compiler.h"
27#include "ecma-builtins.h"
28
29#if ENABLED (JERRY_DEBUGGER)
30#include "debugger.h"
31#endif /* ENABLED (JERRY_DEBUGGER) */
32
33/** \addtogroup ecma ECMA
34 * @{
35 *
36 * \addtogroup ecmahelpers Helpers for operations with ECMA data types
37 * @{
38 */
39
40JERRY_STATIC_ASSERT (ECMA_PROPERTY_TYPE_MASK >= ECMA_PROPERTY_TYPE__MAX,
41                     ecma_property_types_must_be_lower_than_the_container_mask);
42
43JERRY_STATIC_ASSERT (ECMA_OBJECT_TYPE_MASK >= ECMA_OBJECT_TYPE__MAX - 1,
44                     ecma_object_types_must_be_lower_than_the_container_mask);
45
46JERRY_STATIC_ASSERT (ECMA_OBJECT_TYPE_MASK >= ECMA_LEXICAL_ENVIRONMENT_TYPE__MAX,
47                     ecma_lexical_environment_types_must_be_lower_than_the_container_mask);
48
49JERRY_STATIC_ASSERT (ECMA_OBJECT_TYPE_MASK + 1 == ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV,
50                     ecma_built_in_flag_must_follow_the_object_type);
51
52JERRY_STATIC_ASSERT (ECMA_OBJECT_FLAG_EXTENSIBLE == (ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV << 1),
53                     ecma_extensible_flag_must_follow_the_built_in_flag);
54
55JERRY_STATIC_ASSERT (ECMA_OBJECT_REF_ONE == (ECMA_OBJECT_FLAG_EXTENSIBLE << 1),
56                     ecma_object_ref_one_must_follow_the_extensible_flag);
57
58JERRY_STATIC_ASSERT (((ECMA_OBJECT_MAX_REF + ECMA_OBJECT_REF_ONE) | (ECMA_OBJECT_REF_ONE - 1)) == UINT16_MAX,
59                      ecma_object_max_ref_does_not_fill_the_remaining_bits);
60
61JERRY_STATIC_ASSERT (ECMA_PROPERTY_TYPE_DELETED == (ECMA_DIRECT_STRING_MAGIC << ECMA_PROPERTY_NAME_TYPE_SHIFT),
62                     ecma_property_type_deleted_must_have_magic_string_name_type);
63
64/**
65 * Create an object with specified prototype object
66 * (or NULL prototype if there is not prototype for the object)
67 * and value of 'Extensible' attribute.
68 *
69 * Reference counter's value will be set to one.
70 *
71 * @return pointer to the object's descriptor
72 */
73ecma_object_t *
74ecma_create_object (ecma_object_t *prototype_object_p, /**< pointer to prototybe of the object (or NULL) */
75                    size_t ext_object_size, /**< size of extended objects */
76                    ecma_object_type_t type) /**< object type */
77{
78  ecma_object_t *new_object_p;
79
80  if (ext_object_size > 0)
81  {
82    new_object_p = (ecma_object_t *) ecma_alloc_extended_object (ext_object_size);
83  }
84  else
85  {
86    new_object_p = ecma_alloc_object ();
87  }
88
89  new_object_p->type_flags_refs = (uint16_t) (type | ECMA_OBJECT_FLAG_EXTENSIBLE);
90
91  ecma_init_gc_info (new_object_p);
92
93  new_object_p->u1.property_list_cp = JMEM_CP_NULL;
94
95  ECMA_SET_POINTER (new_object_p->u2.prototype_cp, prototype_object_p);
96
97  return new_object_p;
98} /* ecma_create_object */
99
100/**
101 * Create a declarative lexical environment with specified outer lexical environment
102 * (or NULL if the environment is not nested).
103 *
104 * See also: ECMA-262 v5, 10.2.1.1
105 *
106 * Reference counter's value will be set to one.
107 *
108 * @return pointer to the descriptor of lexical environment
109 */
110ecma_object_t *
111ecma_create_decl_lex_env (ecma_object_t *outer_lexical_environment_p) /**< outer lexical environment */
112{
113  ecma_object_t *new_lexical_environment_p = ecma_alloc_object ();
114
115  uint16_t type = ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV | ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE;
116  new_lexical_environment_p->type_flags_refs = type;
117
118  ecma_init_gc_info (new_lexical_environment_p);
119
120  new_lexical_environment_p->u1.property_list_cp = JMEM_CP_NULL;
121
122  ECMA_SET_POINTER (new_lexical_environment_p->u2.outer_reference_cp, outer_lexical_environment_p);
123
124  return new_lexical_environment_p;
125} /* ecma_create_decl_lex_env */
126
127/**
128 * Create a object lexical environment with specified outer lexical environment
129 * (or NULL if the environment is not nested), binding object and provided type flag.
130 *
131 * See also: ECMA-262 v5, 10.2.1.2
132 *
133 * Reference counter's value will be set to one.
134 *
135 * @return pointer to the descriptor of lexical environment
136 */
137ecma_object_t *
138ecma_create_object_lex_env (ecma_object_t *outer_lexical_environment_p, /**< outer lexical environment */
139                            ecma_object_t *binding_obj_p, /**< binding object */
140                            ecma_lexical_environment_type_t type) /**< type of the new lexical environment */
141{
142#if ENABLED (JERRY_ES2015)
143  JERRY_ASSERT (type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND
144                || type == ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND);
145#else /* !ENABLED (JERRY_ES2015) */
146  JERRY_ASSERT (type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
147#endif /* ENABLED (JERRY_ES2015) */
148
149  JERRY_ASSERT (binding_obj_p != NULL
150                && !ecma_is_lexical_environment (binding_obj_p));
151
152  ecma_object_t *new_lexical_environment_p = ecma_alloc_object ();
153
154  new_lexical_environment_p->type_flags_refs = (uint16_t) (ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV | type);
155
156  ecma_init_gc_info (new_lexical_environment_p);
157
158  ECMA_SET_NON_NULL_POINTER (new_lexical_environment_p->u1.bound_object_cp,
159                             binding_obj_p);
160
161  ECMA_SET_POINTER (new_lexical_environment_p->u2.outer_reference_cp, outer_lexical_environment_p);
162
163  return new_lexical_environment_p;
164} /* ecma_create_object_lex_env */
165
166/**
167 * Check if the object is lexical environment.
168 *
169 * @return true  - if object is a lexical environment
170 *         false - otherwise
171 */
172inline bool JERRY_ATTR_PURE
173ecma_is_lexical_environment (const ecma_object_t *object_p) /**< object or lexical environment */
174{
175  JERRY_ASSERT (object_p != NULL);
176
177  uint32_t full_type = object_p->type_flags_refs & (ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV | ECMA_OBJECT_TYPE_MASK);
178
179  return full_type >= (ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV | ECMA_LEXICAL_ENVIRONMENT_TYPE_START);
180} /* ecma_is_lexical_environment */
181
182/**
183 * Set value of [[Extensible]] object's internal property.
184 */
185inline void
186ecma_op_ordinary_object_set_extensible (ecma_object_t *object_p) /**< object */
187{
188  JERRY_ASSERT (object_p != NULL);
189  JERRY_ASSERT (!ecma_is_lexical_environment (object_p));
190
191  object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs | ECMA_OBJECT_FLAG_EXTENSIBLE);
192} /* ecma_op_ordinary_object_set_extensible */
193
194/**
195 * Get object's internal implementation-defined type.
196 *
197 * @return type of the object (ecma_object_type_t)
198 */
199inline ecma_object_type_t JERRY_ATTR_PURE
200ecma_get_object_type (const ecma_object_t *object_p) /**< object */
201{
202  JERRY_ASSERT (object_p != NULL);
203  JERRY_ASSERT (!ecma_is_lexical_environment (object_p));
204
205  return (ecma_object_type_t) (object_p->type_flags_refs & ECMA_OBJECT_TYPE_MASK);
206} /* ecma_get_object_type */
207
208/**
209 * Check if the object is a built-in object
210 *
211 * @return true  - if object is a built-in object
212 *         false - otherwise
213 */
214inline bool JERRY_ATTR_PURE
215ecma_get_object_is_builtin (const ecma_object_t *object_p) /**< object */
216{
217  JERRY_ASSERT (object_p != NULL);
218  JERRY_ASSERT (!ecma_is_lexical_environment (object_p));
219
220  return (object_p->type_flags_refs & ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV) != 0;
221} /* ecma_get_object_is_builtin */
222
223/**
224 * Set flag indicating whether the object is a built-in object
225 */
226inline void
227ecma_set_object_is_builtin (ecma_object_t *object_p) /**< object */
228{
229  JERRY_ASSERT (object_p != NULL);
230  JERRY_ASSERT (!(object_p->type_flags_refs & ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV));
231  JERRY_ASSERT ((object_p->type_flags_refs & ECMA_OBJECT_TYPE_MASK) < ECMA_LEXICAL_ENVIRONMENT_TYPE_START);
232
233  object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs | ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV);
234} /* ecma_set_object_is_builtin */
235
236/**
237 * Get the built-in ID of the object.
238 * If the object is not builtin, return ECMA_BUILTIN_ID__COUNT
239 *
240 * @return the ID of the built-in
241 */
242inline uint8_t
243ecma_get_object_builtin_id (ecma_object_t *object_p) /**< object */
244{
245  if (!ecma_get_object_is_builtin (object_p))
246  {
247    return ECMA_BUILTIN_ID__COUNT;
248  }
249
250  ecma_built_in_props_t *built_in_props_p;
251  ecma_object_type_t object_type = ecma_get_object_type (object_p);
252
253  if (object_type == ECMA_OBJECT_TYPE_CLASS || object_type == ECMA_OBJECT_TYPE_ARRAY)
254  {
255    built_in_props_p = &((ecma_extended_built_in_object_t *) object_p)->built_in;
256  }
257  else
258  {
259    built_in_props_p = &((ecma_extended_object_t *) object_p)->u.built_in;
260  }
261
262  return built_in_props_p->id;
263} /* ecma_get_object_builtin_id */
264
265/**
266 * Get type of lexical environment.
267 *
268 * @return type of the lexical environment (ecma_lexical_environment_type_t)
269 */
270inline ecma_lexical_environment_type_t JERRY_ATTR_PURE
271ecma_get_lex_env_type (const ecma_object_t *object_p) /**< lexical environment */
272{
273  JERRY_ASSERT (object_p != NULL);
274  JERRY_ASSERT (ecma_is_lexical_environment (object_p));
275
276  if (object_p == NULL)
277  {
278    jerry_fatal(ERR_FAILED_INTERNAL_ASSERTION);
279  }
280
281  return (ecma_lexical_environment_type_t) (object_p->type_flags_refs & ECMA_OBJECT_TYPE_MASK);
282} /* ecma_get_lex_env_type */
283
284/**
285 * Get lexical environment's bound object.
286 *
287 * @return pointer to ecma object
288 */
289inline ecma_object_t *JERRY_ATTR_PURE
290ecma_get_lex_env_binding_object (const ecma_object_t *object_p) /**< object-bound lexical environment */
291{
292  JERRY_ASSERT (object_p != NULL);
293  JERRY_ASSERT (ecma_is_lexical_environment (object_p));
294#if ENABLED (JERRY_ES2015)
295  JERRY_ASSERT (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND
296                || ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND);
297#else /* !ENABLED (JERRY_ES2015) */
298  JERRY_ASSERT (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
299#endif /* ENABLED (JERRY_ES2015) */
300
301  return ECMA_GET_NON_NULL_POINTER (ecma_object_t, object_p->u1.bound_object_cp);
302} /* ecma_get_lex_env_binding_object */
303
304/**
305 * Create a new lexical environment with the same property list as the passed lexical environment
306 *
307 * @return pointer to the newly created lexical environment
308 */
309ecma_object_t *
310ecma_clone_decl_lexical_environment (ecma_object_t *lex_env_p, /**< declarative lexical environment */
311                                     bool copy_values) /**< copy property values as well */
312{
313  JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE);
314  JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL);
315
316  ecma_object_t *outer_lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
317  ecma_object_t *new_lex_env_p = ecma_create_decl_lex_env (outer_lex_env_p);
318
319  jmem_cpointer_t prop_iter_cp = lex_env_p->u1.property_list_cp;
320  JERRY_ASSERT (prop_iter_cp != JMEM_CP_NULL);
321
322  ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t,
323                                                                   prop_iter_cp);
324  if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP)
325  {
326    prop_iter_cp = prop_iter_p->next_property_cp;
327  }
328
329  JERRY_ASSERT (prop_iter_cp != JMEM_CP_NULL);
330
331  do
332  {
333    prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp);
334
335    JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));
336
337    ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p;
338
339    for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
340    {
341      if (prop_iter_p->types[i] != ECMA_PROPERTY_TYPE_DELETED)
342      {
343        JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_iter_p->types[i]) == ECMA_PROPERTY_TYPE_NAMEDDATA);
344
345        uint8_t prop_attributes = (uint8_t) (prop_iter_p->types[i] & ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
346        ecma_string_t *name_p = ecma_string_from_property_name (prop_iter_p->types[i], prop_pair_p->names_cp[i]);
347
348        ecma_property_value_t *property_value_p;
349        property_value_p = ecma_create_named_data_property (new_lex_env_p, name_p, prop_attributes, NULL);
350
351        ecma_deref_ecma_string (name_p);
352
353        JERRY_ASSERT (property_value_p->value == ECMA_VALUE_UNDEFINED);
354
355        if (copy_values)
356        {
357          property_value_p->value = ecma_copy_value_if_not_object (prop_pair_p->values[i].value);
358        }
359        else
360        {
361          property_value_p->value = ECMA_VALUE_UNINITIALIZED;
362        }
363      }
364    }
365
366    prop_iter_cp = prop_iter_p->next_property_cp;
367  }
368  while (prop_iter_cp != JMEM_CP_NULL);
369
370  ecma_deref_object (lex_env_p);
371  return new_lex_env_p;
372} /* ecma_clone_decl_lexical_environment */
373
374/**
375 * Create a property in an object and link it into
376 * the object's properties' linked-list (at start of the list).
377 *
378 * @return pointer to the newly created property value
379 */
380static ecma_property_value_t *
381ecma_create_property (ecma_object_t *object_p, /**< the object */
382                      ecma_string_t *name_p, /**< property name */
383                      uint8_t type_and_flags, /**< type and flags, see ecma_property_info_t */
384                      ecma_property_value_t value, /**< property value */
385                      ecma_property_t **out_prop_p) /**< [out] the property is also returned
386                                                     *         if this field is non-NULL */
387{
388  JERRY_ASSERT (ECMA_PROPERTY_PAIR_ITEM_COUNT == 2);
389  JERRY_ASSERT (name_p != NULL);
390  JERRY_ASSERT (object_p != NULL);
391
392  jmem_cpointer_t *property_list_head_p = &object_p->u1.property_list_cp;
393
394  if (*property_list_head_p != ECMA_NULL_POINTER)
395  {
396    /* If the first entry is free (deleted), it is reused. */
397    ecma_property_header_t *first_property_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t,
398                                                                          *property_list_head_p);
399
400#if ENABLED (JERRY_PROPRETY_HASHMAP)
401    bool has_hashmap = false;
402
403    if (first_property_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP)
404    {
405      property_list_head_p = &first_property_p->next_property_cp;
406      first_property_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t,
407                                                    *property_list_head_p);
408      has_hashmap = true;
409    }
410#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
411
412    JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (first_property_p));
413
414    if (first_property_p->types[0] == ECMA_PROPERTY_TYPE_DELETED)
415    {
416      ecma_property_pair_t *first_property_pair_p = (ecma_property_pair_t *) first_property_p;
417
418      ecma_property_t name_type;
419      first_property_pair_p->names_cp[0] = ecma_string_to_property_name (name_p,
420                                                                         &name_type);
421      first_property_p->types[0] = (ecma_property_t) (type_and_flags | name_type);
422
423      ecma_property_t *property_p = first_property_p->types + 0;
424
425      JERRY_ASSERT (ECMA_PROPERTY_VALUE_PTR (property_p) == first_property_pair_p->values + 0);
426
427      if (out_prop_p != NULL)
428      {
429        *out_prop_p = property_p;
430      }
431
432      first_property_pair_p->values[0] = value;
433
434#if ENABLED (JERRY_PROPRETY_HASHMAP)
435      /* The property must be fully initialized before ecma_property_hashmap_insert
436       * is called, because the insert operation may reallocate the hashmap, and
437       * that triggers garbage collection which scans all properties of all objects.
438       * A not fully initialized but queued property may cause a crash. */
439
440      if (has_hashmap)
441      {
442        ecma_property_hashmap_insert (object_p,
443                                      name_p,
444                                      first_property_pair_p,
445                                      0);
446      }
447#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
448
449      return first_property_pair_p->values + 0;
450    }
451  }
452
453  /* Otherwise we create a new property pair and use its second value. */
454  ecma_property_pair_t *first_property_pair_p = ecma_alloc_property_pair ();
455
456  /* Need to query property_list_head_p again and recheck the existennce
457   * of property hasmap, because ecma_alloc_property_pair may delete them. */
458  property_list_head_p = &object_p->u1.property_list_cp;
459#if ENABLED (JERRY_PROPRETY_HASHMAP)
460  bool has_hashmap = false;
461
462  if (*property_list_head_p != ECMA_NULL_POINTER)
463  {
464    ecma_property_header_t *first_property_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t,
465                                                                          *property_list_head_p);
466
467    if (first_property_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP)
468    {
469      property_list_head_p = &first_property_p->next_property_cp;
470      has_hashmap = true;
471    }
472  }
473#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
474
475  /* Just copy the previous value (no need to decompress, compress). */
476  first_property_pair_p->header.next_property_cp = *property_list_head_p;
477  first_property_pair_p->header.types[0] = ECMA_PROPERTY_TYPE_DELETED;
478  first_property_pair_p->names_cp[0] = LIT_INTERNAL_MAGIC_STRING_DELETED;
479
480  ecma_property_t name_type;
481  first_property_pair_p->names_cp[1] = ecma_string_to_property_name (name_p,
482                                                                     &name_type);
483
484  first_property_pair_p->header.types[1] = (ecma_property_t) (type_and_flags | name_type);
485
486  ECMA_SET_NON_NULL_POINTER (*property_list_head_p, &first_property_pair_p->header);
487
488  ecma_property_t *property_p = first_property_pair_p->header.types + 1;
489
490  JERRY_ASSERT (ECMA_PROPERTY_VALUE_PTR (property_p) == first_property_pair_p->values + 1);
491
492  if (out_prop_p != NULL)
493  {
494    *out_prop_p = property_p;
495  }
496
497  first_property_pair_p->values[1] = value;
498
499#if ENABLED (JERRY_PROPRETY_HASHMAP)
500  /* See the comment before the other ecma_property_hashmap_insert above. */
501
502  if (has_hashmap)
503  {
504    ecma_property_hashmap_insert (object_p,
505                                  name_p,
506                                  first_property_pair_p,
507                                  1);
508  }
509#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
510
511  return first_property_pair_p->values + 1;
512} /* ecma_create_property */
513
514/**
515 * Create named data property with given name, attributes and undefined value
516 * in the specified object.
517 *
518 * @return pointer to the newly created property value
519 */
520ecma_property_value_t *
521ecma_create_named_data_property (ecma_object_t *object_p, /**< object */
522                                 ecma_string_t *name_p, /**< property name */
523                                 uint8_t prop_attributes, /**< property attributes (See: ecma_property_flags_t) */
524                                 ecma_property_t **out_prop_p) /**< [out] the property is also returned
525                                                                *         if this field is non-NULL */
526{
527  JERRY_ASSERT (object_p != NULL && name_p != NULL);
528  JERRY_ASSERT (ecma_is_lexical_environment (object_p)
529                || !ecma_op_object_is_fast_array (object_p));
530  JERRY_ASSERT (ecma_find_named_property (object_p, name_p) == NULL);
531  JERRY_ASSERT ((prop_attributes & ~ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE) == 0);
532
533  uint8_t type_and_flags = ECMA_PROPERTY_TYPE_NAMEDDATA | prop_attributes;
534
535  ecma_property_value_t value;
536  value.value = ECMA_VALUE_UNDEFINED;
537
538  return ecma_create_property (object_p, name_p, type_and_flags, value, out_prop_p);
539} /* ecma_create_named_data_property */
540
541/**
542 * Create named accessor property with given name, attributes, getter and setter.
543 *
544 * @return pointer to the newly created property value
545 */
546ecma_property_value_t *
547ecma_create_named_accessor_property (ecma_object_t *object_p, /**< object */
548                                     ecma_string_t *name_p, /**< property name */
549                                     ecma_object_t *get_p, /**< getter */
550                                     ecma_object_t *set_p, /**< setter */
551                                     uint8_t prop_attributes, /**< property attributes */
552                                     ecma_property_t **out_prop_p) /**< [out] the property is also returned
553                                                                    *         if this field is non-NULL */
554{
555  JERRY_ASSERT (object_p != NULL && name_p != NULL);
556  JERRY_ASSERT (ecma_is_lexical_environment (object_p)
557                || !ecma_op_object_is_fast_array (object_p));
558  JERRY_ASSERT (ecma_find_named_property (object_p, name_p) == NULL);
559  JERRY_ASSERT ((prop_attributes & ~ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE) == 0);
560
561  uint8_t type_and_flags = ECMA_PROPERTY_TYPE_NAMEDACCESSOR | prop_attributes;
562
563  ecma_property_value_t value;
564#if ENABLED (JERRY_CPOINTER_32_BIT)
565  ecma_getter_setter_pointers_t *getter_setter_pair_p;
566  getter_setter_pair_p = jmem_pools_alloc (sizeof (ecma_getter_setter_pointers_t));
567  ECMA_SET_POINTER (getter_setter_pair_p->getter_cp, get_p);
568  ECMA_SET_POINTER (getter_setter_pair_p->setter_cp, set_p);
569  ECMA_SET_NON_NULL_POINTER (value.getter_setter_pair_cp, getter_setter_pair_p);
570#else /* !ENABLED (JERRY_CPOINTER_32_BIT) */
571  ECMA_SET_POINTER (value.getter_setter_pair.getter_cp, get_p);
572  ECMA_SET_POINTER (value.getter_setter_pair.setter_cp, set_p);
573#endif /* ENABLED (JERRY_CPOINTER_32_BIT) */
574
575  return ecma_create_property (object_p, name_p, type_and_flags, value, out_prop_p);
576} /* ecma_create_named_accessor_property */
577
578/**
579 * Find named data property or named access property in specified object.
580 *
581 * @return pointer to the property, if it is found,
582 *         NULL - otherwise.
583 */
584ecma_property_t *
585ecma_find_named_property (ecma_object_t *obj_p, /**< object to find property in */
586                          ecma_string_t *name_p) /**< property's name */
587{
588  JERRY_ASSERT (obj_p != NULL);
589  JERRY_ASSERT (name_p != NULL);
590  JERRY_ASSERT (ecma_is_lexical_environment (obj_p)
591                || !ecma_op_object_is_fast_array (obj_p));
592
593  ecma_property_t *property_p = NULL;
594
595#if ENABLED (JERRY_LCACHE)
596  property_p = ecma_lcache_lookup (obj_p, name_p);
597  if (property_p != NULL)
598  {
599    return property_p;
600  }
601#endif /* ENABLED (JERRY_LCACHE) */
602
603  jmem_cpointer_t prop_iter_cp = obj_p->u1.property_list_cp;
604
605#if ENABLED (JERRY_PROPRETY_HASHMAP)
606  if (prop_iter_cp != JMEM_CP_NULL)
607  {
608    ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t,
609                                                                     prop_iter_cp);
610    if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP)
611    {
612      jmem_cpointer_t property_real_name_cp;
613      property_p = ecma_property_hashmap_find ((ecma_property_hashmap_t *) prop_iter_p,
614                                               name_p,
615                                               &property_real_name_cp);
616#if ENABLED (JERRY_LCACHE)
617      if (property_p != NULL
618          && !ecma_is_property_lcached (property_p))
619      {
620        ecma_lcache_insert (obj_p, property_real_name_cp, property_p);
621      }
622#endif /* ENABLED (JERRY_LCACHE) */
623      return property_p;
624    }
625  }
626#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
627
628#if ENABLED (JERRY_PROPRETY_HASHMAP)
629  uint32_t steps = 0;
630#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
631  jmem_cpointer_t property_name_cp = ECMA_NULL_POINTER;
632
633  if (ECMA_IS_DIRECT_STRING (name_p))
634  {
635    ecma_property_t prop_name_type = (ecma_property_t) ECMA_GET_DIRECT_STRING_TYPE (name_p);
636    property_name_cp = (jmem_cpointer_t) ECMA_GET_DIRECT_STRING_VALUE (name_p);
637
638    JERRY_ASSERT (prop_name_type > 0);
639
640    while (prop_iter_cp != JMEM_CP_NULL)
641    {
642      ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t,
643                                                                       prop_iter_cp);
644
645      JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));
646
647      ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p;
648
649      if (prop_pair_p->names_cp[0] == property_name_cp
650          && ECMA_PROPERTY_GET_NAME_TYPE (prop_iter_p->types[0]) == prop_name_type)
651      {
652        JERRY_ASSERT (ECMA_PROPERTY_IS_NAMED_PROPERTY (prop_iter_p->types[0]));
653
654        property_p = prop_iter_p->types + 0;
655        break;
656      }
657
658      if (prop_pair_p->names_cp[1] == property_name_cp
659          && ECMA_PROPERTY_GET_NAME_TYPE (prop_iter_p->types[1]) == prop_name_type)
660      {
661        JERRY_ASSERT (ECMA_PROPERTY_IS_NAMED_PROPERTY (prop_iter_p->types[1]));
662
663        property_p = prop_iter_p->types + 1;
664        break;
665      }
666
667#if ENABLED (JERRY_PROPRETY_HASHMAP)
668      steps++;
669#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
670      prop_iter_cp = prop_iter_p->next_property_cp;
671    }
672  }
673  else
674  {
675    while (prop_iter_cp != JMEM_CP_NULL)
676    {
677      ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t,
678                                                                       prop_iter_cp);
679
680      JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));
681
682      ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p;
683
684      if (ECMA_PROPERTY_GET_NAME_TYPE (prop_iter_p->types[0]) == ECMA_DIRECT_STRING_PTR)
685      {
686        property_name_cp = prop_pair_p->names_cp[0];
687        ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, property_name_cp);
688
689        if (ecma_compare_ecma_non_direct_strings (name_p, prop_name_p))
690        {
691          property_p = prop_iter_p->types + 0;
692          break;
693        }
694      }
695
696      if (ECMA_PROPERTY_GET_NAME_TYPE (prop_iter_p->types[1]) == ECMA_DIRECT_STRING_PTR)
697      {
698        property_name_cp = prop_pair_p->names_cp[1];
699        ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, property_name_cp);
700
701        if (ecma_compare_ecma_non_direct_strings (name_p, prop_name_p))
702        {
703          property_p = prop_iter_p->types + 1;
704          break;
705        }
706      }
707
708#if ENABLED (JERRY_PROPRETY_HASHMAP)
709      steps++;
710#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
711      prop_iter_cp = prop_iter_p->next_property_cp;
712    }
713  }
714
715#if ENABLED (JERRY_PROPRETY_HASHMAP)
716  if (steps >= (ECMA_PROPERTY_HASMAP_MINIMUM_SIZE / 2))
717  {
718    ecma_property_hashmap_create (obj_p);
719  }
720#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
721
722#if ENABLED (JERRY_LCACHE)
723  if (property_p != NULL
724      && !ecma_is_property_lcached (property_p))
725  {
726    ecma_lcache_insert (obj_p, property_name_cp, property_p);
727  }
728#endif /* ENABLED (JERRY_LCACHE) */
729
730  return property_p;
731} /* ecma_find_named_property */
732
733/**
734 * Get named data property or named access property in specified object.
735 *
736 * Warning:
737 *         the property must exist
738 *
739 * @return pointer to the property, if it is found,
740 *         NULL - otherwise.
741 */
742ecma_property_value_t *
743ecma_get_named_data_property (ecma_object_t *obj_p, /**< object to find property in */
744                              ecma_string_t *name_p) /**< property's name */
745{
746  JERRY_ASSERT (obj_p != NULL);
747  JERRY_ASSERT (name_p != NULL);
748  JERRY_ASSERT (ecma_is_lexical_environment (obj_p)
749                || !ecma_op_object_is_fast_array (obj_p));
750
751  ecma_property_t *property_p = ecma_find_named_property (obj_p, name_p);
752
753  JERRY_ASSERT (property_p != NULL
754                && ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA);
755
756  return ECMA_PROPERTY_VALUE_PTR (property_p);
757} /* ecma_get_named_data_property */
758
759/**
760 * Free property values and change their type to deleted.
761 */
762void
763ecma_free_property (ecma_object_t *object_p, /**< object the property belongs to */
764                    jmem_cpointer_t name_cp, /**< name of the property or ECMA_NULL_POINTER */
765                    ecma_property_t *property_p) /**< property */
766{
767  JERRY_ASSERT (object_p != NULL && property_p != NULL);
768
769  switch (ECMA_PROPERTY_GET_TYPE (*property_p))
770  {
771    case ECMA_PROPERTY_TYPE_NAMEDDATA:
772    {
773      ecma_free_value_if_not_object (ECMA_PROPERTY_VALUE_PTR (property_p)->value);
774      break;
775    }
776    case ECMA_PROPERTY_TYPE_NAMEDACCESSOR:
777    {
778#if ENABLED (JERRY_CPOINTER_32_BIT)
779      ecma_getter_setter_pointers_t *getter_setter_pair_p;
780      getter_setter_pair_p = ECMA_GET_NON_NULL_POINTER (ecma_getter_setter_pointers_t,
781                                                        ECMA_PROPERTY_VALUE_PTR (property_p)->getter_setter_pair_cp);
782      jmem_pools_free (getter_setter_pair_p, sizeof (ecma_getter_setter_pointers_t));
783#endif /* ENABLED (JERRY_CPOINTER_32_BIT) */
784      break;
785    }
786    default:
787    {
788      JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_INTERNAL);
789
790      /* Must be a native pointer. */
791      JERRY_ASSERT (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_MAGIC
792                    && name_cp >= LIT_FIRST_INTERNAL_MAGIC_STRING);
793      break;
794    }
795  }
796
797#if ENABLED (JERRY_LCACHE)
798  if (ecma_is_property_lcached (property_p))
799  {
800    ecma_lcache_invalidate (object_p, name_cp, property_p);
801  }
802#endif /* ENABLED (JERRY_LCACHE) */
803
804  if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_PTR)
805  {
806    ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, name_cp);
807    ecma_deref_ecma_string (prop_name_p);
808  }
809} /* ecma_free_property */
810
811/**
812 * Delete the object's property referenced by its value pointer.
813 *
814 * Note: specified property must be owned by specified object.
815 */
816void
817ecma_delete_property (ecma_object_t *object_p, /**< object */
818                      ecma_property_value_t *prop_value_p) /**< property value reference */
819{
820  jmem_cpointer_t cur_prop_cp = object_p->u1.property_list_cp;
821
822  ecma_property_header_t *prev_prop_p = NULL;
823
824#if ENABLED (JERRY_PROPRETY_HASHMAP)
825  ecma_property_hashmap_delete_status hashmap_status = ECMA_PROPERTY_HASHMAP_DELETE_NO_HASHMAP;
826
827  if (cur_prop_cp != JMEM_CP_NULL)
828  {
829    ecma_property_header_t *cur_prop_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t,
830                                                                    cur_prop_cp);
831
832    if (cur_prop_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP)
833    {
834      prev_prop_p = cur_prop_p;
835      cur_prop_cp = cur_prop_p->next_property_cp;
836      hashmap_status = ECMA_PROPERTY_HASHMAP_DELETE_HAS_HASHMAP;
837    }
838  }
839#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
840
841  while (cur_prop_cp != JMEM_CP_NULL)
842  {
843    ecma_property_header_t *cur_prop_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t,
844                                                                    cur_prop_cp);
845
846    JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (cur_prop_p));
847
848    ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) cur_prop_p;
849
850    for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
851    {
852      if ((prop_pair_p->values + i) == prop_value_p)
853      {
854        JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (cur_prop_p->types[i]) != ECMA_PROPERTY_TYPE_SPECIAL);
855
856#if ENABLED (JERRY_PROPRETY_HASHMAP)
857        if (hashmap_status == ECMA_PROPERTY_HASHMAP_DELETE_HAS_HASHMAP)
858        {
859          hashmap_status = ecma_property_hashmap_delete (object_p,
860                                                         prop_pair_p->names_cp[i],
861                                                         cur_prop_p->types + i);
862        }
863#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
864
865        ecma_free_property (object_p, prop_pair_p->names_cp[i], cur_prop_p->types + i);
866        cur_prop_p->types[i] = ECMA_PROPERTY_TYPE_DELETED;
867        prop_pair_p->names_cp[i] = LIT_INTERNAL_MAGIC_STRING_DELETED;
868
869        JERRY_ASSERT (ECMA_PROPERTY_PAIR_ITEM_COUNT == 2);
870
871        if (cur_prop_p->types[1 - i] != ECMA_PROPERTY_TYPE_DELETED)
872        {
873#if ENABLED (JERRY_PROPRETY_HASHMAP)
874          /* The other property is still valid. */
875          if (hashmap_status == ECMA_PROPERTY_HASHMAP_DELETE_RECREATE_HASHMAP)
876          {
877            ecma_property_hashmap_free (object_p);
878            ecma_property_hashmap_create (object_p);
879          }
880#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
881          return;
882        }
883
884        JERRY_ASSERT (cur_prop_p->types[i] == ECMA_PROPERTY_TYPE_DELETED);
885
886        if (prev_prop_p == NULL)
887        {
888          object_p->u1.property_list_cp = cur_prop_p->next_property_cp;
889        }
890        else
891        {
892          prev_prop_p->next_property_cp = cur_prop_p->next_property_cp;
893        }
894
895        ecma_dealloc_property_pair ((ecma_property_pair_t *) cur_prop_p);
896
897#if ENABLED (JERRY_PROPRETY_HASHMAP)
898        if (hashmap_status == ECMA_PROPERTY_HASHMAP_DELETE_RECREATE_HASHMAP)
899        {
900          ecma_property_hashmap_free (object_p);
901          ecma_property_hashmap_create (object_p);
902        }
903#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
904        return;
905      }
906    }
907
908    prev_prop_p = cur_prop_p;
909    cur_prop_cp = cur_prop_p->next_property_cp;
910  }
911} /* ecma_delete_property */
912
913/**
914 * Check whether the object contains a property
915 */
916static void
917ecma_assert_object_contains_the_property (const ecma_object_t *object_p, /**< ecma-object */
918                                          const ecma_property_value_t *prop_value_p, /**< property value */
919                                          ecma_property_types_t type) /**< expected property type */
920{
921#ifndef JERRY_NDEBUG
922  jmem_cpointer_t prop_iter_cp = object_p->u1.property_list_cp;
923  JERRY_ASSERT (prop_iter_cp != JMEM_CP_NULL);
924
925  ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp);
926
927  if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP)
928  {
929    prop_iter_cp = prop_iter_p->next_property_cp;
930  }
931
932  while (prop_iter_cp != JMEM_CP_NULL)
933  {
934    prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp);
935
936    JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));
937
938    ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p;
939
940    for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
941    {
942      if ((prop_pair_p->values + i) == prop_value_p)
943      {
944        JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (prop_pair_p->header.types[i]) == type);
945        return;
946      }
947    }
948
949    prop_iter_cp = prop_iter_p->next_property_cp;
950  }
951#else /* JERRY_NDEBUG */
952  JERRY_UNUSED (object_p);
953  JERRY_UNUSED (prop_value_p);
954  JERRY_UNUSED (type);
955#endif /* !JERRY_NDEBUG */
956} /* ecma_assert_object_contains_the_property */
957
958/**
959 * Assign value to named data property
960 *
961 * Note:
962 *      value previously stored in the property is freed
963 */
964inline void JERRY_ATTR_ALWAYS_INLINE
965ecma_named_data_property_assign_value (ecma_object_t *obj_p, /**< object */
966                                       ecma_property_value_t *prop_value_p, /**< property value reference */
967                                       ecma_value_t value) /**< value to assign */
968{
969  ecma_assert_object_contains_the_property (obj_p, prop_value_p, ECMA_PROPERTY_TYPE_NAMEDDATA);
970
971  ecma_value_assign_value (&prop_value_p->value, value);
972} /* ecma_named_data_property_assign_value */
973
974/**
975 * Get named accessor property getter-setter-pair
976 *
977 * @return pointer to object's getter-setter pair
978 */
979ecma_getter_setter_pointers_t *
980ecma_get_named_accessor_property (const ecma_property_value_t *prop_value_p) /**< property value reference */
981{
982#if ENABLED (JERRY_CPOINTER_32_BIT)
983  return ECMA_GET_NON_NULL_POINTER (ecma_getter_setter_pointers_t, prop_value_p->getter_setter_pair_cp);
984#else /* !ENABLED (JERRY_CPOINTER_32_BIT) */
985  return (ecma_getter_setter_pointers_t *) &prop_value_p->getter_setter_pair;
986#endif /* ENABLED (JERRY_CPOINTER_32_BIT) */
987} /* ecma_get_named_accessor_property */
988
989/**
990 * Set getter of named accessor property
991 */
992void
993ecma_set_named_accessor_property_getter (ecma_object_t *object_p, /**< the property's container */
994                                         ecma_property_value_t *prop_value_p, /**< property value reference */
995                                         ecma_object_t *getter_p) /**< getter object */
996{
997  ecma_assert_object_contains_the_property (object_p, prop_value_p, ECMA_PROPERTY_TYPE_NAMEDACCESSOR);
998
999#if ENABLED (JERRY_CPOINTER_32_BIT)
1000  ecma_getter_setter_pointers_t *getter_setter_pair_p;
1001  getter_setter_pair_p = ECMA_GET_NON_NULL_POINTER (ecma_getter_setter_pointers_t,
1002                                                    prop_value_p->getter_setter_pair_cp);
1003  ECMA_SET_POINTER (getter_setter_pair_p->getter_cp, getter_p);
1004#else /* !ENABLED (JERRY_CPOINTER_32_BIT) */
1005  ECMA_SET_POINTER (prop_value_p->getter_setter_pair.getter_cp, getter_p);
1006#endif /* ENABLED (JERRY_CPOINTER_32_BIT) */
1007} /* ecma_set_named_accessor_property_getter */
1008
1009/**
1010 * Set setter of named accessor property
1011 */
1012void
1013ecma_set_named_accessor_property_setter (ecma_object_t *object_p, /**< the property's container */
1014                                         ecma_property_value_t *prop_value_p, /**< property value reference */
1015                                         ecma_object_t *setter_p) /**< setter object */
1016{
1017  ecma_assert_object_contains_the_property (object_p, prop_value_p, ECMA_PROPERTY_TYPE_NAMEDACCESSOR);
1018
1019#if ENABLED (JERRY_CPOINTER_32_BIT)
1020  ecma_getter_setter_pointers_t *getter_setter_pair_p;
1021  getter_setter_pair_p = ECMA_GET_NON_NULL_POINTER (ecma_getter_setter_pointers_t,
1022                                                    prop_value_p->getter_setter_pair_cp);
1023  ECMA_SET_POINTER (getter_setter_pair_p->setter_cp, setter_p);
1024#else /* !ENABLED (JERRY_CPOINTER_32_BIT) */
1025  ECMA_SET_POINTER (prop_value_p->getter_setter_pair.setter_cp, setter_p);
1026#endif /* ENABLED (JERRY_CPOINTER_32_BIT) */
1027} /* ecma_set_named_accessor_property_setter */
1028
1029/**
1030 * Get property's 'Writable' attribute value
1031 *
1032 * @return true - property is writable,
1033 *         false - otherwise
1034 */
1035inline bool JERRY_ATTR_ALWAYS_INLINE
1036ecma_is_property_writable (ecma_property_t property) /**< property */
1037{
1038  JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_NAMEDDATA
1039                || ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_VIRTUAL);
1040
1041  return (property & ECMA_PROPERTY_FLAG_WRITABLE) != 0;
1042} /* ecma_is_property_writable */
1043
1044/**
1045 * Set property's 'Writable' attribute value
1046 */
1047void
1048ecma_set_property_writable_attr (ecma_property_t *property_p, /**< [in,out] property */
1049                                 bool is_writable) /**< new value for writable flag */
1050{
1051  JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA);
1052
1053  if (is_writable)
1054  {
1055    *property_p = (uint8_t) (*property_p | ECMA_PROPERTY_FLAG_WRITABLE);
1056  }
1057  else
1058  {
1059    *property_p = (uint8_t) (*property_p & ~ECMA_PROPERTY_FLAG_WRITABLE);
1060  }
1061} /* ecma_set_property_writable_attr */
1062
1063/**
1064 * Get property's 'Enumerable' attribute value
1065 *
1066 * @return true - property is enumerable,
1067 *         false - otherwise
1068 */
1069inline bool JERRY_ATTR_ALWAYS_INLINE
1070ecma_is_property_enumerable (ecma_property_t property) /**< property */
1071{
1072  JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_NAMEDDATA
1073                || ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR
1074                || ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_VIRTUAL);
1075
1076  return (property & ECMA_PROPERTY_FLAG_ENUMERABLE) != 0;
1077} /* ecma_is_property_enumerable */
1078
1079/**
1080 * Set property's 'Enumerable' attribute value
1081 */
1082void
1083ecma_set_property_enumerable_attr (ecma_property_t *property_p, /**< [in,out] property */
1084                                   bool is_enumerable) /**< new value for enumerable flag */
1085{
1086  JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA
1087                || ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR);
1088
1089  if (is_enumerable)
1090  {
1091    *property_p = (uint8_t) (*property_p | ECMA_PROPERTY_FLAG_ENUMERABLE);
1092  }
1093  else
1094  {
1095    *property_p = (uint8_t) (*property_p & ~ECMA_PROPERTY_FLAG_ENUMERABLE);
1096  }
1097} /* ecma_set_property_enumerable_attr */
1098
1099/**
1100 * Get property's 'Configurable' attribute value
1101 *
1102 * @return true - property is configurable,
1103 *         false - otherwise
1104 */
1105inline bool JERRY_ATTR_ALWAYS_INLINE
1106ecma_is_property_configurable (ecma_property_t property) /**< property */
1107{
1108  JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_NAMEDDATA
1109                || ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR
1110                || ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_VIRTUAL);
1111
1112  return (property & ECMA_PROPERTY_FLAG_CONFIGURABLE) != 0;
1113} /* ecma_is_property_configurable */
1114
1115/**
1116 * Set property's 'Configurable' attribute value
1117 */
1118void
1119ecma_set_property_configurable_attr (ecma_property_t *property_p, /**< [in,out] property */
1120                                     bool is_configurable) /**< new value for configurable flag */
1121{
1122  JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA
1123                || ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR);
1124
1125  if (is_configurable)
1126  {
1127    *property_p = (uint8_t) (*property_p | ECMA_PROPERTY_FLAG_CONFIGURABLE);
1128  }
1129  else
1130  {
1131    *property_p = (uint8_t) (*property_p & ~ECMA_PROPERTY_FLAG_CONFIGURABLE);
1132  }
1133} /* ecma_set_property_configurable_attr */
1134
1135#if ENABLED (JERRY_LCACHE)
1136
1137/**
1138 * Check whether the property is registered in LCache
1139 *
1140 * @return true / false
1141 */
1142inline bool JERRY_ATTR_ALWAYS_INLINE
1143ecma_is_property_lcached (ecma_property_t *property_p) /**< property */
1144{
1145  JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA
1146                || ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR
1147                || ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_INTERNAL);
1148
1149  return (*property_p & ECMA_PROPERTY_FLAG_LCACHED) != 0;
1150} /* ecma_is_property_lcached */
1151
1152/**
1153 * Set value of flag indicating whether the property is registered in LCache
1154 */
1155inline void JERRY_ATTR_ALWAYS_INLINE
1156ecma_set_property_lcached (ecma_property_t *property_p, /**< property */
1157                           bool is_lcached) /**< new value for lcached flag */
1158{
1159  JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA
1160                || ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR
1161                || ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_INTERNAL);
1162
1163  if (is_lcached)
1164  {
1165    *property_p = (uint8_t) (*property_p | ECMA_PROPERTY_FLAG_LCACHED);
1166  }
1167  else
1168  {
1169    *property_p = (uint8_t) (*property_p & ~ECMA_PROPERTY_FLAG_LCACHED);
1170  }
1171} /* ecma_set_property_lcached */
1172
1173#endif /* ENABLED (JERRY_LCACHE) */
1174
1175/**
1176 * Construct empty property descriptor, i.e.:
1177 *  property descriptor with all is_defined flags set to false and the rest - to default value.
1178 *
1179 * @return empty property descriptor
1180 */
1181ecma_property_descriptor_t
1182ecma_make_empty_property_descriptor (void)
1183{
1184  ecma_property_descriptor_t prop_desc;
1185
1186  prop_desc.flags = 0;
1187  prop_desc.value = ECMA_VALUE_UNDEFINED;
1188  prop_desc.get_p = NULL;
1189  prop_desc.set_p = NULL;
1190
1191  return prop_desc;
1192} /* ecma_make_empty_property_descriptor */
1193
1194/**
1195 * Free values contained in the property descriptor
1196 * and make it empty property descriptor
1197 */
1198void
1199ecma_free_property_descriptor (ecma_property_descriptor_t *prop_desc_p) /**< property descriptor */
1200{
1201  if (prop_desc_p->flags & ECMA_PROP_IS_VALUE_DEFINED)
1202  {
1203    ecma_free_value (prop_desc_p->value);
1204  }
1205
1206  if ((prop_desc_p->flags & ECMA_PROP_IS_GET_DEFINED)
1207      && prop_desc_p->get_p != NULL)
1208  {
1209    ecma_deref_object (prop_desc_p->get_p);
1210  }
1211
1212  if ((prop_desc_p->flags & ECMA_PROP_IS_SET_DEFINED)
1213      && prop_desc_p->set_p != NULL)
1214  {
1215    ecma_deref_object (prop_desc_p->set_p);
1216  }
1217
1218  *prop_desc_p = ecma_make_empty_property_descriptor ();
1219} /* ecma_free_property_descriptor */
1220
1221/**
1222 * The size of error reference must be 8 bytes to use jmem_pools_alloc().
1223 */
1224JERRY_STATIC_ASSERT (sizeof (ecma_error_reference_t) == 8,
1225                     ecma_error_reference_size_must_be_8_bytes);
1226
1227/**
1228 * Create an error reference from a given value.
1229 *
1230 * Note:
1231 *   Reference of the value is taken.
1232 *
1233 * @return error reference value
1234 */
1235ecma_value_t
1236ecma_create_error_reference (ecma_value_t value, /**< referenced value */
1237                             bool is_exception) /**< error reference is an exception */
1238{
1239  ecma_error_reference_t *error_ref_p = (ecma_error_reference_t *) jmem_pools_alloc (sizeof (ecma_error_reference_t));
1240
1241  error_ref_p->refs_and_flags = ECMA_ERROR_REF_ONE | (is_exception ? 0 : ECMA_ERROR_REF_ABORT);
1242  error_ref_p->value = value;
1243  return ecma_make_error_reference_value (error_ref_p);
1244} /* ecma_create_error_reference */
1245
1246/**
1247 * Create an error reference from the currently thrown error value.
1248 *
1249 * @return error reference value
1250 */
1251ecma_value_t
1252ecma_create_error_reference_from_context (void)
1253{
1254  bool is_abort = jcontext_has_pending_abort ();
1255
1256  if (is_abort)
1257  {
1258    jcontext_set_abort_flag (false);
1259  }
1260  return ecma_create_error_reference (jcontext_take_exception (), !is_abort);
1261} /* ecma_create_error_reference_from_context */
1262
1263/**
1264 * Create an error reference from a given object.
1265 *
1266 * Note:
1267 *   Reference of the value is taken.
1268 *
1269 * @return error reference value
1270 */
1271inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE
1272ecma_create_error_object_reference (ecma_object_t *object_p) /**< referenced object */
1273{
1274  return ecma_create_error_reference (ecma_make_object_value (object_p), true);
1275} /* ecma_create_error_object_reference */
1276
1277/**
1278 * Increase ref count of an error reference.
1279 */
1280void
1281ecma_ref_error_reference (ecma_error_reference_t *error_ref_p) /**< error reference */
1282{
1283  if (JERRY_LIKELY (error_ref_p->refs_and_flags < ECMA_ERROR_MAX_REF))
1284  {
1285    error_ref_p->refs_and_flags += ECMA_ERROR_REF_ONE;
1286  }
1287  else
1288  {
1289    jerry_fatal (ERR_REF_COUNT_LIMIT);
1290  }
1291} /* ecma_ref_error_reference */
1292
1293/**
1294 * Decrease ref count of an error reference.
1295 */
1296void
1297ecma_deref_error_reference (ecma_error_reference_t *error_ref_p) /**< error reference */
1298{
1299  JERRY_ASSERT (error_ref_p->refs_and_flags >= ECMA_ERROR_REF_ONE);
1300
1301  error_ref_p->refs_and_flags -= ECMA_ERROR_REF_ONE;
1302
1303  if (error_ref_p->refs_and_flags < ECMA_ERROR_REF_ONE)
1304  {
1305    ecma_free_value (error_ref_p->value);
1306    jmem_pools_free (error_ref_p, sizeof (ecma_error_reference_t));
1307  }
1308} /* ecma_deref_error_reference */
1309
1310/**
1311 * Raise error from the given error reference.
1312 *
1313 * Note: the error reference's ref count is also decreased
1314 */
1315void
1316ecma_raise_error_from_error_reference (ecma_value_t value) /**< error reference */
1317{
1318  JERRY_ASSERT (!jcontext_has_pending_exception () && !jcontext_has_pending_abort ());
1319  ecma_error_reference_t *error_ref_p = ecma_get_error_reference_from_value (value);
1320
1321  JERRY_ASSERT (error_ref_p->refs_and_flags >= ECMA_ERROR_REF_ONE);
1322
1323  ecma_value_t referenced_value = error_ref_p->value;
1324
1325  jcontext_set_exception_flag (true);
1326  jcontext_set_abort_flag (error_ref_p->refs_and_flags & ECMA_ERROR_REF_ABORT);
1327
1328  if (error_ref_p->refs_and_flags >= 2 * ECMA_ERROR_REF_ONE)
1329  {
1330    error_ref_p->refs_and_flags -= ECMA_ERROR_REF_ONE;
1331    referenced_value = ecma_copy_value (referenced_value);
1332  }
1333  else
1334  {
1335    jmem_pools_free (error_ref_p, sizeof (ecma_error_reference_t));
1336  }
1337
1338  JERRY_CONTEXT (error_value) = referenced_value;
1339} /* ecma_raise_error_from_error_reference */
1340
1341/**
1342 * Increase reference counter of Compact
1343 * Byte Code or regexp byte code.
1344 */
1345void
1346ecma_bytecode_ref (ecma_compiled_code_t *bytecode_p) /**< byte code pointer */
1347{
1348  /* Abort program if maximum reference number is reached. */
1349  if (bytecode_p->refs >= UINT16_MAX)
1350  {
1351    jerry_fatal (ERR_REF_COUNT_LIMIT);
1352  }
1353
1354  bytecode_p->refs++;
1355} /* ecma_bytecode_ref */
1356
1357/**
1358 * Decrease reference counter of Compact
1359 * Byte Code or regexp byte code.
1360 */
1361void
1362ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p) /**< byte code pointer */
1363{
1364  JERRY_ASSERT (bytecode_p->refs > 0);
1365  JERRY_ASSERT (!(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION));
1366
1367  bytecode_p->refs--;
1368
1369  if (bytecode_p->refs > 0)
1370  {
1371    /* Non-zero reference counter. */
1372    return;
1373  }
1374
1375  if (bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION)
1376  {
1377    ecma_value_t *literal_start_p = NULL;
1378    uint32_t literal_end;
1379    uint32_t const_literal_end;
1380
1381    if (bytecode_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
1382    {
1383      cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_p;
1384      literal_end = args_p->literal_end;
1385      const_literal_end = args_p->const_literal_end;
1386
1387      literal_start_p = (ecma_value_t *) ((uint8_t *) bytecode_p + sizeof (cbc_uint16_arguments_t));
1388      literal_start_p -= args_p->register_end;
1389    }
1390    else
1391    {
1392      cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_p;
1393      literal_end = args_p->literal_end;
1394      const_literal_end = args_p->const_literal_end;
1395
1396      literal_start_p = (ecma_value_t *) ((uint8_t *) bytecode_p + sizeof (cbc_uint8_arguments_t));
1397      literal_start_p -= args_p->register_end;
1398    }
1399
1400    for (uint32_t i = const_literal_end; i < literal_end; i++)
1401    {
1402      ecma_compiled_code_t *bytecode_literal_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t,
1403                                                                                  literal_start_p[i]);
1404
1405      /* Self references are ignored. */
1406      if (bytecode_literal_p != bytecode_p)
1407      {
1408        ecma_bytecode_deref (bytecode_literal_p);
1409      }
1410    }
1411
1412#if ENABLED (JERRY_DEBUGGER)
1413    if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
1414        && !(bytecode_p->status_flags & CBC_CODE_FLAGS_DEBUGGER_IGNORE)
1415        && jerry_debugger_send_function_cp (JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP, bytecode_p))
1416    {
1417      /* Delay the byte code free until the debugger client is notified.
1418       * If the connection is aborted the pointer is still freed by
1419       * jerry_debugger_close_connection(). */
1420      jerry_debugger_byte_code_free_t *byte_code_free_p = (jerry_debugger_byte_code_free_t *) bytecode_p;
1421      jmem_cpointer_t byte_code_free_head = JERRY_CONTEXT (debugger_byte_code_free_head);
1422
1423      byte_code_free_p->prev_cp = ECMA_NULL_POINTER;
1424
1425      jmem_cpointer_t byte_code_free_cp;
1426      JMEM_CP_SET_NON_NULL_POINTER (byte_code_free_cp, byte_code_free_p);
1427
1428      if (byte_code_free_head == ECMA_NULL_POINTER)
1429      {
1430        JERRY_CONTEXT (debugger_byte_code_free_tail) = byte_code_free_cp;
1431      }
1432      else
1433      {
1434        jerry_debugger_byte_code_free_t *first_byte_code_free_p;
1435
1436        first_byte_code_free_p = JMEM_CP_GET_NON_NULL_POINTER (jerry_debugger_byte_code_free_t,
1437                                                               byte_code_free_head);
1438        first_byte_code_free_p->prev_cp = byte_code_free_cp;
1439      }
1440
1441      JERRY_CONTEXT (debugger_byte_code_free_head) = byte_code_free_cp;
1442      return;
1443    }
1444#endif /* ENABLED (JERRY_DEBUGGER) */
1445
1446#if ENABLED (JERRY_ES2015)
1447    if (bytecode_p->status_flags & CBC_CODE_FLAG_HAS_TAGGED_LITERALS)
1448    {
1449      ecma_collection_t *collection_p = ecma_compiled_code_get_tagged_template_collection (bytecode_p);
1450
1451      /* Since the objects in the tagged template collection are not strong referenced anymore by the compiled code
1452         we can treat them as 'new' objects. */
1453      JERRY_CONTEXT (ecma_gc_new_objects) += collection_p->item_count;
1454      ecma_collection_free (collection_p);
1455    }
1456#endif /* ENABLED (JERRY_ES2015) */
1457
1458#if ENABLED (JERRY_MEM_STATS)
1459    jmem_stats_free_byte_code_bytes (((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG);
1460#endif /* ENABLED (JERRY_MEM_STATS) */
1461  }
1462  else
1463  {
1464#if ENABLED (JERRY_BUILTIN_REGEXP)
1465    re_compiled_code_t *re_bytecode_p = (re_compiled_code_t *) bytecode_p;
1466
1467    ecma_deref_ecma_string (ecma_get_string_from_value (re_bytecode_p->source));
1468#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
1469  }
1470
1471  jmem_heap_free_block (bytecode_p,
1472                        ((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG);
1473} /* ecma_bytecode_deref */
1474
1475#if ENABLED (JERRY_ES2015)
1476/**
1477 * Get the tagged template collection of the compiled code
1478 *
1479 * @return pointer to the tagged template collection
1480 */
1481ecma_collection_t *
1482ecma_compiled_code_get_tagged_template_collection (const ecma_compiled_code_t *bytecode_header_p) /**< compiled code */
1483{
1484  JERRY_ASSERT (bytecode_header_p != NULL);
1485  JERRY_ASSERT (bytecode_header_p->status_flags & CBC_CODE_FLAG_HAS_TAGGED_LITERALS);
1486
1487  uint8_t *byte_p = (uint8_t *) bytecode_header_p;
1488  byte_p += ((size_t) bytecode_header_p->size) << JMEM_ALIGNMENT_LOG;
1489
1490  ecma_value_t *tagged_base_p = (ecma_value_t *) byte_p;
1491  tagged_base_p -= ecma_compiled_code_get_formal_params (bytecode_header_p);
1492
1493  return ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, tagged_base_p[-1]);
1494} /* ecma_compiled_code_get_tagged_template_collection */
1495#endif /* ENABLED (JERRY_ES2015) */
1496
1497#if ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) || ENABLED (JERRY_ES2015)
1498/**
1499 * Get the number of formal parameters of the compiled code
1500 *
1501 * @return number of formal parameters
1502 */
1503ecma_length_t
1504ecma_compiled_code_get_formal_params (const ecma_compiled_code_t *bytecode_header_p) /**< compiled code */
1505{
1506  if (!(bytecode_header_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED))
1507  {
1508    return 0;
1509  }
1510
1511  if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
1512  {
1513    return ((cbc_uint16_arguments_t *) bytecode_header_p)->argument_end;
1514  }
1515
1516  return ((cbc_uint8_arguments_t *) bytecode_header_p)->argument_end;
1517} /* ecma_compiled_code_get_formal_params */
1518#endif /* ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) || ENABLED (JERRY_ES2015) */
1519
1520#if (JERRY_STACK_LIMIT != 0)
1521/**
1522 * Check the current stack usage by calculating the difference from the initial stack base.
1523 *
1524 * @return current stack usage in bytes
1525 */
1526uintptr_t JERRY_ATTR_NOINLINE
1527ecma_get_current_stack_usage (void)
1528{
1529  volatile int __sp;
1530  return (uintptr_t) (JERRY_CONTEXT (stack_base) - (uintptr_t) &__sp);
1531} /* ecma_get_current_stack_usage */
1532
1533#endif /* (JERRY_STACK_LIMIT != 0) */
1534
1535/**
1536 * @}
1537 * @}
1538 */
1539