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